[pygobject] Remove static MainLoop, MainContext, and some GSource bindings



commit 191cf45af44850fc29f2392ae2f0042aed6d13a9
Author: Martin Pitt <martinpitt gnome org>
Date:   Fri Oct 19 09:55:05 2012 +0200

    Remove static MainLoop, MainContext, and some GSource bindings
    
    glib's MainLoop and MainContext are fully introspectable these days, so remove
    our static bindings. This reduces our code, as well enables GLib API which
    hasn't been available through the static bindings before.
    
    This also requires dropping our custom static types for GLib Source, Timeout,
    and Idle. The latter two work fine with introspection and just need tiny
    overrides for a backwards compatible API. g_source_new() is not introspectable,
    though, so we need to keep our static wrappers for that. Move them from
    gi/_glib/pygsource.c to gi/pygi-source.c, so that it can use the GI API.
    
    Note that gi/_glib/pygsource.[hc] is still required for the static PollFD type
    which is used by the static IOChannel binding. Once the latter goes away,
    PollFD can be dropped as well.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=686443

 docs/Makefile.am                      |    6 +-
 docs/reference/pyglib-classes.xml     |    2 -
 docs/reference/pyglib-constants.xml   |   53 ---
 docs/reference/pyglib-functions.xml   |   58 ---
 docs/reference/pyglib-maincontext.xml |  152 --------
 docs/reference/pyglib-mainloop.xml    |  202 -----------
 gi/Makefile.am                        |    2 +
 gi/_glib/Makefile.am                  |    4 -
 gi/_glib/__init__.py                  |   12 -
 gi/_glib/glibmodule.c                 |   45 +---
 gi/_glib/pyglib.c                     |   15 -
 gi/_glib/pyglib.h                     |    1 -
 gi/_glib/pygmaincontext.c             |  126 -------
 gi/_glib/pygmaincontext.h             |   40 --
 gi/_glib/pygmainloop.c                |  362 -------------------
 gi/_glib/pygmainloop.h                |   36 --
 gi/_glib/pygsource.c                  |  640 ---------------------------------
 gi/_glib/pygsource.h                  |    3 -
 gi/_gobject/__init__.py               |   13 -
 gi/gimodule.c                         |    9 +
 gi/overrides/GLib.py                  |  116 ++++++-
 gi/overrides/GObject.py               |   10 +-
 gi/pygi-private.h                     |    1 +
 gi/pygi-source.c                      |  247 +++++++++++++
 gi/pygi-source.h                      |   31 ++
 tests/test_glib.py                    |   22 +-
 tests/test_gobject.py                 |    2 +
 tests/test_source.py                  |    3 -
 28 files changed, 437 insertions(+), 1776 deletions(-)
---
diff --git a/docs/Makefile.am b/docs/Makefile.am
index 5920d5f..c2fc7ef 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -11,8 +11,6 @@ HTML_FILES =					\
 	html/class-gobjectginterface.html	\
 	html/class-gobjectgpointer.html		\
 	html/class-gobject.html			\
-	html/class-glibmaincontext.html		\
-	html/class-glibmainloop.html		\
 	html/glib-constants.html		\
 	html/glib-functions.html		\
 	html/gobject-class-reference.html	\
@@ -37,9 +35,7 @@ XML_FILES = 						\
 	reference/pygobject-gpointer.xml 		\
 	reference/pyglib-classes.xml 			\
 	reference/pyglib-constants.xml 			\
-	reference/pyglib-functions.xml			\
-	reference/pyglib-maincontext.xml 		\
-	reference/pyglib-mainloop.xml
+	reference/pyglib-functions.xml
 
 XSL_FILES =			\
 	xsl/common.xsl 		\
diff --git a/docs/reference/pyglib-classes.xml b/docs/reference/pyglib-classes.xml
index ecc4e5b..da22b90 100644
--- a/docs/reference/pyglib-classes.xml
+++ b/docs/reference/pyglib-classes.xml
@@ -7,8 +7,6 @@
 <title>PyGlibClass Reference</title>
 
 <!-- GLIB CLASSES -->
-<xi:include href="pyglib-maincontext.xml"/>
-<xi:include href="pyglib-mainloop.xml"/>
 <xi:include href="pyglib-functions.xml"/>
 <xi:include href="pyglib-constants.xml"/>
 
diff --git a/docs/reference/pyglib-constants.xml b/docs/reference/pyglib-constants.xml
index 4f4f37b..2646232 100644
--- a/docs/reference/pyglib-constants.xml
+++ b/docs/reference/pyglib-constants.xml
@@ -73,59 +73,6 @@ condition to watch for on an event source.</para>
 
     </refsect2>
 
-    <refsect2 id="glib-priority-constants">
-      <title id="glib-priority-constants-title">Glib Priority Constants</title>
-
-      <para>The Priority constants specify </para>
-
-      <variablelist>
-	<varlistentry>
-	  <term><literal>glib.PRIORITY_HIGH</literal></term>
-	  <listitem>
-	    <simpara>Use this for high priority event sources.</simpara>
-	  </listitem>
-	</varlistentry>
-	<varlistentry>
-	  <term><literal>glib.PRIORITY_DEFAULT</literal></term>
-	  <listitem>
-	    <simpara>Use this for default priority event sources.  This
-	    priority is used when adding timeout functions with the <link
-	    linkend="function-glib--timeout-add"><function>glib.timeout_add</function>()</link>
-	    function. This priority is also used for events from the X
-	    server.</simpara>
-	  </listitem>
-	</varlistentry>
-	<varlistentry>
-	  <term><literal>glib.PRIORITY_HIGH_IDLE</literal></term>
-	  <listitem>
-	    <simpara>Use this for high priority idle functions. For example,
-	    glib.PRIORITY_HIGH_IDLE + 10 is used for resizing operations;
-	    and, glib.PRIORITY_HIGH_IDLE + 20, for redrawing
-	    operations. (This is done to ensure that any pending resizes are
-	    processed before any pending redraws, so that widgets are not
-	    redrawn twice unnecessarily.)</simpara>
-	  </listitem>
-	</varlistentry>
-	<varlistentry>
-	  <term><literal>glib.PRIORITY_DEFAULT_IDLE</literal></term>
-	  <listitem>
-	    <simpara>Use this for default priority idle functions. This
-	    priority is used when adding idle functions with the <link
-	    linkend="function-glib--idle-add"><function>glib.idle_add</function>()</link>
-	    function.</simpara>
-	  </listitem>
-	</varlistentry>
-	<varlistentry>
-	  <term><literal>glib.PRIORITY_LOW</literal></term>
-	  <listitem>
-	    <simpara>Use this for very low priority background
-	    tasks.</simpara>
-	  </listitem>
-	</varlistentry>
-      </variablelist>
-
-    </refsect2>
-
     <refsect2 id="glib-spawn-flag-constants">
       <title id="glib-spawn-flag-constants-title">Glib Spawn Flag Constants</title>
 
diff --git a/docs/reference/pyglib-functions.xml b/docs/reference/pyglib-functions.xml
index 7c4204e..0354082 100644
--- a/docs/reference/pyglib-functions.xml
+++ b/docs/reference/pyglib-functions.xml
@@ -37,14 +37,6 @@ linkend="function-glib--io-add-watch">glib.io_add_watch</link></methodname>
 	<methodparam><parameter>callback</parameter></methodparam>
 	<methodparam><parameter>...</parameter></methodparam>
   </methodsynopsis><methodsynopsis language="python">
