gobject-introspection r179 - in trunk: . giscanner tools



Author: johan
Date: Sat Apr 19 13:31:03 2008
New Revision: 179
URL: http://svn.gnome.org/viewvc/gobject-introspection?rev=179&view=rev

Log:
2008-04-19  Johan Dahlin  <johan gnome org>

        * giscanner/cgobject.py:
        * giscanner/gidlwriter.py:
        * giscanner/gobjecttreebuilder.py:
        * tools/g-ir-scanner:
        Start introspecting get-type functions.
        Implement support for GLib/GFlags GTypes.
        Add a ctype based GObject binding.



Added:
   trunk/giscanner/cgobject.py
   trunk/giscanner/gobjecttreebuilder.py
Modified:
   trunk/ChangeLog
   trunk/giscanner/gidlwriter.py
   trunk/tools/g-ir-scanner

Added: trunk/giscanner/cgobject.py
==============================================================================
--- (empty file)
+++ trunk/giscanner/cgobject.py	Sat Apr 19 13:31:03 2008
@@ -0,0 +1,149 @@
+# Poor mans GObject python bindings
+# Incidentally portable beyond CPython, due to usage of ctypes
+# Why not PyGObject?
+# - 1) Avoid PyGObject dependency
+# - 2) Low-level binding
+# - 3) Implementation independent
+# - 4) Usage lower in the stack
+#
+# based on defsgen.py (C) 2006 John Finlay
+#
+
+import ctypes
+
+# Constants
+
+TYPE_INVALID = 0
+TYPE_INTERFACE = 8
+TYPE_ENUM = 48
+TYPE_FLAGS = 52
+TYPE_STRING = 64
+TYPE_BOXED = 72
+TYPE_OBJECT = 80
+
+
+# Typedefs
+
+GType = ctypes.c_ulong
+
+
+# Structs
+
+class GTypeClass(ctypes.Structure):
+    _fields_ = [('g_type', GType)]
+
+
+class GTypeInstance(ctypes.Structure):
+    _fields_ = [('g_class', ctypes.POINTER(GTypeClass))]
+
+
+class GEnumValue(ctypes.Structure):
+    _fields_ = [('value', ctypes.c_int),
+                ('value_name', ctypes.c_char_p),
+                ('value_nick', ctypes.c_char_p)]
+
+
+class GFlagsValue(ctypes.Structure):
+    _fields_ = [('value', ctypes.c_uint),
+                ('value_name', ctypes.c_char_p),
+                ('value_nick', ctypes.c_char_p)]
+
+
+class GEnumClass(ctypes.Structure):
+    _fields_ = [('g_type_class',  GTypeClass),
+                ('minimum', ctypes.c_int),
+                ('maximum', ctypes.c_int),
+                ('n_values', ctypes.c_uint),
+                ('values', ctypes.POINTER(GEnumValue))]
+
+    def get_values(self):
+        for i in range(self.n_values):
+            yield self.values[i]
+
+
+class GFlagsClass(ctypes.Structure):
+    _fields_ = [('g_type_class', GTypeClass),
+               ('mask', ctypes.c_uint),
+               ('n_values', ctypes.c_uint),
+               ('values', ctypes.POINTER(GFlagsValue))]
+
+    def get_values(self):
+        for i in range(self.n_values):
+            yield self.values[i]
+
+
+class GTypeInterface(ctypes.Structure):
+    _fields_ = [('g_type', GType),
+                ('g_instance_type', GType)]
+
+
+class GParamSpec(ctypes.Structure):
+    _fields_ = [('g_type_instance', GTypeInstance),
+                ('name', ctypes.c_char_p),
+                ('flags', ctypes.c_uint),
+                ('value_type', GType),
+                ('owner_type', GType)]
+
+
+_gobj = ctypes.cdll.LoadLibrary('libgobject-2.0.so')
+_gobj.g_type_init()
+
+
+# Functions
+
+_gobj.g_type_name.restype = ctypes.c_char_p
+def type_name(type_id):
+    return _gobj.g_type_name(type_id)
+
+_gobj.g_type_from_name.argtypes = [ctypes.c_char_p]
+def type_from_name(name):
+    return _gobj.g_type_from_name(name)
+
+def type_fundamental(type_id):
+    return _gobj.g_type_fundamental(type_id)
+
+_gobj.g_type_class_ref.restype = ctypes.POINTER(GTypeClass)
+def type_class_ref(type_id):
+    fundamental_type = type_fundamental(type_id)
+    if fundamental_type == TYPE_INVALID:
+        return None
+    if fundamental_type == TYPE_ENUM:
+        typeclass = GEnumClass
+    elif fundamental_type == TYPE_FLAGS:
+        typeclass = GFlagsClass
+    else:
+        raise NotImplementedError(fundamental_type)
+    ptr = _gobj.g_type_class_ref(type_id)
+    return ctypes.cast(ptr, ctypes.POINTER(typeclass)).contents
+
+_gobj.g_object_class_list_properties.restype = ctypes.POINTER(
+    ctypes.POINTER(GParamSpec))
+def object_class_list_properties(type_id):
+    klass = _gobj.g_type_class_ref(type_id)
+    n = ctypes.c_uint()
+    pspecs = _gobj.g_object_class_list_properties(klass, ctypes.byref(n))
+    for i in range(n.value):
+        yield pspecs[i]
+
+_gobj.g_object_interface_list_properties.restype = ctypes.POINTER(
+    ctypes.POINTER(GParamSpec))
+def object_interface_list_properties(type_id):
+    iface = _gobj.g_type_default_interface_ref(type_id)
+    n = ctypes.c_uint()
+    pspecs = _gobj.g_object_interface_list_properties(iface, ctypes.byref(n))
+    for i in range(n.value):
+        yield pspecs[i]
+
+_gobj.g_type_interfaces.restype = ctypes.POINTER(ctypes.c_int)
+def type_interfaces(type_id):
+    n = ctypes.c_uint()
+    type_ids = _gobj.g_type_interfaces(type_id, ctypes.byref(n))
+    for i in range(n.value):
+        yield type_ids[i]
+
+_gobj.g_type_interface_prerequisites.restype = ctypes.POINTER(ctypes.c_int)
+def type_interface_prerequisites(type_id):
+    n = ctypes.c_uint()
+    type_ids = _gobj.g_type_interface_prerequisites(type_id, ctypes.byref(n))
+    for i in range(n.value):
+        yield type_ids[i]

