aboutsummaryrefslogtreecommitdiffstats
path: root/src/api/wayland/context.rs
blob: ad0977c6aa30f9cff35138f80c8dd7c32a6b6465 (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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
use super::wayland::core::{default_display, Display, Registry};
use super::wayland::core::compositor::{Compositor, SurfaceId, WSurface};
use super::wayland::core::output::Output;
use super::wayland::core::seat::{ButtonState, Seat, Pointer, Keyboard, KeyState};
use super::wayland::core::shell::Shell;
use super::wayland_kbd::MappedKeyboard;
use super::keyboard::keycode_to_vkey;


use std::collections::{VecDeque, HashMap};
use std::sync::{Arc, Mutex};

use Event;
use MouseButton;
use ElementState;

enum AnyKeyboard {
    RawKeyBoard(Keyboard),
    XKB(MappedKeyboard)
}

pub struct WaylandContext {
    pub display: Display,
    pub registry: Registry,
    pub compositor: Compositor,
    pub shell: Shell,
    pub seat: Seat,
    pointer: Option<Mutex<Pointer<WSurface>>>,
    keyboard: Option<AnyKeyboard>,
    windows_event_queues: Arc<Mutex<HashMap<SurfaceId, Arc<Mutex<VecDeque<Event>>>>>>,
    current_pointer_surface: Arc<Mutex<Option<SurfaceId>>>,
    current_keyboard_surface: Arc<Mutex<Option<SurfaceId>>>,
    pub outputs: Vec<Arc<Output>>
}

impl WaylandContext {
    pub fn new() -> Option<WaylandContext> {
        let display = match default_display() {
            Some(d) => d,
            None => return None,
        };
        let registry = display.get_registry();
        // let the registry get its events
        display.sync_roundtrip();
        let compositor = match registry.get_compositor() {
            Some(c) => c,
            None => return None,
        };
        let shell = match registry.get_shell() {
            Some(s) => s,
            None => return None,
        };
        let seat = match registry.get_seats().into_iter().next() {
            Some(s) => s,
            None => return None,
        };
        let outputs = registry.get_outputs().into_iter().map(Arc::new).collect::<Vec<_>>();
        // let the other globals get their events
        display.sync_roundtrip();

        let current_pointer_surface = Arc::new(Mutex::new(None));

        // rustc has trouble finding the correct type here, so we explicit it.
        let windows_event_queues = Arc::new(Mutex::new(
            HashMap::<SurfaceId, Arc<Mutex<VecDeque<Event>>>>::new()
        ));

        // handle pointer inputs
        let mut pointer = seat.get_pointer();
        if let Some(ref mut p) = pointer {
            // set the enter/leave callbacks
            let current_surface = current_pointer_surface.clone();
            p.set_enter_action(move |_, _, sid, x, y| {
                *current_surface.lock().unwrap() = Some(sid);
            });
            let current_surface = current_pointer_surface.clone();
            p.set_leave_action(move |_, _, sid| {
                *current_surface.lock().unwrap() = None;
            });
            // set the events callbacks
            let current_surface = current_pointer_surface.clone();
            let event_queues = windows_event_queues.clone();
            p.set_motion_action(move |_, _, x, y| {
                // dispatch to the appropriate queue
                let sid = *current_surface.lock().unwrap();
                if let Some(sid) = sid {
                    let map = event_queues.lock().unwrap();
                    if let Some(queue) = map.get(&sid) {
                        queue.lock().unwrap().push_back(Event::MouseMoved((x as i32,y as i32)))
                    }
                }
            });
            let current_surface = current_pointer_surface.clone();
            let event_queues = windows_event_queues.clone();
            p.set_button_action(move |_, _, sid, b, s| {
                let button = match b {
                    0x110 => MouseButton::Left,
                    0x111 => MouseButton::Right,
                    0x112 => MouseButton::Middle,
                    _ => return
                };
                let state = match s {
                    ButtonState::Released => ElementState::Released,
                    ButtonState::Pressed => ElementState::Pressed
                };
                // dispatch to the appropriate queue
                let sid = *current_surface.lock().unwrap();
                if let Some(sid) = sid {
                    let map = event_queues.lock().unwrap();
                    if let Some(queue) = map.get(&sid) {
                        queue.lock().unwrap().push_back(Event::MouseInput(state, button))
                    }
                }
            });
        }

        // handle keyboard inputs
        let mut keyboard = None;
        let current_keyboard_surface = Arc::new(Mutex::new(None));
        if let Some(mut wkbd) = seat.get_keyboard() {
            display.sync_roundtrip();

            let current_surface = current_keyboard_surface.clone();
            wkbd.set_enter_action(move |_, _, sid, _| {
                *current_surface.lock().unwrap() = Some(sid);
            });
            let current_surface = current_keyboard_surface.clone();
            wkbd.set_leave_action(move |_, _, sid| {
                *current_surface.lock().unwrap() = None;
            });

            let kbd = match MappedKeyboard::new(wkbd) {
                Ok(mkbd) => {
                    // We managed to load a keymap
                    let current_surface = current_keyboard_surface.clone();
                    let event_queues = windows_event_queues.clone();
                    mkbd.set_key_action(move |state, _, _, _, keycode, keystate| {
                        let kstate = match keystate {
                            KeyState::Released => ElementState::Released,
                            KeyState::Pressed => ElementState::Pressed
                        };
                        let mut events = Vec::new();
                        // key event
                        events.push(Event::KeyboardInput(
                            kstate,
                            (keycode & 0xff) as u8,
                            keycode_to_vkey(state, keycode)
                        ));
                        // utf8 events
                        if kstate == ElementState::Pressed {
                            if let Some(txt) = state.get_utf8(keycode) {
                                events.extend(
                                    txt.chars().map(Event::ReceivedCharacter)
                                );
                            }
                        }
                        // dispatch to the appropriate queue
                        let sid = *current_surface.lock().unwrap();
                        if let Some(sid) = sid {
                            let map = event_queues.lock().unwrap();
                            if let Some(queue) = map.get(&sid) {
                                queue.lock().unwrap().extend(events.into_iter());
                            }
                        }
                    });
                    AnyKeyboard::XKB(mkbd)
                },
                Err(mut rkbd) => {
                    // fallback to raw inputs, no virtual keycodes
                    let current_surface = current_keyboard_surface.clone();
                    let event_queues = windows_event_queues.clone();
                    rkbd.set_key_action(move |_, _, _, keycode, keystate| {
                        let kstate = match keystate {
                            KeyState::Released => ElementState::Released,
                            KeyState::Pressed => ElementState::Pressed
                        };
                        let event = Event::KeyboardInput(kstate, (keycode & 0xff) as u8, None);
                        // dispatch to the appropriate queue
                        let sid = *current_surface.lock().unwrap();
                        if let Some(sid) = sid {
                            let map = event_queues.lock().unwrap();
                            if let Some(queue) = map.get(&sid) {
                                queue.lock().unwrap().push_back(event);
                            }
                        }
                    });
                    AnyKeyboard::RawKeyBoard(rkbd)
                }
            };
            keyboard = Some(kbd);
        }

        Some(WaylandContext {
            display: display,
            registry: registry,
            compositor: compositor,
            shell: shell,
            seat: seat,
            pointer: pointer.map(|p| Mutex::new(p)),
            keyboard: keyboard,
            windows_event_queues: windows_event_queues,
            current_pointer_surface: current_pointer_surface,
            current_keyboard_surface: current_keyboard_surface,
            outputs: outputs
        })
    }

    pub fn register_surface(&self, sid: SurfaceId, queue: Arc<Mutex<VecDeque<Event>>>) {
        self.windows_event_queues.lock().unwrap().insert(sid, queue);
        if let Some(ref p) = self.pointer {
            p.lock().unwrap().add_handled_surface(sid);
        }
    }

    pub fn deregister_surface(&self, sid: SurfaceId) {
        self.windows_event_queues.lock().unwrap().remove(&sid);
        if let Some(ref p) = self.pointer {
            p.lock().unwrap().remove_handled_surface(sid);
        }
    }

    pub fn push_event_for(&self, sid: SurfaceId, evt: Event) {
        let mut guard = self.windows_event_queues.lock().unwrap();
        if let Some(queue) = guard.get(&sid) {
            queue.lock().unwrap().push_back(evt);
        }
    }
}