makepad_platform/os/linux/x11/
xlib_app.rs

1use {
2    std::{
3        collections::HashMap,
4        mem,
5        rc::Rc,
6        cell::{Cell, RefCell},
7        os::raw::{c_char, c_int, c_uint, c_ulong, c_void, c_uchar, c_long},
8        ptr,
9    },
10    self::super::{
11        x11_sys,
12        xlib_event::XlibEvent,
13        xlib_window::*,
14        super::select_timer::SelectTimers,
15    },
16    crate::{
17        makepad_math::DVec2,
18        event::*,
19        cursor::MouseCursor,
20        os::cx_native::EventFlow,
21    },
22};
23
24static mut XLIB_APP: *mut XlibApp = 0 as *mut _;
25
26pub fn get_xlib_app_global() -> &'static mut XlibApp {
27    unsafe {
28        &mut *(XLIB_APP)
29    }
30}
31
32pub fn init_xlib_app_global(event_callback: Box<dyn FnMut(&mut XlibApp, XlibEvent) -> EventFlow>) {
33    unsafe {
34        XLIB_APP = Box::into_raw(Box::new(XlibApp::new(event_callback)));
35    }
36}
37
38pub struct XlibApp {
39    pub display: *mut x11_sys::Display,
40    event_loop_running: bool,
41    pub xim: x11_sys::XIM,
42    pub clipboard: String,
43    pub display_fd: c_int,
44    //pub signal_fds: [c_int; 2],
45    pub window_map: HashMap<c_ulong, *mut XlibWindow>,
46
47    pub timers: SelectTimers,
48
49    pub last_scroll_time: f64,
50    pub last_click_time: f64,
51    pub last_click_pos: (i32, i32),
52    pub event_callback: Option<Box<dyn FnMut(&mut XlibApp, XlibEvent) -> EventFlow >>,
53    //pub free_timers: Vec<usize>,
54    pub event_flow: EventFlow,
55    pub current_cursor: MouseCursor,
56    pub internal_cursor: MouseCursor,
57    pub atoms: XlibAtoms,
58    pub dnd: Dnd,
59    pub next_keypress_is_repeat: bool,
60}
61
62impl XlibApp {
63    pub fn new(event_callback: Box<dyn FnMut(&mut XlibApp, XlibEvent) -> EventFlow>) -> XlibApp {
64        unsafe {
65            let display = x11_sys::XOpenDisplay(ptr::null());
66            let display_fd = x11_sys::XConnectionNumber(display);
67            let xim = x11_sys::XOpenIM(display, ptr::null_mut(), ptr::null_mut(), ptr::null_mut());
68            //let mut signal_fds = [0, 0];
69            //libc_sys::pipe(signal_fds.as_mut_ptr());
70            x11_sys::XrmInitialize();
71            XlibApp {
72                event_loop_running: true,
73                event_callback: Some(event_callback),
74                atoms: XlibAtoms::new(display),
75                xim,
76                display,
77                display_fd,
78                //signal_fds,
79                clipboard: String::new(),
80                last_scroll_time: 0.0,
81                last_click_time: 0.0,
82                last_click_pos: (0, 0),
83                window_map: HashMap::new(),
84                timers: SelectTimers::new(),
85                event_flow: EventFlow::Poll,
86                //free_timers: Vec::new(),
87                current_cursor: MouseCursor::Default,
88                internal_cursor: MouseCursor::Default,
89                dnd: Dnd::new(display),
90                next_keypress_is_repeat: false,
91            }
92        }
93    }
94    
95    pub unsafe fn event_loop_poll(&mut self) {
96        // Update the current time, and compute the amount of time that elapsed since we
97        // last recorded the current time.
98        while self.display != ptr::null_mut() && x11_sys::XPending(self.display) != 0 {
99            let mut event = mem::MaybeUninit::uninit();
100            x11_sys::XNextEvent(self.display, event.as_mut_ptr());
101            let mut event = event.assume_init();
102            match event.type_ as u32 {
103                x11_sys::SelectionNotify => {
104                    let selection = event.xselection;
105                    if selection.property == self.dnd.atoms.selection {
106                        self.dnd.handle_selection_event(&selection);
107                    } else {
108                        // first get the size of the thing
109                        let mut actual_type = mem::MaybeUninit::uninit();
110                        let mut actual_format = mem::MaybeUninit::uninit();
111                        let mut n_items = mem::MaybeUninit::uninit();
112                        let mut bytes_to_read = mem::MaybeUninit::uninit();
113                        let mut ret = mem::MaybeUninit::uninit();
114                        x11_sys::XGetWindowProperty(
115                            self.display,
116                            selection.requestor,
117                            selection.property,
118                            0,
119                            0,
120                            0,
121                            x11_sys::AnyPropertyType as c_ulong,
122                            actual_type.as_mut_ptr(),
123                            actual_format.as_mut_ptr(),
124                            n_items.as_mut_ptr(),
125                            bytes_to_read.as_mut_ptr(),
126                            ret.as_mut_ptr()
127                        );
128                        //let actual_type = actual_type.assume_init();
129                        //let actual_format = actual_format.assume_init();
130                        //let n_items = n_items.assume_init();
131                        let bytes_to_read = bytes_to_read.assume_init();
132                        //let mut ret = ret.assume_init();
133                        let mut bytes_after = mem::MaybeUninit::uninit();
134                        x11_sys::XGetWindowProperty(
135                            self.display,
136                            selection.requestor,
137                            selection.property,
138                            0,
139                            bytes_to_read as c_long,
140                            0,
141                            x11_sys::AnyPropertyType as c_ulong,
142                            actual_type.as_mut_ptr(),
143                            actual_format.as_mut_ptr(),
144                            n_items.as_mut_ptr(),
145                            bytes_after.as_mut_ptr(),
146                            ret.as_mut_ptr()
147                        );
148                        let ret = ret.assume_init();
149                        //let bytes_after = bytes_after.assume_init();
150                        if ret != ptr::null_mut() && bytes_to_read > 0 {
151                            let utf8_slice = std::slice::from_raw_parts::<u8>(ret as *const _ as *const u8, bytes_to_read as usize);
152                            if let Ok(utf8_string) = String::from_utf8(utf8_slice.to_vec()) {
153                                self.do_callback(XlibEvent::TextInput(TextInputEvent {
154                                    input: utf8_string,
155                                    was_paste: true,
156                                    replace_last: false
157                                }));
158                            }
159                            x11_sys::XFree(ret as *mut _ as *mut c_void);
160                        }
161                    }
162                },
163                x11_sys::SelectionRequest => {
164                    let request = event.xselectionrequest;
165                    let mut response = x11_sys::XSelectionEvent {
166                        type_: x11_sys::SelectionNotify as i32,
167                        serial: 0,
168                        send_event: 0,
169                        display: self.display,
170                        requestor: request.requestor,
171                        selection: request.selection,
172                        target: request.target,
173                        time: request.time,
174                        property: request.property,
175                    };
176                    if request.target == self.atoms.targets {
177                        let mut targets = [self.atoms.utf8_string];
178                        x11_sys::XChangeProperty(
179                            self.display,
180                            request.requestor,
181                            request.property,
182                            4,
183                            32,
184                            x11_sys::PropModeReplace as i32,
185                            targets.as_mut() as *mut _ as *mut c_uchar,
186                            targets.len() as i32
187                        );
188                    }
189                    else if request.target == self.atoms.utf8_string {
190                        x11_sys::XChangeProperty(
191                            self.display,
192                            request.requestor,
193                            request.property,
194                            self.atoms.utf8_string,
195                            8,
196                            x11_sys::PropModeReplace as i32,
197                            self.clipboard.as_ptr() as *const _ as *const c_uchar,
198                            self.clipboard.len() as i32
199                        );
200                    }
201                    else {
202                        response.property = 0;
203                    }
204                    x11_sys::XSendEvent(self.display, request.requestor, 1, 0, &mut response as *mut _ as *mut x11_sys::XEvent);
205                },
206                x11_sys::DestroyNotify => { // our window got destroyed
207                    let destroy_window = event.xdestroywindow;
208                    if let Some(window_ptr) = self.window_map.get(&destroy_window.window) {
209                        let window = &mut (**window_ptr);
210                        window.do_callback(XlibEvent::WindowClosed(WindowClosedEvent {
211                            window_id: window.window_id,
212                        }));
213                    }
214                },
215                x11_sys::ConfigureNotify => {
216                    let cfg = event.xconfigure;
217                    if let Some(window_ptr) = self.window_map.get(&cfg.window) {
218                        let window = &mut (**window_ptr);
219                        if cfg.window == window.window.unwrap() {
220                            window.send_change_event();
221                        }
222                    }
223                },
224                x11_sys::EnterNotify => {},
225                x11_sys::LeaveNotify => {
226                    let crossing = event.xcrossing;
227                    if crossing.detail == 4 {
228                        if let Some(_window_ptr) = self.window_map.get(&crossing.window) {
229                            //TODO figure this out
230                            /*
231                            let window = &mut (**window_ptr);
232                            window.do_callback(Event::FingerHover(FingerHoverEvent {
233                                digit: 0,
234                                window_id: window.window_id,
235                                any_down: false,
236                                abs: window.last_mouse_pos,
237                                rel: window.last_mouse_pos,
238                                rect: Rect::default(),
239                                handled: false,
240                                hover_state: HoverState::Out,
241                                modifiers: KeyModifiers::default(),
242                                time: window.time_now()
243                            }));
244                            */
245                        }
246                    }
247                },
248                x11_sys::MotionNotify => { // mousemove
249                    let motion = event.xmotion;
250                    if let Some(window_ptr) = self.window_map.get(&motion.window) {
251                        let window = &mut (**window_ptr);
252                        let x = motion.x;
253                        let y = motion.y;
254                        if window.window.is_none() {
255                            return; // shutdown
256                        }
257                        if motion.window != window.window.unwrap() {
258                            // find the right child
259                            /*
260                            for child in &window.child_windows {
261                                if child.window == motion.window {
262                                    x += child.x;
263                                    y += child.y;
264                                    break
265                                }
266                            }*/
267                        }
268                        
269                        let pos = DVec2 {x: x as f64 / window.last_window_geom.dpi_factor, y: y as f64 / window.last_window_geom.dpi_factor};
270                        
271                        // query window for chrome
272                        let response = Rc::new(Cell::new(WindowDragQueryResponse::NoAnswer));
273                        window.do_callback(XlibEvent::WindowDragQuery(WindowDragQueryEvent {
274                            window_id: window.window_id,
275                            abs: window.last_mouse_pos,
276                            response: response.clone()
277                        }));
278                        // otherwise lets check if we are hover the window edge to resize the window
279                        //println!("{} {}", window.last_window_geom.inner_size.x, pos.x);
280                        window.send_mouse_move(pos, KeyModifiers::default());
281                        let window_size = window.last_window_geom.inner_size;
282                        if pos.x >= 0.0 && pos.x < 10.0 && pos.y >= 0.0 && pos.y < 10.0 {
283                            window.last_nc_mode = Some(_NET_WM_MOVERESIZE_SIZE_TOPLEFT);
284                            self.set_internal_mouse_cursor(MouseCursor::NwResize);
285                        }
286                        else if pos.x >= 0.0 && pos.x < 10.0 && pos.y >= window_size.y - 10.0 {
287                            window.last_nc_mode = Some(_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT);
288                            self.set_internal_mouse_cursor(MouseCursor::SwResize);
289                        }
290                        else if pos.x >= 0.0 && pos.x < 5.0 {
291                            window.last_nc_mode = Some(_NET_WM_MOVERESIZE_SIZE_LEFT);
292                            self.set_internal_mouse_cursor(MouseCursor::WResize);
293                        }
294                        else if pos.x >= window_size.x - 10.0 && pos.y >= 0.0 && pos.y < 10.0 {
295                            window.last_nc_mode = Some(_NET_WM_MOVERESIZE_SIZE_TOPRIGHT);
296                            self.set_internal_mouse_cursor(MouseCursor::NeResize);
297                        }
298                        else if pos.x >= window_size.x - 10.0 && pos.y >= window_size.y - 10.0 {
299                            window.last_nc_mode = Some(_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT);
300                            self.set_internal_mouse_cursor(MouseCursor::SeResize);
301                        }
302                        else if pos.x >= window_size.x - 5.0 {
303                            window.last_nc_mode = Some(_NET_WM_MOVERESIZE_SIZE_RIGHT);
304                            self.set_internal_mouse_cursor(MouseCursor::EResize);
305                        }
306                        else if pos.y <= 5.0 {
307                            window.last_nc_mode = Some(_NET_WM_MOVERESIZE_SIZE_TOP);
308                            self.set_internal_mouse_cursor(MouseCursor::NResize);
309                        }
310                        else if pos.y > window_size.y - 5.0 {
311                            window.last_nc_mode = Some(_NET_WM_MOVERESIZE_SIZE_BOTTOM);
312                            self.set_internal_mouse_cursor(MouseCursor::SResize);
313                        }
314                        else {
315                            match response.get() {
316                                WindowDragQueryResponse::Caption => {
317                                    window.last_nc_mode = Some(_NET_WM_MOVERESIZE_MOVE);
318                                },
319                                _ => {
320                                    window.last_nc_mode = None;
321                                }
322                            }
323                            self.restore_mouse_cursor(self.current_cursor);
324                        }
325                    }
326                },
327                x11_sys::ButtonPress => { // mouse down
328                    let button = event.xbutton;
329                    let time_now = self.time_now();
330                    if let Some(window_ptr) = self.window_map.get(&button.window) {
331                        let window = &mut (**window_ptr);
332                        x11_sys::XSetInputFocus(
333                            self.display,
334                            window.window.unwrap(),
335                            x11_sys::None as i32,
336                            x11_sys::CurrentTime as c_ulong
337                        );
338                        
339                        if button.button >= 4 && button.button <= 7 {
340                            let last_scroll_time = self.last_scroll_time;
341                            self.last_scroll_time = time_now;
342                            // completely arbitrary scroll acceleration curve.
343                            let speed = 1200.0 * (0.2 - 2. * (self.last_scroll_time - last_scroll_time)).max(0.01);
344                            
345                            self.do_callback(XlibEvent::Scroll(ScrollEvent {
346                                window_id: window.window_id,
347                                scroll: DVec2 {
348                                    x: if button.button == 6 {-speed} else if button.button == 7 {speed} else {0.},
349                                    y: if button.button == 4 {-speed} else if button.button == 5 {speed} else {0.}
350                                },
351                                abs: window.last_mouse_pos,
352                                modifiers: self.xkeystate_to_modifiers(button.state),
353                                is_mouse: true,
354                                handled_x: Cell::new(false),
355                                handled_y: Cell::new(false),
356                                time: self.last_scroll_time
357                            }))
358                            
359                        }
360                        else {
361                            // do all the 'nonclient' area messaging to the window manager
362                            if let Some(last_nc_mode) = window.last_nc_mode {
363                                if (time_now - self.last_click_time) < 0.35
364                                    && (button.x_root - self.last_click_pos.0).abs() < 5
365                                    && (button.y_root - self.last_click_pos.1).abs() < 5
366                                    && last_nc_mode == _NET_WM_MOVERESIZE_MOVE {
367                                    if window.get_is_maximized() {
368                                        window.restore();
369                                    }
370                                    else {
371                                        window.maximize();
372                                    }
373                                }
374                                else {
375                                    
376                                    let default_screen = x11_sys::XDefaultScreen(self.display);
377                                    let root_window = x11_sys::XRootWindow(self.display, default_screen);
378                                    x11_sys::XUngrabPointer(self.display, 0);
379                                    x11_sys::XFlush(self.display);
380                                    let mut xclient = x11_sys::XClientMessageEvent {
381                                        type_: x11_sys::ClientMessage as i32,
382                                        serial: 0,
383                                        send_event: 0,
384                                        display: self.display,
385                                        window: window.window.unwrap(),
386                                        message_type: self.atoms.net_wm_moveresize,
387                                        format: 32,
388                                        data: {
389                                            let mut msg = mem::zeroed::<x11_sys::XClientMessageEvent__bindgen_ty_1>();
390                                            msg.l[0] = button.x_root as c_long;
391                                            msg.l[1] = button.y_root as c_long;
392                                            msg.l[2] = last_nc_mode;
393                                            msg
394                                        }
395                                    };
396                                    x11_sys::XSendEvent(
397                                        self.display,
398                                        root_window,
399                                        0,
400                                        (x11_sys::SubstructureRedirectMask | x11_sys::SubstructureNotifyMask) as c_long,
401                                        &mut xclient as *mut _ as *mut x11_sys::XEvent
402                                    );
403                                }
404                            }
405                            else {
406                                window.send_mouse_down(
407                                    self.xbutton_to_mouse_button(button.button),
408                                    self.xkeystate_to_modifiers(button.state)
409                                );
410                            }
411                        }
412                    }
413                    self.last_click_time = time_now;
414                    self.last_click_pos = (button.x_root, button.y_root);
415                },
416                x11_sys::ButtonRelease => { // mouse up
417                    let button = event.xbutton;
418                    if let Some(window_ptr) = self.window_map.get(&button.window) {
419                        let window = &mut (**window_ptr);
420                        window.send_mouse_up(
421                            self.xbutton_to_mouse_button(button.button),
422                            self.xkeystate_to_modifiers(button.state),
423                        );
424                    }
425                },
426                x11_sys::KeyPress => {
427                    if let Some(window_ptr) = self.window_map.get(&event.xkey.window) {
428                        let window = &mut (**window_ptr);
429                        let block_text = if event.xkey.keycode != 0 {
430                            let key_code = self.xkeyevent_to_keycode(&mut event.xkey);
431                            let modifiers = self.xkeystate_to_modifiers(event.xkey.state);
432                            
433                            if modifiers.control || modifiers.logo {
434                                match key_code {
435                                    KeyCode::KeyV => { // paste
436                                        // request the pasteable text from the other side
437                                        x11_sys::XConvertSelection(
438                                            self.display,
439                                            self.atoms.clipboard,
440                                            self.atoms.utf8_string,
441                                            self.atoms.clipboard,
442                                            window.window.unwrap(),
443                                            event.xkey.time
444                                        );
445                                        /*
446                                        self.do_callback(&mut vec![
447                                            Event::TextInput(TextInputEvent {
448                                                input: String::new(),
449                                                was_paste: true,
450                                                replace_last: false
451                                            })
452                                        ]);
453                                        */
454                                    }
455                                    KeyCode::KeyC => {
456                                        let response = Rc::new(RefCell::new(None));
457                                        self.do_callback(XlibEvent::TextCopy(TextClipboardEvent {
458                                            response: response.clone()
459                                        }));
460                                        let response = response.borrow();
461                                        if let Some(response) = response.as_ref() {
462                                            self.copy_to_clipboard(response, window.window.unwrap(), event.xkey.time);
463                                        }
464                                    }
465                                    KeyCode::KeyX => {
466                                        let response = Rc::new(RefCell::new(None));
467                                        self.do_callback(XlibEvent::TextCut(TextClipboardEvent {
468                                            response: response.clone()
469                                        }));
470                                        let response = response.borrow();
471                                        if let Some(response) = response.as_ref() {
472                                            self.copy_to_clipboard(response, window.window.unwrap(), event.xkey.time);
473                                        }
474                                    }
475                                    _ => ()
476                                }
477                            }
478                            
479                            let block_text = modifiers.control || modifiers.logo || modifiers.alt;
480                            self.do_callback(XlibEvent::KeyDown(KeyEvent {
481                                key_code: key_code,
482                                is_repeat: self.next_keypress_is_repeat,
483                                modifiers: modifiers,
484                                time: self.time_now()
485                            }));
486                            self.next_keypress_is_repeat = false;
487                            block_text
488                        }else {false};
489                        
490                        if !block_text {
491                            // decode the character
492                            let mut buffer = [0u8; 32];
493                            let mut keysym = mem::MaybeUninit::uninit();
494                            let mut status = mem::MaybeUninit::uninit();
495                            let count = x11_sys::Xutf8LookupString(
496                                window.xic.unwrap(),
497                                &mut event.xkey,
498                                buffer.as_mut_ptr() as *mut c_char,
499                                buffer.len() as c_int,
500                                keysym.as_mut_ptr(),
501                                status.as_mut_ptr(),
502                            );
503                            //let keysym = keysym.assume_init();
504                            let status = status.assume_init();
505                            if status != x11_sys::XBufferOverflow {
506                                let utf8 = std::str::from_utf8(&buffer[..count as usize]).unwrap_or("").to_string();
507                                let char_code = utf8.chars().next().unwrap_or('\0');
508                                if char_code >= ' ' && char_code != 127 as char {
509                                    self.do_callback(XlibEvent::TextInput(TextInputEvent {
510                                        input: utf8,
511                                        was_paste: false,
512                                        replace_last: false
513                                    }));
514                                }
515                            }
516                        }
517                    }
518                },
519                x11_sys::KeyRelease => {
520                    // if the next event is a keypress, this comes from a repeat
521                    // Therefore, forget both this event and the next
522                    if x11_sys::XEventsQueued(self.display, x11_sys::QueuedAfterReading) > 0 {
523                        let mut nev = mem::MaybeUninit::uninit();
524                        x11_sys::XPeekEvent(self.display, nev.as_mut_ptr());
525                        let nev = nev.assume_init();
526                        if nev.type_ as u32 == x11_sys::KeyPress
527                            && nev.xkey.time == event.xkey.time
528                            && nev.xkey.keycode == event.xkey.keycode {
529                            self.next_keypress_is_repeat = true;
530                        }
531                    }
532                    if !self.next_keypress_is_repeat {
533                        self.do_callback(XlibEvent::KeyUp(KeyEvent {
534                            key_code: self.xkeyevent_to_keycode(&mut event.xkey),
535                            is_repeat: false,
536                            modifiers: self.xkeystate_to_modifiers(event.xkey.state),
537                            time: self.time_now()
538                        }));
539                    }
540                },
541                x11_sys::ClientMessage => {
542                    let event = event.xclient;
543                    if event.message_type == self.atoms.wm_protocols {
544                        if let Some(window_ptr) = self.window_map.get(&event.window) {
545                            let window = &mut (**window_ptr);
546                            window.close_window();
547                        }
548                    }
549                    if event.message_type == self.dnd.atoms.enter {
550                        self.dnd.handle_enter_event(&event);
551                    } else if event.message_type == self.dnd.atoms.drop {
552                        self.dnd.handle_drop_event(&event);
553                    } else if event.message_type == self.dnd.atoms.leave {
554                        self.dnd.handle_leave_event(&event);
555                    } else if event.message_type == self.dnd.atoms.position {
556                        self.dnd.handle_position_event(&event);
557                    }
558                },
559                x11_sys::Expose => {
560                    /* 
561                    (glx.glXMakeCurrent)(display, window, context);
562                    gl::ClearColor(1.0, 0.0, 0.0, 1.0);
563                    gl::Clear(gl::COLOR_BUFFER_BIT);
564                    (glx.glXSwapBuffers)(display, window);
565                    */
566                },
567                x11_sys::VisibilityNotify => {
568                    let event = event.xvisibility;
569                    if event.state != x11_sys::VisibilityFullyObscured {
570                        if let Some(window_ptr) = self.window_map.get(&event.window) {
571                            let window = &mut (**window_ptr);
572                            window.send_focus_event();
573                        }
574                    }
575                }
576
577                _ => {}
578            }
579        }
580        self.do_callback(XlibEvent::Paint);
581    }
582    
583    pub fn event_loop(&mut self) {
584        unsafe {
585            
586            self.do_callback(XlibEvent::Paint);
587            
588            let mut timer_ids = Vec::new();
589            while self.event_loop_running {
590                match self.event_flow {
591                    EventFlow::Exit => {
592                        break;
593                    }
594                    EventFlow::Wait => {
595                        let time = self.time_now();
596                        self.timers.update_timers(&mut timer_ids);
597                        for timer_id in &timer_ids{
598                            self.do_callback(
599                                XlibEvent::Timer(TimerEvent {
600                                    timer_id:*timer_id,
601                                    time: Some(time)
602                                })
603                            );
604                        }
605                        self.timers.select(self.display_fd);
606                        self.event_flow = EventFlow::Poll;
607                    }
608                    EventFlow::Poll => { 
609                        let time = self.time_now();
610                        self.timers.update_timers(&mut timer_ids);
611                        for timer_id in &timer_ids{
612                            self.do_callback(
613                                XlibEvent::Timer(TimerEvent {
614                                    timer_id:*timer_id,
615                                    time: Some(time)
616                                })
617                            );
618                        }
619                        self.event_loop_poll();
620                    }
621                }
622            }
623        }
624    }
625    
626    pub fn do_callback(&mut self, event: XlibEvent) {
627        if let Some(mut callback) = self.event_callback.take() {
628            self.event_flow = callback(self, event);
629            if let EventFlow::Exit = self.event_flow {
630                self.terminate_event_loop();
631            }
632            self.event_callback = Some(callback);
633        }
634    }
635    
636    pub fn terminate_event_loop(&mut self) {
637        self.event_loop_running = false;
638        if !self.xim.is_null() {
639            unsafe {x11_sys::XCloseIM(self.xim)};
640            self.xim = ptr::null_mut();
641        }
642        if !self.display.is_null() {
643            unsafe {x11_sys::XCloseDisplay(self.display)};
644            self.display = ptr::null_mut();
645        }
646    }
647    
648    pub fn start_timer(&mut self, id: u64, timeout: f64, repeats: bool) {
649        self.timers.start_timer(id, timeout, repeats);
650    }
651    
652    pub fn stop_timer(&mut self, id: u64) {
653        self.timers.stop_timer(id);
654    }
655    
656    pub fn time_now(&self) -> f64 {
657        self.timers.time_now()
658    }
659    
660    pub fn load_first_cursor(&self, names: &[&[u8]]) -> Option<c_ulong> {
661        unsafe {
662            for name in names {
663                let cursor = x11_sys::XcursorLibraryLoadCursor(
664                    self.display,
665                    name.as_ptr() as *const c_char,
666                );
667                if cursor != 0 {
668                    return Some(cursor)
669                }
670            }
671        }
672        return None
673    }
674
675    pub fn set_internal_mouse_cursor(&mut self, cursor: MouseCursor) {
676        if self.internal_cursor != cursor {
677            self.internal_cursor = cursor.clone();
678            self.set_mouse_cursor_(cursor);
679        }
680    }
681
682    pub fn restore_mouse_cursor(&mut self, cursor: MouseCursor) {
683        self.set_mouse_cursor_(cursor);
684    }
685
686    pub fn set_mouse_cursor(&mut self, cursor: MouseCursor) {
687        if self.current_cursor != cursor {
688            self.current_cursor = cursor.clone();
689            self.set_mouse_cursor_(cursor);
690        }
691    }
692
693    fn set_mouse_cursor_(&mut self, cursor: MouseCursor) {
694        let x11_cursor = match cursor {
695            MouseCursor::Hidden => {
696                return;
697            },
698            MouseCursor::EResize => self.load_first_cursor(&[b"right_side\0"]),
699            MouseCursor::NResize => self.load_first_cursor(&[b"top_side\0"]),
700            MouseCursor::NeResize => self.load_first_cursor(&[b"top_right_corner\0"]),
701            MouseCursor::NwResize => self.load_first_cursor(&[b"top_left_corner\0"]),
702            MouseCursor::SResize => self.load_first_cursor(&[b"bottom_side\0"]),
703            MouseCursor::SeResize => self.load_first_cursor(&[b"bottom_right_corner\0"]),
704            MouseCursor::SwResize => self.load_first_cursor(&[b"bottom_left_corner\0"]),
705            MouseCursor::WResize => self.load_first_cursor(&[b"left_side\0"]),
706
707            MouseCursor::Default => self.load_first_cursor(&[b"left_ptr\0"]),
708            MouseCursor::Crosshair => self.load_first_cursor(&[b"crosshair\0"]),
709            MouseCursor::Hand => self.load_first_cursor(&[b"hand2\0", b"left_ptr\0"]),
710            MouseCursor::Arrow => self.load_first_cursor(&[b"left_ptr\0\0"]),
711            MouseCursor::Move => self.load_first_cursor(&[b"move\0"]),
712            MouseCursor::NotAllowed => self.load_first_cursor(&[b"crossed_circle\0"]),
713            MouseCursor::Text => self.load_first_cursor(&[b"text\0", b"xterm\0"]),
714            MouseCursor::Wait => self.load_first_cursor(&[b"watch\0"]),
715            MouseCursor::Help => self.load_first_cursor(&[b"question_arrow\0"]),
716            MouseCursor::NsResize => self.load_first_cursor(&[b"v_double_arrow\0"]),
717            MouseCursor::NeswResize => self.load_first_cursor(&[b"fd_double_arrow\0", b"size_fdiag\0"]),
718            MouseCursor::EwResize => self.load_first_cursor(&[b"h_double_arrow\0"]),
719            MouseCursor::NwseResize => self.load_first_cursor(&[b"bd_double_arrow\0", b"size_bdiag\0"]),
720            MouseCursor::ColResize => self.load_first_cursor(&[b"split_h\0", b"h_double_arrow\0"]),
721            MouseCursor::RowResize => self.load_first_cursor(&[b"split_v\0", b"v_double_arrow\0"]),
722            MouseCursor::Grab => self.load_first_cursor(&[b"grab\0"]),
723            MouseCursor::Grabbing => self.load_first_cursor(&[b"grabbing\0"]),
724        };
725        if let Some(x11_cursor) = x11_cursor {
726            unsafe {
727                for (k, v) in &self.window_map {
728                    if !(**v).window.is_none() {
729                        x11_sys::XDefineCursor(self.display, *k, x11_cursor);
730                    }
731                }
732                x11_sys::XFreeCursor(self.display, x11_cursor);
733            }
734        }
735    }
736
737    fn xbutton_to_mouse_button(&self, button: u32) -> MouseButton {
738        match button {
739            0 => MouseButton::empty(), 
740            1 => MouseButton::PRIMARY,
741            2 => MouseButton::MIDDLE,
742            3 => MouseButton::SECONDARY,
743            // Button values 4, 5, 6, 7 are scroll directions
744            4..=7 => MouseButton::empty(), 
745            8 => MouseButton::BACK,
746            9 => MouseButton::FORWARD,
747            10.. => MouseButton::from_raw_button(button as usize - 4),
748        }
749    }
750
751    fn xkeystate_to_modifiers(&self, state: c_uint) -> KeyModifiers {
752        KeyModifiers {
753            alt: state & x11_sys::Mod1Mask != 0,
754            shift: state & x11_sys::ShiftMask != 0,
755            control: state & x11_sys::ControlMask != 0,
756            logo: state & x11_sys::Mod4Mask != 0,
757        }
758    }
759    
760    fn xkeyevent_to_keycode(&self, key_event: &mut x11_sys::XKeyEvent) -> KeyCode {
761        let mut keysym = 0;
762        unsafe {
763            x11_sys::XLookupString(
764                key_event,
765                ptr::null_mut(),
766                0,
767                &mut keysym,
768                ptr::null_mut(),
769            );
770        }
771        match keysym as u32 {
772            x11_sys::XK_a => KeyCode::KeyA,
773            x11_sys::XK_A => KeyCode::KeyA,
774            x11_sys::XK_b => KeyCode::KeyB,
775            x11_sys::XK_B => KeyCode::KeyB,
776            x11_sys::XK_c => KeyCode::KeyC,
777            x11_sys::XK_C => KeyCode::KeyC,
778            x11_sys::XK_d => KeyCode::KeyD,
779            x11_sys::XK_D => KeyCode::KeyD,
780            x11_sys::XK_e => KeyCode::KeyE,
781            x11_sys::XK_E => KeyCode::KeyE,
782            x11_sys::XK_f => KeyCode::KeyF,
783            x11_sys::XK_F => KeyCode::KeyF,
784            x11_sys::XK_g => KeyCode::KeyG,
785            x11_sys::XK_G => KeyCode::KeyG,
786            x11_sys::XK_h => KeyCode::KeyH,
787            x11_sys::XK_H => KeyCode::KeyH,
788            x11_sys::XK_i => KeyCode::KeyI,
789            x11_sys::XK_I => KeyCode::KeyI,
790            x11_sys::XK_j => KeyCode::KeyJ,
791            x11_sys::XK_J => KeyCode::KeyJ,
792            x11_sys::XK_k => KeyCode::KeyK,
793            x11_sys::XK_K => KeyCode::KeyK,
794            x11_sys::XK_l => KeyCode::KeyL,
795            x11_sys::XK_L => KeyCode::KeyL,
796            x11_sys::XK_m => KeyCode::KeyM,
797            x11_sys::XK_M => KeyCode::KeyM,
798            x11_sys::XK_n => KeyCode::KeyN,
799            x11_sys::XK_N => KeyCode::KeyN,
800            x11_sys::XK_o => KeyCode::KeyO,
801            x11_sys::XK_O => KeyCode::KeyO,
802            x11_sys::XK_p => KeyCode::KeyP,
803            x11_sys::XK_P => KeyCode::KeyP,
804            x11_sys::XK_q => KeyCode::KeyQ,
805            x11_sys::XK_Q => KeyCode::KeyQ,
806            x11_sys::XK_r => KeyCode::KeyR,
807            x11_sys::XK_R => KeyCode::KeyR,
808            x11_sys::XK_s => KeyCode::KeyS,
809            x11_sys::XK_S => KeyCode::KeyS,
810            x11_sys::XK_t => KeyCode::KeyT,
811            x11_sys::XK_T => KeyCode::KeyT,
812            x11_sys::XK_u => KeyCode::KeyU,
813            x11_sys::XK_U => KeyCode::KeyU,
814            x11_sys::XK_v => KeyCode::KeyV,
815            x11_sys::XK_V => KeyCode::KeyV,
816            x11_sys::XK_w => KeyCode::KeyW,
817            x11_sys::XK_W => KeyCode::KeyW,
818            x11_sys::XK_x => KeyCode::KeyX,
819            x11_sys::XK_X => KeyCode::KeyX,
820            x11_sys::XK_y => KeyCode::KeyY,
821            x11_sys::XK_Y => KeyCode::KeyY,
822            x11_sys::XK_z => KeyCode::KeyZ,
823            x11_sys::XK_Z => KeyCode::KeyZ,
824            
825            x11_sys::XK_0 => KeyCode::Key0,
826            x11_sys::XK_1 => KeyCode::Key1,
827            x11_sys::XK_2 => KeyCode::Key2,
828            x11_sys::XK_3 => KeyCode::Key3,
829            x11_sys::XK_4 => KeyCode::Key4,
830            x11_sys::XK_5 => KeyCode::Key5,
831            x11_sys::XK_6 => KeyCode::Key6,
832            x11_sys::XK_7 => KeyCode::Key7,
833            x11_sys::XK_8 => KeyCode::Key8,
834            x11_sys::XK_9 => KeyCode::Key9,
835            
836            x11_sys::XK_Alt_L => KeyCode::Alt,
837            x11_sys::XK_Alt_R => KeyCode::Alt,
838            x11_sys::XK_Meta_L => KeyCode::Logo,
839            x11_sys::XK_Meta_R => KeyCode::Logo,
840            x11_sys::XK_Shift_L => KeyCode::Shift,
841            x11_sys::XK_Shift_R => KeyCode::Shift,
842            x11_sys::XK_Control_L => KeyCode::Control,
843            x11_sys::XK_Control_R => KeyCode::Control,
844            
845            x11_sys::XK_equal => KeyCode::Equals,
846            x11_sys::XK_minus => KeyCode::Minus,
847            x11_sys::XK_bracketright => KeyCode::RBracket,
848            x11_sys::XK_bracketleft => KeyCode::LBracket,
849            x11_sys::XK_Return => KeyCode::ReturnKey,
850            x11_sys::XK_grave => KeyCode::Backtick,
851            x11_sys::XK_semicolon => KeyCode::Semicolon,
852            x11_sys::XK_backslash => KeyCode::Backslash,
853            x11_sys::XK_comma => KeyCode::Comma,
854            x11_sys::XK_slash => KeyCode::Slash,
855            x11_sys::XK_period => KeyCode::Period,
856            x11_sys::XK_Tab => KeyCode::Tab,
857            x11_sys::XK_ISO_Left_Tab => KeyCode::Tab,
858            x11_sys::XK_space => KeyCode::Space,
859            x11_sys::XK_BackSpace => KeyCode::Backspace,
860            x11_sys::XK_Escape => KeyCode::Escape,
861            x11_sys::XK_Caps_Lock => KeyCode::Capslock,
862            x11_sys::XK_KP_Decimal => KeyCode::NumpadDecimal,
863            x11_sys::XK_KP_Multiply => KeyCode::NumpadMultiply,
864            x11_sys::XK_KP_Add => KeyCode::NumpadAdd,
865            x11_sys::XK_Num_Lock => KeyCode::Numlock,
866            x11_sys::XK_KP_Divide => KeyCode::NumpadDivide,
867            x11_sys::XK_KP_Enter => KeyCode::NumpadEnter,
868            x11_sys::XK_KP_Subtract => KeyCode::NumpadSubtract,
869            //keysim::XK_9 => KeyCode::NumpadEquals,
870            x11_sys::XK_KP_0 => KeyCode::Numpad0,
871            x11_sys::XK_KP_1 => KeyCode::Numpad1,
872            x11_sys::XK_KP_2 => KeyCode::Numpad2,
873            x11_sys::XK_KP_3 => KeyCode::Numpad3,
874            x11_sys::XK_KP_4 => KeyCode::Numpad4,
875            x11_sys::XK_KP_5 => KeyCode::Numpad5,
876            x11_sys::XK_KP_6 => KeyCode::Numpad6,
877            x11_sys::XK_KP_7 => KeyCode::Numpad7,
878            x11_sys::XK_KP_8 => KeyCode::Numpad8,
879            x11_sys::XK_KP_9 => KeyCode::Numpad9,
880            
881            x11_sys::XK_F1 => KeyCode::F1,
882            x11_sys::XK_F2 => KeyCode::F2,
883            x11_sys::XK_F3 => KeyCode::F3,
884            x11_sys::XK_F4 => KeyCode::F4,
885            x11_sys::XK_F5 => KeyCode::F5,
886            x11_sys::XK_F6 => KeyCode::F6,
887            x11_sys::XK_F7 => KeyCode::F7,
888            x11_sys::XK_F8 => KeyCode::F8,
889            x11_sys::XK_F9 => KeyCode::F9,
890            x11_sys::XK_F10 => KeyCode::F10,
891            x11_sys::XK_F11 => KeyCode::F11,
892            x11_sys::XK_F12 => KeyCode::F12,
893            
894            x11_sys::XK_Print => KeyCode::PrintScreen,
895            x11_sys::XK_Home => KeyCode::Home,
896            x11_sys::XK_Page_Up => KeyCode::PageUp,
897            x11_sys::XK_Delete => KeyCode::Delete,
898            x11_sys::XK_End => KeyCode::End,
899            x11_sys::XK_Page_Down => KeyCode::PageDown,
900            x11_sys::XK_Left => KeyCode::ArrowLeft,
901            x11_sys::XK_Right => KeyCode::ArrowRight,
902            x11_sys::XK_Down => KeyCode::ArrowDown,
903            x11_sys::XK_Up => KeyCode::ArrowUp,
904            _ => KeyCode::Unknown,
905        }
906    }
907
908    pub unsafe fn copy_to_clipboard(&mut self, text: &String, window_id: c_ulong, time: u64) {
909        // store the text on the clipboard
910        self.clipboard = text.clone();
911        // lets set the owner
912        x11_sys::XSetSelectionOwner(
913            self.display,
914            self.atoms.clipboard,
915            window_id,
916            time
917        );
918        x11_sys::XFlush(self.display);
919    }
920}
921
922pub struct XlibAtoms {
923    pub clipboard: x11_sys::Atom,
924    pub net_wm_moveresize: x11_sys::Atom,
925    pub wm_delete_window: x11_sys::Atom,
926    pub wm_protocols: x11_sys::Atom,
927    pub wm_class: x11_sys::Atom,
928    pub motif_wm_hints: x11_sys::Atom,
929    pub net_wm_state: x11_sys::Atom,
930    pub new_wm_state_maximized_horz: x11_sys::Atom,
931    pub new_wm_state_maximized_vert: x11_sys::Atom,
932    pub targets: x11_sys::Atom,
933    pub string: x11_sys::Atom,
934    pub utf8_string: x11_sys::Atom,
935    pub text: x11_sys::Atom,
936    pub multiple: x11_sys::Atom,
937    pub text_plain: x11_sys::Atom,
938    pub atom: x11_sys::Atom,
939}
940
941impl XlibAtoms {
942    fn new(display: *mut x11_sys::Display) -> Self {
943        unsafe {Self {
944            clipboard: x11_sys::XInternAtom(display, "CLIPBOARD\0".as_ptr() as *const _, 0),
945            net_wm_moveresize: x11_sys::XInternAtom(display, "_NET_WM_MOVERESIZE\0".as_ptr() as *const _, 0),
946            wm_delete_window: x11_sys::XInternAtom(display, "WM_DELETE_WINDOW\0".as_ptr() as *const _, 0),
947            wm_protocols: x11_sys::XInternAtom(display, "WM_PROTOCOLS\0".as_ptr() as *const _, 0),
948            wm_class: x11_sys::XInternAtom(display, "WM_CLASS\0".as_ptr() as *const _, 0),
949            motif_wm_hints: x11_sys::XInternAtom(display, "_MOTIF_WM_HINTS\0".as_ptr() as *const _, 0),
950            net_wm_state: x11_sys::XInternAtom(display, "_NET_WM_STATE\0".as_ptr() as *const _, 0),
951            new_wm_state_maximized_horz: x11_sys::XInternAtom(display, "_NET_WM_STATE_MAXIMIZED_HORZ\0".as_ptr() as *const _, 0),
952            new_wm_state_maximized_vert: x11_sys::XInternAtom(display, "_NET_WM_STATE_MAXIMIZED_VERT\0".as_ptr() as *const _, 0),
953            targets: x11_sys::XInternAtom(display, "TARGETS\0".as_ptr() as *const _, 0),
954            string: x11_sys::XInternAtom(display, "STRING\0".as_ptr() as *const _, 0),
955            utf8_string: x11_sys::XInternAtom(display, "UTF8_STRING\0".as_ptr() as *const _, 1),
956            atom: x11_sys::XInternAtom(display, "ATOM\0".as_ptr() as *const _, 0),
957            text: x11_sys::XInternAtom(display, "TEXT\0".as_ptr() as *const _, 0),
958            text_plain: x11_sys::XInternAtom(display, "text/plain\0".as_ptr() as *const _, 0),
959            multiple: x11_sys::XInternAtom(display, "MULTIPLE\0".as_ptr() as *const _, 0),
960        }}
961    }
962}
963