1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// Take a look at the license at the top of the repository in the LICENSE file.

#[cfg(feature = "xlib")]
#[cfg_attr(docsrs, doc(cfg(feature = "xlib")))]
use std::{boxed::Box as Box_, mem::transmute};

#[cfg(feature = "xlib")]
#[cfg_attr(docsrs, doc(cfg(feature = "xlib")))]
use glib::signal::{connect_raw, SignalHandlerId};
use glib::{translate::*, IntoGStr};
#[cfg(all(feature = "v4_4", feature = "egl"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "v4_4", feature = "egl"))))]
use khronos_egl as egl;
#[cfg(feature = "xlib")]
#[cfg_attr(docsrs, doc(cfg(feature = "xlib")))]
use x11::xlib;
#[cfg(feature = "xlib")]
#[cfg_attr(docsrs, doc(cfg(feature = "xlib")))]
use x11::xlib::{Cursor as XCursor, Window as XWindow};

use crate::{prelude::*, X11Display};
#[cfg(not(feature = "xlib"))]
use crate::{XCursor, XWindow};

impl X11Display {
    /// Retrieves the EGL display connection object for the given GDK display.
    ///
    /// This function returns `NULL` if GDK is using GLX.
    ///
    /// # Returns
    ///
    /// the EGL display object
    #[cfg(all(feature = "v4_4", feature = "egl"))]
    #[cfg_attr(docsrs, doc(cfg(all(feature = "v4_4", feature = "egl"))))]
    #[doc(alias = "gdk_x11_display_get_egl_display")]
    #[doc(alias = "get_egl_display")]
    pub fn egl_display(&self) -> Option<egl::Display> {
        unsafe {
            let ptr = ffi::gdk_x11_display_get_egl_display(self.to_glib_none().0);
            if ptr.is_null() {
                None
            } else {
                Some(egl::Display::from_ptr(ptr))
            }
        }
    }

    /// Returns the X cursor belonging to a [`gdk::Cursor`][crate::gdk::Cursor], potentially
    /// creating the cursor.
    ///
    /// Be aware that the returned cursor may not be unique to @cursor.
    /// It may for example be shared with its fallback cursor. On old
    /// X servers that don't support the XCursor extension, all cursors
    /// may even fall back to a few default cursors.
    /// ## `cursor`
    /// a [`gdk::Cursor`][crate::gdk::Cursor]
    ///
    /// # Returns
    ///
    /// an Xlib Cursor.
    #[doc(alias = "gdk_x11_display_get_xcursor")]
    #[doc(alias = "get_xcursor")]
    pub fn xcursor(&self, cursor: &gdk::Cursor) -> XCursor {
        unsafe { ffi::gdk_x11_display_get_xcursor(self.to_glib_none().0, cursor.to_glib_none().0) }
    }

    /// Returns the root X window used by [`gdk::Display`][crate::gdk::Display].
    ///
    /// # Returns
    ///
    /// an X Window
    #[doc(alias = "gdk_x11_display_get_xrootwindow")]
    #[doc(alias = "get_xrootwindow")]
    pub fn xrootwindow(&self) -> XWindow {
        unsafe { ffi::gdk_x11_display_get_xrootwindow(self.to_glib_none().0) }
    }

    /// Returns the X display of a [`gdk::Display`][crate::gdk::Display].
    ///
    /// # Returns
    ///
    /// an X display
    #[cfg(feature = "xlib")]
    #[cfg_attr(docsrs, doc(cfg(feature = "xlib")))]
    #[doc(alias = "gdk_x11_display_get_xdisplay")]
    #[doc(alias = "get_xdisplay")]
    #[allow(clippy::missing_safety_doc)]
    pub unsafe fn xdisplay(&self) -> *mut xlib::Display {
        ffi::gdk_x11_display_get_xdisplay(self.to_glib_none().0) as *mut xlib::Display
    }

    /// Returns the X Screen used by [`gdk::Display`][crate::gdk::Display].
    ///
    /// # Returns
    ///
    /// an X Screen
    #[cfg(feature = "xlib")]
    #[cfg_attr(docsrs, doc(cfg(feature = "xlib")))]
    #[doc(alias = "gdk_x11_display_get_xscreen")]
    #[doc(alias = "get_xscreen")]
    #[allow(clippy::missing_safety_doc)]
    pub unsafe fn xscreen(&self) -> *mut xlib::Screen {
        ffi::gdk_x11_display_get_xscreen(self.to_glib_none().0) as *mut xlib::Screen
    }

    /// The ::xevent signal is a low level signal that is emitted
    /// whenever an XEvent has been received.
    ///
    /// When handlers to this signal return [`true`], no other handlers will be
    /// invoked. In particular, the default handler for this function is
    /// GDK's own event handling mechanism, so by returning [`true`] for an event
    /// that GDK expects to translate, you may break GDK and/or GTK+ in
    /// interesting ways. You have been warned.
    ///
    /// If you want this signal handler to queue a [`gdk::Event`][crate::gdk::Event], you can use
    /// gdk_display_put_event().
    ///
    /// If you are interested in X GenericEvents, bear in mind that
    /// XGetEventData() has been already called on the event, and
    /// XFreeEventData() will be called afterwards.
    /// ## `xevent`
    /// a pointer to the XEvent to process
    ///
    /// # Returns
    ///
    /// [`true`] to stop other handlers from being invoked for the event.
    ///   [`false`] to propagate the event further.
    #[cfg(feature = "xlib")]
    #[cfg_attr(docsrs, doc(cfg(feature = "xlib")))]
    #[doc(alias = "xevent")]
    #[allow(clippy::missing_safety_doc)]
    pub unsafe fn connect_xevent<F: Fn(&Self, *mut xlib::XEvent) -> glib::Propagation + 'static>(
        &self,
        f: F,
    ) -> SignalHandlerId {
        unsafe extern "C" fn xevent_trampoline<
            F: Fn(&X11Display, *mut xlib::XEvent) -> glib::Propagation + 'static,
        >(
            this: *mut ffi::GdkX11Display,
            xevent: glib::ffi::gpointer,
            f: glib::ffi::gpointer,
        ) -> glib::ffi::gboolean {
            let f: &F = &*(f as *const F);
            f(&from_glib_borrow(this), xevent as *mut xlib::XEvent).into_glib()
        }
        let f: Box_<F> = Box_::new(f);
        connect_raw(
            self.as_ptr() as *mut _,
            b"xevent\0".as_ptr() as *const _,
            Some(transmute::<_, unsafe extern "C" fn()>(
                xevent_trampoline::<F> as *const (),
            )),
            Box_::into_raw(f),
        )
    }

    /// Sets the program class.
    ///
    /// The X11 backend uses the program class to set the class name part
    /// of the `WM_CLASS` property on toplevel windows; see the ICCCM.
    /// ## `display`
    /// a [`gdk::Display`][crate::gdk::Display]
    /// ## `program_class`
    /// a string
    #[doc(alias = "gdk_x11_display_set_program_class")]
    pub fn set_program_class(&self, program_class: impl IntoGStr) {
        assert_initialized_main_thread!();
        unsafe {
            program_class.run_with_gstr(|program_class| {
                ffi::gdk_x11_display_set_program_class(
                    self.upcast_ref::<gdk::Display>().to_glib_none().0,
                    program_class.as_ptr(),
                );
            });
        }
    }
}