summaryrefslogtreecommitdiff
path: root/grecord/src
diff options
context:
space:
mode:
authorStefano Karapetsas <[email protected]>2011-12-11 13:11:15 +0100
committerStefano Karapetsas <[email protected]>2011-12-11 13:11:15 +0100
commit4ee2559eaaf2a94ac26c265517e9604a72729360 (patch)
treef24e3e3294c2b75819755289e592bf2e28e668c4 /grecord/src
downloadmate-media-4ee2559eaaf2a94ac26c265517e9604a72729360.tar.bz2
mate-media-4ee2559eaaf2a94ac26c265517e9604a72729360.tar.xz
moved from Mate-Extra
Diffstat (limited to 'grecord/src')
-rw-r--r--grecord/src/Makefile.am30
-rw-r--r--grecord/src/Makefile.in667
-rw-r--r--grecord/src/gsr-window.c2759
-rw-r--r--grecord/src/gsr-window.h61
-rw-r--r--grecord/src/mate-recorder.c232
-rw-r--r--grecord/src/ui.xml41
6 files changed, 3790 insertions, 0 deletions
diff --git a/grecord/src/Makefile.am b/grecord/src/Makefile.am
new file mode 100644
index 0000000..58800fa
--- /dev/null
+++ b/grecord/src/Makefile.am
@@ -0,0 +1,30 @@
+## Process this file with automake to produce Makefile.in
+
+AM_CPPFLAGS = \
+ -DMATELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/grecord/src/recent-files/ \
+ $(GSR_CFLAGS) \
+ $(DISABLE_DEPRECATED) \
+ -DDATADIR=\""$(datadir)"\" \
+ -DGSR_DATADIR=\""$(datadir)/mate-sound-recorder"\" \
+ -DGSR_UIDIR=\""$(datadir)/mate-sound-recorder/ui/"\"
+
+bin_PROGRAMS = mate-sound-recorder
+
+mate_sound_recorder_SOURCES = \
+ mate-recorder.c \
+ gsr-window.c \
+ gsr-window.h
+
+uidir = $(datadir)/mate-sound-recorder/ui
+ui_DATA = ui.xml
+
+EXTRA_DIST = $(ui_DATA)
+
+mate_sound_recorder_LDADD = \
+ -lm \
+ $(GSR_LIBS) -lgstinterfaces-@GST_MAJORMINOR@ \
+ $(top_builddir)/profiles/libmate-media-profiles.la
+
+-include $(top_srcdir)/git.mk
diff --git a/grecord/src/Makefile.in b/grecord/src/Makefile.in
new file mode 100644
index 0000000..b6db1f8
--- /dev/null
+++ b/grecord/src/Makefile.in
@@ -0,0 +1,667 @@
+# 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-sound-recorder$(EXEEXT)
+subdir = grecord/src
+DIST_COMMON = $(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)" "$(DESTDIR)$(uidir)"
+PROGRAMS = $(bin_PROGRAMS)
+am_mate_sound_recorder_OBJECTS = mate-recorder.$(OBJEXT) \
+ gsr-window.$(OBJEXT)
+mate_sound_recorder_OBJECTS = $(am_mate_sound_recorder_OBJECTS)
+am__DEPENDENCIES_1 =
+mate_sound_recorder_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(top_builddir)/profiles/libmate-media-profiles.la
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+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_sound_recorder_SOURCES)
+DIST_SOURCES = $(mate_sound_recorder_SOURCES)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+DATA = $(ui_DATA)
+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@
+AM_CPPFLAGS = \
+ -DMATELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/grecord/src/recent-files/ \
+ $(GSR_CFLAGS) \
+ $(DISABLE_DEPRECATED) \
+ -DDATADIR=\""$(datadir)"\" \
+ -DGSR_DATADIR=\""$(datadir)/mate-sound-recorder"\" \
+ -DGSR_UIDIR=\""$(datadir)/mate-sound-recorder/ui/"\"
+
+mate_sound_recorder_SOURCES = \
+ mate-recorder.c \
+ gsr-window.c \
+ gsr-window.h
+
+uidir = $(datadir)/mate-sound-recorder/ui
+ui_DATA = ui.xml
+EXTRA_DIST = $(ui_DATA)
+mate_sound_recorder_LDADD = \
+ -lm \
+ $(GSR_LIBS) -lgstinterfaces-@GST_MAJORMINOR@ \
+ $(top_builddir)/profiles/libmate-media-profiles.la
+
+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 grecord/src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign grecord/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-sound-recorder$(EXEEXT): $(mate_sound_recorder_OBJECTS) $(mate_sound_recorder_DEPENDENCIES)
+ @rm -f mate-sound-recorder$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(mate_sound_recorder_OBJECTS) $(mate_sound_recorder_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gsr-window.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate-recorder.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
+install-uiDATA: $(ui_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(uidir)" || $(MKDIR_P) "$(DESTDIR)$(uidir)"
+ @list='$(ui_DATA)'; test -n "$(uidir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(uidir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(uidir)" || exit $$?; \
+ done
+
+uninstall-uiDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(ui_DATA)'; test -n "$(uidir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(uidir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(uidir)" && rm -f $$files
+
+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) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(uidir)"; 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-uiDATA
+
+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 uninstall-uiDATA
+
+.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 install-uiDATA 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 uninstall-uiDATA
+
+
+-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/grecord/src/gsr-window.c b/grecord/src/gsr-window.c
new file mode 100644
index 0000000..4d50a44
--- /dev/null
+++ b/grecord/src/gsr-window.c
@@ -0,0 +1,2759 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Iain Holmes <[email protected]>
+ * Johan Dahlin <[email protected]>
+ * Tim-Philipp Müller <tim centricular net>
+ *
+ * Copyright 2002 Iain Holmes
+ *
+ * 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.
+ *
+ * 4th Februrary 2005: Christian Schaller: changed license to LGPL with
+ * permission of Iain Holmes, Ronald Bultje, Leontine Binchy (SUN), Johan Dalhin
+ * and Joe Marcus Clarke
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <math.h>
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <mateconf/mateconf-client.h>
+#include <gst/gst.h>
+#include <gst/interfaces/mixer.h>
+
+#include <profiles/mate-media-profiles.h>
+
+#include "gsr-window.h"
+
+GST_DEBUG_CATEGORY_STATIC (gsr_debug);
+#define GST_CAT_DEFAULT gsr_debug
+
+extern GtkWidget * gsr_open_window (const char *filename);
+extern void gsr_quit (void);
+
+extern MateConfClient *mateconf_client;
+
+extern void gsr_add_recent (gchar *filename);
+
+#define MATECONF_DIR "/apps/mate-sound-recorder/"
+#define KEY_OPEN_DIR MATECONF_DIR "system-state/open-file-directory"
+#define KEY_SAVE_DIR MATECONF_DIR "system-state/save-file-directory"
+#define KEY_LAST_PROFILE_ID MATECONF_DIR "last-profile-id"
+#define KEY_LAST_INPUT MATECONF_DIR "last-input"
+#define EBUSY_TRY_AGAIN 3 /* Empirical data */
+
+typedef struct _GSRWindowPipeline {
+ GstElement *pipeline;
+ GstState state; /* last seen (async) pipeline state */
+ GstBus *bus;
+
+ GstElement *src;
+ GstElement *sink;
+
+ guint tick_id;
+} GSRWindowPipeline;
+
+enum {
+ PROP_0,
+ PROP_LOCATION
+};
+
+static GtkWindowClass *parent_class = NULL;
+
+#define GSR_WINDOW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), GSR_TYPE_WINDOW, GSRWindowPrivate))
+
+struct _GSRWindowPrivate {
+ GtkWidget *main_vbox;
+ GtkWidget *scale;
+ GtkWidget *profile, *input;
+ GtkWidget *rate, *time_sec, *format, *channels;
+ GtkWidget *input_label;
+ GtkWidget *name_label;
+ GtkWidget *length_label;
+ GtkWidget *align;
+ GtkWidget *volume_label;
+ GtkWidget *level;
+
+ gulong seek_id;
+
+ GtkUIManager *ui_manager;
+ GtkActionGroup *action_group;
+ GtkWidget *recent_view;
+ GtkRecentFilter *recent_filter;
+
+ /* statusbar */
+ GtkWidget *statusbar;
+ guint status_message_cid;
+ guint tip_message_cid;
+
+ /* Pipelines */
+ GSRWindowPipeline *play;
+ GSRWindowPipeline *record;
+ char *record_filename;
+ char *filename;
+ char *extension;
+ char *working_file; /* Working file: Operations only occur on the
+ working file. The result of that operation then
+ becomes the new working file. */
+ int record_fd;
+
+ /* File info */
+ int len_secs; /* In seconds */
+ int get_length_attempts;
+
+ /* ATOMIC access */
+ struct {
+ gint n_channels;
+ gint bitrate;
+ gint samplerate;
+ } atomic;
+
+ gboolean has_file;
+ gboolean saved;
+ gboolean dirty;
+ gboolean seek_in_progress;
+
+ gboolean quit_after_save;
+
+ guint32 tick_id; /* tick_callback timeout ID */
+ guint32 record_id; /* record idle callback timeout ID */
+
+ GstElement *ebusy_pipeline; /* which pipeline we're trying to start */
+ guint ebusy_timeout_id;
+
+ GstElement *source;
+ GstMixer *mixer;
+};
+
+static gboolean make_record_source (GSRWindow *window);
+static void fill_record_input (GSRWindow *window, gchar *selected);
+static GSRWindowPipeline * make_record_pipeline (GSRWindow *window);
+static GSRWindowPipeline * make_play_pipeline (GSRWindow *window);
+
+static void
+show_error_dialog (GtkWindow *window,
+ const gchar *debug_message,
+ const gchar *format, ...) G_GNUC_PRINTF (3,4);
+
+static void
+show_error_dialog (GtkWindow *win, const gchar *dbg, const gchar * format, ...)
+{
+ GtkWidget *dialog;
+ va_list args;
+ gchar *s;
+
+ va_start (args, format);
+ s = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ dialog = gtk_message_dialog_new (win,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "%s",
+ s);
+
+ if (dbg != NULL) {
+ g_printerr ("ERROR: %s\nDEBUG MESSAGE: %s\n", s, dbg);
+ }
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ g_free (s);
+}
+
+static void
+show_missing_known_element_error (GtkWindow *win, gchar *description,
+ gchar *element, gchar *plugin, gchar *module)
+{
+ show_error_dialog (win, NULL,
+ _("Could not create the GStreamer %s element.\n"
+ "Please install the '%s' plugin from the '%s' module.\n"
+ "Verify that the installation is correct by running\n"
+ " gst-inspect-0.10 %s\n"
+ "and then restart mate-sound-recorder."),
+ description, plugin, module, element);
+}
+
+static void
+show_profile_error (GtkWindow *win, gchar *debug, gchar *description,
+ const char *profile)
+{
+ gchar *first;
+
+ first = g_strdup_printf (description, profile);
+ show_error_dialog (win, debug, "%s%s", first,
+ _("Please verify its settings.\n"
+ "You may be missing the necessary plugins."));
+ g_free (first);
+}
+/* Why do we need this? when a bin changes from READY => NULL state, its
+ * bus is set to flushing and we're unlikely to ever see any of its messages
+ * if the bin's state reaches NULL before we/the watch in the main thread
+ * collects them. That's why we set the state to READY first, process all
+ * messages 'manually', and then finally set it to NULL. This makes sure
+ * our state-changed handler actually gets to see all the state changes */
+
+static void
+set_pipeline_state_to_null (GstElement *pipeline)
+{
+ GstMessage *msg;
+ GstState cur_state, pending;
+ GstBus *bus;
+
+ gst_element_get_state (pipeline, &cur_state, &pending, 0);
+
+ if (cur_state == GST_STATE_NULL && pending == GST_STATE_VOID_PENDING)
+ return;
+
+ if (cur_state == GST_STATE_NULL && pending != GST_STATE_VOID_PENDING) {
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+ return;
+ }
+
+ gst_element_set_state (pipeline, GST_STATE_READY);
+ gst_element_get_state (pipeline, NULL, NULL, -1);
+
+ bus = gst_element_get_bus (pipeline);
+ while ((msg = gst_bus_pop (bus))) {
+ gst_bus_async_signal_func (bus, msg, NULL);
+ }
+ gst_object_unref (bus);
+
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+ /* maybe we should be paranoid and do _get_state() and check for
+ * the return value here, but then errors in shutdown should be
+ * rather unlikely */
+}
+
+
+static void
+shutdown_pipeline (GSRWindowPipeline *pipe)
+{
+ gst_bus_set_flushing (pipe->bus, TRUE);
+ gst_bus_remove_signal_watch (pipe->bus);
+ gst_element_set_state (pipe->pipeline, GST_STATE_NULL);
+ gst_object_unref (pipe->pipeline);
+ gst_object_unref (pipe->bus);
+}
+
+static char *
+seconds_to_string (guint seconds)
+{
+ int hour, min, sec;
+
+ min = (seconds / 60);
+ hour = min / 60;
+ min -= (hour * 60);
+ sec = seconds - ((hour * 3600) + (min * 60));
+
+ if (hour > 0) {
+ return g_strdup_printf ("%d:%02d:%02d", hour, min, sec);
+ } else {
+ return g_strdup_printf ("%d:%02d", min, sec);
+ }
+}
+
+static char *
+seconds_to_full_string (guint seconds)
+{
+ long days, hours, minutes;
+ char *time = NULL;
+ const char *minutefmt;
+ const char *hourfmt;
+ const char *secondfmt;
+
+ days = seconds / (60 * 60 * 24);
+ hours = (seconds / (60 * 60));
+ minutes = (seconds / 60) - ((days * 24 * 60) + (hours * 60));
+ seconds = seconds % 60;
+
+ minutefmt = ngettext ("%ld minute", "%ld minutes", minutes);
+ hourfmt = ngettext ("%ld hour", "%ld hours", hours);
+ secondfmt = ngettext ("%ld second", "%ld seconds", seconds);
+
+ if (hours > 0) {
+ if (minutes > 0)
+ if (seconds > 0) {
+ char *fmt;
+ /* Translators: the format is "X hours, X minutes and X seconds" */
+ fmt = g_strdup_printf (_("%s, %s and %s"), hourfmt, minutefmt, secondfmt);
+ time = g_strdup_printf (fmt, hours, minutes, seconds);
+ g_free (fmt);
+ } else {
+ char *fmt;
+ /* Translators: the format is "X hours and X minutes" */
+ fmt = g_strdup_printf (_("%s and %s"), hourfmt, minutefmt);
+ time = g_strdup_printf (fmt, hours, minutes);
+ g_free (fmt);
+ }
+ else
+ if (seconds > 0) {
+ char *fmt;
+ /* Translators: the format is "X minutes and X seconds" */
+ fmt = g_strdup_printf (_("%s and %s"), minutefmt, secondfmt);
+ time = g_strdup_printf (fmt, minutes, seconds);
+ g_free (fmt);
+ } else {
+ time = g_strdup_printf (minutefmt, minutes);
+ }
+ } else {
+ if (minutes > 0) {
+ if (seconds > 0) {
+ char *fmt;
+ /* Translators: the format is "X minutes and X seconds" */
+ fmt = g_strdup_printf (_("%s and %s"), minutefmt, secondfmt);
+ time = g_strdup_printf (fmt, minutes, seconds);
+ g_free (fmt);
+ } else {
+ time = g_strdup_printf (minutefmt, minutes);
+ }
+
+ } else {
+ time = g_strdup_printf (secondfmt, seconds);
+ }
+ }
+
+ return time;
+}
+
+static void
+set_action_sensitive (GSRWindow *window,
+ const char *name,
+ gboolean sensitive)
+{
+ GtkAction *action = gtk_action_group_get_action (window->priv->action_group,
+ name);
+ gtk_action_set_sensitive (action, sensitive);
+}
+
+static void
+file_new_cb (GtkAction *action,
+ GSRWindow *window)
+{
+ gsr_open_window (NULL);
+}
+
+static void
+file_open_cb (GtkAction *action,
+ GSRWindow *window)
+{
+ GtkWidget *file_chooser;
+ gchar *directory;
+ gchar *locale_directory = NULL;
+ gint response;
+
+ g_return_if_fail (GSR_IS_WINDOW (window));
+
+ file_chooser = gtk_file_chooser_dialog_new (_("Open a File"),
+ GTK_WINDOW (window),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_OK,
+ NULL);
+
+ directory = mateconf_client_get_string (mateconf_client, KEY_OPEN_DIR, NULL);
+
+ if (directory != NULL && *directory != 0) {
+ locale_directory = g_filename_from_utf8 (directory, -1, NULL, NULL, NULL);
+ if (!locale_directory || !g_file_test (locale_directory, G_FILE_TEST_EXISTS))
+ locale_directory = g_strdup (directory);
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (file_chooser),
+ locale_directory);
+ g_free (locale_directory);
+ }
+
+ response = gtk_dialog_run (GTK_DIALOG (file_chooser));
+
+ if (response == GTK_RESPONSE_OK) {
+ gchar *name;
+ gchar *utf8_name = NULL;
+
+ name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_chooser));
+ if (name) {
+ gchar *dirname;
+
+ utf8_name = g_filename_to_utf8 (name, -1, NULL, NULL, NULL);
+ dirname = g_path_get_dirname (utf8_name);
+ mateconf_client_set_string (mateconf_client, KEY_OPEN_DIR, dirname, NULL);
+ g_free (dirname);
+ g_free (utf8_name);
+
+ if (window->priv->has_file == TRUE) {
+ /* Just open a new window with the file */
+ gsr_open_window (name);
+ } else {
+ /* Set the file in this window */
+ g_object_set (G_OBJECT (window), "location", name, NULL);
+ window->priv->dirty = FALSE;
+ }
+
+ g_free (name);
+ }
+ }
+
+ gtk_widget_destroy (file_chooser);
+ g_free (directory);
+}
+
+static void
+file_open_recent_cb (GtkRecentChooser *chooser,
+ GSRWindow *window)
+{
+ gchar *uri;
+ gchar *filename;
+
+ uri = gtk_recent_chooser_get_current_uri (chooser);
+ g_return_if_fail (uri != NULL);
+
+ if (!g_str_has_prefix (uri, "file://"))
+ return;
+
+ filename = g_filename_from_uri (uri, NULL, NULL);
+ if (filename == NULL)
+ goto out;
+
+ if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
+ gchar *filename_utf8;
+ GtkWidget *dlg;
+
+ filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
+ dlg = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Unable to load file:\n%s"), filename_utf8);
+
+ gtk_widget_show (dlg);
+ gtk_dialog_run (GTK_DIALOG (dlg));
+ gtk_widget_destroy (dlg);
+
+ gtk_recent_manager_remove_item (gtk_recent_manager_get_default (), uri, NULL);
+
+ g_free (filename_utf8);
+ goto out;
+ }
+
+ if (window->priv->has_file == TRUE) {
+ /* Just open a new window with the file */
+ gsr_open_window (filename);
+ } else {
+ /* Set the file in this window */
+ g_object_set (G_OBJECT (window), "location", filename, NULL);
+ window->priv->dirty = FALSE;
+ }
+
+ out:
+ g_free (filename);
+ g_free (uri);
+}
+
+#if 0
+static gboolean
+cb_iterate (GstBin *bin,
+ gpointer data)
+{
+ src = gst_element_get_child (bin, "sink");
+ sink = gst_element_get_child (bin, "sink");
+
+ if (src && sink) {
+ gint64 pos, tot, enc;
+ GstFormat fmt = GST_FORMAT_BYTES;
+
+ gst_element_query (src, GST_QUERY_POSITION, &fmt, &pos);
+ gst_element_query (src, GST_QUERY_TOTAL, &fmt, &tot);
+ gst_element_query (sink, GST_QUERY_POSITION, &fmt, &enc);
+
+ g_print ("Iterate: %lld/%lld -> %lld\n", pos, tot, enc);
+ } else
+ g_print ("Iterate ?\n");
+
+ /* we don't do anything here */
+ return FALSE;
+}
+#endif
+
+static gboolean
+handle_ebusy_error (GSRWindow *window)
+{
+ g_return_val_if_fail (window->priv->ebusy_pipeline != NULL, FALSE);
+
+ gst_element_set_state (window->priv->ebusy_pipeline, GST_STATE_NULL);
+ gst_element_get_state (window->priv->ebusy_pipeline, NULL, NULL, -1);
+ gst_element_set_state (window->priv->ebusy_pipeline, GST_STATE_PLAYING);
+
+ /* Try only once */
+ return FALSE;
+}
+
+static GstElement *
+notgst_element_get_toplevel (GstElement * element)
+{
+ g_return_val_if_fail (element != NULL, NULL);
+ g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
+
+ do {
+ GstElement *parent;
+
+ parent = (GstElement *) gst_element_get_parent (element);
+
+ if (parent == NULL)
+ break;
+
+ gst_object_unref (parent);
+ element = parent;
+ } while (1);
+
+ return element;
+}
+
+static void
+pipeline_error_cb (GstBus * bus, GstMessage * msg, GSRWindow * window)
+{
+ GstElement *pipeline;
+ GError *error = NULL;
+ gchar *dbg = NULL;
+
+ g_return_if_fail (GSR_IS_WINDOW (window));
+
+ gst_message_parse_error (msg, &error, &dbg);
+ g_return_if_fail (error != NULL);
+
+ pipeline = notgst_element_get_toplevel (GST_ELEMENT (msg->src));
+
+ if (error->code == GST_RESOURCE_ERROR_BUSY) {
+ if (window->priv->ebusy_timeout_id == 0) {
+ set_action_sensitive (window, "FileSave", FALSE);
+ set_action_sensitive (window, "FileSaveAs", FALSE);
+ set_action_sensitive (window, "Play", FALSE);
+ set_action_sensitive (window, "Record", FALSE);
+
+ window->priv->ebusy_pipeline = pipeline;
+
+ window->priv->ebusy_timeout_id =
+ g_timeout_add_seconds (EBUSY_TRY_AGAIN,
+ (GSourceFunc) handle_ebusy_error,
+ window);
+
+ g_error_free (error);
+ g_free (dbg);
+ return;
+ }
+ }
+
+ if (window->priv->ebusy_timeout_id) {
+ g_source_remove (window->priv->ebusy_timeout_id);
+ window->priv->ebusy_timeout_id = 0;
+ window->priv->ebusy_pipeline = NULL;
+ }
+
+
+ /* set pipeline to NULL before showing error dialog to make sure
+ * the audio device is freed, in case any accessability software
+ * wants to make use of it to read out the error message */
+ set_pipeline_state_to_null (pipeline);
+
+ show_error_dialog (GTK_WINDOW (window), dbg, "%s", error->message);
+
+ gdk_window_set_cursor (gtk_widget_get_window (window->priv->main_vbox), NULL);
+
+ set_action_sensitive (window, "Stop", FALSE);
+ set_action_sensitive (window, "Play", TRUE);
+ set_action_sensitive (window, "Record", TRUE);
+ set_action_sensitive (window, "FileSave", TRUE);
+ set_action_sensitive (window, "FileSaveAs", TRUE);
+ gtk_widget_set_sensitive (window->priv->scale, TRUE);
+
+ gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
+ window->priv->status_message_cid);
+ gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar),
+ window->priv->status_message_cid,
+ _("Ready"));
+
+ g_error_free (error);
+ g_free (dbg);
+}
+
+static GtkWidget *
+gsr_dialog_add_button (GtkDialog *dialog,
+ const gchar *text,
+ const gchar *stock_id,
+ gint response_id)
+{
+ GtkWidget *button;
+
+ g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
+ g_return_val_if_fail (text != NULL, NULL);
+ g_return_val_if_fail (stock_id != NULL, NULL);
+
+ button = gtk_button_new_with_mnemonic (text);
+ gtk_button_set_image (GTK_BUTTON (button),
+ gtk_image_new_from_stock (stock_id,
+ GTK_ICON_SIZE_BUTTON));
+
+ gtk_widget_set_can_default (button, TRUE);
+
+ gtk_widget_show (button);
+
+ gtk_dialog_add_action_widget (dialog, button, response_id);
+
+ return button;
+}
+
+static gboolean
+replace_dialog (GtkWindow *parent,
+ const gchar *message,
+ const gchar *file_name)
+{
+ GtkWidget *message_dialog;
+ gint ret;
+
+ g_return_val_if_fail (file_name != NULL, FALSE);
+
+ message_dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ message,
+ file_name);
+ /* Add cancel button */
+ gtk_dialog_add_button (GTK_DIALOG (message_dialog),
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL);
+ /* Add replace button */
+ gsr_dialog_add_button (GTK_DIALOG (message_dialog), _("_Replace"),
+ GTK_STOCK_REFRESH,
+ GTK_RESPONSE_YES);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (message_dialog), GTK_RESPONSE_CANCEL);
+ gtk_window_set_resizable (GTK_WINDOW (message_dialog), FALSE);
+ ret = gtk_dialog_run (GTK_DIALOG (message_dialog));
+ gtk_widget_destroy (GTK_WIDGET (message_dialog));
+
+ return (ret == GTK_RESPONSE_YES);
+}
+
+static gboolean
+replace_existing_file (GtkWindow *parent,
+ const gchar *file_name)
+{
+ return replace_dialog (parent,
+ _("A file named \"%s\" already exists. \n"
+ "Do you want to replace it with the "
+ "one you are saving?"),
+ file_name);
+}
+
+static void
+do_save_file (GSRWindow *window,
+ const char *_name)
+{
+ GSRWindowPrivate *priv;
+ char *name;
+ GFile *src, *dst;
+ GError *error = NULL;
+
+ priv = window->priv;
+
+ if (window->priv->extension == NULL ||
+ g_str_has_suffix (_name, window->priv->extension))
+ name = g_strdup (_name);
+ else
+ name = g_strdup_printf ("%s.%s", _name,
+ window->priv->extension);
+ if (g_file_test (name, G_FILE_TEST_EXISTS)) {
+ char *utf8_name;
+ utf8_name = g_filename_to_utf8 (name, -1, NULL, NULL, NULL);
+ if (!replace_existing_file (GTK_WINDOW (window), utf8_name)) {
+ g_free (utf8_name);
+ return;
+ }
+ g_free (utf8_name);
+ }
+ src = g_file_new_for_path(priv->record_filename);
+ dst = g_file_new_for_path(name);
+
+ /* TODO: Show progress? Where? */
+ if (g_file_copy(src, dst, G_FILE_COPY_OVERWRITE,
+ NULL, NULL, NULL, &error)) {
+ g_object_set (G_OBJECT (window), "location", name, NULL);
+ priv->dirty = FALSE;
+ window->priv->saved = TRUE;
+ if (window->priv->quit_after_save == TRUE) {
+ gsr_window_close (window);
+ }
+ } else {
+ char *utf8_name;
+ utf8_name = g_filename_to_utf8 (name, -1, NULL, NULL, NULL);
+ show_error_dialog (GTK_WINDOW (window), NULL,
+ _("Could not save the file \"%s\""), utf8_name);
+ g_free (utf8_name);
+ }
+
+ g_object_unref(src);
+ g_object_unref(dst);
+ g_free (name);
+}
+
+static void
+file_save_as_cb (GtkAction *action,
+ GSRWindow *window)
+{
+ GtkWidget *file_chooser;
+ gchar *directory;
+ gchar *locale_directory = NULL;
+ gint response;
+
+ g_return_if_fail (GSR_IS_WINDOW (window));
+
+ file_chooser = gtk_file_chooser_dialog_new (_("Save file as"),
+ GTK_WINDOW (window),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_OK,
+ NULL);
+
+ directory = mateconf_client_get_string (mateconf_client, KEY_SAVE_DIR, NULL);
+ if (directory != NULL && *directory != 0) {
+ locale_directory = g_filename_from_utf8 (directory, -1, NULL, NULL, NULL);
+ if (!locale_directory || !g_file_test (locale_directory, G_FILE_TEST_EXISTS))
+ locale_directory = g_strdup (directory);
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (file_chooser), locale_directory);
+ g_free (locale_directory);
+ }
+ g_free (directory);
+
+ if (window->priv->filename != NULL) {
+ char *locale_basename;
+ char *basename = NULL;
+ gchar *filename, *filename_ext, *extension;
+ gint length;
+
+ locale_basename = g_path_get_basename (window->priv->filename);
+ basename = g_filename_to_utf8 (locale_basename, -1, NULL, NULL, NULL);
+ length = strlen (basename);
+ extension = g_strrstr (basename, ".");
+
+ if (extension != NULL) {
+ length = length - strlen (extension);
+ }
+
+ filename = g_strndup (basename,length);
+ if (window->priv->extension)
+ filename_ext = g_strdup_printf ("%s.%s", filename,
+ window->priv->extension);
+ else
+ filename_ext = g_strdup (filename);
+ gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (file_chooser),
+ filename_ext);
+ g_free (filename);
+ g_free (filename_ext);
+ g_free (basename);
+ g_free (locale_basename);
+ }
+
+ response = gtk_dialog_run (GTK_DIALOG (file_chooser));
+
+ if (response == GTK_RESPONSE_OK) {
+ gchar *name;
+ gchar *utf8_name = NULL;
+
+ name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_chooser));
+ if (name) {
+ gchar *dirname;
+
+ utf8_name= g_filename_to_utf8 (name, -1, NULL, NULL, NULL);
+ dirname = g_path_get_dirname (utf8_name);
+ mateconf_client_set_string (mateconf_client, KEY_SAVE_DIR, dirname, NULL);
+ g_free (dirname);
+ g_free (utf8_name);
+
+ do_save_file (window, name);
+ g_free (name);
+ }
+ }
+
+ gtk_widget_destroy (file_chooser);
+}
+
+static void
+file_save_cb (GtkAction *action,
+ GSRWindow *window)
+{
+ if (!window->priv->has_file) {
+ file_save_as_cb (NULL, window);
+ } else {
+ do_save_file (window, window->priv->filename);
+ }
+}
+
+static void
+run_mixer_cb (GtkAction *action,
+ GSRWindow *window)
+{
+ char *mixer_path;
+ char *argv[4] = {NULL, "--page", "recording", NULL};
+ GError *error = NULL;
+ gboolean ret;
+
+ /* Open the mixer */
+ mixer_path = g_find_program_in_path ("mate-volume-control");
+ if (mixer_path == NULL) {
+ show_error_dialog (GTK_WINDOW (window), NULL,
+ _("%s is not installed in the path."),
+ "mate-volume-control");
+ return;
+ }
+
+ argv[0] = mixer_path;
+ ret = g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, NULL, &error);
+ if (ret == FALSE) {
+ show_error_dialog (GTK_WINDOW (window), NULL,
+ _("There was an error starting %s: %s"),
+ mixer_path, error->message);
+ g_error_free (error);
+ }
+
+ g_free (mixer_path);
+}
+
+gboolean
+gsr_window_is_saved (GSRWindow *window)
+{
+ return window->priv->saved;
+}
+
+gboolean
+gsr_discard_confirmation_dialog (GSRWindow *window, gboolean closing)
+{
+ GtkWidget *confirmation_dialog;
+ AtkObject *atk_obj;
+ gint response_id;
+ gboolean ret = TRUE;
+
+ confirmation_dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (window),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_NONE,
+ "<span weight=\"bold\" size=\"larger\">%s</span>",
+ closing ?
+ _("Save recording before closing?") :
+ _("Save recording?"));
+
+ gtk_dialog_add_buttons (GTK_DIALOG (confirmation_dialog),
+ closing ?
+ _("Close _without Saving") :
+ _("Continue _without Saving"),
+ GTK_RESPONSE_YES,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE_AS, GTK_RESPONSE_NO, NULL);
+ gtk_dialog_set_default_response (GTK_DIALOG (confirmation_dialog),
+ GTK_RESPONSE_NO);
+
+ gtk_window_set_title (GTK_WINDOW (confirmation_dialog), "");
+
+ atk_obj = gtk_widget_get_accessible (confirmation_dialog);
+ atk_object_set_name (atk_obj, _("Question"));
+
+ response_id = gtk_dialog_run (GTK_DIALOG (confirmation_dialog));
+
+ switch (response_id) {
+ case GTK_RESPONSE_NO:
+ /* hiding the confirmation dialog allows the user to
+ see only one dialog at a time if the user click cancel
+ in the file dialog, they won't expect to return to the
+ confirmation dialog*/
+ gtk_widget_hide (confirmation_dialog);
+ file_save_as_cb (NULL, window);
+ ret = window->priv->has_file;
+ break;
+
+ case GTK_RESPONSE_YES:
+ ret = TRUE;
+ break;
+
+ case GTK_RESPONSE_CANCEL:
+ default:
+ ret = FALSE;
+ break;
+ }
+
+ gtk_widget_destroy (confirmation_dialog);
+
+ return ret;
+}
+
+static GtkWidget *
+make_title_label (const char *text)
+{
+ GtkWidget *label;
+ char *fulltext;
+
+ fulltext = g_strdup_printf ("<span weight=\"bold\">%s</span>", text);
+ label = gtk_label_new (fulltext);
+ g_free (fulltext);
+
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0.0);
+ return label;
+}
+
+static GtkWidget *
+make_info_label (const char *text)
+{
+ GtkWidget *label;
+
+ label = gtk_label_new (text);
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+ gtk_label_set_selectable (GTK_LABEL (label), TRUE);
+ gtk_label_set_line_wrap (GTK_LABEL (label), GTK_WRAP_WORD);
+
+ return label;
+}
+
+static void
+pack_table_widget (GtkWidget *table,
+ GtkWidget *widget,
+ int left,
+ int top)
+{
+ gtk_table_attach (GTK_TABLE (table), widget,
+ left, left + 1, top, top + 1,
+ GTK_FILL, GTK_FILL, 0, 0);
+}
+
+struct _file_props {
+ GtkWidget *dialog;
+
+ GtkWidget *dirname;
+ GtkWidget *filename;
+ GtkWidget *size;
+ GtkWidget *length;
+ GtkWidget *samplerate;
+ GtkWidget *channels;
+ GtkWidget *bitrate;
+};
+
+static void
+fill_in_information (GSRWindow *window,
+ struct _file_props *fp)
+{
+ struct stat buf;
+ guint64 file_size = 0;
+ gchar *text, *name;
+ gchar *utf8_name = NULL;
+ gint n_channels, bitrate, samplerate;
+
+ /* dirname */
+ if (window->priv->dirty) {
+ gtk_label_set_text (GTK_LABEL (fp->dirname), "");
+ } else {
+ name = g_path_get_dirname (window->priv->filename);
+ text = g_filename_to_utf8 (name, -1, NULL, NULL, NULL);
+ gtk_label_set_text (GTK_LABEL (fp->dirname), text);
+ g_free (text);
+ g_free (name);
+ }
+
+ /* filename */
+ name = g_path_get_basename (window->priv->filename);
+ utf8_name = g_filename_to_utf8 (name, -1, NULL, NULL, NULL);
+
+ if (window->priv->dirty) {
+ text = g_strdup_printf (_("%s (Has not been saved)"), utf8_name);
+ } else {
+ text = g_strdup (utf8_name);
+ }
+ gtk_label_set_text (GTK_LABEL (fp->filename), text);
+ g_free (text);
+ g_free (utf8_name);
+ g_free (name);
+
+ /* Size */
+ if (stat (window->priv->working_file, &buf) == 0) {
+ gchar *human;
+
+ file_size = (guint64) buf.st_size;
+ human = g_format_size_for_display (file_size);
+
+ text = g_strdup_printf (ngettext ("%s (%llu byte)", "%s (%llu bytes)",
+ file_size), human, file_size);
+ g_free (human);
+ } else {
+ text = g_strdup (_("Unknown size"));
+ }
+ gtk_label_set_text (GTK_LABEL (fp->size), text);
+ g_free (text);
+
+ /* FIXME: Set up and run our own pipeline
+ * till we can get the info */
+ /* Length */
+ if (window->priv->len_secs == 0) {
+ text = g_strdup (_("Unknown"));
+ } else {
+ text = seconds_to_full_string (window->priv->len_secs);
+ }
+ gtk_label_set_text (GTK_LABEL (fp->length), text);
+ g_free (text);
+
+ /* sample rate */
+ samplerate = g_atomic_int_get (&window->priv->atomic.samplerate);
+ if (samplerate == 0) {
+ text = g_strdup (_("Unknown"));
+ } else {
+ text = g_strdup_printf (_("%.1f kHz"), (float) samplerate / 1000);
+ }
+ gtk_label_set_text (GTK_LABEL (fp->samplerate), text);
+ g_free (text);
+
+ /* bit rate */
+ bitrate = g_atomic_int_get (&window->priv->atomic.bitrate);
+ if (bitrate > 0) {
+ text = g_strdup_printf (_("%.0f kb/s"), (float) bitrate / 1000);
+ } else if (window->priv->len_secs > 0 && file_size > 0) {
+ bitrate = (file_size * 8.0) / window->priv->len_secs;
+ text = g_strdup_printf (_("%.0f kb/s (Estimated)"),
+ (float) bitrate / 1000);
+ } else {
+ text = g_strdup (_("Unknown"));
+ }
+ gtk_label_set_text (GTK_LABEL (fp->bitrate), text);
+ g_free (text);
+
+ /* channels */
+ n_channels = g_atomic_int_get (&window->priv->atomic.n_channels);
+ switch (n_channels) {
+ case 0:
+ text = g_strdup (_("Unknown"));
+ break;
+ case 1:
+ text = g_strdup (_("1 (mono)"));
+ break;
+ case 2:
+ text = g_strdup (_("2 (stereo)"));
+ break;
+ default:
+ text = g_strdup_printf ("%d", n_channels);
+ break;
+ }
+ gtk_label_set_text (GTK_LABEL (fp->channels), text);
+ g_free (text);
+}
+
+static void
+dialog_closed_cb (GtkDialog *dialog,
+ guint response_id,
+ struct _file_props *fp)
+{
+ gtk_widget_destroy (fp->dialog);
+ g_free (fp);
+}
+
+static void
+file_properties_cb (GtkAction *action,
+ GSRWindow *window)
+{
+ GtkWidget *dialog, *vbox, *inner_vbox, *hbox, *table, *label;
+ char *title, *shortname;
+ struct _file_props *fp;
+ shortname = g_path_get_basename (window->priv->filename);
+ title = g_strdup_printf (_("%s Information"), shortname);
+ g_free (shortname);
+
+ dialog = gtk_dialog_new_with_buttons (title, GTK_WINDOW (window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
+ g_free (title);
+#if !GTK_CHECK_VERSION (2, 21, 8)
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+#endif
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2);
+ fp = g_new (struct _file_props, 1);
+ fp->dialog = dialog;
+
+ g_signal_connect (G_OBJECT (dialog), "response",
+ G_CALLBACK (dialog_closed_cb), fp);
+
+ vbox = gtk_vbox_new (FALSE, 18);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), vbox, TRUE, TRUE, 0);
+
+ inner_vbox = gtk_vbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (vbox), inner_vbox, FALSE, FALSE,0);
+
+ label = make_title_label (_("File Information"));
+ gtk_box_pack_start (GTK_BOX (inner_vbox), label, FALSE, FALSE, 0);
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (inner_vbox), hbox, TRUE, TRUE, 0);
+
+ label = gtk_label_new (" ");
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ /* File properties */
+ table = gtk_table_new (3, 2, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0);
+
+ label = make_info_label (_("Folder:"));
+ pack_table_widget (table, label, 0, 0);
+
+ fp->dirname = make_info_label ("");
+ pack_table_widget (table, fp->dirname, 1, 0);
+
+ label = make_info_label (_("Filename:"));
+ pack_table_widget (table, label, 0, 1);
+
+ fp->filename = make_info_label ("");
+ pack_table_widget (table, fp->filename, 1, 1);
+
+ label = make_info_label (_("File size:"));
+ pack_table_widget (table, label, 0, 2);
+
+ fp->size = make_info_label ("");
+ pack_table_widget (table, fp->size, 1, 2);
+
+ inner_vbox = gtk_vbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (vbox), inner_vbox, FALSE, FALSE, 0);
+
+ label = make_title_label (_("Audio Information"));
+ gtk_box_pack_start (GTK_BOX (inner_vbox), label, FALSE, FALSE, 0);
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (inner_vbox), hbox, TRUE, TRUE, 0);
+
+ label = gtk_label_new (" ");
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ /* Audio info */
+ table = gtk_table_new (4, 2, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0);
+
+ label = make_info_label (_("File duration:"));
+ pack_table_widget (table, label, 0, 0);
+
+ fp->length = make_info_label ("");
+ pack_table_widget (table, fp->length, 1, 0);
+
+ label = make_info_label (_("Number of channels:"));
+ pack_table_widget (table, label, 0, 1);
+
+ fp->channels = make_info_label ("");
+ pack_table_widget (table, fp->channels, 1, 1);
+
+ label = make_info_label (_("Sample rate:"));
+ pack_table_widget (table, label, 0, 2);
+
+ fp->samplerate = make_info_label ("");
+ pack_table_widget (table, fp->samplerate, 1, 2);
+
+ label = make_info_label (_("Bit rate:"));
+ pack_table_widget (table, label, 0, 3);
+
+ fp->bitrate = make_info_label ("");
+ pack_table_widget (table, fp->bitrate, 1, 3);
+
+ fill_in_information (window, fp);
+ gtk_widget_show_all (dialog);
+}
+
+void
+gsr_window_close (GSRWindow *window)
+{
+ gtk_widget_destroy (GTK_WIDGET (window));
+}
+
+static void
+file_close_cb (GtkAction *action,
+ GSRWindow *window)
+{
+ if (gsr_window_is_saved (window) || gsr_discard_confirmation_dialog (window, TRUE))
+ gsr_window_close (window);
+}
+
+static void
+quit_cb (GtkAction *action,
+ GSRWindow *window)
+{
+ gsr_quit ();
+}
+
+static void
+help_contents_cb (GtkAction *action,
+ GSRWindow *window)
+{
+ GError *error = NULL;
+
+ gtk_show_uri (gtk_window_get_screen (GTK_WINDOW (window)),
+ "ghelp:mate-sound-recorder",
+ gtk_get_current_event_time (), &error);
+
+ if (error != NULL)
+ {
+ g_warning ("%s", error->message);
+
+ g_error_free (error);
+ }
+}
+
+static void
+about_cb (GtkAction *action,
+ GSRWindow *window)
+{
+ const char * const authors[] = {"Iain Holmes <[email protected]>",
+ "Ronald Bultje <[email protected]>",
+ "Johan Dahlin <[email protected]>",
+ "Tim-Philipp M\303\274ller <tim centricular net>",
+ NULL};
+ const char * const documenters[] = {"Sun Microsystems", NULL};
+
+ gtk_show_about_dialog (GTK_WINDOW (window),
+ "name", _("Sound Recorder"),
+ "version", VERSION,
+ "copyright", "Copyright \xc2\xa9 2002 Iain Holmes",
+ "comments", _("A sound recorder for MATE\n [email protected]"),
+ "authors", authors,
+ "documenters", documenters,
+ "logo-icon-name", "mate-sound-recorder",
+ NULL);
+}
+
+static void
+play_cb (GtkAction *action,
+ GSRWindow *window)
+{
+ GSRWindowPrivate *priv = window->priv;
+
+ if (priv->has_file == FALSE && !priv->working_file)
+ return;
+
+ if (priv->play) {
+ shutdown_pipeline (priv->play);
+ }
+
+ if ((priv->play = make_play_pipeline (window))) {
+ gchar *uri;
+ gchar *usefile;
+ GFile *file;
+
+ if(priv->has_file == FALSE && priv->working_file) usefile = priv->working_file;
+ else usefile = priv->filename;
+
+ file = g_file_new_for_commandline_arg (usefile);
+ uri = g_file_get_uri (file);
+ g_object_unref (file);
+ g_object_set (window->priv->play->pipeline, "uri", uri, NULL);
+ g_free (uri);
+
+ if (priv->record && priv->record->state == GST_STATE_PLAYING) {
+ set_pipeline_state_to_null (priv->record->pipeline);
+ }
+
+ gst_element_set_state (priv->play->pipeline, GST_STATE_PLAYING);
+ }
+}
+
+static void
+stop_cb (GtkAction *action,
+ GSRWindow *window)
+{
+ GSRWindowPrivate *priv = window->priv;
+
+ /* Work out what's playing */
+ if (priv->play && priv->play->state >= GST_STATE_PAUSED) {
+ GST_DEBUG ("Stopping play pipeline");
+ set_pipeline_state_to_null (priv->play->pipeline);
+ } else if (priv->record && priv->record->state == GST_STATE_PLAYING) {
+ GST_DEBUG ("Stopping recording source");
+ /* GstBaseSrc will automatically send an EOS when stopping */
+ gst_element_set_state (priv->record->src, GST_STATE_NULL);
+ gst_element_get_state (priv->record->src, NULL, NULL, -1);
+ gst_element_set_locked_state (priv->record->src, TRUE);
+
+ GST_DEBUG ("Stopping recording pipeline");
+ set_pipeline_state_to_null (priv->record->pipeline);
+ gtk_widget_set_sensitive (window->priv->level, FALSE);
+ gtk_widget_set_sensitive (window->priv->volume_label, FALSE);
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (window->priv->level), 0.0);
+ }
+}
+
+static void
+record_cb (GtkAction *action,
+ GSRWindow *window)
+{
+ if (!gsr_window_is_saved(window) && !gsr_discard_confirmation_dialog (window, FALSE))
+ return;
+
+ GSRWindowPrivate *priv = window->priv;
+
+ if (priv->record) {
+ char *current_source;
+ shutdown_pipeline (priv->record);
+ if (!make_record_source (window))
+ return;
+ current_source = gtk_combo_box_get_active_text (GTK_COMBO_BOX (window->priv->input));
+ fill_record_input (window, current_source);
+ }
+
+ if ((priv->record = make_record_pipeline (window))) {
+ window->priv->len_secs = 0;
+ window->priv->saved = FALSE;
+
+ g_print ("%s", priv->record_filename);
+ g_object_set (G_OBJECT (priv->record->sink),
+ "location", priv->record_filename,
+ NULL);
+
+ gst_element_set_state (priv->record->pipeline, GST_STATE_PLAYING);
+ gtk_widget_set_sensitive (window->priv->level, TRUE);
+ gtk_widget_set_sensitive (window->priv->volume_label, TRUE);
+
+ }
+}
+
+static gboolean
+seek_started (GtkRange *range,
+ GdkEventButton *event,
+ GSRWindow *window)
+{
+ g_return_val_if_fail (window->priv != NULL, FALSE);
+
+ window->priv->seek_in_progress = TRUE;
+ return FALSE;
+}
+
+static gboolean
+seek_to (GtkRange *range,
+ GdkEventButton *gdkevent,
+ GSRWindow *window)
+{
+ gdouble value;
+ gint64 time;
+
+ if (window->priv->play->state < GST_STATE_PLAYING)
+ return FALSE;
+
+ value = gtk_adjustment_get_value (gtk_range_get_adjustment (range));
+ time = ((value / 100.0) * window->priv->len_secs) * GST_SECOND;
+
+ gst_element_seek (window->priv->play->pipeline, 1.0, GST_FORMAT_TIME,
+ GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, time,
+ GST_SEEK_TYPE_NONE, 0);
+
+ window->priv->seek_in_progress = FALSE;
+
+ return FALSE;
+}
+
+static gboolean
+play_tick_callback (GSRWindow *window)
+{
+ GstElement *playbin;
+ GstFormat format = GST_FORMAT_TIME;
+ gint64 val = -1;
+
+ g_return_val_if_fail (window->priv->play != NULL, FALSE);
+ g_return_val_if_fail (window->priv->play->pipeline != NULL, FALSE);
+
+ playbin = window->priv->play->pipeline;
+
+ /* This check stops us from doing an unnecessary query */
+ if (window->priv->play->state != GST_STATE_PLAYING) {
+ GST_DEBUG ("pipeline in wrong state: %s",
+ gst_element_state_get_name (window->priv->play->state));
+ window->priv->play->tick_id = 0;
+ return FALSE;
+ }
+
+ if (gst_element_query_duration (playbin, &format, &val) && val != -1) {
+ gchar *len_str;
+
+ window->priv->len_secs = val / GST_SECOND;
+
+ len_str = seconds_to_full_string (window->priv->len_secs);
+ gtk_label_set_text (GTK_LABEL (window->priv->length_label),
+ len_str);
+ g_free (len_str);
+ } else {
+ if (window->priv->get_length_attempts <= 0) {
+ /* Attempts to get length ran out. */
+ gtk_label_set_text (GTK_LABEL (window->priv->length_label), _("Unknown"));
+ } else {
+ --window->priv->get_length_attempts;
+ }
+ }
+
+ if (window->priv->seek_in_progress) {
+ GST_DEBUG ("seek in progress, try again later");
+ return TRUE;
+ }
+
+ if (window->priv->len_secs == 0) {
+ GST_DEBUG ("no duration, try again later");
+ return TRUE;
+ }
+
+ if (gst_element_query_position (playbin, &format, &val) && val != -1) {
+ gdouble pos, len, percentage;
+
+ pos = (gdouble) (val - (val % GST_SECOND));
+ len = (gdouble) window->priv->len_secs * GST_SECOND;
+ percentage = pos / len * 100.0;
+
+ gtk_adjustment_set_value (gtk_range_get_adjustment (GTK_RANGE (window->priv->scale)),
+ CLAMP (percentage + 0.5, 0.0, 100.0));
+ } else {
+ GST_DEBUG ("failed to query position");
+ }
+
+ return TRUE;
+}
+
+static gboolean
+record_tick_callback (GSRWindow *window)
+{
+ GstElement *pipeline;
+ GstFormat format = GST_FORMAT_TIME;
+ gint64 val = -1;
+ gint secs;
+
+ /* This check stops us from doing an unnecessary query */
+ if (window->priv->record->state != GST_STATE_PLAYING) {
+ GST_DEBUG ("pipeline in wrong state: %s",
+ gst_element_state_get_name (window->priv->record->state));
+ return FALSE;
+ }
+
+ if (window->priv->seek_in_progress)
+ return TRUE;
+
+ pipeline = window->priv->record->pipeline;
+
+ if (gst_element_query_position (pipeline, &format, &val) && val != -1) {
+ gchar* len_str;
+
+ secs = val / GST_SECOND;
+
+ len_str = seconds_to_full_string (secs);
+ window->priv->len_secs = secs;
+ gtk_label_set_text (GTK_LABEL (window->priv->length_label),
+ len_str);
+ g_free (len_str);
+ } else {
+ GST_DEBUG ("failed to query position");
+ }
+
+ return TRUE;
+}
+
+static void
+play_state_changed_cb (GstBus * bus, GstMessage * msg, GSRWindow * window)
+{
+ GstState new_state;
+
+ gst_message_parse_state_changed (msg, NULL, &new_state, NULL);
+
+ g_return_if_fail (GSR_IS_WINDOW (window));
+
+ /* we are only interested in state changes of the top-level pipeline */
+ if (msg->src != GST_OBJECT (window->priv->play->pipeline))
+ return;
+
+ window->priv->play->state = new_state;
+
+ GST_DEBUG ("playbin state: %s", gst_element_state_get_name (new_state));
+
+ switch (new_state) {
+ case GST_STATE_PLAYING:
+ if (window->priv->play->tick_id == 0) {
+ window->priv->play->tick_id =
+ g_timeout_add (200, (GSourceFunc) play_tick_callback, window);
+ }
+
+ set_action_sensitive (window, "Stop", TRUE);
+ set_action_sensitive (window, "Play", FALSE);
+ set_action_sensitive (window, "Record", FALSE);
+ set_action_sensitive (window, "FileSave", FALSE);
+ set_action_sensitive (window, "FileSaveAs", FALSE);
+ gtk_widget_set_sensitive (window->priv->scale, TRUE);
+
+ gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
+ window->priv->status_message_cid);
+ gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar),
+ window->priv->status_message_cid,
+ _("Playing…"));
+
+ if (window->priv->ebusy_timeout_id) {
+ g_source_remove (window->priv->ebusy_timeout_id);
+ window->priv->ebusy_timeout_id = 0;
+ window->priv->ebusy_pipeline = NULL;
+ }
+ break;
+
+ case GST_STATE_READY:
+ if (window->priv->play->tick_id > 0) {
+ g_source_remove (window->priv->play->tick_id);
+ window->priv->play->tick_id = 0;
+ }
+ gtk_adjustment_set_value (gtk_range_get_adjustment (GTK_RANGE (window->priv->scale)), 0.0);
+ gtk_widget_set_sensitive (window->priv->scale, FALSE);
+ /* fallthrough */
+ case GST_STATE_PAUSED:
+ set_action_sensitive (window, "Stop", FALSE);
+ set_action_sensitive (window, "Play", TRUE);
+ set_action_sensitive (window, "Record", TRUE);
+ set_action_sensitive (window, "FileSave", TRUE);
+ set_action_sensitive (window, "FileSaveAs", TRUE);
+
+ gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
+ window->priv->status_message_cid);
+ gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar),
+ window->priv->status_message_cid,
+ _("Ready"));
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+pipeline_deep_notify_caps_cb (GstObject *pipeline,
+ GstObject *object,
+ GParamSpec *pspec,
+ GSRWindow *window)
+{
+ GSRWindowPrivate *priv;
+ GstPadDirection direction;
+
+ if (!GST_IS_PAD (object))
+ return;
+
+ priv = window->priv;
+ if (priv->play && pipeline == GST_OBJECT_CAST (priv->play->pipeline)) {
+ direction = GST_PAD_SRC;
+ } else if (priv->record && pipeline == GST_OBJECT_CAST (priv->record->pipeline)) {
+ direction = GST_PAD_SINK;
+ } else {
+ g_return_if_reached ();
+ }
+
+ if (GST_PAD_DIRECTION (object) == direction) {
+ GstObject *pad_parent;
+
+ pad_parent = gst_object_get_parent (object);
+ if (GST_IS_ELEMENT (pad_parent)) {
+ GstElementFactory *factory;
+ GstElement *element;
+ const gchar *klass;
+
+ element = GST_ELEMENT_CAST (pad_parent);
+ if ((factory = gst_element_get_factory (element)) &&
+ (klass = gst_element_factory_get_klass (factory)) &&
+ strstr (klass, "Audio") &&
+ (strstr (klass, "Decoder") || strstr (klass, "Encoder"))) {
+ GstCaps *caps;
+
+ caps = gst_pad_get_negotiated_caps (GST_PAD_CAST (object));
+ if (caps) {
+ GstStructure *s;
+ gint val;
+
+ s = gst_caps_get_structure (caps, 0);
+ if (gst_structure_get_int (s, "channels", &val)) {
+ gst_atomic_int_set (&priv->atomic.n_channels, val);
+ }
+ if (gst_structure_get_int (s, "rate", &val)) {
+ gst_atomic_int_set (&priv->atomic.samplerate, val);
+ }
+ gst_caps_unref (caps);
+ }
+ }
+ }
+ if (pad_parent)
+ gst_object_unref (pad_parent);
+ }
+}
+
+/* callback for when the recording profile has been changed */
+static void
+profile_changed_cb (GObject *object, GSRWindow *window)
+{
+ GMAudioProfile *profile;
+ gchar *id;
+
+ g_return_if_fail (GTK_IS_COMBO_BOX (object));
+
+ profile = gm_audio_profile_choose_get_active (GTK_WIDGET (object));
+
+ if (profile != NULL) {
+ id = g_strdup (gm_audio_profile_get_id (profile));
+ GST_DEBUG ("profile changed to %s", GST_STR_NULL (id));
+ mateconf_client_set_string (mateconf_client, KEY_LAST_PROFILE_ID, id, NULL);
+ g_free (id);
+ }
+}
+
+static void
+play_eos_msg_cb (GstBus * bus, GstMessage * msg, GSRWindow * window)
+{
+ g_return_if_fail (GSR_IS_WINDOW (window));
+
+ GST_DEBUG ("EOS");
+
+ stop_cb (NULL, window);
+}
+
+static GSRWindowPipeline *
+make_play_pipeline (GSRWindow *window)
+{
+ GSRWindowPipeline *obj;
+ GstElement *playbin;
+ GstElement *audiosink;
+
+ audiosink = gst_element_factory_make ("mateconfaudiosink", "sink");
+ if (audiosink == NULL) {
+ show_missing_known_element_error (NULL,
+ _("MateConf audio output"), "mateconfaudiosink", "mateconfelements",
+ "gst-plugins-good");
+ return NULL;
+ }
+
+ playbin = gst_element_factory_make ("playbin", "playbin");
+ if (playbin == NULL) {
+ gst_object_unref (audiosink);
+ show_missing_known_element_error (NULL,
+ _("Playback"), "playbin", "playback",
+ "gst-plugins-base");
+ return NULL;
+ }
+
+ obj = g_new0 (GSRWindowPipeline, 1);
+ obj->pipeline = playbin;
+ obj->src = NULL; /* don't need that for playback */
+ obj->sink = NULL; /* don't need that for playback */
+
+ g_object_set (playbin, "audio-sink", audiosink, NULL);
+
+ /* we ultimately want to find out the caps on the decoder's source pad */
+ g_signal_connect (playbin, "deep-notify::caps",
+ G_CALLBACK (pipeline_deep_notify_caps_cb),
+ window);
+
+ obj->bus = gst_element_get_bus (playbin);
+
+ gst_bus_add_signal_watch_full (obj->bus, G_PRIORITY_HIGH);
+
+ g_signal_connect (obj->bus, "message::state-changed",
+ G_CALLBACK (play_state_changed_cb),
+ window);
+
+ g_signal_connect (obj->bus, "message::error",
+ G_CALLBACK (pipeline_error_cb),
+ window);
+
+ g_signal_connect (obj->bus, "message::eos",
+ G_CALLBACK (play_eos_msg_cb),
+ window);
+
+ return obj;
+}
+
+static void
+record_eos_msg_cb (GstBus * bus, GstMessage * msg, GSRWindow * window)
+{
+ g_return_if_fail (GSR_IS_WINDOW (window));
+
+ GST_DEBUG ("EOS. Finished recording");
+
+ /* FIXME: this was READY before (why?) */
+ set_pipeline_state_to_null (window->priv->record->pipeline);
+
+ g_free (window->priv->working_file);
+ window->priv->working_file = g_strdup (window->priv->record_filename);
+
+ g_free (window->priv->filename);
+ window->priv->filename = g_strdup (window->priv->record_filename);
+
+ window->priv->has_file = TRUE;
+}
+
+extern int gsr_sample_count;
+
+static gboolean
+record_start (gpointer user_data)
+{
+ GSRWindow *window = GSR_WINDOW (user_data);
+ gchar *name;
+
+ g_assert (window->priv->tick_id == 0);
+
+ window->priv->get_length_attempts = 16;
+ window->priv->tick_id = g_timeout_add (200, (GSourceFunc) record_tick_callback, window);
+
+ set_action_sensitive (window, "Stop", TRUE);
+ set_action_sensitive (window, "Play", FALSE);
+ set_action_sensitive (window, "Record", FALSE);
+ set_action_sensitive (window, "FileSave", FALSE);
+ set_action_sensitive (window, "FileSaveAs", FALSE);
+ gtk_widget_set_sensitive (window->priv->scale, FALSE);
+
+ gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
+ window->priv->status_message_cid);
+ gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar),
+ window->priv->status_message_cid,
+ _("Recording…"));
+
+ window->priv->record_id = 0;
+
+ /* Translator comment: untitled here implies that
+ * there is no active sound sample. Any newly
+ * recorded samples will be saved to disk with this
+ * name as default value. */
+ if (gsr_sample_count == 1) {
+ name = g_strdup (_("Untitled"));
+ } else {
+ name = g_strdup_printf (_("Untitled-%d"), gsr_sample_count);
+ }
+ ++gsr_sample_count;
+ gtk_window_set_title (GTK_WINDOW(window), name);
+
+ g_free (name);
+
+ return FALSE;
+}
+
+static void
+record_state_changed_cb (GstBus *bus, GstMessage *msg, GSRWindow *window)
+{
+ GstState new_state;
+ GMAudioProfile *profile;
+
+ gst_message_parse_state_changed (msg, NULL, &new_state, NULL);
+
+ g_return_if_fail (GSR_IS_WINDOW (window));
+
+ /* we are only interested in state changes of the top-level pipeline */
+ if (msg->src != GST_OBJECT (window->priv->record->pipeline))
+ return;
+
+ window->priv->record->state = new_state;
+
+ GST_DEBUG ("record pipeline state: %s", gst_element_state_get_name (new_state));
+
+ switch (new_state) {
+ case GST_STATE_PLAYING:
+ window->priv->record_id = g_idle_add (record_start, window);
+ g_free (window->priv->extension);
+ profile = gm_audio_profile_choose_get_active (window->priv->profile);
+ window->priv->extension = g_strdup (profile ? gm_audio_profile_get_extension (profile) : NULL);
+ gtk_widget_set_sensitive (window->priv->profile, FALSE);
+ gtk_widget_set_sensitive (window->priv->input, FALSE);
+ break;
+ case GST_STATE_READY:
+ gtk_adjustment_set_value (gtk_range_get_adjustment (GTK_RANGE (window->priv->scale)), 0.0);
+ gtk_widget_set_sensitive (window->priv->scale, FALSE);
+ gtk_widget_set_sensitive (window->priv->profile, TRUE);
+ gtk_widget_set_sensitive (window->priv->input, GST_IS_MIXER (window->priv->mixer));
+ /* fall through */
+ case GST_STATE_PAUSED:
+ set_action_sensitive (window, "Stop", FALSE);
+ set_action_sensitive (window, "Play", TRUE);
+ set_action_sensitive (window, "Record", TRUE);
+ set_action_sensitive (window, "FileSave", TRUE);
+ set_action_sensitive (window, "FileSaveAs", TRUE);
+ gtk_widget_set_sensitive (window->priv->scale, FALSE);
+ gtk_widget_set_sensitive (window->priv->profile, TRUE);
+ gtk_widget_set_sensitive (window->priv->input, TRUE);
+
+ gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
+ window->priv->status_message_cid);
+ gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar),
+ window->priv->status_message_cid,
+ _("Ready"));
+ if (window->priv->tick_id > 0) {
+ g_source_remove (window->priv->tick_id);
+ window->priv->tick_id = 0;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/* create the mateconf-based source for recording.
+ * store the source and the mixer in it in our window-private data
+ */
+static gboolean
+make_record_source (GSRWindow *window)
+{
+ GstElement *source, *e;
+
+ source = gst_element_factory_make ("mateconfaudiosrc", "mateconfaudiosource");
+ if (source == NULL) {
+ show_missing_known_element_error (NULL,
+ _("MateConf audio recording"), "mateconfaudiosrc",
+ "mateconfelements", "gst-plugins-good");
+ return FALSE;
+ }
+
+ /* instantiate the underlying element so we can query it */
+ /* FIXME: maybe we want to trap errors in this case ? */
+ if (!gst_element_set_state (source, GST_STATE_READY)) {
+ show_error_dialog (NULL, NULL,
+ _("Your audio capture settings are invalid. "
+ "Please correct them with the \"Sound Preferences\" "
+ "under the System Preferences menu."));
+ return FALSE;
+ }
+ window->priv->source = source;
+ e = gst_bin_get_by_interface (GST_BIN (source), GST_TYPE_MIXER);
+ window->priv->mixer = GST_MIXER (e);
+
+ return TRUE;
+}
+
+static void
+record_input_changed_cb (GtkComboBox *input, GSRWindow *window)
+{
+ const gchar *text;
+ const GList *l;
+ GstMixerTrack *t = NULL, *new = NULL;
+ static GstMixerTrack *selected = NULL;
+
+ text = gtk_combo_box_get_active_text (input);
+ GST_DEBUG ("record input changed to '%s'", GST_STR_NULL (text));
+
+ if (text == NULL)
+ return;
+
+ /* The pipeline has been destroyed already, we'll try and remember
+ * the input for the next record run in fill_record_input() */
+ if (GST_IS_MIXER (window->priv->mixer) == FALSE)
+ return;
+
+ for (l = gst_mixer_list_tracks (window->priv->mixer);
+ l != NULL; l = l->next) {
+ t = l->data;
+ if (t == NULL || t->label == NULL)
+ continue;
+ if ((g_str_equal (t->label, text)) &&
+ (t->flags & GST_MIXER_TRACK_INPUT)) {
+ if (new == NULL)
+ new = g_object_ref (t);
+ /* FIXME selected == t is equivalent to NULL == t in this case,
+ * selected, after its initialization to NULL, was never written to
+ * before this read access to it
+ * and NULL == t is equivalent to FALSE, because of the check
+ * "if (t == NULL || t->label == NULL)" above
+ */
+ } else if (selected == t)
+ /* re-mute old one */
+ gst_mixer_set_record (window->priv->mixer,
+ selected, FALSE);
+ }
+
+ /* FIXME selected _is_ NULL always at this point - same as 5 lines above*/
+ if (selected != NULL)
+ g_object_unref (selected);
+ if (!(selected = new))
+ return;
+
+ gst_mixer_set_record (window->priv->mixer, selected, TRUE);
+ GST_DEBUG ("input changed to: %s\n", selected->label);
+ mateconf_client_set_string (mateconf_client, KEY_LAST_INPUT, selected->label, NULL);
+}
+
+static void
+fill_record_input (GSRWindow *window, gchar *selected)
+{
+ const GList *l;
+ int i = 0;
+ int last_possible_i = 0;
+ GtkTreeModel *model;
+
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (window->priv->input));
+
+ if (model)
+ gtk_list_store_clear (GTK_LIST_STORE (model));
+
+ if (GST_IS_MIXER (window->priv->mixer) == FALSE
+ || gst_mixer_list_tracks (window->priv->mixer) == NULL) {
+ gtk_widget_hide (window->priv->input);
+ gtk_widget_hide (window->priv->input_label);
+ return;
+ }
+
+ gtk_widget_set_sensitive (window->priv->input, GST_IS_MIXER (window->priv->mixer));
+ if (!GST_IS_MIXER (window->priv->mixer))
+ return;
+
+ for (l = gst_mixer_list_tracks (window->priv->mixer); l != NULL; l = l->next) {
+ GstMixerTrack *t = l->data;
+ if (t->label == NULL)
+ continue;
+ if (t->flags & GST_MIXER_TRACK_INPUT) {
+ gtk_combo_box_append_text (GTK_COMBO_BOX (window->priv->input), t->label);
+ ++i;
+ }
+ if (t->flags & GST_MIXER_TRACK_RECORD) {
+ if (selected == NULL) {
+ gtk_combo_box_set_active (GTK_COMBO_BOX (window->priv->input), i - 1);
+ } else {
+ last_possible_i = i;
+ }
+ }
+ if ((selected != NULL) && g_str_equal (selected, t->label)) {
+ gtk_combo_box_set_active (GTK_COMBO_BOX (window->priv->input), i - 1);
+ }
+ }
+
+ if (gtk_combo_box_get_active (GTK_COMBO_BOX (window->priv->input)) == -1) {
+ gtk_combo_box_set_active (GTK_COMBO_BOX (window->priv->input), last_possible_i - 1);
+ }
+
+ gtk_widget_show (window->priv->input);
+ gtk_widget_show (window->priv->input_label);
+}
+
+static gboolean
+level_message_handler_cb (GstBus * bus, GstMessage * message, GSRWindow *window)
+{
+ GSRWindowPrivate *priv = window->priv;
+
+ if (message->type == GST_MESSAGE_ELEMENT) {
+ const GstStructure *s = gst_message_get_structure (message);
+ const gchar *name = gst_structure_get_name (s);
+
+ if (g_str_equal (name, "level")) {
+ gint channels;
+ gdouble peak_dB;
+ gdouble myind;
+ const GValue *list;
+ const GValue *value;
+
+ gint i;
+ /* we can get the number of channels as the length of any of the value
+ * lists */
+
+ list = gst_structure_get_value (s, "rms");
+ channels = gst_value_list_get_size (list);
+
+ for (i = 0; i < channels; ++i) {
+ list = gst_structure_get_value (s, "peak");
+ value = gst_value_list_get_value (list, i);
+ peak_dB = g_value_get_double (value);
+ myind = exp (peak_dB / 20);
+ if (myind > 1.0)
+ myind = 1.0;
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->level), myind);
+ }
+ }
+ }
+ /* we handled the message we want, and ignored the ones we didn't want.
+ * so the core can unref the message for us */
+ return TRUE;
+}
+
+static GSRWindowPipeline *
+make_record_pipeline (GSRWindow *window)
+{
+ GSRWindowPipeline *pipeline;
+ GMAudioProfile *profile;
+ const gchar *profile_pipeline_desc;
+ GstElement *encoder, *source, *filesink, *level;
+ GError *err = NULL;
+ gchar *pipeline_desc;
+ const char *name;
+
+ source = window->priv->source;
+
+ /* Any reason we are not using matevfssink here? (tpm) */
+ filesink = gst_element_factory_make ("filesink", "sink");
+ if (filesink == NULL)
+ {
+ show_missing_known_element_error (NULL,
+ _("file output"), "filesink", "coreelements",
+ "gstreamer");
+ gst_object_unref (source);
+ return NULL;
+ }
+
+ pipeline = g_new (GSRWindowPipeline, 1);
+
+ pipeline->pipeline = gst_pipeline_new ("record-pipeline");
+ pipeline->src = source;
+ pipeline->sink = filesink;
+
+ gst_bin_add (GST_BIN (pipeline->pipeline), source);
+
+ level = gst_element_factory_make ("level", "level");
+ if (level == NULL)
+ {
+ show_missing_known_element_error (NULL,
+ _("level"), "level", "level",
+ "gstreamer");
+ gst_object_unref (source);
+ return NULL;
+ }
+ gst_element_set_name (level, "level");
+
+ profile = gm_audio_profile_choose_get_active (window->priv->profile);
+ if (profile == NULL)
+ return NULL;
+ profile_pipeline_desc = gm_audio_profile_get_pipeline (profile);
+ name = gm_audio_profile_get_name (profile);
+
+ GST_DEBUG ("encoder profile pipeline: '%s'",
+ GST_STR_NULL (profile_pipeline_desc));
+
+ pipeline_desc = g_strdup_printf ("audioconvert ! %s", profile_pipeline_desc);
+ GST_DEBUG ("making encoder bin from description '%s'", pipeline_desc);
+ encoder = gst_parse_bin_from_description (pipeline_desc, TRUE, &err);
+ g_free (pipeline_desc);
+ pipeline_desc = NULL;
+
+ if (err) {
+ show_profile_error (NULL, err->message,
+ _("Could not parse the '%s' audio profile. "), name);
+ g_printerr ("Failed to create GStreamer encoder plugins [%s]: %s\n",
+ profile_pipeline_desc, err->message);
+ g_error_free (err);
+ gst_object_unref (pipeline->pipeline);
+ gst_object_unref (filesink);
+ g_free (pipeline);
+ return NULL;
+ }
+
+ gst_bin_add (GST_BIN (pipeline->pipeline), level);
+ gst_bin_add (GST_BIN (pipeline->pipeline), encoder);
+ gst_bin_add (GST_BIN (pipeline->pipeline), filesink);
+
+ /* now link it all together */
+ if (!(gst_element_link_many (source, level, encoder, NULL))) {
+ show_profile_error (NULL, NULL,
+ _("Could not capture using the '%s' audio profile. "),
+ name);
+ gst_object_unref (pipeline->pipeline);
+ g_free (pipeline);
+ return NULL;
+ }
+
+ if (!gst_element_link (encoder, filesink)) {
+ show_profile_error (NULL, NULL,
+ _("Could not write to a file using the '%s' audio profile. "),
+ name);
+ gst_object_unref (pipeline->pipeline);
+ g_free (pipeline);
+ return NULL;
+ }
+
+ /* we ultimately want to find out the caps on the encoder's source pad */
+ g_signal_connect (pipeline->pipeline, "deep-notify::caps",
+ G_CALLBACK (pipeline_deep_notify_caps_cb),
+ window);
+
+ pipeline->bus = gst_element_get_bus (pipeline->pipeline);
+
+ gst_bus_add_signal_watch (pipeline->bus);
+
+ g_signal_connect (pipeline->bus, "message::element",
+ G_CALLBACK (level_message_handler_cb),
+ window);
+
+ g_signal_connect (pipeline->bus, "message::state-changed",
+ G_CALLBACK (record_state_changed_cb),
+ window);
+
+ g_signal_connect (pipeline->bus, "message::error",
+ G_CALLBACK (pipeline_error_cb),
+ window);
+
+ g_signal_connect (pipeline->bus, "message::eos",
+ G_CALLBACK (record_eos_msg_cb),
+ window);
+
+ return pipeline;
+}
+
+static char *
+calculate_format_value (GtkScale *scale,
+ double value,
+ GSRWindow *window)
+{
+ gint seconds;
+
+ if (window->priv->record && window->priv->record->state == GST_STATE_PLAYING) {
+ seconds = value;
+ return seconds_to_string (seconds);
+ } else {
+ seconds = window->priv->len_secs * (value / 100);
+ return seconds_to_string (seconds);
+ }
+}
+
+static const GtkActionEntry menu_entries[] =
+{
+ /* File menu. */
+ { "File", NULL, N_("_File") },
+ { "FileNew", GTK_STOCK_NEW, NULL, NULL,
+ N_("Create a new sample"), G_CALLBACK (file_new_cb) },
+ { "FileOpen", GTK_STOCK_OPEN, NULL, NULL,
+ N_("Open a file"), G_CALLBACK (file_open_cb) },
+ { "FileSave", GTK_STOCK_SAVE, NULL, NULL,
+ N_("Save the current file"), G_CALLBACK (file_save_cb) },
+ { "FileSaveAs", GTK_STOCK_SAVE_AS, NULL, "<shift><control>S",
+ N_("Save the current file with a different name"), G_CALLBACK (file_save_as_cb) },
+ { "RunMixer", GTK_STOCK_EXECUTE, N_("Open Volu_me Control"), NULL,
+ N_("Open the audio mixer"), G_CALLBACK (run_mixer_cb) },
+ { "FileProperties", GTK_STOCK_PROPERTIES, NULL, "<control>I",
+ N_("Show information about the current file"), G_CALLBACK (file_properties_cb) },
+ { "FileClose", GTK_STOCK_CLOSE, NULL, NULL,
+ N_("Close the current file"), G_CALLBACK (file_close_cb) },
+ { "Quit", GTK_STOCK_QUIT, NULL, NULL,
+ N_("Quit the program"), G_CALLBACK (quit_cb) },
+
+ /* Control menu */
+ { "Control", NULL, N_("_Control") },
+ { "Record", GTK_STOCK_MEDIA_RECORD, NULL, "<control>R",
+ N_("Record sound"), G_CALLBACK (record_cb) },
+ { "Play", GTK_STOCK_MEDIA_PLAY, NULL, "<control>P",
+ N_("Play sound"), G_CALLBACK (play_cb) },
+ { "Stop", GTK_STOCK_MEDIA_STOP, NULL, "<control>X",
+ N_("Stop sound"), G_CALLBACK (stop_cb) },
+
+ /* Help menu */
+ { "Help", NULL, N_("_Help") },
+ {"HelpContents", GTK_STOCK_HELP, N_("Contents"), "F1",
+ N_("Open the manual"), G_CALLBACK (help_contents_cb) },
+ { "About", GTK_STOCK_ABOUT, NULL, NULL,
+ N_("About this application"), G_CALLBACK (about_cb) }
+};
+
+static void
+menu_item_select_cb (GtkMenuItem *proxy,
+ GSRWindow *window)
+{
+ GtkAction *action;
+ char *message;
+
+ action = g_object_get_data (G_OBJECT (proxy), "gtk-action");
+ g_return_if_fail (action != NULL);
+
+ g_object_get (G_OBJECT (action), "tooltip", &message, NULL);
+ if (message) {
+ gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar),
+ window->priv->tip_message_cid, message);
+ g_free (message);
+ }
+}
+
+static void
+menu_item_deselect_cb (GtkMenuItem *proxy,
+ GSRWindow *window)
+{
+ gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
+ window->priv->tip_message_cid);
+}
+
+static void
+connect_proxy_cb (GtkUIManager *manager,
+ GtkAction *action,
+ GtkWidget *proxy,
+ GSRWindow *window)
+{
+ if (GTK_IS_MENU_ITEM (proxy)) {
+ g_signal_connect (proxy, "select",
+ G_CALLBACK (menu_item_select_cb), window);
+ g_signal_connect (proxy, "deselect",
+ G_CALLBACK (menu_item_deselect_cb), window);
+ }
+}
+
+static void
+disconnect_proxy_cb (GtkUIManager *manager,
+ GtkAction *action,
+ GtkWidget *proxy,
+ GSRWindow *window)
+{
+ if (GTK_IS_MENU_ITEM (proxy)) {
+ g_signal_handlers_disconnect_by_func
+ (proxy, G_CALLBACK (menu_item_select_cb), window);
+ g_signal_handlers_disconnect_by_func
+ (proxy, G_CALLBACK (menu_item_deselect_cb), window);
+ }
+}
+
+/* find the given filename in the uninstalled or installed ui dir */
+static gchar *
+find_ui_file (const gchar * filename)
+{
+ gchar * path;
+
+ path = g_build_filename (GSR_UIDIR_UNINSTALLED, filename, NULL);
+ if (g_file_test (path, G_FILE_TEST_EXISTS))
+ return path;
+
+ g_free (path);
+ path = g_build_filename (GSR_UIDIR, filename, NULL);
+ if (g_file_test (path, G_FILE_TEST_EXISTS))
+ return path;
+
+ g_free (path);
+ return NULL;
+}
+
+static void
+gsr_window_init (GSRWindow *window)
+{
+ GSRWindowPrivate *priv;
+ GError *error = NULL;
+ GtkWidget *main_vbox;
+ GtkWidget *menubar;
+ GtkWidget *file_menu;
+ GtkWidget *submenu;
+ GtkWidget *rec_menu;
+ GtkWidget *toolbar;
+ GtkWidget *content_vbox;
+ GtkWidget *hbox;
+ GtkWidget *label;
+ GtkWidget *table;
+ GtkWidget *align;
+ GtkWidget *frame;
+ gchar *id;
+ gchar *last_input;
+ gchar *path;
+ GtkAction *action;
+ GtkShadowType shadow_type;
+ window->priv = GSR_WINDOW_GET_PRIVATE (window);
+ priv = window->priv;
+
+ /* treat mateconf client as a singleton */
+ if (mateconf_client == NULL)
+ mateconf_client = mateconf_client_get_default ();
+
+ main_vbox = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (window), main_vbox);
+ priv->main_vbox = main_vbox;
+ gtk_widget_show (main_vbox);
+
+ /* menu & toolbar */
+ priv->ui_manager = gtk_ui_manager_new ();
+
+ gtk_window_add_accel_group (GTK_WINDOW (window),
+ gtk_ui_manager_get_accel_group (priv->ui_manager));
+
+ path = find_ui_file ("ui.xml");
+ gtk_ui_manager_add_ui_from_file (priv->ui_manager, path, &error);
+
+ if (error != NULL)
+ {
+ show_error_dialog (GTK_WINDOW (window), error->message,
+ _("Could not load UI file. The program may not be properly installed."));
+ g_error_free (error);
+ exit (1);
+ }
+ g_free (path);
+
+ /* show tooltips in the statusbar */
+ g_signal_connect (priv->ui_manager, "connect_proxy",
+ G_CALLBACK (connect_proxy_cb), window);
+ g_signal_connect (priv->ui_manager, "disconnect_proxy",
+ G_CALLBACK (disconnect_proxy_cb), window);
+
+ priv->action_group = gtk_action_group_new ("GSRWindowActions");
+ gtk_action_group_set_translation_domain (priv->action_group, NULL);
+ gtk_action_group_add_actions (priv->action_group,
+ menu_entries,
+ G_N_ELEMENTS (menu_entries),
+ window);
+
+ gtk_ui_manager_insert_action_group (priv->ui_manager, priv->action_group, 0);
+
+ /* set short labels to use in the toolbar */
+ action = gtk_action_group_get_action (priv->action_group, "FileOpen");
+ g_object_set (action, "short_label", _("Open"), NULL);
+ action = gtk_action_group_get_action (priv->action_group, "FileSave");
+ g_object_set (action, "short_label", _("Save"), NULL);
+ action = gtk_action_group_get_action (priv->action_group, "FileSaveAs");
+ g_object_set (action, "short_label", _("Save As"), NULL);
+
+ set_action_sensitive (window, "FileSave", FALSE);
+ set_action_sensitive (window, "FileSaveAs", FALSE);
+ set_action_sensitive (window, "Play", FALSE);
+ set_action_sensitive (window, "Stop", FALSE);
+
+ menubar = gtk_ui_manager_get_widget (priv->ui_manager, "/MenuBar");
+ gtk_box_pack_start (GTK_BOX (main_vbox), menubar, FALSE, FALSE, 0);
+ gtk_widget_show (menubar);
+
+ toolbar = gtk_ui_manager_get_widget (priv->ui_manager, "/ToolBar");
+ gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), FALSE);
+ gtk_box_pack_start (GTK_BOX (main_vbox), toolbar, FALSE, FALSE, 0);
+ gtk_widget_show (toolbar);
+
+ /* recent files */
+ file_menu = gtk_ui_manager_get_widget (priv->ui_manager,
+ "/MenuBar/FileMenu");
+ submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (file_menu));
+ rec_menu = gtk_ui_manager_get_widget (priv->ui_manager,
+ "/MenuBar/FileMenu/FileRecentMenu");
+ priv->recent_view = gtk_recent_chooser_menu_new ();
+ gtk_recent_chooser_set_local_only (GTK_RECENT_CHOOSER (priv->recent_view), TRUE);
+ gtk_recent_chooser_set_limit (GTK_RECENT_CHOOSER (priv->recent_view), 5);
+ priv->recent_filter = gtk_recent_filter_new ();
+ gtk_recent_filter_add_application (priv->recent_filter, g_get_application_name ());
+ gtk_recent_chooser_set_filter (GTK_RECENT_CHOOSER (priv->recent_view), priv->recent_filter);
+ g_signal_connect (priv->recent_view, "item-activated",
+ G_CALLBACK (file_open_recent_cb), window);
+
+ /* window content: hscale, labels, etc */
+ content_vbox = gtk_vbox_new (FALSE, 7);
+ gtk_container_set_border_width (GTK_CONTAINER (content_vbox), 6);
+ gtk_box_pack_start (GTK_BOX (main_vbox), content_vbox, TRUE, TRUE, 0);
+ gtk_widget_show (content_vbox);
+
+ priv->scale = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, 100, 1, 1, 0)));
+ priv->seek_in_progress = FALSE;
+ g_signal_connect (priv->scale, "format-value",
+ G_CALLBACK (calculate_format_value), window);
+ g_signal_connect (priv->scale, "button-press-event",
+ G_CALLBACK (seek_started), window);
+ g_signal_connect (priv->scale, "button-release-event",
+ G_CALLBACK (seek_to), window);
+
+ gtk_scale_set_value_pos (GTK_SCALE (window->priv->scale), GTK_POS_BOTTOM);
+ /* We can't seek until we find out the length */
+ gtk_widget_set_sensitive (window->priv->scale, FALSE);
+ gtk_box_pack_start (GTK_BOX (content_vbox), priv->scale, FALSE, FALSE, 6);
+ gtk_widget_show (window->priv->scale);
+
+ /* create source and choose mixer input */
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (content_vbox), hbox, FALSE, FALSE, 0);
+
+ priv->input_label = gtk_label_new_with_mnemonic (_("Record from _input:"));
+ gtk_misc_set_alignment (GTK_MISC (priv->input_label), 0, 0.5);
+ gtk_box_pack_start (GTK_BOX (hbox), priv->input_label, FALSE, FALSE, 0);
+
+ priv->input = gtk_combo_box_new_text ();
+ gtk_label_set_mnemonic_widget (GTK_LABEL (priv->input_label), priv->input);
+ gtk_box_pack_start (GTK_BOX (hbox), priv->input, TRUE, TRUE, 0);
+
+ if (!make_record_source (window))
+ exit (1);
+
+ g_signal_connect (priv->input, "changed",
+ G_CALLBACK (record_input_changed_cb), window);
+
+ /* choose profile */
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (content_vbox), hbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new_with_mnemonic (_("_Record as:"));
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ priv->profile = gm_audio_profile_choose_new ();
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->profile);
+ gtk_box_pack_start (GTK_BOX (hbox), window->priv->profile, TRUE, TRUE, 0);
+ gtk_widget_show (window->priv->profile);
+
+ atk_object_add_relationship (gtk_widget_get_accessible (GTK_WIDGET (priv->profile)),
+ ATK_RELATION_LABELLED_BY,
+ gtk_widget_get_accessible (GTK_WIDGET (label)));
+
+ id = mateconf_client_get_string (mateconf_client, KEY_LAST_PROFILE_ID, NULL);
+ if (id) {
+ gm_audio_profile_choose_set_active (window->priv->profile, id);
+ g_free (id);
+ }
+
+ g_signal_connect (priv->profile, "changed",
+ G_CALLBACK (profile_changed_cb), window);
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (content_vbox), hbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new (" "); /* FIXME: better padding? */
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ table = gtk_table_new (3, 2, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0);
+
+ label = make_title_label (_("File Information"));
+
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+ gtk_table_attach (GTK_TABLE (table), label,
+ 0, 2, 0, 1,
+ GTK_FILL, 0, 0, 0);
+
+ label = gtk_label_new (_("Filename:"));
+
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+ gtk_table_attach (GTK_TABLE (table), label,
+ 0, 1, 1, 2,
+ GTK_FILL, 0, 0, 0);
+
+ priv->name_label = gtk_label_new (_("<none>"));
+ gtk_label_set_selectable (GTK_LABEL (priv->name_label), TRUE);
+ gtk_label_set_line_wrap (GTK_LABEL (priv->name_label), GTK_WRAP_WORD);
+ gtk_misc_set_alignment (GTK_MISC (priv->name_label), 0, 0.5);
+ gtk_table_attach (GTK_TABLE (table), priv->name_label,
+ 1, 2, 1, 2,
+ GTK_FILL | GTK_EXPAND, 0,
+ 0, 0);
+
+ atk_object_add_relationship (gtk_widget_get_accessible (GTK_WIDGET (priv->name_label)),
+ ATK_RELATION_LABELLED_BY,
+ gtk_widget_get_accessible (GTK_WIDGET (label)));
+
+
+ label = gtk_label_new (_("Length:"));
+
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+ gtk_table_attach (GTK_TABLE (table), label,
+ 0, 1, 2, 3,
+ GTK_FILL, 0, 0, 0);
+
+ priv->length_label = gtk_label_new ("");
+ gtk_label_set_selectable (GTK_LABEL (priv->length_label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (priv->length_label), 0, 0.5);
+ gtk_table_attach (GTK_TABLE (table), priv->length_label,
+ 1, 2, 2, 3,
+ GTK_FILL | GTK_EXPAND, 0,
+ 0, 0);
+
+ atk_object_add_relationship (gtk_widget_get_accessible (GTK_WIDGET (priv->length_label)),
+ ATK_RELATION_LABELLED_BY,
+ gtk_widget_get_accessible (GTK_WIDGET (label)));
+
+ /* statusbar */
+ priv->statusbar = gtk_statusbar_new ();
+ gtk_widget_set_can_focus (priv->statusbar, TRUE);
+ gtk_box_pack_end (GTK_BOX (main_vbox), priv->statusbar, FALSE, FALSE, 0);
+ gtk_widget_show (priv->statusbar);
+
+ /* hack to get the same shadow as the status bar.. */
+ gtk_widget_style_get (GTK_WIDGET (priv->statusbar), "shadow-type", &shadow_type, NULL);
+
+ frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), shadow_type);
+ gtk_widget_show (frame);
+
+ gtk_box_pack_end (GTK_BOX (priv->statusbar), frame, FALSE, TRUE, 0);
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (frame), hbox);
+ gtk_box_set_spacing (GTK_BOX (hbox), 6);
+
+ priv->volume_label = gtk_label_new (_("Level:"));
+ gtk_box_pack_start (GTK_BOX (hbox), priv->volume_label, FALSE, TRUE, 0);
+
+ /* initialize priv->level */
+ align = gtk_aspect_frame_new ("", 0.0, 0.0, 20, FALSE);
+ gtk_frame_set_shadow_type (GTK_FRAME (align), GTK_SHADOW_NONE);
+ gtk_widget_show (align);
+ gtk_box_pack_start (GTK_BOX (hbox), align, FALSE, FALSE, 0);
+
+ priv->level = gtk_progress_bar_new ();
+ gtk_container_add (GTK_CONTAINER (align), priv->level);
+
+ gtk_widget_set_sensitive (window->priv->volume_label, FALSE);
+ gtk_widget_set_sensitive (window->priv->level, FALSE);
+
+ priv->status_message_cid = gtk_statusbar_get_context_id
+ (GTK_STATUSBAR (priv->statusbar), "status_message");
+ priv->tip_message_cid = gtk_statusbar_get_context_id
+ (GTK_STATUSBAR (priv->statusbar), "tip_message");
+
+ gtk_statusbar_push (GTK_STATUSBAR (priv->statusbar),
+ priv->status_message_cid,
+ _("Ready"));
+
+ gtk_widget_show_all (main_vbox);
+ last_input = mateconf_client_get_string (mateconf_client, KEY_LAST_INPUT, NULL);
+ fill_record_input (window, last_input);
+ if (last_input) {
+ g_free (last_input);
+ }
+
+ /* Make the pipelines */
+ priv->play = NULL;
+ priv->record = NULL;
+
+ priv->len_secs = 0;
+ priv->get_length_attempts = 16;
+ priv->dirty = TRUE;
+}
+
+static void
+gsr_window_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GSRWindow *window;
+ GSRWindowPrivate *priv;
+ struct stat buf;
+ char *title, *short_name;
+ char *utf8_name = NULL;
+ const char *ext;
+
+ window = GSR_WINDOW (object);
+ priv = window->priv;
+
+ switch (prop_id) {
+ case PROP_LOCATION:
+ if (priv->filename != NULL) {
+ if (g_value_get_string (value) == NULL)
+ return;
+ if (g_str_equal (g_value_get_string (value), priv->filename)) {
+ return;
+ }
+ }
+
+ g_free (priv->filename);
+ g_free (priv->working_file);
+
+ priv->filename = g_value_dup_string (value);
+ priv->working_file = g_strdup (priv->filename);
+ priv->len_secs = 0;
+
+ short_name = g_path_get_basename (priv->filename);
+ if (stat (priv->filename, &buf) == 0) {
+ window->priv->has_file = TRUE;
+ } else {
+ window->priv->has_file = FALSE;
+ }
+
+ g_free (window->priv->extension);
+ if ((ext = strrchr (short_name, '.')) && ext[1] != '\0')
+ window->priv->extension = g_strdup (&ext[1]);
+ else
+ window->priv->extension = NULL;
+
+ utf8_name = g_filename_to_utf8 (short_name, -1, NULL, NULL, NULL);
+ if (priv->name_label != NULL) {
+ gtk_label_set_text (GTK_LABEL (priv->name_label),
+ utf8_name);
+ }
+
+ gsr_add_recent (priv->filename);
+
+ /*Translators: this is the window title, %s is the currently open file's name or Untitled*/
+ title = g_strdup_printf (_("%s — Sound Recorder"), utf8_name);
+ gtk_window_set_title (GTK_WINDOW (window), title);
+ g_free (title);
+ g_free (utf8_name);
+ g_free (short_name);
+
+ set_action_sensitive (window, "Play", window->priv->has_file ? TRUE : FALSE);
+ set_action_sensitive (window, "Stop", FALSE);
+ set_action_sensitive (window, "Record", TRUE);
+ set_action_sensitive (window, "FileSave", window->priv->has_file ? TRUE : FALSE);
+ set_action_sensitive (window, "FileSaveAs", TRUE);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gsr_window_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ case PROP_LOCATION:
+ g_value_set_string (value, GSR_WINDOW (object)->priv->filename);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+gsr_window_finalize (GObject *object)
+{
+ GSRWindow *window;
+ GSRWindowPrivate *priv;
+
+ window = GSR_WINDOW (object);
+ priv = window->priv;
+
+ GST_DEBUG ("finalizing ...");
+
+ if (priv == NULL) {
+ return;
+ }
+
+ if (priv->ui_manager) {
+ g_object_unref (priv->ui_manager);
+ priv->ui_manager = NULL;
+ }
+
+ if (priv->action_group) {
+ g_object_unref (priv->action_group);
+ priv->action_group = NULL;
+ }
+
+ if (priv->tick_id > 0) {
+ g_source_remove (priv->tick_id);
+ window->priv->play->tick_id = 0;
+ }
+
+ if (priv->record_id > 0) {
+ g_source_remove (priv->record_id);
+ }
+
+ if (priv->ebusy_timeout_id > 0) {
+ g_source_remove (window->priv->ebusy_timeout_id);
+ }
+
+ g_idle_remove_by_data (window);
+
+ if (priv->play != NULL) {
+ shutdown_pipeline (priv->play);
+ g_free (priv->play);
+ }
+
+ if (priv->record != NULL) {
+ shutdown_pipeline (priv->record);
+ g_free (priv->record);
+ }
+
+ unlink (priv->record_filename);
+ g_free (priv->record_filename);
+
+ g_free (priv->working_file);
+ g_free (priv->filename);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+
+ window->priv = NULL;
+}
+
+static void
+gsr_window_class_init (GSRWindowClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gsr_window_finalize;
+ object_class->set_property = gsr_window_set_property;
+ object_class->get_property = gsr_window_get_property;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ g_object_class_install_property (object_class,
+ PROP_LOCATION,
+ g_param_spec_string ("location",
+ "Location",
+ "",
+ /* Translator comment: default trackname is 'untitled', which
+ * has as effect that the user cannot save to this file. The
+ * 'save' action will open the save-as dialog instead to give
+ * a proper filename. See mate-record.c:94. */
+ _("Untitled"),
+ G_PARAM_READWRITE));
+
+ g_type_class_add_private (object_class, sizeof (GSRWindowPrivate));
+
+ GST_DEBUG_CATEGORY_INIT (gsr_debug, "gsr", 0, "Mate Sound Recorder");
+}
+
+GType
+gsr_window_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ GTypeInfo info = {
+ sizeof (GSRWindowClass),
+ NULL, NULL,
+ (GClassInitFunc) gsr_window_class_init,
+ NULL, NULL,
+ sizeof (GSRWindow), 0,
+ (GInstanceInitFunc) gsr_window_init
+ };
+
+ type = g_type_register_static (GTK_TYPE_WINDOW,
+ "GSRWindow",
+ &info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+gsr_window_new (const char *filename)
+{
+ GSRWindow *window;
+ char *template;
+
+ /* filename has been changed to be without extension */
+ window = g_object_new (GSR_TYPE_WINDOW,
+ "location", filename,
+ NULL);
+ /* FIXME: check extension too */
+ window->priv->filename = g_strdup (filename);
+ if (g_file_test (filename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR) != FALSE) {
+ window->priv->has_file = TRUE;
+ window->priv->dirty = FALSE;
+ } else {
+ window->priv->has_file = FALSE;
+ }
+
+ template = g_strdup_printf ("gsr-record-%s-%d.XXXXXX", filename, getpid ());
+ window->priv->record_fd = g_file_open_tmp (template, &window->priv->record_filename, NULL);
+ g_free (template);
+ close (window->priv->record_fd);
+
+ if (window->priv->has_file == FALSE) {
+ g_free (window->priv->working_file);
+ window->priv->working_file = g_strdup (window->priv->record_filename);
+ } else {
+ g_free (window->priv->working_file);
+ window->priv->working_file = g_strdup (filename);
+ }
+
+ window->priv->saved = TRUE;
+
+ gtk_window_set_default_size (GTK_WINDOW (window), 512, 200);
+
+ return GTK_WIDGET (window);
+}
diff --git a/grecord/src/gsr-window.h b/grecord/src/gsr-window.h
new file mode 100644
index 0000000..6b5a67e
--- /dev/null
+++ b/grecord/src/gsr-window.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Iain Holmes <[email protected]>
+ *
+ * Copyright 2002 Iain Holmes
+ *
+ * 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.
+ *
+ * 4th Februrary 2005: Christian Schaller: changed license to LGPL with
+ * permission of Iain Holmes, Ronald Bultje, Leontine Binchy (SUN), Johan Dahlin
+ * and Joe Marcus Clarke
+ *
+ */
+
+#ifndef __GSR_WINDOW_H__
+#define __GSR_WINDOW_H__
+
+#include <gtk/gtk.h>
+
+#define GSR_TYPE_WINDOW (gsr_window_get_type ())
+#define GSR_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSR_TYPE_WINDOW, GSRWindow))
+#define GSR_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSR_TYPE_WINDOW, GSRWindowClass))
+#define GSR_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSR_TYPE_WINDOW))
+#define GSR_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSR_TYPE_WINDOW))
+
+typedef struct _GSRWindow GSRWindow;
+typedef struct _GSRWindowClass GSRWindowClass;
+typedef struct _GSRWindowPrivate GSRWindowPrivate;
+
+struct _GSRWindow {
+ GtkWindow parent;
+
+ GSRWindowPrivate *priv;
+};
+
+struct _GSRWindowClass {
+ GtkWindowClass parent_class;
+};
+
+
+GType gsr_window_get_type (void);
+
+GtkWidget* gsr_window_new (const char *filename);
+void gsr_window_close (GSRWindow *window);
+gboolean gsr_window_is_saved (GSRWindow *window);
+gboolean gsr_discard_confirmation_dialog (GSRWindow *window, gboolean closing);
+
+#endif
diff --git a/grecord/src/mate-recorder.c b/grecord/src/mate-recorder.c
new file mode 100644
index 0000000..482d014
--- /dev/null
+++ b/grecord/src/mate-recorder.c
@@ -0,0 +1,232 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Iain Holmes <[email protected]>
+ *
+ * Copyright 2002, 2003, 2004, 2005 Iain Holmes
+ * 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.
+ *
+ * 4th Februrary 2005: Christian Schaller: changed license to LGPL with
+ * permission of Iain Holmes, Ronald Bultje, Leontine Binchy (SUN), Johan Dahlin * and Joe Marcus Clarke
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <mateconf/mateconf-client.h>
+#include <gst/gst.h>
+
+#include "gsr-window.h"
+
+void gsr_quit (void);
+void gsr_add_recent (gchar *filename);
+GtkWidget * gsr_open_window (const char *filename);
+
+extern void mate_media_profiles_init (MateConfClient *conf);
+
+static GList *windows = NULL;
+
+/* Also used in gsr-window.c as extern MateConfClient *mateconf_client */
+MateConfClient *mateconf_client = NULL;
+
+static gboolean
+delete_event_cb (GSRWindow *window,
+ gpointer data)
+{
+ if (!gsr_window_is_saved (window) && !gsr_discard_confirmation_dialog (window, TRUE))
+ return TRUE;
+
+ return FALSE;
+}
+
+static void
+window_destroyed (GtkWidget *window,
+ gpointer data)
+{
+ windows = g_list_remove (windows, window);
+
+ if (windows == NULL) {
+ gtk_main_quit ();
+ }
+}
+
+void
+gsr_quit (void)
+{
+ GList *p;
+
+ for (p = windows; p;) {
+ GSRWindow *window = p->data;
+
+ /* p is set here instead of in the for statement,
+ because by the time we get back to the loop,
+ p will be invalid */
+ p = p->next;
+
+ if (gsr_window_is_saved (window) || gsr_discard_confirmation_dialog (window, TRUE))
+ gsr_window_close (window);
+ }
+}
+
+void
+gsr_add_recent (gchar *filename)
+{
+ GtkRecentData data;
+ char *groups[] = { NULL, NULL };
+ char *uri;
+
+ memset (&data, 0, sizeof (data));
+
+ uri = g_filename_to_uri (filename, NULL, NULL);
+ if (uri == NULL)
+ return;
+
+ data.mime_type = g_content_type_guess (uri, NULL, 0, NULL);
+ if (data.mime_type == NULL) {
+ /* No mime-type means warnings, and it breaks when adding
+ * non-GIO supported URI schemes */
+ g_free (uri);
+ return;
+ }
+
+ /* It's a local file */
+ data.display_name = g_filename_display_basename (data.display_name);
+ groups[0] = "Totem";
+
+ data.app_name = g_strdup (g_get_application_name ());
+ data.app_exec = g_strjoin (" ", g_get_prgname (), "%u", NULL);
+ data.groups = groups;
+ gtk_recent_manager_add_full (gtk_recent_manager_get_default (),
+ uri, &data);
+
+ g_free (data.display_name);
+ g_free (data.mime_type);
+ g_free (data.app_name);
+ g_free (data.app_exec);
+
+}
+
+/* Also referenced from gsr-window.c */
+gint gsr_sample_count = 1;
+
+GtkWidget *
+gsr_open_window (const char *filename)
+{
+ GtkWidget *window;
+ char *utf8_name;
+ char *name;
+
+ if (filename == NULL) {
+ /* Translator comment: untitled here implies that
+ * there is no active sound sample. Any newly
+ * recorded samples will be saved to disk with this
+ * name as default value. */
+ if (gsr_sample_count == 1) {
+ utf8_name = g_strdup (_("Untitled"));
+ } else {
+ utf8_name = g_strdup_printf (_("Untitled-%d"), gsr_sample_count);
+ }
+ name = g_filename_from_utf8 (utf8_name, -1, NULL, NULL, NULL);
+ g_free (utf8_name);
+ ++gsr_sample_count;
+ } else {
+ name = g_strdup (filename);
+ }
+
+ window = GTK_WIDGET (gsr_window_new (name));
+ g_free (name);
+
+ g_signal_connect (G_OBJECT (window), "delete-event",
+ G_CALLBACK (delete_event_cb), NULL);
+
+ g_signal_connect (G_OBJECT (window), "destroy",
+ G_CALLBACK (window_destroyed), NULL);
+
+ windows = g_list_prepend (windows, window);
+ gtk_widget_show (window);
+
+ return window;
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ gchar **filenames = NULL;
+ /* this is necessary because someone apparently forgot to add a
+ * convenient way to get the remaining arguments to the MateProgram
+ * API when adding the GOption stuff to it ... */
+ const GOptionEntry entries[] = {
+ { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames,
+ "Special option that collects any remaining arguments for us" },
+ { NULL, }
+ };
+
+ GOptionContext *ctx;
+ GError *error = NULL;
+
+ g_thread_init (NULL);
+
+ /* Init gettext */
+ bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ ctx = g_option_context_new ("mate-sound-recorder");
+ /* Initializes gtk during option parsing */
+ g_option_context_add_group (ctx, gtk_get_option_group (TRUE));
+ g_option_context_add_group (ctx, gst_init_get_option_group ());
+ g_option_context_add_main_entries (ctx, entries, GETTEXT_PACKAGE);
+
+ if (!g_option_context_parse (ctx, &argc, &argv, &error)) {
+ g_printerr ("Option parsing failed: %s\n", error->message);
+ g_error_free (error);
+ g_option_context_free (ctx);
+ return EXIT_FAILURE;
+ }
+
+ g_option_context_free (ctx);
+ gtk_window_set_default_icon_name ("mate-sound-recorder");
+
+ /* use it like a singleton */
+ mateconf_client = mateconf_client_get_default ();
+
+ /* init mate-media-profiles */
+ mate_media_profiles_init (mateconf_client);
+
+ if (filenames != NULL && filenames[0] != NULL) {
+ guint i, num;
+
+ num = g_strv_length (filenames);
+ for (i = 0; i < num; ++i) {
+ gsr_open_window (filenames[i]);
+ }
+ } else {
+ gsr_open_window (NULL);
+ }
+
+ if (filenames) {
+ g_strfreev (filenames);
+ }
+
+ gtk_main ();
+
+ return 0;
+}
diff --git a/grecord/src/ui.xml b/grecord/src/ui.xml
new file mode 100644
index 0000000..a4e9108
--- /dev/null
+++ b/grecord/src/ui.xml
@@ -0,0 +1,41 @@
+<ui>
+
+ <menubar name="MenuBar">
+ <menu name="FileMenu" action="File">
+ <menuitem action="FileNew"/>
+ <menuitem action="FileOpen"/>
+ <separator/>
+ <menuitem action="FileSave"/>
+ <menuitem action="FileSaveAs"/>
+ <separator/>
+ <menuitem action="RunMixer"/>
+ <menuitem action="FileProperties"/>
+ <separator/>
+ <placeholder name="FileRecentMenu"/>
+ <menuitem action="FileClose"/>
+ <menuitem action="Quit"/>
+ </menu>
+
+ <menu name="ControlMenu" action="Control">
+ <menuitem action="Record"/>
+ <menuitem action="Play"/>
+ <menuitem action="Stop"/>
+ </menu>
+
+ <menu name="HelpMenu" action="Help">
+ <menuitem action="HelpContents"/>
+ <menuitem action="About"/>
+ </menu>
+ </menubar>
+
+ <toolbar name="ToolBar">
+ <toolitem action="FileNew"/>
+ <toolitem action="FileOpen"/>
+ <toolitem action="FileSave"/>
+ <separator/>
+ <toolitem action="Record"/>
+ <toolitem action="Play"/>
+ <toolitem action="Stop"/>
+ </toolbar>
+
+</ui>