diff -ruN vdr-1.7.27/CONTRIBUTORS vdr-1.7.28/CONTRIBUTORS
--- vdr-1.7.27/CONTRIBUTORS	2012-03-25 12:44:04.000000000 +0200
+++ vdr-1.7.28/CONTRIBUTORS	2012-06-03 12:02:36.000000000 +0200
@@ -1140,6 +1140,7 @@
  for suggesting to change the Green button in the "Edit timer" menu from "Once"
  to "Single"
  for fixing reduced bpp support for DVB subtitles
+ for implementing "DVB Standard compliance" handling
 
 Ralf Klueber <ralf.klueber@vodafone.com>
  for reporting a bug in cutting a recording if there is only a single editing mark
@@ -1309,6 +1310,7 @@
  for making cEITScanner process new transponders before old ones, to make sure
  transponder changes are recognized
  for helping to debug switching into time shift mode when pausing live video
+ for fixing a possible high CPU load when pausing replay
 
 Richard Robson <richard_robson@beeb.net>
  for reporting freezing replay if a timer starts while in Transfer Mode from the
@@ -1782,6 +1784,7 @@
  for modifying cCharSetConv so that it can be used to convert from "whatever VDR uses"
  to a given code
  for adding some missing 'const' to cDevice
+ for making sure setup strings don't contain any newline characters
 
 Sascha Klek <sklek@gmx.de>
  for reporting a problem with the '0' key in the "Day" item of the "Timers" menu
@@ -2591,6 +2594,9 @@
  for reporting a memory leak in cRecordings::ScanVideoDir() in case there are too
  many link levels
  for reporting a bug in cListBase::Move() in case From and To are equal
+ for reporting a problem with the function cString::sprintf(const char *fmt, va_list &ap),
+ that might inadvertently be called with a 'char *' as the second argument on some
+ compilers and cause a crash
 
 Ales Jurik <ajurik@quick.cz>
  for reporting broken SI data on Czech/Slovak channels after changing the default
@@ -2663,6 +2669,8 @@
  could not be determined after resuming recording
  for reporting a problem with detecting frames for channels that split frames into
  several payloads
+ for reporting a problem with getting the maximum short channel name length in case there
+ are no short names at all
 
 Marcel Unbehaun <frostworks@gmx.de>
  for adding cRecordingInfo::GetEvent()
@@ -2720,6 +2728,7 @@
  for suggesting to assign the source character 'V' to "Analog Video"
  for a patch that was used to implement SCR (Satellite Channel Routing)
  for implementing the SVDRP command 'UPDR'
+ for reporting that the SVDRP command UPDR didn't update the global recordings list
 
 Alex Lasnier <alex@fepg.org>
  for adding tuning support for ATSC devices
@@ -2771,6 +2780,7 @@
 
 Joerg Bornkessel <hd_brummy@gentoo.org>
  for adding LDFLAGS to the linker calls in the Makefiles
+ for fixing font handling with fontconfig 2.9.0 or newer
 
 Andreas Oberritter <obi@opendreambox.org>
  for suggesting to retrieve the include path to the freetype2 header files
@@ -2790,6 +2800,8 @@
 
 Juergen Lock <vdr-l@jelal.kn-bremen.de>
  for fixing cUnbufferedFile::Seek() in case it is compiled without USE_FADVISE
+ for reporting a problem with EPG scan on systems with only a single DVB device that
+ use software output
 
 Sergiu Dotenco <sergiu.dotenco@googlemail.com>
  for reporting a missing initialization in sDvbSpuRect
@@ -2849,6 +2861,9 @@
  of EPG data from BSkyB's "MTV MUSIC"
  for suggesting to make BIDI support check at runtime whether the system runs with
  UTF-8
+ for reporting a bug in checking for UTF-8 support in cFont::Bidi()
+ for a patch that was used to implement caching the information whether a recording
+ is stored on the video directory file system within the cRecording data
 
 Christian Ruppert <idl0r@gentoo.org>
  for some improvements to the Makefiles
@@ -2862,3 +2877,26 @@
  from version 1.7.8 to 1.6.0-3
  for backporting "Fixed cRecordings::DelByName() to avoid compilation errors with
  gcc 4.4" from version 1.7.9 to 1.6.0-3
+
+Marcus Roscher <dad401@gmx.de>
+ for reporting a problem with cDevice::StillPicture(), which called the derived class's
+ function even if no buffer has been allocated
+
+Reinhard Mantey <geronimo013@gmx.de>
+ for reporting a problem with character comparisons in
+ cSubtitleObject::DecodeCharacterString()
+ for fixing a mismatched 'delete' in cSchedules::SetEpgDataFileName()
+
+Michael Schneider <vdrportal_midas@gmx.de>
+ for reporting a problem with the EPG scan in case a transponder is not receivable in
+ a setup with bonded devices
+
+Marco Skambraks <marco@ammec.de>
+ for fixing resetting CAMs
+
+Christian Richter <cr@crichter.net>
+ for extending the interface to the script that gets called for recordings, so that in
+ the "edited" case it also provides the name of the original recording
+
+Christian Kaiser <christian.kaiser@teleservice.com>
+ for adding DeleteEvent() to the EPG handler interface
diff -ruN vdr-1.7.27/HISTORY vdr-1.7.28/HISTORY
--- vdr-1.7.27/HISTORY	2012-03-25 12:43:46.000000000 +0200
+++ vdr-1.7.28/HISTORY	2012-06-03 12:03:55.000000000 +0200
@@ -6603,7 +6603,7 @@
 - Now using pkg-config to get fribidi, freetype and fontconfig cflags and libs (thanks
   to Ville Skytt�).
 - The Makefile now also installs the include files (thanks to Ville Skytt�).
-- Added handling of "ANSI/SCTE 57" descriptors (thanks too Rolf Ahrenberg).
+- Added handling of "ANSI/SCTE 57" descriptors (thanks to Rolf Ahrenberg).
 - Avoiding an unecessary call to Recordings.ResetResume() (thanks to Reinhard
   Nissl).
 
@@ -7051,3 +7051,99 @@
 - Reverted some improvements to Make.config.template (thanks to Christian Ruppert).
 - Fixed handling IDLEPRIORITY in cDvbDevice::ProvidesChannel() (thanks to Frank
   Schmirler).
+
+2012-06-03: Version 1.7.28
+
+- Fixed cPixmapMemory::DrawEllipse() for quadrants -1 and -4.
+- Fixed getting the maximum short channel name length in case there are no short names
+  at all (reported by Derek Kelly).
+- The new function cDevice::DeviceType() returns a string identifying the type of
+  the given device.
+- Now limiting the number of characters of a channel's (short) name to 16 in the
+  schedules menus, to keep that column from getting overly wide in case there is
+  a channel with a very long name that has no short name.
+- Fixed EPG scan on systems with only a single DVB device that use software output
+  (reported by Juergen Lock).
+- Skins can now inquire the menu category for which their cSkinDisplayMenu is currently
+  being used. This can be done either through a call to cSkinDisplayMenu::MenuCategory()
+  or by reimplementing cSkinDisplayMenu::SetMenuCategory(). This information allows a
+  skin to use special icons or decorations for the various types of menus in VDR.
+- The new setup option "DVB/Standard compliance" can be used to switch between different
+  variations of the DVB standard (thanks to Rolf Ahrenberg). Currently there is "DVB"
+  (for the original DVB standard) and "ANSI/SCTE", which is used to properly handle
+  certain private stream types.
+- The disk usage is no longer automatically added to the title of the main and
+  "Recordings" menus. This has always been a mekeshift solution and it is now up
+  to the individual skin if, where and how it wants to display this information.
+  A skin can use the new cVideoDiskUsage class to implement such a display. For
+  compatibility, the default skins "Classic VDR", "ST:TNG Panels" and "Text mode"
+  (i.e. curses) have been changed to behave like before. Other skins may want to
+  display the disk usage in totally different ways.
+- A cOsdMenu can now handle skins that display different numbers of items in the
+  various menu categories.
+- OSD and skin are now reinitialized after a plugin setup page has been confirmed,
+  to have them react immediately in case any change to a plugin's setup parameter
+  has an effect on the OSD.
+- The Timers list is now marked as modified whenever a recording starts or ends.
+- Fixed cDevice::StillPicture(), making sure it doesn't call the derived class's
+  function if no buffer has been allocated (reported by Marcus Roscher).
+- Fixed the SVDRP command UPDR, which didn't update the global recordings list
+  (reported by Lars Hanisch).
+- cControl::Control() now has an additional boolean parameter, which can be set to
+  true to get the current player control even if it is hidden.
+- The new functions cControl::GetRecording() and cControl::GetHeader() can be used
+  to retrieve information about what the current player is playing.
+- Fixed a possible high CPU load when pausing replay (thanks to Reinhard Nissl).
+- Fixed character comparisons in cSubtitleObject::DecodeCharacterString() (reported
+  by Reinhard Mantey).
+- Renamed the function cString::sprintf(const char *fmt, va_list &ap) to vsprintf(),
+  because it might inadvertently be called with a 'char *' as the second argument on
+  some compilers and cause a crash (reported by Sundararaj Reel).
+- Removed the "bondedMasterFailed" mechanism from cDvbTuner, because it caused
+  problems with the EPG scan in case a transponder is not receivable in a setup with
+  bonded devices (reported by Michael Schneider).
+- Making sure setup strings don't contain any newline characters (thanks to Joachim
+  Wilke).
+- The new member function cSkinDisplayReplay::SetRecording() allows a skin to display
+  more information about the currently played recording.
+- Fixed a mismatched 'delete' in cSchedules::SetEpgDataFileName() (thanks to Reinhard
+  Mantey).
+- The DrawText() functions of the OSD now accept the new alignment flag taBorder,
+  which triggers keeping a proper distance from the edge that taLeft or taRight
+  aligns to.
+- Fixed checking for UTF-8 support in cFont::Bidi() (reported by Torsten Lang).
+- If a recording has no info file, the 'title' of the recording's info is now set
+  to the recording's name.
+- cVector::Clear() now reinitializes any previously used members.
+- Fixed resetting CAMs (thanks to Marco Skambraks).
+- The new function RgbShade() (include osd.h) can be used to generate a brighter or
+  darker version of a given color.
+- The new class cSortedTimers can be used to quickly get a list of all timers, sorted
+  by their start time.
+- The new skin "LCARS" is an enhanced version of the "ST:TNG" skin (which is still
+  there in its original layout, for those who don't like the LCARS skin, or can't use
+  it due to OSD limitations). The LCARS skin utilizes the new "menu category" feature
+  to display additional information on the main menu page. It shows upcoming timers
+  and the system's devices, as well as which device is recording which timers. The
+  upper pane of the main menu displays the programme data in live and replay mode,
+  and a progress bar. An indicator on the right side of the device list shows which
+  device is currently used for live viewing, and whether it is in transfer mode.
+  The individual device displays show the device number, the device type, which CAM
+  (if any ) is currently assigned to the device, and the signal strength and quality.
+  On the left side of the OSD there is a permanent display of the current date and
+  time, the disk usage and the system load.
+  "LCARS" is the new default skin of VDR. It requires at least a 4bpp (16 color) full
+  screen OSD, but you can still operate it if your OSD can handle only fewer colors
+  (in which case you may want to switch to the "ST:TNG" or "Classic VDR" skin).
+- Finally removed the code marked with __RECORDING_H_DEPRECATED_DIRECT_MEMBER_ACCESS
+  and LEGACY_CRECEIVER.
+- Now making sure that the "small font" is never larger than the "osd font".
+- Fixed font handling with fontconfig 2.9.0 or newer (thanks to Joerg Bornkessel).
+- Extended the interface to the script that gets called for recordings, so that in
+  the "edited" case it also provides the name of the original recording (thanks to
+  Christian Richter).
+- Added DeleteEvent() to the EPG handler interface, so that an EPG handler can trigger
+  deleting of an event (thanks to Christian Kaiser).
+- Speeded up opening menus on systems with many (several thousands) of recordings, by
+  caching the information whether a recording is stored on the video directory file
+  system within the cRecording data (based on a patch from Torsten Lang).
diff -ruN vdr-1.7.27/INSTALL vdr-1.7.28/INSTALL
--- vdr-1.7.27/INSTALL	2012-02-27 12:03:14.000000000 +0100
+++ vdr-1.7.28/INSTALL	2012-06-03 11:24:21.000000000 +0200
@@ -88,6 +88,15 @@
 
 See the man page vdr(1) for complete information about all command line options.
 
+Standard compliance
+-------------------
+
+Basically VDR works according to the DVB standard, but there are countries/providers
+that use other standards, which in some details deviate from the DVB standard.
+This makes it necessary to handle things differently in some areas, depending on
+which standard is actually used. If this is the case in your area, you may need
+to adjust the option "DVB/Standard compliance" in the Setup menu accordingly.
+
 Locale
 ------
 
@@ -235,8 +244,8 @@
 before and after a recording is performed, and after an editing process
 has finished.
 
-The program will be called with two string parameters. The first parameter
-is one of
+The program will be called with two or three (in case of "edited") string
+parameters. The first parameter is one of
 
   before      if this is *before* a recording starts
   after       if this is *after* a recording has finished
@@ -244,7 +253,8 @@
 
 and the second parameter contains the full name of the recording's
 directory (which may not yet exists at that moment in the "before" case).
-In the "edited" case it will be the name of the edited version.
+In the "edited" case it will be the name of the edited version (second
+parameter) and the name of the source version (third parameter).
 
 Within this program you can do anything you would like to do before and/or
 after a recording or after an editing process. However, the program must return
@@ -265,6 +275,7 @@
             ;;
      edited)
             echo "Edited recording $2"
+            echo "Source recording $3"
             ;;
      *)
             echo "ERROR: unknown state: $1"
diff -ruN vdr-1.7.27/MANUAL vdr-1.7.28/MANUAL
--- vdr-1.7.27/MANUAL	2012-02-25 14:38:52.000000000 +0100
+++ vdr-1.7.28/MANUAL	2012-04-15 11:52:14.000000000 +0200
@@ -674,6 +674,11 @@
                          from the primary DVB interface, so that the viewer will
                          be disturbed as little as possible.
 
+  Standard Compliance = 0
+                         Defines the standard compliance mode:
+                         0 = DVB
+                         1 = ANSI/SCTE
+                         
   Video format = 4:3     The video format (or aspect ratio) of the tv set in use
                          (4:3 or 16:9).
 
diff -ruN vdr-1.7.27/Makefile vdr-1.7.28/Makefile
--- vdr-1.7.27/Makefile	2012-03-11 16:33:57.000000000 +0100
+++ vdr-1.7.28/Makefile	2012-04-15 15:21:31.000000000 +0200
@@ -4,7 +4,7 @@
 # See the main source file 'vdr.c' for copyright information and
 # how to reach the author.
 #
-# $Id: Makefile 2.26 2012/03/11 15:33:57 kls Exp $
+# $Id: Makefile 2.27 2012/04/15 13:21:31 kls Exp $
 
 .DELETE_ON_ERROR:
 
@@ -44,7 +44,7 @@
        dvbplayer.o dvbspu.o dvbsubtitle.o eit.o eitscan.o epg.o filter.o font.o i18n.o interface.o keys.o\
        lirc.o menu.o menuitems.o nit.o osdbase.o osd.o pat.o player.o plugin.o\
        receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sdt.o sections.o shutdown.o\
-       skinclassic.o skins.o skinsttng.o sourceparams.o sources.o spu.o status.o svdrp.o themes.o thread.o\
+       skinclassic.o skinlcars.o skins.o skinsttng.o sourceparams.o sources.o spu.o status.o svdrp.o themes.o thread.o\
        timers.o tools.o transfer.o vdr.o videodir.o
 
 ifndef NO_KBD
diff -ruN vdr-1.7.27/PLUGINS/src/dvbhddevice/dvbhdffdevice.c vdr-1.7.28/PLUGINS/src/dvbhddevice/dvbhdffdevice.c
--- vdr-1.7.27/PLUGINS/src/dvbhddevice/dvbhdffdevice.c	2012-03-07 14:52:41.000000000 +0100
+++ vdr-1.7.28/PLUGINS/src/dvbhddevice/dvbhdffdevice.c	2012-05-08 13:40:32.000000000 +0200
@@ -3,7 +3,7 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: dvbhdffdevice.c 1.41 2012/03/07 13:52:41 kls Exp $
+ * $Id: dvbhdffdevice.c 1.43 2012/05/08 11:40:32 kls Exp $
  */
 
 #include <stdint.h>
@@ -50,7 +50,7 @@
      mHdffCmdIf = new HDFF::cHdffCmdIf(fd_osd);
 
      /* reset some stuff in case the VDR was killed before and had no chance
-	to clean up. */
+        to clean up. */
      mHdffCmdIf->CmdOsdReset();
 
      mHdffCmdIf->CmdAvSetVideoSpeed(0, 100);
@@ -183,68 +183,72 @@
   gHdffSetup.GetOsdSize(Width, Height, PixelAspect);
 }
 
-/*TODO obsolete?
-bool cDvbHdFfDevice::SetAudioBypass(bool On)
-{
-  if (setTransferModeForDolbyDigital != 1)
-     return false;
-  return ioctl(fd_audio, AUDIO_SET_BYPASS_MODE, On) == 0;
-}
-TODO*/
-
 bool cDvbHdFfDevice::SetPid(cPidHandle *Handle, int Type, bool On)
 {
-  if (Handle->pid) {
-     dmx_pes_filter_params pesFilterParams;
-     memset(&pesFilterParams, 0, sizeof(pesFilterParams));
-     if (On) {
-        if (Handle->handle < 0) {
-           Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | O_NONBLOCK, true);
-           if (Handle->handle < 0) {
-              LOG_ERROR;
-              return false;
-              }
-           }
-        if (Type == ptPcr)
-           mHdffCmdIf->CmdAvSetPcrPid(0, Handle->pid);
-        else if (Type == ptVideo) {
-           if (Handle->streamType == 0x1B)
-              mHdffCmdIf->CmdAvSetVideoPid(0, Handle->pid, HDFF_VIDEO_STREAM_H264);
-           else
-              mHdffCmdIf->CmdAvSetVideoPid(0, Handle->pid, HDFF_VIDEO_STREAM_MPEG2);
-           }
-        else if (Type == ptAudio)
-           mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_MPEG1);
-        else if (Type == ptDolby)
-           mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_AC3);
-        if (!(Type <= ptDolby && Handle->used <= 1)) {
-           pesFilterParams.pid     = Handle->pid;
-           pesFilterParams.input   = DMX_IN_FRONTEND;
-           pesFilterParams.output  = DMX_OUT_TS_TAP;
-           pesFilterParams.pes_type= DMX_PES_OTHER;
-           pesFilterParams.flags   = DMX_IMMEDIATE_START;
-           if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
-              LOG_ERROR;
-              return false;
-              }
-           }
+    //printf("SetPid Type %d, On %d, PID %5d, streamtype %d, handle %d, used %d\n", Type, On, Handle->pid, Handle->streamType, Handle->handle, Handle->used);
+    if (Handle->pid) {
+        dmx_pes_filter_params pesFilterParams;
+        memset(&pesFilterParams, 0, sizeof(pesFilterParams));
+        if (On) {
+            if (Handle->handle < 0) {
+                Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | O_NONBLOCK, true);
+                if (Handle->handle < 0) {
+                    LOG_ERROR;
+                    return false;
+                }
+            }
+            if (Type == ptPcr)
+                mHdffCmdIf->CmdAvSetPcrPid(0, Handle->pid);
+            else if (Type == ptVideo) {
+                if (Handle->streamType == 0x1B)
+                    mHdffCmdIf->CmdAvSetVideoPid(0, Handle->pid, HDFF_VIDEO_STREAM_H264);
+                else
+                    mHdffCmdIf->CmdAvSetVideoPid(0, Handle->pid, HDFF_VIDEO_STREAM_MPEG2);
+            }
+            else if (Type == ptAudio) {
+                if (Handle->streamType == 0x03)
+                    mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_MPEG1);
+                else if (Handle->streamType == 0x04)
+                    mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_MPEG2);
+                else if (Handle->streamType == SI::AC3DescriptorTag)
+                    mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_AC3);
+                else if (Handle->streamType == SI::EnhancedAC3DescriptorTag)
+                    mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_EAC3);
+                else if (Handle->streamType == 0x0F)
+                    mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_AAC);
+                else if (Handle->streamType == 0x11)
+                    mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_HE_AAC);
+                else
+                    mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_MPEG1);
+            }
+            if (!(Type <= ptDolby && Handle->used <= 1)) {
+                pesFilterParams.pid     = Handle->pid;
+                pesFilterParams.input   = DMX_IN_FRONTEND;
+                pesFilterParams.output  = DMX_OUT_TS_TAP;
+                pesFilterParams.pes_type= DMX_PES_OTHER;
+                pesFilterParams.flags   = DMX_IMMEDIATE_START;
+                if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
+                    LOG_ERROR;
+                    return false;
+                }
+            }
         }
-     else if (!Handle->used) {
-        CHECK(ioctl(Handle->handle, DMX_STOP));
-        if (Type == ptPcr)
-           mHdffCmdIf->CmdAvSetPcrPid(0, 0);
-        else if (Type == ptVideo)
-           mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF_VIDEO_STREAM_MPEG1);
-        else if (Type == ptAudio)
-           mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1);
-        else if (Type == ptDolby)
-           mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_AC3);
-        //TODO missing setting to 0x1FFF??? see cDvbDevice::SetPid()
-        close(Handle->handle);
-        Handle->handle = -1;
+        else if (!Handle->used) {
+            CHECK(ioctl(Handle->handle, DMX_STOP));
+            if (Type == ptPcr)
+                mHdffCmdIf->CmdAvSetPcrPid(0, 0);
+            else if (Type == ptVideo)
+                mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF_VIDEO_STREAM_MPEG1);
+            else if (Type == ptAudio)
+                mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1);
+            else if (Type == ptDolby)
+                mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_AC3);
+            //TODO missing setting to 0x1FFF??? see cDvbDevice::SetPid()
+            close(Handle->handle);
+            Handle->handle = -1;
         }
-     }
-  return true;
+    }
+    return true;
 }
 
 void cDvbHdFfDevice::TurnOffLiveMode(bool LiveView)
@@ -286,6 +290,8 @@
   if (CamSlot() && !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), CamSlot()->SlotNumber()))
      StartTransferMode |= LiveView && IsPrimaryDevice() && Channel->Ca() >= CA_ENCRYPTED_MIN;
 
+  //printf("SetChannelDevice Transfer %d, Live %d\n", StartTransferMode, LiveView);
+
   bool TurnOnLivePIDs = !StartTransferMode && LiveView;
 
   // Turn off live PIDs if necessary:
@@ -301,13 +307,10 @@
   // PID settings:
 
   if (TurnOnLivePIDs) {
-     //SetAudioBypass(false);//TODO obsolete?
-     if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(vpid, ptVideo, Channel->Vtype()) && AddPid(apid, ptAudio))) {
+     if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(vpid, ptVideo, Channel->Vtype()) && AddPid(apid ? apid : dpid, ptAudio, apid ? 0 : Channel->Dtype(0)))) {
         esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1);
         return false;
         }
-     if (IsPrimaryDevice())
-        AddPid(Channel->Tpid(), ptTeletext);//TODO obsolete?
      }
   else if (StartTransferMode)
      cControl::Launch(new cTransferControl(this, Channel));
@@ -338,27 +341,31 @@
 
 void cDvbHdFfDevice::SetAudioTrackDevice(eTrackType Type)
 {
-  //printf("SetAudioTrackDevice %d\n", Type);
-  const tTrackId *TrackId = GetTrack(Type);
-  if (TrackId && TrackId->id) {
-     if (IS_AUDIO_TRACK(Type)) {
+    //printf("SetAudioTrackDevice %d\n", Type);
+    const tTrackId *TrackId = GetTrack(Type);
+    if (TrackId && TrackId->id) {
+        int streamType = 0;
+        cChannel * channel = Channels.GetByNumber(CurrentChannel());
+        if (channel) {
+            if (IS_AUDIO_TRACK(Type))
+                streamType = channel->Atype(Type - ttAudioFirst);
+            else if (IS_DOLBY_TRACK(Type))
+                streamType = channel->Dtype(Type - ttDolbyFirst);
+        }
+        //printf("SetAudioTrackDevice new %d %d, current %d\n", TrackId->id, streamType, pidHandles[ptAudio].pid);
         if (pidHandles[ptAudio].pid && pidHandles[ptAudio].pid != TrackId->id) {
-           DetachAll(pidHandles[ptAudio].pid);
-           if (CamSlot())
-              CamSlot()->SetPid(pidHandles[ptAudio].pid, false);
-           pidHandles[ptAudio].pid = TrackId->id;
-           SetPid(&pidHandles[ptAudio], ptAudio, true);
-           if (CamSlot()) {
-              CamSlot()->SetPid(pidHandles[ptAudio].pid, true);
-              CamSlot()->StartDecrypting();
-              }
-           }
-	}
-     else if (IS_DOLBY_TRACK(Type)) {
-        pidHandles[ptDolby].pid = TrackId->id;
-        SetPid(&pidHandles[ptDolby], ptDolby, true);
+            DetachAll(pidHandles[ptAudio].pid);
+            if (CamSlot())
+                CamSlot()->SetPid(pidHandles[ptAudio].pid, false);
+            pidHandles[ptAudio].pid = TrackId->id;
+            pidHandles[ptAudio].streamType = streamType;
+            SetPid(&pidHandles[ptAudio], ptAudio, true);
+            if (CamSlot()) {
+                CamSlot()->SetPid(pidHandles[ptAudio].pid, true);
+                CamSlot()->StartDecrypting();
+            }
         }
-     }
+    }
 }
 
 bool cDvbHdFfDevice::CanReplay(void) const
diff -ruN vdr-1.7.27/PLUGINS/src/dvbhddevice/hdffosd.c vdr-1.7.28/PLUGINS/src/dvbhddevice/hdffosd.c
--- vdr-1.7.27/PLUGINS/src/dvbhddevice/hdffosd.c	2011-12-04 16:31:41.000000000 +0100
+++ vdr-1.7.28/PLUGINS/src/dvbhddevice/hdffosd.c	2012-05-17 15:29:50.000000000 +0200
@@ -3,7 +3,7 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: hdffosd.c 1.12 2011/12/04 15:31:41 kls Exp $
+ * $Id: hdffosd.c 1.15 2012/05/17 13:29:50 kls Exp $
  */
 
 #include "hdffosd.h"
@@ -40,7 +40,6 @@
     int mDispHeight;
     bool shown;
     bool mChanged;
-    bool mBitmapModified;
     uint32_t mDisplay;
     tFontFace mFontFaces[MAX_NUM_FONTFACES];
     tFont mFonts[MAX_NUM_FONTS];
@@ -53,7 +52,6 @@
 public:
     cHdffOsd(int Left, int Top, HDFF::cHdffCmdIf * pHdffCmdIf, uint Level);
     virtual ~cHdffOsd();
-    cBitmap *GetBitmap(int Area);
     virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas);
     virtual eOsdError SetAreas(const tArea *Areas, int NumAreas);
     virtual void SaveRegion(int x1, int y1, int x2, int y2);
@@ -79,9 +77,8 @@
     mTop = Top;
     shown = false;
     mChanged = false;
-    mBitmapModified = false;
     mBitmapPalette = HDFF_INVALID_HANDLE;
-    config.FontKerning = false;
+    config.FontKerning = true;
     config.FontAntialiasing = Setup.AntiAlias ? true : false;
     mHdffCmdIf->CmdOsdConfigure(&config);
 
@@ -126,14 +123,6 @@
     mHdffCmdIf->CmdOsdDeleteDisplay(mDisplay);
 }
 
-cBitmap * cHdffOsd::GetBitmap(int Area)
-{
-    //printf("GetBitmap %d\n", Area);
-    mChanged = true;
-    mBitmapModified = true;
-    return cOsd::GetBitmap(Area);
-}
-
 eOsdError cHdffOsd::CanHandleAreas(const tArea *Areas, int NumAreas)
 {
     eOsdError Result = cOsd::CanHandleAreas(Areas, NumAreas);
@@ -150,6 +139,9 @@
 
 eOsdError cHdffOsd::SetAreas(const tArea *Areas, int NumAreas)
 {
+    eOsdError error;
+    cBitmap * bitmap;
+
     for (int i = 0; i < NumAreas; i++)
     {
         //printf("SetAreas %d: %d %d %d %d %d\n", i, Areas[i].x1, Areas[i].y1, Areas[i].x2, Areas[i].y2, Areas[i].bpp);
@@ -160,7 +152,14 @@
         mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
         shown = false;
     }
-    return cOsd::SetAreas(Areas, NumAreas);
+    error = cOsd::SetAreas(Areas, NumAreas);
+
+    for (int i = 0; (bitmap = GetBitmap(i)) != NULL; i++)
+    {
+        bitmap->Clean();
+    }
+
+    return error;
 }
 
 void cHdffOsd::SetActive(bool On)
@@ -186,25 +185,22 @@
 {
     mHdffCmdIf->CmdOsdSaveRegion(mDisplay, mLeft + x1, mTop + y1, x2 - x1 + 1, y2 - y1 + 1);
     mChanged = true;
-    mBitmapModified = false;
 }
 
 void cHdffOsd::RestoreRegion(void)
 {
     mHdffCmdIf->CmdOsdRestoreRegion(mDisplay);
     mChanged = true;
-    mBitmapModified = false;
 }
 
 void cHdffOsd::DrawPixel(int x, int y, tColor Color)
 {
     //printf("DrawPixel\n");
-    mBitmapModified = false;
 }
 
 void cHdffOsd::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay)
 {
-    //printf("DrawBitmap %d %d %d\n", x, y, Overlay);
+    //printf("DrawBitmap %d %d %d x %d\n", x, y, Bitmap.Width(), Bitmap.Height());
     int i;
     int numColors;
     const tColor * colors = Bitmap.Colors(numColors);
@@ -230,37 +226,21 @@
         mHdffCmdIf->CmdOsdSetPaletteColors(mBitmapPalette,
                 HDFF_COLOR_FORMAT_ARGB, 0, numColors, mBitmapColors);
     }
-    mHdffCmdIf->CmdOsdDrawBitmap(mDisplay, mLeft + x, mTop + y,
-        (uint8_t *) Bitmap.Data(0, 0), Bitmap.Width(), Bitmap.Height(),
-        Bitmap.Width() * Bitmap.Height(), HDFF_COLOR_TYPE_CLUT8, mBitmapPalette);
-#if 0
-    uint32_t * tmpBitmap = new uint32_t[Bitmap.Width() * Bitmap.Height()];
-    for (int ix = 0; ix < Bitmap.Width(); ix++)
-    {
-        for (int iy = 0; iy < Bitmap.Height(); iy++)
-        {
-            const tIndex * pixel = Bitmap.Data(ix, iy);
-            tColor color = Bitmap.Color(*pixel);
-            if (!Overlay || *pixel != 0)
-            {
-                if (ColorFg || ColorBg)
-                {
-                    if (*pixel == 0)
-                        color = ColorBg;
-                    else if (*pixel == 1)
-                        color = ColorFg;
-                }
-                tmpBitmap[Bitmap.Width() * iy + ix] = color;
-            }
-        }
+    int width = Bitmap.Width();
+    int height = Bitmap.Height();
+    int chunk = MAX_BITMAP_SIZE / width;
+    if (chunk > height)
+        chunk = height;
+    for (int yc = 0; yc < height; yc += chunk)
+    {
+        int hc = chunk;
+        if (yc + hc > height)
+            hc = height - yc;
+        mHdffCmdIf->CmdOsdDrawBitmap(mDisplay, mLeft + x, mTop + y + yc,
+            (uint8_t *) Bitmap.Data(0, yc), width, hc,
+            width * hc, HDFF_COLOR_TYPE_CLUT8, mBitmapPalette);
     }
-    mHdffCmdIf->CmdOsdDrawBitmap(mDisplay, mLeft + x, mTop + y,
-        (uint8_t *) tmpBitmap, Bitmap.Width(), Bitmap.Height(),
-        Bitmap.Width() * Bitmap.Height() * 4, HDFF::colorTypeARGB8888, InvalidHandle);
-    delete[] tmpBitmap;
-#endif
     mChanged = true;
-    mBitmapModified = false;
 }
 
 void cHdffOsd::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
@@ -365,11 +345,16 @@
         if (Width)
         {
             if ((Alignment & taLeft) != 0)
-                ;
+            {
+                if ((Alignment & taBorder) != 0)
+                    x += max(h / TEXT_ALIGN_BORDER, 1);
+            }
             else if ((Alignment & taRight) != 0)
             {
                 if (w < Width)
                     x += Width - w;
+                if ((Alignment & taBorder) != 0)
+                    x -= max(h / TEXT_ALIGN_BORDER, 1);
             }
             else
             { // taCentered
@@ -413,14 +398,12 @@
     mHdffCmdIf->CmdOsdSetDisplayClippingArea(mDisplay, false, 0, 0, 0, 0);
     //Font->DrawText(this, x, y, s, ColorFg, ColorBg, limit);
     mChanged = true;
-    mBitmapModified = false;
 }
 
 void cHdffOsd::DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
 {
     mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, mLeft + x1, mTop + y1, x2 - x1 + 1, y2 - y1 + 1, Color);
     mChanged = true;
-    mBitmapModified = false;
 }
 
 void cHdffOsd::DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants)
@@ -511,14 +494,12 @@
     }
     mHdffCmdIf->CmdOsdDrawEllipse(mDisplay, mLeft + cx, mTop + cy, rx, ry, Color, flags);
     mChanged = true;
-    mBitmapModified = false;
 }
 
 void cHdffOsd::DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type)
 {
     //printf("DrawSlope\n");
     mChanged = true;
-    mBitmapModified = false;
 }
 
 void cHdffOsd::Flush(void)
@@ -526,23 +507,30 @@
     if (!Active())
         return;
 
-    if (!mChanged)
-        return;
-
     //printf("Flush\n");
-    if (mBitmapModified)
+    cBitmap * Bitmap;
+
+    for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++)
     {
-        cBitmap *Bitmap;
-        for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++)
+        int x1;
+        int y1;
+        int x2;
+        int y2;
+
+        if (Bitmap->Dirty(x1, y1, x2, y2))
         {
+            //printf("dirty %d %d, %d %d\n", x1, y1, x2, y2);
             DrawBitmap(0, 0, *Bitmap);
+            Bitmap->Clean();
         }
     }
 
+    if (!mChanged)
+        return;
+
     mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
 
     mChanged = false;
-    mBitmapModified = false;
 }
 
 
diff -ruN vdr-1.7.27/PLUGINS/src/pictures/HISTORY vdr-1.7.28/PLUGINS/src/pictures/HISTORY
--- vdr-1.7.27/PLUGINS/src/pictures/HISTORY	2012-02-27 12:41:02.000000000 +0100
+++ vdr-1.7.28/PLUGINS/src/pictures/HISTORY	2012-04-28 15:07:18.000000000 +0200
@@ -71,3 +71,7 @@
 2012-02-27: Version 0.1.2
 
 - Removed an obsolete command line option.
+
+2012-04-2r8 Version 0.1.3
+
+- Added cPictureControl::GetHeader().
diff -ruN vdr-1.7.27/PLUGINS/src/pictures/pictures.c vdr-1.7.28/PLUGINS/src/pictures/pictures.c
--- vdr-1.7.27/PLUGINS/src/pictures/pictures.c	2012-02-27 12:40:15.000000000 +0100
+++ vdr-1.7.28/PLUGINS/src/pictures/pictures.c	2012-04-28 13:58:42.000000000 +0200
@@ -3,7 +3,7 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: pictures.c 2.5 2012/02/27 11:40:15 kls Exp $
+ * $Id: pictures.c 2.6 2012/04/28 11:58:42 kls Exp $
  */
 
 #include <getopt.h>
@@ -11,7 +11,7 @@
 #include "menu.h"
 #include "player.h"
 
-static const char *VERSION       = "0.1.2";
+static const char *VERSION       = "0.1.3";
 static const char *DESCRIPTION   = trNOOP("A simple picture viewer");
 static const char *MAINMENUENTRY = trNOOP("Pictures");
 
diff -ruN vdr-1.7.27/PLUGINS/src/pictures/player.c vdr-1.7.28/PLUGINS/src/pictures/player.c
--- vdr-1.7.27/PLUGINS/src/pictures/player.c	2011-02-20 18:15:25.000000000 +0100
+++ vdr-1.7.28/PLUGINS/src/pictures/player.c	2012-04-28 13:58:15.000000000 +0200
@@ -3,7 +3,7 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: player.c 2.1 2011/02/20 17:15:25 kls Exp $
+ * $Id: player.c 2.2 2012/04/28 11:58:15 kls Exp $
  */
 
 #include "player.h"
@@ -204,6 +204,11 @@
   osd->Flush();
 }
 
