Update hooks interface according to upstream
authorMyhailo Danylenko <isbear@ukrpost.net>
Wed, 31 Mar 2010 00:12:21 +0300
changeset 97 b00f9ce82016
parent 96 270ce1cfc823
child 98 59aeae623ac6
Update hooks interface according to upstream
main.c
--- a/main.c	Wed Mar 31 00:09:47 2010 +0300
+++ b/main.c	Wed Mar 31 00:12:21 2010 +0300
@@ -25,7 +25,7 @@
 #include <stdlib.h>    // getenv
 #include <string.h>    // strcmp
 
-#include <mcabber/logprint.h>    // scr_LogPrint
+#include <mcabber/logprint.h>    // scr_log_print
 #include <mcabber/screen.h>      // scr_Beep, scr_WriteIncomingMessage
 #include <mcabber/hbuf.h>        // HBB_PREFIX_INFO
 #include <mcabber/commands.h>    // process_command, cmd_add, cmd_del
@@ -60,7 +60,7 @@
 
 static module_info_t info_lua_experimental = {
 	.branch      = "experimental",
-	.api         = 5,
+	.api         = 10,
 	.version     = PROJECT_VERSION,
 	.description = DESCRIPTION,
 	.requires    = NULL,
@@ -71,7 +71,7 @@
 
 module_info_t info_lua = {
 	.branch      = "dev",
-	.api         = 4,
+	.api         = 11,
 	.version     = PROJECT_VERSION,
 	.description = DESCRIPTION,
 	.requires    = NULL,
@@ -128,7 +128,7 @@
 	}
 	luaL_pushresult (&B);
 
-	scr_LogPrint (LPRINT_LOGNORM | LPRINT_NOTUTF8, lua_tostring (L, -1));
+	scr_log_print (LPRINT_LOGNORM | LPRINT_NOTUTF8, lua_tostring (L, -1));
 	return 0;
 }
 
@@ -151,10 +151,10 @@
 		g_free (fname);
 	}
 
-	if (ret = luaL_loadfile (L, path))
-		scr_LogPrint (LPRINT_LOGNORM, "lua: Unable to compile file %s: %s", path, lua_tostring (L, -1));
-	else if (ret = lua_pcall (L, 0, LUA_MULTRET, 0))
-		scr_LogPrint (LPRINT_LOGNORM, "lua: Runtime error in file %s: %s", path, lua_tostring (L, -1));
+	if ((ret = luaL_loadfile (L, path)))
+		scr_log_print (LPRINT_LOGNORM, "lua: Unable to compile file %s: %s", path, lua_tostring (L, -1));
+	else if ((ret = lua_pcall (L, 0, LUA_MULTRET, 0)))
+		scr_log_print (LPRINT_LOGNORM, "lua: Runtime error in file %s: %s", path, lua_tostring (L, -1));
 	g_free (path);
 
 	if (ret)
@@ -229,7 +229,7 @@
 {
 	int type = luaL_checkenum_multi (L, 1, lua_lprint);
 	lua_concat (L, lua_gettop (L) - 1);
-	scr_LogPrint (type, lua_tostring (L, -1));
+	scr_log_print (type, lua_tostring (L, -1));
 	return 0;
 }
 
@@ -398,7 +398,7 @@
 	char *jid  = to_utf8 (luaL_checkstring (L, 1));
 	char *to   = jidtodisp (jid);
 	char *mesg = to_utf8 (luaL_checkstring (L, 2));
-	scr_WriteIncomingMessage (to, mesg, 0, HBB_PREFIX_INFO, 0);
+	scr_write_incoming_message (to, mesg, 0, HBB_PREFIX_INFO, 0);
 	g_free (mesg);
 	g_free (to);
 	g_free (jid);
@@ -409,7 +409,7 @@
 /// Beeps with system speaker.
 static int lua_main_beep (lua_State *L)
 {
-	scr_Beep ();
+	scr_beep ();
 	return 0;
 }
 
@@ -464,7 +464,7 @@
 		// XXX: we need not convert to utf, RS works on jids/names in locale charset,
 		// but will jidtodisp always correctly work on such tings?
 		char *jid = jidtodisp (luaL_checkstring (L, 1));
