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
// Take a look at the license at the top of the repository in the LICENSE file.

use glib::translate::*;
#[cfg(all(feature = "v4_4", feature = "egl"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "v4_4", feature = "egl"))))]
use khronos_egl as egl;

use crate::{Win32Display, Win32MessageFilterReturn, MSG};

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

    /// Adds an event filter to @window, allowing you to intercept messages
    /// before they reach GDK. This is a low-level operation and makes it
    /// easy to break GDK and/or GTK, so you have to know what you're
    /// doing.
    /// ## `function`
    /// filter callback
    #[doc(alias = "gdk_win32_display_add_filter")]
    pub fn add_filter<F>(&self, filter_func: F) -> Win32DisplayFilterHandle
    where
        F: Fn(&Self, &mut MSG, &mut i32) -> Win32MessageFilterReturn + 'static,
    {
        unsafe extern "C" fn trampoline<
            F: Fn(&Win32Display, &mut MSG, &mut i32) -> Win32MessageFilterReturn + 'static,
        >(
            display: *mut ffi::GdkWin32Display,
            msg: glib::ffi::gpointer,
            return_value: *mut libc::c_int,
            box_: glib::ffi::gpointer,
        ) -> i32 {
            let f: &F = &*(box_ as *const F);
            f(
                &from_glib_borrow(display),
                &mut *(msg as *mut MSG),
                &mut *return_value,
            )
            .into_glib()
        }

        let box_ = Box::into_raw(Box::new(filter_func)) as *mut _;
        let func = unsafe {
            let func: ffi::GdkWin32MessageFilterFunc = Some(trampoline::<F>);
            ffi::gdk_win32_display_add_filter(self.to_glib_none().0, func, box_);
            func
        };

        let display = glib::WeakRef::new();
        display.set(Some(self));

        let drop_ = |b| unsafe {
            let _ = Box::<F>::from_raw(b as *mut _);
        };
        Win32DisplayFilterHandle {
            display,
            func,
            box_,
            drop_,
        }
    }
}

// rustdoc-stripper-ignore-next
/// An owned `Win32Display` filter.
///
/// A `Win32DisplayFilterHandle` removes itself from the `Win32Display` it is
/// attached to when it is dropped.
#[derive(Debug)]
pub struct Win32DisplayFilterHandle {
    display: glib::WeakRef<Win32Display>,
    func: ffi::GdkWin32MessageFilterFunc,
    box_: glib::ffi::gpointer,
    drop_: fn(*mut libc::c_void),
}

impl Drop for Win32DisplayFilterHandle {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            if let Some(display) = self.display.upgrade() {
                ffi::gdk_win32_display_remove_filter(
                    display.to_glib_none().0,
                    self.func,
                    self.box_,
                );
            }
            (self.drop_)(self.box_);
        }
    }
}