Skip to content

Commit c4de546

Browse files
committed
Allow implementing a GAction interface
1 parent 35e15b7 commit c4de546

File tree

5 files changed

+364
-0
lines changed

5 files changed

+364
-0
lines changed

examples/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,7 @@ path = "object_subclass/main.rs"
5151
[[bin]]
5252
name = "virtual_methods"
5353
path = "virtual_methods/main.rs"
54+
55+
[[bin]]
56+
name = "gio_action_impl"
57+
path = "gio_action_impl/main.rs"

examples/gio_action_impl/action.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use gio::{prelude::*, subclass::prelude::*};
2+
use glib;
3+
4+
mod imp {
5+
use super::*;
6+
use std::cell::OnceCell;
7+
8+
#[derive(glib::Properties, Default)]
9+
#[properties(wrapper_type = super::RenamedAction)]
10+
pub struct RenamedAction {
11+
#[property(get, construct_only)]
12+
pub name: OnceCell<glib::GString>,
13+
14+
#[property(get, construct_only)]
15+
pub action: OnceCell<gio::Action>,
16+
}
17+
18+
#[glib::object_subclass]
19+
impl ObjectSubclass for RenamedAction {
20+
const NAME: &str = "ExampleRenamedAction";
21+
type Type = super::RenamedAction;
22+
type Interfaces = (gio::Action,);
23+
}
24+
25+
#[glib::derived_properties]
26+
impl ObjectImpl for RenamedAction {}
27+
28+
impl ActionImpl for RenamedAction {
29+
fn name(&self) -> glib::GString {
30+
self.obj().name()
31+
}
32+
33+
fn parameter_type(&self) -> Option<&glib::VariantTy> {
34+
// self.obj().action().parameter_type()
35+
None
36+
}
37+
38+
fn state_type(&self) -> Option<&glib::VariantTy> {
39+
// self.obj().action().state_type()
40+
None
41+
}
42+
43+
fn state_hint(&self) -> Option<glib::Variant> {
44+
self.obj().action().state_hint()
45+
}
46+
47+
fn is_enabled(&self) -> bool {
48+
self.obj().action().is_enabled()
49+
}
50+
51+
fn state(&self) -> Option<glib::Variant> {
52+
self.obj().action().state()
53+
}
54+
55+
fn change_state(&self, value: glib::Variant) {
56+
self.obj().action().change_state(&value);
57+
}
58+
59+
fn activate(&self, parameter: Option<glib::Variant>) {
60+
self.obj().action().activate(parameter.as_ref());
61+
}
62+
}
63+
}
64+
65+
glib::wrapper! {
66+
pub struct RenamedAction(ObjectSubclass<imp::RenamedAction>)
67+
@implements gio::Action;
68+
}
69+
70+
impl RenamedAction {
71+
pub fn new(name: &str, action: &impl IsA<gio::Action>) -> Self {
72+
glib::Object::builder()
73+
.property("name", name)
74+
.property("action", action)
75+
.build()
76+
}
77+
}

examples/gio_action_impl/main.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
mod action;
2+
3+
use gio::prelude::*;
4+
5+
fn main() {
6+
let action = gio::SimpleAction::new("bark", None);
7+
action.connect_activate(|_, _| {
8+
println!("Woof!");
9+
});
10+
11+
let renamed_action = action::RenamedAction::new("meow", &action);
12+
13+
let group = gio::SimpleActionGroup::new();
14+
group.add_action(&action);
15+
group.add_action(&renamed_action);
16+
17+
group.activate_action("bark", None);
18+
group.activate_action("meow", None);
19+
}

