1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
//! Display server management.
//!
//! Provides functionality to select used display server based on the runtime environment.
use std::env;
use crate::prelude::ClipboardProviderExt;
/// A display server type.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[non_exhaustive]
pub enum DisplayServer {
/// The X11 display server.
X11,
/// The Wayland display server.
Wayland,
/// The default macOS display server.
MacOs,
/// The default Windows display server.
Windows,
/// For TTYs.
/// Not an actual display server, but something with a clipboard context to fall back to.
Tty,
}
impl DisplayServer {
/// Select current used display server.
///
/// This selection is made at runtime. This uses a best effort approach and does not reliably
/// select the current display server. Selects any recognized display server regardless of
/// compiler feature flag configuration. Defaults to `X11` on Unix if display server could not
/// be determined.
#[allow(unreachable_code)]
pub fn select() -> DisplayServer {
#[cfg(target_os = "macos")]
return DisplayServer::MacOs;
#[cfg(windows)]
return DisplayServer::Windows;
// Runtime check on Unix
if is_wayland() {
DisplayServer::Wayland
} else if is_x11() {
DisplayServer::X11
} else if is_tty() {
DisplayServer::Tty
} else {
// TODO: return Option::None if this isn't X11 either.
DisplayServer::X11
}
}
/// Build clipboard context for display server.
///
/// This attempts to build a clipboard context for the selected display server based on what
/// contexts are available.
///
/// If no compatible context is available or if no compatible context could be initialized,
/// `None` is returned.
pub fn try_context(self) -> Option<Box<dyn ClipboardProviderExt>> {
match self {
DisplayServer::X11 => {
#[cfg(feature = "x11-fork")]
{
let context = crate::x11_fork::ClipboardContext::new();
if let Ok(context) = context {
return Some(Box::new(context));
}
}
#[cfg(feature = "x11-bin")]
{
let context = crate::x11_bin::ClipboardContext::new();
if let Ok(context) = context {
return Some(Box::new(context));
}
}
#[cfg(all(
unix,
not(any(
target_os = "macos",
target_os = "android",
target_os = "ios",
target_os = "emscripten"
))
))]
{
let context = copypasta::x11_clipboard::X11ClipboardContext::new();
if let Ok(context) = context {
return Some(Box::new(context));
}
}
None
}
DisplayServer::Wayland => {
#[cfg(feature = "wayland-bin")]
{
let context = crate::wayland_bin::ClipboardContext::new();
if let Ok(context) = context {
return Some(Box::new(context));
}
}
// TODO: this correct?
copypasta::ClipboardContext::new()
.ok()
.map(|c| -> Box<dyn ClipboardProviderExt> { Box::new(c) })
}
DisplayServer::MacOs | DisplayServer::Windows => copypasta::ClipboardContext::new()
.ok()
.map(|c| -> Box<dyn ClipboardProviderExt> { Box::new(c) }),
DisplayServer::Tty => {
#[cfg(feature = "osc52")]
{
let context = crate::osc52::ClipboardContext::new();
if let Ok(context) = context {
return Some(Box::new(context));
}
}
None
}
}
}
}
/// Check whether we're in an X11 environment.
///
/// This is a best effort, may be unreliable.
/// Checks the `XDG_SESSION_TYPE` and `DISPLAY` environment variables.
/// Always returns false on unsupported platforms such as Windows/macOS.
///
/// Available regardless of the `x11-*` compiler feature flags.
pub fn is_x11() -> bool {
if !cfg!(all(unix, not(all(target_os = "macos", target_os = "ios")))) {
return false;
}
match env::var("XDG_SESSION_TYPE").ok().as_deref() {
Some("x11") => true,
Some("wayland") => false,
_ => has_non_empty_env("DISPLAY"),
}
}
/// Check whether we're in a Wayland environment.
///
/// This is a best effort, may be unreliable.
/// Checks the `XDG_SESSION_TYPE` and `WAYLAND_DISPLAY` environment variables.
/// Always returns false on Windows/macOS.
///
/// Available regardless of the `wayland-*` compiler feature flags.
pub fn is_wayland() -> bool {
if !cfg!(all(unix, not(all(target_os = "macos", target_os = "ios")))) {
return false;
}
match env::var("XDG_SESSION_TYPE").ok().as_deref() {
Some("wayland") => true,
Some("x11") => false,
_ => has_non_empty_env("WAYLAND_DISPLAY"),
}
}
/// Check whether we're in a TTY environment.
///
/// This is a basic check and only returns true if `XDG_SESSION_TYPE` is set to `tty` explicitly.
pub fn is_tty() -> bool {
env::var("XDG_SESSION_TYPE").as_deref() == Ok("tty")
}
/// Check if an environment variable is set and is not empty.
#[inline]
fn has_non_empty_env(env: &str) -> bool {
env::var_os(env).map(|v| !v.is_empty()).unwrap_or(false)
}