[gnome-flashback] sound-applet: create status notifier items
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback] sound-applet: create status notifier items
- Date: Sat, 9 Jan 2016 17:45:25 +0000 (UTC)
commit 92b428d0037f1bc1f8fb71efc258b5c1675062ec
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Sat Jan 9 19:44:52 2016 +0200
sound-applet: create status notifier items
configure.ac | 48 +-
gnome-flashback/libsound-applet/Makefile.am | 7 +
gnome-flashback/libsound-applet/gf-sound-applet.c | 53 ++
gnome-flashback/libsound-applet/gf-sound-item.c | 688 +++++++++++++++++++++
gnome-flashback/libsound-applet/gf-sound-item.h | 42 ++
5 files changed, 819 insertions(+), 19 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index dc9a045..b5f39b2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -82,6 +82,26 @@ dnl **************************************************************************
GLIB_GSETTINGS
dnl **************************************************************************
+dnl Build with libstatus-notifier (experimental)
+dnl **************************************************************************
+
+AC_ARG_WITH([libstatus-notifier],
+ [AS_HELP_STRING([--with-libstatus-notifier],
+ [Build with libstatus-notifier (experimental)])],
+ [with_libstatus_notifier="$withval"],
+ [with_libstatus_notifier=no])
+
+LIBSTATUS_NOTIFIER_PKG=""
+AS_IF([test "x$with_libstatus_notifier" = "xyes"], [
+ LIBSTATUS_NOTIFIER_PKG="libstatus-notifier-3.0"
+ AC_DEFINE([WITH_LIBSTATUS_NOTIFIER], [1],
+ [Define to 1 if libstatus-notifier is available])
+])
+
+AM_CONDITIONAL([WITH_LIBSTATUS_NOTIFIER],
+ [test "x$with_libstatus_notifier" = "xyes"])
+
+dnl **************************************************************************
dnl Check for required packages
dnl **************************************************************************
@@ -188,6 +208,15 @@ PKG_CHECK_MODULES([SOUND_APPLET], [
gtk+-3.0 >= $GTK_REQUIRED
libcanberra-gtk3 >= $CANBERRA_REQUIRED
glib-2.0 >= $GLIB_REQUIRED
+ $LIBSTATUS_NOTIFIER_PKG
+])
+
+AS_IF([test "x$with_libstatus_notifier" = "xyes"], [
+ PKG_CHECK_MODULES([WATCHER], [
+ glib-2.0 >= $GLIB_REQUIRED
+ gtk+-3.0 >= $GTK_REQUIRED
+ $LIBSTATUS_NOTIFIER_PKG
+ ])
])
PKG_CHECK_MODULES([WORKAROUNDS], [
@@ -197,25 +226,6 @@ PKG_CHECK_MODULES([WORKAROUNDS], [
])
dnl **************************************************************************
-dnl Build with libstatus-notifier (experimental)
-dnl **************************************************************************
-
-AC_ARG_WITH([libstatus-notifier],
- [AS_HELP_STRING([--with-libstatus-notifier],
- [Build with libstatus-notifier (experimental)])],
- [with_libstatus_notifier="$withval"],
- [with_libstatus_notifier=no])
-
-AS_IF([test "x$with_libstatus_notifier" = "xyes"], [
- PKG_CHECK_MODULES([WATCHER], [libstatus-notifier-3.0])
- AC_DEFINE([WITH_LIBSTATUS_NOTIFIER], [1],
- [Define to 1 if libstatus-notifier is available])
-])
-
-AM_CONDITIONAL([WITH_LIBSTATUS_NOTIFIER],
- [test "x$with_libstatus_notifier" = "xyes"])
-
-dnl **************************************************************************
dnl Define XKB base directory
dnl **************************************************************************
diff --git a/gnome-flashback/libsound-applet/Makefile.am b/gnome-flashback/libsound-applet/Makefile.am
index d3a2624..00e2223 100644
--- a/gnome-flashback/libsound-applet/Makefile.am
+++ b/gnome-flashback/libsound-applet/Makefile.am
@@ -25,6 +25,13 @@ libsound_applet_la_SOURCES = \
gvc-stream-status-icon.h \
$(NULL)
+if WITH_LIBSTATUS_NOTIFIER
+libsound_applet_la_SOURCES += \
+ gf-sound-item.c \
+ gf-sound-item.h \
+ $(NULL)
+endif
+
libsound_applet_la_LDFLAGS = \
$(WARN_LDFLAGS) \
$(AM_LDFLAGS) \
diff --git a/gnome-flashback/libsound-applet/gf-sound-applet.c
b/gnome-flashback/libsound-applet/gf-sound-applet.c
index abd1728..2d7f2cd 100644
--- a/gnome-flashback/libsound-applet/gf-sound-applet.c
+++ b/gnome-flashback/libsound-applet/gf-sound-applet.c
@@ -34,6 +34,10 @@
#include "gvc-mixer-control.h"
#include "gvc-stream-status-icon.h"
+#ifdef WITH_LIBSTATUS_NOTIFIER
+#include "gf-sound-item.h"
+#endif
+
static const gchar *output_icons[] =
{
"audio-volume-muted",
@@ -59,6 +63,11 @@ struct _GfSoundApplet
GvcStreamStatusIcon *input_status_icon;
GvcStreamStatusIcon *output_status_icon;
GvcMixerControl *control;
+
+#ifdef WITH_LIBSTATUS_NOTIFIER
+ GfSoundItem *output_item;
+ GfSoundItem *input_item;
+#endif
};
G_DEFINE_TYPE (GfSoundApplet, gf_sound_applet, G_TYPE_OBJECT)
@@ -81,6 +90,13 @@ maybe_show_status_icons (GfSoundApplet *applet)
gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->output_status_icon), show);
G_GNUC_END_IGNORE_DEPRECATIONS
+#ifdef WITH_LIBSTATUS_NOTIFIER
+ if (show)
+ sn_item_register (SN_ITEM (applet->output_item));
+ else
+ sn_item_unregister (SN_ITEM (applet->output_item));
+#endif
+
show = FALSE;
stream = gvc_mixer_control_get_default_source (applet->control);
source_outputs = gvc_mixer_control_get_source_outputs (applet->control);
@@ -114,6 +130,13 @@ maybe_show_status_icons (GfSoundApplet *applet)
gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->input_status_icon), show);
G_GNUC_END_IGNORE_DEPRECATIONS
+#ifdef WITH_LIBSTATUS_NOTIFIER
+ if (show)
+ sn_item_register (SN_ITEM (applet->input_item));
+ else
+ sn_item_unregister (SN_ITEM (applet->input_item));
+#endif
+
g_slist_free (source_outputs);
}
@@ -127,6 +150,9 @@ update_default_sink (GfSoundApplet *applet)
if (stream != NULL)
{
gvc_stream_status_icon_set_mixer_stream (applet->output_status_icon, stream);
+#ifdef WITH_LIBSTATUS_NOTIFIER
+ gf_sound_item_set_mixer_stream (applet->output_item, stream);
+#endif
maybe_show_status_icons (applet);
}
else
@@ -145,6 +171,9 @@ update_default_source (GfSoundApplet *applet)
if (stream != NULL)
{
gvc_stream_status_icon_set_mixer_stream (applet->input_status_icon, stream);
+#ifdef WITH_LIBSTATUS_NOTIFIER
+ gf_sound_item_set_mixer_stream (applet->input_item, stream);
+#endif
maybe_show_status_icons (applet);
}
else
@@ -259,6 +288,11 @@ gf_sound_applet_dispose (GObject *object)
g_clear_object (&applet->input_status_icon);
g_clear_object (&applet->control);
+#ifdef WITH_LIBSTATUS_NOTIFIER
+ g_clear_object (&applet->output_item);
+ g_clear_object (&applet->input_item);
+#endif
+
G_OBJECT_CLASS (gf_sound_applet_parent_class)->dispose (object);
}
@@ -277,6 +311,9 @@ static void
gf_sound_applet_init (GfSoundApplet *applet)
{
GvcStreamStatusIcon *icon;
+#ifdef WITH_LIBSTATUS_NOTIFIER
+ SnItemCategory category;
+#endif
/* Output icon */
icon = gvc_stream_status_icon_new (NULL, output_icons);
@@ -297,6 +334,22 @@ gf_sound_applet_init (GfSoundApplet *applet)
G_GNUC_END_IGNORE_DEPRECATIONS
applet->input_status_icon = icon;
+
+#ifdef WITH_LIBSTATUS_NOTIFIER
+ category = SN_ITEM_CATEGORY_HARDWARE;
+
+ applet->output_item = gf_sound_item_new (category,
+ "gf-sound-output",
+ _("Sound Output Volume"),
+ _("Output"),
+ output_icons);
+
+ applet->input_item = gf_sound_item_new (category,
+ "gf-sound-input",
+ _("Microphone Volume"),
+ _("Input"),
+ input_icons);
+#endif
}
GfSoundApplet *
diff --git a/gnome-flashback/libsound-applet/gf-sound-item.c b/gnome-flashback/libsound-applet/gf-sound-item.c
new file mode 100644
index 0000000..c88f1ce
--- /dev/null
+++ b/gnome-flashback/libsound-applet/gf-sound-item.c
@@ -0,0 +1,688 @@
+/*
+ * Copyright (C) 2008 William Jon McCann
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <math.h>
+#include <pulse/pulseaudio.h>
+
+#include "gf-sound-item.h"
+#include "gvc-channel-bar.h"
+
+struct _GfSoundItem
+{
+ SnItem parent;
+
+ gchar *display_name;
+ gchar **icon_names;
+
+ GvcMixerStream *mixer_stream;
+ gulong notify_volume_id;
+ gulong notify_is_muted_id;
+
+ GtkWidget *dock;
+ GtkWidget *bar;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_DISPLAY_NAME,
+ PROP_ICON_NAMES,
+
+ LAST_PROP
+};
+
+static GParamSpec *properties[LAST_PROP] = { NULL };
+
+G_DEFINE_TYPE (GfSoundItem, gf_sound_item, SN_TYPE_ITEM)
+
+static void
+ungrab (GfSoundItem *item)
+{
+ GdkDisplay *display;
+ GdkSeat *seat;
+
+ display = gtk_widget_get_display (item->dock);
+ seat = gdk_display_get_default_seat (display);
+
+ gdk_seat_ungrab (seat);
+
+ gtk_grab_remove (item->dock);
+ gtk_widget_hide (item->dock);
+}
+
+static gboolean
+button_press_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ GfSoundItem *item;
+
+ if (event->type != GDK_BUTTON_PRESS)
+ return GDK_EVENT_PROPAGATE;
+
+ item = GF_SOUND_ITEM (user_data);
+
+ ungrab (item);
+
+ return GDK_EVENT_STOP;
+}
+
+static gboolean
+key_release_event_cb (GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer user_data)
+{
+ GfSoundItem *item;
+
+ if (event->keyval != GDK_KEY_Escape)
+ return GDK_EVENT_PROPAGATE;
+
+ item = GF_SOUND_ITEM (user_data);
+
+ ungrab (item);
+
+ return GDK_EVENT_STOP;
+}
+
+static gboolean
+scroll_event_cb (GtkWidget *widget,
+ GdkEventScroll *event,
+ gpointer user_data)
+{
+ GfSoundItem *item;
+
+ item = GF_SOUND_ITEM (user_data);
+
+ return gvc_channel_bar_scroll (GVC_CHANNEL_BAR (item->bar), event);
+}
+
+static void
+update_icon (GfSoundItem *item)
+{
+ guint volume;
+ gboolean is_muted;
+ gdouble db;
+ gboolean can_decibel;
+ guint n;
+ gdouble percent;
+ const gchar *description;
+ gchar *title;
+ gchar *text;
+
+ if (item->mixer_stream == NULL)
+ return;
+
+ volume = gvc_mixer_stream_get_volume (item->mixer_stream);
+ is_muted = gvc_mixer_stream_get_is_muted (item->mixer_stream);
+ db = gvc_mixer_stream_get_decibel (item->mixer_stream);
+ can_decibel = gvc_mixer_stream_get_can_decibel (item->mixer_stream);
+
+ if (volume == 0 || is_muted)
+ {
+ n = 0;
+ }
+ else
+ {
+ n = 3 * volume / PA_VOLUME_NORM + 1;
+
+ if (n < 1)
+ n = 1;
+ else if (n > 3)
+ n = 3;
+ }
+
+ sn_item_set_icon_name (SN_ITEM (item), item->icon_names[n]);
+
+ percent = 100 * (float) volume / PA_VOLUME_NORM;
+ description = gvc_mixer_stream_get_description (item->mixer_stream);
+
+ if (is_muted)
+ {
+ title = g_strdup_printf ("<b>%s: %s</b>", item->display_name, _("Muted"));
+ text = g_strdup_printf ("<small>%s</small>", description);
+ }
+ else if (can_decibel && (db > PA_DECIBEL_MININFTY))
+ {
+ title = g_strdup_printf ("<b>%s: %.0f%%</b>", item->display_name, percent);
+ text = g_strdup_printf ("<small>%0.2f dB\n%s</small>", db, description);
+ }
+ else if (can_decibel)
+ {
+ title = g_strdup_printf ("<b>%s: %.0f%%</b>", item->display_name, percent);
+ text = g_strdup_printf ("<small>-∞ dB\n%s</small>", description);
+ }
+ else
+ {
+ title = g_strdup_printf ("<b>%s: %.0f%%</b>", item->display_name, percent);
+ text = g_strdup_printf ("<small>%s</small>", description);
+ }
+
+ sn_item_set_tooltip (SN_ITEM (item), NULL, NULL, title, text);
+
+ g_free (title);
+ g_free (text);
+}
+
+static void
+value_changed_cb (GtkAdjustment *adjustment,
+ gpointer user_data)
+{
+ GfSoundItem *item;
+ gdouble volume;
+ pa_volume_t volume_t;
+
+ item = GF_SOUND_ITEM (user_data);
+
+ volume = gtk_adjustment_get_value (adjustment);
+ volume_t = (pa_volume_t) round (volume);
+
+ if (gvc_mixer_stream_set_volume (item->mixer_stream, volume_t))
+ gvc_mixer_stream_push_volume (item->mixer_stream);
+}
+
+static void
+update_dock (GfSoundItem *item)
+{
+ GtkAdjustment *adjustment;
+ gdouble value;
+ gboolean is_muted;
+
+ adjustment = gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (item->bar));
+ value = gvc_mixer_stream_get_volume (item->mixer_stream);
+
+ g_signal_handlers_block_by_func (adjustment, value_changed_cb, item);
+ gtk_adjustment_set_value (adjustment, value);
+ g_signal_handlers_unblock_by_func (adjustment, value_changed_cb, item);
+
+ is_muted = gvc_mixer_stream_get_is_muted (item->mixer_stream);
+ gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (item->bar), is_muted);
+}
+
+static void
+bar_notify_is_muted_cb (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GfSoundItem *item;
+ gboolean is_muted;
+
+ item = GF_SOUND_ITEM (user_data);
+ is_muted = gvc_channel_bar_get_is_muted (GVC_CHANNEL_BAR (item->bar));
+
+ if (gvc_mixer_stream_get_is_muted (item->mixer_stream) == is_muted)
+ return;
+
+ gvc_mixer_stream_set_is_muted (item->mixer_stream, is_muted);
+ gvc_mixer_stream_change_is_muted (item->mixer_stream, is_muted);
+}
+
+static void
+gf_sound_item_constructed (GObject *object)
+{
+ GfSoundItem *item;
+ GtkWidget *frame;
+ GtkWidget *box;
+ GtkAdjustment *adjustment;
+
+ G_OBJECT_CLASS (gf_sound_item_parent_class)->constructed (object);
+
+ item = GF_SOUND_ITEM (object);
+
+ item->dock = gtk_window_new (GTK_WINDOW_POPUP);
+
+ gtk_widget_set_name (item->dock, "gvc-stream-status-icon-popup-window");
+ gtk_window_set_decorated (GTK_WINDOW (item->dock), FALSE);
+
+ g_signal_connect (item->dock, "button-press-event",
+ G_CALLBACK (button_press_event_cb), item);
+ g_signal_connect (item->dock, "key-release-event",
+ G_CALLBACK (key_release_event_cb), item);
+ g_signal_connect (item->dock, "scroll-event",
+ G_CALLBACK (scroll_event_cb), item);
+
+ frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
+ gtk_container_add (GTK_CONTAINER (item->dock), frame);
+
+ box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (box), 2);
+ gtk_container_add (GTK_CONTAINER (frame), box);
+
+ item->bar = gvc_channel_bar_new ();
+ gtk_box_pack_start (GTK_BOX (box), item->bar, TRUE, FALSE, 0);
+
+ gvc_channel_bar_set_orientation (GVC_CHANNEL_BAR (item->bar),
+ GTK_ORIENTATION_VERTICAL);
+
+ g_signal_connect (item->bar, "notify::is-muted",
+ G_CALLBACK (bar_notify_is_muted_cb), item);
+
+ adjustment = gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (item->bar));
+ g_signal_connect (adjustment, "value-changed",
+ G_CALLBACK (value_changed_cb), item);
+}
+
+static void
+clear_mixer_stream (GfSoundItem *item)
+{
+ if (item->mixer_stream == NULL)
+ return;
+
+ g_signal_handler_disconnect (item->mixer_stream, item->notify_volume_id);
+ g_signal_handler_disconnect (item->mixer_stream, item->notify_is_muted_id);
+
+ g_clear_object (&item->mixer_stream);
+}
+
+static void
+gf_sound_item_dispose (GObject *object)
+{
+ GfSoundItem *item;
+
+ item = GF_SOUND_ITEM (object);
+
+ if (item->dock != NULL)
+ {
+ gtk_widget_destroy (item->dock);
+ item->dock = NULL;
+ }
+
+ clear_mixer_stream (item);
+
+ G_OBJECT_CLASS (gf_sound_item_parent_class)->dispose (object);
+}
+
+static void
+gf_sound_item_finalize (GObject *object)
+{
+ GfSoundItem *item;
+
+ item = GF_SOUND_ITEM (object);
+
+ g_free (item->display_name);
+ g_strfreev (item->icon_names);
+
+ G_OBJECT_CLASS (gf_sound_item_parent_class)->finalize (object);
+}
+
+static void
+gf_sound_item_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GfSoundItem *item;
+
+ item = GF_SOUND_ITEM (object);
+
+ switch (property_id)
+ {
+ case PROP_DISPLAY_NAME:
+ item->display_name = g_value_dup_string (value);
+ break;
+
+ case PROP_ICON_NAMES:
+ item->icon_names = (gchar **) g_value_dup_boxed (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+toggled_cb (GtkMenuItem *item,
+ gpointer user_data)
+{
+ GfSoundItem *sound_item;
+ gboolean is_muted;
+
+ sound_item = GF_SOUND_ITEM (user_data);
+ is_muted = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item));
+
+ gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (sound_item->bar), is_muted);
+}
+
+static void
+activate_cb (GtkMenuItem *item,
+ gpointer user_data)
+{
+ GdkDisplay *display;
+ GdkAppLaunchContext *context;
+ GAppInfoCreateFlags flags;
+ GError *error;
+ GAppInfo *app_info;
+
+ display = gdk_display_get_default ();
+ context = gdk_display_get_app_launch_context (display);
+
+ flags = G_APP_INFO_CREATE_NONE;
+ error = NULL;
+
+ app_info = g_app_info_create_from_commandline ("gnome-control-center sound",
+ "Sound preferences", flags,
+ &error);
+
+ if (app_info)
+ g_app_info_launch (app_info, NULL, G_APP_LAUNCH_CONTEXT (context), &error);
+
+ if (error != NULL)
+ {
+ gchar *msg;
+ GtkWidget *dialog;
+
+ msg = g_strdup_printf (_("Failed to start Sound Preferences: %s"),
+ error->message);
+
+ dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE, "%s", msg);
+
+ g_error_free (error);
+ g_free (msg);
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+
+ gtk_widget_show (dialog);
+ }
+
+ g_clear_object (&app_info);
+ g_object_unref (context);
+}
+
+typedef struct
+{
+ gint x;
+ gint y;
+} MenuPosition;
+
+static void
+context_menu_position (GtkMenu *menu,
+ gint *x,
+ gint *y,
+ gboolean *push_in,
+ gpointer user_data)
+{
+ MenuPosition *position;
+
+ position = (MenuPosition *) user_data;
+
+ *x = position->x;
+ *y = position->y;
+}
+
+static void
+gf_sound_item_context_menu (SnItem *item,
+ gint x,
+ gint y)
+{
+ GfSoundItem *sound_item;
+ GtkWidget *menu;
+ gboolean is_muted;
+ GtkWidget *menu_item;
+ guint32 event_time;
+ MenuPosition position;
+
+ sound_item = GF_SOUND_ITEM (item);
+
+ menu = gtk_menu_new ();
+ is_muted = gvc_mixer_stream_get_is_muted (sound_item->mixer_stream);
+
+ menu_item = gtk_check_menu_item_new_with_mnemonic (_("_Mute"));
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), is_muted);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+ gtk_widget_show (menu_item);
+
+ g_signal_connect (menu_item, "toggled",
+ G_CALLBACK (toggled_cb), sound_item);
+
+ menu_item = gtk_menu_item_new_with_mnemonic (_("_Sound Preferences"));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+ gtk_widget_show (menu_item);
+
+ g_signal_connect (menu_item, "activate",
+ G_CALLBACK (activate_cb), sound_item);
+
+ position.x = x;
+ position.y = y;
+
+ event_time = gtk_get_current_event_time ();
+
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
+ context_menu_position, &position,
+ 0, event_time);
+}
+
+static void
+gf_sound_item_activate (SnItem *item,
+ gint x,
+ gint y)
+{
+ GfSoundItem *sound_item;
+ GtkWindow *gtk_window;
+ GdkDisplay *display;
+ GdkSeat *seat;
+ GdkWindow *gdk_window;
+ GdkSeatCapabilities capabilities;
+ GdkGrabStatus status;
+
+ sound_item = GF_SOUND_ITEM (item);
+
+ update_dock (sound_item);
+
+ gvc_channel_bar_set_orientation (GVC_CHANNEL_BAR (sound_item->bar),
+ GTK_ORIENTATION_VERTICAL);
+
+ gtk_widget_show_all (sound_item->dock);
+
+ gtk_window = GTK_WINDOW (sound_item->dock);
+ gtk_window_move (gtk_window, x, y);
+
+ gtk_grab_add (sound_item->dock);
+
+ display = gtk_widget_get_display (sound_item->dock);
+ seat = gdk_display_get_default_seat (display);
+ gdk_window = gtk_widget_get_window (sound_item->dock);
+
+ capabilities = GDK_SEAT_CAPABILITY_POINTER | GDK_SEAT_CAPABILITY_KEYBOARD;
+
+ status = gdk_seat_grab (seat, gdk_window, capabilities, TRUE,
+ NULL, NULL, NULL, NULL);
+
+ if (status != GDK_GRAB_SUCCESS)
+ {
+ ungrab (sound_item);
+
+ return;
+ }
+
+ gtk_widget_grab_focus (sound_item->dock);
+}
+
+static void
+gf_sound_item_secondary_activate (SnItem *item,
+ gint x,
+ gint y)
+{
+}
+
+static void
+gf_sound_item_scroll (SnItem *item,
+ gint delta,
+ SnItemOrientation orientation)
+{
+ GfSoundItem *sound_item;
+ GdkEvent *event;
+ GdkScrollDirection direction;
+
+ sound_item = GF_SOUND_ITEM (item);
+
+ if (orientation == SN_ITEM_ORIENTATION_HORIZONTAL)
+ {
+ if (delta < 0)
+ direction = GDK_SCROLL_RIGHT;
+ else
+ direction = GDK_SCROLL_LEFT;
+ }
+ else
+ {
+ if (delta < 0)
+ direction = GDK_SCROLL_DOWN;
+ else
+ direction = GDK_SCROLL_UP;
+ }
+
+ event = gdk_event_new (GDK_SCROLL);
+
+ event->scroll.direction = direction;
+ event->scroll.delta_x = delta;
+ event->scroll.delta_y = delta;
+
+ gvc_channel_bar_scroll (GVC_CHANNEL_BAR (sound_item->bar),
+ (GdkEventScroll *) event);
+ gdk_event_free (event);
+}
+
+static void
+gf_sound_item_class_init (GfSoundItemClass *item_class)
+{
+ GObjectClass *object_class;
+ SnItemClass *sn_item_class;
+
+ object_class = G_OBJECT_CLASS (item_class);
+ sn_item_class = SN_ITEM_CLASS (item_class);
+
+ object_class->constructed = gf_sound_item_constructed;
+ object_class->dispose = gf_sound_item_dispose;
+ object_class->finalize = gf_sound_item_finalize;
+ object_class->set_property = gf_sound_item_set_property;
+
+ sn_item_class->context_menu = gf_sound_item_context_menu;
+ sn_item_class->activate = gf_sound_item_activate;
+ sn_item_class->secondary_activate = gf_sound_item_secondary_activate;
+ sn_item_class->scroll = gf_sound_item_scroll;
+
+ properties[PROP_DISPLAY_NAME] =
+ g_param_spec_string ("display-name",
+ "Display Name",
+ "Name to display for this stream",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_ICON_NAMES] =
+ g_param_spec_boxed ("icon-names",
+ "Icon Names",
+ "Name of icon to display for this stream",
+ G_TYPE_STRV,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, LAST_PROP, properties);
+}
+
+static void
+gf_sound_item_init (GfSoundItem *item)
+{
+}
+
+GfSoundItem *
+gf_sound_item_new (SnItemCategory category,
+ const gchar *id,
+ const gchar *title,
+ const gchar *display_name,
+ const gchar **icon_names)
+{
+ return g_object_new (GF_TYPE_SOUND_ITEM,
+ "version", 1,
+ "category", category,
+ "id", id,
+ "title", title,
+ "display-name", display_name,
+ "icon-names", icon_names,
+ NULL);
+}
+
+static void
+notify_volume_cb (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GfSoundItem *item;
+
+ item = GF_SOUND_ITEM (user_data);
+
+ update_icon (item);
+ update_dock (item);
+}
+
+static void
+stream_notify_is_muted_cb (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GfSoundItem *item;
+
+ item = GF_SOUND_ITEM (user_data);
+
+ update_icon (item);
+ update_dock (item);
+}
+
+void
+gf_sound_item_set_mixer_stream (GfSoundItem *item,
+ GvcMixerStream *stream)
+{
+ GtkAdjustment *adjustment;
+ gdouble value;
+
+ clear_mixer_stream (item);
+
+ if (stream == NULL)
+ return;
+
+ item->mixer_stream = g_object_ref (stream);
+
+ gvc_channel_bar_set_base_volume (GVC_CHANNEL_BAR (item->bar),
+ gvc_mixer_stream_get_base_volume (stream));
+ gvc_channel_bar_set_is_amplified (GVC_CHANNEL_BAR (item->bar),
+ gvc_mixer_stream_get_can_decibel (stream));
+
+ adjustment = gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (item->bar));
+ value = gvc_mixer_stream_get_volume (item->mixer_stream);
+
+ g_signal_handlers_block_by_func (adjustment, value_changed_cb, item);
+ gtk_adjustment_set_value (adjustment, value);
+ g_signal_handlers_unblock_by_func (adjustment, value_changed_cb, item);
+
+ item->notify_volume_id =
+ g_signal_connect (item->mixer_stream, "notify::volume",
+ G_CALLBACK (notify_volume_cb), item);
+
+ item->notify_is_muted_id =
+ g_signal_connect (item->mixer_stream, "notify::is-muted",
+ G_CALLBACK (stream_notify_is_muted_cb), item);
+
+ update_icon (item);
+}
diff --git a/gnome-flashback/libsound-applet/gf-sound-item.h b/gnome-flashback/libsound-applet/gf-sound-item.h
new file mode 100644
index 0000000..d6e3adb
--- /dev/null
+++ b/gnome-flashback/libsound-applet/gf-sound-item.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GF_SOUND_ITEM_H
+#define GF_SOUND_ITEM_H
+
+#include <glib-object.h>
+#include <libstatus-notifier/sn.h>
+
+#include "gvc-mixer-stream.h"
+
+G_BEGIN_DECLS
+
+#define GF_TYPE_SOUND_ITEM gf_sound_item_get_type ()
+G_DECLARE_FINAL_TYPE (GfSoundItem, gf_sound_item, GF, SOUND_ITEM, SnItem)
+
+GfSoundItem *gf_sound_item_new (SnItemCategory category,
+ const gchar *id,
+ const gchar *title,
+ const gchar *display_name,
+ const gchar **icon_names);
+
+void gf_sound_item_set_mixer_stream (GfSoundItem *item,
+ GvcMixerStream *stream);
+
+G_END_DECLS
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]