2017-07-14 15:23:42 +00:00
//! The notification subsystem.
//!
//! This subsystem utilizes libnotify to send notifications as popups
//! to the desktop.
2017-06-26 07:08:37 +00:00
use app_state ::* ;
2017-07-19 10:12:08 +00:00
use audio ::frontend ::* ;
2017-06-26 07:08:37 +00:00
use errors ::* ;
use glib ::prelude ::* ;
use libnotify ;
use prefs ::* ;
use std ::cell ::Cell ;
use std ::rc ::Rc ;
2017-07-14 15:23:42 +00:00
/// An expression of our notification system. Holds all the relevant information
/// needed by Gtk+ callbacks to interact with libnotify.
2017-06-26 07:08:37 +00:00
pub struct Notif {
enabled : Cell < bool > ,
from_popup : Cell < bool > ,
from_tray : Cell < bool > ,
2017-07-13 22:27:46 +00:00
from_hotkeys : Cell < bool > ,
2017-06-26 07:08:37 +00:00
from_external : Cell < bool > ,
volume_notif : libnotify ::Notification ,
text_notif : libnotify ::Notification ,
}
impl Notif {
2017-07-14 15:23:42 +00:00
/// Create a new notification instance from the current preferences.
2017-07-13 22:27:46 +00:00
/// This should only be done once at startup. This also initializes
/// the libnotify system.
2017-06-26 07:08:37 +00:00
pub fn new ( prefs : & Prefs ) -> Result < Self > {
2017-07-13 22:27:46 +00:00
libnotify ::init ( " PNMixer-rs " ) ? ;
2017-06-26 07:08:37 +00:00
let notif = Notif {
enabled : Cell ::new ( false ) ,
from_popup : Cell ::new ( false ) ,
from_tray : Cell ::new ( false ) ,
2017-07-13 22:27:46 +00:00
from_hotkeys : Cell ::new ( false ) ,
2017-06-26 07:08:37 +00:00
from_external : Cell ::new ( false ) ,
volume_notif : libnotify ::Notification ::new ( " " , None , None ) ,
text_notif : libnotify ::Notification ::new ( " " , None , None ) ,
} ;
2017-07-13 22:27:46 +00:00
notif . reload ( prefs ) ;
2017-06-26 07:08:37 +00:00
return Ok ( notif ) ;
}
2017-07-14 15:23:42 +00:00
/// Reload the notification instance from the current
/// preferences.
2017-07-13 22:27:46 +00:00
pub fn reload ( & self , prefs : & Prefs ) {
2017-06-26 07:08:37 +00:00
let timeout = prefs . notify_prefs . notifcation_timeout ;
self . enabled . set ( prefs . notify_prefs . enable_notifications ) ;
self . from_popup . set ( prefs . notify_prefs . notify_popup ) ;
self . from_tray . set ( prefs . notify_prefs . notify_mouse_scroll ) ;
2017-07-13 22:27:46 +00:00
self . from_hotkeys . set ( prefs . notify_prefs . notify_hotkeys ) ;
2017-06-26 07:08:37 +00:00
self . from_external . set ( prefs . notify_prefs . notify_external ) ;
self . volume_notif . set_timeout ( timeout as i32 ) ;
2017-07-19 10:12:08 +00:00
self . volume_notif . set_hint (
" x-canonical-private-synchronous " ,
Some ( " " . to_variant ( ) ) ,
) ;
2017-06-26 07:08:37 +00:00
self . text_notif . set_timeout ( timeout as i32 ) ;
2017-07-19 10:12:08 +00:00
self . text_notif . set_hint (
" x-canonical-private-synchronous " ,
Some ( " " . to_variant ( ) ) ,
) ;
2017-06-26 07:08:37 +00:00
}
2017-07-14 15:23:42 +00:00
/// Shows a volume notification, e.g. for volume or mute state change.
2017-07-18 15:20:17 +00:00
pub fn show_volume_notif < T > ( & self , audio : & T ) -> Result < ( ) >
2017-07-19 10:12:08 +00:00
where
T : AudioFrontend ,
2017-07-18 15:20:17 +00:00
{
let vol = audio . get_vol ( ) ? ;
2017-06-26 07:08:37 +00:00
let vol_level = audio . vol_level ( ) ;
let icon = {
match vol_level {
VolLevel ::Muted = > " audio-volume-muted " ,
VolLevel ::Off = > " audio-volume-off " ,
VolLevel ::Low = > " audio-volume-low " ,
VolLevel ::Medium = > " audio-volume-medium " ,
VolLevel ::High = > " audio-volume-high " ,
}
} ;
let summary = {
match vol_level {
VolLevel ::Muted = > String ::from ( " Volume muted " ) ,
_ = > {
2017-07-19 10:12:08 +00:00
format! (
" {} ({}) \n Volume: {} " ,
audio . card_name ( ) ? ,
audio . chan_name ( ) ? ,
vol as i32
)
2017-06-26 07:08:37 +00:00
}
}
} ;
2017-07-19 10:12:08 +00:00
self . volume_notif
2017-07-22 14:24:32 +00:00
. update ( summary . as_str ( ) , None , Some ( icon ) ) ? ;
2017-07-19 10:12:08 +00:00
self . volume_notif . set_hint (
" value " ,
Some ( ( vol as i32 ) . to_variant ( ) ) ,
) ;
2017-07-22 14:24:32 +00:00
self . volume_notif . show ( ) ? ;
2017-06-26 07:08:37 +00:00
return Ok ( ( ) ) ;
}
2017-07-14 15:23:42 +00:00
/// Shows a text notification, e.g. for warnings or errors.
2017-06-26 07:08:37 +00:00
pub fn show_text_notif ( & self , summary : & str , body : & str ) -> Result < ( ) > {
2017-07-22 14:24:32 +00:00
self . text_notif . update ( summary , Some ( body ) , None ) ? ;
self . text_notif . show ( ) ? ;
2017-06-26 07:08:37 +00:00
return Ok ( ( ) ) ;
}
}
2017-07-13 22:27:46 +00:00
impl Drop for Notif {
fn drop ( & mut self ) {
libnotify ::uninit ( ) ;
}
}
2017-06-26 07:08:37 +00:00
2017-07-14 15:23:42 +00:00
/// Initialize the notification subsystem.
2017-07-18 15:20:17 +00:00
pub fn init_notify < T > ( appstate : Rc < AppS < T > > )
2017-07-19 10:12:08 +00:00
where
T : AudioFrontend + 'static ,
2017-07-18 15:20:17 +00:00
{
2017-06-26 07:08:37 +00:00
{
/* connect handler */
let apps = appstate . clone ( ) ;
appstate . audio . connect_handler ( Box ::new ( move | s , u | {
let notif = & apps . notif ;
2017-07-13 22:27:46 +00:00
if notif . is_none ( ) | | ! notif . as_ref ( ) . unwrap ( ) . enabled . get ( ) {
2017-06-26 07:08:37 +00:00
return ;
}
2017-07-13 22:27:46 +00:00
let notif = notif . as_ref ( ) . unwrap ( ) ;
2017-06-26 07:08:37 +00:00
match ( s ,
u ,
( notif . from_popup . get ( ) ,
notif . from_tray . get ( ) ,
2017-07-13 22:27:46 +00:00
notif . from_external . get ( ) ,
notif . from_hotkeys . get ( ) ) ) {
2017-06-26 07:08:37 +00:00
( AudioSignal ::NoCard , _ , _ ) = > try_w! ( notif . show_text_notif ( " No sound card " , " No playable soundcard found " ) ) ,
( AudioSignal ::CardDisconnected , _ , _ ) = > try_w! ( notif . show_text_notif ( " Soundcard disconnected " , " Soundcard has been disconnected, reloading sound system... " ) ) ,
( AudioSignal ::CardError , _ , _ ) = > ( ) ,
( AudioSignal ::ValuesChanged ,
AudioUser ::TrayIcon ,
2017-07-18 15:20:17 +00:00
( _ , true , _ , _ ) ) = > try_w! ( notif . show_volume_notif ( apps . audio . as_ref ( ) ) ) ,
2017-06-26 07:08:37 +00:00
( AudioSignal ::ValuesChanged ,
AudioUser ::Popup ,
2017-07-18 15:20:17 +00:00
( true , _ , _ , _ ) ) = > try_w! ( notif . show_volume_notif ( apps . audio . as_ref ( ) ) ) ,
2017-06-26 07:08:37 +00:00
( AudioSignal ::ValuesChanged ,
AudioUser ::Unknown ,
2017-07-18 15:20:17 +00:00
( _ , _ , true , _ ) ) = > try_w! ( notif . show_volume_notif ( apps . audio . as_ref ( ) ) ) ,
2017-07-13 22:27:46 +00:00
( AudioSignal ::ValuesChanged ,
AudioUser ::Hotkeys ,
2017-07-18 15:20:17 +00:00
( _ , _ , _ , true ) ) = > try_w! ( notif . show_volume_notif ( apps . audio . as_ref ( ) ) ) ,
2017-06-26 07:08:37 +00:00
_ = > ( ) ,
}
} ) ) ;
}
}