2017-06-29 12:55:07 +00:00
|
|
|
use app_state::*;
|
2017-06-30 23:56:32 +00:00
|
|
|
use gdk;
|
2017-07-03 07:21:51 +00:00
|
|
|
use gdk_pixbuf;
|
2017-06-30 23:56:32 +00:00
|
|
|
use gdk_sys;
|
|
|
|
use glib;
|
|
|
|
use glib_sys;
|
2017-07-03 21:38:39 +00:00
|
|
|
use gtk;
|
2017-06-30 23:56:32 +00:00
|
|
|
use std::mem;
|
2017-06-29 12:55:07 +00:00
|
|
|
use gtk::prelude::*;
|
2017-06-30 15:24:26 +00:00
|
|
|
use std::rc::Rc;
|
2017-06-30 23:56:32 +00:00
|
|
|
use std::cell::RefCell;
|
|
|
|
use libc;
|
2017-07-03 21:38:39 +00:00
|
|
|
use audio::*;
|
2017-06-30 23:56:32 +00:00
|
|
|
use errors::*;
|
2017-07-03 21:38:39 +00:00
|
|
|
use std::path;
|
2017-06-29 12:55:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2017-07-03 21:38:39 +00:00
|
|
|
const ICON_MIN_SIZE: i32 = 16;
|
|
|
|
|
|
|
|
|
2017-07-03 07:21:51 +00:00
|
|
|
// struct VolMeter {
|
2017-07-03 21:38:39 +00:00
|
|
|
// pub red: u8,
|
|
|
|
// pub green: u8,
|
|
|
|
// pub blue: u8,
|
|
|
|
// pub x_offset_pct: i64,
|
|
|
|
// pub y_offset_pct: i64,
|
|
|
|
// /* dynamic */
|
|
|
|
// pub pixbuf: gdk_pixbuf::Pixbuf,
|
|
|
|
// pub width: i64,
|
|
|
|
// pub row: u8,
|
2017-07-03 07:21:51 +00:00
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// impl VolMeter {
|
2017-07-03 21:38:39 +00:00
|
|
|
// pub fn new() -> VolMeter {
|
|
|
|
// let pixbux = Pixbuf::new();
|
|
|
|
// return VolMeter {
|
|
|
|
// red: 255,
|
|
|
|
// green: 255,
|
|
|
|
// blue: 255,
|
|
|
|
// x_offset_pct: 0,
|
|
|
|
// y_offset_pct: 0,
|
|
|
|
// pixbuf: ,
|
|
|
|
// width: ,
|
|
|
|
// row: ,
|
|
|
|
// }
|
2017-07-03 07:21:51 +00:00
|
|
|
// }
|
2017-07-03 21:38:39 +00:00
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: connect on icon theme change
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
struct AudioPix {
|
|
|
|
muted: gdk_pixbuf::Pixbuf,
|
|
|
|
low: gdk_pixbuf::Pixbuf,
|
|
|
|
medium: gdk_pixbuf::Pixbuf,
|
|
|
|
high: gdk_pixbuf::Pixbuf,
|
|
|
|
off: gdk_pixbuf::Pixbuf,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl AudioPix {
|
|
|
|
pub fn new(size: i32) -> Result<AudioPix> {
|
|
|
|
let theme: gtk::IconTheme =
|
|
|
|
gtk::IconTheme::get_default().ok_or("Couldn't get default icon theme")?;
|
|
|
|
let pix = AudioPix {
|
|
|
|
muted: pixbuf_new_from_theme("audio-volume-muted", size, &theme)?,
|
|
|
|
low: pixbuf_new_from_theme("audio-volume-low", size, &theme)?,
|
|
|
|
medium: pixbuf_new_from_theme("audio-volume-medium", size, &theme)?,
|
|
|
|
high: pixbuf_new_from_theme("audio-volume-high", size, &theme)?,
|
|
|
|
/* 'audio-volume-off' is not available in every icon set.
|
|
|
|
* Check freedesktop standard for more info:
|
|
|
|
* http://standards.freedesktop.org/icon-naming-spec/
|
|
|
|
* icon-naming-spec-latest.html
|
|
|
|
*/
|
|
|
|
off: pixbuf_new_from_theme("audio-volume-off", size, &theme).or(pixbuf_new_from_theme("audio-volume-low", size, &theme))?,
|
|
|
|
};
|
|
|
|
|
|
|
|
return Ok(pix);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn select_pix(&self, vol_level: VolLevel) -> &gdk_pixbuf::Pixbuf {
|
|
|
|
match vol_level {
|
|
|
|
VolLevel::Muted => &self.muted,
|
|
|
|
VolLevel::Low => &self.low,
|
|
|
|
VolLevel::Medium => &self.medium,
|
|
|
|
VolLevel::High => &self.high,
|
|
|
|
VolLevel::Off => &self.off,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-03 07:21:51 +00:00
|
|
|
|
2017-07-03 21:38:39 +00:00
|
|
|
fn pixbuf_new_from_theme(icon_name: &str,
|
|
|
|
size: i32,
|
|
|
|
theme: >k::IconTheme)
|
|
|
|
-> Result<gdk_pixbuf::Pixbuf> {
|
2017-07-03 07:21:51 +00:00
|
|
|
|
2017-07-03 21:38:39 +00:00
|
|
|
let icon_info =
|
|
|
|
theme.lookup_icon(icon_name, size, gtk::IconLookupFlags::empty())
|
|
|
|
.ok_or(format!("Couldn't find icon {}", icon_name))?;
|
2017-07-03 07:21:51 +00:00
|
|
|
|
2017-07-03 21:38:39 +00:00
|
|
|
debug!("Loading stock icon {} from {:?}",
|
|
|
|
icon_name,
|
|
|
|
icon_info.get_filename().unwrap_or(path::PathBuf::new()));
|
|
|
|
|
|
|
|
// TODO: propagate error
|
|
|
|
let pixbuf = icon_info.load_icon().unwrap();
|
|
|
|
|
|
|
|
return Ok(pixbuf);
|
2017-07-03 07:21:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-03 21:38:39 +00:00
|
|
|
fn update_tray_icon(audio_pix: &AudioPix, appstate: &AppS) {
|
|
|
|
debug!("Update tray icon");
|
|
|
|
let status_icon = &appstate.gui.status_icon;
|
|
|
|
let pixbuf = audio_pix.select_pix(appstate.audio.vol_level());
|
|
|
|
debug!("VolLevel: {:?}", appstate.audio.vol_level());
|
|
|
|
status_icon.set_from_pixbuf(Some(pixbuf));
|
|
|
|
}
|
|
|
|
|
2017-07-03 07:21:51 +00:00
|
|
|
|
2017-06-30 15:24:26 +00:00
|
|
|
pub fn init_tray_icon(appstate: Rc<AppS>) {
|
2017-07-03 21:38:39 +00:00
|
|
|
let audio_pix = Rc::new(RefCell::new(try_w!(AudioPix::new(ICON_MIN_SIZE))));
|
|
|
|
update_tray_icon(&audio_pix.borrow(), &appstate);
|
|
|
|
|
|
|
|
/* connect audio handler */
|
|
|
|
{
|
|
|
|
let _audio_pix = audio_pix.clone();
|
|
|
|
let apps = appstate.clone();
|
|
|
|
appstate.audio.connect_handler(Box::new(move |s, u| {
|
|
|
|
match (s, u) {
|
|
|
|
(AudioSignal::ValuesChanged, _) => {
|
|
|
|
debug!("tray icon handler: {:?} {:?}", s, u);
|
|
|
|
update_tray_icon(&_audio_pix.borrow(), &apps);
|
|
|
|
},
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* tray_icon.connect_size_changed */
|
|
|
|
{
|
|
|
|
let apps = appstate.clone();
|
|
|
|
let tray_icon = &appstate.gui.status_icon;
|
|
|
|
let _audio_pix = audio_pix.clone();
|
|
|
|
tray_icon.connect_size_changed(move |_, size| on_tray_icon_size_changed(&apps, _audio_pix.as_ref(), size));
|
|
|
|
tray_icon.set_visible(true);
|
|
|
|
}
|
|
|
|
|
2017-07-01 14:55:35 +00:00
|
|
|
/* tray_icon.connect_activate */
|
2017-06-30 23:56:32 +00:00
|
|
|
{
|
|
|
|
let apps = appstate.clone();
|
|
|
|
let tray_icon = &appstate.gui.status_icon;
|
|
|
|
tray_icon.connect_activate(move |_| on_tray_icon_activate(&apps));
|
|
|
|
tray_icon.set_visible(true);
|
|
|
|
}
|
2017-07-01 14:55:35 +00:00
|
|
|
|
|
|
|
/* tray_icon.connect_scroll_event */
|
2017-06-30 23:56:32 +00:00
|
|
|
{
|
2017-07-01 14:55:35 +00:00
|
|
|
let apps = appstate.clone();
|
2017-06-30 23:56:32 +00:00
|
|
|
let tray_icon = &appstate.clone().gui.status_icon;
|
|
|
|
tray_icon.connect_scroll_event(move |_, e| {
|
2017-07-01 14:55:35 +00:00
|
|
|
on_tray_icon_scroll_event(&apps, &e)
|
|
|
|
});
|
2017-06-30 23:56:32 +00:00
|
|
|
}
|
2017-06-29 12:55:07 +00:00
|
|
|
|
2017-07-01 14:55:35 +00:00
|
|
|
/* tray_icon.connect_popup_menu */
|
|
|
|
{
|
|
|
|
let apps = appstate.clone();
|
|
|
|
let tray_icon = &appstate.clone().gui.status_icon;
|
|
|
|
tray_icon.connect_popup_menu(move |_, _, _| {
|
|
|
|
on_tray_icon_popup_menu(&apps)
|
|
|
|
});
|
|
|
|
}
|
2017-06-30 15:24:26 +00:00
|
|
|
}
|
2017-06-29 12:55:07 +00:00
|
|
|
|
|
|
|
|
2017-06-30 15:24:26 +00:00
|
|
|
fn on_tray_icon_activate(appstate: &AppS) {
|
2017-07-01 14:55:35 +00:00
|
|
|
let popup_window = &appstate.gui.popup_window.popup_window;
|
2017-06-30 15:24:26 +00:00
|
|
|
|
|
|
|
if popup_window.get_visible() {
|
|
|
|
popup_window.hide();
|
|
|
|
} else {
|
|
|
|
popup_window.show_now();
|
|
|
|
}
|
2017-06-29 12:55:07 +00:00
|
|
|
}
|
2017-06-30 23:56:32 +00:00
|
|
|
|
|
|
|
|
2017-07-01 14:55:35 +00:00
|
|
|
fn on_tray_icon_popup_menu(appstate: &AppS) {
|
|
|
|
let popup_window = &appstate.gui.popup_window.popup_window;
|
|
|
|
let popup_menu = &appstate.gui.popup_menu.menu;
|
|
|
|
|
|
|
|
popup_window.hide();
|
|
|
|
popup_menu.popup_at_pointer(None);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-06-30 23:56:32 +00:00
|
|
|
fn on_tray_icon_scroll_event(appstate: &AppS,
|
|
|
|
event: &gdk::EventScroll)
|
|
|
|
-> bool {
|
|
|
|
|
2017-07-01 22:03:21 +00:00
|
|
|
let audio = &appstate.audio;
|
|
|
|
|
2017-07-01 14:55:35 +00:00
|
|
|
let scroll_dir: gdk::ScrollDirection = event.get_direction();
|
2017-06-30 23:56:32 +00:00
|
|
|
match scroll_dir {
|
2017-07-01 14:55:35 +00:00
|
|
|
gdk::ScrollDirection::Up => {
|
2017-07-03 21:38:39 +00:00
|
|
|
try_wr!(appstate.audio.increase_vol(AudioUser::TrayIcon), false);
|
2017-06-30 23:56:32 +00:00
|
|
|
}
|
2017-07-01 14:55:35 +00:00
|
|
|
gdk::ScrollDirection::Down => {
|
2017-07-03 21:38:39 +00:00
|
|
|
try_wr!(appstate.audio.decrease_vol(AudioUser::TrayIcon), false);
|
2017-06-30 23:56:32 +00:00
|
|
|
}
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2017-07-03 21:38:39 +00:00
|
|
|
|
|
|
|
|
|
|
|
fn on_tray_icon_size_changed(appstate: &AppS,
|
|
|
|
audio_pix: &RefCell<AudioPix>,
|
|
|
|
size: i32)
|
|
|
|
-> bool {
|
|
|
|
debug!("Tray icon size is now {}", size);
|
|
|
|
|
|
|
|
let mut size = size;
|
|
|
|
if size < ICON_MIN_SIZE {
|
|
|
|
size = ICON_MIN_SIZE;
|
|
|
|
debug!("Forcing size to the minimum value {}", size);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
let mut pix = audio_pix.borrow_mut();
|
|
|
|
*pix = try_wr!(AudioPix::new(size), false);
|
|
|
|
}
|
|
|
|
|
|
|
|
update_tray_icon(&audio_pix.borrow(), &appstate);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|