Skip to content

Commit 740479b

Browse files
fix: improve terminal detection on Linux (#278)
1 parent d50ab12 commit 740479b

File tree

5 files changed

+29
-18
lines changed

5 files changed

+29
-18
lines changed

crates/fig_desktop/src/platform/linux/ibus.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,13 @@ pub async fn launch_ibus_connection(proxy: EventLoopProxy, platform_state: Arc<P
8080
active_input_contexts.remove(path.as_str());
8181
},
8282
"SetCursorLocation" => {
83-
if !active_input_contexts.contains(path.as_str()) {
83+
if !active_input_contexts.contains(path.as_str())
84+
|| platform_state.active_terminal.lock().is_none()
85+
{
8486
debug!("SetCursorLocation rejected on {}", path.as_str());
8587
continue;
8688
}
89+
8790
let body = match msg.body().deserialize::<(i32, i32, i32, i32)>() {
8891
Ok(body) => body,
8992
Err(err) => {

crates/fig_desktop/src/platform/linux/integrations.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,14 @@ pub static WM_CLASS_ALLOWLIST: Lazy<HashMap<&'static str, Terminal>> = Lazy::new
3737
pub static GSE_ALLOWLIST: Lazy<HashMap<&'static str, Terminal>> = Lazy::new(|| {
3838
let mut allowlist = HashMap::new();
3939
for terminal in fig_util::terminal::LINUX_TERMINALS {
40-
if let Some(gnome_id) = terminal.gnome_id() {
41-
allowlist.insert(gnome_id, terminal.clone());
40+
// Using wm_class_instance here since on Wayland, (most?) terminals set the app_id equal to
41+
// the WM_CLASS Instance part. To handle Xwayland terminals, we still want to include wm_class as
42+
// well.
43+
if let (Some(instance), Some(class)) = (terminal.wm_class_instance(), terminal.wm_class()) {
44+
allowlist.insert(instance, terminal.clone());
45+
if class != instance {
46+
allowlist.insert(class, terminal.clone());
47+
}
4248
}
4349
}
4450
allowlist
@@ -65,10 +71,11 @@ pub fn from_hook(hook: FocusedWindowDataHook, platform_state: &PlatformState, pr
6571
}
6672

6773
debug!("focus event on {} from {}", hook.id, hook.source);
68-
if from_source(&hook.source)
74+
if let Some(terminal) = from_source(&hook.source)
6975
.ok_or_else(|| anyhow!("received invalid focus window data source"))?
70-
.contains_key(hook.id.as_str())
76+
.get(hook.id.as_str())
7177
{
78+
*platform_state.0.active_terminal.lock() = Some(terminal.clone());
7279
let inner = hook.inner.unwrap();
7380
let outer = hook.outer.unwrap();
7481
let mut handle = platform_state.0.active_window_data.lock();
@@ -84,6 +91,7 @@ pub fn from_hook(hook: FocusedWindowDataHook, platform_state: &PlatformState, pr
8491
scale: hook.scale,
8592
});
8693
} else {
94+
*platform_state.0.active_terminal.lock() = None;
8795
proxy.send_event(Event::WindowEvent {
8896
window_id: AUTOCOMPLETE_ID,
8997
window_event: WindowEvent::Hide,

crates/fig_util/src/terminal.rs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -464,12 +464,14 @@ impl Terminal {
464464
}
465465
}
466466

467+
/// Returns the "Class" part of the WM_CLASS property.
467468
pub fn wm_class(&self) -> Option<&'static str> {
468469
match self {
469470
Terminal::VSCode => Some("Code"),
470471
Terminal::VSCodeInsiders => Some("Vscode-insiders"),
471472
Terminal::GnomeConsole => Some("Kgx"),
472473
Terminal::GnomeTerminal => Some("Gnome-terminal"),
474+
Terminal::Guake => Some("Guake"),
473475
Terminal::Hyper => Some("Hyper"),
474476
Terminal::Konsole => Some("konsole"),
475477
Terminal::Tilix => Some("Tilix"),
@@ -485,22 +487,18 @@ impl Terminal {
485487
}
486488
}
487489

488-
// corresponds to GSE source type
489-
pub fn gnome_id(&self) -> Option<&'static str> {
490+
/// Returns the "Instance" part of the WM_CLASS property.
491+
pub fn wm_class_instance(&self) -> Option<&'static str> {
490492
match self {
491-
// Terminal::Vscode => Some("Code"),
492-
// Terminal::VSCodeInsiders => Some("Code - Insiders"),
493+
Terminal::GnomeConsole => Some("org.gnome.Console"),
493494
Terminal::GnomeTerminal => Some("gnome-terminal-server"),
494-
// Terminal::Konsole => Some("org.kde.konsole"),
495-
Terminal::Tilix => Some("tilix"),
496-
Terminal::Alacritty => Some("Alacritty"),
497-
Terminal::Kitty => Some("kitty"),
498-
Terminal::XfceTerminal => Some("xfce4-terminal"),
495+
Terminal::Guake => Some("guake"),
496+
Terminal::Hyper => Some("hyper"),
499497
Terminal::Terminator => Some("terminator"),
500-
// Terminal::Terminology => Some("terminology"),
501-
// Terminal::WezTerm => Some("org.wezfurlong.wezterm"),
502-
// Terminal::Tabby => Some("tabby"),
503-
_ => None,
498+
Terminal::Tilix => Some("tilix"),
499+
// Many terminals seem to use the same name for both, falling back to Class name
500+
// as a default.
501+
_ => self.wm_class(),
504502
}
505503
}
506504

extensions/gnome-extension/src/extension.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,7 @@ export default class QCliExtension extends Extension {
701701
* @param {boolean} overlay_pressed
702702
*/
703703
#send_window_data(overlay_pressed) {
704+
// Mutter populates wm class/instance with the app_id on Wayland.
704705
const wm_class = this.#window.get_wm_class();
705706
// https://mutter.gnome.org/meta/method.Window.get_frame_rect.html
706707
const inner_rect = this.#window.get_frame_rect();

extensions/gnome-legacy-extension/src/extension.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,7 @@ class Extension extends GObject.Object {
727727
* @param {boolean} overlay_pressed
728728
*/
729729
#send_window_data(overlay_pressed) {
730+
// Mutter populates wm class/instance will the app_id on Wayland.
730731
const wm_class = this.#window.get_wm_class();
731732
// https://mutter.gnome.org/meta/method.Window.get_frame_rect.html
732733
const inner_rect = this.#window.get_frame_rect();

0 commit comments

Comments
 (0)