Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

adjust volume on scroll-events, mute on middle-click

- scroll on status icon: adjust volume on default sink
- Ctrl scroll on status icon: adjust volume on default source
- middle-click on status icon: toggle mute default sink
- Ctrl middle-click on status icon: toggle mute default source
- scroll on menu item: adjust volume on device/item
- middle-click on menu item: toggle mute device/item

- split long lines
  • Loading branch information...
commit 573aacaa83da631814619f99650d884b94deba1a 1 parent 6eddb99
@christophgysin authored
View
6 README
@@ -4,6 +4,12 @@ Pasystray allows setting the default PulseAudio source/sink and moving
streams on the fly between sources/sinks without restarting the client
application. It does not (yet) support setting X properties.
+Scrolling over the status icon adjusts the default sink volume, holding down
+Ctrl key while scrolling adjusts the default source. Scrolling also works on
+menu items for sources, sinks, input and output streams.
+Middle-clicking on the status icon toggles muting the default sink (default
+source if holding Ctrl-key). Middle clicking on menu entries toggles muting
+the selected device/stream.
Devices can be renamed by right-clicking on the respective menu entry (needs
module-device-manager to be loaded).
View
4 TODO
@@ -2,10 +2,6 @@ detect pulseaudio servers with libavahi-client
switch servers by setting X properties
allow manual adding of servers
-catch scroll wheel events:
-- if hovering over systray icon: default sink volume
-- if hovering over sink/source: sink/source volume
-
libnotify
settings
gettext and translations
View
142 src/menu_info.c
@@ -90,7 +90,8 @@ void menu_info_init(menu_infos_t* mis, menu_info_t* mi, menu_type_t type)
mi->type = type;
mi->menu = NULL;
mi->group = NULL;
- mi->items = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)menu_info_item_destroy);
+ mi->items = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
+ (GDestroyNotify) menu_info_item_destroy);
mi->menu_infos = mis;
mi->parent = NULL;
@@ -107,6 +108,7 @@ void menu_info_item_init(menu_info_item_t* mii)
{
mii->name = NULL;
mii->desc = NULL;
+ mii->volume = NULL;
mii->icon = NULL;
mii->widget = NULL;
mii->menu_info = NULL;
@@ -127,21 +129,27 @@ const char* menu_info_type_name(menu_type_t type)
return MENU_NAME[type];
}
-void menu_info_item_update(menu_info_t* mi, uint32_t index, const char* name, const char* desc, char* tooltip, const char* icon)
+void menu_info_item_update(menu_info_t* mi, uint32_t index, const char* name,
+ const char* desc, const pa_cvolume* vol, int mute, char* tooltip,
+ const char* icon)
{
menu_info_item_t* mii = menu_info_item_get(mi, index);
if(mii == NULL)
- return menu_info_item_add(mi, index, name, desc, tooltip, icon);
+ return menu_info_item_add(mi, index, name, desc, vol, mute, tooltip, icon);
#ifdef DEBUG
- g_message("[menu_info] updating %s %u %s", menu_info_type_name(mii->menu_info->type), index, desc);
+ g_message("[menu_info] updating %s %u %s",
+ menu_info_type_name(mii->menu_info->type), index, desc);
#endif
g_free(mii->name);
mii->name = g_strdup(name);
g_free(mii->desc);
mii->desc = g_strdup(desc);
+ g_free(mii->volume);
+ mii->volume = g_memdup(vol, sizeof(pa_cvolume));
+ mii->mute = mute;
switch(mi->type)
{
@@ -175,9 +183,11 @@ void menu_info_item_update(menu_info_t* mi, uint32_t index, const char* name, co
g_hash_table_iter_init(&iter, submenu->items);
while(g_hash_table_iter_next(&iter, &key, (gpointer*)&item))
- if((subitem = g_hash_table_lookup(item->submenu->items, GUINT_TO_POINTER(mii->index))))
+ if((subitem = g_hash_table_lookup(item->submenu->items,
+ GUINT_TO_POINTER(mii->index))))
if(!g_str_equal(subitem->desc, desc))
- gtk_menu_item_set_label(GTK_MENU_ITEM(subitem->widget), desc);
+ gtk_menu_item_set_label(
+ GTK_MENU_ITEM(subitem->widget), desc);
}
break;
@@ -190,7 +200,8 @@ void menu_info_item_update(menu_info_t* mi, uint32_t index, const char* name, co
}
}
-void menu_info_item_add(menu_info_t* mi, uint32_t index, const char* name, const char* desc, char* tooltip, const char* icon)
+void menu_info_item_add(menu_info_t* mi, uint32_t index, const char* name,
+ const char* desc, const pa_cvolume* vol, int mute, char* tooltip, const char* icon)
{
menu_infos_t* mis = mi->menu_infos;
menu_info_item_t* item = g_new(menu_info_item_t, 1);
@@ -204,6 +215,8 @@ void menu_info_item_add(menu_info_t* mi, uint32_t index, const char* name, const
item->index = index;
item->name = g_strdup(name);
item->desc = g_strdup(desc);
+ item->volume = g_memdup(vol, sizeof(pa_cvolume));
+ item->mute = mute;
item->icon = g_strdup(icon);
switch(item->menu_info->type)
@@ -228,26 +241,34 @@ void menu_info_item_add(menu_info_t* mi, uint32_t index, const char* name, const
case MENU_SINK:
item->context = menu_info_item_context_menu(item);
item->widget = systray_add_radio_item(mi, desc, tooltip);
- gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item->widget), g_str_equal(mi->default_name, item->name));
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item->widget),
+ g_str_equal(mi->default_name, item->name));
systray_add_item_to_all_submenus(item, &mis->menu_info[MENU_INPUT]);
break;
case MENU_SOURCE:
item->context = menu_info_item_context_menu(item);
item->widget = systray_add_radio_item(mi, desc, tooltip);
- gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item->widget), g_str_equal(mi->default_name, item->name));
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item->widget),
+ g_str_equal(mi->default_name, item->name));
systray_add_item_to_all_submenus(item, &mis->menu_info[MENU_OUTPUT]);
break;
case MENU_INPUT:
- item->widget = systray_menu_add_submenu(mi->menu, item->submenu, desc, tooltip, icon);
+ item->widget = systray_menu_add_submenu(mi->menu, item->submenu,
+ desc, tooltip, icon);
systray_add_all_items_to_submenu(&mis->menu_info[MENU_SINK], item);
break;
case MENU_OUTPUT:
- item->widget = systray_menu_add_submenu(mi->menu, item->submenu, desc, tooltip, icon);
+ item->widget = systray_menu_add_submenu(mi->menu, item->submenu,
+ desc, tooltip, icon);
systray_add_all_items_to_submenu(&mis->menu_info[MENU_SOURCE], item);
break;
}
- g_signal_connect(item->widget, "button-press-event", G_CALLBACK(menu_info_item_clicked), item);
+ g_signal_connect(item->widget, "button-press-event",
+ G_CALLBACK(menu_info_item_clicked), item);
+ g_signal_connect(item->widget, "scroll-event",
+ G_CALLBACK(menu_info_item_scrolled), item);
+
g_hash_table_insert(mi->items, GUINT_TO_POINTER(index), item);
}
@@ -256,14 +277,16 @@ GtkMenuShell* menu_info_item_context_menu(menu_info_item_t* mii)
GtkMenuShell* menu = GTK_MENU_SHELL(gtk_menu_new());
GtkWidget* item = gtk_menu_item_new_with_label("rename");
- g_signal_connect(item, "button-press-event", G_CALLBACK(menu_info_item_rename_dialog), mii);
+ g_signal_connect(item, "button-press-event",
+ G_CALLBACK(menu_info_item_rename_dialog), mii);
gtk_menu_shell_append(menu, item);
gtk_widget_show_all(GTK_WIDGET(menu));
return menu;
}
-void menu_info_subitem_add(menu_info_t* mi, uint32_t index, const char* name, const char* desc, char* tooltip, const char* icon)
+void menu_info_subitem_add(menu_info_t* mi, uint32_t index, const char* name,
+ const char* desc, char* tooltip, const char* icon)
{
menu_info_item_t* subitem = g_new(menu_info_item_t, 1);
menu_info_item_init(subitem);
@@ -274,7 +297,8 @@ void menu_info_subitem_add(menu_info_t* mi, uint32_t index, const char* name, co
subitem->widget = systray_add_radio_item(mi, desc, tooltip);
g_hash_table_insert(mi->items, GUINT_TO_POINTER(index), subitem);
- g_signal_connect(subitem->widget, "button-press-event", G_CALLBACK(menu_info_subitem_clicked), subitem);
+ g_signal_connect(subitem->widget, "button-press-event",
+ G_CALLBACK(menu_info_subitem_clicked), subitem);
}
menu_info_item_t* menu_info_item_get(menu_info_t* mi, uint32_t index)
@@ -294,40 +318,80 @@ menu_info_item_t* menu_info_item_get_by_name(menu_info_t* mi, const char* name)
return g_hash_table_find(mi->items, name_equal, (gpointer)name);
}
-void menu_info_item_clicked(GtkWidget* item, GdkEventButton* event, menu_info_item_t* mii)
+void menu_info_item_clicked(GtkWidget* item, GdkEventButton* event,
+ menu_info_item_t* mii)
{
- /* on right-click, show context menu (if any) */
- if(event->type == GDK_BUTTON_PRESS && event->button == 3)
+#ifdef DEBUG
+ g_message("[systray] button-presss-event mod:%s button:%i",
+ (event->state & GDK_CONTROL_MASK) ? "ctrl" : "", event->button);
+#endif
+
+ switch(event->button)
{
- if(mii->context)
- gtk_menu_popup(GTK_MENU(mii->context), NULL, NULL, NULL, NULL,
- (event != NULL) ? event->button : 0,
- gdk_event_get_time((GdkEvent*)event));
- return;
+ /* on left-click, set device as default */
+ case 1:
+ pulseaudio_set_default(mii);
+ break;
+ /* on middle-click, toggle mute device/stream */
+ case 2:
+ pulseaudio_toggle_mute(mii);
+ break;
+ /* on right-click, show context menu (if any) */
+ case 3:
+ if(mii->context)
+ gtk_menu_popup(GTK_MENU(mii->context), NULL, NULL, NULL, NULL,
+ (event != NULL) ? event->button : 0,
+ gdk_event_get_time((GdkEvent*)event));
+ break;
+ }
+}
+
+void menu_info_item_scrolled(GtkWidget* item, GdkEventScroll* event,
+ menu_info_item_t* mii)
+{
+#ifdef DEBUG
+ g_message("[systray] scroll-event mod:%s dir:%s",
+ (event->state & GDK_CONTROL_MASK) ? "ctrl" : "",
+ (event->direction == GDK_SCROLL_UP) ? "up" :
+ (event->direction == GDK_SCROLL_DOWN) ? "down" :
+ (event->direction == GDK_SCROLL_LEFT) ? "left" :
+ (event->direction == GDK_SCROLL_RIGHT) ? "right" : "???");
+#endif
+
+ int inc = 0;
+
+ switch(event->direction)
+ {
+ case GDK_SCROLL_UP:
+ inc = 1;
+ break;
+ case GDK_SCROLL_DOWN:
+ inc = -1;
+ break;
+ default:
+ return;
}
switch(mii->menu_info->type)
{
case MENU_SERVER:
- /* TODO: connect to different server */
break;
case MENU_SINK:
- pulseaudio_set_sink(mii);
- break;
case MENU_SOURCE:
- pulseaudio_set_source(mii);
- break;
case MENU_INPUT:
case MENU_OUTPUT:
+ pulseaudio_volume(mii, inc);
break;
}
}
-void menu_info_subitem_clicked(GtkWidget* item, GdkEvent* event, menu_info_item_t* mii)
+void menu_info_subitem_clicked(GtkWidget* item, GdkEvent* event,
+ menu_info_item_t* mii)
{
#ifdef DEBUG
g_message("move %s %s to %s %s",
- menu_info_type_name(mii->menu_info->parent->menu_info->type), mii->menu_info->parent->desc,
+ menu_info_type_name(mii->menu_info->parent->menu_info->type),
+ mii->menu_info->parent->desc,
menu_info_type_name(mii->menu_info->type), mii->desc);
#endif
@@ -347,12 +411,15 @@ void menu_info_subitem_clicked(GtkWidget* item, GdkEvent* event, menu_info_item_
}
}
-void menu_info_item_rename_dialog(GtkWidget* item, GdkEventButton* event, menu_info_item_t* mii)
+void menu_info_item_rename_dialog(GtkWidget* item, GdkEventButton* event,
+ menu_info_item_t* mii)
{
- char* title = g_strdup_printf("Rename %s %s", menu_info_type_name(mii->menu_info->type), mii->desc);
+ char* title = g_strdup_printf("Rename %s %s",
+ menu_info_type_name(mii->menu_info->type), mii->desc);
GtkWidget* dialog = gtk_dialog_new_with_buttons(title, NULL,
- 0, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
+ 0, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL,
+ GTK_RESPONSE_REJECT, NULL);
GtkWidget* content_area = gtk_dialog_get_content_area(GTK_DIALOG (dialog));
GtkWidget* label = gtk_label_new(g_strdup_printf("%s to:", title));
@@ -369,7 +436,7 @@ void menu_info_item_rename_dialog(GtkWidget* item, GdkEventButton* event, menu_i
const char* name = gtk_entry_get_text(GTK_ENTRY(entry));
if(!g_str_equal(name, mii->desc))
- pulseaudio_rename_device(mii, name);
+ pulseaudio_rename(mii, name);
}
gtk_widget_destroy(dialog);
@@ -394,12 +461,14 @@ void menu_info_item_remove(menu_info_t* mi, uint32_t index)
break;
case MENU_SINK:
if(!mii->menu_info->parent)
- systray_remove_item_from_all_submenus(mii, &mis->menu_info[MENU_INPUT]);
+ systray_remove_item_from_all_submenus(mii,
+ &mis->menu_info[MENU_INPUT]);
systray_remove_radio_item(mi, mii->widget);
break;
case MENU_SOURCE:
if(!mii->menu_info->parent)
- systray_remove_item_from_all_submenus(mii, &mis->menu_info[MENU_OUTPUT]);
+ systray_remove_item_from_all_submenus(mii,
+ &mis->menu_info[MENU_OUTPUT]);
systray_remove_radio_item(mi, mii->widget);
break;
case MENU_INPUT:
@@ -414,6 +483,7 @@ void menu_info_item_remove(menu_info_t* mi, uint32_t index)
void menu_info_item_destroy(menu_info_item_t* mii)
{
g_free(mii->name);
+ g_free(mii->volume);
g_free(mii->icon);
g_free(mii);
}
View
26 src/menu_info.h
@@ -24,6 +24,7 @@
#include <gtk/gtk.h>
#include <stdint.h>
+#include <pulse/pulseaudio.h>
typedef enum {
MENU_SERVER = 0,
@@ -59,6 +60,8 @@ struct menu_info_item_t_ {
int index;
char* name;
char* desc;
+ pa_cvolume* volume;
+ int mute;
char* icon;
GtkWidget* widget;
menu_info_t* menu_info;
@@ -77,16 +80,27 @@ void menu_info_item_init(menu_info_item_t* mii);
void menu_info_destroy(menu_info_t* mi);
const char* menu_info_type_name(menu_type_t type);
-void menu_info_item_add(menu_info_t* mi, uint32_t index, const char* name, const char* desc, char* tooltip, const char* icon);
-void menu_info_item_update(menu_info_t* mi, uint32_t index, const char* name, const char* desc, char* tooltip, const char* icon);
+void menu_info_item_add(menu_info_t* mi, uint32_t index,
+ const char* name, const char* desc, const pa_cvolume* vol, int mute,
+ char* tooltip, const char* icon);
+void menu_info_item_update(menu_info_t* mi, uint32_t index,
+ const char* name, const char* desc, const pa_cvolume* vol, int mute,
+ char* tooltip, const char* icon);
GtkMenuShell* menu_info_item_context_menu(menu_info_item_t* mii);
-void menu_info_subitem_add(menu_info_t* mi, uint32_t index, const char* name, const char* desc, char* tooltip, const char* icon);
+void menu_info_subitem_add(menu_info_t* mi, uint32_t index, const char* name,
+ const char* desc, char* tooltip, const char* icon);
menu_info_item_t* menu_info_item_get(menu_info_t* mi, uint32_t index);
menu_info_item_t* menu_info_item_get_by_name(menu_info_t* mi, const char* name);
-void menu_info_item_clicked(GtkWidget* item, GdkEventButton* event, menu_info_item_t* mii);
-void menu_info_subitem_clicked(GtkWidget* item, GdkEvent* event, menu_info_item_t* mii);
-void menu_info_item_rename_dialog(GtkWidget* item, GdkEventButton* event, menu_info_item_t* mii);
+void menu_info_item_clicked(GtkWidget* item, GdkEventButton* event,
+ menu_info_item_t* mii);
+void menu_info_item_scrolled(GtkWidget* item, GdkEventScroll* event,
+ menu_info_item_t* mii);
+void menu_info_subitem_clicked(GtkWidget* item, GdkEvent* event,
+ menu_info_item_t* mii);
+
+void menu_info_item_rename_dialog(GtkWidget* item, GdkEventButton* event,
+ menu_info_item_t* mii);
void menu_info_item_remove(menu_info_t* mi, uint32_t index);
void menu_info_item_destroy(menu_info_item_t* mii);
View
50 src/pulseaudio.c
@@ -79,7 +79,8 @@ void context_state_cb(pa_context* c, void* userdata)
{
char* tooltip = context_info_str(context);
char* escaped = g_markup_escape_text(tooltip, -1);
- char* markup = g_strdup_printf("<span font_family=\"monospace\" font_size=\"x-small\">%s</span>", escaped);
+ char* markup = g_strdup_printf(
+ "<span font_family=\"monospace\" font_size=\"x-small\">%s</span>", escaped);
gtk_status_icon_set_tooltip_markup(mis->icon, markup);
g_free(escaped);
g_free(tooltip);
@@ -116,11 +117,16 @@ void context_state_cb(pa_context* c, void* userdata)
void subscribed_cb(pa_context* c, int success, void* userdata)
{
menu_infos_t* mis = userdata;
- pa_operation_unref(pa_context_get_server_info(c, add_server_cb, &mis->menu_info[MENU_SERVER]));
- pa_operation_unref(pa_context_get_sink_info_list(c, add_sink_cb, &mis->menu_info[MENU_SINK]));
- pa_operation_unref(pa_context_get_source_info_list(c, add_source_cb, &mis->menu_info[MENU_SOURCE]));
- pa_operation_unref(pa_context_get_sink_input_info_list(c, add_sink_input_cb, &mis->menu_info[MENU_INPUT]));
- pa_operation_unref(pa_context_get_source_output_info_list(c, add_source_output_cb, &mis->menu_info[MENU_OUTPUT]));
+ pa_operation_unref(pa_context_get_server_info(c,
+ add_server_cb, &mis->menu_info[MENU_SERVER]));
+ pa_operation_unref(pa_context_get_sink_info_list(c,
+ add_sink_cb, &mis->menu_info[MENU_SINK]));
+ pa_operation_unref(pa_context_get_source_info_list(c,
+ add_source_cb, &mis->menu_info[MENU_SOURCE]));
+ pa_operation_unref(pa_context_get_sink_input_info_list(c,
+ add_sink_input_cb, &mis->menu_info[MENU_INPUT]));
+ pa_operation_unref(pa_context_get_source_output_info_list(c,
+ add_source_output_cb, &mis->menu_info[MENU_OUTPUT]));
}
void event_cb(pa_context* c, pa_subscription_event_type_t t, uint32_t index, void* userdata)
@@ -141,19 +147,24 @@ void event_cb(pa_context* c, pa_subscription_event_type_t t, uint32_t index, voi
switch(facility)
{
case PA_SUBSCRIPTION_EVENT_SERVER:
- pa_operation_unref(pa_context_get_server_info(c, add_server_cb, &mis->menu_info[MENU_SERVER]));
+ pa_operation_unref(pa_context_get_server_info(c,
+ add_server_cb, &mis->menu_info[MENU_SERVER]));
break;
case PA_SUBSCRIPTION_EVENT_SINK:
- pa_operation_unref(pa_context_get_sink_info_by_index(c, index, add_sink_cb, &mis->menu_info[MENU_SINK]));
+ pa_operation_unref(pa_context_get_sink_info_by_index(c,
+ index, add_sink_cb, &mis->menu_info[MENU_SINK]));
break;
case PA_SUBSCRIPTION_EVENT_SOURCE:
- pa_operation_unref(pa_context_get_source_info_by_index(c, index, add_source_cb, &mis->menu_info[MENU_SOURCE]));
+ pa_operation_unref(pa_context_get_source_info_by_index(c,
+ index, add_source_cb, &mis->menu_info[MENU_SOURCE]));
break;
case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
- pa_operation_unref(pa_context_get_sink_input_info(c, index, add_sink_input_cb, &mis->menu_info[MENU_INPUT]));
+ pa_operation_unref(pa_context_get_sink_input_info(c, index,
+ add_sink_input_cb, &mis->menu_info[MENU_INPUT]));
break;
case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
- pa_operation_unref(pa_context_get_source_output_info(c, index, add_source_output_cb, &mis->menu_info[MENU_OUTPUT]));
+ pa_operation_unref(pa_context_get_source_output_info(c, index,
+ add_source_output_cb, &mis->menu_info[MENU_OUTPUT]));
break;
default:
break;
@@ -212,7 +223,7 @@ void add_server_cb(pa_context* c, const pa_server_info* i, void* userdata)
{
menu_info_t* mi = userdata;
char* tooltip = server_info_str(i);
- menu_info_item_update(mi, 0, NULL, i->host_name, tooltip, NULL);
+ menu_info_item_update(mi, 0, NULL, i->host_name, NULL, 0, tooltip, NULL);
g_free(tooltip);
/* set default sink/source */
@@ -235,7 +246,8 @@ void add_sink_cb(pa_context* c, const pa_sink_info* i, int is_last, void* userda
{
if(is_last < 0)
{
- g_message("Failed to get sink information: %s", pa_strerror(pa_context_errno(c)));
+ g_message("Failed to get sink information: %s",
+ pa_strerror(pa_context_errno(c)));
return;
}
@@ -244,7 +256,8 @@ void add_sink_cb(pa_context* c, const pa_sink_info* i, int is_last, void* userda
menu_info_t* mi = userdata;
char* tooltip = sink_info_str(i);
- menu_info_item_update(mi, i->index, i->name, i->description, tooltip, NULL);
+ menu_info_item_update(mi, i->index, i->name, i->description, &i->volume,
+ i->mute, tooltip, NULL);
g_free(tooltip);
}
@@ -267,7 +280,8 @@ void add_source_cb(pa_context* c, const pa_source_info* i, int is_last, void* us
menu_info_t* mi = userdata;
char* tooltip = source_info_str(i);
- menu_info_item_update(mi, i->index, i->name, i->description, tooltip, NULL);
+ menu_info_item_update(mi, i->index, i->name, i->description, &i->volume,
+ i->mute, tooltip, NULL);
g_free(tooltip);
}
@@ -292,7 +306,8 @@ void add_sink_input_cb(pa_context* c, const pa_sink_input_info* i, int is_last,
menu_info_t* mi = userdata;
char* tooltip = input_info_str(i);
- menu_info_item_update(mi, i->index, NULL, app_name ? app_name : i->name, tooltip, app_icon);
+ menu_info_item_update(mi, i->index, NULL, app_name ? app_name : i->name,
+ &i->volume, i->mute, tooltip, app_icon);
g_free(tooltip);
}
@@ -317,7 +332,8 @@ void add_source_output_cb(pa_context* c, const pa_source_output_info* i, int is_
menu_info_t* mi = userdata;
char* tooltip = output_info_str(i);
- menu_info_item_update(mi, i->index, NULL, app_name ? app_name : i->name, tooltip, app_icon);
+ menu_info_item_update(mi, i->index, NULL, app_name ? app_name : i->name,
+ &i->volume, i->mute, tooltip, app_icon);
g_free(tooltip);
}
View
142 src/pulseaudio_action.c
@@ -20,36 +20,56 @@
***/
#include "pulseaudio_action.h"
+
+#include <pulse/volume.h>
#include <pulse/ext-device-manager.h>
extern pa_context* context;
-void pulseaudio_set_sink(menu_info_item_t* mii)
+void pulseaudio_set_default(menu_info_item_t* mii)
{
- pa_operation_unref(pa_context_set_default_sink(context, mii->name, pulseaudio_success_cb, mii));
-}
+ pa_operation* o;
-void pulseaudio_set_source(menu_info_item_t* mii)
-{
- pa_operation_unref(pa_context_set_default_source(context, mii->name, pulseaudio_success_cb, mii));
+ switch(mii->menu_info->type)
+ {
+ case MENU_SERVER:
+ /* TODO: set X property PULSE_SERVER to hostname */
+ break;
+ case MENU_SINK:
+ o = pa_context_set_default_sink(context, mii->name,
+ pulseaudio_set_default_success_cb, mii);
+ break;
+ case MENU_SOURCE:
+ o = pa_context_set_default_source(context, mii->name,
+ pulseaudio_set_default_success_cb, mii);
+ break;
+ case MENU_INPUT:
+ case MENU_OUTPUT:
+ /* nothing to do here */
+ break;
+ }
+ pa_operation_unref(o);
}
-void pulseaudio_success_cb(pa_context *c, int success, void *userdata)
+void pulseaudio_set_default_success_cb(pa_context *c, int success, void *userdata)
{
menu_info_item_t* mii = userdata;
if(!success)
- g_message("failed to set %s \"%s\"!\n", menu_info_type_name(mii->menu_info->type), mii->name);
+ g_error("failed to set default to %s \"%s\"!\n",
+ menu_info_type_name(mii->menu_info->type), mii->name);
}
void pulseaudio_move_input_to_sink(menu_info_item_t* input, menu_info_item_t* sink)
{
- pa_operation_unref(pa_context_move_sink_input_by_index(context, input->index, sink->index, pulseaudio_move_success_cb, input));
+ pa_operation_unref(pa_context_move_sink_input_by_index(context, input->index,
+ sink->index, pulseaudio_move_success_cb, input));
}
void pulseaudio_move_output_to_source(menu_info_item_t* output, menu_info_item_t* source)
{
- pa_operation_unref(pa_context_move_source_output_by_index(context, output->index, source->index, pulseaudio_move_success_cb, output));
+ pa_operation_unref(pa_context_move_source_output_by_index(context, output->index,
+ source->index, pulseaudio_move_success_cb, output));
}
void pulseaudio_move_success_cb(pa_context *c, int success, void *userdata)
@@ -58,12 +78,12 @@ void pulseaudio_move_success_cb(pa_context *c, int success, void *userdata)
menu_info_item_t* from = to->menu_info->parent;
if(!success)
- g_message("failed to move %s \"%s\" to %s \"%s\"!\n",
+ g_error("failed to move %s \"%s\" to %s \"%s\"!\n",
menu_info_type_name(from->menu_info->type), from->name,
menu_info_type_name(to->menu_info->type), to->name);
}
-void pulseaudio_rename_device(menu_info_item_t* mii, const char* name)
+void pulseaudio_rename(menu_info_item_t* mii, const char* name)
{
#ifdef DEBUG
g_message("rename %s %s to %s",
@@ -73,9 +93,105 @@ void pulseaudio_rename_device(menu_info_item_t* mii, const char* name)
pa_operation* o;
if(!(o = pa_ext_device_manager_set_device_description(context, key, name, NULL, NULL))) {
- g_message("pa_ext_device_manager_set_device_description(context, %s, %s) failed", key, name);
+ g_error("pa_ext_device_manager_set_device_description(context, %s, %s) failed", key, name);
return;
}
pa_operation_unref(o);
}
+void pulseaudio_volume(menu_info_item_t* mii, int inc)
+{
+#ifdef DEBUG
+ g_message("pulseaudio_volume(%s, %i)", mii->name, inc);
+#endif
+
+ /* increment/decrement in 2% steps */
+
+ pa_cvolume* volume;
+ if(inc < 0)
+ volume = pa_cvolume_dec(mii->volume, -inc * PA_VOLUME_NORM / 50);
+ else if(inc > 0)
+ volume = pa_cvolume_inc(mii->volume, inc * PA_VOLUME_NORM / 50);
+ else
+ return;
+
+ pa_operation* o = NULL;
+
+ switch(mii->menu_info->type)
+ {
+ case MENU_SERVER:
+ /* TODO: set X property PULSE_SERVER to hostname */
+ break;
+ case MENU_SINK:
+ o = pa_context_set_sink_volume_by_index(context, mii->index,
+ volume, pulseaudio_set_volume_success_cb, mii);
+ break;
+ case MENU_SOURCE:
+ o = pa_context_set_source_volume_by_index(context, mii->index,
+ volume, pulseaudio_set_volume_success_cb, mii);
+ break;
+ case MENU_INPUT:
+ o = pa_context_set_sink_input_volume(context, mii->index,
+ volume, pulseaudio_set_volume_success_cb, mii);
+ break;
+ case MENU_OUTPUT:
+ o = pa_context_set_source_output_volume(context, mii->index,
+ volume, pulseaudio_set_volume_success_cb, mii);
+ break;
+ }
+ pa_operation_unref(o);
+}
+
+void pulseaudio_set_volume_success_cb(pa_context *c, int success, void *userdata)
+{
+ menu_info_item_t* mii = userdata;
+
+ if(!success)
+ g_error("failed to set volume for %s \"%s\"!\n",
+ menu_info_type_name(mii->menu_info->type), mii->name);
+}
+
+void pulseaudio_toggle_mute(menu_info_item_t* mii)
+{
+#ifdef DEBUG
+ g_message("pulseaudio_toggle_mute(%s)", mii->name);
+#endif
+
+ pa_operation* o = NULL;
+
+ int mute = (mii->mute) ? 0 : 1;
+
+ switch(mii->menu_info->type)
+ {
+ case MENU_SERVER:
+ /* nothing to do here */
+ break;
+ case MENU_SINK:
+ o = pa_context_set_sink_mute_by_index(context, mii->index,
+ mute, pulseaudio_set_volume_success_cb, mii);
+ break;
+ case MENU_SOURCE:
+ o = pa_context_set_source_mute_by_index(context, mii->index,
+ mute, pulseaudio_set_volume_success_cb, mii);
+ break;
+ case MENU_INPUT:
+ o = pa_context_set_sink_input_mute(context, mii->index,
+ mute, pulseaudio_set_volume_success_cb, mii);
+ break;
+ case MENU_OUTPUT:
+ o = pa_context_set_source_output_mute(context, mii->index,
+ mute, pulseaudio_set_volume_success_cb, mii);
+ break;
+ }
+ pa_operation_unref(o);
+}
+
+void pulseaudio_toggle_mute_success_cb(pa_context *c, int success, void *userdata)
+{
+ menu_info_item_t* mii = userdata;
+
+ if(!success)
+ g_error("failed to toogle mute for %s \"%s\"!\n",
+ menu_info_type_name(mii->menu_info->type), mii->name);
+}
+
View
12 src/pulseaudio_action.h
@@ -25,14 +25,18 @@
#include <pulse/pulseaudio.h>
#include "menu_info.h"
-void pulseaudio_set_sink(menu_info_item_t* mii);
-void pulseaudio_set_source(menu_info_item_t* mii);
-void pulseaudio_success_cb(pa_context *c, int success, void *userdata);
+void pulseaudio_set_default(menu_info_item_t* mii);
+void pulseaudio_set_default_success_cb(pa_context *c, int success, void *userdata);
void pulseaudio_move_input_to_sink(menu_info_item_t* input, menu_info_item_t* sink);
void pulseaudio_move_output_to_source(menu_info_item_t* output, menu_info_item_t* source);
void pulseaudio_move_success_cb(pa_context *c, int success, void *userdata);
-void pulseaudio_rename_device(menu_info_item_t* mii, const char* name);
+void pulseaudio_rename(menu_info_item_t* mii, const char* name);
+
+void pulseaudio_volume(menu_info_item_t* mii, int inc);
+void pulseaudio_set_volume_success_cb(pa_context *c, int success, void *userdata);
+void pulseaudio_toggle_mute(menu_info_item_t* mii);
+void pulseaudio_toggle_mute_success_cb(pa_context *c, int success, void *userdata);
#endif /* PASYSTRAY_PULSEAUDIO_ACTION_H */
View
46 src/systray.c
@@ -21,12 +21,14 @@
#include "systray.h"
#include "config.h"
+#include "pulseaudio_action.h"
void systray_create(menu_infos_t* mis)
{
mis->icon = gtk_status_icon_new_from_icon_name("pasystray");
systray_menu_create(mis);
g_signal_connect(mis->icon, "button-press-event", G_CALLBACK(systray_click_cb), mis);
+ g_signal_connect(mis->icon, "scroll-event", G_CALLBACK(systray_scroll_cb), mis);
gtk_status_icon_set_tooltip_text(mis->icon, "connecting to server...");
gtk_status_icon_set_visible(mis->icon, TRUE);
}
@@ -54,7 +56,7 @@ void systray_menu_create(menu_infos_t* mis)
systray_menu_add_application(mis->menu, "_Volume Meter (Recording)...", NULL, COMMAND_PAVUMETER_REC);
systray_menu_add_application(mis->menu, "_Configure Local Sound Server...", NULL, COMMAND_PAPREFS);
- /*
+ /* TODO: settings
systray_menu_add_separator(mis->menu);
item = append_menuitem(mis->menu, "_Preferences...", "gtk-preferences");
g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(show_preferences), NULL);
@@ -269,7 +271,46 @@ GtkWidget* systray_menu_item_quit()
void systray_click_cb(GtkStatusIcon* icon, GdkEventButton* ev, gpointer userdata)
{
menu_infos_t* mis = userdata;
- gtk_menu_popup(GTK_MENU(mis->menu), NULL, NULL, gtk_status_icon_position_menu, icon, ev->button, ev->time);
+
+ switch(ev->button)
+ {
+ case 1:
+ case 3:
+ gtk_menu_popup(GTK_MENU(mis->menu), NULL, NULL, gtk_status_icon_position_menu, icon, ev->button, ev->time);
+ break;
+ case 2:
+ {
+ menu_info_t* mi = &mis->menu_info[MENU_SINK];
+ menu_info_item_t* mii = menu_info_item_get_by_name(mi, mi->default_name);
+ if(mii)
+ pulseaudio_toggle_mute(mii);
+ }
+ break;
+ }
+}
+
+void systray_scroll_cb(GtkStatusIcon* icon, GdkEventScroll* ev, gpointer userdata)
+{
+ int inc = 0;
+
+ switch(ev->direction)
+ {
+ case GDK_SCROLL_UP:
+ inc = 1;
+ break;
+ case GDK_SCROLL_DOWN:
+ inc = -1;
+ break;
+ default:
+ return;
+ }
+
+ menu_infos_t* mis = userdata;
+ menu_info_t* mi = &mis->menu_info[(ev->state & GDK_CONTROL_MASK) ? MENU_SOURCE : MENU_SINK];
+ menu_info_item_t* mii = menu_info_item_get_by_name(mi, mi->default_name);
+
+ if(mii)
+ pulseaudio_volume(mii, inc);
}
void start_application_cb(GtkMenuItem* item, const char* command)
@@ -285,4 +326,3 @@ void systray_set_tooltip(GtkWidget* item, const char* tooltip)
g_free(escaped);
g_free(markup);
}
-
View
1  src/systray.h
@@ -52,6 +52,7 @@ void systray_about_dialog();
GtkWidget* systray_menu_item_quit();
void systray_click_cb(GtkStatusIcon* icon, GdkEventButton* ev, gpointer userdata);
+void systray_scroll_cb(GtkStatusIcon* icon, GdkEventScroll* ev, gpointer userdata);
void start_application_cb(GtkMenuItem* menuitem, const char* command);
void systray_set_tooltip(GtkWidget* item, const char* tooltip);
Please sign in to comment.
Something went wrong with that request. Please try again.