This commit is contained in:
Julian Ospald 2017-07-09 00:14:49 +02:00
parent 5e0d7f9550
commit 45cdc5f9ca
No known key found for this signature in database
GPG Key ID: 511B62C09D50CD28
18 changed files with 288 additions and 93 deletions

View File

@ -6,23 +6,24 @@ authors = ["Julian Ospald <hasufell@posteo.de>"]
[dependencies]
alsa = "^0.1.8"
alsa-sys = "^0.1.1"
libc = "^0.2.23"
gdk-sys = { git = "https://github.com/gtk-rs/sys" }
error-chain = { path = "3rdparty/error-chain" }
ffi = "^0.0.2"
flexi_logger = "^0.5.1"
gdk-pixbuf = { git = "https://github.com/gtk-rs/gdk-pixbuf.git" }
gdk-pixbuf-sys = { git = "https://github.com/gtk-rs/sys" }
gtk-sys = { git = "https://github.com/gtk-rs/sys" }
gdk-sys = { git = "https://github.com/gtk-rs/sys" }
gio = { git = "https://github.com/gtk-rs/gio.git" }
glib = { git = "https://github.com/gtk-rs/glib.git" }
glib-sys = { git = "https://github.com/gtk-rs/sys" }
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
ffi = "^0.0.2"
flexi_logger = "^0.5.1"
gtk-sys = { git = "https://github.com/gtk-rs/sys" }
libc = "^0.2.23"
log = "^0.3.8"
error-chain = { path = "3rdparty/error-chain" }
toml = "^0.4.2"
serde_derive = "^1.0.9"
serde = "^1.0.9"
xdg = "*"
serde_derive = "^1.0.9"
toml = "^0.4.2"
which = "*"
xdg = "*"
[dependencies.gtk]
git = "https://github.com/gtk-rs/gtk.git"
@ -33,12 +34,12 @@ git = "https://github.com/gtk-rs/gdk.git"
features = [ "v3_10", "v3_12", "v3_22" ]
[profile.dev]
opt-level = 2 # controls the `--opt-level` the compiler builds with
opt-level = 0 # controls the `--opt-level` the compiler builds with
debug = true # controls whether the compiler passes `-C debuginfo`
# a value of `true` is equivalent to `2`
rpath = false # controls whether the compiler passes `-C rpath`
lto = false # controls `-C lto` for binaries and staticlibs
debug-assertions = true # controls whether debug assertions are enabled
debug-assertions = false # controls whether debug assertions are enabled
codegen-units = 1 # controls whether the compiler passes `-C codegen-units`
# `codegen-units` is ignored when `lto = true`
panic = 'unwind' # panic strategy (`-C panic=...`), can also be 'abort'

58
Makefile Normal file
View File

