Sending Desktop Notifications from Rust


#1

Hi there,

I’m looking for a nice way to send desktop notifications from my rust application.
I’ve looked at https://crates.io/crates/dbus but find the dbus interface a bit complex.
Has anybody done this before?
Would you suggest using libnotify?

Thanks a lot.


#2

I found this which is not available on crates.io but works.
Unfortunately it took some work to get it to build with the nightly version of rust.
I’m still in the process of wrapping my head around strings, so please don’t read too much into my “fix” there.

have a nice day


#3

After loosing interest for a while I turned back to this topic and wrote a tiny crate that does this, without resorting to using c-code. (The DBus crate I use does though.)
This little crate will do the job.


#4

Looks nice :smile: You could use $crate to get the crate name in the macro. I think it would be better than forcing the user to import the functions.


#5

:flushed: Thanks for the advice, I’m mostly doing this all to learn the language, so there might be a couple of caveats that I probably run into.
$crate is used in v0.0.2 :blush:


#6

Macros are too powerful for this. Consider using the builder pattern like Command does.


#7

I would rather say that a builder pattern is too “powerful”. Why make a whole factory for four arguments? An optional convenience macro does no harm.


#8

Because you can make it clear what each parameter means without inventing non-standard syntax and the error messages will be easier to understand.

Also macro visibility rules aren’t very granular.


#9

I would rather make a small struct, if that is the problem, and implement Default. Anyway, it’s just four arguments, so it’s no big deal. It would be an other thing if it was more complicated.


#10

The current number of parameters and whether you like builders is beside the point. The use of macros to implement named and/or optional parameters is not idiomatic and is strictly inferior to other solutions, a builder being one of them.


#11

It was never about me liking builder patterns or not. Builder patterns are really useful for complicated things and I just thought it would be a bit over the top, compared to just calling the send function. That’s all. I’ll leave you to discuss how named and/or optional parameters are best implemented for notifications. I have no real opinions in that question.

By the way, I thought the whole point with a macro was to allow some (not insanely) non-standard code to ease the development. This case would not be much more crazy than println!. I may be wrong.


#12

[quote=“ogeon, post:11, topic:1057”]
I thought the whole point with a macro was to allow some (not insanely) non-standard code to ease the development.
[/quote]Not sure if that’s the whole point. And non-standard syntax has costs in terms of ease of development too.

[quote=“ogeon, post:11, topic:1057”]
This case would not be much more crazy than println!. I may be wrong.
[/quote]Almost none of the macros in std can be implemented as functions. That’s the criterion usually. print! and panic! rely on the built-in format_args!.


#13

Saying that it is the whole point was a poor choice of words. I meant part of the point. In any case, I agree that there is a cost when using non-standard syntax. There is always a trade off between convenience and “familiarity” (in need of a better word).

True, but formatting can be done without macros, because it’s just a sequence of writes. It’s not fun or convenient, but it is possible.


#14

In this case I chose a macro because I wanted to try out macros and because I read that there is no overloading of methods in rust.

From your discussion I take away that for this sort of functionality one can use an Enum or implement a builder pattern. I will look into this. Thanks alot for the insight.


#15

I would rather make a small struct, if that is the problem, and implement Default.

could you perhaps out an example here?


#16

Sure!

use std::borrow::Cow;

pub struct Notification<'a> {
    appname: Cow<'a, str>,
    summary: Cow<'a, str>,
    body: Cow<'a, str>,
    icon: Cow<'a, str>,
    timeout: i32
}

//Dummy
fn exe_name() -> String {
    String::new()
}

impl<'a> Notification<'a> {
    //Could also be send(&self) to allow reuse
    fn send(self) {
        //...
    }
}

impl<'a> Default for Notification<'a> {
    fn default() -> Notification<'a> {
        Notification {
            appname: exe_name().into(),
            summary: "".into(),
            body: "".into(),
            icon: "".into(),
            timeout: 5
        }
    }
}

fn main() {
    Notification {
        appname: "My App".into(),
        summary: "Oh, no!".into(),
        timeout: 20,
        ..Notification::default()
    }.send();
}

It’s not necessarily the best way to do it and I based it on what you already have, hence the use of Cow to allow both String and &str in the fields.

Also, sorry for not counting properly yesterday. It was five arguments, but still…


#17

Wow, that is almost a patch.
Are all the lifetime annotations necessary? rustbyexample sais references have a lifetime of 'a automatically. And what does a lifetime annotation after impl imply?
Thanks.


#18
            appname: exe_name().into(),
            summary: "".into(),

This pattern doesn’t seem to support non-optional parameters well so far.


#19

They are necessary in structs. You could also lock them to 'static, but that would not be as useful. The annotation on impl declares a generic lifetime to be used in the implementation, just like generic types.


#20

Ah, ok I just read it in the book. So this basically ensures that all members of the struct have the same lifetime as the implementation.