Skip to content

Commit 197cb10

Browse files
committed
wip
1 parent 9d2f569 commit 197cb10

9 files changed

Lines changed: 155 additions & 108 deletions

File tree

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,6 @@ missing-safety-doc = "allow"
9999

100100
[package.metadata.docs.rs]
101101
all-features = true
102+
103+
[workspace.dependencies]
104+
tracing-subscriber = "0.3.23"

examples/render_femtovg/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ edition = "2021"
55
publish = false
66

77
[dependencies]
8-
baseview = { path = "../..", features = ["opengl"] }
8+
baseview = { path = "../..", features = ["opengl", "tracing"] }
99
femtovg = "0.25.1"
10+
tracing-subscriber = { workspace = true }

examples/render_femtovg/src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ impl WindowHandler for FemtovgExample {
116116
}
117117

118118
fn main() -> Result<(), baseview::Error> {
119+
tracing_subscriber::fmt::init();
120+
119121
let window_open_options = WindowOpenOptions::new()
120122
.with_title("Femtovg on Baseview")
121123
.with_size(LogicalSize::new(512, 512))

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,6 @@ pub use window::*;
2525
pub use window_open_options::*;
2626

2727
#[allow(unused)]
28-
pub(crate) use tracing::warn;
28+
pub(crate) use tracing::*;
2929

3030
pub(crate) mod wrappers;

src/platform/x11/error.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ impl From<calloop::Error> for Error {
105105
}
106106
}
107107

