diff -ruN vdr-1.5.2/CONTRIBUTORS vdr-1.5.3/CONTRIBUTORS
--- vdr-1.5.2/CONTRIBUTORS	2007-03-11 11:10:49.000000000 +0100
+++ vdr-1.5.3/CONTRIBUTORS	2007-06-10 10:26:07.000000000 +0200
@@ -585,6 +585,7 @@
  for reporting that the shutdown script is given a reboot time in the past if there
  is a recording going on or about to start, and the user insists in shutting down now
  for suggesting to make the channel entry timeout configurable
+ for a patch that was used to implement the SVDRP command REMO
 
 Jeremy Hall <jhall@UU.NET>
  for fixing an incomplete initialization of the filter parameters in eit.c
@@ -1120,6 +1121,7 @@
  for making cCommand::Execute() use cPipe instead of popen() to avoid problems
  with open file handles when starting background commands
  for fixing handling error status in cDvbTuner::GetFrontendStatus()
+ for fixing a busy loop in fast forward if the next video data file is missing
 
 Richard Robson <richard_robson@beeb.net>
  for reporting freezing replay if a timer starts while in Transfer Mode from the
@@ -1395,6 +1397,7 @@
  speed mode"
  for removing 'assert(0)' from cDvbSpuDecoder::setTime()
  for adapting 'libsi' to DVB-S2
+ for fixing handling ChannelUp/Down keys if there is currently a replay running
 
 J�rgen Schmitz <j.schmitz@web.de>
  for reporting a bug in displaying the current channel when switching via the SVDRP
@@ -1491,6 +1494,7 @@
  for implementing cPlugin::WakeupTime() to allow plugins to request VDR to wake
  up at a particular time
  for making the HUP signal force a restart of VDR
+ for fixing a race condition with signal handlers at program exit
 
 Sven Kreiensen <svenk@kammer.uni-hannover.de>
  for his help in keeping 'channels.conf.terr' up to date
@@ -1659,6 +1663,7 @@
  for reporting that there are places where ntohs() is assigned to different types
  for adapting cThread::ThreadId() to recent kernels
  for some improvements to the man pages
+ for fixing some spelling errors in 'newplugin'
 
 Steffen Beyer <cpunk@reactor.de>
  for fixing setting the colored button help after deleting a recording in case the next
@@ -2014,6 +2019,8 @@
  for suggesting that cDevice::GetDevice() should prefer any device that's already
  receiving and doesn't require detatching receivers
  for improving handling Transfer Mode devices when selecting a device to receive
+ for fixing handling frequencies in NitFilter::Process()
+ for making non-primary devices in Transfer mode be also used for recording
 
 Antti Hartikainen <ami+vdr@ah.fi>
  for updating 'S13E' in 'sources.conf'
@@ -2044,6 +2051,7 @@
 
 Matthias Schwarzott <zzam@gentoo.org>
  for suggesting to add LC_ALL to the checks for UTF-8 at startup
+ for fixing getting the code setting from the locale
 
 Martin Ostermann <martin@familie-ostermann.de>
  for fixing processing the PDCDescriptor in 'libsi' on big endian systems
@@ -2072,3 +2080,10 @@
 
 Oktay Yolge�en <oktay_73@yahoo.de>
  for translating OSD texts to the Turkish language
+
+Krzysztof Parma <krzycho@zoz.wodzislaw.pl>
+ for suggesting to implement the SVDRP command REMO
+
+Alexander Riedel <alexander-riedel@t-online.de>
+ for a patch that was used as a base to implement support for Freetype fonts and
+ UTF-8 handling
diff -ruN vdr-1.5.2/HISTORY vdr-1.5.3/HISTORY
--- vdr-1.5.2/HISTORY	2007-04-22 16:49:26.000000000 +0200
+++ vdr-1.5.3/HISTORY	2007-06-10 15:37:03.000000000 +0200
@@ -5165,3 +5165,67 @@
   On its old transponder, the ProSieben/SAT.1 channels also had their EPG data
   wrongly encoded, but apparently on the new transponder they started broadcasting
   on this month, they got it right.
+
+2007-04-30: Version 1.4.6-1
+
+- Fixed a busy loop in fast forward if the next video data file is missing
+  (thanks to Reinhard Nissl).
+- Fixed handling frequencies in NitFilter::Process() (thanks to Anssi Hannula).
+- Fixed handling ChannelUp/Down keys if there is currently a replay running
+  (thanks to Marco Schl��ler).
+- Increased the maximum number of CA system ids to cope with the AlphaCrypt
+  CAM's version 3.11 firmware.
+
+2007-05-12: Version 1.4.7
+
+- Official release.
+
+2007-06-10: Version 1.5.3
+
+- Fixed some spelling errors in 'newplugin' (thanks to Ville Skytt�).
+- Fixed a busy loop in fast forward if the next video data file is missing
+  (thanks to Reinhard Nissl).
+- Fixed handling frequencies in NitFilter::Process() (thanks to Anssi Hannula).
+- Fixed a race condition with signal handlers at program exit (thanks to Udo
+  Richter).
+- Non-primary devices in Transfer mode are now also used for recording (thanks
+  to Anssi Hannula).
+- Fixed handling ChannelUp/Down keys if there is currently a replay running
+  (thanks to Marco Schl��ler).
+- The new SVDRP command REMO can be used to turn VDR's remote control off and
+  on in case other programs need to be controlled (based on patches from Krzysztof
+  Parma and Helmut Auer).
+- Increased the maximum number of CA system ids to cope with the AlphaCrypt
+  CAM's version 3.11 firmware.
+- Fixed getting the code setting from the locale (thanks to Matthias Schwarzott).
+- Implemented support for Freetype fonts (based on a patch from Alexander Riedel).
+  The font names and sizes can be adjusted in the "Setup/OSD" menu.
+  Note that VDR now requires freetype fonts to be installed in
+  /usr/share/fonts/truetype.
+- If the OSD device in use has at least 8bpp bitmap depth and this is also
+  used by the current skin, Freetype fonts are displayed "anti-aliased".
+  The new setup parameter "OSD/Anti-alias" can be used to turn this off.
+- The new function cOsd::SetAntiAliasGranularity() can be used to help the OSD
+  in managing the available color palette entries when doing anti-aliasing.
+  Skins that use 8bpp bitmaps can call this function with the maximum number
+  of colors used, and the maximum number of color combinations. The OSD will
+  then evenly split the available palette entries between the various colors
+  combinations, so that fonts can be "anti-aliased". By default a total of
+  10 colors and 10 combinations is assumed.
+- The pixel fonts have been completely removed from the VDR source.
+- VDR is now "UTF-8 aware". It handles strings according to the character
+  encoding used on the user's system. All internationalization strings and
+  incoming SI data are converted to the system encoding.
+- Plugins that handle strings need to be aware that on systems with UTF-8
+  encoding a "character symbol" may consist of more than a single byte in
+  memory. The functions and macros named Utf8...() can be used to handle
+  strings without needing to care about the underlying character encoding
+  (see tools.h for details).
+- Even though the weekdays of repeating timers are presented to the user as UTF-8
+  characters in the OSD, the timers.conf file and the SVDRP timer commands still
+  use single byte characters ("MTWTFSS") to make sure this information is handled
+  correctly between systems with different character encodings.
+- Added a missing i18n string for "CAM" in the Turkish OSD texts.
+- Improved editing strings that are too long to fit into the editable area.
+- Changes to the OSD settings in the "Setup/OSD" menu now immediately take effect
+  when the "Ok" key is pressed.
diff -ruN vdr-1.5.2/INSTALL vdr-1.5.3/INSTALL
--- vdr-1.5.2/INSTALL	2007-02-24 16:22:48.000000000 +0100
+++ vdr-1.5.3/INSTALL	2007-06-10 15:13:09.000000000 +0200
@@ -1,25 +1,9 @@
 Installation of the Video Disk Recorder
 ---------------------------------------
 
-Version 1.4
+Version 1.5
 -----------
 
-IMPORTANT NOTES:
-----------------
-
-Please make sure your environment is NOT set to use UTF-8 or
-any other multibyte character representation. Check the value of your
-$LANG or $LC_CTYPE environment variable, and if it contains something
-like "de_DE.UTF-8", make sure you set it to something like "de_DE.iso8859-1"
-or whatever single byte character mode you want. If you run VDR with
-UTF-8 enabled, it may crash in case it encounters EPG or channel data
-that contains non-7-bit ASCII characters. Another problem may occur if
-you have mounted your video partition with "iocharset=utf8". In that case
-recordings that contain umlauts or other non-seven-bit ASCII characters
-may be displayed wrong, or not at all. Please make sure you mount your
-video partition with "iocharset=iso8859-1" or whatever single byte character
-mode you want.
-
 Compiling and running the program:
 ----------------------------------
 
@@ -35,11 +19,18 @@
 VDR requires the Linux-DVB driver version dated 2003-08-23 or higher
 to work properly.
 
-You will also need to install the "libjpeg" and "libcap" libraries,
-as well as their "devel" packages to get the necessary header files
-for compiling VDR. If the "capability" module is not compiled into
-your kernel, you may need to do "modprobe capability" before running
-VDR.
+You will also need to install the following libraries, as well as their
+"devel" packages to get the necessary header files for compiling VDR:
+
+  freetype2
+  libcap
+  libjpeg
+
+If the "capability" module is not compiled into your kernel, you may
+need to do "modprobe capability" before running VDR.
+
+When running VDR, the Freetype fonts must be installed in the directory
+/usr/share/fonts/truetype.
 
 After extracting the package, change into the VDR directory
 and type 'make'. This should produce an executable file
diff -ruN vdr-1.5.2/MANUAL vdr-1.5.3/MANUAL
--- vdr-1.5.2/MANUAL	2007-02-25 15:14:06.000000000 +0100
+++ vdr-1.5.3/MANUAL	2007-06-10 15:02:43.000000000 +0200
@@ -503,6 +503,23 @@
                          current skin wants to, and 2 means always use the small
                          font.
 
+  Anti-alias = 1         Controls whether the OSD uses "anti-aliasing" to improve
+                         font rendering. To make this work, the OSD must support
+                         at least 256 colors, and the skin in use has to
+                         utilize these. If either of these conditions is not met,
+                         rendering will be done without anti-aliasing.
+
+  OSD font name = arialbd.ttf
+  Small font name = arial.ttf
+  Fixed font name = courbd.ttf
+                         The file names of the various fonts to use.
+
+  OSD font size = 22
+  Small font size = 18
+  Fixed font size = 20
+                         The sizes (in pixel) of the various fonts. Valid range is
+                         10...64.
+
   Channel info position = bottom
                          The position of the channel info window in the OSD
                          (either 'bottom' or 'top').
diff -ruN vdr-1.5.2/Makefile vdr-1.5.3/Makefile
--- vdr-1.5.2/Makefile	2007-03-11 11:22:18.000000000 +0100
+++ vdr-1.5.3/Makefile	2007-05-28 13:22:42.000000000 +0200
@@ -4,7 +4,7 @@
 # See the main source file 'vdr.c' for copyright information and
 # how to reach the author.
 #
-# $Id: Makefile 1.99 2007/03/11 10:22:18 kls Exp $
+# $Id: Makefile 1.100 2007/05/28 11:22:42 kls Exp $
 
 .DELETE_ON_ERROR:
 
@@ -17,8 +17,8 @@
 LSIDIR   = ./libsi
 MANDIR   = /usr/local/man
 BINDIR   = /usr/local/bin
-LIBS     = -ljpeg -lpthread -ldl -lcap
-INCLUDES =
+LIBS     = -ljpeg -lpthread -ldl -lcap -lfreetype
+INCLUDES = -I/usr/include/freetype2
 
 PLUGINDIR= ./PLUGINS
 PLUGINLIBDIR= $(PLUGINDIR)/lib
@@ -39,34 +39,6 @@
        skinclassic.o skins.o skinsttng.o sources.o spu.o status.o svdrp.o themes.o thread.o\
        timers.o tools.o transfer.o vdr.o videodir.o
 
-FIXFONT_ISO8859_1 = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1
-OSDFONT_ISO8859_1 = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1
-SMLFONT_ISO8859_1 = -adobe-helvetica-medium-r-normal--18-*-100-100-p-*-iso8859-1
-
-FIXFONT_ISO8859_2 = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-2
-OSDFONT_ISO8859_2 = -adobe-helvetica-medium-r-normal--24-*-75-75-p-*-iso8859-2
-SMLFONT_ISO8859_2 = -adobe-helvetica-medium-r-normal--18-*-75-75-p-*-iso8859-2
-
-FIXFONT_ISO8859_5 = -rfx-courier-bold-r-normal--24-*-75-75-m-*-iso8859-5
-OSDFONT_ISO8859_5 = -rfx-helvetica-medium-r-normal--24-*-75-75-p-*-iso8859-5
-SMLFONT_ISO8859_5 = -rfx-helvetica-medium-r-normal--18-*-75-75-p-*-iso8859-5
-
-FIXFONT_ISO8859_7 = --user-medium-r-normal--26-171-110-110-m-140-iso8859-7
-OSDFONT_ISO8859_7 = --user-medium-r-normal--23-179-85-85-m-120-iso8859-7
-SMLFONT_ISO8859_7 = --user-medium-r-normal--19-160-72-72-m-110-iso8859-7
-
-FIXFONT_ISO8859_9 = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-9
-OSDFONT_ISO8859_9 = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-9
-SMLFONT_ISO8859_9 = -adobe-helvetica-medium-r-normal--18-*-100-100-p-*-iso8859-9
-
-FIXFONT_ISO8859_13 = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-13
-OSDFONT_ISO8859_13 = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-13
-SMLFONT_ISO8859_13 = -adobe-helvetica-medium-r-normal--18-*-100-100-p-*-iso8859-13
-
-FIXFONT_ISO8859_15 = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-15
-OSDFONT_ISO8859_15 = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-15
-SMLFONT_ISO8859_15 = -adobe-helvetica-medium-r-normal--18-*-100-100-p-*-iso8859-15
-
 ifndef NO_KBD
 DEFINES += -DREMOTE_KBD
 endif
@@ -98,15 +70,6 @@
 endif
 
 all: vdr
-font: genfontfile\
-      fontfix-iso8859-1.c fontosd-iso8859-1.c fontsml-iso8859-1.c\
-      fontfix-iso8859-2.c fontosd-iso8859-2.c fontsml-iso8859-2.c\
-      fontfix-iso8859-5.c fontosd-iso8859-5.c fontsml-iso8859-5.c\
-      fontfix-iso8859-7.c fontosd-iso8859-7.c fontsml-iso8859-7.c\
-      fontfix-iso8859-9.c fontosd-iso8859-9.c fontsml-iso8859-9.c\
-      fontfix-iso8859-13.c fontosd-iso8859-13.c fontsml-iso8859-13.c\
-      fontfix-iso8859-15.c fontosd-iso8859-15.c fontsml-iso8859-15.c
-	@echo "font files created."
 
 # Implicit rules:
 
@@ -127,62 +90,6 @@
 vdr: $(OBJS) $(SILIB)
 	$(CXX) $(CXXFLAGS) -rdynamic $(OBJS) $(NCURSESLIB) $(LIBS) $(LIBDIRS) $(SILIB) -o vdr
 
-# The font files:
-
-fontfix-iso8859-1.c:
-	./genfontfile "cFont::tPixelData FontFix_iso8859_1" "$(FIXFONT_ISO8859_1)" > $@
-fontosd-iso8859-1.c:
-	./genfontfile "cFont::tPixelData FontOsd_iso8859_1" "$(OSDFONT_ISO8859_1)" > $@
-fontsml-iso8859-1.c:
-	./genfontfile "cFont::tPixelData FontSml_iso8859_1" "$(SMLFONT_ISO8859_1)" > $@
-
-fontfix-iso8859-2.c:
-	./genfontfile "cFont::tPixelData FontFix_iso8859_2" "$(FIXFONT_ISO8859_2)" > $@
-fontosd-iso8859-2.c:
-	./genfontfile "cFont::tPixelData FontOsd_iso8859_2" "$(OSDFONT_ISO8859_2)" > $@
-fontsml-iso8859-2.c:
-	./genfontfile "cFont::tPixelData FontSml_iso8859_2" "$(SMLFONT_ISO8859_2)" > $@
-
-fontfix-iso8859-5.c:
-	./genfontfile "cFont::tPixelData FontFix_iso8859_5" "$(FIXFONT_ISO8859_5)" > $@
-fontosd-iso8859-5.c:
-	./genfontfile "cFont::tPixelData FontOsd_iso8859_5" "$(OSDFONT_ISO8859_5)" > $@
-fontsml-iso8859-5.c:
-	./genfontfile "cFont::tPixelData FontSml_iso8859_5" "$(SMLFONT_ISO8859_5)" > $@
-
-fontfix-iso8859-7.c:
-	./genfontfile "cFont::tPixelData FontFix_iso8859_7" "$(FIXFONT_ISO8859_7)" > $@
-fontosd-iso8859-7.c:
-	./genfontfile "cFont::tPixelData FontOsd_iso8859_7" "$(OSDFONT_ISO8859_7)" > $@
-fontsml-iso8859-7.c:
-	./genfontfile "cFont::tPixelData FontSml_iso8859_7" "$(SMLFONT_ISO8859_7)" > $@
-
-fontfix-iso8859-9.c:
-	./genfontfile "cFont::tPixelData FontFix_iso8859_9" "$(FIXFONT_ISO8859_9)" > $@
-fontosd-iso8859-9.c:
-	./genfontfile "cFont::tPixelData FontOsd_iso8859_9" "$(OSDFONT_ISO8859_9)" > $@
-fontsml-iso8859-9.c:
-	./genfontfile "cFont::tPixelData FontSml_iso8859_9" "$(SMLFONT_ISO8859_9)" > $@
-
-fontfix-iso8859-13.c:
-	./genfontfile "cFont::tPixelData FontFix_iso8859_13" "$(FIXFONT_ISO8859_13)" > $@
-fontosd-iso8859-13.c:
-	./genfontfile "cFont::tPixelData FontOsd_iso8859_13" "$(OSDFONT_ISO8859_13)" > $@
-fontsml-iso8859-13.c:
-	./genfontfile "cFont::tPixelData FontSml_iso8859_13" "$(SMLFONT_ISO8859_13)" > $@
-
-fontfix-iso8859-15.c:
-	./genfontfile "cFont::tPixelData FontFix_iso8859_15" "$(FIXFONT_ISO8859_15)" > $@
-fontosd-iso8859-15.c:
-	./genfontfile "cFont::tPixelData FontOsd_iso8859_15" "$(OSDFONT_ISO8859_15)" > $@
-fontsml-iso8859-15.c:
-	./genfontfile "cFont::tPixelData FontSml_iso8859_15" "$(SMLFONT_ISO8859_15)" > $@
-
-# The font file generator:
-
-genfontfile: genfontfile.c
-	$(CC) $(CFLAGS) -o $@ -L/usr/X11R6/lib $< -lX11
-
 # The libsi library:
 
 $(SILIB):
@@ -261,10 +168,8 @@
 
 clean:
 	$(MAKE) -C $(LSIDIR) clean
-	-rm -f $(OBJS) $(DEPFILE) vdr genfontfile genfontfile.o core* *~
+	-rm -f $(OBJS) $(DEPFILE) vdr core* *~
 	-rm -rf include
 	-rm -rf srcdoc
-fontclean:
-	-rm -f fontfix*.c fontosd*.c fontsml*.c
-CLEAN: clean fontclean
+CLEAN: clean
 
diff -ruN vdr-1.5.2/PLUGINS.html vdr-1.5.3/PLUGINS.html
--- vdr-1.5.2/PLUGINS.html	2007-02-24 16:32:06.000000000 +0100
+++ vdr-1.5.3/PLUGINS.html	2007-06-10 14:25:51.000000000 +0200
@@ -6,7 +6,7 @@
 
 <center><h1>The VDR Plugin System</h1></center>
 
-<center><b>Version 1.5.1</b></center>
+<center><b>Version 1.5.3</b></center>
 <p>
 <center>
 Copyright &copy; 2006 Klaus Schmidinger<br>
@@ -14,12 +14,15 @@
 <a href="http://www.cadsoft.de/vdr">www.cadsoft.de/vdr</a>
 </center>
 <p>
-<!--X1.5.0--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
+<!--X1.5.0--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
 Important modifications introduced in version 1.5.0 are marked like this.
 <!--X1.5.0--></td></tr></table>
-<!--X1.5.1--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
+<!--X1.5.1--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
 Important modifications introduced in version 1.5.1 are marked like this.
 <!--X1.5.1--></td></tr></table>
+<!--X1.5.3--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
+Important modifications introduced in version 1.5.3 are marked like this.
+<!--X1.5.3--></td></tr></table>
 <p>
 VDR provides an easy to use plugin interface that allows additional functionality
 to be added to the program by implementing a dynamically loadable library file.
@@ -58,7 +61,7 @@
 <li><a href="#Housekeeping">Housekeeping</a>
 <li><a href="#Main thread hook">Main thread hook</a>
 <li><a href="#Activity">Activity</a>
-<!--X1.5.1--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
+<!--X1.5.1--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
 <li><a href="#Wakeup">Wakeup</a>
 <!--X1.5.1--></td></tr></table>
 <li><a href="#Setup parameters">Setup parameters</a>
@@ -82,7 +85,7 @@
 <li><a href="#Devices">Devices</a>
 <li><a href="#Audio">Audio</a>
 <li><a href="#Remote Control">Remote Control</a>
-<!--X1.5.0--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
+<!--X1.5.0--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
 <li><a href="#Conditional Access">Conditional Access</a>
 <!--X1.5.0--></td></tr></table>
 </ul>
@@ -681,7 +684,7 @@
 the shutdown will take place. As soon as one prompt is not confirmed, no
 further plugins will be queried and no shutdown will be done.
 
-<!--X1.5.1--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
+<!--X1.5.1--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
 <a name="Wakeup"><hr><h2>Wakeup</h2>
 
 <center><i><b>Wake me up before you go-go</b></i></center><p>
@@ -970,6 +973,19 @@
 Texts are first searched for in the <i>Phrases</i> registered for this plugin (if any)
 and then in the global VDR texts. So a plugin can make use of texts defined by the
 core VDR code.
+<p>
+<!--X1.5.3--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
+The system VDR is running on may use a character encoding where a single character
+(or <i>symbol</i>) consists of more than one byte (UTF-8, as opposed to, for instance,
+ISO8859-1, where every character is represented by a single byte in memory).
+In order to make sure a plugin works regardless of the character encoding the current
+system uses, the VDR core code provides several functions and macros that allow accessing
+text strings transparently without knowing whether this is a single or multi byte
+character set. The names of these functions and macros are all of the form <tt>Utf8...()</tt>,
+and are defined in <tt>VDR/tools.h</tt>.
+Most of the time a plugin doesn't need to care about this, but when it comes to
+handling individual characters these functions may come in handy.
+<!--X1.5.3--></td></tr></table>
 
 <a name="Custom services"><hr><h2>Custom services</h2>
 
@@ -1618,7 +1634,22 @@
 with the full required resolution. Only if this fails shall it use alternate
 areas. Drawing areas are always rectangular and may not overlap (but do not need
 to be adjacent).
+<p>
+<!--X1.5.3--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
+Special consideration may have to be given to color usage if the OSD provides
+8bpp (256 colors). In that case, fonts may be drawn using <i>anti-aliasing</i>,
+which requires several blended color values between the foreground and background
+color. In order to not use up the whole color palette for a single color
+combination (and thus be unable to draw any other colors at all), it may be
+useful to call
+
+<p><table><tr><td bgcolor=#F0F0F0><pre>
+osd-&gt;SetAntiAliasGranularity();
+</pre></td></tr></table><p>
 
