Skip to content

Commit bb40a03

Browse files
authored
Merge pull request #1634 from swsnr/dbus_register_vfunc
Expose dbus_register and dbus_unregister vfuncs
2 parents 79adf6c + 054d9e2 commit bb40a03

File tree

2 files changed

+285
-107
lines changed

2 files changed

+285
-107
lines changed
Lines changed: 165 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,126 +1,186 @@
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, DBusError};
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+
<method name='GoodBye'></method>
41+
</interface>
42+
</node>
43+
"#;
44+
45+
#[derive(Debug, glib::Variant)]
46+
struct Hello {
47+
name: String,
48+
}
49+
50+
#[derive(Debug, glib::Variant)]
51+
struct SlowHello {
52+
name: String,
53+
delay: u32,
54+
}
3955

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")),
56+
#[derive(Debug)]
57+
enum HelloMethod {
58+
Hello(Hello),
59+
SlowHello(SlowHello),
60+
GoodBye,
61+
}
62+
63+
impl DBusMethodCall for HelloMethod {
64+
fn parse_call(
65+
_obj_path: &str,
66+
_interface: Option<&str>,
67+
method: &str,
68+
params: glib::Variant,
69+
) -> Result<Self, glib::Error> {
70+
match method {
71+
"Hello" => Ok(params.get::<Hello>().map(Self::Hello)),
72+
"SlowHello" => Ok(params.get::<SlowHello>().map(Self::SlowHello)),
73+
"GoodBye" => Ok(Some(Self::GoodBye)),
74+
_ => Err(glib::Error::new(DBusError::UnknownMethod, "No such method")),
75+
}
76+
.and_then(|p| {
77+
p.ok_or_else(|| glib::Error::new(DBusError::InvalidArgs, "Invalid parameters"))
78+
})
5179
}
52-
.and_then(|p| p.ok_or_else(|| glib::Error::new(IOErrorEnum::Failed, "Invalid parameters")))
5380
}
54-
}
5581

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()))
82+
#[derive(Default)]
83+
pub struct SampleApplication {
84+
registration_id: RefCell<Option<gio::RegistrationId>>,
85+
}
86+
87+
impl SampleApplication {
88+
fn register_object(
89+
&self,
90+
connection: &DBusConnection,
91+
) -> Result<gio::RegistrationId, glib::Error> {
92+
let example = gio::DBusNodeInfo::for_xml(EXAMPLE_XML)
93+
.ok()
94+
.and_then(|e| e.lookup_interface("com.github.gtk_rs.examples.HelloWorld"))
95+
.expect("Example interface");
96+
97+
connection
98+
.register_object("/com/github/gtk_rs/examples/HelloWorld", &example)
99+
.typed_method_call::<HelloMethod>()
100+
.invoke_and_return_future_local(glib::clone!(
101+
#[weak_allow_none(rename_to = app)]
102+
self.obj(),
103+
move |_, sender, call| {
104+
println!("Method call from {sender:?}");
105+
let app = app.clone();
106+
async move {
107+
match call {
108+
HelloMethod::Hello(Hello { name }) => {
109+
let greet = format!("Hello {name}!");
110+
println!("{greet}");
111+
Ok(Some(greet.to_variant()))
112+
}
113+
HelloMethod::SlowHello(SlowHello { name, delay }) => {
114+
glib::timeout_future(Duration::from_secs(delay as u64)).await;
115+
let greet = format!("Hello {name} after {delay} seconds!");
116+
println!("{greet}");
117+
Ok(Some(greet.to_variant()))
118+
}
119+
HelloMethod::GoodBye => {
120+
if let Some(app) = app {
121+
app.quit();
122+
}
123+
Ok(None)
124+
}
125+
}
126+
}
81127
}
128+
))
129+
.build()
130+
}
131+
}
132+
133+
#[glib::object_subclass]
134+
impl ObjectSubclass for SampleApplication {
135+
const NAME: &'static str = "SampleApplication";
136+
137+
type Type = super::SampleApplication;
138+
139+
type ParentType = gio::Application;
140+
}
141+
142+
impl ObjectImpl for SampleApplication {}
143+
144+
impl ApplicationImpl for SampleApplication {
145+
fn dbus_register(
146+
&self,
147+
connection: &DBusConnection,
148+
object_path: &str,
149+
) -> Result<(), glib::Error> {
150+
self.parent_dbus_register(connection, object_path)?;
151+
self.registration_id
152+
.replace(Some(self.register_object(connection)?));
153+
println!("registered object on session bus");
154+
Ok(())
155+
}
156+
157+
fn dbus_unregister(&self, connection: &DBusConnection, object_path: &str) {
158+
self.parent_dbus_unregister(connection, object_path);
159+
if let Some(id) = self.registration_id.take() {
160+
if connection.unregister_object(id).is_ok() {
161+
println!("Unregistered object");
162+
} else {
163+
eprintln!("Could not unregister object");
82164
}
83165
}
84-
})
85-
.build()
86-
{
87-
println!("Registered object");
88-
tx.send(id).unwrap();
89-
} else {
90-
eprintln!("Could not register object");
91-
}
92-
}
166+
}
167+
168+
fn shutdown(&self) {
169+
self.parent_shutdown();
170+
println!("Good bye!");
171+
}
93172

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");
173+
fn activate(&self) {
174+
println!("Waiting for DBus Hello method to be called. Call the following command from another terminal:");
175+
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");
176+
println!("Quit with the following command:");
177+
println!("dbus-send --print-reply --dest=com.github.gtk-rs.examples.RegisterDBusObject /com/github/gtk_rs/examples/HelloWorld com.github.gtk_rs.examples.HelloWorld.GoodBye");
101178
}
102179
}
103180
}
104181

105182
fn main() -> glib::ExitCode {
106-
let app = gio::Application::builder()
107-
.application_id("com.github.gtk-rs.examples.RegisterDBusObject")
108-
.build();
183+
let app = SampleApplication::default();
109184
let _guard = app.hold();
110-
let (tx, rx) = channel::<gio::RegistrationId>();
111-
112-
app.connect_startup(move |app| {
113-
on_startup(app, &tx);
114-
});
115-
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-
});
120-
121-
app.connect_shutdown(move |app| {
122-
on_shutdown(app, &rx);
123-
});
124-
125185
app.run()
126186
}

0 commit comments

Comments
 (0)