-		scr_RosterSearch (jid);
+		scr_roster_search (jid);
 		g_free (jid);
 		return 0;
 	} else { // Get
@@ -656,7 +656,7 @@
 	luaL_pushenum (cb->L, context, lua_event_context);
 	lua_pushstring (cb -> L, arg);
 	if (lua_pcall (cb->L, 2, 1, 0)) {
-		scr_LogPrint (LPRINT_LOGNORM, "lua: Event callback execution error: %s", lua_tostring (cb->L, -1));
+		scr_log_print (LPRINT_LOGNORM, "lua: Event callback execution error: %s", lua_tostring (cb->L, -1));
 		lua_pop (cb->L, 1);
 	}
 
@@ -894,7 +894,7 @@
 		lua_pushstring (cb->L, args);
 
 	if (lua_pcall (cb->L, 1, 0, 0)) {
-		scr_LogPrint (LPRINT_LOGNORM, "lua: Command execution error: %s", lua_tostring (cb->L, -1));
+		scr_log_print (LPRINT_LOGNORM, "lua: Command execution error: %s", lua_tostring (cb->L, -1));
 		lua_pop (cb->L, 1);
 	}
 }
@@ -963,6 +963,7 @@
 	char  *word = to_utf8 (luaL_checkstring (L, 2)); // XXX
 	compl_add_category_word (cid, word);
 	g_free (word);
+	return 0;
 }
 
 /// main.del_completion
@@ -974,6 +975,7 @@
 	char  *word = to_utf8 (luaL_checkstring (L, 2)); // XXX
 	compl_del_category_word (cid, word);
 	g_free (word);
+	return 0;
 }
 
 /// main.command
@@ -1071,7 +1073,7 @@
 	int ret;
 	lua_rawgeti (cb->L, LUA_REGISTRYINDEX, cb->reference);
 	if (lua_pcall (cb->L, 0, 1, 0)) {
-		scr_LogPrint (LPRINT_LOGNORM, "lua: Timer callback execution error: %s", lua_tostring (cb->L, -1));
+		scr_log_print (LPRINT_LOGNORM, "lua: Timer callback execution error: %s", lua_tostring (cb->L, -1));
 		lua_pop (cb->L, 1);
 		return FALSE;
 	}
@@ -1140,7 +1142,7 @@
 			lua_rawgeti (cb->L, LUA_REGISTRYINDEX, cb->reference);
 			lua_pushlstring (cb->L, lua_bgread_buffer, read);
 			if (lua_pcall (cb->L, 1, 1, 0)) {
-				scr_LogPrint (LPRINT_LOGNORM, "lua: Bgread callback execution error: %s", lua_tostring (cb->L, -1));
+				scr_log_print (LPRINT_LOGNORM, "lua: Bgread callback execution error: %s", lua_tostring (cb->L, -1));
 				lua_pop (cb->L, 1);
 				return FALSE;
 			}
@@ -1155,7 +1157,7 @@
 		lua_rawgeti (cb->L, LUA_REGISTRYINDEX, cb->reference);
 		lua_pushnil (cb->L);
 		if (lua_pcall (cb->L, 1, 1, 0)) {
-			scr_LogPrint (LPRINT_LOGNORM, "lua: Bgread callback execution error: %s", lua_tostring (cb->L, -1));
+			scr_log_print (LPRINT_LOGNORM, "lua: Bgread callback execution error: %s", lua_tostring (cb->L, -1));
 			lua_pop (cb->L, 1);
 			return FALSE;
 		}
@@ -1209,46 +1211,63 @@
 	return 0;
 }
 
-// MAIN INITIALIZATION CODE
+// HOOK HANDLING
 
-#ifdef LLM_LOG_HANDLER
-// FIXME: this should not be here
-guint lua_lm_log_handler_id;
+typedef struct {
+	lua_State *L;       // lua environment for handler use
+	int        nameref; // reference to hook name string
+	int        cbref;   // reference to hook handler function
+	int        selfref; // self-reference to object
+	guint      hid;     // hook id for object destruction
+} lua_hook_t;
 
