Skip to content

Commit aaf4d8c

Browse files
committed
Rewrite DBus registration example with inheritance
This is more in line how application classes would be used in real world applications which usually create a derived application class which holds the overall state. And it prepares for testing the dbus_register vfunc subsequently.
1 parent 79adf6c commit aaf4d8c

File tree

1 file changed

+141
-105
lines changed
  • examples/gio_dbus_register_object

1 file changed

+141
-105
lines changed
Lines changed: 141 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,126 +1,162 @@
1-
use gio::{prelude::*, IOErrorEnum};
2-
use std::{
3-
sync::mpsc::{channel, Receiver, Sender},
4-
time::Duration,
5-
};
6-
7-
const EXAMPLE_XML: &str = r#"
8-
<node>
9-
<interface name='com.github.gtk_rs.examples.HelloWorld'>
10-
<method name='Hello'>
11-
<arg type='s' name='name' direction='in'/>
12-
<arg type='s' name='greet' direction='out'/>
13-
</method>
14-
<method name='SlowHello'>
15-
<arg type='s' name='name' direction='in'/>
16-
<arg type='u' name='delay' direction='in'/>
17-
<arg type='s' name='greet' direction='out'/>
18-
</method>
19-
</interface>
20-
</node>
21-
"#;
1+
use gio::prelude::*;
222

