dont use onShown .. use onLayoutFinish for hide dish icon
[enigma2.git] / lib / python / Screens / InfoBarGenerics.py
index de12c093a7a01ac73605ab9f1429a356ec1fa906..1a8f88bba55d974a1dcd5b4ad8e47e3c4b480aa5 100644 (file)
@@ -10,20 +10,20 @@ from ChannelSelection import ChannelSelection, BouquetSelector
 from Components.Pixmap import Pixmap, PixmapConditional
 from Components.BlinkingPixmap import BlinkingPixmapConditional
 from Components.ServiceName import ServiceName
 from Components.Pixmap import Pixmap, PixmapConditional
 from Components.BlinkingPixmap import BlinkingPixmapConditional
 from Components.ServiceName import ServiceName
-from Components.EventInfo import EventInfo
+from Components.EventInfo import EventInfo, EventInfoProgress
 
 from ServiceReference import ServiceReference
 from EpgSelection import EPGSelection
 
 from Screens.MessageBox import MessageBox
 
 from ServiceReference import ServiceReference
 from EpgSelection import EPGSelection
 
 from Screens.MessageBox import MessageBox
-from Screens.Volume import Volume
-from Screens.Mute import Mute
 from Screens.Dish import Dish
 from Screens.Standby import Standby
 from Screens.Dish import Dish
 from Screens.Standby import Standby
-from Screens.EventView import EventView
+from Screens.EventView import EventViewEPGSelect
 from Screens.MinuteInput import MinuteInput
 from Components.Harddisk import harddiskmanager
 
 from Screens.MinuteInput import MinuteInput
 from Components.Harddisk import harddiskmanager
 
+from Components.ServiceEventTracker import ServiceEventTracker
+
 from Tools import Notifications
 from Tools.Directories import *
 
 from Tools import Notifications
 from Tools.Directories import *
 
@@ -38,68 +38,10 @@ from Components.config import config, currentConfigSelectionElement
 # hack alert!
 from Menu import MainMenu, mdom
 
 # hack alert!
 from Menu import MainMenu, mdom
 
-class InfoBarVolumeControl:
-       """Volume control, handles volUp, volDown, volMute actions and display 
-       a corresponding dialog"""
-       def __init__(self):
-               config.audio = ConfigSubsection()
-               config.audio.volume = configElement("config.audio.volume", configSequence, [100], configsequencearg.get("INTEGER", (0, 100)))
-
-               self["VolumeActions"] = ActionMap( ["InfobarVolumeActions"] ,
-                       {
-                               "volumeUp": self.volUp,
-                               "volumeDown": self.volDown,
-                               "volumeMute": self.volMute,
-                       })
-
-               self.volumeDialog = self.session.instantiateDialog(Volume)
-               self.muteDialog = self.session.instantiateDialog(Mute)
-
-               self.hideVolTimer = eTimer()
-               self.hideVolTimer.timeout.get().append(self.volHide)
-
-               vol = config.audio.volume.value[0]
-               self.volumeDialog.setValue(vol)
-               eDVBVolumecontrol.getInstance().setVolume(vol, vol)
-       
-       def volSave(self):
-               config.audio.volume.value = eDVBVolumecontrol.getInstance().getVolume()
-               config.audio.volume.save()
-               
-       def     volUp(self):
-               if (eDVBVolumecontrol.getInstance().isMuted()):
-                       self.volMute()
-               eDVBVolumecontrol.getInstance().volumeUp()
-               self.volumeDialog.instance.show()
-               self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
-               self.volSave()
-               self.hideVolTimer.start(3000, True)
-
-       def     volDown(self):
-               if (eDVBVolumecontrol.getInstance().isMuted()):
-                       self.volMute()
-               eDVBVolumecontrol.getInstance().volumeDown()
-               self.volumeDialog.instance.show()
-               self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
-               self.volSave()
-               self.hideVolTimer.start(3000, True)
-               
-       def volHide(self):
-               self.volumeDialog.instance.hide()
-
-       def     volMute(self):
-               eDVBVolumecontrol.getInstance().volumeToggleMute()
-               self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
-               
-               if (eDVBVolumecontrol.getInstance().isMuted()):
-                       self.muteDialog.instance.show()
-               else:
-                       self.muteDialog.instance.hide()
-
 class InfoBarDish:
        def __init__(self):
                self.dishDialog = self.session.instantiateDialog(Dish)
 class InfoBarDish:
        def __init__(self):
                self.dishDialog = self.session.instantiateDialog(Dish)
