gio/subclass/
action_map.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{collections::HashMap, sync::OnceLock};
4
5use glib::{GString, Quark, prelude::*, subclass::prelude::*, translate::*};
6
7use crate::{Action, ActionMap, ffi};
8
9pub trait ActionMapImpl: ObjectImpl + ObjectSubclass<Type: IsA<ActionMap>> {
10    fn lookup_action(&self, action_name: &str) -> Option<Action>;
11    fn add_action(&self, action: &Action);
12    fn remove_action(&self, action_name: &str);
13}
14
15pub trait ActionMapImplExt: ActionMapImpl {
16    fn parent_lookup_action(&self, name: &str) -> Option<Action> {
17        unsafe {
18            let type_data = Self::type_data();
19            let parent_iface = type_data.as_ref().parent_interface::<ActionMap>()
20                as *const ffi::GActionMapInterface;
21
22            let func = (*parent_iface)
23                .lookup_action
24                .expect("no parent \"lookup_action\" implementation");
25            let ret = func(
26                self.obj().unsafe_cast_ref::<ActionMap>().to_glib_none().0,
27                name.to_glib_none().0,
28            );
29            from_glib_none(ret)
30        }
31    }
32
33    fn parent_add_action(&self, action: &Action) {
34        unsafe {
35            let type_data = Self::type_data();
36            let parent_iface = type_data.as_ref().parent_interface::<ActionMap>()
37                as *const ffi::GActionMapInterface;
38
39            let func = (*parent_iface)
40                .add_action
41                .expect("no parent \"add_action\" implementation");
42            func(
43                self.obj().unsafe_cast_ref::<ActionMap>().to_glib_none().0,
44                action.to_glib_none().0,
45            );
46        }
47    }
48
49    fn parent_remove_action(&self, action_name: &str) {
50        unsafe {
51            let type_data = Self::type_data();
52            let parent_iface = type_data.as_ref().parent_interface::<ActionMap>()
53                as *const ffi::GActionMapInterface;
54
55            let func = (*parent_iface)
56                .remove_action
57                .expect("no parent \"remove_action\" implementation");
58            func(
59                self.obj().unsafe_cast_ref::<ActionMap>().to_glib_none().0,
60                action_name.to_glib_none().0,
61            );
62        }
63    }
64}
65
66impl<T: ActionMapImpl> ActionMapImplExt for T {}
67
68unsafe impl<T: ActionMapImpl> IsImplementable<T> for ActionMap {
69    fn interface_init(iface: &mut glib::Interface<Self>) {
70        let iface = iface.as_mut();
71
72        iface.lookup_action = Some(action_map_lookup_action::<T>);
73        iface.add_action = Some(action_map_add_action::<T>);
74        iface.remove_action = Some(action_map_remove_action::<T>);
75    }
76}
77
78unsafe extern "C" fn action_map_lookup_action<T: ActionMapImpl>(
79    action_map: *mut ffi::GActionMap,
80    action_nameptr: *const libc::c_char,
81) -> *mut ffi::GAction {
82    unsafe {
83        let instance = &*(action_map as *mut T::Instance);
84        let action_name = GString::from_glib_borrow(action_nameptr);
85        let imp = instance.imp();
86
87        let ret = imp.lookup_action(&action_name);
88        if let Some(action) = ret {
89            let instance = imp.obj();
90            let actionptr = action.to_glib_none().0;
91
92            let action_map_quark = {
93                static QUARK: OnceLock<Quark> = OnceLock::new();
94                *QUARK.get_or_init(|| Quark::from_str("gtk-rs-subclass-action-map-lookup-action"))
95            };
96
97            let mut map = instance
98                .steal_qdata::<HashMap<String, Action>>(action_map_quark)
99                .unwrap_or_default();
100            map.insert(action_name.to_string(), action);
101            instance.set_qdata(action_map_quark, map);
102
103            actionptr
104        } else {
105            std::ptr::null_mut()
106        }
107    }
108}
109
110unsafe extern "C" fn action_map_add_action<T: ActionMapImpl>(
111    action_map: *mut ffi::GActionMap,
112    actionptr: *mut ffi::GAction,
113) {
114    unsafe {
115        let instance = &*(action_map as *mut T::Instance);
116        let imp = instance.imp();
117        let action: Borrowed<Action> = from_glib_borrow(actionptr);
118
119        imp.add_action(&action);
120    }
121}
122
123unsafe extern "C" fn action_map_remove_action<T: ActionMapImpl>(
124    action_map: *mut ffi::GActionMap,
125    action_nameptr: *const libc::c_char,
126) {
127    unsafe {
128        let instance = &*(action_map as *mut T::Instance);
129        let imp = instance.imp();
130        let action_name = GString::from_glib_borrow(action_nameptr);
131
132        imp.remove_action(&action_name);
133    }
134}