summaryrefslogtreecommitdiffstats
path: root/pysource.c
diff options
context:
space:
mode:
Diffstat (limited to 'pysource.c')
-rw-r--r--pysource.c156
1 files changed, 156 insertions, 0 deletions
diff --git a/pysource.c b/pysource.c
new file mode 100644
index 0000000..f3a0663
--- /dev/null
+++ b/pysource.c
@@ -0,0 +1,156 @@
+#include <Python.h>
+#include "pyirssi.h"
+#include "pysource.h"
+
+typedef struct _PY_SOURCE_REC
+{
+ int once;
+ int tag;
+ int fd;
+ GSList **container; /* "container" points to a list owned by a Script object */
+ PyObject *handler;
+ PyObject *data;
+} PY_SOURCE_REC;
+
+static PY_SOURCE_REC *py_source_new(GSList **list, int once, PyObject *handler, PyObject *data)
+{
+ PY_SOURCE_REC *rec;
+
+ rec = g_new0(PY_SOURCE_REC, 1);
+ rec->once = once;
+ rec->fd = -1;
+ rec->handler = handler;
+ rec->data = data;
+ rec->container = list;
+
+ Py_INCREF(handler);
+ Py_XINCREF(data);
+
+ return rec;
+}
+
+static void py_source_destroy(PY_SOURCE_REC *rec)
+{
+ g_source_remove(rec->tag);
+ Py_DECREF(rec->handler);
+ Py_XDECREF(rec->data);
+ g_free(rec);
+}
+
+static int py_source_proxy(PY_SOURCE_REC *rec)
+{
+ char args[3] = {0,0,0};
+ int fd;
+ PyObject *ret;
+ PyObject *handler, *data;
+
+ /* Copy data out of the rec (there's not much). The rec may be deleted in
+ the if block below or by the Python code executed. Protect handler & data
+ with INCREF.
+ */
+
+ fd = rec->fd;
+ handler = rec->handler;
+ data = rec->data;
+ Py_INCREF(handler);
+ Py_XINCREF(data);
+
+ if (rec->once)
+ {
+ *rec->container = g_slist_remove(*rec->container, rec);
+ py_source_destroy(rec);
+ }
+
+ /* call python function with fd and/or data if available.
+ IO handler will be called with either "iO" or "i".
+ Timeout with "O" or "".
+ */
+
+ if (fd >= 0)
+ {
+ /* IO handler */
+ args[0] = 'i';
+ if (data)
+ args[1] = 'O';
+
+ ret = PyObject_CallFunction(handler, args, fd, data);
+ }
+ else
+ {
+ /* Timeout handler */
+ if (data)
+ args[0] = 'O';
+
+ ret = PyObject_CallFunction(handler, args, data);
+ }
+
+ if (!ret)
+ PyErr_Print();
+ else
+ Py_DECREF(ret);
+
+ Py_DECREF(handler);
+ Py_XDECREF(data);
+
+ return 1;
+}
+
+int pysource_timeout_add_list(GSList **list, int msecs, PyObject *func, PyObject *data, int once)
+{
+ PY_SOURCE_REC *rec;
+
+ g_return_val_if_fail(func != NULL, -1);
+
+ rec = py_source_new(list, once, func, data);
+ rec->tag = g_timeout_add(msecs, (GSourceFunc)py_source_proxy, rec);
+
+ *list = g_slist_append(*list, rec);
+
+ return rec->tag;
+}
+
+int pysource_input_add_list(GSList **list, int fd, int cond, PyObject *func, PyObject *data, int once)
+{
+ PY_SOURCE_REC *rec;
+ GIOChannel *channel;
+
+ g_return_val_if_fail(func != NULL, 1);
+ rec = py_source_new(list, once, func, data);
+ rec->fd = fd;
+ channel = g_io_channel_unix_new(fd);
+ rec->tag = g_input_add(channel, cond, (GInputFunction)py_source_proxy, rec);
+ g_io_channel_unref(channel);
+
+ *list = g_slist_append(*list, rec);
+
+ return rec->tag;
+}
+
+int pysource_remove_tag(GSList **list, int handle)
+{
+ GSList *node;
+
+ for (node = *list; node != NULL; node = node->next)
+ {
+ PY_SOURCE_REC *rec = node->data;
+
+ if (rec->tag == handle)
+ {
+ py_source_destroy(rec);
+ *list = g_slist_delete_link(*list, node);
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+void pysource_remove_list(GSList *list)
+{
+ GSList *node;
+
+ for (node = list; node != NULL; node = node->next)
+ py_source_destroy(node->data);
+}
+