[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