23-
#[derive(Debug, glib::Variant)]
24-
struct Hello {
25-
name: String,
3+
glib::wrapper! {
4+
pub struct SampleApplication(ObjectSubclass<imp::SampleApplication>)
5+
@extends gio::Application,
6+
@implements gio::ActionGroup, gio::ActionMap;
267
}
278

28-
#[derive(Debug, glib::Variant)]
29-
struct SlowHello {
30-
name: String,
31-
delay: u32,
9+
impl Default for SampleApplication {
10+
fn default() -> Self {
11+
glib::Object::builder()
12+
.property(
13+
"application-id",
14+
"com.github.gtk-rs.examples.RegisterDBusObject",
15+
)
16+
.build()
17+
}
3218
}
3319

34-
#[derive(Debug)]
35-
enum HelloMethod {
36-
Hello(Hello),
37-
SlowHello(SlowHello),
38-
}
20+
mod imp {
21+
use std::cell::RefCell;
22+
use std::time::Duration;
23+
24+
use gio::prelude::*;
25+
use gio::subclass::prelude::*;
26+
use gio::{DBusConnection, IOErrorEnum};
27+
28+
const EXAMPLE_XML: &str = r#"
29+
<node>
30+
<interface name='com.github.gtk_rs.examples.HelloWorld'>
31+
<method name='Hello'>
32+
<arg type='s' name='name' direction='in'/>
33+
<arg type='s' name='greet' direction='out'/>
34+
</method>
35+
<method name='SlowHello'>
36+
<arg type='s' name='name' direction='in'/>
37+
<arg type='u' name='delay' direction='in'/>
38+
<arg type='s' name='greet' direction='out'/>
39+
</method>
40+
</interface>
41+
</node>
42+
"#;
43+
44+
#[derive(Debug, glib::Variant)]
45+
struct Hello {
46+
name: String,
47+
}
48+
49+
#[derive(Debug, glib::Variant)]
50+
struct SlowHello {
51+
name: String,
52+
delay: u32,
53+
}
54+
55+
#[derive(Debug)]
56+
enum HelloMethod {
57+
Hello(Hello),
58+
SlowHello(SlowHello),
59+
}
3960

40-
impl DBusMethodCall for HelloMethod {
41-
fn parse_call(
42-
_obj_path: &str,
43-
_interface: Option<&str>,
44-
method: &str,
45-
params: glib::Variant,
46-
) -> Result<Self, glib::Error> {
47-
match method {
48-
"Hello" => Ok(params.get::<Hello>().map(Self::Hello)),
49-
"SlowHello" => Ok(params.get::<SlowHello>().map(Self::SlowHello)),
50-
_ => Err(glib::Error::new(IOErrorEnum::Failed, "No such method")),
61+
impl DBusMethodCall for HelloMethod {
62+
fn parse_call(
63+
_obj_path: &str,
64+
_interface: Option<&str>,
65+
method: &str,
66+
params: glib::Variant,
67+
) -> Result<Self, glib::Error> {
68+
match method {
69+
"Hello" => Ok(params.get::<Hello>().map(Self::Hello)),
70+
"SlowHello" => Ok(params.get::<SlowHello>().map(Self::SlowHello)),
71+
_ => Err(glib::Error::new(IOErrorEnum::Failed, "No such method")),
72+
}
73+
.and_then(|p| {
74+
p.ok_or_else(|| glib::Error::new(IOErrorEnum::Failed, "Invalid parameters"))
75+
})
5176
}
52-
.and_then(|p| p.ok_or_else(|| glib::Error::new(IOErrorEnum::Failed, "Invalid parameters")))
5377
}
54-
}
5578

56-
fn on_startup(app: &gio::Application, tx: &Sender<gio::RegistrationId>) {
57-
let connection = app.dbus_connection().expect("connection");
58-
59-
let example = gio::DBusNodeInfo::for_xml(EXAMPLE_XML)
60-
.ok()
61-
.and_then(|e| e.lookup_interface("com.github.gtk_rs.examples.HelloWorld"))
62-
.expect("Example interface");
63-
64-
if let Ok(id) = connection
65-
.register_object("/com/github/gtk_rs/examples/HelloWorld", &example)
66-
.typed_method_call::<HelloMethod>()
67-
.invoke_and_return_future_local(|_, sender, call| {
68-
println!("Method call from {sender:?}");
69-
async {
70-
match call {
71-
HelloMethod::Hello(Hello { name }) => {
72-
let greet = format!("Hello {name}!");
73-
println!("{greet}");
74-
Ok(Some(greet.to_variant()))
75-
}
76-
HelloMethod::SlowHello(SlowHello { name, delay }) => {
77-
glib::timeout_future(Duration::from_secs(delay as u64)).await;
78-
let greet = format!("Hello {name} after {delay} seconds!");
79-
println!("{greet}");
80-
Ok(Some(greet.to_variant()))
79+
#[derive(Default)]
80+
pub struct SampleApplication {
81+
registration_id: RefCell<Option<gio::RegistrationId>>,
82+
}
83+
84+
impl SampleApplication {
85+
fn register_object(&self, connection: &DBusConnection) {
86+
let example = gio::DBusNodeInfo::for_xml(EXAMPLE_XML)
87+
.ok()
88+
.and_then(|e| e.lookup_interface("com.github.gtk_rs.examples.HelloWorld"))
89+
.expect("Example interface");
90+
91+
if let Ok(id) = connection
92+
.register_object("/com/github/gtk_rs/examples/HelloWorld", &example)
93+
.typed_method_call::<HelloMethod>()
94+
.invoke_and_return_future_local(|_, sender, call| {
95+
println!("Method call from {sender:?}");
96+
async {
97+
match call {
98+
HelloMethod::Hello(Hello { name }) => {
99+
let greet = format!("Hello {name}!");
100+
println!("{greet}");
101+
Ok(Some(greet.to_variant()))
102+
}
103+
HelloMethod::SlowHello(SlowHello { name, delay }) => {
104+
glib::timeout_future(Duration::from_secs(delay as u64)).await;
105+
let greet = format!("Hello {name} after {delay} seconds!");
106+
println!("{greet}");
107+
Ok(Some(greet.to_variant()))
108+
}
109+
}
81110
}
82-
}
111+
})
112+
.build()
113+
{
114+
println!("Registered object");
115+
self.registration_id.replace(Some(id));
116+
} else {
117+
eprintln!("Could not register object");
83118
}
84-
})
85-
.build()
86-
{
87-
println!("Registered object");
88-
tx.send(id).unwrap();
89-
} else {
90-
eprintln!("Could not register object");
119+
}
91120
}
92-
}
93121

94-
fn on_shutdown(app: &gio::Application, rx: &Receiver<gio::RegistrationId>) {
95-
let connection = app.dbus_connection().expect("connection");
96-
if let Ok(registration_id) = rx.try_recv() {
97-
if connection.unregister_object(registration_id).is_ok() {
98-
println!("Unregistered object");
99-
} else {
100-
eprintln!("Could not unregister object");
101-
}
122+
#[glib::object_subclass]
123+
impl ObjectSubclass for SampleApplication {
124+
const NAME: &'static str = "SampleApplication";
125+
126+
type Type = super::SampleApplication;
127+
128+
type ParentType = gio::Application;
102129
}
103-
}
104130

105-
fn main() -> glib::ExitCode {
106-
let app = gio::Application::builder()
107-
.application_id("com.github.gtk-rs.examples.RegisterDBusObject")
108-
.build();
109-
let _guard = app.hold();
110-
let (tx, rx) = channel::<gio::RegistrationId>();
131+
impl ObjectImpl for SampleApplication {}
111132

112-
app.connect_startup(move |app| {
113-
on_startup(app, &tx);
114-
});
133+
impl ApplicationImpl for SampleApplication {
134+
fn startup(&self) {
135+
self.parent_startup();
136+
let connection = self.obj().dbus_connection().expect("connection");
137+
self.register_object(&connection);
138+
}
115139

116-
app.connect_activate(move |_| {
117-
println!("Waiting for DBus Hello method to be called. Call the following command from another terminal:");
118-
println!("dbus-send --print-reply --dest=com.github.gtk-rs.examples.RegisterDBusObject /com/github/gtk_rs/examples/HelloWorld com.github.gtk_rs.examples.HelloWorld.Hello string:YourName");
119-
});
140+
fn shutdown(&self) {
141+
if let Some(id) = self.registration_id.take() {
142+
let connection = self.obj().dbus_connection().expect("connection");
143+
if connection.unregister_object(id).is_ok() {
144+
println!("Unregistered object");
145+
} else {
146+
eprintln!("Could not unregister object");
147+
}
148+
}
149+
}
120150

121-
app.connect_shutdown(move |app| {
122-
on_shutdown(app, &rx);
123-
});
151+
fn activate(&self) {
152+
println!("Waiting for DBus Hello method to be called. Call the following command from another terminal:");
153+
println!("dbus-send --print-reply --dest=com.github.gtk-rs.examples.RegisterDBusObject /com/github/gtk_rs/examples/HelloWorld com.github.gtk_rs.examples.HelloWorld.Hello string:YourName");
154+
}
155+
}
156+
}
124157

158+
fn main() -> glib::ExitCode {
159+
let app = SampleApplication::default();
160+
let _guard = app.hold();
125161
app.run()
126162
}

0 commit comments

Comments
 (0)