-	<methodname><link
-linkend="function-glib--source-remove">glib.source_remove</link></methodname>
-	<methodparam><parameter>tag</parameter></methodparam>
-  </methodsynopsis><methodsynopsis language="python">
-	<methodname><link
-linkend="function-glib--main-context-default">glib.main_context_default</link></methodname>
-	<methodparam></methodparam>
-      </methodsynopsis><methodsynopsis language="python">
         <methodname><link linkend="function-glib--child-watch-add">glib.child_watch_add</link></methodname>
         <methodparam><parameter role="keyword">pid</parameter></methodparam>
         <methodparam><parameter role="keyword">function</parameter></methodparam>
@@ -334,56 +326,6 @@ when the condition is matched.</para>
 
     </refsect2>
 
-    <refsect2 id="function-glib--source-remove">
-      <title>glib.source_remove</title>
-
-      <programlisting><methodsynopsis language="python">
-	  <methodname>glib.source_remove</methodname>
-	  <methodparam><parameter>tag</parameter></methodparam>
-	</methodsynopsis></programlisting>
-      <variablelist>
-	<varlistentry>
-	  <term><parameter>tag</parameter>&nbsp;:</term>
-	  <listitem><simpara>an integer ID</simpara></listitem>
-	</varlistentry>
-	<varlistentry>
-	  <term><emphasis>Returns</emphasis>&nbsp;:</term>
-	  <listitem><simpara><literal>True</literal> if the event source was
-removed</simpara></listitem>
-	</varlistentry>
-      </variablelist>
-
-      <para>The <function>glib.source_remove</function>() function
-removes the event source specified by tag (as returned by the <link
-linkend="function-glib--idle-add"><function>glib.idle_add</function>()</link>, 
-<link
-linkend="function-glib--timeout-add"><function>glib.timeout_add</function></link>() 
-and <link
-linkend="function-glib--io-add-watch"><function>glib.io_add_watch</function>()</link> 
-functions)</para>
-
-    </refsect2>
-
-    <refsect2 id="function-glib--main-context-default">
-      <title>glib.main_context_default</title>
-
-      <programlisting><methodsynopsis language="python">
-	  <methodname>glib.main_context_default</methodname>
-	  <methodparam></methodparam>
-	</methodsynopsis></programlisting>
-      <variablelist>
-	<varlistentry>
-	  <term><emphasis>Returns</emphasis>&nbsp;:</term>
-	  <listitem><simpara>the default glib.MainContext
-object</simpara></listitem>
-	</varlistentry>
-      </variablelist>
-
-      <para>The <function>glib.main_context_default</function>() function
-returns the default glib.MainContext object.</para>
-
-    </refsect2>
-
     <refsect2 id="function-glib--markup-escape-text">
       <title>glib.markup_escape_text</title>
 
diff --git a/gi/Makefile.am b/gi/Makefile.am
index f99e45b..53d0ddf 100644
--- a/gi/Makefile.am
+++ b/gi/Makefile.am
@@ -46,6 +46,8 @@ _gi_la_SOURCES = \
 	pygi-foreign-gvariant.h \
 	pygi-struct.c \
 	pygi-struct.h \
+	pygi-source.c \
+	pygi-source.h \
 	pygi-argument.c \
 	pygi-argument.h \
 	pygi-type.c \
diff --git a/gi/_glib/Makefile.am b/gi/_glib/Makefile.am
index 468e7f4..fed1b43 100644
--- a/gi/_glib/Makefile.am
+++ b/gi/_glib/Makefile.am
@@ -58,10 +58,6 @@ _glib_la_SOURCES = \
 	pygoptioncontext.h \
 	pygoptiongroup.c \
 	pygoptiongroup.h \
-	pygmaincontext.c \
-	pygmaincontext.h \
-	pygmainloop.c \
-	pygmainloop.h \
 	pygsource.c \
 	pygsource.h \
 	pygspawn.c \
diff --git a/gi/_glib/__init__.py b/gi/_glib/__init__.py
index 378d981..b9e5fa4 100644
--- a/gi/_glib/__init__.py
+++ b/gi/_glib/__init__.py
@@ -27,15 +27,10 @@ _PyGLib_API = _glib._PyGLib_API
 # Types
 GError = _glib.GError
 IOChannel = _glib.IOChannel
-Idle = _glib.Idle
-MainContext = _glib.MainContext
-MainLoop = _glib.MainLoop
 OptionContext = _glib.OptionContext
 OptionGroup = _glib.OptionGroup
 Pid = _glib.Pid
 PollFD = _glib.PollFD
-Source = _glib.Source
-Timeout = _glib.Timeout
 
 # Constants
 IO_ERR = _glib.IO_ERR
@@ -68,11 +63,6 @@ OPTION_FLAG_NO_ARG = _glib.OPTION_FLAG_NO_ARG
 OPTION_FLAG_OPTIONAL_ARG = _glib.OPTION_FLAG_OPTIONAL_ARG
 OPTION_FLAG_REVERSE = _glib.OPTION_FLAG_REVERSE
 OPTION_REMAINING = _glib.OPTION_REMAINING
-PRIORITY_DEFAULT = _glib.PRIORITY_DEFAULT
-PRIORITY_DEFAULT_IDLE = _glib.PRIORITY_DEFAULT_IDLE
-PRIORITY_HIGH = _glib.PRIORITY_HIGH
-PRIORITY_HIGH_IDLE = _glib.PRIORITY_HIGH_IDLE
-PRIORITY_LOW = _glib.PRIORITY_LOW
 SPAWN_CHILD_INHERITS_STDIN = _glib.SPAWN_CHILD_INHERITS_STDIN
 SPAWN_DO_NOT_REAP_CHILD = _glib.SPAWN_DO_NOT_REAP_CHILD
 SPAWN_FILE_AND_ARGV_ZERO = _glib.SPAWN_FILE_AND_ARGV_ZERO
@@ -88,9 +78,7 @@ get_current_time = _glib.get_current_time
 glib_version = _glib.glib_version
 idle_add = _glib.idle_add
 io_add_watch = _glib.io_add_watch
-main_context_default = _glib.main_context_default
 pyglib_version = _glib.pyglib_version
-source_remove = _glib.source_remove
 spawn_async = _glib.spawn_async
 threads_init = _glib.threads_init
 timeout_add = _glib.timeout_add
diff --git a/gi/_glib/glibmodule.c b/gi/_glib/glibmodule.c
index 791bd93..dbe5054 100644
--- a/gi/_glib/glibmodule.c
+++ b/gi/_glib/glibmodule.c
@@ -30,8 +30,6 @@
 #include "pyglib.h"
 #include "pyglib-private.h"
 #include "pygiochannel.h"
-#include "pygmaincontext.h"
-#include "pygmainloop.h"
 #include "pygoptioncontext.h"
 #include "pygoptiongroup.h"
 #include "pygsource.h"
@@ -308,23 +306,6 @@ pyglib_io_add_watch(PyObject *self, PyObject *args, PyObject *kwargs)
     return PYGLIB_PyLong_FromLong(handler_id);
 }
 