@ -0,0 +1,58 @@
INSTALL = install
INSTALL_DIR = $(INSTALL) -d
INSTALL_BIN = $(INSTALL) -m 755
INSTALL_DATA = $(INSTALL) -m 644
PREFIX=/usr/local
BINDIR=$(PREFIX)/bin
SHAREDIR=$(PREFIX)/share
DATADIR=$(SHAREDIR)/pnmixer
PIXMAPSDIR=$(DATADIR)/pixmaps
ICONSDIR=$(SHAREDIR)/icons/hicolor/128x128/apps
DESKTOPDIR=$(SHAREDIR)/applications
CARGO ?= cargo
CARGO_ARGS ?=
CARGO_BUILD_ARGS ?= --release
CARGO_BUILD ?= $(CARGO) $(CARGO_ARGS) build $(CARGO_BUILD_ARGS)
CARGO_INSTALL_ARGS ?= --root="$(DESTDIR)/$(PREFIX)"
CARGO_INSTALL ?= $(CARGO) $(CARGO_ARGS) install $(CARGO_INSTALL_ARGS)
pnmixer-rs: Cargo.toml
PIXMAPSDIR=$(PIXMAPSDIR) $(CARGO_BUILD)
install: install-data
$(INSTALL_DIR) "$(DESTDIR)/$(BINDIR)"
$(INSTALL_BIN) target/release/pnmixer "$(DESTDIR)/$(BINDIR)/pnmixer"
install-data: install-pixmaps install-icons install-desktop
install-pixmaps:
$(INSTALL_DIR) "$(DESTDIR)/$(PIXMAPSDIR)"
$(INSTALL_DATA) data/pixmaps/pnmixer-about.png "$(DESTDIR)/$(PIXMAPSDIR)/pnmixer-about.png"
$(INSTALL_DATA) data/pixmaps/pnmixer-high.png "$(DESTDIR)/$(PIXMAPSDIR)/pnmixer-high.png"
$(INSTALL_DATA) data/pixmaps/pnmixer-low.png "$(DESTDIR)/$(PIXMAPSDIR)/pnmixer-low.png"
$(INSTALL_DATA) data/pixmaps/pnmixer-medium.png "$(DESTDIR)/$(PIXMAPSDIR)/pnmixer-medium.png"
$(INSTALL_DATA) data/pixmaps/pnmixer-muted.png "$(DESTDIR)/$(PIXMAPSDIR)/pnmixer-muted.png"
$(INSTALL_DATA) data/pixmaps/pnmixer-off.png "$(DESTDIR)/$(PIXMAPSDIR)/pnmixer-off.png"
install-icons:
$(INSTALL_DIR) "$(DESTDIR)/$(ICONSDIR)"
$(INSTALL_DATA) data/icons/pnmixer.png "$(DESTDIR)/$(ICONSDIR)/pnmixer.png"
install-desktop:
$(INSTALL_DIR) "$(DESTDIR)/$(DESKTOPDIR)"
$(INSTALL_DATA) data/desktop/pnmixer.desktop "$(DESTDIR)/$(DESKTOPDIR)/pnmixer.desktop"
.PHONY: pnmixer-rs install install-data install-pixmaps install-icons install-desktop

View File

@ -1,5 +1,5 @@
[Desktop Entry]
Name=PNMixer
Name=PNMixer-rs
_GenericName=System Tray Mixer
_Comment=An audio mixer for the system tray
Exec=pnmixer

View File

@ -12,8 +12,6 @@
<property name="destroy_with_parent">True</property>
<property name="icon_name">input-keyboard</property>
<property name="type_hint">dialog</property>
<signal name="key-press-event" handler="on_hotkey_dialog_key_press_event" swapped="no"/>
<signal name="key-release-event" handler="on_hotkey_dialog_key_release_event" swapped="no"/>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox1">
<property name="visible">True</property>

View File

@ -31,7 +31,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Mute/Unmute Volume</property>
<signal name="activate" handler="on_mute_item_activate" swapped="no"/>
<child>
<object class="GtkBox" id="box0">
<property name="visible">True</property>
@ -71,7 +70,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Open Volume Control</property>
<signal name="activate" handler="on_mixer_item_activate" swapped="no"/>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
@ -108,7 +106,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Preferences</property>
<signal name="activate" handler="on_prefs_item_activate" swapped="no"/>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
@ -146,7 +143,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Reload Sound</property>
<signal name="activate" handler="on_reload_item_activate" swapped="no"/>
<child>
<object class="GtkBox" id="box3">
<property name="visible">True</property>
@ -184,7 +180,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">About</property>
<signal name="activate" handler="on_about_item_activate" swapped="no"/>
<child>
<object class="GtkBox" id="box4">
<property name="visible">True</property>
@ -229,7 +224,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Quit</property>
<signal name="activate" handler="gtk_main_quit" swapped="no"/>
<child>
<object class="GtkBox" id="box5">
<property name="visible">True</property>

View File

@ -16,9 +16,6 @@
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="decorated">False</property>
<signal name="button-press-event" handler="on_popup_window_event" swapped="no"/>
<signal name="grab-broken-event" handler="on_popup_window_event" swapped="no"/>
<signal name="key-press-event" handler="on_popup_window_event" swapped="no"/>
<child>
<object class="GtkBox" id="vbox1">
<property name="visible">True</property>
@ -36,7 +33,6 @@
<property name="round_digits">0</property>
<property name="digits">0</property>
<property name="height_request">200</property>
<signal name="value-changed" handler="on_vol_scale_value_changed" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
@ -58,7 +54,6 @@
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_mute_check_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
@ -73,7 +68,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_mixer_button_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>