+which allows the system to evenly distribute the palette entries to the various
+color combinations (see <tt>VDR/osd.h</tt> for details).
+<!--X1.5.3--></td></tr></table>
 <p>
 Directly accessing the OSD is only allowed from the foreground thread, which
 restricts this to a <tt>cOsdObject</tt> returned from the plugin's <tt>MainMenuAction()</tt>
@@ -2087,7 +2118,7 @@
 
 The other parameters have the same meaning as in the first version of this function.
 
-<!--X1.5.0--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
+<!--X1.5.0--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
 <a name="Conditional Access"><hr><h2>Conditional Access</h2>
 
 <center><i><b>Members only!</b></i></center><p>
diff -ruN vdr-1.5.2/channels.conf vdr-1.5.3/channels.conf
--- vdr-1.5.2/channels.conf	2007-01-07 14:55:46.000000000 +0100
+++ vdr-1.5.3/channels.conf	2007-06-10 15:28:09.000000000 +0200
@@ -1,13 +1,13 @@
 RTL Television,RTL;RTL World:12187:hC34:S19.2E:27500:163:104=deu;106=deu:105:0:12003:1:1089:0
-SAT.1;ProSiebenSat.1:12480:vC34:S19.2E:27500:1791:1792=deu;1795=deu:34:0:46:133:33:0
-ProSieben;ProSiebenSat.1:12480:vC34:S19.2E:27500:255:256=deu;257=deu:32:0:898:133:33:0
+SAT.1;ProSiebenSat.1:12544:hC56:S19.2E:22000:255:256=deu;259=deu:32:0:17500:1:1107:0
+ProSieben;ProSiebenSat.1:12544:hC56:S19.2E:22000:511:512=deu;515=deu:33:0:17501:1:1107:0
 RTL2;RTL World:12187:hC34:S19.2E:27500:166:128=deu:68:0:12020:1:1089:0
-Das Erste;ARD:11836:hC34:S19.2E:27500:101:102=deu;106=deu:104:0:28106:1:1101:0
-Bayerisches FS;ARD:11836:hC34:S19.2E:27500:201:202=deu:204:0:28107:1:1101:0
+Das Erste;ARD:11836:hC34:S19.2E:27500:101:102=deu,103=2ch;106=dd:104:0:28106:1:1101:0
+Bayerisches FS;ARD:11836:hC34:S19.2E:27500:201:202=deu,203=2ch:204:0:28107:1:1101:0
 hr-fernsehen;ARD:11836:hC34:S19.2E:27500:301:302=deu:304:0:28108:1:1101:0
 NDR FS MV;ARD:12109:hC34:S19.2E:27500:2401:2402=deu:2404:0:28224:1:1073:0
 SR Fernsehen;ARD:12265:hC34:S19.2E:27500:1301:1302=deu:1304:0:28486:1:1093:0
-WDR K�ln;ARD:11836:hC34:S19.2E:27500:601:602=deu:604:0:28111:1:1101:0
+WDR Köln;ARD:11836:hC34:S19.2E:27500:601:602=deu:604:0:28111:1:1101:0
 BR-alpha;ARD:11836:hC34:S19.2E:27500:701:702=deu:704:0:28112:1:1101:0
 SWR Fernsehen BW;ARD:11836:hC34:S19.2E:27500:801:802=deu:804:0:28113:1:1101:0
 Phoenix;ARD:11836:hC34:S19.2E:27500:901:902=deu:904:0:28114:1:1101:0
@@ -15,23 +15,26 @@
 3sat;ZDFvision:11953:hC34:S19.2E:27500:210:220=deu,221=2ch;225=dd:230:0:28007:1:1079:0
 KiKa;ZDFvision:11953:hC34:S19.2E:27500:310:320=deu:330:0:28008:1:1079:0
 arte;ARD:11836:hC34:S19.2E:27500:401:402=deu,403=fra:404:0:28109:1:1101:0
+ORF1;ORF:562:C34D34M16B8T8G4Y0:T:27500:3210:3211=deu;3213=deu:3215:0:10101:13130:320:0
+ORF2S;ORF:562:C34D34M16B8T8G4Y0:T:27500:3220:3221=deu;3223=deu:3225:0:10107:13130:320:0
+ATV;ORF:562:C34D34M16B8T8G4Y0:T:27500:3240:3241=deu:3245:0:10120:13130:320:0
 ORF1;ORF:12692:hC56:S19.2E:22000:160:161=deu;163=deu:165:1762,D05,1801,1702:13001:1:1117:0
 ORF2;ORF:12692:hC56:S19.2E:22000:500:501=deu;503=deu:505:1762,D05,1801,1702:13002:1:1117:0
 ZDFinfokanal;ZDFvision:11953:hC34:S19.2E:27500:610:620=deu:630:0:28011:1:1079:0
 CNN Int.;CNN:11778:vC34:S19.2E:27500:165:100=eng:47:0:28522:1:1068:0
 Super RTL,S RTL;RTL World:12187:hC34:S19.2E:27500:165:120=deu:65:0:12040:1:1089:0
 VOX;RTL World:12187:hC34:S19.2E:27500:167:136=deu:71:0:12060:1:1089:0
-KABEL1;ProSiebenSat.1:12480:vC34:S19.2E:27500:511:512=deu:33:0:899:133:33:0
+kabel eins;ProSiebenSat.1:12544:hC56:S19.2E:22000:767:768=deu:34:0:17502:1:1107:0
 DAS VIERTE,D VIERTE;BetaDigital:12460:hC34:S19.2E:27500:2047:2048=deu:36:0:1793:133:5:0
-9Live;BetaDigital:12480:vC34:S19.2E:27500:767:768=deu:35:0:897:133:33:0
+9Live;ProSiebenSat.1:12544:hC56:S19.2E:22000:1279:1280=deu:36:0:17504:1:1107:0
 DSF;BetaDigital:12480:vC34:S19.2E:27500:1023:1024=deu:39:0:900:133:33:0
 HSE24,HSE24;BetaDigital:12480:vC34:S19.2E:27500:1279:1280=deu:37:0:40:133:33:0
 Bloomberg TV Germany;Bloomberg:12551:vC56:S19.2E:22000:162:99=deu:0:0:12160:1:1108:0
 EURONEWS;CSAT:11817:vC34:S19.2E:27500:163:92=fra,93=eng,94=ita,95=esl,91=rus,98=por,99=deu:0:0:8004:1:1070:0
 rbb Brandenburg;ARD:12109:hC34:S19.2E:27500:601:602=deu:604:0:28205:1:1073:0
 Sky News;BT:11597:vC56:S19.2E:22000:305+131:306=eng:579:0:28707:1:1026:0
-Veronica/JETIX;CANALDIGITAAL:12574:hC56:S19.2E:22000:518+8190:92=dut:38:622,100:5020:53:1109:0
-BVN;CANALDIGITAAL:12574:hC56:S19.2E:22000:515+8190:96=dut:36:0:5025:53:1109:0
+Veronica/JETIX;CANALDIGITAAL SATELLIET:12574:hC56:S19.2E:22000:518+8190:92=dut:38:622,100:5020:53:1109:0
+BVN;CANALDIGITAAL SATELLIET:12574:hC56:S19.2E:22000:515+8190:96=dut:36:0:5025:53:1109:0
 n-tv;RTL World:12187:hC34:S19.2E:27500:169:73=deu:80:0:12090:1:1089:0
 Al Jazeera;CANALSATELLITE:11567:vC56:S19.2E:22000:55:56=ara:0:0:9021:1:1024:0
 TW1;ORF:12662:hC56:S19.2E:22000:1010:1011=deu:1013:0:13101:1:1115:0
@@ -44,27 +47,27 @@
 MDR FERNSEHEN;ARD:12109:hC34:S19.2E:27500:401:402=deu:404:0:28204:1:1073:0
 rbb Berlin;ARD:12109:hC34:S19.2E:27500:601:602=deu:604:0:28206:1:1073:0
 :Premiere World
-PREMIERE START,START;PREMIERE:12070:hC34:S19.2E:27500:3071:3072=deu:32:1702,1722,1801:8:133:1:0
-PREMIERE 1,PREM 1;PREMIERE:11797:hC34:S19.2E:27500:511:512=deu,513=deu;515=deu:32:1722,1702,1801:10:133:2:0
-PREMIERE 2,PREM 2;PREMIERE:11797:hC34:S19.2E:27500:1791:1792=deu,1793=deu;1795=deu:32:1801,1722,1702:11:133:2:0
-PREMIERE 3,PREM 3;PREMIERE:11797:hC34:S19.2E:27500:2303:2304=deu,2305=deu;2307=deu:32:1702,1722,1801:43:133:2:0
-PREMIERE 4,PREM 4;PREMIERE:11797:hC34:S19.2E:27500:767:768=deu,769=deu;771=deu:32:1801,1722,1702:9:133:2:0
-PREMIERE SERIE,SERIE;PREMIERE:11797:hC34:S19.2E:27500:2559:2560=deu;2563=deu:32:1801,1702,1722:16:133:2:0
-PREMIERE KRIMI,KRIMI;PREMIERE:11797:hC34:S19.2E:27500:2815:2816=deu:32:1702,1801,1722:23:133:2:0
-PREMIERE NOSTALGIE,NOSTALGIE;PREMIERE:11719:hC34:S19.2E:27500:1535:1536=deu:32:1702,1801,1722:516:133:3:0
-PREMIERE FILMCLASSICS,FILMCLASSICS;PREMIERE:11719:hC34:S19.2E:27500:1023:1024=deu:32:1722,1702,1801:41:133:3:0
-PREMIERE FILMFEST,FILMFEST;PREMIERE:11719:hC34:S19.2E:27500:1279:1280=deu:32:1801,1702,1722:20:133:3:0
-DISNEY CHANNEL,DISNEY;PREMIERE:11758:hC34:S19.2E:27500:2559:2560=deu:32:1801,1702,1722:34:133:17:0
+PREMIERE START,START;PREMIERE:12070:hC34:S19.2E:27500:3071:3072=deu:32:1722,1702,1801:8:133:1:0
+PREMIERE 1,PREM 1;PREMIERE:11797:hC34:S19.2E:27500:511:512=deu,513=deu;515=deu:32:1702,1722,1831,1801:10:133:2:0
+PREMIERE 2,PREM 2;PREMIERE:11797:hC34:S19.2E:27500:1791:1792=deu,1793=deu;1795=deu:32:1702,1831,1722,1801:11:133:2:0
+PREMIERE 3,PREM 3;PREMIERE:11797:hC34:S19.2E:27500:2303:2304=deu,2305=deu;2307=deu:32:1722,1831,1702,1801:43:133:2:0
+PREMIERE 4,PREM 4;PREMIERE:11797:hC34:S19.2E:27500:767:768=deu,769=deu;771=deu:32:1831,1722,1702,1801:9:133:2:0
+PREMIERE SERIE,SERIE;PREMIERE:11797:hC34:S19.2E:27500:2559:2560=deu;2563=deu:32:1831,1801,1722,1702:16:133:2:0
+PREMIERE KRIMI,KRIMI;PREMIERE:11797:hC34:S19.2E:27500:2815:2816=deu:32:1831,1702,1722,1801:23:133:2:0
+PREMIERE NOSTALGIE,NOSTALGIE;PREMIERE:11719:hC34:S19.2E:27500:1535:1536=deu:32:1722,1831,1702,1801:516:133:3:0
+PREMIERE FILMCLASSICS,FILMCLASSICS;PREMIERE:11719:hC34:S19.2E:27500:1023:1024=deu,1025=deu:32:1831,1801,1722,1702:41:133:3:0
+PREMIERE FILMFEST,FILMFEST;PREMIERE:11719:hC34:S19.2E:27500:1279:1280=deu:32:1831,1801,1702,1722:20:133:3:0
+DISNEY CHANNEL,DISNEY;PREMIERE:11758:hC34:S19.2E:27500:2559:2560=deu:32:1831,1702,1722,1801:34:133:17:0
 :Premiere Direkt
 PREMIERE DIREKT,DIREKT;PREMIERE:12031:hC34:S19.2E:27500:2815:2816=deu,2817=deu;2819=deu:0:0:18:133:4:0
 :PW Erotic
 BEATE-UHSE.TV,B-UHSE;PREMIERE:11758:hC34:S19.2E:27500:1791:1792=deu:32:1702,1722,1801:21:133:17:0
 EROTIK - AB 18!,AB 18!;PREMIERE:12031:hC34:S19.2E:27500:1279:1280=deu:0:1722,1801,1702,1810:513:133:4:0
 :Sportsworld
-PREMIERE SPORT PORTAL,SPORT PORTAL;PREMIERE:11719:hC34:S19.2E:27500:255:256=deu,257=deu;259=deu:32:1722,1801,1702:17:133:3:0
-PREMIERE WIN,WIN;PREMIERE:12031:hC34:S19.2E:27500:3839:3840=deu:33:0:27:133:4:0
+PREMIERE SPORT PORTAL,SPORT PORTAL;PREMIERE:11719:hC34:S19.2E:27500:255:256=deu,257=deu;259=deu:32:1831,1722,1801,1702:17:133:3:0
+BIG BROTHER,BROTHER;PREMIERE:12031:hC34:S19.2E:27500:3839:3840=deu:0:1831,1702,1722,1801:27:133:4:0
 :Beta Digital
-N24;ProSiebenSat.1:12480:vC34:S19.2E:27500:2047:2048=deu:36:0:47:133:33:0
+N24;ProSiebenSat.1:12544:hC56:S19.2E:22000:1023:1024=deu:35:0:17503:1:1107:0
 LibertyTV FR;LibertyTV.com:12610:vC56:S19.2E:22000:941:943=deu:0:0:12199:1:1112:0
 :-
 APS.TV3;BetaDigital:12148:hC34:S19.2E:27500:495:496=deu:0:0:658:133:7:0
@@ -75,19 +78,19 @@
 FRANCE 5;CSAT:12207:vC34:S19.2E:27500:160:80=fra:32:500,100:8501:1:1090:0
 LCP;ABSAT:12285:vC34:S19.2E:27500:167:108:0:0:17027:1:1094:0
 ESCALES;ABSAT:12285:vC34:S19.2E:27500:165:100:41:500,100:17025:1:1094:0
-BEST OF SHOPPING;CSAT:12324:vC34:S19.2E:27500:160:80=fra:0:0:8612:1:1096:0
+BEST OF SHOPPING;CSAT:12324:vC34:S19.2E:27500:2047+160:0:0:0:8612:1:1096:0
 ASTRA-Mosaic;SES ASTRA:12551:vC56:S19.2E:22000:175:176=fra:0:0:3988:1:1108:0
 ASTRA-Mosaic 2;SES ASTRA:12551:vC56:S19.2E:22000:179:120=fra:0:0:3987:1:1108:0
 ASTRA-Mosaic 3;SES ASTRA:12551:vC56:S19.2E:22000:182:169=fra:0:0:3986:1:1108:0
 ASTRA-Mosaic 4;SES ASTRA:12551:vC56:S19.2E:22000:185:170=fra:0:0:3985:1:1108:0
 ASTRA-Mosaic 5;SES ASTRA:12551:vC56:S19.2E:22000:163:164:0:0:3984:1:1108:0
-Chamber TV;Chambre des D�put�es:12551:vC56:S19.2E:22000:55:56=ltz:0:0:12180:1:1108:0
+Chamber TV;Chambre des DØputØes:12551:vC56:S19.2E:22000:55:56=ltz:0:0:12180:1:1108:0
 RTL Tele Letzebuerg:12551:vC56:S19.2E:22000:168:144=ltz,146=fra:301:0:3994:1:1108:0
-tien;CANALDIGITAAL:12574:hC56:S19.2E:22000:512+8190:84=dut:33:622,100:5010:53:1109:0
+tien;CANALDIGITAAL SATELLIET:12574:hC56:S19.2E:22000:512+8190:84=dut:33:622,100:5010:53:1109:0
 NICK AUSTRIA;MTV Networks:12226:hC34:S19.2E:27500:513+8190:661=deu:577:0:28640:1:1091:0
 Service 3;MTV Networks Europe:11739:vC34:S19.2E:27500:3031:3032:3034:0:28653:1:1066:0
 VIVA;MTV Networks Europe:11973:vC34:S19.2E:27500:4061+8190:4062:4064:0:28676:1:1078:0
-VIVA PLUS;MTV Networks Europe:11973:vC34:S19.2E:27500:4071+8190:4072:4074:0:28677:1:1078:0
+COMEDY CENTRAL;MTV Networks Europe:11973:vC34:S19.2E:27500:4071+8190:4072:4074:0:28677:1:1078:0
 QVC Deutschland;QVC:12551:vC56:S19.2E:22000:165:166:167:0:12100:1:1108:0
 TELE 5;BetaDigital:12480:vC34:S19.2E:27500:1535:1536=deu:38:0:51:133:33:0
 :NTSC
@@ -103,30 +106,30 @@
 Astra HD:12441:vC34:S19.2E:27500:133+80:134=eng:0:0:29700:0:0:0
 TV HD;CSAT:12581:vC56:S19.2E:22000:165:100=fra;101=fra:0:0:9306:1:1110:0
 C M HD;Telenor:11261:hC78:S1.0W:24500:517:660=eng;661=eng:0:B00:3306:70:33:0
-CANAL+ HD;Telenor:11389:hC78:S1.0W:24500:512:640;641=eng:580:0:3306:70:34:0
-HELLAS-HDTV;Scopus Network Technologies:11645:hC34:S13.0E:27500:2201:2211=ell,2212=eng:0:0:2200:318:15700:0
+CANAL+ HD;Telenor:11389:hC78:S1.0W:24500:512:640=eng;641=eng:580:0:3306:70:34:0
+Era 2;Service Provider:11645:hC34:S13.0E:27500:2201:2211=ell,2212=eng:0:0:2200:318:15700:0
 TPS Star:10757:vC34:S13.0E:27500:420:430=fra,431=eng:440:500,100:1204:176:11200:0
 :@201 Sky
 Sky One;BSkyB:12285:vC23:S28.2E:27500:513+8190:641=eng,661=NAR:577:960,961:4703:2:2030:0
 Sky Two;BSkyB:12226:hC23:S28.2E:27500:514+8190:642=eng,662=NAR:578:960,961:5104:2:2027:0
-ITV2;BSkyB:10758:vC56:S28.2E:22000:2348:2349=eng,2352=NAR:2354:0:10070:2:2044:0
+ITV2;BSkyB:10758:vC56:S28.2E:22000:2348:2349=eng,2351=NAR:2353:0:10070:2:2044:0
 SCI FI;BSkyB:12148:hC23:S28.2E:27500:512+8190:640=eng,660=NAR:576:960,961:4905:2:2023:0
 ParaComedy 1;BSkyB:12187:hC23:S28.2E:27500:518+8190:666=eng,686=NAR:582:960,961:5904:2:2025:0
 ParaComedy 1;BSkyB:11526:vC23:S28.2E:27500:2317+2306:2318=eng:2319:960,961:50305:2:2404:0
 ParaComedy 2;BSkyB:11914:hC23:S28.2E:27500:514+8190:642=eng,662=NAR:578:960,961:4504:2:2011:0
 Discovery;BSkyB:11875:hC23:S28.2E:27500:2308:2310=eng,2311=NAR:2309:960,961:6201:2:2009:0
-Sky Movies 1;BSkyB:11836:hC23:S28.2E:27500:518+8190:646=eng,653=NAR;666=eng:582:960,961:4303:2:2007:0
-Sky Movies 2;BSkyB:11836:hC23:S28.2E:27500:519+8190:647=eng,655=NAR;667=eng:583:960,961:4302:2:2007:0
-Sky Movies 3;BSkyB:11836:hC23:S28.2E:27500:520+8190:648=eng,654=NAR;668=eng:584:960,961:4403:2:2007:0
-Sky Movies 4;BSkyB:11836:hC23:S28.2E:27500:512+8190:640=eng,657=NAR;660=eng:576:960,961:4304:2:2007:0
-Sky Movies 5;BSkyB:11836:hC23:S28.2E:27500:513+8190:641=eng,658=NAR;661=eng:577:960,961:4305:2:2007:0
-Sky Movies 6;BSkyB:11836:hC23:S28.2E:27500:514+8190:642=eng,659=NAR;662=eng:578:960,961:4306:2:2007:0
+Sky Comedy;BSkyB:11836:hC23:S28.2E:27500:518+8190:646=eng,686=NAR;666=eng:582:960,961:4303:2:2007:0
+Sky Action;BSkyB:11836:hC23:S28.2E:27500:519+8190:647=eng,687=NAR;667=eng:583:960,961:4302:2:2007:0
+Sky Family;BSkyB:11836:hC23:S28.2E:27500:520+8190:648=eng,688=NAR;668=eng:584:960,961:4403:2:2007:0
+Sky ScFi/Horror;BSkyB:11836:hC23:S28.2E:27500:512+8190:640=eng,680=NAR;660=eng:576:960,961:4304:2:2007:0
+Sky Classics;BSkyB:11836:hC23:S28.2E:27500:513+8190:641=eng,681=NAR;661=eng:577:960,961:4305:2:2007:0
+Sky Indie;BSkyB:11836:hC23:S28.2E:27500:514+8190:642=eng,682=NAR;662=eng:578:960,961:4306:2:2007:0
 Sky Movies 7;BSkyB:12285:vC23:S28.2E:27500:515+8190:643=eng,653=NAR;663=eng:579:960,961:4603:2:2030:0
-Sky Movies 8;BSkyB:11836:hC23:S28.2E:27500:515+8190:643=eng,656=NAR;663=eng:579:960,961:5502:2:2007:0
-Sky Movies 9;BSkyB:12285:vC23:S28.2E:27500:518+8190:646=eng,654=NAR;666=eng:2440:960,961:4602:2:2030:0
-Sky Movies 10;BSkyB:12285:vC23:S28.2E:27500:514+8190:642=eng,655=NAR;662=eng:2441:960,961:4604:2:2030:0
-Sky Cinema 1;BSkyB:11603:vC23:S28.2E:27500:513+129:641=eng,661=NAR:577:960,961:4651:2:2408:0
-Sky Cinema 2;BSkyB:11603:vC23:S28.2E:27500:514+130:642=eng,662=NAR:578:960,961:4652:2:2408:0
+Sky Drama;BSkyB:11836:hC23:S28.2E:27500:515+8190:643=eng,683=NAR;663=eng:579:960,961:5502:2:2007:0
+SkyMovies SD1;BSkyB:12285:vC23:S28.2E:27500:518+8190:646=eng,686=NAR;666=eng:2328:960,961:4602:2:2030:0
+SkyMovies SD2;BSkyB:12285:vC23:S28.2E:27500:514+8190:642=eng,682=NAR;662=eng:2331:960,961:4604:2:2030:0
+Sky Premiere;BSkyB:11603:vC23:S28.2E:27500:513+129:641=eng,661=NAR;681=eng:577:960,961:4651:2:2408:0
+Sky Prem+1;BSkyB:11603:vC23:S28.2E:27500:514+130:642=eng,662=NAR;682=eng:578:960,961:4652:2:2408:0
 :@900 Some 'seed' channels
 Chelsea TV;BskyB:11778:vC23:S28.2E:27500:2308+2304:2309=eng:0:960,961:9307:2:2004:0
 WDR M�nster;ARD:12421:hC34:S19.2E:27500:101:102=deu:104:0:28310:1:1201:0
