InfoBarGenerics.py: rename timer to fix automatic infobar hide after channel change
[enigma2.git] / lib / python / Screens / InfoBarGenerics.py
index 3f9fe213734e25cb1321683824ff7188feffebfb..6dd80533d06d55fd32d399e87d8963e49d8b7218 100644 (file)
@@ -10,6 +10,7 @@ from Components.ServiceEventTracker import ServiceEventTracker
 from Components.Sources.Boolean import Boolean
 from Components.config import config, ConfigBoolean, ConfigClock
 from Components.SystemInfo import SystemInfo
 from Components.Sources.Boolean import Boolean
 from Components.config import config, ConfigBoolean, ConfigClock
 from Components.SystemInfo import SystemInfo
+from Components.UsageConfig import preferredInstantRecordPath, defaultMoviePath
 from EpgSelection import EPGSelection
 from Plugins.Plugin import PluginDescriptor
 
 from EpgSelection import EPGSelection
 from Plugins.Plugin import PluginDescriptor
 
@@ -24,15 +25,15 @@ from Screens.TimerSelection import TimerSelection
 from Screens.PictureInPicture import PictureInPicture
 from Screens.SubtitleDisplay import SubtitleDisplay
 from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive
 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 Screens.TimeDateInput import TimeDateInput
+from Screens.UnhandledKey import UnhandledKey
 from ServiceReference import ServiceReference
 
 from Tools import Notifications
 from ServiceReference import ServiceReference
 
 from Tools import Notifications
-from Tools.Directories import SCOPE_HDD, resolveFilename, fileExists
+from Tools.Directories import fileExists
 
 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
 
 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
-       iPlayableService, eServiceReference, eEPGCache
+       iPlayableService, eServiceReference, eEPGCache, eActionMap
 
 from time import time, localtime, strftime
 from os import stat as os_stat
 
 from time import time, localtime, strftime
 from os import stat as os_stat
@@ -47,6 +48,39 @@ class InfoBarDish:
        def __init__(self):
                self.dishDialog = self.session.instantiateDialog(Dish)
 
        def __init__(self):
                self.dishDialog = self.session.instantiateDialog(Dish)
 
+class InfoBarUnhandledKey:
+       def __init__(self):
+               self.unhandledKeyDialog = self.session.instantiateDialog(UnhandledKey)
+               self.hideUnhandledKeySymbolTimer = eTimer()
+               self.hideUnhandledKeySymbolTimer.callback.append(self.unhandledKeyDialog.hide)
+               self.checkUnusedTimer = eTimer()
+               self.checkUnusedTimer.callback.append(self.checkUnused)
+               self.onLayoutFinish.append(self.unhandledKeyDialog.hide)
+               eActionMap.getInstance().bindAction('', -0x7FFFFFFF, self.actionA) #highest prio
+               eActionMap.getInstance().bindAction('', 0x7FFFFFFF, self.actionB) #lowest prio
+               self.flags = (1<<1);
+               self.uflags = 0;
+
+       #this function is called on every keypress!
+       def actionA(self, key, flag):
+               if flag != 4:
+                       if self.flags & (1<<1):
+                               self.flags = self.uflags = 0
+                       self.flags |= (1<<flag)
+                       if flag == 1: # break
+                               self.checkUnusedTimer.start(0, True)
+               return 0
+
+       #this function is only called when no other action has handled this key
+       def actionB(self, key, flag):
+               if flag != 4:
+                       self.uflags |= (1<<flag)
+
+       def checkUnused(self):
+               if self.flags == self.uflags:
+                       self.unhandledKeyDialog.show()
+                       self.hideUnhandledKeySymbolTimer.start(2000, True)
+
 class InfoBarShowHide:
        """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
        fancy animations. """
 class InfoBarShowHide:
        """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
        fancy animations. """
@@ -366,28 +400,77 @@ class InfoBarSimpleEventView:
                self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
                        {
                                "showEventInfo": (self.openEventView, _("show event details")),
                self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
                        {
                                "showEventInfo": (self.openEventView, _("show event details")),
+                               "showInfobarOrEpgWhenInfobarAlreadyVisible": self.showEventInfoWhenNotVisible,
                        })
 
                        })
 
+       def showEventInfoWhenNotVisible(self):
+               if self.shown:
+                       self.openEventView()
+               else:
+                       self.toggleShow()
+                       return 1
+
        def openEventView(self):
        def openEventView(self):
-               self.epglist = [ ]
+               epglist = [ ]
+               self.epglist = epglist
                service = self.session.nav.getCurrentService()
                ref = self.session.nav.getCurrentlyPlayingServiceReference()
                info = service.info()
                ptr=info.getEvent(0)
                if ptr:
                service = self.session.nav.getCurrentService()
                ref = self.session.nav.getCurrentlyPlayingServiceReference()
                info = service.info()
                ptr=info.getEvent(0)
                if ptr:
-                       self.epglist.append(ptr)
+                       epglist.append(ptr)
                ptr=info.getEvent(1)
                if ptr:
                ptr=info.getEvent(1)
                if ptr:
-                       self.epglist.append(ptr)
-               if len(self.epglist) > 0:
-                       self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
+                       epglist.append(ptr)
+               if epglist:
+                       self.session.open(EventViewSimple, epglist[0], ServiceReference(ref), self.eventViewCallback)
 
        def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
 
        def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
