This commit is contained in:
2017-07-01 16:55:35 +02:00
parent c1df692fa8
commit 055459fa7a
14 changed files with 830 additions and 156 deletions

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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
View 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()
),+
};
}
}
}
}

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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
View 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;
}

View File

@@ -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)
});

View File

@@ -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);
}