Compare commits

...

34 Commits

Author SHA1 Message Date
Julian Ospald a951e61a6c
Update libnotify deps 2017-09-02 01:00:43 +02:00
Julian Ospald d830a339e1
Update libnotify-sys deps 2017-09-02 00:59:43 +02:00
Julian Ospald 843fb0c731
Fix build against latest glib 2017-07-19 19:47:08 +02:00
Julian Ospald afcf7a7581
Fix build against latest gtk-rs 2017-07-14 00:47:21 +02:00
Julian Ospald 831b761b02 Explicitly add LICENSE to libnotify-sys subdir
So we also make sure it ends up in the cargo crate.
2017-07-13 11:41:45 +02:00
Julian Ospald 8e955a6e08 Add badges to libnotify-sys 2017-07-13 11:35:04 +02:00
Julian Ospald a3d579d750 Fix LICENSE link 2017-07-13 11:24:15 +02:00
Julian Ospald 6536667a4d Reorder bagdes, add download count badge 2017-07-13 11:20:23 +02:00
Julian Ospald f954a77778 Add documentation badges 2017-07-13 11:12:44 +02:00
Ospald, Julian fc8ca1af63 Fix documentation 2017-07-11 16:33:31 +02:00
Ospald, Julian f28b8bc052 Bump to 1.0.1 2017-07-11 15:59:55 +02:00
Ospald, Julian 49f09df64a Remove obsolete dependency 2017-07-11 15:59:24 +02:00
Ospald, Julian a8b22fa6ef Cosmetic README fix 2017-07-11 15:53:01 +02:00
Ospald, Julian 5f551cf664 Add README.md to libnotify-sys 2017-07-11 15:53:01 +02:00
Ospald, Julian 08d77ee4ff Update metadata 2017-07-11 15:53:01 +02:00
Ospald, Julian 03059f79c6 Remove git dependencies 2017-07-11 15:53:01 +02:00
Ospald, Julian 091ee97b70 Remove BoolError occurences
Because currently depends on unpublished glib binding.
2017-07-11 15:53:01 +02:00
Ospald, Julian d939bee7ea Cargo fmt 2017-07-11 15:24:10 +02:00
Ospald, Julian 557ebbc93f Fix examples 2017-07-11 15:18:40 +02:00
Ospald, Julian b50ff703ad Update README 2017-07-11 15:06:27 +02:00
Ospald, Julian a75ae6a1fe Fix documentation 2017-07-11 14:48:23 +02:00
Ospald, Julian d2a17eba0b Fix compiler warnings 2017-07-11 14:48:17 +02:00
Ospald, Julian e789326c83 Update .gitignore 2017-07-11 14:36:45 +02:00
Ospald, Julian 6a96044a68 Fix examples 2017-07-11 14:36:21 +02:00
Ospald, Julian cee315cf36 Fix travis secret 2017-07-11 14:11:04 +02:00
Ospald, Julian ac0502b16c Merge branch 'gir' 2017-07-11 13:58:52 +02:00
Ospald, Julian fb42397f55 Fix README 2017-07-11 13:58:06 +02:00
Ospald, Julian 69f5fe66f1 Fix travis 2017-07-11 13:58:06 +02:00
Julian Ospald 13850652a7 Switch to gir 2017-07-11 13:58:06 +02:00
Ospald, Julian 965a64aa55 Drop use of gtypes 2017-07-10 11:57:41 +02:00
Ospald, Julian 9f6e3f5d31 Add Drop impl for Notification
The notification is now unrefed via the GObject system.
2017-07-10 11:53:22 +02:00
Julian Ospald 437f2cc756
Rename new_notification() to new() 2017-07-10 01:09:21 +02:00
Julian Ospald fe4d803efe
Small rewrite:
* Use error-chain for errors and expose them
* Don't use Context object, since the lifetimes get us in trouble
  when used with gtk-rs, which has callback closures with static
  lifetime. Instead we just expose notify_init()/notify_uninit() and
  panic when functions are called before notify_init().
2017-07-10 01:01:36 +02:00
Julian Ospald 172cbd5143
Add lifetime specifiers to &self 2017-07-09 21:46:44 +02:00
20 changed files with 815 additions and 404 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
Cargo.lock
target/
.cargo/
docs.md

6
.gitmodules vendored Normal file
View File

@ -0,0 +1,6 @@
[submodule "gir"]
path = gir
url = https://github.com/gtk-rs/gir.git
[submodule "gir-files"]
path = gir-files
url = https://github.com/hasufell/gir-files.git

View File

