mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-05 10:10:41 +00:00
gpu_display: add X11 input bindings.
Adds bindings to the X11 display window to capture keyboard & mouse input & send it to the guest via an EventDevice. Original implementation by zachr@chromium.org. BUG=chromium:1023975 TEST=None Change-Id: I33156a8ca0b8c610a2080e3b6891cca2a865734b Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1971121 Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Noah Gold <nkgold@google.com> Reviewed-by: Zach Reizner <zachr@chromium.org>
This commit is contained in:
parent
1d80dcc01c
commit
7898b80860
10 changed files with 250 additions and 118 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -153,6 +153,7 @@ dependencies = [
|
|||
"kvm 0.1.0",
|
||||
"kvm_sys 0.1.0",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"linux_input_sys 0.1.0",
|
||||
"msg_on_socket_derive 0.1.0",
|
||||
"msg_socket 0.1.0",
|
||||
"net_sys 0.1.0",
|
||||
|
@ -218,6 +219,7 @@ dependencies = [
|
|||
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"data_model 0.1.0",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"linux_input_sys 0.1.0",
|
||||
"sys_util 0.1.0",
|
||||
]
|
||||
|
||||
|
@ -289,6 +291,15 @@ dependencies = [
|
|||
"sys_util 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux_input_sys"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"data_model 0.1.0",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sys_util 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.5"
|
||||
|
|
|
@ -24,6 +24,7 @@ io_jail = { path = "../io_jail" }
|
|||
kvm = { path = "../kvm" }
|
||||
kvm_sys = { path = "../kvm_sys" }
|
||||
libc = "*"
|
||||
linux_input_sys = { path = "../linux_input_sys" }
|
||||
msg_on_socket_derive = { path = "../msg_socket/msg_on_socket_derive" }
|
||||
msg_socket = { path = "../msg_socket" }
|
||||
net_sys = { path = "../net_sys" }
|
||||
|
|
|
@ -8,6 +8,7 @@ use super::virtio_input_event;
|
|||
use super::InputError;
|
||||
use super::Result;
|
||||
use data_model::DataInit;
|
||||
use linux_input_sys::input_event;
|
||||
use std::collections::VecDeque;
|
||||
use std::io::Read;
|
||||
use std::io::Write;
|
||||
|
@ -15,20 +16,11 @@ use std::mem::size_of;
|
|||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use sys_util::{error, warn};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct input_event {
|
||||
timestamp_fields: [u64; 2],
|
||||
pub type_: u16,
|
||||
pub code: u16,
|
||||
pub value: u32,
|
||||
trait ConvertFromVirtioInputEvent {
|
||||
fn from_virtio_input_event(other: &virtio_input_event) -> input_event;
|
||||
}
|
||||
// Safe because it only has data and has no implicit padding.
|
||||
unsafe impl DataInit for input_event {}
|
||||
|
||||
impl input_event {
|
||||
const EVENT_SIZE: usize = size_of::<input_event>();
|
||||
|
||||
impl ConvertFromVirtioInputEvent for input_event {
|
||||
fn from_virtio_input_event(other: &virtio_input_event) -> input_event {
|
||||
input_event {
|
||||
timestamp_fields: [0, 0],
|
||||
|
|
|
@ -15,11 +15,12 @@ use std::os::unix::io::{AsRawFd, RawFd};
|
|||
use data_model::{DataInit, Le16, Le32};
|
||||
use sys_util::{error, warn, EventFd, GuestMemory, PollContext, PollToken};
|
||||
|
||||
use self::event_source::{input_event, EvdevEventSource, EventSource, SocketEventSource};
|
||||
use self::event_source::{EvdevEventSource, EventSource, SocketEventSource};
|
||||
use super::{
|
||||
copy_config, DescriptorChain, DescriptorError, Interrupt, Queue, Reader, VirtioDevice, Writer,
|
||||
TYPE_INPUT,
|
||||
};
|
||||
use linux_input_sys::input_event;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::{self, Display};
|
||||
use std::io::Read;
|
||||
|
|
|
@ -11,6 +11,7 @@ x = []
|
|||
data_model = { path = "../data_model" }
|
||||
libc = "*"
|
||||
sys_util = { path = "../sys_util" }
|
||||
linux_input_sys = { path = "../linux_input_sys" }
|
||||
|
||||
[build-dependencies]
|
||||
cc = "=1.0.25"
|
||||
|
|
|
@ -2,25 +2,17 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use data_model::DataInit;
|
||||
use linux_input_sys::input_event;
|
||||
use std::collections::VecDeque;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::io::{self, Error, ErrorKind, Read, Write};
|
||||
use std::iter::ExactSizeIterator;
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use std::os::unix::net::UnixStream;
|
||||
|
||||
const EVENT_SIZE: usize = 4;
|
||||
const EVENT_SIZE: usize = input_event::EVENT_SIZE;
|
||||
const EVENT_BUFFER_LEN_MAX: usize = 16 * EVENT_SIZE;
|
||||
|
||||
const EV_SYN: u16 = 0x00;
|
||||
const EV_KEY: u16 = 0x01;
|
||||
const EV_REL: u16 = 0x02;
|
||||
const EV_ABS: u16 = 0x03;
|
||||
const SYN_REPORT: u16 = 0;
|
||||
const REL_X: u16 = 0x00;
|
||||
const REL_Y: u16 = 0x01;
|
||||
const ABS_X: u16 = 0x00;
|
||||
const ABS_Y: u16 = 0x01;
|
||||
|
||||
// /// Half-way build `EventDevice` with only the `event_socket` defined. Finish building the
|
||||
// /// `EventDevice` by using `status_socket`.
|
||||
// pub struct PartialEventDevice(UnixStream);
|
||||
|
@ -45,69 +37,6 @@ pub enum EventDeviceKind {
|
|||
Keyboard,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
|
||||
pub struct EventEncoded {
|
||||
pub type_: u16,
|
||||
pub code: u16,
|
||||
pub value: u32,
|
||||
}
|
||||
|
||||
impl EventEncoded {
|
||||
#[inline]
|
||||
pub fn syn() -> EventEncoded {
|
||||
EventEncoded {
|
||||
type_: EV_SYN,
|
||||
code: SYN_REPORT,
|
||||
value: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn absolute(code: u16, value: u32) -> EventEncoded {
|
||||
EventEncoded {
|
||||
type_: EV_ABS,
|
||||
code,
|
||||
value,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn absolute_x(x: u32) -> EventEncoded {
|
||||
Self::absolute(ABS_X, x)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn absolute_y(y: u32) -> EventEncoded {
|
||||
Self::absolute(ABS_Y, y)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn key(code: u16, pressed: bool) -> EventEncoded {
|
||||
EventEncoded {
|
||||
type_: EV_KEY,
|
||||
code,
|
||||
value: if pressed { 1 } else { 0 },
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_bytes(v: [u8; 8]) -> EventEncoded {
|
||||
EventEncoded {
|
||||
type_: u16::from_le_bytes([v[0], v[1]]),
|
||||
code: u16::from_le_bytes([v[2], v[3]]),
|
||||
value: u32::from_le_bytes([v[4], v[5], v[6], v[7]]),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_bytes(&self) -> [u8; 8] {
|
||||
let a = self.type_.to_le_bytes();
|
||||
let b = self.code.to_le_bytes();
|
||||
let c = self.value.to_le_bytes();
|
||||
[a[0], a[1], b[0], b[1], c[0], c[1], c[2], c[3]]
|
||||
}
|
||||
}
|
||||
|
||||
/// Encapsulates a virtual event device, such as a mouse or keyboard
|
||||
pub struct EventDevice {
|
||||
kind: EventDeviceKind,
|
||||
|
@ -164,7 +93,7 @@ impl EventDevice {
|
|||
self.event_buffer.is_empty()
|
||||
}
|
||||
|
||||
pub fn send_report<E: IntoIterator<Item = EventEncoded>>(
|
||||
pub fn send_report<E: IntoIterator<Item = input_event>>(
|
||||
&mut self,
|
||||
events: E,
|
||||
) -> io::Result<bool>
|
||||
|
@ -177,24 +106,24 @@ impl EventDevice {
|
|||
}
|
||||
|
||||
for event in it {
|
||||
let bytes = event.to_bytes();
|
||||
let bytes = event.as_slice();
|
||||
self.event_buffer.extend(bytes.iter());
|
||||
}
|
||||
|
||||
self.event_buffer
|
||||
.extend(EventEncoded::syn().to_bytes().iter());
|
||||
.extend(input_event::syn().as_slice().iter());
|
||||
|
||||
self.flush_buffered_events()
|
||||
}
|
||||
|
||||
/// Sends the given `event`, returning `Ok(true)` if, after this function returns, there are no
|
||||
/// buffered events remaining.
|
||||
pub fn send_event_encoded(&mut self, event: EventEncoded) -> io::Result<bool> {
|
||||
pub fn send_event_encoded(&mut self, event: input_event) -> io::Result<bool> {
|
||||
if !self.flush_buffered_events()? {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let bytes = event.to_bytes();
|
||||
let bytes = event.as_slice();
|
||||
let written = self.event_socket.write(&bytes)?;
|
||||
|
||||
if written == bytes.len() {
|
||||
|
@ -208,10 +137,16 @@ impl EventDevice {
|
|||
Ok(false)
|
||||
}
|
||||
|
||||
pub fn recv_event_encoded(&self) -> io::Result<EventEncoded> {
|
||||
let mut event_bytes = [0; 8];
|
||||
pub fn recv_event_encoded(&self) -> io::Result<input_event> {
|
||||
let mut event_bytes = [0u8; 24];
|
||||
(&self.event_socket).read_exact(&mut event_bytes)?;
|
||||
Ok(EventEncoded::from_bytes(event_bytes))
|
||||
match input_event::from_slice(&event_bytes) {
|
||||
Some(event) => Ok(*event),
|
||||
None => Err(Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"failed to read input_event",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,9 +20,13 @@ pub const PointerMotionMask: u32 = 64;
|
|||
pub const ExposureMask: u32 = 32768;
|
||||
pub const KeyPress: u32 = 2;
|
||||
pub const KeyRelease: u32 = 3;
|
||||
pub const ButtonPress: u32 = 4;
|
||||
pub const ButtonRelease: u32 = 5;
|
||||
pub const MotionNotify: u32 = 6;
|
||||
pub const Expose: u32 = 12;
|
||||
pub const ClientMessage: u32 = 33;
|
||||
pub const Button1Mask: u32 = 256;
|
||||
pub const Button1: u32 = 1;
|
||||
pub const ZPixmap: u32 = 2;
|
||||
pub const XK_VoidSymbol: u32 = 16777215;
|
||||
pub const XK_BackSpace: u32 = 65288;
|
||||
|
|
|
@ -55,7 +55,11 @@ bindgen --no-layout-tests --no-derive-debug \
|
|||
--whitelist-function XShmPutImage \
|
||||
--whitelist-function XShmQueryExtension \
|
||||
--whitelist-var 'XK_.*' \
|
||||
--whitelist-var ButtonPress \
|
||||
--whitelist-var ButtonPressMask \
|
||||
--whitelist-var Button1 \
|
||||
--whitelist-var Button1Mask \
|
||||
--whitelist-var ButtonRelease \
|
||||
--whitelist-var ButtonReleaseMask \
|
||||
--whitelist-var ClientMessage \
|
||||
--whitelist-var Expose \
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
)]
|
||||
mod xlib;
|
||||
|
||||
use linux_input_sys::input_event;
|
||||
use std::cmp::max;
|
||||
use std::collections::BTreeMap;
|
||||
use std::ffi::{c_void, CStr, CString};
|
||||
use std::mem::{transmute_copy, zeroed};
|
||||
|
@ -18,17 +20,22 @@ use std::num::NonZeroU32;
|
|||
use std::os::raw::c_ulong;
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use std::ptr::{null, null_mut, NonNull};
|
||||
use std::rc::Rc;
|
||||
use std::rc::{Rc, Weak};
|
||||
use std::time::Duration;
|
||||
|
||||
use libc::{shmat, shmctl, shmdt, shmget, IPC_CREAT, IPC_PRIVATE, IPC_RMID};
|
||||
|
||||
use crate::{DisplayT, EventDevice, GpuDisplayError, GpuDisplayFramebuffer};
|
||||
use crate::{
|
||||
keycode_converter::KeycodeTranslator, keycode_converter::KeycodeTypes, DisplayT, EventDevice,
|
||||
EventDeviceKind, GpuDisplayError, GpuDisplayFramebuffer,
|
||||
};
|
||||
|
||||
use data_model::VolatileSlice;
|
||||
use sys_util::{error, PollContext, PollToken, WatchingEvents};
|
||||
|
||||
const BUFFER_COUNT: usize = 2;
|
||||
|
||||
type SurfaceId = NonZeroU32;
|
||||
type ObjectId = NonZeroU32;
|
||||
|
||||
/// A wrapper for XFree that takes any type.
|
||||
unsafe fn x_free<T>(t: *mut T) {
|
||||
|
@ -119,6 +126,16 @@ impl XEvent {
|
|||
// Some of the event types are dynamic so they need to be passed in.
|
||||
fn as_enum(&self, shm_complete_type: u32) -> XEventEnum {
|
||||
match self.type_() {
|
||||
xlib::KeyPress | xlib::KeyRelease => XEventEnum::KeyEvent(unsafe { self.0.xkey }),
|
||||
xlib::ButtonPress => XEventEnum::ButtonEvent {
|
||||
event: unsafe { self.0.xbutton },
|
||||
pressed: true,
|
||||
},
|
||||
xlib::ButtonRelease => XEventEnum::ButtonEvent {
|
||||
event: unsafe { self.0.xbutton },
|
||||
pressed: false,
|
||||
},
|
||||
xlib::MotionNotify => XEventEnum::Motion(unsafe { self.0.xmotion }),
|
||||
xlib::Expose => XEventEnum::Expose,
|
||||
xlib::ClientMessage => {
|
||||
XEventEnum::ClientMessage(unsafe { self.0.xclient.data.l[0] as u64 })
|
||||
|
@ -136,6 +153,12 @@ impl XEvent {
|
|||
}
|
||||
|
||||
enum XEventEnum {
|
||||
KeyEvent(xlib::XKeyEvent),
|
||||
ButtonEvent {
|
||||
event: xlib::XButtonEvent,
|
||||
pressed: bool,
|
||||
},
|
||||
Motion(xlib::XMotionEvent),
|
||||
Expose,
|
||||
ClientMessage(u64),
|
||||
ShmCompletionEvent(xlib::ShmSeg),
|
||||
|
@ -201,6 +224,8 @@ struct Surface {
|
|||
gc: xlib::GC,
|
||||
width: u32,
|
||||
height: u32,
|
||||
event_devices: BTreeMap<ObjectId, EventDevice>,
|
||||
keycode_translator: KeycodeTranslator,
|
||||
|
||||
// Fields for handling the buffer swap chain.
|
||||
buffers: [Option<Buffer>; BUFFER_COUNT],
|
||||
|
@ -220,6 +245,7 @@ impl Surface {
|
|||
width: u32,
|
||||
height: u32,
|
||||
) -> Result<Surface, GpuDisplayError> {
|
||||
let keycode_translator = KeycodeTranslator::new(KeycodeTypes::XkbScancode);
|
||||
unsafe {
|
||||
let depth = xlib::XDefaultDepthOfScreen(screen.as_ptr()) as u32;
|
||||
|
||||
|
@ -263,7 +289,16 @@ impl Surface {
|
|||
x_free(size_hints);
|
||||
|
||||
// We will use redraw the buffer when we are exposed.
|
||||
xlib::XSelectInput(display.as_ptr(), window, xlib::ExposureMask as i64);
|
||||
xlib::XSelectInput(
|
||||
display.as_ptr(),
|
||||
window,
|
||||
(xlib::ExposureMask
|
||||
| xlib::KeyPressMask
|
||||
| xlib::KeyReleaseMask
|
||||
| xlib::ButtonPressMask
|
||||
| xlib::ButtonReleaseMask
|
||||
| xlib::PointerMotionMask) as i64,
|
||||
);
|
||||
|
||||
xlib::XClearWindow(display.as_ptr(), window);
|
||||
xlib::XMapRaised(display.as_ptr(), window);
|
||||
|
@ -279,6 +314,8 @@ impl Surface {
|
|||
gc,
|
||||
width,
|
||||
height,
|
||||
event_devices: Default::default(),
|
||||
keycode_translator,
|
||||
buffers: Default::default(),
|
||||
buffer_next: 0,
|
||||
buffer_completion_type,
|
||||
|
@ -296,8 +333,53 @@ impl Surface {
|
|||
}
|
||||
}
|
||||
|
||||
fn dispatch_to_event_devices(&mut self, events: &[input_event], device_type: EventDeviceKind) {
|
||||
for event_device in self.event_devices.values_mut() {
|
||||
if event_device.kind() != device_type {
|
||||
continue;
|
||||
}
|
||||
if let Err(e) = event_device.send_report(events.iter().cloned()) {
|
||||
error!("error sending events to event device: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&mut self, ev: XEvent) {
|
||||
match ev.as_enum(self.buffer_completion_type) {
|
||||
XEventEnum::KeyEvent(key) => {
|
||||
if let Some(linux_keycode) = self.keycode_translator.translate(key.keycode) {
|
||||
let events = &[input_event::key(
|
||||
linux_keycode,
|
||||
key.type_ == xlib::KeyPress as i32,
|
||||
)];
|
||||
self.dispatch_to_event_devices(events, EventDeviceKind::Keyboard);
|
||||
}
|
||||
}
|
||||
XEventEnum::ButtonEvent {
|
||||
event: button_event,
|
||||
pressed,
|
||||
} => {
|
||||
// We only support a single touch from button 1 (left mouse button).
|
||||
if button_event.button & xlib::Button1 != 0 {
|
||||
// The touch event *must* be first per the Linux input subsystem's guidance.
|
||||
let events = &[
|
||||
input_event::touch(pressed),
|
||||
input_event::absolute_x(max(0, button_event.x) as u32),
|
||||
input_event::absolute_y(max(0, button_event.y) as u32),
|
||||
];
|
||||
self.dispatch_to_event_devices(events, EventDeviceKind::Touchscreen);
|
||||
}
|
||||
}
|
||||
XEventEnum::Motion(motion) => {
|
||||
if motion.state & xlib::Button1Mask != 0 {
|
||||
let events = &[
|
||||
input_event::touch(true),
|
||||
input_event::absolute_x(max(0, motion.x) as u32),
|
||||
input_event::absolute_y(max(0, motion.y) as u32),
|
||||
];
|
||||
self.dispatch_to_event_devices(events, EventDeviceKind::Touchscreen);
|
||||
}
|
||||
}
|
||||
XEventEnum::Expose => self.draw_buffer(self.current_buffer()),
|
||||
XEventEnum::ClientMessage(xclient_data) => {
|
||||
if xclient_data == self.delete_window_atom {
|
||||
|
@ -449,16 +531,26 @@ impl Drop for Surface {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(PollToken)]
|
||||
enum DisplayXPollToken {
|
||||
Display,
|
||||
EventDevice { event_device_id: u32 },
|
||||
}
|
||||
|
||||
pub struct DisplayX {
|
||||
poll_ctx: PollContext<DisplayXPollToken>,
|
||||
display: XDisplay,
|
||||
screen: XScreen,
|
||||
visual: *mut xlib::Visual,
|
||||
next_surface_id: SurfaceId,
|
||||
surfaces: BTreeMap<SurfaceId, Surface>,
|
||||
next_id: ObjectId,
|
||||
surfaces: BTreeMap<ObjectId, Surface>,
|
||||
event_devices: BTreeMap<ObjectId, EventDevice>,
|
||||
}
|
||||
|
||||
impl DisplayX {
|
||||
pub fn open_display(display: Option<&str>) -> Result<DisplayX, GpuDisplayError> {
|
||||
let poll_ctx = PollContext::new().map_err(|_| GpuDisplayError::Allocate)?;
|
||||
|
||||
let display_cstr = match display.map(CString::new) {
|
||||
Some(Ok(s)) => Some(s),
|
||||
Some(Err(_)) => return Err(GpuDisplayError::InvalidPath),
|
||||
|
@ -477,6 +569,10 @@ impl DisplayX {
|
|||
None => return Err(GpuDisplayError::Connect),
|
||||
};
|
||||
|
||||
poll_ctx
|
||||
.add(&display, DisplayXPollToken::Display)
|
||||
.map_err(|_| GpuDisplayError::Allocate)?;
|
||||
|
||||
// Check for required extension.
|
||||
if !display.supports_shm() {
|
||||
return Err(GpuDisplayError::RequiredFeature("xshm extension"));
|
||||
|
@ -518,21 +614,31 @@ impl DisplayX {
|
|||
x_free(visual_info);
|
||||
|
||||
Ok(DisplayX {
|
||||
poll_ctx,
|
||||
display,
|
||||
screen,
|
||||
visual,
|
||||
next_surface_id: SurfaceId::new(1).unwrap(),
|
||||
next_id: ObjectId::new(1).unwrap(),
|
||||
surfaces: Default::default(),
|
||||
event_devices: Default::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn surface_ref(&self, surface_id: u32) -> Option<&Surface> {
|
||||
SurfaceId::new(surface_id).and_then(move |id| self.surfaces.get(&id))
|
||||
ObjectId::new(surface_id).and_then(move |id| self.surfaces.get(&id))
|
||||
}
|
||||
|
||||
fn surface_mut(&mut self, surface_id: u32) -> Option<&mut Surface> {
|
||||
SurfaceId::new(surface_id).and_then(move |id| self.surfaces.get_mut(&id))
|
||||
ObjectId::new(surface_id).and_then(move |id| self.surfaces.get_mut(&id))
|
||||
}
|
||||
|
||||
fn event_device(&self, event_device_id: u32) -> Option<&EventDevice> {
|
||||
ObjectId::new(event_device_id).and_then(move |id| self.event_devices.get(&id))
|
||||
}
|
||||
|
||||
fn event_device_mut(&mut self, event_device_id: u32) -> Option<&mut EventDevice> {
|
||||
ObjectId::new(event_device_id).and_then(move |id| self.event_devices.get_mut(&id))
|
||||
}
|
||||
|
||||
fn handle_event(&mut self, ev: XEvent) {
|
||||
|
@ -545,10 +651,8 @@ impl DisplayX {
|
|||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DisplayT for DisplayX {
|
||||
fn dispatch_events(&mut self) {
|
||||
fn dispatch_display_events(&mut self) {
|
||||
loop {
|
||||
self.display.flush();
|
||||
if !self.display.pending_events() {
|
||||
|
@ -559,6 +663,54 @@ impl DisplayT for DisplayX {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_event_device(&mut self, event_device_id: u32) {
|
||||
if let Some(event_device) = self.event_device(event_device_id) {
|
||||
// TODO(zachr): decode the event and forward to the device.
|
||||
let _ = event_device.recv_event_encoded();
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_poll_ctx(&mut self) -> sys_util::Result<()> {
|
||||
let poll_events = self.poll_ctx.wait_timeout(Duration::default())?.to_owned();
|
||||
for poll_event in poll_events.as_ref().iter_writable() {
|
||||
if let DisplayXPollToken::EventDevice { event_device_id } = poll_event.token() {
|
||||
if let Some(event_device) = self.event_device_mut(event_device_id) {
|
||||
if !event_device.flush_buffered_events()? {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Although this looks exactly like the previous if-block, we need to reborrow self
|
||||
// as immutable in order to make use of self.poll_ctx.
|
||||
if let Some(event_device) = self.event_device(event_device_id) {
|
||||
self.poll_ctx.modify(
|
||||
event_device,
|
||||
WatchingEvents::empty().set_read(),
|
||||
DisplayXPollToken::EventDevice { event_device_id },
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for poll_event in poll_events.as_ref().iter_readable() {
|
||||
match poll_event.token() {
|
||||
DisplayXPollToken::Display => self.dispatch_display_events(),
|
||||
DisplayXPollToken::EventDevice { event_device_id } => {
|
||||
self.handle_event_device(event_device_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DisplayT for DisplayX {
|
||||
fn dispatch_events(&mut self) {
|
||||
if let Err(e) = self.handle_poll_ctx() {
|
||||
error!("failed to dispatch events: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
fn create_surface(
|
||||
&mut self,
|
||||
parent_surface_id: Option<u32>,
|
||||
|
@ -576,15 +728,19 @@ impl DisplayT for DisplayX {
|
|||
width,
|
||||
height,
|
||||
)?;
|
||||
let new_surface_id = self.next_surface_id;
|
||||
let new_surface_id = self.next_id;
|
||||
self.surfaces.insert(new_surface_id, new_surface);
|
||||
self.next_surface_id = SurfaceId::new(self.next_surface_id.get() + 1).unwrap();
|
||||
self.next_id = ObjectId::new(self.next_id.get() + 1).unwrap();
|
||||
|
||||
Ok(new_surface_id.get())
|
||||
}
|
||||
|
||||
fn release_surface(&mut self, surface_id: u32) {
|
||||
SurfaceId::new(surface_id).and_then(|id| self.surfaces.remove(&id));
|
||||
if let Some(mut surface) =
|
||||
ObjectId::new(surface_id).and_then(|id| self.surfaces.remove(&id))
|
||||
{
|
||||
self.event_devices.append(&mut surface.event_devices);
|
||||
}
|
||||
}
|
||||
|
||||
fn framebuffer(&mut self, surface_id: u32) -> Option<GpuDisplayFramebuffer> {
|
||||
|
@ -638,19 +794,46 @@ impl DisplayT for DisplayX {
|
|||
fn set_position(&mut self, surface_id: u32, x: u32, y: u32) {
|
||||
// unsupported
|
||||
}
|
||||
fn import_event_device(&mut self, _event_device: EventDevice) -> Result<u32, GpuDisplayError> {
|
||||
Err(GpuDisplayError::Unsupported)
|
||||
|
||||
fn import_event_device(&mut self, event_device: EventDevice) -> Result<u32, GpuDisplayError> {
|
||||
let new_event_device_id = self.next_id;
|
||||
|
||||
self.poll_ctx
|
||||
.add(
|
||||
&event_device,
|
||||
DisplayXPollToken::EventDevice {
|
||||
event_device_id: new_event_device_id.get(),
|
||||
},
|
||||
)
|
||||
.map_err(|_| GpuDisplayError::Allocate)?;
|
||||
|
||||
self.event_devices.insert(new_event_device_id, event_device);
|
||||
self.next_id = ObjectId::new(self.next_id.get() + 1).unwrap();
|
||||
|
||||
Ok(new_event_device_id.get())
|
||||
}
|
||||
fn release_event_device(&mut self, _event_device_id: u32) {
|
||||
// unsupported
|
||||
|
||||
fn release_event_device(&mut self, event_device_id: u32) {
|
||||
ObjectId::new(event_device_id).and_then(|id| self.event_devices.remove(&id));
|
||||
}
|
||||
|
||||
fn attach_event_device(&mut self, surface_id: u32, event_device_id: u32) {
|
||||
// unsupported
|
||||
let event_device_id = match ObjectId::new(event_device_id) {
|
||||
Some(id) => id,
|
||||
None => return,
|
||||
};
|
||||
let surface_id = match ObjectId::new(surface_id) {
|
||||
Some(id) => id,
|
||||
None => return,
|
||||
};
|
||||
let surface = self.surfaces.get_mut(&surface_id).unwrap();
|
||||
let event_device = self.event_devices.remove(&event_device_id).unwrap();
|
||||
surface.event_devices.insert(event_device_id, event_device);
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for DisplayX {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.display.as_raw_fd()
|
||||
self.poll_ctx.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ mod gpu_display_wl;
|
|||
mod gpu_display_x;
|
||||
mod keycode_converter;
|
||||
|
||||
pub use event_device::{EventDevice, EventDeviceKind, EventEncoded};
|
||||
pub use event_device::{EventDevice, EventDeviceKind};
|
||||
|
||||
/// An error generated by `GpuDisplay`.
|
||||
#[derive(Debug)]
|
||||
|
|
Loading…
Reference in a new issue