Events
authorMyhailo Danylenko <isbear@ukrpost.net>
Sun, 22 Mar 2009 18:15:58 +0200
changeset 52 50d4e9bc622d
parent 51 a95a3a73482c
child 53 2162188b20cf
Events
TODO
main.c
--- a/TODO	Sun Mar 22 05:49:14 2009 +0200
+++ b/TODO	Sun Mar 22 18:15:58 2009 +0200
@@ -18,4 +18,5 @@
 eliminate main.parse_args?
 common disco routines should get connection object from outer space - no mcabber dependency, the same for forms parsing, pep sending (though it anyway needs to be converted to pubsub)...
 tune should set self-song only on reply from server
+test node config
 
--- a/main.c	Sun Mar 22 05:49:14 2009 +0200
+++ b/main.c	Sun Mar 22 18:15:58 2009 +0200
@@ -21,6 +21,7 @@
 #include "hooks.h"       // hk_add_handler, hk_del_handler
 #include "settings.h"    // settings_set, settings_del, settings_get
 #include "compl.h"       // compl_new_category, compl_add_category_word, compl_del_category_word
+#include "events.h"      // evs_*
 
 
 // global lua state object, necessary for uninitialization function
@@ -525,6 +526,105 @@
 	return 0;
 }
 
+// MCABBER EVENTS
+
+/// event context
+/// Enum, indicating what exactly caused event function firing.
+/// XXX Well, I am not really understand that EVS_* constants mapping semantics,
+///     so, I just provide data, obtained by experiment.
+/// G:
+static const string2enum_t lua_event_context[] = {
+	{ "timeout", EVS_CONTEXT_TIMEOUT  },
+	{ "cancel",  EVS_CONTEXT_CANCEL   },
+	{ "reject",  EVS_CONTEXT_USER     },
+	{ "accept",  EVS_CONTEXT_USER + 1 },
+	{ NULL,      0                    },
+};
+
+typedef struct {
+	lua_State *L;
+	int        reference;
+} lua_event_callback_t;
+
+static GSList *lua_events = NULL;
+
+/// event function
+/// Function to be called, when some event state change occurs
+/// A: event context
+static int lua_event_callback (eviqs *event, int context)
+{
+	lua_event_callback_t *cb = event->data;
+
+	lua_rawgeti (cb->L, LUA_REGISTRYINDEX, cb->reference);
+	luaL_pushenum (cb->L, context, lua_event_context);
+	if (lua_pcall (cb->L, 1, 0, 0)) {
+		scr_LogPrint (LPRINT_LOGNORM, "lua: Event callback execution error: %s", lua_tostring (cb->L, -1));
+		lua_pop (cb->L, 1);
+	}
+
+	luaL_unref (cb->L, LUA_REGISTRYINDEX, cb->reference);
+	lua_events = g_slist_remove (lua_events, event);
+	evs_del (event->id); // XXX
+
+	return 0; // XXX
+}
+
+/// main.event
+/// Creates new event. If called without arguments, returns event id list.
+/// A: event function (optional), integer (expiration timeout, optional), string (description, optional)
+/// R: string (event id) or nothing (creation error) or table (list of event names)
+static int lua_main_event (lua_State *L)
+{
+	int top = lua_gettop (L);
+	if (top > 0) { // Create
+		eviqs                *event;
+		lua_event_callback_t *cb;
+		int                   timeout = 0;
+		char                 *desc    = NULL;
+		luaL_argcheck (L, lua_type (L, 1) == LUA_TFUNCTION, 1, "event function expected");
+
+		if (top > 1) {
+			timeout = luaL_checkinteger (L, 2);
+			if (top > 2) {
+				desc = g_strdup (luaL_checkstring (L, 3)); // g_freed by mcabber
+				lua_pop (L, 2);
+			} else
+				lua_pop (L, 1);
+		}
+
+		event = evs_new (EVS_TYPE_USER, timeout);
+		if (!event)
+			return 0;
+
+		lua_pushvalue (L, 1);
+		cb            = g_new (lua_event_callback_t, 1); // g_freed by mcabber
+		cb->L         = L;
+		cb->reference = luaL_ref (L, LUA_REGISTRYINDEX);
+
+		event->data     = cb;
+		event->callback = lua_event_callback;
+		event->desc     = desc;
+
+		lua_events = g_slist_prepend (lua_events, event);
+
+		lua_pushstring (L, event->id);
+		return 1;
+	} else { // List
+		GSList *events = evs_geteventslist (0);
+		GSList *event;
+
+		lua_newtable (L);
+		for (event = events; event; event = g_slist_next (event)) {
+			lua_pushstring (L, event->data);
+			luaL_ref (L, -2);
+			g_free (event->data);
+		}
+		g_slist_free (events);
+
+		return 1;
+	}
+}
+
 // MCABBER COMMANDS
 
 /// completion type
@@ -1072,6 +1172,7 @@
 	reg ( fileoption     ) 
 	reg ( add_feature    ) 
 	reg ( del_feature    ) 
+	reg ( event          )
 	reg ( parse_args     ) 
 	reg ( add_category   ) 
 	reg ( del_category   ) 
@@ -1161,6 +1262,14 @@
 	return NULL;
 }
 
+static void lua_events_destroy (eviqs *event, gpointer ignore)
+{
+	lua_event_callback_t *cb = event->data;
+	evs_callback (event->id, EVS_CONTEXT_CANCEL); // ignore
+	luaL_unref (cb->L, LUA_REGISTRYINDEX, cb->reference);
+	evs_del (event->id);
+}
+
 static void lua_timers_destroy (guint source, gpointer ignore)
 {
 	g_source_remove (source);
@@ -1202,6 +1311,10 @@
 		g_slist_free (lua_timers);
 		lua_timers = NULL;
 
+		g_slist_foreach (lua_events, (GFunc) lua_events_destroy, NULL);
+		g_slist_free (lua_events);
+		lua_events = NULL;
+
 		g_slist_foreach (lua_added_features, (GFunc) lua_features_destroy, NULL);
 		g_slist_free (lua_added_features);
 		lua_added_features = NULL;