xref: /aosp_15_r20/external/crosvm/gpu_display/src/gpu_display_x.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2019 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #[path = "generated/xlib.rs"]
6 #[allow(
7     dead_code,
8     non_snake_case,
9     non_camel_case_types,
10     non_upper_case_globals
11 )]
12 mod xlib;
13 
14 use std::cmp::max;
15 use std::ffi::c_void;
16 use std::ffi::CStr;
17 use std::ffi::CString;
18 use std::mem::transmute_copy;
19 use std::mem::zeroed;
20 use std::os::raw::c_ulong;
21 use std::ptr::null;
22 use std::ptr::null_mut;
23 use std::ptr::NonNull;
24 use std::rc::Rc;
25 
26 use base::AsRawDescriptor;
27 use base::RawDescriptor;
28 use base::VolatileSlice;
29 use libc::shmat;
30 use libc::shmctl;
31 use libc::shmdt;
32 use libc::shmget;
33 use libc::IPC_CREAT;
34 use libc::IPC_PRIVATE;
35 use libc::IPC_RMID;
36 use linux_input_sys::virtio_input_event;
37 use vm_control::gpu::DisplayParameters;
38 
39 use crate::keycode_converter::KeycodeTranslator;
40 use crate::keycode_converter::KeycodeTypes;
41 use crate::DisplayT;
42 use crate::EventDeviceKind;
43 use crate::GpuDisplayError;
44 use crate::GpuDisplayEvents;
45 use crate::GpuDisplayFramebuffer;
46 use crate::GpuDisplayResult;
47 use crate::GpuDisplaySurface;
48 use crate::SurfaceType;
49 use crate::SysDisplayT;
50 
51 const BUFFER_COUNT: usize = 2;
52 
53 /// A wrapper for XFree that takes any type.
54 /// SAFETY: It is caller's responsibility to ensure that `t` is valid for the entire duration of the
55 /// call.
x_free<T>(t: *mut T)56 unsafe fn x_free<T>(t: *mut T) {
57     xlib::XFree(t as *mut c_void);
58 }
59 
60 #[derive(Clone)]
61 struct XDisplay(Rc<NonNull<xlib::Display>>);
62 impl Drop for XDisplay {
drop(&mut self)63     fn drop(&mut self) {
64         if Rc::strong_count(&self.0) == 1 {
65             // TODO(b/315870313): Add safety comment
66             #[allow(clippy::undocumented_unsafe_blocks)]
67             unsafe {
68                 xlib::XCloseDisplay(self.as_ptr());
69             }
70         }
71     }
72 }
73 
74 impl XDisplay {
75     /// Returns a pointer to the X display object.
as_ptr(&self) -> *mut xlib::Display76     fn as_ptr(&self) -> *mut xlib::Display {
77         self.0.as_ptr()
78     }
79 
80     /// Sends any pending commands to the X server.
flush(&self)81     fn flush(&self) {
82         // TODO(b/315870313): Add safety comment
83         #[allow(clippy::undocumented_unsafe_blocks)]
84         unsafe {
85             xlib::XFlush(self.as_ptr());
86         }
87     }
88 
89     /// Returns true of the XShm extension is supported on this display.
supports_shm(&self) -> bool90     fn supports_shm(&self) -> bool {
91         // TODO(b/315870313): Add safety comment
92         #[allow(clippy::undocumented_unsafe_blocks)]
93         unsafe {
94             xlib::XShmQueryExtension(self.as_ptr()) != 0
95         }
96     }
97 
98     /// Gets the default screen of this display.
default_screen(&self) -> Option<XScreen>99     fn default_screen(&self) -> Option<XScreen> {
100         Some(XScreen(NonNull::new(
101             // TODO(b/315870313): Add safety comment
102             #[allow(clippy::undocumented_unsafe_blocks)]
103             unsafe {
104                 xlib::XDefaultScreenOfDisplay(self.as_ptr())
105             },
106         )?))
107     }
108 
109     /// Blocks until the next event from the display is received and returns that event.
110     ///
111     /// Always flush before using this if any X commands where issued.
next_event(&self) -> XEvent112     fn next_event(&self) -> XEvent {
113         // TODO(b/315870313): Add safety comment
114         #[allow(clippy::undocumented_unsafe_blocks)]
115         unsafe {
116             let mut ev = zeroed();
117             xlib::XNextEvent(self.as_ptr(), &mut ev);
118             ev.into()
119         }
120     }
121 }
122 
123 impl AsRawDescriptor for XDisplay {
as_raw_descriptor(&self) -> RawDescriptor124     fn as_raw_descriptor(&self) -> RawDescriptor {
125         // TODO(b/315870313): Add safety comment
126         #[allow(clippy::undocumented_unsafe_blocks)]
127         unsafe {
128             xlib::XConnectionNumber(self.as_ptr())
129         }
130     }
131 }
132 
133 struct XEvent(xlib::XEvent);
134 impl From<xlib::XEvent> for XEvent {
from(ev: xlib::XEvent) -> XEvent135     fn from(ev: xlib::XEvent) -> XEvent {
136         XEvent(ev)
137     }
138 }
139 
140 impl XEvent {
any(&self) -> xlib::XAnyEvent141     fn any(&self) -> xlib::XAnyEvent {
142         // All events have the same xany field.
143         // TODO(b/315870313): Add safety comment
144         #[allow(clippy::undocumented_unsafe_blocks)]
145         unsafe {
146             self.0.xany
147         }
148     }
149 
type_(&self) -> u32150     fn type_(&self) -> u32 {
151         // All events have the same type_ field.
152         // TODO(b/315870313): Add safety comment
153         #[allow(clippy::undocumented_unsafe_blocks)]
154         unsafe {
155             self.0.type_ as u32
156         }
157     }
158 
window(&self) -> xlib::Window159     fn window(&self) -> xlib::Window {
160         self.any().window
161     }
162 
163     // Some of the event types are dynamic so they need to be passed in.
as_enum(&self, shm_complete_type: u32) -> XEventEnum164     fn as_enum(&self, shm_complete_type: u32) -> XEventEnum {
165         match self.type_() {
166             xlib::KeyPress | xlib::KeyRelease => XEventEnum::KeyEvent(
167                 // TODO(b/315870313): Add safety comment
168                 #[allow(clippy::undocumented_unsafe_blocks)]
169                 unsafe {
170                     self.0.xkey
171                 },
172             ),
173             xlib::ButtonPress => {
174                 // TODO(b/315870313): Add safety comment
175                 #[allow(clippy::undocumented_unsafe_blocks)]
176                 XEventEnum::ButtonEvent {
177                     event: unsafe { self.0.xbutton },
178                     pressed: true,
179                 }
180             }
181             xlib::ButtonRelease => {
182                 // TODO(b/315870313): Add safety comment
183                 #[allow(clippy::undocumented_unsafe_blocks)]
184                 XEventEnum::ButtonEvent {
185                     event: unsafe { self.0.xbutton },
186                     pressed: false,
187                 }
188             }
189             xlib::MotionNotify => XEventEnum::Motion(
190                 // TODO(b/315870313): Add safety comment
191                 #[allow(clippy::undocumented_unsafe_blocks)]
192                 unsafe {
193                     self.0.xmotion
194                 },
195             ),
196             xlib::Expose => XEventEnum::Expose,
197             xlib::ClientMessage => {
198                 XEventEnum::ClientMessage(
199                     // TODO(b/315870313): Add safety comment
200                     #[allow(clippy::undocumented_unsafe_blocks)]
201                     unsafe {
202                         self.0.xclient.data.l[0] as u64
203                     },
204                 )
205             }
206             t if t == shm_complete_type => {
207                 // Because XShmCompletionEvent is not part of the XEvent union, simulate a union
208                 // with transmute_copy. If the shm_complete_type turns out to be bogus, some of the
209                 // data would be incorrect, but the common event fields would still be valid.
210                 // TODO(b/315870313): Add safety comment
211                 #[allow(clippy::undocumented_unsafe_blocks)]
212                 let ev_completion: xlib::XShmCompletionEvent = unsafe { transmute_copy(&self.0) };
213                 XEventEnum::ShmCompletionEvent(ev_completion.shmseg)
214             }
215             _ => XEventEnum::Unhandled,
216         }
217     }
218 }
219 
220 enum XEventEnum {
221     KeyEvent(xlib::XKeyEvent),
222     ButtonEvent {
223         event: xlib::XButtonEvent,
224         pressed: bool,
225     },
226     Motion(xlib::XMotionEvent),
227     Expose,
228     ClientMessage(u64),
229     ShmCompletionEvent(xlib::ShmSeg),
230     // We don't care about most kinds of events,
231     Unhandled,
232 }
233 
234 struct XScreen(NonNull<xlib::Screen>);
235 
236 impl XScreen {
as_ptr(&self) -> *mut xlib::Screen237     fn as_ptr(&self) -> *mut xlib::Screen {
238         self.0.as_ptr()
239     }
240 
241     /// Gets the screen number of this screen.
get_number(&self) -> i32242     fn get_number(&self) -> i32 {
243         // TODO(b/315870313): Add safety comment
244         #[allow(clippy::undocumented_unsafe_blocks)]
245         unsafe {
246             xlib::XScreenNumberOfScreen(self.as_ptr())
247         }
248     }
249 }
250 
251 struct Buffer {
252     display: XDisplay,
253     image: *mut xlib::XImage,
254     /// The documentation says XShmSegmentInfo must last at least as long as the XImage, which
255     /// probably precludes moving it as well.
256     segment_info: Box<xlib::XShmSegmentInfo>,
257     size: usize,
258     in_use: bool,
259 }
260 
261 impl Drop for Buffer {
drop(&mut self)262     fn drop(&mut self) {
263         // TODO(b/315870313): Add safety comment
264         #[allow(clippy::undocumented_unsafe_blocks)]
265         unsafe {
266             xlib::XShmDetach(self.display.as_ptr(), self.segment_info.as_mut());
267             xlib::XDestroyImage(self.image);
268             shmdt(self.segment_info.shmaddr as *const _);
269             shmctl(self.segment_info.shmid, IPC_RMID, null_mut());
270         }
271     }
272 }
273 
274 impl Buffer {
as_volatile_slice(&self) -> VolatileSlice275     fn as_volatile_slice(&self) -> VolatileSlice {
276         // TODO(b/315870313): Add safety comment
277         #[allow(clippy::undocumented_unsafe_blocks)]
278         unsafe {
279             VolatileSlice::from_raw_parts(self.segment_info.shmaddr as *mut _, self.size)
280         }
281     }
282 
stride(&self) -> usize283     fn stride(&self) -> usize {
284         // TODO(b/315870313): Add safety comment
285         #[allow(clippy::undocumented_unsafe_blocks)]
286         unsafe {
287             (*self.image).bytes_per_line as usize
288         }
289     }
290 
bytes_per_pixel(&self) -> usize291     fn bytes_per_pixel(&self) -> usize {
292         // TODO(b/315870313): Add safety comment
293         #[allow(clippy::undocumented_unsafe_blocks)]
294         let bytes_per_pixel = unsafe { (*self.image).bits_per_pixel / 8 };
295         bytes_per_pixel as usize
296     }
297 }
298 
299 // Surfaces here are equivalent to XWindows.
300 struct XSurface {
301     display: XDisplay,
302     visual: *mut xlib::Visual,
303     depth: u32,
304     window: xlib::Window,
305     gc: xlib::GC,
306     width: u32,
307     height: u32,
308 
309     // Fields for handling the buffer swap chain.
310     buffers: [Option<Buffer>; BUFFER_COUNT],
311     buffer_next: usize,
312     buffer_completion_type: u32,
313 
314     // Fields for handling window close requests
315     delete_window_atom: c_ulong,
316     close_requested: bool,
317 }
318 
319 impl XSurface {
320     /// Returns index of the current (on-screen) buffer, or 0 if there are no buffers.
current_buffer(&self) -> usize321     fn current_buffer(&self) -> usize {
322         match self.buffer_next.checked_sub(1) {
323             Some(i) => i,
324             None => self.buffers.len() - 1,
325         }
326     }
327 
328     /// Draws the indicated buffer onto the screen.
draw_buffer(&mut self, buffer_index: usize)329     fn draw_buffer(&mut self, buffer_index: usize) {
330         let buffer = match self.buffers.get_mut(buffer_index) {
331             Some(Some(b)) => b,
332             _ => {
333                 // If there is no buffer, that means the framebuffer was never set and we should
334                 // simply blank the window with arbitrary contents.
335                 // TODO(b/315870313): Add safety comment
336                 #[allow(clippy::undocumented_unsafe_blocks)]
337                 unsafe {
338                     xlib::XClearWindow(self.display.as_ptr(), self.window);
339                 }
340                 return;
341             }
342         };
343         // Mark the buffer as in use. When the XShmCompletionEvent occurs, this will get marked
344         // false.
345         buffer.in_use = true;
346         // TODO(b/315870313): Add safety comment
347         #[allow(clippy::undocumented_unsafe_blocks)]
348         unsafe {
349             xlib::XShmPutImage(
350                 self.display.as_ptr(),
351                 self.window,
352                 self.gc,
353                 buffer.image,
354                 0, // src x
355                 0, // src y
356                 0, // dst x
357                 0, // dst y
358                 self.width,
359                 self.height,
360                 true as i32, /* send XShmCompletionEvent event */
361             );
362             self.display.flush();
363         }
364     }
365 
366     /// Gets the buffer at buffer_index, allocating it if necessary.
lazily_allocate_buffer(&mut self, buffer_index: usize) -> Option<&Buffer>367     fn lazily_allocate_buffer(&mut self, buffer_index: usize) -> Option<&Buffer> {
368         if buffer_index >= self.buffers.len() {
369             return None;
370         }
371 
372         if self.buffers[buffer_index].is_some() {
373             return self.buffers[buffer_index].as_ref();
374         }
375         // The buffer_index is valid and the buffer was never created, so we create it now.
376         // TODO(b/315870313): Add safety comment
377         #[allow(clippy::undocumented_unsafe_blocks)]
378         unsafe {
379             // The docs for XShmCreateImage imply that XShmSegmentInfo must be allocated to live at
380             // least as long as the XImage, which probably means it can't move either. Use a Box in
381             // order to fulfill those requirements.
382             let mut segment_info: Box<xlib::XShmSegmentInfo> = Box::new(zeroed());
383             let image = xlib::XShmCreateImage(
384                 self.display.as_ptr(),
385                 self.visual,
386                 self.depth,
387                 xlib::ZPixmap as i32,
388                 null_mut(),
389                 segment_info.as_mut(),
390                 self.width,
391                 self.height,
392             );
393             if image.is_null() {
394                 return None;
395             }
396             let size = (*image)
397                 .bytes_per_line
398                 .checked_mul((*image).height)
399                 .unwrap();
400             segment_info.shmid = shmget(IPC_PRIVATE, size as usize, IPC_CREAT | 0o777);
401             if segment_info.shmid == -1 {
402                 xlib::XDestroyImage(image);
403                 return None;
404             }
405             segment_info.shmaddr = shmat(segment_info.shmid, null_mut(), 0) as *mut _;
406             if segment_info.shmaddr == (-1isize) as *mut _ {
407                 xlib::XDestroyImage(image);
408                 shmctl(segment_info.shmid, IPC_RMID, null_mut());
409                 return None;
410             }
411             (*image).data = segment_info.shmaddr;
412             segment_info.readOnly = true as i32;
413             xlib::XShmAttach(self.display.as_ptr(), segment_info.as_mut());
414             self.buffers[buffer_index] = Some(Buffer {
415                 display: self.display.clone(),
416                 image,
417                 segment_info,
418                 size: size as usize,
419                 in_use: false,
420             });
421             self.buffers[buffer_index].as_ref()
422         }
423     }
424 }
425 
426 impl GpuDisplaySurface for XSurface {
427     #[allow(clippy::unnecessary_cast)]
surface_descriptor(&self) -> u64428     fn surface_descriptor(&self) -> u64 {
429         self.window as u64
430     }
431 
framebuffer(&mut self) -> Option<GpuDisplayFramebuffer>432     fn framebuffer(&mut self) -> Option<GpuDisplayFramebuffer> {
433         // Framebuffers are lazily allocated. If the next buffer is not in self.buffers, add it
434         // using push_new_buffer and then get its memory.
435         let framebuffer = self.lazily_allocate_buffer(self.buffer_next)?;
436         let bytes_per_pixel = framebuffer.bytes_per_pixel() as u32;
437         Some(GpuDisplayFramebuffer::new(
438             framebuffer.as_volatile_slice(),
439             framebuffer.stride() as u32,
440             bytes_per_pixel,
441         ))
442     }
443 
next_buffer_in_use(&self) -> bool444     fn next_buffer_in_use(&self) -> bool {
445         // Buffers that have not yet been made are not in use, hence unwrap_or(false).
446         self.buffers
447             .get(self.buffer_next)
448             .and_then(|b| Some(b.as_ref()?.in_use))
449             .unwrap_or(false)
450     }
451 
close_requested(&self) -> bool452     fn close_requested(&self) -> bool {
453         self.close_requested
454     }
455 
flip(&mut self)456     fn flip(&mut self) {
457         let current_buffer_index = self.buffer_next;
458         self.buffer_next = (self.buffer_next + 1) % self.buffers.len();
459         self.draw_buffer(current_buffer_index);
460     }
461 
buffer_completion_type(&self) -> u32462     fn buffer_completion_type(&self) -> u32 {
463         self.buffer_completion_type
464     }
465 
draw_current_buffer(&mut self)466     fn draw_current_buffer(&mut self) {
467         self.draw_buffer(self.current_buffer())
468     }
469 
on_client_message(&mut self, client_data: u64)470     fn on_client_message(&mut self, client_data: u64) {
471         if client_data == self.delete_window_atom {
472             self.close_requested = true;
473         }
474     }
475 
on_shm_completion(&mut self, shm_complete: u64)476     fn on_shm_completion(&mut self, shm_complete: u64) {
477         for buffer in self.buffers.iter_mut().flatten() {
478             if buffer.segment_info.shmseg == shm_complete {
479                 buffer.in_use = false;
480             }
481         }
482     }
483 }
484 
485 impl Drop for XSurface {
drop(&mut self)486     fn drop(&mut self) {
487         // SAFETY:
488         // Safe given it should always be of the correct type.
489         unsafe {
490             xlib::XFreeGC(self.display.as_ptr(), self.gc);
491             xlib::XDestroyWindow(self.display.as_ptr(), self.window);
492         }
493     }
494 }
495 
496 pub struct DisplayX {
497     display: XDisplay,
498     screen: XScreen,
499     visual: *mut xlib::Visual,
500     keycode_translator: KeycodeTranslator,
501     current_event: Option<XEvent>,
502     mt_tracking_id: u16,
503 }
504 
505 impl DisplayX {
open_display(display: Option<&str>) -> GpuDisplayResult<DisplayX>506     pub fn open_display(display: Option<&str>) -> GpuDisplayResult<DisplayX> {
507         let display_cstr = match display.map(CString::new) {
508             Some(Ok(s)) => Some(s),
509             Some(Err(_)) => return Err(GpuDisplayError::InvalidPath),
510             None => None,
511         };
512 
513         let keycode_translator = KeycodeTranslator::new(KeycodeTypes::XkbScancode);
514 
515         // TODO(b/315870313): Add safety comment
516         #[allow(clippy::undocumented_unsafe_blocks)]
517         unsafe {
518             // Open the display
519             let display = match NonNull::new(xlib::XOpenDisplay(
520                 display_cstr
521                     .as_ref()
522                     .map(|s| CStr::as_ptr(s))
523                     .unwrap_or(null()),
524             )) {
525                 Some(display_ptr) => XDisplay(Rc::new(display_ptr)),
526                 None => return Err(GpuDisplayError::Connect),
527             };
528 
529             // Check for required extension.
530             if !display.supports_shm() {
531                 return Err(GpuDisplayError::RequiredFeature("xshm extension"));
532             }
533 
534             let screen = display
535                 .default_screen()
536                 .ok_or(GpuDisplayError::Connect)
537                 .unwrap();
538             let screen_number = screen.get_number();
539 
540             // Check for and save required visual (24-bit BGR for the default screen).
541             let mut visual_info_template = xlib::XVisualInfo {
542                 visual: null_mut(),
543                 visualid: 0,
544                 screen: screen_number,
545                 depth: 24,
546                 class: 0,
547                 red_mask: 0x00ff0000,
548                 green_mask: 0x0000ff00,
549                 blue_mask: 0x000000ff,
550                 colormap_size: 0,
551                 bits_per_rgb: 0,
552             };
553             let visual_info = xlib::XGetVisualInfo(
554                 display.as_ptr(),
555                 (xlib::VisualScreenMask
556                     | xlib::VisualDepthMask
557                     | xlib::VisualRedMaskMask
558                     | xlib::VisualGreenMaskMask
559                     | xlib::VisualBlueMaskMask) as i64,
560                 &mut visual_info_template,
561                 &mut 0,
562             );
563             if visual_info.is_null() {
564                 return Err(GpuDisplayError::RequiredFeature("no matching visual"));
565             }
566             let visual = (*visual_info).visual;
567             x_free(visual_info);
568 
569             Ok(DisplayX {
570                 display,
571                 screen,
572                 visual,
573                 keycode_translator,
574                 current_event: None,
575                 mt_tracking_id: 0,
576             })
577         }
578     }
579 
next_tracking_id(&mut self) -> i32580     pub fn next_tracking_id(&mut self) -> i32 {
581         let cur_id: i32 = self.mt_tracking_id as i32;
582         self.mt_tracking_id = self.mt_tracking_id.wrapping_add(1);
583         cur_id
584     }
585 
current_tracking_id(&self) -> i32586     pub fn current_tracking_id(&self) -> i32 {
587         self.mt_tracking_id as i32
588     }
589 }
590 
591 impl DisplayT for DisplayX {
pending_events(&self) -> bool592     fn pending_events(&self) -> bool {
593         // TODO(b/315870313): Add safety comment
594         #[allow(clippy::undocumented_unsafe_blocks)]
595         unsafe {
596             xlib::XPending(self.display.as_ptr()) != 0
597         }
598     }
599 
flush(&self)600     fn flush(&self) {
601         self.display.flush();
602     }
603 
604     #[allow(clippy::unnecessary_cast)]
next_event(&mut self) -> GpuDisplayResult<u64>605     fn next_event(&mut self) -> GpuDisplayResult<u64> {
606         let ev = self.display.next_event();
607         let descriptor = ev.window() as u64;
608         self.current_event = Some(ev);
609         Ok(descriptor)
610     }
611 
handle_next_event( &mut self, surface: &mut Box<dyn GpuDisplaySurface>, ) -> Option<GpuDisplayEvents>612     fn handle_next_event(
613         &mut self,
614         surface: &mut Box<dyn GpuDisplaySurface>,
615     ) -> Option<GpuDisplayEvents> {
616         // Should not panic since the common layer only calls this when an event exists.
617         let ev = self.current_event.take().unwrap();
618 
619         match ev.as_enum(surface.buffer_completion_type()) {
620             XEventEnum::KeyEvent(key) => {
621                 if let Some(linux_keycode) = self.keycode_translator.translate(key.keycode) {
622                     let events = vec![virtio_input_event::key(
623                         linux_keycode,
624                         key.type_ == xlib::KeyPress as i32,
625                         false,
626                     )];
627 
628                     return Some(GpuDisplayEvents {
629                         events,
630                         device_type: EventDeviceKind::Keyboard,
631                     });
632                 }
633             }
634             XEventEnum::ButtonEvent {
635                 event: button_event,
636                 pressed,
637             } => {
638                 // We only support a single touch from button 1 (left mouse button).
639                 // TODO(tutankhamen): slot is always 0, because all the input
640                 // events come from mouse device, i.e. only one touch is possible at a time.
641                 // Full MT protocol has to be implemented and properly wired later.
642                 if button_event.button & xlib::Button1 != 0 {
643                     // The touch event *must* be first per the Linux input subsystem's guidance.
644                     let mut events = vec![virtio_input_event::multitouch_slot(0)];
645 
646                     if pressed {
647                         events.push(virtio_input_event::multitouch_tracking_id(
648                             self.next_tracking_id(),
649                         ));
650                         events.push(virtio_input_event::multitouch_absolute_x(max(
651                             0,
652                             button_event.x,
653                         )));
654                         events.push(virtio_input_event::multitouch_absolute_y(max(
655                             0,
656                             button_event.y,
657                         )));
658                     } else {
659                         events.push(virtio_input_event::multitouch_tracking_id(-1));
660                     }
661 
662                     return Some(GpuDisplayEvents {
663                         events,
664                         device_type: EventDeviceKind::Touchscreen,
665                     });
666                 }
667             }
668             XEventEnum::Motion(motion) => {
669                 if motion.state & xlib::Button1Mask != 0 {
670                     let events = vec![
671                         virtio_input_event::multitouch_slot(0),
672                         virtio_input_event::multitouch_tracking_id(self.current_tracking_id()),
673                         virtio_input_event::multitouch_absolute_x(max(0, motion.x)),
674                         virtio_input_event::multitouch_absolute_y(max(0, motion.y)),
675                     ];
676 
677                     return Some(GpuDisplayEvents {
678                         events,
679                         device_type: EventDeviceKind::Touchscreen,
680                     });
681                 }
682             }
683             XEventEnum::Expose => surface.draw_current_buffer(),
684             XEventEnum::ClientMessage(xclient_data) => {
685                 surface.on_client_message(xclient_data);
686                 return None;
687             }
688             XEventEnum::ShmCompletionEvent(shmseg) => {
689                 surface.on_shm_completion(shmseg);
690                 return None;
691             }
692             XEventEnum::Unhandled => return None,
693         }
694 
695         None
696     }
697 
create_surface( &mut self, parent_surface_id: Option<u32>, _surface_id: u32, _scanout_id: Option<u32>, display_params: &DisplayParameters, _surf_type: SurfaceType, ) -> GpuDisplayResult<Box<dyn GpuDisplaySurface>>698     fn create_surface(
699         &mut self,
700         parent_surface_id: Option<u32>,
701         _surface_id: u32,
702         _scanout_id: Option<u32>,
703         display_params: &DisplayParameters,
704         _surf_type: SurfaceType,
705     ) -> GpuDisplayResult<Box<dyn GpuDisplaySurface>> {
706         if parent_surface_id.is_some() {
707             return Err(GpuDisplayError::Unsupported);
708         }
709 
710         // TODO(b/315870313): Add safety comment
711         #[allow(clippy::undocumented_unsafe_blocks)]
712         unsafe {
713             let (width, height) = display_params.get_virtual_display_size();
714             let depth = xlib::XDefaultDepthOfScreen(self.screen.as_ptr()) as u32;
715 
716             let black_pixel = xlib::XBlackPixelOfScreen(self.screen.as_ptr());
717 
718             let window = xlib::XCreateSimpleWindow(
719                 self.display.as_ptr(),
720                 xlib::XRootWindowOfScreen(self.screen.as_ptr()),
721                 0,
722                 0,
723                 width,
724                 height,
725                 1,
726                 black_pixel,
727                 black_pixel,
728             );
729 
730             xlib::XStoreName(
731                 self.display.as_ptr(),
732                 window,
733                 CStr::from_bytes_with_nul(b"crosvm\0").unwrap().as_ptr(),
734             );
735 
736             let gc = xlib::XCreateGC(self.display.as_ptr(), window, 0, null_mut());
737 
738             // Because the event is from an extension, its type must be calculated dynamically.
739             let buffer_completion_type =
740                 xlib::XShmGetEventBase(self.display.as_ptr()) as u32 + xlib::ShmCompletion;
741 
742             // Mark this window as responding to close requests.
743             let mut delete_window_atom = xlib::XInternAtom(
744                 self.display.as_ptr(),
745                 CStr::from_bytes_with_nul(b"WM_DELETE_WINDOW\0")
746                     .unwrap()
747                     .as_ptr(),
748                 0,
749             );
750             xlib::XSetWMProtocols(self.display.as_ptr(), window, &mut delete_window_atom, 1);
751 
752             let size_hints = xlib::XAllocSizeHints();
753             (*size_hints).flags = (xlib::PMinSize | xlib::PMaxSize) as i64;
754             (*size_hints).max_width = width as i32;
755             (*size_hints).min_width = width as i32;
756             (*size_hints).max_height = height as i32;
757             (*size_hints).min_height = height as i32;
758             xlib::XSetWMNormalHints(self.display.as_ptr(), window, size_hints);
759             x_free(size_hints);
760 
761             // We will use redraw the buffer when we are exposed.
762             xlib::XSelectInput(
763                 self.display.as_ptr(),
764                 window,
765                 (xlib::ExposureMask
766                     | xlib::KeyPressMask
767                     | xlib::KeyReleaseMask
768                     | xlib::ButtonPressMask
769                     | xlib::ButtonReleaseMask
770                     | xlib::PointerMotionMask) as i64,
771             );
772 
773             xlib::XClearWindow(self.display.as_ptr(), window);
774             xlib::XMapRaised(self.display.as_ptr(), window);
775 
776             // Flush everything so that the window is visible immediately.
777             self.display.flush();
778 
779             Ok(Box::new(XSurface {
780                 display: self.display.clone(),
781                 visual: self.visual,
782                 depth,
783                 window,
784                 gc,
785                 width,
786                 height,
787                 buffers: Default::default(),
788                 buffer_next: 0,
789                 buffer_completion_type,
790                 delete_window_atom,
791                 close_requested: false,
792             }))
793         }
794     }
795 }
796 
797 impl SysDisplayT for DisplayX {}
798 
799 impl AsRawDescriptor for DisplayX {
as_raw_descriptor(&self) -> RawDescriptor800     fn as_raw_descriptor(&self) -> RawDescriptor {
801         self.display.as_raw_descriptor()
802     }
803 }
804