@@ -135,8 +138,8 @@
 CNN;BSkyB:12051:vC23:S28.2E:27500:2317:2319=eng:2318:0:7140:2:2018:0
 BBC PARL'MNT;BSkyB:10847:vC56:S28.2E:22000:2327:2328=eng:2331:0:6902:2:2050:0
 MTI;T-Systems/MTI:11200:vC56:S13.0E:27500:4097:4098:0:0:4733:318:13400:0
-WRN Eng AAP;WRN:12597:vC34:S13.0E:27500:0:2132:0:0:8230:318:9400:0
-Dr Dish TV;Overon:12359:hC34:S13.0E:27500:4231:4232:0:0:14023:318:8300:0
+WRN Eng AAP;Globecast:12597:vC34:S13.0E:27500:0:2132:0:0:8230:318:9400:0
+DrDish Television;BetaDigital:12246:vC34:S19.2E:27500:2047:2048=deu:0:0:10107:1:1092:0
 ! LifeStyle-TV !;T-Systems:12633:hC56:S19.2E:22000:204:304=deu:0:0:12603:1:1113:0
 Challenger Tv;Telespazio:11295:hC34:S13.0E:27500:490:491:0:0:8409:318:500:0
 NDS Enc 3;NDS:11535:vC34:S1.0W:5632:308+8190:256=eng,257=fra:273:0:1:65535:1:0
diff -ruN vdr-1.5.2/ci.c vdr-1.5.3/ci.c
--- vdr-1.5.2/ci.c	2007-01-05 11:38:03.000000000 +0100
+++ vdr-1.5.3/ci.c	2007-04-30 15:02:49.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: ci.c 1.47 2007/01/05 10:38:03 kls Exp $
+ * $Id: ci.c 1.48 2007/04/30 13:02:49 kls Exp $
  */
 
 #include "ci.h"
@@ -643,7 +643,7 @@
 
 // --- cCiConditionalAccessSupport -------------------------------------------
 
-#define MAXCASYSTEMIDS 16
+#define MAXCASYSTEMIDS 64
 
 // CA Enable Ids:
 
diff -ruN vdr-1.5.2/config.c vdr-1.5.3/config.c
--- vdr-1.5.2/config.c	2007-02-25 14:58:45.000000000 +0100
+++ vdr-1.5.3/config.c	2007-06-02 13:21:40.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: config.c 1.150 2007/02/25 13:58:45 kls Exp $
+ * $Id: config.c 1.151 2007/06/02 11:21:40 kls Exp $
  */
 
 #include "config.h"
@@ -264,6 +264,13 @@
   OSDHeight = 486;
   OSDMessageTime = 1;
   UseSmallFont = 1;
+  AntiAlias = 1;
+  strcpy(FontOsd, "arialbd.ttf");
+  strcpy(FontSml, "arial.ttf");
+  strcpy(FontFix, "courbd.ttf");
+  FontOsdSize = 22;
+  FontSmlSize = 18;
+  FontFixSize = 20;
   MaxVideoFileSize = MAXVIDEOFILESIZE;
   SplitEditedFiles = 0;
   MinEventTimeout = 30;
@@ -427,6 +434,13 @@
   else if (!strcasecmp(Name, "OSDHeight"))         { OSDHeight          = atoi(Value); if (OSDHeight < 100) OSDHeight *= 27; }
   else if (!strcasecmp(Name, "OSDMessageTime"))      OSDMessageTime     = atoi(Value);
   else if (!strcasecmp(Name, "UseSmallFont"))        UseSmallFont       = atoi(Value);
+  else if (!strcasecmp(Name, "AntiAlias"))           AntiAlias          = atoi(Value);
+  else if (!strcasecmp(Name, "FontOsd"))             strn0cpy(FontOsd, Value, MAXFONTNAME);
+  else if (!strcasecmp(Name, "FontSml"))             strn0cpy(FontSml, Value, MAXFONTNAME);
+  else if (!strcasecmp(Name, "FontFix"))             strn0cpy(FontFix, Value, MAXFONTNAME);
+  else if (!strcasecmp(Name, "FontOsdSize"))         FontOsdSize        = atoi(Value);
+  else if (!strcasecmp(Name, "FontSmlSize"))         FontSmlSize        = atoi(Value);
+  else if (!strcasecmp(Name, "FontFixSize"))         FontFixSize        = atoi(Value);
   else if (!strcasecmp(Name, "MaxVideoFileSize"))    MaxVideoFileSize   = atoi(Value);
   else if (!strcasecmp(Name, "SplitEditedFiles"))    SplitEditedFiles   = atoi(Value);
   else if (!strcasecmp(Name, "MinEventTimeout"))     MinEventTimeout    = atoi(Value);
@@ -497,6 +511,13 @@
   Store("OSDHeight",          OSDHeight);
   Store("OSDMessageTime",     OSDMessageTime);
   Store("UseSmallFont",       UseSmallFont);
+  Store("AntiAlias",          AntiAlias);
+  Store("FontOsd",            FontOsd);
+  Store("FontSml",            FontSml);
+  Store("FontFix",            FontFix);
+  Store("FontOsdSize",        FontOsdSize);
+  Store("FontSmlSize",        FontSmlSize);
+  Store("FontFixSize",        FontFixSize);
   Store("MaxVideoFileSize",   MaxVideoFileSize);
   Store("SplitEditedFiles",   SplitEditedFiles);
   Store("MinEventTimeout",    MinEventTimeout);
diff -ruN vdr-1.5.2/config.h vdr-1.5.3/config.h
--- vdr-1.5.2/config.h	2007-03-03 16:39:05.000000000 +0100
+++ vdr-1.5.3/config.h	2007-06-02 13:22:17.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: config.h 1.288 2007/03/03 15:39:05 kls Exp $
+ * $Id: config.h 1.290 2007/06/02 11:22:17 kls Exp $
  */
 
 #ifndef __CONFIG_H
@@ -17,12 +17,13 @@
 #include <time.h>
 #include <unistd.h>
 #include "i18n.h"
+#include "font.h"
 #include "tools.h"
 
 // VDR's own version number:
 
-#define VDRVERSION  "1.5.2"
-#define VDRVERSNUM   10502  // Version * 10000 + Major * 100 + Minor
+#define VDRVERSION  "1.5.3"
+#define VDRVERSNUM   10503  // Version * 10000 + Major * 100 + Minor
 
 // The plugin API's version number:
 
@@ -242,6 +243,13 @@
   int OSDLeft, OSDTop, OSDWidth, OSDHeight;
   int OSDMessageTime;
   int UseSmallFont;
+  int AntiAlias;
+  char FontOsd[MAXFONTNAME];
+  char FontSml[MAXFONTNAME];
+  char FontFix[MAXFONTNAME];
+  int FontOsdSize;
+  int FontSmlSize;
+  int FontFixSize;
   int MaxVideoFileSize;
   int SplitEditedFiles;
   int MinEventTimeout, MinUserInactivity;
diff -ruN vdr-1.5.2/device.c vdr-1.5.3/device.c
--- vdr-1.5.2/device.c	2007-01-13 13:05:00.000000000 +0100
+++ vdr-1.5.3/device.c	2007-04-30 11:34:00.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: device.c 1.139 2007/01/13 12:05:00 kls Exp $
+ * $Id: device.c 1.140 2007/04/30 09:34:00 kls Exp $
  */
 
 #include "device.h"
@@ -327,7 +327,7 @@
              // difference, because it results in the most significant bit of the result.
              uint32_t imp = 0;
              imp <<= 1; imp |= LiveView ? !device[i]->IsPrimaryDevice() || ndr : 0;                                  // prefer the primary device for live viewing if we don't need to detach existing receivers
-             imp <<= 1; imp |= !device[i]->Receiving() || ndr;                                                       // use receiving devices if we don't need to detach existing receivers
+             imp <<= 1; imp |= !device[i]->Receiving() && (device[i] != cTransferControl::ReceiverDevice() || device[i]->IsPrimaryDevice()) || ndr; // use receiving devices if we don't need to detach existing receivers, but avoid primary device in local transfer mode
              imp <<= 1; imp |= device[i]->Receiving();                                                               // avoid devices that are receiving
              imp <<= 1; imp |= device[i] == cTransferControl::ReceiverDevice();                                      // avoid the Transfer Mode receiver device
              imp <<= 8; imp |= min(max(device[i]->Priority() + MAXPRIORITY, 0), 0xFF);                               // use the device with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
diff -ruN vdr-1.5.2/dvbplayer.c vdr-1.5.3/dvbplayer.c
--- vdr-1.5.2/dvbplayer.c	2006-04-17 14:45:48.000000000 +0200
+++ vdr-1.5.3/dvbplayer.c	2007-04-28 16:55:22.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: dvbplayer.c 1.45 2006/04/17 12:45:48 kls Exp $
+ * $Id: dvbplayer.c 1.46 2007/04/28 14:55:22 kls Exp $
  */
 
 #include "dvbplayer.h"
@@ -402,8 +402,10 @@
                        bool TimeShiftMode = index->IsStillRecording();
                        int Index = index->GetNextIFrame(readIndex, playDir == pdForward, &FileNumber, &FileOffset, &Length, TimeShiftMode);
                        if (Index >= 0) {
-                          if (!NextFile(FileNumber, FileOffset))
+                          if (!NextFile(FileNumber, FileOffset)) {
+                             readIndex = Index;
                              continue;
+                             }
                           }
                        else {
                           if (!TimeShiftMode && playDir == pdForward) {
diff -ruN vdr-1.5.2/eit.c vdr-1.5.3/eit.c
--- vdr-1.5.2/eit.c	2006-10-09 18:14:36.000000000 +0200
+++ vdr-1.5.3/eit.c	2007-06-10 14:51:05.000000000 +0200
@@ -8,7 +8,7 @@
  * Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
  * Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>.
  *
- * $Id: eit.c 1.122 2006/10/09 16:14:36 kls Exp $
+ * $Id: eit.c 1.123 2007/06/10 12:51:05 kls Exp $
  */
 
 #include "eit.h"
@@ -188,6 +188,7 @@
                     if (hit) {
                        char linkName[ld->privateData.getLength() + 1];
                        strn0cpy(linkName, (const char *)ld->privateData.getData(), sizeof(linkName));
+                       // TODO is there a standard way to determine the character set of this string?
                        cChannel *link = Channels.GetByChannelID(linkID);
                        if (link != channel) { // only link to other channels, not the same one
                           //fprintf(stderr, "Linkage %s %4d %4d %5d %5d %5d %5d  %02X  '%s'\n", hit ? "*" : "", channel->Number(), link ? link->Number() : -1, SiEitEvent.getEventId(), ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId(), ld->getLinkageType(), linkName);//XXX
@@ -218,7 +219,7 @@
                  if (1 <= Stream && Stream <= 2 && Type != 0) {
                     if (!Components)
                        Components = new cComponents;
-                    char buffer[256];
+                    char buffer[Utf8BufSize(256)];
                     Components->SetComponent(Components->NumComponents(), cd->getStreamContent(), cd->getComponentType(), I18nNormalizeLanguageCode(cd->languageCode), cd->description.getText(buffer, sizeof(buffer)));
                     }
                  }
@@ -230,7 +231,7 @@
 
       if (!rEvent) {
          if (ShortEventDescriptor) {
-            char buffer[256];
+            char buffer[Utf8BufSize(256)];
             pEvent->SetTitle(ShortEventDescriptor->name.getText(buffer, sizeof(buffer)));
             pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer, sizeof(buffer)));
             }
@@ -239,7 +240,7 @@
             pEvent->SetShortText(NULL);
             }
          if (ExtendedEventDescriptors) {
-            char buffer[ExtendedEventDescriptors->getMaximumTextLength(": ") + 1];
+            char buffer[Utf8BufSize(ExtendedEventDescriptors->getMaximumTextLength(": ")) + 1];
             pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": "));
             }
          else if (!HasExternalData)
diff -ruN vdr-1.5.2/epg.c vdr-1.5.3/epg.c
--- vdr-1.5.2/epg.c	2006-10-28 11:12:42.000000000 +0200
+++ vdr-1.5.3/epg.c	2007-06-10 14:52:19.000000000 +0200
@@ -7,7 +7,7 @@
  * Original version (as used in VDR before 1.3.0) written by
  * Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
  *
- * $Id: epg.c 1.81 2006/10/28 09:12:42 kls Exp $
+ * $Id: epg.c 1.82 2007/06/10 12:52:19 kls Exp $
  */
 
 #include "epg.h"
@@ -634,6 +634,7 @@
   // data, so let's always convert them to blanks (independent of the setting of EPGBugfixLevel):
   strreplace(title, '\n', ' ');
   strreplace(shortText, '\n', ' ');
+  /* TODO adapt to UTF-8
   // Same for control characters:
   strreplace(title, '\x86', ' ');
   strreplace(title, '\x87', ' ');
@@ -641,6 +642,7 @@
   strreplace(shortText, '\x87', ' ');
   strreplace(description, '\x86', ' ');
   strreplace(description, '\x87', ' ');
+  XXX*/
 }
 
 // --- cSchedule -------------------------------------------------------------
diff -ruN vdr-1.5.2/font.c vdr-1.5.3/font.c
--- vdr-1.5.2/font.c	2007-03-11 10:51:44.000000000 +0100
+++ vdr-1.5.3/font.c	2007-06-09 16:41:27.000000000 +0200
@@ -4,125 +4,296 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: font.c 1.14 2007/03/11 09:51:44 kls Exp $
+ * $Id: font.c 1.15 2007/06/09 14:41:27 kls Exp $
  */
 
-#include "config.h"
-#include <ctype.h>
 #include "font.h"
+#include <ctype.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include "config.h"
+#include "osd.h"
 #include "tools.h"
 
-#include "fontfix-iso8859-1.c"
-#include "fontosd-iso8859-1.c"
-#include "fontsml-iso8859-1.c"
-
-#include "fontfix-iso8859-2.c"
-#include "fontosd-iso8859-2.c"
-#include "fontsml-iso8859-2.c"
-
-#include "fontfix-iso8859-5.c"
-#include "fontosd-iso8859-5.c"
-#include "fontsml-iso8859-5.c"
-
-#include "fontfix-iso8859-7.c"
-#include "fontosd-iso8859-7.c"
-#include "fontsml-iso8859-7.c"
-
-#include "fontfix-iso8859-9.c"
-#include "fontosd-iso8859-9.c"
-#include "fontsml-iso8859-9.c"
-
-#include "fontfix-iso8859-13.c"
-#include "fontosd-iso8859-13.c"
-#include "fontsml-iso8859-13.c"
-
-#include "fontfix-iso8859-15.c"
-#include "fontosd-iso8859-15.c"
-#include "fontsml-iso8859-15.c"
+// --- cFreetypeFont ---------------------------------------------------------
 
-// --- cFont -----------------------------------------------------------------
+#define KERNING_UNKNOWN  (-10000)
 