-void lua_lm_log_handler (const gchar *domain, GLogLevelFlags log_level, const gchar *message, gpointer ignore)
-{
-	if (settings_opt_get_int ("lua_lm_debug"))
-		scr_LogPrint (LPRINT_LOGNORM, "%s: %s", domain, message);
-}
-#endif
+/// hook handler result
+/// What to do with hook processing afterwards
+/// G:
+static const string2enum_t lua_hook_handler_result[] = {
+	{ "proceed", HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS       },
+	{ "stop",    HOOK_HANDLER_RESULT_NO_MORE_HANDLER           },
+	{ "drop",    HOOK_HANDLER_RESULT_NO_MORE_HANDLER_DROP_DATA },
+	{ NULL,      HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS       },
+};
 
-static void do_lua(char *arg, lua_State *L)
+/// hook handler priority
+/// Feel free to specify just a number instead of some preset value.
+/// G:
+static const string2enum_t lua_hook_handler_priority[] = {
+	{ "high",      G_PRIORITY_HIGH         },
+	{ "default",   G_PRIORITY_DEFAULT      },
+	{ "idle-high", G_PRIORITY_HIGH_IDLE    },
+	{ "idle",      G_PRIORITY_DEFAULT_IDLE },
+	{ "low",       G_PRIORITY_LOW          },
+	{ NULL,        G_PRIORITY_DEFAULT      },
+};
+
+/// hook function
+/// Function to be called, when hook will be processsed.
+/// XXX: we can provide object as argument, but is this necessary?
+/// A: table (arguments hash)
+/// R: hook handler result
+static guint lua_hook_cb (const gchar *hookid, hk_arg_t *args, gpointer data)
 {
-	if (luaL_loadbuffer (L, arg, strlen (arg), "line")) {
-		scr_LogPrint (LPRINT_LOGNORM, "lua: Compilation error: %s", lua_tostring (L, -1));
-		lua_pop (L, 1);
-		return;
-	}
- 
-	if (lua_pcall (L, 0, 0, 0)) {
-		scr_LogPrint (LPRINT_NORMAL, "lua: Runtime error: %s", lua_tostring(L, -1));
-		lua_pop (L, 1);
-		return;
-	}
-}
+	lua_hook_t *cb  = data;
+	hk_arg_t   *arg = args;
+	guint       ret = HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+	lua_State  *L   = cb -> L;
 
