~ubuntu-branches/ubuntu/natty/lua-gtk/natty

« back to all changes in this revision

Viewing changes to src/glib/channel.c

  • Committer: Bazaar Package Importer
  • Author(s): Enrico Tassi
  • Date: 2009-05-17 18:16:21 UTC
  • mfrom: (1.2.1 upstream) (4.1.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20090517181621-9kmdd82nxg54jsio
* new upstream snapshot comprising many more GNOME libraries:
    Gtk, GDK, GLib, Pango, Atk, Libxml2, Cairo, Clutter, Gtkhtml, 
    GtkSourceView, Gio, Gtkspell and GConf. 
* new upstream release includes a new configure script written in Lua,
  no more bashisms there (Closes: #507205)
* renamed binary packages to liblua5.1-gnome-*
* updated standards-version to 3.8.1, no changes needed
* patch to load .so.* version of libraries and not .so (that was requiring
  -dev packages) (Closes: #522087)
* removed redundant Architecture line from the source stanza of control
  (Closes: #498120)
* updated copyright file, Wolfgang Oertl holds it for 2009 too.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* vim:sw=4:sts=4
 
2
 * Lua Gtk2 binding.
 
3
 * Handle channels, which requires a few wrappers for glib functions.
 
4
 * Copyright (C) 2007 Wolfgang Oertl
 
5
 *
 
6
 * Exported symbols:
 
7
 *   glib_init_channel
 
8
 */
 
9
 
 
10
/**
 
11
 * @class module
 
12
 * @name gtk_internal.channel
 
13
 */
 
14
 
 
15
#include "module.h"
 
16
#include "override.h"
 
17
#include <glib/giochannel.h>    // GIOChannel structure
 
18
#include <string.h>             // strcmp
 
19
 
 
20
/*-
 
21
 * When g_io_add_watch is called, a Lua stack has to be provided.  This must
 
22
 * be the global, or initial, Lua stack and not of some coroutine.  Because
 
23
 * new watches may be created from within coroutines, the initial Lua stack
 
24
 * has to be stored somewhere...
 
25
 */
 
26
static lua_State *global_lua_state;
 
27
 
 
28
 
 
29
/**
 
30
 * Check that the given Lua value is a object for a GIOChannel.
 
31
 *
 
32
 * @return the object; raises a Lua error otherwise.
 
33
 */
 
34
static GIOChannel *_get_channel(lua_State *L, int index)
 
35
{
 
36
    luaL_checktype(L, index, LUA_TUSERDATA);
 
37
    struct object *o = (struct object*) lua_touserdata(L, index);
 
38
    const char *name = api->get_object_name(o);
 
39
    if (strcmp(name, "GIOChannel"))
 
40
        luaL_error(L, "Argument %d must be a GIOChannel, not %s\n", index,
 
41
            name);
 
42
 
 
43
    return (GIOChannel*) o->p;
 
44
}
 
45
 
 
46
#if 0
 
47
/**
 
48
 * A numeric argument might be given as an ENUM.  If this is so,
 
49
 * extract the value.
 
50
 */
 
51
static int _get_int_or_enum(lua_State *L, int index)
 
52
{
 
53
    int type = lua_type(L, index);
 
54
 
 
55
    switch (type) {
 
56
        case LUA_TNUMBER:
 
57
        return lua_tonumber(L, index);
 
58
 
 
59
        case LUA_TUSERDATA:;
 
60
            typespec_t ts = { 0 };
 
61
            struct lg_enum_t *e = api->get_constant(L, index, ts, 1);
 
62
            return e->value;
 
63
    }
 
64
 
 
65
    luaL_error(L, "Expected integer or enum, got a %s\n",
 
66
        lua_typename(L, type));
 
67
    return 0;
 
68
}
 
69
 
 
70
// the user_data for g_io_add_watch_full
 
71
struct _watch_info {
 
72
    lua_State   *L;
 
73
    int         func_ref;
 
74
    int         data_ref;
 
75
    int         handle;     // for debugging
 
76
    GIOChannel  *gio;       // for debugging in _watch_destroy_notify
 
77
};
 
78
#endif
 
79
 
 
80
#if 0
 
81
 
 
82
/**
 
83
 * This is the handler for channel related events.  Call the appropriates
 
84
 * Lua callback with the prototype of GIOFunc, it is passed the following
 
85
 * arguments:
 
86
 *
 
87
 *  [1]  GIOChannel
 
88
 *  [2]  The condition that led to the activation of the callback
 
89
 *  [3]  The data that was passed to g_io_add_watch
 
90
 *
 
91
 * It is expected to return a boolean (true=keep listening for this event)
 
92
 *
 
93
 * Note: this runs within the initial Lua state.  Maybe a new state would
 
94
 * be better, i.e. in l_gtk_init luaL_newstate().  This might lead to other
 
95
 * problems, like variables not visible from within the handler.
 
96
 *
 
97
 * So, all I can do now is take care that the stack of the global Lua state
 
98
 * isn't modified - well now this would lead to strange bugs...
 
99
 *
 
100
 * @param gio  The I/O channel that was signaled
 
101
 * @param cond  Condition that caused the callback
 
102
 * @param data  a struct _watch_info
 
103
 * @return  true if to continue watching for this event, false otherwise.
 
104
 */
 
105
static gboolean _watch_handler(GIOChannel *gio, GIOCondition cond,
 
106
        gpointer data)
 
107
{
 
108
    struct _watch_info *wi = (struct _watch_info*) data;
 
109
    lua_State *L = wi->L;
 
110
    int stack_top;
 
111
    gboolean again = 0;
 
112
 
 
113
    if (gio != wi->gio) {
 
114
        printf("%s _watch_handler: GIOChannel mismatch %p != %p\n",
 
115
            api->msgprefix, gio, wi->gio);
 
116
        return 0;
 
117
    }
 
118
 
 
119
    stack_top = lua_gettop(L);
 
120
 
 
121
    // [0] the function to call
 
122
    lua_rawgeti(L, LUA_REGISTRYINDEX, wi->func_ref);
 
123
    if (lua_type(L, -1) != LUA_TFUNCTION) {
 
124
        printf("%s _watch_handler: invalid function ref %d\n",
 
125
            api->msgprefix, wi->func_ref);
 
126
        goto ex;
 
127
    }
 
128
 
 
129
    // [1] the GIOChannel; this object should already exist.  Anyway, it's not
 
130
    // new.
 
131
    typespec_t ts = api->find_struct(L, thismodule, "GIOChannel", 1);
 
132
    api->get_object(L, gio, ts, FLAG_NOT_NEW_OBJECT);
 
133
    if (lua_isnil(L, -1)) {
 
134
        printf("%s watch_handler: invalid GIOChannel (first argument)\n",
 
135
            api->msgprefix);
 
136
        goto ex;
 
137
    }
 
138
 
 
139
    // [2] the condition is FLAGS of type GIOCondition
 
140
    ts = api->find_struct(L, thismodule, "GIOCondition", 0);
 
141
    if (!ts.value)
 
142
        luaL_error(L, "internal error: enum GIOCondition not known.");
 
143
    api->push_constant(L, ts, cond);
 
144
 
 
145
    // [3] the extra data
 
146
    lua_rawgeti(L, LUA_REGISTRYINDEX, wi->data_ref);
 
147
 
 
148
    lua_call(L, 3, 1);
 
149
    again = lua_toboolean(L, -1);
 
150
 
 
151
ex:
 
152
    lua_settop(L, stack_top);
 
153
 
 
154
    /* The result of the callback is a boolean.  If it is TRUE, continue to
 
155
     * watch this event, otherwise stop doing so.
 
156
     *
 
157
     * NOTE: if you return FALSE, and do not call g_source_remove for this
 
158
     * watch, then the gtk main loop goes into 100% busy mode, while the GUI is
 
159
     * still being responsive.  Try to avoid this! ;)
 
160
     */
 
161
    return again;
 
162
}
 
163
 
 
164
#endif
 
165
 
 
166
#if 0
 
167
/**
 
168
 * Clean up the data of a watch.
 
169
 *
 
170
 * Some callback information is stored in the registry of the given Lua state;
 
171
 * remove it, then free the struct _watch_info.
 
172
 *
 
173
 * @param data  A struct _watch_info.
 
174
 */
 
175
static void _watch_destroy_notify(gpointer data)
 
176
{
 
177
    struct _watch_info *wi = (struct _watch_info*) data;
 
178
    lua_State *L = wi->L;
 
179
    /*
 
180
    printf("_watch_destroy_notify for GIOChannel %p, handle %d\n", wi->gio,
 
181
        wi->handle);
 
182
    */
 
183
    luaL_unref(L, LUA_REGISTRYINDEX, wi->func_ref);
 
184
    luaL_unref(L, LUA_REGISTRYINDEX, wi->data_ref);
 
185
    g_slice_free(struct _watch_info, wi);
 
186
}
 
187
#endif
 
188
 
 
189
 
 
190
/**
 
191
 * Build a response for the Lua caller about the result of a Channel IO
 
192
 * operation.  Should the OK response not be a simple boolean, handle this
 
193
 * instead of calling this function.
 
194
 *
 
195
 * @param L  lua_State
 
196
 * @param status  I/O status of the operation
 
197
 * @param error  Pointer to a GError structure with further information
 
198
 * @param bytes_transferred  Bytes transferred (and discarded) so far
 
199
 * @return 3 items on the Lua stack.
 
200
 */
 
201
static int _handle_channel_status(lua_State *L, GIOStatus status, GError *error,
 
202
    int bytes_transferred)
 
203
{
 
204
    switch (status) {
 
205
        case G_IO_STATUS_NORMAL:
 
206
            lua_pushboolean(L, 1);
 
207
            lua_pushliteral(L, "ok");
 
208
            lua_pushinteger(L, bytes_transferred);
 
209
            return 3;
 
210
 
 
211
        case G_IO_STATUS_AGAIN:
 
212
            lua_pushnil(L);
 
213
            lua_pushliteral(L, "timeout");
 
214
            lua_pushinteger(L, bytes_transferred);
 
215
            return 3;
 
216
        
 
217
        case G_IO_STATUS_ERROR:
 
218
            lua_pushnil(L);
 
219
            lua_pushstring(L, error->message);
 
220
            lua_pushinteger(L, bytes_transferred);
 
221
            return 3;
 
222
        
 
223
        case G_IO_STATUS_EOF:
 
224
            lua_pushnil(L);
 
225
            lua_pushliteral(L, "connection lost");
 
226
            lua_pushinteger(L, bytes_transferred);
 
227
            return 3;
 
228
    }
 
229
 
 
230
    /* not reached */
 
231
    return 0;
 
232
}
 
233
 
 
234
 
 
235
 
 
236
/**
 
237
 * Add a new watch on a GIOChannel to the main loop.  The callback function
 
238
 * will be called in the context of the main thread.  Information is stored in
 
239
 * the main thread's environment (i.e. the environment of the module gtk).
 
240
 *
 
241
 * The callback can't be run in the thread context of the caller, because
 
242
 * this thread might terminate, leaving L pointing nowhere.  Also, it can't
 
243
 * be run in the thread that will handle the callback (a thread can't resume
 
244
 * itself).
 
245
 * 
 
246
 * @name  g_io_add_watch
 
247
 * @luaparam    GIOChannel (object)
 
248
 * @luaparam    conditions (integer, or ENUM)
 
249
 * @luaparam    callback (Lua function)
 
250
 * @luaparam    thread the callback runs in
 
251
 * @luareturn   ID of the new watch; this can be used to remove it, see
 
252
 *              g_source_remove().
 
253
 */
 
254
#if 0
 
255
static int l_g_io_add_watch(lua_State *L)
 
256
{
 
257
    GIOChannel *channel = _get_channel(L, 1);
 
258
    GIOCondition condition = _get_int_or_enum(L, 2);
 
259
    luaL_checktype(L, 3, LUA_TFUNCTION);
 
260
    luaL_checkany(L, 4);
 
261
    lua_settop(L, 4);       // ignore extra args
 
262
 
 
263
    struct _watch_info *wi = g_slice_new(struct _watch_info);
 
264
 
 
265
    wi->L = global_lua_state;
 
266
    wi->gio = channel;
 
267
 
 
268
    // If the data is not in the global thread, move the arguments there.
 
269
    if (wi->L != L)
 
270
        lua_xmove(L, wi->L, 2);
 
271
 
 
272
    wi->data_ref = luaL_ref(wi->L, LUA_REGISTRYINDEX);
 
273
    wi->func_ref = luaL_ref(wi->L, LUA_REGISTRYINDEX);
 
274
 
 
275
    // use a lower priority, so that the GUI remains fully interactive.
 
276
    // Note: the inverse of this is g_source_remove; it has no
 
277
    // special wrapper, but can be called directly from Lua.
 
278
    int id = g_io_add_watch_full(channel, 3, condition, _watch_handler,
 
279
        (gpointer) wi, _watch_destroy_notify);
 
280
    wi->handle = id;
 
281
    lua_pushinteger(L, id);
 
282
 
 
283
    return 1;
 
284
}
 
285
#endif
 
286
 
 
287
 
 
288
/**
 
289
 * Read data from the channel up to a given maximum length.
 
290
 *
 
291
 * @name g_io_channel_read_chars
 
292
 * @luaparam channel
 
293
 * @luaparam maxbytes
 
294
 * @luareturn  The string read, or nil on error
 
295
 * @luareturn  on error, a message
 
296
 * @luareturn  on error, number of bytes read (and discarded)
 
297
 */
 
298
static int l_g_io_channel_read_chars(lua_State *L)
 
299
{
 
300
    GIOStatus status;
 
301
    GIOChannel *channel = _get_channel(L, 1);
 
302
    gsize buf_size = luaL_checkint(L, 2);
 
303
    gchar *buf = alloca(buf_size);
 
304
    gsize bytes_read;
 
305
    GError *error = NULL;
 
306
 
 
307
    status = g_io_channel_read_chars(channel, buf, buf_size, &bytes_read,
 
308
        &error);
 
309
 
 
310
    if (status == G_IO_STATUS_NORMAL) {
 
311
        lua_pushlstring(L, buf, bytes_read);
 
312
        return 1;
 
313
    }
 
314
 
 
315
    return _handle_channel_status(L, status, error, bytes_read);
 
316
}
 
317
 
 
318
 
 
319
/**
 
320
 * Read the next line from the channel.  Newlines at the end are chopped off
 
321
 * automatically.
 
322
 *
 
323
 * The channel has to be buffered in order for this to work.
 
324
 *
 
325
 * @name g_io_channel_read_line
 
326
 * @luaparam channel
 
327
 * @luareturn string, or nil, error message, bytes transferred
 
328
 */
 
329
static int l_g_io_channel_read_line(lua_State *L)
 
330
{
 
331
    GIOChannel *channel = _get_channel(L, 1);
 
332
    gchar *str = NULL;
 
333
    gsize length=0, terminator_pos=0;
 
334
    GError *error = NULL;
 
335
 
 
336
    GIOStatus status = g_io_channel_read_line(channel, &str, &length,
 
337
        &terminator_pos, &error);
 
338
 
 
339
    if (status == G_IO_STATUS_NORMAL) {
 
340
        if (terminator_pos)
 
341
            length = terminator_pos;
 
342
        while (length > 0 && str[length-1] < ' ')
 
343
            length --;
 
344
        lua_pushlstring(L, str, length);
 
345
        g_free(str);
 
346
        return 1;
 
347
    }
 
348
 
 
349
    return _handle_channel_status(L, status, error, 0);
 
350
}
 
351
 
 
352
/**
 
353
 * Write a buffer to the given IO Channel.
 
354
 *
 
355
 * @name g_io_channel_write_chars
 
356
 * @luaparam channel
 
357
 * @luaparam buf  The string to write
 
358
 * @luareturn  true on success, else nil
 
359
 * @luareturn  on error, a message
 
360
 */
 
361
static int l_g_io_channel_write_chars(lua_State *L)
 
362
{
 
363
    GError *error = NULL;
 
364
    gsize count, bytes_written;
 
365
    GIOChannel *channel = _get_channel(L, 1);
 
366
    const gchar *buf = lua_tolstring(L, 2, &count);
 
367
    GIOStatus status = g_io_channel_write_chars(channel, buf, count,
 
368
        &bytes_written, &error);
 
369
    /*
 
370
    printf("g_io_channel_write_chars: bytes written: %d/%d\n",
 
371
        bytes_written, count);
 
372
    */
 
373
 
 
374
    // if not all bytes were written, treat this as IO timeout.
 
375
    if (status == G_IO_STATUS_NORMAL && bytes_written < count)
 
376
        status = G_IO_STATUS_AGAIN;
 
377
    return _handle_channel_status(L, status, error, bytes_written);
 
378
}
 
379
 
 
380
 
 
381
/**
 
382
 * Flush the IO Channel.
 
383
 *
 
384
 * @name g_io_channel_flush
 
385
 * @luaparam channel
 
386
 */
 
387
static int l_g_io_channel_flush(lua_State *L)
 
388
{
 
389
    GError *error = NULL;
 
390
    GIOChannel *channel = _get_channel(L, 1);
 
391
    GIOStatus status = g_io_channel_flush(channel, &error);
 
392
    return _handle_channel_status(L, status, error, 0);
 
393
}
 
394
 
 
395
static const luaL_reg _channel_reg[] = {
 
396
    {"g_io_channel_read_chars", l_g_io_channel_read_chars },
 
397
    {"g_io_channel_read_line", l_g_io_channel_read_line },
 
398
    {"g_io_channel_write_chars", l_g_io_channel_write_chars },
 
399
    {"g_io_channel_flush", l_g_io_channel_flush },
 
400
//    {"g_io_add_watch", l_g_io_add_watch },
 
401
    { NULL, NULL }
 
402
};
 
403
 
 
404
 
 
405
static int _channel_handler(struct object *w, object_op op, int data)
 
406
{
 
407
    switch (op) {
 
408
        case WIDGET_SCORE:
 
409
            return strcmp(api->get_object_name(w), "GIOChannel") ? 0 : 100;
 
410
 
 
411
        case WIDGET_GET_REFCOUNT:
 
412
            return ((GIOChannel*) w->p)->ref_count;
 
413
 
 
414
        case WIDGET_REF:
 
415
            // GIOChannels are created with a refcount of 1.  Only add more
 
416
            // refs if this is not a new object.
 
417
            if (!data /* is_new */)
 
418
                g_io_channel_ref((GIOChannel*) w->p);
 
419
            /*
 
420
            fprintf(stderr, "%p %p channel ref - refcnt now %d\n", w, w->p,
 
421
                ((GIOChannel*)w->p)->ref_count);
 
422
            */
 
423
            break;
 
424
        
 
425
        case WIDGET_UNREF:;
 
426
            GIOChannel *ioc = (GIOChannel*) w->p;
 
427
            /*
 
428
            fprintf(stderr, "%p %p channel unref - refcnt %d.\n",
 
429
                w, w->p, ioc->ref_count);
 
430
            */
 
431
 
 
432
            // The ref count should not be zero, of course, so this is just
 
433
            // a precaution.
 
434
            if (ioc->ref_count > 0)
 
435
                g_io_channel_unref(ioc);
 
436
            w->p = NULL;
 
437
            break;
 
438
    }
 
439
 
 
440
    return 0;
 
441
}
 
442
 
 
443
 
 
444
void glib_init_channel(lua_State *L)
 
445
{
 
446
    global_lua_state = L;
 
447
    luaL_register(L, NULL, _channel_reg);
 
448
    api->register_object_type("channel", _channel_handler);
 
449
}
 
450
 
 
451