Direct launch of addon from GUI window id
#1
I'm trying to modify my boxee app to run on xbmc. The boxee and xbmc coding are very simular, but since the latest xbmc developments are somewhat different in setup.

Boxee uses apps that are build out of skin files, without any help from WindowXML or xbmcgui. So it opens a skin file instead of executing a python file. I did some research to the new xbmc addon system, but it seems it can not execute a plugin by opening its skin file referring to the window id. From what I can see you have to specify a python startupscript.

I made the following script to initiate the start of the application. I have a skin file in the folder: addonofmyapp/resources/skins/Default/720p. The window id to start is 4444. So I tried to append the path and id, but still I got an error it can not find the window id specified. It seems that xbmc is only looking in the current skin folder and not in the addon resources. Does anybody has an idea how to solve it or a reference to a guide or something.

As this addon has its own full skin for the GUI it does not require any other native xbmc skin windows. My goal is to get it working on all skins.

Code:
import os
import xbmc
import xbmcgui

SOURCEPATH = os.getcwd()
RESOURCES_PATH = os.path.join( SOURCEPATH , "resources" )
SKIN_PATH = os.path.join( RESOURCES_PATH, "skins", "Default" )

if ( __name__ == "__main__" ):
    xbmc.executebuiltin( "ActivateWindow( 4444, '%s')" % (SKIN_PATH) )
    #WINDOW = xbmcgui.Window( 4444 )
Reply
#2
You need to use windowxml in that case, and you are deriving from xbmc.python.script rather than xbmc.python.plugin.

When XBMC runs your script (user clicks on your addon) it'll just call into your main, whereby you DoModal() on your window and away you go. No need to muck around with window ids or anything like that.