-               if len(self.epglist) > 1:
-                       tmp = self.epglist[0]
-                       self.epglist[0]=self.epglist[1]
-                       self.epglist[1]=tmp
-                       setEvent(self.epglist[0])
+               epglist = self.epglist
+               if len(epglist) > 1:
+                       tmp = epglist[0]
+                       epglist[0] = epglist[1]
+                       epglist[1] = tmp
+                       setEvent(epglist[0])
+
+class SimpleServicelist:
+       def __init__(self, services):
+               self.services = services
+               self.length = len(services)
+               self.current = 0
+
+       def selectService(self, service):
+               if not self.length:
+                       self.current = -1
+                       return False
+               else:
+                       self.current = 0
+                       while self.services[self.current].ref != service:
+                               self.current += 1
+                               if self.current >= self.length:
+                                       return False
+               return True
+
+       def nextService(self):
+               if not self.length:
+                       return
+               if self.current+1 < self.length:
+                       self.current += 1
+               else:
+                       self.current = 0
+
+       def prevService(self):
+               if not self.length:
+                       return
+               if self.current-1 > -1:
+                       self.current -= 1
+               else:
+                       self.current = self.length - 1
+
+       def currentService(self):
+               if not self.length or self.current >= self.length:
+                       return None
+               return self.services[self.current]
 
 class InfoBarEPG:
        """ EPG - Opens an EPG list when the showEPGList action fires """
 
 class InfoBarEPG:
        """ EPG - Opens an EPG list when the showEPGList action fires """
@@ -440,7 +523,7 @@ class InfoBarEPG:
 
        def openBouquetEPG(self, bouquet, withCallback=True):
                services = self.getBouquetServices(bouquet)
 
        def openBouquetEPG(self, bouquet, withCallback=True):
                services = self.getBouquetServices(bouquet)
-               if len(services):
+               if services:
                        self.epg_bouquet = bouquet
                        if withCallback:
                                self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
                        self.epg_bouquet = bouquet
                        if withCallback:
                                self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
@@ -455,7 +538,7 @@ class InfoBarEPG:
                                self.bouquetSel.up()
                        bouquet = self.bouquetSel.getCurrent()
                        services = self.getBouquetServices(bouquet)
                                self.bouquetSel.up()
                        bouquet = self.bouquetSel.getCurrent()
                        services = self.getBouquetServices(bouquet)
-                       if len(services):
+                       if services:
                                self.epg_bouquet = bouquet
                                epg.setServices(services)
 
                                self.epg_bouquet = bouquet
                                epg.setServices(services)
 
@@ -485,19 +568,40 @@ class InfoBarEPG:
                elif cnt == 1:
                        self.openBouquetEPG(bouquets[0][1], withCallback)
 
                elif cnt == 1:
                        self.openBouquetEPG(bouquets[0][1], withCallback)
 
+       def changeServiceCB(self, direction, epg):
+               if self.serviceSel:
+                       if direction > 0:
+                               self.serviceSel.nextService()
+                       else:
+                               self.serviceSel.prevService()
+                       epg.setService(self.serviceSel.currentService())
+
+       def SingleServiceEPGClosed(self, ret=False):
+               self.serviceSel = None
+
        def openSingleServiceEPG(self):
                ref=self.session.nav.getCurrentlyPlayingServiceReference()
        def openSingleServiceEPG(self):
                ref=self.session.nav.getCurrentlyPlayingServiceReference()
-               self.session.open(EPGSelection, ref)
+               if ref:
+                       if self.servicelist.getMutableList() is not None: # bouquet in channellist
+                               current_path = self.servicelist.getRoot()
+                               services = self.getBouquetServices(current_path)
+                               self.serviceSel = SimpleServicelist(services)
+                               if self.serviceSel.selectService(ref):
+                                       self.session.openWithCallback(self.SingleServiceEPGClosed, EPGSelection, ref, serviceChangeCB = self.changeServiceCB)
+                               else:
+                                       self.session.openWithCallback(self.SingleServiceEPGClosed, EPGSelection, ref)
+                       else:
+                               self.session.open(EPGSelection, ref)
 
        def showEventInfoPlugins(self):
                list = [(p.name, boundFunction(self.runPlugin, p)) for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EVENTINFO)]
 
                if list:
                        list.append((_("show single service EPG..."), self.openSingleServiceEPG))
 
        def showEventInfoPlugins(self):
                list = [(p.name, boundFunction(self.runPlugin, p)) for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EVENTINFO)]
 
                if list:
                        list.append((_("show single service EPG..."), self.openSingleServiceEPG))
-                       self.session.openWithCallback(self.EventInfoPluginChosen, ChoiceBox, title=_("Please choose an extension..."), list = list)
+                       self.session.openWithCallback(self.EventInfoPluginChosen, ChoiceBox, title=_("Please choose an extension..."), list = list, skin_name = "EPGExtensionsList")
                else:
                        self.openSingleServiceEPG()
                else:
                        self.openSingleServiceEPG()
-                       
+
        def runPlugin(self, plugin):
                plugin(session = self.session, servicelist = self.servicelist)
                
        def runPlugin(self, plugin):
                plugin(session = self.session, servicelist = self.servicelist)
                
