diff --git a/Cargo.lock b/Cargo.lock index 73d045e..534205f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -287,6 +287,7 @@ version = "0.3.0" dependencies = [ "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "xcb 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index d36f8e3..0fa6a5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ failure = "0.1.1" nom = "3.2.1" clap = "2.31.2" nix = "0.10.0" +libc = "0.2.39" [build-dependencies] clap = "2.31.2" diff --git a/README.md b/README.md index 6273e11..4dabe31 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ The output format can be changed using the `-f FORMAT` switch. The possible format values are listed bellow: | Format Specifier | Description | Example | Custom Format Equivalent | -| ---------------- | --------------------------------- | --------------------- | ------------------------ | +| ---------------- | ----------------------------------------- | --------------------- | ------------------------ | | `hex` | Lowercase hexadecimal (default) | `#ff00ff` | `#%{02hr}%{02hg}%{02hb}` | | `HEX` | Uppercase hexadecimal | `#00FF00` | `#%{02Hr}%{02Hg}%{02Hb}` | | `hex!` | Compact lowercase hexadecimal1 | `#fff` | Not expressible | @@ -79,7 +79,7 @@ format values are listed bellow: | `rgb` | Decimal RGB | `rgb(255, 255, 255)` | `rgb(%{r}, %{g}, %{b})` | | `plain` | Decimal with semicolon separators | `0;0;0` | `%{r};%{g};%{b}` | -**1:** The compact form refers to CSS three-letter color codes as specified by [CSS +**1**: The compact form refers to CSS three-letter color codes as specified by [CSS Color Module Level 3](https://www.w3.org/TR/2018/PR-css-color-3-20180315/#rgb-color). If the color is not expressible in three-letter form, the regular six-letter form will be used. diff --git a/src/main.rs b/src/main.rs index 53b5818..3cc1d5c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ extern crate xcb; extern crate failure; extern crate clap; extern crate nix; +extern crate libc; #[macro_use] extern crate nom; diff --git a/src/selection.rs b/src/selection.rs index 919b281..08edc43 100644 --- a/src/selection.rs +++ b/src/selection.rs @@ -1,17 +1,30 @@ use std; +use std::fs; use std::str::FromStr; +use std::os::unix::io::IntoRawFd; use failure::{Error, err_msg}; -use nix::unistd::{fork, ForkResult}; +use nix::unistd::{self, fork, ForkResult}; use xcb::base as xbase; use xcb::base::Connection; use xcb::xproto; +use libc; pub fn into_daemon() -> Result { match fork()? { parent@ForkResult::Parent { .. } => Ok(parent), child@ForkResult::Child => { + unistd::setsid()?; std::env::set_current_dir("/")?; - // TODO: Point file handles to /dev/null + // Not sure if this is safe... + let dev_null = fs::OpenOptions::new() + .read(true) + .write(true) + .open("/dev/null")? + .into_raw_fd(); + for fd in &[libc::STDIN_FILENO, libc::STDOUT_FILENO, libc::STDERR_FILENO] { + unistd::close(*fd)?; + unistd::dup2(dev_null, *fd)?; + } Ok(child) } } @@ -45,6 +58,15 @@ impl Selection { } } +// The selection daemon presented here is not a perfect implementation of the +// ICCCM recommendation. Currently, it does not support large transfers and does +// not verify that the requestor has received the data by monitoring for atom +// deletion. Additionally, we do not support MULTIPLE and TIMESTAMP targets even +// though those are required by the spec. However, this implements just enough +// of the spec to work well enough in practice as color codes do not tend to be +// that large. However, this assumption could of course fail with custom +// templates. + pub fn set_selection(conn: &Connection, root: xproto::Window, selection: Selection, @@ -68,6 +90,7 @@ pub fn set_selection(conn: &Connection, &[]) .request_check()?; + // It would be better to use a real timestamp xproto::set_selection_owner(conn, window, selection, xbase::CURRENT_TIME) .request_check()?; @@ -83,6 +106,8 @@ pub fn set_selection(conn: &Connection, let event: &xproto::SelectionRequestEvent= unsafe { xbase::cast_event(&event) }; + + // We should check the event timestamp let target = event.target(); let property = if target == utf8_string {