mirror of
https://github.com/rust-windowing/winit.git
synced 2026-09-01 14:20:05 -04:00
Use x11rb for event handling
Signed-off-by: John Nunley <dev@notgull.net>
This commit is contained in:
@@ -44,7 +44,7 @@ impl From<io::Error> for DndDataParseError {
|
|||||||
pub(crate) struct Dnd {
|
pub(crate) struct Dnd {
|
||||||
xconn: Arc<XConnection>,
|
xconn: Arc<XConnection>,
|
||||||
// Populated by XdndEnter event handler
|
// Populated by XdndEnter event handler
|
||||||
pub version: Option<c_long>,
|
pub version: Option<u32>,
|
||||||
pub type_list: Option<Vec<xproto::Atom>>,
|
pub type_list: Option<Vec<xproto::Atom>>,
|
||||||
// Populated by XdndPosition event handler
|
// Populated by XdndPosition event handler
|
||||||
pub source_window: Option<xproto::Window>,
|
pub source_window: Option<xproto::Window>,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -9,8 +9,10 @@ use x11rb::protocol::Event;
|
|||||||
use xim::x11rb::{HasConnection, X11rbClient};
|
use xim::x11rb::{HasConnection, X11rbClient};
|
||||||
use xim::{AttributeName, Client as _, ClientError, ClientHandler, InputStyle, Point};
|
use xim::{AttributeName, Client as _, ClientError, ClientHandler, InputStyle, Point};
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
impl HasConnection for XConnection {
|
impl HasConnection for XConnection {
|
||||||
@@ -78,6 +80,9 @@ pub(super) struct ImeData {
|
|||||||
|
|
||||||
/// Inner IME handler.
|
/// Inner IME handler.
|
||||||
struct ImeHandler {
|
struct ImeHandler {
|
||||||
|
/// Handle to the event queue.
|
||||||
|
event_queue: Rc<RefCell<VecDeque<Event>>>,
|
||||||
|
|
||||||
/// Whether IME is currently disconnected.
|
/// Whether IME is currently disconnected.
|
||||||
disconnected: bool,
|
disconnected: bool,
|
||||||
|
|
||||||
@@ -139,7 +144,11 @@ enum Style {
|
|||||||
|
|
||||||
impl ImeData {
|
impl ImeData {
|
||||||
/// Creates the IME data for the display.
|
/// Creates the IME data for the display.
|
||||||
pub(super) fn new(conn: &Arc<XConnection>, screen: usize) -> Result<Self, X11Error> {
|
pub(super) fn new(
|
||||||
|
conn: &Arc<XConnection>,
|
||||||
|
screen: usize,
|
||||||
|
event_queue: &Rc<RefCell<VecDeque<Event>>>,
|
||||||
|
) -> Result<Self, X11Error> {
|
||||||
// IM servers to try, in order:
|
// IM servers to try, in order:
|
||||||
// - None, which defaults to the environment variable `XMODIFIERS` in xim's impl.
|
// - None, which defaults to the environment variable `XMODIFIERS` in xim's impl.
|
||||||
// - "local", which is the default for most IMEs.
|
// - "local", which is the default for most IMEs.
|
||||||
@@ -154,6 +163,7 @@ impl ImeData {
|
|||||||
return Ok(Self {
|
return Ok(Self {
|
||||||
client,
|
client,
|
||||||
handler: ImeHandler {
|
handler: ImeHandler {
|
||||||
|
event_queue: event_queue.clone(),
|
||||||
disconnected: true,
|
disconnected: true,
|
||||||
ime_events: VecDeque::new(),
|
ime_events: VecDeque::new(),
|
||||||
pending_windows: VecDeque::new(),
|
pending_windows: VecDeque::new(),
|
||||||
@@ -429,8 +439,44 @@ impl ImeData {
|
|||||||
let mut last_event = self.conn().poll_for_event()?;
|
let mut last_event = self.conn().poll_for_event()?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let Some(last_event) = last_event {
|
if let Some(last_event) = last_event.as_ref() {
|
||||||
if self.filter_event(&last_event)? {
|
if self.filter_event(last_event)? {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Check the event queue for events.
|
||||||
|
let event_queue = self.handler.event_queue.clone();
|
||||||
|
let mut event_queue = event_queue.borrow_mut();
|
||||||
|
|
||||||
|
// Check the event queue for events we can use.
|
||||||
|
let mut found_event = false;
|
||||||
|
let mut last_err = None;
|
||||||
|
event_queue.retain(|event| match self.filter_event(event) {
|
||||||
|
Ok(false) => {
|
||||||
|
found_event = true;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Ok(true) => false,
|
||||||
|
Err(err) => {
|
||||||
|
last_err = Some(err);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Push our own event to the queue.
|
||||||
|
if let Some(last_event) = last_event.take() {
|
||||||
|
event_queue.push_back(last_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for errors.
|
||||||
|
if let Some(err) = last_err {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we found an event, then we're done.
|
||||||
|
if found_event {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,7 @@ use std::{
|
|||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
ffi::CStr,
|
ffi::CStr,
|
||||||
fmt,
|
fmt, mem,
|
||||||
mem::MaybeUninit,
|
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
os::{
|
os::{
|
||||||
raw::*,
|
raw::*,
|
||||||
@@ -43,15 +42,12 @@ use std::{
|
|||||||
|
|
||||||
use atoms::*;
|
use atoms::*;
|
||||||
|
|
||||||
use x11rb::x11_utils::X11Error as LogicalError;
|
use x11rb::protocol::{
|
||||||
use x11rb::{
|
xinput::{self, ConnectionExt as _},
|
||||||
connection::RequestConnection,
|
xkb,
|
||||||
protocol::{
|
xproto::{self, ConnectionExt as _},
|
||||||
xinput::{self, ConnectionExt as _},
|
|
||||||
xkb,
|
|
||||||
xproto::{self, ConnectionExt as _},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
use x11rb::x11_utils::X11Error as LogicalError;
|
||||||
use x11rb::{
|
use x11rb::{
|
||||||
errors::{ConnectError, ConnectionError, IdsExhausted, ReplyError},
|
errors::{ConnectError, ConnectionError, IdsExhausted, ReplyError},
|
||||||
xcb_ffi::ReplyOrIdError,
|
xcb_ffi::ReplyOrIdError,
|
||||||
@@ -200,12 +196,15 @@ impl<T: 'static> EventLoop<T> {
|
|||||||
let wm_delete_window = atoms[WM_DELETE_WINDOW];
|
let wm_delete_window = atoms[WM_DELETE_WINDOW];
|
||||||
let net_wm_ping = atoms[_NET_WM_PING];
|
let net_wm_ping = atoms[_NET_WM_PING];
|
||||||
|
|
||||||
|
// Create an event queue.
|
||||||
|
let event_queue = Rc::new(RefCell::new(std::collections::VecDeque::with_capacity(4)));
|
||||||
|
|
||||||
let dnd = Dnd::new(Arc::clone(&xconn))
|
let dnd = Dnd::new(Arc::clone(&xconn))
|
||||||
.expect("Failed to call XInternAtoms when initializing drag and drop");
|
.expect("Failed to call XInternAtoms when initializing drag and drop");
|
||||||
|
|
||||||
let (ime_sender, ime_receiver) = mpsc::channel();
|
let (ime_sender, ime_receiver) = mpsc::channel();
|
||||||
|
|
||||||
let ime = match ime::ImeData::new(&xconn, xconn.default_screen_index()) {
|
let ime = match ime::ImeData::new(&xconn, xconn.default_screen_index(), &event_queue) {
|
||||||
Ok(ime) => Some(ime),
|
Ok(ime) => Some(ime),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Failed to open IME: {e}");
|
log::error!("Failed to open IME: {e}");
|
||||||
@@ -213,21 +212,10 @@ impl<T: 'static> EventLoop<T> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let randr_event_offset = xconn
|
xconn
|
||||||
.select_xrandr_input(root)
|
.select_xrandr_input(root)
|
||||||
.expect("Failed to query XRandR extension");
|
.expect("Failed to query XRandR extension");
|
||||||
|
|
||||||
let xi2ext = xconn
|
|
||||||
.xcb_connection()
|
|
||||||
.extension_information(xinput::X11_EXTENSION_NAME)
|
|
||||||
.expect("Failed to query XInput extension")
|
|
||||||
.expect("X server missing XInput extension");
|
|
||||||
let xkbext = xconn
|
|
||||||
.xcb_connection()
|
|
||||||
.extension_information(xkb::X11_EXTENSION_NAME)
|
|
||||||
.expect("Failed to query XKB extension")
|
|
||||||
.expect("X server missing XKB extension");
|
|
||||||
|
|
||||||
// Check for XInput2 support.
|
// Check for XInput2 support.
|
||||||
xconn
|
xconn
|
||||||
.xcb_connection()
|
.xcb_connection()
|
||||||
@@ -309,13 +297,11 @@ impl<T: 'static> EventLoop<T> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let event_processor = EventProcessor {
|
let event_processor = EventProcessor {
|
||||||
|
event_queue,
|
||||||
target: target.clone(),
|
target: target.clone(),
|
||||||
dnd,
|
dnd,
|
||||||
devices: Default::default(),
|
devices: Default::default(),
|
||||||
randr_event_offset,
|
|
||||||
ime_requests: ime_receiver,
|
ime_requests: ime_receiver,
|
||||||
xi2ext,
|
|
||||||
xkbext,
|
|
||||||
kb_state,
|
kb_state,
|
||||||
num_touch: 0,
|
num_touch: 0,
|
||||||
held_key_press: None,
|
held_key_press: None,
|
||||||
@@ -598,12 +584,10 @@ impl<T: 'static> EventLoop<T> {
|
|||||||
F: FnMut(Event<T>, &RootELW<T>),
|
F: FnMut(Event<T>, &RootELW<T>),
|
||||||
{
|
{
|
||||||
let target = &self.target;
|
let target = &self.target;
|
||||||
let mut xev = MaybeUninit::uninit();
|
|
||||||
let wt = get_xtarget(&self.target);
|
let wt = get_xtarget(&self.target);
|
||||||
|
|
||||||
while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } {
|
while let Some(event) = self.event_processor.poll_one_event() {
|
||||||
let mut xev = unsafe { xev.assume_init() };
|
self.event_processor.process_event(event, |event| {
|
||||||
self.event_processor.process_event(&mut xev, |event| {
|
|
||||||
if let Event::WindowEvent {
|
if let Event::WindowEvent {
|
||||||
window_id: crate::window::WindowId(wid),
|
window_id: crate::window::WindowId(wid),
|
||||||
event: WindowEvent::RedrawRequested,
|
event: WindowEvent::RedrawRequested,
|
||||||
@@ -983,34 +967,6 @@ impl<'a, E: fmt::Debug> CookieResultExt for Result<VoidCookie<'a>, E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// XEvents of type GenericEvent store their actual data in an XGenericEventCookie data structure. This is a wrapper to
|
|
||||||
/// extract the cookie from a GenericEvent XEvent and release the cookie data once it has been processed
|
|
||||||
struct GenericEventCookie<'a> {
|
|
||||||
xconn: &'a XConnection,
|
|
||||||
cookie: ffi::XGenericEventCookie,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> GenericEventCookie<'a> {
|
|
||||||
fn from_event(xconn: &XConnection, event: ffi::XEvent) -> Option<GenericEventCookie<'_>> {
|
|
||||||
unsafe {
|
|
||||||
let mut cookie: ffi::XGenericEventCookie = From::from(event);
|
|
||||||
if (xconn.xlib.XGetEventData)(xconn.display, &mut cookie) == ffi::True {
|
|
||||||
Some(GenericEventCookie { xconn, cookie })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Drop for GenericEventCookie<'a> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
(self.xconn.xlib.XFreeEventData)(self.xconn.display, &mut self.cookie);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mkwid(w: xproto::Window) -> crate::window::WindowId {
|
fn mkwid(w: xproto::Window) -> crate::window::WindowId {
|
||||||
crate::window::WindowId(crate::platform_impl::platform::WindowId(w as _))
|
crate::window::WindowId(crate::platform_impl::platform::WindowId(w as _))
|
||||||
}
|
}
|
||||||
@@ -1112,8 +1068,15 @@ impl Device {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the raw X11 representation for a 32-bit floating point to a double.
|
/// Convert the raw X11 representation for a 32-bit fixed point to a double.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn xinput_fp1616_to_float(fp: xinput::Fp1616) -> f64 {
|
fn xinput_fp1616_to_float(fp: xinput::Fp1616) -> f64 {
|
||||||
(fp as f64) / ((1 << 16) as f64)
|
(fp as f64) / ((1 << 16) as f64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Conver the raw X11 representation for a 64-bit fixed point number to a double.
|
||||||
|
#[inline]
|
||||||
|
fn xinput_fp3232_to_float(fp: xinput::Fp3232) -> f64 {
|
||||||
|
let xinput::Fp3232 { integral, frac } = fp;
|
||||||
|
integral as f64 + (frac as f64 / (1u64 << 32) as f64)
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ pub use self::{cursor::*, geometry::*, hint::*, input::*, window_property::*, wm
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
mem::{self, MaybeUninit},
|
mem::{self, MaybeUninit},
|
||||||
ops::BitAnd,
|
|
||||||
os::raw::*,
|
os::raw::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -34,13 +33,6 @@ pub fn maybe_change<T: PartialEq>(field: &mut Option<T>, value: T) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_flag<T>(bitset: T, flag: T) -> bool
|
|
||||||
where
|
|
||||||
T: Copy + PartialEq + BitAnd<T, Output = T>,
|
|
||||||
{
|
|
||||||
bitset & flag == flag
|
|
||||||
}
|
|
||||||
|
|
||||||
impl XConnection {
|
impl XConnection {
|
||||||
// This is impoartant, so pay attention!
|
// This is impoartant, so pay attention!
|
||||||
// Xlib has an output buffer, and tries to hide the async nature of X from you.
|
// Xlib has an output buffer, and tries to hide the async nature of X from you.
|
||||||
|
|||||||
Reference in New Issue
Block a user