-               self.onShown.append(self.dishDialog.instance.hide)
+               self.onLayoutFinish.append(self.dishDialog.show)
 
 class InfoBarShowHide:
        """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
 
 class InfoBarShowHide:
        """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
@@ -116,49 +58,63 @@ class InfoBarShowHide:
                                "hide": self.hide,
                        })
 
                                "hide": self.hide,
                        })
 
-               self.state = self.STATE_SHOWN
+               self.__state = self.STATE_SHOWN
+               self.__locked = 0
                
                self.onExecBegin.append(self.show)
                
                self.onExecBegin.append(self.show)
-               self.onClose.append(self.delHideTimer)
                
                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)
 
 
-       def delHideTimer(self):
-               del self.hideTimer
+       def __onShow(self):
+               self.__state = self.STATE_SHOWN
+               self.startHideTimer()
+       
+       def startHideTimer(self):
+               if self.__state == self.STATE_SHOWN and not self.__locked:
+                       self.hideTimer.start(5000, True)
 
 
-       def hide(self): 
-               self.instance.hide()
-               
-       def show(self):
-               self.state = self.STATE_SHOWN
-               self.hideTimer.start(5000, True)
+       def __onHide(self):
+               self.__state = self.STATE_HIDDEN
+
+       def doShow(self):
+               self.show()
+               self.startHideTimer()
 
        def doTimerHide(self):
                self.hideTimer.stop()
 
        def doTimerHide(self):
                self.hideTimer.stop()
-               if self.state == self.STATE_SHOWN:
-                       self.instance.hide()
-                       self.state = self.STATE_HIDDEN
+               if self.__state == self.STATE_SHOWN:
+                       self.hide()
 
        def toggleShow(self):
 
        def toggleShow(self):
-               if self.state == self.STATE_SHOWN:
-                       self.instance.hide()
-                       #pls check animation support, sorry
-#                      self.startHide()
+               if self.__state == self.STATE_SHOWN:
+                       self.hide()
                        self.hideTimer.stop()
                        self.hideTimer.stop()
-                       self.state = self.STATE_HIDDEN
-               elif self.state == self.STATE_HIDDEN:
-                       self.instance.show()
+               elif self.__state == self.STATE_HIDDEN:
                        self.show()
                        self.show()
-                       
-       def startShow(self):
-               self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
-               self.state = self.STATE_SHOWN
+
+       def lockShow(self):
+               self.__locked = self.__locked + 1
+               if self.execing:
+                       self.show()
+                       self.hideTimer.stop()
        
        
-       def startHide(self):
-               self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
-               self.state = self.STATE_HIDDEN
+       def unlockShow(self):
+               self.__locked = self.__locked - 1
+               if self.execing:
+                       self.startHideTimer()
+
+#      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
 
 class NumberZap(Screen):
        def quit(self):
 
 class NumberZap(Screen):
        def quit(self):
@@ -242,7 +198,7 @@ class InfoBarPowerKey:
 class InfoBarNumberZap:
        """ Handles an initial number for NumberZapping """
        def __init__(self):
 class InfoBarNumberZap:
        """ Handles an initial number for NumberZapping """
        def __init__(self):
