xcb/
event.rs

1use crate::base::{BaseEvent, Raw, ResolveWireEvent, ResolveWireGeEvent};
2use crate::ext::{Extension, ExtensionData};
3use crate::ffi::*;
4use crate::x;
5
6#[cfg(feature = "damage")]
7use crate::damage;
8
9#[cfg(feature = "dri2")]
10use crate::dri2;
11
12#[cfg(feature = "glx")]
13use crate::glx;
14
15#[cfg(feature = "present")]
16use crate::present;
17
18#[cfg(feature = "randr")]
19use crate::randr;
20
21#[cfg(feature = "screensaver")]
22use crate::screensaver;
23
24#[cfg(feature = "shape")]
25use crate::shape;
26
27#[cfg(feature = "shm")]
28use crate::shm;
29
30#[cfg(feature = "sync")]
31use crate::sync;
32
33#[cfg(feature = "xfixes")]
34use crate::xfixes;
35
36#[cfg(feature = "xinput")]
37use crate::xinput;
38
39#[cfg(feature = "xkb")]
40use crate::xkb;
41
42#[cfg(feature = "xprint")]
43use crate::xprint;
44
45#[cfg(feature = "xv")]
46use crate::xv;
47
48/// Unified Event type from the X server.
49#[derive(Debug)]
50pub enum Event {
51    /// The event is issued from the X core protocol.
52    X(x::Event),
53
54    #[cfg(feature = "damage")]
55    /// The event is issued from the `DAMAGE` extension.
56    Damage(damage::Event),
57
58    #[cfg(feature = "dri2")]
59    /// The event is issued from the `DRI2` extension.
60    Dri2(dri2::Event),
61
62    #[cfg(feature = "glx")]
63    /// The event is issued from the `GLX` extension.
64    Glx(glx::Event),
65
66    #[cfg(feature = "present")]
67    /// The event is issued from the `Present` extension.
68    Present(present::Event),
69
70    #[cfg(feature = "randr")]
71    /// The event is issued from the `RANDR` extension.
72    RandR(randr::Event),
73
74    #[cfg(feature = "screensaver")]
75    /// The event is issued from the `MIT-SCREEN-SAVER` extension.
76    ScreenSaver(screensaver::Event),
77
78    #[cfg(feature = "shape")]
79    /// The event is issued from the `SHAPE` extension.
80    Shape(shape::Event),
81
82    #[cfg(feature = "shm")]
83    /// The event is issued from the `MIT-SHM` extension.
84    Shm(shm::Event),
85
86    #[cfg(feature = "sync")]
87    /// The event is issued from the `SYNC` extension.
88    Sync(sync::Event),
89
90    #[cfg(feature = "xfixes")]
91    /// The event is issued from the `XFIXES` extension.
92    XFixes(xfixes::Event),
93
94    #[cfg(feature = "xinput")]
95    /// The event is issued from the `XInputExtension` extension.
96    Input(xinput::Event),
97
98    #[cfg(feature = "xkb")]
99    /// The event is issued from the `XKEYBOARD` extension.
100    Xkb(xkb::Event),
101
102    #[cfg(feature = "xprint")]
103    /// The event is issued from the `XpExtension` extension.
104    XPrint(xprint::Event),
105
106    #[cfg(feature = "xv")]
107    /// The event is issued from the `XVideo` extension.
108    Xv(xv::Event),
109
110    /// The event was not recognized, it was likely issued from a disabled extension.
111    Unknown(UnknownEvent),
112}
113
114impl Event {
115    pub fn as_raw(&self) -> *mut xcb_generic_event_t {
116        match self {
117            Self::X(e) => e.as_raw(),
118            #[cfg(feature = "damage")]
119            Self::Damage(e) => e.as_raw(),
120            #[cfg(feature = "dri2")]
121            Self::Dri2(e) => e.as_raw(),
122            #[cfg(feature = "glx")]
123            Self::Glx(e) => e.as_raw(),
124            #[cfg(feature = "present")]
125            Self::Present(e) => e.as_raw(),
126            #[cfg(feature = "randr")]
127            Self::RandR(e) => e.as_raw(),
128            #[cfg(feature = "screensaver")]
129            Self::ScreenSaver(e) => e.as_raw(),
130            #[cfg(feature = "shape")]
131            Self::Shape(e) => e.as_raw(),
132            #[cfg(feature = "shm")]
133            Self::Shm(e) => e.as_raw(),
134            #[cfg(feature = "sync")]
135            Self::Sync(e) => e.as_raw(),
136            #[cfg(feature = "xfixes")]
137            Self::XFixes(e) => e.as_raw(),
138            #[cfg(feature = "xinput")]
139            Self::Input(e) => e.as_raw(),
140            #[cfg(feature = "xkb")]
141            Self::Xkb(e) => e.as_raw(),
142            #[cfg(feature = "xprint")]
143            Self::XPrint(e) => e.as_raw(),
144            #[cfg(feature = "xv")]
145            Self::Xv(e) => e.as_raw(),
146            Self::Unknown(e) => e.as_raw(),
147        }
148    }
149}
150
151/// an event was not recognized as part of the core protocol or any enabled extension
152pub struct UnknownEvent {
153    raw: *mut xcb_generic_event_t,
154}
155
156impl Raw<xcb_generic_event_t> for UnknownEvent {
157    unsafe fn from_raw(raw: *mut xcb_generic_event_t) -> Self {
158        UnknownEvent { raw }
159    }
160
161    fn as_raw(&self) -> *mut xcb_generic_event_t {
162        self.raw
163    }
164}
165
166impl BaseEvent for UnknownEvent {
167    const EXTENSION: Option<Extension> = None;
168    const NUMBER: u32 = u32::MAX;
169}
170
171impl UnknownEvent {
172    pub fn response_type(&self) -> u8 {
173        unsafe { (*self.raw).response_type }
174    }
175    pub fn sequence(&self) -> u16 {
176        unsafe { (*self.raw).sequence }
177    }
178    pub fn full_sequence(&self) -> u32 {
179        unsafe { (*self.raw).full_sequence }
180    }
181}
182
183unsafe impl Send for UnknownEvent {}
184unsafe impl Sync for UnknownEvent {}
185
186impl std::fmt::Debug for UnknownEvent {
187    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
188        f.debug_tuple("UnknownEvent").finish()
189    }
190}
191
192impl Drop for UnknownEvent {
193    fn drop(&mut self) {
194        unsafe { libc::free(self.raw as *mut _) }
195    }
196}
197
198/// Resolve an event from the X server
199///
200/// If the event originates from an extension, the `extension_data` parameter must contain the
201/// data for the extension of origin.
202/// If the resolution fails, an `Event::Unknown` is returned.
203///
204/// # Panics
205/// The function will panic if the matches with an `XCB_GE_GENERIC` event, but can't
206/// be resolved as such.
207///
208/// # Safety
209/// The caller must ensure that `event` is a valid pointer to an `xcb_generic_event_t`.
210pub unsafe fn resolve_event(
211    event: *mut xcb_generic_event_t,
212    extension_data: &[ExtensionData],
213) -> Event {
214    let response_type = (*event).response_type & 0x7F;
215
216    if response_type == XCB_GE_GENERIC {
217        let event = event as *mut xcb_ge_generic_event_t;
218        let extension = (*event).extension;
219        for ext in extension_data {
220            if ext.major_opcode == extension {
221                match ext.ext {
222                    #[cfg(feature = "present")]
223                    Extension::Present => {
224                        return Event::Present(present::Event::resolve_wire_ge_event(event));
225                    }
226                    #[cfg(feature = "xinput")]
227                    Extension::Input => {
228                        return Event::Input(xinput::Event::resolve_wire_ge_event(event));
229                    }
230                    _ => panic!("could not resolve Generic Event extension"),
231                }
232            }
233        }
234        return Event::Unknown(UnknownEvent::from_raw(event as *mut _));
235    }
236
237    for data in extension_data {
238        if response_type >= data.first_event && data.first_event != 0 {
239            match data.ext {
240                #[cfg(feature = "damage")]
241                Extension::Damage => {
242                    return Event::Damage(
243                        damage::Event::resolve_wire_event(data.first_event, event).unwrap(),
244                    );
245                }
246
247                #[cfg(feature = "dri2")]
248                Extension::Dri2 => {
249                    return Event::Dri2(
250                        dri2::Event::resolve_wire_event(data.first_event, event).unwrap(),
251                    );
252                }
253
254                #[cfg(feature = "glx")]
255                Extension::Glx => {
256                    return Event::Glx(
257                        glx::Event::resolve_wire_event(data.first_event, event).unwrap(),
258                    );
259                }
260
261                #[cfg(feature = "present")]
262                Extension::Present => {
263                    return Event::Present(
264                        present::Event::resolve_wire_event(data.first_event, event).unwrap(),
265                    );
266                }
267
268                #[cfg(feature = "randr")]
269                Extension::RandR => {
270                    return Event::RandR(
271                        randr::Event::resolve_wire_event(data.first_event, event).unwrap(),
272                    );
273                }
274
275                #[cfg(feature = "screensaver")]
276                Extension::ScreenSaver => {
277                    return Event::ScreenSaver(
278                        screensaver::Event::resolve_wire_event(data.first_event, event).unwrap(),
279                    );
280                }
281
282                #[cfg(feature = "shape")]
283                Extension::Shape => {
284                    return Event::Shape(
285                        shape::Event::resolve_wire_event(data.first_event, event).unwrap(),
286                    );
287                }
288
289                #[cfg(feature = "shm")]
290                Extension::Shm => {
291                    return Event::Shm(
292                        shm::Event::resolve_wire_event(data.first_event, event).unwrap(),
293                    );
294                }
295
296                #[cfg(feature = "sync")]
297                Extension::Sync => {
298                    return Event::Sync(
299                        sync::Event::resolve_wire_event(data.first_event, event).unwrap(),
300                    );
301                }
302
303                #[cfg(feature = "xfixes")]
304                Extension::XFixes => {
305                    return Event::XFixes(
306                        xfixes::Event::resolve_wire_event(data.first_event, event).unwrap(),
307                    );
308                }
309
310                #[cfg(feature = "xinput")]
311                Extension::Input => {
312                    return Event::Input(
313                        xinput::Event::resolve_wire_event(data.first_event, event).unwrap(),
314                    );
315                }
316
317                #[cfg(feature = "xkb")]
318                Extension::Xkb => {
319                    return Event::Xkb(
320                        xkb::Event::resolve_wire_event(data.first_event, event).unwrap(),
321                    );
322                }
323
324                #[cfg(feature = "xprint")]
325                Extension::XPrint => {
326                    return Event::XPrint(
327                        xprint::Event::resolve_wire_event(data.first_event, event).unwrap(),
328                    );
329                }
330
331                #[cfg(feature = "xv")]
332                Extension::Xv => {
333                    return Event::Xv(
334                        xv::Event::resolve_wire_event(data.first_event, event).unwrap(),
335                    );
336                }
337
338                _ => {}
339            }
340        }
341    }
342
343    x::Event::resolve_wire_event(0, event)
344        .map(Event::X)
345        .unwrap_or_else(|| {
346            // SAFETY the event type is checked above and the function panicked if it was
347            // not a basic event (XCB_GE_GENERIC)
348            let unknown = UnknownEvent::from_raw(event);
349            Event::Unknown(unknown)
350        })
351}
352
353#[test]
354fn test_event_send_sync() {
355    fn assert_send<T: Send>() {}
356    fn assert_sync<T: Sync>() {}
357
358    assert_send::<Event>();
359    assert_sync::<Event>();
360}