support for 'long keypresses' ('l' in keymap.xml flags)
[enigma2.git] / lib / python / Screens / InfoBarGenerics.py
index 2f7b36c3e3855163c3b70374240c7757cb6b68a3..e12d2f1896b7d2b570a824ba3bccdba2b780bafc 100644 (file)
@@ -3,8 +3,6 @@ from ChannelSelection import ChannelSelection, BouquetSelector
 from Components.ActionMap import ActionMap, HelpableActionMap
 from Components.ActionMap import NumberActionMap
 from Components.BlinkingPixmap import BlinkingPixmapConditional
 from Components.ActionMap import ActionMap, HelpableActionMap
 from Components.ActionMap import NumberActionMap
 from Components.BlinkingPixmap import BlinkingPixmapConditional
-from Components.Clock import Clock
-from Components.EventInfo import EventInfo, EventInfoProgress
 from Components.Harddisk import harddiskmanager
 from Components.Input import Input
 from Components.Label import *
 from Components.Harddisk import harddiskmanager
 from Components.Input import Input
 from Components.Label import *
@@ -12,12 +10,13 @@ from Components.Pixmap import Pixmap, PixmapConditional
 from Components.PluginComponent import plugins
 from Components.ProgressBar import *
 from Components.ServiceEventTracker import ServiceEventTracker
 from Components.PluginComponent import plugins
 from Components.ProgressBar import *
 from Components.ServiceEventTracker import ServiceEventTracker
-from Components.ServiceName import ServiceName
-from Components.config import config, configElement, ConfigSubsection, configSequence, configElementBoolean, configSelection, configElement_nonSave, getConfigListEntry
-from Components.config import configfile, configsequencearg
+from Components.Sources.CurrentService import CurrentService
+from Components.Sources.EventInfo import EventInfo
+from Components.Sources.FrontendStatus import FrontendStatus
+from Components.Sources.Boolean import Boolean
+from Components.Sources.Clock import Clock
 from Components.TimerList import TimerEntryComponent
 from Components.TimerList import TimerEntryComponent
-from Components.TunerInfo import TunerInfo
-
+from Components.config import config, ConfigBoolean, ConfigClock
 from EpgSelection import EPGSelection
 from Plugins.Plugin import PluginDescriptor
 
 from EpgSelection import EPGSelection
 from Plugins.Plugin import PluginDescriptor
 
@@ -31,19 +30,20 @@ from Screens.MinuteInput import MinuteInput
 from Screens.TimerSelection import TimerSelection
 from Screens.PictureInPicture import PictureInPicture
 from Screens.SubtitleDisplay import SubtitleDisplay
 from Screens.TimerSelection import TimerSelection
 from Screens.PictureInPicture import PictureInPicture
 from Screens.SubtitleDisplay import SubtitleDisplay
+from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive
+from Screens.SleepTimerEdit import SleepTimerEdit
+from Screens.TimeDateInput import TimeDateInput
 from ServiceReference import ServiceReference
 
 from Tools import Notifications
 from ServiceReference import ServiceReference
 
 from Tools import Notifications
-from Tools.Directories import *
-
-#from enigma import eTimer, eDVBVolumecontrol, quitMainloop
-from enigma import *
+from Tools.Directories import SCOPE_HDD, resolveFilename
 
 
-import time
-import os
-import bisect
+from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
+       iPlayableService, eServiceReference, eDVBResourceManager, iFrontendInformation, eEPGCache
 
 
-from Components.config import config, currentConfigSelectionElement
+from time import time, localtime, strftime
+from os import stat as os_stat
+from bisect import insort
 
 # hack alert!
 from Menu import MainMenu, mdom
 
 # hack alert!
 from Menu import MainMenu, mdom
@@ -60,33 +60,43 @@ class InfoBarShowHide:
        STATE_HIDING = 1
        STATE_SHOWING = 2
        STATE_SHOWN = 3
        STATE_HIDING = 1
        STATE_SHOWING = 2
        STATE_SHOWN = 3
-       
+
        def __init__(self):
                self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
                        {
                                "toggleShow": self.toggleShow,
                                "hide": self.hide,
        def __init__(self):
                self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
                        {
                                "toggleShow": self.toggleShow,
                                "hide": self.hide,
+                       }, 1) # lower prio to make it possible to override ok and cancel..
+
+               self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
+                       {
+                               iPlayableService.evStart: self.serviceStarted,
                        })
 
                self.__state = self.STATE_SHOWN
                self.__locked = 0
                        })
 
                self.__state = self.STATE_SHOWN
                self.__locked = 0
-               
-               self.onExecBegin.append(self.show)
-               
+
                self.hideTimer = eTimer()
                self.hideTimer.timeout.get().append(self.doTimerHide)
                self.hideTimer.start(5000, True)
                self.hideTimer = eTimer()
                self.hideTimer.timeout.get().append(self.doTimerHide)
                self.hideTimer.start(5000, True)
-               
+
                self.onShow.append(self.__onShow)
                self.onHide.append(self.__onHide)
 
                self.onShow.append(self.__onShow)
                self.onHide.append(self.__onHide)
 
+       def serviceStarted(self):
+               if self.execing:
+                       if config.usage.show_infobar_on_zap.value:
+                               self.doShow()
+
        def __onShow(self):
                self.__state = self.STATE_SHOWN
                self.startHideTimer()
        def __onShow(self):
                self.__state = self.STATE_SHOWN
                self.startHideTimer()
-       
+
        def startHideTimer(self):
                if self.__state == self.STATE_SHOWN and not self.__locked:
        def startHideTimer(self):
                if self.__state == self.STATE_SHOWN and not self.__locked:
-                       self.hideTimer.start(5000, True)
+                       idx = config.usage.infobar_timeout.index
+                       if idx:
+                               self.hideTimer.start(idx*1000, True)
 
        def __onHide(self):
                self.__state = self.STATE_HIDDEN
 
        def __onHide(self):
                self.__state = self.STATE_HIDDEN
@@ -112,7 +122,7 @@ class InfoBarShowHide:
                if self.execing:
                        self.show()
                        self.hideTimer.stop()
                if self.execing:
                        self.show()
                        self.hideTimer.stop()
-       
+
        def unlockShow(self):
                self.__locked = self.__locked - 1
                if self.execing:
        def unlockShow(self):
                self.__locked = self.__locked - 1
                if self.execing:
@@ -121,7 +131,7 @@ class InfoBarShowHide:
 #      def startShow(self):
 #              self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
 #              self.__state = self.STATE_SHOWN
 #      def startShow(self):
 #              self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
 #              self.__state = self.STATE_SHOWN
-#      
+#
 #      def startHide(self):
 #              self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
 #              self.__state = self.STATE_HIDDEN
 #      def startHide(self):
 #              self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
 #              self.__state = self.STATE_HIDDEN
@@ -191,7 +201,6 @@ class InfoBarNumberZap:
 #              print "You pressed number " + str(number)
                if number == 0:
                        self.servicelist.recallPrevService()
 #              print "You pressed number " + str(number)
                if number == 0:
                        self.servicelist.recallPrevService()
-                       self.doShow()
                else:
                        self.session.openWithCallback(self.numberEntered, NumberZap, number)
 
                else:
                        self.session.openWithCallback(self.numberEntered, NumberZap, number)
 
@@ -207,9 +216,9 @@ class InfoBarNumberZap:
                                serviceIterator = servicelist.getNext()
                                if not serviceIterator.valid(): #check end of list
                                        break
                                serviceIterator = servicelist.getNext()
                                if not serviceIterator.valid(): #check end of list
                                        break
-                               if serviceIterator.flags: #assume normal dvb service have no flags set
-                                       continue
-                               num -= 1;
+                               playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
+                               if playable:
+                                       num -= 1;
                        if not num: #found service with searched number ?
                                return serviceIterator, 0
                return None, num
                        if not num: #found service with searched number ?
                                return serviceIterator, 0
                return None, num
@@ -218,18 +227,17 @@ class InfoBarNumberZap:
                bouquet = self.servicelist.bouquet_root
                service = None
                serviceHandler = eServiceCenter.getInstance()
                bouquet = self.servicelist.bouquet_root
                service = None
                serviceHandler = eServiceCenter.getInstance()
-               if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
+               if not config.usage.multibouquet.value:
                        service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
                else:
                        bouquetlist = serviceHandler.list(bouquet)
                        if not bouquetlist is None:
                                while number:
                        service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
                else:
                        bouquetlist = serviceHandler.list(bouquet)
                        if not bouquetlist is None:
                                while number:
-                                       bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
+                                       bouquet = bouquetlist.getNext()
                                        if not bouquet.valid(): #check end of list
                                                break
                                        if not bouquet.valid(): #check end of list
                                                break
-                                       if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
-                                               continue
-                                       service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
+                                       if bouquet.flags & eServiceReference.isDirectory:
+                                               service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
                if not service is None:
                        if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
                                self.servicelist.clearPath()
                if not service is None:
                        if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
                                self.servicelist.clearPath()
@@ -239,7 +247,7 @@ class InfoBarNumberZap:
                        self.servicelist.setCurrentSelection(service) #select the service in servicelist
                        self.servicelist.zap()
 
                        self.servicelist.setCurrentSelection(service) #select the service in servicelist
                        self.servicelist.zap()
 
-config.misc.initialchannelselection = configElementBoolean("config.misc.initialchannelselection", 1);
+config.misc.initialchannelselection = ConfigBoolean(default = True)
 
 class InfoBarChannelSelection:
        """ ChannelSelection - handles the channelSelection dialog and the initial 
 
 class InfoBarChannelSelection:
        """ ChannelSelection - handles the channelSelection dialog and the initial 
@@ -247,23 +255,36 @@ class InfoBarChannelSelection:
        def __init__(self):
                #instantiate forever
                self.servicelist = self.session.instantiateDialog(ChannelSelection)
        def __init__(self):
                #instantiate forever
                self.servicelist = self.session.instantiateDialog(ChannelSelection)