-               self["NumberZapActions"] = NumberActionMap( [ "NumberZapActions"],
+               self["NumberActions"] = NumberActionMap( [ "NumberActions"],
                        {
                                "1": self.keyNumberGlobal,
                                "2": self.keyNumberGlobal,
                        {
                                "1": self.keyNumberGlobal,
                                "2": self.keyNumberGlobal,
@@ -259,9 +215,8 @@ class InfoBarNumberZap:
        def keyNumberGlobal(self, number):
 #              print "You pressed number " + str(number)
                if number == 0:
        def keyNumberGlobal(self, number):
 #              print "You pressed number " + str(number)
                if number == 0:
-                       self.session.nav.zapLast()
-                       self.instance.show()
-                       self.show()
+                       self.servicelist.recallPrevService()
+                       self.doShow()
                else:
                        self.session.openWithCallback(self.numberEntered, NumberZap, number)
 
                else:
                        self.session.openWithCallback(self.numberEntered, NumberZap, number)
 
@@ -297,14 +252,17 @@ class InfoBarNumberZap:
                                        bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
                                        if not bouquet.valid(): #check end of list
                                                break
                                        bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
                                        if not bouquet.valid(): #check end of list
                                                break
-                                       if ((bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory):
+                                       if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
                                                continue
                                        service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
                if not service is None:
                                                continue
                                        service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
                if not service is None:
-                       self.session.nav.playService(service) #play service
                        if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
                        if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
-                               self.servicelist.setRoot(bouquet)
+                               self.servicelist.clearPath()
+                               if self.servicelist.bouquet_root != bouquet:
+                                       self.servicelist.enterPath(self.servicelist.bouquet_root)
+                               self.servicelist.enterPath(bouquet)
                        self.servicelist.setCurrentSelection(service) #select the service in servicelist
                        self.servicelist.setCurrentSelection(service) #select the service in servicelist
+                       self.servicelist.zap()
 
 class InfoBarChannelSelection:
        """ ChannelSelection - handles the channelSelection dialog and the initial 
 
 class InfoBarChannelSelection:
        """ ChannelSelection - handles the channelSelection dialog and the initial 
@@ -320,27 +278,31 @@ class InfoBarChannelSelection:
                                "zapUp": (self.zapUp, _("next channel")),
                                "zapDown": (self.zapDown, _("previous channel")),
                        })
                                "zapUp": (self.zapUp, _("next channel")),
                                "zapDown": (self.zapDown, _("previous channel")),
                        })
-                       
-       def switchChannelUp(self):      
+
+       def switchChannelUp(self):
                self.servicelist.moveUp()
                self.session.execDialog(self.servicelist)
 
                self.servicelist.moveUp()
                self.session.execDialog(self.servicelist)
 
-       def switchChannelDown(self):    
+       def switchChannelDown(self):
                self.servicelist.moveDown()
                self.session.execDialog(self.servicelist)
 
                self.servicelist.moveDown()
                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()
                self.servicelist.zap()
                self.servicelist.moveUp()
                self.servicelist.zap()
-               self.instance.show()
-               self.show()
+               self.doShow()
 
 
-       def     zapDown(self):
-               self.servicelist.moveDown()
+       def zapDown(self):
+               if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
+                       self.servicelist.nextBouquet()
+               else:
+                       self.servicelist.moveDown()
                self.servicelist.zap()
                self.servicelist.zap()
-               self.instance.show()
-               self.show()
-               
+               self.doShow()
+
 class InfoBarMenu:
        """ Handles a menu action, to open the (main) menu """
        def __init__(self):
 class InfoBarMenu:
        """ Handles a menu action, to open the (main) menu """
        def __init__(self):
@@ -360,61 +322,19 @@ class InfoBarEPG:
        def __init__(self):
                self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions", 
                        {
        def __init__(self):
                self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions", 
                        {
-                               "showEPGList": (self.showEPG, _("show EPG...")),
+                               "showEventInfo": (self.openEventView, _("show EPG...")),
                        })
 
                        })
 
-       def showEPG(self):
-               if currentConfigSelectionElement(config.usage.epgtoggle) == "yes":
-                       self.openSingleServiceEPG()
-               else:
-                       self.showEPGList()
-
-       def showEPGList(self):
-               bouquets = self.servicelist.getBouquetList()
-               if bouquets is None:
-                       cnt = 0
-               else:
-                       cnt = len(bouquets)
-               if cnt > 1: # show bouquet list
-                       self.session.open(BouquetSelector, bouquets, self.openBouquetEPG)
-               elif cnt == 1: # add to only one existing bouquet
-                       self.openBouquetEPG(bouquets[0][1])
-               else: #no bouquets so we open single epg
-                       self.openSingleEPGSelector(self.session.nav.getCurrentlyPlayingServiceReference())
-
-       def bouquetEPGCallback(self, info):
-               if info:
-                       self.openSingleServiceEPG()
-       
-       def singleEPGCallback(self, info):
-               if info:
-                       self.showEPGList()
-                       
-       def openEventView(self):
-               try:
-                       self.epglist = [ ]
-                       service = self.session.nav.getCurrentService()
-                       info = service.info()
-                       ptr=info.getEvent(0)
-                       if ptr:
-                               self.epglist.append(ptr)
-                       ptr=info.getEvent(1)
-                       if ptr:
-                               self.epglist.append(ptr)
-                       if len(self.epglist) > 0:
-                               self.session.open(EventView, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
-               except:
-                       pass
-                       
-       def openSingleServiceEPG(self):
-               ref=self.session.nav.getCurrentlyPlayingServiceReference()
-               ptr=eEPGCache.getInstance()
-               if ptr.startTimeQuery(ref) != -1:
-                       self.session.openWithCallback(self.singleEPGCallback, EPGSelection, ref)
-               else: # try to show now/next
-                       print 'no epg for service', ref.toString()
+       def zapToService(self, service):
+               if not service is None:
+                       if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
+                               self.servicelist.clearPath()
+                               if self.servicelist.bouquet_root != self.epg_bouquet:
+                                       self.servicelist.enterPath(self.servicelist.bouquet_root)
+                               self.servicelist.enterPath(self.epg_bouquet)
+                       self.servicelist.setCurrentSelection(service) #select the service in servicelist
+                       self.servicelist.zap()
 
 
-       
        def openBouquetEPG(self, bouquet):
                ptr=eEPGCache.getInstance()
                services = [ ]
        def openBouquetEPG(self, bouquet):
                ptr=eEPGCache.getInstance()
                services = [ ]
@@ -428,28 +348,53 @@ class InfoBarEPG:
                                        continue
                                services.append(ServiceReference(service))
                if len(services):
                                        continue
                                services.append(ServiceReference(service))
                if len(services):
-                       self.session.openWithCallback(self.bouquetEPGCallback, EPGSelection, services)
+                       self.epg_bouquet = bouquet
+                       self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService)
+
+       def closed(self, ret):
+               if ret:
+                       self.close(ret)
+
+       def openMultiServiceEPG(self):
+               bouquets = self.servicelist.getBouquetList()
+               if bouquets is None:
+                       cnt = 0
+               else:
+                       cnt = len(bouquets)
+               if cnt > 1: # show bouquet list
+                       self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG)
+               elif cnt == 1: 
+                       self.openBouquetEPG(bouquets[0][1])
 
 
-       def openSingleEPGSelector(self, ref):
+       def openSingleServiceEPG(self):
+               ref=self.session.nav.getCurrentlyPlayingServiceReference()
                ptr=eEPGCache.getInstance()
                ptr=eEPGCache.getInstance()
