gdritter repos knurling / master src / main.rs
master

Tree @master (Download .tar.gz)

main.rs @master

f6160f0
 
 
9c77396
ab5f41a
c14dd91
 
 
8813b20
c14dd91
9c77396
8813b20
c14dd91
f6160f0
538d887
87ea1f9
e33d73f
 
f6160f0
abdd363
e33d73f
262618d
8813b20
 
 
 
 
 
262618d
abdd363
 
 
 
 
 
8813b20
abdd363
f040d6b
abdd363
 
 
 
 
 
 
 
 
f040d6b
538d887
 
5265971
538d887
262618d
538d887
 
 
232d33a
538d887
f040d6b
262618d
538d887
 
f040d6b
 
 
 
14a6cd6
262618d
 
 
 
 
 
 
232d33a
14a6cd6
262618d
 
 
57ff80d
262618d
 
14a6cd6
262618d
9c77396
262618d
0defe33
262618d
14a6cd6
262618d
538d887
f040d6b
f4aa185
 
f040d6b
538d887
f4aa185
 
262618d
f4aa185
abdd363
f4aa185
14a6cd6
c14dd91
538d887
 
f040d6b
262618d
f4aa185
f040d6b
 
 
 
 
c14dd91
538d887
 
f4aa185
538d887
f040d6b
f6160f0
232d33a
f040d6b
c14dd91
0defe33
9c77396
262618d
f040d6b
c14dd91
538d887
 
262618d
 
 
 
 
 
c14dd91
 
f040d6b
0defe33
262618d
9c77396
262618d
87ea1f9
c14dd91
f6160f0
 
c14dd91
#[macro_use]
extern crate failure;

mod config;
mod widgets;
mod window;

use pango::LayoutExt;
use std::os::unix::io::AsRawFd;

use widgets::Size;
use window::{Display, Event, Window};

fn main() -> Result<(), failure::Error> {
    // set up the display and the window
    let mut config = config::Config::find_config()?;
    let height = config.get_height();

    let mut d = Display::create()?;
    let mut ws = Vec::new();

    for (x_off, wd) in d.get_widths()? {
        let size = Size {
            wd,
            ht: height,
            xo: x_off,
            yo: 0,
        };
        let mut w = Window::create(&d, size)?;
        // set some window-manager properties: this is a dock
        w.change_property("_NET_WM_WINDOW_TYPE", &["_NET_WM_WINDOW_TYPE_DOCK"])?;
        // ...and should push other windows out of the way
        w.change_property("_NET_WM_STRUT", &[x_off as i64, 0, size.ht as i64, 0])?;
        w.change_property(
            "_NET_WM_STRUT_PARTIAL",
            &[0, 0, size.ht as i64, 0, 0, 0, 0, 0, 0, size.wd as i64, 0, 0],
        )?;

        // we won't ever see this, but for good measure.
        w.set_title("rbar")?;
        // we care about some input events!
        w.set_input_masks()?;
        w.set_protocols()?;
        // and now show it!
        w.map();
        ws.push(w);
    }

    // we do some grossness with file descriptors later, so we need
    // the file descriptors we care about here
    let window_fds: Vec<i32> = ws.iter_mut().map(|w| w.get_fd()).collect();
    let stdin_fd = std::io::stdin().as_raw_fd();

    // To begin with, our left-hand side---which normally is whatever
    // was last passed in on stdin---will start as a generic
    // message...
    let mut input = "Loading...".to_string();
    // And let's get a buffered stdin handle now
    let mut stdin = std::io::BufReader::new(std::io::stdin());

    // In the absence of other events, let's refresh every five
    // seconds. Or whatever.
    let mut timer = libc::timeval {
        tv_sec: 5,
        tv_usec: 0,
    };

    let mut ctxs = Vec::new();
    for w in ws.iter_mut() {
        // let's grab the cairo context here
        let surf = w.get_cairo_surface();
        let ctx = cairo::Context::new(&surf);

        let layout = pangocairo::functions::create_layout(&ctx)
            .ok_or_else(|| format_err!("unable to create layout"))?;

        // allow for the whole width of the bar, minus a small fixed amount
        layout.set_width((w.width - 20) * pango::SCALE);
        // this should also be configurable, but Fira Mono is a good font
        let mut font = pango::FontDescription::from_string(config.font());
        font.set_weight(pango::Weight::Bold);
        layout.set_font_description(&font);

        // do an initial pass at drawing the bar!
        config.draw(&ctx, &layout, &input, w.size())?;

        ctxs.push((ctx, layout, w.size()));
    }

    let max_fd = window_fds.iter().max().unwrap_or(&0) + 1;
    // we're gonna keep looping until we don't
    loop {
        let mut fds = std::mem::MaybeUninit::uninit();

        unsafe {
            // set up the FD set to be the X11 fd and the state of stdin
            libc::FD_ZERO(fds.as_mut_ptr());
            fds.assume_init();
            for fd in window_fds.iter() {
                libc::FD_SET(*fd, fds.as_mut_ptr());
            }
            libc::FD_SET(stdin_fd, fds.as_mut_ptr());
            timer.tv_sec = 5;

            // this will block until there's input on either of the
            // above FDs or until five seconds have passed, whichever comes first
            libc::select(
                max_fd,
                fds.as_mut_ptr(),
                std::ptr::null_mut(),
                std::ptr::null_mut(),
                &mut timer,
            );
        }

        // if we _did_ have input on stdin, then read it in: that'll
        // be our new left-hand text
        if unsafe { libc::FD_ISSET(stdin_fd, fds.as_mut_ptr()) } {
            use std::io::BufRead;
            input = String::new();
            stdin.read_line(&mut input)?;
            if input.is_empty() {
                break;
            }
            for (ctx, layout, sz) in ctxs.iter() {
                config.draw(&ctx, &layout, &input, *sz)?;
            }
        }

        // if we have X11 events, handle them. If any one was a quit
        // event, then just... quit.
        for w in ws.iter_mut() {
            while w.has_events() {
                match w.handle() {
                    Some(Event::QuitEvent) => break,
                    _e => (),
                }
            }
        }

        for (ctx, layout, sz) in ctxs.iter() {
            // otherwise, draw the thing!
            config.draw(&ctx, &layout, &input, *sz)?;
        }
        config.update();
    }

    Ok(())
}