Modified: trunk/giscanner/gidlwriter.py
==============================================================================
--- trunk/giscanner/gidlwriter.py	(original)
+++ trunk/giscanner/gidlwriter.py	Sat Apr 19 13:31:03 2008
@@ -1,7 +1,7 @@
+from giscanner.gobjecttreebuilder import GLibEnum, GLibEnumMember, GLibFlags
 from giscanner.treebuilder import Enum, Function
 from giscanner.xmlwriter import XMLWriter
 
-
 class GIDLWriter(XMLWriter):
     def __init__(self, namespace, nodes):
         super(GIDLWriter, self).__init__()
@@ -50,11 +50,21 @@
                                      ('type', parameter.type)])
 
     def _write_enum(self, enum):
-        self.push_tag('enum', [('name', enum.name)])
+        attrs = [('name', enum.name)]
+        tag_name = 'enum'
+        if isinstance(enum, GLibEnum):
+            attrs.append(('get-type', enum.get_type))
+            if isinstance(enum, GLibFlags):
+                tag_name = 'flags'
+
+        self.push_tag(tag_name, attrs)
         for member in enum.members:
             self._write_member(member)
         self.pop_tag()
 
     def _write_member(self, member):
-        self.write_tag('member', [('name', member.name),
-                                  ('value', str(member.value))])
+        attrs = [('name', member.name),
+                 ('value', str(member.value))]
+        if isinstance(member, GLibEnumMember):
+            attrs.append(('nick', member.nick))
+        self.write_tag('member', attrs)