-static const void *const FontData[eDvbCodeSize][eDvbFontSize] = {
-  { FontOsd_iso8859_1,  FontFix_iso8859_1,  FontSml_iso8859_1 },
-  { FontOsd_iso8859_2,  FontFix_iso8859_2,  FontSml_iso8859_2 },
-  { FontOsd_iso8859_5,  FontFix_iso8859_5,  FontSml_iso8859_5 },
-  { FontOsd_iso8859_7,  FontFix_iso8859_7,  FontSml_iso8859_7 },
-  { FontOsd_iso8859_9,  FontFix_iso8859_9,  FontSml_iso8859_9 },
-  { FontOsd_iso8859_13, FontFix_iso8859_13, FontSml_iso8859_13 },
-  { FontOsd_iso8859_15, FontFix_iso8859_15, FontSml_iso8859_15 },
+struct tKerning {
+  uint prevSym;
+  int kerning;
+  tKerning(uint PrevSym, int Kerning) { prevSym = PrevSym; kerning = Kerning; }
   };
 
-static const char *FontCode[eDvbCodeSize] = {
-  "iso8859-1",
-  "iso8859-2",
-  "iso8859-5",
-  "iso8859-7",
-  "iso8859-9",
-  "iso8859-13",
-  "iso8859-15",
+class cGlyph : public cListObject {
+private:
+  uint charCode;
+  uchar *bitmap;
+  int advanceX;
+  int advanceY;
+  int left;  ///< The bitmap's left bearing expressed in integer pixels.
+  int top;   ///< The bitmap's top bearing expressed in integer pixels.
+  int width; ///< The number of pixels per bitmap row.
+  int rows;  ///< The number of bitmap rows.
+  int pitch; ///< The pitch's absolute value is the number of bytes taken by one bitmap row, including padding.
+  cVector<tKerning> kerningCache;
+public:
+  cGlyph(uint CharCode, FT_GlyphSlotRec_ *GlyphData);
+  virtual ~cGlyph();
+  uint CharCode(void) const { return charCode; }
+  uchar *Bitmap(void) const { return bitmap; }
+  int AdvanceX(void) const { return advanceX; }
+  int AdvanceY(void) const { return advanceY; }
+  int Left(void) const { return left; }
+  int Top(void) const { return top; }
+  int Width(void) const { return width; }
+  int Rows(void) const { return rows; }
+  int Pitch(void) const { return pitch; }
+  int GetKerningCache(uint PrevSym) const;
+  void SetKerningCache(uint PrevSym, int Kerning);
   };
 
-eDvbCode cFont::code = code_iso8859_1;
-cFont *cFont::fonts[eDvbFontSize] = { NULL };
+cGlyph::cGlyph(uint CharCode, FT_GlyphSlotRec_ *GlyphData)
+{
+  charCode = CharCode;
+  advanceX = GlyphData->advance.x >> 6;
+  advanceY = GlyphData->advance.y >> 6;
+  left = GlyphData->bitmap_left;
+  top = GlyphData->bitmap_top;
+  width = GlyphData->bitmap.width;
+  rows = GlyphData->bitmap.rows;
+  pitch = GlyphData->bitmap.pitch;
+  bitmap = MALLOC(uchar, rows * pitch);
+  memcpy(bitmap, GlyphData->bitmap.buffer, rows * pitch);
+}
 
-cFont::cFont(const void *Data)
+cGlyph::~cGlyph()
 {
-  SetData(Data);
+  free(bitmap);
 }
 
-void cFont::SetData(const void *Data)
+int cGlyph::GetKerningCache(uint PrevSym) const
 {
-  if (Data) {
-     height = ((tCharData *)Data)->height;
-     for (int i = 0; i < NUMCHARS; i++)
-         data[i] = (tCharData *)&((tPixelData *)Data)[(i < 32 ? 0 : i - 32) * (height + 2)];
+  for (int i = kerningCache.Size(); --i > 0; ) {
+      if (kerningCache[i].prevSym == PrevSym)
+         return kerningCache[i].kerning;
+      }
+  return KERNING_UNKNOWN;
+}
+
+void cGlyph::SetKerningCache(uint PrevSym, int Kerning)
+{
+  kerningCache.Append(tKerning(PrevSym, Kerning));
+}
+
+class cFreetypeFont : public cFont {
+private:
+  int height;
+  int bottom;
+  FT_Library library; ///< Handle to library
+  FT_Face face; ///< Handle to face object
+  mutable cList<cGlyph> glyphCacheMonochrome;
+  mutable cList<cGlyph> glyphCacheAntiAliased;
+  int Bottom(void) const { return bottom; }
+  int Kerning(cGlyph *Glyph, uint PrevSym) const;
+  cGlyph* Glyph(uint CharCode, bool AntiAliased = false) const;
+public:
+  cFreetypeFont(const char *Name, int CharHeight);
+  virtual ~cFreetypeFont();
+  virtual int Width(uint c) const;
+  virtual int Width(const char *s) const;
+  virtual int Height(void) const { return height; }
+  virtual void DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const;
+  };
+
+cFreetypeFont::cFreetypeFont(const char *Name, int CharHeight)
+{
+  height = 0;
+  bottom = 0;
+  int error = FT_Init_FreeType(&library);
+  if (!error) {
+     error = FT_New_Face(library, Name, 0, &face);
+     if (!error) {
+        if (face->num_fixed_sizes && face->available_sizes) { // fixed font
+           // TODO what exactly does all this mean?
+           height = face->available_sizes->height;
+           for (uint sym ='A'; sym < 'z'; sym++) { // search for descender for fixed font FIXME
+               FT_UInt glyph_index = FT_Get_Char_Index(face, sym);
+               error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
+               if (!error) {
+                  error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
+                  if (!error) {
+                     if (face->glyph->bitmap.rows-face->glyph->bitmap_top > bottom)
+                        bottom = face->glyph->bitmap.rows-face->glyph->bitmap_top;
+                     }
+                  else
+                     esyslog("ERROR: FreeType: error %d in FT_Render_Glyph", error);
+                  }
+               else
+                  esyslog("ERROR: FreeType: error %d in FT_Load_Glyph", error);
+               }
+           }
+        else {
+           error = FT_Set_Char_Size(face, // handle to face object
+                                    0,    // char_width in 1/64th of points
+                                    CharHeight * 64, // CharHeight in 1/64th of points
+                                    0,    // horizontal device resolution
+                                    0);   // vertical device resolution
+           if (!error) {
+              height = ((face->size->metrics.ascender-face->size->metrics.descender) + 63) / 64;
+              bottom = abs((face->size->metrics.descender - 63) / 64);
+              }
+           else
+              esyslog("ERROR: FreeType: error %d during FT_Set_Char_Size (font = %s)\n", error, Name);
+           }
+        }
+     else
+        esyslog("ERROR: FreeType: load error %d (font = %s)", error, Name);
      }
   else
-     height = 0;
+     esyslog("ERROR: FreeType: initialization error %d (font = %s)", error, Name);
 }
 
-int cFont::Width(const char *s) const
+cFreetypeFont::~cFreetypeFont()
 {
-  int w = 0;
-  while (s && *s)
-        w += Width(*s++);
-  return w;
+  FT_Done_Face(face);
+  FT_Done_FreeType(library);
 }
 
-int cFont::Height(const char *s) const
+int cFreetypeFont::Kerning(cGlyph *Glyph, uint PrevSym) const
 {
-  int h = 0;
-  if (s && *s)
-     h = height; // all characters have the same height!
-  return h;
+  int kerning = 0;
+  if (Glyph && PrevSym) {
+     kerning = Glyph->GetKerningCache(PrevSym);
+     if (kerning == KERNING_UNKNOWN) {
+        FT_Vector delta;
+        FT_UInt glyph_index = FT_Get_Char_Index(face, Glyph->CharCode());
+        FT_UInt glyph_index_prev = FT_Get_Char_Index(face, PrevSym);
+        FT_Get_Kerning(face, glyph_index_prev, glyph_index, FT_KERNING_DEFAULT, &delta);
+        kerning = delta.x / 64;
+        Glyph->SetKerningCache(PrevSym, kerning);
+        }
+     }
+  return kerning;
 }
 
-bool cFont::SetCode(const char *Code)
+cGlyph* cFreetypeFont::Glyph(uint CharCode, bool AntiAliased) const
 {
-  for (int i = 0; i < eDvbCodeSize; i++) {
-      if (strcmp(Code, FontCode[i]) == 0) {
-         SetCode(eDvbCode(i));
-         return true;
-         }
+  // Lookup in cache:
+  cList<cGlyph> *glyphCache = AntiAliased ? &glyphCacheAntiAliased : &glyphCacheMonochrome;
+  for (cGlyph *g = glyphCache->First(); g; g = glyphCache->Next(g)) {
+      if (g->CharCode() == CharCode)
+         return g;
       }
-  return false;
+
+  FT_UInt glyph_index = FT_Get_Char_Index(face, CharCode);
+
+  // Load glyph image into the slot (erase previous one):
+  int error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
+  if (error)
+     esyslog("ERROR: FreeType: error during FT_Load_Glyph");
+  else {
+#if ((FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 1 && FREETYPE_PATCH >= 7) || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 2 && FREETYPE_PATCH <= 1))// TODO workaround for bug? which one?
+     if (AntiAliased || CharCode == 32)
+#else
+     if (AntiAliased)
+#endif
+        error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
+     else
+        error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);
+     if (error)
+        esyslog("ERROR: FreeType: error during FT_Render_Glyph %d, %d\n", CharCode, glyph_index);
+     else { //new bitmap
+        cGlyph *Glyph = new cGlyph(CharCode, face->glyph);
+        glyphCache->Add(Glyph);
+        return Glyph;
+        }
+     }
+  return NULL;
 }
 
-void cFont::SetCode(eDvbCode Code)
+int cFreetypeFont::Width(uint c) const
 {
-  if (code != Code) {
-     code = Code;
-     for (int i = 0; i < eDvbFontSize; i++) {
-         if (fonts[i])
-            fonts[i]->SetData(FontData[code][i]);
-         }
+  cGlyph *g = Glyph(c, Setup.AntiAlias);
+  return g ? g->AdvanceX() : 0;
+}
+
+int cFreetypeFont::Width(const char *s) const
+{
+  int w = 0;
+  if (s) {
+     uint prevSym = 0;
+     while (*s) {
+           int sl = Utf8CharLen(s);
+           uint sym = Utf8CharGet(s, sl);
+           s += sl;
+           cGlyph *g = Glyph(sym, Setup.AntiAlias);
+           if (g)
+              w += g->AdvanceX() + Kerning(g, prevSym);
+           prevSym = sym;
+           }
+     }
+  return w;
+}
+
+void cFreetypeFont::DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const
+{
+  if (s && height) { // checking height to make sure we actually have a valid font
+     bool AntiAliased = Setup.AntiAlias && Bitmap->Bpp() >= 8;
+     tIndex fg = Bitmap->Index(ColorFg);
+     uint prevSym = 0;
+     while (*s) {
+           int sl = Utf8CharLen(s);
+           uint sym = Utf8CharGet(s, sl);
+           s += sl;
+           cGlyph *g = Glyph(sym, AntiAliased);
+           int kerning = Kerning(g, prevSym);
+           prevSym = sym;
+           uchar *buffer = g->Bitmap();
+           int symWidth = g->Width();
+           if (Width && x + symWidth + g->Left() + kerning - 1 > Width)
+              break; // we don't draw partial characters
+           if (x + symWidth + g->Left() + kerning > 0) {
+              for (int row = 0; row < g->Rows(); row++) {
+                  for (int pitch = 0; pitch < g->Pitch(); pitch++) {
+                      uchar bt = *(buffer + (row * g->Pitch() + pitch));
+                      if (AntiAliased) {
+                         if (bt > 0x00) {
+                            int px = x + pitch + g->Left() + kerning;
+                            int py = y + row + (height - Bottom() - g->Top());
+                            if (bt == 0xFF)
+                               Bitmap->SetIndex(px, py, fg);
+                            else {
+                               tColor bg = (ColorBg != clrTransparent) ? ColorBg : Bitmap->GetColor(px, py);
+                               Bitmap->SetIndex(px, py, Bitmap->Index(Bitmap->Blend(ColorFg, bg, bt)));
+                               }
+                            }
+                         }
+                      else { //monochrome rendering
+                         for (int col = 0; col < 8 && col + pitch * 8 <= symWidth; col++) {
+                             if (bt & 0x80)
+                                Bitmap->SetIndex(x + col + pitch * 8 + g->Left() + kerning, y + row + (height - Bottom() - g->Top()), fg);
+                             bt <<= 1;
+                             }
+                         }
+                      }
+                  }
+              }
+           x += g->AdvanceX() + kerning;
+           if (x > Bitmap->Width() - 1)
+              break;
+           }
      }
 }
 
-void cFont::SetFont(eDvbFont Font, const void *Data)
+// --- cFont -----------------------------------------------------------------
+
+cFont *cFont::fonts[eDvbFontSize] = { NULL };
+
+void cFont::SetFont(eDvbFont Font, const char *Name, int CharHeight)
 {
   delete fonts[Font];
-  fonts[Font] = new cFont(Data ? Data : FontData[code][Font]);
+  fonts[Font] = new cFreetypeFont(*Name == '/' ? Name : *AddDirectory(FONTDIR, Name), CharHeight);
 }
 
 const cFont *cFont::GetFont(eDvbFont Font)
@@ -131,8 +302,13 @@
      Font = fontOsd;
   else if (Setup.UseSmallFont == 2)
      Font = fontSml;
-  if (!fonts[Font])
-     SetFont(Font);
+  if (!fonts[Font]) {
+     switch (Font) {
+       case fontOsd: SetFont(Font, AddDirectory(FONTDIR, Setup.FontOsd), Setup.FontOsdSize); break;
+       case fontSml: SetFont(Font, AddDirectory(FONTDIR, Setup.FontSml), Setup.FontSmlSize); break;
+       case fontFix: SetFont(Font, AddDirectory(FONTDIR, Setup.FontFix), Setup.FontFixSize); break;
+       }
+     }
   return fonts[Font];
 }
 
@@ -176,16 +352,18 @@
   stripspace(text); // strips trailing newlines
 
   for (char *p = text; *p; ) {
-      if (*p == '\n') {
+      int sl = Utf8CharLen(p);
+      uint sym = Utf8CharGet(p, sl);
+      if (sym == '\n') {
          lines++;
          w = 0;
          Blank = Delim = NULL;
          p++;
          continue;
          }
-      else if (isspace(*p))
+      else if (sl == 1 && isspace(sym))
          Blank = p;
-      int cw = Font->Width(*p);
+      int cw = Font->Width(sym);
       if (w + cw > Width) {
          if (Blank) {
             *Blank = '\n';
@@ -214,7 +392,7 @@
          Delim = p;
          Blank = NULL;
          }
-      p++;
+      p += sl;
       }
 }
 
diff -ruN vdr-1.5.2/font.h vdr-1.5.3/font.h
--- vdr-1.5.2/font.h	2007-03-11 10:50:42.000000000 +0100
+++ vdr-1.5.3/font.h	2007-06-10 14:58:54.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: font.h 1.15 2007/03/11 09:50:42 kls Exp $
+ * $Id: font.h 1.16 2007/06/10 12:58:54 kls Exp $
  */
 
 #ifndef __FONT_H
@@ -13,6 +13,10 @@
 #include <stdint.h>
 #include <stdlib.h>
 
+#define MAXFONTNAME 64
+#define MAXFONTSIZE 64
+#define FONTDIR     "/usr/share/fonts/truetype"
+
 enum eDvbFont {
   fontOsd,
   fontFix,
@@ -20,49 +24,35 @@
 #define eDvbFontSize (fontSml + 1)
   };
 
-enum eDvbCode {
-  code_iso8859_1,
-  code_iso8859_2,
-  code_iso8859_5,
-  code_iso8859_7,
-  code_iso8859_9,
-  code_iso8859_13,
-  code_iso8859_15,
-#define eDvbCodeSize (code_iso8859_15 + 1)
-  };
+class cBitmap;
+typedef uint32_t tColor; // see also osd.h
+typedef uint8_t tIndex;
 
 class cFont {
-public:
-  enum { NUMCHARS = 256 };
-  typedef uint32_t tPixelData;
-  struct tCharData {
-    tPixelData width, height;
-    tPixelData lines[1];
-    };
 private:
-  static eDvbCode code;
   static cFont *fonts[];
-  const tCharData *data[NUMCHARS];
-  int height;
 public:
-  cFont(const void *Data);
   virtual ~cFont() {}
-  void SetData(const void *Data);
-  virtual int Width(unsigned char c) const { return data[c]->width; }
-      ///< Returns the width of the given character.
-  virtual int Width(const char *s) const;
-      ///< Returns the width of the given string.
-  virtual int Height(unsigned char c) const { return data[c]->height; }
-      ///< Returns the height of the given character.
-  virtual int Height(const char *s) const;
-      ///< Returns the height of the given string.
-  virtual int Height(void) const { return height; }
-      ///< Returns the height of this font (all characters have the same height).
-  const tCharData *CharData(unsigned char c) const { return data[c]; }
-  static bool SetCode(const char *Code);
-  static void SetCode(eDvbCode Code);
-  static void SetFont(eDvbFont Font, const void *Data = NULL);
+  virtual int Width(uint c) const = 0;
+          ///< Returns the width of the given character in pixel.
+  virtual int Width(const char *s) const = 0;
+          ///< Returns the width of the given string in pixel.
+  virtual int Height(void) const = 0;
+          ///< Returns the height of this font in pixel (all characters have the same height).
+  int Height(const char *s) const { return Height(); }
+          ///< Returns the height of this font in pixel (obsolete, just for backwards compatibilty).
+  virtual void DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const = 0;
+          ///< Draws the given text into the Bitmap at position (x, y) with the given colors.
+          ///< The text will not exceed the given Width (if > 0), and will end with a complete character.
+  static void SetFont(eDvbFont Font, const char *Name, int CharHeight);
+          ///< Sets the given Font to use the font data from the file Name and make its characters
+          ///< CharHeight pixels high.
   static const cFont *GetFont(eDvbFont Font);
+          ///< Gets the given Font, which was previously set by a call to SetFont().
+          ///< If no SetFont() call has been made, the font as defined in the setup is returned.
+          ///< The caller must not use the returned font outside the scope in which
+          ///< it was retrieved by the call to GetFont(), because a call to SetFont()
+          ///< may delete an existing font.
   };
 
 class cTextWrapper {
diff -ruN vdr-1.5.2/i18n.c vdr-1.5.3/i18n.c
--- vdr-1.5.2/i18n.c	2007-03-11 11:05:36.000000000 +0100
+++ vdr-1.5.3/i18n.c	2007-06-09 10:44:54.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: i18n.c 1.293 2007/03/11 10:05:36 kls Exp $
+ * $Id: i18n.c 1.294 2007/06/09 08:44:54 kls Exp $
  *
  * Translations provided by:
  *
@@ -3138,6 +3138,7 @@
     "CAM",
     "CAM",
     "CAM",
+    "CAM",
   },
   { "Recording",
     "Aufnahme",
@@ -3554,6 +3555,167 @@
     "v�dy",
     "hep",
   },
+  { "Setup.OSD$Anti-alias",
+    "Kantengl�ttung",
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+  },
+  { "Setup.OSD$OSD font name",
+    "OSD Schriftart",
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+  },
+  { "Setup.OSD$Small font name",
+    "Kleine Schriftart",
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+  },
+  { "Setup.OSD$Fixed font name",
+    "Festbreiten-Schriftart",
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+  },
+  { "Setup.OSD$OSD font size (pixel)",
+    "OSD Schriftgr��e (pixel)",
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+  },
+  { "Setup.OSD$Small font size (pixel)",
+    "Kleine Schriftgr��e (pixel)",
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+  },
+  { "Setup.OSD$Fixed font size (pixel)",
+    "Festbreiten-Schriftgr��e (pixel)",
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+    "",// TODO
+  },
   { "Setup.OSD$Channel info position",
     "Kanalinfo-Position",
     "Pozicija informacije o kanalu",
@@ -5021,7 +5183,7 @@
     " 0\t-.#~,/_@1\ta��bc2\tdef3\tghi�4\tjkl5\tmno6\tpqrs�7\tt�uv8\twxyz9",
     " 0\t-.#~,/_@1\ta�bc2\tde�f3\tghi�4\tjkl5\tmno���6\tpqrs7\ttu���v8\twxyz9",
     "",//TODO
-    "",//TODO
+    " 0\t-.#~,/_@1\tabc����2\tdef�����3\tghi����4\tjkl���5\tmno���6\tpqrs����7\ttuv�����8\twxyz�����9",
     "",//TODO
     " 0\t-.#~,/_@1\tabc��2\tdef3\tghi4\tjkl5\tmno��6\tpqrs�7\ttuv�8\twxyz�9",
     " 0\t-.#~,/_@1\tabc��2\tdef3\tghi4\tjkl5\tmno�6\tpqrs7\ttuv8\twxyz9",
@@ -6603,25 +6765,33 @@
 class cI18nEntry : public cListObject {
 private:
   const tI18nPhrase *phrases;
+  tI18nPhrase *converted;
   const char *plugin;
 public:
   cI18nEntry(const tI18nPhrase * const Phrases, const char *Plugin);
+  virtual ~cI18nEntry();
   const tI18nPhrase *Phrases(void) { return phrases; }
+  tI18nPhrase **Converted(void) { return &converted; }
   const char *Plugin(void) { return plugin; }
   };
 
 cI18nEntry::cI18nEntry(const tI18nPhrase * const Phrases, const char *Plugin)
 {
   phrases = Phrases;
+  converted = NULL;
   plugin = Plugin;
 }
 
+cI18nEntry::~cI18nEntry()
+{
+  delete converted;
+}
+
 // --- cI18nList -------------------------------------------------------------
 
 class cI18nList : public cList<cI18nEntry> {
 public:
   cI18nEntry *Get(const char *Plugin);
-  const tI18nPhrase *GetPhrases(const char *Plugin);
   };
 
 cI18nEntry *cI18nList::Get(const char *Plugin)
@@ -6635,16 +6805,28 @@
   return NULL;
 }
 
-const tI18nPhrase *cI18nList::GetPhrases(const char *Plugin)
-{
-  cI18nEntry *p = Get(Plugin);
-  return p ? p->Phrases() : NULL;
-}
-
 cI18nList I18nList;
 
 // ---
 
+static tI18nPhrase *Converted = NULL;
+
+static const char *ConvertPhrase(const tI18nPhrase *Original, tI18nPhrase **Converted, int NrPhrase, int NrLanguage)
+{
+  if (!*Converted) {
+     int NumPhrases = 0;
+     for (const tI18nPhrase *p = Original; **p; p++)
+         NumPhrases++;
+     *Converted = new tI18nPhrase[NumPhrases + 1];
+     memset(*Converted, 0, sizeof(tI18nPhrase) * (NumPhrases + 1));
+     }
+  if (!(*Converted)[NrPhrase][NrLanguage]) {
+     cCharSetConv csc(Phrases[1][NrLanguage], cCharSetConv::SystemCharacterTable());
+     (*Converted)[NrPhrase][NrLanguage] = strdup(csc.Convert(Original[NrPhrase][NrLanguage]));
+     }
+  return (*Converted)[NrPhrase][NrLanguage];
+}
+
 void I18nRegister(const tI18nPhrase * const Phrases, const char *Plugin)
 {
   cI18nEntry *p = I18nList.Get(Plugin);
@@ -6657,13 +6839,14 @@
 const char *I18nTranslate(const char *s, const char *Plugin)
 {
   if (Setup.OSDLanguage) {
-     const tI18nPhrase *p = Plugin ? I18nList.GetPhrases(Plugin) : Phrases;
-     if (!p)
-        p = Phrases;
+     cI18nEntry *e = Plugin ? I18nList.Get(Plugin) : NULL;
+     const tI18nPhrase *OriginalPhrases = e ? e->Phrases() : Phrases;
+     tI18nPhrase **ConvertedPhrases = e ? e->Converted() : &Converted;
+     const tI18nPhrase *p = OriginalPhrases;
      for (int i = ((p == Phrases) ? 1 : 2); i--; ) {
          for (; **p; p++) {
              if (strcmp(s, **p) == 0) {
-                const char *t = (*p)[Setup.OSDLanguage];
+                const char *t = ConvertPhrase(OriginalPhrases, ConvertedPhrases, p - OriginalPhrases, Setup.OSDLanguage);
                 if (t && *t)
                    return t;
                 }
@@ -6678,7 +6861,11 @@
 
 const char * const * I18nLanguages(void)
 {
-  return &Phrases[0][0];
+  if (!Converted || !(Converted)[0][0]) {
+     for (int i = 0; i < I18nNumLanguages; i++)
+         ConvertPhrase(Phrases, &Converted, 0, i);
+     }
+  return &Converted[0][0];
 }
 
 const char * const * I18nCharSets(void)
diff -ruN vdr-1.5.2/i18n.h vdr-1.5.3/i18n.h
--- vdr-1.5.2/i18n.h	2007-03-11 10:52:16.000000000 +0100
+++ vdr-1.5.3/i18n.h	2007-05-28 13:43:14.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: i18n.h 1.19 2007/03/11 09:52:16 kls Exp $
+ * $Id: i18n.h 1.20 2007/05/28 11:43:14 kls Exp $
  */
 
 #ifndef __I18N_H
@@ -21,7 +21,6 @@
 const char *I18nTranslate(const char *s, const char *Plugin = NULL) __attribute_format_arg__(1);
 
 const char * const * I18nLanguages(void);
-const char * const * I18nCharSets(void);
 const char *I18nLanguageCode(int Index);
 int I18nLanguageIndex(const char *Code);
 const char *I18nNormalizeLanguageCode(const char *Code);
diff -ruN vdr-1.5.2/libsi/si.c vdr-1.5.3/libsi/si.c
--- vdr-1.5.2/libsi/si.c	2007-04-22 15:56:39.000000000 +0200
+++ vdr-1.5.3/libsi/si.c	2007-06-10 11:31:34.000000000 +0200
@@ -6,7 +6,7 @@
  *   the Free Software Foundation; either version 2 of the License, or     *
  *   (at your option) any later version.                                   *
  *                                                                         *
- *   $Id: si.c 1.18 2007/04/22 13:56:39 kls Exp $
+ *   $Id: si.c 1.20 2007/06/10 09:31:34 kls Exp $
  *                                                                         *
  ***************************************************************************/
 
@@ -219,7 +219,9 @@
    int len=getLength();
    if (len < 0 || len > 4095)
       return strdup("text error"); // caller will delete it!
-   char *data=new char(len+1);
+   char *data=new char(len+1); // FIXME If this function is ever actually used, this buffer might
+                               // need to be bigger in order to hold the string as UTF-8.
+                               // Maybe decodeText should dynamically handle this? kls 2007-06-10
    decodeText(data, len+1);
    return data;
 }
@@ -370,7 +372,7 @@
 {
   if (SystemCharacterTable) {
      iconv_t cd = iconv_open(SystemCharacterTable, fromCode);
-     if (cd >= 0) {
+     if (cd != (iconv_t)-1) {
         char *fromPtr = (char *)from;
         while (fromLength > 0 && toLength > 1) {
            if (iconv(cd, &fromPtr, &fromLength, &to, &toLength) == size_t(-1)) {
@@ -404,6 +406,9 @@
       }
    bool singleByte;
    const char *cs = getCharacterTable(from, len, &singleByte);
+   // FIXME Need to make this UTF-8 aware (different control codes).
+   // However, there's yet to be found a broadcaster that actually
+   // uses UTF-8 for the SI data... (kls 2007-06-10)
    for (int i = 0; i < len; i++) {
       if (*from == 0)
          break;
@@ -440,6 +445,9 @@
       }
    bool singleByte;
    const char *cs = getCharacterTable(from, len, &singleByte);
+   // FIXME Need to make this UTF-8 aware (different control codes).
+   // However, there's yet to be found a broadcaster that actually
+   // uses UTF-8 for the SI data... (kls 2007-06-10)
    for (int i = 0; i < len; i++) {
       if (    ((' ' <= *from) && (*from <= '~'))
            || (*from == '\n')
diff -ruN vdr-1.5.2/menu.c vdr-1.5.3/menu.c
--- vdr-1.5.2/menu.c	2007-02-25 15:04:33.000000000 +0100
+++ vdr-1.5.3/menu.c	2007-06-09 16:36:46.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: menu.c 1.450 2007/02/25 14:04:33 kls Exp $
+ * $Id: menu.c 1.451 2007/06/09 14:36:46 kls Exp $
  */
 
 #include "menu.h"
@@ -761,7 +761,7 @@
 {
   cString day, name("");
   if (timer->WeekDays())
-     day = timer->PrintDay(0, timer->WeekDays());
+     day = timer->PrintDay(0, timer->WeekDays(), false);
   else if (timer->Day() - time(NULL) < 28 * SECSINDAY) {
      day = itoa(timer->GetMDay(timer->Day()));
      name = WeekDayName(timer->Day());
@@ -1052,10 +1052,11 @@
      char t = TimerMatchChars[timerMatch];
      char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' ';
      char r = event->SeenWithin(30) && event->IsRunning() ? '*' : ' ';
+     const char *csn = channel ? channel->ShortName(true) : NULL;
      if (channel && withDate)
-        asprintf(&buffer, "%d\t%.*s\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), 6, channel->ShortName(true), 6, *event->GetDateString(), *event->GetTimeString(), t, v, r, event->Title());
+        asprintf(&buffer, "%d\t%.*s\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, 6, *event->GetDateString(), *event->GetTimeString(), t, v, r, event->Title());
      else if (channel)
-        asprintf(&buffer, "%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), 6, channel->ShortName(true), *event->GetTimeString(), t, v, r, event->Title());
+        asprintf(&buffer, "%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title());
      else
         asprintf(&buffer, "%.*s\t%s\t%c%c%c\t%s", 6, *event->GetDateString(), *event->GetTimeString(), t, v, r, event->Title());
      SetText(buffer, false);
@@ -2157,7 +2158,10 @@
   int skinIndex;
   const char **skinDescriptions;
   cThemes themes;
+  int originalThemeIndex;
   int themeIndex;
+  cFileNameList fontNames;
+  int fontOsdIndex, fontSmlIndex, fontFixIndex;
   virtual void Set(void);
 public:
   cMenuSetupOSD(void);
@@ -2171,13 +2175,18 @@
   skinIndex = originalSkinIndex = Skins.Current()->Index();
   skinDescriptions = new const char*[numSkins];
   themes.Load(Skins.Current()->Name());
-  themeIndex = Skins.Current()->Theme() ? themes.GetThemeIndex(Skins.Current()->Theme()->Description()) : 0;
+  themeIndex = originalThemeIndex = Skins.Current()->Theme() ? themes.GetThemeIndex(Skins.Current()->Theme()->Description()) : 0;
+  fontNames.Load(FONTDIR);
+  if (fontNames.Size()) {
+     fontOsdIndex = max(0, fontNames.Find(Setup.FontOsd));
+     fontSmlIndex = max(0, fontNames.Find(Setup.FontSml));
+     fontFixIndex = max(0, fontNames.Find(Setup.FontFix));
+     }
   Set();
 }
 
 cMenuSetupOSD::~cMenuSetupOSD()
 {
-  cFont::SetCode(I18nCharSets()[Setup.OSDLanguage]);
   delete[] skinDescriptions;
 }
 
@@ -2201,6 +2210,15 @@
   Add(new cMenuEditIntItem( tr("Setup.OSD$Height"),                 &data.OSDHeight, MINOSDHEIGHT, MAXOSDHEIGHT));
   Add(new cMenuEditIntItem( tr("Setup.OSD$Message time (s)"),       &data.OSDMessageTime, 1, 60));
   Add(new cMenuEditStraItem(tr("Setup.OSD$Use small font"),         &data.UseSmallFont, 3, useSmallFontTexts));
+  Add(new cMenuEditBoolItem(tr("Setup.OSD$Anti-alias"),             &data.AntiAlias));
+  if (fontNames.Size()) {
+  Add(new cMenuEditStraItem(tr("Setup.OSD$OSD font name"),          &fontOsdIndex, fontNames.Size(), &fontNames[0]));
+  Add(new cMenuEditStraItem(tr("Setup.OSD$Small font name"),        &fontSmlIndex, fontNames.Size(), &fontNames[0]));
+  Add(new cMenuEditStraItem(tr("Setup.OSD$Fixed font name"),        &fontFixIndex, fontNames.Size(), &fontNames[0]));
+  }
+  Add(new cMenuEditIntItem( tr("Setup.OSD$OSD font size (pixel)"),  &data.FontOsdSize, 10, MAXFONTSIZE));
+  Add(new cMenuEditIntItem( tr("Setup.OSD$Small font size (pixel)"),&data.FontSmlSize, 10, MAXFONTSIZE));
+  Add(new cMenuEditIntItem( tr("Setup.OSD$Fixed font size (pixel)"),&data.FontFixSize, 10, MAXFONTSIZE));
   Add(new cMenuEditBoolItem(tr("Setup.OSD$Channel info position"),  &data.ChannelInfoPos, tr("bottom"), tr("top")));
   Add(new cMenuEditIntItem( tr("Setup.OSD$Channel info time (s)"),  &data.ChannelInfoTime, 1, 60));
   Add(new cMenuEditBoolItem(tr("Setup.OSD$Info on channel switch"), &data.ShowInfoOnChSwitch));
@@ -2215,29 +2233,57 @@
 
 eOSState cMenuSetupOSD::ProcessKey(eKeys Key)
 {
+  bool ModifiedApperance = false;
+
   if (Key == kOk) {
      if (skinIndex != originalSkinIndex) {
         cSkin *Skin = Skins.Get(skinIndex);
         if (Skin) {
            strn0cpy(data.OSDSkin, Skin->Name(), sizeof(data.OSDSkin));
            Skins.SetCurrent(Skin->Name());
+           ModifiedApperance = true;
            }
         }
      if (themes.NumThemes() && Skins.Current()->Theme()) {
         Skins.Current()->Theme()->Load(themes.FileName(themeIndex));
         strn0cpy(data.OSDTheme, themes.Name(themeIndex), sizeof(data.OSDTheme));
+        ModifiedApperance |= themeIndex != originalThemeIndex;
+        }
+     if (data.OSDLeft != Setup.OSDLeft || data.OSDTop != Setup.OSDTop || data.OSDWidth != Setup.OSDWidth || data.OSDHeight != Setup.OSDHeight) {
+        data.OSDWidth &= ~0x07; // OSD width must be a multiple of 8
+        ModifiedApperance = true;
+        }
+     if (data.UseSmallFont != Setup.UseSmallFont || data.AntiAlias != Setup.AntiAlias)
+        ModifiedApperance = true;
+     if (fontNames.Size()) {
+        strn0cpy(data.FontOsd, fontNames[fontOsdIndex], sizeof(data.FontOsd));
+        strn0cpy(data.FontSml, fontNames[fontSmlIndex], sizeof(data.FontSml));
+        strn0cpy(data.FontFix, fontNames[fontFixIndex], sizeof(data.FontFix));
+        }
+     if (strcmp(data.FontOsd, Setup.FontOsd) || data.FontOsdSize != Setup.FontOsdSize) {
+        cFont::SetFont(fontOsd, data.FontOsd, data.FontOsdSize);
+        ModifiedApperance = true;
+        }
+     if (strcmp(data.FontSml, Setup.FontSml) || data.FontSmlSize != Setup.FontSmlSize) {
+        cFont::SetFont(fontSml, data.FontSml, data.FontSmlSize);
+        ModifiedApperance = true;
+        }
+     if (strcmp(data.FontFix, Setup.FontFix) || data.FontFixSize != Setup.FontFixSize) {
+        cFont::SetFont(fontFix, data.FontFix, data.FontFixSize);
+        ModifiedApperance = true;
         }
-     data.OSDWidth &= ~0x07; // OSD width must be a multiple of 8
      }
 
   int osdLanguage = data.OSDLanguage;
   int oldSkinIndex = skinIndex;
   eOSState state = cMenuSetupBase::ProcessKey(Key);
 
+  if (ModifiedApperance)
+     SetDisplayMenu();
+
   if (data.OSDLanguage != osdLanguage || skinIndex != oldSkinIndex) {
      int OriginalOSDLanguage = Setup.OSDLanguage;
      Setup.OSDLanguage = data.OSDLanguage;
-     cFont::SetCode(I18nCharSets()[Setup.OSDLanguage]);
 
      cSkin *Skin = Skins.Get(skinIndex);
      if (Skin) {
@@ -2910,10 +2956,8 @@
         int Minutes = int(double(FreeMB) / MB_PER_MINUTE);
         int Hours = Minutes / 60;
         Minutes %= 60;
-        char buffer[40];
-        snprintf(buffer, sizeof(buffer), "%s  -  %s %d%%  -  %2d:%02d %s", tr("VDR"), tr("Disk"), Percent, Hours, Minutes, tr("free"));
         //XXX -> skin function!!!
-        SetTitle(buffer);
+        SetTitle(cString::sprintf("%s  -  %s %d%%  -  %2d:%02d %s", tr("VDR"), tr("Disk"), Percent, Hours, Minutes, tr("free")));
         result = true;
         }
      lastDiskSpaceCheck = time(NULL);
diff -ruN vdr-1.5.2/menuitems.c vdr-1.5.3/menuitems.c
--- vdr-1.5.2/menuitems.c	2007-01-04 14:30:37.000000000 +0100
+++ vdr-1.5.3/menuitems.c	2007-06-08 17:16:38.000000000 +0200
@@ -4,11 +4,12 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: menuitems.c 1.48 2007/01/04 13:30:37 kls Exp $
+ * $Id: menuitems.c 1.49 2007/06/08 15:16:38 kls Exp $
  */
 
 #include "menuitems.h"
 #include <ctype.h>
+#include <wctype.h>
 #include "i18n.h"
 #include "plugin.h"
 #include "remote.h"
@@ -252,23 +253,64 @@
 cMenuEditStrItem::cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed)
 :cMenuEditItem(Name)
 {
-  orgValue = NULL;
   value = Value;
   length = Length;
-  allowed = strdup(Allowed ? Allowed : "");
+  allowed = Allowed;
   pos = -1;
+  offset = 0;
   insert = uppercase = false;
   newchar = true;
-  charMap = tr(" 0\t-.#~,/_@1\tabc2\tdef3\tghi4\tjkl5\tmno6\tpqrs7\ttuv8\twxyz9");
-  currentChar = NULL;
+  lengthUtf8 = 0;
+  valueUtf8 = NULL;
+  allowedUtf8 = NULL;
+  charMapUtf8 = NULL;
+  currentCharUtf8 = NULL;
   lastKey = kNone;
   Set();
 }
 
 cMenuEditStrItem::~cMenuEditStrItem()
 {
-  free(orgValue);
-  free(allowed);
+  delete valueUtf8;
+  delete allowedUtf8;
+  delete charMapUtf8;
+}
+
+void cMenuEditStrItem::EnterEditMode(void)
+{
+  if (!valueUtf8) {
+     valueUtf8 = new uint[length];
+     lengthUtf8 = Utf8ToArray(value, valueUtf8, length);
+     int l = strlen(allowed) + 1;
+     allowedUtf8 = new uint[l];
+     Utf8ToArray(allowed, allowedUtf8, l);
+     const char *charMap = tr(" 0\t-.#~,/_@1\tabc2\tdef3\tghi4\tjkl5\tmno6\tpqrs7\ttuv8\twxyz9");
+     l = strlen(charMap) + 1;
+     charMapUtf8 = new uint[l];
+     Utf8ToArray(charMap, charMapUtf8, l);
+     currentCharUtf8 = charMapUtf8;
+     AdvancePos();
+     }
+}
+
+void cMenuEditStrItem::LeaveEditMode(bool SaveValue)
+{
+  if (valueUtf8) {
+     if (SaveValue) {
+        Utf8FromArray(valueUtf8, value, length);
+        stripspace(value);
+        }
+     lengthUtf8 = 0;
+     delete valueUtf8;
+     valueUtf8 = NULL;
+     delete allowedUtf8;
+     allowedUtf8 = NULL;
+     delete charMapUtf8;
+     charMapUtf8 = NULL;
+     pos = -1;
+     offset = 0;
+     newchar = true;
+     }
 }
 
 void cMenuEditStrItem::SetHelpKeys(void)
@@ -279,84 +321,120 @@
      cSkinDisplay::Current()->SetButtons(NULL);
 }
 
+uint *cMenuEditStrItem::IsAllowed(uint c)
+{
+  if (allowedUtf8) {
+     for (uint *a = allowedUtf8; *a; a++) {
+         if (c == *a)
+            return a;
+         }
+     }
+  return NULL;
+}
+
 void cMenuEditStrItem::AdvancePos(void)
 {
-  if (pos < length - 2 && pos < int(strlen(value)) ) {
-     if (++pos >= int(strlen(value))) {
-        if (pos >= 2 && value[pos - 1] == ' ' && value[pos - 2] == ' ')
+  if (pos < length - 2 && pos < lengthUtf8) {
+     if (++pos >= lengthUtf8) {
+        if (pos >= 2 && valueUtf8[pos - 1] == ' ' && valueUtf8[pos - 2] == ' ')
            pos--; // allow only two blanks at the end
         else {
-           value[pos] = ' ';
-           value[pos + 1] = 0;
+           valueUtf8[pos] = ' ';
+           valueUtf8[pos + 1] = 0;
+           lengthUtf8++;
            }
         }
      }
   newchar = true;
-  if (!insert && isalpha(value[pos]))
-     uppercase = isupper(value[pos]);
+  if (!insert && Utf8is(alpha, valueUtf8[pos]))
+     uppercase = Utf8is(upper, valueUtf8[pos]);
 }
 
 void cMenuEditStrItem::Set(void)
 {
-  char buf[1000];
-
   if (InEditMode()) {
      // This is an ugly hack to make editing strings work with the 'skincurses' plugin.
      const cFont *font = dynamic_cast<cSkinDisplayMenu *>(cSkinDisplay::Current())->GetTextAreaFont(false);
      if (!font || font->Width("W") != 1) // all characters have with == 1 in the font used by 'skincurses'
         font = cFont::GetFont(fontOsd);
-     strncpy(buf, value, pos);
-     snprintf(buf + pos, sizeof(buf) - pos - 2, insert && newchar ? "[]%c%s" : "[%c]%s", *(value + pos), value + pos + 1);
+
      int width = cSkinDisplay::Current()->EditableWidth();
-     if (font->Width(buf) <= width) {
-        // the whole buffer fits on the screen
-        SetValue(buf);
-        return;
-        }
-     width -= font->Width('>'); // assuming '<' and '>' have the same width
-     int w = 0;
-     int i = 0;
-     int l = strlen(buf);
-     while (i < l && w <= width)
-           w += font->Width(buf[i++]);
-     if (i >= pos + 4) {
-        // the cursor fits on the screen
-        buf[i - 1] = '>';
-        buf[i] = 0;
-        SetValue(buf);
-        return;
-        }
-     // the cursor doesn't fit on the screen
-     w = 0;
-     if (buf[i = pos + 3]) {
-        buf[i] = '>';
-        buf[i + 1] = 0;
-        }
-     else
-        i--;
-     while (i >= 0 && w <= width)
-           w += font->Width(buf[i--]);
-     buf[++i] = '<';
-     SetValue(buf + i);
+     width -= font->Width("[]");
+     width -= font->Width("<>"); // reserving this anyway make the whole thing simpler
+
+     if (pos < offset)
+        offset = pos;
+     int WidthFromOffset = 0;
+     int EndPos = lengthUtf8;
+     for (int i = offset; i < lengthUtf8; i++) {
+         WidthFromOffset += font->Width(valueUtf8[i]);
+         if (WidthFromOffset > width) {
+            if (pos >= i) {
+               do {
+                  WidthFromOffset -= font->Width(valueUtf8[offset]);
+                  offset++;
+                  } while (WidthFromOffset > width && offset < pos);
+               EndPos = pos + 1;
+               }
+            else {
+               EndPos = i;
+               break;
+               }
+            }
+         }
+
+     char buf[1000];
+     char *p = buf;
+     if (offset)
+        *p++ = '<';
+     p += Utf8FromArray(valueUtf8 + offset, p, sizeof(buf) - (p - buf), pos - offset);
+     *p++ = '[';
+     if (insert && newchar)
+        *p++ = ']';
+     p += Utf8FromArray(&valueUtf8[pos], p, sizeof(buf) - (p - buf), 1);
+     if (!(insert && newchar))
+        *p++ = ']';
+     p += Utf8FromArray(&valueUtf8[pos + 1], p, sizeof(buf) - (p - buf), EndPos - pos - 1);
+     if (EndPos != lengthUtf8)
+        *p++ = '>';
+     *p = 0;
+
+     SetValue(buf);
      }
   else
      SetValue(value);
 }
 
-char cMenuEditStrItem::Inc(char c, bool Up)
+uint cMenuEditStrItem::Inc(uint c, bool Up)
 {
-  const char *p = strchr(allowed, c);
+  uint *p = IsAllowed(c);
   if (!p)
-     p = allowed;
+     p = allowedUtf8;
   if (Up) {
      if (!*++p)
-        p = allowed;
+        p = allowedUtf8;
+     }
+  else if (--p < allowedUtf8) {
+     p = allowedUtf8;
+     while (*p && *(p + 1))
+           p++;
      }
-  else if (--p < allowed)
-     p = allowed + strlen(allowed) - 1;
   return *p;
 }
 
+void cMenuEditStrItem::Insert(void)
+{
+  memmove(valueUtf8 + pos + 1, valueUtf8 + pos, (lengthUtf8 - pos + 1) * sizeof(*valueUtf8));
+  lengthUtf8++;
+  valueUtf8[pos] = ' ';
+}
+
+void cMenuEditStrItem::Delete(void)
+{
+  memmove(valueUtf8 + pos, valueUtf8 + pos + 1, (lengthUtf8 - pos) * sizeof(*valueUtf8));
+  lengthUtf8--;
+}
+
 eOSState cMenuEditStrItem::ProcessKey(eKeys Key)
 {
   bool SameKey = NORMALKEY(Key) == lastKey;
@@ -365,7 +443,7 @@
   else if (!newchar && k0 <= lastKey && lastKey <= k9 && autoAdvanceTimeout.TimedOut()) {
      AdvancePos();
      newchar = true;
-     currentChar = NULL;
+     currentCharUtf8 = NULL;
      Set();
      return osContinue;
      }
@@ -374,7 +452,7 @@
                  if (InEditMode()) {
                     if (!insert || !newchar) {
                        uppercase = !uppercase;
-                       value[pos] = uppercase ? toupper(value[pos]) : tolower(value[pos]);
+                       valueUtf8[pos] = uppercase ? Utf8to(upper, valueUtf8[pos]) : Utf8to(lower, valueUtf8[pos]);
                        }
                     }
                  else
@@ -390,21 +468,21 @@
                     return osUnknown;
                  break;
     case kYellow|k_Repeat:
-    case kYellow: // Remove the character at current position; in insert mode it is the character to the right of cursor
+    case kYellow: // Remove the character at the current position; in insert mode it is the character to the right of the cursor
                  if (InEditMode()) {
-                    if (strlen(value) > 1) {
-                       if (!insert || pos < int(strlen(value)) - 1)
-                          memmove(value + pos, value + pos + 1, strlen(value) - pos);
-                       else if (insert && pos == int(strlen(value)) - 1)
-                          value[pos] = ' '; // in insert mode, deleting the last character replaces it with a blank to keep the cursor position
+                    if (lengthUtf8 > 1) {
+                       if (!insert || pos < lengthUtf8 - 1)
+                          Delete();
+                       else if (insert && pos == lengthUtf8 - 1)
+                          valueUtf8[pos] = ' '; // in insert mode, deleting the last character replaces it with a blank to keep the cursor position
                        // reduce position, if we removed the last character
-                       if (pos == int(strlen(value)))
+                       if (pos == lengthUtf8)
                           pos--;
                        }
-                    else if (strlen(value) == 1)
-                       value[0] = ' '; // This is the last character in the string, replace it with a blank
-                    if (isalpha(value[pos]))
-                       uppercase = isupper(value[pos]);
+                    else if (lengthUtf8 == 1)
+                       valueUtf8[0] = ' '; // This is the last character in the string, replace it with a blank
+                    if (Utf8is(alpha, valueUtf8[pos]))
+                       uppercase = Utf8is(upper, valueUtf8[pos]);
                     newchar = true;
                     }
                  else
@@ -423,13 +501,14 @@
                        pos--;
                     newchar = true;
                     }
-                 if (!insert && isalpha(value[pos]))
-                    uppercase = isupper(value[pos]);
+                 if (!insert && Utf8is(alpha, valueUtf8[pos]))
+                    uppercase = Utf8is(upper, valueUtf8[pos]);
                  break;
     case kRight|k_Repeat:
-    case kRight: AdvancePos();
-                 if (pos == 0) {
-                    orgValue = strdup(value);
+    case kRight: if (InEditMode())
+                    AdvancePos();
+                 else {
+                    EnterEditMode();
                     SetHelpKeys();
                     }
                  break;
@@ -439,15 +518,13 @@
     case kDown:  if (InEditMode()) {
                     if (insert && newchar) {
                        // create a new character in insert mode
-                       if (int(strlen(value)) < length - 1) {
-                          memmove(value + pos + 1, value + pos, strlen(value) - pos + 1);
-                          value[pos] = ' ';
-                          }
+                       if (lengthUtf8 < length - 1)
+                          Insert();
                        }
                     if (uppercase)
-                       value[pos] = toupper(Inc(tolower(value[pos]), NORMALKEY(Key) == kUp));
+                       valueUtf8[pos] = Utf8to(upper, Inc(Utf8to(lower, valueUtf8[pos]), NORMALKEY(Key) == kUp));
                     else
-                       value[pos] =         Inc(        value[pos],  NORMALKEY(Key) == kUp);
+                       valueUtf8[pos] =               Inc(              valueUtf8[pos],  NORMALKEY(Key) == kUp);
                     newchar = false;
                     }
                  else
@@ -459,35 +536,33 @@
                     if (!SameKey) {
                        if (!newchar)
                           AdvancePos();
-                       currentChar = NULL;
+                       currentCharUtf8 = NULL;
                        }
-                    if (!currentChar || !*currentChar || *currentChar == '\t') {
+                    if (!currentCharUtf8 || !*currentCharUtf8 || *currentCharUtf8 == '\t') {
                        // find the beginning of the character map entry for Key
                        int n = NORMALKEY(Key) - k0;
-                       currentChar = charMap;
-                       while (n > 0 && *currentChar) {
-                             if (*currentChar++ == '\t')
+                       currentCharUtf8 = charMapUtf8;
+                       while (n > 0 && *currentCharUtf8) {
+                             if (*currentCharUtf8++ == '\t')
                                 n--;
                              }
                        // find first allowed character
-                       while (*currentChar && *currentChar != '\t' && !strchr(allowed, *currentChar))
-                             currentChar++;
+                       while (*currentCharUtf8 && *currentCharUtf8 != '\t' && !IsAllowed(*currentCharUtf8))
+                             currentCharUtf8++;
                        }
-                    if (*currentChar && *currentChar != '\t') {
+                    if (*currentCharUtf8 && *currentCharUtf8 != '\t') {
                        if (insert && newchar) {
                           // create a new character in insert mode
-                          if (int(strlen(value)) < length - 1) {
-                             memmove(value + pos + 1, value + pos, strlen(value) - pos + 1);
-                             value[pos] = ' ';
-                             }
+                          if (lengthUtf8 < length - 1)
+                             Insert();
                           }
-                       value[pos] = *currentChar;
+                       valueUtf8[pos] = *currentCharUtf8;
                        if (uppercase)
-                          value[pos] = toupper(value[pos]);
+                          valueUtf8[pos] = Utf8to(upper, valueUtf8[pos]);
                        // find next allowed character
                        do {
-                          currentChar++;
-                          } while (*currentChar && *currentChar != '\t' && !strchr(allowed, *currentChar));
+                          currentCharUtf8++;
+                          } while (*currentCharUtf8 && *currentCharUtf8 != '\t' && !IsAllowed(*currentCharUtf8));
                        newchar = false;
                        autoAdvanceTimeout.Set(AUTO_ADVANCE_TIMEOUT);
                        }
@@ -498,32 +573,25 @@
                  break;
     case kBack:
     case kOk:    if (InEditMode()) {
-                    if (Key == kBack && orgValue) {
-                       strcpy(value, orgValue);
-                       free(orgValue);
-                       orgValue = NULL;
-                       }
-                    pos = -1;
-                    newchar = true;
-                    stripspace(value);
+                    LeaveEditMode(Key == kOk);
                     SetHelpKeys();
                     break;
                     }
                  // run into default
     default:     if (InEditMode() && BASICKEY(Key) == kKbd) {
                     int c = KEYKBD(Key);
-                    if (c <= 0xFF) {
-                       const char *p = strchr(allowed, tolower(c));
+                    if (c <= 0xFF) { // FIXME what about other UTF-8 characters?
+                       uint *p = IsAllowed(Utf8to(lower, c));
                        if (p) {
-                          int l = strlen(value);
-                          if (insert && l < length - 1)
-                             memmove(value + pos + 1, value + pos, l - pos + 1);
-                          value[pos] = c;
+                          if (insert && lengthUtf8 < length - 1)
+                             Insert();
+                          valueUtf8[pos] = c;
                           if (pos < length - 2)
                              pos++;
-                          if (pos >= l) {
-                             value[pos] = ' ';
-                             value[pos + 1] = 0;
+                          if (pos >= lengthUtf8) {
+                             valueUtf8[pos] = ' ';
+                             valueUtf8[pos + 1] = 0;
+                             lengthUtf8 = pos + 1;
                              }
                           }
                        else {
@@ -540,7 +608,7 @@
                     else {
                        switch (c) {
                          case kfHome: pos = 0; break;
-                         case kfEnd:  pos = strlen(value) - 1; break;
+                         case kfEnd:  pos = lengthUtf8 - 1; break;
                          case kfIns:  return ProcessKey(kGreen);
                          case kfDel:  return ProcessKey(kYellow);
                          }
@@ -690,7 +758,7 @@
 #define DATEBUFFERSIZE 32
   char buf[DATEBUFFERSIZE];
   if (weekdays && *weekdays) {
-     SetValue(cTimer::PrintDay(0, *weekdays));
+     SetValue(cTimer::PrintDay(0, *weekdays, false));
      return;
      }
   else if (*value) {
@@ -880,9 +948,7 @@
 
 void cMenuSetupPage::SetSection(const char *Section)
 {
-  char buf[40];
-  snprintf(buf, sizeof(buf), "%s - %s", tr("Setup"), Section);
-  SetTitle(buf);
+  SetTitle(cString::sprintf("%s - %s", tr("Setup"), Section));
 }
 
 eOSState cMenuSetupPage::ProcessKey(eKeys Key)
@@ -903,9 +969,7 @@
 void cMenuSetupPage::SetPlugin(cPlugin *Plugin)
 {
   plugin = Plugin;
-  char buf[40];
-  snprintf(buf, sizeof(buf), "%s '%s'", tr("Plugin"), plugin->Name());
-  SetSection(buf);
+  SetSection(cString::sprintf("%s '%s'", tr("Plugin"), plugin->Name()));
 }
 
 void cMenuSetupPage::SetupStore(const char *Name, const char *Value)
diff -ruN vdr-1.5.2/menuitems.h vdr-1.5.3/menuitems.h
--- vdr-1.5.2/menuitems.h	2006-04-14 12:01:47.000000000 +0200
+++ vdr-1.5.3/menuitems.h	2007-06-08 13:53:37.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: menuitems.h 1.20 2006/04/14 10:01:47 kls Exp $
+ * $Id: menuitems.h 1.21 2007/06/08 11:53:37 kls Exp $
  */
 
 #ifndef __MENUITEMS_H
@@ -77,22 +77,29 @@
 
 class cMenuEditStrItem : public cMenuEditItem {
 private:
-  char *orgValue;
   char *value;
   int length;
-  char *allowed;
-  int pos;
+  const char *allowed;
+  int pos, offset;
   bool insert, newchar, uppercase;
-  const char *charMap;
-  const char *currentChar;
+  int lengthUtf8;
+  uint *valueUtf8;
+  uint *allowedUtf8;
+  uint *charMapUtf8;
+  uint *currentCharUtf8;
   eKeys lastKey;
   cTimeMs autoAdvanceTimeout;
   void SetHelpKeys(void);
+  uint *IsAllowed(uint c);
   void AdvancePos(void);
   virtual void Set(void);
-  char Inc(char c, bool Up);
-protected:
-  bool InEditMode(void) { return pos >= 0; }
+  uint Inc(uint c, bool Up);
+  void Insert(void);
+  void Delete(void);
+protected:
+  void EnterEditMode(void);
+  void LeaveEditMode(bool SaveValue = false);
+  bool InEditMode(void) { return valueUtf8 != NULL; }
 public:
   cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed);
   ~cMenuEditStrItem();
diff -ruN vdr-1.5.2/newplugin vdr-1.5.3/newplugin
--- vdr-1.5.2/newplugin	2007-02-24 14:23:08.000000000 +0100
+++ vdr-1.5.3/newplugin	2007-04-28 16:46:39.000000000 +0200
@@ -12,7 +12,7 @@
 # See the main source file 'vdr.c' for copyright information and
 # how to reach the author.
 #
-# $Id: newplugin 1.31 2007/02/24 13:23:08 kls Exp $
+# $Id: newplugin 1.32 2007/04/28 14:46:39 kls Exp $
 
 $PLUGIN_NAME = $ARGV[0] || die "Usage: newplugin <name>\n";
 
@@ -61,7 +61,7 @@
 # The official name of this plugin.
 # This name will be used in the '-P...' option of VDR to load the plugin.
 # By default the main source file also carries this name.
-# IPORTANT: the presence of this macro is important for the Make.config
+# IMPORTANT: the presence of this macro is important for the Make.config
 # file. So it must be defined, even if it is not used here!
 #
 PLUGIN = $PLUGIN_NAME
@@ -217,7 +217,7 @@
 
 void cPlugin${PLUGIN_CLASS}::Stop(void)
 {
-  // Stop any background activities the plugin shall perform.
+  // Stop any background activities the plugin is performing.
 }
 
 void cPlugin${PLUGIN_CLASS}::Housekeeping(void)
diff -ruN vdr-1.5.2/nit.c vdr-1.5.3/nit.c
--- vdr-1.5.2/nit.c	2006-10-28 14:31:04.000000000 +0200
+++ vdr-1.5.3/nit.c	2007-04-29 13:35:33.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: nit.c 1.13 2006/10/28 12:31:04 kls Exp $
+ * $Id: nit.c 1.14 2007/04/29 11:35:33 kls Exp $
  */
 
 #include "nit.h"
@@ -144,17 +144,16 @@
                  for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
                      if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
                         if (Setup.UpdateChannels >= 5) {
-                           if (ISTRANSPONDER(cChannel::Transponder(Frequency, Polarization), Transponder())) { // only modify channels if we're actually receiving this transponder
-                              if (!ISTRANSPONDER(cChannel::Transponder(Frequency, Polarization), Channel->Transponder())) {
-                                 for (int n = 0; n < NumFrequencies; n++) {
-                                     if (ISTRANSPONDER(cChannel::Transponder(Frequencies[n], Polarization), Channel->Transponder())) {
-                                        Frequency = Frequencies[n];
-                                        break;
-                                        }
+                           if (!ISTRANSPONDER(cChannel::Transponder(Frequency, Polarization), Channel->Transponder())) {
+                              for (int n = 0; n < NumFrequencies; n++) {
+                                  if (ISTRANSPONDER(cChannel::Transponder(Frequencies[n], Polarization), Channel->Transponder())) {
+                                     Frequency = Frequencies[n];
+                                     break;
                                      }
-                                 }
-                              Channel->SetSatTransponderData(Source, Frequency, Polarization, SymbolRate, CodeRate);
+                                  }
                               }
+                           if (ISTRANSPONDER(cChannel::Transponder(Frequency, Polarization), Transponder())) // only modify channels if we're actually receiving this transponder
+                              Channel->SetSatTransponderData(Source, Frequency, Polarization, SymbolRate, CodeRate);
                            }
                         found = true;
                         }
@@ -195,17 +194,16 @@
                  for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
                      if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
                         if (Setup.UpdateChannels >= 5) {
-                           if (ISTRANSPONDER(Frequency / 1000, Transponder())) { // only modify channels if we're actually receiving this transponder
-                              if (!ISTRANSPONDER(Frequency / 1000, Channel->Transponder())) {
-                                 for (int n = 0; n < NumFrequencies; n++) {
-                                     if (ISTRANSPONDER(Frequencies[n] / 1000, Channel->Transponder())) {
-                                        Frequency = Frequencies[n];
-                                        break;
-                                        }
+                           if (!ISTRANSPONDER(Frequency / 1000, Channel->Transponder())) {
+                              for (int n = 0; n < NumFrequencies; n++) {
+                                  if (ISTRANSPONDER(Frequencies[n] / 1000, Channel->Transponder())) {
+                                     Frequency = Frequencies[n];
+                                     break;
                                      }
-                                 }
-                              Channel->SetCableTransponderData(Source, Frequency, Modulation, SymbolRate, CodeRate);
+                                  }
                               }
+                           if (ISTRANSPONDER(Frequency / 1000, Transponder())) // only modify channels if we're actually receiving this transponder
+                              Channel->SetCableTransponderData(Source, Frequency, Modulation, SymbolRate, CodeRate);
                            }
                         found = true;
                         }
@@ -253,17 +251,16 @@
                  for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
                      if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
                         if (Setup.UpdateChannels >= 5) {
-                           if (ISTRANSPONDER(Frequency / 1000000, Transponder())) { // only modify channels if we're actually receiving this transponder
-                              if (!ISTRANSPONDER(Frequency / 1000000, Channel->Transponder())) {
-                                 for (int n = 0; n < NumFrequencies; n++) {
-                                     if (ISTRANSPONDER(Frequencies[n] / 1000000, Channel->Transponder())) {
-                                        Frequency = Frequencies[n];
-                                        break;
-                                        }
+                           if (!ISTRANSPONDER(Frequency / 1000000, Channel->Transponder())) {
+                              for (int n = 0; n < NumFrequencies; n++) {
+                                  if (ISTRANSPONDER(Frequencies[n] / 1000000, Channel->Transponder())) {
+                                     Frequency = Frequencies[n];
+                                     break;
                                      }
-                                 }
-                              Channel->SetTerrTransponderData(Source, Frequency, Bandwidth, Constellation, Hierarchy, CodeRateHP, CodeRateLP, GuardInterval, TransmissionMode);
+                                  }
                               }
+                           if (ISTRANSPONDER(Frequency / 1000000, Transponder())) // only modify channels if we're actually receiving this transponder
+                              Channel->SetTerrTransponderData(Source, Frequency, Bandwidth, Constellation, Hierarchy, CodeRateHP, CodeRateLP, GuardInterval, TransmissionMode);
                            }
                         found = true;
                         }
diff -ruN vdr-1.5.2/nit.h vdr-1.5.3/nit.h
--- vdr-1.5.2/nit.h	2004-01-18 12:13:48.000000000 +0100
+++ vdr-1.5.3/nit.h	2007-06-10 10:50:21.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: nit.h 1.2 2004/01/18 11:13:48 kls Exp $
+ * $Id: nit.h 1.3 2007/06/10 08:50:21 kls Exp $
  */
 
 #ifndef __NIT_H
@@ -13,7 +13,7 @@
 #include "filter.h"
 
 #define MAXNITS 16
-#define MAXNETWORKNAME 256
+#define MAXNETWORKNAME Utf8BufSize(256)
 
 class cNitFilter : public cFilter {
 private:
diff -ruN vdr-1.5.2/osd.c vdr-1.5.3/osd.c
--- vdr-1.5.2/osd.c	2007-02-17 17:05:52.000000000 +0100
+++ vdr-1.5.3/osd.c	2007-06-10 14:16:36.000000000 +0200
@@ -4,11 +4,12 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: osd.c 1.68 2007/02/17 16:05:52 kls Exp $
+ * $Id: osd.c 1.69 2007/06/10 12:16:36 kls Exp $
  */
 
 #include "osd.h"
 #include <math.h>
+#include <stdarg.h>
 #include <stdlib.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
@@ -20,6 +21,18 @@
 cPalette::cPalette(int Bpp)
 {
   SetBpp(Bpp);
+  SetAntiAliasGranularity(10, 10);
+}
+
+void cPalette::SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
+{
+  if (FixedColors >= MAXNUMCOLORS || BlendColors == 0)
+     antiAliasGranularity = MAXNUMCOLORS - 1;
+  else {
+     int ColorsForBlending = MAXNUMCOLORS - FixedColors;
+     int ColorsPerBlend = ColorsForBlending / BlendColors + 2; // +2 = the full foreground and background colors, which are amoung the fixed colors
+     antiAliasGranularity = double(MAXNUMCOLORS - 1) / (ColorsPerBlend - 1);
+     }
 }
 
 void cPalette::Reset(void)
@@ -30,18 +43,23 @@
 
 int cPalette::Index(tColor Color)
 {
+  // Check if color is already defined:
   for (int i = 0; i < numColors; i++) {
       if (color[i] == Color)
          return i;
       }
+  // No exact color, try a close one:
+  int i = ClosestColor(Color, 4);
+  if (i >= 0)
+     return i;
+  // No close one, try to define a new one:
   if (numColors < maxColors) {
      color[numColors++] = Color;
      modified = true;
      return numColors - 1;
      }
-  dsyslog("too many different colors used in palette");
-  //TODO: return the index of the "closest" color?
-  return 0;
+  // Out of colors, so any close color must do:
+  return ClosestColor(Color);
 }
 
 void cPalette::SetBpp(int Bpp)
@@ -91,6 +109,48 @@
   for (int i = 0; i < Palette.numColors; i++)
       SetColor(i, Palette.color[i]);
   numColors = Palette.numColors;
+  antiAliasGranularity = Palette.antiAliasGranularity;
+}
+
+tColor cPalette::Blend(tColor ColorFg, tColor ColorBg, uint8_t Level)
+{
+  if (antiAliasGranularity > 0)
+     Level = uint8_t(int(Level / antiAliasGranularity + 0.5) * antiAliasGranularity);
+  int Af = (ColorFg & 0xFF000000) >> 24;
+  int Rf = (ColorFg & 0x00FF0000) >> 16;
+  int Gf = (ColorFg & 0x0000FF00) >>  8;
+  int Bf = (ColorFg & 0x000000FF);
+  int Ab = (ColorBg & 0xFF000000) >> 24;
+  int Rb = (ColorBg & 0x00FF0000) >> 16;
+  int Gb = (ColorBg & 0x0000FF00) >>  8;
+  int Bb = (ColorBg & 0x000000FF);
+  int A = (Ab + (Af - Ab) * Level / 0xFF) & 0xFF;
+  int R = (Rb + (Rf - Rb) * Level / 0xFF) & 0xFF;
+  int G = (Gb + (Gf - Gb) * Level / 0xFF) & 0xFF;
+  int B = (Bb + (Bf - Bb) * Level / 0xFF) & 0xFF;
+  return (A << 24) | (R << 16) | (G << 8) | B;
+}
+
+int cPalette::ClosestColor(tColor Color, int MaxDiff)
+{
+  int n = 0;
+  int d = INT_MAX;
+  int A1 = (Color & 0xFF000000) >> 24;
+  int R1 = (Color & 0x00FF0000) >> 16;
+  int G1 = (Color & 0x0000FF00) >>  8;
+  int B1 = (Color & 0x000000FF);
+  for (int i = 0; i < numColors; i++) {
+      int A2 = (color[i] & 0xFF000000) >> 24;
+      int R2 = (color[i] & 0x00FF0000) >> 16;
+      int G2 = (color[i] & 0x0000FF00) >>  8;
+      int B2 = (color[i] & 0x000000FF);
+      int diff = (abs(A1 - A2) << 1) + (abs(R1 - R2) << 1) + (abs(G1 - G2) << 1) + (abs(B1 - B2) << 1);
+      if (diff < d) {
+         d = diff;
+         n = i;
+         }
+      }
+  return d <= MaxDiff ? n : -1;
 }
 
 // --- cBitmap ---------------------------------------------------------------
@@ -424,26 +484,7 @@
         return;
      x -= x0;
      y -= y0;
-     tIndex fg = Index(ColorFg);
-     tIndex bg = (ColorBg != clrTransparent) ? Index(ColorBg) : 0;
-     while (s && *s) {
-           const cFont::tCharData *CharData = Font->CharData(*s++);
-           if (limit && int(x + CharData->width) > limit)
-              break; // we don't draw partial characters
-           if (int(x + CharData->width) > 0) {
-              for (int row = 0; row < h; row++) {
-                  cFont::tPixelData PixelData = CharData->lines[row];
-                  for (int col = CharData->width; col-- > 0; ) {
-                      if (ColorBg != clrTransparent || (PixelData & 1))
-                         SetIndex(x + col, y + row, (PixelData & 1) ? fg : bg);
-                      PixelData >>= 1;
-                      }
-                  }
-              }
-           x += CharData->width;
-           if (x > width - 1)
-              break;
-           }
+     Font->DrawText(this, x, y, s, ColorFg, ColorBg, limit);
      }
 }
 
@@ -623,6 +664,12 @@
   isOpen--;
 }
 
+void cOsd::SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
+{
+  for (int i = 0; i < numBitmaps; i++)
+      bitmaps[i]->SetAntiAliasGranularity(FixedColors, BlendColors);
+}
+
 cBitmap *cOsd::GetBitmap(int Area)
 {
   return Area < numBitmaps ? bitmaps[Area] : NULL;
diff -ruN vdr-1.5.2/osd.h vdr-1.5.3/osd.h
--- vdr-1.5.2/osd.h	2006-02-26 15:45:05.000000000 +0100
+++ vdr-1.5.3/osd.h	2007-06-10 14:15:52.000000000 +0200
@@ -4,12 +4,13 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: osd.h 1.53 2006/02/26 14:45:05 kls Exp $
+ * $Id: osd.h 1.54 2007/06/10 12:15:52 kls Exp $
  */
 
 #ifndef __OSD_H
 #define __OSD_H
 
+#include <limits.h>
 #include <stdio.h>
 #include <stdint.h>
 #include "font.h"
@@ -41,7 +42,7 @@
                  oeUnknown,
                };
 
-typedef uint32_t tColor;
+typedef uint32_t tColor; // see also font.h
 typedef uint8_t tIndex;
 
 class cPalette {
@@ -50,11 +51,22 @@
   int bpp;
   int maxColors, numColors;
   bool modified;
+  double antiAliasGranularity;
 protected:
   typedef tIndex tIndexes[MAXNUMCOLORS];
 public:
   cPalette(int Bpp = 8);
         ///< Initializes the palette with the given color depth.
+  void SetAntiAliasGranularity(uint FixedColors, uint BlendColors);
+        ///< Allows the system to optimize utilization of the limited color
+        ///< palette entries when generating blended colors for anti-aliasing.
+        ///< FixedColors is the maximum number of colors used, and BlendColors
+        ///< is the maximum number of foreground/background color combinations
+        ///< used with anti-aliasing. If this function is not called with
+        ///< useful values, the palette may be filled up with many shades of
+        ///< a single color combination, and may not be able to serve all
+        ///< requested colors. By default the palette assumes there will be
+        ///< 10 fixed colors and 10 color combinations.
   int Bpp(void) { return bpp; }
   void Reset(void);
         ///< Resets the palette, making it contain no colors.
@@ -62,7 +74,7 @@
         ///< Returns the index of the given Color (the first color has index 0).
         ///< If Color is not yet contained in this palette, it will be added if
         ///< there is a free slot. If the color can't be added to this palette,
-        ///< 0 will be returned.
+        ///< the closest existing color will be returned.
   tColor Color(int Index) { return Index < maxColors ? color[Index] : 0; }
         ///< Returns the color at the given Index. If Index is outside the valid
         ///< range, 0 will be returned.
@@ -88,6 +100,18 @@
   void Replace(const cPalette &Palette);
         ///< Replaces the colors of this palette with the colors from the given
         ///< palette.
+  tColor Blend(tColor ColorFg, tColor ColorBg, uint8_t Level);
+        ///< Determines a color that consists of a linear blend between ColorFg
+        ///< and ColorBg. If Level is 0, the result is ColorBg, if it is 255,
+        ///< the result is ColorFg. If SetAntiAliasGranularity() has been called previously,
+        ///< Level will be mapped to a limited range of levels that allow to make best
+        ///< use of the palette entries.
+  int ClosestColor(tColor Color, int MaxDiff = INT_MAX);
+        ///< Returns the index of a color in this paltte that is closest to the given
+        ///< Color. MaxDiff can be used to control the maximum allowed color difference.
+        ///< If no color with a maximum difference of MaxDiff can be found, -1 will
+        ///< be returned. With the default value of INT_MAX, there will always be
+        ///< a valid color index returned, but the color may be completely different.
   };
 
 enum eTextAlignment { taCenter  = 0x00,
@@ -98,6 +122,8 @@
                       taDefault = taTop | taLeft
                     };
 
+class cFont;
+
 class cBitmap : public cPalette {
 private:
   tIndex *bitmap;
@@ -202,6 +228,8 @@
        ///< 7: vertical,   falling, upper
   const tIndex *Data(int x, int y);
        ///< Returns the address of the index byte at the given coordinates.
+  tColor GetColor(int x, int y) { return Color(*Data(x, y)); }
+       ///< Returns the color at the given coordinates.
   };
 
 struct tArea {
@@ -247,6 +275,16 @@
   int Top(void) { return top; }
   int Width(void) { return width; }
   int Height(void) { return height; }
+  void SetAntiAliasGranularity(uint FixedColors, uint BlendColors);
+       ///< Allows the system to optimize utilization of the limited color
+       ///< palette entries when generating blended colors for anti-aliasing.
+       ///< FixedColors is the maximum number of colors used, and BlendColors
+       ///< is the maximum number of foreground/background color combinations
+       ///< used with anti-aliasing. If this function is not called with
+       ///< useful values, the palette may be filled up with many shades of
+       ///< a single color combination, and may not be able to serve all
+       ///< requested colors. By default the palette assumes there will be
+       ///< 10 fixed colors and 10 color combinations.
   cBitmap *GetBitmap(int Area);
        ///< Returns a pointer to the bitmap for the given Area, or NULL if no
        ///< such bitmap exists.
diff -ruN vdr-1.5.2/osdbase.c vdr-1.5.3/osdbase.c
--- vdr-1.5.2/osdbase.c	2007-01-05 11:41:16.000000000 +0100
+++ vdr-1.5.3/osdbase.c	2007-06-09 12:07:46.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: osdbase.c 1.30 2007/01/05 10:41:16 kls Exp $
+ * $Id: osdbase.c 1.31 2007/06/09 10:07:46 kls Exp $
  */
 
 #include "osdbase.h"
@@ -86,10 +86,8 @@
   subMenu = NULL;
   helpRed = helpGreen = helpYellow = helpBlue = NULL;
   status = NULL;
-  if (!displayMenuCount++) {
-     displayMenu = Skins.Current()->DisplayMenu();
-     displayMenuItems = displayMenu->MaxItems();
-     }
+  if (!displayMenuCount++)
+     SetDisplayMenu();
 }
 
 cOsdMenu::~cOsdMenu()
@@ -103,15 +101,25 @@
      DELETENULL(displayMenu);
 }
 
+void cOsdMenu::SetDisplayMenu(void)
+{
+  if (displayMenu) {
+     displayMenu->Clear();
+     delete displayMenu;
+     }
+  displayMenu = Skins.Current()->DisplayMenu();
+  displayMenuItems = displayMenu->MaxItems();
+}
+
 const char *cOsdMenu::hk(const char *s)
 {
-  static char buffer[64];
+  static cString buffer;
   if (s && hasHotkeys) {
      if (digit == 0 && '1' <= *s && *s <= '9' && *(s + 1) == ' ')
         digit = -1; // prevents automatic hotkeys - input already has them
      if (digit >= 0) {
         digit++;
-        snprintf(buffer, sizeof(buffer), " %c %s", (digit < 10) ? '0' + digit : ' ' , s);
+        buffer = cString::sprintf(" %c %s", (digit < 10) ? '0' + digit : ' ' , s);
         s = buffer;
         }
      }
diff -ruN vdr-1.5.2/osdbase.h vdr-1.5.3/osdbase.h
--- vdr-1.5.2/osdbase.h	2007-01-05 11:41:32.000000000 +0100
+++ vdr-1.5.3/osdbase.h	2007-06-09 13:49:00.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: osdbase.h 1.15 2007/01/05 10:41:32 kls Exp $
+ * $Id: osdbase.h 1.16 2007/06/09 11:49:00 kls Exp $
  */
 
 #ifndef __OSDBASE_H
@@ -96,6 +96,7 @@
   int digit;
   bool hasHotkeys;
 protected:
+  void SetDisplayMenu(void);
   cSkinDisplayMenu *DisplayMenu(void) { return displayMenu; }
   const char *hk(const char *s);
   void SetCols(int c0, int c1 = 0, int c2 = 0, int c3 = 0, int c4 = 0);
diff -ruN vdr-1.5.2/remote.c vdr-1.5.3/remote.c
--- vdr-1.5.2/remote.c	2007-02-24 14:23:12.000000000 +0100
+++ vdr-1.5.3/remote.c	2007-04-30 14:27:56.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: remote.c 1.56 2007/02/24 13:23:12 kls Exp $
+ * $Id: remote.c 1.57 2007/04/30 12:27:56 kls Exp $
  */
 
 #include "remote.h"
@@ -31,6 +31,7 @@
 cCondVar cRemote::keyPressed;
 const char *cRemote::keyMacroPlugin = NULL;
 const char *cRemote::callPlugin = NULL;
+bool cRemote::enabled = true;
 time_t cRemote::lastActivity = 0;
 
 cRemote::cRemote(const char *Name)
@@ -185,7 +186,7 @@
          if ((k & k_Repeat) != 0)
             repeatTimeout.Set(REPEATTIMEOUT);
          lastActivity = time(NULL);
-         return k;
+         return enabled ? k : kNone;
          }
       else if (!WaitMs || !keyPressed.TimedWait(mutex, WaitMs) && repeatTimeout.TimedOut())
          return kNone;
diff -ruN vdr-1.5.2/remote.h vdr-1.5.3/remote.h
--- vdr-1.5.2/remote.h	2007-02-24 16:53:00.000000000 +0100
+++ vdr-1.5.3/remote.h	2007-04-30 14:37:37.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: remote.h 1.39 2007/02/24 15:53:00 kls Exp $
+ * $Id: remote.h 1.40 2007/04/30 12:37:37 kls Exp $
  */
 
 #ifndef __REMOTE_H
@@ -31,6 +31,7 @@
   static time_t lastActivity;
   static const char *keyMacroPlugin;
   static const char *callPlugin;
+  static bool enabled;
   char *name;
 protected:
   cRemote(const char *Name);
@@ -45,6 +46,8 @@
   const char *Name(void) { return name; }
   static void SetLearning(cRemote *Learning) { learning = Learning; }
   static bool IsLearning() { return learning != NULL; }
+  static bool Enabled(void) { return enabled; }
+  static void SetEnabled(bool Enabled) { enabled = Enabled; }
   static void Clear(void);
   static bool Put(eKeys Key, bool AtFront = false);
   static bool PutMacro(eKeys Key);
diff -ruN vdr-1.5.2/sdt.c vdr-1.5.3/sdt.c
--- vdr-1.5.2/sdt.c	2006-04-15 16:12:21.000000000 +0200
+++ vdr-1.5.3/sdt.c	2007-06-10 10:50:49.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: sdt.c 1.16 2006/04/15 14:12:21 kls Exp $
+ * $Id: sdt.c 1.17 2007/06/10 08:50:49 kls Exp $
  */
 
 #include "sdt.h"
@@ -56,9 +56,9 @@
                    case 0x04: // NVOD reference service
                    case 0x05: // NVOD time-shifted service
                         {
-                        char NameBuf[1024];
-                        char ShortNameBuf[1024];
-                        char ProviderNameBuf[1024];
+                        char NameBuf[Utf8BufSize(1024)];
+                        char ShortNameBuf[Utf8BufSize(1024)];
+                        char ProviderNameBuf[Utf8BufSize(1024)];
                         sd->serviceName.getText(NameBuf, ShortNameBuf, sizeof(NameBuf), sizeof(ShortNameBuf));
                         char *pn = compactspace(NameBuf);
                         char *ps = compactspace(ShortNameBuf);
diff -ruN vdr-1.5.2/skinclassic.c vdr-1.5.3/skinclassic.c
--- vdr-1.5.2/skinclassic.c	2006-03-31 15:59:50.000000000 +0200
+++ vdr-1.5.3/skinclassic.c	2007-06-10 14:42:02.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: skinclassic.c 1.15 2006/03/31 13:59:50 kls Exp $
+ * $Id: skinclassic.c 1.16 2007/06/10 12:42:02 kls Exp $
  */
 
 #include "skinclassic.h"
@@ -94,8 +94,13 @@
   message = false;
   osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + (Setup.ChannelInfoPos ? 0 : Setup.OSDHeight - Lines * lineHeight));
   timeWidth = font->Width("00:00") + 4;
-  tArea Areas[] = { { 0, 0, Setup.OSDWidth - 1, Lines * lineHeight - 1, 4 } };
-  osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+  tArea Areas[] = { { 0, 0, Setup.OSDWidth - 1, Lines * lineHeight - 1, 8 } };
+  if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
+     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+  else {
+     tArea Areas[] = { { 0, 0, Setup.OSDWidth - 1, Lines * lineHeight - 1, 4 } };
+     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+     }
   osd->DrawRectangle(0, 0, osd->Width() - 1, osd->Height() - 1, Theme.Color(clrBackground));
 }
 
@@ -142,7 +147,9 @@
 {
   if (!message) {
      cString date = DayDateTime();
-     osd->DrawText(osd->Width() - cFont::GetFont(fontSml)->Width(date) - 2, 0, date, Theme.Color(clrChannelDate), Theme.Color(clrBackground), cFont::GetFont(fontSml));
+     const cFont *font = cFont::GetFont(fontSml);
+     int w = font->Width(date);
+     osd->DrawText(osd->Width() - w - 2, 0, date, Theme.Color(clrChannelDate), Theme.Color(clrBackground), cFont::GetFont(fontSml), w);
      }
   osd->Flush();
 }
@@ -155,6 +162,7 @@
   int x0, x1;
   int y0, y1, y2, y3, y4, y5;
   int lineHeight;
+  cString lastDate;
   void SetScrollbar(void);
 public:
   cSkinClassicDisplayMenu(void);
@@ -187,15 +195,20 @@
   y4 = y5 - lineHeight;
   y3 = y4 - lineHeight;
   osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop);
-  tArea Areas[] = { { x0, y0, x1 - 1, y5 - 1, 4 } };
-  if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
+  tArea Areas[] = { { x0, y0, x1 - 1, y5 - 1, 8 } };
+  if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
      osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
   else {
-     tArea Areas[] = { { x0, y0, x1 - 1, y1 - 1, 2 },
-                       { x0, y1, x1 - 1, y3 - 1, 2 },
-                       { x0, y3, x1 - 1, y5 - 1, 4 }
-                     };
-     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+     tArea Areas[] = { { x0, y0, x1 - 1, y5 - 1, 4 } };
+     if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
+        osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+     else {
+        tArea Areas[] = { { x0, y0, x1 - 1, y1 - 1, 2 },
+                          { x0, y1, x1 - 1, y3 - 1, 2 },
+                          { x0, y3, x1 - 1, y5 - 1, 4 }
+                        };
+        osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+        }
      }
   osd->DrawRectangle(x0, y0, x1 - 1, y5 - 1, Theme.Color(clrBackground));
 }
@@ -305,9 +318,10 @@
   ts.Set(osd, xl, y, x1 - xl, y3 - y, t, font, Theme.Color(clrMenuEventTime), Theme.Color(clrBackground));
   if (Event->Vps() && Event->Vps() != Event->StartTime()) {
      char *buffer;
-     asprintf(&buffer, " VPS: %s", *Event->GetVpsString());
+     asprintf(&buffer, " VPS: %s ", *Event->GetVpsString());
      const cFont *font = cFont::GetFont(fontSml);
-     osd->DrawText(x1 - font->Width(buffer), y, buffer, Theme.Color(clrMenuEventVpsFg), Theme.Color(clrMenuEventVpsBg), font);
+     int w = font->Width(buffer);
+     osd->DrawText(x1 - w, y, buffer, Theme.Color(clrMenuEventVpsFg), Theme.Color(clrMenuEventVpsBg), font, w);
      free(buffer);
      }
   y += ts.Height();
@@ -376,8 +390,12 @@
 void cSkinClassicDisplayMenu::Flush(void)
 {
   cString date = DayDateTime();
-  const cFont *font = cFont::GetFont(fontOsd);
-  osd->DrawText(x1 - font->Width(date) - 2, y0, date, Theme.Color(clrMenuDate), Theme.Color(clrMenuTitleBg), font);
+  if (!lastDate || strcmp(date, lastDate)) {
+     const cFont *font = cFont::GetFont(fontOsd);
+     int w = font->Width(date);
+     osd->DrawText(x1 - w - 2, y0, date, Theme.Color(clrMenuDate), Theme.Color(clrMenuTitleBg), font, w);
+     lastDate = date;
+     }
   osd->Flush();
 }
 
@@ -414,8 +432,13 @@
   y2 = 2 * lineHeight;
   y3 = 3 * lineHeight;
   osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - y3);
-  tArea Areas[] = { { x0, y0, x1 - 1, y3 - 1, 4 } };
-  osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+  tArea Areas[] = { { x0, y0, x1 - 1, y3 - 1, 8 } };
+  if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
+     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+  else {
+     tArea Areas[] = { { x0, y0, x1 - 1, y3 - 1, 4 } };
+     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+     }
   osd->DrawRectangle(x0, y0, x1 - 1, y3 - 1, ModeOnly ? clrTransparent : Theme.Color(clrBackground));
 }
 
@@ -455,14 +478,15 @@
 {
   const cFont *font = cFont::GetFont(fontOsd);
   int w = font->Width(Current);
-  osd->DrawText(x0, y2, Current, Theme.Color(clrReplayCurrent), Theme.Color(clrBackground), font, lastCurrentWidth > w ? lastCurrentWidth : 0);
+  osd->DrawText(x0, y2, Current, Theme.Color(clrReplayCurrent), Theme.Color(clrBackground), font, lastCurrentWidth > w ? lastCurrentWidth : w);
   lastCurrentWidth = w;
 }
 
 void cSkinClassicDisplayReplay::SetTotal(const char *Total)
 {
   const cFont *font = cFont::GetFont(fontOsd);
-  osd->DrawText(x1 - font->Width(Total), y2, Total, Theme.Color(clrReplayTotal), Theme.Color(clrBackground), font);
+  int w = font->Width(Total);
+  osd->DrawText(x1 - font->Width(Total), y2, Total, Theme.Color(clrReplayTotal), Theme.Color(clrBackground), font, w);
 }
 
 void cSkinClassicDisplayReplay::SetJump(const char *Jump)
@@ -503,8 +527,13 @@
   const cFont *font = cFont::GetFont(fontOsd);
   int lineHeight = font->Height();
   osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - lineHeight);
-  tArea Areas[] = { { 0, 0, Setup.OSDWidth - 1, lineHeight - 1, 4 } };
-  osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+  tArea Areas[] = { { 0, 0, Setup.OSDWidth - 1, lineHeight - 1, 8 } };
+  if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
+     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+  else {
+     tArea Areas[] = { { 0, 0, Setup.OSDWidth - 1, lineHeight - 1, 4 } };
+     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+     }
 }
 
 cSkinClassicDisplayVolume::~cSkinClassicDisplayVolume()
@@ -572,8 +601,13 @@
   y1 = lineHeight;
   y2 = y1 + NumTracks * lineHeight;
   osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - y2);
-  tArea Areas[] = { { x0, y0, x1 - 1, y2 - 1, 4 } };
-  osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+  tArea Areas[] = { { x0, y0, x1 - 1, y2 - 1, 8 } };
+  if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
+     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+  else {
+     tArea Areas[] = { { x0, y0, x1 - 1, y2 - 1, 4 } };
+     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+     }
   osd->DrawText(x0, y0, Title, Theme.Color(clrMenuTitleFg), Theme.Color(clrMenuTitleBg), font, x1 - x0);
   for (int i = 0; i < NumTracks; i++)
       SetItem(Tracks[i], i, false);
@@ -630,8 +664,13 @@
   const cFont *font = cFont::GetFont(fontOsd);
   int lineHeight = font->Height();
   osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - lineHeight);
-  tArea Areas[] = { { 0, 0, Setup.OSDWidth - 1, lineHeight - 1, 2 } };
-  osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+  tArea Areas[] = { { 0, 0, Setup.OSDWidth - 1, lineHeight - 1, 8 } };
+  if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
+     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+  else {
+     tArea Areas[] = { { 0, 0, Setup.OSDWidth - 1, lineHeight - 1, 2 } };
+     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+     }
 }
 
 cSkinClassicDisplayMessage::~cSkinClassicDisplayMessage()
diff -ruN vdr-1.5.2/skinsttng.c vdr-1.5.3/skinsttng.c
--- vdr-1.5.2/skinsttng.c	2006-02-17 16:57:37.000000000 +0100
+++ vdr-1.5.3/skinsttng.c	2007-06-10 14:40:43.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: skinsttng.c 1.19 2006/02/17 15:57:37 kls Exp $
+ * $Id: skinsttng.c 1.20 2007/06/10 12:40:43 kls Exp $
  */
 
 // Star Trek: The Next Generation� is a registered trademark of Paramount Pictures
@@ -178,8 +178,13 @@
      int yt = (y0 + y1) / 2;
      int yb = (y6 + y7) / 2;
      osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + (Setup.ChannelInfoPos ? 0 : Setup.OSDHeight - y7));
-     tArea Areas[] = { { 0, 0, x7 - 1, y7 - 1, 4 } };
-     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+     tArea Areas[] = { { 0, 0, x7 - 1, y7 - 1, 8 } };
+     if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
+        osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+     else {
+        tArea Areas[] = { { 0, 0, x7 - 1, y7 - 1, 4 } };
+        osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+        }
      osd->DrawRectangle(x0, y0, x7 - 1, y7 - 1, Theme.Color(clrBackground));
      osd->DrawRectangle(x0, y0, x1 - 1, y1 - 1, clrTransparent);
      osd->DrawRectangle(x0, y6, x1 - 1, y7 - 1, clrTransparent);
@@ -211,8 +216,13 @@
      y0 = 0;
      y1 = lineHeight;
      osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + (Setup.ChannelInfoPos ? 0 : Setup.OSDHeight - y1));
-     tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 4 } };
-     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+     tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 8 } };
+     if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
+        osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+     else {
+        tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 4 } };
+        osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+        }
      osd->DrawRectangle(x0, y0, x7 - 1, y1 - 1, clrTransparent);
      osd->DrawEllipse  (x0, y0, x1 - 1, y1 - 1, frameColor, 7);
      osd->DrawRectangle(x1, y0, x2 - 1, y1 - 1, frameColor);
@@ -297,7 +307,7 @@
         const cFont *font = cFont::GetFont(fontSml);
         cString date = DayDateTime();
         int w = font->Width(date);
-        osd->DrawText(x4 - w - 2, y7 - font->Height(date), date, Theme.Color(clrChannelDate), frameColor, font);
+        osd->DrawText(x4 - w - 2, y7 - font->Height(), date, Theme.Color(clrChannelDate), frameColor, font, w);
         cDevice *Device = cDevice::PrimaryDevice();
         const tTrackId *Track = Device->GetTrack(Device->GetCurrentAudioTrack());
         if (!Track && *lastTrackId.description || Track && strcmp(lastTrackId.description, Track->description)) {
@@ -333,6 +343,7 @@
   tColor frameColor;
   int currentIndex;
   bool message;
+  cString lastDate;
   void SetScrollbar(void);
 public:
   cSkinSTTNGDisplayMenu(void);
@@ -378,17 +389,22 @@
   int yt = (y0 + y1) / 2;
   int yb = (y6 + y7) / 2;
   osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop);
-  tArea Areas[] = { { x0, y0, x7 - 1, y7 - 1, 4 } };
-  if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
+  tArea Areas[] = { { x0, y0, x7 - 1, y7 - 1, 8 } };
+  if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
      osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
   else {
-     tArea Areas[] = { { x0, y0, x7 - 1, y3 - 1, 2 },
-                       { x0, y3, x3 - 1, y4 - 1, 1 },
-                       { x3, y3, x4 - 1, y4 - 1, 2 },
-                       { x4, y3, x7 - 1, y4 - 1, 2 },
-                       { x0, y4, x7 - 1, y7 - 1, 4 }
-                     };
-     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+     tArea Areas[] = { { x0, y0, x7 - 1, y7 - 1, 4 } };
+     if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
+        osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+     else {
+        tArea Areas[] = { { x0, y0, x7 - 1, y3 - 1, 2 },
+                          { x0, y3, x3 - 1, y4 - 1, 1 },
+                          { x3, y3, x4 - 1, y4 - 1, 2 },
+                          { x4, y3, x7 - 1, y4 - 1, 2 },
+                          { x0, y4, x7 - 1, y7 - 1, 4 }
+                        };
+        osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+        }
      }
   osd->DrawRectangle(x0, y0, x7 - 1, y7 - 1, Theme.Color(clrBackground));
   osd->DrawRectangle(x0, y0, x1 - 1, y1 - 1, clrTransparent);
@@ -465,7 +481,7 @@
   const char *VDR = " VDR";
   int w = font->Width(VDR);
   osd->DrawText(x3 + 5, y0, Title, Theme.Color(clrMenuTitle), frameColor, font, x4 - w - x3 - 5);
-  osd->DrawText(x4 - w, y0, VDR, frameColor, clrBlack, font);
+  osd->DrawText(x4 - w, y0, VDR, frameColor, clrBlack, font, w, lineHeight);
 }
 
 void cSkinSTTNGDisplayMenu::SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue)
@@ -551,9 +567,10 @@
   ts.Set(osd, xl, y, x4 - xl, y4 - y, t, font, Theme.Color(clrMenuEventTime), Theme.Color(clrBackground));
   if (Event->Vps() && Event->Vps() != Event->StartTime()) {
      char *buffer;
-     asprintf(&buffer, " VPS: %s", *Event->GetVpsString());
+     asprintf(&buffer, " VPS: %s ", *Event->GetVpsString());
      const cFont *font = cFont::GetFont(fontSml);
-     osd->DrawText(x4 - font->Width(buffer), y, buffer, Theme.Color(clrMenuEventVps), frameColor, font);
+     int w = font->Width(buffer);
+     osd->DrawText(x4 - w, y, buffer, Theme.Color(clrMenuEventVps), frameColor, font, w);
      int yb = y + font->Height();
      osd->DrawRectangle(x5, y, x6 - 1, yb - 1, frameColor);
      osd->DrawEllipse  (x6, y, x7 - 1, yb - 1, frameColor, 5);
@@ -640,8 +657,12 @@
 {
   if (!message) {
      cString date = DayDateTime();
-     const cFont *font = cFont::GetFont(fontSml);
-     osd->DrawText(x4 - font->Width(date) - 2, y7 - font->Height(date), date, Theme.Color(clrMenuDate), frameColor, font);
+     if (!lastDate || strcmp(date, lastDate)) {
+        const cFont *font = cFont::GetFont(fontSml);
+        int w = font->Width(date);
+        osd->DrawText(x4 - w - 2, y7 - font->Height(), date, Theme.Color(clrMenuDate), frameColor, font, w);
+        lastDate = date;
+        }
      }
   osd->Flush();
 }
@@ -697,8 +718,13 @@
   int yt = (y0 + y1) / 2;
   int yb = (y6 + y7) / 2;
   osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - y7);
-  tArea Areas[] = { { 0, 0, x7 - 1, y7 - 1, 4 } };
-  osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+  tArea Areas[] = { { 0, 0, x7 - 1, y7 - 1, 8 } };
+  if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
+     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+  else {
+     tArea Areas[] = { { 0, 0, x7 - 1, y7 - 1, 4 } };
+     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+     }
   osd->DrawRectangle(x0, y0, x7 - 1, y7 - 1, ModeOnly ? clrTransparent : Theme.Color(clrBackground));
   if (!ModeOnly) {
      osd->DrawRectangle(x0, y0, x1 - 1, y1 - 1, clrTransparent);
@@ -760,14 +786,15 @@
 {
   const cFont *font = cFont::GetFont(fontSml);
   int w = font->Width(Current);
-  osd->DrawText(x3, y6, Current, Theme.Color(clrReplayCurrent), frameColor, font, lastCurrentWidth > w ? lastCurrentWidth : 0);
+  osd->DrawText(x3, y6, Current, Theme.Color(clrReplayCurrent), frameColor, font, lastCurrentWidth > w ? lastCurrentWidth : w);
   lastCurrentWidth = w;
 }
 
 void cSkinSTTNGDisplayReplay::SetTotal(const char *Total)
 {
   const cFont *font = cFont::GetFont(fontSml);
-  osd->DrawText(x4 - font->Width(Total) - 5, y6, Total, Theme.Color(clrReplayTotal), frameColor, font);
+  int w = font->Width(Total);
+  osd->DrawText(x4 - w - 5, y6, Total, Theme.Color(clrReplayTotal), frameColor, font, w);
 }
 
 void cSkinSTTNGDisplayReplay::SetJump(const char *Jump)
@@ -825,8 +852,13 @@
   y0 = 0;
   y1 = lineHeight;
   osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - y1);
-  tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 4 } };
-  osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+  tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 8 } };
+  if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
+     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+  else {
+     tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 4 } };
+     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+     }
   osd->DrawRectangle(x0, y0, x7 - 1, y1 - 1, clrTransparent);
   osd->DrawEllipse  (x0, y0, x1 - 1, y1 - 1, frameColor, 7);
   osd->DrawRectangle(x1, y0, x2 - 1, y1 - 1, frameColor);
@@ -935,17 +967,22 @@
   int yt = (y0 + y1) / 2;
   int yb = (y6 + y7) / 2;
   osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - y7);
-  tArea Areas[] = { { x0, y0, x7 - 1, y7 - 1, 4 } };
-  if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
+  tArea Areas[] = { { x0, y0, x7 - 1, y7 - 1, 8 } };
+  if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
      osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
   else {
-     tArea Areas[] = { { x0, y0, x7 - 1, y3 - 1, 2 },
-                       { x0, y3, x3 - 1, y4 - 1, 1 },
-                       { x3, y3, x4 - 1, y4 - 1, 2 },
-                       { x4, y3, x7 - 1, y4 - 1, 2 },
-                       { x0, y4, x7 - 1, y7 - 1, 4 }
-                     };
-     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+     tArea Areas[] = { { x0, y0, x7 - 1, y7 - 1, 4 } };
+     if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
+        osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+     else {
+        tArea Areas[] = { { x0, y0, x7 - 1, y3 - 1, 2 },
+                          { x0, y3, x3 - 1, y4 - 1, 1 },
+                          { x3, y3, x4 - 1, y4 - 1, 2 },
+                          { x4, y3, x7 - 1, y4 - 1, 2 },
+                          { x0, y4, x7 - 1, y7 - 1, 4 }
+                        };
+        osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+        }
      }
   osd->DrawRectangle(x0, y0, x7 - 1, y7 - 1, Theme.Color(clrBackground));
   osd->DrawRectangle(x0, y0, x1 - 1, y1 - 1, clrTransparent);
@@ -1057,8 +1094,13 @@
   y0 = 0;
   y1 = lineHeight;
   osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - y1);
-  tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 2 } };
-  osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+  tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 8 } };
+  if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
+     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+  else {
+     tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 2 } };
+     osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+     }
   osd->DrawRectangle(x0, y0, x7 - 1, y1 - 1, clrTransparent);
   osd->DrawEllipse  (x0, y0, x1 - 1, y1 - 1, frameColor, 7);
   osd->DrawRectangle(x1, y0, x2 - 1, y1 - 1, frameColor);