-               
-               if config.misc.initialchannelselection.value == 1:
+
+               if config.misc.initialchannelselection.value:
                        self.onShown.append(self.firstRun)
 
                self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
                        {
                        self.onShown.append(self.firstRun)
 
                self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
                        {
-                               "switchChannelUp": self.switchChannelUp,
-                               "switchChannelDown": self.switchChannelDown,
+                               "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
+                               "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
                                "zapUp": (self.zapUp, _("previous channel")),
                                "zapDown": (self.zapDown, _("next channel")),
                                "historyBack": (self.historyBack, _("previous channel in history")),
                                "zapUp": (self.zapUp, _("previous channel")),
                                "zapDown": (self.zapDown, _("next channel")),
                                "historyBack": (self.historyBack, _("previous channel in history")),
-                               "historyNext": (self.historyNext, _("next channel in history"))
+                               "historyNext": (self.historyNext, _("next channel in history")),
+                               "openServiceList": (self.openServiceList, _("open servicelist")),
                        })
 
                        })
 
+       def showTvChannelList(self, zap=False):
+               self.servicelist.setModeTv()
+               if zap:
+                       self.servicelist.zap()
+               self.session.execDialog(self.servicelist)
+
+       def showRadioChannelList(self, zap=False):
+               self.servicelist.setModeRadio()
+               if zap:
+                       self.servicelist.zap()
+               self.session.execDialog(self.servicelist)
+
        def firstRun(self):
                self.onShown.remove(self.firstRun)
        def firstRun(self):
                self.onShown.remove(self.firstRun)
-               config.misc.initialchannelselection.value = 0
+               config.misc.initialchannelselection.value = False
                config.misc.initialchannelselection.save()
                self.switchChannelDown()
 
                config.misc.initialchannelselection.save()
                self.switchChannelDown()
 
@@ -281,35 +302,65 @@ class InfoBarChannelSelection:
                self.servicelist.moveDown()
                self.session.execDialog(self.servicelist)
 
                self.servicelist.moveDown()
                self.session.execDialog(self.servicelist)
 
+       def openServiceList(self):
+               self.session.execDialog(self.servicelist)
+
        def zapUp(self):
        def zapUp(self):
-               if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
-                       if self.servicelist.inBouquet() and self.servicelist.atBegin():
-                               self.servicelist.prevBouquet()
-               self.servicelist.moveUp()
+               if self.servicelist.inBouquet():
+                       prev = self.servicelist.getCurrentSelection()
+                       if prev:
+                               prev = prev.toString()
+                               while True:
+                                       if config.usage.quickzap_bouquet_change.value:
+                                               if self.servicelist.atBegin():
+                                                       self.servicelist.prevBouquet()
+                                       self.servicelist.moveUp()
+                                       cur = self.servicelist.getCurrentSelection()
+                                       if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
+                                               break
+               else:
+                       self.servicelist.moveUp()
                self.servicelist.zap()
                self.servicelist.zap()
-               self.doShow()
 
        def zapDown(self):
 
        def zapDown(self):
-               if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
-                       self.servicelist.nextBouquet()
+               if self.servicelist.inBouquet():
+                       prev = self.servicelist.getCurrentSelection()
+                       if prev:
+                               prev = prev.toString()
+                               while True:
+                                       if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
+                                               self.servicelist.nextBouquet()
+                                       else:
+                                               self.servicelist.moveDown()
+                                       cur = self.servicelist.getCurrentSelection()
+                                       if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
+                                               break
                else:
                        self.servicelist.moveDown()
                self.servicelist.zap()
                else:
                        self.servicelist.moveDown()
                self.servicelist.zap()
-               self.doShow()
 
 class InfoBarMenu:
        """ Handles a menu action, to open the (main) menu """
        def __init__(self):
                self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions", 
                        {
 
 class InfoBarMenu:
        """ Handles a menu action, to open the (main) menu """
        def __init__(self):
                self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions", 
                        {
-                               "mainMenu": (self.mainMenu, "Enter main menu..."),
+                               "mainMenu": (self.mainMenu, _("Enter main menu...")),
                        })
                        })
+               self.session.infobar = None
 
        def mainMenu(self):
                print "loading mainmenu XML..."
                menu = mdom.childNodes[0]
                assert menu.tagName == "menu", "root element in menu must be 'menu'!"
 
        def mainMenu(self):
                print "loading mainmenu XML..."
                menu = mdom.childNodes[0]
                assert menu.tagName == "menu", "root element in menu must be 'menu'!"
-               self.session.open(MainMenu, menu, menu.childNodes)
+
+               self.session.infobar = self
+               # so we can access the currently active infobar from screens opened from within the mainmenu
+               # at the moment used from the SubserviceSelection
+
+               self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
+
+       def mainMenuClosed(self, *val):
+               self.session.infobar = None
 
 class InfoBarSimpleEventView:
        """ Opens the Eventview for now/next """
 
 class InfoBarSimpleEventView:
        """ Opens the Eventview for now/next """
@@ -375,7 +426,7 @@ class InfoBarEPG:
                                service = servicelist.getNext()
                                if not service.valid(): #check if end of list
                                        break
                                service = servicelist.getNext()
                                if not service.valid(): #check if end of list
                                        break
-                               if service.flags: #ignore non playable services
+                               if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
                                        continue
                                services.append(ServiceReference(service))
                return services
                                        continue
                                services.append(ServiceReference(service))
                return services
@@ -483,49 +534,69 @@ class InfoBarEPG:
 class InfoBarTuner:
        """provides a snr/agc/ber display"""
        def __init__(self):
 class InfoBarTuner:
        """provides a snr/agc/ber display"""
        def __init__(self):
-               self["snr"] = Label()
-               self["agc"] = Label()
-               self["ber"] = Label()
-               self["snr_percent"] = TunerInfo(TunerInfo.SNR_PERCENTAGE, servicefkt = self.session.nav.getCurrentService)
-               self["agc_percent"] = TunerInfo(TunerInfo.AGC_PERCENTAGE, servicefkt = self.session.nav.getCurrentService)
-               self["ber_count"] = TunerInfo(TunerInfo.BER_VALUE, servicefkt = self.session.nav.getCurrentService)
-               self["snr_progress"] = TunerInfo(TunerInfo.SNR_BAR, servicefkt = self.session.nav.getCurrentService)
-               self["agc_progress"] = TunerInfo(TunerInfo.AGC_BAR, servicefkt = self.session.nav.getCurrentService)
-               self["ber_progress"] = TunerInfo(TunerInfo.BER_BAR, servicefkt = self.session.nav.getCurrentService)
-               self.timer = eTimer()
-               self.timer.timeout.get().append(self.updateTunerInfo)
-               self.timer.start(1000)
-
-       def updateTunerInfo(self):
-               if self.instance.isVisible():
-                       self["snr_percent"].update()
-                       self["agc_percent"].update()
-                       self["ber_count"].update()
-                       self["snr_progress"].update()
-                       self["agc_progress"].update()
-                       self["ber_progress"].update()
+               self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
 
 class InfoBarEvent:
        """provides a current/next event info display"""
        def __init__(self):
 
 class InfoBarEvent:
        """provides a current/next event info display"""
        def __init__(self):
-               self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
-               self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
-                               
-               self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
-               self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
+               self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
+               self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
 
 
-               self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
-               self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
+class InfoBarRdsDecoder:
+       """provides RDS and Rass support/display"""
+       def __init__(self):
+               self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
+               self.rass_interactive = None
 
 
-               self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
+               self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
+                       {
+                               iPlayableService.evEnd: self.__serviceStopped,
+                               iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
+                       })
+
+               self["RdsActions"] = ActionMap(["InfobarRdsActions"],
+               {
+                       "startRassInteractive": self.startRassInteractive
+               },-1)
+
+               self["RdsActions"].setEnabled(False)
+
+               self.onLayoutFinish.append(self.rds_display.show)
+               self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
+
+       def RassInteractivePossibilityChanged(self, state):
+               self["RdsActions"].setEnabled(state)
+
+       def RassSlidePicChanged(self):
+               if not self.rass_interactive:
+                       service = self.session.nav.getCurrentService()
+                       decoder = service and service.rdsDecoder()
+                       if decoder:
+                               decoder.showRassSlidePicture()
+
+       def __serviceStopped(self):
+               if self.rass_interactive is not None:
+                       rass_interactive = self.rass_interactive
+                       self.rass_interactive = None
+                       rass_interactive.close()
+
+       def startRassInteractive(self):
+               self.rds_display.hide()
+               self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
+
+       def RassInteractiveClosed(self, *val):
+               if self.rass_interactive is not None:
+                       self.rass_interactive = None
+                       self.RassSlidePicChanged()
+               self.rds_display.show()
 
 class InfoBarServiceName:
        def __init__(self):
 
 class InfoBarServiceName:
        def __init__(self):
-               self["ServiceName"] = ServiceName(self.session.nav)
+               self["CurrentService"] = CurrentService(self.session.nav)
 
 class InfoBarSeek:
        """handles actions like seeking, pause"""
 
 class InfoBarSeek:
        """handles actions like seeking, pause"""
-       
+
        # ispause, isff, issm
        SEEK_STATE_PLAY = (0, 0, 0, ">")
        SEEK_STATE_PAUSE = (1, 0, 0, "||")
        # ispause, isff, issm
        SEEK_STATE_PLAY = (0, 0, 0, ">")
        SEEK_STATE_PAUSE = (1, 0, 0, "||")
@@ -535,22 +606,24 @@ class InfoBarSeek:
        SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
        SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
        SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
        SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
        SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
        SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
-       
+
        SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
        SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
        SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
        SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
        SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
        SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
        SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
        SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
-       
+
        SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
        SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
        SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
        SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
        SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
        SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
-       
-       def __init__(self):
+
+       SEEK_STATE_EOF = (1, 0, 0, "END")
+
+       def __init__(self, actionmap = "InfobarSeekActions"):
                self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
                        {
                                iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
                                iPlayableService.evStart: self.__serviceStarted,
                self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
                        {
                                iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
                                iPlayableService.evStart: self.__serviceStarted,
-                               
+
                                iPlayableService.evEOF: self.__evEOF,
                                iPlayableService.evSOF: self.__evSOF,
                        })
                                iPlayableService.evEOF: self.__evEOF,
                                iPlayableService.evSOF: self.__evSOF,
                        })