-               if ptr.startTimeQuery(ref) != -1:
-                       self.session.open(EPGSelection, ref)
-               else: # try to show now/next
-                       print 'no epg for service', ref.toString()
-                       try:
-                               self.epglist = [ ]
-                               service = self.session.nav.getCurrentService()
-                               info = service.info()
-                               ptr=info.getEvent(0)
-                               if ptr:
-                                       self.epglist.append(ptr)
-                               ptr=info.getEvent(1)
+               self.session.openWithCallback(self.closed, EPGSelection, ref)
+
+       def openEventView(self):
+               self.epglist = [ ]
+               service = self.session.nav.getCurrentService()
+               ref = self.session.nav.getCurrentlyPlayingServiceReference()
+               info = service.info()
+               ptr=info.getEvent(0)
+               if ptr:
+                       self.epglist.append(ptr)
+               ptr=info.getEvent(1)
+               if ptr:
+                       self.epglist.append(ptr)
+               if len(self.epglist) == 0:
+                       epg = eEPGCache.getInstance()
+                       ptr = epg.lookupEventTime(ref, -1)
+                       if ptr:
+                               self.epglist.append(ptr)
+                               ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
                                if ptr:
                                        self.epglist.append(ptr)
                                if ptr:
                                        self.epglist.append(ptr)
-                               if len(self.epglist) > 0:
-                                       self.session.open(EventView, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
-                       except:
-                               pass
+               if len(self.epglist) > 0:
+                       self.session.open(EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG)
+               else:
+                       print "no epg for the service avail.. so we show multiepg instead of eventinfo"
+                       self.openMultiServiceEPG()
 
        def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
                if len(self.epglist) > 1:
 
        def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
                if len(self.epglist) > 1:
@@ -514,6 +459,8 @@ class InfoBarEvent:
                self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Duration)
                self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
 
                self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Duration)
                self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
 
+               self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
+
 class InfoBarServiceName:
        def __init__(self):
                self["ServiceName"] = ServiceName(self.session.nav)
 class InfoBarServiceName:
        def __init__(self):
                self["ServiceName"] = ServiceName(self.session.nav)
@@ -521,26 +468,34 @@ class InfoBarServiceName:
 class InfoBarSeek:
        """handles actions like seeking, pause"""
        
 class InfoBarSeek:
        """handles actions like seeking, pause"""
        