diff -ruN vdr-1.5.2/svdrp.c vdr-1.5.3/svdrp.c
--- vdr-1.5.2/svdrp.c	2006-08-12 11:09:55.000000000 +0200
+++ vdr-1.5.3/svdrp.c	2007-04-30 14:41:07.000000000 +0200
@@ -10,7 +10,7 @@
  * and interact with the Video Disk Recorder - or write a full featured
  * graphical interface that sits on top of an SVDRP connection.
  *
- * $Id: svdrp.c 1.100 2006/08/12 09:09:55 kls Exp $
+ * $Id: svdrp.c 1.101 2007/04/30 12:41:07 kls Exp $
  */
 
 #include "svdrp.h"
@@ -290,6 +290,9 @@
   "    format defined in vdr(5) for the 'epg.data' file.  A '.' on a line\n"
   "    by itself terminates the input and starts processing of the data (all\n"
   "    entered data is buffered until the terminating '.' is seen).",
+  "REMO [ on | off ]\n"
+  "    Turns the remote control on or off. Without a parameter, the current\n"
+  "    status of the remote control is reported.",
   "SCAN\n"
   "    Forces an EPG scan. If this is a single DVB device system, the scan\n"
   "    will be done on the primary device unless it is currently recording.",
@@ -1406,6 +1409,24 @@
      DELETENULL(PUTEhandler);
 }
 
