Skip to content

Commit a18c31b

Browse files
committed
wip
1 parent de19530 commit a18c31b

4 files changed

Lines changed: 192 additions & 32 deletions

File tree

examples/open_parented/src/main.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use baseview::dpi::LogicalSize;
1+
use baseview::dpi::{LogicalSize, PhysicalSize};
22
use baseview::{
33
Event, EventStatus, HandlerError, WindowContext, WindowHandle, WindowHandler,
44
WindowOpenOptions, WindowSize,
@@ -10,7 +10,7 @@ struct ParentWindowHandler {
1010
surface: RefCell<softbuffer::Surface<WindowContext, WindowContext>>,
1111
damaged: Cell<bool>,
1212

13-
_child_window: Option<WindowHandle>,
13+
child_window: WindowHandle,
1414
}
1515

1616
impl ParentWindowHandler {
@@ -27,11 +27,7 @@ impl ParentWindowHandler {
2727

2828
let child_window = baseview::create_window(window_open_options, ChildWindowHandler::new)?;
2929

30-
Ok(Self {
31-
surface: surface.into(),
32-
damaged: true.into(),
33-
_child_window: Some(child_window),
34-
})
30+
Ok(Self { surface: surface.into(), damaged: true.into(), child_window })
3531
}
3632
}
3733

@@ -58,6 +54,9 @@ impl WindowHandler for ParentWindowHandler {
5854
self.damaged.set(true);
5955
}
6056

57+
let child_size =
58+
PhysicalSize::new(new_size.physical.width / 2, new_size.physical.height / 2);
59+
self.child_window.resize(child_size.into())?;
6160
Ok(())
6261
}
6362