It might pay for you to have a hunt around on mirrors.xbmc.org/addons/dharma and pull down a couple of scripts that have their own skin (eg lyrics has it's own dialog).

Note that this is one of the most neglected parts of the XBMC/python interaction, so let us know if you have some good ideas on how to improve things.

Cheers,
Jonathan
Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.


Image
Reply
#3
Thnx I got it working, but my app is a bit more complex then a simple dialog. I can now fireup the main window, but my app contains multipe python code within the skin file. It might not be common practice to use python code inside the skin files in xbmc, but in boxee it is. The problem is that my entire app is developed this way and it would make it very complex to modify all to the code to the xbmc way of coding.

Code:
import sys
import os
import xbmc, xbmcgui, xbmcaddon

path = os.path.join(os.getcwd().replace(";",""),'resources','libs')
sys.path.append(path)
settings = xbmcaddon.Addon(id='com.bart.tv')
settings.setSetting(id='path', value=path)

class GUI(xbmcgui.WindowXML):
    def __init__( self, *args, **kwargs ):
        xbmcgui.WindowXML.__init__( self, *args, **kwargs )
        
if ( __name__ == "__main__" ):
    ui = GUI( "main.xml" , __cwd__, "Default")
    ui.doModal()

My question is that now I have the app running I want to refer to specific buttons, lists to do some actions. But I can't get it to refer to a specific window. In my app I have 3 seperate windows with there own id.

In boxee we can use a function like this to call a list or element:
Code:
mc.GetWindow(14444).GetToggleButton(10101).SetSelected(True)
or
Code:
window = mc.GetWindow(14444)
window.GetControl(1200).SetVisible(True)

I'm actually building a new mc module converting all boxee functions to xbmc executable function. So the result might be usuable to transfer more boxee applications to xbmc.

It might be a newbie question but how to refer to a window and call elements in xbmc and does it work from within the skin.
Reply
#4
You might be able to embed python code inside the XML in XBMC, but it's not really the way things are done, and isn't really supported on our side. It was dumped in by a boxee dev at one point but has had no love since then, so cannot be guaranteed to work (now or in the future).

With that said, I'd be interested in looking at your code just to see how you've done things, and would also be interested in your take on how easy it is to work with compared to separating the code out into a separate script. The latter makes particular sense if you want to skin your addon various ways (or allow others to skin it) which is something I believe boxee does not really allow. It's also nice in that it separates out the logic from the presentation.

For the XBMC way of doing things, now that you have your script running, ui is your window, so ui.GetControl(1200).SetVisible(true) will do the trick.

If you want to get another window (that you own or don't own), there's a routine for this (xbmc.getWindow maybe? See the pydocs which can be generated using the pydocs addon), but note that the id of the window may not be what you set it to be in the XML - in fact, that is ignored completely. Python windows start off with id 13000 and increment from there.

Cheers,
Jonathan
Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.


Image
Reply
#5
yeah xbmc and boxee seems a bit more different then I anticipated. Boxee uses the skin files to control the python code. And xbmc uses the principle of having the python code control the skin code or more like a template as I can see. Still I keep my python pretty seperate from the skin as it allows for importing modules.

For now I'm trying to convert some simple boxee commands to xbmc code. For the elements calls I now have the following in place.

here a fragement of my boxee api emulation, mc.py:

Code:
class GetWindow(object):
    def __init__( self, var):
        file = settings.getSetting(id=str(var))
        path = settings.getAddonInfo('path')
        self.ui = GUI( file , path, "Default")
        

    def GetToggleButton(self, var):
        self.ui.getControl(var)

class GUI(xbmcgui.WindowXML):
    def __init__( self, *args, **kwargs ):
    xbmcgui.WindowXML.__init__( self, *args, **kwargs )


This is called from within the skin file as:
Code:
mc.GetWindow(14444).GetToggleButton(31)

For now it will create the window object, but fails on the gettogglebutton as it connot find the id. Is it correct you call all elements with getControl(id) or do you have spcific commands to call buttons, labels etc like in boxee. It is hard to get some good documentation on it...
Reply
#6
Well I think I understand the xbmc principle a bit better. Fortunatly I have been developing my own app in a way that lots of python code is separate in modules/objects (it is a nice challange to emulate the api)

I can run python code in the skin on xbmc fine, but it is hard to refer to the active window id and element. Now the default.py is started by xbmc and default.py starts the skin from the WindowXML object. Usually any actions etc are done from within the WindowXML object, but now I need to have acces to this from within the skin file script. I can reinitialize the WindowXML file again from within the skin file, but not sure if I can change anything as this is effectively another instance of the object.

It would be great if anyone has some tips or examples to refer to buttons/labels etc from within the skin code!

I also noticed some similarities in the way the windowXML class is created and the boxee python code in the boxee skin. I only have minor python code on initialization of the skin and by pressing buttons or clicks on the lists. For example this is a way how the boxee skin initializes python scripts on start:

Code:
    <onload lang="python">
<![CDATA[
import mc
from libs import main, ba
window = mc.GetWindow(14444)
config = mc.GetApp().GetLocalConfig()
index = 0
mc.GetWindow(14446).ClearStateStack(False)

window.GetToggleButton(10101).SetSelected(True)

main_obj = main.main_obj()
main_obj.Search_DB_Update(86400)

if window.GetControl(1200).IsVisible():
    window.GetControl(1200).SetVisible(True)
    window.GetControl(1300).SetVisible(False)
    window.GetControl(1400).SetVisible(False)
]]>
</onload>

See the full script at github. I think with some modification it could be transformed to something seen below:
Code:
class GUI(xbmcgui.WindowXML):
  def __init__( self, *args, **kwargs ):
    xbmcgui.WindowXML.__init__( self, *args, **kwargs )

  def onInit(self):
    import mc
    from libs import main, ba
    window = mc.GetWindow(14444)
    config = mc.GetApp().GetLocalConfig()
    index = 0    
    mc.GetWindow(14446).ClearStateStack(False)

    window.GetToggleButton(10101).SetSelected(True)

    main_obj = main.main_obj()
    main_obj.Search_DB_Update(86400)

    if window.GetControl(1200).IsVisible():
    window.GetControl(1200).SetVisible(True)
    window.GetControl(1300).SetVisible(False)
    window.GetControl(1400).SetVisible(False))

Still I hope that I do not need major modification and ideally would create a boxee mc emulation module. This would prevent any modification to the scripts at all and allows me to upgrade/develop the application for both platforms at the same time.
Reply
#7
You are bang on in your analysis, and yes, in XBMC you would do it the second way.

You *may* be able to get the boxee way to run, but "14444" is likely the wrong window id, as XBMC manages that completely. You should be able to grab the window from within the skin using the getWindow command - try using the filename of the XML rather than the id.

I'm wondering how the python state is transferred from one block to another in your skin XML - atm we just execute the code by cranking up a new pythread by the looks. I suspect boxee have code to determine the correct context to call. It may be worth taking a look at ExecuteAction in Application.cpp in both apps and seeing what the difference is.

Cheers,
Jonathan
Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.


Image
Reply
#8
Ok, I've looked at the boxee sources, and sure enough they have some "persistent" python thread contexts to handle this that appear to be independent of any other PyThread context, and they also never attempt to cleanup (finalize) the python context, and thus these persistent python threads hang around forever.

While it would be possible to support this, it would need a fair amount of buy-in from our team, so we'd have to have quite a bit of internal discussion regarding this, particularly when our focus is moving python out of our process space and taking advantage of SWiG to auto-generate interfaces for various languages.

Cheers,
Jonathan
Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.


Image
Reply

Logout Mark Read Team Forum Stats Members Help
Direct launch of addon from GUI window id0