@@ -559,32 +632,38 @@ class InfoBarSeek:
                        def __init__(self, screen, *args, **kwargs):
                                HelpableActionMap.__init__(self, screen, *args, **kwargs)
                                self.screen = screen
                        def __init__(self, screen, *args, **kwargs):
                                HelpableActionMap.__init__(self, screen, *args, **kwargs)
                                self.screen = screen
-                               
+
                        def action(self, contexts, action):
                        def action(self, contexts, action):
+                               print "action:", action
                                if action[:5] == "seek:":
                                        time = int(action[5:])
                                        self.screen.seekRelative(time * 90000)
                                if action[:5] == "seek:":
                                        time = int(action[5:])
                                        self.screen.seekRelative(time * 90000)
+                                       if isinstance(self.screen, InfoBarShowHide):
+                                               self.screen.doShow()
                                        return 1
                                else:
                                        return HelpableActionMap.action(self, contexts, action)
 
                                        return 1
                                else:
                                        return HelpableActionMap.action(self, contexts, action)
 
-               self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions"
+               self["SeekActions"] = InfoBarSeekActionMap(self, actionmap
                        {
                        {
-                               "pauseService": (self.pauseService, "pause"),
-                               "unPauseService": (self.unPauseService, "continue"),
-                               
-                               "seekFwd": (self.seekFwd, "skip forward"),
+                               "playpauseService": (self.playpauseService, _("pause")),
+                               "pauseService": (self.pauseService, _("pause")),
+                               "unPauseService": (self.unPauseService, _("continue")),
+
+                               "seekFwd": (self.seekFwd, _("skip forward")),
                                "seekFwdDown": self.seekFwdDown,
                                "seekFwdUp": self.seekFwdUp,
                                "seekFwdDown": self.seekFwdDown,
                                "seekFwdUp": self.seekFwdUp,
-                               "seekBack": (self.seekBack, "skip backward"),
+                               "seekBack": (self.seekBack, _("skip backward")),
                                "seekBackDown": self.seekBackDown,
                                "seekBackUp": self.seekBackUp,
                        }, prio=-1)
                        # give them a little more priority to win over color buttons
 
                                "seekBackDown": self.seekBackDown,
                                "seekBackUp": self.seekBackUp,
                        }, prio=-1)
                        # give them a little more priority to win over color buttons
 
+               self["SeekActions"].setEnabled(False)
+
                self.seekstate = self.SEEK_STATE_PLAY
                self.onClose.append(self.delTimer)
                self.seekstate = self.SEEK_STATE_PLAY
                self.onClose.append(self.delTimer)
-               
+
                self.fwdtimer = False
                self.fwdKeyTimer = eTimer()
                self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
                self.fwdtimer = False
                self.fwdKeyTimer = eTimer()
                self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
@@ -592,21 +671,23 @@ class InfoBarSeek:
                self.rwdtimer = False
                self.rwdKeyTimer = eTimer()
                self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
                self.rwdtimer = False
                self.rwdKeyTimer = eTimer()
                self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
-               
+
                self.onPlayStateChanged = [ ]
                self.onPlayStateChanged = [ ]
-               
+
                self.lockedBecauseOfSkipping = False
                self.lockedBecauseOfSkipping = False
-       
+
+               self.__seekableStatusChanged()
+
        def up(self):
                pass
        def up(self):
                pass
-       
+
        def down(self):
                pass
        def down(self):
                pass
-       
+
        def delTimer(self):
                del self.fwdKeyTimer
                del self.rwdKeyTimer
        def delTimer(self):
                del self.fwdKeyTimer
                del self.rwdKeyTimer
-       
+
        def getSeek(self):
                service = self.session.nav.getCurrentService()
                if service is None:
        def getSeek(self):
                service = self.session.nav.getCurrentService()
                if service is None:
@@ -616,9 +697,9 @@ class InfoBarSeek:
 
                if seek is None or not seek.isCurrentlySeekable():
                        return None
 
                if seek is None or not seek.isCurrentlySeekable():
                        return None
-               
+
                return seek
                return seek
-       
+
        def isSeekable(self):
                if self.getSeek() is None:
                        return False
        def isSeekable(self):
                if self.getSeek() is None:
                        return False
@@ -636,37 +717,44 @@ class InfoBarSeek:
 
        def __serviceStarted(self):
                self.seekstate = self.SEEK_STATE_PLAY
 
        def __serviceStarted(self):
                self.seekstate = self.SEEK_STATE_PLAY
+               self.__seekableStatusChanged()
 
        def setSeekState(self, state):
                service = self.session.nav.getCurrentService()
 
        def setSeekState(self, state):
                service = self.session.nav.getCurrentService()
-               
+
                if service is None:
                        return False
                if service is None:
                        return False
-               
+
                if not self.isSeekable():
                        if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
                                state = self.SEEK_STATE_PLAY
                if not self.isSeekable():
                        if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
                                state = self.SEEK_STATE_PLAY
-               
+
                pauseable = service.pause()
 
                if pauseable is None:
                        print "not pauseable."
                        state = self.SEEK_STATE_PLAY
                pauseable = service.pause()
 
                if pauseable is None:
                        print "not pauseable."
                        state = self.SEEK_STATE_PLAY
-               
+
                oldstate = self.seekstate
                self.seekstate = state
                oldstate = self.seekstate
                self.seekstate = state
-               
+
                for i in range(3):
                        if oldstate[i] != self.seekstate[i]:
                                (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
 
                for c in self.onPlayStateChanged:
                        c(self.seekstate)
                for i in range(3):
                        if oldstate[i] != self.seekstate[i]:
                                (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
 
                for c in self.onPlayStateChanged:
                        c(self.seekstate)
-               
+
                self.checkSkipShowHideLock()
 
                return True
 
                self.checkSkipShowHideLock()
 
                return True
 
+       def playpauseService(self):
+               if self.seekstate != self.SEEK_STATE_PLAY:
+                       self.unPauseService()
+               else:
+                       self.pauseService()
+
        def pauseService(self):
                if self.seekstate == self.SEEK_STATE_PAUSE:
                        print "pause, but in fact unpause"
        def pauseService(self):
                if self.seekstate == self.SEEK_STATE_PAUSE:
                        print "pause, but in fact unpause"
@@ -678,21 +766,23 @@ class InfoBarSeek:
                                print "no", self.seekstate
                        print "pause"
                        self.setSeekState(self.SEEK_STATE_PAUSE);
                                print "no", self.seekstate
                        print "pause"
                        self.setSeekState(self.SEEK_STATE_PAUSE);
-               
+
        def unPauseService(self):
                print "unpause"
        def unPauseService(self):
                print "unpause"
-               self.setSeekState(self.SEEK_STATE_PLAY);
-       
+               if self.seekstate == self.SEEK_STATE_PLAY:
+                       return 0
+               self.setSeekState(self.SEEK_STATE_PLAY)
+
        def doSeek(self, seektime):
                print "doseek", seektime
                service = self.session.nav.getCurrentService()
                if service is None:
                        return
        def doSeek(self, seektime):
                print "doseek", seektime
                service = self.session.nav.getCurrentService()
                if service is None:
                        return
-               
+
                seekable = self.getSeek()
                if seekable is None:
                        return
                seekable = self.getSeek()
                if seekable is None:
                        return
-               
+
                seekable.seekTo(90 * seektime)
 
        def seekFwdDown(self):
                seekable.seekTo(90 * seektime)
 
        def seekFwdDown(self):
@@ -728,17 +818,18 @@ class InfoBarSeek:
                                self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
                                self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
                                self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
                                self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
                                self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
                                self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
-                               self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
+                               self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER,
+                               self.SEEK_STATE_EOF: self.SEEK_STATE_EOF,
                        }
                self.setSeekState(lookup[self.seekstate])
                        }
                self.setSeekState(lookup[self.seekstate])
-       
+
        def seekBackUp(self):
                print "seekBackUp"
                if self.rwdtimer:
                        self.rwdKeyTimer.stop()
                        self.rwdtimer = False
                        self.seekBack()
        def seekBackUp(self):
                print "seekBackUp"
                if self.rwdtimer:
                        self.rwdKeyTimer.stop()
                        self.rwdtimer = False
                        self.seekBack()
-               
+
        def seekBack(self):
                lookup = {
                                self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
        def seekBack(self):
                lookup = {
                                self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
@@ -755,10 +846,11 @@ class InfoBarSeek:
                                self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
                                self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
                                self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
                                self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
                                self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
                                self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
-                               self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
+                               self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE,
+                               self.SEEK_STATE_EOF: self.SEEK_STATE_BACK_16X,
                        }
                self.setSeekState(lookup[self.seekstate])
                        }
                self.setSeekState(lookup[self.seekstate])
-               
+
                if self.seekstate == self.SEEK_STATE_PAUSE:
                        seekable = self.getSeek()
                        if seekable is not None:
                if self.seekstate == self.SEEK_STATE_PAUSE:
                        seekable = self.getSeek()
                        if seekable is not None:
@@ -769,44 +861,50 @@ class InfoBarSeek:
                self.fwdKeyTimer.stop()
                self.fwdtimer = False
                self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
                self.fwdKeyTimer.stop()
                self.fwdtimer = False
                self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
-               
+
        def fwdSeekTo(self, minutes):
                print "Seek", minutes, "minutes forward"
                if minutes != 0:
                        seekable = self.getSeek()
                        if seekable is not None:
                                seekable.seekRelative(1, minutes * 60 * 90000)
        def fwdSeekTo(self, minutes):
                print "Seek", minutes, "minutes forward"
                if minutes != 0:
                        seekable = self.getSeek()
                        if seekable is not None:
                                seekable.seekRelative(1, minutes * 60 * 90000)
-       
+
        def rwdTimerFire(self):
                print "rwdTimerFire"
                self.rwdKeyTimer.stop()
                self.rwdtimer = False
                self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
        def rwdTimerFire(self):
                print "rwdTimerFire"
                self.rwdKeyTimer.stop()
                self.rwdtimer = False
                self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
-       
+
        def rwdSeekTo(self, minutes):
                print "rwdSeekTo"
                self.fwdSeekTo(0 - minutes)
        def rwdSeekTo(self, minutes):
                print "rwdSeekTo"
                self.fwdSeekTo(0 - minutes)
