diff -ruN vdr-1.5.3/CONTRIBUTORS vdr-1.5.4/CONTRIBUTORS
--- vdr-1.5.3/CONTRIBUTORS	2007-06-10 10:26:07.000000000 +0200
+++ vdr-1.5.4/CONTRIBUTORS	2007-06-17 16:02:02.000000000 +0200
@@ -886,6 +886,7 @@
  for removing the LOCK_THREAD from the LIRC thread
  for making the Makefile patch friendlier
  for a patch that was used for implementing setting the user id
+ for pointing out that the canonical spelling of codesets is with '-'
 
 Thomas Koch <tom@harhar.net>
  for his support in keeping the Premiere World channels up to date in 'channels.conf'
@@ -1012,6 +1013,7 @@
  for adding --remove-destination to the 'cp' command for binaries in the Makefiles of
  the plugins
  for increasing the maximum number of DVB devices to 8
+ for suggesting to change the parameter "OSD font" to "Default font" in "Setup/OSD"
 
 Ralf Klueber <ralf.klueber@vodafone.com>
  for reporting a bug in cutting a recording if there is only a single editing mark
@@ -1495,6 +1497,7 @@
  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
+ for fixing handling detached processes in SystemExec()
 
 Sven Kreiensen <svenk@kammer.uni-hannover.de>
  for his help in keeping 'channels.conf.terr' up to date
@@ -1739,6 +1742,7 @@
  for suggesting to extend the version number reported with the '-V' option to also
  show the current APIVERSION
  for fixing i18n characters for the Hungarian texts
+ for implementing using nl_langinfo(CODESET) to determine the local codeset to use
 
 David Woodhouse <dwmw2@infradead.org>
  for his help in replacing the get/put_unaligned() macros from asm/unaligned.h with
@@ -1841,6 +1845,7 @@
  from the "Schedule" menu in case it starts withing the next two minutes
  for reporting a problem with a format string in recording.c on 64bit systems
  for reporting a problem with the device selection in case of timer conflicts
+ for a patch that fixed part of a crash in i18n character set conversion
 
 Thiemo Gehrke <tgehrke@reel-multimedia.com>
  for suggesting to add a setup option to turn off the automatic timeout of the
@@ -1921,6 +1926,7 @@
  to be drawn with a transparent background
  for reporting that the "'1' for encrypted radio channels" part in the description
  of the VPID in vdr.5 is obsolete
+ for a patch that was used to implement storing the channel name in info.vdr
 
 Daniel Karsubka <dkar@gmx.de>
  for suggesting to write the epg.data file when VDR exits
@@ -1947,6 +1953,7 @@
  for reporting that the log message "deleting plugin: ..." is irritating when
  calling "vdr --help"
  for fixing cDevice::ToggleMute()
+ for suggestions that led to implementing cOsd::SetOsdPosition() etc.
 
 Pekka Mauno <pekka.mauno@iki.fi>
  for fixing cSchedule::GetFollowingEvent() in case there is currently no present
@@ -2021,6 +2028,7 @@
  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
+ for code and hints on how to use 'fontconfig' to determine which fonts to use
 
 Antti Hartikainen <ami+vdr@ah.fi>
  for updating 'S13E' in 'sources.conf'
@@ -2087,3 +2095,7 @@
 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
+ for a patch that fixed part of a crash in i18n character set conversion
+
+Jose Alberto Reguero <jareguero@telefonica.net>
+ for a patch that fixed part of a crash in i18n character set conversion
diff -ruN vdr-1.5.3/HISTORY vdr-1.5.4/HISTORY
--- vdr-1.5.3/HISTORY	2007-06-10 15:37:03.000000000 +0200
+++ vdr-1.5.4/HISTORY	2007-06-17 16:00:00.000000000 +0200
@@ -5229,3 +5229,34 @@
 - 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.
+
+2007-06-17: Version 1.5.4
+
+- Increased APIVERSION (forgot to do that in 1.5.2 and 1.5.3).
+- Fixed a crash in i18n character set conversion (thanks to Alexander Riedel,
+  Jose Alberto Reguero and Christian Wieninger for patches that cured part of
+  the problem).
+- Adjusted the 'skincurses' plugin to UTF-8 handling.
+- Using nl_langinfo(CODESET) to determine the local codeset to use (thanks to
+  Thomas Günther). The codeset names in 'libsi/si.c' have been changed to the
+  canonical spelling with '-' (thanks to Ludwig Nussel for pointing this out).
+- Modified handling invalid characters in VFAT mode.
+- Replaced strn0cpy() with Utf8Strn0Cpy() where necessary.
+- Now using 'fontconfig' to determine which fonts to use (thanks to Anssi Hannula
+  for code and hints on how to do this).
+- If no fonts are installed, VDR now uses a dummy font that doesn't actually draw
+  any text, and logs an error message.
+- The new function cFont::CreateFont() can be used by plugins to create and use
+  fonts of their own, independent of VDR's standard fonts.
+- Updated the Finnish OSD texts (thanks to Rolf Ahrenberg).
+- Changed the parameter "OSD font" to "Default font" in "Setup/OSD" (suggested
+  by Rolf Ahrenberg).
+- Fixed handling detached processes in SystemExec() (thanks to Udo Richter).
+- The info.vdr file now also stores the name of the channel, and the new function
+  cRecordingInfo::ChannelName() returns this information if available (based on
+  a patch from Alexander Hans).
+- The new function cOsd::SetOsdPosition() can be used to dynamically change the
+  position and size of the OSD (based on a request from Christoph Haubrich).
+  Plugins that implement skins should no longer use Setup.OSDWidth etc. directly,
+  but should rather use cOsd::OsdWidth() etc. instead.
+  Currently a change to the OSD position will only apply to newly opened OSDs.
diff -ruN vdr-1.5.3/INSTALL vdr-1.5.4/INSTALL
--- vdr-1.5.3/INSTALL	2007-06-10 15:13:09.000000000 +0200
+++ vdr-1.5.4/INSTALL	2007-06-16 15:55:28.000000000 +0200
@@ -22,6 +22,7 @@
 You will also need to install the following libraries, as well as their
 "devel" packages to get the necessary header files for compiling VDR:
 
+  fontconfig
   freetype2
   libcap
   libjpeg
@@ -29,9 +30,6 @@
 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
 named 'vdr', which can be run after the DVB driver has been
diff -ruN vdr-1.5.3/MANUAL vdr-1.5.4/MANUAL
--- vdr-1.5.3/MANUAL	2007-06-10 15:02:43.000000000 +0200
+++ vdr-1.5.4/MANUAL	2007-06-17 14:33:53.000000000 +0200
@@ -509,10 +509,10 @@
                          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.
+  Default font = Sans Serif:Bold
+  Small font = Sans Serif
+  Fixed font = Courier:Bold
+                         The names of the various fonts to use.
 
   OSD font size = 22
   Small font size = 18
diff -ruN vdr-1.5.3/Makefile vdr-1.5.4/Makefile
--- vdr-1.5.3/Makefile	2007-05-28 13:22:42.000000000 +0200
+++ vdr-1.5.4/Makefile	2007-06-16 12:48:59.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.100 2007/05/28 11:22:42 kls Exp $
+# $Id: Makefile 1.101 2007/06/16 10:48:59 kls Exp $
 
 .DELETE_ON_ERROR:
 
@@ -17,7 +17,7 @@
 LSIDIR   = ./libsi
 MANDIR   = /usr/local/man
 BINDIR   = /usr/local/bin
-LIBS     = -ljpeg -lpthread -ldl -lcap -lfreetype
+LIBS     = -ljpeg -lpthread -ldl -lcap -lfreetype -lfontconfig
 INCLUDES = -I/usr/include/freetype2
 
 PLUGINDIR= ./PLUGINS
diff -ruN vdr-1.5.3/PLUGINS/src/skincurses/HISTORY vdr-1.5.4/PLUGINS/src/skincurses/HISTORY
--- vdr-1.5.3/PLUGINS/src/skincurses/HISTORY	2006-09-10 16:25:11.000000000 +0200
+++ vdr-1.5.4/PLUGINS/src/skincurses/HISTORY	2007-06-15 14:24:06.000000000 +0200
@@ -39,3 +39,7 @@
 2006-09-10: Version 0.0.8
 
 - The size of the OSD is now adjusted to the size of the console window.
+
+2007-06-15: Version 0.1.0
+
+- Implemented UTF-8 handling.
diff -ruN vdr-1.5.3/PLUGINS/src/skincurses/Makefile vdr-1.5.4/PLUGINS/src/skincurses/Makefile
--- vdr-1.5.3/PLUGINS/src/skincurses/Makefile	2006-09-09 14:38:35.000000000 +0200
+++ vdr-1.5.4/PLUGINS/src/skincurses/Makefile	2007-06-10 18:19:08.000000000 +0200
@@ -1,7 +1,7 @@
 #
 # Makefile for a Video Disk Recorder plugin
 #