gio/src/subclass/action.rs

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
// Take a look at the license at the top of the repository in the LICENSE file.
2+
3+
use glib::{
4+
ffi::{gboolean, GVariant, GVariantType},
5+
prelude::*,
6+
subclass::prelude::*,
7+
translate::*,
8+
GString, Variant, VariantTy,
9+
};
10+
11+
use crate::{ffi, Action};
12+
13+
pub trait ActionImpl: ObjectImpl + ObjectSubclass<Type: IsA<Action>> {
14+
fn name(&self) -> GString {
15+
self.parent_name()
16+
}
17+
18+
fn parameter_type(&self) -> Option<&VariantTy> {
19+
self.parent_parameter_type()
20+
}
21+
22+
fn state_type(&self) -> Option<&VariantTy> {
23+
self.parent_state_type()
24+
}
25+
26+
fn state_hint(&self) -> Option<Variant> {
27+
self.parent_state_hint()
28+
}
29+
30+
fn is_enabled(&self) -> bool {
31+
self.parent_enabled()
32+
}
33+
34+
fn state(&self) -> Option<Variant> {
35+
self.parent_state()
36+
}
37+
38+
fn change_state(&self, value: Variant) {
39+
self.parent_change_state(value);
40+
}
41+
42+
fn activate(&self, parameter: Option<Variant>) {
43+
self.parent_activate(parameter);
44+
}
45+
}
46+
47+
pub trait ActionImplExt: ActionImpl {
48+
fn parent_name(&self) -> GString {
49+
unsafe {
50+
let type_data = Self::type_data();
51+
let parent_iface =
52+
type_data.as_ref().parent_interface::<Action>() as *const ffi::GActionInterface;
53+
54+
let func = (*parent_iface)
55+
.get_name
56+
.expect("no parent \"get_name\" implementation");
57+
let ret = func(self.obj().unsafe_cast_ref::<Action>().to_glib_none().0);
58+
from_glib_none(ret)
59+
}
60+
}
61+
62+
fn parent_parameter_type(&self) -> Option<&VariantTy> {
63+
unsafe {
64+
let type_data = Self::type_data();
65+
let parent_iface =
66+
type_data.as_ref().parent_interface::<Action>() as *const ffi::GActionInterface;
67+
68+
let func = (*parent_iface)
69+
.get_parameter_type
70+
.expect("no parent \"get_parameter_type\" implementation");
71+
let ret = func(self.obj().unsafe_cast_ref::<Action>().to_glib_none().0);
72+
if ret.is_null() {
73+
None
74+
} else {
75+
Some(VariantTy::from_ptr(ret))
76+
}
77+
}
78+
}
79+
80+
fn parent_state_type(&self) -> Option<&VariantTy> {
81+
unsafe {
82+
let type_data = Self::type_data();
83+
let parent_iface =
84+
type_data.as_ref().parent_interface::<Action>() as *const ffi::GActionInterface;
85+
86+
let func = (*parent_iface)
87+
.get_state_type
88+
.expect("no parent \"get_state_type\" implementation");
89+
let ret = func(self.obj().unsafe_cast_ref::<Action>().to_glib_none().0);
90+
if ret.is_null() {
91+
None
92+
} else {
93+
Some(VariantTy::from_ptr(ret))
94+
}
95+
}
96+
}
97+
98+
fn parent_state_hint(&self) -> Option<Variant> {
99+
unsafe {
100+
let type_data = Self::type_data();
101+
let parent_iface =
102+
type_data.as_ref().parent_interface::<Action>() as *const ffi::GActionInterface;
103+
104+
let func = (*parent_iface)
105+
.get_state_hint
106+
.expect("no parent \"get_state_hint\" implementation");
107+
let ret = func(self.obj().unsafe_cast_ref::<Action>().to_glib_none().0);
108+
from_glib_none(ret)
109+
}
110+
}
111+
112+
fn parent_enabled(&self) -> bool {
113+
unsafe {
114+
let type_data = Self::type_data();
115+
let parent_iface =
116+
type_data.as_ref().parent_interface::<Action>() as *const ffi::GActionInterface;
117+
118+
let func = (*parent_iface)
119+
.get_enabled
120+
.expect("no parent \"get_enabled\" implementation");
121+
let ret = func(self.obj().unsafe_cast_ref::<Action>().to_glib_none().0);
122+
ret != 0
123+
}
124+
}
125+
126+
fn parent_state(&self) -> Option<Variant> {
127+
unsafe {
128+
let type_data = Self::type_data();
129+
let parent_iface =
130+
type_data.as_ref().parent_interface::<Action>() as *const ffi::GActionInterface;
131+
132+
let func = (*parent_iface)
133+
.get_state
134+
.expect("no parent \"get_state\" implementation");
135+
let ret = func(self.obj().unsafe_cast_ref::<Action>().to_glib_none().0);
136+
from_glib_none(ret)
137+
}
138+
}
139+
140+
fn parent_change_state(&self, value: Variant) {
141+
unsafe {
142+
let type_data = Self::type_data();
143+
let parent_iface =
144+
type_data.as_ref().parent_interface::<Action>() as *const ffi::GActionInterface;
145+
146+
let func = (*parent_iface)
147+
.change_state
148+
.expect("no parent \"change_state\" implementation");
149+
func(
150+
self.obj().unsafe_cast_ref::<Action>().to_glib_none().0,
151+
value.to_glib_none().0,
152+
);
153+
}
154+
}
155+
156+
fn parent_activate(&self, parameter: Option<Variant>) {
157+
unsafe {
158+
let type_data = Self::type_data();
159+
let parent_iface =
160+
type_data.as_ref().parent_interface::<Action>() as *const ffi::GActionInterface;
161+
162+
let func = (*parent_iface)
163+
.activate
164+
.expect("no parent \"activate\" implementation");
165+
func(
166+
self.obj().unsafe_cast_ref::<Action>().to_glib_none().0,
167+
parameter.to_glib_none().0,
168+
);
169+
}
170+
}
171+
}
172+
173+
impl<T: ActionImpl> ActionImplExt for T {}
174+
175+
unsafe impl<T: ActionImpl> IsImplementable<T> for Action {
176+
fn interface_init(iface: &mut glib::Interface<Self>) {
177+
let iface = iface.as_mut();
178+
179+
iface.get_name = Some(action_get_name::<T>);
180+
iface.get_parameter_type = Some(action_get_parameter_type::<T>);
181+
iface.get_state_type = Some(action_get_state_type::<T>);
182+
iface.get_state_hint = Some(action_get_state_hint::<T>);
183+
iface.get_enabled = Some(action_get_enabled::<T>);
184+
iface.get_state = Some(action_get_state::<T>);
185+
iface.change_state = Some(action_change_state::<T>);
186+
iface.activate = Some(action_activate::<T>);
187+
}
188+
}
189+
190+
unsafe extern "C" fn action_get_name<T: ActionImpl>(
191+
actionptr: *mut ffi::GAction,
192+
) -> *const libc::c_char {
193+
let instance = &*(actionptr as *mut T::Instance);
194+
let imp = instance.imp();
195+
196+
imp.name().to_glib_none().0
197+
}
198+
199+
unsafe extern "C" fn action_get_parameter_type<T: ActionImpl>(
200+
actionptr: *mut ffi::GAction,
201+
) -> *const GVariantType {
202+
let instance = &*(actionptr as *mut T::Instance);
203+
let imp = instance.imp();
204+
205+
imp.parameter_type().to_glib_none().0
206+
}
207+
208+
unsafe extern "C" fn action_get_state_type<T: ActionImpl>(
209+
actionptr: *mut ffi::GAction,
210+
) -> *const GVariantType {
211+
let instance = &*(actionptr as *mut T::Instance);
212+
let imp = instance.imp();
213+
214+
imp.state_type().to_glib_none().0
215+
}
216+
217+
unsafe extern "C" fn action_get_state_hint<T: ActionImpl>(
218+
actionptr: *mut ffi::GAction,
219+
) -> *mut GVariant {
220+
let instance = &*(actionptr as *mut T::Instance);
221+
let imp = instance.imp();
222+
223+
imp.state_hint().to_glib_full()
224+
}
225+
226+
unsafe extern "C" fn action_get_enabled<T: ActionImpl>(actionptr: *mut ffi::GAction) -> gboolean {
227+
let instance = &*(actionptr as *mut T::Instance);
228+
let imp = instance.imp();
229+
230+
imp.is_enabled() as gboolean
231+
}
232+
233+
unsafe extern "C" fn action_get_state<T: ActionImpl>(
234+
actionptr: *mut ffi::GAction,
235+
) -> *mut GVariant {
236+
let instance = &*(actionptr as *mut T::Instance);
237+
let imp = instance.imp();
238+
239+
imp.state().to_glib_full()
240+
}
241+
242+
unsafe extern "C" fn action_change_state<T: ActionImpl>(
243+
actionptr: *mut ffi::GAction,
244+
value: *mut GVariant,
245+
) {
246+
let instance = &*(actionptr as *mut T::Instance);
247+
let imp = instance.imp();
248+
let value: Variant = from_glib_none(value);
249+
250+
imp.change_state(value);
251+
}
252+
253+
unsafe extern "C" fn action_activate<T: ActionImpl>(
254+
actionptr: *mut ffi::GAction,
255+
parameterptr: *mut GVariant,
256+
) {
257+
let instance = &*(actionptr as *mut T::Instance);
258+
let imp = instance.imp();
259+
let parameter: Option<Variant> = from_glib_none(parameterptr);
260+
261+
imp.activate(parameter);
262+
}

gio/src/subclass/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Take a look at the license at the top of the repository in the LICENSE file.
22

3+
mod action;
34
mod action_group;
45
mod action_map;
56
mod application;
@@ -19,6 +20,7 @@ pub mod prelude {
1920
pub use glib::subclass::prelude::*;
2021

2122
pub use super::{
23+
action::{ActionImpl, ActionImplExt},
2224
action_group::{ActionGroupImpl, ActionGroupImplExt},
2325
action_map::{ActionMapImpl, ActionMapImplExt},
2426
application::{ApplicationImpl, ApplicationImplExt},

0 commit comments

Comments
 (0)