add support for cyclic garbage collection to eTimer and eSocketNotifier
[vuplus_dvbapp] / mytest.py
1 import eBaseImpl
2 import enigma
3 enigma.eTimer = eBaseImpl.eTimer
4 enigma.eSocketNotifier = eBaseImpl.eSocketNotifier
5
6 from Tools.Profile import profile, profile_final
7
8 profile("PYTHON_START")
9
10 from enigma import runMainloop, eDVBDB, eTimer, quitMainloop, eDVBVolumecontrol, \
11         getDesktop, ePythonConfigQuery, eAVSwitch, eWindow, eServiceEvent
12 from tools import *
13
14 profile("LANGUAGE")
15
16 from Components.Language import language
17
18 def setEPGLanguage():
19         print "language set to", language.getLanguage()
20         eServiceEvent.setEPGLanguage(language.getLanguage())
21
22 language.addCallback(setEPGLanguage)
23
24 from traceback import print_exc
25 profile("LOAD:InfoBar")
26 import Screens.InfoBar
27 from Screens.SimpleSummary import SimpleSummary
28
29 from sys import stdout, exc_info
30
31 profile("ParentalControl")
32 from Components.ParentalControl import InitParentalControl
33 InitParentalControl()
34
35 profile("LOAD:Navigation")
36 from Navigation import Navigation
37
38 profile("LOAD:skin")
39 from skin import readSkin, applyAllAttributes
40
41 profile("LOAD:Tools")
42 from Tools.Directories import InitFallbackFiles, resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE
43 from Components.config import config, configfile, ConfigText, ConfigSubsection, ConfigInteger
44 InitFallbackFiles()
45
46 profile("ReloadProfiles")
47 eDVBDB.getInstance().reloadBouquets()
48
49 config.misc.radiopic = ConfigText(default = resolveFilename(SCOPE_SKIN_IMAGE)+"radio.mvi")
50
51 profile("Twisted")
52 try:
53         import twisted.python.runtime
54         twisted.python.runtime.platform.supportsThreads = lambda: False
55
56         import e2reactor
57         e2reactor.install()
58
59         from twisted.internet import reactor
60
61         def runReactor():
62                 reactor.run()
63 except ImportError:
64         print "twisted not available"
65         def runReactor():
66                 runMainloop()
67
68 profile("LOAD:Plugin")
69
70 # initialize autorun plugins and plugin menu entries
71 from Components.PluginComponent import plugins
72
73 profile("LOAD:Wizard")
74 from Screens.Wizard import wizardManager
75 from Screens.ImageWizard import *
76 from Screens.StartWizard import *
77 from Screens.TutorialWizard import *
78 from Tools.BoundFunction import boundFunction
79 from Plugins.Plugin import PluginDescriptor
80
81 profile("misc")
82 had = dict()
83
84 def dump(dir, p = ""):
85         if isinstance(dir, dict):
86                 for (entry, val) in dir.items():
87                         dump(val, p + "(dict)/" + entry)
88         if hasattr(dir, "__dict__"):
89                 for name, value in dir.__dict__.items():
90                         if not had.has_key(str(value)):
91                                 had[str(value)] = 1
92                                 dump(value, p + "/" + str(name))
93                         else:
94                                 print p + "/" + str(name) + ":" + str(dir.__class__) + "(cycle)"
95         else:
96                 print p + ":" + str(dir)
97
98 # + ":" + str(dir.__class__)
99
100 # display
101
102 class OutputDevice:
103         def create(self, screen): pass
104
105 class GUIOutputDevice(OutputDevice):
106         parent = None
107         def create(self, comp, desktop):
108                 comp.createGUIScreen(self.parent, desktop)
109
110 profile("LOAD:ScreenGlobals")
111 from Screens.Globals import Globals
112 from Screens.SessionGlobals import SessionGlobals
113 from Screens.Screen import Screen
114
115 profile("Screen")
116 Screen.global_screen = Globals()
117
118 # Session.open:
119 # * push current active dialog ('current_dialog') onto stack
120 # * call execEnd for this dialog
121 #   * clear in_exec flag
122 #   * hide screen
123 # * instantiate new dialog into 'current_dialog'
124 #   * create screens, components
125 #   * read, apply skin
126 #   * create GUI for screen
127 # * call execBegin for new dialog
128 #   * set in_exec
129 #   * show gui screen
130 #   * call components' / screen's onExecBegin
131 # ... screen is active, until it calls 'close'...
132 # Session.close:
133 # * assert in_exec
134 # * save return value
135 # * start deferred close handler ('onClose')
136 # * execEnd
137 #   * clear in_exec
138 #   * hide screen
139 # .. a moment later:
140 # Session.doClose:
141 # * destroy screen
142
143 class Session:
144         def __init__(self, desktop = None, summary_desktop = None, navigation = None):
145                 self.desktop = desktop
146                 self.summary_desktop = summary_desktop
147                 self.nav = navigation
148                 self.delay_timer = eTimer()
149                 self.delay_timer.callback.append(self.processDelay)
150
151                 self.current_dialog = None
152
153                 self.dialog_stack = [ ]
154                 self.summary_stack = [ ]
155                 self.summary = None
156
157                 self.in_exec = False
158
159                 self.screen = SessionGlobals(self)
160
161                 for p in plugins.getPlugins(PluginDescriptor.WHERE_SESSIONSTART):
162                         p(reason=0, session=self)
163
164         def processDelay(self):
165                 callback = self.current_dialog.callback
166
167                 retval = self.current_dialog.returnValue
168
169                 if self.current_dialog.isTmp:
170                         self.current_dialog.doClose()
171 #                       dump(self.current_dialog)
172                         del self.current_dialog
173                 else:
174                         del self.current_dialog.callback
175
176                 self.popCurrent()
177                 if callback is not None:
178                         callback(*retval)
179
180         def execBegin(self, first=True, do_show = True):
181                 assert not self.in_exec 
182                 self.in_exec = True
183                 c = self.current_dialog
184
185                 # when this is an execbegin after a execend of a "higher" dialog,
186                 # popSummary already did the right thing.
187                 if first:
188                         self.pushSummary()
189                         summary = c.createSummary() or SimpleSummary
190                         self.summary = self.instantiateSummaryDialog(summary, c)
191                         self.summary.show()
192                         c.addSummary(self.summary)
193
194                 c.execBegin()
195
196                 # when execBegin opened a new dialog, don't bother showing the old one.
197                 if c == self.current_dialog and do_show:
198                         c.show()
199
200         def execEnd(self, last=True):
201                 assert self.in_exec
202                 self.in_exec = False
203
204                 self.current_dialog.execEnd()
205                 self.current_dialog.hide()
206
207                 if last:
208                         self.current_dialog.removeSummary(self.summary)
209                         self.popSummary()
210
211         def create(self, screen, arguments, **kwargs):
212                 # creates an instance of 'screen' (which is a class)
213                 try:
214                         return screen(self, *arguments, **kwargs)
215                 except:
216                         errstr = "Screen %s(%s, %s): %s" % (str(screen), str(arguments), str(kwargs), exc_info()[0])
217                         print errstr
218                         print_exc(file=stdout)
219                         quitMainloop(5)
220
221         def instantiateDialog(self, screen, *arguments, **kwargs):
222                 return self.doInstantiateDialog(screen, arguments, kwargs, self.desktop)
223
224         def deleteDialog(self, screen):
225                 screen.hide()
226                 screen.doClose()
227
228         def instantiateSummaryDialog(self, screen, *arguments, **kwargs):
229                 return self.doInstantiateDialog(screen, arguments, kwargs, self.summary_desktop)
230
231         def doInstantiateDialog(self, screen, arguments, kwargs, desktop):
232                 # create dialog
233
234                 try:
235                         dlg = self.create(screen, arguments, **kwargs)
236                 except:
237                         print 'EXCEPTION IN DIALOG INIT CODE, ABORTING:'
238                         print '-'*60
239                         print_exc(file=stdout)
240                         quitMainloop(5)
241                         print '-'*60
242
243                 if dlg is None:
244                         return
245
246                 # read skin data
247                 readSkin(dlg, None, dlg.skinName, desktop)
248
249                 # create GUI view of this dialog
250                 assert desktop is not None
251
252                 z = 0
253                 title = ""
254                 for (key, value) in dlg.skinAttributes:
255                         if key == "zPosition":
256                                 z = int(value)
257                         elif key == "title":
258                                 title = value
259
260                 dlg.instance = eWindow(desktop, z)
261                 dlg.title = title
262                 applyAllAttributes(dlg.instance, desktop, dlg.skinAttributes)
263                 gui = GUIOutputDevice()
264                 gui.parent = dlg.instance
265                 gui.create(dlg, desktop)
266
267                 return dlg
268
269         def pushCurrent(self):
270                 if self.current_dialog is not None:
271                         self.dialog_stack.append((self.current_dialog, self.current_dialog.shown))
272                         self.execEnd(last=False)
273
274         def popCurrent(self):
275                 if len(self.dialog_stack):
276                         (self.current_dialog, do_show) = self.dialog_stack.pop()
277                         self.execBegin(first=False, do_show=do_show)
278                 else:
279                         self.current_dialog = None
280
281         def execDialog(self, dialog):
282                 self.pushCurrent()
283                 self.current_dialog = dialog
284                 self.current_dialog.isTmp = False
285                 self.current_dialog.callback = None # would cause re-entrancy problems.
286                 self.execBegin()
287
288         def openWithCallback(self, callback, screen, *arguments, **kwargs):
289                 dlg = self.open(screen, *arguments, **kwargs)
290                 dlg.callback = callback
291                 return dlg
292
293         def open(self, screen, *arguments, **kwargs):
294                 if len(self.dialog_stack) and not self.in_exec:
295                         raise "modal open are allowed only from a screen which is modal!"
296                         # ...unless it's the very first screen.
297
298                 self.pushCurrent()
299                 dlg = self.current_dialog = self.instantiateDialog(screen, *arguments, **kwargs)
300                 dlg.isTmp = True
301                 dlg.callback = None
302                 self.execBegin()
303                 return dlg
304
305         def close(self, screen, *retval):
306                 if not self.in_exec:
307                         print "close after exec!"
308                         return
309
310                 # be sure that the close is for the right dialog!
311                 # if it's not, you probably closed after another dialog
312                 # was opened. this can happen if you open a dialog
313                 # onExecBegin, and forget to do this only once.
314                 # after close of the top dialog, the underlying will
315                 # gain focus again (for a short time), thus triggering
316                 # the onExec, which opens the dialog again, closing the loop.
317                 assert screen == self.current_dialog
318
319                 self.current_dialog.returnValue = retval
320                 self.delay_timer.start(0, 1)
321                 self.execEnd()
322
323         def pushSummary(self):
324                 if self.summary is not None:
325                         self.summary.hide()
326                 self.summary_stack.append(self.summary)
327                 self.summary = None
328
329         def popSummary(self):
330                 if self.summary is not None:
331                         self.summary.doClose()
332                 self.summary = self.summary_stack.pop()
333                 if self.summary is not None:
334                         self.summary.show()
335
336 from Screens.Volume import Volume
337 from Screens.Mute import Mute
338 from GlobalActions import globalActionMap
339
340 profile("VolumeControl")
341 #TODO .. move this to a own .py file
342 class VolumeControl:
343         """Volume control, handles volUp, volDown, volMute actions and display
344         a corresponding dialog"""
345         def __init__(self, session):
346                 global globalActionMap
347                 globalActionMap.actions["volumeUp"]=self.volUp
348                 globalActionMap.actions["volumeDown"]=self.volDown
349                 globalActionMap.actions["volumeMute"]=self.volMute
350
351                 config.audio = ConfigSubsection()
352                 config.audio.volume = ConfigInteger(default = 100, limits = (0, 100))
353
354                 self.volumeDialog = session.instantiateDialog(Volume)
355                 self.muteDialog = session.instantiateDialog(Mute)
356
357                 self.hideVolTimer = eTimer()
358                 self.hideVolTimer.callback.append(self.volHide)
359
360                 vol = config.audio.volume.value
361                 self.volumeDialog.setValue(vol)
362                 self.volctrl = eDVBVolumecontrol.getInstance()
363                 self.volctrl.setVolume(vol, vol)
364
365         def volSave(self):
366                 if self.volctrl.isMuted():
367                         config.audio.volume.value = 0
368                 else:
369                         config.audio.volume.value = self.volctrl.getVolume()
370                 config.audio.volume.save()
371
372         def volUp(self):
373                 self.setVolume(+1)
374
375         def volDown(self):
376                 self.setVolume(-1)
377
378         def setVolume(self, direction):
379                 oldvol = self.volctrl.getVolume()
380                 if direction > 0:
381                         self.volctrl.volumeUp()
382                 else:
383                         self.volctrl.volumeDown()
384                 is_muted = self.volctrl.isMuted()
385                 vol = self.volctrl.getVolume()
386                 self.volumeDialog.show()
387                 if is_muted:
388                         self.volMute() # unmute
389                 elif not vol:
390                         self.volMute(False, True) # mute but dont show mute symbol
391                 if self.volctrl.isMuted():
392                         self.volumeDialog.setValue(0)
393                 else:
394                         self.volumeDialog.setValue(self.volctrl.getVolume())
395                 self.volSave()
396                 self.hideVolTimer.start(3000, True)
397
398         def volHide(self):
399                 self.volumeDialog.hide()
400
401         def volMute(self, showMuteSymbol=True, force=False):
402                 vol = self.volctrl.getVolume()
403                 if vol or force:
404                         self.volctrl.volumeToggleMute()
405                         if self.volctrl.isMuted():
406                                 if showMuteSymbol:
407                                         self.muteDialog.show()
408                                 self.volumeDialog.setValue(0)
409                         else:
410                                 self.muteDialog.hide()
411                                 self.volumeDialog.setValue(vol)
412
413 profile("Standby,PowerKey")
414 import Screens.Standby
415 from Screens.Menu import MainMenu, mdom
416 import xml.dom.minidom
417
418 class PowerKey:
419         """ PowerKey stuff - handles the powerkey press and powerkey release actions"""
420
421         def __init__(self, session):
422                 self.session = session
423                 globalActionMap.actions["power_down"]=self.powerdown
424                 globalActionMap.actions["power_up"]=self.powerup
425                 globalActionMap.actions["power_long"]=self.powerlong
426                 globalActionMap.actions["deepstandby"]=self.shutdown # frontpanel long power button press
427                 self.standbyblocked = 1
428
429         def MenuClosed(self, *val):
430                 self.session.infobar = None
431
432         def shutdown(self):
433                 print "PowerOff - Now!"
434                 if not Screens.Standby.inTryQuitMainloop:
435                         self.session.open(Screens.Standby.TryQuitMainloop, 1)
436                 
437         def powerlong(self):
438                 self.standbyblocked = 1
439                 action = config.usage.on_long_powerpress.value
440                 if action == "shutdown":
441                         self.shutdown()
442                 elif action == "show_menu":
443                         print "Show shutdown Menu"
444                         menu = mdom.childNodes[0]
445                         for x in menu.childNodes:
446                                 if x.nodeType != xml.dom.minidom.Element.nodeType:
447                                     continue
448                                 elif x.tagName == 'menu':
449                                         for y in x.childNodes:
450                                                 if y.nodeType != xml.dom.minidom.Element.nodeType:
451                                                         continue
452                                                 elif y.tagName == 'id':
453                                                         id = y.getAttribute("val")
454                                                         if id and id == "shutdown":
455                                                                 self.session.infobar = self
456                                                                 menu_screen = self.session.openWithCallback(self.MenuClosed, MainMenu, x, x.childNodes)
457                                                                 menu_screen.setTitle(_("Standby / Restart"))
458                                                                 return
459
460         def powerdown(self):
461                 self.standbyblocked = 0
462
463         def powerup(self):
464                 if self.standbyblocked == 0:
465                         self.standbyblocked = 1
466                         self.standby()
467
468         def standby(self):
469                 if not Screens.Standby.inStandby and self.session.current_dialog and self.session.current_dialog.ALLOW_SUSPEND:
470                         self.session.open(Screens.Standby.Standby)
471
472 profile("Scart")
473 from Screens.Scart import Scart
474
475 class AutoScartControl:
476         def __init__(self, session):
477                 self.force = False
478                 self.current_vcr_sb = eAVSwitch.getInstance().getVCRSlowBlanking()
479                 if self.current_vcr_sb and config.av.vcrswitch.value:
480                         self.scartDialog = session.instantiateDialog(Scart, True)
481                 else:
482                         self.scartDialog = session.instantiateDialog(Scart, False)
483                 config.av.vcrswitch.addNotifier(self.recheckVCRSb)
484                 eAVSwitch.getInstance().vcr_sb_notifier.get().append(self.VCRSbChanged)
485
486         def recheckVCRSb(self, configElement):
487                 self.VCRSbChanged(self.current_vcr_sb)
488
489         def VCRSbChanged(self, value):
490                 #print "vcr sb changed to", value
491                 self.current_vcr_sb = value
492                 if config.av.vcrswitch.value or value > 2:
493                         if value:
494                                 self.scartDialog.showMessageBox()
495                         else:
496                                 self.scartDialog.switchToTV()
497
498 profile("Load:CI")
499 from enigma import eDVBCIInterfaces
500 from Screens.Ci import CiHandler
501
502 def runScreenTest():
503         profile("readPluginList")
504         plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
505
506         profile("Init:Session")
507         session = Session(desktop = getDesktop(0), summary_desktop = getDesktop(1), navigation = Navigation())
508
509         CiHandler.setSession(session)
510
511         screensToRun = [ ]
512
513         for p in plugins.getPlugins(PluginDescriptor.WHERE_WIZARD):
514                 screensToRun.append(p.__call__)
515
516         profile("wizards")
517         screensToRun += wizardManager.getWizards()
518
519         screensToRun.append((100, Screens.InfoBar.InfoBar))
520
521         screensToRun.sort()
522
523         ePythonConfigQuery.setQueryFunc(configfile.getResolvedKey)
524
525 #       eDVBCIInterfaces.getInstance().setDescrambleRules(0 # Slot Number
526 #               ,(      ["1:0:1:24:4:85:C00000:0:0:0:"], #service_list
527 #                       ["PREMIERE"], #provider_list,
528 #                       [] #caid_list
529 #               ));
530
531         def runNextScreen(session, screensToRun, *result):
532                 if result:
533                         quitMainloop(*result)
534                         return
535
536                 screen = screensToRun[0][1]
537
538                 if len(screensToRun):
539                         session.openWithCallback(boundFunction(runNextScreen, session, screensToRun[1:]), screen)
540                 else:
541                         session.open(screen)
542
543         runNextScreen(session, screensToRun)
544
545         profile("Init:VolumeControl")
546         vol = VolumeControl(session)
547         profile("Init:PowerKey")
548         power = PowerKey(session)
549
550         # we need session.scart to access it from within menu.xml
551         session.scart = AutoScartControl(session)
552
553         profile("RunReactor")
554         profile_final()
555         runReactor()
556         profile("configfile.save")
557         configfile.save()
558
559         profile("wakeup")
560         from time import time
561         from Tools.DreamboxHardware import setFPWakeuptime
562         #get currentTime
563         nowTime = time()
564         wakeupList = [
565                 x for x in
566                                 [session.nav.RecordTimer.getNextRecordingTime(),
567                                 session.nav.RecordTimer.getNextZapTime(),
568                                 plugins.getNextWakeupTime()]
569                 if x != -1
570         ]
571         wakeupList.sort()
572         if len(wakeupList):
573                 startTime = wakeupList.pop(0)
574                 if (startTime - nowTime < 330): # no time to switch box back on
575                         setFPWakeuptime(nowTime + 30) # so switch back on in 30 seconds
576                 else:
577                         setFPWakeuptime(startTime - 300)
578         profile("stopService")
579         session.nav.stopService()
580         profile("nav shutdown")
581         session.nav.shutdown()
582
583         return 0
584
585 profile("Init:skin")
586 import skin
587 skin.loadSkinData(getDesktop(0))
588
589 profile("InputDevice")
590 import Components.InputDevice
591 Components.InputDevice.InitInputDevices()
592
593 profile("AVSwitch")
594 import Components.AVSwitch
595 Components.AVSwitch.InitAVSwitch()
596
597 profile("RecordingConfig")
598 import Components.RecordingConfig
599 Components.RecordingConfig.InitRecordingConfig()
600
601 profile("UsageConfig")
602 import Components.UsageConfig
603 Components.UsageConfig.InitUsageConfig()
604
605 profile("keymapparser")
606 import keymapparser
607 keymapparser.readKeymap(config.usage.keymap.value)
608
609 profile("Network")
610 import Components.Network
611 Components.Network.InitNetwork()
612
613 profile("LCD")
614 import Components.Lcd
615 Components.Lcd.InitLcd()
616
617 profile("SetupDevices")
618 import Components.SetupDevices
619 Components.SetupDevices.InitSetupDevices()
620
621 profile("RFMod")
622 import Components.RFmod
623 Components.RFmod.InitRFmod()
624
625 profile("Init:CI")
626 import Screens.Ci
627 Screens.Ci.InitCiConfig()
628
629 # first, setup a screen
630 try:
631         runScreenTest()
632
633         plugins.shutdown()
634
635         from Components.ParentalControl import parentalControl
636         parentalControl.save()
637 except:
638         print 'EXCEPTION IN PYTHON STARTUP CODE:'
639         print '-'*60
640         print_exc(file=stdout)
641         quitMainloop(5)
642         print '-'*60