From f6f2bcd024146678c7c206903453974cd0f392dc Mon Sep 17 00:00:00 2001 From: Barret Rennie Date: Sat, 21 Oct 2017 17:03:58 -0600 Subject: [PATCH] Set urgent WM flag on bell on X11 systems (#812) Sets the urgent WM flag when bell is emitted on X11 systems. Additionally, the flag is cleared on focus because not all WMs clear it automatically. --- src/display.rs | 8 ++++++++ src/event.rs | 9 +++++++++ src/term/mod.rs | 3 +++ src/window.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+) diff --git a/src/display.rs b/src/display.rs index bdd9a9f2..fc5a5d40 100644 --- a/src/display.rs +++ b/src/display.rs @@ -322,6 +322,14 @@ impl Display { self.window.set_title(&title); } + if let Some(is_urgent) = terminal.next_is_urgent.take() { + // We don't need to set the urgent flag if we already have the + // user's attention. + if !is_urgent || !self.window.is_focused { + self.window.set_urgent(is_urgent); + } + } + let size_info = *terminal.size_info(); let visual_bell_intensity = terminal.visual_bell.intensity(); diff --git a/src/event.rs b/src/event.rs index dda18652..0a79e804 100644 --- a/src/event.rs +++ b/src/event.rs @@ -251,6 +251,7 @@ impl Processor { ref_test: bool, resize_tx: &mpsc::Sender<(u32, u32)>, hide_cursor: &mut bool, + window_is_focused: &mut bool, ) { match event { // Pass on device events @@ -322,8 +323,11 @@ impl Processor { processor.ctx.terminal.dirty = true; }, Focused(is_focused) => { + *window_is_focused = is_focused; + if is_focused { processor.ctx.terminal.dirty = true; + processor.ctx.terminal.next_is_urgent = Some(false); } else { *hide_cursor = false; } @@ -395,6 +399,8 @@ impl Processor { mouse_bindings: &self.mouse_bindings[..], }; + let mut window_is_focused = window.is_focused; + // Scope needed to that hide_cursor isn't borrowed after the scope // ends. { @@ -409,6 +415,7 @@ impl Processor { ref_test, resize_tx, hide_cursor, + &mut window_is_focused, ); }; @@ -423,6 +430,8 @@ impl Processor { window.set_cursor_visible(!self.hide_cursor); } + window.is_focused = window_is_focused; + if processor.ctx.selection_modified { processor.ctx.terminal.dirty = true; } diff --git a/src/term/mod.rs b/src/term/mod.rs index 97460421..59cf6baf 100644 --- a/src/term/mod.rs +++ b/src/term/mod.rs @@ -689,6 +689,7 @@ pub struct Term { pub dirty: bool, pub visual_bell: VisualBell, + pub next_is_urgent: Option, /// Saved cursor from main grid cursor_save: Cursor, @@ -791,6 +792,7 @@ impl Term { next_title: None, dirty: false, visual_bell: VisualBell::new(config), + next_is_urgent: None, input_needs_wrap: false, grid: grid, alt_grid: alt, @@ -1459,6 +1461,7 @@ impl ansi::Handler for Term { fn bell(&mut self) { trace!("bell"); self.visual_bell.ring(); + self.next_is_urgent = Some(true); } #[inline] diff --git a/src/window.rs b/src/window.rs index f24def3a..a50daf87 100644 --- a/src/window.rs +++ b/src/window.rs @@ -39,6 +39,9 @@ pub struct Window { event_loop: EventsLoop, window: glutin::GlWindow, cursor_visible: bool, + + /// Whether or not the window is the focused window. + pub is_focused: bool, } /// Threadsafe APIs for the window @@ -204,6 +207,7 @@ impl Window { event_loop: event_loop, window: window, cursor_visible: true, + is_focused: true, }; window.run_os_extensions(); @@ -307,6 +311,43 @@ impl Window { pub fn platform_window_init() { } + #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))] + pub fn set_urgent(&self, is_urgent: bool) { + use glutin::os::unix::WindowExt; + use std::os::raw; + use x11_dl::xlib::{self, XUrgencyHint}; + + let xlib_display = self.window.get_xlib_display(); + let xlib_window = self.window.get_xlib_window(); + + if let (Some(xlib_window), Some(xlib_display)) = (xlib_window, xlib_display) { + let xlib = xlib::Xlib::open().expect("get xlib"); + + unsafe { + let mut hints = (xlib.XGetWMHints)(xlib_display as _, xlib_window as _); + + if hints.is_null() { + hints = (xlib.XAllocWMHints)(); + } + + if is_urgent { + (*hints).flags |= XUrgencyHint; + } else { + (*hints).flags &= !XUrgencyHint; + } + + (xlib.XSetWMHints)(xlib_display as _, xlib_window as _, hints); + + (xlib.XFree)(hints as *mut raw::c_void); + } + } + + } + + #[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd")))] + pub fn set_urgent(&self, is_urgent: bool) { + } + #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))] pub fn send_xim_spot(&self, x: i16, y: i16) { use glutin::os::unix::WindowExt;