[webkit-dev] getting and setting a pointer to a c++ class in a multi-level glib object hierarchy

Luke Kenneth Casson Leighton lkcl at lkcl.net
Mon Aug 25 10:09:28 PDT 2008


folks, hi,
i have a particularly horrendous implementation requirement that i can't
quite get my head round and need some gobject advice for the webkit-gtk
implementation to provide DOM access (which will then percolate to pywebkitgtk).
webkit's c++ DOM object hierarchy is multi-level, is inherited (as best
i can tell) from a virtual base class, Node, and comprises a whopping
_four hundred_ individual classes derived, ultimately, from that base class .

i've written an auto-generator to create the glib-object-based code for all
of these classes: and, btw, i can _thoroughly_ recommend the use of this
code for other projects: it's _not_ just a tool that should stay in webkit,
it's generic enough to used elsewhere.

the problem i am having is best illustrated with an example.  i managed
to get everything compiled and working yesterday, enough to test with this
code, in pywebkitgtk:

doc = main_frame.get_document() # equivalent to document in javascript
txtnode = doc.create_text_node('hello world') # equivalent to createTextNode
doc.append_child(txtnode) # equivalent to doc.appendChild in javascript

the "append_child" is where it all goes horribly wrong: here's why.
doc is of glib type GDOM_TYPE_DOCUMENT, and, naively on my part it contains a
"private" pointer to a c++ "Document" class from webkit.
GDOMDocument is a glib object that inherits from a GDOMNode glib
object, which in turn inherits from a GDOMObject glib object.

likewise, txtnode is of glib type GDOM_TYPE_TEXT_NODE which also happens
to inherit from GDOM_TYPE_NODE which inherits from type GDOM_DOM_OBJECT
which inherits from G_OBJECT.

each and every single GDOM_TYPE_XXX has a "priv" private pointer to its
c++ class - and that turns out to be my mistake.

the reason?  Document::appendChild() takes a Node* - the virtual base
class - as its argument.  and, because append_child is all the way down
at the GDOM_TYPE_NODE glib object level, _guess_ which one of the "priv"
pointer functions gets called to "get" a private member, and guess
which one of the "priv" pointer functions will have been called to _set_
the private member?

when the text node was created, _only_ the gdom_text_node_set_private()
was called, setting a priv member that is exclusive and private to
GDOM_TYPE_TEXT_NODE, and when append_child is called, it's called at
the GDOM_TYPE_NODE, level, resulting in gdom_node_get_private() getting
called (not gdom_text_node_get_private()), which returns... of course...
NULL!

so - this is where i'm a bit lost.

looking at the tutorials i was kindly referred to, there are "abstract
methods" which at first sight look suitable.  however, i can't quite
work out if they can be multi-layer-inherited.  G_DEFINE_ABSTRACT_TYPE
describes how to create an abstract method "super_human_eat", which
is passed in a pointer to a NatureHuman* - not a SuperHuman*.

i need to be able to call the *same* function at each level of the
glib inheritance structure, back down at the "GDOM_TYPE_DOM_OBJECT" base
glib object, which will store a "priv" private member pointer to
the c++ virtual base class (Node*).

the "Interfaces" example looks suitable for what i need but...
i've looked at the "Interfaces" example - and i don't get it.  there
doesn't appear to be a way to store "data" - the example only shows
a method "move".

any help greatly appreciated - this is something really quite obscure
that is easy enough to do in c++ and python.

oh.

duh.

of course.

if i describe what i need in python, perhaps someone can tell me how
it's implemented using Glib Objects?

# base class
class Node:

   def __init__(self):
      self.children = []
      self.parent = None

   def appendChild(self, child):
      self.children.append(child)

   def set_parent(self, parent):
      self.parent = parent

class TextNode(Node):

    def __init__(self, txt):
        Node.__init__(self)
        self.txt = txt

class Document(Node):
   def createTextNode(self, txt):
       tn = TextNode(txt)
       tn.set_parent(self)
       return tn

that's the "implementation" - in c++

this is the GLIB object structure:

class GObject:
    pass

class gdomDOMObject(GObject):
   def __init__(self):
       self.priv = None
   def set_private(self, priv):
       self.priv = priv
   def get_private(self):
       return self.priv

class gdomNode(gdomDOMObject):
   def append_child(self, child):
       self.priv.appendChild(child.get_private())

class gdomDocument(gdomNode):
   def create_text_node(self, text):
       tn = self.priv.createTextNode(text)
       gtn = gdomTextNode()
       gtn.set_private(tn)
       return gtn

that's what i _really_ want - but i've made the mistake of doing "the
equivalent" - in glib object terms - of this:

class gdomNode(gdomDOMObject):
   def __init__(self):
       self.priv = None
   def set_private(self, priv):
       self.priv = priv
   def get_private(self):
       return self.priv
   def append_child(self, child):
       self.priv.appendChild(child.get_private())

class gdomDocument(gdomNode):
   def __init__(self):
       self.priv = None
   def set_private(self, priv):
       self.priv = priv
   def get_private(self):
       return self.priv
   def create_text_node(self, text):
       tn = self.priv.createTextNode(text)
       gtn = gdomTextNode()
       gtn.set_private(tn)
       return gtn

so, consequently, each set_private and get_private method returns
rubbish, when in fact, in glib/gobject terms, i want the set_private
and get_private of the GDOM_TYPE_DOM_OBJECT - but at *every* level.

help!

l.



More information about the webkit-dev mailing list