@@ -621,13 +725,6 @@ class InfoBarSeek:
                                iPlayableService.evEOF: self.__evEOF,
                                iPlayableService.evSOF: self.__evSOF,
                        })
                                iPlayableService.evEOF: self.__evEOF,
                                iPlayableService.evSOF: self.__evSOF,
                        })
-               self.eofState = 0
-               self.eofTimer = eTimer()
-               self.eofTimer.timeout.get().append(self.doEof)
-               self.eofInhibitTimer = eTimer()
-               self.eofInhibitTimer.timeout.get().append(self.inhibitEof)
-
-               self.minSpeedBackward = useSeekBackHack and 16 or 0
 
                class InfoBarSeekActionMap(HelpableActionMap):
                        def __init__(self, screen, *args, **kwargs):
 
                class InfoBarSeekActionMap(HelpableActionMap):
                        def __init__(self, screen, *args, **kwargs):
@@ -642,9 +739,9 @@ class InfoBarSeek:
                                        return 1
                                elif action[:8] == "seekdef:":
                                        key = int(action[8:])
                                        return 1
                                elif action[:8] == "seekdef:":
                                        key = int(action[8:])
-                                       time = [-config.seek.selfdefined_13.value, False, config.seek.selfdefined_13.value,
+                                       time = (-config.seek.selfdefined_13.value, False, config.seek.selfdefined_13.value,
                                                -config.seek.selfdefined_46.value, False, config.seek.selfdefined_46.value,
                                                -config.seek.selfdefined_46.value, False, config.seek.selfdefined_46.value,
-                                               -config.seek.selfdefined_79.value, False, config.seek.selfdefined_79.value][key-1]
+                                               -config.seek.selfdefined_79.value, False, config.seek.selfdefined_79.value)[key-1]
                                        self.screen.doSeekRelative(time * 90000)
                                        return 1                                        
                                else:
                                        self.screen.doSeekRelative(time * 90000)
                                        return 1                                        
                                else:
@@ -675,24 +772,19 @@ class InfoBarSeek:
                self.__seekableStatusChanged()
 
        def makeStateForward(self, n):
                self.__seekableStatusChanged()
 
        def makeStateForward(self, n):
-               minspeed = config.seek.stepwise_minspeed.value
-               repeat = int(config.seek.stepwise_repeat.value)
-               if minspeed != "Never" and n >= int(minspeed) and repeat > 1:
-                       return (0, n * repeat, repeat, ">> %dx" % n)
-               else:
+#              minspeed = config.seek.stepwise_minspeed.value
+#              repeat = int(config.seek.stepwise_repeat.value)
+#              if minspeed != "Never" and n >= int(minspeed) and repeat > 1:
+#                      return (0, n * repeat, repeat, ">> %dx" % n)
+#              else:
                        return (0, n, 0, ">> %dx" % n)
 
        def makeStateBackward(self, n):
                        return (0, n, 0, ">> %dx" % n)
 
        def makeStateBackward(self, n):
-               minspeed = config.seek.stepwise_minspeed.value
-               repeat = int(config.seek.stepwise_repeat.value)
-               if self.minSpeedBackward and n < self.minSpeedBackward:
-                       r = (self.minSpeedBackward - 1)/ n + 1
-                       if minspeed != "Never" and n >= int(minspeed) and repeat > 1:
-                               r = max(r, repeat)
-                       return (0, -n * r, r, "<< %dx" % n)
-               elif minspeed != "Never" and n >= int(minspeed) and repeat > 1:
-                       return (0, -n * repeat, repeat, "<< %dx" % n)
-               else:
+#              minspeed = config.seek.stepwise_minspeed.value
+#              repeat = int(config.seek.stepwise_repeat.value)
+#              if minspeed != "Never" and n >= int(minspeed) and repeat > 1:
+#                      return (0, -n * repeat, repeat, "<< %dx" % n)
+#              else:
                        return (0, -n, 0, "<< %dx" % n)
 
        def makeStateSlowMotion(self, n):
                        return (0, -n, 0, "<< %dx" % n)
 
        def makeStateSlowMotion(self, n):
@@ -761,9 +853,6 @@ class InfoBarSeek:
        def __serviceStarted(self):
                self.seekstate = self.SEEK_STATE_PLAY
                self.__seekableStatusChanged()
        def __serviceStarted(self):
                self.seekstate = self.SEEK_STATE_PLAY
                self.__seekableStatusChanged()
-               if self.eofState != 0:
-                       self.eofTimer.stop()
-               self.eofState = 0
 
        def setSeekState(self, state):
                service = self.session.nav.getCurrentService()
 
        def setSeekState(self, state):
                service = self.session.nav.getCurrentService()
@@ -772,7 +861,7 @@ class InfoBarSeek:
                        return False
 
                if not self.isSeekable():
                        return False
 
                if not self.isSeekable():
-                       if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
+                       if state not in (self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE):
                                state = self.SEEK_STATE_PLAY
 
                pauseable = service.pause()
                                state = self.SEEK_STATE_PLAY
 
                pauseable = service.pause()
@@ -781,12 +870,21 @@ class InfoBarSeek:
                        print "not pauseable."
                        state = self.SEEK_STATE_PLAY
 
                        print "not pauseable."
                        state = self.SEEK_STATE_PLAY
 