-# $Id: Makefile 1.7 2006/09/09 12:38:35 kls Exp $
+# $Id: Makefile 1.8 2007/06/10 16:19:08 kls Exp $
 
 # The official name of this plugin.
 # This name will be used in the '-P...' option of VDR to load the plugin.
@@ -66,7 +66,7 @@
 all: libvdr-$(PLUGIN).so
 
 libvdr-$(PLUGIN).so: $(OBJS)
-	$(CXX) $(CXXFLAGS) -shared $(OBJS) -lncurses -o $@
+	$(CXX) $(CXXFLAGS) -shared $(OBJS) -lncursesw -o $@
 	@cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION)
 
 dist: clean
diff -ruN vdr-1.5.3/PLUGINS/src/skincurses/skincurses.c vdr-1.5.4/PLUGINS/src/skincurses/skincurses.c
--- vdr-1.5.3/PLUGINS/src/skincurses/skincurses.c	2006-09-10 16:23:55.000000000 +0200
+++ vdr-1.5.4/PLUGINS/src/skincurses/skincurses.c	2007-06-16 11:05:04.000000000 +0200
@@ -3,7 +3,7 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: skincurses.c 1.11 2006/09/10 14:23:55 kls Exp $
+ * $Id: skincurses.c 1.13 2007/06/16 09:05:04 kls Exp $
  */
 
 #include <ncurses.h>
@@ -11,7 +11,7 @@
 #include <vdr/plugin.h>
 #include <vdr/skins.h>
 
-static const char *VERSION        = "0.0.8";
+static const char *VERSION        = "0.1.0";
 static const char *DESCRIPTION    = "A text only skin";
 static const char *MAINMENUENTRY  = NULL;
 
@@ -19,12 +19,10 @@
 
 class cCursesFont : public cFont {
 public:
-  cCursesFont(void): cFont(NULL) {}
-  virtual int Width(unsigned char c) const { return 1; }
-  virtual int Width(const char *s) const { return s ? strlen(s) : 0; }
-  virtual int Height(unsigned char c) const { return 1; }
-  virtual int Height(const char *s) const { return 1; }
+  virtual int Width(uint c) const { return 1; }
+  virtual int Width(const char *s) const { return s ? Utf8StrLen(s) : 0; }
   virtual int Height(void) const { return 1; }
+  virtual void DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const {}
   };
 
 static const cCursesFont Font;
@@ -135,6 +133,8 @@
 
 void cCursesOsd::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
 {
+  if (!s)
+     return;
   int w = Font->Width(s);
   int h = Font->Height();
   if (Width || Height) {
@@ -253,7 +253,7 @@
 {
   if (!message) {
      cString date = DayDateTime();
-     osd->DrawText(OsdWidth - strlen(date), 0, date, clrWhite, clrBackground, &Font);
+     osd->DrawText(OsdWidth - Utf8StrLen(date), 0, date, clrWhite, clrBackground, &Font);
      }
   osd->Flush();
 }
@@ -388,7 +388,7 @@
   if (Event->Vps() && Event->Vps() != Event->StartTime()) {
      char *buffer;
      asprintf(&buffer, " VPS: %s", *Event->GetVpsString());
-     osd->DrawText(OsdWidth - strlen(buffer), y, buffer, clrBlack, clrYellow, &Font);
+     osd->DrawText(OsdWidth - Utf8StrLen(buffer), y, buffer, clrBlack, clrYellow, &Font);
      free(buffer);
      }
   y += ts.Height();
@@ -443,7 +443,7 @@
 void cSkinCursesDisplayMenu::Flush(void)
 {
   cString date = DayDateTime();
-  osd->DrawText(OsdWidth - strlen(date) - 2, 0, date, clrBlack, clrCyan, &Font);
+  osd->DrawText(OsdWidth - Utf8StrLen(date) - 2, 0, date, clrBlack, clrCyan, &Font);
   osd->Flush();
 }
 
@@ -508,12 +508,12 @@
 
 void cSkinCursesDisplayReplay::SetCurrent(const char *Current)
 {
-  osd->DrawText(0, 2, Current, clrWhite, clrBackground, &Font, strlen(Current) + 3);
+  osd->DrawText(0, 2, Current, clrWhite, clrBackground, &Font, Utf8StrLen(Current) + 3);
 }
 
 void cSkinCursesDisplayReplay::SetTotal(const char *Total)
 {
-  osd->DrawText(OsdWidth - strlen(Total), 2, Total, clrWhite, clrBackground, &Font);
+  osd->DrawText(OsdWidth - Utf8StrLen(Total), 2, Total, clrWhite, clrBackground, &Font);
 }
 
 void cSkinCursesDisplayReplay::SetJump(const char *Jump)
@@ -569,7 +569,7 @@
      }
   else {
      const char *Prompt = tr("Volume ");
-     int l = strlen(Prompt);
+     int l = Utf8StrLen(Prompt);
      int p = (OsdWidth - l) * Current / Total;
      osd->DrawText(0, 0, Prompt, clrGreen, clrBackground, &Font);
      osd->DrawRectangle(l, 0, l + p - 1, 0, clrGreen);
diff -ruN vdr-1.5.3/config.c vdr-1.5.4/config.c
--- vdr-1.5.3/config.c	2007-06-02 13:21:40.000000000 +0200
+++ vdr-1.5.4/config.c	2007-06-17 13:54:54.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.151 2007/06/02 11:21:40 kls Exp $
+ * $Id: config.c 1.153 2007/06/17 11:54:54 kls Exp $
  */
 
 #include "config.h"
@@ -265,9 +265,9 @@
   OSDMessageTime = 1;
   UseSmallFont = 1;
   AntiAlias = 1;
-  strcpy(FontOsd, "arialbd.ttf");
-  strcpy(FontSml, "arial.ttf");
-  strcpy(FontFix, "courbd.ttf");
+  strcpy(FontOsd, DefaultFontOsd);
+  strcpy(FontSml, DefaultFontSml);
+  strcpy(FontFix, DefaultFontFix);
   FontOsdSize = 22;
   FontSmlSize = 18;
   FontFixSize = 20;
@@ -385,8 +385,8 @@
 bool cSetup::Parse(const char *Name, const char *Value)
 {
   if      (!strcasecmp(Name, "OSDLanguage"))         OSDLanguage        = atoi(Value);
-  else if (!strcasecmp(Name, "OSDSkin"))             strn0cpy(OSDSkin, Value, MaxSkinName);
-  else if (!strcasecmp(Name, "OSDTheme"))            strn0cpy(OSDTheme, Value, MaxThemeName);
+  else if (!strcasecmp(Name, "OSDSkin"))             Utf8Strn0Cpy(OSDSkin, Value, MaxSkinName);
+  else if (!strcasecmp(Name, "OSDTheme"))            Utf8Strn0Cpy(OSDTheme, Value, MaxThemeName);
   else if (!strcasecmp(Name, "PrimaryDVB"))          PrimaryDVB         = atoi(Value);
   else if (!strcasecmp(Name, "ShowInfoOnChSwitch"))  ShowInfoOnChSwitch = atoi(Value);
   else if (!strcasecmp(Name, "TimeoutRequChInfo"))   TimeoutRequChInfo  = atoi(Value);
@@ -394,7 +394,7 @@
   else if (!strcasecmp(Name, "MenuScrollWrap"))      MenuScrollWrap     = atoi(Value);
   else if (!strcasecmp(Name, "MenuKeyCloses"))       MenuKeyCloses      = atoi(Value);
   else if (!strcasecmp(Name, "MarkInstantRecord"))   MarkInstantRecord  = atoi(Value);
-  else if (!strcasecmp(Name, "NameInstantRecord"))   strn0cpy(NameInstantRecord, Value, MaxFileName);
+  else if (!strcasecmp(Name, "NameInstantRecord"))   Utf8Strn0Cpy(NameInstantRecord, Value, MaxFileName);
   else if (!strcasecmp(Name, "InstantRecordTime"))   InstantRecordTime  = atoi(Value);
   else if (!strcasecmp(Name, "LnbSLOF"))             LnbSLOF            = atoi(Value);
   else if (!strcasecmp(Name, "LnbFrequLo"))          LnbFrequLo         = atoi(Value);
@@ -435,9 +435,9 @@
   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, "FontOsd"))             Utf8Strn0Cpy(FontOsd, Value, MAXFONTNAME);
+  else if (!strcasecmp(Name, "FontSml"))             Utf8Strn0Cpy(FontSml, Value, MAXFONTNAME);
+  else if (!strcasecmp(Name, "FontFix"))             Utf8Strn0Cpy(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);
diff -ruN vdr-1.5.3/config.h vdr-1.5.4/config.h
--- vdr-1.5.3/config.h	2007-06-02 13:22:17.000000000 +0200
+++ vdr-1.5.4/config.h	2007-06-13 08:38:33.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.290 2007/06/02 11:22:17 kls Exp $
+ * $Id: config.h 1.291 2007/06/13 06:38:33 kls Exp $
  */
 
 #ifndef __CONFIG_H
@@ -22,13 +22,13 @@
 
 // VDR's own version number:
 
-#define VDRVERSION  "1.5.3"
-#define VDRVERSNUM   10503  // Version * 10000 + Major * 100 + Minor
+#define VDRVERSION  "1.5.4"
+#define VDRVERSNUM   10504  // Version * 10000 + Major * 100 + Minor
 
 // The plugin API's version number:
 
-#define APIVERSION  "1.5.1"
-#define APIVERSNUM   10501  // Version * 10000 + Major * 100 + Minor
+#define APIVERSION  "1.5.4"
+#define APIVERSNUM   10504  // Version * 10000 + Major * 100 + Minor
 
 // When loading plugins, VDR searches them by their APIVERSION, which
 // may be smaller than VDRVERSION in case there have been no changes to
diff -ruN vdr-1.5.3/device.c vdr-1.5.4/device.c
--- vdr-1.5.3/device.c	2007-04-30 11:34:00.000000000 +0200
+++ vdr-1.5.4/device.c	2007-06-16 11:31:32.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.140 2007/04/30 09:34:00 kls Exp $
+ * $Id: device.c 1.141 2007/06/16 09:31:32 kls Exp $
  */
 
 #include "device.h"
@@ -859,7 +859,7 @@
      if (Language)
         strn0cpy(availableTracks[t].language, Language, sizeof(availableTracks[t].language));
      if (Description)
-        strn0cpy(availableTracks[t].description, Description, sizeof(availableTracks[t].description));
+        Utf8Strn0Cpy(availableTracks[t].description, Description, sizeof(availableTracks[t].description));
      if (Id) {
         availableTracks[t].id = Id; // setting 'id' last to avoid the need for extensive locking
         int numAudioTracks = NumAudioTracks();
diff -ruN vdr-1.5.3/font.c vdr-1.5.4/font.c
--- vdr-1.5.3/font.c	2007-06-09 16:41:27.000000000 +0200
+++ vdr-1.5.4/font.c	2007-06-17 14:13:49.000000000 +0200
@@ -4,17 +4,22 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: font.c 1.15 2007/06/09 14:41:27 kls Exp $
+ * $Id: font.c 1.19 2007/06/17 12:13:49 kls Exp $
  */
 
 #include "font.h"
 #include <ctype.h>
+#include <fontconfig/fontconfig.h>
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #include "config.h"
 #include "osd.h"
 #include "tools.h"
 
+const char *DefaultFontOsd = "Sans Serif:Bold";
+const char *DefaultFontSml = "Sans Serif";
+const char *DefaultFontFix = "Courier:Bold";
+
 // --- cFreetypeFont ---------------------------------------------------------
 
 #define KERNING_UNKNOWN  (-10000)
@@ -22,7 +27,7 @@
 struct tKerning {
   uint prevSym;
   int kerning;
-  tKerning(uint PrevSym, int Kerning) { prevSym = PrevSym; kerning = Kerning; }
+  tKerning(uint PrevSym, int Kerning = 0) { prevSym = PrevSym; kerning = Kerning; }
   };
 
 class cGlyph : public cListObject {
@@ -286,14 +291,29 @@
      }
 }
 
+// --- cDummyFont ------------------------------------------------------------
+
+// A dummy font, in case there are no fonts installed:
+
+class cDummyFont : public cFont {
+public:
+  virtual int Width(uint c) const { return 10; }
+  virtual int Width(const char *s) const { return 50; }
+  virtual int Height(void) const { return 20; }
+  virtual void DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const {}
+  };
+
 // --- cFont -----------------------------------------------------------------
 
 cFont *cFont::fonts[eDvbFontSize] = { NULL };
 
 void cFont::SetFont(eDvbFont Font, const char *Name, int CharHeight)
 {
+  cFont *f = CreateFont(Name, CharHeight);
+  if (!f || !f->Height())
+     f = new cDummyFont;
   delete fonts[Font];
-  fonts[Font] = new cFreetypeFont(*Name == '/' ? Name : *AddDirectory(FONTDIR, Name), CharHeight);
+  fonts[Font] = f;
 }
 
 const cFont *cFont::GetFont(eDvbFont Font)
@@ -304,14 +324,85 @@
      Font = fontSml;
   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;
+       case fontOsd: SetFont(Font, Setup.FontOsd, Setup.FontOsdSize); break;
+       case fontSml: SetFont(Font, Setup.FontSml, Setup.FontSmlSize); break;
+       case fontFix: SetFont(Font, Setup.FontFix, Setup.FontFixSize); break;
        }
      }
   return fonts[Font];
 }
 
