summaryrefslogtreecommitdiffstats
path: root/pysource.c
blob: f3a0663d16e9f5a2c382a6107ca82262df3261ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
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);
}