-               oldstate = self.seekstate
                self.seekstate = state
 
                self.seekstate = state
 
-               for i in (0, 1, 2):
-                       if oldstate[i] != self.seekstate[i]:
-                               (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
+               if pauseable is not None:
+                       if self.seekstate[0]:
+                               print "resolved to PAUSE"
+                               pauseable.pause()
+                       elif self.seekstate[1]:
+                               print "resolved to FAST FORWARD"
+                               pauseable.setFastForward(self.seekstate[1])
+                       elif self.seekstate[2]:
+                               print "resolved to SLOW MOTION"
+                               pauseable.setSlowMotion(self.seekstate[2])
+                       else:
+                               print "resolved to PLAY"
+                               pauseable.unpause()
 
                for c in self.onPlayStateChanged:
                        c(self.seekstate)
 
                for c in self.onPlayStateChanged:
                        c(self.seekstate)
@@ -806,7 +904,7 @@ class InfoBarSeek:
                        if config.seek.on_pause.value == "play":
                                self.unPauseService()
                        elif config.seek.on_pause.value == "step":
                        if config.seek.on_pause.value == "play":
                                self.unPauseService()
                        elif config.seek.on_pause.value == "step":
-                               self.doSeekRelative(0)
+                               self.doSeekRelative(1)
                        elif config.seek.on_pause.value == "last":
                                self.setSeekState(self.lastseekstate)
                                self.lastseekstate = self.SEEK_STATE_PLAY
                        elif config.seek.on_pause.value == "last":
                                self.setSeekState(self.lastseekstate)
                                self.lastseekstate = self.SEEK_STATE_PLAY
@@ -825,16 +923,6 @@ class InfoBarSeek:
                seekable = self.getSeek()
                if seekable is None:
                        return
                seekable = self.getSeek()
                if seekable is None:
                        return
-               prevstate = self.seekstate
-               if self.eofState == 1:
-                       self.eofState = 2
-                       self.inhibitEof()
-               if self.seekstate == self.SEEK_STATE_EOF:
-                       if prevstate == self.SEEK_STATE_PAUSE:
-                               self.setSeekState(self.SEEK_STATE_PAUSE)
-                       else:
-                               self.setSeekState(self.SEEK_STATE_PLAY)
-               self.eofInhibitTimer.start(200, True)
                seekable.seekTo(pts)
 
        def doSeekRelative(self, pts):
                seekable.seekTo(pts)
 
        def doSeekRelative(self, pts):
@@ -842,15 +930,12 @@ class InfoBarSeek:
                if seekable is None:
                        return
                prevstate = self.seekstate
                if seekable is None:
                        return
                prevstate = self.seekstate
-               if self.eofState == 1:
-                       self.eofState = 2
-                       self.inhibitEof()
+
                if self.seekstate == self.SEEK_STATE_EOF:
                        if prevstate == self.SEEK_STATE_PAUSE:
                                self.setSeekState(self.SEEK_STATE_PAUSE)
                        else:
                                self.setSeekState(self.SEEK_STATE_PLAY)
                if self.seekstate == self.SEEK_STATE_EOF:
                        if prevstate == self.SEEK_STATE_PAUSE:
                                self.setSeekState(self.SEEK_STATE_PAUSE)
                        else:
                                self.setSeekState(self.SEEK_STATE_PLAY)
-               self.eofInhibitTimer.start(200, True)
                seekable.seekRelative(pts<0 and -1 or 1, abs(pts))
                if abs(pts) > 100 and config.usage.show_infobar_on_skip.value:
                        self.showAfterSeek()
                seekable.seekRelative(pts<0 and -1 or 1, abs(pts))
                if abs(pts) > 100 and config.usage.show_infobar_on_skip.value:
                        self.showAfterSeek()
@@ -885,30 +970,31 @@ class InfoBarSeek:
                        self.setSeekState(self.makeStateSlowMotion(speed))
 
        def seekBack(self):
                        self.setSeekState(self.makeStateSlowMotion(speed))
 
        def seekBack(self):
-               if self.seekstate == self.SEEK_STATE_PLAY:
+               seekstate = self.seekstate
+               if seekstate == self.SEEK_STATE_PLAY:
                        self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
                        self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
-               elif self.seekstate == self.SEEK_STATE_EOF:
+               elif seekstate == self.SEEK_STATE_EOF:
                        self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
                        self.doSeekRelative(-6)
                        self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
                        self.doSeekRelative(-6)
-               elif self.seekstate == self.SEEK_STATE_PAUSE:
-                       self.doSeekRelative(-3)
-               elif self.isStateForward(self.seekstate):
-                       speed = self.seekstate[1]
-                       if self.seekstate[2]:
-                               speed /= self.seekstate[2]
+               elif seekstate == self.SEEK_STATE_PAUSE:
+                       self.doSeekRelative(-1)
+               elif self.isStateForward(seekstate):
+                       speed = seekstate[1]
+                       if seekstate[2]:
+                               speed /= seekstate[2]
                        speed = self.getLower(speed, config.seek.speeds_forward.value)
                        if speed:
                                self.setSeekState(self.makeStateForward(speed))
                        else:
                                self.setSeekState(self.SEEK_STATE_PLAY)
                        speed = self.getLower(speed, config.seek.speeds_forward.value)
                        if speed:
                                self.setSeekState(self.makeStateForward(speed))
                        else:
                                self.setSeekState(self.SEEK_STATE_PLAY)
-               elif self.isStateBackward(self.seekstate):
-                       speed = -self.seekstate[1]
-                       if self.seekstate[2]:
-                               speed /= self.seekstate[2]
+               elif self.isStateBackward(seekstate):
+                       speed = -seekstate[1]
+                       if seekstate[2]:
+                               speed /= seekstate[2]
                        speed = self.getHigher(speed, config.seek.speeds_backward.value) or config.seek.speeds_backward.value[-1]
                        self.setSeekState(self.makeStateBackward(speed))
                        speed = self.getHigher(speed, config.seek.speeds_backward.value) or config.seek.speeds_backward.value[-1]
                        self.setSeekState(self.makeStateBackward(speed))
-               elif self.isStateSlowMotion(self.seekstate):
-                       speed = self.getHigher(self.seekstate[2], config.seek.speeds_slowmotion.value)
+               elif self.isStateSlowMotion(seekstate):
+                       speed = self.getHigher(seekstate[2], config.seek.speeds_slowmotion.value)
                        if speed:
                                self.setSeekState(self.makeStateSlowMotion(speed))
                        else:
                        if speed:
                                self.setSeekState(self.makeStateSlowMotion(speed))
                        else:
@@ -961,44 +1047,19 @@ class InfoBarSeek:
                return False
                
        def __evEOF(self):
                return False
                
        def __evEOF(self):
-               if self.eofState == 0 and self.seekstate != self.SEEK_STATE_EOF:
-                       self.eofState = 1
-                       time = self.calcRemainingTime()
-                       if not time:
-                               time = 3000   # Failed to calc, use default
-                       elif time == 0:
-                               time = 300    # Passed end, shortest wait
-                       elif time > 15000:
-                               self.eofState = -2  # Too long, block eof
-                               time = 15000
-                       else:
-                               time += 1000  # Add margin
-                       self.eofTimer.start(time, True)
-
-       def inhibitEof(self):
-               if self.eofState >= 1:
-                       self.eofState = -self.eofState
-                       self.eofTimer.stop()
-                       self.doEof()
-
-       def doEof(self):
                if self.seekstate == self.SEEK_STATE_EOF:
                        return
                if self.seekstate == self.SEEK_STATE_EOF:
                        return
-               if self.eofState == -2 or self.isStateBackward(self.seekstate):
-                       self.eofState = 0
-                       return
 
 
-               # if we are seeking, we try to end up ~1s before the end, and pause there.
-               eofstate = self.eofState
+               # if we are seeking forward, we try to end up ~1s before the end, and pause there.
                seekstate = self.seekstate
                seekstate = self.seekstate
-               self.eofState = 0
-               if not self.seekstate == self.SEEK_STATE_PAUSE:
+               if self.seekstate != self.SEEK_STATE_PAUSE:
                        self.setSeekState(self.SEEK_STATE_EOF)
                        self.setSeekState(self.SEEK_STATE_EOF)
-               if eofstate == -1 or not seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
+
+               if seekstate not in (self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE): # if we are seeking
                        seekable = self.getSeek()
                        if seekable is not None:
                                seekable.seekTo(-1)
                        seekable = self.getSeek()
                        if seekable is not None:
                                seekable.seekTo(-1)
-               if eofstate == 1 and seekstate == self.SEEK_STATE_PLAY:
+               if seekstate == self.SEEK_STATE_PLAY: # regular EOF
                        self.doEofInternal(True)
                else:
                        self.doEofInternal(False)
                        self.doEofInternal(True)
                else:
                        self.doEofInternal(False)
@@ -1179,10 +1240,7 @@ class InfoBarTimeshift:
                        self.setSeekState(self.SEEK_STATE_PAUSE)
 
                if back:
                        self.setSeekState(self.SEEK_STATE_PAUSE)
 
                if back:
-                       self.doSeek(-5) # seek some gops before end
                        self.ts_rewind_timer.start(200, 1)
                        self.ts_rewind_timer.start(200, 1)
-               else:
-                       self.doSeek(-1) # seek 1 gop before end
 
        def rewindService(self):
                self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
 
        def rewindService(self):
                self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
@@ -1275,7 +1333,7 @@ class InfoBarExtensions:
                list.extend([(x[0](), x) for x in extensionsList])
 
                keys += [""] * len(extensionsList)
                list.extend([(x[0](), x) for x in extensionsList])
 
                keys += [""] * len(extensionsList)
-               self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
+               self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys, skin_name = "ExtensionsList")
 
        def extensionCallback(self, answer):
                if answer is not None:
 
        def extensionCallback(self, answer):
                if answer is not None:
@@ -1293,7 +1351,9 @@ class InfoBarPlugins:
                return name
 
        def getPluginList(self):
                return name
 
        def getPluginList(self):
-               return [((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None) for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU)]
+               list = [((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None, p.name) for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU)]
+               list.sort(key = lambda e: e[2]) # sort by name
+               return list
 
        def runPlugin(self, plugin):
                if isinstance(self, InfoBarChannelSelection):
 
        def runPlugin(self, plugin):
                if isinstance(self, InfoBarChannelSelection):
@@ -1320,25 +1380,21 @@ class InfoBarJobman:
        def JobViewCB(self, in_background):
                job_manager.in_background = in_background
 
        def JobViewCB(self, in_background):
                job_manager.in_background = in_background
 
-# depends on InfoBarExtensions
-class InfoBarSleepTimer:
-       def __init__(self):
-               self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, lambda: True), "1")
-
-       def getSleepTimerName(self):
-               return _("Sleep Timer")
-
-       def showSleepTimerSetup(self):
-               self.session.open(SleepTimerEdit)
-
 # depends on InfoBarExtensions
 class InfoBarPiP:
        def __init__(self):
 # depends on InfoBarExtensions
 class InfoBarPiP:
        def __init__(self):
-               self.session.pipshown = False
+               try:
+                       self.session.pipshown
+               except:
+                       self.session.pipshown = False
                if SystemInfo.get("NumVideoDecoders", 1) > 1:
                if SystemInfo.get("NumVideoDecoders", 1) > 1:
-                       self.addExtension((self.getShowHideName, self.showPiP, lambda: True), "blue")
-                       self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
-                       self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
+                       if (self.allowPiP):
+                               self.addExtension((self.getShowHideName, self.showPiP, lambda: True), "blue")
+                               self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
+                               self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
+                       else:
+                               self.addExtension((self.getShowHideName, self.showPiP, self.pipShown), "blue")
+                               self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
 
        def pipShown(self):
                return self.session.pipshown
 
        def pipShown(self):
                return self.session.pipshown
@@ -1453,7 +1509,7 @@ class InfoBarInstantRecord:
                if isinstance(serviceref, eServiceReference):
                        serviceref = ServiceReference(serviceref)
 
                if isinstance(serviceref, eServiceReference):
                        serviceref = ServiceReference(serviceref)
 
-               recording = RecordTimerEntry(serviceref, begin, end, name, description, eventid, dirname = config.movielist.last_videodir.value)
+               recording = RecordTimerEntry(serviceref, begin, end, name, description, eventid, dirname = preferredInstantRecordPath())
                recording.dontSave = True
                
                if event is None or limitEvent == False:
                recording.dontSave = True
                
                if event is None or limitEvent == False:
@@ -1480,7 +1536,7 @@ class InfoBarInstantRecord:
 
        def isInstantRecordRunning(self):
                print "self.recording:", self.recording
 
        def isInstantRecordRunning(self):
                print "self.recording:", self.recording
-               if len(self.recording) > 0:
+               if self.recording:
                        for x in self.recording:
                                if x.isRunning():
                                        return True
                        for x in self.recording:
                                if x.isRunning():
                                        return True
@@ -1523,7 +1579,7 @@ class InfoBarInstantRecord:
                print "after:\n", self.recording
 
        def setEndtime(self, entry):
                print "after:\n", self.recording
 
        def setEndtime(self, entry):
-               if entry is not None:
+               if entry is not None and entry >= 0:
                        self.selectedEntry = entry
                        self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
                        dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
                        self.selectedEntry = entry
                        self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
                        dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
@@ -1540,7 +1596,7 @@ class InfoBarInstantRecord:
                                self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
 
        def changeDuration(self, entry):
                                self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
 
        def changeDuration(self, entry):
-               if entry is not None:
+               if entry is not None and entry >= 0:
                        self.selectedEntry = entry
                        self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
 
                        self.selectedEntry = entry
                        self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
 
@@ -1554,9 +1610,9 @@ class InfoBarInstantRecord:
                        self.session.nav.RecordTimer.timeChanged(entry)
 
        def instantRecord(self):
                        self.session.nav.RecordTimer.timeChanged(entry)
 
        def instantRecord(self):
-               dir = config.movielist.last_videodir.value
-               if not fileExists(dir, 'w'):
-                       dir = resolveFilename(SCOPE_HDD)
+               dir = preferredInstantRecordPath()
+               if not dir or not fileExists(dir, 'w'):
+                       dir = defaultMoviePath()
                try:
                        stat = os_stat(dir)
                except:
                try:
                        stat = os_stat(dir)
                except:
@@ -1567,21 +1623,21 @@ class InfoBarInstantRecord:
                if self.isInstantRecordRunning():
                        self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
                                title=_("A recording is currently running.\nWhat do you want to do?"), \
                if self.isInstantRecordRunning():
                        self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
                                title=_("A recording is currently running.\nWhat do you want to do?"), \
