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