+cString cPictureControl::GetHeader(void)
+{
+  return tr("Pictures");
+}
+
 eOSState cPictureControl::ProcessKey(eKeys Key)
 {
   switch (Key) {
diff -ruN vdr-1.7.27/PLUGINS/src/pictures/player.h vdr-1.7.28/PLUGINS/src/pictures/player.h
--- vdr-1.7.27/PLUGINS/src/pictures/player.h	2008-01-12 17:21:57.000000000 +0100
+++ vdr-1.7.28/PLUGINS/src/pictures/player.h	2012-04-28 13:56:01.000000000 +0200
@@ -3,7 +3,7 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: player.h 2.0 2008/01/12 16:21:57 kls Exp $
+ * $Id: player.h 2.1 2012/04/28 11:56:01 kls Exp $
  */
 
 #ifndef _PLAYER_H
@@ -39,6 +39,7 @@
 public:
   cPictureControl(cPictureEntry *Pictures, const cPictureEntry *PictureEntry, bool SlideShow = false);
   virtual ~cPictureControl();
+  virtual cString GetHeader(void);
   virtual eOSState ProcessKey(eKeys Key);
   static bool Active(void) { return active > 0; }
   static const char *LastDisplayed(void);
diff -ruN vdr-1.7.27/PLUGINS/src/skincurses/HISTORY vdr-1.7.28/PLUGINS/src/skincurses/HISTORY
--- vdr-1.7.27/PLUGINS/src/skincurses/HISTORY	2012-03-11 15:44:17.000000000 +0100
+++ vdr-1.7.28/PLUGINS/src/skincurses/HISTORY	2012-04-23 10:54:52.000000000 +0200
@@ -96,3 +96,8 @@
 2012-03-11: Version 0.1.11
 
 - Adapted menu column widths of 'skincurses' to the wider HD OSD sizes.
+
+2012-04-23: Version 0.1.12
+
+- Now displaying disk usage in the title of the main and "Recordings" menu,
+  which is no longer done by the VDR core.
diff -ruN vdr-1.7.27/PLUGINS/src/skincurses/skincurses.c vdr-1.7.28/PLUGINS/src/skincurses/skincurses.c
--- vdr-1.7.27/PLUGINS/src/skincurses/skincurses.c	2012-03-11 15:42:52.000000000 +0100
+++ vdr-1.7.28/PLUGINS/src/skincurses/skincurses.c	2012-04-23 10:53:13.000000000 +0200
@@ -3,15 +3,16 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: skincurses.c 2.8 2012/03/11 14:42:52 kls Exp $
+ * $Id: skincurses.c 2.9 2012/04/23 08:53:13 kls Exp $
  */
 
 #include <ncurses.h>
 #include <vdr/osd.h>
 #include <vdr/plugin.h>
 #include <vdr/skins.h>
+#include <vdr/videodir.h>
 
-static const char *VERSION        = "0.1.11";
+static const char *VERSION        = "0.1.12";
 static const char *DESCRIPTION    = trNOOP("A text only skin");
 static const char *MAINMENUENTRY  = NULL;
 
@@ -262,6 +263,9 @@
 class cSkinCursesDisplayMenu : public cSkinDisplayMenu {
 private:
   cOsd *osd;
+  cString title;
+  int lastDiskUsageState;
+  void DrawTitle(void);
   void DrawScrollbar(int Total, int Offset, int Shown, int Top, int Height, bool CanScrollUp, bool CanScrollDown);
   void SetTextScrollbar(void);
 public:
@@ -285,6 +289,7 @@
 cSkinCursesDisplayMenu::cSkinCursesDisplayMenu(void)
 {
   osd = new cCursesOsd(0, 0);
+  lastDiskUsageState = -1;
   osd->DrawRectangle(0, 0, ScOsdWidth - 1, ScOsdHeight - 1, clrBackground);
 }
 
@@ -332,9 +337,16 @@
   textScroller.Reset();
 }
 
+void cSkinCursesDisplayMenu::DrawTitle(void)
+{
+  bool WithDisk = MenuCategory() == mcMain || MenuCategory() == mcRecording;
+  osd->DrawText(0, 0, WithDisk ? cString::sprintf("%s  -  %s", *title, *cVideoDiskUsage::String()) : title, clrBlack, clrCyan, &Font, ScOsdWidth);
+}
+
 void cSkinCursesDisplayMenu::SetTitle(const char *Title)
 {
-  osd->DrawText(0, 0, Title, clrBlack, clrCyan, &Font, ScOsdWidth);
+  title = Title;
+  DrawTitle();
 }
 
 void cSkinCursesDisplayMenu::SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue)
@@ -475,6 +487,8 @@
 
 void cSkinCursesDisplayMenu::Flush(void)
 {
+  if (cVideoDiskUsage::HasChanged(lastDiskUsageState))
+     DrawTitle();
   cString date = DayDateTime();
   osd->DrawText(ScOsdWidth - Utf8StrLen(date) - 2, 0, date, clrBlack, clrCyan, &Font);
   osd->Flush();
diff -ruN vdr-1.7.27/channels.c vdr-1.7.28/channels.c
--- vdr-1.7.27/channels.c	2012-03-11 14:29:06.000000000 +0100
+++ vdr-1.7.28/channels.c	2012-04-01 11:27:08.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: channels.c 2.21 2012/03/11 13:29:06 kls Exp $
+ * $Id: channels.c 2.22 2012/04/01 09:27:08 kls Exp $
  */
 
 #include "channels.h"
@@ -955,7 +955,7 @@
   if (!maxShortChannelNameLength) {
      for (cChannel *channel = First(); channel; channel = Next(channel)) {
          if (!channel->GroupSep())
-            maxShortChannelNameLength = max(Utf8StrLen(channel->ShortName()), maxShortChannelNameLength);
+            maxShortChannelNameLength = max(Utf8StrLen(channel->ShortName(true)), maxShortChannelNameLength);
          }
      }
   return maxShortChannelNameLength;
diff -ruN vdr-1.7.27/ci.c vdr-1.7.28/ci.c
--- vdr-1.7.27/ci.c	2012-02-29 11:24:41.000000000 +0100
+++ vdr-1.7.28/ci.c	2012-05-29 13:13:40.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 2.8 2012/02/29 10:24:41 kls Exp $
+ * $Id: ci.c 2.9 2012/05/29 11:13:40 kls Exp $
  */
 
 #include "ci.h"
@@ -1715,6 +1715,7 @@
      if (ciAdapter->Reset(slotIndex)) {
         resetTime = time(NULL);
         dbgprotocol("ok.\n");
+        lastModuleStatus = msReset;
         return true;
         }
      dbgprotocol("failed!\n");
diff -ruN vdr-1.7.27/config.c vdr-1.7.28/config.c
--- vdr-1.7.27/config.c	2012-02-29 11:15:54.000000000 +0100
+++ vdr-1.7.28/config.c	2012-05-11 13:06:57.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 2.20 2012/02/29 10:15:54 kls Exp $
+ * $Id: config.c 2.22 2012/05/11 11:06:57 kls Exp $
  */
 
 #include "config.h"
@@ -309,9 +309,9 @@
 
 cSetupLine::cSetupLine(const char *Name, const char *Value, const char *Plugin)
 {
-  name = strdup(Name);
-  value = strdup(Value);
-  plugin = Plugin ? strdup(Plugin) : NULL;
+  name = strreplace(strdup(Name), '\n', 0);
+  value = strreplace(strdup(Value), '\n', 0);
+  plugin = Plugin ? strreplace(strdup(Plugin), '\n', 0) : NULL;
 }
 
 cSetupLine::~cSetupLine()
@@ -391,6 +391,7 @@
   SetSystemTime = 0;
   TimeSource = 0;
   TimeTransponder = 0;
+  StandardCompliance = STANDARD_DVB;
   MarginStart = 2;
   MarginStop = 10;
   AudioLanguages[0] = -1;
@@ -585,6 +586,7 @@
   else if (!strcasecmp(Name, "SetSystemTime"))       SetSystemTime      = atoi(Value);
   else if (!strcasecmp(Name, "TimeSource"))          TimeSource         = cSource::FromString(Value);
   else if (!strcasecmp(Name, "TimeTransponder"))     TimeTransponder    = atoi(Value);
+  else if (!strcasecmp(Name, "StandardCompliance"))  StandardCompliance = atoi(Value);
   else if (!strcasecmp(Name, "MarginStart"))         MarginStart        = atoi(Value);
   else if (!strcasecmp(Name, "MarginStop"))          MarginStop         = atoi(Value);
   else if (!strcasecmp(Name, "AudioLanguages"))      return ParseLanguages(Value, AudioLanguages);
@@ -682,6 +684,7 @@
   Store("SetSystemTime",      SetSystemTime);
   Store("TimeSource",         cSource::ToString(TimeSource));
   Store("TimeTransponder",    TimeTransponder);
+  Store("StandardCompliance", StandardCompliance);
   Store("MarginStart",        MarginStart);
   Store("MarginStop",         MarginStop);
   StoreLanguages("AudioLanguages", AudioLanguages);
diff -ruN vdr-1.7.27/config.h vdr-1.7.28/config.h
--- vdr-1.7.27/config.h	2012-03-11 11:41:44.000000000 +0100
+++ vdr-1.7.28/config.h	2012-04-15 12:45:32.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 2.45 2012/03/11 10:41:44 kls Exp $
+ * $Id: config.h 2.47 2012/04/15 10:45:32 kls Exp $
  */
 
 #ifndef __CONFIG_H
@@ -22,13 +22,13 @@
 
 // VDR's own version number:
 
-#define VDRVERSION  "1.7.27"
-#define VDRVERSNUM   10727  // Version * 10000 + Major * 100 + Minor
+#define VDRVERSION  "1.7.28"
+#define VDRVERSNUM   10728  // Version * 10000 + Major * 100 + Minor
 
 // The plugin API's version number:
 
-#define APIVERSION  "1.7.27"
-#define APIVERSNUM   10727  // Version * 10000 + Major * 100 + Minor
+#define APIVERSION  "1.7.28"
+#define APIVERSNUM   10728  // 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
@@ -52,6 +52,16 @@
 #define MaxSkinName 16
 #define MaxThemeName 16
 
+// Basically VDR works according to the DVB standard, but there are countries/providers
+// that use other standards, which in some details deviate from the DVB standard.
+// This makes it necessary to handle things differently in some areas, depending on
+// which standard is actually used. The following macros are used to distinguish
+// these cases (make sure to adjust cMenuSetupDVB::standardComplianceTexts accordingly
+// when adding a new standard):
+
+#define STANDARD_DVB       0
+#define STANDARD_ANSISCTE  1
+
 typedef uint32_t in_addr_t; //XXX from /usr/include/netinet/in.h (apparently this is not defined on systems with glibc < 2.2)
 
 class cSVDRPhost : public cListObject {
@@ -255,6 +265,7 @@
   int SetSystemTime;
   int TimeSource;
   int TimeTransponder;
+  int StandardCompliance;
   int MarginStart, MarginStop;
   int AudioLanguages[I18N_MAX_LANGUAGES + 1];
   int DisplaySubtitles;
diff -ruN vdr-1.7.27/cutter.c vdr-1.7.28/cutter.c
--- vdr-1.7.27/cutter.c	2012-02-16 13:08:39.000000000 +0100
+++ vdr-1.7.28/cutter.c	2012-06-02 15:46:55.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: cutter.c 2.11 2012/02/16 12:08:39 kls Exp $
+ * $Id: cutter.c 2.12 2012/06/02 13:46:55 kls Exp $
  */
 
 #include "cutter.h"
@@ -270,7 +270,7 @@
      error = cuttingThread->Error();
      Stop();
      if (!error)
-        cRecordingUserCommand::InvokeCommand(RUC_EDITEDRECORDING, editedVersionName);
+        cRecordingUserCommand::InvokeCommand(RUC_EDITEDRECORDING, editedVersionName, originalVersionName);
      originalVersionName = NULL;
      editedVersionName = NULL;
      ended = true;
diff -ruN vdr-1.7.27/device.c vdr-1.7.28/device.c
--- vdr-1.7.27/device.c	2012-03-13 10:48:14.000000000 +0100
+++ vdr-1.7.28/device.c	2012-04-26 11:40:36.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 2.58 2012/03/13 09:48:14 kls Exp $
+ * $Id: device.c 2.60 2012/04/26 09:40:36 kls Exp $
  */
 
 #include "device.h"
@@ -162,6 +162,11 @@
   return -1;
 }
 
+cString cDevice::DeviceType(void) const
+{
+  return "";
+}
+
 cString cDevice::DeviceName(void) const
 {
   return "";
@@ -1176,8 +1181,10 @@
               return;
               }
            }
-     StillPicture(buf, Size);
-     free(buf);
+     if (buf) {
+        StillPicture(buf, Size);
+        free(buf);
+        }
      }
 }
 
diff -ruN vdr-1.7.27/device.h vdr-1.7.28/device.h
--- vdr-1.7.27/device.h	2012-03-13 11:17:16.000000000 +0100
+++ vdr-1.7.28/device.h	2012-04-04 11:48:21.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: device.h 2.38 2012/03/13 10:17:16 kls Exp $
+ * $Id: device.h 2.39 2012/04/04 09:48:21 kls Exp $
  */
 
 #ifndef __DEVICE_H
@@ -201,6 +201,12 @@
          ///< Returns the card index of this device (0 ... MAXDEVICES - 1).
   int DeviceNumber(void) const;
          ///< Returns the number of this device (0 ... numDevices).
+  virtual cString DeviceType(void) const;
+         ///< Returns a string identifying the type of this device (like "DVB-S").
+         ///< If this device can receive different delivery systems, the returned
+         ///< string shall be that of the currently used system.
+         ///< The length of the returned string should not exceed 6 characters.
+         ///< The default implementation returns an empty string.
   virtual cString DeviceName(void) const;
          ///< Returns a string identifying the name of this device.
          ///< The default implementation returns an empty string.
diff -ruN vdr-1.7.27/dvbdevice.c vdr-1.7.28/dvbdevice.c
--- vdr-1.7.27/dvbdevice.c	2012-03-25 12:41:45.000000000 +0200
+++ vdr-1.7.28/dvbdevice.c	2012-05-09 10:33:59.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: dvbdevice.c 2.69 2012/03/25 10:41:45 kls Exp $
+ * $Id: dvbdevice.c 2.71 2012/05/09 08:33:59 kls Exp $
  */
 
 #include "dvbdevice.h"
@@ -285,6 +285,7 @@
 private:
   static cMutex bondMutex;
   enum eTunerStatus { tsIdle, tsSet, tsTuned, tsLocked };
+  int frontendType;
   const cDvbDevice *device;
   int fd_frontend;
   int adapter, frontend;
@@ -302,7 +303,6 @@
   cCondVar newSet;
   cDvbTuner *bondedTuner;
   bool bondedMaster;
-  bool bondedMasterFailed;
   bool SetFrontendType(const cChannel *Channel);
   cString GetBondingParams(const cChannel *Channel = NULL) const;
   void ClearEventQueue(void) const;
@@ -314,6 +314,7 @@
 public:
   cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend);
   virtual ~cDvbTuner();
+  int FrontendType(void) const { return frontendType; }
   bool Bond(cDvbTuner *Tuner);
   void UnBond(void);
   bool BondingOk(const cChannel *Channel, bool ConsiderOccupied = false) const;
@@ -331,6 +332,7 @@
 
 cDvbTuner::cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend)
 {
+  frontendType = SYS_UNDEFINED;
   device = Device;
   fd_frontend = Fd_Frontend;
   adapter = Adapter;
@@ -345,7 +347,6 @@
   tunerStatus = tsIdle;
   bondedTuner = NULL;
   bondedMaster = false;
-  bondedMasterFailed = false;
   SetDescription("tuner on frontend %d/%d", adapter, frontend);
   Start();
 }
@@ -435,12 +436,8 @@
   if (!bondedTuner)
      return this; // an unbonded tuner is always "master"
   cMutexLock MutexLock(&bondMutex);
-  if (bondedMaster) {
-     if (!bondedMasterFailed)
-        return this;
-     else
-        bondedMaster = false;
-     }
+  if (bondedMaster)
+     return this;
   // This tuner is bonded, but it's not the master, so let's see if there is a master at all:
   if (cDvbTuner *t = bondedTuner) {
      while (t != this) {
@@ -450,18 +447,9 @@
            }
      }
   // None of the other bonded tuners is master, so make this one the master:
-  cDvbTuner *t = this;
-  if (bondedMasterFailed) {
-     // This one has failed, so switch to the next one:
-     t = bondedTuner;
-     t->bondedMasterFailed = false;
-     cMutexLock MutexLock(&t->mutex);
-     t->channel = channel;
-     t->tunerStatus = tsSet;
-     }
-  t->bondedMaster = true;
-  dsyslog("tuner %d/%d is now bonded master", t->adapter, t->frontend);
-  return t;
+  bondedMaster = true;
+  dsyslog("tuner %d/%d is now bonded master", adapter, frontend);
+  return this;
 }
 
 bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
@@ -733,7 +721,7 @@
   cDvbTransponderParameters dtp(channel.Parameters());
 
   // Determine the required frontend type:
-  int frontendType = GetRequiredDeliverySystem(&channel, &dtp);
+  frontendType = GetRequiredDeliverySystem(&channel, &dtp);
   if (frontendType == SYS_UNDEFINED)
      return false;
 
@@ -875,9 +863,6 @@
                      isyslog("frontend %d/%d timed out while tuning to channel %d, tp %d", adapter, frontend, channel.Number(), channel.Transponder());
                      lastTimeoutReport = time(NULL);
                      }
-                  cMutexLock MutexLock(&bondMutex);
-                  if (bondedTuner && bondedMaster)
-                     bondedMasterFailed = true; // give an other tuner a chance in case the sat cable was disconnected
                   continue;
                   }
                WaitTime = 100; // allows for a quick change from tsTuned to tsLocked
@@ -977,7 +962,7 @@
 cMutex cDvbDevice::bondMutex;
 
 const char *DeliverySystemNames[] = {
-  "UNDEFINED",
+  "",
   "DVB-C",
   "DVB-C",
   "DVB-T",
@@ -1090,6 +1075,17 @@
   return true;
 }
 
