Skip to content

Commit 08cd603

Browse files
committed
feat(WR): fix C-g on Unix
Tested on wayland/x11 Unix.
1 parent 4fc8955 commit 08cd603

File tree

11 files changed

+215
-57
lines changed

11 files changed

+215
-57
lines changed

Cargo.lock

Lines changed: 19 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust_src/crates/webrender/Cargo.in

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ tokio = { version = "1.23", features = ["rt-multi-thread", "sync", "net", "macro
2626
futures = "0.3.25"
2727
winit = { version = "0.27.5", default-features = false }
2828
fontdb = "0.12"
29+
raw-window-handle = "0.5"
2930
errno = "0.2"
3031
spin_sleep = { version = "1.1", optional = true }
3132
surfman = "0.4.4"
@@ -51,13 +52,19 @@ cfg_aliases = "0.1"
5152

5253
[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies]
5354
font-loader = "0.11"
55+
wayland-sys = {version = "0.30", features = ["client", "dlopen"]}
56+
57+
[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies.x11]
58+
features = ["xlib"]
59+
version = "2.20"
60+
optional = true
5461

5562
[target.'cfg(target_os = "macos")'.dependencies]
5663
core-foundation = "0.9.2"
5764

5865
[features]
5966
default = ["wayland", @WEBRENDER_DEFAULT_FEATURES@]
60-
x11 = ["copypasta/x11", "surfman/sm-x11", "winit/x11"]
67+
x11 = ["dep:x11", "copypasta/x11", "surfman/sm-x11", "winit/x11"]
6168
wayland = ["copypasta/wayland", "winit/wayland"]
6269
capture=["webrender/capture", "webrender/serialize_program"]
6370
sw_compositor=["webrender/sw_compositor"]

rust_src/crates/webrender/build.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use ng_bindgen::{generate_crate_exports, BuildError};
55

66
fn main() {
77
println!("cargo:rerun-if-changed=build.rs");
8+
println!("cargo:rerun-if-changed=src/wrterm.rs");
9+
println!("cargo:rerun-if-changed=src/event_loop.rs");
810
// TODO watch relevent files to re rerun, rs files under src?
911

1012
let path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));

rust_src/crates/webrender/src/display_info.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use libc;
2+
use raw_window_handle::RawDisplayHandle;
23
use std::{collections::HashMap, ptr};
34
use winit::window::WindowId;
45

@@ -21,6 +22,10 @@ pub struct DisplayInfoInner {
2122
pub scratch_cursor_gc: Box<Emacs_GC>,
2223

2324
pub fringe_bitmap_caches: HashMap<i32, FringeBitmap>,
25+
26+
pub connection: Option<surfman::Connection>,
27+
28+
pub raw_display_handle: Option<RawDisplayHandle>,
2429
}
2530

2631
impl Default for DisplayInfoInner {
@@ -36,6 +41,8 @@ impl Default for DisplayInfoInner {
3641
}),
3742

3843
fringe_bitmap_caches: HashMap::new(),
44+
connection: None,
45+
raw_display_handle: None,
3946
}
4047
}
4148
}

rust_src/crates/webrender/src/event_loop.rs

Lines changed: 78 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::select::handle_select;
2+
use raw_window_handle::{HasRawDisplayHandle, RawDisplayHandle};
23
use std::{
3-
sync::Mutex,
4+
cell::RefCell,
5+
sync::{Arc, Mutex},
46
time::{Duration, Instant},
57
};
68

