Merge branch 'khorben/controls'
This commit is contained in:
commit
4caa10c5b2
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -2,4 +2,7 @@ Makefile
|
|||
/config.h
|
||||
/config.sh
|
||||
*~
|
||||
*.dll
|
||||
*.dylib
|
||||
*.o
|
||||
*.so
|
||||
|
|
24
include/Mixer.h
Normal file
24
include/Mixer.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2017 Pierre Pronchery <khorben@defora.org> */
|
||||
/* 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 <http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
|
||||
#ifndef DESKTOP_MIXER_H
|
||||
# define DESKTOP_MIXER_H
|
||||
|
||||
|
||||
# include "Mixer/control.h"
|
||||
|
||||
#endif /* !DESKTOP_MIXER_H */
|
68
include/Mixer/control.h
Normal file
68
include/Mixer/control.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2017 Pierre Pronchery <khorben@defora.org> */
|
||||
/* 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 <stdarg.h>
|
||||
# include <gtk/gtk.h>
|
||||
# include <System/string.h>
|
||||
|
||||
|
||||
/* 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;
|
||||
String const * name;
|
||||
String const * description;
|
||||
|
||||
/* callbacks */
|
||||
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);
|
||||
} MixerControlDefinition;
|
||||
|
||||
#endif /* !DESKTOP_MIXER_CONTROL_H */
|
5
include/Mixer/project.conf
Normal file
5
include/Mixer/project.conf
Normal file
|
@ -0,0 +1,5 @@
|
|||
includes=control.h
|
||||
dist=Makefile
|
||||
|
||||
[control.h]
|
||||
install=$(PREFIX)/include/Desktop/Mixer
|
6
include/project.conf
Normal file
6
include/project.conf
Normal file
|
@ -0,0 +1,6 @@
|
|||
subdirs=Mixer
|
||||
includes=Mixer.h
|
||||
dist=Makefile
|
||||
|
||||
[Mixer.h]
|
||||
install=$(PREFIX)/include/Desktop
|
|
@ -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]
|
||||
|
|
42
src/common.h
Normal file
42
src/common.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2017 Pierre Pronchery <khorben@defora.org> */
|
||||
/* 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 */
|
218
src/control.c
Normal file
218
src/control.c
Normal file
|
@ -0,0 +1,218 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2017 Pierre Pronchery <khorben@defora.org> */
|
||||
/* 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. */
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
#include <System/object.h>
|
||||
#include <System/plugin.h>
|
||||
#include "Mixer/control.h"
|
||||
#include "mixer.h"
|
||||
#include "control.h"
|
||||
#include "../config.h"
|
||||
|
||||
|
||||
/* private */
|
||||
/* types */
|
||||
struct _MixerControl
|
||||
{
|
||||
Mixer * mixer;
|
||||
|
||||
MixerControlPluginHelper helper;
|
||||
|
||||
String * id;
|
||||
Plugin * handle;
|
||||
MixerControlDefinition * definition;
|
||||
MixerControlPlugin * plugin;
|
||||
GtkWidget * widget;
|
||||
|
||||
/* widgets */
|
||||
GtkWidget * frame;
|
||||
GtkWidget * icon;
|
||||
GtkWidget * name;
|
||||
};
|
||||
|
||||
|
||||
/* prototypes */
|
||||
/* helper */
|
||||
static int _mixercontrol_helper_set(MixerControl * control);
|
||||
|
||||
|
||||
/* public */
|
||||
/* functions */
|
||||
/* mixercontrol_new */
|
||||
MixerControl * mixercontrol_new(Mixer * mixer, String const * id,
|
||||
String const * icon, String const * name,
|
||||
String const * type, ...)
|
||||
{
|
||||
MixerControl * control;
|
||||
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->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;
|
||||
control->plugin = NULL;
|
||||
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(
|
||||
&control->helper, type, ap)) == NULL
|
||||
|| control->definition->get_widget == NULL
|
||||
|| (control->widget = control->definition->get_widget(
|
||||
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;
|
||||
}
|
||||
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);
|
||||
gtk_frame_set_label_widget(GTK_FRAME(control->frame), hbox);
|
||||
gtk_container_add(GTK_CONTAINER(control->frame), control->widget);
|
||||
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->id != NULL)
|
||||
string_delete(control->id);
|
||||
object_delete(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)
|
||||
{
|
||||
return control->id;
|
||||
}
|
||||
|
||||
|
||||
/* 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)
|
||||
{
|
||||
return control->frame;
|
||||
}
|
||||
|
||||
|
||||
/* mixercontrol_set */
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/* 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);
|
||||
}
|
60
src/control.h
Normal file
60
src/control.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2017 Pierre Pronchery <khorben@defora.org> */
|
||||
/* 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 <gtk/gtk.h>
|
||||
# include <System/string.h>
|
||||
# include "common.h"
|
||||
|
||||
|
||||
/* MixerControl */
|
||||
/* types */
|
||||
typedef struct _MixerControl MixerControl;
|
||||
|
||||
|
||||
/* functions */
|
||||
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);
|
||||
|
||||
void mixercontrol_set_icon(MixerControl * control, String const * icon);
|
||||
|
||||
#endif /* !MIXER_CONTROL_H */
|
525
src/controls/channels.c
Normal file
525
src/controls/channels.c
Normal file
|
@ -0,0 +1,525 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2017 Pierre Pronchery <khorben@defora.org> */
|
||||
/* 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 <stdlib.h>
|
||||
#ifdef DEBUG
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
#include <libintl.h>
|
||||
#include <System/object.h>
|
||||
#include "Mixer/control.h"
|
||||
#define _(string) gettext(string)
|
||||
|
||||
|
||||
/* MixerControlChannels */
|
||||
/* private */
|
||||
/* types */
|
||||
typedef struct _MixerControlChannel
|
||||
{
|
||||
MixerControlPlugin * plugin;
|
||||
|
||||
GtkWidget * widget;
|
||||
} MixerControlChannel;
|
||||
|
||||
struct _MixerControlPlugin
|
||||
{
|
||||
MixerControlPluginHelper * helper;
|
||||
|
||||
GtkWidget * widget;
|
||||
|
||||
unsigned int delta;
|
||||
|
||||
/* channels */
|
||||
GtkWidget * hbox;
|
||||
MixerControlChannel * channels;
|
||||
size_t channels_cnt;
|
||||
|
||||
GtkWidget * bbox;
|
||||
|
||||
/* bind */
|
||||
GtkWidget * bind;
|
||||
GtkWidget * bind_image;
|
||||
|
||||
/* mute */
|
||||
GtkWidget * mute;
|
||||
#if !GTK_CHECK_VERSION(3, 0, 0)
|
||||
GtkWidget * mute_image;
|
||||
#endif
|
||||
|
||||
gboolean signal;
|
||||
};
|
||||
|
||||
|
||||
/* prototypes */
|
||||
/* control */
|
||||
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);
|
||||
|
||||
static int _channels_set(MixerControlPlugin * channels, va_list properties);
|
||||
|
||||
/* callbacks */
|
||||
static void _channels_on_bind_toggled(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 */
|
||||
/* variables */
|
||||
MixerControlDefinition control =
|
||||
{
|
||||
NULL,
|
||||
"Channels",
|
||||
NULL,
|
||||
_channels_init,
|
||||
_channels_destroy,
|
||||
_channels_get,
|
||||
_channels_get_type,
|
||||
_channels_get_widget,
|
||||
_channels_set
|
||||
};
|
||||
|
||||
|
||||
/* private */
|
||||
/* functions */
|
||||
/* channels_init */
|
||||
static MixerControlPlugin * _channels_init(MixerControlPluginHelper * helper,
|
||||
String const * type, va_list properties)
|
||||
{
|
||||
MixerControlPlugin * channels;
|
||||
GtkWidget * hbox;
|
||||
GtkWidget * widget;
|
||||
#if !GTK_CHECK_VERSION(3, 14, 0)
|
||||
GtkWidget * align;
|
||||
#endif
|
||||
(void) 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;
|
||||
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
|
||||
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);
|
||||
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);
|
||||
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();
|
||||
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);
|
||||
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_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);
|
||||
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);
|
||||
channels->signal = FALSE;
|
||||
if(_channels_set(channels, properties) != 0)
|
||||
{
|
||||
_channels_destroy(channels);
|
||||
return NULL;
|
||||
}
|
||||
return channels;
|
||||
}
|
||||
|
||||
|
||||
/* channels_destroy */
|
||||
static void _channels_destroy(MixerControlPlugin * channels)
|
||||
{
|
||||
free(channels->channels);
|
||||
object_delete(channels);
|
||||
}
|
||||
|
||||
|
||||
/* accessors */
|
||||
static gboolean _get_mute(MixerControlPlugin * channels);
|
||||
|
||||
static int _channels_get(MixerControlPlugin * channels, va_list properties)
|
||||
{
|
||||
String const * p;
|
||||
gboolean * b;
|
||||
double * value;
|
||||
size_t i;
|
||||
unsigned int * u;
|
||||
|
||||
#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, "delta") == 0)
|
||||
{
|
||||
u = va_arg(properties, unsigned int *);
|
||||
*u = channels->delta;
|
||||
}
|
||||
else 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)
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return "channels";
|
||||
}
|
||||
|
||||
|
||||
/* 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, 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,
|
||||
size_t channel, gdouble value);
|
||||
|
||||
static int _channels_set(MixerControlPlugin * channels, va_list properties)
|
||||
{
|
||||
String const * p;
|
||||
gboolean b;
|
||||
GtkSizeGroup * group;
|
||||
unsigned int u;
|
||||
gdouble value = 0.0;
|
||||
size_t zu;
|
||||
|
||||
while((p = va_arg(properties, String const *)) != NULL)
|
||||
{
|
||||
if(string_compare(p, "bind") == 0)
|
||||
{
|
||||
b = va_arg(properties, gboolean);
|
||||
_set_bind(channels, b);
|
||||
}
|
||||
else if(string_compare(p, "channels") == 0)
|
||||
{
|
||||
zu = va_arg(properties, size_t);
|
||||
if(_set_channels(channels, zu) != 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);
|
||||
_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 if(string_compare(p, "value") == 0)
|
||||
{
|
||||
value = va_arg(properties, gdouble);
|
||||
_set_value(channels, value);
|
||||
}
|
||||
else if(sscanf(p, "value%zu", &zu) == 1)
|
||||
{
|
||||
value = va_arg(properties, gdouble);
|
||||
_set_value_channel(channels, zu, value);
|
||||
}
|
||||
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;
|
||||
}
|
||||
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, size_t cnt)
|
||||
{
|
||||
size_t i;
|
||||
MixerControlChannel * p;
|
||||
gboolean signal = channels->signal;
|
||||
|
||||
/* delete channels as required */
|
||||
if(channels->channels_cnt >= cnt)
|
||||
{
|
||||
for(i = cnt; i < channels->channels_cnt; i++)
|
||||
g_object_unref(channels->channels[i].widget);
|
||||
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)
|
||||
return -1;
|
||||
channels->channels = p;
|
||||
channels->signal = TRUE;
|
||||
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, 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(
|
||||
_channels_on_changed), p);
|
||||
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
|
||||
gtk_widget_show(channels->bind);
|
||||
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)
|
||||
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)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for(i = 0; i < channels->channels_cnt; i++)
|
||||
_set_value_channel(channels, i, value);
|
||||
}
|
||||
|
||||
static void _set_value_channel(MixerControlPlugin * channels,
|
||||
size_t channel, gdouble value)
|
||||
{
|
||||
gboolean signal;
|
||||
|
||||
if(channel >= channels->channels_cnt)
|
||||
return;
|
||||
signal = channels->signal;
|
||||
channels->signal = TRUE;
|
||||
gtk_range_set_value(GTK_RANGE(channels->channels[channel].widget),
|
||||
value);
|
||||
channels->signal = signal;
|
||||
}
|
||||
|
||||
|
||||
/* callbacks */
|
||||
/* channels_on_bind_toggled */
|
||||
static void _channels_on_bind_toggled(gpointer data)
|
||||
{
|
||||
MixerControlPlugin * channels = data;
|
||||
gboolean active;
|
||||
|
||||
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(GtkWidget * widget, gpointer data)
|
||||
{
|
||||
MixerControlChannel * channel = data;
|
||||
MixerControlPlugin * channels = channel->plugin;
|
||||
gdouble value;
|
||||
size_t i;
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
#if GTK_CHECK_VERSION(3, 0, 0)
|
||||
/* channels_on_mute_notify_active */
|
||||
static void _channels_on_mute_notify_active(gpointer data)
|
||||
{
|
||||
MixerControlPlugin * channels = data;
|
||||
|
||||
channels->helper->mixercontrol_set(channels->helper->control);
|
||||
}
|
||||
#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);
|
||||
channels->helper->mixercontrol_set(channels->helper->control);
|
||||
}
|
||||
#endif
|
231
src/controls/mute.c
Normal file
231
src/controls/mute.c
Normal file
|
@ -0,0 +1,231 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2017 Pierre Pronchery <khorben@defora.org> */
|
||||
/* 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 <libintl.h>
|
||||
#include <System/object.h>
|
||||
#include "Mixer/control.h"
|
||||
#define _(string) gettext(string)
|
||||
|
||||
|
||||
/* MixerControlMute */
|
||||
/* private */
|
||||
/* types */
|
||||
struct _MixerControlPlugin
|
||||
{
|
||||
MixerControlPluginHelper * helper;
|
||||
|
||||
GtkWidget * widget;
|
||||
|
||||
GtkWidget * mute;
|
||||
#if !GTK_CHECK_VERSION(3, 0, 0)
|
||||
GtkWidget * mute_image;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/* prototypes */
|
||||
/* control */
|
||||
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);
|
||||
|
||||
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 */
|
||||
/* variables */
|
||||
MixerControlDefinition control =
|
||||
{
|
||||
NULL,
|
||||
"Mute button",
|
||||
NULL,
|
||||
_mute_init,
|
||||
_mute_destroy,
|
||||
_mute_get,
|
||||
_mute_get_type,
|
||||
_mute_get_widget,
|
||||
_mute_set
|
||||
};
|
||||
|
||||
|
||||
/* private */
|
||||
/* functions */
|
||||
/* mute_init */
|
||||
static MixerControlPlugin * _mute_init(MixerControlPluginHelper * helper,
|
||||
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->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)
|
||||
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();
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
return mute;
|
||||
}
|
||||
|
||||
|
||||
/* mute_destroy */
|
||||
static void _mute_destroy(MixerControlPlugin * mute)
|
||||
{
|
||||
object_delete(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)
|
||||
{
|
||||
return "mute";
|
||||
}
|
||||
|
||||
|
||||
/* 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);
|
||||
#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 */
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* callbacks */
|
||||
#if GTK_CHECK_VERSION(3, 0, 0)
|
||||
/* mute_on_notify_active */
|
||||
static void _mute_on_notify_active(gpointer data)
|
||||
{
|
||||
MixerControlPlugin * mute = data;
|
||||
|
||||
mute->helper->mixercontrol_set(mute->helper->control);
|
||||
}
|
||||
#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);
|
||||
mute->helper->mixercontrol_set(mute->helper->control);
|
||||
}
|
||||
#endif
|
39
src/controls/project.conf
Normal file
39
src/controls/project.conf
Normal file
|
@ -0,0 +1,39 @@
|
|||
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)/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
|
302
src/controls/radio.c
Normal file
302
src/controls/radio.c
Normal file
|
@ -0,0 +1,302 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2017 Pierre Pronchery <khorben@defora.org> */
|
||||
/* 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 <stdlib.h>
|
||||
#include <System/object.h>
|
||||
#include "Mixer/control.h"
|
||||
|
||||
|
||||
/* MixerControlRadio */
|
||||
/* private */
|
||||
/* types */
|
||||
typedef struct _MixerControlRadio
|
||||
{
|
||||
MixerControlPlugin * plugin;
|
||||
|
||||
unsigned int value;
|
||||
|
||||
GtkWidget * widget;
|
||||
} MixerControlRadio;
|
||||
|
||||
struct _MixerControlPlugin
|
||||
{
|
||||
MixerControlPluginHelper * helper;
|
||||
|
||||
GtkWidget * widget;
|
||||
|
||||
GSList * group;
|
||||
MixerControlRadio * radios;
|
||||
size_t radios_cnt;
|
||||
};
|
||||
|
||||
|
||||
/* prototypes */
|
||||
/* control */
|
||||
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);
|
||||
|
||||
static int _radio_set(MixerControlPlugin * radio, va_list properties);
|
||||
|
||||
/* callbacks */
|
||||
static void _radio_on_toggled(gpointer data);
|
||||
|
||||
|
||||
/* public */
|
||||
/* variables */
|
||||
MixerControlDefinition control =
|
||||
{
|
||||
NULL,
|
||||
"Radio buttons",
|
||||
NULL,
|
||||
_radio_init,
|
||||
_radio_destroy,
|
||||
_radio_get,
|
||||
_radio_get_type,
|
||||
_radio_get_widget,
|
||||
_radio_set
|
||||
};
|
||||
|
||||
|
||||
/* private */
|
||||
/* functions */
|
||||
/* radio_init */
|
||||
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);
|
||||
gtk_container_set_border_width(GTK_CONTAINER(radio->widget), 4);
|
||||
radio->group = NULL;
|
||||
radio->radios = NULL;
|
||||
radio->radios_cnt = 0;
|
||||
if(_radio_set(radio, properties) != 0)
|
||||
{
|
||||
_radio_destroy(radio);
|
||||
return NULL;
|
||||
}
|
||||
return radio;
|
||||
}
|
||||
|
||||
|
||||
/* radio_destroy */
|
||||
static void _radio_destroy(MixerControlPlugin * radio)
|
||||
{
|
||||
free(radio->radios);
|
||||
object_delete(radio);
|
||||
}
|
||||
|
||||
|
||||
/* accessors */
|
||||
/* radio_get */
|
||||
static unsigned int _get_value(MixerControlPlugin * radio);
|
||||
|
||||
static int _radio_get(MixerControlPlugin * radio, va_list properties)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* radio_get_type */
|
||||
static String const * _radio_get_type(MixerControlPlugin * radio)
|
||||
{
|
||||
return "radio";
|
||||
}
|
||||
|
||||
|
||||
/* radio_get_widget */
|
||||
static GtkWidget * _radio_get_widget(MixerControlPlugin * radio)
|
||||
{
|
||||
return radio->widget;
|
||||
}
|
||||
|
||||
|
||||
/* radio_set */
|
||||
static int _set_label(MixerControlPlugin * radio, unsigned int pos,
|
||||
String const * label);
|
||||
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;
|
||||
unsigned int value;
|
||||
|
||||
while((p = va_arg(properties, String const *)) != NULL)
|
||||
{
|
||||
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;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _set_label(MixerControlPlugin * radio, unsigned int pos,
|
||||
String const * label)
|
||||
{
|
||||
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 >= cnt)
|
||||
{
|
||||
for(i = cnt; i < radio->radios_cnt; i++)
|
||||
g_object_unref(radio->radios[i].widget);
|
||||
radio->radios_cnt = cnt;
|
||||
return 0;
|
||||
}
|
||||
if((p = realloc(radio->radios, sizeof(*p) * cnt)) == NULL)
|
||||
return -1;
|
||||
radio->radios = p;
|
||||
for(i = radio->radios_cnt; i < cnt; i++)
|
||||
{
|
||||
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);
|
||||
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;
|
||||
gtk_widget_show_all(radio->widget);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _set_value(MixerControlPlugin * radio, unsigned int value)
|
||||
{
|
||||
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,
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* callbacks */
|
||||
/* radio_on_toggled */
|
||||
static void _radio_on_toggled(gpointer data)
|
||||
{
|
||||
MixerControlPlugin * radio = data;
|
||||
|
||||
radio->helper->mixercontrol_set(radio->helper->control);
|
||||
}
|
294
src/controls/set.c
Normal file
294
src/controls/set.c
Normal file
|
@ -0,0 +1,294 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2017 Pierre Pronchery <khorben@defora.org> */
|
||||
/* 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 <stdlib.h>
|
||||
#include <System/object.h>
|
||||
#include "Mixer/control.h"
|
||||
|
||||
|
||||
/* MixerControlSet */
|
||||
/* private */
|
||||
/* types */
|
||||
typedef struct _MixerControlSet
|
||||
{
|
||||
MixerControlPlugin * plugin;
|
||||
|
||||
unsigned int value;
|
||||
|
||||
GtkWidget * widget;
|
||||
} MixerControlSet;
|
||||
|
||||
struct _MixerControlPlugin
|
||||
{
|
||||
MixerControlPluginHelper * helper;
|
||||
|
||||
GtkWidget * widget;
|
||||
|
||||
MixerControlSet * sets;
|
||||
size_t sets_cnt;
|
||||
};
|
||||
|
||||
|
||||
/* prototypes */
|
||||
/* control */
|
||||
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);
|
||||
|
||||
static int _set_set(MixerControlPlugin * set, va_list properties);
|
||||
|
||||
/* callbacks */
|
||||
static void _set_on_toggled(gpointer data);
|
||||
|
||||
|
||||
/* public */
|
||||
/* variables */
|
||||
MixerControlDefinition control =
|
||||
{
|
||||
NULL,
|
||||
"Set of values",
|
||||
NULL,
|
||||
_set_init,
|
||||
_set_destroy,
|
||||
_set_get,
|
||||
_set_get_type,
|
||||
_set_get_widget,
|
||||
_set_set
|
||||
};
|
||||
|
||||
|
||||
/* private */
|
||||
/* functions */
|
||||
/* set_init */
|
||||
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);
|
||||
gtk_container_set_border_width(GTK_CONTAINER(set->widget), 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)
|
||||
{
|
||||
free(set->sets);
|
||||
object_delete(set);
|
||||
}
|
||||
|
||||
|
||||
/* accessors */
|
||||
/* set_get */
|
||||
static unsigned int _get_value(MixerControlPlugin * set);
|
||||
|
||||
static int _set_get(MixerControlPlugin * set, va_list properties)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* set_get_type */
|
||||
static String const * _set_get_type(MixerControlPlugin * set)
|
||||
{
|
||||
return "set";
|
||||
}
|
||||
|
||||
|
||||
/* set_get_widget */
|
||||
static GtkWidget * _set_get_widget(MixerControlPlugin * set)
|
||||
{
|
||||
return set->widget;
|
||||
}
|
||||
|
||||
|
||||
/* set_set */
|
||||
static int _set_label(MixerControlPlugin * set, unsigned int pos,
|
||||
String const * label);
|
||||
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;
|
||||
unsigned int value;
|
||||
|
||||
while((p = va_arg(properties, String const *)) != NULL)
|
||||
{
|
||||
if(sscanf(p, "label%u", &u) == 1)
|
||||
{
|
||||
s = va_arg(properties, String const *);
|
||||
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 */
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _set_label(MixerControlPlugin * set, unsigned int pos,
|
||||
String const * label)
|
||||
{
|
||||
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 >= cnt)
|
||||
{
|
||||
for(i = cnt; i < set->sets_cnt; i++)
|
||||
g_object_unref(set->sets[i].widget);
|
||||
set->sets_cnt = cnt;
|
||||
return 0;
|
||||
}
|
||||
if((p = realloc(set->sets, sizeof(*p) * cnt)) == NULL)
|
||||
return -1;
|
||||
set->sets = p;
|
||||
for(i = set->sets_cnt; i < cnt; i++)
|
||||
{
|
||||
p = &set->sets[i];
|
||||
p->plugin = set;
|
||||
p->value = 0;
|
||||
p->widget = gtk_check_button_new();
|
||||
gtk_widget_set_sensitive(p->widget, FALSE);
|
||||
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;
|
||||
gtk_widget_show_all(set->widget);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _set_value(MixerControlPlugin * set, unsigned int value)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* callbacks */
|
||||
/* set_on_toggled */
|
||||
static void _set_on_toggled(gpointer data)
|
||||
{
|
||||
MixerControlPlugin * set = data;
|
||||
|
||||
set->helper->mixercontrol_set(set->helper->control);
|
||||
}
|
1063
src/mixer.c
1063
src/mixer.c
File diff suppressed because it is too large
Load Diff
21
src/mixer.h
21
src/mixer.h
|
@ -1,5 +1,5 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2009-2015 Pierre Pronchery <khorben@defora.org> */
|
||||
/* Copyright (c) 2009-2017 Pierre Pronchery <khorben@defora.org> */
|
||||
/* This file is part of DeforaOS Desktop Mixer */
|
||||
/* All rights reserved.
|
||||
*
|
||||
|
@ -31,7 +31,10 @@
|
|||
#ifndef MIXER_MIXER_H
|
||||
# define MIXER_MIXER_H
|
||||
|
||||
# include <gtk/gtk.h> /* XXX should not be necessary */
|
||||
# include <gtk/gtk.h>
|
||||
# include <System/string.h>
|
||||
# include "control.h"
|
||||
# include "common.h"
|
||||
|
||||
|
||||
/* Mixer */
|
||||
|
@ -50,27 +53,25 @@ typedef struct _MixerProperties
|
|||
char device[16];
|
||||
} MixerProperties;
|
||||
|
||||
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 */
|
||||
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);
|
||||
|
||||
int mixer_refresh(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 */
|
||||
|
|
|
@ -1,24 +1,29 @@
|
|||
subdirs=controls
|
||||
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
|
||||
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,mixer.h,window.h,callbacks.h
|
||||
dist=Makefile,common.h,control.h,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=../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
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2015-2016 Pierre Pronchery <khorben@defora.org> */
|
||||
static char _copyright[] =
|
||||
"Copyright © 2009-2017 Pierre Pronchery <khorben@defora.org>";
|
||||
/* This file is part of DeforaOS Desktop Mixer */
|
||||
|
@ -241,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");
|
||||
|
|
Loading…
Reference in New Issue
Block a user