Update
This commit is contained in:
parent
5e0d7f9550
commit
45cdc5f9ca
23
Cargo.toml
23
Cargo.toml
@ -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
58
Makefile
Normal 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
|
@ -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
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
52
src/audio.rs
52
src/audio.rs
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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: >k::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;
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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, _) => {
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user