17 Commits

Author SHA1 Message Date
Mika Attila
a61230b012 Update dependencies 2016-01-27 23:11:38 +01:00
Mika Attila
a74f4c9888 Add convenience method to context for showing a notification 2015-11-03 10:06:33 +01:00
Mika Attila
69a2d18218 Version bump 2015-11-03 09:19:13 +01:00
Mika Attila
c698097ffd Remove unnecessary return statement 2015-11-03 09:17:20 +01:00
Mika Attila
8daef60a03 Implement From<ffi::NulError> for error types that have this variant 2015-11-03 09:15:16 +01:00
Mika Attila
d282d2cd50 Add remaining missing documentation 2015-11-03 01:04:22 +01:00
Mika Attila
6251e0ad5c Expose ffi::NulError in nul errors 2015-11-03 01:01:49 +01:00
Mika Attila
db2578ea92 Use fmt::Result 2015-11-03 00:55:09 +01:00
Mika Attila
ba947a35f8 Rename InitFailure to InitError and add documentation 2015-11-03 00:54:03 +01:00
Mika Attila
503eee4441 Warn about missing documentation 2015-11-03 00:51:20 +01:00
Mika Attila
4b0aaab709 Update doc example 2015-11-03 00:50:27 +01:00
Mika Attila
94bb46164f Add NotificationShowError 2015-11-03 00:49:12 +01:00
Mika Attila
3dfc03aebd Format source code with rustfmt 2015-11-02 23:55:35 +01:00
Mika Attila
7bc56e4974 Let's try this again, shall we? 2015-11-01 22:07:39 +01:00
Mika Attila
d42152428f Remove some unnecessary stuff from .travis.yml 2015-11-01 22:05:12 +01:00
Mika Attila
619409ffc4 Add travis badge 2015-11-01 22:03:36 +01:00
Mika Attila
8e7b939a78 Add .travis.yml 2015-11-01 22:01:07 +01:00
5 changed files with 138 additions and 70 deletions

20
.travis.yml Normal file
View File

@@ -0,0 +1,20 @@
language: rust
rust:
- nightly
- beta
- stable
before_script:
- |
pip install 'travis-cargo<0.2' --user &&
export PATH=$HOME/.local/bin:$PATH
script:
- |
travis-cargo build &&
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=

View File

@@ -1,7 +1,7 @@
[package] [package]
name = "libnotify" name = "libnotify"
version = "0.1.0" version = "0.3.0"
authors = ["Mika Attila <radiantstatue@gmail.com>"] authors = ["Mika Attila <radiantstatue@gmail.com>"]
license = "MIT" license = "MIT"
description = "Rust bindings to libnotify" description = "Rust bindings to libnotify"
@@ -11,6 +11,6 @@ documentation = "http://crumblingstatue.github.io/doc/libnotify/libnotify/"
keywords = ["libnotify", "notification"] keywords = ["libnotify", "notification"]
[dependencies] [dependencies]
libnotify-sys = "0.2.0" libnotify-sys = "0.3"
glib-2-0-sys = "0.46.0" glib-2-0-sys = "0.46.0"
gtypes = "0.1.2" gtypes = "0.2"

View File

