libpanel/subclass/
workspace.rs1use crate::{prelude::*, Workspace};
2use adw::subclass::prelude::*;
3use glib::translate::*;
4use glib::GString;
5use glib::Variant;
6use std::collections::HashMap;
7use std::future::Future;
8
9#[derive(Debug, Default)]
10struct Internal {
11 actions: HashMap<String, glib::ffi::gpointer>,
12}
13unsafe impl Sync for Internal {}
14unsafe impl Send for Internal {}
15
16pub trait WorkspaceImpl: AdwApplicationWindowImpl {}
17
18unsafe impl<T: WorkspaceImpl> IsSubclassable<T> for Workspace {
19 fn class_init(class: &mut glib::Class<Self>) {
20 Self::parent_class_init::<T>(class);
21 unsafe {
22 let mut data = T::type_data();
23 let data = data.as_mut();
24 data.set_class_data(<T as ObjectSubclassType>::type_(), Internal::default());
26 }
27 }
28}
29
30pub unsafe trait WorkspaceClassSubclassExt: ClassStruct {
31 fn install_action_async<Fut, F>(
32 &mut self,
33 action_name: &str,
34 parameter_type: Option<&str>,
35 activate: F,
36 ) where
37 F: Fn(
38 <<Self as ClassStruct>::Type as ObjectSubclass>::Type,
39 String,
40 Option<Variant>,
41 ) -> Fut
42 + 'static
43 + Clone,
44 Fut: Future<Output = ()>,
45 {
46 self.install_action(
47 action_name,
48 parameter_type,
49 move |this, action_name, parameter_type| {
50 let ctx = glib::MainContext::default();
51 let action_name = action_name.to_owned();
52 let parameter_type = parameter_type.map(ToOwned::to_owned);
53 ctx.spawn_local(glib::clone!(
54 #[strong]
55 this,
56 #[strong]
57 action_name,
58 #[strong]
59 parameter_type,
60 #[strong]
61 activate,
62 async move {
63 activate(this, action_name, parameter_type).await;
64 }
65 ));
66 },
67 );
68 }
69
70 #[doc(alias = "panel_workspace_class_install_action")]
71 fn install_action<F>(&mut self, action_name: &str, parameter_type: Option<&str>, activate: F)
72 where
73 F: Fn(&<<Self as ClassStruct>::Type as ObjectSubclass>::Type, &str, Option<&Variant>)
74 + 'static,
75 {
76 unsafe {
77 let mut data = <Self::Type as ObjectSubclassType>::type_data();
80 let data = data.as_mut();
81
82 let f: Box<F> = Box::new(activate);
83
84 let internal = data
85 .class_data_mut::<Internal>(<Self::Type as ObjectSubclassType>::type_())
86 .expect("Something bad happened at class_init, the internal class_data is missing");
87 let callback_ptr = Box::into_raw(f) as glib::ffi::gpointer;
88 internal
89 .actions
90 .insert(action_name.to_string(), callback_ptr);
91
92 unsafe extern "C" fn activate_trampoline<F, S>(
93 this: *mut libc::c_void,
94 action_name: *const libc::c_char,
95 parameter: *mut glib::ffi::GVariant,
96 ) where
97 S: ClassStruct,
98 <S as ClassStruct>::Type: ObjectSubclass,
99 F: Fn(&<<S as ClassStruct>::Type as ObjectSubclass>::Type, &str, Option<&Variant>)
100 + 'static,
101 {
102 let action_name = GString::from_glib_borrow(action_name);
103
104 let data = <S::Type as ObjectSubclassType>::type_data();
105 let internal = data
106 .as_ref()
107 .class_data::<Internal>(<S::Type as ObjectSubclassType>::type_())
108 .unwrap();
109 let activate_callback =
110 *internal
111 .actions
112 .get(action_name.as_str())
113 .unwrap_or_else(|| {
114 panic!("Action name '{}' was not found", action_name.as_str());
115 });
116
117 let workspace = Workspace::from_glib_borrow(this as *mut ffi::PanelWorkspace);
118
119 let f: &F = &*(activate_callback as *const F);
120 f(
121 workspace.unsafe_cast_ref(),
122 &action_name,
123 Option::<Variant>::from_glib_borrow(parameter)
124 .as_ref()
125 .as_ref(),
126 )
127 }
128 let workspace_class = self as *mut _ as *mut ffi::PanelWorkspaceClass;
129 let callback = activate_trampoline::<F, Self>;
130 ffi::panel_workspace_class_install_action(
131 workspace_class,
132 action_name.to_glib_none().0,
133 parameter_type.to_glib_none().0,
134 Some(callback),
135 );
136 }
137 }
138
139 #[cfg(any(feature = "v1_4", docsrs))]
140 #[cfg_attr(docsrs, doc(cfg(feature = "v1_4")))]
141 #[doc(alias = "panel_workspace_class_install_property_action")]
142 fn install_property_action(&mut self, action_name: &str, property_name: &str) {
143 unsafe {
144 let workspace_class = self as *mut _ as *mut ffi::PanelWorkspaceClass;
145 ffi::panel_workspace_class_install_property_action(
146 workspace_class,
147 action_name.to_glib_none().0,
148 property_name.to_glib_none().0,
149 );
150 }
151 }
152}
153
154unsafe impl<T: ClassStruct> WorkspaceClassSubclassExt for T where T::Type: WorkspaceImpl {}