Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions crates/gpui_linux/src/linux/x11/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,13 @@ impl X11Client {
if !state.has_xim() {
return;
}
// CreateIc is only valid once the handshake's OpenReply has assigned
// the input method id. The handshake creates the first input context
// itself; creating one earlier names input method 0, which fcitx5
// answers with an XIM_ERROR the client cannot parse, which drops XIM.
if !xim_handshake_complete(state.xim_handler.as_ref()) {
return;
}

let Some((mut ximc, xim_handler)) = state.take_xim() else {
return;
Expand Down Expand Up @@ -2530,6 +2537,21 @@ enum DpiMode {
NotSet,
}

/// GDK scales windows by whole numbers only. A value that is not a positive
/// whole number is left to the other sources rather than guessed at.
fn parse_gdk_scale(value: &str) -> Option<f32> {
match value.trim().parse::<u32>() {
Ok(scale) if scale > 0 => Some(scale as f32),
_ => None,
}
}

/// Whether the XIM handshake has created its input context, so that a focused
/// window may create its own.
fn xim_handshake_complete(handler: Option<&XimHandler>) -> bool {
handler.is_some_and(|handler| handler.connected)
}

fn get_scale_factor(
connection: &XCBConnection,
resource_database: &Database,
Expand Down Expand Up @@ -2596,6 +2618,17 @@ fn get_scale_factor(
return scale;
}

// Xft.dpi wins above, so only sessions that would have guessed a DPI
// change. A compositor that leaves XWayland unscaled states the scale in
// GDK_SCALE and often sets no Xft.dpi.
if let Some(scale) = std::env::var("GDK_SCALE")
.ok()
.and_then(|value| parse_gdk_scale(&value))
{
log::info!("Using scale factor from GDK_SCALE: {}", scale);
return scale;
}

if let Some(scale) = get_randr_scale_factor(connection, screen_index) {
log::info!("Using RandR scale factor: {}", scale);
return scale;
Expand Down Expand Up @@ -2813,6 +2846,28 @@ fn xkb_state_for_key_event(xkb: &xkbc::State, event_state: xproto::KeyButMask) -
mod tests {
use super::*;

#[test]
fn a_whole_gdk_scale_is_the_scale_factor() {
assert_eq!(parse_gdk_scale("2"), Some(2.0));
assert_eq!(parse_gdk_scale(" 1 "), Some(1.0));
}

#[test]
fn a_gdk_scale_that_is_not_a_positive_whole_number_is_ignored() {
for value in ["", "0", "1.5", "-2", "auto"] {
assert_eq!(parse_gdk_scale(value), None, "{value:?}");
}
}

#[test]
fn focus_waits_for_the_xim_handshake() {
assert!(!xim_handshake_complete(None));
assert!(!xim_handshake_complete(Some(&XimHandler::new())));
let mut handler = XimHandler::new();
handler.connected = true;
assert!(xim_handshake_complete(Some(&handler)));
}

fn test_keymap(layouts: &str) -> xkbc::Keymap {
test_keymap_with_variant(layouts, "")
}
Expand Down
Loading