Skip to content
Draft
Show file tree
Hide file tree
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
8 changes: 5 additions & 3 deletions src/platform_impl/linux/x11/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1814,9 +1814,11 @@ impl UnownedWindow {
.unwrap_or_default();

wm_hints.urgent = request_type.is_some();
wm_hints
.set(self.xconn.xcb_connection(), self.xwindow as xproto::Window)
.expect_then_ignore_error("Failed to set WM hints");
if let Ok(cookie) =
wm_hints.set(self.xconn.xcb_connection(), self.xwindow as xproto::Window)
{
cookie.ignore_error();
}
}

#[inline]
Expand Down
74 changes: 74 additions & 0 deletions tests/x11_user_attention.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#![cfg(all(target_os = "linux", feature = "x11"))]

use std::io::{BufRead, BufReader};
use std::process::{Command, Stdio};
use std::time::Duration;

use winit::application::ApplicationHandler;
use winit::event::WindowEvent;
use winit::event_loop::{ActiveEventLoop, EventLoop};
use winit::platform::pump_events::EventLoopExtPumpEvents;
use winit::platform::x11::EventLoopBuilderExtX11;
use winit::window::{UserAttentionType, Window, WindowId};

#[derive(Default)]
struct App {
window: Option<Window>,
}

impl ApplicationHandler for App {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
self.window = Some(event_loop.create_window(Window::default_attributes()).unwrap());
}

fn window_event(
&mut self,
_event_loop: &ActiveEventLoop,
_window_id: WindowId,
_event: WindowEvent,
) {
}
}

#[test]
fn requesting_attention_after_x11_disconnect_does_not_panic() {
let mut server = match Command::new("Xvfb")
.args(["-displayfd", "1", "-nolisten", "tcp"])
.stdout(Stdio::piped())
.stderr(Stdio::null())
.spawn()
{
Ok(server) => server,
Err(error) if error.kind() == std::io::ErrorKind::NotFound => return,
Err(error) => panic!("failed to start Xvfb: {error}"),
};

let mut display = String::new();
BufReader::new(server.stdout.take().unwrap()).read_line(&mut display).unwrap();
let mut builder = EventLoop::builder();
builder.with_x11().with_any_thread(true);
let mut event_loop = {
let previous_display = std::env::var_os("DISPLAY");
std::env::set_var("DISPLAY", format!(":{}", display.trim()));
let result = builder.build().unwrap();
if let Some(previous_display) = previous_display {
std::env::set_var("DISPLAY", previous_display);
} else {
std::env::remove_var("DISPLAY");
}
result
};

let mut app = App::default();
event_loop.pump_app_events(Some(Duration::ZERO), &mut app);
let window = app.window.take().unwrap();
window.request_user_attention(Some(UserAttentionType::Informational));

server.kill().unwrap();
server.wait().unwrap();
window.request_user_attention(Some(UserAttentionType::Informational));
// Xlib may try to use the dead connection while destroying the window and event loop.

std::mem::forget(window);
std::mem::forget(event_loop);
}
Loading