Skip to content

Commit c1df414

Browse files
gtk: Add Accessible subclassing support
1 parent 6e6368f commit c1df414

File tree

2 files changed

+307
-0
lines changed

2 files changed

+307
-0
lines changed

gtk4/src/subclass/accessible.rs

Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
// Take a look at the license at the top of the repository in the LICENSE file.
2+
3+
// rustdoc-stripper-ignore-next
4+
//! Traits intended for implementing the [`Acessible`](crate::Acessible) interface.
5+
6+
use super::PtrHolder;
7+
use crate::{prelude::*, subclass::prelude::*, ATContext, Accessible, AccessiblePlatformState};
8+
use glib::{translate::*, Quark};
9+
use once_cell::sync::Lazy;
10+
use std::mem::MaybeUninit;
11+
12+
pub trait AccessibleImpl: ObjectImpl {
13+
#[doc(alias = "get_platform_state")]
14+
fn platform_state(&self, state: AccessiblePlatformState) -> bool {
15+
self.parent_platform_state(state)
16+
}
17+
18+
#[doc(alias = "get_bounds")]
19+
fn bounds(&self) -> Option<(i32, i32, i32, i32)> {
20+
self.parent_bounds()
21+
}
22+
23+
#[doc(alias = "get_at_context")]
24+
fn at_context(&self) -> Option<ATContext> {
25+
self.parent_at_context()
26+
}
27+
28+
#[doc(alias = "get_accessible_parent")]
29+
fn accessible_parent(&self) -> Option<Accessible> {
30+
self.parent_accessible_parent()
31+
}
32+
33+
#[doc(alias = "get_first_accessible_child")]
34+
fn first_accessible_child(&self) -> Option<Accessible> {
35+
self.parent_first_accessible_child()
36+
}
37+
38+
#[doc(alias = "get_next_accessible_sibling")]
39+
fn next_accessible_sibling(&self) -> Option<Accessible> {
40+
self.parent_next_accessible_sibling()
41+
}
42+
}
43+
44+
pub trait AccessibleImplExt: ObjectSubclass {
45+
fn parent_platform_state(&self, state: AccessiblePlatformState) -> bool;
46+
fn parent_bounds(&self) -> Option<(i32, i32, i32, i32)>;
47+
fn parent_at_context(&self) -> Option<ATContext>;
48+
fn parent_accessible_parent(&self) -> Option<Accessible>;
49+
fn parent_first_accessible_child(&self) -> Option<Accessible>;
50+
fn parent_next_accessible_sibling(&self) -> Option<Accessible>;
51+
}
52+
53+
impl<T: AccessibleImpl> AccessibleImplExt for T {
54+
fn parent_platform_state(&self, state: AccessiblePlatformState) -> bool {
55+
unsafe {
56+
let type_data = Self::type_data();
57+
let parent_iface = type_data.as_ref().parent_interface::<Accessible>()
58+
as *const ffi::GtkAccessibleInterface;
59+
60+
let func = (*parent_iface)
61+
.get_platform_state
62+
.expect("no parent \"get_platform_state\" implementation");
63+
64+
from_glib(func(
65+
self.obj().unsafe_cast_ref::<Accessible>().to_glib_none().0,
66+
state.into_glib(),
67+
))
68+
}
69+
}
70+
71+
fn parent_bounds(&self) -> Option<(i32, i32, i32, i32)> {
72+
unsafe {
73+
let type_data = Self::type_data();
74+
let parent_iface = type_data.as_ref().parent_interface::<Accessible>()
75+
as *const ffi::GtkAccessibleInterface;
76+
77+
let func = (*parent_iface)
78+
.get_bounds
79+
.expect("no parent \"get_bounds\" implementation");
80+
81+
let mut x = MaybeUninit::uninit();
82+
let mut y = MaybeUninit::uninit();
83+
let mut width = MaybeUninit::uninit();
84+
let mut height = MaybeUninit::uninit();
85+
let res = from_glib(func(
86+
self.obj().unsafe_cast_ref::<Accessible>().to_glib_none().0,
87+
x.as_mut_ptr(),
88+
y.as_mut_ptr(),
89+
width.as_mut_ptr(),
90+
height.as_mut_ptr(),
91+
));
92+
if res {
93+
Some((
94+
x.assume_init(),
95+
y.assume_init(),
96+
width.assume_init(),
97+
height.assume_init(),
98+
))
99+
} else {
100+
None
101+
}
102+
}
103+
}
104+
105+
fn parent_at_context(&self) -> Option<ATContext> {
106+
unsafe {
107+
let type_data = Self::type_data();
108+
let parent_iface = type_data.as_ref().parent_interface::<Accessible>()
109+
as *const ffi::GtkAccessibleInterface;
110+
111+
let func = (*parent_iface)
112+
.get_at_context
113+
.expect("no parent \"get_at_context\" implementation");
114+
115+
from_glib_none(func(
116+
self.obj().unsafe_cast_ref::<Accessible>().to_glib_none().0,
117+
))
118+
}
119+
}
120+
121+
fn parent_accessible_parent(&self) -> Option<Accessible> {
122+
unsafe {
123+
let type_data = Self::type_data();
124+
let parent_iface = type_data.as_ref().parent_interface::<Accessible>()
125+
as *const ffi::GtkAccessibleInterface;
126+
127+
let func = (*parent_iface)
128+
.get_accessible_parent
129+
.expect("no parent \"get_accessible_parent\" implementation");
130+
131+
from_glib_none(func(
132+
self.obj().unsafe_cast_ref::<Accessible>().to_glib_none().0,
133+
))
134+
}
135+
}
136+
137+
fn parent_first_accessible_child(&self) -> Option<Accessible> {
138+
unsafe {
139+
let type_data = Self::type_data();
140+
let parent_iface = type_data.as_ref().parent_interface::<Accessible>()
141+
as *const ffi::GtkAccessibleInterface;
142+
143+
let func = (*parent_iface)
144+
.get_first_accessible_child
145+
.expect("no parent \"get_first_accessible_child\" implementation");
146+
147+
from_glib_none(func(
148+
self.obj().unsafe_cast_ref::<Accessible>().to_glib_none().0,
149+
))
150+
}
151+
}
152+
153+
fn parent_next_accessible_sibling(&self) -> Option<Accessible> {
154+
unsafe {
155+
let type_data = Self::type_data();
156+
let parent_iface = type_data.as_ref().parent_interface::<Accessible>()
157+
as *const ffi::GtkAccessibleInterface;
158+
159+
let func = (*parent_iface)
160+
.get_next_accessible_sibling
161+
.expect("no parent \"get_next_accessible_sibling\" implementation");
162+
163+
from_glib_none(func(
164+
self.obj().unsafe_cast_ref::<Accessible>().to_glib_none().0,
165+
))
166+
}
167+
}
168+
}
169+
170+
unsafe impl<T: AccessibleImpl> IsImplementable<T> for Accessible {
171+
fn interface_init(iface: &mut glib::Interface<Self>) {
172+
let iface = iface.as_mut();
173+
174+
iface.get_platform_state = Some(accessible_get_platform_state::<T>);
175+
iface.get_bounds = Some(accessible_get_bounds::<T>);
176+
iface.get_at_context = Some(accessible_get_at_context::<T>);
177+
iface.get_accessible_parent = Some(accessible_get_accessible_parent::<T>);
178+
iface.get_first_accessible_child = Some(accessible_get_first_accessible_child::<T>);
179+
iface.get_next_accessible_sibling = Some(accessible_get_next_accessible_sibling::<T>);
180+
}
181+
}
182+
183+
unsafe extern "C" fn accessible_get_platform_state<T: AccessibleImpl>(
184+
accessible: *mut ffi::GtkAccessible,
185+
state: ffi::GtkAccessiblePlatformState,
186+
) -> glib::ffi::gboolean {
187+
let instance = &*(accessible as *mut T::Instance);
188+
let imp = instance.imp();
189+
190+
imp.platform_state(from_glib(state)).into_glib()
191+
}
192+
193+
unsafe extern "C" fn accessible_get_bounds<T: AccessibleImpl>(
194+
accessible: *mut ffi::GtkAccessible,
195+
xptr: *mut libc::c_int,
196+
yptr: *mut libc::c_int,
197+
widthptr: *mut libc::c_int,
198+
heightptr: *mut libc::c_int,
199+
) -> glib::ffi::gboolean {
200+
let instance = &*(accessible as *mut T::Instance);
201+
let imp = instance.imp();
202+
203+
if let Some((x, y, width, height)) = imp.bounds() {
204+
*xptr = x;
205+
*yptr = y;
206+
*widthptr = width;
207+
*heightptr = height;
208+
209+
true.into_glib()
210+
} else {
211+
false.into_glib()
212+
}
213+
}
214+
215+
static ACCESSIBLE_GET_AT_CONTEXT_QUARK: Lazy<Quark> =
216+
Lazy::new(|| Quark::from_str("gtk4-rs-subclass-accessible-get-at-context"));
217+
unsafe extern "C" fn accessible_get_at_context<T: AccessibleImpl>(
218+
accessible: *mut ffi::GtkAccessible,
219+
) -> *mut ffi::GtkATContext {
220+
let instance = &*(accessible as *mut T::Instance);
221+
let imp = instance.imp();
222+
223+
if let Some(at_context) = imp.at_context() {
224+
let at_context = at_context.into_glib_ptr();
225+
imp.obj().set_qdata(
226+
*ACCESSIBLE_GET_AT_CONTEXT_QUARK,
227+
PtrHolder(at_context, |ptr| {
228+
glib::gobject_ffi::g_object_unref(ptr as *mut _)
229+
}),
230+
);
231+
at_context
232+
} else {
233+
std::ptr::null_mut()
234+
}
235+
}
236+
237+
static ACCESSIBLE_GET_ACCESSIBLE_PARENT: Lazy<Quark> =
238+
Lazy::new(|| Quark::from_str("gtk4-rs-subclass-accessible-get-accessible-parent"));
239+
unsafe extern "C" fn accessible_get_accessible_parent<T: AccessibleImpl>(
240+
accessible: *mut ffi::GtkAccessible,
241+
) -> *mut ffi::GtkAccessible {
242+
let instance = &*(accessible as *mut T::Instance);
243+
let imp = instance.imp();
244+
245+
if let Some(accessible_parent) = imp.accessible_parent() {
246+
let accessible_parent = accessible_parent.into_glib_ptr();
247+
imp.obj().set_qdata(
248+
*ACCESSIBLE_GET_ACCESSIBLE_PARENT,
249+
PtrHolder(accessible_parent, |ptr| {
250+
glib::gobject_ffi::g_object_unref(ptr as *mut _)
251+
}),
252+
);
253+
accessible_parent
254+
} else {
255+
std::ptr::null_mut()
256+
}
257+
}
258+
259+
static ACCESSIBLE_GET_FIRST_ACCESSIBLE_CHILD: Lazy<Quark> =
260+
Lazy::new(|| Quark::from_str("gtk4-rs-subclass-accessible-get-first)accessible-child"));
261+
unsafe extern "C" fn accessible_get_first_accessible_child<T: AccessibleImpl>(
262+
accessible: *mut ffi::GtkAccessible,
263+
) -> *mut ffi::GtkAccessible {
264+
let instance = &*(accessible as *mut T::Instance);
265+
let imp = instance.imp();
266+
267+
if let Some(first_accessible_child) = imp.first_accessible_child() {
268+
let first_accessible_child = first_accessible_child.into_glib_ptr();
269+
imp.obj().set_qdata(
270+
*ACCESSIBLE_GET_FIRST_ACCESSIBLE_CHILD,
271+
PtrHolder(first_accessible_child, |ptr| {
272+
glib::gobject_ffi::g_object_unref(ptr as *mut _)
273+
}),
274+
);
275+
first_accessible_child
276+
} else {
277+
std::ptr::null_mut()
278+
}
279+
}
280+
281+
static ACCESSIBLE_GET_NEXT_ACCESSIBLE_SIBLING: Lazy<Quark> =
282+
Lazy::new(|| Quark::from_str("gtk4-rs-subclass-accessible-get-next-accessible-sibling"));
283+
unsafe extern "C" fn accessible_get_next_accessible_sibling<T: AccessibleImpl>(
284+
accessible: *mut ffi::GtkAccessible,
285+
) -> *mut ffi::GtkAccessible {
286+
let instance = &*(accessible as *mut T::Instance);
287+
let imp = instance.imp();
288+
289+
if let Some(next_accessible_sibling) = imp.next_accessible_sibling() {
290+
let next_accessible_sibling = next_accessible_sibling.into_glib_ptr();
291+
imp.obj().set_qdata(
292+
*ACCESSIBLE_GET_NEXT_ACCESSIBLE_SIBLING,
293+
PtrHolder(next_accessible_sibling, |ptr| {
294+
glib::gobject_ffi::g_object_unref(ptr as *mut _)
295+
}),
296+
);
297+
next_accessible_sibling
298+
} else {
299+
std::ptr::null_mut()
300+
}
301+
}