@@ -1,2 +1,4 @@
[![Build Status](https://travis-ci.org/crumblingstatue/rust-libnotify.svg)](https://travis-ci.org/crumblingstatue/rust-libnotify)
# libnotify-rs # libnotify-rs
Rust binding to libnotify Rust binding to libnotify

View File

@@ -1,12 +1,11 @@
extern crate libnotify; extern crate libnotify;
fn main() { fn main() {
let notify = libnotify::Context::new("hello").unwrap_or_else(|e| { // Create a libnotify context
panic!("{}", e); let notify = libnotify::Context::new("myapp").unwrap();
}); // Create a new notification and show it
let body_text = Some("This is the optional body text."); let n = notify.new_notification("Summary", Some("Optional Body"), None).unwrap();
let n = notify.new_notification("This is the summary.", n.show().unwrap();
body_text, // You can also use the .show() convenience method on the context
None).unwrap_or_else(|e| panic!("{}", e)); notify.show("I am another notification", None, None).unwrap();
n.show().ok().expect("Failed to show notification");
} }

View File

@@ -4,68 +4,91 @@
//! extern crate libnotify; //! extern crate libnotify;
//! //!
//! fn main() { //! fn main() {
//! let notify = libnotify::Context::new("hello").unwrap_or_else(|e| { //! // Create a libnotify context
//! panic!("{}", e); //! let notify = libnotify::Context::new("myapp").unwrap();
//! }); //! // Create a new notification and show it
//! let body_text = Some("This is the optional body text."); //! let n = notify.new_notification("Summary",
//! let n = notify.new_notification("This is the summary.", //! Some("Optional Body"),
//! body_text, //! None).unwrap();
//! None).unwrap_or_else(|e| { //! n.show().unwrap();
//! panic!("{}", e); //! // You can also use the .show() convenience method on the context
//! }); //! notify.show("I am another notification", None, None).unwrap();
//! n.show().ok().expect("Failed to show notification");
//! } //! }
//!
//! ``` //! ```
#![warn(missing_docs)]
extern crate libnotify_sys as sys; extern crate libnotify_sys as sys;
extern crate glib_2_0_sys as glib; extern crate glib_2_0_sys as glib;
extern crate gtypes; extern crate gtypes;
use std::ffi::CString; use std::ffi::{self, CStr, CString};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::fmt; use std::fmt;
use std::error::Error;
use gtypes::{ use gtypes::{TRUE, FALSE};
TRUE,
FALSE
};
/// Error that can happen on context creation /// Error that can happen on context creation
#[derive(Debug)] #[derive(Debug)]
pub enum ContextCreationError { pub enum ContextCreationError {
/// Context already exists /// Context already exists.
AlreadyExists, AlreadyExists,
InitFailure, /// Failed to initialize libnotify.
NulError InitError,
/// A nul byte was found in the provided string.
NulError(ffi::NulError),
} }
impl fmt::Display for ContextCreationError { impl fmt::Display for ContextCreationError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use ContextCreationError::*; use ContextCreationError::*;
match *self { match *self {
AlreadyExists => write!(f, "A Libnotify context already exists."), AlreadyExists => write!(f, "A Libnotify context already exists."),
InitFailure => write!(f, "Failed to initialize libnotify."), InitError => write!(f, "Failed to initialize libnotify."),
NulError => write!(f, "Argument contains a nul character.") NulError(ref e) => write!(f, "{}", e),
} }
} }
} }
impl From<ffi::NulError> for ContextCreationError {
fn from(src: ffi::NulError) -> Self {
ContextCreationError::NulError(src)
}
}
#[derive(Debug)] #[derive(Debug)]
/// An error that can happen when attempting to create a notification.
pub enum NotificationCreationError { pub enum NotificationCreationError {
NulError, /// A nul byte was found in the provided string.
Unknown NulError(ffi::NulError),
/// An unknown error happened.
Unknown,
} }
impl fmt::Display for NotificationCreationError { impl fmt::Display for NotificationCreationError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use NotificationCreationError::*; use NotificationCreationError::*;
match *self { match *self {
NulError => write!(f, "Argument contains a nul character."), NulError(ref e) => write!(f, "{}", e),
Unknown => write!(f, "Unknown error") Unknown => write!(f, "Unknown error"),
} }
} }
} }
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. /// The context which within libnotify operates.
/// ///
/// Only one context can exist at a time. /// Only one context can exist at a time.
@@ -82,12 +105,9 @@ impl Context {
if sys::notify_is_initted() == TRUE { if sys::notify_is_initted() == TRUE {
return Err(ContextCreationError::AlreadyExists); return Err(ContextCreationError::AlreadyExists);
} }
let app_name = match CString::new(app_name) { let app_name = try!(CString::new(app_name));
Ok(name) => name,
Err(_) => return Err(ContextCreationError::NulError)
};
if sys::notify_init(app_name.as_ptr()) == FALSE { if sys::notify_init(app_name.as_ptr()) == FALSE {
return Err(ContextCreationError::InitFailure); return Err(ContextCreationError::InitError);
} }
} }
Ok(Context) Ok(Context)
@@ -99,47 +119,53 @@ impl Context {
/// - summary: Required summary text /// - summary: Required summary text
/// - body: Optional body text /// - body: Optional body text
/// - icon: Optional icon theme icon name or filename /// - icon: Optional icon theme icon name or filename
pub fn new_notification(&self, summary: &str, pub fn new_notification(&self,
body: Option<&str>, summary: &str,
icon: Option<&str>) body: Option<&str>,
-> Result<Notification, NotificationCreationError> { icon: Option<&str>)
let summary = match CString::new(summary) { -> Result<Notification, NotificationCreationError> {
Ok(cstr) => cstr, let summary = try!(CString::new(summary));
Err(_) => return Err(NotificationCreationError::NulError)
};
let body = match body { let body = match body {
Some(body) => match CString::new(body) { Some(body) => Some(try!(CString::new(body))),
Ok(cstr) => Some(cstr), None => None,
Err(_) => return Err(NotificationCreationError::NulError)
},
None => None
}; };
let body_ptr = match body { let body_ptr = match body {
Some(body) => body.as_ptr(), Some(body) => body.as_ptr(),
None => std::ptr::null() None => std::ptr::null(),
}; };
let icon = match icon { let icon = match icon {
Some(icon) => match CString::new(icon) { Some(icon) => Some(try!(CString::new(icon))),
Ok(cstr) => Some(cstr), None => None,
Err(_) => return Err(NotificationCreationError::NulError)
},
None => None
}; };
let icon_ptr = match icon { let icon_ptr = match icon {
Some(icon) => icon.as_ptr(), Some(icon) => icon.as_ptr(),
None => std::ptr::null() None => std::ptr::null(),
}; };
unsafe { unsafe {
let n = sys::notify_notification_new(summary.as_ptr(), let n = sys::notify_notification_new(summary.as_ptr(), body_ptr, icon_ptr);
body_ptr,
icon_ptr);
if n.is_null() { if n.is_null() {
return Err(NotificationCreationError::Unknown); return Err(NotificationCreationError::Unknown);
} }
Ok(Notification{handle: n, _phantom: PhantomData}) 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 { impl Drop for Context {
@@ -153,21 +179,42 @@ impl Drop for Context {
/// A passive pop-up notification /// A passive pop-up notification
pub struct Notification<'a> { pub struct Notification<'a> {
handle: *mut sys::NotifyNotification, handle: *mut sys::NotifyNotification,
_phantom: PhantomData<&'a Context> _phantom: PhantomData<&'a Context>,
} }
impl<'a> Notification<'a> { impl<'a> Notification<'a> {
/// Tells the notification server to display the notification /// Tells the notification server to display the notification
/// on the screen. /// on the screen.
pub fn show(&'a self) -> Result<(), ()> { pub fn show(&'a self) -> Result<(), NotificationShowError> {
unsafe { unsafe {
let mut err: *mut glib::GError = std::ptr::null_mut(); let mut err: *mut glib::GError = std::ptr::null_mut();
sys::notify_notification_show(self.handle, &mut err); sys::notify_notification_show(self.handle, &mut err);
if !err.is_null() { if !err.is_null() {
let result = Err(NotificationShowError {
message: CStr::from_ptr((*err).message).to_string_lossy().into_owned(),
});
glib::g_error_free(err); glib::g_error_free(err);
return Err(()) return result;
} }
return Ok(()) 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"
}
}