+cString cDvbDevice::DeviceType(void) const
+{
+  if (dvbTuner) {
+     if (dvbTuner->FrontendType() != SYS_UNDEFINED)
+        return DeliverySystemNames[dvbTuner->FrontendType()];
+     if (numDeliverySystems)
+        return DeliverySystemNames[deliverySystems[0]]; // to have some reasonable default
+     }
+  return "";
+}
+
 cString cDvbDevice::DeviceName(void) const
 {
   return frontendInfo.name;
diff -ruN vdr-1.7.27/dvbdevice.h vdr-1.7.28/dvbdevice.h
--- vdr-1.7.27/dvbdevice.h	2012-03-13 11:11:15.000000000 +0100
+++ vdr-1.7.28/dvbdevice.h	2012-03-31 13:13:31.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: dvbdevice.h 2.25 2012/03/13 10:11:15 kls Exp $
+ * $Id: dvbdevice.h 2.26 2012/03/31 11:13:31 kls Exp $
  */
 
 #ifndef __DVBDEVICE_H
@@ -138,6 +138,7 @@
   int Adapter(void) const { return adapter; }
   int Frontend(void) const { return frontend; }
   virtual bool Ready(void);
+  virtual cString DeviceType(void) const;
   virtual cString DeviceName(void) const;
   static bool BondDevices(const char *Bondings);
        ///< Bonds the devices as defined in the given Bondings string.
diff -ruN vdr-1.7.27/dvbplayer.c vdr-1.7.28/dvbplayer.c
--- vdr-1.7.27/dvbplayer.c	2012-03-12 15:36:55.000000000 +0100
+++ vdr-1.7.28/dvbplayer.c	2012-05-06 13:02:35.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 2.26 2012/03/12 14:36:55 kls Exp $
+ * $Id: dvbplayer.c 2.27 2012/05/06 11:02:35 kls Exp $
  */
 
 #include "dvbplayer.h"
@@ -408,7 +408,7 @@
      Goto(0, true);
   while (Running()) {
         if (WaitingForData)
-           nonBlockingFileReader->WaitForDataMs(3); // this keeps the CPU load low, but reacts immediately on new data
+           WaitingForData = !nonBlockingFileReader->WaitForDataMs(3); // this keeps the CPU load low, but reacts immediately on new data
         else if (Sleep) {
            cPoller Poller;
            DevicePoll(Poller, 10);
diff -ruN vdr-1.7.27/dvbsubtitle.c vdr-1.7.28/dvbsubtitle.c
--- vdr-1.7.27/dvbsubtitle.c	2012-03-16 12:56:56.000000000 +0100
+++ vdr-1.7.28/dvbsubtitle.c	2012-05-08 10:17:17.000000000 +0200
@@ -7,7 +7,7 @@
  * Original author: Marco Schluessler <marco@lordzodiac.de>
  * With some input from the "subtitle plugin" by Pekka Virtanen <pekka.virtanen@sci.fi>
  *
- * $Id: dvbsubtitle.c 2.31 2012/03/16 11:56:56 kls Exp $
+ * $Id: dvbsubtitle.c 2.32 2012/05/08 08:17:17 kls Exp $
  */
 
 
@@ -217,7 +217,7 @@
         char txt[NumberOfCodes + 1];
         char *p = txt;
         for (int i = 2; i < NumberOfCodes; ++i) {
-            char c = Data[i * 2 + 1] & 0xFF;
+            uchar c = Data[i * 2 + 1] & 0xFF;
             if (c == 0)
                break;
             if (' ' <= c && c <= '~' || c == '\n' || 0xA0 <= c)
diff -ruN vdr-1.7.27/eit.c vdr-1.7.28/eit.c
--- vdr-1.7.27/eit.c	2012-03-14 11:11:15.000000000 +0100
+++ vdr-1.7.28/eit.c	2012-06-02 16:05:22.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 2.16 2012/03/14 10:11:15 kls Exp $
+ * $Id: eit.c 2.17 2012/06/02 14:05:22 kls Exp $
  */
 
 #include "eit.h"
@@ -290,6 +290,11 @@
          channel->SetLinkChannels(LinkChannels);
       Modified = true;
       EpgHandlers.HandleEvent(pEvent);
+
+      if (EpgHandlers.DeleteEvent(pEvent)) {
+         pSchedule->DelEvent(pEvent);
+         pEvent = NULL;
+         }
       }
   if (Tid == 0x4E) {
      if (Empty && getSectionNumber() == 0)
diff -ruN vdr-1.7.27/eitscan.c vdr-1.7.28/eitscan.c
--- vdr-1.7.27/eitscan.c	2012-03-07 14:54:34.000000000 +0100
+++ vdr-1.7.28/eitscan.c	2012-04-07 16:39:28.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: eitscan.c 2.6 2012/03/07 13:54:34 kls Exp $
+ * $Id: eitscan.c 2.7 2012/04/07 14:39:28 kls Exp $
  */
 
 #include "eitscan.h"
@@ -148,7 +148,7 @@
                       if (Channel) {
                          if (!Channel->Ca() || Channel->Ca() == Device->DeviceNumber() + 1 || Channel->Ca() >= CA_ENCRYPTED_MIN) {
                             if (Device->ProvidesTransponder(Channel)) {
-                               if (!Device->Receiving()) {
+                               if (Device->Priority() < 0) {
                                   bool MaySwitchTransponder = Device->MaySwitchTransponder(Channel);
                                   if (MaySwitchTransponder || Device->ProvidesTransponderExclusively(Channel) && now - lastActivity > Setup.EPGScanTimeout * 3600) {
                                      if (!MaySwitchTransponder) {
diff -ruN vdr-1.7.27/epg.c vdr-1.7.28/epg.c
--- vdr-1.7.27/epg.c	2012-03-10 14:14:27.000000000 +0100
+++ vdr-1.7.28/epg.c	2012-06-02 16:08:12.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 2.12 2012/03/10 13:14:27 kls Exp $
+ * $Id: epg.c 2.14 2012/06/02 14:08:12 kls Exp $
  */
 
 #include "epg.h"
@@ -1125,7 +1125,7 @@
 // --- cSchedules ------------------------------------------------------------
 
 cSchedules cSchedules::schedules;
-const char *cSchedules::epgDataFileName = NULL;
+char *cSchedules::epgDataFileName = NULL;
 time_t cSchedules::lastCleanup = time(NULL);
 time_t cSchedules::lastDump = time(NULL);
 time_t cSchedules::modified = 0;
@@ -1137,7 +1137,7 @@
 
 void cSchedules::SetEpgDataFileName(const char *FileName)
 {
-  delete epgDataFileName;
+  free(epgDataFileName);
   epgDataFileName = FileName ? strdup(FileName) : NULL;
 }
 
@@ -1429,6 +1429,15 @@
       }
 }
 
+bool cEpgHandlers::DeleteEvent(const cEvent *Event)
+{
+  for (cEpgHandler *eh = First(); eh; eh = Next(eh)) {
+      if (eh->DeleteEvent(Event))
+         return true;
+      }
+  return false;
+}
+
 void cEpgHandlers::SortSchedule(cSchedule *Schedule)
 {
   for (cEpgHandler *eh = First(); eh; eh = Next(eh)) {
diff -ruN vdr-1.7.27/epg.h vdr-1.7.28/epg.h
--- vdr-1.7.27/epg.h	2012-03-10 14:50:10.000000000 +0100
+++ vdr-1.7.28/epg.h	2012-06-02 16:07:51.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.h 2.8 2012/03/10 13:50:10 kls Exp $
+ * $Id: epg.h 2.10 2012/06/02 14:07:51 kls Exp $
  */
 
 #ifndef __EPG_H
@@ -192,7 +192,7 @@
 private:
   cRwLock rwlock;
   static cSchedules schedules;
-  static const char *epgDataFileName;
+  static char *epgDataFileName;
   static time_t lastCleanup;
   static time_t lastDump;
   static time_t modified;
@@ -258,6 +258,9 @@
   virtual bool HandleEvent(cEvent *Event) { return false; }
           ///< After all modifications of the Event have been done, the EPG handler
           ///< can take a final look at it.
+  virtual bool DeleteEvent(const cEvent *Event) { return false; }
+          ///< After the complete processing of the Event is finished, an EPG handler
+          ///< can decide that this Event shall be deleted from its schedule.
   virtual bool SortSchedule(cSchedule *Schedule) { return false; }
           ///< Sorts the Schedule after the complete table has been processed.
   virtual bool DropOutdated(cSchedule *Schedule, time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version) { return false; }
@@ -280,6 +283,7 @@
   void SetVps(cEvent *Event, time_t Vps);
   void FixEpgBugs(cEvent *Event);
   void HandleEvent(cEvent *Event);
+  bool DeleteEvent(const cEvent *Event);
   void SortSchedule(cSchedule *Schedule);
   void DropOutdated(cSchedule *Schedule, time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version);
   };
diff -ruN vdr-1.7.27/font.c vdr-1.7.28/font.c
--- vdr-1.7.27/font.c	2012-03-02 11:47:45.000000000 +0100
+++ vdr-1.7.28/font.c	2012-06-02 15:38:28.000000000 +0200
@@ -6,7 +6,7 @@
  *
  * BiDi support by Osama Alrawab <alrawab@hotmail.com> @2008 Tripoli-Libya.
  *
- * $Id: font.c 2.10 2012/03/02 10:47:45 kls Exp $
+ * $Id: font.c 2.13 2012/06/02 13:38:28 kls Exp $
  */
 
 #include "font.h"
@@ -412,7 +412,7 @@
   if (!fonts[Font]) {
      switch (Font) {
        case fontOsd: SetFont(Font, Setup.FontOsd, Setup.FontOsdSize); break;
-       case fontSml: SetFont(Font, Setup.FontSml, Setup.FontSmlSize); break;
+       case fontSml: SetFont(Font, Setup.FontSml, min(Setup.FontSmlSize, Setup.FontOsdSize)); break;
        case fontFix: SetFont(Font, Setup.FontFix, Setup.FontFixSize); break;
        default: esyslog("ERROR: unknown Font %d (%s %d)", Font, __FUNCTION__, __LINE__);
        }
@@ -482,7 +482,8 @@
      FcPatternAddBool(pat, FC_SCALABLE, FcTrue);
      FcConfigSubstitute(NULL, pat, FcMatchPattern);
      FcDefaultSubstitute(pat);
-     FcFontSet *fontset = FcFontSort(NULL, pat, FcFalse, NULL, NULL);
+     FcResult fresult;
+     FcFontSet *fontset = FcFontSort(NULL, pat, FcFalse, NULL, &fresult);
      if (fontset) {
         for (int i = 0; i < fontset->nfont; i++) {
             FcBool scalable;
@@ -508,7 +509,7 @@
 #ifdef BIDI
 cString cFont::Bidi(const char *Ltr)
 {
-  if (cCharSetConv::SystemCharacterTable()) { // bidi requires UTF-8
+  if (!cCharSetConv::SystemCharacterTable()) { // bidi requires UTF-8
      fribidi_set_mirroring(true);
      fribidi_set_reorder_nsm(false);
      FriBidiCharSet fribidiCharset = FRIBIDI_CHAR_SET_UTF8;
diff -ruN vdr-1.7.27/menu.c vdr-1.7.28/menu.c
--- vdr-1.7.27/menu.c	2012-03-13 14:14:38.000000000 +0100
+++ vdr-1.7.28/menu.c	2012-05-12 15:08:23.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 2.45 2012/03/13 13:14:38 kls Exp $
+ * $Id: menu.c 2.54 2012/05/12 13:08:23 kls Exp $
  */
 
 #include "menu.h"
@@ -34,7 +34,6 @@
 
 #define MAXWAIT4EPGINFO   3 // seconds
 #define MODETIMEOUT       3 // seconds
-#define DISKSPACECHEK     5 // seconds between disk space checks
 #define NEWTIMERLIMIT   120 // seconds until the start time of a new timer created from the Schedule menu,
                             // within which it will go directly into the "Edit timer" menu to allow
                             // further parameter settings
@@ -47,50 +46,10 @@
 #define CAMRESPONSETIMEOUT  5 // seconds to wait for a response from a CAM
 #define MINFREEDISK       300 // minimum free disk space (in MB) required to start recording
 #define NODISKSPACEDELTA  300 // seconds between "Not enough disk space to start recording!" messages
+#define MAXCHNAMWIDTH      16 // maximum number of characters of channels' short names shown in schedules menus
 
 #define CHNUMWIDTH  (numdigits(Channels.MaxNumber()) + 1)
-#define CHNAMWIDTH  (Channels.MaxShortChannelNameLength() + 1)
-
-// --- cFreeDiskSpace --------------------------------------------------------
-
-#define MB_PER_MINUTE 25.75 // this is just an estimate!
-
-class cFreeDiskSpace {
-private:
-  static time_t lastDiskSpaceCheck;
-  static int lastFreeMB;
-  static cString freeDiskSpaceString;
-public:
-  static bool HasChanged(bool ForceCheck = false);
-  static const char *FreeDiskSpaceString(void) { HasChanged(); return freeDiskSpaceString; }
-  };
-
-time_t cFreeDiskSpace::lastDiskSpaceCheck = 0;
-int cFreeDiskSpace::lastFreeMB = 0;
-cString cFreeDiskSpace::freeDiskSpaceString;
-
-cFreeDiskSpace FreeDiskSpace;
-
-bool cFreeDiskSpace::HasChanged(bool ForceCheck)
-{
-  if (ForceCheck || time(NULL) - lastDiskSpaceCheck > DISKSPACECHEK) {
-     int FreeMB;
-     int Percent = VideoDiskSpace(&FreeMB);
-     lastDiskSpaceCheck = time(NULL);
-     if (ForceCheck || FreeMB != lastFreeMB) {
-        int MBperMinute = Recordings.MBperMinute();
-        if (MBperMinute <= 0)
-           MBperMinute = MB_PER_MINUTE;
-        int Minutes = int(double(FreeMB) / MBperMinute);
-        int Hours = Minutes / 60;
-        Minutes %= 60;
-        freeDiskSpaceString = cString::sprintf("%s %d%%  -  %2d:%02d %s", tr("Disk"), Percent, Hours, Minutes, tr("free"));
-        lastFreeMB = FreeMB;
-        return true;
-        }
-     }
-  return false;
-}
+#define CHNAMWIDTH  (min(MAXCHNAMWIDTH, Channels.MaxShortChannelNameLength() + 1))
 
 // --- cMenuEditCaItem -------------------------------------------------------
 
@@ -213,6 +172,7 @@
 cMenuEditChannel::cMenuEditChannel(cChannel *Channel, bool New)
 :cOsdMenu(tr("Edit channel"), 16)
 {
+  SetMenuCategory(mcChannel);
   channel = Channel;
   sourceParam = NULL;
   *name = 0;
@@ -390,6 +350,7 @@
 cMenuChannels::cMenuChannels(void)
 :cOsdMenu(tr("Channels"), CHNUMWIDTH)
 {
+  SetMenuCategory(mcChannel);
   number = 0;
   Setup();
   Channels.IncBeingEdited();
@@ -585,6 +546,7 @@
 cMenuText::cMenuText(const char *Title, const char *Text, eDvbFont Font)
 :cOsdMenu(Title)
 {
+  SetMenuCategory(mcText);
   text = NULL;
   font = Font;
   SetText(Text);
@@ -673,6 +635,7 @@
 cMenuEditFolder::cMenuEditFolder(const char *Dir, cList<cNestedItem> *List, cNestedItem *Folder)
 :cOsdMenu(Folder ? tr("Edit folder") : tr("New folder"), 12)
 {
+  SetMenuCategory(mcFolder);
   list = List;
   folder = Folder;
   if (folder) {
@@ -745,6 +708,7 @@
 cMenuFolder::cMenuFolder(const char *Title, cNestedItemList *NestedItemList, const char *Path)
 :cOsdMenu(Title)
 {
+  SetMenuCategory(mcFolder);
   list = nestedItemList = NestedItemList;
   firstFolder = NULL;
   editing = false;
@@ -756,6 +720,7 @@
 cMenuFolder::cMenuFolder(const char *Title, cList<cNestedItem> *List, cNestedItemList *NestedItemList, const char *Dir, const char *Path)
 :cOsdMenu(Title)
 {
+  SetMenuCategory(mcFolder);
   list = List;
   nestedItemList = NestedItemList;
   dir = Dir;
@@ -906,6 +871,7 @@
 cMenuEditTimer::cMenuEditTimer(cTimer *Timer, bool New)
 :cOsdMenu(tr("Edit timer"), 12)
 {
+  SetMenuCategory(mcTimer);
   file = NULL;
   day = firstday = NULL;
   timer = Timer;
@@ -1104,6 +1070,7 @@
 cMenuTimers::cMenuTimers(void)
 :cOsdMenu(tr("Timers"), 2, CHNUMWIDTH, 10, 6, 6)
 {
+  SetMenuCategory(mcTimer);
   helpKeys = -1;
   for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) {
       timer->SetEventFromSchedule(); // make sure the event is current
@@ -1242,6 +1209,7 @@
 cMenuEvent::cMenuEvent(const cEvent *Event, bool CanSwitch, bool Buttons)
 :cOsdMenu(tr("Event"))
 {
+  SetMenuCategory(mcEvent);
   event = Event;
   if (event) {
      cChannel *channel = Channels.GetByChannelID(event->ChannelID(), true);
@@ -1389,6 +1357,7 @@
 cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr)
 :cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, CHNAMWIDTH, 6, 4)
 {
+  SetMenuCategory(mcSchedule);
   now = Now;
   helpKeys = -1;
   timerState = 0;
@@ -1553,6 +1522,7 @@
 cMenuSchedule::cMenuSchedule(void)
 :cOsdMenu("")
 {
+  SetMenuCategory(mcSchedule);
   now = next = false;
   otherChannel = 0;
   helpKeys = -1;
@@ -1810,6 +1780,7 @@
 cMenuCommands::cMenuCommands(const char *Title, cList<cNestedItem> *Commands, const char *Parameters)
 :cOsdMenu(Title)
 {
+  SetMenuCategory(mcCommand);
   result = NULL;
   SetHasHotkeys();
   commands = Commands;
@@ -1939,6 +1910,7 @@
 cMenuCam::cMenuCam(cCamSlot *CamSlot)
 :cOsdMenu("", 1) // tab necessary for enquiry!
 {
+  SetMenuCategory(mcCam);
   camSlot = CamSlot;
   ciMenu = NULL;
   ciEnquiry = NULL;
@@ -2118,6 +2090,7 @@
 cMenuRecording::cMenuRecording(const cRecording *Recording, bool WithButtons)
 :cOsdMenu(tr("Recording info"))
 {
+  SetMenuCategory(mcRecording);
   recording = Recording;
   withButtons = WithButtons;
   if (withButtons)
@@ -2212,13 +2185,13 @@
 cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus)
 :cOsdMenu(Base ? Base : tr("Recordings"), 9, 6, 6)
 {
+  SetMenuCategory(mcRecording);
   base = Base ? strdup(Base) : NULL;
   level = Setup.RecordingDirs ? Level : -1;
   Recordings.StateChanged(recordingsState); // just to get the current state
   helpKeys = -1;
   Display(); // this keeps the higher level menus from showing up briefly when pressing 'Back' during replay
   Set();
-  SetFreeDiskDisplay(true);
   if (Current() < 0)
      SetCurrent(First());
   else if (OpenSubMenus && cReplayControl::LastReplayed() && Open(true))
@@ -2233,16 +2206,6 @@
   free(base);
 }
 
-bool cMenuRecordings::SetFreeDiskDisplay(bool Force)
-{
-  if (FreeDiskSpace.HasChanged(Force)) {
-     //XXX -> skin function!!!
-     SetTitle(cString::sprintf("%s  -  %s", base ? base : tr("Recordings"), FreeDiskSpace.FreeDiskSpaceString()));
-     return true;
-     }
-  return false;
-}
-
 void cMenuRecordings::SetHelpKeys(void)
 {
   cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
@@ -2305,7 +2268,6 @@
          }
       }
   free(LastItemText);
-  Refresh |= SetFreeDiskDisplay(Refresh);
   if (Refresh)
      Display();
 }
@@ -2343,7 +2305,7 @@
      else {
         cRecording *recording = GetRecording(ri);
         if (recording) {
-           cReplayControl::SetRecording(recording->FileName(), recording->Title());
+           cReplayControl::SetRecording(recording->FileName());
            return osReplay;
            }
         }
@@ -2411,7 +2373,7 @@
               Recordings.DelByName(ri->FileName());
               cOsdMenu::Del(Current());
               SetHelpKeys();
-              SetFreeDiskDisplay(true);
+              cVideoDiskUsage::ForceCheck();
               Display();
               if (!Count())
                  return osBack;
@@ -2484,8 +2446,6 @@
      Display();
      }
   if (!HasSubMenu()) {
-     if (HadSubMenu)
-        SetFreeDiskDisplay();
      if (Key != kNone)
         SetHelpKeys();
      }
@@ -2767,6 +2727,7 @@
   void Setup(void);
   const char *videoDisplayFormatTexts[3];
   const char *updateChannelsTexts[6];
+  const char *standardComplianceTexts[2];
 public:
   cMenuSetupDVB(void);
   virtual eOSState ProcessKey(eKeys Key);
@@ -2789,6 +2750,8 @@
   updateChannelsTexts[3] = tr("names and PIDs");
   updateChannelsTexts[4] = tr("add new channels");
   updateChannelsTexts[5] = tr("add new transponders");
+  standardComplianceTexts[0] = "DVB";
+  standardComplianceTexts[1] = "ANSI/SCTE";
 
   SetSection(tr("DVB"));
   SetHelp(NULL, tr("Button$Audio"), tr("Button$Subtitles"), NULL); 
@@ -2802,6 +2765,7 @@
   Clear();
 
   Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDevice::NumDevices()));
+  Add(new cMenuEditStraItem(tr("Setup.DVB$Standard compliance"),   &data.StandardCompliance, 2, standardComplianceTexts));
   Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"),          &data.VideoFormat, "4:3", "16:9"));
   if (data.VideoFormat == 0)
      Add(new cMenuEditStraItem(tr("Setup.DVB$Video display format"), &data.VideoDisplayFormat, 3, videoDisplayFormatTexts));
@@ -3222,8 +3186,13 @@
               }
            }
         }
-     else if (state == osContinue)
+     else if (state == osContinue) {
         Store();
+        // Reinitialize OSD and skin, in case any plugin setup change has an influence on these:
+        cOsdProvider::UpdateOsdSize(true);
+        SetDisplayMenu();
+        Display();
+        }
      }
   return state;
 }
@@ -3242,6 +3211,7 @@
 cMenuSetup::cMenuSetup(void)
 :cOsdMenu("")
 {
+  SetMenuCategory(mcSetup);
   Set();
 }
 
@@ -3326,6 +3296,7 @@
 cMenuMain::cMenuMain(eOSState State)
 :cOsdMenu("")
 {
+  SetMenuCategory(mcMain);
   replaying = false;
   stopReplayItem = NULL;
   cancelEditingItem = NULL;
@@ -3394,13 +3365,6 @@
 {
   bool result = false;
 
-  // Title with disk usage:
-  if (FreeDiskSpace.HasChanged(Force)) {
-     //XXX -> skin function!!!
-     SetTitle(cString::sprintf("%s  -  %s", tr("VDR"), FreeDiskSpace.FreeDiskSpaceString()));
-     result = true;
-     }
-
   bool NewReplaying = cControl::Control() != NULL;
   if (Force || NewReplaying != replaying) {
      replaying = NewReplaying;
@@ -4130,6 +4094,8 @@
 
 cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)
 {
+  // Whatever happens here, the timers will be modified in some way...
+  Timers.SetModified();
   // We're going to manipulate an event here, so we need to prevent
   // others from modifying any EPG data:
   cSchedulesLock SchedulesLock;
@@ -4144,7 +4110,6 @@
   if (!timer) {
      timer = new cTimer(true, Pause);
      Timers.Add(timer);
-     Timers.SetModified();
      instantId = cString::sprintf(cDevice::NumDevices() > 1 ? "%s - %d" : "%s", timer->Channel()->Name(), device->CardIndex() + 1);
      }
   timer->SetPending(true);
@@ -4166,9 +4131,8 @@
         }
      else {
         Timers.Del(timer);
-        Timers.SetModified();
         if (!cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
-           cReplayControl::SetRecording(fileName, Recording.Name());
+           cReplayControl::SetRecording(fileName);
         }
      timer = NULL;
      return;
@@ -4183,7 +4147,7 @@
         Recording.WriteInfo();
         cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), true);
         if (!Timer && !cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
-           cReplayControl::SetRecording(fileName, Recording.Name());
+           cReplayControl::SetRecording(fileName);
         Recordings.AddByName(fileName);
         return;
         }
@@ -4194,7 +4158,6 @@
      timer->SetDeferred(DEFERTIMER);
   if (!Timer) {
      Timers.Del(timer);
-     Timers.SetModified();
      timer = NULL;
      }
 }
@@ -4244,6 +4207,7 @@
      cStatus::MsgRecording(device, NULL, fileName, false);
      if (ExecuteUserCommand)
         cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName);
+     Timers.SetModified();
      }
 }
 
@@ -4337,7 +4301,7 @@
 bool cRecordControls::PauseLiveVideo(void)
 {
   Skins.Message(mtStatus, tr("Pausing live video..."));
-  cReplayControl::SetRecording(NULL, NULL); // make sure the new cRecordControl will set cReplayControl::LastReplayed()
+  cReplayControl::SetRecording(NULL); // make sure the new cRecordControl will set cReplayControl::LastReplayed()
   if (Start(NULL, true)) {
      cReplayControl *rc = new cReplayControl(true);
      cControl::Launch(rc);
@@ -4373,6 +4337,15 @@
   return NULL;
 }
 
+cRecordControl *cRecordControls::GetRecordControl(const cTimer *Timer)
+{
+  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
+      if (RecordControls[i] && RecordControls[i]->Timer() == Timer)
+         return RecordControls[i];
+      }
+  return NULL;
+}
+
 void cRecordControls::Process(time_t t)
 {
   for (int i = 0; i < MAXRECORDCONTROLS; i++) {
@@ -4429,8 +4402,7 @@
 // --- cReplayControl --------------------------------------------------------
 
 cReplayControl *cReplayControl::currentReplayControl = NULL;
-char *cReplayControl::fileName = NULL;
-char *cReplayControl::title = NULL;
+cString cReplayControl::fileName;
 
 cReplayControl::cReplayControl(bool PauseLive)
 :cDvbPlayerControl(fileName, PauseLive)
@@ -4460,7 +4432,7 @@
 
 void cReplayControl::Stop(void)
 {
-  if (Setup.DelTimeshiftRec && fileName) {
+  if (Setup.DelTimeshiftRec && *fileName) {
      cRecordControl* rc = cRecordControls::GetRecordControl(fileName);
      if (rc && rc->InstantId()) {
         if (Active()) {
@@ -4473,7 +4445,7 @@
                  Timers.SetModified();
                  }
               cDvbPlayerControl::Stop();
-              cRecording *recording = Recordings.GetByName(fileName);;
+              cRecording *recording = Recordings.GetByName(fileName);
               if (recording) {
                  if (recording->Delete()) {
                     Recordings.DelByName(fileName);
@@ -4490,17 +4462,14 @@
   cDvbPlayerControl::Stop();
 }
 
-void cReplayControl::SetRecording(const char *FileName, const char *Title)
+void cReplayControl::SetRecording(const char *FileName)
 {
-  free(fileName);
-  free(title);
-  fileName = FileName ? strdup(FileName) : NULL;
-  title = Title ? strdup(Title) : NULL;
+  fileName = FileName;
 }
 
 const char *cReplayControl::NowReplaying(void)
 {
-  return currentReplayControl ? fileName : NULL;
+  return currentReplayControl ? *fileName : NULL;
 }
 
 const char *cReplayControl::LastReplayed(void)
@@ -4510,10 +4479,8 @@
 
 void cReplayControl::ClearLastReplayed(const char *FileName)
 {
-  if (fileName && FileName && strcmp(fileName, FileName) == 0) {
-     free(fileName);
+  if (*fileName && FileName && strcmp(fileName, FileName) == 0)
      fileName = NULL;
-     }
 }
 
 void cReplayControl::ShowTimed(int Seconds)
@@ -4585,8 +4552,10 @@
         visible = true;
         }
      if (Initial) {
-        if (title)
-           displayReplay->SetTitle(title);
+        if (*fileName) {
+           if (cRecording *Recording = Recordings.GetByName(fileName))
+              displayReplay->SetRecording(Recording);
+           }
         lastCurrent = lastTotal = -1;
         }
      if (Current != lastCurrent || Total != lastTotal) {
@@ -4758,7 +4727,7 @@
 
 void cReplayControl::EditCut(void)
 {
-  if (fileName) {
+  if (*fileName) {
      Hide();
      if (!cCutter::Active()) {
         if (!marks.Count())
@@ -4800,6 +4769,13 @@
   return NULL;
 }
 
+const cRecording *cReplayControl::GetRecording(void)
+{
+  if (const cRecording *Recording = Recordings.GetByName(LastReplayed()))
+     return Recording;
+  return NULL;
+}
+
 eOSState cReplayControl::ProcessKey(eKeys Key)
 {
   if (!Active())
diff -ruN vdr-1.7.27/menu.h vdr-1.7.28/menu.h
--- vdr-1.7.27/menu.h	2012-03-08 14:11:40.000000000 +0100
+++ vdr-1.7.28/menu.h	2012-05-12 13:48:04.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: menu.h 2.5 2012/03/08 13:11:40 kls Exp $
+ * $Id: menu.h 2.9 2012/05/12 11:48:04 kls Exp $
  */
 
 #ifndef __MENU_H
@@ -196,7 +196,6 @@
   int level;
   int recordingsState;
   int helpKeys;
-  bool SetFreeDiskDisplay(bool Force = false);
   void SetHelpKeys(void);
   void Set(bool Refresh = false);
   bool Open(bool OpenSubMenus = false);
@@ -243,6 +242,9 @@
   static bool PauseLiveVideo(void);
   static const char *GetInstantId(const char *LastInstantId);
   static cRecordControl *GetRecordControl(const char *FileName);
+  static cRecordControl *GetRecordControl(const cTimer *Timer);
+         ///< Returns the cRecordControl for the given Timer.
+         ///< If there is no cRecordControl for Timer, NULL is returned.
   static void Process(time_t t);
   static void ChannelDataModified(cChannel *Channel);
   static bool Active(void);
@@ -267,8 +269,7 @@
   void TimeSearch(void);
   void ShowTimed(int Seconds = 0);
   static cReplayControl *currentReplayControl;
-  static char *fileName;
-  static char *title;
+  static cString fileName;
   void ShowMode(void);
   bool ShowProgress(bool Initial);
   void MarkToggle(void);
@@ -281,11 +282,12 @@
   virtual ~cReplayControl();
   void Stop(void);
   virtual cOsdObject *GetInfo(void);
+  virtual const cRecording *GetRecording(void);
   virtual eOSState ProcessKey(eKeys Key);
   virtual void Show(void);
   virtual void Hide(void);
   bool Visible(void) { return visible; }
-  static void SetRecording(const char *FileName, const char *Title);
+  static void SetRecording(const char *FileName);
   static const char *NowReplaying(void);
   static const char *LastReplayed(void);
   static void ClearLastReplayed(const char *FileName);
diff -ruN vdr-1.7.27/menuitems.c vdr-1.7.28/menuitems.c
--- vdr-1.7.27/menuitems.c	2012-03-13 12:21:57.000000000 +0100
+++ vdr-1.7.28/menuitems.c	2012-04-08 13:20: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.c 2.13 2012/03/13 11:21:57 kls Exp $
+ * $Id: menuitems.c 2.14 2012/04/08 11:20:37 kls Exp $
  */
 
 #include "menuitems.h"
@@ -1126,6 +1126,7 @@
 cMenuSetupPage::cMenuSetupPage(void)
 :cOsdMenu("", 33)
 {
+  SetMenuCategory(mcSetup);
   plugin = NULL;
 }
 
diff -ruN vdr-1.7.27/osd.c vdr-1.7.28/osd.c
--- vdr-1.7.27/osd.c	2012-03-05 11:28:01.000000000 +0100
+++ vdr-1.7.28/osd.c	2012-06-02 15:32:38.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 2.27 2012/03/05 10:28:01 kls Exp $
+ * $Id: osd.c 2.31 2012/06/02 13:32:38 kls Exp $
  */
 
 #include "osd.h"
@@ -40,6 +40,16 @@
      }
 }
 
+tColor RgbShade(tColor Color, double Factor)
+{
+  double f = fabs(constrain(Factor, -1.0, 1.0));
+  double w = Factor > 0 ? f * 0xFF : 0;
+  return (Color & 0xFF000000) |
+         (min(0xFF, int((1 - f) * ((Color >> 16) & 0xFF) + w + 0.5)) << 16) |
+         (min(0xFF, int((1 - f) * ((Color >>  8) & 0xFF) + w + 0.5)) <<  8) |
+         (min(0xFF, int((1 - f) * ( Color        & 0xFF) + w + 0.5))      );
+}
+
 #define USE_ALPHA_LUT
 #ifdef USE_ALPHA_LUT
 // Alpha blending with lookup table (by Reinhard Nissl <rnissl@gmx.de>)
@@ -553,11 +563,15 @@
      if (Width || Height) {
         limit = x + cw - x0;
         if (Width) {
-           if ((Alignment & taLeft) != 0)
-              ;
+           if ((Alignment & taLeft) != 0) {
+              if ((Alignment & taBorder) != 0)
+                 x += max(h / TEXT_ALIGN_BORDER, 1);
+              }
            else if ((Alignment & taRight) != 0) {
               if (w < Width)
                  x += Width - w;
+              if ((Alignment & taBorder) != 0)
+                 x -= max(h / TEXT_ALIGN_BORDER, 1);
               }
            else { // taCentered
               if (w < Width)
@@ -1280,11 +1294,15 @@
   if (Width || Height) {
      limit = x + cw;
      if (Width) {
-        if ((Alignment & taLeft) != 0)
-           ;
+        if ((Alignment & taLeft) != 0) {
+           if ((Alignment & taBorder) != 0)
+              x += max(h / TEXT_ALIGN_BORDER, 1);
+           }
         else if ((Alignment & taRight) != 0) {
            if (w < Width)
               x += Width - w;
+           if ((Alignment & taBorder) != 0)
+              x -= max(h / TEXT_ALIGN_BORDER, 1);
            }
         else { // taCentered
            if (w < Width)
@@ -1382,10 +1400,10 @@
           case  0:
           case  6: DrawRectangle(cRect(cx - x, cy - y, 2 * x + 1,       1), Color); if (Quadrants == 6) break;
           case  8: DrawRectangle(cRect(cx - x, cy + y, 2 * x + 1,       1), Color); break;
-          case -1: DrawRectangle(cRect(cx + x, cy - y, x2 - x + 1,      1), Color); break;
+          case -1: DrawRectangle(cRect(cx + x, cy - y, rx - x + 1,      1), Color); break;
           case -2: DrawRectangle(cRect(x1,     cy - y, cx - x - x1 + 1, 1), Color); break;
           case -3: DrawRectangle(cRect(x1,     cy + y, cx - x - x1 + 1, 1), Color); break;
-          case -4: DrawRectangle(cRect(cx + x, cy + y, x2 - x + 1,      1), Color); break;
+          case -4: DrawRectangle(cRect(cx + x, cy + y, rx - x + 1,      1), Color); break;
           default: ;
           }
         y++;
@@ -1417,10 +1435,10 @@
           case  0:
           case  6: DrawRectangle(cRect(cx - x, cy - y, 2 * x + 1,       1), Color); if (Quadrants == 6) break;
           case  8: DrawRectangle(cRect(cx - x, cy + y, 2 * x + 1,       1), Color); break;
-          case -1: DrawRectangle(cRect(cx + x, cy - y, x2 - x + 1,      1), Color); break;
+          case -1: DrawRectangle(cRect(cx + x, cy - y, rx - x + 1,      1), Color); break;
           case -2: DrawRectangle(cRect(x1,     cy - y, cx - x - x1 + 1, 1), Color); break;
           case -3: DrawRectangle(cRect(x1,     cy + y, cx - x - x1 + 1, 1), Color); break;
-          case -4: DrawRectangle(cRect(cx + x, cy + y, x2 - x + 1,      1), Color); break;
+          case -4: DrawRectangle(cRect(cx + x, cy + y, rx - x + 1,      1), Color); break;
           default: ;
           }
         x++;
@@ -1988,7 +2006,7 @@
      Setup.FontSmlSize = int(round(Height * Setup.FontSmlSizeP));
      cFont::SetFont(fontOsd, Setup.FontOsd, Setup.FontOsdSize);
      cFont::SetFont(fontFix, Setup.FontFix, Setup.FontFixSize);
-     cFont::SetFont(fontSml, Setup.FontSml, Setup.FontSmlSize);
+     cFont::SetFont(fontSml, Setup.FontSml, min(Setup.FontSmlSize, Setup.FontOsdSize));
      oldWidth = Width;
      oldHeight = Height;
      oldAspect = Aspect;
diff -ruN vdr-1.7.27/osd.h vdr-1.7.28/osd.h
--- vdr-1.7.27/osd.h	2011-12-04 14:38:17.000000000 +0100
+++ vdr-1.7.28/osd.h	2012-06-02 12:32:38.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 2.15 2011/12/04 13:38:17 kls Exp $
+ * $Id: osd.h 2.17 2012/06/02 10:32:38 kls Exp $
  */
 
 #ifndef __OSD_H
@@ -25,6 +25,7 @@
 #define ALPHA_TRANSPARENT  0x00
 #define ALPHA_OPAQUE       0xFF
 #define IS_OPAQUE(c)       ((c >> 24) == ALPHA_OPAQUE)
+#define TEXT_ALIGN_BORDER  10 // fraction of the font height used for sizing border
 
 enum {
                    //AARRGGBB
@@ -69,6 +70,14 @@
   return RgbToColor(uint8_t(0xFF * R), uint8_t(0xFF * G), uint8_t(0xFF * B));
 }
 
+tColor RgbShade(tColor Color, double Factor);
+   ///< Returns a brighter (Factor > 0) or darker (Factor < 0) version
+   ///< of the given Color.
+   ///< If Factor is 0.0, the return value is the unchanged Color,
+   ///< If Factor is 1.0, white is returned.
+   ///< If Factor is -1.0, black is returned.
+   ///< The alpha value of Color is returned unchanged.
+
 tColor HsvToColor(double H, double S, double V);
    ///< Converts the given Hue (0..360), Saturation (0..1) and Value (0..1)
    ///< to an RGB tColor value. The alpha value of the result is 0x00, so
@@ -151,6 +160,7 @@
                       taRight   = 0x02,
                       taTop     = 0x04,
                       taBottom  = 0x08,
+                      taBorder  = 0x10, // keeps some distance from the left or right alignment edge
                       taDefault = taTop | taLeft
                     };
 
diff -ruN vdr-1.7.27/osdbase.c vdr-1.7.28/osdbase.c
--- vdr-1.7.27/osdbase.c	2012-03-02 16:49:57.000000000 +0100
+++ vdr-1.7.28/osdbase.c	2012-04-23 11:41:22.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 2.4 2012/03/02 15:49:57 kls Exp $
+ * $Id: osdbase.c 2.6 2012/04/23 09:41:22 kls Exp $
  */
 
 #include "osdbase.h"
@@ -72,14 +72,15 @@
 
 cSkinDisplayMenu *cOsdMenu::displayMenu = NULL;
 int cOsdMenu::displayMenuCount = 0;
-int cOsdMenu::displayMenuItems = 0;//XXX dynamic???
 
 cOsdMenu::cOsdMenu(const char *Title, int c0, int c1, int c2, int c3, int c4)
 {
   isMenu = true;
   digit = 0;
   hasHotkeys = false;
+  displayMenuItems = 0;
   title = NULL;
+  menuCategory = mcUnknown;
   SetTitle(Title);
   SetCols(c0, c1, c2, c3, c4);
   first = 0;
@@ -103,6 +104,11 @@
      DELETENULL(displayMenu);
 }
 
+void cOsdMenu::SetMenuCategory(eMenuCategory MenuCategory)
+{
+  menuCategory = MenuCategory;
+}
+
 void cOsdMenu::SetDisplayMenu(void)
 {
   if (displayMenu) {
@@ -110,7 +116,6 @@
      delete displayMenu;
      }
   displayMenu = Skins.Current()->DisplayMenu();
-  displayMenuItems = displayMenu->MaxItems();
 }
 
 const char *cOsdMenu::hk(const char *s)
@@ -212,6 +217,9 @@
   displayMenu->SetMessage(mtStatus, NULL);
   displayMenu->Clear();
   cStatus::MsgOsdClear();
+  if (menuCategory != displayMenu->MenuCategory())
+     displayMenu->SetMenuCategory(menuCategory);
+  displayMenuItems = displayMenu->MaxItems();
   displayMenu->SetTabs(cols[0], cols[1], cols[2], cols[3], cols[4]);//XXX
   displayMenu->SetTitle(title);
   cStatus::MsgOsdTitle(title);
diff -ruN vdr-1.7.27/osdbase.h vdr-1.7.28/osdbase.h
--- vdr-1.7.27/osdbase.h	2012-03-02 16:49:57.000000000 +0100
+++ vdr-1.7.28/osdbase.h	2012-04-23 11:40:07.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 2.2 2012/03/02 15:49:57 kls Exp $
+ * $Id: osdbase.h 2.4 2012/04/23 09:40:07 kls Exp $
  */
 
 #ifndef __OSDBASE_H
@@ -86,10 +86,11 @@
 private:
   static cSkinDisplayMenu *displayMenu;
   static int displayMenuCount;
-  static int displayMenuItems;
+  int displayMenuItems;
   char *title;
   int cols[cSkinDisplayMenu::MaxTabs];
   int first, current, marked;
+  eMenuCategory menuCategory;
   cOsdMenu *subMenu;
   const char *helpRed, *helpGreen, *helpYellow, *helpBlue;
   bool helpDisplayed;
@@ -128,6 +129,7 @@
   cOsdMenu(const char *Title, int c0 = 0, int c1 = 0, int c2 = 0, int c3 = 0, int c4 = 0);
   virtual ~cOsdMenu();
   virtual bool NeedsFastResponse(void) { return subMenu ? subMenu->NeedsFastResponse() : cOsdObject::NeedsFastResponse(); }
+  void SetMenuCategory(eMenuCategory MenuCategory);
   int Current(void) const { return current; }
   void Add(cOsdItem *Item, bool Current = false, cOsdItem *After = NULL);
   void Ins(cOsdItem *Item, bool Current = false, cOsdItem *Before = NULL);
diff -ruN vdr-1.7.27/pat.c vdr-1.7.28/pat.c
--- vdr-1.7.27/pat.c	2012-03-02 11:56:45.000000000 +0100
+++ vdr-1.7.28/pat.c	2012-04-15 11:54:53.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: pat.c 2.17 2012/03/02 10:56:45 kls Exp $
+ * $Id: pat.c 2.18 2012/04/15 09:54:53 kls Exp $
  */
 
 #include "pat.h"
@@ -456,37 +456,47 @@
                          }
                       }
                       break;
-              case 0x80: // STREAMTYPE_USER_PRIVATE - DigiCipher II VIDEO (ANSI/SCTE 57)
-                      Vpid = esPid;
-                      Ppid = pmt.getPCRPid();
-                      Vtype = 0x02; // compression based upon MPEG-2
-                      ProcessCaDescriptors = true;
-                      break;
-              case 0x81: // STREAMTYPE_USER_PRIVATE - ATSC A/53 AUDIO (ANSI/SCTE 57)
-                      {
-                      char lang[MAXLANGCODE1] = { 0 };
-                      SI::Descriptor *d;
-                      for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
-                          switch (d->getDescriptorTag()) {
-                            case SI::ISO639LanguageDescriptorTag: {
-                                 SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d;
-                                 strn0cpy(lang, I18nNormalizeLanguageCode(ld->languageCode), MAXLANGCODE1);
-                                 }
-                                 break;
-                            default: ;
+              case 0x80: // STREAMTYPE_USER_PRIVATE
+                      if (Setup.StandardCompliance == STANDARD_ANSISCTE) { // DigiCipher II VIDEO (ANSI/SCTE 57)
+                         Vpid = esPid;
+                         Ppid = pmt.getPCRPid();
+                         Vtype = 0x02; // compression based upon MPEG-2
+                         ProcessCaDescriptors = true;
+                         break;
+                         }
+                      // fall through
+              case 0x81: // STREAMTYPE_USER_PRIVATE
+                      if (Setup.StandardCompliance == STANDARD_ANSISCTE) { // ATSC A/53 AUDIO (ANSI/SCTE 57)
+                         char lang[MAXLANGCODE1] = { 0 };
+                         SI::Descriptor *d;
+                         for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
+                             switch (d->getDescriptorTag()) {
+                               case SI::ISO639LanguageDescriptorTag: {
+                                    SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d;
+                                    strn0cpy(lang, I18nNormalizeLanguageCode(ld->languageCode), MAXLANGCODE1);
+                                    }
+                                    break;
+                               default: ;
+                               }
+                            delete d;
+                            }
+                         if (NumDpids < MAXDPIDS) {
+                            Dpids[NumDpids] = esPid;
+                            Dtypes[NumDpids] = SI::AC3DescriptorTag;
+                            strn0cpy(DLangs[NumDpids], lang, MAXLANGCODE1);
+                            NumDpids++;
                             }
-                         delete d;
+                         ProcessCaDescriptors = true;
+                         break;
                          }
-                      if (NumDpids < MAXDPIDS) {
-                         Dpids[NumDpids] = esPid;
-                         Dtypes[NumDpids] = SI::AC3DescriptorTag;
-                         strn0cpy(DLangs[NumDpids], lang, MAXLANGCODE1);
-                         NumDpids++;
+                      // fall through
+              case 0x82: // STREAMTYPE_USER_PRIVATE
+                      if (Setup.StandardCompliance == STANDARD_ANSISCTE) { // STANDARD SUBTITLE (ANSI/SCTE 27)
+                         //TODO
+                         break;
                          }
-                      ProcessCaDescriptors = true;
-                      }
-                      break;
-              case 0x82 ... 0xFF: // STREAMTYPE_USER_PRIVATE
+                      // fall through
+              case 0x83 ... 0xFF: // STREAMTYPE_USER_PRIVATE
                       {
                       char lang[MAXLANGCODE1] = { 0 };
                       bool IsAc3 = false;
diff -ruN vdr-1.7.27/player.c vdr-1.7.28/player.c
--- vdr-1.7.27/player.c	2007-07-20 17:25:24.000000000 +0200
+++ vdr-1.7.28/player.c	2012-04-28 13:52:50.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: player.c 2.0 2007/07/20 15:25:24 kls Exp $
+ * $Id: player.c 2.2 2012/04/28 11:52:50 kls Exp $
  */
 
 #include "player.h"
@@ -60,10 +60,20 @@
   return NULL;
 }
 
-cControl *cControl::Control(void)
+const cRecording *cControl::GetRecording(void)
+{
+  return NULL;
+}
+
+cString cControl::GetHeader(void)
+{
+  return "";
+}
+
+cControl *cControl::Control(bool Hidden)
 {
   cMutexLock MutexLock(&mutex);
-  return (control && !control->hidden) ? control : NULL;
+  return (control && (!control->hidden || Hidden)) ? control : NULL;
 }
 
 void cControl::Launch(cControl *Control)
diff -ruN vdr-1.7.27/player.h vdr-1.7.28/player.h
--- vdr-1.7.27/player.h	2009-03-08 13:29:10.000000000 +0100
+++ vdr-1.7.28/player.h	2012-04-28 15:04:17.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: player.h 2.4 2009/03/08 12:29:10 kls Exp $
+ * $Id: player.h 2.6 2012/04/28 13:04:17 kls Exp $
  */
 
 #ifndef __PLAYER_H
@@ -86,13 +86,28 @@
   virtual ~cControl();
   virtual void Hide(void) = 0;
   virtual cOsdObject *GetInfo(void);
+         ///< Returns an OSD object that displays information about the currently
+         ///< played programme. If no such information is available, NULL will be
+         ///< returned.
+  virtual const cRecording *GetRecording(void);
+         ///< Returns the cRecording that is currently being replayed, or NULL if
+         ///< this player is not playing a cRecording.
+  virtual cString GetHeader(void);
+         ///< This can be used by players that don't play a cRecording, but rather
+         ///< do something completely different. The resulting string may be used by
+         ///< skins as a last resort, in case they want to display the state of the
+         ///< current player. The return value is expected to be a short, single line
+         ///< string. The default implementation returns an empty string.
   double FramesPerSecond(void) { return player->FramesPerSecond(); }
   bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false) { return player->GetIndex(Current, Total, SnapToIFrame); }
   bool GetReplayMode(bool &Play, bool &Forward, int &Speed) { return player->GetReplayMode(Play, Forward, Speed); }
   static void Launch(cControl *Control);
   static void Attach(void);
   static void Shutdown(void);
-  static cControl *Control(void);
+  static cControl *Control(bool Hidden = false);
+         ///< Returns the current replay control (if any) in case it is currently
+         ///< visible. If Hidden is true, the control will be returned even if it is
+         ///< currently hidden.
   };
 
 #endif //__PLAYER_H
diff -ruN vdr-1.7.27/po/ar.po vdr-1.7.28/po/ar.po
--- vdr-1.7.27/po/ar.po	2012-03-11 11:44:44.000000000 +0100
+++ vdr-1.7.28/po/ar.po	2012-06-02 15:12:38.000000000 +0200
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.7.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2008-10-16 11:16-0400\n"
 "Last-Translator: Osama Alrawab <alrawab@hotmail.com>\n"
 "Language-Team: Arabic <ar@li.org>\n"
@@ -517,12 +517,6 @@
 msgid "Key$User9"
 msgstr "المستخدم 9"
 
-msgid "Disk"
-msgstr "القرص الصلب"
-
-msgid "free"
-msgstr "مساحة حرة"
-
 msgid "Free To Air"
 msgstr "غير مشفر"
 
@@ -944,6 +938,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "كرت الستالايت الاولى"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "نوع الفيديو  "
 
@@ -1174,9 +1171,6 @@
 msgid "Schedule"
 msgstr "جدولة"
 
-msgid "VDR"
-msgstr ""
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " ايقاف الاعادة"
@@ -1307,6 +1301,24 @@
 msgid "Classic VDR"
 msgstr "VDR تقليدى  "
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG شاشة "
 
@@ -1370,3 +1382,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "البرنامج سيقوم بالاغلاق بعد%s دقيقة "
+
+msgid "Disk"
+msgstr "القرص الصلب"
+
+msgid "free"
+msgstr "مساحة حرة"
diff -ruN vdr-1.7.27/po/ca_ES.po vdr-1.7.28/po/ca_ES.po
--- vdr-1.7.27/po/ca_ES.po	2012-03-11 11:44:43.000000000 +0100
+++ vdr-1.7.28/po/ca_ES.po	2012-06-02 15:13:00.000000000 +0200
@@ -10,7 +10,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2008-03-02 19:02+0100\n"
 "Last-Translator: Luca Olivetti <luca@ventoso.org>\n"
 "Language-Team: Catalan <vdr@linuxtv.org>\n"
@@ -512,12 +512,6 @@
 msgid "Key$User9"
 msgstr "Usuari 9"
 
-msgid "Disk"
-msgstr "Disc"
-
-msgid "free"
-msgstr "lliure"
-
 msgid "Free To Air"
 msgstr "No codificat"
 
@@ -926,6 +920,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Tarja DVB prim�ria"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Format del v�deo"
 
@@ -1150,9 +1147,6 @@
 msgid "Schedule"
 msgstr "Guia de Programaci�"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Aturar la reproducci�"
@@ -1282,6 +1276,24 @@
 msgid "Classic VDR"
 msgstr "VDR clasico"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "Quadres ST:TNG"
 
@@ -1344,3 +1356,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR s'apagar� en %s minuts"
+
+msgid "Disk"
+msgstr "Disc"
+
+msgid "free"
+msgstr "lliure"
diff -ruN vdr-1.7.27/po/cs_CZ.po vdr-1.7.28/po/cs_CZ.po
--- vdr-1.7.27/po/cs_CZ.po	2012-03-11 11:44:43.000000000 +0100
+++ vdr-1.7.28/po/cs_CZ.po	2012-06-02 15:13:04.000000000 +0200
@@ -9,7 +9,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.7.14\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2010-05-06 11:00+0200\n"
 "Last-Translator: Radek Šťastný <dedkus@gmail.com>\n"
 "Language-Team: Czech <vdr@linuxtv.org>\n"
@@ -511,12 +511,6 @@
 msgid "Key$User9"
 msgstr "Uživatel9"
 
-msgid "Disk"
-msgstr "Disk"
-
-msgid "free"
-msgstr "volno"
-
 msgid "Free To Air"
 msgstr "volný"
 
@@ -925,6 +919,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Primární DVB zařízení"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Formát videa"
 
@@ -1149,9 +1146,6 @@
 msgid "Schedule"
 msgstr "Program (EPG)"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Zastavit přehrávání"
@@ -1281,6 +1275,24 @@
 msgid "Classic VDR"
 msgstr "Klasické VDR"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG konzola"
 
@@ -1343,3 +1355,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR se vypne za %s minut"
+
+msgid "Disk"
+msgstr "Disk"
+
+msgid "free"
+msgstr "volno"
diff -ruN vdr-1.7.27/po/da_DK.po vdr-1.7.28/po/da_DK.po
--- vdr-1.7.27/po/da_DK.po	2012-03-11 11:44:43.000000000 +0100
+++ vdr-1.7.28/po/da_DK.po	2012-06-02 15:13:07.000000000 +0200
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2007-08-12 14:17+0200\n"
 "Last-Translator: Mogens Elneff <mogens@elneff.dk>\n"
 "Language-Team: Danish <vdr@linuxtv.org>\n"
@@ -509,12 +509,6 @@
 msgid "Key$User9"
 msgstr "Bruger9"
 
-msgid "Disk"
-msgstr "Disk"
-
-msgid "free"
-msgstr "fri"
-
 msgid "Free To Air"
 msgstr "Free To Air"
 
@@ -923,6 +917,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Prim�r DVB enhed"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Video format"
 
@@ -1147,9 +1144,6 @@
 msgid "Schedule"
 msgstr "Programoversigt"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Stop afspilning"
@@ -1279,6 +1273,24 @@
 msgid "Classic VDR"
 msgstr "Klassisk VDR"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG konsol"
 
@@ -1341,3 +1353,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR slukker om %s minutter"
+
+msgid "Disk"
+msgstr "Disk"
+
+msgid "free"
+msgstr "fri"
diff -ruN vdr-1.7.27/po/de_DE.po vdr-1.7.28/po/de_DE.po
--- vdr-1.7.27/po/de_DE.po	2012-03-11 11:44:44.000000000 +0100
+++ vdr-1.7.28/po/de_DE.po	2012-06-03 11:14:47.000000000 +0200
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2010-01-16 16:46+0100\n"
 "Last-Translator: Klaus Schmidinger <kls@tvdr.de>\n"
 "Language-Team: German <vdr@linuxtv.org>\n"
@@ -509,12 +509,6 @@
 msgid "Key$User9"
 msgstr "Benutzer9"
 
-msgid "Disk"
-msgstr "Disk"
-
-msgid "free"
-msgstr "frei"
-
 msgid "Free To Air"
 msgstr "frei empfangbar"
 
@@ -923,6 +917,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Prim�res DVB-Interface"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr "Standardkonformit�t"
+
 msgid "Setup.DVB$Video format"
 msgstr "Videoformat"
 
@@ -1147,9 +1144,6 @@
 msgid "Schedule"
 msgstr "Programm"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Wiedergabe beenden"
@@ -1279,6 +1273,24 @@
 msgid "Classic VDR"
 msgstr "Klassischer VDR"
 
+msgid "DISK"
+msgstr "PLATTE"
+
+msgid "LOAD"
+msgstr "LAST"
+
+msgid "TIMERS"
+msgstr "TIMER"
+
+msgid "DEVICES"
+msgstr "EMPF�NGER"
+
+msgid "LIVE"
+msgstr "LIVE"
+
+msgid "PLAY"
+msgstr "WIEDERGABE"
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG-Konsolen"
 
@@ -1341,3 +1353,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR wird in %s Minuten abgeschaltet"
+
+msgid "Disk"
+msgstr "Disk"
+
+msgid "free"
+msgstr "frei"
diff -ruN vdr-1.7.27/po/el_GR.po vdr-1.7.28/po/el_GR.po
--- vdr-1.7.27/po/el_GR.po	2012-03-11 11:44:43.000000000 +0100
+++ vdr-1.7.28/po/el_GR.po	2012-06-02 15:13:13.000000000 +0200
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2007-08-12 14:17+0200\n"
 "Last-Translator: Dimitrios Dimitrakos <mail@dimitrios.de>\n"
 "Language-Team: Greek <vdr@linuxtv.org>\n"
@@ -509,12 +509,6 @@
 msgid "Key$User9"
 msgstr ""
 
-msgid "Disk"
-msgstr "������"
-
-msgid "free"
-msgstr "���������"
-
 msgid "Free To Air"
 msgstr ""
 
@@ -923,6 +917,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "����� DVB �����"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "����� ������"
 
@@ -1147,9 +1144,6 @@
 msgid "Schedule"
 msgstr "���������"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " ����� ������������"
@@ -1279,6 +1273,24 @@
 msgid "Classic VDR"
 msgstr "������� VDR"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "������ ST:TNG"
 
@@ -1341,3 +1353,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr ""
+
+msgid "Disk"
+msgstr "������"
+
+msgid "free"
+msgstr "���������"
diff -ruN vdr-1.7.27/po/es_ES.po vdr-1.7.28/po/es_ES.po
--- vdr-1.7.27/po/es_ES.po	2012-03-11 11:44:43.000000000 +0100
+++ vdr-1.7.28/po/es_ES.po	2012-06-02 15:13:17.000000000 +0200
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2008-03-02 19:02+0100\n"
 "Last-Translator: Luca Olivetti <luca@ventoso.org>\n"
 "Language-Team: Spanish <vdr@linuxtv.org>\n"
@@ -510,12 +510,6 @@
 msgid "Key$User9"
 msgstr "Usuario 9"
 
-msgid "Disk"
-msgstr "Disco"
-
-msgid "free"
-msgstr "libre"
-
 msgid "Free To Air"
 msgstr "en abierto"
 
@@ -924,6 +918,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Interfaz DVB primario"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Formato de v�deo"
 
@@ -1148,9 +1145,6 @@
 msgid "Schedule"
 msgstr "Gu�a de Programaci�n"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Parar reproduci�n"
@@ -1280,6 +1274,24 @@
 msgid "Classic VDR"
 msgstr "VDR cl�sico"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "Paneles ST:TNG"
 
@@ -1342,3 +1354,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR se apagar� en %s minutos"
+
+msgid "Disk"
+msgstr "Disco"
+
+msgid "free"
+msgstr "libre"
diff -ruN vdr-1.7.27/po/et_EE.po vdr-1.7.28/po/et_EE.po
--- vdr-1.7.27/po/et_EE.po	2012-03-12 11:03:28.000000000 +0100
+++ vdr-1.7.28/po/et_EE.po	2012-06-02 15:13:19.000000000 +0200
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2007-08-12 14:17+0200\n"
 "Last-Translator: Arthur Konovalov <artlov@gmail.com>\n"
 "Language-Team: Estonian <vdr@linuxtv.org>\n"
@@ -509,12 +509,6 @@
 msgid "Key$User9"
 msgstr "Lisaklahv9"
 
-msgid "Disk"
-msgstr "Ketas"
-
-msgid "free"
-msgstr "vaba"
-
 msgid "Free To Air"
 msgstr "FTA"
 
@@ -923,6 +917,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Esmane DVB seade"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "TV külgsuhe"
 
@@ -1147,9 +1144,6 @@
 msgid "Schedule"
 msgstr "Kava"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Lõpetada taasesitamine"
@@ -1279,6 +1273,24 @@
 msgid "Classic VDR"
 msgstr "Classic VDR"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG Panels"
 
@@ -1341,3 +1353,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR lülitub välja %s minuti pärast"
+
+msgid "Disk"
+msgstr "Ketas"
+
+msgid "free"
+msgstr "vaba"
diff -ruN vdr-1.7.27/po/fi_FI.po vdr-1.7.28/po/fi_FI.po
--- vdr-1.7.27/po/fi_FI.po	2012-03-11 11:44:43.000000000 +0100
+++ vdr-1.7.28/po/fi_FI.po	2012-06-02 15:13:22.000000000 +0200
@@ -10,7 +10,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2007-08-15 15:52+0200\n"
 "Last-Translator: Rolf Ahrenberg <rahrenbe@cc.hut.fi>\n"
 "Language-Team: Finnish <vdr@linuxtv.org>\n"
@@ -512,12 +512,6 @@
 msgid "Key$User9"
 msgstr "Lisänäppäin 9"
 
-msgid "Disk"
-msgstr "Levy"
-
-msgid "free"
-msgstr "vapaana"
-
 msgid "Free To Air"
 msgstr "vapaa"
 
@@ -926,6 +920,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Ensisijainen DVB-sovitin"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr "Noudatettava standardi"
+
 msgid "Setup.DVB$Video format"
 msgstr "Kuvasuhde"
 
@@ -1150,9 +1147,6 @@
 msgid "Schedule"
 msgstr "Ohjelmisto"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Lopeta toisto"
@@ -1282,6 +1276,24 @@
 msgid "Classic VDR"
 msgstr "Klassinen VDR"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG konsoli"
 
@@ -1344,3 +1356,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR sammuu %s minuutin kuluttua"
+
+msgid "Disk"
+msgstr "Levy"
+
+msgid "free"
+msgstr "vapaana"
diff -ruN vdr-1.7.27/po/fr_FR.po vdr-1.7.28/po/fr_FR.po
--- vdr-1.7.27/po/fr_FR.po	2012-03-11 11:44:44.000000000 +0100
+++ vdr-1.7.28/po/fr_FR.po	2012-06-02 15:13:25.000000000 +0200
@@ -13,7 +13,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2008-02-27 18:14+0100\n"
 "Last-Translator: Jean-Claude Repetto <jc@repetto.org>\n"
 "Language-Team: French <vdr@linuxtv.org>\n"
@@ -515,12 +515,6 @@
 msgid "Key$User9"
 msgstr "Utilisateur9"
 
-msgid "Disk"
-msgstr "Disque"
-
-msgid "free"
-msgstr "restant"
-
 msgid "Free To Air"
 msgstr "En clair"
 
@@ -929,6 +923,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Carte DVB primaire"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Format vid�o"
 
@@ -1153,9 +1150,6 @@
 msgid "Schedule"
 msgstr "Programmes"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Arr�ter la lecture"
@@ -1285,6 +1279,24 @@
 msgid "Classic VDR"
 msgstr "VDR classique"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "Consoles ST:TNG"
 
@@ -1347,3 +1359,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR s'arr�tera dans %s minutes"
+
+msgid "Disk"
+msgstr "Disque"
+
+msgid "free"
+msgstr "restant"
diff -ruN vdr-1.7.27/po/hr_HR.po vdr-1.7.28/po/hr_HR.po
--- vdr-1.7.27/po/hr_HR.po	2012-03-11 11:44:44.000000000 +0100
+++ vdr-1.7.28/po/hr_HR.po	2012-06-02 15:13:28.000000000 +0200
@@ -9,7 +9,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2008-03-17 19:00+0100\n"
 "Last-Translator: Adrian Caval <anrxc@sysphere.org>\n"
 "Language-Team: Croatian <vdr@linuxtv.org>\n"
@@ -511,12 +511,6 @@
 msgid "Key$User9"
 msgstr "Korisnik9"
 
-msgid "Disk"
-msgstr "Disk"
-
-msgid "free"
-msgstr "slobodno"
-
 msgid "Free To Air"
 msgstr "Slobodno"
 
@@ -925,6 +919,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Primarni DVB ure�aj"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Video format"
 
@@ -1149,9 +1146,6 @@
 msgid "Schedule"
 msgstr "Raspored"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Prekini reprodukciju"
@@ -1281,6 +1275,24 @@
 msgid "Classic VDR"
 msgstr "Klasi�ni VDR"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG Panele"
 
@@ -1343,3 +1355,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR �e se isklju�iti za %s minuta"
+
+msgid "Disk"
+msgstr "Disk"
+
+msgid "free"
+msgstr "slobodno"
diff -ruN vdr-1.7.27/po/hu_HU.po vdr-1.7.28/po/hu_HU.po
--- vdr-1.7.27/po/hu_HU.po	2012-03-11 11:44:43.000000000 +0100
+++ vdr-1.7.28/po/hu_HU.po	2012-06-02 15:13:31.000000000 +0200
@@ -10,7 +10,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2012-01-02 11:54+0200\n"
 "Last-Translator: Istv�n F�ley <ifuley@tigercomp.ro>\n"
 "Language-Team: Hungarian <vdr@linuxtv.org>\n"
@@ -512,12 +512,6 @@
 msgid "Key$User9"
 msgstr "Felhaszn�l�9"
 
-msgid "Disk"
-msgstr "Lemez"
-
-msgid "free"
-msgstr "szabad"
-
 msgid "Free To Air"
 msgstr "K�dolatlan"
 
@@ -926,6 +920,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Els� DVB interface"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Video form�tum"
 
@@ -1151,9 +1148,6 @@
 msgid "Schedule"
 msgstr "M�sor�js�g"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Lej�tsz�st befejzni"
@@ -1283,6 +1277,24 @@
 msgid "Classic VDR"
 msgstr "Klasszikus VDR"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG Konzol"
 
@@ -1345,3 +1357,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "A VDR le�ll %s perc m�lva"
+
+msgid "Disk"
+msgstr "Lemez"
+
+msgid "free"
+msgstr "szabad"
diff -ruN vdr-1.7.27/po/it_IT.po vdr-1.7.28/po/it_IT.po
--- vdr-1.7.27/po/it_IT.po	2012-03-19 09:16:10.000000000 +0100
+++ vdr-1.7.28/po/it_IT.po	2012-06-02 15:13:33.000000000 +0200
@@ -11,7 +11,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2012-03-19 01:08+0100\n"
 "Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
 "Language-Team: Italian <vdr@linuxtv.org>\n"
@@ -516,12 +516,6 @@
 msgid "Key$User9"
 msgstr "Utente9"
 
-msgid "Disk"
-msgstr "Disco"
-
-msgid "free"
-msgstr "disponibili"
-
 msgid "Free To Air"
 msgstr "in chiaro"
 
@@ -930,6 +924,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Scheda DVB primaria"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Formato video"
 
@@ -1154,9 +1151,6 @@
 msgid "Schedule"
 msgstr "Programmi"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Ferma riproduzione"
@@ -1286,6 +1280,24 @@
 msgid "Classic VDR"
 msgstr "VDR Classico"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "Consolle ST:TNG"
 
@@ -1348,3 +1360,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR si spegnerà tra %s minuti"
+
+msgid "Disk"
+msgstr "Disco"
+
+msgid "free"
+msgstr "disponibili"
diff -ruN vdr-1.7.27/po/lt_LT.po vdr-1.7.28/po/lt_LT.po
--- vdr-1.7.27/po/lt_LT.po	2012-03-11 11:44:43.000000000 +0100
+++ vdr-1.7.28/po/lt_LT.po	2012-06-02 15:13:35.000000000 +0200
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.7.16\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2010-10-30 11:55+0200\n"
 "Last-Translator: Valdemaras Pipiras <varas@ambernet.lt>\n"
 "Language-Team: Lithuanian <vdr@linuxtv.org>\n"
@@ -509,12 +509,6 @@
 msgid "Key$User9"
 msgstr "Vartotojas9"
 
-msgid "Disk"
-msgstr "Diskas"
-
-msgid "free"
-msgstr "laisva"
-
 msgid "Free To Air"
 msgstr "Nekoduotas kanalas"
 
@@ -923,6 +917,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Pirminiė DVB įvestis"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Video formatas"
 
@@ -1147,9 +1144,6 @@
 msgid "Schedule"
 msgstr "Programa"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Sustabdyti kartojimą"
@@ -1279,6 +1273,24 @@
 msgid "Classic VDR"
 msgstr "Klasikinis VDR"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG Skydeliai"
 
@@ -1341,3 +1353,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR išsijungs per %s minutes"
+
+msgid "Disk"
+msgstr "Diskas"
+
+msgid "free"
+msgstr "laisva"
diff -ruN vdr-1.7.27/po/mk_MK.po vdr-1.7.28/po/mk_MK.po
--- vdr-1.7.27/po/mk_MK.po	2012-03-11 11:44:44.000000000 +0100
+++ vdr-1.7.28/po/mk_MK.po	2012-06-02 15:13:37.000000000 +0200
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR-1.7.14\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2010-03-11 00:54+0100\n"
 "Last-Translator: Dimitar Petrovski <dimeptr@gmail.com>\n"
 "Language-Team: Macedonian <en@li.org>\n"
@@ -510,12 +510,6 @@
 msgid "Key$User9"
 msgstr "Корисник9"
 
-msgid "Disk"
-msgstr "Диск"
-
-msgid "free"
-msgstr "слободен"
-
 msgid "Free To Air"
 msgstr "Слободно"
 
@@ -924,6 +918,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Примарен DVB уред"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Видео формат"
 
@@ -1148,9 +1145,6 @@
 msgid "Schedule"
 msgstr "Распоред"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Запри пуштање"
@@ -1280,6 +1274,24 @@
 msgid "Classic VDR"
 msgstr "Класичен VDR"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG Панели"
 
@@ -1342,3 +1354,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR ќе се исклучи за %s минути"
+
+msgid "Disk"
+msgstr "Диск"
+
+msgid "free"
+msgstr "слободен"
diff -ruN vdr-1.7.27/po/nl_NL.po vdr-1.7.28/po/nl_NL.po
--- vdr-1.7.27/po/nl_NL.po	2012-03-11 11:44:43.000000000 +0100
+++ vdr-1.7.28/po/nl_NL.po	2012-06-02 15:13:40.000000000 +0200
@@ -11,7 +11,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2008-02-26 17:20+0100\n"
 "Last-Translator: Johan Schuring <johan.schuring@vetteblei.nl>\n"
 "Language-Team: Dutch <vdr@linuxtv.org>\n"
@@ -513,12 +513,6 @@
 msgid "Key$User9"
 msgstr "Gebruiker9"
 
-msgid "Disk"
-msgstr "Schijf"
-
-msgid "free"
-msgstr "vrij"
-
 msgid "Free To Air"
 msgstr "Vrij te ontvangen"
 
@@ -927,6 +921,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Eerste DVB kaart"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Videoformaat"
 
@@ -1151,9 +1148,6 @@
 msgid "Schedule"
 msgstr "Programmagids"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Stop afspelen"
@@ -1283,6 +1277,24 @@
 msgid "Classic VDR"
 msgstr "VDR Klassiek"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG Consoles"
 
@@ -1345,3 +1357,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR zal na %s minuten uitschakelen"
+
+msgid "Disk"
+msgstr "Schijf"
+
+msgid "free"
+msgstr "vrij"
diff -ruN vdr-1.7.27/po/nn_NO.po vdr-1.7.28/po/nn_NO.po
--- vdr-1.7.27/po/nn_NO.po	2012-03-11 11:44:44.000000000 +0100
+++ vdr-1.7.28/po/nn_NO.po	2012-06-02 15:13:42.000000000 +0200
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2007-08-12 14:17+0200\n"
 "Last-Translator: Truls Slevigen <truls@slevigen.no>\n"
 "Language-Team: Norwegian Nynorsk <vdr@linuxtv.org>\n"
@@ -510,12 +510,6 @@
 msgid "Key$User9"
 msgstr ""
 
-msgid "Disk"
-msgstr "Disk"
-
-msgid "free"
-msgstr "ledig"
-
 msgid "Free To Air"
 msgstr ""
 
@@ -924,6 +918,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Hoved DVB-enhet"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "TV-Format"
 
@@ -1148,9 +1145,6 @@
 msgid "Schedule"
 msgstr "Programmer"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Stopp avspilling"
@@ -1280,6 +1274,24 @@
 msgid "Classic VDR"
 msgstr ""
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr ""
 
@@ -1342,3 +1354,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr ""
+
+msgid "Disk"
+msgstr "Disk"
+
+msgid "free"
+msgstr "ledig"
diff -ruN vdr-1.7.27/po/pl_PL.po vdr-1.7.28/po/pl_PL.po
--- vdr-1.7.27/po/pl_PL.po	2012-03-11 11:44:43.000000000 +0100
+++ vdr-1.7.28/po/pl_PL.po	2012-06-02 15:13:44.000000000 +0200
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2008-03-09 12:59+0100\n"
 "Last-Translator: Michael Rakowski <mrak@gmx.de>\n"
 "Language-Team: Polish <vdr@linuxtv.org>\n"
@@ -510,12 +510,6 @@
 msgid "Key$User9"
 msgstr "U�ytkownik 9"
 
-msgid "Disk"
-msgstr "Dysk"
-
-msgid "free"
-msgstr "wolnego"
-
 msgid "Free To Air"
 msgstr "nieszyfrowany"
 
@@ -924,6 +918,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Pierwszy interfejs DVB"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Format obrazu"
 
@@ -1148,9 +1145,6 @@
 msgid "Schedule"
 msgstr "Program"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Zatrzymaj odtwarzanie"
@@ -1280,6 +1274,24 @@
 msgid "Classic VDR"
 msgstr "Klasyczny VDR"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "Panel ST:TNG"
 
@@ -1342,3 +1354,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR zostanie wy��czony za %s minut"
+
+msgid "Disk"
+msgstr "Dysk"
+
+msgid "free"
+msgstr "wolnego"
diff -ruN vdr-1.7.27/po/pt_PT.po vdr-1.7.28/po/pt_PT.po
--- vdr-1.7.27/po/pt_PT.po	2012-03-11 11:44:42.000000000 +0100
+++ vdr-1.7.28/po/pt_PT.po	2012-06-02 15:13:46.000000000 +0200
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.7.15\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2010-03-28 22:49+0100\n"
 "Last-Translator: Cris Silva <hudokkow@gmail.com>\n"
 "Language-Team: Portuguese <vdr@linuxtv.org>\n"
@@ -510,12 +510,6 @@
 msgid "Key$User9"
 msgstr "Defini��o9"
 
-msgid "Disk"
-msgstr "Disco"
-
-msgid "free"
-msgstr "livre"
-
 msgid "Free To Air"
 msgstr "FTA"
 
@@ -924,6 +918,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Placa DVB prim�ria"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Formato de v�deo"
 
@@ -1148,9 +1145,6 @@
 msgid "Schedule"
 msgstr "Programa��o"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Parar reprodu��o"
@@ -1280,6 +1274,24 @@
 msgid "Classic VDR"
 msgstr "VDR Cl�ssico"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "Consola ST:TNG"
 
@@ -1342,3 +1354,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "O VDR vai desligar daqui a %s minutos"
+
+msgid "Disk"
+msgstr "Disco"
+
+msgid "free"
+msgstr "livre"
diff -ruN vdr-1.7.27/po/ro_RO.po vdr-1.7.28/po/ro_RO.po
--- vdr-1.7.27/po/ro_RO.po	2012-03-11 11:44:43.000000000 +0100
+++ vdr-1.7.28/po/ro_RO.po	2012-06-02 15:13:48.000000000 +0200
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.7.12\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2011-03-10 23:52+0100\n"
 "Last-Translator: Lucian Muresan <lucianm@users.sourceforge.net>\n"
 "Language-Team: Romanian <vdr@linuxtv.org>\n"
@@ -512,12 +512,6 @@
 msgid "Key$User9"
 msgstr "Utilizator9"
 
-msgid "Disk"
-msgstr "Disc"
-
-msgid "free"
-msgstr "liber"
-
 msgid "Free To Air"
 msgstr "FTA (necriptat)"
 
@@ -926,6 +920,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Dispozitiv DVB primar"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Format video"
 
@@ -1150,9 +1147,6 @@
 msgid "Schedule"
 msgstr "Program (EPG)"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Opre�te redarea"
@@ -1282,6 +1276,24 @@
 msgid "Classic VDR"
 msgstr "VDR clasic"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "Cons. ST:TNG"
 
@@ -1344,3 +1356,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR se va �nchide �n %s minute"
+
+msgid "Disk"
+msgstr "Disc"
+
+msgid "free"
+msgstr "liber"
diff -ruN vdr-1.7.27/po/ru_RU.po vdr-1.7.28/po/ru_RU.po
--- vdr-1.7.27/po/ru_RU.po	2012-03-11 11:44:44.000000000 +0100
+++ vdr-1.7.28/po/ru_RU.po	2012-06-02 15:13:50.000000000 +0200
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2008-12-15 14:37+0100\n"
 "Last-Translator: Oleg Roitburd <oleg@roitburd.de>\n"
 "Language-Team: Russian <vdr@linuxtv.org>\n"
@@ -510,12 +510,6 @@
 msgid "Key$User9"
 msgstr "������������9"
 
-msgid "Disk"
-msgstr "����"
-
-msgid "free"
-msgstr "��������"
-
 msgid "Free To Air"
 msgstr "FTA (��������������)"
 
@@ -924,6 +918,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "�������� DVB-����������"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "������ �����"
 
@@ -1148,9 +1145,6 @@
 msgid "Schedule"
 msgstr "�������"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " ���������� ���������������"
@@ -1280,6 +1274,24 @@
 msgid "Classic VDR"
 msgstr "������������"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG ������"
 
@@ -1342,3 +1354,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR ���������� ����� %s �����"
+
+msgid "Disk"
+msgstr "����"
+
+msgid "free"
+msgstr "��������"
diff -ruN vdr-1.7.27/po/sk_SK.po vdr-1.7.28/po/sk_SK.po
--- vdr-1.7.27/po/sk_SK.po	2012-03-11 11:44:44.000000000 +0100
+++ vdr-1.7.28/po/sk_SK.po	2012-06-02 15:13:52.000000000 +0200
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.7.16\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2011-02-15 16:29+0100\n"
 "Last-Translator: Milan Hrala <hrala.milan@gmail.com>\n"
 "Language-Team: Slovak <vdr@linuxtv.org>\n"
@@ -509,12 +509,6 @@
 msgid "Key$User9"
 msgstr "U��vate�9"
 
-msgid "Disk"
-msgstr "Disk"
-
-msgid "free"
-msgstr "volne"
-
 msgid "Free To Air"
 msgstr "volne ��rite�n�"
 
@@ -923,6 +917,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Hlavn� DVB rozhranie"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Form�t videa"
 
@@ -1147,9 +1144,6 @@
 msgid "Schedule"
 msgstr "TV program"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Zastavi� prehr�vanie"
@@ -1279,6 +1273,24 @@
 msgid "Classic VDR"
 msgstr "Klasick� VDR"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG panely"
 
@@ -1341,3 +1353,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR sa vypne za %s min�t"
+
+msgid "Disk"
+msgstr "Disk"
+
+msgid "free"
+msgstr "volne"
diff -ruN vdr-1.7.27/po/sl_SI.po vdr-1.7.28/po/sl_SI.po
--- vdr-1.7.27/po/sl_SI.po	2012-03-11 11:44:44.000000000 +0100
+++ vdr-1.7.28/po/sl_SI.po	2012-06-02 15:13:54.000000000 +0200
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2008-02-28 19:44+0100\n"
 "Last-Translator: Matjaz Thaler <matjaz.thaler@guest.arnes.si>\n"
 "Language-Team: Slovenian <vdr@linuxtv.org>\n"
@@ -510,12 +510,6 @@
 msgid "Key$User9"
 msgstr "Uporabnik9"
 
-msgid "Disk"
-msgstr "Disk"
-
-msgid "free"
-msgstr "prosto"
-
 msgid "Free To Air"
 msgstr "nekodiran"
 
@@ -924,6 +918,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Primarna naprava"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Video format"
 
@@ -1148,9 +1145,6 @@
 msgid "Schedule"
 msgstr "Program"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Prekini predvajanje"
@@ -1280,6 +1274,24 @@
 msgid "Classic VDR"
 msgstr "Klasi�ni VDR"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG Konsola"
 
@@ -1342,3 +1354,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR se bo zaustavil v %s minutah"
+
+msgid "Disk"
+msgstr "Disk"
+
+msgid "free"
+msgstr "prosto"
diff -ruN vdr-1.7.27/po/sr_SR.po vdr-1.7.28/po/sr_SR.po
--- vdr-1.7.27/po/sr_SR.po	2012-03-11 11:44:44.000000000 +0100
+++ vdr-1.7.28/po/sr_SR.po	2012-06-02 15:14:01.000000000 +0200
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.7.1\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2011-01-09 15:57+0100\n"
 "Last-Translator: Milan Cvijanovi� <elcom_cvijo@hotmail.com>\n"
 "Language-Team: Serbian <vdr@linuxtv.org>\n"
@@ -511,12 +511,6 @@
 msgid "Key$User9"
 msgstr "Korisnik9"
 
-msgid "Disk"
-msgstr "Disk"
-
-msgid "free"
-msgstr "slobodno"
-
 msgid "Free To Air"
 msgstr "Slobodno"
 
@@ -942,6 +936,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Primarni DVB ure�aj"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Video format"
 
@@ -1171,9 +1168,6 @@
 msgid "Schedule"
 msgstr "Raspored Programa"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Zaustavi reprodukciju"
@@ -1305,6 +1299,24 @@
 msgid "Classic VDR"
 msgstr "Klasi�ni VDR"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG Panele"
 
@@ -1368,3 +1380,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR se isklju�uje za %s minuta"
+
+msgid "Disk"
+msgstr "Disk"
+
+msgid "free"
+msgstr "slobodno"
diff -ruN vdr-1.7.27/po/sv_SE.po vdr-1.7.28/po/sv_SE.po
--- vdr-1.7.27/po/sv_SE.po	2012-03-11 11:44:44.000000000 +0100
+++ vdr-1.7.28/po/sv_SE.po	2012-06-02 15:14:04.000000000 +0200
@@ -10,7 +10,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2008-03-12 18:25+0100\n"
 "Last-Translator: Magnus Andersson <svankan@bahnhof.se>\n"
 "Language-Team: Swedish <vdr@linuxtv.org>\n"
@@ -512,12 +512,6 @@
 msgid "Key$User9"
 msgstr "Anv�ndare9"
 
-msgid "Disk"
-msgstr "Disk"
-
-msgid "free"
-msgstr "ledigt"
-
 msgid "Free To Air"
 msgstr "Okodad"
 
@@ -926,6 +920,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Prim�r DVB enhet"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Video format"
 
@@ -1150,9 +1147,6 @@
 msgid "Schedule"
 msgstr "Program"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Avsluta uppspelning"
@@ -1282,6 +1276,24 @@
 msgid "Classic VDR"
 msgstr "Klassisk VDR"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG konsol"
 
@@ -1344,3 +1356,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR kommer att st�ngas ned om %s minuter"
+
+msgid "Disk"
+msgstr "Disk"
+
+msgid "free"
+msgstr "ledigt"
diff -ruN vdr-1.7.27/po/tr_TR.po vdr-1.7.28/po/tr_TR.po
--- vdr-1.7.27/po/tr_TR.po	2012-03-11 11:44:43.000000000 +0100
+++ vdr-1.7.28/po/tr_TR.po	2012-06-02 15:14:06.000000000 +0200
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2008-02-28 00:33+0100\n"
 "Last-Translator: Oktay Yolge�en <oktay_73@yahoo.de>\n"
 "Language-Team: Turkish <vdr@linuxtv.org>\n"
@@ -509,12 +509,6 @@
 msgid "Key$User9"
 msgstr "Kullan�c�9"
 
-msgid "Disk"
-msgstr "Disk"
-
-msgid "free"
-msgstr "bo�"
-
 msgid "Free To Air"
 msgstr "�ifresiz"
 
@@ -923,6 +917,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Primer DVB aray�z�"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Video format�"
 
@@ -1147,9 +1144,6 @@
 msgid "Schedule"
 msgstr "Program"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " G�steri�i bitir"
@@ -1279,6 +1273,24 @@
 msgid "Classic VDR"
 msgstr "Klasik VDR"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG paneli"
 
@@ -1341,3 +1353,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR %s dakikada kapanacak"
+
+msgid "Disk"
+msgstr "Disk"
+
+msgid "free"
+msgstr "bo�"
diff -ruN vdr-1.7.27/po/uk_UA.po vdr-1.7.28/po/uk_UA.po
--- vdr-1.7.27/po/uk_UA.po	2012-03-11 11:44:43.000000000 +0100
+++ vdr-1.7.28/po/uk_UA.po	2012-06-02 15:14:08.000000000 +0200
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.7.7\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2010-04-25 16:35+0200\n"
 "Last-Translator: Yarema aka Knedlyk <yupadmin@gmail.com>\n"
 "Language-Team: Ukrainian <vdr@linuxtv.org>\n"
@@ -509,12 +509,6 @@
 msgid "Key$User9"
 msgstr "Користувач8"
 
-msgid "Disk"
-msgstr "Диск"
-
-msgid "free"
-msgstr "вільно"
-
 msgid "Free To Air"
 msgstr "FTA (незакодовано)"
 
@@ -923,6 +917,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "Основний DVB-пристрій"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "Формат відео"
 
@@ -1147,9 +1144,6 @@
 msgid "Schedule"
 msgstr "Телегід"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr " Зупинити програвання"
@@ -1279,6 +1273,24 @@
 msgid "Classic VDR"
 msgstr "Класичний VDR"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG панелі"
 
@@ -1341,3 +1353,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR виключиться через %s хвилин"
+
+msgid "Disk"
+msgstr "Диск"
+
+msgid "free"
+msgstr "вільно"
diff -ruN vdr-1.7.27/po/zh_CN.po vdr-1.7.28/po/zh_CN.po
--- vdr-1.7.27/po/zh_CN.po	2012-03-11 11:44:43.000000000 +0100
+++ vdr-1.7.28/po/zh_CN.po	2012-06-02 15:14:10.000000000 +0200
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-03-08 14:37+0100\n"
+"POT-Creation-Date: 2012-06-02 15:10+0200\n"
 "PO-Revision-Date: 2009-09-23 23:50+0800\n"
 "Last-Translator: Nan Feng <nfgx@21cn.com>\n"
 "Language-Team: Chinese (simplified) <vdr@linuxtv.org>\n"
@@ -512,12 +512,6 @@
 msgid "Key$User9"
 msgstr "用户9"
 
-msgid "Disk"
-msgstr "硬盘已使用"
-
-msgid "free"
-msgstr "可录像时间"
-
 msgid "Free To Air"
 msgstr "剩余空间"
 
@@ -926,6 +920,9 @@
 msgid "Setup.DVB$Primary DVB interface"
 msgstr "使用中卫星卡接口"
 
+msgid "Setup.DVB$Standard compliance"
+msgstr ""
+
 msgid "Setup.DVB$Video format"
 msgstr "视频格式"
 
@@ -1150,9 +1147,6 @@
 msgid "Schedule"
 msgstr "任务列表"
 
-msgid "VDR"
-msgstr "VDR"
-
 #. TRANSLATORS: note the leading blank!
 msgid " Stop replaying"
 msgstr "停止回放"
@@ -1282,6 +1276,24 @@
 msgid "Classic VDR"
 msgstr "经典VDR面板"
 
+msgid "DISK"
+msgstr ""
+
+msgid "LOAD"
+msgstr ""
+
+msgid "TIMERS"
+msgstr ""
+
+msgid "DEVICES"
+msgstr ""
+
+msgid "LIVE"
+msgstr ""
+
+msgid "PLAY"
+msgstr ""
+
 msgid "ST:TNG Panels"
 msgstr "ST:TNG 面板"
 
@@ -1344,3 +1356,9 @@
 #, c-format
 msgid "VDR will shut down in %s minutes"
 msgstr "VDR系统将要在%s分钟关闭"
+
+msgid "Disk"
+msgstr "硬盘已使用"
+
+msgid "free"
+msgstr "可录像时间"
diff -ruN vdr-1.7.27/receiver.c vdr-1.7.28/receiver.c
--- vdr-1.7.27/receiver.c	2012-02-29 12:49:36.000000000 +0100
+++ vdr-1.7.28/receiver.c	2012-06-02 15:20:38.000000000 +0200
@@ -4,27 +4,13 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: receiver.c 2.5 2012/02/29 11:49:36 kls Exp $
+ * $Id: receiver.c 2.7 2012/06/02 13:20:38 kls Exp $
  */
 
 #include "receiver.h"
 #include <stdio.h>
 #include "tools.h"
 
-#ifdef LEGACY_CRECEIVER
-cReceiver::cReceiver(tChannelID ChannelID, int Priority, int Pid, const int *Pids1, const int *Pids2, const int *Pids3)
-{
-  device = NULL;
-  channelID = ChannelID;
-  priority = constrain(Priority, MINPRIORITY, MAXPRIORITY);
-  numPids = 0;
-  AddPid(Pid);
-  AddPids(Pids1);
-  AddPids(Pids2);
-  AddPids(Pids3);
-}
-#endif
-
 cReceiver::cReceiver(const cChannel *Channel, int Priority)
 {
   device = NULL;
@@ -83,7 +69,7 @@
             AddPids(Channel->Dpids()) &&
             AddPids(Channel->Spids());
      }
-return true;
+  return true;
 }
 
 bool cReceiver::WantsPid(int Pid)
diff -ruN vdr-1.7.27/receiver.h vdr-1.7.28/receiver.h
--- vdr-1.7.27/receiver.h	2012-03-11 16:25:40.000000000 +0100
+++ vdr-1.7.28/receiver.h	2012-06-02 15:20:44.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: receiver.h 2.6 2012/03/11 15:25:40 kls Exp $
+ * $Id: receiver.h 2.8 2012/06/02 13:20:44 kls Exp $
  */
 
 #ifndef __RECEIVER_H
@@ -14,8 +14,6 @@
 
 #define MAXRECEIVEPIDS  64 // the maximum number of PIDs per receiver
 
-//#define LEGACY_CRECEIVER // Code enclosed with this macro is deprecated and may be removed in a future version
-
 class cReceiver {
   friend class cDevice;
 private:
@@ -40,9 +38,6 @@
                ///< will be delivered only ONCE, so the cReceiver must make sure that
                ///< it will be able to buffer the data if necessary.
 public:
-#ifdef LEGACY_CRECEIVER
-  cReceiver(tChannelID ChannelID, int Priority, int Pid, const int *Pids1 = NULL, const int *Pids2 = NULL, const int *Pids3 = NULL);
-#endif
   cReceiver(const cChannel *Channel = NULL, int Priority = MINPRIORITY);
                ///< Creates a new receiver for the given Channel with the given Priority.
                ///< If Channel is not NULL, its pids are set by a call to SetPids().
@@ -62,7 +57,7 @@
                ///< Adds the given Pids to the list of PIDs of this receiver.
   bool SetPids(const cChannel *Channel);
                ///< Sets the PIDs of this receiver to those of the given Channel,
-               ///< replacing and previously stored PIDs. If Channel is NULL, all
+               ///< replacing any previously stored PIDs. If Channel is NULL, all
                ///< PIDs will be cleared. Parameters in the Setup may control whether
                ///< certain types of PIDs (like Dolby Digital, for instance) are
                ///< actually set. The Channel's ID is stored and can later be retrieved
diff -ruN vdr-1.7.27/recording.c vdr-1.7.28/recording.c
--- vdr-1.7.27/recording.c	2012-03-13 14:17:57.000000000 +0100
+++ vdr-1.7.28/recording.c	2012-06-03 11:51:27.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 2.53 2012/03/13 13:17:57 kls Exp $
+ * $Id: recording.c 2.56 2012/06/03 09:51:27 kls Exp $
  */
 
 #include "recording.h"
@@ -153,7 +153,7 @@
            cRecording *r = DeletedRecordings.First();
            cRecording *r0 = NULL;
            while (r) {
-                 if (IsOnVideoDirectoryFileSystem(r->FileName())) { // only remove recordings that will actually increase the free video disk space
+                 if (r->IsOnVideoDirectoryFileSystem()) { // only remove recordings that will actually increase the free video disk space
                     if (!r0 || r->Start() < r0->Start())
                        r0 = r;
                     }
@@ -180,7 +180,7 @@
            cRecording *r = Recordings.First();
            cRecording *r0 = NULL;
            while (r) {
-                 if (IsOnVideoDirectoryFileSystem(r->FileName())) { // only delete recordings that will actually increase the free video disk space
+                 if (r->IsOnVideoDirectoryFileSystem()) { // only delete recordings that will actually increase the free video disk space
                     if (!r->IsEdited() && r->Lifetime() < MAXLIFETIME) { // edited recordings and recordings with MAXLIFETIME live forever
                        if ((r->Lifetime() == 0 && Priority > r->Priority()) || // the recording has no guaranteed lifetime and the new recording has higher priority
                            (r->Lifetime() > 0 && (time(NULL) - r->Start()) / SECSINDAY >= r->Lifetime())) { // the recording's guaranteed lifetime has expired
@@ -617,6 +617,7 @@
   channel = Timer->Channel()->Number();
   instanceId = InstanceId;
   isPesRecording = false;
+  isOnVideoDirectoryFileSystem = -1; // unknown
   framesPerSecond = DEFAULTFRAMESPERSECOND;
   numFrames = -1;
   deleted = 0;
@@ -677,6 +678,7 @@
   priority = MAXPRIORITY; // assume maximum in case there is no info file
   lifetime = MAXLIFETIME;
   isPesRecording = false;
+  isOnVideoDirectoryFileSystem = -1; // unknown
   framesPerSecond = DEFAULTFRAMESPERSECOND;
   numFrames = -1;
   deleted = 0;
@@ -723,7 +725,9 @@
            }
         fclose(f);
         }
-     else if (errno != ENOENT)
+     else if (errno == ENOENT)
+        info->ownEvent->SetTitle(name);
+     else
         LOG_ERROR_STR(*InfoFileName);
 #ifdef SUMMARYFALLBACK
      // fall back to the old 'summary.vdr' if there was no 'info.vdr':
@@ -950,6 +954,13 @@
   return *s == '%';
 }
 
+bool cRecording::IsOnVideoDirectoryFileSystem(void) const
+{
+  if (isOnVideoDirectoryFileSystem < 0)
+     isOnVideoDirectoryFileSystem = ::IsOnVideoDirectoryFileSystem(FileName());
+  return isOnVideoDirectoryFileSystem;
+}
+
 void cRecording::ReadInfo(void)
 {
   info->Read();
@@ -1251,7 +1262,7 @@
   LOCK_THREAD;
   for (cRecording *recording = First(); recording; recording = Next(recording)) {
       int FileSizeMB = recording->FileSizeMB();
-      if (FileSizeMB > 0 && IsOnVideoDirectoryFileSystem(recording->FileName()))
+      if (FileSizeMB > 0 && recording->IsOnVideoDirectoryFileSystem())
          size += FileSizeMB;
       }
   return size;
@@ -1263,7 +1274,7 @@
   int length = 0;
   LOCK_THREAD;
   for (cRecording *recording = First(); recording; recording = Next(recording)) {
-      if (IsOnVideoDirectoryFileSystem(recording->FileName())) {
+      if (recording->IsOnVideoDirectoryFileSystem()) {
          int FileSizeMB = recording->FileSizeMB();
          if (FileSizeMB > 0) {
             int LengthInSeconds = recording->LengthInSeconds();
@@ -1422,13 +1433,17 @@
 
 const char *cRecordingUserCommand::command = NULL;
 
-void cRecordingUserCommand::InvokeCommand(const char *State, const char *RecordingFileName)
+void cRecordingUserCommand::InvokeCommand(const char *State, const char *RecordingFileName, const char *SourceFileName)
 {
   if (command) {
-     cString cmd = cString::sprintf("%s %s \"%s\"", command, State, *strescape(RecordingFileName, "\\\"$"));
-     isyslog("executing '%s'", *cmd);
-     SystemExec(cmd);
-     }
+    cString cmd;
+    if (SourceFileName)
+       cmd = cString::sprintf("%s %s \"%s\" \"%s\"", command, State, *strescape(RecordingFileName, "\\\"$"), *strescape(SourceFileName, "\\\"$"));
+    else
+       cmd = cString::sprintf("%s %s \"%s\"", command, State, *strescape(RecordingFileName, "\\\"$"));
+    isyslog("executing '%s'", *cmd);
+    SystemExec(cmd);
+  }
 }
 
 // --- cIndexFileGenerator ---------------------------------------------------
diff -ruN vdr-1.7.27/recording.h vdr-1.7.28/recording.h
--- vdr-1.7.27/recording.h	2012-03-13 13:41:05.000000000 +0100
+++ vdr-1.7.28/recording.h	2012-06-03 11:49:09.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 2.30 2012/03/13 12:41:05 kls Exp $
+ * $Id: recording.h 2.33 2012/06/03 09:49:09 kls Exp $
  */
 
 #ifndef __RECORDING_H
@@ -22,8 +22,6 @@
 #define TIMERMACRO_TITLE    "TITLE"
 #define TIMERMACRO_EPISODE  "EPISODE"
 
-//#define __RECORDING_H_DEPRECATED_DIRECT_MEMBER_ACCESS // Code enclosed with this macro is deprecated and may be removed in a future version
-
 extern bool VfatFileSystem;
 extern int InstanceId;
 
@@ -93,6 +91,7 @@
   int channel;
   int instanceId;
   bool isPesRecording;
+  mutable int isOnVideoDirectoryFileSystem; // -1 = unknown, 0 = no, 1 = yes
   double framesPerSecond;
   cRecordingInfo *info;
   cRecording(const cRecording&); // can't copy cRecording
@@ -100,9 +99,6 @@
   static char *StripEpisodeName(char *s);
   char *SortName(void) const;
   int GetResume(void) const;
-#ifdef __RECORDING_H_DEPRECATED_DIRECT_MEMBER_ACCESS
-public:
-#endif
   time_t start;
   int priority;
   int lifetime;
@@ -135,6 +131,7 @@
   bool IsNew(void) const { return GetResume() <= 0; }
   bool IsEdited(void) const;
   bool IsPesRecording(void) const { return isPesRecording; }
+  bool IsOnVideoDirectoryFileSystem(void) const;
   void ReadInfo(void);
   bool WriteInfo(void);
   void SetStartTime(time_t Start);
@@ -208,9 +205,6 @@
   friend class cMarks; // for sorting
 private:
   double framesPerSecond;
-#ifdef __RECORDING_H_DEPRECATED_DIRECT_MEMBER_ACCESS
-public:
-#endif
   int position;
   cString comment;
 public:
@@ -251,7 +245,7 @@
   static const char *command;
 public:
   static void SetCommand(const char *Command) { command = Command; }
-  static void InvokeCommand(const char *State, const char *RecordingFileName);
+  static void InvokeCommand(const char *State, const char *RecordingFileName, const char *SourceFileName = NULL);
   };
 
 // The maximum size of a single frame (up to HDTV 1920x1080):
diff -ruN vdr-1.7.27/skinclassic.c vdr-1.7.28/skinclassic.c
--- vdr-1.7.27/skinclassic.c	2011-08-21 13:02:06.000000000 +0200
+++ vdr-1.7.28/skinclassic.c	2012-04-23 10:48:03.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 2.6 2011/08/21 11:02:06 kls Exp $
+ * $Id: skinclassic.c 2.7 2012/04/23 08:48:03 kls Exp $
  */
 
 #include "skinclassic.h"
@@ -12,6 +12,7 @@
 #include "i18n.h"
 #include "osd.h"
 #include "themes.h"
+#include "videodir.h"
 
 #define ScrollWidth (Setup.FontOsdSize / 4)
 #define TextFrame   (Setup.FontOsdSize / 10)
@@ -170,7 +171,10 @@
   int y0, y1, y2, y3, y4, y5;
   int lineHeight;
   int dateWidth;
+  cString title;
   cString lastDate;
+  int lastDiskUsageState;
+  void DrawTitle(void);
   void DrawScrollbar(int Total, int Offset, int Shown, int Top, int Height, bool CanScrollUp, bool CanScrollDown);
   void SetTextScrollbar(void);
 public:
@@ -196,6 +200,7 @@
 {
   const cFont *font = cFont::GetFont(fontOsd);
   lineHeight = font->Height();
+  lastDiskUsageState = -1;
   dateWidth = 0;
   x0 = 0;
   x1 = x0 + 2 * TextSpacing;
@@ -270,10 +275,17 @@
   osd->DrawRectangle(x0, y1, x3 - 1, y4 - 1, Theme.Color(clrBackground));
 }
 
-void cSkinClassicDisplayMenu::SetTitle(const char *Title)
+void cSkinClassicDisplayMenu::DrawTitle(void)
 {
   const cFont *font = cFont::GetFont(fontOsd);
-  osd->DrawText(x0, y0, Title, Theme.Color(clrMenuTitleFg), Theme.Color(clrMenuTitleBg), font, x3 - x0 - dateWidth);
+  bool WithDisk = MenuCategory() == mcMain || MenuCategory() == mcRecording;
+  osd->DrawText(x0, y0, WithDisk ? cString::sprintf("%s  -  %s", *title, *cVideoDiskUsage::String()) : title, Theme.Color(clrMenuTitleFg), Theme.Color(clrMenuTitleBg), font, x3 - x0 - dateWidth);
+}
+
+void cSkinClassicDisplayMenu::SetTitle(const char *Title)
+{
+  title = Title;
+  DrawTitle();
 }
 
 void cSkinClassicDisplayMenu::SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue)
@@ -422,6 +434,8 @@
 
 void cSkinClassicDisplayMenu::Flush(void)
 {
+  if (cVideoDiskUsage::HasChanged(lastDiskUsageState))
+     DrawTitle();
   cString date = DayDateTime();
   if (!*lastDate || strcmp(date, lastDate)) {
      const cFont *font = cFont::GetFont(fontOsd);
diff -ruN vdr-1.7.27/skinlcars.c vdr-1.7.28/skinlcars.c
--- vdr-1.7.27/skinlcars.c	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.28/skinlcars.c	2012-06-03 12:17:00.000000000 +0200
@@ -0,0 +1,2114 @@
+/*
+ * skinlcars.c: A VDR skin with Star Trek's "LCARS" layout
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ * $Id: skinlcars.c 2.2 2012/06/03 10:17:00 kls Exp $
+ */
+
+// "Star Trek: The Next Generation"(R) is a registered trademark of Paramount Pictures,
+// registered in the United States Patent and Trademark Office, all rights reserved.
+// The LCARS system is based upon the designs of Michael Okuda and his Okudagrams.
+//
+// "LCARS" is short for "Library Computer Access and Retrieval System".
+// Some resources used for writing this skin can be found at
+// http://www.lcars.org.uk
+// http://www.lcarsdeveloper.com
+// http://www.lcarscom.net
+// http://lds-jedi.deviantart.com/art/LCARS-Swept-Tutorial-213936938
+// http://lds-jedi.deviantart.com/art/LCARS-Button-Tutorial-210783437
+// http://zelldenver.deviantart.com/art/LCARS-Color-Standard-179565780
+// http://www.lcars47.com
+// http://www.bracercom.com/tutorial/content/CoherentLCARSInterface/LCARSCoherentInterface.html
+// http://www.bracercom.com/tutorial/content/lcars_manifesto/the_lcars_manifesto.html
+
+#include "skinlcars.h"
+#include "font.h"
+#include "menu.h"
+#include "osd.h"
+#include "themes.h"
+#include "videodir.h"
+
+#include "symbols/arrowdown.xpm"
+#include "symbols/arrowup.xpm"
+#include "symbols/audio.xpm"
+#include "symbols/audioleft.xpm"
+#include "symbols/audioright.xpm"
+#include "symbols/audiostereo.xpm"
+#include "symbols/dolbydigital.xpm"
+#include "symbols/encrypted.xpm"
+#include "symbols/ffwd.xpm"
+#include "symbols/ffwd1.xpm"
+#include "symbols/ffwd2.xpm"
+#include "symbols/ffwd3.xpm"
+#include "symbols/frew.xpm"
+#include "symbols/frew1.xpm"
+#include "symbols/frew2.xpm"
+#include "symbols/frew3.xpm"
+#include "symbols/mute.xpm"
+#include "symbols/pause.xpm"
+#include "symbols/play.xpm"
+#include "symbols/radio.xpm"
+#include "symbols/recording.xpm"
+#include "symbols/sfwd.xpm"
+#include "symbols/sfwd1.xpm"
+#include "symbols/sfwd2.xpm"
+#include "symbols/sfwd3.xpm"
+#include "symbols/srew.xpm"
+#include "symbols/srew1.xpm"
+#include "symbols/srew2.xpm"
+#include "symbols/srew3.xpm"
+#include "symbols/teletext.xpm"
+#include "symbols/volume.xpm"
+
+#define Gap            (Setup.FontOsdSize / 5 & ~1) // must be even
+#define TextFrame      (Setup.FontOsdSize / TEXT_ALIGN_BORDER)
+#define TextSpacing    (2 * TextFrame)
+#define SymbolSpacing  TextSpacing
+#define ShowSeenExtent (Setup.FontOsdSize / 5) // pixels by which the "seen" bar extends out of the frame
+
+#define DISKUSAGEALERTLIMIT 95 // percent of disk usage above which the display goes into alert mode
+#define SIGNALDISPLAYDELTA   2 // seconds between subsequent device signal displays
+
+static cTheme Theme;
+
+// Color domains:
+
+#define CLR_BACKGROUND      0x99000000
+#define CLR_MAIN_FRAME      0xFFF1DF6F
+#define CLR_CHANNEL_FRAME   0xFFFFCC99
+#define CLR_REPLAY_FRAME    0xFFCC6666
+#define CLR_DATE            0xFF99CCFF
+#define CLR_MENU_ITEMS      0xFFFFBC57
+#define CLR_TIMER           0xFF99CCFF
+#define CLR_DEVICE          0xFFF1B1AF
+#define CLR_CHANNEL_NAME    0xFF99CCFF
+#define CLR_EVENT_TITLE     0xFF99CCFF
+#define CLR_EVENT_TIME      0xFFFFCC66
+#define CLR_EVENT_SHORTTEXT 0xFFFFCC66
+#define CLR_TEXT            0xFF99CCFF
+#define CLR_TRACK           0xFFFFCC66
+#define CLR_SEEN            0xFFCC99CC
+#define CLR_ALERT           0xFFFF0000
+#define CLR_EXPOSED         0xFF990000
+#define CLR_WHITE           0xFFFFFFFF
+#define CLR_RED             0xFFB20000
+#define CLR_GREEN           0xFF00B200
+#define CLR_YELLOW          0xFFB2B200
+#define CLR_BLUE            0xFF0000B2
+#define CLR_BLACK           0xFF000000
+
+// General colors:
+
+THEME_CLR(Theme, clrBackground,             CLR_BACKGROUND);
+THEME_CLR(Theme, clrDateFg,                 CLR_BLACK);
+THEME_CLR(Theme, clrDateBg,                 CLR_DATE);
+THEME_CLR(Theme, clrTimerFg,                CLR_BLACK);
+THEME_CLR(Theme, clrTimerBg,                CLR_TIMER);
+THEME_CLR(Theme, clrDeviceFg,               CLR_BLACK);
+THEME_CLR(Theme, clrDeviceBg,               CLR_DEVICE);
+THEME_CLR(Theme, clrSignalValue,            CLR_GREEN);
+THEME_CLR(Theme, clrSignalRest,             CLR_RED);
+THEME_CLR(Theme, clrSeen,                   CLR_SEEN);
+THEME_CLR(Theme, clrTrackName,              CLR_TRACK);
+THEME_CLR(Theme, clrAlertFg,                CLR_WHITE);
+THEME_CLR(Theme, clrAlertBg,                CLR_ALERT);
+THEME_CLR(Theme, clrChannelName,            CLR_CHANNEL_NAME);
+THEME_CLR(Theme, clrEventTitle,             CLR_EVENT_TITLE);
+THEME_CLR(Theme, clrEventTime,              CLR_EVENT_TIME);
+THEME_CLR(Theme, clrEventShortText,         CLR_EVENT_SHORTTEXT);
+THEME_CLR(Theme, clrEventDescription,       CLR_TEXT);
+
+// Buttons:
+
+THEME_CLR(Theme, clrButtonRedFg,            CLR_WHITE);
+THEME_CLR(Theme, clrButtonRedBg,            CLR_RED);
+THEME_CLR(Theme, clrButtonGreenFg,          CLR_BLACK);
+THEME_CLR(Theme, clrButtonGreenBg,          CLR_GREEN);
+THEME_CLR(Theme, clrButtonYellowFg,         CLR_BLACK);
+THEME_CLR(Theme, clrButtonYellowBg,         CLR_YELLOW);
+THEME_CLR(Theme, clrButtonBlueFg,           CLR_WHITE);
+THEME_CLR(Theme, clrButtonBlueBg,           CLR_BLUE);
+
+// Messages:
+
+THEME_CLR(Theme, clrMessageStatusFg,        CLR_WHITE);
+THEME_CLR(Theme, clrMessageStatusBg,        CLR_BLUE);
+THEME_CLR(Theme, clrMessageInfoFg,          CLR_BLACK);
+THEME_CLR(Theme, clrMessageInfoBg,          CLR_GREEN);
+THEME_CLR(Theme, clrMessageWarningFg,       CLR_BLACK);
+THEME_CLR(Theme, clrMessageWarningBg,       CLR_YELLOW);
+THEME_CLR(Theme, clrMessageErrorFg,         CLR_WHITE);
+THEME_CLR(Theme, clrMessageErrorBg,         CLR_RED);
+
+// Volume:
+
+THEME_CLR(Theme, clrVolumeFrame,            CLR_MAIN_FRAME);
+THEME_CLR(Theme, clrVolumeSymbol,           CLR_BLACK);
+THEME_CLR(Theme, clrVolumeBarUpper,         RgbShade(CLR_MAIN_FRAME, -0.2));
+THEME_CLR(Theme, clrVolumeBarLower,         CLR_GREEN);
+
+// Channel display:
+
+THEME_CLR(Theme, clrChannelFrameFg,         CLR_BLACK);
+THEME_CLR(Theme, clrChannelFrameBg,         CLR_CHANNEL_FRAME);
+THEME_CLR(Theme, clrChannelSymbolOn,        CLR_BLACK);
+THEME_CLR(Theme, clrChannelSymbolOff,       RgbShade(CLR_CHANNEL_FRAME, -0.2));
+THEME_CLR(Theme, clrChannelSymbolRecFg,     CLR_WHITE);
+THEME_CLR(Theme, clrChannelSymbolRecBg,     CLR_RED);
+
+// Menu:
+
+THEME_CLR(Theme, clrMenuFrameFg,            CLR_BLACK);
+THEME_CLR(Theme, clrMenuFrameBg,            CLR_MAIN_FRAME);
+THEME_CLR(Theme, clrMenuTitle,              CLR_MAIN_FRAME);
+THEME_CLR(Theme, clrMenuMainBracket,        CLR_MENU_ITEMS);
+THEME_CLR(Theme, clrMenuTimerRecording,     CLR_DEVICE);
+THEME_CLR(Theme, clrMenuDeviceRecording,    CLR_TIMER);
+THEME_CLR(Theme, clrMenuItemCurrentFg,      CLR_BLACK);
+THEME_CLR(Theme, clrMenuItemCurrentBg,      CLR_MENU_ITEMS);
+THEME_CLR(Theme, clrMenuItemSelectable,     CLR_MENU_ITEMS);
+THEME_CLR(Theme, clrMenuItemNonSelectable,  CLR_TEXT);
+THEME_CLR(Theme, clrMenuScrollbarTotal,     CLR_MENU_ITEMS);
+THEME_CLR(Theme, clrMenuScrollbarShown,     CLR_SEEN);
+THEME_CLR(Theme, clrMenuScrollbarArrow,     CLR_BLACK);
+THEME_CLR(Theme, clrMenuText,               CLR_TEXT);
+
+// Replay display:
+
+THEME_CLR(Theme, clrReplayFrameFg,          CLR_BLACK);
+THEME_CLR(Theme, clrReplayFrameBg,          CLR_REPLAY_FRAME);
+THEME_CLR(Theme, clrReplayPosition,         CLR_SEEN);
+THEME_CLR(Theme, clrReplayJumpFg,           CLR_BLACK);
+THEME_CLR(Theme, clrReplayJumpBg,           CLR_SEEN);
+THEME_CLR(Theme, clrReplayProgressSeen,     CLR_SEEN);
+THEME_CLR(Theme, clrReplayProgressRest,     RgbShade(CLR_WHITE, -0.2));
+THEME_CLR(Theme, clrReplayProgressSelected, CLR_EXPOSED);
+THEME_CLR(Theme, clrReplayProgressMark,     CLR_BLACK);
+THEME_CLR(Theme, clrReplayProgressCurrent,  CLR_EXPOSED);
+
+// Track display:
+
+THEME_CLR(Theme, clrTrackFrameFg,           CLR_BLACK);
+THEME_CLR(Theme, clrTrackFrameBg,           CLR_TRACK);
+THEME_CLR(Theme, clrTrackItemFg,            CLR_BLACK);
+THEME_CLR(Theme, clrTrackItemBg,            RgbShade(CLR_TRACK, 0.5));
+THEME_CLR(Theme, clrTrackItemCurrentFg,     CLR_BLACK);
+THEME_CLR(Theme, clrTrackItemCurrentBg,     CLR_TRACK);
+
+// --- Helper functions ------------------------------------------------------
+
+static cOsd *CreateOsd(int Left, int Top, int x0, int y0, int x1, int y1)
+{
+  cOsd *Osd = cOsdProvider::NewOsd(Left, Top);
+  int Bpp[] = { 32, 8, 4, 2, 1 };
+  tArea Area = { x0, y0, x1, y1, 0 };
+  for (unsigned int i = 0; i < sizeof(Bpp) / sizeof(int); i++) {
+      Area.bpp = Bpp[i];
+      if (Osd->CanHandleAreas(&Area, 1) == oeOk) {
+         Osd->SetAreas(&Area, 1);
+         break;
+         }
+      }
+  return Osd;
+}
+
+static cFont *CreateTinyFont(int LineHeight)
+{
+  // Creates a font that is not higher than half of LineHeight.
+  LineHeight /= 2;
+  int Height = LineHeight;
+  for (;;) {
+      cFont *TinyFont = cFont::CreateFont(Setup.FontOsd, Height);
+      if (Height < 2 || TinyFont->Height() <= LineHeight)
+         return TinyFont;
+      delete TinyFont;
+      Height -= 1;
+      }
+}
+
+static bool DrawDeviceData(cOsd *Osd, const cDevice *Device, int x0, int y0, int x1, int y1, int &xs, const cFont *TinyFont, cString &LastDeviceType, cCamSlot *&LastCamSlot, bool Initial)
+{
+  cString DeviceType = Device->DeviceType();
+  cCamSlot *CamSlot = Device->CamSlot();
+  if (Initial || strcmp(DeviceType, LastDeviceType) || CamSlot != LastCamSlot) {
+     const cFont *font = cFont::GetFont(fontOsd);
+     tColor ColorFg = Theme.Color(clrDeviceFg);
+     tColor ColorBg = Theme.Color(clrDeviceBg);
+     Osd->DrawRectangle(x0, y0, x1 - 1, y1 - 1, ColorBg);
+     int x = x0;
+     // Device number:
+     cString Nr = itoa(Device->DeviceNumber() + 1);
+     int w = max(font->Width(Nr), y1 - y0);
+     Osd->DrawText(x, y0, Nr, ColorFg, ColorBg, font, w, y1 - y0, taCenter);
+     x += w;
+     // Device type:
+     Osd->DrawText(x, y0, DeviceType, ColorFg, ColorBg, TinyFont);
+     xs = max(xs, x + TinyFont->Width(DeviceType));
+     LastDeviceType = DeviceType;
+     // CAM:
+     if (CamSlot) {
+        cString s = cString::sprintf("CAM %d", CamSlot->SlotNumber());
+        Osd->DrawText(x, y1 - TinyFont->Height(), s, ColorFg, ColorBg, TinyFont);
+        xs = max(xs, x + TinyFont->Width(s));
+        }
+     LastCamSlot = CamSlot;
+     return true;
+     }
+  return false;
+}
+
+static void DrawDeviceSignal(cOsd *Osd, const cDevice *Device, int x0, int y0, int x1, int y1, int &LastSignalStrength, int &LastSignalQuality, bool Initial)
+{
+  int SignalStrength = Device->SignalStrength();
+  int SignalQuality = Device->SignalQuality();
+  int d = max((y1 - y0) / 10, 1);
+  int x00 = x0 + d;
+  int x01 = x1 - d;
+  int h = (y1 - y0 - 3 * d) / 2;
+  int w = x01 - x00;
+  int y00 = y0 + d;
+  int y01 = y00 + h;
+  int y03 = y1 - d;
+  int y02 = y03 - h;
+  if (SignalStrength >= 0 && (Initial || SignalStrength != LastSignalStrength)) {
+     int s = SignalStrength * w / 100;
+     Osd->DrawRectangle(x00, y00, x00 + s - 1, y01 - 1, Theme.Color(clrSignalValue));
+     Osd->DrawRectangle(x00 + s, y00, x01 - 1, y01 - 1, Theme.Color(clrSignalRest));
+     LastSignalStrength = SignalStrength;
+     }
+  if (SignalQuality >= 0 && (Initial || SignalQuality != LastSignalQuality)) {
+     int q = SignalQuality * w / 100;
+     Osd->DrawRectangle(x00, y02, x00 + q - 1, y03 - 1, Theme.Color(clrSignalValue));
+     Osd->DrawRectangle(x00 + q, y02, x01 - 1, y03 - 1, Theme.Color(clrSignalRest));
+     LastSignalQuality = SignalQuality;
+     }
+}
+
+// --- cSkinLCARSDisplayChannel ----------------------------------------------
+
+class cSkinLCARSDisplayChannel : public cSkinDisplayChannel {
+private:
+  cOsd *osd;
+  int xc00, xc01, xc02, xc03, xc04, xc05, xc06, xc07, xc08, xc09, xc10, xc11, xc12, xc13, xc14, xc15;
+  int yc00, yc01, yc02, yc03, yc04, yc05, yc06, yc07, yc08, yc09, yc10, yc11, yc12;
+  int xs; // starting column for signal display
+  bool withInfo;
+  int lineHeight;
+  cFont *tinyFont;
+  cFont *tallFont;
+  tColor frameColor;
+  bool message;
+  const cEvent *present;
+  bool initial;
+  cString lastDate;
+  int lastSeen;
+  int lastDeviceNumber;
+  cString lastDeviceType;
+  cCamSlot *lastCamSlot;
+  int lastSignalStrength;
+  int lastSignalQuality;
+  time_t lastSignalDisplay;
+  tTrackId lastTrackId;
+  static cBitmap bmTeletext, bmRadio, bmAudio, bmDolbyDigital, bmEncrypted, bmRecording;
+  void DrawDate(void);
+  void DrawTrack(void);
+  void DrawSeen(int Current, int Total);
+  void DrawDevice(void);
+  void DrawSignal(void);
+public:
+  cSkinLCARSDisplayChannel(bool WithInfo);
+  virtual ~cSkinLCARSDisplayChannel();
+  virtual void SetChannel(const cChannel *Channel, int Number);
+  virtual void SetEvents(const cEvent *Present, const cEvent *Following);
+  virtual void SetMessage(eMessageType Type, const char *Text);
+  virtual void Flush(void);
+  };
+
+cBitmap cSkinLCARSDisplayChannel::bmTeletext(teletext_xpm);
+cBitmap cSkinLCARSDisplayChannel::bmRadio(radio_xpm);
+cBitmap cSkinLCARSDisplayChannel::bmAudio(audio_xpm);
+cBitmap cSkinLCARSDisplayChannel::bmDolbyDigital(dolbydigital_xpm);
+cBitmap cSkinLCARSDisplayChannel::bmEncrypted(encrypted_xpm);
+cBitmap cSkinLCARSDisplayChannel::bmRecording(recording_xpm);
+
+cSkinLCARSDisplayChannel::cSkinLCARSDisplayChannel(bool WithInfo)
+{
+  tallFont = cFont::CreateFont(Setup.FontOsd, Setup.FontOsdSize * 1.8);
+  initial = true;
+  present = NULL;
+  lastSeen = -1;
+  lastDeviceNumber = -1;
+  lastCamSlot = NULL;
+  lastSignalStrength = -1;
+  lastSignalQuality = -1;
+  lastSignalDisplay = 0;
+  memset(&lastTrackId, 0, sizeof(lastTrackId));
+  const cFont *font = cFont::GetFont(fontOsd);
+  withInfo = WithInfo;
+  lineHeight = font->Height();
+  tinyFont = CreateTinyFont(lineHeight);
+  frameColor = Theme.Color(clrChannelFrameBg);
+  message = false;
+  int d = 5 * lineHeight;
+  xc00 = 0;
+  xc01 = xc00 + d / 2;
+  xc02 = xc00 + d;
+  xc03 = xc02 + lineHeight;
+  xc04 = xc02 + d / 4;
+  xc05 = xc02 + d;
+  xc06 = xc05 + Gap;
+  xc15 = cOsd::OsdWidth();
+  xc14 = xc15 - lineHeight;
+  xc13 = xc14 - Gap;
+  xc07 = (xc15 + xc00) / 2;
+  xc08 = xc07 + Gap;
+  xc09 = xc08 + lineHeight;
+  xc10 = xc09 + Gap;
+  xc11 = (xc10 + xc13 + Gap) / 2;
+  xc12 = xc11 + Gap;
+
+  yc00 = 0;
+  yc01 = yc00 + lineHeight;
+  yc02 = yc01 + lineHeight;
+  yc03 = yc02 + Gap;
+  yc04 = yc03 + 2 * lineHeight;
+  yc05 = yc04 + Gap;
+  yc06 = yc05 + 2 * lineHeight;
+
+  yc07 = yc06 + Gap;
+  yc12 = yc07 + 3 * lineHeight + Gap / 2;
+  yc11 = yc12 - lineHeight;
+  yc10 = yc11 - lineHeight;
+  yc09 = yc11 - d / 4;
+  yc08 = yc12 - d / 2;
+
+  xs = 0;
+
+  int y1 = withInfo ? yc12 : yc02;
+  int y0 = cOsd::OsdTop() + (Setup.ChannelInfoPos ? 0 : cOsd::OsdHeight() - y1);
+  osd = CreateOsd(cOsd::OsdLeft(), y0, xc00, yc00, xc15 - 1, y1 - 1);
+  osd->DrawRectangle(xc00, yc00, xc15 - 1, y1 - 1, Theme.Color(clrBackground));
+  // Rectangles:
+  osd->DrawRectangle(xc00, yc00, xc02 - 1, yc02 - 1, frameColor);
+  if (withInfo) {
+     osd->DrawRectangle(xc00, yc03, xc02 - 1, yc04 - 1, frameColor);
+     osd->DrawRectangle(xc00, yc05, xc02 - 1, yc06 - 1, frameColor);
+     // Elbow:
+     osd->DrawRectangle(xc00, yc07, xc01 - 1, yc08 - 1, frameColor);
+     osd->DrawRectangle(xc00, yc08, xc01 - 1, yc12 - 1, clrTransparent);
+     osd->DrawEllipse  (xc00, yc08, xc01 - 1, yc12 - 1, frameColor, 3);
+     osd->DrawRectangle(xc01, yc07, xc02 - 1, yc12 - 1, frameColor);
+     osd->DrawEllipse  (xc02, yc09, xc04 - 1, yc11 - 1, frameColor, -3);
+     osd->DrawRectangle(xc02, yc11, xc05 - 1, yc12 - 1, frameColor);
+     // Status area:
+     osd->DrawRectangle(xc06, yc11 + lineHeight / 2, xc07 - 1, yc12 - 1, frameColor);
+     osd->DrawRectangle(xc08, yc11, xc09 - 1, yc12 - 1, frameColor);
+     osd->DrawRectangle(xc10, yc11, xc11 - 1, yc12 - 1, Theme.Color(clrDeviceBg));
+     osd->DrawRectangle(xc12, yc11, xc13 - 1, yc12 - 1, Theme.Color(clrDateBg));
+     osd->DrawRectangle(xc14, yc11, xc14 + lineHeight / 2 - 1, yc12 - 1, frameColor);
+     osd->DrawRectangle(xc14 + lineHeight / 2, yc11 + lineHeight / 2, xc15 - 1, yc12 - 1, clrTransparent);
+     osd->DrawEllipse  (xc14 + lineHeight / 2, yc11, xc15 - 1, yc12 - 1, frameColor, 5);
+     }
+  // Icons:
+  osd->DrawRectangle(xc14, yc00, xc14 + lineHeight / 2 - 1, yc01 - 1, frameColor);
+  osd->DrawRectangle(xc14 + lineHeight / 2, yc00, xc15 - 1, yc00 + lineHeight / 2 - 1, clrTransparent);
+  osd->DrawEllipse  (xc14 + lineHeight / 2, yc00, xc15 - 1, yc01 - 1, frameColor, 5);
+}
+
+cSkinLCARSDisplayChannel::~cSkinLCARSDisplayChannel()
+{
+  delete tallFont;
+  delete tinyFont;
+  delete osd;
+}
+
+void cSkinLCARSDisplayChannel::DrawDate(void)
+{
+  cString s = DayDateTime();
+  if (initial || strcmp(s, lastDate)) {
+     osd->DrawText(xc12, yc11, s, Theme.Color(clrDateFg), Theme.Color(clrDateBg), cFont::GetFont(fontOsd), xc13 - xc12, lineHeight, taRight | taBorder);
+     lastDate = s;
+     }
+}
+
+void cSkinLCARSDisplayChannel::DrawTrack(void)
+{
+  cDevice *Device = cDevice::PrimaryDevice();
+  const tTrackId *Track = Device->GetTrack(Device->GetCurrentAudioTrack());
+  if (!Track && *lastTrackId.description || Track && strcmp(lastTrackId.description, Track->description)) {
+     osd->DrawText(xc03, yc07, Track ? Track->description : "", Theme.Color(clrTrackName), Theme.Color(clrBackground), cFont::GetFont(fontOsd), xc07 - xc03);
+     strn0cpy(lastTrackId.description, Track ? Track->description : "", sizeof(lastTrackId.description));
+     }
+}
+
+void cSkinLCARSDisplayChannel::DrawSeen(int Current, int Total)
+{
+  int Seen = min(xc07 - xc06, int((xc07 - xc06) * double(Current) / Total));
+  if (initial || Seen != lastSeen) {
+     int y0 = yc11 - ShowSeenExtent;
+     int y1 = yc11 + lineHeight / 2 - Gap / 2;
+     osd->DrawRectangle(xc06, y0, xc06 + Seen - 1, y1 - 1, Theme.Color(clrSeen));
+     osd->DrawRectangle(xc06 + Seen, y0, xc07 - 1, y1 - 1, Theme.Color(clrBackground));
+     lastSeen = Seen;
+     }
+}
+
+void cSkinLCARSDisplayChannel::DrawDevice(void)
+{
+  const cDevice *Device = cDevice::ActualDevice();
+  if (DrawDeviceData(osd, Device, xc10, yc11, xc11, yc12, xs, tinyFont, lastDeviceType, lastCamSlot, Device->DeviceNumber() != lastDeviceNumber)) {
+     lastDeviceNumber = Device->DeviceNumber();
+     // Make sure signal meters are redrawn:
+     lastSignalStrength = -1;
+     lastSignalQuality = -1;
+     lastSignalDisplay = 0;
+     }
+}
+
+void cSkinLCARSDisplayChannel::DrawSignal(void)
+{
+  time_t Now = time(NULL);
+  if (Now != lastSignalDisplay) {
+     DrawDeviceSignal(osd, cDevice::ActualDevice(), xs + lineHeight / 2, yc11, xc11, yc12, lastSignalStrength, lastSignalQuality, initial);
+     lastSignalDisplay = Now;
+     }
+}
+
+void cSkinLCARSDisplayChannel::SetChannel(const cChannel *Channel, int Number)
+{
+  int x = xc13;
+  int xi = x - SymbolSpacing -
+           bmRecording.Width() - SymbolSpacing -
+           bmEncrypted.Width() - SymbolSpacing -
+           bmDolbyDigital.Width() - SymbolSpacing -
+           bmAudio.Width() - SymbolSpacing -
+           max(bmTeletext.Width(), bmRadio.Width()) - SymbolSpacing;
+  osd->DrawRectangle(xi, yc00, xc13 - 1, yc01 - 1, frameColor);
+  if (Channel && !Channel->GroupSep()) {
+     bool rec = cRecordControls::Active();
+     x -= bmRecording.Width() + SymbolSpacing;
+     osd->DrawBitmap(x, yc00 + (yc01 - yc00 - bmRecording.Height()) / 2, bmRecording, Theme.Color(rec ? clrChannelSymbolRecFg : clrChannelSymbolOff), rec ? Theme.Color(clrChannelSymbolRecBg) : frameColor);
+     x -= bmEncrypted.Width() + SymbolSpacing;
+     osd->DrawBitmap(x, yc00 + (yc01 - yc00 - bmEncrypted.Height()) / 2, bmEncrypted, Theme.Color(Channel->Ca() ? clrChannelSymbolOn : clrChannelSymbolOff), frameColor);
+     x -= bmDolbyDigital.Width() + SymbolSpacing;
+     osd->DrawBitmap(x, yc00 + (yc01 - yc00 - bmDolbyDigital.Height()) / 2, bmDolbyDigital, Theme.Color(Channel->Dpid(0) ? clrChannelSymbolOn : clrChannelSymbolOff), frameColor);
+     x -= bmAudio.Width() + SymbolSpacing;
+     osd->DrawBitmap(x, yc00 + (yc01 - yc00 - bmAudio.Height()) / 2, bmAudio, Theme.Color(Channel->Apid(1) ? clrChannelSymbolOn : clrChannelSymbolOff), frameColor);
+     if (Channel->Vpid()) {
+        x -= bmTeletext.Width() + SymbolSpacing;
+        osd->DrawBitmap(x, yc00 + (yc01 - yc00 - bmTeletext.Height()) / 2, bmTeletext, Theme.Color(Channel->Tpid() ? clrChannelSymbolOn : clrChannelSymbolOff), frameColor);
+        }
+     else if (Channel->Apid(0)) {
+        x -= bmRadio.Width() + SymbolSpacing;
+        osd->DrawBitmap(x, yc00 + (yc01 - yc00 - bmRadio.Height()) / 2, bmRadio, Theme.Color(clrChannelSymbolOn), frameColor);
+        }
+     }
+  cString ChNumber("");
+  cString ChName("");
+  if (Channel) {
+     ChName = Channel->Name();
+     if (!Channel->GroupSep())
+        ChNumber = cString::sprintf("%d%s", Channel->Number(), Number ? "-" : "");
+     }
+  else if (Number)
+     ChNumber = cString::sprintf("%d-", Number);
+  else
+     ChName = ChannelString(NULL, NULL);
+  osd->DrawText(xc00, yc00, ChNumber, Theme.Color(clrChannelFrameFg), frameColor, tallFont, xc02 - xc00, yc02 - yc00, taTop | taRight | taBorder);
+  osd->DrawText(xc03, yc00, ChName, Theme.Color(clrChannelName), Theme.Color(clrBackground), tallFont, xi - xc03 - lineHeight, 0, taTop | taLeft);
+  lastSignalDisplay = 0;
+  if (withInfo)
+     DrawDevice();
+}
+
+void cSkinLCARSDisplayChannel::SetEvents(const cEvent *Present, const cEvent *Following)
+{
+  if (!withInfo)
+     return;
+  if (present != Present)
+     lastSeen = -1;
+  present = Present;
+  for (int i = 0; i < 2; i++) {
+      const cEvent *e = !i ? Present : Following;
+      int y = !i ? yc03 : yc05;
+      if (e) {
+         osd->DrawText(xc00, y, e->GetTimeString(), Theme.Color(clrChannelFrameFg), frameColor, cFont::GetFont(fontOsd), xc02 - xc00, 0, taRight | taBorder);
+         osd->DrawText(xc03, y, e->Title(), Theme.Color(clrEventTitle), Theme.Color(clrBackground), cFont::GetFont(fontOsd), xc13 - xc03);
+         osd->DrawText(xc03, y + lineHeight, e->ShortText(), Theme.Color(clrEventShortText), Theme.Color(clrBackground), cFont::GetFont(fontSml), xc13 - xc03);
+         }
+      else {
+         osd->DrawRectangle(xc00, y, xc02 - 1, y + lineHeight, frameColor);
+         osd->DrawRectangle(xc02, y, xc13 - 1, y + 2 * lineHeight, Theme.Color(clrBackground));
+         }
+      }
+}
+
+void cSkinLCARSDisplayChannel::SetMessage(eMessageType Type, const char *Text)
+{
+  if (Text) {
+     int y0 = yc11 - ShowSeenExtent;
+     int y1 = yc11;
+     osd->SaveRegion(xc06, y0, xc13 - 1, yc12 - 1);
+     osd->DrawRectangle(xc06, y0, xc07, y1 - 1, Theme.Color(clrBackground)); // clears the "seen" bar
+     osd->DrawText(xc06, yc11, Text, Theme.Color(clrMessageStatusFg + 2 * Type), Theme.Color(clrMessageStatusBg + 2 * Type), cFont::GetFont(fontSml), xc13 - xc06, yc12 - yc11, taCenter);
+     }
+  else
+     osd->RestoreRegion();
+}
+
+void cSkinLCARSDisplayChannel::Flush(void)
+{
+  if (withInfo) {
+     if (!message) {
+        DrawDate();
+        DrawTrack();
+        DrawDevice();
+        DrawSignal();
+        }
+     int Current = 0;
+     int Total = 0;
+     if (present) {
+        time_t t = time(NULL);
+        if (t > present->StartTime())
+           Current = t - present->StartTime();
+        Total = present->Duration();
+        }
+     DrawSeen(Current, Total);
+     }
+  osd->Flush();
+  initial = false;
+}
+
+// --- cSkinLCARSDisplayMenu -------------------------------------------------
+
+class cSkinLCARSDisplayMenu : public cSkinDisplayMenu {
+private:
+  cOsd *osd;
+  int xa00, xa01, xa02, xa03, xa04, xa05, xa06, xa07, xa08, xa09;
+  int yt00, yt01, yt02, yt03, yt04, yt05, yt06;
+  int yc00, yc01, yc02, yc03, yc04, yc05, yc06, yc07, yc08, yc09, yc10, yc11;
+  int yb00, yb01, yb02, yb03, yb04, yb05, yb06, yb07, yb08, yb09, yb10, yb11, yb12, yb13, yb14, yb15;
+  int xm00, xm01, xm02, xm03, xm04, xm05, xm06, xm07, xm08;
+  int ym00, ym01, ym02, ym03, ym04, ym05, ym06, ym07;
+  int xs00, xs01, xs02, xs03, xs04, xs05, xs06, xs07, xs08, xs09, xs10, xs11, xs12, xs13;
+  int ys00, ys01, ys02, ys03, ys04, ys05;
+  int xi00, xi01, xi02, xi03;
+  int yi00, yi01;
+  int xb00, xb01, xb02, xb03, xb04, xb05, xb06, xb07, xb08, xb09, xb10, xb11, xb12, xb13, xb14, xb15;
+  int xd00, xd01, xd02, xd03, xd04, xd05, xd06, xd07;
+  int yd00, yd01, yd02, yd03, yd04, yd05;
+  int xs; // starting column for signal display
+  int lineHeight;
+  cFont *tinyFont;
+  cFont *tallFont;
+  tColor frameColor;
+  int currentIndex;
+  cVector<int> deviceOffset;
+  cVector<bool> deviceRecording;
+  cString lastDeviceType[MAXDEVICES];
+  cVector<cCamSlot *> lastCamSlot;
+  cVector<int> lastSignalStrength;
+  cVector<int> lastSignalQuality;
+  bool initial;
+  enum eCurrentMode { cmUnknown, cmLive, cmPlay };
+  eCurrentMode lastMode;
+  cString lastDate;
+  int lastDiskUsageState;
+  bool lastDiskAlert;
+  double lastSystemLoad;
+  int lastTimersState;
+  time_t lastSignalDisplay;
+  int lastLiveIndicatorY;
+  bool lastLiveIndicatorTransferring;
+  const cChannel *lastChannel;
+  const cEvent *lastEvent;
+  const cRecording *lastRecording;
+  cString lastHeader;
+  int lastSeen;
+  static cBitmap bmArrowUp, bmArrowDown, bmTransferMode;
+  void DrawMainFrameUpper(tColor Color);
+  void DrawMainFrameLower(void);
+  void DrawMainButton(const char *Text, int x0, int x1, int x2, int x3, int y0, int y1, tColor ColorFg, tColor ColorBg, const cFont *Font);
+  void DrawMenuFrame(void);
+  void DrawMainBracket(void);
+  void DrawStatusElbows(void);
+  void DrawDate(void);
+  void DrawDisk(void);
+  void DrawLoad(void);
+  void DrawFrameDisplay(void);
+  void DrawScrollbar(int Total, int Offset, int Shown, bool CanScrollUp, bool CanScrollDown);
+  void DrawTimer(const cTimer *Timer, int y, bool MultiRec);
+  void DrawTimers(void);
+  void DrawDevice(const cDevice *Device);
+  void DrawDevices(void);
+  void DrawLiveIndicator(void);
+  void DrawSignals(void);
+  void DrawLive(const cChannel *Channel);
+  void DrawPlay(cControl *Control);
+  void DrawInfo(const cEvent *Event, bool WithTime);
+  void DrawSeen(int Current, int Total);
+  void DrawTextScrollbar(void);
+public:
+  cSkinLCARSDisplayMenu(void);
+  virtual ~cSkinLCARSDisplayMenu();
+  virtual void Scroll(bool Up, bool Page);
+  virtual int MaxItems(void);
+  virtual void Clear(void);
+  virtual void SetMenuCategory(eMenuCategory MenuCategory);
+  virtual void SetTitle(const char *Title);
+  virtual void SetButtons(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL);
+  virtual void SetMessage(eMessageType Type, const char *Text);
+  virtual void SetItem(const char *Text, int Index, bool Current, bool Selectable);
+  virtual void SetScrollbar(int Total, int Offset);
+  virtual void SetEvent(const cEvent *Event);
+  virtual void SetRecording(const cRecording *Recording);
+  virtual void SetText(const char *Text, bool FixedFont);
+  virtual int GetTextAreaWidth(void) const;
+  virtual const cFont *GetTextAreaFont(bool FixedFont) const;
+  virtual void Flush(void);
+  };
+
+cBitmap cSkinLCARSDisplayMenu::bmArrowUp(arrowup_xpm);
+cBitmap cSkinLCARSDisplayMenu::bmArrowDown(arrowdown_xpm);
+cBitmap cSkinLCARSDisplayMenu::bmTransferMode(play_xpm);
+
+cSkinLCARSDisplayMenu::cSkinLCARSDisplayMenu(void)
+{
+  tallFont = cFont::CreateFont(Setup.FontOsd, Setup.FontOsdSize * 1.8);
+  initial = true;
+  lastMode = cmUnknown;
+  lastChannel = NULL;
+  lastEvent = NULL;
+  lastRecording = NULL;
+  lastSeen = -1;
+  lastTimersState = -1;
+  lastSignalDisplay = 0;
+  lastLiveIndicatorY = -1;
+  lastLiveIndicatorTransferring = false;
+  lastDiskUsageState = -1;
+  lastDiskAlert = false;
+  lastSystemLoad = -1;
+  const cFont *font = cFont::GetFont(fontOsd);
+  lineHeight = font->Height();
+  tinyFont = CreateTinyFont(lineHeight);
+  frameColor = Theme.Color(clrMenuFrameBg);
+  currentIndex = -1;
+  // The outer frame:
+  int d = 5 * lineHeight;
+  xa00 = 0;
+  xa01 = xa00 + d / 2;
+  xa02 = xa00 + d;
+  xa03 = xa02 + lineHeight;
+  xa04 = xa02 + d / 4;
+  xa05 = xa02 + d;
+  xa06 = xa05 + Gap;
+  xa09 = cOsd::OsdWidth();
+  xa08 = xa09 - lineHeight;
+  xa07 = xa08 - Gap;
+
+  yt00 = 0;
+  yt01 = yt00 + lineHeight;
+  yt02 = yt01 + lineHeight;
+  yt03 = yt01 + d / 4;
+  yt04 = yt02 + Gap;
+  yt05 = yt00 + d / 2;
+  yt06 = yt04 + 2 * lineHeight;
+
+  yc00 = yt06 + Gap;
+  yc05 = yc00 + 3 * lineHeight + Gap / 2;
+  yc04 = yc05 - lineHeight;
+  yc03 = yc04 - lineHeight;
+  yc02 = yc04 - d / 4;
+  yc01 = yc05 - d / 2;
+
+  yc06 = yc05 + Gap;
+  yc07 = yc06 + lineHeight;
+  yc08 = yc07 + lineHeight;
+  yc09 = yc07 + d / 4;
+  yc10 = yc06 + d / 2;
+  yc11 = yc06 + 3 * lineHeight + Gap / 2;
+
+  yb00 = yc11 + Gap;
+  yb01 = yb00 + 2 * lineHeight;
+  yb02 = yb01 + Gap;
+  yb03 = yb02 + 2 * lineHeight;
+  yb04 = yb03 + Gap;
+  yb05 = yb04 + 2 * lineHeight;
+  yb06 = yb05 + Gap;
+  yb07 = yb06 + 2 * lineHeight;
+  yb08 = yb07 + Gap;
+
+  yb15 = cOsd::OsdHeight();
+  yb14 = yb15 - lineHeight;
+  yb13 = yb14 - lineHeight;
+  yb12 = yb14 - d / 4;
+  yb11 = yb15 - d / 2;
+  yb10 = yb13 - Gap - 2 * lineHeight;
+  yb09 = yb10 - Gap;
+
+  // Compensate for large font size:
+  if (yb09 - yb08 < 2 * lineHeight) {
+     yb08 = yb06;
+     yb06 = 0; // drop empty rectangle
+     }
+  if (yb09 - yb08 < 2 * lineHeight) {
+     yb05 = yb09;
+     yb08 = 0; // drop "LCARS" display
+     }
+  if (yb05 - yb04 < 2 * lineHeight) {
+     yb03 = yb09;
+     yb04 = 0; // drop "LOAD" display
+     }
+  if (yb03 - yb02 < 2 * lineHeight) {
+     yb01 = yb09;
+     yb02 = 0; // drop "DISK" display
+     }
+  // Anything else is just insanely large...
+
+  // The main command menu:
+  xm00 = xa03;
+  xm01 = xa05;
+  xm02 = xa06;
+  xm08 = (xa09 + xa00) / 2;
+  xm07 = xm08 - lineHeight;
+  xm06 = xm07 - lineHeight / 2;
+  xm05 = xm06 - lineHeight / 2;
+  xm04 = xm05 - lineHeight;
+  xm03 = xm04 - Gap;
+  ym00 = yc08;
+  ym01 = ym00 + lineHeight / 2;
+  ym02 = ym01 + lineHeight / 2;
+  ym03 = ym02 + Gap;
+  ym07 = yb15;
+  ym06 = ym07 - lineHeight / 2;
+  ym05 = ym06 - lineHeight / 2;
+  ym04 = ym05 - Gap;
+
+  // The status area:
+  xs00 = xm08 + Gap + lineHeight + Gap;
+  xs13 = xa09;
+  xs12 = xa08;
+  xs11 = xa07;
+  xs05 = (xs00 + xs11 + Gap) / 2;
+  xs04 = xs05 - lineHeight / 2;
+  xs03 = xs04 - lineHeight / 2;
+  xs02 = xs03 - 2 * lineHeight;
+  xs01 = xs02 - Gap;
+  xs06 = xs05 + Gap;
+  xs07 = xs06 + lineHeight / 2;
+  xs08 = xs07 + lineHeight / 2;
+  xs09 = xs08 + 2 * lineHeight;
+  xs10 = xs09 + Gap;
+  ys00 = yc06;
+  ys01 = ys00 + lineHeight;
+  ys02 = ys01 + lineHeight / 2;
+  ys04 = ys01 + lineHeight;
+  ys03 = ys04 - Gap;
+  ys05 = yb15;
+
+  // The color buttons in submenus:
+  xb00 = xa06;
+  xb15 = xa07;
+  int w = (xa08 - xa06) / 4;
+  xb01 = xb00 + lineHeight / 2;
+  xb02 = xb01 + Gap;
+  xb04 = xb00 + w;
+  xb03 = xb04 - Gap;
+  xb05 = xb04 + lineHeight / 2;
+  xb06 = xb05 + Gap;
+  xb08 = xb04 + w;
+  xb07 = xb08 - Gap;
+  xb09 = xb08 + lineHeight / 2;
+  xb10 = xb09 + Gap;
+  xb12 = xb08 + w;
+  xb11 = xb12 - Gap;
+  xb13 = xb12 + lineHeight / 2;
+  xb14 = xb13 + Gap;;
+
+  // The color buttons in the main menu:
+  int r = lineHeight;
+  xd07 = xa09;
+  xd06 = xd07 - r;
+  xd05 = xd06 - 4 * r;
+  xd04 = xd05 - r;
+  xd03 = xd04 - Gap;
+  xd02 = xd03 - r;
+  xd01 = xd02 - 4 * r;
+  xd00 = xd01 - r;
+  yd00 = yt00;
+  yd05 = yc04 - Gap;
+  yd04 = yd05 - 2 * r;
+  yd03 = yd04 - Gap;
+  yd02 = yd03 - 2 * r;
+  yd01 = yd02 - Gap;
+
+  xs = 0;
+
+  osd = CreateOsd(cOsd::OsdLeft(), cOsd::OsdTop(), xa00, yt00, xa09 - 1, yb15 - 1);
+}
+
+cSkinLCARSDisplayMenu::~cSkinLCARSDisplayMenu()
+{
+  delete tallFont;
+  delete tinyFont;
+  delete osd;
+}
+
+void cSkinLCARSDisplayMenu::SetMenuCategory(eMenuCategory MenuCategory)
+{
+  if (initial || MenuCategory != cSkinDisplayMenu::MenuCategory()) {
+     cSkinDisplayMenu::SetMenuCategory(MenuCategory);
+     initial = true;
+     osd->DrawRectangle(xa00, yt00, xa09 - 1, yb15 - 1, Theme.Color(clrBackground));
+     if (MenuCategory == mcMain) {
+        yi00 = ym03;
+        yi01 = ym04;
+        xi00 = xm00;
+        xi01 = xm03;
+        xi02 = xm04;
+        xi03 = xm05;
+        lastTimersState = -1;
+        DrawMainFrameLower();
+        DrawMainBracket();
+        DrawStatusElbows();
+        }
+     else {
+        yi00 = yt02;
+        yi01 = yb13;
+        xi00 = xa03;
+        xi01 = xa07;
+        xi02 = xa08;
+        xi03 = xa09;
+        DrawMenuFrame();
+        }
+     }
+}
+
+void cSkinLCARSDisplayMenu::DrawMainFrameUpper(tColor Color)
+{
+  // Top left rectangles:
+  osd->DrawRectangle(xa00, yt00, xa02 - 1, yt02 - 1, Color);
+  osd->DrawRectangle(xa00, yt04, xa02 - 1, yt06 - 1, Color);
+  // Upper elbow:
+  osd->DrawRectangle(xa00, yc00, xa01 - 1, yc01 - 1, Color);
+  osd->DrawEllipse  (xa00, yc01, xa01 - 1, yc05 - 1, Color, 3);
+  osd->DrawRectangle(xa01, yc00, xa02 - 1, yc05 - 1, Color);
+  osd->DrawEllipse  (xa02, yc02, xa04 - 1, yc04 - 1, Color, -3);
+  osd->DrawRectangle(xa02, yc04, xa05 - 1, yc05 - 1, Color);
+  // Upper delimiter:
+  osd->DrawRectangle(xa06, yc04 + lineHeight / 2, xm08 - 1, yc05 - 1, Color);
+  osd->DrawRectangle(xm08 + Gap, yc04, xs00 - Gap - 1, yc05 - 1, Color);
+  osd->DrawRectangle(xs00, yc04, xs05 - 1, yc05 - 1, Color);
+  osd->DrawRectangle(xs06, yc04, xa07 - 1, yc05 - 1, Color);
+  osd->DrawRectangle(xa08, yc04, xa09 - 1, yc05 - 1, Color);
+}
+
+void cSkinLCARSDisplayMenu::DrawMainFrameLower(void)
+{
+  const cFont *font = cFont::GetFont(fontOsd);
+  // Lower elbow:
+  osd->DrawRectangle(xa00, yc10, xa01 - 1, yc11 - 1, frameColor);
+  osd->DrawEllipse  (xa00, yc06, xa01 - 1, yc10 - 1, frameColor, 2);
+  osd->DrawRectangle(xa01, yc06, xa02 - 1, yc11 - 1, frameColor);
+  osd->DrawEllipse  (xa02, yc07, xa04 - 1, yc09 - 1, frameColor, -2);
+  osd->DrawRectangle(xa02, yc06, xa05 - 1, yc07 - 1, frameColor);
+  // Lower delimiter:
+  osd->DrawRectangle(xa06, yc06, xm08 - 1, yc07 - lineHeight / 2 - 1, frameColor);
+  osd->DrawRectangle(xm08 + Gap, yc06, xs00 - Gap - 1, yc07 - 1, frameColor);
+  osd->DrawRectangle(xa08, yc06, xa09 - 1, yc07 - 1, frameColor);
+  // VDR version:
+  osd->DrawRectangle(xa00, yb10, xa02 - 1, yb15 - 1, frameColor);
+  osd->DrawText(xa00, yb10, "VDR", Theme.Color(clrMenuFrameFg), frameColor, tallFont, xa02 - xa00, yb11 - yb10, taTop | taRight | taBorder);
+  osd->DrawText(xa00, yb15 - lineHeight, VDRVERSION, Theme.Color(clrMenuFrameFg), frameColor, font, xa02 - xa00, lineHeight, taBottom | taRight | taBorder);
+}
+
+void cSkinLCARSDisplayMenu::DrawMainButton(const char *Text, int x0, int x1, int x2, int x3, int y0, int y1, tColor ColorFg, tColor ColorBg, const cFont *Font)
+{
+  int h = y1 - y0;
+  osd->DrawEllipse(x0, y0, x1 - 1, y1 - 1, ColorBg, 7);
+  osd->DrawText(x1 + Gap, y0, Text, ColorFg, ColorBg, Font, x2 - x1 - Gap, h, taBottom | taRight);
+  osd->DrawEllipse(x2, y0, x3 - 1, y1 - 1, ColorBg, 5);
+}
+
+void cSkinLCARSDisplayMenu::DrawMenuFrame(void)
+{
+  // Upper elbow:
+  osd->DrawRectangle(xa00, yt05, xa01 - 1, yt06 - 1, frameColor);
+  osd->DrawRectangle(xa00, yt00, xa01 - 1, yt05 - 1, clrTransparent);
+  osd->DrawEllipse  (xa00, yt00, xa01 - 1, yt05 - 1, frameColor, 2);
+  osd->DrawRectangle(xa01, yt00, xa02 - 1, yt06 - 1, frameColor);
+  osd->DrawEllipse  (xa02, yt01, xa04 - 1, yt03 - 1, frameColor, -2);
+  osd->DrawRectangle(xa02, yt00, xa05 - 1, yt01 - 1, frameColor);
+  osd->DrawRectangle(xa06, yt00, xa07 - 1, yt01 - 1, frameColor);
+  osd->DrawRectangle(xa08, yt00, xa08 + lineHeight / 2 - 1, yt01 - 1, frameColor);
+  osd->DrawRectangle(xa08 + lineHeight / 2, yt00, xa09 - 1, yt00 + lineHeight / 2 - 1, clrTransparent);
+  osd->DrawEllipse  (xa08 + lineHeight / 2, yt00, xa09 - 1, yt01 - 1, frameColor, 5);
+  // Center part:
+  osd->DrawRectangle(xa00, yc00, xa02 - 1, yc11 - 1, frameColor);
+  // Lower elbow:
+  osd->DrawRectangle(xa00, yb10, xa02 - 1, yb11 - 1, frameColor);
+  osd->DrawRectangle(xa00, yb11, xa01 - 1, yb15 - 1, clrTransparent);
+  osd->DrawEllipse  (xa00, yb11, xa01 - 1, yb15 - 1, frameColor, 3);
+  osd->DrawRectangle(xa01, yb11, xa02 - 1, yb15 - 1, frameColor);
+  osd->DrawEllipse  (xa02, yb12, xa04 - 1, yb14 - 1, frameColor, -3);
+  osd->DrawRectangle(xa02, yb14, xa05 - 1, yb15 - 1, frameColor);
+  osd->DrawRectangle(xa08, yb14, xa08 + lineHeight / 2 - 1, yb15 - 1, frameColor);
+  osd->DrawRectangle(xa08 + lineHeight / 2, yb14 + lineHeight / 2, xa09 - 1, yb15 - 1, clrTransparent);
+  osd->DrawEllipse  (xa08 + lineHeight / 2, yb14, xa09 - 1, yb15 - 1, frameColor, 5);
+  osd->DrawText(xa00, yb10, "VDR", Theme.Color(clrMenuFrameFg), frameColor, tallFont, xa02 - xa00, yb11 - yb10, taTop | taRight | taBorder);
+  // Color buttons:
+  osd->DrawRectangle(xb00, yb14, xb01 - 1, yb15 - 1, Theme.Color(clrButtonRedBg));
+  osd->DrawRectangle(xb04, yb14, xb05 - 1, yb15 - 1, Theme.Color(clrButtonGreenBg));
+  osd->DrawRectangle(xb08, yb14, xb09 - 1, yb15 - 1, Theme.Color(clrButtonYellowBg));
+  osd->DrawRectangle(xb12, yb14, xb13 - 1, yb15 - 1, Theme.Color(clrButtonBlueBg));
+}
+
+void cSkinLCARSDisplayMenu::DrawDate(void)
+{
+  cString s = DayDateTime();
+  if (initial || strcmp(s, lastDate)) {
+     const cFont *font = cFont::GetFont(fontOsd);
+     tColor ColorFg = Theme.Color(clrDateFg);
+     tColor ColorBg = Theme.Color(clrDateBg);
+     lastDate = s;
+     const char *t = strrchr(s, ' ');
+     osd->DrawText(xa00, yb01 - lineHeight, t, ColorFg, ColorBg, font, xa02 - xa00, lineHeight, taBottom | taRight | taBorder);
+     s.Truncate(t - s);
+     osd->DrawText(xa00, yb00, s, ColorFg, ColorBg, font, xa02 - xa00, yb01 - yb00 - lineHeight, taTop | taRight | taBorder);
+     }
+}
+
+void cSkinLCARSDisplayMenu::DrawDisk(void)
+{
+  if (yb02) {
+     if (cVideoDiskUsage::HasChanged(lastDiskUsageState) || initial) { // must call HasChanged() first, or it shows an outdated value in the 'initial' case!
+        const cFont *font = cFont::GetFont(fontOsd);
+        int DiskUsage = cVideoDiskUsage::UsedPercent();
+        bool DiskAlert = DiskUsage > DISKUSAGEALERTLIMIT;
+        tColor ColorFg = DiskAlert ? Theme.Color(clrAlertFg) : Theme.Color(clrMenuFrameFg);
+        tColor ColorBg = DiskAlert ? Theme.Color(clrAlertBg) : frameColor;
+        if (initial || DiskAlert != lastDiskAlert)
+           osd->DrawText(xa00, yb02, tr("DISK"), ColorFg, ColorBg, tinyFont, xa02 - xa00, yb03 - yb02, taTop | taLeft | taBorder);
+        osd->DrawText(xa01, yb02, itoa(DiskUsage), ColorFg, ColorBg, font, xa02 - xa01, lineHeight, taBottom | taRight | taBorder);
+        osd->DrawText(xa00, yb03 - lineHeight, cString::sprintf("%02d:%02d", cVideoDiskUsage::FreeMinutes() / 60, cVideoDiskUsage::FreeMinutes() % 60), ColorFg, ColorBg, font, xa02 - xa00, 0, taBottom | taRight | taBorder);
+        lastDiskAlert = DiskAlert;
+        }
+     }
+}
+
+void cSkinLCARSDisplayMenu::DrawLoad(void)
+{
+  if (yb04) {
+     tColor ColorFg = Theme.Color(clrMenuFrameFg);
+     tColor ColorBg = frameColor;
+     if (initial)
+        osd->DrawText(xa00, yb04, tr("LOAD"), ColorFg, ColorBg, tinyFont, xa02 - xa00, yb05 - yb04, taTop | taLeft | taBorder);
+     double SystemLoad;
+     if (getloadavg(&SystemLoad, 1) > 0) {
+        if (initial || SystemLoad != lastSystemLoad) {
+           osd->DrawText(xa00, yb05 - lineHeight, cString::sprintf("%.1f", SystemLoad), ColorFg, ColorBg, cFont::GetFont(fontOsd), xa02 - xa00, lineHeight, taBottom | taRight | taBorder);
+           lastSystemLoad = SystemLoad;
+           }
+        }
+     }
+}
+
+void cSkinLCARSDisplayMenu::DrawMainBracket(void)
+{
+  tColor Color = Theme.Color(clrMenuMainBracket);
+  osd->DrawRectangle(xm00, ym00, xm01 - 1, ym01 - 1, Color);
+  osd->DrawRectangle(xm02, ym00, xm07 - 1, ym01 - 1, Color);
+  osd->DrawEllipse  (xm07, ym00, xm08 - 1, ym02 - 1, Color, 1);
+  osd->DrawEllipse  (xm06, ym01, xm07 - 1, ym02 - 1, Color, -1);
+  osd->DrawRectangle(xm07, ym03, xm08 - 1, ym04 - 1, Color);
+  osd->DrawEllipse  (xm06, ym05, xm07 - 1, ym06 - 1, Color, -4);
+  osd->DrawEllipse  (xm07, ym05, xm08 - 1, ym07 - 1, Color, 4);
+  osd->DrawRectangle(xm02, ym06, xm07 - 1, ym07 - 1, Color);
+  osd->DrawRectangle(xm00, ym06, xm01 - 1, ym07 - 1, Color);
+}
+
+void cSkinLCARSDisplayMenu::DrawStatusElbows(void)
+{
+  const cFont *font = cFont::GetFont(fontOsd);
+  osd->DrawText     (xs00, ys00, tr("TIMERS"), Theme.Color(clrMenuFrameFg), frameColor, font, xs01 - xs00, lineHeight, taBottom | taLeft | taBorder);
+  osd->DrawRectangle(xs02, ys00, xs03 - 1, ys01 - 1, frameColor);
+  osd->DrawEllipse  (xs03, ys00, xs05 - 1, ys01 - 1, frameColor, 1);
+  osd->DrawEllipse  (xs03, ys01, xs04 - 1, ys02 - 1, frameColor, -1);
+  osd->DrawRectangle(xs04, ys01, xs05 - 1, ys03 - 1, frameColor);
+  osd->DrawRectangle(xs04, ys04, xs05 - 1, ys05 - 1, frameColor);
+  osd->DrawText     (xs10, ys00, tr("DEVICES"), Theme.Color(clrMenuFrameFg), frameColor, font, xs11 - xs10, lineHeight, taBottom | taRight | taBorder);
+  osd->DrawRectangle(xs08, ys00, xs09 - 1, ys01 - 1, frameColor);
+  osd->DrawEllipse  (xs06, ys00, xs08 - 1, ys01 - 1, frameColor, 2);
+  osd->DrawEllipse  (xs07, ys01, xs08 - 1, ys02 - 1, frameColor, -2);
+  osd->DrawRectangle(xs06, ys01, xs07 - 1, ys03 - 1, frameColor);
+  osd->DrawRectangle(xs06, ys04, xs07 - 1, ys05 - 1, frameColor);
+  osd->DrawRectangle(xs12, ys00, xs13 - 1, ys01 - 1, frameColor);
+}
+
+void cSkinLCARSDisplayMenu::DrawFrameDisplay(void)
+{
+  DrawDate();
+  DrawDisk();
+  DrawLoad();
+  if (initial) {
+     if (yb06)
+        osd->DrawRectangle(xa00, yb06, xa02 - 1, yb07 - 1, frameColor);
+     if (yb08) {
+        const cFont *font = cFont::GetFont(fontOsd);
+        osd->DrawRectangle(xa00, yb08, xa02 - 1, yb09 - 1, frameColor);
+        osd->DrawText(xa00, yb09 - lineHeight, "LCARS", Theme.Color(clrMenuFrameFg), frameColor, font, xa02 - xa00, lineHeight, taBottom | taRight | taBorder);
+        }
+     }
+}
+
+void cSkinLCARSDisplayMenu::DrawScrollbar(int Total, int Offset, int Shown, bool CanScrollUp, bool CanScrollDown)
+{
+  int x0, x1, tt, tb;
+  tColor ClearColor;
+  if (MenuCategory() == mcMain) {
+     x0 = xm07;
+     x1 = xm08;
+     tt = ym03;
+     tb = ym04;
+     ClearColor = Theme.Color(clrMenuMainBracket);
+     }
+  else {
+     x0 = xa02 + Gap;
+     x1 = x0 + lineHeight / 2;
+     tt = yc00;
+     tb = yc11;
+     ClearColor = Theme.Color(clrBackground);
+     int d = TextFrame;
+     if (CanScrollUp)
+        osd->DrawBitmap(xa02 - bmArrowUp.Width() - d, yc00 + d, bmArrowUp, Theme.Color(clrMenuScrollbarArrow), frameColor);
+     else
+        osd->DrawRectangle(xa02 - bmArrowUp.Width() - d, yc00 + d, xa02 - d - 1, yc00 + d + bmArrowUp.Height() - 1, frameColor);
+     if (CanScrollDown)
+        osd->DrawBitmap(xa02 - bmArrowDown.Width() - d, yc11 - d - bmArrowDown.Height(), bmArrowDown, Theme.Color(clrMenuScrollbarArrow), frameColor);
+     else
+        osd->DrawRectangle(xa02 - bmArrowDown.Width() - d, yc11 - d - bmArrowDown.Height(), xa02 - d - 1, yc11 - d - 1, frameColor);
+     }
+  if (Total > 0 && Total > Shown) {
+     int sw = x1 - x0;
+     int sh = max(int((tb - tt) * double(Shown) / Total + 0.5), sw);
+     int st = min(int(tt + (tb - tt) * double(Offset) / Total + 0.5), tb - sh);
+     int sb = min(st + sh, tb);
+     osd->DrawRectangle(x0, tt, x1 - 1, tb - 1, Theme.Color(clrMenuScrollbarTotal));
+     osd->DrawRectangle(x0, st, x1 - 1, sb - 1, Theme.Color(clrMenuScrollbarShown));
+     }
+  else if (MenuCategory() != mcMain)
+     osd->DrawRectangle(x0, tt, x1 - 1, tb - 1, ClearColor);
+}
+
+void cSkinLCARSDisplayMenu::DrawTimer(const cTimer *Timer, int y, bool MultiRec)
+{
+  // The timer data:
+  bool Alert = !Timer->Recording() && Timer->Pending();
+  tColor ColorFg = Alert ? Theme.Color(clrAlertFg) : Theme.Color(clrTimerFg);
+  tColor ColorBg = Alert ? Theme.Color(clrAlertFg) : Theme.Color(clrTimerBg);
+  osd->DrawRectangle(xs00, y, xs03 - 1, y + lineHeight - 1, ColorBg);
+  cString Date;
+  if (Timer->Recording())
+     Date = cString::sprintf("-%s", *TimeString(Timer->StopTime()));
+  else {
+     time_t Now = time(NULL);
+     cString Today = WeekDayName(Now);
+     cString Time = TimeString(Timer->StartTime());
+     cString Day = WeekDayName(Timer->StartTime());
+     if (Timer->StartTime() > Now + 6 * SECSINDAY)
+        Date = DayDateTime(Timer->StartTime());
+     else if (strcmp(Day, Today) != 0)
+        Date = cString::sprintf("%s %s", *Day, *Time);
+     else
+        Date = Time;
+     }
+  if (Timer->Flags() & tfVps)
+     Date = cString::sprintf("VPS %s", *Date);
+  const cChannel *Channel = Timer->Channel();
+  const cEvent *Event = Timer->Event();
+  int d = max(TextFrame / 2, 1);
+  if (Channel) {
+     osd->DrawText(xs00 + d, y, Channel->Name(), ColorFg, ColorBg, tinyFont, xs03 - xs00 - d);
+     osd->DrawText(xs03 - tinyFont->Width(Date) - d, y, Date, ColorFg, ColorBg, tinyFont);
+     }
+  if (Event)
+     osd->DrawText(xs00 + d, y + lineHeight - tinyFont->Height(), Event->Title(), ColorFg, ColorBg, tinyFont, xs03 - xs00 - 2 * d);
+  // The timer recording indicator:
+  if (Timer->Recording())
+     osd->DrawRectangle(xs03 + Gap, y - (MultiRec ? Gap : 0), xs04 - Gap / 2 - 1, y + lineHeight - 1, Theme.Color(clrMenuTimerRecording));
+}
+
+void cSkinLCARSDisplayMenu::DrawTimers(void)
+{
+  if (Timers.Modified(lastTimersState)) {
+     deviceRecording.Clear();
+     const cFont *font = cFont::GetFont(fontOsd);
+     osd->DrawRectangle(xs00, ys04, xs04 - 1, ys05 - 1, Theme.Color(clrBackground));
+     osd->DrawRectangle(xs07, ys04, xs13 - 1, ys05 - 1, Theme.Color(clrBackground));
+     cSortedTimers SortedTimers;
+     cVector<int> FreeDeviceSlots;
+     int y = ys04;
+     // Timers and recording devices:
+     while (1) {
+           int NumTimers = 0;
+           const cDevice *Device = NULL;
+           for (int i = 0; i < SortedTimers.Size(); i++) {
+               if (y + lineHeight > ys05)
+                  break;
+               if (const cTimer *Timer = SortedTimers[i]) {
+                  if (Timer->Recording()) {
+                     if (cRecordControl *RecordControl = cRecordControls::GetRecordControl(Timer)) {
+                        if (!Device || Device == RecordControl->Device()) {
+                           DrawTimer(Timer, y, NumTimers > 0);
+                           NumTimers++;
+                           if (!Device) {
+                              Device = RecordControl->Device();
+                              deviceOffset[Device->DeviceNumber()] = y;
+                              deviceRecording[Device->DeviceNumber()] = true;
+                              }
+                           else
+                              FreeDeviceSlots.Append(y);
+                           y += lineHeight + Gap;
+                           }
+                        else
+                           continue;
+                        }
+                     SortedTimers[i] = NULL;
+                     }
+                  else if (!Device) {
+                     DrawTimer(Timer, y, false);
+                     FreeDeviceSlots.Append(y);
+                     y += lineHeight + Gap;
+                     SortedTimers[i] = NULL;
+                     }
+                  }
+               }
+           if (!Device)
+              break;
+           }
+     // Devices currently not recording:
+     int Slot = 0;
+     for (int i = 0; i < cDevice::NumDevices(); i++) {
+         if (const cDevice *Device = cDevice::GetDevice(i)) {
+            if (!deviceRecording[Device->DeviceNumber()]) {
+               if (Slot < FreeDeviceSlots.Size()) {
+                  y = FreeDeviceSlots[Slot];
+                  Slot++;
+                  }
+               if (y + lineHeight > ys05)
+                  break;
+               deviceOffset[Device->DeviceNumber()] = y;
+               y += lineHeight + Gap;
+               }
+            }
+         }
+     osd->DrawText(xs02, ys00, itoa(Timers.Count()), Theme.Color(clrMenuFrameFg), frameColor, font, xs03 - xs02, ys01 - ys00, taBottom | taLeft | taBorder);
+     osd->DrawText(xs08, ys00, itoa(cDevice::NumDevices()), Theme.Color(clrMenuFrameFg), frameColor, font, xs09 - xs08, ys01 - ys00, taBottom | taRight | taBorder);
+     lastSignalDisplay = 0;
+     initial = true; // forces redrawing of devices
+     }
+}
+
+void cSkinLCARSDisplayMenu::DrawDevice(const cDevice *Device)
+{
+  int dn = Device->DeviceNumber();
+  int y = deviceOffset[dn];
+  if (y + lineHeight <= ys05) {
+     if (DrawDeviceData(osd, Device, xs08, y, xs11, y + lineHeight, xs, tinyFont, lastDeviceType[dn], lastCamSlot[dn], initial)) {
+        // Make sure signal meters are redrawn:
+        lastSignalStrength[dn] = -1;
+        lastSignalQuality[dn] = -1;
+        lastSignalDisplay = 0;
+        }
+     // The device recording indicator:
+     if (deviceRecording[dn])
+        osd->DrawRectangle(xs07 + Gap / 2, y, xs08 - Gap - 1, y + lineHeight - 1, Theme.Color(clrMenuDeviceRecording));
+     }
+}
+
+void cSkinLCARSDisplayMenu::DrawDevices(void)
+{
+  for (int i = 0; i < cDevice::NumDevices(); i++) {
+      if (const cDevice *Device = cDevice::GetDevice(i))
+         DrawDevice(Device);
+      }
+}
+
+void cSkinLCARSDisplayMenu::DrawLiveIndicator(void)
+{
+  cDevice *Device = cDevice::PrimaryDevice();
+  int y = -1;
+  bool Transferring = Device->Transferring();
+  if (!Device->Replaying() || Transferring)
+     y = deviceOffset[cDevice::ActualDevice()->DeviceNumber()];
+  if (initial || y != lastLiveIndicatorY || Transferring != lastLiveIndicatorTransferring) {
+     if (lastLiveIndicatorY >= 0)
+        osd->DrawRectangle(xs12, lastLiveIndicatorY, xs13 - 1, lastLiveIndicatorY + lineHeight - 1, Theme.Color(clrBackground));
+     if (y >= 0) {
+        osd->DrawRectangle(xs12, y, xs12 + lineHeight / 2 - 1, y + lineHeight - 1, frameColor);
+        osd->DrawEllipse  (xs12 + lineHeight / 2, y, xs13 - 1, y + lineHeight - 1, frameColor, 5);
+        if (Transferring)
+           osd->DrawBitmap((xs12 + xs13 - bmTransferMode.Width()) / 2, y + (lineHeight - bmTransferMode.Height()) / 2, bmTransferMode, Theme.Color(clrChannelFrameFg), Theme.Color(clrChannelFrameBg));
+        }
+     lastLiveIndicatorY = y;
+     lastLiveIndicatorTransferring = Transferring;
+     }
+}
+
+void cSkinLCARSDisplayMenu::DrawSignals(void)
+{
+  time_t Now = time(NULL);
+  if (initial || Now - lastSignalDisplay >= SIGNALDISPLAYDELTA) {
+     for (int i = 0; i < cDevice::NumDevices(); i++) {
+         if (const cDevice *Device = cDevice::GetDevice(i)) {
+            if (int y = deviceOffset[i])
+               DrawDeviceSignal(osd, Device, xs + lineHeight / 2, y, xs11, y + lineHeight, lastSignalStrength[i], lastSignalQuality[i], initial);
+            }
+         }
+     lastSignalDisplay = Now;
+     }
+}
+
+void cSkinLCARSDisplayMenu::DrawLive(const cChannel *Channel)
+{
+  if (lastMode != cmLive) {
+     initial = true;
+     lastMode = cmLive;
+     }
+  if (initial) {
+     DrawMainFrameUpper(Theme.Color(clrChannelFrameBg));
+     osd->DrawText(xd00, yd00, tr("LIVE"), Theme.Color(clrChannelFrameBg), Theme.Color(clrBackground), tallFont, xd07 - xd00, yd01 - yd00, taTop | taRight | taBorder);
+     }
+  if (initial || Channel != lastChannel) {
+     osd->DrawText(xa00, yt00, itoa(Channel->Number()), Theme.Color(clrChannelFrameFg), Theme.Color(clrChannelFrameBg), tallFont, xa02 - xa00, yt02 - yt00, taTop | taRight | taBorder);
+     osd->DrawText(xa03, yt00, Channel->Name(), Theme.Color(clrChannelName), Theme.Color(clrBackground), tallFont, xd00 - xa03, yd01 - yd00, taTop | taLeft);
+     lastChannel = Channel;
+     }
+  // The current programme:
+  cSchedulesLock SchedulesLock;
+  if (const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock)) {
+     if (const cSchedule *Schedule = Schedules->GetSchedule(Channel)) {
+        const cEvent *Event = Schedule->GetPresentEvent();
+        if (initial || Event != lastEvent) {
+           DrawInfo(Event, true);
+           lastEvent = Event;
+           lastSeen = -1;
+           }
+        int Current = 0;
+        int Total = 0;
+        if (Event) {
+           time_t t = time(NULL);
+           if (t > Event->StartTime())
+              Current = t - Event->StartTime();
+           Total = Event->Duration();
+           }
+        DrawSeen(Current, Total);
+        }
+     }
+}
+
+void cSkinLCARSDisplayMenu::DrawPlay(cControl *Control)
+{
+  if (lastMode != cmPlay) {
+     initial = true;
+     lastMode = cmPlay;
+     }
+  if (initial) {
+     DrawMainFrameUpper(Theme.Color(clrReplayFrameBg));
+     osd->DrawText(xd00, yd00, tr("PLAY"), Theme.Color(clrReplayFrameBg), Theme.Color(clrBackground), tallFont, xd07 - xd00, yd01 - yd00, taTop | taRight | taBorder);
+     }
+  // The current progress:
+  int Current = 0;
+  int Total = 0;
+  if (Control->GetIndex(Current, Total))
+     DrawSeen(Current, Total);
+  // The current programme:
+  if (const cRecording *Recording = Control->GetRecording()) {
+     if (initial || Recording != lastRecording) {
+        const cFont *font = cFont::GetFont(fontOsd);
+        if (const cRecordingInfo *Info = Recording->Info()) {
+           osd->DrawText(xa03, yt00, Info->ChannelName(), Theme.Color(clrChannelName), Theme.Color(clrBackground), tallFont, xd00 - xa03, yd01 - yd00, taTop | taLeft);
+           DrawInfo(Info->GetEvent(), false);
+           }
+        else
+           osd->DrawText(xa03, yt04, Recording->Name(), Theme.Color(clrEventTitle), Theme.Color(clrBackground), font, xd00 - xa03, 0, taTop | taLeft);
+        osd->DrawText(xa00, yt04, ShortDateString(Recording->Start()), Theme.Color(clrReplayFrameFg), Theme.Color(clrReplayFrameBg), font, xa02 - xa00, 0, taTop | taRight | taBorder);
+        osd->DrawText(xa00, yt06 - lineHeight, TimeString(Recording->Start()), Theme.Color(clrReplayFrameFg), Theme.Color(clrReplayFrameBg), font, xa02 - xa00, 0, taBottom | taRight | taBorder);
+        lastRecording = Recording;
+        }
+     }
+  else {
+     cString Header = Control->GetHeader();
+     if (!*lastHeader || strcmp(Header, lastHeader)) {
+        osd->DrawText(xa03, yt00, Header, Theme.Color(clrMenuText), Theme.Color(clrBackground), tallFont, xd00 - xa03, yd01 - yd00, taTop | taLeft);
+        lastHeader = Header;
+        }
+     }
+}
+
+void cSkinLCARSDisplayMenu::DrawInfo(const cEvent *Event, bool WithTime)
+{
+  if (Event) {
+     const cFont *font = cFont::GetFont(fontOsd);
+     int y = yt04;
+     osd->DrawText(xa03, y, Event->Title(), Theme.Color(clrEventTitle), Theme.Color(clrBackground), font, xd00 - xa03 - lineHeight, lineHeight, taBottom | taLeft);
+     y += lineHeight;
+     osd->DrawText(xa03, y, Event->ShortText(), Theme.Color(clrEventShortText), Theme.Color(clrBackground), cFont::GetFont(fontSml), xd00 - xa03 - lineHeight, lineHeight, taTop | taLeft);
+     if (WithTime) {
+        osd->DrawText(xa00, yt04, Event->GetTimeString(), Theme.Color(clrChannelFrameFg), Theme.Color(clrChannelFrameBg), font, xa02 - xa00, lineHeight, taTop | taRight | taBorder);
+        osd->DrawText(xa00, yt06 - lineHeight, cString::sprintf("-%s", *Event->GetEndTimeString()), Theme.Color(clrChannelFrameFg), Theme.Color(clrChannelFrameBg), font, xa02 - xa00, lineHeight, taBottom | taRight | taBorder);
+        }
+     }
+}
+
+void cSkinLCARSDisplayMenu::DrawSeen(int Current, int Total)
+{
+  int Seen = min(xm08 - xm02, int((xm08 - xm02) * double(Current) / Total));
+  if (initial || Seen != lastSeen) {
+     int y0 = yc04 - ShowSeenExtent;
+     int y1 = yc04 + lineHeight / 2 - Gap / 2;
+     osd->DrawRectangle(xm02, y0, xm02 + Seen - 1, y1 - 1, Theme.Color(clrSeen));
+     osd->DrawRectangle(xm02 + Seen, y0, xm08 - 1, y1 - 1, Theme.Color(clrBackground));
+     lastSeen = Seen;
+     }
+}
+
+void cSkinLCARSDisplayMenu::DrawTextScrollbar(void)
+{
+  if (textScroller.CanScroll())
+     DrawScrollbar(textScroller.Total(), textScroller.Offset(), textScroller.Shown(), textScroller.CanScrollUp(), textScroller.CanScrollDown());
+}
+
+void cSkinLCARSDisplayMenu::Scroll(bool Up, bool Page)
+{
+  cSkinDisplayMenu::Scroll(Up, Page);
+  DrawTextScrollbar();
+}
+
+int cSkinLCARSDisplayMenu::MaxItems(void)
+{
+  if (MenuCategory() == mcMain)
+     return (ym04 - ym03) / lineHeight;
+  else
+     return (yb13 - yt02) / lineHeight;
+}
+
+void cSkinLCARSDisplayMenu::Clear(void)
+{
+  textScroller.Reset();
+  osd->DrawRectangle(xi00, yi00, xi03 - 1, yi01 - 1, Theme.Color(clrBackground));
+}
+
+void cSkinLCARSDisplayMenu::SetTitle(const char *Title)
+{
+  if (MenuCategory() != mcMain) {
+     const cFont *font = cFont::GetFont(fontOsd);
+     int w = font->Width(Title);
+     osd->DrawRectangle(xa06, yt00, xa07 - w - Gap - 1, yt01 - 1, frameColor);
+     osd->DrawText(xa07 - w - Gap, yt00, Title, Theme.Color(clrMenuTitle), Theme.Color(clrBackground), font, w + Gap, yt01 - yt00, taRight);
+     }
+}
+
+void cSkinLCARSDisplayMenu::SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue)
+{
+  const cFont *font = cFont::GetFont(fontSml);
+  if (MenuCategory() == mcMain) {
+     DrawMainButton(Red,    xd00, xd01, xd02, xd03, yd02, yd03, Theme.Color(clrButtonRedFg),    Theme.Color(clrButtonRedBg),    font);
+     DrawMainButton(Green,  xd04, xd05, xd06, xd07, yd02, yd03, Theme.Color(clrButtonGreenFg),  Theme.Color(clrButtonGreenBg),  font);
+     DrawMainButton(Yellow, xd00, xd01, xd02, xd03, yd04, yd05, Theme.Color(clrButtonYellowFg), Theme.Color(clrButtonYellowBg), font);
+     DrawMainButton(Blue,   xd04, xd05, xd06, xd07, yd04, yd05, Theme.Color(clrButtonBlueFg),   Theme.Color(clrButtonBlueBg),   font);
+     }
+  else {
+     int h = yb15 - yb14;
+     osd->DrawText(xb02, yb14, Red,    Theme.Color(clrButtonRedFg),    Theme.Color(clrButtonRedBg),    font, xb03 - xb02, h, taLeft | taBorder);
+     osd->DrawText(xb06, yb14, Green,  Theme.Color(clrButtonGreenFg),  Theme.Color(clrButtonGreenBg),  font, xb07 - xb06, h, taLeft | taBorder);
+     osd->DrawText(xb10, yb14, Yellow, Theme.Color(clrButtonYellowFg), Theme.Color(clrButtonYellowBg), font, xb11 - xb10, h, taLeft | taBorder);
+     osd->DrawText(xb14, yb14, Blue,   Theme.Color(clrButtonBlueFg),   Theme.Color(clrButtonBlueBg),   font, xb15 - xb14, h, taLeft | taBorder);
+     }
+}
+
+void cSkinLCARSDisplayMenu::SetMessage(eMessageType Type, const char *Text)
+{
+  if (Text) {
+     osd->SaveRegion(xb00, yb14, xb15 - 1, yb15 - 1);
+     osd->DrawText(xb00, yb14, Text, Theme.Color(clrMessageStatusFg + 2 * Type), Theme.Color(clrMessageStatusBg + 2 * Type), cFont::GetFont(fontSml), xb15 - xb00, yb15 - yb14, taCenter);
+     }
+  else
+     osd->RestoreRegion();
+}
+
+void cSkinLCARSDisplayMenu::SetItem(const char *Text, int Index, bool Current, bool Selectable)
+{
+  int y = yi00 + Index * lineHeight;
+  tColor ColorFg, ColorBg;
+  if (Current) {
+     ColorFg = Theme.Color(clrMenuItemCurrentFg);
+     ColorBg = Theme.Color(clrMenuItemCurrentBg);
+     osd->DrawRectangle(xi00, y, xi01 - 1, y + lineHeight - 1, ColorBg);
+     osd->DrawRectangle(xi02, y, xi02 + lineHeight / 2 - 1, y + lineHeight - 1, ColorBg);
+     osd->DrawEllipse  (xi02 + lineHeight / 2, y, xi03 - 1, y + lineHeight - 1, ColorBg, 5);
+     currentIndex = Index;
+     }
+  else {
+     ColorFg = Theme.Color(Selectable ? clrMenuItemSelectable : clrMenuItemNonSelectable);
+     ColorBg = Theme.Color(clrBackground);
+     if (currentIndex == Index)
+        osd->DrawRectangle(xi00, y, xi03 - 1, y + lineHeight - 1, Theme.Color(clrBackground));
+     }
+  const cFont *font = cFont::GetFont(fontOsd);
+  for (int i = 0; i < MaxTabs; i++) {
+      const char *s = GetTabbedText(Text, i);
+      if (s) {
+         int xt = xi00 + TextSpacing + Tab(i);
+         osd->DrawText(xt, y, s, ColorFg, ColorBg, font, xi01 - xt);
+         }
+      if (!Tab(i + 1))
+         break;
+      }
+  SetEditableWidth(xi02 - xi00 - TextSpacing - Tab(1));
+}
+
+void cSkinLCARSDisplayMenu::SetScrollbar(int Total, int Offset)
+{
+  DrawScrollbar(Total, Offset, MaxItems(), Offset > 0, Offset + MaxItems() < Total);
+}
+
+void cSkinLCARSDisplayMenu::SetEvent(const cEvent *Event)
+{
+  if (!Event)
+     return;
+  const cFont *font = cFont::GetFont(fontOsd);
+  int xl = xi00;
+  int y = yi00;
+  cTextScroller ts;
+  char t[32];
+  snprintf(t, sizeof(t), "%s  %s - %s", *Event->GetDateString(), *Event->GetTimeString(), *Event->GetEndTimeString());
+  ts.Set(osd, xl, y, xi01 - xl, yi01 - y, t, font, Theme.Color(clrEventTime), Theme.Color(clrBackground));
+  if (Event->Vps() && Event->Vps() != Event->StartTime()) {
+     cString buffer = cString::sprintf(" VPS: %s ", *Event->GetVpsString());
+     const cFont *font = cFont::GetFont(fontSml);
+     int w = font->Width(buffer);
+     osd->DrawText(xi01 - w, y, buffer, Theme.Color(clrMenuFrameFg), frameColor, font, w);
+     int yb = y + font->Height();
+     osd->DrawRectangle(xi02, y, xi02 + lineHeight / 2 - 1, yb - 1, frameColor);
+     osd->DrawEllipse  (xi02 + lineHeight / 2, y, xi03 - 1, yb - 1, frameColor, 5);
+     }
+  y += ts.Height();
+  if (Event->ParentalRating()) {
+     cString buffer = cString::sprintf(" %s ", *Event->GetParentalRatingString());
+     const cFont *font = cFont::GetFont(fontSml);
+     int w = font->Width(buffer);
+     osd->DrawText(xi01 - w, y, buffer, Theme.Color(clrMenuFrameFg), frameColor, font, w);
+     int yb = y + font->Height();
+     osd->DrawRectangle(xi02, y, xi02 + lineHeight / 2 - 1, yb - 1, frameColor);
+     osd->DrawEllipse  (xi02 + lineHeight / 2, y, xi03 - 1, yb - 1, frameColor, 5);
+     }
+  y += font->Height();
+  ts.Set(osd, xl, y, xi01 - xl, yi01 - y, Event->Title(), font, Theme.Color(clrEventTitle), Theme.Color(clrBackground));
+  y += ts.Height();
+  if (!isempty(Event->ShortText())) {
+     const cFont *font = cFont::GetFont(fontSml);
+     ts.Set(osd, xl, y, xi01 - xl, yi01 - y, Event->ShortText(), font, Theme.Color(clrEventShortText), Theme.Color(clrBackground));
+     y += ts.Height();
+     }
+  y += font->Height();
+  if (!isempty(Event->Description())) {
+     int yt = y;
+     int yb = yi01;
+     textScroller.Set(osd, xl, yt, xi01 - xl, yb - yt, Event->Description(), font, Theme.Color(clrEventDescription), Theme.Color(clrBackground));
+     DrawTextScrollbar();
+     }
+}
+
+void cSkinLCARSDisplayMenu::SetRecording(const cRecording *Recording)
+{
+  if (!Recording)
+     return;
+  const cRecordingInfo *Info = Recording->Info();
+  const cFont *font = cFont::GetFont(fontOsd);
+  int xl = xi00;
+  int y = yi00;
+  cTextScroller ts;
+  char t[32];
+  snprintf(t, sizeof(t), "%s  %s", *DateString(Recording->Start()), *TimeString(Recording->Start()));
+  ts.Set(osd, xl, y, xi01 - xl, yi01 - y, t, font, Theme.Color(clrEventTime), Theme.Color(clrBackground));
+  y += ts.Height();
+  if (Info->GetEvent()->ParentalRating()) {
+     cString buffer = cString::sprintf(" %s ", *Info->GetEvent()->GetParentalRatingString());
+     const cFont *font = cFont::GetFont(fontSml);
+     int w = font->Width(buffer);
+     osd->DrawText(xi01 - w, y, buffer, Theme.Color(clrMenuFrameFg), frameColor, font, w);
+     int yb = y + font->Height();
+     osd->DrawRectangle(xi02, y, xi02 + lineHeight / 2 - 1, yb - 1, frameColor);
+     osd->DrawEllipse  (xi02 + lineHeight / 2, y, xi03 - 1, yb - 1, frameColor, 5);
+     }
+  y += font->Height();
+  const char *Title = Info->Title();
+  if (isempty(Title))
+     Title = Recording->Name();
+  ts.Set(osd, xl, y, xi01 - xl, yi01 - y, Title, font, Theme.Color(clrEventTitle), Theme.Color(clrBackground));
+  y += ts.Height();
+  if (!isempty(Info->ShortText())) {
+     const cFont *font = cFont::GetFont(fontSml);
+     ts.Set(osd, xl, y, xi01 - xl, yi01 - y, Info->ShortText(), font, Theme.Color(clrEventShortText), Theme.Color(clrBackground));
+     y += ts.Height();
+     }
+  y += font->Height();
+  if (!isempty(Info->Description())) {
+     int yt = y;
+     int yb = yi01;
+     textScroller.Set(osd, xl, yt, xi01 - xl, yb - yt, Info->Description(), font, Theme.Color(clrEventDescription), Theme.Color(clrBackground));
+     DrawTextScrollbar();
+     }
+}
+
+void cSkinLCARSDisplayMenu::SetText(const char *Text, bool FixedFont)
+{
+  textScroller.Set(osd, xi00, yi00, GetTextAreaWidth(), yi01 - yi00, Text, GetTextAreaFont(FixedFont), Theme.Color(clrMenuText), Theme.Color(clrBackground));
+  DrawTextScrollbar();
+}
+
+int cSkinLCARSDisplayMenu::GetTextAreaWidth(void) const
+{
+  return xi01 - xi00;
+}
+
+const cFont *cSkinLCARSDisplayMenu::GetTextAreaFont(bool FixedFont) const
+{
+  const cFont *font = cFont::GetFont(FixedFont ? fontFix : fontOsd);
+  //XXX -> make a way to let the text define which font to use
+  return font;
+}
+
+void cSkinLCARSDisplayMenu::Flush(void)
+{
+  if (MenuCategory() == mcMain) {
+     cDevice *Device = cDevice::PrimaryDevice();
+     if (!Device->Replaying() || Device->Transferring()) {
+        const cChannel *Channel = Channels.GetByNumber(cDevice::PrimaryDevice()->CurrentChannel());
+        DrawLive(Channel);
+        }
+     else if (cControl *Control = cControl::Control(true))
+        DrawPlay(Control);
+     DrawTimers();
+     DrawDevices();
+     DrawLiveIndicator();
+     DrawSignals();
+     }
+  DrawFrameDisplay();
+  osd->Flush();
+  initial = false;
+}
+
+// --- cSkinLCARSDisplayReplay -----------------------------------------------
+
+class cSkinLCARSDisplayReplay : public cSkinDisplayReplay {
+private:
+  cOsd *osd;
+  int xp00, xp01, xp02, xp03, xp04, xp05, xp06, xp07, xp08, xp09, xp10, xp11, xp12, xp13, xp14, xp15;
+  int yp00, yp01, yp02, yp03, yp04, yp05, yp06, yp07, yp08, yp09;
+  bool modeOnly;
+  int lineHeight;
+  tColor frameColor;
+  cString lastDate;
+  tTrackId lastTrackId;
+  void DrawDate(void);
+  void DrawTrack(void);
+public:
+  cSkinLCARSDisplayReplay(bool ModeOnly);
+  virtual ~cSkinLCARSDisplayReplay();
+  virtual void SetRecording(const cRecording *Recording);
+  virtual void SetTitle(const char *Title);
+  virtual void SetMode(bool Play, bool Forward, int Speed);
+  virtual void SetProgress(int Current, int Total);
+  virtual void SetCurrent(const char *Current);
+  virtual void SetTotal(const char *Total);
+  virtual void SetJump(const char *Jump);
+  virtual void SetMessage(eMessageType Type, const char *Text);
+  virtual void Flush(void);
+  };
+
+cSkinLCARSDisplayReplay::cSkinLCARSDisplayReplay(bool ModeOnly)
+{
+  const cFont *font = cFont::GetFont(fontOsd);
+  modeOnly = ModeOnly;
+  lineHeight = font->Height();
+  frameColor = Theme.Color(clrReplayFrameBg);
+  int d = 5 * lineHeight;
+  xp00 = 0;
+  xp01 = xp00 + d / 2;
+  xp02 = xp00 + d;
+  xp03 = xp02 + lineHeight;
+  xp04 = xp02 + d / 4;
+  xp05 = xp02 + d;
+  xp06 = xp05 + Gap;
+  xp15 = cOsd::OsdWidth();
+  xp14 = xp15 - lineHeight;
+  xp13 = xp14 - Gap;
+  xp07 = (xp15 + xp00) / 2;
+  xp08 = xp07 + Gap;
+  xp09 = xp08 + lineHeight;
+  xp10 = xp09 + Gap;
+  xp11 = (xp10 + xp13 + Gap) / 2;
+  xp12 = xp11 + Gap;
+
+  yp00 = 0;
+  yp01 = yp00 + 2 * lineHeight;
+  yp02 = yp01 + Gap;
+  yp03 = yp02 + 2 * lineHeight;
+
+  yp04 = yp03 + Gap;
+  yp09 = yp04 + 3 * lineHeight + Gap / 2;
+  yp08 = yp09 - lineHeight;
+  yp07 = yp08 - lineHeight;
+  yp06 = yp08 - d / 4;
+  yp05 = yp09 - d / 2;
+
+  osd = CreateOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - yp09, xp00, yp00, xp15 - 1, yp09 - 1);
+  osd->DrawRectangle(xp00, yp00, xp15 - 1, yp09 - 1, modeOnly ? clrTransparent : Theme.Color(clrBackground));
+  // Rectangles:
+  if (!modeOnly)
+     osd->DrawRectangle(xp00, yp00, xp02 - 1, yp01 - 1, frameColor);
+  osd->DrawRectangle(xp00, yp02, xp02 - 1, yp03 - 1, frameColor);
+  if (!modeOnly) {
+     // Elbow:
+     osd->DrawRectangle(xp00, yp04, xp01 - 1, yp05 - 1, frameColor);
+     osd->DrawRectangle(xp00, yp05, xp01 - 1, yp09 - 1, clrTransparent);
+     osd->DrawEllipse  (xp00, yp05, xp01 - 1, yp09 - 1, frameColor, 3);
+     osd->DrawRectangle(xp01, yp04, xp02 - 1, yp09 - 1, frameColor);
+     osd->DrawEllipse  (xp02, yp06, xp04 - 1, yp08 - 1, frameColor, -3);
+     osd->DrawRectangle(xp02, yp08, xp05 - 1, yp09 - 1, frameColor);
+     // Status area:
+     osd->DrawRectangle(xp06, yp08, xp07 - 1, yp09 - 1, frameColor);
+     osd->DrawRectangle(xp08, yp08, xp09 - 1, yp09 - 1, frameColor);
+     osd->DrawRectangle(xp10, yp08, xp11 - 1, yp09 - 1, frameColor);
+     osd->DrawRectangle(xp12, yp08, xp13 - 1, yp09 - 1, Theme.Color(clrDateBg));
+     osd->DrawRectangle(xp14, yp08, xp14 + lineHeight / 2 - 1, yp09 - 1, frameColor);
+     osd->DrawRectangle(xp14 + lineHeight / 2, yp08 + lineHeight / 2, xp15 - 1, yp09 - 1, clrTransparent);
+     osd->DrawEllipse  (xp14 + lineHeight / 2, yp08, xp15 - 1, yp09 - 1, frameColor, 5);
+     }
+}
+
+cSkinLCARSDisplayReplay::~cSkinLCARSDisplayReplay()
+{
+  delete osd;
+}
+
+void cSkinLCARSDisplayReplay::DrawDate(void)
+{
+  cString s = DayDateTime();
+  if (!*lastDate || strcmp(s, lastDate)) {
+     osd->DrawText(xp12, yp08, s, Theme.Color(clrDateFg), Theme.Color(clrDateBg), cFont::GetFont(fontOsd), xp13 - xp12, lineHeight, taRight | taBorder);
+     lastDate = s;
+     }
+}
+
+void cSkinLCARSDisplayReplay::DrawTrack(void)
+{
+  cDevice *Device = cDevice::PrimaryDevice();
+  const tTrackId *Track = Device->GetTrack(Device->GetCurrentAudioTrack());
+  if (!Track && *lastTrackId.description || Track && strcmp(lastTrackId.description, Track->description)) {
+     osd->DrawText(xp03, yp04, Track ? Track->description : "", Theme.Color(clrTrackName), Theme.Color(clrBackground), cFont::GetFont(fontOsd), xp07 - xp03);
+     strn0cpy(lastTrackId.description, Track ? Track->description : "", sizeof(lastTrackId.description));
+     }
+}
+
+void cSkinLCARSDisplayReplay::SetRecording(const cRecording *Recording)
+{
+  const cRecordingInfo *RecordingInfo = Recording->Info();
+  SetTitle(RecordingInfo->Title());
+  osd->DrawText(xp03, yp01 - lineHeight, RecordingInfo->ShortText(), Theme.Color(clrEventShortText), Theme.Color(clrBackground), cFont::GetFont(fontSml), xp13 - xp03);
+  osd->DrawText(xp00, yp00, ShortDateString(Recording->Start()), Theme.Color(clrReplayFrameFg), frameColor, cFont::GetFont(fontOsd), xp02 - xp00, 0, taTop | taRight | taBorder);
+  osd->DrawText(xp00, yp01 - lineHeight, TimeString(Recording->Start()), Theme.Color(clrReplayFrameFg), frameColor, cFont::GetFont(fontOsd), xp02 - xp00, 0, taBottom | taRight | taBorder);
+}
+
+void cSkinLCARSDisplayReplay::SetTitle(const char *Title)
+{
+  osd->DrawText(xp03, yp00, Title, Theme.Color(clrEventTitle), Theme.Color(clrBackground), cFont::GetFont(fontOsd), xp13 - xp03);
+}
+
+static const char *const *ReplaySymbols[2][2][5] = {
+  { { pause_xpm, srew_xpm, srew1_xpm, srew2_xpm, srew3_xpm },
+    { pause_xpm, sfwd_xpm, sfwd1_xpm, sfwd2_xpm, sfwd3_xpm }, },
+  { { play_xpm,  frew_xpm, frew1_xpm, frew2_xpm, frew3_xpm },
+    { play_xpm,  ffwd_xpm, ffwd1_xpm, ffwd2_xpm, ffwd3_xpm } }
+  };
+
+void cSkinLCARSDisplayReplay::SetMode(bool Play, bool Forward, int Speed)
+{
+  Speed = constrain(Speed, -1, 3);
+  cBitmap bm(ReplaySymbols[Play][Forward][Speed + 1]);
+  osd->DrawBitmap(xp01 - bm.Width() / 2, (yp02 + yp03 - bm.Height()) / 2, bm, Theme.Color(clrReplayFrameFg), frameColor);
+}
+
+void cSkinLCARSDisplayReplay::SetProgress(int Current, int Total)
+{
+  cProgressBar pb(xp13 - xp03, lineHeight, Current, Total, marks, Theme.Color(clrReplayProgressSeen), Theme.Color(clrReplayProgressRest), Theme.Color(clrReplayProgressSelected), Theme.Color(clrReplayProgressMark), Theme.Color(clrReplayProgressCurrent));
+  osd->DrawBitmap(xp03, yp02, pb);
+}
+
+void cSkinLCARSDisplayReplay::SetCurrent(const char *Current)
+{
+  const cFont *font = cFont::GetFont(fontOsd);
+  int w = font->Width(Current) + 10;
+  osd->DrawText(xp03, yp03 - lineHeight, Current, Theme.Color(clrReplayPosition), Theme.Color(clrBackground), font, w, 0, taLeft);
+}
+
+void cSkinLCARSDisplayReplay::SetTotal(const char *Total)
+{
+  const cFont *font = cFont::GetFont(fontOsd);
+  int w = font->Width(Total) + 10;
+  osd->DrawText(xp13 - w, yp03 - lineHeight, Total, Theme.Color(clrReplayPosition), Theme.Color(clrBackground), font, w, 0, taRight);
+}
+
+void cSkinLCARSDisplayReplay::SetJump(const char *Jump)
+{
+  osd->DrawText(xp06, yp08, Jump, Theme.Color(clrReplayJumpFg), Jump ? Theme.Color(clrReplayJumpBg) : frameColor, cFont::GetFont(fontOsd), xp07 - xp06, 0, taCenter);
+}
+
+void cSkinLCARSDisplayReplay::SetMessage(eMessageType Type, const char *Text)
+{
+  if (Text) {
+     osd->SaveRegion(xp06, yp08, xp13 - 1, yp09 - 1);
+     osd->DrawText(xp06, yp08, Text, Theme.Color(clrMessageStatusFg + 2 * Type), Theme.Color(clrMessageStatusBg + 2 * Type), cFont::GetFont(fontSml), xp13 - xp06, 0, taCenter);
+     }
+  else
+     osd->RestoreRegion();
+}
+
+void cSkinLCARSDisplayReplay::Flush(void)
+{
+  if (!modeOnly) {
+     DrawDate();
+     DrawTrack();
+     }
+  osd->Flush();
+}
+
+// --- cSkinLCARSDisplayVolume -----------------------------------------------
+
+class cSkinLCARSDisplayVolume : public cSkinDisplayVolume {
+private:
+  cOsd *osd;
+  int x0, x1, x2, x3, x4, x5, x6, x7;
+  int y0, y1;
+  tColor frameColor;
+  int mute;
+public:
+  cSkinLCARSDisplayVolume(void);
+  virtual ~cSkinLCARSDisplayVolume();
+  virtual void SetVolume(int Current, int Total, bool Mute);
+  virtual void Flush(void);
+  };
+
+cSkinLCARSDisplayVolume::cSkinLCARSDisplayVolume(void)
+{
+  const cFont *font = cFont::GetFont(fontOsd);
+  int lineHeight = font->Height();
+  frameColor = Theme.Color(clrVolumeFrame);
+  mute = -1;
+  x0 = 0;
+  x1 = lineHeight / 2;
+  x2 = lineHeight;
+  x3 = x2 + Gap;
+  x7 = cOsd::OsdWidth();
+  x6 = x7 - lineHeight / 2;
+  x5 = x6 - lineHeight / 2;
+  x4 = x5 - Gap;
+  y0 = 0;
+  y1 = lineHeight;
+  osd = CreateOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - y1, x0, y0, x7 - 1, y1 - 1);
+  osd->DrawRectangle(x0, y0, x7 - 1, y1 - 1, Theme.Color(clrBackground));
+  osd->DrawRectangle(x0, y0, x1 - 1, y1 - 1, clrTransparent);
+  osd->DrawEllipse  (x0, y0, x1 - 1, y1 - 1, frameColor, 7);
+  osd->DrawRectangle(x1, y0, x2 - 1, y1 - 1, frameColor);
+  osd->DrawRectangle(x3, y0, x4 - 1, y1 - 1, frameColor);
+  osd->DrawRectangle(x5, y0, x6 - 1, y1 - 1, frameColor);
+  osd->DrawRectangle(x6, y0, x7 - 1, y1 - 1, clrTransparent);
+  osd->DrawEllipse  (x6, y0, x7 - 1, y1 - 1, frameColor, 5);
+}
+
+cSkinLCARSDisplayVolume::~cSkinLCARSDisplayVolume()
+{
+  delete osd;
+}
+
+void cSkinLCARSDisplayVolume::SetVolume(int Current, int Total, bool Mute)
+{
+  int xl = x3 + TextSpacing;
+  int xr = x4 - TextSpacing;
+  int yt = y0 + TextFrame;
+  int yb = y1 - TextFrame;
+  if (mute != Mute) {
+     osd->DrawRectangle(x3, y0, x4 - 1, y1 - 1, frameColor);
+     mute = Mute;
+     }
+  cBitmap bm(Mute ? mute_xpm : volume_xpm);
+  osd->DrawBitmap(xl, y0 + (y1 - y0 - bm.Height()) / 2, bm, Theme.Color(clrVolumeSymbol), frameColor);
+  if (!Mute) {
+     xl += bm.Width() + TextSpacing;
+     int w = (y1 - y0) / 3;
+     int d = TextFrame;
+     int n = (xr - xl + d) / (w + d);
+     int x = xr - n * (w + d);
+     tColor Color = Theme.Color(clrVolumeBarLower);
+     for (int i = 0; i < n; i++) {
+         if (Total * i >= Current * n)
+            Color = Theme.Color(clrVolumeBarUpper);
+         osd->DrawRectangle(x, yt, x + w - 1, yb - 1, Color);
+         x += w + d;
+         }
+     }
+}
+
+void cSkinLCARSDisplayVolume::Flush(void)
+{
+  osd->Flush();
+}
+
+// --- cSkinLCARSDisplayTracks -----------------------------------------------
+
+class cSkinLCARSDisplayTracks : public cSkinDisplayTracks {
+private:
+  cOsd *osd;
+  int xt00, xt01, xt02, xt03, xt04, xt05, xt06, xt07, xt08, xt09, xt10, xt11, xt12;
+  int yt00, yt01, yt02, yt03, yt04, yt05, yt06, yt07;
+  int lineHeight;
+  tColor frameColor;
+  int currentIndex;
+  static cBitmap bmAudioLeft, bmAudioRight, bmAudioStereo;
+  void SetItem(const char *Text, int Index, bool Current);
+public:
+  cSkinLCARSDisplayTracks(const char *Title, int NumTracks, const char * const *Tracks);
+  virtual ~cSkinLCARSDisplayTracks();
+  virtual void SetTrack(int Index, const char * const *Tracks);
+  virtual void SetAudioChannel(int AudioChannel);
+  virtual void Flush(void);
+  };
+
+cBitmap cSkinLCARSDisplayTracks::bmAudioLeft(audioleft_xpm);
+cBitmap cSkinLCARSDisplayTracks::bmAudioRight(audioright_xpm);
+cBitmap cSkinLCARSDisplayTracks::bmAudioStereo(audiostereo_xpm);
+
+cSkinLCARSDisplayTracks::cSkinLCARSDisplayTracks(const char *Title, int NumTracks, const char * const *Tracks)
+{
+  const cFont *font = cFont::GetFont(fontOsd);
+  lineHeight = font->Height();
+  frameColor = Theme.Color(clrTrackFrameBg);
+  currentIndex = -1;
+  xt00 = 0;
+  xt01 = xt00 + lineHeight / 2;
+  xt02 = xt01 + Gap;
+  xt03 = xt00 + 2 * lineHeight;
+  int ItemsWidth = font->Width(Title) + xt03 - xt02;
+  for (int i = 0; i < NumTracks; i++)
+      ItemsWidth = max(ItemsWidth, font->Width(Tracks[i]) + 2 * TextFrame);
+  xt04 = xt02 + ItemsWidth;
+  xt05 = xt04 + Gap;
+  xt06 = xt04 + lineHeight;
+  xt07 = xt05 + lineHeight;
+  xt08 = xt07 + lineHeight;
+  xt09 = xt08 + Gap;
+  xt10 = xt09 + lineHeight / 2;
+  xt11 = xt10 + Gap;
+  xt12 = xt11 + lineHeight;
+  yt00 = 0;
+  yt01 = yt00 + lineHeight;
+  yt02 = yt01 + lineHeight;
+  yt03 = yt02 + Gap;
+  yt04 = yt03 + NumTracks * lineHeight + (NumTracks - 1) * Gap;
+  yt05 = yt04 + Gap;
+  yt06 = yt05 + lineHeight;
+  yt07 = yt06 + lineHeight;
+  while (yt07 > cOsd::OsdHeight()) {
+        yt04 -= lineHeight + Gap;
+        yt05 = yt04 + Gap;
+        yt06 = yt05 + lineHeight;
+        yt07 = yt06 + lineHeight;
+        }
+  osd = CreateOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - yt07, xt00, yt00, xt12 - 1, yt07 - 1);
+  // The upper elbow:
+  osd->DrawRectangle(xt00, yt00, xt12 - 1, yt07 - 1, Theme.Color(clrBackground));
+  osd->DrawRectangle(xt00, yt00, xt03 - 1, yt02 - 1, clrTransparent);
+  osd->DrawEllipse  (xt00, yt00, xt03 - 1, yt02 - 1, frameColor, 2);
+  osd->DrawRectangle(xt03, yt00, xt04 - 1, yt02 - 1, frameColor);
+  osd->DrawRectangle(xt04, yt00, xt08 - 1, yt01 - 1, frameColor);
+  osd->DrawEllipse  (xt04, yt01, xt06 - 1, yt02 - 1, frameColor, -2);
+  osd->DrawRectangle(xt09, yt00, xt10 - 1, yt01 - 1, frameColor);
+  osd->DrawRectangle(xt11, yt00, xt11 + lineHeight / 2 - 1, yt01 - 1, frameColor);
+  osd->DrawRectangle(xt11 + lineHeight / 2, yt00, xt12 - 1, yt00 + lineHeight / 2 - 1, clrTransparent);
+  osd->DrawEllipse  (xt11 + lineHeight / 2, yt00, xt12 - 1, yt01 - 1, frameColor, 5);
+  osd->DrawText(xt03, yt00, Title, Theme.Color(clrTrackFrameFg), frameColor, font, xt04 - xt03, 0, taTop | taRight);
+  // The items:
+  for (int i = 0; i < NumTracks; i++)
+      SetItem(Tracks[i], i, false);
+  // The lower elbow:
+  osd->DrawRectangle(xt00, yt05, xt03 - 1, yt07 - 1, clrTransparent);
+  osd->DrawEllipse  (xt00, yt05, xt03 - 1, yt07 - 1, frameColor, 3);
+  osd->DrawRectangle(xt03, yt05, xt04 - 1, yt07 - 1, frameColor);
+  osd->DrawRectangle(xt04, yt06, xt08 - 1, yt07 - 1, frameColor);
+  osd->DrawEllipse  (xt04, yt05, xt06 - 1, yt06 - 1, frameColor, -3);
+  osd->DrawRectangle(xt09, yt06, xt10 - 1, yt07 - 1, frameColor);
+  osd->DrawRectangle(xt11, yt06, xt11 + lineHeight / 2 - 1, yt07 - 1, frameColor);
+  osd->DrawRectangle(xt11 + lineHeight / 2, yt06 + lineHeight / 2, xt12 - 1, yt07 - 1, clrTransparent);
+  osd->DrawEllipse  (xt11 + lineHeight / 2, yt06, xt12 - 1, yt07 - 1, frameColor, 5);
+}
+
+cSkinLCARSDisplayTracks::~cSkinLCARSDisplayTracks()
+{
+  delete osd;
+}
+
+void cSkinLCARSDisplayTracks::SetItem(const char *Text, int Index, bool Current)
+{
+  int y0 = yt03 + Index * (lineHeight + Gap);
+  int y1 = y0 + lineHeight;
+  if (y1 > yt04)
+     return;
+  tColor ColorFg, ColorBg;
+  if (Current) {
+     ColorFg = Theme.Color(clrTrackItemCurrentFg);
+     ColorBg = Theme.Color(clrTrackItemCurrentBg);
+     osd->DrawRectangle(xt00, y0, xt01 - 1, y1 - 1, frameColor);
+     osd->DrawRectangle(xt02, y0, xt04 - 1, y1 - 1, ColorBg);
+     osd->DrawRectangle(xt05, y0, xt05 + lineHeight / 2 - 1, y1 - 1, ColorBg);
+     osd->DrawEllipse  (xt05 + lineHeight / 2, y0, xt07 - 1, y1 - 1, ColorBg, 5);
+     currentIndex = Index;
+     }
+  else {
+     ColorFg = Theme.Color(clrTrackItemFg);
+     ColorBg = Theme.Color(clrTrackItemBg);
+     osd->DrawRectangle(xt00, y0, xt01 - 1, y1 - 1, frameColor);
+     osd->DrawRectangle(xt02, y0, xt04 - 1, y1 - 1, ColorBg);
+     if (currentIndex == Index)
+        osd->DrawRectangle(xt05, y0, xt07 - 1, y1 - 1, Theme.Color(clrBackground));
+     }
+  const cFont *font = cFont::GetFont(fontOsd);
+  osd->DrawText(xt02, y0, Text, ColorFg, ColorBg, font, xt04 - xt02, y1 - y0, taTop | taLeft | taBorder);
+}
+
+void cSkinLCARSDisplayTracks::SetTrack(int Index, const char * const *Tracks)
+{
+  if (currentIndex >= 0)
+     SetItem(Tracks[currentIndex], currentIndex, false);
+  SetItem(Tracks[Index], Index, true);
+}
+
+void cSkinLCARSDisplayTracks::SetAudioChannel(int AudioChannel)
+{
+  cBitmap *bm = NULL;
+  switch (AudioChannel) {
+    case 0: bm = &bmAudioStereo; break;
+    case 1: bm = &bmAudioLeft;   break;
+    case 2: bm = &bmAudioRight;  break;
+    default: ;
+    }
+  if (bm)
+     osd->DrawBitmap(xt04 - bm->Width(), (yt06 + yt07 - bm->Height()) / 2, *bm, Theme.Color(clrTrackFrameFg), frameColor);
+  else
+     osd->DrawRectangle(xt03, yt06, xt04 - 1, yt07 - 1, frameColor);
+}
+
+void cSkinLCARSDisplayTracks::Flush(void)
+{
+  osd->Flush();
+}
+
+// --- cSkinLCARSDisplayMessage ----------------------------------------------
+
+class cSkinLCARSDisplayMessage : public cSkinDisplayMessage {
+private:
+  cOsd *osd;
+  int x0, x1, x2, x3, x4, x5, x6, x7;
+  int y0, y1;
+public:
+  cSkinLCARSDisplayMessage(void);
+  virtual ~cSkinLCARSDisplayMessage();
+  virtual void SetMessage(eMessageType Type, const char *Text);
+  virtual void Flush(void);
+  };
+
+cSkinLCARSDisplayMessage::cSkinLCARSDisplayMessage(void)
+{
+  const cFont *font = cFont::GetFont(fontOsd);
+  int lineHeight = font->Height();
+  x0 = 0;
+  x1 = lineHeight / 2;
+  x2 = lineHeight;
+  x3 = x2 + Gap;
+  x7 = cOsd::OsdWidth();
+  x6 = x7 - lineHeight / 2;
+  x5 = x6 - lineHeight / 2;
+  x4 = x5 - Gap;
+  y0 = 0;
+  y1 = lineHeight;
+  osd = CreateOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - y1, x0, y0, x7 - 1, y1 - 1);
+}
+
+cSkinLCARSDisplayMessage::~cSkinLCARSDisplayMessage()
+{
+  delete osd;
+}
+
+void cSkinLCARSDisplayMessage::SetMessage(eMessageType Type, const char *Text)
+{
+  tColor ColorFg = Theme.Color(clrMessageStatusFg + 2 * Type);
+  tColor ColorBg = Theme.Color(clrMessageStatusBg + 2 * Type);
+  osd->DrawRectangle(x0, y0, x7 - 1, y1 - 1, Theme.Color(clrBackground));
+  osd->DrawRectangle(x0, y0, x1 - 1, y1 - 1, clrTransparent);
+  osd->DrawEllipse  (x0, y0, x1 - 1, y1 - 1, ColorBg, 7);
+  osd->DrawRectangle(x1, y0, x2 - 1, y1 - 1, ColorBg);
+  osd->DrawText(x3, y0, Text, ColorFg, ColorBg, cFont::GetFont(fontOsd), x4 - x3, 0, taCenter);
+  osd->DrawRectangle(x5, y0, x6 - 1, y1 - 1, ColorBg);
+  osd->DrawRectangle(x6, y0, x7 - 1, y1 - 1, clrTransparent);
+  osd->DrawEllipse  (x6, y0, x7 - 1, y1 - 1, ColorBg, 5);
+}
+
+void cSkinLCARSDisplayMessage::Flush(void)
+{
+  osd->Flush();
+}
+
+// --- cSkinLCARS ------------------------------------------------------------
+
+cSkinLCARS::cSkinLCARS(void)
+:cSkin("lcars", &::Theme)
+{
+}
+
+const char *cSkinLCARS::Description(void)
+{
+  return "LCARS";
+}
+
+cSkinDisplayChannel *cSkinLCARS::DisplayChannel(bool WithInfo)
+{
+  return new cSkinLCARSDisplayChannel(WithInfo);
+}
+
+cSkinDisplayMenu *cSkinLCARS::DisplayMenu(void)
+{
+  return new cSkinLCARSDisplayMenu;
+}
+
+cSkinDisplayReplay *cSkinLCARS::DisplayReplay(bool ModeOnly)
+{
+  return new cSkinLCARSDisplayReplay(ModeOnly);
+}
+
+cSkinDisplayVolume *cSkinLCARS::DisplayVolume(void)
+{
+  return new cSkinLCARSDisplayVolume;
+}
+
+cSkinDisplayTracks *cSkinLCARS::DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks)
+{
+  return new cSkinLCARSDisplayTracks(Title, NumTracks, Tracks);
+}
+
+cSkinDisplayMessage *cSkinLCARS::DisplayMessage(void)
+{
+  return new cSkinLCARSDisplayMessage;
+}
diff -ruN vdr-1.7.27/skinlcars.h vdr-1.7.28/skinlcars.h
--- vdr-1.7.27/skinlcars.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.28/skinlcars.h	2012-04-15 15:17:35.000000000 +0200
@@ -0,0 +1,27 @@
+/*
+ * skinlcars.h: A VDR skin with Star Trek's "LCARS" layout
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ * $Id: skinlcars.h 1.1 2012/04/15 13:17:35 kls Exp $
+ */
+
+#ifndef __SKINLCARS_H
+#define __SKINLCARS_H
+
+#include "skins.h"
+
+class cSkinLCARS : public cSkin {
+public:
+  cSkinLCARS(void);
+  virtual const char *Description(void);
+  virtual cSkinDisplayChannel *DisplayChannel(bool WithInfo);
+  virtual cSkinDisplayMenu *DisplayMenu(void);
+  virtual cSkinDisplayReplay *DisplayReplay(bool ModeOnly);
+  virtual cSkinDisplayVolume *DisplayVolume(void);
+  virtual cSkinDisplayTracks *DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks);
+  virtual cSkinDisplayMessage *DisplayMessage(void);
+  };
+
+#endif //__SKINLCARS_H
diff -ruN vdr-1.7.27/skins.c vdr-1.7.28/skins.c
--- vdr-1.7.27/skins.c	2012-03-11 15:36:11.000000000 +0100
+++ vdr-1.7.28/skins.c	2012-06-02 13:44:14.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: skins.c 2.5 2012/03/11 14:36:11 kls Exp $
+ * $Id: skins.c 2.10 2012/06/02 11:44:14 kls Exp $
  */
 
 #include "skins.h"
@@ -67,9 +67,15 @@
 
 cSkinDisplayMenu::cSkinDisplayMenu(void)
 {
+  menuCategory = mcUndefined;
   SetTabs(0);
 }
 
+void cSkinDisplayMenu::SetMenuCategory(eMenuCategory MenuCategory)
+{
+  menuCategory = MenuCategory;
+}
+
 void cSkinDisplayMenu::SetTabs(int Tab1, int Tab2, int Tab3, int Tab4, int Tab5)
 {
   tabs[0] = 0;
@@ -166,6 +172,11 @@
   marks = NULL;
 }
 
+void cSkinDisplayReplay::SetRecording(const cRecording *Recording)
+{
+  SetTitle(Recording->Title());
+}
+
 void cSkinDisplayReplay::SetMarks(const cMarks *Marks)
 {
   marks = Marks;
diff -ruN vdr-1.7.27/skins.h vdr-1.7.28/skins.h
--- vdr-1.7.27/skins.h	2012-03-11 15:38:23.000000000 +0100
+++ vdr-1.7.28/skins.h	2012-05-12 13:10:30.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: skins.h 2.2 2012/03/11 14:38:23 kls Exp $
+ * $Id: skins.h 2.5 2012/05/12 11:10:30 kls Exp $
  */
 
 #ifndef __SKINS_H
@@ -72,6 +72,8 @@
   */
   };
 
+enum eMenuCategory { mcUndefined = -1, mcUnknown = 0, mcMain, mcSchedule, mcChannel, mcTimer, mcRecording, mcPlugin, mcSetup, mcCommand, mcEvent, mcText, mcFolder, mcCam };
+
 class cSkinDisplayMenu : public cSkinDisplay {
        ///< This class implements the general purpose menu display, which is
        ///< used throughout the program to display information and let the
@@ -92,6 +94,7 @@
 public:
   enum { MaxTabs = 6 };
 private:
+  eMenuCategory menuCategory;
   int tabs[MaxTabs];
 protected:
   cTextScroller textScroller;
@@ -104,6 +107,16 @@
        ///< part can be found, NULL will be returned.
 public:
   cSkinDisplayMenu(void);
+  eMenuCategory MenuCategory(void) const { return menuCategory; }
+       ///< Returns the menu category, set by a previous call to SetMenuCategory().
+  virtual void SetMenuCategory(eMenuCategory MenuCategory);
+       ///< Sets the current menu category. This allows skins to handle known
+       ///< types of menus in different ways, for instance by displaying icons
+       ///< or special decorations.
+       ///< A derived class can reimplement this function to be informed of any
+       ///< changes in the menu category. If it does, it shall call the base class
+       ///< function in order to set the members accordingly for later calls to the
+       ///< MenuCategory() function.
   virtual void SetTabs(int Tab1, int Tab2 = 0, int Tab3 = 0, int Tab4 = 0, int Tab5 = 0);
        ///< Sets the tab columns to the given values, which are the number of
        ///< characters in each column.
@@ -200,6 +213,11 @@
   virtual void SetMarks(const cMarks *Marks);
        ///< Sets the editing marks to Marks, which shall be used to display the
        ///< progress bar through a cProgressBar object.
+  virtual void SetRecording(const cRecording *Recording);
+       ///< Sets the recording that is currently being played.
+       ///< The default implementation calls SetTitle() with the title and short
+       ///< text of the Recording. A derived class can use any information provided
+       ///< by the given Recording and display it.
   virtual void SetTitle(const char *Title) = 0;
        ///< Sets the title of the recording.
   virtual void SetMode(bool Play, bool Forward, int Speed) = 0;
diff -ruN vdr-1.7.27/skinsttng.c vdr-1.7.28/skinsttng.c
--- vdr-1.7.27/skinsttng.c	2012-03-11 15:06:05.000000000 +0100
+++ vdr-1.7.28/skinsttng.c	2012-04-23 10:39:11.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 2.14 2012/03/11 14:06:05 kls Exp $
+ * $Id: skinsttng.c 2.15 2012/04/23 08:39:11 kls Exp $
  */
 
 // "Star Trek: The Next Generation"(R) is a registered trademark of Paramount Pictures
@@ -16,6 +16,7 @@
 #include "osd.h"
 #include "menu.h"
 #include "themes.h"
+#include "videodir.h"
 
 #include "symbols/arrowdown.xpm"
 #include "symbols/arrowup.xpm"
@@ -401,8 +402,11 @@
   int lineHeight;
   tColor frameColor;
   int currentIndex;
+  cString title;
   bool message;
   cString lastDate;
+  int lastDiskUsageState;
+  void DrawTitle(void);
   void DrawScrollbar(int Total, int Offset, int Shown, int Top, int Height, bool CanScrollUp, bool CanScrollDown);
   void SetTextScrollbar(void);
 public:
@@ -429,6 +433,7 @@
   const cFont *font = cFont::GetFont(fontOsd);
   lineHeight = font->Height();
   frameColor = Theme.Color(clrMenuFrame);
+  lastDiskUsageState = -1;
   currentIndex = -1;
   message = false;
   x0 = 0;
@@ -548,15 +553,22 @@
   osd->DrawRectangle(x1, y3, x7 - 1, y4 - 1, Theme.Color(clrBackground));
 }
 
-void cSkinSTTNGDisplayMenu::SetTitle(const char *Title)
+void cSkinSTTNGDisplayMenu::DrawTitle(void)
 {
   const cFont *font = cFont::GetFont(fontOsd);
   const char *VDR = " VDR";
+  bool WithDisk = MenuCategory() == mcMain || MenuCategory() == mcRecording;
   int w = font->Width(VDR);
-  osd->DrawText(x3 + TextSpacing, y0, Title, Theme.Color(clrMenuTitle), frameColor, font, x4 - w - x3 - TextSpacing);
+  osd->DrawText(x3 + TextSpacing, y0, WithDisk ? cString::sprintf("%s  -  %s", *title, *cVideoDiskUsage::String()) : title, Theme.Color(clrMenuTitle), frameColor, font, x4 - w - x3 - TextSpacing);
   osd->DrawText(x4 - w, y0, VDR, frameColor, clrBlack, font, w, lineHeight);
 }
 
+void cSkinSTTNGDisplayMenu::SetTitle(const char *Title)
+{
+  title = Title;
+  DrawTitle();
+}
+
 void cSkinSTTNGDisplayMenu::SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue)
 {
   cString date = DayDateTime();
@@ -749,6 +761,8 @@
 
 void cSkinSTTNGDisplayMenu::Flush(void)
 {
+  if (cVideoDiskUsage::HasChanged(lastDiskUsageState))
+     DrawTitle();
   if (!message) {
      cString date = DayDateTime();
      if (!*lastDate || strcmp(date, lastDate)) {
diff -ruN vdr-1.7.27/svdrp.c vdr-1.7.28/svdrp.c
--- vdr-1.7.27/svdrp.c	2012-03-04 13:05:56.000000000 +0100
+++ vdr-1.7.28/svdrp.c	2012-05-12 13:55:18.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 2.16 2012/03/04 12:05:56 kls Exp $
+ * $Id: svdrp.c 2.19 2012/05/12 11:55:18 kls Exp $
  */
 
 #include "svdrp.h"
@@ -432,7 +432,7 @@
      if (Code != 0) {
         va_list ap;
         va_start(ap, fmt);
-        cString buffer = cString::sprintf(fmt, ap);
+        cString buffer = cString::vsprintf(fmt, ap);
         va_end(ap);
         const char *s = buffer;
         while (s && *s) {
@@ -662,14 +662,14 @@
 {
   if (*Option) {
      if (isnumber(Option)) {
-        cRecording *recording = Recordings.Get(strtol(Option, NULL, 10) - 1);
+        cRecording *recording = recordings.Get(strtol(Option, NULL, 10) - 1);
         if (recording) {
            cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
            if (!rc) {
               if (!cCutter::Active(recording->FileName())) {
                  if (recording->Delete()) {
                     Reply(250, "Recording \"%s\" deleted", Option);
-                    ::Recordings.DelByName(recording->FileName());
+                    Recordings.DelByName(recording->FileName());
                     }
                  else
                     Reply(554, "Error while deleting recording!");
@@ -681,7 +681,7 @@
               Reply(550, "Recording \"%s\" is in use by timer %d", Option, rc->Timer()->Index() + 1);
            }
         else
-           Reply(550, "Recording \"%s\" not found%s", Option, Recordings.Count() ? "" : " (use LSTR before deleting)");
+           Reply(550, "Recording \"%s\" not found%s", Option, recordings.Count() ? "" : " (use LSTR before deleting)");
         }
      else
         Reply(501, "Error in recording number \"%s\"", Option);
@@ -723,7 +723,7 @@
 {
   if (*Option) {
      if (isnumber(Option)) {
-        cRecording *recording = Recordings.Get(strtol(Option, NULL, 10) - 1);
+        cRecording *recording = recordings.Get(strtol(Option, NULL, 10) - 1);
         if (recording) {
            cMarks Marks;
            if (Marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording()) && Marks.Count()) {
@@ -740,7 +740,7 @@
               Reply(554, "No editing marks defined");
            }
         else
-           Reply(550, "Recording \"%s\" not found%s", Option, Recordings.Count() ? "" : " (use LSTR before editing)");
+           Reply(550, "Recording \"%s\" not found%s", Option, recordings.Count() ? "" : " (use LSTR before editing)");
         }
      else
         Reply(501, "Error in recording number \"%s\"", Option);
@@ -1076,10 +1076,10 @@
 
 void cSVDRP::CmdLSTR(const char *Option)
 {
-  bool recordings = Recordings.Update(true);
+  recordings.Update(true);
   if (*Option) {
      if (isnumber(Option)) {
-        cRecording *recording = Recordings.Get(strtol(Option, NULL, 10) - 1);
+        cRecording *recording = recordings.Get(strtol(Option, NULL, 10) - 1);
         if (recording) {
            FILE *f = fdopen(file, "w");
            if (f) {
@@ -1097,11 +1097,11 @@
      else
         Reply(501, "Error in recording number \"%s\"", Option);
      }
-  else if (recordings) {
-     cRecording *recording = Recordings.First();
+  else if (recordings.Count()) {
+     cRecording *recording = recordings.First();
      while (recording) {
-           Reply(recording == Recordings.Last() ? 250 : -250, "%d %s", recording->Index() + 1, recording->Title(' ', true));
-           recording = Recordings.Next(recording);
+           Reply(recording == recordings.Last() ? 250 : -250, "%d %s", recording->Index() + 1, recording->Title(' ', true));
+           recording = recordings.Next(recording);
            }
      }
   else
@@ -1367,11 +1367,11 @@
      char c = *option;
      *option = 0;
      if (isnumber(num)) {
-        cRecording *recording = Recordings.Get(strtol(num, NULL, 10) - 1);
+        cRecording *recording = recordings.Get(strtol(num, NULL, 10) - 1);
         if (recording) {
            if (c)
               option = skipspace(++option);
-           cReplayControl::SetRecording(NULL, NULL);
+           cReplayControl::SetRecording(NULL);
            cControl::Shutdown();
            if (*option) {
               int pos = 0;
@@ -1383,13 +1383,13 @@
               else
                  resume.Save(pos);
               }
-           cReplayControl::SetRecording(recording->FileName(), recording->Title());
+           cReplayControl::SetRecording(recording->FileName());
            cControl::Launch(new cReplayControl);
            cControl::Attach();
            Reply(250, "Playing recording \"%s\" [%s]", num, recording->Title());
            }
         else
-           Reply(550, "Recording \"%s\" not found%s", num, Recordings.Count() ? "" : " (use LSTR before playing)");
+           Reply(550, "Recording \"%s\" not found%s", num, recordings.Count() ? "" : " (use LSTR before playing)");
         }
      else
         Reply(501, "Error in recording number \"%s\"", num);
diff -ruN vdr-1.7.27/svdrp.h vdr-1.7.28/svdrp.h
--- vdr-1.7.27/svdrp.h	2012-02-16 13:37:53.000000000 +0100
+++ vdr-1.7.28/svdrp.h	2012-04-26 12:30:06.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 2.2 2012/02/16 12:37:53 kls Exp $
+ * $Id: svdrp.h 2.3 2012/04/26 10:30:06 kls Exp $
  */
 
 #ifndef __SVDRP_H
@@ -43,7 +43,7 @@
 private:
   cSocket socket;
   cFile file;
-  cRecordings Recordings;
+  cRecordings recordings;
   cPUTEhandler *PUTEhandler;
   int numChars;
   int length;
diff -ruN vdr-1.7.27/thread.c vdr-1.7.28/thread.c
--- vdr-1.7.27/thread.c	2009-04-13 15:50:39.000000000 +0200
+++ vdr-1.7.28/thread.c	2012-05-08 13:15:57.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 2.3 2009/04/13 13:50:39 kls Exp $
+ * $Id: thread.c 2.4 2012/05/08 11:15:57 kls Exp $
  */
 
 #include "thread.h"
@@ -239,7 +239,7 @@
   if (Description) {
      va_list ap;
      va_start(ap, Description);
-     description = strdup(cString::sprintf(Description, ap));
+     description = strdup(cString::vsprintf(Description, ap));
      va_end(ap);
      }
 }
diff -ruN vdr-1.7.27/timers.c vdr-1.7.28/timers.c
--- vdr-1.7.27/timers.c	2012-02-27 10:38:41.000000000 +0100
+++ vdr-1.7.28/timers.c	2012-04-25 11:02:03.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 2.8 2012/02/27 09:38:41 kls Exp $
+ * $Id: timers.c 2.9 2012/04/25 09:02:03 kls Exp $
  */
 
 #include "timers.h"
@@ -142,7 +142,7 @@
 
 int cTimer::Compare(const cListObject &ListObject) const
 {
-  cTimer *ti = (cTimer *)&ListObject;
+  const cTimer *ti = (const cTimer *)&ListObject;
   time_t t1 = StartTime();
   time_t t2 = ti->StartTime();
   int r = t1 - t2;
@@ -820,3 +820,18 @@
         }
   lastDeleteExpired = time(NULL);
 }
+
+// --- cSortedTimers ---------------------------------------------------------
+
+static int CompareTimers(const void *a, const void *b)
+{
+  return (*(const cTimer **)a)->Compare(**(const cTimer **)b);
+}
+
+cSortedTimers::cSortedTimers(void)
+:cVector(Timers.Count())
+{
+  for (const cTimer *Timer = Timers.First(); Timer; Timer = Timers.Next(Timer))
+      Append(Timer);
+  Sort(CompareTimers);
+}
diff -ruN vdr-1.7.27/timers.h vdr-1.7.28/timers.h
--- vdr-1.7.27/timers.h	2012-02-20 16:52:57.000000000 +0100
+++ vdr-1.7.28/timers.h	2012-04-15 15:21:31.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 2.3 2012/02/20 15:52:57 kls Exp $
+ * $Id: timers.h 2.4 2012/04/15 13:21:31 kls Exp $
  */
 
 #ifndef __TIMERS_H
@@ -135,4 +135,9 @@
 
 extern cTimers Timers;
 
+class cSortedTimers : public cVector<const cTimer *> {
+public:
+  cSortedTimers(void);
+  };
+
 #endif //__TIMERS_H
diff -ruN vdr-1.7.27/tools.c vdr-1.7.28/tools.c
--- vdr-1.7.27/tools.c	2012-02-18 16:30:35.000000000 +0100
+++ vdr-1.7.28/tools.c	2012-05-12 15:29: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.c 2.22 2012/02/18 15:30:35 kls Exp $
+ * $Id: tools.c 2.24 2012/05/12 13:29:20 kls Exp $
  */
 
 #include "tools.h"
@@ -958,7 +958,7 @@
   return cString(buffer, true);
 }
 
-cString cString::sprintf(const char *fmt, va_list &ap)
+cString cString::vsprintf(const char *fmt, va_list &ap)
 {
   char *buffer;
   if (!fmt || vasprintf(&buffer, fmt, ap) < 0) {
@@ -1042,6 +1042,15 @@
   return buf;
 }
 
+cString ShortDateString(time_t t)
+{
+  char buf[32];
+  struct tm tm_r;
+  tm *tm = localtime_r(&t, &tm_r);
+  strftime(buf, sizeof(buf), "%d.%m.%y", tm);
+  return buf;
+}
+
 cString TimeString(time_t t)
 {
   char buf[25];
diff -ruN vdr-1.7.27/tools.h vdr-1.7.28/tools.h
--- vdr-1.7.27/tools.h	2012-02-29 11:41:00.000000000 +0100
+++ vdr-1.7.28/tools.h	2012-05-20 15:58:06.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 2.16 2012/02/29 10:41:00 kls Exp $
+ * $Id: tools.h 2.21 2012/05/20 13:58:06 kls Exp $
  */
 
 #ifndef __TOOLS_H
@@ -177,7 +177,7 @@
   cString &operator=(const char *String);
   cString &Truncate(int Index); ///< Truncate the string at the given Index (if Index is < 0 it is counted from the end of the string).
   static cString sprintf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
-  static cString sprintf(const char *fmt, va_list &ap);
+  static cString vsprintf(const char *fmt, va_list &ap);
   };
 
 ssize_t safe_read(int filedes, void *buffer, size_t size);
@@ -228,13 +228,26 @@
 time_t LastModifiedTime(const char *FileName);
 off_t FileSize(const char *FileName); ///< returns the size of the given file, or -1 in case of an error (e.g. if the file doesn't exist)
 cString WeekDayName(int WeekDay);
+    ///< Converts the given WeekDay (0=Sunday, 1=Monday, ...) to a three letter
+    ///< day name.
 cString WeekDayName(time_t t);
+    ///< Converts the week day of the given time to a three letter day name.
 cString WeekDayNameFull(int WeekDay);
+    ///< Converts the given WeekDay (0=Sunday, 1=Monday, ...) to a full
+    ///< day name.
 cString WeekDayNameFull(time_t t);
+    ///< Converts the week day of the given time to a full day name.
 cString DayDateTime(time_t t = 0);
+    ///< Converts the given time to a string of the form "www dd.mm. hh:mm".
+    ///< If no time is given, the current time is taken.
 cString TimeToString(time_t t);
+    ///< Converts the given time to a string of the form "www mmm dd hh:mm:ss yyyy".
 cString DateString(time_t t);
+    ///< Converts the given time to a string of the form "www dd.mm.yyyy".
+cString ShortDateString(time_t t);
+    ///< Converts the given time to a string of the form "dd.mm.yy".
 cString TimeString(time_t t);
+    ///< Converts the given time to a string of the form "hh:mm".
 uchar *RgbToJpeg(uchar *Mem, int Width, int Height, int &Size, int Quality = 100);
     ///< Converts the given Memory to a JPEG image and returns a pointer
     ///< to the resulting image. Mem must point to a data block of exactly
@@ -457,6 +470,7 @@
   };
 
 template<class T> class cVector {
+  ///< cVector may only be used for *simple* types, like int or pointers - not for class objects that allocate additional memory!
 private:
   mutable int allocated;
   mutable int size;
@@ -515,7 +529,7 @@
   virtual void Append(T Data)
   {
     if (size >= allocated)
-       Realloc(allocated * 4 / 2); // increase size by 50%
+       Realloc(allocated * 3 / 2); // increase size by 50%
     data[size++] = Data;
   }
   virtual void Remove(int Index)
@@ -526,6 +540,8 @@
   }
   virtual void Clear(void)
   {
+    for (int i = 0; i < size; i++)
+        data[i] = T(0);
     size = 0;
   }
   void Sort(__compar_fn_t Compare)
diff -ruN vdr-1.7.27/vdr.c vdr-1.7.28/vdr.c
--- vdr-1.7.27/vdr.c	2012-03-14 10:09:19.000000000 +0100
+++ vdr-1.7.28/vdr.c	2012-04-26 11:23:41.000000000 +0200
@@ -22,7 +22,7 @@
  *
  * The project's page is at http://www.tvdr.de
  *
- * $Id: vdr.c 2.35 2012/03/14 09:09:19 kls Exp $
+ * $Id: vdr.c 2.36 2012/04/26 09:23:41 kls Exp $
  */
 
 #include <getopt.h>
@@ -56,6 +56,7 @@
 #include "recording.h"
 #include "shutdown.h"
 #include "skinclassic.h"
+#include "skinlcars.h"
 #include "skinsttng.h"
 #include "sourceparams.h"
 #include "sources.h"
@@ -677,6 +678,7 @@
 
   // Default skins:
 
+  new cSkinLCARS;
   new cSkinSTTNG;
   new cSkinClassic;
   Skins.SetCurrent(Setup.OSDSkin);
diff -ruN vdr-1.7.27/videodir.c vdr-1.7.28/videodir.c
--- vdr-1.7.27/videodir.c	2008-02-16 14:00:03.000000000 +0100
+++ vdr-1.7.28/videodir.c	2012-04-22 17:03:10.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: videodir.c 2.0 2008/02/16 13:00:03 kls Exp $
+ * $Id: videodir.c 2.1 2012/04/22 15:03:10 kls Exp $
  */
 
 #include "videodir.h"
@@ -241,3 +241,43 @@
      } while (Dir.Next());
   return false;
 }
+
+// --- cVideoDiskUsage -------------------------------------------------------
+
+#define DISKSPACECHEK     5 // seconds between disk space checks
+#define MB_PER_MINUTE 25.75 // this is just an estimate!
+
+int cVideoDiskUsage::state = 0;
+time_t cVideoDiskUsage::lastChecked = 0;
+int cVideoDiskUsage::usedPercent = 0;
+int cVideoDiskUsage::freeMB = 0;
+int cVideoDiskUsage::freeMinutes = 0;
+
+bool cVideoDiskUsage::HasChanged(int &State)
+{
+  if (time(NULL) - lastChecked > DISKSPACECHEK) {
+     int FreeMB;
+     int UsedPercent = VideoDiskSpace(&FreeMB);
+     if (FreeMB != freeMB) {
+        usedPercent = UsedPercent;
+        freeMB = FreeMB;
+        int MBperMinute = Recordings.MBperMinute();
+        if (MBperMinute <= 0)
+           MBperMinute = MB_PER_MINUTE;
+        freeMinutes = int(double(FreeMB) / MBperMinute);
+        state++;
+        }
+     lastChecked = time(NULL);
+     }
+  if (State != state) {
+     State = state;
+     return true;
+     }
+  return false;
+}
+
+cString cVideoDiskUsage::String(void)
+{
+  HasChanged(state);
+  return cString::sprintf("%s %d%%  -  %2d:%02d %s", tr("Disk"), usedPercent, freeMinutes / 60, freeMinutes % 60, tr("free"));
+}
diff -ruN vdr-1.7.27/videodir.h vdr-1.7.28/videodir.h
--- vdr-1.7.27/videodir.h	2008-02-16 13:53:11.000000000 +0100
+++ vdr-1.7.28/videodir.h	2012-04-22 17:07:56.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: videodir.h 2.0 2008/02/16 12:53:11 kls Exp $
+ * $Id: videodir.h 2.1 2012/04/22 15:07:56 kls Exp $
  */
 
 #ifndef __VIDEODIR_H
@@ -25,4 +25,42 @@
 void RemoveEmptyVideoDirectories(void);
 bool IsOnVideoDirectoryFileSystem(const char *FileName);
 
+class cVideoDiskUsage {
+private:
+  static int state;
+  static time_t lastChecked;
+  static int usedPercent;
+  static int freeMB;
+  static int freeMinutes;
+public:
+  static bool HasChanged(int &State);
+    ///< Returns true if the usage of the video disk space has changed since the last
+    ///< call to this function with the given State variable. The caller should
+    ///< initialize State to -1, and it will be set to the current internal state
+    ///< value of the video disk usage checker upon return. Future calls with the same
+    ///< State variable can then quickly check for changes.
+  static void ForceCheck(void) { lastChecked = 0; }
+    ///< To avoid unnecessary load, the video disk usage is only actually checked
+    ///< every DISKSPACECHEK seconds. Calling ForceCheck() makes sure that the next call
+    ///< to HasChanged() will check the disk usage immediately. This is useful in case
+    ///< some files have been deleted and the result shall be displayed instantly.
+  static cString String(void);
+    ///< Returns a localized string of the form "Disk nn%  -  hh:mm free".
+    ///< This function is mainly for use in skins that want to retain the display of the
+    ///< free disk space in the menu title, as was the case until VDR version 1.7.27.
+    ///< An implicit call to HasChanged() is done in this function, to make sure the
+    ///< returned value is up to date.
+  static int UsedPercent(void) { return usedPercent; }
+    ///< Returns the used space of the video disk in percent.
+    ///< The caller should call HasChanged() first, to make sure the value is up to date.
+  static int FreeMB(void) { return freeMB; }
+    ///< Returns the amount of free space on the video disk in MB.
+    ///< The caller should call HasChanged() first, to make sure the value is up to date.
+  static int FreeMinutes(void) { return freeMinutes; }
+    ///< Returns the number of minutes that can still be recorded on the video disk.
+    ///< This is an estimate and depends on the data rate of the existing recordings.
+    ///< There is no guarantee that this value will actually be met.
+    ///< The caller should call HasChanged() first, to make sure the value is up to date.
+  };
+
 #endif //__VIDEODIR_H