+cFont *cFont::CreateFont(const char *Name, int CharHeight)
+{
+  cString fn = GetFontFileName(Name);
+  if (*fn)
+     return new cFreetypeFont(fn, CharHeight);
+  return NULL;
+}
+
+bool cFont::GetAvailableFontNames(cStringList *FontNames, bool Monospaced)
+{
+  if (!FontNames->Size()) {
+     FcInit();
+     FcObjectSet *os = FcObjectSetBuild(FC_FAMILY, FC_STYLE, NULL);
+     FcPattern *pat = FcPatternCreate();
+     FcPatternAddBool(pat, FC_SCALABLE, FcTrue);
+     if (Monospaced)
+        FcPatternAddInteger(pat, FC_SPACING, FC_MONO);
+     FcFontSet* fontset = FcFontList(NULL, pat, os);
+     for (int i = 0; i < fontset->nfont; i++) {
+         char *s = (char *)FcNameUnparse(fontset->fonts[i]);
+         if (s) {
+            // Strip i18n stuff:
+            char *p = strchr(s, ',');
+            if (p)
+               *p = 0;
+            // Make it user presentable:
+            s = strreplace(s, "\\", ""); // '-' is escaped
+            s = strreplace(s, "style=", "");
+            FontNames->Append(s); // takes ownership of s
+            }
+         }
+     FcFontSetDestroy(fontset);
+     FcPatternDestroy(pat);
+     FcObjectSetDestroy(os);
+     FcFini();
+     FontNames->Sort();
+     }
+  return FontNames->Size() > 0;
+}
+
+cString cFont::GetFontFileName(const char *FontName)
+{
+  cString FontFileName;
+  if (FontName) {
+     char *fn = strdup(FontName);
+     fn = strreplace(fn, ":", ":style=");
+     fn = strreplace(fn, "-", "\\-");
+     FcInit();
+     FcPattern *pat = FcNameParse((FcChar8 *)fn);
+     FcPatternAddBool(pat, FC_SCALABLE, FcTrue);
+     FcConfigSubstitute(NULL, pat, FcMatchPattern);
+     FcDefaultSubstitute(pat);
+     FcFontSet *fontset = FcFontSort(NULL, pat, FcFalse, NULL, NULL);
+     for (int i = 0; i < fontset->nfont; i++) {
+         FcBool scalable;
+         FcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable);
+         if (scalable) {
+            FcChar8 *s = NULL;
+            FcPatternGetString(fontset->fonts[i], FC_FILE, 0, &s);
+            FontFileName = (char *)s;
+            break;
+            }
+         }
+     FcFontSetDestroy(fontset);
+     FcPatternDestroy(pat);
+     free(fn);
+     FcFini();
+     }
+  return FontFileName;
+}
+
 // --- cTextWrapper ----------------------------------------------------------
 
 cTextWrapper::cTextWrapper(void)
diff -ruN vdr-1.5.3/font.h vdr-1.5.4/font.h
--- vdr-1.5.3/font.h	2007-06-10 14:58:54.000000000 +0200
+++ vdr-1.5.4/font.h	2007-06-17 14:11:31.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.16 2007/06/10 12:58:54 kls Exp $
+ * $Id: font.h 1.19 2007/06/17 12:11:31 kls Exp $
  */
 
 #ifndef __FONT_H
@@ -12,10 +12,10 @@
 
 #include <stdint.h>
 #include <stdlib.h>
+#include "tools.h"
 
 #define MAXFONTNAME 64
 #define MAXFONTSIZE 64
