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