-static PyObject *
-pyglib_source_remove(PyObject *self, PyObject *args)
-{
-    guint tag;
-
-    if (!PyArg_ParseTuple(args, "I:source_remove", &tag))
-	return NULL;
-
-    return PyBool_FromLong(g_source_remove(tag));
-}
-
-static PyObject *
-pyglib_main_context_default(PyObject *unused)
-{
-    return pyglib_main_context_new(g_main_context_default());
-}
-
 static void
 child_watch_func(GPid pid, gint status, gpointer data)
 {
@@ -465,12 +446,6 @@ static PyMethodDef _glib_functions[] = {
       "data specified by data when the child indicated by pid exits.\n"
       "Condition is a combination of glib.IO_IN, glib.IO_OUT, glib.IO_PRI,\n"
       "gio.IO_ERR and gio.IO_HUB." },
-    { "source_remove",
-      (PyCFunction)pyglib_source_remove, METH_VARARGS,
-      "source_remove(source_id) -> True if removed\n"
-      "Removes the event source specified by source id as returned by the\n"
-      "glib.idle_add(), glib.timeout_add() or glib.io_add_watch()\n"
-      "functions." },
     { "spawn_async",
       (PyCFunction)pyglib_spawn_async, METH_VARARGS|METH_KEYWORDS,
       "spawn_async(argv, envp=None, working_directory=None,\n"
@@ -479,11 +454,6 @@ static PyMethodDef _glib_functions[] = {
       "            standard_error=None) -> (pid, stdin, stdout, stderr)\n"
       "Execute a child program asynchronously within a glib.MainLoop()\n"
       "See the reference manual for a complete reference." },
-    { "main_context_default",
-      (PyCFunction)pyglib_main_context_default, METH_NOARGS,
-      "main_context_default() -> a main context\n"
-      "Returns the default main context. This is the main context used\n"
-      "for main loop functions when a main loop is not explicitly specified." },
     { "filename_from_utf8",
       (PyCFunction)pyglib_filename_from_utf8, METH_VARARGS },
     { "get_current_time",
@@ -498,7 +468,7 @@ static struct _PyGLib_Functions pyglib_api = {
     NULL,  /* gerror_exception */
     NULL,  /* block_threads */
     NULL,  /* unblock_threads */
-    pyg_main_context_new,
+    NULL,  /* pyg_main_context_new */
     pyg_option_context_new,
     pyg_option_group_new,
 };
@@ -572,17 +542,6 @@ pyglib_register_constants(PyObject *m)
     PyModule_AddIntConstant(m, "SPAWN_FILE_AND_ARGV_ZERO",
 			    G_SPAWN_FILE_AND_ARGV_ZERO);
 
-    PyModule_AddIntConstant(m, "PRIORITY_HIGH",
-			    G_PRIORITY_HIGH);
-    PyModule_AddIntConstant(m, "PRIORITY_DEFAULT",
-			    G_PRIORITY_DEFAULT);
-    PyModule_AddIntConstant(m, "PRIORITY_HIGH_IDLE",
-			    G_PRIORITY_HIGH_IDLE);
-    PyModule_AddIntConstant(m, "PRIORITY_DEFAULT_IDLE",
-			    G_PRIORITY_DEFAULT_IDLE);
-    PyModule_AddIntConstant(m, "PRIORITY_LOW",
-			    G_PRIORITY_LOW);
-
     PyModule_AddIntConstant(m, "IO_IN",   G_IO_IN);
     PyModule_AddIntConstant(m, "IO_OUT",  G_IO_OUT);
     PyModule_AddIntConstant(m, "IO_PRI",  G_IO_PRI);
@@ -652,8 +611,6 @@ PYGLIB_MODULE_START(_glib, "_glib")
     pyglib_register_error(d);
     pyglib_register_version_tuples(d);
     pyglib_iochannel_register_types(d);
-    pyglib_mainloop_register_types(d);
-    pyglib_maincontext_register_types(d);
     pyglib_source_register_types(d);
     pyglib_spawn_register_types(d);
     pyglib_option_context_register_types(d);
diff --git a/gi/_glib/pyglib.c b/gi/_glib/pyglib.c
index 3508f55..2e5a0ef 100644
--- a/gi/_glib/pyglib.c
+++ b/gi/_glib/pyglib.c
@@ -27,7 +27,6 @@
 #include <pythread.h>
 #include "pyglib.h"
 #include "pyglib-private.h"
-#include "pygmaincontext.h"
 #include "pygoptioncontext.h"
 #include "pygoptiongroup.h"
 
@@ -411,20 +410,6 @@ pyglib_register_exception_for_domain(gchar *name,
 }
 
 /**
- * pyglib_main_context_new:
- * @context: a GMainContext.
- *
- * Creates a wrapper for a GMainContext.
- *
- * Returns: the GMainContext wrapper.
- */
-PyObject *
-pyglib_main_context_new(GMainContext *context)
-{
-    return _PyGLib_API->main_context_new(context);
-}
-
-/**
  * pyg_option_group_transfer_group:
  * @group: a GOptionGroup wrapper
  *
diff --git a/gi/_glib/pyglib.h b/gi/_glib/pyglib.h
index 261af7b..35e40c4 100644
--- a/gi/_glib/pyglib.h
+++ b/gi/_glib/pyglib.h
@@ -42,7 +42,6 @@ gboolean pyglib_gerror_exception_check(GError **error);
 PyObject *pyglib_register_exception_for_domain(gchar *name,
 					       gint error_domain);
 gboolean pyglib_threads_enabled(void);
-PyObject * pyglib_main_context_new(GMainContext *context);
 void pyglib_set_thread_block_funcs(PyGLibThreadBlockFunc block_threads_func,
 				   PyGLibThreadBlockFunc unblock_threads_func);
 void pyglib_block_threads(void);
diff --git a/gi/_glib/pygsource.c b/gi/_glib/pygsource.c
index d11f474..5a333c4 100644
--- a/gi/_glib/pygsource.c
+++ b/gi/_glib/pygsource.c
@@ -28,624 +28,11 @@
 #endif
 
 #include <Python.h>
-#include <pythread.h>
 #include <structmember.h> /* for PyMemberDef */
 #include "pyglib.h"
 #include "pyglib-private.h"
-#include "pygmaincontext.h"
 #include "pygsource.h"
 
-#define CHECK_DESTROYED(self, ret)			G_STMT_START {	\
-    if ((self)->source == NULL) {					\
-	PyErr_SetString(PyExc_RuntimeError, "source is destroyed");	\
-	return (ret);							\
-    }									\
-} G_STMT_END
-
-
-typedef struct {
-    PyObject_HEAD
-    GSource *source;
-    PyObject *inst_dict;
-    PyObject *weakreflist;
-    gboolean python_source;
-} PyGSource;
-
-typedef struct
-{
-    GSource source;
-    PyObject *obj;
-} PyGRealSource;
-
-/* glib.Source */
-
-PYGLIB_DEFINE_TYPE("gi._glib.Source", PyGSource_Type, PyGSource)
-
-static PyObject *
-source_repr(PyGSource *self, const char *type)
-{
-    gchar buf[256], *desc;
- 
-    if (self->source) {
-	if (g_source_get_context(self->source))
-	    desc = "attached";
-	else
-	    desc = "unattached";
-    } else {
-	desc = "destroyed";
-    }
-
-    if (type)
-	g_snprintf(buf, sizeof(buf), "<%s glib %s source at 0x%lx>",
-		   desc, type, (long) self);
-    else
-	g_snprintf(buf, sizeof(buf), "<%s glib source at 0x%lx>",
-		   desc, (long) self);
-
-    return PYGLIB_PyUnicode_FromString(buf);
-}
-
-static PyObject *
-pyg_source_attach(PyGSource *self, PyObject *args, PyObject *kwargs)
-{
-    static char *kwlist[] = { "context", NULL };
-    PyGMainContext *py_context = NULL;
-    GMainContext *context = NULL;
-    guint id;
-
-    if (!PyArg_ParseTupleAndKeywords (args, kwargs,
-				      "|O!:attach", kwlist,
-				      &PyGMainContext_Type, &py_context))
-	return NULL;
-
-    if (py_context)
-	context = py_context->context;
-
-    CHECK_DESTROYED(self, NULL);
-
-    if (self->python_source) {
-	PyGRealSource *pysource = (PyGRealSource *)self->source;
-	Py_INCREF(pysource->obj);
-    }
-
-    id = g_source_attach(self->source, context);
-    return PYGLIB_PyLong_FromLong(id);
-}
-
-static PyObject *
-pyg_source_destroy(PyGSource *self)
-{
-    CHECK_DESTROYED(self, NULL);
-
-    if (self->python_source && self->source->context) {
-	PyGRealSource *pysource = (PyGRealSource *)self->source;
-	Py_DECREF(pysource->obj);
-    }
-
-    g_source_destroy(self->source);
-    self->source = NULL;
-
-    Py_INCREF(Py_None);
-    return Py_None;
-}
-
-static PyObject *
-pyg_source_is_destroyed(PyGSource *self)
-{
-    PyObject *result;
-
-    if (self->source == NULL || g_source_is_destroyed(self->source))
-        result = Py_True;
-    else
-        result = Py_False;
-
-    Py_INCREF(result);
-    return result;
-}
-
-static PyObject *
-pyg_source_set_callback(PyGSource *self, PyObject *args)
-{
-    PyObject *first, *callback, *cbargs = NULL, *data;
-    gint len;
-
-    CHECK_DESTROYED(self, NULL);
-
-    len = PyTuple_Size (args);
-    if (len < 1) {
-	PyErr_SetString(PyExc_TypeError,
-			"set_callback requires at least 1 argument");
-	return NULL;
-    }
-
-    first = PySequence_GetSlice(args, 0, 1);
-    if (!PyArg_ParseTuple(first, "O:set_callback", &callback)) {
-	Py_DECREF (first);
-	return NULL;
-    }
-    Py_DECREF(first);
-
-    if (!PyCallable_Check(callback)) {
-	PyErr_SetString(PyExc_TypeError, "first argument not callable");
-	return NULL;
-    }
-
-    cbargs = PySequence_GetSlice(args, 1, len);
-    if (cbargs == NULL)
-	return NULL;
-
-    data = Py_BuildValue("(ON)", callback, cbargs);
-    if (data == NULL)
-	return NULL;
-
-    g_source_set_callback(self->source,
-			  _pyglib_handler_marshal, data,
-			  _pyglib_destroy_notify);
-
-    Py_INCREF(Py_None);
-    return Py_None;
-}
-
-static PyObject *
-pyg_source_get_context(PyGSource *self)
-{
-    GMainContext *context;
-
-    CHECK_DESTROYED(self, NULL);
-
-    context = g_source_get_context(self->source);
-
-    if (context) {
-	return pyg_main_context_new(context);
-    } else {
-	Py_INCREF(Py_None);
-	return Py_None;
-    }
-}
-
-static PyObject *
-pyg_source_add_poll(PyGSource *self, PyObject *args, PyObject *kwargs)
-{
-    static char *kwlist[] = { "fd", NULL };
-    PyGPollFD *fd;
-
-    if (!self->python_source) {
-	PyErr_SetString(PyExc_TypeError,
-			"add_poll can only be used with sources "
-			"implemented in python");
-	return NULL;
-    }
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
-				     "O!:add_poll", kwlist,
-				     &PyGPollFD_Type, &fd))
-	return NULL;
-
-    CHECK_DESTROYED(self, NULL);
-
-    g_source_add_poll(self->source, &fd->pollfd);
-
-    Py_INCREF(Py_None);
-    return Py_None;
-}
-
-static PyObject *
-pyg_source_remove_poll(PyGSource *self, PyObject *args, PyObject *kwargs)
-{
-    static char *kwlist[] = { "fd", NULL };
-    PyGPollFD *fd;
-
-    if (!self->python_source) {
-	PyErr_SetString(PyExc_TypeError,
-			"remove_poll can only be used with sources "
-			"implemented in python");
-	return NULL;
-    }
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
-				     "O!:remove_poll", kwlist,
-				     &PyGPollFD_Type, &fd))
-	return NULL;
-
-    CHECK_DESTROYED(self, NULL);
-
-    g_source_remove_poll(self->source, &fd->pollfd);
-
-    Py_INCREF(Py_None);
-    return Py_None;
-}
-
-static PyObject *
-pyg_source_get_current_time(PyGSource *self)
-{
-    double   ret;
-
-    CHECK_DESTROYED(self, NULL);
-
-    ret = g_get_real_time() * 0.000001;
-    return PyFloat_FromDouble(ret);
-}
-
-static PyMethodDef pyg_source_methods[] = {
-    { "attach", (PyCFunction)pyg_source_attach, METH_VARARGS|METH_KEYWORDS },
-    { "destroy", (PyCFunction)pyg_source_destroy, METH_NOARGS },
-    { "is_destroyed", (PyCFunction)pyg_source_is_destroyed, METH_NOARGS },
-    { "set_callback", (PyCFunction)pyg_source_set_callback, METH_VARARGS },
-    { "get_context", (PyCFunction)pyg_source_get_context, METH_NOARGS },
-    { "add_poll", (PyCFunction)pyg_source_add_poll, METH_KEYWORDS },
-    { "remove_poll", (PyCFunction)pyg_source_remove_poll, METH_VARARGS|METH_KEYWORDS },
-    { "get_current_time", (PyCFunction)pyg_source_get_current_time, METH_NOARGS },
-    { NULL, NULL, 0 }
-};
-
-static PyObject *
-pyg_source_get_dict(PyGSource *self, void *closure)
-{
-    if (self->inst_dict == NULL) {
-	self->inst_dict = PyDict_New();
-	if (self->inst_dict == NULL)
-	    return NULL;
-    }
-
-    Py_INCREF(self->inst_dict);
-    return self->inst_dict;
-}
-
-static PyObject *
-pyg_source_get_priority(PyGSource *self, void *closure)
-{
-    CHECK_DESTROYED(self, NULL);
-
-    return PYGLIB_PyLong_FromLong(g_source_get_priority(self->source));
-}
-
-static int
-pyg_source_set_priority(PyGSource *self, PyObject *value, void *closure)
-{
-    CHECK_DESTROYED(self, -1);
-
-    if (value == NULL) {
-	PyErr_SetString(PyExc_TypeError, "cannot delete priority");
-	return -1;
-    }
-
-    if (!PYGLIB_PyLong_Check(value)) {
-	PyErr_SetString(PyExc_TypeError, "type mismatch");
-	return -1;
-    }
-
-    g_source_set_priority(self->source, PYGLIB_PyLong_AsLong(value));
-
-    return 0;
-}
-
-static PyObject *
-pyg_source_get_can_recurse(PyGSource *self, void *closure)
-{
-    CHECK_DESTROYED(self, NULL);
-
-    return PyBool_FromLong(g_source_get_can_recurse(self->source));
-}
-
-static int
-pyg_source_set_can_recurse(PyGSource *self, PyObject *value, void *closure)
-{
-    CHECK_DESTROYED(self, -1);
-
-    if (value == NULL) {
-	PyErr_SetString(PyExc_TypeError, "cannot delete can_recurse");
-	return -1;
-    }
-
-    g_source_set_can_recurse(self->source, PyObject_IsTrue(value));
-
-    return 0;
-}
-
-static PyObject *
-pyg_source_get_id(PyGSource *self, void *closure)
-{
-    CHECK_DESTROYED(self, NULL);
-
-    if (g_source_get_context(self->source) == NULL) {
-	PyErr_SetString(PyExc_RuntimeError, "source is not attached");
-	return NULL;
-    }
-
-    return PYGLIB_PyLong_FromLong(g_source_get_id(self->source));
-}
-
-static PyGetSetDef pyg_source_getsets[] = {
-    { "__dict__", (getter)pyg_source_get_dict,  (setter)0 },
-    {"priority", (getter)pyg_source_get_priority, (setter)pyg_source_set_priority },
-    {"can_recurse", (getter)pyg_source_get_can_recurse, (setter)pyg_source_set_can_recurse },
-    {"id", (getter)pyg_source_get_id, (setter)0 },
-    {NULL, 0, 0}
-};
-
-static PyObject *
-pyg_source_repr(PyGSource *self)
-{
-    return source_repr(self, NULL);
-}
-
-static int
-pyg_source_traverse(PyGSource *self, visitproc visit, void *arg)
-{
-    int ret = 0;
-
-    if (self->inst_dict) ret = visit(self->inst_dict, arg);
-    if (ret != 0) return ret;
-
-    return 0;
-}
-
-static int
-pyg_source_clear(PyGSource *self)
-{
-    PyObject *tmp;
-
-    tmp = self->inst_dict;
-    self->inst_dict = NULL;
-    Py_XDECREF(tmp);
-
-    if (self->source) {
-	g_source_unref(self->source);
-	self->source = NULL;
-    }
-
-    return 0;
-}
-
-static void
-pyg_source_dealloc(PyGSource *self)
-{
-    /* Must be done first, so that there is no chance of Python's GC being
-     * called while tracking this half-deallocated object */
-    PyObject_GC_UnTrack((PyObject *)self);
-
-    PyObject_ClearWeakRefs((PyObject *)self);
-
-    pyg_source_clear(self);
-
-    PyObject_GC_Del(self);
-}
-
-static gboolean
-pyg_source_prepare(GSource *source, gint *timeout)
-{
-    PyGRealSource *pysource = (PyGRealSource *)source;
-    PyObject *t;
-    gboolean ret = FALSE;
-    gboolean got_err = TRUE;
-    PyGILState_STATE state;
-
-    state = pyglib_gil_state_ensure();
-
-    t = PyObject_CallMethod(pysource->obj, "prepare", NULL);
-
-    if (t == NULL) {
-	goto bail;
-    } else if (!PyObject_IsTrue(t)) {
-	got_err = FALSE;
-	goto bail;
-    } else if (!PyTuple_Check(t)) {
-	PyErr_SetString(PyExc_TypeError,
-			"source prepare function must return a tuple or False");
-	goto bail;
-    } else if (PyTuple_Size(t) != 2) {
-	PyErr_SetString(PyExc_TypeError,
-			"source prepare function return tuple must be exactly "
-			"2 elements long");
-	goto bail;
-    }
-
-    ret = PyObject_IsTrue(PyTuple_GET_ITEM(t, 0));
-	*timeout = PYGLIB_PyLong_AsLong(PyTuple_GET_ITEM(t, 1));
-
-	if (*timeout == -1 && PyErr_Occurred()) {
-	    ret = FALSE;
-	    goto bail;
-	}
-
-    got_err = FALSE;
-
-bail:
-    if (got_err)
-	PyErr_Print();
-
-    Py_XDECREF(t);
-
-    pyglib_gil_state_release(state);
-
-    return ret;
-}
-
-static gboolean
-pyg_source_check(GSource *source)
-{
-    PyGRealSource *pysource = (PyGRealSource *)source;
-    PyObject *t;
-    gboolean ret;
-    PyGILState_STATE state;
-
-    state = pyglib_gil_state_ensure();
-
-    t = PyObject_CallMethod(pysource->obj, "check", NULL);
-
-    if (t == NULL) {
-	PyErr_Print();
-	ret = FALSE;
-    } else {
-	ret = PyObject_IsTrue(t);
-	Py_DECREF(t);
-    }
-
-    pyglib_gil_state_release(state);
-
-    return ret;
-}
-
-static gboolean
-pyg_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
-{
-    PyGRealSource *pysource = (PyGRealSource *)source;
-    PyObject *func, *args, *tuple, *t;
-    gboolean ret;
-    PyGILState_STATE state;
-
-    state = pyglib_gil_state_ensure();
-
-    if (callback) {
-	tuple = user_data;
-
-	func = PyTuple_GetItem(tuple, 0);
-        args = PyTuple_GetItem(tuple, 1);
-    } else {
-	func = Py_None;
-	args = Py_None;
-    }
-
-    t = PyObject_CallMethod(pysource->obj, "dispatch", "OO", func, args);
-
-    if (t == NULL) {
-	PyErr_Print();
-	ret = FALSE;
-    } else {
-	ret = PyObject_IsTrue(t);
-	Py_DECREF(t);
-    }
-
-    pyglib_gil_state_release(state);
-
-    return ret;
-}
-
-static void
-pyg_source_finalize(GSource *source)
-{
-    PyGRealSource *pysource = (PyGRealSource *)source;
-    PyObject *func, *t;
-    PyGILState_STATE state;
-
-    state = pyglib_gil_state_ensure();
-
-    func = PyObject_GetAttrString(pysource->obj, "finalize");
-    if (func) {
-	t = PyObject_CallObject(func, NULL);
-	Py_DECREF(func);
-
-	if (t == NULL) {
-	    PyErr_Print();
-	} else {
-	    Py_DECREF(t);
-	}
-    }
-
-    pyglib_gil_state_release(state);
-}
-
-static GSourceFuncs pyg_source_funcs =
-{
-    pyg_source_prepare,
-    pyg_source_check,
-    pyg_source_dispatch,
-    pyg_source_finalize
-};
-
-static int
-pyg_source_init(PyGSource *self, PyObject *args, PyObject *kwargs)
-{
-    PyGRealSource *pysource;
-
-    self->source = g_source_new(&pyg_source_funcs, sizeof(PyGRealSource));
-
-    pysource = (PyGRealSource *)self->source;
-    pysource->obj = (PyObject*)self;
-
-    self->inst_dict = NULL;
-    self->weakreflist = NULL;
-
-    self->python_source = TRUE;
-
-    return 0;
-}
-
-static void
-pyg_source_free(PyObject *op)
-{
-    PyObject_GC_Del(op);
-}
-
-/* glib.Idle */
-
-PYGLIB_DEFINE_TYPE("gi._glib.Idle", PyGIdle_Type, PyGSource)
-
-static PyObject *
-pyg_idle_repr(PyGSource *self)
-{
-    return source_repr(self, "idle");
-}
-
-static int
-pyg_idle_init(PyGSource *self, PyObject *args, PyObject *kwargs)
-{
-    static char *kwlist[] = { "priority", NULL };
-    gint priority = G_PRIORITY_DEFAULT_IDLE;
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
-				     "|i:gi._glib.Idle.__init__", kwlist,
-				     &priority))
-	return -1;
-
-    self->source = g_idle_source_new ();
-
-    if (priority != G_PRIORITY_DEFAULT_IDLE)
-	g_source_set_priority(self->source, priority);
-
-    self->inst_dict = NULL;
-    self->weakreflist = NULL;
-
-    self->python_source = FALSE;
-
-    return 0;
-}
-
-/* glib.Timeout */
-
-PYGLIB_DEFINE_TYPE("gi._glib.Timeout", PyGTimeout_Type, PyGSource)
-
-static PyObject *
-pyg_timeout_repr(PyGSource *self)
-{
-    return source_repr(self, "timeout");
-}
-
-static int
-pyg_timeout_init(PyGSource *self, PyObject *args, PyObject *kwargs)
-{
-    static char *kwlist[] = { "interval", "priority", NULL };
-    gint priority = G_PRIORITY_DEFAULT;
-    guint interval;
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
-				     "I|i:gi._glib.Timeout.__init__", kwlist,
-				     &interval, &priority))
-	return -1;
-
-    self->source = g_timeout_source_new(interval);
-
-    if (priority != G_PRIORITY_DEFAULT)
-	g_source_set_priority(self->source, priority);
-
-    self->inst_dict = NULL;
-    self->weakreflist = NULL;
-
-    self->python_source = FALSE;
-
-    return 0;
-}
-
 /* glib.PollFD */
 
 PYGLIB_DEFINE_TYPE("gi._glib.PollFD", PyGPollFD_Type, PyGPollFD)
