Skip to main content

gtk/subclass/
window.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::translate::*;
4
5use glib::subclass::prelude::*;
6
7use glib::object::Cast;
8
9use super::bin::BinImpl;
10
11use crate::Window;
12use crate::{Widget, ffi};
13
14pub trait WindowImpl: WindowImplExt + BinImpl {
15    /// If `focus` is not the current focus widget, and is focusable, sets
16    /// it as the focus widget for the window. If `focus` is [`None`], unsets
17    /// the focus widget for this window. To set the focus to a particular
18    /// widget in the toplevel, it is usually more convenient to use
19    /// [`WidgetExt::grab_focus()`][crate::prelude::WidgetExt::grab_focus()] instead of this function.
20    /// ## `focus`
21    /// widget to be the new focus widget, or [`None`] to unset
22    ///  any focus widget for the toplevel window.
23    fn set_focus(&self, focus: Option<&Widget>) {
24        self.parent_set_focus(focus)
25    }
26
27    /// Activates the current focused widget within the window.
28    fn activate_focus(&self) {
29        self.parent_activate_focus()
30    }
31
32    /// Activates the default widget for the window.
33    fn activate_default(&self) {
34        self.parent_activate_default()
35    }
36
37    /// Signal gets emitted when the set of accelerators or
38    ///  mnemonics that are associated with window changes.
39    fn keys_changed(&self) {
40        self.parent_keys_changed()
41    }
42
43    /// Class handler for the [`enable-debugging`][struct@crate::Window#enable-debugging]
44    ///  keybinding signal. Since: 3.14
45    fn enable_debugging(&self, toggle: bool) -> bool {
46        self.parent_enable_debugging(toggle)
47    }
48}
49
50mod sealed {
51    pub trait Sealed {}
52    impl<T: super::WindowImpl> Sealed for T {}
53}
54
55pub trait WindowImplExt: ObjectSubclass + sealed::Sealed {
56    fn parent_set_focus(&self, focus: Option<&Widget>) {
57        unsafe {
58            let data = Self::type_data();
59            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWindowClass;
60            if let Some(f) = (*parent_class).set_focus {
61                f(
62                    self.obj().unsafe_cast_ref::<Window>().to_glib_none().0,
63                    focus.to_glib_none().0,
64                )
65            }
66        }
67    }
68    fn parent_activate_focus(&self) {
69        unsafe {
70            let data = Self::type_data();
71            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWindowClass;
72            if let Some(f) = (*parent_class).activate_focus {
73                f(self.obj().unsafe_cast_ref::<Window>().to_glib_none().0)
74            }
75        }
76    }
77    fn parent_activate_default(&self) {
78        unsafe {
79            let data = Self::type_data();
80            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWindowClass;
81            if let Some(f) = (*parent_class).activate_default {
82                f(self.obj().unsafe_cast_ref::<Window>().to_glib_none().0)
83            }
84        }
85    }
86    fn parent_keys_changed(&self) {
87        unsafe {
88            let data = Self::type_data();
89            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWindowClass;
90            if let Some(f) = (*parent_class).keys_changed {
91                f(self.obj().unsafe_cast_ref::<Window>().to_glib_none().0)
92            }
93        }
94    }
95    fn parent_enable_debugging(&self, toggle: bool) -> bool {
96        unsafe {
97            let data = Self::type_data();
98            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWindowClass;
99            if let Some(f) = (*parent_class).enable_debugging {
100                from_glib(f(
101                    self.obj().unsafe_cast_ref::<Window>().to_glib_none().0,
102                    toggle.into_glib(),
103                ))
104            } else {
105                false
106            }
107        }
108    }
109}
110
111impl<T: WindowImpl> WindowImplExt for T {}
112
113unsafe impl<T: WindowImpl> IsSubclassable<T> for Window {
114    fn class_init(class: &mut ::glib::Class<Self>) {
115        Self::parent_class_init::<T>(class);
116
117        if !crate::rt::is_initialized() {
118            panic!("GTK has to be initialized first");
119        }
120
121        let klass = class.as_mut();
122        klass.set_focus = Some(window_set_focus::<T>);
123        klass.activate_focus = Some(window_activate_focus::<T>);
124        klass.activate_default = Some(window_activate_default::<T>);
125        klass.keys_changed = Some(window_keys_changed::<T>);
126        klass.enable_debugging = Some(window_enable_debugging::<T>);
127    }
128}
129
130unsafe extern "C" fn window_set_focus<T: WindowImpl>(
131    ptr: *mut ffi::GtkWindow,
132    widgetptr: *mut ffi::GtkWidget,
133) {
134    unsafe {
135        let instance = &*(ptr as *mut T::Instance);
136        let imp = instance.imp();
137        let widget: Borrowed<Option<Widget>> = from_glib_borrow(widgetptr);
138
139        imp.set_focus(widget.as_ref().as_ref())
140    }
141}
142
143unsafe extern "C" fn window_activate_focus<T: WindowImpl>(ptr: *mut ffi::GtkWindow) {
144    unsafe {
145        let instance = &*(ptr as *mut T::Instance);
146        let imp = instance.imp();
147
148        imp.activate_focus()
149    }
150}
151
152unsafe extern "C" fn window_activate_default<T: WindowImpl>(ptr: *mut ffi::GtkWindow) {
153    unsafe {
154        let instance = &*(ptr as *mut T::Instance);
155        let imp = instance.imp();
156
157        imp.activate_default()
158    }
159}
160
161unsafe extern "C" fn window_keys_changed<T: WindowImpl>(ptr: *mut ffi::GtkWindow) {
162    unsafe {
163        let instance = &*(ptr as *mut T::Instance);
164        let imp = instance.imp();
165
166        imp.keys_changed()
167    }
168}
169
170unsafe extern "C" fn window_enable_debugging<T: WindowImpl>(
171    ptr: *mut ffi::GtkWindow,
172    toggleptr: glib::ffi::gboolean,
173) -> glib::ffi::gboolean {
174    unsafe {
175        let instance = &*(ptr as *mut T::Instance);
176        let imp = instance.imp();
177        let toggle: bool = from_glib(toggleptr);
178
179        imp.enable_debugging(toggle).into_glib()
180    }
181}