1
+ use crate :: { error:: unwrap, GraphicsContextImpl , SoftBufferError } ;
2
+ use nix:: sys:: memfd:: { memfd_create, MemFdCreateFlag } ;
1
3
use raw_window_handle:: { HasRawWindowHandle , WaylandDisplayHandle , WaylandWindowHandle } ;
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 } ;
4
+ use std:: {
5
+ ffi:: CStr ,
6
+ fs:: File ,
7
+ io:: Write ,
8
+ os:: unix:: prelude:: { AsRawFd , FileExt , FromRawFd } ,
9
+ } ;
10
+ use wayland_client:: {
11
+ backend:: { Backend , ObjectId } ,
12
+ globals:: { registry_queue_init, GlobalListContents } ,
13
+ protocol:: { wl_buffer, wl_registry, wl_shm, wl_shm_pool, wl_surface} ,
14
+ Connection , Dispatch , EventQueue , Proxy , QueueHandle ,
15
+ } ;
16
+
17
+ struct State ;
6
18
7
19
pub struct WaylandImpl {
8
- _event_queue : EventQueue ,
9
- surface : WlSurface ,
10
- shm : Main < WlShm > ,
20
+ event_queue : EventQueue < State > ,
21
+ qh : QueueHandle < State > ,
22
+ surface : wl_surface:: WlSurface ,
23
+ shm : wl_shm:: WlShm ,
11
24
tempfile : File ,
12
- buffer : Option < WaylandBuffer >
25
+ buffer : Option < WaylandBuffer > ,
13
26
}
14
27
15
- struct WaylandBuffer {
28
+ struct WaylandBuffer {
16
29
width : i32 ,
17
30
height : i32 ,
18
- buffer : Main < WlBuffer >
31
+ pool : wl_shm_pool:: WlShmPool ,
32
+ buffer : wl_buffer:: WlBuffer ,
19
33
}
20
34
21
- impl WaylandImpl {
35
+ impl Drop for WaylandBuffer {
36
+ fn drop ( & mut self ) {
37
+ self . buffer . destroy ( ) ;
38
+ self . pool . destroy ( ) ;
39
+ }
40
+ }
22
41
23
- pub unsafe fn new < W : HasRawWindowHandle > ( window_handle : WaylandWindowHandle , display_handle : WaylandDisplayHandle ) -> Result < Self , SoftBufferError < W > > {
24
- let display = Display :: from_external_display ( 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 ( window_handle. surface as _ ) . into ( ) ;
32
- Ok ( Self {
33
- _event_queue : event_queue,
34
- surface, shm, tempfile,
35
- buffer : None
42
+ impl WaylandImpl {
43
+ pub unsafe fn new < W : HasRawWindowHandle > (
44
+ window_handle : WaylandWindowHandle ,
45
+ display_handle : WaylandDisplayHandle ,
46
+ ) -> Result < Self , SoftBufferError < W > > {
47
+ let conn = Connection :: from_backend ( Backend :: from_foreign_display (
48
+ display_handle. display as * mut _ ,
49
+ ) ) ;
50
+ let ( globals, event_queue) = unwrap (
51
+ registry_queue_init ( & conn) ,
52
+ "Failed to make round trip to server" ,
53
+ ) ?;
54
+ let qh = event_queue. handle ( ) ;
55
+ let shm: wl_shm:: WlShm = unwrap (
56
+ globals. bind ( & qh, 1 ..=1 , ( ) ) ,
57
+ "Failed to instantiate Wayland Shm" ,
58
+ ) ?;
59
+ let name = CStr :: from_bytes_with_nul_unchecked ( "swbuf\0 " . as_bytes ( ) ) ;
60
+ let tempfile_fd = unwrap (
61
+ memfd_create ( name, MemFdCreateFlag :: MFD_CLOEXEC ) ,
62
+ "Failed to create temporary file to store buffer." ,
63
+ ) ?;
64
+ let tempfile = File :: from_raw_fd ( tempfile_fd) ;
65
+ let surface_id = unwrap (
66
+ ObjectId :: from_ptr (
67
+ wl_surface:: WlSurface :: interface ( ) ,
68
+ window_handle. surface as _ ,
69
+ ) ,
70
+ "Failed to create proxy for surface ID." ,
71
+ ) ?;
72
+ let surface = unwrap (
73
+ wl_surface:: WlSurface :: from_id ( & conn, surface_id) ,
74
+ "Failed to create proxy for surface ID." ,
75
+ ) ?;
76
+ Ok ( Self {
77
+ event_queue : event_queue,
78
+ qh,
79
+ surface,
80
+ shm,
81
+ tempfile,
82
+ buffer : None ,
36
83
} )
37
84
}
38
85
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 {
86
+ fn ensure_buffer_size ( & mut self , width : i32 , height : i32 ) {
87
+ if !self . check_buffer_size_equals ( width, height) {
88
+ let pool =
89
+ self . shm
90
+ . create_pool ( self . tempfile . as_raw_fd ( ) , width * height * 4 , & self . qh , ( ) ) ;
91
+ let buffer = pool. create_buffer (
92
+ 0 ,
44
93
width,
45
94
height,
46
- buffer
95
+ width * 4 ,
96
+ wayland_client:: protocol:: wl_shm:: Format :: Xrgb8888 ,
97
+ & self . qh ,
98
+ ( ) ,
99
+ ) ;
100
+ self . buffer = Some ( WaylandBuffer {
101
+ width,
102
+ height,
103
+ pool,
104
+ buffer,
47
105
} ) ;
48
106
}
49
107
}
50
108
51
- fn check_buffer_size_equals ( & self , width : i32 , height : i32 ) -> bool {
52
- match & self . buffer {
109
+ fn check_buffer_size_equals ( & self , width : i32 , height : i32 ) -> bool {
110
+ match & self . buffer {
53
111
Some ( buffer) => buffer. width == width && buffer. height == height,
54
- None => false
112
+ None => false ,
55
113
}
56
114
}
57
-
58
115
}
59
116
60
117
impl GraphicsContextImpl for WaylandImpl {
61
118
unsafe fn set_buffer ( & mut self , buffer : & [ u32 ] , width : u16 , height : u16 ) {
62
119
self . ensure_buffer_size ( width as i32 , height as i32 ) ;
63
120
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." ) ;
121
+ self . tempfile . set_len ( buffer. len ( ) as u64 * 4 )
122
+ . expect ( "Failed to truncate temporary file." ) ;
123
+ self . tempfile
124
+ . write_at (
125
+ std:: slice:: from_raw_parts ( buffer. as_ptr ( ) as * const u8 , buffer. len ( ) * 4 ) ,
126
+ 0 ,
127
+ )
128
+ . expect ( "Failed to write buffer to temporary file." ) ;
129
+ self . tempfile
130
+ . flush ( )
131
+ . expect ( "Failed to flush buffer to temporary file." ) ;
66
132
self . surface . attach ( Some ( & wayland_buffer. buffer ) , 0 , 0 ) ;
67
133
68
134
// FIXME: Proper damaging mechanism.
69
135
//
70
136
// In order to propagate changes on compositors which track damage, for now damage the entire surface.
71
- if self . surface . as_ref ( ) . version ( ) < 4 {
137
+ if self . surface . version ( ) < 4 {
72
138
// FIXME: Accommodate scale factor since wl_surface::damage is in terms of surface coordinates while
73
139
// wl_surface::damage_buffer is in buffer coordinates.
74
140
//
75
141
// i32::MAX is a valid damage box (most compositors interpret the damage box as "the entire surface")
76
142
self . surface . damage ( 0 , 0 , i32:: MAX , i32:: MAX ) ;
77
143
} else {
78
144
// Introduced in version 4, it is an error to use this request in version 3 or lower.
79
- self . surface . damage_buffer ( 0 , 0 , width as i32 , height as i32 ) ;
145
+ self . surface
146
+ . damage_buffer ( 0 , 0 , width as i32 , height as i32 ) ;
80
147
}
81
148
82
149
self . surface . commit ( ) ;
150
+ let _ = self . event_queue . flush ( ) ;
151
+ }
152
+ }
153
+
154
+ impl Dispatch < wl_registry:: WlRegistry , GlobalListContents > for State {
155
+ fn event (
156
+ _: & mut State ,
157
+ _: & wl_registry:: WlRegistry ,
158
+ _: wl_registry:: Event ,
159
+ _: & GlobalListContents ,
160
+ _: & Connection ,
161
+ _: & QueueHandle < State > ,
162
+ ) {
163
+ // Ignore globals added after initialization
83
164
}
84
- }
165
+ }
166
+
167
+ impl Dispatch < wl_shm:: WlShm , ( ) > for State {
168
+ fn event (
169
+ _: & mut State ,
170
+ _: & wl_shm:: WlShm ,
171
+ _: wl_shm:: Event ,
172
+ _: & ( ) ,
173
+ _: & Connection ,
174
+ _: & QueueHandle < State > ,
175
+ ) {
176
+ }
177
+ }
178
+
179
+ impl Dispatch < wl_shm_pool:: WlShmPool , ( ) > for State {
180
+ fn event (
181
+ _: & mut State ,
182
+ _: & wl_shm_pool:: WlShmPool ,
183
+ _: wl_shm_pool:: Event ,
184
+ _: & ( ) ,
185
+ _: & Connection ,
186
+ _: & QueueHandle < State > ,
187
+ ) {
188
+ }
189
+ }
190
+
191
+ impl Dispatch < wl_buffer:: WlBuffer , ( ) > for State {
192
+ fn event (
193
+ _: & mut State ,
194
+ _: & wl_buffer:: WlBuffer ,
195
+ _: wl_buffer:: Event ,
196
+ _: & ( ) ,
197
+ _: & Connection ,
198
+ _: & QueueHandle < State > ,
199
+ ) {
200
+ }
201
+ }
0 commit comments