1
+ use raw_window_handle:: { HasRawWindowHandle , WaylandHandle } ;
2
+ use tempfile:: tempfile;
3
+ use wayland_client:: { Display , sys:: client:: wl_display, GlobalManager , protocol:: { wl_shm:: WlShm , wl_buffer:: WlBuffer , wl_surface:: WlSurface } , Main , Proxy , EventQueue } ;
4
+ use crate :: { GraphicsContextImpl , SoftBufferError , error:: unwrap} ;
5
+ use std:: { fs:: File , os:: unix:: prelude:: { AsRawFd , FileExt } , io:: Write } ;
6
+
7
+ pub struct WaylandImpl {
8
+ _event_queue : EventQueue ,
9
+ surface : WlSurface ,
10
+ shm : Main < WlShm > ,
11
+ tempfile : File ,
12
+ buffer : Option < WaylandBuffer >
13
+ }
14
+
15
+ struct WaylandBuffer {
16
+ width : i32 ,
17
+ height : i32 ,
18
+ buffer : Main < WlBuffer >
19
+ }
20
+
21
+ impl WaylandImpl {
22
+
23
+ pub unsafe fn new < W : HasRawWindowHandle > ( handle : WaylandHandle ) -> Result < Self , SoftBufferError < W > > {
24
+ let display = Display :: from_external_display ( handle. display as * mut wl_display ) ;
25
+ let mut event_queue = display. create_event_queue ( ) ;
26
+ let attached_display = ( * display) . clone ( ) . attach ( event_queue. token ( ) ) ;
27
+ let globals = GlobalManager :: new ( & attached_display) ;
28
+ unwrap ( event_queue. sync_roundtrip ( & mut ( ) , |_, _, _| unreachable ! ( ) ) , "Failed to make round trip to server" ) ?;
29
+ let shm = unwrap ( globals. instantiate_exact :: < WlShm > ( 1 ) , "Failed to instantiate Wayland Shm" ) ?;
30
+ let tempfile = unwrap ( tempfile ( ) , "Failed to create temporary file to store buffer." ) ?;
31
+ let surface = Proxy :: from_c_ptr ( handle. surface as _ ) . into ( ) ;
32
+ Ok ( Self {
33
+ _event_queue : event_queue,
34
+ surface, shm, tempfile,
35
+ buffer : None
36
+ } )
37
+ }
38
+
39
+ fn ensure_buffer_size ( & mut self , width : i32 , height : i32 ) {
40
+ if !self . check_buffer_size_equals ( width, height) {
41
+ let pool = self . shm . create_pool ( self . tempfile . as_raw_fd ( ) , width* height* 4 ) ;
42
+ let buffer = pool. create_buffer ( 0 , width, height, width* 4 , wayland_client:: protocol:: wl_shm:: Format :: Xrgb8888 ) ;
43
+ self . buffer = Some ( WaylandBuffer {
44
+ width,
45
+ height,
46
+ buffer
47
+ } ) ;
48
+ }
49
+ }
50
+
51
+ fn check_buffer_size_equals ( & self , width : i32 , height : i32 ) -> bool {
52
+ match & self . buffer {
53
+ Some ( buffer) => buffer. width == width && buffer. height == height,
54
+ None => false
55
+ }
56
+ }
57
+
58
+ }
59
+
60
+ impl GraphicsContextImpl for WaylandImpl {
61
+ unsafe fn set_buffer ( & mut self , buffer : & [ u32 ] , width : u16 , height : u16 ) {
62
+ self . ensure_buffer_size ( width as i32 , height as i32 ) ;
63
+ let wayland_buffer = self . buffer . as_mut ( ) . unwrap ( ) ;
64
+ self . tempfile . write_at ( std:: slice:: from_raw_parts ( buffer. as_ptr ( ) as * const u8 , buffer. len ( ) * 4 ) , 0 ) . expect ( "Failed to write buffer to temporary file." ) ;
65
+ self . tempfile . flush ( ) . expect ( "Failed to flush buffer to temporary file." ) ;
66
+ self . surface . attach ( Some ( & wayland_buffer. buffer ) , 0 , 0 ) ;
67
+ self . surface . commit ( ) ;
68
+ }
69
+ }
0 commit comments