@@ -17,7 +19,7 @@ use copypasta::{
1719

1820
use libc::{c_void, fd_set, pselect, sigset_t, timespec};
1921
use once_cell::sync::Lazy;
20-
#[cfg(wayland_platform)]
22+
#[cfg(free_unix)]
2123
use winit::platform::wayland::EventLoopWindowTargetExtWayland;
2224
use winit::{
2325
event::{Event, StartCause, WindowEvent},
@@ -49,7 +51,7 @@ unsafe impl Send for Platform {}
4951

5052
pub struct WrEventLoop {
5153
clipboard: Box<dyn ClipboardProvider>,
52-
pub el: EventLoop<i32>,
54+
el: EventLoop<i32>,
5355
pub connection: Option<Connection>,
5456
}
5557

@@ -61,19 +63,16 @@ impl WrEventLoop {
6163
&self.el
6264
}
6365

64-
pub fn connection(&mut self) -> &Connection {
65-
if self.connection.is_none() {
66-
self.open_native_display();
67-
}
68-
self.connection.as_ref().unwrap()
69-
}
70-
7166
pub fn create_proxy(&self) -> EventLoopProxy<i32> {
7267
self.el.create_proxy()
7368
}
7469

75-
pub fn new_webrender_surfman(&mut self, window: &Window) -> WebrenderSurfman {
76-
let connection = self.connection();
70+
pub fn new_webrender_surfman(
71+
&mut self,
72+
window: &Window,
73+
connection: Option<&Connection>,
74+
) -> WebrenderSurfman {
75+
let connection = connection.expect("device not open");
7776
let adapter = connection
7877
.create_adapter()
7978
.expect("Failed to create adapter");
@@ -87,17 +86,16 @@ impl WrEventLoop {
8786
webrender_surfman
8887
}
8988

90-
pub fn open_native_display(&mut self) -> &Option<Connection> {
89+
pub fn open_native_display(&mut self) -> (Connection, RawDisplayHandle) {
9190
let window_builder = winit::window::WindowBuilder::new().with_visible(false);
9291
let window = window_builder.build(&self.el).unwrap();
92+
let rwh = window.raw_display_handle();
9393

9494
// Initialize surfman
9595
let connection =
9696
Connection::from_winit_window(&window).expect("Failed to create connection");
9797

98-
self.connection = Some(connection);
99-
100-
&self.connection
98+
(connection, rwh)
10199
}
102100

103101
pub fn wait_for_window_resize(&mut self, target_window_id: WindowId) {
@@ -160,16 +158,16 @@ fn build_clipboard(_event_loop: &EventLoop<i32>) -> Box<dyn ClipboardProvider> {
160158
}
161159
}
162160

163-
pub static EVENT_LOOP: Lazy<Mutex<WrEventLoop>> = Lazy::new(|| {
161+
pub static EVENT_LOOP: Lazy<Arc<Mutex<WrEventLoop>>> = Lazy::new(|| {
164162
let el = winit::event_loop::EventLoopBuilder::<i32>::with_user_event().build();
165163
let clipboard = build_clipboard(&el);
166164
let connection = None;
167165

168-
Mutex::new(WrEventLoop {
166+
Arc::new(Mutex::new(WrEventLoop {
169167
clipboard,
170168
el,
171169
connection,
172-
})
170+
}))
173171
});
174172

175173
pub static EVENT_BUFFER: Lazy<Mutex<Vec<GUIEvent>>> = Lazy::new(|| Mutex::new(Vec::new()));
@@ -183,7 +181,13 @@ pub extern "C" fn wr_select(
183181
timeout: *mut timespec,
184182
_sigmask: *mut sigset_t,
185183
) -> i32 {
186-
if unsafe { inhibit_window_system } {
184+
let lock_result = EVENT_LOOP.try_lock();
185+
186+
if lock_result.is_err() || unsafe { inhibit_window_system } {
187+
if lock_result.is_err() {
188+
log::debug!("Failed to grab a lock {:?}", lock_result.err());
189+
}
190+
187191
return unsafe {
188192
thread_select(
189193
Some(pselect),
@@ -197,5 +201,58 @@ pub extern "C" fn wr_select(
197201
};
198202
}
199203

200-
handle_select(nfds, readfds, writefds, _exceptfds, timeout, _sigmask)
204+
let mut event_loop = lock_result.unwrap();
205+
206+
handle_select(
207+
&mut event_loop.el,
208+
nfds,
209+
readfds,
210+
writefds,
211+
_exceptfds,
212+
timeout,
213+
_sigmask,
214+
)
215+
}
216+
217+
// Polling C-g when emacs is blocked
218+
pub fn poll_a_event(timeout: Duration) -> Option<GUIEvent> {
219+
log::trace!("poll a event {:?}", timeout);
220+
let result = EVENT_LOOP.try_lock();
221+
if result.is_err() {
222+
log::trace!("failed to grab a EVENT_LOOP lock");
223+
return None;
224+
}
225+
let mut event_loop = result.unwrap();
226+
let deadline = Instant::now() + timeout;
227+
let result = RefCell::new(None);
228+
event_loop.el.run_return(|e, _target, control_flow| {
229+
control_flow.set_wait_until(deadline);
230+
231+
if let Event::WindowEvent { event, .. } = &e {
232+
log::trace!("{:?}", event);
233+
}
234+
235+
match e {
236+
Event::WindowEvent { ref event, .. } => match event {
237+
WindowEvent::Resized(_)
238+
| WindowEvent::KeyboardInput { .. }
239+
| WindowEvent::ReceivedCharacter(_)
240+
| WindowEvent::ModifiersChanged(_)
241+
| WindowEvent::MouseInput { .. }
242+
| WindowEvent::CursorMoved { .. }
243+
| WindowEvent::Focused(_)
244+
| WindowEvent::MouseWheel { .. }
245+
| WindowEvent::CloseRequested => {
246+
result.replace(Some(e.to_static().unwrap()));
247+
control_flow.set_exit();
248+
}
249+
_ => {}
250+
},
251+
Event::RedrawEventsCleared => {
252+
control_flow.set_exit();
253+
}
254+
_ => {}
255+
};
256+
});
257+
result.into_inner()
201258
}

rust_src/crates/webrender/src/frame.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub fn create_frame(
3636
frame.set_output_method(output_method::output_wr);
3737

3838
let mut event_loop = EVENT_LOOP.lock().unwrap();
39-
let mut output = Box::new(Output::build(&mut event_loop, frame));
39+
let mut output = Box::new(Output::build(&mut event_loop, dpyinfo, frame));
4040

4141
let window_id = output.get_window().id();
4242

rust_src/crates/webrender/src/output.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,11 @@ pub struct Output {
8888
}
8989

9090
impl Output {
91-
pub fn build(event_loop: &mut WrEventLoop, frame: LispFrameRef) -> Self {
91+
pub fn build(
92+
event_loop: &mut WrEventLoop,
93+
dpyinfo: DisplayInfoRef,
94+
frame: LispFrameRef,
95+
) -> Self {
9296
let window_builder = winit::window::WindowBuilder::new().with_visible(true);
9397

9498
#[cfg(wayland_platform)]
@@ -99,7 +103,9 @@ impl Output {
99103
};
100104

101105
let window = window_builder.build(&event_loop.el()).unwrap();
102-
let webrender_surfman = event_loop.new_webrender_surfman(&window);
106+
let dpyinfo_ref = dpyinfo.get_inner();
107+
let connection = dpyinfo_ref.connection.as_ref();
108+
let webrender_surfman = event_loop.new_webrender_surfman(&window, connection);
103109

104110
// Get GL bindings
105111
let gl = match webrender_surfman.connection().gl_api() {

0 commit comments

Comments
 (0)