@@ -702,33 +89,6 @@ pyg_poll_fd_init(PyGPollFD *self, PyObject *args, PyObject *kwargs)
 void
 pyglib_source_register_types(PyObject *d)
 {
-    PyGSource_Type.tp_flags = (Py_TPFLAGS_DEFAULT |
-			       Py_TPFLAGS_BASETYPE |
-			       Py_TPFLAGS_HAVE_GC);
-    PyGSource_Type.tp_init = (initproc)pyg_source_init;
-    PyGSource_Type.tp_free = (freefunc)pyg_source_free;
-    PyGSource_Type.tp_dealloc = (destructor)pyg_source_dealloc;
-    PyGSource_Type.tp_methods = pyg_source_methods;
-    PyGSource_Type.tp_repr = (reprfunc)pyg_source_repr;
-    PyGSource_Type.tp_traverse = (traverseproc)pyg_source_traverse;
-    PyGSource_Type.tp_clear = (inquiry)pyg_source_clear;
-    PyGSource_Type.tp_getset = pyg_source_getsets;
-    PyGSource_Type.tp_weaklistoffset = offsetof(PyGSource, weakreflist);
-    PyGSource_Type.tp_dictoffset = offsetof(PyGSource, inst_dict);
-    PYGLIB_REGISTER_TYPE(d, PyGSource_Type, "Source");
-
-    PyGIdle_Type.tp_repr = (reprfunc)pyg_idle_repr;
-    PyGIdle_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
-    PyGIdle_Type.tp_base = (PyTypeObject *)&PyGSource_Type;
-    PyGIdle_Type.tp_init = (initproc)pyg_idle_init;
-    PYGLIB_REGISTER_TYPE(d, PyGIdle_Type, "Idle");
-
-    PyGTimeout_Type.tp_repr = (reprfunc)pyg_timeout_repr;
-    PyGTimeout_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
-    PyGTimeout_Type.tp_base = (PyTypeObject *)&PyGSource_Type;
-    PyGTimeout_Type.tp_init = (initproc)pyg_timeout_init;
-    PYGLIB_REGISTER_TYPE(d, PyGTimeout_Type, "Timeout");
-
     PyGPollFD_Type.tp_dealloc = (destructor)pyg_poll_fd_dealloc;
     PyGPollFD_Type.tp_repr = (reprfunc)pyg_poll_fd_repr;
     PyGPollFD_Type.tp_flags = Py_TPFLAGS_DEFAULT;
diff --git a/gi/_glib/pygsource.h b/gi/_glib/pygsource.h
index bf2c673..dbae9ac 100644
--- a/gi/_glib/pygsource.h
+++ b/gi/_glib/pygsource.h
@@ -22,9 +22,6 @@
 #ifndef __PYG_SOURCE_H__
 #define __PYG_SOURCE_H__
 
-extern PyTypeObject PyGSource_Type;
-extern PyTypeObject PyGIdle_Type;
-extern PyTypeObject PyGTimeout_Type;
 extern PyTypeObject PyGPollFD_Type;
 
 typedef struct
diff --git a/gi/_gobject/__init__.py b/gi/_gobject/__init__.py
index ba6f7de..2098d27 100644
--- a/gi/_gobject/__init__.py
+++ b/gi/_gobject/__init__.py
@@ -86,21 +86,13 @@ idle_add = _glib.idle_add
 timeout_add = _glib.timeout_add
 timeout_add_seconds = _glib.timeout_add_seconds
 io_add_watch = _glib.io_add_watch
-source_remove = _glib.source_remove
 child_watch_add = _glib.child_watch_add
 get_current_time = _glib.get_current_time
 filename_from_utf8 = _glib.filename_from_utf8
 Pid = _glib.Pid
 GError = _glib.GError
 glib_version = _glib.glib_version
-MainLoop = _glib.MainLoop
-MainContext = _glib.MainContext
-main_context_default = _glib.main_context_default
 IOChannel = _glib.IOChannel
-Source = _glib.Source
-Idle = _glib.Idle
-Timeout = _glib.Timeout
-PollFD = _glib.PollFD
 OptionGroup = _glib.OptionGroup
 OptionContext = _glib.OptionContext
 
@@ -111,11 +103,6 @@ SPAWN_STDOUT_TO_DEV_NULL = _glib.SPAWN_STDOUT_TO_DEV_NULL
 SPAWN_STDERR_TO_DEV_NULL = _glib.SPAWN_STDERR_TO_DEV_NULL
 SPAWN_CHILD_INHERITS_STDIN = _glib.SPAWN_CHILD_INHERITS_STDIN
 SPAWN_FILE_AND_ARGV_ZERO = _glib.SPAWN_FILE_AND_ARGV_ZERO
-PRIORITY_HIGH = _glib.PRIORITY_HIGH
-PRIORITY_DEFAULT = _glib.PRIORITY_DEFAULT
-PRIORITY_HIGH_IDLE = _glib.PRIORITY_HIGH_IDLE
-PRIORITY_DEFAULT_IDLE = _glib.PRIORITY_DEFAULT_IDLE
-PRIORITY_LOW = _glib.PRIORITY_LOW
 IO_IN = _glib.IO_IN
 IO_OUT = _glib.IO_OUT
 IO_PRI = _glib.IO_PRI
diff --git a/gi/gimodule.c b/gi/gimodule.c
index 6ccd87f..fcab468 100644
--- a/gi/gimodule.c
+++ b/gi/gimodule.c
@@ -455,6 +455,13 @@ _wrap_pyg_variant_type_from_string (PyObject *self, PyObject *args)
     return py_variant;
 }
 
