Skip to content

Commit

Permalink
window: add xsettings support on X11 systems
Browse files Browse the repository at this point in the history
This allows reading xsettings which contain information about
both the active theme as well as the DPI.

refs: #947
  • Loading branch information
wez committed Jul 18, 2021
1 parent 1f5b900 commit a697b30
Show file tree
Hide file tree
Showing 8 changed files with 531 additions and 18 deletions.
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docs/config/lua/config/dpi.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The default value is system specific:
|Windows |Probed from the display |Probed from the display |
|X11 |96.0 |96.0 |
|X11 (*version 20210314-114017-04b7cedd and later*)|Probed from `Xft.dpi`, fallback to 96.0 |Probed from `Xft.dpi`, fallback to 96.0 |
|X11 (*Since: nightly builds only*)|Reads `Xft/DPI` via xsettings, fallback to `Xft.dpi`, then fallback to 96.0 | same as standard density |
|Wayland |96.0 |192.0 |

In macOS and Wayland environments there isn't strictly a system DPI value that
Expand Down
3 changes: 2 additions & 1 deletion wezterm-gui/src/termwindow/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,8 @@ impl TermWindow {
self.close_requested(window);
Ok(true)
}
WindowEvent::AppearanceChanged(_appearance) => {
WindowEvent::AppearanceChanged(appearance) => {
log::debug!("Appearance is now {:?}", appearance);
self.config_was_reloaded();
Ok(true)
}
Expand Down
2 changes: 2 additions & 0 deletions window/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ build = "build.rs"
[dev-dependencies]
pretty_env_logger = "0.4"
wgpu = "0.9"
k9 = "0.11.0"

[build-dependencies]
gl_generator = "0.14"
Expand All @@ -24,6 +25,7 @@ async-io = "1.1"
async-task = "4.0"
async-trait = "0.1"
anyhow = "1.0"
bytes = "1.0"
config = { path = "../config" }
color-types = { path = "../color-types" }
thiserror = "1.0"
Expand Down
91 changes: 76 additions & 15 deletions window/src/os/x11/connection.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use super::keyboard::Keyboard;
use crate::connection::ConnectionOps;
use crate::os::x11::window::XWindowInner;
use crate::os::x11::xsettings::*;
use crate::os::Connection;
use crate::spawn::*;
use crate::Appearance;
use anyhow::{anyhow, bail, Context as _};
use mio::unix::EventedFd;
use mio::{Evented, Events, Poll, PollOpt, Ready, Token};
Expand All @@ -16,6 +18,7 @@ use xcb_util::ffi::keysyms::{xcb_key_symbols_alloc, xcb_key_symbols_free, xcb_ke
pub struct XConnection {
pub conn: xcb_util::ewmh::Connection,
default_dpi: RefCell<f64>,
pub(crate) xsettings: RefCell<XSettingsMap>,
pub screen_num: i32,
pub root: xcb::xproto::Window,
pub keyboard: Keyboard,
Expand All @@ -28,6 +31,9 @@ pub struct XConnection {
pub atom_targets: xcb::Atom,
pub atom_clipboard: xcb::Atom,
pub atom_gtk_edge_constraints: xcb::Atom,
pub atom_xsettings_selection: xcb::Atom,
pub atom_xsettings_settings: xcb::Atom,
pub atom_manager: xcb::Atom,
keysyms: *mut xcb_key_symbols_t,
pub(crate) xrm: RefCell<HashMap<String, String>>,
pub(crate) windows: RefCell<HashMap<xcb::xproto::Window, Arc<Mutex<XWindowInner>>>>,
Expand Down Expand Up @@ -150,6 +156,27 @@ impl ConnectionOps for XConnection {
*self.default_dpi.borrow()
}

fn get_appearance(&self) -> Appearance {
if let Some(XSetting::String(name)) = self.xsettings.borrow().get("Net/ThemeName") {
let lower = name.to_ascii_lowercase();
match lower.as_str() {
"highcontrast" => Appearance::LightHighContrast,
"highcontrastinverse" => Appearance::DarkHighContrast,
"adwaita" => Appearance::Light,
"adwaita-dark" => Appearance::Dark,
lower => {
if lower.contains("dark") {
Appearance::Dark
} else {
Appearance::Light
}
}
}
} else {
Appearance::Dark
}
}

fn run_message_loop(&self) -> anyhow::Result<()> {
self.conn.flush();

Expand Down Expand Up @@ -195,19 +222,42 @@ impl ConnectionOps for XConnection {
}
}

impl XConnection {
pub(crate) fn update_xrm(&self) {
let xrm = crate::x11::xrm::parse_root_resource_manager(&self.conn, self.root)
.unwrap_or(HashMap::new());
let dpi = xrm
.get("Xft.dpi")
fn compute_default_dpi(xrm: &HashMap<String, String>, xsettings: &XSettingsMap) -> f64 {
if let Some(XSetting::Integer(dpi)) = xsettings.get("Xft/DPI") {
*dpi as f64 / 1024.0
} else {
xrm.get("Xft.dpi")
.as_ref()
.map(|s| s.as_str())
.unwrap_or("96")
.parse::<f64>()
.unwrap_or(crate::DEFAULT_DPI);
.unwrap_or(crate::DEFAULT_DPI)
}
}

impl XConnection {
pub(crate) fn update_xrm(&self) {
match read_xsettings(
&self.conn,
self.atom_xsettings_selection,
self.atom_xsettings_settings,
) {
Ok(settings) => {
if *self.xsettings.borrow() != settings {
log::trace!("xsettings changed to {:?}", settings);
*self.xsettings.borrow_mut() = settings;
}
}
Err(err) => {
log::error!("error reading xsettings: {:#}", err);
}
}

let xrm = crate::x11::xrm::parse_root_resource_manager(&self.conn, self.root)
.unwrap_or(HashMap::new());
*self.xrm.borrow_mut() = xrm;

let dpi = compute_default_dpi(&self.xrm.borrow(), &self.xsettings.borrow());
*self.default_dpi.borrow_mut() = dpi;
}

Expand Down Expand Up @@ -297,6 +347,16 @@ impl XConnection {
let atom_gtk_edge_constraints = xcb::intern_atom(&conn, false, "_GTK_EDGE_CONSTRAINTS")
.get_reply()?
.atom();
let atom_xsettings_selection =
xcb::intern_atom(&conn, false, &format!("_XSETTINGS_S{}", screen_num))
.get_reply()?
.atom();
let atom_xsettings_settings = xcb::intern_atom(&conn, false, "_XSETTINGS_SETTINGS")
.get_reply()?
.atom();
let atom_manager = xcb::intern_atom(&conn, false, "MANAGER")
.get_reply()?
.atom();

let keysyms = unsafe { xcb_key_symbols_alloc((*conn).get_raw_conn()) };

Expand Down Expand Up @@ -349,25 +409,26 @@ impl XConnection {

let xrm =
crate::x11::xrm::parse_root_resource_manager(&conn, root).unwrap_or(HashMap::new());
let default_dpi = RefCell::new(
xrm.get("Xft.dpi")
.as_ref()
.map(|s| s.as_str())
.unwrap_or("96")
.parse::<f64>()
.unwrap_or(crate::DEFAULT_DPI),
);

let xsettings = read_xsettings(&conn, atom_xsettings_selection, atom_xsettings_settings)?;
log::trace!("xsettings are {:?}", xsettings);

let default_dpi = RefCell::new(compute_default_dpi(&xrm, &xsettings));

let conn = XConnection {
conn,
default_dpi,
xsettings: RefCell::new(xsettings),
cursor_font_id,
screen_num,
root,
xrm: RefCell::new(xrm),
atom_protocols,
atom_clipboard,
atom_gtk_edge_constraints,
atom_xsettings_selection,
atom_xsettings_settings,
atom_manager,
atom_delete,
keysyms,
keyboard,
Expand Down
1 change: 1 addition & 0 deletions window/src/os/x11/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod cursor;
pub mod keyboard;
pub mod window;
pub mod xrm;
pub mod xsettings;

pub use self::window::*;
pub use connection::*;
Expand Down
14 changes: 12 additions & 2 deletions window/src/os/x11/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use crate::connection::ConnectionOps;
use crate::os::xkeysyms;
use crate::os::{Connection, Window};
use crate::{
Clipboard, Dimensions, MouseButtons, MouseCursor, MouseEvent, MouseEventKind, MousePress,
Point, ScreenPoint, WindowDecorations, WindowEvent, WindowEventSender, WindowOps,
Appearance, Clipboard, Dimensions, MouseButtons, MouseCursor, MouseEvent, MouseEventKind,
MousePress, Point, ScreenPoint, WindowDecorations, WindowEvent, WindowEventSender, WindowOps,
};
use anyhow::{anyhow, Context as _};
use async_trait::async_trait;
Expand Down Expand Up @@ -61,6 +61,7 @@ pub(crate) struct XWindowInner {
cursors: CursorInfo,
copy_and_paste: CopyAndPaste,
config: ConfigHandle,
appearance: Appearance,
}

impl Drop for XWindowInner {
Expand Down Expand Up @@ -319,6 +320,12 @@ impl XWindowInner {
// when running under gnome.
conn.update_xrm();
self.check_dpi_and_synthesize_resize();
let appearance = conn.get_appearance();
if appearance != self.appearance {
self.appearance = appearance;
self.events
.dispatch(WindowEvent::AppearanceChanged(appearance));
}
}
}
xcb::FOCUS_IN => {
Expand Down Expand Up @@ -735,7 +742,10 @@ impl XWindow {

events.assign_window(Window::X11(XWindow::from_id(window_id)));

let appearance = conn.get_appearance();

Arc::new(Mutex::new(XWindowInner {
appearance,
window_id,
conn: Rc::downgrade(&conn),
events,
Expand Down
Loading

0 comments on commit a697b30

Please sign in to comment.