embedding onboard into GTK project

Asked by Chester on 2012-12-05

I see Onboard uses the XID protocol to embed in Gnome.
I'm interested in embedding into my GTK project (linuxcnc a machine control operator screen)

Is there away to do this? Is a patch necessary?
We are using Ubuntu 10.04 but will move towards 12.04.
I am using python.

Thanks
Chris Morley

Question information

Language:
English Edit question
Status:
Solved
For:
Onboard Edit question
Assignee:
No assignee Edit question
Solved by:
Chester
Solved:
2013-04-02
Last query:
2013-04-02
Last reply:
2013-04-01
Chester (chrisinnanaimo) said : #1

Actually the patch was small and easy.
Are you open to patches? How does one present them?

Thanks

Chris Morley

marmuta (marmuta) said : #2

Hey Chester, xembedding should actually work out of the box. Did you encounter any issues that required patching Onboard?

Patches are welcome, though we can't attach any files here to questions. If you think you've found a bug you can always open a bug report and attach a patch there, or even better link a branch with your changes.
https://help.launchpad.net/Code/UploadingABranch

marmuta (marmuta) said : #3

Here's a minimal socket example to embed Onboard (though somewhat outdated and should be updated to Gtk3 and gobject introspection).

First run onboard --xid, then socket.py <xid> in another terminal.

socket.py:
#!/usr/bin/python

import string

import pygtk
pygtk.require('2.0')
import gtk,sys

window = gtk.Window()
window.resize(800,200)
window.show()

socket = gtk.Socket()
socket.show()
window.add(socket)

print "Socket ID=", socket.get_id()
window.connect("destroy", lambda w: gtk.main_quit())

def plugged_event(widget):
    print "I (", widget, ") have just had a plug inserted!"

socket.connect("plug-added", plugged_event)

if len(sys.argv) == 2:
    socket.add_id(long(sys.argv[1]))

gtk.main()

Chester (chrisinnanaimo) said : #4

Thanks you for the response and example.
In that example you seem to have to pass the XID manually to the socket program?
I'm certainly not an super experienced programmer so maybe I'm missing an easy way.
The way I patched Onboard is the way our project reparents other programs.

I patched Onboard to reparent it's self to a given window object:
This allows my program to load Onboard into it.
This is most of the code:

IN ONBoardGTK.py:

def reparent(window, parent):
    from Xlib import display
    from Xlib.xobject import drawable
    d = display.Display()
    w = drawable.Window(d.display, window.window.xid, 0)
    # Honor XEmbed spec
    atom = d.get_atom('_XEMBED_INFO')
    w.change_property(atom, atom, 32, [0, 1])
    w.reparent(parent, 0, 0)
    w.map()
    d.sync()

    def __init__(self, main=True):
        sys.path.append(os.path.join(config.install_dir, 'scripts'))

        # create main window
        if config.xid_mode: # XEmbed mode for gnome-screensaver?
            self._window = KbdPlugWindow()
            if config.destination_window:
                print "EMbed",config.destination_window
                reparent(self._window, config.destination_window)
            # write xid to stdout
            sys.stdout.write('%d\n' % self._window.get_id())
            sys.stdout.flush()
        else:
            self._window = KbdWindow()

In Config.py

        self.xid_mode = options.xid_mode
        self.destination_window = None
        if options.window:
            self.xid_mode = True
            self.destination_window = long(options.window, 0)
        _logger.debug("Leaving _init")

This is in the Ubuntu 10.04 version. (0.93...)
I would build a formal patch if you think you would accept it.
I would be happy if you would back port it to 12.04 :)

Thanks
Chris Morley

marmuta (marmuta) said : #5

I'm not sure we could maintain those changes. This would mean one more code path to test, debug, and keep in conformance with the XEmbed spec. Is there no way for your project to integrate a socket window? GTK has GtkSocket, I've heard Qt has something similar that should be compatible with Onboard.
Alternatively, have you tried to build your own simplified socket that does the reparenting? Run onboard --xid, read the window id from stdin and reparent it to wherever you need it in your project?

Launchpad Janitor (janitor) said : #6

This question was expired because it remained in the 'Open' state without activity for the last 15 days.

Chester (chrisinnanaimo) said : #7

I have got back to this and am having trouble reading the window id from standard input.
every time the process blocks my program.
sample:

    # shows 'Onboard' virtual keyboard if available
    def launch_keyboard(self,args="--xid",x="",y=""):
        print args,x,y
        try:
            self.data.ob = subprocess.Popen(["onboard",args,x,y],stdout=subprocess.PIPE,stdin=subprocess.PIPE)
            ins, outs, errs = self.data.ob.communicate()

            print "windowid =", ins,outs
        except:
            x
            print _("error with 'onboard' on screen keyboard program")

Can you suggest workable solution?

marmuta (marmuta) said : #8

Don't use communicate(), it blocks until Onboard exits. You can read from the stdout pipe directly instead. I've done something similar here:
http://bazaar.launchpad.net/~onboard/onboard/trunk/view/head:/Onboard/SpellChecker.py#L299
self._p is a process that keeps running in parallel with Onboard and it is written to/read from without blocking.

Chester (chrisinnanaimo) said : #9

Thanks alot ! I think that will do it.