Hello community, here is the log from the commit of package pasystray for openSUSE:Factory checked in at 2016-07-20 09:24:26 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/pasystray (Old) and /work/SRC/openSUSE:Factory/.pasystray.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "pasystray" Changes: -------- --- /work/SRC/openSUSE:Factory/pasystray/pasystray.changes 2016-01-12 16:13:33.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.pasystray.new/pasystray.changes 2016-07-20 09:24:28.000000000 +0200 @@ -1,0 +2,33 @@ +Mon Jul 18 11:42:38 UTC 2016 - [email protected] + +- Version bump to 0.6.0: + * start pavucontrol with ctrl-click on status icon + * update systray icon on default sink change + * add context menu option to move all in/outputs to sink/source + * update the volume icon of non-default sinks + * To fix notifications for changes of their volume level + * possible to set the volume icon for notifications independent of the tray icon + * use gauges for volume notifications + * set notification icon when changing systray icon + * send notifications only on volume / mute changes + * add option to always send notifications on volume change + * log systray implementation + * add option to include monitors + * support disabling status icon support + * include volume and muted state in item name + * set notification urgency to low + * minor Housekeeping for README + * deprecate --max-volume in favor of --volume-max + * add option to disable all notifications + * re-add volume-max option handling + * update manpage with --volume-inc + * add option to set volume increment + * add TODO entries for feature requests + * stop using stock GtkButton + * check mii only where needed + * start pavucontrol with ctrl-click on status icon + * pasystray.desktop: Add missing semicolon to "Keywords" + +- Removed patch icon_keywords_fix.patch (fixed in upstream) + +------------------------------------------------------------------- Old: ---- icon_keywords_fix.patch pasystray-0.5.2.tar.gz New: ---- pasystray-0.6.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ pasystray.spec ++++++ --- /var/tmp/diff_new_pack.Ar81tO/_old 2016-07-20 09:24:29.000000000 +0200 +++ /var/tmp/diff_new_pack.Ar81tO/_new 2016-07-20 09:24:29.000000000 +0200 @@ -22,16 +22,15 @@ %define build_wayland_backend 1 %endif Name: pasystray -Version: 0.5.2 +Version: 0.6.0 Release: 0 Summary: PulseAudio system tray License: LGPL-2.1+ Group: System/GUI/Other Url: https://github.com/christophgysin/pasystray Source: https://github.com/christophgysin/pasystray/archive/pasystray-%{version}.tar.gz -# pasystray.desktop: Add missing semicolon to "Keywords" -Patch0: icon_keywords_fix.patch BuildRequires: automake +BuildRequires: pkgconfig BuildRequires: update-desktop-files BuildRequires: pkgconfig(avahi-glib) BuildRequires: pkgconfig(avahi-ui) @@ -65,7 +64,6 @@ %prep %setup -q -n %{name}-%{name}-%{version} -%patch0 -p1 %build autoreconf -fi @@ -73,7 +71,7 @@ make %{?_smp_mflags} %install -make DESTDIR=%{buildroot} install %{?_smp_mflags} +make %{?_smp_mflags} DESTDIR=%{buildroot} install %suse_update_desktop_file -u -r %{buildroot}%{_datadir}/applications/pasystray.desktop AudioVideo Mixer %suse_update_desktop_file -u -r %{buildroot}%{_sysconfdir}/xdg/autostart/pasystray.desktop AudioVideo Mixer @@ -85,7 +83,8 @@ %{_bindir}/pasystray %{_datadir}/applications/pasystray.desktop %{_datadir}/icons/hicolor/scalable/apps/pasystray.svg -%{_mandir}/man1/pasystray.1.gz +%{_mandir}/man1/pasystray.1%{ext_man} %{_datadir}/pasystray/pasystray.glade %{_datadir}/pixmaps/pasystray.png +%changelog ++++++ pasystray-0.5.2.tar.gz -> pasystray-0.6.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/.travis.sh new/pasystray-pasystray-0.6.0/.travis.sh --- old/pasystray-pasystray-0.5.2/.travis.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/pasystray-pasystray-0.6.0/.travis.sh 2016-07-17 12:41:33.000000000 +0200 @@ -0,0 +1,14 @@ +#!/bin/bash +set -euo pipefail + +export CC=${USE_CC:-$CC} + +$CC --version + +aclocal +autoconf +autoheader +automake --add-missing +./configure ${EXTRA_CONF:-} || (cat config.log; exit 1) +make +make test diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/.travis.yml new/pasystray-pasystray-0.6.0/.travis.yml --- old/pasystray-pasystray-0.5.2/.travis.yml 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/.travis.yml 2016-07-17 12:41:33.000000000 +0200 @@ -1,9 +1,22 @@ +addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + packages: + - gcc-4.9 + - clang-3.7 + - libgtk-3-dev + - libpulse-dev + - libnotify-dev + - libappindicator3-dev language: c -before_install: - - sudo apt-get update -qq - - sudo apt-get install -qq libgtk-3-dev libpulse-dev libavahi-client-dev libavahi-glib-dev libnotify-dev libappindicator3-dev -before_script: - - aclocal - - autoconf - - autoheader - - automake --add-missing +script: ./.travis.sh +env: + - CFLAGS=--std=c99 + - CFLAGS=--std=c99 EXTRA_CONF=--with-gtk=2 + - USE_CC=gcc-4.9 CFLAGS=--std=c99 + - USE_CC=gcc-4.9 CFLAGS=--std=c11 + - USE_CC=clang-3.7 CFLAGS=--std=c99 + - USE_CC=clang-3.7 CFLAGS=--std=c11 +sudo: false diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/README.md new/pasystray-pasystray-0.6.0/README.md --- old/pasystray-pasystray-0.5.2/README.md 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/README.md 2016-07-17 12:41:33.000000000 +0200 @@ -1,10 +1,10 @@ -PulseAudio system tray +PulseAudio System Tray ====================== [](https://travis-ci.org/christophgysin/pasystray) -A replacement for the deprecated padevchooser +A replacement for the deprecated padevchooser. -Pasystray allows setting the default PulseAudio source/sink and moving +pasystray allows setting the default PulseAudio source/sink and moving streams on the fly between sources/sinks without restarting the client applications. @@ -12,13 +12,11 @@ -------- * switch default sink/source -* move playback/record stream to different sink/source on the fly +* move playback/record stream to a different sink/source on the fly * detect pulseaudio instances on the network with avahi * set X property PULSE_SERVER (like padevchooser's "set default server") * adjust volume/toggle mute of sinks/sources and playback/record streams -* rename devices - -Renaming devices needs module-device-manager to be loaded in pulseaudio. +* rename devices (pulseaudio must have module-device-manager loaded) To detect remote sinks/sources you need to enable module-zeroconf-discover on the local PulseAudio instance and module-zeroconf-publish on the remote side. @@ -28,10 +26,12 @@ $ PULSE_SERVER=remote_host pasystray ``` -Mouse bindings +Mouse Bindings -------------- over status icon: +* left/right-click: open menu +* ctrl + left-click: start pavucontrol * middle-click / alt + left-click: toggle mute default sink * ctrl + middle-click / ctrl + alt + left-click: toggle mute default source * scroll up/down: adjust the default sink volume @@ -50,9 +50,9 @@ Troubleshooting --------------- -If pasystray icon is not displayed in your Unity system tray, you will have +If the pasystray icon is not displayed in your Unity system tray, you will have to whitelist it. Read this for instructions: http://askubuntu.com/questions/30742/how-do-i-access-and-enable-more-icons-to-be-in-the-system-tray -For ubuntu 13.04 and above, AppIndicator is mandatory. Unfortunatly, the -ctrl-click/ctrl-scroll bindings don't work with AppIndicator. +For Ubuntu 13.04 and above, AppIndicator is mandatory. Unfortunately, the +ctrl + click / ctrl + scroll bindings don't work with AppIndicator. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/TODO new/pasystray-pasystray-0.6.0/TODO --- old/pasystray-pasystray-0.5.2/TODO 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/TODO 2016-07-17 12:41:33.000000000 +0200 @@ -1,3 +1,4 @@ +TODO: verify all mouse bindings works BUGS: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/configure.ac new/pasystray-pasystray-0.6.0/configure.ac --- old/pasystray-pasystray-0.5.2/configure.ac 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/configure.ac 2016-07-17 12:41:33.000000000 +0200 @@ -1,6 +1,6 @@ # This file is part of PaSystray # -# Copyright (C) 2011-2015 Christoph Gysin +# Copyright (C) 2011-2016 Christoph Gysin # # PaSystray is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as @@ -19,7 +19,7 @@ AC_PREREQ([2.68]) -AC_INIT([pasystray], [0.5.2], [[email protected]], [pasystray], +AC_INIT([pasystray], [0.6.0], [[email protected]], [pasystray], [http://github.com/christophgysin/pasystray]) AC_CONFIG_SRCDIR([src/pasystray.c]) AC_CONFIG_HEADERS([src/config.h]) @@ -38,6 +38,7 @@ AC_MSG_RESULT($GTK_VERSION) PKG_CHECK_MODULES(GTK, [ $GTK_VERSION ]) +AC_DEFINE_UNQUOTED(GTK_VERSION_MAJOR, $with_gtk, [Have GTK version?]) AC_SUBST(GTK_CFLAGS) AC_SUBST(GTK_LIBS) @@ -100,12 +101,28 @@ AS_IF([test "x$HAVE_X11" = x1], AC_DEFINE([HAVE_X11], 1, [Have X11?])) +### optional gtk stausicon support ########################################### +AC_ARG_ENABLE([statusicon], + AS_HELP_STRING([--disable-statusicon], [Disable optional statusicon support])) + +AS_IF([test "x$enable_statusicon" != xno], + HAVE_STATUSICON=1, HAVE_STATUSICON=0) + +AC_SUBST(HAVE_STATUSICON) +AM_CONDITIONAL([HAVE_STATUSICON], [test "x$HAVE_STATUSICON" = x1]) +AS_IF([test "x$HAVE_STATUSICON" = x1], AC_DEFINE([HAVE_STATUSICON], 1, + [Have StatusIcon?])) + ### optional libappindicator support ########################################### AC_ARG_ENABLE([appindicator], AS_HELP_STRING([--disable-appindicator], [Disable optional appindicator support])) +case ${with_gtk} in + 2) APPINDICATOR_VERSION=appindicator-0.1;; + 3) APPINDICATOR_VERSION=appindicator3-0.1;; +esac AS_IF([test "x$enable_appindicator" != xno], - [PKG_CHECK_MODULES(APPINDICATOR, [ appindicator3-0.1 ], HAVE_APPINDICATOR=1, + [PKG_CHECK_MODULES(APPINDICATOR, [ $APPINDICATOR_VERSION ], HAVE_APPINDICATOR=1, HAVE_APPINDICATOR=0)], HAVE_APPINDICATOR=0) AS_IF([test "x$enable_appindicator" = xyes && test "x$HAVE_APPINDICATOR" = x0], @@ -116,7 +133,7 @@ AC_SUBST(HAVE_APPINDICATOR) AM_CONDITIONAL([HAVE_APPINDICATOR], [test "x$HAVE_APPINDICATOR" = x1]) AS_IF([test "x$HAVE_APPINDICATOR" = x1], AC_DEFINE([HAVE_APPINDICATOR], 1, - [Have APPINDICATOR?])) + [Have AppIndicator?])) ################################################################################ if test "x$GCC" = xyes -o "x$CLANG" = xyes; then diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/data/pasystray.desktop new/pasystray-pasystray-0.6.0/data/pasystray.desktop --- old/pasystray-pasystray-0.5.2/data/pasystray.desktop 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/data/pasystray.desktop 2016-07-17 12:41:33.000000000 +0200 @@ -8,4 +8,4 @@ StartupNotify=true Type=Application Categories=AudioVideo;Audio; -Keywords=pulseaudio;tray;system tray;applet;volume +Keywords=pulseaudio;tray;system tray;applet;volume; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/man/pasystray.1 new/pasystray-pasystray-0.6.0/man/pasystray.1 --- old/pasystray-pasystray-0.5.2/man/pasystray.1 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/man/pasystray.1 2016-07-17 12:41:33.000000000 +0200 @@ -94,8 +94,20 @@ .B \-d, \-\-debug Print debugging information. .TP -.B \-m, \-\-max-volume=N +.B \-m, \-\-volume-max=N Set the maximum volume (in percent). +.TP +.B \-i, \-\-volume-inc=N +Set the volume increment. +.TP +.B \-n, \-\-no-notify +Disable all notifications. +.TP +.B \-a, \-\-always-notify +Enable notifications for all changes in pulsaudio. +.TP +.B \-\-include-monitors +Show monitor sources. .SH SEE ALSO .BR pulseaudio (1), .BR pactl (1). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/scripts/ubuntu-build-deps.sh new/pasystray-pasystray-0.6.0/scripts/ubuntu-build-deps.sh --- old/pasystray-pasystray-0.5.2/scripts/ubuntu-build-deps.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/pasystray-pasystray-0.6.0/scripts/ubuntu-build-deps.sh 2016-07-17 12:41:33.000000000 +0200 @@ -0,0 +1,4 @@ +apt-get install \ + build-essential automake autoconf pkg-config \ + libgtk-3-dev libpulse-dev libpulse-mainloop-glib0 \ + libnotify-dev libavahi-glib-dev libappindicator3-dev diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/src/menu_info.c new/pasystray-pasystray-0.6.0/src/menu_info.c --- old/pasystray-pasystray-0.5.2/src/menu_info.c 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/src/menu_info.c 2016-07-17 12:41:33.000000000 +0200 @@ -19,6 +19,7 @@ USA. ***/ +#include <string.h> #include <glib.h> #include "menu_info.h" @@ -189,6 +190,30 @@ return -1; } +char* menu_info_item_label(menu_info_item_t* mii) +{ + gchar* desc = mii->desc; + + const size_t DESC_MAX = 80; + gchar desc_buf[DESC_MAX + 1]; + if (strlen(mii->desc) > DESC_MAX) + { + g_snprintf(desc_buf, DESC_MAX+1, "%.*s...", (int)DESC_MAX-3, mii->desc); + desc = desc_buf; + } + + if(!mii->volume) + return g_strdup(desc); + + char vol_buf[PA_CVOLUME_SNPRINT_MAX]; + gchar* label = g_strdup_printf("%s %s%s", + desc, + pa_volume_snprint(vol_buf, sizeof(vol_buf), mii->volume->values[0]), + mii->mute ? " [muted]" : ""); + + return label; +} + 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, const char* address, uint32_t target) @@ -206,13 +231,22 @@ return; } + menu_infos_t* mis = item->menu_info->menu_infos; + g_debug("[menu_info] updating %s %u %s (target: %d)", menu_info_type_name(item->menu_info->type), index, desc, (int)target); g_free(item->name); item->name = g_strdup(name); + g_free(item->desc); item->desc = g_strdup(desc); + + /* only notify on volume / mute changes */ + int notify = 0; + if ((vol && !pa_cvolume_equal(item->volume, vol)) || mute != item->mute) + notify = 1; + g_free(item->volume); item->volume = g_memdup(vol, sizeof(pa_cvolume)); item->mute = mute; @@ -223,7 +257,10 @@ menu_type_t submenu_type = menu_info_submenu_type(mi->type); menu_info_t* submenu = &mi->menu_infos->menu_info[submenu_type]; - gtk_menu_item_set_label(GTK_MENU_ITEM(item->widget), desc); + gchar* label = menu_info_item_label(item); + gtk_menu_item_set_label(GTK_MENU_ITEM(item->widget), label); + g_free(label); + systray_set_tooltip(GTK_WIDGET(item->widget), tooltip); switch(mi->type) @@ -231,10 +268,11 @@ case MENU_SERVER: case MENU_MODULE: g_debug("[menu_info] *** unhandled %s update! (index: %u, desc: %s)", - menu_info_type_name(mi->type), index, desc); + menu_info_type_name(mi->type), index, item->desc); break; case MENU_SINK: case MENU_SOURCE: + ui_set_volume_icon(item); // update sink item systray_update_item_in_all_submenus(item, submenu); break; case MENU_INPUT: @@ -246,6 +284,9 @@ /* if this is the default sink, update status icon acording to volume */ if(mi->type == MENU_SINK && item == menu_info_item_get_by_name(mi, mi->default_name)) ui_update_systray_icon(item); + + if(notify && mis->settings.notify == NOTIFY_ALWAYS) + pulseaudio_update_volume_notification(item); } void menu_info_item_add(menu_info_t* mi, uint32_t index, const char* name, @@ -286,7 +327,7 @@ switch(mi->type) { case MENU_SERVER: - item->widget = systray_add_radio_item(mi, desc, tooltip); + item->widget = systray_add_radio_item(item, tooltip); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item->widget), (item->address == mi->default_name) || (item->address && mi->default_name && @@ -295,20 +336,24 @@ case MENU_SINK: case MENU_SOURCE: item->context = menu_info_item_context_menu(item); - item->widget = systray_add_radio_item(mi, desc, tooltip); + item->widget = systray_add_radio_item(item, tooltip); 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, submenu); break; case MENU_INPUT: case MENU_OUTPUT: + { + gchar* label = menu_info_item_label(item); item->widget = systray_menu_add_submenu(mi->menu, item->submenu, - desc, tooltip, icon); + label, tooltip, icon); + g_free(label); systray_add_all_items_to_submenu(submenu, item); break; + } case MENU_MODULE: item->context = menu_info_item_context_menu(item); - item->widget = systray_add_menu_item(mi, desc, tooltip, icon); + item->widget = systray_add_menu_item(mi, item->desc, tooltip, icon); break; } @@ -342,19 +387,30 @@ case MENU_SINK: case MENU_SOURCE: + { + menu_type_t type = (mii->menu_info->type == MENU_SINK) ? MENU_INPUT : MENU_OUTPUT; + gchar* label = g_strdup_printf("move all %ss here", + menu_info_type_name(type)); + item = gtk_menu_item_new_with_label(label); + g_free(label); + g_signal_connect(item, "button-press-event", + G_CALLBACK(menu_info_item_move_all_cb), mii); + gtk_menu_shell_append(menu, item); + item = gtk_menu_item_new_with_label("rename"); g_signal_connect(item, "button-press-event", G_CALLBACK(menu_info_item_rename_cb), mii); + gtk_menu_shell_append(menu, item); break; - + } case MENU_MODULE: item = gtk_menu_item_new_with_label("unload"); g_signal_connect(item, "button-press-event", G_CALLBACK(menu_info_module_unload_cb), mii); + gtk_menu_shell_append(menu, item); break; } - gtk_menu_shell_append(menu, item); gtk_widget_show_all(GTK_WIDGET(menu)); return menu; } @@ -368,7 +424,7 @@ subitem->name = g_strdup(name); subitem->desc = g_strdup(desc); subitem->menu_info = mi; - subitem->widget = systray_add_radio_item(mi, desc, tooltip); + subitem->widget = systray_add_radio_item(subitem, tooltip); gboolean active = mi->parent->target == index; gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(subitem->widget), active); @@ -395,8 +451,10 @@ g_debug("[menu_info] updating subitem %s %u '%s' %s", menu_info_type_name(mi->type), index, desc, active ? " (active)" : ""); - if(!g_str_equal(item->desc, desc)) - gtk_menu_item_set_label(GTK_MENU_ITEM(item->widget), desc); + gchar* label = menu_info_item_label(item); + gtk_menu_item_set_label(GTK_MENU_ITEM(item->widget), label); + g_free(label); + if(active) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item->widget), TRUE); } @@ -433,8 +491,10 @@ void menu_info_item_clicked(GtkWidget* item, GdkEventButton* event, menu_info_item_t* mii) { - g_debug("[systray] button-press-event mod:%s button:%i", - (event->state & GDK_CONTROL_MASK) ? "ctrl" : "", event->button); + g_debug("[menu_info] item clicked mod:%s%s button:%i", + (event->state & GDK_CONTROL_MASK) ? "[ctrl]" : "", + (event->state & GDK_MOD1_MASK) ? "[alt]" : "", + event->button); switch(event->button) { @@ -464,22 +524,24 @@ void menu_info_item_scrolled(GtkWidget* item, GdkEventScroll* event, menu_info_item_t* mii) { - g_debug("[systray] scroll-event mod:%s dir:%s", + g_debug("[menu_info] 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" : "???"); + menu_infos_t* mis = mii->menu_info->menu_infos; + int inc = 0; switch(event->direction) { case GDK_SCROLL_UP: - inc = 1; + inc = mis->settings.volume_inc; break; case GDK_SCROLL_DOWN: - inc = -1; + inc = -mis->settings.volume_inc; break; default: return; @@ -499,13 +561,13 @@ } } -void menu_info_subitem_clicked(GtkWidget* item, GdkEvent* event, +void menu_info_subitem_clicked(GtkWidget* item, GdkEventButton* event, menu_info_item_t* mii) { - g_debug("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->type), mii->desc); + g_debug("[menu_info] subitem clicked mod:%s%s button:%i", + (event->state & GDK_CONTROL_MASK) ? "[ctrl]" : "", + (event->state & GDK_MOD1_MASK) ? "[alt]" : "", + event->button); switch(mii->menu_info->type) { @@ -523,9 +585,16 @@ } } +void menu_info_item_move_all_cb(GtkWidget* item, GdkEventButton* event, void* userdata) +{ + menu_info_item_t* mii = userdata; + pulseaudio_move_all(mii); +} + void menu_info_item_rename_cb(GtkWidget* item, GdkEventButton* event, void* userdata) { - menu_info_item_rename_dialog(userdata); + menu_info_item_t* mii = userdata; + menu_info_item_rename_dialog(mii); } void menu_info_item_rename_dialog(menu_info_item_t* mii) @@ -533,7 +602,7 @@ gtk_menu_popdown(GTK_MENU(mii->menu_info->menu_infos->menu)); char* title = g_strdup_printf("Rename %s %s", - menu_info_type_name(mii->menu_info->type), mii->desc); + menu_info_type_name(mii->menu_info->type), mii->name); char* text = g_strdup_printf("%s to:", title); GtkDialog* dialog = ui_renamedialog(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/src/menu_info.h new/pasystray-pasystray-0.6.0/src/menu_info.h --- old/pasystray-pasystray-0.5.2/src/menu_info.h 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/src/menu_info.h 2016-07-17 12:41:33.000000000 +0200 @@ -55,8 +55,17 @@ char* default_name; }; +typedef enum { + NOTIFY_NEVER, + NOTIFY_DEFAULT, + NOTIFY_ALWAYS, +} notify_t; + struct settings_t_ { - int max_volume; + int volume_max; + int volume_inc; + notify_t notify; + gboolean monitors; }; typedef struct settings_t_ settings_t; @@ -97,6 +106,8 @@ const char* menu_info_type_name(menu_type_t type); menu_type_t menu_info_submenu_type(menu_type_t menu_type); +char* menu_info_item_label(menu_info_item_t* mii); + 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, const char* address, uint32_t target); @@ -116,9 +127,11 @@ 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, +void menu_info_subitem_clicked(GtkWidget* item, GdkEventButton* event, menu_info_item_t* mii); +void menu_info_item_move_all_cb(GtkWidget* item, GdkEventButton* event, void* userdata); + void menu_info_item_rename_cb(GtkWidget* item, GdkEventButton* event, void* userdata); void menu_info_item_rename_dialog(menu_info_item_t* mii); void menu_info_item_rename_error(menu_info_item_t* mii); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/src/notify.c new/pasystray-pasystray-0.6.0/src/notify.c --- old/pasystray-pasystray-0.5.2/src/notify.c 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/src/notify.c 2016-07-17 12:41:33.000000000 +0200 @@ -49,16 +49,23 @@ error->code); } -notify_handle_t notify(const char* msg, const char* body, const char* icon) +notify_handle_t notify(const char* msg, const char* body, const char* icon, gint value) { NotifyNotification* n = notify_notification_new(msg, body, icon); + notify_notification_set_urgency(n, NOTIFY_URGENCY_LOW); + notify_notification_set_timeout(n, 2000); // timeout in ms + if(value > -1) + notify_notification_set_hint_int32 (n, "value", value); notify_show(n); return (notify_handle_t) n; } -void notify_update(notify_handle_t h, const char* msg, const char* body, const char* icon) +void notify_update(notify_handle_t h, const char* msg, const char* body, const char* icon, gint value) { NotifyNotification* n = (NotifyNotification*) h; + notify_notification_set_timeout(n, 2000); // timeout in ms + if(value > -1) + notify_notification_set_hint_int32 (n, "value", value); if(!notify_notification_update(n, msg, body, icon)) g_error("[notify] invalid arguments passed to notify_update()"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/src/notify.h new/pasystray-pasystray-0.6.0/src/notify.h --- old/pasystray-pasystray-0.5.2/src/notify.h 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/src/notify.h 2016-07-17 12:41:33.000000000 +0200 @@ -27,7 +27,7 @@ typedef void* notify_handle_t; void notify_initialize(); -notify_handle_t notify(const char* msg, const char* body, const char* icon); -void notify_update(notify_handle_t h, const char* msg, const char* body, const char* icon); +notify_handle_t notify(const char* msg, const char* body, const char* icon, gint value); +void notify_update(notify_handle_t h, const char* msg, const char* body, const char* icon, gint value); #endif /* PASYSTRAY_NOTIFY_H */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/src/options.c new/pasystray-pasystray-0.6.0/src/options.c --- old/pasystray-pasystray-0.5.2/src/options.c 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/src/options.c 2016-07-17 12:41:33.000000000 +0200 @@ -27,29 +27,33 @@ static gboolean version = FALSE; static gboolean debug = FALSE; -static int max_volume = 0; +static int volume_max = 0; +static int volume_inc = 1; +static gboolean no_notify = FALSE; +static gboolean always_notify = FALSE; +static gboolean monitors = FALSE; static GOptionEntry entries[] = { { "version", 'V', 0, G_OPTION_ARG_NONE, &version, "print version and exit", NULL }, { "debug", 'd', 0, G_OPTION_ARG_NONE, &debug, "print debugging information", NULL }, - { "max-volume", 'm', 0, G_OPTION_ARG_INT, &max_volume, "maximum volume (in percent)", "N" }, + { "max-volume", 0, 0, G_OPTION_ARG_INT, &volume_max, "deprecated, use volume-max instead", "N" }, + { "volume-max", 'm', 0, G_OPTION_ARG_INT, &volume_max, "maximum volume (in percent)", "N" }, + { "volume-inc", 'i', 0, G_OPTION_ARG_INT, &volume_inc, "volume increment", "N" }, + { "no-notify", 'n', 0, G_OPTION_ARG_NONE, &no_notify, "disable all notifications", NULL }, + { "always-notify", 'a', 0, G_OPTION_ARG_NONE, &always_notify, + "enable notifications for all changes in pulsaudio", NULL }, + { "include-monitors", 'n', 0, G_OPTION_ARG_NONE, &monitors, "include monitor sources", NULL }, { .long_name = NULL } }; -void parse_options(int argc, char *argv[], settings_t* settings) +GOptionEntry* get_options() { - GError *error = NULL; - GOptionContext *context; - - context = g_option_context_new(NULL); - g_option_context_add_main_entries(context, entries, NULL); - g_option_context_add_group(context, gtk_get_option_group(TRUE)); - if(!g_option_context_parse(context, &argc, &argv, &error)) - { - g_error("option parsing failed: %s\n", error->message); - } + return entries; +} +void parse_options(settings_t* settings) +{ if(version) { g_print("%s\n", VERSION); @@ -61,8 +65,27 @@ setenv("G_MESSAGES_DEBUG", "pasystray", 1); } - if(max_volume > 0) + settings->volume_max = 0; + if(volume_max > 0) + { + settings->volume_max = volume_max; + } + + settings->volume_inc = 1; + if(volume_inc > 0) + { + settings->volume_inc = volume_inc; + } + + settings->notify = NOTIFY_DEFAULT; + if(no_notify) { - settings->max_volume = max_volume; + settings->notify = NOTIFY_NEVER; } + if(always_notify) + { + settings->notify = NOTIFY_ALWAYS; + } + + settings->monitors = monitors; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/src/options.h new/pasystray-pasystray-0.6.0/src/options.h --- old/pasystray-pasystray-0.5.2/src/options.h 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/src/options.h 2016-07-17 12:41:33.000000000 +0200 @@ -24,6 +24,7 @@ #include "menu_info.h" -void parse_options(int argc, char *argv[], settings_t* settings); +GOptionEntry* get_options(); +void parse_options(settings_t* settings); #endif /* PASYSTRAY_OPTIONS_H */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/src/pasystray.c new/pasystray-pasystray-0.6.0/src/pasystray.c --- old/pasystray-pasystray-0.5.2/src/pasystray.c 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/src/pasystray.c 2016-07-17 12:41:33.000000000 +0200 @@ -19,6 +19,7 @@ USA. ***/ +#include <glib.h> #include <gtk/gtk.h> #include "pasystray.h" @@ -36,15 +37,23 @@ int main(int argc, char *argv[]) { + GOptionEntry* options = get_options(); + GError *error = NULL; + gtk_init_with_args(&argc, &argv, NULL, options, NULL, &error); + if(error) + { + g_print("option parsing failed: %s\n", error->message); + return EXIT_FAILURE; + } + settings_t settings; - parse_options(argc, argv, &settings); - gtk_init(&argc, &argv); + parse_options(&settings); init(&settings); g_main_loop_run(loop); destroy(); - return 0; + return EXIT_SUCCESS; } void init(settings_t* settings) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/src/pasystray.glade new/pasystray-pasystray-0.6.0/src/pasystray.glade --- old/pasystray-pasystray-0.5.2/src/pasystray.glade 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/src/pasystray.glade 2016-07-17 12:41:33.000000000 +0200 @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.18.3 --> <interface> - <!-- interface-requires gtk+ 3.0 --> + <requires lib="gtk+" version="3.0"/> <object class="GtkAboutDialog" id="aboutdialog"> <property name="can_focus">False</property> <property name="border_width">5</property> @@ -37,37 +38,50 @@ </object> </child> </object> - <object class="GtkDialog" id="renamedialog"> + <object class="GtkMessageDialog" id="errordialog"> <property name="can_focus">False</property> <property name="border_width">5</property> - <property name="title" translatable="yes">Rename <device> <name></property> - <property name="type_hint">normal</property> + <property name="title" translatable="yes">Error</property> + <property name="resizable">False</property> + <property name="type_hint">dialog</property> + <property name="message_type">error</property> + <property name="buttons">ok</property> + <property name="text" translatable="yes">An error occurred</property> <child internal-child="vbox"> - <object class="GtkBox" id="dialog-vbox"> + <object class="GtkBox" id="messagedialog-vbox2"> <property name="can_focus">False</property> - <property name="orientation">vertical</property> - <property name="spacing">2</property> - <child> - <object class="GtkLabel" id="label"> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="messagedialog-action_area2"> <property name="can_focus">False</property> - <property name="label" translatable="yes">Rename <device> <old name> to:</property> </object> <packing> <property name="expand">False</property> - <property name="fill">True</property> + <property name="fill">False</property> <property name="position">0</property> </packing> </child> + </object> + </child> + </object> + <object class="GtkDialog" id="renamedialog"> + <property name="can_focus">False</property> + <property name="border_width">5</property> + <property name="title" translatable="yes">Rename <device> <name></property> + <property name="type_hint">normal</property> + <child internal-child="vbox"> + <object class="GtkBox" id="dialog-vbox"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">2</property> <child internal-child="action_area"> <object class="GtkButtonBox" id="dialog-action_area3"> <property name="can_focus">False</property> <property name="layout_style">end</property> <child> <object class="GtkButton" id="cancelbutton"> - <property name="label">gtk-cancel</property> + <property name="label">Cancel</property> <property name="can_focus">True</property> <property name="receives_default">False</property> - <property name="use_stock">True</property> </object> <packing> <property name="expand">False</property> @@ -77,10 +91,10 @@ </child> <child> <object class="GtkButton" id="okbutton"> - <property name="label">gtk-ok</property> + <property name="label">OK</property> <property name="can_focus">True</property> <property name="receives_default">False</property> - <property name="use_stock">True</property> + <property name="image_position">bottom</property> </object> <packing> <property name="expand">False</property> @@ -97,6 +111,17 @@ </packing> </child> <child> + <object class="GtkLabel" id="label"> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Rename <device> <old name> to:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> <object class="GtkEntry" id="entry"> <property name="can_focus">True</property> <property name="has_focus">True</property> @@ -119,14 +144,4 @@ <action-widget response="-5">okbutton</action-widget> </action-widgets> </object> - <object class="GtkMessageDialog" id="errordialog"> - <property name="can_focus">False</property> - <property name="border_width">5</property> - <property name="resizable">False</property> - <property name="type_hint">dialog</property> - <property name="title" translatable="yes">Error</property> - <property name="text" translatable="yes">An error occurred</property> - <property name="message_type">GTK_MESSAGE_ERROR</property> - <property name="buttons">GTK_BUTTONS_OK</property> - </object> </interface> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/src/pulseaudio.c new/pasystray-pasystray-0.6.0/src/pulseaudio.c --- old/pasystray-pasystray-0.5.2/src/pulseaudio.c 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/src/pulseaudio.c 2016-07-17 12:41:33.000000000 +0200 @@ -31,16 +31,13 @@ static pa_glib_mainloop* m = NULL; static pa_proplist* context_proplist = NULL; -static char* server = NULL; void pulseaudio_init(menu_infos_t* mis) { if(!(m = pa_glib_mainloop_new(g_main_context_default()))) pulseaudio_quit("pa_glib_mainloop_new() failed."); - pulseaudio_prepare_context(mis); - - pulseaudio_connect(); + pulseaudio_connect(mis); } void pulseaudio_destroy() @@ -62,15 +59,37 @@ pa_context_set_state_callback(context, pulseaudio_context_state_cb, mis); } -void pulseaudio_connect() +void pulseaudio_connect(menu_infos_t* mis) { - if(pa_context_connect(context, server, PA_CONTEXT_NOFLAGS, NULL) < 0) + pulseaudio_prepare_context(mis); + + if(pa_context_connect(context, NULL, PA_CONTEXT_NOFAIL, NULL) < 0) { - g_warning("pa_context_connect() failed: "); - pulseaudio_quit(pa_strerror(pa_context_errno(context))); + g_warning("pa_context_connect() failed: %s", + pa_strerror(pa_context_errno(context))); } } +void pulseaudio_reconnect_cb(pa_mainloop_api *api, pa_time_event *event, const struct timeval *tv, void *userdata) +{ + menu_infos_t* mis = userdata; + pulseaudio_connect(mis); +} + +void pulseaudio_reconnect(menu_infos_t* mis) +{ + systray_impl_set_icon(mis->systray, "pasystray"); + + pa_mainloop_api* api = pa_glib_mainloop_get_api(m); + + struct timeval tv; + struct timeval* delay_tv = pa_gettimeofday(&tv); + pa_timeval_add(delay_tv, 1 * PA_USEC_PER_SEC); + + // reconnect with 1s delay + api->time_new(api, delay_tv, pulseaudio_reconnect_cb, mis); +} + void pulseaudio_context_state_cb(pa_context* c, void* userdata) { menu_infos_t* mis = userdata; @@ -109,9 +128,8 @@ menu_infos_clear(mis); pa_context_unref(context); - pulseaudio_prepare_context(mis); g_debug("[pulseaudio] trying again..."); - pulseaudio_connect(); + pulseaudio_reconnect(mis); break; case PA_CONTEXT_TERMINATED: @@ -119,9 +137,8 @@ menu_infos_clear(mis); pa_context_unref(context); - pulseaudio_prepare_context(mis); g_debug("[pulseaudio] reconnecting..."); - pulseaudio_connect(); + pulseaudio_reconnect(mis); break; case PA_CONTEXT_CONNECTING: @@ -358,14 +375,16 @@ if(is_last) return; - if(is_new) + menu_info_t* mi = userdata; + menu_infos_t* mis = mi->menu_infos; + + if(is_new && mis->settings.notify != NOTIFY_NEVER) { gchar* msg = g_strdup_printf("new sink \"%s\"", i->description); - notify(msg, i->name, NULL); + notify(msg, i->name, NULL, -1); g_free(msg); } - menu_info_t* mi = userdata; char* tooltip = sink_info_str(i); menu_info_item_update(mi, i->index, i->name, i->description, &i->volume, i->mute, tooltip, NULL, NULL, -1); @@ -400,18 +419,20 @@ const char* class = pa_proplist_gets(i->proplist, PA_PROP_DEVICE_CLASS); + menu_info_t* mi = userdata; + menu_infos_t* mis = mi->menu_infos; + // ignore monitors - if(class && g_str_equal(class, "monitor")) + if(!mis->settings.monitors && class && g_str_equal(class, "monitor")) return; - if(is_new) + if(is_new && mis->settings.notify != NOTIFY_NEVER) { gchar* msg = g_strdup_printf("new source \"%s\"", i->description); - notify(msg, i->name, NULL); + notify(msg, i->name, NULL, -1); g_free(msg); } - menu_info_t* mi = userdata; char* tooltip = source_info_str(i); menu_info_item_update(mi, i->index, i->name, i->description, &i->volume, i->mute, tooltip, NULL, NULL, -1); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/src/pulseaudio.h new/pasystray-pasystray-0.6.0/src/pulseaudio.h --- old/pasystray-pasystray-0.5.2/src/pulseaudio.h 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/src/pulseaudio.h 2016-07-17 12:41:33.000000000 +0200 @@ -29,7 +29,8 @@ void pulseaudio_init(menu_infos_t* mis); void pulseaudio_destroy(); void pulseaudio_prepare_context(menu_infos_t* mis); -void pulseaudio_connect(); +void pulseaudio_connect(menu_infos_t* mis); +void pulseaudio_reconnect(menu_infos_t* mis); void pulseaudio_start(); void pulseaudio_context_state_cb(pa_context* c, void* userdata); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/src/pulseaudio_action.c new/pasystray-pasystray-0.6.0/src/pulseaudio_action.c --- old/pasystray-pasystray-0.5.2/src/pulseaudio_action.c 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/src/pulseaudio_action.c 2016-07-17 12:41:33.000000000 +0200 @@ -25,6 +25,7 @@ #include <pulse/ext-device-manager.h> #include "notify.h" +#include "ui.h" #include "x11-property.h" extern pa_context* context; @@ -63,23 +64,58 @@ { menu_info_item_t* mii = userdata; - if(!success) + if(success) + { + if(mii->menu_info->type == MENU_SINK) + ui_update_systray_icon(mii); + } + else g_warning("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) { + g_debug("[pulseaudio_action] move input %s to sink %s", + input->desc, sink->desc); + 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) { + g_debug("[pulseaudio_action] move output %s to source %s", + output->desc, source->desc); + pa_operation_unref(pa_context_move_source_output_by_index(context, output->index, source->index, pulseaudio_move_success_cb, output)); } +void pulseaudio_move_all(menu_info_item_t* mii) +{ + menu_infos_t* mis = mii->menu_info->menu_infos; + menu_type_t target_type = mii->menu_info->type; + menu_type_t source_type = (target_type == MENU_SINK) ? MENU_INPUT : MENU_OUTPUT; + + g_debug("[pulseaudio_action] move all %s to %s %s", + menu_info_type_name(source_type), + menu_info_type_name(target_type), + mii->desc); + + GHashTableIter iter; + gpointer key; + gpointer value; + g_hash_table_iter_init(&iter, mis->menu_info[MENU_INPUT].items); + while (g_hash_table_iter_next(&iter, &key, &value)) + { + if (target_type == MENU_SINK) + pulseaudio_move_input_to_sink(value, mii); + else if (target_type == MENU_SOURCE) + pulseaudio_move_output_to_source(value, mii); + } +} + void pulseaudio_move_success_cb(pa_context *c, int success, void *userdata) { menu_info_item_t* to = userdata; @@ -125,10 +161,10 @@ volume = pa_cvolume_dec(mii->volume, -inc * PA_VOLUME_NORM / 50); else if(inc > 0) { - int max_volume = mii->menu_info->menu_infos->settings.max_volume; - if(max_volume > 0) + int volume_max = mii->menu_info->menu_infos->settings.volume_max; + if(volume_max > 0) volume = pa_cvolume_inc_clamp(mii->volume, inc * PA_VOLUME_NORM / 50, - PA_VOLUME_NORM * max_volume / 100); + PA_VOLUME_NORM * volume_max / 100); else volume = pa_cvolume_inc(mii->volume, inc * PA_VOLUME_NORM / 50); } @@ -175,21 +211,30 @@ return; } - pulseaudio_update_volume_notification(mii); + menu_infos_t* mis = mii->menu_info->menu_infos; + + /* update sink icon */ + if(mii->menu_info->type == MENU_SINK || mii->menu_info->type == MENU_SOURCE) + ui_set_volume_icon(mii); + + if(mis->settings.notify != NOTIFY_NEVER) + { + pulseaudio_update_volume_notification(mii); + } } void pulseaudio_update_volume_notification(menu_info_item_t* mii) { - char vol[PA_CVOLUME_SNPRINT_MAX]; - gchar* msg = g_strdup_printf("%s %s: %s%s", - menu_info_type_name(mii->menu_info->type), mii->desc, - pa_cvolume_snprint(vol, sizeof(vol), mii->volume), - mii->mute ? " [muted]" : ""); + gchar* label = menu_info_item_label(mii); + gchar* msg = g_strdup_printf("%s %s", + menu_info_type_name(mii->menu_info->type), label); + g_free(label); + gint volume = (mii->volume->values[0]*100+PA_VOLUME_NORM/2)/PA_VOLUME_NORM; if(!mii->notify) - mii->notify = notify(msg, NULL, mii->icon); + mii->notify = notify(msg, NULL, mii->icon, volume); else - notify_update(mii->notify, msg, NULL, mii->icon); + notify_update(mii->notify, msg, NULL, mii->icon, volume); g_free(msg); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/src/pulseaudio_action.h new/pasystray-pasystray-0.6.0/src/pulseaudio_action.h --- old/pasystray-pasystray-0.5.2/src/pulseaudio_action.h 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/src/pulseaudio_action.h 2016-07-17 12:41:33.000000000 +0200 @@ -30,6 +30,7 @@ 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_all(menu_info_item_t* mii); void pulseaudio_move_success_cb(pa_context *c, int success, void *userdata); void pulseaudio_rename(menu_info_item_t* mii, const char* name); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/src/systray.c new/pasystray-pasystray-0.6.0/src/systray.c --- old/pasystray-pasystray-0.5.2/src/systray.c 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/src/systray.c 2016-07-17 12:41:33.000000000 +0200 @@ -27,6 +27,12 @@ #include "ui.h" #include "systray_impl.h" +static const char* COMMAND_PAMAN = "paman"; +static const char* COMMAND_PAVUCONTROL = "pavucontrol"; +static const char* COMMAND_PAVUMETER = "pavumeter"; +static const char* COMMAND_PAVUMETER_REC = "pavumeter --record"; +static const char* COMMAND_PAPREFS = "paprefs"; + void systray_create(menu_infos_t* mis) { systray_menu_create(mis); @@ -45,12 +51,6 @@ systray_rootmenu_add_submenu(mis, MENU_MODULE, "_Modules", "list-add"); systray_menu_add_separator(mis->menu); - static const char* COMMAND_PAMAN = "paman"; - static const char* COMMAND_PAVUCONTROL = "pavucontrol"; - static const char* COMMAND_PAVUMETER = "pavumeter"; - static const char* COMMAND_PAVUMETER_REC = "pavumeter --record"; - static const char* COMMAND_PAPREFS = "paprefs"; - systray_menu_add_application(mis->menu, "_Manager...", NULL, COMMAND_PAMAN); systray_menu_add_application(mis->menu, "Volume _Control...", NULL, COMMAND_PAVUCONTROL); systray_menu_add_application(mis->menu, "Volume Meter (_Playback)...", NULL, COMMAND_PAVUMETER); @@ -156,9 +156,12 @@ systray_add_placeholder(mi); } -GtkWidget* systray_add_radio_item(menu_info_t* mi, const char* desc, const char* tooltip) +GtkWidget* systray_add_radio_item(menu_info_item_t* mii, const char* tooltip) { - GtkWidget* item = gtk_radio_menu_item_new_with_label(mi->group, desc); + menu_info_t* mi = mii->menu_info; + gchar* label = menu_info_item_label(mii); + GtkWidget* item = gtk_radio_menu_item_new_with_label(mi->group, label); + g_free(label); if(tooltip) systray_set_tooltip(item, tooltip); @@ -192,18 +195,30 @@ { GtkWidget* item = gtk_menu_item_new(); +#if GTK_VERSION_MAJOR == 2 + GtkWidget* hbox = gtk_hbox_new(FALSE, 0); +#else GtkWidget* hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); +#endif gtk_container_add(GTK_CONTAINER(item), hbox); if(icon) { GtkWidget* image = gtk_image_new_from_icon_name(icon, GTK_ICON_SIZE_MENU); +#if GTK_VERSION_MAJOR == 2 + gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0); +#else gtk_container_add(GTK_CONTAINER(hbox), image); +#endif } GtkWidget* label = gtk_label_new(NULL); gtk_label_set_text_with_mnemonic(GTK_LABEL(label), desc); +#if GTK_VERSION_MAJOR == 2 + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 15); +#else gtk_container_add(GTK_CONTAINER(hbox), label); +#endif if(tooltip) systray_set_tooltip(item, tooltip); @@ -331,39 +346,68 @@ 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); + g_debug("[systray] click mod:%s%s button:%i", + (ev->state & GDK_CONTROL_MASK) ? "[ctrl]" : "", + (ev->state & GDK_MOD1_MASK) ? "[alt]" : "", + ev->button); + switch(ev->button) { case 1: /* on alt + left-click, toggle mute default sink */ - if((ev->state & GDK_MOD1_MASK) && mii) - pulseaudio_toggle_mute(mii); + if(ev->state & GDK_MOD1_MASK) + { + if(mii) + pulseaudio_toggle_mute(mii); + } + /* on ctrl + left-click, start pavucontrol */ + else if(ev->state & GDK_CONTROL_MASK) + { + g_spawn_command_line_async(COMMAND_PAVUCONTROL, NULL); + } /* on left-click, show menu */ else - gtk_menu_popup(GTK_MENU(mis->menu), NULL, NULL, gtk_status_icon_position_menu, icon, ev->button, ev->time); + { + gtk_menu_popup(GTK_MENU(mis->menu), NULL, NULL, +#if HAVE_STATUSICON + gtk_status_icon_position_menu, +#else + NULL, +#endif + icon, ev->button, ev->time); + } break; case 2: /* on middle-click, toggle mute default sink */ if(mii) + { pulseaudio_toggle_mute(mii); + } break; case 3: /* on right-click, show menu */ - gtk_menu_popup(GTK_MENU(mis->menu), NULL, NULL, gtk_status_icon_position_menu, icon, ev->button, ev->time); + gtk_menu_popup(GTK_MENU(mis->menu), NULL, NULL, +#if HAVE_STATUSICON + gtk_status_icon_position_menu, +#else + NULL, +#endif + icon, ev->button, ev->time); break; } } -void systray_scroll_cb(systray_t* systray, guint state, GdkScrollDirection direction, menu_infos_t* mis) +void systray_scroll_cb(guint state, GdkScrollDirection direction, menu_infos_t* mis) { int inc = 0; switch(direction) { case GDK_SCROLL_UP: - inc = 1; + inc = mis->settings.volume_inc; break; case GDK_SCROLL_DOWN: - inc = -1; + inc = -mis->settings.volume_inc; break; default: return; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/src/systray.h new/pasystray-pasystray-0.6.0/src/systray.h --- old/pasystray-pasystray-0.5.2/src/systray.h 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/src/systray.h 2016-07-17 12:41:33.000000000 +0200 @@ -44,7 +44,7 @@ GtkWidget* systray_add_menu_item(menu_info_t* mi, const char* desc, const char* tooltip, const char* icon); void systray_remove_menu_item(menu_info_t* mi, GtkWidget* item); -GtkWidget* systray_add_radio_item(menu_info_t* m, const char* desc, const char* tooltip); +GtkWidget* systray_add_radio_item(menu_info_item_t* mii, const char* tooltip); void systray_remove_radio_item(menu_info_t* mi, GtkWidget* item); GtkWidget* systray_add_item(GtkMenuShell* menu, const char* desc, const char* tooltip, const char* icon); @@ -60,7 +60,7 @@ void systray_about_dialog(); void systray_click_cb(GtkStatusIcon* icon, GdkEventButton* ev, gpointer userdata); -void systray_scroll_cb(systray_t* systray, guint state, GdkScrollDirection direction, menu_infos_t* mis); +void systray_scroll_cb(guint state, GdkScrollDirection direction, menu_infos_t* mis); void start_application_cb(GtkMenuItem* menuitem, const char* command); void systray_set_tooltip(GtkWidget* item, const char* tooltip); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/src/systray_impl.c new/pasystray-pasystray-0.6.0/src/systray_impl.c --- old/pasystray-pasystray-0.5.2/src/systray_impl.c 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/src/systray_impl.c 2016-07-17 12:41:33.000000000 +0200 @@ -30,15 +30,14 @@ static void systray_impl_scroll_cb(AppIndicator* appind, gint delta, GdkScrollDirection direction, gpointer userdata) { - systray_t systray = appind; guint state = 0; // TODO: get modifiers? menu_infos_t* mis = userdata; - systray_scroll_cb(systray, state, direction, mis); + systray_scroll_cb(state, direction, mis); } systray_t systray_impl_create(menu_infos_t* mis) { - g_debug("creating systray implementation using AppIndicator"); + g_debug("[systray_impl] using AppIndicator"); AppIndicator* appind = app_indicator_new("pasystray", "pasystray", APP_INDICATOR_CATEGORY_HARDWARE); app_indicator_set_status(appind, APP_INDICATOR_STATUS_ACTIVE); @@ -58,15 +57,14 @@ { // TODO: set tooltip? } -#else +#elif HAVE_STATUSICON #include "ui.h" static void systray_impl_scroll_cb(GtkStatusIcon* icon, GdkEventScroll* ev, gpointer userdata) { - systray_t systray = icon; menu_infos_t* mis = userdata; - systray_scroll_cb(systray, ev->state, ev->direction, mis); + systray_scroll_cb(ev->state, ev->direction, mis); } static GtkStatusIcon* systray_impl_create_statusicon() @@ -103,7 +101,7 @@ systray_t systray_impl_create(menu_infos_t* mis) { - g_debug("creating systray implementation using GtkStatusIcon"); + g_debug("[systray_impl] using GtkStatusIcon"); GtkStatusIcon* icon = systray_impl_create_statusicon(); g_signal_connect(icon, "button-press-event", G_CALLBACK(systray_click_cb), mis); @@ -153,4 +151,47 @@ gtk_status_icon_set_tooltip_markup(icon, markup); } +#else + +static void systray_impl_scroll_cb(GtkImage* image, GdkEventScroll* ev, gpointer userdata) +{ + menu_infos_t* mis = userdata; + systray_scroll_cb(ev->state, ev->direction, mis); +} + +systray_t systray_impl_create(menu_infos_t* mis) +{ + g_debug("[systray_impl] using GtkWindow"); + + GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), "pasystray"); + + GtkWidget *button = gtk_menu_button_new(); + gtk_container_add(GTK_CONTAINER(window), button); + gtk_menu_button_set_popup(GTK_MENU_BUTTON(button), GTK_WIDGET(mis->menu)); + gtk_widget_add_events(button, GDK_SCROLL_MASK); + g_signal_connect(button, "button-press-event", G_CALLBACK(systray_click_cb), mis); + g_signal_connect(button, "scroll-event", G_CALLBACK(systray_impl_scroll_cb), mis); + + GtkWidget *image = gtk_image_new(); + gtk_image_set_from_icon_name(GTK_IMAGE(image), "pasystray", GTK_ICON_SIZE_DIALOG); + gtk_button_set_image(GTK_BUTTON(button), image); + + gtk_widget_show_all(window); + + return image; +} + +void systray_impl_set_icon(systray_t systray, const char* icon_name) +{ + GtkImage *image = systray; + gtk_image_set_from_icon_name(image, icon_name, GTK_ICON_SIZE_DIALOG); +} + +void systray_impl_set_tooltip(systray_t systray, const char* markup) +{ + GtkImage *image = systray; + gtk_widget_set_tooltip_markup(GTK_WIDGET(image), markup); +} + #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/src/ui.c new/pasystray-pasystray-0.6.0/src/ui.c --- old/pasystray-pasystray-0.5.2/src/ui.c 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/src/ui.c 2016-07-17 12:41:33.000000000 +0200 @@ -52,9 +52,9 @@ } } -void ui_update_systray_icon(menu_info_item_t* mii) +void ui_set_volume_icon(menu_info_item_t* mii) { - g_debug("pulseaudio_update_systray_icon(%s)", mii->name); + g_debug("pulseaudio_set_volume_icon(%s)", mii->name); pa_volume_t volume = pa_cvolume_avg(mii->volume); @@ -71,8 +71,18 @@ else icon_name = "audio-volume-high"; + g_free(mii->icon); + mii->icon = g_strdup(icon_name); +} + +void ui_update_systray_icon(menu_info_item_t* mii) +{ + g_debug("pulseaudio_update_systray_icon(%s)", mii->name); + + ui_set_volume_icon(mii); + menu_infos_t* mis = mii->menu_info->menu_infos; - systray_impl_set_icon(mis->systray, icon_name); + systray_impl_set_icon(mis->systray, mii->icon); } GtkDialog* ui_aboutdialog() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pasystray-pasystray-0.5.2/src/ui.h new/pasystray-pasystray-0.6.0/src/ui.h --- old/pasystray-pasystray-0.5.2/src/ui.h 2015-05-05 21:25:16.000000000 +0200 +++ new/pasystray-pasystray-0.6.0/src/ui.h 2016-07-17 12:41:33.000000000 +0200 @@ -26,6 +26,7 @@ #include <gtk/gtk.h> void ui_load(); +void ui_set_volume_icon(menu_info_item_t* mii); void ui_update_systray_icon(menu_info_item_t* mii); GtkDialog* ui_aboutdialog(); GtkDialog* ui_renamedialog();