View File

@ -69,7 +69,6 @@
<property name="receives_default">False</property>
<property name="halign">start</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_noti_enable_check_toggled" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
@ -233,7 +232,7 @@
</object>
<object class="GtkDialog" id="prefs_dialog">
<property name="can_focus">False</property>
<property name="title" translatable="yes">PNMixer Preferences</property>
<property name="title" translatable="yes">PNMixer-rs Preferences</property>
<property name="resizable">False</property>
<property name="icon_name">preferences-system</property>
<property name="type_hint">dialog</property>
@ -447,7 +446,6 @@
<object class="GtkComboBoxText" id="card_combo">
<property name="visible">True</property>
<property name="can_focus">False</property>
<signal name="changed" handler="on_card_combo_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
@ -581,7 +579,6 @@
<property name="receives_default">False</property>
<property name="halign">start</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_vol_meter_draw_check_toggled" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
@ -744,6 +741,35 @@
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label32">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Fine Scroll Step:</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="fine_scroll_step_spin">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="text" translatable="yes">0,00</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="adjustment">fine_scroll_step_adjustment</property>
<property name="digits">2</property>
<property name="numeric">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
</child>
<child type="label">
@ -805,7 +831,6 @@
<object class="GtkComboBoxText" id="middle_click_combo">
<property name="visible">True</property>
<property name="can_focus">False</property>
<signal name="changed" handler="on_middle_click_combo_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
@ -891,7 +916,6 @@
<property name="receives_default">False</property>
<property name="halign">start</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_hotkeys_enable_check_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
@ -976,7 +1000,6 @@
<object class="GtkEventBox" id="hotkeys_mute_eventbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<signal name="button-press-event" handler="on_hotkey_event_box_button_press_event" swapped="no"/>
<child>
<object class="GtkLabel" id="hotkeys_mute_label">
<property name="visible">True</property>
@ -997,7 +1020,6 @@
<object class="GtkEventBox" id="hotkeys_up_eventbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<signal name="button-press-event" handler="on_hotkey_event_box_button_press_event" swapped="no"/>
<child>
<object class="GtkLabel" id="hotkeys_up_label">
<property name="visible">True</property>
@ -1018,7 +1040,6 @@
<object class="GtkEventBox" id="hotkeys_down_eventbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<signal name="button-press-event" handler="on_hotkey_event_box_button_press_event" swapped="no"/>
<child>
<object class="GtkLabel" id="hotkeys_down_label">
<property name="visible">True</property>

View File

@ -233,6 +233,7 @@ extern "C" fn watch_cb(chan: *mut glib_sys::GIOChannel,
let acard =
unsafe { mem::transmute::<glib_sys::gpointer, &AlsaCard>(data) };
let cb = &acard.cb;
unsafe {
let mixer_ptr =
@ -261,15 +262,21 @@ extern "C" fn watch_cb(chan: *mut glib_sys::GIOChannel,
glib_sys::G_IO_STATUS_AGAIN => {
debug!("G_IO_STATUS_AGAIN");
continue;
}
},
// TODO: handle these failure cases
glib_sys::G_IO_STATUS_NORMAL => debug!("G_IO_STATUS_NORMAL"),
glib_sys::G_IO_STATUS_ERROR => debug!("G_IO_STATUS_ERROR"),
glib_sys::G_IO_STATUS_EOF => debug!("G_IO_STATUS_EOF"),
glib_sys::G_IO_STATUS_NORMAL => {
error!("Alsa failed to clear the channel");
cb(AlsaEvent::AlsaCardError);
},
glib_sys::G_IO_STATUS_ERROR => (),
glib_sys::G_IO_STATUS_EOF => {
error!("GIO error has occurred");
cb(AlsaEvent::AlsaCardError);
},
_ => warn!("Unknown status from g_io_channel_read_chars()"),
}
return true as glib_sys::gboolean;
}
let cb = &acard.cb;
cb(AlsaEvent::AlsaCardValuesChanged);
return true as glib_sys::gboolean;

View File