Added: trunk/giscanner/gobjecttreebuilder.py
==============================================================================
--- (empty file)
+++ trunk/giscanner/gobjecttreebuilder.py	Sat Apr 19 13:31:03 2008
@@ -0,0 +1,103 @@
+import ctypes
+
+from giscanner.treebuilder import Enum, Function, Member, Struct
+from giscanner import cgobject
+
+
+class GLibEnum(Enum):
+    def __init__(self, name, members, get_type):
+        Enum.__init__(self, name, members)
+        self.get_type = get_type
+
+
+class GLibFlags(GLibEnum):
+    pass
+
+
+class GLibEnumMember(Member):
+    def __init__(self, name, value, nick):
+        Member.__init__(self, name, value)
+        self.nick = nick
+
+
+class GObjectTreeBuilder(object):
+    def __init__(self):
+        self.inputnodes = []
+        self.outputnodes = []
+        self._library = None
+
+    # Public API
+
+    def get_nodes(self):
+        return self.outputnodes
+
+    def load_library(self, libname):
+        self._library = ctypes.cdll.LoadLibrary(libname)
+
+    def parse(self, nodes):
+        nodes = list(nodes)
+        for node in nodes:
+            self._parse_node(node)
+
+    # Private
+
+    def _call_get_type_function(self, symbol_name):
+        func = getattr(self._library, symbol_name)
+        func.restype = cgobject.GType
+        func.argtypes = []
+        return func()
+
+    def _parse_node(self, node):
+        if isinstance(node, Enum):
+            self._parse_enum(node)
+        elif isinstance(node, Function):
+            self._parse_function(node)
+        elif isinstance(node, Struct):
+            self._parse_struct(node)
+        else:
+            print 'Unhandled node:', node
+
+    def _parse_enum(self, enum):
+        self.outputnodes.append(enum)
+
+    def _parse_function(self, func):
+        if (func.name.endswith('_get_type') and
+            func.retval.type == 'GType' and
+            not func.parameters):
+            symbol = func.name
+            type_id = self._call_get_type_function(symbol)
+            self._parse_gtype(type_id, symbol)
+            return
+        print 'todo', func
+
+    def _parse_struct(self, struct):
+        if (struct.name.startswith('_') or
+            struct.name.endswith('Iface') or
+            struct.name.endswith('Class')):
+            return
+        print 'todo', struct
+
+    def _parse_gtype(self, type_id, symbol):
+        fundamental_type_id = cgobject.type_fundamental(type_id)
+        if (fundamental_type_id == cgobject.TYPE_ENUM or
+            fundamental_type_id == cgobject.TYPE_FLAGS):
+            self._introspect_enum(fundamental_type_id, type_id, symbol)
+        #elif fundamental_type == cgobject.TYPE_OBJECT:
+        #    pass
+        else:
+            print 'unhandled GType: %s' % (cgobject.type_name(type_id),)
+
+    def _introspect_enum(self, ftype_id, type_id, symbol):
+        type_class = cgobject.type_class_ref(type_id)
+        if type_class is None:
+            return
+
+        members = []
+        for enum_value in type_class.get_values():
+            members.append(GLibEnumMember(enum_value.value_name,
+                                          enum_value.value,
+                                          enum_value.value_nick))
+
+        klass = (GLibFlags if ftype_id == cgobject.TYPE_FLAGS else GLibEnum)
+        cenum = klass(cgobject.type_name(type_id), members, symbol)
+        self.outputnodes.append(cenum)

Modified: trunk/tools/g-ir-scanner
==============================================================================
--- trunk/tools/g-ir-scanner	(original)
+++ trunk/tools/g-ir-scanner	Sat Apr 19 13:31:03 2008
@@ -5,6 +5,7 @@
 sys.path.insert(0, '.')
 
 from giscanner.gidlwriter import GIDLWriter
+from giscanner.gobjecttreebuilder import GObjectTreeBuilder
 from giscanner.sourcescanner import SourceScanner
 from giscanner.treebuilder import TreeBuilder
 
@@ -16,6 +17,9 @@
     parser.add_option("-n", "--namespace",
                       action="store", dest="namespace",
                       help="namespace of this unit")
+    parser.add_option("-l", "--library",
+                      action="store", dest="library",
+                      help="library of this unit")
 
     group = optparse.OptionGroup(parser, "Preprocessor options")
     group.add_option("-I", help="Pre-processor include file",
@@ -47,7 +51,10 @@
         ss.parse_file(filename)
     ss.parse_macros()
 
-    builder = TreeBuilder(ss)
+    builder = GObjectTreeBuilder()
+    builder.load_library(options.library)
+    builder.parse(TreeBuilder(ss).get_nodes())
+
     writer = GIDLWriter(options.namespace, builder.get_nodes())
     print writer.get_xml()
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]