-       
+
        def checkSkipShowHideLock(self):
                wantlock = self.seekstate != self.SEEK_STATE_PLAY
        def checkSkipShowHideLock(self):
                wantlock = self.seekstate != self.SEEK_STATE_PLAY
-               
-               if self.lockedBecauseOfSkipping and not wantlock:
-                       self.unlockShow()
-                       self.lockedBecauseOfSkipping = False
-               
-               if wantlock and not self.lockedBecauseOfSkipping:
-                       self.lockShow()
-                       self.lockedBecauseOfSkipping = True
+
+               if config.usage.show_infobar_on_zap.value:
+                       if self.lockedBecauseOfSkipping and not wantlock:
+                               self.unlockShow()
+                               self.lockedBecauseOfSkipping = False
+
+                       if wantlock and not self.lockedBecauseOfSkipping:
+                               self.lockShow()
+                               self.lockedBecauseOfSkipping = True
 
        def __evEOF(self):
 
        def __evEOF(self):
-               if self.seekstate != self.SEEK_STATE_PLAY:
-                       self.setSeekState(self.SEEK_STATE_PAUSE)
-                       # HACK
-                       #self.getSeek().seekRelative(1, -90000)
-                       self.setSeekState(self.SEEK_STATE_PLAY)
+               if self.seekstate == self.SEEK_STATE_EOF:
+                       return
+               if self.seekstate[1] < 0: # SEEK_STATE_BACK_*X
+                       print "end of stream while seeking back, ignoring."
+                       return
+
+               # if we are seeking, we try to end up ~1s before the end, and pause there.
+               if not self.seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
+                       self.setSeekState(self.SEEK_STATE_EOF)
+                       self.seekRelativeToEnd(-90000)
                else:
                else:
-                       self.setSeekState(self.SEEK_STATE_PAUSE)
-       
+                       self.setSeekState(self.SEEK_STATE_EOF)
+
        def __evSOF(self):
                self.setSeekState(self.SEEK_STATE_PLAY)
                self.doSeek(0)
        def __evSOF(self):
                self.setSeekState(self.SEEK_STATE_PLAY)
                self.doSeek(0)
@@ -814,7 +912,26 @@ class InfoBarSeek:
        def seekRelative(self, diff):
                seekable = self.getSeek()
                if seekable is not None:
        def seekRelative(self, diff):
                seekable = self.getSeek()
                if seekable is not None:
-                       seekable.seekRelative(1, diff)
+                       print "seekRelative: res:", seekable.seekRelative(1, diff)
+               else:
+                       print "seek failed!"
+
+       def seekRelativeToEnd(self, diff):
+               assert diff <= 0, "diff is expected to be negative!"
+
+               # might sound like an evil hack, but:
+               # if we seekRelativeToEnd(0), we expect to be at the end, which is what we want,
+               # and we don't get that by passing 0 here (it would seek to begin).
+               if diff == 0:
+                       diff = -1
+
+               # relative-to-end seeking is implemented as absolutes seeks with negative time
+               self.seekAbsolute(diff)
+
+       def seekAbsolute(self, abs):
+               seekable = self.getSeek()
+               if seekable is not None:
+                       seekable.seekTo(abs)
 
 from Screens.PVRState import PVRState, TimeshiftState
 
 
 from Screens.PVRState import PVRState, TimeshiftState
 
@@ -822,22 +939,25 @@ class InfoBarPVRState:
        def __init__(self, screen=PVRState):
                self.onPlayStateChanged.append(self.__playStateChanged)
                self.pvrStateDialog = self.session.instantiateDialog(screen)
        def __init__(self, screen=PVRState):
                self.onPlayStateChanged.append(self.__playStateChanged)
                self.pvrStateDialog = self.session.instantiateDialog(screen)
-               self.onShow.append(self.__mayShow)
+               self.onShow.append(self._mayShow)
                self.onHide.append(self.pvrStateDialog.hide)
                self.onHide.append(self.pvrStateDialog.hide)
-       
-       def __mayShow(self):
-               if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
+
+       def _mayShow(self):
+               if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
                        self.pvrStateDialog.show()
 
        def __playStateChanged(self, state):
                playstateString = state[3]
                self.pvrStateDialog["state"].setText(playstateString)
                        self.pvrStateDialog.show()
 
        def __playStateChanged(self, state):
                playstateString = state[3]
                self.pvrStateDialog["state"].setText(playstateString)
-               self.__mayShow()
+               self._mayShow()
 
 class InfoBarTimeshiftState(InfoBarPVRState):
        def __init__(self):
                InfoBarPVRState.__init__(self, screen=TimeshiftState)
 
 
 class InfoBarTimeshiftState(InfoBarPVRState):
        def __init__(self):
                InfoBarPVRState.__init__(self, screen=TimeshiftState)
 
+       def _mayShow(self):
+               if self.execing and self.timeshift_enabled:
+                       self.pvrStateDialog.show()
 
 class InfoBarShowMovies:
 
 
 class InfoBarShowMovies:
 
@@ -859,7 +979,7 @@ class InfoBarShowMovies:
 # Timeshift works the following way:
 #                                         demux0   demux1                    "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
 # - normal playback                       TUNER    unused      PLAY               enable                disable              disable
 # Timeshift works the following way:
 #                                         demux0   demux1                    "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
 # - normal playback                       TUNER    unused      PLAY               enable                disable              disable
-# - user presses "yellow" button.         TUNER    record      PAUSE              enable                disable              enable
+# - user presses "yellow" button.         FILE     record      PAUSE              enable                disable              enable
 # - user presess pause again              FILE     record      PLAY               enable                disable              enable
 # - user fast forwards                    FILE     record      FF                 enable                disable              enable
 # - end of timeshift buffer reached       TUNER    record      PLAY               enable                enable               disable
 # - user presess pause again              FILE     record      PLAY               enable                disable              enable
 # - user fast forwards                    FILE     record      FF                 enable                disable              enable
 # - end of timeshift buffer reached       TUNER    record      PLAY               enable                enable               disable
@@ -884,26 +1004,26 @@ class InfoBarTimeshift:
        def __init__(self):
                self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions", 
                        {
        def __init__(self):
                self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions", 
                        {
-                               "timeshiftStart": (self.startTimeshift, "start timeshift"),  # the "yellow key"
-                               "timeshiftStop": (self.stopTimeshift, "stop timeshift")      # currently undefined :), probably 'TV'
+                               "timeshiftStart": (self.startTimeshift, _("start timeshift")),  # the "yellow key"
+                               "timeshiftStop": (self.stopTimeshift, _("stop timeshift"))      # currently undefined :), probably 'TV'
                        }, prio=1)
                self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
                        {
                        }, prio=1)
                self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
                        {
-                               "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
-                               "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause  # something like "backward key"
+                               "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
+                               "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause  # something like "pause key"
                        }, prio=-1) # priority over record
 
                self.timeshift_enabled = 0
                self.timeshift_state = 0
                        }, prio=-1) # priority over record
 
                self.timeshift_enabled = 0
                self.timeshift_state = 0
-               self.ts_pause_timer = eTimer()
-               self.ts_pause_timer.timeout.get().append(self.pauseService)
+               self.ts_rewind_timer = eTimer()
+               self.ts_rewind_timer.timeout.get().append(self.rewindService)
 
                self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
                        {
                                iPlayableService.evStart: self.__serviceStarted,
                                iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
                        })
 
                self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
                        {
                                iPlayableService.evStart: self.__serviceStarted,
                                iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
                        })
-       
+
        def getTimeshift(self):
                service = self.session.nav.getCurrentService()
                return service and service.timeshift()
        def getTimeshift(self):
                service = self.session.nav.getCurrentService()
                return service and service.timeshift()
@@ -914,19 +1034,21 @@ class InfoBarTimeshift:
                if ts is None:
                        self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
                        print "no ts interface"
                if ts is None:
                        self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
                        print "no ts interface"
-                       return
-               
+                       return 0
+
                if self.timeshift_enabled:
                        print "hu, timeshift already enabled?"
                else:
                        if not ts.startTimeshift():
                if self.timeshift_enabled:
                        print "hu, timeshift already enabled?"
                else:
                        if not ts.startTimeshift():
-                               import time
                                self.timeshift_enabled = 1
                                self.timeshift_enabled = 1
-                               self.pvrStateDialog["timeshift"].setRelative(time.time())
-                               
+
+                               # we remove the "relative time" for now.
+                               #self.pvrStateDialog["timeshift"].setRelative(time.time())
+
                                # PAUSE.
                                # PAUSE.
-                               self.setSeekState(self.SEEK_STATE_PAUSE)
-                               
+                               #self.setSeekState(self.SEEK_STATE_PAUSE)
+                               self.activateTimeshiftEnd(False)
+
                                # enable the "TimeshiftEnableActions", which will override
                                # the startTimeshift actions
                                self.__seekableStatusChanged()
                                # enable the "TimeshiftEnableActions", which will override
                                # the startTimeshift actions
                                self.__seekableStatusChanged()
@@ -935,11 +1057,11 @@ class InfoBarTimeshift:
 
        def stopTimeshift(self):
                if not self.timeshift_enabled:
 
        def stopTimeshift(self):
                if not self.timeshift_enabled:
-                       return
+                       return 0
                print "disable timeshift"
                ts = self.getTimeshift()
                if ts is None:
                print "disable timeshift"
                ts = self.getTimeshift()
                if ts is None:
-                       return
+                       return 0
                self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
 
        def stopTimeshiftConfirmed(self, confirmed):
                self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
 
        def stopTimeshiftConfirmed(self, confirmed):
@@ -955,45 +1077,42 @@ class InfoBarTimeshift:
 
                # disable actions
                self.__seekableStatusChanged()
 
                # disable actions
                self.__seekableStatusChanged()
-       
+
        # activates timeshift, and seeks to (almost) the end
        # activates timeshift, and seeks to (almost) the end
-       def activateTimeshiftEnd(self):
+       def activateTimeshiftEnd(self, back = True):
                ts = self.getTimeshift()
                ts = self.getTimeshift()
-               
+               print "activateTimeshiftEnd"
+
                if ts is None:
                        return
                if ts is None:
                        return
