Skip to main content

flutterbug/
event.rs

1/* -----------------------------------------------------------------------------------
2 * src/event.rs - An event that is emitted by the X11 server. The main Event object 
3 *                should be an enum that encompasses all other events.
4 * beetle - Simple graphics framework for Rust
5 * Copyright © 2020 not_a_seagull
6 *
7 * This project is licensed under either the Apache 2.0 license or the MIT license, at
8 * your option. For more information, please consult the LICENSE-APACHE or LICENSE-MIT
9 * files in the repository root.
10 * -----------------------------------------------------------------------------------
11 * MIT License:
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining a copy
14 * of this software and associated documentation files (the “Software”), to deal
15 * in the Software without restriction, including without limitation the rights
16 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 * copies of the Software, and to permit persons to whom the Software is
18 * furnished to do so, subject to the following conditions:
19 *
20 * The above copyright notice and this permission notice shall be included in
21 * all copies or substantial portions of the Software.
22 *
23 * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 * THE SOFTWARE.
30 * -----------------------------------------------------------------------------------
31 * Apache 2.0 License Declaration:
32 *
33 * Licensed under the Apache License, Version 2.0 (the "License");
34 * you may not use this file except in compliance with the License.
35 * You may obtain a copy of the License at
36 *
37 *     http://www.apache.org/licenses/LICENSE-2.0
38 *
39 * Unless required by applicable law or agreed to in writing, software
40 * distributed under the License is distributed on an "AS IS" BASIS,
41 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
42 * See the License for the specific language governing permissions and
43 * limitations under the License.
44 * ----------------------------------------------------------------------------------
45 */
46
47use super::{FlutterbugError, GenericDisplay, GenericInputContext, Window};
48use std::{
49    ffi::CString,
50    mem,
51    os::raw::{c_int, c_long, c_uchar, c_uint, c_ulong},
52    ptr::{self, NonNull},
53};
54use x11::xlib::{self, XID};
55
56/// The type of an X11 event.
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub enum EventType {
59    KeyPress,
60    KeyRelease,
61    ButtonPress,
62    ButtonRelease,
63    MotionNotify,
64    EnterNotify,
65    LeaveNotify,
66    FocusIn,
67    FocusOut,
68    KeymapNotify,
69    Expose,
70    GraphicsExpose,
71    NoExpose,
72    CirculateRequest,
73    ConfigureRequest,
74    MapRequest,
75    ResizeRequest,
76    CirculateNotify,
77    ConfigureNotify,
78    CreateNotify,
79    DestroyNotify,
80    GravityNotify,
81    MapNotify,
82    MappingNotify,
83    ReparentNotify,
84    UnmapNotify,
85    VisibilityNotify,
86    ColormapEvent,
87    ClientMessage,
88    PropertyNotify,
89    SelectionClear,
90    SelectionNotify,
91    SelectionRequest,
92}
93
94impl EventType {
95    /// Convert a C integer representing an event to an event
96    pub fn from_int(t: c_int) -> Option<Self> {
97        Some(match t {
98            xlib::KeyPress => Self::KeyPress,
99            xlib::KeyRelease => Self::KeyRelease,
100            xlib::ButtonPress => Self::ButtonPress,
101            xlib::ButtonRelease => Self::ButtonRelease,
102            xlib::MotionNotify => Self::MotionNotify,
103            xlib::EnterNotify => Self::EnterNotify,
104            xlib::LeaveNotify => Self::LeaveNotify,
105            xlib::FocusIn => Self::FocusIn,
106            xlib::FocusOut => Self::FocusOut,
107            xlib::KeymapNotify => Self::KeymapNotify,
108            xlib::Expose => Self::Expose,
109            xlib::GraphicsExpose => Self::GraphicsExpose,
110            xlib::NoExpose => Self::NoExpose,
111            xlib::CirculateRequest => Self::CirculateRequest,
112            xlib::ConfigureRequest => Self::ConfigureRequest,
113            xlib::MapRequest => Self::MapRequest,
114            xlib::ResizeRequest => Self::ResizeRequest,
115            xlib::CirculateNotify => Self::CirculateNotify,
116            xlib::ConfigureNotify => Self::ConfigureNotify,
117            xlib::CreateNotify => Self::CreateNotify,
118            xlib::DestroyNotify => Self::DestroyNotify,
119            xlib::GravityNotify => Self::GravityNotify,
120            xlib::MapNotify => Self::MapNotify,
121            xlib::MappingNotify => Self::MappingNotify,
122            xlib::ReparentNotify => Self::ReparentNotify,
123            xlib::UnmapNotify => Self::UnmapNotify,
124            xlib::VisibilityNotify => Self::VisibilityNotify,
125            xlib::ColormapNotify => Self::ColormapEvent,
126            xlib::ClientMessage => Self::ClientMessage,
127            xlib::PropertyNotify => Self::PropertyNotify,
128            xlib::SelectionClear => Self::SelectionClear,
129            xlib::SelectionNotify => Self::SelectionNotify,
130            xlib::SelectionRequest => Self::SelectionRequest,
131            _ => return None,
132        })
133    }
134
135    /// Convert to a representative C integer.
136    pub fn to_int(self) -> c_int {
137        match self {
138            Self::KeyPress => xlib::KeyPress,
139            Self::KeyRelease => xlib::KeyRelease,
140            Self::ButtonPress => xlib::ButtonPress,
141            Self::ButtonRelease => xlib::ButtonRelease,
142            Self::MotionNotify => xlib::MotionNotify,
143            Self::EnterNotify => xlib::EnterNotify,
144            Self::LeaveNotify => xlib::LeaveNotify,
145            Self::FocusIn => xlib::FocusIn,
146            Self::FocusOut => xlib::FocusOut,
147            Self::KeymapNotify => xlib::KeymapNotify,
148            Self::Expose => xlib::Expose,
149            Self::GraphicsExpose => xlib::GraphicsExpose,
150            Self::NoExpose => xlib::NoExpose,
151            Self::CirculateRequest => xlib::CirculateRequest,
152            Self::ConfigureRequest => xlib::ConfigureRequest,
153            Self::MapRequest => xlib::MapRequest,
154            Self::ResizeRequest => xlib::ResizeRequest,
155            Self::CirculateNotify => xlib::CirculateNotify,
156            Self::ConfigureNotify => xlib::ConfigureNotify,
157            Self::CreateNotify => xlib::CreateNotify,
158            Self::DestroyNotify => xlib::DestroyNotify,
159            Self::GravityNotify => xlib::GravityNotify,
160            Self::MapNotify => xlib::MapNotify,
161            Self::MappingNotify => xlib::MappingNotify,
162            Self::ReparentNotify => xlib::ReparentNotify,
163            Self::UnmapNotify => xlib::UnmapNotify,
164            Self::VisibilityNotify => xlib::VisibilityNotify,
165            Self::ColormapEvent => xlib::ColormapNotify,
166            Self::ClientMessage => xlib::ClientMessage,
167            Self::PropertyNotify => xlib::PropertyNotify,
168            Self::SelectionClear => xlib::SelectionClear,
169            Self::SelectionNotify => xlib::SelectionNotify,
170            Self::SelectionRequest => xlib::SelectionRequest,
171        }
172    }
173}
174
175bitflags::bitflags! {
176    #[doc = "The masks that can be applied to an event listener"]
177    pub struct EventMask : c_long {
178        const NO_EVENT_MASK = xlib::NoEventMask;
179        const KEY_PRESS_MASK = xlib::KeyPressMask;
180        const KEY_RELEASE_MASK = xlib::KeyReleaseMask;
181        const BUTTON_PRESS_MASK = xlib::ButtonPressMask;
182        const BUTTON_RELEASE_MASK = xlib::ButtonReleaseMask;
183        const ENTER_WINDOW_MASK = xlib::EnterWindowMask;
184        const LEAVE_WINDOW_MASK = xlib::LeaveWindowMask;
185        const POINTER_MOTION_MASK = xlib::PointerMotionMask;
186        const POINTER_MOTION_HINT_MASK = xlib::PointerMotionHintMask;
187        const BUTTON_1_MOTION_MASK = xlib::Button1MotionMask;
188        const BUTTON_2_MOTION_MASK = xlib::Button2MotionMask;
189        const BUTTON_3_MOTION_MASK = xlib::Button3MotionMask;
190        const BUTTON_4_MOTION_MASK = xlib::Button4MotionMask;
191        const BUTTON_5_MOTION_MASK = xlib::Button5MotionMask;
192        const BUTTON_MOTION_MASK = xlib::ButtonMotionMask;
193        const KEYMAP_STATE_MASK = xlib::KeymapStateMask;
194        const EXPOSURE_MASK = xlib::ExposureMask;
195        const VISIBILITY_CHANGE_MASK = xlib::VisibilityChangeMask;
196        const STRUCTURE_NOTIFY_MASK = xlib::StructureNotifyMask;
197        const RESIZE_REDIRECT_MASK = xlib::ResizeRedirectMask;
198        const SUBSTRUCTURE_NOTIFY_MASK = xlib::SubstructureNotifyMask;
199        const FOCUS_CHANGE_MASK = xlib::FocusChangeMask;
200        const PROPERTY_CHANGE_MASK = xlib::PropertyChangeMask;
201        const COLORMAP_CHANGE_MASK = xlib::ColormapChangeMask;
202        const OWNER_GRAB_BUTTON_MASK = xlib::OwnerGrabButtonMask;
203    }
204}
205
206/// Non-generic trait for event wrappers.
207pub trait DerivesAnEvent: Sized + Clone {
208    /// Convert this item to an AnyEvent
209    fn as_anyevent(&self) -> AnyEvent {
210        AnyEvent::from_raw(
211            self.kind(),
212            self.serial(),
213            unsafe { self.display() },
214            self.window(),
215            self.from_send_event(),
216        )
217    }
218    /// Get the type of this event.
219    fn kind(&self) -> EventType;
220    /// Get the serial number associated with this event.
221    fn serial(&self) -> c_ulong;
222    /// Get the connection associated with this event.
223    ///
224    /// # Safety
225    ///
226    /// This is unsafe because it circumvents the usual Flutterbug method of
227    /// using the Display/DisplayReference structure.
228    unsafe fn display(&self) -> NonNull<xlib::Display>;
229    /// Get the window ID representing this event.
230    fn window(&self) -> xlib::Window;
231    /// Is the event sent from the SendEvent function?
232    fn from_send_event(&self) -> bool;
233}
234
235/// Trait for event wrappers.
236pub trait DerivesEvent<EvStruct: Copy>: DerivesAnEvent {
237    /// Derive this item from the native struct.
238    fn from_evstruct(xev: EvStruct) -> Result<Self, FlutterbugError>
239    where
240        Self: Sized;
241
242    /// Get the raw inner event.
243    fn inner(&self) -> Result<EvStruct, FlutterbugError>;
244}
245
246/// The default XEvent
247#[derive(Debug, Clone)]
248pub struct AnyEvent {
249    kind: EventType,
250    serial: c_ulong,
251    display: NonNull<xlib::Display>,
252    window: xlib::Window,
253    from_send_event: bool,
254}
255
256impl AnyEvent {
257    /// Fill out with raw details
258    #[inline]
259    pub(crate) fn from_raw(
260        kind: EventType,
261        serial: c_ulong,
262        display: NonNull<xlib::Display>,
263        window: xlib::Window,
264        fse: bool,
265    ) -> Self {
266        Self {
267            kind,
268            serial,
269            display,
270            window,
271            from_send_event: fse,
272        }
273    }
274}
275
276impl DerivesAnEvent for AnyEvent {
277    #[inline]
278    fn as_anyevent(&self) -> Self {
279        self.clone()
280    }
281    #[inline]
282    fn kind(&self) -> EventType {
283        self.kind
284    }
285    #[inline]
286    fn serial(&self) -> c_ulong {
287        self.serial
288    }
289    #[inline]
290    unsafe fn display(&self) -> NonNull<xlib::Display> {
291        self.display
292    }
293    #[inline]
294    fn window(&self) -> xlib::Window {
295        self.window
296    }
297    #[inline]
298    fn from_send_event(&self) -> bool {
299        self.from_send_event
300    }
301}
302
303// impl AnyEvent for all events
304macro_rules! anyev_impl {
305    ($xev: ty [ $winname: ident ]) => {
306        impl DerivesEvent<$xev> for AnyEvent {
307            #[inline]
308            fn from_evstruct(xev: $xev) -> Result<Self, FlutterbugError> {
309                Ok(Self {
310                    kind: EventType::from_int(xev.type_)
311                        .ok_or_else(|| FlutterbugError::InvalidEventType)?,
312                    serial: xev.serial,
313                    display: NonNull::new(xev.display)
314                        .ok_or_else(|| FlutterbugError::DisplayFieldNull)?,
315                    window: xev.$winname,
316                    from_send_event: xev.send_event != 0,
317                })
318            }
319
320            #[inline]
321            fn inner(&self) -> Result<$xev, FlutterbugError> {
322                Err(FlutterbugError::InnerAnyEventInaccessible)
323            }
324        }
325    };
326    ($xev:ty) => {
327        anyev_impl! {$xev[window]}
328    };
329}
330
331// manually implement the AnyEvent
332impl DerivesEvent<xlib::XAnyEvent> for AnyEvent {
333    #[inline]
334    fn from_evstruct(xev: xlib::XAnyEvent) -> Result<Self, FlutterbugError> {
335        Ok(Self {
336            kind: EventType::from_int(xev.type_)
337                .ok_or_else(|| FlutterbugError::InvalidEventType)?,
338            serial: xev.serial,
339            display: NonNull::new(xev.display).ok_or_else(|| FlutterbugError::DisplayFieldNull)?,
340            window: xev.window,
341            from_send_event: xev.send_event != 0,
342        })
343    }
344
345    #[inline]
346    fn inner(&self) -> Result<xlib::XAnyEvent, FlutterbugError> {
347        Ok(xlib::XAnyEvent {
348            type_: self.kind.to_int(),
349            serial: self.serial,
350            display: self.display.as_ptr(),
351            window: self.window,
352            send_event: if self.from_send_event { 1 } else { 0 },
353        })
354    }
355}
356
357anyev_impl! {xlib::XKeyEvent}
358anyev_impl! {xlib::XButtonEvent}
359anyev_impl! {xlib::XMotionEvent}
360anyev_impl! {xlib::XCrossingEvent}
361anyev_impl! {xlib::XFocusChangeEvent}
362anyev_impl! {xlib::XExposeEvent}
363anyev_impl! {xlib::XGraphicsExposeEvent[drawable]}
364anyev_impl! {xlib::XNoExposeEvent[drawable]}
365anyev_impl! {xlib::XVisibilityEvent}
366anyev_impl! {xlib::XCreateWindowEvent[parent]}
367anyev_impl! {xlib::XDestroyWindowEvent}
368anyev_impl! {xlib::XUnmapEvent}
369anyev_impl! {xlib::XMapEvent}
370anyev_impl! {xlib::XMapRequestEvent}
371anyev_impl! {xlib::XReparentEvent}
372anyev_impl! {xlib::XConfigureEvent}
373anyev_impl! {xlib::XGravityEvent}
374anyev_impl! {xlib::XResizeRequestEvent}
375anyev_impl! {xlib::XConfigureRequestEvent}
376anyev_impl! {xlib::XCirculateEvent}
377anyev_impl! {xlib::XCirculateRequestEvent}
378anyev_impl! {xlib::XPropertyEvent}
379anyev_impl! {xlib::XSelectionClearEvent}
380anyev_impl! {xlib::XSelectionRequestEvent[owner]}
381anyev_impl! {xlib::XSelectionEvent[requestor]}
382anyev_impl! {xlib::XColormapEvent}
383anyev_impl! {xlib::XClientMessageEvent}
384anyev_impl! {xlib::XMappingEvent[event]}
385anyev_impl! {xlib::XKeymapEvent}
386
387// manually do one for XErrorEvent
388/*impl DerivesEvent<xlib::XErrorEvent> for AnyEvent {
389    #[inline]
390    fn from_evstruct(xev: xlib::XErrorEvent) -> Result<Self, FlutterbugError> {
391        Ok(Self {
392            kind: EventType::from_int(xev.type_)
393                .ok_or_else(|| FlutterbugError::InvalidEventType)?,
394            window: xev.resourceid,
395            from_send_event: false,
396        })
397    }
398
399    #[inline]
400    fn inner(&self) -> Result<xlib::XErrorEvent, FlutterbugError> {
401        Err(FlutterbugError::StaticMsg(
402            "Unable to access inner element of AnyEvent",
403        ))
404    }
405}*/
406
407// macro to create a new event type
408macro_rules! event_type {
409    ($(#[$attr: meta])* $vis: vis struct $sname: ident : $bname: ty [ $winname: ident ] {
410        $($fvis: vis $fname: ident : $ftname: ty = $sfname: ident),*
411        $(,)?
412    }: $mname: ident) => {
413        $vis mod $mname {
414            #![allow(clippy::all)]
415            #![allow(unused_imports)]
416
417            use crate::{FlutterbugError, GenericDisplay, Window};
418            use super::{DerivesAnEvent, DerivesEvent, EventType};
419            use std::{convert::TryInto, os::raw::{c_char, c_uint, c_ulong, c_int}, ptr::NonNull};
420            use x11::xlib;
421
422            #[derive(Debug, Clone)]
423            $(#[$attr])*
424            pub struct $sname {
425                kind: EventType,
426                serial: c_ulong,
427                display: NonNull<xlib::Display>,
428                window: xlib::Window,
429                from_send_event: bool,
430                inner: $bname,
431                $($fvis $fname: $ftname),*
432            }
433
434            impl DerivesAnEvent for $sname {
435                #[inline]
436                fn kind(&self) -> EventType { self.kind }
437                #[inline]
438                fn serial(&self) -> c_ulong { self.serial }
439                #[inline]
440                unsafe fn display(&self) -> NonNull<xlib::Display> { self.display }
441                #[inline]
442                fn window(&self) -> xlib::Window { self.window }
443                #[inline]
444                fn from_send_event(&self) -> bool { self.from_send_event }
445            }
446
447            impl DerivesEvent<$bname> for $sname {
448                #[inline]
449                fn from_evstruct(ev: $bname) -> Result<Self, FlutterbugError> {
450                    Ok(Self {
451                        kind: EventType::from_int(ev.type_).ok_or_else(|| FlutterbugError::InvalidEventType)?,
452                        serial: ev.serial,
453                        display: NonNull::new(ev.display).ok_or_else(|| FlutterbugError::DisplayFieldNull)?,
454                        window: ev.$winname,
455                        from_send_event: ev.send_event != 0,
456                        inner: ev,
457                        $($fname: ev.$sfname.try_into().unwrap_or_else(|_|
458                            panic!("Tried to convert {} and failed", stringify!($fname))
459                        )),*
460                    })
461                }
462
463                #[inline]
464                fn inner(&self) -> Result<$bname, FlutterbugError> { Ok(self.inner) }
465            }
466
467            type OurStruct = $bname;
468
469            impl $sname {
470               $(#[inline] pub fn $fname(&self) -> $ftname { self.$fname })*
471
472                #[inline]
473                pub fn new(
474                    kind: EventType,
475                    serial: c_ulong,
476                    display: &dyn GenericDisplay,
477                    sender_window: &Window,
478                    fse: bool,
479                    $($fname: $ftname),*
480                ) -> Result<Self, FlutterbugError> {
481                    let inner = OurStruct {
482                        type_: kind.to_int(),
483                        serial,
484                        display: display.raw()?.as_ptr(),
485                        $winname: sender_window.window(),
486                        send_event: if fse { 1 } else { 0 },
487                        $($sfname: $fname.try_into().unwrap_or_else(|_|
488                            panic!("Tried to convert {} and failed", stringify!($fname))
489                        )),*
490                    };
491
492                    Ok(Self {
493                        kind, serial, display: display.raw()?, window: sender_window.window(),
494                        from_send_event: fse,
495                        inner,
496                        $($fname),*
497                    })
498                }
499            }
500        }
501
502        $vis use $mname::*;
503    };
504    ($(#[$attr: meta])* $vis: vis struct $sname: ident : $bname: ty {
505        $($fvis: vis $fname: ident : $ftname: ty = $sfname: ident),*
506        $(,)?
507    }: $mname: ident) => {
508        event_type! {
509            $(#[$attr])*
510            $vis struct $sname : $bname [ window ] {
511                $($fvis $fname: $ftname = $sfname),*
512            } : $mname
513        }
514    };
515}
516
517event_type! {
518    pub struct KeyEvent : xlib::XKeyEvent {
519        root: xlib::Window = root,
520        subwindow: xlib::Window = subwindow,
521        time: xlib::Time = time,
522        x: i32 = x,
523        y: i32 = y,
524        x_root: u32 = x_root,
525        y_root: u32 = y_root,
526        pub state: c_uint = state,
527        keycode: c_uint = keycode,
528        same_screen: xlib::Bool = same_screen,
529    }: key_event
530}
531
532bitflags::bitflags! {
533    #[doc = "Represents function keys that can be depressed"]
534    pub struct FunctionKeys : c_uint {
535        const CONTROL = xlib::ControlMask;
536        const ALT = 8;
537        const SHIFT = xlib::ShiftMask;
538        const CAPS_LOCK = 2;
539    }
540}
541
542impl KeyEvent {
543    /// Tell if a function is in the state.
544    #[inline]
545    pub fn has_function(&self, f: FunctionKeys) -> bool {
546        (self.state & f.bits()) != 0
547    }
548
549    /// Add or remove a function key.
550    #[inline]
551    pub fn set_function(&mut self, f: FunctionKeys, is_in: bool) {
552        if !is_in {
553            self.state &= !f.bits();
554        } else {
555            self.state |= f.bits();
556        }
557    }
558
559    /// Lookup the keysym and text that this symbol corresponds to.
560    #[inline]
561    pub fn lookup(&self) -> Result<(xlib::KeySym, String), FlutterbugError> {
562        const BUFFER_SIZE: usize = 50;
563        let mut inner = self.inner()?;
564        let buffer = crate::cstring_buffer(BUFFER_SIZE);
565        let buffer = buffer.into_raw();
566        let mut ks = 0;
567
568        let _bsize = unsafe {
569            xlib::XLookupString(
570                &mut inner,
571                buffer,
572                BUFFER_SIZE as c_int - 1,
573                &mut ks,
574                ptr::null_mut(),
575            )
576        };
577        let res = unsafe { CString::from_raw(buffer) }.into_string()?;
578
579        Ok((ks, res))
580    }
581
582    /// Lookup the keysym and text that this symbols corresponds to, with full UTF-8 support.
583    #[inline]
584    pub fn lookup_utf8(
585        &self,
586        ic: &dyn GenericInputContext,
587    ) -> Result<(Option<xlib::KeySym>, Option<String>), FlutterbugError> {
588        const BUFFER_SIZE: usize = 50;
589        let mut inner = self.inner()?;
590        let buffer = crate::cstring_buffer(BUFFER_SIZE);
591        let buffer = buffer.into_raw();
592        let mut status = 0;
593        let mut ks = 0;
594
595        let _bsize = unsafe {
596            xlib::Xutf8LookupString(
597                ic.raw()?.as_mut(),
598                &mut inner,
599                buffer,
600                BUFFER_SIZE as c_int - 1,
601                &mut ks,
602                &mut status,
603            )
604        };
605
606        let mut res_str = None;
607        let mut res_ks = None;
608
609        match status {
610            xlib::XBufferOverflow => {
611                return Err(FlutterbugError::StaticMsg("Did not allocate enough memory"));
612            }
613            xlib::XLookupBoth | xlib::XLookupChars => {
614                res_str = Some(unsafe { CString::from_raw(buffer) }.into_string()?);
615            }
616            _ => { /* do nothing */ }
617        }
618
619        match status {
620            xlib::XLookupBoth | xlib::XLookupKeySym => {
621                res_ks = Some(ks);
622            }
623            _ => { /* do nothing */ }
624        }
625
626        Ok((res_ks, res_str))
627    }
628}
629
630event_type! {
631    pub struct ButtonEvent : xlib::XButtonEvent {
632        root: xlib::Window = root,
633        subwindow: xlib::Window = subwindow,
634        time: xlib::Time = time,
635        x: i32 = x,
636        y: i32 = y,
637        x_root: u32 = x_root,
638        y_root: u32 = y_root,
639        state: c_uint = state,
640        button: c_uint = button,
641        same_screen: xlib::Bool = same_screen,
642    }: button_event
643}
644
645event_type! {
646    pub struct MotionEvent : xlib::XMotionEvent {
647        root: xlib::Window = root,
648        subwindow: xlib::Window = subwindow,
649        time: xlib::Time = time,
650        x: i32 = x,
651        y: i32 = y,
652        x_root: u32 = x_root,
653        y_root: u32 = y_root,
654        state: c_uint = state,
655        is_hint: c_char = is_hint,
656        same_screen: xlib::Bool = same_screen,
657    }: motion_event
658}
659
660event_type! {
661    pub struct CrossingEvent : xlib::XCrossingEvent {
662        root: xlib::Window = root,
663        subwindow: xlib::Window = subwindow,
664        time: xlib::Time = time,
665        x: i32 = x,
666        y: i32 = y,
667        x_root: u32 = x_root,
668        y_root: u32 = y_root,
669        state: c_uint = state,
670        mode: c_int = mode,
671        detail: c_int = detail,
672        focus: xlib::Bool = focus,
673        same_screen: xlib::Bool = same_screen,
674    }: crossing_event
675}
676
677event_type! {
678    pub struct FocusChangeEvent : xlib::XFocusChangeEvent {
679        mode: c_int = mode,
680        detail: c_int = detail,
681    }: focus_change_event
682}
683
684event_type! {
685    pub struct ExposeEvent : xlib::XExposeEvent {
686        x: i32 = x,
687        y: i32 = y,
688        width: u32 = width,
689        height: u32 = height,
690        count: i32 = count,
691    }: expose_event
692}
693
694event_type! {
695   pub struct NoExposeEvent : xlib::XNoExposeEvent[drawable] {
696       major_code: c_int = major_code,
697       minor_code: c_int = minor_code,
698   }: no_expose_event
699}
700
701event_type! {
702    pub struct GraphicsExposeEvent : xlib::XGraphicsExposeEvent[drawable] {
703        x: i32 = x,
704        y: i32 = y,
705        width: u32 = width,
706        height: u32 = height,
707        count: i32 = count,
708        major_code: c_int = major_code,
709        minor_code: c_int = minor_code,
710    }: graphics_expose_event
711}
712
713event_type! {
714    pub struct ConfigureEvent : xlib::XConfigureEvent[event] {
715        child: xlib::Window = window,
716        x: i32 = x,
717        y: i32 = y,
718        width: u32 = width,
719        height: u32 = height,
720        border_width: u32 = border_width,
721        above: xlib::Window = above,
722        override_redirect: xlib::Bool = override_redirect,
723    }: configure_event
724}
725
726event_type! {
727    pub struct VisibilityEvent : xlib::XVisibilityEvent {
728        state: c_int = state,
729    }: visibility_event
730}
731
732event_type! {
733    pub struct CreateWindowEvent : xlib::XCreateWindowEvent[parent] {
734        child: xlib::Window = window,
735        x: i32 = x,
736        y: i32 = y,
737        width: u32 = width,
738        height: u32 = height,
739        border_width: u32 = border_width,
740        override_redirect: xlib::Bool = override_redirect,
741    }: create_window_event
742}
743
744event_type! {
745    pub struct DestroyWindowEvent : xlib::XDestroyWindowEvent[event] {
746        child: xlib::Window = window,
747    }: destroy_window_event
748}
749
750event_type! {
751    pub struct UnmapEvent : xlib::XUnmapEvent[event] {
752        child: xlib::Window = window,
753        from_configure: xlib::Bool = from_configure,
754    }: unmap_event
755}
756
757event_type! {
758    pub struct MapEvent : xlib::XMapEvent[event] {
759        child: xlib::Window = window,
760        override_redirect: xlib::Bool = override_redirect,
761    }: map_event
762}
763
764event_type! {
765    pub struct MapRequestEvent : xlib::XMapRequestEvent[parent] {
766        child: xlib::Window = window,
767    }: map_request_event
768}
769
770event_type! {
771    pub struct ReparentEvent : xlib::XReparentEvent[event] {
772        child: xlib::Window = window,
773        parent: xlib::Window = parent,
774        x: i32 = x,
775        y: i32 = y,
776        override_redirect: xlib::Bool = override_redirect,
777    }: reparent_event
778}
779
780event_type! {
781    pub struct GravityEvent : xlib::XGravityEvent[event] {
782        child: xlib::Window = window,
783        x: i32 = x,
784        y: i32 = y,
785    }: gravity_event
786}
787
788event_type! {
789    pub struct ResizeRequestEvent : xlib::XResizeRequestEvent {
790        width: u32 = width,
791        height: u32 = height,
792    }: resize_request_event
793}
794
795event_type! {
796    pub struct ConfigureRequestEvent : xlib::XConfigureRequestEvent {
797        parent: xlib::Window = parent,
798        x: i32 = x,
799        y: i32 = y,
800        width: u32 = width,
801        height: u32 = height,
802        border_width: u32 = border_width,
803        above: xlib::Window = above,
804        detail: c_int = detail,
805        value_mask: c_uint = value_mask,
806    }: configure_request_event
807}
808
809event_type! {
810    pub struct CirculateEvent : xlib::XCirculateEvent {
811        event: xlib::Window = event,
812        place: c_int = place,
813    }: circulate_event
814}
815
816event_type! {
817    pub struct CirculateRequestEvent : xlib::XCirculateRequestEvent {
818        parent: xlib::Window = parent,
819        place: c_int = place,
820    }: circulate_request_event
821}
822
823event_type! {
824    pub struct PropertyEvent : xlib::XPropertyEvent {
825        atom: xlib::Atom = atom,
826        time: xlib::Time = time,
827        state: c_int = state,
828    }: property_event
829}
830
831event_type! {
832    pub struct SelectionClearEvent : xlib::XSelectionClearEvent {
833        selection: xlib::Atom = selection,
834        time: xlib::Time = time,
835    }: selection_clear_event
836}
837
838event_type! {
839    pub struct SelectionRequestEvent : xlib::XSelectionRequestEvent[owner] {
840        requestor: xlib::Window = requestor,
841        selection: xlib::Atom = selection,
842        target: xlib::Atom = target,
843        property: xlib::Atom = property,
844        time: xlib::Time = time,
845    }: selection_request_event
846}
847
848event_type! {
849    pub struct SelectionEvent : xlib::XSelectionEvent[requestor] {
850        selection: xlib::Atom = selection,
851        target: xlib::Atom = target,
852        property: xlib::Atom = property,
853        time: xlib::Time = time,
854    }: selection_event
855}
856
857event_type! {
858    pub struct ColormapEvent : xlib::XColormapEvent {
859        colormap: xlib::Colormap = colormap,
860        state: c_int = state,
861        is_new_map: xlib::Bool = new,
862    }: colormap_event
863}
864
865event_type! {
866    pub struct ClientMessageEvent : xlib::XClientMessageEvent {
867        message_type: xlib::Atom = message_type,
868        format: c_int = format,
869        data: xlib::ClientMessageData = data,
870    }: client_message_event
871}
872
873event_type! {
874    pub struct MappingEvent : xlib::XMappingEvent[event] {
875        request: c_int = request,
876        first_keycode: c_int = first_keycode,
877        count: i32 = count,
878    }: mapping_event
879}
880
881event_type! {
882    pub struct KeymapEvent : xlib::XKeymapEvent {
883        keys: [c_char; 32] = key_vector
884    }: keymap_event
885}
886
887/// The event signifying an X11 error.
888#[derive(Clone)]
889pub struct ErrorEvent {
890    kind: EventType,
891    display: NonNull<xlib::Display>,
892    resource_id: XID,
893    serial: c_ulong,
894    error_code: c_uchar,
895    minor_code: c_uchar,
896    request: c_uchar,
897    err_text: String,
898}
899
900impl DerivesAnEvent for ErrorEvent {
901    #[inline]
902    fn kind(&self) -> EventType {
903        self.kind
904    }
905    #[inline]
906    fn window(&self) -> xlib::Window {
907        self.resource_id
908    }
909    #[inline]
910    fn from_send_event(&self) -> bool {
911        false
912    }
913    #[inline]
914    unsafe fn display(&self) -> NonNull<xlib::Display> {
915        self.display
916    }
917    #[inline]
918    fn serial(&self) -> c_ulong {
919        self.serial
920    }
921}
922
923/// An X11 event that can be received from the event loop.
924#[derive(Debug, Clone)]
925pub enum Event {
926    Any(AnyEvent),
927    Key(KeyEvent),
928    Button(ButtonEvent),
929    Motion(MotionEvent),
930    Crossing(CrossingEvent),
931    FocusChange(FocusChangeEvent),
932    Expose(ExposeEvent),
933    GraphicsExpose(GraphicsExposeEvent),
934    NoExpose(NoExposeEvent),
935    Visibility(VisibilityEvent),
936    CreateWindow(CreateWindowEvent),
937    DestroyWindow(DestroyWindowEvent),
938    Unmap(UnmapEvent),
939    Map(MapEvent),
940    MapRequest(MapRequestEvent),
941    Reparent(ReparentEvent),
942    Configure(ConfigureEvent),
943    Gravity(GravityEvent),
944    ResizeRequest(ResizeRequestEvent),
945    ConfigureRequest(ConfigureRequestEvent),
946    Circulate(CirculateEvent),
947    CirculateRequest(CirculateRequestEvent),
948    Property(PropertyEvent),
949    SelectionClear(SelectionClearEvent),
950    SelectionRequest(SelectionRequestEvent),
951    Selection(SelectionEvent),
952    Colormap(ColormapEvent),
953    ClientMessage(ClientMessageEvent),
954    Mapping(MappingEvent),
955    Keymap(KeymapEvent),
956}
957
958macro_rules! get_inner_property {
959    ($s: ident, $prop: ident) => {
960        match *$s {
961            Event::Any(ref a) => a.$prop(),
962            Event::Key(ref k) => k.$prop(),
963            Event::Button(ref b) => b.$prop(),
964            Event::Motion(ref m) => m.$prop(),
965            Event::Crossing(ref c) => c.$prop(),
966            Event::FocusChange(ref fc) => fc.$prop(),
967            Event::Expose(ref e) => e.$prop(),
968            Event::GraphicsExpose(ref ge) => ge.$prop(),
969            Event::NoExpose(ref ne) => ne.$prop(),
970            Event::Visibility(ref v) => v.$prop(),
971            Event::CreateWindow(ref cw) => cw.$prop(),
972            Event::DestroyWindow(ref dw) => dw.$prop(),
973            Event::Unmap(ref u) => u.$prop(),
974            Event::Map(ref m) => m.$prop(),
975            Event::MapRequest(ref mr) => mr.$prop(),
976            Event::Reparent(ref r) => r.$prop(),
977            Event::Configure(ref c) => c.$prop(),
978            Event::Gravity(ref g) => g.$prop(),
979            Event::ResizeRequest(ref rr) => rr.$prop(),
980            Event::ConfigureRequest(ref cr) => cr.$prop(),
981            Event::Circulate(ref c) => c.$prop(),
982            Event::CirculateRequest(ref cr) => cr.$prop(),
983            Event::Property(ref p) => p.$prop(),
984            Event::SelectionClear(ref sc) => sc.$prop(),
985            Event::SelectionRequest(ref sr) => sr.$prop(),
986            Event::Selection(ref s) => s.$prop(),
987            Event::Colormap(ref cm) => cm.$prop(),
988            Event::ClientMessage(ref cm) => cm.$prop(),
989            Event::Mapping(ref m) => m.$prop(),
990            Event::Keymap(ref k) => k.$prop(),
991        }
992    };
993}
994
995impl DerivesEvent<xlib::XEvent> for Event {
996    fn from_evstruct(x: xlib::XEvent) -> Result<Self, FlutterbugError> {
997        macro_rules! evt {
998            ($bname: ident, $sname: ty, $evfield: ident) => {
999                Ok(Event::$bname(<$sname>::from_evstruct(unsafe {
1000                    x.$evfield
1001                })?))
1002            };
1003        }
1004
1005        let kind = unsafe { x.type_ };
1006        let kind = match EventType::from_int(kind) {
1007            Some(k) => k,
1008            None => return evt!(Any, AnyEvent, any),
1009        };
1010
1011        match kind {
1012            EventType::KeyPress | EventType::KeyRelease => evt!(Key, KeyEvent, key),
1013            EventType::ButtonPress | EventType::ButtonRelease => evt!(Button, ButtonEvent, button),
1014            EventType::MotionNotify => evt!(Motion, MotionEvent, motion),
1015            EventType::FocusIn | EventType::FocusOut => {
1016                evt!(FocusChange, FocusChangeEvent, focus_change)
1017            }
1018            EventType::EnterNotify | EventType::LeaveNotify => {
1019                evt!(Crossing, CrossingEvent, crossing)
1020            }
1021            EventType::KeymapNotify => evt!(Keymap, KeymapEvent, keymap),
1022            EventType::Expose => evt!(Expose, ExposeEvent, expose),
1023            EventType::GraphicsExpose => evt!(GraphicsExpose, GraphicsExposeEvent, graphics_expose),
1024            EventType::NoExpose => evt!(NoExpose, NoExposeEvent, no_expose),
1025            EventType::CirculateRequest => {
1026                evt!(CirculateRequest, CirculateRequestEvent, circulate_request)
1027            }
1028            EventType::ConfigureRequest => {
1029                evt!(ConfigureRequest, ConfigureRequestEvent, configure_request)
1030            }
1031            EventType::MapRequest => evt!(MapRequest, MapRequestEvent, map_request),
1032            EventType::ResizeRequest => evt!(ResizeRequest, ResizeRequestEvent, resize_request),
1033            EventType::CirculateNotify => evt!(Circulate, CirculateEvent, circulate),
1034            EventType::ConfigureNotify => evt!(Configure, ConfigureEvent, configure),
1035            EventType::CreateNotify => evt!(CreateWindow, CreateWindowEvent, create_window),
1036            EventType::DestroyNotify => evt!(DestroyWindow, DestroyWindowEvent, destroy_window),
1037            EventType::GravityNotify => evt!(Gravity, GravityEvent, gravity),
1038            EventType::MapNotify => evt!(Map, MapEvent, map),
1039            EventType::MappingNotify => evt!(Mapping, MappingEvent, mapping),
1040            EventType::ReparentNotify => evt!(Reparent, ReparentEvent, reparent),
1041            EventType::UnmapNotify => evt!(Unmap, UnmapEvent, unmap),
1042            EventType::VisibilityNotify => evt!(Visibility, VisibilityEvent, visibility),
1043            EventType::ColormapEvent => evt!(Colormap, ColormapEvent, colormap),
1044            EventType::ClientMessage => evt!(ClientMessage, ClientMessageEvent, client_message),
1045            EventType::PropertyNotify => evt!(Property, PropertyEvent, property),
1046            EventType::SelectionClear => evt!(SelectionClear, SelectionClearEvent, selection_clear),
1047            EventType::SelectionRequest => {
1048                evt!(SelectionRequest, SelectionRequestEvent, selection_request)
1049            }
1050            EventType::SelectionNotify => evt!(Selection, SelectionEvent, selection),
1051        }
1052    }
1053
1054    #[allow(unused_unsafe)]
1055    fn inner(&self) -> Result<xlib::XEvent, FlutterbugError> {
1056        let mut xev: xlib::XEvent = unsafe { mem::zeroed() };
1057
1058        macro_rules! set_evt {
1059            ($item: ident, $field: ident) => {
1060                unsafe { xev.$field = $item.inner()? }
1061            };
1062        }
1063
1064        match *self {
1065            Event::Any(ref a) => set_evt!(a, any),
1066            Event::Button(ref b) => set_evt!(b, button),
1067            Event::Key(ref k) => set_evt!(k, key),
1068            Event::Motion(ref m) => set_evt!(m, motion),
1069            Event::FocusChange(ref f) => set_evt!(f, focus_change),
1070            Event::Crossing(ref c) => set_evt!(c, crossing),
1071            Event::Keymap(ref km) => set_evt!(km, keymap),
1072            Event::Expose(ref e) => set_evt!(e, expose),
1073            Event::GraphicsExpose(ref ge) => set_evt!(ge, graphics_expose),
1074            Event::NoExpose(ref ne) => set_evt!(ne, no_expose),
1075            Event::CirculateRequest(ref ce) => set_evt!(ce, circulate_request),
1076            Event::ConfigureRequest(ref ce) => set_evt!(ce, configure_request),
1077            Event::MapRequest(ref me) => set_evt!(me, map_request),
1078            Event::ResizeRequest(ref rr) => set_evt!(rr, resize_request),
1079            Event::Circulate(ref cn) => set_evt!(cn, circulate),
1080            Event::Configure(ref cn) => set_evt!(cn, configure),
1081            Event::CreateWindow(ref cn) => set_evt!(cn, create_window),
1082            Event::DestroyWindow(ref dn) => set_evt!(dn, destroy_window),
1083            Event::Gravity(ref gn) => set_evt!(gn, gravity),
1084            Event::Map(ref m) => set_evt!(m, map),
1085            Event::Mapping(ref m) => set_evt!(m, mapping),
1086            Event::Reparent(ref r) => set_evt!(r, reparent),
1087            Event::Unmap(ref u) => set_evt!(u, unmap),
1088            Event::Visibility(ref v) => set_evt!(v, visibility),
1089            Event::Colormap(ref c) => set_evt!(c, colormap),
1090            Event::ClientMessage(ref cm) => set_evt!(cm, client_message),
1091            Event::Property(ref p) => set_evt!(p, property),
1092            Event::SelectionClear(ref sc) => set_evt!(sc, selection_clear),
1093            Event::SelectionRequest(ref sr) => set_evt!(sr, selection_request),
1094            Event::Selection(ref sn) => set_evt!(sn, selection),
1095        }
1096
1097        Ok(xev)
1098    }
1099}
1100
1101impl Event {
1102    /// Get the next event from the event loop.
1103    pub fn next(dpy: &dyn GenericDisplay) -> Result<Event, FlutterbugError> {
1104        let mut xev: xlib::XEvent = unsafe { mem::zeroed() };
1105        unsafe { xlib::XNextEvent(dpy.raw()?.as_mut(), &mut xev) };
1106
1107        Self::from_evstruct(xev)
1108    }
1109
1110    /// Send this event into an event loop.
1111    #[inline]
1112    pub fn send(
1113        self,
1114        dpy: &dyn GenericDisplay,
1115        target: &Window,
1116        propogate: bool,
1117        mask: EventMask,
1118    ) -> Result<(), FlutterbugError> {
1119        let mut ev = self.inner()?;
1120        unsafe {
1121            xlib::XSendEvent(
1122                dpy.raw()?.as_mut(),
1123                target.window(),
1124                if propogate { 1 } else { 0 },
1125                mask.bits(),
1126                &mut ev,
1127            )
1128        };
1129        Ok(())
1130    }
1131
1132    /// Wait for a map event.
1133    #[inline]
1134    pub fn wait_for_map(display: &dyn GenericDisplay) -> Result<(), FlutterbugError> {
1135        'mapwait: loop {
1136            if let Self::Map(_m) = Self::next(display)? {
1137                break 'mapwait;
1138            }
1139        }
1140
1141        Ok(())
1142    }
1143
1144    /// Filter this event if it is a raw event.
1145    #[inline]
1146    pub fn filter(&self, window: Option<&Window>) -> Result<bool, FlutterbugError> {
1147        let mut inner = self.inner()?;
1148        Ok(unsafe {
1149            xlib::XFilterEvent(
1150                &mut inner,
1151                match window {
1152                    Some(w) => w.window(),
1153                    None => 0,
1154                },
1155            )
1156        } != 0)
1157    }
1158}
1159
1160impl DerivesAnEvent for Event {
1161    fn kind(&self) -> EventType {
1162        get_inner_property!(self, kind)
1163    }
1164
1165    fn window(&self) -> xlib::Window {
1166        get_inner_property!(self, window)
1167    }
1168
1169    fn from_send_event(&self) -> bool {
1170        get_inner_property!(self, from_send_event)
1171    }
1172
1173    fn serial(&self) -> c_ulong {
1174        get_inner_property!(self, serial)
1175    }
1176    unsafe fn display(&self) -> NonNull<xlib::Display> {
1177        get_inner_property!(self, display)
1178    }
1179}