summaryrefslogtreecommitdiff
path: root/mate-volume-control
diff options
context:
space:
mode:
authorMichal Ratajsky <[email protected]>2014-07-18 17:55:53 +0200
committerinfirit <[email protected]>2014-10-09 16:53:00 +0200
commit0c558fac14266f8c18cfb8bc1d4669ed35868c2f (patch)
treefb7479547b7c1032b13a1adc0f33e9c71861251a /mate-volume-control
parent25445eb4cb2d7b49bc435113056587f83b742104 (diff)
downloadmate-media-0c558fac14266f8c18cfb8bc1d4669ed35868c2f.tar.bz2
mate-media-0c558fac14266f8c18cfb8bc1d4669ed35868c2f.tar.xz
More porting work along with fixes and cleanups
Diffstat (limited to 'mate-volume-control')
-rw-r--r--mate-volume-control/src/Makefile.am2
-rw-r--r--mate-volume-control/src/applet-main.c7
-rw-r--r--mate-volume-control/src/dialog-main.c52
-rw-r--r--mate-volume-control/src/gvc-applet.c170
-rw-r--r--mate-volume-control/src/gvc-applet.h1
-rw-r--r--mate-volume-control/src/gvc-balance-bar.c401
-rw-r--r--mate-volume-control/src/gvc-balance-bar.h3
-rw-r--r--mate-volume-control/src/gvc-channel-bar.c1403
-rw-r--r--mate-volume-control/src/gvc-channel-bar.h99
-rw-r--r--mate-volume-control/src/gvc-combo-box.c327
-rw-r--r--mate-volume-control/src/gvc-combo-box.h38
-rw-r--r--mate-volume-control/src/gvc-level-bar.c542
-rw-r--r--mate-volume-control/src/gvc-level-bar.h36
-rw-r--r--mate-volume-control/src/gvc-mixer-dialog.c1889
-rw-r--r--mate-volume-control/src/gvc-mixer-dialog.h2
-rw-r--r--mate-volume-control/src/gvc-speaker-test.c436
-rw-r--r--mate-volume-control/src/gvc-speaker-test.h20
-rw-r--r--mate-volume-control/src/gvc-stream-status-icon.c642
-rw-r--r--mate-volume-control/src/gvc-stream-status-icon.h9
-rw-r--r--mate-volume-control/src/mvc-helpers.c240
-rw-r--r--mate-volume-control/src/mvc-helpers.h6
21 files changed, 3571 insertions, 2754 deletions
diff --git a/mate-volume-control/src/Makefile.am b/mate-volume-control/src/Makefile.am
index 8dd1b93..3ca81f5 100644
--- a/mate-volume-control/src/Makefile.am
+++ b/mate-volume-control/src/Makefile.am
@@ -9,7 +9,7 @@ AM_CPPFLAGS = \
$(WARN_CFLAGS) \
-I$(top_srcdir)/sound-theme \
$(VOLUME_CONTROL_CFLAGS) \
- $(DISABLE_DEPRECATED) \
+ $(xxDISABLE_DEPRECATED) \
$(PULSEAUDIO_CFLAGS) \
-DLOCALE_DIR=\""$(datadir)/locale"\" \
-DLIBEXECDIR=\"$(libexecdir)\" \
diff --git a/mate-volume-control/src/applet-main.c b/mate-volume-control/src/applet-main.c
index 34151ba..1c260fc 100644
--- a/mate-volume-control/src/applet-main.c
+++ b/mate-volume-control/src/applet-main.c
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -20,8 +21,9 @@
#include "config.h"
-#include <glib/gi18n.h>
#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
#include <gtk/gtk.h>
#include <libintl.h>
@@ -37,7 +39,7 @@ main (int argc, char **argv)
{
GError *error = NULL;
GvcApplet *applet;
- UniqueApp *app = NULL;
+ UniqueApp *app;
GOptionEntry entries[] = {
{ "version", 'v', 0, G_OPTION_ARG_NONE, &show_version, N_("Version of this application"), NULL },
{ NULL }
@@ -51,6 +53,7 @@ main (int argc, char **argv)
(char *) _(" — MATE Volume Control Applet"),
entries, GETTEXT_PACKAGE,
&error);
+
if (error != NULL) {
g_warning ("%s", error->message);
return 1;
diff --git a/mate-volume-control/src/dialog-main.c b/mate-volume-control/src/dialog-main.c
index 2b139b1..24cae78 100644
--- a/mate-volume-control/src/dialog-main.c
+++ b/mate-volume-control/src/dialog-main.c
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -20,11 +21,11 @@
#include "config.h"
-#include <libintl.h>
-#include <glib/gi18n.h>
#include <glib.h>
+#include <glib/gi18n.h>
#include <gtk/gtk.h>
+#include <libintl.h>
#include <unique/uniqueapp.h>
#include <libmatemixer/matemixer.h>
@@ -42,10 +43,10 @@ static GtkWidget *warning_dialog = NULL;
static void
on_dialog_response (GtkDialog *dialog, guint response_id, gpointer data)
{
- gboolean destroy = GPOINTER_TO_INT (data);
+ gboolean destroy = GPOINTER_TO_INT (data);
- if (destroy)
- gtk_widget_destroy (GTK_WIDGET (dialog));
+ if (destroy)
+ gtk_widget_destroy (GTK_WIDGET (dialog));
gtk_main_quit ();
}
@@ -53,10 +54,10 @@ on_dialog_response (GtkDialog *dialog, guint response_id, gpointer data)
static void
on_dialog_close (GtkDialog *dialog, gpointer data)
{
- gboolean destroy = GPOINTER_TO_INT (data);
+ gboolean destroy = GPOINTER_TO_INT (data);
- if (destroy)
- gtk_widget_destroy (GTK_WIDGET (dialog));
+ if (destroy)
+ gtk_widget_destroy (GTK_WIDGET (dialog));
gtk_main_quit ();
}
@@ -76,12 +77,12 @@ on_app_message_received (UniqueApp *app,
static void
remove_warning_dialog (void)
{
- if (popup_id != 0) {
- g_source_remove (popup_id);
- popup_id = 0;
- }
+ if (popup_id != 0) {
+ g_source_remove (popup_id);
+ popup_id = 0;
+ }
- g_clear_pointer (&warning_dialog, gtk_widget_destroy);
+ g_clear_pointer (&warning_dialog, gtk_widget_destroy);
}
static void
@@ -93,25 +94,30 @@ control_ready (MateMixerControl *control, UniqueApp *app)
return;
app_dialog = GTK_WIDGET (gvc_mixer_dialog_new (control));
- g_signal_connect (app_dialog,
+
+ g_signal_connect (G_OBJECT (app_dialog),
"response",
G_CALLBACK (on_dialog_response),
GINT_TO_POINTER (FALSE));
- g_signal_connect (app_dialog,
+ g_signal_connect (G_OBJECT (app_dialog),
"close",
G_CALLBACK (on_dialog_close),
GINT_TO_POINTER (FALSE));
gvc_mixer_dialog_set_page (GVC_MIXER_DIALOG (app_dialog), page);
- g_signal_connect (app, "message-received",
- G_CALLBACK (on_app_message_received), app_dialog);
+ g_signal_connect (G_OBJECT (app),
+ "message-received",
+ G_CALLBACK (on_app_message_received),
+ app_dialog);
gtk_widget_show (app_dialog);
}
static void
-on_control_state_notify (MateMixerControl *control, UniqueApp *app)
+on_control_state_notify (MateMixerControl *control,
+ GParamSpec *pspec,
+ UniqueApp *app)
{
MateMixerState state = mate_mixer_control_get_state (control);
gboolean failed = FALSE;
@@ -194,6 +200,7 @@ main (int argc, char **argv)
(char *) _(" — MATE Volume Control"),
entries, GETTEXT_PACKAGE,
&error);
+
if (error != NULL) {
g_warning ("%s", error->message);
return 1;
@@ -206,8 +213,8 @@ main (int argc, char **argv)
app = unique_app_new (GVC_DIALOG_DBUS_NAME, NULL);
if (unique_app_is_running (app)) {
- unique_app_send_message (app, UNIQUE_ACTIVATE, NULL);
- return 0;
+ unique_app_send_message (app, UNIQUE_ACTIVATE, NULL);
+ return 0;
}
if (!mate_mixer_init ()) {
g_warning ("libmatemixer initialization failed, exiting");
@@ -216,19 +223,20 @@ main (int argc, char **argv)
control = mate_mixer_control_new ();
+ mate_mixer_control_set_backend_type (control, MATE_MIXER_BACKEND_NULL);
+
mate_mixer_control_set_app_name (control, _("Volume Control"));
mate_mixer_control_set_app_id (control, GVC_DIALOG_DBUS_NAME);
mate_mixer_control_set_app_version (control, VERSION);
mate_mixer_control_set_app_icon (control, "multimedia-volume-control");
- g_signal_connect (control,
+ g_signal_connect (G_OBJECT (control),
"notify::state",
G_CALLBACK (on_control_state_notify),
app);
mate_mixer_control_open (control);
- /* */
if (mate_mixer_control_get_state (control) == MATE_MIXER_STATE_CONNECTING)
popup_id = g_timeout_add_seconds (DIALOG_POPUP_TIMEOUT,
dialog_popup_timeout,
diff --git a/mate-volume-control/src/gvc-applet.c b/mate-volume-control/src/gvc-applet.c
index 4522a8f..b2f40a1 100644
--- a/mate-volume-control/src/gvc-applet.c
+++ b/mate-volume-control/src/gvc-applet.c
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
*
* 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
@@ -18,17 +19,14 @@
*
*/
-// XXX there are some bugs unrelated to the port, let's see if I can fix them:
-// - clicking in the slider makes it disappear
-// - drag all the way down to mute, then start dragging up and the change won't
-// be reflected until i stop dragging
-// - disable the slider if the volume is not changable
-
#include "config.h"
+#include <string.h>
#include <glib.h>
#include <glib/gi18n.h>
+#include <glib-object.h>
#include <gtk/gtk.h>
+
#include <libmatemixer/matemixer.h>
#include "gvc-applet.h"
@@ -75,39 +73,69 @@ update_icon_input (GvcApplet *applet)
* is a non-mixer application using the input */
stream = mate_mixer_control_get_default_input_stream (applet->priv->control);
if (stream != NULL) {
- const gchar *app;
+ const gchar *app_id;
const GList *inputs =
mate_mixer_control_list_streams (applet->priv->control);
- while (inputs) {
+ while (inputs != NULL) {
MateMixerStream *input = MATE_MIXER_STREAM (inputs->data);
MateMixerStreamFlags flags = mate_mixer_stream_get_flags (input);
- if (flags & MATE_MIXER_STREAM_INPUT &&
- flags & MATE_MIXER_STREAM_APPLICATION) {
+ if (flags & MATE_MIXER_STREAM_INPUT && flags & MATE_MIXER_STREAM_CLIENT) {
MateMixerClientStream *client =
MATE_MIXER_CLIENT_STREAM (input);
- app = mate_mixer_client_stream_get_app_id (client);
- if (app == NULL) {
+ MateMixerClientStreamRole client_role =
+ mate_mixer_client_stream_get_role (client);
+ MateMixerClientStreamFlags client_flags =
+ mate_mixer_client_stream_get_flags (client);
+
+ if (!(client_flags & MATE_MIXER_CLIENT_STREAM_APPLICATION) ||
+ client_role == MATE_MIXER_CLIENT_STREAM_ROLE_EVENT ||
+ client_role == MATE_MIXER_CLIENT_STREAM_ROLE_TEST ||
+ client_role == MATE_MIXER_CLIENT_STREAM_ROLE_ABSTRACT ||
+ client_role == MATE_MIXER_CLIENT_STREAM_ROLE_FILTER) {
+ /* Skip roles we don't care about and non-application
+ * client streams */
+ inputs = inputs->next;
+ continue;
+ }
+
+ app_id = mate_mixer_client_stream_get_app_id (client);
+ if (app_id == NULL) {
/* A recording application which has no
* identifier set */
+ g_debug ("Found a recording application %s (%s)",
+ mate_mixer_stream_get_name (input),
+ mate_mixer_stream_get_description (input));
show = TRUE;
break;
}
- if (!g_str_equal (app, "org.mate.VolumeControl") &&
- !g_str_equal (app, "org.gnome.VolumeControl") &&
- !g_str_equal (app, "org.PulseAudio.pavucontrol")) {
+ if (strcmp (app_id, "org.mate.VolumeControl") != 0 &&
+ strcmp (app_id, "org.gnome.VolumeControl") != 0 &&
+ strcmp (app_id, "org.PulseAudio.pavucontrol") != 0) {
+ g_debug ("Found a recording application %s", app_id);
show = TRUE;
break;
}
}
inputs = inputs->next;
}
+
+ g_debug ("Current default input stream is %s (%s)",
+ mate_mixer_stream_get_name (stream),
+ mate_mixer_stream_get_description (stream));
+
+ if (show)
+ g_debug ("Input icon enabled");
+ else
+ g_debug ("There is no recording application, input icon disabled");
+ } else {
+ g_debug ("There is no default input stream, input icon disabled");
}
- gvc_stream_status_icon_set_mixer_stream (applet->priv->icon_input, stream);
+ gvc_stream_status_icon_set_stream (applet->priv->icon_input, stream);
gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->priv->icon_input), show);
}
@@ -119,33 +147,23 @@ update_icon_output (GvcApplet *applet)
stream = mate_mixer_control_get_default_output_stream (applet->priv->control);
- gvc_stream_status_icon_set_mixer_stream (applet->priv->icon_output, stream);
-
- /* Enable the output icon in case there is an output stream present */
- gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->priv->icon_output),
- (stream != NULL) ? TRUE : FALSE);
-}
-
-void
-gvc_applet_start (GvcApplet *applet)
-{
- g_return_if_fail (GVC_IS_APPLET (applet));
+ gvc_stream_status_icon_set_stream (applet->priv->icon_output, stream);
- if (G_UNLIKELY (applet->priv->running))
- return;
+ if (stream != NULL) {
+ g_debug ("Current default output stream is %s (%s)",
+ mate_mixer_stream_get_name (stream),
+ mate_mixer_stream_get_description (stream));
- if (mate_mixer_control_open (applet->priv->control) == FALSE) {
- /* Normally this should never happen, in the worst case we
- * should end up with the Null module */
- g_warning ("Failed to connect to a sound system");
+ gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->priv->icon_output),
+ TRUE);
+ g_debug ("Output icon enabled");
+ } else {
gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->priv->icon_output),
FALSE);
- gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->priv->icon_input),
- FALSE);
- }
- applet->priv->running = TRUE;
+ g_debug ("There is no default output stream, output icon disabled");
+ }
}
static void
@@ -155,12 +173,20 @@ on_control_state_notify (MateMixerControl *control,
{
MateMixerState state = mate_mixer_control_get_state (control);
- if (state == MATE_MIXER_STATE_FAILED)
+ switch (state) {
+ case MATE_MIXER_STATE_FAILED:
g_warning ("Failed to connect to a sound system");
+ break;
- /* Each status change may affect the visibility of the icons */
- update_icon_output (applet);
- update_icon_input (applet);
+ case MATE_MIXER_STATE_READY:
+ case MATE_MIXER_STATE_CONNECTING:
+ /* Each status change may affect the visibility of the icons */
+ update_icon_output (applet);
+ update_icon_input (applet);
+ break;
+ default:
+ break;
+ }
}
static void
@@ -195,9 +221,21 @@ on_control_stream_added (MateMixerControl *control,
/* Newly added input application stream may cause the input status
* icon to change visibility */
- if (flags & MATE_MIXER_STREAM_INPUT &&
- flags & MATE_MIXER_STREAM_APPLICATION)
- update_icon_input (applet);
+ if (flags & MATE_MIXER_STREAM_CLIENT && flags & MATE_MIXER_STREAM_INPUT) {
+ MateMixerClientStreamFlags client_flags =
+ mate_mixer_client_stream_get_flags (MATE_MIXER_CLIENT_STREAM (stream));
+
+ if (client_flags & MATE_MIXER_CLIENT_STREAM_APPLICATION) {
+ g_debug ("Added input application stream %s (%s)",
+ mate_mixer_stream_get_name (stream),
+ mate_mixer_stream_get_description (stream));
+
+ update_icon_input (applet);
+ }
+ } else
+ g_debug ("Ignoring new stream %s (%s)",
+ mate_mixer_stream_get_name (stream),
+ mate_mixer_stream_get_description (stream));
}
static void
@@ -205,11 +243,45 @@ on_control_stream_removed (MateMixerControl *control,
const gchar *name,
GvcApplet *applet)
{
+ g_debug ("Removed stream %s", name);
+
/* The removed stream could be an application input, which may cause
* the input status icon to disappear */
update_icon_input (applet);
}
+void
+gvc_applet_start (GvcApplet *applet)
+{
+ MateMixerState state;
+
+ g_return_if_fail (GVC_IS_APPLET (applet));
+
+ if (G_UNLIKELY (applet->priv->running == TRUE))
+ return;
+
+ state = mate_mixer_control_get_state (applet->priv->control);
+
+ if (G_UNLIKELY (state != MATE_MIXER_STATE_IDLE)) {
+ g_warn_if_reached ();
+ } else {
+ if (mate_mixer_control_open (applet->priv->control) == FALSE) {
+ /* Normally this should never happen, in the worst case we
+ * should end up with the Null module */
+ g_warning ("Failed to connect to a sound system");
+ }
+
+ gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->priv->icon_output),
+ FALSE);
+ gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->priv->icon_input),
+ FALSE);
+ }
+
+ g_debug ("Applet has been started");
+
+ applet->priv->running = TRUE;
+}
+
static void
gvc_applet_dispose (GObject *object)
{
@@ -257,23 +329,23 @@ gvc_applet_init (GvcApplet *applet)
mate_mixer_control_set_app_version (applet->priv->control, VERSION);
mate_mixer_control_set_app_icon (applet->priv->control, "multimedia-volume-control");
- g_signal_connect (applet->priv->control,
+ g_signal_connect (G_OBJECT (applet->priv->control),
"notify::state",
G_CALLBACK (on_control_state_notify),
applet);
- g_signal_connect (applet->priv->control,
+ g_signal_connect (G_OBJECT (applet->priv->control),
"notify::default-input",
G_CALLBACK (on_control_default_input_notify),
applet);
- g_signal_connect (applet->priv->control,
+ g_signal_connect (G_OBJECT (applet->priv->control),
"notify::default-output",
G_CALLBACK (on_control_default_output_notify),
applet);
- g_signal_connect (applet->priv->control,
+ g_signal_connect (G_OBJECT (applet->priv->control),
"stream-added",
G_CALLBACK (on_control_stream_added),
applet);
- g_signal_connect (applet->priv->control,
+ g_signal_connect (G_OBJECT (applet->priv->control),
"stream-removed",
G_CALLBACK (on_control_stream_removed),
applet);
diff --git a/mate-volume-control/src/gvc-applet.h b/mate-volume-control/src/gvc-applet.h
index 50b3a80..991ef6d 100644
--- a/mate-volume-control/src/gvc-applet.h
+++ b/mate-volume-control/src/gvc-applet.h
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
*
* 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
diff --git a/mate-volume-control/src/gvc-balance-bar.c b/mate-volume-control/src/gvc-balance-bar.c
index 0730b67..f31d136 100644
--- a/mate-volume-control/src/gvc-balance-bar.c
+++ b/mate-volume-control/src/gvc-balance-bar.c
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 William Jon McCann
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
*
* 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
@@ -18,10 +19,9 @@
*
*/
-#include "config.h"
-
#include <glib.h>
#include <glib/gi18n.h>
+#include <glib-object.h>
#include <gtk/gtk.h>
#include <canberra-gtk.h>
@@ -29,14 +29,17 @@
#include "gvc-balance-bar.h"
-#define SCALE_SIZE 128
-#define ADJUSTMENT_MAX_NORMAL 65536.0 /* PA_VOLUME_NORM */ // XXX
+#define BALANCE_BAR_STYLE \
+ "style \"balance-bar-scale-style\" {\n" \
+ " GtkScale::trough-side-details = 0\n" \
+ "}\n" \
+ "widget \"*.balance-bar-scale\" style : rc \"balance-bar-scale-style\"\n"
+#define SCALE_SIZE 128
#define GVC_BALANCE_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_BALANCE_BAR, GvcBalanceBarPrivate))
struct _GvcBalanceBarPrivate
{
- MateMixerStream *stream;
GvcBalanceType btype;
GtkWidget *scale_box;
GtkWidget *start_box;
@@ -46,7 +49,8 @@ struct _GvcBalanceBarPrivate
GtkAdjustment *adjustment;
GtkSizeGroup *size_group;
gboolean symmetric;
- gboolean click_lock;
+ MateMixerStream *stream;
+ gint lfe_channel;
};
enum
@@ -59,21 +63,16 @@ enum
static GParamSpec *properties[N_PROPERTIES] = { NULL, };
-static void gvc_balance_bar_class_init (GvcBalanceBarClass *klass);
-static void gvc_balance_bar_init (GvcBalanceBar *balance_bar);
-static void gvc_balance_bar_dispose (GObject *object);
-
-static gboolean on_scale_button_press_event (GtkWidget *widget,
- GdkEventButton *event,
- GvcBalanceBar *bar);
-static gboolean on_scale_button_release_event (GtkWidget *widget,
- GdkEventButton *event,
- GvcBalanceBar *bar);
-static gboolean on_scale_scroll_event (GtkWidget *widget,
- GdkEventScroll *event,
- GvcBalanceBar *bar);
-static void on_adjustment_value_changed (GtkAdjustment *adjustment,
- GvcBalanceBar *bar);
+static void gvc_balance_bar_class_init (GvcBalanceBarClass *klass);
+static void gvc_balance_bar_init (GvcBalanceBar *balance_bar);
+static void gvc_balance_bar_dispose (GObject *object);
+
+static gboolean on_scale_scroll_event (GtkWidget *widget,
+ GdkEventScroll *event,
+ GvcBalanceBar *bar);
+
+static void on_adjustment_value_changed (GtkAdjustment *adjustment,
+ GvcBalanceBar *bar);
#if GTK_CHECK_VERSION (3, 0, 0)
G_DEFINE_TYPE (GvcBalanceBar, gvc_balance_bar, GTK_TYPE_BOX)
@@ -81,33 +80,78 @@ G_DEFINE_TYPE (GvcBalanceBar, gvc_balance_bar, GTK_TYPE_BOX)
G_DEFINE_TYPE (GvcBalanceBar, gvc_balance_bar, GTK_TYPE_HBOX)
#endif
-static GtkWidget *
-_scale_box_new (GvcBalanceBar *bar)
+static void
+create_scale_box (GvcBalanceBar *bar)
{
- GvcBalanceBarPrivate *priv = bar->priv;
- GtkWidget *box;
- GtkWidget *sbox;
- GtkWidget *ebox;
- GtkAdjustment *adjustment = bar->priv->adjustment;
- char *str_lower, *str_upper;
- gdouble lower, upper;
+#if GTK_CHECK_VERSION (3, 0, 0)
+ bar->priv->scale_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ bar->priv->start_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ bar->priv->end_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ bar->priv->scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL,
+ bar->priv->adjustment);
+#if GTK_CHECK_VERSION (3, 4, 0)
+ /* Balance and fade scales do not have an origin */
+ if (bar->priv->btype != BALANCE_TYPE_LFE)
+ gtk_scale_set_has_origin (GTK_SCALE (bar->priv->scale), FALSE);
+#endif
+#else
+ bar->priv->scale_box = gtk_hbox_new (FALSE, 6);
+ bar->priv->start_box = gtk_hbox_new (FALSE, 6);
+ bar->priv->end_box = gtk_hbox_new (FALSE, 6);
+ bar->priv->scale = gtk_hscale_new (bar->priv->adjustment);
+
+ /* GTK2 way to remove the origin */
+ if (bar->priv->btype != BALANCE_TYPE_LFE) {
+ gtk_rc_parse_string (BALANCE_BAR_STYLE);
+ gtk_widget_set_name (bar->priv->scale, "balance-bar-scale");
+ }
+#endif
- bar->priv->scale_box = box = gtk_hbox_new (FALSE, 6);
- priv->scale = gtk_hscale_new (priv->adjustment);
- gtk_widget_set_size_request (priv->scale, SCALE_SIZE, -1);
+ gtk_widget_set_size_request (bar->priv->scale, SCALE_SIZE, -1);
+
+ gtk_box_pack_start (GTK_BOX (bar->priv->scale_box),
+ bar->priv->start_box,
+ FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (bar->priv->start_box),
+ bar->priv->label,
+ FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (bar->priv->scale_box),
+ bar->priv->scale,
+ TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (bar->priv->scale_box),
+ bar->priv->end_box,
+ FALSE, FALSE, 0);
- gtk_widget_set_name (priv->scale, "balance-bar-scale");
- gtk_rc_parse_string ("style \"balance-bar-scale-style\" {\n"
- " GtkScale::trough-side-details = 0\n"
- "}\n"
- "widget \"*.balance-bar-scale\" style : rc \"balance-bar-scale-style\"\n");
+ ca_gtk_widget_disable_sounds (bar->priv->scale, FALSE);
- bar->priv->start_box = sbox = gtk_hbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (box), sbox, FALSE, FALSE, 0);
+ gtk_widget_add_events (bar->priv->scale, GDK_SCROLL_MASK);
- gtk_box_pack_start (GTK_BOX (sbox), priv->label, FALSE, FALSE, 0);
+ g_signal_connect (G_OBJECT (bar->priv->scale),
+ "scroll-event",
+ G_CALLBACK (on_scale_scroll_event),
+ bar);
- gtk_box_pack_start (GTK_BOX (box), priv->scale, TRUE, TRUE, 0);
+ if (bar->priv->size_group != NULL) {
+ gtk_size_group_add_widget (bar->priv->size_group,
+ bar->priv->start_box);
+
+ if (bar->priv->symmetric)
+ gtk_size_group_add_widget (bar->priv->size_group,
+ bar->priv->end_box);
+ }
+
+ gtk_scale_set_draw_value (GTK_SCALE (bar->priv->scale), FALSE);
+}
+
+static void
+update_scale_marks (GvcBalanceBar *bar)
+{
+ gchar *str_lower = NULL,
+ *str_upper = NULL;
+ gdouble lower,
+ upper;
+
+ gtk_scale_clear_marks (GTK_SCALE (bar->priv->scale));
switch (bar->priv->btype) {
case BALANCE_TYPE_RL:
@@ -122,49 +166,26 @@ _scale_box_new (GvcBalanceBar *bar)
str_lower = g_strdup_printf ("<small>%s</small>", C_("balance", "Minimum"));
str_upper = g_strdup_printf ("<small>%s</small>", C_("balance", "Maximum"));
break;
- default:
- g_assert_not_reached ();
}
- lower = gtk_adjustment_get_lower (adjustment);
- gtk_scale_add_mark (GTK_SCALE (priv->scale), lower,
- GTK_POS_BOTTOM, str_lower);
+ lower = gtk_adjustment_get_lower (bar->priv->adjustment);
+ gtk_scale_add_mark (GTK_SCALE (bar->priv->scale),
+ lower,
+ GTK_POS_BOTTOM,
+ str_lower);
+ upper = gtk_adjustment_get_upper (bar->priv->adjustment);
+ gtk_scale_add_mark (GTK_SCALE (bar->priv->scale),
+ upper,
+ GTK_POS_BOTTOM,
+ str_upper);
g_free (str_lower);
- upper = gtk_adjustment_get_upper (adjustment);
- gtk_scale_add_mark (GTK_SCALE (priv->scale), upper,
- GTK_POS_BOTTOM, str_upper);
g_free (str_upper);
- if (bar->priv->btype != BALANCE_TYPE_LFE) {
- gtk_scale_add_mark (GTK_SCALE (priv->scale),
- (upper - lower)/2 + lower,
- GTK_POS_BOTTOM, NULL);
- }
-
- bar->priv->end_box = ebox = gtk_hbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, FALSE, 0);
-
- ca_gtk_widget_disable_sounds (bar->priv->scale, FALSE);
- gtk_widget_add_events (bar->priv->scale, GDK_SCROLL_MASK);
-
- g_signal_connect (G_OBJECT (bar->priv->scale), "button-press-event",
- G_CALLBACK (on_scale_button_press_event), bar);
- g_signal_connect (G_OBJECT (bar->priv->scale), "button-release-event",
- G_CALLBACK (on_scale_button_release_event), bar);
- g_signal_connect (G_OBJECT (bar->priv->scale), "scroll-event",
- G_CALLBACK (on_scale_scroll_event), bar);
-
- if (bar->priv->size_group != NULL) {
- gtk_size_group_add_widget (bar->priv->size_group, sbox);
-
- if (bar->priv->symmetric) {
- gtk_size_group_add_widget (bar->priv->size_group, ebox);
- }
- }
-
- gtk_scale_set_draw_value (GTK_SCALE (priv->scale), FALSE);
-
- return box;
+ if (bar->priv->btype != BALANCE_TYPE_LFE)
+ gtk_scale_add_mark (GTK_SCALE (bar->priv->scale),
+ (upper - lower) / 2 + lower,
+ GTK_POS_BOTTOM,
+ NULL);
}
void
@@ -173,6 +194,7 @@ gvc_balance_bar_set_size_group (GvcBalanceBar *bar,
gboolean symmetric)
{
g_return_if_fail (GVC_IS_BALANCE_BAR (bar));
+ g_return_if_fail (GTK_IS_SIZE_GROUP (group));
bar->priv->size_group = group;
bar->priv->symmetric = symmetric;
@@ -181,31 +203,13 @@ gvc_balance_bar_set_size_group (GvcBalanceBar *bar,
gtk_size_group_add_widget (bar->priv->size_group,
bar->priv->start_box);
- if (bar->priv->symmetric) {
+ if (bar->priv->symmetric)
gtk_size_group_add_widget (bar->priv->size_group,
bar->priv->end_box);
- }
}
gtk_widget_queue_draw (GTK_WIDGET (bar));
}
-static const char *
-btype_to_string (guint btype)
-{
- switch (btype) {
- case BALANCE_TYPE_RL:
- return "Balance";
- case BALANCE_TYPE_FR:
- return "Fade";
- break;
- case BALANCE_TYPE_LFE:
- return "LFE";
- default:
- g_assert_not_reached ();
- }
- return NULL;
-}
-
static void
update_balance_value (GvcBalanceBar *bar)
{
@@ -214,20 +218,20 @@ update_balance_value (GvcBalanceBar *bar)
switch (bar->priv->btype) {
case BALANCE_TYPE_RL:
value = mate_mixer_stream_get_balance (bar->priv->stream);
+ g_debug ("Balance value changed to %.2f", value);
break;
case BALANCE_TYPE_FR:
value = mate_mixer_stream_get_fade (bar->priv->stream);
+ g_debug ("Fade value changed to %.2f", value);
break;
case BALANCE_TYPE_LFE:
- value = mate_mixer_stream_get_position_volume (bar->priv->stream,
- MATE_MIXER_CHANNEL_LFE);
+ value = mate_mixer_stream_get_channel_volume (bar->priv->stream,
+ bar->priv->lfe_channel);
+
+ g_debug ("Subwoofer volume changed to %.0f", value);
break;
- default:
- g_assert_not_reached ();
}
- g_debug ("%s value changed to %.1f", btype_to_string (bar->priv->btype), value);
-
gtk_adjustment_set_value (bar->priv->adjustment, value);
}
@@ -239,6 +243,22 @@ on_balance_value_changed (MateMixerStream *stream,
update_balance_value (bar);
}
+static gint
+find_stream_lfe_channel (MateMixerStream *stream)
+{
+ guint i;
+
+ for (i = 0; i < mate_mixer_stream_get_num_channels (stream); i++) {
+ MateMixerChannelPosition position;
+
+ position = mate_mixer_stream_get_channel_position (stream, i);
+ if (position == MATE_MIXER_CHANNEL_LFE)
+ return i;
+ }
+
+ return -1;
+}
+
static void
gvc_balance_bar_set_stream (GvcBalanceBar *bar, MateMixerStream *stream)
{
@@ -254,6 +274,37 @@ gvc_balance_bar_set_stream (GvcBalanceBar *bar, MateMixerStream *stream)
bar->priv->stream = g_object_ref (stream);
+ if (bar->priv->btype == BALANCE_TYPE_LFE) {
+ gdouble minimum = 0.0;
+ gdouble maximum = 0.0;
+
+ if (mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_HAS_VOLUME) {
+ minimum = mate_mixer_stream_get_min_volume (stream);
+ maximum = mate_mixer_stream_get_normal_volume (stream);
+ }
+
+ /* Configure the adjustment for the volume limits of the current
+ * stream.
+ * Only subwoofer scale uses volume, balance and fade use fixed
+ * limits which do not need to be updated as balance type is
+ * only set during construction. */
+ gtk_adjustment_configure (GTK_ADJUSTMENT (bar->priv->adjustment),
+ gtk_adjustment_get_value (bar->priv->adjustment),
+ minimum,
+ maximum,
+ (maximum - minimum) / 100.0,
+ (maximum - minimum) / 10.0,
+ 0.0);
+
+ bar->priv->lfe_channel = find_stream_lfe_channel (stream);
+
+ if (G_LIKELY (bar->priv->lfe_channel > -1))
+ g_debug ("Found LFE channel at position %d", bar->priv->lfe_channel);
+ else
+ g_warn_if_reached ();
+ } else
+ bar->priv->lfe_channel = -1;
+
switch (bar->priv->btype) {
case BALANCE_TYPE_RL:
g_signal_connect (G_OBJECT (stream),
@@ -273,41 +324,30 @@ gvc_balance_bar_set_stream (GvcBalanceBar *bar, MateMixerStream *stream)
G_CALLBACK (on_balance_value_changed),
bar);
break;
- default:
- g_assert_not_reached ();
}
update_balance_value (bar);
+ update_scale_marks (bar);
- g_object_notify (G_OBJECT (bar), "stream");
+ g_object_notify_by_pspec (G_OBJECT (bar), properties[PROP_STREAM]);
}
static void
gvc_balance_bar_set_balance_type (GvcBalanceBar *bar, GvcBalanceType btype)
{
- GtkWidget *frame;
+ GtkWidget *frame;
+ GtkAdjustment *adjustment;
- g_return_if_fail (GVC_BALANCE_BAR (bar));
+ /* Create adjustment with limits for balance and fade types because
+ * some limits must be provided.
+ * If subwoofer type is used instead, the limits will be changed when
+ * stream is set. */
+ adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, -1.0, 1.0, 0.05, 0.5, 0.0));
bar->priv->btype = btype;
- if (bar->priv->btype != BALANCE_TYPE_LFE) {
- bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
- -1.0,
- 1.0,
- 0.5,
- 0.5,
- 0.0));
- } else {
- bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
- 0.0,
- ADJUSTMENT_MAX_NORMAL,
- ADJUSTMENT_MAX_NORMAL/100.0,
- ADJUSTMENT_MAX_NORMAL/10.0,
- 0.0));
- }
+ bar->priv->adjustment = GTK_ADJUSTMENT (g_object_ref_sink (adjustment));
- g_object_ref_sink (bar->priv->adjustment);
- g_signal_connect (bar->priv->adjustment,
+ g_signal_connect (G_OBJECT (adjustment),
"value-changed",
G_CALLBACK (on_adjustment_value_changed),
bar);
@@ -322,27 +362,26 @@ gvc_balance_bar_set_balance_type (GvcBalanceBar *bar, GvcBalanceType btype)
case BALANCE_TYPE_LFE:
bar->priv->label = gtk_label_new_with_mnemonic (_("_Subwoofer:"));
break;
- default:
- g_assert_not_reached ();
}
- gtk_misc_set_alignment (GTK_MISC (bar->priv->label),
- 0.0,
- 0.0);
- /* frame */
+
+ gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0.0, 0.0);
+
+ /* Frame */
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
- gtk_container_add (GTK_CONTAINER (bar), frame);
+ gtk_box_pack_start (GTK_BOX (bar), frame, TRUE, TRUE, 0);
- /* box with scale */
- bar->priv->scale_box = _scale_box_new (bar);
+ /* Box with scale */
+ create_scale_box (bar);
gtk_container_add (GTK_CONTAINER (frame), bar->priv->scale_box);
- gtk_widget_show_all (frame);
- gtk_widget_set_direction (bar->priv->scale, GTK_TEXT_DIR_LTR);
gtk_label_set_mnemonic_widget (GTK_LABEL (bar->priv->label),
bar->priv->scale);
- g_object_notify (G_OBJECT (bar), "balance-type");
+ gtk_widget_set_direction (bar->priv->scale, GTK_TEXT_DIR_LTR);
+ gtk_widget_show_all (frame);
+
+ g_object_notify_by_pspec (G_OBJECT (bar), properties[PROP_BALANCE_TYPE]);
}
static void
@@ -414,60 +453,37 @@ gvc_balance_bar_class_init (GvcBalanceBarClass *klass)
g_type_class_add_private (klass, sizeof (GvcBalanceBarPrivate));
}
-
-static gboolean
-on_scale_button_press_event (GtkWidget *widget,
- GdkEventButton *event,
- GvcBalanceBar *bar)
-{
- // XXX this is unused
- bar->priv->click_lock = TRUE;
- return FALSE;
-}
-
-static gboolean
-on_scale_button_release_event (GtkWidget *widget,
- GdkEventButton *event,
- GvcBalanceBar *bar)
-{
- // XXX this is unused
- bar->priv->click_lock = FALSE;
- return FALSE;
-}
-
static gboolean
on_scale_scroll_event (GtkWidget *widget,
GdkEventScroll *event,
GvcBalanceBar *bar)
{
gdouble value;
-
- value = gtk_adjustment_get_value (bar->priv->adjustment);
-
- if (bar->priv->btype == BALANCE_TYPE_LFE) {
- if (event->direction == GDK_SCROLL_UP) {
- if (value + ADJUSTMENT_MAX_NORMAL/100.0 > ADJUSTMENT_MAX_NORMAL)
- value = ADJUSTMENT_MAX_NORMAL;
- else
- value = value + ADJUSTMENT_MAX_NORMAL/100.0;
- } else if (event->direction == GDK_SCROLL_DOWN) {
- if (value - ADJUSTMENT_MAX_NORMAL/100.0 < 0)
- value = 0.0;
- else
- value = value - ADJUSTMENT_MAX_NORMAL/100.0;
- }
- } else {
- if (event->direction == GDK_SCROLL_UP) {
- if (value + 0.01 > 1.0)
- value = 1.0;
- else
- value = value + 0.01;
- } else if (event->direction == GDK_SCROLL_DOWN) {
- if (value - 0.01 < 0)
- value = 0.0;
- else
- value = value - 0.01;
- }
+ gdouble minimum;
+ gdouble maximum;
+ gdouble step;
+
+ value = gtk_adjustment_get_value (bar->priv->adjustment);
+ minimum = gtk_adjustment_get_lower (bar->priv->adjustment);
+ maximum = gtk_adjustment_get_upper (bar->priv->adjustment);
+
+ // XXX fix this for GTK3
+
+ if (bar->priv->btype == BALANCE_TYPE_LFE)
+ step = (maximum - minimum) / 100.0;
+ else
+ step = 0.05;
+
+ if (event->direction == GDK_SCROLL_UP) {
+ if (value + step > maximum)
+ value = maximum;
+ else
+ value = value + step;
+ } else if (event->direction == GDK_SCROLL_DOWN) {
+ if (value - step < minimum)
+ value = minimum;
+ else
+ value = value - step;
}
gtk_adjustment_set_value (bar->priv->adjustment, value);
@@ -492,12 +508,10 @@ on_adjustment_value_changed (GtkAdjustment *adjustment, GvcBalanceBar *bar)
mate_mixer_stream_set_fade (bar->priv->stream, value);
break;
case BALANCE_TYPE_LFE:
- mate_mixer_stream_set_position_volume (bar->priv->stream,
- MATE_MIXER_CHANNEL_LFE,
- value);
+ mate_mixer_stream_set_channel_volume (bar->priv->stream,
+ bar->priv->lfe_channel,
+ value);
break;
- default:
- g_assert_not_reached ();
}
}
@@ -530,5 +544,8 @@ gvc_balance_bar_new (MateMixerStream *stream, GvcBalanceType btype)
return g_object_new (GVC_TYPE_BALANCE_BAR,
"balance-type", btype,
"stream", stream,
+#if GTK_CHECK_VERSION (3, 0, 0)
+ "orientation", GTK_ORIENTATION_HORIZONTAL,
+#endif
NULL);
}
diff --git a/mate-volume-control/src/gvc-balance-bar.h b/mate-volume-control/src/gvc-balance-bar.h
index 02149d0..32602ae 100644
--- a/mate-volume-control/src/gvc-balance-bar.h
+++ b/mate-volume-control/src/gvc-balance-bar.h
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
*
* 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
@@ -67,7 +68,7 @@ struct _GvcBalanceBarClass
#endif
};
-GType gvc_balance_bar_get_type (void);
+GType gvc_balance_bar_get_type (void) G_GNUC_CONST;
GtkWidget * gvc_balance_bar_new (MateMixerStream *stream,
GvcBalanceType btype);
diff --git a/mate-volume-control/src/gvc-channel-bar.c b/mate-volume-control/src/gvc-channel-bar.c
index b1bf894..9a2c765 100644
--- a/mate-volume-control/src/gvc-channel-bar.c
+++ b/mate-volume-control/src/gvc-channel-bar.c
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 William Jon McCann
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
*
* 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
@@ -22,75 +23,71 @@
#include <glib.h>
#include <glib/gi18n.h>
+#include <glib-object.h>
#include <gtk/gtk.h>
#include <canberra-gtk.h>
+#include <libmatemixer/matemixer.h>
#include "gvc-channel-bar.h"
#define SCALE_SIZE 128
-#define ADJUSTMENT_MAX_NORMAL 65536.0 /* PA_VOLUME_NORM */
-#define ADJUSTMENT_MAX_AMPLIFIED 98304.0 /* 1.5 * ADJUSTMENT_MAX_NORMAL */
-#define ADJUSTMENT_MAX (bar->priv->is_amplified ? ADJUSTMENT_MAX_AMPLIFIED : ADJUSTMENT_MAX_NORMAL)
-#define SCROLLSTEP (ADJUSTMENT_MAX / 100.0 * 5.0)
-
#define GVC_CHANNEL_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_CHANNEL_BAR, GvcChannelBarPrivate))
-struct GvcChannelBarPrivate
-{
- GtkOrientation orientation;
- GtkWidget *scale_box;
- GtkWidget *start_box;
- GtkWidget *end_box;
- GtkWidget *image;
- GtkWidget *label;
- GtkWidget *low_image;
- GtkWidget *scale;
- GtkWidget *high_image;
- GtkWidget *mute_box;
- GtkWidget *mute_button;
- GtkAdjustment *adjustment;
- GtkAdjustment *zero_adjustment;
- gboolean show_mute;
- gboolean is_muted;
- char *name;
- char *icon_name;
- char *low_icon_name;
- char *high_icon_name;
- GtkSizeGroup *size_group;
- gboolean symmetric;
- gboolean click_lock;
- gboolean is_amplified;
- guint32 base_volume;
+struct _GvcChannelBarPrivate
+{
+ GtkOrientation orientation;
+ GtkWidget *scale_box;
+ GtkWidget *start_box;
+ GtkWidget *end_box;
+ GtkWidget *image;
+ GtkWidget *label;
+ GtkWidget *low_image;
+ GtkWidget *scale;
+ GtkWidget *high_image;
+ GtkWidget *mute_box;
+ GtkWidget *mute_button;
+ GtkAdjustment *adjustment;
+ gboolean show_icons;
+ gboolean show_mute;
+ gboolean show_marks;
+ gboolean extended;
+ GtkSizeGroup *size_group;
+ gboolean symmetric;
+ gboolean click_lock;
+ MateMixerStream *stream;
+ MateMixerStreamFlags stream_flags;
};
-enum
-{
+enum {
PROP_0,
+ PROP_STREAM,
PROP_ORIENTATION,
+ PROP_SHOW_ICONS,
PROP_SHOW_MUTE,
- PROP_IS_MUTED,
- PROP_ADJUSTMENT,
+ PROP_SHOW_MARKS,
+ PROP_EXTENDED,
PROP_NAME,
PROP_ICON_NAME,
PROP_LOW_ICON_NAME,
PROP_HIGH_ICON_NAME,
- PROP_IS_AMPLIFIED,
+ N_PROPERTIES
};
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
static void gvc_channel_bar_class_init (GvcChannelBarClass *klass);
-static void gvc_channel_bar_init (GvcChannelBar *channel_bar);
-static void gvc_channel_bar_finalize (GObject *object);
-
-static gboolean on_scale_button_press_event (GtkWidget *widget,
- GdkEventButton *event,
- GvcChannelBar *bar);
-static gboolean on_scale_button_release_event (GtkWidget *widget,
- GdkEventButton *event,
- GvcChannelBar *bar);
-static gboolean on_scale_scroll_event (GtkWidget *widget,
- GdkEventScroll *event,
- GvcChannelBar *bar);
+static void gvc_channel_bar_init (GvcChannelBar *bar);
+
+static gboolean on_scale_button_press_event (GtkWidget *widget,
+ GdkEventButton *event,
+ GvcChannelBar *bar);
+static gboolean on_scale_button_release_event (GtkWidget *widget,
+ GdkEventButton *event,
+ GvcChannelBar *bar);
+static gboolean on_scale_scroll_event (GtkWidget *widget,
+ GdkEventScroll *event,
+ GvcChannelBar *bar);
#if GTK_CHECK_VERSION (3, 0, 0)
G_DEFINE_TYPE (GvcChannelBar, gvc_channel_bar, GTK_TYPE_BOX)
@@ -98,131 +95,159 @@ G_DEFINE_TYPE (GvcChannelBar, gvc_channel_bar, GTK_TYPE_BOX)
G_DEFINE_TYPE (GvcChannelBar, gvc_channel_bar, GTK_TYPE_HBOX)
#endif
-static GtkWidget *
-_scale_box_new (GvcChannelBar *bar)
+static void
+create_scale_box (GvcChannelBar *bar)
{
- GvcChannelBarPrivate *priv = bar->priv;
- GtkWidget *box;
- GtkWidget *sbox;
- GtkWidget *ebox;
-
- if (priv->orientation == GTK_ORIENTATION_VERTICAL) {
- bar->priv->scale_box = box = gtk_vbox_new (FALSE, 6);
-
- priv->scale = gtk_vscale_new (priv->adjustment);
-
- gtk_widget_set_size_request (priv->scale, -1, SCALE_SIZE);
- gtk_range_set_inverted (GTK_RANGE (priv->scale), TRUE);
-
- bar->priv->start_box = sbox = gtk_vbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (box), sbox, FALSE, FALSE, 0);
-
- gtk_box_pack_start (GTK_BOX (sbox), priv->image, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (sbox), priv->label, FALSE, FALSE, 0);
-
- gtk_box_pack_start (GTK_BOX (sbox), priv->high_image, FALSE, FALSE, 0);
- gtk_widget_hide (priv->high_image);
- gtk_box_pack_start (GTK_BOX (box), priv->scale, TRUE, TRUE, 0);
-
- bar->priv->end_box = ebox = gtk_vbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, FALSE, 0);
-
- gtk_box_pack_start (GTK_BOX (ebox), priv->low_image, FALSE, FALSE, 0);
- gtk_widget_hide (priv->low_image);
-
- gtk_box_pack_start (GTK_BOX (ebox), priv->mute_box, FALSE, FALSE, 0);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ bar->priv->scale_box = gtk_box_new (bar->priv->orientation, 6);
+ bar->priv->start_box = gtk_box_new (bar->priv->orientation, 6);
+ bar->priv->end_box = gtk_box_new (bar->priv->orientation, 6);
+ bar->priv->scale = gtk_scale_new (bar->priv->orientation,
+ bar->priv->adjustment);
+#else
+ if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
+ bar->priv->scale_box = gtk_vbox_new (FALSE, 6);
+ bar->priv->start_box = gtk_vbox_new (FALSE, 6);
+ bar->priv->end_box = gtk_vbox_new (FALSE, 6);
+ bar->priv->scale = gtk_vscale_new (bar->priv->adjustment);
} else {
- bar->priv->scale_box = box = gtk_hbox_new (FALSE, 6);
-
- priv->scale = gtk_hscale_new (priv->adjustment);
-
- gtk_widget_set_size_request (priv->scale, SCALE_SIZE, -1);
-
- bar->priv->start_box = sbox = gtk_hbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (box), sbox, FALSE, FALSE, 0);
-
- gtk_box_pack_end (GTK_BOX (sbox), priv->low_image, FALSE, FALSE, 0);
- gtk_widget_show (priv->low_image);
-
- gtk_box_pack_start (GTK_BOX (sbox), priv->image, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (sbox), priv->label, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (box), priv->scale, TRUE, TRUE, 0);
-
- bar->priv->end_box = ebox = gtk_hbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, FALSE, 0);
+ bar->priv->scale_box = gtk_hbox_new (FALSE, 6);
+ bar->priv->start_box = gtk_hbox_new (FALSE, 6);
+ bar->priv->end_box = gtk_hbox_new (FALSE, 6);
+ bar->priv->scale = gtk_hscale_new (bar->priv->adjustment);
+ }
+#endif
+ if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
+ gtk_widget_set_size_request (bar->priv->scale, -1, SCALE_SIZE);
+
+ gtk_range_set_inverted (GTK_RANGE (bar->priv->scale), TRUE);
+
+ gtk_box_pack_start (GTK_BOX (bar->priv->scale_box),
+ bar->priv->start_box,
+ FALSE, FALSE, 0);
+
+ gtk_box_pack_start (GTK_BOX (bar->priv->start_box),
+ bar->priv->image,
+ FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (bar->priv->start_box),
+ bar->priv->label,
+ FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (bar->priv->start_box),
+ bar->priv->high_image,
+ FALSE, FALSE, 0);
+
+ gtk_box_pack_start (GTK_BOX (bar->priv->scale_box),
+ bar->priv->scale,
+ TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (bar->priv->scale_box),
+ bar->priv->end_box,
+ FALSE, FALSE, 0);
+
+ gtk_box_pack_start (GTK_BOX (bar->priv->end_box),
+ bar->priv->low_image,
+ FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (bar->priv->end_box),
+ bar->priv->mute_box,
+ FALSE, FALSE, 0);
+ } else {
+ gtk_widget_set_size_request (bar->priv->scale, SCALE_SIZE, -1);
+
+ gtk_box_pack_start (GTK_BOX (bar->priv->scale_box),
+ bar->priv->image,
+ FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (bar->priv->scale_box),
+ bar->priv->start_box,
+ FALSE, FALSE, 0);
+
+ gtk_box_pack_end (GTK_BOX (bar->priv->start_box),
+ bar->priv->low_image,
+ FALSE, FALSE, 0);
+
+ gtk_box_pack_start (GTK_BOX (bar->priv->start_box),
+ bar->priv->label,
+ TRUE, TRUE, 0);
+
+ gtk_box_pack_start (GTK_BOX (bar->priv->scale_box),
+ bar->priv->scale,
+ TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (bar->priv->scale_box),
+ bar->priv->end_box,
+ FALSE, FALSE, 0);
+
+ gtk_box_pack_start (GTK_BOX (bar->priv->end_box),
+ bar->priv->high_image,
+ FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (bar->priv->end_box),
+ bar->priv->mute_box,
+ FALSE, FALSE, 0);
+ }
- gtk_box_pack_start (GTK_BOX (ebox), priv->high_image, FALSE, FALSE, 0);
- gtk_widget_show (priv->high_image);
- gtk_box_pack_start (GTK_BOX (ebox), priv->mute_box, FALSE, FALSE, 0);
+ if (bar->priv->show_icons) {
+ gtk_widget_show (bar->priv->low_image);
+ gtk_widget_show (bar->priv->high_image);
+ } else {
+ gtk_widget_hide (bar->priv->low_image);
+ gtk_widget_hide (bar->priv->high_image);
}
-#if !GTK_CHECK_VERSION (3, 0, 0)
- gtk_range_set_update_policy (GTK_RANGE (priv->scale), GTK_UPDATE_CONTINUOUS);
-#endif
ca_gtk_widget_disable_sounds (bar->priv->scale, FALSE);
+
gtk_widget_add_events (bar->priv->scale, GDK_SCROLL_MASK);
- g_signal_connect (G_OBJECT (bar->priv->scale), "button-press-event",
- G_CALLBACK (on_scale_button_press_event), bar);
- g_signal_connect (G_OBJECT (bar->priv->scale), "button-release-event",
- G_CALLBACK (on_scale_button_release_event), bar);
- g_signal_connect (G_OBJECT (bar->priv->scale), "scroll-event",
- G_CALLBACK (on_scale_scroll_event), bar);
+ g_signal_connect (G_OBJECT (bar->priv->scale),
+ "button-press-event",
+ G_CALLBACK (on_scale_button_press_event),
+ bar);
+ g_signal_connect (G_OBJECT (bar->priv->scale),
+ "button-release-event",
+ G_CALLBACK (on_scale_button_release_event),
+ bar);
+ g_signal_connect (G_OBJECT (bar->priv->scale),
+ "scroll-event",
+ G_CALLBACK (on_scale_scroll_event),
+ bar);
if (bar->priv->size_group != NULL) {
- gtk_size_group_add_widget (bar->priv->size_group, sbox);
+ gtk_size_group_add_widget (bar->priv->size_group,
+ bar->priv->start_box);
- if (bar->priv->symmetric) {
- gtk_size_group_add_widget (bar->priv->size_group, ebox);
- }
+ if (bar->priv->symmetric)
+ gtk_size_group_add_widget (bar->priv->size_group,
+ bar->priv->end_box);
}
- gtk_scale_set_draw_value (GTK_SCALE (priv->scale), FALSE);
-
- return box;
+ gtk_scale_set_draw_value (GTK_SCALE (bar->priv->scale), FALSE);
}
static void
-update_image (GvcChannelBar *bar)
+on_adjustment_value_changed (GtkAdjustment *adjustment,
+ GvcChannelBar *bar)
{
- gtk_image_set_from_icon_name (GTK_IMAGE (bar->priv->image),
- bar->priv->icon_name,
- GTK_ICON_SIZE_DIALOG);
+ gdouble value;
+ gdouble lower;
- if (bar->priv->icon_name != NULL) {
- gtk_widget_show (bar->priv->image);
- } else {
- gtk_widget_hide (bar->priv->image);
- }
-}
+ if (bar->priv->stream == NULL || bar->priv->click_lock == TRUE)
+ return;
-static void
-update_label (GvcChannelBar *bar)
-{
- if (bar->priv->name != NULL) {
- gtk_label_set_text_with_mnemonic (GTK_LABEL (bar->priv->label),
- bar->priv->name);
- gtk_label_set_mnemonic_widget (GTK_LABEL (bar->priv->label),
- bar->priv->scale);
- gtk_widget_show (bar->priv->label);
- } else {
- gtk_label_set_text (GTK_LABEL (bar->priv->label), NULL);
- gtk_widget_hide (bar->priv->label);
- }
+ value = gtk_adjustment_get_value (bar->priv->adjustment);
+ lower = gtk_adjustment_get_lower (bar->priv->adjustment);
+
+ if (bar->priv->stream_flags & MATE_MIXER_STREAM_HAS_MUTE)
+ mate_mixer_stream_set_mute (bar->priv->stream, (value <= lower));
+
+ if (bar->priv->stream_flags & MATE_MIXER_STREAM_CAN_SET_VOLUME)
+ mate_mixer_stream_set_volume (bar->priv->stream, (guint) value);
}
static void
update_layout (GvcChannelBar *bar)
{
- GtkWidget *box;
GtkWidget *frame;
- if (bar->priv->scale == NULL) {
+ if (bar->priv->scale == NULL)
return;
- }
- box = bar->priv->scale_box;
- frame = gtk_widget_get_parent (box);
+ frame = gtk_widget_get_parent (bar->priv->scale_box);
g_object_ref (bar->priv->image);
g_object_ref (bar->priv->label);
@@ -230,24 +255,36 @@ update_layout (GvcChannelBar *bar)
g_object_ref (bar->priv->low_image);
g_object_ref (bar->priv->high_image);
- gtk_container_remove (GTK_CONTAINER (bar->priv->start_box), bar->priv->image);
- gtk_container_remove (GTK_CONTAINER (bar->priv->start_box), bar->priv->label);
- gtk_container_remove (GTK_CONTAINER (bar->priv->end_box), bar->priv->mute_box);
+ // XXX this is not the opposite of what is done above
+ gtk_container_remove (GTK_CONTAINER (bar->priv->start_box),
+ bar->priv->image);
+ gtk_container_remove (GTK_CONTAINER (bar->priv->start_box),
+ bar->priv->label);
+ gtk_container_remove (GTK_CONTAINER (bar->priv->end_box),
+ bar->priv->mute_box);
if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
- gtk_container_remove (GTK_CONTAINER (bar->priv->start_box), bar->priv->low_image);
- gtk_container_remove (GTK_CONTAINER (bar->priv->end_box), bar->priv->high_image);
+ gtk_container_remove (GTK_CONTAINER (bar->priv->start_box),
+ bar->priv->low_image);
+ gtk_container_remove (GTK_CONTAINER (bar->priv->end_box),
+ bar->priv->high_image);
} else {
- gtk_container_remove (GTK_CONTAINER (bar->priv->end_box), bar->priv->low_image);
- gtk_container_remove (GTK_CONTAINER (bar->priv->start_box), bar->priv->high_image);
+ gtk_container_remove (GTK_CONTAINER (bar->priv->end_box),
+ bar->priv->low_image);
+ gtk_container_remove (GTK_CONTAINER (bar->priv->start_box),
+ bar->priv->high_image);
}
- gtk_container_remove (GTK_CONTAINER (box), bar->priv->start_box);
- gtk_container_remove (GTK_CONTAINER (box), bar->priv->scale);
- gtk_container_remove (GTK_CONTAINER (box), bar->priv->end_box);
- gtk_container_remove (GTK_CONTAINER (frame), box);
+ gtk_container_remove (GTK_CONTAINER (bar->priv->scale_box),
+ bar->priv->start_box);
+ gtk_container_remove (GTK_CONTAINER (bar->priv->scale_box),
+ bar->priv->scale);
+ gtk_container_remove (GTK_CONTAINER (bar->priv->scale_box),
+ bar->priv->end_box);
+ gtk_container_remove (GTK_CONTAINER (frame),
+ bar->priv->scale_box);
- bar->priv->scale_box = _scale_box_new (bar);
+ create_scale_box (bar);
gtk_container_add (GTK_CONTAINER (frame), bar->priv->scale_box);
g_object_unref (bar->priv->image);
@@ -259,122 +296,144 @@ update_layout (GvcChannelBar *bar)
gtk_widget_show_all (frame);
}
-void
-gvc_channel_bar_set_size_group (GvcChannelBar *bar,
- GtkSizeGroup *group,
- gboolean symmetric)
+static void
+update_marks (GvcChannelBar *bar)
{
- g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
+ gdouble base;
+ gdouble normal;
+ gboolean has_mark = FALSE;
- bar->priv->size_group = group;
- bar->priv->symmetric = symmetric;
-
- if (bar->priv->size_group != NULL) {
- gtk_size_group_add_widget (bar->priv->size_group,
- bar->priv->start_box);
+ gtk_scale_clear_marks (GTK_SCALE (bar->priv->scale));
- if (bar->priv->symmetric) {
- gtk_size_group_add_widget (bar->priv->size_group,
- bar->priv->end_box);
- }
- }
- gtk_widget_queue_draw (GTK_WIDGET (bar));
-}
+ if (bar->priv->stream == NULL || bar->priv->show_marks == FALSE)
+ return;
+ if (!(bar->priv->stream_flags & MATE_MIXER_STREAM_HAS_VOLUME))
+ return;
-void
-gvc_channel_bar_set_name (GvcChannelBar *bar,
- const char *name)
-{
- g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
+ /* Base volume represents unamplified volume, normal volume is the 100%
+ * volume, in many cases they are the same as unamplified volume is unknown */
+ base = mate_mixer_stream_get_base_volume (bar->priv->stream);
+ normal = mate_mixer_stream_get_normal_volume (bar->priv->stream);
- g_free (bar->priv->name);
- bar->priv->name = g_strdup (name);
- update_label (bar);
- g_object_notify (G_OBJECT (bar), "name");
-}
+ if (normal <= gtk_adjustment_get_lower (bar->priv->adjustment))
+ return;
-void
-gvc_channel_bar_set_icon_name (GvcChannelBar *bar,
- const char *name)
-{
- g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
+ if (base < normal) {
+ gchar *str = g_strdup_printf ("<small>%s</small>", C_("volume", "Unamplified"));
- g_free (bar->priv->icon_name);
- bar->priv->icon_name = g_strdup (name);
- update_image (bar);
- g_object_notify (G_OBJECT (bar), "icon-name");
-}
+ gtk_scale_add_mark (GTK_SCALE (bar->priv->scale),
+ base,
+ GTK_POS_BOTTOM,
+ str);
+ has_mark = TRUE;
+ g_free (str);
+ }
-void
-gvc_channel_bar_set_low_icon_name (GvcChannelBar *bar,
- const char *name)
-{
- g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
+ /* Only show 100% mark if the scale is extended beyond 100% and
+ * there is no unamplified mark or it is below the normal volume */
+ if (bar->priv->extended && (base == normal || base < normal)) {
+ gchar *str = g_strdup_printf ("<small>%s</small>", C_("volume", "100%"));
- if (name != NULL && strcmp (bar->priv->low_icon_name, name) != 0) {
- g_free (bar->priv->low_icon_name);
- bar->priv->low_icon_name = g_strdup (name);
- gtk_image_set_from_icon_name (GTK_IMAGE (bar->priv->low_image),
- bar->priv->low_icon_name,
- GTK_ICON_SIZE_BUTTON);
- g_object_notify (G_OBJECT (bar), "low-icon-name");
+ gtk_scale_add_mark (GTK_SCALE (bar->priv->scale),
+ normal,
+ GTK_POS_BOTTOM,
+ str);
+ has_mark = TRUE;
+ g_free (str);
}
-}
-void
-gvc_channel_bar_set_high_icon_name (GvcChannelBar *bar,
- const char *name)
-{
- g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
+ if (has_mark) {
+ gtk_alignment_set (GTK_ALIGNMENT (bar->priv->mute_box), 0.5, 0, 0, 0);
+
+ gtk_misc_set_alignment (GTK_MISC (bar->priv->low_image), 0.5, 0);
+ gtk_misc_set_alignment (GTK_MISC (bar->priv->high_image), 0.5, 0);
+ gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0, 0);
+ } else {
+ gtk_alignment_set (GTK_ALIGNMENT (bar->priv->mute_box), 0.5, 0.5, 0, 0);
- if (name != NULL && strcmp (bar->priv->high_icon_name, name) != 0) {
- g_free (bar->priv->high_icon_name);
- bar->priv->high_icon_name = g_strdup (name);
- gtk_image_set_from_icon_name (GTK_IMAGE (bar->priv->high_image),
- bar->priv->high_icon_name,
- GTK_ICON_SIZE_BUTTON);
- g_object_notify (G_OBJECT (bar), "high-icon-name");
+ gtk_misc_set_alignment (GTK_MISC (bar->priv->low_image), 0.5, 0.5);
+ gtk_misc_set_alignment (GTK_MISC (bar->priv->high_image), 0.5, 0.5);
+ gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0, 0.5);
}
}
-void
-gvc_channel_bar_set_orientation (GvcChannelBar *bar,
- GtkOrientation orientation)
+static void
+update_adjustment_value (GvcChannelBar *bar)
{
- g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
+ gdouble value;
+ gboolean set_lower = FALSE;
+
+ /* Move the slider to the minimal value if the stream is muted or
+ * volume is unavailable */
+ if (!(bar->priv->stream_flags & MATE_MIXER_STREAM_HAS_VOLUME))
+ set_lower = TRUE;
+ else if (bar->priv->stream == NULL ||
+ bar->priv->stream_flags & MATE_MIXER_STREAM_HAS_MUTE)
+ set_lower = mate_mixer_stream_get_mute (bar->priv->stream);
+
+ if (set_lower)
+ value = gtk_adjustment_get_lower (bar->priv->adjustment);
+ else
+ value = mate_mixer_stream_get_volume (bar->priv->stream);
+
+ g_signal_handlers_block_by_func (G_OBJECT (bar->priv->adjustment),
+ on_adjustment_value_changed,
+ bar);
- if (orientation != bar->priv->orientation) {
- bar->priv->orientation = orientation;
- update_layout (bar);
- g_object_notify (G_OBJECT (bar), "orientation");
- }
+ gtk_adjustment_set_value (bar->priv->adjustment, value);
+
+ g_signal_handlers_unblock_by_func (G_OBJECT (bar->priv->adjustment),
+ on_adjustment_value_changed,
+ bar);
}
static void
-gvc_channel_bar_set_adjustment (GvcChannelBar *bar,
- GtkAdjustment *adjustment)
+update_adjustment_limits (GvcChannelBar *bar)
{
- g_return_if_fail (GVC_CHANNEL_BAR (bar));
- g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+ gdouble minimum = 0.0;
+ gdouble maximum = 0.0;
- if (bar->priv->adjustment != NULL) {
- g_object_unref (bar->priv->adjustment);
- }
- bar->priv->adjustment = g_object_ref_sink (adjustment);
-
- if (bar->priv->scale != NULL) {
- gtk_range_set_adjustment (GTK_RANGE (bar->priv->scale), adjustment);
+ if (bar->priv->stream_flags & MATE_MIXER_STREAM_HAS_VOLUME) {
+ minimum = mate_mixer_stream_get_min_volume (bar->priv->stream);
+ if (bar->priv->extended)
+ maximum = mate_mixer_stream_get_max_volume (bar->priv->stream);
+ else
+ maximum = mate_mixer_stream_get_normal_volume (bar->priv->stream);
}
- g_object_notify (G_OBJECT (bar), "adjustment");
+ gtk_adjustment_configure (bar->priv->adjustment,
+ gtk_adjustment_get_value (bar->priv->adjustment),
+ minimum,
+ maximum,
+ (maximum - minimum) / 100.0,
+ (maximum - minimum) / 15.0,
+ 0.0);
}
-GtkAdjustment *
-gvc_channel_bar_get_adjustment (GvcChannelBar *bar)
+static void
+update_mute_button (GvcChannelBar *bar)
{
- g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), NULL);
+ if (bar->priv->show_mute == TRUE) {
+ gboolean enable = FALSE;
+
+ if (bar->priv->stream != NULL &&
+ bar->priv->stream_flags & MATE_MIXER_STREAM_HAS_MUTE)
+ enable = TRUE;
- return bar->priv->adjustment;
+ if (enable == TRUE) {
+ gboolean mute = mate_mixer_stream_get_mute (bar->priv->stream);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bar->priv->mute_button),
+ mute);
+ } else {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bar->priv->mute_button),
+ FALSE);
+ }
+
+ gtk_widget_set_sensitive (bar->priv->mute_button, enable);
+ gtk_widget_show (bar->priv->mute_button);
+ } else
+ gtk_widget_hide (bar->priv->mute_button);
}
static gboolean
@@ -382,16 +441,29 @@ on_scale_button_press_event (GtkWidget *widget,
GdkEventButton *event,
GvcChannelBar *bar)
{
- /* HACK: we want the behaviour you get with the middle button, so we
- * mangle the event. clicking with other buttons moves the slider in
- * step increments, clicking with the middle button moves the slider to
- * the location of the click.
- */
+
+#if !GTK_CHECK_VERSION (3, 6, 0)
+ /* Up to GTK 3.4 the slider selection only moves in increments when
+ * clicking in the slider with the left button and it moves directly
+ * to the clicked position with the middle mouse button.
+ * Change this behaviour to also jump to the clicked position with the
+ * left mouse button. */
if (event->button == 1)
event->button = 2;
+#endif
- bar->priv->click_lock = TRUE;
+ /* Muting the stream when volume is non-zero moves the slider to zero,
+ * but the volume remains the same. In this case delay unmuting and
+ * changing volume until user releases the mouse button. */
+ if (bar->priv->stream_flags & MATE_MIXER_STREAM_HAS_MUTE &&
+ bar->priv->stream_flags & MATE_MIXER_STREAM_HAS_VOLUME) {
+ if (mate_mixer_stream_get_mute (bar->priv->stream) == TRUE) {
+ guint minimum = (guint) gtk_adjustment_get_lower (bar->priv->adjustment);
+ if (mate_mixer_stream_get_volume (bar->priv->stream) > minimum)
+ bar->priv->click_lock = TRUE;
+ }
+ }
return FALSE;
}
@@ -400,246 +472,422 @@ on_scale_button_release_event (GtkWidget *widget,
GdkEventButton *event,
GvcChannelBar *bar)
{
- GtkAdjustment *adj;
- gdouble value;
-
- /* HACK: see on_scale_button_press_event() */
+#if !GTK_CHECK_VERSION (3, 6, 0)
if (event->button == 1)
event->button = 2;
+#endif
- bar->priv->click_lock = FALSE;
-
- adj = gtk_range_get_adjustment (GTK_RANGE (widget));
-
- value = gtk_adjustment_get_value (adj);
-
- /* this means the adjustment moved away from zero and
- * therefore we should unmute and set the volume. */
- gvc_channel_bar_set_is_muted (bar, (value == 0.0));
+ if (bar->priv->click_lock == TRUE) {
+ /* The volume change is not reflected while the lock is
+ * held, propagate the change now that user has released
+ * the mouse button */
+ bar->priv->click_lock = FALSE;
+ on_adjustment_value_changed (bar->priv->adjustment, bar);
+ }
- /* Play a sound! */
+ /* Play a sound */
ca_gtk_play_for_widget (GTK_WIDGET (bar), 0,
CA_PROP_EVENT_ID, "audio-volume-change",
- CA_PROP_EVENT_DESCRIPTION, "foobar event happened",
+ CA_PROP_EVENT_DESCRIPTION, "Volume change",
CA_PROP_APPLICATION_ID, "org.mate.VolumeControl",
+ CA_PROP_APPLICATION_NAME, _("Volume Control"),
+ CA_PROP_APPLICATION_VERSION, VERSION,
+ CA_PROP_APPLICATION_ICON_NAME, "multimedia-volume-control",
NULL);
-
return FALSE;
}
-gboolean
-gvc_channel_bar_scroll (GvcChannelBar *bar, GdkScrollDirection direction)
+static gboolean
+on_scale_scroll_event (GtkWidget *widget,
+ GdkEventScroll *event,
+ GvcChannelBar *bar)
{
- GtkAdjustment *adj;
- gdouble value;
+ GdkScrollDirection direction = event->direction;
- g_return_val_if_fail (bar != NULL, FALSE);
- g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
+#if GTK_CHECK_VERSION (3, 4, 0)
+ if (direction == GDK_SCROLL_SMOOTH) {
+ gdouble dx = 0.0;
+ gdouble dy = 0.0;
- if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
- if (direction != GDK_SCROLL_UP && direction != GDK_SCROLL_DOWN)
- return FALSE;
- } else {
- /* Switch direction for RTL */
- if (gtk_widget_get_direction (GTK_WIDGET (bar)) == GTK_TEXT_DIR_RTL) {
- if (direction == GDK_SCROLL_RIGHT)
- direction = GDK_SCROLL_LEFT;
- else if (direction == GDK_SCROLL_LEFT)
- direction = GDK_SCROLL_RIGHT;
- }
- /* Switch side scroll to vertical */
- if (direction == GDK_SCROLL_RIGHT)
- direction = GDK_SCROLL_UP;
- else if (direction == GDK_SCROLL_LEFT)
+ gdk_event_get_scroll_deltas ((const GdkEvent *) event, &dx, &dy);
+ if (dy > 0.0)
direction = GDK_SCROLL_DOWN;
+ else if (dy < 0.0)
+ direction = GDK_SCROLL_UP;
+ else
+ return FALSE;
}
+#endif
+ return gvc_channel_bar_scroll (bar, direction);
+}
- adj = gtk_range_get_adjustment (GTK_RANGE (bar->priv->scale));
- if (adj == bar->priv->zero_adjustment) {
- if (direction == GDK_SCROLL_UP)
- gvc_channel_bar_set_is_muted (bar, FALSE);
- return TRUE;
- }
+static void
+on_stream_volume_notify (MateMixerStream *stream,
+ GParamSpec *pspec,
+ GvcChannelBar *bar)
+{
+ update_adjustment_value (bar);
+}
- value = gtk_adjustment_get_value (adj);
+static void
+on_stream_mute_notify (MateMixerStream *stream,
+ GParamSpec *pspec,
+ GvcChannelBar *bar)
+{
+ if (bar->priv->show_mute == TRUE) {
+ gboolean mute = mate_mixer_stream_get_mute (stream);
- if (direction == GDK_SCROLL_UP) {
- if (value + SCROLLSTEP > ADJUSTMENT_MAX)
- value = ADJUSTMENT_MAX;
- else
- value = value + SCROLLSTEP;
- } else if (direction == GDK_SCROLL_DOWN) {
- if (value - SCROLLSTEP < 0)
- value = 0.0;
- else
- value = value - SCROLLSTEP;
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bar->priv->mute_button), mute);
}
+ update_adjustment_value (bar);
+}
- gvc_channel_bar_set_is_muted (bar, (value == 0.0));
- adj = gtk_range_get_adjustment (GTK_RANGE (bar->priv->scale));
- gtk_adjustment_set_value (adj, value);
+MateMixerStream *
+gvc_channel_bar_get_stream (GvcChannelBar *bar)
+{
+ g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), NULL);
- return TRUE;
+ return bar->priv->stream;
}
-static gboolean
-on_scale_scroll_event (GtkWidget *widget,
- GdkEventScroll *event,
- GvcChannelBar *bar)
+void
+gvc_channel_bar_set_stream (GvcChannelBar *bar, MateMixerStream *stream)
{
- return gvc_channel_bar_scroll (bar, event->direction);
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
+
+ if (bar->priv->stream == stream)
+ return;
+
+ if (stream != NULL)
+ g_object_ref (stream);
+
+ if (bar->priv->stream != NULL) {
+ g_signal_handlers_disconnect_by_func (G_OBJECT (bar->priv->stream),
+ G_CALLBACK (on_stream_volume_notify),
+ bar);
+ g_signal_handlers_disconnect_by_func (G_OBJECT (bar->priv->stream),
+ G_CALLBACK (on_stream_mute_notify),
+ bar);
+ g_object_unref (bar->priv->stream);
+ }
+
+ bar->priv->stream = stream;
+
+ if (stream != NULL)
+ bar->priv->stream_flags = mate_mixer_stream_get_flags (stream);
+ else
+ bar->priv->stream_flags = MATE_MIXER_STREAM_NO_FLAGS;
+
+ if (bar->priv->stream_flags & MATE_MIXER_STREAM_HAS_VOLUME)
+ g_signal_connect (G_OBJECT (stream),
+ "notify::volume",
+ G_CALLBACK (on_stream_volume_notify),
+ bar);
+ if (bar->priv->stream_flags & MATE_MIXER_STREAM_HAS_MUTE)
+ g_signal_connect (G_OBJECT (stream),
+ "notify::mute",
+ G_CALLBACK (on_stream_mute_notify),
+ bar);
+
+ update_marks (bar);
+ update_mute_button (bar);
+ update_adjustment_limits (bar);
+ update_adjustment_value (bar);
}
-static void
-on_zero_adjustment_value_changed (GtkAdjustment *adjustment,
- GvcChannelBar *bar)
+GtkOrientation
+gvc_channel_bar_get_orientation (GvcChannelBar *bar)
{
- gdouble value;
+ g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), 0);
- if (bar->priv->click_lock != FALSE) {
+ return bar->priv->orientation;
+}
+
+void
+gvc_channel_bar_set_orientation (GvcChannelBar *bar,
+ GtkOrientation orientation)
+{
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
+
+ if (orientation == bar->priv->orientation)
return;
- }
- value = gtk_adjustment_get_value (bar->priv->zero_adjustment);
- gtk_adjustment_set_value (bar->priv->adjustment, value);
+ bar->priv->orientation = orientation;
+ update_layout (bar);
+ g_object_notify_by_pspec (G_OBJECT (bar), properties[PROP_ORIENTATION]);
+}
- if (bar->priv->show_mute == FALSE) {
- /* this means the adjustment moved away from zero and
- * therefore we should unmute and set the volume. */
- gvc_channel_bar_set_is_muted (bar, value > 0.0);
- }
+gboolean
+gvc_channel_bar_get_show_icons (GvcChannelBar *bar)
+{
+ g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
+
+ return bar->priv->show_icons;
}
-static void
-update_mute_button (GvcChannelBar *bar)
+void
+gvc_channel_bar_set_show_icons (GvcChannelBar *bar, gboolean show_icons)
{
- if (bar->priv->show_mute) {
- gtk_widget_show (bar->priv->mute_button);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bar->priv->mute_button),
- bar->priv->is_muted);
- } else {
- gtk_widget_hide (bar->priv->mute_button);
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
- if (bar->priv->is_muted) {
- /* If we aren't showing the mute button then
- * move slider to the zero. But we don't want to
- * change the adjustment. */
- g_signal_handlers_block_by_func (bar->priv->zero_adjustment,
- on_zero_adjustment_value_changed,
- bar);
- gtk_adjustment_set_value (bar->priv->zero_adjustment, 0);
- g_signal_handlers_unblock_by_func (bar->priv->zero_adjustment,
- on_zero_adjustment_value_changed,
- bar);
- gtk_range_set_adjustment (GTK_RANGE (bar->priv->scale),
- bar->priv->zero_adjustment);
- } else {
- /* no longer muted so restore the original adjustment
- * and tell the front-end that the value changed */
- gtk_range_set_adjustment (GTK_RANGE (bar->priv->scale),
- bar->priv->adjustment);
- gtk_adjustment_value_changed (bar->priv->adjustment);
- }
+ if (show_icons == bar->priv->show_icons)
+ return;
+
+ bar->priv->show_icons = show_icons;
+
+ if (bar->priv->show_icons == TRUE) {
+ gtk_widget_show (bar->priv->low_image);
+ gtk_widget_show (bar->priv->high_image);
+ } else {
+ gtk_widget_hide (bar->priv->low_image);
+ gtk_widget_hide (bar->priv->high_image);
}
+
+ g_object_notify_by_pspec (G_OBJECT (bar), properties[PROP_SHOW_ICONS]);
+}
+
+gboolean
+gvc_channel_bar_get_show_mute (GvcChannelBar *bar)
+{
+ g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
+
+ return bar->priv->show_mute;
}
void
-gvc_channel_bar_set_is_muted (GvcChannelBar *bar,
- gboolean is_muted)
+gvc_channel_bar_set_show_mute (GvcChannelBar *bar, gboolean show_mute)
{
g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
- if (is_muted != bar->priv->is_muted) {
- /* Update our internal state before telling the
- * front-end about our changes */
- bar->priv->is_muted = is_muted;
- update_mute_button (bar);
- g_object_notify (G_OBJECT (bar), "is-muted");
- }
+ if (show_mute == bar->priv->show_mute)
+ return;
+
+ bar->priv->show_mute = show_mute;
+ update_mute_button (bar);
+
+ g_object_notify_by_pspec (G_OBJECT (bar), properties[PROP_SHOW_MUTE]);
}
gboolean
-gvc_channel_bar_get_is_muted (GvcChannelBar *bar)
+gvc_channel_bar_get_show_marks (GvcChannelBar *bar)
{
g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
- return bar->priv->is_muted;
+
+ return bar->priv->show_marks;
}
void
-gvc_channel_bar_set_show_mute (GvcChannelBar *bar,
- gboolean show_mute)
+gvc_channel_bar_set_show_marks (GvcChannelBar *bar, gboolean show_marks)
{
g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
- if (show_mute != bar->priv->show_mute) {
- bar->priv->show_mute = show_mute;
- g_object_notify (G_OBJECT (bar), "show-mute");
- update_mute_button (bar);
- }
+ if (show_marks == bar->priv->show_marks)
+ return;
+
+ bar->priv->show_marks = show_marks;
+ update_marks (bar);
+
+ g_object_notify_by_pspec (G_OBJECT (bar), properties[PROP_SHOW_MARKS]);
}
gboolean
-gvc_channel_bar_get_show_mute (GvcChannelBar *bar)
+gvc_channel_bar_get_extended (GvcChannelBar *bar)
{
g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
- return bar->priv->show_mute;
+
+ return bar->priv->extended;
}
void
-gvc_channel_bar_set_is_amplified (GvcChannelBar *bar, gboolean amplified)
+gvc_channel_bar_set_extended (GvcChannelBar *bar, gboolean extended)
{
g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
- bar->priv->is_amplified = amplified;
- gtk_adjustment_set_upper (bar->priv->adjustment, ADJUSTMENT_MAX);
- gtk_adjustment_set_upper (bar->priv->zero_adjustment, ADJUSTMENT_MAX);
- gtk_scale_clear_marks (GTK_SCALE (bar->priv->scale));
+ if (extended == bar->priv->extended)
+ return;
- if (amplified) {
- char *str;
+ bar->priv->extended = extended;
- if (bar->priv->base_volume == ADJUSTMENT_MAX_NORMAL) {
- str = g_strdup_printf ("<small>%s</small>", C_("volume", "100%"));
- gtk_scale_add_mark (GTK_SCALE (bar->priv->scale), ADJUSTMENT_MAX_NORMAL,
- GTK_POS_BOTTOM, str);
- } else {
- str = g_strdup_printf ("<small>%s</small>", C_("volume", "Unamplified"));
- gtk_scale_add_mark (GTK_SCALE (bar->priv->scale), bar->priv->base_volume,
- GTK_POS_BOTTOM, str);
- /* Only show 100% if it's higher than the base volume */
- if (bar->priv->base_volume < ADJUSTMENT_MAX_NORMAL) {
- str = g_strdup_printf ("<small>%s</small>", C_("volume", "100%"));
- gtk_scale_add_mark (GTK_SCALE (bar->priv->scale), ADJUSTMENT_MAX_NORMAL,
- GTK_POS_BOTTOM, str);
- }
- }
+ /* Update displayed marks as non-extended scales do not show the 100%
+ * limit at the end of the scale */
+ update_marks (bar);
+ update_adjustment_limits (bar);
- g_free (str);
- gtk_alignment_set (GTK_ALIGNMENT (bar->priv->mute_box), 0.5, 0, 0, 0);
- gtk_misc_set_alignment (GTK_MISC (bar->priv->low_image), 0.5, 0);
- gtk_misc_set_alignment (GTK_MISC (bar->priv->high_image), 0.5, 0);
- gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0, 0);
+ g_object_notify_by_pspec (G_OBJECT (bar), properties[PROP_EXTENDED]);
+}
+
+const gchar *
+gvc_channel_bar_get_name (GvcChannelBar *bar)
+{
+ g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), NULL);
+
+ return gtk_label_get_text (GTK_LABEL (bar->priv->label));
+}
+
+void
+gvc_channel_bar_set_name (GvcChannelBar *bar, const gchar *name)
+{
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
+
+ if (name != NULL) {
+ gtk_label_set_text_with_mnemonic (GTK_LABEL (bar->priv->label), name);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (bar->priv->label),
+ bar->priv->scale);
+
+ gtk_widget_show (bar->priv->label);
} else {
- gtk_alignment_set (GTK_ALIGNMENT (bar->priv->mute_box), 0.5, 0.5, 0, 0);
- gtk_misc_set_alignment (GTK_MISC (bar->priv->low_image), 0.5, 0.5);
- gtk_misc_set_alignment (GTK_MISC (bar->priv->high_image), 0.5, 0.5);
- gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0, 0.5);
+ gtk_label_set_text (GTK_LABEL (bar->priv->label), NULL);
+ gtk_widget_hide (bar->priv->label);
}
+
+ g_object_notify_by_pspec (G_OBJECT (bar), properties[PROP_NAME]);
+}
+
+const gchar *
+gvc_channel_bar_get_icon_name (GvcChannelBar *bar)
+{
+ const gchar *name = NULL;
+
+ g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), NULL);
+
+ gtk_image_get_icon_name (GTK_IMAGE (bar->priv->image), &name, NULL);
+ return name;
}
void
-gvc_channel_bar_set_base_volume (GvcChannelBar *bar, guint base_volume)
+gvc_channel_bar_set_icon_name (GvcChannelBar *bar, const gchar *name)
{
g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
- if (base_volume == 0) {
- bar->priv->base_volume = ADJUSTMENT_MAX_NORMAL;
- return;
+ gtk_image_set_from_icon_name (GTK_IMAGE (bar->priv->image),
+ name,
+ GTK_ICON_SIZE_DIALOG);
+ if (name != NULL)
+ gtk_widget_show (bar->priv->image);
+ else
+ gtk_widget_hide (bar->priv->image);
+
+ g_object_notify_by_pspec (G_OBJECT (bar), properties[PROP_ICON_NAME]);
+}
+
+const gchar *
+gvc_channel_bar_get_low_icon_name (GvcChannelBar *bar)
+{
+ const gchar *name = NULL;
+
+ g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), NULL);
+
+ gtk_image_get_icon_name (GTK_IMAGE (bar->priv->low_image), &name, NULL);
+ return name;
+}
+
+void
+gvc_channel_bar_set_low_icon_name (GvcChannelBar *bar, const gchar *name)
+{
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
+
+ gtk_image_set_from_icon_name (GTK_IMAGE (bar->priv->low_image),
+ name,
+ GTK_ICON_SIZE_BUTTON);
+
+ g_object_notify_by_pspec (G_OBJECT (bar), properties[PROP_LOW_ICON_NAME]);
+}
+
+const gchar *
+gvc_channel_bar_get_high_icon_name (GvcChannelBar *bar)
+{
+ const gchar *name = NULL;
+
+ g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), NULL);
+
+ gtk_image_get_icon_name (GTK_IMAGE (bar->priv->high_image), &name, NULL);
+ return name;
+}
+
+void
+gvc_channel_bar_set_high_icon_name (GvcChannelBar *bar, const gchar *name)
+{
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
+
+ gtk_image_set_from_icon_name (GTK_IMAGE (bar->priv->high_image),
+ name,
+ GTK_ICON_SIZE_BUTTON);
+
+ g_object_notify_by_pspec (G_OBJECT (bar), properties[PROP_HIGH_ICON_NAME]);
+}
+
+gboolean
+gvc_channel_bar_scroll (GvcChannelBar *bar, GdkScrollDirection direction)
+{
+ gdouble value;
+ gdouble minimum;
+ gdouble maximum;
+ gdouble scrollstep;
+
+ g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
+
+ if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
+ if (direction != GDK_SCROLL_UP && direction != GDK_SCROLL_DOWN)
+ return FALSE;
+ } else {
+ /* Switch direction for RTL */
+ if (gtk_widget_get_direction (GTK_WIDGET (bar)) == GTK_TEXT_DIR_RTL) {
+ if (direction == GDK_SCROLL_RIGHT)
+ direction = GDK_SCROLL_LEFT;
+ else if (direction == GDK_SCROLL_LEFT)
+ direction = GDK_SCROLL_RIGHT;
+ }
+
+ /* Switch side scroll to vertical */
+ if (direction == GDK_SCROLL_RIGHT)
+ direction = GDK_SCROLL_UP;
+ else if (direction == GDK_SCROLL_LEFT)
+ direction = GDK_SCROLL_DOWN;
+ }
+
+ value = gtk_adjustment_get_value (bar->priv->adjustment);
+ minimum = gtk_adjustment_get_lower (bar->priv->adjustment);
+ maximum = gtk_adjustment_get_upper (bar->priv->adjustment);
+
+ scrollstep = maximum / 100.0 * 5.0;
+
+ if (direction == GDK_SCROLL_UP) {
+ if (value + scrollstep > maximum)
+ value = maximum;
+ else
+ value = value + scrollstep;
+ } else if (direction == GDK_SCROLL_DOWN) {
+ if (value - scrollstep < minimum)
+ value = minimum;
+ else
+ value = value - scrollstep;
}
- /* Note that you need to call _is_amplified() afterwards to update the marks */
- bar->priv->base_volume = base_volume;
+ gtk_adjustment_set_value (bar->priv->adjustment, value);
+ return TRUE;
+}
+
+void
+gvc_channel_bar_set_size_group (GvcChannelBar *bar,
+ GtkSizeGroup *group,
+ gboolean symmetric)
+{
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
+ g_return_if_fail (GTK_IS_SIZE_GROUP (group));
+
+ bar->priv->size_group = group;
+ bar->priv->symmetric = symmetric;
+
+ if (bar->priv->size_group != NULL) {
+ gtk_size_group_add_widget (bar->priv->size_group,
+ bar->priv->start_box);
+
+ if (bar->priv->symmetric)
+ gtk_size_group_add_widget (bar->priv->size_group,
+ bar->priv->end_box);
+ }
+ gtk_widget_queue_draw (GTK_WIDGET (bar));
}
static void
@@ -651,15 +899,24 @@ gvc_channel_bar_set_property (GObject *object,
GvcChannelBar *self = GVC_CHANNEL_BAR (object);
switch (prop_id) {
+ case PROP_STREAM:
+ gvc_channel_bar_set_stream (self, g_value_get_object (value));
+ break;
case PROP_ORIENTATION:
gvc_channel_bar_set_orientation (self, g_value_get_enum (value));
break;
- case PROP_IS_MUTED:
- gvc_channel_bar_set_is_muted (self, g_value_get_boolean (value));
- break;
case PROP_SHOW_MUTE:
gvc_channel_bar_set_show_mute (self, g_value_get_boolean (value));
break;
+ case PROP_SHOW_ICONS:
+ gvc_channel_bar_set_show_icons (self, g_value_get_boolean (value));
+ break;
+ case PROP_SHOW_MARKS:
+ gvc_channel_bar_set_show_marks (self, g_value_get_boolean (value));
+ break;
+ case PROP_EXTENDED:
+ gvc_channel_bar_set_extended (self, g_value_get_boolean (value));
+ break;
case PROP_NAME:
gvc_channel_bar_set_name (self, g_value_get_string (value));
break;
@@ -672,12 +929,6 @@ gvc_channel_bar_set_property (GObject *object,
case PROP_HIGH_ICON_NAME:
gvc_channel_bar_set_high_icon_name (self, g_value_get_string (value));
break;
- case PROP_ADJUSTMENT:
- gvc_channel_bar_set_adjustment (self, g_value_get_object (value));
- break;
- case PROP_IS_AMPLIFIED:
- gvc_channel_bar_set_is_amplified (self, g_value_get_boolean (value));
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -691,35 +942,28 @@ gvc_channel_bar_get_property (GObject *object,
GParamSpec *pspec)
{
GvcChannelBar *self = GVC_CHANNEL_BAR (object);
- GvcChannelBarPrivate *priv = self->priv;
switch (prop_id) {
- case PROP_ORIENTATION:
- g_value_set_enum (value, priv->orientation);
+ case PROP_STREAM:
+ g_value_set_object (value, self->priv->stream);
break;
- case PROP_IS_MUTED:
- g_value_set_boolean (value, priv->is_muted);
+ case PROP_ORIENTATION:
+ g_value_set_enum (value, self->priv->orientation);
break;
case PROP_SHOW_MUTE:
- g_value_set_boolean (value, priv->show_mute);
- break;
- case PROP_NAME:
- g_value_set_string (value, priv->name);
+ g_value_set_boolean (value, self->priv->show_mute);
break;
- case PROP_ICON_NAME:
- g_value_set_string (value, priv->icon_name);
- break;
- case PROP_LOW_ICON_NAME:
- g_value_set_string (value, priv->low_icon_name);
+ case PROP_SHOW_ICONS:
+ g_value_set_boolean (value, self->priv->show_icons);
break;
- case PROP_HIGH_ICON_NAME:
- g_value_set_string (value, priv->high_icon_name);
+ case PROP_SHOW_MARKS:
+ g_value_set_boolean (value, self->priv->show_marks);
break;
- case PROP_ADJUSTMENT:
- g_value_set_object (value, gvc_channel_bar_get_adjustment (self));
+ case PROP_EXTENDED:
+ g_value_set_boolean (value, self->priv->extended);
break;
- case PROP_IS_AMPLIFIED:
- g_value_set_boolean (value, priv->is_amplified);
+ case PROP_NAME:
+ g_value_set_string (value, gtk_label_get_text (GTK_LABEL (self->priv->label)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -727,109 +971,119 @@ gvc_channel_bar_get_property (GObject *object,
}
}
-static GObject *
-gvc_channel_bar_constructor (GType type,
- guint n_construct_properties,
- GObjectConstructParam *construct_params)
-{
- GObject *object;
- GvcChannelBar *self;
-
- object = G_OBJECT_CLASS (gvc_channel_bar_parent_class)->constructor (type, n_construct_properties, construct_params);
-
- self = GVC_CHANNEL_BAR (object);
-
- update_mute_button (self);
-
- return object;
-}
-
static void
gvc_channel_bar_class_init (GvcChannelBarClass *klass)
{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
- object_class->constructor = gvc_channel_bar_constructor;
- object_class->finalize = gvc_channel_bar_finalize;
object_class->set_property = gvc_channel_bar_set_property;
object_class->get_property = gvc_channel_bar_get_property;
- g_object_class_install_property (object_class,
- PROP_ORIENTATION,
- g_param_spec_enum ("orientation",
- "Orientation",
- "The orientation of the scale",
- GTK_TYPE_ORIENTATION,
- GTK_ORIENTATION_VERTICAL,
- G_PARAM_READWRITE));
- g_object_class_install_property (object_class,
- PROP_IS_MUTED,
- g_param_spec_boolean ("is-muted",
- "is muted",
- "Whether stream is muted",
- FALSE,
- G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
- g_object_class_install_property (object_class,
- PROP_SHOW_MUTE,
- g_param_spec_boolean ("show-mute",
- "show mute",
- "Whether stream is muted",
- FALSE,
- G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
-
- g_object_class_install_property (object_class,
- PROP_ADJUSTMENT,
- g_param_spec_object ("adjustment",
- "Adjustment",
- "The GtkAdjustment that contains the current value of this scale button object",
- GTK_TYPE_ADJUSTMENT,
- G_PARAM_READWRITE));
- g_object_class_install_property (object_class,
- PROP_NAME,
- g_param_spec_string ("name",
- "Name",
- "Name to display for this stream",
- NULL,
- G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
- g_object_class_install_property (object_class,
- PROP_ICON_NAME,
- g_param_spec_string ("icon-name",
- "Icon Name",
- "Name of icon to display for this stream",
- NULL,
- G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
- g_object_class_install_property (object_class,
- PROP_LOW_ICON_NAME,
- g_param_spec_string ("low-icon-name",
- "Icon Name",
- "Name of icon to display for this stream",
- "audio-volume-low",
- G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
- g_object_class_install_property (object_class,
- PROP_HIGH_ICON_NAME,
- g_param_spec_string ("high-icon-name",
- "Icon Name",
- "Name of icon to display for this stream",
- "audio-volume-high",
- G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
- g_object_class_install_property (object_class,
- PROP_IS_AMPLIFIED,
- g_param_spec_boolean ("is-amplified",
- "is amplified",
- "Whether the stream is digitally amplified",
- FALSE,
- G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ properties[PROP_STREAM] =
+ g_param_spec_object ("stream",
+ "Stream",
+ "MateMixer stream",
+ MATE_MIXER_TYPE_STREAM,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_ORIENTATION] =
+ g_param_spec_enum ("orientation",
+ "Orientation",
+ "The orientation of the scale",
+ GTK_TYPE_ORIENTATION,
+ GTK_ORIENTATION_VERTICAL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_SHOW_MUTE] =
+ g_param_spec_boolean ("show-mute",
+ "show mute",
+ "Whether stream is muted",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_SHOW_ICONS] =
+ g_param_spec_boolean ("show-icons",
+ "show mute",
+ "Whether to show low and high icons",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_SHOW_MARKS] =
+ g_param_spec_boolean ("show-marks",
+ "Show marks",
+ "Whether to show scale marks",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_EXTENDED] =
+ g_param_spec_boolean ("extended",
+ "Extended",
+ "Allow the scale to be extended above normal volume",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_NAME] =
+ g_param_spec_string ("name",
+ "Name",
+ "Name to display for this stream",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_ICON_NAME] =
+ g_param_spec_string ("icon-name",
+ "Icon name",
+ "Name of icon to display for this stream",
+ NULL,
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_LOW_ICON_NAME] =
+ g_param_spec_string ("low-icon-name",
+ "Low icon name",
+ "Name of low volume icon to display for this stream",
+ "audio-volume-low",
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_HIGH_ICON_NAME] =
+ g_param_spec_string ("high-icon-name",
+ "High icon name",
+ "Name of high volume icon to display for this stream",
+ "audio-volume-high",
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
g_type_class_add_private (klass, sizeof (GvcChannelBarPrivate));
}
static void
-on_mute_button_toggled (GtkToggleButton *button,
- GvcChannelBar *bar)
+on_mute_button_toggled (GtkToggleButton *button, GvcChannelBar *bar)
{
- gboolean is_muted;
- is_muted = gtk_toggle_button_get_active (button);
- gvc_channel_bar_set_is_muted (bar, is_muted);
+ gboolean mute;
+
+ if (G_UNLIKELY (bar->priv->stream == NULL))
+ g_warn_if_reached ();
+
+ mute = gtk_toggle_button_get_active (button);
+
+ mate_mixer_stream_set_mute (bar->priv->stream, mute);
}
static void
@@ -839,89 +1093,64 @@ gvc_channel_bar_init (GvcChannelBar *bar)
bar->priv = GVC_CHANNEL_BAR_GET_PRIVATE (bar);
- bar->priv->base_volume = ADJUSTMENT_MAX_NORMAL;
- bar->priv->low_icon_name = g_strdup ("audio-volume-low");
- bar->priv->high_icon_name = g_strdup ("audio-volume-high");
-
- bar->priv->orientation = GTK_ORIENTATION_VERTICAL;
- bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
- 0.0,
- ADJUSTMENT_MAX_NORMAL,
- ADJUSTMENT_MAX_NORMAL/100.0,
- ADJUSTMENT_MAX_NORMAL/10.0,
- 0.0));
- g_object_ref_sink (bar->priv->adjustment);
-
- bar->priv->zero_adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
- 0.0,
- ADJUSTMENT_MAX_NORMAL,
- ADJUSTMENT_MAX_NORMAL/100.0,
- ADJUSTMENT_MAX_NORMAL/10.0,
- 0.0));
- g_object_ref_sink (bar->priv->zero_adjustment);
-
- g_signal_connect (bar->priv->zero_adjustment,
- "value-changed",
- G_CALLBACK (on_zero_adjustment_value_changed),
- bar);
-
+ /* Mute button */
bar->priv->mute_button = gtk_check_button_new_with_label (_("Mute"));
gtk_widget_set_no_show_all (bar->priv->mute_button, TRUE);
+
g_signal_connect (bar->priv->mute_button,
"toggled",
G_CALLBACK (on_mute_button_toggled),
bar);
+
bar->priv->mute_box = gtk_alignment_new (0.5, 0.5, 0, 0);
gtk_container_add (GTK_CONTAINER (bar->priv->mute_box), bar->priv->mute_button);
- bar->priv->low_image = gtk_image_new_from_icon_name ("audio-volume-low",
- GTK_ICON_SIZE_BUTTON);
- gtk_widget_set_no_show_all (bar->priv->low_image, TRUE);
- bar->priv->high_image = gtk_image_new_from_icon_name ("audio-volume-high",
- GTK_ICON_SIZE_BUTTON);
- gtk_widget_set_no_show_all (bar->priv->high_image, TRUE);
-
bar->priv->image = gtk_image_new ();
gtk_widget_set_no_show_all (bar->priv->image, TRUE);
+ /* Low/high icons */
+ bar->priv->low_image = gtk_image_new ();
+ gtk_widget_set_no_show_all (bar->priv->low_image, TRUE);
+
+ bar->priv->high_image = gtk_image_new ();
+ gtk_widget_set_no_show_all (bar->priv->high_image, TRUE);
+
bar->priv->label = gtk_label_new (NULL);
gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0.0, 0.5);
gtk_widget_set_no_show_all (bar->priv->label, TRUE);
- /* frame */
+ /* Frame */
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
- gtk_container_add (GTK_CONTAINER (bar), frame);
- gtk_widget_show_all (frame);
+ gtk_box_pack_start (GTK_BOX (bar), frame, TRUE, TRUE, 0);
- /* box with scale */
- bar->priv->scale_box = _scale_box_new (bar);
+ gtk_widget_show_all (frame);
- gtk_container_add (GTK_CONTAINER (frame), bar->priv->scale_box);
-}
+ /* Create a default adjustment */
+ bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, 0, 0, 0, 0));
-static void
-gvc_channel_bar_finalize (GObject *object)
-{
- GvcChannelBar *channel_bar;
-
- g_return_if_fail (object != NULL);
- g_return_if_fail (GVC_IS_CHANNEL_BAR (object));
+ g_object_ref_sink (bar->priv->adjustment);
- channel_bar = GVC_CHANNEL_BAR (object);
+ g_signal_connect (bar->priv->adjustment,
+ "value-changed",
+ G_CALLBACK (on_adjustment_value_changed),
+ bar);
- g_return_if_fail (channel_bar->priv != NULL);
+ /* Initially create a vertical scale box */
+ bar->priv->orientation = GTK_ORIENTATION_VERTICAL;
- g_free (channel_bar->priv->name);
- g_free (channel_bar->priv->icon_name);
- g_free (channel_bar->priv->low_icon_name);
- g_free (channel_bar->priv->high_icon_name);
+ create_scale_box (bar);
- G_OBJECT_CLASS (gvc_channel_bar_parent_class)->finalize (object);
+ gtk_container_add (GTK_CONTAINER (frame), bar->priv->scale_box);
}
GtkWidget *
-gvc_channel_bar_new (void)
+gvc_channel_bar_new (MateMixerStream *stream)
{
- return g_object_new (GVC_TYPE_CHANNEL_BAR, NULL);
+ return g_object_new (GVC_TYPE_CHANNEL_BAR,
+ "stream", stream,
+#if GTK_CHECK_VERSION (3, 0, 0)
+ "orientation", GTK_ORIENTATION_HORIZONTAL,
+#endif
+ NULL);
}
diff --git a/mate-volume-control/src/gvc-channel-bar.h b/mate-volume-control/src/gvc-channel-bar.h
index d31da50..16d6257 100644
--- a/mate-volume-control/src/gvc-channel-bar.h
+++ b/mate-volume-control/src/gvc-channel-bar.h
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
*
* 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
@@ -23,6 +24,9 @@
#include <glib.h>
#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include <libmatemixer/matemixer.h>
G_BEGIN_DECLS
@@ -33,9 +37,11 @@ G_BEGIN_DECLS
#define GVC_IS_CHANNEL_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_CHANNEL_BAR))
#define GVC_CHANNEL_BAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_CHANNEL_BAR, GvcChannelBarClass))
-typedef struct GvcChannelBarPrivate GvcChannelBarPrivate;
+typedef struct _GvcChannelBar GvcChannelBar;
+typedef struct _GvcChannelBarClass GvcChannelBarClass;
+typedef struct _GvcChannelBarPrivate GvcChannelBarPrivate;
-typedef struct
+struct _GvcChannelBar
{
#if GTK_CHECK_VERSION (3, 0, 0)
GtkBox parent;
@@ -43,52 +49,69 @@ typedef struct
GtkHBox parent;
#endif
GvcChannelBarPrivate *priv;
-} GvcChannelBar;
+};
-typedef struct
+struct _GvcChannelBarClass
{
#if GTK_CHECK_VERSION (3, 0, 0)
GtkBoxClass parent_class;
#else
GtkHBoxClass parent_class;
#endif
-} GvcChannelBarClass;
+
+ void (* changed) (GvcChannelBar *bar);
+};
GType gvc_channel_bar_get_type (void);
-GtkWidget * gvc_channel_bar_new (void);
-
-void gvc_channel_bar_set_name (GvcChannelBar *bar,
- const char *name);
-void gvc_channel_bar_set_icon_name (GvcChannelBar *bar,
- const char *icon_name);
-void gvc_channel_bar_set_low_icon_name (GvcChannelBar *bar,
- const char *icon_name);
-void gvc_channel_bar_set_high_icon_name (GvcChannelBar *bar,
- const char *icon_name);
-
-void gvc_channel_bar_set_orientation (GvcChannelBar *bar,
- GtkOrientation orientation);
-GtkOrientation gvc_channel_bar_get_orientation (GvcChannelBar *bar);
-
-GtkAdjustment * gvc_channel_bar_get_adjustment (GvcChannelBar *bar);
-
-gboolean gvc_channel_bar_get_is_muted (GvcChannelBar *bar);
-void gvc_channel_bar_set_is_muted (GvcChannelBar *bar,
- gboolean is_muted);
-gboolean gvc_channel_bar_get_show_mute (GvcChannelBar *bar);
-void gvc_channel_bar_set_show_mute (GvcChannelBar *bar,
- gboolean show_mute);
-void gvc_channel_bar_set_size_group (GvcChannelBar *bar,
- GtkSizeGroup *group,
- gboolean symmetric);
-void gvc_channel_bar_set_is_amplified (GvcChannelBar *bar,
- gboolean amplified);
-void gvc_channel_bar_set_base_volume (GvcChannelBar *bar,
- guint32 base_volume);
-
-gboolean gvc_channel_bar_scroll (GvcChannelBar *bar,
- GdkScrollDirection direction);
+GtkWidget * gvc_channel_bar_new (MateMixerStream *stream);
+
+MateMixerStream * gvc_channel_bar_get_stream (GvcChannelBar *bar);
+void gvc_channel_bar_set_stream (GvcChannelBar *bar,
+ MateMixerStream *stream);
+
+const gchar * gvc_channel_bar_get_name (GvcChannelBar *bar);
+void gvc_channel_bar_set_name (GvcChannelBar *bar,
+ const gchar *name);
+
+const gchar * gvc_channel_bar_get_icon_name (GvcChannelBar *bar);
+void gvc_channel_bar_set_icon_name (GvcChannelBar *bar,
+ const gchar *icon_name);
+
+const gchar * gvc_channel_bar_get_low_icon_name (GvcChannelBar *bar);
+void gvc_channel_bar_set_low_icon_name (GvcChannelBar *bar,
+ const gchar *icon_name);
+
+const gchar * gvc_channel_bar_get_high_icon_name (GvcChannelBar *bar);
+void gvc_channel_bar_set_high_icon_name (GvcChannelBar *bar,
+ const gchar *icon_name);
+
+GtkOrientation gvc_channel_bar_get_orientation (GvcChannelBar *bar);
+void gvc_channel_bar_set_orientation (GvcChannelBar *bar,
+ GtkOrientation orientation);
+
+gboolean gvc_channel_bar_get_show_icons (GvcChannelBar *bar);
+void gvc_channel_bar_set_show_icons (GvcChannelBar *bar,
+ gboolean show_mute);
+
+gboolean gvc_channel_bar_get_show_mute (GvcChannelBar *bar);
+void gvc_channel_bar_set_show_mute (GvcChannelBar *bar,
+ gboolean show_mute);
+
+gboolean gvc_channel_bar_get_show_marks (GvcChannelBar *bar);
+void gvc_channel_bar_set_show_marks (GvcChannelBar *bar,
+ gboolean show_marks);
+
+gboolean gvc_channel_bar_get_extended (GvcChannelBar *bar);
+void gvc_channel_bar_set_extended (GvcChannelBar *bar,
+ gboolean extended);
+
+void gvc_channel_bar_set_size_group (GvcChannelBar *bar,
+ GtkSizeGroup *group,
+ gboolean symmetric);
+
+gboolean gvc_channel_bar_scroll (GvcChannelBar *bar,
+ GdkScrollDirection direction);
G_END_DECLS
diff --git a/mate-volume-control/src/gvc-combo-box.c b/mate-volume-control/src/gvc-combo-box.c
index 6004632..524e1b0 100644
--- a/mate-volume-control/src/gvc-combo-box.c
+++ b/mate-volume-control/src/gvc-combo-box.c
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2009 Bastien Nocera
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
*
* 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
@@ -18,20 +19,18 @@
*
*/
-#include "config.h"
-
#include <glib.h>
#include <glib/gi18n.h>
+#include <glib-object.h>
#include <gtk/gtk.h>
-#include <canberra-gtk.h>
#include <libmatemixer/matemixer.h>
#include "gvc-combo-box.h"
#define GVC_COMBO_BOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_COMBO_BOX, GvcComboBoxPrivate))
-struct GvcComboBoxPrivate
+struct _GvcComboBoxPrivate
{
GtkWidget *drop_box;
GtkWidget *start_box;
@@ -57,18 +56,21 @@ enum {
LAST_SIGNAL
};
+static guint signals[LAST_SIGNAL] = { 0, };
+
enum {
PROP_0,
PROP_LABEL,
PROP_SHOW_BUTTON,
- PROP_BUTTON_LABEL
+ PROP_BUTTON_LABEL,
+ N_PROPERTIES
};
-static guint signals [LAST_SIGNAL] = { 0, };
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
-static void gvc_combo_box_class_init (GvcComboBoxClass *klass);
-static void gvc_combo_box_init (GvcComboBox *combo_box);
-static void gvc_combo_box_finalize (GObject *object);
+static void gvc_combo_box_class_init (GvcComboBoxClass *klass);
+static void gvc_combo_box_init (GvcComboBox *combo);
+static void gvc_combo_box_dispose (GObject *object);
#if GTK_CHECK_VERSION (3, 0, 0)
G_DEFINE_TYPE (GvcComboBox, gvc_combo_box, GTK_TYPE_BOX)
@@ -77,25 +79,25 @@ G_DEFINE_TYPE (GvcComboBox, gvc_combo_box, GTK_TYPE_HBOX)
#endif
void
-gvc_combo_box_set_size_group (GvcComboBox *combo_box,
- GtkSizeGroup *group,
- gboolean symmetric)
+gvc_combo_box_set_size_group (GvcComboBox *combobox,
+ GtkSizeGroup *group,
+ gboolean symmetric)
{
- g_return_if_fail (GVC_IS_COMBO_BOX (combo_box));
+ g_return_if_fail (GVC_IS_COMBO_BOX (combobox));
+ g_return_if_fail (GTK_IS_SIZE_GROUP (group));
- combo_box->priv->size_group = group;
- combo_box->priv->symmetric = symmetric;
+ combobox->priv->size_group = group;
+ combobox->priv->symmetric = symmetric;
- if (combo_box->priv->size_group != NULL) {
- gtk_size_group_add_widget (combo_box->priv->size_group,
- combo_box->priv->start_box);
+ if (combobox->priv->size_group != NULL) {
+ gtk_size_group_add_widget (combobox->priv->size_group,
+ combobox->priv->start_box);
- if (combo_box->priv->symmetric) {
- gtk_size_group_add_widget (combo_box->priv->size_group,
- combo_box->priv->end_box);
- }
+ if (combobox->priv->symmetric)
+ gtk_size_group_add_widget (combobox->priv->size_group,
+ combobox->priv->end_box);
}
- gtk_widget_queue_draw (GTK_WIDGET (combo_box));
+ gtk_widget_queue_draw (GTK_WIDGET (combobox));
}
static void
@@ -132,16 +134,13 @@ gvc_combo_box_get_property (GObject *object,
switch (prop_id) {
case PROP_LABEL:
- g_value_set_string (value,
- gtk_label_get_text (GTK_LABEL (self->priv->label)));
+ g_value_set_string (value, gtk_label_get_text (GTK_LABEL (self->priv->label)));
break;
case PROP_BUTTON_LABEL:
- g_value_set_string (value,
- gtk_button_get_label (GTK_BUTTON (self->priv->button)));
+ g_value_set_string (value, gtk_button_get_label (GTK_BUTTON (self->priv->button)));
break;
case PROP_SHOW_BUTTON:
- g_value_set_boolean (value,
- gtk_widget_get_visible (self->priv->button));
+ g_value_set_boolean (value, gtk_widget_get_visible (self->priv->button));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -154,32 +153,34 @@ gvc_combo_box_class_init (GvcComboBoxClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- object_class->finalize = gvc_combo_box_finalize;
+ object_class->dispose = gvc_combo_box_dispose;
object_class->set_property = gvc_combo_box_set_property;
object_class->get_property = gvc_combo_box_get_property;
- g_object_class_install_property (object_class,
- PROP_LABEL,
- g_param_spec_string ("label",
- "label",
- "The combo box label",
- _("_Profile:"),
- G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
- g_object_class_install_property (object_class,
- PROP_SHOW_BUTTON,
- g_param_spec_boolean ("show-button",
- "show-button",
- "Whether to show the button",
- FALSE,
- G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
- g_object_class_install_property (object_class,
- PROP_BUTTON_LABEL,
- g_param_spec_string ("button-label",
- "button-label",
- "The button's label",
- "APPLICATION BUG",
- G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
- signals [CHANGED] =
+ properties[PROP_LABEL] =
+ g_param_spec_string ("label",
+ "label",
+ "The combo box label",
+ _("_Profile:"),
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+
+ properties[PROP_SHOW_BUTTON] =
+ g_param_spec_boolean ("show-button",
+ "show-button",
+ "Whether to show the button",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+
+ properties[PROP_BUTTON_LABEL] =
+ g_param_spec_string ("button-label",
+ "button-label",
+ "The button's label",
+ "",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ signals[CHANGED] =
g_signal_new ("changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
@@ -187,7 +188,8 @@ gvc_combo_box_class_init (GvcComboBoxClass *klass)
NULL, NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1, G_TYPE_STRING);
- signals [BUTTON_CLICKED] =
+
+ signals[BUTTON_CLICKED] =
g_signal_new ("button-clicked",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
@@ -200,190 +202,219 @@ gvc_combo_box_class_init (GvcComboBoxClass *klass)
}
void
-gvc_combo_box_set_profiles (GvcComboBox *combo_box,
- const GList *profiles)
+gvc_combo_box_set_profiles (GvcComboBox *combobox, const GList *profiles)
{
const GList *l;
- g_return_if_fail (GVC_IS_COMBO_BOX (combo_box));
- g_return_if_fail (combo_box->priv->set_called == FALSE);
+ g_return_if_fail (GVC_IS_COMBO_BOX (combobox));
+ g_return_if_fail (combobox->priv->set_called == FALSE);
for (l = profiles; l != NULL; l = l->next) {
MateMixerDeviceProfile *p = MATE_MIXER_DEVICE_PROFILE (l->data);
- gtk_list_store_insert_with_values (GTK_LIST_STORE (combo_box->priv->model),
+ gtk_list_store_insert_with_values (GTK_LIST_STORE (combobox->priv->model),
NULL,
G_MAXINT,
- COL_NAME, mate_mixer_device_profile_get_name (p),
- COL_HUMAN_NAME, mate_mixer_device_profile_get_description (p),
+ COL_NAME,
+ mate_mixer_device_profile_get_name (p),
+ COL_HUMAN_NAME,
+ mate_mixer_device_profile_get_description (p),
-1);
}
- combo_box->priv->set_called = TRUE;
+ combobox->priv->set_called = TRUE;
}
void
-gvc_combo_box_set_ports (GvcComboBox *combo_box, const GList *ports)
+gvc_combo_box_set_ports (GvcComboBox *combobox, const GList *ports)
{
const GList *l;
- g_return_if_fail (GVC_IS_COMBO_BOX (combo_box));
- g_return_if_fail (combo_box->priv->set_called == FALSE);
+ g_return_if_fail (GVC_IS_COMBO_BOX (combobox));
+ g_return_if_fail (combobox->priv->set_called == FALSE);
for (l = ports; l != NULL; l = l->next) {
MateMixerPort *p = MATE_MIXER_PORT (l->data);
- gtk_list_store_insert_with_values (GTK_LIST_STORE (combo_box->priv->model),
+ gtk_list_store_insert_with_values (GTK_LIST_STORE (combobox->priv->model),
NULL,
G_MAXINT,
- COL_NAME, mate_mixer_port_get_name (p),
- COL_HUMAN_NAME, mate_mixer_port_get_description (p),
+ COL_NAME,
+ mate_mixer_port_get_name (p),
+ COL_HUMAN_NAME,
+ mate_mixer_port_get_description (p),
-1);
}
- combo_box->priv->set_called = TRUE;
+ combobox->priv->set_called = TRUE;
}
void
-gvc_combo_box_set_active (GvcComboBox *combo_box,
- const char *id)
+gvc_combo_box_set_active (GvcComboBox *combobox, const gchar *id)
{
GtkTreeIter iter;
- gboolean cont;
+ gboolean cont;
- cont = gtk_tree_model_get_iter_first (combo_box->priv->model, &iter);
+ g_return_if_fail (GVC_IS_COMBO_BOX (combobox));
+ g_return_if_fail (id != NULL);
+
+ cont = gtk_tree_model_get_iter_first (combobox->priv->model, &iter);
while (cont != FALSE) {
- char *name;
+ gchar *name;
- gtk_tree_model_get (combo_box->priv->model, &iter,
+ gtk_tree_model_get (combobox->priv->model, &iter,
COL_NAME, &name,
-1);
if (g_strcmp0 (name, id) == 0) {
- gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box->priv->combobox), &iter);
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combobox->priv->combobox), &iter);
+ g_free (name);
return;
}
- gtk_tree_model_iter_next (combo_box->priv->model, &iter);
+ g_free (name);
+
+ gtk_tree_model_iter_next (combobox->priv->model, &iter);
}
g_warning ("Could not find id '%s' in combo box", id);
}
static void
-on_combo_box_changed (GtkComboBox *widget,
- GvcComboBox *combo_box)
+on_combo_box_changed (GtkComboBox *widget, GvcComboBox *combobox)
{
- GtkTreeIter iter;
- char *profile;
+ GtkTreeIter iter;
+ gchar *profile;
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter) == FALSE) {
g_warning ("Could not find an active profile or port");
return;
}
- gtk_tree_model_get (combo_box->priv->model, &iter,
+ gtk_tree_model_get (combobox->priv->model, &iter,
COL_NAME, &profile,
-1);
- g_signal_emit (combo_box, signals[CHANGED], 0, profile);
+
+ g_signal_emit (combobox, signals[CHANGED], 0, profile);
g_free (profile);
}
static void
-on_combo_box_button_clicked (GtkButton *button,
- GvcComboBox *combo_box)
+on_combo_box_button_clicked (GtkButton *button, GvcComboBox *combobox)
{
- g_signal_emit (combo_box, signals[BUTTON_CLICKED], 0);
+ g_signal_emit (combobox, signals[BUTTON_CLICKED], 0);
}
static void
-gvc_combo_box_init (GvcComboBox *combo_box)
+gvc_combo_box_init (GvcComboBox *combobox)
{
- GtkWidget *frame;
- GtkWidget *box;
- GtkWidget *sbox;
- GtkWidget *ebox;
- GtkCellRenderer *renderer;
+ GtkWidget *frame;
+ GtkCellRenderer *renderer;
- combo_box->priv = GVC_COMBO_BOX_GET_PRIVATE (combo_box);
+ combobox->priv = GVC_COMBO_BOX_GET_PRIVATE (combobox);
- combo_box->priv->model = GTK_TREE_MODEL (gtk_list_store_new (NUM_COLS,
- G_TYPE_STRING,
- G_TYPE_STRING));
+ combobox->priv->model = GTK_TREE_MODEL (gtk_list_store_new (NUM_COLS,
+ G_TYPE_STRING,
+ G_TYPE_STRING));
+ combobox->priv->label = gtk_label_new (NULL);
- combo_box->priv->label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (combo_box->priv->label),
- 0.0,
- 0.5);
+ gtk_misc_set_alignment (GTK_MISC (combobox->priv->label), 0.0, 0.5);
- /* frame */
+ /* Frame */
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
- gtk_container_add (GTK_CONTAINER (combo_box), frame);
+ gtk_box_pack_start (GTK_BOX (combobox), frame, TRUE, TRUE, 0);
+
+#if GTK_CHECK_VERSION (3, 0, 0)
+ combobox->priv->drop_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ combobox->priv->start_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ combobox->priv->end_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+#else
+ combobox->priv->drop_box = gtk_hbox_new (FALSE, 6);
+ combobox->priv->start_box = gtk_hbox_new (FALSE, 6);
+ combobox->priv->end_box = gtk_hbox_new (FALSE, 6);
+#endif
+ combobox->priv->combobox = gtk_combo_box_new_with_model (combobox->priv->model);
- combo_box->priv->drop_box = box = gtk_hbox_new (FALSE, 6);
- combo_box->priv->combobox = gtk_combo_box_new_with_model (combo_box->priv->model);
renderer = gtk_cell_renderer_text_new ();
- gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box->priv->combobox),
- renderer, FALSE);
- gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->combobox),
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox->priv->combobox),
+ renderer,
+ FALSE);
+ gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combobox->priv->combobox),
renderer,
- "text", COL_HUMAN_NAME);
-
-/* gtk_widget_set_size_request (combo_box->priv->combobox, 128, -1); */
-
- combo_box->priv->start_box = sbox = gtk_hbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (box), sbox, FALSE, FALSE, 0);
+ "text",
+ COL_HUMAN_NAME);
- gtk_box_pack_start (GTK_BOX (sbox), combo_box->priv->label, FALSE, FALSE, 0);
-
- gtk_box_pack_start (GTK_BOX (box), combo_box->priv->combobox, TRUE, TRUE, 0);
-
- combo_box->priv->button = gtk_button_new_with_label ("APPLICATION BUG");
- gtk_widget_set_no_show_all (combo_box->priv->button, TRUE);
- gtk_box_pack_start (GTK_BOX (box), combo_box->priv->button, FALSE, FALSE, 0);
-
-
- combo_box->priv->end_box = ebox = gtk_hbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, FALSE, 0);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ /* Make sure the combo box does not get too long on long profile names */
+ g_object_set (G_OBJECT (renderer),
+ "ellipsize",
+ PANGO_ELLIPSIZE_END,
+ NULL);
- if (combo_box->priv->size_group != NULL) {
- gtk_size_group_add_widget (combo_box->priv->size_group, sbox);
+ gtk_combo_box_set_popup_fixed_width (GTK_COMBO_BOX (combobox->priv->combobox), FALSE);
+#endif
- if (combo_box->priv->symmetric) {
- gtk_size_group_add_widget (combo_box->priv->size_group, ebox);
- }
+ gtk_box_pack_start (GTK_BOX (combobox->priv->drop_box),
+ combobox->priv->start_box,
+ FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (combobox->priv->start_box),
+ combobox->priv->label,
+ FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (combobox->priv->drop_box),
+ combobox->priv->combobox,
+ TRUE, TRUE, 0);
+
+ combobox->priv->button = gtk_button_new_with_label ("");
+
+ gtk_box_pack_start (GTK_BOX (combobox->priv->drop_box),
+ combobox->priv->button,
+ FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (combobox->priv->drop_box),
+ combobox->priv->end_box,
+ FALSE, FALSE, 0);
+
+ gtk_widget_set_no_show_all (combobox->priv->button, TRUE);
+
+ if (combobox->priv->size_group != NULL) {
+ gtk_size_group_add_widget (combobox->priv->size_group,
+ combobox->priv->start_box);
+
+ if (combobox->priv->symmetric)
+ gtk_size_group_add_widget (combobox->priv->size_group,
+ combobox->priv->end_box);
}
- gtk_container_add (GTK_CONTAINER (frame), combo_box->priv->drop_box);
- gtk_widget_show_all (frame);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (combobox->priv->label),
+ combobox->priv->combobox);
- gtk_label_set_mnemonic_widget (GTK_LABEL (combo_box->priv->label),
- combo_box->priv->combobox);
+ gtk_container_add (GTK_CONTAINER (frame), combobox->priv->drop_box);
+ gtk_widget_show_all (frame);
- g_signal_connect (G_OBJECT (combo_box->priv->combobox), "changed",
- G_CALLBACK (on_combo_box_changed), combo_box);
- g_signal_connect (G_OBJECT (combo_box->priv->button), "clicked",
- G_CALLBACK (on_combo_box_button_clicked), combo_box);
+ g_signal_connect (G_OBJECT (combobox->priv->combobox),
+ "changed",
+ G_CALLBACK (on_combo_box_changed),
+ combobox);
+ g_signal_connect (G_OBJECT (combobox->priv->button),
+ "clicked",
+ G_CALLBACK (on_combo_box_button_clicked),
+ combobox);
}
static void
-gvc_combo_box_finalize (GObject *object)
+gvc_combo_box_dispose (GObject *object)
{
- GvcComboBox *combo_box;
-
- g_return_if_fail (object != NULL);
- g_return_if_fail (GVC_IS_COMBO_BOX (object));
+ GvcComboBox *combobox;
- combo_box = GVC_COMBO_BOX (object);
+ combobox = GVC_COMBO_BOX (object);
- g_return_if_fail (combo_box->priv != NULL);
+ g_clear_object (&combobox->priv->model);
- g_object_unref (combo_box->priv->model);
- combo_box->priv->model = NULL;
-
- G_OBJECT_CLASS (gvc_combo_box_parent_class)->finalize (object);
+ G_OBJECT_CLASS (gvc_combo_box_parent_class)->dispose (object);
}
GtkWidget *
-gvc_combo_box_new (const char *label)
+gvc_combo_box_new (const gchar *label)
{
return g_object_new (GVC_TYPE_COMBO_BOX,
"label", label,
+#if GTK_CHECK_VERSION (3, 0, 0)
+ "orientation", GTK_ORIENTATION_HORIZONTAL,
+#endif
NULL);
}
diff --git a/mate-volume-control/src/gvc-combo-box.h b/mate-volume-control/src/gvc-combo-box.h
index ee18ff8..4cd8511 100644
--- a/mate-volume-control/src/gvc-combo-box.h
+++ b/mate-volume-control/src/gvc-combo-box.h
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
*
* 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
@@ -21,7 +22,9 @@
#ifndef __GVC_COMBO_BOX_H
#define __GVC_COMBO_BOX_H
+#include <glib.h>
#include <glib-object.h>
+#include <gtk/gtk.h>
G_BEGIN_DECLS
@@ -32,43 +35,46 @@ G_BEGIN_DECLS
#define GVC_IS_COMBO_BOX_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_COMBO_BOX))
#define GVC_COMBO_BOX_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_COMBO_BOX, GvcComboBoxClass))
-typedef struct GvcComboBoxPrivate GvcComboBoxPrivate;
+typedef struct _GvcComboBox GvcComboBox;
+typedef struct _GvcComboBoxClass GvcComboBoxClass;
+typedef struct _GvcComboBoxPrivate GvcComboBoxPrivate;
-typedef struct
+struct _GvcComboBox
{
#if GTK_CHECK_VERSION (3, 0, 0)
- GtkBox parent;
+ GtkBox parent;
#else
- GtkHBox parent;
+ GtkHBox parent;
#endif
- GvcComboBoxPrivate *priv;
-} GvcComboBox;
+ GvcComboBoxPrivate *priv;
+};
-typedef struct
+struct _GvcComboBoxClass
{
#if GTK_CHECK_VERSION (3, 0, 0)
GtkBoxClass parent_class;
#else
GtkHBoxClass parent_class;
#endif
- void (* changed) (GvcComboBox *combobox, const char *name);
+ void (* changed) (GvcComboBox *combobox,
+ const gchar *name);
void (* button_clicked) (GvcComboBox *combobox);
-} GvcComboBoxClass;
+};
-GType gvc_combo_box_get_type (void);
+GType gvc_combo_box_get_type (void) G_GNUC_CONST;
-GtkWidget * gvc_combo_box_new (const char *label);
+GtkWidget * gvc_combo_box_new (const gchar *label);
-void gvc_combo_box_set_size_group (GvcComboBox *combo_box,
+void gvc_combo_box_set_size_group (GvcComboBox *combobox,
GtkSizeGroup *group,
gboolean symmetric);
-void gvc_combo_box_set_profiles (GvcComboBox *combo_box,
+void gvc_combo_box_set_profiles (GvcComboBox *combobox,
const GList *profiles);
-void gvc_combo_box_set_ports (GvcComboBox *combo_box,
+void gvc_combo_box_set_ports (GvcComboBox *combobox,
const GList *ports);
-void gvc_combo_box_set_active (GvcComboBox *combo_box,
- const char *id);
+void gvc_combo_box_set_active (GvcComboBox *combobox,
+ const gchar *id);
G_END_DECLS
diff --git a/mate-volume-control/src/gvc-level-bar.c b/mate-volume-control/src/gvc-level-bar.c
index fbc0538..0f3dc1b 100644
--- a/mate-volume-control/src/gvc-level-bar.c
+++ b/mate-volume-control/src/gvc-level-bar.c
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 William Jon McCann <[email protected]>
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
*
* 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
@@ -18,54 +19,50 @@
*
*/
-#include "config.h"
+// XXX on gtk3 the last two squares don't get filled
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
#include <math.h>
-
#include <glib.h>
#include <glib/gi18n.h>
+#include <glib-object.h>
#include <gtk/gtk.h>
#include "gvc-level-bar.h"
-
-#define NUM_BOXES 15
+#include "mvc-helpers.h"
#define GVC_LEVEL_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_LEVEL_BAR, GvcLevelBarPrivate))
+#define NUM_BOXES 15
#define MIN_HORIZONTAL_BAR_WIDTH 150
#define HORIZONTAL_BAR_HEIGHT 6
#define VERTICAL_BAR_WIDTH 6
#define MIN_VERTICAL_BAR_HEIGHT 400
typedef struct {
- int peak_num;
- int max_peak_num;
-
- GdkRectangle area;
- int delta;
- int box_width;
- int box_height;
- int box_radius;
- double bg_r;
- double bg_g;
- double bg_b;
- double bdr_r;
- double bdr_g;
- double bdr_b;
- double fl_r;
- double fl_g;
- double fl_b;
+ int peak_num;
+ int max_peak_num;
+ GdkRectangle area;
+ int delta;
+ int box_width;
+ int box_height;
+ int box_radius;
+#if GTK_CHECK_VERSION (3, 0, 0)
+ GdkRGBA color_bg;
+ GdkRGBA color_fg;
+ GdkRGBA color_dark;
+#else
+ GdkColor color_bg;
+ GdkColor color_fg;
+ GdkColor color_dark;
+#endif
} LevelBarLayout;
-struct GvcLevelBarPrivate
+struct _GvcLevelBarPrivate
{
GtkOrientation orientation;
GtkAdjustment *peak_adjustment;
GtkAdjustment *rms_adjustment;
- int scale;
+ GvcLevelScale scale;
gdouble peak_fraction;
gdouble rms_fraction;
gdouble max_peak;
@@ -80,47 +77,51 @@ enum
PROP_RMS_ADJUSTMENT,
PROP_SCALE,
PROP_ORIENTATION,
+ N_PROPERTIES
};
-static void gvc_level_bar_class_init (GvcLevelBarClass *klass);
-static void gvc_level_bar_init (GvcLevelBar *level_bar);
-static void gvc_level_bar_finalize (GObject *object);
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
-#if GTK_CHECK_VERSION (3, 0, 0)
-G_DEFINE_TYPE (GvcLevelBar, gvc_level_bar, GTK_TYPE_BOX)
-#else
-G_DEFINE_TYPE (GvcLevelBar, gvc_level_bar, GTK_TYPE_HBOX)
-#endif
+static void gvc_level_bar_class_init (GvcLevelBarClass *klass);
+static void gvc_level_bar_init (GvcLevelBar *bar);
+static void gvc_level_bar_finalize (GObject *object);
-#define check_rectangle(rectangle1, rectangle2) \
- { \
- if (rectangle1.x != rectangle2.x) return TRUE; \
- if (rectangle1.y != rectangle2.y) return TRUE; \
- if (rectangle1.width != rectangle2.width) return TRUE; \
- if (rectangle1.height != rectangle2.height) return TRUE; \
- }
+G_DEFINE_TYPE (GvcLevelBar, gvc_level_bar, GTK_TYPE_WIDGET)
static gboolean
-layout_changed (LevelBarLayout *layout1,
- LevelBarLayout *layout2)
+layout_changed (LevelBarLayout *layout1, LevelBarLayout *layout2)
{
- check_rectangle (layout1->area, layout2->area);
- if (layout1->delta != layout2->delta) return TRUE;
- if (layout1->peak_num != layout2->peak_num) return TRUE;
- if (layout1->max_peak_num != layout2->max_peak_num) return TRUE;
- if (layout1->bg_r != layout2->bg_r
- || layout1->bg_g != layout2->bg_g
- || layout1->bg_b != layout2->bg_b)
+ if (layout1->area.x != layout2->area.x)
+ return TRUE;
+ if (layout1->area.y != layout2->area.y)
return TRUE;
- if (layout1->bdr_r != layout2->bdr_r
- || layout1->bdr_g != layout2->bdr_g
- || layout1->bdr_b != layout2->bdr_b)
+ if (layout1->area.width != layout2->area.width)
return TRUE;
- if (layout1->fl_r != layout2->fl_r
- || layout1->fl_g != layout2->fl_g
- || layout1->fl_b != layout2->fl_b)
+ if (layout1->area.height != layout2->area.height)
return TRUE;
+ if (layout1->delta != layout2->delta)
+ return TRUE;
+ if (layout1->peak_num != layout2->peak_num)
+ return TRUE;
+ if (layout1->max_peak_num != layout2->max_peak_num)
+ return TRUE;
+
+#if GTK_CHECK_VERSION (3, 0, 0)
+ if (!gdk_rgba_equal (&layout1->color_fg, &layout2->color_fg))
+ return TRUE;
+ if (!gdk_rgba_equal (&layout1->color_bg, &layout2->color_bg))
+ return TRUE;
+ if (!gdk_rgba_equal (&layout1->color_dark, &layout2->color_dark))
+ return TRUE;
+#else
+ if (!gdk_color_equal (&layout1->color_fg, &layout2->color_fg))
+ return TRUE;
+ if (!gdk_color_equal (&layout1->color_bg, &layout2->color_bg))
+ return TRUE;
+ if (!gdk_color_equal (&layout1->color_dark, &layout2->color_dark))
+ return TRUE;
+#endif
return FALSE;
}
@@ -129,14 +130,13 @@ fraction_from_adjustment (GvcLevelBar *bar,
GtkAdjustment *adjustment)
{
gdouble level;
- gdouble fraction;
+ gdouble fraction = 0.0;
gdouble min;
gdouble max;
level = gtk_adjustment_get_value (adjustment);
-
- min = gtk_adjustment_get_lower (adjustment);
- max = gtk_adjustment_get_upper (adjustment);
+ min = gtk_adjustment_get_lower (adjustment);
+ max = gtk_adjustment_get_upper (adjustment);
switch (bar->priv->scale) {
case GVC_LEVEL_SCALE_LINEAR:
@@ -145,8 +145,6 @@ fraction_from_adjustment (GvcLevelBar *bar,
case GVC_LEVEL_SCALE_LOG:
fraction = log10 ((level - min + 1) / (max - min + 1));
break;
- default:
- g_assert_not_reached ();
}
return fraction;
@@ -155,12 +153,12 @@ fraction_from_adjustment (GvcLevelBar *bar,
static gboolean
reset_max_peak (GvcLevelBar *bar)
{
- gdouble min;
+ bar->priv->max_peak = gtk_adjustment_get_lower (bar->priv->peak_adjustment);
- min = gtk_adjustment_get_lower (bar->priv->peak_adjustment);
- bar->priv->max_peak = min;
bar->priv->layout.max_peak_num = 0;
+
gtk_widget_queue_draw (GTK_WIDGET (bar));
+
bar->priv->max_peak_id = 0;
return FALSE;
}
@@ -168,30 +166,43 @@ reset_max_peak (GvcLevelBar *bar)
static void
bar_calc_layout (GvcLevelBar *bar)
{
- GdkColor color;
- int peak_level;
- int max_peak_level;
+ int peak_level;
+ int max_peak_level;
GtkAllocation allocation;
+
+#if GTK_CHECK_VERSION (3, 0, 0)
+ GtkStyleContext *context;
+
+ context = gtk_widget_get_style_context (GTK_WIDGET (bar));
+
+ gtk_style_context_get_background_color (context,
+ GTK_STATE_FLAG_NORMAL,
+ &bar->priv->layout.color_bg);
+ gtk_style_context_get_background_color (context,
+ GTK_STATE_FLAG_SELECTED,
+ &bar->priv->layout.color_fg);
+ gtk_style_context_get_color (context,
+ GTK_STATE_FLAG_NORMAL,
+ &bar->priv->layout.color_dark);
+
+ mvc_color_shade (&bar->priv->layout.color_dark,
+ &bar->priv->layout.color_dark,
+ 0.7);
+#else
GtkStyle *style;
+ style = gtk_widget_get_style (GTK_WIDGET (bar));
+
+ bar->priv->layout.color_bg = style->bg[GTK_STATE_NORMAL];
+ bar->priv->layout.color_fg = style->bg[GTK_STATE_SELECTED];
+ bar->priv->layout.color_dark = style->dark[GTK_STATE_NORMAL];
+#endif
+
gtk_widget_get_allocation (GTK_WIDGET (bar), &allocation);
+
bar->priv->layout.area.width = allocation.width - 2;
bar->priv->layout.area.height = allocation.height - 2;
- style = gtk_widget_get_style (GTK_WIDGET (bar));
- color = style->bg [GTK_STATE_NORMAL];
- bar->priv->layout.bg_r = (float)color.red / 65535.0;
- bar->priv->layout.bg_g = (float)color.green / 65535.0;
- bar->priv->layout.bg_b = (float)color.blue / 65535.0;
- color = style->dark [GTK_STATE_NORMAL];
- bar->priv->layout.bdr_r = (float)color.red / 65535.0;
- bar->priv->layout.bdr_g = (float)color.green / 65535.0;
- bar->priv->layout.bdr_b = (float)color.blue / 65535.0;
- color = style->bg [GTK_STATE_SELECTED];
- bar->priv->layout.fl_r = (float)color.red / 65535.0;
- bar->priv->layout.fl_g = (float)color.green / 65535.0;
- bar->priv->layout.fl_b = (float)color.blue / 65535.0;
-
if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
peak_level = bar->priv->peak_fraction * bar->priv->layout.area.height;
max_peak_level = bar->priv->max_peak * bar->priv->layout.area.height;
@@ -200,7 +211,7 @@ bar_calc_layout (GvcLevelBar *bar)
bar->priv->layout.area.x = 0;
bar->priv->layout.area.y = 0;
bar->priv->layout.box_height = bar->priv->layout.delta / 2;
- bar->priv->layout.box_width = bar->priv->layout.area.width;
+ bar->priv->layout.box_width = bar->priv->layout.area.width;
bar->priv->layout.box_radius = bar->priv->layout.box_width / 2;
} else {
peak_level = bar->priv->peak_fraction * bar->priv->layout.area.width;
@@ -209,7 +220,7 @@ bar_calc_layout (GvcLevelBar *bar)
bar->priv->layout.delta = bar->priv->layout.area.width / NUM_BOXES;
bar->priv->layout.area.x = 0;
bar->priv->layout.area.y = 0;
- bar->priv->layout.box_width = bar->priv->layout.delta / 2;
+ bar->priv->layout.box_width = bar->priv->layout.delta / 2;
bar->priv->layout.box_height = bar->priv->layout.area.height;
bar->priv->layout.box_radius = bar->priv->layout.box_height / 2;
}
@@ -221,42 +232,41 @@ bar_calc_layout (GvcLevelBar *bar)
static void
update_peak_value (GvcLevelBar *bar)
{
- gdouble val;
+ gdouble value;
LevelBarLayout layout;
- layout = bar->priv->layout;
+ value = fraction_from_adjustment (bar, bar->priv->peak_adjustment);
- val = fraction_from_adjustment (bar, bar->priv->peak_adjustment);
- bar->priv->peak_fraction = val;
+ bar->priv->peak_fraction = value;
- if (val > bar->priv->max_peak) {
- if (bar->priv->max_peak_id > 0) {
+ if (value > bar->priv->max_peak) {
+ if (bar->priv->max_peak_id > 0)
g_source_remove (bar->priv->max_peak_id);
- }
- bar->priv->max_peak_id = g_timeout_add_seconds (1, (GSourceFunc)reset_max_peak, bar);
- bar->priv->max_peak = val;
+
+ bar->priv->max_peak_id =
+ g_timeout_add_seconds (1, (GSourceFunc) reset_max_peak, bar);
+ bar->priv->max_peak = value;
}
+ layout = bar->priv->layout;
+
bar_calc_layout (bar);
- if (layout_changed (&bar->priv->layout, &layout)) {
+ if (layout_changed (&bar->priv->layout, &layout))
gtk_widget_queue_draw (GTK_WIDGET (bar));
- }
}
static void
update_rms_value (GvcLevelBar *bar)
{
- gdouble val;
-
- val = fraction_from_adjustment (bar, bar->priv->rms_adjustment);
- bar->priv->rms_fraction = val;
+ bar->priv->rms_fraction = fraction_from_adjustment (bar, bar->priv->rms_adjustment);
}
GtkOrientation
gvc_level_bar_get_orientation (GvcLevelBar *bar)
{
g_return_val_if_fail (GVC_IS_LEVEL_BAR (bar), 0);
+
return bar->priv->orientation;
}
@@ -267,9 +277,17 @@ gvc_level_bar_set_orientation (GvcLevelBar *bar,
g_return_if_fail (GVC_IS_LEVEL_BAR (bar));
if (orientation != bar->priv->orientation) {
+ if (G_UNLIKELY (orientation != GTK_ORIENTATION_VERTICAL &&
+ orientation != GTK_ORIENTATION_HORIZONTAL)) {
+ g_warn_if_reached ();
+ return;
+ }
+
bar->priv->orientation = orientation;
+
gtk_widget_queue_draw (GTK_WIDGET (bar));
- g_object_notify (G_OBJECT (bar), "orientation");
+
+ g_object_notify_by_pspec (G_OBJECT (bar), properties[PROP_ORIENTATION]);
}
}
@@ -295,7 +313,7 @@ gvc_level_bar_set_peak_adjustment (GvcLevelBar *bar,
g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
if (bar->priv->peak_adjustment != NULL) {
- g_signal_handlers_disconnect_by_func (bar->priv->peak_adjustment,
+ g_signal_handlers_disconnect_by_func (G_OBJECT (bar->priv->peak_adjustment),
G_CALLBACK (on_peak_adjustment_value_changed),
bar);
g_object_unref (bar->priv->peak_adjustment);
@@ -303,14 +321,14 @@ gvc_level_bar_set_peak_adjustment (GvcLevelBar *bar,
bar->priv->peak_adjustment = g_object_ref_sink (adjustment);
- g_signal_connect (bar->priv->peak_adjustment,
+ g_signal_connect (G_OBJECT (bar->priv->peak_adjustment),
"value-changed",
G_CALLBACK (on_peak_adjustment_value_changed),
bar);
update_peak_value (bar);
- g_object_notify (G_OBJECT (bar), "peak-adjustment");
+ g_object_notify_by_pspec (G_OBJECT (bar), properties[PROP_PEAK_ADJUSTMENT]);
}
void
@@ -321,7 +339,7 @@ gvc_level_bar_set_rms_adjustment (GvcLevelBar *bar,
g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
if (bar->priv->rms_adjustment != NULL) {
- g_signal_handlers_disconnect_by_func (bar->priv->peak_adjustment,
+ g_signal_handlers_disconnect_by_func (G_OBJECT (bar->priv->rms_adjustment),
G_CALLBACK (on_rms_adjustment_value_changed),
bar);
g_object_unref (bar->priv->rms_adjustment);
@@ -329,15 +347,14 @@ gvc_level_bar_set_rms_adjustment (GvcLevelBar *bar,
bar->priv->rms_adjustment = g_object_ref_sink (adjustment);
-
- g_signal_connect (bar->priv->peak_adjustment,
+ g_signal_connect (G_OBJECT (bar->priv->rms_adjustment),
"value-changed",
- G_CALLBACK (on_peak_adjustment_value_changed),
+ G_CALLBACK (on_rms_adjustment_value_changed),
bar);
update_rms_value (bar);
- g_object_notify (G_OBJECT (bar), "rms-adjustment");
+ g_object_notify_by_pspec (G_OBJECT (bar), properties[PROP_RMS_ADJUSTMENT]);
}
GtkAdjustment *
@@ -357,26 +374,30 @@ gvc_level_bar_get_rms_adjustment (GvcLevelBar *bar)
}
void
-gvc_level_bar_set_scale (GvcLevelBar *bar,
- GvcLevelScale scale)
+gvc_level_bar_set_scale (GvcLevelBar *bar, GvcLevelScale scale)
{
g_return_if_fail (GVC_IS_LEVEL_BAR (bar));
if (scale != bar->priv->scale) {
+ if (G_UNLIKELY (scale != GVC_LEVEL_SCALE_LINEAR &&
+ scale != GVC_LEVEL_SCALE_LOG)) {
+ g_warn_if_reached ();
+ return;
+ }
bar->priv->scale = scale;
update_peak_value (bar);
update_rms_value (bar);
- g_object_notify (G_OBJECT (bar), "scale");
+ g_object_notify_by_pspec (G_OBJECT (bar), properties[PROP_SCALE]);
}
}
static void
gvc_level_bar_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
GvcLevelBar *self = GVC_LEVEL_BAR (object);
@@ -401,9 +422,9 @@ gvc_level_bar_set_property (GObject *object,
static void
gvc_level_bar_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
{
GvcLevelBar *self = GVC_LEVEL_BAR (object);
@@ -426,14 +447,6 @@ gvc_level_bar_get_property (GObject *object,
}
}
-static GObject *
-gvc_level_bar_constructor (GType type,
- guint n_construct_properties,
- GObjectConstructParam *construct_params)
-{
- return G_OBJECT_CLASS (gvc_level_bar_parent_class)->constructor (type, n_construct_properties, construct_params);
-}
-
static void
gvc_level_bar_size_request (GtkWidget *widget,
GtkRequisition *requisition)
@@ -447,19 +460,17 @@ gvc_level_bar_size_request (GtkWidget *widget,
switch (bar->priv->orientation) {
case GTK_ORIENTATION_VERTICAL:
- requisition->width = VERTICAL_BAR_WIDTH;
+ requisition->width = VERTICAL_BAR_WIDTH;
requisition->height = MIN_VERTICAL_BAR_HEIGHT;
break;
case GTK_ORIENTATION_HORIZONTAL:
- requisition->width = MIN_HORIZONTAL_BAR_WIDTH;
+ requisition->width = MIN_HORIZONTAL_BAR_WIDTH;
requisition->height = HORIZONTAL_BAR_HEIGHT;
break;
- default:
- g_assert_not_reached ();
- break;
}
}
+#if GTK_CHECK_VERSION (3, 0, 0)
static void
gvc_level_bar_get_preferred_width (GtkWidget *widget,
gint *minimum,
@@ -469,7 +480,10 @@ gvc_level_bar_get_preferred_width (GtkWidget *widget,
gvc_level_bar_size_request (widget, &requisition);
- *minimum = *natural = requisition.width;
+ if (minimum != NULL)
+ *minimum = requisition.width;
+ if (natural != NULL)
+ *natural = requisition.width;
}
static void
@@ -481,18 +495,18 @@ gvc_level_bar_get_preferred_height (GtkWidget *widget,
gvc_level_bar_size_request (widget, &requisition);
- *minimum = *natural = requisition.height;
+ if (minimum != NULL)
+ *minimum = requisition.height;
+ if (natural != NULL)
+ *natural = requisition.height;
}
+#endif
static void
-gvc_level_bar_size_allocate (GtkWidget *widget,
- GtkAllocation *allocation)
+gvc_level_bar_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
{
GvcLevelBar *bar;
- g_return_if_fail (GVC_IS_LEVEL_BAR (widget));
- g_return_if_fail (allocation != NULL);
-
bar = GVC_LEVEL_BAR (widget);
/* FIXME: add height property, labels, etc */
@@ -503,9 +517,9 @@ gvc_level_bar_size_allocate (GtkWidget *widget,
if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
allocation->height = MIN (allocation->height, MIN_VERTICAL_BAR_HEIGHT);
- allocation->width = MAX (allocation->width, VERTICAL_BAR_WIDTH);
+ allocation->width = MAX (allocation->width, VERTICAL_BAR_WIDTH);
} else {
- allocation->width = MIN (allocation->width, MIN_HORIZONTAL_BAR_WIDTH);
+ allocation->width = MIN (allocation->width, MIN_HORIZONTAL_BAR_WIDTH);
allocation->height = MAX (allocation->height, HORIZONTAL_BAR_HEIGHT);
}
@@ -526,9 +540,8 @@ curved_rectangle (cairo_t *cr,
x1 = x0 + width;
y1 = y0 + height;
- if (!width || !height) {
+ if (!width || !height)
return;
- }
if (width / 2 < radius) {
if (height / 2 < radius) {
@@ -541,7 +554,7 @@ curved_rectangle (cairo_t *cr,
cairo_move_to (cr, x0, y0 + radius);
cairo_curve_to (cr, x0, y0, x0, y0, (x0 + x1) / 2, y0);
cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
- cairo_line_to (cr, x1, y1 - radius);
+ cairo_line_to (cr, x1, y1 - radius);
cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1);
cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius);
}
@@ -549,19 +562,19 @@ curved_rectangle (cairo_t *cr,
if (height / 2 < radius) {
cairo_move_to (cr, x0, (y0 + y1) / 2);
cairo_curve_to (cr, x0, y0, x0 , y0, x0 + radius, y0);
- cairo_line_to (cr, x1 - radius, y0);
+ cairo_line_to (cr, x1 - radius, y0);
cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2);
cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
- cairo_line_to (cr, x0 + radius, y1);
+ cairo_line_to (cr, x0 + radius, y1);
cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2);
} else {
cairo_move_to (cr, x0, y0 + radius);
cairo_curve_to (cr, x0 , y0, x0 , y0, x0 + radius, y0);
- cairo_line_to (cr, x1 - radius, y0);
+ cairo_line_to (cr, x1 - radius, y0);
cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
- cairo_line_to (cr, x1, y1 - radius);
+ cairo_line_to (cr, x1, y1 - radius);
cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
- cairo_line_to (cr, x0 + radius, y1);
+ cairo_line_to (cr, x0 + radius, y1);
cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius);
}
}
@@ -570,40 +583,13 @@ curved_rectangle (cairo_t *cr,
}
static int
-#if GTK_CHECK_VERSION (3, 0, 0)
-gvc_level_bar_draw (GtkWidget *widget,
- cairo_t *cr)
-#else
-gvc_level_bar_expose (GtkWidget *widget,
- GdkEventExpose *event)
-#endif
+gvc_level_bar_draw (GtkWidget *widget, cairo_t *cr)
{
- GvcLevelBar *bar;
-#if !GTK_CHECK_VERSION (3, 0, 0)
- cairo_t *cr;
- GtkAllocation allocation;
-#endif
-
- g_return_val_if_fail (GVC_IS_LEVEL_BAR (widget), FALSE);
-#if !GTK_CHECK_VERSION (3, 0, 0)
- g_return_val_if_fail (event != NULL, FALSE);
-
- /* event queue compression */
- if (event->count > 0) {
- return FALSE;
- }
-#endif
+ GvcLevelBar *bar;
bar = GVC_LEVEL_BAR (widget);
-#if !GTK_CHECK_VERSION (3, 0, 0)
- cr = gdk_cairo_create (gtk_widget_get_window (widget));
-
- gtk_widget_get_allocation (widget, &allocation);
- cairo_translate (cr,
- allocation.x,
- allocation.y);
-#endif
+ cairo_save (cr);
if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
int i;
@@ -619,31 +605,68 @@ gvc_level_bar_expose (GtkWidget *widget,
bar->priv->layout.box_radius);
if ((bar->priv->layout.max_peak_num - 1) == i) {
/* fill peak foreground */
- cairo_set_source_rgb (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ gdk_cairo_set_source_rgba (cr, &bar->priv->layout.color_fg);
+#else
+ gdk_cairo_set_source_color (cr, &bar->priv->layout.color_fg);
+#endif
cairo_fill_preserve (cr);
} else if ((bar->priv->layout.peak_num - 1) >= i) {
/* fill background */
- cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ gdk_cairo_set_source_rgba (cr, &bar->priv->layout.color_bg);
+#else
+ gdk_cairo_set_source_color (cr, &bar->priv->layout.color_bg);
+#endif
cairo_fill_preserve (cr);
+
/* fill foreground */
- cairo_set_source_rgba (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b, 0.5);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ cairo_set_source_rgba (cr,
+ bar->priv->layout.color_fg.red,
+ bar->priv->layout.color_fg.green,
+ bar->priv->layout.color_fg.blue,
+ 0.5);
+#else
+ cairo_set_source_rgba (cr,
+ bar->priv->layout.color_fg.red / 65535.0,
+ bar->priv->layout.color_fg.green / 65535.0,
+ bar->priv->layout.color_fg.blue / 65535.0,
+ 0.5);
+#endif
cairo_fill_preserve (cr);
} else {
/* fill background */
- cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ gdk_cairo_set_source_rgba (cr, &bar->priv->layout.color_bg);
+#else
+ gdk_cairo_set_source_color (cr, &bar->priv->layout.color_bg);
+#endif
cairo_fill_preserve (cr);
}
/* stroke border */
- cairo_set_source_rgb (cr, bar->priv->layout.bdr_r, bar->priv->layout.bdr_g, bar->priv->layout.bdr_b);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ gdk_cairo_set_source_rgba (cr, &bar->priv->layout.color_dark);
+#else
+ gdk_cairo_set_source_color (cr, &bar->priv->layout.color_dark);
+#endif
cairo_set_line_width (cr, 1);
cairo_stroke (cr);
}
-
} else {
int i;
int bx;
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) {
+ GtkAllocation allocation;
+
+ gtk_widget_get_allocation (widget, &allocation);
+
+ cairo_scale (cr, -1, 1);
+ cairo_translate (cr, -allocation.width, 0);
+ }
+
for (i = 0; i < NUM_BOXES; i++) {
bx = i * bar->priv->layout.delta;
curved_rectangle (cr,
@@ -655,33 +678,88 @@ gvc_level_bar_expose (GtkWidget *widget,
if ((bar->priv->layout.max_peak_num - 1) == i) {
/* fill peak foreground */
- cairo_set_source_rgb (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ gdk_cairo_set_source_rgba (cr, &bar->priv->layout.color_fg);
+#else
+ gdk_cairo_set_source_color (cr, &bar->priv->layout.color_fg);
+#endif
cairo_fill_preserve (cr);
} else if ((bar->priv->layout.peak_num - 1) >= i) {
/* fill background */
- cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ gdk_cairo_set_source_rgba (cr, &bar->priv->layout.color_bg);
+#else
+ gdk_cairo_set_source_color (cr, &bar->priv->layout.color_bg);
+#endif
cairo_fill_preserve (cr);
+
/* fill foreground */
- cairo_set_source_rgba (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b, 0.5);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ cairo_set_source_rgba (cr,
+ bar->priv->layout.color_fg.red,
+ bar->priv->layout.color_fg.green,
+ bar->priv->layout.color_fg.blue,
+ 0.5);
+#else
+ cairo_set_source_rgba (cr,
+ bar->priv->layout.color_fg.red / 65535.0,
+ bar->priv->layout.color_fg.green / 65535.0,
+ bar->priv->layout.color_fg.blue / 65535.0,
+ 0.5);
+#endif
cairo_fill_preserve (cr);
} else {
/* fill background */
- cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ gdk_cairo_set_source_rgba (cr, &bar->priv->layout.color_bg);
+#else
+ gdk_cairo_set_source_color (cr, &bar->priv->layout.color_bg);
+#endif
cairo_fill_preserve (cr);
}
/* stroke border */
- cairo_set_source_rgb (cr, bar->priv->layout.bdr_r, bar->priv->layout.bdr_g, bar->priv->layout.bdr_b);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ gdk_cairo_set_source_rgba (cr, &bar->priv->layout.color_dark);
+#else
+ gdk_cairo_set_source_color (cr, &bar->priv->layout.color_dark);
+#endif
cairo_set_line_width (cr, 1);
cairo_stroke (cr);
}
}
+
+ cairo_restore (cr);
+
+ return FALSE;
+}
+
#if !GTK_CHECK_VERSION (3, 0, 0)
- cairo_destroy (cr);
-#endif
+static int
+gvc_level_bar_expose (GtkWidget *widget, GdkEventExpose *event)
+{
+ cairo_t *cr;
+ GtkAllocation allocation;
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ /* Event queue compression */
+ if (event->count > 0)
+ return FALSE;
+
+ gtk_widget_get_allocation (widget, &allocation);
+
+ cr = gdk_cairo_create (gtk_widget_get_window (widget));
+ cairo_translate (cr,
+ allocation.x,
+ allocation.y);
+
+ gvc_level_bar_draw (widget, cr);
+
+ cairo_destroy (cr);
return FALSE;
}
+#endif
static void
gvc_level_bar_class_init (GvcLevelBarClass *klass)
@@ -689,7 +767,6 @@ gvc_level_bar_class_init (GvcLevelBarClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- object_class->constructor = gvc_level_bar_constructor;
object_class->finalize = gvc_level_bar_finalize;
object_class->set_property = gvc_level_bar_set_property;
object_class->get_property = gvc_level_bar_get_property;
@@ -704,37 +781,43 @@ gvc_level_bar_class_init (GvcLevelBarClass *klass)
#endif
widget_class->size_allocate = gvc_level_bar_size_allocate;
- g_object_class_install_property (object_class,
- PROP_ORIENTATION,
- g_param_spec_enum ("orientation",
- "Orientation",
- "The orientation of the bar",
- GTK_TYPE_ORIENTATION,
- GTK_ORIENTATION_HORIZONTAL,
- G_PARAM_READWRITE));
- g_object_class_install_property (object_class,
- PROP_PEAK_ADJUSTMENT,
- g_param_spec_object ("peak-adjustment",
- "Peak Adjustment",
- "The GtkAdjustment that contains the current peak value",
- GTK_TYPE_ADJUSTMENT,
- G_PARAM_READWRITE));
- g_object_class_install_property (object_class,
- PROP_RMS_ADJUSTMENT,
- g_param_spec_object ("rms-adjustment",
- "RMS Adjustment",
- "The GtkAdjustment that contains the current rms value",
- GTK_TYPE_ADJUSTMENT,
- G_PARAM_READWRITE));
- g_object_class_install_property (object_class,
- PROP_SCALE,
- g_param_spec_int ("scale",
- "Scale",
- "Scale",
- 0,
- G_MAXINT,
- GVC_LEVEL_SCALE_LINEAR,
- G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ properties[PROP_ORIENTATION] =
+ g_param_spec_enum ("orientation",
+ "Orientation",
+ "The orientation of the bar",
+ GTK_TYPE_ORIENTATION,
+ GTK_ORIENTATION_HORIZONTAL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_PEAK_ADJUSTMENT] =
+ g_param_spec_object ("peak-adjustment",
+ "Peak Adjustment",
+ "The GtkAdjustment that contains the current peak value",
+ GTK_TYPE_ADJUSTMENT,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_RMS_ADJUSTMENT] =
+ g_param_spec_object ("rms-adjustment",
+ "RMS Adjustment",
+ "The GtkAdjustment that contains the current rms value",
+ GTK_TYPE_ADJUSTMENT,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_SCALE] =
+ g_param_spec_int ("scale",
+ "Scale",
+ "Scale",
+ 0,
+ G_MAXINT,
+ GVC_LEVEL_SCALE_LINEAR,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
g_type_class_add_private (klass, sizeof (GvcLevelBarPrivate));
}
@@ -751,6 +834,7 @@ gvc_level_bar_init (GvcLevelBar *bar)
0.1,
0.1));
g_object_ref_sink (bar->priv->peak_adjustment);
+
g_signal_connect (bar->priv->peak_adjustment,
"value-changed",
G_CALLBACK (on_peak_adjustment_value_changed),
@@ -763,6 +847,7 @@ gvc_level_bar_init (GvcLevelBar *bar)
0.1,
0.1));
g_object_ref_sink (bar->priv->rms_adjustment);
+
g_signal_connect (bar->priv->rms_adjustment,
"value-changed",
G_CALLBACK (on_rms_adjustment_value_changed),
@@ -776,16 +861,10 @@ gvc_level_bar_finalize (GObject *object)
{
GvcLevelBar *bar;
- g_return_if_fail (object != NULL);
- g_return_if_fail (GVC_IS_LEVEL_BAR (object));
-
bar = GVC_LEVEL_BAR (object);
- if (bar->priv->max_peak_id > 0) {
+ if (bar->priv->max_peak_id > 0)
g_source_remove (bar->priv->max_peak_id);
- }
-
- g_return_if_fail (bar->priv != NULL);
G_OBJECT_CLASS (gvc_level_bar_parent_class)->finalize (object);
}
@@ -793,8 +872,5 @@ gvc_level_bar_finalize (GObject *object)
GtkWidget *
gvc_level_bar_new (void)
{
- GObject *bar;
- bar = g_object_new (GVC_TYPE_LEVEL_BAR,
- NULL);
- return GTK_WIDGET (bar);
+ return g_object_new (GVC_TYPE_LEVEL_BAR, NULL);
}
diff --git a/mate-volume-control/src/gvc-level-bar.h b/mate-volume-control/src/gvc-level-bar.h
index 844d0f9..ef9ae7e 100644
--- a/mate-volume-control/src/gvc-level-bar.h
+++ b/mate-volume-control/src/gvc-level-bar.h
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 William Jon McCann <[email protected]>
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
*
* 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
@@ -21,6 +22,7 @@
#ifndef __GVC_LEVEL_BAR_H
#define __GVC_LEVEL_BAR_H
+#include <glib.h>
#include <glib-object.h>
#include <gtk/gtk.h>
@@ -33,35 +35,28 @@ G_BEGIN_DECLS
#define GVC_IS_LEVEL_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_LEVEL_BAR))
#define GVC_LEVEL_BAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_LEVEL_BAR, GvcLevelBarClass))
-typedef struct GvcLevelBarPrivate GvcLevelBarPrivate;
+typedef struct _GvcLevelBar GvcLevelBar;
+typedef struct _GvcLevelBarClass GvcLevelBarClass;
+typedef struct _GvcLevelBarPrivate GvcLevelBarPrivate;
-typedef struct
+struct _GvcLevelBar
{
-#if GTK_CHECK_VERSION (3, 0, 0)
- GtkBox parent;
-#else
- GtkHBox parent;
-#endif
- GvcLevelBarPrivate *priv;
-} GvcLevelBar;
+ GtkWidget parent;
+ GvcLevelBarPrivate *priv;
+};
-typedef struct
+struct _GvcLevelBarClass
{
-#if GTK_CHECK_VERSION (3, 0, 0)
- GtkBoxClass parent_class;
-#else
- GtkHBoxClass parent_class;
-#endif
-} GvcLevelBarClass;
+ GtkWidgetClass parent_class;
+};
typedef enum
{
GVC_LEVEL_SCALE_LINEAR,
- GVC_LEVEL_SCALE_LOG,
- GVC_LEVEL_SCALE_LAST
+ GVC_LEVEL_SCALE_LOG
} GvcLevelScale;
-GType gvc_level_bar_get_type (void);
+GType gvc_level_bar_get_type (void) G_GNUC_CONST;
GtkWidget * gvc_level_bar_new (void);
void gvc_level_bar_set_orientation (GvcLevelBar *bar,
@@ -71,13 +66,14 @@ GtkOrientation gvc_level_bar_get_orientation (GvcLevelBar *bar);
void gvc_level_bar_set_peak_adjustment (GvcLevelBar *bar,
GtkAdjustment *adjustment);
GtkAdjustment * gvc_level_bar_get_peak_adjustment (GvcLevelBar *bar);
+
void gvc_level_bar_set_rms_adjustment (GvcLevelBar *bar,
GtkAdjustment *adjustment);
GtkAdjustment * gvc_level_bar_get_rms_adjustment (GvcLevelBar *bar);
+
void gvc_level_bar_set_scale (GvcLevelBar *bar,
GvcLevelScale scale);
-
G_END_DECLS
#endif /* __GVC_LEVEL_BAR_H */
diff --git a/mate-volume-control/src/gvc-mixer-dialog.c b/mate-volume-control/src/gvc-mixer-dialog.c
index e46ca1a..9b524fe 100644
--- a/mate-volume-control/src/gvc-mixer-dialog.c
+++ b/mate-volume-control/src/gvc-mixer-dialog.c
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 William Jon McCann
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
*
* 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
@@ -22,11 +23,11 @@
#include <glib.h>
#include <glib/gi18n.h>
+#include <glib-object.h>
+#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
-#if GTK_CHECK_VERSION (3, 0, 0)
-#include <gdk/gdkkeysyms-compat.h>
-#endif
+#include <libmatemixer/matemixer.h>
#include "gvc-channel-bar.h"
#include "gvc-balance-bar.h"
@@ -57,9 +58,10 @@ struct _GvcMixerDialogPrivate
GtkWidget *input_box;
GtkWidget *output_box;
GtkWidget *applications_box;
- GtkWidget *applications_scrolled_window;
+ GtkWidget *applications_window;
GtkWidget *no_apps_label;
GtkWidget *output_treeview;
+ GtkWidget *output_settings_frame;
GtkWidget *output_settings_box;
GtkWidget *output_balance_bar;
GtkWidget *output_fade_bar;
@@ -70,7 +72,6 @@ struct _GvcMixerDialogPrivate
GtkWidget *input_settings_box;
GtkWidget *sound_theme_chooser;
GtkSizeGroup *size_group;
- GtkSizeGroup *apps_size_group;
gdouble last_input_peak;
guint num_apps;
};
@@ -79,7 +80,6 @@ enum {
ICON_COLUMN,
NAME_COLUMN,
DESCRIPTION_COLUMN,
- DEVICE_COLUMN,
ACTIVE_COLUMN,
SPEAKERS_COLUMN,
NUM_COLUMNS
@@ -91,212 +91,292 @@ enum {
HW_DESCRIPTION_COLUMN,
HW_STATUS_COLUMN,
HW_PROFILE_COLUMN,
- HW_PROFILE_HUMAN_COLUMN,
- HW_SENSITIVE_COLUMN,
HW_NUM_COLUMNS
};
enum {
- PAGE_EVENTS,
+ PAGE_EFFECTS,
PAGE_HARDWARE,
PAGE_INPUT,
PAGE_OUTPUT,
PAGE_APPLICATIONS
};
-enum
-{
+enum {
PROP_0,
- PROP_MIXER_CONTROL
+ PROP_CONTROL
};
-static void gvc_mixer_dialog_class_init (GvcMixerDialogClass *klass);
-static void gvc_mixer_dialog_init (GvcMixerDialog *mixer_dialog);
-static void gvc_mixer_dialog_finalize (GObject *object);
+static const guint tab_accel_keys[] = {
+ GDK_KEY_1, GDK_KEY_2, GDK_KEY_3, GDK_KEY_4, GDK_KEY_5
+};
-static void bar_set_stream (GvcMixerDialog *dialog,
- GtkWidget *bar,
- MateMixerStream *stream);
+static void gvc_mixer_dialog_class_init (GvcMixerDialogClass *klass);
+static void gvc_mixer_dialog_init (GvcMixerDialog *dialog);
+static void gvc_mixer_dialog_finalize (GObject *object);
-static void on_adjustment_value_changed (GtkAdjustment *adjustment,
- GvcMixerDialog *dialog);
+static void bar_set_stream (GvcMixerDialog *dialog,
+ GtkWidget *bar,
+ MateMixerStream *stream);
G_DEFINE_TYPE (GvcMixerDialog, gvc_mixer_dialog, GTK_TYPE_DIALOG)
-static void
-update_default_input (GvcMixerDialog *dialog)
+static gboolean
+find_tree_item_by_name (GtkTreeModel *model,
+ const gchar *name,
+ guint column,
+ GtkTreeIter *iter)
{
- GtkTreeModel *model;
- GtkTreeIter iter;
- gboolean ret;
+ gboolean found = FALSE;
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
- ret = gtk_tree_model_get_iter_first (model, &iter);
- if (ret == FALSE) {
- g_debug ("No default input selected or available");
- return;
- }
- do {
- gboolean toggled;
- gboolean is_default = FALSE;
- MateMixerStream *stream;
- gchar *name;
+ if (!gtk_tree_model_get_iter_first (model, iter))
+ return FALSE;
- gtk_tree_model_get (model, &iter,
- NAME_COLUMN, &name,
- ACTIVE_COLUMN, &toggled,
- -1);
+ do {
+ gchar *n;
- stream = mate_mixer_control_get_stream (dialog->priv->control, name);
- if (stream == NULL) {
- g_warning ("Unable to find stream for id: %s", name);
- g_free (name);
- continue;
- }
+ gtk_tree_model_get (model, iter, column, &n, -1);
- if (stream == mate_mixer_control_get_default_input_stream (dialog->priv->control))
- is_default = TRUE;
+ if (!g_strcmp0 (name, n))
+ found = TRUE;
- gtk_list_store_set (GTK_LIST_STORE (model),
- &iter,
- ACTIVE_COLUMN, is_default,
- -1);
+ g_free (n);
+ } while (!found && gtk_tree_model_iter_next (model, iter));
- g_free (name);
- } while (gtk_tree_model_iter_next (model, &iter));
+ return found;
}
static void
-update_description (GvcMixerDialog *dialog,
- guint column,
- const gchar *value,
- MateMixerStream *stream)
+update_default_item (GvcMixerDialog *dialog,
+ GtkTreeModel *model,
+ MateMixerStream *stream)
{
- GtkTreeModel *model;
- GtkTreeIter iter;
- MateMixerStreamFlags flags;
- const gchar *name;
-
- flags = mate_mixer_stream_get_flags (stream);
+ GtkTreeIter iter;
+ const gchar *name = NULL;
- if (flags & MATE_MIXER_STREAM_INPUT)
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
- else if (flags & MATE_MIXER_STREAM_OUTPUT)
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
- else
- g_assert_not_reached ();
+ if (gtk_tree_model_get_iter_first (model, &iter) == FALSE)
+ return;
- gtk_tree_model_get_iter_first (model, &iter);
+ /* The supplied stream is the default, or the selected item. Traverse
+ * the item list and mark each item as being selected or not. Also do not
+ * presume some known stream is selected and allow NULL here. */
+ if (stream != NULL)
+ name = mate_mixer_stream_get_name (stream);
- name = mate_mixer_stream_get_name (stream);
do {
- const gchar *current_name;
-
- gtk_tree_model_get (model, &iter, NAME_COLUMN, &current_name, -1);
- if (!g_strcmp0 (name, current_name))
- continue;
+ gchar *n;
+ gtk_tree_model_get (model, &iter,
+ NAME_COLUMN, &n,
+ -1);
gtk_list_store_set (GTK_LIST_STORE (model),
&iter,
- column, value,
+ ACTIVE_COLUMN, !g_strcmp0 (name, n),
-1);
- break;
+ g_free (n);
} while (gtk_tree_model_iter_next (model, &iter));
}
static void
-port_selection_changed (GvcComboBox *combo,
- const gchar *port,
- GvcMixerDialog *dialog)
+on_combo_box_port_changed (GvcComboBox *combo,
+ const gchar *name,
+ GvcMixerDialog *dialog)
{
MateMixerStream *stream;
+ MateMixerPort *port = NULL;
+ GList *ports;
stream = g_object_get_data (G_OBJECT (combo), "stream");
- if (stream == NULL) {
- g_warning ("Could not find stream for port combo box");
+ if (G_UNLIKELY (stream == NULL)) {
+ g_warn_if_reached ();
+ return;
+ }
+
+ ports = (GList *) mate_mixer_stream_list_ports (stream);
+ while (ports) {
+ port = MATE_MIXER_PORT (ports->data);
+
+ if (!g_strcmp0 (mate_mixer_port_get_name (port), name))
+ break;
+
+ port = NULL;
+ ports = ports->next;
+ }
+
+ if (G_UNLIKELY (port == NULL)) {
+ g_warn_if_reached ();
return;
}
+ g_debug ("Stream port changed to %s for stream %s",
+ name,
+ mate_mixer_stream_get_name (stream));
+
mate_mixer_stream_set_active_port (stream, port);
}
static void
+on_combo_box_profile_changed (GvcComboBox *combo,
+ const gchar *name,
+ GvcMixerDialog *dialog)
+{
+ MateMixerDevice *device;
+ MateMixerDeviceProfile *profile = NULL;
+ GList *profiles;
+
+ device = g_object_get_data (G_OBJECT (combo), "device");
+ if (G_UNLIKELY (device == NULL)) {
+ g_warn_if_reached ();
+ return;
+ }
+
+ profiles = (GList *) mate_mixer_device_list_profiles (device);
+ while (profiles) {
+ profile = MATE_MIXER_DEVICE_PROFILE (profiles->data);
+
+ if (!g_strcmp0 (mate_mixer_device_profile_get_name (profile), name))
+ break;
+
+ profile = NULL;
+ profiles = profiles->next;
+ }
+
+ if (G_UNLIKELY (profile == NULL)) {
+ g_warn_if_reached ();
+ return;
+ }
+
+ g_debug ("Device profile changed to %s for device %s",
+ name,
+ mate_mixer_device_get_name (device));
+
+ mate_mixer_device_set_active_profile (device, profile);
+}
+
+static GtkWidget *
+create_port_combo_box (GvcMixerDialog *dialog,
+ MateMixerStream *stream,
+ const gchar *name,
+ const GList *items,
+ const gchar *active)
+{
+ GtkWidget *combobox;
+
+ combobox = gvc_combo_box_new (name);
+
+ gvc_combo_box_set_ports (GVC_COMBO_BOX (combobox), items);
+ gvc_combo_box_set_active (GVC_COMBO_BOX (combobox), active);
+
+ gvc_combo_box_set_size_group (GVC_COMBO_BOX (combobox),
+ dialog->priv->size_group,
+ FALSE);
+
+ g_object_set_data_full (G_OBJECT (combobox),
+ "stream",
+ g_object_ref (stream),
+ g_object_unref);
+
+ g_signal_connect (G_OBJECT (combobox),
+ "changed",
+ G_CALLBACK (on_combo_box_port_changed),
+ dialog);
+
+ return combobox;
+}
+
+static void
update_output_settings (GvcMixerDialog *dialog)
{
MateMixerStream *stream;
MateMixerStreamFlags flags;
const GList *ports;
+ gboolean has_settings = FALSE;
g_debug ("Updating output settings");
+
if (dialog->priv->output_balance_bar != NULL) {
gtk_container_remove (GTK_CONTAINER (dialog->priv->output_settings_box),
dialog->priv->output_balance_bar);
+
dialog->priv->output_balance_bar = NULL;
}
if (dialog->priv->output_fade_bar != NULL) {
gtk_container_remove (GTK_CONTAINER (dialog->priv->output_settings_box),
dialog->priv->output_fade_bar);
+
dialog->priv->output_fade_bar = NULL;
}
if (dialog->priv->output_lfe_bar != NULL) {
gtk_container_remove (GTK_CONTAINER (dialog->priv->output_settings_box),
dialog->priv->output_lfe_bar);
+
dialog->priv->output_lfe_bar = NULL;
}
if (dialog->priv->output_port_combo != NULL) {
gtk_container_remove (GTK_CONTAINER (dialog->priv->output_settings_box),
dialog->priv->output_port_combo);
+
dialog->priv->output_port_combo = NULL;
}
stream = mate_mixer_control_get_default_output_stream (dialog->priv->control);
if (stream == NULL) {
- g_warning ("Default sink stream not found");
+ g_debug ("There is no default output stream - output settings disabled");
+ gtk_widget_hide (dialog->priv->output_settings_frame);
return;
}
flags = mate_mixer_stream_get_flags (stream);
- gvc_channel_bar_set_base_volume (GVC_CHANNEL_BAR (dialog->priv->output_bar),
- mate_mixer_stream_get_base_volume (stream));
- gvc_channel_bar_set_is_amplified (GVC_CHANNEL_BAR (dialog->priv->output_bar),
- flags & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME);
+ /* Enable balance bar if stream feature is available */
+ if (flags & MATE_MIXER_STREAM_CAN_BALANCE) {
+ dialog->priv->output_balance_bar =
+ gvc_balance_bar_new (stream, BALANCE_TYPE_RL);
- dialog->priv->output_balance_bar = gvc_balance_bar_new (stream, BALANCE_TYPE_RL);
- if (dialog->priv->size_group != NULL) {
gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (dialog->priv->output_balance_bar),
dialog->priv->size_group,
TRUE);
+
+ gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box),
+ dialog->priv->output_balance_bar,
+ FALSE, FALSE, 6);
+
+ gtk_widget_show (dialog->priv->output_balance_bar);
+ has_settings = TRUE;
}
- gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box),
- dialog->priv->output_balance_bar,
- FALSE, FALSE, 6);
- gtk_widget_show (dialog->priv->output_balance_bar);
+ /* Enable fade bar if stream feature is available */
if (flags & MATE_MIXER_STREAM_CAN_FADE) {
- dialog->priv->output_fade_bar = gvc_balance_bar_new (stream, BALANCE_TYPE_FR);
- if (dialog->priv->size_group != NULL) {
- gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (dialog->priv->output_fade_bar),
- dialog->priv->size_group,
- TRUE);
- }
+ dialog->priv->output_fade_bar =
+ gvc_balance_bar_new (stream, BALANCE_TYPE_FR);
+
+ gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (dialog->priv->output_fade_bar),
+ dialog->priv->size_group,
+ TRUE);
+
gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box),
dialog->priv->output_fade_bar,
FALSE, FALSE, 6);
+
gtk_widget_show (dialog->priv->output_fade_bar);
+ has_settings = TRUE;
}
- if (mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_LFE)) {
- dialog->priv->output_lfe_bar = gvc_balance_bar_new (stream, BALANCE_TYPE_LFE);
- if (dialog->priv->size_group != NULL) {
- gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (dialog->priv->output_lfe_bar),
- dialog->priv->size_group,
- TRUE);
- }
+ /* Enable subwoofer volume bar if subwoofer is available */
+ if (mate_mixer_stream_has_channel_position (stream, MATE_MIXER_CHANNEL_LFE)) {
+ dialog->priv->output_lfe_bar =
+ gvc_balance_bar_new (stream, BALANCE_TYPE_LFE);
+
+ gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (dialog->priv->output_lfe_bar),
+ dialog->priv->size_group,
+ TRUE);
+
gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box),
dialog->priv->output_lfe_bar,
FALSE, FALSE, 6);
+
gtk_widget_show (dialog->priv->output_lfe_bar);
+ has_settings = TRUE;
}
ports = mate_mixer_stream_list_ports (stream);
@@ -304,180 +384,149 @@ update_output_settings (GvcMixerDialog *dialog)
MateMixerPort *port;
port = mate_mixer_stream_get_active_port (stream);
+ if (G_UNLIKELY (port == NULL)) {
+ /* Select the first port if none is selected at the moment */
+ port = MATE_MIXER_PORT (ports->data);
+ mate_mixer_stream_set_active_port (stream, port);
+ }
- dialog->priv->output_port_combo = gvc_combo_box_new (_("Co_nnector:"));
- gvc_combo_box_set_ports (GVC_COMBO_BOX (dialog->priv->output_port_combo),
- ports);
-
- gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->output_port_combo),
- mate_mixer_port_get_name (port));
-
- g_object_set_data (G_OBJECT (dialog->priv->output_port_combo), "stream", stream);
- g_signal_connect (G_OBJECT (dialog->priv->output_port_combo), "changed",
- G_CALLBACK (port_selection_changed), dialog);
+ dialog->priv->output_port_combo =
+ create_port_combo_box (dialog,
+ stream,
+ _("Co_nnector:"),
+ ports,
+ mate_mixer_port_get_name (port));
gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box),
dialog->priv->output_port_combo,
TRUE, FALSE, 6);
- gvc_combo_box_set_size_group (GVC_COMBO_BOX (dialog->priv->output_port_combo), dialog->priv->size_group, FALSE);
-
gtk_widget_show (dialog->priv->output_port_combo);
+ has_settings = TRUE;
}
- /* FIXME: We could make this into a "No settings" label instead */
- gtk_widget_set_sensitive (dialog->priv->output_balance_bar, flags & MATE_MIXER_STREAM_CAN_BALANCE);
+ if (has_settings == TRUE)
+ gtk_widget_show (dialog->priv->output_settings_frame);
+ else
+ gtk_widget_hide (dialog->priv->output_settings_frame);
}
static void
-update_default_output (GvcMixerDialog *dialog)
+on_control_default_output_notify (MateMixerControl *control,
+ GParamSpec *pspec,
+ GvcMixerDialog *dialog)
{
- GtkTreeModel *model;
- GtkTreeIter iter;
-
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
- gtk_tree_model_get_iter_first (model, &iter);
- do {
- gboolean toggled;
- gboolean is_default = FALSE;
- gchar *name;
- MateMixerStream *stream;
+ GtkTreeModel *model;
+ MateMixerStream *stream;
- gtk_tree_model_get (model, &iter,
- NAME_COLUMN, &name,
- ACTIVE_COLUMN, &toggled,
- -1);
+ stream = mate_mixer_control_get_default_output_stream (control);
+ if (stream != NULL) {
+ GList *streams;
- stream = mate_mixer_control_get_stream (dialog->priv->control, name);
- if (stream == NULL) {
- g_warning ("Unable to find stream for id: %s", name);
- g_free (name);
- continue;
- }
+ streams = (GList *) mate_mixer_control_list_cached_streams (dialog->priv->control);
- if (stream == mate_mixer_control_get_default_output_stream (dialog->priv->control))
- is_default = TRUE;
+ /* Move all cached stream to the newly selected default stream */
+ while (streams) {
+ MateMixerStream *parent;
+ MateMixerClientStream *client = MATE_MIXER_CLIENT_STREAM (streams->data);
- gtk_list_store_set (GTK_LIST_STORE (model),
- &iter,
- ACTIVE_COLUMN, is_default,
- -1);
- g_free (name);
- } while (gtk_tree_model_iter_next (model, &iter));
-}
+ parent = mate_mixer_client_stream_get_parent (client);
-static void
-on_control_default_output_notify (MateMixerControl *control,
- GParamSpec *pspec,
- GvcMixerDialog *dialog)
-{
- MateMixerStream *stream;
+ if (parent != stream) {
+ MateMixerStreamFlags flags;
- g_debug ("Default output stream has changed");
+ flags = mate_mixer_stream_get_flags (MATE_MIXER_STREAM (client));
- stream = mate_mixer_control_get_default_output_stream (control);
+ if (flags & MATE_MIXER_STREAM_OUTPUT)
+ mate_mixer_client_stream_set_parent (client, stream);
+ }
+ streams = streams->next;
+ }
+ }
bar_set_stream (dialog, dialog->priv->output_bar, stream);
- update_output_settings (dialog);
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
+ update_default_item (dialog, model, stream);
- update_default_output (dialog);
+ update_output_settings (dialog);
}
-
#define DECAY_STEP .15
static void
-update_input_peak (GvcMixerDialog *dialog, gdouble v)
+on_stream_monitor_value (MateMixerStream *stream,
+ gdouble value,
+ GvcMixerDialog *dialog)
{
GtkAdjustment *adj;
if (dialog->priv->last_input_peak >= DECAY_STEP) {
- if (v < dialog->priv->last_input_peak - DECAY_STEP) {
- v = dialog->priv->last_input_peak - DECAY_STEP;
+ if (value < dialog->priv->last_input_peak - DECAY_STEP) {
+ value = dialog->priv->last_input_peak - DECAY_STEP;
}
}
- dialog->priv->last_input_peak = v;
+ dialog->priv->last_input_peak = value;
adj = gvc_level_bar_get_peak_adjustment (GVC_LEVEL_BAR (dialog->priv->input_level_bar));
- if (v >= 0) {
- gtk_adjustment_set_value (adj, v);
- } else {
+ if (value >= 0)
+ gtk_adjustment_set_value (adj, value);
+ else
gtk_adjustment_set_value (adj, 0.0);
- }
-}
-
-static void
-on_stream_monitor_value (MateMixerStream *stream,
- gdouble value,
- GvcMixerDialog *dialog)
-{
- g_debug ("Monitor %.2f", value);
- update_input_peak (dialog, value);
}
static void
update_input_settings (GvcMixerDialog *dialog)
{
- MateMixerStream *stream;
+ MateMixerStream *stream;
MateMixerStreamFlags flags;
- const GList *ports;
+ const GList *ports;
g_debug ("Updating input settings");
if (dialog->priv->input_port_combo != NULL) {
gtk_container_remove (GTK_CONTAINER (dialog->priv->input_settings_box),
dialog->priv->input_port_combo);
+
dialog->priv->input_port_combo = NULL;
}
stream = mate_mixer_control_get_default_input_stream (dialog->priv->control);
if (stream == NULL) {
- g_debug ("Default source stream not found");
+ g_debug ("There is no default input stream");
return;
}
- mate_mixer_stream_monitor_set_name (stream, _("Peak detect"));
-
- g_signal_connect (G_OBJECT (stream),
- "monitor-value",
- G_CALLBACK (on_stream_monitor_value),
- dialog);
-
flags = mate_mixer_stream_get_flags (stream);
- gvc_channel_bar_set_base_volume (GVC_CHANNEL_BAR (dialog->priv->input_bar),
- mate_mixer_stream_get_base_volume (stream));
+ /* Enable level bar only if supported by the stream */
+ if (flags & MATE_MIXER_STREAM_HAS_MONITOR) {
+ mate_mixer_stream_monitor_set_name (stream, _("Peak detect"));
- // XXX probably wrong
- gvc_channel_bar_set_is_amplified (GVC_CHANNEL_BAR (dialog->priv->input_bar),
- flags & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME);
+ g_signal_connect (G_OBJECT (stream),
+ "monitor-value",
+ G_CALLBACK (on_stream_monitor_value),
+ dialog);
+ }
ports = mate_mixer_stream_list_ports (stream);
if (ports != NULL) {
MateMixerPort *port;
port = mate_mixer_stream_get_active_port (stream);
+ if (G_UNLIKELY (port == NULL)) {
+ /* Select the first port if none is selected at the moment */
+ port = MATE_MIXER_PORT (ports->data);
+ mate_mixer_stream_set_active_port (stream, port);
+ }
- dialog->priv->input_port_combo = gvc_combo_box_new (_("Co_nnector:"));
- gvc_combo_box_set_ports (GVC_COMBO_BOX (dialog->priv->input_port_combo),
- ports);
- gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->input_port_combo),
- mate_mixer_port_get_name (port));
-
- g_object_set_data (G_OBJECT (dialog->priv->input_port_combo),
- "stream",
- stream);
-
- g_signal_connect (G_OBJECT (dialog->priv->input_port_combo),
- "changed",
- G_CALLBACK (port_selection_changed),
- dialog);
-
- gvc_combo_box_set_size_group (GVC_COMBO_BOX (dialog->priv->input_port_combo),
- dialog->priv->size_group,
- FALSE);
+ dialog->priv->input_port_combo =
+ create_port_combo_box (dialog,
+ stream,
+ _("Co_nnector:"),
+ ports,
+ mate_mixer_port_get_name (port));
gtk_box_pack_start (GTK_BOX (dialog->priv->input_settings_box),
dialog->priv->input_port_combo,
@@ -492,361 +541,332 @@ on_control_default_input_notify (MateMixerControl *control,
GParamSpec *pspec,
GvcMixerDialog *dialog)
{
+ GtkTreeModel *model;
MateMixerStream *stream;
MateMixerStream *current;
- GtkAdjustment *adj;
- stream = mate_mixer_control_get_default_input_stream (control);
+ g_debug ("Default input stream has changed");
- current = g_object_get_data (G_OBJECT (dialog->priv->input_bar), "gvc-mixer-dialog-stream");
- if (current != NULL)
+ current = gvc_channel_bar_get_stream (GVC_CHANNEL_BAR (dialog->priv->input_bar));
+ if (current != NULL) {
+ /* Make sure to disable monitoring of the removed stream */
g_signal_handlers_disconnect_by_func (G_OBJECT (current),
- on_stream_monitor_value,
+ G_CALLBACK (on_stream_monitor_value),
dialog);
- if (gtk_notebook_get_current_page (GTK_NOTEBOOK (dialog->priv->notebook)) == PAGE_INPUT) {
- if (current != NULL)
- mate_mixer_stream_monitor_stop (current);
- if (stream != NULL)
- mate_mixer_stream_monitor_start (stream);
+ mate_mixer_stream_monitor_stop (current);
}
- // g_debug ("GvcMixerDialog: default source changed: %u", id);
-
- // XXX is the default input reffed/unreffed anywhere?
-
- /* Disconnect the adj, otherwise it might change if is_amplified changes */
- adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->input_bar)));
-
- g_signal_handlers_disconnect_by_func (adj,
- on_adjustment_value_changed,
- dialog);
-
- bar_set_stream (dialog, dialog->priv->input_bar, stream);
- update_input_settings (dialog);
-
- g_signal_connect (adj,
- "value-changed",
- G_CALLBACK (on_adjustment_value_changed),
- dialog);
+ stream = mate_mixer_control_get_default_input_stream (control);
+ if (stream != NULL) {
+ GList *streams;
+ guint page = gtk_notebook_get_current_page (GTK_NOTEBOOK (dialog->priv->notebook));
- update_default_input (dialog);
-}
+ streams = (GList *) mate_mixer_control_list_cached_streams (dialog->priv->control);
-static void
-on_adjustment_value_changed (GtkAdjustment *adjustment,
- GvcMixerDialog *dialog)
-{
- MateMixerStream *stream;
+ /* Move all cached stream to the newly selected default stream */
+ while (streams) {
+ MateMixerStream *parent;
+ MateMixerClientStream *client = MATE_MIXER_CLIENT_STREAM (streams->data);
- stream = g_object_get_data (G_OBJECT (adjustment), "gvc-mixer-dialog-stream");
- if (stream != NULL) {
- GObject *bar;
- gdouble volume, rounded;
- char *name;
+ parent = mate_mixer_client_stream_get_parent (client);
- volume = gtk_adjustment_get_value (adjustment);
- rounded = round (volume);
+ if (parent != stream) {
+ MateMixerStreamFlags flags;
- bar = g_object_get_data (G_OBJECT (adjustment), "gvc-mixer-dialog-bar");
- g_object_get (bar, "name", &name, NULL);
- g_debug ("Setting stream volume %lf (rounded: %lf) for bar '%s'", volume, rounded, name);
- g_free (name);
+ flags = mate_mixer_stream_get_flags (MATE_MIXER_STREAM (client));
- /* FIXME would need to do that in the balance bar really... */
- /* Make sure we do not unmute muted streams, there's a button for that */
- if (volume == 0.0)
- mate_mixer_stream_set_mute (stream, TRUE);
+ if (flags & MATE_MIXER_STREAM_INPUT)
+ mate_mixer_client_stream_set_parent (client, stream);
+ }
+ streams = streams->next;
+ }
- mate_mixer_stream_set_volume (stream, rounded);
+ if (page == PAGE_INPUT)
+ mate_mixer_stream_monitor_start (stream);
}
-}
-
-static void
-on_bar_is_muted_notify (GObject *object,
- GParamSpec *pspec,
- GvcMixerDialog *dialog)
-{
- gboolean is_muted;
- MateMixerStream *stream;
- is_muted = gvc_channel_bar_get_is_muted (GVC_CHANNEL_BAR (object));
+ bar_set_stream (dialog, dialog->priv->input_bar, stream);
- stream = g_object_get_data (object, "gvc-mixer-dialog-stream");
- if (stream != NULL) {
- mate_mixer_stream_set_mute (stream, is_muted);
- } else {
- char *name;
- g_object_get (object, "name", &name, NULL);
- g_warning ("Unable to find stream for bar '%s'", name);
- g_free (name);
- }
-}
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
+ update_default_item (dialog, model, stream);
-static GtkWidget *
-lookup_bar_for_stream (GvcMixerDialog *dialog, MateMixerStream *stream)
-{
- return g_hash_table_lookup (dialog->priv->bars, mate_mixer_stream_get_name (stream));
+ update_input_settings (dialog);
}
-static GtkWidget *
-lookup_combo_box_for_stream (GvcMixerDialog *dialog,
- MateMixerStream *stream)
+static GvcComboBox *
+find_combo_box_by_stream (GvcMixerDialog *dialog, MateMixerStream *stream)
{
MateMixerStream *combo_stream;
- const gchar *name;
-
- name = mate_mixer_stream_get_name (stream);
if (dialog->priv->output_port_combo != NULL) {
combo_stream = g_object_get_data (G_OBJECT (dialog->priv->output_port_combo),
"stream");
- if (combo_stream != NULL) {
- if (!g_strcmp0 (name, mate_mixer_stream_get_name (combo_stream)))
- return dialog->priv->output_port_combo;
- }
+ if (combo_stream == stream)
+ return GVC_COMBO_BOX (dialog->priv->output_port_combo);
}
if (dialog->priv->input_port_combo != NULL) {
combo_stream = g_object_get_data (G_OBJECT (dialog->priv->input_port_combo),
"stream");
- if (combo_stream != NULL) {
- if (!g_strcmp0 (name, mate_mixer_stream_get_name (combo_stream)))
- return dialog->priv->input_port_combo;
- }
+ if (combo_stream == stream)
+ return GVC_COMBO_BOX (dialog->priv->input_port_combo);
}
-
return NULL;
}
static void
on_stream_description_notify (MateMixerStream *stream,
- GParamSpec *pspec,
- GvcMixerDialog *dialog)
+ GParamSpec *pspec,
+ GvcMixerDialog *dialog)
{
- update_description (dialog, NAME_COLUMN,
- mate_mixer_stream_get_description (stream),
- stream);
-}
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ MateMixerStreamFlags flags;
-static void
-on_stream_port_notify (GObject *object,
- GParamSpec *pspec,
- GvcMixerDialog *dialog)
-{
- GvcComboBox *combo;
- MateMixerPort *port;
+ flags = mate_mixer_stream_get_flags (stream);
- combo = GVC_COMBO_BOX (lookup_combo_box_for_stream (dialog, MATE_MIXER_STREAM (object)));
- if (combo == NULL)
- return;
+ if (flags & MATE_MIXER_STREAM_INPUT)
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
+ else
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
- g_signal_handlers_block_by_func (G_OBJECT (combo),
- port_selection_changed,
- dialog);
+ if (find_tree_item_by_name (model,
+ mate_mixer_stream_get_name (stream),
+ NAME_COLUMN,
+ &iter) == TRUE) {
+ const gchar *description;
- g_object_get (object, "active-port", &port, NULL);
- // XXX is this correct?
- if (port) {
- gvc_combo_box_set_active (GVC_COMBO_BOX (combo),
- mate_mixer_port_get_name (port));
+ description = mate_mixer_stream_get_description (stream);
+ gtk_list_store_set (GTK_LIST_STORE (model),
+ &iter,
+ DESCRIPTION_COLUMN, description,
+ -1);
}
-
- g_signal_handlers_unblock_by_func (G_OBJECT (combo),
- port_selection_changed,
- dialog);
}
static void
-on_stream_volume_notify (GObject *object,
- GParamSpec *pspec,
- GvcMixerDialog *dialog)
+on_stream_port_notify (MateMixerStream *stream,
+ GParamSpec *pspec,
+ GvcMixerDialog *dialog)
{
- MateMixerStream *stream;
- GtkWidget *bar;
- GtkAdjustment *adj;
-
- stream = MATE_MIXER_STREAM (object);
-
- bar = lookup_bar_for_stream (dialog, stream);
+ GvcComboBox *combobox;
+ MateMixerPort *port;
- if (bar == NULL) {
- g_warning ("Unable to find bar for stream %s in on_stream_volume_notify()",
- mate_mixer_stream_get_name (stream));
+ combobox = find_combo_box_by_stream (dialog, stream);
+ if (G_UNLIKELY (combobox == NULL)) {
+ g_warn_if_reached ();
return;
}
- adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar)));
+ g_debug ("Stream %s port has changed",
+ mate_mixer_stream_get_name (stream));
- g_signal_handlers_block_by_func (adj,
- on_adjustment_value_changed,
+ g_signal_handlers_block_by_func (G_OBJECT (combobox),
+ on_combo_box_port_changed,
dialog);
- gtk_adjustment_set_value (adj,
- mate_mixer_stream_get_volume (stream));
+ port = mate_mixer_stream_get_active_port (stream);
+ if (G_LIKELY (port != NULL)) {
+ const gchar *name = mate_mixer_port_get_name (port);
+
+ g_debug ("The current port is %s", name);
- g_signal_handlers_unblock_by_func (adj,
- on_adjustment_value_changed,
+ gvc_combo_box_set_active (GVC_COMBO_BOX (combobox), name);
+ }
+
+ g_signal_handlers_unblock_by_func (G_OBJECT (combobox),
+ on_combo_box_port_changed,
dialog);
}
static void
-on_stream_mute_notify (GObject *object,
- GParamSpec *pspec,
- GvcMixerDialog *dialog)
+on_stream_mute_notify (MateMixerStream *stream,
+ GParamSpec *pspec,
+ GvcMixerDialog *dialog)
{
- MateMixerStream *stream;
- GtkWidget *bar;
- gboolean is_muted;
-
- stream = MATE_MIXER_STREAM (object);
- bar = lookup_bar_for_stream (dialog, stream);
-
- if (bar == NULL) {
- g_warning ("Unable to find bar for stream %s in on_stream_is_muted_notify()",
- mate_mixer_stream_get_name (stream));
- return;
- }
+ MateMixerStream *input;
- is_muted = mate_mixer_stream_get_mute (stream);
- gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (bar), is_muted);
+ input = mate_mixer_control_get_default_input_stream (dialog->priv->control);
- if (stream == mate_mixer_control_get_default_output_stream (dialog->priv->control)) {
- gtk_widget_set_sensitive (dialog->priv->applications_box,
- !is_muted);
+ /* Stop monitoring the input stream when it gets muted */
+ if (stream == input) {
+ if (mate_mixer_stream_get_mute (stream))
+ mate_mixer_stream_monitor_stop (stream);
+ else
+ mate_mixer_stream_monitor_start (stream);
}
-
-}
-
-static void
-save_bar_for_stream (GvcMixerDialog *dialog,
- MateMixerStream *stream,
- GtkWidget *bar)
-{
- g_hash_table_insert (dialog->priv->bars,
- (gpointer) mate_mixer_stream_get_name (stream),
- bar);
}
static GtkWidget *
-create_bar (GvcMixerDialog *dialog,
- GtkSizeGroup *size_group,
- gboolean symmetric)
+create_bar (GvcMixerDialog *dialog, gboolean use_size_group, gboolean symmetric)
{
GtkWidget *bar;
- bar = gvc_channel_bar_new ();
- gtk_widget_set_sensitive (bar, FALSE);
- if (size_group != NULL) {
+ bar = gvc_channel_bar_new (NULL);
+
+ if (use_size_group == TRUE)
gvc_channel_bar_set_size_group (GVC_CHANNEL_BAR (bar),
- size_group,
+ dialog->priv->size_group,
symmetric);
- }
- gvc_channel_bar_set_orientation (GVC_CHANNEL_BAR (bar),
- GTK_ORIENTATION_HORIZONTAL);
- gvc_channel_bar_set_show_mute (GVC_CHANNEL_BAR (bar),
- TRUE);
- g_signal_connect (bar,
- "notify::is-muted",
- G_CALLBACK (on_bar_is_muted_notify),
- dialog);
+
+ g_object_set (G_OBJECT (bar),
+ "orientation", GTK_ORIENTATION_HORIZONTAL,
+ "show-mute", TRUE,
+ "show-icons", TRUE,
+ "show-marks", TRUE,
+ "extended", TRUE, NULL);
return bar;
}
static void
-bar_set_stream (GvcMixerDialog *dialog, GtkWidget *bar, MateMixerStream *stream)
+bar_set_stream (GvcMixerDialog *dialog,
+ GtkWidget *bar,
+ MateMixerStream *stream)
{
- GtkAdjustment *adj;
- MateMixerStream *old_stream;
+ MateMixerStream *previous;
- old_stream = g_object_get_data (G_OBJECT (bar), "gvc-mixer-dialog-stream");
- if (old_stream != NULL) {
- char *name;
+ previous = gvc_channel_bar_get_stream (GVC_CHANNEL_BAR (bar));
+ if (previous != NULL) {
+ const gchar *name = mate_mixer_stream_get_name (previous);
- g_object_get (bar, "name", &name, NULL);
- g_debug ("Disconnecting old stream '%s' from bar '%s'",
- mate_mixer_stream_get_name (old_stream), name);
- g_free (name);
+ g_debug ("Disconnecting old stream %s", name);
+
+ g_signal_handlers_disconnect_by_func (previous,
+ on_stream_mute_notify,
+ dialog);
+ g_signal_handlers_disconnect_by_func (previous,
+ on_stream_port_notify,
+ dialog);
- g_signal_handlers_disconnect_by_func (old_stream, on_stream_mute_notify, dialog);
- g_signal_handlers_disconnect_by_func (old_stream, on_stream_volume_notify, dialog);
- g_signal_handlers_disconnect_by_func (old_stream, on_stream_port_notify, dialog);
+ if (mate_mixer_stream_get_flags (previous) & MATE_MIXER_STREAM_INPUT)
+ mate_mixer_stream_monitor_stop (previous);
g_hash_table_remove (dialog->priv->bars, name);
}
- gtk_widget_set_sensitive (bar, (stream != NULL));
-
- adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar)));
-
- // XXX already done in notify
- g_signal_handlers_disconnect_by_func (adj, on_adjustment_value_changed, dialog);
-
- g_object_set_data (G_OBJECT (bar), "gvc-mixer-dialog-stream", stream);
- g_object_set_data (G_OBJECT (adj), "gvc-mixer-dialog-stream", stream);
- g_object_set_data (G_OBJECT (adj), "gvc-mixer-dialog-bar", bar);
+ gvc_channel_bar_set_stream (GVC_CHANNEL_BAR (bar), stream);
if (stream != NULL) {
- gboolean is_muted;
+ const gchar *name = mate_mixer_stream_get_name (stream);
- is_muted = mate_mixer_stream_get_mute (stream);
- gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (bar), is_muted);
-
- save_bar_for_stream (dialog, stream, bar);
-
- gtk_adjustment_set_value (adj, mate_mixer_stream_get_volume (stream));
+ g_debug ("Connecting new stream %s", name);
g_signal_connect (stream,
"notify::mute",
G_CALLBACK (on_stream_mute_notify),
dialog);
g_signal_connect (stream,
- "notify::volume",
- G_CALLBACK (on_stream_volume_notify),
- dialog);
- g_signal_connect (stream,
"notify::active-port",
G_CALLBACK (on_stream_port_notify),
dialog);
- g_signal_connect (adj,
- "value-changed",
- G_CALLBACK (on_adjustment_value_changed),
- dialog);
+
+ g_hash_table_insert (dialog->priv->bars, (gpointer) name, bar);
}
+
+ gtk_widget_set_sensitive (GTK_WIDGET (bar), (stream != NULL));
}
static void
add_stream (GvcMixerDialog *dialog, MateMixerStream *stream)
{
- GtkWidget *bar = NULL;
- gboolean is_default = FALSE;
- MateMixerClientStream *client = NULL;
- MateMixerStreamFlags flags;
+ GtkWidget *bar = NULL;
+ MateMixerStreamFlags flags;
flags = mate_mixer_stream_get_flags (stream);
- if (flags & MATE_MIXER_STREAM_EVENT)
- return;
- if (flags & MATE_MIXER_STREAM_APPLICATION) {
- const gchar *app_id;
+ if (MATE_MIXER_IS_CLIENT_STREAM (stream)) {
+ MateMixerClientStream *client ;
+ MateMixerClientStreamFlags client_flags;
+ MateMixerClientStreamRole client_role;
+ const gchar *name;
+ const gchar *icon;
- client = MATE_MIXER_CLIENT_STREAM (stream);
- app_id = mate_mixer_client_stream_get_app_id (client);
+ client = MATE_MIXER_CLIENT_STREAM (stream);
+ client_flags = mate_mixer_client_stream_get_flags (client);
+ client_role = mate_mixer_client_stream_get_role (client);
- /* These applications are not displayed on the Applications tab */
- if (!g_strcmp0 (app_id, "org.mate.VolumeControl") ||
- !g_strcmp0 (app_id, "org.gnome.VolumeControl") ||
- !g_strcmp0 (app_id, "org.PulseAudio.pavucontrol"))
- return;
- }
+ /* We use a cached event stream for the effects volume slider,
+ * because regular streams are only created when an event sound
+ * is played and then immediately destroyed.
+ * The cached event stream should exist all the time. */
+ if (client_flags & MATE_MIXER_CLIENT_STREAM_CACHED &&
+ client_role == MATE_MIXER_CLIENT_STREAM_ROLE_EVENT) {
+ g_debug ("Found cached event role stream %s",
+ mate_mixer_stream_get_name (stream));
+
+ bar = dialog->priv->effects_bar;
+ }
- if (client == NULL) {
+ /* Add stream to the applications page, but make sure the stream
+ * qualifies for the inclusion */
+ if (client_flags & MATE_MIXER_CLIENT_STREAM_APPLICATION) {
+ const gchar *app_id;
+
+ /* Skip streams with roles we don't care about */
+ if (client_role == MATE_MIXER_CLIENT_STREAM_ROLE_EVENT ||
+ client_role == MATE_MIXER_CLIENT_STREAM_ROLE_TEST ||
+ client_role == MATE_MIXER_CLIENT_STREAM_ROLE_ABSTRACT ||
+ client_role == MATE_MIXER_CLIENT_STREAM_ROLE_FILTER)
+ return;
+
+ app_id = mate_mixer_client_stream_get_app_id (client);
+
+ /* These applications may have associated streams because
+ * they do peak level monitoring, skip these too */
+ if (!g_strcmp0 (app_id, "org.mate.VolumeControl") ||
+ !g_strcmp0 (app_id, "org.gnome.VolumeControl") ||
+ !g_strcmp0 (app_id, "org.PulseAudio.pavucontrol"))
+ return;
+
+ name = mate_mixer_client_stream_get_app_name (client);
+ if (name == NULL)
+ name = mate_mixer_stream_get_description (stream);
+ if (name == NULL)
+ name = mate_mixer_stream_get_name (stream);
+ if (G_UNLIKELY (name == NULL))
+ return;
+
+ bar = create_bar (dialog, FALSE, FALSE);
+
+ g_object_set (G_OBJECT (bar),
+ "show-marks", FALSE,
+ "extended", FALSE,
+ NULL);
+
+ /* By default channel bars use speaker icons, use microphone
+ * icons instead for recording applications */
+ if (flags & MATE_MIXER_STREAM_INPUT)
+ g_object_set (G_OBJECT (bar),
+ "low-icon-name", "audio-input-microphone-low",
+ "high-icon-name", "audio-input-microphone-high",
+ NULL);
+
+ icon = mate_mixer_client_stream_get_app_icon (client);
+ if (icon == NULL) {
+ if (flags & MATE_MIXER_STREAM_INPUT)
+ icon = "audio-input-microphone";
+ else
+ icon = "applications-multimedia";
+ }
+
+ gvc_channel_bar_set_name (GVC_CHANNEL_BAR (bar), name);
+ gvc_channel_bar_set_icon_name (GVC_CHANNEL_BAR (bar), icon);
+
+ gtk_box_pack_start (GTK_BOX (dialog->priv->applications_box),
+ bar,
+ FALSE, FALSE, 12);
+
+ gtk_widget_hide (dialog->priv->no_apps_label);
+ dialog->priv->num_apps++;
+ }
+ } else {
GtkTreeModel *model = NULL;
GtkTreeIter iter;
MateMixerStream *input;
MateMixerStream *output;
const gchar *speakers = NULL;
- GtkAdjustment *adj;
+ gboolean is_default = FALSE;
input = mate_mixer_control_get_default_input_stream (dialog->priv->control);
output = mate_mixer_control_get_default_output_stream (dialog->priv->control);
@@ -854,28 +874,17 @@ add_stream (GvcMixerDialog *dialog, MateMixerStream *stream)
if (flags & MATE_MIXER_STREAM_INPUT) {
if (stream == input) {
bar = dialog->priv->input_bar;
- adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar)));
- g_signal_handlers_disconnect_by_func (G_OBJECT (adj),
- on_adjustment_value_changed,
- dialog);
update_input_settings (dialog);
is_default = TRUE;
}
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
-
- } else if (flags & MATE_MIXER_STREAM_OUTPUT) {
+ }
+ else if (flags & MATE_MIXER_STREAM_OUTPUT) {
if (stream == output) {
bar = dialog->priv->output_bar;
- adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar)));
-
- gtk_widget_set_sensitive (dialog->priv->applications_box,
- mate_mixer_stream_get_mute (stream) == FALSE);
- g_signal_handlers_disconnect_by_func (G_OBJECT (adj),
- on_adjustment_value_changed,
- dialog);
update_output_settings (dialog);
is_default = TRUE;
}
@@ -885,23 +894,8 @@ add_stream (GvcMixerDialog *dialog, MateMixerStream *stream)
}
if (model != NULL) {
- MateMixerDevice *device;
- const gchar *name,
- *description;
- const gchar *device_name = NULL;
- const gchar *icon = NULL;
-
- device = mate_mixer_stream_get_device (stream);
- if (G_LIKELY (device != NULL)) {
- device_name = mate_mixer_device_get_description (device);
- if (device_name == NULL)
- device_name = mate_mixer_device_get_name (device);
-
- icon = mate_mixer_device_get_icon (device);
- }
-
- if (icon == NULL)
- icon = "audio-card";
+ const gchar *name;
+ const gchar *description;
name = mate_mixer_stream_get_name (stream);
description = mate_mixer_stream_get_description (stream);
@@ -911,7 +905,6 @@ add_stream (GvcMixerDialog *dialog, MateMixerStream *stream)
&iter,
NAME_COLUMN, name,
DESCRIPTION_COLUMN, description,
- DEVICE_COLUMN, device_name,
ACTIVE_COLUMN, is_default,
SPEAKERS_COLUMN, speakers,
-1);
@@ -921,48 +914,6 @@ add_stream (GvcMixerDialog *dialog, MateMixerStream *stream)
G_CALLBACK (on_stream_description_notify),
dialog);
}
- } else {
- const gchar *name;
- const gchar *icon;
-
- bar = create_bar (dialog, dialog->priv->apps_size_group, FALSE);
-
- // FIXME:
- // 1) We should ideally provide application name on the first line and
- // description on a second line in italics
- // 2) We should watch for name changes as it may include for example
- // the name of the current song
- name = mate_mixer_client_stream_get_app_name (client);
- if (name == NULL)
- name = mate_mixer_stream_get_description (stream);
- if (name == NULL)
- name = mate_mixer_stream_get_name (stream);
-
- if (name == NULL || strchr (name, '_') == NULL) {
- gvc_channel_bar_set_name (GVC_CHANNEL_BAR (bar), name);
- } else {
- char **tokens, *escaped;
-
- // XXX why is this here?
- tokens = g_strsplit (name, "_", -1);
- escaped = g_strjoinv ("__", tokens);
- g_strfreev (tokens);
- gvc_channel_bar_set_name (GVC_CHANNEL_BAR (bar), escaped);
- g_free (escaped);
- }
-
- icon = mate_mixer_client_stream_get_app_icon (client);
- if (icon == NULL) {
- /* If there is no name of the application icon, set a default */
- icon = "applications-multimedia";
- }
-
- gvc_channel_bar_set_icon_name (GVC_CHANNEL_BAR (bar), icon);
-
- gtk_box_pack_start (GTK_BOX (dialog->priv->applications_box), bar, FALSE, FALSE, 12);
- gtk_widget_hide (dialog->priv->no_apps_label);
-
- dialog->priv->num_apps++;
}
if (bar != NULL) {
@@ -980,80 +931,61 @@ on_control_stream_added (MateMixerControl *control,
GtkWidget *bar;
bar = g_hash_table_lookup (dialog->priv->bars, name);
- if (bar != NULL) {
- g_debug ("Ignoring already known stream %s", name);
+ if (G_UNLIKELY (bar != NULL))
return;
- }
stream = mate_mixer_control_get_stream (control, name);
- if (G_LIKELY (stream != NULL))
- add_stream (dialog, stream);
-}
-
-static gboolean
-find_tree_item_by_name (GtkTreeModel *model,
- const gchar *name,
- guint column,
- GtkTreeIter *iter)
-{
- gboolean found = FALSE;
-
- if (!gtk_tree_model_get_iter_first (model, iter))
- return FALSE;
-
- do {
- gchar *n;
-
- gtk_tree_model_get (model, iter, column, &n, -1);
-
- if (!g_strcmp0 (name, n))
- found = TRUE;
-
- g_free (n);
- } while (!found && gtk_tree_model_iter_next (model, iter));
+ if (G_UNLIKELY (stream == NULL))
+ return;
- return found;
+ add_stream (dialog, stream);
}
static void
remove_stream (GvcMixerDialog *dialog, const gchar *name)
{
GtkWidget *bar;
- gboolean found;
GtkTreeIter iter;
GtkTreeModel *model;
- /* remove bars for applications and reset fixed bars */
+ /* Remove bars for applications and reset fixed bars */
bar = g_hash_table_lookup (dialog->priv->bars, name);
- if (bar == dialog->priv->output_bar
- || bar == dialog->priv->input_bar
- || bar == dialog->priv->effects_bar) { // XXX effects bad? verify this!
- char *bar_name;
- g_object_get (bar, "name", &bar_name, NULL);
- g_debug ("Removing stream for bar '%s'", bar_name);
- g_free (bar_name);
+
+ if (bar == dialog->priv->input_bar || bar == dialog->priv->output_bar) {
+ g_debug ("Removing stream %s from bar %s",
+ name,
+ gvc_channel_bar_get_name (GVC_CHANNEL_BAR (bar)));
+
bar_set_stream (dialog, bar, NULL);
} else if (bar != NULL) {
+ g_debug ("Removing application stream %s", name);
+
g_hash_table_remove (dialog->priv->bars, name);
- gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (bar)),
- bar);
- dialog->priv->num_apps--;
- if (dialog->priv->num_apps == 0) {
- gtk_widget_show (dialog->priv->no_apps_label);
+ gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (bar)), bar);
+
+ if (G_UNLIKELY (dialog->priv->num_apps <= 0)) {
+ g_warn_if_reached ();
+ dialog->priv->num_apps = 1;
}
+
+ if (--dialog->priv->num_apps == 0)
+ gtk_widget_show (dialog->priv->no_apps_label);
}
- /* remove from any models */
+ /* Remove from any models */
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
- found = find_tree_item_by_name (GTK_TREE_MODEL (model), name, NAME_COLUMN, &iter);
- if (found) {
+ if (find_tree_item_by_name (GTK_TREE_MODEL (model),
+ name,
+ NAME_COLUMN,
+ &iter) == TRUE)
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
- }
+
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
- found = find_tree_item_by_name (GTK_TREE_MODEL (model), name, NAME_COLUMN, &iter);
- if (found) {
+ if (find_tree_item_by_name (GTK_TREE_MODEL (model),
+ name,
+ NAME_COLUMN,
+ &iter) == TRUE)
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
- }
}
static void
@@ -1064,8 +996,28 @@ on_control_stream_removed (MateMixerControl *control,
remove_stream (dialog, name);
}
+static void
+on_control_cached_stream_removed (MateMixerControl *control,
+ const gchar *name,
+ GvcMixerDialog *dialog)
+{
+ GtkWidget *bar;
+
+ bar = g_hash_table_lookup (dialog->priv->bars, name);
+
+ if (bar != NULL) {
+ /* We only use a cached stream in the effects bar */
+ if (G_UNLIKELY (bar != dialog->priv->effects_bar)) {
+ g_warn_if_reached ();
+ return;
+ }
+
+ bar_set_stream (dialog, bar, NULL);
+ }
+}
+
static gchar *
-card_profile_status (MateMixerDeviceProfile *profile)
+device_profile_status (MateMixerDeviceProfile *profile)
{
guint inputs;
guint outputs;
@@ -1099,7 +1051,7 @@ card_profile_status (MateMixerDeviceProfile *profile)
inputs);
}
- if (inputs_str == NULL && outputs_str == NULL) {
+ if (inputs_str != NULL && outputs_str != NULL) {
gchar *ret = g_strdup_printf ("%s / %s",
outputs_str,
inputs_str);
@@ -1115,92 +1067,129 @@ card_profile_status (MateMixerDeviceProfile *profile)
}
static void
-add_device (GvcMixerDialog *dialog, MateMixerDevice *device)
+update_device_info (GvcMixerDialog *dialog, MateMixerDevice *device)
{
- GtkTreeModel *model;
- GtkTreeIter iter;
- GtkTreeSelection *selection;
+ GtkTreeModel *model = NULL;
+ GtkTreeIter iter;
MateMixerDeviceProfile *profile;
- GIcon *icon;
- const gchar *name;
- const gchar *profile_name;
- gchar *profile_status;
+ const gchar *description;
+ const gchar *profile_description = NULL;
+ gchar *profile_status = NULL;
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->hw_treeview));
- name = mate_mixer_device_get_name (device);
-
- if (find_tree_item_by_name (GTK_TREE_MODEL (model), name, HW_NAME_COLUMN, &iter) == FALSE)
- gtk_list_store_append (GTK_LIST_STORE (model), &iter);
- profile = mate_mixer_device_get_active_profile (device);
- g_assert (profile != NULL);
- icon = g_themed_icon_new_with_default_fallbacks (mate_mixer_device_get_icon (device));
+ if (find_tree_item_by_name (model,
+ mate_mixer_device_get_name (device),
+ HW_NAME_COLUMN,
+ &iter) == FALSE)
+ return;
- //FIXME we need the status (default for a profile?) here
+ description = mate_mixer_device_get_description (device);
- profile_name = mate_mixer_device_profile_get_name (profile);
- profile_status = card_profile_status (profile);
+ profile = mate_mixer_device_get_active_profile (device);
+ if (profile != NULL) {
+ profile_description = mate_mixer_device_profile_get_description (profile);
+ profile_status = device_profile_status (profile);
+ }
gtk_list_store_set (GTK_LIST_STORE (model),
&iter,
- HW_NAME_COLUMN, mate_mixer_device_get_name (device),
- HW_DESCRIPTION_COLUMN, mate_mixer_device_get_description (device),
- HW_ICON_COLUMN, icon,
- HW_PROFILE_COLUMN, profile_name,
- HW_PROFILE_HUMAN_COLUMN, mate_mixer_device_profile_get_description (profile),
+ HW_DESCRIPTION_COLUMN, description,
+ HW_PROFILE_COLUMN, profile_description,
HW_STATUS_COLUMN, profile_status,
- HW_SENSITIVE_COLUMN, g_strcmp0 (profile_name, "off") != 0,
-1);
g_free (profile_status);
+}
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->hw_treeview));
+static void
+on_device_profile_notify (MateMixerDevice *device,
+ GParamSpec *pspec,
+ GvcMixerDialog *dialog)
+{
+ MateMixerDeviceProfile *profile;
- if (gtk_tree_selection_get_selected (selection, NULL, NULL) == FALSE) {
- /* Select the currently added item if nothing is selected now */
- gtk_tree_selection_select_iter (selection, &iter);
- } else if (dialog->priv->hw_profile_combo != NULL) {
- MateMixerDevice *selected;
+ g_debug ("Device profile has changed");
- /* Set the current profile if it changed for the selected card */
- selected = g_object_get_data (G_OBJECT (dialog->priv->hw_profile_combo), "device");
+ g_signal_handlers_block_by_func (G_OBJECT (dialog->priv->hw_profile_combo),
+ G_CALLBACK (on_combo_box_profile_changed),
+ dialog);
- if (!g_strcmp0 (mate_mixer_device_get_name (device),
- mate_mixer_device_get_name (selected))) {
- gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->hw_profile_combo),
- profile_name);
+ profile = mate_mixer_device_get_active_profile (device);
+ if (G_LIKELY (profile != NULL)) {
+ const gchar *name = mate_mixer_device_profile_get_name (profile);
- g_object_set (G_OBJECT (dialog->priv->hw_profile_combo),
- "show-button",
- mate_mixer_device_profile_get_num_output_streams (profile) >= 1,
- NULL);
- }
+ g_debug ("The current profile is %s", name);
+
+ gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->hw_profile_combo),
+ name);
}
+
+ g_signal_handlers_unblock_by_func (G_OBJECT (dialog->priv->hw_profile_combo),
+ G_CALLBACK (on_combo_box_profile_changed),
+ dialog);
+
+ update_device_info (dialog, device);
}
static void
-on_control_device_added (MateMixerControl *control, const gchar *name, GvcMixerDialog *dialog)
+add_device (GvcMixerDialog *dialog, MateMixerDevice *device)
{
- MateMixerDevice *device;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ MateMixerDeviceProfile *profile;
+ GIcon *icon;
+ const gchar *name;
+ const gchar *description;
+ const gchar *profile_description = NULL;
+ gchar *profile_status = NULL;
- device = mate_mixer_control_get_device (control, name);
- if (device != NULL)
- add_device (dialog, device);
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->hw_treeview));
+
+ name = mate_mixer_device_get_name (device);
+ description = mate_mixer_device_get_description (device);
+
+ if (find_tree_item_by_name (GTK_TREE_MODEL (model),
+ name,
+ HW_NAME_COLUMN,
+ &iter) == FALSE)
+ gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+
+ icon = g_themed_icon_new_with_default_fallbacks (mate_mixer_device_get_icon (device));
+
+ profile = mate_mixer_device_get_active_profile (device);
+ if (profile != NULL) {
+ profile_description = mate_mixer_device_profile_get_description (profile);
+ profile_status = device_profile_status (profile);
+ }
+
+ gtk_list_store_set (GTK_LIST_STORE (model),
+ &iter,
+ HW_NAME_COLUMN, name,
+ HW_DESCRIPTION_COLUMN, description,
+ HW_ICON_COLUMN, icon,
+ HW_PROFILE_COLUMN, profile_description,
+ HW_STATUS_COLUMN, profile_status,
+ -1);
+
+ g_free (profile_status);
+
+ g_signal_connect (device,
+ "notify::active-profile",
+ G_CALLBACK (on_device_profile_notify),
+ dialog);
}
static void
-remove_card (GvcMixerDialog *dialog, const gchar *name)
+on_control_device_added (MateMixerControl *control, const gchar *name, GvcMixerDialog *dialog)
{
- gboolean found;
- GtkTreeIter iter;
- GtkTreeModel *model;
+ MateMixerDevice *device;
- /* remove from any models */
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->hw_treeview));
- found = find_tree_item_by_name (GTK_TREE_MODEL (model), name, HW_NAME_COLUMN, &iter);
- if (found) {
- gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
- }
+ device = mate_mixer_control_get_device (control, name);
+ if (G_UNLIKELY (device == NULL))
+ return;
+
+ add_device (dialog, device);
}
static void
@@ -1208,43 +1197,54 @@ on_control_device_removed (MateMixerControl *control,
const gchar *name,
GvcMixerDialog *dialog)
{
- remove_card (dialog, name);
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+
+ /* Remove from any models */
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->hw_treeview));
+
+ if (find_tree_item_by_name (GTK_TREE_MODEL (model),
+ name,
+ HW_NAME_COLUMN,
+ &iter) == TRUE)
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
}
static void
-_gtk_label_make_bold (GtkLabel *label)
+make_label_bold (GtkLabel *label)
{
PangoFontDescription *font_desc;
font_desc = pango_font_description_new ();
- pango_font_description_set_weight (font_desc,
- PANGO_WEIGHT_BOLD);
+ pango_font_description_set_weight (font_desc, PANGO_WEIGHT_BOLD);
/* This will only affect the weight of the font, the rest is
* from the current state of the widget, which comes from the
* theme or user prefs, since the font desc only has the
- * weight flag turned on.
- */
+ * weight flag turned on. */
+#if GTK_CHECK_VERSION (3, 0, 0)
+ gtk_widget_override_font (GTK_WIDGET (label), font_desc);
+#else
gtk_widget_modify_font (GTK_WIDGET (label), font_desc);
-
+#endif
pango_font_description_free (font_desc);
}
static void
on_input_radio_toggled (GtkCellRendererToggle *renderer,
- char *path_str,
+ gchar *path_str,
GvcMixerDialog *dialog)
{
GtkTreeModel *model;
GtkTreeIter iter;
GtkTreePath *path;
- gboolean toggled;
- gchar *name;
+ gboolean toggled = FALSE;
+ gchar *name = NULL;
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
+ path = gtk_tree_path_new_from_string (path_str);
- path = gtk_tree_path_new_from_string (path_str);
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_path_free (path);
@@ -1252,34 +1252,36 @@ on_input_radio_toggled (GtkCellRendererToggle *renderer,
NAME_COLUMN, &name,
ACTIVE_COLUMN, &toggled,
-1);
-
if (toggled ^ 1) {
MateMixerStream *stream;
- g_debug ("Default input selected: %s", name);
stream = mate_mixer_control_get_stream (dialog->priv->control, name);
+ if (G_UNLIKELY (stream == NULL)) {
+ g_warn_if_reached ();
+ g_free (name);
+ return;
+ }
- if (stream != NULL)
- mate_mixer_control_set_default_input_stream (dialog->priv->control,
- stream);
+ g_debug ("Default input stream selection changed to %s", name);
+ mate_mixer_control_set_default_input_stream (dialog->priv->control, stream);
}
g_free (name);
}
static void
on_output_radio_toggled (GtkCellRendererToggle *renderer,
- char *path_str,
+ gchar *path_str,
GvcMixerDialog *dialog)
{
GtkTreeModel *model;
GtkTreeIter iter;
GtkTreePath *path;
- gboolean toggled;
- gchar *name;
+ gboolean toggled = FALSE;
+ gchar *name = NULL;
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
+ path = gtk_tree_path_new_from_string (path_str);
- path = gtk_tree_path_new_from_string (path_str);
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_path_free (path);
@@ -1287,44 +1289,74 @@ on_output_radio_toggled (GtkCellRendererToggle *renderer,
NAME_COLUMN, &name,
ACTIVE_COLUMN, &toggled,
-1);
-
if (toggled ^ 1) {
MateMixerStream *stream;
- g_debug ("Default output selected: %s", name);
stream = mate_mixer_control_get_stream (dialog->priv->control, name);
- if (stream != NULL)
- mate_mixer_control_set_default_output_stream (dialog->priv->control,
- stream);
+ if (G_UNLIKELY (stream == NULL)) {
+ g_warn_if_reached ();
+ g_free (name);
+ return;
+ }
+
+ g_debug ("Default output stream selection changed to %s", name);
+ mate_mixer_control_set_default_output_stream (dialog->priv->control, stream);
}
g_free (name);
}
static void
-name_to_text (GtkTreeViewColumn *column,
- GtkCellRenderer *cell,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer user_data)
+stream_name_to_text (GtkTreeViewColumn *column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer user_data)
{
- char *description, *mapping;
+ gchar *description;
+ gchar *speakers;
gtk_tree_model_get (model, iter,
DESCRIPTION_COLUMN, &description,
- SPEAKERS_COLUMN, &mapping,
+ SPEAKERS_COLUMN, &speakers,
-1);
- if (mapping == NULL) {
- g_object_set (cell, "text", description, NULL);
- } else {
- gchar *str = g_strdup_printf ("%s\n<i>%s</i>", description, mapping);
+ if (speakers != NULL) {
+ gchar *str = g_strdup_printf ("%s\n<i>%s</i>",
+ description,
+ speakers);
g_object_set (cell, "markup", str, NULL);
g_free (str);
+ g_free (speakers);
+ } else {
+ g_object_set (cell, "text", description, NULL);
}
g_free (description);
- g_free (mapping);
+}
+
+static gint
+compare_stream_treeview_items (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
+{
+ gchar *desc_a = NULL;
+ gchar *desc_b = NULL;
+ gint result;
+
+ gtk_tree_model_get (model, a,
+ DESCRIPTION_COLUMN, &desc_a,
+ -1);
+ gtk_tree_model_get (model, b,
+ DESCRIPTION_COLUMN, &desc_b,
+ -1);
+
+ result = g_ascii_strcasecmp (desc_a, desc_b);
+
+ g_free (desc_a);
+ g_free (desc_b);
+ return result;
}
static GtkWidget *
@@ -1342,7 +1374,6 @@ create_stream_treeview (GvcMixerDialog *dialog, GCallback on_toggled)
G_TYPE_ICON,
G_TYPE_STRING,
G_TYPE_STRING,
- G_TYPE_STRING,
G_TYPE_BOOLEAN,
G_TYPE_STRING);
@@ -1356,9 +1387,10 @@ create_stream_treeview (GvcMixerDialog *dialog, GCallback on_toggled)
renderer,
"active", ACTIVE_COLUMN,
NULL);
+
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
- g_signal_connect (renderer,
+ g_signal_connect (G_OBJECT (renderer),
"toggled",
G_CALLBACK (on_toggled),
dialog);
@@ -1366,48 +1398,66 @@ create_stream_treeview (GvcMixerDialog *dialog, GCallback on_toggled)
gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview), -1,
_("Name"),
gtk_cell_renderer_text_new (),
- name_to_text, NULL, NULL);
+ stream_name_to_text,
+ NULL, NULL);
-#if 0
- renderer = gtk_cell_renderer_text_new ();
- column = gtk_tree_view_column_new_with_attributes (_("Device"),
- renderer,
- "text", DEVICE_COLUMN,
- NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
-#endif
+ /* Keep the list of streams sorted by the name */
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+ DESCRIPTION_COLUMN,
+ GTK_SORT_ASCENDING);
+
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store),
+ DESCRIPTION_COLUMN,
+ compare_stream_treeview_items,
+ NULL, NULL);
return treeview;
}
-static void
-on_profile_changed (GvcComboBox *widget, const gchar *profile, gpointer user_data)
+static MateMixerStream *
+find_device_test_stream (GvcMixerDialog *dialog, MateMixerDevice *device)
{
- MateMixerDevice *device;
+ GList *streams;
- device = g_object_get_data (G_OBJECT (widget), "device");
- if (device == NULL) {
- g_warning ("Could not find card for combobox");
- return;
- }
+ streams = (GList *) mate_mixer_control_list_streams (dialog->priv->control);
+ while (streams) {
+ MateMixerStream *stream;
- g_debug ("Profile changed to %s for device %s",
- profile,
- mate_mixer_device_get_name (device));
+ stream = MATE_MIXER_STREAM (streams->data);
- mate_mixer_device_set_active_profile (device, profile);
+ if (mate_mixer_stream_get_device (stream) == device &&
+ mate_mixer_stream_get_num_channels (stream) >= 1) {
+ MateMixerStreamFlags flags;
+
+ flags = mate_mixer_stream_get_flags (stream);
+
+ if ((flags & (MATE_MIXER_STREAM_OUTPUT |
+ MATE_MIXER_STREAM_CLIENT)) == MATE_MIXER_STREAM_OUTPUT)
+ return stream;
+ }
+ streams = streams->next;
+ }
+ return FALSE;
}
static void
-on_test_speakers_clicked (GvcComboBox *widget, gpointer user_data)
+on_test_speakers_clicked (GvcComboBox *widget, GvcMixerDialog *dialog)
{
- GvcMixerDialog *dialog = GVC_MIXER_DIALOG (user_data);
- MateMixerDevice *device;
- GtkWidget *d, *speaker_test, *container;
- char *title;
+ GtkWidget *d,
+ *test,
+ *container;
+ gchar *title;
+ MateMixerDevice *device;
+ MateMixerStream *stream;
device = g_object_get_data (G_OBJECT (widget), "device");
- if (device == NULL) {
- g_warning ("Could not find card for combobox");
+ if (G_UNLIKELY (device == NULL)) {
+ g_warn_if_reached ();
+ return;
+ }
+
+ stream = find_device_test_stream (dialog, device);
+ if (G_UNLIKELY (stream == NULL)) {
+ g_warn_if_reached ();
return;
}
@@ -1418,92 +1468,139 @@ on_test_speakers_clicked (GvcComboBox *widget, gpointer user_data)
GTK_WINDOW (dialog),
GTK_DIALOG_MODAL |
GTK_DIALOG_DESTROY_WITH_PARENT,
+ "gtk-close",
+ GTK_RESPONSE_CLOSE,
NULL);
g_free (title);
- speaker_test = gvc_speaker_test_new (dialog->priv->control, device);
- gtk_widget_show (speaker_test);
+ gtk_window_set_resizable (GTK_WINDOW (d), FALSE);
+
+ test = gvc_speaker_test_new (stream);
+ gtk_widget_show (test);
+
container = gtk_dialog_get_content_area (GTK_DIALOG (d));
- gtk_container_add (GTK_CONTAINER (container), speaker_test);
+ gtk_container_add (GTK_CONTAINER (container), test);
gtk_dialog_run (GTK_DIALOG (d));
gtk_widget_destroy (d);
}
+static GtkWidget *
+create_profile_combo_box (GvcMixerDialog *dialog,
+ MateMixerDevice *device,
+ const gchar *name,
+ const GList *items,
+ const gchar *active)
+{
+ GtkWidget *combobox;
+
+ combobox = gvc_combo_box_new (name);
+
+ gvc_combo_box_set_profiles (GVC_COMBO_BOX (combobox), items);
+ gvc_combo_box_set_active (GVC_COMBO_BOX (combobox), active);
+
+ gvc_combo_box_set_size_group (GVC_COMBO_BOX (combobox),
+ dialog->priv->size_group,
+ FALSE);
+
+ g_object_set_data_full (G_OBJECT (combobox),
+ "device",
+ g_object_ref (device),
+ g_object_unref);
+
+ g_signal_connect (G_OBJECT (combobox),
+ "changed",
+ G_CALLBACK (on_combo_box_profile_changed),
+ dialog);
+
+ return combobox;
+}
+
static void
-on_card_selection_changed (GtkTreeSelection *selection,
- gpointer user_data)
+on_device_selection_changed (GtkTreeSelection *selection, GvcMixerDialog *dialog)
{
- GvcMixerDialog *dialog = GVC_MIXER_DIALOG (user_data);
- GtkTreeModel *model;
GtkTreeIter iter;
- const GList *profiles;
- gchar *name;
- MateMixerDevice *device;
- MateMixerDeviceProfile *profile;
+ gchar *name;
+ MateMixerDevice *device;
+ MateMixerBackendType backend;
- g_debug ("Card selection changed");
+ g_debug ("Device selection changed");
if (dialog->priv->hw_profile_combo != NULL) {
gtk_container_remove (GTK_CONTAINER (dialog->priv->hw_settings_box),
dialog->priv->hw_profile_combo);
+
dialog->priv->hw_profile_combo = NULL;
}
if (gtk_tree_selection_get_selected (selection, NULL, &iter) == FALSE)
return;
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->hw_treeview));
- gtk_tree_model_get (model, &iter,
+ gtk_tree_model_get (gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->hw_treeview)),
+ &iter,
HW_NAME_COLUMN, &name,
-1);
device = mate_mixer_control_get_device (dialog->priv->control, name);
- if (device == NULL) {
- g_warning ("Unable to find card for id: %s", name);
+ if (G_UNLIKELY (device == NULL)) {
+ g_warn_if_reached ();
g_free (name);
return;
}
g_free (name);
- profile = mate_mixer_device_get_active_profile (device);
- profiles = mate_mixer_device_list_profiles (device);
-
- dialog->priv->hw_profile_combo = gvc_combo_box_new (_("_Profile:"));
-
- g_object_set (G_OBJECT (dialog->priv->hw_profile_combo),
- "button-label",
- _("Test Speakers"),
- NULL);
+ backend = mate_mixer_control_get_backend_type (dialog->priv->control);
+
+ /* Speaker test is only possible on PulseAudio and profile changing is
+ * not supported on other backends by libmatemixer, so avoid displaying
+ * the combo box on other backends */
+ if (backend == MATE_MIXER_BACKEND_PULSEAUDIO) {
+ const GList *profiles;
+ const gchar *profile_name = NULL;
+ MateMixerStream *stream = NULL;
+
+ profiles = mate_mixer_device_list_profiles (device);
+ if (profiles != NULL) {
+ MateMixerDeviceProfile *profile;
+
+ profile = mate_mixer_device_get_active_profile (device);
+ if (G_UNLIKELY (profile == NULL)) {
+ /* Select the first profile if none is selected */
+ profile = MATE_MIXER_DEVICE_PROFILE (profiles->data);
+ mate_mixer_device_set_active_profile (device, profile);
+ }
- gvc_combo_box_set_profiles (GVC_COMBO_BOX (dialog->priv->hw_profile_combo),
- profiles);
- gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->hw_profile_combo),
- mate_mixer_device_profile_get_name (profile));
+ profile_name = mate_mixer_device_profile_get_name (profile);
+ }
- gtk_box_pack_start (GTK_BOX (dialog->priv->hw_settings_box),
- dialog->priv->hw_profile_combo,
- TRUE, TRUE, 6);
+ dialog->priv->hw_profile_combo =
+ create_profile_combo_box (dialog,
+ device,
+ _("_Profile:"),
+ profiles,
+ profile_name);
- g_object_set (G_OBJECT (dialog->priv->hw_profile_combo),
- "show-button",
- mate_mixer_device_profile_get_num_output_streams (profile) >= 1,
- NULL);
+ gtk_box_pack_start (GTK_BOX (dialog->priv->hw_settings_box),
+ dialog->priv->hw_profile_combo,
+ TRUE, TRUE, 6);
- gtk_widget_show (dialog->priv->hw_profile_combo);
+ /* Enable the speaker test button if the selected device
+ * is capable of sound output */
+ stream = find_device_test_stream (dialog, device);
+ if (stream != NULL) {
+ g_object_set (G_OBJECT (dialog->priv->hw_profile_combo),
+ "show-button", TRUE,
+ "button-label", _("Test Speakers"),
+ NULL);
- g_object_set_data (G_OBJECT (dialog->priv->hw_profile_combo),
- "device",
- g_object_ref (device));
+ g_signal_connect (G_OBJECT (dialog->priv->hw_profile_combo),
+ "button-clicked",
+ G_CALLBACK (on_test_speakers_clicked),
+ dialog);
+ }
- g_signal_connect (G_OBJECT (dialog->priv->hw_profile_combo),
- "changed",
- G_CALLBACK (on_profile_changed),
- dialog);
- g_signal_connect (G_OBJECT (dialog->priv->hw_profile_combo),
- "button-clicked",
- G_CALLBACK (on_test_speakers_clicked),
- dialog);
+ gtk_widget_show (dialog->priv->hw_profile_combo);
+ }
}
static void
@@ -1525,36 +1622,71 @@ on_notebook_switch_page (GtkNotebook *notebook,
}
static void
-card_to_text (GtkTreeViewColumn *column,
- GtkCellRenderer *cell,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer user_data)
+device_name_to_text (GtkTreeViewColumn *column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer user_data)
{
- gchar *description, *status, *profile, *str;
- gboolean sensitive;
+ gchar *description = NULL;
+ gchar *profile = NULL;
+ gchar *profile_status = NULL;
gtk_tree_model_get (model, iter,
HW_DESCRIPTION_COLUMN, &description,
- HW_STATUS_COLUMN, &status,
- HW_PROFILE_HUMAN_COLUMN, &profile,
- HW_SENSITIVE_COLUMN, &sensitive,
+ HW_PROFILE_COLUMN, &profile,
+ HW_STATUS_COLUMN, &profile_status,
-1);
- str = g_strdup_printf ("%s\n<i>%s</i>\n<i>%s</i>", description, status, profile);
- g_object_set (cell,
- "markup", str,
- "sensitive", sensitive,
- NULL);
- g_free (str);
+ if (profile != NULL) {
+ gchar *str;
+
+ if (G_LIKELY (profile_status != NULL))
+ str = g_strdup_printf ("%s\n<i>%s</i>\n<i>%s</i>",
+ description,
+ profile_status,
+ profile);
+ else
+ str = g_strdup_printf ("%s\n<i>%s</i>",
+ description,
+ profile);
+
+ g_object_set (cell, "markup", str, NULL);
+ g_free (str);
+ g_free (profile);
+ g_free (profile_status);
+ } else
+ g_object_set (cell, "text", description, NULL);
g_free (description);
- g_free (status);
- g_free (profile);
+}
+
+static gint
+compare_device_treeview_items (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
+{
+ gchar *desc_a = NULL;
+ gchar *desc_b = NULL;
+ gint result;
+
+ gtk_tree_model_get (model, a,
+ HW_DESCRIPTION_COLUMN, &desc_a,
+ -1);
+ gtk_tree_model_get (model, b,
+ HW_DESCRIPTION_COLUMN, &desc_b,
+ -1);
+
+ result = g_ascii_strcasecmp (desc_a, desc_b);
+
+ g_free (desc_a);
+ g_free (desc_b);
+ return result;
}
static GtkWidget *
-create_cards_treeview (GvcMixerDialog *dialog, GCallback on_changed)
+create_device_treeview (GvcMixerDialog *dialog, GCallback on_changed)
{
GtkWidget *treeview;
GtkListStore *store;
@@ -1576,37 +1708,41 @@ create_cards_treeview (GvcMixerDialog *dialog, GCallback on_changed)
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_BOOLEAN);
+ G_TYPE_STRING);
gtk_tree_view_set_model (GTK_TREE_VIEW (treeview),
GTK_TREE_MODEL (store));
renderer = gtk_cell_renderer_pixbuf_new ();
- g_object_set (G_OBJECT (renderer), "stock-size", GTK_ICON_SIZE_DIALOG, NULL);
+ g_object_set (G_OBJECT (renderer),
+ "stock-size",
+ GTK_ICON_SIZE_DIALOG,
+ NULL);
column = gtk_tree_view_column_new_with_attributes (NULL,
renderer,
"gicon", HW_ICON_COLUMN,
- "sensitive", HW_SENSITIVE_COLUMN,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
-
gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview), -1,
_("Name"),
gtk_cell_renderer_text_new (),
- card_to_text,
+ device_name_to_text,
NULL, NULL);
+ /* Keep the list of streams sorted by the name */
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+ HW_DESCRIPTION_COLUMN,
+ GTK_SORT_ASCENDING);
+
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store),
+ HW_DESCRIPTION_COLUMN,
+ compare_device_treeview_items,
+ NULL, NULL);
return treeview;
}
-static const guint tab_accel_keys[] = {
- GDK_1, GDK_2, GDK_3, GDK_4, GDK_5
-};
-
static void
dialog_accel_cb (GtkAccelGroup *accelgroup,
GObject *object,
@@ -1641,17 +1777,19 @@ gvc_mixer_dialog_constructor (GType type,
GtkWidget *box;
GtkWidget *sbox;
GtkWidget *ebox;
- GList *list;
GtkTreeSelection *selection;
GtkAccelGroup *accel_group;
GClosure *closure;
- gint i;
+ GtkTreeIter iter;
+ gint i;
+ GList *list;
object = G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->constructor (type,
n_construct_properties,
construct_params);
self = GVC_MIXER_DIALOG (object);
+
gtk_dialog_add_button (GTK_DIALOG (self), "gtk-close", GTK_RESPONSE_OK);
main_vbox = gtk_dialog_get_content_area (GTK_DIALOG (self));
@@ -1659,17 +1797,25 @@ gvc_mixer_dialog_constructor (GType type,
gtk_container_set_border_width (GTK_CONTAINER (self), 6);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ self->priv->output_stream_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+#else
self->priv->output_stream_box = gtk_hbox_new (FALSE, 12);
+#endif
+
alignment = gtk_alignment_new (0, 0, 1, 1);
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 12, 0, 0, 0);
gtk_container_add (GTK_CONTAINER (alignment), self->priv->output_stream_box);
gtk_box_pack_start (GTK_BOX (main_vbox),
alignment,
FALSE, FALSE, 0);
- self->priv->output_bar = create_bar (self, self->priv->size_group, TRUE);
+
+ self->priv->output_bar = create_bar (self, TRUE, TRUE);
gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->output_bar),
_("_Output volume: "));
+
gtk_widget_set_sensitive (self->priv->output_bar, FALSE);
+
gtk_box_pack_start (GTK_BOX (self->priv->output_stream_box),
self->priv->output_bar, TRUE, TRUE, 12);
@@ -1678,6 +1824,11 @@ gvc_mixer_dialog_constructor (GType type,
self->priv->notebook,
TRUE, TRUE, 0);
+ g_signal_connect (G_OBJECT (self->priv->notebook),
+ "switch-page",
+ G_CALLBACK (on_notebook_switch_page),
+ self);
+
gtk_container_set_border_width (GTK_CONTAINER (self->priv->notebook), 5);
/* Set up accels (borrowed from Empathy) */
@@ -1685,9 +1836,9 @@ gvc_mixer_dialog_constructor (GType type,
gtk_window_add_accel_group (GTK_WINDOW (self), accel_group);
for (i = 0; i < G_N_ELEMENTS (tab_accel_keys); i++) {
- closure = g_cclosure_new (G_CALLBACK (dialog_accel_cb),
- self,
- NULL);
+ closure = g_cclosure_new (G_CALLBACK (dialog_accel_cb),
+ self,
+ NULL);
gtk_accel_group_connect (accel_group,
tab_accel_keys[i],
GDK_MOD1_MASK,
@@ -1697,29 +1848,44 @@ gvc_mixer_dialog_constructor (GType type,
g_object_unref (accel_group);
- /* Effects page */
+ /* Create notebook pages */
+#if GTK_CHECK_VERSION (3, 0, 0)
+ self->priv->sound_effects_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+#else
self->priv->sound_effects_box = gtk_vbox_new (FALSE, 6);
+#endif
gtk_container_set_border_width (GTK_CONTAINER (self->priv->sound_effects_box), 12);
+
label = gtk_label_new (_("Sound Effects"));
gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
self->priv->sound_effects_box,
label);
- self->priv->effects_bar = create_bar (self, self->priv->size_group, TRUE);
+ self->priv->effects_bar = create_bar (self, TRUE, TRUE);
+ gtk_box_pack_start (GTK_BOX (self->priv->sound_effects_box),
+ self->priv->effects_bar, FALSE, FALSE, 0);
+
+ gvc_channel_bar_set_show_marks (GVC_CHANNEL_BAR (self->priv->effects_bar), FALSE);
+ gvc_channel_bar_set_extended (GVC_CHANNEL_BAR (self->priv->effects_bar), FALSE);
+
gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->effects_bar),
_("_Alert volume: "));
+
gtk_widget_set_sensitive (self->priv->effects_bar, FALSE);
- gtk_box_pack_start (GTK_BOX (self->priv->sound_effects_box),
- self->priv->effects_bar, FALSE, FALSE, 0);
self->priv->sound_theme_chooser = gvc_sound_theme_chooser_new ();
+
gtk_box_pack_start (GTK_BOX (self->priv->sound_effects_box),
self->priv->sound_theme_chooser,
TRUE, TRUE, 6);
- /* Hardware page */
+#if GTK_CHECK_VERSION (3, 0, 0)
+ self->priv->hw_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+#else
self->priv->hw_box = gtk_vbox_new (FALSE, 12);
+#endif
gtk_container_set_border_width (GTK_CONTAINER (self->priv->hw_box), 12);
+
label = gtk_label_new (_("Hardware"));
gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
self->priv->hw_box,
@@ -1727,7 +1893,7 @@ gvc_mixer_dialog_constructor (GType type,
box = gtk_frame_new (_("C_hoose a device to configure:"));
label = gtk_frame_get_label_widget (GTK_FRAME (box));
- _gtk_label_make_bold (GTK_LABEL (label));
+ make_label_bold (GTK_LABEL (label));
gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
gtk_box_pack_start (GTK_BOX (self->priv->hw_box), box, TRUE, TRUE, 0);
@@ -1736,8 +1902,8 @@ gvc_mixer_dialog_constructor (GType type,
gtk_container_add (GTK_CONTAINER (box), alignment);
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0);
- self->priv->hw_treeview = create_cards_treeview (self,
- G_CALLBACK (on_card_selection_changed));
+ self->priv->hw_treeview = create_device_treeview (self,
+ G_CALLBACK (on_device_selection_changed));
gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->priv->hw_treeview);
box = gtk_scrolled_window_new (NULL, NULL);
@@ -1754,21 +1920,32 @@ gvc_mixer_dialog_constructor (GType type,
box = gtk_frame_new (_("Settings for the selected device:"));
label = gtk_frame_get_label_widget (GTK_FRAME (box));
- _gtk_label_make_bold (GTK_LABEL (label));
+ make_label_bold (GTK_LABEL (label));
gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
gtk_box_pack_start (GTK_BOX (self->priv->hw_box), box, FALSE, TRUE, 12);
+
+#if GTK_CHECK_VERSION (3, 0, 0)
+ self->priv->hw_settings_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+#else
self->priv->hw_settings_box = gtk_vbox_new (FALSE, 12);
+#endif
+
gtk_container_add (GTK_CONTAINER (box), self->priv->hw_settings_box);
- /* Input page */
+#if GTK_CHECK_VERSION (3, 0, 0)
+ self->priv->input_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+#else
self->priv->input_box = gtk_vbox_new (FALSE, 12);
+#endif
+
gtk_container_set_border_width (GTK_CONTAINER (self->priv->input_box), 12);
+
label = gtk_label_new (_("Input"));
gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
self->priv->input_box,
label);
- self->priv->input_bar = create_bar (self, self->priv->size_group, TRUE);
+ self->priv->input_bar = create_bar (self, TRUE, TRUE);
gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->input_bar),
_("_Input volume: "));
gvc_channel_bar_set_low_icon_name (GVC_CHANNEL_BAR (self->priv->input_bar),
@@ -1776,6 +1953,7 @@ gvc_mixer_dialog_constructor (GType type,
gvc_channel_bar_set_high_icon_name (GVC_CHANNEL_BAR (self->priv->input_bar),
"audio-input-microphone-high");
gtk_widget_set_sensitive (self->priv->input_bar, FALSE);
+
alignment = gtk_alignment_new (0, 0, 1, 1);
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0);
gtk_container_add (GTK_CONTAINER (alignment), self->priv->input_bar);
@@ -1783,12 +1961,19 @@ gvc_mixer_dialog_constructor (GType type,
alignment,
FALSE, FALSE, 0);
- box = gtk_hbox_new (FALSE, 6);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ sbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ ebox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+#else
+ box = gtk_hbox_new (FALSE, 6);
+ sbox = gtk_hbox_new (FALSE, 6);
+ ebox = gtk_hbox_new (FALSE, 6);
+#endif
+
gtk_box_pack_start (GTK_BOX (self->priv->input_box),
box,
FALSE, FALSE, 6);
-
- sbox = gtk_hbox_new (FALSE, 6);
gtk_box_pack_start (GTK_BOX (box),
sbox,
FALSE, FALSE, 0);
@@ -1808,20 +1993,23 @@ gvc_mixer_dialog_constructor (GType type,
self->priv->input_level_bar,
TRUE, TRUE, 6);
- ebox = gtk_hbox_new (FALSE, 6);
gtk_box_pack_start (GTK_BOX (box),
ebox,
FALSE, FALSE, 0);
gtk_size_group_add_widget (self->priv->size_group, ebox);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ self->priv->input_settings_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+#else
self->priv->input_settings_box = gtk_hbox_new (FALSE, 6);
+#endif
gtk_box_pack_start (GTK_BOX (self->priv->input_box),
self->priv->input_settings_box,
FALSE, FALSE, 0);
box = gtk_frame_new (_("C_hoose a device for sound input:"));
label = gtk_frame_get_label_widget (GTK_FRAME (box));
- _gtk_label_make_bold (GTK_LABEL (label));
+ make_label_bold (GTK_LABEL (label));
gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
gtk_box_pack_start (GTK_BOX (self->priv->input_box), box, TRUE, TRUE, 0);
@@ -1830,8 +2018,9 @@ gvc_mixer_dialog_constructor (GType type,
gtk_container_add (GTK_CONTAINER (box), alignment);
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0);
- self->priv->input_treeview = create_stream_treeview (self,
- G_CALLBACK (on_input_radio_toggled));
+ self->priv->input_treeview =
+ create_stream_treeview (self, G_CALLBACK (on_input_radio_toggled));
+
gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->priv->input_treeview);
box = gtk_scrolled_window_new (NULL, NULL);
@@ -1856,7 +2045,7 @@ gvc_mixer_dialog_constructor (GType type,
box = gtk_frame_new (_("C_hoose a device for sound output:"));
label = gtk_frame_get_label_widget (GTK_FRAME (box));
- _gtk_label_make_bold (GTK_LABEL (label));
+ make_label_bold (GTK_LABEL (label));
gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
gtk_box_pack_start (GTK_BOX (self->priv->output_box), box, TRUE, TRUE, 0);
@@ -1883,26 +2072,43 @@ gvc_mixer_dialog_constructor (GType type,
box = gtk_frame_new (_("Settings for the selected device:"));
label = gtk_frame_get_label_widget (GTK_FRAME (box));
- _gtk_label_make_bold (GTK_LABEL (label));
+ make_label_bold (GTK_LABEL (label));
gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
gtk_box_pack_start (GTK_BOX (self->priv->output_box), box, FALSE, FALSE, 12);
self->priv->output_settings_box = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (box), self->priv->output_settings_box);
+ self->priv->output_settings_frame = box;
+
/* Applications */
- self->priv->applications_scrolled_window = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (self->priv->applications_scrolled_window),
- GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (self->priv->applications_scrolled_window),
+ self->priv->applications_window = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (self->priv->applications_window),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
+
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (self->priv->applications_window),
GTK_SHADOW_IN);
+
+#if GTK_CHECK_VERSION (3, 0, 0)
+ self->priv->applications_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+#else
self->priv->applications_box = gtk_vbox_new (FALSE, 12);
+#endif
gtk_container_set_border_width (GTK_CONTAINER (self->priv->applications_box), 12);
- gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (self->priv->applications_scrolled_window),
+
+#if GTK_CHECK_VERSION (3, 8, 0)
+ gtk_container_add (GTK_CONTAINER (self->priv->applications_window),
+ self->priv->applications_box);
+#else
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (self->priv->applications_window),
self->priv->applications_box);
+#endif
+
label = gtk_label_new (_("Applications"));
gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
- self->priv->applications_scrolled_window,
+ self->priv->applications_window,
label);
+
self->priv->no_apps_label = gtk_label_new (_("No application is currently playing or recording audio."));
gtk_box_pack_start (GTK_BOX (self->priv->applications_box),
self->priv->no_apps_label,
@@ -1910,6 +2116,8 @@ gvc_mixer_dialog_constructor (GType type,
gtk_widget_show_all (main_vbox);
+ // XXX subscribe to cached stream stuff, in case event stream is not found
+
list = (GList *) mate_mixer_control_list_streams (self->priv->control);
while (list) {
add_stream (self, MATE_MIXER_STREAM (list->data));
@@ -1922,10 +2130,30 @@ gvc_mixer_dialog_constructor (GType type,
list = list->next;
}
- g_signal_connect (G_OBJECT (self->priv->notebook),
- "switch-page",
- G_CALLBACK (on_notebook_switch_page),
- self);
+ /* Find an event role stream */
+ list = (GList *) mate_mixer_control_list_cached_streams (self->priv->control);
+ while (list) {
+ MateMixerClientStreamRole role;
+
+ role = mate_mixer_client_stream_get_role (MATE_MIXER_CLIENT_STREAM (list->data));
+
+ if (role == MATE_MIXER_CLIENT_STREAM_ROLE_EVENT)
+ add_stream (self, MATE_MIXER_STREAM (list->data));
+
+ list = list->next;
+ }
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->hw_treeview));
+
+ /* Select the first device in the list */
+ // XXX handle no devices
+ if (gtk_tree_selection_get_selected (selection, NULL, NULL) == FALSE) {
+ GtkTreeModel *model =
+ gtk_tree_view_get_model (GTK_TREE_VIEW (self->priv->hw_treeview));
+
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ gtk_tree_selection_select_iter (selection, &iter);
+ }
return object;
}
@@ -1948,28 +2176,36 @@ gvc_mixer_dialog_set_control (GvcMixerDialog *dialog, MateMixerControl *control)
dialog->priv->control = g_object_ref (control);
- g_signal_connect (dialog->priv->control,
+ g_signal_connect (G_OBJECT (dialog->priv->control),
"stream-added",
G_CALLBACK (on_control_stream_added),
dialog);
- g_signal_connect (dialog->priv->control,
+ g_signal_connect (G_OBJECT (dialog->priv->control),
+ "cached-stream-added",
+ G_CALLBACK (on_control_stream_added),
+ dialog);
+ g_signal_connect (G_OBJECT (dialog->priv->control),
"stream-removed",
G_CALLBACK (on_control_stream_removed),
dialog);
- g_signal_connect (dialog->priv->control,
+ g_signal_connect (G_OBJECT (dialog->priv->control),
+ "cached-stream-removed",
+ G_CALLBACK (on_control_cached_stream_removed),
+ dialog);
+ g_signal_connect (G_OBJECT (dialog->priv->control),
"device-added",
G_CALLBACK (on_control_device_added),
dialog);
- g_signal_connect (dialog->priv->control,
+ g_signal_connect (G_OBJECT (dialog->priv->control),
"device-removed",
G_CALLBACK (on_control_device_removed),
dialog);
- g_signal_connect (dialog->priv->control,
+ g_signal_connect (G_OBJECT (dialog->priv->control),
"notify::default-output",
G_CALLBACK (on_control_default_output_notify),
dialog);
- g_signal_connect (dialog->priv->control,
+ g_signal_connect (G_OBJECT (dialog->priv->control),
"notify::default-input",
G_CALLBACK (on_control_default_input_notify),
dialog);
@@ -1986,7 +2222,7 @@ gvc_mixer_dialog_set_property (GObject *object,
GvcMixerDialog *self = GVC_MIXER_DIALOG (object);
switch (prop_id) {
- case PROP_MIXER_CONTROL:
+ case PROP_CONTROL:
gvc_mixer_dialog_set_control (self, g_value_get_object (value));
break;
default:
@@ -2004,7 +2240,7 @@ gvc_mixer_dialog_get_property (GObject *object,
GvcMixerDialog *self = GVC_MIXER_DIALOG (object);
switch (prop_id) {
- case PROP_MIXER_CONTROL:
+ case PROP_CONTROL:
g_value_set_object (value, gvc_mixer_dialog_get_control (self));
break;
default:
@@ -2050,7 +2286,7 @@ gvc_mixer_dialog_class_init (GvcMixerDialogClass *klass)
object_class->get_property = gvc_mixer_dialog_get_property;
g_object_class_install_property (object_class,
- PROP_MIXER_CONTROL,
+ PROP_CONTROL,
g_param_spec_object ("control",
"Control",
"MateMixer control",
@@ -2068,7 +2304,6 @@ gvc_mixer_dialog_init (GvcMixerDialog *dialog)
dialog->priv->bars = g_hash_table_new (g_str_hash, g_str_equal);
dialog->priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
- dialog->priv->apps_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
}
static void
@@ -2102,7 +2337,7 @@ gvc_mixer_dialog_set_page (GvcMixerDialog *self, const gchar *page)
if (page != NULL) {
if (g_str_equal (page, "effects"))
- num = PAGE_EVENTS;
+ num = PAGE_EFFECTS;
else if (g_str_equal (page, "hardware"))
num = PAGE_HARDWARE;
else if (g_str_equal (page, "input"))
diff --git a/mate-volume-control/src/gvc-mixer-dialog.h b/mate-volume-control/src/gvc-mixer-dialog.h
index cc6e665..c494c1a 100644
--- a/mate-volume-control/src/gvc-mixer-dialog.h
+++ b/mate-volume-control/src/gvc-mixer-dialog.h
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
*
* 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
@@ -23,6 +24,7 @@
#include <glib.h>
#include <glib-object.h>
+
#include <libmatemixer/matemixer.h>
G_BEGIN_DECLS
diff --git a/mate-volume-control/src/gvc-speaker-test.c b/mate-volume-control/src/gvc-speaker-test.c
index 25b836c..61fd510 100644
--- a/mate-volume-control/src/gvc-speaker-test.c
+++ b/mate-volume-control/src/gvc-speaker-test.c
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2009 Bastien Nocera
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
*
* 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
@@ -22,7 +23,9 @@
#include <glib.h>
#include <glib/gi18n.h>
+#include <glib-object.h>
#include <gtk/gtk.h>
+
#include <canberra.h>
#include <libmatemixer/matemixer.h>
@@ -31,51 +34,88 @@
#endif
#include "gvc-speaker-test.h"
+#include "mvc-helpers.h"
#define GVC_SPEAKER_TEST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_SPEAKER_TEST, GvcSpeakerTestPrivate))
struct _GvcSpeakerTestPrivate
{
- // XXX pulse constant
- GtkWidget *channel_controls[PA_CHANNEL_POSITION_MAX];
+ GArray *controls;
ca_context *canberra;
MateMixerControl *control;
- MateMixerDevice *device;
+ MateMixerStream *stream;
};
enum {
PROP_0,
- PROP_CONTROL,
- PROP_DEVICE,
+ PROP_STREAM,
N_PROPERTIES
};
static GParamSpec *properties[N_PROPERTIES] = { NULL, };
-static void gvc_speaker_test_class_init (GvcSpeakerTestClass *klass);
-static void gvc_speaker_test_init (GvcSpeakerTest *speaker_test);
-static void gvc_speaker_test_dispose (GObject *object);
-static void gvc_speaker_test_finalize (GObject *object);
-static void update_channel_map (GvcSpeakerTest *speaker_test);
+static void gvc_speaker_test_class_init (GvcSpeakerTestClass *klass);
+static void gvc_speaker_test_init (GvcSpeakerTest *test);
+static void gvc_speaker_test_dispose (GObject *object);
+static void gvc_speaker_test_finalize (GObject *object);
+#if GTK_CHECK_VERSION (3, 4, 0)
+G_DEFINE_TYPE (GvcSpeakerTest, gvc_speaker_test, GTK_TYPE_GRID)
+#else
G_DEFINE_TYPE (GvcSpeakerTest, gvc_speaker_test, GTK_TYPE_TABLE)
+#endif
-static const int position_table[] = {
+typedef struct {
+ MateMixerChannelPosition position;
+ guint left;
+ guint top;
+} TablePosition;
+
+static const TablePosition positions[] = {
/* Position, X, Y */
- MATE_MIXER_CHANNEL_FRONT_LEFT, 0, 0,
- MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER, 1, 0,
- MATE_MIXER_CHANNEL_FRONT_CENTER, 2, 0,
- MATE_MIXER_CHANNEL_MONO, 2, 0,
- MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER, 3, 0,
- MATE_MIXER_CHANNEL_FRONT_RIGHT, 4, 0,
- MATE_MIXER_CHANNEL_SIDE_LEFT, 0, 1,
- MATE_MIXER_CHANNEL_SIDE_RIGHT, 4, 1,
- MATE_MIXER_CHANNEL_BACK_LEFT, 0, 2,
- MATE_MIXER_CHANNEL_BACK_CENTER, 2, 2,
- MATE_MIXER_CHANNEL_BACK_RIGHT, 4, 2,
- MATE_MIXER_CHANNEL_LFE, 3, 2
+ { MATE_MIXER_CHANNEL_FRONT_LEFT, 0, 0, },
+ { MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER, 1, 0, },
+ { MATE_MIXER_CHANNEL_FRONT_CENTER, 2, 0, },
+ { MATE_MIXER_CHANNEL_MONO, 2, 0, },
+ { MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER, 3, 0, },
+ { MATE_MIXER_CHANNEL_FRONT_RIGHT, 4, 0, },
+ { MATE_MIXER_CHANNEL_SIDE_LEFT, 0, 1, },
+ { MATE_MIXER_CHANNEL_SIDE_RIGHT, 4, 1, },
+ { MATE_MIXER_CHANNEL_BACK_LEFT, 0, 2, },
+ { MATE_MIXER_CHANNEL_BACK_CENTER, 2, 2, },
+ { MATE_MIXER_CHANNEL_BACK_RIGHT, 4, 2, },
+ { MATE_MIXER_CHANNEL_LFE, 3, 2 }
};
+MateMixerStream *
+gvc_speaker_test_get_stream (GvcSpeakerTest *test)
+{
+ g_return_val_if_fail (GVC_IS_SPEAKER_TEST (test), NULL);
+
+ return test->priv->stream;
+}
+
+static void
+gvc_speaker_test_set_stream (GvcSpeakerTest *test, MateMixerStream *stream)
+{
+ guint i;
+ const gchar *name;
+
+ name = mate_mixer_stream_get_name (stream);
+
+ ca_context_change_device (test->priv->canberra, name);
+
+ for (i = 0; i < G_N_ELEMENTS (positions); i++) {
+ gboolean has_position =
+ mate_mixer_stream_has_channel_position (stream, positions[i].position);
+
+ gtk_widget_set_visible (g_array_index (test->priv->controls, GtkWidget *, i),
+ has_position);
+ }
+
+ test->priv->stream = g_object_ref (stream);
+}
+
static void
gvc_speaker_test_set_property (GObject *object,
guint prop_id,
@@ -85,20 +125,8 @@ gvc_speaker_test_set_property (GObject *object,
GvcSpeakerTest *self = GVC_SPEAKER_TEST (object);
switch (prop_id) {
- case PROP_CONTROL:
- /* Construct-only object */
- self->priv->control = g_value_dup_object (value);
- if (self->priv->control != NULL)
- update_channel_map (self);
- break;
-
- case PROP_DEVICE:
- if (self->priv->device)
- g_object_unref (self->priv->device);
-
- self->priv->device = g_value_dup_object (value);
- if (self->priv->device != NULL)
- update_channel_map (self);
+ case PROP_STREAM:
+ gvc_speaker_test_set_stream (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -115,11 +143,8 @@ gvc_speaker_test_get_property (GObject *object,
GvcSpeakerTest *self = GVC_SPEAKER_TEST (object);
switch (prop_id) {
- case PROP_CONTROL:
- g_value_set_object (value, self->priv->control);
- break;
- case PROP_DEVICE:
- g_value_set_object (value, self->priv->device);
+ case PROP_STREAM:
+ g_value_set_object (value, self->priv->stream);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -137,19 +162,14 @@ gvc_speaker_test_class_init (GvcSpeakerTestClass *klass)
object_class->set_property = gvc_speaker_test_set_property;
object_class->get_property = gvc_speaker_test_get_property;
- properties[PROP_CONTROL] =
- g_param_spec_object ("control",
- "Control",
- "The mixer controller",
- MATE_MIXER_TYPE_CONTROL,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
-
- properties[PROP_DEVICE] =
- g_param_spec_object ("device",
- "Device",
- "The mixer device",
- MATE_MIXER_TYPE_DEVICE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+ properties[PROP_STREAM] =
+ g_param_spec_object ("stream",
+ "Stream",
+ "MateMixer stream",
+ MATE_MIXER_TYPE_STREAM,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
@@ -188,23 +208,41 @@ icon_name (MateMixerChannelPosition position, gboolean playing)
{
switch (position) {
case MATE_MIXER_CHANNEL_FRONT_LEFT:
- return playing ? "audio-speaker-left-testing" : "audio-speaker-left";
+ return playing
+ ? "audio-speaker-left-testing"
+ : "audio-speaker-left";
case MATE_MIXER_CHANNEL_FRONT_RIGHT:
- return playing ? "audio-speaker-right-testing" : "audio-speaker-right";
+ return playing
+ ? "audio-speaker-right-testing"
+ : "audio-speaker-right";
case MATE_MIXER_CHANNEL_FRONT_CENTER:
- return playing ? "audio-speaker-center-testing" : "audio-speaker-center";
+ return playing
+ ? "audio-speaker-center-testing"
+ : "audio-speaker-center";
case MATE_MIXER_CHANNEL_BACK_LEFT:
- return playing ? "audio-speaker-left-back-testing" : "audio-speaker-left-back";
+ return playing
+ ? "audio-speaker-left-back-testing"
+ : "audio-speaker-left-back";
case MATE_MIXER_CHANNEL_BACK_RIGHT:
- return playing ? "audio-speaker-right-back-testing" : "audio-speaker-right-back";
+ return playing
+ ? "audio-speaker-right-back-testing"
+ : "audio-speaker-right-back";
case MATE_MIXER_CHANNEL_BACK_CENTER:
- return playing ? "audio-speaker-center-back-testing" : "audio-speaker-center-back";
+ return playing
+ ? "audio-speaker-center-back-testing"
+ : "audio-speaker-center-back";
case MATE_MIXER_CHANNEL_LFE:
- return playing ? "audio-subwoofer-testing" : "audio-subwoofer";
+ return playing
+ ? "audio-subwoofer-testing"
+ : "audio-subwoofer";
case MATE_MIXER_CHANNEL_SIDE_LEFT:
- return playing ? "audio-speaker-left-side-testing" : "audio-speaker-left-side";
+ return playing
+ ? "audio-speaker-left-side-testing"
+ : "audio-speaker-left-side";
case MATE_MIXER_CHANNEL_SIDE_RIGHT:
- return playing ? "audio-speaker-right-side-testing" : "audio-speaker-right-side";
+ return playing
+ ? "audio-speaker-right-side-testing"
+ : "audio-speaker-right-side";
default:
return NULL;
}
@@ -215,92 +253,20 @@ update_button (GtkWidget *control)
{
GtkWidget *button;
GtkWidget *image;
- pa_channel_position_t position;
- gboolean playing;
+ gboolean playing;
+ MateMixerChannelPosition position;
button = g_object_get_data (G_OBJECT (control), "button");
- image = g_object_get_data (G_OBJECT (control), "image");
- position = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (control), "position"));
- playing = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (control), "playing"));
- gtk_button_set_label (GTK_BUTTON (button), playing ? _("Stop") : _("Test"));
- gtk_image_set_from_icon_name (GTK_IMAGE (image), icon_name (position, playing), GTK_ICON_SIZE_DIALOG);
-}
+ image = g_object_get_data (G_OBJECT (control), "image");
-static const char *
-channel_position_string (MateMixerChannelPosition position, gboolean pretty)
-{
-#ifdef HAVE_PULSEAUDIO
- pa_channel_position_t pa_position;
+ position = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (control), "position"));
+ playing = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (control), "playing"));
- switch (position) {
- case MATE_MIXER_CHANNEL_MONO:
- pa_position = PA_CHANNEL_POSITION_MONO;
- break;
- case MATE_MIXER_CHANNEL_FRONT_LEFT:
- pa_position = PA_CHANNEL_POSITION_FRONT_LEFT;
- break;
- case MATE_MIXER_CHANNEL_FRONT_RIGHT:
- pa_position = PA_CHANNEL_POSITION_FRONT_RIGHT;
- break;
- case MATE_MIXER_CHANNEL_FRONT_CENTER:
- pa_position = PA_CHANNEL_POSITION_FRONT_CENTER;
- break;
- case MATE_MIXER_CHANNEL_LFE:
- pa_position = PA_CHANNEL_POSITION_LFE;
- break;
- case MATE_MIXER_CHANNEL_BACK_LEFT:
- pa_position = PA_CHANNEL_POSITION_REAR_LEFT;
- break;
- case MATE_MIXER_CHANNEL_BACK_RIGHT:
- pa_position = PA_CHANNEL_POSITION_REAR_RIGHT;
- break;
- case MATE_MIXER_CHANNEL_BACK_CENTER:
- pa_position = PA_CHANNEL_POSITION_REAR_CENTER;
- break;
- case MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER:
- pa_position = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
- break;
- case MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER:
- pa_position = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
- break;
- case MATE_MIXER_CHANNEL_SIDE_LEFT:
- pa_position = PA_CHANNEL_POSITION_SIDE_LEFT;
- break;
- case MATE_MIXER_CHANNEL_SIDE_RIGHT:
- pa_position = PA_CHANNEL_POSITION_SIDE_RIGHT;
- break;
- case MATE_MIXER_CHANNEL_TOP_FRONT_LEFT:
- pa_position = PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
- break;
- case MATE_MIXER_CHANNEL_TOP_FRONT_RIGHT:
- pa_position = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
- break;
- case MATE_MIXER_CHANNEL_TOP_FRONT_CENTER:
- pa_position = PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
- break;
- case MATE_MIXER_CHANNEL_TOP_CENTER:
- pa_position = PA_CHANNEL_POSITION_TOP_CENTER;
- break;
- case MATE_MIXER_CHANNEL_TOP_BACK_LEFT:
- pa_position = PA_CHANNEL_POSITION_TOP_REAR_LEFT;
- break;
- case MATE_MIXER_CHANNEL_TOP_BACK_RIGHT:
- pa_position = PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
- break;
- case MATE_MIXER_CHANNEL_TOP_BACK_CENTER:
- pa_position = PA_CHANNEL_POSITION_TOP_REAR_CENTER;
- break;
- default:
- pa_position = PA_CHANNEL_POSITION_INVALID;
- break;
- }
+ gtk_button_set_label (GTK_BUTTON (button), playing ? _("Stop") : _("Test"));
- if (pretty)
- return pa_channel_position_to_pretty_string (pa_position);
- else
- return pa_channel_position_to_string (pa_position);
-#endif
- return NULL;
+ gtk_image_set_from_icon_name (GTK_IMAGE (image),
+ icon_name (position, playing),
+ GTK_ICON_SIZE_DIALOG);
}
static gboolean
@@ -343,19 +309,20 @@ on_test_button_clicked (GtkButton *button, GtkWidget *control)
g_object_set_data (G_OBJECT (control), "playing", GINT_TO_POINTER (FALSE));
} else {
MateMixerChannelPosition position;
- const char *name;
+ const gchar *name;
ca_proplist *proplist;
position = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (control), "position"));
ca_proplist_create (&proplist);
- ca_proplist_sets (proplist, CA_PROP_MEDIA_ROLE, "test");
+ ca_proplist_sets (proplist,
+ CA_PROP_MEDIA_ROLE, "test");
ca_proplist_sets (proplist,
CA_PROP_MEDIA_NAME,
- channel_position_string (position, TRUE));
+ mvc_channel_position_to_pretty_string (position));
ca_proplist_sets (proplist,
CA_PROP_CANBERRA_FORCE_CHANNEL,
- channel_position_string (position, FALSE));
+ mvc_channel_position_to_string (position));
ca_proplist_sets (proplist, CA_PROP_CANBERRA_ENABLE, "1");
@@ -374,23 +341,30 @@ on_test_button_clicked (GtkButton *button, GtkWidget *control)
ca_proplist_sets(proplist, CA_PROP_EVENT_ID, "bell-window-system");
playing = ca_context_play_full (canberra, 1, proplist, finish_cb, control) >= 0;
}
- g_object_set_data (G_OBJECT (control), "playing", GINT_TO_POINTER(playing));
+
+ g_object_set_data (G_OBJECT (control), "playing", GINT_TO_POINTER (playing));
}
update_button (control);
}
static GtkWidget *
-channel_control_new (ca_context *canberra, MateMixerChannelPosition position)
+create_control (ca_context *canberra, MateMixerChannelPosition position)
{
- GtkWidget *control;
- GtkWidget *box;
- GtkWidget *label;
- GtkWidget *image;
- GtkWidget *test_button;
- const char *name;
-
+ GtkWidget *control;
+ GtkWidget *box;
+ GtkWidget *label;
+ GtkWidget *image;
+ GtkWidget *test_button;
+ const gchar *name;
+
+#if GTK_CHECK_VERSION (3, 0, 0)
+ control = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+#else
control = gtk_vbox_new (FALSE, 6);
+ box = gtk_hbox_new (FALSE, 0);
+#endif
g_object_set_data (G_OBJECT (control), "playing", GINT_TO_POINTER (FALSE));
g_object_set_data (G_OBJECT (control), "position", GINT_TO_POINTER (position));
g_object_set_data (G_OBJECT (control), "canberra", canberra);
@@ -403,16 +377,17 @@ channel_control_new (ca_context *canberra, MateMixerChannelPosition position)
g_object_set_data (G_OBJECT (control), "image", image);
gtk_box_pack_start (GTK_BOX (control), image, FALSE, FALSE, 0);
- label = gtk_label_new (channel_position_string (position, TRUE));
+ label = gtk_label_new (mvc_channel_position_to_pretty_string (position));
gtk_box_pack_start (GTK_BOX (control), label, FALSE, FALSE, 0);
test_button = gtk_button_new_with_label (_("Test"));
- g_signal_connect (G_OBJECT (test_button), "clicked",
- G_CALLBACK (on_test_button_clicked), control);
+ g_signal_connect (G_OBJECT (test_button),
+ "clicked",
+ G_CALLBACK (on_test_button_clicked),
+ control);
g_object_set_data (G_OBJECT (control), "button", test_button);
- box = gtk_hbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (box), test_button, TRUE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (control), box, FALSE, FALSE, 0);
@@ -422,80 +397,60 @@ channel_control_new (ca_context *canberra, MateMixerChannelPosition position)
}
static void
-create_channel_controls (GvcSpeakerTest *test)
+create_controls (GvcSpeakerTest *test)
{
guint i;
- for (i = 0; i < G_N_ELEMENTS (position_table); i += 3) {
- test->priv->channel_controls[position_table[i]] =
- channel_control_new (test->priv->canberra,
- (MateMixerChannelPosition) position_table[i]);
+ for (i = 0; i < G_N_ELEMENTS (positions); i++) {
+ GtkWidget *control = create_control (test->priv->canberra, positions[i].position);
+#if GTK_CHECK_VERSION (3, 4, 0)
+ gtk_grid_attach (GTK_GRID (test),
+ control,
+ positions[i].left,
+ positions[i].top,
+ 1, 1);
+#else
gtk_table_attach (GTK_TABLE (test),
- test->priv->channel_controls[position_table[i]],
- position_table[i+1],
- position_table[i+1]+1,
- position_table[i+2],
- position_table[i+2]+1,
+ control,
+ positions[i].left,
+ positions[i].left + 1,
+ positions[i].top,
+ positions[i].top + 1,
GTK_EXPAND, GTK_EXPAND, 0, 0);
+#endif
+ g_array_insert_val (test->priv->controls, i, control);
}
}
-static MateMixerStream *
-get_device_output_stream (MateMixerControl *control, MateMixerDevice *device)
-{
- MateMixerStream *stream;
- const GList *streams;
-
- streams = mate_mixer_control_list_streams (control);
- while (streams) {
- stream = MATE_MIXER_STREAM (streams->data);
-
- if (mate_mixer_stream_get_device (stream) == device) {
- if ((mate_mixer_stream_get_flags (stream) &
- (MATE_MIXER_STREAM_OUTPUT |
- MATE_MIXER_STREAM_CLIENT)) == MATE_MIXER_STREAM_OUTPUT)
- break;
- }
- stream = NULL;
- streams = streams->next;
- }
-
- return stream;
-}
-
static void
-update_channel_map (GvcSpeakerTest *test)
+gvc_speaker_test_init (GvcSpeakerTest *test)
{
- MateMixerStream *stream;
- guint i;
+ GtkWidget *face;
- if (test->priv->control == NULL ||
- test->priv->device == NULL)
- return;
+ test->priv = GVC_SPEAKER_TEST_GET_PRIVATE (test);
- stream = get_device_output_stream (test->priv->control, test->priv->device);
- if (G_UNLIKELY (stream == NULL)) {
- g_debug ("Failed to find an output stream for sound device %s",
- mate_mixer_device_get_name (test->priv->device));
- return;
- }
+ gtk_container_set_border_width (GTK_CONTAINER (test), 12);
- ca_context_change_device (test->priv->canberra,
- mate_mixer_stream_get_name (stream));
+ face = gtk_image_new_from_icon_name ("face-smile", GTK_ICON_SIZE_DIALOG);
- for (i = 0; i < G_N_ELEMENTS (position_table); i += 3)
- gtk_widget_set_visible (test->priv->channel_controls[position_table[i]],
- mate_mixer_stream_has_position (stream,
- position_table[i]));
-}
+#if GTK_CHECK_VERSION (3, 4, 0)
+ gtk_grid_attach (GTK_GRID (test),
+ face,
+ 1, 1,
+ 3, 1);
-static void
-gvc_speaker_test_init (GvcSpeakerTest *test)
-{
- GtkWidget *icon;
- test->priv = GVC_SPEAKER_TEST_GET_PRIVATE (test);
+ gtk_grid_set_baseline_row (GTK_GRID (test), 1);
+#else
+ gtk_table_attach (GTK_TABLE (test),
+ face,
+ 2, 3, 1, 2,
+ GTK_EXPAND,
+ GTK_EXPAND,
+ 0, 0);
+#endif
+ gtk_widget_show (face);
ca_context_create (&test->priv->canberra);
@@ -505,31 +460,15 @@ gvc_speaker_test_init (GvcSpeakerTest *test)
ca_context_set_driver (test->priv->canberra, "pulse");
ca_context_change_props (test->priv->canberra,
- CA_PROP_APPLICATION_NAME, _("MATE Volume Control Applet"),
CA_PROP_APPLICATION_ID, "org.mate.VolumeControl",
+ CA_PROP_APPLICATION_NAME, _("Volume Control"),
CA_PROP_APPLICATION_VERSION, VERSION,
CA_PROP_APPLICATION_ICON_NAME, "multimedia-volume-control",
NULL);
- gtk_table_resize (GTK_TABLE (test), 3, 5);
-
- gtk_container_set_border_width (GTK_CONTAINER (test), 12);
-
- gtk_table_set_homogeneous (GTK_TABLE (test), TRUE);
- gtk_table_set_row_spacings (GTK_TABLE (test), 12);
- gtk_table_set_col_spacings (GTK_TABLE (test), 12);
-
- create_channel_controls (test);
-
- icon = gtk_image_new_from_icon_name ("computer", GTK_ICON_SIZE_DIALOG);
+ test->priv->controls = g_array_new (FALSE, FALSE, sizeof (GtkWidget *));
- gtk_table_attach (GTK_TABLE (test), icon,
- 2, 3, 1, 2,
- GTK_EXPAND,
- GTK_EXPAND,
- 0, 0);
-
- gtk_widget_show (icon);
+ create_controls (test);
}
static void
@@ -539,8 +478,7 @@ gvc_speaker_test_dispose (GObject *object)
test = GVC_SPEAKER_TEST (object);
- g_clear_object (&test->priv->control);
- g_clear_object (&test->priv->device);
+ g_clear_object (&test->priv->stream);
G_OBJECT_CLASS (gvc_speaker_test_parent_class)->dispose (object);
}
@@ -558,16 +496,24 @@ gvc_speaker_test_finalize (GObject *object)
}
GtkWidget *
-gvc_speaker_test_new (MateMixerControl *control, MateMixerDevice *device)
+gvc_speaker_test_new (MateMixerStream *stream)
{
GObject *test;
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
test = g_object_new (GVC_TYPE_SPEAKER_TEST,
- "control", control,
- "device", device,
+ "row-spacing", 6,
+ "column-spacing", 6,
+#if GTK_CHECK_VERSION (3, 4, 0)
+ "row-homogeneous", TRUE,
+ "column-homogeneous", TRUE,
+#else
+ "homogeneous", TRUE,
+ "n-rows", 3,
+ "n-columns", 5,
+#endif
+ "stream", stream,
NULL);
return GTK_WIDGET (test);
diff --git a/mate-volume-control/src/gvc-speaker-test.h b/mate-volume-control/src/gvc-speaker-test.h
index 035df19..1c1546d 100644
--- a/mate-volume-control/src/gvc-speaker-test.h
+++ b/mate-volume-control/src/gvc-speaker-test.h
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
*
* 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
@@ -23,6 +24,8 @@
#include <glib.h>
#include <glib-object.h>
+#include <gtk/gtk.h>
+
#include <libmatemixer/matemixer.h>
G_BEGIN_DECLS
@@ -40,19 +43,28 @@ typedef struct _GvcSpeakerTestPrivate GvcSpeakerTestPrivate;
struct _GvcSpeakerTest
{
- GtkNotebook parent;
+#if GTK_CHECK_VERSION (3, 4, 0)
+ GtkGrid parent;
+#else
+ GtkTable parent;
+#endif
GvcSpeakerTestPrivate *priv;
};
struct _GvcSpeakerTestClass
{
- GtkNotebookClass parent_class;
+#if GTK_CHECK_VERSION (3, 4, 0)
+ GtkGridClass parent_class;
+#else
+ GtkTableClass parent_class;
+#endif
};
GType gvc_speaker_test_get_type (void) G_GNUC_CONST;
-GtkWidget * gvc_speaker_test_new (MateMixerControl *control,
- MateMixerDevice *device);
+GtkWidget * gvc_speaker_test_new (MateMixerStream *stream);
+
+MateMixerStream * gvc_speaker_test_get_stream (GvcSpeakerTest *test);
G_END_DECLS
diff --git a/mate-volume-control/src/gvc-stream-status-icon.c b/mate-volume-control/src/gvc-stream-status-icon.c
index 4e80e91..15372df 100644
--- a/mate-volume-control/src/gvc-stream-status-icon.c
+++ b/mate-volume-control/src/gvc-stream-status-icon.c
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 William Jon McCann
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
*
* 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
@@ -18,13 +19,11 @@
*
*/
-#include "config.h"
-
-#include <math.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
-#include <gdk/gdkkeysyms-compat.h>
+#include <gdk/gdkkeysyms.h>
+
#include <libmatemixer/matemixer.h>
#define MATE_DESKTOP_USE_UNSTABLE_API
@@ -38,78 +37,50 @@
struct _GvcStreamStatusIconPrivate
{
- char **icon_names;
+ gchar **icon_names;
GtkWidget *dock;
GtkWidget *bar;
guint current_icon;
- char *display_name;
- gboolean thaw;
- MateMixerStream *mixer_stream;
+ gchar *display_name;
+ MateMixerStream *stream;
};
enum
{
PROP_0,
+ PROP_STREAM,
PROP_DISPLAY_NAME,
- PROP_MIXER_STREAM,
PROP_ICON_NAMES,
+ N_PROPERTIES
};
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
static void gvc_stream_status_icon_class_init (GvcStreamStatusIconClass *klass);
static void gvc_stream_status_icon_init (GvcStreamStatusIcon *stream_status_icon);
static void gvc_stream_status_icon_finalize (GObject *object);
G_DEFINE_TYPE (GvcStreamStatusIcon, gvc_stream_status_icon, GTK_TYPE_STATUS_ICON)
-static void
-on_adjustment_value_changed (GtkAdjustment *adjustment,
- GvcStreamStatusIcon *icon)
-{
- if (icon->priv->thaw == FALSE)
- mate_mixer_stream_set_volume (icon->priv->mixer_stream,
- round (gtk_adjustment_get_value (adjustment)));
-}
-
-static void
-update_dock (GvcStreamStatusIcon *icon)
-{
- GtkAdjustment *adj;
-
- g_return_if_fail (icon);
-
- adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (icon->priv->bar)));
-
- icon->priv->thaw = TRUE;
- gtk_adjustment_set_value (adj,
- mate_mixer_stream_get_volume (icon->priv->mixer_stream));
- gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (icon->priv->bar),
- mate_mixer_stream_get_mute (icon->priv->mixer_stream));
- icon->priv->thaw = FALSE;
-}
-
static gboolean
-popup_dock (GvcStreamStatusIcon *icon,
- guint time)
+popup_dock (GvcStreamStatusIcon *icon, guint time)
{
GdkRectangle area;
GtkOrientation orientation;
GdkDisplay *display;
GdkScreen *screen;
- gboolean res;
int x;
int y;
int monitor_num;
GdkRectangle monitor;
GtkRequisition dock_req;
- update_dock (icon);
-
screen = gtk_status_icon_get_screen (GTK_STATUS_ICON (icon));
- res = gtk_status_icon_get_geometry (GTK_STATUS_ICON (icon),
- &screen,
- &area,
- &orientation);
- if (! res) {
+
+ if (gtk_status_icon_get_geometry (GTK_STATUS_ICON (icon),
+ &screen,
+ &area,
+ &orientation) == FALSE) {
g_warning ("Unable to determine geometry of status icon");
return FALSE;
}
@@ -131,68 +102,88 @@ popup_dock (GvcStreamStatusIcon *icon,
#endif
if (orientation == GTK_ORIENTATION_VERTICAL) {
- if (area.x + area.width + dock_req.width <= monitor.x + monitor.width) {
+ if (area.x + area.width + dock_req.width <= monitor.x + monitor.width)
x = area.x + area.width;
- } else {
+ else
x = area.x - dock_req.width;
- }
- if (area.y + dock_req.height <= monitor.y + monitor.height) {
+
+ if (area.y + dock_req.height <= monitor.y + monitor.height)
y = area.y;
- } else {
+ else
y = monitor.y + monitor.height - dock_req.height;
- }
} else {
- if (area.y + area.height + dock_req.height <= monitor.y + monitor.height) {
+ if (area.y + area.height + dock_req.height <= monitor.y + monitor.height)
y = area.y + area.height;
- } else {
+ else
y = area.y - dock_req.height;
- }
- if (area.x + dock_req.width <= monitor.x + monitor.width) {
+
+ if (area.x + dock_req.width <= monitor.x + monitor.width)
x = area.x;
- } else {
+ else
x = monitor.x + monitor.width - dock_req.width;
- }
}
gtk_window_move (GTK_WINDOW (icon->priv->dock), x, y);
- /* FIXME: without this, the popup window appears as a square
- * after changing the orientation
- */
+ /* Without this, the popup window appears as a square after changing
+ * the orientation */
gtk_window_resize (GTK_WINDOW (icon->priv->dock), 1, 1);
gtk_widget_show_all (icon->priv->dock);
-
- /* grab focus */
+ /* Grab focus */
gtk_grab_add (icon->priv->dock);
- if (gdk_pointer_grab (gtk_widget_get_window (icon->priv->dock), TRUE,
- GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
- GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK, NULL, NULL,
- time)
- != GDK_GRAB_SUCCESS) {
+ display = gtk_widget_get_display (icon->priv->dock);
+
+#if GTK_CHECK_VERSION (3, 0, 0)
+ do {
+ GdkDeviceManager *manager = gdk_display_get_device_manager (display);
+
+ if (gdk_device_grab (gdk_device_manager_get_client_pointer (manager),
+ gtk_widget_get_window (icon->priv->dock),
+ GDK_OWNERSHIP_NONE,
+ TRUE,
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK |
+ GDK_SCROLL_MASK,
+ NULL,
+ time) != GDK_GRAB_SUCCESS) {
+ gtk_grab_remove (icon->priv->dock);
+ gtk_widget_hide (icon->priv->dock);
+ }
+ } while (0);
+#else
+ if (gdk_pointer_grab (gtk_widget_get_window (icon->priv->dock),
+ TRUE,
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK |
+ GDK_SCROLL_MASK,
+ NULL, NULL,
+ time) != GDK_GRAB_SUCCESS) {
gtk_grab_remove (icon->priv->dock);
gtk_widget_hide (icon->priv->dock);
return FALSE;
}
- if (gdk_keyboard_grab (gtk_widget_get_window (icon->priv->dock), TRUE, time) != GDK_GRAB_SUCCESS) {
- display = gtk_widget_get_display (icon->priv->dock);
+ if (gdk_keyboard_grab (gtk_widget_get_window (icon->priv->dock),
+ TRUE,
+ time) != GDK_GRAB_SUCCESS) {
gdk_display_pointer_ungrab (display, time);
gtk_grab_remove (icon->priv->dock);
gtk_widget_hide (icon->priv->dock);
return FALSE;
}
-
+#endif
gtk_widget_grab_focus (icon->priv->dock);
return TRUE;
}
static void
-on_status_icon_activate (GtkStatusIcon *status_icon,
- GvcStreamStatusIcon *icon)
+on_status_icon_activate (GtkStatusIcon *status_icon, GvcStreamStatusIcon *icon)
{
popup_dock (icon, GDK_CURRENT_TIME);
}
@@ -202,38 +193,35 @@ on_status_icon_button_press (GtkStatusIcon *status_icon,
GdkEventButton *event,
GvcStreamStatusIcon *icon)
{
- /* middle click acts as mute/unmute */
+ /* Middle click acts as mute/unmute */
if (event->button == 2) {
- gboolean is_muted;
- is_muted = mate_mixer_stream_get_mute (icon->priv->mixer_stream);
+ gboolean is_muted = mate_mixer_stream_get_mute (icon->priv->stream);
- mate_mixer_stream_set_mute (icon->priv->mixer_stream, !is_muted);
+ mate_mixer_stream_set_mute (icon->priv->stream, !is_muted);
return TRUE;
}
return FALSE;
}
static void
-on_menu_mute_toggled (GtkMenuItem *item,
- GvcStreamStatusIcon *icon)
+on_menu_mute_toggled (GtkMenuItem *item, GvcStreamStatusIcon *icon)
{
gboolean is_muted;
+
is_muted = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item));
- gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (icon->priv->bar), is_muted);
+
+ mate_mixer_stream_set_mute (icon->priv->stream, is_muted);
}
static void
-on_menu_activate_open_volume_control (GtkMenuItem *item,
- GvcStreamStatusIcon *icon)
+on_menu_activate_open_volume_control (GtkMenuItem *item,
+ GvcStreamStatusIcon *icon)
{
GError *error = NULL;
- // XXX update to libmate-desktop 1.9.1 and uncomment this
- /*
mate_spawn_command_line_on_screen (gtk_widget_get_screen (icon->priv->dock),
"mate-volume-control",
&error);
- */
if (error != NULL) {
GtkWidget *dialog;
@@ -243,7 +231,7 @@ on_menu_activate_open_volume_control (GtkMenuItem *item,
GTK_BUTTONS_CLOSE,
_("Failed to start Sound Preferences: %s"),
error->message);
- g_signal_connect (dialog,
+ g_signal_connect (G_OBJECT (dialog),
"response",
G_CALLBACK (gtk_widget_destroy),
NULL);
@@ -260,27 +248,38 @@ on_status_icon_popup_menu (GtkStatusIcon *status_icon,
{
GtkWidget *menu;
GtkWidget *item;
- GtkWidget *image;
menu = gtk_menu_new ();
-
item = gtk_check_menu_item_new_with_mnemonic (_("_Mute"));
+
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
- mate_mixer_stream_get_mute (icon->priv->mixer_stream));
- g_signal_connect (item,
+ mate_mixer_stream_get_mute (icon->priv->stream));
+ g_signal_connect (G_OBJECT (item),
"toggled",
G_CALLBACK (on_menu_mute_toggled),
icon);
+
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+#if GTK_CHECK_VERSION (3, 10, 0)
+ item = gtk_menu_item_new_with_mnemonic (_("_Sound Preferences"));
+#else
item = gtk_image_menu_item_new_with_mnemonic (_("_Sound Preferences"));
- image = gtk_image_new_from_icon_name ("multimedia-volume-control",
- GTK_ICON_SIZE_MENU);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
- g_signal_connect (item,
+
+ do {
+ GtkWidget *image;
+
+ image = gtk_image_new_from_icon_name ("multimedia-volume-control",
+ GTK_ICON_SIZE_MENU);
+
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+ } while (0);
+#endif
+ g_signal_connect (G_OBJECT (item),
"activate",
G_CALLBACK (on_menu_activate_open_volume_control),
icon);
+
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_widget_show_all (menu);
@@ -302,25 +301,28 @@ on_status_icon_scroll_event (GtkStatusIcon *status_icon,
}
static void
-gvc_icon_release_grab (GvcStreamStatusIcon *icon,
- GdkEventButton *event)
+gvc_icon_release_grab (GvcStreamStatusIcon *icon, GdkEventButton *event)
{
- GdkDisplay *display;
+#if GTK_CHECK_VERSION (3, 0, 0)
+ gdk_device_ungrab (event->device, event->time);
+#else
+ GdkDisplay *display;
- /* ungrab focus */
display = gtk_widget_get_display (GTK_WIDGET (icon->priv->dock));
+
gdk_display_keyboard_ungrab (display, event->time);
gdk_display_pointer_ungrab (display, event->time);
+#endif
gtk_grab_remove (icon->priv->dock);
- /* hide again */
+ /* Hide again */
gtk_widget_hide (icon->priv->dock);
}
static gboolean
-on_dock_button_press (GtkWidget *widget,
- GdkEventButton *event,
- GvcStreamStatusIcon *icon)
+on_dock_button_press (GtkWidget *widget,
+ GdkEventButton *event,
+ GvcStreamStatusIcon *icon)
{
if (event->type == GDK_BUTTON_PRESS) {
gvc_icon_release_grab (icon, event);
@@ -335,33 +337,34 @@ popdown_dock (GvcStreamStatusIcon *icon)
{
GdkDisplay *display;
- /* ungrab focus */
display = gtk_widget_get_display (icon->priv->dock);
+
+#if GTK_CHECK_VERSION (3, 0, 0)
+ GdkDeviceManager *manager = gdk_display_get_device_manager (display);
+
+ gdk_device_ungrab (gdk_device_manager_get_client_pointer (manager),
+ GDK_CURRENT_TIME);
+#else
gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
gtk_grab_remove (icon->priv->dock);
-
- /* hide again */
+#endif
+ /* Hide again */
gtk_widget_hide (icon->priv->dock);
}
-/* This is called when the grab is broken for
- * either the dock, or the scale itself */
+/* This is called when the grab is broken for either the dock, or the scale */
static void
-gvc_icon_grab_notify (GvcStreamStatusIcon *icon,
- gboolean was_grabbed)
+gvc_icon_grab_notify (GvcStreamStatusIcon *icon, gboolean was_grabbed)
{
- if (was_grabbed != FALSE) {
+ if (was_grabbed != FALSE)
return;
- }
- if (!gtk_widget_has_grab (icon->priv->dock)) {
+ if (gtk_widget_has_grab (icon->priv->dock) == FALSE)
return;
- }
- if (gtk_widget_is_ancestor (gtk_grab_get_current (), icon->priv->dock)) {
+ if (gtk_widget_is_ancestor (gtk_grab_get_current (), icon->priv->dock))
return;
- }
popdown_dock (icon);
}
@@ -380,7 +383,6 @@ on_dock_grab_broken_event (GtkWidget *widget,
GvcStreamStatusIcon *icon)
{
gvc_icon_grab_notify (icon, FALSE);
-
return FALSE;
}
@@ -389,17 +391,10 @@ on_dock_key_release (GtkWidget *widget,
GdkEventKey *event,
GvcStreamStatusIcon *icon)
{
- if (event->keyval == GDK_Escape) {
+ if (event->keyval == GDK_KEY_Escape) {
popdown_dock (icon);
return TRUE;
}
-
-#if 0
- if (!gtk_bindings_activate_event (GTK_OBJECT (widget), event)) {
- /* The popup hasn't managed the event, pass onto the button */
- gtk_bindings_activate_event (GTK_OBJECT (user_data), event);
- }
-#endif
return TRUE;
}
@@ -416,171 +411,187 @@ on_dock_scroll_event (GtkWidget *widget,
static void
update_icon (GvcStreamStatusIcon *icon)
{
- gint64 volume;
+ guint volume = 0;
gdouble decibel = 0;
- gint64 normal_volume;
- gboolean is_muted;
- guint n;
- char *markup;
- gboolean can_decibel = FALSE;
+ guint normal = 0;
+ gboolean muted = FALSE;
+ guint n = 0;
+ gchar *markup;
+ const gchar *description;
MateMixerStreamFlags flags;
- if (icon->priv->mixer_stream == NULL) {
+ if (icon->priv->stream == NULL) {
+ /* Do not bother creating a tooltip for an unusable icon as it
+ * has no practical use */
+ gtk_status_icon_set_has_tooltip (GTK_STATUS_ICON (icon), FALSE);
return;
- }
-
- volume = mate_mixer_stream_get_volume (icon->priv->mixer_stream);
- is_muted = mate_mixer_stream_get_mute (icon->priv->mixer_stream);
+ } else
+ gtk_status_icon_set_has_tooltip (GTK_STATUS_ICON (icon), TRUE);
- flags = mate_mixer_stream_get_flags (icon->priv->mixer_stream);
+ flags = mate_mixer_stream_get_flags (icon->priv->stream);
- if (flags & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME) {
- decibel = mate_mixer_stream_get_decibel (icon->priv->mixer_stream);
- can_decibel = TRUE;
- }
+ if (flags & MATE_MIXER_STREAM_HAS_MUTE)
+ muted = mate_mixer_stream_get_mute (icon->priv->stream);
- normal_volume = mate_mixer_stream_get_normal_volume (icon->priv->mixer_stream);
+ if (flags & MATE_MIXER_STREAM_HAS_VOLUME) {
+ volume = mate_mixer_stream_get_volume (icon->priv->stream);
+ normal = mate_mixer_stream_get_normal_volume (icon->priv->stream);
- /* select image */
- if (volume <= 0 || is_muted) {
- n = 0;
- } else {
- n = 3 * volume / normal_volume + 1;
- if (n < 1) {
- n = 1;
- } else if (n > 3) {
- n = 3;
- }
+ /* Select an icon, they are expected to be sorted, the lowest index being
+ * the mute icon and the rest being volume increments */
+ if (volume <= 0 || muted)
+ n = 0;
+ else
+ n = CLAMP (3 * volume / normal + 1, 1, 3);
}
+ if (flags & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME)
+ decibel = mate_mixer_stream_get_decibel (icon->priv->stream);
- /* apparently status icon will reset icon even if
- * if doesn't change */
+ /* Apparently status icon will reset icon even if it doesn't change */
if (icon->priv->current_icon != n) {
gtk_status_icon_set_from_icon_name (GTK_STATUS_ICON (icon),
- icon->priv->icon_names [n]);
+ icon->priv->icon_names[n]);
icon->priv->current_icon = n;
}
+ description = mate_mixer_stream_get_description (icon->priv->stream);
- if (is_muted) {
- markup = g_strdup_printf (
- "<b>%s: %s</b>\n<small>%s</small>",
+ if (muted) {
+ markup = g_strdup_printf ("<b>%s: %s</b>\n<small>%s</small>",
icon->priv->display_name,
_("Muted"),
- mate_mixer_stream_get_description (icon->priv->mixer_stream));
- } else if (can_decibel && (decibel > -MATE_MIXER_INFINITY)) {
- markup = g_strdup_printf (
- "<b>%s: %.0f%%</b>\n<small>%0.2f dB\n%s</small>",
- icon->priv->display_name,
- 100 * (float) volume / normal_volume,
- decibel,
- mate_mixer_stream_get_description (icon->priv->mixer_stream));
- } else if (can_decibel) {
- markup = g_strdup_printf (
- "<b>%s: %.0f%%</b>\n<small>-&#8734; dB\n%s</small>",
- icon->priv->display_name,
- 100 * (float) volume / normal_volume,
- mate_mixer_stream_get_description (icon->priv->mixer_stream));
+ description);
+ } else if (flags & MATE_MIXER_STREAM_HAS_VOLUME) {
+ gdouble display_volume = 100 * volume / normal;
+
+ if (flags & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME) {
+ if (decibel > -MATE_MIXER_INFINITY) {
+ markup = g_strdup_printf ("<b>%s: %.0f%%</b>\n"
+ "<small>%0.2f dB\n%s</small>",
+ icon->priv->display_name,
+ display_volume,
+ decibel,
+ description);
+ } else {
+ markup = g_strdup_printf ("<b>%s: %.0f%%</b>\n"
+ "<small>-&#8734; dB\n%s</small>",
+ icon->priv->display_name,
+ display_volume,
+ description);
+ }
+ } else {
+ markup = g_strdup_printf ("<b>%s: %.0f%%</b>\n<small>%s</small>",
+ icon->priv->display_name,
+ display_volume,
+ description);
+ }
} else {
- markup = g_strdup_printf (
- "<b>%s: %.0f%%</b>\n<small>%s</small>",
+ markup = g_strdup_printf ("<b>%s</b>\n<small>%s</small>",
icon->priv->display_name,
- 100 * (float) volume / normal_volume,
- mate_mixer_stream_get_description (icon->priv->mixer_stream));
+ description);
}
+
gtk_status_icon_set_tooltip_markup (GTK_STATUS_ICON (icon), markup);
+
g_free (markup);
}
void
gvc_stream_status_icon_set_icon_names (GvcStreamStatusIcon *icon,
- const char **names)
+ const gchar **names)
{
g_return_if_fail (GVC_IS_STREAM_STATUS_ICON (icon));
+ g_return_if_fail (names != NULL && *names != NULL);
+
+ if (G_UNLIKELY (g_strv_length ((gchar **) names) != 4)) {
+ g_warn_if_reached ();
+ return;
+ }
g_strfreev (icon->priv->icon_names);
- icon->priv->icon_names = g_strdupv ((char **)names);
+
+ icon->priv->icon_names = g_strdupv ((gchar **) names);
+
+ /* Set the first icon as the initial one, the icon may be immediately
+ * updated or not depending on whether a stream is available */
+ gtk_status_icon_set_from_icon_name (GTK_STATUS_ICON (icon), names[0]);
update_icon (icon);
- g_object_notify (G_OBJECT (icon), "icon-names");
+
+ g_object_notify_by_pspec (G_OBJECT (icon), properties[PROP_ICON_NAMES]);
}
static void
-on_stream_volume_notify (GObject *object,
+on_stream_volume_notify (MateMixerStream *stream,
GParamSpec *pspec,
GvcStreamStatusIcon *icon)
{
update_icon (icon);
- update_dock (icon);
}
static void
-on_stream_mute_notify (GObject *object,
+on_stream_mute_notify (MateMixerStream *stream,
GParamSpec *pspec,
GvcStreamStatusIcon *icon)
{
update_icon (icon);
- update_dock (icon);
}
void
gvc_stream_status_icon_set_display_name (GvcStreamStatusIcon *icon,
- const char *name)
+ const gchar *name)
{
g_return_if_fail (GVC_STREAM_STATUS_ICON (icon));
g_free (icon->priv->display_name);
+
icon->priv->display_name = g_strdup (name);
update_icon (icon);
- g_object_notify (G_OBJECT (icon), "display-name");
+
+ g_object_notify_by_pspec (G_OBJECT (icon), properties[PROP_DISPLAY_NAME]);
}
void
-gvc_stream_status_icon_set_mixer_stream (GvcStreamStatusIcon *icon,
- MateMixerStream *stream)
+gvc_stream_status_icon_set_stream (GvcStreamStatusIcon *icon,
+ MateMixerStream *stream)
{
g_return_if_fail (GVC_STREAM_STATUS_ICON (icon));
- if (stream != NULL) {
+ if (icon->priv->stream == stream)
+ return;
+
+ if (stream != NULL)
g_object_ref (stream);
- }
- if (icon->priv->mixer_stream != NULL) {
- g_signal_handlers_disconnect_by_func (icon->priv->mixer_stream,
+ if (icon->priv->stream != NULL) {
+ g_signal_handlers_disconnect_by_func (icon->priv->stream,
G_CALLBACK (on_stream_volume_notify),
icon);
- g_signal_handlers_disconnect_by_func (icon->priv->mixer_stream,
+ g_signal_handlers_disconnect_by_func (icon->priv->stream,
G_CALLBACK (on_stream_mute_notify),
icon);
- g_object_unref (icon->priv->mixer_stream);
+ g_object_unref (icon->priv->stream);
}
- icon->priv->mixer_stream = stream;
-
- if (icon->priv->mixer_stream != NULL) {
- GtkAdjustment *adj;
-
- g_object_ref (icon->priv->mixer_stream);
-
- icon->priv->thaw = TRUE;
- adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (icon->priv->bar)));
- gtk_adjustment_set_value (adj,
- mate_mixer_stream_get_volume (icon->priv->mixer_stream));
- icon->priv->thaw = FALSE;
+ icon->priv->stream = stream;
- g_signal_connect (icon->priv->mixer_stream,
+ if (icon->priv->stream != NULL) {
+ g_signal_connect (icon->priv->stream,
"notify::volume",
G_CALLBACK (on_stream_volume_notify),
icon);
- g_signal_connect (icon->priv->mixer_stream,
+ g_signal_connect (icon->priv->stream,
"notify::mute",
G_CALLBACK (on_stream_mute_notify),
icon);
+
+ // XXX when no stream set some default icon and "unset" dock
+ update_icon (icon);
}
- update_icon (icon);
+ gvc_channel_bar_set_stream (GVC_CHANNEL_BAR (icon->priv->bar), stream);
- g_object_notify (G_OBJECT (icon), "mixer-stream");
+ g_object_notify_by_pspec (G_OBJECT (icon), properties[PROP_STREAM]);
}
static void
@@ -592,8 +603,8 @@ gvc_stream_status_icon_set_property (GObject *object,
GvcStreamStatusIcon *self = GVC_STREAM_STATUS_ICON (object);
switch (prop_id) {
- case PROP_MIXER_STREAM:
- gvc_stream_status_icon_set_mixer_stream (self, g_value_get_object (value));
+ case PROP_STREAM:
+ gvc_stream_status_icon_set_stream (self, g_value_get_object (value));
break;
case PROP_DISPLAY_NAME:
gvc_stream_status_icon_set_display_name (self, g_value_get_string (value));
@@ -614,17 +625,16 @@ gvc_stream_status_icon_get_property (GObject *object,
GParamSpec *pspec)
{
GvcStreamStatusIcon *self = GVC_STREAM_STATUS_ICON (object);
- GvcStreamStatusIconPrivate *priv = self->priv;
switch (prop_id) {
- case PROP_MIXER_STREAM:
- g_value_set_object (value, priv->mixer_stream);
+ case PROP_STREAM:
+ g_value_set_object (value, self->priv->stream);
break;
case PROP_DISPLAY_NAME:
- g_value_set_string (value, priv->display_name);
+ g_value_set_string (value, self->priv->display_name);
break;
case PROP_ICON_NAMES:
- g_value_set_boxed (value, priv->icon_names);
+ g_value_set_boxed (value, self->priv->icon_names);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -633,86 +643,6 @@ gvc_stream_status_icon_get_property (GObject *object,
}
static void
-on_bar_is_muted_notify (GObject *object,
- GParamSpec *pspec,
- GvcStreamStatusIcon *icon)
-{
- mate_mixer_stream_set_mute (icon->priv->mixer_stream,
- gvc_channel_bar_get_is_muted (GVC_CHANNEL_BAR (object)));
-}
-
-static GObject *
-gvc_stream_status_icon_constructor (GType type,
- guint n_construct_properties,
- GObjectConstructParam *construct_params)
-{
- GObject *object;
- GvcStreamStatusIcon *icon;
- GtkWidget *frame;
- GtkWidget *box;
- GtkAdjustment *adj;
-
- object = G_OBJECT_CLASS (gvc_stream_status_icon_parent_class)->constructor (type, n_construct_properties, construct_params);
-
- icon = GVC_STREAM_STATUS_ICON (object);
-
- gtk_status_icon_set_from_icon_name (GTK_STATUS_ICON (icon),
- icon->priv->icon_names[0]);
-
- /* window */
- icon->priv->dock = gtk_window_new (GTK_WINDOW_POPUP);
- gtk_widget_set_name (icon->priv->dock, "gvc-stream-status-icon-popup-window");
- g_signal_connect (icon->priv->dock,
- "button-press-event",
- G_CALLBACK (on_dock_button_press),
- icon);
- g_signal_connect (icon->priv->dock,
- "key-release-event",
- G_CALLBACK (on_dock_key_release),
- icon);
- g_signal_connect (icon->priv->dock,
- "scroll-event",
- G_CALLBACK (on_dock_scroll_event),
- icon);
- g_signal_connect (icon->priv->dock,
- "grab-notify",
- G_CALLBACK (on_dock_grab_notify),
- icon);
- g_signal_connect (icon->priv->dock,
- "grab-broken-event",
- G_CALLBACK (on_dock_grab_broken_event),
- icon);
-
- gtk_window_set_decorated (GTK_WINDOW (icon->priv->dock), FALSE);
-
- frame = gtk_frame_new (NULL);
- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
- gtk_container_add (GTK_CONTAINER (icon->priv->dock), frame);
-
- box = gtk_vbox_new (FALSE, 6);
- gtk_container_set_border_width (GTK_CONTAINER (box), 2);
- gtk_container_add (GTK_CONTAINER (frame), box);
-
- icon->priv->bar = gvc_channel_bar_new ();
- gvc_channel_bar_set_orientation (GVC_CHANNEL_BAR (icon->priv->bar),
- GTK_ORIENTATION_VERTICAL);
-
- gtk_box_pack_start (GTK_BOX (box), icon->priv->bar, TRUE, FALSE, 0);
- g_signal_connect (icon->priv->bar,
- "notify::is-muted",
- G_CALLBACK (on_bar_is_muted_notify),
- icon);
-
- adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (icon->priv->bar)));
- g_signal_connect (adj,
- "value-changed",
- G_CALLBACK (on_adjustment_value_changed),
- icon);
-
- return object;
-}
-
-static void
gvc_stream_status_icon_dispose (GObject *object)
{
GvcStreamStatusIcon *icon = GVC_STREAM_STATUS_ICON (object);
@@ -722,7 +652,7 @@ gvc_stream_status_icon_dispose (GObject *object)
icon->priv->dock = NULL;
}
- g_clear_object (&icon->priv->mixer_stream);
+ g_clear_object (&icon->priv->stream);
G_OBJECT_CLASS (gvc_stream_status_icon_parent_class)->dispose (object);
}
@@ -732,36 +662,33 @@ gvc_stream_status_icon_class_init (GvcStreamStatusIconClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- object_class->constructor = gvc_stream_status_icon_constructor;
object_class->finalize = gvc_stream_status_icon_finalize;
- object_class->dispose = gvc_stream_status_icon_dispose;
+ object_class->dispose = gvc_stream_status_icon_dispose;
object_class->set_property = gvc_stream_status_icon_set_property;
object_class->get_property = gvc_stream_status_icon_get_property;
- g_object_class_install_property (object_class,
- PROP_MIXER_STREAM,
- g_param_spec_object ("mixer-stream",
- "mixer stream",
- "mixer stream",
- MATE_MIXER_TYPE_STREAM,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT));
- g_object_class_install_property (object_class,
- PROP_DISPLAY_NAME,
- g_param_spec_string ("display-name",
- "Display Name",
- "Name to display for this stream",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT));
- g_object_class_install_property (object_class,
- PROP_ICON_NAMES,
- g_param_spec_boxed ("icon-names",
- "Icon Names",
- "Name of icon to display for this stream",
- G_TYPE_STRV,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT));
+ properties[PROP_STREAM] =
+ g_param_spec_object ("stream",
+ "Stream",
+ "MateMixer stream",
+ MATE_MIXER_TYPE_STREAM,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+
+ properties[PROP_DISPLAY_NAME] =
+ g_param_spec_string ("display-name",
+ "Display name",
+ "Name to display for this stream",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+
+ 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_READWRITE | G_PARAM_CONSTRUCT);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
g_type_class_add_private (klass, sizeof (GvcStreamStatusIconPrivate));
}
@@ -769,43 +696,84 @@ gvc_stream_status_icon_class_init (GvcStreamStatusIconClass *klass)
static void
on_status_icon_visible_notify (GvcStreamStatusIcon *icon)
{
- gboolean visible;
-
- g_object_get (icon, "visible", &visible, NULL);
- if (! visible) {
- if (icon->priv->dock != NULL) {
- gtk_widget_hide (icon->priv->dock);
- }
- }
+ if (gtk_status_icon_get_visible (GTK_STATUS_ICON (icon)) == FALSE)
+ gtk_widget_hide (icon->priv->dock);
}
static void
gvc_stream_status_icon_init (GvcStreamStatusIcon *icon)
{
+ GtkWidget *frame;
+ GtkWidget *box;
+
icon->priv = GVC_STREAM_STATUS_ICON_GET_PRIVATE (icon);
- g_signal_connect (icon,
+ g_signal_connect (G_OBJECT (icon),
"activate",
G_CALLBACK (on_status_icon_activate),
icon);
- g_signal_connect (icon,
+ g_signal_connect (G_OBJECT (icon),
"button-press-event",
G_CALLBACK (on_status_icon_button_press),
icon);
- g_signal_connect (icon,
+ g_signal_connect (G_OBJECT (icon),
"popup-menu",
G_CALLBACK (on_status_icon_popup_menu),
icon);
- g_signal_connect (icon,
+ g_signal_connect (G_OBJECT (icon),
"scroll-event",
G_CALLBACK (on_status_icon_scroll_event),
icon);
- g_signal_connect (icon,
+ g_signal_connect (G_OBJECT (icon),
"notify::visible",
G_CALLBACK (on_status_icon_visible_notify),
NULL);
- icon->priv->thaw = FALSE;
+ /* Create the dock window */
+ icon->priv->dock = gtk_window_new (GTK_WINDOW_POPUP);
+
+ gtk_window_set_decorated (GTK_WINDOW (icon->priv->dock), FALSE);
+
+ g_signal_connect (G_OBJECT (icon->priv->dock),
+ "button-press-event",
+ G_CALLBACK (on_dock_button_press),
+ icon);
+ g_signal_connect (G_OBJECT (icon->priv->dock),
+ "key-release-event",
+ G_CALLBACK (on_dock_key_release),
+ icon);
+ g_signal_connect (G_OBJECT (icon->priv->dock),
+ "scroll-event",
+ G_CALLBACK (on_dock_scroll_event),
+ icon);
+ g_signal_connect (G_OBJECT (icon->priv->dock),
+ "grab-notify",
+ G_CALLBACK (on_dock_grab_notify),
+ icon);
+ g_signal_connect (G_OBJECT (icon->priv->dock),
+ "grab-broken-event",
+ G_CALLBACK (on_dock_grab_broken_event),
+ icon);
+
+ frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
+ gtk_container_add (GTK_CONTAINER (icon->priv->dock), frame);
+
+ icon->priv->bar = gvc_channel_bar_new (NULL);
+
+ gvc_channel_bar_set_orientation (GVC_CHANNEL_BAR (icon->priv->bar),
+ GTK_ORIENTATION_VERTICAL);
+
+#if GTK_CHECK_VERSION (3, 0, 0)
+ box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+#else
+ box = gtk_vbox_new (FALSE, 6);
+#endif
+
+ gtk_container_set_border_width (GTK_CONTAINER (box), 2);
+ gtk_container_add (GTK_CONTAINER (frame), box);
+
+ gtk_box_pack_start (GTK_BOX (box), icon->priv->bar, TRUE, FALSE, 0);
}
static void
@@ -822,10 +790,10 @@ gvc_stream_status_icon_finalize (GObject *object)
GvcStreamStatusIcon *
gvc_stream_status_icon_new (MateMixerStream *stream,
- const char **icon_names)
+ const gchar **icon_names)
{
return g_object_new (GVC_TYPE_STREAM_STATUS_ICON,
- "mixer-stream", stream,
+ "stream", stream,
"icon-names", icon_names,
NULL);
}
diff --git a/mate-volume-control/src/gvc-stream-status-icon.h b/mate-volume-control/src/gvc-stream-status-icon.h
index cd32f64..9b61898 100644
--- a/mate-volume-control/src/gvc-stream-status-icon.h
+++ b/mate-volume-control/src/gvc-stream-status-icon.h
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
*
* 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
@@ -52,13 +53,13 @@ struct _GvcStreamStatusIconClass
GType gvc_stream_status_icon_get_type (void) G_GNUC_CONST;
GvcStreamStatusIcon * gvc_stream_status_icon_new (MateMixerStream *stream,
- const char **icon_names);
+ const gchar **icon_names);
void gvc_stream_status_icon_set_icon_names (GvcStreamStatusIcon *icon,
- const char **icon_names);
+ const gchar **icon_names);
void gvc_stream_status_icon_set_display_name (GvcStreamStatusIcon *icon,
- const char *display_name);
-void gvc_stream_status_icon_set_mixer_stream (GvcStreamStatusIcon *icon,
+ const gchar *display_name);
+void gvc_stream_status_icon_set_stream (GvcStreamStatusIcon *icon,
MateMixerStream *stream);
G_END_DECLS
diff --git a/mate-volume-control/src/mvc-helpers.c b/mate-volume-control/src/mvc-helpers.c
index 2861bbd..b82d6c8 100644
--- a/mate-volume-control/src/mvc-helpers.c
+++ b/mate-volume-control/src/mvc-helpers.c
@@ -18,8 +18,11 @@
*
*/
+#include "config.h"
+
#include <glib.h>
#include <glib/gi18n.h>
+#include <gtk/gtk.h>
#include <libmatemixer/matemixer.h>
@@ -30,7 +33,7 @@
#include "mvc-helpers.h"
#ifdef HAVE_PULSEAUDIO
-static pa_position_t
+static pa_channel_position_t
position_to_pulse (MateMixerChannelPosition position)
{
switch (position) {
@@ -101,55 +104,236 @@ mvc_channel_map_to_pretty_string (MateMixerStream *stream)
{
g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
+#define HAS_POSITION(p) (mate_mixer_stream_has_channel_position (stream, (p)))
+
/* Modeled after PulseAudio 5.0, probably could be extended with other combinations */
switch (mate_mixer_stream_get_num_channels (stream)) {
case 1:
- if (mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_MONO))
+ if (HAS_POSITION (MATE_MIXER_CHANNEL_MONO))
return _("Mono");
break;
case 2:
- if (mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_FRONT_LEFT) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_FRONT_RIGHT))
+ if (HAS_POSITION (MATE_MIXER_CHANNEL_FRONT_LEFT) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_FRONT_RIGHT))
return _("Stereo");
break;
case 4:
- if (mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_FRONT_LEFT) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_FRONT_RIGHT) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_BACK_LEFT) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_BACK_RIGHT))
+ if (HAS_POSITION (MATE_MIXER_CHANNEL_FRONT_LEFT) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_FRONT_RIGHT) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_BACK_LEFT) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_BACK_RIGHT))
return _("Surround 4.0");
break;
case 5:
- if (mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_FRONT_LEFT) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_FRONT_RIGHT) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_BACK_LEFT) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_BACK_RIGHT))
- if (mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_LFE))
+ if (HAS_POSITION (MATE_MIXER_CHANNEL_FRONT_LEFT) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_FRONT_RIGHT) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_BACK_LEFT) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_BACK_RIGHT))
+ if (HAS_POSITION (MATE_MIXER_CHANNEL_LFE))
return _("Surround 4.1");
- if (mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_FRONT_CENTER))
+ if (HAS_POSITION (MATE_MIXER_CHANNEL_FRONT_CENTER))
return _("Surround 5.0");
break;
case 6:
- if (mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_FRONT_LEFT) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_FRONT_RIGHT) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_FRONT_CENTER) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_BACK_LEFT) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_BACK_RIGHT) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_LFE))
+ if (HAS_POSITION (MATE_MIXER_CHANNEL_FRONT_LEFT) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_FRONT_RIGHT) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_FRONT_CENTER) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_BACK_LEFT) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_BACK_RIGHT) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_LFE))
return _("Surround 5.1");
break;
case 8:
- if (mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_FRONT_LEFT) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_FRONT_RIGHT) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_FRONT_CENTER) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_BACK_LEFT) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_BACK_RIGHT) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_SIDE_LEFT) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_SIDE_RIGHT) &&
- mate_mixer_stream_has_position (stream, MATE_MIXER_CHANNEL_LFE))
+ if (HAS_POSITION (MATE_MIXER_CHANNEL_FRONT_LEFT) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_FRONT_RIGHT) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_FRONT_CENTER) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_BACK_LEFT) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_BACK_RIGHT) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_SIDE_LEFT) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_SIDE_RIGHT) &&
+ HAS_POSITION (MATE_MIXER_CHANNEL_LFE))
return _("Surround 7.1");
break;
}
+#undef HAS_POSITION
+
return NULL;
}
+
+#if GTK_CHECK_VERSION (3, 0, 0)
+/* Taken from gtkstyle.c */
+static void rgb_to_hls (gdouble *r, gdouble *g, gdouble *b);
+static void hls_to_rgb (gdouble *h, gdouble *l, gdouble *s);
+
+void
+mvc_color_shade (GdkRGBA *a, GdkRGBA *b, gdouble k)
+{
+ gdouble red;
+ gdouble green;
+ gdouble blue;
+
+ red = (gdouble) a->red / 65535.0;
+ green = (gdouble) a->green / 65535.0;
+ blue = (gdouble) a->blue / 65535.0;
+
+ rgb_to_hls (&red, &green, &blue);
+
+ green *= k;
+ if (green > 1.0)
+ green = 1.0;
+ else if (green < 0.0)
+ green = 0.0;
+
+ blue *= k;
+ if (blue > 1.0)
+ blue = 1.0;
+ else if (blue < 0.0)
+ blue = 0.0;
+
+ hls_to_rgb (&red, &green, &blue);
+
+ b->red = red * 65535.0;
+ b->green = green * 65535.0;
+ b->blue = blue * 65535.0;
+}
+
+static void
+rgb_to_hls (gdouble *r, gdouble *g, gdouble *b)
+{
+ gdouble min;
+ gdouble max;
+ gdouble red;
+ gdouble green;
+ gdouble blue;
+ gdouble h, l, s;
+ gdouble delta;
+
+ red = *r;
+ green = *g;
+ blue = *b;
+
+ if (red > green) {
+ if (red > blue)
+ max = red;
+ else
+ max = blue;
+
+ if (green < blue)
+ min = green;
+ else
+ min = blue;
+ } else {
+ if (green > blue)
+ max = green;
+ else
+ max = blue;
+
+ if (red < blue)
+ min = red;
+ else
+ min = blue;
+ }
+
+ l = (max + min) / 2;
+ s = 0;
+ h = 0;
+
+ if (max != min) {
+ if (l <= 0.5)
+ s = (max - min) / (max + min);
+ else
+ s = (max - min) / (2 - max - min);
+
+ delta = max - min;
+ if (red == max)
+ h = (green - blue) / delta;
+ else if (green == max)
+ h = 2 + (blue - red) / delta;
+ else if (blue == max)
+ h = 4 + (red - green) / delta;
+
+ h *= 60;
+ if (h < 0.0)
+ h += 360;
+ }
+
+ *r = h;
+ *g = l;
+ *b = s;
+}
+
+static void
+hls_to_rgb (gdouble *h, gdouble *l, gdouble *s)
+{
+ gdouble hue;
+ gdouble lightness;
+ gdouble saturation;
+ gdouble m1, m2;
+ gdouble r, g, b;
+
+ lightness = *l;
+ saturation = *s;
+
+ if (lightness <= 0.5)
+ m2 = lightness * (1 + saturation);
+ else
+ m2 = lightness + saturation - lightness * saturation;
+ m1 = 2 * lightness - m2;
+
+ if (saturation == 0) {
+ *h = lightness;
+ *l = lightness;
+ *s = lightness;
+ } else {
+ hue = *h + 120;
+ while (hue > 360)
+ hue -= 360;
+ while (hue < 0)
+ hue += 360;
+
+ if (hue < 60)
+ r = m1 + (m2 - m1) * hue / 60;
+ else if (hue < 180)
+ r = m2;
+ else if (hue < 240)
+ r = m1 + (m2 - m1) * (240 - hue) / 60;
+ else
+ r = m1;
+
+ hue = *h;
+ while (hue > 360)
+ hue -= 360;
+ while (hue < 0)
+ hue += 360;
+
+ if (hue < 60)
+ g = m1 + (m2 - m1) * hue / 60;
+ else if (hue < 180)
+ g = m2;
+ else if (hue < 240)
+ g = m1 + (m2 - m1) * (240 - hue) / 60;
+ else
+ g = m1;
+
+ hue = *h - 120;
+ while (hue > 360)
+ hue -= 360;
+ while (hue < 0)
+ hue += 360;
+
+ if (hue < 60)
+ b = m1 + (m2 - m1) * hue / 60;
+ else if (hue < 180)
+ b = m2;
+ else if (hue < 240)
+ b = m1 + (m2 - m1) * (240 - hue) / 60;
+ else
+ b = m1;
+
+ *h = r;
+ *l = g;
+ *s = b;
+ }
+}
+#endif
diff --git a/mate-volume-control/src/mvc-helpers.h b/mate-volume-control/src/mvc-helpers.h
index 248c843..16e48db 100644
--- a/mate-volume-control/src/mvc-helpers.h
+++ b/mate-volume-control/src/mvc-helpers.h
@@ -31,6 +31,12 @@ const gchar *mvc_channel_position_to_string (MateMixerChannelPosition pos
const gchar *mvc_channel_position_to_pretty_string (MateMixerChannelPosition position);
const gchar *mvc_channel_map_to_pretty_string (MateMixerStream *stream);
+#if GTK_CHECK_VERSION (3, 0, 0)
+void mvc_color_shade (GdkRGBA *a,
+ GdkRGBA *b,
+ gdouble k);
+#endif
+
G_END_DECLS
#endif /* __MVC_HELPERS_H */