Skip to content

Commit

Permalink
Allow implementing a GAction interface
Browse files Browse the repository at this point in the history
  • Loading branch information
andy128k committed Jan 27, 2025
1 parent 35e15b7 commit 1c5636b
Show file tree
Hide file tree
Showing 2 changed files with 256 additions and 0 deletions.
254 changes: 254 additions & 0 deletions gio/src/subclass/action.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
// Take a look at the license at the top of the repository in the LICENSE file.

use glib::{
ffi::{gboolean, GVariant, GVariantType},
prelude::*,
subclass::prelude::*,
translate::*,
GString, Variant, VariantType,
};

use crate::{ffi, Action};

pub trait ActionImpl: ObjectImpl + ObjectSubclass<Type: IsA<Action>> {
fn name(&self) -> GString {
self.parent_name()
}

fn parameter_type(&self) -> Option<VariantType> {
self.parent_parameter_type()
}

fn state_type(&self) -> Option<VariantType> {
self.parent_state_type()
}

fn state_hint(&self) -> Option<Variant> {
self.parent_state_hint()
}

fn enabled(&self) -> bool {
self.parent_enabled()
}

fn state(&self) -> Option<Variant> {
self.parent_state()
}

fn change_state(&self, value: Variant) {
self.parent_change_state(value);
}

fn activate(&self, parameter: Option<Variant>) {
self.parent_activate(parameter);
}
}

pub trait ActionImplExt: ActionImpl {
fn parent_name(&self) -> GString {
unsafe {
let type_data = Self::type_data();
let parent_iface =
type_data.as_ref().parent_interface::<Action>() as *const ffi::GActionInterface;

let func = (*parent_iface)
.get_name
.expect("no parent \"get_name\" implementation");
let ret = func(self.obj().unsafe_cast_ref::<Action>().to_glib_none().0);
from_glib_none(ret)
}
}

fn parent_parameter_type(&self) -> Option<VariantType> {
unsafe {
let type_data = Self::type_data();
let parent_iface =
type_data.as_ref().parent_interface::<Action>() as *const ffi::GActionInterface;

let func = (*parent_iface)
.get_parameter_type
.expect("no parent \"get_parameter_type\" implementation");
let ret = func(self.obj().unsafe_cast_ref::<Action>().to_glib_none().0);
from_glib_none(ret)
}
}

fn parent_state_type(&self) -> Option<VariantType> {
unsafe {
let type_data = Self::type_data();
let parent_iface =
type_data.as_ref().parent_interface::<Action>() as *const ffi::GActionInterface;

let func = (*parent_iface)
.get_state_type
.expect("no parent \"get_state_type\" implementation");
let ret = func(self.obj().unsafe_cast_ref::<Action>().to_glib_none().0);
from_glib_none(ret)
}
}

fn parent_state_hint(&self) -> Option<Variant> {
unsafe {
let type_data = Self::type_data();
let parent_iface =
type_data.as_ref().parent_interface::<Action>() as *const ffi::GActionInterface;

let func = (*parent_iface)
.get_state_hint
.expect("no parent \"get_state_hint\" implementation");
let ret = func(self.obj().unsafe_cast_ref::<Action>().to_glib_none().0);
from_glib_none(ret)
}
}

fn parent_enabled(&self) -> bool {
unsafe {
let type_data = Self::type_data();
let parent_iface =
type_data.as_ref().parent_interface::<Action>() as *const ffi::GActionInterface;

let func = (*parent_iface)
.get_enabled
.expect("no parent \"get_enabled\" implementation");
let ret = func(self.obj().unsafe_cast_ref::<Action>().to_glib_none().0);
ret != 0
}
}

fn parent_state(&self) -> Option<Variant> {
unsafe {
let type_data = Self::type_data();
let parent_iface =
type_data.as_ref().parent_interface::<Action>() as *const ffi::GActionInterface;

let func = (*parent_iface)
.get_state
.expect("no parent \"get_state\" implementation");
let ret = func(self.obj().unsafe_cast_ref::<Action>().to_glib_none().0);
from_glib_none(ret)
}
}

fn parent_change_state(&self, value: Variant) {
unsafe {
let type_data = Self::type_data();
let parent_iface =
type_data.as_ref().parent_interface::<Action>() as *const ffi::GActionInterface;

let func = (*parent_iface)
.change_state
.expect("no parent \"change_state\" implementation");
func(
self.obj().unsafe_cast_ref::<Action>().to_glib_none().0,
value.to_glib_none().0,
);
}
}

fn parent_activate(&self, parameter: Option<Variant>) {
unsafe {
let type_data = Self::type_data();
let parent_iface =
type_data.as_ref().parent_interface::<Action>() as *const ffi::GActionInterface;

let func = (*parent_iface)
.activate
.expect("no parent \"activate\" implementation");
func(
self.obj().unsafe_cast_ref::<Action>().to_glib_none().0,
parameter.to_glib_none().0,
);
}
}
}