-               
+
                if ts.isTimeshiftActive():
                        print "!! activate timeshift called - but shouldn't this be a normal pause?"
                        self.pauseService()
                else:
                if ts.isTimeshiftActive():
                        print "!! activate timeshift called - but shouldn't this be a normal pause?"
                        self.pauseService()
                else:
-                       self.setSeekState(self.SEEK_STATE_PLAY)
-                       ts.activateTimeshift()
-                       self.seekRelative(0)
-       
+                       print "play, ..."
+                       ts.activateTimeshift() # activate timeshift will automatically pause
+                       self.setSeekState(self.SEEK_STATE_PAUSE)
+                       self.seekRelativeToEnd(-90000) # seek approx. 1 sec before end
+
+               if back:
+                       self.ts_rewind_timer.start(200, 1)
+
+       def rewindService(self):
+               self.setSeekState(self.SEEK_STATE_BACK_16X)
+
        # same as activateTimeshiftEnd, but pauses afterwards.
        def activateTimeshiftEndAndPause(self):
        # same as activateTimeshiftEnd, but pauses afterwards.
        def activateTimeshiftEndAndPause(self):
-               state = self.seekstate
-               self.activateTimeshiftEnd()
-               
-               # well, this is "andPause", but it could be pressed from pause,
-               # when pausing on the (fake-)"live" picture, so an un-pause
-               # is perfectly ok.
-               
-               print "now, pauseService"
-               if state == self.SEEK_STATE_PLAY:
-                       print "is PLAYING, start pause timer"
-                       self.ts_pause_timer.start(200, 1)
-               else:
-                       print "unpause"
-                       self.unPauseService()
-       
+               print "activateTimeshiftEndAndPause"
+               #state = self.seekstate
+               self.activateTimeshiftEnd(False)
+
        def __seekableStatusChanged(self):
                enabled = False
        def __seekableStatusChanged(self):
                enabled = False
-               
+
                print "self.isSeekable", self.isSeekable()
                print "self.timeshift_enabled", self.timeshift_enabled
                print "self.isSeekable", self.isSeekable()
                print "self.timeshift_enabled", self.timeshift_enabled
-               
+
                # when this service is not seekable, but timeshift
                # is enabled, this means we can activate
                # the timeshift
                # when this service is not seekable, but timeshift
                # is enabled, this means we can activate
                # the timeshift
@@ -1010,52 +1129,164 @@ class InfoBarTimeshift:
 from Screens.PiPSetup import PiPSetup
 
 class InfoBarExtensions:
 from Screens.PiPSetup import PiPSetup
 
 class InfoBarExtensions:
+       EXTENSION_SINGLE = 0
+       EXTENSION_LIST = 1
+
        def __init__(self):
        def __init__(self):
-               self.pipshown = False
-               
+               self.list = []
+
                self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
                        {
                self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
                        {
-                               "extensions": (self.extensions, "Extensions..."),
+                               "extensions": (self.showExtensionSelection, _("view extensions...")),
                        })
 
                        })
 
-       PIPON = 0
-       PIPOFF = 1
-       MOVEPIP = 2
-       PIPSWAP = 3
+       def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
+               self.list.append((type, extension, key))
+
+       def updateExtension(self, extension, key = None):
+               self.extensionsList.append(extension)
+               if key is not None:
+                       if self.extensionKeys.has_key(key):
+                               key = None
+
+               if key is None:
+                       for x in self.availableKeys:
+                               if not self.extensionKeys.has_key(x):
+                                       key = x
+                                       break
+
+               if key is not None:
+                       self.extensionKeys[key] = len(self.extensionsList) - 1
+
+       def updateExtensions(self):
+               self.extensionsList = []
+               self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
+               self.extensionKeys = {}
+               for x in self.list:
+                       if x[0] == self.EXTENSION_SINGLE:
+                               self.updateExtension(x[1], x[2])
+                       else:
+                               for y in x[1]():
+                                       self.updateExtension(y[0], y[1])
+
 
 
-       def extensions(self):
+       def showExtensionSelection(self):
+               self.updateExtensions()
+               extensionsList = self.extensionsList[:]
+               keys = []
                list = []
                list = []
-               if self.pipshown == False:
-                       list.append((_("Activate Picture in Picture"), self.PIPON))
-               elif self.pipshown == True:
-                       list.append((_("Disable Picture in Picture"), self.PIPOFF))
-                       list.append((_("Move Picture in Picture"), self.MOVEPIP))
-                       list.append((_("Swap services"), self.PIPSWAP))
-               self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list)
+               for x in self.availableKeys:
+                       if self.extensionKeys.has_key(x):
+                               entry = self.extensionKeys[x]
+                               extension = self.extensionsList[entry]
+                               if extension[2]():
+                                       name = str(extension[0]())
+                                       list.append((extension[0](), extension))
+                                       keys.append(x)
+                                       extensionsList.remove(extension)
+                               else:
+                                       extensionsList.remove(extension)
+               for x in extensionsList:
+                       list.append((x[0](), x))
+               keys += [""] * len(extensionsList)
+               self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
 
        def extensionCallback(self, answer):
                if answer is not None:
 
        def extensionCallback(self, answer):
                if answer is not None:
-                       if answer[1] == self.PIPON:
-                               self.pip = self.session.instantiateDialog(PictureInPicture)
-                               
-                               newservice = self.session.nav.getCurrentlyPlayingServiceReference()
-                               
-                               if self.pip.playService(newservice):
-                                       self.pipshown = True
-                               else:
-                                       self.pipshown = False
-                                       del self.pip
-                               self.session.nav.playService(newservice)
-                       elif answer[1] == self.PIPOFF:
-                               del self.pip
-                               self.pipshown = False
-                       elif answer[1] == self.PIPSWAP:
-                               swapservice = self.pip.getCurrentService()
-                               self.pip.playService(self.session.nav.getCurrentlyPlayingServiceReference())
-                               self.session.nav.playService(swapservice)
-                               
-                       elif answer[1] == self.MOVEPIP:
-                               self.session.open(PiPSetup, pip = self.pip)
+                       answer[1][1]()
+
+from Tools.BoundFunction import boundFunction
+
+# depends on InfoBarExtensions
+from Components.PluginComponent import plugins
+
+class InfoBarPlugins:
+       def __init__(self):
+               self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
+
+       def getPluginName(self, name):
+               return name
+
+       def getPluginList(self):
+               list = []
+               for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
+                       list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
+               return list
+
+       def runPlugin(self, plugin):
+               plugin(session = self.session)
+
+# depends on InfoBarExtensions
+class InfoBarSleepTimer:
+       def __init__(self):
+               self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
+
+       def available(self):
+               return True
+
+       def getSleepTimerName(self):
+               return _("Sleep Timer")
+
+       def showSleepTimerSetup(self):
+               self.session.open(SleepTimerEdit)
+
+# depends on InfoBarExtensions
+class InfoBarPiP:
+       def __init__(self):
+               self.session.pipshown = False
+
+               self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
+               self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
+               self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
+
+       def available(self):
+               return True
+
+       def pipShown(self):
+               return self.session.pipshown
+
+       def getShowHideName(self):
+               if self.session.pipshown:
+                       return _("Disable Picture in Picture")
+               else:
+                       return _("Activate Picture in Picture")
+
+       def getSwapName(self):
+               return _("Swap Services")
+
+       def getMoveName(self):
+               return _("Move Picture in Picture")
+
+       def showPiP(self):
+               if self.session.pipshown:
+                       del self.session.pip
+                       self.session.pipshown = False
+               else:
+                       self.session.pip = self.session.instantiateDialog(PictureInPicture)
+                       newservice = self.session.nav.getCurrentlyPlayingServiceReference()
+                       if self.session.pip.playService(newservice):
+                               self.session.pipshown = True
+                               self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
+                       else:
+                               self.session.pipshown = False
+                               del self.session.pip
+                       self.session.nav.playService(newservice)
+
+       def swapPiP(self):
+               swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
+               if self.session.pip.servicePath:
+                       servicepath = self.servicelist.getCurrentServicePath()
+                       ref=servicepath[len(servicepath)-1]
+                       pipref=self.session.pip.getCurrentService()
+                       self.session.pip.playService(swapservice)
+                       self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
+                       if pipref.toString() != ref.toString(): # is a subservice ?
+                               self.session.nav.stopService() # stop portal
+                               self.session.nav.playService(pipref) # start subservice
+                       self.session.pip.servicePath=servicepath
+
+       def movePiP(self):
+               self.session.open(PiPSetup, pip = self.session.pip)
 
 from RecordTimer import parseEvent
 
 
 from RecordTimer import parseEvent
 
@@ -1065,21 +1296,21 @@ class InfoBarInstantRecord:
        def __init__(self):
                self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
                        {
        def __init__(self):
                self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
                        {
-                               "instantRecord": (self.instantRecord, "Instant Record..."),
+                               "instantRecord": (self.instantRecord, _("Instant Record...")),
                        })
                self.recording = []
                self["BlinkingPoint"] = BlinkingPixmapConditional()
                self["BlinkingPoint"].hide()
                self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
 
                        })
                self.recording = []
                self["BlinkingPoint"] = BlinkingPixmapConditional()
                self["BlinkingPoint"].hide()
                self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
 
-       def stopCurrentRecording(self, entry = -1):     
+       def stopCurrentRecording(self, entry = -1):
                if entry is not None and entry != -1:
                        self.session.nav.RecordTimer.removeEntry(self.recording[entry])
                        self.recording.remove(self.recording[entry])
                if entry is not None and entry != -1:
                        self.session.nav.RecordTimer.removeEntry(self.recording[entry])
                        self.recording.remove(self.recording[entry])
-                       
+
        def startInstantRecording(self, limitEvent = False):
                serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
        def startInstantRecording(self, limitEvent = False):
                serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
-               
+
                # try to get event info
                event = None
                try:
                # try to get event info
                event = None
                try:
@@ -1093,12 +1324,12 @@ class InfoBarInstantRecord:
                except:
                        pass
 
                except:
                        pass
 
-               begin = time.time()
-               end = time.time() + 3600 * 10
+               begin = time()
+               end = time() + 3600 * 10
                name = "instant record"
                description = ""
                eventid = None
                name = "instant record"
                description = ""
                eventid = None