@ -1,8 +1,18 @@
dist: trusty
sudo: false
language: rust
rust:
- nightly
- beta
- stable
addons:
apt:
packages:
- libgdk-pixbuf2.0-common
- libgdk-pixbuf2.0-dev
- libglib2.0-data
- libglib2.0-dev
- libnotify-dev
before_script:
- |
pip install 'travis-cargo<0.2' --user &&
@ -10,12 +20,11 @@ before_script:
script:
- |
travis-cargo build &&
travis-cargo test &&
# travis-cargo test &&
travis-cargo --only stable doc
after_success:
- travis-cargo --only stable doc-upload
env:
global:
- TRAVIS_CARGO_NIGHTLY_FEATURE=""
- secure: IjahTjjwmuvig/wTDMwxpk1F3Ywi2d0r17+JmOXHPdbfSfhi4puiTzsOgMjBhFtosTwcvlBeFwwFeTtl9KFNG165xm9Fqbhcez9sx+hS+EWZR/MBPFhKorJlgva0nuH8L1cxDUP+mDkcV/BdXCDeT7ml+y/FqEDAI4N0lwEsVMk=
- secure: B8QPcNgwOmbJ8dNJn/p/tE1cLeUOLTo/Oj7nOBkK1tatMgS6yfQFa5pyNEqeTyZAyNptssqSH1BpRC3RxTJ/b+kFzdy8Kq1nkJfp9R9zTY34w5gWukfmmTH4Qe2lyWY/DKL1lGVjb+8mroV9sPaS5Y4DqYHbeYtpWF8Gi27vIL4=
- secure: B9+n+ikrYqSxK1SYOHIvjtYi58IvdVC0HYJxyDiJnzIcEtos/aDiGbMZU1pIvC+qIAibdltIqzZ1afVC1msfsxeaov2e4VPKfTJV0gwLLq6tzuuaOeujtM9YUUWrdr8QQXk3LEPIl8HD5jm6VTLcl2TqPeiiyn96rk67nA5jeS8=

View File

@ -1,19 +1,24 @@
[package]
name = "libnotify"
version = "0.5.0"
authors = ["Mika Attila <radiantstatue@gmail.com>", "Julian Ospald <hasufell@posteo.de>"]
license = "MIT"
authors = [
"Mika Attila <radiantstatue@gmail.com>",
"Julian Ospald <hasufell@posteo.de>",
]
description = "Rust bindings to libnotify"
documentation = "https://hasufell.github.io/rust-libnotify/libnotify/"
keywords = [
"libnotify",
"notification",
]
license = "MIT"
name = "libnotify"
readme = "README.md"
repository = "https://github.com/crumblingstatue/rust-libnotify"
documentation = "http://crumblingstatue.github.io/doc/libnotify/libnotify/"
keywords = ["libnotify", "notification"]
repository = "https://github.com/hasufell/rust-libnotify"
version = "1.0.2"
[dependencies]
libnotify-sys = "^0.5.0"
gdk-pixbuf = "^0.1.3"
gdk-pixbuf-sys = "^0.3.4"
glib-sys = "^0.3.4"
gtypes = "^0.2.0"
glib = "^0.1.3"
gdk-pixbuf = "^0.2.0"
gdk-pixbuf-sys = "^0.4.0"
glib = "^0.3.1"
glib-sys = "^0.4.0"
gobject-sys = "^0.4.0"
libnotify-sys = "^1.0.1"

69
Gir.toml Normal file
View File

@ -0,0 +1,69 @@
[options]
girs_dir = "gir-files"
library = "Notify"
version = "0.7"
min_cfg_version = "0.7.7"
target_path = "."
work_mode = "normal"
generate_safety_asserts = true
deprecate_by_min_version = true
generate = [
"Notify.Urgency",
]
[[object]]
name = "Notify.Notification"
status = "generate"
[[object.function]]
name = "get_closed_reason"
ignore = true
[[object.function]]
name = "add_action"
ignore = true
[[object.function]]
name = "clear_actions"
ignore = true
[[object.function]]
name = "close"
# manual
ignore = true
[[object.function]]
name = "set_hint"
# manual
ignore = true
[[object.function]]
name = "set_icon_from_pixbuf"
# deprecated
ignore = true
[[object.function]]
name = "set_image_from_pixbuf"
# manual
ignore = true
[[object.function]]
name = "show"
# manual
ignore = true
[[object.function]]
name = "update"
[object.function.return]
bool_return_is_error = "Invalid parameter passed"
[[object.function]]
name = "set_app_name"
[[object.function.parameter]]
name = "app_name"
nullable = true
[[object]]
name = "Notify.*"
status = "generate"
[[object.function]]
name = "is_initted"
# manual assert_initialized_main_thread
ignore = true
[[object.function]]
name = "init"
# manual assert_initialized_main_thread
ignore = true

19
Makefile Normal file
View File

@ -0,0 +1,19 @@
GIR = gir/target/bin/gir
GIR_SRC = gir/Cargo.toml gir/Cargo.lock gir/build.rs $(shell find gir/src -name '*.rs')
GIR_FILES = gir-files/Notify-0.7.gir
# Run `gir` generating the bindings
gir : src/auto/mod.rs
src/auto/mod.rs : Gir.toml $(GIR) $(GIR_FILES)
$(GIR) -c Gir.toml
$(GIR) -m doc -c Gir.toml
rustdoc-stripper -g -o docs.md
$(GIR) : $(GIR_SRC)
rm -f gir/target/bin/gir
cargo install --path gir --root gir/target
rm -f gir/target/.crates.toml
$(GIR_SRC) $(GIR_FILES) :
git submodule update --init

View File