+static PyObject *
+_wrap_pyg_source_new (PyObject *self, PyObject *args)
+{
+    return pyg_source_new ();
+}
+
+
 static PyMethodDef _gi_functions[] = {
     { "enum_add", (PyCFunction) _wrap_pyg_enum_add, METH_VARARGS | METH_KEYWORDS },
     { "enum_register_new_gtype_and_add", (PyCFunction) _wrap_pyg_enum_register_new_gtype_and_add, METH_VARARGS | METH_KEYWORDS },
@@ -465,6 +472,8 @@ static PyMethodDef _gi_functions[] = {
     { "hook_up_vfunc_implementation", (PyCFunction) _wrap_pyg_hook_up_vfunc_implementation, METH_VARARGS },
     { "variant_new_tuple", (PyCFunction) _wrap_pyg_variant_new_tuple, METH_VARARGS },
     { "variant_type_from_string", (PyCFunction) _wrap_pyg_variant_type_from_string, METH_VARARGS },
+    { "source_new", (PyCFunction) _wrap_pyg_source_new, METH_NOARGS },
+    { "source_set_callback", (PyCFunction) pyg_source_set_callback, METH_VARARGS },
     { NULL, NULL, 0 }
 };
 
diff --git a/gi/overrides/GLib.py b/gi/overrides/GLib.py
index 3dcc618..0969cf0 100644
--- a/gi/overrides/GLib.py
+++ b/gi/overrides/GLib.py
@@ -19,8 +19,11 @@
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
 # USA
 
+import signal
+
 from ..importer import modules
-from .._gi import variant_new_tuple, variant_type_from_string
+from .._gi import variant_new_tuple, variant_type_from_string, source_new, source_set_callback
+from ..overrides import override
 
 GLib = modules['GLib']._introspection_module
 
@@ -422,3 +425,114 @@ for n in ['DESKTOP', 'DOCUMENTS', 'DOWNLOAD', 'MUSIC', 'PICTURES',
           'PUBLIC_SHARE', 'TEMPLATES', 'VIDEOS']:
     exec('USER_DIRECTORY_%s = GLib.UserDirectory.DIRECTORY_%s' % (n, n))
     __all__.append('USER_DIRECTORY_' + n)
+
+
+class MainLoop(GLib.MainLoop):
+    # Backwards compatible constructor API
+    def __new__(cls, context=None):
+        return GLib.MainLoop.new(context, False)
+
+    # Retain classic pygobject behaviour of quitting main loops on SIGINT
+    def __init__(self, context=None):
+        def _handler(loop):
+            loop.quit()
+            loop._quit_by_sigint = True
+
+        self._signal_source = GLib.unix_signal_add_full(
+            GLib.PRIORITY_DEFAULT, signal.SIGINT, _handler, self)
+
+    def __del__(self):
+        GLib.source_remove(self._signal_source)
+
+    def run(self):
+        super(MainLoop, self).run()
+        if hasattr(self, '_quit_by_sigint'):
+            # caught by _main_loop_sigint_handler()
+            raise KeyboardInterrupt
+
+MainLoop = override(MainLoop)
+__all__.append('MainLoop')
+
+
+class MainContext(GLib.MainContext):
+    # Backwards compatible API with default value
+    def iteration(self, may_block=True):
+        return super(MainContext, self).iteration(may_block)
+
+MainContext = override(MainContext)
+__all__.append('MainContext')
+
+
+class Source(GLib.Source):
+    def __new__(cls):
+        # use our custom pyg_source_new() here as g_source_new() is not
+        # bindable
+        source = source_new()
+        source.__class__ = cls
+        setattr(source, '__pygi_custom_source', True)
+        return source
+
+    # Backwards compatible API for optional arguments
+    def attach(self, context=None):
+        id = super(Source, self).attach(context)
+        return id
+
+    def set_callback(self, fn, user_data=None):
+        if hasattr(self, '__pygi_custom_source'):
+            # use our custom pyg_source_set_callback() if for a GSource object
+            # with custom functions
+            source_set_callback(self, fn, user_data)
+        else:
+            # otherwise, for Idle and Timeout, use the standard method
+            super(Source, self).set_callback(fn, user_data)
+
+    def get_current_time(self):
+        return GLib.get_real_time() * 0.000001
+
+    # as get/set_priority are introspected, we can't use the static
+    # property(get_priority, ..) here
+    def __get_priority(self):
+        return self.get_priority()
+
+    def __set_priority(self, value):
+        self.set_priority(value)
+
+    priority = property(__get_priority, __set_priority)
+
+    def __get_can_recurse(self):
+        return self.get_can_recurse()
+
+    def __set_can_recurse(self, value):
+        self.set_can_recurse(value)
+
+    can_recurse = property(__get_can_recurse, __set_can_recurse)
+
+Source = override(Source)
+__all__.append('Source')
+
+
+class Idle(Source):
+    def __new__(cls, priority=GLib.PRIORITY_DEFAULT):
+        source = GLib.idle_source_new()
+        source.__class__ = cls
+        return source
+
+    def __init__(self, priority=GLib.PRIORITY_DEFAULT):
+        super(Source, self).__init__()
+        if priority != GLib.PRIORITY_DEFAULT:
+            self.set_priority(priority)
+
+__all__.append('Idle')
+
+
+class Timeout(Source):
+    def __new__(cls, interval=0, priority=GLib.PRIORITY_DEFAULT):
+        source = GLib.timeout_source_new(interval)
+        source.__class__ = cls
+        return source
+
+    def __init__(self, interval=0, priority=GLib.PRIORITY_DEFAULT):
+        if priority != GLib.PRIORITY_DEFAULT:
+            self.set_priority(priority)
+
+__all__.append('Timeout')
diff --git a/gi/overrides/GObject.py b/gi/overrides/GObject.py
index 3af4d44..e65de7e 100644
--- a/gi/overrides/GObject.py
+++ b/gi/overrides/GObject.py
@@ -27,6 +27,14 @@ __all__ = []
 for name in ['markup_escape_text', 'get_application_name',
              'set_application_name', 'get_prgname', 'set_prgname',
              'main_depth', 'filename_display_basename',
-             'filename_display_name', 'uri_list_extract_uris']:
+             'filename_display_name', 'uri_list_extract_uris',
+             'MainLoop', 'MainContext', 'main_context_default',
+             'source_remove', 'Source', 'Idle', 'Timeout', 'PollFD']:
+    globals()[name] = getattr(GLib, name)
+    __all__.append(name)
+
+# constants are also deprecated, but cannot mark them as such
+for name in ['PRIORITY_DEFAULT', 'PRIORITY_DEFAULT_IDLE', 'PRIORITY_HIGH',
+             'PRIORITY_HIGH_IDLE', 'PRIORITY_LOW']:
     globals()[name] = getattr(GLib, name)
     __all__.append(name)