-               
+
                if event is not None:
                        curEvent = parseEvent(event)
                        name = curEvent[2]
                if event is not None:
                        curEvent = parseEvent(event)
                        name = curEvent[2]
@@ -1109,15 +1340,15 @@ class InfoBarInstantRecord:
                else:
                        if limitEvent:
                                self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
                else:
                        if limitEvent:
                                self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
-                               
+
                data = (begin, end, name, description, eventid)
                data = (begin, end, name, description, eventid)
-               
+
                recording = self.session.nav.recordWithTimer(serviceref, *data)
                recording.dontSave = True
                self.recording.append(recording)
                recording = self.session.nav.recordWithTimer(serviceref, *data)
                recording.dontSave = True
                self.recording.append(recording)
-               
+
                #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
                #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
-               
+
        def isInstantRecordRunning(self):
                print "self.recording:", self.recording
                if len(self.recording) > 0:
        def isInstantRecordRunning(self):
                print "self.recording:", self.recording
                if len(self.recording) > 0:
@@ -1128,7 +1359,7 @@ class InfoBarInstantRecord:
 
        def recordQuestionCallback(self, answer):
                print "pre:\n", self.recording
 
        def recordQuestionCallback(self, answer):
                print "pre:\n", self.recording
-               
+
                if answer is None or answer[1] == "no":
                        return
                list = []
                if answer is None or answer[1] == "no":
                        return
                list = []
@@ -1137,29 +1368,46 @@ class InfoBarInstantRecord:
                        if not x in self.session.nav.RecordTimer.timer_list:
                                self.recording.remove(x)
                        elif x.dontSave and x.isRunning():
                        if not x in self.session.nav.RecordTimer.timer_list:
                                self.recording.remove(x)
                        elif x.dontSave and x.isRunning():
-                               list.append(TimerEntryComponent(x, False))              
+                               list.append(TimerEntryComponent(x, False))
 
                if answer[1] == "changeduration":
                        if len(self.recording) == 1:
                                self.changeDuration(0)
                        else:
                                self.session.openWithCallback(self.changeDuration, TimerSelection, list)
 
                if answer[1] == "changeduration":
                        if len(self.recording) == 1:
                                self.changeDuration(0)
                        else:
                                self.session.openWithCallback(self.changeDuration, TimerSelection, list)
+               elif answer[1] == "changeendtime":
+                       if len(self.recording) == 1:
+                               self.setEndtime(0)
+                       else:
+                               self.session.openWithCallback(self.setEndTime, TimerSelection, list)
                elif answer[1] == "stop":
                        if len(self.recording) == 1:
                                self.stopCurrentRecording(0)
                        else:
                                self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
                elif answer[1] == "stop":
                        if len(self.recording) == 1:
                                self.stopCurrentRecording(0)
                        else:
                                self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
-               if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
-                       limitEvent = False
-                       if answer[1] == "event":
-                               limitEvent = True
+               elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
+                       self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
                        if answer[1] == "manualduration":
                        if answer[1] == "manualduration":
-                               self.selectedEntry = len(self.recording)
-                               self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
-                       self.startInstantRecording(limitEvent = limitEvent)
-                       
+                               self.changeDuration(len(self.recording)-1)
+                       elif answer[1] == "manualendtime":
+                               self.setEndtime(len(self.recording)-1)
                print "after:\n", self.recording
 
                print "after:\n", self.recording
 
+       def setEndtime(self, entry):
+               if entry is not None:
+                       self.selectedEntry = entry
+                       self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
+                       dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
+                       dlg.setTitle(_("Please change recording endtime"))
+
+       def TimeDateInputClosed(self, ret):
+               if len(ret) > 1:
+                       if ret[0]:
+                               localendtime = localtime(ret[1])
+                               print "stopping recording at", strftime("%c", localendtime)
+                               self.recording[self.selectedEntry].end = ret[1]
+                               self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
+
        def changeDuration(self, entry):
                if entry is not None:
                        self.selectedEntry = entry
        def changeDuration(self, entry):
                if entry is not None:
                        self.selectedEntry = entry
@@ -1168,20 +1416,35 @@ class InfoBarInstantRecord:
        def inputCallback(self, value):
                if value is not None:
                        print "stopping recording after", int(value), "minutes."
        def inputCallback(self, value):
                if value is not None:
                        print "stopping recording after", int(value), "minutes."
-                       self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
+                       self.recording[self.selectedEntry].end = time() + 60 * int(value)
                        self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
 
        def instantRecord(self):
                try:
                        self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
 
        def instantRecord(self):
                try:
-                       stat = os.stat(resolveFilename(SCOPE_HDD))
+                       stat = os_stat(resolveFilename(SCOPE_HDD))
                except:
                        self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
                        return
                except:
                        self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
                        return
-       
+
                if self.isInstantRecordRunning():
                if self.isInstantRecordRunning():
-                       self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=_("A recording is currently running.\nWhat do you want to do?"), list=[(_("stop recording"), "stop"), (_("change recording (duration)"), "changeduration"), (_("add recording (indefinitely)"), "indefinitely"), (_("add recording (stop after current event)"), "event"), (_("add recording (enter recording duration)"), "manualduration"), (_("do nothing"), "no")])
+                       self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
+                               title=_("A recording is currently running.\nWhat do you want to do?"), \
+                               list=[(_("stop recording"), "stop"), \
+                               (_("change recording (duration)"), "changeduration"), \
+                               (_("change recording (endtime)"), "changeendtime"), \
+                               (_("add recording (indefinitely)"), "indefinitely"), \
+                               (_("add recording (stop after current event)"), "event"), \
+                               (_("add recording (enter recording duration)"), "manualduration"), \
+                               (_("add recording (enter recording endtime)"), "manualendtime"), \
+                               (_("do nothing"), "no")])
                else:
                else:
-                       self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=_("Start recording?"), list=[(_("add recording (indefinitely)"), "indefinitely"), (_("add recording (stop after current event)"), "event"), (_("add recording (enter recording duration)"), "manualduration"),(_("don't record"), "no")])
+                       self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
+                               title=_("Start recording?"), \
+                               list=[(_("add recording (indefinitely)"), "indefinitely"), \
+                               (_("add recording (stop after current event)"), "event"), \
+                               (_("add recording (enter recording duration)"), "manualduration"), \
+                               (_("add recording (enter recording endtime)"), "manualendtime"), \
+                               (_("don't record"), "no")])
 
 from Tools.ISO639 import LanguageCodes
 
 
 from Tools.ISO639 import LanguageCodes
 
@@ -1189,56 +1452,70 @@ class InfoBarAudioSelection:
        def __init__(self):
                self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions", 
                        {
        def __init__(self):
                self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions", 
                        {
-                               "audioSelection": (self.audioSelection, "Audio Options..."),
+                               "audioSelection": (self.audioSelection, _("Audio Options...")),
                        })
 
        def audioSelection(self):
                service = self.session.nav.getCurrentService()
                        })
 
        def audioSelection(self):
                service = self.session.nav.getCurrentService()
-               audio = service.audioTracks()
+               audio = service and service.audioTracks()
                self.audioTracks = audio
                self.audioTracks = audio
-               n = audio.getNumberOfTracks()
+               n = audio and audio.getNumberOfTracks() or 0
+               keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
+               tlist = []
+               print "tlist:", tlist
                if n > 0:
                if n > 0:
-#                      self.audioChannel = service.audioChannel()
-#                      config.audio.audiochannel = configElement_nonSave("config.audio.audiochannel", configSelection, self.audioChannel.getCurrentChannel(), (("left", _("Left  >")), ("stereo", _("<  Stereo  >")), ("right", _("<  Right"))))
-                       tlist = []
+                       self.audioChannel = service.audioChannel()
+
                        for x in range(n):
                                i = audio.getTrackInfo(x)
                                language = i.getLanguage()
                        for x in range(n):
                                i = audio.getTrackInfo(x)
                                language = i.getLanguage()
-                               description = i.getDescription();
-       
-                               if len(language) == 3:
-                                       if language in LanguageCodes:
-                                               language = LanguageCodes[language][0]
-       
+                               description = i.getDescription()
+
+                               if LanguageCodes.has_key(language):
+                                       language = LanguageCodes[language][0]
+
                                if len(description):
                                        description += " (" + language + ")"
                                else:
                                        description = language
                                if len(description):
                                        description += " (" + language + ")"
                                else:
                                        description = language
-       
+
                                tlist.append((description, x))
                                tlist.append((description, x))
-                       
+
                        selectedAudio = tlist[0][1]
                        tlist.sort(lambda x,y : cmp(x[0], y[0]))
 
                        selectedAudio = tlist[0][1]
                        tlist.sort(lambda x,y : cmp(x[0], y[0]))
 
-#                      tlist.insert(0, getConfigListEntry(_("Audio Channel"), config.audio.audiochannel))
-
-                       selection = 0
+                       selection = 2
                        for x in tlist:
                                if x[1] != selectedAudio:
                                        selection += 1
                                else:
                                        break
                        for x in tlist:
                                if x[1] != selectedAudio:
                                        selection += 1
                                else:
                                        break
-                       
-                       self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection)
+
+                       tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
+                       self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
                else:
                        del self.audioTracks
 
        def audioSelected(self, audio):
                if audio is not None:
                else:
                        del self.audioTracks
 
        def audioSelected(self, audio):
                if audio is not None:
-                       self.audioTracks.selectTrack(audio[1])
+                       if isinstance(audio[1], str):
+                               if audio[1] == "mode":
+                                       keys = ["red", "green", "yellow"]
+                                       selection = self.audioChannel.getCurrentChannel()
+                                       tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
+                                       self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
+                       else:
+                               del self.audioChannel
+                               if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
+                                       self.audioTracks.selectTrack(audio[1])
+               else:
+                       del self.audioChannel
                del self.audioTracks
                del self.audioTracks
-#              del self.audioChannel
-#              del config.audio.audiochannel
+
+       def modeSelected(self, mode):
+               if mode is not None:
+                       self.audioChannel.selectChannel(mode[1])
+               del self.audioChannel
 
 class InfoBarSubserviceSelection:
        def __init__(self):
 
 class InfoBarSubserviceSelection:
        def __init__(self):
@@ -1256,11 +1533,13 @@ class InfoBarSubserviceSelection:
 
                self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
 
 
                self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
 
