Skip to content

Commit db5dcfd

Browse files
committed
Implement Destroyed
1 parent c76a29c commit db5dcfd

7 files changed

Lines changed: 144 additions & 69 deletions

File tree

src/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ impl WindowContext {
5050
/// The given `size` can either be in [physical](dpi::PhysicalSize) or
5151
/// [logical](dpi::LogicalSize) pixels.
5252
pub fn resize(&self, size: impl Into<Size>) -> Result<(), Error> {
53-
self.inner.resize(size.into())?;
53+
self.inner.resize_later(size.into())?;
5454
Ok(())
5555
}
5656

src/platform/win/window.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub(crate) const BV_WINDOW_MUST_CLOSE: u32 = WM_USER + 1;
2323
use super::drop_target::DropTarget;
2424
use super::*;
2525
use crate::handler::WindowHandlerBuilder;
26+
use crate::host::Host;
2627
use crate::platform::win::window_state::{WindowSharedState, WindowState};
2728
use crate::platform::Error;
2829
use crate::wrappers::win32::cursor::SystemCursor;
@@ -112,6 +113,11 @@ impl WindowHandle {
112113
Err(Error::ResizeFailed)
113114
}
114115
}
116+
117+
#[inline]
118+
pub fn handle_main_thread_callback(&self) {
119+
// No-op
120+
}
115121
}
116122

