summaryrefslogtreecommitdiffstats
path: root/glib
diff options
context:
space:
mode:
Diffstat (limited to 'glib')
-rw-r--r--glib/Makefile.am10
-rw-r--r--glib/glibmodule.c21
-rw-r--r--glib/pyglib.c34
-rw-r--r--glib/pyglib.h13
-rw-r--r--glib/pygmaincontext.c133
-rw-r--r--glib/pygmaincontext.h40
-rw-r--r--glib/pygmainloop.c383
-rw-r--r--glib/pygmainloop.h36
8 files changed, 657 insertions, 13 deletions
diff --git a/glib/Makefile.am b/glib/Makefile.am
index f0160d8..e32d24d 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -28,10 +28,12 @@ libpyglib_2_0_la_SOURCES = \
_glib_la_CFLAGS = $(GLIB_CFLAGS)
_glib_la_LDFLAGS = $(common_ldflags) -export-symbols-regex init_glib
_glib_la_LIBADD = $(GLIB_LIBS) libpyglib-2.0.la
-_glib_la_SOURCES = \
- glibmodule.c \
- pygspawn.c \
- pygspawn.h
+_glib_la_SOURCES = \
+ glibmodule.c \
+ pygspawn.c \
+ pygspawn.h \
+ pygmaincontext.c \
+ pygmainloop.c
if PLATFORM_WIN32
_glib_la_CFLAGS += -DPLATFORM_WIN32
diff --git a/glib/glibmodule.c b/glib/glibmodule.c
index 25ded22..6892d1a 100644
--- a/glib/glibmodule.c
+++ b/glib/glibmodule.c
@@ -29,8 +29,10 @@
#include <glib.h>
#include "pyglib.h"
-#include "pygspawn.h"
#include "pyglib-private.h"
+#include "pygmaincontext.h"
+#include "pygmainloop.h"
+#include "pygspawn.h"
#define PYGLIB_MAJOR_VERSION PYGOBJECT_MAJOR_VERSION
#define PYGLIB_MINOR_VERSION PYGOBJECT_MINOR_VERSION
@@ -343,13 +345,11 @@ pyg_source_remove(PyObject *self, PyObject *args)
return PyBool_FromLong(g_source_remove(tag));
}
-#ifdef FIXME
static PyObject *
-pyg_main_context_default(PyObject *unused)
+pyglib_main_context_default(PyObject *unused)
{
- return pyg_main_context_new(g_main_context_default());
+ return pyglib_main_context_new(g_main_context_default());
}
-#endif
struct _PyGChildData {
PyObject *func;
@@ -565,6 +565,8 @@ pyg_set_prgname(PyObject *self, PyObject *args)
static PyMethodDef pyglib_functions[] = {
{ "spawn_async",
(PyCFunction)pyglib_spawn_async, METH_VARARGS|METH_KEYWORDS },
+ { "main_context_default",
+ (PyCFunction)pyglib_main_context_default, METH_NOARGS },
{ "idle_add",
(PyCFunction)pyg_idle_add, METH_VARARGS|METH_KEYWORDS },
@@ -598,10 +600,8 @@ static PyMethodDef pyglib_functions[] = {
(PyCFunction)pyg_set_prgname, METH_VARARGS },
{ "main_depth",
(PyCFunction)pyg_main_depth, METH_NOARGS },
-#if 0
- { "main_context_default",
- (PyCFunction)pyg_main_context_default, METH_NOARGS },
-#endif
+
+
{ NULL, NULL, 0 }
};
@@ -675,4 +675,7 @@ init_glib(void)
pyg_register_error(d);
pyg_register_version_tuples(d);
pyg_spawn_register_types(d);
+
+ pyglib_mainloop_register_types(d);
+ pyglib_maincontext_register_types(d);
}
diff --git a/glib/pyglib.c b/glib/pyglib.c
index 57bc095..3f7ebbd 100644
--- a/glib/pyglib.c
+++ b/glib/pyglib.c
@@ -27,10 +27,14 @@
#include <pythread.h>
#include "pyglib.h"
#include "pyglib-private.h"
+#include "pygmaincontext.h"
static struct _PyGLib_Functions *_PyGLib_API;
static int pyglib_thread_state_tls_key;
+static PyTypeObject *_PyGMainContext_Type;
+#define PyGMainContext_Type (*_PyGMainContext_Type)
+
void
pyglib_init(void)
{
@@ -63,6 +67,8 @@ pyglib_init(void)
"could not import glib (could not find _PyGLib_API object)");
Py_DECREF(glib);
}
+
+ _PyGMainContext_Type = (PyTypeObject*)PyObject_GetAttrString(glib, "MainContext");
}
void
@@ -71,6 +77,12 @@ pyglib_init_internal(PyObject *api)
_PyGLib_API = (struct _PyGLib_Functions *) PyCObject_AsVoidPtr(api);
}
+gboolean
+pyglib_threads_enabled(void)
+{
+ return _PyGLib_API->threads_enabled;
+}
+
PyGILState_STATE
pyglib_gil_state_ensure(void)
{
@@ -255,3 +267,25 @@ bad_gerror:
PyErr_Print();
return -2;
}
+
+/**
+ * pyglib_main_context_new:
+ * @context: a GMainContext.
+ *
+ * Creates a wrapper for a GMainContext.
+ *
+ * Returns: the GMainContext wrapper.
+ */
+PyObject *
+pyglib_main_context_new(GMainContext *context)
+{
+ PyGMainContext *self;
+
+ self = (PyGMainContext *)PyObject_NEW(PyGMainContext,
+ &PyGMainContext_Type);
+ if (self == NULL)
+ return NULL;
+
+ self->context = g_main_context_ref(context);
+ return (PyObject *)self;
+}
diff --git a/glib/pyglib.h b/glib/pyglib.h
index 30b5f74..b2235d3 100644
--- a/glib/pyglib.h
+++ b/glib/pyglib.h
@@ -35,6 +35,19 @@ void pyglib_gil_state_release(PyGILState_STATE state);
gboolean pyglib_enable_threads(void);
gboolean pyglib_error_check(GError **error);
gboolean pyglib_gerror_exception_check(GError **error);
+gboolean pyglib_threads_enabled(void);
+PyObject *pyglib_main_context_new(GMainContext *context);
+
+#define pyglib_begin_allow_threads \
+ G_STMT_START { \
+ PyThreadState *_save = NULL; \
+ if (pyglib_threads_enabled()) \
+ _save = PyEval_SaveThread();
+
+#define pyglib_end_allow_threads \
+ if (pyglib_threads_enabled()) \
+ PyEval_RestoreThread(_save); \
+ } G_STMT_END
G_END_DECLS
diff --git a/glib/pygmaincontext.c b/glib/pygmaincontext.c
new file mode 100644
index 0000000..c969af5
--- /dev/null
+++ b/glib/pygmaincontext.c
@@ -0,0 +1,133 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * pygtk- Python bindings for the GTK toolkit.
+ * Copyright (C) 1998-2003 James Henstridge
+ *
+ * pygmaincontext.c: GMainContext 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Python.h>
+#include <pythread.h>
+#include <glib.h>
+#include "pygmaincontext.h"
+#include "pyglib.h"
+#include "pyglib-private.h"
+
+static int
+pyg_main_context_init(PyGMainContext *self)
+{
+ self->context = g_main_context_new();
+ return 0;
+}
+
+static void
+pyg_main_context_dealloc(PyGMainContext *self)
+{
+ if (self->context != NULL) {
+ g_main_context_unref(self->context);
+ self->context = NULL;
+ }
+
+ PyObject_Del(self);
+}
+
+static int
+pyg_main_context_compare(PyGMainContext *self, PyGMainContext *v)
+{
+ if (self->context == v->context) return 0;
+ if (self->context > v->context) return -1;
+ return 1;
+}
+
+static PyObject *
+_wrap_g_main_context_iteration (PyGMainContext *self, PyObject *args)
+{
+ gboolean ret, may_block = TRUE;
+
+ if (!PyArg_ParseTuple(args, "|i:GMainContext.iteration",
+ &may_block))
+ return NULL;
+
+ pyglib_begin_allow_threads;
+ ret = g_main_context_iteration(self->context, may_block);
+ pyglib_end_allow_threads;
+
+ return PyBool_FromLong(ret);
+}
+
+static PyObject *
+_wrap_g_main_context_pending (PyGMainContext *self)
+{
+ return PyBool_FromLong(g_main_context_pending(self->context));
+}
+
+static PyMethodDef _PyGMainContext_methods[] = {
+ { "iteration", (PyCFunction)_wrap_g_main_context_iteration, METH_VARARGS },
+ { "pending", (PyCFunction)_wrap_g_main_context_pending, METH_NOARGS },
+ { NULL, NULL, 0 }
+};
+
+PyTypeObject PyGMainContext_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "glib.MainContext",
+ sizeof(PyGMainContext),
+ 0,
+ /* methods */
+ (destructor)pyg_main_context_dealloc,
+ (printfunc)0,
+ (getattrfunc)0,
+ (setattrfunc)0,
+ (cmpfunc)pyg_main_context_compare,
+ (reprfunc)0,
+ 0,
+ 0,
+ 0,
+ (hashfunc)0,
+ (ternaryfunc)0,
+ (reprfunc)0,
+ (getattrofunc)0,
+ (setattrofunc)0,
+ 0,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ NULL,
+ (traverseproc)0,
+ (inquiry)0,
+ (richcmpfunc)0,
+ 0,
+ (getiterfunc)0,
+ (iternextfunc)0,
+ _PyGMainContext_methods,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ (descrgetfunc)0,
+ (descrsetfunc)0,
+ 0,
+ (initproc)pyg_main_context_init,
+};
+
+void
+pyglib_maincontext_register_types(PyObject *d)
+{
+ PYGLIB_REGISTER_TYPE(d, PyGMainContext_Type, "MainContext");
+}
diff --git a/glib/pygmaincontext.h b/glib/pygmaincontext.h
new file mode 100644
index 0000000..58ffbf0
--- /dev/null
+++ b/glib/pygmaincontext.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * pyglib - Python bindings for GLib toolkit.
+ * Copyright (C) 1998-2003 James Henstridge
+ * 2004-2008 Johan Dahlin
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifndef __PYG_MAINCONTEXT_H__
+#define __PYG_MAINCONTEXT_H__
+
+#include <Python.h>
+#include <glib.h>
+
+typedef struct {
+ PyObject_HEAD
+ GMainContext *context;
+} PyGMainContext;
+
+extern PyTypeObject PyGMainContext_Type;
+
+PyObject * pyglib_main_context_new(GMainContext *context);
+
+void pyglib_maincontext_register_types(PyObject *d);
+
+#endif /* __PYG_MAINCONTEXT_H__ */
+
diff --git a/glib/pygmainloop.c b/glib/pygmainloop.c
new file mode 100644
index 0000000..04653de
--- /dev/null
+++ b/glib/pygmainloop.c
@@ -0,0 +1,383 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * pygtk- Python bindings for the GTK toolkit.
+ * Copyright (C) 1998-2003 James Henstridge
+ * Copyright (C) 2004 Johan Dahlin
+ *
+ * pygmainloop.c: GMainLoop 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Python.h>
+#include <pythread.h>
+#include <glib.h>
+
+#include "pygmainloop.h"
+#include "pygmaincontext.h"
+#include "pyglib.h"
+#include "pyglib-private.h"
+
+
+typedef struct {
+ GSource source;
+ int fds[2];
+ GPollFD fd;
+} PySignalWatchSource;
+
+#ifdef DISABLE_THREADING
+static GMainLoop *pyg_current_main_loop = NULL;;
+
+static inline GMainLoop *
+pyg_save_current_main_loop (GMainLoop *main_loop)
+{
+ GMainLoop *retval = pyg_current_main_loop;
+
+ g_return_val_if_fail(main_loop != NULL, NULL);
+
+ pyg_current_main_loop = g_main_loop_ref(main_loop);
+
+ return retval;
+}
+
+static inline void
+pyg_restore_current_main_loop (GMainLoop *main_loop)
+{
+ if (pyg_current_main_loop != NULL)
+ g_main_loop_unref(pyg_current_main_loop);
+ pyg_current_main_loop = main_loop;
+}
+
+static inline GMainLoop *
+pyg_get_current_main_loop (void)
+{
+ return pyg_current_main_loop;
+}
+#else /* !defined(#ifndef DISABLE_THREADING) */
+
+static int pyg_current_main_loop_key = -1;
+
+static inline GMainLoop *
+pyg_save_current_main_loop (GMainLoop *main_loop)
+{
+ GMainLoop *retval;
+
+ g_return_val_if_fail(main_loop != NULL, NULL);
+
+ if (pyg_current_main_loop_key == -1)
+ pyg_current_main_loop_key = PyThread_create_key();
+
+ retval = PyThread_get_key_value(pyg_current_main_loop_key);
+ PyThread_delete_key_value(pyg_current_main_loop_key);
+ PyThread_set_key_value(pyg_current_main_loop_key,
+ g_main_loop_ref(main_loop));
+
+ return retval;
+}
+
+static inline void
+pyg_restore_current_main_loop (GMainLoop *main_loop)
+{
+ GMainLoop *prev;
+
+ g_return_if_fail (pyg_current_main_loop_key != -1);
+
+ prev = PyThread_get_key_value(pyg_current_main_loop_key);
+ if (prev != NULL)
+ g_main_loop_unref(prev);
+ PyThread_delete_key_value(pyg_current_main_loop_key);
+ if (main_loop != NULL)
+ PyThread_set_key_value(pyg_current_main_loop_key, main_loop);
+}
+
+static inline GMainLoop *
+pyg_get_current_main_loop (void)
+{
+ if (pyg_current_main_loop_key == -1)
+ return NULL;
+ return PyThread_get_key_value(pyg_current_main_loop_key);
+}
+#endif /* DISABLE_THREADING */
+
+static gboolean
+pyg_signal_watch_prepare(GSource *source,
+ int *timeout)
+{
+#ifdef HAVE_PYSIGNAL_SETWAKEUPFD
+ PySignalWatchSource *real_source = (PySignalWatchSource *)source;
+#endif
+
+ /* Python only invokes signal handlers from the main thread,
+ * so if a thread other than the main thread receives the signal
+ * from the kernel, PyErr_CheckSignals() from that thread will
+ * do nothing.
+ */
+
+ /* On Windows g_poll() won't be interrupted by a signal
+ * (AFAIK), so we need the timeout there too, even if there's
+ * only one thread.
+ */
+#ifndef PLATFORM_WIN32
+ if (!pyglib_threads_enabled())
+ return FALSE;
+#endif
+
+#ifdef HAVE_PYSIGNAL_SETWAKEUPFD
+ if (real_source->fds[0] != 0)
+ return FALSE;
+
+ /* Unfortunately we need to create a new pipe here instead of
+ * reusing the pipe inside the GMainContext.
+ * Ideally an api should be added to GMainContext which allows us
+ * to reuse that pipe which would suit us perfectly fine.
+ */
+ if (pipe(real_source->fds) < 0)
+ g_error("Cannot create main loop pipe: %s\n",
+ g_strerror(errno));
+
+ real_source->fd.fd = real_source->fds[0];
+ real_source->fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
+ g_source_add_poll(source, &real_source->fd);
+
+ PySignal_SetWakeupFd(real_source->fds[1]);
+
+#else /* !HAVE_PYSIGNAL_SETWAKEUPFD */
+ /* If we're using 2.5 or an earlier version of python we
+ * will default to a timeout every second, be aware,
+ * this will cause unnecessary wakeups, see
+ * http://bugzilla.gnome.org/show_bug.cgi?id=481569
+ */
+ *timeout = 1000;
+#endif /* HAVE_PYSIGNAL_SETWAKEUPFD */
+
+ return FALSE;
+}
+
+static gboolean
+pyg_signal_watch_check(GSource *source)
+{
+ PyGILState_STATE state;
+ GMainLoop *main_loop;
+
+ state = pyglib_gil_state_ensure();
+
+ main_loop = pyg_get_current_main_loop();
+
+ if (PyErr_CheckSignals() == -1 && main_loop != NULL) {
+ PyErr_SetNone(PyExc_KeyboardInterrupt);
+ g_main_loop_quit(main_loop);
+ }
+
+ pyglib_gil_state_release(state);
+
+ return FALSE;
+}
+
+static gboolean
+pyg_signal_watch_dispatch(GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ /* We should never be dispatched */
+ g_assert_not_reached();
+ return TRUE;
+}
+
+static void
+pyg_signal_watch_finalize(GSource *source)
+{
+ PySignalWatchSource *real_source = (PySignalWatchSource*)source;
+
+ if (source != NULL) {
+ if (real_source->fds[0] != 0)
+ close(real_source->fds[0]);
+
+ if (real_source->fds[1] != 0)
+ close(real_source->fds[1]);
+ }
+}
+
+static GSourceFuncs pyg_signal_watch_funcs =
+{
+ pyg_signal_watch_prepare,
+ pyg_signal_watch_check,
+ pyg_signal_watch_dispatch,
+ pyg_signal_watch_finalize
+};
+
+static GSource *
+pyg_signal_watch_new(void)
+{
+ return g_source_new(&pyg_signal_watch_funcs, sizeof(PySignalWatchSource));
+}
+
+static int
+pyg_main_loop_new(PyGMainLoop *self, PyObject *args, PyObject *kwargs)
+{
+
+ static char *kwlist[] = { "context", "is_running", NULL };
+ PyObject *py_context = Py_None;
+ int is_running;
+ GMainContext *context;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+ "|Ob:GMainLoop.__init__",
+ kwlist, &py_context, &is_running))
+ return -1;
+
+ if (!PyObject_TypeCheck(py_context, &PyGMainContext_Type) &&
+ py_context != Py_None) {
+ PyErr_SetString(PyExc_TypeError,
+ "context must be a glib.GMainContext or None");
+ return -1;
+ }
+
+ if (py_context != Py_None) {
+ context = ((PyGMainContext*)py_context)->context;
+ } else {
+ context = NULL;
+ }
+
+ self->loop = g_main_loop_new(context, is_running);
+
+ self->signal_source = pyg_signal_watch_new();
+ g_source_attach(self->signal_source, context);
+
+ return 0;
+}
+
+static void
+pyg_main_loop_dealloc(PyGMainLoop *self)
+{
+ if (self->signal_source != NULL) {
+ g_source_destroy(self->signal_source);
+ self->signal_source = NULL;
+ }
+
+ if (self->loop != NULL) {
+ g_main_loop_unref(self->loop);
+ self->loop = NULL;
+ }
+
+ PyObject_Del(self);
+}
+
+static int
+pyg_main_loop_compare(PyGMainLoop *self, PyGMainLoop *v)
+{
+ if (self->loop == v->loop) return 0;
+ if (self->loop > v->loop) return -1;
+ return 1;
+}
+
+static PyObject *
+_wrap_g_main_loop_get_context (PyGMainLoop *loop)
+{
+ return pyglib_main_context_new(g_main_loop_get_context(loop->loop));
+}
+
+static PyObject *
+_wrap_g_main_loop_is_running (PyGMainLoop *self)
+{
+ return PyBool_FromLong(g_main_loop_is_running(self->loop));
+}
+
+static PyObject *
+_wrap_g_main_loop_quit (PyGMainLoop *self)
+{
+ g_main_loop_quit(self->loop);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+_wrap_g_main_loop_run (PyGMainLoop *self)
+{
+ GMainLoop *prev_loop;
+
+ prev_loop = pyg_save_current_main_loop(self->loop);
+
+ pyglib_begin_allow_threads;
+ g_main_loop_run(self->loop);
+ pyglib_end_allow_threads;
+
+ pyg_restore_current_main_loop(prev_loop);
+
+ if (PyErr_Occurred())
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMethodDef _PyGMainLoop_methods[] = {
+ { "get_context", (PyCFunction)_wrap_g_main_loop_get_context, METH_NOARGS },
+ { "is_running", (PyCFunction)_wrap_g_main_loop_is_running, METH_NOARGS },
+ { "quit", (PyCFunction)_wrap_g_main_loop_quit, METH_NOARGS },
+ { "run", (PyCFunction)_wrap_g_main_loop_run, METH_NOARGS },
+ { NULL, NULL, 0 }
+};
+
+PyTypeObject PyGMainLoop_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "glib.MainLoop",
+ sizeof(PyGMainLoop),
+ 0,
+ /* methods */
+ (destructor)pyg_main_loop_dealloc,
+ (printfunc)0,
+ (getattrfunc)0,
+ (setattrfunc)0,
+ (cmpfunc)pyg_main_loop_compare,
+ (reprfunc)0,
+ 0,
+ 0,
+ 0,
+ (hashfunc)0,
+ (ternaryfunc)0,
+ (reprfunc)0,
+ (getattrofunc)0,
+ (setattrofunc)0,
+ 0,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ NULL,
+ (traverseproc)0,
+ (inquiry)0,
+ (richcmpfunc)0,
+ 0,
+ (getiterfunc)0,
+ (iternextfunc)0,
+ _PyGMainLoop_methods,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ (descrgetfunc)0,
+ (descrsetfunc)0,
+ 0,
+ (initproc)pyg_main_loop_new,
+};
+
+void
+pyglib_mainloop_register_types(PyObject *d)
+{
+ PYGLIB_REGISTER_TYPE(d, PyGMainLoop_Type, "MainLoop");
+}
diff --git a/glib/pygmainloop.h b/glib/pygmainloop.h
new file mode 100644
index 0000000..cdb44db
--- /dev/null
+++ b/glib/pygmainloop.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * pyglib - Python bindings for GLib toolkit.
+ * Copyright (C) 1998-2003 James Henstridge
+ * 2004-2008 Johan Dahlin
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifndef __PYG_MAINLOOP_H__
+#define __PYG_MAINLOOP_H__
+
+typedef struct {
+ PyObject_HEAD
+ GMainLoop *loop;
+ GSource *signal_source;
+} PyGMainLoop;
+
+extern PyTypeObject PyGMainLoop_Type;
+
+void pyglib_mainloop_register_types(PyObject *d);
+
+#endif /* __PYG_MAINLOOP_H__ */
+