gdritter repos knurling / 262618d
Actually spawn multiple windows Getty Ritter 4 years ago
2 changed file(s) with 83 addition(s) and 67 deletion(s). Collapse all Expand all
1919 ht: 36,
2020 };
2121 let mut ws = Vec::new();
22 for (x_off, wd) in in d.get_widths() {
22 for (x_off, wd) in d.get_widths()? {
2323 let size = Size { wd, ht: 36 };
24 let mut w = Window::create(d, size)?;
24 let mut w = Window::create(&d, size)?;
2525 // set some window-manager properties: this is a dock
2626 w.change_property("_NET_WM_WINDOW_TYPE", &["_NET_WM_WINDOW_TYPE_DOCK"])?;
2727 // ...and should push other windows out of the way
4444 ws.push(w);
4545 }
4646
47 // let's grab the cairo context here
48 let surf = w.get_cairo_surface();
49 let ctx = cairo::Context::new(&surf);
50
5147 // we do some grossness with file descriptors later, so we need
5248 // the file descriptors we care about here
53 let window_fds = ws.map{ |w| w.get_fd() };
49 let window_fds: Vec<i32> = ws.iter_mut().map({ |w| w.get_fd() }).collect();
5450 let stdin_fd = std::io::stdin().as_raw_fd();
51 let mut fds = unsafe { std::mem::uninitialized() };
5552
56 let mut fds = unsafe { std::mem::uninitialized() };
5753 // To begin with, our left-hand side---which normally is whatever
5854 // was last passed in on stdin---will start as a generic
5955 // message...
6056 let mut input = format!("Loading...");
6157 // And let's get a buffered stdin handle now
6258 let mut stdin = std::io::BufReader::new(std::io::stdin());
59
6360 // In the absence of other events, let's refresh every five
6461 // seconds. Or whatever.
6562 let mut timer = libc::timeval {
6764 tv_usec: 0,
6865 };
6966
70 let layout = pangocairo::functions::create_layout(&ctx)
71 .ok_or(format_err!("foo"))?;
72
73 // allow for the whole width of the bar, minus a small fixed amount
74 layout.set_width((size.wd - 20) * pango::SCALE);
75 // this should also be configurable, but Fira Mono is a good font
76 let mut font = pango::FontDescription::from_string("Fira Mono 18");
77 font.set_weight(pango::Weight::Bold);
78 layout.set_font_description(&font);
79
80 // do an initial pass at drawing the bar!
81 draw(&ctx, &layout, &input, size)?;
67 let mut ctxs = Vec::new();
68 for w in ws.iter_mut() {
69 // let's grab the cairo context here
70 let surf = w.get_cairo_surface();
71 let ctx = cairo::Context::new(&surf);
8272
8373
74 let layout = pangocairo::functions::create_layout(&ctx)
75 .ok_or(format_err!("unable to create layout"))?;
76
77 // allow for the whole width of the bar, minus a small fixed amount
78 layout.set_width((w.width - 20) * pango::SCALE);
79 // this should also be configurable, but Fira Mono is a good font
80 let mut font = pango::FontDescription::from_string("Fira Mono 18");
81 font.set_weight(pango::Weight::Bold);
82 layout.set_font_description(&font);
83
84 // do an initial pass at drawing the bar!
85 draw(&ctx, &layout, &input, w.size())?;
86
87 ctxs.push((ctx, layout));
88 }
89
90
91 let max_fd = window_fds.iter().max().unwrap_or(&0) + 1;
8492 // we're gonna keep looping until we don't
8593 loop {
8694 unsafe {
8795 // set up the FD set to be the X11 fd and the state of stdin
8896 libc::FD_ZERO(&mut fds);
89 for fd in window_fds {
90 libc::FD_SET(fd, &mut fds);
97 for fd in window_fds.iter() {
98 libc::FD_SET(*fd, &mut fds);
9199 }
92100 libc::FD_SET(stdin_fd, &mut fds);
93101 timer.tv_sec = 5;
95103 // this will block until there's input on either of the
96104 // above FDs or until five seconds have passed, whichever comes first
97105 libc::select(
98 window_fd + 1,
106 max_fd,
99107 &mut fds,
100108 std::ptr::null_mut(),
101109 std::ptr::null_mut(),
112120 if input.len() == 0 {
113121 break;
114122 }
115 draw(&ctx, &layout, &input, size)?;
123 for (ctx, layout) in ctxs.iter() {
124 draw(&ctx, &layout, &input, size)?;
125 }
116126 }
117127
118128 // if we have X11 events, handle them. If any one was a quit
119129 // event, then just... quit.
120 while w.has_events() {
121 match w.handle() {
122 Some(Event::QuitEvent) => break,
123 _e => (),
130 for w in ws.iter_mut() {
131 while w.has_events() {
132 match w.handle() {
133 Some(Event::QuitEvent) => break,
134 _e => (),
135 }
124136 }
125137 }
126138
127 // otherwise, draw the thing!
128 draw(&ctx, &layout, &input, size)?;
139 for (ctx, layout) in ctxs.iter() {
140 // otherwise, draw the thing!
141 draw(&ctx, &layout, &input, size)?;
142 }
129143 }
130144
131145 Ok(())
5050 }
5151 }
5252
53 impl Drop for Display {
54 fn drop(&mut self) {
55 unsafe {
56 xlib::XCloseDisplay(self.display);
57 }
58 }
59 }
60
5361 /// All the state needed to keep around to run this sort of
5462 /// application!
55 pub struct Window {
56 pub display: *mut xlib::_XDisplay,
63 pub struct Window<'t> {
64 pub display: &'t Display,
5765 pub screen: i32,
5866 pub window: u64,
5967 // these two are interned strings kept around because we want to
6674 pub height: i32,
6775 }
6876
69 impl Window {
77 impl<'t> Window<'t> {
7078 /// Create a new Window from a given Display and with the desire
7179 /// width and height
7280 pub fn create(
73 d: Display,
81 display: &'t Display,
7482 Size { wd: width, ht: height }: Size,
75 ) -> Result<Window, failure::Error> {
76 unsafe {
77 let display = d.display;
78 let screen = d.screen;
83 ) -> Result<Window<'t>, failure::Error> {
84 unsafe {
85 let screen = display.screen;
7986 let window = xlib::XCreateSimpleWindow(
80 display,
81 xlib::XRootWindow(display, screen),
87 display.display,
88 xlib::XRootWindow(display.display, screen),
8289 0,
8390 0,
8491 width as u32,
8592 height as u32,
8693 1,
87 xlib::XBlackPixel(display, screen),
88 xlib::XWhitePixel(display, screen),
94 xlib::XBlackPixel(display.display, screen),
95 xlib::XWhitePixel(display.display, screen),
8996 );
9097 let wm_protocols = {
9198 let cstr = CString::new("WM_PROTOCOLS")?;
92 xlib::XInternAtom(display, cstr.as_ptr(), 0)
99 xlib::XInternAtom(display.display, cstr.as_ptr(), 0)
93100 };
94101 let wm_delete_window = {
95102 let cstr = CString::new("WM_DELETE_WINDOW")?;
96 xlib::XInternAtom(display, cstr.as_ptr(), 0)
103 xlib::XInternAtom(display.display, cstr.as_ptr(), 0)
97104 };
98105 Ok(Window {
99106 display,
117124 let xinput_str = CString::new("XInputExtension")?;
118125 unsafe {
119126 xlib::XQueryExtension(
120 self.display,
127 self.display.display,
121128 xinput_str.as_ptr(),
122129 &mut opcode,
123130 &mut event,
141148
142149 match unsafe {
143150 xinput2::XISelectEvents(
144 self.display,
151 self.display.display,
145152 self.window,
146153 &mut input_event_mask,
147154 1,
158165 let mut protocols = [self.intern("WM_DELETE_WINDOW")?];
159166 unsafe {
160167 xlib::XSetWMProtocols(
161 self.display,
168 self.display.display,
162169 self.window,
163170 protocols.as_mut_ptr(),
164171 protocols.len() as c_int,
171178 pub fn set_title(&mut self, name: &str) -> Result<(), failure::Error> {
172179 unsafe {
173180 xlib::XStoreName(
174 self.display,
181 self.display.display,
175182 self.window,
176183 CString::new(name)?.as_ptr(),
177184 );
182189 /// Map the window to the screen
183190 pub fn map(&mut self) {
184191 unsafe {
185 xlib::XMapWindow(self.display, self.window);
192 xlib::XMapWindow(self.display.display, self.window);
186193 }
187194 }
188195
190197 pub fn intern(&mut self, s: &str) -> Result<u64, failure::Error> {
191198 unsafe {
192199 let cstr = CString::new(s)?;
193 Ok(xlib::XInternAtom(self.display, cstr.as_ptr(), 0))
200 Ok(xlib::XInternAtom(self.display.display, cstr.as_ptr(), 0))
194201 }
195202 }
196203
206213 let len = val.len();
207214 T::with_ptr(val, self, |w, typ, ptr| {
208215 xlib::XChangeProperty(
209 w.display,
216 w.display.display,
210217 w.window,
211218 prop,
212219 typ,
225232 pub fn get_cairo_surface(&mut self) -> cairo::Surface {
226233 unsafe {
227234 let s = cairo_sys::cairo_xlib_surface_create(
228 self.display,
235 self.display.display,
229236 self.window,
230 xlib::XDefaultVisual(self.display, self.screen),
237 xlib::XDefaultVisual(self.display.display, self.screen),
231238 self.width,
232239 self.height,
233240 );
241248 /// will also only return values for events we care about
242249 pub fn handle(&mut self) -> Option<Event> {
243250 let mut e = unsafe { mem::uninitialized() };
244 unsafe { xlib::XNextEvent(self.display, &mut e) };
251 unsafe { xlib::XNextEvent(self.display.display, &mut e) };
245252 match e.get_type() {
246253 // Is it a quit event? We gotta do some tedious string
247254 // comparison to find out
261268 // otherwise, it might be a mouse press event
262269 xlib::GenericEvent => {
263270 let mut cookie: xlib::XGenericEventCookie = From::from(e);
264 unsafe { xlib::XGetEventData(self.display, &mut cookie) };
271 unsafe { xlib::XGetEventData(self.display.display, &mut cookie) };
265272 match cookie.evtype {
266273 xinput2::XI_ButtonPress => {
267274 let data: &xinput2::XIDeviceEvent =
280287 /// True if there are any pending events.
281288 pub fn has_events(&mut self) -> bool {
282289 unsafe {
283 xlib::XPending(self.display) != 0
290 xlib::XPending(self.display.display) != 0
284291 }
285292 }
286293
288295 /// surface to wait on events? This lets us use select on it!
289296 pub fn get_fd(&mut self) -> i32 {
290297 unsafe {
291 xlib::XConnectionNumber(self.display)
292 }
293 }
294 }
295
296 /// Always close the display when we're done.
297 impl Drop for Window {
298 fn drop(&mut self) {
299 unsafe {
300 xlib::XCloseDisplay(self.display);
301 }
298 xlib::XConnectionNumber(self.display.display)
299 }
300 }
301
302 pub fn size(&self) -> Size {
303 Size { wd: self.width, ht: self.height }
302304 }
303305 }
304306