linux/x11: use a channel for quit signal

This commit is contained in:
Thorsten Ball
2024-06-27 18:01:59 +02:00
parent 3956717065
commit feb7efff4e
4 changed files with 53 additions and 15 deletions

View File

@@ -22,7 +22,7 @@ impl HeadlessClient {
pub(crate) fn new() -> Self {
let event_loop = EventLoop::try_new().unwrap();
let (common, main_receiver) = LinuxCommon::new(event_loop.get_signal());
let (common, main_receiver) = LinuxCommon::new(Box::new(event_loop.get_signal()));
let handle = event_loop.handle();

View File

@@ -84,6 +84,16 @@ pub(crate) struct PlatformHandlers {
pub(crate) validate_app_menu_command: Option<Box<dyn FnMut(&dyn Action) -> bool>>,
}
pub trait QuitSignal {
fn quit(&mut self);
}
impl QuitSignal for LoopSignal {
fn quit(&mut self) {
self.stop();
}
}
pub(crate) struct LinuxCommon {
pub(crate) background_executor: BackgroundExecutor,
pub(crate) foreground_executor: ForegroundExecutor,
@@ -91,12 +101,12 @@ pub(crate) struct LinuxCommon {
pub(crate) appearance: WindowAppearance,
pub(crate) auto_hide_scrollbars: bool,
pub(crate) callbacks: PlatformHandlers,
pub(crate) signal: LoopSignal,
pub(crate) signal: Box<dyn QuitSignal>,
pub(crate) menus: Vec<OwnedMenu>,
}
impl LinuxCommon {
pub fn new(signal: LoopSignal) -> (Self, Channel<Runnable>) {
pub fn new(signal: Box<dyn QuitSignal>) -> (Self, Channel<Runnable>) {
let (main_sender, main_receiver) = calloop::channel::channel::<Runnable>();
let text_system = Arc::new(CosmicTextSystem::new());
let callbacks = PlatformHandlers::default();
@@ -146,7 +156,7 @@ impl<P: LinuxClient + 'static> Platform for P {
}
fn quit(&self) {
self.with_common(|common| common.signal.stop());
self.with_common(|common| common.signal.quit());
}
fn compositor_name(&self) -> &'static str {

View File

@@ -310,7 +310,7 @@ impl WaylandClientStatePtr {
}
}
if state.windows.is_empty() {
state.common.signal.stop();
state.common.signal.quit();
}
}
}
@@ -406,7 +406,7 @@ impl WaylandClient {
let event_loop = EventLoop::<WaylandClientStatePtr>::try_new().unwrap();
let (common, main_receiver) = LinuxCommon::new(event_loop.get_signal());
let (common, main_receiver) = LinuxCommon::new(Box::new(event_loop.get_signal()));
let handle = event_loop.handle();
handle

View File

@@ -8,10 +8,10 @@ use anyhow::Context;
use async_task::Runnable;
use calloop::channel::Channel;
use calloop::EventLoop;
use collections::HashMap;
use futures::channel::oneshot;
use util::ResultExt;
use x11rb::connection::{Connection, RequestConnection};
use x11rb::cursor;
@@ -32,7 +32,7 @@ use crate::platform::{LinuxCommon, PlatformWindow};
use crate::{
modifiers_from_xinput_info, point, px, AnyWindowHandle, Bounds, ClipboardItem, CursorStyle,
DisplayId, Keystroke, Modifiers, ModifiersChangedEvent, Pixels, PlatformDisplay, PlatformInput,
Point, ScrollDelta, Size, TouchPhase, WindowParams, X11Window,
Point, QuitSignal, ScrollDelta, Size, TouchPhase, WindowParams, X11Window,
};
use super::{
@@ -128,6 +128,8 @@ pub struct X11ClientState {
pub(crate) clipboard: x11_clipboard::Clipboard,
pub(crate) clipboard_item: Option<ClipboardItem>,
quit_signal_rx: oneshot::Receiver<()>,
runnables: Channel<Runnable>,
xdp_event_source: XDPEventSource,
}
@@ -150,7 +152,29 @@ impl X11ClientStatePtr {
state.cursor_styles.remove(&x_window);
if state.windows.is_empty() {
state.common.signal.stop();
state.common.signal.quit();
}
}
}
struct ChannelQuitSignal {
tx: Option<oneshot::Sender<()>>,
}
impl ChannelQuitSignal {
fn new() -> (Self, oneshot::Receiver<()>) {
let (tx, rx) = oneshot::channel::<()>();
let quit_signal = ChannelQuitSignal { tx: Some(tx) };
(quit_signal, rx)
}
}
impl QuitSignal for ChannelQuitSignal {
fn quit(&mut self) {
if let Some(tx) = self.tx.take() {
tx.send(()).log_err();
}
}
}
@@ -160,11 +184,9 @@ pub(crate) struct X11Client(Rc<RefCell<X11ClientState>>);
impl X11Client {
pub(crate) fn new() -> Self {
// TODO: We don't need this anymore.
let event_loop: calloop::EventLoop<X11Client> = EventLoop::try_new().unwrap();
let (quit_signal, quit_signal_rx) = ChannelQuitSignal::new();
// TODO: We need to send a quit signal in there.
let (common, runnables) = LinuxCommon::new(event_loop.get_signal());
let (common, runnables) = LinuxCommon::new(Box::new(quit_signal));
let (xcb_connection, x_root_index) = XCBConnection::connect(None).unwrap();
xcb_connection
@@ -268,6 +290,7 @@ impl X11Client {
X11Client(Rc::new(RefCell::new(X11ClientState {
runnables,
xdp_event_source,
quit_signal_rx,
common,
@@ -1072,7 +1095,12 @@ impl LinuxClient for X11Client {
fn run(&self) {
loop {
let mut sleep = true;
{
let mut state = self.0.borrow_mut();
if let Ok(Some(())) = state.quit_signal_rx.try_recv() {
return;
}
}
// Send expose events to windows that need refreshing
let mut windows_to_expose = HashSet::new();
@@ -1085,7 +1113,7 @@ impl LinuxClient for X11Client {
}
}
}
sleep = windows_to_expose.is_empty();
let mut sleep = windows_to_expose.is_empty();
let _ = self.send_window_expose_events(windows_to_expose).log_err();
// Read all X11 events and then handle them in a batch