diff -Nurp tvtime-1.0.2/configure.ac tvtime-1.0.2-custom/configure.ac
--- tvtime-1.0.2/configure.ac 2005-09-14 23:40:44.000000000 +0200
+++ tvtime-1.0.2-custom/configure.ac 2011-05-29 13:07:28.219041386 +0200
@@ -10,12 +10,7 @@ if test x"$host_alias" = x""; then host_
# Check for compilers.
AC_PROG_CC
-AC_CHECK_PROG(found_cc, "$CC", yes, no)
-test "x$found_cc" = "xyes" || exit 1
-
AC_PROG_CXX
-AC_CHECK_PROG(found_cxx, "$CXX", yes, no)
-test "x$found_cxx" = "xyes" || exit 1
# Check for libtool.
AC_PROG_LIBTOOL
@@ -74,18 +69,26 @@ dnl ------------------------------------
dnl libxml2
dnl ---------------------------------------------
dnl Test for libxml2
-
AC_PATH_PROG(LIBXML2_CONFIG,xml2-config,no)
if test "$LIBXML2_CONFIG" = "no" ; then
AC_MSG_ERROR(libxml2 needed and xml2-config not found)
else
XML2_LIBS="`$LIBXML2_CONFIG --libs`"
XML2_FLAG="`$LIBXML2_CONFIG --cflags`"
- AC_DEFINE(HAVE_LIBXML2,,[LIBXML2 support])
+ AC_DEFINE(HAVE_LIBXML2,,[LIBXML2 support])
fi
AC_SUBST(XML2_LIBS)
AC_SUBST(XML2_FLAG)
+dnl ---------------------------------------------
+dnl libasound2
+dnl ---------------------------------------------
+dnl Test for ALSA
+AM_PATH_ALSA(1.0.9,
+ [ AC_DEFINE(HAVE_ALSA,1,[Define this if you have Alsa (libasound) installed]) ],
+ AC_MSG_RESULT(libasound needed and not found))
+AM_CONDITIONAL(HAVE_ALSA, test x"$no_alsa" != "yes")
+
dnl ---------------------------------------------
dnl check for gtk+-2.0
@@ -99,6 +102,8 @@ dnl ------------------------------------
dnl check for X11, Xv and XF86VidModeExtension
dnl ---------------------------------------------
AC_PATH_XTRA
+AC_ARG_WITH([xinerama],
+ [AS_HELP_STRING([--without-xinerama], [Disable Xinerama extension support (default: check)])])
if test x"$no_x" != x"yes"; then
dnl check for Xshm
AC_CHECK_LIB([Xext],[XShmCreateImage],
@@ -112,16 +117,18 @@ if test x"$no_x" != x"yes"; then
X11_LIBS="$X11_LIBS -lXv"],,
[$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS -lXext])
- dnl check for Xinerama
- AC_CHECK_LIB([Xinerama],[XineramaQueryScreens],
- [AC_DEFINE([HAVE_XINERAMA],,[Xinerama support])
- X11_LIBS="$X11_LIBS -lXinerama"],,
- [$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS -lXext])
-
- dnl check for XTest
- AC_CHECK_LIB([Xtst],[XTestFakeKeyEvent],
- [AC_DEFINE([HAVE_XTESTEXTENSION],,[XTest support])
- X11_LIBS="$X11_LIBS -lXtst"],,
+ if test "x$with_xinerama" != "xno"; then
+ dnl check for Xinerama
+ AC_CHECK_LIB([Xinerama],[XineramaQueryScreens],
+ [AC_DEFINE([HAVE_XINERAMA],,[Xinerama support])
+ X11_LIBS="$X11_LIBS -lXinerama"],,
+ [$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS -lXext])
+ fi
+
+ dnl check for XSs
+ AC_CHECK_LIB([Xss],[XScreenSaverSuspend],
+ [AC_DEFINE([HAVE_XSSEXTENSION],,[XSs support])
+ X11_LIBS="$X11_LIBS -lXss"],,
[$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS -lXext])
dnl check for Xvidmode
diff -Nurp tvtime-1.0.2/configure.ac.orig tvtime-1.0.2-custom/configure.ac.orig
--- tvtime-1.0.2/configure.ac.orig 1970-01-01 01:00:00.000000000 +0100
+++ tvtime-1.0.2-custom/configure.ac.orig 2011-05-29 13:07:28.159040652 +0200
@@ -0,0 +1,244 @@
+# Process this file with autoconf to produce a configure script.
+AC_PREREQ(2.52)
+AC_INIT(tvtime, 1.0.2, http://tvtime.net/)
+AC_CONFIG_SRCDIR([src/tvtime.c])
+AM_INIT_AUTOMAKE(tvtime,1.0.2)
+AM_CONFIG_HEADER(config.h)
+AM_MAINTAINER_MODE
+AC_CANONICAL_HOST
+if test x"$host_alias" = x""; then host_alias="$host"; fi
+
+# Check for compilers.
+AC_PROG_CC
+AC_CHECK_PROG(found_cc, "$CC", yes, no)
+test "x$found_cc" = "xyes" || exit 1
+
+AC_PROG_CXX
+AC_CHECK_PROG(found_cxx, "$CXX", yes, no)
+test "x$found_cxx" = "xyes" || exit 1
+
+# Check for libtool.
+AC_PROG_LIBTOOL
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS([ctype.h dirent.h errno.h fcntl.h getopt.h langinfo.h math.h netinet/in.h pwd.h signal.h stdint.h stdio.h stdlib.h string.h sys/ioctl.h sys/mman.h sys/resource.h sys/stat.h sys/time.h sys/wait.h sys/types.h unistd.h wordexp.h locale.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_HEADER_TIME
+
+# Checks for library functions.
+AC_PROG_GCC_TRADITIONAL
+AC_FUNC_MMAP
+AC_CHECK_FUNCS([asprintf atexit fork execlp getopt_long getpriority gettimeofday seteuid memset setreuid setpriority signal sigemptyset sigaction strerror vsscanf wordexp wordfree])
+
+# Check for gettext
+AM_GNU_GETTEXT
+
+dnl ---------------------------------------------
+dnl zlib
+dnl ---------------------------------------------
+dnl Test for libz
+AC_CHECK_LIB(z, gzsetparams,
+ [ AC_CHECK_HEADER(zlib.h,
+ have_zlib=yes
+ ZLIB_LIBS="-lz",)], AC_MSG_ERROR(zlib needed))
+
+AM_CONDITIONAL(HAVE_ZLIB, [test x"$have_zlib" = "xyes"])
+AC_SUBST(ZLIB_LIBS)
+
+
+dnl ---------------------------------------------
+dnl libpng
+dnl ---------------------------------------------
+dnl Test for libpng
+AC_CHECK_LIB(png, png_read_png,
+ [ AC_CHECK_HEADER(png.h,
+ have_libpng=yes
+ PNG_LIBS="-lpng $ZLIB_LIBS -lm",)], AC_MSG_ERROR(libpng needed), "$ZLIB_LIBS" -lm)
+
+AM_CONDITIONAL(HAVE_LIBPNG, [test x"$have_libpng" = "xyes"])
+AC_SUBST(PNG_LIBS)
+
+
+dnl ---------------------------------------------
+dnl freetype
+dnl ---------------------------------------------
+dnl Test for freetype
+AC_PATH_PROG(FREETYPE_CONFIG, freetype-config, no)
+if test "$FREETYPE_CONFIG" = "no" ; then
+ AC_MSG_ERROR(freetype2 needed and freetype-config not found)
+fi
+
+dnl ---------------------------------------------
+dnl libxml2
+dnl ---------------------------------------------
+dnl Test for libxml2
+AC_PATH_PROG(LIBXML2_CONFIG,xml2-config,no)
+if test "$LIBXML2_CONFIG" = "no" ; then
+ AC_MSG_ERROR(libxml2 needed and xml2-config not found)
+else
+ XML2_LIBS="`$LIBXML2_CONFIG --libs`"
+ XML2_FLAG="`$LIBXML2_CONFIG --cflags`"
+ AC_DEFINE(HAVE_LIBXML2,,[LIBXML2 support])
+fi
+AC_SUBST(XML2_LIBS)
+AC_SUBST(XML2_FLAG)
+
+dnl ---------------------------------------------
+dnl libasound2
+dnl ---------------------------------------------
+dnl Test for ALSA
+AM_PATH_ALSA(1.0.9,
+ [ AC_DEFINE(HAVE_ALSA,1,[Define this if you have Alsa (libasound) installed]) ],
+ AC_MSG_RESULT(libasound needed and not found))
+AM_CONDITIONAL(HAVE_ALSA, test x"$no_alsa" != "yes")
+
+
+dnl ---------------------------------------------
+dnl check for gtk+-2.0
+dnl ---------------------------------------------
+dnl PKG_CHECK_MODULES(GTK, gtk+-2.0)
+dnl AC_SUBST(GTK_CFLAGS)
+dnl AC_SUBST(GTK_LIBS)
+
+
+dnl ---------------------------------------------
+dnl check for X11, Xv and XF86VidModeExtension
+dnl ---------------------------------------------
+AC_PATH_XTRA
+AC_ARG_WITH([xinerama],
+ [AS_HELP_STRING([--without-xinerama], [Disable Xinerama extension support (default: check)])])
+if test x"$no_x" != x"yes"; then
+ dnl check for Xshm
+ AC_CHECK_LIB([Xext],[XShmCreateImage],
+ [AC_DEFINE([HAVE_X11],,[X11 support])
+ X11_CFLAGS="$X_CFLAGS"
+ X11_LIBS="$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS -lXext"
+
+ dnl check for Xv
+ AC_CHECK_LIB([Xv],[XvShmCreateImage],
+ [AC_DEFINE([HAVE_XV],,[Xv support])
+ X11_LIBS="$X11_LIBS -lXv"],,
+ [$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS -lXext])
+
+ if test "x$with_xinerama" != "xno"; then
+ dnl check for Xinerama
+ AC_CHECK_LIB([Xinerama],[XineramaQueryScreens],
+ [AC_DEFINE([HAVE_XINERAMA],,[Xinerama support])
+ X11_LIBS="$X11_LIBS -lXinerama"],,
+ [$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS -lXext])
+ fi
+
+ dnl check for XTest
+ AC_CHECK_LIB([Xtst],[XTestFakeKeyEvent],
+ [AC_DEFINE([HAVE_XTESTEXTENSION],,[XTest support])
+ X11_LIBS="$X11_LIBS -lXtst"],,
+ [$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS -lXext])
+
+ dnl check for Xvidmode
+ AC_CHECK_LIB([Xxf86vm],[XF86VidModeGetModeLine],
+ [AC_DEFINE([HAVE_XF86VIDMODE],,[XF86VidModeExtension support])
+ X11_LIBS="$X11_LIBS -lXxf86vm"],,
+ [$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS -lXext])],,
+ [$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS])
+else
+ AC_MSG_ERROR(X needed and no X libraries or development headers found)
+fi
+AC_SUBST(X11_CFLAGS)
+AC_SUBST(X11_LIBS)
+
+dnl This stuff looked kinda cool in the mpeg2dec source tree.
+
+dnl GCC-specific flags
+if test x"$GCC" = x"yes"; then
+
+ dnl -Wall -Werror moved to the end to not disturb the configure script
+
+ dnl -O3
+ changequote(<<,>>)
+ OPT_CFLAGS=`echo "$CFLAGS"|sed "s/-O[0-9]*//g;"`
+ changequote([,])
+ OPT_CFLAGS="$OPT_CFLAGS -O3"
+ AC_TRY_CFLAGS([$OPT_CFLAGS],[CFLAGS=$OPT_CFLAGS])
+
+ dnl -fomit-frame-pointer
+ OPT_CFLAGS="$CFLAGS -fomit-frame-pointer"
+ AC_TRY_CFLAGS([$OPT_CFLAGS],[CFLAGS=$OPT_CFLAGS])
+
+ dnl -std=gnu99
+ OPT_CFLAGS="$CFLAGS -std=gnu99"
+ AC_TRY_CFLAGS([$OPT_CFLAGS],[CFLAGS=$OPT_CFLAGS])
+
+ dnl arch-specific flags
+ case "$host_alias" in
+ i?86-* | k?-*)
+ AC_DEFINE([ARCH_X86],,[x86 architecture])
+ AC_DEFINE([ARCH_386],,[386 architecture])
+ ARCH_X86=yes
+ ARCH_386=yes
+ OPT_CFLAGS="$CFLAGS"
+ AC_TRY_CFLAGS([$OPT_CFLAGS],[CFLAGS=$OPT_CFLAGS]);;
+ x86_64-*)
+ AC_DEFINE([ARCH_X86],,[x86 architecture])
+ AC_DEFINE([ARCH_X86_64],,[x86_64 architecture])
+ ARCH_X86=yes
+ ARCH_X86_64=yes;;
+ ppc-* | powerpc-*)
+ OPT_CFLAGS="$CFLAGS -Wa,-m7400"
+ AC_TRY_CFLAGS([$OPT_CFLAGS],
+ [CFLAGS=$OPT_CFLAGS; AC_DEFINE([ARCH_PPC],,[ppc architecture])]);;
+ sparc-* | sparc64-*)
+ OPT_CFLAGS="$CFLAGS -mcpu=ultrasparc -mvis -Wa,-Av9"
+ AC_TRY_CFLAGS([$OPT_CFLAGS],[CFLAGS=$OPT_CFLAGS]);;
+ mips-sgi-irix6.*) dnl do we need to be that specific ?
+ OPT_CFLAGS="$CFLAGS -mabi=64"
+ AC_TRY_CFLAGS([$OPT_CFLAGS],[CFLAGS=$OPT_CFLAGS]);;
+ esac
+elif test x"$CC" = x"tcc"; then
+ dnl TenDRA portability checking compiler
+ CFLAGS="-Xp -Yansi -f`pwd`/include/tendra.h"
+ enable_mlib=no
+ no_x=yes
+ enable_sdl=no
+else
+ dnl non-gcc flags - we probably need exact configuration triplets here.
+ case "$host_alias" in
+ mips-sgi-irix6.*)
+ OPT_CFLAGS="$CFLAGS -64"
+ AC_TRY_CFLAGS([$OPT_CFLAGS],[CFLAGS=$OPT_CFLAGS]);;
+ sparc-sun-solaris*)
+ OPT_CFLAGS="$CFLAGS -xCC -fast -xO5"
+ AC_TRY_CFLAGS([$OPT_CFLAGS],[CFLAGS=$OPT_CFLAGS]);;
+ esac
+fi
+AM_CONDITIONAL(ARCH_X86, [test "$ARCH_X86" = "yes"])
+AM_CONDITIONAL(ARCH_386, [test "$ARCH_386" = "yes"])
+AM_CONDITIONAL(ARCH_X86_64, [test "$ARCH_X86_64" = "yes"])
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS([memalign])
+AC_TYPE_SIGNAL
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_C_INLINE
+AC_TYPE_SIZE_T
+AC_C_BIGENDIAN
+AC_C_ATTRIBUTE_ALIGNED
+
+AC_CONFIG_FILES([
+ Makefile
+ docs/Makefile
+ data/Makefile
+ plugins/Makefile
+ src/Makefile
+ intl/Makefile
+ po/Makefile.in
+ m4/Makefile
+ docs/man/Makefile
+ docs/man/de/Makefile
+ docs/man/en/Makefile
+ docs/man/es/Makefile
+])
+AC_OUTPUT
diff -Nurp tvtime-1.0.2/docs/html/default.tvtime.xml tvtime-1.0.2-custom/docs/html/default.tvtime.xml
--- tvtime-1.0.2/docs/html/default.tvtime.xml 2005-09-08 06:06:57.000000000 +0200
+++ tvtime-1.0.2-custom/docs/html/default.tvtime.xml 2011-05-29 13:07:28.139040408 +0200
@@ -116,13 +116,15 @@
<option name="VBIDevice" value="/dev/vbi0"/>
<!--
- This sets the mixer device and channel to use. The format is device
- name:channel name. Valid channels are:
+ This sets the mixer device and channel to use. The format for OSS
+ is device name:channel name. Valid OSS channels are:
vol, bass, treble, synth, pcm, speaker, line, mic, cd, mix, pcm2,
rec, igain, ogain, line1, line2, line3, dig1, dig2, dig3, phin,
phout, video, radio, monitor
+ The format for ALSA mixer is device/channel (e.g., "default/Line"
+ or "hw:0/CD")
-->
- <option name="MixerDevice" value="/dev/mixer:line"/>
+ <option name="MixerDevice" value="default/Line"/>
<!--
This option enables 16:9 aspect ratio mode by default on startup.
diff -Nurp tvtime-1.0.2/docs/man/en/tvtime.xml.5 tvtime-1.0.2-custom/docs/man/en/tvtime.xml.5
--- tvtime-1.0.2/docs/man/en/tvtime.xml.5 2005-09-08 06:05:35.000000000 +0200
+++ tvtime-1.0.2-custom/docs/man/en/tvtime.xml.5 2011-05-29 13:07:28.139040408 +0200
@@ -234,7 +234,10 @@ This sets which device to use for VBI de
.TP
<option name="MixerDevice" value="/dev/mixer:line"/>
This sets the mixer device and channel to use. The format is device
-name:channel name. Valid channels are:
+name:channel name for OSS mixer (e.g., "/dev/mixer:Line") or device/channel
+for ALSA (e.g., "hw:0/CD").
+
+Valid OSS channels are:
.nh
.IR vol ", " bass ", " treble ", " synth ", " pcm ", " speaker ", "
diff -Nurp tvtime-1.0.2/plugins/greedyh.asm tvtime-1.0.2-custom/plugins/greedyh.asm
--- tvtime-1.0.2/plugins/greedyh.asm 2005-08-14 18:16:43.000000000 +0200
+++ tvtime-1.0.2-custom/plugins/greedyh.asm 2011-05-29 13:07:28.085706424 +0200
@@ -18,7 +18,7 @@
#include "x86-64_macros.inc"
-void DScalerFilterGreedyH::FUNCT_NAME(TDeinterlaceInfo* pInfo)
+void FUNCT_NAME(TDeinterlaceInfo* pInfo)
{
int64_t i;
bool InfoIsOdd = (pInfo->PictureHistory[0]->Flags & PICTURE_INTERLACED_ODD) ? 1 : 0;
diff -Nurp tvtime-1.0.2/plugins/tomsmocomp/TomsMoCompAll2.inc tvtime-1.0.2-custom/plugins/tomsmocomp/TomsMoCompAll2.inc
--- tvtime-1.0.2/plugins/tomsmocomp/TomsMoCompAll2.inc 2004-10-20 17:31:05.000000000 +0200
+++ tvtime-1.0.2-custom/plugins/tomsmocomp/TomsMoCompAll2.inc 2011-05-29 13:07:28.085706424 +0200
@@ -5,9 +5,9 @@
#endif
#ifdef USE_STRANGE_BOB
-#define SEARCH_EFFORT_FUNC(n) DScalerFilterTomsMoComp::SEFUNC(n##_SB)
+#define SEARCH_EFFORT_FUNC(n) SEFUNC(n##_SB)
#else
-#define SEARCH_EFFORT_FUNC(n) DScalerFilterTomsMoComp::SEFUNC(n)
+#define SEARCH_EFFORT_FUNC(n) SEFUNC(n)
#endif
int SEARCH_EFFORT_FUNC(0) // we don't try at all ;-)
diff -Nurp tvtime-1.0.2/plugins/tomsmocomp.cpp tvtime-1.0.2-custom/plugins/tomsmocomp.cpp
--- tvtime-1.0.2/plugins/tomsmocomp.cpp 2004-10-20 19:38:04.000000000 +0200
+++ tvtime-1.0.2-custom/plugins/tomsmocomp.cpp 2011-05-29 13:07:28.089039798 +0200
@@ -31,7 +31,7 @@ public:
#define IS_MMX
#define SSE_TYPE MMX
-#define FUNCT_NAME DScalerFilterTomsMoComp::filterDScaler_MMX
+#define FUNCT_NAME filterDScaler_MMX
#include "tomsmocomp/TomsMoCompAll.inc"
#undef IS_MMX
#undef SSE_TYPE
@@ -39,7 +39,7 @@ public:
#define IS_3DNOW
#define SSE_TYPE 3DNOW
-#define FUNCT_NAME DScalerFilterTomsMoComp::filterDScaler_3DNOW
+#define FUNCT_NAME filterDScaler_3DNOW
#include "tomsmocomp/TomsMoCompAll.inc"
#undef IS_3DNOW
#undef SSE_TYPE
@@ -47,7 +47,7 @@ public:
#define IS_SSE
#define SSE_TYPE SSE
-#define FUNCT_NAME DScalerFilterTomsMoComp::filterDScaler_SSE
+#define FUNCT_NAME filterDScaler_SSE
#include "tomsmocomp/TomsMoCompAll.inc"
#undef IS_SSE
#undef SSE_TYPE
diff -Nurp tvtime-1.0.2/src/commands.c tvtime-1.0.2-custom/src/commands.c
--- tvtime-1.0.2/src/commands.c 2005-11-10 03:39:05.000000000 +0100
+++ tvtime-1.0.2-custom/src/commands.c 2011-05-29 13:07:28.169040774 +0200
@@ -128,6 +128,7 @@ struct commands_s {
int togglepulldowndetection;
int togglematte;
int togglequiet;
+ int changedoverscan;
int framerate;
int scan_channels;
int pause;
@@ -2900,7 +2901,7 @@ void commands_handle( commands_t *cmd, i
case TVTIME_OVERSCAN_DOWN:
cmd->overscan = cmd->overscan + ( (tvtime_cmd == TVTIME_OVERSCAN_UP) ? 0.0025 : -0.0025 );
if( cmd->overscan > 0.4 ) cmd->overscan = 0.4; if( cmd->overscan < 0.0 ) cmd->overscan = 0.0;
-
+ cmd->changedoverscan = 1;
if( cmd->osd ) {
char message[ 200 ];
snprintf( message, sizeof( message ), _("Overscan: %.1f%%"),
@@ -3056,10 +3057,10 @@ void commands_handle( commands_t *cmd, i
break;
case TVTIME_MIXER_TOGGLE_MUTE:
- mixer_mute( !mixer_ismute() );
+ mixer->mute( !mixer->ismute() );
if( cmd->osd ) {
- tvtime_osd_show_data_bar( cmd->osd, _("Volume"), (mixer_get_volume()) & 0xff );
+ tvtime_osd_show_data_bar( cmd->osd, _("Volume"), (mixer->get_volume()) & 0xff );
}
break;
@@ -3073,9 +3074,9 @@ void commands_handle( commands_t *cmd, i
/* Check to see if an argument was passed, if so, use it. */
if (atoi(arg) > 0) {
int perc = atoi(arg);
- volume = mixer_set_volume( ( (tvtime_cmd == TVTIME_MIXER_UP) ? perc : -perc ) );
+ volume = mixer->set_volume( ( (tvtime_cmd == TVTIME_MIXER_UP) ? perc : -perc ) );
} else {
- volume = mixer_set_volume( ( (tvtime_cmd == TVTIME_MIXER_UP) ? 1 : -1 ) );
+ volume = mixer->set_volume( ( (tvtime_cmd == TVTIME_MIXER_UP) ? 1 : -1 ) );
}
if( cmd->osd ) {
@@ -3492,6 +3493,7 @@ void commands_next_frame( commands_t *cm
cmd->togglepulldowndetection = 0;
cmd->togglematte = 0;
cmd->togglequiet = 0;
+ cmd->changedoverscan = 0;
cmd->resizewindow = 0;
cmd->setdeinterlacer = 0;
cmd->setfreqtable = 0;
@@ -3539,6 +3541,11 @@ int commands_toggle_aspect( commands_t *
return cmd->toggleaspect;
}
+int commands_get_changed_overscan( commands_t *cmd )
+{
+ return cmd->changedoverscan;
+}
+
int commands_toggle_alwaysontop( commands_t *cmd )
{
return cmd->togglealwaysontop;
diff -Nurp tvtime-1.0.2/src/commands.c.orig tvtime-1.0.2-custom/src/commands.c.orig
--- tvtime-1.0.2/src/commands.c.orig 1970-01-01 01:00:00.000000000 +0100
+++ tvtime-1.0.2-custom/src/commands.c.orig 2011-05-29 13:07:28.102373294 +0200
@@ -0,0 +1,3771 @@
+/**
+ * Copyright (C) 2002 Doug Bell <drbell@users.sourceforge.net>.
+ * Copyright (C) 2003 Billy Biggs <vektor@dumbterm.net>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <time.h>
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#ifdef ENABLE_NLS
+# define _(string) gettext (string)
+# include "gettext.h"
+#else
+# define _(string) (string)
+#endif
+#include "station.h"
+#include "mixer.h"
+#include "input.h"
+#include "commands.h"
+#include "utils.h"
+#include "xmltv.h"
+#include "tvtimeglyphs.h"
+
+#define NUM_FAVORITES 9
+#define MAX_USER_MENUS 64
+
+/* Maximum number of steps to increment sleeptimer. */
+#define SLEEPTIMER_NUMSTEPS 13
+
+enum menu_type
+{
+ MENU_REDIRECT,
+ MENU_FAVORITES,
+ MENU_USER
+};
+
+typedef struct menu_names_s {
+ const char *name;
+ int menutype;
+ const char *dest;
+} menu_names_t;
+
+static menu_names_t menu_table[] = {
+ { "root", MENU_REDIRECT, "root-tuner" },
+ { "picture", MENU_REDIRECT, "picture-tuner" },
+ { "input", MENU_REDIRECT, "input-ntsc" },
+ { "favorites", MENU_FAVORITES, 0 },
+};
+
+static int tvtime_num_builtin_menus( void )
+{
+ return ( sizeof( menu_table ) / sizeof( menu_names_t ) );
+}
+
+static void set_redirect( const char *menu, const char *dest )
+{
+ int i;
+
+ for( i = 0; i < tvtime_num_builtin_menus(); i++ ) {
+ if( !strcasecmp( menu, menu_table[ i ].name ) ) {
+ menu_table[ i ].dest = dest;
+ return;
+ }
+ }
+}
+
+
+static int sleeptimer_function( int step )
+{
+ if( step < 3 ) {
+ return step * 10;
+ } else {
+ return (step - 2) * 30;
+ }
+}
+
+struct commands_s {
+ config_t *cfg;
+ videoinput_t *vidin;
+ tvtime_osd_t *osd;
+ station_mgr_t *stationmgr;
+ char next_chan_buffer[ 5 ];
+ int frame_counter;
+ int digit_counter;
+ int quit;
+ int sleeptimer;
+ time_t sleeptimer_start;
+
+ xmltv_t *xmltv;
+
+ int picturemode;
+ int brightness;
+ int contrast;
+ int saturation;
+ int hue;
+
+ int boost;
+
+ int displayinfo;
+ int screenshot;
+ char screenshotfile[ 2048 ];
+ int printdebug;
+ int showbars;
+ int showdeinterlacerinfo;
+ int togglefullscreen;
+ int toggleaspect;
+ int togglealwaysontop;
+ int toggledeinterlacer;
+ int togglepulldowndetection;
+ int togglematte;
+ int togglequiet;
+ int framerate;
+ int scan_channels;
+ int pause;
+ int halfsize;
+ int resizewindow;
+ int restarttvtime;
+ int setdeinterlacer;
+ int normset;
+ const char *newnorm;
+ int newinputwidth;
+ char deinterlacer[ 128 ];
+ int setfreqtable;
+ char newfreqtable[ 128 ];
+ int checkfreq;
+ int usexds;
+ int pulldown_alg;
+ char newmatte[ 16 ];
+ char newpos[ 16 ];
+
+ int delay;
+
+ int change_channel;
+ int renumbering;
+ int xmltvupdated;
+ int tunerreset;
+
+ int apply_invert;
+ int apply_mirror;
+ int apply_chroma_kill;
+
+ double overscan;
+
+ vbidata_t *vbi;
+ int capturemode;
+
+ int curfavorite;
+ int numfavorites;
+ int favorites[ NUM_FAVORITES ];
+
+ int menuactive;
+ int curmenu;
+ int curmenupos;
+ int curmenusize;
+ menu_t *curusermenu;
+ menu_t *menus[ MAX_USER_MENUS ];
+};
+
+static void menu_set_value( menu_t *menu, int newval, const char *icon )
+{
+ char string[ 128 ];
+ snprintf( string, sizeof( string ), "%s %s: %d",
+ icon, _("Current"), newval );
+ menu_set_text( menu, 1, string );
+}
+
+static void update_xmltv_channel( commands_t *cmd )
+{
+ if( cmd->xmltv && cmd->osd ) {
+ if( station_get_current_xmltv_id( cmd->stationmgr ) ) {
+ xmltv_set_channel( cmd->xmltv, station_get_current_xmltv_id( cmd->stationmgr ) );
+ } else {
+ xmltv_set_channel( cmd->xmltv, xmltv_lookup_channel( cmd->xmltv,
+ station_get_current_channel_name( cmd->stationmgr ) ) );
+ }
+ } else if( cmd->osd ) {
+ tvtime_osd_show_program_info( cmd->osd, 0, 0, 0 );
+ tvtime_osd_set_info_available( cmd->osd, 0 );
+ }
+}
+
+static void display_xmltv_description( commands_t *cmd, const char *title,
+ const char *subtitle,
+ const char *description,
+ const char *next_title )
+{
+ int cur = 0;
+
+ if( title ) {
+ /* Using set_multitext for one line only gives you the truncating. */
+ cur = tvtime_osd_list_set_multitext( cmd->osd, cur, title, 1 );
+ } else {
+ tvtime_osd_list_set_text( cmd->osd, cur++,
+ /* TRANSLATORS: This refers to a TV program, not a computer program. */
+ _("No program information available") );
+ }
+
+ if( subtitle && *subtitle ) {
+ cur = tvtime_osd_list_set_multitext( cmd->osd, cur, subtitle, 1 );
+ } else {
+ tvtime_osd_list_set_text( cmd->osd, cur++,
+ _("No program information available") );
+ }
+
+ if( description && *description ) {
+ tvtime_osd_list_set_text( cmd->osd, cur++, "" );
+ cur = tvtime_osd_list_set_multitext( cmd->osd, cur, description, 6 );
+ }
+
+ if( next_title && *next_title ) {
+ tvtime_osd_list_set_text( cmd->osd, cur++, "" );
+ cur = tvtime_osd_list_set_multitext( cmd->osd, cur, next_title, 1 );
+ }
+ tvtime_osd_list_set_lines( cmd->osd, cur );
+ tvtime_osd_list_set_hilight( cmd->osd, -1 );
+ tvtime_osd_show_list( cmd->osd, 1, 1 );
+}
+
+static void update_xmltv_display( commands_t *cmd )
+{
+ if( cmd->xmltv && cmd->osd ) {
+ const char *desc;
+ const char *title;
+ time_t timestamp;
+ char start_time[ 50 ];
+ char end_time[ 50 ];
+ char next_title[ 1024 ];
+ char subtitle[ 1024 ];
+
+ timestamp = xmltv_get_start_time( cmd->xmltv );
+ if( timestamp == 0 ) {
+ /* No information available */
+ start_time[0] = '\0';
+ end_time[0] = '\0';
+ subtitle[0] = '\0';
+ title = 0;
+ desc = 0;
+ } else {
+ strftime( start_time, 50, "%H:%M", localtime( ×tamp ) );
+ timestamp = xmltv_get_end_time( cmd->xmltv );
+ strftime( end_time, 50, "%H:%M", localtime( ×tamp ) );
+
+ if( xmltv_get_sub_title( cmd->xmltv ) ) {
+ snprintf( subtitle, sizeof( subtitle ), "%s - %s - %s",
+ start_time, end_time,
+ xmltv_get_sub_title( cmd->xmltv ) );
+ } else {
+ snprintf( subtitle, sizeof( subtitle ), "%s - %s",
+ start_time, end_time );
+ }
+
+ title = xmltv_get_title( cmd->xmltv );
+ desc = xmltv_get_description( cmd->xmltv );
+ }
+
+ if( xmltv_get_next_title( cmd->xmltv ) ) {
+ snprintf( next_title, sizeof( next_title ),
+ _("Next: %s"), xmltv_get_next_title( cmd->xmltv ) );
+ } else {
+ *next_title = '\0';
+ }
+
+ if( !cmd->displayinfo || cmd->menuactive ) {
+ tvtime_osd_show_program_info( cmd->osd, title, subtitle, next_title );
+ tvtime_osd_set_info_available( cmd->osd, desc && *desc );
+ } else {
+ tvtime_osd_show_program_info( cmd->osd, 0, 0, 0 );
+ display_xmltv_description( cmd, title, subtitle, desc, next_title );
+ tvtime_osd_set_info_available( cmd->osd, 0 );
+ }
+ }
+}
+
+static void update_xmltv_listings( commands_t *cmd )
+{
+ if( cmd->xmltv && cmd->osd && cmd->vidin &&
+ videoinput_has_tuner( cmd->vidin ) &&
+ xmltv_needs_refresh( cmd->xmltv ) ) {
+
+ xmltv_refresh( cmd->xmltv );
+ update_xmltv_display( cmd );
+ cmd->xmltvupdated = 1;
+ }
+}
+
+static void reset_stations_menu( menu_t *menu, int ntsc, int pal, int secam,
+ int ntsccable, int active, int signaldetect,
+ int scanning, int v4l2, int default_paldk,
+ int paldk )
+{
+ char string[ 128 ];
+ int cur;
+
+ /* Start over. */
+ menu_reset_num_lines( menu );
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "root" );
+ cur = 1;
+
+ if( !ntsc ) {
+ snprintf( string, sizeof( string ), TVTIME_ICON_RENUMBERCHANNEL " %s",
+ _("Renumber current channel") );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_CHANNEL_RENUMBER, "" );
+ cur++;
+ }
+
+ if( active ) {
+ snprintf( string, sizeof( string ), TVTIME_ICON_GENERALTOGGLEON " %s",
+ _("Current channel active in list") );
+ } else {
+ snprintf( string, sizeof( string ), TVTIME_ICON_GENERALTOGGLEOFF " %s",
+ _("Current channel active in list") );
+ }
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_CHANNEL_SKIP, "" );
+ cur++;
+
+ if( signaldetect ) {
+ if( scanning ) {
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_SCANFORSTATIONS " %s",
+ _("Stop channel scan") );
+ } else {
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_SCANFORSTATIONS " %s",
+ _("Scan channels for signal") );
+ }
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_CHANNEL_SCAN, "" );
+ cur++;
+ }
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_ALLCHANNELSACTIVE " %s",
+ _("Reset all channels as active") );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_CHANNEL_ACTIVATE_ALL, "" );
+ cur++;
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_FINETUNECHANNEL " %s",
+ _("Finetune current channel") );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_SHOW_MENU, "finetune" );
+ cur++;
+
+ if( ntsccable ) {
+ snprintf( string, sizeof( string ), TVTIME_ICON_CHANGENTSCMODE " %s",
+ _("Change NTSC cable mode") );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_TOGGLE_NTSC_CABLE_MODE, "" );
+ cur++;
+ } else if( pal || secam ) {
+ snprintf( string, sizeof( string ), TVTIME_ICON_TVLOGO " %s", pal?
+ _("Set current channel as SECAM"):
+ _("Set current channel as PAL") );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_TOGGLE_PAL_SECAM, "" );
+ cur++;
+ }
+
+ if( pal && v4l2 ) {
+ const char *amode = "PAL-BG";
+ if( paldk == VIDEOINPUT_PAL_I_AUDIO ) {
+ amode = "PAL-I";
+ } else if( paldk == VIDEOINPUT_PAL_DK_AUDIO ) {
+ amode = "PAL-DK";
+ }
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_VIDEOINPUT " %s (%s)",
+ _("Switch audio standard"), amode );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_TOGGLE_CHANNEL_PAL_DK, "" );
+ cur++;
+ }
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_FREQUENCYTABLESEL " %s",
+ _("Change frequency table") );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_SHOW_MENU, "frequencies" );
+ cur++;
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_STATIONMANAGEMENT " %s",
+ signaldetect? _("Disable signal detection"):
+ _("Enable signal detection") );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_TOGGLE_SIGNAL_DETECTION, "" );
+ cur++;
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_SHOW_MENU, "root" );
+}
+
+static void reset_xmltv_languages_menu( menu_t *menu, xmltv_t *xmltv )
+{
+ int num = xmltv_get_num_languages( xmltv );
+ const char *cur = xmltv_get_language( xmltv );
+ char string[ 128 ];
+ int i;
+
+ if( !xmltv ) return;
+
+ menu_reset_num_lines( menu );
+ menu_set_back_command( menu, TVTIME_MENU_EXIT, 0 );
+ snprintf( string, sizeof( string ), "%s %s",
+ cur? TVTIME_ICON_RADIOOFF : TVTIME_ICON_RADIOON,
+ _("Default language") );
+ menu_set_text( menu, 1, string );
+ menu_set_enter_command( menu, 1, TVTIME_SET_XMLTV_LANGUAGE, "none" );
+
+ for( i = 1; i <= num; i++ ) {
+ const char *code = xmltv_get_language_code( xmltv, i );
+ const char *name = xmltv_get_language_name( xmltv, i );
+ const char *radio;
+
+ if( cur && code && !strncasecmp( cur, code, 2 ) ) {
+ radio = TVTIME_ICON_RADIOON;
+ } else {
+ radio = TVTIME_ICON_RADIOOFF;
+ }
+
+ snprintf( string, sizeof( string ), "%s %s (%s)",
+ radio, name? name : _("Unknown language"), code );
+ menu_set_text( menu, i + 1, string );
+ menu_set_enter_command( menu, i + 1,
+ TVTIME_SET_XMLTV_LANGUAGE, code );
+ }
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, num + 2, string );
+ menu_set_enter_command( menu, num + 2, TVTIME_MENU_EXIT, 0 );
+}
+
+static void reinit_tuner( commands_t *cmd )
+{
+ /* Setup the tuner if available. */
+ if( cmd->vbi ) {
+ vbidata_reset( cmd->vbi );
+ vbidata_capture_mode( cmd->vbi, cmd->capturemode );
+ }
+
+ set_redirect( "root", "root-notuner" );
+ set_redirect( "picture", "picture-notuner" );
+
+ if( cmd->vidin && videoinput_has_tuner( cmd->vidin ) ) {
+ int norm;
+
+ set_redirect( "root", "root-tuner" );
+ set_redirect( "picture", "picture-tuner" );
+
+ cmd->tunerreset = 1;
+
+ videoinput_set_tuner_freq( cmd->vidin, station_get_current_frequency( cmd->stationmgr )
+ + ((station_get_current_finetune( cmd->stationmgr ) * 1000)/16) );
+ menu_set_value( commands_get_menu( cmd, "finetune" ), station_get_current_finetune( cmd->stationmgr ), TVTIME_ICON_FINETUNECHANNEL );
+ commands_refresh_menu( cmd );
+
+ norm = videoinput_get_norm_number( station_get_current_norm( cmd->stationmgr ) );
+ if( norm >= 0 ) {
+ videoinput_switch_pal_secam( cmd->vidin, norm );
+ }
+ videoinput_set_pal_audio_mode( cmd->vidin,
+ station_get_current_audio_norm( cmd->stationmgr ) );
+
+ if( config_get_save_restore_picture( cmd->cfg ) ) {
+ int brightness = station_get_current_brightness( cmd->stationmgr );
+ int contrast = station_get_current_contrast( cmd->stationmgr );
+ int saturation = station_get_current_saturation( cmd->stationmgr );
+ int hue = station_get_current_hue( cmd->stationmgr );
+
+ if( brightness >= 0 ) {
+ videoinput_set_brightness( cmd->vidin, brightness );
+ } else {
+ videoinput_set_brightness( cmd->vidin, cmd->brightness );
+ }
+ if( contrast >= 0 ) {
+ videoinput_set_contrast( cmd->vidin, contrast );
+ } else {
+ videoinput_set_contrast( cmd->vidin, cmd->contrast );
+ }
+ if( saturation >= 0 ) {
+ videoinput_set_saturation( cmd->vidin, saturation );
+ } else {
+ videoinput_set_saturation( cmd->vidin, cmd->saturation );
+ }
+ if( hue >= 0 ) {
+ videoinput_set_hue( cmd->vidin, hue );
+ } else {
+ videoinput_set_hue( cmd->vidin, cmd->hue );
+ }
+ }
+
+ if( cmd->osd ) {
+ char channel_display[ 20 ];
+ const char *xmltv_name = 0;
+
+ snprintf( channel_display, sizeof( channel_display ), "%d",
+ station_get_current_id( cmd->stationmgr ) );
+ update_xmltv_channel( cmd );
+ if ( cmd->xmltv && !strcmp( station_get_current_channel_name( cmd->stationmgr ), channel_display ) ) {
+ xmltv_name = xmltv_lookup_channel_name( cmd->xmltv, xmltv_get_channel( cmd->xmltv ) );
+ if ( xmltv_name ) {
+ tvtime_osd_set_channel_name( cmd->osd, xmltv_name );
+ }
+ }
+ if ( !xmltv_name ) {
+ tvtime_osd_set_channel_name( cmd->osd, station_get_current_channel_name( cmd->stationmgr ) );
+ }
+ tvtime_osd_set_norm( cmd->osd, videoinput_get_norm_name( videoinput_get_norm( cmd->vidin ) ) );
+ tvtime_osd_set_audio_mode( cmd->osd, videoinput_get_audio_mode_name( cmd->vidin, videoinput_get_audio_mode( cmd->vidin ) ) );
+ tvtime_osd_set_freq_table( cmd->osd, station_get_current_band( cmd->stationmgr ) );
+ tvtime_osd_set_channel_number( cmd->osd, channel_display );
+ tvtime_osd_set_network_call( cmd->osd, station_get_current_network_call_letters( cmd->stationmgr ) );
+ tvtime_osd_set_network_name( cmd->osd, station_get_current_network_name( cmd->stationmgr ) );
+ tvtime_osd_set_show_name( cmd->osd, "" );
+ tvtime_osd_set_show_rating( cmd->osd, "" );
+ tvtime_osd_set_show_start( cmd->osd, "" );
+ tvtime_osd_set_show_length( cmd->osd, "" );
+ tvtime_osd_show_info( cmd->osd );
+
+ reset_stations_menu( commands_get_menu( cmd, "stations" ),
+ (videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_NTSC ||
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_NTSC_JP),
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_PAL,
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_SECAM,
+ (!strcasecmp( cmd->newfreqtable, "us-cable" ) ||
+ !strcasecmp( cmd->newfreqtable, "us-cable100" )),
+ station_get_current_active( cmd->stationmgr ), cmd->checkfreq,
+ cmd->scan_channels,
+ videoinput_is_v4l2( cmd->vidin ),
+ station_get_default_audio_norm( cmd->stationmgr ),
+ station_get_current_audio_norm( cmd->stationmgr ) );
+ commands_refresh_menu( cmd );
+ }
+ cmd->frame_counter = 0;
+ } else if( cmd->osd ) {
+ tvtime_osd_set_audio_mode( cmd->osd, "" );
+ tvtime_osd_set_freq_table( cmd->osd, "" );
+ tvtime_osd_set_channel_number( cmd->osd, "" );
+ tvtime_osd_set_channel_name( cmd->osd, "" );
+ tvtime_osd_set_network_call( cmd->osd, "" );
+ tvtime_osd_set_network_name( cmd->osd, "" );
+ tvtime_osd_set_show_name( cmd->osd, "" );
+ tvtime_osd_set_show_rating( cmd->osd, "" );
+ tvtime_osd_set_show_start( cmd->osd, "" );
+ tvtime_osd_set_show_length( cmd->osd, "" );
+ tvtime_osd_show_program_info( cmd->osd, 0, 0, 0 );
+ tvtime_osd_set_info_available( cmd->osd, 0 );
+ tvtime_osd_show_info( cmd->osd );
+ tvtime_osd_clear( cmd->osd );
+ }
+
+ if( config_get_save_restore_picture( cmd->cfg ) && cmd->vidin && !videoinput_has_tuner( cmd->vidin ) ) {
+ if( cmd->brightness >= 0 ) {
+ videoinput_set_brightness( cmd->vidin, cmd->brightness );
+ }
+ if( cmd->contrast >= 0 ) {
+ videoinput_set_contrast( cmd->vidin, cmd->contrast );
+ }
+ if( cmd->saturation >= 0 ) {
+ videoinput_set_saturation( cmd->vidin, cmd->saturation );
+ }
+ if( cmd->hue >= 0 ) {
+ videoinput_set_hue( cmd->vidin, cmd->hue );
+ }
+ }
+
+ if( cmd->vidin ) {
+ menu_set_value (commands_get_menu (cmd, "brightness"),
+ videoinput_get_brightness (cmd->vidin),
+ TVTIME_ICON_BRIGHTNESS);
+ menu_set_value (commands_get_menu (cmd, "contrast"),
+ videoinput_get_contrast (cmd->vidin),
+ TVTIME_ICON_CONTRAST);
+ menu_set_value (commands_get_menu (cmd, "saturation"),
+ videoinput_get_saturation (cmd->vidin),
+ TVTIME_ICON_SATURATION);
+ menu_set_value (commands_get_menu (cmd, "hue"),
+ videoinput_get_hue (cmd->vidin),
+ TVTIME_ICON_HUE);
+ }
+}
+
+static void reset_pal_input_menu( menu_t *menu, videoinput_t *vidin, station_mgr_t *stationmgr )
+{
+ char string[ 128 ];
+ int cur = 2;
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_STATIONMANAGEMENT " %s",
+ _("Preferred audio mode") );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_SHOW_MENU, "audiomode" );
+ cur++;
+
+ if( videoinput_is_v4l2( vidin ) ) {
+ const char *curnorm = "PAL-BG";
+ int defnorm = station_get_default_audio_norm( stationmgr );
+ if( defnorm == VIDEOINPUT_PAL_I_AUDIO ) {
+ curnorm = "PAL-I";
+ } else if( defnorm == VIDEOINPUT_PAL_DK_AUDIO ) {
+ curnorm = "PAL-DK";
+ }
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_TVPGICON " %s (%s)",
+ _("Change default audio standard"), curnorm );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_TOGGLE_PAL_DK_AUDIO, "" );
+ cur++;
+ }
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_STATIONMANAGEMENT " %s",
+ _("Audio volume boost") );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_SHOW_MENU, "audioboost" );
+ cur++;
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_TELEVISIONSTANDARD " %s",
+ _("Television standard") );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_SHOW_MENU, "norm" );
+ cur++;
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_INPUTWIDTH " %s",
+ _("Horizontal resolution") );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_SHOW_MENU, "hres" );
+ cur++;
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_SHOW_MENU, "root" );
+ cur++;
+}
+
+static void reset_frequency_menu( menu_t *menu, int norm, const char *tablename )
+{
+ char string[ 128 ];
+
+ if( norm == VIDEOINPUT_NTSC || norm == VIDEOINPUT_PAL_M || norm == VIDEOINPUT_PAL_NC ) {
+ snprintf( string, sizeof( string ),
+ !strcasecmp( tablename, "us-cable" ) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Cable") );
+ menu_set_text( menu, 1, string );
+ menu_set_enter_command( menu, 1, TVTIME_SET_FREQUENCY_TABLE, "us-cable" );
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "stations" );
+
+ snprintf( string, sizeof( string ),
+ !strcasecmp( tablename, "us-broadcast" ) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Broadcast") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_SET_FREQUENCY_TABLE, "us-broadcast" );
+
+ snprintf( string, sizeof( string ),
+ !strcasecmp( tablename, "us-cable100" ) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Cable with channels 100+") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_SET_FREQUENCY_TABLE, "us-cable100" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, 4, string );
+ menu_set_enter_command( menu, 4, TVTIME_SHOW_MENU, "stations" );
+ } else if( norm == VIDEOINPUT_NTSC_JP ) {
+ snprintf( string, sizeof( string ),
+ !strcasecmp( tablename, "japan-cable" ) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Cable") );
+ menu_set_text( menu, 1, string );
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "stations" );
+ menu_set_enter_command( menu, 1, TVTIME_SET_FREQUENCY_TABLE, "japan-cable" );
+
+ snprintf( string, sizeof( string ),
+ !strcasecmp( tablename, "japan-broadcast" ) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Broadcast") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_SET_FREQUENCY_TABLE, "japan-broadcast" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_SHOW_MENU, "input" );
+ } else {
+ snprintf( string, sizeof( string ),
+ !strcasecmp( tablename, "europe" ) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Europe") );
+ menu_set_text( menu, 1, string );
+ menu_set_enter_command( menu, 1, TVTIME_SET_FREQUENCY_TABLE, "europe" );
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "stations" );
+
+ snprintf( string, sizeof( string ),
+ !strcasecmp( tablename, "russia" ) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Russia") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_SET_FREQUENCY_TABLE, "russia" );
+
+ snprintf( string, sizeof( string ),
+ !strcasecmp( tablename, "france" ) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("France") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_SET_FREQUENCY_TABLE, "france" );
+
+ snprintf( string, sizeof( string ),
+ !strcasecmp( tablename, "australia" ) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Australia") );
+ menu_set_text( menu, 4, string );
+ menu_set_enter_command( menu, 4, TVTIME_SET_FREQUENCY_TABLE, "australia" );
+
+ snprintf( string, sizeof( string ),
+ !strcasecmp( tablename, "australia-optus" ) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Australia (Optus)") );
+ menu_set_text( menu, 5, string );
+ menu_set_enter_command( menu, 5, TVTIME_SET_FREQUENCY_TABLE, "australia-optus" );
+
+ snprintf( string, sizeof( string ),
+ !strcasecmp( tablename, "newzealand" ) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("New Zealand") );
+ menu_set_text( menu, 6, string );
+ menu_set_enter_command( menu, 6, TVTIME_SET_FREQUENCY_TABLE, "newzealand" );
+
+ snprintf( string, sizeof( string ),
+ !strcasecmp( tablename, "china-broadcast" ) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("China Broadcast") );
+ menu_set_text( menu, 7, string );
+ menu_set_enter_command( menu, 7, TVTIME_SET_FREQUENCY_TABLE, "china-broadcast" );
+
+ snprintf( string, sizeof( string ),
+ !strcasecmp( tablename, "southafrica" ) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("South Africa") );
+ menu_set_text( menu, 8, string );
+ menu_set_enter_command( menu, 8, TVTIME_SET_FREQUENCY_TABLE, "southafrica" );
+
+ snprintf( string, sizeof( string ),
+ !strcasecmp( tablename, "custom" ) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Custom (first run tvtime-scanner)") );
+ menu_set_text( menu, 9, string );
+ menu_set_enter_command( menu, 9, TVTIME_SET_FREQUENCY_TABLE, "custom" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, 10, string );
+ menu_set_enter_command( menu, 10, TVTIME_SHOW_MENU, "stations" );
+ }
+}
+
+static void reset_audio_boost_menu( menu_t *menu, int curvol )
+{
+ char string[ 128 ];
+
+ snprintf( string, sizeof( string ), (curvol == -1) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Disabled") );
+ menu_set_text( menu, 1, string );
+ menu_set_enter_command( menu, 1, TVTIME_SET_AUDIO_BOOST, "-1" );
+
+ snprintf( string, sizeof( string ), (curvol == 50) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Quiet") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_SET_AUDIO_BOOST, "50" );
+
+ snprintf( string, sizeof( string ), (curvol == 90) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Medium") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_SET_AUDIO_BOOST, "90" );
+
+ snprintf( string, sizeof( string ), (curvol == 100) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Full") );
+ menu_set_text( menu, 4, string );
+ menu_set_enter_command( menu, 4, TVTIME_SET_AUDIO_BOOST, "100" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, 5, string );
+ menu_set_enter_command( menu, 5, TVTIME_SHOW_MENU, "input" );
+}
+
+static void reset_inputwidth_menu( menu_t *menu, int inputwidth, int maxwidth )
+{
+ char string[ 128 ];
+ int entry_num;
+
+ snprintf( string, sizeof( string ),
+ _("%s Current: %d pixels"), TVTIME_ICON_INPUTWIDTH, inputwidth );
+ menu_set_text( menu, 1, string );
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "input" );
+ menu_set_enter_command( menu, 1, TVTIME_SHOW_MENU, "input" );
+
+ snprintf( string, sizeof( string ), (inputwidth == 360) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Low (360 pixels)") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_SET_INPUT_WIDTH, "360" );
+
+ snprintf( string, sizeof( string ), (inputwidth == 576) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Moderate (576 pixels)") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_SET_INPUT_WIDTH, "576" );
+
+ snprintf( string, sizeof( string ), (inputwidth == 720) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Standard (720 pixels)") );
+ menu_set_text( menu, 4, string );
+ menu_set_enter_command( menu, 4, TVTIME_SET_INPUT_WIDTH, "720" );
+
+ snprintf( string, sizeof( string ), (inputwidth == 768) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("High (768 pixels)") );
+ menu_set_text( menu, 5, string );
+ menu_set_enter_command( menu, 5, TVTIME_SET_INPUT_WIDTH, "768" );
+
+ entry_num = 6;
+ if( maxwidth > 768 ) {
+ snprintf( string, sizeof( string ), _("%s Maximum (%d pixels)"),
+ (inputwidth == maxwidth) ?
+ TVTIME_ICON_RADIOON : TVTIME_ICON_RADIOOFF, maxwidth );
+ menu_set_text( menu, entry_num, string );
+ snprintf( string, sizeof( string ), "%d", maxwidth );
+ menu_set_enter_command( menu, entry_num,
+ TVTIME_SET_INPUT_WIDTH, string );
+ entry_num++;
+ }
+ snprintf( string, sizeof( string ), TVTIME_ICON_RESTART " %s",
+ _("Restart with new settings") );
+ menu_set_text( menu, entry_num, string );
+ menu_set_enter_command( menu, entry_num, TVTIME_RESTART, "" );
+ entry_num++;
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, entry_num, string );
+ menu_set_enter_command( menu, entry_num, TVTIME_SHOW_MENU, "input" );
+}
+
+static void reset_norm_menu( menu_t *menu, const char *norm )
+{
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "input" );
+
+ menu_set_text (menu, 1, strcasecmp (norm, "ntsc") == 0 ?
+ TVTIME_ICON_RADIOON " NTSC" :
+ TVTIME_ICON_RADIOOFF " NTSC");
+ menu_set_enter_command( menu, 1, TVTIME_SET_NORM, "ntsc" );
+
+ menu_set_text (menu, 2, strcasecmp (norm, "pal") == 0 ?
+ TVTIME_ICON_RADIOON " PAL" :
+ TVTIME_ICON_RADIOOFF " PAL");
+ menu_set_enter_command( menu, 2, TVTIME_SET_NORM, "pal" );
+
+ menu_set_text (menu, 3, strcasecmp (norm, "secam") == 0 ?
+ TVTIME_ICON_RADIOON " SECAM" :
+ TVTIME_ICON_RADIOOFF " SECAM");
+ menu_set_enter_command( menu, 3, TVTIME_SET_NORM, "secam" );
+
+ menu_set_text (menu, 4, strcasecmp (norm, "pal-nc") == 0 ?
+ TVTIME_ICON_RADIOON " PAL-NC" :
+ TVTIME_ICON_RADIOOFF " PAL-NC");
+ menu_set_enter_command( menu, 4, TVTIME_SET_NORM, "pal-nc" );
+
+ menu_set_text (menu, 5, strcasecmp (norm, "pal-m") == 0 ?
+ TVTIME_ICON_RADIOON " PAL-M" :
+ TVTIME_ICON_RADIOOFF " PAL-M");
+ menu_set_enter_command( menu, 5, TVTIME_SET_NORM, "pal-m" );
+
+ menu_set_text (menu, 6, strcasecmp (norm, "pal-n") == 0 ?
+ TVTIME_ICON_RADIOON " PAL-N" :
+ TVTIME_ICON_RADIOOFF " PAL-N");
+ menu_set_enter_command( menu, 6, TVTIME_SET_NORM, "pal-n" );
+
+ menu_set_text (menu, 7, strcasecmp (norm, "ntsc-jp") == 0 ?
+ TVTIME_ICON_RADIOON " NTSC-JP" :
+ TVTIME_ICON_RADIOOFF " NTSC-JP");
+ menu_set_enter_command( menu, 7, TVTIME_SET_NORM, "ntsc-jp" );
+
+ menu_set_text (menu, 8, strcasecmp (norm, "pal-60") == 0 ?
+ TVTIME_ICON_RADIOON " PAL-60" :
+ TVTIME_ICON_RADIOOFF " PAL-60");
+ menu_set_enter_command( menu, 8, TVTIME_SET_NORM, "pal-60" );
+}
+
+static void reset_audio_mode_menu( menu_t *menu, int ntsc, int curmode )
+{
+ char string[ 128 ];
+
+ snprintf( string, sizeof( string ), curmode == VIDEOINPUT_MONO ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Mono") );
+ menu_set_text( menu, 1, string );
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "input" );
+ menu_set_enter_command( menu, 1, TVTIME_SET_AUDIO_MODE, "mono" );
+
+ snprintf( string, sizeof( string ), curmode == VIDEOINPUT_STEREO ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Stereo") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_SET_AUDIO_MODE, "stereo" );
+
+ if( ntsc ) {
+ snprintf( string, sizeof( string ), (curmode == VIDEOINPUT_LANG1 ||
+ curmode == VIDEOINPUT_LANG2) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("SAP") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_SET_AUDIO_MODE, "sap" );
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+
+ menu_set_text( menu, 4, string );
+ menu_set_enter_command( menu, 4, TVTIME_SHOW_MENU, "input" );
+ } else {
+ snprintf( string, sizeof( string ), (curmode == VIDEOINPUT_LANG1) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Primary Language") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_SET_AUDIO_MODE, "lang1" );
+ snprintf( string, sizeof( string ), (curmode == VIDEOINPUT_LANG2) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("Secondary Language") );
+ menu_set_text( menu, 4, string );
+ menu_set_enter_command( menu, 4, TVTIME_SET_AUDIO_MODE, "lang2" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, 5, string );
+ menu_set_enter_command( menu, 5, TVTIME_SHOW_MENU, "input" );
+ }
+}
+
+static void reset_overscan_menu( menu_t *menu, double overscan )
+{
+ char string[ 128 ];
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_TVLOGO " %s: %.1f%%",
+ _("Current"), overscan * 2.0 * 100.0 );
+ menu_set_text( menu, 1, string );
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "output" );
+ menu_set_enter_command( menu, 1, TVTIME_SHOW_MENU, "output" );
+
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_PLUSBUTTON " %s", _("Increase") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_OVERSCAN_UP, "" );
+
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_MINUSBUTTON " %s", _("Decrease") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_OVERSCAN_DOWN, "" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, 4, string );
+ menu_set_enter_command( menu, 4, TVTIME_SHOW_MENU, "output" );
+}
+
+static void reset_filters_menu( menu_t *menu, int apply_invert,
+ int apply_mirror, int apply_chroma_kill,
+ int isntsc, int apply_pulldown )
+{
+ char string[ 128 ];
+ int cur = 1;
+
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "processing" );
+
+ if( isntsc ) {
+ snprintf( string, sizeof( string ), apply_pulldown ?
+ TVTIME_ICON_GENERALTOGGLEON " %s" :
+ TVTIME_ICON_GENERALTOGGLEOFF " %s",
+ _("2-3 pulldown inversion") );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_TOGGLE_PULLDOWN_DETECTION, "" );
+ cur++;
+ }
+
+ snprintf( string, sizeof( string ), apply_invert ?
+ TVTIME_ICON_GENERALTOGGLEON " %s" :
+ TVTIME_ICON_GENERALTOGGLEOFF " %s",
+ _("Colour invert") );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_TOGGLE_COLOUR_INVERT, "" );
+ cur++;
+
+ snprintf( string, sizeof( string ), apply_mirror ?
+ TVTIME_ICON_GENERALTOGGLEON " %s" :
+ TVTIME_ICON_GENERALTOGGLEOFF " %s",
+ _("Mirror") );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_TOGGLE_MIRROR, "" );
+ cur++;
+
+ snprintf( string, sizeof( string ), apply_chroma_kill ?
+ TVTIME_ICON_GENERALTOGGLEON " %s" :
+ TVTIME_ICON_GENERALTOGGLEOFF " %s",
+ _("Chroma killer") );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_TOGGLE_CHROMA_KILL, "" );
+ cur++;
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, cur, string );
+ menu_set_enter_command( menu, cur, TVTIME_SHOW_MENU, "processing" );
+}
+
+commands_t *commands_new( config_t *cfg, videoinput_t *vidin,
+ station_mgr_t *mgr, tvtime_osd_t *osd,
+ int fieldtime )
+{
+ commands_t *cmd = malloc( sizeof( struct commands_s ) );
+ char string[ 128 ];
+ menu_t *menu;
+ int maxwidth;
+ int curpos = 0;
+
+ if( !cmd ) {
+ return 0;
+ }
+
+ cmd->cfg = cfg;
+ cmd->vidin = vidin;
+ cmd->osd = osd;
+ cmd->stationmgr = mgr;
+ memset( cmd->next_chan_buffer, 0, sizeof( cmd->next_chan_buffer ) );
+ cmd->frame_counter = 0;
+ cmd->digit_counter = 0;
+ cmd->quit = 0;
+ cmd->sleeptimer = 0;
+ cmd->sleeptimer_start = 0;
+
+ if( config_get_xmltv_file( cfg ) && strcasecmp( config_get_xmltv_file( cfg ), "none" ) ) {
+ if( config_get_xmltv_language( cfg ) && strcasecmp( config_get_xmltv_language( cfg ), "none" ) ) {
+ cmd->xmltv = xmltv_new( config_get_xmltv_file( cfg ),
+ config_get_xmltv_language( cfg ) );
+ } else {
+ cmd->xmltv = xmltv_new( config_get_xmltv_file( cfg ), 0 );
+ }
+ } else {
+ cmd->xmltv = 0;
+ }
+
+ cmd->picturemode = 3;
+ cmd->brightness = config_get_global_brightness( cfg );
+ cmd->contrast = config_get_global_contrast( cfg );
+ cmd->saturation = config_get_global_saturation( cfg );
+ cmd->hue = config_get_global_hue( cfg );
+
+ cmd->displayinfo = 0;
+ cmd->screenshot = 0;
+ memset( cmd->screenshotfile, 0, sizeof( cmd->screenshotfile ) );
+ cmd->printdebug = 0;
+ cmd->showbars = 0;
+ cmd->showdeinterlacerinfo = 0;
+ cmd->togglefullscreen = 0;
+ cmd->toggleaspect = 0;
+ cmd->togglealwaysontop = 0;
+ cmd->toggledeinterlacer = 0;
+ cmd->togglepulldowndetection = 0;
+ cmd->togglematte = 0;
+ cmd->togglequiet = 0;
+ cmd->framerate = FRAMERATE_FULL;
+ cmd->scan_channels = 0;
+ cmd->pause = 0;
+ cmd->halfsize = 0;
+ cmd->resizewindow = 0;
+ cmd->restarttvtime = 0;
+ cmd->setdeinterlacer = 0;
+ cmd->normset = 0;
+ cmd->newnorm = 0;
+ cmd->newinputwidth = 0;
+ memset( cmd->deinterlacer, 0, sizeof( cmd->deinterlacer ) );
+ cmd->setfreqtable = 0;
+ snprintf( cmd->newfreqtable, sizeof( cmd->newfreqtable ), "%s", config_get_v4l_freq( cfg ) );
+ cmd->checkfreq = config_get_check_freq_present( cfg );
+ cmd->usexds = config_get_usexds( cfg );
+ cmd->pulldown_alg = 0;
+ memset( cmd->newmatte, 0, sizeof( cmd->newmatte ) );
+ memset( cmd->newpos, 0, sizeof( cmd->newpos ) );
+
+ /* Number of frames to wait for next channel digit. */
+ cmd->delay = 1000000 / fieldtime;
+
+ cmd->change_channel = 0;
+ cmd->renumbering = 0;
+ cmd->xmltvupdated = 0;
+ cmd->tunerreset = 0;
+
+ cmd->apply_invert = config_get_invert( cfg );
+ cmd->apply_mirror = config_get_mirror( cfg );
+ cmd->apply_chroma_kill = 0;
+
+ cmd->boost = config_get_audio_boost( cfg );
+
+ cmd->overscan = config_get_overscan( cfg );
+ if( cmd->overscan > 0.4 ) cmd->overscan = 0.4; if( cmd->overscan < 0.0 ) cmd->overscan = 0.0;
+
+ cmd->vbi = 0;
+ cmd->capturemode = config_get_cc( cfg ) ? CAPTURE_CC1 : CAPTURE_OFF;
+
+ cmd->curfavorite = 0;
+ cmd->numfavorites = 0;
+ memset( cmd->favorites, 0, sizeof( cmd->favorites ) );
+
+ cmd->menuactive = 0;
+ cmd->curmenu = MENU_FAVORITES;
+ cmd->curmenupos = 0;
+ cmd->curmenusize = 0;
+ cmd->curusermenu = 0;
+ memset( cmd->menus, 0, sizeof( cmd->menus ) );
+
+ if( vidin && videoinput_get_norm( vidin ) != VIDEOINPUT_NTSC &&
+ videoinput_get_norm( vidin ) != VIDEOINPUT_NTSC_JP ) {
+ set_redirect( "input", "input-pal" );
+ }
+
+ if( vidin && (videoinput_get_norm( vidin ) == VIDEOINPUT_PAL ||
+ videoinput_get_norm( vidin ) == VIDEOINPUT_SECAM) ) {
+ if( cmd->checkfreq ) {
+ set_redirect( "stations", "stations-palsecam-signal" );
+ } else {
+ set_redirect( "stations", "stations-palsecam-nosignal" );
+ }
+ } else if( vidin && videoinput_get_norm( vidin ) == VIDEOINPUT_NTSC &&
+ (!strcasecmp( config_get_v4l_freq( cfg ), "us-cable" ) ||
+ !strcasecmp( config_get_v4l_freq( cfg ), "us-cable100" )) ) {
+ if( cmd->checkfreq ) {
+ set_redirect( "stations", "stations-ntsccable-signal" );
+ } else {
+ set_redirect( "stations", "stations-ntsccable-nosignal" );
+ }
+ }
+
+ menu = menu_new( "root-tuner" );
+ menu_set_back_command( menu, TVTIME_MENU_EXIT, 0 );
+
+ menu_set_text( menu, 0, _("Setup") );
+
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_STATIONMANAGEMENT " %s", _("Channel management") );
+ menu_set_text( menu, 1, string );
+ menu_set_enter_command( menu, 1, TVTIME_SHOW_MENU, "stations" );
+
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_INPUTCONF " %s", _("Input configuration") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_SHOW_MENU, "input" );
+
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_PICTURESETTINGS " %s", _("Picture settings") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_SHOW_MENU, "picture" );
+
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_VIDEOPROCESSING " %s", _("Video processing") );
+ menu_set_text( menu, 4, string );
+ menu_set_enter_command( menu, 4, TVTIME_SHOW_MENU, "processing" );
+
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_OUTPUTCONF " %s", _("Output configuration") );
+ menu_set_text( menu, 5, string );
+ menu_set_enter_command( menu, 5, TVTIME_SHOW_MENU, "output" );
+
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_EXIT " %s", _("Exit menu") );
+ menu_set_text( menu, 6, string );
+ menu_set_enter_command( menu, 6, TVTIME_MENU_EXIT, 0 );
+
+ commands_add_menu( cmd, menu );
+
+ menu = menu_new( "root-notuner" );
+ menu_set_text( menu, 0, _("Setup") );
+ menu_set_back_command( menu, TVTIME_MENU_EXIT, 0 );
+
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_INPUTCONF " %s", _("Input configuration") );
+ menu_set_text( menu, 1, string );
+ menu_set_enter_command( menu, 1, TVTIME_SHOW_MENU, "input" );
+
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_PICTURESETTINGS " %s", _("Picture settings") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_SHOW_MENU, "picture" );
+
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_VIDEOPROCESSING " %s", _("Video processing") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_SHOW_MENU, "processing" );
+
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_OUTPUTCONF " %s", _("Output configuration") );
+ menu_set_text( menu, 4, string );
+ menu_set_enter_command( menu, 4, TVTIME_SHOW_MENU, "output" );
+
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_EXIT " %s", _("Exit menu") );
+ menu_set_text( menu, 5, string );
+ menu_set_enter_command( menu, 5, TVTIME_MENU_EXIT, 0 );
+
+ commands_add_menu( cmd, menu );
+
+ menu = menu_new( "stations" );
+ snprintf( string, sizeof( string ), "%s - %s",
+ _("Setup"), _("Channel management") );
+ menu_set_text( menu, 0, string);
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "stations" );
+ commands_add_menu( cmd, menu );
+ if( vidin ) {
+ reset_stations_menu( commands_get_menu( cmd, "stations" ),
+ (videoinput_get_norm( vidin ) == VIDEOINPUT_NTSC ||
+ videoinput_get_norm( vidin ) == VIDEOINPUT_NTSC_JP),
+ videoinput_get_norm( vidin ) == VIDEOINPUT_PAL,
+ videoinput_get_norm( vidin ) == VIDEOINPUT_SECAM,
+ (!strcasecmp( cmd->newfreqtable, "us-cable" ) ||
+ !strcasecmp( cmd->newfreqtable, "us-cable100" )),
+ station_get_current_active( cmd->stationmgr ),
+ cmd->checkfreq, cmd->scan_channels,
+ videoinput_is_v4l2( cmd->vidin ),
+ station_get_default_audio_norm( cmd->stationmgr ),
+ station_get_current_audio_norm( cmd->stationmgr ) );
+ }
+
+ menu = menu_new( "frequencies" );
+ snprintf( string, sizeof( string ), "%s - %s - %s", _("Setup"),
+ _("Channel management"), _("Frequency table") );
+ menu_set_text( menu, 0, string );
+ commands_add_menu( cmd, menu );
+ if( vidin ) {
+ reset_frequency_menu( commands_get_menu( cmd, "frequencies" ),
+ videoinput_get_norm( vidin ),
+ config_get_v4l_freq( cfg ) );
+ }
+
+ menu = menu_new( "finetune" );
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "stations" );
+ snprintf( string, sizeof( string ), "%s - %s - %s", _("Setup"),
+ _("Channel management"), _("Finetune") );
+ menu_set_text( menu, 0, string );
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_TVLOGO " %s: ---", _("Current") );
+ menu_set_text( menu, 1, string );
+ menu_set_enter_command( menu, 1, TVTIME_SHOW_MENU, "stations" );
+
+ menu_set_default_cursor( menu, 1 );
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_PLUSBUTTON " %s", _("Increase") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_FINETUNE_UP, "" );
+
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_MINUSBUTTON " %s",_("Decrease") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_FINETUNE_DOWN, "" );
+
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_PLAINLEFTARROW " %s", _("Back") );
+ menu_set_text( menu, 4, string );
+ menu_set_enter_command( menu, 4, TVTIME_SHOW_MENU, "stations" );
+
+ commands_add_menu( cmd, menu );
+
+ menu = menu_new( "input-ntsc" );
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "root" );
+ snprintf( string, sizeof( string ), "%s - %s", _("Setup"),
+ _("Input configuration") );
+ menu_set_text( menu, 0, string );
+ if( vidin ) {
+ snprintf( string, sizeof( string ), TVTIME_ICON_VIDEOINPUT " %s: %s",
+ _("Change video source"), videoinput_get_input_name( vidin ) );
+ } else {
+ snprintf( string, sizeof( string ), TVTIME_ICON_VIDEOINPUT " %s",
+ _("Change video source") );
+ }
+ menu_set_text( menu, 1, string );
+ menu_set_enter_command( menu, 1, TVTIME_TOGGLE_INPUT, "" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_STATIONMANAGEMENT " %s",
+ _("Preferred audio mode") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_SHOW_MENU, "audiomode" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_STATIONMANAGEMENT " %s",
+ _("Audio volume boost") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_SHOW_MENU, "audioboost" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_TELEVISIONSTANDARD " %s",
+ _("Television standard") );
+ menu_set_text( menu, 4, string );
+ menu_set_enter_command( menu, 4, TVTIME_SHOW_MENU, "norm" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_INPUTWIDTH " %s",
+ _("Horizontal resolution") );
+ menu_set_text( menu, 5, string );
+ menu_set_enter_command( menu, 5, TVTIME_SHOW_MENU, "hres" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_CLOSEDCAPTIONICON " %s",
+ _("Toggle closed captions") );
+ menu_set_text( menu, 6, string );
+ menu_set_enter_command( menu, 6, TVTIME_TOGGLE_CC, "" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_TVPGICON " %s",
+ _("Toggle XDS decoding") );
+ menu_set_text( menu, 7, string );
+ menu_set_enter_command( menu, 7, TVTIME_TOGGLE_XDS, "" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, 8, string );
+ menu_set_enter_command( menu, 8, TVTIME_SHOW_MENU, "root" );
+
+ commands_add_menu( cmd, menu );
+
+ menu = menu_new( "input-pal" );
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "root" );
+ snprintf( string, sizeof( string ),
+ "%s - %s", _("Setup"), _("Input configuration") );
+ menu_set_text (menu, 0, string);
+ if( vidin ) {
+ snprintf( string, sizeof( string ), TVTIME_ICON_VIDEOINPUT " %s: %s",
+ _("Change video source"), videoinput_get_input_name( vidin ) );
+ } else {
+ snprintf( string, sizeof( string ), TVTIME_ICON_VIDEOINPUT " %s",
+ _("Change video source") );
+ }
+ menu_set_text( menu, 1, string );
+ menu_set_enter_command( menu, 1, TVTIME_TOGGLE_INPUT, "" );
+ if( vidin ) {
+ reset_pal_input_menu( menu, vidin, cmd->stationmgr );
+ }
+ commands_add_menu( cmd, menu );
+
+ menu = menu_new( "hres" );
+ snprintf( string, sizeof( string ), "%s - %s - %s",
+ _("Setup"), _("Input configuration"), _("Horizontal resolution") );
+ menu_set_text( menu, 0, string );
+ menu_set_default_cursor( menu, 1 );
+ commands_add_menu( cmd, menu );
+ maxwidth = cmd->vidin? videoinput_get_maxwidth( cmd->vidin ) : 0;
+ reset_inputwidth_menu( commands_get_menu( cmd, "hres" ),
+ config_get_inputwidth( cfg ), maxwidth);
+
+ menu = menu_new( "audiomode" );
+ snprintf( string, sizeof( string ), "%s - %s - %s",
+ _("Setup"), _("Input configuration"), _("Preferred audio mode") );
+ menu_set_text( menu, 0, string );
+ commands_add_menu( cmd, menu );
+ if( cmd->vidin ) {
+ reset_audio_mode_menu( commands_get_menu( cmd, "audiomode" ),
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_NTSC,
+ videoinput_get_audio_mode( cmd->vidin ) );
+ } else {
+ reset_audio_mode_menu( commands_get_menu( cmd, "audiomode" ), 0, 0 );
+ }
+
+ menu = menu_new( "audioboost" );
+ snprintf( string, sizeof( string ), "%s - %s - %s",
+ _("Setup"), _("Input configuration"), _("Audio volume boost") );
+ menu_set_text( menu, 0, string );
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "input" );
+ commands_add_menu( cmd, menu );
+ reset_audio_boost_menu( commands_get_menu( cmd, "audioboost" ),
+ cmd->boost );
+
+ menu = menu_new( "norm" );
+ snprintf( string, sizeof( string ), "%s - %s - %s",
+ _("Setup"), _("Input configuration"), _("Television standard") );
+ menu_set_text( menu, 0, string );
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "root" );
+ snprintf( string, sizeof( string ), TVTIME_ICON_RESTART " %s",
+ _("Restart with new settings") );
+ menu_set_text( menu, 9, string );
+ menu_set_enter_command( menu, 9, TVTIME_RESTART, "" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, 10, string );
+ menu_set_enter_command( menu, 10, TVTIME_SHOW_MENU, "input" );
+
+ if( !strcasecmp( config_get_v4l_norm( cfg ), "pal" ) ) {
+ cmd->newnorm = "PAL";
+ } else if( !strcasecmp( config_get_v4l_norm( cfg ), "secam" ) ) {
+ cmd->newnorm = "SECAM";
+ } else if( !strcasecmp( config_get_v4l_norm( cfg ), "pal-nc" ) ) {
+ cmd->newnorm = "PAL-Nc";
+ } else if( !strcasecmp( config_get_v4l_norm( cfg ), "pal-m" ) ) {
+ cmd->newnorm = "PAL-M";
+ } else if( !strcasecmp( config_get_v4l_norm( cfg ), "pal-n" ) ) {
+ cmd->newnorm = "PAL-N";
+ } else if( !strcasecmp( config_get_v4l_norm( cfg ), "ntsc-jp" ) ) {
+ cmd->newnorm = "NTSC-JP";
+ } else if( !strcasecmp( config_get_v4l_norm( cfg ), "pal-60" ) ) {
+ cmd->newnorm = "PAL-60";
+ } else {
+ cmd->newnorm = "NTSC";
+ }
+ reset_norm_menu( menu, cmd->newnorm );
+ commands_add_menu( cmd, menu );
+
+ menu = menu_new( "output" );
+ snprintf( string, sizeof( string ), "%s - %s",
+ _("Setup"), _("Output configuration") );
+ menu_set_text( menu, 0, string );
+ commands_add_menu( cmd, menu );
+
+ menu = menu_new( "matte" );
+ snprintf( string, sizeof( string ), "%s - %s - %s",
+ _("Setup"), _("Output configuration"), _("Apply matte") );
+ menu_set_text( menu, 0, string );
+ commands_add_menu( cmd, menu );
+
+ menu = menu_new( "overscan" );
+ snprintf( string, sizeof( string ), "%s - %s - %s",
+ _("Setup"), _("Output configuration"), _("Overscan") );
+ menu_set_text( menu, 0, string );
+ commands_add_menu( cmd, menu );
+ reset_overscan_menu( commands_get_menu( cmd, "overscan" ), cmd->overscan );
+
+ menu = menu_new( "fspos" );
+ snprintf( string, sizeof( string ), "%s - %s - %s",
+ _("Setup"), _("Output configuration"), _("Fullscreen position") );
+ menu_set_text( menu, 0, string );
+ commands_add_menu( cmd, menu );
+
+ menu = menu_new( "processing" );
+ snprintf( string, sizeof( string ), "%s - %s",
+ _("Setup"), _("Video processing") );
+ menu_set_text( menu, 0, string );
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "root" );
+ snprintf( string, sizeof( string ), TVTIME_ICON_DEINTERLACERCONF " %s",
+ _("Deinterlacer configuration") );
+ menu_set_text( menu, 1, string );
+ menu_set_enter_command( menu, 1, TVTIME_SHOW_MENU, "deinterlacer" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_DEINTERLACERDESC " %s",
+ _("Current deinterlacer description") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_SHOW_MENU, "deintdescription" );
+ snprintf( string, sizeof( string ), TVTIME_ICON_ATTEMPTEDFRAMERATE " %s",
+ _("Attempted framerate") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_SHOW_MENU, "framerate" );
+ snprintf( string, sizeof( string ), TVTIME_ICON_INPUTFILTERS " %s",
+ _("Input filters") );
+ menu_set_text( menu, 4, string );
+ menu_set_enter_command( menu, 4, TVTIME_SHOW_MENU, "filters" );
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, 5, string );
+ menu_set_enter_command( menu, 5, TVTIME_SHOW_MENU, "root" );
+ commands_add_menu( cmd, menu );
+
+ menu = menu_new( "deinterlacer" );
+
+ snprintf( string, sizeof( string ), "%s - %s - %s", _("Setup"),
+ _("Video processing"), _("Deinterlacer configuration") );
+ menu_set_text( menu, 0, string );
+ commands_add_menu( cmd, menu );
+
+ menu = menu_new( "deintdescription" );
+ snprintf( string, sizeof( string ), "%s - %s - %s", _("Setup"),
+ _("Video processing"), _("Deinterlacer description") );
+ menu_set_text( menu, 0, string );
+
+ commands_add_menu( cmd, menu );
+
+ menu = menu_new( "framerate" );
+
+ snprintf( string, sizeof( string ), "%s - %s - %s", _("Setup"),
+ _("Video processing"), _("Attempted framerate") );
+ menu_set_text( menu, 0, string );
+ commands_add_menu( cmd, menu );
+
+ menu = menu_new( "filters" );
+ snprintf( string, sizeof( string ), "%s - %s - %s", _("Setup"),
+ _("Video processing"), _("Input filters") );
+ menu_set_text( menu, 0, string );
+ commands_add_menu( cmd, menu );
+ reset_filters_menu( commands_get_menu( cmd, "filters" ),
+ cmd->apply_invert, cmd->apply_mirror,
+ cmd->apply_chroma_kill,
+ cmd->vidin && videoinput_get_height( cmd->vidin ) == 480,
+ cmd->pulldown_alg );
+
+ menu = menu_new( "picture-notuner" );
+ snprintf( string, sizeof( string ), "%s - %s", _("Setup"), _("Picture") );
+ menu_set_text( menu, 0, string );
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "root" );
+ snprintf( string, sizeof( string ), TVTIME_ICON_BRIGHTNESS " %s",
+ _("Brightness") );
+ menu_set_text( menu, 1, string );
+ menu_set_enter_command( menu, 1, TVTIME_SHOW_MENU, "brightness" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_CONTRAST " %s",
+ _("Contrast") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_SHOW_MENU, "contrast" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_SATURATION " %s", _("Saturation") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_SHOW_MENU, "saturation" );
+
+ curpos = 4;
+ if( cmd->vidin && videoinput_get_height( cmd->vidin ) == 480 &&
+ videoinput_get_norm( cmd->vidin ) != VIDEOINPUT_PAL_60 ) {
+ /* Hue only applies to NTSC norms. */
+ snprintf( string, sizeof( string ), TVTIME_ICON_HUE " %s", _("Hue") );
+ menu_set_text( menu, curpos, string );
+ menu_set_enter_command( menu, curpos, TVTIME_SHOW_MENU, "hue" );
+ curpos++;
+ }
+
+ if (config_get_save_restore_picture (cfg)) {
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_SAVEPICTUREGLOBAL " %s",
+ _("Save current settings as defaults") );
+ menu_set_text( menu, curpos, string );
+ menu_set_enter_command( menu, curpos, TVTIME_SAVE_PICTURE_GLOBAL, "" );
+ curpos++;
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_RESETTODEFAULTS " %s",
+ _("Reset to global defaults") );
+ menu_set_text( menu, curpos, string );
+ menu_set_enter_command( menu, curpos, TVTIME_AUTO_ADJUST_PICT, "" );
+ curpos++;
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, curpos, string );
+ menu_set_enter_command( menu, curpos, TVTIME_SHOW_MENU, "root" );
+ commands_add_menu( cmd, menu );
+ } else {
+ snprintf( string, sizeof( string ), TVTIME_ICON_RESETTODEFAULTS " %s",
+ _("Reset to global defaults") );
+ menu_set_text( menu, curpos, string );
+ menu_set_enter_command( menu, curpos, TVTIME_AUTO_ADJUST_PICT, "" );
+ curpos++;
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, curpos, string );
+ menu_set_enter_command( menu, curpos, TVTIME_SHOW_MENU, "root" );
+ commands_add_menu( cmd, menu );
+ }
+
+ menu = menu_new( "picture-tuner" );
+ snprintf( string, sizeof( string ), "%s - %s", _("Setup"), _("Picture") );
+ menu_set_text( menu, 0, string);
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "root" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_BRIGHTNESS " %s",
+ _("Brightness") );
+ menu_set_text( menu, 1, string );
+ menu_set_enter_command( menu, 1, TVTIME_SHOW_MENU, "brightness" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_CONTRAST " %s",
+ _("Contrast") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_SHOW_MENU, "contrast" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_SATURATION " %s", _("Saturation") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_SHOW_MENU, "saturation" );
+
+ curpos = 4;
+ if( cmd->vidin && videoinput_get_height( cmd->vidin ) == 480 &&
+ videoinput_get_norm( cmd->vidin ) != VIDEOINPUT_PAL_60 ) {
+ snprintf( string, sizeof( string ), TVTIME_ICON_HUE " %s", _("Hue") );
+ menu_set_text( menu, curpos, string );
+ menu_set_enter_command( menu, curpos, TVTIME_SHOW_MENU, "hue" );
+ curpos++;
+ }
+
+ if( config_get_save_restore_picture( cfg ) ) {
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_SAVEPICTUREGLOBAL " %s",
+ _("Save current settings as global defaults") );
+ menu_set_text( menu, curpos, string );
+ menu_set_enter_command( menu, curpos, TVTIME_SAVE_PICTURE_GLOBAL, "" );
+ curpos++;
+
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_SAVEPICTURECHANNEL " %s",
+ _("Save current settings as channel defaults") );
+ menu_set_text( menu, curpos, string );
+ menu_set_enter_command( menu, curpos, TVTIME_SAVE_PICTURE_CHANNEL, "" );
+ curpos++;
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_RESETTODEFAULTS " %s",
+ _("Reset to global defaults") );
+ menu_set_text( menu, curpos, string );
+ menu_set_enter_command( menu, curpos, TVTIME_AUTO_ADJUST_PICT, "" );
+ curpos++;
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, curpos, string );
+ menu_set_enter_command( menu, curpos, TVTIME_SHOW_MENU, "root" );
+
+ commands_add_menu( cmd, menu );
+ } else {
+ snprintf( string, sizeof( string ), TVTIME_ICON_RESETTODEFAULTS " %s",
+ _("Reset to global defaults") );
+ menu_set_text( menu, curpos, string );
+ menu_set_enter_command( menu, curpos, TVTIME_AUTO_ADJUST_PICT, "" );
+ curpos++;
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, curpos, string );
+ menu_set_enter_command( menu, curpos, TVTIME_SHOW_MENU, "root" );
+ curpos++;
+
+ commands_add_menu( cmd, menu );
+ }
+
+
+ menu = menu_new( "brightness" );
+ snprintf( string, sizeof( string ), "%s - %s - %s",
+ _("Setup"), _("Picture"), _("Brightness") );
+ menu_set_text( menu, 0, string );
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "picture" );
+ snprintf( string, sizeof( string ), TVTIME_ICON_TVLOGO " %s: ---",
+ _("Current") );
+ menu_set_text( menu, 1, string );
+ menu_set_enter_command( menu, 1, TVTIME_SHOW_MENU, "picture" );
+
+ menu_set_default_cursor( menu, 1 );
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLUSBUTTON " %s",
+ _("Increase") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_BRIGHTNESS_UP, "" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_MINUSBUTTON " %s",
+ _("Decrease") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_BRIGHTNESS_DOWN, "" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, 4, string );
+ menu_set_enter_command( menu, 4, TVTIME_SHOW_MENU, "picture" );
+
+ commands_add_menu( cmd, menu );
+ if( vidin ) {
+ menu_set_value (commands_get_menu (cmd, "brightness"),
+ videoinput_get_brightness (cmd->vidin),
+ TVTIME_ICON_BRIGHTNESS);
+ }
+
+ menu = menu_new( "contrast" );
+ snprintf( string, sizeof( string ), "%s - %s - %s",
+ _("Setup"), _("Picture"), _("Contrast") );
+ menu_set_text( menu, 0, string );
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "picture" );
+ snprintf( string, sizeof( string ), TVTIME_ICON_TVLOGO " %s: ---",
+ _("Current") );
+ menu_set_text( menu, 1, string );
+ menu_set_enter_command( menu, 1, TVTIME_SHOW_MENU, "picture" );
+ menu_set_default_cursor( menu, 1 );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLUSBUTTON " %s",
+ _("Increase") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_CONTRAST_UP, "" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_MINUSBUTTON " %s",
+ _("Decrease") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_CONTRAST_DOWN, "" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, 4, string );
+ menu_set_enter_command( menu, 4, TVTIME_SHOW_MENU, "picture" );
+
+ commands_add_menu( cmd, menu );
+ if( vidin ) {
+ menu_set_value (commands_get_menu( cmd, "contrast" ),
+ videoinput_get_contrast( cmd->vidin ),
+ TVTIME_ICON_CONTRAST);
+ }
+
+ menu = menu_new( "saturation" );
+ snprintf( string, sizeof( string ), "%s - %s - %s",
+ _("Setup"), _("Picture"), _("Saturation") );
+ menu_set_text( menu, 0, string );
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "picture" );
+ snprintf( string, sizeof( string ), TVTIME_ICON_TVLOGO " %s: ---",
+ _("Current") );
+ menu_set_text( menu, 1, string );
+ menu_set_enter_command( menu, 1, TVTIME_SHOW_MENU, "picture" );
+
+ menu_set_default_cursor( menu, 1 );
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLUSBUTTON " %s",
+ _("Increase") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_SATURATION_UP, "" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_MINUSBUTTON " %s",
+ _("Decrease") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_SATURATION_DOWN, "" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, 4, string );
+ menu_set_enter_command( menu, 4, TVTIME_SHOW_MENU, "picture" );
+
+ commands_add_menu( cmd, menu );
+ if( vidin ) {
+ menu_set_value (commands_get_menu (cmd, "saturation" ),
+ videoinput_get_saturation (cmd->vidin),
+ TVTIME_ICON_SATURATION);
+ }
+
+ menu = menu_new( "hue" );
+ snprintf( string, sizeof( string ), "%s - %s - %s",
+ _("Setup"), _("Picture"), _("Hue") );
+ menu_set_text( menu, 0, string );
+ menu_set_back_command( menu, TVTIME_SHOW_MENU, "picture" );
+ snprintf( string, sizeof( string ), TVTIME_ICON_TVLOGO " %s: ---",
+ _("Current") );
+ menu_set_text( menu, 1, string );
+ menu_set_enter_command( menu, 1, TVTIME_SHOW_MENU, "picture" );
+ menu_set_default_cursor( menu, 1 );
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLUSBUTTON " %s",
+ _("Increase") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_HUE_UP, "" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_MINUSBUTTON " %s",
+ _("Decrease") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_HUE_DOWN, "" );
+
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
+ _("Back") );
+ menu_set_text( menu, 4, string );
+ menu_set_enter_command( menu, 4, TVTIME_SHOW_MENU, "picture" );
+
+ commands_add_menu( cmd, menu );
+ if( vidin ) {
+ menu_set_value (commands_get_menu (cmd, "hue"),
+ videoinput_get_hue (cmd->vidin),
+ TVTIME_ICON_HUE);
+ }
+
+ if( cmd->xmltv ) {
+ menu = menu_new( "xmltv-language" );
+ snprintf( string, sizeof( string ), "%s",
+ _("Preferred XMLTV language") );
+ menu_set_text( menu, 0, string );
+ commands_add_menu( cmd, menu );
+ reset_xmltv_languages_menu( menu, cmd->xmltv );
+ }
+
+ reinit_tuner( cmd );
+
+ return cmd;
+}
+
+void commands_delete( commands_t *cmd )
+{
+ int i;
+
+ for( i = 0; i < MAX_USER_MENUS; i++ ) {
+ if( cmd->menus[ i ] ) {
+ menu_delete( cmd->menus[ i ] );
+ }
+ }
+
+ if( cmd->xmltv ) xmltv_delete( cmd->xmltv );
+ free( cmd );
+}
+
+static void add_to_favorites( commands_t *cmd, int pos )
+{
+ int i;
+
+ for( i = 0; i < NUM_FAVORITES; i++ ) {
+ if( cmd->favorites[ i ] == pos ) return;
+ }
+ cmd->favorites[ cmd->curfavorite ] = pos;
+ cmd->curfavorite = (cmd->curfavorite + 1) % NUM_FAVORITES;
+ if( cmd->numfavorites < NUM_FAVORITES ) {
+ cmd->numfavorites++;
+ }
+}
+
+static void osd_list_audio_modes( tvtime_osd_t *osd, int ntsc, int curmode )
+{
+ tvtime_osd_list_set_lines( osd, ntsc ? 4 : 5 );
+ tvtime_osd_list_set_text( osd, 0, _("Preferred audio mode") );
+ tvtime_osd_list_set_text( osd, 1, _("Mono") );
+ tvtime_osd_list_set_text( osd, 2, _("Stereo") );
+ tvtime_osd_list_set_text( osd, 3, ntsc ?
+ _("SAP") : _("Primary Language") );
+ if( !ntsc ) tvtime_osd_list_set_text( osd, 4, _("Secondary Language") );
+ if( curmode == VIDEOINPUT_MONO ) {
+ tvtime_osd_list_set_hilight( osd, 1 );
+ } else if( curmode == VIDEOINPUT_STEREO ) {
+ tvtime_osd_list_set_hilight( osd, 2 );
+ } else if( curmode == VIDEOINPUT_LANG1 || (ntsc && curmode == VIDEOINPUT_LANG2) ) {
+ tvtime_osd_list_set_hilight( osd, 3 );
+ } else if( curmode == VIDEOINPUT_LANG2 ) {
+ tvtime_osd_list_set_hilight( osd, 4 );
+ }
+ tvtime_osd_show_list( osd, 1, 0 );
+}
+
+/**
+ * Hardcoded menus.
+ */
+
+static void menu_off( commands_t *cmd )
+{
+ tvtime_osd_list_hold( cmd->osd, 0 );
+ tvtime_osd_show_list( cmd->osd, 0, 0 );
+ cmd->menuactive = 0;
+}
+
+static void menu_enter( commands_t *cmd )
+{
+ if( cmd->curmenu == MENU_FAVORITES ) {
+ if( cmd->curmenupos == cmd->numfavorites ) {
+ add_to_favorites( cmd, station_get_current_id( cmd->stationmgr ) );
+ } else {
+ if( cmd->curmenupos < cmd->numfavorites ) {
+ station_set( cmd->stationmgr, cmd->favorites[ cmd->curmenupos ] );
+ cmd->change_channel = 1;
+ }
+ }
+ menu_off( cmd );
+ } else if( cmd->curmenu == MENU_USER ) {
+ int command = menu_get_enter_command( cmd->curusermenu, cmd->curmenupos + 1 );
+ const char *argument = menu_get_enter_argument( cmd->curusermenu, cmd->curmenupos + 1 );
+
+ /* I check for MENU_ENTER just to avoid a malicious infinite loop. */
+ if( command != TVTIME_MENU_ENTER ) {
+ commands_handle( cmd, command, argument );
+ }
+ }
+}
+
+static void menu_back( commands_t *cmd )
+{
+ if( cmd->curmenu == MENU_FAVORITES ) {
+ commands_handle( cmd, TVTIME_SHOW_MENU, "stations" );
+ } else if( cmd->curmenu == MENU_USER ) {
+ int command = menu_get_back_command( cmd->curusermenu );
+ const char *argument = menu_get_back_argument( cmd->curusermenu );
+
+ /* I check for MENU_ENTER just to avoid a malicious infinite loop. */
+ if( command != TVTIME_MENU_ENTER ) {
+ commands_handle( cmd, command, argument );
+ }
+ }
+}
+
+static void display_current_menu( commands_t *cmd )
+{
+ int i;
+
+ if( cmd->curmenu == MENU_FAVORITES ) {
+ char string[ 128 ];
+ tvtime_osd_list_set_lines( cmd->osd, cmd->numfavorites + 3 );
+ tvtime_osd_list_set_text( cmd->osd, 0, _("Favorites") );
+ for( i = 0; i < cmd->numfavorites; i++ ) {
+ char text[ 32 ];
+ snprintf( text, sizeof (text), "%d", cmd->favorites[ i ] );
+ tvtime_osd_list_set_text( cmd->osd, i + 1, text );
+ }
+ snprintf( string, sizeof( string ), TVTIME_ICON_PLUSBUTTON " %s",
+ _("Add current channel") );
+ tvtime_osd_list_set_text( cmd->osd, cmd->numfavorites + 1, string );
+ snprintf( string, sizeof( string ), TVTIME_ICON_EXIT " %s", _("Exit") );
+ tvtime_osd_list_set_text( cmd->osd, cmd->numfavorites + 2, string );
+ cmd->curmenusize = cmd->numfavorites + 2;
+ } else if( cmd->curmenu == MENU_USER && cmd->curusermenu ) {
+ tvtime_osd_list_set_lines( cmd->osd, menu_get_num_lines( cmd->curusermenu ) );
+ for( i = 0; i < menu_get_num_lines( cmd->curusermenu ); i++ ) {
+ tvtime_osd_list_set_text( cmd->osd, i, menu_get_text( cmd->curusermenu, i ) );
+ }
+ cmd->curmenusize = menu_get_num_lines( cmd->curusermenu ) - 1;
+ }
+
+ tvtime_osd_list_set_hilight( cmd->osd, cmd->curmenupos + 1 );
+ tvtime_osd_show_list( cmd->osd, 1, 0 );
+ tvtime_osd_list_hold( cmd->osd, 1 );
+}
+
+menu_t *commands_get_menu( commands_t *cmd, const char *menuname )
+{
+ int i;
+
+ for( i = 0; i < tvtime_num_builtin_menus(); i++ ) {
+ if( !strcasecmp( menu_table[ i ].name, menuname ) ) {
+ if( menu_table[ i ].menutype == MENU_REDIRECT ) {
+ return commands_get_menu( cmd, menu_table[ i ].dest );
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ for( i = 0; i < MAX_USER_MENUS; i++ ) {
+ if( !cmd->menus[ i ] ) break;
+
+ if( !strcasecmp( menuname, menu_get_name( cmd->menus[ i ] ) ) ) {
+ return cmd->menus[ i ];
+ cmd->curusermenu = cmd->menus[ i ];
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int set_menu( commands_t *cmd, const char *menuname )
+{
+ int i;
+
+ if( !menuname || !*menuname ) {
+ return 0;
+ }
+
+ cmd->menuactive = 1;
+ cmd->curusermenu = 0;
+
+ for( i = 0; i < tvtime_num_builtin_menus(); i++ ) {
+ if( !strcasecmp( menu_table[ i ].name, menuname ) ) {
+ if( menu_table[ i ].menutype == MENU_REDIRECT ) {
+ return set_menu( cmd, menu_table[ i ].dest );
+ } else {
+ cmd->curmenu = menu_table[ i ].menutype;
+ cmd->curmenupos = 0;
+ return 1;
+ }
+ }
+ }
+
+ cmd->curmenu = MENU_USER;
+ cmd->curusermenu = 0;
+
+ if( menuname && *menuname ) {
+ for( i = 0; i < MAX_USER_MENUS; i++ ) {
+ if( !cmd->menus[ i ] ) {
+ break;
+ }
+
+ if( !strcasecmp( menuname, menu_get_name( cmd->menus[ i ] ) ) ) {
+ cmd->curusermenu = cmd->menus[ i ];
+ break;
+ }
+ }
+ }
+
+ if( cmd->curusermenu ) {
+ cmd->curmenupos = menu_get_cursor( cmd->curusermenu );
+ cmd->curmenusize = menu_get_num_lines( cmd->curusermenu ) - 1;
+ return 1;
+ }
+
+ cmd->menuactive = 0;
+ return 0;
+}
+
+void commands_refresh_menu( commands_t *cmd )
+{
+ if( cmd->menuactive ) {
+ if( cmd->curmenu == MENU_USER ) {
+ const char *curname = menu_get_name( cmd->curusermenu );
+ int i;
+
+ for( i = 0; i < tvtime_num_builtin_menus(); i++ ) {
+ if( !strncasecmp( menu_table[ i ].name, curname, strlen( menu_table[ i ].name ) ) ) {
+ if( menu_table[ i ].menutype == MENU_REDIRECT ) {
+ set_menu( cmd, menu_table[ i ].name );
+ break;
+ }
+ }
+ }
+ }
+ display_current_menu( cmd );
+ }
+}
+
+void commands_add_menu( commands_t *cmd, menu_t *menu )
+{
+ int i;
+
+ for( i = 0; i < MAX_USER_MENUS; i++ ) {
+ if( !cmd->menus[ i ] ) {
+ cmd->menus[ i ] = menu;
+ return;
+ }
+ }
+}
+
+void commands_set_station_mgr( commands_t *cmd, station_mgr_t *mgr )
+{
+ cmd->stationmgr = mgr;
+ reinit_tuner( cmd );
+}
+
+void commands_clear_menu_positions( commands_t *cmd )
+{
+ int i;
+
+ for( i = 0; i < MAX_USER_MENUS; i++ ) {
+ if( cmd->menus[ i ] ) {
+ menu_set_cursor( cmd->menus[ i ], menu_get_default_cursor( cmd->menus[ i ] ) );
+ } else {
+ return;
+ }
+ }
+}
+
+int commands_in_menu( commands_t *cmd )
+{
+ return cmd->menuactive;
+}
+
+static void osd_list_xmltv_languages( tvtime_osd_t *osd, commands_t *cmd )
+{
+ int num = xmltv_get_num_languages( cmd->xmltv );
+ const char *cur = xmltv_get_language( cmd->xmltv );
+ char string[ 128 ];
+ int i;
+
+ if( !cmd->xmltv ) return;
+
+ tvtime_osd_list_set_hilight( osd, 1 );
+ tvtime_osd_list_set_lines( osd, num + 2);
+ tvtime_osd_list_set_text( osd, 0, _("Preferred XMLTV language") );
+ tvtime_osd_list_set_text( osd, 1, _("Default language") );
+ for( i = 1; i <= num; i++ ) {
+ const char *code = xmltv_get_language_code( cmd->xmltv, i );
+ const char *name = xmltv_get_language_name( cmd->xmltv, i );
+ snprintf( string, sizeof( string ), "%s (%s)",
+ name? name : _("Unknown language"), code );
+ tvtime_osd_list_set_text( osd, i + 1, string );
+ if( cur && code && !strncasecmp( cur, code, 2 ) ) {
+ tvtime_osd_list_set_hilight( osd, i + 1 );
+ }
+ }
+ tvtime_osd_show_list( osd, 1, 0 );
+}
+
+void commands_handle( commands_t *cmd, int tvtime_cmd, const char *arg )
+{
+ time_t now;
+ int volume;
+ int key;
+
+ if( tvtime_cmd == TVTIME_NOCOMMAND ) return;
+
+ if( cmd->menuactive && tvtime_is_menu_command( tvtime_cmd ) ) {
+ int x, y, line;
+ switch( tvtime_cmd ) {
+ case TVTIME_MENU_EXIT:
+ menu_off( cmd );
+ break;
+ case TVTIME_MENU_UP:
+ cmd->curmenupos = (cmd->curmenupos + cmd->curmenusize - 1) % (cmd->curmenusize);
+ if( cmd->curusermenu ) menu_set_cursor( cmd->curusermenu, cmd->curmenupos );
+ display_current_menu( cmd );
+ break;
+ case TVTIME_MENU_DOWN:
+ cmd->curmenupos = (cmd->curmenupos + 1) % (cmd->curmenusize);
+ if( cmd->curusermenu ) menu_set_cursor( cmd->curusermenu, cmd->curmenupos );
+ display_current_menu( cmd );
+ break;
+ case TVTIME_MENU_BACK: menu_back( cmd ); break;
+ case TVTIME_MENU_ENTER: menu_enter( cmd ); break;
+ case TVTIME_SHOW_MENU:
+ if( set_menu( cmd, arg ) ) {
+ display_current_menu( cmd );
+ } else {
+ menu_off( cmd );
+ }
+ break;
+ case TVTIME_MOUSE_MOVE:
+ sscanf( arg, "%d %d", &x, &y );
+ if( cmd->halfsize ) y *= 2;
+ line = tvtime_osd_list_get_line_pos( cmd->osd, y );
+ if( line > 0 ) {
+ cmd->curmenupos = (line - 1);
+ if( cmd->curusermenu ) menu_set_cursor( cmd->curusermenu, cmd->curmenupos );
+ display_current_menu( cmd );
+ }
+ break;
+ }
+ return;
+ }
+
+ switch( tvtime_cmd ) {
+ case TVTIME_NOOP:
+ break;
+
+ case TVTIME_QUIT:
+ cmd->quit = 1;
+ break;
+
+ case TVTIME_SHOW_MENU:
+ if( cmd->osd ) {
+ commands_clear_menu_positions( cmd );
+ if( set_menu( cmd, arg ) || set_menu( cmd, "root" ) ) {
+ display_current_menu( cmd );
+ }
+ }
+ break;
+
+ case TVTIME_KEY_EVENT:
+ key = input_string_to_special_key( arg );
+ if( !key ) key = arg[ 0 ];
+ tvtime_cmd = config_key_to_command( cmd->cfg, key );
+ if( tvtime_cmd != TVTIME_KEY_EVENT ) {
+ commands_handle( cmd, tvtime_cmd, arg );
+ }
+ break;
+
+ case TVTIME_UP:
+ if( cmd->menuactive ) {
+ commands_handle( cmd, TVTIME_MENU_UP, "" );
+ } else {
+ commands_handle( cmd, TVTIME_CHANNEL_INC, "" );
+ }
+ break;
+ case TVTIME_DOWN:
+ if( cmd->menuactive ) {
+ commands_handle( cmd, TVTIME_MENU_DOWN, "" );
+ } else {
+ commands_handle( cmd, TVTIME_CHANNEL_DEC, "" );
+ }
+ break;
+ case TVTIME_LEFT:
+ if( cmd->menuactive ) {
+ commands_handle( cmd, TVTIME_MENU_BACK, "" );
+ } else {
+ commands_handle( cmd, TVTIME_MIXER_DOWN, "" );
+ }
+ break;
+ case TVTIME_RIGHT:
+ if( cmd->menuactive ) {
+ commands_handle( cmd, TVTIME_MENU_ENTER, "" );
+ } else {
+ commands_handle( cmd, TVTIME_MIXER_UP, "" );
+ }
+ break;
+
+ case TVTIME_SLEEP:
+ time( &now );
+ /**
+ * increment sleeptimer by SLEEPTIMER_STEP if user hits
+ * button within 5 seconds else turn it off
+ */
+ if( cmd->sleeptimer_start && (now > (cmd->sleeptimer_start + 5)) ) {
+ cmd->sleeptimer = 0;
+ cmd->sleeptimer_start = 0;
+ } else if( cmd->sleeptimer > SLEEPTIMER_NUMSTEPS ) {
+ cmd->sleeptimer = 0;
+ cmd->sleeptimer_start = 0;
+ } else {
+ cmd->sleeptimer++;
+ cmd->sleeptimer_start = now;
+ }
+
+ if( cmd->osd ) {
+ char message[ 256 ];
+
+ if( cmd->sleeptimer ) {
+ snprintf( message, sizeof (message), _("Sleep in %d minutes."),
+ sleeptimer_function( cmd->sleeptimer ) );
+ } else {
+ snprintf( message, sizeof (message), _("Sleep off.") );
+ }
+
+ tvtime_osd_show_message( cmd->osd, message );
+ }
+ break;
+
+ case TVTIME_SHOW_DEINTERLACER_INFO:
+ cmd->showdeinterlacerinfo = 1;
+ break;
+
+ case TVTIME_SHOW_STATS:
+ cmd->printdebug = 1;
+ break;
+
+ case TVTIME_RESTART:
+ cmd->restarttvtime = 1;
+ break;
+
+ case TVTIME_SCREENSHOT:
+ if( arg ) {
+ snprintf( cmd->screenshotfile, sizeof( cmd->screenshotfile ),
+ "%s", arg );
+ } else {
+ *cmd->screenshotfile = 0;
+ }
+ cmd->screenshot = 1;
+ break;
+
+ case TVTIME_TOGGLE_CHANNEL_PAL_DK:
+ if( cmd->vidin ) {
+ int new_mode = (station_get_current_audio_norm( cmd->stationmgr ) + 1) % 3;
+ station_set_current_audio_norm( cmd->stationmgr, new_mode );
+ videoinput_set_pal_audio_mode( cmd->vidin,
+ station_get_current_audio_norm( cmd->stationmgr ) );
+ if( cmd->osd ) {
+ char message[ 128 ];
+ if( new_mode == VIDEOINPUT_PAL_I_AUDIO ) {
+ snprintf( message, sizeof( message ),
+ _("Using PAL-I audio decoding for this channel.") );
+ } else if( new_mode == VIDEOINPUT_PAL_DK_AUDIO ) {
+ snprintf( message, sizeof( message ),
+ _("Using PAL-DK audio decoding for this channel.") );
+ } else {
+ snprintf( message, sizeof( message ),
+ _("Using PAL-BG audio decoding for this channel.") );
+ }
+ reset_stations_menu( commands_get_menu( cmd, "stations" ),
+ (videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_NTSC ||
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_NTSC_JP),
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_PAL,
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_SECAM,
+ (!strcasecmp( cmd->newfreqtable, "us-cable" ) ||
+ !strcasecmp( cmd->newfreqtable, "us-cable100" )),
+ station_get_current_active( cmd->stationmgr ), cmd->checkfreq,
+ cmd->scan_channels,
+ videoinput_is_v4l2( cmd->vidin ),
+ station_get_default_audio_norm( cmd->stationmgr ),
+ station_get_current_audio_norm( cmd->stationmgr ) );
+ commands_refresh_menu( cmd );
+ tvtime_osd_show_message( cmd->osd, message );
+ }
+ }
+ break;
+
+ case TVTIME_TOGGLE_PAL_DK_AUDIO:
+ if( cmd->vidin ) {
+ int dk_default = station_get_default_audio_norm( cmd->stationmgr );
+ char message[ 128 ];
+ dk_default = (dk_default + 1) % 3;
+ station_set_default_audio_norm( cmd->stationmgr, dk_default );
+ videoinput_set_pal_audio_mode( cmd->vidin,
+ station_get_current_audio_norm( cmd->stationmgr ) );
+ if( cmd->osd ) {
+ if( dk_default == VIDEOINPUT_PAL_I_AUDIO ) {
+ snprintf( message, sizeof( message ),
+ _("Defaulting to PAL-I audio decoding.") );
+ } else if( dk_default == VIDEOINPUT_PAL_DK_AUDIO ) {
+ snprintf( message, sizeof( message ),
+ _("Defaulting to PAL-DK audio decoding.") );
+ } else {
+ snprintf( message, sizeof( message ),
+ _("Defaulting to PAL-BG audio decoding.") );
+ }
+ reset_pal_input_menu( commands_get_menu( cmd, "input-pal" ),
+ cmd->vidin, cmd->stationmgr );
+ commands_refresh_menu( cmd );
+ tvtime_osd_show_message( cmd->osd, message );
+ }
+ }
+ break;
+
+ case TVTIME_TOGGLE_BARS:
+ cmd->showbars = !cmd->showbars;
+ break;
+
+ case TVTIME_TOGGLE_FULLSCREEN:
+ cmd->togglefullscreen = 1;
+ break;
+
+ case TVTIME_TOGGLE_FRAMERATE:
+ cmd->framerate = (cmd->framerate + 1) % FRAMERATE_MAX;
+ break;
+
+ case TVTIME_CHANNEL_SKIP:
+ if( cmd->vidin && videoinput_has_tuner( cmd->vidin ) ) {
+ station_set_current_active( cmd->stationmgr, !station_get_current_active( cmd->stationmgr ) );
+ if( cmd->osd ) {
+ if( station_get_current_active( cmd->stationmgr ) ) {
+ tvtime_osd_show_message( cmd->osd,
+ _("Channel marked as active in the browse list.") );
+ } else {
+ tvtime_osd_show_message( cmd->osd,
+ _("Channel disabled from the browse list.") );
+ }
+ }
+ reset_stations_menu( commands_get_menu( cmd, "stations" ),
+ (videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_NTSC ||
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_NTSC_JP),
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_PAL,
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_SECAM,
+ (!strcasecmp( cmd->newfreqtable, "us-cable" ) ||
+ !strcasecmp( cmd->newfreqtable, "us-cable100" )),
+ station_get_current_active( cmd->stationmgr ), cmd->checkfreq,
+ cmd->scan_channels,
+ videoinput_is_v4l2( cmd->vidin ),
+ station_get_default_audio_norm( cmd->stationmgr ),
+ station_get_current_audio_norm( cmd->stationmgr ) );
+ commands_refresh_menu( cmd );
+ station_writeconfig( cmd->stationmgr );
+ }
+ break;
+
+ case TVTIME_SET_AUDIO_BOOST:
+ cmd->boost = atoi( arg );
+ if( cmd->vidin ) {
+ videoinput_set_capture_volume( cmd->vidin, cmd->boost );
+ }
+ if( cmd->osd ) {
+ menu_t *boostmenu = commands_get_menu( cmd, "audioboost" );
+ char message[ 128 ];
+ reset_audio_boost_menu( boostmenu, cmd->boost );
+ commands_refresh_menu( cmd );
+ if( cmd->boost < 0 ) {
+ snprintf( message, sizeof( message ),
+ _("Capture card volume will not be set by tvtime.") );
+ } else {
+ snprintf( message, sizeof( message ),
+ _("Setting capture card volume to %d%%."),
+ cmd->boost );
+ }
+ tvtime_osd_show_message( cmd->osd, message );
+ }
+ break;
+
+ case TVTIME_SET_DEINTERLACER:
+ cmd->setdeinterlacer = 1;
+ snprintf( cmd->deinterlacer, sizeof( cmd->deinterlacer ), "%s", arg );
+ break;
+
+ case TVTIME_SET_FREQUENCY_TABLE:
+ cmd->setfreqtable = 1;
+ snprintf( cmd->newfreqtable, sizeof( cmd->newfreqtable ), "%s", arg );
+ if( cmd->vidin ) {
+ reset_frequency_menu( commands_get_menu( cmd, "frequencies" ),
+ videoinput_get_norm( cmd->vidin ), cmd->newfreqtable );
+ commands_refresh_menu( cmd );
+ }
+ break;
+
+ case TVTIME_SET_FRAMERATE:
+ if( !strcasecmp( arg, "full" ) ) {
+ cmd->framerate = FRAMERATE_FULL;
+ } else if( !strcasecmp( arg, "top" ) ) {
+ cmd->framerate = FRAMERATE_HALF_TFF;
+ } else {
+ cmd->framerate = FRAMERATE_HALF_BFF;
+ }
+ if( cmd->osd ) {
+ if( cmd->framerate == FRAMERATE_FULL ) {
+ tvtime_osd_show_message( cmd->osd,
+ _("Processing every input field.") );
+ } else if( cmd->framerate == FRAMERATE_HALF_TFF ) {
+ tvtime_osd_show_message( cmd->osd,
+ _("Processing every top field.") );
+ } else {
+ tvtime_osd_show_message( cmd->osd,
+ _("Processing every bottom field.") );
+ }
+ }
+ break;
+
+ case TVTIME_SET_INPUT_WIDTH:
+ cmd->newinputwidth = atoi( arg );
+ if( cmd->osd ) {
+ const char *curname = menu_get_name( cmd->curusermenu );
+ menu_t *sharpmenu = commands_get_menu( cmd, "hres" );
+ char message[ 128 ];
+ int maxw = cmd->vidin? videoinput_get_maxwidth( cmd->vidin ) : 0;
+ reset_inputwidth_menu( sharpmenu, cmd->newinputwidth, maxw );
+ curname = menu_get_name( cmd->curusermenu );
+ commands_refresh_menu( cmd );
+ snprintf( message, sizeof( message ),
+ _("Horizontal resolution will be %d pixels on restart."),
+ cmd->newinputwidth );
+ tvtime_osd_show_message( cmd->osd, message );
+ }
+ break;
+
+ case TVTIME_SET_FULLSCREEN_POSITION:
+ if( arg ) {
+ snprintf( cmd->newpos, sizeof( cmd->newpos ), "%s", arg );
+ }
+ break;
+
+ case TVTIME_SET_MATTE:
+ if( arg ) {
+ snprintf( cmd->newmatte, sizeof( cmd->newmatte ), "%s", arg );
+ }
+ break;
+
+ case TVTIME_SET_STATION:
+ if( arg ) {
+ if( isdigit( arg[ 0 ] ) ) {
+ station_set( cmd->stationmgr, atoi( arg ) );
+ } else {
+ station_set_by_name( cmd->stationmgr, arg );
+ }
+ cmd->change_channel = 1;
+ }
+ break;
+
+ case TVTIME_SET_NORM:
+ if( !arg || !*arg ) {
+ cmd->newnorm = "NTSC";
+ } else if( !strcasecmp( arg, "pal" ) ) {
+ cmd->newnorm = "PAL";
+ } else if( !strcasecmp( arg, "secam" ) ) {
+ cmd->newnorm = "SECAM";
+ } else if( !strcasecmp( arg, "pal-nc" ) ) {
+ cmd->newnorm = "PAL-Nc";
+ } else if( !strcasecmp( arg, "pal-m" ) ) {
+ cmd->newnorm = "PAL-M";
+ } else if( !strcasecmp( arg, "pal-n" ) ) {
+ cmd->newnorm = "PAL-N";
+ } else if( !strcasecmp( arg, "ntsc-jp" ) ) {
+ cmd->newnorm = "NTSC-JP";
+ } else if( !strcasecmp( arg, "pal-60" ) ) {
+ cmd->newnorm = "PAL-60";
+ } else {
+ cmd->newnorm = "NTSC";
+ }
+ cmd->normset = 1;
+
+ if( cmd->osd ) {
+ menu_t *normmenu = commands_get_menu( cmd, "norm" );
+ char message[ 128 ];
+ reset_norm_menu( normmenu, cmd->newnorm );
+ commands_refresh_menu( cmd );
+ snprintf( message, sizeof (message),
+ _("Television standard will be %s on restart."),
+ cmd->newnorm );
+ tvtime_osd_show_message( cmd->osd, message );
+ }
+ break;
+
+ case TVTIME_SET_XMLTV_LANGUAGE:
+ if( cmd->xmltv && arg ) {
+ if( isdigit( arg[ 0 ] ) ) {
+ xmltv_select_language( cmd->xmltv, atoi( arg ) );
+ } else if( !strcasecmp( arg, "none" ) ) {
+ xmltv_set_language( cmd->xmltv, 0 );
+ } else {
+ xmltv_set_language( cmd->xmltv, arg );
+ }
+ update_xmltv_listings( cmd );
+
+ if( cmd->osd ) {
+ char message[ 128 ];
+ menu_t *langmenu = commands_get_menu( cmd, "xmltv-language" );
+ int i = xmltv_get_langnum( cmd->xmltv );
+ const char *code = xmltv_get_language_code( cmd->xmltv, i );
+ const char *name = xmltv_get_language_name( cmd->xmltv, i );
+
+ reset_xmltv_languages_menu( langmenu, cmd->xmltv );
+ commands_refresh_menu( cmd );
+ if( !code ) {
+ snprintf( message, sizeof( message ),
+ _("Using default language for XMLTV data.") );
+ } else if( !name ) {
+ snprintf( message, sizeof( message ),
+ _("Using unknown language (%s) for XMLTV data."),
+ code );
+ } else {
+ snprintf( message, sizeof( message ),
+ _("XMLTV language set to %s (%s)."),
+ name, code );
+ }
+ tvtime_osd_show_message( cmd->osd, message );
+ }
+
+ config_save( cmd->cfg, "XMLTVLanguage", arg );
+ }
+ break;
+
+ case TVTIME_TOGGLE_ASPECT:
+ cmd->toggleaspect = 1;
+ break;
+
+ case TVTIME_TOGGLE_ALWAYSONTOP:
+ cmd->togglealwaysontop = 1;
+ break;
+
+ case TVTIME_CHANNEL_SAVE_TUNING:
+ if( cmd->vidin && videoinput_has_tuner( cmd->vidin ) ) {
+ char freq[ 32 ];
+ int pos;
+
+ snprintf( freq, sizeof( freq ), "%f", ((double) videoinput_get_tuner_freq( cmd->vidin )) / 1000.0 );
+ pos = station_add( cmd->stationmgr, 0, "Custom", freq, 0 );
+ station_writeconfig( cmd->stationmgr );
+ station_set( cmd->stationmgr, pos );
+ cmd->change_channel = 1;
+ }
+ break;
+
+ case TVTIME_CHANNEL_ACTIVATE_ALL:
+ if( cmd->vidin && videoinput_has_tuner( cmd->vidin ) ) {
+ if( cmd->osd ) {
+ tvtime_osd_show_message( cmd->osd,
+ _("All channels re-activated.") );
+ }
+ station_activate_all_channels( cmd->stationmgr );
+ station_writeconfig( cmd->stationmgr );
+ }
+ break;
+
+ case TVTIME_CHANNEL_RENUMBER:
+ if( cmd->vidin && videoinput_has_tuner( cmd->vidin ) ) {
+ /* If we're scanning and suddenly want to renumber, stop scanning. */
+ if( cmd->scan_channels ) {
+ commands_handle( cmd, TVTIME_CHANNEL_SCAN, 0 );
+ }
+
+ /* Accept input of the destination channel. */
+ if( cmd->digit_counter == 0 ) memset( cmd->next_chan_buffer, 0, 5 );
+ cmd->frame_counter = cmd->delay;
+ cmd->renumbering = 1;
+ if( cmd->osd ) {
+ char message[ 256 ];
+ snprintf( message, sizeof( message ),
+ _("Remapping %d. Enter new channel number."),
+ station_get_current_id( cmd->stationmgr ) );
+ tvtime_osd_set_hold_message( cmd->osd, message, 0 );
+ }
+ }
+ break;
+
+ case TVTIME_CHANNEL_SCAN:
+ if( cmd->vidin && videoinput_has_tuner( cmd->vidin ) ) {
+ if( !cmd->checkfreq ) {
+ if( cmd->osd ) {
+ tvtime_osd_show_message( cmd->osd,
+ _("Scanner unavailable with signal checking disabled.") );
+ }
+ } else {
+ cmd->scan_channels = !cmd->scan_channels;
+
+ if( cmd->scan_channels && cmd->renumbering ) {
+ memset( cmd->next_chan_buffer, 0, 5 );
+ cmd->digit_counter = 0;
+ cmd->frame_counter = 0;
+ if( cmd->osd ) tvtime_osd_set_hold_message( cmd->osd, "", 0 );
+ cmd->renumbering = 0;
+ }
+
+ if( cmd->osd ) {
+ reset_stations_menu( commands_get_menu( cmd, "stations" ),
+ (videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_NTSC ||
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_NTSC_JP),
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_PAL,
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_SECAM,
+ (!strcasecmp( cmd->newfreqtable, "us-cable" ) ||
+ !strcasecmp( cmd->newfreqtable, "us-cable100" )),
+ station_get_current_active( cmd->stationmgr ), cmd->checkfreq,
+ cmd->scan_channels,
+ videoinput_is_v4l2( cmd->vidin ),
+ station_get_default_audio_norm( cmd->stationmgr ),
+ station_get_current_audio_norm( cmd->stationmgr ) );
+ commands_refresh_menu( cmd );
+
+ if( cmd->scan_channels ) {
+ tvtime_osd_set_hold_message( cmd->osd,
+ _("Scanning for channels being broadcast."), 0 );
+ } else {
+ /* Nuke the hold message, and make sure we show nothing (hack). */
+ tvtime_osd_set_hold_message( cmd->osd, "", 0 );
+ tvtime_osd_show_message( cmd->osd, " " );
+ }
+ tvtime_osd_show_info( cmd->osd );
+ }
+ }
+ }
+ break;
+
+ case TVTIME_TOGGLE_CC:
+ if( cmd->vbi ) {
+ vbidata_capture_mode( cmd->vbi, cmd->capturemode ? CAPTURE_OFF : CAPTURE_CC1 );
+ if( cmd->capturemode ) {
+ if( cmd->osd ) {
+ tvtime_osd_show_message( cmd->osd,
+ _("Closed captions disabled.") );
+ }
+ cmd->capturemode = CAPTURE_OFF;
+ } else {
+ if( cmd->osd ) {
+ tvtime_osd_show_message( cmd->osd,
+ _("Closed captions enabled.") );
+ }
+ cmd->capturemode = CAPTURE_CC1;
+ }
+ if( cmd->capturemode ) {
+ config_save( cmd->cfg, "ShowCC", "1" );
+ } else {
+ config_save( cmd->cfg, "ShowCC", "0" );
+ }
+ } else {
+ if( cmd->osd ) {
+ tvtime_osd_show_message( cmd->osd,
+ _("No VBI device configured for CC decoding.") );
+ }
+ }
+ break;
+
+ case TVTIME_TOGGLE_PAL_SECAM:
+ videoinput_toggle_pal_secam( cmd->vidin );
+ if( videoinput_has_tuner( cmd->vidin ) ) {
+ station_set_current_norm( cmd->stationmgr, videoinput_get_norm_name( videoinput_get_norm( cmd->vidin ) ) );
+ station_writeconfig( cmd->stationmgr );
+ }
+ if( cmd->osd ) {
+ char message[ 128 ];
+ tvtime_osd_set_norm( cmd->osd, videoinput_get_norm_name( videoinput_get_norm( cmd->vidin ) ) );
+ tvtime_osd_show_info( cmd->osd );
+ snprintf( message, sizeof( message ),
+ _("Colour decoding for this channel set to %s."),
+ videoinput_get_norm_name( videoinput_get_norm( cmd->vidin ) ) );
+ tvtime_osd_show_message( cmd->osd, message );
+
+ reset_stations_menu( commands_get_menu( cmd, "stations" ),
+ (videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_NTSC ||
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_NTSC_JP),
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_PAL,
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_SECAM,
+ (!strcasecmp( cmd->newfreqtable, "us-cable" ) ||
+ !strcasecmp( cmd->newfreqtable, "us-cable100" )),
+ station_get_current_active( cmd->stationmgr ), cmd->checkfreq,
+ cmd->scan_channels,
+ videoinput_is_v4l2( cmd->vidin ),
+ station_get_default_audio_norm( cmd->stationmgr ),
+ station_get_current_audio_norm( cmd->stationmgr ) );
+ commands_refresh_menu( cmd );
+ }
+
+ break;
+
+ case TVTIME_DISPLAY_MESSAGE:
+ if( cmd->osd && arg ) tvtime_osd_show_message( cmd->osd, arg );
+ break;
+
+ case TVTIME_DISPLAY_INFO:
+ cmd->displayinfo = !cmd->displayinfo;
+ if( cmd->osd ) {
+ if( cmd->xmltv && cmd->vidin &&
+ videoinput_has_tuner( cmd->vidin ) ) {
+ update_xmltv_display( cmd );
+ }
+ if( cmd->displayinfo ) {
+ tvtime_osd_hold( cmd->osd, 1 );
+ tvtime_osd_show_info( cmd->osd );
+ } else {
+ tvtime_osd_hold( cmd->osd, 0 );
+ tvtime_osd_clear( cmd->osd );
+ }
+ }
+ break;
+
+ case TVTIME_RUN_COMMAND:
+ if( arg ) {
+ char commandline[ 256 ];
+ snprintf( commandline, sizeof (commandline), "%s &", arg );
+ if( cmd->osd ) {
+ char message[ 256 ];
+ snprintf( message, sizeof (message), _("Running: %s"), arg );
+ tvtime_osd_show_message( cmd->osd, message );
+ }
+ system( commandline );
+ }
+ break;
+
+ case TVTIME_TOGGLE_CREDITS:
+ break;
+
+ case TVTIME_SET_AUDIO_MODE:
+ if( cmd->vidin ) {
+ if( !strcasecmp( arg, "mono" ) ) {
+ videoinput_set_audio_mode( cmd->vidin, VIDEOINPUT_MONO );
+ } else if( !strcasecmp( arg, "stereo" ) ) {
+ videoinput_set_audio_mode( cmd->vidin, VIDEOINPUT_STEREO );
+ } else if( !strcasecmp( arg, "sap" ) || !strcasecmp( arg, "lang1" ) ) {
+ videoinput_set_audio_mode( cmd->vidin, VIDEOINPUT_LANG1 );
+ } else {
+ videoinput_set_audio_mode( cmd->vidin, VIDEOINPUT_LANG2 );
+ }
+ if( cmd->osd ) {
+ if( !cmd->menuactive ) {
+ osd_list_audio_modes( cmd->osd, videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_NTSC,
+ videoinput_get_audio_mode( cmd->vidin ) );
+ }
+ tvtime_osd_set_audio_mode( cmd->osd, videoinput_get_audio_mode_name( cmd->vidin, videoinput_get_audio_mode( cmd->vidin ) ) );
+ tvtime_osd_show_info( cmd->osd );
+ reset_audio_mode_menu( commands_get_menu( cmd, "audiomode" ),
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_NTSC,
+ videoinput_get_audio_mode( cmd->vidin ) );
+ commands_refresh_menu( cmd );
+ }
+ }
+ break;
+
+ case TVTIME_TOGGLE_AUDIO_MODE:
+ if( cmd->vidin ) {
+ videoinput_set_audio_mode( cmd->vidin, videoinput_get_audio_mode( cmd->vidin ) << 1 );
+ if( cmd->osd ) {
+ osd_list_audio_modes( cmd->osd, videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_NTSC,
+ videoinput_get_audio_mode( cmd->vidin ) );
+ tvtime_osd_set_audio_mode( cmd->osd, videoinput_get_audio_mode_name( cmd->vidin, videoinput_get_audio_mode( cmd->vidin ) ) );
+ tvtime_osd_show_info( cmd->osd );
+ reset_audio_mode_menu( commands_get_menu( cmd, "audiomode" ),
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_NTSC,
+ videoinput_get_audio_mode( cmd->vidin ) );
+ commands_refresh_menu( cmd );
+ }
+ }
+ break;
+
+ case TVTIME_TOGGLE_DEINTERLACER:
+ cmd->toggledeinterlacer = 1;
+ break;
+
+ case TVTIME_TOGGLE_PULLDOWN_DETECTION:
+ cmd->togglepulldowndetection = 1;
+ break;
+
+ case TVTIME_TOGGLE_SIGNAL_DETECTION:
+ cmd->checkfreq = !cmd->checkfreq;
+ if( !cmd->checkfreq && cmd->scan_channels ) {
+ commands_handle( cmd, TVTIME_CHANNEL_SCAN, 0 );
+ }
+ if( cmd->osd ) {
+ reset_stations_menu( commands_get_menu( cmd, "stations" ),
+ (videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_NTSC ||
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_NTSC_JP),
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_PAL,
+ videoinput_get_norm( cmd->vidin ) == VIDEOINPUT_SECAM,
+ (!strcasecmp( cmd->newfreqtable, "us-cable" ) ||
+ !strcasecmp( cmd->newfreqtable, "us-cable100" )),
+ station_get_current_active( cmd->stationmgr ), cmd->checkfreq,
+ cmd->scan_channels,
+ videoinput_is_v4l2( cmd->vidin ),
+ station_get_default_audio_norm( cmd->stationmgr ),
+ station_get_current_audio_norm( cmd->stationmgr ) );
+ if( cmd->checkfreq ) {
+ tvtime_osd_show_message( cmd->osd,
+ _("Signal detection enabled.") );
+ } else {
+ tvtime_osd_show_message( cmd->osd,
+ _("Signal detection disabled.") );
+ }
+ commands_refresh_menu( cmd );
+ }
+ break;
+
+ case TVTIME_TOGGLE_XDS:
+ if( cmd->vidin && videoinput_get_height( cmd->vidin ) == 480 && cmd->vbi ) {
+ cmd->usexds = !cmd->usexds;
+ vbidata_capture_xds( cmd->vbi, cmd->usexds );
+ if( cmd->osd ) {
+ if( cmd->usexds ) {
+ tvtime_osd_show_message( cmd->osd,
+ _("XDS decoding enabled.") );
+ } else {
+ tvtime_osd_show_message( cmd->osd,
+ _("XDS decoding disabled.") );
+ }
+ }
+ }
+ break;
+
+ case TVTIME_CHANNEL_CHAR:
+ if( arg && isdigit( arg[ 0 ] ) && cmd->vidin && videoinput_has_tuner( cmd->vidin ) ) {
+
+ /* If we're scanning and the user hits a key, stop scanning. */
+ if( cmd->scan_channels ) {
+ commands_handle( cmd, TVTIME_CHANNEL_SCAN, 0 );
+ }
+
+ /* Decode the input char from commands. */
+ if( cmd->digit_counter == 0 ) memset( cmd->next_chan_buffer, 0, 5 );
+ cmd->next_chan_buffer[ cmd->digit_counter ] = arg[ 0 ];
+ cmd->digit_counter++;
+ cmd->frame_counter = cmd->delay;
+
+ /**
+ * Send an enter command if we type more
+ * digits than there are channels.
+ */
+ if( cmd->digit_counter > 0 && (station_get_max_position( cmd->stationmgr ) < 10) ) {
+ commands_handle( cmd, TVTIME_ENTER, 0 );
+ } else if( cmd->digit_counter > 1 && (station_get_max_position( cmd->stationmgr ) < 100) ) {
+ commands_handle( cmd, TVTIME_ENTER, 0 );
+ } else if( cmd->digit_counter > 2 ) {
+ commands_handle( cmd, TVTIME_ENTER, 0 );
+ }
+ }
+ break;
+
+ case TVTIME_TOGGLE_COLOUR_INVERT:
+ cmd->apply_invert = !cmd->apply_invert;
+ if( cmd->osd ) {
+ reset_filters_menu( commands_get_menu( cmd, "filters" ),
+ cmd->apply_invert, cmd->apply_mirror,
+ cmd->apply_chroma_kill,
+ cmd->vidin && videoinput_get_height( cmd->vidin ) == 480,
+ cmd->pulldown_alg );
+ commands_refresh_menu( cmd );
+
+ if( cmd->apply_invert ) {
+ tvtime_osd_show_message( cmd->osd, _("Colour invert enabled.") );
+ } else {
+ tvtime_osd_show_message( cmd->osd, _("Colour invert disabled.") );
+ }
+ }
+ if( cmd->apply_invert ) {
+ config_save( cmd->cfg, "ColourInvert", "1" );
+ } else {
+ config_save( cmd->cfg, "ColourInvert", "0" );
+ }
+ break;
+
+ case TVTIME_TOGGLE_MIRROR:
+ cmd->apply_mirror = !cmd->apply_mirror;
+ if( cmd->osd ) {
+ reset_filters_menu( commands_get_menu( cmd, "filters" ),
+ cmd->apply_invert, cmd->apply_mirror,
+ cmd->apply_chroma_kill,
+ cmd->vidin && videoinput_get_height( cmd->vidin ) == 480,
+ cmd->pulldown_alg );
+ commands_refresh_menu( cmd );
+
+ if( cmd->apply_mirror ) {
+ tvtime_osd_show_message( cmd->osd, _("Mirror enabled.") );
+ } else {
+ tvtime_osd_show_message( cmd->osd, _("Mirror disabled.") );
+ }
+ }
+ if( cmd->apply_mirror ) {
+ config_save( cmd->cfg, "MirrorInput", "1" );
+ } else {
+ config_save( cmd->cfg, "MirrorInput", "0" );
+ }
+ break;
+
+ case TVTIME_TOGGLE_CHROMA_KILL:
+ cmd->apply_chroma_kill = !cmd->apply_chroma_kill;
+ if( cmd->osd ) {
+ reset_filters_menu( commands_get_menu( cmd, "filters" ),
+ cmd->apply_invert, cmd->apply_mirror,
+ cmd->apply_chroma_kill,
+ cmd->vidin && videoinput_get_height( cmd->vidin ) == 480,
+ cmd->pulldown_alg );
+ commands_refresh_menu( cmd );
+
+ if( cmd->apply_chroma_kill ) {
+ tvtime_osd_show_message( cmd->osd, _("Chroma kill enabled.") );
+ } else {
+ tvtime_osd_show_message( cmd->osd, _("Chroma kill disabled.") );
+ }
+ }
+ break;
+
+ case TVTIME_OVERSCAN_UP:
+ case TVTIME_OVERSCAN_DOWN:
+ cmd->overscan = cmd->overscan + ( (tvtime_cmd == TVTIME_OVERSCAN_UP) ? 0.0025 : -0.0025 );
+ if( cmd->overscan > 0.4 ) cmd->overscan = 0.4; if( cmd->overscan < 0.0 ) cmd->overscan = 0.0;
+
+ if( cmd->osd ) {
+ char message[ 200 ];
+ snprintf( message, sizeof( message ), _("Overscan: %.1f%%"),
+ cmd->overscan * 2.0 * 100.0 );
+ tvtime_osd_show_message( cmd->osd, message );
+ reset_overscan_menu( commands_get_menu( cmd, "overscan" ), cmd->overscan );
+ commands_refresh_menu( cmd );
+ }
+ break;
+
+ case TVTIME_AUTO_ADJUST_PICT:
+ if( cmd->vidin ) {
+ if( cmd->brightness >= 0 ) {
+ videoinput_set_brightness( cmd->vidin, cmd->brightness );
+ } else {
+ videoinput_set_brightness( cmd->vidin, 50 );
+ }
+ if( cmd->contrast >= 0 ) {
+ videoinput_set_contrast( cmd->vidin, cmd->contrast );
+ } else {
+ videoinput_set_contrast( cmd->vidin, 50 );
+ }
+ if( cmd->saturation >= 0 ) {
+ videoinput_set_saturation( cmd->vidin, cmd->saturation );
+ } else {
+ videoinput_set_saturation( cmd->vidin, 50 );
+ }
+ if( cmd->hue >= 0 ) {
+ videoinput_set_hue( cmd->vidin, cmd->hue );
+ } else {
+ videoinput_set_hue( cmd->vidin, 50 );
+ }
+ if( cmd->osd ) {
+ tvtime_osd_show_message( cmd->osd,
+ _("Picture settings reset to defaults.") );
+ menu_set_value( commands_get_menu( cmd, "brightness" ),
+ videoinput_get_brightness( cmd->vidin ),
+ TVTIME_ICON_BRIGHTNESS );
+ menu_set_value( commands_get_menu( cmd, "contrast" ),
+ videoinput_get_brightness( cmd->vidin ),
+ TVTIME_ICON_CONTRAST );
+ menu_set_value( commands_get_menu( cmd, "saturation" ),
+ videoinput_get_brightness( cmd->vidin ),
+ TVTIME_ICON_SATURATION );
+ menu_set_value( commands_get_menu( cmd, "hue" ),
+ videoinput_get_brightness( cmd->vidin ),
+ TVTIME_ICON_HUE );
+ }
+ }
+ break;
+
+ case TVTIME_AUTO_ADJUST_WINDOW:
+ cmd->resizewindow = 1;
+ break;
+
+ case TVTIME_TOGGLE_NTSC_CABLE_MODE:
+ if( cmd->vidin && videoinput_has_tuner( cmd->vidin ) ) {
+ station_toggle_us_cable_mode( cmd->stationmgr );
+ if( station_get_us_cable_mode( cmd->stationmgr ) == NTSC_CABLE_MODE_STANDARD ) {
+ config_save( cmd->cfg, "NTSCCableMode", "Nominal" );
+ if( cmd->osd ) {
+ tvtime_osd_show_message( cmd->osd,
+ _("Using nominal NTSC cable frequencies.") );
+ }
+ } else if( station_get_us_cable_mode( cmd->stationmgr ) == NTSC_CABLE_MODE_IRC ) {
+ config_save( cmd->cfg, "NTSCCableMode", "IRC" );
+ if( cmd->osd ) {
+ tvtime_osd_show_message( cmd->osd,
+ _("Using IRC cable frequencies.") );
+ }
+ } else if( station_get_us_cable_mode( cmd->stationmgr ) == NTSC_CABLE_MODE_HRC ) {
+ config_save( cmd->cfg, "NTSCCableMode", "HRC" );
+ if( cmd->osd ) {
+ tvtime_osd_show_message( cmd->osd,
+ _("Using HRC cable frequencies.") );
+ }
+ }
+ cmd->change_channel = 1;
+ }
+ break;
+
+ case TVTIME_FINETUNE_DOWN:
+ case TVTIME_FINETUNE_UP:
+ if( cmd->vidin && videoinput_has_tuner( cmd->vidin ) ) {
+ station_set_current_finetune( cmd->stationmgr, station_get_current_finetune( cmd->stationmgr )
+ + (tvtime_cmd == TVTIME_FINETUNE_UP ? 1 : -1) );
+ videoinput_set_tuner_freq( cmd->vidin, station_get_current_frequency( cmd->stationmgr )
+ + ((station_get_current_finetune( cmd->stationmgr ) * 1000)/16) );
+
+ if( cmd->vbi ) {
+ vbidata_reset( cmd->vbi );
+ vbidata_capture_mode( cmd->vbi, cmd->capturemode );
+ }
+
+ if( cmd->osd ) {
+ menu_set_value (commands_get_menu (cmd, "finetune"),
+ station_get_current_finetune (cmd->stationmgr),
+ TVTIME_ICON_FINETUNECHANNEL);
+ commands_refresh_menu( cmd );
+ tvtime_osd_show_data_bar_centered( cmd->osd, _("Finetune"),
+ station_get_current_finetune( cmd->stationmgr ) );
+ }
+ } else if( cmd->osd ) {
+ tvtime_osd_show_info( cmd->osd );
+ }
+ break;
+
+ case TVTIME_CHANNEL_INC:
+ if( cmd->vidin && videoinput_has_tuner( cmd->vidin ) ) {
+
+ /**
+ * If we're scanning and the user hits a key, stop scanning.
+ * arg will be 0 if the scanner has called us.
+ */
+ if( cmd->scan_channels && arg ) {
+ commands_handle( cmd, TVTIME_CHANNEL_SCAN, 0 );
+ }
+
+ station_inc( cmd->stationmgr );
+ cmd->change_channel = 1;
+ } else if( cmd->osd ) {
+ tvtime_osd_show_info( cmd->osd );
+ }
+ break;
+ case TVTIME_CHANNEL_DEC:
+ if( cmd->vidin && videoinput_has_tuner( cmd->vidin ) ) {
+
+ /* If we're scanning and the user hits a key, stop scanning. */
+ if( cmd->scan_channels ) {
+ commands_handle( cmd, TVTIME_CHANNEL_SCAN, 0 );
+ }
+
+ station_dec( cmd->stationmgr );
+ cmd->change_channel = 1;
+ } else if( cmd->osd ) {
+ tvtime_osd_show_info( cmd->osd );
+ }
+ break;
+
+ case TVTIME_CHANNEL_PREV:
+ if( cmd->vidin && videoinput_has_tuner( cmd->vidin ) ) {
+
+ /* If we're scanning and the user hits a key, stop scanning. */
+ if( cmd->scan_channels ) {
+ commands_handle( cmd, TVTIME_CHANNEL_SCAN, 0 );
+ }
+
+ station_prev( cmd->stationmgr );
+ cmd->change_channel = 1;
+ } else if( cmd->osd ) {
+ tvtime_osd_show_info( cmd->osd );
+ }
+ break;
+
+ case TVTIME_MIXER_TOGGLE_MUTE:
+ mixer->mute( !mixer->ismute() );
+
+ if( cmd->osd ) {
+ tvtime_osd_show_data_bar( cmd->osd, _("Volume"), (mixer->get_volume()) & 0xff );
+ }
+ break;
+
+ case TVTIME_MIXER_UP:
+ case TVTIME_MIXER_DOWN:
+
+ /* If the user hits the volume control, drop us out of mute mode. */
+ if( cmd->vidin && videoinput_get_muted( cmd->vidin ) ) {
+ commands_handle( cmd, TVTIME_TOGGLE_MUTE, 0 );
+ }
+ /* Check to see if an argument was passed, if so, use it. */
+ if (atoi(arg) > 0) {
+ int perc = atoi(arg);
+ volume = mixer->set_volume( ( (tvtime_cmd == TVTIME_MIXER_UP) ? perc : -perc ) );
+ } else {
+ volume = mixer->set_volume( ( (tvtime_cmd == TVTIME_MIXER_UP) ? 1 : -1 ) );
+ }
+
+ if( cmd->osd ) {
+ tvtime_osd_show_data_bar( cmd->osd, _("Volume"), volume & 0xff );
+ }
+ break;
+
+ case TVTIME_TOGGLE_MUTE:
+ if( cmd->vidin ) {
+ videoinput_mute( cmd->vidin, !videoinput_get_muted( cmd->vidin ) );
+ if( cmd->osd ) {
+ tvtime_osd_volume_muted( cmd->osd, videoinput_get_muted( cmd->vidin ) );
+ }
+ }
+ break;
+
+ case TVTIME_TOGGLE_INPUT:
+ if( cmd->vidin ) {
+ cmd->frame_counter = 0;
+
+ if( cmd->renumbering ) {
+ memset( cmd->next_chan_buffer, 0, sizeof( cmd->next_chan_buffer ) );
+ commands_handle( cmd, TVTIME_ENTER, 0 );
+ }
+
+ if( cmd->scan_channels ) {
+ commands_handle( cmd, TVTIME_CHANNEL_SCAN, 0 );
+ }
+
+ videoinput_set_input_num( cmd->vidin, ( videoinput_get_input_num( cmd->vidin ) + 1 ) % videoinput_get_num_inputs( cmd->vidin ) );
+ reinit_tuner( cmd );
+
+ if( cmd->osd ) {
+ char string[ 128 ];
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_VIDEOINPUT " %s: %s",
+ _("Change video source"),
+ videoinput_get_input_name( cmd->vidin ) );
+ menu_set_text( commands_get_menu( cmd, "input" ), 1, string );
+ commands_refresh_menu( cmd );
+ tvtime_osd_set_input( cmd->osd, videoinput_get_input_name( cmd->vidin ) );
+ tvtime_osd_show_info( cmd->osd );
+ }
+ }
+ break;
+
+ case TVTIME_SET_INPUT:
+ if( cmd->vidin ) {
+ cmd->frame_counter = 0;
+
+ if( cmd->renumbering ) {
+ memset( cmd->next_chan_buffer, 0, sizeof( cmd->next_chan_buffer ) );
+ commands_handle( cmd, TVTIME_ENTER, 0 );
+ }
+
+ if( cmd->scan_channels ) {
+ commands_handle( cmd, TVTIME_CHANNEL_SCAN, 0 );
+ }
+
+ videoinput_set_input_num( cmd->vidin, atoi( arg ) % videoinput_get_num_inputs( cmd->vidin ) );
+ reinit_tuner( cmd );
+
+ if( cmd->osd ) {
+ char string[ 128 ];
+ snprintf( string, sizeof( string ),
+ TVTIME_ICON_VIDEOINPUT " %s: %s",
+ _("Change video source"),
+ videoinput_get_input_name( cmd->vidin ) );
+ menu_set_text( commands_get_menu( cmd, "input" ), 1, string );
+ commands_refresh_menu( cmd );
+ tvtime_osd_set_input( cmd->osd, videoinput_get_input_name( cmd->vidin ) );
+ tvtime_osd_show_info( cmd->osd );
+ }
+ }
+ break;
+
+ case TVTIME_HUE_UP:
+ case TVTIME_HUE_DOWN:
+ if( cmd->vidin ) {
+ videoinput_set_hue_relative( cmd->vidin, (tvtime_cmd == TVTIME_HUE_UP) ? 1 : -1 );
+ if( cmd->osd ) {
+ int hue = videoinput_get_hue( cmd->vidin );
+ tvtime_osd_show_data_bar( cmd->osd, _("Hue"), hue );
+ menu_set_value (commands_get_menu (cmd, "hue"), hue,
+ TVTIME_ICON_HUE);
+ commands_refresh_menu( cmd );
+ }
+ }
+ break;
+
+ case TVTIME_BRIGHTNESS_UP:
+ case TVTIME_BRIGHTNESS_DOWN:
+ if( cmd->vidin ) {
+ videoinput_set_brightness_relative( cmd->vidin, (tvtime_cmd == TVTIME_BRIGHTNESS_UP) ? 1 : -1 );
+ if( cmd->osd ) {
+ int brightness = videoinput_get_brightness( cmd->vidin );
+ tvtime_osd_show_data_bar( cmd->osd, _("Brightness"), brightness );
+ menu_set_value (commands_get_menu (cmd, "brightness"),
+ brightness, TVTIME_ICON_BRIGHTNESS);
+ commands_refresh_menu( cmd );
+ }
+ }
+ break;
+
+ case TVTIME_CONTRAST_UP:
+ case TVTIME_CONTRAST_DOWN:
+ if( cmd->vidin ) {
+ videoinput_set_contrast_relative( cmd->vidin, (tvtime_cmd == TVTIME_CONTRAST_UP) ? 1 : -1 );
+ if( cmd->osd ) {
+ int contrast = videoinput_get_contrast( cmd->vidin );
+ tvtime_osd_show_data_bar( cmd->osd, _("Contrast"), contrast );
+ menu_set_value (commands_get_menu (cmd, "contrast"),
+ contrast, TVTIME_ICON_CONTRAST);
+ commands_refresh_menu( cmd );
+ }
+ }
+ break;
+
+ case TVTIME_SATURATION_UP:
+ case TVTIME_SATURATION_DOWN:
+ if( cmd->vidin ) {
+ videoinput_set_saturation_relative( cmd->vidin, (tvtime_cmd == TVTIME_SATURATION_UP) ? 1 : -1 );
+ if( cmd->osd ) {
+ int saturation = videoinput_get_saturation( cmd->vidin );
+ tvtime_osd_show_data_bar( cmd->osd, _("Saturation"), saturation );
+ menu_set_value (commands_get_menu (cmd, "saturation"),
+ saturation, TVTIME_ICON_SATURATION);
+ commands_refresh_menu( cmd );
+ }
+ }
+ break;
+
+ case TVTIME_PICTURE:
+ cmd->picturemode = (cmd->picturemode + 1) % 4;
+ if( cmd->osd && cmd->vidin ) {
+ if( cmd->picturemode == 0 ) {
+ int cur = videoinput_get_brightness( cmd->vidin );
+ tvtime_osd_show_data_bar( cmd->osd, _("Brightness"), cur );
+ } else if( cmd->picturemode == 1 ) {
+ int cur = videoinput_get_contrast( cmd->vidin );
+ tvtime_osd_show_data_bar( cmd->osd, _("Contrast"), cur );
+ } else if( cmd->picturemode == 2 ) {
+ int cur = videoinput_get_saturation( cmd->vidin );
+ tvtime_osd_show_data_bar( cmd->osd, _("Saturation"), cur );
+ } else if( cmd->picturemode == 3 ) {
+ int cur = videoinput_get_hue( cmd->vidin );
+ tvtime_osd_show_data_bar( cmd->osd, _("Hue"), cur );
+ }
+ }
+ break;
+
+ case TVTIME_PICTURE_UP:
+ if( cmd->picturemode == 0 ) {
+ commands_handle( cmd, TVTIME_BRIGHTNESS_UP, "" );
+ } else if( cmd->picturemode == 1 ) {
+ commands_handle( cmd, TVTIME_CONTRAST_UP, "" );
+ } else if( cmd->picturemode == 2 ) {
+ commands_handle( cmd, TVTIME_SATURATION_UP, "" );
+ } else if( cmd->picturemode == 3 ) {
+ commands_handle( cmd, TVTIME_HUE_UP, "" );
+ }
+ break;
+
+ case TVTIME_PICTURE_DOWN:
+ if( cmd->picturemode == 0 ) {
+ commands_handle( cmd, TVTIME_BRIGHTNESS_DOWN, "" );
+ } else if( cmd->picturemode == 1 ) {
+ commands_handle( cmd, TVTIME_CONTRAST_DOWN, "" );
+ } else if( cmd->picturemode == 2 ) {
+ commands_handle( cmd, TVTIME_SATURATION_DOWN, "" );
+ } else if( cmd->picturemode == 3 ) {
+ commands_handle( cmd, TVTIME_HUE_DOWN, "" );
+ }
+ break;
+
+ case TVTIME_SAVE_PICTURE_GLOBAL:
+ if( cmd->vidin && config_get_save_restore_picture( cmd->cfg ) ) {
+ cmd->brightness = videoinput_get_brightness( cmd->vidin );
+ cmd->contrast = videoinput_get_contrast( cmd->vidin );
+ cmd->saturation = videoinput_get_saturation( cmd->vidin );
+ cmd->hue = videoinput_get_hue( cmd->vidin );
+ if( cmd->osd ) {
+ tvtime_osd_show_message( cmd->osd,
+ _("Saved current picture settings as global defaults.\n") );
+ }
+ }
+ break;
+ case TVTIME_SAVE_PICTURE_CHANNEL:
+ if( cmd->stationmgr && cmd->vidin && config_get_save_restore_picture( cmd->cfg ) ) {
+ station_set_current_brightness( cmd->stationmgr, videoinput_get_brightness( cmd->vidin ) );
+ station_set_current_contrast( cmd->stationmgr, videoinput_get_contrast( cmd->vidin ) );
+ station_set_current_saturation( cmd->stationmgr, videoinput_get_saturation( cmd->vidin ) );
+ station_set_current_hue( cmd->stationmgr, videoinput_get_hue( cmd->vidin ) );
+ if( cmd->osd ) {
+ char message[ 128 ];
+ snprintf( message, sizeof (message),
+ _("Saved current picture settings on channel %d.\n"),
+ station_get_current_id( cmd->stationmgr ) );
+ tvtime_osd_show_message( cmd->osd, message );
+ }
+ }
+ break;
+
+ case TVTIME_ENTER:
+ if( cmd->next_chan_buffer[ 0 ] ) {
+ if( cmd->renumbering ) {
+ station_remap( cmd->stationmgr, atoi( cmd->next_chan_buffer ) );
+ station_writeconfig( cmd->stationmgr );
+ cmd->renumbering = 0;
+ if( cmd->osd ) tvtime_osd_set_hold_message( cmd->osd, "", 0 );
+ }
+ if( station_set( cmd->stationmgr, atoi( cmd->next_chan_buffer ) ) ) {
+ cmd->change_channel = 1;
+ } else {
+ snprintf( cmd->next_chan_buffer, sizeof( cmd->next_chan_buffer ),
+ "%d", station_get_current_id( cmd->stationmgr ) );
+ if( cmd->osd ) {
+ tvtime_osd_set_channel_number( cmd->osd, cmd->next_chan_buffer );
+ tvtime_osd_show_info( cmd->osd );
+ }
+ }
+ } else {
+ if( cmd->renumbering ) {
+ cmd->renumbering = 0;
+ if( cmd->osd ) tvtime_osd_set_hold_message( cmd->osd, "", 0 );
+ }
+ snprintf( cmd->next_chan_buffer, sizeof( cmd->next_chan_buffer ),
+ "%d", station_get_current_id( cmd->stationmgr ) );
+ if( cmd->osd ) {
+ if( cmd->vidin && videoinput_has_tuner( cmd->vidin ) ) {
+ tvtime_osd_set_channel_number( cmd->osd,
+ cmd->next_chan_buffer );
+ }
+ commands_handle( cmd, TVTIME_DISPLAY_INFO, "" );
+ }
+ }
+ cmd->frame_counter = 0;
+ break;
+
+ case TVTIME_CHANNEL_1:
+ commands_handle( cmd, TVTIME_CHANNEL_CHAR, "1" );
+ break;
+
+ case TVTIME_CHANNEL_2:
+ commands_handle( cmd, TVTIME_CHANNEL_CHAR, "2" );
+ break;
+
+ case TVTIME_CHANNEL_3:
+ commands_handle( cmd, TVTIME_CHANNEL_CHAR, "3" );
+ break;
+
+ case TVTIME_CHANNEL_4:
+ commands_handle( cmd, TVTIME_CHANNEL_CHAR, "4" );
+ break;
+
+ case TVTIME_CHANNEL_5:
+ commands_handle( cmd, TVTIME_CHANNEL_CHAR, "5" );
+ break;
+
+ case TVTIME_CHANNEL_6:
+ commands_handle( cmd, TVTIME_CHANNEL_CHAR, "6" );
+ break;
+
+ case TVTIME_CHANNEL_7:
+ commands_handle( cmd, TVTIME_CHANNEL_CHAR, "7" );
+ break;
+
+ case TVTIME_CHANNEL_8:
+ commands_handle( cmd, TVTIME_CHANNEL_CHAR, "8" );
+ break;
+
+ case TVTIME_CHANNEL_9:
+ commands_handle( cmd, TVTIME_CHANNEL_CHAR, "9" );
+ break;
+
+ case TVTIME_CHANNEL_0:
+ commands_handle( cmd, TVTIME_CHANNEL_CHAR, "0" );
+ break;
+
+ case TVTIME_TOGGLE_PAUSE:
+ cmd->pause = !(cmd->pause);
+ if( cmd->osd ) {
+ tvtime_osd_show_message( cmd->osd,
+ cmd->pause ? _("Paused.") : _("Resumed.") );
+ }
+ break;
+
+ case TVTIME_TOGGLE_MATTE:
+ cmd->togglematte = 1;
+ break;
+
+ case TVTIME_TOGGLE_QUIET_SCREENSHOTS:
+ cmd->togglequiet = 1;
+ break;
+
+ case TVTIME_TOGGLE_XMLTV_LANGUAGE:
+ if( cmd->xmltv ) {
+ const char *lang;
+ int i = xmltv_get_langnum( cmd->xmltv ) + 1;
+ if( i > xmltv_get_num_languages( cmd->xmltv ) ) i = 0;
+ xmltv_select_language( cmd->xmltv, i );
+ update_xmltv_listings( cmd );
+ if( cmd->osd ) {
+ menu_t *langmenu = commands_get_menu( cmd, "xmltv-language" );
+ reset_xmltv_languages_menu( langmenu, cmd->xmltv );
+ if( !cmd->menuactive ) {
+ osd_list_xmltv_languages( cmd->osd, cmd );
+ } else {
+ commands_refresh_menu( cmd );
+ }
+ }
+ if( cmd->osd && !cmd->menuactive ) {
+ osd_list_xmltv_languages( cmd->osd, cmd );
+ }
+ lang = xmltv_get_language( cmd->xmltv );
+ config_save( cmd->cfg, "XMLTVLanguage", lang? lang : "none" );
+ }
+ break;
+ }
+}
+
+void commands_next_frame( commands_t *cmd )
+{
+ cmd->tunerreset = 0;
+
+ /* Decrement the frame counter if user is typing digits */
+ if( cmd->frame_counter > 0 ) {
+ cmd->frame_counter--;
+ if( cmd->frame_counter == 0 ) {
+ /* Switch to the next channel if the countdown expires. */
+ commands_handle( cmd, TVTIME_ENTER, 0 );
+ }
+ }
+
+ if( cmd->frame_counter == 0 ) {
+ memset( cmd->next_chan_buffer, 0, 5 );
+ cmd->digit_counter = 0;
+ if( cmd->renumbering ) {
+ if( cmd->osd ) tvtime_osd_set_hold_message( cmd->osd, "", 0 );
+ cmd->renumbering = 0;
+ }
+ }
+
+ if( cmd->frame_counter > 0 && !(cmd->frame_counter % 5)) {
+ char input_text[6];
+
+ strcpy( input_text, cmd->next_chan_buffer );
+ if( !(cmd->frame_counter % 10) ) {
+ strcat( input_text, "_" );
+ } else {
+ strcat( input_text, " " );
+ }
+ if( cmd->osd ) {
+ tvtime_osd_set_channel_number( cmd->osd, input_text );
+ tvtime_osd_show_info( cmd->osd );
+ }
+ }
+
+ if( cmd->change_channel ) {
+ char number[ 6 ];
+ reinit_tuner( cmd );
+ cmd->change_channel = 0;
+ snprintf( number, 4, "%d",
+ station_get_current_id( cmd->stationmgr ) );
+ config_save( cmd->cfg, "Channel", number );
+ }
+
+ cmd->xmltvupdated = 0;
+ update_xmltv_listings( cmd );
+ if( cmd->vbi ) {
+ if( *(vbidata_get_network_name( cmd->vbi )) ) {
+ /* If the network name has changed, save it to the config file. */
+ if( strcmp( station_get_current_network_name( cmd->stationmgr ),
+ vbidata_get_network_name( cmd->vbi ) ) ) {
+ station_set_current_network_name( cmd->stationmgr,
+ vbidata_get_network_name( cmd->vbi ) );
+ station_writeconfig( cmd->stationmgr );
+ }
+
+ if( cmd->osd ) {
+ tvtime_osd_set_network_name( cmd->osd, station_get_current_network_name( cmd->stationmgr ) );
+ }
+ }
+
+ if( *(vbidata_get_network_call_letters( cmd->vbi )) ) {
+ /* If the call letters have changed, save them to the config file. */
+ if( strcmp( station_get_current_network_call_letters( cmd->stationmgr ),
+ vbidata_get_network_call_letters( cmd->vbi ) ) ) {
+ station_set_current_network_call_letters( cmd->stationmgr,
+ vbidata_get_network_call_letters( cmd->vbi ) );
+ station_writeconfig( cmd->stationmgr );
+ }
+
+ if( cmd->osd ) {
+ tvtime_osd_set_network_call( cmd->osd, station_get_current_network_call_letters( cmd->stationmgr ) );
+ }
+ }
+
+ if( cmd->osd ) {
+ tvtime_osd_set_show_name( cmd->osd, vbidata_get_program_name( cmd->vbi ) );
+ tvtime_osd_set_show_rating( cmd->osd, vbidata_get_program_rating( cmd->vbi ) );
+ tvtime_osd_set_show_start( cmd->osd, vbidata_get_program_start_time( cmd->vbi ) );
+ tvtime_osd_set_show_length( cmd->osd, vbidata_get_program_length( cmd->vbi ) );
+ }
+ }
+
+ cmd->printdebug = 0;
+ cmd->showdeinterlacerinfo = 0;
+ cmd->screenshot = 0;
+ cmd->togglefullscreen = 0;
+ cmd->toggleaspect = 0;
+ cmd->togglealwaysontop = 0;
+ cmd->toggledeinterlacer = 0;
+ cmd->togglepulldowndetection = 0;
+ cmd->togglematte = 0;
+ cmd->togglequiet = 0;
+ cmd->resizewindow = 0;
+ cmd->setdeinterlacer = 0;
+ cmd->setfreqtable = 0;
+ memset( cmd->newmatte, 0, sizeof( cmd->newmatte ) );
+ memset( cmd->newpos, 0, sizeof( cmd->newpos ) );
+}
+
+int commands_quit( commands_t *cmd )
+{
+ return cmd->quit;
+}
+
+int commands_print_debug( commands_t *cmd )
+{
+ return cmd->printdebug;
+}
+
+int commands_show_bars( commands_t *cmd )
+{
+ return cmd->showbars;
+}
+
+int commands_take_screenshot( commands_t *cmd )
+{
+ return cmd->screenshot;
+}
+
+const char *commands_screenshot_filename( commands_t *cmd )
+{
+ return cmd->screenshotfile;
+}
+
+int commands_toggle_fullscreen( commands_t *cmd )
+{
+ return cmd->togglefullscreen;
+}
+
+int commands_get_framerate( commands_t *cmd )
+{
+ return cmd->framerate;
+}
+
+int commands_toggle_aspect( commands_t *cmd )
+{
+ return cmd->toggleaspect;
+}
+
+int commands_toggle_alwaysontop( commands_t *cmd )
+{
+ return cmd->togglealwaysontop;
+}
+
+int commands_toggle_deinterlacer( commands_t *cmd )
+{
+ return cmd->toggledeinterlacer;
+}
+
+int commands_toggle_pulldown_detection( commands_t *cmd )
+{
+ return cmd->togglepulldowndetection;
+}
+
+int commands_toggle_matte( commands_t *cmd )
+{
+ return cmd->togglematte;
+}
+
+int commands_toggle_quiet_screenshots( commands_t *cmd )
+{
+ return cmd->togglequiet;
+}
+
+void commands_set_vbidata( commands_t *cmd, vbidata_t *vbi )
+{
+ cmd->vbi = vbi;
+}
+
+int commands_scan_channels( commands_t *cmd )
+{
+ return cmd->scan_channels;
+}
+
+int commands_pause( commands_t *cmd )
+{
+ return cmd->pause;
+}
+
+int commands_apply_colour_invert( commands_t *cmd )
+{
+ return cmd->apply_invert;
+}
+
+int commands_apply_mirror( commands_t *cmd )
+{
+ return cmd->apply_mirror;
+}
+
+int commands_apply_chroma_kill( commands_t *cmd )
+{
+ return cmd->apply_chroma_kill;
+}
+
+double commands_get_overscan( commands_t *cmd )
+{
+ return cmd->overscan;
+}
+
+int commands_resize_window( commands_t *cmd )
+{
+ return cmd->resizewindow;
+}
+
+void commands_set_framerate( commands_t *cmd, int framerate )
+{
+ cmd->framerate = framerate % FRAMERATE_MAX;
+}
+
+int commands_show_deinterlacer_info( commands_t *cmd )
+{
+ return cmd->showdeinterlacerinfo;
+}
+
+int commands_restart_tvtime( commands_t *cmd )
+{
+ return cmd->restarttvtime;
+}
+
+const char *commands_get_new_norm( commands_t *cmd )
+{
+ if( cmd->normset ) {
+ return cmd->newnorm;
+ } else {
+ return 0;
+ }
+}
+
+int commands_set_deinterlacer( commands_t *cmd )
+{
+ return cmd->setdeinterlacer;
+}
+
+const char *commands_get_new_deinterlacer( commands_t *cmd )
+{
+ return cmd->deinterlacer;
+}
+
+int commands_menu_active( commands_t *cmd )
+{
+ return cmd->menuactive;
+}
+
+void commands_set_half_size( commands_t *cmd, int halfsize )
+{
+ cmd->halfsize = halfsize;
+}
+
+int commands_get_new_input_width( commands_t *cmd )
+{
+ return cmd->newinputwidth;
+}
+
+int commands_get_global_brightness( commands_t *cmd )
+{
+ return cmd->brightness;
+}
+
+int commands_get_global_contrast( commands_t *cmd )
+{
+ return cmd->contrast;
+}
+
+int commands_get_global_saturation( commands_t *cmd )
+{
+ return cmd->saturation;
+}
+
+int commands_get_global_hue( commands_t *cmd )
+{
+ return cmd->hue;
+}
+
+int commands_set_freq_table( commands_t *cmd )
+{
+ return cmd->setfreqtable;
+}
+
+const char *commands_get_new_freq_table( commands_t *cmd )
+{
+ return cmd->newfreqtable;
+}
+
+int commands_check_freq_present( commands_t *cmd )
+{
+ return cmd->checkfreq;
+}
+
+int commands_sleeptimer( commands_t *cmd )
+{
+ return cmd->sleeptimer;
+}
+
+int commands_sleeptimer_do_shutdown( commands_t *cmd )
+{
+ time_t now;
+
+ time( &now );
+
+ return (now >= ((sleeptimer_function( cmd->sleeptimer ) * 60) + cmd->sleeptimer_start));
+}
+
+void commands_set_pulldown_alg( commands_t *cmd, int pulldown_alg )
+{
+ cmd->pulldown_alg = pulldown_alg;
+ reset_filters_menu( commands_get_menu( cmd, "filters" ),
+ cmd->apply_invert, cmd->apply_mirror,
+ cmd->apply_chroma_kill,
+ cmd->vidin && videoinput_get_height( cmd->vidin ) == 480,
+ cmd->pulldown_alg );
+ commands_refresh_menu( cmd );
+}
+
+const char *commands_get_matte_mode( commands_t *cmd )
+{
+ if( *cmd->newmatte ) {
+ return cmd->newmatte;
+ } else {
+ return 0;
+ }
+}
+
+const char *commands_get_fs_pos( commands_t *cmd )
+{
+ if( *cmd->newpos ) {
+ return cmd->newpos;
+ } else {
+ return 0;
+ }
+}
+
+int commands_get_audio_boost( commands_t *cmd )
+{
+ return cmd->boost;
+}
+
+int commands_xmltv_updated( commands_t *cmd )
+{
+ return cmd->xmltvupdated;
+}
+
+int commands_tuner_reset( commands_t *cmd )
+{
+ return cmd->tunerreset;
+}
+
+const char *commands_get_xmltv_title( commands_t *cmd )
+{
+ if( cmd->xmltv ) {
+ return xmltv_get_title( cmd->xmltv );
+ } else {
+ return 0;
+ }
+}
+
+void commands_get_menu_bounding_box( commands_t *cmd, int *x, int *y,
+ int *width, int *height )
+{
+ if( cmd->osd ) {
+ tvtime_osd_list_get_bounding_box( cmd->osd, x, y, width, height );
+ if( cmd->halfsize ) {
+ *y /= 2;
+ *height /= 2;
+ }
+ } else {
+ *x = *y = *width = *height = 0;
+ }
+}
+
diff -Nurp tvtime-1.0.2/src/commands.h tvtime-1.0.2-custom/src/commands.h
--- tvtime-1.0.2/src/commands.h 2004-10-28 02:50:24.000000000 +0200
+++ tvtime-1.0.2-custom/src/commands.h 2011-05-29 13:07:28.169040774 +0200
@@ -64,6 +64,7 @@ void commands_set_pulldown_alg( commands
int commands_quit( commands_t *cmd );
int commands_toggle_fullscreen( commands_t *cmd );
int commands_toggle_aspect( commands_t *cmd );
+int commands_get_changed_overscan( commands_t *cmd );
int commands_toggle_deinterlacer( commands_t *cmd );
int commands_toggle_pulldown_detection( commands_t *cmd );
int commands_toggle_matte( commands_t *cmd );
diff -Nurp tvtime-1.0.2/src/cpu_accel.c tvtime-1.0.2-custom/src/cpu_accel.c
--- tvtime-1.0.2/src/cpu_accel.c 2004-04-04 18:48:37.000000000 +0200
+++ tvtime-1.0.2-custom/src/cpu_accel.c 2011-05-29 13:07:28.149040530 +0200
@@ -35,7 +35,7 @@ static inline uint32_t arch_accel (void)
int AMD;
uint32_t caps;
-#ifndef PIC
+#if !defined(__PIC__) || defined(__x86_64__)
#define cpuid(op,eax,ebx,ecx,edx) \
__asm__ ("cpuid" \
: "=a" (eax), \
diff -Nurp tvtime-1.0.2/src/Makefile.am tvtime-1.0.2-custom/src/Makefile.am
--- tvtime-1.0.2/src/Makefile.am 2005-02-08 06:00:16.000000000 +0100
+++ tvtime-1.0.2-custom/src/Makefile.am 2011-05-29 13:42:33.649601355 +0200
@@ -29,6 +29,11 @@ OPT_CFLAGS = -Wall -pedantic -I. -DDATAD
-DCONFDIR="\"$(pkgsysconfdir)\"" -DFIFODIR="\"$(tmpdir)\"" \
-D_LARGEFILE64_SOURCE -DLOCALEDIR="\"$(localedir)\""
+if HAVE_ALSA
+ALSA_SRCS = mixer-alsa.c
+else
+ALSA_SRCS =
+endif
COMMON_SRCS = mixer.c videoinput.c rtctimer.c leetft.c osdtools.c tvtimeconf.c \
pngoutput.c tvtimeosd.c input.c cpu_accel.c speedy.c pnginput.c \
deinterlace.c videotools.c attributes.h deinterlace.h leetft.h \
@@ -40,7 +45,7 @@ COMMON_SRCS = mixer.c videoinput.c rtcti
utils.h utils.c pulldown.h pulldown.c hashtable.h hashtable.c \
cpuinfo.h cpuinfo.c videodev.h videodev2.h menu.c menu.h \
outputfilter.h outputfilter.c xmltv.h xmltv.c gettext.h tvtimeglyphs.h \
- copyfunctions.h copyfunctions.c
+ copyfunctions.h copyfunctions.c mixer-oss.c $(ALSA_SRCS)
if ARCH_X86
DSCALER_SRCS = $(top_srcdir)/plugins/dscalerapi.h \
@@ -74,10 +79,10 @@ bin_PROGRAMS = tvtime tvtime-command tvt
tvtime_SOURCES = $(COMMON_SRCS) $(OUTPUT_SRCS) $(PLUGIN_SRCS) tvtime.c
tvtime_CFLAGS = $(TTF_CFLAGS) $(PNG_CFLAGS) $(OPT_CFLAGS) \
- $(PLUGIN_CFLAGS) $(X11_CFLAGS) $(XML2_FLAG) \
+ $(PLUGIN_CFLAGS) $(X11_CFLAGS) $(XML2_FLAG) $(ALSA_CFLAGS) \
$(FONT_CFLAGS) $(AM_CFLAGS)
tvtime_LDFLAGS = $(TTF_LIBS) $(ZLIB_LIBS) $(PNG_LIBS) \
- $(X11_LIBS) $(XML2_LIBS) -lm -lstdc++
+ $(X11_LIBS) $(XML2_LIBS) $(ALSA_LIBS) -lm -lsupc++
tvtime_command_SOURCES = utils.h utils.c tvtimeconf.h tvtimeconf.c \
tvtime-command.c
@@ -90,6 +95,6 @@ tvtime_configure_LDFLAGS = $(ZLIB_LIBS)
tvtime_scanner_SOURCES = utils.h utils.c videoinput.h videoinput.c \
tvtimeconf.h tvtimeconf.c station.h station.c tvtime-scanner.c \
mixer.h mixer.c
-tvtime_scanner_CFLAGS = $(OPT_CFLAGS) $(XML2_FLAG) $(AM_CFLAGS)
-tvtime_scanner_LDFLAGS = $(ZLIB_LIBS) $(XML2_LIBS)
+tvtime_scanner_CFLAGS = $(OPT_CFLAGS) $(XML2_FLAG) $(ALSA_CFLAGS) $(AM_CFLAGS)
+tvtime_scanner_LDFLAGS = $(ZLIB_LIBS) $(XML2_LIBS) $(ALSA_LIBS)
diff -Nurp tvtime-1.0.2/src/mixer-alsa.c tvtime-1.0.2-custom/src/mixer-alsa.c
--- tvtime-1.0.2/src/mixer-alsa.c 1970-01-01 01:00:00.000000000 +0100
+++ tvtime-1.0.2-custom/src/mixer-alsa.c 2011-05-29 13:07:28.122373538 +0200
@@ -0,0 +1,240 @@
+/**
+ * Copyright (C) 2006 Philipp Hahn <pmhahn@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <string.h>
+#include <math.h>
+#include <alsa/asoundlib.h>
+#include "utils.h"
+#include "mixer.h"
+
+static const char alsa_core_devnames[] = "default";
+static char *card, *channel;
+static int muted = 0;
+static int mutecount = 0;
+static snd_mixer_t *handle = NULL;
+static snd_mixer_elem_t *elem = NULL;
+
+static long alsa_min, alsa_max, alsa_vol;
+
+static void alsa_open_mixer( void )
+{
+ int err;
+ static snd_mixer_selem_id_t *sid = NULL;
+ if ((err = snd_mixer_open (&handle, 0)) < 0) {
+ fprintf(stderr, "mixer: open error: %s\n", snd_strerror(err));
+ return;
+ }
+ if ((err = snd_mixer_attach (handle, card)) < 0) {
+ fprintf(stderr, "mixer: attach error: %s\n", snd_strerror(err));
+ goto error;
+ }
+ if ((err = snd_mixer_selem_register (handle, NULL, NULL)) < 0) {
+ fprintf(stderr, "mixer: register error: %s\n", snd_strerror(err));
+ goto error;
+ }
+ if ((err = snd_mixer_load (handle)) < 0) {
+ fprintf(stderr, "mixer: load error: %s\n", snd_strerror(err));
+ goto error;
+ }
+ snd_mixer_selem_id_malloc(&sid);
+ if (sid == NULL)
+ goto error;
+ snd_mixer_selem_id_set_name(sid, channel);
+ if (!(elem = snd_mixer_find_selem(handle, sid))) {
+ fprintf(stderr, "mixer: find error: %s\n", snd_strerror(err));
+ goto error;
+ }
+ if (!snd_mixer_selem_has_playback_volume(elem)) {
+ fprintf(stderr, "mixer: no playback\n");
+ goto error;
+ }
+ snd_mixer_selem_get_playback_volume_range(elem, &alsa_min, &alsa_max);
+ if ((alsa_max - alsa_min) <= 0) {
+ fprintf(stderr, "mixer: no valid playback range\n");
+ goto error;
+ }
+ snd_mixer_selem_id_free(sid);
+ return;
+
+error:
+ if (sid)
+ snd_mixer_selem_id_free(sid);
+ if (handle) {
+ snd_mixer_close(handle);
+ handle = NULL;
+ }
+ return;
+}
+
+/* Volume saved to file */
+static int alsa_get_unmute_volume( void )
+{
+ long val;
+ assert (elem);
+
+ if (snd_mixer_selem_is_playback_mono(elem)) {
+ snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_MONO, &val);
+ return val;
+ } else {
+ int c, n = 0;
+ long sum = 0;
+ for (c = 0; c <= SND_MIXER_SCHN_LAST; c++) {
+ if (snd_mixer_selem_has_playback_channel(elem, c)) {
+ snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &val);
+ sum += val;
+ n++;
+ }
+ }
+ if (! n) {
+ return 0;
+ }
+
+ val = sum / n;
+ sum = (long)((double)(alsa_vol * (alsa_max - alsa_min)) / 100. + 0.5);
+
+ if (sum != val) {
+ alsa_vol = (long)(((val * 100.) / (alsa_max - alsa_min)) + 0.5);
+ }
+ return alsa_vol;
+ }
+}
+
+static int alsa_get_volume( void )
+{
+ if (muted)
+ return 0;
+ else
+ return alsa_get_unmute_volume();
+}
+
+static int alsa_set_volume( int percentdiff )
+{
+ long volume;
+
+ alsa_get_volume();
+
+ alsa_vol += percentdiff;
+ if( alsa_vol > 100 ) alsa_vol = 100;
+ if( alsa_vol < 0 ) alsa_vol = 0;
+
+ volume = (long)((alsa_vol * (alsa_max - alsa_min) / 100.) + 0.5);
+
+ snd_mixer_selem_set_playback_volume_all(elem, volume + alsa_min);
+ snd_mixer_selem_set_playback_switch_all(elem, 1);
+ muted = 0;
+ mutecount = 0;
+
+ return alsa_vol;
+}
+
+static void alsa_mute( int mute )
+{
+ /**
+ * Make sure that if multiple users mute the card,
+ * we only honour the last one.
+ */
+ if( !mute && mutecount ) mutecount--;
+ if( mutecount ) return;
+
+ if( mute ) {
+ mutecount++;
+ muted = 1;
+ if (snd_mixer_selem_has_playback_switch(elem))
+ snd_mixer_selem_set_playback_switch_all(elem, 0);
+ else
+ fprintf(stderr, "mixer: mute not implemented\n");
+ } else {
+ muted = 0;
+ if (snd_mixer_selem_has_playback_switch(elem))
+ snd_mixer_selem_set_playback_switch_all(elem, 1);
+ else
+ fprintf(stderr, "mixer: mute not implemented\n");
+ }
+}
+
+static int alsa_ismute( void )
+{
+ return muted;
+}
+
+static int alsa_set_device( const char *devname )
+{
+ int i;
+
+ if (card) free(card);
+ card = strdup( devname );
+ if( !card ) return -1;
+
+ i = strcspn( card, "/" );
+ if( i == strlen( card ) ) {
+ channel = "Line";
+ } else {
+ card[i] = 0;
+ channel = card + i + 1;
+ }
+ alsa_open_mixer();
+ if (!handle) {
+ fprintf( stderr, "mixer: Can't open mixer %s, "
+ "mixer volume and mute unavailable.\n", card );
+ return -1;
+ }
+ return 0;
+}
+
+static void alsa_set_state( int ismuted, int unmute_volume )
+{
+ /**
+ * 1. we come back unmuted: Don't touch anything
+ * 2. we don't have a saved volume: Don't touch anything
+ * 3. we come back muted and we have a saved volume:
+ * - if tvtime muted it, unmute to old volume
+ * - if user did it, remember that we're muted and old volume
+ */
+ if( alsa_get_volume() == 0 && unmute_volume > 0 ) {
+ snd_mixer_selem_set_playback_volume_all(elem, unmute_volume);
+ muted = 1;
+
+ if( !ismuted ) {
+ alsa_mute( 0 );
+ }
+ }
+}
+
+static void alsa_close_device( void )
+{
+ elem = NULL;
+ if (handle)
+ snd_mixer_close(handle);
+ handle = NULL;
+ muted = 0;
+ mutecount = 0;
+}
+
+struct mixer alsa_mixer = {
+ .set_device = alsa_set_device,
+ .set_state = alsa_set_state,
+ .get_volume = alsa_get_volume,
+ .get_unmute_volume = alsa_get_unmute_volume,
+ .set_volume = alsa_set_volume,
+ .mute = alsa_mute,
+ .ismute = alsa_ismute,
+ .close_device = alsa_close_device,
+};
+// vim: ts=4 sw=4 et foldmethod=marker
diff -Nurp tvtime-1.0.2/src/mixer.c tvtime-1.0.2-custom/src/mixer.c
--- tvtime-1.0.2/src/mixer.c 2004-10-29 04:15:23.000000000 +0200
+++ tvtime-1.0.2-custom/src/mixer.c 2011-05-29 13:07:28.125706912 +0200
@@ -19,230 +19,104 @@
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/soundcard.h>
-#include <sys/mman.h>
-#include <string.h>
-#include "utils.h"
#include "mixer.h"
-static char *mixer_device = "/dev/mixer";
-static int saved_volume = (50 << 8 & 0xFF00) | (50 & 0x00FF);
-static int mixer_channel = SOUND_MIXER_LINE;
-static int mixer_dev_mask = 1 << SOUND_MIXER_LINE;
-static int muted = 0;
-static int mutecount = 0;
-static int fd = -1;
-
-int mixer_get_volume( void )
-{
- int v, cmd, devs;
- int curvol = 0;
-
- if( fd < 0 ) fd = open( mixer_device, O_RDONLY );
- if( fd != -1 ) {
-
- ioctl( fd, SOUND_MIXER_READ_DEVMASK, &devs );
- if( devs & mixer_dev_mask ) {
- cmd = MIXER_READ( mixer_channel );
- } else {
- return curvol;
- }
-
- ioctl( fd, cmd, &v );
- curvol = ( v & 0xFF00 ) >> 8;
- }
-
- return curvol;
+/**
+ * Sets the mixer device and channel.
+ */
+static int null_set_device( const char *devname )
+{
+ return 0;
}
-int mixer_get_unmute_volume( void )
+/**
+ * Sets the initial state of the mixer device.
+ */
+static void null_set_state( int ismuted, int unmute_volume )
{
- if( muted ) {
- return saved_volume;
- } else {
- int v, cmd, devs;
-
- if( fd < 0 ) fd = open( mixer_device, O_RDONLY );
- if( fd != -1 ) {
-
- ioctl( fd, SOUND_MIXER_READ_DEVMASK, &devs );
- if( devs & mixer_dev_mask ) {
- cmd = MIXER_READ( mixer_channel );
- } else {
- return -1;
- }
-
- ioctl( fd, cmd, &v );
- return v;
- }
- }
-
- return -1;
}
-int mixer_set_volume( int percentdiff )
+/**
+ * Returns the current volume setting.
+ */
+static int null_get_volume( void )
{
- int v, cmd, devs, levelpercentage;
-
- levelpercentage = mixer_get_volume();
-
- levelpercentage += percentdiff;
- if( levelpercentage > 100 ) levelpercentage = 100;
- if( levelpercentage < 0 ) levelpercentage = 0;
-
- if( fd < 0 ) fd = open( mixer_device, O_RDONLY );
- if( fd != -1 ) {
- ioctl( fd, SOUND_MIXER_READ_DEVMASK, &devs );
- if( devs & mixer_dev_mask ) {
- cmd = MIXER_WRITE( mixer_channel );
- } else {
- return 0;
- }
-
- v = ( levelpercentage << 8 ) | levelpercentage;
- ioctl( fd, cmd, &v );
- muted = 0;
- mutecount = 0;
- return v;
- }
-
return 0;
}
-void mixer_mute( int mute )
+/**
+ * Returns the volume that would be used to restore the unmute state.
+ */
+static int null_get_unmute_volume( void )
{
- int v, cmd, devs;
-
- /**
- * Make sure that if multiple users mute the card,
- * we only honour the last one.
- */
- if( !mute && mutecount ) mutecount--;
- if( mutecount ) return;
-
- if( fd < 0 ) fd = open( mixer_device, O_RDONLY );
-
- if( mute ) {
- mutecount++;
- if( fd != -1 ) {
-
- /* Save volume */
- ioctl( fd, SOUND_MIXER_READ_DEVMASK, &devs );
- if( devs & mixer_dev_mask ) {
- cmd = MIXER_READ( mixer_channel );
- } else {
- return;
- }
-
- ioctl( fd,cmd,&v );
- saved_volume = v;
-
- /* Now set volume to 0 */
- ioctl( fd, SOUND_MIXER_READ_DEVMASK, &devs );
- if( devs & mixer_dev_mask ) {
- cmd = MIXER_WRITE( mixer_channel );
- } else {
- return;
- }
-
- v = 0;
- ioctl( fd, cmd, &v );
-
- muted = 1;
- return;
- }
- } else {
- if( fd != -1 ) {
- ioctl( fd, SOUND_MIXER_READ_DEVMASK, &devs );
- if( devs & mixer_dev_mask ) {
- cmd = MIXER_WRITE( mixer_channel );
- } else {
- return;
- }
-
- v = saved_volume;
- ioctl( fd, cmd, &v );
- muted = 0;
- return;
- }
- }
+ return 0;
}
-int mixer_ismute( void )
+/**
+ * Tunes the relative volume.
+ */
+static int null_set_volume( int percentdiff )
{
- return muted;
+ return 0;
}
-static char *oss_core_devnames[] = SOUND_DEVICE_NAMES;
-
-void mixer_set_device( const char *devname )
+/**
+ * Sets the mute state.
+ */
+static void null_mute( int mute )
{
- const char *channame;
- int found = 0;
- int i;
-
- mixer_device = strdup( devname );
- if( !mixer_device ) return;
-
- i = strcspn( mixer_device, ":" );
- if( i == strlen( mixer_device ) ) {
- channame = "line";
- } else {
- mixer_device[ i ] = 0;
- channame = mixer_device + i + 1;
- }
- if( !file_is_openable_for_read( mixer_device ) ) {
- fprintf( stderr, "mixer: Can't open device %s, "
- "mixer volume and mute unavailable.\n", mixer_device );
- }
-
- mixer_channel = SOUND_MIXER_LINE;
- for( i = 0; i < SOUND_MIXER_NRDEVICES; i++ ) {
- if( !strcasecmp( channame, oss_core_devnames[ i ] ) ) {
- mixer_channel = i;
- found = 1;
- break;
- }
- }
- if( !found ) {
- fprintf( stderr, "mixer: No such mixer channel '%s', using channel 'line'.\n", channame );
- }
- mixer_dev_mask = 1 << mixer_channel;
}
-void mixer_set_state( int ismuted, int unmute_volume )
+/**
+ * Returns true if the mixer is muted.
+ */
+static int null_ismute( void )
{
- /**
- * 1. we come back unmuted: Don't touch anything
- * 2. we don't have a saved volume: Don't touch anything
- * 3. we come back muted and we have a saved volume:
- * - if tvtime muted it, unmute to old volume
- * - if user did it, remember that we're muted and old volume
- */
- if( mixer_get_volume() == 0 && unmute_volume > 0 ) {
- saved_volume = unmute_volume;
- muted = 1;
-
- if( !ismuted ) {
- mixer_mute( 0 );
- }
- }
+ return 0;
}
-void mixer_close_device( void )
+/**
+ * Closes the mixer device if it is open.
+ */
+static void null_close_device( void )
{
- if( fd >= 0 ) close( fd );
- saved_volume = (50 << 8 & 0xFF00) | (50 & 0x00FF);
- mixer_channel = SOUND_MIXER_LINE;
- mixer_dev_mask = 1 << SOUND_MIXER_LINE;
- muted = 0;
- mutecount = 0;
- fd = -1;
}
+/* The null device, which always works. */
+static struct mixer null_mixer = {
+ .set_device = null_set_device,
+ .set_state = null_set_state,
+ .get_volume = null_get_volume,
+ .get_unmute_volume = null_get_unmute_volume,
+ .set_volume = null_set_volume,
+ .mute = null_mute,
+ .ismute = null_ismute,
+ .close_device = null_close_device,
+};
+
+/* List of all available access methods.
+ * Uses weak symbols: NULL is not linked in. */
+static struct mixer *mixers[] = {
+ &alsa_mixer,
+ &oss_mixer,
+ &null_mixer /* LAST */
+};
+/* The actual access method. */
+struct mixer *mixer = &null_mixer;
+
+/**
+ * Sets the mixer device and channel.
+ * Try each access method until one succeeds.
+ */
+void mixer_set_device( const char *devname )
+{
+ int i;
+ mixer->close_device();
+ for (i = 0; i < sizeof(mixers)/sizeof(mixers[0]); i++) {
+ mixer = mixers[i];
+ if (!mixer)
+ continue;
+ if (mixer->set_device(devname) == 0)
+ break;
+ }
+}
diff -Nurp tvtime-1.0.2/src/mixer.h tvtime-1.0.2-custom/src/mixer.h
--- tvtime-1.0.2/src/mixer.h 2004-08-27 03:18:49.000000000 +0200
+++ tvtime-1.0.2-custom/src/mixer.h 2011-05-29 13:07:28.129040286 +0200
@@ -27,45 +27,58 @@ extern "C" {
#endif
/**
- * Sets the mixer device and channel. The device name is of the form
- * devicename:channelname. The default is /dev/mixer:line.
+ * Sets the mixer device and channel.
+ * All interfaces are scanned until one succeeds.
*/
void mixer_set_device( const char *devname );
+struct mixer {
+/**
+ * Sets the mixer device and channel.
+ */
+int (* set_device)( const char *devname );
+
/**
* Sets the initial state of the mixer device.
*/
-void mixer_set_state( int ismuted, int unmute_volume );
+void (* set_state)( int ismuted, int unmute_volume );
/**
* Returns the current volume setting.
*/
-int mixer_get_volume( void );
+int (* get_volume)( void );
/**
* Returns the volume that would be used to restore the unmute state.
*/
-int mixer_get_unmute_volume( void );
+int (* get_unmute_volume)( void );
/**
* Tunes the relative volume.
*/
-int mixer_set_volume( int percentdiff );
+int (* set_volume)( int percentdiff );
/**
* Sets the mute state.
*/
-void mixer_mute( int mute );
+void (* mute)( int mute );
/**
* Returns true if the mixer is muted.
*/
-int mixer_ismute( void );
+int (* ismute)( void );
/**
* Closes the mixer device if it is open.
*/
-void mixer_close_device( void );
+void (* close_device)( void );
+};
+
+#pragma weak alsa_mixer
+extern struct mixer alsa_mixer;
+#pragma weak oss_mixer
+extern struct mixer oss_mixer;
+extern struct mixer *mixer;
#ifdef __cplusplus
};
diff -Nurp tvtime-1.0.2/src/mixer-oss.c tvtime-1.0.2-custom/src/mixer-oss.c
--- tvtime-1.0.2/src/mixer-oss.c 1970-01-01 01:00:00.000000000 +0100
+++ tvtime-1.0.2-custom/src/mixer-oss.c 2011-05-29 13:07:28.129040286 +0200
@@ -0,0 +1,261 @@
+/**
+ * Copyright (C) 2002, 2003 Doug Bell <drbell@users.sourceforge.net>
+ *
+ * Some mixer routines from mplayer, http://mplayer.sourceforge.net.
+ * Copyright (C) 2000-2002. by A'rpi/ESP-team & others
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/soundcard.h>
+#include <sys/mman.h>
+#include <string.h>
+#include "utils.h"
+#include "mixer.h"
+
+static char *mixer_device = "/dev/mixer";
+static int saved_volume = (50 << 8 & 0xFF00) | (50 & 0x00FF);
+static int mixer_channel = SOUND_MIXER_LINE;
+static int mixer_dev_mask = 1 << SOUND_MIXER_LINE;
+static int muted = 0;
+static int mutecount = 0;
+static int fd = -1;
+
+static int oss_get_volume( void )
+{
+ int v, cmd, devs;
+ int curvol = 0;
+
+ if( fd < 0 ) fd = open( mixer_device, O_RDONLY );
+ if( fd != -1 ) {
+
+ ioctl( fd, SOUND_MIXER_READ_DEVMASK, &devs );
+ if( devs & mixer_dev_mask ) {
+ cmd = MIXER_READ( mixer_channel );
+ } else {
+ return curvol;
+ }
+
+ ioctl( fd, cmd, &v );
+ curvol = ( v & 0xFF00 ) >> 8;
+ }
+
+ return curvol;
+}
+
+static int oss_get_unmute_volume( void )
+{
+ if( muted ) {
+ return saved_volume;
+ } else {
+ int v, cmd, devs;
+
+ if( fd < 0 ) fd = open( mixer_device, O_RDONLY );
+ if( fd != -1 ) {
+
+ ioctl( fd, SOUND_MIXER_READ_DEVMASK, &devs );
+ if( devs & mixer_dev_mask ) {
+ cmd = MIXER_READ( mixer_channel );
+ } else {
+ return -1;
+ }
+
+ ioctl( fd, cmd, &v );
+ return v;
+ }
+ }
+
+ return -1;
+}
+
+static int oss_set_volume( int percentdiff )
+{
+ int v, cmd, devs, levelpercentage;
+
+ levelpercentage = oss_get_volume();
+
+ levelpercentage += percentdiff;
+ if( levelpercentage > 100 ) levelpercentage = 100;
+ if( levelpercentage < 0 ) levelpercentage = 0;
+
+ if( fd < 0 ) fd = open( mixer_device, O_RDONLY );
+ if( fd != -1 ) {
+ ioctl( fd, SOUND_MIXER_READ_DEVMASK, &devs );
+ if( devs & mixer_dev_mask ) {
+ cmd = MIXER_WRITE( mixer_channel );
+ } else {
+ return 0;
+ }
+
+ v = ( levelpercentage << 8 ) | levelpercentage;
+ ioctl( fd, cmd, &v );
+ muted = 0;
+ mutecount = 0;
+ return v;
+ }
+
+ return 0;
+}
+
+static void oss_mute( int mute )
+{
+ int v, cmd, devs;
+
+ /**
+ * Make sure that if multiple users mute the card,
+ * we only honour the last one.
+ */
+ if( !mute && mutecount ) mutecount--;
+ if( mutecount ) return;
+
+ if( fd < 0 ) fd = open( mixer_device, O_RDONLY );
+
+ if( mute ) {
+ mutecount++;
+ if( fd != -1 ) {
+
+ /* Save volume */
+ ioctl( fd, SOUND_MIXER_READ_DEVMASK, &devs );
+ if( devs & mixer_dev_mask ) {
+ cmd = MIXER_READ( mixer_channel );
+ } else {
+ return;
+ }
+
+ ioctl( fd,cmd,&v );
+ saved_volume = v;
+
+ /* Now set volume to 0 */
+ ioctl( fd, SOUND_MIXER_READ_DEVMASK, &devs );
+ if( devs & mixer_dev_mask ) {
+ cmd = MIXER_WRITE( mixer_channel );
+ } else {
+ return;
+ }
+
+ v = 0;
+ ioctl( fd, cmd, &v );
+
+ muted = 1;
+ return;
+ }
+ } else {
+ if( fd != -1 ) {
+ ioctl( fd, SOUND_MIXER_READ_DEVMASK, &devs );
+ if( devs & mixer_dev_mask ) {
+ cmd = MIXER_WRITE( mixer_channel );
+ } else {
+ return;
+ }
+
+ v = saved_volume;
+ ioctl( fd, cmd, &v );
+ muted = 0;
+ return;
+ }
+ }
+}
+
+static int oss_ismute( void )
+{
+ return muted;
+}
+
+static char *oss_core_devnames[] = SOUND_DEVICE_NAMES;
+
+static int oss_set_device( const char *devname )
+{
+ const char *channame;
+ int found = 0;
+ int i;
+
+ mixer_device = strdup( devname );
+ if( !mixer_device ) return -1;
+
+ i = strcspn( mixer_device, ":" );
+ if( i == strlen( mixer_device ) ) {
+ channame = "line";
+ } else {
+ mixer_device[ i ] = 0;
+ channame = mixer_device + i + 1;
+ }
+ if( !file_is_openable_for_read( mixer_device ) ) {
+ fprintf( stderr, "mixer: Can't open device %s, "
+ "mixer volume and mute unavailable.\n", mixer_device );
+ return -1;
+ }
+
+ mixer_channel = SOUND_MIXER_LINE;
+ for( i = 0; i < SOUND_MIXER_NRDEVICES; i++ ) {
+ if( !strcasecmp( channame, oss_core_devnames[ i ] ) ) {
+ mixer_channel = i;
+ found = 1;
+ break;
+ }
+ }
+ if( !found ) {
+ fprintf( stderr, "mixer: No such mixer channel '%s', using channel 'line'.\n", channame );
+ return -1;
+ }
+ mixer_dev_mask = 1 << mixer_channel;
+ return 0;
+}
+
+static void oss_set_state( int ismuted, int unmute_volume )
+{
+ /**
+ * 1. we come back unmuted: Don't touch anything
+ * 2. we don't have a saved volume: Don't touch anything
+ * 3. we come back muted and we have a saved volume:
+ * - if tvtime muted it, unmute to old volume
+ * - if user did it, remember that we're muted and old volume
+ */
+ if( oss_get_volume() == 0 && unmute_volume > 0 ) {
+ saved_volume = unmute_volume;
+ muted = 1;
+
+ if( !ismuted ) {
+ oss_mute( 0 );
+ }
+ }
+}
+
+static void oss_close_device( void )
+{
+ if( fd >= 0 ) close( fd );
+ saved_volume = (50 << 8 & 0xFF00) | (50 & 0x00FF);
+ mixer_channel = SOUND_MIXER_LINE;
+ mixer_dev_mask = 1 << SOUND_MIXER_LINE;
+ muted = 0;
+ mutecount = 0;
+ fd = -1;
+}
+
+struct mixer oss_mixer = {
+ .set_device = oss_set_device,
+ .set_state = oss_set_state,
+ .get_volume = oss_get_volume,
+ .get_unmute_volume = oss_get_unmute_volume,
+ .set_volume = oss_set_volume,
+ .mute = oss_mute,
+ .ismute = oss_ismute,
+ .close_device = oss_close_device,
+};
diff -Nurp tvtime-1.0.2/src/tvtime.c tvtime-1.0.2-custom/src/tvtime.c
--- tvtime-1.0.2/src/tvtime.c 2005-09-08 04:55:54.000000000 +0200
+++ tvtime-1.0.2-custom/src/tvtime.c 2011-05-29 13:07:28.172374148 +0200
@@ -1062,84 +1062,55 @@ static void build_matte_menu( menu_t *me
char string[ 128 ];
menu_set_back_command( menu, TVTIME_SHOW_MENU, "output" );
- if( sixteennine ) {
- snprintf( string, sizeof( string ), (mode == 0) ?
- TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
- _("16:9 + Overscan") );
- menu_set_text( menu, 1, string );
- menu_set_enter_command( menu, 1, TVTIME_SET_MATTE, "16:9" );
- snprintf( string, sizeof( string ), (mode == 1) ?
- TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
- _("1.85:1") );
- menu_set_text( menu, 2, string );
- menu_set_enter_command( menu, 2, TVTIME_SET_MATTE, "1.85:1" );
- snprintf( string, sizeof( string ), (mode == 2) ?
- TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
- _("2.35:1") );
- menu_set_text( menu, 3, string );
- menu_set_enter_command( menu, 3, TVTIME_SET_MATTE, "2.35:1" );
- snprintf( string, sizeof( string ), (mode == 3) ?
- TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
- _("4:3 centre") );
- menu_set_text( menu, 4, string );
- menu_set_enter_command( menu, 4, TVTIME_SET_MATTE, "4:3" );
- snprintf( string, sizeof( string ), (mode == 4) ?
- TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
- _("16:10") );
- menu_set_text( menu, 5, string );
- menu_set_enter_command( menu, 5, TVTIME_SET_MATTE, "16:10" );
- } else {
- snprintf( string, sizeof( string ), (mode == 0) ?
- TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
- _("4:3 + Overscan") );
- menu_set_text( menu, 1, string );
- menu_set_enter_command( menu, 1, TVTIME_SET_MATTE, "4:3" );
- snprintf( string, sizeof( string ), (mode == 1) ?
- TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
- _("16:9") );
- menu_set_text( menu, 2, string );
- menu_set_enter_command( menu, 2, TVTIME_SET_MATTE, "16:9" );
- snprintf( string, sizeof( string ), (mode == 2) ?
- TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
- _("16:10") );
- menu_set_text( menu, 3, string );
- menu_set_enter_command( menu, 3, TVTIME_SET_MATTE, "16:10" );
- snprintf( string, sizeof( string ), (mode == 3) ?
- TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
- _("1.85:1") );
- menu_set_text( menu, 4, string );
- menu_set_enter_command( menu, 4, TVTIME_SET_MATTE, "1.85:1" );
- snprintf( string, sizeof( string ), (mode == 4) ?
- TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
- _("2.35:1") );
- menu_set_text( menu, 5, string );
- menu_set_enter_command( menu, 5, TVTIME_SET_MATTE, "2.35:1" );
- }
+
+ snprintf( string, sizeof( string ), (mode == 0) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("4:3") );
+ menu_set_text( menu, 1, string );
+ menu_set_enter_command( menu, 1, TVTIME_SET_MATTE, "4:3" );
+ snprintf( string, sizeof( string ), (mode == 1) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("16:10") );
+ menu_set_text( menu, 2, string );
+ menu_set_enter_command( menu, 2, TVTIME_SET_MATTE, "16:10" );
+ snprintf( string, sizeof( string ), (mode == 2) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("16:9") );
+ menu_set_text( menu, 3, string );
+ menu_set_enter_command( menu, 3, TVTIME_SET_MATTE, "16:9" );
+ snprintf( string, sizeof( string ), (mode == 3) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("1.85:1") );
+ menu_set_text( menu, 4, string );
+ menu_set_enter_command( menu, 4, TVTIME_SET_MATTE, "1.85:1" );
+ snprintf( string, sizeof( string ), (mode == 4) ?
+ TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s",
+ _("2.35:1") );
+ menu_set_text( menu, 5, string );
+ menu_set_enter_command( menu, 5, TVTIME_SET_MATTE, "2.35:1" );
+
snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s",
_("Back") );
menu_set_text( menu, 6, string );
menu_set_enter_command( menu, 6, TVTIME_SHOW_MENU, "output" );
}
-
+
static void osd_list_matte( tvtime_osd_t *osd, int mode, int sixteennine )
{
tvtime_osd_list_set_lines( osd, 6 );
if( sixteennine ) {
tvtime_osd_list_set_text( osd, 0, _("Matte setting (Anamorphic input)") );
- tvtime_osd_list_set_text( osd, 1, _("16:9 + Overscan") );
- tvtime_osd_list_set_text( osd, 2, "1.85:1" );
- tvtime_osd_list_set_text( osd, 3, "2.35:1" );
- tvtime_osd_list_set_text( osd, 4, _("4:3 centre") );
- tvtime_osd_list_set_text( osd, 5, "16:10" );
+
} else {
tvtime_osd_list_set_text( osd, 0, _("Matte setting (4:3 input)") );
- tvtime_osd_list_set_text( osd, 1, _("4:3 + Overscan") );
- tvtime_osd_list_set_text( osd, 2, "16:9" );
- tvtime_osd_list_set_text( osd, 3, "16:10" );
- tvtime_osd_list_set_text( osd, 4, "1.85:1" );
- tvtime_osd_list_set_text( osd, 5, "2.35:1" );
}
+ tvtime_osd_list_set_text( osd, 1, "4:3" );
+ tvtime_osd_list_set_text( osd, 2, "16:10" );
+ tvtime_osd_list_set_text( osd, 3, "16:9" );
+ tvtime_osd_list_set_text( osd, 4, "1.85:1" );
+ tvtime_osd_list_set_text( osd, 5, "2.35:1" );
+
tvtime_osd_list_set_hilight( osd, mode + 1 );
tvtime_osd_show_list( osd, 1, 0 );
}
@@ -1204,6 +1175,7 @@ int tvtime_main( rtctimer_t *rtctimer, i
int matte_y = 0;
int matte_h = 0;
int matte_mode = 0;
+ int matte_changed = 0;
int restarttvtime = 0;
int return_value = 0;
int last_current_id = -1;
@@ -1241,6 +1213,7 @@ int tvtime_main( rtctimer_t *rtctimer, i
output = get_xv_output();
sixteennine = config_get_aspect( ct );
+ matte_mode = config_get_matte( ct );
if( !output || !output->init( config_get_geometry( ct ),
sixteennine, config_get_square_pixels( ct ),
@@ -1441,7 +1414,7 @@ int tvtime_main( rtctimer_t *rtctimer, i
/* Set the mixer device. */
mixer_set_device( config_get_mixer_device( ct ) );
- mixer_set_state( config_get_muted( ct ), config_get_unmute_volume( ct ) );
+ mixer->set_state( config_get_muted( ct ), config_get_unmute_volume( ct ) );
/* Setup OSD stuff. */
pixel_aspect = ( (double) width ) /
@@ -1594,6 +1567,15 @@ int tvtime_main( rtctimer_t *rtctimer, i
build_fspos_menu( commands_get_menu( commands, "fspos" ),
config_get_fullscreen_position( ct ) );
+ matte_changed = 1;
+ double matte = 4.0/3.0;
+
+ /* initialize with safe values until matte is calculated later in the loop. */
+ matte_x = 0;
+ matte_y = 0;
+ matte_w = width;
+ matte_h = height;
+
/* Initialize our timestamps. */
for(;;) {
const char *fifo_args = 0;
@@ -1607,31 +1589,19 @@ int tvtime_main( rtctimer_t *rtctimer, i
int exposed = output->is_exposed();
int current_id;
+
if( vidin && videoinput_has_tuner( vidin ) ) {
current_id = station_get_current_id( stationmgr );
} else {
current_id = 0;
}
-
- if( matte_mode ) {
+ /* Since the matte/overscan calculations changed these could probably
+ be the same variables, but we'll leave it like this for now. */
output_x = matte_x;
output_w = matte_w;
output_y = matte_y;
output_h = matte_h;
- } else {
- output_x = (int) ((((double) width) *
- commands_get_overscan( commands )) + 0.5);
- output_w = (int) ((((double) width) -
- (((double) width) *
- commands_get_overscan( commands ) * 2.0)) +
- 0.5);
- output_y = (int) ((((double) height) *
- commands_get_overscan( commands )) + 0.5);
- output_h = (int) ((((double) height) -
- (((double) height) *
- commands_get_overscan( commands ) * 2.0)) +
- 0.5);
- }
+
if( fifo ) {
int cmd;
@@ -1766,11 +1736,14 @@ int tvtime_main( rtctimer_t *rtctimer, i
quiet_screenshots );
commands_refresh_menu( commands );
}
+
+
if( commands_toggle_aspect( commands ) ) {
- matte_mode = 0;
- output->set_matte( 0, 0 );
if( output->toggle_aspect() ) {
sixteennine = 1;
+ /* Matte is now always applied so we change it to 16:9 mode too so that
+ nothing other than overscan is cropped. */
+ matte_mode = 2;
if( osd ) {
tvtime_osd_show_message( osd,
_("16:9 display mode active.") );
@@ -1780,6 +1753,7 @@ int tvtime_main( rtctimer_t *rtctimer, i
( ( (double) height ) * (16.0 / 9.0) );
} else {
sixteennine = 0;
+ matte_mode = 0;
if( osd ) {
tvtime_osd_show_message( osd,
_("4:3 display mode active.") );
@@ -1800,9 +1774,7 @@ int tvtime_main( rtctimer_t *rtctimer, i
output->is_alwaysontop_supported(),
output->is_overscan_supported(),
quiet_screenshots );
- build_matte_menu( commands_get_menu( commands, "matte" ),
- matte_mode, sixteennine );
- commands_refresh_menu( commands );
+ matte_changed = 1;
}
if( commands_get_fs_pos( commands ) ) {
const char *fspos = commands_get_fs_pos( commands );
@@ -1839,84 +1811,92 @@ int tvtime_main( rtctimer_t *rtctimer, i
}
commands_refresh_menu( commands );
}
+
+ /* Overscan has been changed so it is calculated and applied with the matte.
+ So changing it now generated this event so that we can tell it to redo the matte. */
+ if( commands_get_changed_overscan( commands ) ) {
+ matte_changed = 1;
+ }
if( commands_toggle_matte( commands ) ||
commands_get_matte_mode( commands ) ) {
- double matte = 4.0 / 3.0;
- int sqwidth = sixteennine ?
- ((height * 16) / 9) : ((height * 4) / 3);
- int sqheight = sixteennine ?
- ((width * 9) / 16) : ((width * 3) / 4);
- matte_x = 0;
- matte_w = width;
if( commands_toggle_matte( commands ) ) {
matte_mode = (matte_mode + 1) % 5;
} else {
- if( !strcmp( commands_get_matte_mode( commands ), "16:9" ) ) {
- matte_mode = sixteennine ? 0 : 1;
- } else if( !strcmp( commands_get_matte_mode( commands ),
- "16:10" ) ) {
- matte_mode = sixteennine ? 4 : 2;
+ if( !strcmp( commands_get_matte_mode( commands ), "16:10" ) ) {
+ matte_mode = 1;
+ } else if( !strcmp( commands_get_matte_mode( commands ),
+ "16:9" ) ) {
+ matte_mode = 2;
} else if( !strcmp( commands_get_matte_mode( commands ),
"1.85:1" ) ) {
- matte_mode = sixteennine ? 1 : 3;
+ matte_mode = 3;
} else if( !strcmp( commands_get_matte_mode( commands ),
"2.35:1" ) ) {
- matte_mode = sixteennine ? 2 : 4;
+ matte_mode = 4;
} else {
- matte_mode = sixteennine ? 3 : 0;
+ matte_mode = 0;
}
}
-
- if( sixteennine ) {
- if( matte_mode == 0 ) {
- matte = 16.0 / 9.0;
- } else if( matte_mode == 1 ) {
- matte = 1.85;
- } else if( matte_mode == 2 ) {
- matte = 2.35;
- } else if( matte_mode == 3 ) {
- matte = 4.0 / 3.0;
- matte_w = (int) (((double) sqheight * matte) + 0.5);
- matte_x = (width - matte_w) / 2;
- /* We're cropping the sides off so we add overscan to avoid mess
- * at the top of the screen. */
- matte_y = commands_get_overscan( commands ) * height / 2;
- matte_h = height - matte_y;
- output->set_matte( (matte_h * 4) / 3, matte_h );
- } else if( matte_mode == 4 ) {
- matte = 1.6;
- matte_w = (int) (((double) sqheight * matte) + 0.5);
- matte_x = (width - matte_w) / 2;
- /* We're cropping the sides off so we add overscan to avoid mess
- * at the top of the screen. */
- matte_y = commands_get_overscan( commands ) * height / 2;
- matte_h = height - matte_y;
- output->set_matte( (matte_h * 16) / 10, matte_h );
- }
- } else {
- if( matte_mode == 1 ) {
- matte = 16.0 / 9.0;
- } else if( matte_mode == 2 ) {
- matte = 1.6;
- } else if( matte_mode == 3 ) {
- matte = 1.85;
- } else if( matte_mode == 4 ) {
- matte = 2.35;
- }
- }
- if( !matte_x ) {
- matte_h = (int) ((((double) sqwidth)/matte) + 0.5);
- matte_y = (height - matte_h) / 2;
- output->set_matte( sqwidth, matte_h );
- }
if( osd && !commands_menu_active( commands ) ) {
osd_list_matte( osd, matte_mode, sixteennine );
}
build_matte_menu( commands_get_menu( commands, "matte" ),
matte_mode, sixteennine );
commands_refresh_menu( commands );
+ matte_changed = 1;
}
+ if (matte_changed) {
+ matte_changed = 0;
+
+ /* start with overscan then apply matte */
+ matte_x = (int) ((((double) width) *
+ commands_get_overscan( commands )) + 0.5);
+ matte_w = (int) ((((double) width) -
+ (((double) width) *
+ commands_get_overscan( commands ) * 2.0)) +
+ 0.5);
+ matte_y = (int) ((((double) height) *
+ commands_get_overscan( commands )) + 0.5);
+ matte_h = (int) ((((double) height) -
+ (((double) height) *
+ commands_get_overscan( commands ) * 2.0)) +
+ 0.5);
+
+ int sqwidth = sixteennine ?
+ ((matte_h * 16) / 9) : ((matte_h * 4) / 3);
+ int sqheight = sixteennine ?
+ ((matte_w * 9) / 16) : ((matte_w * 3) / 4);
+
+ if( matte_mode == 0 ) {
+ matte = 4.0 / 3.0;
+ config_save( ct, "Matte", "4:3" );
+ } else if( matte_mode == 1 ) {
+ matte = 1.6;
+ config_save( ct, "Matte", "16:10" );
+ } else if( matte_mode == 2 ) {
+ matte = 16.0/9.0;
+ config_save( ct, "Matte", "16:9" );
+ } else if( matte_mode == 3 ) {
+ matte = 1.85;
+ config_save( ct, "Matte", "1.85:1" );
+ } else if( matte_mode == 4 ) {
+ matte = 2.35;
+ config_save( ct, "Matte", "2.35:1" );
+ }
+
+ if( sixteennine && matte < (16.0/9.0) )
+ {
+ matte_w = (int) (((double) sqheight * matte) + 0.5);
+ matte_x = (width - matte_w) / 2;
+ output->set_matte( matte_w, sqheight );
+ } else {
+ matte_h = (int) ((((double) sqwidth)/matte) + 0.5);
+ matte_y = (height - matte_h) / 2;
+ output->set_matte( sqwidth, matte_h );
+ }
+ }
+
if( commands_toggle_pulldown_detection( commands ) ) {
if( height == 480 ) {
tvtime->pulldown_alg =
@@ -2565,14 +2545,14 @@ int tvtime_main( rtctimer_t *rtctimer, i
snprintf( number, 4, "%d", quiet_screenshots );
config_save( ct, "QuietScreenshots", number );
- snprintf( number, 6, "%d", mixer_get_unmute_volume() );
+ snprintf( number, 6, "%d", mixer->get_unmute_volume() );
config_save( ct, "UnmuteVolume", number );
- snprintf( number, 4, "%d", mixer_ismute() );
+ snprintf( number, 4, "%d", mixer->ismute() );
config_save( ct, "Muted", number );
if( config_get_mute_on_exit( ct ) ) {
- mixer_mute( 1 );
+ mixer->mute( 1 );
}
if( vidin ) {
@@ -2619,7 +2599,7 @@ int tvtime_main( rtctimer_t *rtctimer, i
if( osd ) {
tvtime_osd_delete( osd );
}
- mixer_close_device();
+ mixer->close_device();
/* Free temporary memory. */
free( colourbars );
diff -Nurp tvtime-1.0.2/src/tvtimeconf.c tvtime-1.0.2-custom/src/tvtimeconf.c
--- tvtime-1.0.2/src/tvtimeconf.c 2005-09-08 06:07:56.000000000 +0200
+++ tvtime-1.0.2-custom/src/tvtimeconf.c 2011-05-29 13:07:28.179040896 +0200
@@ -56,6 +56,7 @@ struct config_s
char *geometry;
int verbose;
int aspect;
+ int matte;
int squarepixels;
int debug;
int fullscreen;
@@ -290,6 +291,22 @@ static void parse_option( config_t *ct,
ct->aspect = atoi( curval );
}
+ if( !xmlStrcasecmp( name, BAD_CAST "Matte" ) ) {
+ if(!strcmp( curval, "4:3")) {
+ ct->matte = 0;
+ } else if(!strcmp( curval, "16:10")) {
+ ct->matte = 1;
+ } else if(!strcmp( curval, "16:9")) {
+ ct->matte = 2;
+ } else if(!strcmp( curval, "1.85:1")) {
+ ct->matte = 3;
+ } else if(!strcmp( curval, "2.35:1")) {
+ ct->matte = 4;
+ }
+ /* No valid matte if found ct->matte will be -1 and config_get_matte will choose
+ a default based on the aspect ratio. */
+ }
+
if( !xmlStrcasecmp( name, BAD_CAST "DebugMode" ) ) {
ct->debug = atoi( curval );
}
@@ -629,9 +646,11 @@ static void print_usage( char **argv )
lfputs( _(" -l, --xmltvlanguage=LANG Use XMLTV data in given language, if available.\n"), stderr );
lfputs( _(" -v, --verbose Print debugging messages to stderr.\n"), stderr );
lfputs( _(" -X, --display=DISPLAY Use the given X display to connect to.\n"), stderr );
- lfputs( _(" -x, --mixer=DEVICE[:CH] The mixer device and channel to control.\n"
- " (defaults to /dev/mixer:line)\n\n"
- " Valid channels are:\n"
+ lfputs( _(" -x, --mixer=<DEVICE[:CH]>|<DEVICE/CH>\n"
+ " The mixer device and channel to control. The first\n"
+ " variant sets the OSS mixer the second one ALSA.\n"
+ " (defaults to default/Line)\n\n"
+ " Valid channels for OSS are:\n"
" vol, bass, treble, synth, pcm, speaker, line,\n"
" mic, cd, mix, pcm2, rec, igain, ogain, line1,\n"
" line2, line3, dig1, dig2, dig3, phin, phout,\n"
@@ -677,9 +696,11 @@ static void print_config_usage( char **a
lfputs( _(" -R, --priority=PRI Sets the process priority to run tvtime at.\n"), stderr );
lfputs( _(" -t, --xmltv=FILE Read XMLTV listings from the given file.\n"), stderr );
lfputs( _(" -l, --xmltvlanguage=LANG Use XMLTV data in given language, if available.\n"), stderr );
- lfputs( _(" -x, --mixer=DEVICE[:CH] The mixer device and channel to control.\n"
- " (defaults to /dev/mixer:line)\n\n"
- " Valid channels are:\n"
+ lfputs( _(" -x, --mixer=<DEVICE[:CH]>|<DEVICE/CH>\n"
+ " The mixer device and channel to control. The first\n"
+ " variant sets the OSS mixer the second one ALSA.\n"
+ " (defaults to default/Line)\n\n"
+ " Valid channels for OSS are:\n"
" vol, bass, treble, synth, pcm, speaker, line,\n"
" mic, cd, mix, pcm2, rec, igain, ogain, line1,\n"
" line2, line3, dig1, dig2, dig3, phin, phout,\n"
@@ -712,6 +733,7 @@ config_t *config_new( void )
ct->geometry = strdup( "0x576" );
ct->verbose = 0;
ct->aspect = 0;
+ ct->matte = -1;
ct->squarepixels = 1;
ct->debug = 0;
ct->fullscreen = 0;
@@ -764,7 +786,7 @@ config_t *config_new( void )
ct->uid = getuid();
- ct->mixerdev = strdup( "/dev/mixer:line" );
+ ct->mixerdev = strdup( "default/Line" );
ct->deinterlace_method = strdup( "GreedyH" );
ct->check_freq_present = 1;
@@ -807,6 +829,10 @@ config_t *config_new( void )
ct->keymap[ 'a' ] = TVTIME_TOGGLE_ASPECT;
ct->keymap[ 'f' ] = TVTIME_TOGGLE_FULLSCREEN;
ct->keymap[ 'i' ] = TVTIME_TOGGLE_INPUT;
+ ct->keymap[ 'a' ] = TVTIME_TOGGLE_ASPECT;
+ ct->keymap[ I_INSERT ] = TVTIME_TOGGLE_MATTE;
+ ct->keymap[ ',' ] = TVTIME_OVERSCAN_DOWN;
+ ct->keymap[ '.' ] = TVTIME_OVERSCAN_DOWN;
ct->keymap[ 's' ] = TVTIME_SCREENSHOT;
ct->keymap[ ',' ] = TVTIME_MIXER_TOGGLE_MUTE;
ct->keymap[ 'e' ] = TVTIME_TOGGLE_AUDIO_MODE;
@@ -1451,6 +1477,13 @@ int config_get_aspect( config_t *ct )
return ct->aspect;
}
+int config_get_matte( config_t *ct )
+{
+ /* If matte is not set then default to 0 for normal or 2 for widescreen. */
+ if (ct->matte == -1) return ct->aspect * 2;
+ return ct->matte;
+}
+
int config_get_start_channel( config_t *ct )
{
return ct->start_channel;
diff -Nurp tvtime-1.0.2/src/tvtimeconf.c.orig tvtime-1.0.2-custom/src/tvtimeconf.c.orig
--- tvtime-1.0.2/src/tvtimeconf.c.orig 1970-01-01 01:00:00.000000000 +0100
+++ tvtime-1.0.2-custom/src/tvtimeconf.c.orig 2011-05-29 13:07:28.142373782 +0200
@@ -0,0 +1,1667 @@
+/**
+ * Copyright (C) 2002, 2003 Doug Bell <drbell@users.sourceforge.net>
+ * Copyright (C) 2003 Alexander Belov <asbel@mail.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <langinfo.h>
+#include <locale.h>
+#include <pwd.h>
+#include <errno.h>
+#include <libxml/parser.h>
+#include <math.h>
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#ifdef ENABLE_NLS
+# define _(string) gettext (string)
+# include "gettext.h"
+#else
+# define _(string) string
+#endif
+#include "tvtimeconf.h"
+#include "input.h"
+#include "station.h"
+#include "utils.h"
+
+#define MAX_KEYSYMS 350
+#define MAX_BUTTONS 15
+
+struct config_s
+{
+ char *geometry;
+ int verbose;
+ int aspect;
+ int squarepixels;
+ int debug;
+ int fullscreen;
+ int alwaysontop;
+ int priority;
+ int ntsc_mode;
+ int send_fields;
+ int fspos;
+ int picsaverestore;
+ int brightness;
+ int contrast;
+ int saturation;
+ int hue;
+ int invert;
+ int cc;
+ int mirror;
+ int boost;
+ int quiet_screenshots;
+ int unmute_volume;
+ int muted;
+ int mute_on_exit;
+ int show_taglines;
+
+ int keymap[ 8 * MAX_KEYSYMS ];
+ char *keymap_arg[ 8 * MAX_KEYSYMS ];
+ int keymapmenu[ 8 * MAX_KEYSYMS ];
+ char *keymapmenu_arg[ 8 * MAX_KEYSYMS ];
+ int buttonmap[ MAX_BUTTONS ];
+ char *buttonmap_arg[ MAX_BUTTONS ];
+ int buttonmapmenu[ MAX_BUTTONS ];
+ char *buttonmapmenu_arg[ MAX_BUTTONS ];
+
+ int inputwidth;
+ int inputnum;
+ char *v4ldev;
+ char *norm;
+ char *freq;
+ char *ssdir;
+ char *timeformat;
+ char *audiomode;
+ char *xmltvfile;
+ char *xmltvlanguage;
+ unsigned int channel_text_rgb;
+ unsigned int other_text_rgb;
+
+ uid_t uid;
+
+ char *mixerdev;
+
+ char *deinterlace_method;
+ int check_freq_present;
+
+ int use_xds;
+ char *vbidev;
+
+ int start_channel;
+ int prev_channel;
+ int framerate;
+ int slave_mode;
+
+ double overscan;
+
+ char *config_filename;
+ xmlDocPtr doc;
+};
+
+static unsigned int parse_colour( const char *str )
+{
+ unsigned int a, r, g, b;
+ int ret;
+
+ if( !str || !*str ) return 0;
+
+ if( strlen( str ) == 1 ) return (unsigned int)atoi( str );
+
+ if( str[0] == '0' && str[1] == 'x' ) {
+ ret = sscanf( str, "0x%x", &a );
+ } else {
+ ret = sscanf( str, "%u %u %u %u", &a, &r, &g, &b );
+ }
+
+ if( ret == 1 ) {
+ return a;
+ } else if( ret == 2 ) {
+ return 0xff000000 | ( (a & 0xff) << 8 ) | (r & 0xff);
+ } else if( ret == 3 ) {
+ return 0xff000000 | ( (a & 0xff) << 16 ) | ( (r & 0xff) << 8 ) | ( g & 0xff);
+ } else if( ret == 4 ) {
+ return ( (a & 0xff) << 24 ) | ( (r & 0xff) << 16 ) | ( ( g & 0xff) << 8 ) | (b & 0xff);
+ }
+
+ return 0;
+}
+
+static xmlNodePtr find_option( xmlNodePtr node, const char *optname )
+{
+ while( node ) {
+ if( !xmlStrcasecmp( node->name, BAD_CAST "option" ) ) {
+ xmlChar *name = xmlGetProp( node, BAD_CAST "name" );
+
+ if( name && !xmlStrcasecmp( name, BAD_CAST optname ) ) {
+ xmlFree( name );
+ return node;
+ }
+ if( name ) xmlFree( name );
+ }
+
+ node = node->next;
+ }
+
+ return 0;
+}
+
+static void parse_option( config_t *ct, xmlNodePtr node )
+{
+ xmlChar *name;
+ xmlChar *value;
+
+ name = xmlGetProp( node, BAD_CAST "name" );
+ value = xmlGetProp( node, BAD_CAST "value" );
+
+ if( name && value ) {
+ char *curval = (char *) value;
+
+ if( !xmlStrcasecmp( name, BAD_CAST "WindowGeometry" ) ) {
+ if( ct->geometry ) free( ct->geometry );
+ ct->geometry = strdup( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "InputWidth" ) ) {
+ ct->inputwidth = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "Verbose" ) ) {
+ ct->verbose = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "SaveAndRestorePictureSettings" ) ) {
+ ct->picsaverestore = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "DefaultBrightness" ) ) {
+ ct->brightness = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "DefaultContrast" ) ) {
+ ct->contrast = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "DefaultColour" ) ) {
+ ct->saturation = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "DefaultSaturation" ) ) {
+ ct->saturation = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "DefaultHue" ) ) {
+ ct->hue = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "ColourInvert" ) ) {
+ ct->invert = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "MirrorInput" ) ) {
+ ct->mirror = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "AudioBoost" ) ) {
+ ct->boost = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "QuietScreenshots" ) ) {
+ ct->quiet_screenshots = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "UnmuteVolume" ) ) {
+ ct->unmute_volume = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "Muted" ) ) {
+ ct->muted = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "MuteOnExit" ) ) {
+ ct->mute_on_exit = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "ShowTaglines" ) ) {
+ ct->show_taglines = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "ShowCC" ) ) {
+ ct->cc = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "DFBSendFields" ) ) {
+ ct->send_fields = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "AudioMode" ) ) {
+ if( ct->audiomode ) free( ct->audiomode );
+ ct->audiomode = strdup( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "XMLTVFile" ) ) {
+ if( ct->xmltvfile ) free( ct->xmltvfile );
+ ct->xmltvfile = expand_user_path( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "XMLTVLanguage" ) ) {
+ if( ct->xmltvlanguage ) free( ct->xmltvlanguage );
+ ct->xmltvlanguage = strdup( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "FullscreenPosition" ) ) {
+ if( tolower( curval[ 0 ] ) == 't' ) {
+ ct->fspos = 1;
+ } else if( tolower( curval[ 0 ] ) == 'b' ) {
+ ct->fspos = 2;
+ } else {
+ ct->fspos = 0;
+ }
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "SquarePixels" ) ) {
+ ct->squarepixels = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "Widescreen" ) ) {
+ ct->aspect = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "DebugMode" ) ) {
+ ct->debug = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "V4LDevice" ) ) {
+ if( ct->v4ldev ) free( ct->v4ldev );
+ ct->v4ldev = strdup( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "VBIDevice" ) ) {
+ if( ct->vbidev ) free( ct->vbidev );
+ ct->vbidev = strdup( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "V4LInput" ) ) {
+ ct->inputnum = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "UseXDS" ) ) {
+ ct->use_xds = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "ProcessPriority" ) ) {
+ ct->priority = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "Fullscreen" ) ) {
+ ct->fullscreen = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "AlwaysOnTop" ) ) {
+ ct->alwaysontop = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "FramerateMode" ) ) {
+ ct->framerate = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "Norm" ) ) {
+ if( ct->norm ) free( ct->norm );
+ ct->norm = strdup( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "Frequencies" ) ) {
+ if( ct->freq ) free( ct->freq );
+ ct->freq = strdup( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "TimeFormat" ) ) {
+ if( ct->timeformat ) free( ct->timeformat );
+ ct->timeformat = strdup( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "ScreenShotDir" ) ) {
+ if( ct->ssdir ) free( ct->ssdir );
+ ct->ssdir = expand_user_path( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "ChannelTextFG" ) ) {
+ ct->channel_text_rgb = parse_colour( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "OtherTextFG" ) ) {
+ ct->other_text_rgb = parse_colour( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "PrevChannel" ) ) {
+ ct->prev_channel = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "Channel" ) ) {
+ ct->start_channel = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "NTSCCableMode" ) ) {
+ if( !xmlStrcasecmp( value, BAD_CAST "IRC" ) ) {
+ ct->ntsc_mode = NTSC_CABLE_MODE_IRC;
+ } else if( !xmlStrcasecmp( value, BAD_CAST "HRC" ) ) {
+ ct->ntsc_mode = NTSC_CABLE_MODE_HRC;
+ } else {
+ ct->ntsc_mode = NTSC_CABLE_MODE_STANDARD;
+ }
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "DeinterlaceMethod" ) ) {
+ if( ct->deinterlace_method ) free( ct->deinterlace_method );
+ ct->deinterlace_method = strdup( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "CheckForSignal" ) ) {
+ ct->check_freq_present = atoi( curval );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "Overscan" ) ) {
+ char prevloc[ 256 ];
+
+ /* Make sure floating point numbers are always written to
+ * the config file in "C" locale format.
+ */
+ strncpy( prevloc, setlocale( LC_NUMERIC, NULL ), sizeof prevloc );
+ setlocale( LC_NUMERIC, "C" );
+ ct->overscan = ( atof( curval ) / 2.0 ) / 100.0;
+ if( !isnormal( ct->overscan ) ) {
+ ct->overscan = 0.0;
+ }
+ setlocale( LC_NUMERIC, prevloc );
+ }
+
+ if( !xmlStrcasecmp( name, BAD_CAST "MixerDevice" ) ) {
+ if( ct->mixerdev ) free( ct->mixerdev );
+ ct->mixerdev = strdup( curval );
+ }
+ }
+
+ if( name ) xmlFree( name );
+ if( value ) xmlFree( value );
+}
+
+static void parse_bind( config_t *ct, xmlNodePtr node )
+{
+ xmlChar *command = xmlGetProp( node, BAD_CAST "command" );
+ xmlChar *arg = xmlGetProp( node, BAD_CAST "argument" );
+
+ if( command ) {
+ xmlNodePtr binding = node->xmlChildrenNode;
+
+ while( binding ) {
+ if( !xmlStrcasecmp( binding->name, BAD_CAST "keyboard" ) ) {
+ xmlChar *key = xmlGetProp( binding, BAD_CAST "key" );
+
+ if( key ) {
+ int keycode, command_id;
+
+ keycode = input_string_to_special_key( (const char *) key );
+ if( !keycode ) {
+ keycode = (*key);
+ }
+
+ command_id = tvtime_string_to_command( (const char *) command );
+ if( tvtime_is_menu_command( command_id ) ) {
+ ct->keymapmenu[ keycode ] = command_id;
+ if( arg ) ct->keymapmenu_arg[ keycode ] = strdup( (const char *) arg );
+ } else if( command_id != TVTIME_NOCOMMAND ) {
+ ct->keymap[ keycode ] = command_id;
+ if( arg ) ct->keymap_arg[ keycode ] = strdup( (const char *) arg );
+ }
+ }
+ } else if( !xmlStrcasecmp( binding->name, BAD_CAST "mouse" ) ) {
+ xmlChar *button = xmlGetProp( binding, BAD_CAST "button" );
+ if( button ) {
+ int id = atoi( (const char *) button );
+ if( (id > 0) && (id < MAX_BUTTONS) ) {
+ int command_id = tvtime_string_to_command( (const char *) command );
+ if( tvtime_is_menu_command( command_id ) ) {
+ ct->buttonmapmenu[ id ] = command_id;
+ if( arg ) ct->buttonmapmenu_arg[ id ] = strdup( (const char *) arg );
+ } else {
+ ct->buttonmap[ id ] = command_id;
+ if( arg ) ct->buttonmap_arg[ id ] = strdup( (const char *) arg );
+ }
+ }
+ xmlFree( button );
+ }
+ }
+ binding = binding->next;
+ }
+
+ xmlFree( command );
+ }
+ if( arg ) xmlFree( arg );
+}
+
+static int conf_xml_parse( config_t *ct, char *configFile )
+{
+ xmlDocPtr doc;
+ xmlNodePtr top, node;
+
+ doc = xmlParseFile( configFile );
+ if( !doc ) {
+ lfprintf( stderr, _("Error parsing configuration file %s.\n"),
+ configFile );
+ return 0;
+ }
+
+ top = xmlDocGetRootElement( doc );
+ if( !top ) {
+ lfprintf( stderr, _("No XML root element found in %s.\n"),
+ configFile );
+ xmlFreeDoc( doc );
+ return 0;
+ }
+
+ if( xmlStrcasecmp( top->name, BAD_CAST "tvtime" ) ) {
+ lfprintf( stderr,
+ _("%s is not a tvtime configuration file.\n"),
+ configFile );
+ xmlFreeDoc( doc );
+ return 0;
+ }
+
+ node = top->xmlChildrenNode;
+ while( node ) {
+ if( !xmlIsBlankNode( node ) ) {
+ if( !xmlStrcasecmp( node->name, BAD_CAST "option" ) ) {
+ parse_option( ct, node );
+ } else if( !xmlStrcasecmp( node->name, BAD_CAST "bind" ) ) {
+ parse_bind( ct, node );
+ }
+ }
+ node = node->next;
+ }
+
+ xmlFreeDoc( doc );
+ return 1;
+}
+
+/* Attempt to parse the file for key elements and create them if they don't exist */
+static xmlDocPtr configsave_open( const char *config_filename )
+{
+ xmlDocPtr doc;
+ xmlNodePtr top;
+ int create_file = 0;
+
+ doc = xmlParseFile( config_filename );
+ if( !doc ) {
+ if( file_is_openable_for_read( config_filename ) ) {
+ lfputs( _("Config file cannot be parsed. "
+ "Settings will not be saved.\n"), stderr );
+ return 0;
+ } else {
+ /* Config file doesn't exist, create a new one. */
+ doc = xmlNewDoc( BAD_CAST "1.0" );
+ if( !doc ) {
+ lfputs( _("Could not create new config file.\n"), stderr );
+ return 0;
+ }
+ create_file = 1;
+ }
+ }
+
+ top = xmlDocGetRootElement( doc );
+ if( !top ) {
+ /* Set the DTD */
+ xmlDtdPtr dtd;
+ dtd = xmlNewDtd( doc, BAD_CAST "tvtime",
+ BAD_CAST "-//tvtime//DTD tvtime 1.0//EN",
+ BAD_CAST "http://tvtime.sourceforge.net/DTD/tvtime1.dtd" );
+ doc->intSubset = dtd;
+ if( !doc->children ) {
+ xmlAddChild( (xmlNodePtr) doc, (xmlNodePtr) dtd );
+ } else {
+ xmlAddPrevSibling( doc->children, (xmlNodePtr) dtd );
+ }
+
+ /* Create the root node */
+ top = xmlNewDocNode( doc, 0, BAD_CAST "tvtime", 0 );
+ if( !top ) {
+ lfputs( _("Error creating configuration file.\n"), stderr );
+ xmlFreeDoc( doc );
+ return 0;
+ } else {
+ xmlDocSetRootElement( doc, top );
+ xmlNewProp( top, BAD_CAST "xmlns",
+ BAD_CAST "http://tvtime.sourceforge.net/DTD/" );
+ }
+ }
+
+ if( xmlStrcasecmp( top->name, BAD_CAST "tvtime" ) ) {
+ lfprintf( stderr, _("%s is not a tvtime configuration file.\n"),
+ config_filename );
+ xmlFreeDoc( doc );
+ return 0;
+ }
+
+ xmlKeepBlanksDefault( 0 );
+ xmlSaveFormatFile( config_filename, doc, 1 );
+ if( create_file ) {
+ if( chown( config_filename, getuid(), getgid() ) < 0 ) {
+ lfprintf( stderr, _("Cannot change owner of %s: %s.\n"),
+ config_filename, strerror( errno ) );
+ }
+ }
+ return doc;
+}
+
+static void print_copyright( void )
+{
+ lfputs (_("\n"
+ "tvtime is free software, written by Billy Biggs, Doug Bell and many\n"
+ "others. For details and copying conditions, please see our website\n"
+ "at http://tvtime.net/\n"
+ "\n"
+ "tvtime is Copyright (C) 2001, 2002, 2003 by Billy Biggs, Doug Bell,\n"
+ "Alexander S. Belov, and Achim Schneider.\n"), stderr );
+}
+
+static void print_usage( char **argv )
+{
+ lfprintf( stderr, _("usage: %s [OPTION]...\n\n"), argv[ 0 ] );
+ lfputs( _(" -a, --widescreen 16:9 mode.\n"), stderr );
+ lfputs( _(" -A, --nowidescreen 4:3 mode.\n"), stderr );
+ lfputs( _(" -b, --vbidevice=DEVICE VBI device (defaults to /dev/vbi0).\n"), stderr );
+ lfputs( _(" -c, --channel=CHANNEL Tune to the specified channel on startup.\n"), stderr );
+ lfputs( _(" -d, --device=DEVICE video4linux device (defaults to /dev/video0).\n"), stderr );
+ lfputs( _(" -f, --frequencies=NAME The frequency table to use for the tuner.\n"
+ " (defaults to us-cable).\n\n"
+ " Valid values are:\n"
+ " us-cable\n"
+ " us-cable100\n"
+ " us-broadcast\n"
+ " china-broadcast\n"
+ " southafrica\n"
+ " japan-cable\n"
+ " japan-broadcast\n"
+ " europe\n"
+ " australia\n"
+ " australia-optus\n"
+ " newzealand\n"
+ " france\n"
+ " russia\n"
+ " custom (first run tvtime-scanner)\n\n"), stderr );
+ lfputs( _(" -F, --configfile=FILE Additional config file to load settings from.\n"), stderr );
+ lfputs( _(" -h, --help Show this help message.\n"), stderr );
+ lfputs( _(" -g, --geometry=GEOMETRY Sets the output window size.\n"), stderr );
+ lfputs( _(" -i, --input=INPUTNUM video4linux input number (defaults to 0).\n"), stderr );
+ lfputs( _(" -I, --inputwidth=SAMPLING Horizontal resolution of input\n"
+ " (defaults to 720 pixels).\n"), stderr );
+ lfputs( _(" -k, --slave Disables input handling in tvtime (slave mode).\n"), stderr );
+ lfputs( _(" -m, --fullscreen Start tvtime in fullscreen mode.\n"), stderr );
+ lfputs( _(" -M, --window Start tvtime in window mode.\n"), stderr );
+ lfputs( _(" -n, --norm=NORM The norm to use for the input. tvtime supports:\n"
+ " NTSC, NTSC-JP, SECAM, PAL, PAL-Nc, PAL-M,\n"
+ " PAL-N or PAL-60 (defaults to NTSC).\n"), stderr );
+ lfputs( _(" -s, --showdrops Print stats on frame drops (for debugging).\n"), stderr );
+ lfputs( _(" -S, --saveoptions Save command line options to the config file.\n"), stderr );
+ lfputs( _(" -t, --xmltv=FILE Read XMLTV listings from the given file.\n"), stderr );
+ lfputs( _(" -l, --xmltvlanguage=LANG Use XMLTV data in given language, if available.\n"), stderr );
+ lfputs( _(" -v, --verbose Print debugging messages to stderr.\n"), stderr );
+ lfputs( _(" -X, --display=DISPLAY Use the given X display to connect to.\n"), stderr );
+ lfputs( _(" -x, --mixer=<DEVICE[:CH]>|<DEVICE/CH>\n"
+ " The mixer device and channel to control. The first\n"
+ " variant sets the OSS mixer the second one ALSA.\n"
+ " (defaults to default/Line)\n\n"
+ " Valid channels for OSS are:\n"
+ " vol, bass, treble, synth, pcm, speaker, line,\n"
+ " mic, cd, mix, pcm2, rec, igain, ogain, line1,\n"
+ " line2, line3, dig1, dig2, dig3, phin, phout,\n"
+ " video, radio, monitor\n"), stderr );
+}
+
+static void print_config_usage( char **argv )
+{
+ lfprintf( stderr, _("usage: %s [OPTION]...\n\n"), argv[ 0 ] );
+ lfputs( _(" -a, --widescreen 16:9 mode.\n"), stderr );
+ lfputs( _(" -A, --nowidescreen 4:3 mode.\n"), stderr );
+ lfputs( _(" -b, --vbidevice=DEVICE VBI device (defaults to /dev/vbi0).\n"), stderr );
+ lfputs( _(" -c, --channel=CHANNEL Tune to the specified channel on startup.\n"), stderr );
+ lfputs( _(" -d, --device=DEVICE video4linux device (defaults to /dev/video0).\n"), stderr );
+ lfputs( _(" -f, --frequencies=NAME The frequency table to use for the tuner.\n"
+ " (defaults to us-cable).\n\n"
+ " Valid values are:\n"
+ " us-cable\n"
+ " us-cable100\n"
+ " us-broadcast\n"
+ " china-broadcast\n"
+ " southafrica\n"
+ " japan-cable\n"
+ " japan-broadcast\n"
+ " europe\n"
+ " australia\n"
+ " australia-optus\n"
+ " newzealand\n"
+ " france\n"
+ " russia\n"
+ " custom (first run tvtime-scanner)\n\n"), stderr );
+ lfputs( _(" -F, --configfile=FILE Additional config file to load settings from.\n"), stderr );
+ lfputs( _(" -h, --help Show this help message.\n"), stderr );
+ lfputs( _(" -g, --geometry=GEOMETRY Sets the output window size.\n"), stderr );
+ lfputs( _(" -i, --input=INPUTNUM video4linux input number (defaults to 0).\n"), stderr );
+ lfputs( _(" -I, --inputwidth=SAMPLING Horizontal resolution of input\n"
+ " (defaults to 720 pixels).\n"), stderr );
+ lfputs( _(" -m, --fullscreen Start tvtime in fullscreen mode.\n"), stderr );
+ lfputs( _(" -M, --window Start tvtime in window mode.\n"), stderr );
+ lfputs( _(" -n, --norm=NORM The norm to use for the input. tvtime supports:\n"
+ " NTSC, NTSC-JP, SECAM, PAL, PAL-Nc, PAL-M,\n"
+ " PAL-N or PAL-60 (defaults to NTSC).\n"), stderr );
+ lfputs( _(" -R, --priority=PRI Sets the process priority to run tvtime at.\n"), stderr );
+ lfputs( _(" -t, --xmltv=FILE Read XMLTV listings from the given file.\n"), stderr );
+ lfputs( _(" -l, --xmltvlanguage=LANG Use XMLTV data in given language, if available.\n"), stderr );
+ lfputs( _(" -x, --mixer=<DEVICE[:CH]>|<DEVICE/CH>\n"
+ " The mixer device and channel to control. The first\n"
+ " variant sets the OSS mixer the second one ALSA.\n"
+ " (defaults to default/Line)\n\n"
+ " Valid channels for OSS are:\n"
+ " vol, bass, treble, synth, pcm, speaker, line,\n"
+ " mic, cd, mix, pcm2, rec, igain, ogain, line1,\n"
+ " line2, line3, dig1, dig2, dig3, phin, phout,\n"
+ " video, radio, monitor\n"), stderr );
+}
+
+static void print_scanner_usage( char **argv )
+{
+ lfprintf( stderr, _("usage: %s [OPTION]...\n\n"), argv[ 0 ]);
+ lfputs( _(" -d, --device=DEVICE video4linux device (defaults to /dev/video0).\n"), stderr );
+ lfputs( _(" -F, --configfile=FILE Additional config file to load settings from.\n"), stderr );
+ lfputs( _(" -h, --help Show this help message.\n"), stderr );
+ lfputs( _(" -i, --input=INPUTNUM video4linux input number (defaults to 0).\n"), stderr );
+ lfputs( _(" -n, --norm=NORM The norm to use for the input. tvtime supports:\n"
+ " NTSC, NTSC-JP, SECAM, PAL, PAL-Nc, PAL-M,\n"
+ " PAL-N or PAL-60 (defaults to NTSC).\n"), stderr );
+}
+
+config_t *config_new( void )
+{
+ char *temp_dirname;
+ char *base;
+
+ config_t *ct = malloc( sizeof( config_t ) );
+ if( !ct ) {
+ return 0;
+ }
+
+ /* Default settings. */
+ ct->geometry = strdup( "0x576" );
+ ct->verbose = 0;
+ ct->aspect = 0;
+ ct->squarepixels = 1;
+ ct->debug = 0;
+ ct->fullscreen = 0;
+ ct->alwaysontop = 0;
+ ct->priority = -10;
+ ct->ntsc_mode = 0;
+ ct->send_fields = 0;
+ ct->fspos = 0;
+ ct->picsaverestore = 1;
+ ct->brightness = -1;
+ ct->contrast = -1;
+ ct->saturation = -1;
+ ct->hue = -1;
+ ct->invert = 0;
+ ct->cc = 0;
+ ct->mirror = 0;
+ ct->boost = -1;
+ ct->quiet_screenshots = 0;
+ ct->unmute_volume = -1;
+ ct->muted = 0;
+ ct->mute_on_exit = 0;
+ ct->show_taglines = 1;
+
+ memset( ct->keymap, 0, sizeof( ct->keymap ) );
+ memset( ct->keymap_arg, 0, sizeof( ct->keymap_arg ) );
+ memset( ct->keymapmenu, 0, sizeof( ct->keymapmenu ) );
+ memset( ct->keymapmenu_arg, 0, sizeof( ct->keymapmenu_arg ) );
+ memset( ct->buttonmap, 0, sizeof( ct->buttonmap ) );
+ memset( ct->buttonmap_arg, 0, sizeof( ct->buttonmap_arg ) );
+ memset( ct->buttonmapmenu, 0, sizeof( ct->buttonmapmenu ) );
+ memset( ct->buttonmapmenu_arg, 0, sizeof( ct->buttonmapmenu_arg ) );
+
+ ct->inputwidth = 720;
+ ct->inputnum = 0;
+ ct->v4ldev = strdup( "/dev/video0" );
+ ct->norm = strdup( "ntsc" );
+ ct->freq = strdup( "us-cable" );
+ temp_dirname = getenv( "HOME" );
+ if( temp_dirname ) {
+ ct->ssdir = strdup( temp_dirname );
+ } else {
+ ct->ssdir = 0;
+ }
+ ct->audiomode = strdup( "stereo" );
+ ct->xmltvfile = strdup( "none" );
+ ct->xmltvlanguage = strdup( "none" );
+ ct->timeformat = strdup( "%X" );
+ ct->channel_text_rgb = 0xffffff00; /* opaque yellow */
+ ct->other_text_rgb = 0xfff5deb3; /* opaque wheat */
+
+ ct->uid = getuid();
+
+ ct->mixerdev = strdup( "default/Line" );
+
+ ct->deinterlace_method = strdup( "GreedyH" );
+ ct->check_freq_present = 1;
+
+ ct->use_xds = 0;
+ ct->vbidev = strdup( "/dev/vbi0" );
+
+ ct->start_channel = 1;
+ ct->prev_channel = 1;
+ ct->framerate = FRAMERATE_FULL;
+ ct->slave_mode = 0;
+
+ ct->overscan = 0.0;
+
+ ct->config_filename = 0;
+ ct->doc = 0;
+
+ /* Default key bindings. */
+ ct->keymap[ 0 ] = TVTIME_NOCOMMAND;
+ ct->keymap[ I_ESCAPE ] = TVTIME_QUIT;
+ ct->keymap[ 'q' ] = TVTIME_QUIT;
+ ct->keymap[ I_UP ] = TVTIME_UP;
+ ct->keymap[ I_DOWN ] = TVTIME_DOWN;
+ ct->keymap[ I_LEFT ] = TVTIME_LEFT;
+ ct->keymap[ I_RIGHT ] = TVTIME_RIGHT;
+ ct->keymap[ I_BACKSPACE ] = TVTIME_CHANNEL_PREV;
+ ct->keymap[ 'c' ] = TVTIME_TOGGLE_CC;
+ ct->keymap[ 'm' ] = TVTIME_TOGGLE_MUTE;
+ ct->keymap[ '-' ] = TVTIME_MIXER_DOWN;
+ ct->keymap[ '+' ] = TVTIME_MIXER_UP;
+ ct->keymap[ ' ' ] = TVTIME_AUTO_ADJUST_PICT;
+ ct->keymap[ I_ENTER ] = TVTIME_ENTER;
+ ct->keymap[ I_F1 ] = TVTIME_SHOW_MENU;
+ ct->keymap[ 'h' ] = TVTIME_SHOW_MENU;
+ ct->keymap[ '\t' ] = TVTIME_SHOW_MENU;
+ ct->keymap[ I_F5 ] = TVTIME_PICTURE;
+ ct->keymap[ I_F6 ] = TVTIME_PICTURE_DOWN;
+ ct->keymap[ I_F7 ] = TVTIME_PICTURE_UP;
+ ct->keymap[ 'd' ] = TVTIME_SHOW_STATS;
+ ct->keymap[ 'a' ] = TVTIME_TOGGLE_ASPECT;
+ ct->keymap[ 'f' ] = TVTIME_TOGGLE_FULLSCREEN;
+ ct->keymap[ 'i' ] = TVTIME_TOGGLE_INPUT;
+ ct->keymap[ 's' ] = TVTIME_SCREENSHOT;
+ ct->keymap[ ',' ] = TVTIME_MIXER_TOGGLE_MUTE;
+ ct->keymap[ 'e' ] = TVTIME_TOGGLE_AUDIO_MODE;
+ ct->keymap[ '/' ] = TVTIME_AUTO_ADJUST_WINDOW;
+ ct->keymap[ 'v' ] = TVTIME_TOGGLE_ALWAYSONTOP;
+ ct->keymap[ '0' ] = TVTIME_CHANNEL_0;
+ ct->keymap[ '1' ] = TVTIME_CHANNEL_1;
+ ct->keymap[ '2' ] = TVTIME_CHANNEL_2;
+ ct->keymap[ '3' ] = TVTIME_CHANNEL_3;
+ ct->keymap[ '4' ] = TVTIME_CHANNEL_4;
+ ct->keymap[ '5' ] = TVTIME_CHANNEL_5;
+ ct->keymap[ '6' ] = TVTIME_CHANNEL_6;
+ ct->keymap[ '7' ] = TVTIME_CHANNEL_7;
+ ct->keymap[ '8' ] = TVTIME_CHANNEL_8;
+ ct->keymap[ '9' ] = TVTIME_CHANNEL_9;
+
+ ct->buttonmap[ 1 ] = TVTIME_DISPLAY_INFO;
+ ct->buttonmap[ 2 ] = TVTIME_TOGGLE_MUTE;
+ ct->buttonmap[ 3 ] = TVTIME_SHOW_MENU;
+ ct->buttonmap[ 4 ] = TVTIME_CHANNEL_INC;
+ ct->buttonmap[ 5 ] = TVTIME_CHANNEL_DEC;
+
+ /* Menu keys. */
+ ct->keymapmenu[ I_UP ] = TVTIME_MENU_UP;
+ ct->keymapmenu[ I_DOWN ] = TVTIME_MENU_DOWN;
+ ct->keymapmenu[ I_LEFT ] = TVTIME_MENU_BACK;
+ ct->keymapmenu[ I_RIGHT ] = TVTIME_MENU_ENTER;
+ ct->keymapmenu[ I_ENTER ] = TVTIME_MENU_ENTER;
+ ct->keymapmenu[ I_F1 ] = TVTIME_MENU_EXIT;
+ ct->keymapmenu[ '\t' ] = TVTIME_MENU_EXIT;
+ ct->keymapmenu[ 'q' ] = TVTIME_MENU_EXIT;
+ ct->keymapmenu[ I_ESCAPE ] = TVTIME_MENU_EXIT;
+ ct->buttonmapmenu[ 1 ] = TVTIME_MENU_ENTER;
+ ct->buttonmapmenu[ 3 ] = TVTIME_MENU_ENTER;
+ ct->buttonmapmenu[ 4 ] = TVTIME_MENU_UP;
+ ct->buttonmapmenu[ 5 ] = TVTIME_MENU_DOWN;
+
+ /* Make the ~/.tvtime directory every time on startup, to be safe. */
+ if( asprintf( &temp_dirname, "%s/.tvtime", getenv( "HOME" ) ) < 0 ) {
+ /* FIXME: Clean up ?? */
+ return 0;
+ }
+ mkdir_and_force_owner( temp_dirname, ct->uid, getgid() );
+ free( temp_dirname );
+
+ /* First read in global settings. */
+ asprintf( &base, "%s/tvtime.xml", CONFDIR );
+ if( file_is_openable_for_read( base ) ) {
+ lfprintf( stderr, _("Reading configuration from %s\n"), base );
+ conf_xml_parse( ct, base );
+ }
+ free( base );
+
+ /* Then read in local settings. */
+ asprintf( &base, "%s/.tvtime/tvtime.xml", getenv( "HOME" ) );
+ ct->config_filename = strdup( base );
+ if( file_is_openable_for_read( base ) ) {
+ lfprintf( stderr, _("Reading configuration from %s\n"), base );
+ conf_xml_parse( ct, base );
+ }
+ free( base );
+
+ return ct;
+}
+
+int config_parse_tvtime_command_line( config_t *ct, int argc, char **argv )
+{
+ static struct option long_options[] = {
+ { "help", 0, 0, 'h' },
+ { "verbose", 0, 0, 'v' },
+ { "geometry", 1, 0, 'g' },
+ { "saveoptions", 0, 0, 'S' },
+ { "inputwidth", 1, 0, 'I' },
+ { "driver", 1, 0, 'D' },
+ { "input", 1, 0, 'i' },
+ { "channel", 1, 0, 'c' },
+ { "configfile", 1, 0, 'F' },
+ { "norm", 1, 0, 'n' },
+ { "frequencies", 1, 0, 'f' },
+ { "vbidevice", 1, 0, 'b' },
+ { "device", 1, 0, 'd' },
+ { "mixer", 1, 0, 'x' },
+ { "showdrops", 0, 0, 's' },
+ { "fullscreen", 0, 0, 'm' },
+ { "window", 0, 0, 'M' },
+ { "slave", 0, 0, 'k' },
+ { "widescreen", 0, 0, 'a' },
+ { "nowidescreen", 0, 0, 'A' },
+ { "xmltv", 1, 0, 't' },
+ { "xmltvlanguage", 1, 0, 'l' },
+ { "display", 1, 0, 'X' },
+ { "version", 0, 0, 'Q' },
+ { 0, 0, 0, 0 }
+ };
+ int option_index = 0;
+ int saveoptions = 0;
+ int filename_specified = 0;
+ int c;
+
+ if( argc ) {
+ while( (c = getopt_long( argc, argv, "aAhkmMsSvF:r:g:I:d:b:i:c:n:D:f:x:X:t:l:Qg:",
+ long_options, &option_index )) != -1 ) {
+ switch( c ) {
+ case 'a': ct->aspect = 1; break;
+ case 'A': ct->aspect = 0; break;
+ case 'k': ct->slave_mode = 1; break;
+ case 'm': ct->fullscreen = 1; break;
+ case 'M': ct->fullscreen = 0; break;
+ case 's': ct->debug = 1; break;
+ case 'S': saveoptions = 1; break;
+ case 'v': ct->verbose = 1; break;
+ case 't': if( ct->xmltvfile ) { free( ct->xmltvfile ); }
+ ct->xmltvfile = expand_user_path( optarg ); break;
+ case 'l': if( ct->xmltvlanguage ) { free( ct->xmltvlanguage ); }
+ ct->xmltvlanguage = strdup( optarg ); break;
+ case 'F': if( ct->config_filename ) free( ct->config_filename );
+ filename_specified = 1;
+ ct->config_filename = expand_user_path( optarg );
+ if( ct->config_filename ) {
+ lfprintf
+ ( stderr,
+ _("Reading configuration from %s\n"),
+ ct->config_filename );
+ conf_xml_parse( ct, ct->config_filename );
+ }
+ break;
+ case 'x': if( ct->mixerdev ) { free( ct->mixerdev ); }
+ ct->mixerdev = strdup( optarg ); break;
+ case 'X': setenv( "DISPLAY", optarg, 1 ); break;
+ case 'g': if( ct->geometry ) { free( ct->geometry ); }
+ ct->geometry = strdup( optarg ); break;
+ case 'I': ct->inputwidth = atoi( optarg ); break;
+ case 'd': free( ct->v4ldev ); ct->v4ldev = strdup( optarg ); break;
+ case 'b': free( ct->vbidev ); ct->vbidev = strdup( optarg ); break;
+ case 'i': ct->inputnum = atoi( optarg ); break;
+ case 'c': ct->prev_channel = ct->start_channel;
+ ct->start_channel = atoi( optarg ); break;
+ case 'n': free( ct->norm ); ct->norm = strdup( optarg ); break;
+ case 'f': free( ct->freq ); ct->freq = strdup( optarg ); break;
+ case 'Q': print_copyright(); return 0;
+ default:
+ print_usage( argv );
+ return 0;
+ }
+ }
+ }
+
+ if( !filename_specified ) {
+ char *fifofile = get_tvtime_fifo_filename( config_get_uid( ct ) );
+ int fifofd;
+
+ if( !fifofile ) {
+ lfprintf( stderr, _("%s: Cannot allocate memory.\n"), argv[ 0 ] );
+ return 0;
+ }
+
+ fifofd = open( fifofile, O_WRONLY | O_NONBLOCK );
+ if( fifofd >= 0 ) {
+ lfprintf( stderr,
+ _("Cannot run two instances of tvtime with the same configuration.\n") );
+ return 0;
+ }
+ close( fifofd );
+ }
+
+
+ ct->doc = configsave_open( ct->config_filename );
+
+ if( ct->doc && saveoptions ) {
+ char tempstring[ 32 ];
+ lfputs( _("Saving command line options.\n"), stderr );
+
+ /**
+ * Options that aren't specified on the command line
+ * will match the config file anyway, so save everything that
+ * you can save on the command line.
+ */
+ snprintf( tempstring, sizeof( tempstring ), "%d", ct->aspect );
+ config_save( ct, "Widescreen", tempstring );
+
+ snprintf( tempstring, sizeof( tempstring ), "%d", ct->fullscreen );
+ config_save( ct, "Fullscreen", tempstring );
+
+ snprintf( tempstring, sizeof( tempstring ), "%d", ct->verbose );
+ config_save( ct, "Verbose", tempstring );
+
+ config_save( ct, "WindowGeometry", ct->geometry );
+
+ snprintf( tempstring, sizeof( tempstring ), "%d", ct->inputwidth );
+ config_save( ct, "InputWidth", tempstring );
+
+ config_save( ct, "V4LDevice", ct->v4ldev );
+ config_save( ct, "VBIDevice", ct->vbidev );
+
+ snprintf( tempstring, sizeof( tempstring ), "%d", ct->inputnum );
+ config_save( ct, "V4LInput", tempstring );
+
+ config_save( ct, "Norm", ct->norm );
+ config_save( ct, "Frequencies", ct->freq );
+
+ config_save( ct, "MixerDevice", ct->mixerdev );
+
+ config_save( ct, "XMLTVFile", ct->xmltvfile );
+ config_save( ct, "XMLTVLanguage", ct->xmltvlanguage );
+ }
+
+ return 1;
+}
+
+int config_parse_tvtime_config_command_line( config_t *ct, int argc, char **argv )
+{
+ static struct option long_options[] = {
+ { "help", 0, 0, 'h' },
+ { "geometry", 1, 0, 'g' },
+ { "inputwidth", 1, 0, 'I' },
+ { "driver", 1, 0, 'D' },
+ { "input", 2, 0, 'i' },
+ { "channel", 1, 0, 'c' },
+ { "configfile", 1, 0, 'F' },
+ { "norm", 2, 0, 'n' },
+ { "frequencies", 2, 0, 'f' },
+ { "vbidevice", 2, 0, 'b' },
+ { "device", 2, 0, 'd' },
+ { "mixer", 1, 0, 'x' },
+ { "fullscreen", 0, 0, 'm' },
+ { "window", 0, 0, 'M' },
+ { "widescreen", 0, 0, 'a' },
+ { "nowidescreen", 0, 0, 'A' },
+ { "xmltv", 2, 0, 't' },
+ { "xmltvlanguage", 2, 0, 'l' },
+ { "priority", 2, 0, 'R' },
+ { 0, 0, 0, 0 }
+ };
+ int option_index = 0;
+ int filename_specified = 0;
+ int c;
+
+ if( argc == 1 ) {
+ print_config_usage( argv );
+ return 0;
+ }
+
+ while( (c = getopt_long( argc, argv, "aAhmMF:g:I:d:b:i:c:n:D:f:x:t:l:R:",
+ long_options, &option_index )) != -1 ) {
+ switch( c ) {
+ case 'a': ct->aspect = 1; break;
+ case 'A': ct->aspect = 0; break;
+ case 'm': ct->fullscreen = 1; break;
+ case 'M': ct->fullscreen = 0; break;
+ case 'F': if( ct->config_filename ) free( ct->config_filename );
+ filename_specified = 1;
+ ct->config_filename = expand_user_path( optarg );
+ if( ct->config_filename ) {
+ lfprintf( stderr,
+ _("Reading configuration from %s\n"),
+ ct->config_filename );
+ conf_xml_parse( ct, ct->config_filename );
+ }
+ break;
+ case 'x': if( ct->mixerdev ) { free( ct->mixerdev ); }
+ ct->mixerdev = strdup( optarg ); break;
+ case 'g': if( ct->geometry ) { free( ct->geometry ); }
+ ct->geometry = strdup( optarg ); break;
+ case 'I': ct->inputwidth = atoi( optarg ); break;
+ case 'd': if( !optarg ) {
+ fprintf( stdout, "V4LDevice:%s\n",
+ config_get_v4l_device( ct ) );
+ } else {
+ free( ct->v4ldev );
+ ct->v4ldev = strdup( optarg );
+ }
+ break;
+ case 'b': if( !optarg ) {
+ fprintf( stdout, "VBIDevice:%s\n",
+ config_get_vbi_device( ct ) );
+ } else {
+ free( ct->vbidev );
+ ct->vbidev = strdup( optarg );
+ }
+ break;
+ case 'i': if( !optarg ) {
+ fprintf( stdout, "V4LInput:%d\n",
+ config_get_inputnum( ct ) );
+ } else {
+ ct->inputnum = atoi( optarg );
+ }
+ break;
+ case 'c': ct->prev_channel = ct->start_channel;
+ ct->start_channel = atoi( optarg ); break;
+ case 't': if( !optarg ) {
+ fprintf( stdout, "XMLTVFile:%s\n",
+ config_get_xmltv_file( ct ) );
+ } else {
+ if( ct->xmltvfile ) free( ct->xmltvfile );
+ ct->xmltvfile = expand_user_path( optarg );
+ }
+ break;
+ case 'l': if( !optarg ) {
+ fprintf( stdout, "XMLTVLanguage:%s\n",
+ config_get_xmltv_language( ct ) );
+ } else {
+ if( ct->xmltvlanguage ) free( ct->xmltvlanguage );
+ ct->xmltvlanguage = strdup( optarg );
+ }
+ break;
+ case 'n': if( !optarg ) {
+ fprintf( stdout, "Norm:%s\n", config_get_v4l_norm( ct ) );
+ } else {
+ free( ct->norm );
+ ct->norm = strdup( optarg );
+ }
+ break;
+ case 'f': if( !optarg ) {
+ fprintf( stdout, "Frequencies:%s\n",
+ config_get_v4l_freq( ct ) );
+ } else {
+ free( ct->freq );
+ ct->freq = strdup( optarg );
+ }
+ break;
+ case 'R': if( !optarg ) {
+ fprintf( stdout, "Priority:%d\n",
+ config_get_priority( ct ) );
+ } else {
+ ct->priority = atoi( optarg );
+ }
+ break;
+ default:
+ print_config_usage( argv );
+ return 0;
+ }
+ }
+
+ if( !filename_specified ) {
+ char *fifofile = get_tvtime_fifo_filename( config_get_uid( ct ) );
+ int fifofd;
+
+ if( !fifofile ) {
+ lfprintf( stderr, _("%s: Cannot allocate memory.\n"), argv[ 0 ] );
+ return 0;
+ }
+
+ fifofd = open( fifofile, O_WRONLY | O_NONBLOCK );
+ if( fifofd >= 0 ) {
+ lfprintf( stderr,
+ _("Cannot update configuration while tvtime running.\n") );
+ return 0;
+ }
+ close( fifofd );
+ }
+
+ ct->doc = configsave_open( ct->config_filename );
+
+ if( ct->doc ) {
+ char tempstring[ 32 ];
+
+ /**
+ * Options that aren't specified on the command line
+ * will match the config file anyway, so save everything that
+ * you can save on the command line.
+ */
+ snprintf( tempstring, sizeof( tempstring ), "%d", ct->aspect );
+ config_save( ct, "Widescreen", tempstring );
+
+ snprintf( tempstring, sizeof( tempstring ), "%d", ct->fullscreen );
+ config_save( ct, "Fullscreen", tempstring );
+
+ snprintf( tempstring, sizeof( tempstring ), "%d", ct->verbose );
+ config_save( ct, "Verbose", tempstring );
+
+ config_save( ct, "WindowGeometry", ct->geometry );
+
+ snprintf( tempstring, sizeof( tempstring ), "%d", ct->inputwidth );
+ config_save( ct, "InputWidth", tempstring );
+
+ config_save( ct, "V4LDevice", ct->v4ldev );
+
+ config_save( ct, "VBIDevice", ct->vbidev );
+
+ snprintf( tempstring, sizeof( tempstring ), "%d", ct->inputnum );
+ config_save( ct, "V4LInput", tempstring );
+
+ config_save( ct, "Norm", ct->norm );
+ config_save( ct, "Frequencies", ct->freq );
+
+ config_save( ct, "MixerDevice", ct->mixerdev );
+
+ config_save( ct, "XMLTVFile", ct->xmltvfile );
+ config_save( ct, "XMLTVLanguage", ct->xmltvlanguage );
+
+ snprintf( tempstring, sizeof( tempstring ), "%d", ct->priority );
+ config_save( ct, "ProcessPriority", tempstring );
+ }
+
+ return 1;
+}
+
+int config_parse_tvtime_scanner_command_line( config_t *ct, int argc,
+ char **argv )
+{
+ static struct option long_options[] = {
+ { "help", 0, 0, 'h' },
+ { "height", 1, 0, 'H' },
+ { "input", 1, 0, 'i' },
+ { "configfile", 1, 0, 'F' },
+ { "norm", 1, 0, 'n' },
+ { "device", 1, 0, 'd' },
+ { 0, 0, 0, 0 }
+ };
+ int option_index = 0;
+ int c;
+
+ while( (c = getopt_long( argc, argv, "hF:d:i:n:",
+ long_options, &option_index )) != -1 ) {
+ switch( c ) {
+ case 'F': if( ct->config_filename ) free( ct->config_filename );
+ ct->config_filename = expand_user_path( optarg );
+ if( ct->config_filename ) {
+ lfprintf( stderr,
+ _("Reading configuration from %s\n"),
+ ct->config_filename );
+ conf_xml_parse( ct, ct->config_filename );
+ }
+ break;
+ case 'd': free( ct->v4ldev ); ct->v4ldev = strdup( optarg ); break;
+ case 'i': ct->inputnum = atoi( optarg ); break;
+ case 'n': free( ct->norm ); ct->norm = strdup( optarg ); break;
+ default:
+ print_scanner_usage( argv );
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+
+void config_free_data( config_t *ct )
+{
+ if( ct->doc ) xmlFreeDoc( ct->doc );
+ if( ct->geometry ) free( ct->geometry );
+ if( ct->v4ldev ) free( ct->v4ldev );
+ if( ct->norm ) free( ct->norm );
+ if( ct->freq ) free( ct->freq );
+ if( ct->ssdir ) free( ct->ssdir );
+ if( ct->audiomode ) free( ct->audiomode );
+ if( ct->xmltvfile ) free( ct->xmltvfile );
+ if( ct->xmltvlanguage ) free( ct->xmltvlanguage );
+ if( ct->timeformat ) free( ct->timeformat );
+ if( ct->mixerdev ) free( ct->mixerdev );
+ if( ct->vbidev ) free( ct->vbidev );
+ if( ct->config_filename ) free( ct->config_filename );
+ if( ct->deinterlace_method ) free( ct->deinterlace_method );
+}
+
+void config_delete( config_t *ct )
+{
+ int i;
+
+ for( i = 0; i < 8 * MAX_KEYSYMS; i++ ) {
+ if( ct->keymap_arg[ i ] ) free( ct->keymap_arg[ i ] );
+ if( ct->keymapmenu_arg[ i ] ) free( ct->keymapmenu_arg[ i ] );
+ }
+
+ for( i = 0; i < MAX_BUTTONS; i++ ) {
+ if( ct->buttonmap_arg[ i ] ) free( ct->buttonmap_arg[ i ] );
+ if( ct->buttonmapmenu_arg[ i ] ) free( ct->buttonmapmenu_arg[ i ] );
+ }
+
+ config_free_data( ct );
+ free( ct );
+}
+
+void config_save( config_t *ct, const char *name, const char *value )
+{
+ xmlNodePtr top, node;
+
+ if( !ct->doc ) return;
+
+ top = xmlDocGetRootElement( ct->doc );
+ if( !top ) {
+ return;
+ }
+
+ node = find_option( top->xmlChildrenNode, name );
+ if( !node ) {
+ node = xmlNewTextChild( top, 0, BAD_CAST "option", 0 );
+ xmlNewProp( node, BAD_CAST "name", BAD_CAST name );
+ xmlNewProp( node, BAD_CAST "value", BAD_CAST value );
+ } else {
+ xmlSetProp( node, BAD_CAST "value", BAD_CAST value );
+ }
+
+ xmlKeepBlanksDefault( 0 );
+ xmlSaveFormatFile( ct->config_filename, ct->doc, 1 );
+}
+
+int config_key_to_command( config_t *ct, int key )
+{
+ if( key ) {
+ if( ct->keymap[ MAX_KEYSYMS*((key & 0x70000)>>16) + (key & 0x1ff) ] ) {
+ return ct->keymap[ MAX_KEYSYMS*((key & 0x70000)>>16) + (key & 0x1ff) ];
+ }
+
+ if( isalnum( key & 0x1ff ) ) {
+ return TVTIME_CHANNEL_CHAR;
+ }
+ }
+
+ return TVTIME_NOCOMMAND;
+}
+
+const char *config_key_to_command_argument( config_t *ct, int key )
+{
+ if( key ) {
+ if( ct->keymap_arg[ MAX_KEYSYMS*((key & 0x70000)>>16) + (key & 0x1ff) ] ) {
+ return ct->keymap_arg[ MAX_KEYSYMS*((key & 0x70000)>>16) + (key & 0x1ff) ];
+ }
+ }
+ return 0;
+}
+
+int config_key_to_menu_command( config_t *ct, int key )
+{
+ if( key ) {
+ int cmd;
+
+ if( ct->keymapmenu[ MAX_KEYSYMS*((key & 0x70000)>>16) + (key & 0x1ff) ] ) {
+ return ct->keymapmenu[ MAX_KEYSYMS*((key & 0x70000)>>16) + (key & 0x1ff) ];
+ }
+
+ /* Fall back to standard commands. */
+ cmd = config_key_to_command( ct, key );
+ if( cmd != TVTIME_NOCOMMAND ) {
+ return cmd;
+ }
+
+ if( isalnum( key & 0x1ff ) ) {
+ return TVTIME_CHANNEL_CHAR;
+ }
+ }
+
+ return TVTIME_NOCOMMAND;
+}
+
+const char *config_key_to_menu_command_argument( config_t *ct, int key )
+{
+ if( key ) {
+ if( ct->keymapmenu_arg[ MAX_KEYSYMS*((key & 0x70000)>>16) + (key & 0x1ff) ] ) {
+ return ct->keymapmenu_arg[ MAX_KEYSYMS*((key & 0x70000)>>16) + (key & 0x1ff) ];
+ }
+
+ return config_key_to_command_argument( ct, key );
+ }
+
+ return 0;
+}
+
+int config_command_to_key( config_t *ct, int command )
+{
+ int i;
+
+ for( i = 0; i < 8 * MAX_KEYSYMS; i++ ) {
+ if( ct->keymap[ i ] == command ) return i;
+ }
+
+ return 0;
+}
+
+int config_button_to_command( config_t *ct, int button )
+{
+ if( button < 0 || button >= MAX_BUTTONS ) {
+ return 0;
+ } else {
+ return ct->buttonmap[ button ];
+ }
+}
+
+const char *config_button_to_command_argument( config_t *ct, int button )
+{
+ if( button < 0 || button >= MAX_BUTTONS ) {
+ return 0;
+ } else {
+ return ct->buttonmap_arg[ button ];
+ }
+}
+
+int config_button_to_menu_command( config_t *ct, int button )
+{
+ if( button < 0 || button >= MAX_BUTTONS ) {
+ return 0;
+ } else {
+ if( ct->buttonmapmenu[ button ] ) {
+ return ct->buttonmapmenu[ button ];
+ } else {
+ return ct->buttonmap[ button ];
+ }
+ }
+}
+
+const char *config_button_to_menu_command_argument( config_t *ct, int button )
+{
+ if( button < 0 || button >= MAX_BUTTONS ) {
+ return 0;
+ } else {
+ if( ct->buttonmapmenu_arg[ button ] ) {
+ return ct->buttonmapmenu_arg[ button ];
+ } else {
+ return ct->buttonmap_arg[ button ];
+ }
+ }
+}
+
+int config_get_verbose( config_t *ct )
+{
+ return ct->verbose;
+}
+
+int config_get_send_fields( config_t *ct )
+{
+ return ct->send_fields;
+}
+
+int config_get_debug( config_t *ct )
+{
+ return ct->debug;
+}
+
+const char *config_get_geometry( config_t *ct )
+{
+ return ct->geometry;
+}
+
+int config_get_inputwidth( config_t *ct )
+{
+ return ct->inputwidth;
+}
+
+int config_get_aspect( config_t *ct )
+{
+ return ct->aspect;
+}
+
+int config_get_start_channel( config_t *ct )
+{
+ return ct->start_channel;
+}
+
+int config_get_prev_channel( config_t *ct )
+{
+ return ct->prev_channel;
+}
+
+int config_get_inputnum( config_t *ct )
+{
+ return ct->inputnum;
+}
+
+const char *config_get_deinterlace_method( config_t *ct )
+{
+ return ct->deinterlace_method;
+}
+
+const char *config_get_v4l_device( config_t *ct )
+{
+ return ct->v4ldev;
+}
+
+const char *config_get_v4l_norm( config_t *ct )
+{
+ return ct->norm;
+}
+
+int config_get_fullscreen( config_t *ct )
+{
+ return ct->fullscreen;
+}
+
+int config_get_alwaysontop( config_t *ct )
+{
+ return ct->alwaysontop;
+}
+
+int config_get_priority( config_t *ct )
+{
+ return ct->priority;
+}
+
+const char *config_get_v4l_freq( config_t *ct )
+{
+ return ct->freq;
+}
+
+const char *config_get_vbi_device( config_t *ct )
+{
+ return ct->vbidev;
+}
+
+const char *config_get_timeformat( config_t *ct )
+{
+ return ct->timeformat;
+}
+
+unsigned int config_get_channel_text_rgb( config_t *ct )
+{
+ return ct->channel_text_rgb;
+}
+
+unsigned int config_get_other_text_rgb( config_t *ct )
+{
+ return ct->other_text_rgb;
+}
+
+uid_t config_get_uid( config_t *ct )
+{
+ return ct->uid;
+}
+
+int config_get_usexds( config_t *ct )
+{
+ return ct->use_xds;
+}
+
+int config_get_check_freq_present( config_t *ct )
+{
+ return ct->check_freq_present;
+}
+
+double config_get_overscan( config_t *ct )
+{
+ return ct->overscan;
+}
+
+int config_get_ntsc_cable_mode( config_t *ct )
+{
+ return ct->ntsc_mode;
+}
+
+const char *config_get_screenshot_dir( config_t *ct )
+{
+ return ct->ssdir;
+}
+
+int config_get_framerate_mode( config_t *ct )
+{
+ return ct->framerate;
+}
+
+int config_get_slave_mode( config_t *ct )
+{
+ return ct->slave_mode;
+}
+
+const char *config_get_mixer_device( config_t *ct )
+{
+ return ct->mixerdev;
+}
+
+int config_get_fullscreen_position( config_t *ct )
+{
+ return ct->fspos;
+}
+
+int config_get_save_restore_picture( config_t *ct )
+{
+ return ct->picsaverestore;
+}
+
+int config_get_global_brightness( config_t *ct )
+{
+ return ct->brightness;
+}
+
+int config_get_global_contrast( config_t *ct )
+{
+ return ct->contrast;
+}
+
+int config_get_global_saturation( config_t *ct )
+{
+ return ct->saturation;
+}
+
+int config_get_global_hue( config_t *ct )
+{
+ return ct->hue;
+}
+
+const char *config_get_audio_mode( config_t *ct )
+{
+ return ct->audiomode;
+}
+
+const char *config_get_xmltv_file( config_t *ct )
+{
+ return ct->xmltvfile;
+}
+
+const char *config_get_xmltv_language( config_t *ct )
+{
+ return ct->xmltvlanguage;
+}
+
+int config_get_invert( config_t *ct )
+{
+ return ct->invert;
+}
+
+int config_get_cc( config_t *ct )
+{
+ return ct->cc;
+}
+
+int config_get_mirror( config_t *ct )
+{
+ return ct->mirror;
+}
+
+int config_get_audio_boost( config_t *ct )
+{
+ return ct->boost;
+}
+
+int config_get_quiet_screenshots( config_t *ct )
+{
+ return ct->quiet_screenshots;
+}
+
+int config_get_unmute_volume( config_t *ct )
+{
+ return ct->unmute_volume;
+}
+
+int config_get_muted( config_t *ct )
+{
+ return ct->muted;
+}
+
+int config_get_mute_on_exit( config_t *ct )
+{
+ return ct->mute_on_exit;
+}
+
+int config_get_show_taglines( config_t *ct )
+{
+ return ct->show_taglines;
+}
+
+int config_get_square_pixels( config_t *ct )
+{
+ return ct->squarepixels;
+}
+
diff -Nurp tvtime-1.0.2/src/tvtimeconf.h tvtime-1.0.2-custom/src/tvtimeconf.h
--- tvtime-1.0.2/src/tvtimeconf.h 2005-08-14 19:00:11.000000000 +0200
+++ tvtime-1.0.2-custom/src/tvtimeconf.h 2011-05-29 13:07:28.179040896 +0200
@@ -151,6 +151,7 @@ int config_get_debug( config_t *ct );
const char *config_get_geometry( config_t *ct );
int config_get_inputwidth( config_t *ct );
int config_get_aspect( config_t *ct );
+int config_get_matte( config_t *ct );
int config_get_inputnum( config_t *ct );
const char *config_get_v4l_device( config_t *ct );
const char *config_get_v4l_norm( config_t *ct );
diff -Nurp tvtime-1.0.2/src/videodev2.h tvtime-1.0.2-custom/src/videodev2.h
--- tvtime-1.0.2/src/videodev2.h 2005-01-17 03:36:40.000000000 +0100
+++ tvtime-1.0.2-custom/src/videodev2.h 2011-05-29 13:07:28.215708012 +0200
@@ -16,7 +16,6 @@
#ifdef __KERNEL__
#include <linux/time.h> /* need struct timeval */
#endif
-#include <linux/compiler.h> /* need __user */
/* for kernel versions 2.4.26 and below: */
#ifndef __user
diff -Nurp tvtime-1.0.2/src/videoinput.c tvtime-1.0.2-custom/src/videoinput.c
--- tvtime-1.0.2/src/videoinput.c 2005-09-08 05:13:37.000000000 +0200
+++ tvtime-1.0.2-custom/src/videoinput.c 2011-05-29 13:07:28.232374882 +0200
@@ -376,7 +376,9 @@ uint8_t *videoinput_next_frame( videoinp
wait_for_frame_v4l2( vidin );
+ videoinput_get_aspect( vidin );
cur_buf.type = vidin->capbuffers[ 0 ].vidbuf.type;
+ cur_buf.memory = vidin->capbuffers[ 0 ].vidbuf.memory;
if( ioctl( vidin->grab_fd, VIDIOC_DQBUF, &cur_buf ) < 0 ) {
/* some drivers return EIO when there is no signal */
if( errno != EIO ) {
@@ -1148,6 +1150,22 @@ void videoinput_set_saturation_relative(
}
}
+float videoinput_get_aspect( videoinput_t *vidin )
+{
+ float aspect = 1.0;
+
+ if( vidin->isv4l2 ) {
+ struct v4l2_cropcap cropcap;
+ /* on success 0 is returned */
+ if( !ioctl( vidin->grab_fd, VIDIOC_CROPCAP, &cropcap ) ) {
+ aspect = (float)cropcap.pixelaspect.numerator / (float)cropcap.pixelaspect.denominator;
+ fprintf( stderr, "videoinput: Aspect ratio: %f\n", aspect);
+ }
+ }
+
+ return aspect;
+}
+
static void videoinput_do_mute( videoinput_t *vidin, int mute )
{
if( vidin->hasaudio && mute != vidin->hw_muted ) {
@@ -1269,7 +1287,7 @@ void videoinput_set_tuner_freq( videoinp
}
vidin->change_muted = 1;
- mixer_mute( 1 );
+ mixer->mute( 1 );
videoinput_do_mute( vidin, vidin->user_muted || vidin->change_muted );
vidin->cur_tuner_state = TUNER_STATE_SIGNAL_DETECTED;
vidin->signal_acquire_wait = SIGNAL_ACQUIRE_DELAY;
@@ -1620,7 +1638,7 @@ int videoinput_check_for_signal( videoin
if( vidin->change_muted ) {
vidin->change_muted = 0;
videoinput_do_mute( vidin, vidin->user_muted || vidin->change_muted );
- mixer_mute( 0 );
+ mixer->mute( 0 );
}
break;
}
@@ -1631,7 +1649,7 @@ int videoinput_check_for_signal( videoin
vidin->cur_tuner_state = TUNER_STATE_SIGNAL_LOST;
vidin->signal_recover_wait = SIGNAL_RECOVER_DELAY;
vidin->change_muted = 1;
- mixer_mute( 1 );
+ mixer->mute( 1 );
videoinput_do_mute( vidin, vidin->user_muted || vidin->change_muted );
case TUNER_STATE_SIGNAL_LOST:
if( vidin->signal_recover_wait ) {
diff -Nurp tvtime-1.0.2/src/videoinput.c.orig tvtime-1.0.2-custom/src/videoinput.c.orig
--- tvtime-1.0.2/src/videoinput.c.orig 1970-01-01 01:00:00.000000000 +0100
+++ tvtime-1.0.2-custom/src/videoinput.c.orig 2011-05-29 13:07:28.185707644 +0200
@@ -0,0 +1,1812 @@
+/**
+ * Copyright (C) 2001, 2002, 2003 Billy Biggs <vektor@dumbterm.net>.
+ *
+ * Uses hacky bttv detection code from xawtv:
+ * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include "videodev.h"
+#include "videodev2.h"
+#include "videoinput.h"
+#include "mixer.h"
+
+/**
+ * How long to wait when we lose a signal, or acquire a signal.
+ */
+#define SIGNAL_RECOVER_DELAY 2
+#define SIGNAL_ACQUIRE_DELAY 2
+
+/**
+ * How many seconds to wait before deciding it's a driver problem.
+ */
+#define SYNC_TIMEOUT 3
+
+/**
+ * Maximum number of capture buffers we allow.
+ */
+#define MAX_CAPTURE_BUFFERS 16
+
+const char *videoinput_get_norm_name( int norm )
+{
+ if( norm == VIDEOINPUT_NTSC ) {
+ return "NTSC";
+ } else if( norm == VIDEOINPUT_PAL ) {
+ return "PAL";
+ } else if( norm == VIDEOINPUT_SECAM ) {
+ return "SECAM";
+ } else if( norm == VIDEOINPUT_PAL_NC ) {
+ return "PAL-NC";
+ } else if( norm == VIDEOINPUT_PAL_M ) {
+ return "PAL-M";
+ } else if( norm == VIDEOINPUT_PAL_N ) {
+ return "PAL-N";
+ } else if( norm == VIDEOINPUT_NTSC_JP ) {
+ return "NTSC-JP";
+ } else if( norm == VIDEOINPUT_PAL_60 ) {
+ return "PAL-60";
+ } else {
+ return "ERROR";
+ }
+}
+
+static v4l2_std_id videoinput_get_v4l2_norm( int norm )
+{
+ if( norm == VIDEOINPUT_NTSC ) {
+ return V4L2_STD_NTSC_M;
+ } else if( norm == VIDEOINPUT_PAL ) {
+ return V4L2_STD_PAL;
+ } else if( norm == VIDEOINPUT_SECAM ) {
+ return V4L2_STD_SECAM;
+ } else if( norm == VIDEOINPUT_PAL_NC ) {
+ return V4L2_STD_PAL_Nc;
+ } else if( norm == VIDEOINPUT_PAL_M ) {
+ return V4L2_STD_PAL_M;
+ } else if( norm == VIDEOINPUT_PAL_N ) {
+ return V4L2_STD_PAL_N;
+ } else if( norm == VIDEOINPUT_NTSC_JP ) {
+ return V4L2_STD_NTSC_M_JP;
+ } else if( norm == VIDEOINPUT_PAL_60 ) {
+ return V4L2_STD_PAL_60;
+ } else {
+ return 0;
+ }
+}
+
+static int videoinput_get_v4l1_norm( int norm )
+{
+ if( norm == VIDEOINPUT_NTSC ) {
+ return VIDEO_MODE_NTSC;
+ } else if( norm == VIDEOINPUT_PAL ) {
+ return VIDEO_MODE_PAL;
+ } else if( norm == VIDEOINPUT_SECAM ) {
+ return VIDEO_MODE_SECAM;
+ } else if( norm == VIDEOINPUT_PAL_NC ) {
+ return 3;
+ } else if( norm == VIDEOINPUT_PAL_M ) {
+ return 4;
+ } else if( norm == VIDEOINPUT_PAL_N ) {
+ return 5;
+ } else if( norm == VIDEOINPUT_NTSC_JP ) {
+ return 6;
+ } else {
+ return 0;
+ }
+}
+
+static int videoinput_get_audmode_v4l2( int mode )
+{
+ if( mode == VIDEOINPUT_MONO ) {
+ return V4L2_TUNER_MODE_MONO;
+ } else if( mode == VIDEOINPUT_STEREO ) {
+ return V4L2_TUNER_MODE_STEREO;
+ } else if( mode == VIDEOINPUT_LANG1 ) {
+ return V4L2_TUNER_MODE_LANG1;
+ } else if( mode == VIDEOINPUT_LANG2 ) {
+ return V4L2_TUNER_MODE_LANG2;
+ }
+ return V4L2_TUNER_MODE_MONO;
+}
+
+int videoinput_get_norm_number( const char *name )
+{
+ int i;
+
+ for( i = 0; i < VIDEOINPUT_PAL_60 + 1; i++ ) {
+ if( !strcasecmp( name, videoinput_get_norm_name( i ) ) ) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static int videoinput_get_norm_height( int norm )
+{
+ if( norm == VIDEOINPUT_NTSC || norm == VIDEOINPUT_NTSC_JP || norm == VIDEOINPUT_PAL_M || norm == VIDEOINPUT_PAL_60 ) {
+ return 480;
+ } else {
+ return 576;
+ }
+}
+
+int videoinput_get_time_per_field( int norm )
+{
+ if( norm == VIDEOINPUT_NTSC || norm == VIDEOINPUT_NTSC_JP || norm == VIDEOINPUT_PAL_M || norm == VIDEOINPUT_PAL_60 ) {
+ return 16683;
+ } else {
+ return 20000;
+ }
+}
+
+typedef struct capture_buffer_s
+{
+ struct v4l2_buffer vidbuf;
+ uint8_t *data;
+ int length;
+ int free;
+} capture_buffer_t;
+
+struct videoinput_s
+{
+ int verbose;
+ int grab_fd;
+ char drivername[ 64 ];
+ char shortdriver[ 64 ];
+
+ int numinputs;
+ int curinput;
+ char inputname[ 32 ];
+
+ int width;
+ int height;
+ int maxwidth;
+ int norm;
+ int volume;
+ int amode;
+
+ int isbttv;
+ int isv4l2;
+ int isuyvy;
+
+ int curframe;
+ int numframes;
+
+ int hasaudio;
+ int audiomode;
+ int change_muted;
+ int user_muted;
+ int hw_muted;
+
+ int hastuner;
+ int numtuners;
+ int tunerid;
+ int tunerlow;
+
+ int cur_tuner_state;
+ int signal_recover_wait;
+ int signal_acquire_wait;
+
+ int frames_since_start;
+
+ /* V4L2 capture state. */
+ capture_buffer_t capbuffers[ MAX_CAPTURE_BUFFERS ];
+ int is_streaming;
+
+ /* V4L1 mmap-mode state. */
+ int have_mmap;
+ uint8_t *map;
+ struct video_mmap *grab_buf;
+ struct video_mbuf gb_buffers;
+
+ /* V4L1 read-mode state. */
+ int grab_size;
+ uint8_t *grab_data;
+};
+
+const char *videoinput_get_audio_mode_name( videoinput_t *vidin, int mode )
+{
+ if( mode == VIDEO_SOUND_MONO ) {
+ return "Mono";
+ } else if( mode == VIDEO_SOUND_STEREO ) {
+ return "Stereo";
+ } else if( vidin->norm == VIDEOINPUT_NTSC ) {
+ if( mode == VIDEO_SOUND_LANG2 ) {
+ return "SAP";
+ }
+ } else {
+ if( mode == VIDEO_SOUND_LANG1 ) {
+ return "Language 1";
+ } else if( mode == VIDEO_SOUND_LANG2 ) {
+ return "Language 2";
+ }
+ }
+
+ return "ERROR";
+}
+
+static void videoinput_start_capture_v4l2( videoinput_t *vidin )
+{
+ if( !vidin->is_streaming ) {
+ if( ioctl( vidin->grab_fd, VIDIOC_STREAMON, &vidin->capbuffers[ 0 ].vidbuf.type ) < 0 ) {
+ fprintf( stderr, "videoinput: Driver refuses to start streaming: %s.\n",
+ strerror( errno ) );
+ }
+ vidin->is_streaming = 1;
+ vidin->frames_since_start = 0;
+ }
+}
+
+static void videoinput_stop_capture_v4l2( videoinput_t *vidin )
+{
+ if( vidin->is_streaming ) {
+ if( ioctl( vidin->grab_fd, VIDIOC_STREAMOFF, &vidin->capbuffers[ 0 ].vidbuf.type ) < 0 ) {
+ fprintf( stderr, "videoinput: Driver refuses to stop streaming: %s.\n",
+ strerror( errno ) );
+ }
+ vidin->is_streaming = 0;
+ }
+}
+
+static int alarms;
+
+static void sigalarm( int signal )
+{
+ alarms++;
+}
+
+static void siginit( void )
+{
+ struct sigaction act, old;
+
+ memset( &act, 0, sizeof( act ) );
+ act.sa_handler = sigalarm;
+ sigemptyset( &act.sa_mask );
+ sigaction( SIGALRM, &act, &old );
+}
+
+static void free_frame( videoinput_t *vidin, int frameid )
+{
+ if( vidin->isv4l2 ) {
+ if( ioctl( vidin->grab_fd, VIDIOC_QBUF, &vidin->capbuffers[ frameid ].vidbuf ) < 0 ) {
+ fprintf( stderr, "videoinput: Can't free frame %d: %s\n",
+ frameid, strerror( errno ) );
+ }
+ vidin->capbuffers[ frameid ].free = 1;
+ } else {
+ if( ioctl( vidin->grab_fd, VIDIOCMCAPTURE, vidin->grab_buf + frameid ) < 0 ) {
+ fprintf( stderr, "videoinput: Can't free frame %d: %s\n",
+ frameid, strerror( errno ) );
+ }
+ }
+}
+
+void videoinput_free_frame( videoinput_t *vidin, int frameid )
+{
+ if( vidin->isv4l2 || vidin->have_mmap ) {
+ free_frame( vidin, frameid );
+ }
+}
+
+static void videoinput_free_all_frames( videoinput_t *vidin )
+{
+ int i;
+
+ for( i = 0; i < vidin->numframes; i++ ) {
+ free_frame( vidin, i );
+ }
+ vidin->curframe = 0;
+}
+
+static void wait_for_frame_v4l1( videoinput_t *vidin, int frameid )
+{
+ alarms = 0;
+ alarm( SYNC_TIMEOUT );
+ if( ioctl( vidin->grab_fd, VIDIOCSYNC, vidin->grab_buf + frameid ) < 0 ) {
+ fprintf( stderr, "videoinput: Can't wait for frame %d: %s\n",
+ frameid, strerror( errno ) );
+ }
+ if( alarms ) {
+ fprintf( stderr, "\n"
+ " Your capture card driver: %s\n"
+ " is taking too long to provide frames to tvtime. This could be due\n"
+ " either to a broken capture card, a signal that has become unstable\n"
+ " or very noisy, or a driver misconfiguration.\n"
+ "\n"
+ " Please report this on our bugs page: " PACKAGE_BUGREPORT "\n\n",
+ vidin->drivername );
+ }
+ alarm( 0 );
+}
+
+static void wait_for_frame_v4l2( videoinput_t * vidin )
+{
+ struct timeval timeout;
+ fd_set rdset;
+ int n;
+
+ FD_ZERO( &rdset );
+ FD_SET( vidin->grab_fd, &rdset );
+
+ timeout.tv_sec = SYNC_TIMEOUT;
+ timeout.tv_usec = 0;
+
+ n = select( vidin->grab_fd + 1, &rdset, 0, 0, &timeout );
+ if( n == -1 ) {
+ fprintf( stderr, "videoinput: Error waiting for frame: %s\n",
+ strerror( errno ) );
+ } else if( n == 0 ) {
+ sigalarm( 0 );
+ }
+}
+
+uint8_t *videoinput_next_frame( videoinput_t *vidin, int *frameid )
+{
+ if( vidin->isv4l2 ) {
+ struct v4l2_buffer cur_buf;
+
+ wait_for_frame_v4l2( vidin );
+
+ videoinput_get_aspect( vidin );
+ cur_buf.type = vidin->capbuffers[ 0 ].vidbuf.type;
+ if( ioctl( vidin->grab_fd, VIDIOC_DQBUF, &cur_buf ) < 0 ) {
+ /* some drivers return EIO when there is no signal */
+ if( errno != EIO ) {
+ fprintf( stderr, "videoinput: Can't read frame. Error was: %s (%d).\n",
+ strerror( errno ), vidin->frames_since_start );
+ }
+ /* We must now restart capture. */
+ videoinput_stop_capture_v4l2( vidin );
+ videoinput_free_all_frames( vidin );
+ videoinput_start_capture_v4l2( vidin );
+ *frameid = -1;
+ return 0;
+ }
+ vidin->frames_since_start++;
+ vidin->capbuffers[ cur_buf.index ].free = 0;
+ *frameid = cur_buf.index;
+ return vidin->capbuffers[ cur_buf.index ].data;
+ } else {
+ if( vidin->have_mmap ) {
+ uint8_t *cur;
+ wait_for_frame_v4l1( vidin, vidin->curframe );
+ cur = vidin->map + vidin->gb_buffers.offsets[ vidin->curframe ];
+ *frameid = vidin->curframe;
+ vidin->curframe = ( vidin->curframe + 1 ) % vidin->numframes;
+ return cur;
+ } else {
+ int rc = read( vidin->grab_fd, vidin->grab_data, vidin->grab_size );
+ if( vidin->grab_size != rc ) {
+ fprintf( stderr, "videoinput: Can't read frame. Returned %d, error: %s.\n",
+ rc, strerror( errno ) );
+ return 0;
+ } else {
+ return vidin->grab_data;
+ }
+ }
+ }
+}
+
+int videoinput_buffer_invalid( videoinput_t *vidin, int frameid )
+{
+ if( !vidin->isv4l2 ) {
+ return 0;
+ } else {
+ return vidin->capbuffers[ frameid ].free;
+ }
+}
+
+videoinput_t *videoinput_new( const char *v4l_device, int capwidth,
+ int volume, int norm, int verbose, char *error_string )
+{
+ videoinput_t *vidin = malloc( sizeof( videoinput_t ) );
+ struct video_capability caps_v4l1;
+ struct v4l2_capability caps_v4l2;
+ struct video_picture grab_pict;
+ struct video_window grab_win;
+ int i;
+
+ if( capwidth & 1 ) {
+ capwidth -= 1;
+ if( verbose ) {
+ fprintf( stderr, "videoinput: Odd values for input width not allowed, "
+ "using %d instead.\n", capwidth );
+ }
+ }
+
+ if( !vidin ) {
+ fprintf( stderr, "videoinput: Cannot allocate memory.\n" );
+ sprintf( error_string, "%s", strerror( ENOMEM ) );
+ return 0;
+ }
+
+ siginit();
+
+ vidin->curframe = 0;
+ vidin->verbose = verbose;
+ vidin->norm = norm;
+ vidin->volume = volume;
+ vidin->amode = 0;
+ vidin->height = videoinput_get_norm_height( norm );
+ vidin->cur_tuner_state = TUNER_STATE_NO_SIGNAL;
+
+ vidin->hastuner = 0;
+ vidin->numtuners = 0;
+ vidin->tunerid = 0;
+ vidin->tunerlow = 0;
+
+ vidin->isv4l2 = 0;
+ vidin->isbttv = 0;
+ vidin->isuyvy = 0;
+
+ vidin->signal_recover_wait = 0;
+ vidin->signal_acquire_wait = 0;
+ vidin->change_muted = 1;
+ vidin->user_muted = 0;
+ vidin->hw_muted = 1;
+ vidin->hasaudio = 1;
+ vidin->audiomode = 0;
+ vidin->curinput = 0;
+ vidin->have_mmap = 0;
+ vidin->is_streaming = 0;
+
+ memset( vidin->inputname, 0, sizeof( vidin->inputname ) );
+ memset( vidin->drivername, 0, sizeof( vidin->drivername ) );
+ memset( vidin->shortdriver, 0, sizeof( vidin->shortdriver ) );
+
+ /* First, open the device. */
+ vidin->grab_fd = open( v4l_device, O_RDWR );
+ if( vidin->grab_fd < 0 ) {
+ fprintf( stderr, "videoinput: Cannot open capture device %s: %s\n",
+ v4l_device, strerror( errno ) );
+ sprintf( error_string, "%s", strerror( errno ) );
+ free( vidin );
+ return 0;
+ }
+
+ /**
+ * Next, ask for its capabilities. This will also confirm it's a V4L2
+ * device.
+ */
+ if( ioctl( vidin->grab_fd, VIDIOC_QUERYCAP, &caps_v4l2 ) < 0 ) {
+ /* Can't get V4L2 capabilities, maybe this is a V4L1 device? */
+ if( ioctl( vidin->grab_fd, VIDIOCGCAP, &caps_v4l1 ) < 0 ) {
+ fprintf( stderr, "videoinput: %s is not a video4linux device.\n",
+ v4l_device );
+ sprintf( error_string, "Not a video4linux device" );
+ close( vidin->grab_fd );
+ free( vidin );
+ return 0;
+ } else if( vidin->verbose ) {
+ fprintf( stderr, "videoinput: Using video4linux driver '%s'.\n"
+ "videoinput: Card type is %x, audio %d.\n",
+ caps_v4l1.name, caps_v4l1.type, caps_v4l1.audios );
+ }
+ snprintf( vidin->drivername, sizeof( vidin->drivername ),
+ "%s", caps_v4l1.name );
+ snprintf( vidin->shortdriver, sizeof( vidin->shortdriver ),
+ "%s", caps_v4l1.name );
+ } else {
+ if( vidin->verbose ) {
+ fprintf( stderr, "videoinput: Using video4linux2 driver '%s', card '%s' (bus %s).\n"
+ "videoinput: Version is %u, capabilities %x.\n",
+ caps_v4l2.driver, caps_v4l2.card, caps_v4l2.bus_info,
+ caps_v4l2.version, caps_v4l2.capabilities );
+ }
+ vidin->isv4l2 = 1;
+ snprintf( vidin->drivername, sizeof( vidin->drivername ),
+ "%s [%s/%s/%u]",
+ caps_v4l2.driver, caps_v4l2.card,
+ caps_v4l2.bus_info, caps_v4l2.version );
+ snprintf( vidin->shortdriver, sizeof( vidin->shortdriver ),
+ "%s", caps_v4l2.driver );
+ }
+
+ if( vidin->isv4l2 ) {
+ struct v4l2_input in;
+
+ vidin->numinputs = 0;
+ in.index = vidin->numinputs;
+
+ /**
+ * We have to enumerate all of the inputs just to know how many
+ * there are.
+ */
+ while( ioctl( vidin->grab_fd, VIDIOC_ENUMINPUT, &in ) >= 0 ) {
+ vidin->numinputs++;
+ in.index = vidin->numinputs;
+ }
+
+ if( !vidin->numinputs ) {
+ fprintf( stderr, "videoinput: No inputs available on "
+ "video4linux2 device '%s'.\n", v4l_device );
+ sprintf( error_string, "No inputs available" );
+ close( vidin->grab_fd );
+ free( vidin );
+ return 0;
+ }
+ } else {
+ /* The capabilities should tell us how many inputs this card has. */
+ vidin->numinputs = caps_v4l1.channels;
+ if( vidin->numinputs == 0 ) {
+ fprintf( stderr, "videoinput: No inputs available on "
+ "video4linux device '%s'.\n", v4l_device );
+ sprintf( error_string, "No inputs available" );
+ close( vidin->grab_fd );
+ free( vidin );
+ return 0;
+ }
+ }
+
+ /* Check if this is a bttv-based card. Code taken from xawtv. */
+#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
+ /* dirty hack time / v4l design flaw -- works with bttv only
+ * this adds support for a few less common PAL versions */
+ if( !(ioctl( vidin->grab_fd, BTTV_VERSION, &i ) < 0) ) {
+ vidin->isbttv = 1;
+ }
+#undef BTTV_VERSION
+
+ if( !vidin->isv4l2 ) {
+ if( !vidin->isbttv && norm > VIDEOINPUT_SECAM ) {
+ fprintf( stderr, "videoinput: Capture card '%s' does not seem to use the bttv driver.\n"
+ "videoinput: The norm %s is only supported in V4L1 for bttv-supported cards.\n",
+ v4l_device, videoinput_get_norm_name( norm ) );
+ sprintf( error_string, "%s unsupported by %s", videoinput_get_norm_name( norm ), vidin->shortdriver );
+ close( vidin->grab_fd );
+ free( vidin );
+ return 0;
+ }
+
+ if( norm > VIDEOINPUT_NTSC_JP ) {
+ fprintf( stderr, "videoinput: Detected only a V4L1 driver. The PAL-60 norm\n"
+ "videoinput: is only available if driver supports V4L2.\n" );
+ sprintf( error_string, "%s unsupported by %s", videoinput_get_norm_name( norm ), vidin->shortdriver );
+ close( vidin->grab_fd );
+ free( vidin );
+ return 0;
+ }
+ }
+
+ /* On initialization, set to input 0. This is just to start things up. */
+ videoinput_set_input_num( vidin, 0 );
+
+ /* Test for audio support. */
+ if( !vidin->isv4l2 ) {
+ struct video_audio audio;
+
+ if( ( ioctl( vidin->grab_fd, VIDIOCGAUDIO, &audio ) < 0 ) && vidin->verbose ) {
+ vidin->hasaudio = 0;
+ fprintf( stderr, "videoinput: No audio capability detected (asked for audio, got '%s').\n",
+ strerror( errno ) );
+ } else if( verbose ) {
+ fprintf( stderr, "videoinput: Audio supports " );
+ if( audio.flags & VIDEO_AUDIO_MUTE ) {
+ fprintf( stderr, "Mute " );
+ } else if( audio.flags & VIDEO_AUDIO_MUTABLE ) {
+ fprintf( stderr, "Mutable " );
+ } else if( audio.flags & VIDEO_AUDIO_VOLUME ) {
+ fprintf( stderr, "Volume " );
+ } else if( audio.flags & VIDEO_AUDIO_BASS ) {
+ fprintf( stderr, "Bass " );
+ } else if( audio.flags & VIDEO_AUDIO_TREBLE ) {
+ fprintf( stderr, "Treble " );
+ }
+ fprintf( stderr, "\n" );
+ }
+ }
+
+ /* Set to stereo by default. */
+ videoinput_set_audio_mode( vidin, VIDEO_SOUND_STEREO );
+
+ /**
+ * Once we're here, we've set the hardware norm. Now confirm that
+ * our width is acceptable by again asking what the capabilities
+ * are.
+ */
+ if( vidin->isv4l2 ) {
+ struct v4l2_format imgformat;
+
+ imgformat.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ memset( &(imgformat.fmt.pix), 0, sizeof( struct v4l2_pix_format ) );
+ imgformat.fmt.pix.width = capwidth;
+ imgformat.fmt.pix.height = vidin->height;
+ imgformat.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ imgformat.fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+ if( ioctl( vidin->grab_fd, VIDIOC_S_FMT, &imgformat ) < 0 ) {
+ /* Try for UYVY instead. */
+ imgformat.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+ if( ioctl( vidin->grab_fd, VIDIOC_S_FMT, &imgformat ) < 0 ) {
+
+ fprintf( stderr, "\n"
+ " Your capture card driver: %s\n"
+ " does not support studio-quality colour images required by tvtime.\n"
+ " This is a hardware limitation of some cards including many\n"
+ " low-quality webcams. Please select a different video device to use\n"
+ " with the command line option --device.\n"
+ "\n"
+ " Message from the card was: %s\n\n",
+ vidin->drivername, strerror( errno ) );
+
+ sprintf( error_string, "%s: %s", vidin->shortdriver, strerror( errno ) );
+ close( vidin->grab_fd );
+ free( vidin );
+ return 0;
+ }
+ vidin->isuyvy = 1;
+ }
+
+ if( vidin->height != imgformat.fmt.pix.height ) {
+ fprintf( stderr, "\n"
+ " Your capture card driver: %s\n"
+ " does not support full size studio-quality images required by tvtime.\n"
+ " This is true for many low-quality webcams. Please select a\n"
+ " different video device for tvtime to use with the command line\n"
+ " option --device.\n\n", vidin->drivername );
+ sprintf( error_string, "Frames too short from %s", vidin->shortdriver );
+ close( vidin->grab_fd );
+ free( vidin );
+ return 0;
+ }
+
+ if( capwidth != imgformat.fmt.pix.width && verbose ) {
+ fprintf( stderr, "videoinput: Width %d too high, using %d "
+ "instead as suggested by the driver.\n",
+ capwidth, imgformat.fmt.pix.width );
+ }
+ vidin->width = imgformat.fmt.pix.width;
+
+ /* Query the maximum input width - I wish there was a nicer way */
+ imgformat.fmt.pix.width = 10000;
+ if( ioctl( vidin->grab_fd, VIDIOC_TRY_FMT, &imgformat ) < 0 ) {
+ vidin->maxwidth = 768;
+ if( verbose ) {
+ fprintf( stderr, "videoinput: Your capture card driver does "
+ "not implement the TRY_FMT query.\n"
+ "Setting maximum input width to 768.\n" );
+ }
+ } else {
+ vidin->maxwidth = imgformat.fmt.pix.width;
+ if( verbose ) {
+ fprintf( stderr, "videoinput: Maximum input width: %d "
+ "pixels.\n", vidin->maxwidth );
+ }
+ }
+
+ } else {
+ if( ioctl( vidin->grab_fd, VIDIOCGCAP, &caps_v4l1 ) < 0 ) {
+ fprintf( stderr, "videoinput: video4linux device '%s' refuses "
+ "to provide set capability information, giving up.\n",
+ v4l_device );
+ sprintf( error_string, "%s: %s", vidin->shortdriver, strerror( errno ) );
+ close( vidin->grab_fd );
+ free( vidin );
+ return 0;
+ }
+ vidin->maxwidth = caps_v4l1.maxwidth;
+ if( verbose ) {
+ fprintf( stderr, "videoinput: Maximum input width: %d pixels.\n",
+ vidin->maxwidth );
+ }
+ if( capwidth > caps_v4l1.maxwidth ) {
+ if( verbose ) {
+ fprintf( stderr, "videoinput: Width %d too high, using %d "
+ "instead as suggested by the driver.\n",
+ capwidth, caps_v4l1.maxwidth );
+ }
+ capwidth = caps_v4l1.maxwidth;
+ }
+ if( capwidth < caps_v4l1.minwidth ) {
+ if( verbose ) {
+ fprintf( stderr, "videoinput: Width %d too low, using %d "
+ "instead as suggested by the driver.\n",
+ capwidth, caps_v4l1.minwidth );
+ }
+ capwidth = caps_v4l1.minwidth;
+ }
+ vidin->width = capwidth;
+
+
+ /* Set the format using the SPICT ioctl. */
+ if( ioctl( vidin->grab_fd, VIDIOCGPICT, &grab_pict ) < 0 ) {
+ fprintf( stderr, "videoinput: Can't get image information from the card, unable to "
+ "process the output: %s.\n", strerror( errno ) );
+ fprintf( stderr, "videoinput: Please post a bug report to " PACKAGE_BUGREPORT
+ " indicating your capture card, driver, and the error message above.\n" );
+ sprintf( error_string, "%s: %s", vidin->shortdriver, strerror( errno ) );
+ close( vidin->grab_fd );
+ free( vidin );
+ return 0;
+ }
+
+ grab_pict.depth = 16;
+ grab_pict.palette = VIDEO_PALETTE_YUV422;
+ if( ioctl( vidin->grab_fd, VIDIOCSPICT, &grab_pict ) < 0 ) {
+ /* Try for UYVY instead. */
+ grab_pict.palette = VIDEO_PALETTE_UYVY;
+ if( ioctl( vidin->grab_fd, VIDIOCSPICT, &grab_pict ) < 0 ) {
+ fprintf( stderr, "\n"
+ " Your capture card driver: %s\n"
+ " does not support studio-quality colour images required by tvtime.\n"
+ " This is a hardware limitation of some cards including many\n"
+ " low-quality webcams. Please select a different video device to use\n"
+ " with the command line option --device.\n"
+ "\n"
+ " Message from the card was: %s\n\n",
+ vidin->drivername, strerror( errno ) );
+ sprintf( error_string, "Format unsupported by %s", vidin->shortdriver );
+ close( vidin->grab_fd );
+ free( vidin );
+ return 0;
+ }
+ vidin->isuyvy = 1;
+ }
+ if( vidin->verbose ) {
+ fprintf( stderr, "videoinput: Brightness %d, hue %d, colour %d, contrast %d\n"
+ "videoinput: Whiteness %d, depth %d, palette %d.\n",
+ grab_pict.brightness, grab_pict.hue, grab_pict.colour, grab_pict.contrast,
+ grab_pict.whiteness, grab_pict.depth, grab_pict.palette );
+ }
+
+ /* Set and get the window settings. */
+ memset( &grab_win, 0, sizeof( struct video_window ) );
+ grab_win.width = vidin->width;
+ grab_win.height = vidin->height;
+ if( ioctl( vidin->grab_fd, VIDIOCSWIN, &grab_win ) < 0 ) {
+ fprintf( stderr, "videoinput: Failed to set the V4L window size (capture width and height): %s\n",
+ strerror( errno ) );
+ sprintf( error_string, "%s: %s", vidin->shortdriver, strerror( errno ) );
+ close( vidin->grab_fd );
+ free( vidin );
+ return 0;
+ }
+ }
+
+ if( vidin->isv4l2 ) {
+ struct v4l2_requestbuffers req;
+
+ /**
+ * Ask Video Device for Buffers
+ */
+ req.count = 4;
+ req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ req.memory = V4L2_MEMORY_MMAP;
+
+ if( ioctl( vidin->grab_fd, VIDIOC_REQBUFS, &req ) < 0 ) {
+ fprintf( stderr, "videoinput: Card failed to allocate capture buffers: %s\n",
+ strerror( errno ) );
+ sprintf( error_string, "%s: %s", vidin->shortdriver, strerror( errno ) );
+ close( vidin->grab_fd );
+ free( vidin );
+ return 0;
+ }
+ vidin->numframes = req.count;
+
+ if( vidin->numframes < 1 ) {
+ fprintf( stderr, "videoinput: No capture buffers available from card.\n" );
+ sprintf( error_string, "%s: No capture buffers", vidin->shortdriver );
+ close( vidin->grab_fd );
+ free( vidin );
+ return 0;
+ } else if( vidin->numframes > 4 ) {
+ /* If we got more frames than we asked for, limit to 4 for now. */
+ if( vidin->verbose ) {
+ fprintf( stderr, "videoinput: Capture card provides %d buffers, but we only need 4.\n",
+ vidin->numframes );
+ }
+ vidin->numframes = 4;
+ }
+
+ /**
+ * Query each buffer and map it to the video device
+ */
+ for( i = 0; i < vidin->numframes; i++ ) {
+ struct v4l2_buffer *vidbuf = &(vidin->capbuffers[ i ].vidbuf);
+
+ vidbuf->index = i;
+ vidbuf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ vidbuf->memory = V4L2_MEMORY_MMAP;
+ if( ioctl( vidin->grab_fd, VIDIOC_QUERYBUF, vidbuf ) < 0 ) {
+ fprintf( stderr, "videoinput: Can't get information about buffer %d: %s.\n",
+ i, strerror( errno ) );
+ sprintf( error_string, "%s: %s", vidin->shortdriver, strerror( errno ) );
+ close( vidin->grab_fd );
+ free( vidin );
+ return 0;
+ }
+
+ vidin->capbuffers[ i ].data = mmap( 0, vidbuf->length,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED, vidin->grab_fd,
+ vidbuf->m.offset );
+ if( vidin->capbuffers[ i ].data == MAP_FAILED ) {
+ fprintf( stderr, "videoinput: Can't map buffer %d: %s.\n",
+ i, strerror( errno ) );
+ sprintf( error_string, "%s: %s", vidin->shortdriver, strerror( errno ) );
+ close( vidin->grab_fd );
+ free( vidin );
+ return 0;
+ }
+ vidin->capbuffers[ i ].length = vidbuf->length;
+ }
+ videoinput_free_all_frames( vidin );
+
+ /**
+ * Tell video stream to begin capture.
+ */
+ videoinput_start_capture_v4l2( vidin );
+
+ return vidin;
+ } else {
+ /* Try to set up mmap-based capture. */
+ if( ioctl( vidin->grab_fd, VIDIOCGMBUF, &(vidin->gb_buffers) ) < 0 ) {
+ fprintf( stderr, "videoinput: Can't get capture buffer properties. No mmap support?\n"
+ "Please post a bug report about this to " PACKAGE_BUGREPORT "\n"
+ "with your card, driver and this error message: %s.\n", strerror( errno ) );
+ fprintf( stderr, "videoinput: Will try to fall back to (untested) read()-based capture..\n" );
+ } else {
+ /* If we got more frames than we asked for, limit to 4 for now. */
+ if( vidin->gb_buffers.frames > 4 ) {
+ if( vidin->verbose ) {
+ fprintf( stderr, "videoinput: Capture card provides %d buffers, but we only need 4.\n",
+ vidin->gb_buffers.frames );
+ }
+ vidin->numframes = 4;
+ } else {
+ vidin->numframes = vidin->gb_buffers.frames;
+ }
+
+ vidin->grab_buf = malloc( sizeof( struct video_mmap ) *
+ vidin->numframes );
+ if( !vidin->grab_buf ) {
+ fprintf( stderr, "videoinput: Can't allocate memory.\n" );
+ sprintf( error_string, "%s", strerror( ENOMEM ) );
+ close( vidin->grab_fd );
+ free( vidin );
+ return 0;
+ }
+
+ /* Setup mmap capture buffers. */
+ for( i = 0; i < vidin->numframes; i++ ) {
+ if( vidin->isuyvy ) {
+ vidin->grab_buf[ i ].format = VIDEO_PALETTE_UYVY;
+ } else {
+ vidin->grab_buf[ i ].format = VIDEO_PALETTE_YUV422;
+ }
+ vidin->grab_buf[ i ].frame = i;
+ vidin->grab_buf[ i ].width = vidin->width;
+ vidin->grab_buf[ i ].height = vidin->height;
+ }
+
+ vidin->map = mmap( 0, vidin->gb_buffers.size, PROT_READ|PROT_WRITE,
+ MAP_SHARED, vidin->grab_fd, 0 );
+ if( vidin->map != MAP_FAILED ) {
+ vidin->have_mmap = 1;
+ videoinput_free_all_frames( vidin );
+ return vidin;
+ } else {
+ fprintf( stderr, "videoinput: mmap() failed. Will try to fall back to "
+ "(untested) read()-based capture..\n" );
+ }
+ }
+
+ /* Fallback to read(). THIS CODE IS UNTESTED. IS THIS EVEN FINISHED? */
+ if( vidin->verbose ) {
+ fprintf( stderr, "videoinput: No mmap support available, using read().\n" );
+ }
+
+ vidin->have_mmap = 0;
+ vidin->grab_size = (capwidth * vidin->height * 2);
+ vidin->grab_data = malloc( vidin->grab_size );
+ vidin->numframes = 2;
+
+ return vidin;
+ }
+}
+
+void videoinput_delete( videoinput_t *vidin )
+{
+ /* Mute audio on exit. */
+ videoinput_mute( vidin, 1 );
+
+ if( vidin->isv4l2 ) {
+ int i;
+
+ videoinput_stop_capture_v4l2( vidin );
+ videoinput_free_all_frames( vidin );
+
+ for( i = 0; i < vidin->numframes; i++ ) {
+ munmap( vidin->capbuffers[ i ].data, vidin->capbuffers[ i ].length );
+ }
+ } else {
+ if( vidin->have_mmap ) {
+ munmap( vidin->map, vidin->gb_buffers.size );
+ free( vidin->grab_buf );
+ } else {
+ free( vidin->grab_data );
+ }
+ }
+
+ close( vidin->grab_fd );
+ free( vidin );
+}
+
+static double videoinput_get_control_v4l2( videoinput_t *vidin, uint32_t id )
+{
+ struct v4l2_queryctrl query;
+
+ query.id = id;
+ if( ioctl( vidin->grab_fd, VIDIOC_QUERYCTRL, &query ) >= 0 && !(query.flags & V4L2_CTRL_FLAG_DISABLED) ) {
+ struct v4l2_control control;
+ control.id = id;
+ if( ioctl( vidin->grab_fd, VIDIOC_G_CTRL, &control ) >= 0 ) {
+ return (((double) (control.value - query.minimum)) / ((double) (query.maximum - query.minimum)));
+ }
+ }
+ return 0.0;
+}
+
+static void videoinput_set_control_v4l2( videoinput_t *vidin, uint32_t id, double val )
+{
+ struct v4l2_queryctrl query;
+
+ query.id = id;
+ if( ioctl( vidin->grab_fd, VIDIOC_QUERYCTRL, &query ) >= 0 && !(query.flags & V4L2_CTRL_FLAG_DISABLED) ) {
+ struct v4l2_control control;
+ control.id = id;
+ control.value = query.minimum + ((int) ((val * ((double) (query.maximum - query.minimum))) + 0.5));
+ ioctl( vidin->grab_fd, VIDIOC_S_CTRL, &control );
+ }
+}
+
+int videoinput_get_hue( videoinput_t *vidin )
+{
+ if( vidin->isv4l2 ) {
+ return (int) ((videoinput_get_control_v4l2( vidin, V4L2_CID_HUE ) * 100.0) + 0.5);
+ } else {
+ struct video_picture grab_pict;
+
+ if( ioctl( vidin->grab_fd, VIDIOCGPICT, &grab_pict ) >= 0 ) {
+ return (int) ((((double) grab_pict.hue / 65535.0) * 100.0) + 0.5);
+ }
+ }
+
+ return 0;
+}
+
+void videoinput_set_hue( videoinput_t *vidin, int newhue )
+{
+ if( newhue > 100 ) newhue = 100;
+ if( newhue < 0 ) newhue = 50;
+
+ if( vidin->isv4l2 ) {
+ videoinput_set_control_v4l2( vidin, V4L2_CID_HUE, ((double) newhue) / 100.0 );
+ } else {
+ struct video_picture grab_pict;
+
+ if( ioctl( vidin->grab_fd, VIDIOCGPICT, &grab_pict ) >= 0 ) {
+ grab_pict.hue = (int) (((((double) newhue) / 100.0) * 65535.0) + 0.5);
+ ioctl( vidin->grab_fd, VIDIOCSPICT, &grab_pict );
+ }
+ }
+}
+
+void videoinput_set_hue_relative( videoinput_t *vidin, int offset )
+{
+ int hue = videoinput_get_hue( vidin );
+ if( hue + offset >= 0 ) {
+ videoinput_set_hue( vidin, hue + offset );
+ }
+}
+
+int videoinput_get_brightness( videoinput_t *vidin )
+{
+ if( vidin->isv4l2 ) {
+ return (int) ((videoinput_get_control_v4l2( vidin, V4L2_CID_BRIGHTNESS ) * 100.0) + 0.5);
+ } else {
+ struct video_picture grab_pict;
+
+ if( ioctl( vidin->grab_fd, VIDIOCGPICT, &grab_pict ) >= 0 ) {
+ return (int) ((((double) grab_pict.brightness / 65535.0) * 100.0) + 0.5);
+ }
+ }
+
+ return 0;
+}
+
+void videoinput_set_brightness( videoinput_t *vidin, int newbright )
+{
+ if( newbright > 100 ) newbright = 100;
+ if( newbright < 0 ) newbright = 50;
+
+ if( vidin->isv4l2 ) {
+ videoinput_set_control_v4l2( vidin, V4L2_CID_BRIGHTNESS, ((double) newbright) / 100.0 );
+ } else {
+ struct video_picture grab_pict;
+
+ if( ioctl( vidin->grab_fd, VIDIOCGPICT, &grab_pict ) >= 0 ) {
+ grab_pict.brightness = (int) (((((double) newbright) / 100.0) * 65535.0) + 0.5);
+ ioctl( vidin->grab_fd, VIDIOCSPICT, &grab_pict );
+ }
+ }
+}
+
+void videoinput_set_brightness_relative( videoinput_t *vidin, int offset )
+{
+ int brightness = videoinput_get_brightness( vidin );
+ if( brightness + offset >= 0 ) {
+ videoinput_set_brightness( vidin, brightness + offset );
+ }
+}
+
+int videoinput_get_contrast( videoinput_t *vidin )
+{
+ if( vidin->isv4l2 ) {
+ return (int) ((videoinput_get_control_v4l2( vidin, V4L2_CID_CONTRAST ) * 100.0) + 0.5);
+ } else {
+ struct video_picture grab_pict;
+
+ if( ioctl( vidin->grab_fd, VIDIOCGPICT, &grab_pict ) >= 0 ) {
+ return (int) ((((double) grab_pict.contrast / 65535.0) * 100.0) + 0.5);
+ }
+ }
+
+ return 0;
+}
+
+void videoinput_set_contrast( videoinput_t *vidin, int newcont )
+{
+ if( newcont > 100 ) newcont = 100;
+ if( newcont < 0 ) newcont = 50;
+
+ if( vidin->isv4l2 ) {
+ videoinput_set_control_v4l2( vidin, V4L2_CID_CONTRAST, ((double) newcont) / 100.0 );
+ } else {
+ struct video_picture grab_pict;
+
+ if( ioctl( vidin->grab_fd, VIDIOCGPICT, &grab_pict ) >= 0 ) {
+ grab_pict.contrast = (int) (((((double) newcont) / 100.0) * 65535.0) + 0.5);
+ ioctl( vidin->grab_fd, VIDIOCSPICT, &grab_pict );
+ }
+ }
+}
+
+void videoinput_set_contrast_relative( videoinput_t *vidin, int offset )
+{
+ int contrast = videoinput_get_contrast( vidin );
+ if( contrast + offset >= 0 ) {
+ videoinput_set_contrast( vidin, contrast + offset );
+ }
+}
+
+int videoinput_get_saturation( videoinput_t *vidin )
+{
+ if( vidin->isv4l2 ) {
+ return (int) ((videoinput_get_control_v4l2( vidin, V4L2_CID_SATURATION ) * 100.0) + 0.5);
+ } else {
+ struct video_picture grab_pict;
+
+ if( ioctl( vidin->grab_fd, VIDIOCGPICT, &grab_pict ) >= 0 ) {
+ return (int) ((((double) grab_pict.colour / 65535.0) * 100.0) + 0.5);
+ }
+ }
+
+ return 0;
+}
+
+void videoinput_set_saturation( videoinput_t *vidin, int newsaturation )
+{
+ if( newsaturation > 100 ) newsaturation = 100;
+ if( newsaturation < 0 ) newsaturation = 50;
+
+ if( vidin->isv4l2 ) {
+ videoinput_set_control_v4l2( vidin, V4L2_CID_SATURATION, ((double) newsaturation) / 100.0 );
+ } else {
+ struct video_picture grab_pict;
+
+ if( ioctl( vidin->grab_fd, VIDIOCGPICT, &grab_pict ) >= 0 ) {
+ grab_pict.colour = (int) (((((double) newsaturation) / 100.0) * 65535.0) + 0.5);
+ ioctl( vidin->grab_fd, VIDIOCSPICT, &grab_pict );
+ }
+ }
+}
+
+void videoinput_set_saturation_relative( videoinput_t *vidin, int offset )
+{
+ int saturation = videoinput_get_saturation( vidin );
+ if( saturation + offset >= 0 ) {
+ videoinput_set_saturation( vidin, saturation + offset );
+ }
+}
+
+float videoinput_get_aspect( videoinput_t *vidin )
+{
+ float aspect = 1.0;
+
+ if( vidin->isv4l2 ) {
+ struct v4l2_cropcap cropcap;
+ /* on success 0 is returned */
+ if( !ioctl( vidin->grab_fd, VIDIOC_CROPCAP, &cropcap ) ) {
+ aspect = (float)cropcap.pixelaspect.numerator / (float)cropcap.pixelaspect.denominator;
+ fprintf( stderr, "videoinput: Aspect ratio: %f\n", aspect);
+ }
+ }
+
+ return aspect;
+}
+
+static void videoinput_do_mute( videoinput_t *vidin, int mute )
+{
+ if( vidin->hasaudio && mute != vidin->hw_muted ) {
+ if( vidin->isv4l2 ) {
+ struct v4l2_control control;
+
+ control.id = V4L2_CID_AUDIO_MUTE;
+ control.value = mute ? 1 : 0;
+
+ if( ioctl( vidin->grab_fd, VIDIOC_S_CTRL, &control ) < 0 ) {
+ fprintf( stderr, "videoinput: Can't mute card. Post a bug report with your\n"
+ "videoinput: driver info to " PACKAGE_BUGREPORT "\n" );
+ fprintf( stderr, "videoinput: Include this error: '%s'\n", strerror( errno ) );
+ }
+
+ if( !mute && vidin->volume > 0 ) {
+ videoinput_set_control_v4l2( vidin, V4L2_CID_AUDIO_VOLUME, ((double) vidin->volume) / 100.0 );
+ }
+ } else {
+ struct video_audio audio;
+
+ if( ioctl( vidin->grab_fd, VIDIOCGAUDIO, &audio ) < 0 ) {
+ fprintf( stderr, "videoinput: Audio state query failed (got '%s').\n",
+ strerror( errno ) );
+ } else {
+ if( mute ) {
+ audio.flags |= VIDEO_AUDIO_MUTE;
+ } else {
+ audio.flags &= ~VIDEO_AUDIO_MUTE;
+ }
+ if( vidin->volume > 0 ) {
+ audio.volume = (vidin->volume * 65535) / 100;
+ }
+
+ if( ioctl( vidin->grab_fd, VIDIOCSAUDIO, &audio ) < 0 ) {
+ fprintf( stderr, "videoinput: Can't set audio settings. I have no idea what "
+ "might cause this. Post a bug report with your driver info to "
+ PACKAGE_BUGREPORT "\n" );
+ fprintf( stderr, "videoinput: Include this error: '%s'\n", strerror( errno ) );
+ }
+ }
+ }
+ vidin->hw_muted = mute;
+ }
+}
+
+void videoinput_set_audio_mode( videoinput_t *vidin, int mode )
+{
+ if( mode == VIDEOINPUT_LANG1 && vidin->norm == VIDEOINPUT_NTSC ) {
+ mode = VIDEOINPUT_LANG2;
+ }
+
+ if( mode > VIDEOINPUT_LANG2 ) {
+ mode = VIDEOINPUT_MONO;
+ }
+
+ if( vidin->audiomode != mode ) {
+ if( vidin->isv4l2 ) {
+ if( vidin->hastuner ) {
+ struct v4l2_tuner tuner;
+
+ memset( &tuner, 0, sizeof( struct v4l2_tuner ) );
+ tuner.index = vidin->tunerid;
+ tuner.audmode = videoinput_get_audmode_v4l2( mode );
+ if( ioctl( vidin->grab_fd, VIDIOC_S_TUNER, &tuner ) < 0 ) {
+ fprintf( stderr, "videoinput: Can't set tuner audio mode: %s\n",
+ strerror( errno ) );
+ } else {
+ vidin->audiomode = mode;
+ }
+ }
+ } else {
+ struct video_audio audio;
+
+ if( ioctl( vidin->grab_fd, VIDIOCGAUDIO, &audio ) < 0 ) {
+ if( vidin->verbose ) {
+ fprintf( stderr, "videoinput: Audio state query failed (got '%s').\n",
+ strerror( errno ) );
+ }
+ } else {
+ int was_muted = (audio.flags & VIDEO_AUDIO_MUTE);
+
+ /* Set the mode. */
+ audio.mode = mode;
+ if( ioctl( vidin->grab_fd, VIDIOCSAUDIO, &audio ) < 0 ) {
+ fprintf( stderr, "videoinput: Can't set audio mode setting. I have no idea what "
+ "might cause this. Post a bug report with your driver info to "
+ PACKAGE_BUGREPORT "\n" );
+ fprintf( stderr, "videoinput: Include this error: '%s'\n", strerror( errno ) );
+ } else {
+ vidin->audiomode = mode;
+ }
+
+ if( was_muted & !(audio.flags & VIDEO_AUDIO_MUTE) ) {
+ /* Stupid card dropped the mute state, have to go back to being muted. */
+ vidin->hw_muted = 0;
+ videoinput_do_mute( vidin, 1 );
+ }
+ }
+ }
+ }
+}
+
+/* freqKHz is in KHz (duh) */
+void videoinput_set_tuner_freq( videoinput_t *vidin, int freqKHz )
+{
+ unsigned long frequency = freqKHz;
+
+ if( videoinput_has_tuner( vidin ) ) {
+ if( frequency < 0 ) {
+ /* Ignore bogus frequencies. */
+ return;
+ }
+
+ frequency *= 16;
+
+ if( !vidin->tunerlow ) {
+ frequency /= 1000; /* switch to MHz */
+ }
+
+ vidin->change_muted = 1;
+ mixer->mute( 1 );
+ videoinput_do_mute( vidin, vidin->user_muted || vidin->change_muted );
+ vidin->cur_tuner_state = TUNER_STATE_SIGNAL_DETECTED;
+ vidin->signal_acquire_wait = SIGNAL_ACQUIRE_DELAY;
+ vidin->signal_recover_wait = 0;
+
+ if( vidin->isv4l2 ) {
+ struct v4l2_frequency freqinfo;
+ int wasstreaming = vidin->is_streaming;
+
+ memset( &freqinfo, 0, sizeof( struct v4l2_frequency ) );
+ freqinfo.tuner = vidin->tunerid;
+ freqinfo.type = V4L2_TUNER_ANALOG_TV;
+ freqinfo.frequency = frequency;
+
+ videoinput_stop_capture_v4l2( vidin );
+ if( ioctl( vidin->grab_fd, VIDIOC_S_FREQUENCY, &freqinfo ) < 0 ) {
+ fprintf( stderr, "videoinput: Tuner present, but our request to change to\n"
+ "videoinput: frequency %d failed with this error: %s.\n", freqKHz, strerror( errno ) );
+ fprintf( stderr, "videoinput: Please file a bug report at " PACKAGE_BUGREPORT "\n" );
+ }
+ if( wasstreaming ) {
+ videoinput_free_all_frames( vidin );
+ videoinput_start_capture_v4l2( vidin );
+ }
+ } else {
+ if( ioctl( vidin->grab_fd, VIDIOCSFREQ, &frequency ) < 0 ) {
+ fprintf( stderr, "videoinput: Tuner present, but our request to change "
+ "to frequency %d failed with this error: %s.\n", freqKHz, strerror( errno ) );
+ fprintf( stderr, "videoinput: Please file a bug report at " PACKAGE_BUGREPORT "\n" );
+ }
+ }
+ }
+}
+
+int videoinput_get_tuner_freq( videoinput_t *vidin )
+{
+ if( vidin->hastuner ) {
+ unsigned long frequency;
+
+ if( vidin->isv4l2 ) {
+ struct v4l2_frequency freqinfo;
+
+ freqinfo.tuner = vidin->tunerid;
+ freqinfo.type = V4L2_TUNER_ANALOG_TV;
+
+ if( ioctl( vidin->grab_fd, VIDIOC_G_FREQUENCY, &freqinfo ) < 0 ) {
+ fprintf( stderr, "videoinput: Tuner refuses to tell us the current frequency: %s\n",
+ strerror( errno ) );
+ fprintf( stderr, "videoinput: Please file a bug report at " PACKAGE_BUGREPORT "\n" );
+ return 0;
+ }
+ frequency = freqinfo.frequency;
+ } else {
+ if( ioctl( vidin->grab_fd, VIDIOCGFREQ, &frequency ) < 0 ) {
+ fprintf( stderr, "videoinput: Tuner refuses to tell us the current frequency: %s\n",
+ strerror( errno ) );
+ fprintf( stderr, "videoinput: Please file a bug report at " PACKAGE_BUGREPORT "\n" );
+ return 0;
+ }
+ }
+
+ if( !vidin->tunerlow ) {
+ frequency *= 1000; /* switch from MHz to KHz */
+ }
+
+ return frequency / 16;
+ }
+ return 0;
+}
+
+int videoinput_freq_present( videoinput_t *vidin )
+{
+ if( videoinput_has_tuner( vidin ) ) {
+ if( vidin->isv4l2 ) {
+ struct v4l2_tuner tuner;
+
+ tuner.index = vidin->tunerid;
+ if( ioctl( vidin->grab_fd, VIDIOC_G_TUNER, &tuner ) < 0 ) {
+ if( vidin->verbose ) {
+ fprintf( stderr, "videoinput: Cannot detect signal from tuner: %s\n",
+ strerror( errno ) );
+ }
+ } else if( !tuner.signal ) {
+ return 0;
+ }
+ } else {
+ struct video_tuner tuner;
+
+ if( ioctl( vidin->grab_fd, VIDIOCGTUNER, &tuner ) < 0 ) {
+ if( vidin->verbose ) {
+ fprintf( stderr, "videoinput: Cannot detect signal from tuner: %s\n",
+ strerror( errno ) );
+ }
+ } else if( !tuner.signal ) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+/**
+ * Finds an appropriate tuner.
+ */
+static void videoinput_find_and_set_tuner( videoinput_t *vidin )
+{
+ if( vidin->isv4l2 ) {
+ struct v4l2_tuner tuner;
+
+ tuner.index = vidin->tunerid;
+ if( ioctl( vidin->grab_fd, VIDIOC_G_TUNER, &tuner ) < 0 ) {
+ fprintf( stderr, "videoinput: Can't get tuner info: %s\n",
+ strerror( errno ) );
+ } else {
+ vidin->tunerlow = (tuner.capability & V4L2_TUNER_CAP_LOW) ? 1 : 0;
+ }
+ } else {
+ struct video_tuner tuner;
+ int tuner_number = -1;
+ int found = 0;
+ int i;
+
+ for( i = 0; i < vidin->numtuners; i++ ) {
+ tuner.tuner = i;
+
+ if( ioctl( vidin->grab_fd, VIDIOCGTUNER, &tuner ) >= 0 ) {
+ if( ((vidin->norm == VIDEOINPUT_PAL || vidin->norm == VIDEOINPUT_PAL_NC || vidin->norm == VIDEOINPUT_PAL_N) && tuner.flags & VIDEO_TUNER_PAL) ||
+ (vidin->norm == VIDEOINPUT_SECAM && tuner.flags & VIDEO_TUNER_SECAM) ||
+ ((vidin->norm == VIDEOINPUT_NTSC || vidin->norm == VIDEOINPUT_NTSC_JP || vidin->norm == VIDEOINPUT_PAL_M) && tuner.flags & VIDEO_TUNER_NTSC) ) {
+ found = 1;
+ tuner_number = i;
+ break;
+ }
+ }
+ }
+
+ if( found ) {
+ int mustchange = 0;
+
+ tuner.tuner = tuner_number;
+
+ if( vidin->norm == VIDEOINPUT_PAL || vidin->norm == VIDEOINPUT_PAL_NC || vidin->norm == VIDEOINPUT_PAL_N ) {
+ if( tuner.mode != VIDEO_MODE_PAL ) {
+ mustchange = 1;
+ tuner.mode = VIDEO_MODE_PAL;
+ }
+ } else if( vidin->norm == VIDEOINPUT_SECAM ) {
+ if( tuner.mode != VIDEO_MODE_SECAM ) {
+ mustchange = 1;
+ tuner.mode = VIDEO_MODE_SECAM;
+ }
+ } else {
+ if( tuner.mode != VIDEO_MODE_NTSC ) {
+ mustchange = 1;
+ tuner.mode = VIDEO_MODE_NTSC;
+ }
+ }
+
+ if( mustchange ) {
+ struct video_channel grab_chan;
+
+ if( ioctl( vidin->grab_fd, VIDIOCSTUNER, &tuner ) < 0 ) {
+ fprintf( stderr, "videoinput: Tuner is not in the correct mode, and we can't set it.\n"
+ " Please file a bug report at " PACKAGE_BUGREPORT "\n"
+ " indicating your card, driver and this error message: %s.\n",
+ strerror( errno ) );
+ }
+
+ /**
+ * After setting the tuner, we need to re-set the norm on our channel.
+ * Doing this fixes PAL-M, at least with the bttv driver in 2.4.20.
+ * I am not happy with this, as I haven't seen it documented anywhere.
+ * Please correct me if I'm wrong.
+ */
+ grab_chan.channel = vidin->curinput;
+ grab_chan.norm = videoinput_get_v4l1_norm( vidin->norm );
+
+ if( ioctl( vidin->grab_fd, VIDIOCSCHAN, &grab_chan ) < 0 ) {
+ fprintf( stderr, "videoinput: Card refuses to re-set the channel.\n"
+ "Please post a bug report to " PACKAGE_BUGREPORT "\n"
+ "indicating your card, driver, and this error message: %s.\n", strerror( errno ) );
+ } else {
+ vidin->numtuners = grab_chan.tuners;
+ }
+ }
+ }
+
+ if( vidin->numtuners > 0 ) {
+ tuner.tuner = tuner_number;
+
+ if( ioctl( vidin->grab_fd, VIDIOCGTUNER, &tuner ) < 0 ) {
+ fprintf( stderr, "videoinput: Input indicates that tuners are available, but "
+ "driver refuses to give information about them.\n"
+ "videoinput: Please file a bug report at " PACKAGE_BUGREPORT
+ " and indicate that card and driver you have.\n" );
+ fprintf( stderr, "videoinput: Also include this error: '%s'\n", strerror( errno ) );
+ return;
+ }
+
+ if( vidin->verbose ) {
+ fprintf( stderr, "videoinput: Tuner %s (",
+ tuner.name );
+
+ switch (tuner.mode) {
+ case VIDEO_MODE_PAL: fprintf( stderr, "PAL" ); break;
+ case VIDEO_MODE_NTSC: fprintf( stderr, "NTSC" ); break;
+ case VIDEO_MODE_SECAM: fprintf( stderr, "SECAM" ); break;
+ case VIDEO_MODE_AUTO: fprintf( stderr, "AUTO" ); break;
+ default: fprintf( stderr, "UNDEFINED" ); break;
+ }
+
+ fprintf( stderr, "), flags: " );
+
+ if( tuner.flags & VIDEO_TUNER_PAL ) fprintf( stderr, "PAL " );
+ if( tuner.flags & VIDEO_TUNER_NTSC ) fprintf( stderr, "NTSC " );
+ if( tuner.flags & VIDEO_TUNER_SECAM ) fprintf( stderr, "SECAM " );
+ if( tuner.flags & VIDEO_TUNER_LOW ) fprintf( stderr, "LOW " );
+ if( tuner.flags & VIDEO_TUNER_NORM ) fprintf( stderr, "NORM " );
+ if( tuner.flags & VIDEO_TUNER_STEREO_ON ) fprintf( stderr, "STEREO_ON " );
+ if( tuner.flags & VIDEO_TUNER_RDS_ON ) fprintf( stderr, "RDS_ON " );
+ if( tuner.flags & VIDEO_TUNER_MBS_ON ) fprintf( stderr, "MBS_ON" );
+ fprintf( stderr, "\n" );
+ }
+
+ vidin->tunerlow = (tuner.flags & VIDEO_TUNER_LOW) ? 1 : 0;
+ vidin->hastuner = 1;
+ }
+ }
+}
+
+
+void videoinput_set_input_num( videoinput_t *vidin, int inputnum )
+{
+ if( vidin->isv4l2 ) {
+ v4l2_std_id std;
+ int index = inputnum;
+ int wasstreaming = vidin->is_streaming;
+
+ videoinput_stop_capture_v4l2( vidin );
+
+ if( ioctl( vidin->grab_fd, VIDIOC_S_INPUT, &index ) < 0 ) {
+ fprintf( stderr, "videoinput: Card refuses to set its input.\n"
+ "Please post a bug report to " PACKAGE_BUGREPORT "\n"
+ "indicating your card, driver, and this error message: %s.\n",
+ strerror( errno ) );
+ } else {
+ struct v4l2_input input;
+
+ if( ioctl( vidin->grab_fd, VIDIOC_G_INPUT, &input.index ) < 0 ) {
+ fprintf( stderr, "videoinput: Driver won't tell us its input: %s\n",
+ strerror( errno ) );
+ } else if( input.index != inputnum ) {
+ fprintf( stderr, "videoinput: Driver refuses to switch to input %d.\n",
+ inputnum );
+ inputnum = input.index;
+ }
+ vidin->curinput = inputnum;
+
+ if( ioctl( vidin->grab_fd, VIDIOC_ENUMINPUT, &input ) < 0 ) {
+ fprintf( stderr, "videoinput: Driver won't tell us input info: %s\n",
+ strerror( errno ) );
+ } else {
+ snprintf( vidin->inputname, sizeof( vidin->inputname ), "%s", input.name );
+ vidin->hastuner = input.type == V4L2_INPUT_TYPE_TUNER;
+ vidin->tunerid = input.tuner;
+ }
+ }
+
+ if( ioctl( vidin->grab_fd, VIDIOC_G_STD, &std ) < 0 ) {
+ fprintf( stderr, "videoinput: Driver won't tell us its norm: %s\n",
+ strerror( errno ) );
+ } else {
+ std = videoinput_get_v4l2_norm( vidin->norm );
+ if( std == V4L2_STD_PAL ) {
+ if( vidin->amode == VIDEOINPUT_PAL_DK_AUDIO ) {
+ std = V4L2_STD_PAL_DK;
+ } else if( vidin->amode == VIDEOINPUT_PAL_I_AUDIO ) {
+ std = V4L2_STD_PAL_I;
+ }
+ }
+ if( ioctl( vidin->grab_fd, VIDIOC_S_STD, &std ) < 0 ) {
+ fprintf( stderr, "videoinput: Driver refuses to set norm: %s\n",
+ strerror( errno ) );
+ }
+ }
+
+ if( wasstreaming ) {
+ videoinput_free_all_frames( vidin );
+ videoinput_start_capture_v4l2( vidin );
+ }
+ } else {
+ if( inputnum >= vidin->numinputs ) {
+ fprintf( stderr, "videoinput: Requested input number %d not valid, "
+ "max is %d.\n", inputnum, vidin->numinputs );
+ } else {
+ struct video_channel grab_chan;
+
+ grab_chan.channel = inputnum;
+ if( ioctl( vidin->grab_fd, VIDIOCGCHAN, &grab_chan ) < 0 ) {
+ fprintf( stderr, "videoinput: Card refuses to give information on its current input.\n"
+ "Please post a bug report to " PACKAGE_BUGREPORT "\n"
+ "indicating your card, driver, and this error message: %s.\n", strerror( errno ) );
+ } else {
+ grab_chan.channel = inputnum;
+ grab_chan.norm = videoinput_get_v4l1_norm( vidin->norm );
+
+ if( ioctl( vidin->grab_fd, VIDIOCSCHAN, &grab_chan ) < 0 ) {
+ fprintf( stderr, "videoinput: Card refuses to set the channel.\n"
+ "Please post a bug report to " PACKAGE_BUGREPORT "\n"
+ "indicating your card, driver, and this error message: %s.\n", strerror( errno ) );
+ }
+
+ vidin->curinput = inputnum;
+ if( ioctl( vidin->grab_fd, VIDIOCGCHAN, &grab_chan ) < 0 ) {
+ fprintf( stderr, "videoinput: Card refuses to give information on its current input.\n"
+ "Please post a bug report to " PACKAGE_BUGREPORT "\n"
+ "indicating your card, driver, and this error message: %s.\n", strerror( errno ) );
+ } else {
+ snprintf( vidin->inputname, sizeof( vidin->inputname ), "%s", grab_chan.name );
+ vidin->numtuners = grab_chan.tuners;
+ vidin->hastuner = (vidin->numtuners > 0);
+ }
+ }
+ }
+ }
+
+ /* Once we've set the input, go look for a tuner. */
+ videoinput_find_and_set_tuner( vidin );
+}
+
+int videoinput_check_for_signal( videoinput_t *vidin, int check_freq_present )
+{
+ if( videoinput_freq_present( vidin ) || !check_freq_present ) {
+ switch( vidin->cur_tuner_state ) {
+ case TUNER_STATE_NO_SIGNAL:
+ case TUNER_STATE_SIGNAL_LOST:
+ vidin->cur_tuner_state = TUNER_STATE_SIGNAL_DETECTED;
+ vidin->signal_acquire_wait = SIGNAL_ACQUIRE_DELAY;
+ vidin->signal_recover_wait = 0;
+ case TUNER_STATE_SIGNAL_DETECTED:
+ if( vidin->signal_acquire_wait ) {
+ vidin->signal_acquire_wait--;
+ break;
+ } else {
+ vidin->cur_tuner_state = TUNER_STATE_HAS_SIGNAL;
+ }
+ default:
+ if( vidin->change_muted ) {
+ vidin->change_muted = 0;
+ videoinput_do_mute( vidin, vidin->user_muted || vidin->change_muted );
+ mixer->mute( 0 );
+ }
+ break;
+ }
+ } else {
+ switch( vidin->cur_tuner_state ) {
+ case TUNER_STATE_HAS_SIGNAL:
+ case TUNER_STATE_SIGNAL_DETECTED:
+ vidin->cur_tuner_state = TUNER_STATE_SIGNAL_LOST;
+ vidin->signal_recover_wait = SIGNAL_RECOVER_DELAY;
+ vidin->change_muted = 1;
+ mixer->mute( 1 );
+ videoinput_do_mute( vidin, vidin->user_muted || vidin->change_muted );
+ case TUNER_STATE_SIGNAL_LOST:
+ if( vidin->signal_recover_wait ) {
+ vidin->signal_recover_wait--;
+ break;
+ } else {
+ vidin->cur_tuner_state = TUNER_STATE_NO_SIGNAL;
+ }
+ default: break;
+ }
+ }
+
+ return vidin->cur_tuner_state;
+}
+
+void videoinput_toggle_pal_secam( videoinput_t *vidin )
+{
+ if( vidin->norm == VIDEOINPUT_PAL ) {
+ vidin->norm = VIDEOINPUT_SECAM;
+ } else {
+ vidin->norm = VIDEOINPUT_PAL;
+ }
+ videoinput_set_input_num( vidin, videoinput_get_input_num( vidin ) );
+}
+
+void videoinput_switch_pal_secam( videoinput_t *vidin, int norm )
+{
+ if( norm != vidin->norm && (norm == VIDEOINPUT_PAL || norm == VIDEOINPUT_SECAM) ) {
+ vidin->norm = norm;
+ videoinput_set_input_num( vidin, videoinput_get_input_num( vidin ) );
+ }
+}
+
+void videoinput_mute( videoinput_t *vidin, int mute )
+{
+ vidin->user_muted = mute;
+ videoinput_do_mute( vidin, vidin->user_muted || vidin->change_muted );
+}
+
+int videoinput_get_muted( videoinput_t *vidin )
+{
+ return vidin->user_muted;
+}
+
+int videoinput_get_audio_mode( videoinput_t *vidin )
+{
+ if( !vidin->audiomode || vidin->audiomode > VIDEO_SOUND_LANG2 ) {
+ return VIDEO_SOUND_MONO;
+ } else {
+ return vidin->audiomode;
+ }
+}
+
+void videoinput_set_pal_audio_mode( videoinput_t *vidin, int amode )
+{
+ if( amode != vidin->amode && vidin->norm == VIDEOINPUT_PAL ) {
+ vidin->amode = amode;
+ videoinput_set_input_num( vidin, videoinput_get_input_num( vidin ) );
+ }
+}
+
+int videoinput_get_pal_audio_mode( videoinput_t *vidin )
+{
+ if( !vidin ) return 0;
+ return vidin->amode;
+}
+
+int videoinput_has_tuner( videoinput_t *vidin )
+{
+ return vidin->hastuner;
+}
+
+int videoinput_get_width( videoinput_t *vidin )
+{
+ return vidin->width;
+}
+
+int videoinput_get_height( videoinput_t *vidin )
+{
+ return vidin->height;
+}
+
+int videoinput_get_maxwidth( videoinput_t *vidin )
+{
+ return vidin->maxwidth;
+}
+
+int videoinput_get_norm( videoinput_t *vidin )
+{
+ return vidin->norm;
+}
+
+int videoinput_get_numframes( videoinput_t *vidin )
+{
+ return vidin->numframes;
+}
+
+int videoinput_get_num_inputs( videoinput_t *vidin )
+{
+ return vidin->numinputs;
+}
+
+int videoinput_is_bttv( videoinput_t *vidin )
+{
+ return vidin->isbttv;
+}
+
+int videoinput_is_uyvy( videoinput_t *vidin )
+{
+ return vidin->isuyvy;
+}
+
+int videoinput_is_v4l2( videoinput_t *vidin )
+{
+ return vidin->isv4l2;
+}
+
+int videoinput_get_input_num( videoinput_t *vidin )
+{
+ return vidin->curinput;
+}
+
+const char *videoinput_get_input_name( videoinput_t *vidin )
+{
+ return vidin->inputname;
+}
+
+const char *videoinput_get_driver_name( videoinput_t *vidin )
+{
+ return vidin->drivername;
+}
+
+void videoinput_set_capture_volume( videoinput_t *vidin, int volume )
+{
+ vidin->volume = volume;
+ if( vidin->volume >= 0 ) {
+ if( vidin->isv4l2 ) {
+ videoinput_set_control_v4l2( vidin, V4L2_CID_AUDIO_VOLUME,
+ ((double) vidin->volume) / 100.0 );
+ } else {
+ struct video_audio audio;
+
+ if( ioctl( vidin->grab_fd, VIDIOCGAUDIO, &audio ) < 0 ) {
+ fprintf( stderr, "videoinput: Audio state query failed (got '%s').\n",
+ strerror( errno ) );
+ } else {
+ if( vidin->volume > 0 ) {
+ audio.volume = (vidin->volume * 65535) / 100;
+ }
+
+ if( ioctl( vidin->grab_fd, VIDIOCSAUDIO, &audio ) < 0 ) {
+ fprintf( stderr, "videoinput: Can't set audio settings. I have no idea what "
+ "might cause this. Post a bug report with your driver info to "
+ PACKAGE_BUGREPORT "\n" );
+ fprintf( stderr, "videoinput: Include this error: '%s'\n", strerror( errno ) );
+ }
+ }
+ }
+ }
+}
+
diff -Nurp tvtime-1.0.2/src/videoinput.h tvtime-1.0.2-custom/src/videoinput.h
--- tvtime-1.0.2/src/videoinput.h 2005-09-08 04:55:10.000000000 +0200
+++ tvtime-1.0.2-custom/src/videoinput.h 2011-05-29 13:07:28.185707644 +0200
@@ -71,6 +71,8 @@ typedef struct videoinput_s videoinput_t
#define VIDEOINPUT_LANG1 4
#define VIDEOINPUT_LANG2 8
+float videoinput_get_aspect( videoinput_t *vidin );
+
/**
* Possible PAL audio modes, for the cx88 driver that cannot autodetect.
*/
diff -Nurp tvtime-1.0.2/src/xcommon.c tvtime-1.0.2-custom/src/xcommon.c
--- tvtime-1.0.2/src/xcommon.c 2005-08-14 19:36:52.000000000 +0200
+++ tvtime-1.0.2-custom/src/xcommon.c 2011-05-29 13:07:28.245708378 +0200
@@ -25,6 +25,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#if defined(__FreeBSD__)
#include <machine/param.h>
@@ -45,8 +46,8 @@
#include <X11/keysym.h>
#include <X11/cursorfont.h>
#include <X11/extensions/XShm.h>
-#ifdef HAVE_XTESTEXTENSION
-#include <X11/extensions/XTest.h>
+#ifdef HAVE_XSSEXTENSION
+#include <X11/extensions/scrnsaver.h>
#endif
#include "xfullscreen.h"
@@ -67,7 +68,7 @@ static Window wm_window;
static Window fs_window;
static Window output_window;
static GC gc;
-static int have_xtest;
+static int have_xss;
static int output_width, output_height;
static int output_aspect;
static int output_on_root;
@@ -106,10 +107,7 @@ static Atom wm_protocols;
static Atom wm_delete_window;
static Atom xawtv_station;
static Atom xawtv_remote;
-
-#ifdef HAVE_XTESTEXTENSION
-static KeyCode kc_shift_l; /* Fake key to send. */
-#endif
+static Atom net_wm_pid;
static area_t video_area;
static area_t window_area;
@@ -150,11 +148,12 @@ static void load_atoms( Display *dpy )
"WM_PROTOCOLS",
"WM_DELETE_WINDOW",
"_XAWTV_STATION",
- "_XAWTV_REMOTE"
+ "_XAWTV_REMOTE",
+ "_NET_WM_PID"
};
- Atom atoms_return[ 17 ];
+ Atom atoms_return[ 18 ];
- XInternAtoms( display, atom_names, 17, False, atoms_return );
+ XInternAtoms( display, atom_names, 18, False, atoms_return );
net_supporting_wm_check = atoms_return[ 0 ];
net_supported = atoms_return[ 1 ];
net_wm_name = atoms_return[ 2 ];
@@ -172,6 +171,7 @@ static void load_atoms( Display *dpy )
wm_delete_window = atoms_return[ 14 ];
xawtv_station = atoms_return[ 15 ];
xawtv_remote = atoms_return[ 16 ];
+ net_wm_pid = atoms_return[ 17 ];
}
static uint32_t icon_colours[256];
@@ -248,12 +248,12 @@ static void x11_wait_mapped( Display *dp
} while ( (event.type != MapNotify) || (event.xmap.event != win) );
}
-static int have_xtestextention( void )
+static int have_xssextention( void )
{
-#ifdef HAVE_XTESTEXTENSION
- int dummy1, dummy2, dummy3, dummy4;
+#ifdef HAVE_XSSEXTENSION
+ int dummy1, dummy2;
- return (XTestQueryExtension( display, &dummy1, &dummy2, &dummy3, &dummy4 ) == True);
+ return (XScreenSaverQueryExtension( display, &dummy1, &dummy2 ) == True);
#endif
return 0;
}
@@ -843,7 +843,7 @@ int xcommon_open_display( const char *us
output_aspect = aspect;
output_height = 576;
- have_xtest = 0;
+ have_xss = 0;
output_on_root = 0;
has_ewmh_state_fullscreen = 0;
has_ewmh_state_above = 0;
@@ -927,13 +927,16 @@ int xcommon_open_display( const char *us
xfullscreen_print_summary( xf );
}
-#ifdef HAVE_XTESTEXTENSION
- kc_shift_l = XKeysymToKeycode( display, XK_Shift_L );
-#endif
- have_xtest = have_xtestextention();
- if( have_xtest && xcommon_verbose ) {
- fprintf( stderr, "xcommon: Have XTest, will use it to ping the screensaver.\n" );
+ have_xss = have_xssextention();
+ if( have_xss && xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Have XSS, will use it to disable the screensaver.\n" );
+ }
+
+#ifdef HAVE_XSSEXTENSION
+ if ( have_xss ) {
+ XScreenSaverSuspend( display, True );
}
+#endif
/* Initially, get the best width for our height. */
output_width = xv_get_width_for_height( output_height );
@@ -1017,6 +1020,16 @@ int xcommon_open_display( const char *us
free( data );
}
}
+
+ /* Set _NET_WM_PID */
+ {
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: try to set _NET_WM_PID" );
+ }
+ pid_t mypid = getpid();
+ XChangeProperty(display, wm_window, net_wm_pid, cardinal, 32,
+ PropModeReplace, (const unsigned char*) &mypid, 1);
+ }
if( check_for_EWMH_wm( display, &wmname ) ) {
if( xcommon_verbose ) {
@@ -1112,15 +1125,7 @@ void xcommon_ping_screensaver( void )
gettimeofday( &curtime, 0 );
if( timediff( &curtime, &last_ping_time ) > SCREENSAVER_PING_TIME ) {
last_ping_time = curtime;
-#ifdef HAVE_XTESTEXTENSION
- if( have_xtest ) {
- XTestFakeKeyEvent( display, kc_shift_l, True, CurrentTime );
- XTestFakeKeyEvent( display, kc_shift_l, False, CurrentTime );
- } else
-#endif
- {
- XResetScreenSaver( display );
- }
+ XResetScreenSaver( display );
}
}
@@ -1715,6 +1720,11 @@ void xcommon_poll_events( input_t *in )
void xcommon_close_display( void )
{
+#ifdef HAVE_XSSEXTENSION
+ if ( have_xss ) {
+ XScreenSaverSuspend( display, False );
+ }
+#endif
XDestroyWindow( display, output_window );
XDestroyWindow( display, wm_window );
XDestroyWindow( display, fs_window );
diff -Nurp tvtime-1.0.2/src/xcommon.c.orig tvtime-1.0.2-custom/src/xcommon.c.orig
--- tvtime-1.0.2/src/xcommon.c.orig 1970-01-01 01:00:00.000000000 +0100
+++ tvtime-1.0.2-custom/src/xcommon.c.orig 2011-05-29 13:07:28.202374516 +0200
@@ -0,0 +1,1840 @@
+/**
+ * Copyright (C) 2001, 2002, 2003 Billy Biggs <vektor@dumbterm.net>.
+ *
+ * Common routines for X output drivers. Uses EWMH code and lots of
+ * help from:
+ *
+ * Ogle - A video player
+ * Copyright (C) 2001, 2002 Björn Englund, Håkan Hjort
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__FreeBSD__)
+#include <machine/param.h>
+#endif
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/time.h>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <X11/X.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <X11/cursorfont.h>
+#include <X11/extensions/XShm.h>
+#ifdef HAVE_XSSEXTENSION
+#include <X11/extensions/scrnsaver.h>
+#endif
+
+#include "xfullscreen.h"
+#include "speedy.h"
+#include "utils.h"
+#include "xcommon.h"
+
+/* Every 30 seconds, ping the screensaver. */
+#define SCREENSAVER_PING_TIME (30 * 1000 * 1000)
+
+/* Useful. */
+#define MIN(x,y)((x)<(y)?(x):(y))
+#define MAX(x,y)((x)>(y)?(x):(y))
+
+static Display *display;
+static int screen;
+static Window wm_window;
+static Window fs_window;
+static Window output_window;
+static GC gc;
+static int have_xss;
+static int output_width, output_height;
+static int output_aspect;
+static int output_on_root;
+static int has_ewmh_state_fullscreen;
+static int has_ewmh_state_above;
+static int has_ewmh_state_below;
+static Cursor nocursor;
+static int output_fullscreen;
+static int xcommon_verbose;
+static int xcommon_exposed;
+static int xcommon_colourkey;
+static int motion_timeout;
+static int fullscreen_position;
+static int matte_width;
+static int matte_height;
+static int alwaysontop;
+static int has_focus;
+static int wm_is_metacity;
+static int use_square_pixels;
+static xfullscreen_t *xf;
+
+static Atom net_supporting_wm_check;
+static Atom net_supported;
+static Atom net_wm_name;
+static Atom net_wm_state;
+static Atom net_wm_state_above;
+static Atom net_wm_state_below;
+static Atom net_wm_state_fullscreen;
+static Atom net_wm_user_time;
+static Atom net_wm_icon;
+static Atom net_active_window;
+static Atom utf8_string;
+static Atom cardinal;
+static Atom kwm_keep_on_top;
+static Atom wm_protocols;
+static Atom wm_delete_window;
+static Atom xawtv_station;
+static Atom xawtv_remote;
+
+static area_t video_area;
+static area_t window_area;
+static area_t scale_area;
+
+static Time lastpresstime = 0;
+static Time lastreleasetime = 0;
+static Time last_server_time = 0;
+
+static int timediff( struct timeval *large, struct timeval *small )
+{
+ return ( ( ( large->tv_sec * 1000 * 1000 ) + large->tv_usec )
+ - ( ( small->tv_sec * 1000 * 1000 ) + small->tv_usec ) );
+}
+
+/**
+ * Cache every atom we need in xcommon. This minimizes round trips
+ * to the server. The number of atoms and their position is hardcoded,
+ * but it's small. Making this look pretty I think would be too
+ * annoying to be worth it.
+ */
+static void load_atoms( Display *dpy )
+{
+ static char *atom_names[] = {
+ "_NET_SUPPORTING_WM_CHECK",
+ "_NET_SUPPORTED",
+ "_NET_WM_NAME",
+ "_NET_WM_STATE",
+ "_NET_WM_STATE_ABOVE",
+ "_NET_WM_STATE_BELOW",
+ "_NET_WM_STATE_FULLSCREEN",
+ "_NET_WM_USER_TIME",
+ "_NET_WM_ICON",
+ "_NET_ACTIVE_WINDOW",
+ "UTF8_STRING",
+ "CARDINAL",
+ "KWM_KEEP_ON_TOP",
+ "WM_PROTOCOLS",
+ "WM_DELETE_WINDOW",
+ "_XAWTV_STATION",
+ "_XAWTV_REMOTE"
+ };
+ Atom atoms_return[ 17 ];
+
+ XInternAtoms( display, atom_names, 17, False, atoms_return );
+ net_supporting_wm_check = atoms_return[ 0 ];
+ net_supported = atoms_return[ 1 ];
+ net_wm_name = atoms_return[ 2 ];
+ net_wm_state = atoms_return[ 3 ];
+ net_wm_state_above = atoms_return[ 4 ];
+ net_wm_state_below = atoms_return[ 5 ];
+ net_wm_state_fullscreen = atoms_return[ 6 ];
+ net_wm_user_time = atoms_return[ 7 ];
+ net_wm_icon = atoms_return[ 8 ];
+ net_active_window = atoms_return[ 9 ];
+ utf8_string = atoms_return[ 10 ];
+ cardinal = atoms_return[ 11 ];
+ kwm_keep_on_top = atoms_return[ 12 ];
+ wm_protocols = atoms_return[ 13 ];
+ wm_delete_window = atoms_return[ 14 ];
+ xawtv_station = atoms_return[ 15 ];
+ xawtv_remote = atoms_return[ 16 ];
+}
+
+static uint32_t icon_colours[256];
+static int colours_loaded = 0;
+
+static const char *tvtime_icon =
+" "
+" "
+" "
+" "
+" %@@@@@@@++..........% "
+" ..####=##=##=####..#*& "
+" ++@%@@@@@+++++..+...%&& "
+" ..%%%@@@+++....#+.+.%$&$ "
+" +.@%@@++++...###....%&$& "
+" ++@@@@+++..#.#...++.%$&& "
+" +.@@+++....#.##...+.%&$& "
+" ++@@+++...#.##..+.++%$$& "
+" ++++++...###.#..+++.%&$& "
+" ++++...#.#.#....++++*$$$ "
+" ++@....###.#...++++.*$$& "
+" +++..#.#.#...+++@+++*$$$ "
+" @@+.##.#.#...+++@+++%$&$ "
+" +++.#.##...+++@@@+++*$$$ "
+" @@.##.#....++@@@%+@+*$$$ "
+" @@+#.#...++++@@@%+++*&$$ "
+" @@++....+++@@@%%@+@+-$$& "
+" ++++....+++@@%%-%+++*$$ "
+" @++.+......#...+++++%$$ "
+" +.++++......#..+@+*$& "
+" ...+++++...+++%$ "
+" ...++@+++* "
+" "
+" "
+" "
+" "
+" "
+" " ;
+
+static void load_icon( uint32_t *data )
+{
+ int i;
+
+ if( !colours_loaded ) {
+ colours_loaded = 1;
+ icon_colours[ ' ' ] = 0x00000000;
+ icon_colours[ '.' ] = 0xffcccccc;
+ icon_colours[ '+' ] = 0xffb2b2b2;
+ icon_colours[ '@' ] = 0xff999999;
+ icon_colours[ '#' ] = 0xffe5e5e5;
+ icon_colours[ '$' ] = 0xff4c4c4c;
+ icon_colours[ '%' ] = 0xff7f7f7f;
+ icon_colours[ '&' ] = 0xff333333;
+ icon_colours[ '*' ] = 0xff666666;
+ icon_colours[ '=' ] = 0xffffffff;
+ icon_colours[ '-' ] = 0xff007f7f;
+ }
+
+ *data++ = 32;
+ *data++ = 32;
+ for( i = 0; i < 32 * 32; i++ ) {
+ *data++ = icon_colours[ (int) tvtime_icon[ i ] ];
+ }
+}
+
+/**
+ * Called after mapping a window - waits until the window is mapped.
+ */
+static void x11_wait_mapped( Display *dpy, Window win )
+{
+ XEvent event;
+ do {
+ XMaskEvent( dpy, StructureNotifyMask, &event );
+ } while ( (event.type != MapNotify) || (event.xmap.event != win) );
+}
+
+static int have_xssextention( void )
+{
+#ifdef HAVE_XSSEXTENSION
+ int dummy1, dummy2;
+
+ return (XScreenSaverQueryExtension( display, &dummy1, &dummy2 ) == True);
+#endif
+ return 0;
+}
+
+static int calculate_gcd( int x, int y )
+{
+ if( y > x ) return calculate_gcd( y, x );
+ if( y < 0 ) return calculate_gcd( -y, 0 );
+
+ while( y ) {
+ int tmp = y;
+ y = x % y;
+ x = tmp;
+ }
+
+ return x;
+}
+
+static void simplify_fraction( int *n, int *d )
+{
+ int gcd = calculate_gcd( *n, *d );
+ *n /= gcd;
+ *d /= gcd;
+}
+
+/*
+ * Integer division always truncates in C -- it rounds down.
+ *
+ * To compensate for this, we round up if
+ * n mod d > d/2
+ * To avoid adding another truncation error, I multiply
+ * this condition by two:
+ * 2 * (n mod d) > d
+ * And use the property that this evaluates to 1 if true to round up.
+ */
+static int rounded_int_division( int n, int d )
+{
+ simplify_fraction( &n, &d );
+ return ( n/d + (2 * (n%d) > d) );
+}
+
+/*
+ * Returns the aspect ratio (4:3 or 16:9) for our output,
+ * and corrected for rectangular pixels.
+ */
+static void xv_get_output_aspect( int *px_widthratio, int *px_heightratio )
+{
+ int metric_widthratio = output_aspect ? 16 : 4;
+ int metric_heightratio = output_aspect ? 9 : 3;
+ int sar_frac_w, sar_frac_h;
+
+ if( matte_height ) {
+ metric_heightratio = matte_height;
+ metric_widthratio = matte_width;
+ }
+
+ if( use_square_pixels ) {
+ sar_frac_w = sar_frac_h = 1;
+ } else {
+ xfullscreen_get_pixel_aspect( xf, &sar_frac_w, &sar_frac_h );
+ }
+
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Pixel aspect ratio %d:%d.\n",
+ sar_frac_w, sar_frac_h );
+ }
+
+ /* PX_RATIO = METRIC_RATIO / SAR_FRAC = METRIC_RATIO * (1 / SAR_FRAC) */
+ *px_widthratio = metric_widthratio * sar_frac_h;
+ *px_heightratio = metric_heightratio * sar_frac_w;
+ simplify_fraction( px_widthratio, px_heightratio );
+}
+
+static int xv_get_width_for_height( int window_height )
+{
+ int n, d;
+
+ xv_get_output_aspect( &n, &d );
+ return rounded_int_division( window_height * n, d );
+}
+
+static int xv_get_height_for_width( int window_width )
+{
+ int n, d;
+
+ xv_get_output_aspect( &d, &n );
+ return rounded_int_division( window_width * n, d );
+}
+
+static void x11_northwest_gravity( Display *dpy, Window win )
+{
+ XSizeHints hints;
+ hints.flags = PWinGravity;
+ hints.win_gravity = NorthWestGravity;
+ XSetWMNormalHints( dpy, win, &hints );
+}
+
+static void x11_grab_fullscreen_input( Display *dpy, Window win )
+{
+ int tries = 10;
+ int result = -1;
+
+ while( tries && result != GrabSuccess ) {
+ result = XGrabPointer( dpy, win, True, 0, GrabModeAsync, GrabModeAsync,
+ win, None, CurrentTime );
+ tries--;
+ }
+ XGrabKeyboard( dpy, win, True, GrabModeAsync, GrabModeAsync, CurrentTime );
+ XSync( dpy, False );
+}
+
+static void x11_ungrab_fullscreen_input( Display *dpy )
+{
+ XUngrabPointer( dpy, CurrentTime );
+ XUngrabKeyboard( dpy, CurrentTime );
+}
+
+/* Used for error handling. */
+static unsigned long req_serial;
+static int (*prev_xerrhandler)( Display *dpy, XErrorEvent *ev );
+
+static int xprop_errorhandler( Display *dpy, XErrorEvent *ev )
+{
+ if( ev->serial == req_serial ) {
+ /* this is an error to the XGetWindowProperty request
+ * most probable the window specified by the property
+ * _NET_SUPPORTING_WM_CHECK on the root window no longer exists
+ */
+ fprintf( stderr, "xprop_errhandler: error in XGetWindowProperty\n" );
+ return 0;
+ } else {
+ /* if we get another error we should handle it,
+ * so we give it to the previous errorhandler
+ */
+ fprintf( stderr, "xprop_errhandler: unexpected error\n" );
+ return prev_xerrhandler( dpy, ev );
+ }
+}
+
+/**
+ * Returns the window name for an Extended Window Manager Hints (EWMH)
+ * compliant window manager. Sets the name to "unknown" if no name is
+ * set (non-compliant by the spec, but worth handling).
+ */
+static void get_window_manager_name( Display *dpy, Window wm_window, char **wm_name_return )
+{
+ Atom type_return;
+ int format_return;
+ unsigned long bytes_after_return;
+ unsigned long nitems_return;
+ unsigned char *prop_return = 0;
+
+ if( XGetWindowProperty( dpy, wm_window, net_wm_name, 0,
+ 4, False, XA_STRING,
+ &type_return, &format_return,
+ &nitems_return, &bytes_after_return,
+ &prop_return ) != Success ) {
+ fprintf( stderr, "xcommon: Can't get window manager name "
+ "property (WM not compliant).\n" );
+ *wm_name_return = strdup( "unknown" );
+ return;
+ }
+
+ if( type_return == None ) {
+ fprintf( stderr, "xcommon: No window manager name "
+ "property found (WM not compliant).\n" );
+ *wm_name_return = strdup( "unknown" );
+ XFree( prop_return );
+ return;
+ }
+
+ if( type_return != XA_STRING ) {
+ XFree( prop_return );
+
+ if( type_return == utf8_string ) {
+ if( XGetWindowProperty( dpy, wm_window, net_wm_name, 0,
+ 4, False, utf8_string,
+ &type_return, &format_return,
+ &nitems_return,
+ &bytes_after_return,
+ &prop_return ) != Success ) {
+ fprintf( stderr, "wm_name: Can't get window "
+ "manager name property "
+ "(WM not compliant).\n" );
+ *wm_name_return = strdup( "unknown" );
+ return;
+ }
+
+ if( format_return == 8 ) {
+ *wm_name_return = strdup( (char *) prop_return );
+ }
+ XFree( prop_return );
+ } else {
+ fprintf( stderr, "xcommon: Window manager name not "
+ "ASCII or UTF8, giving up.\n" );
+ *wm_name_return = strdup( "unknown" );
+ return;
+ }
+ } else {
+ if( format_return == 8 ) {
+ *wm_name_return = strdup( (char *) prop_return );
+ }
+ XFree( prop_return );
+ }
+}
+
+/**
+ * returns 1 if a window manager compliant to the
+ * Extended Window Manager Hints (EWMH) spec is running.
+ * (version 1.2)
+ * Oterhwise returns 0.
+ */
+static int check_for_EWMH_wm( Display *dpy, char **wm_name_return )
+{
+ Atom type_return;
+ int format_return;
+ unsigned long nitems_return;
+ unsigned long bytes_after_return;
+ unsigned char *prop_return = 0;
+
+ if( XGetWindowProperty( dpy, DefaultRootWindow( dpy ), net_supporting_wm_check, 0,
+ 1, False, XA_WINDOW,
+ &type_return, &format_return, &nitems_return,
+ &bytes_after_return, &prop_return ) != Success ) {
+ fprintf( stderr, "xcommon: Can't get window property to check for EWMH.\n" );
+ return 0;
+ }
+
+ if( type_return == None ) {
+ fprintf( stderr, "xcommon: No window properties found for EWMH.\n" );
+ return 0;
+ }
+
+ if( type_return != XA_WINDOW ) {
+ fprintf( stderr, "xcommon: Can't get window property for EWMH.\n" );
+ if( prop_return ) XFree( prop_return );
+ return 0;
+ }
+
+ if( format_return == 32 && nitems_return == 1 && bytes_after_return == 0 ) {
+ Window win_id = *( (long *) prop_return );
+ int status;
+
+ XFree( prop_return );
+ prop_return = 0;
+
+ /* Make sure we don't have any unhandled errors. */
+ XSync( dpy, False );
+
+ /* Set error handler so we can check if XGetWindowProperty failed. */
+ prev_xerrhandler = XSetErrorHandler( xprop_errorhandler );
+
+ /* get the serial of the XGetWindowProperty request */
+ req_serial = NextRequest( dpy );
+
+ /* try to get property
+ * this can fail if we have a property with the win_id on the
+ * root window, but the win_id is no longer valid.
+ * This is to check for a stale window manager
+ */
+ status = XGetWindowProperty( dpy, win_id, net_supporting_wm_check, 0,
+ 1, False, XA_WINDOW,
+ &type_return, &format_return, &nitems_return,
+ &bytes_after_return, &prop_return );
+
+ /* make sure XGetWindowProperty has been processed and any errors
+ have been returned to us */
+ XSync( dpy, False );
+
+ /* revert to the previous xerrorhandler */
+ XSetErrorHandler( prev_xerrhandler );
+
+ if( status != Success || type_return == None ) {
+ fprintf( stderr, "xcommon: EWMH check failed on child window, "
+ "stale window manager property on root?\n" );
+ return 0;
+ }
+
+ if( type_return == XA_CARDINAL ) {
+ /* Hack for old and busted metacity. */
+ /* Allow this atom to be a CARDINAL. */
+ XGetWindowProperty( dpy, win_id, net_supporting_wm_check, 0,
+ 1, False, XA_CARDINAL,
+ &type_return, &format_return, &nitems_return,
+ &bytes_after_return, &prop_return );
+ } else if( type_return != XA_WINDOW ) {
+ fprintf( stderr, "didn't return XA_WINDOW?\n" );
+ fprintf( stderr, "xcommon: EWMH check failed on child window, "
+ "stale window manager property on root?\n" );
+ if( prop_return ) {
+ XFree( prop_return );
+ }
+ return 0;
+ }
+
+ if( format_return == 32 && nitems_return == 1 && bytes_after_return == 0 ) {
+ if( win_id == *( (long *) prop_return ) ) {
+ /* We have successfully detected a EWMH compliant Window Manager. */
+ XFree( prop_return );
+
+ /* Get the name of the wm */
+ get_window_manager_name( dpy, win_id, wm_name_return );
+ return 1;
+ }
+ XFree( prop_return );
+ return 0;
+ } else if( prop_return ) {
+ XFree( prop_return );
+ }
+ } else if( prop_return ) {
+ XFree( prop_return );
+ }
+
+ return 0;
+}
+
+/**
+ * Returns 1 if a window manager compliant to the Extended Window
+ * Manager Hints (EWMH) specification supports the
+ * _NET_WM_STATE_FULLSCREEN window state. Otherwise, returns 0.
+ */
+static int check_for_state_fullscreen( Display *dpy )
+{
+ Atom type_return;
+ int format_return;
+ unsigned long nitems_return;
+ unsigned long bytes_after_return;
+ unsigned char *prop_return = 0;
+ int nr_items = 40;
+ int item_offset = 0;
+ int supports_net_wm_state = 0;
+ int supports_net_wm_state_fullscreen = 0;
+
+ do {
+ if( XGetWindowProperty( dpy, DefaultRootWindow( dpy ), net_supported,
+ item_offset, nr_items, False, XA_ATOM,
+ &type_return, &format_return, &nitems_return,
+ &bytes_after_return, &prop_return) != Success ) {
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Can't check the fullscreen property (WM not compliant).\n" );
+ }
+ return 0;
+ }
+
+ if( type_return == None ) {
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: No property for fullscreen support (WM not compliant).\n" );
+ }
+ return 0;
+ }
+
+ if( type_return != XA_ATOM ) {
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Broken property for fullscreen support (WM not compliant).\n");
+ }
+ if( prop_return ) XFree( prop_return );
+ return 0;
+ } else {
+ if( format_return == 32 ) {
+ int n;
+
+ for( n = 0; n < nitems_return; n++ ) {
+ if( ((long *) prop_return)[ n ] == net_wm_state ) {
+ supports_net_wm_state = 1;
+ } else if( ((long *) prop_return)[ n ] == net_wm_state_fullscreen ) {
+ supports_net_wm_state_fullscreen = 1;
+ }
+
+ if( supports_net_wm_state && supports_net_wm_state_fullscreen ) {
+ XFree( prop_return );
+ return 1;
+ }
+ }
+
+ XFree( prop_return );
+ } else {
+ XFree( prop_return );
+ return 0;
+ }
+ }
+
+ item_offset += nr_items;
+ } while( bytes_after_return > 0 );
+
+ return 0;
+}
+
+/**
+ * Returns 1 if a window manager compliant to the Extended Window
+ * Manager Hints (EWMH) specification supports the _NET_WM_STATE_ABOVE
+ * window state. Otherwise, returns 0.
+ */
+static int check_for_state_above( Display *dpy )
+{
+ Atom type_return;
+ int format_return;
+ unsigned long nitems_return;
+ unsigned long bytes_after_return;
+ unsigned char *prop_return = 0;
+ int nr_items = 40;
+ int item_offset = 0;
+ int supports_net_wm_state = 0;
+ int supports_net_wm_state_above = 0;
+
+ do {
+ if( XGetWindowProperty( dpy, DefaultRootWindow( dpy ), net_supported,
+ item_offset, nr_items, False, XA_ATOM,
+ &type_return, &format_return, &nitems_return,
+ &bytes_after_return, &prop_return) != Success ) {
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Can't check the above property (WM not compliant).\n" );
+ }
+ return 0;
+ }
+
+ if( type_return == None ) {
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: No property for above support (WM not compliant).\n" );
+ }
+ return 0;
+ }
+
+ if( type_return != XA_ATOM ) {
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Broken property for above support (WM not compliant).\n");
+ }
+ if( prop_return ) XFree( prop_return );
+ return 0;
+ } else {
+ if( format_return == 32 ) {
+ int n;
+
+ for( n = 0; n < nitems_return; n++ ) {
+ if( ((long *) prop_return)[ n ] == net_wm_state ) {
+ supports_net_wm_state = 1;
+ } else if( ((long *) prop_return)[ n ] == net_wm_state_above ) {
+ supports_net_wm_state_above = 1;
+ }
+
+ if( supports_net_wm_state && supports_net_wm_state_above ) {
+ XFree( prop_return );
+ return 1;
+ }
+ }
+
+ XFree( prop_return );
+ } else {
+ XFree( prop_return );
+ return 0;
+ }
+ }
+
+ item_offset += nr_items;
+ } while( bytes_after_return > 0 );
+
+ return 0;
+}
+
+/**
+ * Returns 1 if a window manager compliant to the Extended Window
+ * Manager Hints (EWMH) specification supports the _NET_WM_STATE_BELOW
+ * window state. Otherwise, returns 0.
+ */
+static int check_for_state_below( Display *dpy )
+{
+ Atom type_return;
+ int format_return;
+ unsigned long nitems_return;
+ unsigned long bytes_after_return;
+ unsigned char *prop_return = 0;
+ int nr_items = 40;
+ int item_offset = 0;
+ int supports_net_wm_state = 0;
+ int supports_net_wm_state_below = 0;
+
+ do {
+ if( XGetWindowProperty( dpy, DefaultRootWindow( dpy ), net_supported,
+ item_offset, nr_items, False, XA_ATOM,
+ &type_return, &format_return, &nitems_return,
+ &bytes_after_return, &prop_return) != Success ) {
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Can't check the below property (WM not compliant).\n" );
+ }
+ return 0;
+ }
+
+ if( type_return == None ) {
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: No property for below support (WM not compliant).\n" );
+ }
+ return 0;
+ }
+
+ if( type_return != XA_ATOM ) {
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Broken property for below support (WM not compliant).\n");
+ }
+ if( prop_return ) XFree( prop_return );
+ return 0;
+ } else {
+ if( format_return == 32 ) {
+ int n;
+
+ for( n = 0; n < nitems_return; n++ ) {
+ if( ((long *) prop_return)[ n ] == net_wm_state ) {
+ supports_net_wm_state = 1;
+ } else if( ((long *) prop_return)[ n ] == net_wm_state_below ) {
+ supports_net_wm_state_below = 1;
+ }
+
+ if( supports_net_wm_state && supports_net_wm_state_below ) {
+ XFree( prop_return );
+ return 1;
+ }
+ }
+
+ XFree( prop_return );
+ } else {
+ XFree( prop_return );
+ return 0;
+ }
+ }
+
+ item_offset += nr_items;
+ } while( bytes_after_return > 0 );
+
+ return 0;
+}
+
+
+/**
+ * Some math:
+ *
+ * pixel size = pw/ph
+ * screen size = sw/sh
+ * resolution = rw/rh
+ *
+ * sw = pw*rw therefore pw = sw / rw
+ * sh = ph*rh therefore ph = sh / rh
+ */
+
+static void calculate_video_area( void )
+{
+ int curwidth, curheight;
+
+ curwidth = output_width;
+ curheight = xv_get_height_for_width( curwidth );
+ if( curheight > output_height ) {
+ curheight = output_height;
+ curwidth = xv_get_width_for_height( curheight );
+ }
+
+ video_area.x = ( output_width - curwidth ) / 2;
+ video_area.y = ( output_height - curheight ) / 2;
+ if( output_fullscreen ) {
+ if( fullscreen_position == 1 ) {
+ video_area.y = 0;
+ } else if( fullscreen_position == 2 ) {
+ video_area.y = output_height - curheight;
+ }
+ }
+ video_area.width = curwidth;
+ video_area.height = curheight;
+
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Displaying in a %dx%d window inside %dx%d space.\n",
+ curwidth, curheight, output_width, output_height );
+ }
+}
+
+
+int xcommon_open_display( const char *user_geometry, int aspect, int verbose )
+{
+ Pixmap curs_pix;
+ XEvent xev;
+ XSizeHints hint;
+ XClassHint classhint;
+ XColor curs_col;
+ XSetWindowAttributes xswa;
+ const char *hello = "tvtime";
+ unsigned long mask;
+ char *wmname = 0;
+ int wx, wy;
+ unsigned int ww, wh;
+ int gflags;
+
+ output_aspect = aspect;
+ output_height = 576;
+
+ have_xss = 0;
+ output_on_root = 0;
+ has_ewmh_state_fullscreen = 0;
+ has_ewmh_state_above = 0;
+ has_ewmh_state_below = 0;
+ output_fullscreen = 0;
+ xcommon_verbose = verbose;
+ xcommon_exposed = 0;
+ xcommon_colourkey = 0;
+ motion_timeout = 0;
+ fullscreen_position = 0;
+ matte_width = 0;
+ matte_height = 0;
+ alwaysontop = 0;
+ has_focus = 0;
+ wm_is_metacity = 0;
+
+ display = XOpenDisplay( 0 );
+ if( !display ) {
+ if( getenv( "DISPLAY" ) ) {
+ fprintf( stderr, "xcommon: Cannot open display '%s'.\n", getenv( "DISPLAY" ) );
+ } else {
+ fprintf( stderr, "xcommon: No DISPLAY set, so no output possible!\n" );
+ }
+ return 0;
+ }
+
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Display %s, vendor %s, ",
+ DisplayString( display ), ServerVendor( display ) );
+
+ if( strstr( ServerVendor( display ), "XFree86" ) ) {
+ int vendrel = VendorRelease( display );
+
+ fprintf( stderr, "XFree86 " );
+ if( vendrel < 336 ) {
+ /*
+ * vendrel was set incorrectly for 3.3.4 and 3.3.5, so handle
+ * those cases here.
+ */
+ fprintf( stderr, "%d.%d.%d", vendrel / 100, (vendrel / 10) % 10, vendrel % 10);
+ } else if( vendrel < 3900 ) {
+ /* 3.3.x versions, other than the exceptions handled above */
+ fprintf( stderr, "%d.%d", vendrel / 1000, (vendrel / 100) % 10);
+ if (((vendrel / 10) % 10) || (vendrel % 10)) {
+ fprintf( stderr, ".%d", (vendrel / 10) % 10);
+ if (vendrel % 10) {
+ fprintf( stderr, ".%d", vendrel % 10);
+ }
+ }
+ } else if( vendrel < 40000000 ) {
+ /* 4.0.x versions */
+ fprintf( stderr, "%d.%d", vendrel / 1000, (vendrel / 10) % 10);
+ if( vendrel % 10 ) {
+ fprintf( stderr, ".%d", vendrel % 10 );
+ }
+ } else {
+ /* post-4.0.x */
+ fprintf( stderr, "%d.%d.%d", vendrel / 10000000, (vendrel / 100000) % 100, (vendrel / 1000) % 100);
+ if( vendrel % 1000 ) {
+ fprintf( stderr, ".%d", vendrel % 1000);
+ }
+ }
+ fprintf( stderr, "\n" );
+ } else {
+ fprintf( stderr, "vendor release %d\n", VendorRelease( display ) );
+ }
+ }
+
+ load_atoms( display );
+
+ screen = DefaultScreen( display );
+
+ xf = xfullscreen_new( display, screen, verbose );
+ if( !xf ) {
+ fprintf( stderr, "xcommon: Can't initialize fullscreen information object.\n" );
+ XCloseDisplay( display );
+ return 0;
+ }
+
+ if( xcommon_verbose ) {
+ xfullscreen_print_summary( xf );
+ }
+
+ have_xss = have_xssextention();
+ if( have_xss && xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Have XSS, will use it to disable the screensaver.\n" );
+ }
+
+#ifdef HAVE_XSSEXTENSION
+ if ( have_xss ) {
+ XScreenSaverSuspend( display, True );
+ }
+#endif
+
+ /* Initially, get the best width for our height. */
+ output_width = xv_get_width_for_height( output_height );
+
+ window_area.x = 0;
+ window_area.y = 0;
+ window_area.width = output_width;
+ window_area.height = output_height;
+
+ xswa.override_redirect = False;
+ xswa.backing_store = NotUseful;
+ xswa.save_under = False;
+ xswa.background_pixel = BlackPixel( display, screen );
+ xswa.event_mask = ButtonPressMask | ButtonReleaseMask |
+ StructureNotifyMask | KeyPressMask | PointerMotionMask |
+ VisibilityChangeMask | FocusChangeMask |
+ PropertyChangeMask | ExposureMask;
+
+ mask = (CWBackPixel | CWSaveUnder | CWBackingStore | CWEventMask);
+
+ gflags = XParseGeometry( user_geometry, &wx, &wy, &ww, &wh );
+ if( !(gflags & WidthValue) ) {
+ ww = output_width;
+ }
+ if( !(gflags & HeightValue) ) {
+ wh = output_height;
+ } else if( ww == 0 ) {
+ ww = xv_get_width_for_height( wh );
+ }
+
+ window_area.width = ww;
+ window_area.height = wh;
+ output_width = ww;
+ output_height = wh;
+
+ wm_window = XCreateWindow( display, RootWindow( display, screen ), 0, 0,
+ ww, wh, 0, CopyFromParent, InputOutput,
+ CopyFromParent, mask, &xswa);
+
+ output_window = XCreateWindow( display, wm_window, 0, 0,
+ ww, wh, 0, CopyFromParent, InputOutput,
+ CopyFromParent, mask, &xswa);
+
+ xswa.override_redirect = True;
+ xswa.border_pixel = 0;
+
+ mask = (CWBackPixel | CWOverrideRedirect | CWEventMask);
+
+ fs_window = XCreateWindow( display, RootWindow( display, screen ), 0, 0,
+ output_width, output_height, 0,
+ CopyFromParent, InputOutput, CopyFromParent,
+ mask, &xswa );
+
+ /* Tell KDE to keep the fullscreen window on top. */
+ {
+ XEvent ev;
+ long mask;
+
+ memset( &ev, 0, sizeof( ev ) );
+ ev.xclient.type = ClientMessage;
+ ev.xclient.window = DefaultRootWindow( display );
+ ev.xclient.message_type = kwm_keep_on_top;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[ 0 ] = fs_window;
+ ev.xclient.data.l[ 1 ] = CurrentTime;
+ mask = SubstructureRedirectMask;
+ XSendEvent( display, DefaultRootWindow( display ), False, mask, &ev );
+ }
+
+ /* Set the icon on the window. */
+ {
+ uint32_t *data = malloc( 1026 * 4 );
+ if( data ) {
+ load_icon( data );
+ XChangeProperty( display, wm_window, net_wm_icon, cardinal, 32,
+ PropModeReplace,
+ (const unsigned char*) data, 1026 );
+ XChangeProperty( display, fs_window, net_wm_icon, cardinal, 32,
+ PropModeReplace, (const unsigned char*) data,
+ 1026 );
+ free( data );
+ }
+ }
+
+ if( check_for_EWMH_wm( display, &wmname ) ) {
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Window manager is %s and is EWMH compliant.\n", wmname );
+ }
+
+ if( !strcasecmp( wmname, "metacity" ) ) {
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: You are using metacity. Disabling aspect ratio hints\n"
+ "xcommon: since most deployed versions of metacity are still broken.\n" );
+ }
+ wm_is_metacity = 1;
+ }
+ free( wmname );
+
+
+ /**
+ * If we have an EWMH compliant window manager, check for
+ * fullscreen, above and below states.
+ */
+ has_ewmh_state_fullscreen = check_for_state_fullscreen( display );
+ if( has_ewmh_state_fullscreen && xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Using EWMH state fullscreen property.\n" );
+ }
+ has_ewmh_state_above = check_for_state_above( display );
+ if( has_ewmh_state_above && xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Using EWMH state above property.\n" );
+ }
+ has_ewmh_state_below = check_for_state_below( display );
+ if( has_ewmh_state_below && xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Using EWMH state below property.\n" );
+ }
+ } else if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Window manager is not EWMH compliant.\n" );
+ }
+
+ gc = DefaultGC( display, screen );
+
+ hint.width = output_width;
+ hint.height = output_height;
+ hint.flags = PSize;
+
+ XSetStandardProperties( display, wm_window, hello, hello, None, 0, 0, &hint );
+
+ /* The class hint is useful for window managers like WindowMaker. */
+ classhint.res_class = "tvtime";
+ classhint.res_name = "TVWindow";
+ XSetClassHint( display, wm_window, &classhint );
+ classhint.res_name = "TVFullscreen";
+ XSetClassHint( display, fs_window, &classhint );
+
+ /* collaborate with the window manager for close requests */
+ XSetWMProtocols( display, wm_window, &wm_delete_window, 1 );
+
+ calculate_video_area();
+
+ XMapWindow( display, output_window );
+ XMapWindow( display, wm_window );
+
+ /* FIXME: Do I need to wait for the window to be mapped? */
+ /* x11_wait_mapped( display, wm_window ); */
+
+ /* Wait for map. */
+ XMaskEvent( display, StructureNotifyMask, &xev );
+
+ /* Create a 1 pixel cursor to use in full screen mode */
+ curs_pix = XCreatePixmap( display, output_window, 1, 1, 1 );
+ curs_col.pixel = 0;
+ curs_col.red = 0;
+ curs_col.green = 0;
+ curs_col.blue = 0;
+ curs_col.flags = 0;
+ curs_col.pad = 0;
+ nocursor = XCreatePixmapCursor( display, curs_pix, curs_pix, &curs_col, &curs_col, 1, 1 );
+ XDefineCursor( display, output_window, nocursor );
+ XSetIconName( display, wm_window, "tvtime" );
+
+ return 1;
+}
+
+static struct timeval last_ping_time;
+static int time_initialized = 0;
+
+void xcommon_ping_screensaver( void )
+{
+ struct timeval curtime;
+
+ if( !time_initialized ) {
+ gettimeofday( &last_ping_time, 0 );
+ time_initialized = 1;
+ }
+
+ gettimeofday( &curtime, 0 );
+ if( timediff( &curtime, &last_ping_time ) > SCREENSAVER_PING_TIME ) {
+ last_ping_time = curtime;
+ XResetScreenSaver( display );
+ }
+}
+
+void xcommon_frame_drawn( void )
+{
+ if( motion_timeout ) {
+ motion_timeout--;
+ if( !motion_timeout ) {
+ XDefineCursor( display, output_window, nocursor );
+ }
+ }
+}
+
+void xcommon_set_window_position( int x, int y )
+{
+ if( output_fullscreen ) {
+ xcommon_toggle_fullscreen( 0, 0 );
+ }
+
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Target window position %d,%d.\n", x, y );
+ }
+
+ x11_northwest_gravity( display, wm_window );
+ XMoveWindow( display, wm_window, x, y );
+}
+
+void xcommon_set_window_height( int window_height )
+{
+ XWindowChanges win_changes;
+ int window_width;
+
+ if( output_fullscreen ) {
+ xcommon_toggle_fullscreen( 0, 0 );
+ }
+
+ window_width = xv_get_width_for_height( window_height );
+
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Target window size %dx%d.\n", window_width, window_height );
+ }
+
+ win_changes.width = window_width;
+ win_changes.height = window_height;
+
+ XReconfigureWMWindow( display, wm_window, 0,
+ CWWidth | CWHeight, &win_changes );
+}
+
+void xcommon_clear_screen( void )
+{
+ XSetForeground( display, gc, BlackPixel( display, screen ) );
+ XClearWindow( display, output_window );
+ XSetForeground( display, gc, xcommon_colourkey );
+ XFillRectangle( display, output_window, gc, video_area.x, video_area.y,
+ video_area.width, video_area.height );
+ /* This is how to draw text.
+ XSetForeground( display, gc, WhitePixel( display, screen ) );
+ XDrawString( display, output_window, gc,
+ video_area.x + (video_area.width/3),
+ video_area.y + (video_area.height/3),
+ text, strlen( text ) );
+ */
+ XSync( display, False );
+}
+
+void xcommon_clear_area( int x, int y, int w, int h )
+{
+ int dx, dy, dw, dh;
+
+ /* First fill the new area to black. */
+ XSetForeground( display, gc, BlackPixel( display, screen ) );
+ XFillRectangle( display, output_window, gc, x, y, w, h );
+
+ /**
+ * Only fill the intersection of the video area and the exposed
+ * area with the colour key.
+ */
+ dx = MAX( x, video_area.x );
+ dy = MAX( y, video_area.y );
+ dw = MIN( x + w, video_area.x + video_area.width ) - dx;
+ dh = MIN( y + h, video_area.y + video_area.height ) - dy;
+ if( dx >= 0 && dy >= 0 && dw >= 0 && dh >= 0 ) {
+ XSetForeground( display, gc, xcommon_colourkey );
+ XFillRectangle( display, output_window, gc, dx, dy, dw, dh );
+ }
+}
+
+/**
+ * Called after unmapping a window - waits until the window is unmapped.
+ */
+static void x11_wait_unmapped( Display *dpy, Window win )
+{
+ XEvent event;
+ do {
+ XMaskEvent( dpy, StructureNotifyMask, &event );
+ } while ( (event.type != UnmapNotify) || (event.xunmap.event != win) );
+}
+
+int xcommon_toggle_alwaysontop( void )
+{
+ if( has_ewmh_state_above ) {
+ XEvent ev;
+
+ alwaysontop = !alwaysontop;
+
+ ev.type = ClientMessage;
+ ev.xclient.window = wm_window;
+ ev.xclient.message_type = net_wm_state;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[ 0 ] = alwaysontop ? 1 : 0;
+ ev.xclient.data.l[ 1 ] = net_wm_state_above;
+ ev.xclient.data.l[ 2 ] = 0;
+
+ XSendEvent( display, DefaultRootWindow( display ), False,
+ SubstructureNotifyMask|SubstructureRedirectMask, &ev );
+ }
+
+ return alwaysontop;
+}
+
+static void xcommon_activate_window( void )
+{
+ XEvent ev;
+
+ ev.type = ClientMessage;
+ ev.xclient.window = wm_window;
+ ev.xclient.message_type = net_active_window;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[ 0 ] = 1;
+ ev.xclient.data.l[ 1 ] = last_server_time;
+ ev.xclient.data.l[ 2 ] = 0;
+
+ XSendEvent( display, DefaultRootWindow( display ), False,
+ SubstructureNotifyMask|SubstructureRedirectMask, &ev );
+}
+
+int xcommon_toggle_fullscreen( int fullscreen_width, int fullscreen_height )
+{
+ output_fullscreen = !output_fullscreen;
+ if( output_fullscreen ) {
+ int x, y, w, h;
+
+ xfullscreen_update( xf );
+ xfullscreen_get_position( xf, window_area.x, window_area.y,
+ window_area.width, window_area.height,
+ &x, &y, &w, &h );
+
+ output_width = w;
+ output_height = h;
+
+ window_area.x = x;
+ window_area.y = y;
+ window_area.width = w;
+ window_area.height = h;
+
+ if( has_ewmh_state_fullscreen ) {
+ XEvent ev;
+
+ ev.type = ClientMessage;
+ ev.xclient.display = display;
+ ev.xclient.window = wm_window;
+ ev.xclient.message_type = net_wm_state;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[ 0 ] = 1;
+ ev.xclient.data.l[ 1 ] = net_wm_state_fullscreen;
+ ev.xclient.data.l[ 2 ] = 0;
+ ev.xclient.data.l[ 3 ] = 0;
+ ev.xclient.data.l[ 4 ] = 0;
+
+ XSendEvent( display, DefaultRootWindow( display ), False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &ev );
+
+ /* When we go fullscreen, explicitly ask to get focus. */
+ xcommon_activate_window();
+ } else {
+ /* Show our fullscreen window. */
+ XMoveResizeWindow( display, fs_window, x, y, w, h );
+ XMapRaised( display, fs_window );
+ x11_wait_mapped( display, fs_window );
+ XRaiseWindow( display, fs_window );
+
+ /* Since we just mapped the window and got our
+ * Map event, we mark this here. */
+ xcommon_exposed = 1;
+
+ XReparentWindow( display, output_window, fs_window, 0, 0);
+
+ /* Grab the pointer, grab input focus, then ungrab. */
+ x11_grab_fullscreen_input( display, fs_window );
+ XSetInputFocus( display, fs_window, RevertToPointerRoot, CurrentTime );
+ x11_ungrab_fullscreen_input( display );
+ }
+ } else {
+ XWindowAttributes attrs;
+
+ XGetWindowAttributes( display, wm_window, &attrs );
+
+ output_width = attrs.width;
+ output_height = attrs.height;
+ window_area.width = attrs.width;
+ window_area.height = attrs.height;
+
+ if( has_ewmh_state_fullscreen ) {
+ XEvent ev;
+
+ ev.type = ClientMessage;
+ ev.xclient.display = display;
+ ev.xclient.window = wm_window;
+ ev.xclient.message_type = net_wm_state;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[ 0 ] = 0;
+ ev.xclient.data.l[ 1 ] = net_wm_state_fullscreen;
+ ev.xclient.data.l[ 2 ] = 0;
+ ev.xclient.data.l[ 3 ] = 0;
+ ev.xclient.data.l[ 4 ] = 0;
+
+ XSendEvent( display, DefaultRootWindow( display ), False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &ev );
+ } else {
+ XReparentWindow( display, output_window, wm_window, 0, 0 );
+ XUnmapWindow( display, fs_window );
+ x11_wait_unmapped( display, fs_window );
+ }
+ }
+ XResizeWindow( display, output_window, output_width, output_height );
+ calculate_video_area();
+ xcommon_clear_screen();
+ XFlush( display );
+ XSync( display, False );
+
+ return output_fullscreen;
+}
+
+int xcommon_toggle_root( int fullscreen_width, int fullscreen_height )
+{
+ return 0;
+}
+
+int xcommon_toggle_aspect( void )
+{
+ output_aspect = !output_aspect;
+ calculate_video_area();
+ xcommon_clear_screen();
+ return output_aspect;
+}
+
+void xcommon_update_server_time( unsigned long timestamp )
+{
+ if( !timestamp ) {
+ /**
+ * Get the current timestamp by causing an event to be generated
+ * by the X server. This is only a single round-trip to the
+ * X server. Inspired by kapplication::updateUserTimestamp().
+ */
+ unsigned char data[ 1 ];
+ Window w = XCreateSimpleWindow( display, DefaultRootWindow( display ),
+ 0, 0, 1, 1, 0, 0, 0 );
+ XEvent ev;
+ XSelectInput( display, w, PropertyChangeMask );
+ XChangeProperty( display, w, XA_ATOM, XA_ATOM, 8,
+ PropModeAppend, data, 1 );
+ XWindowEvent( display, w, PropertyChangeMask, &ev );
+ timestamp = ev.xproperty.time;
+ XDestroyWindow( display, w );
+ }
+
+ last_server_time = timestamp;
+ XChangeProperty( display, wm_window, net_wm_user_time, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) ×tamp, 1 );
+}
+
+void xcommon_poll_events( input_t *in )
+{
+ XEvent event;
+ int reconfigure = 0;
+ int reconfwidth = 0;
+ int reconfheight = 0;
+ int getfocus = 0;
+ int motion = 0;
+ int motion_x = 0;
+ int motion_y = 0;
+ int bx = -1;
+ int by = -1;
+ int bw = -1;
+ int bh = -1;
+
+ while( XPending( display ) ) {
+ KeySym mykey;
+ char mykey_string;
+ int arg = 0;
+
+ XNextEvent( display, &event );
+
+ switch( event.type ) {
+ case ClientMessage:
+ /* X sucks this way. Thanks to walken for help on this one. */
+ if( ( event.xclient.message_type == wm_protocols ) && ( event.xclient.format == 32 ) &&
+ ( event.xclient.data.l[ 0 ] == wm_delete_window ) ) {
+ input_callback( in, I_QUIT, 0 );
+ }
+ break;
+
+ case Expose:
+ if( bx < 0 ) {
+ bx = event.xexpose.x;
+ by = event.xexpose.y;
+ bw = event.xexpose.width;
+ bh = event.xexpose.height;
+ } else {
+ int dx, dy, dw, dh;
+ int cx, cy, cw, ch;
+ cx = event.xexpose.x;
+ cy = event.xexpose.y;
+ cw = event.xexpose.width;
+ ch = event.xexpose.height;
+ dx = MIN(bx, cx);
+ dy = MIN(by, cy);
+ dw = MAX(bx + bw, cx + cw) - dx;
+ dh = MAX(by + bh, cy + ch) - dy;
+ bx = dx;
+ by = dy;
+ bw = dw;
+ bh = dh;
+ }
+ break;
+ case DestroyNotify:
+ if( event.xdestroywindow.window != wm_window ) {
+ break;
+ }
+ input_callback( in, I_QUIT, 0 );
+ break;
+ case MotionNotify:
+ if( event.xmotion.x >= video_area.x && event.xmotion.x < (video_area.x + video_area.width) &&
+ event.xmotion.y >= video_area.y && event.xmotion.y < (video_area.y + video_area.height) &&
+ video_area.width && video_area.height ) {
+
+ int videox = event.xmotion.x - video_area.x;
+ int videoy = event.xmotion.y - video_area.y;
+ int imagex = scale_area.x + ((scale_area.width * videox) / video_area.width);
+ int imagey = scale_area.y + ((scale_area.height * videoy) / video_area.height);
+
+ motion = 1;
+ motion_x = imagex;
+ motion_y = imagey;
+ }
+ XUndefineCursor( display, output_window );
+ motion_timeout = 30;
+ break;
+ case EnterNotify:
+ getfocus = 1;
+ break;
+ case FocusIn:
+ has_focus = 1;
+ break;
+ case FocusOut:
+ has_focus = 0;
+ break;
+ case MapNotify:
+ if( !output_on_root ) {
+ xcommon_exposed = 1;
+ xcommon_clear_screen();
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Received a map, marking window as visible (%lu).\n",
+ event.xany.serial );
+ }
+ }
+ break;
+ case UnmapNotify:
+ if( !output_on_root ) {
+ xcommon_exposed = 0;
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Received an unmap, marking window as hidden (%lu).\n",
+ event.xany.serial );
+ }
+ }
+ break;
+ case VisibilityNotify:
+ if( !output_on_root ) {
+ if( event.xvisibility.state == VisibilityFullyObscured ) {
+ if( xcommon_exposed ) {
+ xcommon_exposed = 0;
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Window fully obscured, marking window as hidden (%lu).\n",
+ event.xany.serial );
+ }
+ }
+ } else if( !xcommon_exposed ) {
+ xcommon_exposed = 1;
+ xcommon_clear_screen();
+ if( xcommon_verbose ) {
+ fprintf( stderr, "xcommon: Window made visible, marking window as visible (%lu).\n",
+ event.xany.serial );
+ }
+ }
+ }
+ break;
+ case ConfigureNotify:
+ if( event.xconfigure.window == wm_window ) {
+ if( event.xconfigure.send_event == False ) {
+ int gx, gy;
+ Window dw;
+
+ if( XTranslateCoordinates( display, wm_window,
+ DefaultRootWindow( display ),
+ 0, 0, &gx, &gy, &dw) == True) {
+ window_area.x = gx;
+ window_area.y = gy;
+ }
+ } else {
+ window_area.x = event.xconfigure.x;
+ window_area.y = event.xconfigure.y;
+ }
+ window_area.width = event.xconfigure.width;
+ window_area.height = event.xconfigure.height;
+ }
+ reconfwidth = event.xconfigure.width;
+ reconfheight = event.xconfigure.height;
+ if( reconfwidth != output_width || reconfheight != output_height ) {
+ reconfigure = 1;
+ }
+ break;
+ case PropertyNotify:
+ if( event.xproperty.atom == xawtv_remote ) {
+ Atom type_return;
+ int format_return;
+ unsigned long bytes_after_return;
+ unsigned long nitems_return;
+ unsigned char *prop_return = 0;
+ char *argv[ 32 ];
+ if( XGetWindowProperty( display, event.xproperty.window,
+ event.xproperty.atom, 0, 65536,
+ True, XA_STRING, &type_return,
+ &format_return, &nitems_return,
+ &bytes_after_return,
+ &prop_return ) == Success ) {
+ if( nitems_return > 0 ) {
+ int arg = 0;
+ int i;
+ for( i = 0; i < nitems_return && *(prop_return + i); i += strlen( ((char *) prop_return) + i ) + 1 ) {
+ argv[ arg++ ] = ((char *) prop_return) + i;
+ }
+ argv[ arg ] = 0;
+ input_xawtv_command( in, arg, argv );
+ XFree( prop_return );
+ }
+ }
+ }
+ break;
+ case KeyPress:
+ xcommon_update_server_time( event.xkey.time );
+ /* if( event.xkey.state & ShiftMask ) arg |= I_SHIFT; */
+ /* this alternate approach allows handling of keys like '<' and '>' -- mrallen */
+ if( event.xkey.state & ShiftMask ) {
+ mykey = XKeycodeToKeysym( display, event.xkey.keycode, 1 );
+ } else {
+ mykey = XKeycodeToKeysym( display, event.xkey.keycode, 0 );
+ }
+ if( event.xkey.state & ControlMask ) arg |= I_CTRL;
+ if( event.xkey.state & Mod1Mask ) arg |= I_META;
+
+ if( mykey >= XK_a && mykey <= XK_z ) {
+ arg |= mykey - XK_a + 'a';
+ } else if( mykey >= XK_A && mykey <= XK_Z ) {
+ arg |= mykey - XK_A + 'a';
+ } else if( mykey >= XK_0 && mykey <= XK_9 ) {
+ arg |= mykey - XK_0 + '0';
+ } else {
+ XLookupString( &event.xkey, &mykey_string, 1, 0, 0 );
+ arg |= mykey_string;
+ }
+
+ switch( mykey ) {
+ case XK_Escape: arg |= I_ESCAPE; break;
+
+ case XK_Home: arg |= I_HOME; break;
+ case XK_End: arg |= I_END; break;
+ case XK_Left: arg |= I_LEFT; break;
+ case XK_Up: arg |= I_UP; break;
+ case XK_Right: arg |= I_RIGHT; break;
+ case XK_Down: arg |= I_DOWN; break;
+ case XK_Page_Up: arg |= I_PGUP; break;
+ case XK_Page_Down: arg |= I_PGDN; break;
+ case XK_Insert: arg |= I_INSERT; break;
+
+ case XK_F1: arg |= I_F1; break;
+ case XK_F2: arg |= I_F2; break;
+ case XK_F3: arg |= I_F3; break;
+ case XK_F4: arg |= I_F4; break;
+ case XK_F5: arg |= I_F5; break;
+ case XK_F6: arg |= I_F6; break;
+ case XK_F7: arg |= I_F7; break;
+ case XK_F8: arg |= I_F8; break;
+ case XK_F9: arg |= I_F9; break;
+ case XK_F10: arg |= I_F10; break;
+ case XK_F11: arg |= I_F11; break;
+ case XK_F12: arg |= I_F12; break;
+
+ case XK_KP_Enter: arg |= I_ENTER; break;
+ case XK_KP_0: arg |= '0'; break;
+ case XK_KP_1: arg |= '1'; break;
+ case XK_KP_2: arg |= '2'; break;
+ case XK_KP_3: arg |= '3'; break;
+ case XK_KP_4: arg |= '4'; break;
+ case XK_KP_5: arg |= '5'; break;
+ case XK_KP_6: arg |= '6'; break;
+ case XK_KP_7: arg |= '7'; break;
+ case XK_KP_8: arg |= '8'; break;
+ case XK_KP_9: arg |= '9'; break;
+ case XK_KP_Multiply: arg |= '*'; break;
+ case XK_KP_Subtract: arg |= '-'; break;
+ case XK_KP_Add: arg |= '+'; break;
+ case XK_KP_Divide: arg |= '/'; break;
+
+ case XK_KP_Insert: arg |= '0'; break;
+ case XK_KP_End: arg |= '1'; break;
+ case XK_KP_Down: arg |= '2'; break;
+ case XK_KP_Next: arg |= '3'; break;
+ case XK_KP_Left: arg |= '4'; break;
+ case XK_KP_Begin: arg |= '5'; break;
+ case XK_KP_Right: arg |= '6'; break;
+ case XK_KP_Home: arg |= '7'; break;
+ case XK_KP_Up: arg |= '8'; break;
+ case XK_KP_Prior: arg |= '9'; break;
+
+ default: break;
+ }
+ input_callback( in, I_KEYDOWN, arg );
+ break;
+ case ButtonPress:
+ xcommon_update_server_time( event.xbutton.time );
+ if( event.xbutton.time != lastpresstime ) {
+ input_callback( in, I_BUTTONPRESS, event.xbutton.button );
+ lastpresstime = event.xbutton.time;
+ }
+ getfocus = 1;
+ break;
+ case ButtonRelease:
+ xcommon_update_server_time( event.xbutton.time );
+ if( event.xbutton.time != lastreleasetime ) {
+ input_callback( in, I_BUTTONRELEASE, event.xbutton.button );
+ lastreleasetime = event.xbutton.time;
+ }
+ getfocus = 1;
+ break;
+ default: break;
+ }
+ }
+
+ if( motion ) {
+ input_callback( in, I_MOUSEMOVE, ((motion_x & 0xffff) << 16 | (motion_y & 0xffff)) );
+ }
+
+ if( getfocus ) {
+ XSetInputFocus( display, wm_window, RevertToPointerRoot, CurrentTime );
+ }
+
+ if( !has_ewmh_state_fullscreen && output_fullscreen ) {
+ /**
+ * We used to check if we still have focus too.
+ * Let's ignore that for now and see how well this
+ * works.
+ */
+ if( !xcommon_exposed /* || !has_focus */ ) {
+ /**
+ * Switch back to windowed mode if we have lost
+ * input focus or window visibility.
+ */
+ xcommon_toggle_fullscreen( 0, 0 );
+ }
+ }
+
+ if( bx >= 0 ) {
+ xcommon_clear_area( bx, by, bw, bh );
+ }
+
+ if( reconfigure ) {
+ if( !output_on_root && !output_fullscreen ) {
+ output_width = reconfwidth;
+ output_height = reconfheight;
+ XResizeWindow( display, output_window,
+ output_width, output_height );
+ }
+
+ calculate_video_area();
+ xcommon_clear_screen();
+ XSync( display, False );
+ }
+}
+
+void xcommon_close_display( void )
+{
+#ifdef HAVE_XSSEXTENSION
+ if ( have_xss ) {
+ XScreenSaverSuspend( display, False );
+ }
+#endif
+ XDestroyWindow( display, output_window );
+ XDestroyWindow( display, wm_window );
+ XDestroyWindow( display, fs_window );
+ XCloseDisplay( display );
+ xfullscreen_delete( xf );
+}
+
+static char *old_caption = 0;
+
+void xcommon_set_window_caption( const char *caption )
+{
+ if( !old_caption || strcmp( caption, old_caption ) ) {
+ if( old_caption ) free( old_caption );
+ old_caption = strdup( caption );
+ XStoreName( display, wm_window, caption );
+ XChangeProperty( display, wm_window, net_wm_name, utf8_string, 8,
+ PropModeReplace, (const unsigned char *) caption,
+ strlen( caption ) );
+ }
+}
+
+Display *xcommon_get_display( void )
+{
+ return display;
+}
+
+Window xcommon_get_output_window( void )
+{
+ return output_window;
+}
+
+GC xcommon_get_gc( void )
+{
+ return gc;
+}
+
+int xcommon_is_fullscreen( void )
+{
+ return output_fullscreen;
+}
+
+int xcommon_is_alwaysontop( void )
+{
+ return alwaysontop;
+}
+
+int xcommon_is_fullscreen_supported( void )
+{
+ return 1;
+}
+
+int xcommon_is_alwaysontop_supported( void )
+{
+ return has_ewmh_state_above;
+}
+
+area_t xcommon_get_video_area( void )
+{
+ return video_area;
+}
+
+int xcommon_is_exposed( void )
+{
+ return xcommon_exposed;
+}
+
+void xcommon_set_colourkey( int colourkey )
+{
+ xcommon_colourkey = colourkey;
+}
+
+int xcommon_get_visible_width( void )
+{
+ return video_area.width;
+}
+
+int xcommon_get_visible_height( void )
+{
+ return video_area.height;
+}
+
+area_t xcommon_get_window_area( void )
+{
+ return window_area;
+}
+
+void xcommon_set_fullscreen_position( int pos )
+{
+ fullscreen_position = pos;
+ calculate_video_area();
+ xcommon_clear_screen();
+}
+
+void xcommon_set_matte( int width, int height )
+{
+ matte_width = width;
+ matte_height = height;
+ calculate_video_area();
+ xcommon_clear_screen();
+ XSync( display, False );
+}
+
+void xcommon_set_video_scale( area_t scalearea )
+{
+ scale_area = scalearea;
+}
+
+void xcommon_update_xawtv_station( int frequency, int channel_id,
+ const char *channel_name )
+{
+ char data[ 1024 ];
+ int length;
+
+ length = sprintf( data, "%.3f", ((float) frequency) / 1000.0 ) + 1;
+ length += sprintf( data + length, "%d", channel_id ) + 1;
+ length += sprintf( data + length, "%s", channel_name ) + 1;
+
+ XChangeProperty( display, wm_window, xawtv_station,
+ XA_STRING, 8, PropModeReplace,
+ (unsigned char *) data, length );
+}
+
+void xcommon_set_square_pixel_mode( int squarepixel )
+{
+ use_square_pixels = squarepixel;
+}
+
diff -Nurp tvtime-1.0.2/src/xfullscreen.c tvtime-1.0.2-custom/src/xfullscreen.c
--- tvtime-1.0.2/src/xfullscreen.c 2004-10-14 02:12:02.000000000 +0200
+++ tvtime-1.0.2-custom/src/xfullscreen.c 2011-05-29 13:07:28.195707767 +0200
@@ -263,6 +263,10 @@ void xfullscreen_get_position( xfullscre
int max_area = -1;
int i;
+ *x = xf->heads[ 0 ].x;
+ *y = xf->heads[ 0 ].y;
+ *w = xf->heads[ 0 ].w;
+ *h = xf->heads[ 0 ].h;
for( i = 0; i < xf->nheads; i++ ) {
int head_x1 = xf->heads[ i ].x;
int head_x2 = xf->heads[ i ].x + xf->heads[ i ].w - 1;
diff -Nurp tvtime-1.0.2/src/xmltv.c tvtime-1.0.2-custom/src/xmltv.c
--- tvtime-1.0.2/src/xmltv.c 2004-09-26 18:40:01.000000000 +0200
+++ tvtime-1.0.2-custom/src/xmltv.c 2011-05-29 13:07:28.229041508 +0200
@@ -118,9 +118,9 @@ const int num_timezones = sizeof( date_m
typedef struct {
const char *code;
const char *name;
-} locale_t;
+} tv_locale_t;
-static locale_t locale_table[] = {
+static tv_locale_t locale_table[] = {
{"AA", "Afar"}, {"AB", "Abkhazian"}, {"AF", "Afrikaans"},
{"AM", "Amharic"}, {"AR", "Arabic"}, {"AS", "Assamese"},
{"AY", "Aymara"}, {"AZ", "Azerbaijani"}, {"BA", "Bashkir"},
@@ -168,7 +168,7 @@ static locale_t locale_table[] = {
{"XH", "Xhosa"}, {"YO", "Yoruba"}, {"ZH", "Chinese"},
{"ZU", "Zulu"} };
-const int num_locales = sizeof( locale_table ) / sizeof( locale_t );
+const int num_locales = sizeof( locale_table ) / sizeof( tv_locale_t );
/**
* Timezone parsing code based loosely on the algorithm in
diff -Nurp tvtime-1.0.2/src/xvoutput.c tvtime-1.0.2-custom/src/xvoutput.c
--- tvtime-1.0.2/src/xvoutput.c 2005-08-14 19:35:50.000000000 +0200
+++ tvtime-1.0.2-custom/src/xvoutput.c 2011-05-29 13:07:28.189041018 +0200
@@ -233,7 +233,7 @@ static int xv_alloc_frame( void )
{
int size;
uint8_t *alloc;
-
+
size = input_width * input_height * 2;
if( use_shm ) {
alloc = create_shm( size );