-#define FONTDIR     "/usr/share/fonts/truetype"
 
 enum eDvbFont {
   fontOsd,
@@ -28,6 +28,10 @@
 typedef uint32_t tColor; // see also osd.h
 typedef uint8_t tIndex;
 
+extern const char *DefaultFontOsd;
+extern const char *DefaultFontSml;
+extern const char *DefaultFontFix;
+
 class cFont {
 private:
   static cFont *fonts[];
@@ -45,14 +49,30 @@
           ///< 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.
+          ///< Sets the given Font to use the font data according to Name (see CreateFont())
+          ///< 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.
+  static cFont *CreateFont(const char *Name, int CharHeight);
+          ///< Creates a new font object with the given Name and makes its characters
+          ///< CharHeight pixels high. Name is of the form "Family:Style", for instance
+          ///< "Verdana:Bold Italic" or "Times New Roman". See GetAvailableFontNames()
+          ///< for how to get a list of all available font names.
+          ///< If the requested font can't be created, NULL is returned.
+          ///< The caller must delete the font when it is no longer needed.
+  static bool GetAvailableFontNames(cStringList *FontNames, bool Monospaced = false);
+          ///< Queries the font configuration for a list of available font names,
+          ///< which is returned in FontNames. If Monospaced is true, only
+          ///< monospaced fonts will be returned. The resulting font names are
+          ///< in a format that can be used with GetFontFileName() to get the name
+          ///< of the actual font file.
+          ///< Returns true if any font names were found.
+  static cString GetFontFileName(const char *FontName);
+          ///< Retruns the actual font file name for the given FontName.
   };
 
 class cTextWrapper {
diff -ruN vdr-1.5.3/i18n.c vdr-1.5.4/i18n.c
--- vdr-1.5.3/i18n.c	2007-06-09 10:44:54.000000000 +0200
+++ vdr-1.5.4/i18n.c	2007-06-17 14:31:02.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.294 2007/06/09 08:44:54 kls Exp $
+ * $Id: i18n.c 1.297 2007/06/17 12:31:02 kls Exp $
  *
  * Translations provided by:
  *
@@ -3563,7 +3563,7 @@
     "",// TODO
     "",// TODO
     "",// TODO
-    "",// TODO
+    "Käytä antialiasointia",
     "",// TODO
     "",// TODO
     "",// TODO
@@ -3578,15 +3578,15 @@
     "",// TODO
     "",// TODO
   },
-  { "Setup.OSD$OSD font name",
-    "OSD Schriftart",
-    "",// TODO
+  { "Setup.OSD$Default font",
+    "Standard-Schriftart",
     "",// TODO
     "",// TODO
     "",// TODO
     "",// TODO
     "",// TODO
     "",// TODO
+    "Oletuskirjasintyyppi",
     "",// TODO
     "",// TODO
     "",// TODO
@@ -3601,7 +3601,7 @@
     "",// TODO
     "",// TODO
   },
-  { "Setup.OSD$Small font name",
+  { "Setup.OSD$Small font",
     "Kleine Schriftart",
     "",// TODO
     "",// TODO
@@ -3609,7 +3609,7 @@
     "",// TODO
     "",// TODO
     "",// TODO
-    "",// TODO
+    "Pienikirjasintyyppi",
     "",// TODO
     "",// TODO
     "",// TODO
@@ -3624,7 +3624,7 @@
     "",// TODO
     "",// TODO
   },
-  { "Setup.OSD$Fixed font name",
+  { "Setup.OSD$Fixed font",
     "Festbreiten-Schriftart",
     "",// TODO
     "",// TODO
@@ -3632,7 +3632,7 @@
     "",// TODO
     "",// TODO
     "",// TODO
-    "",// TODO
+    "Tasavälinen kirjasintyyppi",
     "",// TODO
     "",// TODO
     "",// TODO
@@ -3655,7 +3655,7 @@
     "",// TODO
     "",// TODO
     "",// TODO
-    "",// TODO
+    "Oletuskirjasintyypin koko (px)",
     "",// TODO
     "",// TODO
     "",// TODO
@@ -3678,7 +3678,7 @@
     "",// TODO
     "",// TODO
     "",// TODO
-    "",// TODO
+    "Pienen kirjasintyypin koko (px)",
     "",// TODO
     "",// TODO
     "",// TODO
@@ -3701,7 +3701,7 @@
     "",// TODO
     "",// TODO
     "",// TODO
-    "",// TODO
+    "Tasavälisen kirjasintyypin koko (px)",
     "",// TODO
     "",// TODO
     "",// TODO
@@ -6820,7 +6820,7 @@
      *Converted = new tI18nPhrase[NumPhrases + 1];
      memset(*Converted, 0, sizeof(tI18nPhrase) * (NumPhrases + 1));
      }
-  if (!(*Converted)[NrPhrase][NrLanguage]) {
+  if (!(*Converted)[NrPhrase][NrLanguage] && Original[NrPhrase][NrLanguage]) {
      cCharSetConv csc(Phrases[1][NrLanguage], cCharSetConv::SystemCharacterTable());
      (*Converted)[NrPhrase][NrLanguage] = strdup(csc.Convert(Original[NrPhrase][NrLanguage]));
      }
@@ -6851,7 +6851,8 @@
                    return t;
                 }
              }
-         p = Phrases;
+         p = OriginalPhrases = Phrases;
+         ConvertedPhrases = &Converted;
          }
      esyslog("%s%sno translation found for '%s' in language %d (%s)", Plugin ? Plugin : "", Plugin ? ": " : "", s, Setup.OSDLanguage, Phrases[0][Setup.OSDLanguage]);
      }
diff -ruN vdr-1.5.3/libsi/si.c vdr-1.5.4/libsi/si.c
--- vdr-1.5.3/libsi/si.c	2007-06-10 11:31:34.000000000 +0200
+++ vdr-1.5.4/libsi/si.c	2007-06-15 15:08:31.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.20 2007/06/10 09:31:34 kls Exp $
+ *   $Id: si.c 1.21 2007/06/15 13:08:31 kls Exp $
  *                                                                         *
  ***************************************************************************/
 
@@ -250,59 +250,59 @@
 }
 
 static const char *CharacterTables1[] = {
-  NULL,         // 0x00
-  "ISO8859-5",  // 0x01
-  "ISO8859-6",  // 0x02
-  "ISO8859-7",  // 0x03
-  "ISO8859-8",  // 0x04
-  "ISO8859-9",  // 0x05
-  "ISO8859-10", // 0x06
-  "ISO8859-11", // 0x07
-  "ISO8859-12", // 0x08
-  "ISO8859-13", // 0x09
-  "ISO8859-14", // 0x0A
-  "ISO8859-15", // 0x0B
-  NULL,         // 0x0C
-  NULL,         // 0x0D
-  NULL,         // 0x0E
-  NULL,         // 0x0F
-  NULL,         // 0x10
-  "UTF16",      // 0x11
-  "EUC-KR",     // 0x12
-  "GB2312",     // 0x13
-  "GBK",        // 0x14
-  "UTF8",       // 0x15
-  NULL,         // 0x16
-  NULL,         // 0x17
-  NULL,         // 0x18
-  NULL,         // 0x19
-  NULL,         // 0x1A
-  NULL,         // 0x1B
-  NULL,         // 0x1C
-  NULL,         // 0x1D
-  NULL,         // 0x1E
-  NULL,         // 0x1F
+  NULL,          // 0x00
+  "ISO-8859-5",  // 0x01
+  "ISO-8859-6",  // 0x02
+  "ISO-8859-7",  // 0x03
+  "ISO-8859-8",  // 0x04
+  "ISO-8859-9",  // 0x05
+  "ISO-8859-10", // 0x06
+  "ISO-8859-11", // 0x07
+  "ISO-8859-12", // 0x08
+  "ISO-8859-13", // 0x09
+  "ISO-8859-14", // 0x0A
+  "ISO-8859-15", // 0x0B
+  NULL,          // 0x0C
+  NULL,          // 0x0D
+  NULL,          // 0x0E
+  NULL,          // 0x0F
+  NULL,          // 0x10
+  "UTF-16",      // 0x11
+  "EUC-KR",      // 0x12
+  "GB2312",      // 0x13
+  "GBK",         // 0x14
+  "UTF-8",       // 0x15
+  NULL,          // 0x16
+  NULL,          // 0x17
+  NULL,          // 0x18
+  NULL,          // 0x19
+  NULL,          // 0x1A
+  NULL,          // 0x1B
+  NULL,          // 0x1C
+  NULL,          // 0x1D
+  NULL,          // 0x1E
+  NULL,          // 0x1F
 };
 
 #define SingleByteLimit 0x0B
 
 static const char *CharacterTables2[] = {
   NULL,         // 0x00
-  "ISO8859-1",  // 0x01
-  "ISO8859-2",  // 0x02
-  "ISO8859-3",  // 0x03
-  "ISO8859-4",  // 0x04
-  "ISO8859-5",  // 0x05
-  "ISO8859-6",  // 0x06
-  "ISO8859-7",  // 0x07
-  "ISO8859-8",  // 0x08
-  "ISO8859-9",  // 0x09
-  "ISO8859-10", // 0x0A
-  "ISO8859-11", // 0x0B
+  "ISO-8859-1",  // 0x01
+  "ISO-8859-2",  // 0x02
+  "ISO-8859-3",  // 0x03
+  "ISO-8859-4",  // 0x04
+  "ISO-8859-5",  // 0x05
+  "ISO-8859-6",  // 0x06
+  "ISO-8859-7",  // 0x07
+  "ISO-8859-8",  // 0x08
+  "ISO-8859-9",  // 0x09
+  "ISO-8859-10", // 0x0A
+  "ISO-8859-11", // 0x0B
   NULL,         // 0x0C
-  "ISO8859-13", // 0x0D
-  "ISO8859-14", // 0x0E
-  "ISO8859-15", // 0x0F
+  "ISO-8859-13", // 0x0D
+  "ISO-8859-14", // 0x0E
+  "ISO-8859-15", // 0x0F
 };
 
 #define NumEntries(Table) (sizeof(Table) / sizeof(char *))
