3
* Handle channels, which requires a few wrappers for glib functions.
4
* Copyright (C) 2007 Wolfgang Oertl
12
* @name gtk_internal.channel
17
#include <glib/giochannel.h> // GIOChannel structure
18
#include <string.h> // strcmp
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...
26
static lua_State *global_lua_state;
30
* Check that the given Lua value is a object for a GIOChannel.
32
* @return the object; raises a Lua error otherwise.
34
static GIOChannel *_get_channel(lua_State *L, int index)
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,
43
return (GIOChannel*) o->p;
48
* A numeric argument might be given as an ENUM. If this is so,
51
static int _get_int_or_enum(lua_State *L, int index)
53
int type = lua_type(L, index);
57
return lua_tonumber(L, index);
60
typespec_t ts = { 0 };
61
struct lg_enum_t *e = api->get_constant(L, index, ts, 1);
65
luaL_error(L, "Expected integer or enum, got a %s\n",
66
lua_typename(L, type));
70
// the user_data for g_io_add_watch_full
75
int handle; // for debugging
76
GIOChannel *gio; // for debugging in _watch_destroy_notify
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
88
* [2] The condition that led to the activation of the callback
89
* [3] The data that was passed to g_io_add_watch
91
* It is expected to return a boolean (true=keep listening for this event)
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.
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...
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.
105
static gboolean _watch_handler(GIOChannel *gio, GIOCondition cond,
108
struct _watch_info *wi = (struct _watch_info*) data;
109
lua_State *L = wi->L;
113
if (gio != wi->gio) {
114
printf("%s _watch_handler: GIOChannel mismatch %p != %p\n",
115
api->msgprefix, gio, wi->gio);
119
stack_top = lua_gettop(L);
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);
129
// [1] the GIOChannel; this object should already exist. Anyway, it's not
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",
139
// [2] the condition is FLAGS of type GIOCondition
140
ts = api->find_struct(L, thismodule, "GIOCondition", 0);
142
luaL_error(L, "internal error: enum GIOCondition not known.");
143
api->push_constant(L, ts, cond);
145
// [3] the extra data
146
lua_rawgeti(L, LUA_REGISTRYINDEX, wi->data_ref);
149
again = lua_toboolean(L, -1);
152
lua_settop(L, stack_top);
154
/* The result of the callback is a boolean. If it is TRUE, continue to
155
* watch this event, otherwise stop doing so.
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! ;)
168
* Clean up the data of a watch.
170
* Some callback information is stored in the registry of the given Lua state;
171
* remove it, then free the struct _watch_info.
173
* @param data A struct _watch_info.
175
static void _watch_destroy_notify(gpointer data)
177
struct _watch_info *wi = (struct _watch_info*) data;
178
lua_State *L = wi->L;
180
printf("_watch_destroy_notify for GIOChannel %p, handle %d\n", wi->gio,
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);
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.
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.
201
static int _handle_channel_status(lua_State *L, GIOStatus status, GError *error,
202
int bytes_transferred)
205
case G_IO_STATUS_NORMAL:
206
lua_pushboolean(L, 1);
207
lua_pushliteral(L, "ok");
208
lua_pushinteger(L, bytes_transferred);
211
case G_IO_STATUS_AGAIN:
213
lua_pushliteral(L, "timeout");
214
lua_pushinteger(L, bytes_transferred);
217
case G_IO_STATUS_ERROR:
219
lua_pushstring(L, error->message);
220
lua_pushinteger(L, bytes_transferred);
223
case G_IO_STATUS_EOF:
225
lua_pushliteral(L, "connection lost");
226
lua_pushinteger(L, bytes_transferred);
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).
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
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
255
static int l_g_io_add_watch(lua_State *L)
257
GIOChannel *channel = _get_channel(L, 1);
258
GIOCondition condition = _get_int_or_enum(L, 2);
259
luaL_checktype(L, 3, LUA_TFUNCTION);
261
lua_settop(L, 4); // ignore extra args
263
struct _watch_info *wi = g_slice_new(struct _watch_info);
265
wi->L = global_lua_state;
268
// If the data is not in the global thread, move the arguments there.
270
lua_xmove(L, wi->L, 2);
272
wi->data_ref = luaL_ref(wi->L, LUA_REGISTRYINDEX);
273
wi->func_ref = luaL_ref(wi->L, LUA_REGISTRYINDEX);
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);
281
lua_pushinteger(L, id);
289
* Read data from the channel up to a given maximum length.
291
* @name g_io_channel_read_chars
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)
298
static int l_g_io_channel_read_chars(lua_State *L)
301
GIOChannel *channel = _get_channel(L, 1);
302
gsize buf_size = luaL_checkint(L, 2);
303
gchar *buf = alloca(buf_size);
305
GError *error = NULL;
307
status = g_io_channel_read_chars(channel, buf, buf_size, &bytes_read,
310
if (status == G_IO_STATUS_NORMAL) {
311
lua_pushlstring(L, buf, bytes_read);
315
return _handle_channel_status(L, status, error, bytes_read);
320
* Read the next line from the channel. Newlines at the end are chopped off
323
* The channel has to be buffered in order for this to work.
325
* @name g_io_channel_read_line
327
* @luareturn string, or nil, error message, bytes transferred
329
static int l_g_io_channel_read_line(lua_State *L)
331
GIOChannel *channel = _get_channel(L, 1);
333
gsize length=0, terminator_pos=0;
334
GError *error = NULL;
336
GIOStatus status = g_io_channel_read_line(channel, &str, &length,
337
&terminator_pos, &error);
339
if (status == G_IO_STATUS_NORMAL) {
341
length = terminator_pos;
342
while (length > 0 && str[length-1] < ' ')
344
lua_pushlstring(L, str, length);
349
return _handle_channel_status(L, status, error, 0);
353
* Write a buffer to the given IO Channel.
355
* @name g_io_channel_write_chars
357
* @luaparam buf The string to write
358
* @luareturn true on success, else nil
359
* @luareturn on error, a message
361
static int l_g_io_channel_write_chars(lua_State *L)
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);
370
printf("g_io_channel_write_chars: bytes written: %d/%d\n",
371
bytes_written, count);
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);
382
* Flush the IO Channel.
384
* @name g_io_channel_flush
387
static int l_g_io_channel_flush(lua_State *L)
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);
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 },
405
static int _channel_handler(struct object *w, object_op op, int data)
409
return strcmp(api->get_object_name(w), "GIOChannel") ? 0 : 100;
411
case WIDGET_GET_REFCOUNT:
412
return ((GIOChannel*) w->p)->ref_count;
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);
420
fprintf(stderr, "%p %p channel ref - refcnt now %d\n", w, w->p,
421
((GIOChannel*)w->p)->ref_count);
426
GIOChannel *ioc = (GIOChannel*) w->p;
428
fprintf(stderr, "%p %p channel unref - refcnt %d.\n",
429
w, w->p, ioc->ref_count);
432
// The ref count should not be zero, of course, so this is just
434
if (ioc->ref_count > 0)
435
g_io_channel_unref(ioc);
444
void glib_init_channel(lua_State *L)
446
global_lua_state = L;
447
luaL_register(L, NULL, _channel_reg);
448
api->register_object_type("channel", _channel_handler);