+               self.bsel = None
+
        def checkSubservicesAvail(self, ev):
                if ev == iPlayableService.evUpdatedEventInfo:
                        service = self.session.nav.getCurrentService()
        def checkSubservicesAvail(self, ev):
                if ev == iPlayableService.evUpdatedEventInfo:
                        service = self.session.nav.getCurrentService()
-                       subservices = service.subServices()
-                       if subservices.getNumberOfSubservices() == 0:
+                       subservices = service and service.subServices()
+                       if not subservices or subservices.getNumberOfSubservices() == 0:
                                self["SubserviceQuickzapAction"].setEnabled(False)
 
        def nextSubservice(self):
                                self["SubserviceQuickzapAction"].setEnabled(False)
 
        def nextSubservice(self):
@@ -1271,9 +1550,9 @@ class InfoBarSubserviceSelection:
 
        def changeSubservice(self, direction):
                service = self.session.nav.getCurrentService()
 
        def changeSubservice(self, direction):
                service = self.session.nav.getCurrentService()
-               subservices = service.subServices()
-               n = subservices.getNumberOfSubservices()
-               if n > 0:
+               subservices = service and service.subServices()
+               n = subservices and subservices.getNumberOfSubservices()
+               if n and n > 0:
                        selection = -1
                        ref = self.session.nav.getCurrentlyPlayingServiceReference()
                        for x in range(n):
                        selection = -1
                        ref = self.session.nav.getCurrentlyPlayingServiceReference()
                        for x in range(n):
@@ -1293,11 +1572,11 @@ class InfoBarSubserviceSelection:
 
        def subserviceSelection(self):
                service = self.session.nav.getCurrentService()
 
        def subserviceSelection(self):
                service = self.session.nav.getCurrentService()
-               subservices = service.subServices()
-               
-               n = subservices.getNumberOfSubservices()
+               subservices = service and service.subServices()
+               self.bouquets = self.servicelist.getBouquetList()
+               n = subservices and subservices.getNumberOfSubservices()
                selection = 0
                selection = 0
-               if n > 0:
+               if n and n > 0:
                        ref = self.session.nav.getCurrentlyPlayingServiceReference()
                        tlist = []
                        for x in range(n):
                        ref = self.session.nav.getCurrentlyPlayingServiceReference()
                        tlist = []
                        for x in range(n):
@@ -1306,116 +1585,110 @@ class InfoBarSubserviceSelection:
                                        selection = x
                                tlist.append((i.getName(), i))
 
                                        selection = x
                                tlist.append((i.getName(), i))
 
-                       self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection)
+                       if self.bouquets and len(self.bouquets):
+                               keys = ["red", "green", "",  "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
+                               if config.usage.multibouquet.value:
+                                       tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
+                               else:
+                                       tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
+                               selection += 3
+                       else:
+                               tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
+                               keys = ["red", "",  "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
+                               selection += 2
+
+                       self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
 
        def subserviceSelected(self, service):
 
        def subserviceSelected(self, service):
+               del self.bouquets
                if not service is None:
                if not service is None:
-                       self["SubserviceQuickzapAction"].setEnabled(True)
-                       self.session.nav.playService(service[1])
+                       if isinstance(service[1], str):
+                               if service[1] == "quickzap":
+                                       from Screens.SubservicesQuickzap import SubservicesQuickzap
+                                       self.session.open(SubservicesQuickzap, service[2])
+                       else:
+                               self["SubserviceQuickzapAction"].setEnabled(True)
+                               self.session.nav.playService(service[1])
+
+       def addSubserviceToBouquetCallback(self, service):
+               if len(service) > 1 and isinstance(service[1], eServiceReference):
+                       self.selectedSubservice = service
+                       if self.bouquets is None:
+                               cnt = 0
+                       else:
+                               cnt = len(self.bouquets)
+                       if cnt > 1: # show bouquet list
+                               self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
+                       elif cnt == 1: # add to only one existing bouquet
+                               self.addSubserviceToBouquet(self.bouquets[0][1])
+                               self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
+
+       def bouquetSelClosed(self, confirmed):
+               self.bsel = None
+               del self.selectedSubservice
+               if confirmed:
+                       self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
+
+       def addSubserviceToBouquet(self, dest):
+               self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
+               if self.bsel:
+                       self.bsel.close(True)
+               else:
+                       del self.selectedSubservice
 
 class InfoBarAdditionalInfo:
        def __init__(self):
 
 class InfoBarAdditionalInfo:
        def __init__(self):
-               self["DolbyActive"] = Pixmap()
-               self["CryptActive"] = Pixmap()
-               self["FormatActive"] = Pixmap()
-               
-               self["ButtonRed"] = PixmapConditional(withTimer = False)
-               self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
-               self.onLayoutFinish.append(self["ButtonRed"].update)
-               self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
-               self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
-               self.onLayoutFinish.append(self["ButtonRedText"].update)
-
-               self["ButtonGreen"] = Pixmap()
-               self["ButtonGreenText"] = Label(_("Subservices"))
-
-               self["ButtonYellow"] = PixmapConditional(withTimer = False)
-               self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
-               self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
-               self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
-               self.onLayoutFinish.append(self["ButtonYellow"].update)
-               self.onLayoutFinish.append(self["ButtonYellowText"].update)
-
-               self["ButtonBlue"] = PixmapConditional(withTimer = False)
-               self["ButtonBlue"].setConnect(lambda: True)
-               self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
-               self["ButtonBlueText"].setConnect(lambda: True)
-               self.onLayoutFinish.append(self["ButtonBlue"].update)
-               self.onLayoutFinish.append(self["ButtonBlueText"].update)
+               self["NimA"] = Pixmap()
+               self["NimB"] = Pixmap()
+               self["NimA_Active"] = Pixmap()
+               self["NimB_Active"] = Pixmap()
 
 
-               self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
-
-       def hideSubServiceIndication(self):
-               self["ButtonGreen"].hide()
-               self["ButtonGreenText"].hide()
+               self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
+               self["TimeshiftPossible"] = self["RecordingPossible"]
+               self["ExtensionsAvailable"] = Boolean(fixed=1)
 
 
-       def showSubServiceIndication(self):
-               self["ButtonGreen"].show()
-               self["ButtonGreenText"].show()
-
-       def checkFormat(self, service):
-               info = service.info()
-               if info is not None:
-                       aspect = info.getInfo(iServiceInformation.sAspect)
-                       if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
-                               self["FormatActive"].show()
-                       else:
-                               self["FormatActive"].hide()
+               self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
+               res_mgr = eDVBResourceManager.getInstance()
+               if res_mgr:
+                       res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
 
 
-       def checkSubservices(self, service):
-               if service.subServices().getNumberOfSubservices() > 0:
-                       self.showSubServiceIndication()
+       def tunerUseMaskChanged(self, mask):
+               if mask&1:
+                       self["NimA_Active"].show()
                else:
                else:
-                       self.hideSubServiceIndication()
-
-       def checkDolby(self, service):
-               # FIXME
-               dolby = False
-               audio = service.audioTracks()
-               if audio is not None:
-                       n = audio.getNumberOfTracks()
-                       for x in range(n):
-                               i = audio.getTrackInfo(x)
-                               description = i.getDescription();
-                               if description.find("AC3") != -1 or description.find("DTS") != -1:
-                                       dolby = True
-                                       break
-               if dolby:
-                       self["DolbyActive"].show()
+                       self["NimA_Active"].hide()
+               if mask&2:
+                       self["NimB_Active"].show()
                else:
                else:
-                       self["DolbyActive"].hide()
-
-       def checkCrypted(self, service):
-               info = service.info()
-               if info is not None:
-                       if info.getInfo(iServiceInformation.sIsCrypted) > 0:
-                               self["CryptActive"].show()
-                       else:
-                               self["CryptActive"].hide()
+                       self["NimB_Active"].hide()
+
+       def checkTunerState(self, service):
+               info = service and service.frontendInfo()
+               feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
+               if feNumber is None:
+                       self["NimA"].hide()
+                       self["NimB"].hide()
+               elif feNumber == 0:
+                       self["NimB"].hide()
+                       self["NimA"].show()
+               elif feNumber == 1:
+                       self["NimA"].hide()
+                       self["NimB"].show()
 
        def gotServiceEvent(self, ev):
                service = self.session.nav.getCurrentService()
 
        def gotServiceEvent(self, ev):
                service = self.session.nav.getCurrentService()
-               if ev == iPlayableService.evUpdatedEventInfo:
-                       self.checkSubservices(service)
-                       self.checkFormat(service)
-               elif ev == iPlayableService.evUpdatedInfo:
-                       self.checkCrypted(service)
-                       self.checkDolby(service)
-               elif ev == iPlayableService.evEnd:
-                       self.hideSubServiceIndication()
-                       self["CryptActive"].hide()
-                       self["DolbyActive"].hide()
-                       self["FormatActive"].hide()
+               if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
+                       self.checkTunerState(service)
 
 class InfoBarNotifications:
        def __init__(self):
                self.onExecBegin.append(self.checkNotifications)
                Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
                self.onClose.append(self.__removeNotification)
 
 class InfoBarNotifications:
        def __init__(self):
                self.onExecBegin.append(self.checkNotifications)
                Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
                self.onClose.append(self.__removeNotification)
-       
+
        def __removeNotification(self):
                Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
        def __removeNotification(self):
                Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
-       
+
        def checkNotificationsIfExecing(self):
                if self.execing:
                        self.checkNotifications()
        def checkNotificationsIfExecing(self):
                if self.execing:
                        self.checkNotifications()
@@ -1423,12 +1696,26 @@ class InfoBarNotifications:
        def checkNotifications(self):
                if len(Notifications.notifications):
                        n = Notifications.notifications[0]
        def checkNotifications(self):
                if len(Notifications.notifications):
                        n = Notifications.notifications[0]
+
                        Notifications.notifications = Notifications.notifications[1:]
                        cb = n[0]
                        Notifications.notifications = Notifications.notifications[1:]
                        cb = n[0]
+
+                       if n[3].has_key("onSessionOpenCallback"):
+                               n[3]["onSessionOpenCallback"]()
+                               del n[3]["onSessionOpenCallback"]
+
                        if cb is not None:
                        if cb is not None:
-                               self.session.openWithCallback(cb, n[1], *n[2], **n[3])
+                               dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
                        else:
                        else:
-                               self.session.open(n[1], *n[2], **n[3])
+                               dlg = self.session.open(n[1], *n[2], **n[3])
+
+                       # remember that this notification is currently active
+                       d = (n[4], dlg)
+                       Notifications.current_notifications.append(d)
+                       dlg.onClose.append(boundFunction(self.__notificationClosed, d))
+
+       def __notificationClosed(self, d):
+               Notifications.current_notifications.remove(d)
 
 class InfoBarServiceNotifications:
        def __init__(self):
 
 class InfoBarServiceNotifications:
        def __init__(self):
@@ -1449,7 +1736,10 @@ class InfoBarCueSheetSupport:
        CUT_TYPE_IN = 0
        CUT_TYPE_OUT = 1
        CUT_TYPE_MARK = 2
        CUT_TYPE_IN = 0
        CUT_TYPE_OUT = 1
        CUT_TYPE_MARK = 2
-       
+       CUT_TYPE_LAST = 3
+
+       ENABLE_RESUME_SUPPORT = False
+
        def __init__(self):
                self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions", 
                        {
        def __init__(self):
                self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions", 
                        {
@@ -1457,17 +1747,37 @@ class InfoBarCueSheetSupport:
                                "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
                                "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
                        }, prio=1) 
                                "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
                                "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
                        }, prio=1) 