impl<T: ActionImpl> ActionImplExt for T {}

unsafe impl<T: ActionImpl> IsImplementable<T> for Action {
fn interface_init(iface: &mut glib::Interface<Self>) {
let iface = iface.as_mut();

iface.get_name = Some(action_get_name::<T>);
iface.get_parameter_type = Some(action_get_parameter_type::<T>);
iface.get_state_type = Some(action_get_state_type::<T>);
iface.get_state_hint = Some(action_get_state_hint::<T>);
iface.get_enabled = Some(action_get_enabled::<T>);
iface.get_state = Some(action_get_state::<T>);
iface.change_state = Some(action_change_state::<T>);
iface.activate = Some(action_activate::<T>);
}
}

unsafe extern "C" fn action_get_name<T: ActionImpl>(
actionptr: *mut ffi::GAction,
) -> *const libc::c_char {
let instance = &*(actionptr as *mut T::Instance);
let imp = instance.imp();

imp.name().to_glib_none().0
}

unsafe extern "C" fn action_get_parameter_type<T: ActionImpl>(
actionptr: *mut ffi::GAction,
) -> *const GVariantType {
let instance = &*(actionptr as *mut T::Instance);
let imp = instance.imp();

imp.parameter_type().to_glib_none().0
}

unsafe extern "C" fn action_get_state_type<T: ActionImpl>(
actionptr: *mut ffi::GAction,
) -> *const GVariantType {
let instance = &*(actionptr as *mut T::Instance);
let imp = instance.imp();

imp.state_type().to_glib_none().0
}

unsafe extern "C" fn action_get_state_hint<T: ActionImpl>(
actionptr: *mut ffi::GAction,
) -> *mut GVariant {
let instance = &*(actionptr as *mut T::Instance);
let imp = instance.imp();

imp.state_hint().to_glib_full()
}

unsafe extern "C" fn action_get_enabled<T: ActionImpl>(actionptr: *mut ffi::GAction) -> gboolean {
let instance = &*(actionptr as *mut T::Instance);
let imp = instance.imp();

imp.enabled() as gboolean
}

unsafe extern "C" fn action_get_state<T: ActionImpl>(
actionptr: *mut ffi::GAction,
) -> *mut GVariant {
let instance = &*(actionptr as *mut T::Instance);
let imp = instance.imp();

imp.state().to_glib_full()
}

unsafe extern "C" fn action_change_state<T: ActionImpl>(
actionptr: *mut ffi::GAction,
value: *mut GVariant,
) {
let instance = &*(actionptr as *mut T::Instance);
let imp = instance.imp();
let value: Variant = from_glib_none(value);

imp.change_state(value);
}

unsafe extern "C" fn action_activate<T: ActionImpl>(
actionptr: *mut ffi::GAction,
parameterptr: *mut GVariant,
) {
let instance = &*(actionptr as *mut T::Instance);
let imp = instance.imp();
let parameter: Option<Variant> = from_glib_none(parameterptr);

imp.activate(parameter);
}
2 changes: 2 additions & 0 deletions gio/src/subclass/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Take a look at the license at the top of the repository in the LICENSE file.

mod action;
mod action_group;
mod action_map;
mod application;
Expand All @@ -19,6 +20,7 @@ pub mod prelude {
pub use glib::subclass::prelude::*;

pub use super::{
action::{ActionImpl, ActionImplExt},
action_group::{ActionGroupImpl, ActionGroupImplExt},
action_map::{ActionMapImpl, ActionMapImplExt},
application::{ApplicationImpl, ApplicationImplExt},
Expand Down

0 comments on commit 1c5636b

Please sign in to comment.