@ -1,4 +1,12 @@
[![Build Status](https://travis-ci.org/crumblingstatue/rust-libnotify.svg)](https://travis-ci.org/crumblingstatue/rust-libnotify)
[![Latest Version](https://img.shields.io/crates/v/libnotify.svg)](https://crates.io/crates/libnotify)
[![License](https://img.shields.io/github/license/hasufell/rust-libnotify.svg)](LICENSE)
[![Crate download count](https://img.shields.io/crates/d/libnotify.svg)](https://crates.io/crates/libnotify)
# libnotify-rs
Rust binding to libnotify
[![Documentation (crates.io)](https://img.shields.io/badge/documentation-docs.rs-df3600.svg)](https://docs.rs/libnotify)
[![Documentation (master)](https://img.shields.io/badge/documentation-master-yellow.svg)](https://hasufell.github.io/rust-libnotify/)
[![Build Status](https://travis-ci.org/hasufell/rust-libnotify.svg)](https://travis-ci.org/hasufell/rust-libnotify)
[![Join the chat at https://gitter.im/hasufell/rust-libnotify](https://badges.gitter.im/hasufell/rust-libnotify.svg)](https://gitter.im/hasufell/rust-libnotify?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
# rust-libnotify
Rust binding to libnotify.

View File

@ -1,12 +1,17 @@
extern crate libnotify;
fn main() {
// Create a libnotify context
let notify = libnotify::Context::new("myapp").unwrap();
// Create a new notification and show it
let n = notify.new_notification("Summary", Some("Optional Body"), None)
.unwrap();
// Init libnotify
libnotify::init("myapp");
// Create a new notification (doesn't show it yet)
let n =
libnotify::Notification::new("Summary", Some("Optional Body"), None);
// Show the notification
n.show().unwrap();
// You can also use the .show() convenience method on the context
notify.show("I am another notification", None, None).unwrap();
// Update the existent notification
n.update("I am another notification", None, None).unwrap();
// Show the updated notification
n.show().unwrap();
// We are done, deinit
libnotify::uninit();
}

1
gir Submodule

@ -0,0 +1 @@
Subproject commit ac9a8dadb62d003af9f0c6ed46e82ff0971125e5

1
gir-files Submodule

@ -0,0 +1 @@
Subproject commit 1f01de0ff05a22bdb5de4b1a330c46bdafdea300

11
gir-libnotify.toml Normal file
View File

@ -0,0 +1,11 @@
[options]
work_mode = "sys"
library = "Notify"
version = "0.7"
min_cfg_version = "0.7.6"
external_libraries = [
"GLib",
"GObject",
"GdkPixbuf",
]

30
libnotify-sys/Cargo.toml Normal file
View File

@ -0,0 +1,30 @@
[package]
authors = [
"Mika Attila <radiantstatue@gmail.com>",
"Julian Ospald <hasufell@posteo.de>",
]
build = "build.rs"
description = "FFI bindings to libnotify"
keywords = [
"libnotify",
"notification",
]
license = "MIT"
links = "libnotify"
name = "libnotify-sys"
readme = "README.md"
repository = "https://github.com/hasufell/rust-libnotify"
version = "1.0.1"
[build-dependencies]
pkg-config = ">=0.3.9"
[dependencies]
bitflags = "^0.9.1"
gdk-pixbuf-sys = "^0.4.0"
glib-sys = "^0.4.0"
gobject-sys = "^0.4.0"
libc = "^0.2.30"
[lib]
name = "libnotify_sys"

21
libnotify-sys/LICENSE Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Mika Attila
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

7
libnotify-sys/README.md Normal file
View File

@ -0,0 +1,7 @@
[![Latest Version](https://img.shields.io/crates/v/libnotify-sys.svg)](https://crates.io/crates/libnotify-sys)
[![License](https://img.shields.io/github/license/hasufell/rust-libnotify.svg)](LICENSE)
[![Crate download count](https://img.shields.io/crates/d/libnotify-sys.svg)](https://crates.io/crates/libnotify-sys)
# rust-libnotify-sys
Rust FFI declarations for libnotify

61
libnotify-sys/build.rs Normal file
View File

@ -0,0 +1,61 @@
extern crate pkg_config;
use pkg_config::{Config, Error};
use std::env;
use std::io::prelude::*;
use std::io;
use std::process;
fn main() {
if let Err(s) = find() {
let _ = writeln!(io::stderr(), "{}", s);
process::exit(1);
}
}
fn find() -> Result<(), Error> {
let package_name = "libnotify";
let shared_libs = ["notify"];
let version = {
"0.7.6"
};
if let Ok(lib_dir) = env::var("GTK_LIB_DIR") {
for lib_ in shared_libs.iter() {
println!("cargo:rustc-link-lib=dylib={}", lib_);
}
println!("cargo:rustc-link-search=native={}", lib_dir);
return Ok(())
}
let target = env::var("TARGET").expect("TARGET environment variable doesn't exist");
let hardcode_shared_libs = target.contains("windows");
let mut config = Config::new();
config.atleast_version(version);
if hardcode_shared_libs {
config.cargo_metadata(false);
}
match config.probe(package_name) {
Ok(library) => {
if hardcode_shared_libs {
for lib_ in shared_libs.iter() {
println!("cargo:rustc-link-lib=dylib={}", lib_);
}
for path in library.link_paths.iter() {
println!("cargo:rustc-link-search=native={}",
path.to_str().expect("library path doesn't exist"));
}
}
Ok(())
}
Err(Error::EnvNoPkgConfig(_)) | Err(Error::Command { .. }) => {
for lib_ in shared_libs.iter() {
println!("cargo:rustc-link-lib=dylib={}", lib_);
}
Ok(())
}
Err(err) => Err(err),
}
}

98
libnotify-sys/src/lib.rs Normal file
View File

@ -0,0 +1,98 @@
// This file was generated by gir (89daf8f) from gir-files (1f01de0)
// DO NOT EDIT
#![allow(non_camel_case_types, non_upper_case_globals)]
extern crate libc;
extern crate bitflags;
extern crate glib_sys as glib;
extern crate gobject_sys as gobject;
extern crate gdk_pixbuf_sys as gdk_pixbuf;
#[allow(unused_imports)]
use libc::{c_int, c_char, c_uchar, c_float, c_uint, c_double,
c_short, c_ushort, c_long, c_ulong,
c_void, size_t, ssize_t, intptr_t, uintptr_t, time_t, FILE};
#[allow(unused_imports)]
use glib::{gboolean, gconstpointer, gpointer, GType, Volatile};
// Enums
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(C)]
pub enum NotifyUrgency {
Low = 0,
Normal = 1,
Critical = 2,
}
pub const NOTIFY_URGENCY_LOW: NotifyUrgency = NotifyUrgency::Low;
pub const NOTIFY_URGENCY_NORMAL: NotifyUrgency = NotifyUrgency::Normal;
pub const NOTIFY_URGENCY_CRITICAL: NotifyUrgency = NotifyUrgency::Critical;
// Constants
pub const NOTIFY_EXPIRES_DEFAULT: c_int = -1;
pub const NOTIFY_EXPIRES_NEVER: c_int = 0;
pub const NOTIFY_VERSION_MAJOR: c_int = 0;
pub const NOTIFY_VERSION_MICRO: c_int = 7;
pub const NOTIFY_VERSION_MINOR: c_int = 7;
// Callbacks
pub type NotifyActionCallback = Option<unsafe extern "C" fn(*mut NotifyNotification, *mut c_char, gpointer)>;
// Records
#[repr(C)]
pub struct NotifyNotificationClass {
pub parent_class: gobject::GObjectClass,
pub closed: Option<unsafe extern "C" fn(*mut NotifyNotification)>,
}
#[repr(C)]
pub struct NotifyNotificationPrivate(c_void);
// Classes
#[repr(C)]
pub struct NotifyNotification {
pub parent_object: gobject::GObject,
pub priv_: *mut NotifyNotificationPrivate,
}
extern "C" {
//=========================================================================
// NotifyNotification
//=========================================================================
pub fn notify_notification_get_type() -> GType;
pub fn notify_notification_new(summary: *const c_char, body: *const c_char, icon: *const c_char) -> *mut NotifyNotification;
//pub fn notify_notification_add_action(notification: *mut NotifyNotification, action: *const c_char, label: *const c_char, callback: NotifyActionCallback, user_data: gpointer, free_func: /*Metadata mismatch*/[c:type mismatch `GFreeFunc` != `GDestroyNotify` of `DestroyNotify`]);
pub fn notify_notification_clear_actions(notification: *mut NotifyNotification);
pub fn notify_notification_clear_hints(notification: *mut NotifyNotification);
pub fn notify_notification_close(notification: *mut NotifyNotification, error: *mut *mut glib::GError) -> gboolean;
pub fn notify_notification_get_closed_reason(notification: *const NotifyNotification) -> c_int;
pub fn notify_notification_set_app_name(notification: *mut NotifyNotification, app_name: *const c_char);
pub fn notify_notification_set_category(notification: *mut NotifyNotification, category: *const c_char);
pub fn notify_notification_set_hint(notification: *mut NotifyNotification, key: *const c_char, value: *mut glib::GVariant);
pub fn notify_notification_set_hint_byte(notification: *mut NotifyNotification, key: *const c_char, value: c_uchar);
pub fn notify_notification_set_hint_byte_array(notification: *mut NotifyNotification, key: *const c_char, value: *mut u8, len: size_t);
pub fn notify_notification_set_hint_double(notification: *mut NotifyNotification, key: *const c_char, value: c_double);
pub fn notify_notification_set_hint_int32(notification: *mut NotifyNotification, key: *const c_char, value: c_int);
pub fn notify_notification_set_hint_string(notification: *mut NotifyNotification, key: *const c_char, value: *const c_char);
pub fn notify_notification_set_hint_uint32(notification: *mut NotifyNotification, key: *const c_char, value: c_uint);
pub fn notify_notification_set_icon_from_pixbuf(notification: *mut NotifyNotification, icon: *mut gdk_pixbuf::GdkPixbuf);
pub fn notify_notification_set_image_from_pixbuf(notification: *mut NotifyNotification, pixbuf: *mut gdk_pixbuf::GdkPixbuf);
pub fn notify_notification_set_timeout(notification: *mut NotifyNotification, timeout: c_int);
pub fn notify_notification_set_urgency(notification: *mut NotifyNotification, urgency: NotifyUrgency);
pub fn notify_notification_show(notification: *mut NotifyNotification, error: *mut *mut glib::GError) -> gboolean;
pub fn notify_notification_update(notification: *mut NotifyNotification, summary: *const c_char, body: *const c_char, icon: *const c_char) -> gboolean;
//=========================================================================
// Other functions
//=========================================================================
pub fn notify_get_app_name() -> *const c_char;
pub fn notify_get_server_caps() -> *mut glib::GList;
pub fn notify_get_server_info(ret_name: *mut *mut c_char, ret_vendor: *mut *mut c_char, ret_version: *mut *mut c_char, ret_spec_version: *mut *mut c_char) -> gboolean;
pub fn notify_init(app_name: *const c_char) -> gboolean;
pub fn notify_is_initted() -> gboolean;
pub fn notify_set_app_name(app_name: *const c_char);
pub fn notify_uninit();
}

45
src/enums.rs Normal file
View File

@ -0,0 +1,45 @@
// This file was generated by gir (89daf8f) from gir-files (1f01de0)
// DO NOT EDIT
use ffi;
use glib::translate::*;
use std;
/// The urgency level of the notification.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum Urgency {
/// Low urgency. Used for unimportant notifications.
Low,
/// Normal urgency. Used for most standard notifications.
Normal,
/// Critical urgency. Used for very important notifications.
Critical,
#[doc(hidden)]
__Unknown(i32),
}
#[doc(hidden)]
impl ToGlib for Urgency {
type GlibType = ffi::NotifyUrgency;
fn to_glib(&self) -> ffi::NotifyUrgency {
match *self {
Urgency::Low => ffi::NOTIFY_URGENCY_LOW,
Urgency::Normal => ffi::NOTIFY_URGENCY_NORMAL,
Urgency::Critical => ffi::NOTIFY_URGENCY_CRITICAL,
Urgency::__Unknown(value) => unsafe { std::mem::transmute(value) },
}
}
}
#[doc(hidden)]
impl FromGlib<ffi::NotifyUrgency> for Urgency {
fn from_glib(value: ffi::NotifyUrgency) -> Self {
match value as i32 {
0 => Urgency::Low,
1 => Urgency::Normal,
2 => Urgency::Critical,
value => Urgency::__Unknown(value),
}
}
}

112
src/functions.rs Normal file
View File

@ -0,0 +1,112 @@
use ffi;
use glib::translate::*;
use glib_ffi;
use std::ptr;
/// Gets whether or not libnotify is initialized.
///
/// # Returns
///
/// `true` if libnotify is initialized, or `false` otherwise.
pub fn is_initted() -> bool {
unsafe { from_glib(ffi::notify_is_initted()) }
}
/// Initialized libnotify. This must be called before any other functions.
///
/// # Returns
///
/// `Ok(())` if successful, `Err(str)` on error.
// TODO: switch back to BoolError when it hits stable glib
pub fn init(app_name: &str) -> Result<(), String> {
unsafe {
let b = ffi::notify_init(app_name.to_glib_none().0);
match b {
glib_ffi::GFALSE => Err(
String::from("Failed to initialize libnotify"),
),
_ => Ok(()),
}
}
}
/// Gets the application name registered.
///
/// # Returns
///
/// The registered application name, passed to `init()`.
pub fn get_app_name() -> Option<String> {
assert_initialized_libnotify!();
unsafe { from_glib_none(ffi::notify_get_app_name()) }
}
/// Synchronously queries the server for its capabilities and returns them as
/// a Vector.
///
/// # Returns
///
/// A Vector of server capability Strings.
pub fn get_server_caps() -> Vec<String> {
assert_initialized_libnotify!();
unsafe {
FromGlibPtrContainer::from_glib_full(ffi::notify_get_server_caps())
}
}
/// Synchronously queries the server for its information, specifically,
/// the name, vendor, server version, and the version of the notifications
/// specification that it is compliant with.
///
/// # Returns
///
/// `Some(ret_name, ret_vendor, ret_version, ret_spec_version)` on
/// success, otherwise `None` on error.
pub fn get_server_info() -> Option<(String, String, String, String)> {
assert_initialized_libnotify!();
unsafe {
let mut ret_name = ptr::null_mut();
let mut ret_vendor = ptr::null_mut();
let mut ret_version = ptr::null_mut();
let mut ret_spec_version = ptr::null_mut();
let ret = from_glib(ffi::notify_get_server_info(
&mut ret_name,
&mut ret_vendor,
&mut ret_version,
&mut ret_spec_version,
));
if ret {
Some((
from_glib_full(ret_name),
from_glib_full(ret_vendor),
from_glib_full(ret_version),
from_glib_full(ret_spec_version),
))
} else {
None
}
}
}
/// Sets the application name.
/// ## `app_name`
/// The name of the application.
pub fn set_app_name(app_name: &str) {
assert_initialized_libnotify!();
unsafe {
ffi::notify_set_app_name(app_name.to_glib_none().0);
}
}
/// Uninitialized libnotify.
///
/// This should be called when the program no longer needs libnotify for
/// the rest of its lifecycle, typically just before exitting.
pub fn uninit() {
assert_initialized_libnotify!();
unsafe {
ffi::notify_uninit();
}
}

View File

@ -4,15 +4,20 @@
//! extern crate libnotify;
//!
//! fn main() {
//! // Create a libnotify context
//! let notify = libnotify::Context::new("myapp").unwrap();
//! // Create a new notification and show it
//! let n = notify.new_notification("Summary",
//! Some("Optional Body"),
//! None).unwrap();
//! // Init libnotify
//! libnotify::init("myapp").unwrap();
//! // Create a new notification (doesn't show it yet)
//! let n = libnotify::Notification::new("Summary",
//! Some("Optional Body"),
//! None);
//! // Show the notification
//! n.show().unwrap();
//! // You can also use the .show() convenience method on the context
//! notify.show("I am another notification", None, None).unwrap();
//! // Update the existent notification
//! n.update("I am another notification", None, None).unwrap();
//! // Show the updated notification
//! n.show().unwrap();
//! // We are done, deinit
//! libnotify::uninit();
//! }
//!
//! ```
@ -20,382 +25,28 @@
#![warn(missing_docs)]
extern crate gdk_pixbuf;
extern crate gdk_pixbuf_sys;
#[macro_use]
extern crate glib;
extern crate glib_sys;
extern crate gtypes;
extern crate libnotify_sys as sys;
use gdk_pixbuf_sys::GdkPixbuf;
use glib::translate::*;
use gtypes::{TRUE, FALSE};
use std::error::Error;
use std::ffi::{self, CStr, CString};
use std::fmt;
use std::marker::PhantomData;
use std::os::raw::c_int;
extern crate glib_sys as glib_ffi;
extern crate gobject_sys as gobject_ffi;
extern crate libnotify_sys as ffi;
/// The urgency level of the notification.
pub enum Urgency {
/// Low urgency. Used for unimportant notifications.
Low,
/// Normal urgency. Used for most standard notifications.
Normal,
/// Critical urgency. Used for very important notifications.
Critical,
}
pub use enums::*;
pub use functions::*;
pub use notification::*;
impl From<sys::NotifyUrgency> for Urgency {
fn from(urgency: sys::NotifyUrgency) -> Urgency {
match urgency {
sys::NotifyUrgency::NotifyUrgencyLow => Urgency::Low,
sys::NotifyUrgency::NotifyUrgencyNormal => Urgency::Normal,
sys::NotifyUrgency::NotifyUrgencyCritical => Urgency::Critical,
}
}
}
impl From<Urgency> for sys::NotifyUrgency {
fn from(urgency: Urgency) -> sys::NotifyUrgency {
match urgency {
Urgency::Low => sys::NotifyUrgency::NotifyUrgencyLow,
Urgency::Normal => sys::NotifyUrgency::NotifyUrgencyNormal,
Urgency::Critical => sys::NotifyUrgency::NotifyUrgencyCritical,
macro_rules! assert_initialized_libnotify {
() => {
use functions::*;
if !is_initted() {
panic!("Notify system not initialized, invalid call of function");
}
}
}
/// Error that can happen on context creation
#[derive(Debug)]
pub enum ContextCreationError {
/// Context already exists.
AlreadyExists,
/// Failed to initialize libnotify.
InitError,
/// A nul byte was found in the provided string.
NulError(ffi::NulError),
}
impl fmt::Display for ContextCreationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use ContextCreationError::*;
match *self {
AlreadyExists => write!(f, "A Libnotify context already exists."),
InitError => write!(f, "Failed to initialize libnotify."),
NulError(ref e) => write!(f, "{}", e),
}
}
}
impl From<ffi::NulError> for ContextCreationError {
fn from(src: ffi::NulError) -> Self {
ContextCreationError::NulError(src)
}
}
#[derive(Debug)]
/// An error that can happen when attempting to create a notification.
pub enum NotificationCreationError {
/// A nul byte was found in the provided string.
NulError(ffi::NulError),
/// An unknown error happened.
Unknown,
/// Invalid parameter passed to a glib function
InvalidParameter,
}
impl fmt::Display for NotificationCreationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use NotificationCreationError::*;
match *self {
NulError(ref e) => write!(f, "{}", e),
Unknown => write!(f, "Unknown error"),
InvalidParameter => write!(f, "An invalid parameter was passed"),
}
}
}
impl From<ffi::NulError> for NotificationCreationError {
fn from(src: ffi::NulError) -> Self {
NotificationCreationError::NulError(src)
}
}
impl Error for NotificationCreationError {
fn description(&self) -> &str {
"notification creation error"
}
}
/// The context which within libnotify operates.
///
/// Only one context can exist at a time.
pub struct Context;
impl Context {
/// Create a new context
///
/// Arguments:
///
/// - app_name: The name of the application using the context
pub fn new(app_name: &str) -> Result<Context, ContextCreationError> {
unsafe {
if sys::notify_is_initted() == TRUE {
return Err(ContextCreationError::AlreadyExists);
}
let app_name = try!(CString::new(app_name));
if sys::notify_init(app_name.as_ptr()) == FALSE {
return Err(ContextCreationError::InitError);
}
}
Ok(Context)
}
/// Creates a new Notification.
///
/// Arguments:
///
/// - summary: Required summary text
/// - body: Optional body text
/// - icon: Optional icon theme icon name or filename
pub fn new_notification
(&self,
summary: &str,
body: Option<&str>,
icon: Option<&str>)
-> Result<Notification, NotificationCreationError> {
let summary = try!(CString::new(summary));
let body = match body {
Some(body) => Some(try!(CString::new(body))),
None => None,
};
let body_ptr = match body {
Some(ref body) => body.as_ptr(),
None => std::ptr::null(),
};
let icon = match icon {
Some(icon) => Some(try!(CString::new(icon))),
None => None,
};
let icon_ptr = match icon {
Some(ref icon) => icon.as_ptr(),
None => std::ptr::null(),
};
unsafe {
let n = sys::notify_notification_new(summary.as_ptr(),
body_ptr,
icon_ptr);
if n.is_null() {
return Err(NotificationCreationError::Unknown);
}
Ok(Notification {
handle: n,
_phantom: PhantomData,
})
}
}
/// Show a notification.
///
/// This is a convenience method that creates a new notification,
/// and shows it in one step.
pub fn show(&self,
summary: &str,
body: Option<&str>,
icon: Option<&str>)
-> Result<(), Box<Error>> {
let notif = try!(self.new_notification(summary, body, icon));
try!(notif.show());
Ok(())
}
}
impl Drop for Context {
fn drop(&mut self) {
unsafe {
sys::notify_uninit();
}
}
}
/// A passive pop-up notification
pub struct Notification<'a> {
handle: *mut sys::NotifyNotification,
_phantom: PhantomData<&'a Context>,
}
impl<'a> Notification<'a> {
/// Tells the notification server to display the notification
/// on the screen.
pub fn show(&'a self) -> Result<(), NotificationShowError> {
unsafe {
let mut err: *mut glib_sys::GError = std::ptr::null_mut();
sys::notify_notification_show(self.handle, &mut err);
if !err.is_null() {
let result = Err(NotificationShowError {
message: CStr::from_ptr((*err).message)
.to_string_lossy()
.into_owned(),
});
glib_sys::g_error_free(err);
return result;
}
Ok(())
}
}
/// Set the notification timeout. Note that the server might ignore
/// the timeout.
pub fn set_notification_timeout(&self, timeout: i32) {
let _timeout: c_int = From::from(timeout);
unsafe { sys::notify_notification_set_timeout(self.handle, _timeout) }
}
/// Updates the notification text and icon. This won't send the update
/// out and display it on the screen. For that, you will need to
/// call `.show()`.
pub fn update(&self,
summary: &str,
body: Option<&str>,
icon: Option<&str>)
-> Result<(), NotificationCreationError> {
let summary = try!(CString::new(summary));
let body = match body {
Some(body) => Some(try!(CString::new(body))),
None => None,
};
let body_ptr = match body {
Some(ref body) => body.as_ptr(),
None => std::ptr::null(),
};
let icon = match icon {
Some(icon) => Some(try!(CString::new(icon))),
None => None,
};
let icon_ptr = match icon {
Some(ref icon) => icon.as_ptr(),
None => std::ptr::null(),
};
unsafe {
let b = sys::notify_notification_update(self.handle,
summary.as_ptr(),
body_ptr,
icon_ptr);
if b == FALSE {
return Err(NotificationCreationError::InvalidParameter);
}
}
return Ok(());
}
/// Sets a hint for `key` with value `value`. If value is `None`,
/// then key is unset.
pub fn set_hint(&self,
key: &str,
value: Option<glib::variant::Variant>)
-> Result<(), NotificationCreationError> {
let key = try!(CString::new(key));
let gvalue: *mut glib_sys::GVariant = {
match value {
Some(ref value) => value.to_glib_none().0,
None => std::ptr::null_mut(),
}
};
unsafe {
sys::notify_notification_set_hint(self.handle, key.as_ptr(), gvalue)
}
return Ok(());
}
/// Sets the category of this notification. This can be used by the
/// notification server to filter or display the data in a certain way.
pub fn set_category(&self, category: &str) -> Result<(), NotificationCreationError> {
let category = try!(CString::new(category));
unsafe {
sys::notify_notification_set_category(self.handle,
category.as_ptr());
}
return Ok(());
}
/// Sets the urgency level of this notification.
pub fn set_urgency(&self, urgency: Urgency) {
let urgency: sys::NotifyUrgency = From::from(urgency);
unsafe {
sys::notify_notification_set_urgency(self.handle,
urgency);
}
}
/// Sets the image in the notification from a Pixbuf.
pub fn set_image_from_pixbuf(&self, pixbuf: &gdk_pixbuf::Pixbuf) {
let pixbuf: *mut GdkPixbuf = pixbuf.to_glib_none().0;
unsafe {
sys::notify_notification_set_image_from_pixbuf(self.handle,
pixbuf);
}
}
/// Clears all hints from the notification.
pub fn clear_hints(&self) {
unsafe {
sys::notify_notification_clear_hints(self.handle);
}
}
/// Synchronously tells the notification server to hide the
/// notification on the screen.
pub fn close(&self) -> Result<(), NotificationShowError> {
unsafe {
let mut err: *mut glib_sys::GError = std::ptr::null_mut();
sys::notify_notification_close(self.handle,
&mut err);
if !err.is_null() {
let result = Err(NotificationShowError {
message: CStr::from_ptr((*err).message)
.to_string_lossy()
.into_owned(),
});
glib_sys::g_error_free(err);
return result;
}
}
return Ok(());
}
}
/// An error that can happen when attempting to show a notification.
#[derive(Debug)]
pub struct NotificationShowError {
message: String,
}
impl fmt::Display for NotificationShowError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Error showing notification: {}", self.message)
}
}
impl Error for NotificationShowError {
fn description(&self) -> &str {
"notification show error"
}
}
mod enums;
mod functions;
mod notification;

251
src/notification.rs Normal file
View File

@ -0,0 +1,251 @@
use Urgency;
use ffi;
use gdk_pixbuf;
use glib::translate::*;
use glib;
use glib_ffi;
use gobject_ffi;
use std::mem;
use std::ptr;
use std;
glib_wrapper! {
/// `Notification` represents a passive pop-up notification. It can contain
/// summary text, body text, and an icon, as well as hints specifying how
/// the notification should be presented. The notification is rendered by
/// a notification daemon, and may present the notification in any number
/// of ways. As such, there is a clear separation of content and
/// presentation, and this API enforces that.
pub struct Notification(Object<ffi::NotifyNotification>);
match fn {
get_type => || ffi::notify_notification_get_type(),
}
}
impl Notification {
/// Creates a new `Notification`. The summary text is required, but
/// all other parameters are optional.
/// ## `summary`
/// The required summary text.
/// ## `body`
/// The optional body text.
/// ## `icon`
/// The optional icon theme icon name or filename.
///
/// # Returns
///
/// The new `Notification`.
pub fn new<'a, 'b, P: Into<Option<&'a str>>, Q: Into<Option<&'b str>>>(
summary: &str,
body: P,
icon: Q,
) -> Notification {
assert_initialized_libnotify!();
let body = body.into();
let body = body.to_glib_none();
let icon = icon.into();
let icon = icon.to_glib_none();
unsafe {
from_glib_full(ffi::notify_notification_new(
summary.to_glib_none().0,
body.0,
icon.0,
))
}
}
/// Synchronously tells the notification server to hide the notification on the screen.
///
/// # Returns
///
/// `Ok(())` on success, or `Err(err)` on error
pub fn close(&self) -> Result<(), glib::error::Error> {
assert_initialized_libnotify!();
unsafe {
let mut err: *mut glib_ffi::GError = std::ptr::null_mut();
ffi::notify_notification_close(self.to_glib_none().0, &mut err);
if !err.is_null() {
return Err(glib::error::Error::wrap(err));
} else {
return Ok(());
}
}
}
/// Tells the notification server to display the notification on the screen.
///
/// # Returns
///
/// `Ok(())` on success, or `Err(err)` on error
// TODO: test if Error leaks memory
pub fn show(&self) -> Result<(), glib::error::Error> {
assert_initialized_libnotify!();
unsafe {
let mut err: *mut glib_ffi::GError = std::ptr::null_mut();
ffi::notify_notification_show(self.to_glib_none().0, &mut err);
if !err.is_null() {
return Err(glib::error::Error::wrap(err));
} else {
return Ok(());
}
}
}
/// Sets a hint for `key` with value `value`. If `value` is `None`,
/// a previously set hint for `key` is unset.
///
/// If `value` is floating, it is consumed.
/// ## `key`
/// the hint key
/// ## `value`
pub fn set_hint(&self, key: &str, value: Option<glib::variant::Variant>) {
assert_initialized_libnotify!();
let gvalue: *mut glib_ffi::GVariant = {
match value {
Some(ref value) => value.to_glib_none().0,
None => std::ptr::null_mut(),
}
};
unsafe {
ffi::notify_notification_set_hint(
self.to_glib_none().0,
key.to_glib_none().0,
gvalue,
)
}
}
/// Sets the image in the notification from a `gdk_pixbuf::Pixbuf`.
/// ## `pixbuf`
/// The image.
pub fn set_image_from_pixbuf(&self, pixbuf: &gdk_pixbuf::Pixbuf) {
assert_initialized_libnotify!();
unsafe {
ffi::notify_notification_set_image_from_pixbuf(
self.to_glib_none().0,
pixbuf.to_glib_none().0,
);
}
}
/// Clears all hints from the notification.
pub fn clear_hints(&self) {
unsafe {
ffi::notify_notification_clear_hints(self.to_glib_none().0);
}
}
/// Sets the application name for the notification. If this function is
/// not called or if `app_name` is `None`, the application name will be
/// set from the value used in `notify_init` or overridden with
/// `notify_set_app_name`.
/// ## `app_name`
/// the localised application name
pub fn set_app_name<'a, P: Into<Option<&'a str>>>(&self, app_name: P) {
let app_name = app_name.into();
let app_name = app_name.to_glib_none();
unsafe {
ffi::notify_notification_set_app_name(
self.to_glib_none().0,
app_name.0,
);
}
}
/// Sets the category of this notification. This can be used by the
/// notification server to filter or display the data in a certain way.
/// ## `category`
/// The category.
pub fn set_category(&self, category: &str) {
unsafe {
ffi::notify_notification_set_category(
self.to_glib_none().0,
category.to_glib_none().0,
);
}
}
/// Sets the timeout of the notification. To set the default time, pass
/// `NOTIFY_EXPIRES_DEFAULT` as `timeout`. To set the notification to never
/// expire, pass `NOTIFY_EXPIRES_NEVER`.
///
/// Note that the timeout may be ignored by the server.
/// ## `timeout`
/// The timeout in milliseconds.
pub fn set_timeout(&self, timeout: i32) {
unsafe {
ffi::notify_notification_set_timeout(
self.to_glib_none().0,
timeout,
);
}
}
/// Sets the urgency level of this notification.
///
/// See: `Urgency`
/// ## `urgency`
/// The urgency level.
pub fn set_urgency(&self, urgency: Urgency) {
unsafe {
ffi::notify_notification_set_urgency(
self.to_glib_none().0,
urgency.to_glib(),
);
}
}
/// Updates the notification text and icon. This won't send the update out
/// and display it on the screen. For that, you will need to call
/// `Notification::show`.
/// ## `summary`
/// The new required summary text.
/// ## `body`
/// The optional body text.
/// ## `icon`
/// The optional icon theme icon name or filename.
///
/// # Returns
///
/// `Ok(())` on success, or `Err(str)` if an invalid parameter was passed
// TODO: switch back to BoolError when it hits stable glib
pub fn update<
'a,
'b,
P: Into<Option<&'a str>>,
Q: Into<Option<&'b str>>,
>(
&self,
summary: &str,
body: P,
icon: Q,
) -> Result<(), String> {
let body = body.into();
let body = body.to_glib_none();
let icon = icon.into();
let icon = icon.to_glib_none();
unsafe {
let b = ffi::notify_notification_update(
self.to_glib_none().0,
summary.to_glib_none().0,
body.0,
icon.0,
);
match b {
glib_ffi::GFALSE => Err(
String::from("Invalid parameter passed"),
),
_ => Ok(()),
}
}
}
}