diff -ruN vdr-1.5.3/menu.c vdr-1.5.4/menu.c
--- vdr-1.5.3/menu.c	2007-06-09 16:36:46.000000000 +0200
+++ vdr-1.5.4/menu.c	2007-06-17 14:33:01.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.451 2007/06/09 14:36:46 kls Exp $
+ * $Id: menu.c 1.455 2007/06/17 12:33:01 kls Exp $
  */
 
 #include "menu.h"
@@ -2160,7 +2160,7 @@
   cThemes themes;
   int originalThemeIndex;
   int themeIndex;
-  cFileNameList fontNames;
+  cStringList fontOsdNames, fontSmlNames, fontFixNames;
   int fontOsdIndex, fontSmlIndex, fontFixIndex;
   virtual void Set(void);
 public:
@@ -2176,12 +2176,15 @@
   skinDescriptions = new const char*[numSkins];
   themes.Load(Skins.Current()->Name());
   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));
-     }
+  cFont::GetAvailableFontNames(&fontOsdNames);
+  cFont::GetAvailableFontNames(&fontSmlNames);
+  cFont::GetAvailableFontNames(&fontFixNames, true);
+  fontOsdNames.Insert(strdup(DefaultFontOsd));
+  fontSmlNames.Insert(strdup(DefaultFontSml));
+  fontFixNames.Insert(strdup(DefaultFontFix));
+  fontOsdIndex = max(0, fontOsdNames.Find(Setup.FontOsd));
+  fontSmlIndex = max(0, fontSmlNames.Find(Setup.FontSml));
+  fontFixIndex = max(0, fontFixNames.Find(Setup.FontFix));
   Set();
 }
 
@@ -2211,11 +2214,9 @@
   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 cMenuEditStraItem(tr("Setup.OSD$Default font"),           &fontOsdIndex, fontOsdNames.Size(), &fontOsdNames[0]));
+  Add(new cMenuEditStraItem(tr("Setup.OSD$Small font"),             &fontSmlIndex, fontSmlNames.Size(), &fontSmlNames[0]));
+  Add(new cMenuEditStraItem(tr("Setup.OSD$Fixed font"),             &fontFixIndex, fontFixNames.Size(), &fontFixNames[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));
@@ -2239,14 +2240,14 @@
      if (skinIndex != originalSkinIndex) {
         cSkin *Skin = Skins.Get(skinIndex);
         if (Skin) {
-           strn0cpy(data.OSDSkin, Skin->Name(), sizeof(data.OSDSkin));
+           Utf8Strn0Cpy(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));
+        Utf8Strn0Cpy(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) {
@@ -2255,11 +2256,9 @@
         }
      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));
-        }
+     Utf8Strn0Cpy(data.FontOsd, fontOsdNames[fontOsdIndex], sizeof(data.FontOsd));
+     Utf8Strn0Cpy(data.FontSml, fontSmlNames[fontSmlIndex], sizeof(data.FontSml));
+     Utf8Strn0Cpy(data.FontFix, fontFixNames[fontFixIndex], sizeof(data.FontFix));
      if (strcmp(data.FontOsd, Setup.FontOsd) || data.FontOsdSize != Setup.FontOsdSize) {
         cFont::SetFont(fontOsd, data.FontOsd, data.FontOsdSize);
         ModifiedApperance = true;
diff -ruN vdr-1.5.3/osd.c vdr-1.5.4/osd.c
--- vdr-1.5.3/osd.c	2007-06-10 14:16:36.000000000 +0200
+++ vdr-1.5.4/osd.c	2007-06-17 15:54:34.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: osd.c 1.69 2007/06/10 12:16:36 kls Exp $
+ * $Id: osd.c 1.70 2007/06/17 13:54:34 kls Exp $
  */
 
 #include "osd.h"
@@ -642,6 +642,10 @@
 
 // --- cOsd ------------------------------------------------------------------
 
+int cOsd::osdLeft = 0;
+int cOsd::osdTop = 0;
+int cOsd::osdWidth = 0;
+int cOsd::osdHeight = 0;
 int cOsd::isOpen = 0;
 
 cOsd::cOsd(int Left, int Top)
@@ -664,6 +668,14 @@
   isOpen--;
 }
 