+void cSVDRP::CmdREMO(const char *Option)
+{
+  if (*Option) {
+     if (!strcasecmp(Option, "ON")) {
+        cRemote::SetEnabled(true);
+        Reply(250, "Remote control enabled");
+        }
+     else if (!strcasecmp(Option, "OFF")) {
+        cRemote::SetEnabled(false);
+        Reply(250, "Remote control disabled");
+        }
+     else
+        Reply(501, "Invalid Option \"%s\"", Option);
+     }
+  else
+     Reply(250, "Remote control is %s", cRemote::Enabled() ? "enabled" : "disabled");
+}
+
 void cSVDRP::CmdSCAN(const char *Option)
 {
   EITScanner.ForceScan();
@@ -1526,6 +1547,7 @@
   else if (CMD("PLAY"))  CmdPLAY(s);
   else if (CMD("PLUG"))  CmdPLUG(s);
   else if (CMD("PUTE"))  CmdPUTE(s);
+  else if (CMD("REMO"))  CmdREMO(s);
   else if (CMD("SCAN"))  CmdSCAN(s);
   else if (CMD("STAT"))  CmdSTAT(s);
   else if (CMD("UPDT"))  CmdUPDT(s);
diff -ruN vdr-1.5.2/svdrp.h vdr-1.5.3/svdrp.h
--- vdr-1.5.2/svdrp.h	2006-08-06 10:51:09.000000000 +0200
+++ vdr-1.5.3/svdrp.h	2007-04-30 14:28:28.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: svdrp.h 1.28 2006/08/06 08:51:09 kls Exp $
+ * $Id: svdrp.h 1.29 2007/04/30 12:28:28 kls Exp $
  */
 
 #ifndef __SVDRP_H
@@ -78,6 +78,7 @@
   void CmdPLAY(const char *Option);
   void CmdPLUG(const char *Option);
   void CmdPUTE(const char *Option);
+  void CmdREMO(const char *Option);
   void CmdSCAN(const char *Option);
   void CmdSTAT(const char *Option);
   void CmdUPDT(const char *Option);
diff -ruN vdr-1.5.2/timers.c vdr-1.5.3/timers.c
--- vdr-1.5.2/timers.c	2006-09-15 16:15:53.000000000 +0200
+++ vdr-1.5.3/timers.c	2007-06-03 15:48:57.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: timers.c 1.65 2006/09/15 14:15:53 kls Exp $
+ * $Id: timers.c 1.66 2007/06/03 13:48:57 kls Exp $
  */
 
 #include "timers.h"
@@ -136,7 +136,7 @@
 {
   char *buffer;
   strreplace(file, ':', '|');
-  asprintf(&buffer, "%u:%s:%s:%04d:%04d:%d:%d:%s:%s\n", flags, UseChannelID ? *Channel()->GetChannelID().ToString() : *itoa(Channel()->Number()), *PrintDay(day, weekdays), start, stop, priority, lifetime, file, aux ? aux : "");
+  asprintf(&buffer, "%u:%s:%s:%04d:%04d:%d:%d:%s:%s\n", flags, UseChannelID ? *Channel()->GetChannelID().ToString() : *itoa(Channel()->Number()), *PrintDay(day, weekdays, true), start, stop, priority, lifetime, file, aux ? aux : "");
   strreplace(file, '|', ':');
   return cString(buffer, true);
 }
@@ -212,17 +212,26 @@
   return true;
 }
 