-                               list=((_("add recording (stop after current event)"), "event"), \
+                               list=((_("stop recording"), "stop"), \
+                               (_("add recording (stop after current event)"), "event"), \
+                               (_("add recording (indefinitely)"), "indefinitely"), \
                                (_("add recording (enter recording duration)"), "manualduration"), \
                                (_("add recording (enter recording endtime)"), "manualendtime"), \
                                (_("add recording (enter recording duration)"), "manualduration"), \
                                (_("add recording (enter recording endtime)"), "manualendtime"), \
-                               (_("add recording (indefinitely)"), "indefinitely"), \
                                (_("change recording (duration)"), "changeduration"), \
                                (_("change recording (endtime)"), "changeendtime"), \
                                (_("change recording (duration)"), "changeduration"), \
                                (_("change recording (endtime)"), "changeendtime"), \
-                               (_("stop recording"), "stop"), \
                                (_("do nothing"), "no")))
                else:
                        self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
                                title=_("Start recording?"), \
                                list=((_("add recording (stop after current event)"), "event"), \
                                (_("do nothing"), "no")))
                else:
                        self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
                                title=_("Start recording?"), \
                                list=((_("add recording (stop after current event)"), "event"), \
+                               (_("add recording (indefinitely)"), "indefinitely"), \
                                (_("add recording (enter recording duration)"), "manualduration"), \
                                (_("add recording (enter recording endtime)"), "manualendtime"), \
                                (_("add recording (enter recording duration)"), "manualduration"), \
                                (_("add recording (enter recording endtime)"), "manualendtime"), \
-                               (_("add recording (indefinitely)"), "indefinitely"), \
                                (_("don't record"), "no")))
 
 from Tools.ISO639 import LanguageCodes
                                (_("don't record"), "no")))
 
 from Tools.ISO639 import LanguageCodes
@@ -1603,12 +1659,20 @@ class InfoBarAudioSelection:
 
                        idx = 0
                        while idx < n:
 
                        idx = 0
                        while idx < n:
+                               cnt = 0
                                i = audio.getTrackInfo(idx)
                                i = audio.getTrackInfo(idx)
-                               language = i.getLanguage()
+                               languages = i.getLanguage().split('/')
                                description = i.getDescription()
                                description = i.getDescription()
+                               language = ""
 
 
-                               if LanguageCodes.has_key(language):
-                                       language = LanguageCodes[language][0]
+                               for lang in languages:
+                                       if cnt:
+                                               language += ' / '
+                                       if LanguageCodes.has_key(lang):
+                                               language += LanguageCodes[lang][0]
+                                       else:
+                                               language += lang
+                                       cnt += 1
 
                                if len(description):
                                        description += " (" + language + ")"
 
                                if len(description):
                                        description += " (" + language + ")"
@@ -1630,17 +1694,46 @@ class InfoBarAudioSelection:
                                else:
                                        break
 
                                else:
                                        break
 
+                       availableKeys = []
+                       usedKeys = []
+
                        if SystemInfo["CanDownmixAC3"]:
                        if SystemInfo["CanDownmixAC3"]:
-                               tlist = [(_("AC3 downmix") + " - " +[_("Off"), _("On")][config.av.downmix_ac3.value and 1 or 0], "CALLFUNC", self.changeAC3Downmix),
-                                       ([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"),
-                                       ("--", "")] + tlist
-                               keys = [ "red", "green", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
-                               selection += 3
-                       else:
-                               tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
-                               keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
+                               flist = [(_("AC3 downmix") + " - " +(_("Off"), _("On"))[config.av.downmix_ac3.value and 1 or 0], "CALLFUNC", self.changeAC3Downmix),
+                                       ((_("Left"), _("Stereo"), _("Right"))[self.audioChannel.getCurrentChannel()], "mode")]
+                               usedKeys.extend(["red", "green"])
+                               availableKeys.extend(["yellow", "blue"])
                                selection += 2
                                selection += 2
-                       self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
+                       else:
+                               flist = [((_("Left"), _("Stereo"), _("Right"))[self.audioChannel.getCurrentChannel()], "mode")]
+                               usedKeys.extend(["red"])
+                               availableKeys.extend(["green", "yellow", "blue"])
+                               selection += 1
+
+                       if hasattr(self, "runPlugin"):
+                               class PluginCaller:
+                                       def __init__(self, fnc, *args):
+                                               self.fnc = fnc
+                                               self.args = args
+                                       def __call__(self, *args, **kwargs):
+                                               self.fnc(*self.args)
+
+                               Plugins = [ (p.name, PluginCaller(self.runPlugin, p)) for p in plugins.getPlugins(where = PluginDescriptor.WHERE_AUDIOMENU) ]
+
+                               for p in Plugins:
+                                       selection += 1
+                                       flist.append((p[0], "CALLFUNC", p[1]))
+                                       if availableKeys:
+                                               usedKeys.append(availableKeys[0])
+                                               del availableKeys[0]
+                                       else:
+                                               usedKeys.append("")
+
+                       flist.append(("--", ""))
+                       usedKeys.append("")
+                       selection += 1
+
+                       keys = usedKeys + [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" ] + [""] * n
+                       self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = flist + tlist, selection = selection, keys = keys, skin_name = "AudioTrackSelection")
                else:
                        del self.audioTracks
 
                else:
                        del self.audioTracks
 
@@ -1649,7 +1742,7 @@ class InfoBarAudioSelection:
                list = choicelist.list
                t = list[0][1]
                list[0][1]=(t[0], t[1], t[2], t[3], t[4], t[5], t[6],
                list = choicelist.list
                t = list[0][1]
                list[0][1]=(t[0], t[1], t[2], t[3], t[4], t[5], t[6],
-                       _("AC3 downmix") + " - " +[_("On"), _("Off")][config.av.downmix_ac3.value and 1 or 0])
+                       _("AC3 downmix") + " - " + (_("On"), _("Off"))[config.av.downmix_ac3.value and 1 or 0])
                choicelist.setList(list)
                if config.av.downmix_ac3.value:
                        config.av.downmix_ac3.value = False
                choicelist.setList(list)
                if config.av.downmix_ac3.value:
                        config.av.downmix_ac3.value = False
@@ -1664,7 +1757,7 @@ class InfoBarAudioSelection:
                                        keys = ["red", "green", "yellow"]
                                        selection = self.audioChannel.getCurrentChannel()
                                        tlist = ((_("left"), 0), (_("stereo"), 1), (_("right"), 2))
                                        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)
+                                       self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys, skin_name ="AudioModeSelection")
                        else:
                                del self.audioChannel
                                if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
                        else:
                                del self.audioChannel
                                if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
@@ -1765,7 +1858,7 @@ class InfoBarSubserviceSelection:
                                keys = ["red", "",  "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
                                selection += 2
 
                                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)
+                       self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys, skin_name = "SubserviceSelection")
 
        def subserviceSelected(self, service):
                del self.bouquets
 
        def subserviceSelected(self, service):
                del self.bouquets