-       # ispause, isff, issm, skip
-       SEEK_STATE_PLAY = (0, 0, 0, 0)
-       SEEK_STATE_PAUSE = (1, 0, 0, 0)
-       SEEK_STATE_FF_2X = (0, 2, 0, 0)
-       SEEK_STATE_FF_4X = (0, 4, 0, 0)
-       SEEK_STATE_FF_8X = (0, 8, 0, 0)
-       SEEK_STATE_FF_32X = (0, 4, 0, 32)
-       SEEK_STATE_FF_64X = (0, 4, 0, 64)
-       SEEK_STATE_FF_128X = (0, 4, 0, 128)
+       # ispause, isff, issm
+       SEEK_STATE_PLAY = (0, 0, 0, ">")
+       SEEK_STATE_PAUSE = (1, 0, 0, "||")
+       SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
+       SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
+       SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
+       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_4X = (0, 0, 0, -4)
-       SEEK_STATE_BACK_32X = (0, 0, 0, -32)
-       SEEK_STATE_BACK_64X = (0, 0, 0, -64)
-       SEEK_STATE_BACK_128X = (0, 0, 0, -128)
+       SEEK_STATE_BACK_4X = (0, -4, 0, "<< 4x")
+       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, 0)
-       SEEK_STATE_SM_QUARTER = (0, 0, 4, 0)
-       SEEK_STATE_SM_EIGHTH = (0, 0, 8, 0)
+       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):
        
        def __init__(self):
+               self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
+                       {
+                               iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
+                               iPlayableService.evStart: self.__serviceStarted,
+                               
+                               iPlayableService.evEOF: self.__evEOF,
+                               iPlayableService.evSOF: self.__evSOF,
+                       })
                self["SeekActions"] = HelpableActionMap(self, "InfobarSeekActions", 
                        {
                                "pauseService": (self.pauseService, "pause"),
                self["SeekActions"] = HelpableActionMap(self, "InfobarSeekActions", 
                        {
                                "pauseService": (self.pauseService, "pause"),
@@ -550,13 +505,11 @@ class InfoBarSeek:
                                "seekFwdUp": (self.seekFwdUp, "skip forward"),
                                "seekBack": (self.seekBack, "skip backward"),
                                "seekBackUp": (self.seekBackUp, "skip backward"),
                                "seekFwdUp": (self.seekFwdUp, "skip forward"),
                                "seekBack": (self.seekBack, "skip backward"),
                                "seekBackUp": (self.seekBackUp, "skip backward"),
-                       })
+                       }, prio=-1)
+                       # give them a little more priority to win over color buttons
 
                self.seekstate = self.SEEK_STATE_PLAY
 
                self.seekstate = self.SEEK_STATE_PLAY
-               self.seekTimer = eTimer()
-               self.seekTimer.timeout.get().append(self.seekTimerFired)
-               self.skipinterval = 500 # 500ms skip interval
-               self.onClose.append(self.delSeekTimer)
+               self.onClose.append(self.delTimer)
                
                self.fwdtimer = False
                self.fwdKeyTimer = eTimer()
                
                self.fwdtimer = False
                self.fwdKeyTimer = eTimer()
@@ -565,6 +518,10 @@ 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.lockedBecauseOfSkipping = False
        
        def up(self):
                pass
        
        def up(self):
                pass
@@ -572,73 +529,96 @@ class InfoBarSeek:
        def down(self):
                pass
        
        def down(self):
                pass
        
-       def delSeekTimer(self):
-               del self.seekTimer
+       def delTimer(self):
+               del self.fwdKeyTimer
+               del self.rwdKeyTimer
        
        
-       def seekTimerFired(self):
-               self.seekbase += self.skipmode * self.skipinterval
+       def getSeek(self):
+               service = self.session.nav.getCurrentService()
+               if service is None:
+                       return False
+
+               seek = service.seek()
+
+               if seek is None or not seek.isCurrentlySeekable():
+                       return None
                
                
-               # check if we bounced against the beginning of the file
-               if self.seekbase < 0:
-                       self.seekbase = 0;
+               return seek
+       
+       def isSeekable(self):
+               if self.getSeek() is None:
+                       return False
+               return True
+
+       def __seekableStatusChanged(self):
+               print "seekable status changed!"
+               if not self.isSeekable():
+                       self["SeekActions"].setEnabled(False)
+                       print "not seekable, return to play"
                        self.setSeekState(self.SEEK_STATE_PLAY)
                        self.setSeekState(self.SEEK_STATE_PLAY)
-                       
-               self.doSeek(self.seekbase)
+               else:
+                       self["SeekActions"].setEnabled(True)
+                       print "seekable"
 
 
-       def setSeekState(self, state):
-               oldstate = self.seekstate
-               
-               self.seekstate = state
+       def __serviceStarted(self):
+               self.seekstate = self.SEEK_STATE_PLAY
 
 
+       def setSeekState(self, state):
                service = self.session.nav.getCurrentService()
                service = self.session.nav.getCurrentService()
+               
                if service is None:
                if service is None:
