Browse Source

Switch to Failure-based error handling

Getty Ritter 5 years ago
parent
commit
f6160f08b9
5 changed files with 211 additions and 55 deletions
  1. 118 0
      Cargo.lock
  2. 1 0
      Cargo.toml
  3. 29 16
      src/main.rs
  4. 22 13
      src/widgets.rs
  5. 41 26
      src/window.rs

+ 118 - 0
Cargo.lock

@@ -1,5 +1,32 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
+[[package]]
+name = "autocfg"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "backtrace"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "backtrace-sys"
+version = "0.1.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "bitflags"
 version = "1.0.4"
@@ -30,6 +57,16 @@ dependencies = [
  "x11 2.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "cc"
+version = "1.0.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "cfg-if"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "chrono"
 version = "0.4.6"
@@ -40,6 +77,26 @@ dependencies = [
  "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "failure"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "failure_derive"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "glib"
 version = "0.7.1"
@@ -78,6 +135,7 @@ dependencies = [
  "cairo-rs 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cairo-sys-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
  "pango 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "pangocairo 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -166,11 +224,53 @@ name = "pkg-config"
 version = "0.3.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "proc-macro2"
+version = "0.4.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "quote"
+version = "0.6.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "redox_syscall"
 version = "0.1.51"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "rustc-demangle"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "syn"
+version = "0.15.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "time"
 version = "0.1.42"
@@ -181,6 +281,11 @@ dependencies = [
  "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "unicode-xid"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "winapi"
 version = "0.3.6"
@@ -210,10 +315,17 @@ dependencies = [
 ]
 
 [metadata]
+"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
+"checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4"
+"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
 "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
 "checksum cairo-rs 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e09d8a818b2ccc8983f04d95a9350c3cf8d24cc456cedca3b88fa3a81fdc0e2"
 "checksum cairo-sys-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3fa13914fdc013387afa771f554f2f71d6ae931f4e5be9246c337d60c3dc484"
+"checksum cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ce8bb087aacff865633f0bd5aeaed910fe2fe55b55f4739527f2e023a2e53d"
+"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
 "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
+"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
+"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
 "checksum glib 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e8fdc159c196a5dfa53a92929ac4c10c8a6637ffb43951f3fff89c2cd2365"
 "checksum glib-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bda542f3caee39a027638e9644ff89204101ad916fd7370b585ad2c5fc97e61"
 "checksum gobject-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23e05a14290d3dc255223cba51db4b0f3da438d5250657996fa99b2a30faf43e"
@@ -226,8 +338,14 @@ dependencies = [
 "checksum pangocairo 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "706e885b46a16ba96f46f3c8d880ca6082c2c62693b75f3d167bd3aa4e34b0d4"
 "checksum pangocairo-sys 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "868310e83da5269323c28bd47b641557d032426f396cddfa45e247ff44da9a12"
 "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
+"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
+"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
 "checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85"
+"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
+"checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2"
+"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
 "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
+"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
 "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
 "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

+ 1 - 0
Cargo.toml

@@ -11,6 +11,7 @@ pangocairo = "0.7"
 # time = "0.1"
 chrono = "*"
 libc = "0.2"
+failure = "*"
 
 [dependencies.cairo-sys-rs]
 version = "0.8"

+ 29 - 16
src/main.rs

@@ -1,3 +1,6 @@
+#[macro_use]
+extern crate failure;
+
 mod widgets;
 mod window;
 
@@ -7,32 +10,32 @@ use pango::LayoutExt;
 use widgets::Widget;
 use window::{Display,Event,Size,Window};
 
-fn main() {
+fn main() -> Result<(), failure::Error> {
     // set up the display and the window
-    let mut d = Display::create();
+    let mut d = Display::create()?;
     let size = Size {
         wd: d.get_width(),
         // TODO: this should be a function of font size
         ht: 36,
     };
-    let mut w = Window::create(d, size);
+    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"]);
+    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", &[0i64, 0, size.ht as i64, 0],);
+    w.change_property("_NET_WM_STRUT", &[0i64, 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");
+    w.set_title("rbar")?;
     // we care about some input events!
-    w.set_input_masks();
-    w.set_protocols();
+    w.set_input_masks()?;
+    w.set_protocols()?;
     // and now show it!
     w.map();
 
@@ -59,7 +62,8 @@ fn main() {
         tv_usec: 0,
     };
 
-    let layout = pangocairo::functions::create_layout(&ctx).unwrap();
+    let layout = pangocairo::functions::create_layout(&ctx)
+        .ok_or(format_err!("foo"))?;
 
     // allow for the whole width of the bar, minus a small fixed amount
     layout.set_width((size.wd - 20) * pango::SCALE);
@@ -69,7 +73,7 @@ fn main() {
     layout.set_font_description(&font);
 
     // do an initial pass at drawing the bar!
-    draw(&ctx, &layout, &input, size);
+    draw(&ctx, &layout, &input, size)?;
 
 
     // we're gonna keep looping until we don't
@@ -97,11 +101,11 @@ fn main() {
         if unsafe { libc::FD_ISSET(stdin_fd, &mut fds) } {
             use std::io::BufRead;
             input = String::new();
-            stdin.read_line(&mut input).unwrap();
+            stdin.read_line(&mut input)?;
             if input.len() == 0 {
                 break;
             }
-            draw(&ctx, &layout, &input, size);
+            draw(&ctx, &layout, &input, size)?;
         }
 
         // if we have X11 events, handle them. If any one was a quit
@@ -114,14 +118,22 @@ fn main() {
         }
 
         // otherwise, draw the thing!
-        draw(&ctx, &layout, &input, size);
+        draw(&ctx, &layout, &input, size)?;
     }
+
+    Ok(())
 }
 
 
 /// Do our Cairo drawing. This needs to be refactored to allow for
 /// more configurability in terms of what gets written!
-fn draw(ctx: &cairo::Context, layout: &pango::Layout, left: &str, size: Size) {
+fn draw(
+    ctx: &cairo::Context,
+    layout: &pango::Layout,
+    left: &str,
+    size: Size)
+    -> Result<(), failure::Error>
+{
     // the background is... gray-ish? this'll be configurable eventually
     ctx.set_source_rgb(0.1, 0.1, 0.1);
     ctx.paint();
@@ -138,7 +150,7 @@ fn draw(ctx: &cairo::Context, layout: &pango::Layout, left: &str, size: Size) {
     // set up our widgets
     let text = widgets::Text::new(left);
     let time = widgets::Time::new();
-    let bat = widgets::Battery;
+    let bat = widgets::Battery::new().unwrap();
 
     // and create a 'config' which tells us which widgets to draw from
     // the left, and which from the right
@@ -154,4 +166,5 @@ fn draw(ctx: &cairo::Context, layout: &pango::Layout, left: &str, size: Size) {
     // and draw them!
     config.draw(&drawing);
 
+    Ok(())
 }

+ 22 - 13
src/widgets.rs

@@ -105,36 +105,45 @@ impl Widget for SmallBox {
 
 
 
-pub struct Battery;
+pub struct Battery {
+    file_list: Vec<std::path::PathBuf>,
+}
 
 impl Battery {
-    fn read_status(&self) -> f64 {
+    pub fn new() -> Result<Battery, failure::Error> {
         use std::fs;
 
         let mut batteries = Vec::new();
-        for entry in fs::read_dir("/sys/class/power_supply").unwrap() {
-            let e = entry.unwrap();
+        for entry in fs::read_dir("/sys/class/power_supply")? {
+            let e = entry?;
             if e.file_name().to_string_lossy().starts_with("BAT") {
-                batteries.push(e.path());
+                let mut path = e.path();
+                path.push("capacity");
+                batteries.push(path);
             }
         }
 
-        let mut charges: Vec<i32> = Vec::new();
-        for mut bat in batteries {
-            bat.push("capacity");
-            let r = fs::read_to_string(bat).unwrap();
-            charges.push(r.trim().parse::<i32>().unwrap());
-        }
+        Ok(Battery {
+            file_list: batteries,
+        })
+    }
+
+    fn read_status(&self) -> Result<f64, failure::Error> {
+        let charges: Result<Vec<i32>, failure::Error> =
+            self.file_list.iter().map(|path| {
+            Ok(std::fs::read_to_string(path)?.trim().parse()?)
+            }).collect();
+        let charges = charges?;
 
         let len = charges.len() as f64;
         let sum: i32 = charges.into_iter().sum();
-        sum as f64 / len / 100.0
+        Ok(sum as f64 / len / 100.0)
     }
 }
 
 impl Widget for Battery {
     fn draw(&self, d: &Drawing, loc: Located) -> i32 {
-        let amt = self.read_status();
+        let amt = self.read_status().unwrap();
         let sz = d.size.ht - 8;
         let x = loc.target_x(d, sz);
         if amt < 0.1 {

+ 41 - 26
src/window.rs

@@ -16,10 +16,13 @@ pub struct Display {
 }
 
 impl Display {
-    pub fn create() -> Display {
+    pub fn create() -> Result<Display, failure::Error> {
         let display = unsafe { xlib::XOpenDisplay(ptr::null()) };
+        if display.is_null() {
+            bail!("Unable to open X11 display");
+        }
         let screen = unsafe { xlib::XDefaultScreen(display) };
-        Display { display, screen }
+        Ok(Display { display, screen })
     }
 
     pub fn get_width(&mut self) -> i32 {
@@ -52,7 +55,7 @@ impl Window {
     pub fn create(
         d: Display,
         Size { wd: width, ht: height }: Size,
-    ) -> Window {
+    ) -> Result<Window, failure::Error> {
         unsafe {
             let display = d.display;
             let screen = d.screen;
@@ -68,14 +71,14 @@ impl Window {
                 xlib::XWhitePixel(display, screen),
             );
             let wm_protocols = {
-                let cstr = CString::new("WM_PROTOCOLS").unwrap();
+                let cstr = CString::new("WM_PROTOCOLS")?;
                 xlib::XInternAtom(display, cstr.as_ptr(), 0)
             };
             let wm_delete_window = {
-                let cstr = CString::new("WM_DELETE_WINDOW").unwrap();
+                let cstr = CString::new("WM_DELETE_WINDOW")?;
                 xlib::XInternAtom(display, cstr.as_ptr(), 0)
             };
-            Window {
+            Ok(Window {
                 display,
                 screen,
                 window,
@@ -83,18 +86,18 @@ impl Window {
                 wm_delete_window,
                 width,
                 height,
-            }
+            })
         }
     }
 
     /// for this application, we might eventually care about the
     /// mouse, so make sure we notify x11 that we care about those
-    pub fn set_input_masks(&mut self) {
+    pub fn set_input_masks(&mut self) -> Result<(), failure::Error> {
         let mut opcode = 0;
         let mut event = 0;
         let mut error = 0;
 
-        let xinput_str = CString::new("XInputExtension").unwrap();
+        let xinput_str = CString::new("XInputExtension")?;
         unsafe {
             xlib::XQueryExtension(
                 self.display,
@@ -128,13 +131,14 @@ impl Window {
             )
         } {
             status if status as u8 == xlib::Success => (),
-            err => panic!("Failed to select events {:?}", err)
+            err => bail!("Failed to select events {:?}", err)
         }
 
+        Ok(())
     }
 
-    pub fn set_protocols(&mut self) {
-        let mut protocols = [self.intern("WM_DELETE_WINDOW")];
+    pub fn set_protocols(&mut self) -> Result<(), failure::Error> {
+        let mut protocols = [self.intern("WM_DELETE_WINDOW")?];
         unsafe {
             xlib::XSetWMProtocols(
                 self.display,
@@ -143,17 +147,19 @@ impl Window {
                 protocols.len() as c_int,
             );
         }
+        Ok(())
     }
 
     /// Set the name of the window to the desired string
-    pub fn set_title(&mut self, name: &str) {
+    pub fn set_title(&mut self, name: &str) -> Result<(), failure::Error> {
         unsafe {
             xlib::XStoreName(
                 self.display,
                 self.window,
-                CString::new(name).unwrap().as_ptr(),
+                CString::new(name)?.as_ptr(),
             );
         }
+        Ok(())
     }
 
     /// Map the window to the screen
@@ -164,16 +170,21 @@ impl Window {
     }
 
     /// Intern a string in the x server
-    pub fn intern(&mut self, s: &str) -> u64 {
+    pub fn intern(&mut self, s: &str) -> Result<u64, failure::Error> {
         unsafe {
-            let cstr = CString::new(s).unwrap();
-            xlib::XInternAtom(self.display, cstr.as_ptr(), 0)
+            let cstr = CString::new(s)?;
+            Ok(xlib::XInternAtom(self.display, cstr.as_ptr(), 0))
         }
     }
 
     /// Modify the supplied property to the noted value.
-    pub fn change_property<T: XProperty>(&mut self, prop: &str, val: &[T]) {
-        let prop = self.intern(prop);
+    pub fn change_property<T: XProperty>(
+        &mut self,
+        prop: &str,
+        val: &[T]
+    ) -> Result<(), failure::Error>
+    {
+        let prop = self.intern(prop)?;
         unsafe {
             let len = val.len();
             T::with_ptr(val, self, |w, typ, ptr| {
@@ -187,8 +198,9 @@ impl Window {
                     ptr,
                     len as c_int,
                 );
-            });
+            })?;
         }
+        Ok(())
     }
 
     /// Get the Cairo drawing surface corresponding to the whole
@@ -280,7 +292,7 @@ pub trait XProperty : Sized {
         xs: &[Self],
         w: &mut Window,
         f: impl FnOnce(&mut Window, u64, *const u8),
-    );
+    ) -> Result<(), failure::Error> ;
 }
 
 impl XProperty for i64 {
@@ -288,8 +300,9 @@ impl XProperty for i64 {
         xs: &[Self],
         w: &mut Window,
         f: impl FnOnce(&mut Window, u64, *const u8),
-    ) {
-        f(w, xlib::XA_CARDINAL, unsafe { mem::transmute(xs.as_ptr()) })
+    ) -> Result<(), failure::Error> {
+        f(w, xlib::XA_CARDINAL, unsafe { mem::transmute(xs.as_ptr()) });
+        Ok(())
     }
 }
 
@@ -298,9 +311,11 @@ impl XProperty for &str {
         xs: &[Self],
         w: &mut Window,
         f: impl FnOnce(&mut Window, u64, *const u8),
-    ) {
-        let xs: Vec<u64> = xs.iter().map(|s| w.intern(s)).collect();
-        f(w, xlib::XA_ATOM, unsafe { mem::transmute(xs.as_ptr()) })
+    ) -> Result<(), failure::Error> {
+        let xs: Result<Vec<u64>, failure::Error> =
+            xs.iter().map(|s| w.intern(s)).collect();
+        f(w, xlib::XA_ATOM, unsafe { mem::transmute(xs?.as_ptr()) });
+        Ok(())
     }
 }