src/platform/x11/event_loop.rs

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ use super::keyboard::{convert_key_press_event, convert_key_release_event, key_mo
33
use super::*;
44
use std::result::Result;
55

6+
use crate::platform::x11::window_thread::{
7+
WindowThreadRequest, WindowThreadResponse, WindowThreadResponseMessage,
8+
};
69
use crate::warn;
710
use crate::wrappers::xkbcommon::XkbcommonState;
811
use crate::{Event, MouseButton, MouseEvent, ScrollDelta, WindowEvent, WindowHandler, WindowSize};
@@ -11,6 +14,7 @@ use calloop::timer::{TimeoutAction, Timer};
1114
use calloop::{Interest, LoopSignal, Mode, PostAction};
1215
use dpi::{PhysicalPosition, PhysicalSize};
1316
use std::rc::Rc;
17+
use std::sync::mpsc;
1418
use std::time::{Duration, Instant};
1519
use x11rb::connection::Connection;
1620
use x11rb::errors::ConnectionError;
@@ -28,13 +32,17 @@ pub(crate) struct EventLoop {
2832
xkb_state: Option<XkbcommonState>,
2933

3034
run_error: Option<Error>,
35+
36+
response_sender: mpsc::Sender<WindowThreadResponseMessage>,
3137
}
3238

3339
const FRAME_INTERVAL: Duration = Duration::from_millis(15);
3440

3541
impl EventLoop {
3642
pub fn new(
3743
window: Rc<WindowInner>, handler: Box<dyn WindowHandler>,
44+
request_receiver: calloop::channel::Channel<WindowThreadRequest>,
45+
response_sender: mpsc::Sender<WindowThreadResponseMessage>,
3846
inner: &mut calloop::EventLoop<'static, Self>,
3947
) -> Result<Self, Error> {
4048
let loop_handle = inner.handle();
@@ -50,6 +58,10 @@ impl EventLoop {
5058
)
5159
.map_err(|e| e.error)?;
5260

61+
loop_handle
62+
.insert_source(request_receiver, |e, _, l| l.handle_main_thread_request(e))
63+
.map_err(|e| e.error)?;
64+
5365
Ok(Self {
5466
loop_signal: inner.get_signal(),
5567
handler,
@@ -58,6 +70,7 @@ impl EventLoop {
5870
xkb_state: XkbcommonState::new(&window.connection),
5971
run_error: None,
6072
window,
73+
response_sender,
6174
})
6275
}
6376

@@ -73,21 +86,75 @@ impl EventLoop {
7386
}
7487

7588
if let Some(size) = self.new_physical_size.take() {
76-
let previous = self.window.window_size.replace(size);
89+
let previous = self.window.store_size(size);
7790

7891
let scale_factor = self.window.scaling_factor.get();
7992
if let Err(e) =
8093
self.handler.resized(WindowSize::from_physical(size.cast(), scale_factor))
8194
{
8295
warn!("Window Handler failed to resize: {}", e);
83-
self.window.window_size.set(previous);
96+
self.window.store_size(previous);
8497
self.window.xcb_window.resize(previous.cast())?.check_warn();
8598
}
8699
}
87100

88101
Ok(())
89102
}
90103

104+
fn handle_main_thread_request(&mut self, event: calloop::channel::Event<WindowThreadRequest>) {
105+
match event {
106+
calloop::channel::Event::Closed => {
107+
// Closed channel means the sender, i.e. the Window Handle has been dropped.
108+
// It should already stop this event loop on drop, but we'll take the hint.
109+
self.stop_now();
110+
}
111+
calloop::channel::Event::Msg(req) => match self.handle_request(req) {
112+
Ok(()) => self.send_response(Ok(WindowThreadResponse::Ok)),
113+
Err(e) => self.send_response(Err(e.to_string())),
114+
},
115+
}
116+
}
117+
118+
fn send_response(&mut self, response: WindowThreadResponseMessage) {
119+
if let Err(e) = self.response_sender.send(response) {
120+
warn!("Failed to send response back to main thread: {}", &e);
121+
if let Err(e) = e.0 {
122+
crate::error!("Request failed: {}", e)
123+
}
124+
125+
self.stop_now();
126+
}
127+
}
128+
129+
fn stop_now(&self) {
130+
self.loop_signal.stop();
131+
self.loop_signal.wakeup();
132+
}
133+
134+
fn handle_request(&mut self, req: WindowThreadRequest) -> Result<(), Error> {
135+
match req {
136+
WindowThreadRequest::Resize(new_size) => {
137+
let scale_factor = self.window.scaling_factor.get();
138+
let new_size = new_size.to_physical(scale_factor);
139+
140+
// Handle everything directly, so we can return a handler error immediately.
141+
let previous = self.window.store_size(new_size);
142+
self.window.xcb_window.resize(new_size.cast())?; // Will not call handler, as size is the same as above.
143+
144+
if let Err(e) =
145+
self.handler.resized(WindowSize::from_physical(new_size.cast(), scale_factor))
146+
{
147+
warn!("Window Handler failed to resize: {}. Reverting to previous size", &e);
148+
self.window.store_size(previous);
149+
return Err(e.into());
150+
}
151+
152+
Ok(())
153+
}
154+
_ => todo!(),
155+
}
156+
}
157+
91158
fn handle_connection_event_ready(&mut self) -> Result<PostAction, ConnectionError> {
92159
self.drain_xcb_events()?;
93160

@@ -97,7 +164,7 @@ impl EventLoop {
97164
fn handle_frame(&mut self, previous_deadline: Instant) -> TimeoutAction {
98165
if let Err(e) = self.handler.on_frame() {
99166
self.run_error = Some(e.into());
100-
self.loop_signal.stop();
167+
self.stop_now();
101168
return TimeoutAction::Drop;
102169
}
103170

@@ -194,9 +261,7 @@ impl EventLoop {
194261
XEvent::ConfigureNotify(event) => {
195262
let new_physical_size = PhysicalSize::new(event.width, event.height);
196263

197-
if self.new_physical_size.is_some()
198-
|| new_physical_size != self.window.window_size.get()
199-
{
264+
if self.new_physical_size.is_some() || new_physical_size != self.window.get_size() {
200265
self.new_physical_size = Some(new_physical_size);
201266
}
202267
}

src/platform/x11/window_shared.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::platform::x11::event_loop::EventLoop;
22
use crate::platform::x11::visual_info::WindowVisualConfig;
3+
use crate::platform::x11::window_thread::WindowThreadShared;
34
use crate::platform::x11::xcb_window::XcbWindow;
45
use crate::platform::*;
56
use crate::{MouseCursor, WindowOpenOptions, WindowScalePolicy, WindowSize};
@@ -20,17 +21,20 @@ pub(crate) struct WindowInner {
2021
pub(crate) xcb_window: XcbWindow,
2122
pub(crate) connection: Rc<X11Connection>,
2223
pub(crate) scaling_factor: Cell<f64>,
23-
pub(crate) window_size: Cell<PhysicalSize<u16>>,
24+
window_size: Cell<PhysicalSize<u16>>,
2425
mouse_cursor: Cell<MouseCursor>,
2526
pub(crate) visual_id: Visualid,
2627

2728
pub(crate) is_focused: Cell<bool>,
2829
pub(crate) loop_signal: LoopSignal,
30+
31+
main_thread_shared: Arc<WindowThreadShared>,
2932
}
3033

3134
impl WindowInner {
3235
pub(crate) fn create(
3336
options: WindowOpenOptions, ev_loop: &calloop::EventLoop<'static, EventLoop>,
37+
shared: Arc<WindowThreadShared>,
3438
) -> Result<Rc<Self>> {
3539
// Connect to the X server
3640
let xcb_connection = X11Connection::new()?;
@@ -40,6 +44,7 @@ impl WindowInner {
4044
WindowScalePolicy::ScaleFactor(scale) => scale,
4145
};
4246

47+
shared.set_scaling_factor(scaling);
4348
let physical_size = options.size.to_physical(scaling);
4449

4550
#[cfg(feature = "opengl")]
@@ -82,17 +87,17 @@ impl WindowInner {
8287
}
8388
};
8489

85-
let visual_id = visual_info.visual_id;
8690
Ok(Rc::new(Self {
8791
connection,
8892
xcb_window,
89-
visual_id,
93+
visual_id: visual_info.visual_id,
9094
window_size: physical_size.into(),
9195
scaling_factor: scaling.into(),
9296
mouse_cursor: MouseCursor::default().into(),
9397
loop_signal: ev_loop.get_signal(),
9498

9599
is_focused: false.into(),
100+
main_thread_shared: shared,
96101

97102
#[cfg(feature = "opengl")]
98103
gl_context,
@@ -121,6 +126,16 @@ impl WindowInner {
121126
Ok(())
122127
}
123128

129+
pub fn store_size(&self, size: PhysicalSize<u16>) -> PhysicalSize<u16> {
130+
let previous = self.window_size.replace(size);
131+
self.main_thread_shared.set_size(size);
132+
previous
133+
}
134+
135+
pub fn get_size(&self) -> PhysicalSize<u16> {
136+
self.window_size.get()
137+
}
138+
124139
pub fn request_close(&self) {
125140
self.loop_signal.stop();
126141
self.loop_signal.wakeup();
@@ -140,7 +155,7 @@ impl WindowInner {
140155
}
141156

142157
pub fn resize(&self, size: Size) -> Result<()> {
143-
let new_physical_size = size.to_physical::<u32>(self.scaling_factor.get());
158+
let new_physical_size = size.to_physical(self.scaling_factor.get());
144159
self.xcb_window.resize(new_physical_size)?;
145160

146161
// This will trigger a `ConfigureNotify` event which will in turn change `self.window_info`

0 commit comments

Comments
 (0)