-                       return
+                       return False
                
                
-               pauseable = service.pause()
+               if not self.isSeekable():
+                       if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
+                               state = self.SEEK_STATE_PLAY
                
                
-               for i in range(4):
-                       if oldstate[i] != self.seekstate[i]:
-                               (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion, self.setSkipMode)[i](self.seekstate[i])
+               pauseable = service.pause()
+
+               if pauseable is None:
+                       print "not pauseable."
+                       state = self.SEEK_STATE_PLAY
                
                
-       def setSkipMode(self, skipmode):
-               self.skipmode = skipmode
-               if skipmode == 0:
-                       self.seekTimer.stop()
-               else:
-                       self.seekTimer.start(500)
+               oldstate = self.seekstate
+               self.seekstate = state
                
                
-               service = self.session.nav.getCurrentService()
-               if service is None:
-                       return
+               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)
                
                
-               seekable = service.seek()
-               if seekable is None:
-                       return
+               self.checkSkipShowHideLock()
 
 
-               if skipmode:
-                       seekable.setTrickmode(1)
-               else:
-                       seekable.setTrickmode(0)
+               return True
                
                
-               self.seekbase = seekable.getPlayPosition()[1] / 90
-       
        def pauseService(self):
        def pauseService(self):
-               if (self.seekstate == self.SEEK_STATE_PAUSE):
+               if self.seekstate == self.SEEK_STATE_PAUSE:
+                       print "pause, but in fact unpause"
                        self.unPauseService()
                else:
                        self.unPauseService()
                else:
+                       if self.seekstate == self.SEEK_STATE_PLAY:
+                               print "yes, playing."
+                       else:
+                               print "no", self.seekstate
+                       print "pause"
                        self.setSeekState(self.SEEK_STATE_PAUSE);
                
        def unPauseService(self):
                        self.setSeekState(self.SEEK_STATE_PAUSE);
                
        def unPauseService(self):
+               print "unpause"
                self.setSeekState(self.SEEK_STATE_PLAY);
        
        def doSeek(self, seektime):
                self.setSeekState(self.SEEK_STATE_PLAY);
        
        def doSeek(self, seektime):
+               print "doseek", seektime
                service = self.session.nav.getCurrentService()
                if service is None:
                        return
                
                service = self.session.nav.getCurrentService()
                if service is None:
                        return
                
-               seekable = service.seek()
+               seekable = self.getSeek()
                if seekable is None:
                        return
                if seekable is None:
                        return
+               
                seekable.seekTo(90 * seektime)
 
        def seekFwd(self):
                seekable.seekTo(90 * seektime)
 
        def seekFwd(self):
@@ -652,6 +632,7 @@ class InfoBarSeek:
                self.rwdKeyTimer.start(500)
 
        def seekFwdUp(self):
                self.rwdKeyTimer.start(500)
 
        def seekFwdUp(self):
+               print "seekFwdUp"
                if self.fwdtimer:
                        self.fwdKeyTimer.stop()
                        self.fwdtimer = False
                if self.fwdtimer:
                        self.fwdKeyTimer.stop()
                        self.fwdtimer = False
@@ -675,6 +656,7 @@ class InfoBarSeek:
                        self.setSeekState(lookup[self.seekstate]);
        
        def seekBackUp(self):
                        self.setSeekState(lookup[self.seekstate]);
        
        def seekBackUp(self):
+               print "seekBackUp"
                if self.rwdtimer:
                        self.rwdKeyTimer.stop()
                        self.rwdtimer = False
                if self.rwdtimer:
                        self.rwdKeyTimer.stop()
                        self.rwdtimer = False
@@ -707,27 +689,66 @@ class InfoBarSeek:
        def fwdSeekTo(self, minutes):
                print "Seek", minutes, "minutes forward"
                if minutes != 0:
        def fwdSeekTo(self, minutes):
                print "Seek", minutes, "minutes forward"
                if minutes != 0:
-                       service = self.session.nav.getCurrentService()
-                       if service is None:
-                               return
-                       seekable = service.seek()
-                       if seekable is None:
-                               return
-                       seekable.seekRelative(1, minutes * 60 * 90000)
+                       seekable = self.getSeek()
+                       if seekable is not None:
+                               seekable.seekRelative(1, minutes * 60 * 90000)
        
        def rwdTimerFire(self):
        
        def rwdTimerFire(self):
+               print "rwdTimerFire"
                self.rwdKeyTimer.stop()
                self.rwdtimer = False
                self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
        
        def rwdSeekTo(self, minutes):
                self.rwdKeyTimer.stop()
                self.rwdtimer = False
                self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
        
        def rwdSeekTo(self, minutes):
+               print "rwdSeekTo"
                self.fwdSeekTo(0 - minutes)
                self.fwdSeekTo(0 - minutes)