108+
impl From<RecvError> for Error {
109+
fn from(value: RecvError) -> Self {
110+
Self::Channel(value)
111+
}
112+
}
113+
108114
#[cfg(feature = "opengl")]
109115
impl From<crate::wrappers::xlib::XLibError> for Error {
110116
fn from(value: crate::wrappers::xlib::XLibError) -> Self {

src/platform/x11/event_loop.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use super::*;
44
use std::result::Result;
55

66
use crate::warn;
7-
use crate::wrappers::connection_poller::{ConnectionPoller, PollStatus};
87
use crate::wrappers::xkbcommon::XkbcommonState;
98
use crate::{Event, MouseButton, MouseEvent, ScrollDelta, WindowEvent, WindowHandler, WindowSize};
109
use calloop::generic::Generic;
@@ -37,20 +36,20 @@ impl EventLoop {
3736
pub fn new(
3837
window: Rc<WindowInner>, handler: Box<dyn WindowHandler>,
3938
inner: &mut calloop::EventLoop<'static, Self>,
40-
) -> Self {
39+
) -> Result<Self, Error> {
4140
let loop_handle = inner.handle();
4241
let frame_timer = loop_handle
4342
.insert_source(Timer::from_duration(FRAME_INTERVAL), |i, _, e| e.handle_frame(i))
44-
.unwrap();
43+
.map_err(|e| e.error)?;
4544

4645
loop_handle
4746
.insert_source(
4847
Generic::new_with_error(window.connection.conn.clone(), Interest::READ, Mode::Edge),
4948
|_, _, e| e.handle_connection_event_ready(),
5049
)
51-
.unwrap();
50+
.map_err(|e| e.error)?;
5251

53-
Self {
52+
Ok(Self {
5453
loop_handle,
5554
loop_signal: inner.get_signal(),
5655
handler,
@@ -59,7 +58,7 @@ impl EventLoop {
5958
drag_n_drop: DragNDropState::NoCurrentSession,
6059
xkb_state: XkbcommonState::new(&window.connection),
6160
window,
62-
}
61+
})
6362
}
6463

6564
pub fn window_id(&self) -> NonZeroU32 {
@@ -139,8 +138,8 @@ impl EventLoop {
139138
}
140139
}
141140

142-
pub fn run(&mut self, mut inner: calloop::EventLoop<Self>) -> Result<(), Error> {
143-
inner.run(None, self, Self::handle_idle)?;
141+
pub fn run(mut self, mut inner: calloop::EventLoop<Self>) -> Result<(), Error> {
142+
inner.run(None, &mut self, Self::handle_idle)?;
144143

145144
Ok(())
146145
}

src/platform/x11/window.rs

Lines changed: 2 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,6 @@
1-
use std::cell::Cell;
2-
use std::num::NonZero;
3-
use std::sync::atomic::{AtomicBool, Ordering};
4-
use std::sync::mpsc;
5-
use std::sync::Arc;
6-
use std::thread::{self, JoinHandle};
1+
use crate::platform::x11::window_thread::WindowThreadHandle;
72

8-
use crate::handler::WindowHandlerBuilder;
9-
use crate::platform::Result;
10-
use crate::*;
11-
12-
pub struct WindowHandle {
13-
window_id: Option<NonZero<x11rb::protocol::xproto::Window>>,
14-
event_loop_handle: Cell<Option<JoinHandle<()>>>,
15-
close_requested: Arc<AtomicBool>,
16-
is_open: Arc<AtomicBool>,
17-
}
18-
19-
impl WindowHandle {
20-
pub fn create_window(
21-
options: WindowOpenOptions, handler: WindowHandlerBuilder,
22-
) -> Result<WindowHandle> {
23-
let (tx, rx) = mpsc::sync_channel::<WindowOpenResult>(1);
24-
let (parent_handle, mut window_handle) = ParentHandle::new();
25-
26-
let join_handle =
27-
thread::spawn(move || match create_window(options, handler, Some(parent_handle)) {
28-
Ok(ev_loop) => {
29-
tx.send(Ok(ev_loop.window_id())).unwrap();
30-
ev_loop.run().unwrap();
31-
}
32-
Err(e) => {
33-
tx.send(Err(format!("{}", e))).unwrap();
34-
}
35-
});
36-
37-
let id = match rx.recv() {
38-
Ok(Ok(id)) => id,
39-
Err(e) => return Err(super::Error::Channel(e)),
40-
Ok(Err(s)) => return Err(super::error::Error::CreationFailed(s)),
41-
};
42-
43-
window_handle.window_id = Some(id);
44-
window_handle.event_loop_handle = Some(join_handle).into();
45-
Ok(window_handle)
46-
}
47-
48-
pub fn run_until_closed(self) {
49-
let Some(thread) = self.event_loop_handle.take() else { return };
50-
51-
thread.join().unwrap_or_else(|err| {
52-
eprintln!("Window thread panicked: {:#?}", err);
53-
});
54-
}
55-
56-
pub fn is_open(&self) -> bool {
57-
self.is_open.load(Ordering::Relaxed)
58-
}
59-
}
60-
61-
impl Drop for WindowHandle {
62-
fn drop(&mut self) {
63-
self.close_requested.store(true, Ordering::Relaxed);
64-
if let Some(event_loop) = self.event_loop_handle.take() {
65-
let _ = event_loop.join();
66-
}
67-
}
68-
}
69-
70-
pub(crate) struct ParentHandle {
71-
close_requested: Arc<AtomicBool>,
72-
is_open: Arc<AtomicBool>,
73-
}
74-
75-
impl ParentHandle {
76-
pub fn new() -> (Self, WindowHandle) {
77-
let close_requested = Arc::new(AtomicBool::new(false));
78-
let is_open = Arc::new(AtomicBool::new(true));
79-
let handle = WindowHandle {
80-
window_id: None,
81-
event_loop_handle: None.into(),
82-
close_requested: Arc::clone(&close_requested),
83-
is_open: Arc::clone(&is_open),
84-
};
85-
86-
(Self { close_requested, is_open }, handle)
87-
}
88-
89-
pub fn parent_did_drop(&self) -> bool {
90-
self.close_requested.load(Ordering::Relaxed)
91-
}
92-
}
93-
94-
impl Drop for ParentHandle {
95-
fn drop(&mut self) {
96-
self.is_open.store(false, Ordering::Relaxed);
97-
}
98-
}
3+
pub type WindowHandle = WindowThreadHandle;
994

1005
pub fn copy_to_clipboard(_data: &str) {
1016
todo!()

src/platform/x11/window_thread.rs

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
use super::*;
2+
use crate::handler::WindowHandlerBuilder;
3+
use crate::platform::x11::event_loop::EventLoop;
4+
use crate::platform::x11::window_shared::WindowInner;
5+
use crate::{WindowContext, WindowOpenOptions};
6+
use calloop::LoopSignal;
7+
use std::cell::Cell;
8+
use std::num::NonZeroU32;
9+
use std::panic::resume_unwind;
10+
use std::rc::Rc;
11+
use std::sync::mpsc;
12+
use std::thread;
13+
use std::thread::JoinHandle;
14+
use std::time::Duration;
15+
16+
pub struct WindowThreadHandle {
17+
window_id: NonZeroU32,
18+
event_loop_handle: Cell<Option<JoinHandle<()>>>,
19+
}
20+
21+
impl WindowThreadHandle {
22+
pub fn create_window(
23+
options: WindowOpenOptions, handler: WindowHandlerBuilder,
24+
) -> Result<Self> {
25+
let (tx, rx) = result_channel();
26+
27+
let join_handle = thread::spawn(move || {
28+
let thread = match WindowThread::create(options, handler) {
29+
Err(e) => return tx.send_error(e),
30+
Ok(thread) => thread,
31+
};
32+
33+
if tx.send_success(&thread) {
34+
thread.run()
35+
}
36+
});
37+
38+
thread::sleep(Duration::from_millis(2000));
39+
40+
rx.receive(join_handle)
41+
}
42+
43+
pub fn run_until_closed(self) {
44+
let Some(thread) = self.event_loop_handle.take() else { return };
45+
46+
if let Err(panic) = thread.join() {
47+
resume_unwind(panic);
48+
}
49+
}
50+
51+
pub fn is_open(&self) -> bool {
52+
todo!()
53+
}
54+
}
55+
56+
impl Drop for WindowThreadHandle {
57+
fn drop(&mut self) {
58+
// TODO: stop event loop
59+
if let Some(event_loop) = self.event_loop_handle.take() {
60+
let _ = event_loop.join();
61+
}
62+
}
63+
}
64+
65+
enum WindowOpenResult {
66+
Success { window_id: NonZeroU32, loop_signal: LoopSignal },
67+
Error(String),
68+
}
69+
70+
struct WindowThread {
71+
event_loop: EventLoop,
72+
ev_loop: calloop::EventLoop<'static, EventLoop>,
73+
}
74+
75+
impl WindowThread {
76+
pub fn create(options: WindowOpenOptions, handler: WindowHandlerBuilder) -> Result<Self> {
77+
let mut ev_loop = calloop::EventLoop::try_new()?;
78+
let inner = WindowInner::create(options)?;
79+
let handler = handler.build(WindowContext::new(Rc::clone(&inner)))?;
80+
let event_loop = EventLoop::new(inner, handler, &mut ev_loop)?;
81+
82+
Ok(Self { event_loop, ev_loop })
83+
}
84+
85+
pub fn run(self) {
86+
self.event_loop.run(self.ev_loop).unwrap();
87+
}
88+
}
89+
90+
fn result_channel() -> (WindowResultSender, WindowResultReceiver) {
91+
let (tx, rx) = mpsc::sync_channel::<WindowOpenResult>(1);
92+
(WindowResultSender(tx), WindowResultReceiver(rx))
93+
}
94+
95+
struct WindowResultSender(mpsc::SyncSender<WindowOpenResult>);
96+
impl WindowResultSender {
97+
pub fn send_error(self, error: Error) {
98+
if let Err(err) = self.0.send(WindowOpenResult::Error(format!("{}", error))) {
99+
crate::error!("Window creation failed: {}", error);
100+
crate::warn!("Failed to send error to main thread: {err}");
101+
}
102+
}
103+
104+
pub fn send_success(self, thread: &WindowThread) -> bool {
105+
let msg = WindowOpenResult::Success {
106+
loop_signal: thread.ev_loop.get_signal(),
107+
window_id: thread.event_loop.window_id(),
108+
};
109+
110+
if let Err(err) = self.0.send(msg) {
111+
crate::error!("Failed to send created window to main thread: {}. Aborting.", err);
112+
return false;
113+
}
114+
115+
true
116+
}
117+
}
118+
119+
struct WindowResultReceiver(mpsc::Receiver<WindowOpenResult>);
120+
impl WindowResultReceiver {
121+
pub fn receive(self, join_handle: JoinHandle<()>) -> Result<WindowThreadHandle> {
122+
let result = self.0.recv()?;
123+
match result {
124+
WindowOpenResult::Error(e) => Err(Error::CreationFailed(e)),
125+
WindowOpenResult::Success { window_id, loop_signal } => {
126+
Ok(WindowThreadHandle { event_loop_handle: Some(join_handle).into(), window_id })
127+
}
128+
}
129+
}
130+
}

src/tracing.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#[cfg(feature = "tracing")]
2-
pub use tracing::*;
2+
pub use tracing::{error, warn};
33

44
#[cfg(not(feature = "tracing"))]
55
mod tracing_impl {
@@ -13,6 +13,7 @@ mod tracing_impl {
1313
}
1414

1515
pub(crate) use __warn as warn;
16+
pub(crate) use __warn as error;
1617
}
1718

1819
#[cfg(not(feature = "tracing"))]

0 commit comments

Comments
 (0)