gio/subclass/
action_map.rs
1use 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 + 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 let instance = &*(action_map as *mut T::Instance);
83 let action_name = GString::from_glib_borrow(action_nameptr);
84 let imp = instance.imp();
85
86 let ret = imp.lookup_action(&action_name);
87 if let Some(action) = ret {
88 let instance = imp.obj();
89 let actionptr = action.to_glib_none().0;
90
91 let action_map_quark = {
92 static QUARK: OnceLock<Quark> = OnceLock::new();
93 *QUARK.get_or_init(|| Quark::from_str("gtk-rs-subclass-action-map-lookup-action"))
94 };
95
96 let mut map = instance
97 .steal_qdata::<HashMap<String, Action>>(action_map_quark)
98 .unwrap_or_default();
99 map.insert(action_name.to_string(), action);
100 instance.set_qdata(action_map_quark, map);
101
102 actionptr
103 } else {
104 std::ptr::null_mut()
105 }
106}
107
108unsafe extern "C" fn action_map_add_action<T: ActionMapImpl>(
109 action_map: *mut ffi::GActionMap,
110 actionptr: *mut ffi::GAction,
111) {
112 let instance = &*(action_map as *mut T::Instance);
113 let imp = instance.imp();
114 let action: Borrowed<Action> = from_glib_borrow(actionptr);
115
116 imp.add_action(&action);
117}
118
119unsafe extern "C" fn action_map_remove_action<T: ActionMapImpl>(
120 action_map: *mut ffi::GActionMap,
121 action_nameptr: *const libc::c_char,
122) {
123 let instance = &*(action_map as *mut T::Instance);
124 let imp = instance.imp();
125 let action_name = GString::from_glib_borrow(action_nameptr);
126
127 imp.remove_action(&action_name);
128}