+       
+       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
+
+       def __evEOF(self):
+               self.setSeekState(self.SEEK_STATE_PAUSE)
+       
+       def __evSOF(self):
+               self.setSeekState(self.SEEK_STATE_PLAY)
+               self.doSeek(0)
+
+       def seekRelative(self, diff):
+               seekable = self.getSeek()
+               if seekable is not None:
+                       seekable.seekRelative(0, diff)
+
+from Screens.PVRState import PVRState
+
+class InfoBarPVRState:
+       def __init__(self):
+               self.onPlayStateChanged.append(self.__playStateChanged)
+               self.pvrStateDialog = self.session.instantiateDialog(PVRState)
+               self.onShow.append(self.__mayShow)
+               self.onHide.append(self.pvrStateDialog.hide)
+       
+       def __mayShow(self):
+               if self.seekstate != self.SEEK_STATE_PLAY:
+                       self.pvrStateDialog.show()
+
+       def __playStateChanged(self, state):
+               playstateString = state[3]
+               self.pvrStateDialog["state"].setText(playstateString)
+               self.__mayShow()
 
 class InfoBarShowMovies:
 
        # i don't really like this class. 
        # it calls a not further specified "movie list" on up/down/movieList,
 
 class InfoBarShowMovies:
 
        # i don't really like this class. 
        # it calls a not further specified "movie list" on up/down/movieList,
-       # so this is not moe than an action map
+       # so this is not more than an action map
        def __init__(self):
                self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions", 
                        {
        def __init__(self):
                self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions", 
                        {
@@ -736,45 +757,151 @@ class InfoBarShowMovies:
                                "down": (self.showMovies, "movie list")
                        })
 
                                "down": (self.showMovies, "movie list")
                        })
 
+# InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
+
+# Hrmf.
+#
+# 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 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 backwards                        FILE     record      BACK  # !!         enable                disable              enable
+#
+
+# in other words:
+# - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
+# freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
+# now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
+# - the user can now PVR around
+# - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
+# the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
+# after!
+# the seek actions will be disabled, but the timeshiftActivateActions will be enabled
+# - if the user rewinds, or press pause, timeshift will be activated again
+
+# note that a timeshift can be enabled ("recording") and
+# activated (currently time-shifting).
+
 class InfoBarTimeshift:
        def __init__(self):
                self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions", 
                        {
 class InfoBarTimeshift:
        def __init__(self):
                self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions", 
                        {
-                               "timeshiftStart": (self.startTimeshift, "start timeshift "),
-                               "timeshiftStop": (self.stopTimeshift, "stop timeshift")
+                               "timeshiftStart": (self.startTimeshift, "start timeshift"),  # the "yellow key"
+                               "timeshiftStop": (self.stopTimeshift, "stop timeshift")      # currently undefined :), probably 'TV'
+                       }, prio=1)
+               self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
+                       {
+                               "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
+                               "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause  # something like "backward key"
+                       }, 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.__event_tracker = ServiceEventTracker(screen=self, eventmap=
+                       {
+                               iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
                        })
                        })
-               self.tshack = 0
        
        def getTimeshift(self):
                service = self.session.nav.getCurrentService()
                return service.timeshift()
 
        def startTimeshift(self):
        
        def getTimeshift(self):
                service = self.session.nav.getCurrentService()
                return service.timeshift()
 
        def startTimeshift(self):
-               # TODO: check for harddisk! (or do this in the interface? would make
-               # more sense... for example radio could be timeshifted in memory,
-               # and the decision can't be made here)
                print "enable timeshift"
                ts = self.getTimeshift()
                if ts is None:
                        self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
                        print "no ts interface"
                        return
                print "enable timeshift"
                ts = self.getTimeshift()
                if ts is None:
                        self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
                        print "no ts interface"
                        return
-               print "ok, timeshift enabled"
-               if self.tshack == 0:
-                       ts.startTimeshift()
-                       self.tshack = 1
+               
+               if self.timeshift_enabled:
+                       print "hu, timeshift already enabled?"
                else:
                else:
-                       pauseable = self.session.nav.getCurrentService().pause()
-                       pauseable.pause() # switch to record
+                       if not ts.startTimeshift():
+                               self.timeshift_enabled = 1
+                               
+                               # PAUSE.
+                               self.setSeekState(self.SEEK_STATE_PAUSE)
+                               
+                               # enable the "TimeshiftEnableActions", which will override
+                               # the startTimeshift actions
+                               self.__seekableStatusChanged()
+                       else:
+                               print "timeshift failed"
 
        def stopTimeshift(self):
                print "disable timeshift"
                ts = self.getTimeshift()
                if ts is None:
                        return
 
        def stopTimeshift(self):
                print "disable timeshift"
                ts = self.getTimeshift()
                if ts is None:
                        return
