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 {