Update
This commit is contained in:
@@ -2,6 +2,7 @@ use gtk;
|
||||
use audio::AlsaCard;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use glade_helpers::*;
|
||||
|
||||
|
||||
// TODO: destructors
|
||||
@@ -15,9 +16,11 @@ pub struct AppS {
|
||||
|
||||
impl AppS {
|
||||
pub fn new() -> AppS {
|
||||
let builder_popup = gtk::Builder::new_from_string(include_str!("../data/ui/popup-window-vertical.glade"));
|
||||
let builder_popup_window =
|
||||
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"));
|
||||
return AppS {
|
||||
gui: Gui::new(builder_popup),
|
||||
gui: Gui::new(builder_popup_window, builder_popup_menu),
|
||||
acard: AlsaCard::new(None, Some(String::from("Master")))
|
||||
.unwrap(),
|
||||
};
|
||||
@@ -28,34 +31,32 @@ impl AppS {
|
||||
pub struct Gui {
|
||||
pub status_icon: gtk::StatusIcon,
|
||||
pub popup_window: PopupWindow,
|
||||
pub popup_menu: PopupMenu,
|
||||
}
|
||||
|
||||
|
||||
impl Gui {
|
||||
pub fn new(builder: gtk::Builder) -> Gui {
|
||||
pub fn new(builder_popup_window: gtk::Builder,
|
||||
builder_popup_menu: gtk::Builder)
|
||||
-> Gui {
|
||||
return Gui {
|
||||
status_icon: gtk::StatusIcon::new_from_icon_name("pnmixer"),
|
||||
popup_window: PopupWindow::new(builder),
|
||||
popup_window: PopupWindow::new(builder_popup_window),
|
||||
popup_menu: PopupMenu::new(builder_popup_menu),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct PopupWindow {
|
||||
pub window: gtk::Window,
|
||||
pub vol_scale_adj: gtk::Adjustment,
|
||||
pub vol_scale: gtk::Scale,
|
||||
pub mute_check: gtk::CheckButton,
|
||||
}
|
||||
create_builder_item!(PopupMenu,
|
||||
menu_window: gtk::Window,
|
||||
menubar: gtk::MenuBar,
|
||||
menu: gtk::Menu,
|
||||
about_item: gtk::MenuItem);
|
||||
|
||||
|
||||
impl PopupWindow {
|
||||
pub fn new(builder: gtk::Builder) -> PopupWindow {
|
||||
return PopupWindow {
|
||||
window: builder.get_object("popup_window").unwrap(),
|
||||
vol_scale_adj: builder.get_object("vol_scale_adj").unwrap(),
|
||||
vol_scale: builder.get_object("vol_scale").unwrap(),
|
||||
mute_check: builder.get_object("mute_check").unwrap(),
|
||||
};
|
||||
}
|
||||
}
|
||||
create_builder_item!(PopupWindow,
|
||||
popup_window: gtk::Window,
|
||||
vol_scale_adj: gtk::Adjustment,
|
||||
vol_scale: gtk::Scale,
|
||||
mute_check: gtk::CheckButton);
|
||||
|
||||
10
src/audio.rs
10
src/audio.rs
@@ -103,12 +103,12 @@ impl AlsaCard {
|
||||
}
|
||||
|
||||
|
||||
pub fn switch_card(old_card: Rc<RefCell<AlsaCard>>,
|
||||
card_name: Option<String>,
|
||||
elem_name: Option<String>)
|
||||
-> Result<Rc<RefCell<AlsaCard>>> {
|
||||
// pub fn switch_card(old_card: Rc<RefCell<AlsaCard>>,
|
||||
// card_name: Option<String>,
|
||||
// elem_name: Option<String>)
|
||||
// -> Result<Rc<RefCell<AlsaCard>>> {
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
|
||||
pub fn selem(&self) -> Selem {
|
||||
|
||||
@@ -12,22 +12,6 @@ error_chain! {
|
||||
}
|
||||
|
||||
|
||||
pub trait CHErr {
|
||||
type Item;
|
||||
fn cherr(self) -> Result<Self::Item>;
|
||||
}
|
||||
|
||||
|
||||
impl<A, E: std::error::Error> CHErr for std::result::Result<A, E>
|
||||
where Error: std::convert::From<E>
|
||||
{
|
||||
type Item = A;
|
||||
fn cherr(self) -> Result<Self::Item> {
|
||||
return self.map_err(From::from);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! try_w {
|
||||
($expr:expr) => {
|
||||
|
||||
21
src/glade_helpers.rs
Normal file
21
src/glade_helpers.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
#[macro_export]
|
||||
macro_rules! create_builder_item {
|
||||
($sname:ident, $($element: ident: $ty: ty),+) => {
|
||||
pub struct $sname {
|
||||
$(
|
||||
pub $element: $ty
|
||||
),+
|
||||
}
|
||||
|
||||
impl $sname {
|
||||
pub fn new(builder: gtk::Builder) -> $sname {
|
||||
return $sname {
|
||||
$(
|
||||
$element: builder.get_object(stringify!($element)).unwrap()
|
||||
),+
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,10 +25,14 @@ use std::rc::Rc;
|
||||
#[macro_use]
|
||||
mod errors;
|
||||
|
||||
#[macro_use]
|
||||
mod glade_helpers;
|
||||
|
||||
mod app_state;
|
||||
mod audio;
|
||||
mod myalsa;
|
||||
mod ui_entry;
|
||||
mod ui_popup_menu;
|
||||
mod ui_popup_window;
|
||||
mod ui_tray_icon;
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ pub fn get_alsa_card_by_name(name: String) -> Result<Card> {
|
||||
|
||||
|
||||
pub fn get_mixer(card: &Card) -> Result<Mixer> {
|
||||
return Mixer::new(&format!("hw:{}", card.get_index()), false).cherr();
|
||||
return Mixer::new(&format!("hw:{}", card.get_index()), false).from_err();
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ pub fn get_vol(selem: &Selem) -> Result<f64> {
|
||||
return vol_to_percent(v, range);
|
||||
});
|
||||
|
||||
return volume.cherr();
|
||||
return volume.from_err();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ use app_state::*;
|
||||
use audio::{AlsaCard, AudioSignal, AudioUser};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use ui_popup_menu::*;
|
||||
use ui_popup_window::*;
|
||||
use ui_tray_icon::*;
|
||||
|
||||
@@ -24,4 +25,5 @@ pub fn init(appstate: Rc<AppS>) {
|
||||
|
||||
init_tray_icon(appstate.clone());
|
||||
init_popup_window(appstate.clone());
|
||||
init_popup_menu(appstate.clone());
|
||||
}
|
||||
|
||||
71
src/ui_popup_menu.rs
Normal file
71
src/ui_popup_menu.rs
Normal file
@@ -0,0 +1,71 @@
|
||||
use app_state::*;
|
||||
use gdk;
|
||||
use gdk_sys;
|
||||
use glib;
|
||||
use glib_sys;
|
||||
use std::mem;
|
||||
use gtk::prelude::*;
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use libc;
|
||||
use audio::AudioUser::*;
|
||||
use errors::*;
|
||||
use gtk;
|
||||
|
||||
|
||||
|
||||
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
|
||||
pub fn init_popup_menu(appstate: Rc<AppS>) {
|
||||
|
||||
/* about_item.connect_activate_link */
|
||||
{
|
||||
let apps = appstate.clone();
|
||||
let about_item = &appstate.clone()
|
||||
.gui
|
||||
.popup_menu
|
||||
.about_item;
|
||||
about_item.connect_activate(move |_| {
|
||||
on_about_item_activate(&apps);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn on_about_item_activate(appstate: &AppS) {
|
||||
let popup_menu = &appstate.gui.popup_menu.menu_window;
|
||||
let about_dialog = create_about_dialog();
|
||||
about_dialog.set_skip_taskbar_hint(true);
|
||||
about_dialog.set_transient_for(popup_menu);
|
||||
about_dialog.run();
|
||||
about_dialog.destroy();
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
under the terms of the GNU General Public License v3 as published
|
||||
by the Free Software Foundation.
|
||||
|
||||
PNMixer is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with PNMixer; if not, write to the Free Software Foundation,
|
||||
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_logo_icon_name("pnmixer");
|
||||
about_dialog.set_version(VERSION);
|
||||
about_dialog.set_website("https://github.com/hasufell/pnmixer-rust");
|
||||
about_dialog.set_comments("A mixer for the system tray");
|
||||
|
||||
return about_dialog;
|
||||
}
|
||||
@@ -34,7 +34,7 @@ pub fn init_popup_window(appstate: Rc<AppS>) {
|
||||
let popup_window = &appstate.clone()
|
||||
.gui
|
||||
.popup_window
|
||||
.window;
|
||||
.popup_window;
|
||||
popup_window.connect_show(move |w| {
|
||||
on_popup_window_show(w,
|
||||
&_appstate,
|
||||
@@ -60,7 +60,7 @@ pub fn init_popup_window(appstate: Rc<AppS>) {
|
||||
let popup_window = &appstate.clone()
|
||||
.gui
|
||||
.popup_window
|
||||
.window;
|
||||
.popup_window;
|
||||
popup_window.connect_event(move |w, e| {
|
||||
on_popup_window_event(w, e, &_appstate)
|
||||
});
|
||||
|
||||
@@ -14,25 +14,36 @@ use errors::*;
|
||||
|
||||
|
||||
pub fn init_tray_icon(appstate: Rc<AppS>) {
|
||||
/* tray_icon.connect_activate */
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/* tray_icon.connect_scroll_event */
|
||||
{
|
||||
let apps = appstate.clone();
|
||||
let tray_icon = &appstate.clone().gui.status_icon;
|
||||
tray_icon.connect_scroll_event(move |_, e| {
|
||||
on_tray_icon_scroll_event(&appstate.clone(), &e)
|
||||
});
|
||||
tray_icon.set_visible(true);
|
||||
on_tray_icon_scroll_event(&apps, &e)
|
||||
});
|
||||
}
|
||||
|
||||
/* 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)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn on_tray_icon_activate(appstate: &AppS) {
|
||||
let popup_window = &appstate.gui.popup_window.window;
|
||||
let popup_window = &appstate.gui.popup_window.popup_window;
|
||||
|
||||
if popup_window.get_visible() {
|
||||
popup_window.hide();
|
||||
@@ -42,17 +53,26 @@ fn on_tray_icon_activate(appstate: &AppS) {
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
fn on_tray_icon_scroll_event(appstate: &AppS,
|
||||
event: &gdk::EventScroll)
|
||||
-> bool {
|
||||
|
||||
let scroll_dir = event.as_ref().direction;
|
||||
let scroll_dir: gdk::ScrollDirection = event.get_direction();
|
||||
match scroll_dir {
|
||||
gdk_sys::GdkScrollDirection::Up => {
|
||||
gdk::ScrollDirection::Up => {
|
||||
try_wr!(appstate.acard.borrow().increase_vol(AudioUserTrayIcon),
|
||||
false);
|
||||
}
|
||||
gdk_sys::GdkScrollDirection::Down => {
|
||||
gdk::ScrollDirection::Down => {
|
||||
try_wr!(appstate.acard.borrow().decrease_vol(AudioUserTrayIcon),
|
||||
false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user