Update
This commit is contained in:
parent
973e6a0257
commit
e70e88690b
@ -1,6 +1,8 @@
|
|||||||
use gtk;
|
|
||||||
use audio::Audio;
|
use audio::Audio;
|
||||||
|
use gtk;
|
||||||
|
use prefs::Prefs;
|
||||||
use ui_tray_icon::TrayIcon;
|
use ui_tray_icon::TrayIcon;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -10,6 +12,7 @@ use ui_tray_icon::TrayIcon;
|
|||||||
pub struct AppS {
|
pub struct AppS {
|
||||||
pub gui: Gui,
|
pub gui: Gui,
|
||||||
pub audio: Audio,
|
pub audio: Audio,
|
||||||
|
pub prefs: RefCell<Prefs>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -18,11 +21,15 @@ impl AppS {
|
|||||||
let builder_popup_window =
|
let builder_popup_window =
|
||||||
gtk::Builder::new_from_string(include_str!("../data/ui/popup-window.glade"));
|
gtk::Builder::new_from_string(include_str!("../data/ui/popup-window.glade"));
|
||||||
let builder_popup_menu = gtk::Builder::new_from_string(include_str!("../data/ui/popup-menu.glade"));
|
let builder_popup_menu = gtk::Builder::new_from_string(include_str!("../data/ui/popup-menu.glade"));
|
||||||
|
let prefs = RefCell::new(Prefs::new().unwrap());
|
||||||
|
let gui =
|
||||||
|
Gui::new(builder_popup_window, builder_popup_menu, &prefs.borrow());
|
||||||
|
|
||||||
return AppS {
|
return AppS {
|
||||||
gui: Gui::new(builder_popup_window, builder_popup_menu),
|
gui: gui,
|
||||||
audio: Audio::new(None, Some(String::from("Master")))
|
audio: Audio::new(None, Some(String::from("Master")))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
prefs: prefs,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,10 +45,11 @@ pub struct Gui {
|
|||||||
|
|
||||||
impl Gui {
|
impl Gui {
|
||||||
pub fn new(builder_popup_window: gtk::Builder,
|
pub fn new(builder_popup_window: gtk::Builder,
|
||||||
builder_popup_menu: gtk::Builder)
|
builder_popup_menu: gtk::Builder,
|
||||||
|
prefs: &Prefs)
|
||||||
-> Gui {
|
-> Gui {
|
||||||
return Gui {
|
return Gui {
|
||||||
tray_icon: TrayIcon::new().unwrap(),
|
tray_icon: TrayIcon::new(prefs).unwrap(),
|
||||||
popup_window: PopupWindow::new(builder_popup_window),
|
popup_window: PopupWindow::new(builder_popup_window),
|
||||||
popup_menu: PopupMenu::new(builder_popup_menu),
|
popup_menu: PopupMenu::new(builder_popup_menu),
|
||||||
};
|
};
|
||||||
|
@ -89,24 +89,24 @@ macro_rules! try_er {
|
|||||||
($expr:expr, $ret:expr) => (match $expr {
|
($expr:expr, $ret:expr) => (match $expr {
|
||||||
::std::result::Result::Ok(val) => val,
|
::std::result::Result::Ok(val) => val,
|
||||||
::std::result::Result::Err(err) => {
|
::std::result::Result::Err(err) => {
|
||||||
err!("{:?}", err);
|
error!("{:?}", err);
|
||||||
return $ret;
|
::std::process::exit(1);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
($expr:expr, $ret:expr, $fmt:expr) => (match $expr {
|
($expr:expr, $ret:expr, $fmt:expr) => (match $expr {
|
||||||
::std::result::Result::Ok(val) => val,
|
::std::result::Result::Ok(val) => val,
|
||||||
::std::result::Result::Err(err) => {
|
::std::result::Result::Err(err) => {
|
||||||
err!("Original error: {:?}", err);
|
error!("Original error: {:?}", err);
|
||||||
err!($fmt);
|
error!($fmt);
|
||||||
return $ret;
|
std::process::exit(1);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
($expr:expr, $ret:expr, $fmt:expr, $($arg:tt)+) => (match $expr {
|
($expr:expr, $ret:expr, $fmt:expr, $($arg:tt)+) => (match $expr {
|
||||||
::std::result::Result::Ok(val) => val,
|
::std::result::Result::Ok(val) => val,
|
||||||
::std::result::Result::Err(err) => {
|
::std::result::Result::Err(err) => {
|
||||||
err!("Original error: {:?}", err);
|
error!("Original error: {:?}", err);
|
||||||
err!(format!($fmt, $(arg)+));
|
error!(format!($fmt, $(arg)+));
|
||||||
return $ret;
|
std::process::exit(1);
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,6 @@ mod support_ui;
|
|||||||
mod support_alsa;
|
mod support_alsa;
|
||||||
|
|
||||||
use app_state::*;
|
use app_state::*;
|
||||||
use prefs::*;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -65,12 +64,6 @@ fn main() {
|
|||||||
|
|
||||||
let apps = Rc::new(AppS::new());
|
let apps = Rc::new(AppS::new());
|
||||||
|
|
||||||
let mut prefs = prefs::Prefs::new().unwrap();
|
|
||||||
println!("Channel: {}", prefs.to_str());
|
|
||||||
prefs.store_config();
|
|
||||||
|
|
||||||
println!("Control_cmd: {:?}", prefs.get_avail_vol_control_cmd());
|
|
||||||
|
|
||||||
ui_entry::init(apps);
|
ui_entry::init(apps);
|
||||||
|
|
||||||
gtk::main();
|
gtk::main();
|
||||||
|
10
src/prefs.rs
10
src/prefs.rs
@ -36,7 +36,7 @@ impl Default for MiddleClickAction {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct DevicePrefs {
|
pub struct DevicePrefs {
|
||||||
pub card: String,
|
pub card: String,
|
||||||
pub channel: String,
|
pub channel: String,
|
||||||
// TODO: normalize volume?
|
// TODO: normalize volume?
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ pub struct ViewPrefs {
|
|||||||
pub draw_vol_meter: bool,
|
pub draw_vol_meter: bool,
|
||||||
pub vol_meter_offset: i64,
|
pub vol_meter_offset: i64,
|
||||||
pub system_theme: bool,
|
pub system_theme: bool,
|
||||||
pub vol_meter_color: VolColor,
|
pub vol_meter_color: VolColor,
|
||||||
// TODO: Display text folume/text volume pos?
|
// TODO: Display text folume/text volume pos?
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ impl Default for VolColor {
|
|||||||
pub struct BehaviorPrefs {
|
pub struct BehaviorPrefs {
|
||||||
pub vol_control_cmd: Option<String>,
|
pub vol_control_cmd: Option<String>,
|
||||||
pub vol_scroll_step: f64,
|
pub vol_scroll_step: f64,
|
||||||
pub middle_click_action: MiddleClickAction,
|
pub middle_click_action: MiddleClickAction,
|
||||||
// TODO: fine scroll step?
|
// TODO: fine scroll step?
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +118,7 @@ pub struct NotifyPrefs {
|
|||||||
pub notifcation_timeout: i64,
|
pub notifcation_timeout: i64,
|
||||||
pub notify_mouse_scroll: bool,
|
pub notify_mouse_scroll: bool,
|
||||||
pub notify_popup: bool,
|
pub notify_popup: bool,
|
||||||
pub notify_external: bool,
|
pub notify_external: bool,
|
||||||
// TODO: notify_hotkeys?
|
// TODO: notify_hotkeys?
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +141,7 @@ pub struct Prefs {
|
|||||||
pub device_prefs: DevicePrefs,
|
pub device_prefs: DevicePrefs,
|
||||||
pub view_prefs: ViewPrefs,
|
pub view_prefs: ViewPrefs,
|
||||||
pub behavior_prefs: BehaviorPrefs,
|
pub behavior_prefs: BehaviorPrefs,
|
||||||
pub notify_prefs: NotifyPrefs,
|
pub notify_prefs: NotifyPrefs,
|
||||||
// TODO: HotKeys?
|
// TODO: HotKeys?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ use gdk_pixbuf;
|
|||||||
use gdk_pixbuf_sys::GDK_COLORSPACE_RGB;
|
use gdk_pixbuf_sys::GDK_COLORSPACE_RGB;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gtk;
|
use gtk;
|
||||||
|
use prefs::Prefs;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -15,50 +16,74 @@ use support_ui::*;
|
|||||||
// TODO: on_apply
|
// TODO: on_apply
|
||||||
|
|
||||||
|
|
||||||
const ICON_MIN_SIZE: i64 = 16;
|
const ICON_MIN_SIZE: i32 = 16;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub struct TrayIcon {
|
pub struct TrayIcon {
|
||||||
pub volmeter: VolMeter,
|
pub volmeter: Option<VolMeter>,
|
||||||
pub audio_pix: AudioPix,
|
pub audio_pix: RefCell<AudioPix>,
|
||||||
pub status_icon: gtk::StatusIcon,
|
pub status_icon: gtk::StatusIcon,
|
||||||
pub icon_size: Cell<i64>,
|
pub icon_size: Cell<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl TrayIcon {
|
impl TrayIcon {
|
||||||
// TODO: take settings as parameter
|
pub fn new(prefs: &Prefs) -> Result<TrayIcon> {
|
||||||
pub fn new() -> Result<TrayIcon> {
|
let draw_vol_meter = prefs.view_prefs.draw_vol_meter;
|
||||||
let volmeter = VolMeter::new();
|
|
||||||
let audio_pix = AudioPix::new_from_pnmixer()?;
|
let volmeter = {
|
||||||
|
if draw_vol_meter {
|
||||||
|
Some(VolMeter::new(prefs))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let audio_pix = AudioPix::new(ICON_MIN_SIZE, prefs)?;
|
||||||
let status_icon = gtk::StatusIcon::new();
|
let status_icon = gtk::StatusIcon::new();
|
||||||
|
|
||||||
return Ok(TrayIcon {
|
return Ok(TrayIcon {
|
||||||
volmeter,
|
volmeter,
|
||||||
audio_pix,
|
audio_pix: RefCell::new(audio_pix),
|
||||||
status_icon,
|
status_icon,
|
||||||
icon_size: Cell::new(ICON_MIN_SIZE),
|
icon_size: Cell::new(ICON_MIN_SIZE),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&self, audio: &Audio, m_size: Option<i64>) {
|
fn update(&self,
|
||||||
|
prefs: &Prefs,
|
||||||
|
audio: &Audio,
|
||||||
|
m_size: Option<i32>)
|
||||||
|
-> Result<()> {
|
||||||
match m_size {
|
match m_size {
|
||||||
Some(s) => {
|
Some(s) => {
|
||||||
if s < ICON_MIN_SIZE {
|
if s < ICON_MIN_SIZE {
|
||||||
self.icon_size.set(ICON_MIN_SIZE);
|
self.icon_size.set(ICON_MIN_SIZE);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
self.icon_size.set(s);
|
self.icon_size.set(s);
|
||||||
}
|
}
|
||||||
|
/* if icon size changed, we have to re-init audio pix */
|
||||||
|
let pixbuf = AudioPix::new(self.icon_size.get(), &prefs)?;
|
||||||
|
*self.audio_pix.borrow_mut() = pixbuf;
|
||||||
}
|
}
|
||||||
None => (),
|
None => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let cur_vol = try_w!(audio.vol());
|
let cur_vol = audio.vol()?;
|
||||||
let pixbuf = self.audio_pix.select_pix(audio.vol_level());
|
let audio_pix = self.audio_pix.borrow();
|
||||||
let vol_pix = try_w!(self.volmeter.meter_draw(cur_vol as i64, &pixbuf));
|
let pixbuf = audio_pix.select_pix(audio.vol_level());
|
||||||
|
|
||||||
self.status_icon.set_from_pixbuf(Some(&vol_pix));
|
let volmeter = &self.volmeter.as_ref();
|
||||||
|
match volmeter {
|
||||||
|
&Some(v) => {
|
||||||
|
let vol_pix = v.meter_draw(cur_vol as i64, &pixbuf)?;
|
||||||
|
self.status_icon.set_from_pixbuf(Some(&vol_pix));
|
||||||
|
}
|
||||||
|
&None => self.status_icon.set_from_pixbuf(Some(pixbuf)),
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,13 +102,12 @@ pub struct VolMeter {
|
|||||||
|
|
||||||
|
|
||||||
impl VolMeter {
|
impl VolMeter {
|
||||||
// TODO: take settings
|
pub fn new(prefs: &Prefs) -> VolMeter {
|
||||||
pub fn new() -> VolMeter {
|
|
||||||
return VolMeter {
|
return VolMeter {
|
||||||
red: 245,
|
red: prefs.view_prefs.vol_meter_color.red,
|
||||||
green: 121,
|
green: prefs.view_prefs.vol_meter_color.green,
|
||||||
blue: 0,
|
blue: prefs.view_prefs.vol_meter_color.blue,
|
||||||
x_offset_pct: 10,
|
x_offset_pct: prefs.view_prefs.vol_meter_offset,
|
||||||
y_offset_pct: 10,
|
y_offset_pct: 10,
|
||||||
/* dynamic */
|
/* dynamic */
|
||||||
width: Cell::new(0),
|
width: Cell::new(0),
|
||||||
@ -182,41 +206,47 @@ pub struct AudioPix {
|
|||||||
|
|
||||||
|
|
||||||
impl AudioPix {
|
impl AudioPix {
|
||||||
// TODO: take settings
|
pub fn new(size: i32, prefs: &Prefs) -> Result<AudioPix> {
|
||||||
pub fn new_from_theme(size: i32) -> Result<AudioPix> {
|
let system_theme = prefs.view_prefs.system_theme;
|
||||||
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),
|
|
||||||
)?,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
let pix = {
|
||||||
|
if system_theme {
|
||||||
|
let theme: gtk::IconTheme = gtk::IconTheme::get_default().ok_or(
|
||||||
|
"Couldn't get default icon theme",
|
||||||
|
)?;
|
||||||
|
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),
|
||||||
|
)?,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AudioPix {
|
||||||
|
muted: pixbuf_new_from_file("pnmixer-muted.png")?,
|
||||||
|
low: pixbuf_new_from_file("pnmixer-low.png")?,
|
||||||
|
medium: pixbuf_new_from_file("pnmixer-medium.png")?,
|
||||||
|
high: pixbuf_new_from_file("pnmixer-high.png")?,
|
||||||
|
off: pixbuf_new_from_file("pnmixer-off.png")?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
return Ok(pix);
|
return Ok(pix);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_from_pnmixer() -> Result<AudioPix> {
|
|
||||||
gtk::IconTheme::get_default().ok_or("Couldn't get default icon theme")?;
|
|
||||||
let pix = AudioPix {
|
|
||||||
muted: pixbuf_new_from_file("pnmixer-muted.png")?,
|
|
||||||
low: pixbuf_new_from_file("pnmixer-low.png")?,
|
|
||||||
medium: pixbuf_new_from_file("pnmixer-medium.png")?,
|
|
||||||
high: pixbuf_new_from_file("pnmixer-high.png")?,
|
|
||||||
off: pixbuf_new_from_file("pnmixer-off.png")?,
|
|
||||||
};
|
|
||||||
|
|
||||||
return Ok(pix);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn select_pix(&self, vol_level: VolLevel) -> &gdk_pixbuf::Pixbuf {
|
pub fn select_pix(&self, vol_level: VolLevel) -> &gdk_pixbuf::Pixbuf {
|
||||||
match vol_level {
|
match vol_level {
|
||||||
@ -233,7 +263,7 @@ impl AudioPix {
|
|||||||
pub fn init_tray_icon(appstate: Rc<AppS>) {
|
pub fn init_tray_icon(appstate: Rc<AppS>) {
|
||||||
let audio = &appstate.audio;
|
let audio = &appstate.audio;
|
||||||
let tray_icon = &appstate.gui.tray_icon;
|
let tray_icon = &appstate.gui.tray_icon;
|
||||||
tray_icon.update(&audio, None);
|
try_e!(tray_icon.update(&appstate.prefs.borrow_mut(), &audio, None));
|
||||||
|
|
||||||
tray_icon.status_icon.set_visible(true);
|
tray_icon.status_icon.set_visible(true);
|
||||||
|
|
||||||
@ -243,7 +273,7 @@ pub fn init_tray_icon(appstate: Rc<AppS>) {
|
|||||||
appstate.audio.connect_handler(
|
appstate.audio.connect_handler(
|
||||||
Box::new(move |s, u| match (s, u) {
|
Box::new(move |s, u| match (s, u) {
|
||||||
(AudioSignal::ValuesChanged, _) => {
|
(AudioSignal::ValuesChanged, _) => {
|
||||||
apps.gui.tray_icon.update(&apps.audio, None);
|
try_w!(apps.gui.tray_icon.update(&apps.prefs.borrow_mut(), &apps.audio, None));
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}),
|
}),
|
||||||
@ -254,7 +284,7 @@ pub fn init_tray_icon(appstate: Rc<AppS>) {
|
|||||||
{
|
{
|
||||||
let apps = appstate.clone();
|
let apps = appstate.clone();
|
||||||
tray_icon.status_icon.connect_size_changed(move |_, size| {
|
tray_icon.status_icon.connect_size_changed(move |_, size| {
|
||||||
apps.gui.tray_icon.update(&apps.audio, Some(size as i64));
|
try_wr!(apps.gui.tray_icon.update(&apps.prefs.borrow_mut(), &apps.audio, Some(size)), false);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -317,8 +347,6 @@ fn on_tray_icon_scroll_event(appstate: &AppS,
|
|||||||
event: &gdk::EventScroll)
|
event: &gdk::EventScroll)
|
||||||
-> bool {
|
-> bool {
|
||||||
|
|
||||||
let audio = &appstate.audio;
|
|
||||||
|
|
||||||
let scroll_dir: gdk::ScrollDirection = event.get_direction();
|
let scroll_dir: gdk::ScrollDirection = event.get_direction();
|
||||||
match scroll_dir {
|
match scroll_dir {
|
||||||
gdk::ScrollDirection::Up => {
|
gdk::ScrollDirection::Up => {
|
||||||
|
Loading…
Reference in New Issue
Block a user