gtk4/src/subclass/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ impl<T, F: Fn(*mut T) + 'static> Drop for PtrHolder<T, F> {
1414
}
1515
}
1616

17+
#[cfg(any(feature = "v4_10", feature = "dox"))]
18+
#[cfg_attr(feature = "dox", doc(cfg(feature = "v4_10")))]
19+
pub mod accessible;
1720
#[cfg(any(feature = "v4_10", feature = "dox"))]
1821
#[cfg_attr(feature = "dox", doc(cfg(feature = "v4_10")))]
1922
pub mod accessible_range;
@@ -92,6 +95,9 @@ pub mod prelude {
9295
#[doc(hidden)]
9396
pub use glib::subclass::prelude::*;
9497

98+
#[cfg(any(feature = "v4_10", feature = "dox"))]
99+
#[cfg_attr(feature = "dox", doc(cfg(feature = "v4_10")))]
100+
pub use super::accessible::{AccessibleImpl, AccessibleImplExt};
95101
#[cfg(any(feature = "v4_10", feature = "dox"))]
96102
#[cfg_attr(feature = "dox", doc(cfg(feature = "v4_10")))]
97103
pub use super::accessible_range::{AccessibleRangeImpl, AccessibleRangeImplExt};

0 commit comments

Comments
 (0)