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