-               
+
                self.cut_list = [ ]
                self.cut_list = [ ]
+               self.is_closing = False
                self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
                        {
                                iPlayableService.evStart: self.__serviceStarted,
                        })
 
        def __serviceStarted(self):
                self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
                        {
                                iPlayableService.evStart: self.__serviceStarted,
                        })
 
        def __serviceStarted(self):
+               if self.is_closing:
+                       return
                print "new service started! trying to download cuts!"
                self.downloadCuesheet()
 
                print "new service started! trying to download cuts!"
                self.downloadCuesheet()
 
+               if self.ENABLE_RESUME_SUPPORT:
+                       last = None
+
+                       for (pts, what) in self.cut_list:
+                               if what == self.CUT_TYPE_LAST:
+                                       last = pts
+
+                       if last is not None:
+                               self.resume_point = last
+                               Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
+
+       def playLastCB(self, answer):
+               if answer == True:
+                       seekable = self.__getSeekable()
+                       if seekable is not None:
+                               seekable.seekTo(self.resume_point)
+
        def __getSeekable(self):
                service = self.session.nav.getCurrentService()
                if service is None:
        def __getSeekable(self):
                service = self.session.nav.getCurrentService()
                if service is None:
@@ -1512,7 +1822,7 @@ class InfoBarCueSheetSupport:
                nearest = None
                for cp in self.cut_list:
                        diff = cmp(cp[0] - pts)
                nearest = None
                for cp in self.cut_list:
                        diff = cmp(cp[0] - pts)
-                       if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
+                       if cp[1] == self.CUT_TYPE_MARK and diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
                                nearest = cp
                return nearest
 
                                nearest = cp
                return nearest
 
@@ -1521,9 +1831,9 @@ class InfoBarCueSheetSupport:
                if current_pos is None:
                        print "not seekable"
                        return
                if current_pos is None:
                        print "not seekable"
                        return
-               
+
                nearest_cutpoint = self.getNearestCutPoint(current_pos)
                nearest_cutpoint = self.getNearestCutPoint(current_pos)
-               
+
                if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
                        if onlyreturn:
                                return nearest_cutpoint
                if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
                        if onlyreturn:
                                return nearest_cutpoint
@@ -1531,12 +1841,12 @@ class InfoBarCueSheetSupport:
                                self.removeMark(nearest_cutpoint)
                elif not onlyremove and not onlyreturn:
                        self.addMark((current_pos, self.CUT_TYPE_MARK))
                                self.removeMark(nearest_cutpoint)
                elif not onlyremove and not onlyreturn:
                        self.addMark((current_pos, self.CUT_TYPE_MARK))
-               
+
                if onlyreturn:
                        return None
 
        def addMark(self, point):
                if onlyreturn:
                        return None
 
        def addMark(self, point):
-               bisect.insort(self.cut_list, point)
+               insort(self.cut_list, point)
                self.uploadCuesheet()
 
        def removeMark(self, point):
                self.uploadCuesheet()
 
        def removeMark(self, point):
@@ -1568,33 +1878,37 @@ class InfoBarCueSheetSupport:
 class InfoBarSummary(Screen):
        skin = """
        <screen position="0,0" size="132,64">
 class InfoBarSummary(Screen):
        skin = """
        <screen position="0,0" size="132,64">
-               <widget name="Clock" position="50,46" size="82,18" font="Regular;16" />
-               <widget name="CurrentService" position="0,4" size="132,42" font="Regular;18" />
+               <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
+                       <convert type="ClockToText">WithSeconds</convert>
+               </widget>
+               <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
+                       <convert type="ServiceName">Name</convert>
+               </widget>
        </screen>"""
 
        def __init__(self, session, parent):
                Screen.__init__(self, session)
        </screen>"""
 
        def __init__(self, session, parent):
                Screen.__init__(self, session)
-               self["CurrentService"] = ServiceName(self.session.nav)
-               self["Clock"] = Clock()
+               self["CurrentService"] = CurrentService(self.session.nav)
+               self["CurrentTime"] = Clock()
 
 class InfoBarSummarySupport:
        def __init__(self):
                pass
 
 class InfoBarSummarySupport:
        def __init__(self):
                pass
-       
+
        def createSummary(self):
                return InfoBarSummary
 
 class InfoBarTeletextPlugin:
        def __init__(self):
                self.teletext_plugin = None
        def createSummary(self):
                return InfoBarSummary
 
 class InfoBarTeletextPlugin:
        def __init__(self):
                self.teletext_plugin = None
-               
+
                for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
                        self.teletext_plugin = p
                for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
                        self.teletext_plugin = p
-               
+
                if self.teletext_plugin is not None:
                        self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
                                {
                if self.teletext_plugin is not None:
                        self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
                                {
-                                       "startTeletext": (self.startTeletext, "View teletext...")
+                                       "startTeletext": (self.startTeletext, _("View teletext..."))
                                })
                else:
                        print "no teletext plugin found!"
                                })
                else:
                        print "no teletext plugin found!"
@@ -1610,31 +1924,88 @@ class InfoBarSubtitleSupport(object):
 
                self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
                        {
 
                self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
                        {
-                               iPlayableService.evStart: self.__serviceStarted,
+                               iPlayableService.evEnd: self.__serviceStopped,
+                               iPlayableService.evUpdatedInfo: self.__updatedInfo
                        })
                        })
+               self.cached_subtitle_checked = False
+               self.__selected_subtitle = None
 
 
-       def __serviceStarted(self):
-               # reenable if it was enabled
-               r = self.__subtitles_enabled
+       def __serviceStopped(self):
+               self.subtitle_window.hide()
                self.__subtitles_enabled = False
                self.__subtitles_enabled = False
-               self.setSubtitlesEnable(r)
+               self.cached_subtitle_checked = False
+
+       def __updatedInfo(self):
+               if not self.cached_subtitle_checked:
+                       subtitle = self.getCurrentServiceSubtitle()
+                       self.cached_subtitle_checked = True
+                       self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
+                       if self.__selected_subtitle:
+                               subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
+                               self.subtitle_window.show()
+                               self.__subtitles_enabled = True
 
        def getCurrentServiceSubtitle(self):
                service = self.session.nav.getCurrentService()
                return service and service.subtitle()
 
        def getCurrentServiceSubtitle(self):
                service = self.session.nav.getCurrentService()
                return service and service.subtitle()
-       
+
        def setSubtitlesEnable(self, enable=True):
                subtitle = self.getCurrentServiceSubtitle()
        def setSubtitlesEnable(self, enable=True):
                subtitle = self.getCurrentServiceSubtitle()
-               if enable:
+               if enable and self.__selected_subtitle is not None:
                        if subtitle and not self.__subtitles_enabled:
                        if subtitle and not self.__subtitles_enabled:
-                               subtitle.enableSubtitles(self.subtitle_window.instance, 0)
+                               subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
                                self.subtitle_window.show()
                                self.__subtitles_enabled = True
                else:
                        if subtitle:
                                subtitle.disableSubtitles(self.subtitle_window.instance)
                                self.subtitle_window.show()
                                self.__subtitles_enabled = True
                else:
                        if subtitle:
                                subtitle.disableSubtitles(self.subtitle_window.instance)
-
-                       self.subtitle_window.hide()
                        self.__subtitles_enabled = False
                        self.__subtitles_enabled = False
-               
-       subtitlesEnabled = property(lambda self: self.__subtitlesEnabled, setSubtitlesEnable)
+                       self.subtitle_window.hide()
+
+       def setSelectedSubtitle(self, subtitle):
+               self.__selected_subtitle = subtitle
+
+       subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
+       selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
+
+class InfoBarServiceErrorPopupSupport:
+       def __init__(self):
+               self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
+                       {
+                               iPlayableService.evTuneFailed: self.__tuneFailed,
+                               iPlayableService.evStart: self.__serviceStarted
+                       })
+               self.__serviceStarted()
+
+       def __serviceStarted(self):
+               self.last_error = None
+               Notifications.RemovePopup(id = "ZapError")
+
+       def __tuneFailed(self):
+               service = self.session.nav.getCurrentService()
+               info = service and service.info()
+               error = info and info.getInfo(iServiceInformation.sDVBState)
+
+               if error == self.last_error:
+                       error = None
+               else:
+                       self.last_error = error
+
+               errors = {
+                       eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
+                       eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
+                       eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
+                       eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
+                       eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
+                       eDVBServicePMTHandler.eventNewProgramInfo: None,
+                       eDVBServicePMTHandler.eventTuned: None,
+                       eDVBServicePMTHandler.eventSOF: None,
+                       eDVBServicePMTHandler.eventEOF: None
+               }
+
+               error = errors.get(error) #this returns None when the key not exist in the dict
+
+               if error is not None:
+                       Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
+               else:
+                       Notifications.RemovePopup(id = "ZapError")