+               self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
+
+       def stopTimeshiftConfirmed(self, confirmed):
+               if not confirmed:
+                       return
+
+               ts = self.getTimeshift()
+               if ts is None:
+                       return
+
                ts.stopTimeshift()
                ts.stopTimeshift()
-               self.tshack = 0
+               self.timeshift_enabled = 0
+
+               # disable actions
+               self.__seekableStatusChanged()
+       
+       # activates timeshift, and seeks to (almost) the end
+       def activateTimeshiftEnd(self):
+               ts = self.getTimeshift()
+               
+               if ts is None:
+                       return
+               
+               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)
+       
+       # 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()
+       
+       def __seekableStatusChanged(self):
+               enabled = False
+               
+               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
+               if not self.isSeekable() and self.timeshift_enabled:
+                       enabled = True
+
+               print "timeshift activate:", enabled
+               self["TimeshiftActivateActions"].setEnabled(enabled)
 
 from RecordTimer import parseEvent
 
 
 from RecordTimer import parseEvent
 
@@ -787,15 +914,14 @@ class InfoBarInstantRecord:
                                "instantRecord": (self.instantRecord, "Instant Record..."),
                        })
                self.recording = None
                                "instantRecord": (self.instantRecord, "Instant Record..."),
                        })
                self.recording = None
-               
                self["BlinkingPoint"] = BlinkingPixmapConditional()
                self["BlinkingPoint"] = BlinkingPixmapConditional()
-               self.onShown.append(self["BlinkingPoint"].hideWidget)
+               self.onLayoutFinish.append(self["BlinkingPoint"].hideWidget)
                self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
                self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
-               
+
        def stopCurrentRecording(self): 
                self.session.nav.RecordTimer.removeEntry(self.recording)
                self.recording = None
        def stopCurrentRecording(self): 
                self.session.nav.RecordTimer.removeEntry(self.recording)
                self.recording = None
-                       
+
        def startInstantRecording(self):
                serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
                
        def startInstantRecording(self):
                serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
                
@@ -811,15 +937,8 @@ class InfoBarInstantRecord:
                
                if event is not None:
                        data = parseEvent(event)
                
                if event is not None:
                        data = parseEvent(event)
-                       begin = data[0]
-                       if begin < time.time():
-                               begin = time.time()
-                       
-                       end = data[1]
-                       if end < begin:
-                               end = begin
-                       
-                       end += 3600 * 10
+                       begin = time.time()
+                       end = begin + 3600 * 10
                        
                        data = (begin, end, data[2], data[3], data[4])
                else:
                        
                        data = (begin, end, data[2], data[3], data[4])
                else:
@@ -968,13 +1087,13 @@ class InfoBarAdditionalInfo:
 
        def gotServiceEvent(self, ev):
                service = self.session.nav.getCurrentService()
 
        def gotServiceEvent(self, ev):
                service = self.session.nav.getCurrentService()
-               if ev == pNavigation.evUpdatedEventInfo:
+               if ev == iPlayableService.evUpdatedEventInfo:
                        self.checkSubservices(service)
                        self.checkFormat(service)
                        self.checkSubservices(service)
                        self.checkFormat(service)
-               elif ev == pNavigation.evUpdatedInfo:
+               elif ev == iPlayableService.evUpdatedInfo:
                        self.checkCrypted(service)
                        self.checkDolby(service)
                        self.checkCrypted(service)
                        self.checkDolby(service)
-               elif ev == pNavigation.evStopService:
+               elif ev == iPlayableService.evEnd:
                        self.hideSubServiceIndication()
                        self["CryptActive"].hideWidget()
                        self["DolbyActive"].hideWidget()
                        self.hideSubServiceIndication()
                        self["CryptActive"].hideWidget()
                        self["DolbyActive"].hideWidget()
@@ -999,3 +1118,18 @@ class InfoBarNotifications:
                                self.session.openWithCallback(cb, *n[1:])
                        else:
                                self.session.open(*n[1:])
                                self.session.openWithCallback(cb, *n[1:])
                        else:
                                self.session.open(*n[1:])
+
+class InfoBarServiceNotifications:
+       def __init__(self):
+               self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
+                       {
+                               iPlayableService.evEnd: self.serviceHasEnded
+                       })
+
+       def serviceHasEnded(self):
+               print "service end!"
+
+               try:
+                       self.setSeekState(self.SEEK_STATE_PLAY)
+               except:
+                       pass