-static void lua_hook (guint32 hookid, hk_arg_t *args, lua_State *L)
-{
-	hk_arg_t   *arg  = args;
-	const char *hook = settings_opt_get ("lua_hook_function");
-	if (!hook)
-		return;
-	lua_getglobal (L, hook);
+	if (cb -> cbref == LUA_NOREF)
+		return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+
+	lua_rawgeti (L, LUA_REGISTRYINDEX, cb -> cbref);
 	if (!lua_isfunction (L, -1)) {
 		lua_pop (L, 1);
-		return;
+		return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
 	}
+
 	lua_newtable (L);
+	lua_pushliteral (L, "hook");
+	lua_pushstring  (L, hookid);
+	lua_settable (L, -3);
 	while (arg->name != NULL) {
 		char *name  = from_utf8 (arg->name);
 		char *value = from_utf8 (arg->value);
@@ -1259,10 +1278,272 @@
 		g_free (value);
 		arg++;
 	}
-	if (lua_pcall (L, 1, 0, 0)) {
-		scr_LogPrint (LPRINT_NORMAL, "lua: Error in hook handler: %s", lua_tostring (L, -1));
+
+	if (lua_pcall (L, 1, 1, 0)) {
+		scr_log_print (LPRINT_NORMAL, "lua: Error in hook handler: %s", lua_tostring (L, -1));
+		lua_pop (L, 1);
+	} else {
+		switch (lua_type (L, -1)) {
+		case LUA_TSTRING:
+		case LUA_TNUMBER:
+			ret = luaL_checkenum (L, -1, lua_hook_handler_result);
+			break;
+		default:
+			ret = HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+			break;
+		}
 		lua_pop (L, 1);
 	}
+
+	return ret;
+}
+
+/// main.hook
+/// Installs hook handler, returns an object, that you need to keep until
+/// hook handling is no more needed.
+/// A: string (hook name), hook function, integer (priority, optional)
+/// R: userdata (hook object)
+static int lua_main_hook (lua_State *L)
+{
+	const char   *hook_name = luaL_checkstring (L, 1);
+	int           priority  = G_PRIORITY_DEFAULT;
+	lua_hook_t   *cb;
+
+	luaL_argcheck (L, lua_isfunction (L, 2), 2, "function expected");
+
+	if (lua_gettop (L) > 2)
+		priority = luaL_checkenum (L, 3, lua_hook_handler_priority);
+
+	cb = lua_newuserdata (L, sizeof (lua_hook_t));
+	luaL_getmetatable (L, "mcabber.hook");
+	lua_setmetatable (L, -2);
+
+	lua_pushvalue (L, -1);
+	cb -> selfref = luaL_ref (L, LUA_REGISTRYINDEX);
+	lua_pushvalue (L, 1);
+	cb -> nameref = luaL_ref (L, LUA_REGISTRYINDEX);
+	lua_pushvalue (L, 2);
+	cb -> cbref   = luaL_ref (L, LUA_REGISTRYINDEX);
+	cb -> L       = L;
+	cb -> hid     = hk_add_handler (lua_hook_cb, hook_name, priority, cb);
+
+	return 1;
+}
+
+static void lua_mcabber_unregister_hook (lua_State *L, lua_hook_t *cb)
+{
+	const char *name;
+
+	if (!cb -> hid || cb -> nameref == LUA_NOREF)
+		return;
+
+	lua_rawgeti (L, LUA_REGISTRYINDEX, cb -> nameref);
+	name = lua_tostring (L, -1);
+	if (name) {
+		hk_del_handler (name, cb -> hid);
+		cb -> hid = 0;
+	}
+
+	lua_pop (L, 1);
+}
+
+/// hook:del
+/// Unregisters given hook handler from mcabber. Object will be destroyed later.
+static int lua_mcabber_hook_del (lua_State *L)
+{
+	lua_hook_t *cb = luaL_checkudata (L, 1, "mcabber.hook");
+	luaL_argcheck (L, cb != NULL, 1, "mcabber hook object expected");
+	lua_mcabber_unregister_hook (L, cb);
+	if (cb -> selfref != LUA_NOREF) {
+		luaL_unref (L, LUA_REGISTRYINDEX, cb -> selfref);
+		cb -> selfref = LUA_NOREF;
+	}
+	return 0;
+}
+
+static int lua_mcabber_hook_gc (lua_State *L)
+{
+	lua_hook_t *cb = luaL_checkudata (L, 1, "mcabber.hook");
+	luaL_argcheck (L, cb != NULL, 1, "mcabber hook object expected");
+	lua_mcabber_unregister_hook (L, cb);
+	if (cb -> nameref != LUA_NOREF)
+		luaL_unref (L, LUA_REGISTRYINDEX, cb -> nameref);
+	if (cb -> cbref != LUA_NOREF)
+		luaL_unref (L, LUA_REGISTRYINDEX, cb -> cbref);
+	return 0;
+}
+
+static const luaL_Reg lua_mcabber_hook_reg_m[] = {
+	{ "del",  lua_mcabber_hook_del },
+	{ "__gc", lua_mcabber_hook_gc  },
+	{ NULL,   NULL                 },
+};
+
+static void lua_hook_init (lua_State *L)
+{
+	luaL_newmetatable (L, "mcabber.hook");
+	lua_pushvalue (L, -1);
+	lua_setfield (L, -2, "__index");
+	luaL_register (L, NULL, lua_mcabber_hook_reg_m);
+	lua_pop (L, 1);
+}
+
+#if 0
+// OPTION GUARDS
+
+GSList *lua_installed_guards = NULL;
+
+typedef struct {
+	lua_State *L;       // lua environment for handler use
+	int        nameref; // reference to key name string
+	int        cbref;   // reference to guard function
+//	int        objref;  // self_reference to object
+	guint      hid;     // hook id for object destruction
+} lua_guard_t;
+
+/// guard function
+/// Function to be called, when option changes it's value.
+/// Old option value is still accessible through main.option.
+/// A: string (key), string (new value)
+/// R: string (value to save in hash table)
+static gchar *lua_guard_cb (const gchar *key, const gchar *value)
+{
+	lua_guard_t *cb = ;// FIXME
+	lua_State   *L  = cb -> L;
+
+	if (cb -> cbref == LUA_NOREF)
+		return g_strdup (value);
+
+	lua_rawgeti (L, LUA_REGISTRYINDEX, cb -> cbref);
+	if (!lua_isfunction (L, -1)) {
+		lua_pop (L, 1);
+		return g_strdup (value);
+	}
+
+	lua_pushstring (L, key);
+	lua_psuhstring (L, value);
+
+	if (lua_pcall (L, 2, 1, 0)) {
+		scr_log_print (LPRINT_NORMAL, "lua: Error in hook handler: %s", lua_tostring (L, -1));
+		lua_pop (L, 1);
+		return g_strdup (value);
+	}
+
+	return g_strdup (lua_tostring (L, -1));
+}
+
+/// main.guard
+/// Installs option guard for given option. Returns guard object, that
+/// should be kept around as long, as guard is needed.
+/// A: string (option name), guard function
+/// R: userdata (guard object)
+static int lua_main_guard (lua_State *L)
+{
+	const char   *name      = luaL_checkstring (L, 1);
+	int           priority  = G_PRIORITY_DEFAULT;
+	lua_guard_t   *cb;
+
+	luaL_argcheck (L, lua_isfunction (L, 2), 2, "function expected");
+
+	cb = lua_newuserdata (L, sizeof (lua_guard_t));
+	luaL_getmetatable (L, "mcabber.guard");
+	lua_setmetatable (L, -2);
+
+	lua_pushvalue (L, 1);
+	cb -> nameref = luaL_ref (L, LUA_REGISTRYINDEX);
+	lua_pushvalue (L, 2);
+	cb -> cbref   = luaL_ref (L, LUA_REGISTRYINDEX);
+	cb -> L       = L;
+
+	settings_set_guard (name, lua_guard_cb)
+
+	return 1;
+}
+
+static void lua_mcabber_unregister_guard (lua_State *L, lua_guard_t *cb)
+{
+	const char *name;
+
+	if (cb -> nameref == LUA_NOREF)
+		return;
+
+	lua_rawgeti (L, LUA_REGISTRYINDEX, cb -> nameref);
+	name = lua_tostring (L, -1);
+	if (name) {
+		settings_del_guard (name);
+		luaL_unref (L, LUA_REGISTRYINDEX, cb -> nameref);
+		cb -> nameref = LUA_NOREF;
+	}
+
+	lua_pop (L, 1);
+}
+
+/// guard:del
+/// Unregisters given option guard from mcabber. Object will be destroyed later.
+static int lua_mcabber_guard_del (lua_State *L)
+{
+	lua_guard_t *cb = luaL_checkudata (L, 1, "mcabber.guard");
+	luaL_argcheck (L, cb != NULL, 1, "mcabber guard object expected");
+	lua_mcabber_unregister_guard (L, cb);
+	return 0;
+}
+
+static int lua_mcabber_guard_gc (lua_State *L)
+{
+	lua_hook_t *cb = luaL_checkudata (L, 1, "mcabber.guard");
+	luaL_argcheck (L, cb != NULL, 1, "mcabber guard object expected");
+	lua_mcabber_unregister_guard (L, cb);
+	if (cb -> cbref != LUA_NOREF)
+		luaL_unref (L, LUA_REGISTRYINDEX, cb -> cbref);
+	return 0;
+}
+
+static const luaL_Reg lua_mcabber_hook_reg_m[] = {
+	{ "del",  lua_mcabber_guard_del },
+	{ "__gc", lua_mcabber_guard_gc  },
+	{ NULL,   NULL                 },
+};
+
+static void lua_guard_init (lua_State *L)
+{
+	luaL_newmetatable (L, "mcabber.guard");
+	lua_pushvalue (L, -1);
+	lua_setfield (L, -2, "__index");
+	luaL_register (L, NULL, lua_mcabber_guard_reg_m);
+	lua_pop (L, 1);
+}
+
+static void lua_guard_uninit (lua_State *L)
+{
+}
+#endif
+
+// MAIN INITIALIZATION CODE
+
+#ifdef LLM_LOG_HANDLER
+// FIXME: this should not be here
+guint lua_lm_log_handler_id;
+
+void lua_lm_log_handler (const gchar *domain, GLogLevelFlags log_level, const gchar *message, gpointer ignore)
+{
+	if (settings_opt_get_int ("lua_lm_debug"))
+		scr_log_print (LPRINT_LOGNORM, "%s: %s", domain, message);
+}
+#endif
+
+static void do_lua(char *arg, lua_State *L)
+{
+	if (luaL_loadbuffer (L, arg, strlen (arg), "line")) {
+		scr_log_print (LPRINT_LOGNORM, "lua: Compilation error: %s", lua_tostring (L, -1));
+		lua_pop (L, 1);
+		return;
+	}
+ 
+	if (lua_pcall (L, 0, 0, 0)) {
+		scr_log_print (LPRINT_NORMAL, "lua: Runtime error: %s", lua_tostring(L, -1));
+		lua_pop (L, 1);
+		return;
+	}
 }
 
 static void *lua_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
@@ -1303,7 +1584,29 @@
 	reg ( full_jid       ) 
 	reg ( buddy_info     ) 
 	reg ( timer          ) 
+	reg ( alias          ) 
+	reg ( binding        ) 
+	reg ( fileoption     ) 
+	reg ( add_feature    ) 
+	reg ( del_feature    ) 
+	reg ( event          )
+	reg ( parse_args     ) 
+	reg ( add_category   ) 
+	reg ( del_category   ) 
+	reg ( add_completion ) 
+	reg ( del_completion ) 
+	reg ( command        ) 
+	reg ( print_info     ) 
+	reg ( beep           ) 
+	reg ( run            ) 
+	reg ( status         ) 
+	reg ( roster         ) 
+	reg ( current_buddy  ) 
+	reg ( full_jid       ) 
+	reg ( buddy_info     ) 
+	reg ( timer          ) 
 	reg ( bgread         ) 
+	reg ( hook           )
 	{ NULL, NULL },
 };
 #undef reg
