summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gi/.gitignore40
-rw-r--r--gi/HACKING26
-rw-r--r--gi/Makefile.am67
-rw-r--r--gi/__init__.py24
-rw-r--r--gi/demos/gtk-demo/demos/__init__.py0
-rw-r--r--gi/demos/gtk-demo/demos/appwindow.py411
-rw-r--r--gi/demos/gtk-demo/demos/assistant.py134
-rw-r--r--gi/demos/gtk-demo/demos/builder.py57
-rw-r--r--gi/demos/gtk-demo/demos/button_box.py121
-rw-r--r--gi/demos/gtk-demo/demos/clipboard.py238
-rw-r--r--gi/demos/gtk-demo/demos/colorselector.py121
-rw-r--r--gi/demos/gtk-demo/demos/combobox.py282
-rw-r--r--gi/demos/gtk-demo/demos/data/alphatest.pngbin0 -> 26529 bytes
-rw-r--r--gi/demos/gtk-demo/demos/data/apple-red.pngbin0 -> 3545 bytes
-rw-r--r--gi/demos/gtk-demo/demos/data/background.jpgbin0 -> 22219 bytes
-rw-r--r--gi/demos/gtk-demo/demos/data/demo.ui258
-rw-r--r--gi/demos/gtk-demo/demos/data/floppybuddy.gifbin0 -> 5216 bytes
-rw-r--r--gi/demos/gtk-demo/demos/data/gnome-applets.pngbin0 -> 3090 bytes
-rw-r--r--gi/demos/gtk-demo/demos/data/gnome-calendar.pngbin0 -> 2755 bytes
-rw-r--r--gi/demos/gtk-demo/demos/data/gnome-foot.pngbin0 -> 2916 bytes
-rw-r--r--gi/demos/gtk-demo/demos/data/gnome-fs-directory.pngbin0 -> 2044 bytes
-rw-r--r--gi/demos/gtk-demo/demos/data/gnome-fs-regular.pngbin0 -> 1795 bytes
-rw-r--r--gi/demos/gtk-demo/demos/data/gnome-gimp.pngbin0 -> 3410 bytes
-rw-r--r--gi/demos/gtk-demo/demos/data/gnome-gmush.pngbin0 -> 3244 bytes
-rw-r--r--gi/demos/gtk-demo/demos/data/gnome-gsame.pngbin0 -> 4263 bytes
-rw-r--r--gi/demos/gtk-demo/demos/data/gnu-keys.pngbin0 -> 3852 bytes
-rw-r--r--gi/demos/gtk-demo/demos/data/gtk-logo-rgb.gifbin0 -> 6427 bytes
-rw-r--r--gi/demos/gtk-demo/demos/test.py14
-rwxr-xr-xgi/demos/gtk-demo/gtk-demo.py266
-rw-r--r--gi/examples/Makefile.am2
-rwxr-xr-xgi/examples/cairo-demo.py121
-rw-r--r--gi/gimodule.c297
-rw-r--r--gi/importer.py85
-rw-r--r--gi/module.py216
-rw-r--r--gi/overrides/GIMarshallingTests.py69
-rw-r--r--gi/overrides/Gdk.py77
-rw-r--r--gi/overrides/Gtk.py250
-rw-r--r--gi/overrides/Makefile.am12
-rw-r--r--gi/overrides/__init__.py0
-rw-r--r--gi/overrides/keysyms.py1499
-rw-r--r--gi/pygi-argument.c1956
-rw-r--r--gi/pygi-argument.h66
-rw-r--r--gi/pygi-boxed.c196
-rw-r--r--gi/pygi-boxed.h40
-rw-r--r--gi/pygi-callbacks.c223
-rw-r--r--gi/pygi-callbacks.h48
-rw-r--r--gi/pygi-closure.c399
-rw-r--r--gi/pygi-closure.h57
-rw-r--r--gi/pygi-foreign-cairo.c103
-rw-r--r--gi/pygi-foreign-cairo.h55
-rw-r--r--gi/pygi-foreign.c125
-rw-r--r--gi/pygi-foreign.h52
-rw-r--r--gi/pygi-info.c1518
-rw-r--r--gi/pygi-info.h66
-rw-r--r--gi/pygi-invoke.c1003
-rw-r--r--gi/pygi-invoke.h37
-rw-r--r--gi/pygi-private.h59
-rw-r--r--gi/pygi-repository.c238
-rw-r--r--gi/pygi-repository.h39
-rw-r--r--gi/pygi-struct.c169
-rw-r--r--gi/pygi-struct.h40
-rw-r--r--gi/pygi-type.c96
-rw-r--r--gi/pygi-type.h43
-rw-r--r--gi/pygi.h105
-rw-r--r--gi/pygobject-external.h83
-rw-r--r--gi/repository/Makefile.am8
-rw-r--r--gi/repository/__init__.py30
-rw-r--r--gi/tests/Makefile.am22
-rw-r--r--gi/tests/runtests.py21
-rw-r--r--gi/tests/test_everything.py270
-rw-r--r--gi/tests/test_gi.py1624
-rw-r--r--gi/tests/test_overrides.py132
-rw-r--r--gi/types.py180
-rwxr-xr-xpre-commit.hook39
-rw-r--r--pygi-Makefile.am28
-rw-r--r--pygi-configure.ac60
-rw-r--r--pygi-convert.sh152
-rw-r--r--pygi.doap34
78 files changed, 14103 insertions, 0 deletions
diff --git a/gi/.gitignore b/gi/.gitignore
new file mode 100644
index 00000000..24694626
--- /dev/null
+++ b/gi/.gitignore
@@ -0,0 +1,40 @@
+.libs/
+.deps/
+/COPYING
+Makefile
+Makefile.in
+/aclocal.m4
+/autom4te.cache/
+/config.guess
+/config.h
+/config.h.in
+/config.log
+/config.status
+/config.sub
+/configure
+/depcomp
+/install-sh
+/libtool
+/ltmain.sh
+/m4/
+/missing
+/py-compile
+/pygi-*.tar.gz
+/stamp-h1
+
+*.o
+*.lo
+*.la
+*.so
+*.pyc
+*.gir
+*.typelib
+
+.*.swp
+
+*~
+*.orig
+*.rej
+
+tests/tmp-introspect*
+
diff --git a/gi/HACKING b/gi/HACKING
new file mode 100644
index 00000000..b6260a8c
--- /dev/null
+++ b/gi/HACKING
@@ -0,0 +1,26 @@
+Tests
+===
+
+'make check' execute all tests
+
+'make check TEST_NAMES="test_gi"' executes the tests in test_gi.py
+
+'make check TEST_NAMES="test_gi.TestUtf8"' executes the tests in test_gi.TestUtf8
+
+'make check TEST_NAMES="test_gi.TestUtf8.test_utf8_full_return"' executes the test_gi.TestUtf8.test_utf8_full_return test
+
+'make check.gdb' executes all the tests in a gdb session
+
+'make test_gi.TestUtf8.gdb' executes all the tests in test_gi.TestUtf8 in a gdb session
+
+'make check.valgrind' executes all the tests in valgrind
+
+'make test_gi.TestUtf8.valgrind' executes all the tests in test_gi.TestUtf8 in valgrind
+
+Releasing
+===
+* Bump version in configure.ac
+* Commit & Tag
+* Make distcheck
+* Upload tarball to git servers
+* Email PyGTK-announce & gnome-release mailing list
diff --git a/gi/Makefile.am b/gi/Makefile.am
new file mode 100644
index 00000000..8efe0511
--- /dev/null
+++ b/gi/Makefile.am
@@ -0,0 +1,67 @@
+PLATFORM_VERSION = 2.0
+
+pkgincludedir = $(includedir)/pygtk-$(PLATFORM_VERSION)
+pkgpyexecdir = $(pyexecdir)/gtk-2.0
+
+SUBDIRS = \
+ repository \
+ overrides
+AM_CFLAGS = \
+ $(PYTHON_INCLUDES) \
+ $(GNOME_CFLAGS) \
+ $(PYCAIRO_CFLAGS)
+
+pygidir = $(pkgpyexecdir)/gi
+pygi_PYTHON = \
+ types.py \
+ module.py \
+ importer.py \
+ __init__.py
+
+_gi_la_LDFLAGS = \
+ -module \
+ -avoid-version \
+ -export-symbols-regex init_gi
+_gi_la_LIBADD = \
+ $(GNOME_LIBS) \
+ $(PYCAIRO_LIBS)
+_gi_la_SOURCES = \
+ pygi-repository.c \
+ pygi-repository.h \
+ pygi-info.c \
+ pygi-info.h \
+ pygi-invoke.c \
+ pygi-invoke.h \
+ pygi-foreign.c \
+ pygi-foreign.h \
+ pygi-foreign-cairo.c \
+ pygi-foreign-cairo.h \
+ pygi-struct.c \
+ pygi-struct.h \
+ pygi-argument.c \
+ pygi-argument.h \
+ pygi-type.c \
+ pygi-type.h \
+ pygi-boxed.c \
+ pygi-boxed.h \
+ pygi-closure.c \
+ pygi-closure.h \
+ pygi-callbacks.c \
+ pygi-callbacks.h \
+ pygi.h \
+ pygi-private.h \
+ pygobject-external.h \
+ gimodule.c
+
+pygi_LTLIBRARIES = _gi.la
+
+# This is to ensure we have a symlink to the .so in the
+# build directory, which the Python interpreter can load
+# directly without having to know how to parse .la files.
+_gi.so: _gi.la
+ rm -f $@ && $(LN_S) .libs/$@ $@
+
+all-local: _gi.so
+clean-local:
+ rm -f _gi.so
+
diff --git a/gi/__init__.py b/gi/__init__.py
new file mode 100644
index 00000000..3edea9f0
--- /dev/null
+++ b/gi/__init__.py
@@ -0,0 +1,24 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+from __future__ import absolute_import
+
+from ._gi import _API
+
diff --git a/gi/demos/gtk-demo/demos/__init__.py b/gi/demos/gtk-demo/demos/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/__init__.py
diff --git a/gi/demos/gtk-demo/demos/appwindow.py b/gi/demos/gtk-demo/demos/appwindow.py
new file mode 100644
index 00000000..eb70705d
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/appwindow.py
@@ -0,0 +1,411 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2010 Red Hat, Inc., John (J5) Palmieri <johnp@redhat.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+title = "Application main window"
+description = """
+Demonstrates a typical application window with menubar, toolbar, statusbar.
+"""
+
+# See FIXME's
+is_fully_bound = False
+
+from gi.repository import Gtk, GdkPixbuf, Gdk
+import sys, os
+
+global infobar
+global window
+global messagelabel
+
+def widget_destroy(widget, button):
+ widget.destroy()
+
+def activate_action(action):
+ global window
+
+ name = action.get_name()
+ _type = type(action)
+ if name == 'DarkTheme':
+ value = action.get_active()
+ settings = Gtk.Settings.get_default()
+ settings.set_property('gtk-application-prefer-dark-theme', value)
+ return
+
+
+ dialog = Gtk.MessageDialog(message_type=Gtk.MessageType.INFO,
+ buttons=Gtk.ButtonsType.CLOSE,
+ text='You activated action: "%s" of type %s' % (name, _type))
+
+ # FIXME: this should be done in the constructor
+ dialog.set_transient_for(window)
+ dialog.connect('response', widget_destroy)
+ dialog.show()
+
+def activate_radio_action(action, current):
+ global infobar
+ global messagelabel
+
+ name = current.get_name()
+ _type = type(current)
+ active = current.get_active()
+ value = current.get_current_value()
+ if active:
+ text = 'You activated radio action: "%s" of type %s.\n Current value: %d' % (name, _type, value)
+ messagelabel.set_text(text)
+ infobar.set_message_type(Gtk.MessageType(value))
+ infobar.show()
+
+def update_statusbar(buffer, statusbar):
+ statusbar.pop(0)
+ count = buffer.get_char_count()
+
+ iter = buffer.get_iter_at_mark(buffer.get_insert())
+ row = iter.get_line()
+ col = iter.get_line_offset()
+ msg = 'Cursor at row %d column %d - %d chars in document' % (row, col, count)
+
+ statusbar.push(0, msg)
+
+def mark_set_callback(buffer, new_location, mark, data):
+ update_statusbar(buffer, data)
+
+def update_resize_grip(widget, event, statusbar):
+ pass
+ # FIXME: event should be a Gdk.EventWindowState but is only a Gdk.Event
+ if event.changed_mask and (Gdk.WindowState.MAXIMIZED or
+ Gdk.WindowState.FULLSCREEN):
+
+ maximized = event.new_window_state and (Gdk.WindowState.MAXIMIZED or
+ Gdk.WindowState.FULLSCREEN)
+ statusbar.set_has_resize_grip(not maximized)
+
+def activate_email(about, link, data):
+ text = 'send mail to %s' % (link,)
+ print text
+
+def activate_url(about, link, data):
+ text = 'show url %s' % (link,)
+ print text
+
+def about_cb(widget):
+ global window
+
+ authors = ['John (J5) Palmieri',
+ 'Tomeu Vizoso',
+ 'and many more...']
+
+ documentors = ['David Malcolm',
+ 'Zack Goldberg',
+ 'and many more...']
+
+ license = """
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the Gnome Library; see the file COPYING.LIB. If not,
+write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+"""
+ filename = os.path.join('data', 'gtk-logo-rgb.gif')
+ pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename)
+ transparent = pixbuf.add_alpha(True, 0xff, 0xff, 0xff)
+ Gtk.AboutDialog.set_email_hook(activate_email, None)
+ Gtk.AboutDialog.set_url_hook(activate_url, None)
+ # FIXME: override Gtk.show_about_dialog
+ # make about dailog constructor take a parent argument
+ about = Gtk.AboutDialog(program_name='GTK+ Code Demos',
+ version='0.1',
+ copyright='(C) 2010 The PyGI Team',
+ license=license,
+ website='http://live.gnome.org/PyGI',
+ comments='Program to demonstrate PyGI functions.',
+ authors=authors,
+ documenters=documentors,
+ logo=transparent,
+ title='About GTK+ Code Demos')
+
+ about.set_transient_for(window)
+ about.connect('response', widget_destroy)
+ about.show()
+
+
+action_entries = (
+ ("FileMenu", None, "_File"), # name, stock id, label
+ ("OpenMenu", None, "_Open"), # name, stock id, label
+ ("PreferencesMenu", None, "_Preferences"), # name, stock id, label
+ ("ColorMenu", None, "_Color"), # name, stock id, label
+ ("ShapeMenu", None, "_Shape"), # name, stock id, label
+ ("HelpMenu", None, "_Help"), # name, stock id, label
+ ("New", Gtk.STOCK_NEW, # name, stock id
+ "_New", "<control>N", # label, accelerator
+ "Create a new file", # tooltip
+ activate_action),
+ ("File1", None, # name, stock id
+ "File1", None, # label, accelerator
+ "Open first file", # tooltip
+ activate_action),
+ ("Save", Gtk.STOCK_SAVE, # name, stock id
+ "_Save","<control>S", # label, accelerator
+ "Save current file", # tooltip
+ activate_action),
+ ("SaveAs", Gtk.STOCK_SAVE, # name, stock id
+ "Save _As...", None, # label, accelerator
+ "Save to a file", # tooltip
+ activate_action),
+ ("Quit", Gtk.STOCK_QUIT, # name, stock id
+ "_Quit", "<control>Q", # label, accelerator
+ "Quit", # tooltip
+ activate_action),
+ ("About", None, # name, stock id
+ "_About", "<control>A", # label, accelerator
+ "About", # tooltip
+ about_cb),
+ ("Logo", "demo-gtk-logo", # name, stock id
+ None, None, # label, accelerator
+ "GTK+", # tooltip
+ activate_action),
+)
+
+toggle_action_entries = (
+ ("Bold", Gtk.STOCK_BOLD, # name, stock id
+ "_Bold", "<control>B", # label, accelerator
+ "Bold", # tooltip
+ activate_action,
+ True), # is_active
+ ("DarkTheme", None, # name, stock id
+ "_Prefer Dark Theme", None, # label, accelerator
+ "Prefer Dark Theme", # tooltip
+ activate_action,
+ False), # is_active
+)
+
+(COLOR_RED,
+ COLOR_GREEN,
+ COLOR_BLUE) = range(3)
+
+color_action_entries = (
+ ("Red", None, # name, stock id
+ "_Red", "<control>R", # label, accelerator
+ "Blood", COLOR_RED), # tooltip, value
+ ("Green", None, # name, stock id
+ "_Green", "<control>G", # label, accelerator
+ "Grass", COLOR_GREEN), # tooltip, value
+ ("Blue", None, # name, stock id
+ "_Blue", "<control>B", # label, accelerator
+ "Sky", COLOR_BLUE), # tooltip, value
+)
+
+(SHAPE_SQUARE,
+ SHAPE_RECTANGLE,
+ SHAPE_OVAL) = range(3)
+
+shape_action_entries = (
+ ("Square", None, # name, stock id
+ "_Square", "<control>S", # label, accelerator
+ "Square", SHAPE_SQUARE), # tooltip, value
+ ("Rectangle", None, # name, stock id
+ "_Rectangle", "<control>R", # label, accelerator
+ "Rectangle", SHAPE_RECTANGLE), # tooltip, value
+ ("Oval", None, # name, stock id
+ "_Oval", "<control>O", # label, accelerator
+ "Egg", SHAPE_OVAL ), # tooltip, value
+)
+
+ui_info = """
+<ui>
+ <menubar name='MenuBar'>
+ <menu action='FileMenu'>
+ <menuitem action='New'/>
+ <menuitem action='Open'/>
+ <menuitem action='Save'/>
+ <menuitem action='SaveAs'/>
+ <separator/>
+ <menuitem action='Quit'/>
+ </menu>
+ <menu action='PreferencesMenu'>
+ <menuitem action='DarkTheme'/>
+ <menu action='ColorMenu'>
+ <menuitem action='Red'/>
+ <menuitem action='Green'/>
+ <menuitem action='Blue'/>
+ </menu>
+ <menu action='ShapeMenu'>
+ <menuitem action='Square'/>
+ <menuitem action='Rectangle'/>
+ <menuitem action='Oval'/>
+ </menu>
+ <menuitem action='Bold'/>
+ </menu>
+ <menu action='HelpMenu'>
+ <menuitem action='About'/>
+ </menu>
+ </menubar>
+ <toolbar name='ToolBar'>
+ <toolitem action='Open'>
+ <menu action='OpenMenu'>
+ <menuitem action='File1'/>
+ </menu>
+ </toolitem>
+ <toolitem action='Quit'/>
+ <separator action='Sep1'/>
+ <toolitem action='Logo'/>
+ </toolbar>
+</ui>
+"""
+
+def _quit(*args):
+ Gtk.main_quit()
+
+def register_stock_icons():
+ """
+ This function registers our custom toolbar icons, so they can be themed.
+ It's totally optional to do this, you could just manually insert icons
+ and have them not be themeable, especially if you never expect people
+ to theme your app.
+ """
+ '''
+ item = Gtk.StockItem()
+ item.stock_id = 'demo-gtk-logo'
+ item.label = '_GTK!'
+ item.modifier = 0
+ item.keyval = 0
+ item.translation_domain = None
+
+ Gtk.stock_add(item, 1)
+ '''
+
+ factory = Gtk.IconFactory()
+ factory.add_default()
+ filename = os.path.join('data', 'gtk-logo-rgb.gif')
+ pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename)
+ transparent = pixbuf.add_alpha(True, 0xff, 0xff, 0xff)
+ icon_set = Gtk.IconSet.new_from_pixbuf(transparent)
+
+ factory.add('demo-gtk-logo', icon_set)
+
+class ToolMenuAction(Gtk.Action):
+ __gtype_name__ = "GtkToolMenuAction"
+ def do_create_tool_item(self):
+ return Gtk.MenuToolButton()
+
+def main():
+ global infobar
+ global window
+ global messagelabel
+
+ register_stock_icons()
+
+ window = Gtk.Window()
+ window.set_title('Application Window')
+ window.set_icon_name('gtk-open')
+ window.connect_after('destroy', _quit)
+ table = Gtk.Table(n_rows=1,
+ n_columns=5,
+ homogeneous=False)
+ window.add(table)
+
+ action_group = Gtk.ActionGroup(name='AppWindowActions')
+ open_action = ToolMenuAction(name = 'Open',
+ stock_id = Gtk.STOCK_OPEN,
+ label = '_Open',
+ tooltip = 'Open a file')
+
+ action_group.add_action(open_action)
+ action_group.add_actions(action_entries)
+ action_group.add_toggle_actions(toggle_action_entries)
+ action_group.add_radio_actions(color_action_entries,
+ COLOR_RED,
+ activate_radio_action)
+ action_group.add_radio_actions(shape_action_entries,
+ SHAPE_SQUARE,
+ activate_radio_action)
+
+ merge = Gtk.UIManager()
+ merge.insert_action_group(action_group, 0)
+ window.add_accel_group(merge.get_accel_group())
+
+ merge.add_ui_from_string(ui_info)
+
+ bar = merge.get_widget('/MenuBar')
+ bar.show()
+ table.attach(bar, 0, 1, 0, 1,
+ Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL,
+ 0, 0, 0)
+
+ bar = merge.get_widget('/ToolBar')
+ bar.show()
+ table.attach(bar, 0, 1, 1, 2,
+ Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL,
+ 0, 0, 0)
+
+
+ infobar = Gtk.InfoBar();
+ infobar.set_no_show_all(True)
+ messagelabel = Gtk.Label()
+ messagelabel.show()
+ infobar.get_content_area().pack_start(messagelabel, True, True, 0)
+ infobar.add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK)
+ infobar.connect('response', lambda a, b: Gtk.Widget.hide(a))
+
+ table.attach(infobar, 0, 1, 2, 3,
+ Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL,
+ 0, 0, 0)
+
+ sw = Gtk.ScrolledWindow(hadjustment=None,
+ vadjustment=None)
+ sw.set_shadow_type(Gtk.ShadowType.IN)
+ table.attach(sw, 0, 1, 3, 4,
+ Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL,
+ Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL,
+ 0, 0)
+
+ contents = Gtk.TextView()
+ contents.grab_focus()
+ sw.add(contents)
+
+ # Create statusbar
+ statusbar = Gtk.Statusbar()
+ table.attach(statusbar, 0, 1, 4, 5,
+ Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL,
+ 0, 0, 0)
+
+ # show text widget info in the statusbar
+ buffer = contents.get_buffer()
+ buffer.connect('changed', update_statusbar, statusbar)
+ buffer.connect('mark_set', mark_set_callback, statusbar)
+
+ window.connect('window_state_event', update_resize_grip, statusbar)
+
+ update_statusbar(buffer, statusbar);
+
+ window.set_default_size(200, 200)
+ window.show_all()
+ Gtk.main()
+
+if __name__ == '__main__':
+ main()
diff --git a/gi/demos/gtk-demo/demos/assistant.py b/gi/demos/gtk-demo/demos/assistant.py
new file mode 100644
index 00000000..3d6f1bfd
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/assistant.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2010 Red Hat, Inc., John (J5) Palmieri <johnp@redhat.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+title = "Assistant"
+description = """
+Demonstrates a sample multistep assistant. Assistants are used to divide
+an operation into several simpler sequential steps, and to guide the user
+through these steps.
+"""
+
+# See FIXME's
+is_fully_bound = True
+
+from gi.repository import Gtk, GdkPixbuf
+
+class AssistantApp:
+ def __init__(self):
+ self.assistant = Gtk.Assistant()
+ self.assistant.set_default_size(-1, 300)
+
+ self.create_page1()
+ self.create_page2()
+ self.create_page3()
+
+ self.assistant.connect('cancel', self.on_close_cancel)
+ self.assistant.connect('close', self.on_close_cancel)
+ self.assistant.connect('apply', self.on_apply)
+ self.assistant.connect('prepare', self.on_prepare)
+
+ self.assistant.show()
+
+ def on_close_cancel(self, assistant):
+ assistant.destroy()
+ Gtk.main_quit()
+
+ def on_apply(self, assistant):
+ # apply changes here; this is a fictional example so just do
+ # nothing here
+ pass
+
+ def on_prepare(self, assistant, page):
+ current_page = assistant.get_current_page()
+ n_pages = assistant.get_n_pages()
+ title = 'Sample assistant (%d of %d)' % (current_page + 1, n_pages)
+ assistant.set_title(title)
+
+ def on_entry_changed(self, widget):
+ page_number = self.assistant.get_current_page()
+ current_page = self.assistant.get_nth_page(page_number)
+ text = widget.get_text()
+
+ if text:
+ self.assistant.set_page_complete(current_page, True)
+ else:
+ self.assistant.set_page_complete(current_page, False)
+
+ def create_page1(self):
+ box = Gtk.HBox(homogeneous=False,
+ spacing=12)
+ box.set_border_width(12)
+ label = Gtk.Label(label='You must fill out this entry to continue:')
+ box.pack_start(label, False, False, 0)
+
+ entry = Gtk.Entry()
+ box.pack_start(entry, True, True, 0)
+ entry.connect('changed', self.on_entry_changed)
+
+ box.show_all()
+ self.assistant.append_page(box)
+ self.assistant.set_page_title(box, 'Page 1')
+ self.assistant.set_page_type(box, Gtk.AssistantPageType.INTRO)
+
+ pixbuf = self.assistant.render_icon(Gtk.STOCK_DIALOG_INFO,
+ Gtk.IconSize.DIALOG,
+ None)
+
+ self.assistant.set_page_header_image(box, pixbuf)
+
+ def create_page2(self):
+ box = Gtk.VBox(homogeneous=False,
+ spacing=12)
+ box.set_border_width(12)
+
+ checkbutton = Gtk.CheckButton(label='This is optional data, you may continue even if you do not check this')
+ box.pack_start(checkbutton, False, False, 0)
+
+ box.show_all()
+
+ self.assistant.append_page(box)
+ self.assistant.set_page_complete(box, True)
+ self.assistant.set_page_title(box, 'Page 2')
+
+ pixbuf = self.assistant.render_icon(Gtk.STOCK_DIALOG_INFO,
+ Gtk.IconSize.DIALOG,
+ None)
+ self.assistant.set_page_header_image(box, pixbuf)
+
+ def create_page3(self):
+ label = Gtk.Label(label='This is a confirmation page, press "Apply" to apply changes')
+ label.show()
+ self.assistant.append_page(label)
+ self.assistant.set_page_complete(label, True)
+ self.assistant.set_page_title(label, 'Confirmation')
+ self.assistant.set_page_type(label, Gtk.AssistantPageType.CONFIRM)
+
+ pixbuf = self.assistant.render_icon(Gtk.STOCK_DIALOG_INFO,
+ Gtk.IconSize.DIALOG,
+ None)
+ self.assistant.set_page_header_image(label, pixbuf)
+
+def main():
+ app = AssistantApp()
+ Gtk.main()
+
+if __name__ == '__main__':
+ main()
diff --git a/gi/demos/gtk-demo/demos/builder.py b/gi/demos/gtk-demo/demos/builder.py
new file mode 100644
index 00000000..d72ce51d
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/builder.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2010 Red Hat, Inc., John (J5) Palmieri <johnp@redhat.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+title = "Builder"
+description = """
+Demonstrates an interface loaded from a XML description.
+"""
+
+# See FIXME's
+is_fully_bound = True
+
+from gi.repository import Gtk, GdkPixbuf, Gdk
+import os
+
+class BuilderApp:
+ def __init__(self):
+ self.builder = Gtk.Builder()
+ filename = os.path.join('data', 'demo.ui')
+ self.builder.add_from_file(filename)
+ self.builder.connect_signals(self)
+
+ window = self.builder.get_object('window1')
+ window.connect('destroy', lambda x: Gtk.main_quit())
+ window.show_all()
+
+ def about_activate(self, action):
+ about_dlg = self.builder.get_object('aboutdialog1')
+ about_dlg.run()
+ about_dlg.hide()
+
+ def quit_activate(self, action):
+ Gtk.main_quit()
+
+def main():
+ app = BuilderApp()
+ Gtk.main()
+
+if __name__ == '__main__':
+ main()
diff --git a/gi/demos/gtk-demo/demos/button_box.py b/gi/demos/gtk-demo/demos/button_box.py
new file mode 100644
index 00000000..dfbcf194
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/button_box.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2010 Red Hat, Inc., John (J5) Palmieri <johnp@redhat.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+title = "Button Boxes"
+description = """
+The Button Box widgets are used to arrange buttons with padding.
+"""
+
+# See FIXME's
+is_fully_bound = False
+
+from gi.repository import Gtk
+
+class ButtonBoxApp:
+ def __init__(self):
+ window = Gtk.Window()
+ window.set_title('Button Boxes')
+ window.connect('destroy', lambda x: Gtk.main_quit())
+ window.set_border_width(10)
+
+ main_vbox = Gtk.VBox(homogeneous=False, spacing=0)
+ window.add(main_vbox)
+
+ frame_horz = Gtk.Frame(label='Horizontal Button Boxes')
+ main_vbox.pack_start(frame_horz, True, True, 10)
+
+ vbox = Gtk.VBox(homogeneous=False, spacing=0)
+ vbox.set_border_width(10)
+ frame_horz.add(vbox)
+
+ vbox.pack_start(
+ self.create_bbox(True, 'Spread', 40, Gtk.ButtonBoxStyle.SPREAD),
+ True, True, 0)
+
+ vbox.pack_start(
+ self.create_bbox(True, 'Edge', 40, Gtk.ButtonBoxStyle.EDGE),
+ True, True, 5)
+
+ vbox.pack_start(
+ self.create_bbox(True, 'Start', 40, Gtk.ButtonBoxStyle.START),
+ True, True, 5)
+
+ vbox.pack_start(
+ self.create_bbox(True, 'End', 40, Gtk.ButtonBoxStyle.END),
+ True, True, 5)
+
+ frame_vert = Gtk.Frame(label='Vertical Button Boxes')
+ main_vbox.pack_start(frame_vert, True, True, 10)
+
+ hbox = Gtk.HBox(homogeneous=False, spacing=0)
+ hbox.set_border_width(10)
+ frame_vert.add(hbox)
+
+ hbox.pack_start(
+ self.create_bbox(False, 'Spread', 30, Gtk.ButtonBoxStyle.SPREAD),
+ True, True, 0)
+
+ hbox.pack_start(
+ self.create_bbox(False, 'Edge', 30, Gtk.ButtonBoxStyle.EDGE),
+ True, True, 5)
+
+ hbox.pack_start(
+ self.create_bbox(False, 'Start', 30, Gtk.ButtonBoxStyle.START),
+ True, True, 5)
+
+ hbox.pack_start(
+ self.create_bbox(False, 'End', 30, Gtk.ButtonBoxStyle.END),
+ True, True, 5)
+
+ window.show_all()
+
+ def create_bbox(self, is_horizontal, title, spacing, layout):
+ frame = Gtk.Frame(label=title)
+
+ if is_horizontal:
+ bbox = Gtk.HButtonBox()
+ else:
+ bbox = Gtk.VButtonBox()
+
+ bbox.set_border_width(5)
+ frame.add(bbox)
+
+ bbox.set_layout(layout)
+ bbox.set_spacing(spacing)
+
+ # FIXME: GtkButton consturctor should take a stock_id
+ button = Gtk.Button.new_from_stock(Gtk.STOCK_OK)
+ bbox.add(button)
+
+ button = Gtk.Button.new_from_stock(Gtk.STOCK_CANCEL)
+ bbox.add(button)
+
+ button = Gtk.Button.new_from_stock(Gtk.STOCK_HELP)
+ bbox.add(button)
+
+ return frame
+
+def main():
+ app = ButtonBoxApp()
+ Gtk.main()
+
+if __name__ == '__main__':
+ main()
diff --git a/gi/demos/gtk-demo/demos/clipboard.py b/gi/demos/gtk-demo/demos/clipboard.py
new file mode 100644
index 00000000..fb129cd0
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/clipboard.py
@@ -0,0 +1,238 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2010 Red Hat, Inc., John (J5) Palmieri <johnp@redhat.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+title = "Clipboard"
+description = """
+GtkClipboard is used for clipboard handling. This demo shows how to
+copy and paste text to and from the clipboard.
+
+It also shows how to transfer images via the clipboard or via
+drag-and-drop, and how to make clipboard contents persist after
+the application exits. Clipboard persistence requires a clipboard
+manager to run.
+"""
+
+# See FIXME's
+is_fully_bound = False
+
+from gi.repository import Gtk, Gdk
+
+class ClipboardApp:
+ def __init__(self):
+ self.window = Gtk.Window()
+ self.window.set_title('Clipboard demo')
+ self.window.connect('destroy', lambda w: Gtk.main_quit())
+
+ vbox = Gtk.VBox(homogeneous=False, spacing=0)
+ vbox.set_border_width(8)
+ self.window.add(vbox)
+
+ label = Gtk.Label(label='"Copy" will copy the text\nin the entry to the clipboard')
+ vbox.pack_start(label, False, False, 0)
+
+ hbox = Gtk.HBox(homogeneous=False, spacing=4)
+ hbox.set_border_width(8)
+ vbox.pack_start(hbox, False, False, 0)
+
+ # create first entry
+ entry = Gtk.Entry()
+ hbox.pack_start(entry, True, True, 0)
+
+ #FIXME: have the button constuctor take a stock_id
+ # create button
+ button = Gtk.Button.new_from_stock(Gtk.STOCK_COPY)
+ hbox.pack_start(button, False, False, 0)
+ button.connect('clicked', self.copy_button_clicked, entry)
+
+
+ label = Gtk.Label(label='"Paste" will paste the text from the clipboard to the entry')
+ vbox.pack_start(label, False, False, 0)
+
+ hbox = Gtk.HBox(homogeneous=False, spacing=4)
+ hbox.set_border_width(8)
+ vbox.pack_start(hbox, False, False, 0)
+
+ # create secondary entry
+ entry = Gtk.Entry()
+ hbox.pack_start(entry, True, True, 0)
+ #FIXME: have the button constuctor take a stock_id
+ # create button
+ button = Gtk.Button.new_from_stock(Gtk.STOCK_PASTE)
+ hbox.pack_start(button, False, False, 0)
+ button.connect('clicked', self.paste_button_clicked, entry)
+
+ label = Gtk.Label(label='Images can be transferred via the clipboard, too')
+ vbox.pack_start(label, False, False, 0)
+
+ hbox = Gtk.HBox(homogeneous=False, spacing=4)
+ hbox.set_border_width(8)
+ vbox.pack_start(hbox, False, False, 0)
+
+ # create the first image
+ image = Gtk.Image(stock=Gtk.STOCK_DIALOG_WARNING,
+ icon_size=Gtk.IconSize.BUTTON)
+
+ ebox = Gtk.EventBox()
+ ebox.add(image)
+ hbox.add(ebox)
+
+ # make ebox a drag source
+ Gtk.drag_source_set(ebox, Gdk.ModifierType.BUTTON1_MASK,
+ None, Gdk.DragAction.COPY)
+ Gtk.drag_source_add_image_targets(ebox)
+ ebox.connect('drag-begin', self.drag_begin, image)
+ ebox.connect('drag-data-get', self.drag_data_get, image)
+
+ # accept drops on ebox
+ Gtk.drag_dest_set(ebox, Gtk.DestDefaults.ALL,
+ None, Gdk.DragAction.COPY)
+ Gtk.drag_dest_add_image_targets(ebox)
+ ebox.connect('drag-data-received', self.drag_data_received, image)
+
+ # context menu on ebox
+ ebox.connect('button-press-event', self.button_press, image)
+
+ # create the second image
+ image = Gtk.Image(stock=Gtk.STOCK_STOP,
+ icon_size=Gtk.IconSize.BUTTON)
+
+ ebox = Gtk.EventBox()
+ ebox.add(image)
+ hbox.add(ebox)
+
+ # make ebox a drag source
+ Gtk.drag_source_set(ebox, Gdk.ModifierType.BUTTON1_MASK,
+ None, Gdk.DragAction.COPY)
+ Gtk.drag_source_add_image_targets(ebox)
+ ebox.connect('drag-begin', self.drag_begin, image)
+ ebox.connect('drag-data-get', self.drag_data_get, image)
+
+ # accept drops on ebox
+ Gtk.drag_dest_set(ebox, Gtk.DestDefaults.ALL,
+ None, Gdk.DragAction.COPY)
+ Gtk.drag_dest_add_image_targets(ebox)
+ ebox.connect('drag-data-received', self.drag_data_received, image)
+
+ # context menu on ebox
+ ebox.connect('button-press-event', self.button_press, image)
+
+ # tell the clipboard manager to make data persistent
+ #FIXME: Allow sending strings a Atoms and convert in PyGI
+ atom = Gdk.atom_intern('CLIPBOARD', True)
+ clipboard = Gtk.Clipboard.get(atom)
+ clipboard.set_can_store(None, 0)
+
+ self.window.show_all()
+
+ def copy_button_clicked(self, button, entry):
+ # get the default clipboard
+ atom = Gdk.atom_intern('CLIPBOARD', True)
+ clipboard = entry.get_clipboard(atom)
+
+ # set the clipboard's text
+ # FIXME: don't require passing length argument
+ clipboard.set_text(entry.get_text(), -1)
+
+ def paste_received(self, clipboard, text, entry):
+ if text != None:
+ entry.set_text(text)
+
+ def paste_button_clicked(self, button, entry):
+ # get the default clipboard
+ atom = Gdk.atom_intern('CLIPBOARD', True)
+ clipboard = entry.get_clipboard(atom)
+
+ # set the clipboard's text
+ clipboard.request_text(self.paste_received, entry)
+
+ def get_image_pixbuf(self, image):
+ # FIXME: We should hide storage types in an override
+ storage_type = image.get_storage_type()
+ if storage_type == Gtk.ImageType.PIXBUF:
+ return image.get_pixbuf()
+ elif storage_type == Gtk.ImageType.STOCK:
+ (stock_id, size) = image.get_stock()
+ return image.render_icon(stock_id, size, None)
+
+ return None
+
+ def drag_begin(self, widget, context, data):
+ pixbuf = self.get_image_pixbuf(data)
+ Gtk.drag_set_icon_pixbuf(context, pixbuf, -2, -2)
+
+ def drag_data_get(self, widget, context, selection_data, info, time, data):
+ pixbuf = self.get_image_pixbuf(data)
+ selection_data.set_pixbuf(pixbuf)
+
+ def drag_data_received(self, widget, context, x, y, selection_data, info, time, data):
+ if selection_data.length > 0:
+ pixbuf = selection_data.get_pixbuf()
+ data.set_from_pixbuf(pixbuf)
+
+ def copy_image(self, item, data):
+ # get the default clipboard
+ atom = Gdk.atom_intern('CLIPBOARD', True)
+ clipboard = Gtk.Clipboard.get(atom)
+ pixbuf = self.get_image_pixbuf(data)
+
+ clipboard.set_image(pixbuf)
+
+ def paste_image(self, item, data):
+ # get the default clipboard
+ atom = Gdk.atom_intern('CLIPBOARD', True)
+ clipboard = Gtk.Clipboard.get(atom)
+ pixbuf = clipboard.wait_for_image()
+
+ if pixbuf != None:
+ data.set_from_pixbuf(pixbuf)
+
+ def button_press(self, widget, event, data):
+ if event.button.button != 3:
+ return False
+
+ menu = Gtk.Menu()
+
+ #FIXME: default constructor should take a stock property
+ item = Gtk.ImageMenuItem.new_from_stock(Gtk.STOCK_COPY, None)
+ item.connect('activate', self.copy_image, data)
+ item.show()
+ menu.append(item)
+
+ #FIXME: default constructor should take a stock property
+ item = Gtk.ImageMenuItem.new_from_stock(Gtk.STOCK_PASTE, None)
+ item.connect('activate', self.paste_image, data)
+ item.show()
+ menu.append(item)
+
+ #FIXME: This doesn't work as we pass a None as a function
+ # pointer. PyGI doesn't correctly check for
+ # allow-none on callback parameters
+ # Fix is waiting for approval -
+ # https://bugzilla.gnome.org/show_bug.cgi?id=620906
+
+ menu.popup(None, None, None, None, 3, event.button.time)
+
+def main():
+ app = ClipboardApp()
+ Gtk.main()
+
+if __name__ == '__main__':
+ main()
diff --git a/gi/demos/gtk-demo/demos/colorselector.py b/gi/demos/gtk-demo/demos/colorselector.py
new file mode 100644
index 00000000..ee94b64a
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/colorselector.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2010 Red Hat, Inc., John (J5) Palmieri <johnp@redhat.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+title = "Color Selector"
+description = """
+ GtkColorSelection lets the user choose a color. GtkColorSelectionDialog is
+ a prebuilt dialog containing a GtkColorSelection.
+ """
+
+# See FIXME's
+is_fully_bound = False
+
+from gi.repository import Gtk, Gdk
+
+class ColorSelectorApp:
+ def __init__(self):
+ # FIXME: we should allow Gdk.Color to be allocated without parameters
+ # Also color doesn't seem to work
+ self.color = Gdk.Color(0, 65535, 0)
+
+ self.window = Gtk.Window()
+ self.window.set_title('Color Selection')
+ self.window.set_border_width(8)
+ self.window.connect('destroy', lambda w: Gtk.main_quit())
+
+ vbox = Gtk.VBox(homogeneous = False,
+ spacing = 8)
+ vbox.set_border_width(8)
+ self.window.add(vbox)
+
+ # create color swatch area
+ frame = Gtk.Frame()
+ frame.set_shadow_type(Gtk.ShadowType.IN)
+ vbox.pack_start(frame, True, True, 0)
+
+ self.da = Gtk.DrawingArea()
+ self.da.connect('expose_event', self.expose_event_cb)
+
+ # set a minimum size
+ self.da.set_size_request(200, 200)
+ # set the color
+ self.da.modify_bg(Gtk.StateType.NORMAL, self.color)
+ frame.add(self.da)
+
+ alignment = Gtk.Alignment(xalign=1.0,
+ yalign=0.5,
+ xscale=0.0,
+ yscale=0.0)
+
+ button = Gtk.Button(label='_Change the above color',
+ use_underline=True)
+ alignment.add(button)
+ vbox.pack_start(alignment, False, False, 0)
+
+ button.connect('clicked', self.change_color_cb)
+
+ self.window.show_all()
+
+ def expose_event_cb(self, widget, event):
+ window = widget.get_window()
+
+ if window:
+
+ style = widget.get_style()
+ x = event.expose.area.x
+ y = event.expose.area.y
+ width = event.expose.area.width
+ height = event.expose.area.height
+
+ """
+ Gdk.draw_rectangle(window,
+ # FIXME: accessing style attribute segfaults
+ style.bg_gc[Gtk.StateType.NORMAL],
+ True,
+ event.expose.area.x, event.expose.area.y,
+ event.expose.area.width, event.expose.area.height)
+ """
+ return True
+
+
+ def change_color_cb(self, button):
+ dialog = Gtk.ColorSelectionDialog(title='Changing color')
+ dialog.set_transient_for(self.window)
+
+ colorsel = dialog.get_color_selection()
+ colorsel.set_previous_color(self.color)
+ colorsel.set_current_color(self.color)
+ colorsel.set_has_palette(True)
+
+ response = dialog.run()
+
+ if response == Gtk.ResponseType.OK:
+ self.color = colorsel.get_current_color()
+ self.da.modify_bg(Gtk.StateType.NORMAL, self.color)
+
+ dialog.destroy()
+
+def main():
+ app = ColorSelectorApp()
+ Gtk.main()
+
+if __name__ == '__main__':
+ main()
diff --git a/gi/demos/gtk-demo/demos/combobox.py b/gi/demos/gtk-demo/demos/combobox.py
new file mode 100644
index 00000000..7e54a2a5
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/combobox.py
@@ -0,0 +1,282 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2010 Red Hat, Inc., John (J5) Palmieri <johnp@redhat.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+title = "Combo boxes"
+description = """
+The ComboBox widget allows to select one option out of a list.
+The ComboBoxEntry additionally allows the user to enter a value
+that is not in the list of options.
+
+How the options are displayed is controlled by cell renderers.
+ """
+
+# See FIXME's
+is_fully_bound = False
+
+from gi.repository import Gtk, Gdk, GdkPixbuf, GLib
+
+(PIXBUF_COL,
+ TEXT_COL) = range(2)
+
+class MaskEntry(Gtk.Entry):
+ __gtype_name__ = 'MaskEntry'
+
+ def __init__(self, mask=None):
+ self.mask = mask
+ super(MaskEntry, self).__init__()
+
+ self.connect('changed', self.changed_cb)
+
+ def set_background(self):
+ error_color = Gdk.Color(65535, 60000, 60000)
+ if self.mask:
+ if not GLib.regex_match_simple(self.mask,
+ self.get_text(), 0, 0):
+ self.modify_base(Gtk.StateType.NORMAL, error_color)
+ return
+
+ self.modify_base(Gtk.StateType.NORMAL, None)
+
+ def changed_cb(self, entry):
+ self.set_background()
+
+class ComboboxApp:
+ def __init__(self):
+ self.window = Gtk.Window()
+ self.window.set_title('Combo boxes')
+ self.window.set_border_width(10)
+ self.window.connect('destroy', lambda w: Gtk.main_quit())
+
+ vbox = Gtk.VBox(homogeneous=False, spacing=2)
+ self.window.add(vbox)
+
+ frame = Gtk.Frame(label='Some stock icons')
+ vbox.pack_start(frame, False, False, 0)
+
+ box = Gtk.VBox(homogeneous=False, spacing=0)
+ box.set_border_width(5)
+ frame.add(box)
+
+ model = self.create_stock_icon_store()
+ combo = Gtk.ComboBox(model=model)
+ box.add(combo)
+
+ renderer = Gtk.CellRendererPixbuf()
+ combo.pack_start(renderer, False)
+
+ # FIXME: override set_attributes
+ combo.add_attribute(renderer, 'pixbuf', PIXBUF_COL)
+ combo.set_cell_data_func(renderer, self.set_sensitive, None)
+
+ renderer = Gtk.CellRendererText()
+ combo.pack_start(renderer, True)
+ combo.add_attribute(renderer, 'text', TEXT_COL)
+ combo.set_cell_data_func(renderer, self.set_sensitive, None)
+
+ combo.set_row_separator_func(self.is_separator, None)
+ combo.set_active(0)
+
+ # a combobox demonstrating trees
+ frame = Gtk.Frame(label='Where are we ?')
+ vbox.pack_start(frame, False, False, 0)
+
+ box = Gtk.VBox(homogeneous=False, spacing=0)
+ box.set_border_width(5)
+ frame.add(box)
+
+ model = self.create_capital_store()
+ combo = Gtk.ComboBox(model=model)
+ box.add(combo)
+
+ renderer = Gtk.CellRendererText()
+ combo.pack_start(renderer, True)
+ combo.add_attribute(renderer, 'text', 0)
+ combo.set_cell_data_func(renderer, self.is_capital_sensistive, None)
+
+ # FIXME: make new_from_indices work
+ # make constructor take list or string of indices
+ iter = Gtk.TreeIter()
+ path = Gtk.TreePath.new_from_string('0:8')
+ model.get_iter(iter, path)
+ combo.set_active_iter(iter)
+
+ # A GtkComboBoxEntry with validation.
+ frame = Gtk.Frame(label='Editable')
+ vbox.pack_start(frame, False, False, 0)
+
+ box = Gtk.VBox(homogeneous=False, spacing=0)
+ box.set_border_width(5)
+ frame.add(box)
+
+ combo = Gtk.ComboBoxEntry.new_text()
+ self.fill_combo_entry(combo)
+ box.add(combo)
+
+ entry = MaskEntry(mask='^([0-9]*|One|Two|2\302\275|Three)$')
+
+ combo.remove(combo.get_child())
+ combo.add(entry)
+
+ self.window.show_all()
+
+ def strip_underscore(self, s):
+ return s.replace('_', '')
+
+ def create_stock_icon_store(self):
+ item = Gtk.StockItem()
+ stock_id = (Gtk.STOCK_DIALOG_WARNING,
+ Gtk.STOCK_STOP,
+ Gtk.STOCK_NEW,
+ Gtk.STOCK_CLEAR,
+ None,
+ Gtk.STOCK_OPEN)
+
+ cellview = Gtk.CellView()
+ store = Gtk.ListStore(GdkPixbuf.Pixbuf, str)
+
+ for id in stock_id:
+ if id is not None:
+ pixbuf = cellview.render_icon(id, Gtk.IconSize.BUTTON, None)
+ # FIXME: item should be annotated (out)
+ Gtk.stock_lookup(id, item)
+ label = self.strip_underscore(item.label)
+ store.append((pixbuf, label))
+ else:
+ store.append((None, 'separator'))
+
+ return store
+
+ def set_sensitive(self, cell_layout, cell, tree_model, iter, data):
+ """
+ A GtkCellLayoutDataFunc that demonstrates how one can control
+ sensitivity of rows. This particular function does nothing
+ useful and just makes the second row insensitive.
+ """
+
+ path = tree_model.get_path(iter)
+ indices = path.get_indices()
+
+ sensitive = not(indices[0] == 1)
+ cell.set_property('sensitive', sensitive)
+
+ def is_separator(self, model, iter, data):
+ """
+ A GtkTreeViewRowSeparatorFunc that demonstrates how rows can be
+ rendered as separators. This particular function does nothing
+ useful and just turns the fourth row into a separator.
+ """
+
+ path = model.get_path(iter)
+ indices = path.get_indices()
+
+ result = (indices[0] == 4)
+
+ return result
+
+ def create_capital_store(self):
+ capitals = (
+ {'group': 'A - B', 'capital': None},
+ {'group': None, 'capital': 'Albany'},
+ {'group': None, 'capital': 'Annapolis'},
+ {'group': None, 'capital': 'Atlanta'},
+ {'group': None, 'capital': 'Augusta'},
+ {'group': None, 'capital': 'Austin'},
+ {'group': None, 'capital': 'Baton Rouge'},
+ {'group': None, 'capital': 'Bismarck'},
+ {'group': None, 'capital': 'Boise'},
+ {'group': None, 'capital': 'Boston'},
+ {'group': 'C - D', 'capital': None},
+ {'group': None, 'capital': 'Carson City'},
+ {'group': None, 'capital': 'Charleston'},
+ {'group': None, 'capital': 'Cheyeene'},
+ {'group': None, 'capital': 'Columbia'},
+ {'group': None, 'capital': 'Columbus'},
+ {'group': None, 'capital': 'Concord'},
+ {'group': None, 'capital': 'Denver'},
+ {'group': None, 'capital': 'Des Moines'},
+ {'group': None, 'capital': 'Dover'},
+ {'group': 'E - J', 'capital': None},
+ {'group': None, 'capital': 'Frankfort'},
+ {'group': None, 'capital': 'Harrisburg'},
+ {'group': None, 'capital': 'Hartford'},
+ {'group': None, 'capital': 'Helena'},
+ {'group': None, 'capital': 'Honolulu'},
+ {'group': None, 'capital': 'Indianapolis'},
+ {'group': None, 'capital': 'Jackson'},
+ {'group': None, 'capital': 'Jefferson City'},
+ {'group': None, 'capital': 'Juneau'},
+ {'group': 'K - O', 'capital': None},
+ {'group': None, 'capital': 'Lansing'},
+ {'group': None, 'capital': 'Lincon'},
+ {'group': None, 'capital': 'Little Rock'},
+ {'group': None, 'capital': 'Madison'},
+ {'group': None, 'capital': 'Montgomery'},
+ {'group': None, 'capital': 'Montpelier'},
+ {'group': None, 'capital': 'Nashville'},
+ {'group': None, 'capital': 'Oklahoma City'},
+ {'group': None, 'capital': 'Olympia'},
+ {'group': 'P - S', 'capital': None},
+ {'group': None, 'capital': 'Phoenix'},
+ {'group': None, 'capital': 'Pierre'},
+ {'group': None, 'capital': 'Providence'},
+ {'group': None, 'capital': 'Raleigh'},
+ {'group': None, 'capital': 'Richmond'},
+ {'group': None, 'capital': 'Sacramento'},
+ {'group': None, 'capital': 'Salem'},
+ {'group': None, 'capital': 'Salt Lake City'},
+ {'group': None, 'capital': 'Santa Fe'},
+ {'group': None, 'capital': 'Springfield'},
+ {'group': None, 'capital': 'St. Paul'},
+ {'group': 'T - Z', 'capital': None},
+ {'group': None, 'capital': 'Tallahassee'},
+ {'group': None, 'capital': 'Topeka'},
+ {'group': None, 'capital': 'Trenton'}
+ )
+
+ parent = Gtk.TreeIter()
+
+ store = Gtk.TreeStore(str)
+
+ for item in capitals:
+ if item['group']:
+ parent = store.append(None, (item['group'],))
+ elif item['capital']:
+ store.append(parent, (item['capital'],))
+
+ return store
+
+ def is_capital_sensistive(self, cell_layout, cell, tree_model, iter, data):
+ sensitive = not tree_model.iter_has_child(iter)
+ cell.set_property('sensitive', sensitive)
+
+
+ def fill_combo_entry(self, entry):
+ entry.append_text('One')
+ entry.append_text('Two')
+ entry.append_text('2\302\275')
+ entry.append_text('Three')
+
+def main():
+ app = ComboboxApp()
+ Gtk.main()
+
+if __name__ == '__main__':
+ main()
diff --git a/gi/demos/gtk-demo/demos/data/alphatest.png b/gi/demos/gtk-demo/demos/data/alphatest.png
new file mode 100644
index 00000000..eb5885f8
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/data/alphatest.png
Binary files differ
diff --git a/gi/demos/gtk-demo/demos/data/apple-red.png b/gi/demos/gtk-demo/demos/data/apple-red.png
new file mode 100644
index 00000000..b0a24e94
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/data/apple-red.png
Binary files differ
diff --git a/gi/demos/gtk-demo/demos/data/background.jpg b/gi/demos/gtk-demo/demos/data/background.jpg
new file mode 100644
index 00000000..86c006aa
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/data/background.jpg
Binary files differ
diff --git a/gi/demos/gtk-demo/demos/data/demo.ui b/gi/demos/gtk-demo/demos/data/demo.ui
new file mode 100644
index 00000000..57dd2325
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/data/demo.ui
@@ -0,0 +1,258 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<interface domain="gtk20">
+ <object class="GtkListStore" id="liststore1">
+ <columns>
+ <column type="gchararray"/>
+ <column type="gchararray"/>
+ <column type="gint"/>
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">John</col>
+ <col id="1" translatable="yes">Doe</col>
+ <col id="2">25</col>
+ <col id="3" translatable="yes">This is the John Doe row</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Mary</col>
+ <col id="1" translatable="yes">Unknown</col>
+ <col id="2">50</col>
+ <col id="3" translatable="yes">This is the Mary Unknown row</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkUIManager" id="uimanager">
+ <child>
+ <object class="GtkActionGroup" id="DefaultActions">
+ <child>
+ <object class="GtkAction" id="Copy">
+ <property name="name">Copy</property>
+ <property name="tooltip" translatable="yes">Copy selected object into the clipboard</property>
+ <property name="stock_id">gtk-copy</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="Cut">
+ <property name="name">Cut</property>
+ <property name="tooltip" translatable="yes">Cut selected object into the clipboard</property>
+ <property name="stock_id">gtk-cut</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="EditMenu">
+ <property name="name">EditMenu</property>
+ <property name="label" translatable="yes">_Edit</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="FileMenu">
+ <property name="name">FileMenu</property>
+ <property name="label" translatable="yes">_File</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="New">
+ <property name="name">New</property>
+ <property name="tooltip" translatable="yes">Create a new file</property>
+ <property name="stock_id">gtk-new</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="Open">
+ <property name="name">Open</property>
+ <property name="tooltip" translatable="yes">Open a file</property>
+ <property name="stock_id">gtk-open</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="Paste">
+ <property name="name">Paste</property>
+ <property name="tooltip" translatable="yes">Paste object from the Clipboard</property>
+ <property name="stock_id">gtk-paste</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="Quit">
+ <property name="name">Quit</property>
+ <property name="tooltip" translatable="yes">Quit the program</property>
+ <property name="stock_id">gtk-quit</property>
+ <signal handler="quit_activate" name="activate"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="Save">
+ <property name="name">Save</property>
+ <property name="is_important">True</property>
+ <property name="tooltip" translatable="yes">Save a file</property>
+ <property name="stock_id">gtk-save</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="SaveAs">
+ <property name="name">SaveAs</property>
+ <property name="tooltip" translatable="yes">Save with a different name</property>
+ <property name="stock_id">gtk-save-as</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="HelpMenu">
+ <property name="name">HelpMenu</property>
+ <property name="label" translatable="yes">_Help</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="About">
+ <property name="name">About</property>
+ <property name="stock_id">gtk-about</property>
+ <signal handler="about_activate" name="activate"/>
+ </object>
+ <accelerator key="F1"/>
+ </child>
+ </object>
+ </child>
+ <ui>
+ <menubar name="menubar1">
+ <menu action="FileMenu" name="FileMenu">
+ <menuitem action="New" name="New"/>
+ <menuitem action="Open" name="Open"/>
+ <menuitem action="Save" name="Save"/>
+ <menuitem action="SaveAs" name="SaveAs"/>
+ <separator/>
+ <menuitem action="Quit" name="Quit"/>
+ </menu>
+ <menu action="EditMenu">
+ <menuitem action="Copy" name="Copy"/>
+ <menuitem action="Cut" name="Cut"/>
+ <menuitem action="Paste" name="Paste"/>
+ </menu>
+ <menu action="HelpMenu" name="HelpMenu">
+ <menuitem action="About" name="About"/>
+ </menu>
+ </menubar>
+ <toolbar name="toolbar1">
+ <toolitem action="New" name="New"/>
+ <toolitem action="Open" name="Open"/>
+ <toolitem action="Save" name="Save"/>
+ <separator/>
+ <toolitem action="Copy" name="Copy"/>
+ <toolitem action="Cut" name="Cut"/>
+ <toolitem action="Paste" name="Paste"/>
+ </toolbar>
+ </ui>
+ </object>
+ <object class="GtkAboutDialog" id="aboutdialog1">
+ <property name="program-name" translatable="yes">GtkBuilder demo</property>
+ <accessibility>
+ <relation target="window1" type="subwindow-of"/>
+ </accessibility>
+ </object>
+ <object class="GtkWindow" id="window1">
+ <property name="default_height">250</property>
+ <property name="default_width">440</property>
+ <property name="title">GtkBuilder demo</property>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <child>
+ <object constructor="uimanager" class="GtkMenuBar" id="menubar1">
+ <property name="visible">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="a11y-menubar">
+ <property name="AtkObject::accessible-name">The menubar</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <object constructor="uimanager" class="GtkToolbar" id="toolbar1">
+ <property name="visible">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="a11y-toolbar">
+ <property name="AtkObject::accessible-name">The toolbar</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <property name="visible">True</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <child>
+ <object class="GtkTreeView" id="treeview1">
+ <property name="visible">True</property>
+ <property name="model">liststore1</property>
+ <property name="tooltip-column">3</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="a11y-treeview">
+ <property name="AtkObject::accessible-name">Name list</property>
+ <property name="AtkObject::accessible-description">
+ A list of person with name, surname and age columns
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="column1">
+ <property name="title">Name</property>
+ <child>
+ <object class="GtkCellRendererText" id="renderer1"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="column2">
+ <property name="title">Surname</property>
+ <child>
+ <object class="GtkCellRendererText" id="renderer2"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="column3">
+ <property name="title">Age</property>
+ <child>
+ <object class="GtkCellRendererText" id="renderer3"/>
+ <attributes>
+ <attribute name="text">2</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <accessibility>
+ <action action_name="move-cursor" description="Move the cursor to select another person."/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkStatusbar" id="statusbar1">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/gi/demos/gtk-demo/demos/data/floppybuddy.gif b/gi/demos/gtk-demo/demos/data/floppybuddy.gif
new file mode 100644
index 00000000..ac986c8e
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/data/floppybuddy.gif
Binary files differ
diff --git a/gi/demos/gtk-demo/demos/data/gnome-applets.png b/gi/demos/gtk-demo/demos/data/gnome-applets.png
new file mode 100644
index 00000000..8d3549e9
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/data/gnome-applets.png
Binary files differ
diff --git a/gi/demos/gtk-demo/demos/data/gnome-calendar.png b/gi/demos/gtk-demo/demos/data/gnome-calendar.png
new file mode 100644
index 00000000..889f329a
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/data/gnome-calendar.png
Binary files differ
diff --git a/gi/demos/gtk-demo/demos/data/gnome-foot.png b/gi/demos/gtk-demo/demos/data/gnome-foot.png
new file mode 100644
index 00000000..04766585
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/data/gnome-foot.png
Binary files differ
diff --git a/gi/demos/gtk-demo/demos/data/gnome-fs-directory.png b/gi/demos/gtk-demo/demos/data/gnome-fs-directory.png
new file mode 100644
index 00000000..05921a66
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/data/gnome-fs-directory.png
Binary files differ
diff --git a/gi/demos/gtk-demo/demos/data/gnome-fs-regular.png b/gi/demos/gtk-demo/demos/data/gnome-fs-regular.png
new file mode 100644
index 00000000..0f5019c8
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/data/gnome-fs-regular.png
Binary files differ
diff --git a/gi/demos/gtk-demo/demos/data/gnome-gimp.png b/gi/demos/gtk-demo/demos/data/gnome-gimp.png
new file mode 100644
index 00000000..f6bbc6d3
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/data/gnome-gimp.png
Binary files differ
diff --git a/gi/demos/gtk-demo/demos/data/gnome-gmush.png b/gi/demos/gtk-demo/demos/data/gnome-gmush.png
new file mode 100644
index 00000000..0a4b0d04
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/data/gnome-gmush.png
Binary files differ
diff --git a/gi/demos/gtk-demo/demos/data/gnome-gsame.png b/gi/demos/gtk-demo/demos/data/gnome-gsame.png
new file mode 100644
index 00000000..01c06115
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/data/gnome-gsame.png
Binary files differ
diff --git a/gi/demos/gtk-demo/demos/data/gnu-keys.png b/gi/demos/gtk-demo/demos/data/gnu-keys.png
new file mode 100644
index 00000000..58a33770
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/data/gnu-keys.png
Binary files differ
diff --git a/gi/demos/gtk-demo/demos/data/gtk-logo-rgb.gif b/gi/demos/gtk-demo/demos/data/gtk-logo-rgb.gif
new file mode 100644
index 00000000..63c622b9
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/data/gtk-logo-rgb.gif
Binary files differ
diff --git a/gi/demos/gtk-demo/demos/test.py b/gi/demos/gtk-demo/demos/test.py
new file mode 100644
index 00000000..4716ff77
--- /dev/null
+++ b/gi/demos/gtk-demo/demos/test.py
@@ -0,0 +1,14 @@
+title = "Test Demo"
+description = "Dude this is a test"
+is_fully_bound = True
+
+from gi.repository import Gtk
+
+def _quit(*args):
+ Gtk.main_quit()
+
+def main():
+ window = Gtk.Window()
+ window.connect_after('destroy', _quit)
+ window.show_all()
+ Gtk.main()
diff --git a/gi/demos/gtk-demo/gtk-demo.py b/gi/demos/gtk-demo/gtk-demo.py
new file mode 100755
index 00000000..9c164dc3
--- /dev/null
+++ b/gi/demos/gtk-demo/gtk-demo.py
@@ -0,0 +1,266 @@
+#!/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2010 Red Hat, Inc., John (J5) Palmieri <johnp@redhat.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+
+
+from gi.repository import Gtk, GLib, GObject, GdkPixbuf, Gio, Pango
+import os
+import glob
+
+_DEMOCODEDIR = os.getcwd()
+
+class Demo(GObject.GObject):
+ __gtype_name__ = 'GtkDemo'
+
+ def __init__(self, title = None, module = None, filename = None, children = None):
+ super(Demo, self).__init__()
+ self.title = title
+ self.module = module
+ self.filename = filename
+ if children is None:
+ children = []
+
+ self.children = children
+
+class GtkDemoApp(object):
+ def _quit(self, *args):
+ Gtk.main_quit()
+
+ def __init__(self):
+ super(GtkDemoApp, self).__init__()
+
+ self._demos = []
+ self.load_demos()
+
+ self.setup_default_icon()
+
+ window = Gtk.Window(type=Gtk.WindowType.TOPLEVEL)
+ window.set_title('PyGI GTK+ Code Demos')
+
+ window.connect_after('destroy', self._quit)
+
+ hbox = Gtk.HBox(homogeneous = False, spacing = 0)
+ window.add(hbox)
+
+ tree = self.create_tree()
+ hbox.pack_start(tree, False, False, 0)
+
+ notebook = Gtk.Notebook()
+ hbox.pack_start(notebook, True, True, 0)
+
+ (text_widget, info_buffer) = self.create_text(True)
+ notebook.append_page(text_widget, Gtk.Label.new_with_mnemonic('_Info'))
+ self.info_buffer = info_buffer
+
+ tag = info_buffer.create_tag ('title', font = 'Sans 18')
+
+ (text_widget, source_buffer) = self.create_text(True)
+ notebook.append_page(text_widget, Gtk.Label.new_with_mnemonic('_Source'))
+
+ self.source_buffer = source_buffer;
+ tag = source_buffer.create_tag ('comment', foreground = 'DodgerBlue')
+ tag = source_buffer.create_tag ('type', foreground = 'ForestGreen')
+ tag = source_buffer.create_tag ('string',
+ foreground = 'RosyBrown',
+ weight = Pango.Weight.BOLD)
+ tag = source_buffer.create_tag ('control', foreground = 'purple')
+ tag = source_buffer.create_tag ('preprocessor',
+ style = Pango.Style.OBLIQUE,
+ foreground = 'burlywood4')
+ tag = source_buffer.create_tag ('function' ,
+ weight = Pango.Weight.BOLD,
+ foreground = 'DarkGoldenrod4')
+
+ self.source_buffer = source_buffer
+ window.set_default_size (600, 400)
+ window.show_all()
+
+ self.selection_cb(self.tree_view.get_selection(),
+ self.tree_view.get_model())
+ Gtk.main()
+
+ def load_demos(self):
+ demo_wildcard = os.path.join('demos', '*.py')
+ demo_file_list = glob.glob(demo_wildcard)
+ for f in demo_file_list:
+ base_name = os.path.basename(f)
+ if base_name == '__init__.py':
+ continue
+
+ module_name = base_name[0:-3]
+ module = getattr(__import__('demos.' + module_name), module_name)
+ try:
+ demo = Demo(module.title, module, f)
+ except AttributeError, e:
+ raise AttributeError('(%s): %s' % (f, e.message))
+ self._demos.append(demo)
+
+
+ def demo_find_file(self, base=''):
+ dir = os.path.join('demos', 'data')
+ logo_file = os.path.join(dir, 'gtk-logo-rgb.gif')
+ base_file = os.path.join(dir, base)
+
+ if (GLib.file_test(logo_file, GLib.FileTest.EXISTS) and
+ GLib.file_test(base_file, GLib.FileTest.EXISTS)):
+ return base_file
+ else:
+ filename = os.path.join(_DEMOCODEDIR, base)
+ if GLib.file_test(filename, GLib.FileTest.EXISTS):
+ return filename
+
+ # can't find the file
+ raise IOError('Cannot find demo data file "%s"' % base)
+
+ def setup_default_icon(self):
+ filename = self.demo_find_file ('gtk-logo-rgb.gif')
+ pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename)
+ transparent = pixbuf.add_alpha(True, 0xff, 0xff, 0xff)
+ list = []
+ list.append(transparent)
+ Gtk.Window.set_default_icon_list(list)
+
+ def selection_cb(self, selection, model):
+ start = Gtk.TextIter()
+ end = Gtk.TextIter()
+ iter = Gtk.TreeIter()
+
+ (success, m) = selection.get_selected(iter)
+ if not success:
+ return
+
+ demo = model.get_value(iter, 1)
+
+ title = demo.title
+ description = demo.module.description
+ code = GLib.file_get_contents(demo.filename)[1]
+
+ # output and style the title
+ self.info_buffer.get_bounds(start, end)
+ self.info_buffer.delete(start, end)
+ self.source_buffer.get_bounds(start, end)
+ self.source_buffer.delete(start, end)
+
+ self.info_buffer.get_iter_at_offset(start, 0)
+ end = start.copy()
+ self.info_buffer.insert(end, title)
+ start = end.copy()
+ start.backward_chars(len(title))
+ self.info_buffer.apply_tag_by_name('title', start, end)
+ self.info_buffer.insert(end, '\n\n')
+
+ # output the description
+ self.info_buffer.insert(end, description)
+
+ # output the code
+ self.source_buffer.get_iter_at_offset(start, 0)
+ end = start.copy()
+ self.source_buffer.insert(end, code)
+
+ def row_activated_cb(self, view, path, col, store):
+ iter = Gtk.TreeIter()
+ store.get_iter(iter, path)
+ demo = store.get_value(iter, 1)
+ demo.module.main()
+
+ def create_tree(self):
+ tree_store = Gtk.TreeStore(str, Demo, Pango.Style)
+ tree_view = Gtk.TreeView()
+ self.tree_view = tree_view
+ tree_view.set_model(tree_store)
+ selection = tree_view.get_selection()
+ selection.set_mode(Gtk.SelectionMode.BROWSE)
+ tree_view.set_size_request(200, -1)
+
+ for demo in self._demos:
+ children = demo.children
+ parent = tree_store.append(None,
+ (demo.title,
+ demo,
+ Pango.Style.NORMAL))
+ if children:
+ for child_demo in children:
+ tree_store.append(parent,
+ (child_demo.title,
+ Pango.Style.NORMAL))
+
+ cell = Gtk.CellRendererText()
+ column = Gtk.TreeViewColumn(title = 'Widget (double click for demo)',
+ cell_renderer = cell,
+ text = 0,
+ style = 2)
+
+
+ first_iter = Gtk.TreeIter()
+ tree_store.get_iter_first(first_iter)
+ selection.select_iter(first_iter)
+ selection.connect('changed', self.selection_cb, tree_store)
+ tree_view.connect('row_activated', self.row_activated_cb, tree_store)
+
+ tree_view.append_column(column)
+
+ tree_view.collapse_all()
+ tree_view.set_headers_visible(False)
+ scrolled_window = Gtk.ScrolledWindow(hadjustment = None,
+ vadjustment = None)
+ scrolled_window.set_policy(Gtk.PolicyType.NEVER,
+ Gtk.PolicyType.AUTOMATIC)
+
+ scrolled_window.add(tree_view)
+
+ label = Gtk.Label(label = 'Widget (double click for demo)')
+
+ box = Gtk.Notebook()
+ box.append_page(scrolled_window, label)
+
+ tree_view.grab_focus()
+
+ return box
+
+ def create_text(self, is_source):
+ scrolled_window = Gtk.ScrolledWindow(hadjustment = None,
+ vadjustment = None)
+ scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC,
+ Gtk.PolicyType.AUTOMATIC)
+ scrolled_window.set_shadow_type(Gtk.ShadowType.IN)
+
+ text_view = Gtk.TextView()
+ buffer = Gtk.TextBuffer()
+
+ text_view.set_buffer(buffer)
+ text_view.set_editable(False)
+ text_view.set_cursor_visible(False)
+
+ scrolled_window.add(text_view)
+
+ if is_source:
+ font_desc = Pango.Font.description_from_string('monospace')
+ text_view.modify_font(font_desc)
+ text_view.set_wrap_mode(Gtk.WrapMode.NONE)
+ else:
+ text_view.set_wrap_mode(Gtk.WrapMode.WORD)
+ text_view.set_pixels_above_lines(2)
+ text_view.set_pixels_below_lines(2)
+
+ return(scrolled_window, buffer)
+
+if __name__ == '__main__':
+ demo = GtkDemoApp()
diff --git a/gi/examples/Makefile.am b/gi/examples/Makefile.am
new file mode 100644
index 00000000..a0309aff
--- /dev/null
+++ b/gi/examples/Makefile.am
@@ -0,0 +1,2 @@
+EXTRA_DIST = cairo-demo.py
+
diff --git a/gi/examples/cairo-demo.py b/gi/examples/cairo-demo.py
new file mode 100755
index 00000000..8420c2fb
--- /dev/null
+++ b/gi/examples/cairo-demo.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+"""Based on cairo-demo/X11/cairo-demo.c
+"""
+import cairo
+from gi.repository import Gdk, Gtk
+
+SIZE = 30
+
+def triangle(ctx):
+ ctx.move_to(SIZE, 0)
+ ctx.rel_line_to(SIZE, 2*SIZE)
+ ctx.rel_line_to(-2*SIZE, 0)
+ ctx.close_path()
+
+def square(ctx):
+ ctx.move_to(0, 0)
+ ctx.rel_line_to(2*SIZE, 0)
+ ctx.rel_line_to(0, 2*SIZE)
+ ctx.rel_line_to(-2*SIZE, 0)
+ ctx.close_path()
+
+def bowtie(ctx):
+ ctx.move_to(0, 0)
+ ctx.rel_line_to(2*SIZE, 2*SIZE)
+ ctx.rel_line_to(-2*SIZE, 0)
+ ctx.rel_line_to(2*SIZE, -2*SIZE)
+ ctx.close_path()
+
+def inf(ctx):
+ ctx.move_to(0, SIZE)
+ ctx.rel_curve_to(0,SIZE, SIZE,SIZE, 2*SIZE,0)
+ ctx.rel_curve_to(SIZE,-SIZE, 2*SIZE,-SIZE, 2*SIZE,0)
+ ctx.rel_curve_to(0,SIZE, -SIZE,SIZE, -2*SIZE,0)
+ ctx.rel_curve_to(-SIZE,-SIZE, -2*SIZE,-SIZE, -2*SIZE,0)
+ ctx.close_path()
+
+def draw_shapes(ctx, x, y, fill):
+ ctx.save()
+
+ ctx.new_path()
+ ctx.translate(x+SIZE, y+SIZE)
+ bowtie(ctx)
+ if fill:
+ ctx.fill()
+ else:
+ ctx.stroke()
+
+ ctx.new_path()
+ ctx.translate(3*SIZE, 0)
+ square(ctx)
+ if fill:
+ ctx.fill()
+ else:
+ ctx.stroke()
+
+ ctx.new_path()
+ ctx.translate(3*SIZE, 0)
+ triangle(ctx)
+ if fill:
+ ctx.fill()
+ else:
+ ctx.stroke()
+
+ ctx.new_path()
+ ctx.translate(3*SIZE, 0)
+ inf(ctx)
+ if fill:
+ ctx.fill()
+ else:
+ ctx.stroke()
+
+ ctx.restore()
+
+def fill_shapes(ctx, x, y):
+ draw_shapes(ctx, x, y, True)
+
+def stroke_shapes(ctx, x, y):
+ draw_shapes(ctx, x, y, False)
+
+def expose (da, event):
+ ctx = Gdk.cairo_create(da.window)
+
+ ctx.set_source_rgb(0, 0, 0)
+
+ ctx.set_line_width(SIZE / 4)
+ ctx.set_tolerance(0.1)
+
+ ctx.set_line_join(cairo.LINE_JOIN_ROUND)
+ ctx.set_dash([SIZE/4.0, SIZE/4.0], 0)
+ stroke_shapes(ctx, 0, 0)
+
+ ctx.set_dash([], 0)
+ stroke_shapes(ctx, 0, 3*SIZE)
+
+ ctx.set_line_join(cairo.LINE_JOIN_BEVEL)
+ stroke_shapes(ctx, 0, 6*SIZE)
+
+ ctx.set_line_join(cairo.LINE_JOIN_MITER)
+ stroke_shapes(ctx, 0, 9*SIZE)
+
+ fill_shapes(ctx, 0, 12*SIZE)
+
+ ctx.set_line_join(cairo.LINE_JOIN_BEVEL)
+ fill_shapes(ctx, 0, 15*SIZE)
+ ctx.set_source_rgb(1,0,0)
+ stroke_shapes(ctx, 0, 15*SIZE)
+
+def main():
+ win = Gtk.Window()
+ win.connect('destroy', Gtk.main_quit)
+ win.set_default_size(450, 550)
+
+ drawingarea = Gtk.DrawingArea()
+ win.add(drawingarea)
+ drawingarea.connect('expose_event', expose)
+
+ win.show_all()
+ Gtk.main()
+
+if __name__ == '__main__':
+ main()
diff --git a/gi/gimodule.c b/gi/gimodule.c
new file mode 100644
index 00000000..59601fb1
--- /dev/null
+++ b/gi/gimodule.c
@@ -0,0 +1,297 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org>
+ *
+ * gimodule.c: wrapper for the gobject-introspection library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "pygi-private.h"
+
+#include <pygobject.h>
+
+# include <pycairo.h>
+Pycairo_CAPI_t *Pycairo_CAPI;
+
+static PyObject *
+_wrap_pyg_enum_add (PyObject *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ static char *kwlist[] = { "g_type", NULL };
+ PyObject *py_g_type;
+ GType g_type;
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "O!:enum_add",
+ kwlist, &PyGTypeWrapper_Type, &py_g_type)) {
+ return NULL;
+ }
+
+ g_type = pyg_type_from_object (py_g_type);
+ if (g_type == G_TYPE_INVALID) {
+ return NULL;
+ }
+
+ return pyg_enum_add (NULL, g_type_name (g_type), NULL, g_type);
+}
+
+static PyObject *
+_wrap_pyg_flags_add (PyObject *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ static char *kwlist[] = { "g_type", NULL };
+ PyObject *py_g_type;
+ GType g_type;
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "O!:flags_add",
+ kwlist, &PyGTypeWrapper_Type, &py_g_type)) {
+ return NULL;
+ }
+
+ g_type = pyg_type_from_object (py_g_type);
+ if (g_type == G_TYPE_INVALID) {
+ return NULL;
+ }
+
+ return pyg_flags_add (NULL, g_type_name (g_type), NULL, g_type);
+}
+
+static PyObject *
+_wrap_pyg_set_object_has_new_constructor (PyObject *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ static char *kwlist[] = { "g_type", NULL };
+ PyObject *py_g_type;
+ GType g_type;
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "O!:set_object_has_new_constructor",
+ kwlist, &PyGTypeWrapper_Type, &py_g_type)) {
+ return NULL;
+ }
+
+ g_type = pyg_type_from_object (py_g_type);
+ if (!g_type_is_a (g_type, G_TYPE_OBJECT)) {
+ PyErr_SetString (PyExc_TypeError, "must be a subtype of GObject");
+ return NULL;
+ }
+
+ pyg_set_object_has_new_constructor (g_type);
+
+ Py_RETURN_NONE;
+}
+
+static void
+initialize_interface (GTypeInterface *iface, PyTypeObject *pytype)
+{
+ // pygobject prints a warning if interface_init is NULL
+}
+
+static PyObject *
+_wrap_pyg_register_interface_info (PyObject *self, PyObject *args)
+{
+ PyObject *py_g_type;
+ GType g_type;
+ GInterfaceInfo *info;
+
+ if (!PyArg_ParseTuple (args, "O!:register_interface_info",
+ &PyGTypeWrapper_Type, &py_g_type)) {
+ return NULL;
+ }
+
+ g_type = pyg_type_from_object (py_g_type);
+ if (!g_type_is_a (g_type, G_TYPE_INTERFACE)) {
+ PyErr_SetString (PyExc_TypeError, "must be an interface");
+ return NULL;
+ }
+
+ info = g_new0 (GInterfaceInfo, 1);
+ info->interface_init = (GInterfaceInitFunc) initialize_interface;
+
+ pyg_register_interface_info (g_type, info);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+_wrap_pyg_hook_up_vfunc_implementation (PyObject *self, PyObject *args)
+{
+ PyGIBaseInfo *py_info;
+ PyObject *py_type;
+ PyObject *py_function;
+ gpointer implementor_class = NULL;
+ GType ancestor_g_type = 0;
+ GType implementor_gtype = 0;
+ gpointer *method_ptr = NULL;
+ int length, i;
+ GIBaseInfo *vfunc_info;
+ GIBaseInfo *ancestor_info;
+ GIStructInfo *struct_info;
+ gboolean is_interface = FALSE;
+ PyGICClosure *closure = NULL;
+
+ if (!PyArg_ParseTuple (args, "O!O!O:hook_up_vfunc_implementation",
+ &PyGIBaseInfo_Type, &py_info,
+ &PyGTypeWrapper_Type, &py_type,
+ &py_function))
+ return NULL;
+
+ implementor_gtype = pyg_type_from_object (py_type);
+ g_assert (G_TYPE_IS_CLASSED (implementor_gtype));
+
+ vfunc_info = py_info->info;
+ ancestor_info = g_base_info_get_container (vfunc_info);
+ is_interface = g_base_info_get_type (ancestor_info) == GI_INFO_TYPE_INTERFACE;
+
+ ancestor_g_type = g_registered_type_info_get_g_type (
+ (GIRegisteredTypeInfo *) ancestor_info);
+
+ implementor_class = g_type_class_ref (implementor_gtype);
+ if (is_interface) {
+ GTypeInstance *implementor_iface_class;
+ implementor_iface_class = g_type_interface_peek (implementor_class,
+ ancestor_g_type);
+ if (implementor_iface_class == NULL) {
+ g_type_class_unref (implementor_class);
+ PyErr_Format (PyExc_RuntimeError,
+ "Couldn't find GType of implementor of interface %s. "
+ "Forgot to set __gtype_name__?",
+ g_type_name (ancestor_g_type));
+ return NULL;
+ }
+
+ g_type_class_unref (implementor_class);
+ implementor_class = implementor_iface_class;
+
+ struct_info = g_interface_info_get_iface_struct ( (GIInterfaceInfo*) ancestor_info);
+ } else
+ struct_info = g_object_info_get_class_struct ( (GIObjectInfo*) ancestor_info);
+
+ length = g_struct_info_get_n_fields (struct_info);
+ for (i = 0; i < length; i++) {
+ GIFieldInfo *field_info;
+ GITypeInfo *type_info;
+ GIBaseInfo *interface_info;
+ GICallbackInfo *callback_info;
+ gint offset;
+
+ field_info = g_struct_info_get_field (struct_info, i);
+
+ if (strcmp (g_base_info_get_name ( (GIBaseInfo*) field_info),
+ g_base_info_get_name ( (GIBaseInfo*) vfunc_info)) != 0)
+ continue;
+
+ type_info = g_field_info_get_type (field_info);
+ if (g_type_info_get_tag (type_info) != GI_TYPE_TAG_INTERFACE)
+ continue;
+
+ interface_info = g_type_info_get_interface (type_info);
+ g_assert (g_base_info_get_type (interface_info) == GI_INFO_TYPE_CALLBACK);
+
+ callback_info = (GICallbackInfo*) interface_info;
+ offset = g_field_info_get_offset (field_info);
+ method_ptr = G_STRUCT_MEMBER_P (implementor_class, offset);
+
+ closure = _pygi_make_native_closure ( (GICallableInfo*) callback_info,
+ GI_SCOPE_TYPE_NOTIFIED, py_function, NULL);
+
+ *method_ptr = closure->closure;
+
+ g_base_info_unref (interface_info);
+ g_base_info_unref (type_info);
+ g_base_info_unref (field_info);
+
+ break;
+ }
+
+ g_base_info_unref (struct_info);
+
+ if (!is_interface)
+ g_type_class_unref (implementor_class);
+
+ Py_RETURN_NONE;
+}
+
+static void
+_sink_gobject (GObject *obj)
+{
+ if (G_IS_INITIALLY_UNOWNED (obj) || g_object_is_floating (obj)) {
+ g_object_ref_sink (obj);
+ }
+}
+
+static PyMethodDef _pygi_functions[] = {
+ { "enum_add", (PyCFunction) _wrap_pyg_enum_add, METH_VARARGS | METH_KEYWORDS },
+ { "flags_add", (PyCFunction) _wrap_pyg_flags_add, METH_VARARGS | METH_KEYWORDS },
+
+ { "set_object_has_new_constructor", (PyCFunction) _wrap_pyg_set_object_has_new_constructor, METH_VARARGS | METH_KEYWORDS },
+ { "register_interface_info", (PyCFunction) _wrap_pyg_register_interface_info, METH_VARARGS },
+ { "hook_up_vfunc_implementation", (PyCFunction) _wrap_pyg_hook_up_vfunc_implementation, METH_VARARGS },
+ { NULL, NULL, 0 }
+};
+
+struct PyGI_API PyGI_API = {
+ pygi_type_import_by_g_type
+};
+
+
+PyMODINIT_FUNC
+init_gi (void)
+{
+ PyObject *m;
+ PyObject *api;
+
+ m = Py_InitModule ("_gi", _pygi_functions);
+ if (m == NULL) {
+ return;
+ }
+
+ if (pygobject_init (-1, -1, -1) == NULL) {
+ return;
+ }
+
+ if (_pygobject_import() < 0) {
+ return;
+ }
+
+ Pycairo_IMPORT;
+ if (Pycairo_CAPI == NULL)
+ return;
+
+ // register our floating object sink while we wait for the pygobject
+ // patch to be approved. Once the patch is in this becomes a noop
+ // For more details - https://bugzilla.gnome.org/show_bug.cgi?id=583909
+ pygobject_register_sinkfunc (G_TYPE_OBJECT, _sink_gobject);
+
+ _pygi_repository_register_types (m);
+ _pygi_info_register_types (m);
+ _pygi_struct_register_types (m);
+ _pygi_boxed_register_types (m);
+ _pygi_argument_init();
+
+ api = PyCObject_FromVoidPtr ( (void *) &PyGI_API, NULL);
+ if (api == NULL) {
+ return;
+ }
+ PyModule_AddObject (m, "_API", api);
+}
+
diff --git a/gi/importer.py b/gi/importer.py
new file mode 100644
index 00000000..c79318e9
--- /dev/null
+++ b/gi/importer.py
@@ -0,0 +1,85 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org>
+#
+# importer.py: dynamic importer for introspected libraries.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+from __future__ import absolute_import
+
+import sys
+import gobject
+
+from ._gi import Repository, RepositoryError
+from .module import DynamicModule, DynamicGObjectModule, ModuleProxy
+
+
+repository = Repository.get_default()
+modules = {}
+
+
+class DynamicImporter(object):
+
+ # Note: see PEP302 for the Importer Protocol implemented below.
+
+ def __init__(self, path):
+ self.path = path
+
+ def find_module(self, fullname, path=None):
+ if not fullname.startswith(self.path):
+ return
+
+ path, namespace = fullname.rsplit('.', 1)
+ if path != self.path:
+ return
+ try:
+ repository.require(namespace)
+ except RepositoryError:
+ pass
+ else:
+ return self
+
+ def load_module(self, fullname):
+ if fullname in sys.modules:
+ return sys.modules[fullname]
+
+ path, namespace = fullname.rsplit('.', 1)
+
+ # Workaround for GObject
+ if namespace == 'GObject':
+ sys.modules[fullname] = DynamicGObjectModule()
+ return sys.modules[fullname]
+
+ dynamic_module = DynamicModule(namespace)
+ modules[namespace] = dynamic_module
+
+ overrides_modules = __import__('gi.overrides', fromlist=[namespace])
+ overrides_module = getattr(overrides_modules, namespace, None)
+
+ if overrides_module is not None:
+ module = ModuleProxy(fullname, namespace, dynamic_module, overrides_module)
+ else:
+ module = dynamic_module
+
+ module.__file__ = '<%s>' % fullname
+ module.__loader__ = self
+
+ sys.modules[fullname] = module
+
+ return module
+
diff --git a/gi/module.py b/gi/module.py
new file mode 100644
index 00000000..e1326aa2
--- /dev/null
+++ b/gi/module.py
@@ -0,0 +1,216 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2007-2009 Johan Dahlin <johan@gnome.org>
+#
+# module.py: dynamic module for introspected libraries.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+from __future__ import absolute_import
+
+import os
+import gobject
+
+from ._gi import \
+ Repository, \
+ FunctionInfo, \
+ RegisteredTypeInfo, \
+ EnumInfo, \
+ ObjectInfo, \
+ InterfaceInfo, \
+ ConstantInfo, \
+ StructInfo, \
+ UnionInfo, \
+ Struct, \
+ Boxed, \
+ enum_add, \
+ flags_add
+from .types import \
+ GObjectMeta, \
+ StructMeta, \
+ Function, \
+ Enum
+
+repository = Repository.get_default()
+
+
+def get_parent_for_object(object_info):
+ parent_object_info = object_info.get_parent()
+
+ if not parent_object_info:
+ return object
+
+ namespace = parent_object_info.get_namespace()
+ name = parent_object_info.get_name()
+
+ # Workaround for GObject.Object and GObject.InitiallyUnowned.
+ if namespace == 'GObject' and name == 'Object' or name == 'InitiallyUnowned':
+ return gobject.GObject
+
+ module = __import__('gi.repository.%s' % namespace, fromlist=[name])
+ return getattr(module, name)
+
+def get_interfaces_for_object(object_info):
+ interfaces = []
+ for interface_info in object_info.get_interfaces():
+ namespace = interface_info.get_namespace()
+ name = interface_info.get_name()
+
+ module = __import__('gi.repository.%s' % namespace, fromlist=[name])
+ interfaces.append(getattr(module, name))
+ return interfaces
+
+
+class DynamicModule(object):
+
+ def __init__(self, namespace):
+ self._namespace = namespace
+
+ def __getattr__(self, name):
+ info = repository.find_by_name(self._namespace, name)
+ if not info:
+ raise AttributeError("%r object has no attribute %r" % (
+ self.__class__.__name__, name))
+
+ if isinstance(info, EnumInfo):
+ g_type = info.get_g_type()
+ wrapper = g_type.pytype
+
+ if wrapper is None:
+ if g_type.is_a(gobject.TYPE_ENUM):
+ wrapper = enum_add(g_type)
+ elif g_type.is_a(gobject.TYPE_NONE):
+ # An enum with a GType of None is an enum without GType
+ wrapper = Enum
+ else:
+ wrapper = flags_add(g_type)
+
+ wrapper.__info__ = info
+ wrapper.__module__ = 'gi.repository.' + info.get_namespace()
+
+ for value_info in info.get_values():
+ name = value_info.get_name().upper()
+ setattr(wrapper, name, wrapper(value_info.get_value()))
+
+ elif isinstance(info, RegisteredTypeInfo):
+ g_type = info.get_g_type()
+
+ # Check if there is already a Python wrapper.
+ if g_type != gobject.TYPE_NONE:
+ type_ = g_type.pytype
+ if type_ is not None:
+ self.__dict__[name] = type_
+ return type_
+
+ # Create a wrapper.
+ if isinstance(info, ObjectInfo):
+ parent = get_parent_for_object(info)
+ interfaces = tuple(interface for interface in get_interfaces_for_object(info)
+ if not issubclass(parent, interface))
+ bases = (parent,) + interfaces
+ metaclass = GObjectMeta
+ elif isinstance(info, InterfaceInfo):
+ bases = (gobject.GInterface,)
+ metaclass = GObjectMeta
+ elif isinstance(info, (StructInfo, UnionInfo)):
+ if g_type.is_a(gobject.TYPE_BOXED):
+ bases = (Boxed,)
+ elif g_type.is_a(gobject.TYPE_POINTER) or g_type == gobject.TYPE_NONE:
+ bases = (Struct,)
+ else:
+ raise TypeError, "unable to create a wrapper for %s.%s" % (info.get_namespace(), info.get_name())
+ metaclass = StructMeta
+ else:
+ raise NotImplementedError(info)
+
+ name = info.get_name()
+ dict_ = {
+ '__info__': info,
+ '__module__': 'gi.repository.' + self._namespace,
+ '__gtype__': g_type
+ }
+ wrapper = metaclass(name, bases, dict_)
+
+ # Register the new Python wrapper.
+ if g_type != gobject.TYPE_NONE:
+ g_type.pytype = wrapper
+
+ elif isinstance(info, FunctionInfo):
+ wrapper = Function(info)
+ elif isinstance(info, ConstantInfo):
+ wrapper = info.get_value()
+ else:
+ raise NotImplementedError(info)
+
+ self.__dict__[name] = wrapper
+ return wrapper
+
+ def __repr__(self):
+ path = repository.get_typelib_path(self._namespace)
+ return "<DynamicModule %r from %r>" % (self._namespace, path)
+
+
+class DynamicGObjectModule(DynamicModule):
+ """Wrapper for the GObject module
+
+ This class allows us to access both the static PyGObject module and the GI GObject module
+ through the same interface. It is returned when by importing GObject from the gi repository:
+
+ from gi.repository import GObject
+
+ We use this because some PyGI interfaces generated from the GIR require GObject types not wrapped
+ by the static bindings. This also allows access to module attributes in a way that is more
+ familiar to GI application developers. Take signal flags as an example. The G_SIGNAL_RUN_FIRST
+ flag would be accessed as GObject.SIGNAL_RUN_FIRST in the static bindings but in the dynamic bindings
+ can be accessed as GObject.SignalFlags.RUN_FIRST. The latter follows a GI naming convention which
+ would be familiar to GI application developers in a number of languages.
+ """
+
+ def __init__(self):
+ self._namespace = 'GObject'
+ self._module = gobject
+
+ def __getattr__(self, name):
+ # first see if this attr is in the gobject module
+ attr = getattr(self._module, name, None)
+
+ # if not in module assume request for an attr exported through GI
+ if attr is None:
+ attr = super(DynamicGObjectModule, self).__getattr__(name)
+
+ return attr
+
+class ModuleProxy(object):
+
+ def __init__(self, name, namespace, dynamic_module, overrides_module):
+ self.__name__ = name
+
+ self._namespace = namespace
+ self._dynamic_module = dynamic_module
+ self._overrides_module = overrides_module
+
+ def __getattr__(self, name):
+ override_exports = getattr(self._overrides_module, '__all__', ())
+ if (name in override_exports):
+ attribute = getattr(self._overrides_module, name, None)
+ else:
+ attribute = getattr(self._dynamic_module, name)
+ return attribute
+
+ def __str__(self):
+ return "<ModuleProxy %r>" % self.__name__
+
diff --git a/gi/overrides/GIMarshallingTests.py b/gi/overrides/GIMarshallingTests.py
new file mode 100644
index 00000000..1ff91471
--- /dev/null
+++ b/gi/overrides/GIMarshallingTests.py
@@ -0,0 +1,69 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2010 Simon van der Linden <svdlinden@src.gnome.org>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+from ..types import override
+from ..importer import modules
+
+GIMarshallingTests = modules['GIMarshallingTests']
+
+
+OVERRIDES_CONSTANT = 7
+
+
+class OverridesStruct(GIMarshallingTests.OverridesStruct):
+
+ def __new__(cls, long_):
+ return GIMarshallingTests.OverridesStruct.__new__(cls)
+
+ def __init__(self, long_):
+ GIMarshallingTests.OverridesStruct.__init__(self)
+ self.long_ = long_
+
+ def method(self):
+ return GIMarshallingTests.OverridesStruct.method(self) / 7
+
+OverridesStruct = override(OverridesStruct)
+
+
+class OverridesObject(GIMarshallingTests.OverridesObject):
+
+ def __new__(cls, long_):
+ return GIMarshallingTests.OverridesObject.__new__(cls)
+
+ def __init__(self, long_):
+ GIMarshallingTests.OverridesObject.__init__(self)
+ # FIXME: doesn't work yet
+ #self.long_ = long_
+
+ @classmethod
+ def new(cls, long_):
+ self = GIMarshallingTests.OverridesObject.new()
+ # FIXME: doesn't work yet
+ #self.long_ = long_
+ return self
+
+ def method(self):
+ return GIMarshallingTests.OverridesObject.method(self) / 7
+
+OverridesObject = override(OverridesObject)
+
+
+__all__ = ['OVERRIDES_CONSTANT', 'OverridesStruct', 'OverridesObject']
+
diff --git a/gi/overrides/Gdk.py b/gi/overrides/Gdk.py
new file mode 100644
index 00000000..ac735c65
--- /dev/null
+++ b/gi/overrides/Gdk.py
@@ -0,0 +1,77 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2009 Johan Dahlin <johan@gnome.org>
+# 2010 Simon van der Linden <svdlinden@src.gnome.org>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+from ..types import override
+from ..importer import modules
+
+Gdk = modules['Gdk']
+
+
+class Rectangle(Gdk.Rectangle):
+
+ def __init__(self, x, y, width, height):
+ Gdk.Rectangle.__init__(self)
+ self.x = x
+ self.y = y
+ self.width = width
+ self.height = height
+
+ def __new__(cls, *args, **kwargs):
+ return Gdk.Rectangle.__new__(cls)
+
+ def __repr__(self):
+ return '<Gdk.Rectangle(x=%d, y=%d, width=%d, height=%d)>' % (
+ self.x, self.y, self.width, self.height)
+
+Rectangle = override(Rectangle)
+
+
+class Color(Gdk.Color):
+
+ def __init__(self, red, green, blue):
+ Gdk.Color.__init__(self)
+ self.red = red
+ self.green = green
+ self.blue = blue
+
+ def __new__(cls, *args, **kwargs):
+ return Gdk.Color.__new__(cls)
+
+ def __repr__(self):
+ return '<Gdk.Color(red=%d, green=%d, blue=%d)>' % (self.red, self.green, self.blue)
+
+Color = override(Color)
+
+class Drawable(Gdk.Drawable):
+ def cairo_create(self):
+ return Gdk.cairo_create(self)
+
+Drawable = override(Drawable)
+
+__all__ = ['Rectangle', 'Color', 'Drawable']
+
+
+
+import sys
+
+initialized, argv = Gdk.init_check(sys.argv)
+if not initialized:
+ raise RuntimeError("Gdk couldn't be initialized")
diff --git a/gi/overrides/Gtk.py b/gi/overrides/Gtk.py
new file mode 100644
index 00000000..38b0dfa5
--- /dev/null
+++ b/gi/overrides/Gtk.py
@@ -0,0 +1,250 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2009 Johan Dahlin <johan@gnome.org>
+# 2010 Simon van der Linden <svdlinden@src.gnome.org>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+import gobject
+from gi.repository import Gdk
+from gi.repository import GObject
+from ..types import override
+from ..importer import modules
+
+Gtk = modules['Gtk']
+
+class ActionGroup(Gtk.ActionGroup):
+ def add_actions(self, entries):
+ """
+ The add_actions() method is a convenience method that creates a number
+ of gtk.Action objects based on the information in the list of action
+ entry tuples contained in entries and adds them to the action group.
+ The entry tuples can vary in size from one to six items with the
+ following information:
+
+ * The name of the action. Must be specified.
+ * The stock id for the action. Optional with a default value of None
+ if a label is specified.
+ * The label for the action. This field should typically be marked
+ for translation, see the set_translation_domain() method. Optional
+ with a default value of None if a stock id is specified.
+ * The accelerator for the action, in the format understood by the
+ gtk.accelerator_parse() function. Optional with a default value of
+ None.
+ * The tooltip for the action. This field should typically be marked
+ for translation, see the set_translation_domain() method. Optional
+ with a default value of None.
+ * The callback function invoked when the action is activated.
+ Optional with a default value of None.
+
+ The "activate" signals of the actions are connected to the callbacks and
+ their accel paths are set to <Actions>/group-name/action-name.
+ """
+ try:
+ iter(entries)
+ except:
+ raise TypeError('entries must be iterable')
+
+ def _process_action(name, stock_id=None, label=None, accelerator=None, tooltip=None, callback=None):
+ action = Gtk.Action(name=name, label=label, tooltip=tooltip, stock_id=stock_id)
+ if callback is not None:
+ action.connect('activate', callback)
+
+ self.add_action_with_accel(action, accelerator)
+
+ for e in entries:
+ # using inner function above since entries can leave out optional arguments
+ _process_action(*e)
+
+ def add_toggle_actions(self, entries):
+ """
+ The add_toggle_actions() method is a convenience method that creates a
+ number of gtk.ToggleAction objects based on the information in the list
+ of action entry tuples contained in entries and adds them to the action
+ group. The toggle action entry tuples can vary in size from one to seven
+ items with the following information:
+
+ * The name of the action. Must be specified.
+ * The stock id for the action. Optional with a default value of None
+ if a label is specified.
+ * The label for the action. This field should typically be marked
+ for translation, see the set_translation_domain() method. Optional
+ with a default value of None if a stock id is specified.
+ * The accelerator for the action, in the format understood by the
+ gtk.accelerator_parse() function. Optional with a default value of
+ None.
+ * The tooltip for the action. This field should typically be marked
+ for translation, see the set_translation_domain() method. Optional
+ with a default value of None.
+ * The callback function invoked when the action is activated.
+ Optional with a default value of None.
+ * A flag indicating whether the toggle action is active. Optional
+ with a default value of False.
+
+ The "activate" signals of the actions are connected to the callbacks and
+ their accel paths are set to <Actions>/group-name/action-name.
+ """
+
+ try:
+ iter(entries)
+ except:
+ raise TypeError('entries must be iterable')
+
+ def _process_action(name, stock_id=None, label=None, accelerator=None, tooltip=None, callback=None, is_active=False):
+ action = Gtk.ToggleAction(name=name, label=label, tooltip=tooltip, stock_id=stock_id)
+ action.set_active(is_active)
+ if callback is not None:
+ action.connect('activate', callback)
+
+ self.add_action_with_accel(action, accelerator)
+
+ for e in entries:
+ # using inner function above since entries can leave out optional arguments
+ _process_action(*e)
+
+
+ def add_radio_actions(self, entries, value=None, on_change=None):
+ """
+ The add_radio_actions() method is a convenience method that creates a
+ number of gtk.RadioAction objects based on the information in the list
+ of action entry tuples contained in entries and adds them to the action
+ group. The entry tuples can vary in size from one to six items with the
+ following information:
+
+ * The name of the action. Must be specified.
+ * The stock id for the action. Optional with a default value of None
+ if a label is specified.
+ * The label for the action. This field should typically be marked
+ for translation, see the set_translation_domain() method. Optional
+ with a default value of None if a stock id is specified.
+ * The accelerator for the action, in the format understood by the
+ gtk.accelerator_parse() function. Optional with a default value of
+ None.
+ * The tooltip for the action. This field should typically be marked
+ for translation, see the set_translation_domain() method. Optional
+ with a default value of None.
+ * The value to set on the radio action. Optional with a default
+ value of 0. Should be specified in applications.
+
+ The value parameter specifies the radio action that should be set
+ active. The "changed" signal of the first radio action is connected to
+ the on_change callback (if specified and not None) and the accel paths
+ of the actions are set to <Actions>/group-name/action-name.
+ """
+ try:
+ iter(entries)
+ except:
+ raise TypeError('entries must be iterable')
+
+ first_action = None
+
+ def _process_action(group_source, name, stock_id=None, label=None, accelerator=None, tooltip=None, entry_value=0):
+ action = Gtk.RadioAction(name=name, label=label, tooltip=tooltip, stock_id=stock_id, value=entry_value)
+
+ # FIXME: join_group is a patch to Gtk+ 3.0
+ # otherwise we can't effectively add radio actions to a
+ # group. Should we depend on 3.0 and error out here
+ # or should we offer the functionality via a compat
+ # C module?
+ if hasattr(action, 'join_group'):
+ action.join_group(group_source)
+
+ if value == entry_value:
+ action.set_active(True)
+
+ self.add_action_with_accel(action, accelerator)
+ return action
+
+ for e in entries:
+ # using inner function above since entries can leave out optional arguments
+ action = _process_action(first_action, *e)
+ if first_action is None:
+ first_action = action
+
+ if first_action is not None and on_change is not None:
+ first_action.connect('changed', on_change)
+
+ActionGroup = override(ActionGroup)
+
+class UIManager(Gtk.UIManager):
+ def add_ui_from_string(self, buffer):
+ if not isinstance(buffer, basestring):
+ raise TypeError('buffer must be a string')
+
+ length = len(buffer)
+
+ return Gtk.UIManager.add_ui_from_string(self, buffer, length)
+
+UIManager = override(UIManager)
+
+class Builder(Gtk.Builder):
+
+ def connect_signals(self, obj_or_map):
+ def _full_callback(builder, gobj, signal_name, handler_name, connect_obj, flags, obj_or_map):
+ handler = None
+ if isinstance(obj_or_map, dict):
+ handler = obj_or_map.get(handler_name, None)
+ else:
+ handler = getattr(obj_or_map, handler_name, None)
+
+ if handler is None:
+ raise AttributeError('Handler %s not found' % handler_name)
+
+ if not callable(handler):
+ raise TypeError('Handler %s is not a method or function' % handler_name)
+
+ after = flags or GObject.ConnectFlags.AFTER
+ if connect_obj is not None:
+ if after:
+ gobj.connect_object_after(signal_name, handler, connect_obj)
+ else:
+ gobj.connect_object(signal_name, handler, connect_obj)
+ else:
+ if after:
+ gobj.connect_after(signal_name, handler)
+ else:
+ gobj.connect(signal_name, handler)
+
+ self.connect_signals_full(_full_callback,
+ obj_or_map);
+
+ def add_from_string(self, buffer):
+ if not isinstance(buffer, basestring):
+ raise TypeError('buffer must be a string')
+
+ length = len(buffer)
+
+ return Gtk.Builder.add_from_string(self, buffer, length)
+
+ def add_objects_from_string(self, buffer, object_ids):
+ if not isinstance(buffer, basestring):
+ raise TypeError('buffer must be a string')
+
+ length = len(buffer)
+
+ return Gtk.Builder.add_objects_from_string(self, buffer, length, object_ids)
+
+Builder = override(Builder)
+
+__all__ = ['ActionGroup', 'Builder', 'UIManager']
+
+import sys
+
+initialized, argv = Gtk.init_check(sys.argv)
+sys.argv = argv
+if not initialized:
+ raise RuntimeError("Gtk couldn't be initialized")
diff --git a/gi/overrides/Makefile.am b/gi/overrides/Makefile.am
new file mode 100644
index 00000000..62f6457f
--- /dev/null
+++ b/gi/overrides/Makefile.am
@@ -0,0 +1,12 @@
+PLATFORM_VERSION = 2.0
+
+pkgpyexecdir = $(pyexecdir)/gtk-2.0/gi
+
+pygioverridesdir = $(pkgpyexecdir)/overrides
+pygioverrides_PYTHON = \
+ Gtk.py \
+ Gdk.py \
+ GIMarshallingTests.py \
+ keysyms.py \
+ __init__.py
+
diff --git a/gi/overrides/__init__.py b/gi/overrides/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gi/overrides/__init__.py
diff --git a/gi/overrides/keysyms.py b/gi/overrides/keysyms.py
new file mode 100644
index 00000000..35ee8ebf
--- /dev/null
+++ b/gi/overrides/keysyms.py
@@ -0,0 +1,1499 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# pygtk - Python bindings for the GTK toolkit.
+# Copyright (C) 1998-2003 James Henstridge
+#
+# gtk/keysyms.py: list of keysyms.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+VoidSymbol = 0xFFFFFF
+BackSpace = 0xFF08
+Tab = 0xFF09
+Linefeed = 0xFF0A
+Clear = 0xFF0B
+Return = 0xFF0D
+Pause = 0xFF13
+Scroll_Lock = 0xFF14
+Sys_Req = 0xFF15
+Escape = 0xFF1B
+Delete = 0xFFFF
+Multi_key = 0xFF20
+Codeinput = 0xFF37
+SingleCandidate = 0xFF3C
+MultipleCandidate = 0xFF3D
+PreviousCandidate = 0xFF3E
+Kanji = 0xFF21
+Muhenkan = 0xFF22
+Henkan_Mode = 0xFF23
+Henkan = 0xFF23
+Romaji = 0xFF24
+Hiragana = 0xFF25
+Katakana = 0xFF26
+Hiragana_Katakana = 0xFF27
+Zenkaku = 0xFF28
+Hankaku = 0xFF29
+Zenkaku_Hankaku = 0xFF2A
+Touroku = 0xFF2B
+Massyo = 0xFF2C
+Kana_Lock = 0xFF2D
+Kana_Shift = 0xFF2E
+Eisu_Shift = 0xFF2F
+Eisu_toggle = 0xFF30
+Kanji_Bangou = 0xFF37
+Zen_Koho = 0xFF3D
+Mae_Koho = 0xFF3E
+Home = 0xFF50
+Left = 0xFF51
+Up = 0xFF52
+Right = 0xFF53
+Down = 0xFF54
+Prior = 0xFF55
+Page_Up = 0xFF55
+Next = 0xFF56
+Page_Down = 0xFF56
+End = 0xFF57
+Begin = 0xFF58
+Select = 0xFF60
+Print = 0xFF61
+Execute = 0xFF62
+Insert = 0xFF63
+Undo = 0xFF65
+Redo = 0xFF66
+Menu = 0xFF67
+Find = 0xFF68
+Cancel = 0xFF69
+Help = 0xFF6A
+Break = 0xFF6B
+Mode_switch = 0xFF7E
+script_switch = 0xFF7E
+Num_Lock = 0xFF7F
+KP_Space = 0xFF80
+KP_Tab = 0xFF89
+KP_Enter = 0xFF8D
+KP_F1 = 0xFF91
+KP_F2 = 0xFF92
+KP_F3 = 0xFF93
+KP_F4 = 0xFF94
+KP_Home = 0xFF95
+KP_Left = 0xFF96
+KP_Up = 0xFF97
+KP_Right = 0xFF98
+KP_Down = 0xFF99
+KP_Prior = 0xFF9A
+KP_Page_Up = 0xFF9A
+KP_Next = 0xFF9B
+KP_Page_Down = 0xFF9B
+KP_End = 0xFF9C
+KP_Begin = 0xFF9D
+KP_Insert = 0xFF9E
+KP_Delete = 0xFF9F
+KP_Equal = 0xFFBD
+KP_Multiply = 0xFFAA
+KP_Add = 0xFFAB
+KP_Separator = 0xFFAC
+KP_Subtract = 0xFFAD
+KP_Decimal = 0xFFAE
+KP_Divide = 0xFFAF
+KP_0 = 0xFFB0
+KP_1 = 0xFFB1
+KP_2 = 0xFFB2
+KP_3 = 0xFFB3
+KP_4 = 0xFFB4
+KP_5 = 0xFFB5
+KP_6 = 0xFFB6
+KP_7 = 0xFFB7
+KP_8 = 0xFFB8
+KP_9 = 0xFFB9
+F1 = 0xFFBE
+F2 = 0xFFBF
+F3 = 0xFFC0
+F4 = 0xFFC1
+F5 = 0xFFC2
+F6 = 0xFFC3
+F7 = 0xFFC4
+F8 = 0xFFC5
+F9 = 0xFFC6
+F10 = 0xFFC7
+F11 = 0xFFC8
+L1 = 0xFFC8
+F12 = 0xFFC9
+L2 = 0xFFC9
+F13 = 0xFFCA
+L3 = 0xFFCA
+F14 = 0xFFCB
+L4 = 0xFFCB
+F15 = 0xFFCC
+L5 = 0xFFCC
+F16 = 0xFFCD
+L6 = 0xFFCD
+F17 = 0xFFCE
+L7 = 0xFFCE
+F18 = 0xFFCF
+L8 = 0xFFCF
+F19 = 0xFFD0
+L9 = 0xFFD0
+F20 = 0xFFD1
+L10 = 0xFFD1
+F21 = 0xFFD2
+R1 = 0xFFD2
+F22 = 0xFFD3
+R2 = 0xFFD3
+F23 = 0xFFD4
+R3 = 0xFFD4
+F24 = 0xFFD5
+R4 = 0xFFD5
+F25 = 0xFFD6
+R5 = 0xFFD6
+F26 = 0xFFD7
+R6 = 0xFFD7
+F27 = 0xFFD8
+R7 = 0xFFD8
+F28 = 0xFFD9
+R8 = 0xFFD9
+F29 = 0xFFDA
+R9 = 0xFFDA
+F30 = 0xFFDB
+R10 = 0xFFDB
+F31 = 0xFFDC
+R11 = 0xFFDC
+F32 = 0xFFDD
+R12 = 0xFFDD
+F33 = 0xFFDE
+R13 = 0xFFDE
+F34 = 0xFFDF
+R14 = 0xFFDF
+F35 = 0xFFE0
+R15 = 0xFFE0
+Shift_L = 0xFFE1
+Shift_R = 0xFFE2
+Control_L = 0xFFE3
+Control_R = 0xFFE4
+Caps_Lock = 0xFFE5
+Shift_Lock = 0xFFE6
+Meta_L = 0xFFE7
+Meta_R = 0xFFE8
+Alt_L = 0xFFE9
+Alt_R = 0xFFEA
+Super_L = 0xFFEB
+Super_R = 0xFFEC
+Hyper_L = 0xFFED
+Hyper_R = 0xFFEE
+ISO_Lock = 0xFE01
+ISO_Level2_Latch = 0xFE02
+ISO_Level3_Shift = 0xFE03
+ISO_Level3_Latch = 0xFE04
+ISO_Level3_Lock = 0xFE05
+ISO_Group_Shift = 0xFF7E
+ISO_Group_Latch = 0xFE06
+ISO_Group_Lock = 0xFE07
+ISO_Next_Group = 0xFE08
+ISO_Next_Group_Lock = 0xFE09
+ISO_Prev_Group = 0xFE0A
+ISO_Prev_Group_Lock = 0xFE0B
+ISO_First_Group = 0xFE0C
+ISO_First_Group_Lock = 0xFE0D
+ISO_Last_Group = 0xFE0E
+ISO_Last_Group_Lock = 0xFE0F
+ISO_Left_Tab = 0xFE20
+ISO_Move_Line_Up = 0xFE21
+ISO_Move_Line_Down = 0xFE22
+ISO_Partial_Line_Up = 0xFE23
+ISO_Partial_Line_Down = 0xFE24
+ISO_Partial_Space_Left = 0xFE25
+ISO_Partial_Space_Right = 0xFE26
+ISO_Set_Margin_Left = 0xFE27
+ISO_Set_Margin_Right = 0xFE28
+ISO_Release_Margin_Left = 0xFE29
+ISO_Release_Margin_Right = 0xFE2A
+ISO_Release_Both_Margins = 0xFE2B
+ISO_Fast_Cursor_Left = 0xFE2C
+ISO_Fast_Cursor_Right = 0xFE2D
+ISO_Fast_Cursor_Up = 0xFE2E
+ISO_Fast_Cursor_Down = 0xFE2F
+ISO_Continuous_Underline = 0xFE30
+ISO_Discontinuous_Underline = 0xFE31
+ISO_Emphasize = 0xFE32
+ISO_Center_Object = 0xFE33
+ISO_Enter = 0xFE34
+dead_grave = 0xFE50
+dead_acute = 0xFE51
+dead_circumflex = 0xFE52
+dead_tilde = 0xFE53
+dead_macron = 0xFE54
+dead_breve = 0xFE55
+dead_abovedot = 0xFE56
+dead_diaeresis = 0xFE57
+dead_abovering = 0xFE58
+dead_doubleacute = 0xFE59
+dead_caron = 0xFE5A
+dead_cedilla = 0xFE5B
+dead_ogonek = 0xFE5C
+dead_iota = 0xFE5D
+dead_voiced_sound = 0xFE5E
+dead_semivoiced_sound = 0xFE5F
+dead_belowdot = 0xFE60
+First_Virtual_Screen = 0xFED0
+Prev_Virtual_Screen = 0xFED1
+Next_Virtual_Screen = 0xFED2
+Last_Virtual_Screen = 0xFED4
+Terminate_Server = 0xFED5
+AccessX_Enable = 0xFE70
+AccessX_Feedback_Enable = 0xFE71
+RepeatKeys_Enable = 0xFE72
+SlowKeys_Enable = 0xFE73
+BounceKeys_Enable = 0xFE74
+StickyKeys_Enable = 0xFE75
+MouseKeys_Enable = 0xFE76
+MouseKeys_Accel_Enable = 0xFE77
+Overlay1_Enable = 0xFE78
+Overlay2_Enable = 0xFE79
+AudibleBell_Enable = 0xFE7A
+Pointer_Left = 0xFEE0
+Pointer_Right = 0xFEE1
+Pointer_Up = 0xFEE2
+Pointer_Down = 0xFEE3
+Pointer_UpLeft = 0xFEE4
+Pointer_UpRight = 0xFEE5
+Pointer_DownLeft = 0xFEE6
+Pointer_DownRight = 0xFEE7
+Pointer_Button_Dflt = 0xFEE8
+Pointer_Button1 = 0xFEE9
+Pointer_Button2 = 0xFEEA
+Pointer_Button3 = 0xFEEB
+Pointer_Button4 = 0xFEEC
+Pointer_Button5 = 0xFEED
+Pointer_DblClick_Dflt = 0xFEEE
+Pointer_DblClick1 = 0xFEEF
+Pointer_DblClick2 = 0xFEF0
+Pointer_DblClick3 = 0xFEF1
+Pointer_DblClick4 = 0xFEF2
+Pointer_DblClick5 = 0xFEF3
+Pointer_Drag_Dflt = 0xFEF4
+Pointer_Drag1 = 0xFEF5
+Pointer_Drag2 = 0xFEF6
+Pointer_Drag3 = 0xFEF7
+Pointer_Drag4 = 0xFEF8
+Pointer_Drag5 = 0xFEFD
+Pointer_EnableKeys = 0xFEF9
+Pointer_Accelerate = 0xFEFA
+Pointer_DfltBtnNext = 0xFEFB
+Pointer_DfltBtnPrev = 0xFEFC
+_3270_Duplicate = 0xFD01
+_3270_FieldMark = 0xFD02
+_3270_Right2 = 0xFD03
+_3270_Left2 = 0xFD04
+_3270_BackTab = 0xFD05
+_3270_EraseEOF = 0xFD06
+_3270_EraseInput = 0xFD07
+_3270_Reset = 0xFD08
+_3270_Quit = 0xFD09
+_3270_PA1 = 0xFD0A
+_3270_PA2 = 0xFD0B
+_3270_PA3 = 0xFD0C
+_3270_Test = 0xFD0D
+_3270_Attn = 0xFD0E
+_3270_CursorBlink = 0xFD0F
+_3270_AltCursor = 0xFD10
+_3270_KeyClick = 0xFD11
+_3270_Jump = 0xFD12
+_3270_Ident = 0xFD13
+_3270_Rule = 0xFD14
+_3270_Copy = 0xFD15
+_3270_Play = 0xFD16
+_3270_Setup = 0xFD17
+_3270_Record = 0xFD18
+_3270_ChangeScreen = 0xFD19
+_3270_DeleteWord = 0xFD1A
+_3270_ExSelect = 0xFD1B
+_3270_CursorSelect = 0xFD1C
+_3270_PrintScreen = 0xFD1D
+_3270_Enter = 0xFD1E
+space = 0x020
+exclam = 0x021
+quotedbl = 0x022
+numbersign = 0x023
+dollar = 0x024
+percent = 0x025
+ampersand = 0x026
+apostrophe = 0x027
+quoteright = 0x027
+parenleft = 0x028
+parenright = 0x029
+asterisk = 0x02a
+plus = 0x02b
+comma = 0x02c
+minus = 0x02d
+period = 0x02e
+slash = 0x02f
+_0 = 0x030
+_1 = 0x031
+_2 = 0x032
+_3 = 0x033
+_4 = 0x034
+_5 = 0x035
+_6 = 0x036
+_7 = 0x037
+_8 = 0x038
+_9 = 0x039
+colon = 0x03a
+semicolon = 0x03b
+less = 0x03c
+equal = 0x03d
+greater = 0x03e
+question = 0x03f
+at = 0x040
+A = 0x041
+B = 0x042
+C = 0x043
+D = 0x044
+E = 0x045
+F = 0x046
+G = 0x047
+H = 0x048
+I = 0x049
+J = 0x04a
+K = 0x04b
+L = 0x04c
+M = 0x04d
+N = 0x04e
+O = 0x04f
+P = 0x050
+Q = 0x051
+R = 0x052
+S = 0x053
+T = 0x054
+U = 0x055
+V = 0x056
+W = 0x057
+X = 0x058
+Y = 0x059
+Z = 0x05a
+bracketleft = 0x05b
+backslash = 0x05c
+bracketright = 0x05d
+asciicircum = 0x05e
+underscore = 0x05f
+grave = 0x060
+quoteleft = 0x060
+a = 0x061
+b = 0x062
+c = 0x063
+d = 0x064
+e = 0x065
+f = 0x066
+g = 0x067
+h = 0x068
+i = 0x069
+j = 0x06a
+k = 0x06b
+l = 0x06c
+m = 0x06d
+n = 0x06e
+o = 0x06f
+p = 0x070
+q = 0x071
+r = 0x072
+s = 0x073
+t = 0x074
+u = 0x075
+v = 0x076
+w = 0x077
+x = 0x078
+y = 0x079
+z = 0x07a
+braceleft = 0x07b
+bar = 0x07c
+braceright = 0x07d
+asciitilde = 0x07e
+nobreakspace = 0x0a0
+exclamdown = 0x0a1
+cent = 0x0a2
+sterling = 0x0a3
+currency = 0x0a4
+yen = 0x0a5
+brokenbar = 0x0a6
+section = 0x0a7
+diaeresis = 0x0a8
+copyright = 0x0a9
+ordfeminine = 0x0aa
+guillemotleft = 0x0ab
+notsign = 0x0ac
+hyphen = 0x0ad
+registered = 0x0ae
+macron = 0x0af
+degree = 0x0b0
+plusminus = 0x0b1
+twosuperior = 0x0b2
+threesuperior = 0x0b3
+acute = 0x0b4
+mu = 0x0b5
+paragraph = 0x0b6
+periodcentered = 0x0b7
+cedilla = 0x0b8
+onesuperior = 0x0b9
+masculine = 0x0ba
+guillemotright = 0x0bb
+onequarter = 0x0bc
+onehalf = 0x0bd
+threequarters = 0x0be
+questiondown = 0x0bf
+Agrave = 0x0c0
+Aacute = 0x0c1
+Acircumflex = 0x0c2
+Atilde = 0x0c3
+Adiaeresis = 0x0c4
+Aring = 0x0c5
+AE = 0x0c6
+Ccedilla = 0x0c7
+Egrave = 0x0c8
+Eacute = 0x0c9
+Ecircumflex = 0x0ca
+Ediaeresis = 0x0cb
+Igrave = 0x0cc
+Iacute = 0x0cd
+Icircumflex = 0x0ce
+Idiaeresis = 0x0cf
+ETH = 0x0d0
+Eth = 0x0d0
+Ntilde = 0x0d1
+Ograve = 0x0d2
+Oacute = 0x0d3
+Ocircumflex = 0x0d4
+Otilde = 0x0d5
+Odiaeresis = 0x0d6
+multiply = 0x0d7
+Ooblique = 0x0d8
+Ugrave = 0x0d9
+Uacute = 0x0da
+Ucircumflex = 0x0db
+Udiaeresis = 0x0dc
+Yacute = 0x0dd
+THORN = 0x0de
+Thorn = 0x0de
+ssharp = 0x0df
+agrave = 0x0e0
+aacute = 0x0e1
+acircumflex = 0x0e2
+atilde = 0x0e3
+adiaeresis = 0x0e4
+aring = 0x0e5
+ae = 0x0e6
+ccedilla = 0x0e7
+egrave = 0x0e8
+eacute = 0x0e9
+ecircumflex = 0x0ea
+ediaeresis = 0x0eb
+igrave = 0x0ec
+iacute = 0x0ed
+icircumflex = 0x0ee
+idiaeresis = 0x0ef
+eth = 0x0f0
+ntilde = 0x0f1
+ograve = 0x0f2
+oacute = 0x0f3
+ocircumflex = 0x0f4
+otilde = 0x0f5
+odiaeresis = 0x0f6
+division = 0x0f7
+oslash = 0x0f8
+ugrave = 0x0f9
+uacute = 0x0fa
+ucircumflex = 0x0fb
+udiaeresis = 0x0fc
+yacute = 0x0fd
+thorn = 0x0fe
+ydiaeresis = 0x0ff
+Aogonek = 0x1a1
+breve = 0x1a2
+Lstroke = 0x1a3
+Lcaron = 0x1a5
+Sacute = 0x1a6
+Scaron = 0x1a9
+Scedilla = 0x1aa
+Tcaron = 0x1ab
+Zacute = 0x1ac
+Zcaron = 0x1ae
+Zabovedot = 0x1af
+aogonek = 0x1b1
+ogonek = 0x1b2
+lstroke = 0x1b3
+lcaron = 0x1b5
+sacute = 0x1b6
+caron = 0x1b7
+scaron = 0x1b9
+scedilla = 0x1ba
+tcaron = 0x1bb
+zacute = 0x1bc
+doubleacute = 0x1bd
+zcaron = 0x1be
+zabovedot = 0x1bf
+Racute = 0x1c0
+Abreve = 0x1c3
+Lacute = 0x1c5
+Cacute = 0x1c6
+Ccaron = 0x1c8
+Eogonek = 0x1ca
+Ecaron = 0x1cc
+Dcaron = 0x1cf
+Dstroke = 0x1d0
+Nacute = 0x1d1
+Ncaron = 0x1d2
+Odoubleacute = 0x1d5
+Rcaron = 0x1d8
+Uring = 0x1d9
+Udoubleacute = 0x1db
+Tcedilla = 0x1de
+racute = 0x1e0
+abreve = 0x1e3
+lacute = 0x1e5
+cacute = 0x1e6
+ccaron = 0x1e8
+eogonek = 0x1ea
+ecaron = 0x1ec
+dcaron = 0x1ef
+dstroke = 0x1f0
+nacute = 0x1f1
+ncaron = 0x1f2
+odoubleacute = 0x1f5
+udoubleacute = 0x1fb
+rcaron = 0x1f8
+uring = 0x1f9
+tcedilla = 0x1fe
+abovedot = 0x1ff
+Hstroke = 0x2a1
+Hcircumflex = 0x2a6
+Iabovedot = 0x2a9
+Gbreve = 0x2ab
+Jcircumflex = 0x2ac
+hstroke = 0x2b1
+hcircumflex = 0x2b6
+idotless = 0x2b9
+gbreve = 0x2bb
+jcircumflex = 0x2bc
+Cabovedot = 0x2c5
+Ccircumflex = 0x2c6
+Gabovedot = 0x2d5
+Gcircumflex = 0x2d8
+Ubreve = 0x2dd
+Scircumflex = 0x2de
+cabovedot = 0x2e5
+ccircumflex = 0x2e6
+gabovedot = 0x2f5
+gcircumflex = 0x2f8
+ubreve = 0x2fd
+scircumflex = 0x2fe
+kra = 0x3a2
+kappa = 0x3a2
+Rcedilla = 0x3a3
+Itilde = 0x3a5
+Lcedilla = 0x3a6
+Emacron = 0x3aa
+Gcedilla = 0x3ab
+Tslash = 0x3ac
+rcedilla = 0x3b3
+itilde = 0x3b5
+lcedilla = 0x3b6
+emacron = 0x3ba
+gcedilla = 0x3bb
+tslash = 0x3bc
+ENG = 0x3bd
+eng = 0x3bf
+Amacron = 0x3c0
+Iogonek = 0x3c7
+Eabovedot = 0x3cc
+Imacron = 0x3cf
+Ncedilla = 0x3d1
+Omacron = 0x3d2
+Kcedilla = 0x3d3
+Uogonek = 0x3d9
+Utilde = 0x3dd
+Umacron = 0x3de
+amacron = 0x3e0
+iogonek = 0x3e7
+eabovedot = 0x3ec
+imacron = 0x3ef
+ncedilla = 0x3f1
+omacron = 0x3f2
+kcedilla = 0x3f3
+uogonek = 0x3f9
+utilde = 0x3fd
+umacron = 0x3fe
+OE = 0x13bc
+oe = 0x13bd
+Ydiaeresis = 0x13be
+overline = 0x47e
+kana_fullstop = 0x4a1
+kana_openingbracket = 0x4a2
+kana_closingbracket = 0x4a3
+kana_comma = 0x4a4
+kana_conjunctive = 0x4a5
+kana_middledot = 0x4a5
+kana_WO = 0x4a6
+kana_a = 0x4a7
+kana_i = 0x4a8
+kana_u = 0x4a9
+kana_e = 0x4aa
+kana_o = 0x4ab
+kana_ya = 0x4ac
+kana_yu = 0x4ad
+kana_yo = 0x4ae
+kana_tsu = 0x4af
+kana_tu = 0x4af
+prolongedsound = 0x4b0
+kana_A = 0x4b1
+kana_I = 0x4b2
+kana_U = 0x4b3
+kana_E = 0x4b4
+kana_O = 0x4b5
+kana_KA = 0x4b6
+kana_KI = 0x4b7
+kana_KU = 0x4b8
+kana_KE = 0x4b9
+kana_KO = 0x4ba
+kana_SA = 0x4bb
+kana_SHI = 0x4bc
+kana_SU = 0x4bd
+kana_SE = 0x4be
+kana_SO = 0x4bf
+kana_TA = 0x4c0
+kana_CHI = 0x4c1
+kana_TI = 0x4c1
+kana_TSU = 0x4c2
+kana_TU = 0x4c2
+kana_TE = 0x4c3
+kana_TO = 0x4c4
+kana_NA = 0x4c5
+kana_NI = 0x4c6
+kana_NU = 0x4c7
+kana_NE = 0x4c8
+kana_NO = 0x4c9
+kana_HA = 0x4ca
+kana_HI = 0x4cb
+kana_FU = 0x4cc
+kana_HU = 0x4cc
+kana_HE = 0x4cd
+kana_HO = 0x4ce
+kana_MA = 0x4cf
+kana_MI = 0x4d0
+kana_MU = 0x4d1
+kana_ME = 0x4d2
+kana_MO = 0x4d3
+kana_YA = 0x4d4
+kana_YU = 0x4d5
+kana_YO = 0x4d6
+kana_RA = 0x4d7
+kana_RI = 0x4d8
+kana_RU = 0x4d9
+kana_RE = 0x4da
+kana_RO = 0x4db
+kana_WA = 0x4dc
+kana_N = 0x4dd
+voicedsound = 0x4de
+semivoicedsound = 0x4df
+kana_switch = 0xFF7E
+Arabic_comma = 0x5ac
+Arabic_semicolon = 0x5bb
+Arabic_question_mark = 0x5bf
+Arabic_hamza = 0x5c1
+Arabic_maddaonalef = 0x5c2
+Arabic_hamzaonalef = 0x5c3
+Arabic_hamzaonwaw = 0x5c4
+Arabic_hamzaunderalef = 0x5c5
+Arabic_hamzaonyeh = 0x5c6
+Arabic_alef = 0x5c7
+Arabic_beh = 0x5c8
+Arabic_tehmarbuta = 0x5c9
+Arabic_teh = 0x5ca
+Arabic_theh = 0x5cb
+Arabic_jeem = 0x5cc
+Arabic_hah = 0x5cd
+Arabic_khah = 0x5ce
+Arabic_dal = 0x5cf
+Arabic_thal = 0x5d0
+Arabic_ra = 0x5d1
+Arabic_zain = 0x5d2
+Arabic_seen = 0x5d3
+Arabic_sheen = 0x5d4
+Arabic_sad = 0x5d5
+Arabic_dad = 0x5d6
+Arabic_tah = 0x5d7
+Arabic_zah = 0x5d8
+Arabic_ain = 0x5d9
+Arabic_ghain = 0x5da
+Arabic_tatweel = 0x5e0
+Arabic_feh = 0x5e1
+Arabic_qaf = 0x5e2
+Arabic_kaf = 0x5e3
+Arabic_lam = 0x5e4
+Arabic_meem = 0x5e5
+Arabic_noon = 0x5e6
+Arabic_ha = 0x5e7
+Arabic_heh = 0x5e7
+Arabic_waw = 0x5e8
+Arabic_alefmaksura = 0x5e9
+Arabic_yeh = 0x5ea
+Arabic_fathatan = 0x5eb
+Arabic_dammatan = 0x5ec
+Arabic_kasratan = 0x5ed
+Arabic_fatha = 0x5ee
+Arabic_damma = 0x5ef
+Arabic_kasra = 0x5f0
+Arabic_shadda = 0x5f1
+Arabic_sukun = 0x5f2
+Arabic_switch = 0xFF7E
+Serbian_dje = 0x6a1
+Macedonia_gje = 0x6a2
+Cyrillic_io = 0x6a3
+Ukrainian_ie = 0x6a4
+Ukranian_je = 0x6a4
+Macedonia_dse = 0x6a5
+Ukrainian_i = 0x6a6
+Ukranian_i = 0x6a6
+Ukrainian_yi = 0x6a7
+Ukranian_yi = 0x6a7
+Cyrillic_je = 0x6a8
+Serbian_je = 0x6a8
+Cyrillic_lje = 0x6a9
+Serbian_lje = 0x6a9
+Cyrillic_nje = 0x6aa
+Serbian_nje = 0x6aa
+Serbian_tshe = 0x6ab
+Macedonia_kje = 0x6ac
+Ukrainian_ghe_with_upturn = 0x6ad
+Byelorussian_shortu = 0x6ae
+Cyrillic_dzhe = 0x6af
+Serbian_dze = 0x6af
+numerosign = 0x6b0
+Serbian_DJE = 0x6b1
+Macedonia_GJE = 0x6b2
+Cyrillic_IO = 0x6b3
+Ukrainian_IE = 0x6b4
+Ukranian_JE = 0x6b4
+Macedonia_DSE = 0x6b5
+Ukrainian_I = 0x6b6
+Ukranian_I = 0x6b6
+Ukrainian_YI = 0x6b7
+Ukranian_YI = 0x6b7
+Cyrillic_JE = 0x6b8
+Serbian_JE = 0x6b8
+Cyrillic_LJE = 0x6b9
+Serbian_LJE = 0x6b9
+Cyrillic_NJE = 0x6ba
+Serbian_NJE = 0x6ba
+Serbian_TSHE = 0x6bb
+Macedonia_KJE = 0x6bc
+Ukrainian_GHE_WITH_UPTURN = 0x6bd
+Byelorussian_SHORTU = 0x6be
+Cyrillic_DZHE = 0x6bf
+Serbian_DZE = 0x6bf
+Cyrillic_yu = 0x6c0
+Cyrillic_a = 0x6c1
+Cyrillic_be = 0x6c2
+Cyrillic_tse = 0x6c3
+Cyrillic_de = 0x6c4
+Cyrillic_ie = 0x6c5
+Cyrillic_ef = 0x6c6
+Cyrillic_ghe = 0x6c7
+Cyrillic_ha = 0x6c8
+Cyrillic_i = 0x6c9
+Cyrillic_shorti = 0x6ca
+Cyrillic_ka = 0x6cb
+Cyrillic_el = 0x6cc
+Cyrillic_em = 0x6cd
+Cyrillic_en = 0x6ce
+Cyrillic_o = 0x6cf
+Cyrillic_pe = 0x6d0
+Cyrillic_ya = 0x6d1
+Cyrillic_er = 0x6d2
+Cyrillic_es = 0x6d3
+Cyrillic_te = 0x6d4
+Cyrillic_u = 0x6d5
+Cyrillic_zhe = 0x6d6
+Cyrillic_ve = 0x6d7
+Cyrillic_softsign = 0x6d8
+Cyrillic_yeru = 0x6d9
+Cyrillic_ze = 0x6da
+Cyrillic_sha = 0x6db
+Cyrillic_e = 0x6dc
+Cyrillic_shcha = 0x6dd
+Cyrillic_che = 0x6de
+Cyrillic_hardsign = 0x6df
+Cyrillic_YU = 0x6e0
+Cyrillic_A = 0x6e1
+Cyrillic_BE = 0x6e2
+Cyrillic_TSE = 0x6e3
+Cyrillic_DE = 0x6e4
+Cyrillic_IE = 0x6e5
+Cyrillic_EF = 0x6e6
+Cyrillic_GHE = 0x6e7
+Cyrillic_HA = 0x6e8
+Cyrillic_I = 0x6e9
+Cyrillic_SHORTI = 0x6ea
+Cyrillic_KA = 0x6eb
+Cyrillic_EL = 0x6ec
+Cyrillic_EM = 0x6ed
+Cyrillic_EN = 0x6ee
+Cyrillic_O = 0x6ef
+Cyrillic_PE = 0x6f0
+Cyrillic_YA = 0x6f1
+Cyrillic_ER = 0x6f2
+Cyrillic_ES = 0x6f3
+Cyrillic_TE = 0x6f4
+Cyrillic_U = 0x6f5
+Cyrillic_ZHE = 0x6f6
+Cyrillic_VE = 0x6f7
+Cyrillic_SOFTSIGN = 0x6f8
+Cyrillic_YERU = 0x6f9
+Cyrillic_ZE = 0x6fa
+Cyrillic_SHA = 0x6fb
+Cyrillic_E = 0x6fc
+Cyrillic_SHCHA = 0x6fd
+Cyrillic_CHE = 0x6fe
+Cyrillic_HARDSIGN = 0x6ff
+Greek_ALPHAaccent = 0x7a1
+Greek_EPSILONaccent = 0x7a2
+Greek_ETAaccent = 0x7a3
+Greek_IOTAaccent = 0x7a4
+Greek_IOTAdiaeresis = 0x7a5
+Greek_OMICRONaccent = 0x7a7
+Greek_UPSILONaccent = 0x7a8
+Greek_UPSILONdieresis = 0x7a9
+Greek_OMEGAaccent = 0x7ab
+Greek_accentdieresis = 0x7ae
+Greek_horizbar = 0x7af
+Greek_alphaaccent = 0x7b1
+Greek_epsilonaccent = 0x7b2
+Greek_etaaccent = 0x7b3
+Greek_iotaaccent = 0x7b4
+Greek_iotadieresis = 0x7b5
+Greek_iotaaccentdieresis = 0x7b6
+Greek_omicronaccent = 0x7b7
+Greek_upsilonaccent = 0x7b8
+Greek_upsilondieresis = 0x7b9
+Greek_upsilonaccentdieresis = 0x7ba
+Greek_omegaaccent = 0x7bb
+Greek_ALPHA = 0x7c1
+Greek_BETA = 0x7c2
+Greek_GAMMA = 0x7c3
+Greek_DELTA = 0x7c4
+Greek_EPSILON = 0x7c5
+Greek_ZETA = 0x7c6
+Greek_ETA = 0x7c7
+Greek_THETA = 0x7c8
+Greek_IOTA = 0x7c9
+Greek_KAPPA = 0x7ca
+Greek_LAMDA = 0x7cb
+Greek_LAMBDA = 0x7cb
+Greek_MU = 0x7cc
+Greek_NU = 0x7cd
+Greek_XI = 0x7ce
+Greek_OMICRON = 0x7cf
+Greek_PI = 0x7d0
+Greek_RHO = 0x7d1
+Greek_SIGMA = 0x7d2
+Greek_TAU = 0x7d4
+Greek_UPSILON = 0x7d5
+Greek_PHI = 0x7d6
+Greek_CHI = 0x7d7
+Greek_PSI = 0x7d8
+Greek_OMEGA = 0x7d9
+Greek_alpha = 0x7e1
+Greek_beta = 0x7e2
+Greek_gamma = 0x7e3
+Greek_delta = 0x7e4
+Greek_epsilon = 0x7e5
+Greek_zeta = 0x7e6
+Greek_eta = 0x7e7
+Greek_theta = 0x7e8
+Greek_iota = 0x7e9
+Greek_kappa = 0x7ea
+Greek_lamda = 0x7eb
+Greek_lambda = 0x7eb
+Greek_mu = 0x7ec
+Greek_nu = 0x7ed
+Greek_xi = 0x7ee
+Greek_omicron = 0x7ef
+Greek_pi = 0x7f0
+Greek_rho = 0x7f1
+Greek_sigma = 0x7f2
+Greek_finalsmallsigma = 0x7f3
+Greek_tau = 0x7f4
+Greek_upsilon = 0x7f5
+Greek_phi = 0x7f6
+Greek_chi = 0x7f7
+Greek_psi = 0x7f8
+Greek_omega = 0x7f9
+Greek_switch = 0xFF7E
+leftradical = 0x8a1
+topleftradical = 0x8a2
+horizconnector = 0x8a3
+topintegral = 0x8a4
+botintegral = 0x8a5
+vertconnector = 0x8a6
+topleftsqbracket = 0x8a7
+botleftsqbracket = 0x8a8
+toprightsqbracket = 0x8a9
+botrightsqbracket = 0x8aa
+topleftparens = 0x8ab
+botleftparens = 0x8ac
+toprightparens = 0x8ad
+botrightparens = 0x8ae
+leftmiddlecurlybrace = 0x8af
+rightmiddlecurlybrace = 0x8b0
+topleftsummation = 0x8b1
+botleftsummation = 0x8b2
+topvertsummationconnector = 0x8b3
+botvertsummationconnector = 0x8b4
+toprightsummation = 0x8b5
+botrightsummation = 0x8b6
+rightmiddlesummation = 0x8b7
+lessthanequal = 0x8bc
+notequal = 0x8bd
+greaterthanequal = 0x8be
+integral = 0x8bf
+therefore = 0x8c0
+variation = 0x8c1
+infinity = 0x8c2
+nabla = 0x8c5
+approximate = 0x8c8
+similarequal = 0x8c9
+ifonlyif = 0x8cd
+implies = 0x8ce
+identical = 0x8cf
+radical = 0x8d6
+includedin = 0x8da
+includes = 0x8db
+intersection = 0x8dc
+union = 0x8dd
+logicaland = 0x8de
+logicalor = 0x8df
+partialderivative = 0x8ef
+function = 0x8f6
+leftarrow = 0x8fb
+uparrow = 0x8fc
+rightarrow = 0x8fd
+downarrow = 0x8fe
+blank = 0x9df
+soliddiamond = 0x9e0
+checkerboard = 0x9e1
+ht = 0x9e2
+ff = 0x9e3
+cr = 0x9e4
+lf = 0x9e5
+nl = 0x9e8
+vt = 0x9e9
+lowrightcorner = 0x9ea
+uprightcorner = 0x9eb
+upleftcorner = 0x9ec
+lowleftcorner = 0x9ed
+crossinglines = 0x9ee
+horizlinescan1 = 0x9ef
+horizlinescan3 = 0x9f0
+horizlinescan5 = 0x9f1
+horizlinescan7 = 0x9f2
+horizlinescan9 = 0x9f3
+leftt = 0x9f4
+rightt = 0x9f5
+bott = 0x9f6
+topt = 0x9f7
+vertbar = 0x9f8
+emspace = 0xaa1
+enspace = 0xaa2
+em3space = 0xaa3
+em4space = 0xaa4
+digitspace = 0xaa5
+punctspace = 0xaa6
+thinspace = 0xaa7
+hairspace = 0xaa8
+emdash = 0xaa9
+endash = 0xaaa
+signifblank = 0xaac
+ellipsis = 0xaae
+doubbaselinedot = 0xaaf
+onethird = 0xab0
+twothirds = 0xab1
+onefifth = 0xab2
+twofifths = 0xab3
+threefifths = 0xab4
+fourfifths = 0xab5
+onesixth = 0xab6
+fivesixths = 0xab7
+careof = 0xab8
+figdash = 0xabb
+leftanglebracket = 0xabc
+decimalpoint = 0xabd
+rightanglebracket = 0xabe
+marker = 0xabf
+oneeighth = 0xac3
+threeeighths = 0xac4
+fiveeighths = 0xac5
+seveneighths = 0xac6
+trademark = 0xac9
+signaturemark = 0xaca
+trademarkincircle = 0xacb
+leftopentriangle = 0xacc
+rightopentriangle = 0xacd
+emopencircle = 0xace
+emopenrectangle = 0xacf
+leftsinglequotemark = 0xad0
+rightsinglequotemark = 0xad1
+leftdoublequotemark = 0xad2
+rightdoublequotemark = 0xad3
+prescription = 0xad4
+minutes = 0xad6
+seconds = 0xad7
+latincross = 0xad9
+hexagram = 0xada
+filledrectbullet = 0xadb
+filledlefttribullet = 0xadc
+filledrighttribullet = 0xadd
+emfilledcircle = 0xade
+emfilledrect = 0xadf
+enopencircbullet = 0xae0
+enopensquarebullet = 0xae1
+openrectbullet = 0xae2
+opentribulletup = 0xae3
+opentribulletdown = 0xae4
+openstar = 0xae5
+enfilledcircbullet = 0xae6
+enfilledsqbullet = 0xae7
+filledtribulletup = 0xae8
+filledtribulletdown = 0xae9
+leftpointer = 0xaea
+rightpointer = 0xaeb
+club = 0xaec
+diamond = 0xaed
+heart = 0xaee
+maltesecross = 0xaf0
+dagger = 0xaf1
+doubledagger = 0xaf2
+checkmark = 0xaf3
+ballotcross = 0xaf4
+musicalsharp = 0xaf5
+musicalflat = 0xaf6
+malesymbol = 0xaf7
+femalesymbol = 0xaf8
+telephone = 0xaf9
+telephonerecorder = 0xafa
+phonographcopyright = 0xafb
+caret = 0xafc
+singlelowquotemark = 0xafd
+doublelowquotemark = 0xafe
+cursor = 0xaff
+leftcaret = 0xba3
+rightcaret = 0xba6
+downcaret = 0xba8
+upcaret = 0xba9
+overbar = 0xbc0
+downtack = 0xbc2
+upshoe = 0xbc3
+downstile = 0xbc4
+underbar = 0xbc6
+jot = 0xbca
+quad = 0xbcc
+uptack = 0xbce
+circle = 0xbcf
+upstile = 0xbd3
+downshoe = 0xbd6
+rightshoe = 0xbd8
+leftshoe = 0xbda
+lefttack = 0xbdc
+righttack = 0xbfc
+hebrew_doublelowline = 0xcdf
+hebrew_aleph = 0xce0
+hebrew_bet = 0xce1
+hebrew_beth = 0xce1
+hebrew_gimel = 0xce2
+hebrew_gimmel = 0xce2
+hebrew_dalet = 0xce3
+hebrew_daleth = 0xce3
+hebrew_he = 0xce4
+hebrew_waw = 0xce5
+hebrew_zain = 0xce6
+hebrew_zayin = 0xce6
+hebrew_chet = 0xce7
+hebrew_het = 0xce7
+hebrew_tet = 0xce8
+hebrew_teth = 0xce8
+hebrew_yod = 0xce9
+hebrew_finalkaph = 0xcea
+hebrew_kaph = 0xceb
+hebrew_lamed = 0xcec
+hebrew_finalmem = 0xced
+hebrew_mem = 0xcee
+hebrew_finalnun = 0xcef
+hebrew_nun = 0xcf0
+hebrew_samech = 0xcf1
+hebrew_samekh = 0xcf1
+hebrew_ayin = 0xcf2
+hebrew_finalpe = 0xcf3
+hebrew_pe = 0xcf4
+hebrew_finalzade = 0xcf5
+hebrew_finalzadi = 0xcf5
+hebrew_zade = 0xcf6
+hebrew_zadi = 0xcf6
+hebrew_qoph = 0xcf7
+hebrew_kuf = 0xcf7
+hebrew_resh = 0xcf8
+hebrew_shin = 0xcf9
+hebrew_taw = 0xcfa
+hebrew_taf = 0xcfa
+Hebrew_switch = 0xFF7E
+Thai_kokai = 0xda1
+Thai_khokhai = 0xda2
+Thai_khokhuat = 0xda3
+Thai_khokhwai = 0xda4
+Thai_khokhon = 0xda5
+Thai_khorakhang = 0xda6
+Thai_ngongu = 0xda7
+Thai_chochan = 0xda8
+Thai_choching = 0xda9
+Thai_chochang = 0xdaa
+Thai_soso = 0xdab
+Thai_chochoe = 0xdac
+Thai_yoying = 0xdad
+Thai_dochada = 0xdae
+Thai_topatak = 0xdaf
+Thai_thothan = 0xdb0
+Thai_thonangmontho = 0xdb1
+Thai_thophuthao = 0xdb2
+Thai_nonen = 0xdb3
+Thai_dodek = 0xdb4
+Thai_totao = 0xdb5
+Thai_thothung = 0xdb6
+Thai_thothahan = 0xdb7
+Thai_thothong = 0xdb8
+Thai_nonu = 0xdb9
+Thai_bobaimai = 0xdba
+Thai_popla = 0xdbb
+Thai_phophung = 0xdbc
+Thai_fofa = 0xdbd
+Thai_phophan = 0xdbe
+Thai_fofan = 0xdbf
+Thai_phosamphao = 0xdc0
+Thai_moma = 0xdc1
+Thai_yoyak = 0xdc2
+Thai_rorua = 0xdc3
+Thai_ru = 0xdc4
+Thai_loling = 0xdc5
+Thai_lu = 0xdc6
+Thai_wowaen = 0xdc7
+Thai_sosala = 0xdc8
+Thai_sorusi = 0xdc9
+Thai_sosua = 0xdca
+Thai_hohip = 0xdcb
+Thai_lochula = 0xdcc
+Thai_oang = 0xdcd
+Thai_honokhuk = 0xdce
+Thai_paiyannoi = 0xdcf
+Thai_saraa = 0xdd0
+Thai_maihanakat = 0xdd1
+Thai_saraaa = 0xdd2
+Thai_saraam = 0xdd3
+Thai_sarai = 0xdd4
+Thai_saraii = 0xdd5
+Thai_saraue = 0xdd6
+Thai_sarauee = 0xdd7
+Thai_sarau = 0xdd8
+Thai_sarauu = 0xdd9
+Thai_phinthu = 0xdda
+Thai_maihanakat_maitho = 0xdde
+Thai_baht = 0xddf
+Thai_sarae = 0xde0
+Thai_saraae = 0xde1
+Thai_sarao = 0xde2
+Thai_saraaimaimuan = 0xde3
+Thai_saraaimaimalai = 0xde4
+Thai_lakkhangyao = 0xde5
+Thai_maiyamok = 0xde6
+Thai_maitaikhu = 0xde7
+Thai_maiek = 0xde8
+Thai_maitho = 0xde9
+Thai_maitri = 0xdea
+Thai_maichattawa = 0xdeb
+Thai_thanthakhat = 0xdec
+Thai_nikhahit = 0xded
+Thai_leksun = 0xdf0
+Thai_leknung = 0xdf1
+Thai_leksong = 0xdf2
+Thai_leksam = 0xdf3
+Thai_leksi = 0xdf4
+Thai_lekha = 0xdf5
+Thai_lekhok = 0xdf6
+Thai_lekchet = 0xdf7
+Thai_lekpaet = 0xdf8
+Thai_lekkao = 0xdf9
+Hangul = 0xff31
+Hangul_Start = 0xff32
+Hangul_End = 0xff33
+Hangul_Hanja = 0xff34
+Hangul_Jamo = 0xff35
+Hangul_Romaja = 0xff36
+Hangul_Codeinput = 0xff37
+Hangul_Jeonja = 0xff38
+Hangul_Banja = 0xff39
+Hangul_PreHanja = 0xff3a
+Hangul_PostHanja = 0xff3b
+Hangul_SingleCandidate = 0xff3c
+Hangul_MultipleCandidate = 0xff3d
+Hangul_PreviousCandidate = 0xff3e
+Hangul_Special = 0xff3f
+Hangul_switch = 0xFF7E
+Hangul_Kiyeog = 0xea1
+Hangul_SsangKiyeog = 0xea2
+Hangul_KiyeogSios = 0xea3
+Hangul_Nieun = 0xea4
+Hangul_NieunJieuj = 0xea5
+Hangul_NieunHieuh = 0xea6
+Hangul_Dikeud = 0xea7
+Hangul_SsangDikeud = 0xea8
+Hangul_Rieul = 0xea9
+Hangul_RieulKiyeog = 0xeaa
+Hangul_RieulMieum = 0xeab
+Hangul_RieulPieub = 0xeac
+Hangul_RieulSios = 0xead
+Hangul_RieulTieut = 0xeae
+Hangul_RieulPhieuf = 0xeaf
+Hangul_RieulHieuh = 0xeb0
+Hangul_Mieum = 0xeb1
+Hangul_Pieub = 0xeb2
+Hangul_SsangPieub = 0xeb3
+Hangul_PieubSios = 0xeb4
+Hangul_Sios = 0xeb5
+Hangul_SsangSios = 0xeb6
+Hangul_Ieung = 0xeb7
+Hangul_Jieuj = 0xeb8
+Hangul_SsangJieuj = 0xeb9
+Hangul_Cieuc = 0xeba
+Hangul_Khieuq = 0xebb
+Hangul_Tieut = 0xebc
+Hangul_Phieuf = 0xebd
+Hangul_Hieuh = 0xebe
+Hangul_A = 0xebf
+Hangul_AE = 0xec0
+Hangul_YA = 0xec1
+Hangul_YAE = 0xec2
+Hangul_EO = 0xec3
+Hangul_E = 0xec4
+Hangul_YEO = 0xec5
+Hangul_YE = 0xec6
+Hangul_O = 0xec7
+Hangul_WA = 0xec8
+Hangul_WAE = 0xec9
+Hangul_OE = 0xeca
+Hangul_YO = 0xecb
+Hangul_U = 0xecc
+Hangul_WEO = 0xecd
+Hangul_WE = 0xece
+Hangul_WI = 0xecf
+Hangul_YU = 0xed0
+Hangul_EU = 0xed1
+Hangul_YI = 0xed2
+Hangul_I = 0xed3
+Hangul_J_Kiyeog = 0xed4
+Hangul_J_SsangKiyeog = 0xed5
+Hangul_J_KiyeogSios = 0xed6
+Hangul_J_Nieun = 0xed7
+Hangul_J_NieunJieuj = 0xed8
+Hangul_J_NieunHieuh = 0xed9
+Hangul_J_Dikeud = 0xeda
+Hangul_J_Rieul = 0xedb
+Hangul_J_RieulKiyeog = 0xedc
+Hangul_J_RieulMieum = 0xedd
+Hangul_J_RieulPieub = 0xede
+Hangul_J_RieulSios = 0xedf
+Hangul_J_RieulTieut = 0xee0
+Hangul_J_RieulPhieuf = 0xee1
+Hangul_J_RieulHieuh = 0xee2
+Hangul_J_Mieum = 0xee3
+Hangul_J_Pieub = 0xee4
+Hangul_J_PieubSios = 0xee5
+Hangul_J_Sios = 0xee6
+Hangul_J_SsangSios = 0xee7
+Hangul_J_Ieung = 0xee8
+Hangul_J_Jieuj = 0xee9
+Hangul_J_Cieuc = 0xeea
+Hangul_J_Khieuq = 0xeeb
+Hangul_J_Tieut = 0xeec
+Hangul_J_Phieuf = 0xeed
+Hangul_J_Hieuh = 0xeee
+Hangul_RieulYeorinHieuh = 0xeef
+Hangul_SunkyeongeumMieum = 0xef0
+Hangul_SunkyeongeumPieub = 0xef1
+Hangul_PanSios = 0xef2
+Hangul_KkogjiDalrinIeung = 0xef3
+Hangul_SunkyeongeumPhieuf = 0xef4
+Hangul_YeorinHieuh = 0xef5
+Hangul_AraeA = 0xef6
+Hangul_AraeAE = 0xef7
+Hangul_J_PanSios = 0xef8
+Hangul_J_KkogjiDalrinIeung = 0xef9
+Hangul_J_YeorinHieuh = 0xefa
+Korean_Won = 0xeff
+Armenian_eternity = 0x14a1
+Armenian_section_sign = 0x14a2
+Armenian_full_stop = 0x14a3
+Armenian_verjaket = 0x14a3
+Armenian_parenright = 0x14a4
+Armenian_parenleft = 0x14a5
+Armenian_guillemotright = 0x14a6
+Armenian_guillemotleft = 0x14a7
+Armenian_em_dash = 0x14a8
+Armenian_dot = 0x14a9
+Armenian_mijaket = 0x14a9
+Armenian_separation_mark = 0x14aa
+Armenian_but = 0x14aa
+Armenian_comma = 0x14ab
+Armenian_en_dash = 0x14ac
+Armenian_hyphen = 0x14ad
+Armenian_yentamna = 0x14ad
+Armenian_ellipsis = 0x14ae
+Armenian_exclam = 0x14af
+Armenian_amanak = 0x14af
+Armenian_accent = 0x14b0
+Armenian_shesht = 0x14b0
+Armenian_question = 0x14b1
+Armenian_paruyk = 0x14b1
+Armenian_AYB = 0x14b2
+Armenian_ayb = 0x14b3
+Armenian_BEN = 0x14b4
+Armenian_ben = 0x14b5
+Armenian_GIM = 0x14b6
+Armenian_gim = 0x14b7
+Armenian_DA = 0x14b8
+Armenian_da = 0x14b9
+Armenian_YECH = 0x14ba
+Armenian_yech = 0x14bb
+Armenian_ZA = 0x14bc
+Armenian_za = 0x14bd
+Armenian_E = 0x14be
+Armenian_e = 0x14bf
+Armenian_AT = 0x14c0
+Armenian_at = 0x14c1
+Armenian_TO = 0x14c2
+Armenian_to = 0x14c3
+Armenian_ZHE = 0x14c4
+Armenian_zhe = 0x14c5
+Armenian_INI = 0x14c6
+Armenian_ini = 0x14c7
+Armenian_LYUN = 0x14c8
+Armenian_lyun = 0x14c9
+Armenian_KHE = 0x14ca
+Armenian_khe = 0x14cb
+Armenian_TSA = 0x14cc
+Armenian_tsa = 0x14cd
+Armenian_KEN = 0x14ce
+Armenian_ken = 0x14cf
+Armenian_HO = 0x14d0
+Armenian_ho = 0x14d1
+Armenian_DZA = 0x14d2
+Armenian_dza = 0x14d3
+Armenian_GHAT = 0x14d4
+Armenian_ghat = 0x14d5
+Armenian_TCHE = 0x14d6
+Armenian_tche = 0x14d7
+Armenian_MEN = 0x14d8
+Armenian_men = 0x14d9
+Armenian_HI = 0x14da
+Armenian_hi = 0x14db
+Armenian_NU = 0x14dc
+Armenian_nu = 0x14dd
+Armenian_SHA = 0x14de
+Armenian_sha = 0x14df
+Armenian_VO = 0x14e0
+Armenian_vo = 0x14e1
+Armenian_CHA = 0x14e2
+Armenian_cha = 0x14e3
+Armenian_PE = 0x14e4
+Armenian_pe = 0x14e5
+Armenian_JE = 0x14e6
+Armenian_je = 0x14e7
+Armenian_RA = 0x14e8
+Armenian_ra = 0x14e9
+Armenian_SE = 0x14ea
+Armenian_se = 0x14eb
+Armenian_VEV = 0x14ec
+Armenian_vev = 0x14ed
+Armenian_TYUN = 0x14ee
+Armenian_tyun = 0x14ef
+Armenian_RE = 0x14f0
+Armenian_re = 0x14f1
+Armenian_TSO = 0x14f2
+Armenian_tso = 0x14f3
+Armenian_VYUN = 0x14f4
+Armenian_vyun = 0x14f5
+Armenian_PYUR = 0x14f6
+Armenian_pyur = 0x14f7
+Armenian_KE = 0x14f8
+Armenian_ke = 0x14f9
+Armenian_O = 0x14fa
+Armenian_o = 0x14fb
+Armenian_FE = 0x14fc
+Armenian_fe = 0x14fd
+Armenian_apostrophe = 0x14fe
+Armenian_ligature_ew = 0x14ff
+Georgian_an = 0x15d0
+Georgian_ban = 0x15d1
+Georgian_gan = 0x15d2
+Georgian_don = 0x15d3
+Georgian_en = 0x15d4
+Georgian_vin = 0x15d5
+Georgian_zen = 0x15d6
+Georgian_tan = 0x15d7
+Georgian_in = 0x15d8
+Georgian_kan = 0x15d9
+Georgian_las = 0x15da
+Georgian_man = 0x15db
+Georgian_nar = 0x15dc
+Georgian_on = 0x15dd
+Georgian_par = 0x15de
+Georgian_zhar = 0x15df
+Georgian_rae = 0x15e0
+Georgian_san = 0x15e1
+Georgian_tar = 0x15e2
+Georgian_un = 0x15e3
+Georgian_phar = 0x15e4
+Georgian_khar = 0x15e5
+Georgian_ghan = 0x15e6
+Georgian_qar = 0x15e7
+Georgian_shin = 0x15e8
+Georgian_chin = 0x15e9
+Georgian_can = 0x15ea
+Georgian_jil = 0x15eb
+Georgian_cil = 0x15ec
+Georgian_char = 0x15ed
+Georgian_xan = 0x15ee
+Georgian_jhan = 0x15ef
+Georgian_hae = 0x15f0
+Georgian_he = 0x15f1
+Georgian_hie = 0x15f2
+Georgian_we = 0x15f3
+Georgian_har = 0x15f4
+Georgian_hoe = 0x15f5
+Georgian_fi = 0x15f6
+EcuSign = 0x20a0
+ColonSign = 0x20a1
+CruzeiroSign = 0x20a2
+FFrancSign = 0x20a3
+LiraSign = 0x20a4
+MillSign = 0x20a5
+NairaSign = 0x20a6
+PesetaSign = 0x20a7
+RupeeSign = 0x20a8
+WonSign = 0x20a9
+NewSheqelSign = 0x20aa
+DongSign = 0x20ab
+EuroSign = 0x20ac
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
new file mode 100644
index 00000000..76fa58d8
--- /dev/null
+++ b/gi/pygi-argument.c
@@ -0,0 +1,1956 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org>
+ *
+ * pygi-argument.c: GArgument - PyObject conversion functions.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "pygi-private.h"
+
+#include <string.h>
+#include <time.h>
+
+#include <datetime.h>
+#include <pygobject.h>
+
+
+static void
+_pygi_g_type_tag_py_bounds (GITypeTag type_tag,
+ PyObject **lower,
+ PyObject **upper)
+{
+ switch (type_tag) {
+ case GI_TYPE_TAG_INT8:
+ *lower = PyInt_FromLong (-128);
+ *upper = PyInt_FromLong (127);
+ break;
+ case GI_TYPE_TAG_UINT8:
+ *upper = PyInt_FromLong (255);
+ *lower = PyInt_FromLong (0);
+ break;
+ case GI_TYPE_TAG_INT16:
+ *lower = PyInt_FromLong (-32768);
+ *upper = PyInt_FromLong (32767);
+ break;
+ case GI_TYPE_TAG_UINT16:
+ *upper = PyInt_FromLong (65535);
+ *lower = PyInt_FromLong (0);
+ break;
+ case GI_TYPE_TAG_INT32:
+ *lower = PyInt_FromLong (G_MININT32);
+ *upper = PyInt_FromLong (G_MAXINT32);
+ break;
+ case GI_TYPE_TAG_UINT32:
+ /* Note: On 32-bit archs, this number doesn't fit in a long. */
+ *upper = PyLong_FromLongLong (G_MAXUINT32);
+ *lower = PyInt_FromLong (0);
+ break;
+ case GI_TYPE_TAG_INT64:
+ /* Note: On 32-bit archs, these numbers don't fit in a long. */
+ *lower = PyLong_FromLongLong (G_MININT64);
+ *upper = PyLong_FromLongLong (G_MAXINT64);
+ break;
+ case GI_TYPE_TAG_UINT64:
+ *upper = PyLong_FromUnsignedLongLong (G_MAXUINT64);
+ *lower = PyInt_FromLong (0);
+ break;
+ case GI_TYPE_TAG_SHORT:
+ *lower = PyInt_FromLong (G_MINSHORT);
+ *upper = PyInt_FromLong (G_MAXSHORT);
+ break;
+ case GI_TYPE_TAG_USHORT:
+ *upper = PyInt_FromLong (G_MAXUSHORT);
+ *lower = PyInt_FromLong (0);
+ break;
+ case GI_TYPE_TAG_INT:
+ *lower = PyInt_FromLong (G_MININT);
+ *upper = PyInt_FromLong (G_MAXINT);
+ break;
+ case GI_TYPE_TAG_UINT:
+ /* Note: On 32-bit archs, this number doesn't fit in a long. */
+ *upper = PyLong_FromLongLong (G_MAXUINT);
+ *lower = PyInt_FromLong (0);
+ break;
+ case GI_TYPE_TAG_LONG:
+ case GI_TYPE_TAG_SSIZE:
+ *lower = PyInt_FromLong (G_MINLONG);
+ *upper = PyInt_FromLong (G_MAXLONG);
+ break;
+ case GI_TYPE_TAG_ULONG:
+ case GI_TYPE_TAG_SIZE:
+ *upper = PyLong_FromUnsignedLongLong (G_MAXULONG);
+ *lower = PyInt_FromLong (0);
+ break;
+ case GI_TYPE_TAG_FLOAT:
+ *upper = PyFloat_FromDouble (G_MAXFLOAT);
+ *lower = PyFloat_FromDouble (-G_MAXFLOAT);
+ break;
+ case GI_TYPE_TAG_DOUBLE:
+ *upper = PyFloat_FromDouble (G_MAXDOUBLE);
+ *lower = PyFloat_FromDouble (-G_MAXDOUBLE);
+ break;
+ default:
+ PyErr_SetString (PyExc_TypeError, "Non-numeric type tag");
+ *lower = *upper = NULL;
+ return;
+ }
+}
+
+gint
+_pygi_g_registered_type_info_check_object (GIRegisteredTypeInfo *info,
+ gboolean is_instance,
+ PyObject *object)
+{
+ gint retval;
+
+ GType g_type;
+ PyObject *py_type;
+ gchar *type_name_expected = NULL;
+ GIInfoType interface_type;
+
+ interface_type = g_base_info_get_type (info);
+ if ( (interface_type == GI_INFO_TYPE_STRUCT) &&
+ (g_struct_info_is_foreign ( (GIStructInfo*) info))) {
+ /* TODO: Could we check is the correct foreign type? */
+ return 1;
+ }
+
+ g_type = g_registered_type_info_get_g_type (info);
+ if (g_type != G_TYPE_NONE) {
+ py_type = _pygi_type_get_from_g_type (g_type);
+ } else {
+ py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) info);
+ }
+
+ if (py_type == NULL) {
+ return 0;
+ }
+
+ g_assert (PyType_Check (py_type));
+
+ if (is_instance) {
+ retval = PyObject_IsInstance (object, py_type);
+ if (!retval) {
+ type_name_expected = _pygi_g_base_info_get_fullname (
+ (GIBaseInfo *) info);
+ }
+ } else {
+ if (!PyObject_Type (py_type)) {
+ type_name_expected = "type";
+ retval = 0;
+ } else if (!PyType_IsSubtype ( (PyTypeObject *) object,
+ (PyTypeObject *) py_type)) {
+ type_name_expected = _pygi_g_base_info_get_fullname (
+ (GIBaseInfo *) info);
+ retval = 0;
+ } else {
+ retval = 1;
+ }
+ }
+
+ Py_DECREF (py_type);
+
+ if (!retval) {
+ PyTypeObject *object_type;
+
+ if (type_name_expected == NULL) {
+ return -1;
+ }
+
+ object_type = (PyTypeObject *) PyObject_Type (object);
+ if (object_type == NULL) {
+ return -1;
+ }
+
+ PyErr_Format (PyExc_TypeError, "Must be %s, not %s",
+ type_name_expected, object_type->tp_name);
+
+ g_free (type_name_expected);
+ }
+
+ return retval;
+}
+
+gint
+_pygi_g_type_info_check_object (GITypeInfo *type_info,
+ PyObject *object,
+ gboolean allow_none)
+{
+ GITypeTag type_tag;
+ gint retval = 1;
+
+ if (allow_none && object == Py_None) {
+ return retval;
+ }
+
+ type_tag = g_type_info_get_tag (type_info);
+
+ switch (type_tag) {
+ case GI_TYPE_TAG_VOID:
+ /* No check; VOID means undefined type */
+ break;
+ case GI_TYPE_TAG_BOOLEAN:
+ /* No check; every Python object has a truth value. */
+ break;
+ case GI_TYPE_TAG_INT8:
+ case GI_TYPE_TAG_UINT8:
+ case GI_TYPE_TAG_INT16:
+ case GI_TYPE_TAG_UINT16:
+ case GI_TYPE_TAG_INT32:
+ case GI_TYPE_TAG_UINT32:
+ case GI_TYPE_TAG_INT64:
+ case GI_TYPE_TAG_UINT64:
+ case GI_TYPE_TAG_SHORT:
+ case GI_TYPE_TAG_USHORT:
+ case GI_TYPE_TAG_INT:
+ case GI_TYPE_TAG_UINT:
+ case GI_TYPE_TAG_LONG:
+ case GI_TYPE_TAG_ULONG:
+ case GI_TYPE_TAG_SSIZE:
+ case GI_TYPE_TAG_SIZE:
+ case GI_TYPE_TAG_FLOAT:
+ case GI_TYPE_TAG_DOUBLE:
+ {
+ PyObject *number, *lower, *upper;
+
+ if (!PyNumber_Check (object)) {
+ PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+ object->ob_type->tp_name);
+ retval = 0;
+ break;
+ }
+
+ if (type_tag == GI_TYPE_TAG_FLOAT || type_tag == GI_TYPE_TAG_DOUBLE) {
+ number = PyNumber_Float (object);
+ } else {
+ number = PyNumber_Int (object);
+ }
+
+ _pygi_g_type_tag_py_bounds (type_tag, &lower, &upper);
+
+ if (lower == NULL || upper == NULL || number == NULL) {
+ retval = -1;
+ goto check_number_release;
+ }
+
+ /* Check bounds */
+ if (PyObject_Compare (lower, number) > 0
+ || PyObject_Compare (upper, number) < 0) {
+ PyObject *lower_str;
+ PyObject *upper_str;
+
+ if (PyErr_Occurred()) {
+ retval = -1;
+ goto check_number_release;
+ }
+
+ lower_str = PyObject_Str (lower);
+ upper_str = PyObject_Str (upper);
+ if (lower_str == NULL || upper_str == NULL) {
+ retval = -1;
+ goto check_number_error_release;
+ }
+
+ PyErr_Format (PyExc_ValueError, "Must range from %s to %s",
+ PyString_AS_STRING (lower_str),
+ PyString_AS_STRING (upper_str));
+
+ retval = 0;
+
+check_number_error_release:
+ Py_XDECREF (lower_str);
+ Py_XDECREF (upper_str);
+ }
+
+check_number_release:
+ Py_XDECREF (number);
+ Py_XDECREF (lower);
+ Py_XDECREF (upper);
+ break;
+ }
+ case GI_TYPE_TAG_TIME_T:
+ if (!PyDateTime_Check (object)) {
+ PyErr_Format (PyExc_TypeError, "Must be datetime.datetime, not %s",
+ object->ob_type->tp_name);
+ retval = 0;
+ }
+ break;
+ case GI_TYPE_TAG_GTYPE:
+ {
+ gint is_instance;
+
+ is_instance = PyObject_IsInstance (object, (PyObject *) &PyGTypeWrapper_Type);
+ if (is_instance < 0) {
+ retval = -1;
+ break;
+ }
+
+ if (!is_instance && (!PyType_Check (object) || pyg_type_from_object (object) == 0)) {
+ PyErr_Format (PyExc_TypeError, "Must be gobject.GType, not %s",
+ object->ob_type->tp_name);
+ retval = 0;
+ }
+ break;
+ }
+ case GI_TYPE_TAG_UTF8:
+ case GI_TYPE_TAG_FILENAME:
+ if (!PyString_Check (object)) {
+ PyErr_Format (PyExc_TypeError, "Must be string, not %s",
+ object->ob_type->tp_name);
+ retval = 0;
+ }
+ break;
+ case GI_TYPE_TAG_ARRAY:
+ {
+ gssize fixed_size;
+ Py_ssize_t length;
+ GITypeInfo *item_type_info;
+ Py_ssize_t i;
+
+ if (!PySequence_Check (object)) {
+ PyErr_Format (PyExc_TypeError, "Must be sequence, not %s",
+ object->ob_type->tp_name);
+ retval = 0;
+ break;
+ }
+
+ length = PySequence_Length (object);
+ if (length < 0) {
+ retval = -1;
+ break;
+ }
+
+ fixed_size = g_type_info_get_array_fixed_size (type_info);
+ if (fixed_size >= 0 && length != fixed_size) {
+ PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd",
+ fixed_size, length);
+ retval = 0;
+ break;
+ }
+
+ item_type_info = g_type_info_get_param_type (type_info, 0);
+ g_assert (item_type_info != NULL);
+
+ for (i = 0; i < length; i++) {
+ PyObject *item;
+
+ item = PySequence_GetItem (object, i);
+ if (item == NULL) {
+ retval = -1;
+ break;
+ }
+
+ retval = _pygi_g_type_info_check_object (item_type_info, item, TRUE);
+
+ Py_DECREF (item);
+
+ if (retval < 0) {
+ break;
+ }
+ if (!retval) {
+ _PyGI_ERROR_PREFIX ("Item %zd: ", i);
+ break;
+ }
+ }
+
+ g_base_info_unref ( (GIBaseInfo *) item_type_info);
+
+ break;
+ }
+ case GI_TYPE_TAG_INTERFACE:
+ {
+ GIBaseInfo *info;
+ GIInfoType info_type;
+
+ info = g_type_info_get_interface (type_info);
+ g_assert (info != NULL);
+
+ info_type = g_base_info_get_type (info);
+
+ switch (info_type) {
+ case GI_INFO_TYPE_CALLBACK:
+ if (!PyCallable_Check (object)) {
+ PyErr_Format (PyExc_TypeError, "Must be callable, not %s",
+ object->ob_type->tp_name);
+ retval = 0;
+ }
+ break;
+ case GI_INFO_TYPE_ENUM:
+ retval = _pygi_g_registered_type_info_check_object (
+ (GIRegisteredTypeInfo *) info, TRUE, object);
+ break;
+ case GI_INFO_TYPE_FLAGS:
+ if (PyNumber_Check (object)) {
+ /* Accept 0 as a valid flag value */
+ PyObject *number = PyNumber_Int (object);
+ if (number == NULL)
+ PyErr_Clear();
+ else {
+ long value = PyInt_AsLong (number);
+ if (value == 0)
+ break;
+ else if (value == -1)
+ PyErr_Clear();
+ }
+ }
+ retval = _pygi_g_registered_type_info_check_object (
+ (GIRegisteredTypeInfo *) info, TRUE, object);
+ break;
+ case GI_INFO_TYPE_STRUCT:
+ {
+ GType type;
+
+ /* Handle special cases. */
+ type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
+ if (g_type_is_a (type, G_TYPE_VALUE)) {
+ GType object_type;
+ object_type = pyg_type_from_object ( (PyObject *) object->ob_type);
+ if (object_type == G_TYPE_INVALID) {
+ PyErr_Format (PyExc_TypeError, "Must be of a known GType, not %s",
+ object->ob_type->tp_name);
+ retval = 0;
+ }
+ break;
+ } else if (g_type_is_a (type, G_TYPE_CLOSURE)) {
+ if (!PyCallable_Check (object)) {
+ PyErr_Format (PyExc_TypeError, "Must be callable, not %s",
+ object->ob_type->tp_name);
+ retval = 0;
+ }
+ break;
+ }
+
+ /* Fallback. */
+ }
+ case GI_INFO_TYPE_BOXED:
+ case GI_INFO_TYPE_INTERFACE:
+ case GI_INFO_TYPE_OBJECT:
+ case GI_INFO_TYPE_UNION:
+ retval = _pygi_g_registered_type_info_check_object ( (GIRegisteredTypeInfo *) info, TRUE, object);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ g_base_info_unref (info);
+ break;
+ }
+ case GI_TYPE_TAG_GLIST:
+ case GI_TYPE_TAG_GSLIST:
+ {
+ Py_ssize_t length;
+ GITypeInfo *item_type_info;
+ Py_ssize_t i;
+
+ if (!PySequence_Check (object)) {
+ PyErr_Format (PyExc_TypeError, "Must be sequence, not %s",
+ object->ob_type->tp_name);
+ retval = 0;
+ break;
+ }
+
+ length = PySequence_Length (object);
+ if (length < 0) {
+ retval = -1;
+ break;
+ }
+
+ item_type_info = g_type_info_get_param_type (type_info, 0);
+ g_assert (item_type_info != NULL);
+
+ for (i = 0; i < length; i++) {
+ PyObject *item;
+
+ item = PySequence_GetItem (object, i);
+ if (item == NULL) {
+ retval = -1;
+ break;
+ }
+
+ retval = _pygi_g_type_info_check_object (item_type_info, item, TRUE);
+
+ Py_DECREF (item);
+
+ if (retval < 0) {
+ break;
+ }
+ if (!retval) {
+ _PyGI_ERROR_PREFIX ("Item %zd: ", i);
+ break;
+ }
+ }
+
+ g_base_info_unref ( (GIBaseInfo *) item_type_info);
+ break;
+ }
+ case GI_TYPE_TAG_GHASH:
+ {
+ Py_ssize_t length;
+ PyObject *keys;
+ PyObject *values;
+ GITypeInfo *key_type_info;
+ GITypeInfo *value_type_info;
+ Py_ssize_t i;
+
+ if (!PyMapping_Check (object)) {
+ PyErr_Format (PyExc_TypeError, "Must be mapping, not %s",
+ object->ob_type->tp_name);
+ retval = 0;
+ break;
+ }
+
+ length = PyMapping_Length (object);
+ if (length < 0) {
+ retval = -1;
+ break;
+ }
+
+ keys = PyMapping_Keys (object);
+ if (keys == NULL) {
+ retval = -1;
+ break;
+ }
+
+ values = PyMapping_Values (object);
+ if (values == NULL) {
+ retval = -1;
+ Py_DECREF (keys);
+ break;
+ }
+
+ key_type_info = g_type_info_get_param_type (type_info, 0);
+ g_assert (key_type_info != NULL);
+
+ value_type_info = g_type_info_get_param_type (type_info, 1);
+ g_assert (value_type_info != NULL);
+
+ for (i = 0; i < length; i++) {
+ PyObject *key;
+ PyObject *value;
+
+ key = PyList_GET_ITEM (keys, i);
+ value = PyList_GET_ITEM (values, i);
+
+ retval = _pygi_g_type_info_check_object (key_type_info, key, TRUE);
+ if (retval < 0) {
+ break;
+ }
+ if (!retval) {
+ _PyGI_ERROR_PREFIX ("Key %zd :", i);
+ break;
+ }
+
+ retval = _pygi_g_type_info_check_object (value_type_info, value, TRUE);
+ if (retval < 0) {
+ break;
+ }
+ if (!retval) {
+ _PyGI_ERROR_PREFIX ("Value %zd :", i);
+ break;
+ }
+ }
+
+ g_base_info_unref ( (GIBaseInfo *) key_type_info);
+ g_base_info_unref ( (GIBaseInfo *) value_type_info);
+ Py_DECREF (values);
+ Py_DECREF (keys);
+ break;
+ }
+ case GI_TYPE_TAG_ERROR:
+ PyErr_SetString (PyExc_NotImplementedError, "Error marshalling is not supported yet");
+ /* TODO */
+ break;
+ }
+
+ return retval;
+}
+
+GArray *
+_pygi_argument_to_array (GArgument *arg,
+ GArgument *args[],
+ GITypeInfo *type_info,
+ gboolean is_method)
+{
+ GITypeInfo *item_type_info;
+ gboolean is_zero_terminated;
+ gsize item_size;
+ gssize length;
+ GArray *g_array;
+
+ if (arg->v_pointer == NULL) {
+ return NULL;
+ }
+
+ is_zero_terminated = g_type_info_is_zero_terminated (type_info);
+ item_type_info = g_type_info_get_param_type (type_info, 0);
+
+ item_size = _pygi_g_type_info_size (item_type_info);
+
+ g_base_info_unref ( (GIBaseInfo *) item_type_info);
+
+ if (is_zero_terminated) {
+ length = g_strv_length (arg->v_pointer);
+ } else {
+ length = g_type_info_get_array_fixed_size (type_info);
+ if (length < 0) {
+ gint length_arg_pos;
+
+ length_arg_pos = g_type_info_get_array_length (type_info);
+ g_assert (length_arg_pos >= 0);
+
+ if (is_method) {
+ length_arg_pos--;
+ }
+
+ g_assert (length_arg_pos >= 0);
+
+ /* FIXME: Take into account the type of the argument. */
+ length = args[length_arg_pos]->v_int;
+ }
+ }
+
+ g_assert (length >= 0);
+
+ g_array = g_array_new (is_zero_terminated, FALSE, item_size);
+
+ g_array->data = arg->v_pointer;
+ g_array->len = length;
+
+ return g_array;
+}
+
+GArgument
+_pygi_argument_from_object (PyObject *object,
+ GITypeInfo *type_info,
+ GITransfer transfer)
+{
+ GArgument arg;
+ GITypeTag type_tag;
+
+ type_tag = g_type_info_get_tag (type_info);
+
+ switch (type_tag) {
+ case GI_TYPE_TAG_VOID:
+ g_warn_if_fail (transfer == GI_TRANSFER_NOTHING);
+ arg.v_pointer = object;
+ break;
+ case GI_TYPE_TAG_BOOLEAN:
+ {
+ arg.v_boolean = PyObject_IsTrue (object);
+ break;
+ }
+ case GI_TYPE_TAG_INT8:
+ case GI_TYPE_TAG_UINT8:
+ case GI_TYPE_TAG_INT16:
+ case GI_TYPE_TAG_UINT16:
+ case GI_TYPE_TAG_INT32:
+ case GI_TYPE_TAG_SHORT:
+ case GI_TYPE_TAG_USHORT:
+ case GI_TYPE_TAG_INT:
+ case GI_TYPE_TAG_LONG:
+ case GI_TYPE_TAG_SSIZE:
+ {
+ PyObject *int_;
+
+ int_ = PyNumber_Int (object);
+ if (int_ == NULL) {
+ break;
+ }
+
+ arg.v_long = PyInt_AsLong (int_);
+
+ Py_DECREF (int_);
+
+ break;
+ }
+ case GI_TYPE_TAG_UINT32:
+ case GI_TYPE_TAG_UINT64:
+ case GI_TYPE_TAG_UINT:
+ case GI_TYPE_TAG_ULONG:
+ case GI_TYPE_TAG_SIZE:
+ {
+ PyObject *number;
+ guint64 value;
+
+ number = PyNumber_Int (object);
+ if (number == NULL) {
+ break;
+ }
+
+ if (PyInt_Check (number)) {
+ value = PyInt_AS_LONG (number);
+ } else {
+ value = PyLong_AsUnsignedLongLong (number);
+ }
+
+ arg.v_uint64 = value;
+
+ Py_DECREF (number);
+
+ break;
+ }
+ case GI_TYPE_TAG_INT64:
+ {
+ PyObject *number;
+ gint64 value;
+
+ number = PyNumber_Int (object);
+ if (number == NULL) {
+ break;
+ }
+
+ if (PyInt_Check (number)) {
+ value = PyInt_AS_LONG (number);
+ } else {
+ value = PyLong_AsLongLong (number);
+ }
+
+ arg.v_int64 = value;
+
+ Py_DECREF (number);
+
+ break;
+ }
+ case GI_TYPE_TAG_FLOAT:
+ {
+ PyObject *float_;
+
+ float_ = PyNumber_Float (object);
+ if (float_ == NULL) {
+ break;
+ }
+
+ arg.v_float = (float) PyFloat_AsDouble (float_);
+ Py_DECREF (float_);
+
+ break;
+ }
+ case GI_TYPE_TAG_DOUBLE:
+ {
+ PyObject *float_;
+
+ float_ = PyNumber_Float (object);
+ if (float_ == NULL) {
+ break;
+ }
+
+ arg.v_double = PyFloat_AsDouble (float_);
+ Py_DECREF (float_);
+
+ break;
+ }
+ case GI_TYPE_TAG_TIME_T:
+ {
+ PyDateTime_DateTime *py_datetime;
+ struct tm datetime;
+
+ py_datetime = (PyDateTime_DateTime *) object;
+
+ if (py_datetime->hastzinfo) {
+ if (PyErr_WarnEx (NULL, "tzinfo ignored; only local time is supported", 1) < 0) {
+ break;
+ }
+ }
+
+ datetime.tm_sec = PyDateTime_DATE_GET_SECOND (py_datetime);
+ datetime.tm_min = PyDateTime_DATE_GET_MINUTE (py_datetime);
+ datetime.tm_hour = PyDateTime_DATE_GET_HOUR (py_datetime);
+ datetime.tm_mday = PyDateTime_GET_DAY (py_datetime);
+ datetime.tm_mon = PyDateTime_GET_MONTH (py_datetime) - 1;
+ datetime.tm_year = PyDateTime_GET_YEAR (py_datetime) - 1900;
+ datetime.tm_isdst = -1;
+
+ arg.v_long = mktime (&datetime);
+ if (arg.v_long == -1) {
+ PyErr_SetString (PyExc_RuntimeError, "datetime conversion failed");
+ break;
+ }
+
+ break;
+ }
+ case GI_TYPE_TAG_GTYPE:
+ {
+ arg.v_long = pyg_type_from_object (object);
+
+ break;
+ }
+ case GI_TYPE_TAG_UTF8:
+ {
+ const gchar *string;
+
+ if (object == Py_None) {
+ arg.v_string = NULL;
+ break;
+ }
+
+ string = PyString_AsString (object);
+
+ /* Don't need to check for errors, since g_strdup is NULL-proof. */
+ arg.v_string = g_strdup (string);
+ break;
+ }
+ case GI_TYPE_TAG_FILENAME:
+ {
+ GError *error = NULL;
+ const gchar *string;
+
+ string = PyString_AsString (object);
+ if (string == NULL) {
+ break;
+ }
+
+ arg.v_string = g_filename_from_utf8 (string, -1, NULL, NULL, &error);
+ if (arg.v_string == NULL) {
+ PyErr_SetString (PyExc_Exception, error->message);
+ /* TODO: Convert the error to an exception. */
+ }
+
+ break;
+ }
+ case GI_TYPE_TAG_ARRAY:
+ {
+ Py_ssize_t length;
+ gboolean is_zero_terminated;
+ GITypeInfo *item_type_info;
+ gsize item_size;
+ GArray *array;
+ GITransfer item_transfer;
+ Py_ssize_t i;
+
+ if (object == Py_None) {
+ arg.v_pointer = NULL;
+ break;
+ }
+
+ length = PySequence_Length (object);
+ if (length < 0) {
+ break;
+ }
+
+ is_zero_terminated = g_type_info_is_zero_terminated (type_info);
+ item_type_info = g_type_info_get_param_type (type_info, 0);
+
+ item_size = _pygi_g_type_info_size (item_type_info);
+
+ array = g_array_sized_new (is_zero_terminated, FALSE, item_size, length);
+ if (array == NULL) {
+ g_base_info_unref ( (GIBaseInfo *) item_type_info);
+ PyErr_NoMemory();
+ break;
+ }
+
+ item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
+
+ for (i = 0; i < length; i++) {
+ PyObject *py_item;
+ GArgument item;
+
+ py_item = PySequence_GetItem (object, i);
+ if (py_item == NULL) {
+ goto array_item_error;
+ }
+
+ item = _pygi_argument_from_object (py_item, item_type_info, item_transfer);
+
+ Py_DECREF (py_item);
+
+ if (PyErr_Occurred()) {
+ goto array_item_error;
+ }
+
+ g_array_insert_val (array, i, item);
+ continue;
+
+array_item_error:
+ /* Free everything we have converted so far. */
+ _pygi_argument_release ( (GArgument *) &array, type_info,
+ GI_TRANSFER_NOTHING, GI_DIRECTION_IN);
+ array = NULL;
+
+ _PyGI_ERROR_PREFIX ("Item %zd: ", i);
+ break;
+ }
+
+ arg.v_pointer = array;
+
+ g_base_info_unref ( (GIBaseInfo *) item_type_info);
+ break;
+ }
+ case GI_TYPE_TAG_INTERFACE:
+ {
+ GIBaseInfo *info;
+ GIInfoType info_type;
+
+ info = g_type_info_get_interface (type_info);
+ info_type = g_base_info_get_type (info);
+
+ switch (info_type) {
+ case GI_INFO_TYPE_CALLBACK:
+ /* This should be handled in invoke() */
+ g_assert_not_reached();
+ break;
+ case GI_INFO_TYPE_BOXED:
+ case GI_INFO_TYPE_STRUCT:
+ case GI_INFO_TYPE_UNION:
+ {
+ GType type;
+
+ if (object == Py_None) {
+ arg.v_pointer = NULL;
+ break;
+ }
+
+ type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
+
+ /* Handle special cases first. */
+ if (g_type_is_a (type, G_TYPE_VALUE)) {
+ GValue *value;
+ GType object_type;
+ gint retval;
+
+ object_type = pyg_type_from_object ( (PyObject *) object->ob_type);
+ if (object_type == G_TYPE_INVALID) {
+ PyErr_SetString (PyExc_RuntimeError, "unable to retrieve object's GType");
+ break;
+ }
+
+ g_warn_if_fail (transfer == GI_TRANSFER_NOTHING);
+
+ value = g_slice_new0 (GValue);
+ g_value_init (value, object_type);
+
+ retval = pyg_value_from_pyobject (value, object);
+ if (retval < 0) {
+ g_slice_free (GValue, value);
+ PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GValue failed");
+ break;
+ }
+
+ arg.v_pointer = value;
+ } else if (g_type_is_a (type, G_TYPE_CLOSURE)) {
+ GClosure *closure;
+
+ g_warn_if_fail (transfer == GI_TRANSFER_NOTHING);
+
+ closure = pyg_closure_new (object, NULL, NULL);
+ if (closure == NULL) {
+ PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GClosure failed");
+ break;
+ }
+
+ arg.v_pointer = closure;
+ } else if (g_type_is_a (type, G_TYPE_BOXED)) {
+ arg.v_pointer = pyg_boxed_get (object, void);
+ if (transfer == GI_TRANSFER_EVERYTHING) {
+ arg.v_pointer = g_boxed_copy (type, arg.v_pointer);
+ }
+ } else if ( (type == G_TYPE_NONE) && (g_struct_info_is_foreign (info))) {
+ gint retval;
+
+ retval = pygi_struct_foreign_convert_to_g_argument (
+ object, type_info, transfer, &arg);
+
+ if (!retval) {
+ PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to foreign struct failed");
+ break;
+ }
+ } else if (g_type_is_a (type, G_TYPE_POINTER) || type == G_TYPE_NONE) {
+ g_warn_if_fail (!g_type_info_is_pointer (type_info) || transfer == GI_TRANSFER_NOTHING);
+ arg.v_pointer = pyg_pointer_get (object, void);
+ } else {
+ PyErr_Format (PyExc_NotImplementedError, "structure type '%s' is not supported yet", g_type_name (type));
+ }
+
+ break;
+ }
+ case GI_INFO_TYPE_ENUM:
+ case GI_INFO_TYPE_FLAGS:
+ {
+ PyObject *int_;
+
+ int_ = PyNumber_Int (object);
+ if (int_ == NULL) {
+ break;
+ }
+
+ arg.v_long = PyInt_AsLong (int_);
+
+ Py_DECREF (int_);
+
+ break;
+ }
+ case GI_INFO_TYPE_INTERFACE:
+ case GI_INFO_TYPE_OBJECT:
+ if (object == Py_None) {
+ arg.v_pointer = NULL;
+ break;
+ }
+
+ arg.v_pointer = pygobject_get (object);
+ if (transfer == GI_TRANSFER_EVERYTHING) {
+ g_object_ref (arg.v_pointer);
+ }
+
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ g_base_info_unref (info);
+ break;
+ }
+ case GI_TYPE_TAG_GLIST:
+ case GI_TYPE_TAG_GSLIST:
+ {
+ Py_ssize_t length;
+ GITypeInfo *item_type_info;
+ GSList *list = NULL;
+ GITransfer item_transfer;
+ Py_ssize_t i;
+
+ if (object == Py_None) {
+ arg.v_pointer = NULL;
+ break;
+ }
+
+ length = PySequence_Length (object);
+ if (length < 0) {
+ break;
+ }
+
+ item_type_info = g_type_info_get_param_type (type_info, 0);
+ g_assert (item_type_info != NULL);
+
+ item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
+
+ for (i = length - 1; i >= 0; i--) {
+ PyObject *py_item;
+ GArgument item;
+
+ py_item = PySequence_GetItem (object, i);
+ if (py_item == NULL) {
+ goto list_item_error;
+ }
+
+ item = _pygi_argument_from_object (py_item, item_type_info, item_transfer);
+
+ Py_DECREF (py_item);
+
+ if (PyErr_Occurred()) {
+ goto list_item_error;
+ }
+
+ if (type_tag == GI_TYPE_TAG_GLIST) {
+ list = (GSList *) g_list_prepend ( (GList *) list, item.v_pointer);
+ } else {
+ list = g_slist_prepend (list, item.v_pointer);
+ }
+
+ continue;
+
+list_item_error:
+ /* Free everything we have converted so far. */
+ _pygi_argument_release ( (GArgument *) &list, type_info,
+ GI_TRANSFER_NOTHING, GI_DIRECTION_IN);
+ list = NULL;
+
+ _PyGI_ERROR_PREFIX ("Item %zd: ", i);
+ break;
+ }
+
+ arg.v_pointer = list;
+
+ g_base_info_unref ( (GIBaseInfo *) item_type_info);
+
+ break;
+ }
+ case GI_TYPE_TAG_GHASH:
+ {
+ Py_ssize_t length;
+ PyObject *keys;
+ PyObject *values;
+ GITypeInfo *key_type_info;
+ GITypeInfo *value_type_info;
+ GITypeTag key_type_tag;
+ GHashFunc hash_func;
+ GEqualFunc equal_func;
+ GHashTable *hash_table;
+ GITransfer item_transfer;
+ Py_ssize_t i;
+
+
+ if (object == Py_None) {
+ arg.v_pointer = NULL;
+ break;
+ }
+
+ length = PyMapping_Length (object);
+ if (length < 0) {
+ break;
+ }
+
+ keys = PyMapping_Keys (object);
+ if (keys == NULL) {
+ break;
+ }
+
+ values = PyMapping_Values (object);
+ if (values == NULL) {
+ Py_DECREF (keys);
+ break;
+ }
+
+ key_type_info = g_type_info_get_param_type (type_info, 0);
+ g_assert (key_type_info != NULL);
+
+ value_type_info = g_type_info_get_param_type (type_info, 1);
+ g_assert (value_type_info != NULL);
+
+ key_type_tag = g_type_info_get_tag (key_type_info);
+
+ switch (key_type_tag) {
+ case GI_TYPE_TAG_UTF8:
+ case GI_TYPE_TAG_FILENAME:
+ hash_func = g_str_hash;
+ equal_func = g_str_equal;
+ break;
+ default:
+ hash_func = NULL;
+ equal_func = NULL;
+ }
+
+ hash_table = g_hash_table_new (hash_func, equal_func);
+ if (hash_table == NULL) {
+ PyErr_NoMemory();
+ goto hash_table_release;
+ }
+
+ item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
+
+ for (i = 0; i < length; i++) {
+ PyObject *py_key;
+ PyObject *py_value;
+ GArgument key;
+ GArgument value;
+
+ py_key = PyList_GET_ITEM (keys, i);
+ py_value = PyList_GET_ITEM (values, i);
+
+ key = _pygi_argument_from_object (py_key, key_type_info, item_transfer);
+ if (PyErr_Occurred()) {
+ goto hash_table_item_error;
+ }
+
+ value = _pygi_argument_from_object (py_value, value_type_info, item_transfer);
+ if (PyErr_Occurred()) {
+ _pygi_argument_release (&key, type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN);
+ goto hash_table_item_error;
+ }
+
+ g_hash_table_insert (hash_table, key.v_pointer, value.v_pointer);
+ continue;
+
+hash_table_item_error:
+ /* Free everything we have converted so far. */
+ _pygi_argument_release ( (GArgument *) &hash_table, type_info,
+ GI_TRANSFER_NOTHING, GI_DIRECTION_IN);
+ hash_table = NULL;
+
+ _PyGI_ERROR_PREFIX ("Item %zd: ", i);
+ break;
+ }
+
+ arg.v_pointer = hash_table;
+
+hash_table_release:
+ g_base_info_unref ( (GIBaseInfo *) key_type_info);
+ g_base_info_unref ( (GIBaseInfo *) value_type_info);
+ Py_DECREF (keys);
+ Py_DECREF (values);
+ break;
+ }
+ case GI_TYPE_TAG_ERROR:
+ PyErr_SetString (PyExc_NotImplementedError, "error marshalling is not supported yet");
+ /* TODO */
+ break;
+ }
+
+ return arg;
+}
+
+PyObject *
+_pygi_argument_to_object (GArgument *arg,
+ GITypeInfo *type_info,
+ GITransfer transfer)
+{
+ GITypeTag type_tag;
+ PyObject *object = NULL;
+
+ type_tag = g_type_info_get_tag (type_info);
+ switch (type_tag) {
+ case GI_TYPE_TAG_VOID:
+ if (g_type_info_is_pointer (type_info)) {
+ /* Raw Python objects are passed to void* args */
+ g_warn_if_fail (transfer == GI_TRANSFER_NOTHING);
+ object = arg->v_pointer;
+ } else
+ object = Py_None;
+ Py_XINCREF (object);
+ break;
+ case GI_TYPE_TAG_BOOLEAN:
+ {
+ object = PyBool_FromLong (arg->v_boolean);
+ break;
+ }
+ case GI_TYPE_TAG_INT8:
+ {
+ object = PyInt_FromLong (arg->v_int8);
+ break;
+ }
+ case GI_TYPE_TAG_UINT8:
+ {
+ object = PyInt_FromLong (arg->v_uint8);
+ break;
+ }
+ case GI_TYPE_TAG_INT16:
+ {
+ object = PyInt_FromLong (arg->v_int16);
+ break;
+ }
+ case GI_TYPE_TAG_UINT16:
+ {
+ object = PyInt_FromLong (arg->v_uint16);
+ break;
+ }
+ case GI_TYPE_TAG_INT32:
+ {
+ object = PyInt_FromLong (arg->v_int32);
+ break;
+ }
+ case GI_TYPE_TAG_UINT32:
+ {
+ object = PyLong_FromLongLong (arg->v_uint32);
+ break;
+ }
+ case GI_TYPE_TAG_INT64:
+ {
+ object = PyLong_FromLongLong (arg->v_int64);
+ break;
+ }
+ case GI_TYPE_TAG_UINT64:
+ {
+ object = PyLong_FromUnsignedLongLong (arg->v_uint64);
+ break;
+ }
+ case GI_TYPE_TAG_SHORT:
+ {
+ object = PyInt_FromLong (arg->v_short);
+ break;
+ }
+ case GI_TYPE_TAG_USHORT:
+ {
+ object = PyInt_FromLong (arg->v_ushort);
+ break;
+ }
+ case GI_TYPE_TAG_INT:
+ {
+ object = PyInt_FromLong (arg->v_int);
+ break;
+ }
+ case GI_TYPE_TAG_UINT:
+ {
+ object = PyLong_FromLongLong (arg->v_uint);
+ break;
+ }
+ case GI_TYPE_TAG_LONG:
+ {
+ object = PyInt_FromLong (arg->v_long);
+ break;
+ }
+ case GI_TYPE_TAG_ULONG:
+ {
+ object = PyLong_FromUnsignedLongLong (arg->v_ulong);
+ break;
+ }
+ case GI_TYPE_TAG_SSIZE:
+ {
+ object = PyInt_FromLong (arg->v_ssize);
+ break;
+ }
+ case GI_TYPE_TAG_SIZE:
+ {
+ object = PyLong_FromUnsignedLongLong (arg->v_size);
+ break;
+ }
+ case GI_TYPE_TAG_FLOAT:
+ {
+ object = PyFloat_FromDouble (arg->v_float);
+ break;
+ }
+ case GI_TYPE_TAG_DOUBLE:
+ {
+ object = PyFloat_FromDouble (arg->v_double);
+ break;
+ }
+ case GI_TYPE_TAG_TIME_T:
+ {
+ time_t *time_;
+ struct tm *datetime;
+
+ time_ = (time_t *) &arg->v_long;
+
+ datetime = localtime (time_);
+ object = PyDateTime_FromDateAndTime (
+ datetime->tm_year + 1900,
+ datetime->tm_mon + 1,
+ datetime->tm_mday,
+ datetime->tm_hour,
+ datetime->tm_min,
+ datetime->tm_sec,
+ 0);
+ break;
+ }
+ case GI_TYPE_TAG_GTYPE:
+ {
+ object = pyg_type_wrapper_new ( (GType) arg->v_long);
+ break;
+ }
+ case GI_TYPE_TAG_UTF8:
+ if (arg->v_string == NULL) {
+ object = Py_None;
+ Py_INCREF (object);
+ break;
+ }
+
+ object = PyString_FromString (arg->v_string);
+ break;
+ case GI_TYPE_TAG_FILENAME:
+ {
+ GError *error = NULL;
+ gchar *string;
+
+ if (arg->v_string == NULL) {
+ object = Py_None;
+ Py_INCREF (object);
+ break;
+ }
+
+ string = g_filename_to_utf8 (arg->v_string, -1, NULL, NULL, &error);
+ if (string == NULL) {
+ PyErr_SetString (PyExc_Exception, error->message);
+ /* TODO: Convert the error to an exception. */
+ break;
+ }
+
+ object = PyString_FromString (string);
+
+ g_free (string);
+
+ break;
+ }
+ case GI_TYPE_TAG_ARRAY:
+ {
+ GArray *array;
+ GITypeInfo *item_type_info;
+ GITypeTag item_type_tag;
+ GITransfer item_transfer;
+ gsize i, item_size;
+
+ if (arg->v_pointer == NULL) {
+ object = Py_None;
+ Py_INCREF (object);
+ break;
+ }
+
+ array = arg->v_pointer;
+
+ object = PyTuple_New (array->len);
+ if (object == NULL) {
+ break;
+ }
+
+ item_type_info = g_type_info_get_param_type (type_info, 0);
+ g_assert (item_type_info != NULL);
+
+ item_type_tag = g_type_info_get_tag (item_type_info);
+ item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
+ item_size = g_array_get_element_size (array);
+
+ for (i = 0; i < array->len; i++) {
+ GArgument item;
+ PyObject *py_item;
+ gboolean is_struct = FALSE;
+
+ if (item_type_tag == GI_TYPE_TAG_INTERFACE) {
+ GIBaseInfo *iface_info = g_type_info_get_interface (item_type_info);
+ switch (g_base_info_get_type (iface_info)) {
+ case GI_INFO_TYPE_STRUCT:
+ case GI_INFO_TYPE_BOXED:
+ is_struct = TRUE;
+ default:
+ break;
+ }
+ g_base_info_unref ( (GIBaseInfo *) iface_info);
+ }
+
+ if (is_struct) {
+ item.v_pointer = &_g_array_index (array, GArgument, i);
+ } else {
+ memcpy (&item, &_g_array_index (array, GArgument, i), item_size);
+ }
+
+ py_item = _pygi_argument_to_object (&item, item_type_info, item_transfer);
+ if (py_item == NULL) {
+ Py_CLEAR (object);
+ _PyGI_ERROR_PREFIX ("Item %zu: ", i);
+ break;
+ }
+
+ PyTuple_SET_ITEM (object, i, py_item);
+ }
+
+ g_base_info_unref ( (GIBaseInfo *) item_type_info);
+ break;
+ }
+ case GI_TYPE_TAG_INTERFACE:
+ {
+ GIBaseInfo *info;
+ GIInfoType info_type;
+
+ info = g_type_info_get_interface (type_info);
+ info_type = g_base_info_get_type (info);
+
+ switch (info_type) {
+ case GI_INFO_TYPE_CALLBACK:
+ {
+ /* There is no way we can support a callback return
+ * as we are never sure if the callback was set from C
+ * or Python. API that return callbacks are broken
+ * so we print a warning and send back a None
+ */
+
+ g_warning ("You are trying to use an API which returns a callback."
+ "Callback returns can not be supported. Returning None instead.");
+ object = Py_None;
+ Py_INCREF (object);
+ break;
+ }
+ case GI_INFO_TYPE_BOXED:
+ case GI_INFO_TYPE_STRUCT:
+ case GI_INFO_TYPE_UNION:
+ {
+ GType type;
+
+ if (arg->v_pointer == NULL) {
+ object = Py_None;
+ Py_INCREF (object);
+ break;
+ }
+
+ type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
+ if (g_type_is_a (type, G_TYPE_VALUE)) {
+ object = pyg_value_as_pyobject (arg->v_pointer, FALSE);
+ } else if (g_type_is_a (type, G_TYPE_BOXED)) {
+ PyObject *py_type;
+
+ py_type = _pygi_type_get_from_g_type (type);
+ if (py_type == NULL)
+ break;
+
+ object = _pygi_boxed_new ( (PyTypeObject *) py_type, arg->v_pointer, transfer == GI_TRANSFER_EVERYTHING);
+
+ Py_DECREF (py_type);
+ } else if (g_type_is_a (type, G_TYPE_POINTER)) {
+ PyObject *py_type;
+
+ py_type = _pygi_type_get_from_g_type (type);
+
+ if (py_type == NULL || !PyType_IsSubtype ( (PyTypeObject *) type, &PyGIStruct_Type)) {
+ g_warn_if_fail (transfer == GI_TRANSFER_NOTHING);
+ object = pyg_pointer_new (type, arg->v_pointer);
+ } else {
+ object = _pygi_struct_new ( (PyTypeObject *) py_type, arg->v_pointer, transfer == GI_TRANSFER_EVERYTHING);
+ }
+
+ Py_XDECREF (py_type);
+ } else if ( (type == G_TYPE_NONE) && (g_struct_info_is_foreign (info))) {
+ object = pygi_struct_foreign_convert_from_g_argument (type_info, arg->v_pointer);
+ } else if (type == G_TYPE_NONE) {
+ PyObject *py_type;
+
+ py_type = _pygi_type_import_by_gi_info (info);
+ if (py_type == NULL) {
+ break;
+ }
+
+ if (transfer != GI_TRANSFER_NOTHING)
+ g_warning ("Transfer mode should be set to None for "
+ "struct types as there is no way to free "
+ "them safely. Ignoring transfer mode "
+ "to prevent a potential invalid free. "
+ "This may cause a leak in your application.");
+
+ object = _pygi_struct_new ( (PyTypeObject *) py_type, arg->v_pointer,
+ FALSE);
+
+ Py_DECREF (py_type);
+ } else {
+ PyErr_Format (PyExc_NotImplementedError, "structure type '%s' is not supported yet", g_type_name (type));
+ }
+
+ break;
+ }
+ case GI_INFO_TYPE_ENUM:
+ case GI_INFO_TYPE_FLAGS:
+ {
+ GType type;
+
+ type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
+
+ if (type == G_TYPE_NONE) {
+ /* An enum with a GType of None is an enum without GType */
+ PyObject *py_type = _pygi_type_import_by_gi_info (info);
+ PyObject *py_args = NULL;
+
+ if (!py_type)
+ return NULL;
+
+ py_args = PyTuple_New (1);
+ if (PyTuple_SetItem (py_args, 0, PyLong_FromLong (arg->v_long)) != 0) {
+ Py_DECREF (py_args);
+ Py_DECREF (py_type);
+ return NULL;
+ }
+
+ object = PyObject_CallFunction (py_type, "l", arg->v_long);
+
+ Py_DECREF (py_args);
+ Py_DECREF (py_type);
+
+ } else if (info_type == GI_INFO_TYPE_ENUM) {
+ object = pyg_enum_from_gtype (type, arg->v_long);
+ } else {
+ object = pyg_flags_from_gtype (type, arg->v_long);
+ }
+
+ break;
+ }
+ case GI_INFO_TYPE_INTERFACE:
+ case GI_INFO_TYPE_OBJECT:
+ if (arg->v_pointer == NULL) {
+ object = Py_None;
+ Py_INCREF (object);
+ break;
+ }
+ object = pygobject_new (arg->v_pointer);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ g_base_info_unref (info);
+ break;
+ }
+ case GI_TYPE_TAG_GLIST:
+ case GI_TYPE_TAG_GSLIST:
+ {
+ GSList *list;
+ gsize length;
+ GITypeInfo *item_type_info;
+ GITransfer item_transfer;
+ gsize i;
+
+ list = arg->v_pointer;
+ length = g_slist_length (list);
+
+ object = PyList_New (length);
+ if (object == NULL) {
+ break;
+ }
+
+ item_type_info = g_type_info_get_param_type (type_info, 0);
+ g_assert (item_type_info != NULL);
+
+ item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
+
+ for (i = 0; list != NULL; list = g_slist_next (list), i++) {
+ GArgument item;
+ PyObject *py_item;
+
+ item.v_pointer = list->data;
+
+ py_item = _pygi_argument_to_object (&item, item_type_info, item_transfer);
+ if (py_item == NULL) {
+ Py_CLEAR (object);
+ _PyGI_ERROR_PREFIX ("Item %zu: ", i);
+ break;
+ }
+
+ PyList_SET_ITEM (object, i, py_item);
+ }
+
+ g_base_info_unref ( (GIBaseInfo *) item_type_info);
+ break;
+ }
+ case GI_TYPE_TAG_GHASH:
+ {
+ GITypeInfo *key_type_info;
+ GITypeInfo *value_type_info;
+ GITransfer item_transfer;
+ GHashTableIter hash_table_iter;
+ GArgument key;
+ GArgument value;
+
+ if (arg->v_pointer == NULL) {
+ object = Py_None;
+ Py_INCREF (object);
+ break;
+ }
+
+ object = PyDict_New();
+ if (object == NULL) {
+ break;
+ }
+
+ key_type_info = g_type_info_get_param_type (type_info, 0);
+ g_assert (key_type_info != NULL);
+
+ value_type_info = g_type_info_get_param_type (type_info, 1);
+ g_assert (value_type_info != NULL);
+
+ item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
+
+ g_hash_table_iter_init (&hash_table_iter, (GHashTable *) arg->v_pointer);
+ while (g_hash_table_iter_next (&hash_table_iter, &key.v_pointer, &value.v_pointer)) {
+ PyObject *py_key;
+ PyObject *py_value;
+ int retval;
+
+ py_key = _pygi_argument_to_object (&key, key_type_info, item_transfer);
+ if (py_key == NULL) {
+ break;
+ }
+
+ py_value = _pygi_argument_to_object (&value, value_type_info, item_transfer);
+ if (py_value == NULL) {
+ Py_DECREF (py_key);
+ break;
+ }
+
+ retval = PyDict_SetItem (object, py_key, py_value);
+
+ Py_DECREF (py_key);
+ Py_DECREF (py_value);
+
+ if (retval < 0) {
+ Py_CLEAR (object);
+ break;
+ }
+ }
+
+ g_base_info_unref ( (GIBaseInfo *) key_type_info);
+ g_base_info_unref ( (GIBaseInfo *) value_type_info);
+ break;
+ }
+ case GI_TYPE_TAG_ERROR:
+ /* Errors should be handled in the invoke wrapper. */
+ g_assert_not_reached();
+ }
+
+ return object;
+}
+
+void
+_pygi_argument_release (GArgument *arg,
+ GITypeInfo *type_info,
+ GITransfer transfer,
+ GIDirection direction)
+{
+ GITypeTag type_tag;
+
+ type_tag = g_type_info_get_tag (type_info);
+
+ switch (type_tag) {
+ case GI_TYPE_TAG_VOID:
+ /* Don't do anything, it's transparent to the C side */
+ break;
+ case GI_TYPE_TAG_BOOLEAN:
+ case GI_TYPE_TAG_INT8:
+ case GI_TYPE_TAG_UINT8:
+ case GI_TYPE_TAG_INT16:
+ case GI_TYPE_TAG_UINT16:
+ case GI_TYPE_TAG_INT32:
+ case GI_TYPE_TAG_UINT32:
+ case GI_TYPE_TAG_INT64:
+ case GI_TYPE_TAG_UINT64:
+ case GI_TYPE_TAG_SHORT:
+ case GI_TYPE_TAG_USHORT:
+ case GI_TYPE_TAG_INT:
+ case GI_TYPE_TAG_UINT:
+ case GI_TYPE_TAG_LONG:
+ case GI_TYPE_TAG_ULONG:
+ case GI_TYPE_TAG_SSIZE:
+ case GI_TYPE_TAG_SIZE:
+ case GI_TYPE_TAG_FLOAT:
+ case GI_TYPE_TAG_DOUBLE:
+ case GI_TYPE_TAG_TIME_T:
+ case GI_TYPE_TAG_GTYPE:
+ break;
+ case GI_TYPE_TAG_FILENAME:
+ case GI_TYPE_TAG_UTF8:
+ /* With allow-none support the string could be NULL */
+ if (arg->v_string != NULL &&
+ (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)
+ || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) {
+ g_free (arg->v_string);
+ }
+ break;
+ case GI_TYPE_TAG_ARRAY:
+ {
+ GArray *array;
+ gsize i;
+
+ if (arg->v_pointer == NULL) {
+ return;
+ }
+
+ array = arg->v_pointer;
+
+ if ( (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING)
+ || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) {
+ GITypeInfo *item_type_info;
+ GITransfer item_transfer;
+
+ item_type_info = g_type_info_get_param_type (type_info, 0);
+
+ item_transfer = direction == GI_DIRECTION_IN ? GI_TRANSFER_NOTHING : GI_TRANSFER_EVERYTHING;
+
+ /* Free the items */
+ for (i = 0; i < array->len; i++) {
+ GArgument *item;
+ item = &_g_array_index (array, GArgument, i);
+ _pygi_argument_release (item, item_type_info, item_transfer, direction);
+ }
+
+ g_base_info_unref ( (GIBaseInfo *) item_type_info);
+ }
+
+ if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)
+ || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) {
+ g_array_free (array, TRUE);
+ }
+
+ break;
+ }
+ case GI_TYPE_TAG_INTERFACE:
+ {
+ GIBaseInfo *info;
+ GIInfoType info_type;
+
+ info = g_type_info_get_interface (type_info);
+ info_type = g_base_info_get_type (info);
+
+ switch (info_type) {
+ case GI_INFO_TYPE_CALLBACK:
+ /* TODO */
+ break;
+ case GI_INFO_TYPE_BOXED:
+ case GI_INFO_TYPE_STRUCT:
+ case GI_INFO_TYPE_UNION:
+ {
+ GType type;
+
+ if (arg->v_pointer == NULL) {
+ return;
+ }
+
+ type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
+
+ if (g_type_is_a (type, G_TYPE_VALUE)) {
+ GValue *value;
+
+ value = arg->v_pointer;
+
+ if ( (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING)
+ || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) {
+ g_value_unset (value);
+ }
+
+ if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)
+ || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) {
+ g_slice_free (GValue, value);
+ }
+ } else if (g_type_is_a (type, G_TYPE_CLOSURE)) {
+ if (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) {
+ g_closure_unref (arg->v_pointer);
+ }
+ } else if (g_struct_info_is_foreign ( (GIStructInfo*) info)) {
+ if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING) {
+ pygi_struct_foreign_release_g_argument (transfer, type_info, arg);
+ }
+ } else if (g_type_is_a (type, G_TYPE_BOXED)) {
+ } else if (g_type_is_a (type, G_TYPE_POINTER) || type == G_TYPE_NONE) {
+ g_warn_if_fail (!g_type_info_is_pointer (type_info) || transfer == GI_TRANSFER_NOTHING);
+ }
+
+ break;
+ }
+ case GI_INFO_TYPE_ENUM:
+ case GI_INFO_TYPE_FLAGS:
+ break;
+ case GI_INFO_TYPE_INTERFACE:
+ case GI_INFO_TYPE_OBJECT:
+ if (arg->v_pointer == NULL) {
+ return;
+ }
+ if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING) {
+ g_object_unref (arg->v_pointer);
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ g_base_info_unref (info);
+ break;
+ }
+ case GI_TYPE_TAG_GLIST:
+ case GI_TYPE_TAG_GSLIST:
+ {
+ GSList *list;
+
+ if (arg->v_pointer == NULL) {
+ return;
+ }
+
+ list = arg->v_pointer;
+
+ if ( (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING)
+ || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) {
+ GITypeInfo *item_type_info;
+ GITransfer item_transfer;
+ GSList *item;
+
+ item_type_info = g_type_info_get_param_type (type_info, 0);
+ g_assert (item_type_info != NULL);
+
+ item_transfer = direction == GI_DIRECTION_IN ? GI_TRANSFER_NOTHING : GI_TRANSFER_EVERYTHING;
+
+ /* Free the items */
+ for (item = list; item != NULL; item = g_slist_next (item)) {
+ _pygi_argument_release ( (GArgument *) &item->data, item_type_info,
+ item_transfer, direction);
+ }
+
+ g_base_info_unref ( (GIBaseInfo *) item_type_info);
+ }
+
+ if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)
+ || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) {
+ if (type_tag == GI_TYPE_TAG_GLIST) {
+ g_list_free ( (GList *) list);
+ } else {
+ /* type_tag == GI_TYPE_TAG_GSLIST */
+ g_slist_free (list);
+ }
+ }
+
+ break;
+ }
+ case GI_TYPE_TAG_GHASH:
+ {
+ GHashTable *hash_table;
+
+ if (arg->v_pointer == NULL) {
+ return;
+ }
+
+ hash_table = arg->v_pointer;
+
+ if (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) {
+ /* We created the table without a destroy function, so keys and
+ * values need to be released. */
+ GITypeInfo *key_type_info;
+ GITypeInfo *value_type_info;
+ GITransfer item_transfer;
+ GHashTableIter hash_table_iter;
+ gpointer key;
+ gpointer value;
+
+ key_type_info = g_type_info_get_param_type (type_info, 0);
+ g_assert (key_type_info != NULL);
+
+ value_type_info = g_type_info_get_param_type (type_info, 1);
+ g_assert (value_type_info != NULL);
+
+ if (direction == GI_DIRECTION_IN) {
+ item_transfer = GI_TRANSFER_NOTHING;
+ } else {
+ item_transfer = GI_TRANSFER_EVERYTHING;
+ }
+
+ g_hash_table_iter_init (&hash_table_iter, hash_table);
+ while (g_hash_table_iter_next (&hash_table_iter, &key, &value)) {
+ _pygi_argument_release ( (GArgument *) &key, key_type_info,
+ item_transfer, direction);
+ _pygi_argument_release ( (GArgument *) &value, value_type_info,
+ item_transfer, direction);
+ }
+
+ g_base_info_unref ( (GIBaseInfo *) key_type_info);
+ g_base_info_unref ( (GIBaseInfo *) value_type_info);
+ } else if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_CONTAINER) {
+ /* Be careful to avoid keys and values being freed if the
+ * callee gave a destroy function. */
+ g_hash_table_steal_all (hash_table);
+ }
+
+ if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)
+ || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) {
+ g_hash_table_unref (hash_table);
+ }
+
+ break;
+ }
+ case GI_TYPE_TAG_ERROR:
+ {
+ GError *error;
+
+ if (arg->v_pointer == NULL) {
+ return;
+ }
+
+ error = * (GError **) arg->v_pointer;
+
+ if (error != NULL) {
+ g_error_free (error);
+ }
+
+ g_slice_free (GError *, arg->v_pointer);
+ break;
+ }
+ }
+}
+
+void
+_pygi_argument_init (void)
+{
+ PyDateTime_IMPORT;
+ _pygobject_import();
+}
+
diff --git a/gi/pygi-argument.h b/gi/pygi-argument.h
new file mode 100644
index 00000000..821737a4
--- /dev/null
+++ b/gi/pygi-argument.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef __PYGI_ARGUMENT_H__
+#define __PYGI_ARGUMENT_H__
+
+#include <Python.h>
+
+#include <girepository.h>
+
+G_BEGIN_DECLS
+
+
+/* Private */
+
+gint _pygi_g_type_info_check_object (GITypeInfo *type_info,
+ PyObject *object,
+ gboolean allow_none);
+
+gint _pygi_g_registered_type_info_check_object (GIRegisteredTypeInfo *info,
+ gboolean is_instance,
+ PyObject *object);
+
+
+GArray* _pygi_argument_to_array (GArgument *arg,
+ GArgument *args[],
+ GITypeInfo *type_info,
+ gboolean is_method);
+
+GArgument _pygi_argument_from_object (PyObject *object,
+ GITypeInfo *type_info,
+ GITransfer transfer);
+
+PyObject* _pygi_argument_to_object (GArgument *arg,
+ GITypeInfo *type_info,
+ GITransfer transfer);
+
+
+void _pygi_argument_release (GArgument *arg,
+ GITypeInfo *type_info,
+ GITransfer transfer,
+ GIDirection direction);
+
+void _pygi_argument_init (void);
+
+G_END_DECLS
+
+#endif /* __PYGI_ARGUMENT_H__ */
diff --git a/gi/pygi-boxed.c b/gi/pygi-boxed.c
new file mode 100644
index 00000000..49038344
--- /dev/null
+++ b/gi/pygi-boxed.c
@@ -0,0 +1,196 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2009 Simon van der Linden <svdlinden@src.gnome.org>
+ *
+ * pygi-boxed.c: wrapper to handle registered structures.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "pygi-private.h"
+
+#include <pygobject.h>
+#include <girepository.h>
+
+static void
+_boxed_dealloc (PyGIBoxed *self)
+{
+ GType g_type;
+
+ PyObject_GC_UnTrack ( (PyObject *) self);
+
+ PyObject_ClearWeakRefs ( (PyObject *) self);
+
+ if ( ( (PyGBoxed *) self)->free_on_dealloc) {
+ if (self->slice_allocated) {
+ g_slice_free1 (self->size, ( (PyGBoxed *) self)->boxed);
+ } else {
+ g_type = pyg_type_from_object ( (PyObject *) self);
+ g_boxed_free (g_type, ( (PyGBoxed *) self)->boxed);
+ }
+ }
+
+ ( (PyGObject *) self)->ob_type->tp_free ( (PyObject *) self);
+}
+
+static PyObject *
+_boxed_new (PyTypeObject *type,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ static char *kwlist[] = { NULL };
+
+ GIBaseInfo *info;
+ gsize size;
+ gpointer boxed;
+ PyGIBoxed *self = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs, "", kwlist)) {
+ return NULL;
+ }
+
+ info = _pygi_object_get_gi_info ( (PyObject *) type, &PyGIBaseInfo_Type);
+ if (info == NULL) {
+ if (PyErr_ExceptionMatches (PyExc_AttributeError)) {
+ PyErr_Format (PyExc_TypeError, "missing introspection information");
+ }
+ return NULL;
+ }
+
+ switch (g_base_info_get_type (info)) {
+ case GI_INFO_TYPE_UNION:
+ size = g_union_info_get_size ( (GIUnionInfo *) info);
+ break;
+ case GI_INFO_TYPE_BOXED:
+ case GI_INFO_TYPE_STRUCT:
+ size = g_struct_info_get_size ( (GIStructInfo *) info);
+ break;
+ default:
+ PyErr_Format (PyExc_TypeError,
+ "info should be Boxed or Union, not '%d'",
+ g_base_info_get_type (info));
+ return NULL;
+ }
+
+ boxed = g_slice_alloc0 (size);
+ if (boxed == NULL) {
+ PyErr_NoMemory();
+ goto out;
+ }
+
+ self = (PyGIBoxed *) _pygi_boxed_new (type, boxed, TRUE);
+ if (self == NULL) {
+ g_slice_free1 (size, boxed);
+ goto out;
+ }
+
+ self->size = size;
+ self->slice_allocated = TRUE;
+
+out:
+ g_base_info_unref (info);
+
+ return (PyObject *) self;
+}
+
+static int
+_boxed_init (PyObject *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ /* Don't call PyGBoxed's init, which raises an exception. */
+ return 0;
+}
+
+
+PyTypeObject PyGIBoxed_Type = {
+ PyObject_HEAD_INIT (NULL)
+ 0,
+ "gi.Boxed", /* tp_name */
+ sizeof (PyGIBoxed), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor) _boxed_dealloc, /* tp_dealloc */
+ (printfunc) NULL, /* tp_print */
+ (getattrfunc) NULL, /* tp_getattr */
+ (setattrfunc) NULL, /* tp_setattr */
+ (cmpfunc) NULL, /* tp_compare */
+ (reprfunc) NULL, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ (hashfunc) NULL, /* tp_hash */
+ (ternaryfunc) NULL, /* tp_call */
+ (reprfunc) NULL, /* tp_str */
+ (getattrofunc) NULL, /* tp_getattro */
+ (setattrofunc) NULL, /* tp_setattro */
+ NULL, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ NULL, /* tp_doc */
+ (traverseproc) NULL, /* tp_traverse */
+ (inquiry) NULL, /* tp_clear */
+ (richcmpfunc) NULL, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc) NULL, /* tp_iter */
+ (iternextfunc) NULL, /* tp_iternext */
+ NULL, /* tp_methods */
+ NULL, /* tp_members */
+ NULL, /* tp_getset */
+ (PyTypeObject *) NULL, /* tp_base */
+};
+
+PyObject *
+_pygi_boxed_new (PyTypeObject *type,
+ gpointer boxed,
+ gboolean free_on_dealloc)
+{
+ PyGIBoxed *self;
+
+ if (!boxed) {
+ Py_RETURN_NONE;
+ }
+
+ if (!PyType_IsSubtype (type, &PyGIBoxed_Type)) {
+ PyErr_SetString (PyExc_TypeError, "must be a subtype of gi.Boxed");
+ return NULL;
+ }
+
+ self = (PyGIBoxed *) type->tp_alloc (type, 0);
+ if (self == NULL) {
+ return NULL;
+ }
+
+ ( (PyGBoxed *) self)->gtype = pyg_type_from_object ( (PyObject *) type);
+ ( (PyGBoxed *) self)->boxed = boxed;
+ ( (PyGBoxed *) self)->free_on_dealloc = free_on_dealloc;
+ self->size = 0;
+ self->slice_allocated = FALSE;
+
+ return (PyObject *) self;
+}
+
+void
+_pygi_boxed_register_types (PyObject *m)
+{
+ PyGIBoxed_Type.ob_type = &PyType_Type;
+ PyGIBoxed_Type.tp_base = &PyGBoxed_Type;
+ PyGIBoxed_Type.tp_new = (newfunc) _boxed_new;
+ PyGIBoxed_Type.tp_init = (initproc) _boxed_init;
+ if (PyType_Ready (&PyGIBoxed_Type))
+ return;
+ if (PyModule_AddObject (m, "Boxed", (PyObject *) &PyGIBoxed_Type))
+ return;
+}
diff --git a/gi/pygi-boxed.h b/gi/pygi-boxed.h
new file mode 100644
index 00000000..4f840604
--- /dev/null
+++ b/gi/pygi-boxed.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2009 Simon van der Linden <svdlinden@src.gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef __PYGI_BOXED_H__
+#define __PYGI_BOXED_H__
+
+#include <Python.h>
+
+G_BEGIN_DECLS
+
+extern PyTypeObject PyGIBoxed_Type;
+
+PyObject *
+_pygi_boxed_new (PyTypeObject *type,
+ gpointer boxed,
+ gboolean free_on_dealloc);
+
+void _pygi_boxed_register_types (PyObject *m);
+
+G_END_DECLS
+
+#endif /* __PYGI_BOXED_H__ */
diff --git a/gi/pygi-callbacks.c b/gi/pygi-callbacks.c
new file mode 100644
index 00000000..868f2fb3
--- /dev/null
+++ b/gi/pygi-callbacks.c
@@ -0,0 +1,223 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * pygi-callbacks.c: PyGI C Callback Functions and Helpers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "pygi-private.h"
+
+static PyGICClosure *global_destroy_notify;
+
+static void
+_pygi_destroy_notify_callback_closure (ffi_cif *cif,
+ void *result,
+ void **args,
+ void *data)
+{
+ PyGICClosure *info = * (void**) (args[0]);
+
+ g_assert (info);
+
+ _pygi_invoke_closure_free (info);
+}
+
+
+PyGICClosure*
+_pygi_destroy_notify_create (void)
+{
+ if (!global_destroy_notify) {
+
+ ffi_status status;
+ PyGICClosure *destroy_notify = g_slice_new0 (PyGICClosure);
+
+ g_assert (destroy_notify);
+
+ GIBaseInfo* glib_destroy_notify = g_irepository_find_by_name (NULL, "GLib", "DestroyNotify");
+ g_assert (glib_destroy_notify != NULL);
+ g_assert (g_base_info_get_type (glib_destroy_notify) == GI_INFO_TYPE_CALLBACK);
+
+ destroy_notify->closure = g_callable_info_prepare_closure ( (GICallableInfo*) glib_destroy_notify,
+ &destroy_notify->cif,
+ _pygi_destroy_notify_callback_closure,
+ NULL);
+
+ global_destroy_notify = destroy_notify;
+ }
+
+ return global_destroy_notify;
+}
+
+
+gboolean
+_pygi_scan_for_callbacks (GIFunctionInfo *function_info,
+ gboolean is_method,
+ guint8 *callback_index,
+ guint8 *user_data_index,
+ guint8 *destroy_notify_index)
+{
+ guint i, n_args;
+
+ *callback_index = G_MAXUINT8;
+ *user_data_index = G_MAXUINT8;
+ *destroy_notify_index = G_MAXUINT8;
+
+ n_args = g_callable_info_get_n_args ( (GICallableInfo *) function_info);
+ for (i = 0; i < n_args; i++) {
+ GIDirection direction;
+ GIArgInfo *arg_info;
+ GITypeInfo *type_info;
+ guint8 destroy, closure;
+ GITypeTag type_tag;
+
+ arg_info = g_callable_info_get_arg ( (GICallableInfo*) function_info, i);
+ type_info = g_arg_info_get_type (arg_info);
+ type_tag = g_type_info_get_tag (type_info);
+
+ if (type_tag == GI_TYPE_TAG_INTERFACE) {
+ GIBaseInfo* interface_info;
+ GIInfoType interface_type;
+
+ interface_info = g_type_info_get_interface (type_info);
+ interface_type = g_base_info_get_type (interface_info);
+ if (interface_type == GI_INFO_TYPE_CALLBACK &&
+ ! (strcmp (g_base_info_get_namespace ( (GIBaseInfo*) interface_info), "GLib") == 0 &&
+ strcmp (g_base_info_get_name ( (GIBaseInfo*) interface_info), "DestroyNotify") == 0)) {
+ if (*callback_index != G_MAXUINT8) {
+ PyErr_Format (PyExc_TypeError, "Function %s.%s has multiple callbacks, not supported",
+ g_base_info_get_namespace ( (GIBaseInfo*) function_info),
+ g_base_info_get_name ( (GIBaseInfo*) function_info));
+ g_base_info_unref (interface_info);
+ return FALSE;
+ }
+ *callback_index = i;
+ }
+ g_base_info_unref (interface_info);
+ }
+ destroy = g_arg_info_get_destroy (arg_info);
+ if (is_method)
+ --destroy;
+ closure = g_arg_info_get_closure (arg_info);
+ if (is_method)
+ --closure;
+ direction = g_arg_info_get_direction (arg_info);
+
+ if (destroy > 0 && destroy < n_args) {
+ if (*destroy_notify_index != G_MAXUINT8) {
+ PyErr_Format (PyExc_TypeError, "Function %s has multiple GDestroyNotify, not supported",
+ g_base_info_get_name ( (GIBaseInfo*) function_info));
+ return FALSE;
+ }
+ *destroy_notify_index = destroy;
+ }
+
+ if (closure > 0 && closure < n_args) {
+ if (*user_data_index != G_MAXUINT8) {
+ PyErr_Format (PyExc_TypeError, "Function %s has multiple user_data arguments, not supported",
+ g_base_info_get_name ( (GIBaseInfo*) function_info));
+ return FALSE;
+ }
+ *user_data_index = closure;
+ }
+
+ g_base_info_unref ( (GIBaseInfo*) arg_info);
+ g_base_info_unref ( (GIBaseInfo*) type_info);
+ }
+
+ return TRUE;
+}
+
+gboolean
+_pygi_create_callback (GIBaseInfo *function_info,
+ gboolean is_method,
+ gboolean is_constructor,
+ int n_args,
+ Py_ssize_t py_argc,
+ PyObject *py_argv,
+ guint8 callback_index,
+ guint8 user_data_index,
+ guint8 destroy_notify_index,
+ PyGICClosure **closure_out)
+{
+ GIArgInfo *callback_arg;
+ GITypeInfo *callback_type;
+ GICallbackInfo *callback_info;
+ GIScopeType scope;
+ gboolean found_py_function;
+ PyObject *py_function;
+ guint8 i, py_argv_pos;
+ PyObject *py_user_data;
+ gboolean allow_none;
+
+ callback_arg = g_callable_info_get_arg ( (GICallableInfo*) function_info, callback_index);
+ scope = g_arg_info_get_scope (callback_arg);
+ allow_none = g_arg_info_may_be_null (callback_arg);
+
+ callback_type = g_arg_info_get_type (callback_arg);
+ g_assert (g_type_info_get_tag (callback_type) == GI_TYPE_TAG_INTERFACE);
+
+ callback_info = (GICallbackInfo*) g_type_info_get_interface (callback_type);
+ g_assert (g_base_info_get_type ( (GIBaseInfo*) callback_info) == GI_INFO_TYPE_CALLBACK);
+
+ /* Find the Python function passed for the callback */
+ found_py_function = FALSE;
+ py_function = Py_None;
+ py_user_data = NULL;
+
+ /* if its a method then we need to skip over 'self' */
+ if (is_method || is_constructor)
+ py_argv_pos = 1;
+ else
+ py_argv_pos = 0;
+
+ for (i = 0; i < n_args && i < py_argc; i++) {
+ if (i == callback_index) {
+ py_function = PyTuple_GetItem (py_argv, py_argv_pos);
+ /* if we allow none then set the closure to NULL and return */
+ if (allow_none && py_function == Py_None) {
+ *closure_out = NULL;
+ goto out;
+ }
+ found_py_function = TRUE;
+ } else if (i == user_data_index) {
+ py_user_data = PyTuple_GetItem (py_argv, py_argv_pos);
+ }
+ py_argv_pos++;
+ }
+
+ if (!found_py_function
+ || (py_function == Py_None || !PyCallable_Check (py_function))) {
+ PyErr_Format (PyExc_TypeError, "Error invoking %s.%s: Invalid callback given for argument %s",
+ g_base_info_get_namespace ( (GIBaseInfo*) function_info),
+ g_base_info_get_name ( (GIBaseInfo*) function_info),
+ g_base_info_get_name ( (GIBaseInfo*) callback_arg));
+ g_base_info_unref ( (GIBaseInfo*) callback_info);
+ g_base_info_unref ( (GIBaseInfo*) callback_type);
+ return FALSE;
+ }
+
+ /** Now actually build the closure **/
+ *closure_out = _pygi_make_native_closure ( (GICallableInfo *) callback_info,
+ g_arg_info_get_scope (callback_arg),
+ py_function,
+ py_user_data);
+out:
+ g_base_info_unref ( (GIBaseInfo*) callback_info);
+ g_base_info_unref ( (GIBaseInfo*) callback_type);
+
+ return TRUE;
+}
diff --git a/gi/pygi-callbacks.h b/gi/pygi-callbacks.h
new file mode 100644
index 00000000..7535bba4
--- /dev/null
+++ b/gi/pygi-callbacks.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef __PYGI_CALLBACKS_H__
+#define __PYGI_CALLBACKS_H__
+
+G_BEGIN_DECLS
+
+void _pygi_callback_notify_info_free (gpointer user_data);
+
+PyGICClosure*_pygi_destroy_notify_create (void);
+
+gboolean _pygi_scan_for_callbacks (GIFunctionInfo *self,
+ gboolean is_method,
+ guint8 *callback_index,
+ guint8 *user_data_index,
+ guint8 *destroy_notify_index);
+
+gboolean _pygi_create_callback (GIFunctionInfo *self,
+ gboolean is_method,
+ gboolean is_constructor,
+ int n_args,
+ Py_ssize_t py_argc,
+ PyObject *py_argv,
+ guint8 callback_index,
+ guint8 user_data_index,
+ guint8 destroy_notify_index,
+ PyGICClosure **closure_out);
+
+G_END_DECLS
+
+#endif
diff --git a/gi/pygi-closure.c b/gi/pygi-closure.c
new file mode 100644
index 00000000..a752ae28
--- /dev/null
+++ b/gi/pygi-closure.c
@@ -0,0 +1,399 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * pygi-closure.c: PyGI C Closure functions
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "pygi-private.h"
+
+/* This maintains a list of closures which can be free'd whenever
+ as they have been called. We will free them on the next
+ library function call.
+ */
+static GSList* async_free_list;
+
+
+static GArgument *
+_pygi_closure_convert_ffi_arguments (GICallableInfo *callable_info, void **args)
+{
+ gint num_args, i;
+ GIArgInfo *arg_info;
+ GITypeInfo *arg_type;
+ GITypeTag tag;
+ GIDirection direction;
+ GArgument *g_args;
+
+ num_args = g_callable_info_get_n_args (callable_info);
+ g_args = g_new0 (GArgument, num_args);
+
+ for (i = 0; i < num_args; i++) {
+ arg_info = g_callable_info_get_arg (callable_info, i);
+ arg_type = g_arg_info_get_type (arg_info);
+ tag = g_type_info_get_tag (arg_type);
+ direction = g_arg_info_get_direction (arg_info);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
+ g_args[i].v_pointer = * (gpointer *) args[i];
+ } else {
+ switch (tag) {
+ case GI_TYPE_TAG_BOOLEAN:
+ g_args[i].v_boolean = * (gboolean *) args[i];
+ break;
+ case GI_TYPE_TAG_INT8:
+ g_args[i].v_int8 = * (gint8 *) args[i];
+ break;
+ case GI_TYPE_TAG_UINT8:
+ g_args[i].v_uint8 = * (guint8 *) args[i];
+ break;
+ case GI_TYPE_TAG_INT16:
+ g_args[i].v_int16 = * (gint16 *) args[i];
+ break;
+ case GI_TYPE_TAG_UINT16:
+ g_args[i].v_uint16 = * (guint16 *) args[i];
+ break;
+ case GI_TYPE_TAG_INT32:
+ g_args[i].v_int32 = * (gint32 *) args[i];
+ break;
+ case GI_TYPE_TAG_UINT32:
+ g_args[i].v_uint32 = * (guint32 *) args[i];
+ break;
+ case GI_TYPE_TAG_LONG:
+ case GI_TYPE_TAG_INT64:
+ g_args[i].v_int64 = * (glong *) args[i];
+ break;
+ case GI_TYPE_TAG_ULONG:
+ case GI_TYPE_TAG_UINT64:
+ g_args[i].v_uint64 = * (glong *) args[i];
+ break;
+ case GI_TYPE_TAG_INT:
+ case GI_TYPE_TAG_SSIZE:
+ case GI_TYPE_TAG_SIZE:
+ g_args[i].v_int32 = * (gint *) args[i];
+ break;
+ case GI_TYPE_TAG_UINT:
+ g_args[i].v_uint32 = * (guint *) args[i];
+ break;
+ case GI_TYPE_TAG_FLOAT:
+ g_args[i].v_float = * (gfloat *) args[i];
+ break;
+ case GI_TYPE_TAG_DOUBLE:
+ g_args[i].v_double = * (gdouble *) args[i];
+ break;
+ case GI_TYPE_TAG_UTF8:
+ g_args[i].v_string = * (gchar **) args[i];
+ break;
+ case GI_TYPE_TAG_INTERFACE:
+ {
+ GIBaseInfo *interface;
+ GIInfoType interface_type;
+
+ interface = g_type_info_get_interface (arg_type);
+ interface_type = g_base_info_get_type (interface);
+
+ if (interface_type == GI_INFO_TYPE_OBJECT ||
+ interface_type == GI_INFO_TYPE_INTERFACE) {
+ g_args[i].v_pointer = * (gpointer *) args[i];
+ g_base_info_unref (interface);
+ break;
+ } else if (interface_type == GI_INFO_TYPE_ENUM ||
+ interface_type == GI_INFO_TYPE_FLAGS) {
+ g_args[i].v_double = * (double *) args[i];
+ g_base_info_unref (interface);
+ break;
+ } else if (interface_type == GI_INFO_TYPE_STRUCT) {
+ g_args[i].v_pointer = * (gpointer *) args[i];
+ g_base_info_unref (interface);
+ break;
+ }
+
+ g_base_info_unref (interface);
+ }
+ case GI_TYPE_TAG_GLIST:
+ case GI_TYPE_TAG_GSLIST:
+ g_args[i].v_pointer = * (gpointer *) args[i];
+ break;
+ default:
+ g_args[i].v_pointer = 0;
+ }
+ }
+ g_base_info_unref ( (GIBaseInfo *) arg_info);
+ g_base_info_unref ( (GIBaseInfo *) arg_type);
+ }
+ return g_args;
+}
+
+static gboolean
+_pygi_closure_convert_arguments (GICallableInfo *callable_info, void **args,
+ void *user_data, PyObject **py_args,
+ GArgument **out_args)
+{
+ int n_args = g_callable_info_get_n_args (callable_info);
+ int n_in_args = 0;
+ int n_out_args = 0;
+ int i;
+ GArgument *g_args = NULL;
+
+ *py_args = NULL;
+ *py_args = PyTuple_New (n_args);
+ if (*py_args == NULL)
+ goto error;
+
+ *out_args = NULL;
+ *out_args = g_new0 (GArgument, n_args);
+ g_args = _pygi_closure_convert_ffi_arguments (callable_info, args);
+
+ for (i = 0; i < n_args; i++) {
+ GIArgInfo *arg_info = g_callable_info_get_arg (callable_info, i);
+ GIDirection direction = g_arg_info_get_direction (arg_info);
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
+ GITypeInfo *arg_type = g_arg_info_get_type (arg_info);
+ GITypeTag arg_tag = g_type_info_get_tag (arg_type);
+ GITransfer transfer = g_arg_info_get_ownership_transfer (arg_info);
+ PyObject *value;
+ GArgument *arg;
+
+ if (direction == GI_DIRECTION_IN && arg_tag == GI_TYPE_TAG_VOID &&
+ g_type_info_is_pointer (arg_type)) {
+
+ if (user_data == NULL) {
+ Py_INCREF (Py_None);
+ value = Py_None;
+ } else {
+ value = user_data;
+ Py_INCREF (value);
+ }
+ } else {
+ if (direction == GI_DIRECTION_IN)
+ arg = (GArgument*) &g_args[i];
+ else
+ arg = (GArgument*) g_args[i].v_pointer;
+
+ value = _pygi_argument_to_object (arg, arg_type, transfer);
+ if (value == NULL) {
+ g_base_info_unref (arg_type);
+ g_base_info_unref (arg_info);
+ goto error;
+ }
+ }
+ PyTuple_SET_ITEM (*py_args, n_in_args, value);
+ n_in_args++;
+
+ g_base_info_unref (arg_type);
+ }
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
+ (*out_args) [n_out_args] = g_args[i];
+ n_out_args++;
+ }
+
+ g_base_info_unref (arg_info);
+ }
+
+ if (_PyTuple_Resize (py_args, n_in_args) == -1)
+ goto error;
+
+ return TRUE;
+
+error:
+ Py_CLEAR (*py_args);
+
+ if (*out_args != NULL)
+ g_free (*out_args);
+
+ if (g_args != NULL)
+ g_free (g_args);
+
+ return FALSE;
+}
+
+static void
+_pygi_closure_set_out_arguments (GICallableInfo *callable_info,
+ PyObject *py_retval, GArgument *out_args,
+ void *resp)
+{
+ int n_args, i, i_py_retval, i_out_args;
+ GITypeInfo *return_type_info;
+ GITypeTag return_type_tag;
+
+ i_py_retval = 0;
+ return_type_info = g_callable_info_get_return_type (callable_info);
+ return_type_tag = g_type_info_get_tag (return_type_info);
+ if (return_type_tag != GI_TYPE_TAG_VOID) {
+ GArgument arg;
+ GITransfer transfer = g_callable_info_get_caller_owns (callable_info);
+ if (PyTuple_Check (py_retval)) {
+ PyObject *item = PyTuple_GET_ITEM (py_retval, 0);
+ arg = _pygi_argument_from_object (item, return_type_info, transfer);
+ * ( (GArgument*) resp) = arg;
+ } else {
+ arg = _pygi_argument_from_object (py_retval, return_type_info, transfer);
+ * ( (GArgument*) resp) = arg;
+ }
+ i_py_retval++;
+ }
+ g_base_info_unref (return_type_info);
+
+ i_out_args = 0;
+ n_args = g_callable_info_get_n_args (callable_info);
+ for (i = 1; i < n_args; i++) {
+ GIArgInfo *arg_info = g_callable_info_get_arg (callable_info, i);
+ GITypeInfo *type_info = g_arg_info_get_type (arg_info);
+ GIDirection direction = g_arg_info_get_direction (arg_info);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
+ GITransfer transfer = g_arg_info_get_ownership_transfer (arg_info);
+ GArgument arg;
+ if (PyTuple_Check (py_retval)) {
+ PyObject *item = PyTuple_GET_ITEM (py_retval, i_py_retval);
+ arg = _pygi_argument_from_object (item, type_info, transfer);
+ * ( (GArgument*) out_args[i_out_args].v_pointer) = arg;
+ } else if (i_py_retval == 0) {
+ arg = _pygi_argument_from_object (py_retval, type_info, transfer);
+ * ( (GArgument*) out_args[i_out_args].v_pointer) = arg;
+ } else
+ g_assert_not_reached();
+
+ i_out_args++;
+ i_py_retval++;
+ }
+ g_base_info_unref (type_info);
+ g_base_info_unref (arg_info);
+ }
+}
+
+void
+_pygi_closure_handle (ffi_cif *cif,
+ void *result,
+ void **args,
+ void *data)
+{
+ PyGILState_STATE state;
+ PyGICClosure *closure = data;
+ GITypeTag return_tag;
+ GITransfer return_transfer;
+ GITypeInfo *return_type;
+ PyObject *retval;
+ PyObject *py_args;
+ GArgument *out_args;
+
+ /* Lock the GIL as we are coming into this code without the lock and we
+ may be executing python code */
+ state = PyGILState_Ensure();
+
+ return_type = g_callable_info_get_return_type (closure->info);
+ return_tag = g_type_info_get_tag (return_type);
+ return_transfer = g_callable_info_get_caller_owns (closure->info);
+
+ if (!_pygi_closure_convert_arguments ( (GICallableInfo *) closure->info, args,
+ closure->user_data,
+ &py_args, &out_args)) {
+ if (PyErr_Occurred ())
+ PyErr_Print();
+ goto end;
+ }
+
+ retval = PyObject_CallObject ( (PyObject *) closure->function, py_args);
+ Py_DECREF (py_args);
+
+ if (retval == NULL) {
+ PyErr_Print();
+ goto end;
+ }
+
+ _pygi_closure_set_out_arguments (closure->info, retval, out_args, result);
+
+end:
+ g_base_info_unref ( (GIBaseInfo*) return_type);
+
+ PyGILState_Release (state);
+
+ /* Now that the closure has finished we can make a decision about how
+ to free it. Scope call gets free'd at the end of wrap_g_function_info_invoke
+ scope notified will be freed, when the notify is called and we can free async
+ anytime we want as long as its after we return from this function (you can't free the closure
+ you are currently using!)
+ */
+ switch (closure->scope) {
+ case GI_SCOPE_TYPE_CALL:
+ case GI_SCOPE_TYPE_NOTIFIED:
+ break;
+ case GI_SCOPE_TYPE_ASYNC:
+ /* Append this PyGICClosure to a list of closure that we will free
+ after we're done with this function invokation */
+ async_free_list = g_slist_prepend (async_free_list, closure);
+ break;
+ default:
+ g_error ("Invalid scope reached inside %s. Possibly a bad annotation?",
+ g_base_info_get_name (closure->info));
+ }
+}
+
+void _pygi_invoke_closure_free (gpointer data)
+{
+ PyGICClosure* invoke_closure = (PyGICClosure *) data;
+
+ Py_DECREF (invoke_closure->function);
+
+ g_callable_info_free_closure (invoke_closure->info,
+ invoke_closure->closure);
+
+ if (invoke_closure->info)
+ g_base_info_unref ( (GIBaseInfo*) invoke_closure->info);
+
+ Py_XDECREF (invoke_closure->user_data);
+
+ g_slice_free (PyGICClosure, invoke_closure);
+}
+
+
+PyGICClosure*
+_pygi_make_native_closure (GICallableInfo* info,
+ GIScopeType scope,
+ PyObject *py_function,
+ gpointer py_user_data)
+{
+ PyGICClosure *closure;
+ ffi_closure *fficlosure;
+
+ /* Begin by cleaning up old async functions */
+ g_slist_foreach (async_free_list, (GFunc) _pygi_invoke_closure_free, NULL);
+ g_slist_free (async_free_list);
+ async_free_list = NULL;
+
+ /* Build the closure itself */
+ closure = g_slice_new0 (PyGICClosure);
+ closure->info = (GICallableInfo *) g_base_info_ref ( (GIBaseInfo *) info);
+ closure->function = py_function;
+ closure->user_data = py_user_data;
+
+ Py_INCREF (py_function);
+ if (closure->user_data)
+ Py_INCREF (closure->user_data);
+
+ fficlosure =
+ g_callable_info_prepare_closure (info, &closure->cif, _pygi_closure_handle,
+ closure);
+ closure->closure = fficlosure;
+
+ /* Give the closure the information it needs to determine when
+ to free itself later */
+ closure->scope = scope;
+
+ return closure;
+}
diff --git a/gi/pygi-closure.h b/gi/pygi-closure.h
new file mode 100644
index 00000000..6f983398
--- /dev/null
+++ b/gi/pygi-closure.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef __PYGI_CLOSURE_H__
+#define __PYGI_CLOSURE_H__
+
+#include <Python.h>
+#include <girffi.h>
+#include <ffi.h>
+
+G_BEGIN_DECLS
+
+
+/* Private */
+
+typedef struct _PyGICClosure
+{
+ GICallableInfo *info;
+ PyObject *function;
+
+ ffi_closure *closure;
+ ffi_cif cif;
+
+ GIScopeType scope;
+
+ PyObject* user_data;
+} PyGICClosure;
+
+void _pygi_closure_handle (ffi_cif *cif, void *result, void
+ **args, void *userdata);
+
+void _pygi_invoke_closure_free (gpointer user_data);
+
+PyGICClosure* _pygi_make_native_closure (GICallableInfo* info,
+ GIScopeType scope,
+ PyObject *function,
+ gpointer user_data);
+
+G_END_DECLS
+
+#endif /* __PYGI_CLOSURE_H__ */
diff --git a/gi/pygi-foreign-cairo.c b/gi/pygi-foreign-cairo.c
new file mode 100644
index 00000000..7ec71c1d
--- /dev/null
+++ b/gi/pygi-foreign-cairo.c
@@ -0,0 +1,103 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (c) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <cairo.h>
+#include <pycairo.h>
+extern Pycairo_CAPI_t *Pycairo_CAPI;
+
+#include "pygi-foreign.h"
+#include "pygi-foreign-cairo.h"
+
+gboolean
+cairo_context_to_arg (PyObject *value,
+ GITypeInfo *type_info,
+ GITransfer transfer,
+ GArgument *arg)
+{
+ cairo_t *cr;
+
+ g_assert (transfer == GI_TRANSFER_NOTHING);
+
+ cr = PycairoContext_GET (value);
+ if (!cr)
+ return FALSE;
+
+ arg->v_pointer = cr;
+ return TRUE;
+}
+
+PyObject *
+cairo_context_from_arg (GITypeInfo *type_info, GArgument *arg)
+{
+ cairo_t *context = (cairo_t*) arg;
+
+ cairo_reference (context);
+
+ return PycairoContext_FromContext (context, &PycairoContext_Type, NULL);
+}
+
+gboolean
+cairo_context_release_arg (GITransfer transfer, GITypeInfo *type_info,
+ GArgument *arg)
+{
+ cairo_destroy ( (cairo_t*) arg->v_pointer);
+ return TRUE;
+}
+
+
+gboolean
+cairo_surface_to_arg (PyObject *value,
+ GITypeInfo *type_info,
+ GITransfer transfer,
+ GArgument *arg)
+{
+ cairo_surface_t *surface;
+
+ g_assert (transfer == GI_TRANSFER_NOTHING);
+
+ surface = ( (PycairoSurface*) value)->surface;
+ if (!surface)
+ return FALSE;
+
+ arg->v_pointer = surface;
+ return TRUE;
+}
+
+PyObject *
+cairo_surface_from_arg (GITypeInfo *type_info, GArgument *arg)
+{
+ cairo_surface_t *surface = (cairo_surface_t*) arg;
+
+ cairo_surface_reference (surface);
+
+ return PycairoSurface_FromSurface (surface, NULL);
+}
+
+gboolean
+cairo_surface_release_arg (GITransfer transfer, GITypeInfo *type_info,
+ GArgument *arg)
+{
+ cairo_surface_destroy ( (cairo_surface_t*) arg->v_pointer);
+ return TRUE;
+}
+
diff --git a/gi/pygi-foreign-cairo.h b/gi/pygi-foreign-cairo.h
new file mode 100644
index 00000000..7bff01dd
--- /dev/null
+++ b/gi/pygi-foreign-cairo.h
@@ -0,0 +1,55 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (c) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __PYGI_FOREIGN_CAIRO_H__
+#define __PYGI_FOREIGN_CAIRO_H__
+
+#include "pygi-foreign.h"
+
+gboolean cairo_context_to_arg (PyObject *value,
+ GITypeInfo *type_info,
+ GITransfer transfer,
+ GArgument *arg);
+
+PyObject *cairo_context_from_arg (GITypeInfo *type_info,
+ GArgument *arg);
+
+gboolean cairo_context_release_arg (GITransfer transfer,
+ GITypeInfo *type_info,
+ GArgument *arg);
+
+
+gboolean cairo_surface_to_arg (PyObject *value,
+ GITypeInfo *type_info,
+ GITransfer transfer,
+ GArgument *arg);
+
+PyObject *cairo_surface_from_arg (GITypeInfo *type_info,
+ GArgument *arg);
+
+gboolean cairo_surface_release_arg (GITransfer transfer,
+ GITypeInfo *type_info,
+ GArgument *arg);
+
+#endif /* __PYGI_FOREIGN_CAIRO_H__ */
+
diff --git a/gi/pygi-foreign.c b/gi/pygi-foreign.c
new file mode 100644
index 00000000..d2613df7
--- /dev/null
+++ b/gi/pygi-foreign.c
@@ -0,0 +1,125 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (c) 2010 litl, LLC
+ * Copyright (c) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "pygi-foreign.h"
+
+#include <config.h>
+#include <girepository.h>
+
+#include "pygi-foreign-cairo.h"
+
+static struct {
+ char *namespace;
+ char *name;
+ PyGIArgOverrideToGArgumentFunc to_func;
+ PyGIArgOverrideFromGArgumentFunc from_func;
+ PyGIArgOverrideReleaseGArgumentFunc release_func;
+} foreign_structs[] = {
+ { "cairo", "Context", cairo_context_to_arg, cairo_context_from_arg,
+ cairo_context_release_arg
+ },
+ { "cairo", "Surface", cairo_surface_to_arg, cairo_surface_from_arg,
+ cairo_surface_release_arg
+ },
+ { NULL }
+};
+
+static gint
+pygi_struct_foreign_lookup (GITypeInfo *type_info)
+{
+ GIBaseInfo *base_info;
+
+ base_info = g_type_info_get_interface (type_info);
+ if (base_info) {
+ gint i;
+ const gchar *namespace = g_base_info_get_namespace (base_info);
+ const gchar *name = g_base_info_get_name (base_info);
+
+ for (i = 0; foreign_structs[i].namespace; ++i) {
+
+ if ( (strcmp (namespace, foreign_structs[i].namespace) == 0) &&
+ (strcmp (name, foreign_structs[i].name) == 0)) {
+ g_base_info_unref (base_info);
+ return i;
+ }
+ }
+
+ PyErr_Format (PyExc_TypeError, "Couldn't find type %s.%s", namespace,
+ name);
+
+ g_base_info_unref (base_info);
+ }
+ return -1;
+}
+
+gboolean
+pygi_struct_foreign_convert_to_g_argument (PyObject *value,
+ GITypeInfo *type_info,
+ GITransfer transfer,
+ GArgument *arg)
+{
+ gint struct_index;
+
+ struct_index = pygi_struct_foreign_lookup (type_info);
+ if (struct_index < 0)
+ return FALSE;
+
+ if (!foreign_structs[struct_index].to_func (value, type_info, transfer, arg))
+ return FALSE;
+
+ return TRUE;
+}
+
+PyObject *
+pygi_struct_foreign_convert_from_g_argument (GITypeInfo *type_info,
+ GArgument *arg)
+{
+ gint struct_index;
+
+ struct_index = pygi_struct_foreign_lookup (type_info);
+ if (struct_index < 0)
+ return NULL;
+
+ return foreign_structs[struct_index].from_func (type_info, arg);
+}
+
+gboolean
+pygi_struct_foreign_release_g_argument (GITransfer transfer,
+ GITypeInfo *type_info,
+ GArgument *arg)
+{
+ gint struct_index;
+
+ struct_index = pygi_struct_foreign_lookup (type_info);
+ if (struct_index < 0)
+ return FALSE;
+
+ if (!foreign_structs[struct_index].release_func)
+ return TRUE;
+
+ if (!foreign_structs[struct_index].release_func (transfer, type_info, arg))
+ return FALSE;
+
+ return TRUE;
+}
diff --git a/gi/pygi-foreign.h b/gi/pygi-foreign.h
new file mode 100644
index 00000000..7962b497
--- /dev/null
+++ b/gi/pygi-foreign.h
@@ -0,0 +1,52 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (c) 2010 litl, LLC
+ * Copyright (c) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __PYGI_FOREIGN_H__
+#define __PYGI_FOREIGN_H__
+
+#include <Python.h>
+#include <girepository.h>
+
+typedef gboolean (*PyGIArgOverrideToGArgumentFunc) (PyObject *value,
+ GITypeInfo *type_info,
+ GITransfer transfer,
+ GArgument *arg);
+
+typedef PyObject * (*PyGIArgOverrideFromGArgumentFunc) (GITypeInfo *type_info,
+ GArgument *arg);
+typedef gboolean (*PyGIArgOverrideReleaseGArgumentFunc) (GITransfer transfer,
+ GITypeInfo *type_info,
+ GArgument *arg);
+
+gboolean pygi_struct_foreign_convert_to_g_argument (PyObject *value,
+ GITypeInfo *type_info,
+ GITransfer transfer,
+ GArgument *arg);
+PyObject *pygi_struct_foreign_convert_from_g_argument (GITypeInfo *type_info,
+ GArgument *arg);
+gboolean pygi_struct_foreign_release_g_argument (GITransfer transfer,
+ GITypeInfo *type_info,
+ GArgument *arg);
+
+#endif /* __PYGI_FOREIGN_H__ */
diff --git a/gi/pygi-info.c b/gi/pygi-info.c
new file mode 100644
index 00000000..b7819cab
--- /dev/null
+++ b/gi/pygi-info.c
@@ -0,0 +1,1518 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org>
+ *
+ * pygi-info.c: GI.*Info wrappers.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "pygi-private.h"
+
+#include <pygobject.h>
+
+#define _PyGI_DEFINE_INFO_TYPE(name, cname, base) \
+static PyMethodDef _Py##cname##_methods[]; \
+PyTypeObject Py##cname##_Type = { \
+ PyObject_HEAD_INIT(NULL) \
+ 0, \
+ "gi." name, /* tp_name */ \
+ sizeof(PyGIBaseInfo), /* tp_basicsize */ \
+ 0, /* tp_itemsize */ \
+ (destructor)NULL, /* tp_dealloc */ \
+ (printfunc)NULL, /* tp_print */ \
+ (getattrfunc)NULL, /* tp_getattr */ \
+ (setattrfunc)NULL, /* tp_setattr */ \
+ (cmpfunc)NULL, /* tp_compare */ \
+ (reprfunc)NULL, /* tp_repr */ \
+ NULL, /* tp_as_number */ \
+ NULL, /* tp_as_sequence */ \
+ NULL, /* tp_as_mapping */ \
+ (hashfunc)NULL, /* tp_hash */ \
+ (ternaryfunc)NULL, /* tp_call */ \
+ (reprfunc)NULL, /* tp_str */ \
+ (getattrofunc)NULL, /* tp_getattro */ \
+ (setattrofunc)NULL, /* tp_setattro */ \
+ NULL, /* tp_as_buffer */ \
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ \
+ NULL, /* tp_doc */ \
+ (traverseproc)NULL, /* tp_traverse */ \
+ (inquiry)NULL, /* tp_clear */ \
+ (richcmpfunc)NULL, /* tp_richcompare */ \
+ offsetof(PyGIBaseInfo, inst_weakreflist), /* tp_weaklistoffset */ \
+ (getiterfunc)NULL, /* tp_iter */ \
+ (iternextfunc)NULL, /* tp_iternext */ \
+ _Py##cname##_methods, /* tp_methods */ \
+ NULL, /* tp_members */ \
+ NULL, /* tp_getset */ \
+ &base /* tp_base */ \
+}
+
+
+/* BaseInfo */
+
+static void
+_base_info_dealloc (PyGIBaseInfo *self)
+{
+ PyObject_GC_UnTrack ( (PyObject *) self);
+
+ PyObject_ClearWeakRefs ( (PyObject *) self);
+
+ g_base_info_unref (self->info);
+
+ self->ob_type->tp_free ( (PyObject *) self);
+}
+
+static int
+_base_info_traverse (PyGIBaseInfo *self,
+ visitproc visit,
+ void *arg)
+{
+ return 0;
+}
+
+static PyObject *
+_base_info_repr (PyGIBaseInfo *self)
+{
+ return PyString_FromFormat ("<%s object (%s) at 0x%p>",
+ self->ob_type->tp_name, g_base_info_get_name (self->info), (void *) self);
+}
+
+static PyMethodDef _PyGIBaseInfo_methods[];
+
+PyTypeObject PyGIBaseInfo_Type = {
+ PyObject_HEAD_INIT (NULL)
+ 0,
+ "gi.BaseInfo", /* tp_name */
+ sizeof (PyGIBaseInfo), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor) _base_info_dealloc, /* tp_dealloc */
+ (printfunc) NULL, /* tp_print */
+ (getattrfunc) NULL, /* tp_getattr */
+ (setattrfunc) NULL, /* tp_setattr */
+ (cmpfunc) NULL, /* tp_compare */
+ (reprfunc) _base_info_repr, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ (hashfunc) NULL, /* tp_hash */
+ (ternaryfunc) NULL, /* tp_call */
+ (reprfunc) NULL, /* tp_str */
+ (getattrofunc) NULL, /* tp_getattro */
+ (setattrofunc) NULL, /* tp_setattro */
+ NULL, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
+ Py_TPFLAGS_HAVE_GC, /* tp_flags */
+ NULL, /* tp_doc */
+ (traverseproc) _base_info_traverse, /* tp_traverse */
+ (inquiry) NULL, /* tp_clear */
+ (richcmpfunc) NULL, /* tp_richcompare */
+ offsetof (PyGIBaseInfo, inst_weakreflist), /* tp_weaklistoffset */
+ (getiterfunc) NULL, /* tp_iter */
+ (iternextfunc) NULL, /* tp_iternext */
+ _PyGIBaseInfo_methods, /* tp_methods */
+};
+
+static PyObject *
+_wrap_g_base_info_get_name (PyGIBaseInfo *self)
+{
+ return PyString_FromString (g_base_info_get_name (self->info));
+}
+
+static PyObject *
+_wrap_g_base_info_get_namespace (PyGIBaseInfo *self)
+{
+ return PyString_FromString (g_base_info_get_namespace (self->info));
+}
+
+static PyObject *
+_wrap_g_base_info_get_container (PyGIBaseInfo *self)
+{
+ GIBaseInfo *info;
+
+ info = g_base_info_get_container (self->info);
+
+ if (info == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ return _pygi_info_new (info);
+}
+
+
+static PyMethodDef _PyGIBaseInfo_methods[] = {
+ { "get_name", (PyCFunction) _wrap_g_base_info_get_name, METH_NOARGS },
+ { "get_namespace", (PyCFunction) _wrap_g_base_info_get_namespace, METH_NOARGS },
+ { "get_container", (PyCFunction) _wrap_g_base_info_get_container, METH_NOARGS },
+ { NULL, NULL, 0 }
+};
+
+PyObject *
+_pygi_info_new (GIBaseInfo *info)
+{
+ GIInfoType info_type;
+ PyTypeObject *type = NULL;
+ PyGIBaseInfo *self;
+
+ info_type = g_base_info_get_type (info);
+
+ switch (info_type)
+ {
+ case GI_INFO_TYPE_INVALID:
+ PyErr_SetString (PyExc_RuntimeError, "Invalid info type");
+ return NULL;
+ case GI_INFO_TYPE_FUNCTION:
+ type = &PyGIFunctionInfo_Type;
+ break;
+ case GI_INFO_TYPE_CALLBACK:
+ PyErr_SetString (PyExc_NotImplementedError, "GICallbackInfo bindings not implemented");
+ return NULL;
+ case GI_INFO_TYPE_STRUCT:
+ type = &PyGIStructInfo_Type;
+ break;
+ case GI_INFO_TYPE_BOXED:
+ PyErr_SetString (PyExc_NotImplementedError, "GIBoxedInfo bindings not implemented");
+ return NULL;
+ case GI_INFO_TYPE_ENUM:
+ case GI_INFO_TYPE_FLAGS:
+ type = &PyGIEnumInfo_Type;
+ break;
+ case GI_INFO_TYPE_OBJECT:
+ type = &PyGIObjectInfo_Type;
+ break;
+ case GI_INFO_TYPE_INTERFACE:
+ type = &PyGIInterfaceInfo_Type;
+ break;
+ case GI_INFO_TYPE_CONSTANT:
+ type = &PyGIConstantInfo_Type;
+ break;
+ case GI_INFO_TYPE_ERROR_DOMAIN:
+ PyErr_SetString (PyExc_NotImplementedError, "GIErrorDomainInfo bindings not implemented");
+ return NULL;
+ case GI_INFO_TYPE_UNION:
+ type = &PyGIUnionInfo_Type;
+ break;
+ case GI_INFO_TYPE_VALUE:
+ type = &PyGIValueInfo_Type;
+ break;
+ case GI_INFO_TYPE_SIGNAL:
+ PyErr_SetString (PyExc_NotImplementedError, "GISignalInfo bindings not implemented");
+ return NULL;
+ case GI_INFO_TYPE_VFUNC:
+ type = &PyGIVFuncInfo_Type;
+ break;
+ case GI_INFO_TYPE_PROPERTY:
+ PyErr_SetString (PyExc_NotImplementedError, "GIPropertyInfo bindings not implemented");
+ return NULL;
+ case GI_INFO_TYPE_FIELD:
+ type = &PyGIFieldInfo_Type;
+ break;
+ case GI_INFO_TYPE_ARG:
+ PyErr_SetString (PyExc_NotImplementedError, "GIArgInfo bindings not implemented");
+ return NULL;
+ case GI_INFO_TYPE_TYPE:
+ PyErr_SetString (PyExc_NotImplementedError, "GITypeInfo bindings not implemented");
+ return NULL;
+ case GI_INFO_TYPE_UNRESOLVED:
+ type = &PyGIUnresolvedInfo_Type;
+ break;
+ }
+
+ self = (PyGIBaseInfo *) type->tp_alloc (type, 0);
+ if (self == NULL) {
+ return NULL;
+ }
+
+ self->info = g_base_info_ref (info);
+
+ return (PyObject *) self;
+}
+
+GIBaseInfo *
+_pygi_object_get_gi_info (PyObject *object,
+ PyTypeObject *type)
+{
+ PyObject *py_info;
+ GIBaseInfo *info = NULL;
+
+ py_info = PyObject_GetAttrString (object, "__info__");
+ if (py_info == NULL) {
+ return NULL;
+ }
+ if (!PyObject_TypeCheck (py_info, type)) {
+ PyErr_Format (PyExc_TypeError, "attribute '__info__' must be %s, not %s",
+ type->tp_name, py_info->ob_type->tp_name);
+ goto out;
+ }
+
+ info = ( (PyGIBaseInfo *) py_info)->info;
+ g_base_info_ref (info);
+
+out:
+ Py_DECREF (py_info);
+
+ return info;
+}
+
+
+/* CallableInfo */
+_PyGI_DEFINE_INFO_TYPE ("CallableInfo", GICallableInfo, PyGIBaseInfo_Type);
+
+static PyMethodDef _PyGICallableInfo_methods[] = {
+ { NULL, NULL, 0 }
+};
+
+
+/* FunctionInfo */
+_PyGI_DEFINE_INFO_TYPE ("FunctionInfo", GIFunctionInfo, PyGICallableInfo_Type);
+
+static PyObject *
+_wrap_g_function_info_is_constructor (PyGIBaseInfo *self)
+{
+ GIFunctionInfoFlags flags;
+ gboolean is_constructor;
+
+ flags = g_function_info_get_flags ( (GIFunctionInfo*) self->info);
+ is_constructor = flags & GI_FUNCTION_IS_CONSTRUCTOR;
+
+ return PyBool_FromLong (is_constructor);
+}
+
+static PyObject *
+_wrap_g_function_info_is_method (PyGIBaseInfo *self)
+{
+ GIFunctionInfoFlags flags;
+ gboolean is_method;
+
+ flags = g_function_info_get_flags ( (GIFunctionInfo*) self->info);
+ is_method = flags & GI_FUNCTION_IS_METHOD;
+
+ return PyBool_FromLong (is_method);
+}
+
+gsize
+_pygi_g_type_tag_size (GITypeTag type_tag)
+{
+ gsize size = 0;
+
+ switch (type_tag) {
+ case GI_TYPE_TAG_BOOLEAN:
+ size = sizeof (gboolean);
+ break;
+ case GI_TYPE_TAG_INT8:
+ case GI_TYPE_TAG_UINT8:
+ size = sizeof (gint8);
+ break;
+ case GI_TYPE_TAG_INT16:
+ case GI_TYPE_TAG_UINT16:
+ size = sizeof (gint16);
+ break;
+ case GI_TYPE_TAG_INT32:
+ case GI_TYPE_TAG_UINT32:
+ size = sizeof (gint32);
+ break;
+ case GI_TYPE_TAG_INT64:
+ case GI_TYPE_TAG_UINT64:
+ size = sizeof (gint64);
+ break;
+ case GI_TYPE_TAG_SHORT:
+ case GI_TYPE_TAG_USHORT:
+ size = sizeof (gshort);
+ break;
+ case GI_TYPE_TAG_INT:
+ case GI_TYPE_TAG_UINT:
+ size = sizeof (gint);
+ break;
+ case GI_TYPE_TAG_LONG:
+ case GI_TYPE_TAG_ULONG:
+ size = sizeof (glong);
+ break;
+ case GI_TYPE_TAG_SIZE:
+ case GI_TYPE_TAG_SSIZE:
+ size = sizeof (gsize);
+ break;
+ case GI_TYPE_TAG_FLOAT:
+ size = sizeof (gfloat);
+ break;
+ case GI_TYPE_TAG_DOUBLE:
+ size = sizeof (gdouble);
+ break;
+ case GI_TYPE_TAG_TIME_T:
+ size = sizeof (time_t);
+ break;
+ case GI_TYPE_TAG_GTYPE:
+ size = sizeof (GType);
+ break;
+ case GI_TYPE_TAG_VOID:
+ case GI_TYPE_TAG_UTF8:
+ case GI_TYPE_TAG_FILENAME:
+ case GI_TYPE_TAG_ARRAY:
+ case GI_TYPE_TAG_INTERFACE:
+ case GI_TYPE_TAG_GLIST:
+ case GI_TYPE_TAG_GSLIST:
+ case GI_TYPE_TAG_GHASH:
+ case GI_TYPE_TAG_ERROR:
+ PyErr_Format (PyExc_TypeError,
+ "Unable to know the size (assuming %s is not a pointer)",
+ g_type_tag_to_string (type_tag));
+ break;
+ }
+
+ return size;
+}
+
+gsize
+_pygi_g_type_info_size (GITypeInfo *type_info)
+{
+ gsize size = 0;
+
+ GITypeTag type_tag;
+
+ type_tag = g_type_info_get_tag (type_info);
+ switch (type_tag) {
+ case GI_TYPE_TAG_BOOLEAN:
+ case GI_TYPE_TAG_INT8:
+ case GI_TYPE_TAG_UINT8:
+ case GI_TYPE_TAG_INT16:
+ case GI_TYPE_TAG_UINT16:
+ case GI_TYPE_TAG_INT32:
+ case GI_TYPE_TAG_UINT32:
+ case GI_TYPE_TAG_INT64:
+ case GI_TYPE_TAG_UINT64:
+ case GI_TYPE_TAG_SHORT:
+ case GI_TYPE_TAG_USHORT:
+ case GI_TYPE_TAG_INT:
+ case GI_TYPE_TAG_UINT:
+ case GI_TYPE_TAG_LONG:
+ case GI_TYPE_TAG_ULONG:
+ case GI_TYPE_TAG_SIZE:
+ case GI_TYPE_TAG_SSIZE:
+ case GI_TYPE_TAG_FLOAT:
+ case GI_TYPE_TAG_DOUBLE:
+ case GI_TYPE_TAG_TIME_T:
+ case GI_TYPE_TAG_GTYPE:
+ if (g_type_info_is_pointer (type_info)) {
+ size = sizeof (gpointer);
+ } else {
+ size = _pygi_g_type_tag_size (type_tag);
+ g_assert (size > 0);
+ }
+ break;
+ case GI_TYPE_TAG_INTERFACE:
+ {
+ GIBaseInfo *info;
+ GIInfoType info_type;
+
+ info = g_type_info_get_interface (type_info);
+ info_type = g_base_info_get_type (info);
+
+ switch (info_type) {
+ case GI_INFO_TYPE_STRUCT:
+ if (g_type_info_is_pointer (type_info)) {
+ size = sizeof (gpointer);
+ } else {
+ size = g_struct_info_get_size ( (GIStructInfo *) info);
+ }
+ break;
+ case GI_INFO_TYPE_UNION:
+ if (g_type_info_is_pointer (type_info)) {
+ size = sizeof (gpointer);
+ } else {
+ size = g_union_info_get_size ( (GIUnionInfo *) info);
+ }
+ break;
+ case GI_INFO_TYPE_ENUM:
+ case GI_INFO_TYPE_FLAGS:
+ if (g_type_info_is_pointer (type_info)) {
+ size = sizeof (gpointer);
+ } else {
+ GITypeTag type_tag;
+
+ type_tag = g_enum_info_get_storage_type ( (GIEnumInfo *) info);
+ size = _pygi_g_type_tag_size (type_tag);
+ }
+ break;
+ case GI_INFO_TYPE_BOXED:
+ case GI_INFO_TYPE_OBJECT:
+ case GI_INFO_TYPE_INTERFACE:
+ case GI_INFO_TYPE_CALLBACK:
+ size = sizeof (gpointer);
+ break;
+ case GI_INFO_TYPE_VFUNC:
+ case GI_INFO_TYPE_INVALID:
+ case GI_INFO_TYPE_FUNCTION:
+ case GI_INFO_TYPE_CONSTANT:
+ case GI_INFO_TYPE_ERROR_DOMAIN:
+ case GI_INFO_TYPE_VALUE:
+ case GI_INFO_TYPE_SIGNAL:
+ case GI_INFO_TYPE_PROPERTY:
+ case GI_INFO_TYPE_FIELD:
+ case GI_INFO_TYPE_ARG:
+ case GI_INFO_TYPE_TYPE:
+ case GI_INFO_TYPE_UNRESOLVED:
+ g_assert_not_reached();
+ break;
+ }
+
+ g_base_info_unref (info);
+ break;
+ }
+ case GI_TYPE_TAG_ARRAY:
+ case GI_TYPE_TAG_VOID:
+ case GI_TYPE_TAG_UTF8:
+ case GI_TYPE_TAG_FILENAME:
+ case GI_TYPE_TAG_GLIST:
+ case GI_TYPE_TAG_GSLIST:
+ case GI_TYPE_TAG_GHASH:
+ case GI_TYPE_TAG_ERROR:
+ size = sizeof (gpointer);
+ break;
+ }
+
+ return size;
+}
+
+static PyMethodDef _PyGIFunctionInfo_methods[] = {
+ { "is_constructor", (PyCFunction) _wrap_g_function_info_is_constructor, METH_NOARGS },
+ { "is_method", (PyCFunction) _wrap_g_function_info_is_method, METH_NOARGS },
+ { "invoke", (PyCFunction) _wrap_g_function_info_invoke, METH_VARARGS },
+ { NULL, NULL, 0 }
+};
+
+
+/* RegisteredTypeInfo */
+_PyGI_DEFINE_INFO_TYPE ("RegisteredTypeInfo", GIRegisteredTypeInfo, PyGIBaseInfo_Type);
+
+static PyObject *
+_wrap_g_registered_type_info_get_g_type (PyGIBaseInfo *self)
+{
+ GType type;
+
+ type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) self->info);
+
+ return pyg_type_wrapper_new (type);
+}
+
+static PyMethodDef _PyGIRegisteredTypeInfo_methods[] = {
+ { "get_g_type", (PyCFunction) _wrap_g_registered_type_info_get_g_type, METH_NOARGS },
+ { NULL, NULL, 0 }
+};
+
+
+/* GIStructInfo */
+_PyGI_DEFINE_INFO_TYPE ("StructInfo", GIStructInfo, PyGIRegisteredTypeInfo_Type);
+
+static PyObject *
+_get_fields (PyGIBaseInfo *self, GIInfoType info_type)
+{
+ gssize n_infos;
+ PyObject *infos;
+ gssize i;
+
+ switch (info_type) {
+ case GI_INFO_TYPE_STRUCT:
+ n_infos = g_struct_info_get_n_fields ( (GIStructInfo *) self->info);
+ break;
+ case GI_INFO_TYPE_OBJECT:
+ n_infos = g_object_info_get_n_fields ( (GIObjectInfo *) self->info);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ infos = PyTuple_New (n_infos);
+ if (infos == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < n_infos; i++) {
+ GIBaseInfo *info;
+ PyObject *py_info;
+
+ switch (info_type) {
+ case GI_INFO_TYPE_STRUCT:
+ info = (GIBaseInfo *) g_struct_info_get_field ( (GIStructInfo *) self->info, i);
+ break;
+ case GI_INFO_TYPE_OBJECT:
+ info = (GIBaseInfo *) g_object_info_get_field ( (GIObjectInfo *) self->info, i);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ g_assert (info != NULL);
+
+ py_info = _pygi_info_new (info);
+
+ g_base_info_unref (info);
+
+ if (py_info == NULL) {
+ Py_CLEAR (infos);
+ break;
+ }
+
+ PyTuple_SET_ITEM (infos, i, py_info);
+ }
+
+ return infos;
+}
+
+static PyObject *
+_get_methods (PyGIBaseInfo *self, GIInfoType info_type)
+{
+ gssize n_infos;
+ PyObject *infos;
+ gssize i;
+
+ switch (info_type) {
+ case GI_INFO_TYPE_STRUCT:
+ n_infos = g_struct_info_get_n_methods ( (GIStructInfo *) self->info);
+ break;
+ case GI_INFO_TYPE_OBJECT:
+ n_infos = g_object_info_get_n_methods ( (GIObjectInfo *) self->info);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ infos = PyTuple_New (n_infos);
+ if (infos == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < n_infos; i++) {
+ GIBaseInfo *info;
+ PyObject *py_info;
+
+ switch (info_type) {
+ case GI_INFO_TYPE_STRUCT:
+ info = (GIBaseInfo *) g_struct_info_get_method ( (GIStructInfo *) self->info, i);
+ break;
+ case GI_INFO_TYPE_OBJECT:
+ info = (GIBaseInfo *) g_object_info_get_method ( (GIObjectInfo *) self->info, i);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ g_assert (info != NULL);
+
+ py_info = _pygi_info_new (info);
+
+ g_base_info_unref (info);
+
+ if (py_info == NULL) {
+ Py_CLEAR (infos);
+ break;
+ }
+
+ PyTuple_SET_ITEM (infos, i, py_info);
+ }
+
+ return infos;
+}
+
+static PyObject *
+_get_constants (PyGIBaseInfo *self, GIInfoType info_type)
+{
+ gssize n_infos;
+ PyObject *infos;
+ gssize i;
+
+ switch (info_type) {
+ case GI_INFO_TYPE_INTERFACE:
+ n_infos = g_interface_info_get_n_constants ( (GIInterfaceInfo *) self->info);
+ break;
+ case GI_INFO_TYPE_OBJECT:
+ n_infos = g_object_info_get_n_constants ( (GIObjectInfo *) self->info);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ infos = PyTuple_New (n_infos);
+ if (infos == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < n_infos; i++) {
+ GIBaseInfo *info;
+ PyObject *py_info;
+
+ switch (info_type) {
+ case GI_INFO_TYPE_INTERFACE:
+ info = (GIBaseInfo *) g_interface_info_get_constant ( (GIInterfaceInfo *) self->info, i);
+ break;
+ case GI_INFO_TYPE_OBJECT:
+ info = (GIBaseInfo *) g_object_info_get_constant ( (GIObjectInfo *) self->info, i);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ g_assert (info != NULL);
+
+ py_info = _pygi_info_new (info);
+
+ g_base_info_unref (info);
+
+ if (py_info == NULL) {
+ Py_CLEAR (infos);
+ break;
+ }
+
+ PyTuple_SET_ITEM (infos, i, py_info);
+ }
+
+ return infos;
+}
+
+static PyObject *
+_get_vfuncs (PyGIBaseInfo *self, GIInfoType info_type)
+{
+ gssize n_infos;
+ PyObject *infos;
+ gssize i;
+
+ switch (info_type) {
+ case GI_INFO_TYPE_INTERFACE:
+ n_infos = g_interface_info_get_n_vfuncs ( (GIInterfaceInfo *) self->info);
+ break;
+ case GI_INFO_TYPE_OBJECT:
+ n_infos = g_object_info_get_n_vfuncs ( (GIObjectInfo *) self->info);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ infos = PyTuple_New (n_infos);
+ if (infos == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < n_infos; i++) {
+ GIBaseInfo *info;
+ PyObject *py_info;
+
+ switch (info_type) {
+ case GI_INFO_TYPE_INTERFACE:
+ info = (GIBaseInfo *) g_interface_info_get_vfunc ( (GIInterfaceInfo *) self->info, i);
+ break;
+ case GI_INFO_TYPE_OBJECT:
+ info = (GIBaseInfo *) g_object_info_get_vfunc ( (GIObjectInfo *) self->info, i);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ g_assert (info != NULL);
+
+ py_info = _pygi_info_new (info);
+
+ g_base_info_unref (info);
+
+ if (py_info == NULL) {
+ Py_CLEAR (infos);
+ break;
+ }
+
+ PyTuple_SET_ITEM (infos, i, py_info);
+ }
+
+ return infos;
+}
+
+static PyObject *
+_wrap_g_struct_info_get_fields (PyGIBaseInfo *self)
+{
+ return _get_fields (self, GI_INFO_TYPE_STRUCT);
+}
+
+static PyObject *
+_wrap_g_struct_info_get_methods (PyGIBaseInfo *self)
+{
+ return _get_methods (self, GI_INFO_TYPE_STRUCT);
+}
+
+static PyMethodDef _PyGIStructInfo_methods[] = {
+ { "get_fields", (PyCFunction) _wrap_g_struct_info_get_fields, METH_NOARGS },
+ { "get_methods", (PyCFunction) _wrap_g_struct_info_get_methods, METH_NOARGS },
+ { NULL, NULL, 0 }
+};
+
+gboolean
+pygi_g_struct_info_is_simple (GIStructInfo *struct_info)
+{
+ gboolean is_simple;
+ gsize n_field_infos;
+ gsize i;
+
+ is_simple = TRUE;
+
+ n_field_infos = g_struct_info_get_n_fields (struct_info);
+
+ for (i = 0; i < n_field_infos && is_simple; i++) {
+ GIFieldInfo *field_info;
+ GITypeInfo *field_type_info;
+
+ field_info = g_struct_info_get_field (struct_info, i);
+ field_type_info = g_field_info_get_type (field_info);
+
+ GITypeTag field_type_tag;
+
+ field_type_tag = g_type_info_get_tag (field_type_info);
+
+ switch (field_type_tag) {
+ case GI_TYPE_TAG_BOOLEAN:
+ case GI_TYPE_TAG_INT8:
+ case GI_TYPE_TAG_UINT8:
+ case GI_TYPE_TAG_INT16:
+ case GI_TYPE_TAG_UINT16:
+ case GI_TYPE_TAG_INT32:
+ case GI_TYPE_TAG_UINT32:
+ case GI_TYPE_TAG_SHORT:
+ case GI_TYPE_TAG_USHORT:
+ case GI_TYPE_TAG_INT:
+ case GI_TYPE_TAG_UINT:
+ case GI_TYPE_TAG_INT64:
+ case GI_TYPE_TAG_UINT64:
+ case GI_TYPE_TAG_LONG:
+ case GI_TYPE_TAG_ULONG:
+ case GI_TYPE_TAG_SSIZE:
+ case GI_TYPE_TAG_SIZE:
+ case GI_TYPE_TAG_FLOAT:
+ case GI_TYPE_TAG_DOUBLE:
+ case GI_TYPE_TAG_TIME_T:
+ if (g_type_info_is_pointer (field_type_info)) {
+ is_simple = FALSE;
+ }
+ break;
+ case GI_TYPE_TAG_VOID:
+ case GI_TYPE_TAG_GTYPE:
+ case GI_TYPE_TAG_ERROR:
+ case GI_TYPE_TAG_UTF8:
+ case GI_TYPE_TAG_FILENAME:
+ case GI_TYPE_TAG_ARRAY:
+ case GI_TYPE_TAG_GLIST:
+ case GI_TYPE_TAG_GSLIST:
+ case GI_TYPE_TAG_GHASH:
+ is_simple = FALSE;
+ break;
+ case GI_TYPE_TAG_INTERFACE:
+ {
+ GIBaseInfo *info;
+ GIInfoType info_type;
+
+ info = g_type_info_get_interface (field_type_info);
+ info_type = g_base_info_get_type (info);
+
+ switch (info_type) {
+ case GI_INFO_TYPE_STRUCT:
+ if (g_type_info_is_pointer (field_type_info)) {
+ is_simple = FALSE;
+ } else {
+ is_simple = pygi_g_struct_info_is_simple ( (GIStructInfo *) info);
+ }
+ break;
+ case GI_INFO_TYPE_UNION:
+ /* TODO */
+ is_simple = FALSE;
+ break;
+ case GI_INFO_TYPE_ENUM:
+ case GI_INFO_TYPE_FLAGS:
+ if (g_type_info_is_pointer (field_type_info)) {
+ is_simple = FALSE;
+ }
+ break;
+ case GI_INFO_TYPE_BOXED:
+ case GI_INFO_TYPE_OBJECT:
+ case GI_INFO_TYPE_CALLBACK:
+ case GI_INFO_TYPE_INTERFACE:
+ is_simple = FALSE;
+ break;
+ case GI_INFO_TYPE_VFUNC:
+ case GI_INFO_TYPE_INVALID:
+ case GI_INFO_TYPE_FUNCTION:
+ case GI_INFO_TYPE_CONSTANT:
+ case GI_INFO_TYPE_ERROR_DOMAIN:
+ case GI_INFO_TYPE_VALUE:
+ case GI_INFO_TYPE_SIGNAL:
+ case GI_INFO_TYPE_PROPERTY:
+ case GI_INFO_TYPE_FIELD:
+ case GI_INFO_TYPE_ARG:
+ case GI_INFO_TYPE_TYPE:
+ case GI_INFO_TYPE_UNRESOLVED:
+ g_assert_not_reached();
+ }
+
+ g_base_info_unref (info);
+ break;
+ }
+ }
+
+ g_base_info_unref ( (GIBaseInfo *) field_type_info);
+ g_base_info_unref ( (GIBaseInfo *) field_info);
+ }
+
+ return is_simple;
+}
+
+
+/* EnumInfo */
+_PyGI_DEFINE_INFO_TYPE ("EnumInfo", GIEnumInfo, PyGIRegisteredTypeInfo_Type);
+
+static PyObject *
+_wrap_g_enum_info_get_values (PyGIBaseInfo *self)
+{
+ gssize n_infos;
+ PyObject *infos;
+ gssize i;
+
+ n_infos = g_enum_info_get_n_values ( (GIEnumInfo *) self->info);
+
+ infos = PyTuple_New (n_infos);
+ if (infos == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < n_infos; i++) {
+ GIBaseInfo *info;
+ PyObject *py_info;
+
+ info = (GIBaseInfo *) g_enum_info_get_value ( (GIEnumInfo *) self->info, i);
+ g_assert (info != NULL);
+
+ py_info = _pygi_info_new (info);
+
+ g_base_info_unref (info);
+
+ if (py_info == NULL) {
+ Py_CLEAR (infos);
+ break;
+ }
+
+ PyTuple_SET_ITEM (infos, i, py_info);
+ }
+
+ return infos;
+}
+
+static PyMethodDef _PyGIEnumInfo_methods[] = {
+ { "get_values", (PyCFunction) _wrap_g_enum_info_get_values, METH_NOARGS },
+ { NULL, NULL, 0 }
+};
+
+
+/* ObjectInfo */
+_PyGI_DEFINE_INFO_TYPE ("ObjectInfo", GIObjectInfo, PyGIRegisteredTypeInfo_Type);
+
+static PyObject *
+_wrap_g_object_info_get_parent (PyGIBaseInfo *self)
+{
+ GIBaseInfo *info;
+ PyObject *py_info;
+
+ info = (GIBaseInfo *) g_object_info_get_parent ( (GIObjectInfo*) self->info);
+
+ if (info == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ py_info = _pygi_info_new (info);
+
+ g_base_info_unref (info);
+
+ return py_info;
+}
+
+static PyObject *
+_wrap_g_object_info_get_methods (PyGIBaseInfo *self)
+{
+ return _get_methods (self, GI_INFO_TYPE_OBJECT);
+}
+
+static PyObject *
+_wrap_g_object_info_get_fields (PyGIBaseInfo *self)
+{
+ return _get_fields (self, GI_INFO_TYPE_OBJECT);
+}
+
+static PyObject *
+_wrap_g_object_info_get_interfaces (PyGIBaseInfo *self)
+{
+ gssize n_infos;
+ PyObject *infos;
+ gssize i;
+
+ n_infos = g_object_info_get_n_interfaces ( (GIObjectInfo *) self->info);
+
+ infos = PyTuple_New (n_infos);
+ if (infos == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < n_infos; i++) {
+ GIBaseInfo *info;
+ PyObject *py_info;
+
+ info = (GIBaseInfo *) g_object_info_get_interface ( (GIObjectInfo *) self->info, i);
+ g_assert (info != NULL);
+
+ py_info = _pygi_info_new (info);
+
+ g_base_info_unref (info);
+
+ if (py_info == NULL) {
+ Py_CLEAR (infos);
+ break;
+ }
+
+ PyTuple_SET_ITEM (infos, i, py_info);
+ }
+
+ return infos;
+}
+
+static PyObject *
+_wrap_g_object_info_get_constants (PyGIBaseInfo *self)
+{
+ return _get_constants (self, GI_INFO_TYPE_OBJECT);
+}
+
+static PyObject *
+_wrap_g_object_info_get_vfuncs (PyGIBaseInfo *self)
+{
+ return _get_vfuncs (self, GI_INFO_TYPE_OBJECT);
+}
+
+static PyMethodDef _PyGIObjectInfo_methods[] = {
+ { "get_parent", (PyCFunction) _wrap_g_object_info_get_parent, METH_NOARGS },
+ { "get_methods", (PyCFunction) _wrap_g_object_info_get_methods, METH_NOARGS },
+ { "get_fields", (PyCFunction) _wrap_g_object_info_get_fields, METH_NOARGS },
+ { "get_interfaces", (PyCFunction) _wrap_g_object_info_get_interfaces, METH_NOARGS },
+ { "get_constants", (PyCFunction) _wrap_g_object_info_get_constants, METH_NOARGS },
+ { "get_vfuncs", (PyCFunction) _wrap_g_object_info_get_vfuncs, METH_NOARGS },
+ { NULL, NULL, 0 }
+};
+
+
+/* GIInterfaceInfo */
+_PyGI_DEFINE_INFO_TYPE ("InterfaceInfo", GIInterfaceInfo, PyGIRegisteredTypeInfo_Type);
+
+static PyObject *
+_wrap_g_interface_info_get_methods (PyGIBaseInfo *self)
+{
+ gssize n_infos;
+ PyObject *infos;
+ gssize i;
+
+ n_infos = g_interface_info_get_n_methods ( (GIInterfaceInfo *) self->info);
+
+ infos = PyTuple_New (n_infos);
+ if (infos == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < n_infos; i++) {
+ GIBaseInfo *info;
+ PyObject *py_info;
+
+ info = (GIBaseInfo *) g_interface_info_get_method ( (GIInterfaceInfo *) self->info, i);
+ g_assert (info != NULL);
+
+ py_info = _pygi_info_new (info);
+
+ g_base_info_unref (info);
+
+ if (py_info == NULL) {
+ Py_CLEAR (infos);
+ break;
+ }
+
+ PyTuple_SET_ITEM (infos, i, py_info);
+ }
+
+ return infos;
+}
+
+static PyObject *
+_wrap_g_interface_info_get_constants (PyGIBaseInfo *self)
+{
+ return _get_constants (self, GI_INFO_TYPE_INTERFACE);
+}
+
+static PyObject *
+_wrap_g_interface_info_get_vfuncs (PyGIBaseInfo *self)
+{
+ return _get_vfuncs (self, GI_INFO_TYPE_INTERFACE);
+}
+
+static PyMethodDef _PyGIInterfaceInfo_methods[] = {
+ { "get_methods", (PyCFunction) _wrap_g_interface_info_get_methods, METH_NOARGS },
+ { "get_constants", (PyCFunction) _wrap_g_interface_info_get_constants, METH_NOARGS },
+ { "get_vfuncs", (PyCFunction) _wrap_g_interface_info_get_vfuncs, METH_NOARGS },
+ { NULL, NULL, 0 }
+};
+
+/* GIConstantInfo */
+_PyGI_DEFINE_INFO_TYPE ("ConstantInfo", GIConstantInfo, PyGIBaseInfo_Type);
+
+static PyObject *
+_wrap_g_constant_info_get_value (PyGIBaseInfo *self)
+{
+ GITypeInfo *type_info;
+ GArgument value;
+ PyObject *py_value;
+
+ if (g_constant_info_get_value ( (GIConstantInfo *) self->info, &value) < 0) {
+ PyErr_SetString (PyExc_RuntimeError, "unable to get value");
+ return NULL;
+ }
+
+ type_info = g_constant_info_get_type ( (GIConstantInfo *) self->info);
+
+ py_value = _pygi_argument_to_object (&value, type_info, GI_TRANSFER_NOTHING);
+
+ g_base_info_unref ( (GIBaseInfo *) type_info);
+
+ return py_value;
+}
+
+static PyMethodDef _PyGIConstantInfo_methods[] = {
+ { "get_value", (PyCFunction) _wrap_g_constant_info_get_value, METH_NOARGS },
+ { NULL, NULL, 0 }
+};
+
+/* GIValueInfo */
+_PyGI_DEFINE_INFO_TYPE ("ValueInfo", GIValueInfo, PyGIBaseInfo_Type);
+
+static PyObject *
+_wrap_g_value_info_get_value (PyGIBaseInfo *self)
+{
+ glong value;
+
+ value = g_value_info_get_value ( (GIValueInfo *) self->info);
+
+ return PyInt_FromLong (value);
+}
+
+
+static PyMethodDef _PyGIValueInfo_methods[] = {
+ { "get_value", (PyCFunction) _wrap_g_value_info_get_value, METH_NOARGS },
+ { NULL, NULL, 0 }
+};
+
+
+/* GIFieldInfo */
+_PyGI_DEFINE_INFO_TYPE ("FieldInfo", GIFieldInfo, PyGIBaseInfo_Type);
+
+static PyObject *
+_wrap_g_field_info_get_value (PyGIBaseInfo *self,
+ PyObject *args)
+{
+ PyObject *instance;
+ GIBaseInfo *container_info;
+ GIInfoType container_info_type;
+ gpointer pointer;
+ GITypeInfo *field_type_info;
+ GArgument value;
+ PyObject *py_value = NULL;
+
+ if (!PyArg_ParseTuple (args, "O:FieldInfo.get_value", &instance)) {
+ return NULL;
+ }
+
+ container_info = g_base_info_get_container (self->info);
+ g_assert (container_info != NULL);
+
+ /* Check the instance. */
+ if (!_pygi_g_registered_type_info_check_object ( (GIRegisteredTypeInfo *) container_info, TRUE, instance)) {
+ _PyGI_ERROR_PREFIX ("argument 1: ");
+ return NULL;
+ }
+
+ /* Get the pointer to the container. */
+ container_info_type = g_base_info_get_type (container_info);
+ switch (container_info_type) {
+ case GI_INFO_TYPE_UNION:
+ case GI_INFO_TYPE_STRUCT:
+ pointer = pyg_boxed_get (instance, void);
+ break;
+ case GI_INFO_TYPE_OBJECT:
+ pointer = pygobject_get (instance);
+ break;
+ default:
+ /* Other types don't have fields. */
+ g_assert_not_reached();
+ }
+
+ /* Get the field's value. */
+ field_type_info = g_field_info_get_type ( (GIFieldInfo *) self->info);
+
+ /* A few types are not handled by g_field_info_get_field, so do it here. */
+ if (!g_type_info_is_pointer (field_type_info)
+ && g_type_info_get_tag (field_type_info) == GI_TYPE_TAG_INTERFACE) {
+ GIBaseInfo *info;
+ GIInfoType info_type;
+
+ if (! (g_field_info_get_flags ( (GIFieldInfo *) self->info) & GI_FIELD_IS_READABLE)) {
+ PyErr_SetString (PyExc_RuntimeError, "field is not readable");
+ goto out;
+ }
+
+ info = g_type_info_get_interface (field_type_info);
+
+ info_type = g_base_info_get_type (info);
+
+ g_base_info_unref (info);
+
+ switch (info_type) {
+ case GI_INFO_TYPE_UNION:
+ PyErr_SetString (PyExc_NotImplementedError, "getting an union is not supported yet");
+ goto out;
+ case GI_INFO_TYPE_STRUCT:
+ {
+ gsize offset;
+
+ offset = g_field_info_get_offset ( (GIFieldInfo *) self->info);
+
+ value.v_pointer = pointer + offset;
+
+ goto argument_to_object;
+ }
+ default:
+ /* Fallback. */
+ break;
+ }
+ }
+
+ if (!g_field_info_get_field ( (GIFieldInfo *) self->info, pointer, &value)) {
+ PyErr_SetString (PyExc_RuntimeError, "unable to get the value");
+ goto out;
+ }
+
+ if ( (g_type_info_get_tag (field_type_info) == GI_TYPE_TAG_ARRAY) &&
+ (g_type_info_get_array_type (field_type_info) == GI_ARRAY_TYPE_C)) {
+ value.v_pointer = _pygi_argument_to_array (&value, NULL,
+ field_type_info, FALSE);
+ }
+
+argument_to_object:
+ py_value = _pygi_argument_to_object (&value, field_type_info, GI_TRANSFER_NOTHING);
+
+ if ( (g_type_info_get_tag (field_type_info) == GI_TYPE_TAG_ARRAY) &&
+ (g_type_info_get_array_type (field_type_info) == GI_ARRAY_TYPE_C)) {
+ g_array_free (value.v_pointer, FALSE);
+ }
+
+out:
+ g_base_info_unref ( (GIBaseInfo *) field_type_info);
+
+ return py_value;
+}
+
+static PyObject *
+_wrap_g_field_info_set_value (PyGIBaseInfo *self,
+ PyObject *args)
+{
+ PyObject *instance;
+ PyObject *py_value;
+ GIBaseInfo *container_info;
+ GIInfoType container_info_type;
+ gpointer pointer;
+ GITypeInfo *field_type_info;
+ GArgument value;
+ PyObject *retval = NULL;
+
+ if (!PyArg_ParseTuple (args, "OO:FieldInfo.set_value", &instance, &py_value)) {
+ return NULL;
+ }
+
+ container_info = g_base_info_get_container (self->info);
+ g_assert (container_info != NULL);
+
+ /* Check the instance. */
+ if (!_pygi_g_registered_type_info_check_object ( (GIRegisteredTypeInfo *) container_info, TRUE, instance)) {
+ _PyGI_ERROR_PREFIX ("argument 1: ");
+ return NULL;
+ }
+
+ /* Get the pointer to the container. */
+ container_info_type = g_base_info_get_type (container_info);
+ switch (container_info_type) {
+ case GI_INFO_TYPE_UNION:
+ case GI_INFO_TYPE_STRUCT:
+ pointer = pyg_boxed_get (instance, void);
+ break;
+ case GI_INFO_TYPE_OBJECT:
+ pointer = pygobject_get (instance);
+ break;
+ default:
+ /* Other types don't have fields. */
+ g_assert_not_reached();
+ }
+
+ field_type_info = g_field_info_get_type ( (GIFieldInfo *) self->info);
+
+ /* Check the value. */
+ {
+ gboolean retval;
+
+ retval = _pygi_g_type_info_check_object (field_type_info, py_value, TRUE);
+ if (retval < 0) {
+ goto out;
+ }
+
+ if (!retval) {
+ _PyGI_ERROR_PREFIX ("argument 2: ");
+ goto out;
+ }
+ }
+
+ /* Set the field's value. */
+ /* A few types are not handled by g_field_info_set_field, so do it here. */
+ if (!g_type_info_is_pointer (field_type_info)
+ && g_type_info_get_tag (field_type_info) == GI_TYPE_TAG_INTERFACE) {
+ GIBaseInfo *info;
+ GIInfoType info_type;
+
+ if (! (g_field_info_get_flags ( (GIFieldInfo *) self->info) & GI_FIELD_IS_WRITABLE)) {
+ PyErr_SetString (PyExc_RuntimeError, "field is not writable");
+ goto out;
+ }
+
+ info = g_type_info_get_interface (field_type_info);
+
+ info_type = g_base_info_get_type (info);
+
+ switch (info_type) {
+ case GI_INFO_TYPE_UNION:
+ PyErr_SetString (PyExc_NotImplementedError, "setting an union is not supported yet");
+ goto out;
+ case GI_INFO_TYPE_STRUCT:
+ {
+ gboolean is_simple;
+ gsize offset;
+ gssize size;
+
+ is_simple = pygi_g_struct_info_is_simple ( (GIStructInfo *) info);
+
+ if (!is_simple) {
+ PyErr_SetString (PyExc_TypeError,
+ "cannot set a structure which has no well-defined ownership transfer rules");
+ g_base_info_unref (info);
+ goto out;
+ }
+
+ value = _pygi_argument_from_object (py_value, field_type_info, GI_TRANSFER_NOTHING);
+ if (PyErr_Occurred()) {
+ g_base_info_unref (info);
+ goto out;
+ }
+
+ offset = g_field_info_get_offset ( (GIFieldInfo *) self->info);
+ size = g_struct_info_get_size ( (GIStructInfo *) info);
+ g_assert (size > 0);
+
+ g_memmove (pointer + offset, value.v_pointer, size);
+
+ g_base_info_unref (info);
+
+ retval = Py_None;
+ goto out;
+ }
+ default:
+ /* Fallback. */
+ break;
+ }
+
+ g_base_info_unref (info);
+ }
+
+ value = _pygi_argument_from_object (py_value, field_type_info, GI_TRANSFER_EVERYTHING);
+ if (PyErr_Occurred()) {
+ goto out;
+ }
+
+ if (!g_field_info_set_field ( (GIFieldInfo *) self->info, pointer, &value)) {
+ _pygi_argument_release (&value, field_type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN);
+ PyErr_SetString (PyExc_RuntimeError, "unable to set value for field");
+ goto out;
+ }
+
+ retval = Py_None;
+
+out:
+ g_base_info_unref ( (GIBaseInfo *) field_type_info);
+
+ Py_XINCREF (retval);
+ return retval;
+}
+
+static PyMethodDef _PyGIFieldInfo_methods[] = {
+ { "get_value", (PyCFunction) _wrap_g_field_info_get_value, METH_VARARGS },
+ { "set_value", (PyCFunction) _wrap_g_field_info_set_value, METH_VARARGS },
+ { NULL, NULL, 0 }
+};
+
+
+/* GIUnresolvedInfo */
+_PyGI_DEFINE_INFO_TYPE ("UnresolvedInfo", GIUnresolvedInfo, PyGIBaseInfo_Type);
+
+static PyMethodDef _PyGIUnresolvedInfo_methods[] = {
+ { NULL, NULL, 0 }
+};
+
+/* GIVFuncInfo */
+_PyGI_DEFINE_INFO_TYPE ("VFuncInfo", GIVFuncInfo, PyGIBaseInfo_Type);
+
+static PyMethodDef _PyGIVFuncInfo_methods[] = {
+ { NULL, NULL, 0 }
+};
+
+
+/* GIUnionInfo */
+_PyGI_DEFINE_INFO_TYPE ("UnionInfo", GIUnionInfo, PyGIRegisteredTypeInfo_Type);
+
+static PyObject *
+_wrap_g_union_info_get_fields (PyGIBaseInfo *self)
+{
+ gssize n_infos;
+ PyObject *infos;
+ gssize i;
+
+ n_infos = g_union_info_get_n_fields ( (GIUnionInfo *) self->info);
+
+ infos = PyTuple_New (n_infos);
+ if (infos == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < n_infos; i++) {
+ GIBaseInfo *info;
+ PyObject *py_info;
+
+ info = (GIBaseInfo *) g_union_info_get_field ( (GIUnionInfo *) self->info, i);
+ g_assert (info != NULL);
+
+ py_info = _pygi_info_new (info);
+
+ g_base_info_unref (info);
+
+ if (py_info == NULL) {
+ Py_CLEAR (infos);
+ break;
+ }
+
+ PyTuple_SET_ITEM (infos, i, py_info);
+ }
+
+ return infos;
+}
+
+static PyObject *
+_wrap_g_union_info_get_methods (PyGIBaseInfo *self)
+{
+ gssize n_infos;
+ PyObject *infos;
+ gssize i;
+
+ n_infos = g_union_info_get_n_methods ( (GIUnionInfo *) self->info);
+
+ infos = PyTuple_New (n_infos);
+ if (infos == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < n_infos; i++) {
+ GIBaseInfo *info;
+ PyObject *py_info;
+
+ info = (GIBaseInfo *) g_union_info_get_method ( (GIUnionInfo *) self->info, i);
+ g_assert (info != NULL);
+
+ py_info = _pygi_info_new (info);
+
+ g_base_info_unref (info);
+
+ if (py_info == NULL) {
+ Py_CLEAR (infos);
+ break;
+ }
+
+ PyTuple_SET_ITEM (infos, i, py_info);
+ }
+
+ return infos;
+}
+
+static PyMethodDef _PyGIUnionInfo_methods[] = {
+ { "get_fields", (PyCFunction) _wrap_g_union_info_get_fields, METH_NOARGS },
+ { "get_methods", (PyCFunction) _wrap_g_union_info_get_methods, METH_NOARGS },
+ { NULL, NULL, 0 }
+};
+
+/* Private */
+
+gchar *
+_pygi_g_base_info_get_fullname (GIBaseInfo *info)
+{
+ GIBaseInfo *container_info;
+ gchar *fullname;
+
+ container_info = g_base_info_get_container (info);
+ if (container_info != NULL) {
+ fullname = g_strdup_printf ("%s.%s.%s",
+ g_base_info_get_namespace (container_info),
+ g_base_info_get_name (container_info),
+ g_base_info_get_name (info));
+ } else {
+ fullname = g_strdup_printf ("%s.%s",
+ g_base_info_get_namespace (info),
+ g_base_info_get_name (info));
+ }
+
+ if (fullname == NULL) {
+ PyErr_NoMemory();
+ }
+
+ return fullname;
+}
+
+void
+_pygi_info_register_types (PyObject *m)
+{
+#define _PyGI_REGISTER_TYPE(m, type, name) \
+ type.ob_type = &PyType_Type; \
+ if (PyType_Ready(&type)) \
+ return; \
+ if (PyModule_AddObject(m, name, (PyObject *)&type)) \
+ return
+
+ _PyGI_REGISTER_TYPE (m, PyGIBaseInfo_Type, "BaseInfo");
+ _PyGI_REGISTER_TYPE (m, PyGIUnresolvedInfo_Type, "UnresolvedInfo");
+ _PyGI_REGISTER_TYPE (m, PyGICallableInfo_Type, "CallableInfo");
+ _PyGI_REGISTER_TYPE (m, PyGIFunctionInfo_Type, "FunctionInfo");
+ _PyGI_REGISTER_TYPE (m, PyGIRegisteredTypeInfo_Type, "RegisteredTypeInfo");
+ _PyGI_REGISTER_TYPE (m, PyGIStructInfo_Type, "StructInfo");
+ _PyGI_REGISTER_TYPE (m, PyGIEnumInfo_Type, "EnumInfo");
+ _PyGI_REGISTER_TYPE (m, PyGIObjectInfo_Type, "ObjectInfo");
+ _PyGI_REGISTER_TYPE (m, PyGIInterfaceInfo_Type, "InterfaceInfo");
+ _PyGI_REGISTER_TYPE (m, PyGIConstantInfo_Type, "ConstantInfo");
+ _PyGI_REGISTER_TYPE (m, PyGIValueInfo_Type, "ValueInfo");
+ _PyGI_REGISTER_TYPE (m, PyGIFieldInfo_Type, "FieldInfo");
+ _PyGI_REGISTER_TYPE (m, PyGIVFuncInfo_Type, "VFuncInfo");
+ _PyGI_REGISTER_TYPE (m, PyGIUnionInfo_Type, "UnionInfo");
+
+#undef _PyGI_REGISTER_TYPE
+}
diff --git a/gi/pygi-info.h b/gi/pygi-info.h
new file mode 100644
index 00000000..0d2bade3
--- /dev/null
+++ b/gi/pygi-info.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef __PYGI_INFO_H__
+#define __PYGI_INFO_H__
+
+#include <Python.h>
+
+#include <girepository.h>
+
+G_BEGIN_DECLS
+
+gboolean pygi_g_struct_info_is_simple (GIStructInfo *struct_info);
+
+
+/* Private */
+
+extern PyTypeObject PyGIBaseInfo_Type;
+extern PyTypeObject PyGICallableInfo_Type;
+extern PyTypeObject PyGIFunctionInfo_Type;
+extern PyTypeObject PyGIRegisteredTypeInfo_Type;
+extern PyTypeObject PyGIStructInfo_Type;
+extern PyTypeObject PyGIEnumInfo_Type;
+extern PyTypeObject PyGIObjectInfo_Type;
+extern PyTypeObject PyGIInterfaceInfo_Type;
+extern PyTypeObject PyGIConstantInfo_Type;
+extern PyTypeObject PyGIValueInfo_Type;
+extern PyTypeObject PyGIFieldInfo_Type;
+extern PyTypeObject PyGIUnresolvedInfo_Type;
+extern PyTypeObject PyGIVFuncInfo_Type;
+extern PyTypeObject PyGIUnionInfo_Type;
+
+#define PyGIBaseInfo_GET_GI_INFO(object) g_base_info_ref(((PyGIBaseInfo *)object)->info)
+
+PyObject* _pygi_info_new (GIBaseInfo *info);
+GIBaseInfo* _pygi_object_get_gi_info (PyObject *object,
+ PyTypeObject *type);
+
+gchar* _pygi_g_base_info_get_fullname (GIBaseInfo *info);
+
+gsize _pygi_g_type_tag_size (GITypeTag type_tag);
+gsize _pygi_g_type_info_size (GITypeInfo *type_info);
+
+void _pygi_info_register_types (PyObject *m);
+
+G_END_DECLS
+
+#endif /* __PYGI_INFO_H__ */
diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c
new file mode 100644
index 00000000..13ebe801
--- /dev/null
+++ b/gi/pygi-invoke.c
@@ -0,0 +1,1003 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org>
+ *
+ * pygi-invoke.c: main invocation function
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "pygi-invoke.h"
+
+struct invocation_state
+{
+ gboolean is_method;
+ gboolean is_constructor;
+
+ gsize n_args;
+ gsize n_in_args;
+ gsize n_out_args;
+ gsize n_backup_args;
+ Py_ssize_t n_py_args;
+ gsize n_aux_in_args;
+ gsize n_aux_out_args;
+ gsize n_return_values;
+
+ guint8 callback_index;
+ guint8 user_data_index;
+ guint8 destroy_notify_index;
+ PyGICClosure *closure;
+
+ glong error_arg_pos;
+
+ GIArgInfo **arg_infos;
+ GITypeInfo **arg_type_infos;
+ GITypeInfo *return_type_info;
+ GITypeTag return_type_tag;
+
+ GArgument **args;
+ gboolean *args_is_auxiliary;
+
+ GArgument *in_args;
+ GArgument *out_args;
+ GArgument *out_values;
+ GArgument *backup_args;
+ GArgument return_arg;
+
+ PyObject *return_value;
+};
+
+static void
+_initialize_invocation_state (struct invocation_state *state,
+ GIFunctionInfo *info,
+ PyObject *py_args)
+{
+ GIFunctionInfoFlags flags;
+
+ flags = g_function_info_get_flags (info);
+ state->is_method = (flags & GI_FUNCTION_IS_METHOD) != 0;
+ state->is_constructor = (flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0;
+
+ /* Count arguments. */
+ state->n_args = g_callable_info_get_n_args ( (GICallableInfo *) info);
+ state->n_in_args = 0;
+ state->n_out_args = 0;
+ state->n_backup_args = 0;
+ state->n_aux_in_args = 0;
+ state->n_aux_out_args = 0;
+
+ /* Check the argument count. */
+ state->n_py_args = PyTuple_Size (py_args);
+ g_assert (state->n_py_args >= 0);
+
+ state->error_arg_pos = -1;
+
+ state->arg_infos = g_slice_alloc0 (sizeof (gpointer) * state->n_args);
+ state->arg_type_infos = g_slice_alloc0 (sizeof (gpointer) * state->n_args);
+ state->args_is_auxiliary = g_slice_alloc0 (sizeof (gboolean) * state->n_args);
+
+ state->return_value = NULL;
+ state->closure = NULL;
+ state->return_type_info = NULL;
+ state->args = NULL;
+ state->in_args = NULL;
+ state->out_args = NULL;
+ state->out_values = NULL;
+ state->backup_args = NULL;
+}
+
+static gboolean
+_prepare_invocation_state (struct invocation_state *state,
+ GIFunctionInfo *function_info, PyObject *py_args)
+{
+ gsize i;
+
+ if (!_pygi_scan_for_callbacks (function_info,
+ state->is_method,
+ &state->callback_index, &state->user_data_index,
+ &state->destroy_notify_index))
+ return FALSE;
+
+ if (state->callback_index != G_MAXUINT8) {
+
+ if (!_pygi_create_callback (function_info,
+ state->is_method,
+ state->is_constructor,
+ state->n_args, state->n_py_args,
+ py_args, state->callback_index,
+ state->user_data_index,
+ state->destroy_notify_index, &state->closure))
+ return FALSE;
+
+ state->args_is_auxiliary[state->callback_index] = FALSE;
+ if (state->destroy_notify_index != G_MAXUINT8) {
+ state->args_is_auxiliary[state->destroy_notify_index] = TRUE;
+ state->n_aux_in_args += 1;
+ }
+ }
+
+ if (state->is_method) {
+ /* The first argument is the instance. */
+ state->n_in_args += 1;
+ }
+
+ /* We do a first (well, second) pass here over the function to scan for special cases.
+ * This is currently array+length combinations, GError and GValue.
+ */
+ for (i = 0; i < state->n_args; i++) {
+ GIDirection direction;
+ GITransfer transfer;
+ GITypeTag arg_type_tag;
+
+ state->arg_infos[i] = g_callable_info_get_arg ( (GICallableInfo *) function_info,
+ i);
+
+ state->arg_type_infos[i] = g_arg_info_get_type (state->arg_infos[i]);
+
+ direction = g_arg_info_get_direction (state->arg_infos[i]);
+ transfer = g_arg_info_get_ownership_transfer (state->arg_infos[i]);
+ arg_type_tag = g_type_info_get_tag (state->arg_type_infos[i]);
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
+ state->n_in_args += 1;
+ if (transfer == GI_TRANSFER_CONTAINER) {
+ state->n_backup_args += 1;
+ }
+ }
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
+ state->n_out_args += 1;
+ }
+
+ if (direction == GI_DIRECTION_INOUT && transfer == GI_TRANSFER_NOTHING) {
+ state->n_backup_args += 1;
+ }
+
+ switch (arg_type_tag) {
+ case GI_TYPE_TAG_ARRAY:
+ {
+ gint length_arg_pos;
+
+ length_arg_pos = g_type_info_get_array_length (state->arg_type_infos[i]);
+
+ if (state->is_method)
+ length_arg_pos--; // length_arg_pos refers to C args
+
+ if (length_arg_pos < 0) {
+ break;
+ }
+
+ g_assert (length_arg_pos < state->n_args);
+ state->args_is_auxiliary[length_arg_pos] = TRUE;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
+ state->n_aux_in_args += 1;
+ }
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
+ state->n_aux_out_args += 1;
+ }
+
+ break;
+ }
+ case GI_TYPE_TAG_ERROR:
+ g_warn_if_fail (state->error_arg_pos < 0);
+ state->error_arg_pos = i;
+ break;
+ default:
+ break;
+ }
+ }
+
+ state->return_type_info = g_callable_info_get_return_type ( (GICallableInfo *) function_info);
+ state->return_type_tag = g_type_info_get_tag (state->return_type_info);
+
+ if (state->return_type_tag == GI_TYPE_TAG_ARRAY) {
+ gint length_arg_pos;
+ length_arg_pos = g_type_info_get_array_length (state->return_type_info);
+
+ if (state->is_method)
+ length_arg_pos--; // length_arg_pos refers to C args
+
+ if (length_arg_pos >= 0) {
+ g_assert (length_arg_pos < state->n_args);
+ state->args_is_auxiliary[length_arg_pos] = TRUE;
+ state->n_aux_out_args += 1;
+ }
+ }
+
+ state->n_return_values = state->n_out_args - state->n_aux_out_args;
+ if (state->return_type_tag != GI_TYPE_TAG_VOID) {
+ state->n_return_values += 1;
+ }
+
+ {
+ gsize n_py_args_expected;
+ Py_ssize_t py_args_pos;
+
+ n_py_args_expected = state->n_in_args
+ + (state->is_constructor ? 1 : 0)
+ - state->n_aux_in_args
+ - (state->error_arg_pos >= 0 ? 1 : 0);
+
+ if (state->n_py_args != n_py_args_expected) {
+ PyErr_Format (PyExc_TypeError,
+ "%s() takes exactly %zd argument(s) (%zd given)",
+ g_base_info_get_name ( (GIBaseInfo *) function_info),
+ n_py_args_expected, state->n_py_args);
+ return FALSE;
+ }
+
+ /* Check argument typestate-> */
+ py_args_pos = 0;
+ if (state->is_constructor || state->is_method) {
+ py_args_pos += 1;
+ }
+
+ for (i = 0; i < state->n_args; i++) {
+ GIDirection direction;
+ GITypeTag type_tag;
+ PyObject *py_arg;
+ gint retval;
+ gboolean allow_none;
+
+ direction = g_arg_info_get_direction (state->arg_infos[i]);
+ type_tag = g_type_info_get_tag (state->arg_type_infos[i]);
+
+ if (direction == GI_DIRECTION_OUT
+ || state->args_is_auxiliary[i]
+ || type_tag == GI_TYPE_TAG_ERROR) {
+ continue;
+ }
+
+ g_assert (py_args_pos < state->n_py_args);
+ py_arg = PyTuple_GET_ITEM (py_args, py_args_pos);
+
+ allow_none = g_arg_info_may_be_null (state->arg_infos[i]);
+
+ retval = _pygi_g_type_info_check_object (state->arg_type_infos[i],
+ py_arg,
+ allow_none);
+
+ if (retval < 0) {
+ return FALSE;
+ } else if (!retval) {
+ _PyGI_ERROR_PREFIX ("argument %zd: ", py_args_pos);
+ return FALSE;
+ }
+
+ py_args_pos += 1;
+ }
+
+ g_assert (py_args_pos == state->n_py_args);
+ }
+
+ state->args = g_slice_alloc0 (sizeof (gpointer) * state->n_args);
+ state->in_args = g_slice_alloc0 (sizeof (GArgument) * state->n_in_args);
+ state->out_args = g_slice_alloc0 (sizeof (GArgument) * state->n_out_args);
+ state->out_values = g_slice_alloc0 (sizeof (GArgument) * state->n_out_args);
+ state->backup_args = g_slice_alloc0 (sizeof (GArgument) * state->n_backup_args);
+
+ /* Bind args so we can use an unique index. */
+ {
+ gsize in_args_pos;
+ gsize out_args_pos;
+
+ in_args_pos = state->is_method ? 1 : 0;
+ out_args_pos = 0;
+
+ for (i = 0; i < state->n_args; i++) {
+ GIDirection direction;
+ GIBaseInfo *info;
+ gboolean is_caller_allocates;
+
+ direction = g_arg_info_get_direction (state->arg_infos[i]);
+ is_caller_allocates = g_arg_info_is_caller_allocates (state->arg_infos[i]);
+
+ switch (direction) {
+ case GI_DIRECTION_IN:
+ g_assert (in_args_pos < state->n_in_args);
+ state->args[i] = &state->in_args[in_args_pos];
+ in_args_pos += 1;
+ break;
+ case GI_DIRECTION_INOUT:
+ g_assert (in_args_pos < state->n_in_args);
+ g_assert (out_args_pos < state->n_out_args);
+
+ state->in_args[in_args_pos].v_pointer = &state->out_values[out_args_pos];
+ in_args_pos += 1;
+ case GI_DIRECTION_OUT:
+ g_assert (out_args_pos < state->n_out_args);
+
+ /* caller allocates only applies to structures but GI has
+ * no way to denote that yet, so we only use caller allocates
+ * if we see a structure
+ */
+ if (is_caller_allocates) {
+ GITypeTag type_tag;
+
+ is_caller_allocates = FALSE;
+ type_tag = g_type_info_get_tag (state->arg_type_infos[i]);
+
+ if (type_tag == GI_TYPE_TAG_INTERFACE) {
+ GIInfoType info_type;
+
+ info = g_type_info_get_interface (state->arg_type_infos[i]);
+ g_assert (info != NULL);
+ info_type = g_base_info_get_type (info);
+
+ if (info_type == GI_INFO_TYPE_STRUCT)
+ is_caller_allocates = TRUE;
+ }
+ }
+
+ if (is_caller_allocates) {
+ gsize size;
+ gpointer value;
+
+ /* if caller allocates only use one level of indirection */
+ state->out_args[out_args_pos].v_pointer = NULL;
+ state->args[i] = &state->out_args[out_args_pos];
+
+ size = g_struct_info_get_size ( (GIStructInfo *) info);
+
+ state->args[i]->v_pointer = g_malloc0 (size);
+ } else {
+ state->out_args[out_args_pos].v_pointer = &state->out_values[out_args_pos];
+ state->out_values[out_args_pos].v_pointer = NULL;
+ state->args[i] = &state->out_values[out_args_pos];
+ }
+
+ out_args_pos += 1;
+ }
+ }
+
+ g_assert (in_args_pos == state->n_in_args);
+ g_assert (out_args_pos == state->n_out_args);
+ }
+
+ /* Convert the input arguments. */
+ {
+ Py_ssize_t py_args_pos;
+ gsize backup_args_pos;
+
+ py_args_pos = 0;
+ backup_args_pos = 0;
+
+ if (state->is_constructor) {
+ /* Skip the first argument. */
+ py_args_pos += 1;
+ } else if (state->is_method) {
+ /* Get the instance. */
+ GIBaseInfo *container_info;
+ GIInfoType container_info_type;
+ PyObject *py_arg;
+
+ container_info = g_base_info_get_container (function_info);
+ container_info_type = g_base_info_get_type (container_info);
+
+ g_assert (py_args_pos < state->n_py_args);
+ py_arg = PyTuple_GET_ITEM (py_args, py_args_pos);
+
+ switch (container_info_type) {
+ case GI_INFO_TYPE_UNION:
+ case GI_INFO_TYPE_STRUCT:
+ {
+ GType type;
+
+ type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) container_info);
+
+ if (g_type_is_a (type, G_TYPE_BOXED)) {
+ g_assert (state->n_in_args > 0);
+ state->in_args[0].v_pointer = pyg_boxed_get (py_arg, void);
+ } else if (g_type_is_a (type, G_TYPE_POINTER) || type == G_TYPE_NONE) {
+ g_assert (state->n_in_args > 0);
+ state->in_args[0].v_pointer = pyg_pointer_get (py_arg, void);
+ } else {
+ PyErr_Format (PyExc_TypeError, "unable to convert an instance of '%s'", g_type_name (type));
+ return FALSE;
+ }
+
+ break;
+ }
+ case GI_INFO_TYPE_OBJECT:
+ case GI_INFO_TYPE_INTERFACE:
+ g_assert (state->n_in_args > 0);
+ state->in_args[0].v_pointer = pygobject_get (py_arg);
+ break;
+ default:
+ /* Other types don't have methods. */
+ g_assert_not_reached();
+ }
+
+ py_args_pos += 1;
+ }
+
+ for (i = 0; i < state->n_args; i++) {
+ GIDirection direction;
+
+ if (i == state->callback_index) {
+ if (state->closure)
+ state->args[i]->v_pointer = state->closure->closure;
+ else
+ /* Some callbacks params accept NULL */
+ state->args[i]->v_pointer = NULL;
+ py_args_pos++;
+ continue;
+ } else if (i == state->user_data_index) {
+ state->args[i]->v_pointer = state->closure;
+ py_args_pos++;
+ continue;
+ } else if (i == state->destroy_notify_index) {
+ if (state->closure) {
+ /* No need to clean up if the callback is NULL */
+ PyGICClosure *destroy_notify = _pygi_destroy_notify_create();
+ state->args[i]->v_pointer = destroy_notify->closure;
+ }
+ continue;
+ }
+
+ if (state->args_is_auxiliary[i]) {
+ continue;
+ }
+
+ direction = g_arg_info_get_direction (state->arg_infos[i]);
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
+ PyObject *py_arg;
+ GITypeTag arg_type_tag;
+ GITransfer transfer;
+
+ arg_type_tag = g_type_info_get_tag (state->arg_type_infos[i]);
+
+ if (arg_type_tag == GI_TYPE_TAG_ERROR) {
+ GError **error;
+
+ error = g_slice_new (GError *);
+ *error = NULL;
+
+ state->args[i]->v_pointer = error;
+ continue;
+ }
+
+ transfer = g_arg_info_get_ownership_transfer (state->arg_infos[i]);
+
+ g_assert (py_args_pos < state->n_py_args);
+ py_arg = PyTuple_GET_ITEM (py_args, py_args_pos);
+
+ *state->args[i] = _pygi_argument_from_object (py_arg, state->arg_type_infos[i], transfer);
+
+ if (PyErr_Occurred()) {
+ /* TODO: release previous input arguments. */
+ return FALSE;
+ }
+
+ if (direction == GI_DIRECTION_INOUT && transfer == GI_TRANSFER_NOTHING) {
+ /* We need to keep a copy of the argument to be able to release it later. */
+ g_assert (backup_args_pos < state->n_backup_args);
+ state->backup_args[backup_args_pos] = *state->args[i];
+ backup_args_pos += 1;
+ } else if (transfer == GI_TRANSFER_CONTAINER) {
+ /* We need to keep a copy of the items to be able to release them later. */
+ switch (arg_type_tag) {
+ case GI_TYPE_TAG_ARRAY:
+ {
+ GArray *array;
+ gsize item_size;
+ GArray *new_array;
+
+ array = state->args[i]->v_pointer;
+
+ item_size = g_array_get_element_size (array);
+
+ new_array = g_array_sized_new (FALSE, FALSE, item_size, array->len);
+ g_array_append_vals (new_array, array->data, array->len);
+
+ g_assert (backup_args_pos < state->n_backup_args);
+ state->backup_args[backup_args_pos].v_pointer = new_array;
+
+ break;
+ }
+ case GI_TYPE_TAG_GLIST:
+ g_assert (backup_args_pos < state->n_backup_args);
+ state->backup_args[backup_args_pos].v_pointer = g_list_copy (state->args[i]->v_pointer);
+ break;
+ case GI_TYPE_TAG_GSLIST:
+ g_assert (backup_args_pos < state->n_backup_args);
+ state->backup_args[backup_args_pos].v_pointer = g_slist_copy (state->args[i]->v_pointer);
+ break;
+ case GI_TYPE_TAG_GHASH:
+ {
+ GHashTable *hash_table;
+ GList *keys;
+ GList *values;
+
+ hash_table = state->args[i]->v_pointer;
+
+ keys = g_hash_table_get_keys (hash_table);
+ values = g_hash_table_get_values (hash_table);
+
+ g_assert (backup_args_pos < state->n_backup_args);
+ state->backup_args[backup_args_pos].v_pointer = g_list_concat (keys, values);
+
+ break;
+ }
+ default:
+ g_warn_if_reached();
+ }
+
+ backup_args_pos += 1;
+ }
+
+ if (arg_type_tag == GI_TYPE_TAG_ARRAY) {
+ GArray *array;
+ gssize length_arg_pos;
+
+ array = state->args[i]->v_pointer;
+
+ length_arg_pos = g_type_info_get_array_length (state->arg_type_infos[i]);
+ if (state->is_method)
+ length_arg_pos--; // length_arg_pos refers to C args
+ if (length_arg_pos >= 0) {
+ int len = 0;
+ /* Set the auxiliary argument holding the length. */
+ if (array)
+ len = array->len;
+
+ state->args[length_arg_pos]->v_size = len;
+ }
+
+ /* Get rid of the GArray. */
+ if ( (array != NULL) &&
+ (g_type_info_get_array_type (state->arg_type_infos[i]) == GI_ARRAY_TYPE_C)) {
+ state->args[i]->v_pointer = array->data;
+
+ if (direction != GI_DIRECTION_INOUT || transfer != GI_TRANSFER_NOTHING) {
+ /* The array hasn't been referenced anywhere, so free it to avoid losing memory. */
+ g_array_free (array, FALSE);
+ }
+ }
+ }
+
+ py_args_pos += 1;
+ }
+ }
+
+ g_assert (py_args_pos == state->n_py_args);
+ g_assert (backup_args_pos == state->n_backup_args);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+_invoke_function (struct invocation_state *state,
+ GIFunctionInfo *function_info, PyObject *py_args)
+{
+ GError *error;
+ gint retval;
+
+ error = NULL;
+
+ retval = g_function_info_invoke ( (GIFunctionInfo *) function_info,
+ state->in_args, state->n_in_args, state->out_args, state->n_out_args, &state->return_arg, &error);
+ if (!retval) {
+ g_assert (error != NULL);
+ /* TODO: raise the right error, out of the error domain. */
+ PyErr_SetString (PyExc_RuntimeError, error->message);
+ g_error_free (error);
+
+ /* TODO: release input arguments. */
+
+ return FALSE;
+ }
+
+ if (state->error_arg_pos >= 0) {
+ GError **error;
+
+ error = state->args[state->error_arg_pos]->v_pointer;
+
+ if (*error != NULL) {
+ /* TODO: raise the right error, out of the error domain, if applicable. */
+ PyErr_SetString (PyExc_Exception, (*error)->message);
+ g_error_free (*error);
+
+ /* TODO: release input arguments. */
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+_process_invocation_state (struct invocation_state *state,
+ GIFunctionInfo *function_info, PyObject *py_args)
+{
+ gsize i;
+
+ /* Convert the return value. */
+ if (state->is_constructor) {
+ PyTypeObject *py_type;
+ GIBaseInfo *info;
+ GIInfoType info_type;
+ GITransfer transfer;
+
+ g_assert (state->n_py_args > 0);
+ py_type = (PyTypeObject *) PyTuple_GET_ITEM (py_args, 0);
+
+ info = g_type_info_get_interface (state->return_type_info);
+ g_assert (info != NULL);
+
+ info_type = g_base_info_get_type (info);
+
+ transfer = g_callable_info_get_caller_owns ( (GICallableInfo *) function_info);
+
+ switch (info_type) {
+ case GI_INFO_TYPE_UNION:
+ /* TODO */
+ PyErr_SetString (PyExc_NotImplementedError, "creating unions is not supported yet");
+ g_base_info_unref (info);
+ return FALSE;
+ case GI_INFO_TYPE_STRUCT:
+ {
+ GType type;
+
+ type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
+
+ if (g_type_is_a (type, G_TYPE_BOXED)) {
+ if (state->return_arg.v_pointer == NULL) {
+ PyErr_SetString (PyExc_TypeError, "constructor returned NULL");
+ break;
+ }
+ g_warn_if_fail (transfer == GI_TRANSFER_EVERYTHING);
+ state->return_value = _pygi_boxed_new (py_type, state->return_arg.v_pointer, transfer == GI_TRANSFER_EVERYTHING);
+ } else if (g_type_is_a (type, G_TYPE_POINTER) || type == G_TYPE_NONE) {
+ if (state->return_arg.v_pointer == NULL) {
+ PyErr_SetString (PyExc_TypeError, "constructor returned NULL");
+ break;
+ }
+
+ if (transfer != GI_TRANSFER_NOTHING)
+ g_warning ("Transfer mode should be set to None for "
+ "struct types as there is no way to free "
+ "them safely. Ignoring transfer mode "
+ "to prevent a potential invalid free. "
+ "This may cause a leak in your application.");
+
+ state->return_value = _pygi_struct_new (py_type, state->return_arg.v_pointer, FALSE);
+ } else {
+ PyErr_Format (PyExc_TypeError, "cannot create '%s' instances", py_type->tp_name);
+ g_base_info_unref (info);
+ return FALSE;
+ }
+
+ break;
+ }
+ case GI_INFO_TYPE_OBJECT:
+ if (state->return_arg.v_pointer == NULL) {
+ PyErr_SetString (PyExc_TypeError, "constructor returned NULL");
+ break;
+ }
+ state->return_value = pygobject_new (state->return_arg.v_pointer);
+ if (transfer == GI_TRANSFER_EVERYTHING) {
+ /* The new wrapper increased the reference count, so decrease it. */
+ g_object_unref (state->return_arg.v_pointer);
+ }
+ break;
+ default:
+ /* Other types don't have neither methods nor constructors. */
+ g_assert_not_reached();
+ }
+
+ g_base_info_unref (info);
+
+ if (state->return_value == NULL) {
+ /* TODO: release arguments. */
+ return FALSE;
+ }
+ } else {
+ GITransfer transfer;
+
+ if ( (state->return_type_tag == GI_TYPE_TAG_ARRAY) &&
+ (g_type_info_get_array_type (state->return_type_info) == GI_ARRAY_TYPE_C)) {
+ /* Create a #GArray. */
+ state->return_arg.v_pointer = _pygi_argument_to_array (&state->return_arg, state->args, state->return_type_info, state->is_method);
+ }
+
+ transfer = g_callable_info_get_caller_owns ( (GICallableInfo *) function_info);
+
+ state->return_value = _pygi_argument_to_object (&state->return_arg, state->return_type_info, transfer);
+ if (state->return_value == NULL) {
+ /* TODO: release argument. */
+ return FALSE;
+ }
+
+ _pygi_argument_release (&state->return_arg, state->return_type_info, transfer, GI_DIRECTION_OUT);
+
+ if (state->return_type_tag == GI_TYPE_TAG_ARRAY
+ && transfer == GI_TRANSFER_NOTHING) {
+ /* We created a #GArray, so free it. */
+ state->return_arg.v_pointer = g_array_free (state->return_arg.v_pointer, FALSE);
+ }
+ }
+
+ /* Convert output arguments and release arguments. */
+ {
+ gsize backup_args_pos;
+ gsize return_values_pos;
+
+ backup_args_pos = 0;
+ return_values_pos = 0;
+
+ if (state->n_return_values > 1) {
+ /* Return a tuple. */
+ PyObject *return_values;
+
+ return_values = PyTuple_New (state->n_return_values);
+ if (return_values == NULL) {
+ /* TODO: release arguments. */
+ return FALSE;
+ }
+
+ if (state->return_type_tag == GI_TYPE_TAG_VOID) {
+ /* The current return value is None. */
+ Py_DECREF (state->return_value);
+ } else {
+ /* Put the return value first. */
+ g_assert (state->return_value != NULL);
+ PyTuple_SET_ITEM (return_values, return_values_pos, state->return_value);
+ return_values_pos += 1;
+ }
+
+ state->return_value = return_values;
+ }
+
+ for (i = 0; i < state->n_args; i++) {
+ GIDirection direction;
+ GITypeTag type_tag;
+ GITransfer transfer;
+
+ if (state->args_is_auxiliary[i]) {
+ /* Auxiliary arguments are handled at the same time as their relatives. */
+ continue;
+ }
+
+ direction = g_arg_info_get_direction (state->arg_infos[i]);
+ transfer = g_arg_info_get_ownership_transfer (state->arg_infos[i]);
+
+ type_tag = g_type_info_get_tag (state->arg_type_infos[i]);
+
+ if ( (type_tag == GI_TYPE_TAG_ARRAY) &&
+ (g_type_info_get_array_type (state->arg_type_infos[i]) == GI_ARRAY_TYPE_C) &&
+ (direction != GI_DIRECTION_IN || transfer == GI_TRANSFER_NOTHING)) {
+ /* Create a #GArray. */
+ state->args[i]->v_pointer = _pygi_argument_to_array (state->args[i], state->args, state->arg_type_infos[i], state->is_method);
+ }
+
+ if (direction == GI_DIRECTION_INOUT || direction == GI_DIRECTION_OUT) {
+ /* Convert the argument. */
+ PyObject *obj;
+
+ obj = _pygi_argument_to_object (state->args[i], state->arg_type_infos[i], transfer);
+ if (obj == NULL) {
+ /* TODO: release arguments. */
+ return FALSE;
+ }
+
+ g_assert (return_values_pos < state->n_return_values);
+
+ if (state->n_return_values > 1) {
+ PyTuple_SET_ITEM (state->return_value, return_values_pos, obj);
+ } else {
+ /* The current return value is None. */
+ Py_DECREF (state->return_value);
+ state->return_value = obj;
+ }
+
+ return_values_pos += 1;
+ }
+
+ /* Release the argument. */
+
+ if ( (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ && transfer == GI_TRANSFER_CONTAINER) {
+ /* Release the items we kept in another container. */
+ switch (type_tag) {
+ case GI_TYPE_TAG_ARRAY:
+ case GI_TYPE_TAG_GLIST:
+ case GI_TYPE_TAG_GSLIST:
+ g_assert (backup_args_pos < state->n_backup_args);
+ _pygi_argument_release (&state->backup_args[backup_args_pos], state->arg_type_infos[i],
+ transfer, GI_DIRECTION_IN);
+ break;
+ case GI_TYPE_TAG_GHASH:
+ {
+ GITypeInfo *key_type_info;
+ GITypeInfo *value_type_info;
+ GList *item;
+ gsize length;
+ gsize j;
+
+ key_type_info = g_type_info_get_param_type (state->arg_type_infos[i], 0);
+ value_type_info = g_type_info_get_param_type (state->arg_type_infos[i], 1);
+
+ g_assert (backup_args_pos < state->n_backup_args);
+ item = state->backup_args[backup_args_pos].v_pointer;
+
+ length = g_list_length (item) / 2;
+
+ for (j = 0; j < length; j++, item = g_list_next (item)) {
+ _pygi_argument_release ( (GArgument *) &item->data, key_type_info,
+ GI_TRANSFER_NOTHING, GI_DIRECTION_IN);
+ }
+
+ for (j = 0; j < length; j++, item = g_list_next (item)) {
+ _pygi_argument_release ( (GArgument *) &item->data, value_type_info,
+ GI_TRANSFER_NOTHING, GI_DIRECTION_IN);
+ }
+
+ g_list_free (state->backup_args[backup_args_pos].v_pointer);
+
+ break;
+ }
+ default:
+ g_warn_if_reached();
+ }
+
+ if (direction == GI_DIRECTION_INOUT) {
+ /* Release the output argument. */
+ _pygi_argument_release (state->args[i], state->arg_type_infos[i], GI_TRANSFER_CONTAINER,
+ GI_DIRECTION_OUT);
+ }
+
+ backup_args_pos += 1;
+ } else if (direction == GI_DIRECTION_INOUT) {
+ if (transfer == GI_TRANSFER_NOTHING) {
+ g_assert (backup_args_pos < state->n_backup_args);
+ _pygi_argument_release (&state->backup_args[backup_args_pos], state->arg_type_infos[i],
+ GI_TRANSFER_NOTHING, GI_DIRECTION_IN);
+ backup_args_pos += 1;
+ }
+
+ _pygi_argument_release (state->args[i], state->arg_type_infos[i], transfer,
+ GI_DIRECTION_OUT);
+ } else {
+ _pygi_argument_release (state->args[i], state->arg_type_infos[i], transfer, direction);
+ }
+
+ if (type_tag == GI_TYPE_TAG_ARRAY
+ && (direction != GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)) {
+ /* We created a #GArray and it has not been released above, so free it. */
+ state->args[i]->v_pointer = g_array_free (state->args[i]->v_pointer, FALSE);
+ }
+ }
+
+ g_assert (state->n_return_values <= 1 || return_values_pos == state->n_return_values);
+ g_assert (backup_args_pos == state->n_backup_args);
+ }
+
+ return TRUE;
+}
+
+static void
+_free_invocation_state (struct invocation_state *state)
+{
+ gsize i;
+
+ if (state->return_type_info != NULL) {
+ g_base_info_unref ( (GIBaseInfo *) state->return_type_info);
+ }
+
+ if (state->closure != NULL) {
+ if (state->closure->scope == GI_SCOPE_TYPE_CALL)
+ _pygi_invoke_closure_free (state->closure);
+ }
+
+ for (i = 0; i < state->n_args; i++) {
+
+ /* check for caller-allocated values we need to free */
+ if (g_arg_info_is_caller_allocates (state->arg_infos[i])) {
+ GIBaseInfo *info;
+ GIInfoType info_type;
+
+ info = g_type_info_get_interface (state->arg_type_infos[i]);
+ g_assert (info != NULL);
+ info_type = g_base_info_get_type (info);
+
+ /* caller-allocates applies only to structs right now
+ * the GI scanner is overzealous when marking parameters
+ * as caller-allocates, so we only free if this was a struct
+ */
+ if (info_type == GI_INFO_TYPE_STRUCT) {
+ /* special case GValues so we make sure to unset them */
+ if (g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info) == G_TYPE_VALUE) {
+ g_value_unset ( (GValue *) state->args[i]);
+ }
+
+ g_free (state->args[i]);
+ }
+ }
+
+ if (state->arg_type_infos[i] != NULL)
+ g_base_info_unref ( (GIBaseInfo *) state->arg_type_infos[i]);
+ if (state->arg_infos[i] != NULL)
+ g_base_info_unref ( (GIBaseInfo *) state->arg_infos[i]);
+ }
+
+ if (state->arg_infos != NULL) {
+ g_slice_free1 (sizeof (gpointer) * state->n_args, state->arg_infos);
+ }
+
+ if (state->arg_type_infos != NULL) {
+ g_slice_free1 (sizeof (gpointer) * state->n_args, state->arg_type_infos);
+ }
+
+ if (state->args != NULL) {
+ g_slice_free1 (sizeof (gpointer) * state->n_args, state->args);
+ }
+
+ if (state->args_is_auxiliary != NULL) {
+ g_slice_free1 (sizeof (gboolean) * state->n_args, state->args_is_auxiliary);
+ }
+
+ if (state->in_args != NULL) {
+ g_slice_free1 (sizeof (GArgument) * state->n_in_args, state->in_args);
+ }
+
+ if (state->out_args != NULL) {
+ g_slice_free1 (sizeof (GArgument) * state->n_out_args, state->out_args);
+ }
+
+ if (state->out_values != NULL) {
+ g_slice_free1 (sizeof (GArgument) * state->n_out_args, state->out_values);
+ }
+
+ if (state->backup_args != NULL) {
+ g_slice_free1 (sizeof (GArgument) * state->n_backup_args, state->backup_args);
+ }
+
+ if (PyErr_Occurred()) {
+ Py_CLEAR (state->return_value);
+ }
+}
+
+
+PyObject *
+_wrap_g_function_info_invoke (PyGIBaseInfo *self, PyObject *py_args)
+{
+ struct invocation_state state;
+
+ _initialize_invocation_state (&state, self->info, py_args);
+
+ if (!_prepare_invocation_state (&state, self->info, py_args)) {
+ _free_invocation_state (&state);
+ return NULL;
+ }
+
+ if (!_invoke_function (&state, self->info, py_args)) {
+ _free_invocation_state (&state);
+ return NULL;
+ }
+
+ if (!_process_invocation_state (&state, self->info, py_args)) {
+ _free_invocation_state (&state);
+ return NULL;
+ }
+
+ return state.return_value;
+}
+
diff --git a/gi/pygi-invoke.h b/gi/pygi-invoke.h
new file mode 100644
index 00000000..0d07b21a
--- /dev/null
+++ b/gi/pygi-invoke.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef __PYGI_INVOKE_H__
+#define __PYGI_INVOKE_H__
+
+#include <Python.h>
+
+#include <girepository.h>
+
+#include "pygi-private.h"
+
+G_BEGIN_DECLS
+
+PyObject *_wrap_g_function_info_invoke (PyGIBaseInfo *self, PyObject *py_args);
+
+G_END_DECLS
+
+#endif /* __PYGI_INVOKE_H__ */
diff --git a/gi/pygi-private.h b/gi/pygi-private.h
new file mode 100644
index 00000000..0ff5df7e
--- /dev/null
+++ b/gi/pygi-private.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ */
+#ifndef __PYGI_PRIVATE_H__
+#define __PYGI_PRIVATE_H__
+
+#ifdef __PYGI_H__
+# error "Import pygi.h or pygi-private.h, but not both"
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Python.h>
+
+#include "pygi.h"
+
+#include "pygobject-external.h"
+
+#include "pygi-repository.h"
+#include "pygi-info.h"
+#include "pygi-struct.h"
+#include "pygi-boxed.h"
+#include "pygi-argument.h"
+#include "pygi-type.h"
+#include "pygi-foreign.h"
+#include "pygi-closure.h"
+#include "pygi-callbacks.h"
+#include "pygi-invoke.h"
+
+G_BEGIN_DECLS
+
+#define _PyGI_ERROR_PREFIX(format, ...) G_STMT_START { \
+ PyObject *py_error_prefix; \
+ py_error_prefix = PyString_FromFormat(format, ## __VA_ARGS__); \
+ if (py_error_prefix != NULL) { \
+ PyObject *py_error_type, *py_error_value, *py_error_traceback; \
+ PyErr_Fetch(&py_error_type, &py_error_value, &py_error_traceback); \
+ if (PyString_Check(py_error_value)) { \
+ PyString_ConcatAndDel(&py_error_prefix, py_error_value); \
+ if (py_error_prefix != NULL) { \
+ py_error_value = py_error_prefix; \
+ } \
+ } \
+ PyErr_Restore(py_error_type, py_error_value, py_error_traceback); \
+ } \
+} G_STMT_END
+
+/* Redefine g_array_index because we want it to return the i-th element, casted
+ * to the type t, of the array a, and not the i-th element of the array a
+ * casted to the type t. */
+#define _g_array_index(a,t,i) \
+ *(t *)((a)->data + g_array_get_element_size(a) * (i))
+
+
+G_END_DECLS
+
+#endif /* __PYGI_PRIVATE_H__ */
diff --git a/gi/pygi-repository.c b/gi/pygi-repository.c
new file mode 100644
index 00000000..783b4aa2
--- /dev/null
+++ b/gi/pygi-repository.c
@@ -0,0 +1,238 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org>
+ *
+ * pygi-repository.c: GIRepository wrapper.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "pygi-private.h"
+
+PyObject *PyGIRepositoryError;
+
+static PyMethodDef _PyGIRepository_methods[];
+
+PyTypeObject PyGIRepository_Type = {
+ PyObject_HEAD_INIT (NULL)
+ 0,
+ "gi.Repository", /* tp_name */
+ sizeof (PyGIRepository), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor) NULL, /* tp_dealloc */
+ (printfunc) NULL, /* tp_print */
+ (getattrfunc) NULL, /* tp_getattr */
+ (setattrfunc) NULL, /* tp_setattr */
+ (cmpfunc) NULL, /* tp_compare */
+ (reprfunc) NULL, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ (hashfunc) NULL, /* tp_hash */
+ (ternaryfunc) NULL, /* tp_call */
+ (reprfunc) NULL, /* tp_str */
+ (getattrofunc) NULL, /* tp_getattro */
+ (setattrofunc) NULL, /* tp_setattro */
+ NULL, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ NULL, /* tp_doc */
+ (traverseproc) NULL, /* tp_traverse */
+ (inquiry) NULL, /* tp_clear */
+ (richcmpfunc) NULL, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc) NULL, /* tp_iter */
+ (iternextfunc) NULL, /* tp_iternext */
+ _PyGIRepository_methods, /* tp_methods */
+};
+
+static PyObject *
+_wrap_g_irepository_get_default (PyObject *self)
+{
+ static PyGIRepository *repository = NULL;
+
+ if (!repository) {
+ repository = (PyGIRepository *) PyObject_New (PyGIRepository, &PyGIRepository_Type);
+ if (repository == NULL) {
+ return NULL;
+ }
+
+ repository->repository = g_irepository_get_default();
+ }
+
+ Py_INCREF ( (PyObject *) repository);
+ return (PyObject *) repository;
+}
+
+static PyObject *
+_wrap_g_irepository_require (PyGIRepository *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ static char *kwlist[] = { "namespace", "version", "lazy", NULL };
+
+ const char *namespace_;
+ const char *version = NULL;
+ PyObject *lazy = NULL;
+ GIRepositoryLoadFlags flags = 0;
+ GTypelib *typelib;
+ GError *error;
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s|sO:Repository.require",
+ kwlist, &namespace_, &version, &lazy)) {
+ return NULL;
+ }
+
+ if (lazy != NULL && PyObject_IsTrue (lazy)) {
+ flags |= G_IREPOSITORY_LOAD_FLAG_LAZY;
+ }
+
+ error = NULL;
+ typelib = g_irepository_require (self->repository, namespace_, version, flags, &error);
+ if (error != NULL) {
+ PyErr_SetString (PyGIRepositoryError, error->message);
+ g_error_free (error);
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+_wrap_g_irepository_find_by_name (PyGIRepository *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ static char *kwlist[] = { "namespace", "name", NULL };
+
+ const char *namespace_;
+ const char *name;
+ GIBaseInfo *info;
+ PyObject *py_info;
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "ss:Repository.find_by_name", kwlist, &namespace_, &name)) {
+ return NULL;
+ }
+
+ info = g_irepository_find_by_name (self->repository, namespace_, name);
+ if (info == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ py_info = _pygi_info_new (info);
+
+ g_base_info_unref (info);
+
+ return py_info;
+}
+
+static PyObject *
+_wrap_g_irepository_get_infos (PyGIRepository *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ static char *kwlist[] = { "namespace", NULL };
+
+ const char *namespace_;
+ gssize n_infos;
+ PyObject *infos;
+ gssize i;
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s:Repository.get_infos",
+ kwlist, &namespace_)) {
+ return NULL;
+ }
+
+ n_infos = g_irepository_get_n_infos (self->repository, namespace_);
+ if (n_infos < 0) {
+ PyErr_Format (PyExc_RuntimeError, "Namespace '%s' not loaded", namespace_);
+ return NULL;
+ }
+
+ infos = PyTuple_New (n_infos);
+
+ for (i = 0; i < n_infos; i++) {
+ GIBaseInfo *info;
+ PyObject *py_info;
+
+ info = g_irepository_get_info (self->repository, namespace_, i);
+ g_assert (info != NULL);
+
+ py_info = _pygi_info_new (info);
+
+ g_base_info_unref (info);
+
+ if (py_info == NULL) {
+ Py_CLEAR (infos);
+ break;
+ }
+
+ PyTuple_SET_ITEM (infos, i, py_info);
+ }
+
+ return infos;
+}
+
+static PyObject *
+_wrap_g_irepository_get_typelib_path (PyGIRepository *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ static char *kwlist[] = { "namespace", NULL };
+ const char *namespace_;
+ const gchar *typelib_path;
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "s:Repository.get_typelib_path", kwlist, &namespace_)) {
+ return NULL;
+ }
+
+ typelib_path = g_irepository_get_typelib_path (self->repository, namespace_);
+ if (typelib_path == NULL) {
+ PyErr_Format (PyExc_RuntimeError, "Namespace '%s' not loaded", namespace_);
+ return NULL;
+ }
+
+ return PyString_FromString (typelib_path);
+}
+
+static PyMethodDef _PyGIRepository_methods[] = {
+ { "get_default", (PyCFunction) _wrap_g_irepository_get_default, METH_STATIC | METH_NOARGS },
+ { "require", (PyCFunction) _wrap_g_irepository_require, METH_VARARGS | METH_KEYWORDS },
+ { "get_infos", (PyCFunction) _wrap_g_irepository_get_infos, METH_VARARGS | METH_KEYWORDS },
+ { "find_by_name", (PyCFunction) _wrap_g_irepository_find_by_name, METH_VARARGS | METH_KEYWORDS },
+ { "get_typelib_path", (PyCFunction) _wrap_g_irepository_get_typelib_path, METH_VARARGS | METH_KEYWORDS },
+ { NULL, NULL, 0 }
+};
+
+void
+_pygi_repository_register_types (PyObject *m)
+{
+ PyGIRepository_Type.ob_type = &PyType_Type;
+ if (PyType_Ready (&PyGIRepository_Type)) {
+ return;
+ }
+ if (PyModule_AddObject (m, "Repository", (PyObject *) &PyGIRepository_Type)) {
+ return;
+ }
+
+ PyGIRepositoryError = PyErr_NewException ("gi.RepositoryError", NULL, NULL);
+ if (PyModule_AddObject (m, "RepositoryError", PyGIRepositoryError)) {
+ return;
+ }
+}
+
diff --git a/gi/pygi-repository.h b/gi/pygi-repository.h
new file mode 100644
index 00000000..d8eb8cfd
--- /dev/null
+++ b/gi/pygi-repository.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef __PYGI_REPOSITORY_H__
+#define __PYGI_REPOSITORY_H__
+
+#include <Python.h>
+
+G_BEGIN_DECLS
+
+/* Private */
+
+extern PyTypeObject PyGIRepository_Type;
+
+extern PyObject *PyGIRepositoryError;
+
+void _pygi_repository_register_types (PyObject *m);
+
+G_END_DECLS
+
+#endif /* __PYGI_REPOSITORY_H__ */
diff --git a/gi/pygi-struct.c b/gi/pygi-struct.c
new file mode 100644
index 00000000..2f1ce42c
--- /dev/null
+++ b/gi/pygi-struct.c
@@ -0,0 +1,169 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2009 Simon van der Linden <svdlinden@src.gnome.org>
+ *
+ * pygi-struct.c: wrapper to handle non-registered structures.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "pygi-private.h"
+
+#include <pygobject.h>
+#include <girepository.h>
+
+static void
+_struct_dealloc (PyGIStruct *self)
+{
+ PyObject_GC_UnTrack ( (PyObject *) self);
+
+ PyObject_ClearWeakRefs ( (PyObject *) self);
+
+ if (self->free_on_dealloc) {
+ g_free ( ( (PyGPointer *) self)->pointer);
+ }
+
+ ( (PyGPointer *) self)->ob_type->tp_free ( (PyObject *) self);
+}
+
+static PyObject *
+_struct_new (PyTypeObject *type,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ static char *kwlist[] = { NULL };
+
+ GIBaseInfo *info;
+ gboolean is_simple;
+ gsize size;
+ gpointer pointer;
+ PyObject *self = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs, "", kwlist)) {
+ return NULL;
+ }
+
+ info = _pygi_object_get_gi_info ( (PyObject *) type, &PyGIStructInfo_Type);
+ if (info == NULL) {
+ if (PyErr_ExceptionMatches (PyExc_AttributeError)) {
+ PyErr_Format (PyExc_TypeError, "missing introspection information");
+ }
+ return NULL;
+ }
+
+ size = g_struct_info_get_size ( (GIStructInfo *) info);
+ pointer = g_try_malloc0 (size);
+ if (pointer == NULL) {
+ PyErr_NoMemory();
+ goto out;
+ }
+
+ self = _pygi_struct_new (type, pointer, TRUE);
+ if (self == NULL) {
+ g_free (pointer);
+ }
+
+out:
+ g_base_info_unref (info);
+
+ return (PyObject *) self;
+}
+
+static int
+_struct_init (PyObject *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ /* Don't call PyGPointer's init, which raises an exception. */
+ return 0;
+}
+
+
+PyTypeObject PyGIStruct_Type = {
+ PyObject_HEAD_INIT (NULL)
+ 0,
+ "gi.Struct", /* tp_name */
+ sizeof (PyGIStruct), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor) _struct_dealloc, /* tp_dealloc */
+ (printfunc) NULL, /* tp_print */
+ (getattrfunc) NULL, /* tp_getattr */
+ (setattrfunc) NULL, /* tp_setattr */
+ (cmpfunc) NULL, /* tp_compare */
+ (reprfunc) NULL, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ (hashfunc) NULL, /* tp_hash */
+ (ternaryfunc) NULL, /* tp_call */
+ (reprfunc) NULL, /* tp_str */
+ (getattrofunc) NULL, /* tp_getattro */
+ (setattrofunc) NULL, /* tp_setattro */
+ NULL, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ NULL, /* tp_doc */
+ (traverseproc) NULL, /* tp_traverse */
+ (inquiry) NULL, /* tp_clear */
+ (richcmpfunc) NULL, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc) NULL, /* tp_iter */
+ (iternextfunc) NULL, /* tp_iternext */
+ NULL, /* tp_methods */
+ NULL, /* tp_members */
+ NULL, /* tp_getset */
+ (PyTypeObject *) NULL, /* tp_base */
+};
+
+PyObject *
+_pygi_struct_new (PyTypeObject *type,
+ gpointer pointer,
+ gboolean free_on_dealloc)
+{
+ PyGIStruct *self;
+ GType g_type;
+
+ if (!PyType_IsSubtype (type, &PyGIStruct_Type)) {
+ PyErr_SetString (PyExc_TypeError, "must be a subtype of gi.Struct");
+ return NULL;
+ }
+
+ self = (PyGIStruct *) type->tp_alloc (type, 0);
+ if (self == NULL) {
+ return NULL;
+ }
+
+ g_type = pyg_type_from_object ( (PyObject *) type);
+
+ ( (PyGPointer *) self)->gtype = g_type;
+ ( (PyGPointer *) self)->pointer = pointer;
+ self->free_on_dealloc = free_on_dealloc;
+
+ return (PyObject *) self;
+}
+
+void
+_pygi_struct_register_types (PyObject *m)
+{
+ PyGIStruct_Type.ob_type = &PyType_Type;
+ PyGIStruct_Type.tp_base = &PyGPointer_Type;
+ PyGIStruct_Type.tp_new = (newfunc) _struct_new;
+ PyGIStruct_Type.tp_init = (initproc) _struct_init;
+ if (PyType_Ready (&PyGIStruct_Type))
+ return;
+ if (PyModule_AddObject (m, "Struct", (PyObject *) &PyGIStruct_Type))
+ return;
+}
diff --git a/gi/pygi-struct.h b/gi/pygi-struct.h
new file mode 100644
index 00000000..963d05a3
--- /dev/null
+++ b/gi/pygi-struct.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2009 Simon van der Linden <svdlinden@src.gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef __PYGI_STRUCT_H__
+#define __PYGI_STRUCT_H__
+
+#include <Python.h>
+
+G_BEGIN_DECLS
+
+extern PyTypeObject PyGIStruct_Type;
+
+PyObject *
+_pygi_struct_new (PyTypeObject *type,
+ gpointer pointer,
+ gboolean free_on_dealloc);
+
+void _pygi_struct_register_types (PyObject *m);
+
+G_END_DECLS
+
+#endif /* __PYGI_STRUCT_H__ */
diff --git a/gi/pygi-type.c b/gi/pygi-type.c
new file mode 100644
index 00000000..410efe19
--- /dev/null
+++ b/gi/pygi-type.c
@@ -0,0 +1,96 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2009 Simon van der Linden <svdlinden@src.gnome.org>
+ *
+ * pygi-type.c: helpers to lookup Python wrappers from GType and GIBaseInfo.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "pygi-private.h"
+
+
+PyObject *
+_pygi_type_import_by_gi_info (GIBaseInfo *info)
+{
+ const gchar *namespace_;
+ const gchar *name;
+ gchar *module_name;
+ PyObject *py_module;
+ PyObject *py_object;
+
+ namespace_ = g_base_info_get_namespace (info);
+ name = g_base_info_get_name (info);
+
+ module_name = g_strconcat ("gi.repository.", namespace_, NULL);
+
+ py_module = PyImport_ImportModule (module_name);
+
+ g_free (module_name);
+
+ if (py_module == NULL) {
+ return NULL;
+ }
+
+ py_object = PyObject_GetAttrString (py_module, name);
+
+ Py_DECREF (py_module);
+
+ return py_object;
+}
+
+PyObject *
+pygi_type_import_by_g_type (GType g_type)
+{
+ GIRepository *repository;
+ GIBaseInfo *info;
+ PyObject *type;
+
+ repository = g_irepository_get_default();
+
+ info = g_irepository_find_by_gtype (repository, g_type);
+ if (info == NULL) {
+ return NULL;
+ }
+
+ type = _pygi_type_import_by_gi_info (info);
+ g_base_info_unref (info);
+
+ return type;
+}
+
+PyObject *
+_pygi_type_get_from_g_type (GType g_type)
+{
+ PyObject *py_g_type;
+ PyObject *py_type;
+
+ py_g_type = pyg_type_wrapper_new (g_type);
+ if (py_g_type == NULL) {
+ return NULL;
+ }
+
+ py_type = PyObject_GetAttrString (py_g_type, "pytype");
+ if (py_type == Py_None) {
+ py_type = pygi_type_import_by_g_type (g_type);
+ }
+
+ Py_DECREF (py_g_type);
+
+ return py_type;
+}
+
diff --git a/gi/pygi-type.h b/gi/pygi-type.h
new file mode 100644
index 00000000..19d07dca
--- /dev/null
+++ b/gi/pygi-type.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2009 Simon van der Linden <svdlinden@src.gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef __PYGI_TYPE_H__
+#define __PYGI_TYPE_H__
+
+#include <Python.h>
+
+G_BEGIN_DECLS
+
+/* Public */
+
+PyObject *pygi_type_import_by_g_type (GType g_type);
+
+
+/* Private */
+
+PyObject *_pygi_type_import_by_gi_info (GIBaseInfo *info);
+
+PyObject *_pygi_type_get_from_g_type (GType g_type);
+
+
+G_END_DECLS
+
+#endif /* __PYGI_TYPE_H__ */
diff --git a/gi/pygi.h b/gi/pygi.h
new file mode 100644
index 00000000..a9c46653
--- /dev/null
+++ b/gi/pygi.h
@@ -0,0 +1,105 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef __PYGI_H__
+#define __PYGI_H__
+
+#include <pygobject.h>
+
+#include <girepository.h>
+
+G_BEGIN_DECLS
+
+typedef struct {
+ PyObject_HEAD
+ GIRepository *repository;
+} PyGIRepository;
+
+typedef struct {
+ PyObject_HEAD
+ GIBaseInfo *info;
+ PyObject *inst_weakreflist;
+} PyGIBaseInfo;
+
+typedef struct {
+ PyGPointer base;
+ gboolean free_on_dealloc;
+} PyGIStruct;
+
+typedef struct {
+ PyGBoxed base;
+ gboolean slice_allocated;
+ gsize size;
+} PyGIBoxed;
+
+
+struct PyGI_API {
+ PyObject* (*type_import_by_g_type) (GType g_type);
+};
+
+
+#ifndef __PYGI_PRIVATE_H__
+
+static struct PyGI_API *PyGI_API = NULL;
+
+#define pygi_type_import_by_g_type (PyGI_API->type_import_by_g_type)
+
+
+static int
+pygi_import (void)
+{
+ PyObject *module;
+ PyObject *api;
+
+ if (PyGI_API != NULL) {
+ return 1;
+ }
+
+ module = PyImport_ImportModule ("gi");
+ if (module == NULL) {
+ return -1;
+ }
+
+ api = PyObject_GetAttrString (module, "_API");
+ if (api == NULL) {
+ Py_DECREF (module);
+ return -1;
+ }
+ if (!PyCObject_Check (api)) {
+ Py_DECREF (module);
+ Py_DECREF (api);
+ PyErr_Format (PyExc_TypeError, "gi._API must be cobject, not %s",
+ api->ob_type->tp_name);
+ return -1;
+ }
+
+ PyGI_API = (struct PyGI_API *) PyCObject_AsVoidPtr (api);
+
+ Py_DECREF (api);
+
+ return 0;
+}
+
+#endif /* __PYGI_PRIVATE_H__ */
+
+G_END_DECLS
+
+#endif /* __PYGI_H__ */
diff --git a/gi/pygobject-external.h b/gi/pygobject-external.h
new file mode 100644
index 00000000..00b8b6f7
--- /dev/null
+++ b/gi/pygobject-external.h
@@ -0,0 +1,83 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2009 Simon van der Linden <svdlinden@src.gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef __PYGOBJECT_EXTERN_H__
+#define __PYGOBJECT_EXTERN_H__
+
+#include <Python.h>
+
+G_BEGIN_DECLS
+
+static PyTypeObject *_PyGObject_Type;
+static PyTypeObject *_PyGTypeWrapper_Type;
+
+#define PyGObject_Type (*_PyGObject_Type)
+#define PyGTypeWrapper_Type (*_PyGTypeWrapper_Type)
+
+__attribute__ ( (unused))
+static int
+_pygobject_import (void)
+{
+ static gboolean imported = FALSE;
+ PyObject *from_list;
+ PyObject *module;
+ int retval = 0;
+
+ if (imported) {
+ return 1;
+ }
+
+ from_list = Py_BuildValue ("(ss)", "GObject", "GTypeWrapper");
+ if (from_list == NULL) {
+ return -1;
+ }
+
+ module = PyImport_ImportModuleEx ("gobject", NULL, NULL, from_list);
+
+ Py_DECREF (from_list);
+
+ if (module == NULL) {
+ return -1;
+ }
+
+ _PyGObject_Type = (PyTypeObject *) PyObject_GetAttrString (module, "GObject");
+ if (_PyGObject_Type == NULL) {
+ retval = -1;
+ goto out;
+ }
+
+ _PyGTypeWrapper_Type = (PyTypeObject *) PyObject_GetAttrString (module, "GType");
+ if (_PyGTypeWrapper_Type == NULL) {
+ retval = -1;
+ goto out;
+ }
+
+ imported = TRUE;
+
+out:
+ Py_DECREF (module);
+
+ return retval;
+}
+
+G_END_DECLS
+
+#endif /* __PYGOBJECT_EXTERN_H__ */
diff --git a/gi/repository/Makefile.am b/gi/repository/Makefile.am
new file mode 100644
index 00000000..c9138ce9
--- /dev/null
+++ b/gi/repository/Makefile.am
@@ -0,0 +1,8 @@
+PLATFORM_VERSION = 2.0
+
+pkgpyexecdir = $(pyexecdir)/gtk-2.0/gi
+
+pygirepositorydir = $(pkgpyexecdir)/repository
+pygirepository_PYTHON = \
+ __init__.py
+
diff --git a/gi/repository/__init__.py b/gi/repository/__init__.py
new file mode 100644
index 00000000..5c5552ac
--- /dev/null
+++ b/gi/repository/__init__.py
@@ -0,0 +1,30 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2009 Johan Dahlin <johan@gnome.org>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+from __future__ import absolute_import
+
+import sys
+
+from ..importer import DynamicImporter
+
+sys.meta_path.append(DynamicImporter('gi.repository'))
+
+del DynamicImporter
+del sys
diff --git a/gi/tests/Makefile.am b/gi/tests/Makefile.am
new file mode 100644
index 00000000..f8a65dc5
--- /dev/null
+++ b/gi/tests/Makefile.am
@@ -0,0 +1,22 @@
+noinst_PYTHON = \
+ runtests.py \
+ test_everything.py \
+ test_gi.py \
+ test_overrides.py
+
+check-local:
+ LD_LIBRARY_PATH=$(srcdir)/.libs$${LD_LIBRARY_PATH:+:$$LD_LIBRARY_PATH} \
+ $(EXEC_NAME) $(PYTHON) $(srcdir)/runtests.py $(TEST_NAMES)
+
+check.gdb:
+ EXEC_NAME="gdb --args" $(MAKE) check
+
+%.gdb:
+ EXEC_NAME="gdb --args" TEST_NAMES=$* $(MAKE) check
+
+check.valgrind:
+ EXEC_NAME="valgrind" $(MAKE) check
+
+%.valgrind:
+ EXEC_NAME="valgrind" TEST_NAMES=$* $(MAKE) check
+
diff --git a/gi/tests/runtests.py b/gi/tests/runtests.py
new file mode 100644
index 00000000..ba6942cb
--- /dev/null
+++ b/gi/tests/runtests.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+import sys
+import unittest
+import glob
+
+
+loader = unittest.TestLoader()
+
+if len(sys.argv) > 1:
+ names = sys.argv[1:]
+ suite = loader.loadTestsFromNames(names)
+else:
+ names = []
+ for filename in glob.iglob("test_*.py"):
+ names.append(filename[:-3])
+ suite = loader.loadTestsFromNames(names)
+
+runner = unittest.TextTestRunner(verbosity=2)
+runner.run(suite)
+
diff --git a/gi/tests/test_everything.py b/gi/tests/test_everything.py
new file mode 100644
index 00000000..36de1e39
--- /dev/null
+++ b/gi/tests/test_everything.py
@@ -0,0 +1,270 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+
+import unittest
+
+import sys
+sys.path.insert(0, "../")
+from sys import getrefcount
+
+import cairo
+
+from gi.repository import GObject
+from gi.repository import Everything
+
+class TestEverything(unittest.TestCase):
+
+ def test_cairo_context(self):
+ context = Everything.test_cairo_context_full_return()
+ self.assertTrue(isinstance(context, cairo.Context))
+
+ surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
+ context = cairo.Context(surface)
+ Everything.test_cairo_context_none_in(context)
+
+ def test_cairo_surface(self):
+ surface = Everything.test_cairo_surface_none_return()
+ self.assertTrue(isinstance(surface, cairo.ImageSurface))
+ self.assertTrue(isinstance(surface, cairo.Surface))
+ self.assertEquals(surface.get_format(), cairo.FORMAT_ARGB32)
+ self.assertEquals(surface.get_width(), 10)
+ self.assertEquals(surface.get_height(), 10)
+
+ surface = Everything.test_cairo_surface_full_return()
+ self.assertTrue(isinstance(surface, cairo.ImageSurface))
+ self.assertTrue(isinstance(surface, cairo.Surface))
+ self.assertEquals(surface.get_format(), cairo.FORMAT_ARGB32)
+ self.assertEquals(surface.get_width(), 10)
+ self.assertEquals(surface.get_height(), 10)
+
+ surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
+ Everything.test_cairo_surface_none_in(surface)
+
+ surface = Everything.test_cairo_surface_full_out()
+ self.assertTrue(isinstance(surface, cairo.ImageSurface))
+ self.assertTrue(isinstance(surface, cairo.Surface))
+ self.assertEquals(surface.get_format(), cairo.FORMAT_ARGB32)
+ self.assertEquals(surface.get_width(), 10)
+ self.assertEquals(surface.get_height(), 10)
+
+ def test_floating(self):
+ Everything.TestFloating()
+
+ def test_caller_allocates(self):
+ struct_a = Everything.TestStructA()
+ struct_a.some_int = 10
+ struct_a.some_int8 = 21
+ struct_a.some_double = 3.14
+ struct_a.some_enum = Everything.TestEnum.VALUE3
+
+ struct_a_clone = struct_a.clone()
+ self.assertTrue(struct_a != struct_a_clone)
+ self.assertEquals(struct_a.some_int, struct_a_clone.some_int)
+ self.assertEquals(struct_a.some_int8, struct_a_clone.some_int8)
+ self.assertEquals(struct_a.some_double, struct_a_clone.some_double)
+ self.assertEquals(struct_a.some_enum, struct_a_clone.some_enum)
+
+ struct_b = Everything.TestStructB()
+ struct_b.some_int8 = 8
+ struct_b.nested_a.some_int = 20
+ struct_b.nested_a.some_int8 = 12
+ struct_b.nested_a.some_double = 333.3333
+ struct_b.nested_a.some_enum = Everything.TestEnum.VALUE2
+
+ struct_b_clone = struct_b.clone()
+ self.assertTrue(struct_b != struct_b_clone)
+ self.assertEquals(struct_b.some_int8, struct_b_clone.some_int8)
+ self.assertEquals(struct_b.nested_a.some_int, struct_b_clone.nested_a.some_int)
+ self.assertEquals(struct_b.nested_a.some_int8, struct_b_clone.nested_a.some_int8)
+ self.assertEquals(struct_b.nested_a.some_double, struct_b_clone.nested_a.some_double)
+ self.assertEquals(struct_b.nested_a.some_enum, struct_b_clone.nested_a.some_enum)
+
+ def test_wrong_type_of_arguments(self):
+ try:
+ Everything.test_int8()
+ except TypeError, e:
+ self.assertEquals(e.args, ("test_int8() takes exactly 1 argument(s) (0 given)",))
+
+class TestNullableArgs(unittest.TestCase):
+ def test_in_nullable_hash(self):
+ Everything.test_ghash_null_in(None)
+
+ def test_in_nullable_list(self):
+ Everything.test_gslist_null_in(None)
+ Everything.test_glist_null_in(None)
+
+ def test_in_nullable_array(self):
+ Everything.test_array_int_null_in(None)
+
+ def test_in_nullable_string(self):
+ Everything.test_utf8_null_in(None)
+
+ def test_in_nullable_object(self):
+ Everything.test_object_null_in(None)
+
+ def test_out_nullable_hash(self):
+ self.assertEqual(None, Everything.test_ghash_null_out())
+
+ def test_out_nullable_list(self):
+ self.assertEqual([], Everything.test_gslist_null_out())
+ self.assertEqual([], Everything.test_glist_null_out())
+
+ def test_out_nullable_array(self):
+ self.assertEqual(None, Everything.test_array_int_null_out())
+
+ def test_out_nullable_string(self):
+ self.assertEqual(None, Everything.test_utf8_null_out())
+
+ def test_out_nullable_object(self):
+ self.assertEqual(None, Everything.test_object_null_out())
+
+class TestCallbacks(unittest.TestCase):
+ called = False
+ main_loop = GObject.MainLoop()
+
+ def testCallback(self):
+ TestCallbacks.called = False
+ def callback():
+ TestCallbacks.called = True
+
+ Everything.test_simple_callback(callback)
+ self.assertTrue(TestCallbacks.called)
+
+ def testCallbackException(self):
+ """
+ This test ensures that we get errors from callbacks correctly
+ and in particular that we do not segv when callbacks fail
+ """
+ def callback():
+ x = 1 / 0
+
+ try:
+ Everything.test_simple_callback(callback)
+ except ZeroDivisionError:
+ pass
+
+ def testDoubleCallbackException(self):
+ """
+ This test ensures that we get errors from callbacks correctly
+ and in particular that we do not segv when callbacks fail
+ """
+ def badcallback():
+ x = 1 / 0
+
+ def callback():
+ Everything.test_boolean(True)
+ Everything.test_boolean(False)
+ Everything.test_simple_callback(badcallback())
+
+ try:
+ Everything.test_simple_callback(callback)
+ except ZeroDivisionError:
+ pass
+
+ def testReturnValueCallback(self):
+ TestCallbacks.called = False
+ def callback():
+ TestCallbacks.called = True
+ return 44
+
+ self.assertEquals(Everything.test_callback(callback), 44)
+ self.assertTrue(TestCallbacks.called)
+
+ def testCallbackAsync(self):
+ TestCallbacks.called = False
+ def callback(foo):
+ TestCallbacks.called = True
+ return foo
+
+ Everything.test_callback_async(callback, 44);
+ i = Everything.test_callback_thaw_async();
+ self.assertEquals(44, i);
+ self.assertTrue(TestCallbacks.called)
+
+ def testCallbackScopeCall(self):
+ TestCallbacks.called = 0
+ def callback():
+ TestCallbacks.called += 1
+ return 0
+
+ Everything.test_multi_callback(callback)
+ self.assertEquals(TestCallbacks.called, 2)
+
+ def testCallbackUserdata(self):
+ TestCallbacks.called = 0
+ def callback(userdata):
+ self.assertEquals(userdata, "Test%d" % TestCallbacks.called)
+ TestCallbacks.called += 1
+ return TestCallbacks.called
+
+ for i in range(100):
+ val = Everything.test_callback_user_data(callback, "Test%d" % i)
+ self.assertEquals(val, i+1)
+
+ self.assertEquals(TestCallbacks.called, 100)
+
+ def testCallbackUserdataRefCount(self):
+ TestCallbacks.called = False
+ def callback(userdata):
+ TestCallbacks.called = True
+ return 1
+
+ ud = "Test User Data"
+
+ start_ref_count = getrefcount(ud)
+ for i in range(100):
+ Everything.test_callback_destroy_notify(callback, ud)
+
+ Everything.test_callback_thaw_notifications()
+ end_ref_count = getrefcount(ud)
+
+ self.assertEquals(start_ref_count, end_ref_count)
+
+ def testAsyncReadyCallback(self):
+ TestCallbacks.called = False
+ TestCallbacks.main_loop = GObject.MainLoop()
+
+ def callback(obj, result, user_data):
+ TestCallbacks.main_loop.quit()
+ TestCallbacks.called = True
+
+ Everything.test_async_ready_callback(callback)
+
+ TestCallbacks.main_loop.run()
+
+ self.assertTrue(TestCallbacks.called)
+
+ def testCallbackDestroyNotify(self):
+ def callback(user_data):
+ TestCallbacks.called = True
+ return 42
+
+ TestCallbacks.called = False
+ self.assertEquals(Everything.test_callback_destroy_notify(callback, 42), 42)
+ self.assertTrue(TestCallbacks.called)
+ self.assertEquals(Everything.test_callback_thaw_notifications(), 42)
+
+ def testCallbackInMethods(self):
+ object_ = Everything.TestObj()
+
+ def callback():
+ TestCallbacks.called = True
+
+ TestCallbacks.called = False
+ object_.instance_method_callback(callback)
+ self.assertTrue(TestCallbacks.called)
+
+ TestCallbacks.called = False
+ Everything.TestObj.static_method_callback(callback)
+ self.assertTrue(TestCallbacks.called)
+
+ def callbackWithUserData(user_data):
+ TestCallbacks.called = True
+
+ TestCallbacks.called = False
+ obj_ = Everything.TestObj.new_callback(callbackWithUserData, None)
+ self.assertTrue(TestCallbacks.called)
+
+ def testCallbackNone(self):
+ # make sure this doesn't assert or crash
+ Everything.test_simple_callback(None) \ No newline at end of file
diff --git a/gi/tests/test_gi.py b/gi/tests/test_gi.py
new file mode 100644
index 00000000..2541c2d2
--- /dev/null
+++ b/gi/tests/test_gi.py
@@ -0,0 +1,1624 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+
+import pygtk
+pygtk.require("2.0")
+
+import unittest
+from gi.repository import GObject
+
+from datetime import datetime
+
+import sys
+sys.path.insert(0, "../")
+
+import gobject
+from gi.repository import GIMarshallingTests
+
+
+CONSTANT_UTF8 = "const \xe2\x99\xa5 utf8"
+CONSTANT_NUMBER = 42
+
+
+class Number(object):
+
+ def __init__(self, value):
+ self.value = value
+
+ def __int__(self):
+ return int(self.value)
+
+ def __float__(self):
+ return float(self.value)
+
+
+class Sequence(object):
+
+ def __init__(self, sequence):
+ self.sequence = sequence
+
+ def __len__(self):
+ return len(self.sequence)
+
+ def __getitem__(self, key):
+ return self.sequence[key]
+
+
+class TestConstant(unittest.TestCase):
+
+# Blocked by https://bugzilla.gnome.org/show_bug.cgi?id=595773
+# def test_constant_utf8(self):
+# self.assertEquals(CONSTANT_UTF8, GIMarshallingTests.CONSTANT_UTF8)
+
+ def test_constant_number(self):
+ self.assertEquals(CONSTANT_NUMBER, GIMarshallingTests.CONSTANT_NUMBER)
+
+
+class TestBoolean(unittest.TestCase):
+
+ def test_boolean_return(self):
+ self.assertEquals(True, GIMarshallingTests.boolean_return_true())
+ self.assertEquals(False, GIMarshallingTests.boolean_return_false())
+
+ def test_boolean_in(self):
+ GIMarshallingTests.boolean_in_true(True)
+ GIMarshallingTests.boolean_in_false(False)
+
+ GIMarshallingTests.boolean_in_true(1)
+ GIMarshallingTests.boolean_in_false(0)
+
+ def test_boolean_out(self):
+ self.assertEquals(True, GIMarshallingTests.boolean_out_true())
+ self.assertEquals(False, GIMarshallingTests.boolean_out_false())
+
+ def test_boolean_inout(self):
+ self.assertEquals(False, GIMarshallingTests.boolean_inout_true_false(True))
+ self.assertEquals(True, GIMarshallingTests.boolean_inout_false_true(False))
+
+
+class TestInt8(unittest.TestCase):
+
+ MAX = GObject.G_MAXINT8
+ MIN = GObject.G_MININT8
+
+ def test_int8_return(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.int8_return_max())
+ self.assertEquals(self.MIN, GIMarshallingTests.int8_return_min())
+
+ def test_int8_in(self):
+ max = Number(self.MAX)
+ min = Number(self.MIN)
+
+ GIMarshallingTests.int8_in_max(max)
+ GIMarshallingTests.int8_in_min(min)
+
+ max.value += 1
+ min.value -= 1
+
+ self.assertRaises(ValueError, GIMarshallingTests.int8_in_max, max)
+ self.assertRaises(ValueError, GIMarshallingTests.int8_in_min, min)
+
+ self.assertRaises(TypeError, GIMarshallingTests.int8_in_max, "self.MAX")
+
+ def test_int8_out(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.int8_out_max())
+ self.assertEquals(self.MIN, GIMarshallingTests.int8_out_min())
+
+ def test_int8_inout(self):
+ self.assertEquals(self.MIN, GIMarshallingTests.int8_inout_max_min(Number(self.MAX)))
+ self.assertEquals(self.MAX, GIMarshallingTests.int8_inout_min_max(Number(self.MIN)))
+
+
+class TestUInt8(unittest.TestCase):
+
+ MAX = GObject.G_MAXUINT8
+
+ def test_uint8_return(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.uint8_return())
+
+ def test_uint8_in(self):
+ number = Number(self.MAX)
+
+ GIMarshallingTests.uint8_in(number)
+
+ number.value += 1
+
+ self.assertRaises(ValueError, GIMarshallingTests.uint8_in, number)
+ self.assertRaises(ValueError, GIMarshallingTests.uint8_in, Number(-1))
+
+ self.assertRaises(TypeError, GIMarshallingTests.uint8_in, "self.MAX")
+
+ def test_uint8_out(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.uint8_out())
+
+ def test_uint8_inout(self):
+ self.assertEquals(0, GIMarshallingTests.uint8_inout(Number(self.MAX)))
+
+
+class TestInt16(unittest.TestCase):
+
+ MAX = GObject.G_MAXINT16
+ MIN = GObject.G_MININT16
+
+ def test_int16_return(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.int16_return_max())
+ self.assertEquals(self.MIN, GIMarshallingTests.int16_return_min())
+
+ def test_int16_in(self):
+ max = Number(self.MAX)
+ min = Number(self.MIN)
+
+ GIMarshallingTests.int16_in_max(max)
+ GIMarshallingTests.int16_in_min(min)
+
+ max.value += 1
+ min.value -= 1
+
+ self.assertRaises(ValueError, GIMarshallingTests.int16_in_max, max)
+ self.assertRaises(ValueError, GIMarshallingTests.int16_in_min, min)
+
+ self.assertRaises(TypeError, GIMarshallingTests.int16_in_max, "self.MAX")
+
+ def test_int16_out(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.int16_out_max())
+ self.assertEquals(self.MIN, GIMarshallingTests.int16_out_min())
+
+ def test_int16_inout(self):
+ self.assertEquals(self.MIN, GIMarshallingTests.int16_inout_max_min(Number(self.MAX)))
+ self.assertEquals(self.MAX, GIMarshallingTests.int16_inout_min_max(Number(self.MIN)))
+
+
+class TestUInt16(unittest.TestCase):
+
+ MAX = GObject.G_MAXUINT16
+
+ def test_uint16_return(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.uint16_return())
+
+ def test_uint16_in(self):
+ number = Number(self.MAX)
+
+ GIMarshallingTests.uint16_in(number)
+
+ number.value += 1
+
+ self.assertRaises(ValueError, GIMarshallingTests.uint16_in, number)
+ self.assertRaises(ValueError, GIMarshallingTests.uint16_in, Number(-1))
+
+ self.assertRaises(TypeError, GIMarshallingTests.uint16_in, "self.MAX")
+
+ def test_uint16_out(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.uint16_out())
+
+ def test_uint16_inout(self):
+ self.assertEquals(0, GIMarshallingTests.uint16_inout(Number(self.MAX)))
+
+
+class TestInt32(unittest.TestCase):
+
+ MAX = GObject.G_MAXINT32
+ MIN = GObject.G_MININT32
+
+ def test_int32_return(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.int32_return_max())
+ self.assertEquals(self.MIN, GIMarshallingTests.int32_return_min())
+
+ def test_int32_in(self):
+ max = Number(self.MAX)
+ min = Number(self.MIN)
+
+ GIMarshallingTests.int32_in_max(max)
+ GIMarshallingTests.int32_in_min(min)
+
+ max.value += 1
+ min.value -= 1
+
+ self.assertRaises(ValueError, GIMarshallingTests.int32_in_max, max)
+ self.assertRaises(ValueError, GIMarshallingTests.int32_in_min, min)
+
+ self.assertRaises(TypeError, GIMarshallingTests.int32_in_max, "self.MAX")
+
+ def test_int32_out(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.int32_out_max())
+ self.assertEquals(self.MIN, GIMarshallingTests.int32_out_min())
+
+ def test_int32_inout(self):
+ self.assertEquals(self.MIN, GIMarshallingTests.int32_inout_max_min(Number(self.MAX)))
+ self.assertEquals(self.MAX, GIMarshallingTests.int32_inout_min_max(Number(self.MIN)))
+
+
+class TestUInt32(unittest.TestCase):
+
+ MAX = GObject.G_MAXUINT32
+
+ def test_uint32_return(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.uint32_return())
+
+ def test_uint32_in(self):
+ number = Number(self.MAX)
+
+ GIMarshallingTests.uint32_in(number)
+
+ number.value += 1
+
+ self.assertRaises(ValueError, GIMarshallingTests.uint32_in, number)
+ self.assertRaises(ValueError, GIMarshallingTests.uint32_in, Number(-1))
+
+ self.assertRaises(TypeError, GIMarshallingTests.uint32_in, "self.MAX")
+
+ def test_uint32_out(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.uint32_out())
+
+ def test_uint32_inout(self):
+ self.assertEquals(0, GIMarshallingTests.uint32_inout(Number(self.MAX)))
+
+
+class TestInt64(unittest.TestCase):
+
+ MAX = 2 ** 63 - 1
+ MIN = - (2 ** 63)
+
+ def test_int64_return(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.int64_return_max())
+ self.assertEquals(self.MIN, GIMarshallingTests.int64_return_min())
+
+ def test_int64_in(self):
+ max = Number(self.MAX)
+ min = Number(self.MIN)
+
+ GIMarshallingTests.int64_in_max(max)
+ GIMarshallingTests.int64_in_min(min)
+
+ max.value += 1
+ min.value -= 1
+
+ self.assertRaises(ValueError, GIMarshallingTests.int64_in_max, max)
+ self.assertRaises(ValueError, GIMarshallingTests.int64_in_min, min)
+
+ self.assertRaises(TypeError, GIMarshallingTests.int64_in_max, "self.MAX")
+
+ def test_int64_out(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.int64_out_max())
+ self.assertEquals(self.MIN, GIMarshallingTests.int64_out_min())
+
+ def test_int64_inout(self):
+ self.assertEquals(self.MIN, GIMarshallingTests.int64_inout_max_min(Number(self.MAX)))
+ self.assertEquals(self.MAX, GIMarshallingTests.int64_inout_min_max(Number(self.MIN)))
+
+
+class TestUInt64(unittest.TestCase):
+
+ MAX = 2 ** 64 - 1
+
+ def test_uint64_return(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.uint64_return())
+
+ def test_uint64_in(self):
+ number = Number(self.MAX)
+
+ GIMarshallingTests.uint64_in(number)
+
+ number.value += 1
+
+ self.assertRaises(ValueError, GIMarshallingTests.uint64_in, number)
+ self.assertRaises(ValueError, GIMarshallingTests.uint64_in, Number(-1))
+
+ self.assertRaises(TypeError, GIMarshallingTests.uint64_in, "self.MAX")
+
+ def test_uint64_out(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.uint64_out())
+
+ def test_uint64_inout(self):
+ self.assertEquals(0, GIMarshallingTests.uint64_inout(Number(self.MAX)))
+
+
+class TestShort(unittest.TestCase):
+
+ MAX = GObject.constants.G_MAXSHORT
+ MIN = GObject.constants.G_MINSHORT
+
+ def test_short_return(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.short_return_max())
+ self.assertEquals(self.MIN, GIMarshallingTests.short_return_min())
+
+ def test_short_in(self):
+ max = Number(self.MAX)
+ min = Number(self.MIN)
+
+ GIMarshallingTests.short_in_max(max)
+ GIMarshallingTests.short_in_min(min)
+
+ max.value += 1
+ min.value -= 1
+
+ self.assertRaises(ValueError, GIMarshallingTests.short_in_max, max)
+ self.assertRaises(ValueError, GIMarshallingTests.short_in_min, min)
+
+ self.assertRaises(TypeError, GIMarshallingTests.short_in_max, "self.MAX")
+
+ def test_short_out(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.short_out_max())
+ self.assertEquals(self.MIN, GIMarshallingTests.short_out_min())
+
+ def test_short_inout(self):
+ self.assertEquals(self.MIN, GIMarshallingTests.short_inout_max_min(Number(self.MAX)))
+ self.assertEquals(self.MAX, GIMarshallingTests.short_inout_min_max(Number(self.MIN)))
+
+
+class TestUShort(unittest.TestCase):
+
+ MAX = GObject.constants.G_MAXUSHORT
+
+ def test_ushort_return(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.ushort_return())
+
+ def test_ushort_in(self):
+ number = Number(self.MAX)
+
+ GIMarshallingTests.ushort_in(number)
+
+ number.value += 1
+
+ self.assertRaises(ValueError, GIMarshallingTests.ushort_in, number)
+ self.assertRaises(ValueError, GIMarshallingTests.ushort_in, Number(-1))
+
+ self.assertRaises(TypeError, GIMarshallingTests.ushort_in, "self.MAX")
+
+ def test_ushort_out(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.ushort_out())
+
+ def test_ushort_inout(self):
+ self.assertEquals(0, GIMarshallingTests.ushort_inout(Number(self.MAX)))
+
+
+class TestInt(unittest.TestCase):
+
+ MAX = GObject.constants.G_MAXINT
+ MIN = GObject.constants.G_MININT
+
+ def test_int_return(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.int_return_max())
+ self.assertEquals(self.MIN, GIMarshallingTests.int_return_min())
+
+ def test_int_in(self):
+ max = Number(self.MAX)
+ min = Number(self.MIN)
+
+ GIMarshallingTests.int_in_max(max)
+ GIMarshallingTests.int_in_min(min)
+
+ max.value += 1
+ min.value -= 1
+
+ self.assertRaises(ValueError, GIMarshallingTests.int_in_max, max)
+ self.assertRaises(ValueError, GIMarshallingTests.int_in_min, min)
+
+ self.assertRaises(TypeError, GIMarshallingTests.int_in_max, "self.MAX")
+
+ def test_int_out(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.int_out_max())
+ self.assertEquals(self.MIN, GIMarshallingTests.int_out_min())
+
+ def test_int_inout(self):
+ self.assertEquals(self.MIN, GIMarshallingTests.int_inout_max_min(Number(self.MAX)))
+ self.assertEquals(self.MAX, GIMarshallingTests.int_inout_min_max(Number(self.MIN)))
+
+
+class TestUInt(unittest.TestCase):
+
+ MAX = GObject.constants.G_MAXUINT
+
+ def test_uint_return(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.uint_return())
+
+ def test_uint_in(self):
+ number = Number(self.MAX)
+
+ GIMarshallingTests.uint_in(number)
+
+ number.value += 1
+
+ self.assertRaises(ValueError, GIMarshallingTests.uint_in, number)
+ self.assertRaises(ValueError, GIMarshallingTests.uint_in, Number(-1))
+
+ self.assertRaises(TypeError, GIMarshallingTests.uint_in, "self.MAX")
+
+ def test_uint_out(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.uint_out())
+
+ def test_uint_inout(self):
+ self.assertEquals(0, GIMarshallingTests.uint_inout(Number(self.MAX)))
+
+
+class TestLong(unittest.TestCase):
+
+ MAX = GObject.constants.G_MAXLONG
+ MIN = GObject.constants.G_MINLONG
+
+ def test_long_return(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.long_return_max())
+ self.assertEquals(self.MIN, GIMarshallingTests.long_return_min())
+
+ def test_long_in(self):
+ max = Number(self.MAX)
+ min = Number(self.MIN)
+
+ GIMarshallingTests.long_in_max(max)
+ GIMarshallingTests.long_in_min(min)
+
+ max.value += 1
+ min.value -= 1
+
+ self.assertRaises(ValueError, GIMarshallingTests.long_in_max, max)
+ self.assertRaises(ValueError, GIMarshallingTests.long_in_min, min)
+
+ self.assertRaises(TypeError, GIMarshallingTests.long_in_max, "self.MAX")
+
+ def test_long_out(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.long_out_max())
+ self.assertEquals(self.MIN, GIMarshallingTests.long_out_min())
+
+ def test_long_inout(self):
+ self.assertEquals(self.MIN, GIMarshallingTests.long_inout_max_min(Number(self.MAX)))
+ self.assertEquals(self.MAX, GIMarshallingTests.long_inout_min_max(Number(self.MIN)))
+
+
+class TestULong(unittest.TestCase):
+
+ MAX = GObject.constants.G_MAXULONG
+
+ def test_ulong_return(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.ulong_return())
+
+ def test_ulong_in(self):
+ number = Number(self.MAX)
+
+ GIMarshallingTests.ulong_in(number)
+
+ number.value += 1
+
+ self.assertRaises(ValueError, GIMarshallingTests.ulong_in, number)
+ self.assertRaises(ValueError, GIMarshallingTests.ulong_in, Number(-1))
+
+ self.assertRaises(TypeError, GIMarshallingTests.ulong_in, "self.MAX")
+
+ def test_ulong_out(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.ulong_out())
+
+ def test_ulong_inout(self):
+ self.assertEquals(0, GIMarshallingTests.ulong_inout(Number(self.MAX)))
+
+
+class TestSSize(unittest.TestCase):
+
+ MAX = GObject.constants.G_MAXLONG
+ MIN = GObject.constants.G_MINLONG
+
+ def test_ssize_return(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.ssize_return_max())
+ self.assertEquals(self.MIN, GIMarshallingTests.ssize_return_min())
+
+ def test_ssize_in(self):
+ max = Number(self.MAX)
+ min = Number(self.MIN)
+
+ GIMarshallingTests.ssize_in_max(max)
+ GIMarshallingTests.ssize_in_min(min)
+
+ max.value += 1
+ min.value -= 1
+
+ self.assertRaises(ValueError, GIMarshallingTests.ssize_in_max, max)
+ self.assertRaises(ValueError, GIMarshallingTests.ssize_in_min, min)
+
+ self.assertRaises(TypeError, GIMarshallingTests.ssize_in_max, "self.MAX")
+
+ def test_ssize_out(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.ssize_out_max())
+ self.assertEquals(self.MIN, GIMarshallingTests.ssize_out_min())
+
+ def test_ssize_inout(self):
+ self.assertEquals(self.MIN, GIMarshallingTests.ssize_inout_max_min(Number(self.MAX)))
+ self.assertEquals(self.MAX, GIMarshallingTests.ssize_inout_min_max(Number(self.MIN)))
+
+
+class TestSize(unittest.TestCase):
+
+ MAX = GObject.constants.G_MAXULONG
+
+ def test_size_return(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.size_return())
+
+ def test_size_in(self):
+ number = Number(self.MAX)
+
+ GIMarshallingTests.size_in(number)
+
+ number.value += 1
+
+ self.assertRaises(ValueError, GIMarshallingTests.size_in, number)
+ self.assertRaises(ValueError, GIMarshallingTests.size_in, Number(-1))
+
+ self.assertRaises(TypeError, GIMarshallingTests.size_in, "self.MAX")
+
+ def test_size_out(self):
+ self.assertEquals(self.MAX, GIMarshallingTests.size_out())
+
+ def test_size_inout(self):
+ self.assertEquals(0, GIMarshallingTests.size_inout(Number(self.MAX)))
+
+
+class TestFloat(unittest.TestCase):
+
+ MAX = GObject.constants.G_MAXFLOAT
+ MIN = GObject.constants.G_MINFLOAT
+
+ def test_float_return(self):
+ self.assertAlmostEquals(self.MAX, GIMarshallingTests.float_return())
+
+ def test_float_in(self):
+ GIMarshallingTests.float_in(Number(self.MAX))
+
+ self.assertRaises(TypeError, GIMarshallingTests.float_in, "self.MAX")
+
+ def test_float_out(self):
+ self.assertAlmostEquals(self.MAX, GIMarshallingTests.float_out())
+
+ def test_float_inout(self):
+ self.assertAlmostEquals(self.MIN, GIMarshallingTests.float_inout(Number(self.MAX)))
+
+
+class TestDouble(unittest.TestCase):
+
+ MAX = GObject.constants.G_MAXDOUBLE
+ MIN = GObject.constants.G_MINDOUBLE
+
+ def test_double_return(self):
+ self.assertAlmostEquals(self.MAX, GIMarshallingTests.double_return())
+
+ def test_double_in(self):
+ GIMarshallingTests.double_in(Number(self.MAX))
+
+ self.assertRaises(TypeError, GIMarshallingTests.double_in, "self.MAX")
+
+ def test_double_out(self):
+ self.assertAlmostEquals(self.MAX, GIMarshallingTests.double_out())
+
+ def test_double_inout(self):
+ self.assertAlmostEquals(self.MIN, GIMarshallingTests.double_inout(Number(self.MAX)))
+
+
+class TestTimeT(unittest.TestCase):
+
+ DATETIME = datetime.fromtimestamp(1234567890)
+
+ def test_time_t_return(self):
+ self.assertEquals(self.DATETIME, GIMarshallingTests.time_t_return())
+
+ def test_time_t_in(self):
+ GIMarshallingTests.time_t_in(self.DATETIME)
+
+ self.assertRaises(TypeError, GIMarshallingTests.time_t_in, "self.DATETIME")
+
+ def test_time_t_out(self):
+ self.assertEquals(self.DATETIME, GIMarshallingTests.time_t_out())
+
+ def test_time_t_inout(self):
+ self.assertEquals(datetime.fromtimestamp(0), GIMarshallingTests.time_t_inout(self.DATETIME))
+
+
+class TestGType(unittest.TestCase):
+
+ def test_gtype_return(self):
+ self.assertEquals(GObject.TYPE_NONE, GIMarshallingTests.gtype_return())
+
+ def test_gtype_in(self):
+ GIMarshallingTests.gtype_in(GObject.TYPE_NONE)
+
+ self.assertRaises(TypeError, GIMarshallingTests.gtype_in, "GObject.TYPE_NONE")
+
+ def test_gtype_out(self):
+ self.assertEquals(GObject.TYPE_NONE, GIMarshallingTests.gtype_out())
+
+ def test_gtype_inout(self):
+ self.assertEquals(GObject.TYPE_INT, GIMarshallingTests.gtype_inout(GObject.TYPE_NONE))
+
+
+class TestUtf8(unittest.TestCase):
+
+ def test_utf8_none_return(self):
+ self.assertEquals(CONSTANT_UTF8, GIMarshallingTests.utf8_none_return())
+
+ def test_utf8_full_return(self):
+ self.assertEquals(CONSTANT_UTF8, GIMarshallingTests.utf8_full_return())
+
+ def test_utf8_none_in(self):
+ GIMarshallingTests.utf8_none_in(CONSTANT_UTF8)
+
+ self.assertRaises(TypeError, GIMarshallingTests.utf8_none_in, CONSTANT_NUMBER)
+ self.assertRaises(TypeError, GIMarshallingTests.utf8_none_in, None)
+
+ def test_utf8_full_in(self):
+ GIMarshallingTests.utf8_full_in(CONSTANT_UTF8)
+
+ def test_utf8_none_out(self):
+ self.assertEquals(CONSTANT_UTF8, GIMarshallingTests.utf8_none_out())
+
+ def test_utf8_full_out(self):
+ self.assertEquals(CONSTANT_UTF8, GIMarshallingTests.utf8_full_out())
+
+ def test_utf8_dangling_out(self):
+ GIMarshallingTests.utf8_dangling_out()
+
+ def test_utf8_none_inout(self):
+ self.assertEquals("", GIMarshallingTests.utf8_none_inout(CONSTANT_UTF8))
+
+ def test_utf8_full_inout(self):
+ self.assertEquals("", GIMarshallingTests.utf8_full_inout(CONSTANT_UTF8))
+
+
+class TestArray(unittest.TestCase):
+
+ def test_array_fixed_int_return(self):
+ self.assertEquals((-1, 0, 1, 2), GIMarshallingTests.array_fixed_int_return())
+
+ def test_array_fixed_short_return(self):
+ self.assertEquals((-1, 0, 1, 2), GIMarshallingTests.array_fixed_short_return())
+
+ def test_array_fixed_int_in(self):
+ GIMarshallingTests.array_fixed_int_in(Sequence((-1, 0, 1, 2)))
+
+ self.assertRaises(TypeError, GIMarshallingTests.array_fixed_int_in, Sequence((-1, '0', 1, 2)))
+
+ self.assertRaises(TypeError, GIMarshallingTests.array_fixed_int_in, 42)
+ self.assertRaises(TypeError, GIMarshallingTests.array_fixed_int_in, None)
+
+ def test_array_fixed_short_in(self):
+ GIMarshallingTests.array_fixed_short_in(Sequence((-1, 0, 1, 2)))
+
+ def test_array_fixed_out(self):
+ self.assertEquals((-1, 0, 1, 2), GIMarshallingTests.array_fixed_out())
+
+ def test_array_fixed_inout(self):
+ self.assertEquals((2, 1, 0, -1), GIMarshallingTests.array_fixed_inout((-1, 0, 1, 2)))
+
+
+ def test_array_return(self):
+ self.assertEquals((-1, 0, 1, 2), GIMarshallingTests.array_return())
+
+ def test_array_in(self):
+ GIMarshallingTests.array_in(Sequence((-1, 0, 1, 2)))
+
+ def test_array_out(self):
+ self.assertEquals((-1, 0, 1, 2), GIMarshallingTests.array_out())
+
+ def test_array_inout(self):
+ self.assertEquals((-2, -1, 0, 1, 2), GIMarshallingTests.array_inout(Sequence((-1, 0, 1, 2))))
+
+ def test_method_array_in(self):
+ object_ = GIMarshallingTests.Object()
+ object_.method_array_in(Sequence((-1, 0, 1, 2)))
+
+ def test_method_array_out(self):
+ object_ = GIMarshallingTests.Object()
+ self.assertEquals((-1, 0, 1, 2), object_.method_array_out())
+
+ def test_method_array_inout(self):
+ object_ = GIMarshallingTests.Object()
+ self.assertEquals((-2, -1, 0, 1, 2), object_.method_array_inout(Sequence((-1, 0, 1, 2))))
+
+ def test_method_array_return(self):
+ object_ = GIMarshallingTests.Object()
+ self.assertEquals((-1, 0, 1, 2), object_.method_array_return())
+
+ def test_array_fixed_out_struct(self):
+ struct1, struct2 = GIMarshallingTests.array_fixed_out_struct()
+
+ self.assertEquals(7, struct1.long_)
+ self.assertEquals(6, struct1.int8)
+ self.assertEquals(6, struct2.long_)
+ self.assertEquals(7, struct2.int8)
+
+ def test_array_zero_terminated_return(self):
+ self.assertEquals(('0', '1', '2'), GIMarshallingTests.array_zero_terminated_return())
+
+ def test_array_zero_terminated_in(self):
+ GIMarshallingTests.array_zero_terminated_in(Sequence(('0', '1', '2')))
+
+ def test_array_zero_terminated_out(self):
+ self.assertEquals(('0', '1', '2'), GIMarshallingTests.array_zero_terminated_out())
+
+ def test_array_zero_terminated_out(self):
+ self.assertEquals(('0', '1', '2'), GIMarshallingTests.array_zero_terminated_out())
+
+ def test_array_zero_terminated_inout(self):
+ self.assertEquals(('-1', '0', '1', '2'), GIMarshallingTests.array_zero_terminated_inout(('0', '1', '2')))
+
+ def test_gstrv_return(self):
+ self.assertEquals(('0', '1', '2'), GIMarshallingTests.gstrv_return())
+
+ def test_gstrv_in(self):
+ GIMarshallingTests.gstrv_in(Sequence(('0', '1', '2')))
+
+ def test_gstrv_out(self):
+ self.assertEquals(('0', '1', '2'), GIMarshallingTests.gstrv_out())
+
+ def test_gstrv_out(self):
+ self.assertEquals(('0', '1', '2'), GIMarshallingTests.gstrv_out())
+
+ def test_gstrv_inout(self):
+ self.assertEquals(('-1', '0', '1', '2'), GIMarshallingTests.gstrv_inout(('0', '1', '2')))
+
+
+class TestGArray(unittest.TestCase):
+
+ def test_garray_int_none_return(self):
+ self.assertEquals((-1, 0, 1, 2), GIMarshallingTests.garray_int_none_return())
+
+ def test_garray_utf8_none_return(self):
+ self.assertEquals(('0', '1', '2'), GIMarshallingTests.garray_utf8_none_return())
+
+ def test_garray_utf8_container_return(self):
+ self.assertEquals(('0', '1', '2'), GIMarshallingTests.garray_utf8_container_return())
+
+ def test_garray_utf8_full_return(self):
+ self.assertEquals(('0', '1', '2'), GIMarshallingTests.garray_utf8_full_return())
+
+ def test_garray_int_none_in(self):
+ GIMarshallingTests.garray_int_none_in(Sequence((-1, 0, 1, 2)))
+
+ self.assertRaises(TypeError, GIMarshallingTests.garray_int_none_in, Sequence((-1, '0', 1, 2)))
+
+ self.assertRaises(TypeError, GIMarshallingTests.garray_int_none_in, 42)
+ self.assertRaises(TypeError, GIMarshallingTests.garray_int_none_in, None)
+
+ def test_garray_utf8_none_in(self):
+ GIMarshallingTests.garray_utf8_none_in(Sequence(('0', '1', '2')))
+
+ def test_garray_utf8_container_in(self):
+ GIMarshallingTests.garray_utf8_container_in(Sequence(('0', '1', '2')))
+
+ def test_garray_utf8_full_in(self):
+ GIMarshallingTests.garray_utf8_full_in(Sequence(('0', '1', '2')))
+
+ def test_garray_utf8_none_out(self):
+ self.assertEquals(('0', '1', '2'), GIMarshallingTests.garray_utf8_none_out())
+
+ def test_garray_utf8_container_out(self):
+ self.assertEquals(('0', '1', '2'), GIMarshallingTests.garray_utf8_container_out())
+
+ def test_garray_utf8_full_out(self):
+ self.assertEquals(('0', '1', '2'), GIMarshallingTests.garray_utf8_full_out())
+
+ def test_garray_utf8_none_inout(self):
+ self.assertEquals(('-2', '-1', '0', '1'), GIMarshallingTests.garray_utf8_none_inout(Sequence(('0', '1', '2'))))
+
+ def test_garray_utf8_container_inout(self):
+ self.assertEquals(('-2', '-1','0', '1'), GIMarshallingTests.garray_utf8_container_inout(('0', '1', '2')))
+
+ def test_garray_utf8_full_inout(self):
+ self.assertEquals(('-2', '-1','0', '1'), GIMarshallingTests.garray_utf8_full_inout(('0', '1', '2')))
+
+
+class TestGList(unittest.TestCase):
+
+ def test_glist_int_none_return(self):
+ self.assertEquals([-1, 0, 1, 2], GIMarshallingTests.glist_int_none_return())
+
+ def test_glist_utf8_none_return(self):
+ self.assertEquals(['0', '1', '2'], GIMarshallingTests.glist_utf8_none_return())
+
+ def test_glist_utf8_container_return(self):
+ self.assertEquals(['0', '1', '2'], GIMarshallingTests.glist_utf8_container_return())
+
+ def test_glist_utf8_full_return(self):
+ self.assertEquals(['0', '1', '2'], GIMarshallingTests.glist_utf8_full_return())
+
+ def test_glist_int_none_in(self):
+ GIMarshallingTests.glist_int_none_in(Sequence((-1, 0, 1, 2)))
+
+ self.assertRaises(TypeError, GIMarshallingTests.glist_int_none_in, Sequence((-1, '0', 1, 2)))
+
+ self.assertRaises(TypeError, GIMarshallingTests.glist_int_none_in, 42)
+ self.assertRaises(TypeError, GIMarshallingTests.glist_int_none_in, None)
+
+ def test_glist_utf8_none_in(self):
+ GIMarshallingTests.glist_utf8_none_in(Sequence(('0', '1', '2')))
+
+ def test_glist_utf8_container_in(self):
+ GIMarshallingTests.glist_utf8_container_in(Sequence(('0', '1', '2')))
+
+ def test_glist_utf8_full_in(self):
+ GIMarshallingTests.glist_utf8_full_in(Sequence(('0', '1', '2')))
+
+ def test_glist_utf8_none_out(self):
+ self.assertEquals(['0', '1', '2'], GIMarshallingTests.glist_utf8_none_out())
+
+ def test_glist_utf8_container_out(self):
+ self.assertEquals(['0', '1', '2'], GIMarshallingTests.glist_utf8_container_out())
+
+ def test_glist_utf8_full_out(self):
+ self.assertEquals(['0', '1', '2'], GIMarshallingTests.glist_utf8_full_out())
+
+ def test_glist_utf8_none_inout(self):
+ self.assertEquals(['-2', '-1', '0', '1'], GIMarshallingTests.glist_utf8_none_inout(Sequence(('0', '1', '2'))))
+
+ def test_glist_utf8_container_inout(self):
+ self.assertEquals(['-2', '-1','0', '1'], GIMarshallingTests.glist_utf8_container_inout(('0', '1', '2')))
+
+ def test_glist_utf8_full_inout(self):
+ self.assertEquals(['-2', '-1','0', '1'], GIMarshallingTests.glist_utf8_full_inout(('0', '1', '2')))
+
+
+class TestGSList(unittest.TestCase):
+
+ def test_gslist_int_none_return(self):
+ self.assertEquals([-1, 0, 1, 2], GIMarshallingTests.gslist_int_none_return())
+
+ def test_gslist_utf8_none_return(self):
+ self.assertEquals(['0', '1', '2'], GIMarshallingTests.gslist_utf8_none_return())
+
+ def test_gslist_utf8_container_return(self):
+ self.assertEquals(['0', '1', '2'], GIMarshallingTests.gslist_utf8_container_return())
+
+ def test_gslist_utf8_full_return(self):
+ self.assertEquals(['0', '1', '2'], GIMarshallingTests.gslist_utf8_full_return())
+
+ def test_gslist_int_none_in(self):
+ GIMarshallingTests.gslist_int_none_in(Sequence((-1, 0, 1, 2)))
+
+ self.assertRaises(TypeError, GIMarshallingTests.gslist_int_none_in, Sequence((-1, '0', 1, 2)))
+
+ self.assertRaises(TypeError, GIMarshallingTests.gslist_int_none_in, 42)
+ self.assertRaises(TypeError, GIMarshallingTests.gslist_int_none_in, None)
+
+ def test_gslist_utf8_none_in(self):
+ GIMarshallingTests.gslist_utf8_none_in(Sequence(('0', '1', '2')))
+
+ def test_gslist_utf8_container_in(self):
+ GIMarshallingTests.gslist_utf8_container_in(Sequence(('0', '1', '2')))
+
+ def test_gslist_utf8_full_in(self):
+ GIMarshallingTests.gslist_utf8_full_in(Sequence(('0', '1', '2')))
+
+ def test_gslist_utf8_none_out(self):
+ self.assertEquals(['0', '1', '2'], GIMarshallingTests.gslist_utf8_none_out())
+
+ def test_gslist_utf8_container_out(self):
+ self.assertEquals(['0', '1', '2'], GIMarshallingTests.gslist_utf8_container_out())
+
+ def test_gslist_utf8_full_out(self):
+ self.assertEquals(['0', '1', '2'], GIMarshallingTests.gslist_utf8_full_out())
+
+ def test_gslist_utf8_none_inout(self):
+ self.assertEquals(['-2', '-1', '0', '1'], GIMarshallingTests.gslist_utf8_none_inout(Sequence(('0', '1', '2'))))
+
+ def test_gslist_utf8_container_inout(self):
+ self.assertEquals(['-2', '-1','0', '1'], GIMarshallingTests.gslist_utf8_container_inout(('0', '1', '2')))
+
+ def test_gslist_utf8_full_inout(self):
+ self.assertEquals(['-2', '-1','0', '1'], GIMarshallingTests.gslist_utf8_full_inout(('0', '1', '2')))
+
+
+class TestGHashTable(unittest.TestCase):
+
+ def test_ghashtable_int_none_return(self):
+ self.assertEquals({-1: 1, 0: 0, 1: -1, 2: -2}, GIMarshallingTests.ghashtable_int_none_return())
+
+ def test_ghashtable_int_none_return(self):
+ self.assertEquals({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_none_return())
+
+ def test_ghashtable_int_container_return(self):
+ self.assertEquals({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_container_return())
+
+ def test_ghashtable_int_full_return(self):
+ self.assertEquals({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_full_return())
+
+ def test_ghashtable_int_none_in(self):
+ GIMarshallingTests.ghashtable_int_none_in({-1: 1, 0: 0, 1: -1, 2: -2})
+
+ self.assertRaises(TypeError, GIMarshallingTests.ghashtable_int_none_in, {-1: 1, '0': 0, 1: -1, 2: -2})
+ self.assertRaises(TypeError, GIMarshallingTests.ghashtable_int_none_in, {-1: 1, 0: '0', 1: -1, 2: -2})
+
+ self.assertRaises(TypeError, GIMarshallingTests.ghashtable_int_none_in, '{-1: 1, 0: 0, 1: -1, 2: -2}')
+ self.assertRaises(TypeError, GIMarshallingTests.ghashtable_int_none_in, None)
+
+ def test_ghashtable_utf8_none_in(self):
+ GIMarshallingTests.ghashtable_utf8_none_in({'-1': '1', '0': '0', '1': '-1', '2': '-2'})
+
+ def test_ghashtable_utf8_container_in(self):
+ GIMarshallingTests.ghashtable_utf8_container_in({'-1': '1', '0': '0', '1': '-1', '2': '-2'})
+
+ def test_ghashtable_utf8_full_in(self):
+ GIMarshallingTests.ghashtable_utf8_full_in({'-1': '1', '0': '0', '1': '-1', '2': '-2'})
+
+ def test_ghashtable_utf8_none_out(self):
+ self.assertEquals({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_none_out())
+
+ def test_ghashtable_utf8_container_out(self):
+ self.assertEquals({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_container_out())
+
+ def test_ghashtable_utf8_full_out(self):
+ self.assertEquals({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_full_out())
+
+ def test_ghashtable_utf8_none_inout(self):
+ self.assertEquals({'-1': '1', '0': '0', '1': '1'},
+ GIMarshallingTests.ghashtable_utf8_none_inout({'-1': '1', '0': '0', '1': '-1', '2': '-2'}))
+
+ def test_ghashtable_utf8_container_inout(self):
+ self.assertEquals({'-1': '1', '0': '0', '1': '1'},
+ GIMarshallingTests.ghashtable_utf8_container_inout({'-1': '1', '0': '0', '1': '-1', '2': '-2'}))
+
+ def test_ghashtable_utf8_full_inout(self):
+ self.assertEquals({'-1': '1', '0': '0', '1': '1'},
+ GIMarshallingTests.ghashtable_utf8_full_inout({'-1': '1', '0': '0', '1': '-1', '2': '-2'}))
+
+
+class TestGValue(unittest.TestCase):
+
+ def test_gvalue_return(self):
+ self.assertEquals(42, GIMarshallingTests.gvalue_return())
+
+ def test_gvalue_in(self):
+ GIMarshallingTests.gvalue_in(42)
+ self.assertRaises(TypeError, GIMarshallingTests.gvalue_in, None)
+
+ def test_gvalue_out(self):
+ self.assertEquals(42, GIMarshallingTests.gvalue_out())
+
+ def test_gvalue_inout(self):
+ self.assertEquals('42', GIMarshallingTests.gvalue_inout(42))
+
+
+class TestGClosure(unittest.TestCase):
+
+ def test_gclosure_in(self):
+ GIMarshallingTests.gclosure_in(lambda: 42)
+
+ self.assertRaises(TypeError, GIMarshallingTests.gclosure_in, 42)
+ self.assertRaises(TypeError, GIMarshallingTests.gclosure_in, None)
+
+
+class TestPointer(unittest.TestCase):
+ def test_pointer_in_return(self):
+ self.assertEquals(GIMarshallingTests.pointer_in_return(42), 42)
+
+
+class TestEnum(unittest.TestCase):
+
+ def test_enum(self):
+ self.assertTrue(issubclass(GIMarshallingTests.Enum, int))
+ self.assertTrue(isinstance(GIMarshallingTests.Enum.VALUE1, GIMarshallingTests.Enum))
+ self.assertTrue(isinstance(GIMarshallingTests.Enum.VALUE2, GIMarshallingTests.Enum))
+ self.assertTrue(isinstance(GIMarshallingTests.Enum.VALUE3, GIMarshallingTests.Enum))
+ self.assertEquals(42, GIMarshallingTests.Enum.VALUE3)
+
+ def test_enum_in(self):
+ GIMarshallingTests.enum_in(GIMarshallingTests.Enum.VALUE3)
+
+ self.assertRaises(TypeError, GIMarshallingTests.enum_in, 42)
+ self.assertRaises(TypeError, GIMarshallingTests.enum_in, 'GIMarshallingTests.Enum.VALUE3')
+
+ def test_enum_out(self):
+ enum = GIMarshallingTests.enum_out()
+ self.assertTrue(isinstance(enum, GIMarshallingTests.Enum))
+ self.assertEquals(enum, GIMarshallingTests.Enum.VALUE3)
+
+ def test_enum_inout(self):
+ enum = GIMarshallingTests.enum_inout(GIMarshallingTests.Enum.VALUE3)
+ self.assertTrue(isinstance(enum, GIMarshallingTests.Enum))
+ self.assertEquals(enum, GIMarshallingTests.Enum.VALUE1)
+
+
+class TestGEnum(unittest.TestCase):
+
+ def test_genum(self):
+ self.assertTrue(issubclass(GIMarshallingTests.GEnum, GObject.GEnum))
+ self.assertTrue(isinstance(GIMarshallingTests.GEnum.VALUE1, GIMarshallingTests.GEnum))
+ self.assertTrue(isinstance(GIMarshallingTests.GEnum.VALUE2, GIMarshallingTests.GEnum))
+ self.assertTrue(isinstance(GIMarshallingTests.GEnum.VALUE3, GIMarshallingTests.GEnum))
+ self.assertEquals(42, GIMarshallingTests.GEnum.VALUE3)
+
+ def test_genum_in(self):
+ GIMarshallingTests.genum_in(GIMarshallingTests.GEnum.VALUE3)
+
+ self.assertRaises(TypeError, GIMarshallingTests.genum_in, 42)
+ self.assertRaises(TypeError, GIMarshallingTests.genum_in, 'GIMarshallingTests.GEnum.VALUE3')
+
+ def test_genum_out(self):
+ genum = GIMarshallingTests.genum_out()
+ self.assertTrue(isinstance(genum, GIMarshallingTests.GEnum))
+ self.assertEquals(genum, GIMarshallingTests.GEnum.VALUE3)
+
+ def test_genum_inout(self):
+ genum = GIMarshallingTests.genum_inout(GIMarshallingTests.GEnum.VALUE3)
+ self.assertTrue(isinstance(genum, GIMarshallingTests.GEnum))
+ self.assertEquals(genum, GIMarshallingTests.GEnum.VALUE1)
+
+
+class TestGFlags(unittest.TestCase):
+
+ def test_flags(self):
+ self.assertTrue(issubclass(GIMarshallingTests.Flags, GObject.GFlags))
+ self.assertTrue(isinstance(GIMarshallingTests.Flags.VALUE1, GIMarshallingTests.Flags))
+ self.assertTrue(isinstance(GIMarshallingTests.Flags.VALUE2, GIMarshallingTests.Flags))
+ self.assertTrue(isinstance(GIMarshallingTests.Flags.VALUE3, GIMarshallingTests.Flags))
+ self.assertEquals(1 << 1, GIMarshallingTests.Flags.VALUE2)
+
+ def test_flags_in(self):
+ GIMarshallingTests.flags_in(GIMarshallingTests.Flags.VALUE2)
+ GIMarshallingTests.flags_in_zero(Number(0))
+
+ self.assertRaises(TypeError, GIMarshallingTests.flags_in, 1 << 1)
+ self.assertRaises(TypeError, GIMarshallingTests.flags_in, 'GIMarshallingTests.Flags.VALUE2')
+
+ def test_flags_out(self):
+ flags = GIMarshallingTests.flags_out()
+ self.assertTrue(isinstance(flags, GIMarshallingTests.Flags))
+ self.assertEquals(flags, GIMarshallingTests.Flags.VALUE2)
+
+ def test_flags_inout(self):
+ flags = GIMarshallingTests.flags_inout(GIMarshallingTests.Flags.VALUE2)
+ self.assertTrue(isinstance(flags, GIMarshallingTests.Flags))
+ self.assertEquals(flags, GIMarshallingTests.Flags.VALUE1)
+
+
+class TestStructure(unittest.TestCase):
+
+ def test_simple_struct(self):
+ self.assertTrue(issubclass(GIMarshallingTests.SimpleStruct, GObject.GPointer))
+
+ struct = GIMarshallingTests.SimpleStruct()
+ self.assertTrue(isinstance(struct, GIMarshallingTests.SimpleStruct))
+
+ self.assertEquals(0, struct.long_)
+ self.assertEquals(0, struct.int8)
+
+ struct.long_ = 6
+ struct.int8 = 7
+
+ self.assertEquals(6, struct.long_)
+ self.assertEquals(7, struct.int8)
+
+ del struct
+
+ def test_nested_struct(self):
+ struct = GIMarshallingTests.NestedStruct()
+
+ self.assertTrue(isinstance(struct.simple_struct, GIMarshallingTests.SimpleStruct))
+
+ struct.simple_struct.long_ = 42
+ self.assertEquals(42, struct.simple_struct.long_)
+
+ del struct
+
+ def test_not_simple_struct(self):
+ struct = GIMarshallingTests.NotSimpleStruct()
+ self.assertEquals(None, struct.pointer)
+
+ def test_simple_struct_return(self):
+ struct = GIMarshallingTests.simple_struct_return()
+
+ self.assertTrue(isinstance(struct, GIMarshallingTests.SimpleStruct))
+ self.assertEquals(6, struct.long_)
+ self.assertEquals(7, struct.int8)
+
+ del struct
+
+ def test_simple_struct_in(self):
+ struct = GIMarshallingTests.SimpleStruct()
+ struct.long_ = 6
+ struct.int8 = 7
+
+ GIMarshallingTests.simple_struct_in(struct)
+
+ del struct
+
+ struct = GIMarshallingTests.NestedStruct()
+
+ self.assertRaises(TypeError, GIMarshallingTests.simple_struct_in, struct)
+
+ del struct
+
+ self.assertRaises(TypeError, GIMarshallingTests.simple_struct_in, None)
+
+ def test_simple_struct_out(self):
+ struct = GIMarshallingTests.simple_struct_out()
+
+ self.assertTrue(isinstance(struct, GIMarshallingTests.SimpleStruct))
+ self.assertEquals(6, struct.long_)
+ self.assertEquals(7, struct.int8)
+
+ del struct
+
+ def test_simple_struct_inout(self):
+ in_struct = GIMarshallingTests.SimpleStruct()
+ in_struct.long_ = 6
+ in_struct.int8 = 7
+
+ out_struct = GIMarshallingTests.simple_struct_inout(in_struct)
+
+ self.assertTrue(isinstance(out_struct, GIMarshallingTests.SimpleStruct))
+ self.assertEquals(7, out_struct.long_)
+ self.assertEquals(6, out_struct.int8)
+
+ del in_struct
+ del out_struct
+
+ def test_simple_struct_method(self):
+ struct = GIMarshallingTests.SimpleStruct()
+ struct.long_ = 6
+ struct.int8 = 7
+
+ struct.method()
+
+ del struct
+
+ self.assertRaises(TypeError, GIMarshallingTests.SimpleStruct.method)
+
+
+ def test_pointer_struct(self):
+ self.assertTrue(issubclass(GIMarshallingTests.PointerStruct, GObject.GPointer))
+
+ struct = GIMarshallingTests.PointerStruct()
+ self.assertTrue(isinstance(struct, GIMarshallingTests.PointerStruct))
+
+ del struct
+
+ def test_pointer_struct_return(self):
+ struct = GIMarshallingTests.pointer_struct_return()
+
+ self.assertTrue(isinstance(struct, GIMarshallingTests.PointerStruct))
+ self.assertEquals(42, struct.long_)
+
+ del struct
+
+ def test_pointer_struct_in(self):
+ struct = GIMarshallingTests.PointerStruct()
+ struct.long_ = 42
+
+ GIMarshallingTests.pointer_struct_in(struct)
+
+ del struct
+
+ def test_pointer_struct_out(self):
+ struct = GIMarshallingTests.pointer_struct_out()
+
+ self.assertTrue(isinstance(struct, GIMarshallingTests.PointerStruct))
+ self.assertEquals(42, struct.long_)
+
+ del struct
+
+ def test_pointer_struct_inout(self):
+ in_struct = GIMarshallingTests.PointerStruct()
+ in_struct.long_ = 42
+
+ out_struct = GIMarshallingTests.pointer_struct_inout(in_struct)
+
+ self.assertTrue(isinstance(out_struct, GIMarshallingTests.PointerStruct))
+ self.assertEquals(0, out_struct.long_)
+
+ del in_struct
+ del out_struct
+
+ def test_boxed_struct(self):
+ self.assertTrue(issubclass(GIMarshallingTests.BoxedStruct, GObject.GBoxed))
+
+ struct = GIMarshallingTests.BoxedStruct()
+ self.assertTrue(isinstance(struct, GIMarshallingTests.BoxedStruct))
+
+ self.assertEquals(0, struct.long_)
+ self.assertEquals(None, struct.g_strv)
+
+ del struct
+
+ def test_boxed_struct_new(self):
+ struct = GIMarshallingTests.BoxedStruct.new()
+ self.assertTrue(isinstance(struct, GIMarshallingTests.BoxedStruct))
+
+ del struct
+
+ def test_boxed_struct_copy(self):
+ struct = GIMarshallingTests.BoxedStruct()
+
+ new_struct = struct.copy()
+ self.assertTrue(isinstance(new_struct, GIMarshallingTests.BoxedStruct))
+
+ del new_struct
+ del struct
+
+ def test_boxed_struct_return(self):
+ struct = GIMarshallingTests.boxed_struct_return()
+
+ self.assertTrue(isinstance(struct, GIMarshallingTests.BoxedStruct))
+ self.assertEquals(42, struct.long_)
+ self.assertEquals(('0', '1', '2'), struct.g_strv)
+
+ del struct
+
+ def test_boxed_struct_in(self):
+ struct = GIMarshallingTests.BoxedStruct()
+ struct.long_ = 42
+
+ GIMarshallingTests.boxed_struct_in(struct)
+
+ del struct
+
+ def test_boxed_struct_out(self):
+ struct = GIMarshallingTests.boxed_struct_out()
+
+ self.assertTrue(isinstance(struct, GIMarshallingTests.BoxedStruct))
+ self.assertEquals(42, struct.long_)
+
+ del struct
+
+ def test_boxed_struct_inout(self):
+ in_struct = GIMarshallingTests.BoxedStruct()
+ in_struct.long_ = 42
+
+ out_struct = GIMarshallingTests.boxed_struct_inout(in_struct)
+
+ self.assertTrue(isinstance(out_struct, GIMarshallingTests.BoxedStruct))
+ self.assertEquals(0, out_struct.long_)
+
+ del in_struct
+ del out_struct
+
+ def test_union(self):
+ union = GIMarshallingTests.Union()
+
+ self.assertTrue(isinstance(union, GIMarshallingTests.Union))
+
+ new_union = union.copy()
+ self.assertTrue(isinstance(new_union, GIMarshallingTests.Union))
+
+ del union
+ del new_union
+
+ def test_union_return(self):
+ union = GIMarshallingTests.union_return()
+
+ self.assertTrue(isinstance(union, GIMarshallingTests.Union))
+ self.assertEquals(42, union.long_)
+
+ del union
+
+ def test_union_in(self):
+ union = GIMarshallingTests.Union()
+ union.long_ = 42
+
+ GIMarshallingTests.union_in(union)
+
+ del union
+
+ def test_union_out(self):
+ union = GIMarshallingTests.union_out()
+
+ self.assertTrue(isinstance(union, GIMarshallingTests.Union))
+ self.assertEquals(42, union.long_)
+
+ del union
+
+ def test_union_inout(self):
+ in_union = GIMarshallingTests.Union()
+ in_union.long_ = 42
+
+ out_union = GIMarshallingTests.union_inout(in_union)
+
+ self.assertTrue(isinstance(out_union, GIMarshallingTests.Union))
+ self.assertEquals(0, out_union.long_)
+
+ del in_union
+ del out_union
+
+ def test_union_method(self):
+ union = GIMarshallingTests.Union()
+ union.long_ = 42
+
+ union.method()
+
+ del union
+
+ self.assertRaises(TypeError, GIMarshallingTests.Union.method)
+
+class TestGObject(unittest.TestCase):
+
+ def test_object(self):
+ self.assertTrue(issubclass(GIMarshallingTests.Object, GObject.GObject))
+
+ object_ = GIMarshallingTests.Object()
+ self.assertTrue(isinstance(object_, GIMarshallingTests.Object))
+ self.assertEquals(object_.__grefcount__, 1)
+
+ def test_object_new(self):
+ object_ = GIMarshallingTests.Object.new(42)
+ self.assertTrue(isinstance(object_, GIMarshallingTests.Object))
+ self.assertEquals(object_.__grefcount__, 1)
+
+ def test_object_int(self):
+ object_ = GIMarshallingTests.Object(int = 42)
+ self.assertEquals(object_.int_, 42)
+# FIXME: Don't work yet.
+# object_.int_ = 0
+# self.assertEquals(object_.int_, 0)
+
+ def test_object_static_method(self):
+ GIMarshallingTests.Object.static_method()
+
+ def test_object_method(self):
+ GIMarshallingTests.Object(int = 42).method()
+ self.assertRaises(TypeError, GIMarshallingTests.Object.method, GObject.GObject())
+ self.assertRaises(TypeError, GIMarshallingTests.Object.method)
+
+
+ def test_sub_object(self):
+ self.assertTrue(issubclass(GIMarshallingTests.SubObject, GIMarshallingTests.Object))
+
+ object_ = GIMarshallingTests.SubObject()
+ self.assertTrue(isinstance(object_, GIMarshallingTests.SubObject))
+
+ def test_sub_object_new(self):
+ self.assertRaises(TypeError, GIMarshallingTests.SubObject.new, 42)
+
+ def test_sub_object_static_method(self):
+ object_ = GIMarshallingTests.SubObject()
+ object_.static_method()
+
+ def test_sub_object_method(self):
+ object_ = GIMarshallingTests.SubObject(int = 42)
+ object_.method()
+
+ def test_sub_object_sub_method(self):
+ object_ = GIMarshallingTests.SubObject()
+ object_.sub_method()
+
+ def test_sub_object_overwritten_method(self):
+ object_ = GIMarshallingTests.SubObject()
+ object_.overwritten_method()
+
+ self.assertRaises(TypeError, GIMarshallingTests.SubObject.overwritten_method, GIMarshallingTests.Object())
+
+ def test_sub_object_int(self):
+ object_ = GIMarshallingTests.SubObject()
+ self.assertEquals(object_.int_, 0)
+# FIXME: Don't work yet.
+# object_.int_ = 42
+# self.assertEquals(object_.int_, 42)
+
+ def test_object_none_return(self):
+ object_ = GIMarshallingTests.object_none_return()
+ self.assertTrue(isinstance(object_, GIMarshallingTests.Object))
+ self.assertEquals(object_.__grefcount__, 2)
+
+ def test_object_full_return(self):
+ object_ = GIMarshallingTests.object_full_return()
+ self.assertTrue(isinstance(object_, GIMarshallingTests.Object))
+ self.assertEquals(object_.__grefcount__, 1)
+
+ def test_object_none_in(self):
+ object_ = GIMarshallingTests.Object(int = 42)
+ GIMarshallingTests.object_none_in(object_)
+ self.assertEquals(object_.__grefcount__, 1)
+
+ object_ = GIMarshallingTests.SubObject(int = 42)
+ GIMarshallingTests.object_none_in(object_)
+
+ object_ = GObject.GObject()
+ self.assertRaises(TypeError, GIMarshallingTests.object_none_in, object_)
+
+ self.assertRaises(TypeError, GIMarshallingTests.object_none_in, None)
+
+ def test_object_full_in(self):
+ object_ = GIMarshallingTests.Object(int = 42)
+ GIMarshallingTests.object_full_in(object_)
+ self.assertEquals(object_.__grefcount__, 1)
+
+ def test_object_none_out(self):
+ object_ = GIMarshallingTests.object_none_out()
+ self.assertTrue(isinstance(object_, GIMarshallingTests.Object))
+ self.assertEquals(object_.__grefcount__, 2)
+
+ new_object = GIMarshallingTests.object_none_out()
+ self.assertTrue(new_object is object_)
+
+ def test_object_full_out(self):
+ object_ = GIMarshallingTests.object_full_out()
+ self.assertTrue(isinstance(object_, GIMarshallingTests.Object))
+ self.assertEquals(object_.__grefcount__, 1)
+
+ def test_object_none_inout(self):
+ object_ = GIMarshallingTests.Object(int = 42)
+ new_object = GIMarshallingTests.object_none_inout(object_)
+
+ self.assertTrue(isinstance(new_object, GIMarshallingTests.Object))
+
+ self.assertFalse(object_ is new_object)
+
+ self.assertEquals(object_.__grefcount__, 1)
+ self.assertEquals(new_object.__grefcount__, 2)
+
+ new_new_object = GIMarshallingTests.object_none_inout(object_)
+ self.assertTrue(new_new_object is new_object)
+
+ GIMarshallingTests.object_none_inout(GIMarshallingTests.SubObject(int = 42))
+
+ def test_object_full_inout(self):
+ object_ = GIMarshallingTests.Object(int = 42)
+ new_object = GIMarshallingTests.object_full_inout(object_)
+
+ self.assertTrue(isinstance(new_object, GIMarshallingTests.Object))
+
+ self.assertFalse(object_ is new_object)
+
+ self.assertEquals(object_.__grefcount__, 1)
+ self.assertEquals(new_object.__grefcount__, 1)
+
+# FIXME: Doesn't actually return the same object.
+# def test_object_inout_same(self):
+# object_ = GIMarshallingTests.Object()
+# new_object = GIMarshallingTests.object_full_inout(object_)
+# self.assertTrue(object_ is new_object)
+# self.assertEquals(object_.__grefcount__, 1)
+
+
+class TestPythonGObject(unittest.TestCase):
+
+ class Object(GIMarshallingTests.Object):
+ __gtype_name__ = "Object"
+
+ def __init__(self, int):
+ GIMarshallingTests.Object.__init__(self)
+ self.val = None
+
+ def method(self):
+ # Don't call super, which asserts that self.int == 42.
+ pass
+
+ def do_method_int8_in(self, int8):
+ self.val = int8
+
+ def do_method_int8_out(self):
+ return 42
+
+ def do_method_with_default_implementation(self, int8):
+ self.props.int = int8 * 2
+
+ def test_object(self):
+ self.assertTrue(issubclass(self.Object, GIMarshallingTests.Object))
+
+ object_ = self.Object(int = 42)
+ self.assertTrue(isinstance(object_, self.Object))
+
+ def test_object_method(self):
+ self.Object(int = 0).method()
+
+ def test_object_vfuncs(self):
+ object_ = self.Object(int = 42)
+ object_.method_int8_in(84)
+ self.assertEqual(object_.val, 84)
+ self.assertEqual(object_.method_int8_out(), 42)
+
+ object_.method_with_default_implementation(42)
+ self.assertEqual(object_.val, 84)
+
+ class ObjectWithoutVFunc(GIMarshallingTests.Object):
+ __gtype_name__ = 'ObjectWithoutVFunc'
+
+ def __init__(self, int):
+ GIMarshallingTests.Object.__init__(self)
+
+ object_ = ObjectWithoutVFunc(int = 42)
+ object_.method_with_default_implementation(84)
+ self.assertEqual(object_.props.int, 84)
+
+ def test_dynamic_module(self):
+ from gi.module import DynamicGObjectModule
+ self.assertTrue(isinstance(GObject, DynamicGObjectModule))
+ # compare the same enum from both the pygobject attrs and gi GObject attrs
+ self.assertEquals(GObject.SIGNAL_ACTION, GObject.SignalFlags.ACTION)
+ # compare a static gobject attr with a dynamic GObject attr
+ self.assertEquals(GObject.GObject, gobject.GObject)
+
+class TestMultiOutputArgs(unittest.TestCase):
+
+ def test_int_out_out(self):
+ self.assertEquals((6, 7), GIMarshallingTests.int_out_out())
+
+ def test_int_return_out(self):
+ self.assertEquals((6, 7), GIMarshallingTests.int_return_out())
+
+
+# Interface
+
+class TestInterfaces(unittest.TestCase):
+
+ def test_wrapper(self):
+ self.assertTrue(issubclass(GIMarshallingTests.Interface, GObject.GInterface))
+ self.assertEquals(GIMarshallingTests.Interface.__gtype__.name, 'GIMarshallingTestsInterface')
+ self.assertRaises(NotImplementedError, GIMarshallingTests.Interface)
+
+ def test_implementation(self):
+
+ class TestInterfaceImpl(GObject.GObject, GIMarshallingTests.Interface):
+ __gtype_name__ = 'TestInterfaceImpl'
+ def __init__(self):
+ GObject.GObject.__init__(self)
+ self.val = None
+
+ def do_test_int8_in(self, int8):
+ self.val = int8
+
+ self.assertTrue(issubclass(TestInterfaceImpl, GIMarshallingTests.Interface))
+
+ instance = TestInterfaceImpl()
+ self.assertTrue(isinstance(instance, GIMarshallingTests.Interface))
+
+ GIMarshallingTests.test_interface_test_int8_in(instance, 42)
+ self.assertEquals(instance.val, 42)
+
+ class TestInterfaceImplA(TestInterfaceImpl):
+ __gtype_name__ = 'TestInterfaceImplA'
+
+ class TestInterfaceImplB(TestInterfaceImplA):
+ __gtype_name__ = 'TestInterfaceImplB'
+
+ instance = TestInterfaceImplA()
+ GIMarshallingTests.test_interface_test_int8_in(instance, 42)
+ self.assertEquals(instance.val, 42)
+
+ def define_implementor_without_gtype():
+ class TestInterfaceImpl(gobject.GObject, GIMarshallingTests.Interface):
+ def __init__(self):
+ gobject.GObject.__init__(self)
+ self.val = None
+
+ def do_test_int8_in(self, int8):
+ self.val = int8
+ self.assertRaises(RuntimeError, define_implementor_without_gtype)
+
+
+class TestOverrides(unittest.TestCase):
+
+ def test_constant(self):
+ self.assertEquals(GIMarshallingTests.OVERRIDES_CONSTANT, 7)
+
+ def test_struct(self):
+ # Test that the constructor has been overridden.
+ struct = GIMarshallingTests.OverridesStruct(42)
+
+ self.assertTrue(isinstance(struct, GIMarshallingTests.OverridesStruct))
+
+ # Test that the method has been overridden.
+ self.assertEquals(6, struct.method())
+
+ del struct
+
+ # Test that the overrides wrapper has been registered.
+ struct = GIMarshallingTests.overrides_struct_return()
+
+ self.assertTrue(isinstance(struct, GIMarshallingTests.OverridesStruct))
+
+ del struct
+
+ def test_object(self):
+ # Test that the constructor has been overridden.
+ object_ = GIMarshallingTests.OverridesObject(42)
+
+ self.assertTrue(isinstance(object_, GIMarshallingTests.OverridesObject))
+
+ # Test that the alternate constructor has been overridden.
+ object_ = GIMarshallingTests.OverridesObject.new(42)
+
+ self.assertTrue(isinstance(object_, GIMarshallingTests.OverridesObject))
+
+ # Test that the method has been overridden.
+ self.assertEquals(6, object_.method())
+
+ # Test that the overrides wrapper has been registered.
+ object_ = GIMarshallingTests.overrides_object_return()
+
+ self.assertTrue(isinstance(object_, GIMarshallingTests.OverridesObject))
+
+ def test_module_name(self):
+ self.assertEquals(GIMarshallingTests.OverridesStruct.__module__, 'gi.overrides.GIMarshallingTests')
+ self.assertEquals(GObject.InitiallyUnowned.__module__, 'gi.repository.GObject')
diff --git a/gi/tests/test_overrides.py b/gi/tests/test_overrides.py
new file mode 100644
index 00000000..b5af4d12
--- /dev/null
+++ b/gi/tests/test_overrides.py
@@ -0,0 +1,132 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+
+import pygtk
+pygtk.require("2.0")
+
+import unittest
+
+import sys
+sys.path.insert(0, "../")
+
+from gi.repository import GObject
+from gi.repository import Gdk
+from gi.repository import Gtk
+import gi.overrides as overrides
+
+class TestGdk(unittest.TestCase):
+
+ def test_color(self):
+ color = Gdk.Color(100, 200, 300)
+ self.assertEquals(color.red, 100)
+ self.assertEquals(color.green, 200)
+ self.assertEquals(color.blue, 300)
+
+class TestGtk(unittest.TestCase):
+ def test_uimanager(self):
+ self.assertEquals(Gtk.UIManager, overrides.Gtk.UIManager)
+ ui = Gtk.UIManager()
+ ui.add_ui_from_string(
+"""
+<ui>
+ <menubar name="menubar1"></menubar>
+</ui>
+"""
+)
+ menubar = ui.get_widget("/menubar1")
+ self.assertEquals(type(menubar), Gtk.MenuBar)
+
+ def test_actiongroup(self):
+ self.assertEquals(Gtk.ActionGroup, overrides.Gtk.ActionGroup)
+ action_group = Gtk.ActionGroup (name = 'TestActionGroup')
+
+ action_group.add_actions ([
+ ('test-action1', None, 'Test Action 1',
+ None, None, None),
+ ('test-action2', Gtk.STOCK_COPY, 'Test Action 2',
+ None, None, None)])
+ action_group.add_toggle_actions([
+ ('test-toggle-action1', None, 'Test Toggle Action 1',
+ None, None, None, False),
+ ('test-toggle-action2', Gtk.STOCK_COPY, 'Test Toggle Action 2',
+ None, None, None, True)])
+ action_group.add_radio_actions([
+ ('test-radio-action1', None, 'Test Radio Action 1'),
+ ('test-radio-action2', Gtk.STOCK_COPY, 'Test Radio Action 2')], 1, None)
+
+ expected_results = (('test-action1', Gtk.Action),
+ ('test-action2', Gtk.Action),
+ ('test-toggle-action1', Gtk.ToggleAction),
+ ('test-toggle-action2', Gtk.ToggleAction),
+ ('test-radio-action1', Gtk.RadioAction),
+ ('test-radio-action2', Gtk.RadioAction))
+
+ for action, cmp in zip(action_group.list_actions(), expected_results):
+ a = (action.get_name(), type(action))
+ self.assertEquals(a,cmp)
+
+ def test_builder(self):
+ self.assertEquals(Gtk.Builder, overrides.Gtk.Builder)
+
+ class SignalTest(GObject.GObject):
+ __gtype_name__ = "GIOverrideSignalTest"
+ __gsignals__ = {
+ "test-signal": (GObject.SIGNAL_RUN_FIRST,
+ GObject.TYPE_NONE,
+ []),
+ }
+
+
+ class SignalCheck:
+ def __init__(self):
+ self.sentinel = 0
+
+ def on_signal_1(self, *args):
+ self.sentinel += 1
+
+ def on_signal_3(self, *args):
+ self.sentinel += 3
+
+ signal_checker = SignalCheck()
+ builder = Gtk.Builder()
+
+ # add object1 to the builder
+ builder.add_from_string(
+"""
+<interface>
+ <object class="GIOverrideSignalTest" id="object1">
+ <signal name="test-signal" handler="on_signal_1" />
+ </object>
+</interface>
+""")
+
+ # only add object3 to the builder
+ builder.add_objects_from_string(
+"""
+<interface>
+ <object class="GIOverrideSignalTest" id="object2">
+ <signal name="test-signal" handler="on_signal_2" />
+ </object>
+ <object class="GIOverrideSignalTest" id="object3">
+ <signal name="test-signal" handler="on_signal_3" />
+ </object>
+ <object class="GIOverrideSignalTest" id="object4">
+ <signal name="test-signal" handler="on_signal_4" />
+ </object>
+</interface>
+
+""",
+ ['object3'])
+
+ # hook up signals
+ builder.connect_signals(signal_checker)
+
+ # call their notify signals and check sentinel
+ objects = builder.get_objects()
+ self.assertEquals(len(objects), 2)
+ for obj in objects:
+ obj.emit('test-signal')
+
+ self.assertEquals(signal_checker.sentinel, 4)
+
+
diff --git a/gi/types.py b/gi/types.py
new file mode 100644
index 00000000..8ac9cab4
--- /dev/null
+++ b/gi/types.py
@@ -0,0 +1,180 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org>
+#
+# types.py: base types for introspected items.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+from __future__ import absolute_import
+
+import sys
+import gobject
+
+from ._gi import \
+ InterfaceInfo, \
+ ObjectInfo, \
+ StructInfo, \
+ set_object_has_new_constructor, \
+ register_interface_info, \
+ hook_up_vfunc_implementation
+
+
+def Function(info):
+
+ def function(*args):
+ return info.invoke(*args)
+ function.__info__ = info
+ function.__name__ = info.get_name()
+ function.__module__ = info.get_namespace()
+
+ return function
+
+
+def Constructor(info):
+
+ def constructor(cls, *args):
+ cls_name = info.get_container().get_name()
+ if cls.__name__ != cls_name:
+ raise TypeError, '%s constructor cannot be used to create instances of a subclass' % cls_name
+ return info.invoke(cls, *args)
+
+ constructor.__info__ = info
+ constructor.__name__ = info.get_name()
+ constructor.__module__ = info.get_namespace()
+
+ return constructor
+
+
+class MetaClassHelper(object):
+
+ def _setup_constructors(cls):
+ for method_info in cls.__info__.get_methods():
+ if method_info.is_constructor():
+ name = method_info.get_name()
+ constructor = classmethod(Constructor(method_info))
+ setattr(cls, name, constructor)
+
+ def _setup_methods(cls):
+ for method_info in cls.__info__.get_methods():
+ name = method_info.get_name()
+ function = Function(method_info)
+ if method_info.is_method():
+ method = function
+ elif method_info.is_constructor():
+ continue
+ else:
+ method = staticmethod(function)
+ setattr(cls, name, method)
+
+ def _setup_fields(cls):
+ for field_info in cls.__info__.get_fields():
+ name = field_info.get_name().replace('-', '_')
+ setattr(cls, name, property(field_info.get_value, field_info.set_value))
+
+ def _setup_constants(cls):
+ for constant_info in cls.__info__.get_constants():
+ name = constant_info.get_name()
+ value = constant_info.get_value()
+ setattr(cls, name, value)
+
+ def _setup_vfuncs(cls):
+ for base in cls.__bases__:
+ if not hasattr(base, '__info__') or \
+ not hasattr(base.__info__, 'get_vfuncs'):
+ continue
+ for vfunc_info in base.__info__.get_vfuncs():
+ vfunc = getattr(cls, 'do_' + vfunc_info.get_name(), None)
+ if vfunc is None and isinstance(base.__info__, InterfaceInfo) and \
+ not hasattr(cls, vfunc_info.get_name()):
+ raise TypeError('Class implementing %s.%s should implement '
+ 'the method do_%s()' % (base.__info__.get_namespace(),
+ base.__info__.get_name(),
+ vfunc_info.get_name()))
+ elif vfunc is not None and not \
+ is_function_in_classes(vfunc.im_func, cls.__bases__):
+ hook_up_vfunc_implementation(vfunc_info, cls.__gtype__,
+ vfunc)
+
+def is_function_in_classes(function, classes):
+ for klass in classes:
+ if function in klass.__dict__.values():
+ return True
+ elif is_function_in_classes(function, klass.__bases__):
+ return True
+ return False
+
+class GObjectMeta(gobject.GObjectMeta, MetaClassHelper):
+
+ def __init__(cls, name, bases, dict_):
+ super(GObjectMeta, cls).__init__(name, bases, dict_)
+
+ is_gi_defined = False
+ if cls.__module__ == 'gi.repository.' + cls.__info__.get_namespace():
+ is_gi_defined = True
+
+ is_python_defined = False
+ if not is_gi_defined and cls.__module__ != GObjectMeta.__module__:
+ is_python_defined = True
+
+ if is_python_defined:
+ cls._setup_vfuncs()
+ elif is_gi_defined:
+ cls._setup_methods()
+ cls._setup_constants()
+
+ if isinstance(cls.__info__, ObjectInfo):
+ cls._setup_fields()
+ cls._setup_constructors()
+ set_object_has_new_constructor(cls.__info__.get_g_type())
+ elif isinstance(cls.__info__, InterfaceInfo):
+ register_interface_info(cls.__info__.get_g_type())
+
+class StructMeta(type, MetaClassHelper):
+
+ def __init__(cls, name, bases, dict_):
+ super(StructMeta, cls).__init__(name, bases, dict_)
+
+ # Avoid touching anything else than the base class.
+ g_type = cls.__info__.get_g_type()
+ if g_type != gobject.TYPE_INVALID and g_type.pytype is not None:
+ return
+
+ cls._setup_fields()
+ cls._setup_methods()
+ cls._setup_constructors()
+
+
+def override(type_):
+ g_type = type_.__info__.get_g_type()
+ if g_type != gobject.TYPE_INVALID:
+ g_type.pytype = type_
+ return type_
+
+class Enum(int):
+ __info__ = None
+ def __init__(self, value):
+ int.__init__(value)
+
+ def __repr__(self):
+ value_name = str(self)
+ for value_info in self.__info__.get_values():
+ if self == value_info.get_value():
+ value_name = value_info.get_name().upper()
+ return "<enum %s of type %s.%s>" % (value_name,
+ self.__info__.get_namespace(),
+ self.__info__.get_name())
diff --git a/pre-commit.hook b/pre-commit.hook
new file mode 100755
index 00000000..13979332
--- /dev/null
+++ b/pre-commit.hook
@@ -0,0 +1,39 @@
+#!/bin/bash
+#
+# Check that the code follows a consistant code style
+#
+
+# Check for existence of astyle, and error out if not present.
+if ! builtin type -P astyle; then
+ echo "PyGI git pre-commit hook:"
+ echo "Did not find astyle, please install it before continuing."
+ exit 1
+fi
+
+ASTYLE_PARAMETERS="-p -d -c -S -U -M60"
+
+echo "--Checking style--"
+for file in `git-diff-index --cached --name-only HEAD --diff-filter=ACMR| grep "\.c$"` ; do
+ # nf is the temporary checkout. This makes sure we check against the
+ # revision in the index (and not the checked out version).
+ nf=`git checkout-index --temp ${file} | cut -f 1`
+ newfile=`mktemp /tmp/${nf}.XXXXXX` || exit 1
+ astyle ${ASTYLE_PARAMETERS} < $nf > $newfile 2>> /dev/null
+ diff -u -p "${nf}" "${newfile}"
+ r=$?
+ rm "${newfile}"
+ rm "${nf}"
+ if [ $r != 0 ] ; then
+echo "================================================================================================="
+echo " Code style error in: $file "
+echo " "
+echo " Please fix before committing. Don't forget to run git add before trying to commit again. "
+echo " If the whole file is to be committed, this should work (run from the top-level directory): "
+echo " "
+echo " astyle ${ASTYLE_PARAMETERS} $file; git add $file; git commit"
+echo " "
+echo "================================================================================================="
+ exit 1
+ fi
+done
+echo "--Checking style pass--"
diff --git a/pygi-Makefile.am b/pygi-Makefile.am
new file mode 100644
index 00000000..af67cda8
--- /dev/null
+++ b/pygi-Makefile.am
@@ -0,0 +1,28 @@
+ACLOCAL_AMFLAGS = -I m4
+
+AM_CFLAGS = \
+ -Wall \
+ -g
+
+SUBDIRS = \
+ gi \
+ tests \
+ examples
+
+EXTRA_DIST = \
+ autogen.sh \
+ pygi-convert.sh \
+ HACKING
+
+check.gdb:
+ cd tests && $(MAKE) check.gdb
+
+%.gdb:
+ cd tests && $(MAKE) $*.gdb
+
+check.valgrind:
+ cd tests && $(MAKE) check.valgrind
+
+%.valgrind:
+ cd tests && $(MAKE) $*.valgrind
+
diff --git a/pygi-configure.ac b/pygi-configure.ac
new file mode 100644
index 00000000..30c765b0
--- /dev/null
+++ b/pygi-configure.ac
@@ -0,0 +1,60 @@
+AC_INIT(pygi, 0.6.1)
+
+AM_INIT_AUTOMAKE(foreign)
+AC_CONFIG_HEADERS(config.h)
+AC_CONFIG_MACRO_DIR(m4)
+
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES(yes)])
+
+AM_MAINTAINER_MODE
+
+AC_ISC_POSIX
+AC_PROG_CC
+AM_PROG_CC_STDC
+AC_HEADER_STDC
+
+AM_PROG_LIBTOOL
+
+# Python
+AM_PATH_PYTHON(2.5.2)
+
+AC_PATH_TOOL(PYTHON_CONFIG, "python${PYTHON_VERSION}-config")
+if test -z "$PYTHON_CONFIG"; then
+ AC_PATH_TOOL(PYTHON_CONFIG, "python-config-${PYTHON_VERSION}")
+ if test -z "$PYTHON_CONFIG"; then
+ AC_MSG_ERROR(Python development tools not found)
+ fi
+fi
+PYTHON_INCLUDES=`$PYTHON_CONFIG --includes`
+AC_SUBST(PYTHON_INCLUDES)
+
+save_CPPFLAGS="${CPPFLAGS}"
+CPPFLAGS="${CPPFLAGS} ${PYTHON_INCLUDES}"
+AC_CHECK_HEADER(Python.h, , AC_MSG_ERROR(Python headers not found))
+CPPFLAGS="${save_CPPFLAGS}"
+
+# FFI
+PKG_CHECK_MODULES(FFI, libffi >= 3.0)
+
+# GNOME
+PKG_CHECK_MODULES(GNOME,
+ glib-2.0 >= 2.22.4
+ gobject-introspection-1.0 >= 0.6.14
+ pygobject-2.0 >= 2.21.1
+ pycairo >= 1.0.2
+)
+
+INTROSPECTION_SCANNER=`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0`
+INTROSPECTION_COMPILER=`$PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0`
+
+AC_SUBST(INTROSPECTION_SCANNER)
+AC_SUBST(INTROSPECTION_COMPILER)
+
+AC_OUTPUT(
+ Makefile
+ examples/Makefile
+ gi/Makefile
+ gi/repository/Makefile
+ gi/overrides/Makefile
+ tests/Makefile
+)
diff --git a/pygi-convert.sh b/pygi-convert.sh
new file mode 100644
index 00000000..10b3de53
--- /dev/null
+++ b/pygi-convert.sh
@@ -0,0 +1,152 @@
+#!/bin/sh
+
+FILES_TO_CONVERT="$(find sugar-pygi -iname \*.py) $(find sugar-toolkit-pygi -iname \*.py) sugar-pygi/bin/sugar-session"
+
+for f in $FILES_TO_CONVERT; do
+ perl -i -0 \
+ -pe "s/import gconf\n/from gi.repository import GConf\n/g;" \
+ -pe "s/gconf\./GConf\./g;" \
+ -pe "s/GConf\.client_get_default/GConf.Client.get_default/g;" \
+ -pe "s/GConf\.CLIENT_/GConf.ClientPreloadType./g;" \
+ -pe "s/gconf_client.notify_add\('\/desktop\/sugar\/collaboration\/publish_gadget',/return;gconf_client.notify_add\('\/desktop\/sugar\/collaboration\/publish_gadget',/g;" \
+\
+ -pe "s/import gtk\n/from gi.repository import Gtk\n/g;" \
+ -pe "s/gtk\./Gtk\./g;" \
+ -pe "s/Gtk.SIZE_GROUP_/Gtk.SizeGroupMode./g;" \
+ -pe "s/Gtk.POLICY_/Gtk.PolicyType./g;" \
+ -pe "s/Gtk.STATE_/Gtk.StateType./g;" \
+ -pe "s/Gtk.TARGET_/Gtk.TargetFlags./g;" \
+ -pe "s/Gtk.SHADOW_NONE/Gtk.ShadowType.NONE/g;" \
+ -pe "s/Gtk.ICON_SIZE_/Gtk.IconSize./g;" \
+ -pe "s/Gtk.IMAGE_/Gtk.ImageType./g;" \
+ -pe "s/Gtk.SELECTION_/Gtk.SelectionMode./g;" \
+ -pe "s/Gtk.CELL_RENDERER_MODE_/Gtk.CellRendererMode./g;" \
+ -pe "s/Gtk.TREE_VIEW_COLUMN_/Gtk.TreeViewColumnSizing./g;" \
+ -pe "s/Gtk.CORNER_/Gtk.CornerType./g;" \
+ -pe "s/Gtk.settings_get_default/Gtk.Settings.get_default/g;" \
+ -pe "s/Gtk.icon_theme_get_default/Gtk.IconTheme.get_default/g;" \
+ -pe "s/.window.set_type_hint/.set_type_hint/g;" \
+ -pe "s/self.drag_source_unset\(\)/Gtk.drag_source_unset\(self\)/g;" \
+ -pe "s/self.drag_dest_unset\(\)/Gtk.drag_dest_unset\(self\)/g;" \
+ -pe "s/Gtk.ListStore\(([^\)]*)\)/Gtk.ListStore.newv\(\[\1\]\)/g;" \
+ -pe "s/self._model.filter_new\(\)/Gtk.TreeModelFilter.new\(self._model, None\)/g;" \
+ -pe "#s/Gtk.ScrolledWindow\(\)/Gtk.ScrolledWindow\(None, None\)/g;" \
+ -pe "#s/Gtk.Window.__init__\(self\)/Gtk.Window.__init__\(Gtk.WindowType.TOPLEVEL\)/g;" \
+ -pe "#s/\.child/.get_child\(\)/g;" \
+\
+ -pe "s/column.pack_start\(([^,\)]*)\)/column.pack_start\(\1, True\)/g;" \
+ -pe "s/pack_start\(([^,\)]*)\)/pack_start\(\1, True, True, 0\)/g;" \
+ -pe "s/pack_start\(([^,]*), fill=([^,\)]*)\)/pack_start\(\1, True, \2, 0\)/g;" \
+ -pe "s/pack_start\(([^,]*), expand=([^,\)]*)\)/pack_start\(\1, \2, True, 0\)/g;" \
+ -pe "s/pack_start\(([^,]*),(\s*)padding=([A-Za-z0-9._]*)\)/pack_start\(\1,\2True, True,\2\3\)/g;" \
+ -pe "#s/Gtk.HBox\(\)/Gtk.HBox\(False, 0\)/g;" \
+ -pe "#s/Gtk.VBox\(\)/Gtk.VBox\(False, 0\)/g;" \
+ -pe "s/Gtk.Label\(([^,\)]+)\)/Gtk.Label\(label=\1\)/g;" \
+ -pe "s/Gtk.AccelLabel\(([^,\)]+)\)/Gtk.AccelLabel\(label=\1\)/g;" \
+ -pe "s/len\(self._content.get_children\(\)\) > 0/self._content.get_children\(\)/g;" \
+ -pe "s/len\(self.menu.get_children\(\)\) > 0/self.menu.get_children\(\)/g;" \
+\
+ -pe "s/Gtk\..*\.__init__/gobject.GObject.__init__/g;" \
+\
+ -pe "s/Gtk.gdk\./Gdk\./g;" \
+ -pe "s/Gdk.screen_width/Gdk.Screen.width/g;" \
+ -pe "s/Gdk.screen_height/Gdk.Screen.height/g;" \
+ -pe "s/Gdk.screen_get_default/Gdk.Screen.get_default/g;" \
+ -pe "s/Gdk.WINDOW_TYPE_HINT_/Gdk.WindowTypeHint./g;" \
+ -pe "s/Gdk\.Rectangle/Gdk.rectangle_new/g;" \
+ -pe "s/Gdk.BUTTON_PRESS_MASK/Gdk.EventMask.BUTTON_PRESS_MASK/g;" \
+ -pe "s/Gdk.POINTER_MOTION_HINT_MASK/Gdk.EventMask.POINTER_MOTION_HINT_MASK/g;" \
+ -pe "s/Gdk.VISIBILITY_NOTIFY_MASK/Gdk.EventMask.VISIBILITY_NOTIFY_MASK/g;" \
+ -pe "s/Gdk.Color\(/Gdk.color_new\(/g;" \
+ -pe "s/Gdk.BUTTON_PRESS/Gdk.EventType.BUTTON_PRESS/g;" \
+\
+ -pe "s/import pango\n/from gi.repository import Pango\n/g;" \
+ -pe "s/pango\./Pango\./g;" \
+ -pe "s/Pango\.FontDescription/Pango\.Font\.description_from_string/g;" \
+ -pe "s/Pango.ELLIPSIZE_/Pango.EllipsizeMode./g;" \
+\
+ -pe "s/import hippo\n/from gi.repository import Hippo\n/g;" \
+ -pe "s/hippo\./Hippo\./g;" \
+ -pe "s/Hippo\..*\.__init__/gobject.GObject.__init__/g;" \
+ -pe "#s/insert_sorted\(([^,\)]*), ([^,\)]*), ([^,\)]*)\)/insert_sorted\(\1, \2, \3, None\)/g;" \
+ -pe "s/self\._box\.insert_sorted/#self\._box\.insert_sorted/g;" \
+ -pe "s/self._box.append\(([^,\)]*)\)/self._box.append\(\1, 0\)/g;" \
+ -pe "s/self._box.sort\(([^,\)]*)\)/self._box.sort\(\1, None\)/g;" \
+\
+ -pe "s/import wnck\n/from gi.repository import Wnck\n/g;" \
+ -pe "s/wnck\./Wnck\./g;" \
+ -pe "s/Wnck.screen_get_default/Wnck.Screen.get_default/g;" \
+ -pe "s/Wnck.WINDOW_/Wnck.WindowType./g;" \
+\
+ -pe "s/from sugar import _sugarext\n/from gi.repository import SugarExt\n/g;" \
+ -pe "s/_sugarext\.ICON_ENTRY_/SugarExt.SexyIconEntryPosition./g;" \
+ -pe "s/_sugarext\.IconEntry/SugarExt.SexyIconEntry/g;" \
+ -pe "s/_sugarext\.SMClientXSMP/SugarExt.GsmClientXSMP/g;" \
+ -pe "s/_sugarext\.VolumeAlsa/SugarExt.AcmeVolumeAlsa/g;" \
+ -pe "s/_sugarext\./SugarExt\./g;" \
+\
+ -pe "s/import gtksourceview2\n/from gi.repository import GtkSource\n/g;" \
+\
+ -pe "#s/import cairo\n/from gi.repository import cairo\n/g;" \
+\
+ -pe "s/SugarExt.xsmp_init\(\)/'mec'/g;" \
+ -pe "s/SugarExt.xsmp_run\(\)/#SugarExt.xsmp_run\(\)/g;" \
+ -pe "s/SugarExt.session_create_global\(\)/None #SugarExt.session_create_global\(\)/g;" \
+ -pe "s/self.session.start\(\)/return #self.session.start\(\)/g;" \
+\
+ -pe "s/self._box.sort\(self._layout.compare_activities, None\)/pass #self._box.sort(self._layout.compare_activities, None)/g;" \
+ -pe "s/attach_points = info.get_attach_points/has_attach_points_, attach_points = info.get_attach_points/g;" \
+ -pe "s/attach_points\[0\]\[0\]/attach_points\[0\].x/g;" \
+ -pe "s/attach_points\[0\]\[1\]/attach_points\[0\].y/g;" \
+ -pe "s/has_attach_points_/return 0,0;has_attach_points_/g;" \
+ -pe "s/gobject.GObject.__init__\(self, self._model_filter\)/gobject.GObject.__init__\(self, model=self._model_filter\)/g;" \
+ -pe "s/self._model_filter.set_visible_func/return;self._model_filter.set_visible_func/g;" \
+ -pe "s/buddies_column.set_cell_data_func/return;buddies_column.set_cell_data_func/g;" \
+ -pe "s/ column.set_cell_data_func/# column.set_cell_data_func/g;" \
+ -pe "s/Hippo\.cairo_surface_from_gdk_pixbuf/SugarExt\.cairo_surface_from_pixbuf/g;" \
+ $f
+done
+
+NEED_GOBJECT=`grep -R -l gobject\. $FILES_TO_CONVERT | xargs grep -nL import\ gobject`
+for f in $NEED_GOBJECT; do
+ sed -i "/import Gdk/ i\import gobject" $f
+done
+
+NEED_GOBJECT=`grep -R -l gobject\. $FILES_TO_CONVERT | xargs grep -nL import\ gobject`
+for f in $NEED_GOBJECT; do
+ sed -i "/import Gtk/ i\import gobject" $f
+done
+
+NEED_GOBJECT=`grep -R -l gobject\. $FILES_TO_CONVERT | xargs grep -nL import\ gobject`
+for f in $NEED_GOBJECT; do
+ sed -i "/import Hippo/ i\import gobject" $f
+done
+
+NEED_GDK=`grep -R -l Gdk\. $FILES_TO_CONVERT | xargs grep -nL import\ Gdk`
+for f in $NEED_GDK; do
+ sed -i "/import Gtk/ i\from gi.repository import Gdk" $f
+done
+
+NEED_SUGAR_EXT=`grep -R -l SugarExt\. $FILES_TO_CONVERT | xargs grep -nL import\ SugarExt`
+for f in $NEED_SUGAR_EXT; do
+ sed -i "/import cairo/ i\from gi.repository import SugarExt" $f
+done
+
+for f in sugar-pygi/src/jarabe/util/emulator.py sugar-pygi/bin/sugar-session; do
+ sed -i "/import Gdk/ a\Gdk.init_check([])" $f
+ sed -i "/import Gtk/ a\Gtk.init_check([])" $f
+done
+
+sed -i "/Gdk.threads_init()/ i\gobject.threads_init()" sugar-pygi/bin/sugar-session
+
+# Disable treeview stuff
+sed -i 's/class CellRendererIcon(Gtk.GenericCellRenderer):/class CellRendererIcon(Gtk.CellRenderer):/g' sugar-toolkit-pygi/src/sugar/graphics/icon.py
+
+#sed -i '/def get_icon_state(base_name, perc, step=5):/ i\"""' sugar-toolkit-pygi/src/sugar/graphics/icon.py
+
+#sed -i 's/from sugar.graphics.icon import Icon, CellRendererIcon/from sugar.graphics.icon import Icon/g' sugar-pygi/src/jarabe/desktop/activitieslist.py
+
+#sed -i '/class CellRendererFavorite(CellRendererIcon):/ i\"""' sugar-pygi/src/jarabe/desktop/activitieslist.py
+#sed -i '/def get_icon_state(base_name, perc, step=5):/ i\"""' sugar-toolkit-pygi/src/sugar/graphics/icon.py
+
+
diff --git a/pygi.doap b/pygi.doap
new file mode 100644
index 00000000..f63820cf
--- /dev/null
+++ b/pygi.doap
@@ -0,0 +1,34 @@
+<Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+ xmlns:foaf="http://xmlns.com/foaf/0.1/"
+ xmlns:gnome="http://api.gnome.org/doap-extensions#"
+ xmlns="http://usefulinc.com/ns/doap#">
+
+ <name xml:lang="en">PyGI</name>
+ <shortdesc xml:lang="en">Python dynamic bindings based on GObject-Introspection</shortdesc>
+ <category rdf:resource="http://api.gnome.org/doap-extensions#bindings" />
+ <mailing-list rdf:resource="http://www.daa.com.au/mailman/listinfo/pygtk" />
+ <homepage rdf:resource="http://live.gnome.org/PyGi" />
+
+ <maintainer>
+ <foaf:Person>
+ <foaf:name>Simon van der Linden</foaf:name>
+ <foaf:mbox rdf:resource="mailto:svdlinden@src.gnome.org" />
+ <gnome:userid>svdlinden</gnome:userid>
+ </foaf:Person>
+ </maintainer>
+ <maintainer>
+ <foaf:Person>
+ <foaf:name>Tomeu Vizoso</foaf:name>
+ <foaf:mbox rdf:resource="mailto:tomeu@sugarlabs.org" />
+ <gnome:userid>tomeuv</gnome:userid>
+ </foaf:Person>
+ </maintainer>
+ <maintainer>
+ <foaf:Person>
+ <foaf:name>Zach Goldberg</foaf:name>
+ <foaf:mbox rdf:resource="mailto:zach@zachgoldberg.com" />
+ <gnome:userid>zgoldberg</gnome:userid>
+ </foaf:Person>
+ </maintainer>
+</Project>