summaryrefslogtreecommitdiff
path: root/src/event.rs
blob: 6f5c4276cf5f694a2fa03825e9627b5f2dffc95d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// See LICENSE file for copyright and license details.

use x11::xlib::{
    XEvent,
    XKeyEvent,
    XButtonEvent,
    XMotionEvent,
    XCrossingEvent,
    XCreateWindowEvent,
    XDestroyWindowEvent,
    XUnmapEvent,
    XMapEvent,
    XConfigureEvent,

    XPending,
};
use x11::xlib;
use x11::xlib::Display;

use unix_socket::UnixStream;
use unix_socket::UnixListener;

use libc::c_int;
use libc::{
    FD_SET,
    FD_ZERO,
    FD_ISSET,
    select,
    fd_set,
};
use std::fmt;
use std::ptr;
use std::mem::uninitialized;
use std::cmp::max;
use std::os::unix::io::AsRawFd;

use safe_x11::next_xevent;

pub enum Event {
    Key(XKeyEvent, bool),
    Button(XButtonEvent, bool),
    Drag(XMotionEvent),
    Enter(XCrossingEvent),
    Leave(XCrossingEvent),
    Generic(XEvent),
    Create(XCreateWindowEvent),
    Destroy(XDestroyWindowEvent),
    Unmap(XUnmapEvent),
    Map(XMapEvent),
    Configure(XConfigureEvent),
    Socket(UnixStream),
    NoEvent
}

impl fmt::Debug for Event {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match self {
            &Event::Key(ev, pressed) => format!("Key({}, {})", XEvent::from(ev).get_type(), pressed),
            &Event::Button(ev, pressed) => format!("Button({}, {})", XEvent::from(ev).get_type(), pressed),
            &Event::Drag(ev) => format!("Drag({})", XEvent::from(ev).get_type()),
            &Event::Generic(ev) => format!("Generic({})", XEvent::from(ev).get_type()),
            &Event::Enter(ev) => format!("Enter({})", XEvent::from(ev).get_type()),
            &Event::Leave(ev) => format!("Enter({})", XEvent::from(ev).get_type()),
            &Event::Create(ev) => format!("Create({})", XEvent::from(ev).get_type()),
            &Event::Destroy(ev) => format!("Destroy({})", XEvent::from(ev).get_type()),
            &Event::Unmap(ev) => format!("Unmap({})", XEvent::from(ev).get_type()),
            &Event::Map(ev) => format!("Map({})", XEvent::from(ev).get_type()),
            &Event::Configure(ev) => format!("Configure({})", XEvent::from(ev).get_type()),
            &Event::Socket(_) => format!("Socket()"),
            &Event::NoEvent => format!("NoEvent"),
        };

        write!(f, "{}", s)
    }
}

pub unsafe fn select_event(display: *mut Display, x11fd: c_int, listener: &UnixListener) -> Event {
    // Return right now if there're some XEvent on the queue
    if XPending(display) > 0 {
        return next_event(display);
    }

    let socket_fd = listener.as_raw_fd();
    let mut read_fdset: fd_set = uninitialized();

    FD_ZERO(&mut read_fdset);
    FD_SET(x11fd, &mut read_fdset);
    FD_SET(socket_fd, &mut read_fdset);

    select(max(x11fd, socket_fd) + 1,
           &mut read_fdset, ptr::null_mut(), ptr::null_mut(),
           ptr::null_mut());

    if FD_ISSET(x11fd, &mut read_fdset) {
        next_event(display)
    } else if FD_ISSET(socket_fd, &mut read_fdset) {
        let mut listener_iter = listener.incoming();
        if let Some(Ok(stream)) = listener_iter.nth(0) {
            return Event::Socket(stream)
        } else {
            Event::NoEvent
        }
    } else {
        Event::NoEvent
    }
}

pub fn next_event(display: *mut Display) -> Event {
    let ev = next_xevent(display);

    match ev.get_type() {
        2 => Event::Key(xlib::XKeyEvent::from(ev), true),
        3 => Event::Key(xlib::XKeyEvent::from(ev), false),
        4 => Event::Button(xlib::XButtonEvent::from(ev), true),
        5 => Event::Button(xlib::XButtonEvent::from(ev), false),
        6 => Event::Drag(XMotionEvent::from(ev)),
        7 => Event::Enter(XCrossingEvent::from(ev)),
        8 => Event::Leave(XCrossingEvent::from(ev)),
        16 => Event::Create(XCreateWindowEvent::from(ev)),
        17 => Event::Destroy(XDestroyWindowEvent::from(ev)),
        18 => Event::Unmap(XUnmapEvent::from(ev)),
        19 => Event::Map(XMapEvent::from(ev)),
        22 => Event::Configure(XConfigureEvent::from(ev)),
        e => {
            println!("Unknown event {}", e);
            Event::NoEvent
        },
    }
}