diff options
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 Binary files differnew file mode 100644 index 00000000..eb5885f8 --- /dev/null +++ b/gi/demos/gtk-demo/demos/data/alphatest.png diff --git a/gi/demos/gtk-demo/demos/data/apple-red.png b/gi/demos/gtk-demo/demos/data/apple-red.png Binary files differnew file mode 100644 index 00000000..b0a24e94 --- /dev/null +++ b/gi/demos/gtk-demo/demos/data/apple-red.png diff --git a/gi/demos/gtk-demo/demos/data/background.jpg b/gi/demos/gtk-demo/demos/data/background.jpg Binary files differnew file mode 100644 index 00000000..86c006aa --- /dev/null +++ b/gi/demos/gtk-demo/demos/data/background.jpg 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 Binary files differnew file mode 100644 index 00000000..ac986c8e --- /dev/null +++ b/gi/demos/gtk-demo/demos/data/floppybuddy.gif diff --git a/gi/demos/gtk-demo/demos/data/gnome-applets.png b/gi/demos/gtk-demo/demos/data/gnome-applets.png Binary files differnew file mode 100644 index 00000000..8d3549e9 --- /dev/null +++ b/gi/demos/gtk-demo/demos/data/gnome-applets.png diff --git a/gi/demos/gtk-demo/demos/data/gnome-calendar.png b/gi/demos/gtk-demo/demos/data/gnome-calendar.png Binary files differnew file mode 100644 index 00000000..889f329a --- /dev/null +++ b/gi/demos/gtk-demo/demos/data/gnome-calendar.png diff --git a/gi/demos/gtk-demo/demos/data/gnome-foot.png b/gi/demos/gtk-demo/demos/data/gnome-foot.png Binary files differnew file mode 100644 index 00000000..04766585 --- /dev/null +++ b/gi/demos/gtk-demo/demos/data/gnome-foot.png diff --git a/gi/demos/gtk-demo/demos/data/gnome-fs-directory.png b/gi/demos/gtk-demo/demos/data/gnome-fs-directory.png Binary files differnew file mode 100644 index 00000000..05921a66 --- /dev/null +++ b/gi/demos/gtk-demo/demos/data/gnome-fs-directory.png diff --git a/gi/demos/gtk-demo/demos/data/gnome-fs-regular.png b/gi/demos/gtk-demo/demos/data/gnome-fs-regular.png Binary files differnew file mode 100644 index 00000000..0f5019c8 --- /dev/null +++ b/gi/demos/gtk-demo/demos/data/gnome-fs-regular.png diff --git a/gi/demos/gtk-demo/demos/data/gnome-gimp.png b/gi/demos/gtk-demo/demos/data/gnome-gimp.png Binary files differnew file mode 100644 index 00000000..f6bbc6d3 --- /dev/null +++ b/gi/demos/gtk-demo/demos/data/gnome-gimp.png diff --git a/gi/demos/gtk-demo/demos/data/gnome-gmush.png b/gi/demos/gtk-demo/demos/data/gnome-gmush.png Binary files differnew file mode 100644 index 00000000..0a4b0d04 --- /dev/null +++ b/gi/demos/gtk-demo/demos/data/gnome-gmush.png diff --git a/gi/demos/gtk-demo/demos/data/gnome-gsame.png b/gi/demos/gtk-demo/demos/data/gnome-gsame.png Binary files differnew file mode 100644 index 00000000..01c06115 --- /dev/null +++ b/gi/demos/gtk-demo/demos/data/gnome-gsame.png diff --git a/gi/demos/gtk-demo/demos/data/gnu-keys.png b/gi/demos/gtk-demo/demos/data/gnu-keys.png Binary files differnew file mode 100644 index 00000000..58a33770 --- /dev/null +++ b/gi/demos/gtk-demo/demos/data/gnu-keys.png diff --git a/gi/demos/gtk-demo/demos/data/gtk-logo-rgb.gif b/gi/demos/gtk-demo/demos/data/gtk-logo-rgb.gif Binary files differnew file mode 100644 index 00000000..63c622b9 --- /dev/null +++ b/gi/demos/gtk-demo/demos/data/gtk-logo-rgb.gif 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> |