Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/gpu_display/src/gpu_display_x.rs
5394 views
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.
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 {
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.
76
fn as_ptr(&self) -> *mut xlib::Display {
77
self.0.as_ptr()
78
}
79
80
/// Sends any pending commands to the X server.
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.
90
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.
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.
112
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 {
124
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 {
135
fn from(ev: xlib::XEvent) -> XEvent {
136
XEvent(ev)
137
}
138
}
139
140
impl XEvent {
141
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
150
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
159
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.
164
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 {
237
fn as_ptr(&self) -> *mut xlib::Screen {
238
self.0.as_ptr()
239
}
240
241
/// Gets the screen number of this screen.
242
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 {
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 {
275
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
283
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
291
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.
321
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.
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.
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)]
428
fn surface_descriptor(&self) -> u64 {
429
self.window as u64
430
}
431
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
444
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
452
fn close_requested(&self) -> bool {
453
self.close_requested
454
}
455
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
462
fn buffer_completion_type(&self) -> u32 {
463
self.buffer_completion_type
464
}
465
466
fn draw_current_buffer(&mut self) {
467
self.draw_buffer(self.current_buffer())
468
}
469
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
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 {
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 {
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
580
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
586
pub fn current_tracking_id(&self) -> i32 {
587
self.mt_tracking_id as i32
588
}
589
}
590
591
impl DisplayT for DisplayX {
592
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
600
fn flush(&self) {
601
self.display.flush();
602
}
603
604
#[allow(clippy::unnecessary_cast)]
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
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
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(self.display.as_ptr(), window, c"crosvm".as_ptr());
731
732
let gc = xlib::XCreateGC(self.display.as_ptr(), window, 0, null_mut());
733
734
// Because the event is from an extension, its type must be calculated dynamically.
735
let buffer_completion_type =
736
xlib::XShmGetEventBase(self.display.as_ptr()) as u32 + xlib::ShmCompletion;
737
738
// Mark this window as responding to close requests.
739
let mut delete_window_atom =
740
xlib::XInternAtom(self.display.as_ptr(), c"WM_DELETE_WINDOW".as_ptr(), 0);
741
xlib::XSetWMProtocols(self.display.as_ptr(), window, &mut delete_window_atom, 1);
742
743
let size_hints = xlib::XAllocSizeHints();
744
(*size_hints).flags = (xlib::PMinSize | xlib::PMaxSize) as i64;
745
(*size_hints).max_width = width as i32;
746
(*size_hints).min_width = width as i32;
747
(*size_hints).max_height = height as i32;
748
(*size_hints).min_height = height as i32;
749
xlib::XSetWMNormalHints(self.display.as_ptr(), window, size_hints);
750
x_free(size_hints);
751
752
// We will use redraw the buffer when we are exposed.
753
xlib::XSelectInput(
754
self.display.as_ptr(),
755
window,
756
(xlib::ExposureMask
757
| xlib::KeyPressMask
758
| xlib::KeyReleaseMask
759
| xlib::ButtonPressMask
760
| xlib::ButtonReleaseMask
761
| xlib::PointerMotionMask) as i64,
762
);
763
764
xlib::XClearWindow(self.display.as_ptr(), window);
765
xlib::XMapRaised(self.display.as_ptr(), window);
766
767
// Flush everything so that the window is visible immediately.
768
self.display.flush();
769
770
Ok(Box::new(XSurface {
771
display: self.display.clone(),
772
visual: self.visual,
773
depth,
774
window,
775
gc,
776
width,
777
height,
778
buffers: Default::default(),
779
buffer_next: 0,
780
buffer_completion_type,
781
delete_window_atom,
782
close_requested: false,
783
}))
784
}
785
}
786
}
787
788
impl SysDisplayT for DisplayX {}
789
790
impl AsRawDescriptor for DisplayX {
791
fn as_raw_descriptor(&self) -> RawDescriptor {
792
self.display.as_raw_descriptor()
793
}
794
}
795
796