summaryrefslogtreecommitdiff
path: root/gst-mixer/src
diff options
context:
space:
mode:
Diffstat (limited to 'gst-mixer/src')
-rw-r--r--gst-mixer/src/Makefile.am42
-rw-r--r--gst-mixer/src/Makefile.in648
-rw-r--r--gst-mixer/src/button.c133
-rw-r--r--gst-mixer/src/button.h71
-rw-r--r--gst-mixer/src/element.c595
-rw-r--r--gst-mixer/src/element.h68
-rw-r--r--gst-mixer/src/keys.h39
-rw-r--r--gst-mixer/src/main.c177
-rw-r--r--gst-mixer/src/misc.c72
-rw-r--r--gst-mixer/src/misc.h32
-rw-r--r--gst-mixer/src/preferences.c441
-rw-r--r--gst-mixer/src/preferences.h77
-rw-r--r--gst-mixer/src/track.c647
-rw-r--r--gst-mixer/src/track.h113
-rw-r--r--gst-mixer/src/volume.c552
-rw-r--r--gst-mixer/src/volume.h82
-rw-r--r--gst-mixer/src/window.c435
-rw-r--r--gst-mixer/src/window.h75
18 files changed, 4299 insertions, 0 deletions
diff --git a/gst-mixer/src/Makefile.am b/gst-mixer/src/Makefile.am
new file mode 100644
index 0000000..d85a6b9
--- /dev/null
+++ b/gst-mixer/src/Makefile.am
@@ -0,0 +1,42 @@
+
+if HAVE_SOUND_THEME
+GVC_ST_LIBS = $(SOUND_THEME_LIBS) \
+ $(top_builddir)/sound-theme/libsoundtheme.la
+endif
+
+AM_CPPFLAGS = \
+ $(GSTMIXER_CFLAGS) \
+ $(DISABLE_DEPRECATED) \
+ -I$(top_srcdir)/sound-theme \
+ -DMATELOCALEDIR=\""$(datadir)/locale"\" \
+ -DDATA_DIR=\""$(pkgdatadir)"\" \
+ -DPIX_DIR=\""$(pkgdatadir)/pixmaps"\"
+
+bin_PROGRAMS = mate-volume-control
+
+mate_volume_control_SOURCES = \
+ button.c \
+ element.c \
+ main.c \
+ preferences.c \
+ track.c \
+ volume.c \
+ window.c \
+ misc.c
+
+noinst_HEADERS = \
+ button.h \
+ element.h \
+ keys.h \
+ preferences.h \
+ track.h \
+ volume.h \
+ window.h \
+ misc.h
+
+mate_volume_control_LDFLAGS = \
+ $(GVC_ST_LIBS) \
+ $(GSTMIXER_LIBS)
+
+
+-include $(top_srcdir)/git.mk
diff --git a/gst-mixer/src/Makefile.in b/gst-mixer/src/Makefile.in
new file mode 100644
index 0000000..e5334c7
--- /dev/null
+++ b/gst-mixer/src/Makefile.in
@@ -0,0 +1,648 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+bin_PROGRAMS = mate-volume-control$(EXEEXT)
+subdir = gst-mixer/src
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/as-ac-expand.m4 \
+ $(top_srcdir)/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/m4/as-version.m4 $(top_srcdir)/m4/intltool.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/mate-doc-utils.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/build-aux/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+am_mate_volume_control_OBJECTS = button.$(OBJEXT) element.$(OBJEXT) \
+ main.$(OBJEXT) preferences.$(OBJEXT) track.$(OBJEXT) \
+ volume.$(OBJEXT) window.$(OBJEXT) misc.$(OBJEXT)
+mate_volume_control_OBJECTS = $(am_mate_volume_control_OBJECTS)
+mate_volume_control_LDADD = $(LDADD)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+mate_volume_control_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mate_volume_control_LDFLAGS) \
+ $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(mate_volume_control_SOURCES)
+DIST_SOURCES = $(mate_volume_control_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISABLE_DEPRECATED = @DISABLE_DEPRECATED@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOC_USER_FORMATS = @DOC_USER_FORMATS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLADEUI_CATALOG_DIR = @GLADEUI_CATALOG_DIR@
+GLADEUI_CFLAGS = @GLADEUI_CFLAGS@
+GLADEUI_LIBS = @GLADEUI_LIBS@
+GLADEUI_MODULE_DIR = @GLADEUI_MODULE_DIR@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GMOFILES = @GMOFILES@
+GMP_CFLAGS = @GMP_CFLAGS@
+GMP_LIBS = @GMP_LIBS@
+GMSGFMT = @GMSGFMT@
+GREP = @GREP@
+GSR_CFLAGS = @GSR_CFLAGS@
+GSR_LIBS = @GSR_LIBS@
+GSTMIXER_CFLAGS = @GSTMIXER_CFLAGS@
+GSTMIXER_LIBS = @GSTMIXER_LIBS@
+GSTPROPS_CFLAGS = @GSTPROPS_CFLAGS@
+GSTPROPS_LIBS = @GSTPROPS_LIBS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+HAVE_PULSEAUDIO = @HAVE_PULSEAUDIO@
+HAVE_SOUND_THEME = @HAVE_SOUND_THEME@
+HELP_DIR = @HELP_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MATECC_DESKTOP_DIR = @MATECC_DESKTOP_DIR@
+MATECONFTOOL = @MATECONFTOOL@
+MATECONF_SCHEMA_CONFIG_SOURCE = @MATECONF_SCHEMA_CONFIG_SOURCE@
+MATECONF_SCHEMA_FILE_DIR = @MATECONF_SCHEMA_FILE_DIR@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OMF_DIR = @OMF_DIR@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POFILES = @POFILES@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+PROGRAMS_GSTPROPS = @PROGRAMS_GSTPROPS@
+PULSEAUDIO_CFLAGS = @PULSEAUDIO_CFLAGS@
+PULSEAUDIO_LIBS = @PULSEAUDIO_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOUNDTHEME_CFLAGS = @SOUNDTHEME_CFLAGS@
+SOUNDTHEME_LIBS = @SOUNDTHEME_LIBS@
+SOUND_THEME_CFLAGS = @SOUND_THEME_CFLAGS@
+SOUND_THEME_LIBS = @SOUND_THEME_LIBS@
+STRIP = @STRIP@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+VOLUME_CONTROL_CFLAGS = @VOLUME_CONTROL_CFLAGS@
+VOLUME_CONTROL_LIBS = @VOLUME_CONTROL_LIBS@
+WARN_CFLAGS = @WARN_CFLAGS@
+WARN_CXXFLAGS = @WARN_CXXFLAGS@
+XGETTEXT = @XGETTEXT@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@HAVE_SOUND_THEME_TRUE@GVC_ST_LIBS = $(SOUND_THEME_LIBS) \
+@HAVE_SOUND_THEME_TRUE@ $(top_builddir)/sound-theme/libsoundtheme.la
+
+AM_CPPFLAGS = \
+ $(GSTMIXER_CFLAGS) \
+ $(DISABLE_DEPRECATED) \
+ -I$(top_srcdir)/sound-theme \
+ -DMATELOCALEDIR=\""$(datadir)/locale"\" \
+ -DDATA_DIR=\""$(pkgdatadir)"\" \
+ -DPIX_DIR=\""$(pkgdatadir)/pixmaps"\"
+
+mate_volume_control_SOURCES = \
+ button.c \
+ element.c \
+ main.c \
+ preferences.c \
+ track.c \
+ volume.c \
+ window.c \
+ misc.c
+
+noinst_HEADERS = \
+ button.h \
+ element.h \
+ keys.h \
+ preferences.h \
+ track.h \
+ volume.h \
+ window.h \
+ misc.h
+
+mate_volume_control_LDFLAGS = \
+ $(GVC_ST_LIBS) \
+ $(GSTMIXER_LIBS)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gst-mixer/src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign gst-mixer/src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p || test -f $$p1; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+mate-volume-control$(EXEEXT): $(mate_volume_control_OBJECTS) $(mate_volume_control_DEPENDENCIES)
+ @rm -f mate-volume-control$(EXEEXT)
+ $(AM_V_CCLD)$(mate_volume_control_LINK) $(mate_volume_control_OBJECTS) $(mate_volume_control_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/button.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/element.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/preferences.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/track.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/volume.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/window.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic clean-libtool ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-binPROGRAMS install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-binPROGRAMS
+
+
+-include $(top_srcdir)/git.mk
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/gst-mixer/src/button.c b/gst-mixer/src/button.c
new file mode 100644
index 0000000..5fde995
--- /dev/null
+++ b/gst-mixer/src/button.c
@@ -0,0 +1,133 @@
+/* MATE Volume Control
+ * Copyright (C) 2003-2004 Ronald Bultje <[email protected]>
+ *
+ * button.c: flat toggle button with icons
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include "button.h"
+
+G_DEFINE_TYPE (MateVolumeControlButton, mate_volume_control_button, GTK_TYPE_BUTTON)
+
+
+static void mate_volume_control_button_class_init (MateVolumeControlButtonClass *klass);
+static void mate_volume_control_button_init (MateVolumeControlButton *button);
+static void mate_volume_control_button_dispose (GObject *object);
+
+static void mate_volume_control_button_clicked (GtkButton *button);
+
+static void
+mate_volume_control_button_class_init (MateVolumeControlButtonClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkButtonClass *gtkbutton_class = GTK_BUTTON_CLASS (klass);
+
+ gobject_class->dispose = mate_volume_control_button_dispose;
+ gtkbutton_class->clicked = mate_volume_control_button_clicked;
+}
+
+static void
+mate_volume_control_button_init (MateVolumeControlButton *button)
+{
+ button->active_icon = NULL;
+ button->inactive_icon = NULL;
+
+ button->active = FALSE;
+}
+
+static void
+mate_volume_control_button_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (mate_volume_control_button_parent_class)->dispose (object);
+}
+
+GtkWidget *
+mate_volume_control_button_new (gchar *active_icon,
+ gchar *inactive_icon,
+ gchar *msg)
+{
+ MateVolumeControlButton *button;
+ GtkWidget *image;
+
+ button = g_object_new (MATE_VOLUME_CONTROL_TYPE_BUTTON, NULL);
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+ button->active_icon = active_icon;
+ button->inactive_icon = inactive_icon;
+
+ image = gtk_image_new ();
+ gtk_container_add (GTK_CONTAINER (button), image);
+ gtk_widget_show (image);
+ button->image = GTK_IMAGE (image);
+ gtk_button_clicked (GTK_BUTTON (button));
+
+ gtk_widget_set_tooltip_text (GTK_WIDGET (button), g_strdup (msg));
+
+ return GTK_WIDGET (button);
+}
+
+gboolean
+mate_volume_control_button_get_active (MateVolumeControlButton *button)
+{
+ return button->active;
+}
+
+void
+mate_volume_control_button_set_active (MateVolumeControlButton *button,
+ gboolean active)
+{
+ if (button->active != active)
+ gtk_button_clicked (GTK_BUTTON (button));
+}
+
+static void
+mate_volume_control_button_clicked (GtkButton *_button)
+{
+ MateVolumeControlButton *button = MATE_VOLUME_CONTROL_BUTTON (_button);
+
+ button->active = !button->active;
+
+ if (strstr (button->active_icon, ".png")) {
+ gchar *filename;
+ GdkPixbuf *pixbuf;
+
+ if (button->active)
+ filename = g_build_filename (PIX_DIR, button->active_icon, NULL);
+ else
+ filename = g_build_filename (PIX_DIR, button->inactive_icon, NULL);
+
+ pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
+ gtk_image_set_from_pixbuf (button->image, pixbuf);
+ g_object_unref (pixbuf);
+ g_free (filename);
+ } else {
+ if (button->active) {
+ gtk_image_set_from_icon_name (button->image, button->active_icon,
+ GTK_ICON_SIZE_MENU);
+ } else {
+ gtk_image_set_from_icon_name (button->image, button->inactive_icon,
+ GTK_ICON_SIZE_MENU);
+ }
+ }
+}
diff --git a/gst-mixer/src/button.h b/gst-mixer/src/button.h
new file mode 100644
index 0000000..6f8d0a7
--- /dev/null
+++ b/gst-mixer/src/button.h
@@ -0,0 +1,71 @@
+/* MATE Button Control
+ * Copyright (C) 2003-2004 Ronald Bultje <[email protected]>
+ *
+ * button.h: flat toggle button with images
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GVC_BUTTON_H__
+#define __GVC_BUTTON_H__
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define MATE_VOLUME_CONTROL_TYPE_BUTTON \
+ (mate_volume_control_button_get_type ())
+#define MATE_VOLUME_CONTROL_BUTTON(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), MATE_VOLUME_CONTROL_TYPE_BUTTON, \
+ MateVolumeControlButton))
+#define MATE_VOLUME_CONTROL_BUTTON_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), MATE_VOLUME_CONTROL_TYPE_BUTTON, \
+ MateVolumeControlButtonClass))
+#define MATE_VOLUME_CONTROL_IS_BUTTON(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MATE_VOLUME_CONTROL_TYPE_BUTTON))
+#define MATE_VOLUME_CONTROL_IS_BUTTON_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), MATE_VOLUME_CONTROL_TYPE_BUTTON))
+
+typedef struct _MateVolumeControlButton {
+ GtkButton parent;
+
+ /* stock icons */
+ gchar *active_icon,
+ *inactive_icon;
+
+ /* state */
+ gboolean active;
+
+ /* image */
+ GtkImage *image;
+} MateVolumeControlButton;
+
+typedef struct _MateVolumeControlButtonClass {
+ GtkButtonClass klass;
+} MateVolumeControlButtonClass;
+
+GType mate_volume_control_button_get_type (void);
+GtkWidget * mate_volume_control_button_new (gchar *active_icon,
+ gchar *inactive_icon,
+ gchar *msg);
+gboolean mate_volume_control_button_get_active (MateVolumeControlButton *button);
+void mate_volume_control_button_set_active (MateVolumeControlButton *button,
+ gboolean active);
+
+G_END_DECLS
+
+#endif /* __GVC_BUTTON_H__ */
diff --git a/gst-mixer/src/element.c b/gst-mixer/src/element.c
new file mode 100644
index 0000000..a190582
--- /dev/null
+++ b/gst-mixer/src/element.c
@@ -0,0 +1,595 @@
+/* MATE Volume Control
+ * Copyright (C) 2003-2004 Ronald Bultje <[email protected]>
+ *
+ * element.c: widget representation of a single mixer element
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "element.h"
+#include "keys.h"
+#include "preferences.h"
+#include "track.h"
+#include "misc.h"
+#ifdef HAVE_SOUND_THEME
+#include "gvc-sound-theme-chooser.h"
+#endif
+
+G_DEFINE_TYPE (MateVolumeControlElement, mate_volume_control_element, GTK_TYPE_NOTEBOOK)
+
+static void mate_volume_control_element_class_init (MateVolumeControlElementClass *klass);
+static void mate_volume_control_element_init (MateVolumeControlElement *el);
+static void mate_volume_control_element_dispose (GObject *object);
+
+static void cb_mateconf (MateConfClient *client,
+ guint connection_id,
+ MateConfEntry *entry,
+ gpointer data);
+
+
+static void
+mate_volume_control_element_class_init (MateVolumeControlElementClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->dispose = mate_volume_control_element_dispose;
+}
+
+static void
+mate_volume_control_element_init (MateVolumeControlElement *el)
+{
+ el->client = NULL;
+ el->mixer = NULL;
+}
+
+GtkWidget *
+mate_volume_control_element_new (MateConfClient *client)
+{
+ MateVolumeControlElement *el;
+
+ /* element */
+ el = g_object_new (MATE_VOLUME_CONTROL_TYPE_ELEMENT, NULL);
+ el->client = g_object_ref (G_OBJECT (client));
+
+ mateconf_client_add_dir (el->client, MATE_VOLUME_CONTROL_KEY_DIR,
+ MATECONF_CLIENT_PRELOAD_RECURSIVE, NULL);
+ mateconf_client_notify_add (el->client, MATE_VOLUME_CONTROL_KEY_DIR,
+ cb_mateconf, el, NULL, NULL);
+
+ return GTK_WIDGET (el);
+}
+
+static void
+mate_volume_control_element_dispose (GObject *object)
+{
+ MateVolumeControlElement *el = MATE_VOLUME_CONTROL_ELEMENT (object);
+
+ if (el->client) {
+ g_object_unref (G_OBJECT (el->client));
+ el->client = NULL;
+ }
+
+ if (el->mixer) {
+ /* remove g_timeout_add() mainloop handlers */
+ mate_volume_control_element_change (el, NULL);
+ gst_element_set_state (GST_ELEMENT (el->mixer), GST_STATE_NULL);
+ gst_object_unref (GST_OBJECT (el->mixer));
+ el->mixer = NULL;
+ }
+
+ G_OBJECT_CLASS (mate_volume_control_element_parent_class)->dispose (object);
+}
+
+/*
+ * Checks if we want to show the track by default ("whitelist").
+ */
+
+gboolean
+mate_volume_control_element_whitelist (GstMixer *mixer,
+ GstMixerTrack *track)
+{
+ gint i, pos;
+ gboolean found = FALSE;
+
+ /* Yes this is a hack. */
+ static struct {
+ gchar *label;
+ gboolean done;
+ } list[] = {
+
+/* Translator comment: the names below are a whitelist for which volume
+ * controls to show by default. Make sure that those match the translations
+ * of GStreamer-plugins' ALSA/OSS plugins. */
+ { "cd", FALSE },
+ { "line", FALSE },
+ { "mic", FALSE },
+ { "pcm", FALSE },
+ { "headphone", FALSE },
+ { "speaker", FALSE },
+ { "volume", FALSE },
+ { "master", FALSE },
+ { "digital output", FALSE },
+ { "recording", FALSE },
+ { "front", FALSE },
+ { NULL, FALSE }
+ };
+
+ /*
+ * When the user changes devices, it is necessary to reset the whitelist
+ * to a good default state. This fixes bugs LP:345645, 576022
+ */
+ if (track == NULL)
+ {
+ for (i = 0; list[i].label != NULL; i++)
+ list[i].done = FALSE;
+ return TRUE;
+ }
+
+ /* honor the mixer supplied hints about whitelisting if available */
+ if (gst_mixer_get_mixer_flags (GST_MIXER (mixer)) & GST_MIXER_FLAG_HAS_WHITELIST) {
+ if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_WHITELIST)) {
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+ }
+
+ for (i = 0; !found && list[i].label != NULL; i++) {
+ gchar *label_l = NULL;
+
+ if (list[i].done)
+ continue;
+
+ /* make case insensitive */
+ if (g_object_class_find_property (G_OBJECT_GET_CLASS (track), "untranslated-label"))
+ g_object_get (track, "untranslated-label", &label_l, NULL);
+ if (label_l == NULL)
+ g_object_get (track, "label", &label_l, NULL);
+ for (pos = 0; label_l[pos] != '\0'; pos++)
+ label_l[pos] = g_ascii_tolower (label_l[pos]);
+
+ if (g_strrstr (label_l, list[i].label) != NULL) {
+ found = TRUE;
+ list[i].done = TRUE;
+ }
+ g_free (label_l);
+ }
+
+ return found;
+}
+
+/*
+ * Hide/show notebook page.
+ */
+
+static void
+update_tab_visibility (MateVolumeControlElement *el, gint page, gint tabnum)
+{
+ const GList *item;
+ gboolean visible = FALSE;
+ GtkWidget *t;
+
+ for (item = gst_mixer_list_tracks (el->mixer);
+ item != NULL; item = item->next) {
+ GstMixerTrack *track = item->data;
+ MateVolumeControlTrack *trkw =
+ g_object_get_data (G_OBJECT (track), "mate-volume-control-trkw");
+
+ if (get_page_num (el->mixer, track) == page && trkw->visible) {
+ visible = TRUE;
+ break;
+ }
+ }
+
+ t = gtk_notebook_get_nth_page (GTK_NOTEBOOK (el), tabnum);
+ if (visible)
+ gtk_widget_show (t);
+ else
+ gtk_widget_hide (t);
+}
+
+static void
+cb_notify_message (GstBus *bus, GstMessage *message, gpointer data)
+{
+ MateVolumeControlElement *el = data;
+ GstMixerMessageType type;
+ MateVolumeControlTrack *trkw;
+ GstMixerTrack *track = NULL;
+ GstMixerOptions *options = NULL;
+
+ if (GST_MESSAGE_SRC (message) != GST_OBJECT (el->mixer)) {
+ /* not from our mixer - can't update anything anyway */
+ return;
+ }
+
+ /* This code only calls refresh if the first_track changes, because the
+ * refresh code only retrieves the current value from that track anyway */
+ type = gst_mixer_message_get_type (message);
+ if (type == GST_MIXER_MESSAGE_MUTE_TOGGLED) {
+ gst_mixer_message_parse_mute_toggled (message, &track, NULL);
+ } else if (type == GST_MIXER_MESSAGE_VOLUME_CHANGED) {
+ gst_mixer_message_parse_volume_changed (message, &track, NULL, NULL);
+ } else if (type == GST_MIXER_MESSAGE_OPTION_CHANGED) {
+ gst_mixer_message_parse_option_changed (message, &options, NULL);
+ track = GST_MIXER_TRACK (options);
+ } else {
+ return;
+ }
+
+ trkw = g_object_get_data (G_OBJECT (track),
+ "mate-volume-control-trkw");
+
+ mate_volume_control_track_update (trkw);
+}
+
+/*
+ * Change the element. Basically recreates this object internally.
+ */
+
+void
+mate_volume_control_element_change (MateVolumeControlElement *el,
+ GstElement *element)
+{
+ struct {
+ GtkWidget *page, *old_sep, *new_sep, *flagbuttonbox;
+ gboolean use;
+ gint pos, height, width;
+ MateVolumeControlTrack * (* get_track_widget) (GtkTable *table,
+ gint tab_pos,
+ GstMixer *mixer,
+ GstMixerTrack *track,
+ GtkWidget *left_sep,
+ GtkWidget *right_sep,
+ GtkWidget *flagbox);
+
+ } content[4] = {
+ { NULL, NULL, NULL, NULL, FALSE, 0, 5, 1,
+ mate_volume_control_track_add_playback },
+ { NULL, NULL, NULL, NULL, FALSE, 0, 5, 1,
+ mate_volume_control_track_add_recording },
+ { NULL, NULL, NULL, NULL, FALSE, 0, 1, 3,
+ mate_volume_control_track_add_playback },
+ { NULL, NULL, NULL, NULL, FALSE, 0, 1, 3,
+ mate_volume_control_track_add_option }
+ };
+ static gboolean theme_page = FALSE;
+ const GList *item;
+ GstMixer *mixer;
+ GstBus *bus;
+ gint i;
+
+ /* remove old pages, but not the "Sound Theme" page */
+ i = 0;
+ if (theme_page)
+ i = 1;
+
+ while (gtk_notebook_get_n_pages (GTK_NOTEBOOK (el)) > i) {
+ gtk_notebook_remove_page (GTK_NOTEBOOK (el), 0);
+ }
+
+ /* take/put reference */
+ if (el->mixer) {
+ for (item = gst_mixer_list_tracks (el->mixer);
+ item != NULL; item = item->next) {
+ GstMixerTrack *track = item->data;
+ MateVolumeControlTrack *trkw;
+
+ trkw = g_object_get_data (G_OBJECT (track),
+ "mate-volume-control-trkw");
+ g_object_set_data (G_OBJECT (track), "mate-volume-control-trkw", NULL);
+ mate_volume_control_track_free (trkw);
+ }
+ }
+ if (!element)
+ return;
+
+ g_return_if_fail (GST_IS_MIXER (element));
+ mixer = GST_MIXER (element);
+ gst_object_replace ((GstObject **) &el->mixer, GST_OBJECT (element));
+
+ /* Bus for notifications */
+ if (GST_ELEMENT_BUS (mixer) == NULL) {
+ bus = gst_bus_new ();
+ gst_bus_add_signal_watch (bus);
+ g_signal_connect (G_OBJECT (bus), "message::element",
+ (GCallback) cb_notify_message, el);
+ gst_element_set_bus (GST_ELEMENT (mixer), bus);
+ }
+
+ /* content pages */
+ for (i = 0; i < 4; i++) {
+ content[i].page = gtk_table_new (content[i].width, content[i].height, FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (content[i].page), 6);
+ if (i >= 2)
+ gtk_table_set_row_spacings (GTK_TABLE (content[i].page), 6);
+ gtk_table_set_col_spacings (GTK_TABLE (content[i].page), 6);
+ content[i].flagbuttonbox = NULL;
+ }
+
+ /* show */
+ mate_volume_control_element_whitelist (el->mixer, NULL);
+ for (item = gst_mixer_list_tracks (el->mixer);
+ item != NULL; item = item->next) {
+ GstMixerTrack *track = item->data;
+ MateVolumeControlTrack *trkw;
+ gchar *key;
+ const MateConfValue *value;
+ gboolean active;
+
+ i = get_page_num (el->mixer, track);
+
+ /* FIXME:
+ * - do not create separator if there is no more track
+ * _of this type_. We currently destroy it at the
+ * end, so it's not critical, but not nice either.
+ */
+ if (i == 3) {
+ content[i].new_sep = gtk_hseparator_new ();
+ } else if (i < 2) {
+ content[i].new_sep = gtk_vseparator_new ();
+ } else {
+ content[i].new_sep = NULL;
+ }
+
+ /* visible? */
+ active = mate_volume_control_element_whitelist (mixer, track);
+ key = get_mateconf_key (el->mixer, track);
+ if ((value = mateconf_client_get (el->client, key, NULL)) != NULL &&
+ value->type == MATECONF_VALUE_BOOL) {
+ active = mateconf_value_get_bool (value);
+ }
+ g_free (key);
+
+ /* Show left separator if we're not the first track */
+ if (active && content[i].use && content[i].old_sep) {
+
+ /* Do not show separator for switches/options on Playback/Recording tab */
+ if (i < 2 && track->num_channels != 0) {
+ gtk_widget_show (content[i].old_sep);
+ }
+ }
+
+ /* widget */
+ trkw = content[i].get_track_widget (GTK_TABLE (content[i].page),
+ content[i].pos++, el->mixer, track,
+ content[i].old_sep, content[i].new_sep,
+ content[i].flagbuttonbox);
+ mate_volume_control_track_show (trkw, active);
+
+ /* Only the first trkw on the page will return flagbuttonbox */
+ if (trkw->flagbuttonbox != NULL)
+ content[i].flagbuttonbox = trkw->flagbuttonbox;
+ g_object_set_data (G_OBJECT (track),
+ "mate-volume-control-trkw", trkw);
+
+ /* separator */
+ if (item->next != NULL && content[i].new_sep) {
+ if (i >= 2) {
+ gtk_table_attach (GTK_TABLE (content[i].page), content[i].new_sep,
+ 0, 3, content[i].pos, content[i].pos + 1,
+ GTK_SHRINK | GTK_FILL, 0, 0, 0);
+ } else {
+ gtk_table_attach (GTK_TABLE (content[i].page), content[i].new_sep,
+ content[i].pos, content[i].pos + 1, 0, 6,
+ 0, GTK_SHRINK | GTK_FILL, 0, 0);
+ }
+ content[i].pos++;
+ }
+
+ content[i].old_sep = content[i].new_sep;
+
+ if (active) {
+ content[i].use = TRUE;
+ }
+ }
+
+ /* show - need to build the tabs backwards so that deleting the "Sound Theme"
+ * page can be avoided.
+ */
+ for (i = 3; i >= 0; i--) {
+ GtkWidget *label, *view, *viewport;
+ GtkAdjustment *hadjustment, *vadjustment;
+
+ /* don't show last separator */
+ if (content[i].new_sep)
+ gtk_widget_destroy (content[i].new_sep);
+
+ /* viewport for lots of tracks */
+ view = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view),
+ i >= 2 ? GTK_POLICY_NEVER :
+ GTK_POLICY_AUTOMATIC,
+ i >= 2 ? GTK_POLICY_AUTOMATIC :
+ GTK_POLICY_NEVER);
+
+ hadjustment = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (view));
+ vadjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (view));
+ viewport = gtk_viewport_new (hadjustment, vadjustment);
+ gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport), GTK_SHADOW_NONE);
+
+ if (content[i].flagbuttonbox != NULL) {
+ GtkWidget *vbox = NULL;
+ GtkWidget *hbox = NULL;
+ GtkWidget *hbox2 = NULL;
+ GtkWidget *separator = NULL;
+
+ if (i < 2) {
+ vbox = gtk_vbox_new (FALSE, 0);
+ hbox = gtk_hbox_new (FALSE, 6);
+ hbox2 = gtk_hbox_new (FALSE, 6);
+ separator = gtk_hseparator_new ();
+ gtk_box_pack_start (GTK_BOX (vbox), content[i].page, TRUE, TRUE, 6);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (hbox2), separator, TRUE, TRUE, 6);
+ gtk_box_pack_start (GTK_BOX (hbox), content[i].flagbuttonbox, TRUE,
+ FALSE, 6);
+ } else {
+ /* orientation is rotated for these ... */
+ vbox = gtk_hbox_new (FALSE, 0);
+ hbox = gtk_vbox_new (FALSE, 0);
+ hbox2 = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), content[i].page, FALSE, FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (hbox), content[i].flagbuttonbox, TRUE,
+ FALSE, 6);
+ }
+ gtk_widget_show_all (hbox2);
+ gtk_widget_show (content[i].flagbuttonbox);
+ gtk_widget_show (hbox);
+ gtk_widget_show (content[i].page);
+ gtk_widget_show (vbox);
+
+ gtk_container_add (GTK_CONTAINER (viewport), vbox);
+ gtk_container_add (GTK_CONTAINER (view), viewport);
+ } else {
+ gtk_container_add (GTK_CONTAINER (viewport), content[i].page);
+ gtk_container_add (GTK_CONTAINER (view), viewport);
+ }
+
+ label = gtk_label_new (get_page_description (i));
+ gtk_notebook_prepend_page (GTK_NOTEBOOK (el), view, label);
+ gtk_widget_show (content[i].page);
+ gtk_widget_show (viewport);
+ gtk_widget_show (view);
+ gtk_widget_show (label);
+
+ update_tab_visibility (el, i, 0);
+ }
+
+ /* refresh fix */
+ for (i = gtk_notebook_get_n_pages (GTK_NOTEBOOK (el)) - 1;
+ i >= 0; i--) {
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (el), i);
+ }
+
+#ifdef HAVE_SOUND_THEME
+ /* Add tab for managing themes */
+ if (!theme_page) {
+ theme_page = TRUE;
+ GtkWidget *label, *view, *viewport, *sound_theme_chooser, *vbox;
+ GtkAdjustment *hadjustment, *vadjustment;
+
+ label = gtk_label_new (_("Sound Theme"));
+
+ view = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+
+ hadjustment = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (view));
+ vadjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (view));
+ viewport = gtk_viewport_new (hadjustment, vadjustment);
+ gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport), GTK_SHADOW_NONE);
+ gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport), GTK_SHADOW_NONE);
+
+ sound_theme_chooser = gvc_sound_theme_chooser_new ();
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), sound_theme_chooser, TRUE, TRUE, 6);
+ gtk_container_add (GTK_CONTAINER (viewport), vbox);
+ gtk_container_add (GTK_CONTAINER (view), viewport);
+
+ gtk_widget_show_all (vbox);
+ gtk_widget_show (sound_theme_chooser);
+ gtk_widget_show (viewport);
+ gtk_widget_show (view);
+ gtk_widget_show (label);
+
+ gtk_notebook_append_page (GTK_NOTEBOOK (el), view, label);
+ }
+#endif
+}
+
+/*
+ * MateConf callback.
+ */
+
+static void
+cb_mateconf (MateConfClient *client,
+ guint connection_id,
+ MateConfEntry *entry,
+ gpointer data)
+{
+ MateVolumeControlElement *el = MATE_VOLUME_CONTROL_ELEMENT (data);
+ gchar *keybase = get_mateconf_key (el->mixer, NULL);
+
+ if (!strncmp (mateconf_entry_get_key (entry),
+ keybase, strlen (keybase))) {
+ const GList *item;
+
+ for (item = gst_mixer_list_tracks (el->mixer);
+ item != NULL; item = item->next) {
+ GstMixerTrack *track = item->data;
+ MateVolumeControlTrack *trkw =
+ g_object_get_data (G_OBJECT (track), "mate-volume-control-trkw");
+ gchar *key = get_mateconf_key (el->mixer, track);
+
+ g_return_if_fail (mateconf_entry_get_key (entry) != NULL);
+ g_return_if_fail (key != NULL);
+
+ if (g_str_equal (mateconf_entry_get_key (entry), key)) {
+ MateConfValue *value = mateconf_entry_get_value (entry);
+
+ if (value->type == MATECONF_VALUE_BOOL) {
+ gboolean active = mateconf_value_get_bool (value),
+ first[4] = { TRUE, TRUE, TRUE, TRUE };
+ gint n, page = get_page_num (el->mixer, track);
+
+ mate_volume_control_track_show (trkw, active);
+
+ /* separators */
+ for (item = gst_mixer_list_tracks (el->mixer);
+ item != NULL; item = item->next) {
+ GstMixerTrack *track = item->data;
+ MateVolumeControlTrack *trkw =
+ g_object_get_data (G_OBJECT (track), "mate-volume-control-trkw");
+
+ n = get_page_num (el->mixer, track);
+ if (trkw->visible && !first[n]) {
+ if (trkw->left_separator) {
+ if (n < 2 && track->num_channels == 0) {
+ gtk_widget_hide (trkw->left_separator);
+ } else {
+ gtk_widget_show (trkw->left_separator);
+ }
+ }
+ } else {
+ if (trkw->left_separator)
+ gtk_widget_hide (trkw->left_separator);
+ }
+
+ if (trkw->visible && first[n])
+ first[n] = FALSE;
+ }
+ update_tab_visibility (el, page, page);
+ break;
+ }
+ }
+
+ g_free (key);
+ }
+ }
+ g_free (keybase);
+}
diff --git a/gst-mixer/src/element.h b/gst-mixer/src/element.h
new file mode 100644
index 0000000..bb224a0
--- /dev/null
+++ b/gst-mixer/src/element.h
@@ -0,0 +1,68 @@
+/* MATE Volume Control
+ * Copyright (C) 2003-2004 Ronald Bultje <[email protected]>
+ *
+ * element.h: widget representation of a single mixer element
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GVC_ELEMENT_H__
+#define __GVC_ELEMENT_H__
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <mateconf/mateconf-client.h>
+#include <gst/interfaces/mixer.h>
+
+G_BEGIN_DECLS
+
+#define MATE_VOLUME_CONTROL_TYPE_ELEMENT \
+ (mate_volume_control_element_get_type ())
+#define MATE_VOLUME_CONTROL_ELEMENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), MATE_VOLUME_CONTROL_TYPE_ELEMENT, \
+ MateVolumeControlElement))
+#define MATE_VOLUME_CONTROL_ELEMENT_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), MATE_VOLUME_CONTROL_TYPE_ELEMENT, \
+ MateVolumeControlElementClass))
+#define MATE_VOLUME_CONTROL_IS_ELEMENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MATE_VOLUME_CONTROL_TYPE_ELEMENT))
+#define MATE_VOLUME_CONTROL_IS_ELEMENT_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), MATE_VOLUME_CONTROL_TYPE_ELEMENT))
+
+typedef struct _MateVolumeControlElement {
+ GtkNotebook parent;
+
+ /* current element that we're working on */
+ GstMixer *mixer;
+
+ /* mateconf client inherited from our parent */
+ MateConfClient *client;
+} MateVolumeControlElement;
+
+typedef struct _MateVolumeControlElementClass {
+ GtkNotebookClass klass;
+} MateVolumeControlElementClass;
+
+GType mate_volume_control_element_get_type (void);
+GtkWidget * mate_volume_control_element_new (MateConfClient *client);
+void mate_volume_control_element_change (MateVolumeControlElement *el,
+ GstElement *element);
+gboolean mate_volume_control_element_whitelist (GstMixer *mixer,
+ GstMixerTrack *track);
+
+G_END_DECLS
+
+#endif /* __GVC_ELEMENT_H__ */
diff --git a/gst-mixer/src/keys.h b/gst-mixer/src/keys.h
new file mode 100644
index 0000000..809d507
--- /dev/null
+++ b/gst-mixer/src/keys.h
@@ -0,0 +1,39 @@
+/* MATE Volume Control
+ * Copyright (C) 2003-2004 Ronald Bultje <[email protected]>
+ *
+ * keys.h: MateConf key macros
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GVC_KEYS_H__
+#define __GVC_KEYS_H__
+
+G_BEGIN_DECLS
+
+#define MATE_VOLUME_CONTROL_KEY_DIR \
+ "/apps/mate-volume-control"
+#define MATE_VOLUME_CONTROL_KEY(key) \
+ MATE_VOLUME_CONTROL_KEY_DIR "/" key
+
+#define MATE_VOLUME_CONTROL_KEY_ACTIVE_ELEMENT \
+ MATE_VOLUME_CONTROL_KEY ("active-element")
+#define PREF_UI_WINDOW_WIDTH MATE_VOLUME_CONTROL_KEY ("ui/window_width")
+#define PREF_UI_WINDOW_HEIGHT MATE_VOLUME_CONTROL_KEY ("ui/window_height")
+
+G_END_DECLS
+
+#endif /* __GVC_KEYS_H__ */
diff --git a/gst-mixer/src/main.c b/gst-mixer/src/main.c
new file mode 100644
index 0000000..f039af8
--- /dev/null
+++ b/gst-mixer/src/main.c
@@ -0,0 +1,177 @@
+/* MATE Volume Control
+ * Copyright (C) 2003-2004 Ronald Bultje <[email protected]>
+ *
+ * main.c: intialization, window setup
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <getopt.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gst/gst.h>
+#include <gst/audio/mixerutils.h>
+
+#include "keys.h"
+#include "window.h"
+
+static gchar* page = NULL;
+static GOptionEntry entries[] =
+{
+ { "page", 'p', 0, G_OPTION_ARG_STRING, &page, N_("Startup page"), "playback|recording|switches|options" }
+};
+
+/*
+ * Probe for mixer elements. Set up GList * with elements,
+ * where each element has a GObject data node set of the
+ * name "mate-volume-control-name" with the value being
+ * the human-readable name of the element.
+ *
+ * All elements in the returned GList * are in state
+ * GST_STATE_NULL.
+ */
+
+static gboolean
+mixer_filter_func (GstMixer * mixer, gpointer user_data)
+{
+ GstElementFactory *factory;
+ const gchar *long_name;
+ gchar *devname = NULL;
+ gchar *name;
+ gint *p_count = (gint *) user_data;
+
+ /* fetch name */
+ if (g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (mixer)),
+ "device-name")) {
+ g_object_get (mixer, "device-name", &devname, NULL);
+ GST_DEBUG ("device name: %s", GST_STR_NULL (devname));
+ } else {
+ devname = NULL;
+ GST_DEBUG ("device name unknown, no 'device-name' property");
+ }
+
+ factory = gst_element_get_factory (GST_ELEMENT (mixer));
+ long_name = gst_element_factory_get_longname (factory);
+
+ if (devname) {
+ name = g_strdup_printf ("%s (%s)", devname, long_name);
+ g_free (devname);
+ } else {
+ gchar *title;
+
+ *p_count += 1;
+
+ title = g_strdup_printf (_("Unknown Volume Control %d"), *p_count);
+ name = g_strdup_printf ("%s (%s)", title, long_name);
+ g_free (title);
+ }
+
+ g_object_set_data_full (G_OBJECT (mixer),
+ "mate-volume-control-name",
+ name,
+ (GDestroyNotify) g_free);
+
+ GST_DEBUG ("Adding '%s' to list of available mixers", name);
+
+ gst_element_set_state (GST_ELEMENT (mixer), GST_STATE_NULL);
+
+ return TRUE; /* add mixer to list */
+}
+
+static GList *
+create_mixer_collection (void)
+{
+ GList *mixer_list;
+ gint counter = 0;
+
+ mixer_list = gst_audio_default_registry_mixer_filter (mixer_filter_func,
+ FALSE,
+ &counter);
+
+ return mixer_list;
+}
+
+static void
+cb_destroy (GtkWidget *widget,
+ gpointer data)
+{
+ gtk_main_quit ();
+}
+
+static void
+cb_check_resize (GtkContainer *container,
+ gpointer user_data)
+{
+ MateConfClient *client;
+ gint width, height;
+
+ client = mateconf_client_get_default();
+ gtk_window_get_size (GTK_WINDOW (container), &width, &height);
+ mateconf_client_set_int (client, PREF_UI_WINDOW_WIDTH, width, NULL);
+ mateconf_client_set_int (client, PREF_UI_WINDOW_HEIGHT, height, NULL);
+}
+
+gint
+main (gint argc,
+ gchar *argv[])
+{
+ GOptionContext *ctx;
+ GtkWidget *win;
+ GList *elements;
+
+ /* i18n */
+ bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ g_thread_init (NULL);
+ ctx = g_option_context_new ("mate-volume-control");
+ g_option_context_add_main_entries(ctx, entries, GETTEXT_PACKAGE);
+ g_option_context_add_group (ctx, gst_init_get_option_group ());
+ g_option_context_parse(ctx, &argc, &argv, NULL);
+ g_option_context_free(ctx);
+
+ gtk_init (&argc, &argv);
+
+ gtk_window_set_default_icon_name ("multimedia-volume-control");
+
+ if (!(elements = create_mixer_collection ())) {
+ win = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ _("No volume control GStreamer plugins and/or devices found."));
+ gtk_widget_show (win);
+ gtk_dialog_run (GTK_DIALOG (win));
+ gtk_widget_destroy (win);
+ return -1;
+ }
+
+ /* window contains everything automagically */
+ win = mate_volume_control_window_new (elements);
+ if (page != NULL)
+ mate_volume_control_window_set_page(win, page);
+ g_signal_connect (win, "destroy", G_CALLBACK (cb_destroy), NULL);
+ g_signal_connect (win, "check_resize", G_CALLBACK (cb_check_resize), NULL);
+
+ gtk_widget_show (win);
+ gtk_main ();
+
+ return 0;
+}
diff --git a/gst-mixer/src/misc.c b/gst-mixer/src/misc.c
new file mode 100644
index 0000000..4ede2c6
--- /dev/null
+++ b/gst-mixer/src/misc.c
@@ -0,0 +1,72 @@
+/* MATE Volume Control
+ * Copyright (C) 2003-2004 Ronald Bultje <[email protected]>
+ *
+ * misc.c: miscelaneous functions
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gst/interfaces/mixer.h>
+#include <gst/interfaces/mixertrack.h>
+#include <gst/interfaces/mixeroptions.h>
+
+#include "misc.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+gint get_page_num (GstMixer *mixer, GstMixerTrack *track)
+{
+ /* is it possible to have a track that does input and output? */
+ g_assert (! (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_INPUT)
+ && GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_OUTPUT)));
+
+ if ((gst_mixer_get_mixer_flags (GST_MIXER (mixer)) &
+ GST_MIXER_FLAG_GROUPING) == 0) {
+ /* old style grouping, only volume sliders on the first two pages */
+ if (GST_IS_MIXER_OPTIONS (track))
+ return 3;
+ else if (track->num_channels == 0)
+ return 2;
+ }
+ if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_INPUT))
+ return 1;
+ else if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_OUTPUT))
+ return 0;
+ else if (GST_IS_MIXER_OPTIONS (track))
+ return 3;
+ else
+ return 2;
+
+ g_assert_not_reached ();
+}
+
+gchar *get_page_description (gint n)
+{
+ /* needs i18n work */
+ switch (n) {
+ case 0:
+ return _("Playback");
+ case 1:
+ return _("Recording");
+ case 2:
+ return _("Switches");
+ case 3:
+ return _("Options");
+ }
+
+ g_assert_not_reached ();
+}
diff --git a/gst-mixer/src/misc.h b/gst-mixer/src/misc.h
new file mode 100644
index 0000000..722ba56
--- /dev/null
+++ b/gst-mixer/src/misc.h
@@ -0,0 +1,32 @@
+/* MATE Volume Control
+ * Copyright (C) 2003-2004 Ronald Bultje <[email protected]>
+ *
+ * element.h: widget representation of a single mixer element
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_MIXER_MISC_H__
+#define __GST_MIXER_MISC_H__
+
+#include <glib.h>
+#include <gst/interfaces/mixertrack.h>
+
+gint get_page_num (GstMixer *mixer, GstMixerTrack *track);
+
+gchar *get_page_description (gint n);
+
+#endif /* __GST_MIXER_MISC_H__ */
diff --git a/gst-mixer/src/preferences.c b/gst-mixer/src/preferences.c
new file mode 100644
index 0000000..7b34085
--- /dev/null
+++ b/gst-mixer/src/preferences.c
@@ -0,0 +1,441 @@
+/* MATE Volume Control
+ * Copyright (C) 2003-2004 Ronald Bultje <[email protected]>
+ *
+ * preferences.c: preferences screen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <mateconf/mateconf-client.h>
+
+#include "element.h"
+#include "preferences.h"
+#include "keys.h"
+#include "track.h"
+#include "misc.h"
+
+enum {
+ COL_ACTIVE,
+ COL_LABEL,
+ COL_TRACK,
+ COL_TYPE,
+ COL_PAGE,
+ NUM_COLS
+};
+
+G_DEFINE_TYPE (MateVolumeControlPreferences, mate_volume_control_preferences, GTK_TYPE_DIALOG)
+
+static void mate_volume_control_preferences_class_init (MateVolumeControlPreferencesClass *klass);
+static void mate_volume_control_preferences_init (MateVolumeControlPreferences *prefs);
+static void mate_volume_control_preferences_dispose (GObject *object);
+static void mate_volume_control_preferences_response (GtkDialog *dialog,
+ gint response_id);
+
+static void set_mateconf_track_active (MateConfClient *client, GstMixer *mixer,
+ GstMixerTrack *track, gboolean active);
+
+
+static void cb_toggle (GtkCellRendererToggle *cell,
+ gchar *path_str,
+ gpointer data);
+static void cb_activated (GtkTreeView *view, GtkTreePath *path,
+ GtkTreeViewColumn *col, gpointer userdata);
+static void cb_mateconf (MateConfClient *client,
+ guint connection_id,
+ MateConfEntry *entry,
+ gpointer userdata);
+
+
+static void
+mate_volume_control_preferences_class_init (MateVolumeControlPreferencesClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkDialogClass *gtkdialog_class = (GtkDialogClass *) klass;
+
+ gobject_class->dispose = mate_volume_control_preferences_dispose;
+ gtkdialog_class->response = mate_volume_control_preferences_response;
+}
+
+/*
+ * Mixer tracks are sorted by their types.
+ */
+static gint
+sort_by_page_num (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
+{
+ gint a_type, b_type;
+
+ gtk_tree_model_get (model, a, COL_PAGE, &a_type, -1);
+ gtk_tree_model_get (model, b, COL_PAGE, &b_type, -1);
+
+ return (a_type - b_type);
+}
+
+static void
+mate_volume_control_preferences_init (MateVolumeControlPreferences *prefs)
+{
+ GtkWidget *box, *label, *view;
+ GtkListStore *store;
+ GtkTreeSelection *sel;
+ GtkTreeViewColumn *col;
+ GtkCellRenderer *render;
+
+ prefs->client = NULL;
+ prefs->client_cnxn = 0;
+ prefs->mixer = NULL;
+
+ /* make window look cute */
+ gtk_window_set_title (GTK_WINDOW (prefs), _("Volume Control Preferences"));
+ gtk_dialog_set_has_separator (GTK_DIALOG (prefs), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (prefs), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (prefs))), 2);
+ gtk_dialog_add_buttons (GTK_DIALOG (prefs),
+ GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+ /* help goes here (future) */
+ NULL);
+
+ /* add a treeview for all the properties */
+ box = gtk_vbox_new (FALSE, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (box), 5);
+
+ label = gtk_label_new_with_mnemonic (_("_Select mixers to be visible:"));
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ store = gtk_list_store_new (NUM_COLS, G_TYPE_BOOLEAN,
+ G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING,
+ G_TYPE_INT);
+ gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (store), sort_by_page_num, NULL, NULL);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
+ prefs->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (prefs->treeview), FALSE);
+ gtk_label_set_mnemonic_widget (GTK_LABEL(label), GTK_WIDGET (prefs->treeview));
+
+ /* viewport for lots of tracks */
+ view = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (view),
+ GTK_SHADOW_IN);
+ gtk_widget_set_size_request (view, -1, 250);
+
+ gtk_container_add (GTK_CONTAINER (view), prefs->treeview);
+ gtk_box_pack_start (GTK_BOX (box), view, TRUE, TRUE, 0);
+
+ gtk_widget_show (prefs->treeview);
+ gtk_widget_show (view);
+
+ /* treeview internals */
+ sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (prefs->treeview));
+ gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
+
+ render = gtk_cell_renderer_toggle_new ();
+ g_signal_connect (render, "toggled",
+ G_CALLBACK (cb_toggle), prefs);
+ g_signal_connect (prefs->treeview, "row-activated",
+ G_CALLBACK (cb_activated), prefs);
+ col = gtk_tree_view_column_new_with_attributes ("Active", render,
+ "active", COL_ACTIVE,
+ NULL);
+ gtk_tree_view_column_set_clickable (col, TRUE);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (prefs->treeview), col);
+
+ render = gtk_cell_renderer_text_new ();
+ col = gtk_tree_view_column_new_with_attributes ("Track name", render,
+ "text", COL_LABEL,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (prefs->treeview), col);
+
+ render = gtk_cell_renderer_text_new ();
+ col = gtk_tree_view_column_new_with_attributes ("Type", render,
+ "text", COL_TYPE,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (prefs->treeview), col);
+
+ gtk_tree_view_set_search_column (GTK_TREE_VIEW (prefs->treeview), COL_LABEL);
+
+ /* and show */
+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (prefs))), box,
+ TRUE, TRUE, 0);
+ gtk_widget_show (box);
+}
+
+GtkWidget *
+mate_volume_control_preferences_new (GstElement *element,
+ MateConfClient *client)
+{
+ MateVolumeControlPreferences *prefs;
+
+ g_return_val_if_fail (GST_IS_MIXER (element), NULL);
+
+ /* element */
+ prefs = g_object_new (MATE_VOLUME_CONTROL_TYPE_PREFERENCES, NULL);
+ prefs->client = g_object_ref (G_OBJECT (client));
+
+ mate_volume_control_preferences_change (prefs, element);
+
+ /* mateconf */
+ prefs->client_cnxn = mateconf_client_notify_add (prefs->client,
+ MATE_VOLUME_CONTROL_KEY_DIR,
+ cb_mateconf, prefs, NULL, NULL);
+
+ return GTK_WIDGET (prefs);
+}
+
+static void
+mate_volume_control_preferences_dispose (GObject *object)
+{
+ MateVolumeControlPreferences *prefs;
+
+ prefs = MATE_VOLUME_CONTROL_PREFERENCES (object);
+
+ if (prefs->client) {
+ mateconf_client_notify_remove (prefs->client, prefs->client_cnxn);
+ g_object_unref (G_OBJECT (prefs->client));
+ prefs->client = NULL;
+ }
+
+ if (prefs->mixer) {
+ gst_object_unref (GST_OBJECT (prefs->mixer));
+ prefs->mixer = NULL;
+ }
+
+ G_OBJECT_CLASS (mate_volume_control_preferences_parent_class)->dispose (object);
+}
+
+static void
+mate_volume_control_preferences_response (GtkDialog *dialog,
+ gint response_id)
+{
+ switch (response_id) {
+ case GTK_RESPONSE_CLOSE:
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ break;
+
+ default:
+ break;
+ }
+
+ if (((GtkDialogClass *) mate_volume_control_preferences_parent_class)->response)
+ ((GtkDialogClass *) mate_volume_control_preferences_parent_class)->response (dialog, response_id);
+}
+
+/*
+ * Hide non-alphanumeric characters, for saving in mateconf.
+ */
+
+gchar *
+get_mateconf_key (GstMixer *mixer, GstMixerTrack *track)
+{
+ const gchar *dev;
+ gchar *res;
+ gint i, pos;
+ gchar *label = NULL;
+
+ g_return_val_if_fail(mixer != NULL, NULL);
+
+ dev = g_object_get_data (G_OBJECT (mixer),
+ "mate-volume-control-name");
+ if (track != NULL) {
+ label = g_strdup (track->label);
+ } else {
+ label = g_strdup ("");
+ }
+
+ pos = strlen (MATE_VOLUME_CONTROL_KEY_DIR) + 1;
+ res = g_new (gchar, pos + strlen (dev) + 1 + strlen (label) + 1);
+ strcpy (res, MATE_VOLUME_CONTROL_KEY_DIR "/");
+
+ for (i = 0; dev[i] != '\0'; i++) {
+ if (g_ascii_isalnum (dev[i]))
+ res[pos++] = dev[i];
+ }
+ res[pos] = '/';
+ for (i = 0; label[i] != '\0'; i++) {
+ if (g_ascii_isalnum (label[i]))
+ res[pos++] = label[i];
+ }
+ res[pos] = '\0';
+
+ g_free (label);
+ return res;
+}
+
+/*
+ * Change the element. Basically recreates this object internally.
+ */
+
+void
+mate_volume_control_preferences_change (MateVolumeControlPreferences *prefs,
+ GstElement *element)
+{
+ GstMixer *mixer;
+ GtkTreeIter iter;
+ GtkListStore *store;
+ const GList *item;
+ gint pgnum;
+
+ g_return_if_fail (GST_IS_MIXER (element));
+ mixer = GST_MIXER (element);
+
+ store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (prefs->treeview)));
+
+ /* remove old */
+ while (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter)) {
+ gtk_list_store_remove (store, &iter);
+ }
+
+ /* take/put reference */
+ gst_object_replace ((GstObject **) &prefs->mixer, GST_OBJECT (element));
+
+ /* add all tracks */
+ mate_volume_control_element_whitelist (mixer, NULL);
+ for (item = gst_mixer_list_tracks (mixer);
+ item != NULL; item = item->next) {
+ GstMixerTrack *track = item->data;
+ gchar *key = get_mateconf_key (mixer, track);
+ MateConfValue *value;
+ gboolean active = mate_volume_control_element_whitelist (mixer, track);
+
+ if ((value = mateconf_client_get (prefs->client, key, NULL)) != NULL &&
+ value->type == MATECONF_VALUE_BOOL) {
+ active = mateconf_value_get_bool (value);
+ }
+ g_free (key);
+
+ pgnum = get_page_num (mixer, track);
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_ACTIVE, active,
+ COL_LABEL, track->label,
+ COL_TRACK, track,
+ COL_TYPE, get_page_description (pgnum),
+ COL_PAGE, pgnum,
+ -1);
+ }
+}
+
+/*
+ * Callback if something is toggled.
+ */
+
+static void
+set_mateconf_track_active(MateConfClient *client, GstMixer *mixer,
+ GstMixerTrack *track, gboolean active)
+{
+ gchar *key;
+
+ key = get_mateconf_key (mixer, track);
+ mateconf_client_set_bool (client, key, active, NULL);
+ g_free (key);
+}
+
+static void
+cb_mateconf(MateConfClient *client, guint connection_id,
+ MateConfEntry *entry, gpointer userdata)
+{
+ MateVolumeControlPreferences *prefs;
+ MateConfValue *value;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ gchar *keybase;
+ gboolean active, valid;
+ GstMixerTrack *track;
+
+ prefs = MATE_VOLUME_CONTROL_PREFERENCES (userdata);
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW(prefs->treeview));
+ keybase = get_mateconf_key (prefs->mixer, NULL);
+
+ if (g_str_equal (mateconf_entry_get_key (entry), keybase) &&
+ (value = mateconf_entry_get_value (entry)) != NULL &&
+ (value->type == MATECONF_VALUE_BOOL)) {
+ active = mateconf_value_get_bool (value);
+ valid = gtk_tree_model_get_iter_first(model, &iter);
+
+ while (valid == TRUE) {
+ gtk_tree_model_get (model, &iter,
+ COL_TRACK, &track,
+ -1);
+ if (g_str_equal (track->label, mateconf_entry_get_key (entry) + strlen (keybase))) {
+ gtk_list_store_set( GTK_LIST_STORE(model), &iter, COL_ACTIVE, active, -1);
+ break ;
+ }
+ valid = gtk_tree_model_iter_next(model, &iter);
+ }
+ }
+}
+
+static void
+cb_activated(GtkTreeView *view, GtkTreePath *path,
+ GtkTreeViewColumn *col, gpointer userdata)
+
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gboolean active;
+ GstMixerTrack *track;
+ MateVolumeControlPreferences *prefs;
+
+ prefs = MATE_VOLUME_CONTROL_PREFERENCES (userdata);
+ model = gtk_tree_view_get_model(view);
+
+ if (gtk_tree_model_get_iter(model, &iter, path)) {
+ gtk_tree_model_get(model, &iter,
+ COL_ACTIVE, &active,
+ COL_TRACK, &track,
+ -1);
+
+ active = !active;
+
+ gtk_list_store_set( GTK_LIST_STORE(model), &iter, COL_ACTIVE, active, -1);
+ set_mateconf_track_active(prefs->client, prefs->mixer, track, active);
+ }
+}
+
+static void
+cb_toggle (GtkCellRendererToggle *cell,
+ gchar *path_str,
+ gpointer data)
+{
+ MateVolumeControlPreferences *prefs = data;
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (prefs->treeview));
+ GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
+ GtkTreeIter iter;
+ gboolean active;
+ GstMixerTrack *track;
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ COL_ACTIVE, &active,
+ COL_TRACK, &track,
+ -1);
+
+ active = !active;
+
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+ COL_ACTIVE, active,
+ -1);
+ gtk_tree_path_free (path);
+
+ set_mateconf_track_active(prefs->client, prefs->mixer, track, active);
+}
diff --git a/gst-mixer/src/preferences.h b/gst-mixer/src/preferences.h
new file mode 100644
index 0000000..d9850f4
--- /dev/null
+++ b/gst-mixer/src/preferences.h
@@ -0,0 +1,77 @@
+/* MATE Volume Control
+ * Copyright (C) 2003-2004 Ronald Bultje <[email protected]>
+ *
+ * preferences.h: preferences screen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GVC_PREFERENCES_H__
+#define __GVC_PREFERENCES_H__
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <mateconf/mateconf-client.h>
+#include <gst/interfaces/mixer.h>
+
+G_BEGIN_DECLS
+
+#define MATE_VOLUME_CONTROL_TYPE_PREFERENCES \
+ (mate_volume_control_preferences_get_type ())
+#define MATE_VOLUME_CONTROL_PREFERENCES(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), MATE_VOLUME_CONTROL_TYPE_PREFERENCES, \
+ MateVolumeControlPreferences))
+#define MATE_VOLUME_CONTROL_PREFERENCES_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), MATE_VOLUME_CONTROL_TYPE_PREFERENCES, \
+ MateVolumeControlPreferencesClass))
+#define MATE_VOLUME_CONTROL_IS_PREFERENCES(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MATE_VOLUME_CONTROL_TYPE_PREFERENCES))
+#define MATE_VOLUME_CONTROL_IS_PREFERENCES_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), MATE_VOLUME_CONTROL_TYPE_PREFERENCES))
+
+typedef struct _MateVolumeControlPreferences {
+ GtkDialog parent;
+
+ /* current element that we're working on */
+ GstMixer *mixer;
+
+ /* mateconf client inherited from our parent */
+ MateConfClient *client;
+ guint client_cnxn;
+
+ /* treeview inside us */
+ GtkWidget *treeview;
+} MateVolumeControlPreferences;
+
+typedef struct _MateVolumeControlPreferencesClass {
+ GtkDialogClass klass;
+} MateVolumeControlPreferencesClass;
+
+GType mate_volume_control_preferences_get_type (void);
+GtkWidget *mate_volume_control_preferences_new (GstElement *element,
+ MateConfClient *client);
+void mate_volume_control_preferences_change (MateVolumeControlPreferences *prefs,
+ GstElement *element);
+
+/*
+ * MateConf thingy. Escapes spaces and such.
+ */
+gchar * get_mateconf_key (GstMixer *mixer, GstMixerTrack *track);
+
+
+G_END_DECLS
+
+#endif /* __GVC_PREFERENCES_H__ */
diff --git a/gst-mixer/src/track.c b/gst-mixer/src/track.c
new file mode 100644
index 0000000..9b742be
--- /dev/null
+++ b/gst-mixer/src/track.c
@@ -0,0 +1,647 @@
+/* MATE Volume Control
+ * Copyright (C) 2003-2004 Ronald Bultje <[email protected]>
+ *
+ * track.c: layout of a single mixer track
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <unistd.h>
+#include <glib/gi18n.h>
+#include <string.h>
+
+#include "button.h"
+#include "track.h"
+#include "volume.h"
+
+static const struct {
+ gchar *label,
+ *pixmap;
+} pix[] = {
+ { "cd", "media-optical" },
+ { "line", "gvc-line-in" },
+ { "aux", "gvc-line-in" },
+ { "mic", "audio-input-microphone" },
+ { "cap", "gvc-line-in" },
+ { "mix", "multimedia-volume-control" },
+ { "pcm", "gvc-tone" },
+ { "headphone", "gvc-headphones" },
+ { "phone", "phone" },
+ { "speaker", "audio-volume-high" },
+ { "front", "audio-volume-high" },
+ { "surround", "audio-volume-high" },
+ { "side", "audio-volume-high" },
+ { "center", "audio-volume-high" },
+ { "lfe", "audio-volume-high" },
+ { "video", "video-display" },
+ { "volume", "gvc-tone" },
+ { "master", "gvc-tone" },
+ { "3d", "gvc-3d-sound" },
+ { "beep", "keyboard" },
+ { "record", "audio-input-microphone" },
+ { NULL, NULL }
+};
+
+/*
+ * UI responses.
+ */
+
+static void
+cb_mute_toggled (MateVolumeControlButton *button,
+ gpointer data)
+{
+ MateVolumeControlTrack *ctrl = data;
+
+ gst_mixer_set_mute (ctrl->mixer, ctrl->track,
+ !mate_volume_control_button_get_active (button));
+}
+
+static void
+cb_record_toggled (MateVolumeControlButton *button,
+ gpointer data)
+{
+ MateVolumeControlTrack *ctrl = data;
+
+ gst_mixer_set_record (ctrl->mixer, ctrl->track,
+ mate_volume_control_button_get_active (button));
+}
+
+/* Tells us whether toggling a switch should change the corresponding
+ * GstMixerTrack's MUTE or RECORD flag.
+ */
+static gboolean
+should_toggle_record_switch (const GstMixerTrack *track)
+{
+ return (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_INPUT) &&
+ !GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_NO_RECORD));
+}
+
+
+static void
+cb_toggle_changed (GtkToggleButton *button,
+ gpointer data)
+{
+ MateVolumeControlTrack *ctrl = data;
+
+ if (should_toggle_record_switch (ctrl->track)) {
+ gst_mixer_set_record (ctrl->mixer, ctrl->track,
+ gtk_toggle_button_get_active (button));
+ } else {
+ gst_mixer_set_mute (ctrl->mixer, ctrl->track,
+ !gtk_toggle_button_get_active (button));
+ }
+}
+
+static void
+cb_option_changed (GtkComboBox *box,
+ gpointer data)
+{
+ MateVolumeControlTrack *ctrl = data;
+ gchar *opt;
+
+ opt = gtk_combo_box_get_active_text (box);
+ if (opt)
+ gst_mixer_set_option (ctrl->mixer, GST_MIXER_OPTIONS (ctrl->track), opt);
+ g_free (opt);
+}
+
+/*
+ * Timeout to check for changes in mixer outside ourselves.
+ */
+
+void
+mate_volume_control_track_update (MateVolumeControlTrack *trkw)
+{
+ gboolean mute, record;
+ gboolean vol_is_zero = FALSE, slider_is_zero = FALSE;
+ GstMixer *mixer;
+ GstMixerTrack *track;
+ gint i;
+ gint *dummy;
+
+ g_return_if_fail (trkw != NULL);
+
+ track = trkw->track;
+ mixer = trkw->mixer;
+
+ /* trigger an update of the mixer state */
+ if (GST_IS_MIXER_OPTIONS (track)) {
+ const GList *opt;
+ GstMixerOptions *options = GST_MIXER_OPTIONS (track);
+ const char *active_opt;
+ active_opt = gst_mixer_get_option (mixer, options);
+
+ for (i = 0, opt = gst_mixer_options_get_values (options);
+ opt != NULL;
+ opt = opt->next, i++) {
+ if (g_str_equal (active_opt, opt->data)) {
+ gtk_combo_box_set_active (GTK_COMBO_BOX (trkw->options), i);
+ }
+ }
+
+ return;
+ }
+
+ dummy = g_new (gint, MAX (track->num_channels, 1));
+ gst_mixer_get_volume (mixer, track, dummy);
+ g_free (dummy);
+
+ mute = GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE) ?
+ TRUE : FALSE;
+ record = GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD) ?
+ TRUE : FALSE;
+
+ if (trkw->sliderbox) {
+ mate_volume_control_volume_update (MATE_VOLUME_CONTROL_VOLUME (trkw->sliderbox));
+ mate_volume_control_volume_ask (
+ MATE_VOLUME_CONTROL_VOLUME (trkw->sliderbox),
+ &vol_is_zero, &slider_is_zero);
+
+ if (trkw->mute && !slider_is_zero && vol_is_zero)
+ mute = TRUE;
+ }
+
+ if (trkw->mute) {
+ if (mate_volume_control_button_get_active (trkw->mute) == mute) {
+ mate_volume_control_button_set_active (trkw->mute, !mute);
+ }
+ }
+
+ if (trkw->record) {
+ if (mate_volume_control_button_get_active (trkw->record) != record) {
+ mate_volume_control_button_set_active (trkw->record, record);
+ }
+ }
+
+ if (trkw->toggle) {
+ if (should_toggle_record_switch (trkw->track)) {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (trkw->toggle),
+ GST_MIXER_TRACK_HAS_FLAG (trkw->track, GST_MIXER_TRACK_RECORD));
+ } else {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (trkw->toggle),
+ !GST_MIXER_TRACK_HAS_FLAG (trkw->track, GST_MIXER_TRACK_MUTE));
+ }
+ }
+
+ /* FIXME:
+ * - options.
+ */
+}
+
+
+static gboolean
+cb_check (gpointer data)
+{
+ mate_volume_control_track_update (data);
+
+ return TRUE;
+}
+
+/*
+ * Actual UI code.
+ */
+
+static MateVolumeControlTrack *
+mate_volume_control_track_add_title (GtkTable *table,
+ gint tab_pos,
+ GtkOrientation or,
+ GstMixer *mixer,
+ GstMixerTrack *track,
+ GtkWidget *l_sep,
+ GtkWidget *r_sep)
+{
+ MateVolumeControlTrack *ctrl;
+ gchar *ulabel = NULL;
+ gchar *str = NULL;
+ gint i;
+ gboolean need_timeout = TRUE;
+
+ need_timeout = ((gst_mixer_get_mixer_flags (GST_MIXER (mixer)) &
+ GST_MIXER_FLAG_AUTO_NOTIFICATIONS) == 0);
+
+ /* start */
+ ctrl = g_new0 (MateVolumeControlTrack, 1);
+ ctrl->mixer = mixer;
+ g_object_ref (G_OBJECT (track));
+ ctrl->track = track;
+ ctrl->left_separator = l_sep;
+ ctrl->right_separator = r_sep;
+ ctrl->visible = TRUE;
+ ctrl->table = table;
+ ctrl->pos = tab_pos;
+ if (need_timeout)
+ ctrl->id = g_timeout_add (200, cb_check, ctrl);
+ ctrl->flagbuttonbox = NULL;
+
+ /* find image from label string (optional) */
+ if (g_object_class_find_property (G_OBJECT_GET_CLASS (track), "untranslated-label"))
+ g_object_get (track, "untranslated-label", &ulabel, NULL);
+
+ if (ulabel == NULL)
+ g_object_get (track, "label", &ulabel, NULL);
+
+ if (ulabel) {
+ gint pos;
+
+ /* make case insensitive */
+ for (pos = 0; ulabel[pos] != '\0'; pos++)
+ ulabel[pos] = g_ascii_tolower (ulabel[pos]);
+
+ for (i = 0; pix[i].label != NULL; i++) {
+ if (g_strrstr (ulabel, pix[i].label) != NULL) {
+ str = pix[i].pixmap;
+ break;
+ }
+ }
+
+ g_free (ulabel);
+ }
+
+ if ((str != NULL) && (track->num_channels != 0)) {
+ if ((ctrl->image = gtk_image_new_from_icon_name (str, GTK_ICON_SIZE_MENU)) != NULL) {
+ gtk_misc_set_alignment (GTK_MISC (ctrl->image), 0.5, 0.5);
+ if (or == GTK_ORIENTATION_VERTICAL) {
+ gtk_table_attach (GTK_TABLE (table), ctrl->image,
+ tab_pos, tab_pos + 1, 0, 1,
+ GTK_EXPAND, 0, 0, 0);
+ } else {
+ gtk_table_attach (GTK_TABLE (table), ctrl->image,
+ 0, 1, tab_pos, tab_pos + 1,
+ 0, GTK_EXPAND, 0, 0);
+ }
+ gtk_widget_show (ctrl->image);
+ }
+ }
+
+ /* text label */
+ if (or == GTK_ORIENTATION_HORIZONTAL)
+ str = g_strdup_printf (_("%s:"), track->label);
+ else
+ str = g_strdup (track->label);
+ ctrl->label = gtk_label_new (str);
+ if (or == GTK_ORIENTATION_HORIZONTAL) {
+ g_free (str);
+ gtk_misc_set_alignment (GTK_MISC (ctrl->label), 0.0, 0.5);
+ }
+ if (or == GTK_ORIENTATION_VERTICAL) {
+ gtk_table_attach (table, ctrl->label,
+ tab_pos, tab_pos + 1, 1, 2,
+ GTK_EXPAND, 0, 0, 0);
+ } else {
+ gtk_table_attach (table, ctrl->label,
+ 1, 2, tab_pos, tab_pos + 1,
+ GTK_FILL, GTK_EXPAND, 0, 0);
+ }
+ gtk_widget_show (ctrl->label);
+
+ return ctrl;
+}
+
+static void
+mate_volume_control_track_put_switch (GtkTable *table,
+ gint tab_pos,
+ MateVolumeControlTrack *ctrl)
+{
+ GtkWidget *button;
+ AtkObject *accessible;
+ gchar *accessible_name, *msg;
+
+ /* container box */
+ ctrl->buttonbox = gtk_hbox_new (FALSE, 0);
+ gtk_table_attach (GTK_TABLE (table), ctrl->buttonbox,
+ tab_pos, tab_pos + 1,
+ 3, 4, GTK_EXPAND, 0, 0, 0);
+ gtk_widget_show (ctrl->buttonbox);
+
+ /* if we weren't supposed to show the mute button, then don't create it */
+ if (GST_MIXER_TRACK_HAS_FLAG (ctrl->track, GST_MIXER_TRACK_NO_MUTE)) {
+ return;
+ }
+
+ /* mute button */
+ msg = g_strdup_printf (_("Mute/Unmute %s"), ctrl->track->label);
+ button = mate_volume_control_button_new ("audio-volume-high",
+ "audio-volume-muted",
+ msg);
+ ctrl->mute = MATE_VOLUME_CONTROL_BUTTON (button);
+ g_free (msg);
+
+ mate_volume_control_button_set_active (
+ MATE_VOLUME_CONTROL_BUTTON (button),
+ !GST_MIXER_TRACK_HAS_FLAG (ctrl->track, GST_MIXER_TRACK_MUTE));
+
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (cb_mute_toggled), ctrl);
+
+ /* a11y */
+ accessible = gtk_widget_get_accessible (button);
+ if (GTK_IS_ACCESSIBLE (accessible)) {
+ accessible_name = g_strdup_printf (_("Track %s: mute"),
+ ctrl->track->label);
+ atk_object_set_name (accessible, accessible_name);
+ g_free (accessible_name);
+ }
+
+ /* show */
+ gtk_box_pack_start (GTK_BOX (ctrl->buttonbox), button,
+ FALSE, FALSE, 0);
+ gtk_widget_show (button);
+}
+
+MateVolumeControlTrack *
+mate_volume_control_track_add_playback (GtkTable *table,
+ gint tab_pos,
+ GstMixer *mixer,
+ GstMixerTrack *track,
+ GtkWidget *l_sep,
+ GtkWidget *r_sep,
+ GtkWidget *fbox)
+{
+ MateVolumeControlTrack *ctrl;
+
+ /* switch and options exception (no sliders) */
+ if (track->num_channels == 0) {
+ if (GST_IS_MIXER_OPTIONS (track)) {
+ return (mate_volume_control_track_add_option (table, tab_pos, mixer, track,
+ l_sep, r_sep, fbox));
+ }
+ return (mate_volume_control_track_add_switch (table, tab_pos, mixer, track,
+ l_sep, r_sep, fbox));
+ }
+
+ /* image, title */
+ ctrl = mate_volume_control_track_add_title (table, tab_pos,
+ GTK_ORIENTATION_VERTICAL,
+ mixer, track, l_sep, r_sep);
+
+ ctrl->sliderbox = mate_volume_control_volume_new (ctrl->mixer,
+ ctrl->track, 6);
+ gtk_table_attach (GTK_TABLE (table), ctrl->sliderbox,
+ tab_pos, tab_pos + 1, 2, 3,
+ GTK_EXPAND, GTK_EXPAND | GTK_FILL, 0, 0);
+ gtk_widget_show (ctrl->sliderbox);
+
+ /* mute button */
+ mate_volume_control_track_put_switch (table, tab_pos, ctrl);
+
+ return ctrl;
+}
+
+MateVolumeControlTrack *
+mate_volume_control_track_add_recording (GtkTable *table,
+ gint tab_pos,
+ GstMixer *mixer,
+ GstMixerTrack *track,
+ GtkWidget *l_sep,
+ GtkWidget *r_sep,
+ GtkWidget *fbox)
+{
+ MateVolumeControlTrack *ctrl;
+ GtkWidget *button;
+ AtkObject *accessible;
+ gchar *accessible_name, *msg;
+
+ ctrl = mate_volume_control_track_add_playback (table, tab_pos, mixer,
+ track, l_sep, r_sep, fbox);
+ if (track->num_channels == 0) {
+ return ctrl;
+ }
+
+ /* FIXME:
+ * - there's something fishy about this button, it
+ * is always FALSE.
+ */
+ if (!GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_NO_RECORD)) {
+ /* only the record button here */
+ msg = g_strdup_printf (_("Toggle audio recording from %s"),
+ ctrl->track->label);
+ button = mate_volume_control_button_new ("audio-input-microphone",
+ "audio-input-microphone-muted",
+ msg);
+ ctrl->record = MATE_VOLUME_CONTROL_BUTTON (button);
+ g_free (msg);
+ mate_volume_control_button_set_active (MATE_VOLUME_CONTROL_BUTTON (button),
+ GST_MIXER_TRACK_HAS_FLAG (track,
+ GST_MIXER_TRACK_RECORD));
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (cb_record_toggled), ctrl);
+
+ /* a11y */
+ accessible = gtk_widget_get_accessible (button);
+ if (GTK_IS_ACCESSIBLE (accessible)) {
+ accessible_name = g_strdup_printf (_("Track %s: audio recording"),
+ track->label);
+ atk_object_set_name (accessible, accessible_name);
+ g_free (accessible_name);
+ }
+
+ /* attach, show */
+ gtk_box_pack_start (GTK_BOX (ctrl->buttonbox), button,
+ FALSE, FALSE, 0);
+ gtk_widget_show (button);
+ }
+
+ return ctrl;
+}
+
+MateVolumeControlTrack *
+mate_volume_control_track_add_switch (GtkTable *table,
+ gint tab_pos,
+ GstMixer *mixer,
+ GstMixerTrack *track,
+ GtkWidget *l_sep,
+ GtkWidget *r_sep,
+ GtkWidget *fbox)
+{
+ MateVolumeControlTrack *ctrl;
+ GtkWidget *toggle;
+ gint volume;
+
+ /* image, title */
+ toggle = gtk_check_button_new ();
+
+ /* this is a hack - we query volume to initialize switch state */
+ gst_mixer_get_volume (mixer, track, &volume);
+
+ if (should_toggle_record_switch (track)) {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
+ GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD));
+ } else {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
+ !GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE));
+ }
+
+ if (fbox == NULL) {
+ fbox = gtk_table_new(0, 3, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (fbox), 6);
+ }
+ table = GTK_TABLE (fbox);
+
+ ctrl = mate_volume_control_track_add_title (table, tab_pos,
+ GTK_ORIENTATION_HORIZONTAL,
+ mixer, track, l_sep, r_sep);
+ ctrl->toggle = toggle;
+ ctrl->flagbuttonbox = fbox;
+
+ /* attach'n'show */
+ gtk_table_attach (table, toggle,
+ 2, 3, tab_pos, tab_pos + 1,
+ GTK_EXPAND | GTK_FILL, GTK_EXPAND, 0, 0);
+
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (cb_toggle_changed), ctrl);
+ gtk_widget_show (toggle);
+
+ return ctrl;
+}
+
+MateVolumeControlTrack *
+mate_volume_control_track_add_option (GtkTable *table,
+ gint tab_pos,
+ GstMixer *mixer,
+ GstMixerTrack *track,
+ GtkWidget *l_sep,
+ GtkWidget *r_sep,
+ GtkWidget *fbox)
+{
+ MateVolumeControlTrack *ctrl;
+ GstMixerOptions *options = GST_MIXER_OPTIONS (track);
+ const GList *opt, *opts;
+ AtkObject *accessible;
+ gchar *accessible_name;
+ gint i = 0;
+ const gchar *active_opt;
+
+ if (fbox == NULL) {
+ fbox = gtk_table_new(0, 3, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (fbox), 6);
+ }
+ table = GTK_TABLE (fbox);
+
+ ctrl = mate_volume_control_track_add_title (table, tab_pos,
+ GTK_ORIENTATION_HORIZONTAL,
+ mixer, track, l_sep, r_sep);
+
+ /* optionmenu */
+ active_opt = gst_mixer_get_option (mixer, options);
+ if (active_opt != NULL) {
+ ctrl->options = gtk_combo_box_new_text ();
+ opts = gst_mixer_options_get_values (options);
+ for (opt = opts; opt != NULL; opt = opt->next, i++) {
+ if (opt->data == NULL)
+ continue;
+
+ gtk_combo_box_append_text (GTK_COMBO_BOX (ctrl->options), opt->data);
+
+ if (g_str_equal (active_opt, opt->data)) {
+ gtk_combo_box_set_active (GTK_COMBO_BOX (ctrl->options), i);
+ }
+ }
+ }
+
+ /* a11y */
+ accessible = gtk_widget_get_accessible (ctrl->options);
+ if (GTK_IS_ACCESSIBLE (accessible)) {
+ accessible_name = g_strdup_printf (_("%s Option Selection"),
+ ctrl->track->label);
+ atk_object_set_name (accessible, accessible_name);
+ g_free (accessible_name);
+ }
+ gtk_widget_show (ctrl->options);
+ g_signal_connect (ctrl->options, "changed",
+ G_CALLBACK (cb_option_changed), ctrl);
+
+ ctrl->flagbuttonbox = fbox;
+
+ /* attach'n'show */
+ gtk_table_attach (table, ctrl->options,
+ 2, 3, tab_pos, tab_pos + 1,
+ GTK_EXPAND | GTK_FILL, GTK_EXPAND, 0, 0);
+ gtk_widget_show (ctrl->options);
+
+ return ctrl;
+}
+
+void
+mate_volume_control_track_free (MateVolumeControlTrack *track)
+{
+ if (track->id != 0) {
+ g_source_remove (track->id);
+ track->id = 0;
+ }
+
+ g_object_unref (G_OBJECT (track->track));
+
+ g_free (track);
+}
+
+void
+mate_volume_control_track_show (MateVolumeControlTrack *track,
+ gboolean visible)
+{
+#define func(w) \
+ if (w != NULL) { \
+ if (visible) { \
+ gtk_widget_show (w); \
+ } else { \
+ gtk_widget_hide (w); \
+ } \
+ }
+
+ func (track->label);
+ func (track->image);
+ func (track->sliderbox);
+ func (track->buttonbox);
+ func (track->toggle);
+ func (track->options);
+
+ track->visible = visible;
+
+ /* get rid of spacing between hidden tracks */
+ if (visible) {
+ if (track->options) {
+ gtk_table_set_row_spacing (track->table,
+ track->pos, 6);
+ if (track->pos > 0)
+ gtk_table_set_row_spacing (track->table,
+ track->pos - 1, 6);
+ } else if (!track->toggle) {
+ gtk_table_set_col_spacing (track->table,
+ track->pos, 6);
+ if (track->pos > 0)
+ gtk_table_set_col_spacing (track->table,
+ track->pos - 1, 6);
+ }
+ } else {
+ if (track->options) {
+ gtk_table_set_row_spacing (track->table,
+ track->pos, 0);
+ if (track->pos > 0)
+ gtk_table_set_row_spacing (track->table,
+ track->pos - 1, 0);
+ } else if (!track->toggle) {
+ gtk_table_set_col_spacing (track->table,
+ track->pos, 0);
+ if (track->pos > 0)
+ gtk_table_set_col_spacing (track->table,
+ track->pos - 1, 0);
+ }
+ }
+}
diff --git a/gst-mixer/src/track.h b/gst-mixer/src/track.h
new file mode 100644
index 0000000..1ace5f8
--- /dev/null
+++ b/gst-mixer/src/track.h
@@ -0,0 +1,113 @@
+/* MATE Volume Control
+ * Copyright (C) 2003-2004 Ronald Bultje <[email protected]>
+ *
+ * track.h: layout of a single mixer track
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GVC_TRACK_H__
+#define __GVC_TRACK_H__
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <mateconf/mateconf-client.h>
+#include <gst/gst.h>
+#include <gst/interfaces/mixer.h>
+
+#include "button.h"
+
+G_BEGIN_DECLS
+
+typedef struct _MateVolumeControlTrack {
+ /* pointer to table in which we write */
+ GtkTable *table;
+ gint pos;
+
+ /* gstreamer object pointers */
+ GstMixer *mixer;
+ GstMixerTrack *track;
+
+ /* widgets associated with this track */
+ GtkWidget *label,
+ *image,
+ *sliderbox,
+ *buttonbox,
+ *toggle,
+ *options,
+ *flagbuttonbox;
+
+ MateVolumeControlButton *mute, *record;
+
+ /* list of slider adjustments */
+ GList *sliders;
+
+ /* separator left/right (or top/bottom) of the actual widget */
+ GtkWidget *left_separator,
+ *right_separator;
+
+ /* whether we're currently "visible" */
+ gboolean visible;
+
+ /* signal IDs */
+ guint id;
+} MateVolumeControlTrack;
+
+MateVolumeControlTrack *
+ mate_volume_control_track_add_playback (GtkTable *table,
+ gint tab_pos,
+ GstMixer *mixer,
+ GstMixerTrack *track,
+ GtkWidget *l_sep,
+ GtkWidget *r_sep,
+ GtkWidget *fbox);
+MateVolumeControlTrack *
+ mate_volume_control_track_add_recording(GtkTable *table,
+ gint tab_pos,
+ GstMixer *mixer,
+ GstMixerTrack *track,
+ GtkWidget *l_sep,
+ GtkWidget *r_sep,
+ GtkWidget *fbox);
+
+MateVolumeControlTrack *
+ mate_volume_control_track_add_switch (GtkTable *table,
+ gint tab_pos,
+ GstMixer *mixer,
+ GstMixerTrack *track,
+ GtkWidget *l_sep,
+ GtkWidget *r_sep,
+ GtkWidget *fbox);
+
+MateVolumeControlTrack *
+ mate_volume_control_track_add_option (GtkTable *table,
+ gint tab_pos,
+ GstMixer *mixer,
+ GstMixerTrack *track,
+ GtkWidget *l_sep,
+ GtkWidget *r_sep,
+ GtkWidget *fbox);
+
+void mate_volume_control_track_free (MateVolumeControlTrack *track);
+
+void mate_volume_control_track_show (MateVolumeControlTrack *track,
+ gboolean visible);
+
+void mate_volume_control_track_update (MateVolumeControlTrack *trkw);
+
+G_END_DECLS
+
+#endif /* __GVC_TRACK_H__ */
diff --git a/gst-mixer/src/volume.c b/gst-mixer/src/volume.c
new file mode 100644
index 0000000..a3386f1
--- /dev/null
+++ b/gst-mixer/src/volume.c
@@ -0,0 +1,552 @@
+/* MATE Volume Control
+ * Copyright (C) 2003-2004 Ronald Bultje <[email protected]>
+ *
+ * volume.c: representation of a track's volume channels
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define _ISOC99_SOURCE
+
+#include <math.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+
+#include "volume.h"
+#include "button.h"
+
+G_DEFINE_TYPE (MateVolumeControlVolume, mate_volume_control_volume, GTK_TYPE_FIXED)
+
+
+static void mate_volume_control_volume_class_init (MateVolumeControlVolumeClass *klass);
+static void mate_volume_control_volume_init (MateVolumeControlVolume *el);
+static void mate_volume_control_volume_dispose (GObject *object);
+
+static void mate_volume_control_volume_size_req (GtkWidget *widget,
+ GtkRequisition *req);
+static void mate_volume_control_volume_size_alloc (GtkWidget *widget,
+ GtkAllocation *alloc);
+static gboolean mate_volume_control_volume_expose (GtkWidget *widget,
+ GdkEventExpose *expose);
+
+static void cb_volume_changed (GtkAdjustment *adj,
+ gpointer data);
+static void cb_lock_toggled (GtkToggleButton *button,
+ gpointer data);
+
+static gboolean cb_check (gpointer data);
+
+
+static void
+mate_volume_control_volume_class_init (MateVolumeControlVolumeClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (klass);
+
+ gobject_class->dispose = mate_volume_control_volume_dispose;
+ gtkwidget_class->size_allocate = mate_volume_control_volume_size_alloc;
+ gtkwidget_class->size_request = mate_volume_control_volume_size_req;
+ gtkwidget_class->expose_event = mate_volume_control_volume_expose;
+}
+
+static void
+mate_volume_control_volume_init (MateVolumeControlVolume *vol)
+{
+ #if GTK_CHECK_VERSION(2,18,0)
+ gtk_widget_set_has_window (GTK_WIDGET (vol), TRUE);
+ #else
+ gtk_fixed_set_has_window (GTK_FIXED (vol), TRUE);
+ #endif
+
+ vol->mixer = NULL;
+ vol->track = NULL;
+ vol->padding = 6;
+ vol->scales = NULL;
+ vol->button = NULL;
+ vol->locked = FALSE;
+ vol->id = 0;
+}
+
+static GtkWidget *
+get_scale (MateVolumeControlVolume *vol,
+ gint num_chan,
+ gint volume)
+{
+ GtkWidget *slider;
+ GtkObject *adj;
+ AtkObject *accessible;
+ gchar *accessible_name;
+
+ adj = gtk_adjustment_new (volume,
+ vol->track->min_volume, vol->track->max_volume,
+ (vol->track->max_volume - vol->track->min_volume) / 100.0,
+ (vol->track->max_volume - vol->track->min_volume) / 10.0, 0.0);
+ g_signal_connect (adj, "value_changed",
+ G_CALLBACK (cb_volume_changed), vol);
+ slider = gtk_vscale_new (GTK_ADJUSTMENT (adj));
+ gtk_scale_set_draw_value (GTK_SCALE (slider), FALSE);
+ gtk_range_set_inverted (GTK_RANGE (slider), TRUE);
+
+ /* a11y */
+ accessible = gtk_widget_get_accessible (slider);
+ if (GTK_IS_ACCESSIBLE (accessible)) {
+ if (vol->track->num_channels == 1) {
+ accessible_name = g_strdup_printf (_("Track %s"),
+ vol->track->label);
+ } else {
+ gchar *accessible_desc = g_strdup_printf (_("Channel %d of track %s"),
+ num_chan + 1,
+ vol->track->label);
+ accessible_name = g_strdup_printf (_("Track %s, channel %d"),
+ vol->track->label, num_chan + 1);
+ atk_object_set_description (accessible, accessible_desc);
+ g_free (accessible_desc);
+ }
+ atk_object_set_name (accessible, accessible_name);
+ g_free (accessible_name);
+ }
+
+ return slider;
+}
+
+static void
+get_button (MateVolumeControlVolume *vol,
+ gint *volumes)
+{
+ AtkObject *accessible;
+ gchar *accessible_name, *msg;
+ gint n;
+
+ msg = g_strdup_printf (_("Lock channels for %s together"), vol->track->label);
+ vol->button = mate_volume_control_button_new ("chain.png",
+ "chain-broken.png",
+ msg);
+ g_free (msg);
+ g_signal_connect (vol->button, "clicked",
+ G_CALLBACK (cb_lock_toggled), vol);
+ for (n = 1; n < vol->track->num_channels; n++) {
+ /* default, unlocked */
+ if (volumes[n] != volumes[0])
+ break;
+ }
+ mate_volume_control_button_set_active (MATE_VOLUME_CONTROL_BUTTON (vol->button),
+ n == vol->track->num_channels);
+
+ /* a11y */
+ accessible = gtk_widget_get_accessible (vol->button);
+ if (GTK_IS_ACCESSIBLE (accessible)) {
+ accessible_name = g_strdup_printf (_("Track %s: lock channels together"),
+ vol->track->label);
+ atk_object_set_name (accessible, accessible_name);
+ g_free (accessible_name);
+ }
+}
+
+GtkWidget *
+mate_volume_control_volume_new (GstMixer *mixer,
+ GstMixerTrack *track,
+ gint padding)
+{
+ MateVolumeControlVolume *vol;
+ gint *volumes, n;
+ gchar *msg, *chan;
+ gboolean need_timeout = TRUE;
+
+ need_timeout = ((gst_mixer_get_mixer_flags (GST_MIXER (mixer)) &
+ GST_MIXER_FLAG_AUTO_NOTIFICATIONS) == 0);
+
+ /* volume */
+ vol = g_object_new (MATE_VOLUME_CONTROL_TYPE_VOLUME, NULL);
+ gst_object_ref (GST_OBJECT (mixer));
+ vol->mixer = mixer;
+ vol->track = g_object_ref (G_OBJECT (track));
+ if (padding >= 0)
+ vol->padding = padding;
+
+ /* sliders */
+ volumes = g_new0 (gint, track->num_channels);
+ gst_mixer_get_volume (mixer, track, volumes);
+ for (n = 0; n < track->num_channels; n++) {
+ GtkWidget *slider;
+
+ /* we will reposition the widget once we're drawing up */
+ slider = get_scale (vol, n, volumes[n]);
+ gtk_fixed_put (GTK_FIXED (vol), slider, 0, 0);
+ gtk_widget_show (slider);
+ vol->scales = g_list_append (vol->scales, slider);
+
+ /* somewhat dirty hack that will suffice for now. 1 chan
+ * means mono, two means stereo (left/right) and > 2 means
+ * alsa, where channel order is front, rear, center, lfe,
+ * side. */
+ if (vol->track->num_channels == 1) {
+ chan = _("mono");
+ } else if (vol->track->num_channels == 2) {
+ chan = (n == 0) ? _("left") : _("right");
+ } else {
+ switch (n) {
+ case 0: chan = _("front left"); break;
+ case 1: chan = _("front right"); break;
+ case 2: chan = _("rear left"); break;
+ case 3: chan = _("rear right"); break;
+ case 4: chan = _("front center"); break;
+ /* Translators: This is the name of a surround sound channel. It
+ * stands for "Low-Frequency Effects". If you're not sure that
+ * this has an established and different translation in your
+ * language, leave it unchanged. */
+ case 5: chan = _("LFE"); break;
+ case 6: chan = _("side left"); break;
+ case 7: chan = _("side right"); break;
+ default: chan = _("unknown"); break;
+ }
+ }
+
+ /* Here, we can actually tell people that this
+ * is a slider that will change channel X. */
+ msg = g_strdup_printf (_("Volume of %s channel on %s"),
+ chan, vol->track->label);
+ gtk_widget_set_tooltip_text (slider, msg);
+ g_free (msg);
+ }
+
+ /* chainbutton */
+ get_button (vol, volumes);
+ if (track->num_channels > 1) {
+ gtk_fixed_put (GTK_FIXED (vol), vol->button, 0, 0);
+ gtk_widget_show (vol->button);
+ }
+
+ g_free (volumes);
+
+ /* GStreamer signals */
+ if (need_timeout)
+ vol->id = g_timeout_add (100, cb_check, vol);
+
+ return GTK_WIDGET (vol);
+}
+
+static void
+mate_volume_control_volume_dispose (GObject *object)
+{
+ MateVolumeControlVolume *vol = MATE_VOLUME_CONTROL_VOLUME (object);
+
+ if (vol->id != 0) {
+ g_source_remove (vol->id);
+ vol->id = 0;
+ }
+
+ if (vol->track) {
+ g_object_unref (G_OBJECT (vol->track));
+ vol->track = NULL;
+ }
+
+ if (vol->mixer) {
+ gst_object_unref (GST_OBJECT (vol->mixer));
+ vol->mixer = NULL;
+ }
+
+ if (vol->scales) {
+ g_list_free (vol->scales);
+ vol->scales = NULL;
+ }
+
+ G_OBJECT_CLASS (mate_volume_control_volume_parent_class)->dispose (object);
+}
+
+/*
+ * Gtk/GDK virtual functions for size negotiation.
+ */
+
+static void
+mate_volume_control_volume_size_req (GtkWidget *widget,
+ GtkRequisition *req)
+{
+ MateVolumeControlVolume *vol = MATE_VOLUME_CONTROL_VOLUME (widget);
+ GtkRequisition but_req, scale_req;
+
+ /* request size of kids */
+ GTK_WIDGET_GET_CLASS (vol->button)->size_request (vol->button, &but_req);
+ GTK_WIDGET_GET_CLASS (vol->scales->data)->size_request (vol->scales->data,
+ &scale_req);
+ if (scale_req.height < 100)
+ scale_req.height = 100;
+
+ /* calculate our own size from that */
+ req->width = scale_req.width * vol->track->num_channels +
+ vol->padding * (vol->track->num_channels - 1);
+ req->height = scale_req.height + but_req.height /*+ vol->padding*/;
+}
+
+static void
+mate_volume_control_volume_size_alloc (GtkWidget *widget,
+ GtkAllocation *alloc)
+{
+ MateVolumeControlVolume *vol = MATE_VOLUME_CONTROL_VOLUME (widget);
+ GtkRequisition but_req, scale_req;
+ GtkAllocation but_all, scale_all;
+ gint x_offset, but_deco_width, n = 0;
+ GList *scales;
+ GtkAllocation allocation;
+
+ /* loop? */
+ gtk_widget_get_allocation (widget, &allocation);
+ if (alloc->x == allocation.x &&
+ alloc->y == allocation.y &&
+ alloc->width == allocation.width &&
+ alloc->height == allocation.height)
+ return;
+
+ /* request size of kids */
+ GTK_WIDGET_GET_CLASS (vol->button)->size_request (vol->button, &but_req);
+ GTK_WIDGET_GET_CLASS (vol->scales->data)->size_request (vol->scales->data,
+ &scale_req);
+
+ /* calculate */
+ x_offset = (alloc->width - ((vol->track->num_channels * scale_req.width) +
+ (vol->track->num_channels - 1) * vol->padding)) / 2;
+ scale_all.width = scale_req.width;
+ scale_all.height = alloc->height - but_req.height;
+ scale_all.y = 0;
+ but_deco_width = alloc->width - (2 * x_offset);
+ but_all.width = but_req.width;
+ but_all.height = but_req.height;
+ but_all.x = x_offset + (but_deco_width - but_req.width) / 2;
+ but_all.y = alloc->height - but_req.height;
+
+ /* tell sliders */
+ for (scales = vol->scales; scales != NULL; scales = scales->next, n++) {
+ scale_all.x = x_offset + n * (scale_req.width + vol->padding);
+ gtk_fixed_move (GTK_FIXED (vol), scales->data, scale_all.x, scale_all.y);
+ gtk_widget_set_size_request (scales->data, scale_all.width, scale_all.height);
+ }
+
+ /* tell button */
+ if (vol->track->num_channels > 1) {
+ gtk_fixed_move (GTK_FIXED (vol), vol->button, but_all.x, but_all.y);
+ gtk_widget_set_size_request (vol->button, but_all.width, but_all.height);
+ }
+
+ /* parent will resize window */
+ GTK_WIDGET_CLASS (mate_volume_control_volume_parent_class)->size_allocate (widget, alloc);
+}
+
+static gboolean
+mate_volume_control_volume_expose (GtkWidget *widget,
+ GdkEventExpose *expose)
+{
+ GtkAllocation allocation;
+ MateVolumeControlVolume *vol = MATE_VOLUME_CONTROL_VOLUME (widget);
+
+ /* clear background */
+ gtk_widget_get_allocation (widget, &allocation);
+ gdk_window_clear_area (gtk_widget_get_window (widget), 0, 0,
+ allocation.width,
+ allocation.height);
+
+ if (vol->track->num_channels > 1) {
+ gint x_offset, y_offset, height, width;
+ GtkRequisition scale_req, but_req;
+ GdkPoint points[3];
+ GtkStyle *style;
+ GtkStateType state;
+
+ /* request size of kids */
+ GTK_WIDGET_GET_CLASS (vol->button)->size_request (vol->button, &but_req);
+ GTK_WIDGET_GET_CLASS (vol->scales->data)->size_request (vol->scales->data,
+ &scale_req);
+
+ /* calculate */
+ gtk_widget_get_allocation (widget, &allocation);
+ x_offset = (allocation.width -
+ ((vol->track->num_channels * scale_req.width) +
+ (vol->track->num_channels - 1) * vol->padding)) / 2;
+ y_offset = allocation.height - but_req.height;
+ width = allocation.width - (2 * x_offset + but_req.width);
+ height = but_req.height / 2;
+ points[0].y = y_offset + 3;
+ points[1].y = points[2].y = points[0].y + height - 3;
+
+ /* draw chainbutton decorations */
+ style = gtk_widget_get_style (widget);
+ state = gtk_widget_get_state (widget);
+
+ points[0].x = points[1].x = x_offset + 3;
+ points[2].x = points[0].x + width - 6;
+ gtk_paint_polygon (style, gtk_widget_get_window (widget),
+ state,
+ GTK_SHADOW_ETCHED_IN,
+ &expose->area, widget, "hseparator",
+ points, 3, FALSE);
+
+ points[0].x = points[1].x = allocation.width - x_offset - 3;
+ points[2].x = points[0].x - width + 6;
+ gtk_paint_polygon (style, gtk_widget_get_window (widget),
+ state,
+ GTK_SHADOW_ETCHED_IN,
+ &expose->area, widget, "hseparator",
+ points, 3, FALSE);
+ }
+
+ /* take care of redrawing the kids */
+ return GTK_WIDGET_CLASS (mate_volume_control_volume_parent_class)->expose_event (widget, expose);
+}
+
+/*
+ * Signals handlers.
+ */
+
+static void
+cb_volume_changed (GtkAdjustment *_adj,
+ gpointer data)
+{
+ MateVolumeControlVolume *vol = data;
+ gint *volumes, i = 0;
+ GList *scales;
+
+ if (vol->locked)
+ return;
+ vol->locked = TRUE;
+ volumes = g_new (gint, vol->track->num_channels);
+
+ for (scales = vol->scales; scales != NULL; scales = scales->next) {
+ GtkAdjustment *adj = gtk_range_get_adjustment (scales->data);
+
+ if (mate_volume_control_button_get_active (
+ MATE_VOLUME_CONTROL_BUTTON (vol->button))) {
+ gtk_adjustment_set_value (adj, gtk_adjustment_get_value (_adj));
+ volumes[i++] = rint (gtk_adjustment_get_value (_adj));
+ } else {
+ volumes[i++] = rint (gtk_adjustment_get_value (adj));
+ }
+ }
+
+ gst_mixer_set_volume (vol->mixer, vol->track, volumes);
+
+ g_free (volumes);
+ vol->locked = FALSE;
+}
+
+static void
+cb_lock_toggled (GtkToggleButton *button,
+ gpointer data)
+{
+ MateVolumeControlVolume *vol = data;
+
+ if (mate_volume_control_button_get_active (
+ MATE_VOLUME_CONTROL_BUTTON (vol->button))) {
+ /* get the mean value, and set it on the first adjustment.
+ * the cb_volume_changed () callback will take care of the
+ * rest. */
+ gint volume = 0, num = 0;
+ GList *scales;
+
+ for (scales = vol->scales ; scales != NULL; scales = scales->next) {
+ GtkAdjustment *adj = gtk_range_get_adjustment (scales->data);
+
+ num++;
+ volume += gtk_adjustment_get_value (adj);
+ }
+
+ /* safety check */
+ if (vol->scales != NULL) {
+ gtk_adjustment_set_value (gtk_range_get_adjustment (vol->scales->data),
+ volume / num);
+ }
+ }
+}
+
+/*
+ * See if our volume is zero.
+ */
+
+void
+mate_volume_control_volume_ask (MateVolumeControlVolume * vol,
+ gboolean *real_zero, gboolean *slider_zero)
+{
+ GList *scales;
+ gint *volumes, n, tot = 0;
+
+ volumes = g_new (gint, vol->track->num_channels);
+ gst_mixer_get_volume (vol->mixer, vol->track, volumes);
+ for (n = 0; n < vol->track->num_channels; n++)
+ tot += volumes[n];
+ g_free (volumes);
+ *real_zero = (tot == 0);
+
+ *slider_zero = TRUE;
+ for (n = 0, scales = vol->scales;
+ scales != NULL; scales = scales->next, n++) {
+ GtkAdjustment *adj = gtk_range_get_adjustment (scales->data);
+
+ if (rint (gtk_adjustment_get_value (adj)) != 0) {
+ *slider_zero = FALSE;
+ break;
+ }
+ }
+}
+
+
+void
+mate_volume_control_volume_update (MateVolumeControlVolume *vol)
+{
+ gint *volumes, n;
+ GList *scales;
+
+ /* don't do callbacks */
+ if (vol->locked)
+ return;
+
+ vol->locked = TRUE;
+
+ volumes = g_new (gint, vol->track->num_channels);
+ gst_mixer_get_volume (vol->mixer, vol->track, volumes);
+
+ /* did we change? */
+ for (n = 0, scales = vol->scales;
+ scales != NULL; scales = scales->next, n++) {
+ GtkAdjustment *adj = gtk_range_get_adjustment (scales->data);
+
+ if ((gint) gtk_adjustment_get_value (adj) != volumes[n]) {
+ gtk_range_set_value (scales->data, volumes[n]);
+ }
+
+ /* should we release lock? */
+ if (volumes[n] != volumes[0]) {
+ mate_volume_control_button_set_active (
+ MATE_VOLUME_CONTROL_BUTTON (vol->button), FALSE);
+ }
+ }
+
+ g_free (volumes);
+ vol->locked = FALSE;
+}
+
+/*
+ * Timeout to check for volume changes.
+ */
+
+static gboolean
+cb_check (gpointer data)
+{
+ mate_volume_control_volume_update (data);
+
+ return TRUE;
+}
diff --git a/gst-mixer/src/volume.h b/gst-mixer/src/volume.h
new file mode 100644
index 0000000..678aab4
--- /dev/null
+++ b/gst-mixer/src/volume.h
@@ -0,0 +1,82 @@
+/* MATE Volume Control
+ * Copyright (C) 2003-2004 Ronald Bultje <[email protected]>
+ *
+ * volume.h: representation of a track's volume channels
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GVC_VOLUME_H__
+#define __GVC_VOLUME_H__
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gst/interfaces/mixer.h>
+
+G_BEGIN_DECLS
+
+#define MATE_VOLUME_CONTROL_TYPE_VOLUME \
+ (mate_volume_control_volume_get_type ())
+#define MATE_VOLUME_CONTROL_VOLUME(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), MATE_VOLUME_CONTROL_TYPE_VOLUME, \
+ MateVolumeControlVolume))
+#define MATE_VOLUME_CONTROL_VOLUME_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), MATE_VOLUME_CONTROL_TYPE_VOLUME, \
+ MateVolumeControlVolumeClass))
+#define MATE_VOLUME_CONTROL_IS_VOLUME(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MATE_VOLUME_CONTROL_TYPE_VOLUME))
+#define MATE_VOLUME_CONTROL_IS_VOLUME_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), MATE_VOLUME_CONTROL_TYPE_VOLUME))
+
+typedef struct _MateVolumeControlVolume {
+ GtkFixed parent;
+
+ /* track + mixer */
+ GstMixer *mixer;
+ GstMixerTrack *track;
+
+ /* padding */
+ gint padding;
+
+ /* childs */
+ GList *scales;
+ GtkWidget *button, *image;
+
+ /* this will be set to true if the user changes volumes
+ * in the mixer as a response to a user query. It prevents
+ * infinite loops. */
+ gboolean locked;
+
+ /* signal ID */
+ guint id;
+} MateVolumeControlVolume;
+
+typedef struct _MateVolumeControlVolumeClass {
+ GtkFixedClass klass;
+} MateVolumeControlVolumeClass;
+
+GType mate_volume_control_volume_get_type (void);
+GtkWidget * mate_volume_control_volume_new (GstMixer *mixer,
+ GstMixerTrack *track,
+ gint padding);
+void mate_volume_control_volume_ask (MateVolumeControlVolume *volume,
+ gboolean * real_zero,
+ gboolean * slider_zero);
+void mate_volume_control_volume_update (MateVolumeControlVolume *volume);
+
+G_END_DECLS
+
+#endif /* __GVC_VOLUME_H__ */
diff --git a/gst-mixer/src/window.c b/gst-mixer/src/window.c
new file mode 100644
index 0000000..19b9eed
--- /dev/null
+++ b/gst-mixer/src/window.c
@@ -0,0 +1,435 @@
+/* MATE Volume Control
+ * Copyright (C) 2003-2004 Ronald Bultje <[email protected]>
+ *
+ * window.c: main window
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <mateconf/mateconf-client.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "keys.h"
+#include "preferences.h"
+#include "window.h"
+
+G_DEFINE_TYPE (MateVolumeControlWindow, mate_volume_control_window, GTK_TYPE_WINDOW)
+
+void mate_volume_control_window_set_page(GtkWidget *widget, const gchar *page)
+{
+ MateVolumeControlWindow *win = MATE_VOLUME_CONTROL_WINDOW (widget);
+
+ if (g_ascii_strncasecmp(page, "playback",8) == 0)
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (win->el), 0);
+ else if (g_ascii_strncasecmp(page, "recording",9) == 0)
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (win->el), 1);
+ else if (g_ascii_strncasecmp(page, "switches",9) == 0)
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (win->el), 2);
+ else if (g_ascii_strncasecmp(page, "options",9) == 0)
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (win->el), 3);
+ else /* default is "playback" */
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (win->el), 0);
+}
+
+
+/*
+ * Menu actions.
+ */
+
+static void
+cb_change (GtkComboBox *widget,
+ MateVolumeControlWindow *win)
+{
+ gchar *device_name;
+
+ device_name = gtk_combo_box_get_active_text (widget);
+ g_return_if_fail (device_name != NULL);
+
+ mateconf_client_set_string (win->client, MATE_VOLUME_CONTROL_KEY_ACTIVE_ELEMENT, device_name, NULL);
+
+ g_free (device_name);
+}
+
+static void
+cb_exit (GtkAction *action,
+ MateVolumeControlWindow *win)
+{
+ gtk_widget_destroy (GTK_WIDGET (win));
+}
+
+static void
+cb_preferences_destroy (GtkWidget *widget,
+ MateVolumeControlWindow *win)
+{
+ win->prefs = NULL;
+}
+
+static void
+cb_preferences (GtkAction *action,
+ MateVolumeControlWindow *win)
+{
+
+ if (!win->prefs) {
+ win->prefs = mate_volume_control_preferences_new (GST_ELEMENT (win->el->mixer),
+ win->client);
+ g_signal_connect (win->prefs, "destroy", G_CALLBACK (cb_preferences_destroy), win);
+ gtk_widget_show (win->prefs);
+ } else {
+ gtk_window_present (GTK_WINDOW (win->prefs));
+ }
+}
+
+static void
+cb_help (GtkAction *action,
+ MateVolumeControlWindow *win)
+{
+ GdkScreen *screen;
+ GtkWidget *dialog;
+ GError *error = NULL;
+
+ screen = gtk_window_get_screen (GTK_WINDOW (win));
+
+ if (gtk_show_uri (screen, "ghelp:mate-volume-control", GDK_CURRENT_TIME,
+ &error) == FALSE) {
+ dialog = gtk_message_dialog_new (GTK_WINDOW (win), GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", error->message);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ g_error_free (error);
+ }
+}
+
+static void
+cb_show_about (MateVolumeControlWindow *win)
+{
+ const gchar *authors[] = { "Ronald Bultje <[email protected]>",
+ "Leif Johnson <[email protected]>",
+ NULL };
+ const gchar *documenters[] = { "Sun Microsystems",
+ NULL};
+
+ gtk_show_about_dialog (GTK_WINDOW (win),
+ "version", VERSION,
+ "copyright", "Copyright \xc2\xa9 2003-2004 Ronald Bultje",
+ "comments", _("A MATE/GStreamer-based volume control application"),
+ "authors", authors,
+ "documenters", documenters,
+ "translator-credits", _("translator-credits"),
+ "logo-icon-name", "multimedia-volume-control",
+ NULL);
+}
+
+static void
+window_change_mixer_element (MateVolumeControlWindow *win,
+ const gchar *el)
+{
+ const char *cur_el_str;
+ GList *item;
+
+ g_return_if_fail (win != NULL);
+ g_return_if_fail (el != NULL);
+
+ for (item = win->elements; item != NULL; item = item->next) {
+ cur_el_str = g_object_get_data (item->data, "mate-volume-control-name");
+
+ if (cur_el_str == NULL)
+ continue;
+
+ if (g_str_equal (cur_el_str, el)) {
+ GstElement *old_element = GST_ELEMENT (win->el->mixer);
+ gchar *title;
+
+ /* change element */
+ gst_element_set_state (item->data, GST_STATE_READY);
+ mate_volume_control_element_change (win->el, item->data);
+
+ if (win->prefs != NULL)
+ mate_volume_control_preferences_change (MATE_VOLUME_CONTROL_PREFERENCES (win->prefs),
+ item->data);
+
+ if (old_element != NULL)
+ gst_element_set_state (old_element, GST_STATE_NULL);
+
+ /* change window title */
+ title = g_strdup_printf (_("Volume Control: %s"), cur_el_str);
+ gtk_window_set_title (GTK_WINDOW (win), title);
+ g_free (title);
+
+ break;
+ }
+ }
+}
+
+static void
+cb_mateconf (MateConfClient *client,
+ guint connection_id,
+ MateConfEntry *entry,
+ gpointer data)
+{
+ g_return_if_fail (mateconf_entry_get_key (entry) != NULL);
+
+ if (g_str_equal (mateconf_entry_get_key (entry),
+ MATE_VOLUME_CONTROL_KEY_ACTIVE_ELEMENT)) {
+ window_change_mixer_element (MATE_VOLUME_CONTROL_WINDOW (data),
+ mateconf_value_get_string (mateconf_entry_get_value (entry)));
+ }
+}
+
+/*
+ * Signal handlers.
+ */
+
+#if 0
+static void
+cb_error (GstElement *element,
+ GstElement *source,
+ GError *error,
+ gchar *debug,
+ gpointer data)
+{
+ MateVolumeControlWindow *win = MATE_VOLUME_CONTROL_WINDOW (data);
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (win),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+ error->message);
+ gtk_widget_show (dialog);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+#endif
+
+static void
+mate_volume_control_window_dispose (GObject *object)
+{
+ MateVolumeControlWindow *win = MATE_VOLUME_CONTROL_WINDOW (object);
+
+ if (win->prefs) {
+ gtk_widget_destroy (win->prefs);
+ win->prefs = NULL;
+ }
+
+ /* clean up */
+ if (win->elements) {
+
+ g_list_foreach (win->elements, (GFunc) g_object_unref, NULL);
+ g_list_free (win->elements);
+ win->elements = NULL;
+ }
+
+ if (win->client) {
+ g_object_unref (win->client);
+ win->client = NULL;
+ }
+
+ G_OBJECT_CLASS (mate_volume_control_window_parent_class)->dispose (object);
+}
+
+
+static void
+mate_volume_control_window_class_init (MateVolumeControlWindowClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->dispose = mate_volume_control_window_dispose;
+}
+
+
+static void
+mate_volume_control_window_init (MateVolumeControlWindow *win)
+{
+ int width, height;
+
+ win->elements = NULL;
+ win->el = NULL;
+ win->client = mateconf_client_get_default ();
+ win->prefs = NULL;
+ win->use_default_mixer = FALSE;
+
+ g_set_application_name (_("Volume Control"));
+ gtk_window_set_title (GTK_WINDOW (win), _("Volume Control"));
+
+ /* To set the window according to previous geometry */
+ width = mateconf_client_get_int (win->client, PREF_UI_WINDOW_WIDTH, NULL);
+ if (width < 250)
+ width = 250;
+ height = mateconf_client_get_int (win->client, PREF_UI_WINDOW_HEIGHT, NULL);
+ if (height < 100)
+ height = -1;
+ gtk_window_set_default_size (GTK_WINDOW (win), width, height);
+}
+
+GtkWidget *
+mate_volume_control_window_new (GList *elements)
+{
+ gchar *active_el_str, *cur_el_str;
+ GstElement *active_element;
+ GList *item;
+ MateVolumeControlWindow *win;
+ GtkAccelGroup *accel_group;
+ GtkWidget *combo_box;
+ GtkWidget *label;
+ GtkWidget *hbox;
+ GtkWidget *buttons;
+ GtkWidget *el;
+ GtkWidget *prefsbtn;
+ GtkWidget *closebtn;
+ GtkWidget *helpbtn;
+ gint count = 0;
+ GtkWidget *vbox;
+ GtkCellRenderer *renderer;
+ gint active_element_num;
+
+ g_return_val_if_fail (elements != NULL, NULL);
+ active_element = NULL;
+
+ /* window */
+ win = g_object_new (MATE_VOLUME_CONTROL_TYPE_WINDOW, NULL);
+ win->elements = elements;
+
+ accel_group = gtk_accel_group_new ();
+
+ gtk_window_add_accel_group (GTK_WINDOW (win), accel_group);
+ gtk_accel_group_connect (accel_group, GDK_A, GDK_CONTROL_MASK, 0,
+ g_cclosure_new_swap (G_CALLBACK (cb_show_about), win, NULL));
+
+ /* get active element, if any (otherwise we use the default) */
+ active_el_str = mateconf_client_get_string (win->client,
+ MATE_VOLUME_CONTROL_KEY_ACTIVE_ELEMENT,
+ NULL);
+ if (active_el_str != NULL && *active_el_str != '\0') {
+ for (count = 0, item = elements; item != NULL; item = item->next, count++) {
+ cur_el_str = g_object_get_data (item->data, "mate-volume-control-name");
+ if (cur_el_str == NULL)
+ continue;
+
+ if (g_str_equal (active_el_str, cur_el_str)) {
+ active_element = item->data;
+ break;
+ }
+ }
+ g_free (active_el_str);
+ if (!item) {
+ count = 0;
+ active_element = elements->data;
+ /* If there's a default but it doesn't match what we have available,
+ * reset the default */
+ mateconf_client_set_string (win->client,
+ MATE_VOLUME_CONTROL_KEY_ACTIVE_ELEMENT,
+ g_object_get_data (G_OBJECT (active_element),
+ "mate-volume-control-name"),
+ NULL);
+ }
+ /* default element to first */
+ if (!active_element)
+ active_element = elements->data;
+ } else {
+ count = 0;
+ active_element = elements->data;
+ }
+ active_element_num = count;
+
+ combo_box = gtk_combo_box_new_text ();
+ renderer = gtk_cell_renderer_text_new ();
+ g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+ gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo_box));
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE);
+ gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box), renderer, "text", 0);
+ for (count = 0, item = elements; item != NULL; item = item->next, count++) {
+ const gchar *name;
+
+ name = g_object_get_data (item->data, "mate-volume-control-name");
+ gtk_combo_box_append_text(GTK_COMBO_BOX (combo_box), name);
+ }
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), active_element_num);
+ g_signal_connect (combo_box, "changed", G_CALLBACK (cb_change), win);
+
+
+ /* mateconf */
+ mateconf_client_add_dir (win->client, MATE_VOLUME_CONTROL_KEY_DIR,
+ MATECONF_CLIENT_PRELOAD_RECURSIVE, NULL);
+ mateconf_client_notify_add (win->client, MATE_VOLUME_CONTROL_KEY_DIR,
+ cb_mateconf, win, NULL, NULL);
+
+ win->use_default_mixer = (active_el_str == NULL);
+
+ /* add the combo box to choose the device */
+ label = gtk_label_new (NULL);
+ gtk_label_set_text_with_mnemonic (GTK_LABEL (label), _("_Device: "));
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo_box);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), combo_box, TRUE, TRUE, 0);
+
+ /* add content for this element */
+ el = mate_volume_control_element_new (win->client);
+ win->el = MATE_VOLUME_CONTROL_ELEMENT (el);
+
+ /* create the buttons box */
+ helpbtn = gtk_button_new_from_stock (GTK_STOCK_HELP);
+ prefsbtn = gtk_button_new_from_stock (GTK_STOCK_PREFERENCES);
+ closebtn = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
+ g_signal_connect (helpbtn, "clicked", G_CALLBACK (cb_help), win);
+ g_signal_connect (prefsbtn, "clicked", G_CALLBACK (cb_preferences), win);
+ g_signal_connect (closebtn, "clicked", G_CALLBACK (cb_exit), win);
+ gtk_widget_add_accelerator (closebtn, "clicked", accel_group,
+ GDK_Escape, 0, 0);
+ gtk_widget_add_accelerator (helpbtn, "clicked", accel_group,
+ GDK_F1, 0, 0);
+ buttons = gtk_hbutton_box_new ();
+ gtk_box_pack_start (GTK_BOX (buttons), helpbtn, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (buttons), prefsbtn, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (buttons), closebtn, FALSE, FALSE, 0);
+ gtk_box_set_spacing (GTK_BOX (buttons), 6);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (buttons), GTK_BUTTONBOX_END);
+ gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (buttons), helpbtn, TRUE);
+
+ /* Put the the elements in a vbox */
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER(win), vbox);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (vbox), el, TRUE, TRUE, 6);
+ gtk_box_pack_start (GTK_BOX (vbox), buttons, FALSE, FALSE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
+
+ /* set tooltips */
+ gtk_widget_set_tooltip_text (combo_box, _("Control volume on a different device"));
+
+ gtk_widget_show_all (GTK_WIDGET (win));
+
+ /* refresh the control and window title with the default mixer */
+ window_change_mixer_element (win, g_object_get_data (G_OBJECT (active_element),
+ "mate-volume-control-name"));
+
+ /* FIXME:
+ * - set error handler (cb_error) after device activation:
+ * g_signal_connect (element, "error", G_CALLBACK (cb_error), win);.
+ * - on device change: reset error handler, change menu (in case this
+ * was done outside the UI).
+ */
+
+ return GTK_WIDGET (win);
+}
+
+
diff --git a/gst-mixer/src/window.h b/gst-mixer/src/window.h
new file mode 100644
index 0000000..e108d75
--- /dev/null
+++ b/gst-mixer/src/window.h
@@ -0,0 +1,75 @@
+/* MATE Volume Control
+ * Copyright (C) 2003-2004 Ronald Bultje <[email protected]>
+ *
+ * window.h: main window
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GVC_WINDOW_H__
+#define __GVC_WINDOW_H__
+
+#include <glib.h>
+#include <mateconf/mateconf-client.h>
+#include <gst/gst.h>
+
+#include "element.h"
+
+G_BEGIN_DECLS
+
+#define MATE_VOLUME_CONTROL_TYPE_WINDOW \
+ (mate_volume_control_window_get_type ())
+#define MATE_VOLUME_CONTROL_WINDOW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), MATE_VOLUME_CONTROL_TYPE_WINDOW, \
+ MateVolumeControlWindow))
+#define MATE_VOLUME_CONTROL_WINDOW_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), MATE_VOLUME_CONTROL_TYPE_WINDOW, \
+ MateVolumeControlWindowClass))
+#define MATE_VOLUME_CONTROL_IS_WINDOW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MATE_VOLUME_CONTROL_TYPE_WINDOW))
+#define MATE_VOLUME_CONTROL_IS_WINDOW_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), MATE_VOLUME_CONTROL_TYPE_WINDOW))
+
+typedef struct {
+ GtkWindow parent;
+
+ /* element list */
+ GList *elements;
+
+ /* mateconf client */
+ MateConfClient *client;
+
+ /* contents */
+ MateVolumeControlElement *el;
+
+ /* preferences window, if opened */
+ GtkWidget *prefs;
+
+ /* use default mixer */
+ gboolean use_default_mixer;
+} MateVolumeControlWindow;
+
+typedef struct {
+ GtkWindowClass klass;
+} MateVolumeControlWindowClass;
+
+GType mate_volume_control_window_get_type (void);
+GtkWidget * mate_volume_control_window_new (GList *elements);
+void mate_volume_control_window_set_page (GtkWidget *win, const gchar *page);
+
+G_END_DECLS
+
+#endif /* __GVC_WINDOW_H__ */