+void cOsd::SetOsdPostion(int Left, int Top, int Width, int Height)
+{
+  osdLeft = Left;
+  osdTop = Top;
+  osdWidth = Width;
+  osdHeight = Height;
+}
+
 void cOsd::SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
 {
   for (int i = 0; i < numBitmaps; i++)
diff -ruN vdr-1.5.3/osd.h vdr-1.5.4/osd.h
--- vdr-1.5.3/osd.h	2007-06-10 14:15:52.000000000 +0200
+++ vdr-1.5.4/osd.h	2007-06-17 15:59:22.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: osd.h 1.54 2007/06/10 12:15:52 kls Exp $
+ * $Id: osd.h 1.55 2007/06/17 13:59:22 kls Exp $
  */
 
 #ifndef __OSD_H
@@ -13,6 +13,7 @@
 #include <limits.h>
 #include <stdio.h>
 #include <stdint.h>
+#include "config.h"
 #include "font.h"
 
 #define MAXNUMCOLORS 256
@@ -245,6 +246,7 @@
 class cOsd {
   friend class cOsdProvider;
 private:
+  static int osdLeft, osdTop, osdWidth, osdHeight;
   static int isOpen;
   cBitmap *savedRegion;
   cBitmap *bitmaps[MAXOSDAREAS];
@@ -270,6 +272,15 @@
 public:
   virtual ~cOsd();
        ///< Shuts down the OSD.
+  static int OsdLeft(void) { return osdLeft ? osdLeft : Setup.OSDLeft; }
+  static int OsdTop(void) { return osdTop ? osdTop : Setup.OSDTop; }
+  static int OsdWidth(void) { return osdWidth ? osdWidth : Setup.OSDWidth; }
+  static int OsdHeight(void) { return osdHeight ? osdHeight : Setup.OSDHeight; }
+  static void SetOsdPostion(int Left, int Top, int Width, int Height);
+       ///< Sets the position and size of the OSD to the given values.
+       ///< This may be useful for plugins that determine the scaling of the
+       ///< video image and need to scale the OSD accordingly to fit on the
+       ///< screen.
   static int IsOpen(void) { return isOpen; }
   int Left(void) { return left; }
   int Top(void) { return top; }
diff -ruN vdr-1.5.3/recording.c vdr-1.5.4/recording.c
--- vdr-1.5.3/recording.c	2006-10-07 14:46:22.000000000 +0200
+++ vdr-1.5.4/recording.c	2007-06-17 15:10:12.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: recording.c 1.151 2006/10/07 12:46:22 kls Exp $
+ * $Id: recording.c 1.154 2007/06/17 13:10:12 kls Exp $
  */
 
 #include "recording.h"
@@ -262,6 +262,7 @@
 cRecordingInfo::cRecordingInfo(const cChannel *Channel, const cEvent *Event)
 {
   channelID = Channel ? Channel->GetChannelID() : tChannelID::InvalidID;
+  channelName = Channel ? strdup(Channel->Name()) : NULL;
   ownEvent = Event ? NULL : new cEvent(0);
   event = ownEvent ? ownEvent : Event;
   aux = NULL;
@@ -304,6 +305,7 @@
 {
   delete ownEvent;
   free(aux);
+  free(channelName);
 }
 
 void cRecordingInfo::SetData(const char *Title, const char *ShortText, const char *Description)
@@ -334,8 +336,11 @@
            switch (*s) {
              case 'C': {
                          char *p = strchr(t, ' ');
-                         if (p)
+                         if (p) {
+                            free(channelName);
+                            asprintf(&channelName, "%s", compactspace(p));
                             *p = 0; // strips optional channel name
+                            }
                          if (*t)
                             channelID = tChannelID::FromString(t);
                        }
@@ -375,7 +380,7 @@
 bool cRecordingInfo::Write(FILE *f, const char *Prefix) const
 {
   if (channelID.Valid())
-     fprintf(f, "%sC %s\n", Prefix, *channelID.ToString());
+     fprintf(f, "%sC %s%s%s\n", Prefix, *channelID.ToString(), channelName ? " " : "", channelName ? channelName : "");
   event->Dump(f, Prefix, true);
   if (aux)
      fprintf(f, "%s@ %s\n", Prefix, aux);
@@ -406,34 +411,14 @@
            // The VFAT file system can't handle all characters, so we
            // have to take extra efforts to encode/decode them:
            if (ToFileSystem) {
+              const char *InvalidChars = "\"\\/:*?|<>#";
               switch (*p) {
-                     // characters that can be used "as is":
-                     case '!':
-                     case '@':
-                     case '$':
-                     case '%':
-                     case '&':
-                     case '(':
-                     case ')':
-                     case '+':
-                     case ',':
-                     case '-':
-                     case ';':
-                     case '=':
-                     case '0' ... '9':
-                     case 'a' ... 'z':
-                     case 'A' ... 'Z':
-                     case 'ä': case 'Ä':
-                     case 'ö': case 'Ö':
-                     case 'ü': case 'Ü':
-                     case 'ß':
-                          break;
                      // characters that can be mapped to other characters:
                      case ' ': *p = '_'; break;
                      case '~': *p = '/'; break;
                      // characters that have to be encoded:
                      default:
-                       if (*p != '.' || !*(p + 1) || *(p + 1) == '~') { // Windows can't handle '.' at the end of directory names
+                       if (strchr(InvalidChars, *p) || *p == '.' && (!*(p + 1) || *(p + 1) == '~')) { // Windows can't handle '.' at the end of file/directory names
                           int l = p - s;
                           s = (char *)realloc(s, strlen(s) + 10);
                           p = s + l;
@@ -450,7 +435,7 @@
                 // mapped characters:
                 case '_': *p = ' '; break;
                 case '/': *p = '~'; break;
-                // encodes characters:
+                // encoded characters:
                 case '#': {
                      if (strlen(p) > 2) {
                         char buf[3];
@@ -500,7 +485,7 @@
      Subtitle = " ";
   else if (strlen(Subtitle) > MAX_SUBTITLE_LENGTH) {
      // let's make sure the Subtitle doesn't produce too long a file name:
-     strn0cpy(SubtitleBuffer, Subtitle, MAX_SUBTITLE_LENGTH);
+     Utf8Strn0Cpy(SubtitleBuffer, Subtitle, MAX_SUBTITLE_LENGTH);
      Subtitle = SubtitleBuffer;
      }
   char *macroTITLE   = strstr(Timer->File(), TIMERMACRO_TITLE);
diff -ruN vdr-1.5.3/recording.h vdr-1.5.4/recording.h
--- vdr-1.5.3/recording.h	2006-12-01 16:06:07.000000000 +0100
+++ vdr-1.5.4/recording.h	2007-06-17 14:53:05.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: recording.h 1.56 2006/12/01 15:06:07 kls Exp $
+ * $Id: recording.h 1.57 2007/06/17 12:53:05 kls Exp $
  */
 
 #ifndef __RECORDING_H
@@ -42,6 +42,7 @@
   friend class cRecording;
 private:
   tChannelID channelID;
+  char *channelName;
   const cEvent *event;
   cEvent *ownEvent;
   char *aux;
@@ -51,6 +52,7 @@
 public:
   ~cRecordingInfo();
   tChannelID ChannelID(void) const { return channelID; }
+  const char *ChannelName(void) const { return channelName; }
   const char *Title(void) const { return event->Title(); }
   const char *ShortText(void) const { return event->ShortText(); }
   const char *Description(void) const { return event->Description(); }
diff -ruN vdr-1.5.3/skinclassic.c vdr-1.5.4/skinclassic.c
--- vdr-1.5.3/skinclassic.c	2007-06-10 14:42:02.000000000 +0200
+++ vdr-1.5.4/skinclassic.c	2007-06-17 15:53:09.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.16 2007/06/10 12:42:02 kls Exp $
+ * $Id: skinclassic.c 1.17 2007/06/17 13:53:09 kls Exp $
  */
 
 #include "skinclassic.h"
@@ -92,13 +92,13 @@
   const cFont *font = cFont::GetFont(fontOsd);
   lineHeight = font->Height();
   message = false;
-  osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + (Setup.ChannelInfoPos ? 0 : Setup.OSDHeight - Lines * lineHeight));
+  osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop() + (Setup.ChannelInfoPos ? 0 : cOsd::OsdHeight() - Lines * lineHeight));
   timeWidth = font->Width("00:00") + 4;
-  tArea Areas[] = { { 0, 0, Setup.OSDWidth - 1, Lines * lineHeight - 1, 8 } };
+  tArea Areas[] = { { 0, 0, cOsd::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 } };
+     tArea Areas[] = { { 0, 0, cOsd::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));
@@ -187,14 +187,14 @@
   const cFont *font = cFont::GetFont(fontOsd);
   lineHeight = font->Height();
   x0 = 0;
-  x1 = Setup.OSDWidth;
+  x1 = cOsd::OsdWidth();
   y0 = 0;
   y1 = lineHeight;
   y2 = y1 + lineHeight;
-  y5 = Setup.OSDHeight;
+  y5 = cOsd::OsdHeight();
   y4 = y5 - lineHeight;
   y3 = y4 - lineHeight;
-  osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop);
+  osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop());
   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));
@@ -426,12 +426,12 @@
   int lineHeight = font->Height();
   lastCurrentWidth = 0;
   x0 = 0;
-  x1 = Setup.OSDWidth;
+  x1 = cOsd::OsdWidth();
   y0 = 0;
   y1 = lineHeight;
   y2 = 2 * lineHeight;
   y3 = 3 * lineHeight;
-  osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - y3);
+  osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - y3);
   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));
@@ -526,12 +526,12 @@
 {
   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, 8 } };
+  osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - lineHeight);
+  tArea Areas[] = { { 0, 0, cOsd::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 } };
+     tArea Areas[] = { { 0, 0, cOsd::OsdWidth() - 1, lineHeight - 1, 4 } };
      osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
      }
 }
@@ -591,7 +591,7 @@
       ItemsWidth = max(ItemsWidth, font->Width(Tracks[i]));
   ItemsWidth += 10;
   x0 = 0;
-  x1 = Setup.OSDWidth;
+  x1 = cOsd::OsdWidth();
   int d = x1 - x0;
   if (d > ItemsWidth) {
      d = (d - ItemsWidth) & ~0x07; // must be multiple of 8
@@ -600,7 +600,7 @@
   y0 = 0;
   y1 = lineHeight;
   y2 = y1 + NumTracks * lineHeight;
-  osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - y2);
+  osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - y2);
   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));
@@ -663,12 +663,12 @@
 {
   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, 8 } };
+  osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - lineHeight);
+  tArea Areas[] = { { 0, 0, cOsd::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 } };
+     tArea Areas[] = { { 0, 0, cOsd::OsdWidth() - 1, lineHeight - 1, 2 } };
      osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
      }
 }
@@ -681,7 +681,7 @@
 void cSkinClassicDisplayMessage::SetMessage(eMessageType Type, const char *Text)
 {
   const cFont *font = cFont::GetFont(fontOsd);
-  osd->DrawText(0, 0, Text, Theme.Color(clrMessageStatusFg + 2 * Type), Theme.Color(clrMessageStatusBg + 2 * Type), font, Setup.OSDWidth, 0, taCenter);
+  osd->DrawText(0, 0, Text, Theme.Color(clrMessageStatusFg + 2 * Type), Theme.Color(clrMessageStatusBg + 2 * Type), font, cOsd::OsdWidth(), 0, taCenter);
 }
 
 void cSkinClassicDisplayMessage::Flush(void)