diff --git a/gi/pygi-private.h b/gi/pygi-private.h
index 29ec131..b8ef175 100644
--- a/gi/pygi-private.h
+++ b/gi/pygi-private.h
@@ -32,6 +32,7 @@
 #include "pygi-signal-closure.h"
 #include "pygi-invoke.h"
 #include "pygi-cache.h"
+#include "pygi-source.h"
 
 G_BEGIN_DECLS
 #if PY_VERSION_HEX >= 0x03000000
diff --git a/gi/pygi-source.c b/gi/pygi-source.c
new file mode 100644
index 0000000..1825a18
--- /dev/null
+++ b/gi/pygi-source.c
@@ -0,0 +1,247 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 1998-2003  James Henstridge
+ * Copyright (C) 2005       Oracle
+ * Copyright (c) 2012       Canonical Ltd.
+ *
+ * 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 "pygobject.h"
+
+#include "pygi-private.h"
+#include "pyglib.h"
+#include "pyglib-private.h"
+#include "pygi-source.h"
+
+typedef struct
+{
+    GSource source;
+    PyObject *obj;
+} PyGRealSource;
+
+static gboolean
+pyg_source_prepare(GSource *source, gint *timeout)
+{
+    PyGRealSource *pysource = (PyGRealSource *)source;
+    PyObject *t;
+    gboolean ret = FALSE;
+    gboolean got_err = TRUE;
+    PyGILState_STATE state;
+
+    state = pyglib_gil_state_ensure();
+
+    t = PyObject_CallMethod(pysource->obj, "prepare", NULL);
+
+    if (t == NULL) {
+	goto bail;
+    } else if (!PyObject_IsTrue(t)) {
+	got_err = FALSE;
+	goto bail;
+    } else if (!PyTuple_Check(t)) {
+	PyErr_SetString(PyExc_TypeError,
+			"source prepare function must return a tuple or False");
+	goto bail;
+    } else if (PyTuple_Size(t) != 2) {
+	PyErr_SetString(PyExc_TypeError,
+			"source prepare function return tuple must be exactly "
+			"2 elements long");
+	goto bail;
+    }
+
+    ret = PyObject_IsTrue(PyTuple_GET_ITEM(t, 0));
+	*timeout = PYGLIB_PyLong_AsLong(PyTuple_GET_ITEM(t, 1));
+
+	if (*timeout == -1 && PyErr_Occurred()) {
+	    ret = FALSE;
+	    goto bail;
+	}
+
+    got_err = FALSE;
+
+bail:
+    if (got_err)
+	PyErr_Print();
+
+    Py_XDECREF(t);
+
+    pyglib_gil_state_release(state);
+
+    return ret;
+}
+
+static gboolean
+pyg_source_check(GSource *source)
+{
+    PyGRealSource *pysource = (PyGRealSource *)source;
+    PyObject *t;
+    gboolean ret;
+    PyGILState_STATE state;
+
+    state = pyglib_gil_state_ensure();
+
+    t = PyObject_CallMethod(pysource->obj, "check", NULL);
+
+    if (t == NULL) {
+	PyErr_Print();
+	ret = FALSE;
+    } else {
+	ret = PyObject_IsTrue(t);
+	Py_DECREF(t);
+    }
+
+    pyglib_gil_state_release(state);
+
+    return ret;
+}
+
+static gboolean
+pyg_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
+{
+    PyGRealSource *pysource = (PyGRealSource *)source;
+    PyObject *func, *args, *tuple, *t;
+    gboolean ret;
+    PyGILState_STATE state;
+
+    state = pyglib_gil_state_ensure();
+
+    if (callback) {
+	tuple = user_data;
+
+	func = PyTuple_GetItem(tuple, 0);
+        args = PyTuple_GetItem(tuple, 1);
+    } else {
+	func = Py_None;
+	args = Py_None;
+    }
+
+    t = PyObject_CallMethod(pysource->obj, "dispatch", "OO", func, args);
+
+    if (t == NULL) {
+	PyErr_Print();
+	ret = FALSE;
+    } else {
+	ret = PyObject_IsTrue(t);
+	Py_DECREF(t);
+    }
+
+    pyglib_gil_state_release(state);
+
+    return ret;
+}
+
+static void
+pyg_source_finalize(GSource *source)
+{
+    PyGRealSource *pysource = (PyGRealSource *)source;
+    PyObject *func, *t;
+    PyGILState_STATE state;
+
+    state = pyglib_gil_state_ensure();
+
+    func = PyObject_GetAttrString(pysource->obj, "finalize");
+    if (func) {
+	t = PyObject_CallObject(func, NULL);
+	Py_DECREF(func);
+
+	if (t == NULL) {
+	    PyErr_Print();
+	} else {
+	    Py_DECREF(t);
+	}
+    }
+
+    pyglib_gil_state_release(state);
+}
+
+static GSourceFuncs pyg_source_funcs =
+{
+    pyg_source_prepare,
+    pyg_source_check,
+    pyg_source_dispatch,
+    pyg_source_finalize
+};
+
+PyObject *
+pyg_source_set_callback(PyGObject *self_module, PyObject *args)
+{
+    PyObject *self, *first, *callback, *cbargs = NULL, *data;
+    PyObject        *source_py_type;
+    gint len;
+
+    len = PyTuple_Size (args);
+    if (len < 2) {
+	PyErr_SetString(PyExc_TypeError,
+			"set_callback requires at least 2 arguments");
+	return NULL;
+    }
+
+    first = PySequence_GetSlice(args, 0, 2);
+    if (!PyArg_ParseTuple(first, "OO:set_callback", &self, &callback)) {
+	Py_DECREF (first);
+	return NULL;
+    }
+    Py_DECREF(first);
+    
+    source_py_type = _pygi_type_import_by_name ("GLib", "Source");
+    if (!pyg_boxed_check (self, G_TYPE_SOURCE)) {
+	PyErr_SetString(PyExc_TypeError, "first argument is not a GLib.Source");
+	return NULL;
+    }
+
+    if (!PyCallable_Check(callback)) {
+	PyErr_SetString(PyExc_TypeError, "second argument not callable");
+	return NULL;
+    }
+
+    cbargs = PySequence_GetSlice(args, 2, len);
+    if (cbargs == NULL)
+	return NULL;
+
+    data = Py_BuildValue("(ON)", callback, cbargs);
+    if (data == NULL)
+	return NULL;
+
+    g_source_set_callback(pyg_boxed_get (self, GSource),
+			  _pyglib_handler_marshal, data,
+			  _pyglib_destroy_notify);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+/**
+ * pyg_source_new:
+ *
+ * Wrap the un-bindable g_source_new() and provide wrapper callbacks in the
+ * GSourceFuncs which call back to Python.
+ */
+PyObject*
+pyg_source_new ()
+{
+    PyGRealSource *source = NULL;
+    PyObject      *py_type;
+
+    source = (PyGRealSource*) g_source_new (&pyg_source_funcs, sizeof (PyGRealSource));
+
+    py_type = _pygi_type_import_by_name ("GLib", "Source");
+    source->obj = _pygi_boxed_new ( (PyTypeObject *) py_type, source, FALSE);
+
+    return source->obj;
+}
diff --git a/gi/pygi-source.h b/gi/pygi-source.h
new file mode 100644
index 0000000..024cf15
--- /dev/null
+++ b/gi/pygi-source.h
@@ -0,0 +1,31 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (c) 2012 Canonical Ltd.
+ *
+ * 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_SOURCE_H__
+#define __PYGI_SOURCE_H__
+
+PyObject *pyg_source_new ();
+PyObject *pyg_source_set_callback (PyGObject *self, PyObject *args);
+
+#endif /* __PYGI_SOURCE_H__ */
+
diff --git a/tests/test_glib.py b/tests/test_glib.py
index 4058fae..21df318 100644
--- a/tests/test_glib.py
+++ b/tests/test_glib.py
@@ -72,16 +72,32 @@ https://my.org/q?x=1&y=2
         self.assertFalse(ml.is_running())
 
         context = ml.get_context()
-        self.assertFalse(context.pending())
+        self.assertEqual(context, GLib.MainContext.default())
+        self.assertTrue(context.is_owner() in [True, False])
+        self.assertTrue(context.pending() in [True, False])
         self.assertFalse(context.iteration(False))
 
+    def test_main_loop_with_context(self):
+        context = GLib.MainContext()
+        ml = GLib.MainLoop(context)
+        self.assertFalse(ml.is_running())
+        self.assertEqual(ml.get_context(), context)
+
     def test_main_context(self):
         # constructor
         context = GLib.MainContext()
+        self.assertTrue(context.is_owner() in [True, False])
         self.assertFalse(context.pending())
         self.assertFalse(context.iteration(False))
 
+        # GLib API
+        context = GLib.MainContext.default()
+        self.assertTrue(context.is_owner() in [True, False])
+        self.assertTrue(context.pending() in [True, False])
+        self.assertTrue(context.iteration(False) in [True, False])
+
         # backwards compatible API
         context = GLib.main_context_default()
-        self.assertFalse(context.pending())
-        self.assertFalse(context.iteration(False))
+        self.assertTrue(context.is_owner() in [True, False])
+        self.assertTrue(context.pending() in [True, False])
+        self.assertTrue(context.iteration(False) in [True, False])
diff --git a/tests/test_gobject.py b/tests/test_gobject.py
index de4fc7a..82bdff9 100644
--- a/tests/test_gobject.py
+++ b/tests/test_gobject.py
@@ -30,6 +30,8 @@ class TestGObjectAPI(unittest.TestCase):
         context = GObject.MainContext()
         self.assertFalse(context.pending())
 
+            self.assertLess(GObject.PRIORITY_HIGH, GObject.PRIORITY_DEFAULT)
+
 
 class TestReferenceCounting(unittest.TestCase):
     def testRegularObject(self):
diff --git a/tests/test_source.py b/tests/test_source.py
index 98bb0ce..d77060f 100644
--- a/tests/test_source.py
+++ b/tests/test_source.py
@@ -163,9 +163,6 @@ class TestSource(unittest.TestCase):
         self.assertGreater(time, 1300000000.0)
         self.assertLess(time, 2000000000.0)
 
-    # currently broken with Python 3,
-    # https://bugzilla.gnome.org/show_bug.cgi?id=686443
-    @unittest.expectedFailure
     def testAddRemovePoll(self):
         # FIXME: very shallow test, only verifies the API signature
         pollfd = GLib.PollFD(99, GLib.IO_IN | GLib.IO_HUP)



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