pipzap: add experimental ACS support
[enigma2-plugins.git] / pipzap / src / plugin.py
1 from __future__ import print_function
2
3 # Plugin definition
4 from Plugins.Plugin import PluginDescriptor
5
6 from Components.ActionMap import HelpableActionMap
7 from Components.ChoiceList import ChoiceEntryComponent
8 from Components.config import config, ConfigSubsection, ConfigEnableDisable
9 from Components.SystemInfo import SystemInfo
10 from Components.ParentalControl import parentalControl
11 from enigma import ePoint, eServiceReference, getDesktop
12 from Screens.ChannelSelection import ChannelContextMenu, ChannelSelection, ChannelSelectionBase
13 from Screens.InfoBar import InfoBar, MoviePlayer
14 from Screens.InfoBarGenerics import InfoBarNumberZap, InfoBarEPG, InfoBarChannelSelection, InfoBarPiP, InfoBarShowMovies, InfoBarTimeshift, InfoBarSeek, InfoBarPlugins
15 from Screens.PictureInPicture import PictureInPicture
16 from Screens.Screen import Screen
17 from Screens.MessageBox import MessageBox
18 from PipzapSetup import PipzapSetup
19 from Components.PluginComponent import plugins
20
21 class baseMethods:
22         pass
23
24 #pragma mark -
25 #pragma mark ChannelSelection
26 #pragma mark -
27
28 # ChannelContextMenu: switch "Activate Picture in Picture" for pip/mainpicture
29 def ChannelContextMenu___init__(self, session, csel, *args, **kwargs):
30         baseMethods.ChannelContextMenu__init__(self, session, csel, *args, **kwargs)
31
32         if self.pipAvailable:
33                 list = self["menu"].list
34                 x = 0
35                 # TRANSLATORS: Do NOT translate this! This is not a string in our plugin but one from e2 core which we try to find, so a custom translation will probably disallow us to do so.
36                 searchText = _("Activate Picture in Picture")
37                 for entry in list:
38                         if entry[0][0] == searchText:
39                                 if csel.dopipzap:
40                                         entry = ChoiceEntryComponent("", (_("play in mainwindow"), self.playMain))
41                                 else:
42                                         entry = ChoiceEntryComponent("blue", (_("play as picture in picture"), self.showServiceInPiP))
43                                 list[x] = entry
44                                 break
45                         x += 1
46                 self["menu"].setList(list)
47
48 def ChannelContextMenu_playMain(self):
49         # XXX: we want to keep the current selection
50         sel = self.csel.getCurrentSelection()
51         self.csel.zap()
52         self.csel.setCurrentSelection(sel)
53         self.close()
54
55 # do not hide existing pip
56 def ChannelContextMenu_showServiceInPiP(self):
57         if not self.pipAvailable:
58                 return
59
60         if not self.session.pipshown:
61                 self.session.pip = self.session.instantiateDialog(PictureInPicture)
62                 self.session.pip.show()
63
64         newservice = self.csel.servicelist.getCurrent()
65         if self.session.pip.playService(newservice):
66                 self.session.pipshown = True
67                 self.session.pip.servicePath = self.csel.getCurrentServicePath()
68                 self.close(True)
69         else:
70                 self.session.pipshown = False
71                 del self.session.pip
72                 self.session.openWithCallback(self.close, MessageBox, _("Could not open Picture in Picture"), MessageBox.TYPE_ERROR)
73
74 def ChannelSelectionBase__init__(self, *args, **kwargs):
75         baseMethods.ChannelSelectionBase__init__(self, *args, **kwargs)
76         self.dopipzap = False
77         self.enable_pipzap = False
78
79 def ChannelSelectionBase_setCurrentSelection(self, service, *args, **kwargs):
80         if service:
81                 baseMethods.ChannelSelectionBase_setCurrentSelection(self, service, *args, **kwargs)
82
83 def ChannelSelection_channelSelected(self, *args, **kwargs):
84         self.enable_pipzap = True
85         baseMethods.ChannelSelection_channelSelected(self, *args, **kwargs)
86
87 def ChannelSelection_togglePipzap(self):
88         assert(self.session.pip)
89         title = self.instance.getTitle()
90         pos = title.find(" (")
91         if pos != -1:
92                 title = title[:pos]
93         if self.dopipzap:
94                 # Mark PiP as inactive and effectively deactivate pipzap
95                 self.session.pip.inactive()
96                 self.dopipzap = False
97
98                 # Disable PiP if not playing a service
99                 if self.session.pip.pipservice is None:
100                         self.session.pipshown = False
101                         del self.session.pip
102
103                 # Move to playing service
104                 lastservice = eServiceReference(self.lastservice.value)
105                 if lastservice.valid() and self.getCurrentSelection() != lastservice:
106                         self.setCurrentSelection(lastservice)
107
108                 title += " (TV)"
109         else:
110                 # Mark PiP as active and effectively active pipzap
111                 self.session.pip.active()
112                 self.dopipzap = True
113
114                 # Move to service playing in pip (will not work with subservices)
115                 self.setCurrentSelection(self.session.pip.getCurrentService())
116
117                 title += " (PiP)"
118         self.setTitle(title)
119         self.buildTitleString()
120
121 def ChannelSelection_zap(self, *args, **kwargs):
122         if self.enable_pipzap and self.dopipzap:
123                 if not self.session.pipshown:
124                         self.session.pip = self.session.instantiateDialog(PictureInPicture)
125                         self.session.pip.show()
126                         self.session.pipshown = True
127                 self.revertMode=None
128                 ref = self.session.pip.getCurrentService()
129                 nref = self.getCurrentSelection()
130                 if ref is None or ref != nref:
131                         if not config.ParentalControl.configured.value or parentalControl.getProtectionLevel(nref.toCompareString()) == -1:
132                                 if not self.session.pip.playService(nref):
133                                         # XXX: Make sure we set an invalid ref
134                                         self.session.pip.playService(None)
135         else:
136                 baseMethods.ChannelSelection_zap(self, *args, **kwargs)
137
138                 # Yes, we might double-check this, but we need to re-select pipservice if pipzap is active
139                 # and we just wanted to zap in mainwindow once
140                 # XXX: do we really want this? this also resets the service when zapping from context menu
141                 #      which is irritating
142                 if self.dopipzap:
143                         # This unfortunately won't work with subservices
144                         self.setCurrentSelection(self.session.pip.getCurrentService())
145         self.enable_pipzap = False
146
147 def ChannelSelection_setHistoryPath(self, *args, **kwargs):
148         baseMethods.ChannelSelection_setHistoryPath(self, *args, **kwargs)
149         if self.dopipzap:
150                 self.setCurrentSelection(self.session.pip.getCurrentService())
151
152 def ChannelSelection_cancel(self, *args, **kwargs):
153         if self.revertMode is None and self.dopipzap:
154                 # This unfortunately won't work with subservices
155                 self.setCurrentSelection(self.session.pip.getCurrentService())
156                 self.revertMode = 1337 # not in (None, MODE_TV, MODE_RADIO)
157         baseMethods.ChannelSelection_cancel(self, *args, **kwargs)
158
159 #pragma mark -
160 #pragma mark MoviePlayer
161 #pragma mark -
162
163 def MoviePlayer__init__(self, *args, **kwargs):
164         baseMethods.MoviePlayer__init__(self, *args, **kwargs)
165         self.servicelist = InfoBar.instance and InfoBar.instance.servicelist
166
167         self["DirectionActions"] = HelpableActionMap(self, "DirectionActions",
168                 {
169                         "left": self.left,
170                         "right": self.right
171                 }, prio = -2)
172
173 def MoviePlayer_up(self):
174         slist = self.servicelist
175         if slist and slist.dopipzap:
176                 slist.moveUp()
177                 self.session.execDialog(slist)
178         else:
179                 self.showMovies()
180
181 def MoviePlayer_down(self):
182         slist = self.servicelist
183         if slist and slist.dopipzap:
184                 slist.moveDown()
185                 self.session.execDialog(slist)
186         else:
187                 self.showMovies()
188
189 def MoviePlayer_right(self):
190         # XXX: gross hack, we do not really seek if changing channel in pip :-)
191         slist = self.servicelist
192         if slist and slist.dopipzap:
193                 # XXX: We replicate InfoBarChannelSelection.zapDown here - we shouldn't do that
194                 if slist.inBouquet():
195                         prev = slist.getCurrentSelection()
196                         if prev:
197                                 prev = prev.toString()
198                                 while True:
199                                         if config.usage.quickzap_bouquet_change.value and slist.atEnd():
200                                                 slist.nextBouquet()
201                                         else:
202                                                 slist.moveDown()
203                                         cur = slist.getCurrentSelection()
204                                         if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
205                                                 break
206                 else:
207                         slist.moveDown()
208                 slist.enable_pipzap = True
209                 slist.zap()
210         else:
211                 InfoBarSeek.seekFwd(self)
212
213 def MoviePlayer_left(self):
214         slist = self.servicelist
215         if slist and slist.dopipzap:
216                 # XXX: We replicate InfoBarChannelSelection.zapUp here - we shouldn't do that
217                 if slist.inBouquet():
218                         prev = slist.getCurrentSelection()
219                         if prev:
220                                 prev = prev.toString()
221                                 while True:
222                                         if config.usage.quickzap_bouquet_change.value:
223                                                 if slist.atBegin():
224                                                         slist.prevBouquet()
225                                         slist.moveUp()
226                                         cur = slist.getCurrentSelection()
227                                         if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
228                                                 break
229                 else:
230                         slist.moveUp()
231                 slist.enable_pipzap = True
232                 slist.zap()
233         else:
234                 InfoBarSeek.seekBack(self)
235
236 def MoviePlayer_swapPiP(self):
237         pass
238
239 #pragma mark -
240 #pragma mark InfoBarGenerics
241 #pragma mark -
242
243 def InfoBarNumberZap_zapToNumber(self, *args, **kwargs):
244         try:
245                 self.servicelist.enable_pipzap = True
246         except AttributeError as ae:
247                 pass
248         baseMethods.InfoBarNumberZap_zapToNumber(self, *args, **kwargs)
249
250 def InfoBarChannelSelection_zapUp(self, *args, **kwargs):
251         self.servicelist.enable_pipzap = True
252         baseMethods.InfoBarChannelSelection_zapUp(self, *args, **kwargs)
253
254 def InfoBarChannelSelection_zapDown(self, *args, **kwargs):
255         self.servicelist.enable_pipzap = True
256         baseMethods.InfoBarChannelSelection_zapDown(self, *args, **kwargs)
257
258 def InfoBarEPG_zapToService(self, *args, **kwargs):
259         try:
260                 self.servicelist.enable_pipzap = True
261         except AttributeError as ae:
262                 pass
263         baseMethods.InfoBarEPG_zapToService(self, *args, **kwargs)
264
265 def InfoBarShowMovies__init__(self):
266         baseMethods.InfoBarShowMovies__init__(self)
267         self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
268                 {
269                         "movieList": (self.showMovies, _("movie list")),
270                         "up": (self.up, _("movie list")),
271                         "down": (self.down, _("movie list"))
272                 })
273
274 def InfoBarPiP__init__(self):
275         baseMethods.InfoBarPiP__init__(self)
276         if SystemInfo.get("NumVideoDecoders", 1) > 1 and self.allowPiP:
277                 self.addExtension((self.getTogglePipzapName, self.togglePipzap, self.pipzapAvailable), "red")
278                 if config.plugins.pipzap.enable_hotkey.value:
279                         self["pipzapActions"] = HelpableActionMap(self, "pipzapActions",
280                                 {
281                                         "switchPiP": (self.togglePipzap, _("zap in pip window...")),
282                                 })
283
284 def InfoBarPiP_pipzapAvailable(self):
285         try:
286                 return True if self.servicelist and self.session.pipshown else False
287         except AttributeError as ae:
288                 return False
289
290 def InfoBarPiP_getTogglePipzapName(self):
291         slist = self.servicelist
292         if slist and slist.dopipzap:
293                 return _("Zap focus to main screen")
294         return _("Zap focus to Picture in Picture")
295
296 def InfoBarPiP_togglePipzap(self):
297         # supposed to fix some problems with permanent timeshift patch
298         if isinstance(self, InfoBarTimeshift) and isinstance(self, InfoBarSeek) and \
299                 self.timeshift_enabled and self.isSeekable():
300                         return 0
301
302         if not self.session.pipshown:
303                 self.showPiP()
304         slist = self.servicelist
305         if slist:
306                 slist.togglePipzap()
307
308 def InfoBarPiP_togglePipzapHelpable(self):
309         """Stupid helper for InfoBarPiP_togglePipzap to optimize away the check if help should be shown if it already was."""
310         InfoBarPiP.togglePipzap = InfoBarPiP_togglePipzap
311
312         if config.plugins.pipzap.show_help.value and pipzapHelp:
313                 pipzapHelp.open(self.session)
314                 config.plugins.pipzap.show_help.value = False
315                 config.plugins.pipzap.save()
316
317         self.togglePipzap()
318
319 def InfoBarPiP_showPiP(self, *args, **kwargs):
320         try:
321                 slist = self.servicelist
322         except AttributeError as ae:
323                 slist = None
324
325         if self.session.pipshown and slist and slist.dopipzap:
326                 slist.togglePipzap()
327         elif not self.session.pipshown and isinstance(self, InfoBarShowMovies):
328                 self.session.pip = self.session.instantiateDialog(PictureInPicture)
329                 self.session.pip.show()
330                 self.session.pipshown = True
331                 if slist:
332                         self.session.pip.playService(slist.getCurrentSelection())
333                 return
334         baseMethods.InfoBarPiP_showPiP(self, *args, **kwargs)
335
336 # Using the base implementation would cause nasty bugs, so ignore it here
337 def InfoBarPiP_swapPiP(self):
338         swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
339         pipref = self.session.pip.getCurrentService()
340         if pipref and swapservice and pipref.toString() != swapservice.toString():
341                         self.session.pip.playService(swapservice)
342
343                         try:
344                                 slist = self.servicelist
345                         except AttributeError as ae:
346                                 slist = None
347                         if slist:
348                                 # TODO: this behaves real bad on subservices
349                                 if slist.dopipzap:
350                                         slist.servicelist.setCurrent(swapservice)
351                                 else:
352                                         slist.servicelist.setCurrent(pipref)
353
354                                 slist.addToHistory(pipref) # add service to history
355                                 slist.lastservice.value = pipref.toString() # save service as last playing one
356                         self.session.nav.stopService() # stop portal
357                         self.session.nav.playService(pipref) # start subservice
358
359 #pragma mark -
360 #pragma mark Picture in Picture
361 #pragma mark -
362
363 class PictureInPictureZapping(Screen):
364         skin = """<screen name="PictureInPictureZapping" flags="wfNoBorder" position="50,50" size="90,26" title="PiPZap" zPosition="-1">
365                 <eLabel text="PiP-Zap" position="0,0" size="90,26" foregroundColor="#00ff66" font="Regular;26" />
366         </screen>"""
367         def refreshPosition(self):
368                 x = config.av.pip.value[0]
369                 y = config.av.pip.value[1]
370                 width = getDesktop(0).size().width()
371                 height = getDesktop(0).size().height()
372                 if x > width / 2:
373                         x = 40
374                 else:
375                         x = width - 120
376                 if y > height / 2:
377                         y = 40
378                 else:
379                         y = height - 55
380                 self.instance.move(ePoint(x, y))
381
382 def PictureInPicture__init__(self, session, *args, **kwargs):
383         baseMethods.PictureInPicture__init__(self, session, *args, **kwargs)
384         self.pipActive = session.instantiateDialog(PictureInPictureZapping)
385
386 def PictureInPicture_active(self):
387         if config.plugins.pipzap.show_label.value:
388                 self.pipActive.show()
389
390 def PictureInPicture_inactive(self):
391         self.pipActive.hide()
392
393 def PictureInPicture_move(self, *args, **kwargs):
394         baseMethods.PictureInPicture_move(self, *args, **kwargs)
395         self.pipActive.refreshPosition()
396
397 #pragma mark -
398 #pragma mark - Help
399 #pragma mark -
400
401 try:
402         if SystemInfo.get("NumVideoDecoders", 1) > 1:
403                 from Plugins.SystemPlugins.MPHelp import registerHelp, XMLHelpReader
404                 from Tools.Directories import resolveFilename, SCOPE_PLUGINS
405                 reader = XMLHelpReader(resolveFilename(SCOPE_PLUGINS, "Extensions/pipzap/mphelp.xml"))
406                 pipzapHelp = registerHelp(*reader)
407 except Exception as e:
408         print("[pipzap] Unable to initialize MPHelp:", e,"- Help not available!")
409         pipzapHelp = None
410
411 #pragma mark -
412 #pragma mark Plugin
413 #pragma mark -
414
415 def overwriteFunctions():
416         """Overwrite existing functions here to increase system stability a bit."""
417         try:
418                 baseMethods.ChannelContextMenu__init__
419         except AttributeError as ae:
420                 pass
421         else:
422                 print("[pipzap] already initialized, aborting.")
423                 return
424
425         global ChannelContextMenu, ChannelSelection, ChannelSelectionBase
426         try:
427                 from Plugins.Extensions.AdvancedChannelSelection import plugin
428         except ImportError as ie:
429                 pass
430         else:
431                 if config.plugins.AdvancedChannelSelection.enabled.value:
432                         print("[pipzap] ACS is installed and activated, ugly just invited scary to the party xD")
433                         from Plugins.Extensions.AdvancedChannelSelection.ChannelSelection import ChannelContextMenu, ChannelSelection, ChannelSelectionBase
434
435         baseMethods.ChannelContextMenu__init__ = ChannelContextMenu.__init__
436         ChannelContextMenu.__init__ = ChannelContextMenu___init__
437
438         ChannelContextMenu.playMain = ChannelContextMenu_playMain
439         ChannelContextMenu.showServiceInPiP = ChannelContextMenu_showServiceInPiP
440
441         baseMethods.ChannelSelectionBase__init__ = ChannelSelectionBase.__init__
442         ChannelSelectionBase.__init__ = ChannelSelectionBase__init__
443
444         baseMethods.ChannelSelectionBase_setCurrentSelection = ChannelSelectionBase.setCurrentSelection
445         ChannelSelectionBase.setCurrentSelection = ChannelSelectionBase_setCurrentSelection
446
447         baseMethods.ChannelSelection_channelSelected = ChannelSelection.channelSelected
448         ChannelSelection.channelSelected = ChannelSelection_channelSelected
449
450         ChannelSelection.togglePipzap = ChannelSelection_togglePipzap 
451
452         baseMethods.ChannelSelection_zap = ChannelSelection.zap
453         ChannelSelection.zap = ChannelSelection_zap
454
455         baseMethods.ChannelSelection_setHistoryPath = ChannelSelection.setHistoryPath
456         ChannelSelection.setHistoryPath = ChannelSelection_setHistoryPath
457
458         baseMethods.ChannelSelection_cancel = ChannelSelection.cancel
459         ChannelSelection.cancel = ChannelSelection_cancel
460
461         baseMethods.MoviePlayer__init__ = MoviePlayer.__init__
462         MoviePlayer.__init__ = MoviePlayer__init__
463
464         MoviePlayer.allowPiP = property(lambda *x: True, lambda *x: None)
465
466         MoviePlayer.up = MoviePlayer_up
467         MoviePlayer.down = MoviePlayer_down
468         MoviePlayer.right = MoviePlayer_right
469         MoviePlayer.left = MoviePlayer_left
470         MoviePlayer.swapPiP = MoviePlayer_swapPiP
471
472         baseMethods.InfoBarNumberZap_zapToNumber = InfoBarNumberZap.zapToNumber
473         InfoBarNumberZap.zapToNumber = InfoBarNumberZap_zapToNumber
474
475         baseMethods.InfoBarChannelSelection_zapUp = InfoBarChannelSelection.zapUp
476         InfoBarChannelSelection.zapUp = InfoBarChannelSelection_zapUp
477
478         baseMethods.InfoBarChannelSelection_zapDown = InfoBarChannelSelection.zapDown
479         InfoBarChannelSelection.zapDown = InfoBarChannelSelection_zapDown
480
481         baseMethods.InfoBarEPG_zapToService = InfoBarEPG.zapToService
482         InfoBarEPG.zapToService = InfoBarEPG_zapToService
483
484         baseMethods.InfoBarShowMovies__init__ = InfoBarShowMovies.__init__
485         InfoBarShowMovies.__init__ = InfoBarShowMovies__init__
486
487         baseMethods.InfoBarPiP__init__ = InfoBarPiP.__init__
488         InfoBarPiP.__init__ = InfoBarPiP__init__
489
490         InfoBarPiP.pipzapAvailable = InfoBarPiP_pipzapAvailable
491         InfoBarPiP.getTogglePipzapName = InfoBarPiP_getTogglePipzapName
492         InfoBarPiP.swapPiP = InfoBarPiP_swapPiP
493
494         if config.plugins.pipzap.show_help.value and pipzapHelp:
495                 InfoBarPiP.togglePipzap = InfoBarPiP_togglePipzapHelpable
496         else:
497                 InfoBarPiP.togglePipzap = InfoBarPiP_togglePipzap
498
499         baseMethods.InfoBarPiP_showPiP = InfoBarPiP.showPiP
500         InfoBarPiP.showPiP = InfoBarPiP_showPiP
501
502         baseMethods.PictureInPicture__init__ = PictureInPicture.__init__
503         PictureInPicture.__init__ = PictureInPicture__init__
504
505         PictureInPicture.active = PictureInPicture_active
506         PictureInPicture.inactive = PictureInPicture_inactive
507
508         baseMethods.PictureInPicture_move = PictureInPicture.move
509         PictureInPicture.move = PictureInPicture_move
510
511 config.plugins.pipzap = ConfigSubsection()
512 config.plugins.pipzap.enable_hotkey = ConfigEnableDisable(default = True)
513 config.plugins.pipzap.show_in_plugins = ConfigEnableDisable(default = False)
514 config.plugins.pipzap.show_label = ConfigEnableDisable(default = True)
515 config.plugins.pipzap.show_help = ConfigEnableDisable(default = True)
516
517 def autostart(reason, **kwargs):
518         if reason == 0:
519                 overwriteFunctions()
520
521 def activate(session, *args, **kwargs):
522         infobar = InfoBar.instance
523         if not infobar:
524                 session.open(MessageBox, _("Unable to access InfoBar.\npipzap not available."), MessageBox.TYPE_ERROR)
525         elif hasattr(infobar, 'togglePipzap'): # check if plugin is already hooked into enigma2
526                 infobar.togglePipzap()
527         else:
528                 session.open(MessageBox, _("pipzap not properly installed.\nPlease restart Enigma2."), MessageBox.TYPE_ERROR)
529
530 def main(session, *args, **kwargs):
531         session.open(PipzapSetup)
532
533 def menu(menuid):
534         if menuid != "system":
535                 return []
536         return [(_("pipzap"), main, "pipzap_setup", None)]
537
538 def housekeepingPluginmenu(el):
539         if el.value:
540                 plugins.addPlugin(activateDescriptor)
541         else:
542                 plugins.removePlugin(activateDescriptor)
543
544 config.plugins.pipzap.show_in_plugins.addNotifier(housekeepingPluginmenu, initial_call=False, immediate_feedback=True)
545 activateDescriptor = PluginDescriptor(name="pipzap", description=_("Toggle pipzap status"), where=PluginDescriptor.WHERE_PLUGINMENU, fnc=activate, needsRestart=False)
546
547 def showHideNotifier(el):
548         infobar = InfoBar.instance
549         if not infobar:
550                 return
551         session = infobar.session
552         slist = infobar.servicelist
553         if slist and hasattr(slist, 'dopipzap'): # check if plugin is already hooked into enigma2
554                 if session.pipshown:
555                         if el.value and slist.dopipzap:
556                                 session.pip.active()
557                         else:
558                                 session.pip.inactive()
559
560 config.plugins.pipzap.show_label.addNotifier(showHideNotifier, initial_call=False, immediate_feedback=True)
561
562 def Plugins(**kwargs):
563         # do not add any entry if only one (or less :P) video decoders present
564         if SystemInfo.get("NumVideoDecoders", 1) < 2:
565                 return []
566
567         l = [
568                 PluginDescriptor(
569                         where=PluginDescriptor.WHERE_AUTOSTART,
570                         fnc=autostart,
571                         needsRestart=True, # XXX: force restart for now as I don't think the plugin will work properly without one
572                 ),
573                 PluginDescriptor(
574                         where=PluginDescriptor.WHERE_MENU,
575                         fnc=menu,
576                         needsRestart=False,
577                 ),
578         ]
579         if config.plugins.pipzap.show_in_plugins.value:
580                 l.append(activateDescriptor)
581         return l