-cString cTimer::PrintDay(time_t Day, int WeekDays)
+cString cTimer::PrintDay(time_t Day, int WeekDays, bool SingleByteChars)
 {
-#define DAYBUFFERSIZE 32
+#define DAYBUFFERSIZE 64
   char buffer[DAYBUFFERSIZE];
   char *b = buffer;
   if (WeekDays) {
-     const char *w = tr("MTWTFSS");
+     const char *w = "MTWTFSS";
+     if (!SingleByteChars)
+        w = tr(w);
      while (*w) {
-           *b++ = (WeekDays & 1) ? *w : '-';
+           int sl = Utf8CharLen(w);
+           if (WeekDays & 1) {
+              for (int i = 0; i < sl; i++)
+                  b[i] = w[i];
+              b += sl;
+              }
+           else
+              *b++ = '-';
            WeekDays >>= 1;
-           w++;
+           w += sl;
            }
      if (Day)
         *b++ = '@';
@@ -239,7 +248,7 @@
 cString cTimer::PrintFirstDay(void) const
 {
   if (weekdays) {
-     cString s = PrintDay(day, weekdays);
+     cString s = PrintDay(day, weekdays, true);
      if (strlen(s) == 18)
         return *s + 8;
      }
diff -ruN vdr-1.5.2/timers.h vdr-1.5.3/timers.h
--- vdr-1.5.2/timers.h	2006-09-04 19:07:39.000000000 +0200
+++ vdr-1.5.3/timers.h	2007-06-03 15:24:58.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: timers.h 1.29 2006/09/04 17:07:39 kls Exp $
+ * $Id: timers.h 1.30 2007/06/03 13:24:58 kls Exp $
  */
 
 #ifndef __TIMERS_H
@@ -94,7 +94,7 @@
   cString PrintFirstDay(void) const;
   static int TimeToInt(int t);
   static bool ParseDay(const char *s, time_t &Day, int &WeekDays);
-  static cString PrintDay(time_t Day, int WeekDays);
+  static cString PrintDay(time_t Day, int WeekDays, bool SingleByteChars);
   };
 
 class cTimers : public cConfig<cTimer> {
diff -ruN vdr-1.5.2/tools.c vdr-1.5.3/tools.c
--- vdr-1.5.2/tools.c	2007-01-05 11:44:57.000000000 +0100
+++ vdr-1.5.3/tools.c	2007-06-09 16:21:21.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: tools.c 1.122 2007/01/05 10:44:57 kls Exp $
+ * $Id: tools.c 1.123 2007/06/09 14:21:21 kls Exp $
  */
 
 #include "tools.h"
@@ -570,6 +570,221 @@
   return Now() - begin;
 }
 
+// --- UTF-8 support ---------------------------------------------------------
+
+static uint SystemToUtf8[128] = { 0 };
+
+int Utf8CharLen(const char *s)
+{
+  if (cCharSetConv::SystemCharacterTable())
+     return 1;
+#define MT(s, m, v) ((*(s) & (m)) == (v)) // Mask Test
+  if (MT(s, 0xE0, 0xC0) && MT(s + 1, 0xC0, 0x80))
+     return 2;
+  if (MT(s, 0xF0, 0xE0) && MT(s + 1, 0xC0, 0x80) && MT(s + 2, 0xC0, 0x80))
+     return 3;
+  if (MT(s, 0xF8, 0xF0) && MT(s + 1, 0xC0, 0x80) && MT(s + 2, 0xC0, 0x80) && MT(s + 3, 0xC0, 0x80))
+     return 4;
+  return 1;
+}
+
+uint Utf8CharGet(const char *s, int Length)
+{
+  if (cCharSetConv::SystemCharacterTable())
+     return (uchar)*s < 128 ? *s : SystemToUtf8[(uchar)*s - 128];
+  if (!Length)
+     Length = Utf8CharLen(s);
+  switch (Length) {
+    case 2: return ((*s & 0x1F) << 6) |  (*(s + 1) & 0x3F);
+    case 3: return ((*s & 0x0F) << 4) | ((*(s + 1) & 0x3F) << 6) |  (*(s + 2) & 0x3F);
+    case 4: return ((*s & 0x07) << 2) | ((*(s + 1) & 0x3F) << 4) | ((*(s + 2) & 0x3F) << 6) | (*(s + 3) & 0x3F);
+    }
+  return *s;
+}
+
+int Utf8CharSet(uint c, char *s)
+{
+  if (c < 0x80 || cCharSetConv::SystemCharacterTable()) {
+     if (s)
+        *s = c;
+     return 1;
+     }
+  if (c < 0x800) {
+     if (s) {
+        *s++ = ((c >> 6) & 0x1F) | 0xC0;
+        *s   = (c & 0x3F) | 0x80;
+        }
+     return 2;
+     }
+  if (c < 0x10000) {
+     if (s) {
+        *s++ = ((c >> 12) & 0x0F) | 0xE0;
+        *s++ = ((c >>  6) & 0x3F) | 0x80;
+        *s   = (c & 0x3F) | 0x80;
+        }
+     return 3;
+     }
+  if (c < 0x110000) {
+     if (s) {
+        *s++ = ((c >> 18) & 0x07) | 0xF0;
+        *s++ = ((c >> 12) & 0x3F) | 0x80;
+        *s++ = ((c >>  6) & 0x3F) | 0x80;
+        *s   = (c & 0x3F) | 0x80;
+        }
+     return 4;
+     }
+  return 0; // can't convert to UTF-8
+}
+
+int Utf8SymChars(const char *s, int Symbols)
+{
+  if (cCharSetConv::SystemCharacterTable())
+     return Symbols;
+  int n = 0;
+  while (*s && Symbols--) {
+        int sl = Utf8CharLen(s);
+        s += sl;
+        n += sl;
+        }
+  return n;
+}
+
+int Utf8ToArray(const char *s, uint *a, int Size)
+{
+  int n = 0;
+  while (*s && --Size > 0) {
+        if (cCharSetConv::SystemCharacterTable())
+           *a++ = *s++;
+        else {
+           int sl = Utf8CharLen(s);
+           *a++ = Utf8CharGet(s, sl);
+           s += sl;
+           }
+        n++;
+        }
+  if (Size > 0)
+     *a = 0;
+  return n;
+}
+
+int Utf8FromArray(const uint *a, char *s, int Size, int Max)
+{
+  int NumChars = 0;
+  int NumSyms = 0;
+  while (*a && NumChars < Size) {
+        if (Max >= 0 && NumSyms++ >= Max)
+           break;
+        if (cCharSetConv::SystemCharacterTable()) {
+           *s++ = *a++;
+           NumChars++;
+           }
+        else {
+           int sl = Utf8CharSet(*a);
+           if (NumChars + sl <= Size) {
+              Utf8CharSet(*a, s);
+              a++;
+              s += sl;
+              NumChars += sl;
+              }
+           else
+              break;
+           }
+        }
+  if (NumChars < Size)
+     *s = 0;
+  return NumChars;
+}
+
+// --- cCharSetConv ----------------------------------------------------------
+
+char *cCharSetConv::systemCharacterTable = NULL;
+
+cCharSetConv::cCharSetConv(const char *FromCode, const char *ToCode)
+{
+  if (!FromCode)
+     FromCode = systemCharacterTable;
+  if (!ToCode)
+     ToCode = "UTF-8";
+  cd = (FromCode && ToCode) ? iconv_open(ToCode, FromCode) : (iconv_t)-1;
+  result = NULL;
+  length = 0;
+}
+
+cCharSetConv::~cCharSetConv()
+{
+  free(result);
+  iconv_close(cd);
+}
+
+void cCharSetConv::SetSystemCharacterTable(const char *CharacterTable)
+{
+  free(systemCharacterTable);
+  systemCharacterTable = NULL;
+  if (!strcasestr(CharacterTable, "UTF")) {
+     // Set up a map for the character values 128...255:
+     char buf[129];
+     for (int i = 0; i < 128; i++)
+         buf[i] = i + 128;
+     buf[129] = 0;
+     cCharSetConv csc(CharacterTable);
+     const char *s = csc.Convert(buf);
+     int i = 0;
+     while (*s) {
+           int sl = Utf8CharLen(s);
+           SystemToUtf8[i] = Utf8CharGet(s, sl);
+           s += sl;
+           i++;
+           }
+     systemCharacterTable = strdup(CharacterTable);
+     }
+}
+
+const char *cCharSetConv::Convert(const char *From, char *To, size_t ToLength)
+{
+  if (cd != (iconv_t)-1) {
+     char *FromPtr = (char *)From;
+     size_t FromLength = strlen(From);
+     char *ToPtr = To;
+     if (!ToPtr) {
+        length = max(length, FromLength * 2); // some reserve to avoid later reallocations
+        result = (char *)realloc(result, length);
+        ToPtr = result;
+        ToLength = length;
+        }
+     else if (!ToLength)
+        return From; // can't convert into a zero sized buffer
+     ToLength--; // save space for terminating 0
+     char *Converted = ToPtr;
+     while (FromLength > 0) {
+           if (iconv(cd, &FromPtr, &FromLength, &ToPtr, &ToLength) == size_t(-1)) {
+              if (errno == E2BIG || errno == EILSEQ && ToLength < 1) {
+                 if (To)
+                    break; // caller provided a fixed size buffer, but it was too small
+                 // The result buffer is too small, so increase it:
+                 size_t d = ToPtr - result;
+                 size_t r = length / 2;
+                 length += r;
+                 result = (char *)realloc(result, length);
+                 ToLength += r;
+                 ToPtr = result + d;
+                 }
+              if (errno == EILSEQ) {
+                 // A character can't be converted, so mark it with '?' and proceed:
+                 FromPtr++;
+                 FromLength--;
+                 *ToPtr++ = '?';
+                 ToLength--;
+                 }
+              else if (errno != E2BIG)
+                 return From; // unknown error, return original string
+              }
+           }
+     *ToPtr = 0;
+     return Converted;
+     }
+  return From;
+}
+
 // --- cString ---------------------------------------------------------------
 
 cString::cString(const char *S, bool TakePointer)
@@ -607,12 +822,12 @@
 
 cString WeekDayName(int WeekDay)
 {
-  char buffer[4];
+  char buffer[16];
   WeekDay = WeekDay == 0 ? 6 : WeekDay - 1; // we start with Monday==0!
   if (0 <= WeekDay && WeekDay <= 6) {
      const char *day = tr("MonTueWedThuFriSatSun");
-     day += WeekDay * 3;
-     strn0cpy(buffer, day, sizeof(buffer));
+     day += Utf8SymChars(day, WeekDay * 3);
+     strn0cpy(buffer, day, min(Utf8SymChars(day, 3) + 1, int(sizeof(buffer))));
      return buffer;
      }
   else
@@ -890,6 +1105,47 @@
   return directory && readdir_r(directory, &u.d, &result) == 0 ? result : NULL;
 }
 
+// --- cFileNameList ---------------------------------------------------------
+
+cFileNameList::cFileNameList(const char *Directory)
+{
+  Load(Directory);
+}
+
+cFileNameList::~cFileNameList()
+{
+  for (int i = 0; i < Size(); i++)
+      free(At(i));
+}
+
+bool cFileNameList::Load(const char *Directory)
+{
+  if (Directory) {
+     cReadDir d(Directory);
+     struct dirent *e;
+     if (d.Ok()) {
+        while ((e = d.Next()) != NULL) {
+              if (strcmp(e->d_name, ".") && strcmp(e->d_name, ".."))
+                 Append(strdup(e->d_name));
+              }
+        Sort(CompareStrings);
+        return true;
+        }
+     else
+        LOG_ERROR_STR(Directory);
+     }
+  return false;
+}
+
+int cFileNameList::Find(const char *FileName)
+{
+  for (int i = 0; i < Size(); i++) {
+      if (!strcmp(FileName, At(i)))
+         return i;
+      }
+  return -1;
+}
+
 // --- cFile -----------------------------------------------------------------
 
 bool cFile::files[FD_SETSIZE] = { false };
diff -ruN vdr-1.5.2/tools.h vdr-1.5.3/tools.h
--- vdr-1.5.2/tools.h	2007-01-05 11:45:11.000000000 +0100
+++ vdr-1.5.3/tools.h	2007-06-10 10:46:23.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: tools.h 1.97 2007/01/05 10:45:11 kls Exp $
+ * $Id: tools.h 1.98 2007/06/10 08:46:23 kls Exp $
  */
 
 #ifndef __TOOLS_H
@@ -13,10 +13,12 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <iconv.h>
 #include <poll.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <syslog.h>
 #include <sys/stat.h>
@@ -72,6 +74,73 @@
   ((s *)p)->v = v;
 }
 
+// When handling strings that might contain UTF-8 characters, it may be necessary
+// to process a "symbol" that consists of several actual character bytes. The
+// following functions allow transparently accessing a "char *" string without
+// having to worry about what character set is actually used.
+
+int Utf8CharLen(const char *s);
+    ///< Returns the number of character bytes at the beginning of the given
+    ///< string that form a UTF-8 symbol.
+uint Utf8CharGet(const char *s, int Length = 0);
+    ///< Returns the UTF-8 symbol at the beginning of the given string.
+    ///< Length can be given from a previous call to Utf8CharLen() to avoid calculating
+    ///< it again. If no Length is given, Utf8CharLen() will be called.
+int Utf8CharSet(uint c, char *s = NULL);
+    ///< Converts the given UTF-8 symbol to a sequence of character bytes and copies
+    ///< them to the given string. Returns the number of bytes written. If no string
+    ///< is given, only the number of bytes is returned and nothing is copied.
+int Utf8SymChars(const char *s, int Symbols);
+    ///< Returns the number of character bytes at the beginning of the given
+    ///< string that form at most the given number of UTF-8 Symbols.
+int Utf8ToArray(const char *s, uint *a, int Size);
+    ///< Converts the given character bytes (including the terminating 0) into an
+    ///< array of UTF-8 symbols of the given Size. Returns the number of symbols
+    ///< in the array (without the terminating 0).
+int Utf8FromArray(const uint *a, char *s, int Size, int Max = -1);
+    ///< Converts the given array of UTF-8 symbols (including the terminating 0)
+    ///< into a sequence of character bytes of at most Size length. Returns the
+    ///< number of character bytes written (without the terminating 0).
+    ///< If Max is given, only that many symbols will be converted.
+    ///< The resulting string is always zero-terminated if Size is big enough.
+
+// When allocating buffer space, make sure we reserve enough space to hold
+// a string in UTF-8 representation:
+
+#define Utf8BufSize(s) ((s) * 4)
+
+// The following macros automatically use the correct versions of the character
+// class functions:
+
+#define Utf8to(conv, c) (cCharSetConv::SystemCharacterTable() ? to##conv(c) : tow##conv(c))
+#define Utf8is(ccls, c) (cCharSetConv::SystemCharacterTable() ? is##ccls(c) : isw##ccls(c))
+
+class cCharSetConv {
+private:
+  iconv_t cd;
+  char *result;
+  size_t length;
+  static char *systemCharacterTable;
+public:
+  cCharSetConv(const char *FromCode = NULL, const char *ToCode = NULL);
+     ///< Sets up a character set converter to convert from FromCode to ToCode.
+     ///< If FromCode is NULL, the previously set systemCharacterTable is used.
+     ///< If ToCode is NULL, "UTF-8" is used.
+  ~cCharSetConv();
+  const char *Convert(const char *From, char *To = NULL, size_t ToLength = 0);
+     ///< Converts the given Text from FromCode to ToCode (as set in the cosntructor).
+     ///< If To is given, it is used to copy at most ToLength bytes of the result
+     ///< (including the terminating 0) into that buffer. If To is not given,
+     ///< the result is copied into a dynamically allocated buffer and is valid as
+     ///< long as this object lives, or until the next call to Convert(). The
+     ///< return value always points to the result if the conversion was successful
+     ///< (even if a fixed size To buffer was given and the result didn't fit into
+     ///< it). If the string could not be converted, the result points to the
+     ///< original From string.
+  static const char *SystemCharacterTable(void) { return systemCharacterTable; }
+  static void SetSystemCharacterTable(const char *CharacterTable);
+  };
+
 class cString {
 private:
   char *s;
@@ -320,6 +389,61 @@
   T *Next(const T *object) const { return (T *)object->cListObject::Next(); } // avoid ambiguities in case of a "list of lists"
   };
 
+template<class T> class cVector {
+private:
+  mutable int allocated;
+  mutable int size;
+  mutable T *data;
+  void Realloc(int NewAllocated) const { data = (T *)realloc(data, (allocated = NewAllocated) * sizeof(T)); }
+public:
+  cVector(int Allocated = 10)
+  {
+    allocated = 0;
+    size = 0;
+    data = NULL;
+    Realloc(Allocated);
+  }
+  virtual ~cVector() { free(data); }
+  T& At(int Index) const
+  {
+    if (Index >= size)
+       Realloc(size = Index + 1);
+    return data[Index];
+  }
+  const T& operator[](int Index) const
+  {
+    return At(Index);
+  }
+  T& operator[](int Index)
+  {
+    return At(Index);
+  }
+  int Size(void) const { return size; }
+  virtual void Append(T Data)
+  {
+    if (size >= allocated)
+       Realloc(allocated * 4 / 2); // increase size by 50%
+    data[size++] = Data;
+  }
+  void Sort(__compar_fn_t Compare)
+  {
+    qsort(data, size, sizeof(T), Compare);
+  }
+  };
+
+inline int CompareStrings(const void *a, const void *b)
+{
+  return strcmp(*(const char **)a, *(const char **)b);
+}
+
+class cFileNameList : public cVector<char *> {
+public:
+  cFileNameList(const char *Directory = NULL);
+  virtual ~cFileNameList();
+  bool Load(const char *Directory);
+  int Find(const char *FileName);
+  };
+
 class cHashObject : public cListObject {
   friend class cHashBase;
 private:
diff -ruN vdr-1.5.2/vdr.5 vdr-1.5.3/vdr.5
--- vdr-1.5.2/vdr.5	2007-01-07 15:04:12.000000000 +0100
+++ vdr-1.5.3/vdr.5	2007-06-03 15:21:34.000000000 +0200
@@ -8,7 +8,7 @@
 .\" License as specified in the file COPYING that comes with the
 .\" vdr distribution.
 .\"
-.\" $Id: vdr.5 1.61 2007/01/07 14:04:12 kls Exp $
+.\" $Id: vdr.5 1.62 2007/06/03 13:21:34 kls Exp $
 .\"
 .TH vdr 5 "07 Jan 2007" "1.4.5" "Video Disk Recorder Files"
 .SH NAME
@@ -249,9 +249,14 @@
 .B MTWTF\-\-
 
 will define a timer that records on Monday through Friday and does not record
-on weekends. The same result could be achieved with \fBABCDE\-\-\fR (this is
-used to allow setting the days with language specific characters).
+on weekends.
 Note that only letters may be used here, no digits.
+For compatibility with timers created with earlier versions of VDR,
+the same result could be achieved with \fBABCDE\-\-\fR (which was
+used to allow setting the days with language specific characters).
+Since version 1.5.3 VDR can use UTF-8 characters to present data to
+the user, but the weekday encoding in the \fItimers.conf\fR file
+always uses single byte characters.
 
 The day definition of a `repeating' timer may be followed by the date when that
 timer shall hit for the first time. The format for this is \fB@YYYY\-MM\-DD\fR,
diff -ruN vdr-1.5.2/vdr.c vdr-1.5.3/vdr.c
--- vdr-1.5.2/vdr.c	2007-04-22 15:28:32.000000000 +0200
+++ vdr-1.5.3/vdr.c	2007-06-09 14:33:53.000000000 +0200
@@ -22,7 +22,7 @@
  *
  * The project's page is at http://www.cadsoft.de/vdr
  *
- * $Id: vdr.c 1.287 2007/04/22 13:28:32 kls Exp $
+ * $Id: vdr.c 1.291 2007/06/09 12:33:53 kls Exp $
  */
 
 #include <getopt.h>
@@ -493,13 +493,16 @@
 
   // Set the system character table:
 
-  char *LangEnv = getenv("LANG");
+  char *LangEnv = setlocale(LC_CTYPE, "");
+  if (!LangEnv)
+     LangEnv = getenv("LANG"); // last resort in case locale stuff isn't installed
   if (LangEnv) {
      char *CodeSet = strchr(LangEnv, '.');
      if (CodeSet) {
         CodeSet++; // skip the dot
         bool known = SI::SetSystemCharacterTable(CodeSet);
         isyslog("codeset is '%s' - %s", CodeSet, known ? "known" : "unknown");
+        cCharSetConv::SetSystemCharacterTable(CodeSet);
         }
      }
 
@@ -542,8 +545,6 @@
         ))
      EXIT(2);
 
-  cFont::SetCode(I18nCharSets()[Setup.OSDLanguage]);
-
   // Recordings:
 
   Recordings.Update();
@@ -952,7 +953,7 @@
           case kChanDn:
                if (!Interact)
                   Menu = new cDisplayChannel(NORMALKEY(key));
-               else if (cDisplayChannel::IsOpen()) {
+               else if (cDisplayChannel::IsOpen() || cControl::Control()) {
                   Interact->ProcessKey(key);
                   continue;
                   }
@@ -1203,6 +1204,13 @@
 
 Exit:
 
+  // Reset all signal handlers to default before Interface gets deleted:
+  signal(SIGHUP,  SIG_DFL);
+  signal(SIGINT,  SIG_DFL);
+  signal(SIGTERM, SIG_DFL);
+  signal(SIGPIPE, SIG_DFL);
+  signal(SIGALRM, SIG_DFL);
+
   PluginManager.StopPlugins();
   cRecordControls::Shutdown();
   cCutter::Stop();