diff -ruN vdr-1.5.3/skinsttng.c vdr-1.5.4/skinsttng.c
--- vdr-1.5.3/skinsttng.c	2007-06-10 14:40:43.000000000 +0200
+++ vdr-1.5.4/skinsttng.c	2007-06-17 15:51:56.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.20 2007/06/10 12:40:43 kls Exp $
+ * $Id: skinsttng.c 1.21 2007/06/17 13:51:56 kls Exp $
  */
 
 // Star Trek: The Next Generation® is a registered trademark of Paramount Pictures
@@ -163,7 +163,7 @@
      x1 = x0 + font->Width("00:00") + 4;
      x2 = x1 + Roundness;
      x3 = x2 + Gap;
-     x7 = Setup.OSDWidth;
+     x7 = cOsd::OsdWidth();
      x6 = x7 - lineHeight / 2;
      x5 = x6 - lineHeight / 2;
      x4 = x5 - Gap;
@@ -177,7 +177,7 @@
      y7 = y6 + cFont::GetFont(fontSml)->Height();
      int yt = (y0 + y1) / 2;
      int yb = (y6 + y7) / 2;
-     osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + (Setup.ChannelInfoPos ? 0 : Setup.OSDHeight - y7));
+     osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop() + (Setup.ChannelInfoPos ? 0 : cOsd::OsdHeight() - y7));
      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));
@@ -209,13 +209,13 @@
      x1 = lineHeight / 2;
      x2 = lineHeight;
      x3 = x2 + Gap;
-     x7 = Setup.OSDWidth;
+     x7 = cOsd::OsdWidth();
      x6 = x7 - lineHeight / 2;
      x5 = x6 - lineHeight / 2;
      x4 = x5 - Gap;
      y0 = 0;
      y1 = lineHeight;
-     osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + (Setup.ChannelInfoPos ? 0 : Setup.OSDHeight - y1));
+     osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop() + (Setup.ChannelInfoPos ? 0 : cOsd::OsdHeight() - y1));
      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));
@@ -374,7 +374,7 @@
   x1 = lineHeight / 2;
   x3 = (x1 + Roundness + Gap + 7) & ~0x07; // must be multiple of 8
   x2 = x3 - Gap;
-  x7 = Setup.OSDWidth;
+  x7 = cOsd::OsdWidth();
   x6 = x7 - lineHeight / 2;
   x4 = (x6 - lineHeight / 2 - Gap) & ~0x07; // must be multiple of 8
   x5 = x4 + Gap;
@@ -382,13 +382,13 @@
   y1 = lineHeight;
   y2 = y1 + Roundness;
   y3 = y2 + Gap;
-  y7 = Setup.OSDHeight;
+  y7 = cOsd::OsdHeight();
   y6 = y7 - cFont::GetFont(fontSml)->Height();
   y5 = y6 - Roundness;
   y4 = y5 - Gap;
   int yt = (y0 + y1) / 2;
   int yb = (y6 + y7) / 2;
-  osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop);
+  osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop());
   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));
@@ -703,7 +703,7 @@
   x1 = max(SymbolWidth, bm.Width());
   x2 = x1 + Roundness;
   x3 = x2 + Gap;
-  x7 = Setup.OSDWidth;
+  x7 = cOsd::OsdWidth();
   x6 = x7 - lineHeight / 2;
   x5 = x6 - lineHeight / 2;
   x4 = x5 - Gap;
@@ -717,7 +717,7 @@
   y7 = y6 + font->Height();
   int yt = (y0 + y1) / 2;
   int yb = (y6 + y7) / 2;
-  osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - y7);
+  osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - y7);
   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));
@@ -845,13 +845,13 @@
   x1 = lineHeight / 2;
   x2 = lineHeight;
   x3 = x2 + Gap;
-  x7 = Setup.OSDWidth;
+  x7 = cOsd::OsdWidth();
   x6 = x7 - lineHeight / 2;
   x5 = x6 - lineHeight / 2;
   x4 = x5 - Gap;
   y0 = 0;
   y1 = lineHeight;
-  osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - y1);
+  osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - y1);
   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));
@@ -943,7 +943,7 @@
   x1 = lineHeight / 2;
   x3 = (x1 + Roundness + Gap + 7) & ~0x07; // must be multiple of 8
   x2 = x3 - Gap;
-  x7 = Setup.OSDWidth;
+  x7 = cOsd::OsdWidth();
   x6 = x7 - lineHeight / 2;
   x4 = (x6 - lineHeight / 2 - Gap) & ~0x07; // must be multiple of 8
   x5 = x4 + Gap;
@@ -959,14 +959,14 @@
   y1 = lineHeight;
   y2 = y1 + Roundness;
   y3 = y2 + Gap;
-  // limit to Setup.OSDHeight? - what if height is too big???
+  // limit to cOsd::OsdHeight()? - what if height is too big???
   y4 = y3 + NumTracks * lineHeight + 2 * Roundness;
   y5 = y4 + Gap;
   y6 = y5 + Roundness;
   y7 = y6 + cFont::GetFont(fontSml)->Height();
   int yt = (y0 + y1) / 2;
   int yb = (y6 + y7) / 2;
-  osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - y7);
+  osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - y7);
   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));
@@ -1087,13 +1087,13 @@
   x1 = lineHeight / 2;
   x2 = lineHeight;
   x3 = x2 + Gap;
-  x7 = Setup.OSDWidth;
+  x7 = cOsd::OsdWidth();
   x6 = x7 - lineHeight / 2;
   x5 = x6 - lineHeight / 2;
   x4 = x5 - Gap;
   y0 = 0;
   y1 = lineHeight;
-  osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - y1);
+  osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - y1);
   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));
diff -ruN vdr-1.5.3/thread.c vdr-1.5.4/thread.c
--- vdr-1.5.3/thread.c	2007-02-24 17:13:33.000000000 +0100
+++ vdr-1.5.4/thread.c	2007-06-17 14:43:40.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: thread.c 1.60 2007/02/24 16:13:33 kls Exp $
+ * $Id: thread.c 1.61 2007/06/17 12:43:40 kls Exp $
  */
 
 #include "thread.h"
@@ -12,6 +12,7 @@
 #include <linux/unistd.h>
 #include <malloc.h>
 #include <stdarg.h>
+#include <stdlib.h>
 #include <sys/resource.h>
 #include <sys/syscall.h>
 #include <sys/time.h>
@@ -507,7 +508,7 @@
 
   if (pid > 0) { // parent process
      int status = 0;
-     if (!Detached && waitpid(pid, &status, 0) < 0) {
+     if (waitpid(pid, &status, 0) < 0) {
         LOG_ERROR;
         return -1;
         }
@@ -515,6 +516,9 @@
      }
   else { // child process
      if (Detached) {
+        // Fork again and let first child die - grandchild stays alive without parent
+        if (fork() > 0)
+           exit(0);
         // Start a new session
         pid_t sid = setsid();
         if (sid < 0)
diff -ruN vdr-1.5.3/timers.c vdr-1.5.4/timers.c
--- vdr-1.5.3/timers.c	2007-06-03 15:48:57.000000000 +0200
+++ vdr-1.5.4/timers.c	2007-06-16 12:41:21.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.66 2007/06/03 13:48:57 kls Exp $
+ * $Id: timers.c 1.67 2007/06/16 10:41:21 kls Exp $
  */
 
 #include "timers.h"
@@ -78,7 +78,7 @@
   *file = 0;
   const char *Title = Event->Title();
   if (!isempty(Title))
-     strn0cpy(file, Event->Title(), sizeof(file));
+     Utf8Strn0Cpy(file, Event->Title(), sizeof(file));
   aux = NULL;
   event = NULL; // let SetEvent() be called to get a log message
 }
@@ -286,7 +286,7 @@
         }
      //TODO add more plausibility checks
      result = ParseDay(daybuffer, day, weekdays);
-     strn0cpy(file, filebuffer, MaxFileName);
+     Utf8Strn0Cpy(file, filebuffer, MaxFileName);
      strreplace(file, '|', ':');
      if (isnumber(channelbuffer))
         channel = Channels.GetByNumber(atoi(channelbuffer));
@@ -358,7 +358,7 @@
 char *cTimer::SetFile(const char *File)
 {
   if (!isempty(File))
-     strn0cpy(file, File, sizeof(file));
+     Utf8Strn0Cpy(file, File, sizeof(file));
   return file;
 }
 
diff -ruN vdr-1.5.3/tools.c vdr-1.5.4/tools.c
--- vdr-1.5.3/tools.c	2007-06-09 16:21:21.000000000 +0200
+++ vdr-1.5.4/tools.c	2007-06-17 13:02:34.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.123 2007/06/09 14:21:21 kls Exp $
+ * $Id: tools.c 1.129 2007/06/17 11:02:34 kls Exp $
  */
 
 #include "tools.h"
@@ -649,6 +649,37 @@
   return n;
 }
 
