@@ -3,6 +3,9 @@ use super::keyboard::{convert_key_press_event, convert_key_release_event, key_mo
33use super :: * ;
44use std:: result:: Result ;
55
6+ use crate :: platform:: x11:: window_thread:: {
7+ WindowThreadRequest , WindowThreadResponse , WindowThreadResponseMessage ,
8+ } ;
69use crate :: warn;
710use crate :: wrappers:: xkbcommon:: XkbcommonState ;
811use crate :: { Event , MouseButton , MouseEvent , ScrollDelta , WindowEvent , WindowHandler , WindowSize } ;
@@ -11,6 +14,7 @@ use calloop::timer::{TimeoutAction, Timer};
1114use calloop:: { Interest , LoopSignal , Mode , PostAction } ;
1215use dpi:: { PhysicalPosition , PhysicalSize } ;
1316use std:: rc:: Rc ;
17+ use std:: sync:: mpsc;
1418use std:: time:: { Duration , Instant } ;
1519use x11rb:: connection:: Connection ;
1620use 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
3339const FRAME_INTERVAL : Duration = Duration :: from_millis ( 15 ) ;
3440
3541impl 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 }
0 commit comments