@@ -2080,9 +2173,6 @@ class InfoBarSummary(Screen):
 #                      <convert type="ServiceName">Reference</convert>
 #              </widget>
 
 #                      <convert type="ServiceName">Reference</convert>
 #              </widget>
 
-       def __init__(self, session, parent):
-               Screen.__init__(self, session, parent = parent)
-
 class InfoBarSummarySupport:
        def __init__(self):
                pass
 class InfoBarSummarySupport:
        def __init__(self):
                pass
@@ -2108,9 +2198,6 @@ class InfoBarMoviePlayerSummary(Screen):
                </widget>
        </screen>"""
 
                </widget>
        </screen>"""
 
-       def __init__(self, session, parent):
-               Screen.__init__(self, session)
-
 class InfoBarMoviePlayerSummarySupport:
        def __init__(self):
                pass
 class InfoBarMoviePlayerSummarySupport:
        def __init__(self):
                pass
@@ -2151,19 +2238,19 @@ class InfoBarSubtitleSupport(object):
                self.__selected_subtitle = None
 
        def __serviceStopped(self):
                self.__selected_subtitle = None
 
        def __serviceStopped(self):
-               self.subtitle_window.hide()
-               self.__subtitles_enabled = False
                self.cached_subtitle_checked = False
                self.cached_subtitle_checked = False
+               if self.__subtitles_enabled:
+                       self.subtitle_window.hide()
+                       self.__subtitles_enabled = False
+                       self.__selected_subtitle = None
 
        def __updatedInfo(self):
                if not self.cached_subtitle_checked:
 
        def __updatedInfo(self):
                if not self.cached_subtitle_checked:
-                       subtitle = self.getCurrentServiceSubtitle()
                        self.cached_subtitle_checked = True
                        self.cached_subtitle_checked = True
-                       self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
+                       subtitle = self.getCurrentServiceSubtitle()
+                       self.setSelectedSubtitle(subtitle and subtitle.getCachedSubtitle())
                        if self.__selected_subtitle:
                        if self.__selected_subtitle:
-                               subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
-                               self.subtitle_window.show()
-                               self.__subtitles_enabled = True
+                               self.setSubtitlesEnable(True)
 
        def getCurrentServiceSubtitle(self):
                service = self.session.nav.getCurrentService()
 
        def getCurrentServiceSubtitle(self):
                service = self.session.nav.getCurrentService()
@@ -2171,14 +2258,16 @@ class InfoBarSubtitleSupport(object):
 
        def setSubtitlesEnable(self, enable=True):
                subtitle = self.getCurrentServiceSubtitle()
 
        def setSubtitlesEnable(self, enable=True):
                subtitle = self.getCurrentServiceSubtitle()
-               if enable and self.__selected_subtitle is not None:
-                       if subtitle and not self.__subtitles_enabled:
-                               subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
-                               self.subtitle_window.show()
-                               self.__subtitles_enabled = True
+               if enable:
+                       if self.__selected_subtitle:
+                               if subtitle and not self.__subtitles_enabled:
+                                       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)
                else:
                        if subtitle:
                                subtitle.disableSubtitles(self.subtitle_window.instance)
+                       self.__selected_subtitle = False
                        self.__subtitles_enabled = False
                        self.subtitle_window.hide()
 
                        self.__subtitles_enabled = False
                        self.subtitle_window.hide()
 
@@ -2211,7 +2300,7 @@ class InfoBarServiceErrorPopupSupport:
                else:
                        self.last_error = error
 
                else:
                        self.last_error = error
 
-               errors = {
+               error = {
                        eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
                        eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
                        eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
                        eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
                        eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
                        eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
@@ -2222,9 +2311,7 @@ class InfoBarServiceErrorPopupSupport:
                        eDVBServicePMTHandler.eventSOF: None,
                        eDVBServicePMTHandler.eventEOF: None,
                        eDVBServicePMTHandler.eventMisconfiguration: _("Service unavailable!\nCheck tuner configuration!"),
                        eDVBServicePMTHandler.eventSOF: None,
                        eDVBServicePMTHandler.eventEOF: None,
                        eDVBServicePMTHandler.eventMisconfiguration: _("Service unavailable!\nCheck tuner configuration!"),
-               }
-
-               error = errors.get(error) #this returns None when the key not exist in the dict
+               }.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")
 
                if error is not None:
                        Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")