From 541ba6f8f2ef07fae3b39d29efde113bd96054a0 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 21 May 2017 02:03:56 +0200 Subject: [PATCH 01/68] Import the first definition of MixerControlPlugin --- include/Mixer.h | 24 ++++++ include/Mixer/control.h | 56 ++++++++++++++ include/Mixer/project.conf | 5 ++ include/project.conf | 6 ++ project.conf | 2 +- src/control.c | 152 +++++++++++++++++++++++++++++++++++++ src/control.h | 55 ++++++++++++++ src/project.conf | 6 +- 8 files changed, 304 insertions(+), 2 deletions(-) create mode 100644 include/Mixer.h create mode 100644 include/Mixer/control.h create mode 100644 include/Mixer/project.conf create mode 100644 include/project.conf create mode 100644 src/control.c create mode 100644 src/control.h diff --git a/include/Mixer.h b/include/Mixer.h new file mode 100644 index 0000000..bbb48bd --- /dev/null +++ b/include/Mixer.h @@ -0,0 +1,24 @@ +/* $Id$ */ +/* Copyright (c) 2017 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Mixer */ +/* This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + + + +#ifndef DESKTOP_MIXER_H +# define DESKTOP_MIXER_H + + +# include "Mixer/control.h" + +#endif /* !DESKTOP_MIXER_H */ diff --git a/include/Mixer/control.h b/include/Mixer/control.h new file mode 100644 index 0000000..65017d3 --- /dev/null +++ b/include/Mixer/control.h @@ -0,0 +1,56 @@ +/* $Id$ */ +/* Copyright (c) 2017 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Mixer */ +/* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + + +#ifndef DESKTOP_MIXER_CONTROL_H +# define DESKTOP_MIXER_CONTROL_H + +# include +# include +# include + + +/* MixerControlPlugin */ +typedef struct _MixerControlPlugin MixerControlPlugin; + +typedef struct _MixerControlDefinition +{ + String const * icon; + String const * name; + String const * description; + + /* callbacks */ + MixerControlPlugin * (*init)(String const * type, va_list properties); + void (*destroy)(MixerControlPlugin * plugin); + + GtkWidget * (*get_widget)(MixerControlPlugin * plugin); + int (*set)(MixerControlPlugin * plugin, va_list properties); +} MixerControlDefinition; + +#endif /* !DESKTOP_MIXER_CONTROL_H */ diff --git a/include/Mixer/project.conf b/include/Mixer/project.conf new file mode 100644 index 0000000..1cdbf23 --- /dev/null +++ b/include/Mixer/project.conf @@ -0,0 +1,5 @@ +includes=control.h +dist=Makefile + +[control.h] +install=$(PREFIX)/include/Desktop/Mixer diff --git a/include/project.conf b/include/project.conf new file mode 100644 index 0000000..85dbd9f --- /dev/null +++ b/include/project.conf @@ -0,0 +1,6 @@ +subdirs=Mixer +includes=Mixer.h +dist=Makefile + +[Mixer.h] +install=$(PREFIX)/include/Desktop diff --git a/project.conf b/project.conf index bd0f515..138de61 100644 --- a/project.conf +++ b/project.conf @@ -2,7 +2,7 @@ package=Mixer version=0.2.2 config=h,sh -subdirs=data,doc,po,src,tests +subdirs=data,doc,include,po,src,tests dist=COPYING,Makefile,README.md,config.h,config.sh [README.md] diff --git a/src/control.c b/src/control.c new file mode 100644 index 0000000..f5d4795 --- /dev/null +++ b/src/control.c @@ -0,0 +1,152 @@ +/* $Id$ */ +/* Copyright (c) 2017 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Mixer */ +/* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + + +#include +#include +#include "Mixer/control.h" +#include "control.h" +#include "../config.h" + + +/* private */ +/* types */ +struct _MixerControl +{ + String * id; + Plugin * handle; + MixerControlDefinition * definition; + MixerControlPlugin * plugin; + GtkWidget * widget; + + /* widgets */ + GtkWidget * frame; + GtkWidget * icon; + GtkWidget * name; +}; + + +/* public */ +/* functions */ +/* mixercontrol_new */ +MixerControl * mixercontrol_new(String const * id, String const * icon, + String const * name, String const * type, ...) +{ + MixerControl * control; + va_list ap; + GtkWidget * hbox; + + if((control = object_new(sizeof(*control))) == NULL) + return NULL; + control->id = string_new(id); + control->handle = plugin_new(LIBDIR, PACKAGE, "controls", type); + control->frame = NULL; + va_start(ap, type); + if(control->id == NULL + || control->handle == NULL + || (control->definition = plugin_lookup(control->handle, + "control")) == NULL + || control->definition->init == NULL + || control->definition->destroy == NULL + || (control->plugin = control->definition->init(type, + ap)) == NULL + || control->definition->get_widget == NULL + || (control->widget = control->definition->get_widget( + control->plugin)) == NULL) + { + va_end(ap); + mixercontrol_delete(control); + return NULL; + } + va_end(ap); + /* widgets */ + control->frame = gtk_frame_new(NULL); + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); + control->icon = gtk_image_new_from_icon_name(icon, GTK_ICON_SIZE_MENU); + gtk_box_pack_start(GTK_BOX(hbox), control->icon, FALSE, TRUE, 0); + control->name = gtk_label_new(name); +#if GTK_CHECK_VERSION(3, 0, 0) + gtk_widget_set_halign(control->name, GTK_ALIGN_START); +#else + gtk_misc_set_alignment(GTK_MISC(control->name), 0.0, 0.5); +#endif + gtk_box_pack_start(GTK_BOX(hbox), control->name, TRUE, TRUE, 0); + return control; +} + + +/* mixercontrol_delete */ +void mixercontrol_delete(MixerControl * control) +{ + if(control->plugin != NULL && control->definition->destroy != NULL) + control->definition->destroy(control->plugin); + if(control->handle != NULL) + plugin_delete(control->handle); + if(control->frame != NULL) + g_object_unref(control->frame); + if(control->id != NULL) + string_delete(control->id); + object_delete(control); +} + + +/* accessors */ +/* mixercontrol_get_id */ +String const * mixercontrol_get_id(MixerControl * control) +{ + return control->id; +} + + +/* mixercontrol_get_widget */ +GtkWidget * mixercontrol_get_widget(MixerControl * control) +{ + return control->frame; +} + + +/* mixercontrol_set */ +int mixercontrol_set(MixerControl * control, ...) +{ + int ret; + va_list ap; + + va_start(ap, control); + ret = control->definition->set(control->plugin, ap); + va_end(ap); + return ret; +} + + +/* mixercontrol_set_icon */ +void mixercontrol_set_icon(MixerControl * control, String const * icon) +{ + gtk_image_set_from_icon_name(GTK_IMAGE(control->icon), icon, + GTK_ICON_SIZE_MENU); +} diff --git a/src/control.h b/src/control.h new file mode 100644 index 0000000..e06b3ab --- /dev/null +++ b/src/control.h @@ -0,0 +1,55 @@ +/* $Id$ */ +/* Copyright (c) 2017 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Mixer */ +/* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + + +#ifndef MIXER_CONTROL_H +# define MIXER_CONTROL_H + +# include +# include + + +/* MixerControl */ +/* types */ +typedef struct _MixerControl MixerControl; + + +/* functions */ +MixerControl * mixercontrol_new(String const * id, String const * icon, + String const * name, String const * type, ...); +void mixercontrol_delete(MixerControl * control); + +/* accessors */ +String const * mixercontrol_get_id(MixerControl * control); +GtkWidget * mixercontrol_get_widget(MixerControl * control); + +int mixercontrol_set(MixerControl * control, ...); +void mixercontrol_set_icon(MixerControl * control, String const * icon); + +#endif /* !MIXER_CONTROL_H */ diff --git a/src/project.conf b/src/project.conf index c3af87e..bddf76f 100644 --- a/src/project.conf +++ b/src/project.conf @@ -1,4 +1,5 @@ targets=mixer +cppflags_force=-I../include #cppflags=-D EMBEDDED cflags_force=`pkg-config --cflags libDesktop` cflags=-W -Wall -g -O2 -fPIE -D_FORTIFY_SOURCE=2 -fstack-protector-all @@ -8,9 +9,12 @@ dist=Makefile,mixer.h,window.h,callbacks.h [mixer] type=binary -sources=mixer.c,window.c,callbacks.c,main.c +sources=control.c,mixer.c,window.c,callbacks.c,main.c install=$(BINDIR) +[control.c] +depends=control.h,../config.h + [mixer.c] depends=callbacks.h,mixer.h,../config.h From d1093bd347c2efd81d66f7634b313aa3db53f34b Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 21 May 2017 03:34:43 +0200 Subject: [PATCH 02/68] Import first implementations of individual controls --- src/controls/channels.c | 247 ++++++++++++++++++++++++++++++++++++++ src/controls/mute.c | 142 ++++++++++++++++++++++ src/controls/project.conf | 27 +++++ src/controls/radio.c | 149 +++++++++++++++++++++++ src/controls/set.c | 138 +++++++++++++++++++++ src/project.conf | 1 + 6 files changed, 704 insertions(+) create mode 100644 src/controls/channels.c create mode 100644 src/controls/mute.c create mode 100644 src/controls/project.conf create mode 100644 src/controls/radio.c create mode 100644 src/controls/set.c diff --git a/src/controls/channels.c b/src/controls/channels.c new file mode 100644 index 0000000..aff69fb --- /dev/null +++ b/src/controls/channels.c @@ -0,0 +1,247 @@ +/* $Id$ */ +/* Copyright (c) 2017 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Mixer */ +/* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + + +#include +#include +#include "Mixer/control.h" + + +/* MixerControlChannels */ +/* private */ +/* types */ +typedef struct _MixerControlChannel +{ + MixerControlPlugin * plugin; + + GtkWidget * widget; +} MixerControlChannel; + +struct _MixerControlPlugin +{ + GtkWidget * widget; + + /* channels */ + GtkWidget * hbox; + MixerControlChannel * channels; + size_t channels_cnt; + + GtkWidget * bind; + GtkWidget * mute; +}; + + +/* prototypes */ +/* control */ +static MixerControlPlugin * _channels_init(String const * type, + va_list properties); +static void _channels_destroy(MixerControlPlugin * channels); + +static GtkWidget * _channels_get_widget(MixerControlPlugin * channels); + +static int _channels_set(MixerControlPlugin * channels, + va_list properties); + +/* callbacks */ +static void _channels_on_changed(gpointer data); + + +/* public */ +/* variables */ +MixerControlDefinition control = +{ + NULL, + "Channels", + NULL, + _channels_init, + _channels_destroy, + _channels_get_widget, + _channels_set +}; + + +/* private */ +/* functions */ +/* channels_init */ +static MixerControlPlugin * _channels_init(String const * type, + va_list properties) +{ + MixerControlPlugin * channels; + (void) type; + + if((channels = object_new(sizeof(*channels))) == NULL) + return NULL; + channels->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); + channels->channels = NULL; + channels->channels_cnt = 0; + channels->hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); + gtk_box_pack_start(GTK_BOX(channels->widget), channels->hbox, TRUE, + TRUE, 0); + if(_channels_set(channels, properties) != 0) + { + _channels_destroy(channels); + return NULL; + } + channels->bind = gtk_toggle_button_new(); + /* FIXME really implement */ + gtk_box_pack_start(GTK_BOX(channels->widget), channels->bind, + FALSE, TRUE, 0); + channels->mute = gtk_toggle_button_new(); + /* FIXME really implement */ + gtk_box_pack_start(GTK_BOX(channels->widget), channels->mute, + FALSE, TRUE, 0); + return channels; +} + + +/* channels_destroy */ +static void _channels_destroy(MixerControlPlugin * channels) +{ + g_object_unref(channels->widget); + object_delete(channels); +} + + +/* accessors */ +/* channels_get_widget */ +static GtkWidget * _channels_get_widget(MixerControlPlugin * channels) +{ + return channels->widget; +} + + +/* channels_set */ +static void _set_bind(MixerControlPlugin * channels, gboolean bind); +static int _set_channels(MixerControlPlugin * channels, guint cnt, + gdouble value); +static void _set_mute(MixerControlPlugin * channels, gboolean mute); +static void _set_value(MixerControlPlugin * channels, gdouble value); + +static int _channels_set(MixerControlPlugin * channels, + va_list properties) +{ + String const * p; + gboolean b; + guint u; + gdouble value = 0.0; + + while((p = va_arg(properties, String const *)) != NULL) + { + if(string_compare(p, "value") == 0) + { + value = va_arg(properties, gdouble); + _set_value(channels, value); + } + else if(string_compare(p, "bind") == 0) + { + b = va_arg(properties, gboolean); + _set_bind(channels, b); + } + else if(string_compare(p, "channels") == 0) + { + u = va_arg(properties, unsigned int); + /* FIXME look for the initial value first */ + if(_set_channels(channels, u, value) != 0) + return -1; + } + else if(string_compare(p, "mute") == 0) + { + b = va_arg(properties, gboolean); + _set_mute(channels, b); + } + else + /* FIXME report the error */ + return -1; + } + return 0; +} + +static void _set_bind(MixerControlPlugin * channels, gboolean bind) +{ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(channels->bind), bind); +} + +static int _set_channels(MixerControlPlugin * channels, guint cnt, + gdouble value) +{ + size_t i; + MixerControlChannel * p; + + /* delete channels as required */ + if(channels->channels_cnt >= cnt) + { + for(i = cnt; i < channels->channels_cnt; i++) + g_object_unref(channels->channels[i].widget); + channels->channels_cnt = cnt; + return 0; + } + if((p = realloc(channels->channels, sizeof(*p) * cnt)) == NULL) + return -1; + channels->channels = p; + for(i = channels->channels_cnt; i < cnt; i++) + { + p = &channels->channels[i]; + p->plugin = channels; + p->widget = gtk_scale_new_with_range(GTK_ORIENTATION_VERTICAL, + 0.0, 100.0, 1.0); + gtk_range_set_inverted(GTK_RANGE(p->widget), TRUE); + gtk_range_set_value(GTK_RANGE(p->widget), value); + g_signal_connect_swapped(p->widget, "value-changed", G_CALLBACK( + _channels_on_changed), p); + gtk_box_pack_start(GTK_BOX(channels->hbox), p->widget, TRUE, + TRUE, 0); + } + channels->channels_cnt = cnt; + return 0; +} + +static void _set_mute(MixerControlPlugin * channels, gboolean mute) +{ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(channels->mute), mute); +} + +static void _set_value(MixerControlPlugin * channels, gdouble value) +{ + size_t i; + gdouble v; + + v = (value / 255.0) * 100.0; + for(i = 0; i < channels->channels_cnt; i++) + gtk_range_set_value(GTK_RANGE(channels->channels[i].widget), v); +} + + +/* callbacks */ +/* channels_on_changed */ +static void _channels_on_changed(gpointer data) +{ + MixerControlChannel * channel = data; + + /* FIXME implement */ +} diff --git a/src/controls/mute.c b/src/controls/mute.c new file mode 100644 index 0000000..2ad2756 --- /dev/null +++ b/src/controls/mute.c @@ -0,0 +1,142 @@ +/* $Id$ */ +/* Copyright (c) 2017 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Mixer */ +/* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + + +#include "Mixer/control.h" +#include + + +/* MixerControlMute */ +/* private */ +/* types */ +struct _MixerControlPlugin +{ + GtkWidget * widget; + + GtkWidget * mute; +}; + + +/* prototypes */ +/* control */ +static MixerControlPlugin * _mute_init(String const * type, va_list properties); +static void _mute_destroy(MixerControlPlugin * mute); + +static GtkWidget * _mute_get_widget(MixerControlPlugin * mute); + +static int _mute_set(MixerControlPlugin * mute, va_list properties); + +/* callbacks */ +static void _mute_on_toggled(gpointer data); + + +/* public */ +/* variables */ +MixerControlDefinition control = +{ + NULL, + "Mute button", + NULL, + _mute_init, + _mute_destroy, + _mute_get_widget, + _mute_set +}; + + +/* private */ +/* functions */ +/* mute_init */ +static MixerControlPlugin * _mute_init(String const * type, va_list properties) +{ + MixerControlPlugin * mute; + (void) type; + + if((mute = object_new(sizeof(*mute))) == NULL) + return NULL; + mute->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); + mute->mute = gtk_toggle_button_new(); + g_signal_connect(mute->mute, "toggled", G_CALLBACK(_mute_on_toggled), + mute); + gtk_box_pack_start(GTK_BOX(mute->widget), mute->mute, FALSE, TRUE, 0); + if(_mute_set(mute, properties) != 0) + { + _mute_destroy(mute); + return NULL; + } + return mute; +} + + +/* mute_destroy */ +static void _mute_destroy(MixerControlPlugin * mute) +{ + g_object_unref(mute->widget); + object_delete(mute); +} + + +/* accessors */ +/* mute_get_widget */ +static GtkWidget * _mute_get_widget(MixerControlPlugin * mute) +{ + return mute->widget; +} + + +/* mute_set */ +static int _mute_set(MixerControlPlugin * mute, va_list properties) +{ + String const * p; + gboolean value; + + while((p = va_arg(properties, String const *)) != NULL) + { + if(string_compare(p, "value") == 0) + { + value = va_arg(properties, gboolean); + gtk_toggle_button_set_active( + GTK_TOGGLE_BUTTON(mute->mute), value); + } + else + /* FIXME report the error */ + return -1; + } + return 0; +} + + +/* callbacks */ +/* mute_on_toggled */ +static void _mute_on_toggled(gpointer data) +{ + MixerControlPlugin * mute = data; + + /* FIXME implement */ +} diff --git a/src/controls/project.conf b/src/controls/project.conf new file mode 100644 index 0000000..66b8212 --- /dev/null +++ b/src/controls/project.conf @@ -0,0 +1,27 @@ +targets=channels,mute,radio,set +cppflags_force=-I../../include +cflags_force=`pkg-config --cflags libDesktop` +cflags=-W -Wall -g -O2 -fPIC -D_FORTIFY_SOURCE=2 -fstack-protector-all +ldflags_force=`pkg-config --libs libDesktop` +ldflags=-Wl,-z,relro -Wl,-z,now +dist=Makefile + +[channels] +type=plugin +sources=channels.c +install=$(LIBDIR)/Desktop/Mixer/controls + +[radio] +type=plugin +sources=radio.c +install=$(LIBDIR)/Desktop/Mixer/controls + +[mute] +type=plugin +sources=mute.c +install=$(LIBDIR)/Desktop/Mixer/controls + +[set] +type=plugin +sources=set.c +install=$(LIBDIR)/Desktop/Mixer/controls diff --git a/src/controls/radio.c b/src/controls/radio.c new file mode 100644 index 0000000..a2f23e9 --- /dev/null +++ b/src/controls/radio.c @@ -0,0 +1,149 @@ +/* $Id$ */ +/* Copyright (c) 2017 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Mixer */ +/* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + + +#include +#include "Mixer/control.h" + + +/* MixerControlRadio */ +/* private */ +/* types */ +typedef struct _MixerControlRadio +{ + MixerControlPlugin * plugin; + + GtkWidget * widget; +} MixerControlRadio; + +struct _MixerControlPlugin +{ + GtkWidget * widget; + + MixerControlRadio * radio; + size_t radio_cnt; +}; + + +/* prototypes */ +/* control */ +static MixerControlPlugin * _radio_init(String const * type, + va_list properties); +static void _radio_destroy(MixerControlPlugin * radio); + +static GtkWidget * _radio_get_widget(MixerControlPlugin * radio); + +static int _radio_set(MixerControlPlugin * radio, + va_list properties); + +/* callbacks */ + + +/* public */ +/* variables */ +MixerControlDefinition control = +{ + NULL, + "Radio buttons", + NULL, + _radio_init, + _radio_destroy, + _radio_get_widget, + _radio_set +}; + + +/* private */ +/* functions */ +/* radio_init */ +static MixerControlPlugin * _radio_init(String const * type, va_list properties) +{ + MixerControlPlugin * radio; + (void) type; + + if((radio = object_new(sizeof(*radio))) == NULL) + return NULL; + radio->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); + radio->radio = NULL; + radio->radio_cnt = 0; + if(_radio_set(radio, properties) != 0) + { + _radio_destroy(radio); + return NULL; + } + return radio; +} + + +/* radio_destroy */ +static void _radio_destroy(MixerControlPlugin * radio) +{ + g_object_unref(radio->widget); + object_delete(radio); +} + + +/* accessors */ +/* radio_get_widget */ +static GtkWidget * _radio_get_widget(MixerControlPlugin * radio) +{ + return radio->widget; +} + + +/* radio_set */ +static void _set_value(MixerControlPlugin * radio, guint value); + +static int _radio_set(MixerControlPlugin * radio, va_list properties) +{ + String const * p; + guint value; + + while((p = va_arg(properties, String const *)) != NULL) + { + if(string_compare(p, "value") == 0) + { + value = va_arg(properties, guint); + _set_value(radio, value); + } + else + /* FIXME report the error */ + return -1; + } + return 0; +} + +static void _set_value(MixerControlPlugin * radio, guint value) +{ + /* FIXME implement */ +} + + +/* callbacks */ +/* FIXME implement */ diff --git a/src/controls/set.c b/src/controls/set.c new file mode 100644 index 0000000..21ac745 --- /dev/null +++ b/src/controls/set.c @@ -0,0 +1,138 @@ +/* $Id$ */ +/* Copyright (c) 2017 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Mixer */ +/* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + + +#include +#include "Mixer/control.h" + + +/* MixerControlSet */ +/* private */ +/* types */ +typedef struct _MixerControlSet +{ + GtkWidget * widget; +} MixerControlSet; + +struct _MixerControlPlugin +{ + GtkWidget * widget; + + MixerControlSet * sets; + size_t sets_cnt; +}; + + +/* prototypes */ +static MixerControlPlugin * _set_init(String const * type, va_list properties); +static void _set_destroy(MixerControlPlugin * set); + +static GtkWidget * _set_get_widget(MixerControlPlugin * set); + +static int _set_set(MixerControlPlugin * set, va_list properties); + + +/* public */ +/* variables */ +MixerControlDefinition control = +{ + NULL, + "Set of values", + NULL, + _set_init, + _set_destroy, + _set_get_widget, + _set_set +}; + + +/* private */ +/* functions */ +/* set_init */ +static MixerControlPlugin * _set_init(String const * type, va_list properties) +{ + MixerControlPlugin * set; + (void) type; + + if((set = object_new(sizeof(*set))) == NULL) + return NULL; + set->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); + set->sets = NULL; + set->sets_cnt = 0; + if(_set_set(set, properties) != 0) + { + _set_destroy(set); + return NULL; + } + return set; +} + + +/* set_destroy */ +static void _set_destroy(MixerControlPlugin * set) +{ + g_object_unref(set->widget); + object_delete(set); +} + + +/* accessors */ +/* set_get_widget */ +static GtkWidget * _set_get_widget(MixerControlPlugin * set) +{ + return set->widget; +} + + +/* set_set */ +static void _set_value(MixerControlPlugin * set, guint value); + +static int _set_set(MixerControlPlugin * set, va_list properties) +{ + String const * p; + guint value; + + while((p = va_arg(properties, String const *)) != NULL) + { + if(string_compare(p, "value") == 0) + { + value = va_arg(properties, guint); + _set_value(set, value); + } + else + /* FIXME report the error */ + return -1; + } + return 0; +} + +static void _set_value(MixerControlPlugin * set, guint value) +{ + /* FIXME implement */ +} diff --git a/src/project.conf b/src/project.conf index bddf76f..917316d 100644 --- a/src/project.conf +++ b/src/project.conf @@ -1,3 +1,4 @@ +subdirs=controls targets=mixer cppflags_force=-I../include #cppflags=-D EMBEDDED From 56e72b049ef279201e8e37b4b30f26ae6dba2351 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 21 May 2017 03:35:30 +0200 Subject: [PATCH 03/68] Register more temporary objects --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 7bef143..b47ad4f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,7 @@ Makefile /config.h /config.sh *~ +*.dll +*.dylib *.o +*.so From 370c417e73e5d8811c9af852ad9edcc816683241 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 21 May 2017 03:52:46 +0200 Subject: [PATCH 04/68] Restore the alignment code for the channels --- src/controls/channels.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/controls/channels.c b/src/controls/channels.c index aff69fb..8dae478 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -93,6 +93,9 @@ static MixerControlPlugin * _channels_init(String const * type, va_list properties) { MixerControlPlugin * channels; +#if !GTK_CHECK_VERSION(3, 14, 0) + GtkWidget * align; +#endif (void) type; if((channels = object_new(sizeof(*channels))) == NULL) @@ -101,8 +104,15 @@ static MixerControlPlugin * _channels_init(String const * type, channels->channels = NULL; channels->channels_cnt = 0; channels->hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); +#if GTK_CHECK_VERSION(3, 14, 0) + gtk_widget_set_halign(channels->hbox, GTK_ALIGN_CENTER); gtk_box_pack_start(GTK_BOX(channels->widget), channels->hbox, TRUE, TRUE, 0); +#else + align = gtk_alignment_new(0.5, 0.5, 0.0, 1.0); + gtk_container_add(GTK_CONTAINER(align), channels->hbox); + gtk_box_pack_start(GTK_BOX(channels->widget), align, TRUE, TRUE, 0); +#endif if(_channels_set(channels, properties) != 0) { _channels_destroy(channels); From e76f926a6c471e8145f6322281cf882281da6f6c Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 21 May 2017 04:11:23 +0200 Subject: [PATCH 05/68] Code cleanup --- src/mixer.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/mixer.c b/src/mixer.c index f0b7db1..f97d1bd 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -284,12 +284,8 @@ Mixer * mixer_new(GtkWidget * window, char const * device, MixerLayout layout) control = _new_set(mixer, i, &md.un.s); break; case AUDIO_MIXER_VALUE: -# if GTK_CHECK_VERSION(3, 0, 0) bbox = gtk_button_box_new( GTK_ORIENTATION_VERTICAL); -# else - bbox = gtk_vbutton_box_new(); -# endif gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_START); gtk_size_group_add_widget(vgroup, bbox); From 0f3f6b745a0a6448fb746e353948577d436dfbac Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 21 May 2017 04:22:52 +0200 Subject: [PATCH 06/68] Avoid a warning on NetBSD --- src/mixer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mixer.c b/src/mixer.c index f97d1bd..b7af405 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -154,7 +154,9 @@ Mixer * mixer_new(GtkWidget * window, char const * device, MixerLayout layout) { Mixer * mixer; GtkSizeGroup * hgroup; +#ifndef AUDIO_MIXER_DEVINFO GtkSizeGroup * vgroup; +#endif GtkWidget * scrolled = NULL; GtkWidget * label; GtkWidget * widget; @@ -190,7 +192,9 @@ Mixer * mixer_new(GtkWidget * window, char const * device, MixerLayout layout) mixer->mc_cnt = 0; #endif hgroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); +#ifndef AUDIO_MIXER_DEVINFO vgroup = gtk_size_group_new(GTK_SIZE_GROUP_VERTICAL); +#endif if(mixer->device == NULL || mixer->fd < 0) { _mixer_error(NULL, device, 0); From f60ff4bd85d53271de9c6fc35e71513120a32067 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 21 May 2017 04:41:59 +0200 Subject: [PATCH 07/68] Avoid using uninitialized variables --- src/control.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/control.c b/src/control.c index f5d4795..c283875 100644 --- a/src/control.c +++ b/src/control.c @@ -66,6 +66,8 @@ MixerControl * mixercontrol_new(String const * id, String const * icon, return NULL; control->id = string_new(id); control->handle = plugin_new(LIBDIR, PACKAGE, "controls", type); + control->definition = NULL; + control->plugin = NULL; control->frame = NULL; va_start(ap, type); if(control->id == NULL From 94eead47613b5722f5e771ca7ca9e4453304f4ac Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 21 May 2017 04:49:58 +0200 Subject: [PATCH 08/68] Correct the installation path for the controls --- src/controls/project.conf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/controls/project.conf b/src/controls/project.conf index 66b8212..df2e1bb 100644 --- a/src/controls/project.conf +++ b/src/controls/project.conf @@ -9,19 +9,19 @@ dist=Makefile [channels] type=plugin sources=channels.c -install=$(LIBDIR)/Desktop/Mixer/controls +install=$(LIBDIR)/Mixer/controls [radio] type=plugin sources=radio.c -install=$(LIBDIR)/Desktop/Mixer/controls +install=$(LIBDIR)/Mixer/controls [mute] type=plugin sources=mute.c -install=$(LIBDIR)/Desktop/Mixer/controls +install=$(LIBDIR)/Mixer/controls [set] type=plugin sources=set.c -install=$(LIBDIR)/Desktop/Mixer/controls +install=$(LIBDIR)/Mixer/controls From f4c74c683e8aee5d8a6e15c1318ffac676e9e0cc Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 21 May 2017 04:53:51 +0200 Subject: [PATCH 09/68] Set the widget for the frame label --- src/control.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/control.c b/src/control.c index c283875..ceb6a7d 100644 --- a/src/control.c +++ b/src/control.c @@ -99,6 +99,7 @@ MixerControl * mixercontrol_new(String const * id, String const * icon, gtk_misc_set_alignment(GTK_MISC(control->name), 0.0, 0.5); #endif gtk_box_pack_start(GTK_BOX(hbox), control->name, TRUE, TRUE, 0); + gtk_frame_set_label_widget(GTK_FRAME(control->frame), hbox); return control; } From 2094dc1460ec8e3e7ad0ce3022c11066397fb8d8 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 21 May 2017 04:57:01 +0200 Subject: [PATCH 10/68] Embed the actual control widget within the frame --- src/control.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/control.c b/src/control.c index ceb6a7d..4c951b2 100644 --- a/src/control.c +++ b/src/control.c @@ -100,6 +100,7 @@ MixerControl * mixercontrol_new(String const * id, String const * icon, #endif gtk_box_pack_start(GTK_BOX(hbox), control->name, TRUE, TRUE, 0); gtk_frame_set_label_widget(GTK_FRAME(control->frame), hbox); + gtk_container_add(GTK_CONTAINER(control->frame), control->widget); return control; } From 28089c59b2ddb9ba146843cf98e25d02d930cb1c Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 21 May 2017 05:05:34 +0200 Subject: [PATCH 11/68] Set a border around the main container for controls --- src/controls/channels.c | 1 + src/controls/mute.c | 1 + src/controls/radio.c | 1 + src/controls/set.c | 1 + 4 files changed, 4 insertions(+) diff --git a/src/controls/channels.c b/src/controls/channels.c index 8dae478..3f0c853 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -101,6 +101,7 @@ static MixerControlPlugin * _channels_init(String const * type, if((channels = object_new(sizeof(*channels))) == NULL) return NULL; channels->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); + gtk_container_set_border_width(GTK_CONTAINER(channels->widget), 4); channels->channels = NULL; channels->channels_cnt = 0; channels->hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); diff --git a/src/controls/mute.c b/src/controls/mute.c index 2ad2756..0f7d51b 100644 --- a/src/controls/mute.c +++ b/src/controls/mute.c @@ -81,6 +81,7 @@ static MixerControlPlugin * _mute_init(String const * type, va_list properties) if((mute = object_new(sizeof(*mute))) == NULL) return NULL; mute->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); + gtk_container_set_border_width(GTK_CONTAINER(mute->widget), 4); mute->mute = gtk_toggle_button_new(); g_signal_connect(mute->mute, "toggled", G_CALLBACK(_mute_on_toggled), mute); diff --git a/src/controls/radio.c b/src/controls/radio.c index a2f23e9..a746f2b 100644 --- a/src/controls/radio.c +++ b/src/controls/radio.c @@ -90,6 +90,7 @@ static MixerControlPlugin * _radio_init(String const * type, va_list properties) if((radio = object_new(sizeof(*radio))) == NULL) return NULL; radio->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); + gtk_container_set_border_width(GTK_CONTAINER(radio->widget), 4); radio->radio = NULL; radio->radio_cnt = 0; if(_radio_set(radio, properties) != 0) diff --git a/src/controls/set.c b/src/controls/set.c index 21ac745..253447a 100644 --- a/src/controls/set.c +++ b/src/controls/set.c @@ -83,6 +83,7 @@ static MixerControlPlugin * _set_init(String const * type, va_list properties) if((set = object_new(sizeof(*set))) == NULL) return NULL; set->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); + gtk_container_set_border_width(GTK_CONTAINER(set->widget), 4); set->sets = NULL; set->sets_cnt = 0; if(_set_set(set, properties) != 0) From 2ccd08048a5976146cc354e0990bcc54d325f55c Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 21 May 2017 05:11:52 +0200 Subject: [PATCH 12/68] Automatically show or hide the "Bind" button --- src/controls/channels.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/controls/channels.c b/src/controls/channels.c index 3f0c853..368a9b2 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -114,19 +114,20 @@ static MixerControlPlugin * _channels_init(String const * type, gtk_container_add(GTK_CONTAINER(align), channels->hbox); gtk_box_pack_start(GTK_BOX(channels->widget), align, TRUE, TRUE, 0); #endif + channels->mute = gtk_toggle_button_new(); + /* FIXME really implement */ + gtk_box_pack_end(GTK_BOX(channels->widget), channels->mute, + FALSE, TRUE, 0); + channels->bind = gtk_toggle_button_new(); + /* FIXME really implement */ + gtk_widget_set_no_show_all(channels->bind, TRUE); + gtk_box_pack_end(GTK_BOX(channels->widget), channels->bind, + FALSE, TRUE, 0); if(_channels_set(channels, properties) != 0) { _channels_destroy(channels); return NULL; } - channels->bind = gtk_toggle_button_new(); - /* FIXME really implement */ - gtk_box_pack_start(GTK_BOX(channels->widget), channels->bind, - FALSE, TRUE, 0); - channels->mute = gtk_toggle_button_new(); - /* FIXME really implement */ - gtk_box_pack_start(GTK_BOX(channels->widget), channels->mute, - FALSE, TRUE, 0); return channels; } @@ -209,7 +210,10 @@ static int _set_channels(MixerControlPlugin * channels, guint cnt, { for(i = cnt; i < channels->channels_cnt; i++) g_object_unref(channels->channels[i].widget); - channels->channels_cnt = cnt; + if((channels->channels_cnt = cnt) < 2) + gtk_widget_hide(channels->bind); + else + gtk_widget_show(channels->bind); return 0; } if((p = realloc(channels->channels, sizeof(*p) * cnt)) == NULL) @@ -228,7 +232,10 @@ static int _set_channels(MixerControlPlugin * channels, guint cnt, gtk_box_pack_start(GTK_BOX(channels->hbox), p->widget, TRUE, TRUE, 0); } - channels->channels_cnt = cnt; + if((channels->channels_cnt = cnt) < 2) + gtk_widget_hide(channels->bind); + else + gtk_widget_show(channels->bind); return 0; } From f73af29602d38496ac44eda724950f72bf1a7eb9 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 21 May 2017 05:14:21 +0200 Subject: [PATCH 13/68] Use a Gtk+ switch for the mute button with Gtk+ 3 --- src/controls/channels.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/controls/channels.c b/src/controls/channels.c index 368a9b2..c199222 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -114,7 +114,11 @@ static MixerControlPlugin * _channels_init(String const * type, gtk_container_add(GTK_CONTAINER(align), channels->hbox); gtk_box_pack_start(GTK_BOX(channels->widget), align, TRUE, TRUE, 0); #endif +# if GTK_CHECK_VERSION(3, 0, 0) + channels->mute = gtk_switch_new(); +#else channels->mute = gtk_toggle_button_new(); +#endif /* FIXME really implement */ gtk_box_pack_end(GTK_BOX(channels->widget), channels->mute, FALSE, TRUE, 0); @@ -241,7 +245,11 @@ static int _set_channels(MixerControlPlugin * channels, guint cnt, static void _set_mute(MixerControlPlugin * channels, gboolean mute) { +# if GTK_CHECK_VERSION(3, 0, 0) + gtk_switch_set_active(GTK_SWITCH(channels->mute), mute); +#else gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(channels->mute), mute); +#endif } static void _set_value(MixerControlPlugin * channels, gdouble value) From 1defd1f0199a0a8d273b5badc7a33fd2362bab52 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 21 May 2017 05:14:41 +0200 Subject: [PATCH 14/68] Code cleanup --- src/controls/channels.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/controls/channels.c b/src/controls/channels.c index c199222..bf25e5b 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -120,13 +120,13 @@ static MixerControlPlugin * _channels_init(String const * type, channels->mute = gtk_toggle_button_new(); #endif /* FIXME really implement */ - gtk_box_pack_end(GTK_BOX(channels->widget), channels->mute, - FALSE, TRUE, 0); + gtk_box_pack_end(GTK_BOX(channels->widget), channels->mute, FALSE, TRUE, + 0); channels->bind = gtk_toggle_button_new(); /* FIXME really implement */ gtk_widget_set_no_show_all(channels->bind, TRUE); - gtk_box_pack_end(GTK_BOX(channels->widget), channels->bind, - FALSE, TRUE, 0); + gtk_box_pack_end(GTK_BOX(channels->widget), channels->bind, FALSE, TRUE, + 0); if(_channels_set(channels, properties) != 0) { _channels_destroy(channels); From 4a59e57b98a1936f85d99af5fa7db55e4d2e1eba Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 21 May 2017 05:24:15 +0200 Subject: [PATCH 15/68] Set an image and a label for the buttons --- src/controls/channels.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/controls/channels.c b/src/controls/channels.c index bf25e5b..c07ea2c 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -29,8 +29,10 @@ #include +#include #include #include "Mixer/control.h" +#define _(string) gettext(string) /* MixerControlChannels */ @@ -93,6 +95,8 @@ static MixerControlPlugin * _channels_init(String const * type, va_list properties) { MixerControlPlugin * channels; + GtkWidget * hbox; + GtkWidget * widget; #if !GTK_CHECK_VERSION(3, 14, 0) GtkWidget * align; #endif @@ -114,15 +118,30 @@ static MixerControlPlugin * _channels_init(String const * type, gtk_container_add(GTK_CONTAINER(align), channels->hbox); gtk_box_pack_start(GTK_BOX(channels->widget), align, TRUE, TRUE, 0); #endif -# if GTK_CHECK_VERSION(3, 0, 0) +#if GTK_CHECK_VERSION(3, 0, 0) channels->mute = gtk_switch_new(); #else channels->mute = gtk_toggle_button_new(); + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); + widget = gtk_image_new_from_icon_name("audio-volume-muted", + GTK_ICON_SIZE_BUTTON); + gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); + widget = gtk_label_new(_("Mute")); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + gtk_container_add(GTK_CONTAINER(channels->mute), hbox); #endif /* FIXME really implement */ gtk_box_pack_end(GTK_BOX(channels->widget), channels->mute, FALSE, TRUE, 0); channels->bind = gtk_toggle_button_new(); + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); + widget = gtk_image_new_from_stock(GTK_STOCK_CONNECT, + GTK_ICON_SIZE_BUTTON); + gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); + widget = gtk_label_new(_("Bind")); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + gtk_widget_show_all(hbox); + gtk_container_add(GTK_CONTAINER(channels->bind), hbox); /* FIXME really implement */ gtk_widget_set_no_show_all(channels->bind, TRUE); gtk_box_pack_end(GTK_BOX(channels->widget), channels->bind, FALSE, TRUE, From b37868c17a13ce837d2ee44e3764b29e4e2f7958 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 21 May 2017 05:34:07 +0200 Subject: [PATCH 16/68] Update the icon when binding the channels --- src/controls/channels.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/controls/channels.c b/src/controls/channels.c index c07ea2c..2ffd475 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -71,6 +71,8 @@ static int _channels_set(MixerControlPlugin * channels, va_list properties); /* callbacks */ +static void _channels_on_bind_toggled(GtkWidget * widget, gpointer data); + static void _channels_on_changed(gpointer data); @@ -96,6 +98,7 @@ static MixerControlPlugin * _channels_init(String const * type, { MixerControlPlugin * channels; GtkWidget * hbox; + GtkWidget * image; GtkWidget * widget; #if !GTK_CHECK_VERSION(3, 14, 0) GtkWidget * align; @@ -135,15 +138,17 @@ static MixerControlPlugin * _channels_init(String const * type, 0); channels->bind = gtk_toggle_button_new(); hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); - widget = gtk_image_new_from_stock(GTK_STOCK_CONNECT, + image = gtk_image_new_from_icon_name("gtk-connect", GTK_ICON_SIZE_BUTTON); - gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, TRUE, 0); widget = gtk_label_new(_("Bind")); gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); gtk_widget_show_all(hbox); gtk_container_add(GTK_CONTAINER(channels->bind), hbox); - /* FIXME really implement */ gtk_widget_set_no_show_all(channels->bind, TRUE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(channels->bind), TRUE); + g_signal_connect(channels->bind, "toggled", G_CALLBACK( + _channels_on_bind_toggled), image); gtk_box_pack_end(GTK_BOX(channels->widget), channels->bind, FALSE, TRUE, 0); if(_channels_set(channels, properties) != 0) @@ -283,6 +288,19 @@ static void _set_value(MixerControlPlugin * channels, gdouble value) /* callbacks */ +/* channels_on_bind_toggled */ +static void _channels_on_bind_toggled(GtkWidget * widget, gpointer data) +{ + GtkWidget * image = data; + gboolean active; + + active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); + gtk_image_set_from_icon_name(GTK_IMAGE(image), + active ? "gtk-connect" : "gtk-disconnect", + GTK_ICON_SIZE_BUTTON); +} + + /* channels_on_changed */ static void _channels_on_changed(gpointer data) { From 47c4365932e88d36be062d22040b9bae223704b7 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 21 May 2017 05:50:54 +0200 Subject: [PATCH 17/68] Code cleanup --- src/mixer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mixer.c b/src/mixer.c index b7af405..97da6b0 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -1160,7 +1160,6 @@ static int _mixer_get_control(Mixer * mixer, int index, MixerControl * control) control->un.level.channels_cnt = 2; control->un.level.channels[0] = ((value & 0xff) * 255) / 100; control->un.level.channels[1] = (((value >> 8) & 0xff) * 255) / 100; - return 0; #endif return 0; } From 277a86ae62308950b68b0753ba6277ce2e61ebc2 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 22 May 2017 18:43:31 +0200 Subject: [PATCH 18/68] Fix signal handling --- src/controls/channels.c | 81 ++++++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 18 deletions(-) diff --git a/src/controls/channels.c b/src/controls/channels.c index 2ffd475..139e867 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -54,8 +54,15 @@ struct _MixerControlPlugin MixerControlChannel * channels; size_t channels_cnt; + /* bind */ GtkWidget * bind; + GtkWidget * bind_image; + + /* mute */ GtkWidget * mute; +#if !GTK_CHECK_VERSION(3, 0, 0) + GtkWidget * mute_image; +#endif }; @@ -71,9 +78,15 @@ static int _channels_set(MixerControlPlugin * channels, va_list properties); /* callbacks */ -static void _channels_on_bind_toggled(GtkWidget * widget, gpointer data); +static void _channels_on_bind_toggled(gpointer data); -static void _channels_on_changed(gpointer data); +static void _channels_on_changed(GtkWidget * widget, gpointer data); + +#if GTK_CHECK_VERSION(3, 0, 0) +static void _channels_on_mute_notify_active(gpointer data); +#else +static void _channels_on_mute_toggled(gpointer data); +#endif /* public */ @@ -98,7 +111,6 @@ static MixerControlPlugin * _channels_init(String const * type, { MixerControlPlugin * channels; GtkWidget * hbox; - GtkWidget * image; GtkWidget * widget; #if !GTK_CHECK_VERSION(3, 14, 0) GtkWidget * align; @@ -123,32 +135,35 @@ static MixerControlPlugin * _channels_init(String const * type, #endif #if GTK_CHECK_VERSION(3, 0, 0) channels->mute = gtk_switch_new(); + g_signal_connect_swapped(channels->mute, "notify::active", + G_CALLBACK(_channels_on_mute_notify_active), channels); #else channels->mute = gtk_toggle_button_new(); hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); - widget = gtk_image_new_from_icon_name("audio-volume-muted", - GTK_ICON_SIZE_BUTTON); - gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); + channels->mute_image = gtk_image_new_from_icon_name( + "audio-volume-muted", GTK_ICON_SIZE_BUTTON); + gtk_box_pack_start(GTK_BOX(hbox), channels->mute_image, FALSE, TRUE, 0); widget = gtk_label_new(_("Mute")); gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); gtk_container_add(GTK_CONTAINER(channels->mute), hbox); + g_signal_connect_swapped(channels->mute, "toggled", G_CALLBACK( + _channels_on_mute_toggled), channels); #endif - /* FIXME really implement */ gtk_box_pack_end(GTK_BOX(channels->widget), channels->mute, FALSE, TRUE, 0); channels->bind = gtk_toggle_button_new(); hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); - image = gtk_image_new_from_icon_name("gtk-connect", + channels->bind_image = gtk_image_new_from_icon_name("gtk-connect", GTK_ICON_SIZE_BUTTON); - gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), channels->bind_image, FALSE, TRUE, 0); widget = gtk_label_new(_("Bind")); gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); gtk_widget_show_all(hbox); gtk_container_add(GTK_CONTAINER(channels->bind), hbox); gtk_widget_set_no_show_all(channels->bind, TRUE); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(channels->bind), TRUE); - g_signal_connect(channels->bind, "toggled", G_CALLBACK( - _channels_on_bind_toggled), image); + g_signal_connect_swapped(channels->bind, "toggled", G_CALLBACK( + _channels_on_bind_toggled), channels); gtk_box_pack_end(GTK_BOX(channels->widget), channels->bind, FALSE, TRUE, 0); if(_channels_set(channels, properties) != 0) @@ -255,7 +270,7 @@ static int _set_channels(MixerControlPlugin * channels, guint cnt, 0.0, 100.0, 1.0); gtk_range_set_inverted(GTK_RANGE(p->widget), TRUE); gtk_range_set_value(GTK_RANGE(p->widget), value); - g_signal_connect_swapped(p->widget, "value-changed", G_CALLBACK( + g_signal_connect(p->widget, "value-changed", G_CALLBACK( _channels_on_changed), p); gtk_box_pack_start(GTK_BOX(channels->hbox), p->widget, TRUE, TRUE, 0); @@ -289,22 +304,52 @@ static void _set_value(MixerControlPlugin * channels, gdouble value) /* callbacks */ /* channels_on_bind_toggled */ -static void _channels_on_bind_toggled(GtkWidget * widget, gpointer data) +static void _channels_on_bind_toggled(gpointer data) { - GtkWidget * image = data; + MixerControlPlugin * channels = data; gboolean active; - active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); - gtk_image_set_from_icon_name(GTK_IMAGE(image), + active = gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(channels->bind)); + gtk_image_set_from_icon_name(GTK_IMAGE(channels->bind_image), active ? "gtk-connect" : "gtk-disconnect", GTK_ICON_SIZE_BUTTON); } /* channels_on_changed */ -static void _channels_on_changed(gpointer data) +static void _channels_on_changed(GtkWidget * widget, gpointer data) { - MixerControlChannel * channel = data; + MixerControlPlugin * channels = data; + gdouble value; + value = gtk_range_get_value(GTK_RANGE(widget)); /* FIXME implement */ } + + +#if GTK_CHECK_VERSION(3, 0, 0) +/* channels_on_mute_notify_active */ +static void _channels_on_mute_notify_active(gpointer data) +{ + MixerControlPlugin * channels = data; + gboolean active; + + active = gtk_switch_get_active(GTK_SWITCH(channels->mute)); + /* FIXME implement */ +} +#else +/* channels_on_mute_toggled */ +static void _channels_on_mute_toggled(gpointer data) +{ + MixerControlPlugin * channels = data; + gboolean active; + + active = gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(channels->mute)); + gtk_image_set_from_icon_name(GTK_IMAGE(channels->mute_image), + active ? "audio-volume-muted" : "audio-volume-high", + GTK_ICON_SIZE_BUTTON); + /* FIXME implement */ +} +#endif From 7d6edb705d82b5a27c5c75ba8b8b57b118766518 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 22 May 2017 18:45:12 +0200 Subject: [PATCH 19/68] Match the behavior of the mute button for channels --- src/controls/mute.c | 56 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/src/controls/mute.c b/src/controls/mute.c index 0f7d51b..f7df6bb 100644 --- a/src/controls/mute.c +++ b/src/controls/mute.c @@ -28,8 +28,10 @@ -#include "Mixer/control.h" +#include #include +#include "Mixer/control.h" +#define _(string) gettext(string) /* MixerControlMute */ @@ -40,6 +42,9 @@ struct _MixerControlPlugin GtkWidget * widget; GtkWidget * mute; +#if !GTK_CHECK_VERSION(3, 0, 0) + GtkWidget * mute_image; +#endif }; @@ -53,7 +58,11 @@ static GtkWidget * _mute_get_widget(MixerControlPlugin * mute); static int _mute_set(MixerControlPlugin * mute, va_list properties); /* callbacks */ +#if GTK_CHECK_VERSION(3, 0, 0) +static void _mute_on_notify_active(gpointer data); +#else static void _mute_on_toggled(gpointer data); +#endif /* public */ @@ -76,16 +85,33 @@ MixerControlDefinition control = static MixerControlPlugin * _mute_init(String const * type, va_list properties) { MixerControlPlugin * mute; +#if !GTK_CHECK_VERSION(3, 0, 0) + GtkWidget * hbox; + GtkWidget * widget; +#endif (void) type; if((mute = object_new(sizeof(*mute))) == NULL) return NULL; mute->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); gtk_container_set_border_width(GTK_CONTAINER(mute->widget), 4); +#if GTK_CHECK_VERSION(3, 0, 0) + mute->mute = gtk_switch_new(); + g_signal_connect_swapped(mute->mute, "notify::active", + G_CALLBACK(_mute_on_notify_active), mute); +#else mute->mute = gtk_toggle_button_new(); - g_signal_connect(mute->mute, "toggled", G_CALLBACK(_mute_on_toggled), - mute); - gtk_box_pack_start(GTK_BOX(mute->widget), mute->mute, FALSE, TRUE, 0); + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); + mute->mute_image = gtk_image_new_from_icon_name("audio-volume-high", + GTK_ICON_SIZE_BUTTON); + gtk_box_pack_start(GTK_BOX(hbox), mute->mute_image, FALSE, TRUE, 0); + widget = gtk_label_new(_("Mute")); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + gtk_container_add(GTK_CONTAINER(mute->mute), hbox); + g_signal_connect_swapped(mute->mute, "toggled", + G_CALLBACK(_mute_on_toggled), mute); +#endif + gtk_box_pack_end(GTK_BOX(mute->widget), mute->mute, FALSE, TRUE, 0); if(_mute_set(mute, properties) != 0) { _mute_destroy(mute); @@ -122,8 +148,12 @@ static int _mute_set(MixerControlPlugin * mute, va_list properties) if(string_compare(p, "value") == 0) { value = va_arg(properties, gboolean); +#if GTK_CHECK_VERSION(3, 0, 0) + gtk_switch_set_active(GTK_SWITCH(mute->mute), value); +#else gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(mute->mute), value); +#endif } else /* FIXME report the error */ @@ -134,10 +164,28 @@ static int _mute_set(MixerControlPlugin * mute, va_list properties) /* callbacks */ +#if GTK_CHECK_VERSION(3, 0, 0) +/* mute_on_notify_active */ +static void _mute_on_notify_active(gpointer data) +{ + MixerControlPlugin * mute = data; + gboolean active; + + active = gtk_switch_get_active(GTK_SWITCH(mute->mute)); + /* FIXME implement */ +} +#else /* mute_on_toggled */ static void _mute_on_toggled(gpointer data) { MixerControlPlugin * mute = data; + gboolean active; + + active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mute->mute)); + gtk_image_set_from_icon_name(GTK_IMAGE(mute->mute_image), + active ? "audio-volume-muted" : "audio-volume-high", + GTK_ICON_SIZE_BUTTON); /* FIXME implement */ } +#endif From 6da2573fc2df399049767252e6025694088f27f3 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 22 May 2017 23:13:34 +0200 Subject: [PATCH 20/68] Place the mute button directly below the channels --- src/controls/channels.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/controls/channels.c b/src/controls/channels.c index 139e867..a97941d 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -133,6 +133,22 @@ static MixerControlPlugin * _channels_init(String const * type, gtk_container_add(GTK_CONTAINER(align), channels->hbox); gtk_box_pack_start(GTK_BOX(channels->widget), align, TRUE, TRUE, 0); #endif + /* bind */ + channels->bind = gtk_toggle_button_new(); + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); + channels->bind_image = gtk_image_new_from_icon_name("gtk-connect", + GTK_ICON_SIZE_BUTTON); + gtk_box_pack_start(GTK_BOX(hbox), channels->bind_image, FALSE, TRUE, 0); + widget = gtk_label_new(_("Bind")); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + gtk_widget_show_all(hbox); + gtk_container_add(GTK_CONTAINER(channels->bind), hbox); + gtk_widget_set_no_show_all(channels->bind, TRUE); + g_signal_connect_swapped(channels->bind, "toggled", G_CALLBACK( + _channels_on_bind_toggled), channels); + gtk_box_pack_end(GTK_BOX(channels->widget), channels->bind, FALSE, TRUE, + 0); + /* mute */ #if GTK_CHECK_VERSION(3, 0, 0) channels->mute = gtk_switch_new(); g_signal_connect_swapped(channels->mute, "notify::active", @@ -145,27 +161,14 @@ static MixerControlPlugin * _channels_init(String const * type, gtk_box_pack_start(GTK_BOX(hbox), channels->mute_image, FALSE, TRUE, 0); widget = gtk_label_new(_("Mute")); gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + gtk_widget_show_all(hbox); gtk_container_add(GTK_CONTAINER(channels->mute), hbox); g_signal_connect_swapped(channels->mute, "toggled", G_CALLBACK( _channels_on_mute_toggled), channels); #endif + gtk_widget_set_no_show_all(channels->mute, TRUE); gtk_box_pack_end(GTK_BOX(channels->widget), channels->mute, FALSE, TRUE, 0); - channels->bind = gtk_toggle_button_new(); - hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); - channels->bind_image = gtk_image_new_from_icon_name("gtk-connect", - GTK_ICON_SIZE_BUTTON); - gtk_box_pack_start(GTK_BOX(hbox), channels->bind_image, FALSE, TRUE, 0); - widget = gtk_label_new(_("Bind")); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); - gtk_widget_show_all(hbox); - gtk_container_add(GTK_CONTAINER(channels->bind), hbox); - gtk_widget_set_no_show_all(channels->bind, TRUE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(channels->bind), TRUE); - g_signal_connect_swapped(channels->bind, "toggled", G_CALLBACK( - _channels_on_bind_toggled), channels); - gtk_box_pack_end(GTK_BOX(channels->widget), channels->bind, FALSE, TRUE, - 0); if(_channels_set(channels, properties) != 0) { _channels_destroy(channels); From 7d71e6d0277f1c53fb858b484daaac81d3712d83 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 22 May 2017 23:14:14 +0200 Subject: [PATCH 21/68] Also implement "show-bind" and "show-mute" --- src/controls/channels.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/controls/channels.c b/src/controls/channels.c index a97941d..e145587 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -233,6 +233,18 @@ static int _channels_set(MixerControlPlugin * channels, b = va_arg(properties, gboolean); _set_mute(channels, b); } + else if(string_compare(p, "show-bind") == 0) + { + value = va_arg(properties, gboolean); + value ? gtk_widget_show(channels->bind) + : gtk_widget_hide(channels->bind); + } + else if(string_compare(p, "show-mute") == 0) + { + value = va_arg(properties, gboolean); + value ? gtk_widget_show(channels->mute) + : gtk_widget_hide(channels->mute); + } else /* FIXME report the error */ return -1; From d33caae4e62c47e19f0a6765a22a961b1ef9234f Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 22 May 2017 23:15:19 +0200 Subject: [PATCH 22/68] Implement labels for the "radio" control --- src/controls/radio.c | 56 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/src/controls/radio.c b/src/controls/radio.c index a746f2b..e92a830 100644 --- a/src/controls/radio.c +++ b/src/controls/radio.c @@ -28,6 +28,7 @@ +#include #include #include "Mixer/control.h" @@ -46,8 +47,9 @@ struct _MixerControlPlugin { GtkWidget * widget; - MixerControlRadio * radio; - size_t radio_cnt; + GSList * group; + MixerControlRadio * radios; + size_t radios_cnt; }; @@ -59,8 +61,7 @@ static void _radio_destroy(MixerControlPlugin * radio); static GtkWidget * _radio_get_widget(MixerControlPlugin * radio); -static int _radio_set(MixerControlPlugin * radio, - va_list properties); +static int _radio_set(MixerControlPlugin * radio, va_list properties); /* callbacks */ @@ -91,8 +92,9 @@ static MixerControlPlugin * _radio_init(String const * type, va_list properties) return NULL; radio->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); gtk_container_set_border_width(GTK_CONTAINER(radio->widget), 4); - radio->radio = NULL; - radio->radio_cnt = 0; + radio->group = NULL; + radio->radios = NULL; + radio->radios_cnt = 0; if(_radio_set(radio, properties) != 0) { _radio_destroy(radio); @@ -105,6 +107,7 @@ static MixerControlPlugin * _radio_init(String const * type, va_list properties) /* radio_destroy */ static void _radio_destroy(MixerControlPlugin * radio) { + free(radio->radios); g_object_unref(radio->widget); object_delete(radio); } @@ -119,11 +122,15 @@ static GtkWidget * _radio_get_widget(MixerControlPlugin * radio) /* radio_set */ +static int _set_label(MixerControlPlugin * radio, guint pos, + String const * label); static void _set_value(MixerControlPlugin * radio, guint value); static int _radio_set(MixerControlPlugin * radio, va_list properties) { String const * p; + String const * s; + unsigned int u; guint value; while((p = va_arg(properties, String const *)) != NULL) @@ -133,6 +140,12 @@ static int _radio_set(MixerControlPlugin * radio, va_list properties) value = va_arg(properties, guint); _set_value(radio, value); } + else if(sscanf(p, "label%u", &u) == 1) + { + s = va_arg(properties, String const *); + if(_set_label(radio, u, s) != 0) + return -1; + } else /* FIXME report the error */ return -1; @@ -140,6 +153,37 @@ static int _radio_set(MixerControlPlugin * radio, va_list properties) return 0; } +static int _set_label(MixerControlPlugin * radio, guint pos, + String const * label) +{ + guint i; + MixerControlRadio * p; + + if(pos >= radio->radios_cnt) + { + if((p = realloc(radio->radios, sizeof(*p) * (pos + 1))) == NULL) + return -1; + radio->radios = p; + } + for(i = radio->radios_cnt; i < pos; i++) + { + radio->radios[i].plugin = radio; + /* FIXME set the correct label */ + radio->radios[i].widget = gtk_radio_button_new_with_label( + radio->group, label); + /* FIXME implement the callback */ + if(radio->group == NULL) + radio->group = gtk_radio_button_get_group( + GTK_RADIO_BUTTON( + radio->radios[i].widget)); + gtk_box_pack_start(GTK_BOX(radio->widget), + radio->radios[i].widget, FALSE, TRUE, 0); + } + radio->radios_cnt = pos; + gtk_widget_show_all(radio->widget); + return 0; +} + static void _set_value(MixerControlPlugin * radio, guint value) { /* FIXME implement */ From 725eb71ee1e88af9d1929b65adfe1e3170979829 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 22 May 2017 23:16:02 +0200 Subject: [PATCH 23/68] Implement the labels for the "set" control --- src/controls/set.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/controls/set.c b/src/controls/set.c index 253447a..045448c 100644 --- a/src/controls/set.c +++ b/src/controls/set.c @@ -28,6 +28,7 @@ +#include #include #include "Mixer/control.h" @@ -37,6 +38,8 @@ /* types */ typedef struct _MixerControlSet { + MixerControlPlugin * plugin; + GtkWidget * widget; } MixerControlSet; @@ -98,6 +101,7 @@ static MixerControlPlugin * _set_init(String const * type, va_list properties) /* set_destroy */ static void _set_destroy(MixerControlPlugin * set) { + free(set->sets); g_object_unref(set->widget); object_delete(set); } @@ -112,11 +116,15 @@ static GtkWidget * _set_get_widget(MixerControlPlugin * set) /* set_set */ +static int _set_label(MixerControlPlugin * set, guint pos, + String const * label); static void _set_value(MixerControlPlugin * set, guint value); static int _set_set(MixerControlPlugin * set, va_list properties) { String const * p; + String const * s; + unsigned int u; guint value; while((p = va_arg(properties, String const *)) != NULL) @@ -126,6 +134,11 @@ static int _set_set(MixerControlPlugin * set, va_list properties) value = va_arg(properties, guint); _set_value(set, value); } + else if(sscanf(p, "label%u", &u) == 1) + { + s = va_arg(properties, String const *); + _set_label(set, u, s); + } else /* FIXME report the error */ return -1; @@ -133,7 +146,36 @@ static int _set_set(MixerControlPlugin * set, va_list properties) return 0; } +static int _set_label(MixerControlPlugin * set, guint pos, String const * label) +{ + guint i; + MixerControlSet * p; + + if(pos >= set->sets_cnt) + { + if((p = realloc(set->sets, sizeof(*p) * (pos + 1))) == NULL) + return -1; + set->sets = p; + } + for(i = set->sets_cnt; i < pos; i++) + { + set->sets[i].plugin = set; + /* FIXME set the correct label */ + set->sets[i].widget = gtk_check_button_new_with_label(label); + /* FIXME implement the callback */ + gtk_box_pack_start(GTK_BOX(set->widget), set->sets[i].widget, + FALSE, TRUE, 0); + } + set->sets_cnt = pos; + gtk_widget_show_all(set->widget); + return 0; +} + static void _set_value(MixerControlPlugin * set, guint value) { /* FIXME implement */ } + + +/* callbacks */ +/* FIXME implement */ From cd940287dc9d2469006f17c5e100dc216adcfdb0 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 22 May 2017 23:27:06 +0200 Subject: [PATCH 24/68] Add a couple comments --- src/controls/radio.c | 1 + src/controls/set.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/controls/radio.c b/src/controls/radio.c index e92a830..95c1510 100644 --- a/src/controls/radio.c +++ b/src/controls/radio.c @@ -159,6 +159,7 @@ static int _set_label(MixerControlPlugin * radio, guint pos, guint i; MixerControlRadio * p; + /* FIXME free and reduce if necessary */ if(pos >= radio->radios_cnt) { if((p = realloc(radio->radios, sizeof(*p) * (pos + 1))) == NULL) diff --git a/src/controls/set.c b/src/controls/set.c index 045448c..ec078c9 100644 --- a/src/controls/set.c +++ b/src/controls/set.c @@ -151,6 +151,7 @@ static int _set_label(MixerControlPlugin * set, guint pos, String const * label) guint i; MixerControlSet * p; + /* FIXME free and reduce if necessary */ if(pos >= set->sets_cnt) { if((p = realloc(set->sets, sizeof(*p) * (pos + 1))) == NULL) From 7bc7133abf68eb63d437c00af1874e1b51103e30 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 22 May 2017 23:28:24 +0200 Subject: [PATCH 25/68] Remove duplicate copyright line --- src/window.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/window.c b/src/window.c index ec02f7f..0d2f873 100644 --- a/src/window.c +++ b/src/window.c @@ -1,5 +1,4 @@ /* $Id$ */ -/* Copyright (c) 2015-2016 Pierre Pronchery */ static char _copyright[] = "Copyright © 2009-2017 Pierre Pronchery "; /* This file is part of DeforaOS Desktop Mixer */ From 504a1d350e29779d8f47376ab169029e6f286f9a Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 22 May 2017 23:28:39 +0200 Subject: [PATCH 26/68] Create a taller window by default in vertical layout --- src/window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window.c b/src/window.c index 0d2f873..5fb7eeb 100644 --- a/src/window.c +++ b/src/window.c @@ -240,7 +240,7 @@ MixerWindow * mixerwindow_new(char const * device, MixerLayout layout, mixer->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_add_accel_group(GTK_WINDOW(mixer->window), accel); gtk_window_set_default_size(GTK_WINDOW(mixer->window), 800, - 350); + (layout == ML_VERTICAL) ? 600 : 350); #if GTK_CHECK_VERSION(2, 6, 0) gtk_window_set_icon_name(GTK_WINDOW(mixer->window), "stock_volume"); From 48a2380fffeae488df3b24e44991f5769f947f72 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 23 May 2017 00:17:05 +0200 Subject: [PATCH 27/68] Improve the layout for the "bind" and "mute" buttons --- src/controls/channels.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/controls/channels.c b/src/controls/channels.c index e145587..387f9d4 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -54,6 +54,8 @@ struct _MixerControlPlugin MixerControlChannel * channels; size_t channels_cnt; + GtkWidget * bbox; + /* bind */ GtkWidget * bind; GtkWidget * bind_image; @@ -74,8 +76,7 @@ static void _channels_destroy(MixerControlPlugin * channels); static GtkWidget * _channels_get_widget(MixerControlPlugin * channels); -static int _channels_set(MixerControlPlugin * channels, - va_list properties); +static int _channels_set(MixerControlPlugin * channels, va_list properties); /* callbacks */ static void _channels_on_bind_toggled(gpointer data); @@ -133,6 +134,8 @@ static MixerControlPlugin * _channels_init(String const * type, gtk_container_add(GTK_CONTAINER(align), channels->hbox); gtk_box_pack_start(GTK_BOX(channels->widget), align, TRUE, TRUE, 0); #endif + channels->bbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); + gtk_box_set_homogeneous(GTK_BOX(channels->bbox), TRUE); /* bind */ channels->bind = gtk_toggle_button_new(); hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); @@ -146,8 +149,9 @@ static MixerControlPlugin * _channels_init(String const * type, gtk_widget_set_no_show_all(channels->bind, TRUE); g_signal_connect_swapped(channels->bind, "toggled", G_CALLBACK( _channels_on_bind_toggled), channels); - gtk_box_pack_end(GTK_BOX(channels->widget), channels->bind, FALSE, TRUE, - 0); + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_pack_start(GTK_BOX(hbox), channels->bind, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(channels->bbox), hbox, FALSE, TRUE, 0); /* mute */ #if GTK_CHECK_VERSION(3, 0, 0) channels->mute = gtk_switch_new(); @@ -167,7 +171,10 @@ static MixerControlPlugin * _channels_init(String const * type, _channels_on_mute_toggled), channels); #endif gtk_widget_set_no_show_all(channels->mute, TRUE); - gtk_box_pack_end(GTK_BOX(channels->widget), channels->mute, FALSE, TRUE, + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_pack_start(GTK_BOX(hbox), channels->mute, TRUE, TRUE, 0); + gtk_box_pack_end(GTK_BOX(channels->bbox), hbox, FALSE, TRUE, 0); + gtk_box_pack_end(GTK_BOX(channels->widget), channels->bbox, FALSE, TRUE, 0); if(_channels_set(channels, properties) != 0) { @@ -200,12 +207,14 @@ static int _set_channels(MixerControlPlugin * channels, guint cnt, gdouble value); static void _set_mute(MixerControlPlugin * channels, gboolean mute); static void _set_value(MixerControlPlugin * channels, gdouble value); +static void _set_value_channel(MixerControlPlugin * channels, guint channel, + gdouble value); -static int _channels_set(MixerControlPlugin * channels, - va_list properties) +static int _channels_set(MixerControlPlugin * channels, va_list properties) { String const * p; gboolean b; + GtkSizeGroup * group; guint u; gdouble value = 0.0; @@ -245,6 +254,11 @@ static int _channels_set(MixerControlPlugin * channels, value ? gtk_widget_show(channels->mute) : gtk_widget_hide(channels->mute); } + else if(string_compare(p, "vgroup") == 0) + { + group = va_arg(properties, GtkSizeGroup *); + gtk_size_group_add_widget(group, channels->bbox); + } else /* FIXME report the error */ return -1; From 88d812b4c021be8a51c966703a957f5494a19eeb Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 23 May 2017 00:17:54 +0200 Subject: [PATCH 28/68] Allow setting the values of each channel separately --- src/controls/channels.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/controls/channels.c b/src/controls/channels.c index 387f9d4..edc205e 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -225,6 +225,11 @@ static int _channels_set(MixerControlPlugin * channels, va_list properties) value = va_arg(properties, gdouble); _set_value(channels, value); } + else if(sscanf(p, "value%u", &u) == 1) + { + value = va_arg(properties, gdouble); + _set_value_channel(channels, u, value); + } else if(string_compare(p, "bind") == 0) { b = va_arg(properties, gboolean); @@ -323,11 +328,21 @@ static void _set_mute(MixerControlPlugin * channels, gboolean mute) static void _set_value(MixerControlPlugin * channels, gdouble value) { size_t i; + + for(i = 0; i < channels->channels_cnt; i++) + _set_value_channel(channels, i, value); +} + +static void _set_value_channel(MixerControlPlugin * channels, guint channel, + gdouble value) +{ gdouble v; - v = (value / 255.0) * 100.0; - for(i = 0; i < channels->channels_cnt; i++) - gtk_range_set_value(GTK_RANGE(channels->channels[i].widget), v); + v = (value * 100.0) / 255.0; + if(channel < channels->channels_cnt) + gtk_range_set_value( + GTK_RANGE(channels->channels[channel].widget), + v); } From e2f0cfbc3516a3d903f906d7d7e3785a25eb276c Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 23 May 2017 00:18:26 +0200 Subject: [PATCH 29/68] Delete buttons as required --- src/controls/radio.c | 5 ++++- src/controls/set.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/controls/radio.c b/src/controls/radio.c index 95c1510..4b89434 100644 --- a/src/controls/radio.c +++ b/src/controls/radio.c @@ -159,7 +159,10 @@ static int _set_label(MixerControlPlugin * radio, guint pos, guint i; MixerControlRadio * p; - /* FIXME free and reduce if necessary */ + /* delete buttons as required */ + if(radio->radios_cnt >= pos) + for(i = pos; i < radio->radios_cnt; i++) + g_object_unref(radio->radios[i].widget); if(pos >= radio->radios_cnt) { if((p = realloc(radio->radios, sizeof(*p) * (pos + 1))) == NULL) diff --git a/src/controls/set.c b/src/controls/set.c index ec078c9..70e9d47 100644 --- a/src/controls/set.c +++ b/src/controls/set.c @@ -151,7 +151,10 @@ static int _set_label(MixerControlPlugin * set, guint pos, String const * label) guint i; MixerControlSet * p; - /* FIXME free and reduce if necessary */ + /* delete buttons as required */ + if(set->sets_cnt >= pos) + for(i = pos; i < set->sets_cnt; i++) + g_object_unref(set->sets[i].widget); if(pos >= set->sets_cnt) { if((p = realloc(set->sets, sizeof(*p) * (pos + 1))) == NULL) From 7160eefaa9cef5a1156db079c895144210675fa1 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 23 May 2017 01:31:32 +0200 Subject: [PATCH 30/68] Code cleanup --- src/controls/channels.c | 43 +++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/src/controls/channels.c b/src/controls/channels.c index edc205e..5593eac 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -203,34 +203,23 @@ static GtkWidget * _channels_get_widget(MixerControlPlugin * channels) /* channels_set */ static void _set_bind(MixerControlPlugin * channels, gboolean bind); -static int _set_channels(MixerControlPlugin * channels, guint cnt, - gdouble value); +static int _set_channels(MixerControlPlugin * channels, unsigned int cnt); static void _set_mute(MixerControlPlugin * channels, gboolean mute); static void _set_value(MixerControlPlugin * channels, gdouble value); -static void _set_value_channel(MixerControlPlugin * channels, guint channel, - gdouble value); +static void _set_value_channel(MixerControlPlugin * channels, + unsigned int channel, gdouble value); static int _channels_set(MixerControlPlugin * channels, va_list properties) { String const * p; gboolean b; GtkSizeGroup * group; - guint u; + unsigned int u; gdouble value = 0.0; while((p = va_arg(properties, String const *)) != NULL) { - if(string_compare(p, "value") == 0) - { - value = va_arg(properties, gdouble); - _set_value(channels, value); - } - else if(sscanf(p, "value%u", &u) == 1) - { - value = va_arg(properties, gdouble); - _set_value_channel(channels, u, value); - } - else if(string_compare(p, "bind") == 0) + if(string_compare(p, "bind") == 0) { b = va_arg(properties, gboolean); _set_bind(channels, b); @@ -238,8 +227,7 @@ static int _channels_set(MixerControlPlugin * channels, va_list properties) else if(string_compare(p, "channels") == 0) { u = va_arg(properties, unsigned int); - /* FIXME look for the initial value first */ - if(_set_channels(channels, u, value) != 0) + if(_set_channels(channels, u) != 0) return -1; } else if(string_compare(p, "mute") == 0) @@ -259,6 +247,16 @@ static int _channels_set(MixerControlPlugin * channels, va_list properties) value ? gtk_widget_show(channels->mute) : gtk_widget_hide(channels->mute); } + else if(string_compare(p, "value") == 0) + { + value = va_arg(properties, gdouble); + _set_value(channels, value); + } + else if(sscanf(p, "value%u", &u) == 1) + { + value = va_arg(properties, gdouble); + _set_value_channel(channels, u, value); + } else if(string_compare(p, "vgroup") == 0) { group = va_arg(properties, GtkSizeGroup *); @@ -276,8 +274,7 @@ static void _set_bind(MixerControlPlugin * channels, gboolean bind) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(channels->bind), bind); } -static int _set_channels(MixerControlPlugin * channels, guint cnt, - gdouble value) +static int _set_channels(MixerControlPlugin * channels, unsigned int cnt) { size_t i; MixerControlChannel * p; @@ -303,7 +300,7 @@ static int _set_channels(MixerControlPlugin * channels, guint cnt, p->widget = gtk_scale_new_with_range(GTK_ORIENTATION_VERTICAL, 0.0, 100.0, 1.0); gtk_range_set_inverted(GTK_RANGE(p->widget), TRUE); - gtk_range_set_value(GTK_RANGE(p->widget), value); + gtk_range_set_value(GTK_RANGE(p->widget), 0.0); g_signal_connect(p->widget, "value-changed", G_CALLBACK( _channels_on_changed), p); gtk_box_pack_start(GTK_BOX(channels->hbox), p->widget, TRUE, @@ -333,8 +330,8 @@ static void _set_value(MixerControlPlugin * channels, gdouble value) _set_value_channel(channels, i, value); } -static void _set_value_channel(MixerControlPlugin * channels, guint channel, - gdouble value) +static void _set_value_channel(MixerControlPlugin * channels, + unsigned int channel, gdouble value) { gdouble v; From f76eb85c0d97d65f210146d5be632bcafa967cda Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 23 May 2017 01:31:48 +0200 Subject: [PATCH 31/68] Implement a "delta" property --- src/controls/channels.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/controls/channels.c b/src/controls/channels.c index 5593eac..77bbb8a 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -49,6 +49,8 @@ struct _MixerControlPlugin { GtkWidget * widget; + unsigned int delta; + /* channels */ GtkWidget * hbox; MixerControlChannel * channels; @@ -122,6 +124,7 @@ static MixerControlPlugin * _channels_init(String const * type, return NULL; channels->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); gtk_container_set_border_width(GTK_CONTAINER(channels->widget), 4); + channels->delta = 1; channels->channels = NULL; channels->channels_cnt = 0; channels->hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); @@ -204,6 +207,7 @@ static GtkWidget * _channels_get_widget(MixerControlPlugin * channels) /* channels_set */ static void _set_bind(MixerControlPlugin * channels, gboolean bind); static int _set_channels(MixerControlPlugin * channels, unsigned int cnt); +static void _set_delta(MixerControlPlugin * channels, unsigned int delta); static void _set_mute(MixerControlPlugin * channels, gboolean mute); static void _set_value(MixerControlPlugin * channels, gdouble value); static void _set_value_channel(MixerControlPlugin * channels, @@ -230,6 +234,11 @@ static int _channels_set(MixerControlPlugin * channels, va_list properties) if(_set_channels(channels, u) != 0) return -1; } + else if(string_compare(p, "delta") == 0) + { + u = va_arg(properties, unsigned int); + _set_delta(channels, u); + } else if(string_compare(p, "mute") == 0) { b = va_arg(properties, gboolean); @@ -298,7 +307,7 @@ static int _set_channels(MixerControlPlugin * channels, unsigned int cnt) p = &channels->channels[i]; p->plugin = channels; p->widget = gtk_scale_new_with_range(GTK_ORIENTATION_VERTICAL, - 0.0, 100.0, 1.0); + 0.0, 100.0, channels->delta); gtk_range_set_inverted(GTK_RANGE(p->widget), TRUE); gtk_range_set_value(GTK_RANGE(p->widget), 0.0); g_signal_connect(p->widget, "value-changed", G_CALLBACK( @@ -313,6 +322,17 @@ static int _set_channels(MixerControlPlugin * channels, unsigned int cnt) return 0; } +static void _set_delta(MixerControlPlugin * channels, unsigned int delta) +{ + size_t i; + + channels->delta = delta; + for(i = 0; i < channels->channels_cnt; i++) + gtk_range_set_increments( + GTK_RANGE(channels->channels[i].widget), delta, + delta); +} + static void _set_mute(MixerControlPlugin * channels, gboolean mute) { # if GTK_CHECK_VERSION(3, 0, 0) From 475af1b44dca1fca324d2752917900a5dd251407 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 23 May 2017 01:34:15 +0200 Subject: [PATCH 32/68] Rework the properties --- src/controls/radio.c | 97 +++++++++++++++++++++++++++++++------------- src/controls/set.c | 97 ++++++++++++++++++++++++++++++++------------ 2 files changed, 138 insertions(+), 56 deletions(-) diff --git a/src/controls/radio.c b/src/controls/radio.c index 4b89434..0333a92 100644 --- a/src/controls/radio.c +++ b/src/controls/radio.c @@ -40,6 +40,8 @@ typedef struct _MixerControlRadio { MixerControlPlugin * plugin; + unsigned int value; + GtkWidget * widget; } MixerControlRadio; @@ -122,30 +124,46 @@ static GtkWidget * _radio_get_widget(MixerControlPlugin * radio) /* radio_set */ -static int _set_label(MixerControlPlugin * radio, guint pos, +static int _set_label(MixerControlPlugin * radio, unsigned int pos, String const * label); -static void _set_value(MixerControlPlugin * radio, guint value); +static int _set_members(MixerControlPlugin * radio, unsigned int cnt); +static int _set_value(MixerControlPlugin * radio, unsigned int value); +static int _set_value_pos(MixerControlPlugin * radio, unsigned int pos, + unsigned int value); static int _radio_set(MixerControlPlugin * radio, va_list properties) { String const * p; String const * s; unsigned int u; - guint value; + unsigned int value; while((p = va_arg(properties, String const *)) != NULL) { - if(string_compare(p, "value") == 0) - { - value = va_arg(properties, guint); - _set_value(radio, value); - } - else if(sscanf(p, "label%u", &u) == 1) + if(sscanf(p, "label%u", &u) == 1) { s = va_arg(properties, String const *); if(_set_label(radio, u, s) != 0) return -1; } + else if(string_compare(p, "members") == 0) + { + u = va_arg(properties, unsigned int); + if(_set_members(radio, u) != 0) + return -1; + } + else if(string_compare(p, "value") == 0) + { + value = va_arg(properties, unsigned int); + if(_set_value(radio, value) != 0) + return -1; + } + else if(sscanf(p, "value%u", &u) == 1) + { + value = va_arg(properties, unsigned int); + if(_set_value_pos(radio, u, value) != 0) + return -1; + } else /* FIXME report the error */ return -1; @@ -153,44 +171,65 @@ static int _radio_set(MixerControlPlugin * radio, va_list properties) return 0; } -static int _set_label(MixerControlPlugin * radio, guint pos, +static int _set_label(MixerControlPlugin * radio, unsigned int pos, String const * label) { - guint i; + if(pos >= radio->radios_cnt) + return -1; + gtk_button_set_label(GTK_BUTTON(radio->radios[pos].widget), label); + return 0; +} + +static int _set_members(MixerControlPlugin * radio, unsigned int cnt) +{ + size_t i; MixerControlRadio * p; /* delete buttons as required */ - if(radio->radios_cnt >= pos) - for(i = pos; i < radio->radios_cnt; i++) + if(radio->radios_cnt >= cnt) + { + for(i = cnt; i < radio->radios_cnt; i++) g_object_unref(radio->radios[i].widget); - if(pos >= radio->radios_cnt) - { - if((p = realloc(radio->radios, sizeof(*p) * (pos + 1))) == NULL) - return -1; - radio->radios = p; + radio->radios_cnt = cnt; + return 0; } - for(i = radio->radios_cnt; i < pos; i++) + if((p = realloc(radio->radios, sizeof(*p) * cnt)) == NULL) + return -1; + radio->radios = p; + for(i = radio->radios_cnt; i < cnt; i++) { - radio->radios[i].plugin = radio; - /* FIXME set the correct label */ - radio->radios[i].widget = gtk_radio_button_new_with_label( - radio->group, label); + p = &radio->radios[i]; + p->plugin = radio; + p->value = 0; + p->widget = gtk_radio_button_new(radio->group); + gtk_widget_set_sensitive(p->widget, FALSE); /* FIXME implement the callback */ if(radio->group == NULL) radio->group = gtk_radio_button_get_group( - GTK_RADIO_BUTTON( - radio->radios[i].widget)); - gtk_box_pack_start(GTK_BOX(radio->widget), - radio->radios[i].widget, FALSE, TRUE, 0); + GTK_RADIO_BUTTON(p->widget)); + gtk_box_pack_start(GTK_BOX(radio->widget), p->widget, FALSE, + TRUE, 0); } - radio->radios_cnt = pos; + radio->radios_cnt = cnt; gtk_widget_show_all(radio->widget); return 0; } -static void _set_value(MixerControlPlugin * radio, guint value) +static int _set_value(MixerControlPlugin * radio, unsigned int value) { /* FIXME implement */ + return 0; +} + +static int _set_value_pos(MixerControlPlugin * radio, unsigned int pos, + unsigned int value) +{ + if(pos >= radio->radios_cnt) + return -1; + radio->radios[pos].value = value; + gtk_widget_set_sensitive(radio->radios[pos].widget, (value != 0) + ? TRUE : FALSE); + return 0; } diff --git a/src/controls/set.c b/src/controls/set.c index 70e9d47..bb8cbd2 100644 --- a/src/controls/set.c +++ b/src/controls/set.c @@ -40,6 +40,8 @@ typedef struct _MixerControlSet { MixerControlPlugin * plugin; + unsigned int value; + GtkWidget * widget; } MixerControlSet; @@ -116,28 +118,45 @@ static GtkWidget * _set_get_widget(MixerControlPlugin * set) /* set_set */ -static int _set_label(MixerControlPlugin * set, guint pos, +static int _set_label(MixerControlPlugin * set, unsigned int pos, String const * label); -static void _set_value(MixerControlPlugin * set, guint value); +static int _set_members(MixerControlPlugin * set, unsigned int cnt); +static int _set_value(MixerControlPlugin * set, unsigned int value); +static int _set_value_pos(MixerControlPlugin * set, unsigned int pos, + unsigned int value); static int _set_set(MixerControlPlugin * set, va_list properties) { String const * p; String const * s; unsigned int u; - guint value; + unsigned int value; while((p = va_arg(properties, String const *)) != NULL) { - if(string_compare(p, "value") == 0) - { - value = va_arg(properties, guint); - _set_value(set, value); - } - else if(sscanf(p, "label%u", &u) == 1) + if(sscanf(p, "label%u", &u) == 1) { s = va_arg(properties, String const *); - _set_label(set, u, s); + if(_set_label(set, u, s) != 0) + return -1; + } + else if(string_compare(p, "members") == 0) + { + u = va_arg(properties, unsigned int); + if(_set_members(set, u) != 0) + return -1; + } + else if(string_compare(p, "value") == 0) + { + value = va_arg(properties, unsigned int); + if(_set_value(set, value) != 0) + return -1; + } + else if(sscanf(p, "value%u", &u) == 1) + { + value = va_arg(properties, unsigned int); + if(_set_value_pos(set, u, value) != 0) + return -1; } else /* FIXME report the error */ @@ -146,38 +165,62 @@ static int _set_set(MixerControlPlugin * set, va_list properties) return 0; } -static int _set_label(MixerControlPlugin * set, guint pos, String const * label) +static int _set_label(MixerControlPlugin * set, unsigned int pos, + String const * label) { - guint i; + if(pos >= set->sets_cnt) + return -1; + gtk_button_set_label(GTK_BUTTON(set->sets[pos].widget), label); + return 0; +} + +static int _set_members(MixerControlPlugin * set, unsigned int cnt) +{ + size_t i; MixerControlSet * p; /* delete buttons as required */ - if(set->sets_cnt >= pos) - for(i = pos; i < set->sets_cnt; i++) + if(set->sets_cnt >= cnt) + { + for(i = cnt; i < set->sets_cnt; i++) g_object_unref(set->sets[i].widget); - if(pos >= set->sets_cnt) - { - if((p = realloc(set->sets, sizeof(*p) * (pos + 1))) == NULL) - return -1; - set->sets = p; + set->sets_cnt = cnt; + return 0; } - for(i = set->sets_cnt; i < pos; i++) + if((p = realloc(set->sets, sizeof(*p) * cnt)) == NULL) + return -1; + set->sets = p; + for(i = set->sets_cnt; i < cnt; i++) { - set->sets[i].plugin = set; - /* FIXME set the correct label */ - set->sets[i].widget = gtk_check_button_new_with_label(label); + p = &set->sets[i]; + p->plugin = set; + p->value = 0; + p->widget = gtk_check_button_new(); + gtk_widget_set_sensitive(p->widget, FALSE); /* FIXME implement the callback */ - gtk_box_pack_start(GTK_BOX(set->widget), set->sets[i].widget, - FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(set->widget), p->widget, FALSE, TRUE, + 0); } - set->sets_cnt = pos; + set->sets_cnt = cnt; gtk_widget_show_all(set->widget); return 0; } -static void _set_value(MixerControlPlugin * set, guint value) +static int _set_value(MixerControlPlugin * set, unsigned int value) { /* FIXME implement */ + return 0; +} + +static int _set_value_pos(MixerControlPlugin * set, unsigned int pos, + unsigned int value) +{ + if(pos >= set->sets_cnt) + return -1; + set->sets[pos].value = value; + gtk_widget_set_sensitive(set->sets[pos].widget, (value != 0) + ? TRUE : FALSE); + return 0; } From 287eded619a3ca8a2ae2137ac81613c4a675ff7d Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 23 May 2017 01:35:58 +0200 Subject: [PATCH 33/68] Use a button box for the "radio" and "set" controls --- src/controls/radio.c | 7 ++++--- src/controls/set.c | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/controls/radio.c b/src/controls/radio.c index 0333a92..37c90ca 100644 --- a/src/controls/radio.c +++ b/src/controls/radio.c @@ -92,7 +92,9 @@ static MixerControlPlugin * _radio_init(String const * type, va_list properties) if((radio = object_new(sizeof(*radio))) == NULL) return NULL; - radio->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); + radio->widget = gtk_button_box_new(GTK_ORIENTATION_VERTICAL); + gtk_button_box_set_layout(GTK_BUTTON_BOX(radio->widget), + GTK_BUTTONBOX_SPREAD); gtk_container_set_border_width(GTK_CONTAINER(radio->widget), 4); radio->group = NULL; radio->radios = NULL; @@ -207,8 +209,7 @@ static int _set_members(MixerControlPlugin * radio, unsigned int cnt) if(radio->group == NULL) radio->group = gtk_radio_button_get_group( GTK_RADIO_BUTTON(p->widget)); - gtk_box_pack_start(GTK_BOX(radio->widget), p->widget, FALSE, - TRUE, 0); + gtk_container_add(GTK_CONTAINER(radio->widget), p->widget); } radio->radios_cnt = cnt; gtk_widget_show_all(radio->widget); diff --git a/src/controls/set.c b/src/controls/set.c index bb8cbd2..0e603a4 100644 --- a/src/controls/set.c +++ b/src/controls/set.c @@ -87,7 +87,9 @@ static MixerControlPlugin * _set_init(String const * type, va_list properties) if((set = object_new(sizeof(*set))) == NULL) return NULL; - set->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); + set->widget = gtk_button_box_new(GTK_ORIENTATION_VERTICAL); + gtk_button_box_set_layout(GTK_BUTTON_BOX(set->widget), + GTK_BUTTONBOX_SPREAD); gtk_container_set_border_width(GTK_CONTAINER(set->widget), 4); set->sets = NULL; set->sets_cnt = 0; @@ -198,8 +200,7 @@ static int _set_members(MixerControlPlugin * set, unsigned int cnt) p->widget = gtk_check_button_new(); gtk_widget_set_sensitive(p->widget, FALSE); /* FIXME implement the callback */ - gtk_box_pack_start(GTK_BOX(set->widget), p->widget, FALSE, TRUE, - 0); + gtk_container_add(GTK_CONTAINER(set->widget), p->widget); } set->sets_cnt = cnt; gtk_widget_show_all(set->widget); From cf8d3653f4b921dc0dee576ae55ddcc387b205db Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 23 May 2017 01:54:20 +0200 Subject: [PATCH 34/68] Add debugging information --- src/control.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/control.c b/src/control.c index 4c951b2..604b561 100644 --- a/src/control.c +++ b/src/control.c @@ -62,6 +62,10 @@ MixerControl * mixercontrol_new(String const * id, String const * icon, va_list ap; GtkWidget * hbox; +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(\"%s\", \"%s\", \"%s\")\n", __func__, id, + name, type); +#endif if((control = object_new(sizeof(*control))) == NULL) return NULL; control->id = string_new(id); @@ -83,6 +87,10 @@ MixerControl * mixercontrol_new(String const * id, String const * icon, control->plugin)) == NULL) { va_end(ap); +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s() => NULL %p %p\n", __func__, + control->handle, control->definition); +#endif mixercontrol_delete(control); return NULL; } From a7ee8d3a1f8b677e7533f9d8959047909ab13ceb Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 23 May 2017 01:56:08 +0200 Subject: [PATCH 35/68] Use the new control widgets Some features are still missing from before the transition: - actually set the volume - implement channel binding - group channels by class - specific icons per control Some improvements were made: - support for a delta (step) when setting channel values - nicer interface overall However this paves the way for allowing to refresh the volume automatically in the background. --- src/mixer.c | 419 ++++++++++++++++++---------------------------------- src/mixer.h | 3 +- 2 files changed, 146 insertions(+), 276 deletions(-) diff --git a/src/mixer.c b/src/mixer.c index 97da6b0..01b0936 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -48,6 +48,7 @@ #include #include #include +#include "control.h" #include "mixer.h" #include "../config.h" #define _(string) gettext(string) @@ -75,6 +76,7 @@ typedef struct _MixerClass typedef struct _MixerLevel { uint8_t channels[8]; + uint8_t delta; size_t channels_cnt; } MixerLevel; @@ -99,7 +101,7 @@ struct _Mixer PangoFontDescription * bold; /* internals */ - char * device; + String * device; #ifdef AUDIO_MIXER_DEVINFO int fd; @@ -108,6 +110,9 @@ struct _Mixer #else int fd; #endif + + MixerControl ** controls; + size_t controls_cnt; }; @@ -130,40 +135,28 @@ static void _mixer_show_view(Mixer * mixer, int view); static GtkWidget * _new_frame_label(GdkPixbuf * pixbuf, char const * name, char const * label); #ifdef AUDIO_MIXER_DEVINFO -static GtkWidget * _new_enum(Mixer * mixer, int dev, - struct audio_mixer_enum * e); -static GtkWidget * _new_mute(Mixer * mixer, int dev, - struct audio_mixer_enum * e); -static GtkWidget * _new_set(Mixer * mixer, int dev, struct audio_mixer_set * s); -/* callbacks */ -static void _new_enum_on_toggled(GtkWidget * widget, gpointer data); -#if GTK_CHECK_VERSION(3, 0, 0) -static void _new_mute_on_notify(GObject * object, GParamSpec * spec, - gpointer data); -#else -static void _new_mute_on_toggled(GtkWidget * widget, gpointer data); +static MixerControl * _new_enum(Mixer * mixer, int dev, + struct audio_mixer_enum * e, String const * id, + String const * icon, String const * name); +static MixerControl * _new_set(Mixer * mixer, int dev, + struct audio_mixer_set * s, String const * id, + String const * icon, String const * name); #endif -static void _new_set_on_toggled(GtkWidget * widget, gpointer data); -#endif -static GtkWidget * _new_value(Mixer * mixer, int index, GtkWidget ** bbox); -/* callbacks */ -static void _new_bind_on_toggled(GtkWidget * widget, gpointer data); -static void _new_value_on_changed(GtkWidget * widget, gpointer data); +static MixerControl * _new_value(Mixer * mixer, int index, + GtkSizeGroup * vgroup, String const * id, String const * icon, + String const * name); -Mixer * mixer_new(GtkWidget * window, char const * device, MixerLayout layout) +Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout) { Mixer * mixer; GtkSizeGroup * hgroup; -#ifndef AUDIO_MIXER_DEVINFO GtkSizeGroup * vgroup; -#endif GtkWidget * scrolled = NULL; GtkWidget * label; GtkWidget * widget; GtkWidget * hvbox = NULL; GtkWidget * hbox; - GtkWidget * bbox; - GtkWidget * control; + MixerControl * control; int i; #ifdef AUDIO_MIXER_DEVINFO mixer_devinfo_t md; @@ -182,7 +175,7 @@ Mixer * mixer_new(GtkWidget * window, char const * device, MixerLayout layout) return NULL; if(device == NULL) device = MIXER_DEFAULT_DEVICE; - mixer->device = strdup(device); + mixer->device = string_new(device); mixer->fd = open(device, O_RDWR); mixer->window = window; mixer->properties = NULL; @@ -191,10 +184,10 @@ Mixer * mixer_new(GtkWidget * window, char const * device, MixerLayout layout) mixer->mc = NULL; mixer->mc_cnt = 0; #endif + mixer->controls = NULL; + mixer->controls_cnt = 0; hgroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); -#ifndef AUDIO_MIXER_DEVINFO vgroup = gtk_size_group_new(GTK_SIZE_GROUP_VERTICAL); -#endif if(mixer->device == NULL || mixer->fd < 0) { _mixer_error(NULL, device, 0); @@ -277,35 +270,35 @@ Mixer * mixer_new(GtkWidget * window, char const * device, MixerLayout layout) if(u == mixer->mc_cnt) continue; hbox = mixer->mc[u].hbox; - bbox = NULL; control = NULL; switch(md.type) { case AUDIO_MIXER_ENUM: - control = _new_enum(mixer, i, &md.un.e); + control = _new_enum(mixer, i, &md.un.e, + md.label.name, + "audio-value-high", + md.label.name); break; case AUDIO_MIXER_SET: - control = _new_set(mixer, i, &md.un.s); + control = _new_set(mixer, i, &md.un.s, + md.label.name, + "audio-value-high", + md.label.name); break; case AUDIO_MIXER_VALUE: - bbox = gtk_button_box_new( - GTK_ORIENTATION_VERTICAL); - gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), - GTK_BUTTONBOX_START); - gtk_size_group_add_widget(vgroup, bbox); - control = _new_value(mixer, i, &bbox); + control = _new_value(mixer, i, vgroup, + md.label.name, + "audio-volume-high", + md.label.name); break; } if(control == NULL) continue; + widget = mixercontrol_get_widget(control); vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4); - gtk_box_pack_start(GTK_BOX(vbox2), control, TRUE, TRUE, 0); - label = _new_frame_label(NULL, md.label.name, NULL); - widget = gtk_frame_new(NULL); + gtk_box_pack_start(GTK_BOX(vbox2), widget, TRUE, TRUE, 0); gtk_size_group_add_widget(hgroup, widget); - gtk_frame_set_label_widget(GTK_FRAME(widget), label); - gtk_container_add(GTK_CONTAINER(widget), vbox2); if(hbox == NULL) { mixer->mc[u].hbox = gtk_box_new( @@ -336,9 +329,9 @@ Mixer * mixer_new(GtkWidget * window, char const * device, MixerLayout layout) gtk_box_pack_start(GTK_BOX(hvbox), hbox, FALSE, TRUE, 0); } - gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), vbox2, FALSE, TRUE, 0); /* add a mute button if relevant */ - if(bbox == NULL) + if(md.type != AUDIO_MIXER_VALUE) continue; md2.index = md.index + 1; if(ioctl(mixer->fd, AUDIO_MIXER_DEVINFO, &md2) < 0) @@ -356,30 +349,20 @@ Mixer * mixer_new(GtkWidget * window, char const * device, MixerLayout layout) || (u = strlen(md2.label.name)) < 6 || strcmp(&md2.label.name[u - 5], ".mute") != 0) continue; - if((widget = _new_mute(mixer, i + 1, &md2.un.e)) == NULL) - continue; - gtk_container_add(GTK_CONTAINER(bbox), widget); + /* XXX may fail */ + mixercontrol_set(control, "show-mute", TRUE, NULL); i++; #else if(i == SOUND_MIXER_NONE) break; if(ioctl(mixer->fd, MIXER_READ(i), &value) != 0) continue; -# if GTK_CHECK_VERSION(3, 0, 0) - bbox = gtk_button_box_new(GTK_ORIENTATION_VERTICAL); -# else - bbox = gtk_vbutton_box_new(); -# endif - gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), - GTK_BUTTONBOX_START); - gtk_size_group_add_widget(vgroup, bbox); - control = _new_value(mixer, i, &bbox); - gtk_container_set_border_width(GTK_CONTAINER(control), 4); - label = _new_frame_label(NULL, names[i], labels[i]); - widget = gtk_frame_new(NULL); + if((control = _new_value(mixer, i, vgroup, names[i], + "audio-volume-high", labels[i])) + == NULL) + continue; + widget = mixercontrol_get_widget(control); gtk_size_group_add_widget(hgroup, widget); - gtk_frame_set_label_widget(GTK_FRAME(widget), label); - gtk_container_add(GTK_CONTAINER(widget), control); gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); #endif } @@ -458,277 +441,158 @@ static GtkWidget * _new_frame_label(GdkPixbuf * pixbuf, char const * name, } #ifdef AUDIO_MIXER_DEVINFO -static GtkWidget * _new_enum(Mixer * mixer, int dev, - struct audio_mixer_enum * e) +static MixerControl * _new_enum(Mixer * mixer, int dev, + struct audio_mixer_enum * e, String const * id, + String const * icon, String const * name) { MixerControl * mc; - GtkWidget * vbox; + MixerControl * control; int i; - GtkWidget * widget; - GSList * group = NULL; - int * q; + char label[16]; + char value[16]; if(e->num_mem <= 0 || (mc = malloc(sizeof(*mc))) == NULL) return NULL; - if(_mixer_get_control(mixer, dev, mc) != 0) + if(_mixer_get_control(mixer, dev, mc) != 0 + || (control = mixercontrol_new(id, icon, name, "radio", + "members", e->num_mem, NULL)) == NULL) { free(mc); return NULL; } - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); for(i = 0; i < e->num_mem; i++) { - widget = gtk_radio_button_new_with_label(group, - e->member[i].label.name); - group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(widget)); - if(mc->un.ord == i) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), - TRUE); - g_object_set_data(G_OBJECT(widget), "ctrl", mc); - if((q = malloc(sizeof(*q))) != NULL) + snprintf(label, sizeof(label), "label%d", i); + snprintf(value, sizeof(value), "value%d", i); + if(mixercontrol_set(control, label, e->member[i].label.name, + value, e->member[i].ord, NULL) != 0) { - *q = e->member[i].ord; - g_object_set_data(G_OBJECT(widget), "ord", q); + mixercontrol_delete(control); + return NULL; } - g_signal_connect(widget, "toggled", G_CALLBACK( - _new_enum_on_toggled), mixer); - gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0); } - return vbox; -} - -static GtkWidget * _new_mute(Mixer * mixer, int dev, - struct audio_mixer_enum * e) -{ - MixerControl * mc; -#if !GTK_CHECK_VERSION(3, 0, 0) - GtkWidget * hbox; -#endif - GtkWidget * widget; - gboolean active; - - if(e->num_mem != 2 || (mc = malloc(sizeof(*mc))) == NULL) - return NULL; - if(_mixer_get_control(mixer, dev, mc) != 0) + if(mixercontrol_set(control, "value", mc->un.mask, NULL) != 0) { - free(mc); + mixercontrol_delete(control); return NULL; } -# if GTK_CHECK_VERSION(3, 0, 0) - widget = gtk_switch_new(); - active = (strcmp(e->member[mc->un.ord].label.name, "on") == 0) - ? FALSE : TRUE; - gtk_switch_set_active(GTK_SWITCH(widget), active); - g_object_set_data(G_OBJECT(widget), "ctrl", mc); - g_signal_connect(widget, "notify::active", - G_CALLBACK(_new_mute_on_notify), mixer); -# else - hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); - widget = gtk_image_new_from_icon_name("audio-volume-muted", - GTK_ICON_SIZE_BUTTON); - gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); - widget = gtk_label_new(_("Mute")); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); - widget = gtk_toggle_button_new(); - gtk_container_add(GTK_CONTAINER(widget), hbox); - active = (strcmp(e->member[mc->un.ord].label.name, "on") == 0) - ? TRUE : FALSE; - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), active); - g_object_set_data(G_OBJECT(widget), "ctrl", mc); - g_signal_connect(widget, "toggled", G_CALLBACK(_new_mute_on_toggled), - mixer); -# endif - return widget; + return control; } -static GtkWidget * _new_set(Mixer * mixer, int dev, struct audio_mixer_set * s) +static MixerControl * _new_set(Mixer * mixer, int dev, + struct audio_mixer_set * s, String const * id, + String const * icon, String const * name) { MixerControl * mc; - GtkWidget * vbox; + MixerControl * control; int i; - GtkWidget * widget; - int * q; + char label[16]; + char value[16]; if(s->num_mem <= 0 || (mc = malloc(sizeof(*mc))) == NULL) return NULL; - if(_mixer_get_control(mixer, dev, mc) != 0) + if(_mixer_get_control(mixer, dev, mc) != 0 + || (control = mixercontrol_new(id, icon, name, "set", + "members", s->num_mem, NULL)) == NULL) { free(mc); return NULL; } - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_box_set_homogeneous(GTK_BOX(vbox), TRUE); for(i = 0; i < s->num_mem; i++) { - widget = gtk_check_button_new_with_label( - s->member[i].label.name); - if(mc->un.mask & (1 << i)) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), - TRUE); - g_object_set_data(G_OBJECT(widget), "ctrl", mc); - if((q = malloc(sizeof(*q))) != NULL) + snprintf(label, sizeof(label), "label%d", i); + snprintf(value, sizeof(value), "value%d", i); + if(mixercontrol_set(control, label, s->member[i].label.name, + value, s->member[i].mask, NULL) != 0) { - *q = s->member[i].mask; - g_object_set_data(G_OBJECT(widget), "mask", q); + mixercontrol_delete(control); + return NULL; } - g_signal_connect(widget, "toggled", G_CALLBACK( - _new_set_on_toggled), mixer); - gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0); } - return vbox; -} - -/* callbacks */ -static void _new_enum_on_toggled(GtkWidget * widget, gpointer data) -{ - Mixer * mixer = data; - - if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)) == TRUE) - mixer_set_enum(mixer, widget); -} - -#if GTK_CHECK_VERSION(3, 0, 0) -static void _new_mute_on_notify(GObject * object, GParamSpec * spec, - gpointer data) -{ - Mixer * mixer = data; - (void) spec; - - mixer_set_mute(mixer, GTK_WIDGET(object)); -} -#else -static void _new_mute_on_toggled(GtkWidget * widget, gpointer data) -{ - Mixer * mixer = data; - - mixer_set_mute(mixer, widget); -} -#endif - -static void _new_set_on_toggled(GtkWidget * widget, gpointer data) -{ - Mixer * mixer = data; - -#ifdef DEBUG - fprintf(stderr, "DEBUG: %s()\n", __func__); -#endif - mixer_set_set(mixer, widget); + if(mixercontrol_set(control, "value", mc->un.mask, NULL) != 0) + { + mixercontrol_delete(control); + return NULL; + } + return control; } #endif /* AUDIO_MIXER_DEVINFO */ -static GtkWidget * _new_value(Mixer * mixer, int index, GtkWidget ** bbox) +static MixerControl * _new_value(Mixer * mixer, int index, + GtkSizeGroup * vgroup, String const * id, String const * icon, + String const * name) { -#if !GTK_CHECK_VERSION(3, 14, 0) - GtkWidget * align; -#endif - GtkWidget * vbox; - GtkWidget * hbox; - GtkWidget * image; - GtkWidget * widget; - GtkWidget * bind = NULL; - GSList * list = NULL; - size_t i; - gdouble v; MixerControl * mc; + MixerControl * control; + size_t i; + gboolean bind = TRUE; + char buf[16]; + gdouble value; - if((mc = malloc(sizeof(*mc))) == NULL) - return NULL; - if(_mixer_get_control(mixer, index, mc) != 0 - || mc->un.level.channels_cnt <= 0) + if((mc = malloc(sizeof(*mc))) == NULL + || _mixer_get_control(mixer, index, mc) != 0 + || mc->un.level.channels_cnt <= 0 + || (control = mixercontrol_new(id, icon, name, + "channels", + "channels", mc->un.level.channels_cnt, + "delta", mc->un.level.delta, + "vgroup", vgroup, NULL)) == NULL) { free(mc); return NULL; } - /* bind button */ - if(mc->un.level.channels_cnt >= 2) - { - hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); - image = gtk_image_new_from_stock(GTK_STOCK_CONNECT, - GTK_ICON_SIZE_BUTTON); - gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, TRUE, 0); - widget = gtk_label_new(_("Bind")); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); - bind = gtk_toggle_button_new(); - gtk_container_add(GTK_CONTAINER(bind), hbox); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bind), TRUE); - g_signal_connect(bind, "toggled", G_CALLBACK( - _new_bind_on_toggled), image); - } - /* sliders */ - hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - for(i = 0; i < mc->un.level.channels_cnt; i++) - { -#if GTK_CHECK_VERSION(3, 0, 0) - widget = gtk_scale_new_with_range(GTK_ORIENTATION_VERTICAL, 0.0, - 100.0, 1.0); -#else - widget = gtk_vscale_new_with_range(0.0, 100.0, 1.0); -#endif - gtk_range_set_inverted(GTK_RANGE(widget), TRUE); - v = (mc->un.level.channels[i] / 255.0) * 100.0; - gtk_range_set_value(GTK_RANGE(widget), v); - if(bind != NULL) + free(mc); + /* detect if binding is in place */ + for(i = 1; i < mc->un.level.channels_cnt; i++) + if(mc->un.level.channels[i] != mc->un.level.channels[0]) { - g_object_set_data(G_OBJECT(widget), "bind", bind); - list = g_slist_append(list, widget); + bind = FALSE; + break; + } + if(bind) + { + value = (mc->un.level.channels[0] / 255.0) * 100.0; + if(mixercontrol_set(control, "value", value, "bind", bind, NULL) + != 0) + { + mixercontrol_delete(control); + return NULL; } - g_object_set_data(G_OBJECT(widget), "ctrl", mc); - g_object_set_data(G_OBJECT(widget), "channel", - &mc->un.level.channels[i]); - g_signal_connect(widget, "value-changed", G_CALLBACK( - _new_value_on_changed), mixer); - gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); } - if(mc->un.level.channels_cnt < 2) - return hbox; - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); -#if GTK_CHECK_VERSION(3, 14, 0) - gtk_widget_set_halign(hbox, GTK_ALIGN_CENTER); - gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); -#else - align = gtk_alignment_new(0.5, 0.5, 0.0, 1.0); - gtk_container_add(GTK_CONTAINER(align), hbox); - gtk_box_pack_start(GTK_BOX(vbox), align, TRUE, TRUE, 0); -#endif - g_object_set_data(G_OBJECT(bind), "list", list); - gtk_container_add(GTK_CONTAINER(*bbox), bind); - gtk_box_pack_start(GTK_BOX(vbox), *bbox, FALSE, TRUE, 0); - return vbox; -} - -/* callbacks */ -static void _new_bind_on_toggled(GtkWidget * widget, gpointer data) -{ - GtkWidget * image = data; - gboolean active; - - active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); - gtk_image_set_from_stock(GTK_IMAGE(image), - active ? GTK_STOCK_CONNECT : GTK_STOCK_DISCONNECT, - GTK_ICON_SIZE_BUTTON); -} - -static void _new_value_on_changed(GtkWidget * widget, gpointer data) -{ - Mixer * mixer = data; - gdouble value; - -#ifdef DEBUG - fprintf(stderr, "DEBUG: %s(%p, %f, %p)\n", __func__, (void *)widget, - value, (void *)data); -#endif - value = gtk_range_get_value(GTK_RANGE(widget)); - mixer_set_value(mixer, widget, value); + else + { + if(mixercontrol_set(control, "bind", bind, NULL) != 0) + { + mixercontrol_delete(control); + return NULL; + } + for(i = 0; i < mc->un.level.channels_cnt; i++) + { + snprintf(buf, sizeof(buf), "value%zu", i); + value = (mc->un.level.channels[i] / 255.0) * 100.0; + if(mixercontrol_set(control, buf, value, NULL) != 0) + { + mixercontrol_delete(control); + return NULL; + } + } + } + return control; } /* mixer_delete */ void mixer_delete(Mixer * mixer) { + size_t i; + + for(i = 0; i < mixer->controls_cnt; i++) + mixercontrol_delete(mixer->controls[i]); + free(mixer->controls); if(mixer->fd >= 0) close(mixer->fd); if(mixer->device != NULL) - free(mixer->device); + string_delete(mixer->device); if(mixer->bold != NULL) pango_font_description_free(mixer->bold); free(mixer); @@ -1134,6 +998,9 @@ static int _mixer_get_control(Mixer * mixer, int index, MixerControl * control) # endif break; case AUDIO_MIXER_VALUE: + if((control->un.level.delta = (md.un.v.delta * 100) + / 255) == 0) + control->un.level.delta = 1; control->un.level.channels_cnt = p.un.value.num_channels; for(i = 0; i < p.un.value.num_channels; i++) @@ -1157,9 +1024,11 @@ static int _mixer_get_control(Mixer * mixer, int index, MixerControl * control) if(ioctl(mixer->fd, MIXER_READ(index), &value) != 0) return -_mixer_error(NULL, "MIXER_READ", 1); control->type = 0; + control->un.level.delta = 1; control->un.level.channels_cnt = 2; control->un.level.channels[0] = ((value & 0xff) * 255) / 100; - control->un.level.channels[1] = (((value >> 8) & 0xff) * 255) / 100; + control->un.level.channels[1] = ((((value & 0xff00) >> 8) & 0xff) * 255) + / 100; #endif return 0; } diff --git a/src/mixer.h b/src/mixer.h index 796535d..c83e3bd 100644 --- a/src/mixer.h +++ b/src/mixer.h @@ -32,6 +32,7 @@ # define MIXER_MIXER_H # include /* XXX should not be necessary */ +# include /* Mixer */ @@ -54,7 +55,7 @@ typedef struct _Mixer Mixer; /* functions */ -Mixer * mixer_new(GtkWidget * window, char const * device, MixerLayout layout); +Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout); void mixer_delete(Mixer * mixer); /* accessors */ From 524355135eda9c3676b437f9dfadc82af4a24134 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 23 May 2017 01:56:25 +0200 Subject: [PATCH 36/68] Update the copyright notice --- src/mixer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mixer.h b/src/mixer.h index c83e3bd..9537567 100644 --- a/src/mixer.h +++ b/src/mixer.h @@ -1,5 +1,5 @@ /* $Id$ */ -/* Copyright (c) 2009-2015 Pierre Pronchery */ +/* Copyright (c) 2009-2017 Pierre Pronchery */ /* This file is part of DeforaOS Desktop Mixer */ /* All rights reserved. * From 80442f9424be7c8cb48bd0f7568edd8188e56812 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 23 May 2017 02:03:02 +0200 Subject: [PATCH 37/68] Minor optimization --- src/mixer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mixer.c b/src/mixer.c index 01b0936..f610d76 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -1027,8 +1027,7 @@ static int _mixer_get_control(Mixer * mixer, int index, MixerControl * control) control->un.level.delta = 1; control->un.level.channels_cnt = 2; control->un.level.channels[0] = ((value & 0xff) * 255) / 100; - control->un.level.channels[1] = ((((value & 0xff00) >> 8) & 0xff) * 255) - / 100; + control->un.level.channels[1] = (((value & 0xff00) >> 8) * 255) / 100; #endif return 0; } From 0fa5ce2f16bb5bce70bbd3bdebe1be05181aba60 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 23 May 2017 02:10:06 +0200 Subject: [PATCH 38/68] Correct the border in horizontal and vertical layouts --- src/mixer.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mixer.c b/src/mixer.c index f610d76..9658a20 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -209,7 +209,8 @@ Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout) ? GTK_POLICY_AUTOMATIC : GTK_POLICY_NEVER); hvbox = gtk_box_new((layout == ML_VERTICAL) ? GTK_ORIENTATION_VERTICAL - : GTK_ORIENTATION_HORIZONTAL, 0); + : GTK_ORIENTATION_HORIZONTAL, 4); + gtk_container_set_border_width(GTK_CONTAINER(hvbox), 4); if(layout == ML_VERTICAL) gtk_box_set_homogeneous(GTK_BOX(hvbox), TRUE); _mixer_scrolled_window_add(scrolled, hvbox); @@ -296,7 +297,6 @@ Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout) continue; widget = mixercontrol_get_widget(control); vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); - gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4); gtk_box_pack_start(GTK_BOX(vbox2), widget, TRUE, TRUE, 0); gtk_size_group_add_widget(hgroup, widget); if(hbox == NULL) @@ -304,7 +304,6 @@ Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout) mixer->mc[u].hbox = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 4); hbox = mixer->mc[u].hbox; - gtk_container_set_border_width(GTK_CONTAINER(hbox), 4); if(mixer->notebook != NULL) { if((name = strdup(mixer->mc[u].label.name)) From b4c29bb8219c44c5f710b2a9de648d1aaf5bb0bf Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 23 May 2017 02:16:20 +0200 Subject: [PATCH 39/68] Correct the channel levels --- src/mixer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mixer.c b/src/mixer.c index 9658a20..6ad76e1 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -550,7 +550,7 @@ static MixerControl * _new_value(Mixer * mixer, int index, } if(bind) { - value = (mc->un.level.channels[0] / 255.0) * 100.0; + value = mc->un.level.channels[0]; if(mixercontrol_set(control, "value", value, "bind", bind, NULL) != 0) { @@ -568,7 +568,7 @@ static MixerControl * _new_value(Mixer * mixer, int index, for(i = 0; i < mc->un.level.channels_cnt; i++) { snprintf(buf, sizeof(buf), "value%zu", i); - value = (mc->un.level.channels[i] / 255.0) * 100.0; + value = mc->un.level.channels[i]; if(mixercontrol_set(control, buf, value, NULL) != 0) { mixercontrol_delete(control); From ee90a8edb5e2933e6380fbb87216e74df7b58b4b Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 23 May 2017 02:17:12 +0200 Subject: [PATCH 40/68] Code cleanup --- src/controls/channels.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/controls/channels.c b/src/controls/channels.c index 77bbb8a..93cf959 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -353,13 +353,10 @@ static void _set_value(MixerControlPlugin * channels, gdouble value) static void _set_value_channel(MixerControlPlugin * channels, unsigned int channel, gdouble value) { - gdouble v; - - v = (value * 100.0) / 255.0; if(channel < channels->channels_cnt) gtk_range_set_value( GTK_RANGE(channels->channels[channel].widget), - v); + (value * 100.0) / 255.0); } From add0b21907db565f345403401265f3fdefb808ab Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 23 May 2017 03:09:55 +0200 Subject: [PATCH 41/68] Choose more appropriate icons again --- src/mixer.c | 93 +++++++++++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 42 deletions(-) diff --git a/src/mixer.c b/src/mixer.c index 6ad76e1..83e934c 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -122,11 +122,16 @@ struct _Mixer /* prototypes */ static int _mixer_error(Mixer * mixer, char const * message, int ret); + /* accessors */ static int _mixer_get_control(Mixer * mixer, int index, MixerControl * control); static int _mixer_set_control(Mixer * mixer, int index, MixerControl * control); + +static String const * _mixer_get_icon(String const * id); + /* useful */ static void _mixer_scrolled_window_add(GtkWidget * window, GtkWidget * widget); + static void _mixer_show_view(Mixer * mixer, int view); @@ -277,19 +282,19 @@ Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout) case AUDIO_MIXER_ENUM: control = _new_enum(mixer, i, &md.un.e, md.label.name, - "audio-value-high", + _mixer_get_icon(md.label.name), md.label.name); break; case AUDIO_MIXER_SET: control = _new_set(mixer, i, &md.un.s, md.label.name, - "audio-value-high", + _mixer_get_icon(md.label.name), md.label.name); break; case AUDIO_MIXER_VALUE: control = _new_value(mixer, i, vgroup, md.label.name, - "audio-volume-high", + _mixer_get_icon(md.label.name), md.label.name); break; } @@ -357,7 +362,8 @@ Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout) if(ioctl(mixer->fd, MIXER_READ(i), &value) != 0) continue; if((control = _new_value(mixer, i, vgroup, names[i], - "audio-volume-high", labels[i])) + _mixer_get_icon(names[i]), + labels[i])) == NULL) continue; widget = mixercontrol_get_widget(control); @@ -379,49 +385,14 @@ static GtkWidget * _new_frame_label(GdkPixbuf * pixbuf, char const * name, GtkIconTheme * icontheme; GtkWidget * hbox; GtkWidget * widget; - struct - { - char const * name; - char const * icon; - } icons[] = { - { "beep", "audio-volume-high" }, - { "cd", "media-cdrom" }, - { "dacsel", "audio-card" }, - { "input", "stock_mic" }, - { "line", "stock_volume" }, - { "master", "audio-volume-high" }, - { "mic", "audio-input-microphone"}, - { "monitor", "utilities-system-monitor"}, - { "output", "audio-volume-high" }, - { "pcm", "audio-volume-high" }, - { "rec", "gtk-media-record" }, - { "source", "audio-card" }, - { "vol", "audio-volume-high" } - }; - size_t i; - size_t len; const int size = 16; icontheme = gtk_icon_theme_get_default(); hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); - for(i = 0; pixbuf == NULL && i < sizeof(icons) / sizeof(*icons); i++) - if(strncmp(icons[i].name, name, strlen(icons[i].name)) == 0) - pixbuf = gtk_icon_theme_load_icon(icontheme, - icons[i].icon, size, - GTK_ICON_LOOKUP_GENERIC_FALLBACK, NULL); if(pixbuf == NULL) - { - len = strlen(name); - /* more generic fallbacks */ - if(strstr(name, "sel") != NULL) - pixbuf = gtk_icon_theme_load_icon(icontheme, - "multimedia", size, - GTK_ICON_LOOKUP_GENERIC_FALLBACK, NULL); - else if(len > 5 && strcmp(&name[len - 5], ".mute") == 0) - pixbuf = gtk_icon_theme_load_icon(icontheme, - "audio-volume-muted", size, - GTK_ICON_LOOKUP_GENERIC_FALLBACK, NULL); - } + pixbuf = gtk_icon_theme_load_icon(icontheme, + _mixer_get_icon(name), size, + GTK_ICON_LOOKUP_GENERIC_FALLBACK, NULL); if(pixbuf != NULL) { widget = gtk_image_new_from_pixbuf(pixbuf); @@ -1032,6 +1003,44 @@ static int _mixer_get_control(Mixer * mixer, int index, MixerControl * control) } +/* mixer_get_icon */ +static String const * _mixer_get_icon(String const * id) +{ + struct + { + String const * name; + String const * icon; + } icons[] = { + { "beep", "audio-volume-high" }, + { "cd", "media-cdrom" }, + { "dacsel", "audio-card" }, + { "input", "stock_mic" }, + { "line", "stock_volume" }, + { "master", "audio-volume-high" }, + { "mic", "audio-input-microphone"}, + { "monitor", "utilities-system-monitor"}, + { "output", "audio-volume-high" }, + { "pcm", "audio-volume-high" }, + { "rec", "gtk-media-record" }, + { "source", "audio-card" }, + { "vol", "audio-volume-high" } + }; + size_t len; + size_t i; + + for(i = 0; i < sizeof(icons) / sizeof(*icons); i++) + if(strncmp(icons[i].name, id, string_length(icons[i].name)) + == 0) + return icons[i].icon; + len = string_length(id); + if(string_find(id, "sel") != NULL) + return "multimedia"; + else if(len > 5 && string_compare(&id[len - 5], ".mute") == 0) + return "audio-volume-muted"; + return "audio-volume-high"; +} + + /* mixer_set_control */ static int _mixer_set_control(Mixer * mixer, int index, MixerControl * control) { From 076a381cf2e876c01d26a52fe3c652a594d89dc7 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sat, 27 May 2017 02:51:25 +0200 Subject: [PATCH 42/68] Code cleanup --- src/controls/channels.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/controls/channels.c b/src/controls/channels.c index 93cf959..03f5dcb 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -206,12 +206,12 @@ static GtkWidget * _channels_get_widget(MixerControlPlugin * channels) /* channels_set */ static void _set_bind(MixerControlPlugin * channels, gboolean bind); -static int _set_channels(MixerControlPlugin * channels, unsigned int cnt); +static int _set_channels(MixerControlPlugin * channels, size_t cnt); static void _set_delta(MixerControlPlugin * channels, unsigned int delta); static void _set_mute(MixerControlPlugin * channels, gboolean mute); static void _set_value(MixerControlPlugin * channels, gdouble value); static void _set_value_channel(MixerControlPlugin * channels, - unsigned int channel, gdouble value); + size_t channel, gdouble value); static int _channels_set(MixerControlPlugin * channels, va_list properties) { @@ -220,6 +220,7 @@ static int _channels_set(MixerControlPlugin * channels, va_list properties) GtkSizeGroup * group; unsigned int u; gdouble value = 0.0; + size_t zu; while((p = va_arg(properties, String const *)) != NULL) { @@ -230,8 +231,8 @@ static int _channels_set(MixerControlPlugin * channels, va_list properties) } else if(string_compare(p, "channels") == 0) { - u = va_arg(properties, unsigned int); - if(_set_channels(channels, u) != 0) + zu = va_arg(properties, size_t); + if(_set_channels(channels, zu) != 0) return -1; } else if(string_compare(p, "delta") == 0) @@ -261,10 +262,10 @@ static int _channels_set(MixerControlPlugin * channels, va_list properties) value = va_arg(properties, gdouble); _set_value(channels, value); } - else if(sscanf(p, "value%u", &u) == 1) + else if(sscanf(p, "value%zu", &zu) == 1) { value = va_arg(properties, gdouble); - _set_value_channel(channels, u, value); + _set_value_channel(channels, zu, value); } else if(string_compare(p, "vgroup") == 0) { @@ -283,7 +284,7 @@ static void _set_bind(MixerControlPlugin * channels, gboolean bind) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(channels->bind), bind); } -static int _set_channels(MixerControlPlugin * channels, unsigned int cnt) +static int _set_channels(MixerControlPlugin * channels, size_t cnt) { size_t i; MixerControlChannel * p; @@ -351,7 +352,7 @@ static void _set_value(MixerControlPlugin * channels, gdouble value) } static void _set_value_channel(MixerControlPlugin * channels, - unsigned int channel, gdouble value) + size_t channel, gdouble value) { if(channel < channels->channels_cnt) gtk_range_set_value( From f736307b4c1df417b68b7a5edac5d00f66021aef Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sat, 27 May 2017 02:51:33 +0200 Subject: [PATCH 43/68] Implement channel binding --- src/controls/channels.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/controls/channels.c b/src/controls/channels.c index 03f5dcb..d41ec71 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -379,11 +379,18 @@ static void _channels_on_bind_toggled(gpointer data) /* channels_on_changed */ static void _channels_on_changed(GtkWidget * widget, gpointer data) { - MixerControlPlugin * channels = data; + MixerControlChannel * channel = data; + MixerControlPlugin * channels = channel->plugin; gdouble value; + size_t i; value = gtk_range_get_value(GTK_RANGE(widget)); - /* FIXME implement */ + if(channels->bind) + for(i = 0; i < channels->channels_cnt; i++) + gtk_range_set_value( + GTK_RANGE(channels->channels[i].widget), + value); + /* FIXME really implement */ } From c0f2198b5039d21041a911286234c86ebc34c6ca Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sat, 27 May 2017 02:57:56 +0200 Subject: [PATCH 44/68] Register more dependencies --- src/controls/project.conf | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/controls/project.conf b/src/controls/project.conf index df2e1bb..f146aab 100644 --- a/src/controls/project.conf +++ b/src/controls/project.conf @@ -11,17 +11,29 @@ type=plugin sources=channels.c install=$(LIBDIR)/Mixer/controls +[channels.c] +depends=../../include/Mixer/control.h + [radio] type=plugin sources=radio.c install=$(LIBDIR)/Mixer/controls +[radio.c] +depends=../../include/Mixer/control.h + [mute] type=plugin sources=mute.c install=$(LIBDIR)/Mixer/controls +[mute.c] +depends=../../include/Mixer/control.h + [set] type=plugin sources=set.c install=$(LIBDIR)/Mixer/controls + +[set.c] +depends=../../include/Mixer/control.h From 020ea9ea8d3932833ccac32d16523fe948e26c1f Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sat, 27 May 2017 03:02:05 +0200 Subject: [PATCH 45/68] Let control plug-ins report (and change) their type --- include/Mixer/control.h | 1 + src/control.c | 8 ++++++++ src/control.h | 1 + src/controls/channels.c | 9 +++++++++ src/controls/mute.c | 9 +++++++++ src/controls/radio.c | 9 +++++++++ src/controls/set.c | 9 +++++++++ 7 files changed, 46 insertions(+) diff --git a/include/Mixer/control.h b/include/Mixer/control.h index 65017d3..eeab679 100644 --- a/include/Mixer/control.h +++ b/include/Mixer/control.h @@ -49,6 +49,7 @@ typedef struct _MixerControlDefinition MixerControlPlugin * (*init)(String const * type, va_list properties); void (*destroy)(MixerControlPlugin * plugin); + String const * (*get_type)(MixerControlPlugin * plugin); GtkWidget * (*get_widget)(MixerControlPlugin * plugin); int (*set)(MixerControlPlugin * plugin, va_list properties); } MixerControlDefinition; diff --git a/src/control.c b/src/control.c index 604b561..ac10532 100644 --- a/src/control.c +++ b/src/control.c @@ -136,6 +136,14 @@ String const * mixercontrol_get_id(MixerControl * control) } +/* mixercontrol_get_type */ +String const * mixercontrol_get_type(MixerControl * control) +{ + return (control->definition->get_type != NULL) + ? control->definition->get_type(control->plugin) : NULL; +} + + /* mixercontrol_get_widget */ GtkWidget * mixercontrol_get_widget(MixerControl * control) { diff --git a/src/control.h b/src/control.h index e06b3ab..1fcebdd 100644 --- a/src/control.h +++ b/src/control.h @@ -47,6 +47,7 @@ void mixercontrol_delete(MixerControl * control); /* accessors */ String const * mixercontrol_get_id(MixerControl * control); +String const * mixercontrol_get_type(MixerControl * control); GtkWidget * mixercontrol_get_widget(MixerControl * control); int mixercontrol_set(MixerControl * control, ...); diff --git a/src/controls/channels.c b/src/controls/channels.c index d41ec71..f6a5796 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -76,6 +76,7 @@ static MixerControlPlugin * _channels_init(String const * type, va_list properties); static void _channels_destroy(MixerControlPlugin * channels); +static String const * _channels_get_type(MixerControlPlugin * channels); static GtkWidget * _channels_get_widget(MixerControlPlugin * channels); static int _channels_set(MixerControlPlugin * channels, va_list properties); @@ -101,6 +102,7 @@ MixerControlDefinition control = NULL, _channels_init, _channels_destroy, + _channels_get_type, _channels_get_widget, _channels_set }; @@ -197,6 +199,13 @@ static void _channels_destroy(MixerControlPlugin * channels) /* accessors */ +/* channels_get_type */ +static String const * _channels_get_type(MixerControlPlugin * channels) +{ + return "channels"; +} + + /* channels_get_widget */ static GtkWidget * _channels_get_widget(MixerControlPlugin * channels) { diff --git a/src/controls/mute.c b/src/controls/mute.c index f7df6bb..0ead16a 100644 --- a/src/controls/mute.c +++ b/src/controls/mute.c @@ -53,6 +53,7 @@ struct _MixerControlPlugin static MixerControlPlugin * _mute_init(String const * type, va_list properties); static void _mute_destroy(MixerControlPlugin * mute); +static String const * _mute_get_type(MixerControlPlugin * mute); static GtkWidget * _mute_get_widget(MixerControlPlugin * mute); static int _mute_set(MixerControlPlugin * mute, va_list properties); @@ -74,6 +75,7 @@ MixerControlDefinition control = NULL, _mute_init, _mute_destroy, + _mute_get_type, _mute_get_widget, _mute_set }; @@ -130,6 +132,13 @@ static void _mute_destroy(MixerControlPlugin * mute) /* accessors */ +/* mute_get_type */ +static String const * _mute_get_type(MixerControlPlugin * mute) +{ + return "mute"; +} + + /* mute_get_widget */ static GtkWidget * _mute_get_widget(MixerControlPlugin * mute) { diff --git a/src/controls/radio.c b/src/controls/radio.c index 37c90ca..983c19d 100644 --- a/src/controls/radio.c +++ b/src/controls/radio.c @@ -61,6 +61,7 @@ static MixerControlPlugin * _radio_init(String const * type, va_list properties); static void _radio_destroy(MixerControlPlugin * radio); +static String const * _radio_get_type(MixerControlPlugin * radio); static GtkWidget * _radio_get_widget(MixerControlPlugin * radio); static int _radio_set(MixerControlPlugin * radio, va_list properties); @@ -77,6 +78,7 @@ MixerControlDefinition control = NULL, _radio_init, _radio_destroy, + _radio_get_type, _radio_get_widget, _radio_set }; @@ -118,6 +120,13 @@ static void _radio_destroy(MixerControlPlugin * radio) /* accessors */ +/* radio_get_type */ +static String const * _radio_get_type(MixerControlPlugin * radio) +{ + return "radio"; +} + + /* radio_get_widget */ static GtkWidget * _radio_get_widget(MixerControlPlugin * radio) { diff --git a/src/controls/set.c b/src/controls/set.c index 0e603a4..3b163db 100644 --- a/src/controls/set.c +++ b/src/controls/set.c @@ -58,6 +58,7 @@ struct _MixerControlPlugin static MixerControlPlugin * _set_init(String const * type, va_list properties); static void _set_destroy(MixerControlPlugin * set); +static String const * _set_get_type(MixerControlPlugin * set); static GtkWidget * _set_get_widget(MixerControlPlugin * set); static int _set_set(MixerControlPlugin * set, va_list properties); @@ -72,6 +73,7 @@ MixerControlDefinition control = NULL, _set_init, _set_destroy, + _set_get_type, _set_get_widget, _set_set }; @@ -112,6 +114,13 @@ static void _set_destroy(MixerControlPlugin * set) /* accessors */ +/* set_get_type */ +static String const * _set_get_type(MixerControlPlugin * set) +{ + return "set"; +} + + /* set_get_widget */ static GtkWidget * _set_get_widget(MixerControlPlugin * set) { From c0156b4cbf7ee1a331e29e190175a7504370eec6 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sat, 27 May 2017 03:04:59 +0200 Subject: [PATCH 46/68] Report the delta in debugging mode (on NetBSD) --- src/mixer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mixer.c b/src/mixer.c index 83e934c..bce6ea4 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -982,6 +982,9 @@ static int _mixer_get_control(Mixer * mixer, int index, MixerControl * control) sep = ","; # endif } +#ifdef DEBUG + printf(" delta=%u", md.un.v.delta); +#endif break; } # ifdef DEBUG From df85edfc0584dc2ac61cdf5a20083db9d11296ec Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sat, 27 May 2017 03:08:16 +0200 Subject: [PATCH 47/68] Report sets in debugging mode (on NetBSD) --- src/mixer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mixer.c b/src/mixer.c index bce6ea4..307489d 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -965,6 +965,10 @@ static int _mixer_get_control(Mixer * mixer, int index, MixerControl * control) md.un.s.member[i].label.name); sep = ","; } + printf("%s", " {"); + for(i = 0; i < md.un.s.num_mem; i++) + printf(" %s", md.un.s.member[i].label.name); + printf("%s", " }"); # endif break; case AUDIO_MIXER_VALUE: From 7a8e1096b77dbf3236a4125ca8001a976a5d112e Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sat, 27 May 2017 05:25:23 +0200 Subject: [PATCH 48/68] Avoid a compilation warning --- src/mixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mixer.c b/src/mixer.c index 307489d..85b0fdf 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -768,7 +768,7 @@ void mixer_properties(Mixer * mixer) ""); #if GTK_CHECK_VERSION(2, 10, 0) gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(mixer->properties), - gtk_image_new_from_stock(GTK_STOCK_PROPERTIES, + gtk_image_new_from_icon_name("gtk-properties", GTK_ICON_SIZE_DIALOG)); #endif gtk_window_set_title(GTK_WINDOW(mixer->properties), _("Properties")); From df3b2fbf9358e051f39391efd518a4d3717dbe8f Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sat, 27 May 2017 05:26:12 +0200 Subject: [PATCH 49/68] Code cleanup --- src/mixer.c | 2 +- src/mixer.h | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/mixer.c b/src/mixer.c index 85b0fdf..a35a238 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -842,7 +842,7 @@ void mixer_show_all(Mixer * mixer) /* mixer_show_class */ -void mixer_show_class(Mixer * mixer, char const * name) +void mixer_show_class(Mixer * mixer, String const * name) { #ifdef AUDIO_MIXER_DEVINFO size_t u; diff --git a/src/mixer.h b/src/mixer.h index 9537567..1e6cfe8 100644 --- a/src/mixer.h +++ b/src/mixer.h @@ -31,7 +31,7 @@ #ifndef MIXER_MIXER_H # define MIXER_MIXER_H -# include /* XXX should not be necessary */ +# include # include @@ -55,7 +55,8 @@ typedef struct _Mixer Mixer; /* functions */ -Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout); +Mixer * mixer_new(GtkWidget * window, String const * device, + MixerLayout layout); void mixer_delete(Mixer * mixer); /* accessors */ @@ -72,6 +73,6 @@ void mixer_properties(Mixer * mixer); void mixer_show(Mixer * mixer); void mixer_show_all(Mixer * mixer); -void mixer_show_class(Mixer * mixer, char const * name); +void mixer_show_class(Mixer * mixer, String const * name); #endif /* !MIXER_MIXER_H */ From d5c839e321cf5ed4f2b9d875267a1503c719a188 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 29 May 2017 00:53:53 +0200 Subject: [PATCH 50/68] Support updating channels again --- include/Mixer/control.h | 13 +- src/common.h | 42 ++++ src/control.c | 56 ++++- src/control.h | 10 +- src/controls/channels.c | 95 ++++++-- src/controls/mute.c | 44 +++- src/controls/radio.c | 21 +- src/controls/set.c | 20 +- src/mixer.c | 493 ++++++++++++++++++++++------------------ src/mixer.h | 9 +- src/project.conf | 10 +- 11 files changed, 549 insertions(+), 264 deletions(-) create mode 100644 src/common.h diff --git a/include/Mixer/control.h b/include/Mixer/control.h index eeab679..2d74734 100644 --- a/include/Mixer/control.h +++ b/include/Mixer/control.h @@ -37,8 +37,17 @@ /* MixerControlPlugin */ +typedef struct _MixerControl MixerControl; + typedef struct _MixerControlPlugin MixerControlPlugin; +typedef struct _MixerControlPluginHelper +{ + MixerControl * control; + + int (*mixercontrol_set)(MixerControl * control); +} MixerControlPluginHelper; + typedef struct _MixerControlDefinition { String const * icon; @@ -46,9 +55,11 @@ typedef struct _MixerControlDefinition String const * description; /* callbacks */ - MixerControlPlugin * (*init)(String const * type, va_list properties); + MixerControlPlugin * (*init)(MixerControlPluginHelper * helper, + String const * type, va_list properties); void (*destroy)(MixerControlPlugin * plugin); + int (*get)(MixerControlPlugin * plugin, va_list properties); String const * (*get_type)(MixerControlPlugin * plugin); GtkWidget * (*get_widget)(MixerControlPlugin * plugin); int (*set)(MixerControlPlugin * plugin, va_list properties); diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..ba3ea57 --- /dev/null +++ b/src/common.h @@ -0,0 +1,42 @@ +/* $Id$ */ +/* Copyright (c) 2017 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Mixer */ +/* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + + +#ifndef MIXER_COMMON_H +# define MIXER_COMMON_H + + +/* types */ +typedef struct _Mixer Mixer; + + +/* constants */ +#define MIXER_DEFAULT_DEVICE "/dev/mixer" + +#endif /* !MIXER_COMMON_H */ diff --git a/src/control.c b/src/control.c index ac10532..1a933c2 100644 --- a/src/control.c +++ b/src/control.c @@ -28,9 +28,13 @@ +#ifdef DEBUG +# include +#endif #include #include #include "Mixer/control.h" +#include "mixer.h" #include "control.h" #include "../config.h" @@ -39,6 +43,10 @@ /* types */ struct _MixerControl { + Mixer * mixer; + + MixerControlPluginHelper helper; + String * id; Plugin * handle; MixerControlDefinition * definition; @@ -52,11 +60,17 @@ struct _MixerControl }; +/* prototypes */ +/* helper */ +static int _mixercontrol_helper_set(MixerControl * control); + + /* public */ /* functions */ /* mixercontrol_new */ -MixerControl * mixercontrol_new(String const * id, String const * icon, - String const * name, String const * type, ...) +MixerControl * mixercontrol_new(Mixer * mixer, String const * id, + String const * icon, String const * name, + String const * type, ...) { MixerControl * control; va_list ap; @@ -68,6 +82,9 @@ MixerControl * mixercontrol_new(String const * id, String const * icon, #endif if((control = object_new(sizeof(*control))) == NULL) return NULL; + control->mixer = mixer; + control->helper.control = control; + control->helper.mixercontrol_set = _mixercontrol_helper_set; control->id = string_new(id); control->handle = plugin_new(LIBDIR, PACKAGE, "controls", type); control->definition = NULL; @@ -80,8 +97,8 @@ MixerControl * mixercontrol_new(String const * id, String const * icon, "control")) == NULL || control->definition->init == NULL || control->definition->destroy == NULL - || (control->plugin = control->definition->init(type, - ap)) == NULL + || (control->plugin = control->definition->init( + &control->helper, type, ap)) == NULL || control->definition->get_widget == NULL || (control->widget = control->definition->get_widget( control->plugin)) == NULL) @@ -129,6 +146,24 @@ void mixercontrol_delete(MixerControl * control) /* accessors */ +/* mixercontrol_get */ +int mixercontrol_get(MixerControl * control, ...) +{ + int ret; + va_list ap; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s()\n", __func__); +#endif + if(control->definition->get == NULL) + return -1; + va_start(ap, control); + ret = control->definition->get(control->plugin, ap); + va_end(ap); + return ret; +} + + /* mixercontrol_get_id */ String const * mixercontrol_get_id(MixerControl * control) { @@ -157,6 +192,8 @@ int mixercontrol_set(MixerControl * control, ...) int ret; va_list ap; + if(control->definition->set == NULL) + return -1; va_start(ap, control); ret = control->definition->set(control->plugin, ap); va_end(ap); @@ -170,3 +207,14 @@ void mixercontrol_set_icon(MixerControl * control, String const * icon) gtk_image_set_from_icon_name(GTK_IMAGE(control->icon), icon, GTK_ICON_SIZE_MENU); } + + +/* private */ +/* mixercontrol_helper_set */ +static int _mixercontrol_helper_set(MixerControl * control) +{ +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(%p)\n", __func__, (void *)control); +#endif + return mixer_set(control->mixer, control); +} diff --git a/src/control.h b/src/control.h index 1fcebdd..cbd68b4 100644 --- a/src/control.h +++ b/src/control.h @@ -33,6 +33,7 @@ # include # include +# include "common.h" /* MixerControl */ @@ -41,16 +42,19 @@ typedef struct _MixerControl MixerControl; /* functions */ -MixerControl * mixercontrol_new(String const * id, String const * icon, - String const * name, String const * type, ...); +MixerControl * mixercontrol_new(Mixer * mixer, String const * id, + String const * icon, String const * name, + String const * type, ...); void mixercontrol_delete(MixerControl * control); /* accessors */ +int mixercontrol_get(MixerControl * control, ...); +int mixercontrol_set(MixerControl * control, ...); + String const * mixercontrol_get_id(MixerControl * control); String const * mixercontrol_get_type(MixerControl * control); GtkWidget * mixercontrol_get_widget(MixerControl * control); -int mixercontrol_set(MixerControl * control, ...); void mixercontrol_set_icon(MixerControl * control, String const * icon); #endif /* !MIXER_CONTROL_H */ diff --git a/src/controls/channels.c b/src/controls/channels.c index f6a5796..0f3a080 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -29,6 +29,9 @@ #include +#ifdef DEBUG +# include +#endif #include #include #include "Mixer/control.h" @@ -47,6 +50,8 @@ typedef struct _MixerControlChannel struct _MixerControlPlugin { + MixerControlPluginHelper * helper; + GtkWidget * widget; unsigned int delta; @@ -67,15 +72,19 @@ struct _MixerControlPlugin #if !GTK_CHECK_VERSION(3, 0, 0) GtkWidget * mute_image; #endif + + gboolean signal; }; /* prototypes */ /* control */ -static MixerControlPlugin * _channels_init(String const * type, - va_list properties); +static MixerControlPlugin * _channels_init(MixerControlPluginHelper * helper, + String const * type, va_list properties); static void _channels_destroy(MixerControlPlugin * channels); +static int _channels_get(MixerControlPlugin * channels, va_list properties); + static String const * _channels_get_type(MixerControlPlugin * channels); static GtkWidget * _channels_get_widget(MixerControlPlugin * channels); @@ -102,6 +111,7 @@ MixerControlDefinition control = NULL, _channels_init, _channels_destroy, + _channels_get, _channels_get_type, _channels_get_widget, _channels_set @@ -111,8 +121,8 @@ MixerControlDefinition control = /* private */ /* functions */ /* channels_init */ -static MixerControlPlugin * _channels_init(String const * type, - va_list properties) +static MixerControlPlugin * _channels_init(MixerControlPluginHelper * helper, + String const * type, va_list properties) { MixerControlPlugin * channels; GtkWidget * hbox; @@ -124,6 +134,7 @@ static MixerControlPlugin * _channels_init(String const * type, if((channels = object_new(sizeof(*channels))) == NULL) return NULL; + channels->helper = helper; channels->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); gtk_container_set_border_width(GTK_CONTAINER(channels->widget), 4); channels->delta = 1; @@ -181,6 +192,7 @@ static MixerControlPlugin * _channels_init(String const * type, gtk_box_pack_end(GTK_BOX(channels->bbox), hbox, FALSE, TRUE, 0); gtk_box_pack_end(GTK_BOX(channels->widget), channels->bbox, FALSE, TRUE, 0); + channels->signal = FALSE; if(_channels_set(channels, properties) != 0) { _channels_destroy(channels); @@ -199,6 +211,50 @@ static void _channels_destroy(MixerControlPlugin * channels) /* accessors */ +static int _channels_get(MixerControlPlugin * channels, va_list properties) +{ + String const * p; + gboolean * b; + double * value; + size_t i; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s()\n", __func__); +#endif + while((p = va_arg(properties, String const *)) != NULL) + if(string_compare(p, "bind") == 0) + { + b = va_arg(properties, gboolean *); + *b = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( + channels->bind)); + } + else if(string_compare(p, "value") == 0) + { + if(channels->channels_cnt == 0) + return -1; + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( + channels->bind)) + == FALSE) + return -1; + value = va_arg(properties, double *); + *value = gtk_range_get_value(GTK_RANGE( + channels->channels[0].widget)); + } + else if(sscanf(p, "value%zu", &i) == 1) + { + if(i >= channels->channels_cnt) + return -1; + value = va_arg(properties, double *); + *value = gtk_range_get_value(GTK_RANGE( + channels->channels[i].widget)); + } + /* FIXME implement the rest */ + else + return -1; + return 0; +} + + /* channels_get_type */ static String const * _channels_get_type(MixerControlPlugin * channels) { @@ -393,13 +449,24 @@ static void _channels_on_changed(GtkWidget * widget, gpointer data) gdouble value; size_t i; - value = gtk_range_get_value(GTK_RANGE(widget)); - if(channels->bind) - for(i = 0; i < channels->channels_cnt; i++) - gtk_range_set_value( - GTK_RANGE(channels->channels[i].widget), - value); - /* FIXME really implement */ +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s()\n", __func__); +#endif + if(channels->signal == TRUE) + return; + channels->signal = TRUE; + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(channels->bind))) + { + value = gtk_range_get_value(GTK_RANGE(widget)); + if(channels->bind) + for(i = 0; i < channels->channels_cnt; i++) + { + widget = channels->channels[i].widget; + gtk_range_set_value(GTK_RANGE(widget), value); + } + } + channels->helper->mixercontrol_set(channels->helper->control); + channels->signal = FALSE; } @@ -408,10 +475,8 @@ static void _channels_on_changed(GtkWidget * widget, gpointer data) static void _channels_on_mute_notify_active(gpointer data) { MixerControlPlugin * channels = data; - gboolean active; - active = gtk_switch_get_active(GTK_SWITCH(channels->mute)); - /* FIXME implement */ + channels->helper->mixercontrol_set(channels->helper->control); } #else /* channels_on_mute_toggled */ @@ -425,6 +490,6 @@ static void _channels_on_mute_toggled(gpointer data) gtk_image_set_from_icon_name(GTK_IMAGE(channels->mute_image), active ? "audio-volume-muted" : "audio-volume-high", GTK_ICON_SIZE_BUTTON); - /* FIXME implement */ + channels->helper->mixercontrol_set(channels->helper->control); } #endif diff --git a/src/controls/mute.c b/src/controls/mute.c index 0ead16a..40417ff 100644 --- a/src/controls/mute.c +++ b/src/controls/mute.c @@ -39,6 +39,8 @@ /* types */ struct _MixerControlPlugin { + MixerControlPluginHelper * helper; + GtkWidget * widget; GtkWidget * mute; @@ -50,9 +52,12 @@ struct _MixerControlPlugin /* prototypes */ /* control */ -static MixerControlPlugin * _mute_init(String const * type, va_list properties); +static MixerControlPlugin * _mute_init(MixerControlPluginHelper * helper, + String const * type, va_list properties); static void _mute_destroy(MixerControlPlugin * mute); +static int _mute_get(MixerControlPlugin * mute, va_list properties); + static String const * _mute_get_type(MixerControlPlugin * mute); static GtkWidget * _mute_get_widget(MixerControlPlugin * mute); @@ -75,6 +80,7 @@ MixerControlDefinition control = NULL, _mute_init, _mute_destroy, + _mute_get, _mute_get_type, _mute_get_widget, _mute_set @@ -84,7 +90,8 @@ MixerControlDefinition control = /* private */ /* functions */ /* mute_init */ -static MixerControlPlugin * _mute_init(String const * type, va_list properties) +static MixerControlPlugin * _mute_init(MixerControlPluginHelper * helper, + String const * type, va_list properties) { MixerControlPlugin * mute; #if !GTK_CHECK_VERSION(3, 0, 0) @@ -95,6 +102,7 @@ static MixerControlPlugin * _mute_init(String const * type, va_list properties) if((mute = object_new(sizeof(*mute))) == NULL) return NULL; + mute->helper = helper; mute->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); gtk_container_set_border_width(GTK_CONTAINER(mute->widget), 4); #if GTK_CHECK_VERSION(3, 0, 0) @@ -132,6 +140,32 @@ static void _mute_destroy(MixerControlPlugin * mute) /* accessors */ +/* mute_get */ +static int _mute_get(MixerControlPlugin * mute, va_list properties) +{ + String const * p; + gboolean * b; + + while((p = va_arg(properties, String const *)) != NULL) + if(string_compare(p, "value") == 0) + { + b = va_arg(properties, gboolean *); +# if GTK_CHECK_VERSION(3, 0, 0) + *b = gtk_switch_get_active(GTK_SWITCH(mute->mute)) + ? 0 : 1; /* XXX assumes 1 is "off" */ +# else + *b = gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(mute->mute)) + ? 1 : 0; /* XXX assumes 0 is "off" */ +# endif + } + /* FIXME implement the rest */ + else + return -1; + return 0; +} + + /* mute_get_type */ static String const * _mute_get_type(MixerControlPlugin * mute) { @@ -178,10 +212,8 @@ static int _mute_set(MixerControlPlugin * mute, va_list properties) static void _mute_on_notify_active(gpointer data) { MixerControlPlugin * mute = data; - gboolean active; - active = gtk_switch_get_active(GTK_SWITCH(mute->mute)); - /* FIXME implement */ + mute->helper->mixercontrol_set(mute->helper->control); } #else /* mute_on_toggled */ @@ -195,6 +227,6 @@ static void _mute_on_toggled(gpointer data) gtk_image_set_from_icon_name(GTK_IMAGE(mute->mute_image), active ? "audio-volume-muted" : "audio-volume-high", GTK_ICON_SIZE_BUTTON); - /* FIXME implement */ + mute->helper->mixercontrol_set(mute->helper->control); } #endif diff --git a/src/controls/radio.c b/src/controls/radio.c index 983c19d..38d7e69 100644 --- a/src/controls/radio.c +++ b/src/controls/radio.c @@ -47,6 +47,8 @@ typedef struct _MixerControlRadio struct _MixerControlPlugin { + MixerControlPluginHelper * helper; + GtkWidget * widget; GSList * group; @@ -57,10 +59,12 @@ struct _MixerControlPlugin /* prototypes */ /* control */ -static MixerControlPlugin * _radio_init(String const * type, - va_list properties); +static MixerControlPlugin * _radio_init(MixerControlPluginHelper * helper, + String const * type, va_list properties); static void _radio_destroy(MixerControlPlugin * radio); +static int _radio_get(MixerControlPlugin * radio, va_list properties); + static String const * _radio_get_type(MixerControlPlugin * radio); static GtkWidget * _radio_get_widget(MixerControlPlugin * radio); @@ -78,6 +82,7 @@ MixerControlDefinition control = NULL, _radio_init, _radio_destroy, + _radio_get, _radio_get_type, _radio_get_widget, _radio_set @@ -87,13 +92,15 @@ MixerControlDefinition control = /* private */ /* functions */ /* radio_init */ -static MixerControlPlugin * _radio_init(String const * type, va_list properties) +static MixerControlPlugin * _radio_init(MixerControlPluginHelper * helper, + String const * type, va_list properties) { MixerControlPlugin * radio; (void) type; if((radio = object_new(sizeof(*radio))) == NULL) return NULL; + radio->helper = helper; radio->widget = gtk_button_box_new(GTK_ORIENTATION_VERTICAL); gtk_button_box_set_layout(GTK_BUTTON_BOX(radio->widget), GTK_BUTTONBOX_SPREAD); @@ -120,6 +127,14 @@ static void _radio_destroy(MixerControlPlugin * radio) /* accessors */ +/* radio_get */ +static int _radio_get(MixerControlPlugin * radio, va_list properties) +{ + /* FIXME implement */ + return -1; +} + + /* radio_get_type */ static String const * _radio_get_type(MixerControlPlugin * radio) { diff --git a/src/controls/set.c b/src/controls/set.c index 3b163db..26ac2e3 100644 --- a/src/controls/set.c +++ b/src/controls/set.c @@ -47,6 +47,8 @@ typedef struct _MixerControlSet struct _MixerControlPlugin { + MixerControlPluginHelper * helper; + GtkWidget * widget; MixerControlSet * sets; @@ -55,9 +57,12 @@ struct _MixerControlPlugin /* prototypes */ -static MixerControlPlugin * _set_init(String const * type, va_list properties); +static MixerControlPlugin * _set_init(MixerControlPluginHelper * helper, + String const * type, va_list properties); static void _set_destroy(MixerControlPlugin * set); +static int _set_get(MixerControlPlugin * set, va_list properties); + static String const * _set_get_type(MixerControlPlugin * set); static GtkWidget * _set_get_widget(MixerControlPlugin * set); @@ -73,6 +78,7 @@ MixerControlDefinition control = NULL, _set_init, _set_destroy, + _set_get, _set_get_type, _set_get_widget, _set_set @@ -82,13 +88,15 @@ MixerControlDefinition control = /* private */ /* functions */ /* set_init */ -static MixerControlPlugin * _set_init(String const * type, va_list properties) +static MixerControlPlugin * _set_init(MixerControlPluginHelper * helper, + String const * type, va_list properties) { MixerControlPlugin * set; (void) type; if((set = object_new(sizeof(*set))) == NULL) return NULL; + set->helper = helper; set->widget = gtk_button_box_new(GTK_ORIENTATION_VERTICAL); gtk_button_box_set_layout(GTK_BUTTON_BOX(set->widget), GTK_BUTTONBOX_SPREAD); @@ -114,6 +122,14 @@ static void _set_destroy(MixerControlPlugin * set) /* accessors */ +/* set_get */ +static int _set_get(MixerControlPlugin * set, va_list properties) +{ + /* FIXME implement */ + return -1; +} + + /* set_get_type */ static String const * _set_get_type(MixerControlPlugin * set) { diff --git a/src/mixer.c b/src/mixer.c index a35a238..310f514 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -49,6 +49,7 @@ #include #include #include "control.h" +#include "common.h" #include "mixer.h" #include "../config.h" #define _(string) gettext(string) @@ -80,7 +81,10 @@ typedef struct _MixerLevel size_t channels_cnt; } MixerLevel; -typedef struct _MixerControl +/* FIXME there are two different MixerControl types */ +typedef struct _MixerControl MixerControl; + +struct _MixerControl { int index; int type; @@ -89,7 +93,9 @@ typedef struct _MixerControl int mask; MixerLevel level; } un; -} MixerControl; + + MixerControl * control; +}; struct _Mixer { @@ -105,27 +111,23 @@ struct _Mixer #ifdef AUDIO_MIXER_DEVINFO int fd; - MixerClass * mc; - size_t mc_cnt; + MixerClass * classes; + size_t classes_cnt; #else int fd; #endif - MixerControl ** controls; + MixerControl * controls; size_t controls_cnt; }; -/* constants */ -#define MIXER_DEFAULT_DEVICE "/dev/mixer" - - /* prototypes */ static int _mixer_error(Mixer * mixer, char const * message, int ret); /* accessors */ -static int _mixer_get_control(Mixer * mixer, int index, MixerControl * control); -static int _mixer_set_control(Mixer * mixer, int index, MixerControl * control); +static int _mixer_get_control(Mixer * mixer, MixerControl * control); +static int _mixer_set_control(Mixer * mixer, MixerControl * control); static String const * _mixer_get_icon(String const * id); @@ -140,10 +142,10 @@ static void _mixer_show_view(Mixer * mixer, int view); static GtkWidget * _new_frame_label(GdkPixbuf * pixbuf, char const * name, char const * label); #ifdef AUDIO_MIXER_DEVINFO -static MixerControl * _new_enum(Mixer * mixer, int dev, +static MixerControl * _new_enum(Mixer * mixer, int index, struct audio_mixer_enum * e, String const * id, String const * icon, String const * name); -static MixerControl * _new_set(Mixer * mixer, int dev, +static MixerControl * _new_set(Mixer * mixer, int index, struct audio_mixer_set * s, String const * id, String const * icon, String const * name); #endif @@ -162,6 +164,7 @@ Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout) GtkWidget * hvbox = NULL; GtkWidget * hbox; MixerControl * control; + MixerControl * q; int i; #ifdef AUDIO_MIXER_DEVINFO mixer_devinfo_t md; @@ -186,8 +189,8 @@ Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout) mixer->properties = NULL; mixer->bold = NULL; #ifdef AUDIO_MIXER_DEVINFO - mixer->mc = NULL; - mixer->mc_cnt = 0; + mixer->classes = NULL; + mixer->classes_cnt = 0; #endif mixer->controls = NULL; mixer->controls_cnt = 0; @@ -228,15 +231,16 @@ Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout) break; if(md.type != AUDIO_MIXER_CLASS) continue; - if((p = realloc(mixer->mc, sizeof(*mixer->mc) - * (mixer->mc_cnt + 1))) == NULL) + if((p = realloc(mixer->classes, sizeof(*p) + * (mixer->classes_cnt + 1))) + == NULL) { _mixer_error(NULL, "realloc", 1); mixer_delete(mixer); return NULL; } - mixer->mc = p; - p = &mixer->mc[mixer->mc_cnt++]; + mixer->classes = p; + p = &mixer->classes[mixer->classes_cnt++]; p->mixer_class = md.mixer_class; memcpy(&p->label, &md.label, sizeof(md.label)); p->hbox = NULL; @@ -270,12 +274,12 @@ Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout) break; if(md.type == AUDIO_MIXER_CLASS) continue; - for(u = 0; u < mixer->mc_cnt; u++) - if(mixer->mc[u].mixer_class == md.mixer_class) + for(u = 0; u < mixer->classes_cnt; u++) + if(mixer->classes[u].mixer_class == md.mixer_class) break; - if(u == mixer->mc_cnt) + if(u == mixer->classes_cnt) continue; - hbox = mixer->mc[u].hbox; + hbox = mixer->classes[u].hbox; control = NULL; switch(md.type) { @@ -300,23 +304,37 @@ Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout) } if(control == NULL) continue; + if((q = realloc(mixer->controls, sizeof(*q) + * (mixer->controls_cnt + 1))) + == NULL) + { + mixercontrol_delete(control); + /* FIXME report error */ + continue; + } + mixer->controls = q; + q = &mixer->controls[mixer->controls_cnt++]; + q->index = md.index; + q->type = md.type; + q->control = control; widget = mixercontrol_get_widget(control); vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); gtk_box_pack_start(GTK_BOX(vbox2), widget, TRUE, TRUE, 0); gtk_size_group_add_widget(hgroup, widget); if(hbox == NULL) { - mixer->mc[u].hbox = gtk_box_new( - GTK_ORIENTATION_HORIZONTAL, 4); - hbox = mixer->mc[u].hbox; + p = &mixer->classes[u]; + p->hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); + hbox = p->hbox; if(mixer->notebook != NULL) { - if((name = strdup(mixer->mc[u].label.name)) + if((name = strdup(mixer->classes[u].label.name)) != NULL) name[0] = toupper( (unsigned char)name[0]); label = _new_frame_label(NULL, - mixer->mc[u].label.name, name); + mixer->classes[u].label.name, + name); free(name); gtk_widget_show_all(label); scrolled = gtk_scrolled_window_new(NULL, NULL); @@ -324,14 +342,14 @@ Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout) GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER); - _mixer_scrolled_window_add(scrolled, hbox); - mixer->mc[u].page = gtk_notebook_append_page( + _mixer_scrolled_window_add(scrolled, p->hbox); + p->page = gtk_notebook_append_page( GTK_NOTEBOOK(mixer->notebook), scrolled, label); } else if(hvbox != NULL) - gtk_box_pack_start(GTK_BOX(hvbox), hbox, FALSE, - TRUE, 0); + gtk_box_pack_start(GTK_BOX(hvbox), p->hbox, + FALSE, TRUE, 0); } gtk_box_pack_start(GTK_BOX(hbox), vbox2, FALSE, TRUE, 0); /* add a mute button if relevant */ @@ -342,10 +360,10 @@ Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout) break; if(md2.type == AUDIO_MIXER_CLASS) continue; - for(u = 0; u < mixer->mc_cnt; u++) - if(mixer->mc[u].mixer_class == md2.mixer_class) + for(u = 0; u < mixer->classes_cnt; u++) + if(mixer->classes[u].mixer_class == md2.mixer_class) break; - if(u == mixer->mc_cnt) + if(u == mixer->classes_cnt) continue; u = strlen(md.label.name); if(md2.type != AUDIO_MIXER_ENUM || strncmp(md.label.name, @@ -361,11 +379,22 @@ Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout) break; if(ioctl(mixer->fd, MIXER_READ(i), &value) != 0) continue; + if((q = realloc(mixer->controls, sizeof(*q) + * (mixer->controls_cnt + 1))) + == NULL) + /* FIXME report error */ + continue; + mixer->controls = q; + q = &mixer->controls[mixer->controls_cnt]; if((control = _new_value(mixer, i, vgroup, names[i], _mixer_get_icon(names[i]), labels[i])) == NULL) continue; + q->index = i; + q->type = 0; + q->control = control; + mixer->controls_cnt++; widget = mixercontrol_get_widget(control); gtk_size_group_add_widget(hgroup, widget); gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); @@ -411,25 +440,24 @@ static GtkWidget * _new_frame_label(GdkPixbuf * pixbuf, char const * name, } #ifdef AUDIO_MIXER_DEVINFO -static MixerControl * _new_enum(Mixer * mixer, int dev, +static MixerControl * _new_enum(Mixer * mixer, int index, struct audio_mixer_enum * e, String const * id, String const * icon, String const * name) { - MixerControl * mc; + MixerControl mc; MixerControl * control; int i; char label[16]; char value[16]; - if(e->num_mem <= 0 || (mc = malloc(sizeof(*mc))) == NULL) + if(e->num_mem <= 0) return NULL; - if(_mixer_get_control(mixer, dev, mc) != 0 - || (control = mixercontrol_new(id, icon, name, "radio", - "members", e->num_mem, NULL)) == NULL) - { - free(mc); + mc.index = index; + if(_mixer_get_control(mixer, &mc) != 0 + || (control = mixercontrol_new(mixer, id, icon, name, + "radio", "members", e->num_mem, NULL)) + == NULL) return NULL; - } for(i = 0; i < e->num_mem; i++) { snprintf(label, sizeof(label), "label%d", i); @@ -441,7 +469,7 @@ static MixerControl * _new_enum(Mixer * mixer, int dev, return NULL; } } - if(mixercontrol_set(control, "value", mc->un.mask, NULL) != 0) + if(mixercontrol_set(control, "value", mc.un.mask, NULL) != 0) { mixercontrol_delete(control); return NULL; @@ -449,25 +477,24 @@ static MixerControl * _new_enum(Mixer * mixer, int dev, return control; } -static MixerControl * _new_set(Mixer * mixer, int dev, +static MixerControl * _new_set(Mixer * mixer, int index, struct audio_mixer_set * s, String const * id, String const * icon, String const * name) { - MixerControl * mc; + MixerControl mc; MixerControl * control; int i; char label[16]; char value[16]; - if(s->num_mem <= 0 || (mc = malloc(sizeof(*mc))) == NULL) + if(s->num_mem <= 0) return NULL; - if(_mixer_get_control(mixer, dev, mc) != 0 - || (control = mixercontrol_new(id, icon, name, "set", - "members", s->num_mem, NULL)) == NULL) - { - free(mc); + mc.index = index; + if(_mixer_get_control(mixer, &mc) != 0 + || (control = mixercontrol_new(mixer, id, icon, name, + "set", "members", s->num_mem, NULL)) + == NULL) return NULL; - } for(i = 0; i < s->num_mem; i++) { snprintf(label, sizeof(label), "label%d", i); @@ -479,7 +506,7 @@ static MixerControl * _new_set(Mixer * mixer, int dev, return NULL; } } - if(mixercontrol_set(control, "value", mc->un.mask, NULL) != 0) + if(mixercontrol_set(control, "value", mc.un.mask, NULL) != 0) { mixercontrol_delete(control); return NULL; @@ -492,36 +519,32 @@ static MixerControl * _new_value(Mixer * mixer, int index, GtkSizeGroup * vgroup, String const * id, String const * icon, String const * name) { - MixerControl * mc; + MixerControl mc; MixerControl * control; size_t i; gboolean bind = TRUE; char buf[16]; gdouble value; - if((mc = malloc(sizeof(*mc))) == NULL - || _mixer_get_control(mixer, index, mc) != 0 - || mc->un.level.channels_cnt <= 0 - || (control = mixercontrol_new(id, icon, name, + mc.index = index; + if(_mixer_get_control(mixer, &mc) != 0 + || mc.un.level.channels_cnt <= 0 + || (control = mixercontrol_new(mixer, id, icon, name, "channels", - "channels", mc->un.level.channels_cnt, - "delta", mc->un.level.delta, + "channels", mc.un.level.channels_cnt, + "delta", mc.un.level.delta, "vgroup", vgroup, NULL)) == NULL) - { - free(mc); return NULL; - } - free(mc); /* detect if binding is in place */ - for(i = 1; i < mc->un.level.channels_cnt; i++) - if(mc->un.level.channels[i] != mc->un.level.channels[0]) + for(i = 1; i < mc.un.level.channels_cnt; i++) + if(mc.un.level.channels[i] != mc.un.level.channels[0]) { bind = FALSE; break; } if(bind) { - value = mc->un.level.channels[0]; + value = mc.un.level.channels[0]; if(mixercontrol_set(control, "value", value, "bind", bind, NULL) != 0) { @@ -536,10 +559,10 @@ static MixerControl * _new_value(Mixer * mixer, int index, mixercontrol_delete(control); return NULL; } - for(i = 0; i < mc->un.level.channels_cnt; i++) + for(i = 0; i < mc.un.level.channels_cnt; i++) { snprintf(buf, sizeof(buf), "value%zu", i); - value = mc->un.level.channels[i]; + value = mc.un.level.channels[i]; if(mixercontrol_set(control, buf, value, NULL) != 0) { mixercontrol_delete(control); @@ -608,133 +631,163 @@ GtkWidget * mixer_get_widget(Mixer * mixer) } -/* mixer_set_enum */ -int mixer_set_enum(Mixer * mixer, GtkWidget * widget) -{ -#ifdef AUDIO_MIXER_DEVINFO - mixer_ctrl_t * p; - int * q; - -# ifdef DEBUG - fprintf(stderr, "DEBUG: %s(%p) fd=%d\n", __func__, (void *)mixer, - mixer->fd); -# endif - p = g_object_get_data(G_OBJECT(widget), "ctrl"); - q = g_object_get_data(G_OBJECT(widget), "ord"); - if(p == NULL || q == NULL) - return 1; - p->un.ord = *q; -# ifdef DEBUG - fprintf(stderr, "DEBUG: %s(%p) fd=%d ord=%d\n", __func__, (void *)mixer, - mixer->fd, p->un.ord); -# endif - if(ioctl(mixer->fd, AUDIO_MIXER_WRITE, p) != 0) - return -_mixer_error(mixer, "AUDIO_MIXER_WRITE", 1); -#else - /* FIXME implement */ +/* mixer_set */ +static int _set_channels(Mixer * mixer, MixerControl * control); +#if defined(AUDIO_MIXER_DEVINFO) +static int _set_mute(Mixer * mixer, MixerControl * control); +static int _set_radio(Mixer * mixer, MixerControl * control); +static int _set_set(Mixer * mixer, MixerControl * control); #endif - return 0; -} - -/* mixer_set_mute */ -int mixer_set_mute(Mixer * mixer, GtkWidget * widget) +int mixer_set(Mixer * mixer, MixerControl * control) { -#ifdef AUDIO_MIXER_DEVINFO - mixer_ctrl_t * p; - -# ifdef DEBUG - fprintf(stderr, "DEBUG: %s(%p) fd=%d\n", __func__, (void *)mixer, - mixer->fd); -# endif - if((p = g_object_get_data(G_OBJECT(widget), "ctrl")) == NULL) - return -1; -#if GTK_CHECK_VERSION(3, 0, 0) - p->un.ord = gtk_switch_get_active(GTK_SWITCH(widget)) - ? 0 : 1; /* XXX assumes 1 is "off" */ -#else - p->un.ord = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)) - ? 1 : 0; /* XXX assumes 0 is "off" */ -#endif -# ifdef DEBUG - fprintf(stderr, "DEBUG: %s(%p) fd=%d ord=%d\n", __func__, (void *)mixer, - mixer->fd, p->un.ord); -# endif - if(ioctl(mixer->fd, AUDIO_MIXER_WRITE, p) != 0) - return -_mixer_error(mixer, "AUDIO_MIXER_WRITE", 1); -#else - /* FIXME implement */ -#endif - return 0; -} - - -/* mixer_set_set */ -int mixer_set_set(Mixer * mixer, GtkWidget * widget) -{ - gboolean active; -#ifdef AUDIO_MIXER_DEVINFO - mixer_ctrl_t * p; - int * q; - -# ifdef DEBUG - fprintf(stderr, "DEBUG: %s(%p) fd=%d\n", __func__, (void *)mixer, - mixer->fd); -# endif - active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); - p = g_object_get_data(G_OBJECT(widget), "ctrl"); - q = g_object_get_data(G_OBJECT(widget), "mask"); - if(p == NULL || q == NULL) - return 1; - if(ioctl(mixer->fd, AUDIO_MIXER_READ, p) != 0) - return -_mixer_error(mixer, "AUDIO_MIXER_READ", 1); - p->un.mask = (active) ? (p->un.mask | *q) - : (p->un.mask - (p->un.mask & *q)); -# ifdef DEBUG - fprintf(stderr, "DEBUG: %s(%p) fd=%d mask=%d\n", __func__, - (void *)mixer, mixer->fd, p->un.mask); -# endif - if(ioctl(mixer->fd, AUDIO_MIXER_WRITE, p) != 0) - return -_mixer_error(mixer, "AUDIO_MIXER_WRITE", 1); -#else - active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); - /* FIXME implement */ -#endif - return 0; -} - - -/* mixer_set_value */ -int mixer_set_value(Mixer * mixer, GtkWidget * widget, gdouble value) -{ - GtkWidget * b; - MixerControl * mc; - uint8_t * channel; - size_t i; - GSList * q; + String const * type; #ifdef DEBUG - fprintf(stderr, "DEBUG: %s(%p, %f) fd=%d\n", __func__, (void *)mixer, - value, mixer->fd); + fprintf(stderr, "DEBUG: %s()\n", __func__); #endif - b = g_object_get_data(G_OBJECT(widget), "bind"); - mc = g_object_get_data(G_OBJECT(widget), "ctrl"); - channel = g_object_get_data(G_OBJECT(widget), "channel"); - if(mc == NULL || channel == NULL) - return 1; - *channel = (value / 100.0) * 255; - if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b))) - { - for(i = 0; i < mc->un.level.channels_cnt; i++) - mc->un.level.channels[i] = *channel; - if(b != NULL) - for(q = g_object_get_data(G_OBJECT(b), "list"); - q != NULL; q = q->next) - gtk_range_set_value(GTK_RANGE(q->data), value); - } - return _mixer_set_control(mixer, mc->index, mc); + if((type = mixercontrol_get_type(control)) == NULL) + return -1; + else if(string_compare(type, "channels") == 0) + return _set_channels(mixer, control); +#if defined(AUDIO_MIXER_DEVINFO) + else if(string_compare(type, "mute") == 0) + return _set_mute(mixer, control); + else if(string_compare(type, "radio") == 0) + return _set_radio(mixer, control); + else if(string_compare(type, "set") == 0) + return _set_set(mixer, control); +#endif + return -1; } +static int _set_channels(Mixer * mixer, MixerControl * control) +{ + size_t i; + double value; + uint8_t channel; + MixerControl mc; + char buf[16]; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(%p, %p) fd=%d\n", __func__, (void *)mixer, + (void *)control, mixer->fd); +#endif + for(i = 0; i < mixer->controls_cnt; i++) + if(mixer->controls[i].control == control) + break; + if(i == mixer->controls_cnt) + return -1; + mc.index = mixer->controls[i].index; + if(_mixer_get_control(mixer, &mc) != 0) + return -1; + for(i = 0; i < mc.un.level.channels_cnt; i++) + { + snprintf(buf, sizeof(buf), "value%zu", i); + if(mixercontrol_get(control, buf, &value, NULL) != 0) + return -1; + channel = (value * 255.0) / 100.0; +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s() value%zu=%f\n", __func__, i, + value); +#endif + mc.un.level.channels[i] = channel; + } + return _mixer_set_control(mixer, &mc); +} + +#if defined(AUDIO_MIXER_DEVINFO) +static int _set_mute(Mixer * mixer, MixerControl * control) +{ + size_t i; + gboolean value; + MixerControl * mc; + mixer_ctrl_t p; + +# ifdef DEBUG + fprintf(stderr, "DEBUG: %s(%p, %p) fd=%d\n", __func__, (void *)mixer, + (void *)control, mixer->fd); +# endif + for(i = 0; i < mixer->controls_cnt; i++) + if(mixer->controls[i].control == control) + break; + if(i == mixer->controls_cnt) + return -1; + mc = &mixer->controls[i]; + p.dev = mc->index; + p.type = mc->type; + if(mixercontrol_get(control, "value", &value, NULL) != 0) + return -1; + p.un.ord = value; +# ifdef DEBUG + fprintf(stderr, "DEBUG: %s() ord=%d\n", __func__, p.un.ord); +# endif + if(ioctl(mixer->fd, AUDIO_MIXER_WRITE, &p) != 0) + return -_mixer_error(mixer, "AUDIO_MIXER_WRITE", 1); + return 0; +} + +static int _set_radio(Mixer * mixer, MixerControl * control) +{ + size_t i; + MixerControl * mc; + mixer_ctrl_t p; + unsigned int value; + +# ifdef DEBUG + fprintf(stderr, "DEBUG: %s(%p) fd=%d\n", __func__, (void *)mixer, + mixer->fd); +# endif + for(i = 0; i < mixer->controls_cnt; i++) + if(mixer->controls[i].control == control) + break; + if(i == mixer->controls_cnt) + return -1; + mc = &mixer->controls[i]; + p.dev = mc->index; + p.type = mc->type; + if(mixercontrol_get(control, "value", &value, NULL) != 0) + return -1; + p.un.ord = value; +# ifdef DEBUG + fprintf(stderr, "DEBUG: %s() ord=%d\n", __func__, p.un.ord); +# endif + if(ioctl(mixer->fd, AUDIO_MIXER_WRITE, p) != 0) + return -_mixer_error(mixer, "AUDIO_MIXER_WRITE", 1); + return 0; +} + +static int _set_set(Mixer * mixer, MixerControl * control) +{ + size_t i; + unsigned int value; + MixerControl * mc; + mixer_ctrl_t p; + +# ifdef DEBUG + fprintf(stderr, "DEBUG: %s(%p) fd=%d\n", __func__, (void *)mixer, + mixer->fd); +# endif + for(i = 0; i < mixer->controls_cnt; i++) + if(mixer->controls[i].control == control) + break; + if(i == mixer->controls_cnt) + return -1; + mc = &mixer->controls[i]; + p.dev = mc->index; + p.type = mc->type; + if(mixercontrol_get(control, "value", &value, NULL) != 0) + return -1; + p.un.mask = value; +# ifdef DEBUG + fprintf(stderr, "DEBUG: %s() mask=%d\n", __func__, p.un.mask); +# endif + if(ioctl(mixer->fd, AUDIO_MIXER_WRITE, p) != 0) + return -_mixer_error(mixer, "AUDIO_MIXER_WRITE", 1); + return 0; +} +#endif + /* useful */ /* mixer_properties */ @@ -849,26 +902,27 @@ void mixer_show_class(Mixer * mixer, String const * name) if(mixer->notebook != NULL && name != NULL) { - for(u = 0; u < mixer->mc_cnt; u++) + for(u = 0; u < mixer->classes_cnt; u++) { - if(mixer->mc[u].hbox == NULL) + if(mixer->classes[u].hbox == NULL) continue; - if(strcmp(mixer->mc[u].label.name, name) != 0) + if(strcmp(mixer->classes[u].label.name, name) != 0) continue; gtk_notebook_set_current_page(GTK_NOTEBOOK( mixer->notebook), - mixer->mc[u].page); + mixer->classes[u].page); } return; } - for(u = 0; u < mixer->mc_cnt; u++) - if(mixer->mc[u].hbox == NULL) + for(u = 0; u < mixer->classes_cnt; u++) + if(mixer->classes[u].hbox == NULL) continue; else if(name == NULL - || strcmp(mixer->mc[u].label.name, name) == 0) - gtk_widget_show(mixer->mc[u].hbox); + || strcmp(mixer->classes[u].label.name, name) + == 0) + gtk_widget_show(mixer->classes[u].hbox); else - gtk_widget_hide(mixer->mc[u].hbox); + gtk_widget_hide(mixer->classes[u].hbox); #endif } @@ -911,7 +965,7 @@ static int _error_text(char const * message, int ret) /* accessors */ /* mixer_get_control */ -static int _mixer_get_control(Mixer * mixer, int index, MixerControl * control) +static int _mixer_get_control(Mixer * mixer, MixerControl * control) { #ifdef AUDIO_MIXER_DEVINFO mixer_ctrl_t p; @@ -922,21 +976,20 @@ static int _mixer_get_control(Mixer * mixer, int index, MixerControl * control) char * sep = ""; # endif - md.index = index; + md.index = control->index; if(ioctl(mixer->fd, AUDIO_MIXER_DEVINFO, &md) != 0) return -_mixer_error(mixer, "AUDIO_MIXER_DEVINFO", 1); - p.dev = index; + p.dev = control->index; /* XXX this is necessary for some drivers and I don't like it */ if((p.type = md.type) == AUDIO_MIXER_VALUE) p.un.value.num_channels = md.un.v.num_channels; if(ioctl(mixer->fd, AUDIO_MIXER_READ, &p) != 0) return -_mixer_error(mixer, "AUDIO_MIXER_READ", 1); - control->index = index; control->type = p.type; # ifdef DEBUG - for(u = 0; u < mixer->mc_cnt; u++) - if(mixer->mc[u].mixer_class == md.mixer_class) - printf("%s", mixer->mc[u].label.name); + for(u = 0; u < mixer->classes_cnt; u++) + if(mixer->classes[u].mixer_class == md.mixer_class) + printf("%s", mixer->classes[u].label.name); printf(".%s=", md.label.name); # endif switch(p.type) @@ -997,8 +1050,7 @@ static int _mixer_get_control(Mixer * mixer, int index, MixerControl * control) #else int value; - control->index = index; - if(ioctl(mixer->fd, MIXER_READ(index), &value) != 0) + if(ioctl(mixer->fd, MIXER_READ(control->index), &value) != 0) return -_mixer_error(NULL, "MIXER_READ", 1); control->type = 0; control->un.level.delta = 1; @@ -1049,13 +1101,13 @@ static String const * _mixer_get_icon(String const * id) /* mixer_set_control */ -static int _mixer_set_control(Mixer * mixer, int index, MixerControl * control) +static int _mixer_set_control(Mixer * mixer, MixerControl * control) { #ifdef AUDIO_MIXER_DEVINFO mixer_ctrl_t p; int i; - p.dev = index; + p.dev = control->index; p.type = control->type; p.un.value.num_channels = control->un.level.channels_cnt; for(i = 0; i < p.un.value.num_channels; i++) @@ -1067,7 +1119,10 @@ static int _mixer_set_control(Mixer * mixer, int index, MixerControl * control) level |= (control->un.level.channels[0] * 100) / 255; level |= ((control->un.level.channels[1] * 100) / 255) << 8; - if(ioctl(mixer->fd, MIXER_WRITE(index), &level) != 0) +# ifdef DEBUG + fprintf(stderr, "DEBUG: %s() level=0x%04x\n", __func__, level); +# endif + if(ioctl(mixer->fd, MIXER_WRITE(control->index), &level) != 0) return -_mixer_error(mixer, "MIXER_WRITE", 1); #endif return 0; @@ -1095,20 +1150,20 @@ static void _mixer_show_view(Mixer * mixer, int view) if(view < 0) { - for(u = 0; u < mixer->mc_cnt; u++) - if(mixer->mc[u].hbox != NULL) - gtk_widget_show(mixer->mc[u].hbox); + for(u = 0; u < mixer->classes_cnt; u++) + if(mixer->classes[u].hbox != NULL) + gtk_widget_show(mixer->classes[u].hbox); return; } u = view; - if(u >= mixer->mc_cnt) + if(u >= mixer->classes_cnt) return; - for(u = 0; u < mixer->mc_cnt; u++) - if(mixer->mc[u].hbox == NULL) + for(u = 0; u < mixer->classes_cnt; u++) + if(mixer->classes[u].hbox == NULL) continue; else if(u == (size_t)view) - gtk_widget_show(mixer->mc[u].hbox); + gtk_widget_show(mixer->classes[u].hbox); else - gtk_widget_hide(mixer->mc[u].hbox); + gtk_widget_hide(mixer->classes[u].hbox); #endif } diff --git a/src/mixer.h b/src/mixer.h index 1e6cfe8..ee7f6aa 100644 --- a/src/mixer.h +++ b/src/mixer.h @@ -33,6 +33,8 @@ # include # include +# include "control.h" +# include "common.h" /* Mixer */ @@ -51,8 +53,6 @@ typedef struct _MixerProperties char device[16]; } MixerProperties; -typedef struct _Mixer Mixer; - /* functions */ Mixer * mixer_new(GtkWidget * window, String const * device, @@ -63,10 +63,7 @@ void mixer_delete(Mixer * mixer); int mixer_get_properties(Mixer * mixer, MixerProperties * properties); GtkWidget * mixer_get_widget(Mixer * mixer); -int mixer_set_enum(Mixer * mixer, GtkWidget * widget); -int mixer_set_mute(Mixer * mixer, GtkWidget * widget); -int mixer_set_set(Mixer * mixer, GtkWidget * widget); -int mixer_set_value(Mixer * mixer, GtkWidget * widget, gdouble value); +int mixer_set(Mixer * mixer, MixerControl * control); /* useful */ void mixer_properties(Mixer * mixer); diff --git a/src/project.conf b/src/project.conf index 917316d..34a2902 100644 --- a/src/project.conf +++ b/src/project.conf @@ -6,7 +6,7 @@ cflags_force=`pkg-config --cflags libDesktop` cflags=-W -Wall -g -O2 -fPIE -D_FORTIFY_SOURCE=2 -fstack-protector-all ldflags_force=`pkg-config --libs libDesktop` -lintl ldflags=-pie -Wl,-z,relro -Wl,-z,now -dist=Makefile,mixer.h,window.h,callbacks.h +dist=Makefile,common.h,mixer.h,window.h,callbacks.h [mixer] type=binary @@ -14,16 +14,16 @@ sources=control.c,mixer.c,window.c,callbacks.c,main.c install=$(BINDIR) [control.c] -depends=control.h,../config.h +depends=../include/Mixer/control.h,common.h,control.h,../config.h [mixer.c] -depends=callbacks.h,mixer.h,../config.h +depends=callbacks.h,common.h,mixer.h,../config.h [window.c] depends=mixer.h,window.h [callbacks.c] -depends=mixer.h,callbacks.h,../config.h +depends=mixer.h,common.h,callbacks.h,../config.h [main.c] -depends=mixer.h,window.h,../config.h +depends=mixer.h,window.h,common.h,../config.h From a0953f5e733ce4d3dbd5fe534f501e9ebfc3d3f6 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 29 May 2017 18:22:03 +0200 Subject: [PATCH 51/68] Implement background refreshing of audio volume levels This is still buggy though. --- src/controls/channels.c | 9 ++ src/mixer.c | 215 +++++++++++++++++++++++++++++----------- src/mixer.h | 2 + 3 files changed, 167 insertions(+), 59 deletions(-) diff --git a/src/controls/channels.c b/src/controls/channels.c index 0f3a080..5dc070b 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -239,6 +239,7 @@ static int _channels_get(MixerControlPlugin * channels, va_list properties) value = va_arg(properties, double *); *value = gtk_range_get_value(GTK_RANGE( channels->channels[0].widget)); + *value = (*value * 255.0) / 100.0; } else if(sscanf(p, "value%zu", &i) == 1) { @@ -247,6 +248,7 @@ static int _channels_get(MixerControlPlugin * channels, va_list properties) value = va_arg(properties, double *); *value = gtk_range_get_value(GTK_RANGE( channels->channels[i].widget)); + *value = (*value * 255.0) / 100.0; } /* FIXME implement the rest */ else @@ -353,6 +355,7 @@ static int _set_channels(MixerControlPlugin * channels, size_t cnt) { size_t i; MixerControlChannel * p; + gboolean signal = channels->signal; /* delete channels as required */ if(channels->channels_cnt >= cnt) @@ -368,6 +371,7 @@ static int _set_channels(MixerControlPlugin * channels, size_t cnt) if((p = realloc(channels->channels, sizeof(*p) * cnt)) == NULL) return -1; channels->channels = p; + channels->signal = TRUE; for(i = channels->channels_cnt; i < cnt; i++) { p = &channels->channels[i]; @@ -381,6 +385,7 @@ static int _set_channels(MixerControlPlugin * channels, size_t cnt) gtk_box_pack_start(GTK_BOX(channels->hbox), p->widget, TRUE, TRUE, 0); } + channels->signal = signal; if((channels->channels_cnt = cnt) < 2) gtk_widget_hide(channels->bind); else @@ -419,10 +424,14 @@ static void _set_value(MixerControlPlugin * channels, gdouble value) static void _set_value_channel(MixerControlPlugin * channels, size_t channel, gdouble value) { + gboolean signal = channels->signal; + + channels->signal = TRUE; if(channel < channels->channels_cnt) gtk_range_set_value( GTK_RANGE(channels->channels[channel].widget), (value * 100.0) / 255.0); + channels->signal = signal; } diff --git a/src/mixer.c b/src/mixer.c index 310f514..bc3b25a 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -81,10 +81,8 @@ typedef struct _MixerLevel size_t channels_cnt; } MixerLevel; -/* FIXME there are two different MixerControl types */ -typedef struct _MixerControl MixerControl; - -struct _MixerControl +/* XXX rename this type */ +typedef struct _MixerControl2 { int index; int type; @@ -95,7 +93,7 @@ struct _MixerControl } un; MixerControl * control; -}; +} MixerControl2; struct _Mixer { @@ -117,8 +115,10 @@ struct _Mixer int fd; #endif - MixerControl * controls; + MixerControl2 * controls; size_t controls_cnt; + + guint source; }; @@ -126,12 +126,16 @@ struct _Mixer static int _mixer_error(Mixer * mixer, char const * message, int ret); /* accessors */ -static int _mixer_get_control(Mixer * mixer, MixerControl * control); -static int _mixer_set_control(Mixer * mixer, MixerControl * control); +static int _mixer_get_control(Mixer * mixer, MixerControl2 * control); +static int _mixer_set_control(Mixer * mixer, MixerControl2 * control); + +static int _mixer_set_control_widget(Mixer * mixer, MixerControl2 * control); static String const * _mixer_get_icon(String const * id); /* useful */ +static int _mixer_refresh_control(Mixer * mixer, MixerControl2 * control); + static void _mixer_scrolled_window_add(GtkWidget * window, GtkWidget * widget); static void _mixer_show_view(Mixer * mixer, int view); @@ -152,6 +156,8 @@ static MixerControl * _new_set(Mixer * mixer, int index, static MixerControl * _new_value(Mixer * mixer, int index, GtkSizeGroup * vgroup, String const * id, String const * icon, String const * name); +/* callbacks */ +static gboolean _new_on_refresh(gpointer data); Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout) { @@ -164,7 +170,7 @@ Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout) GtkWidget * hvbox = NULL; GtkWidget * hbox; MixerControl * control; - MixerControl * q; + MixerControl2 * q; int i; #ifdef AUDIO_MIXER_DEVINFO mixer_devinfo_t md; @@ -194,14 +200,15 @@ Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout) #endif mixer->controls = NULL; mixer->controls_cnt = 0; - hgroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - vgroup = gtk_size_group_new(GTK_SIZE_GROUP_VERTICAL); + mixer->source = 0; if(mixer->device == NULL || mixer->fd < 0) { _mixer_error(NULL, device, 0); mixer_delete(mixer); return NULL; } + hgroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + vgroup = gtk_size_group_new(GTK_SIZE_GROUP_VERTICAL); /* widgets */ mixer->bold = pango_font_description_new(); pango_font_description_set_weight(mixer->bold, PANGO_WEIGHT_BOLD); @@ -405,6 +412,7 @@ Mixer * mixer_new(GtkWidget * window, String const * device, MixerLayout layout) mixer_show_class(mixer, AudioCoutputs); #endif gtk_widget_show_all(mixer->widget); + mixer->source = g_timeout_add(500, _new_on_refresh, mixer); return mixer; } @@ -444,7 +452,7 @@ static MixerControl * _new_enum(Mixer * mixer, int index, struct audio_mixer_enum * e, String const * id, String const * icon, String const * name) { - MixerControl mc; + MixerControl2 mc; MixerControl * control; int i; char label[16]; @@ -469,7 +477,7 @@ static MixerControl * _new_enum(Mixer * mixer, int index, return NULL; } } - if(mixercontrol_set(control, "value", mc.un.mask, NULL) != 0) + if(_mixer_set_control_widget(mixer, &mc) != 0) { mixercontrol_delete(control); return NULL; @@ -481,7 +489,7 @@ static MixerControl * _new_set(Mixer * mixer, int index, struct audio_mixer_set * s, String const * id, String const * icon, String const * name) { - MixerControl mc; + MixerControl2 mc; MixerControl * control; int i; char label[16]; @@ -495,6 +503,7 @@ static MixerControl * _new_set(Mixer * mixer, int index, "set", "members", s->num_mem, NULL)) == NULL) return NULL; + mc.control = control; for(i = 0; i < s->num_mem; i++) { snprintf(label, sizeof(label), "label%d", i); @@ -506,7 +515,7 @@ static MixerControl * _new_set(Mixer * mixer, int index, return NULL; } } - if(mixercontrol_set(control, "value", mc.un.mask, NULL) != 0) + if(_mixer_set_control_widget(mixer, &mc) != 0) { mixercontrol_delete(control); return NULL; @@ -519,12 +528,10 @@ static MixerControl * _new_value(Mixer * mixer, int index, GtkSizeGroup * vgroup, String const * id, String const * icon, String const * name) { - MixerControl mc; + MixerControl2 mc; MixerControl * control; size_t i; gboolean bind = TRUE; - char buf[16]; - gdouble value; mc.index = index; if(_mixer_get_control(mixer, &mc) != 0 @@ -535,6 +542,7 @@ static MixerControl * _new_value(Mixer * mixer, int index, "delta", mc.un.level.delta, "vgroup", vgroup, NULL)) == NULL) return NULL; + mc.control = control; /* detect if binding is in place */ for(i = 1; i < mc.un.level.channels_cnt; i++) if(mc.un.level.channels[i] != mc.un.level.channels[0]) @@ -542,43 +550,32 @@ static MixerControl * _new_value(Mixer * mixer, int index, bind = FALSE; break; } - if(bind) + if(mixercontrol_set(control, "bind", bind, NULL) != 0 + || _mixer_set_control_widget(mixer, &mc) != 0) { - value = mc.un.level.channels[0]; - if(mixercontrol_set(control, "value", value, "bind", bind, NULL) - != 0) - { - mixercontrol_delete(control); - return NULL; - } - } - else - { - if(mixercontrol_set(control, "bind", bind, NULL) != 0) - { - mixercontrol_delete(control); - return NULL; - } - for(i = 0; i < mc.un.level.channels_cnt; i++) - { - snprintf(buf, sizeof(buf), "value%zu", i); - value = mc.un.level.channels[i]; - if(mixercontrol_set(control, buf, value, NULL) != 0) - { - mixercontrol_delete(control); - return NULL; - } - } + mixercontrol_delete(control); + return NULL; } return control; } +/* callbacks */ +static gboolean _new_on_refresh(gpointer data) +{ + Mixer * mixer = data; + + mixer_refresh(mixer); + return TRUE; +} + /* mixer_delete */ void mixer_delete(Mixer * mixer) { size_t i; + if(mixer->source > 0) + g_source_remove(mixer->source); for(i = 0; i < mixer->controls_cnt; i++) mixercontrol_delete(mixer->controls[i]); free(mixer->controls); @@ -665,8 +662,7 @@ static int _set_channels(Mixer * mixer, MixerControl * control) { size_t i; double value; - uint8_t channel; - MixerControl mc; + MixerControl2 mc; char buf[16]; #ifdef DEBUG @@ -686,12 +682,11 @@ static int _set_channels(Mixer * mixer, MixerControl * control) snprintf(buf, sizeof(buf), "value%zu", i); if(mixercontrol_get(control, buf, &value, NULL) != 0) return -1; - channel = (value * 255.0) / 100.0; #ifdef DEBUG - fprintf(stderr, "DEBUG: %s() value%zu=%f\n", __func__, i, - value); + fprintf(stderr, "DEBUG: %s() value%zu=%f\n", + __func__, i, value); #endif - mc.un.level.channels[i] = channel; + mc.un.level.channels[i] = value; } return _mixer_set_control(mixer, &mc); } @@ -701,7 +696,7 @@ static int _set_mute(Mixer * mixer, MixerControl * control) { size_t i; gboolean value; - MixerControl * mc; + MixerControl2 * mc; mixer_ctrl_t p; # ifdef DEBUG @@ -730,7 +725,7 @@ static int _set_mute(Mixer * mixer, MixerControl * control) static int _set_radio(Mixer * mixer, MixerControl * control) { size_t i; - MixerControl * mc; + MixerControl2 * mc; mixer_ctrl_t p; unsigned int value; @@ -761,7 +756,7 @@ static int _set_set(Mixer * mixer, MixerControl * control) { size_t i; unsigned int value; - MixerControl * mc; + MixerControl2 * mc; mixer_ctrl_t p; # ifdef DEBUG @@ -880,6 +875,18 @@ static gboolean _properties_on_closex(GtkWidget * widget) } +/* mixer_refresh */ +int mixer_refresh(Mixer * mixer) +{ + int ret = 0; + size_t i; + + for(i = 0; i < mixer->controls_cnt; i++) + ret |= _mixer_refresh_control(mixer, &mixer->controls[i]); + return ret; +} + + /* mixer_show */ void mixer_show(Mixer * mixer) { @@ -965,7 +972,7 @@ static int _error_text(char const * message, int ret) /* accessors */ /* mixer_get_control */ -static int _mixer_get_control(Mixer * mixer, MixerControl * control) +static int _mixer_get_control(Mixer * mixer, MixerControl2 * control) { #ifdef AUDIO_MIXER_DEVINFO mixer_ctrl_t p; @@ -1049,14 +1056,24 @@ static int _mixer_get_control(Mixer * mixer, MixerControl * control) # endif #else int value; + uint16_t u16; if(ioctl(mixer->fd, MIXER_READ(control->index), &value) != 0) return -_mixer_error(NULL, "MIXER_READ", 1); control->type = 0; control->un.level.delta = 1; control->un.level.channels_cnt = 2; - control->un.level.channels[0] = ((value & 0xff) * 255) / 100; - control->un.level.channels[1] = (((value & 0xff00) >> 8) * 255) / 100; + u16 = value & 0xff; + u16 = u16 * 255 / 100; + control->un.level.channels[0] = u16; + u16 = (value & 0xff00) >> 8; + u16 = u16 * 255 / 100; + control->un.level.channels[1] = u16; +# ifdef DEBUG + fprintf(stderr, "DEBUG: %s() 0x%02x%02x\n", __func__, + control->un.level.channels[0], + control->un.level.channels[1]); +# endif #endif return 0; } @@ -1101,7 +1118,7 @@ static String const * _mixer_get_icon(String const * id) /* mixer_set_control */ -static int _mixer_set_control(Mixer * mixer, MixerControl * control) +static int _mixer_set_control(Mixer * mixer, MixerControl2 * control) { #ifdef AUDIO_MIXER_DEVINFO mixer_ctrl_t p; @@ -1116,9 +1133,14 @@ static int _mixer_set_control(Mixer * mixer, MixerControl * control) return -_mixer_error(mixer, "AUDIO_MIXER_WRITE", 1); #else int level = 0; + uint16_t u16; - level |= (control->un.level.channels[0] * 100) / 255; - level |= ((control->un.level.channels[1] * 100) / 255) << 8; + u16 = control->un.level.channels[0]; + u16 = (u16 * 100) / 255; + level |= u16; + u16 = control->un.level.channels[1]; + u16 = (u16 * 100) / 255; + level |= (u16 << 8); # ifdef DEBUG fprintf(stderr, "DEBUG: %s() level=0x%04x\n", __func__, level); # endif @@ -1129,7 +1151,82 @@ static int _mixer_set_control(Mixer * mixer, MixerControl * control) } +/* mixer_set_control_widget */ +static int _set_control_widget_channels(MixerControl2 * control); +static int _set_control_widget_mute(MixerControl2 * control); +static int _set_control_widget_radio(MixerControl2 * control); +static int _set_control_widget_set(MixerControl2 * control); + +static int _mixer_set_control_widget(Mixer * mixer, MixerControl2 * control) +{ + String const * type; + + if((type = mixercontrol_get_type(control->control)) == NULL) + /* XXX report error */ + return -1; + if(string_compare(type, "channels") == 0) + return _set_control_widget_channels(control); + if(string_compare(type, "mute") == 0) + return _set_control_widget_mute(control); + if(string_compare(type, "radio") == 0) + return _set_control_widget_radio(control); + if(string_compare(type, "set") == 0) + return _set_control_widget_set(control); + return -1; +} + +static int _set_control_widget_channels(MixerControl2 * control) +{ + gboolean bind; + gdouble value; + size_t i; + char buf[16]; + + if(mixercontrol_get(control->control, "bind", &bind, NULL) != 0) + return -1; + if(bind) + { + value = control->un.level.channels[0]; + return mixercontrol_set(control->control, "value", value, NULL); + } + for(i = 0; i < control->un.level.channels_cnt; i++) + { + snprintf(buf, sizeof(buf), "value%zu", i); + value = control->un.level.channels[i]; + if(mixercontrol_set(control->control, buf, value, NULL) + != 0) + return -1; + } + return 0; +} + +static int _set_control_widget_mute(MixerControl2 * control) +{ + /* FIXME implement */ + return -1; +} + +static int _set_control_widget_radio(MixerControl2 * control) +{ + return mixercontrol_set(control->control, "value", control->un.mask, + NULL); +} + +static int _set_control_widget_set(MixerControl2 * control) +{ + return mixercontrol_set(control->control, "value", control->un.mask, + NULL); +} + + /* useful */ +/* mixer_refresh_control */ +static int _mixer_refresh_control(Mixer * mixer, MixerControl2 * control) +{ + return _mixer_set_control_widget(mixer, control); +} + + /* mixer_scrolled_window_add */ static void _mixer_scrolled_window_add(GtkWidget * window, GtkWidget * widget) { diff --git a/src/mixer.h b/src/mixer.h index ee7f6aa..bf4607f 100644 --- a/src/mixer.h +++ b/src/mixer.h @@ -68,6 +68,8 @@ int mixer_set(Mixer * mixer, MixerControl * control); /* useful */ void mixer_properties(Mixer * mixer); +int mixer_refresh(Mixer * mixer); + void mixer_show(Mixer * mixer); void mixer_show_all(Mixer * mixer); void mixer_show_class(Mixer * mixer, String const * name); From 60cb36f55f4d5eb021ff7c7edc2ed26f6887396f Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 6 Jun 2017 16:59:11 +0200 Subject: [PATCH 52/68] Fix compilation --- src/mixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mixer.c b/src/mixer.c index bc3b25a..519e74e 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -577,7 +577,7 @@ void mixer_delete(Mixer * mixer) if(mixer->source > 0) g_source_remove(mixer->source); for(i = 0; i < mixer->controls_cnt; i++) - mixercontrol_delete(mixer->controls[i]); + mixercontrol_delete(mixer->controls[i].control); free(mixer->controls); if(mixer->fd >= 0) close(mixer->fd); From eb4d16383e961481f723fd61eb510606b5639500 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 6 Jun 2017 19:04:42 +0200 Subject: [PATCH 53/68] Implement obtaining the delta back --- src/controls/channels.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/controls/channels.c b/src/controls/channels.c index 5dc070b..9aa926b 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -217,6 +217,7 @@ static int _channels_get(MixerControlPlugin * channels, va_list properties) gboolean * b; double * value; size_t i; + unsigned int * u; #ifdef DEBUG fprintf(stderr, "DEBUG: %s()\n", __func__); @@ -228,6 +229,11 @@ static int _channels_get(MixerControlPlugin * channels, va_list properties) *b = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( channels->bind)); } + else if(string_compare(p, "delta") == 0) + { + u = va_arg(properties, unsigned int *); + *u = channels->delta; + } else if(string_compare(p, "value") == 0) { if(channels->channels_cnt == 0) From f325dd727fe902263325e1b4f02dd94308deff9c Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 6 Jun 2017 19:06:15 +0200 Subject: [PATCH 54/68] Minor optimization --- src/controls/channels.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/controls/channels.c b/src/controls/channels.c index 9aa926b..7eaa0b2 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -430,13 +430,14 @@ static void _set_value(MixerControlPlugin * channels, gdouble value) static void _set_value_channel(MixerControlPlugin * channels, size_t channel, gdouble value) { - gboolean signal = channels->signal; + gboolean signal; + if(channel >= channels->channels_cnt) + return; + signal = channels->signal; channels->signal = TRUE; - if(channel < channels->channels_cnt) - gtk_range_set_value( - GTK_RANGE(channels->channels[channel].widget), - (value * 100.0) / 255.0); + gtk_range_set_value(GTK_RANGE(channels->channels[channel].widget), + (value * 100.0) / 255.0); channels->signal = signal; } From ce4903ee46fcd2b3c56c6659b26e0050b6b754f4 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 6 Jun 2017 19:08:19 +0200 Subject: [PATCH 55/68] Fix setting radio and set values on NetBSD --- src/mixer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mixer.c b/src/mixer.c index 519e74e..be9f10d 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -747,7 +747,7 @@ static int _set_radio(Mixer * mixer, MixerControl * control) # ifdef DEBUG fprintf(stderr, "DEBUG: %s() ord=%d\n", __func__, p.un.ord); # endif - if(ioctl(mixer->fd, AUDIO_MIXER_WRITE, p) != 0) + if(ioctl(mixer->fd, AUDIO_MIXER_WRITE, &p) != 0) return -_mixer_error(mixer, "AUDIO_MIXER_WRITE", 1); return 0; } @@ -777,7 +777,7 @@ static int _set_set(Mixer * mixer, MixerControl * control) # ifdef DEBUG fprintf(stderr, "DEBUG: %s() mask=%d\n", __func__, p.un.mask); # endif - if(ioctl(mixer->fd, AUDIO_MIXER_WRITE, p) != 0) + if(ioctl(mixer->fd, AUDIO_MIXER_WRITE, &p) != 0) return -_mixer_error(mixer, "AUDIO_MIXER_WRITE", 1); return 0; } From c8fdfc1663dcef6c0b3df2856c98d1142ab3c51f Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 6 Jun 2017 19:10:51 +0200 Subject: [PATCH 56/68] Keep the internal structures up to date --- src/mixer.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mixer.c b/src/mixer.c index be9f10d..537d12b 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -662,7 +662,7 @@ static int _set_channels(Mixer * mixer, MixerControl * control) { size_t i; double value; - MixerControl2 mc; + MixerControl2 * mc; char buf[16]; #ifdef DEBUG @@ -674,10 +674,10 @@ static int _set_channels(Mixer * mixer, MixerControl * control) break; if(i == mixer->controls_cnt) return -1; - mc.index = mixer->controls[i].index; - if(_mixer_get_control(mixer, &mc) != 0) + mc = &mixer->controls[i]; + if(_mixer_get_control(mixer, mc) != 0) return -1; - for(i = 0; i < mc.un.level.channels_cnt; i++) + for(i = 0; i < mc->un.level.channels_cnt; i++) { snprintf(buf, sizeof(buf), "value%zu", i); if(mixercontrol_get(control, buf, &value, NULL) != 0) @@ -686,9 +686,9 @@ static int _set_channels(Mixer * mixer, MixerControl * control) fprintf(stderr, "DEBUG: %s() value%zu=%f\n", __func__, i, value); #endif - mc.un.level.channels[i] = value; + mc->un.level.channels[i] = value; } - return _mixer_set_control(mixer, &mc); + return _mixer_set_control(mixer, mc); } #if defined(AUDIO_MIXER_DEVINFO) From 7a26a8d0673ec64c86bbecda081d629e2c743ba7 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 6 Jun 2017 19:12:30 +0200 Subject: [PATCH 57/68] Fix automatic refreshing --- src/mixer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mixer.c b/src/mixer.c index 537d12b..6696756 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -1223,6 +1223,8 @@ static int _set_control_widget_set(MixerControl2 * control) /* mixer_refresh_control */ static int _mixer_refresh_control(Mixer * mixer, MixerControl2 * control) { + if(_mixer_get_control(mixer, control) != 0) + return -1; return _mixer_set_control_widget(mixer, control); } From 3c9781e005c59f81b55dc248d2d1beabcc0ecbe8 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 6 Jun 2017 19:13:45 +0200 Subject: [PATCH 58/68] Unset bind if the channels differ --- src/mixer.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/mixer.c b/src/mixer.c index 6696756..cc2d55f 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -1177,24 +1177,28 @@ static int _mixer_set_control_widget(Mixer * mixer, MixerControl2 * control) static int _set_control_widget_channels(MixerControl2 * control) { - gboolean bind; + gboolean bind = TRUE; gdouble value; size_t i; char buf[16]; - if(mixercontrol_get(control->control, "bind", &bind, NULL) != 0) - return -1; - if(bind) - { - value = control->un.level.channels[0]; - return mixercontrol_set(control->control, "value", value, NULL); - } + /* unset bind if the channels are no longer synchronized */ + for(i = 1; i < control->un.level.channels_cnt; i++) + if(control->un.level.channels[i] + != control->un.level.channels[i - 1]) + { + bind = FALSE; + break; + } + if(bind == FALSE) + if(mixercontrol_set(control->control, "bind", FALSE, NULL) != 0) + return -1; + /* set the individual channels */ for(i = 0; i < control->un.level.channels_cnt; i++) { snprintf(buf, sizeof(buf), "value%zu", i); value = control->un.level.channels[i]; - if(mixercontrol_set(control->control, buf, value, NULL) - != 0) + if(mixercontrol_set(control->control, buf, value, NULL) != 0) return -1; } return 0; From 13474e6cd0a34d906c302dd5fb0db2306ca8d07c Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 6 Jun 2017 19:15:44 +0200 Subject: [PATCH 59/68] Handle channel levels from 0 to 100% internally --- src/controls/channels.c | 4 +--- src/mixer.c | 30 +++++++++++++----------------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/controls/channels.c b/src/controls/channels.c index 7eaa0b2..997ccc8 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -245,7 +245,6 @@ static int _channels_get(MixerControlPlugin * channels, va_list properties) value = va_arg(properties, double *); *value = gtk_range_get_value(GTK_RANGE( channels->channels[0].widget)); - *value = (*value * 255.0) / 100.0; } else if(sscanf(p, "value%zu", &i) == 1) { @@ -254,7 +253,6 @@ static int _channels_get(MixerControlPlugin * channels, va_list properties) value = va_arg(properties, double *); *value = gtk_range_get_value(GTK_RANGE( channels->channels[i].widget)); - *value = (*value * 255.0) / 100.0; } /* FIXME implement the rest */ else @@ -437,7 +435,7 @@ static void _set_value_channel(MixerControlPlugin * channels, signal = channels->signal; channels->signal = TRUE; gtk_range_set_value(GTK_RANGE(channels->channels[channel].widget), - (value * 100.0) / 255.0); + value); channels->signal = signal; } diff --git a/src/mixer.c b/src/mixer.c index cc2d55f..02c277a 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -686,7 +686,7 @@ static int _set_channels(Mixer * mixer, MixerControl * control) fprintf(stderr, "DEBUG: %s() value%zu=%f\n", __func__, i, value); #endif - mc->un.level.channels[i] = value; + mc->un.level.channels[i] = (value * 255.0) / 100.0; } return _mixer_set_control(mixer, mc); } @@ -978,6 +978,7 @@ static int _mixer_get_control(Mixer * mixer, MixerControl2 * control) mixer_ctrl_t p; struct mixer_devinfo md; int i; + uint16_t u16; # ifdef DEBUG size_t u; char * sep = ""; @@ -1032,19 +1033,21 @@ static int _mixer_get_control(Mixer * mixer, MixerControl2 * control) # endif break; case AUDIO_MIXER_VALUE: - if((control->un.level.delta = (md.un.v.delta * 100) - / 255) == 0) - control->un.level.delta = 1; + u16 = md.un.v.delta; + if((u16 = (u16 * 100) / 255) == 0) + u16 = 1; + control->un.level.delta = u16; control->un.level.channels_cnt = p.un.value.num_channels; for(i = 0; i < p.un.value.num_channels; i++) { - control->un.level.channels[i] - = p.un.value.level[i]; # ifdef DEBUG printf("%s%u", sep, p.un.value.level[i]); sep = ","; # endif + u16 = p.un.value.level[i]; + u16 = (u16 * 100) / 255; + control->un.level.channels[i] = u16; } #ifdef DEBUG printf(" delta=%u", md.un.v.delta); @@ -1064,13 +1067,11 @@ static int _mixer_get_control(Mixer * mixer, MixerControl2 * control) control->un.level.delta = 1; control->un.level.channels_cnt = 2; u16 = value & 0xff; - u16 = u16 * 255 / 100; control->un.level.channels[0] = u16; u16 = (value & 0xff00) >> 8; - u16 = u16 * 255 / 100; control->un.level.channels[1] = u16; # ifdef DEBUG - fprintf(stderr, "DEBUG: %s() 0x%02x%02x\n", __func__, + fprintf(stderr, "DEBUG: %s() % 3d % 3d\n", __func__, control->un.level.channels[0], control->un.level.channels[1]); # endif @@ -1132,15 +1133,10 @@ static int _mixer_set_control(Mixer * mixer, MixerControl2 * control) if(ioctl(mixer->fd, AUDIO_MIXER_WRITE, &p) != 0) return -_mixer_error(mixer, "AUDIO_MIXER_WRITE", 1); #else - int level = 0; - uint16_t u16; + int level; - u16 = control->un.level.channels[0]; - u16 = (u16 * 100) / 255; - level |= u16; - u16 = control->un.level.channels[1]; - u16 = (u16 * 100) / 255; - level |= (u16 << 8); + level = (control->un.level.channels[1] << 8) + | control->un.level.channels[0]; # ifdef DEBUG fprintf(stderr, "DEBUG: %s() level=0x%04x\n", __func__, level); # endif From 2dca9f77c9e095616a6539d5d7efed2b96bc9c5e Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 6 Jun 2017 19:24:16 +0200 Subject: [PATCH 60/68] Support reporting the current mute setting --- src/controls/channels.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/controls/channels.c b/src/controls/channels.c index 997ccc8..ac39e6c 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -211,6 +211,8 @@ static void _channels_destroy(MixerControlPlugin * channels) /* accessors */ +static gboolean _get_mute(MixerControlPlugin * channels); + static int _channels_get(MixerControlPlugin * channels, va_list properties) { String const * p; @@ -234,6 +236,11 @@ static int _channels_get(MixerControlPlugin * channels, va_list properties) u = va_arg(properties, unsigned int *); *u = channels->delta; } + if(string_compare(p, "mute") == 0) + { + b = va_arg(properties, gboolean *); + *b = _get_mute(channels); + } else if(string_compare(p, "value") == 0) { if(channels->channels_cnt == 0) @@ -260,6 +267,15 @@ static int _channels_get(MixerControlPlugin * channels, va_list properties) return 0; } +static gboolean _get_mute(MixerControlPlugin * channels) +{ +#if GTK_CHECK_VERSION(3, 0, 0) + return gtk_switch_get_active(GTK_SWITCH(channels->mute)); +#else + return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(channels->mute)); +#endif +} + /* channels_get_type */ static String const * _channels_get_type(MixerControlPlugin * channels) From 663139ca30e8866a432109493efc7769e884b5ba Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 7 Jun 2017 00:46:20 -0400 Subject: [PATCH 61/68] Avoid a crash when refreshing the channels --- src/controls/channels.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controls/channels.c b/src/controls/channels.c index ac39e6c..2470f84 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -236,7 +236,7 @@ static int _channels_get(MixerControlPlugin * channels, va_list properties) u = va_arg(properties, unsigned int *); *u = channels->delta; } - if(string_compare(p, "mute") == 0) + else if(string_compare(p, "mute") == 0) { b = va_arg(properties, gboolean *); *b = _get_mute(channels); From 44cb8c5516578250c338e669c1de94e27b3c74d5 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Thu, 8 Jun 2017 23:48:09 -0400 Subject: [PATCH 62/68] Review memory management when exiting --- src/control.c | 2 -- src/controls/channels.c | 2 +- src/controls/mute.c | 1 - src/controls/radio.c | 1 - src/controls/set.c | 1 - 5 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/control.c b/src/control.c index 1a933c2..241485d 100644 --- a/src/control.c +++ b/src/control.c @@ -137,8 +137,6 @@ void mixercontrol_delete(MixerControl * control) control->definition->destroy(control->plugin); if(control->handle != NULL) plugin_delete(control->handle); - if(control->frame != NULL) - g_object_unref(control->frame); if(control->id != NULL) string_delete(control->id); object_delete(control); diff --git a/src/controls/channels.c b/src/controls/channels.c index 2470f84..a8dcd3f 100644 --- a/src/controls/channels.c +++ b/src/controls/channels.c @@ -205,7 +205,7 @@ static MixerControlPlugin * _channels_init(MixerControlPluginHelper * helper, /* channels_destroy */ static void _channels_destroy(MixerControlPlugin * channels) { - g_object_unref(channels->widget); + free(channels->channels); object_delete(channels); } diff --git a/src/controls/mute.c b/src/controls/mute.c index 40417ff..c65925d 100644 --- a/src/controls/mute.c +++ b/src/controls/mute.c @@ -134,7 +134,6 @@ static MixerControlPlugin * _mute_init(MixerControlPluginHelper * helper, /* mute_destroy */ static void _mute_destroy(MixerControlPlugin * mute) { - g_object_unref(mute->widget); object_delete(mute); } diff --git a/src/controls/radio.c b/src/controls/radio.c index 38d7e69..a5b31bf 100644 --- a/src/controls/radio.c +++ b/src/controls/radio.c @@ -121,7 +121,6 @@ static MixerControlPlugin * _radio_init(MixerControlPluginHelper * helper, static void _radio_destroy(MixerControlPlugin * radio) { free(radio->radios); - g_object_unref(radio->widget); object_delete(radio); } diff --git a/src/controls/set.c b/src/controls/set.c index 26ac2e3..1c2de6d 100644 --- a/src/controls/set.c +++ b/src/controls/set.c @@ -116,7 +116,6 @@ static MixerControlPlugin * _set_init(MixerControlPluginHelper * helper, static void _set_destroy(MixerControlPlugin * set) { free(set->sets); - g_object_unref(set->widget); object_delete(set); } From 31c03267cf655042aee40beb4de6a01e3f790259 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 9 Jun 2017 00:13:16 -0400 Subject: [PATCH 63/68] Implement getting and setting the values --- src/controls/set.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/controls/set.c b/src/controls/set.c index 1c2de6d..aab74f3 100644 --- a/src/controls/set.c +++ b/src/controls/set.c @@ -122,10 +122,35 @@ static void _set_destroy(MixerControlPlugin * set) /* accessors */ /* set_get */ +static unsigned int _get_value(MixerControlPlugin * set); + static int _set_get(MixerControlPlugin * set, va_list properties) { - /* FIXME implement */ - return -1; + String const * p; + unsigned int * u; + + while((p = va_arg(properties, String const *)) != NULL) + if(string_compare(p, "value") == 0) + { + u = va_arg(properties, unsigned int *); + *u = _get_value(set); + } + else + /* FIXME implement the rest */ + return -1; + return 0; +} + +static unsigned int _get_value(MixerControlPlugin * set) +{ + unsigned int ret = 0; + size_t i; + + for(i = 0; i < set->sets_cnt; i++) + ret |= gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(set->sets[i].widget)) + ? set->sets[i].value : 0; + return ret; } @@ -233,7 +258,12 @@ static int _set_members(MixerControlPlugin * set, unsigned int cnt) static int _set_value(MixerControlPlugin * set, unsigned int value) { - /* FIXME implement */ + size_t i; + + for(i = 0; i < set->sets_cnt; i++) + gtk_toggle_button_set_active( + GTK_TOGGLE_BUTTON(set->sets[i].widget), + (set->sets[i].value & value) ? TRUE : FALSE); return 0; } From 7b0736d21a49139c7bcaf891dba0333bd6a830ca Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 9 Jun 2017 00:17:40 -0400 Subject: [PATCH 64/68] Implement the callback for sets --- src/controls/set.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/controls/set.c b/src/controls/set.c index aab74f3..920c03e 100644 --- a/src/controls/set.c +++ b/src/controls/set.c @@ -68,6 +68,9 @@ static GtkWidget * _set_get_widget(MixerControlPlugin * set); static int _set_set(MixerControlPlugin * set, va_list properties); +/* callbacks */ +static void _set_on_toggled(gpointer data); + /* public */ /* variables */ @@ -248,7 +251,8 @@ static int _set_members(MixerControlPlugin * set, unsigned int cnt) p->value = 0; p->widget = gtk_check_button_new(); gtk_widget_set_sensitive(p->widget, FALSE); - /* FIXME implement the callback */ + g_signal_connect_swapped(p->widget, "toggled", G_CALLBACK( + _set_on_toggled), set); gtk_container_add(GTK_CONTAINER(set->widget), p->widget); } set->sets_cnt = cnt; @@ -280,4 +284,10 @@ static int _set_value_pos(MixerControlPlugin * set, unsigned int pos, /* callbacks */ -/* FIXME implement */ +/* set_on_toggled */ +static void _set_on_toggled(gpointer data) +{ + MixerControlPlugin * set = data; + + set->helper->mixercontrol_set(set->helper->control); +} From eda11af1b53ed374c64e9b89aa05e99441a68d5d Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 9 Jun 2017 00:30:48 -0400 Subject: [PATCH 65/68] Code cleanup --- src/controls/radio.c | 53 +++++++++++++++++++++++++++++++++++++++----- src/controls/set.c | 1 + 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/controls/radio.c b/src/controls/radio.c index a5b31bf..af1e479 100644 --- a/src/controls/radio.c +++ b/src/controls/radio.c @@ -71,6 +71,7 @@ static GtkWidget * _radio_get_widget(MixerControlPlugin * radio); static int _radio_set(MixerControlPlugin * radio, va_list properties); /* callbacks */ +static void _radio_on_toggled(gpointer data); /* public */ @@ -127,10 +128,34 @@ static void _radio_destroy(MixerControlPlugin * radio) /* accessors */ /* radio_get */ +static unsigned int _get_value(MixerControlPlugin * radio); + static int _radio_get(MixerControlPlugin * radio, va_list properties) { - /* FIXME implement */ - return -1; + String const * p; + unsigned int * u; + + while((p = va_arg(properties, String const *)) != NULL) + if(string_compare(p, "value") == 0) + { + u = va_arg(properties, unsigned int *); + *u = _get_value(radio); + } + else + /* FIXME implement the rest */ + return -1; + return 0; +} + +static unsigned int _get_value(MixerControlPlugin * radio) +{ + size_t i; + + for(i = 0; i < radio->radios_cnt; i++) + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( + radio->radios[i].widget))) + return radio->radios[i].value; + return 0; } @@ -228,10 +253,11 @@ static int _set_members(MixerControlPlugin * radio, unsigned int cnt) p->value = 0; p->widget = gtk_radio_button_new(radio->group); gtk_widget_set_sensitive(p->widget, FALSE); - /* FIXME implement the callback */ if(radio->group == NULL) radio->group = gtk_radio_button_get_group( GTK_RADIO_BUTTON(p->widget)); + g_signal_connect_swapped(p->widget, "toggled", G_CALLBACK( + _radio_on_toggled), radio); gtk_container_add(GTK_CONTAINER(radio->widget), p->widget); } radio->radios_cnt = cnt; @@ -241,8 +267,17 @@ static int _set_members(MixerControlPlugin * radio, unsigned int cnt) static int _set_value(MixerControlPlugin * radio, unsigned int value) { - /* FIXME implement */ - return 0; + size_t i; + + for(i = 0; i < radio->radios_cnt; i++) + if(radio->radios[i].value == value) + { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( + radio->radios[i].widget), + TRUE); + return 0; + } + return -1; } static int _set_value_pos(MixerControlPlugin * radio, unsigned int pos, @@ -258,4 +293,10 @@ static int _set_value_pos(MixerControlPlugin * radio, unsigned int pos, /* callbacks */ -/* FIXME implement */ +/* radio_on_toggled */ +static void _radio_on_toggled(gpointer data) +{ + MixerControlPlugin * radio = data; + + radio->helper->mixercontrol_set(radio->helper->control); +} diff --git a/src/controls/set.c b/src/controls/set.c index 920c03e..1c26432 100644 --- a/src/controls/set.c +++ b/src/controls/set.c @@ -57,6 +57,7 @@ struct _MixerControlPlugin /* prototypes */ +/* control */ static MixerControlPlugin * _set_init(MixerControlPluginHelper * helper, String const * type, va_list properties); static void _set_destroy(MixerControlPlugin * set); From bc8988b30b4bb802079eb17913f3430546fe2c96 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 14 Jun 2017 16:16:34 -0400 Subject: [PATCH 66/68] Round up when converting scale with audioio --- src/mixer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mixer.c b/src/mixer.c index 02c277a..c51d680 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -1034,7 +1034,7 @@ static int _mixer_get_control(Mixer * mixer, MixerControl2 * control) break; case AUDIO_MIXER_VALUE: u16 = md.un.v.delta; - if((u16 = (u16 * 100) / 255) == 0) + if((u16 = ceil((u16 * 100) / 255.0)) == 0) u16 = 1; control->un.level.delta = u16; control->un.level.channels_cnt @@ -1046,7 +1046,7 @@ static int _mixer_get_control(Mixer * mixer, MixerControl2 * control) sep = ","; # endif u16 = p.un.value.level[i]; - u16 = (u16 * 100) / 255; + u16 = ceil((u16 * 100) / 255.0); control->un.level.channels[i] = u16; } #ifdef DEBUG From 9eacf2981f8017f6d690c015b76d56527f3d8646 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 30 Jun 2017 12:58:51 +0200 Subject: [PATCH 67/68] Add missing include ceil() needs . --- src/mixer.c | 1 + src/project.conf | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mixer.c b/src/mixer.c index c51d680..384ca5d 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include diff --git a/src/project.conf b/src/project.conf index 34a2902..fcaaf70 100644 --- a/src/project.conf +++ b/src/project.conf @@ -4,7 +4,7 @@ cppflags_force=-I../include #cppflags=-D EMBEDDED cflags_force=`pkg-config --cflags libDesktop` cflags=-W -Wall -g -O2 -fPIE -D_FORTIFY_SOURCE=2 -fstack-protector-all -ldflags_force=`pkg-config --libs libDesktop` -lintl +ldflags_force=`pkg-config --libs libDesktop` -lintl -lm ldflags=-pie -Wl,-z,relro -Wl,-z,now dist=Makefile,common.h,mixer.h,window.h,callbacks.h From e406bac13dfbb679ee9ab34e64de8b0fb2a363ae Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 30 Jun 2017 12:59:36 +0200 Subject: [PATCH 68/68] Also ship control.h --- src/project.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/project.conf b/src/project.conf index fcaaf70..4ba7444 100644 --- a/src/project.conf +++ b/src/project.conf @@ -6,7 +6,7 @@ cflags_force=`pkg-config --cflags libDesktop` cflags=-W -Wall -g -O2 -fPIE -D_FORTIFY_SOURCE=2 -fstack-protector-all ldflags_force=`pkg-config --libs libDesktop` -lintl -lm ldflags=-pie -Wl,-z,relro -Wl,-z,now -dist=Makefile,common.h,mixer.h,window.h,callbacks.h +dist=Makefile,common.h,control.h,mixer.h,window.h,callbacks.h [mixer] type=binary