117123
impl Drop for WindowHandle {
@@ -128,6 +134,7 @@ pub struct BaseviewWindow {
128134
initial_size: Size,
129135

130136
handler_builder: Cell<Option<WindowHandlerBuilder>>,
137+
host: Host,
131138

132139
// Things not directly used, but kept so their Drop impl runs when the window is destroyed
133140
_keyboard_hook: Cell<Option<hook::KeyboardHookHandle>>,
@@ -198,7 +205,7 @@ impl WindowImpl for BaseviewWindow {
198205
unsafe fn handle_message(
199206
&self, window: HWnd, msg: u32, wparam: WPARAM, lparam: LPARAM,
200207
) -> Option<LRESULT> {
201-
unsafe { wnd_proc_inner(window, msg, wparam, lparam, &self.window_state) }
208+
unsafe { wnd_proc_inner(window, msg, wparam, lparam, &self) }
202209
}
203210

204211
fn before_destroy(&self, window: HWnd) {
@@ -209,8 +216,9 @@ impl WindowImpl for BaseviewWindow {
209216
/// Our custom `wnd_proc` handler. If the result contains a value, then this is returned after
210217
/// handling any deferred tasks. otherwise the default window procedure is invoked.
211218
unsafe fn wnd_proc_inner(
212-
window: HWnd, msg: u32, wparam: WPARAM, lparam: LPARAM, window_state: &WindowState,
219+
window: HWnd, msg: u32, wparam: WPARAM, lparam: LPARAM, window_bv: &BaseviewWindow,
213220
) -> Option<LRESULT> {
221+
let window_state = &window_bv.window_state;
214222
match msg {
215223
WM_MOUSEMOVE => {
216224
if window_state.mouse_was_outside_window.get() {
@@ -465,7 +473,7 @@ unsafe fn wnd_proc_inner(
465473

466474
impl WindowHandle {
467475
pub fn create_window(
468-
options: WindowOpenOptions, build: WindowHandlerBuilder,
476+
options: WindowOpenOptions, build: WindowHandlerBuilder, host: Host,
469477
) -> Result<WindowHandle> {
470478
let extended_user_32 = ExtendedUser32::load()?;
471479
let title = HSTRING::from(options.title);
@@ -495,6 +503,7 @@ impl WindowHandle {
495503
initial_size: options.size,
496504
handler_builder: Cell::new(Some(build)),
497505
shared_state,
506+
host,
498507

499508
_drop_target: None.into(),
500509
_keyboard_hook: None.into(),

src/platform/x11/error.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,40 @@ use crate::platform::x11::xcb_connection::GetPropertyError;
44
use crate::warn;
55
use crate::wrappers::xlib::{DisplayOpenFailedError, InitThreadsFailedError};
66
use crate::HandlerError;
7+
use std::fmt::{Display, Formatter};
78
use std::sync::mpsc::RecvError;
89
use x11_dl::error::OpenError;
910
use x11rb::connection::RequestConnection;
1011
use x11rb::cookie::{Cookie, VoidCookie};
1112
use x11rb::errors::{ConnectError, ConnectionError, ReplyError, ReplyOrIdError};
1213
use x11rb::x11_utils::{TryParse, X11Error};
1314

15+
#[derive(Debug)]
16+
pub enum FatalError {
17+
Connection(ConnectionError),
18+
SendMainThread,
19+
ReceiveMainThread,
20+
}
21+
22+
impl Display for FatalError {
23+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
24+
match self {
25+
FatalError::Connection(e) => e.fmt(f),
26+
// TODO: better errors
27+
FatalError::SendMainThread => f.write_str("SendMainThread"),
28+
FatalError::ReceiveMainThread => f.write_str("ReceiveMainThread"),
29+
}
30+
}
31+
}
32+
33+
impl std::error::Error for FatalError {}
34+
35+
impl From<ConnectionError> for FatalError {
36+
fn from(err: ConnectionError) -> FatalError {
37+
FatalError::Connection(err)
38+
}
39+
}
40+
1441
#[derive(Debug)]
1542
pub enum Error {
1643
CreationFailed(String),
@@ -35,7 +62,7 @@ pub enum Error {
3562
Gl(super::gl::CreationFailedError),
3663
}
3764

38-
impl std::fmt::Display for Error {
65+
impl Display for Error {
3966
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4067
match self {
4168
Error::Io(e) => e.fmt(f),

src/platform/x11/event_loop.rs

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

66
use crate::host::HostMainThreadCaller;
7+
use crate::platform::x11::error::FatalError;
78
use crate::platform::x11::window_thread::{
89
HostCallback, WindowThreadRequest, WindowThreadResponse, WindowThreadResponseMessage,
910
};
@@ -16,11 +17,36 @@ use calloop::{Interest, LoopSignal, Mode, PostAction};
1617
use dpi::{PhysicalPosition, PhysicalSize};
1718
use std::rc::Rc;
1819
use std::sync::mpsc;
20+
use std::sync::mpsc::Receiver;
1921
use std::time::{Duration, Instant};
2022
use x11rb::connection::Connection;
2123
use x11rb::errors::ConnectionError;
2224
use x11rb::protocol::Event as XEvent;
2325

26+
pub struct MainThreadCaller {
27+
sender: mpsc::Sender<HostCallback>,
28+
caller: Box<dyn HostMainThreadCaller>,
29+
}
30+
31+
impl MainThreadCaller {
32+
pub(crate) fn new(
33+
main_thread: Option<Box<dyn HostMainThreadCaller>>,
34+
) -> (Option<Self>, Option<Receiver<HostCallback>>) {
35+
let Some(main_thread) = main_thread else {
36+
return (None, None);
37+
};
38+
39+
let (sender, receiver) = mpsc::channel();
40+
(Some(Self { sender, caller: main_thread }), Some(receiver))
41+
}
42+
43+
pub fn send(&mut self, msg: HostCallback) -> Result<(), FatalError> {
44+
self.sender.send(msg).map_err(|_| FatalError::SendMainThread)?;
45+
self.caller.call_main_thread();
46+
Ok(())
47+
}
48+
}
49+
2450
pub(crate) struct EventLoop {
2551
handler: Box<dyn WindowHandler>,
2652
window: Rc<WindowInner>,
@@ -35,8 +61,7 @@ pub(crate) struct EventLoop {
3561
run_error: Option<Error>,
3662

3763
response_sender: mpsc::Sender<WindowThreadResponseMessage>,
38-
callback_sender: mpsc::Sender<HostCallback>,
39-
main_thread_caller: Option<Box<dyn HostMainThreadCaller>>,
64+
main_thread: Option<MainThreadCaller>,
4065
}
4166

4267
const FRAME_INTERVAL: Duration = Duration::from_millis(15);
@@ -46,9 +71,7 @@ impl EventLoop {
4671
window: Rc<WindowInner>, handler: Box<dyn WindowHandler>,
4772
request_receiver: calloop::channel::Channel<WindowThreadRequest>,
4873
response_sender: mpsc::Sender<WindowThreadResponseMessage>,
49-
callback_sender: mpsc::Sender<HostCallback>,
50-
main_thread_caller: Option<Box<dyn HostMainThreadCaller>>,
51-
inner: &mut calloop::EventLoop<'static, Self>,
74+
main_thread: Option<MainThreadCaller>, inner: &mut calloop::EventLoop<'static, Self>,
5275
) -> Result<Self, Error> {
5376
let loop_handle = inner.handle();
5477

@@ -74,16 +97,15 @@ impl EventLoop {
7497
drag_n_drop: DragNDropState::NoCurrentSession,
7598
xkb_state: XkbcommonState::new(&window.connection),
7699
run_error: None,
77-
callback_sender,
78-
main_thread_caller,
100+
main_thread,
79101

80102
window,
81103
response_sender,
82104
})
83105
}
84106

85107
#[inline]
86-
fn drain_xcb_events(&mut self) -> Result<(), ConnectionError> {
108+
fn drain_xcb_events(&mut self) -> Result<(), FatalError> {
87109
// the X server has a tendency to send spurious/extraneous configure notify events when a
88110
// window is resized, and we need to batch those together and just send one resize event
89111
// when they've all been coalesced.
@@ -93,28 +115,31 @@ impl EventLoop {
93115
self.handle_xcb_event(event)?;
94116
}
95117

96-
if let Some(size) = self.new_physical_size.take() {
97-
let previous = self.window.store_size(size);
98-
99-
let scale_factor = self.window.scaling_factor.get();
100-
let new_size = WindowSize::from_physical(size.cast(), scale_factor);
101-
102-
if let Err(e) = self.handler.resized(new_size) {
103-
warn!("Window Handler failed to resize: {}", e);
104-
self.window.store_size(previous);
105-
self.window.xcb_window.resize(previous.cast())?.check_warn();
106-
} else {
107-
// TODO: only if this wansn't the result of a host request
108-
// TODO: do not allocate channel if no host callback is present
109-
if let Some(main_thread) = self.main_thread_caller.as_mut() {
110-
self.callback_sender
111-
.send(HostCallback::Resized {
112-
new_size,
113-
previous: WindowSize::from_physical(previous.cast(), scale_factor),
114-
})
115-
.unwrap(); // TODO: unwrap
116-
main_thread.call_main_thread();
117-
}
118+
self.handle_coalesced_resize_events()
119+
}
120+
121+
fn handle_coalesced_resize_events(&mut self) -> Result<(), FatalError> {
122+
let Some(new_size) = self.new_physical_size.take() else { return Ok(()) };
123+
let previous = self.window.store_size(new_size);
124+
125+
if previous == new_size {
126+
return Ok(());
127+
};
128+
129+
let scale_factor = self.window.scaling_factor.get();
130+
let new_size = WindowSize::from_physical(new_size.cast(), scale_factor);
131+
132+
if let Err(e) = self.handler.resized(new_size) {
133+
warn!("Window Handler failed to resize: {}", e);
134+
self.window.store_size(previous);
135+
self.window.xcb_window.resize(previous.cast())?.check_warn();
136+
} else {
137+
// TODO: only if this wansn't the result of a host request
138+
if let Some(host) = self.main_thread.as_mut() {
139+
host.send(HostCallback::Resized {
140+
new_size,
141+
previous: WindowSize::from_physical(previous.cast(), scale_factor),
142+
})?;
118143
}
119144
}
120145

@@ -177,7 +202,7 @@ impl EventLoop {
177202
}
178203
}
179204

180-
fn handle_connection_event_ready(&mut self) -> Result<PostAction, ConnectionError> {
205+
fn handle_connection_event_ready(&mut self) -> Result<PostAction, FatalError> {
181206
self.drain_xcb_events()?;
182207

183208
Ok(PostAction::Continue)
@@ -214,6 +239,15 @@ impl EventLoop {
214239

215240
self.handle_event(Event::Window(WindowEvent::WillClose));
216241

242+
// If the event loop doesn't stop because the host asked it to, then we should notify it
243+
if !self.window.main_thread_shared.is_stop_host_requested() {
244+
if let Some(main_thread) = self.main_thread.as_mut() {
245+
if let Err(e) = main_thread.send(HostCallback::Destroyed) {
246+
warn!("Could not notify host that X11 thread is stopping: {}", e)
247+
}
248+
}
249+
}
250+
217251
if let Some(err) = self.run_error {
218252
return Err(err);
219253
};

src/platform/x11/window_shared.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ pub(crate) struct WindowInner {
6161
pub(crate) is_focused: Cell<bool>,
6262
pub(crate) loop_signal: LoopSignal,
6363

64-
main_thread_shared: Arc<WindowThreadShared>,
64+
pub(crate) main_thread_shared: Arc<WindowThreadShared>,
6565
}
6666

6767
impl WindowInner {
@@ -186,7 +186,7 @@ impl WindowInner {
186186
Ok(())
187187
}
188188

189-
pub fn resize(&self, size: Size) -> Result<()> {
189+
pub fn resize_later(&self, size: Size) -> Result<()> {
190190
let new_physical_size = size.to_physical(self.scaling_factor.get());
191191
self.xcb_window.resize(new_physical_size)?.check()?;
192192

@@ -211,10 +211,12 @@ impl WindowInner {
211211
warn!("Window Handler failed to resize: {}. Reverting to previous size", &e);
212212
self.store_size(previous);
213213
return Err(e.into());
214-
} else {
215-
self.xcb_window.resize(new_size.cast())?.check()?; // Will not call handler, as size is the same as above.
216214
}
217215

216+
self.xcb_window.resize(new_size.cast())?.check()?; // Will not call handler, as size is the same as above.
217+
218+
// These come from the Host, no need to notify it about the new size
219+
218220
Ok(())
219221
}
220222

0 commit comments

Comments
 (0)