@ -5,6 +5,7 @@ use prefs::*;
use std::cell::RefCell;
use ui_entry::Gui;
use ui_prefs_dialog::show_prefs_dialog;
use notif::*;
// TODO: notify popups
@ -17,6 +18,7 @@ pub struct AppS {
_cant_construct: (),
pub gui: Gui,
pub audio: Audio,
pub notif: Notif,
pub prefs: RefCell<Prefs>,
}
@ -42,11 +44,14 @@ impl AppS {
.channel
.clone();
let notif = Notif::new(&prefs.borrow());
return AppS {
_cant_construct: (),
gui: gui,
gui,
audio: Audio::new(Some(card_name), Some(chan_name)).unwrap(),
prefs: prefs,
notif,
prefs,
};
}
@ -64,9 +69,4 @@ impl AppS {
debug!("Update PopupWindow!");
return self.gui.popup_window.update(&self.audio);
}
// TODO
pub fn show_preferences(&self) {
// show_prefs_dialog(self);
}
}

View File

@ -90,9 +90,22 @@ impl Audio {
})
};
let acard = AlsaCard::new(card_name, elem_name, cb);
/* additionally dispatch signals */
if acard.is_err() {
invoke_handlers(&handlers.borrow(),
AudioSignal::NoCard,
AudioUser::Unknown);
} else {
invoke_handlers(&handlers.borrow(),
AudioSignal::CardInitialized,
AudioUser::Unknown);
}
let audio = Audio {
_cannot_construct: (),
acard: RefCell::new(AlsaCard::new(card_name, elem_name, cb)?),
acard: RefCell::new(acard?),
last_action_timestamp: last_action_timestamp.clone(),
handlers: handlers.clone(),
scroll_step: Cell::new(5),
@ -126,17 +139,10 @@ impl Audio {
let mut ac = self.acard.borrow_mut();
*ac = AlsaCard::new(card_name, elem_name, cb)?;
}
debug!("Old card name: {}",
self.acard
.borrow()
.card_name()
.unwrap());
debug!("Old chan name: {}",
self.acard
.borrow()
.chan_name()
.unwrap());
// invoke_handlers(&self.handlers.borrow(),
// AudioSignal::CardCleanedUp,
// user);
invoke_handlers(&self.handlers.borrow(),
AudioSignal::CardInitialized,
user);
@ -216,9 +222,6 @@ impl Audio {
self.set_vol(new_vol, user)?;
invoke_handlers(&self.handlers.borrow(),
AudioSignal::ValuesChanged,
user);
return Ok(());
}
@ -245,9 +248,6 @@ impl Audio {
self.set_vol(new_vol, user)?;
invoke_handlers(&self.handlers.borrow(),
AudioSignal::ValuesChanged,
user);
return Ok(());
}
@ -307,6 +307,11 @@ fn invoke_handlers(handlers: &Vec<Box<Fn(AudioSignal, AudioUser)>>,
debug!("Invoking handlers for signal {:?} by user {:?}",
signal,
user);
if handlers.is_empty() {
debug!("No handler found");
} else {
debug!("Executing handlers")
}
for handler in handlers {
let unboxed = handler.as_ref();
unboxed(signal, user);
@ -332,10 +337,17 @@ fn on_alsa_event(last_action_timestamp: &mut i64,
/* external change */
match alsa_event {
// TODO: invoke handlers with AudioUserUnknown
AlsaEvent::AlsaCardError => debug!("AlsaCardError"),
AlsaEvent::AlsaCardDiconnected => debug!("AlsaCardDiconnected"),
AlsaEvent::AlsaCardError => {
invoke_handlers(handlers,
self::AudioSignal::CardError,
self::AudioUser::Unknown);
},
AlsaEvent::AlsaCardDiconnected => {
invoke_handlers(handlers,
self::AudioSignal::CardDisconnected,
self::AudioUser::Unknown);
},
AlsaEvent::AlsaCardValuesChanged => {
debug!("AlsaCardValuesChanged");
invoke_handlers(handlers,
self::AudioSignal::ValuesChanged,
self::AudioUser::Unknown);

View File

@ -20,6 +20,7 @@ extern crate gdk;
extern crate gdk_pixbuf;
extern crate gdk_pixbuf_sys;
extern crate gdk_sys;
extern crate gio;
extern crate glib;
extern crate glib_sys;
extern crate gobject_sys;

View File

@ -122,6 +122,7 @@ impl Default for VolColor {
pub struct BehaviorPrefs {
pub vol_control_cmd: Option<String>,
pub vol_scroll_step: f64,
pub vol_fine_scroll_step: f64,
pub middle_click_action: MiddleClickAction,
pub custom_command: Option<String>, // TODO: fine scroll step?
}
@ -131,6 +132,7 @@ impl Default for BehaviorPrefs {
return BehaviorPrefs {
vol_control_cmd: None,
vol_scroll_step: 5.0,
vol_fine_scroll_step: 1.0,
middle_click_action: MiddleClickAction::default(),
custom_command: None,
};

View File

@ -43,16 +43,28 @@ pub fn pixbuf_new_from_theme(icon_name: &str,
pub fn pixbuf_new_from_file(filename: &str) -> Result<gdk_pixbuf::Pixbuf> {
ensure!(!filename.is_empty(), "Filename is empty");
let mut syspath = String::new();
let sysdir = option_env!("PIXMAPSDIR").map(|s|{
syspath = format!("{}/{}", s, filename);
Path::new(syspath.as_str())
});
let cargopath = format!("./data/pixmaps/{}",
filename);
let cargodir = Path::new(cargopath.as_str());
let s = format!("{}/data/pixmaps/{}", env!("CARGO_MANIFEST_DIR"), filename);
let path = Path::new(s.as_str());
// prefer local dir
let final_dir = {
if cargodir.exists() {
cargodir
} else if sysdir.is_some() && sysdir.unwrap().exists() {
sysdir.unwrap()
} else {
bail!("No valid path found")
}
};
if path.exists() {
let str_path = path.to_str().ok_or("Path is not valid unicode")?;
// TODO: propagate error
return Ok(gdk_pixbuf::Pixbuf::new_from_file(str_path).unwrap());
} else {
bail!("Uh-oh");
}
let str_path = final_dir.to_str().ok_or("Path is not valid unicode")?;
debug!("Loading icon from {}", str_path);
// TODO: propagate error
return Ok(gdk_pixbuf::Pixbuf::new_from_file(str_path).unwrap());
}

View File

@ -1,13 +1,20 @@
use app_state::*;
use audio::{AudioUser, AudioSignal};
use gtk::DialogExt;
use gtk::MessageDialogExt;
use gtk::WidgetExt;
use gtk::WindowExt;
use gtk;
use gtk_sys::{GTK_DIALOG_DESTROY_WITH_PARENT, GTK_RESPONSE_YES};
use notif::*;
use prefs::*;
use std::cell::RefCell;
use std::rc::Rc;
use support_audio::*;
use ui_popup_menu::*;
use ui_popup_window::*;
use ui_prefs_dialog::*;
use ui_tray_icon::*;
use audio::{AudioUser, AudioSignal};
@ -39,16 +46,25 @@ impl Gui {
pub fn init(appstate: Rc<AppS>) {
{
/* "global" audio signal handler */
let apps = appstate.clone();
appstate.audio.connect_handler(
Box::new(move |s, u| match (s, u) {
(AudioSignal::ValuesChanged, AudioUser::Unknown) => {
debug!("Appstate references: {}!", Rc::strong_count(&apps));
}
_ => debug!("Nix"),
}),
);
(AudioSignal::CardDisconnected, _) => {
try_w!(audio_reload(&apps.audio,
&apps.prefs.borrow(),
AudioUser::Unknown));
},
(AudioSignal::CardError, _) => {
if run_audio_error_dialog(&apps.gui.popup_menu.menu_window) == (GTK_RESPONSE_YES as i32) {
try_w!(audio_reload(&apps.audio,
&apps.prefs.borrow(),
AudioUser::Unknown));
}
},
_ => (),
}
));
}
@ -57,3 +73,28 @@ pub fn init(appstate: Rc<AppS>) {
init_popup_menu(appstate.clone());
init_prefs_callback(appstate.clone());
}
fn run_audio_error_dialog(parent: &gtk::Window) -> i32 {
error!("Connection with audio failed, you probably need to restart pnmixer.");
let dialog = gtk::MessageDialog::new(
Some(parent),
gtk::DIALOG_DESTROY_WITH_PARENT,
gtk::MessageType::Error,
gtk::ButtonsType::YesNo,
"Warning: Connection to sound system failed."
);
dialog.set_property_secondary_text(Some("Do you want to re-initialize the audio connection ?
If you do not, you will either need to restart PNMixer
or select the 'Reload Audio' option in the right-click
menu in order for PNMixer to function."));
dialog.set_title("PNMixer-rs Error");
let resp = dialog.run();
dialog.destroy();
return resp;
}

View File

@ -127,7 +127,7 @@ fn create_about_dialog() -> gtk::AboutDialog {
let about_dialog: gtk::AboutDialog = gtk::AboutDialog::new();
about_dialog.set_license(Some(
"PNMixer is free software; you can redistribute it and/or modify it
"PNMixer-rs is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License v3 as published
by the Free Software Foundation.
@ -143,7 +143,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.",
about_dialog.set_copyright(Some("Copyright © 2017 Julian Ospald"));
about_dialog.set_authors(&["Julian Ospald"]);
about_dialog.set_artists(&["Paul Davey"]);
about_dialog.set_program_name("pnmixer-rs");
about_dialog.set_program_name("PNMixer-rs");
about_dialog.set_logo_icon_name("pnmixer");
about_dialog.set_version(VERSION);
about_dialog.set_website("https://github.com/hasufell/pnmixer-rust");

View File

@ -9,6 +9,7 @@ use glib;
use gtk::ToggleButtonExt;
use gtk::prelude::*;
use gtk;
use prefs::*;
use std::cell::Cell;
use std::rc::Rc;
use support_cmd::*;
@ -71,6 +72,13 @@ impl PopupWindow {
glib::signal_handler_unblock(&self.mute_check,
self.toggle_signal.get());
}
fn set_vol_increment(&self, prefs: &Prefs) {
self.vol_scale_adj
.set_page_increment(prefs.behavior_prefs.vol_scroll_step);
self.vol_scale_adj
.set_step_increment(prefs.behavior_prefs.vol_fine_scroll_step);
}
}
@ -104,7 +112,6 @@ pub fn init_popup_window(appstate: Rc<AppS>) {
}
}
}));
}
/* mute_check.connect_toggled */
@ -174,6 +181,7 @@ pub fn init_popup_window(appstate: Rc<AppS>) {
fn on_popup_window_show(appstate: &AppS) {
appstate.gui.popup_window.set_vol_increment(&appstate.prefs.borrow());
try_w!(appstate.gui.popup_window.update(&appstate.audio));
appstate.gui
.popup_window

View File

@ -6,7 +6,6 @@ use gtk::ResponseType;
use gtk::prelude::*;
use gtk;
use prefs::*;
use std::mem;
use std::rc::Rc;
use support_alsa::*;
use support_audio::*;
@ -34,6 +33,7 @@ pub struct PrefsDialog {
/* BehaviorPrefs */
vol_control_entry: gtk::Entry,
scroll_step_spin: gtk::SpinButton,
fine_scroll_step_spin: gtk::SpinButton,
middle_click_combo: gtk::ComboBoxText,
custom_entry: gtk::Entry,
@ -68,6 +68,8 @@ impl PrefsDialog {
vol_control_entry: builder.get_object("vol_control_entry").unwrap(),
scroll_step_spin: builder.get_object("scroll_step_spin").unwrap(),
fine_scroll_step_spin: builder.get_object("fine_scroll_step_spin")
.unwrap(),
middle_click_combo: builder.get_object("middle_click_combo")
.unwrap(),
custom_entry: builder.get_object("custom_entry").unwrap(),
@ -113,6 +115,8 @@ impl PrefsDialog {
.unwrap_or(&String::from(""))
.as_str());
self.scroll_step_spin.set_value(prefs.behavior_prefs.vol_scroll_step);
self.fine_scroll_step_spin
.set_value(prefs.behavior_prefs.vol_fine_scroll_step);
// TODO: make sure these values always match, must be a better way
// also check to_prefs()
@ -184,6 +188,7 @@ impl PrefsDialog {
let behavior_prefs = BehaviorPrefs {
vol_control_cmd,
vol_scroll_step: self.scroll_step_spin.get_value(),
vol_fine_scroll_step: self.fine_scroll_step_spin.get_value(),
middle_click_action: self.middle_click_combo.get_active().into(),
custom_command,
};
@ -234,6 +239,11 @@ pub fn show_prefs_dialog(appstate: &Rc<AppS>) {
pub fn init_prefs_callback(appstate: Rc<AppS>) {
let apps = appstate.clone();
appstate.audio.connect_handler(Box::new(move |s, u| {
/* skip if prefs window is not present */
if apps.gui.prefs_dialog.borrow().is_none() {
return;
}
match (s, u) {
(AudioSignal::CardInitialized, _) => (),
(AudioSignal::CardCleanedUp, _) => {

View File

@ -1,9 +1,11 @@
use app_state::*;
use audio::*;
use errors::*;
use glib;
use gio;
use gdk;
use gdk_pixbuf;
use gdk_pixbuf_sys::GDK_COLORSPACE_RGB;
use gdk_pixbuf_sys;
use gtk::prelude::*;
use gtk;
use prefs::{Prefs, MiddleClickAction};
@ -12,6 +14,7 @@ use std::cell::RefCell;
use std::rc::Rc;
use support_cmd::*;
use support_ui::*;
use ui_prefs_dialog::show_prefs_dialog;
// TODO tooltip
@ -78,6 +81,36 @@ impl TrayIcon {
}
fn update_tooltip(&self, audio: &Audio) {
let cardname = audio.acard
.borrow()
.card_name()
.unwrap_or(String::from("Unknown card"));
let channame = audio.acard
.borrow()
.chan_name()
.unwrap_or(String::from("unknown channel"));
let vol = audio.vol()
.map(|s| format!("{}", s.round()))
.unwrap_or(String::from("unknown volume"));
let mute_info = {
if !audio.has_mute() {
"\nNo mute switch"
} else if audio.get_mute().unwrap_or(false) {
"\nMuted"
} else {
""
}
};
self.status_icon.set_tooltip_text(format!("{} ({})\nVolume: {}{}",
cardname,
channame,
vol,
mute_info)
.as_str());
}
pub fn update_all(&self,
prefs: &Prefs,
audio: &Audio,
@ -104,6 +137,7 @@ impl TrayIcon {
*self.volmeter.borrow_mut() = Some(volmeter);
}
self.update_tooltip(&audio);
return self.update_pixbuf(audio.vol()?, audio.vol_level());
}
}
@ -142,7 +176,7 @@ impl VolMeter {
pixbuf: &gdk_pixbuf::Pixbuf)
-> Result<gdk_pixbuf::Pixbuf> {
ensure!(pixbuf.get_colorspace() == GDK_COLORSPACE_RGB,
ensure!(pixbuf.get_colorspace() == gdk_pixbuf_sys::GDK_COLORSPACE_RGB,
"Invalid colorspace in pixbuf");
ensure!(pixbuf.get_bits_per_sample() == 8,
"Invalid bits per sample in pixbuf");
@ -310,6 +344,7 @@ pub fn init_tray_icon(appstate: Rc<AppS>) {
let apps = appstate.clone();
appstate.audio.connect_handler(Box::new(move |s, u| match (s, u) {
(_, _) => {
apps.gui.tray_icon.update_tooltip(&apps.audio);
try_w!(apps.gui.tray_icon.update_audio(&apps.audio));
}
}));
@ -400,7 +435,7 @@ fn on_tray_icon_scroll_event(appstate: &AppS,
}
fn on_tray_button_release_event(appstate: &AppS,
fn on_tray_button_release_event(appstate: &Rc<AppS>,
event_button: &gdk::EventButton)
-> bool {
let button = event_button.get_button();
@ -421,7 +456,8 @@ fn on_tray_button_release_event(appstate: &AppS,
try_wr!(audio.toggle_mute(AudioUser::Popup), false);
}
}
&MiddleClickAction::ShowPreferences => (),
// TODO
&MiddleClickAction::ShowPreferences => show_prefs_dialog(&appstate),
&MiddleClickAction::VolumeControl => {
try_wr!(execute_vol_control_command(&appstate.prefs.borrow()),
false);