@@ -40,7 +40,7 @@ use x11rb::xcb_ffi::XCBConnection;
4040#[ derive( Debug ) ]
4141pub struct X11DisplayImpl < D : ?Sized > {
4242 /// The handle to the XCB connection.
43- connection : Option < XCBConnection > ,
43+ connection : XCBConnection ,
4444
4545 /// SHM extension is available.
4646 is_shm_available : bool ,
@@ -53,7 +53,11 @@ pub struct X11DisplayImpl<D: ?Sized> {
5353 /// Without `&mut`, the underlying connection cannot be closed without other unsafe behavior.
5454 /// With `&mut`, the connection can be dropped without us knowing about it. Therefore, we
5555 /// cannot provide `&mut` access to this field.
56+ ///
57+ /// This has to be dropped *after* the `conn` field. This is done by placing this field last:
58+ /// <https://doc.rust-lang.org/std/ops/trait.Drop.html#drop-order>
5659 _display : D ,
60+ // NO FIELDS AFTER THIS!
5761}
5862
5963impl < D : HasDisplayHandle + ?Sized > ContextInterface < D > for Arc < X11DisplayImpl < D > > {
@@ -110,28 +114,17 @@ impl<D: HasDisplayHandle + ?Sized> ContextInterface<D> for Arc<X11DisplayImpl<D>
110114 let supported_visuals = supported_visuals ( & connection) ;
111115
112116 Ok ( Arc :: new ( X11DisplayImpl {
113- connection : Some ( connection ) ,
117+ connection,
114118 is_shm_available,
115119 supported_visuals,
116120 _display : display,
117121 } ) )
118122 }
119123}
120124
121- impl < D : ?Sized > X11DisplayImpl < D > {
122- fn connection ( & self ) -> & XCBConnection {
123- self . connection
124- . as_ref ( )
125- . expect ( "X11DisplayImpl::connection() called after X11DisplayImpl::drop()" )
126- }
127- }
128-
129125/// The handle to an X11 drawing context.
130126#[ derive( Debug ) ]
131- pub struct X11Impl < D : ?Sized , W : ?Sized > {
132- /// X display this window belongs to.
133- display : Arc < X11DisplayImpl < D > > ,
134-
127+ pub struct X11Impl < D : ?Sized , W > {
135128 /// The window to draw to.
136129 window : xproto:: Window ,
137130
@@ -154,7 +147,13 @@ pub struct X11Impl<D: ?Sized, W: ?Sized> {
154147 size : Option < ( NonZeroU16 , NonZeroU16 ) > ,
155148
156149 /// Keep the window alive.
150+ /// NOTE: Drop this second-to-last!
157151 window_handle : W ,
152+
153+ /// X display this window belongs to.
154+ /// NOTE: Drop this last!
155+ display : Arc < X11DisplayImpl < D > > ,
156+ // NO FIELDS AFTER THIS!
158157}
159158
160159/// The buffer that is being drawn to.
@@ -219,13 +218,13 @@ impl<D: HasDisplayHandle + ?Sized, W: HasWindowHandle> SurfaceInterface<D, W> fo
219218 let display2 = display. clone ( ) ;
220219 let tokens = {
221220 let geometry_token = display2
222- . connection ( )
221+ . connection
223222 . get_geometry ( window)
224223 . swbuf_err ( "Failed to send geometry request" ) ?;
225224 let window_attrs_token = if window_handle. visual_id . is_none ( ) {
226225 Some (
227226 display2
228- . connection ( )
227+ . connection
229228 . get_window_attributes ( window)
230229 . swbuf_err ( "Failed to send window attributes request" ) ?,
231230 )
@@ -238,11 +237,11 @@ impl<D: HasDisplayHandle + ?Sized, W: HasWindowHandle> SurfaceInterface<D, W> fo
238237
239238 // Create a new graphics context to draw to.
240239 let gc = display
241- . connection ( )
240+ . connection
242241 . generate_id ( )
243242 . swbuf_err ( "Failed to generate GC ID" ) ?;
244243 display
245- . connection ( )
244+ . connection
246245 . create_gc (
247246 gc,
248247 window,
@@ -344,7 +343,7 @@ impl<D: HasDisplayHandle + ?Sized, W: HasWindowHandle> SurfaceInterface<D, W> fo
344343 if self . size != Some ( ( width, height) ) {
345344 self . buffer_presented = false ;
346345 self . buffer
347- . resize ( self . display . connection ( ) , num_bytes)
346+ . resize ( & self . display . connection , num_bytes)
348347 . swbuf_err ( "Failed to resize X11 buffer" ) ?;
349348
350349 // We successfully resized the buffer.
@@ -358,11 +357,11 @@ impl<D: HasDisplayHandle + ?Sized, W: HasWindowHandle> SurfaceInterface<D, W> fo
358357 tracing:: trace!( "next_buffer: window={:X}" , self . window) ;
359358
360359 // Finish waiting on the previous `shm::PutImage` request, if any.
361- self . buffer . finish_wait ( self . display . connection ( ) ) ?;
360+ self . buffer . finish_wait ( & self . display . connection ) ?;
362361
363362 // We can now safely call `next_buffer` on the buffer.
364363 Ok ( BufferImpl {
365- connection : self . display . connection ( ) ,
364+ connection : & self . display . connection ,
366365 window : self . window ,
367366 gc : self . gc ,
368367 depth : self . depth ,
@@ -382,7 +381,7 @@ impl<D: HasDisplayHandle + ?Sized, W: HasWindowHandle> SurfaceInterface<D, W> fo
382381 // TODO: Is it worth it to do SHM here? Probably not.
383382 let reply = self
384383 . display
385- . connection ( )
384+ . connection
386385 . get_image (
387386 xproto:: ImageFormat :: Z_PIXMAP ,
388387 self . window ,
@@ -775,25 +774,18 @@ impl Drop for ShmSegment {
775774 }
776775}
777776
778- impl < D : ?Sized > Drop for X11DisplayImpl < D > {
779- fn drop ( & mut self ) {
780- // Make sure that the x11rb connection is dropped before its source is.
781- self . connection = None ;
782- }
783- }
784-
785- impl < D : ?Sized , W : ?Sized > Drop for X11Impl < D , W > {
777+ impl < D : ?Sized , W > Drop for X11Impl < D , W > {
786778 fn drop ( & mut self ) {
787779 // If we used SHM, make sure it's detached from the server.
788780 if let Buffer :: Shm ( mut shm) = mem:: replace (
789781 & mut self . buffer ,
790782 Buffer :: Wire ( util:: PixelBuffer ( Vec :: new ( ) ) ) ,
791783 ) {
792784 // If we were in the middle of processing a buffer, wait for it to finish.
793- shm. finish_wait ( self . display . connection ( ) ) . ok ( ) ;
785+ shm. finish_wait ( & self . display . connection ) . ok ( ) ;
794786
795787 if let Some ( ( segment, seg_id) ) = shm. seg . take ( ) {
796- if let Ok ( token) = self . display . connection ( ) . shm_detach ( seg_id) {
788+ if let Ok ( token) = self . display . connection . shm_detach ( seg_id) {
797789 token. ignore_error ( ) ;
798790 }
799791
@@ -803,7 +795,7 @@ impl<D: ?Sized, W: ?Sized> Drop for X11Impl<D, W> {
803795 }
804796
805797 // Close the graphics context that we created.
806- if let Ok ( token) = self . display . connection ( ) . free_gc ( self . gc ) {
798+ if let Ok ( token) = self . display . connection . free_gc ( self . gc ) {
807799 token. ignore_error ( ) ;
808800 }
809801 }
0 commit comments