@@ -1355,32 +1658,31 @@
 	lua_lm_log_handler_id = g_log_set_handler ("lua-lm", G_LOG_LEVEL_MASK, (GLogFunc) lua_lm_log_handler, NULL);
 #endif
 
+	lua_hook_init (lua);
+
 	{
 		char *initfile = expand_filename (settings_opt_get ("lua_init_filename"));
 		
 		if (!initfile)
-			scr_LogPrint (LPRINT_LOGNORM, "lua: Cannot determine config file name");
+			scr_log_print (LPRINT_LOGNORM, "lua: Cannot determine config file name");
 		else {
 			if (luaL_loadfile(lua, initfile)) {
-				scr_LogPrint (LPRINT_LOGNORM, "lua: Unable to compile rc file: %s", lua_tostring (lua, -1));
+				scr_log_print (LPRINT_LOGNORM, "lua: Unable to compile rc file: %s", lua_tostring (lua, -1));
 				lua_pop (lua, 1);
 			} else if (lua_pcall (lua, 0, LUA_MULTRET, 0)) {
-				scr_LogPrint (LPRINT_LOGNORM, "lua: Runtime error in rc file: %s", lua_tostring(lua, -1));
+				scr_log_print (LPRINT_LOGNORM, "lua: Runtime error in rc file: %s", lua_tostring(lua, -1));
 				lua_pop (lua, 1);
 			} else
-				scr_LogPrint (LPRINT_LOGNORM, "lua: Loaded %s", initfile);
+				scr_log_print (LPRINT_LOGNORM, "lua: Loaded %s", initfile);
 			g_free (initfile);
 		}
 	}
 
-	hk_add_handler ((hk_handler_t) lua_hook, ~((guint32)0), lua);
-
 	{
 		hk_arg_t args[] = {
-			{ "hook", "hook-start" },
-			{ NULL,   NULL         },
+			{ NULL, NULL },
 		};
-		lua_hook (0, args, lua);
+		hk_run_handlers("hook-lua-start", args);
 	}
 }
 
@@ -1441,12 +1743,11 @@
 {
 	if (lua) {
 		hk_arg_t args[] = {
-			{ "hook", "hook-quit" },
-			{ NULL,   NULL        },
+			{ NULL, NULL },
 		};
-		lua_hook (0, args, lua);
+		hk_run_handlers ("hook-lua-quit", args);
 
-		hk_del_handler ((hk_handler_t) lua_hook, lua);
+		// hook handlers will be unregistered upon objects destruction
 
 		g_slist_foreach (lua_bgreads, (GFunc) lua_bgreads_destroy, NULL);
 		g_slist_free (lua_bgreads);