+int Utf8StrLen(const char *s)
+{
+  if (cCharSetConv::SystemCharacterTable())
+     return strlen(s);
+  int n = 0;
+  while (*s) {
+        s += Utf8CharLen(s);
+        n++;
+        }
+  return n;
+}
+
+char *Utf8Strn0Cpy(char *Dest, const char *Src, int n)
+{
+  if (cCharSetConv::SystemCharacterTable())
+     return strn0cpy(Dest, Src, n);
+  char *d = Dest;
+  while (*Src) {
+        int sl = Utf8CharLen(Src);
+        n -= sl;
+        if (n > 0) {
+           while (sl--)
+                 *d++ = *Src++;
+           }
+        else
+           break;
+        }
+  *d = 0;
+  return Dest;
+}
+
 int Utf8ToArray(const char *s, uint *a, int Size)
 {
   int n = 0;
@@ -720,7 +751,7 @@
 {
   free(systemCharacterTable);
   systemCharacterTable = NULL;
-  if (!strcasestr(CharacterTable, "UTF")) {
+  if (!strcasestr(CharacterTable, "UTF-8")) {
      // Set up a map for the character values 128...255:
      char buf[129];
      for (int i = 0; i < 128; i++)
@@ -741,7 +772,7 @@
 
 const char *cCharSetConv::Convert(const char *From, char *To, size_t ToLength)
 {
-  if (cd != (iconv_t)-1) {
+  if (cd != (iconv_t)-1 && From && *From) {
      char *FromPtr = (char *)From;
      size_t FromLength = strlen(From);
      char *ToPtr = To;
@@ -1105,21 +1136,39 @@
   return directory && readdir_r(directory, &u.d, &result) == 0 ? result : NULL;
 }
 
-// --- cFileNameList ---------------------------------------------------------
+// --- cStringList -----------------------------------------------------------
 
-cFileNameList::cFileNameList(const char *Directory)
+cStringList::~cStringList()
 {
-  Load(Directory);
+  Clear();
 }
 
-cFileNameList::~cFileNameList()
+int cStringList::Find(const char *s) const
+{
+  for (int i = 0; i < Size(); i++) {
+      if (!strcmp(s, At(i)))
+         return i;
+      }
+  return -1;
+}
+
+void cStringList::Clear(void)
 {
   for (int i = 0; i < Size(); i++)
       free(At(i));
 }
 
+// --- cFileNameList ---------------------------------------------------------
+
+// TODO better GetFileNames(const char *Directory, cStringList *List)?
+cFileNameList::cFileNameList(const char *Directory)
+{
+  Load(Directory);
+}
+
 bool cFileNameList::Load(const char *Directory)
 {
+  Clear();
   if (Directory) {
      cReadDir d(Directory);
      struct dirent *e;
@@ -1128,7 +1177,7 @@
               if (strcmp(e->d_name, ".") && strcmp(e->d_name, ".."))
                  Append(strdup(e->d_name));
               }
-        Sort(CompareStrings);
+        Sort();
         return true;
         }
      else
@@ -1137,15 +1186,6 @@
   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.3/tools.h vdr-1.5.4/tools.h
--- vdr-1.5.3/tools.h	2007-06-10 10:46:23.000000000 +0200
+++ vdr-1.5.4/tools.h	2007-06-17 13:00:20.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.98 2007/06/10 08:46:23 kls Exp $
+ * $Id: tools.h 1.102 2007/06/17 11:00:20 kls Exp $
  */
 
 #ifndef __TOOLS_H
@@ -92,7 +92,15 @@
     ///< 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.
+    ///< string that form at most the given number of UTF-8 symbols.
+int Utf8StrLen(const char *s);
+    ///< Returns the number of UTF-8 symbols formed by the given string of
+    ///< character bytes.
+char *Utf8Strn0Cpy(char *Dest, const char *Src, int n);
+    ///< Copies at most n character bytes from Src to Dst, making sure that the
+    ///< resulting copy ends with a complete UTF-8 symbol. The copy is guaranteed
+    ///< to be zero terminated.
+    ///< Returns a pointer to Dest.
 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
@@ -394,7 +402,17 @@
   mutable int allocated;
   mutable int size;
   mutable T *data;
-  void Realloc(int NewAllocated) const { data = (T *)realloc(data, (allocated = NewAllocated) * sizeof(T)); }
+  cVector(const cVector &Vector) {} // don't copy...
+  cVector &operator=(const cVector &Vector) { return *this; } // ...or assign this!
+  void Realloc(int Index) const
+  {
+    if (++Index > allocated) {
+       data = (T *)realloc(data, Index * sizeof(T));
+       for (int i = allocated; i < Index; i++)
+           data[i] = T(0);
+       allocated = Index;
+       }
+  }
 public:
   cVector(int Allocated = 10)
   {
@@ -406,8 +424,9 @@
   virtual ~cVector() { free(data); }
   T& At(int Index) const
   {
+    Realloc(Index);
     if (Index >= size)
-       Realloc(size = Index + 1);
+       size = Index + 1;
     return data[Index];
   }
   const T& operator[](int Index) const
@@ -419,12 +438,24 @@
     return At(Index);
   }
   int Size(void) const { return size; }
+  virtual void Insert(T Data, int Before = 0)
+  {
+    if (Before < size) {
+       Realloc(size);
+       memmove(&data[Before + 1], &data[Before], (size - Before) * sizeof(T));
+       size++;
+       data[Before] = Data;
+       }
+    else
+       Append(Data);
+  }
   virtual void Append(T Data)
   {
     if (size >= allocated)
        Realloc(allocated * 4 / 2); // increase size by 50%
     data[size++] = Data;
   }
+  virtual void Clear(void) {}
   void Sort(__compar_fn_t Compare)
   {
     qsort(data, size, sizeof(T), Compare);
@@ -436,12 +467,19 @@
   return strcmp(*(const char **)a, *(const char **)b);
 }
 
-class cFileNameList : public cVector<char *> {
+class cStringList : public cVector<char *> {
+public:
+  cStringList(int Allocated = 10): cVector<char *>(Allocated) {}
+  virtual ~cStringList();
+  int Find(const char *s) const;
+  void Sort(void) { cVector<char *>::Sort(CompareStrings); }
+  virtual void Clear(void);
+  };
+
+class cFileNameList : public cStringList {
 public:
   cFileNameList(const char *Directory = NULL);
-  virtual ~cFileNameList();
   bool Load(const char *Directory);
-  int Find(const char *FileName);
   };
 
 class cHashObject : public cListObject {
diff -ruN vdr-1.5.3/vdr.c vdr-1.5.4/vdr.c
--- vdr-1.5.3/vdr.c	2007-06-09 14:33:53.000000000 +0200
+++ vdr-1.5.4/vdr.c	2007-06-17 13:23:08.000000000 +0200
@@ -22,11 +22,12 @@
  *
  * The project's page is at http://www.cadsoft.de/vdr
  *
- * $Id: vdr.c 1.291 2007/06/09 12:33:53 kls Exp $
+ * $Id: vdr.c 1.293 2007/06/17 11:23:08 kls Exp $
  */
 
 #include <getopt.h>
 #include <grp.h>
+#include <langinfo.h>
 #include <locale.h>
 #include <pwd.h>
 #include <signal.h>
@@ -493,18 +494,22 @@
 
   // Set the system character table:
 
-  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);
+  char *CodeSet = NULL;
+  if (setlocale(LC_CTYPE, ""))
+     CodeSet = nl_langinfo(CODESET);
+  else {
+     char *LangEnv = getenv("LANG"); // last resort in case locale stuff isn't installed
+     if (LangEnv) {
+        CodeSet = strchr(LangEnv, '.');
+        if (CodeSet)
+           CodeSet++; // skip the dot
         }
      }
+  if (CodeSet) {
+     bool known = SI::SetSystemCharacterTable(CodeSet);
+     isyslog("codeset is '%s' - %s", CodeSet, known ? "known" : "unknown");
+     cCharSetConv::SetSystemCharacterTable(CodeSet);
+     }
 
   // Main program loop variables - need to be here to have them initialized before any EXIT():
 
@@ -545,6 +550,12 @@
         ))
      EXIT(2);
 
+  if (!*cFont::GetFontFileName(Setup.FontOsd)) {
+     const char *msg = "no fonts available - OSD will not show any text!";
+     fprintf(stderr, "vdr: %s\n", msg);
+     esyslog("ERROR: %s", msg);
+     }
+
   // Recordings:
 
   Recordings.Update();
