manage signal handler: use awesome.startup
[awesome.git] / luaa.c
blob8def66c791a0b2936baae26a4c8667dac09f326b
1 /*
2 * luaa.c - Lua configuration management
4 * Copyright © 2008-2009 Julien Danjou <julien@danjou.info>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #define _GNU_SOURCE
24 #include <lua.h>
25 #include <lauxlib.h>
26 #include <lualib.h>
28 #include <basedir_fs.h>
30 #include <xcb/xcb_atom.h>
32 #include "awesome.h"
33 #include "config.h"
34 #include "objects/timer.h"
35 #include "awesome-version-internal.h"
36 #include "ewmh.h"
37 #include "luaa.h"
38 #include "spawn.h"
39 #include "objects/tag.h"
40 #include "objects/client.h"
41 #include "objects/drawin.h"
42 #include "objects/drawable.h"
43 #include "screen.h"
44 #include "event.h"
45 #include "property.h"
46 #include "selection.h"
47 #include "systray.h"
48 #include "common/xcursor.h"
49 #include "common/buffer.h"
50 #include "common/backtrace.h"
52 #ifdef WITH_DBUS
53 extern const struct luaL_Reg awesome_dbus_lib[];
54 #endif
55 extern const struct luaL_Reg awesome_keygrabber_lib[];
56 extern const struct luaL_Reg awesome_mousegrabber_lib[];
57 extern const struct luaL_Reg awesome_root_lib[];
58 extern const struct luaL_Reg awesome_mouse_methods[];
59 extern const struct luaL_Reg awesome_mouse_meta[];
60 extern const struct luaL_Reg awesome_screen_methods[];
61 extern const struct luaL_Reg awesome_screen_meta[];
63 /** Path to config file */
64 static char *conffile;
66 /** Check whether a composite manager is running.
67 * \return True if such a manager is running.
69 static bool
70 composite_manager_running(void)
72 xcb_intern_atom_reply_t *atom_r;
73 xcb_get_selection_owner_reply_t *selection_r;
74 char *atom_name;
75 bool result;
77 if(!(atom_name = xcb_atom_name_by_screen("_NET_WM_CM", globalconf.default_screen)))
79 warn("error getting composite manager atom");
80 return false;
83 atom_r = xcb_intern_atom_reply(globalconf.connection,
84 xcb_intern_atom_unchecked(globalconf.connection, false,
85 a_strlen(atom_name), atom_name),
86 NULL);
87 p_delete(&atom_name);
88 if(!atom_r)
89 return false;
91 selection_r = xcb_get_selection_owner_reply(globalconf.connection,
92 xcb_get_selection_owner_unchecked(globalconf.connection,
93 atom_r->atom),
94 NULL);
95 p_delete(&atom_r);
97 result = selection_r != NULL && selection_r->owner != XCB_NONE;
98 p_delete(&selection_r);
100 return result;
103 /** Quit awesome.
104 * \param L The Lua VM state.
105 * \return The number of elements pushed on stack.
107 static int
108 luaA_quit(lua_State *L)
110 g_main_loop_quit(globalconf.loop);
111 return 0;
114 /** Execute another application, probably a window manager, to replace
115 * awesome.
116 * \param L The Lua VM state.
117 * \return The number of elements pushed on stack.
118 * \luastack
119 * \lparam The command line to execute.
121 static int
122 luaA_exec(lua_State *L)
124 const char *cmd = luaL_checkstring(L, 1);
126 awesome_atexit(false);
128 a_exec(cmd);
129 return 0;
132 /** Restart awesome.
134 static int
135 luaA_restart(lua_State *L)
137 awesome_restart();
138 return 0;
141 /** Load an image from a given path.
142 * \param L The Lua VM state.
143 * \return The number of elements pushed on stack.
144 * \luastack
145 * \lparam The command line to execute.
147 static int
148 luaA_load_image(lua_State *L)
150 const char *filename = luaL_checkstring(L, 1);
151 cairo_surface_t *surface = draw_load_image(L, filename);
152 if (!surface)
153 return 0;
154 /* lua has to make sure to free the ref or we have a leak */
155 lua_pushlightuserdata(L, surface);
156 return 1;
159 /** UTF-8 aware string length computing.
160 * \param L The Lua VM state.
161 * \return The number of elements pushed on stack.
163 static int
164 luaA_mbstrlen(lua_State *L)
166 const char *cmd = luaL_checkstring(L, 1);
167 lua_pushnumber(L, (ssize_t) mbstowcs(NULL, NONULL(cmd), 0));
168 return 1;
171 /** Enhanced type() function which recognize awesome objects.
172 * \param L The Lua VM state.
173 * \return The number of arguments pushed on the stack.
175 static int
176 luaAe_type(lua_State *L)
178 luaL_checkany(L, 1);
179 lua_pushstring(L, luaA_typename(L, 1));
180 return 1;
183 /** Replace various standards Lua functions with our own.
184 * \param L The Lua VM state.
186 static void
187 luaA_fixups(lua_State *L)
189 /* export string.wlen */
190 lua_getglobal(L, "string");
191 lua_pushcfunction(L, luaA_mbstrlen);
192 lua_setfield(L, -2, "wlen");
193 lua_pop(L, 1);
194 /* replace type */
195 lua_pushcfunction(L, luaAe_type);
196 lua_setglobal(L, "type");
197 /* set selection */
198 lua_pushcfunction(L, luaA_selection_get);
199 lua_setglobal(L, "selection");
202 /** awesome global table.
203 * \param L The Lua VM state.
204 * \return The number of elements pushed on stack.
205 * \luastack
206 * \lfield conffile The configuration file which has been loaded.
207 * \lfield version The version of awesome.
208 * \lfield release The release name of awesome.
209 * \lfield startup True if we are still in startup, false otherwise.
210 * \lfield startup_errors Error message for errors that occured during startup.
211 * \lfield composite_manager_running True if a composite manager is running.
213 static int
214 luaA_awesome_index(lua_State *L)
216 if(luaA_usemetatable(L, 1, 2))
217 return 1;
219 const char *buf = luaL_checkstring(L, 2);
221 if(A_STREQ(buf, "conffile"))
223 lua_pushstring(L, conffile);
224 return 1;
227 if(A_STREQ(buf, "version"))
229 lua_pushliteral(L, AWESOME_VERSION);
230 return 1;
233 if(A_STREQ(buf, "release"))
235 lua_pushliteral(L, AWESOME_RELEASE);
236 return 1;
239 if(A_STREQ(buf, "startup"))
241 lua_pushboolean(L, globalconf.loop == NULL);
242 return 1;
245 if(A_STREQ(buf, "startup_errors"))
247 if (globalconf.startup_errors.len == 0)
248 return 0;
249 lua_pushstring(L, globalconf.startup_errors.s);
250 return 1;
253 if(A_STREQ(buf, "composite_manager_running"))
255 lua_pushboolean(L, composite_manager_running());
256 return 1;
259 return luaA_default_index(L);
262 /** Add a global signal.
263 * \param L The Lua VM state.
264 * \return The number of elements pushed on stack.
265 * \luastack
266 * \lparam A string with the event name.
267 * \lparam The function to call.
269 static int
270 luaA_awesome_connect_signal(lua_State *L)
272 const char *name = luaL_checkstring(L, 1);
273 luaA_checkfunction(L, 2);
274 signal_connect(&global_signals, name, luaA_object_ref(L, 2));
275 return 0;
278 /** Remove a global signal.
279 * \param L The Lua VM state.
280 * \return The number of elements pushed on stack.
281 * \luastack
282 * \lparam A string with the event name.
283 * \lparam The function to call.
285 static int
286 luaA_awesome_disconnect_signal(lua_State *L)
288 const char *name = luaL_checkstring(L, 1);
289 luaA_checkfunction(L, 2);
290 const void *func = lua_topointer(L, 2);
291 signal_disconnect(&global_signals, name, func);
292 luaA_object_unref(L, (void *) func);
293 return 0;
296 /** Emit a global signal.
297 * \param L The Lua VM state.
298 * \return The number of elements pushed on stack.
299 * \luastack
300 * \lparam A string with the event name.
301 * \lparam The function to call.
303 static int
304 luaA_awesome_emit_signal(lua_State *L)
306 signal_object_emit(L, &global_signals, luaL_checkstring(L, 1), lua_gettop(L) - 1);
307 return 0;
310 static int
311 luaA_panic(lua_State *L)
313 warn("unprotected error in call to Lua API (%s)",
314 lua_tostring(L, -1));
315 buffer_t buf;
316 backtrace_get(&buf);
317 warn("dumping backtrace\n%s", buf.s);
318 warn("restarting awesome");
319 awesome_restart();
320 return 0;
323 static int
324 luaA_dofunction_on_error(lua_State *L)
326 /* duplicate string error */
327 lua_pushvalue(L, -1);
328 /* emit error signal */
329 signal_object_emit(L, &global_signals, "debug::error", 1);
331 if(!luaL_dostring(L, "return debug.traceback(\"error while running function\", 3)"))
333 /* Move traceback before error */
334 lua_insert(L, -2);
335 /* Insert sentence */
336 lua_pushliteral(L, "\nerror: ");
337 /* Move it before error */
338 lua_insert(L, -2);
339 lua_concat(L, 3);
341 return 1;
344 /** Initialize the Lua VM
345 * \param xdg An xdg handle to use to get XDG basedir.
347 void
348 luaA_init(xdgHandle* xdg)
350 lua_State *L;
351 static const struct luaL_Reg awesome_lib[] =
353 { "quit", luaA_quit },
354 { "exec", luaA_exec },
355 { "spawn", luaA_spawn },
356 { "restart", luaA_restart },
357 { "connect_signal", luaA_awesome_connect_signal },
358 { "disconnect_signal", luaA_awesome_disconnect_signal },
359 { "emit_signal", luaA_awesome_emit_signal },
360 { "systray", luaA_systray },
361 { "load_image", luaA_load_image },
362 { "register_xproperty", luaA_register_xproperty },
363 { "set_xproperty", luaA_set_xproperty },
364 { "get_xproperty", luaA_get_xproperty },
365 { "__index", luaA_awesome_index },
366 { "__newindex", luaA_default_newindex },
367 { NULL, NULL }
370 L = globalconf.L = luaL_newstate();
372 /* Set panic function */
373 lua_atpanic(L, luaA_panic);
375 /* Set error handling function */
376 lualib_dofunction_on_error = luaA_dofunction_on_error;
378 luaL_openlibs(L);
380 luaA_fixups(L);
382 luaA_object_setup(L);
384 /* Export awesome lib */
385 luaA_openlib(L, "awesome", awesome_lib, awesome_lib);
387 /* Export root lib */
388 luaA_registerlib(L, "root", awesome_root_lib);
389 lua_pop(L, 1); /* luaA_registerlib() leaves the table on stack */
391 #ifdef WITH_DBUS
392 /* Export D-Bus lib */
393 luaA_registerlib(L, "dbus", awesome_dbus_lib);
394 lua_pop(L, 1); /* luaA_registerlib() leaves the table on stack */
395 #endif
397 /* Export keygrabber lib */
398 luaA_registerlib(L, "keygrabber", awesome_keygrabber_lib);
399 lua_pop(L, 1); /* luaA_registerlib() leaves the table on stack */
401 /* Export mousegrabber lib */
402 luaA_registerlib(L, "mousegrabber", awesome_mousegrabber_lib);
403 lua_pop(L, 1); /* luaA_registerlib() leaves the table on stack */
405 /* Export screen */
406 luaA_openlib(L, "screen", awesome_screen_methods, awesome_screen_meta);
408 /* Export mouse */
409 luaA_openlib(L, "mouse", awesome_mouse_methods, awesome_mouse_meta);
411 /* Export button */
412 button_class_setup(L);
414 /* Export tag */
415 tag_class_setup(L);
417 /* Export window */
418 window_class_setup(L);
420 /* Export drawable */
421 drawable_class_setup(L);
423 /* Export drawin */
424 drawin_class_setup(L);
426 /* Export client */
427 client_class_setup(L);
429 /* Export keys */
430 key_class_setup(L);
432 /* Export timer */
433 timer_class_setup(L);
435 /* add Lua search paths */
436 lua_getglobal(L, "package");
437 if (LUA_TTABLE != lua_type(L, 1))
439 warn("package is not a table");
440 return;
442 lua_getfield(L, 1, "path");
443 if (LUA_TSTRING != lua_type(L, 2))
445 warn("package.path is not a string");
446 lua_pop(L, 1);
447 return;
450 /* add XDG_CONFIG_DIR as include path */
451 const char * const *xdgconfigdirs = xdgSearchableConfigDirectories(xdg);
452 for(; *xdgconfigdirs; xdgconfigdirs++)
454 size_t len = a_strlen(*xdgconfigdirs);
455 lua_pushliteral(L, ";");
456 lua_pushlstring(L, *xdgconfigdirs, len);
457 lua_pushliteral(L, "/awesome/?.lua");
458 lua_concat(L, 3);
460 lua_pushliteral(L, ";");
461 lua_pushlstring(L, *xdgconfigdirs, len);
462 lua_pushliteral(L, "/awesome/?/init.lua");
463 lua_concat(L, 3);
465 lua_concat(L, 3); /* concatenate with package.path */
468 /* add Lua lib path (/usr/share/awesome/lib by default) */
469 lua_pushliteral(L, ";" AWESOME_LUA_LIB_PATH "/?.lua");
470 lua_pushliteral(L, ";" AWESOME_LUA_LIB_PATH "/?/init.lua");
471 lua_concat(L, 3); /* concatenate with package.path */
472 lua_setfield(L, 1, "path"); /* package.path = "concatenated string" */
474 lua_getfield(L, 1, "loaded");
476 lua_pop(L, 2); /* pop "package" and "package.loaded" */
478 signal_add(&global_signals, "debug::error");
479 signal_add(&global_signals, "debug::deprecation");
480 signal_add(&global_signals, "debug::index::miss");
481 signal_add(&global_signals, "debug::newindex::miss");
482 signal_add(&global_signals, "systray::update");
483 signal_add(&global_signals, "wallpaper_changed");
484 signal_add(&global_signals, "refresh");
485 signal_add(&global_signals, "exit");
488 static void
489 luaA_startup_error(const char *err)
491 if (globalconf.startup_errors.len > 0)
492 buffer_addsl(&globalconf.startup_errors, "\n\n");
493 buffer_adds(&globalconf.startup_errors, err);
496 static bool
497 luaA_loadrc(const char *confpath, bool run)
499 if(!luaL_loadfile(globalconf.L, confpath))
501 if(run)
503 /* Set the conffile right now so it can be used inside the
504 * configuration file. */
505 conffile = a_strdup(confpath);
506 /* Move error handling function before function */
507 lua_pushcfunction(globalconf.L, luaA_dofunction_on_error);
508 lua_insert(globalconf.L, -2);
509 if(lua_pcall(globalconf.L, 0, LUA_MULTRET, -2))
511 const char *err = lua_tostring(globalconf.L, -1);
512 luaA_startup_error(err);
513 fprintf(stderr, "%s\n", err);
514 /* An error happened, so reset this. */
515 conffile = NULL;
517 else
518 return true;
520 else
522 lua_pop(globalconf.L, 1);
523 return true;
526 else
528 const char *err = lua_tostring(globalconf.L, -1);
529 luaA_startup_error(err);
530 fprintf(stderr, "%s\n", err);
533 return false;
536 /** Load a configuration file.
537 * \param xdg An xdg handle to use to get XDG basedir.
538 * \param confpatharg The configuration file to load.
539 * \param run Run the configuration file.
541 bool
542 luaA_parserc(xdgHandle* xdg, const char *confpatharg, bool run)
544 char *confpath = NULL;
545 bool ret = false;
547 /* try to load, return if it's ok */
548 if(confpatharg)
550 if(luaA_loadrc(confpatharg, run))
552 ret = true;
553 goto bailout;
555 else if(!run)
556 goto bailout;
559 confpath = xdgConfigFind("awesome/rc.lua", xdg);
561 char *tmp = confpath;
563 /* confpath is "string1\0string2\0string3\0\0" */
564 while(*tmp)
566 if(luaA_loadrc(tmp, run))
568 ret = true;
569 goto bailout;
571 else if(!run)
572 goto bailout;
573 tmp += a_strlen(tmp) + 1;
576 bailout:
578 p_delete(&confpath);
580 return ret;
584 luaA_class_index_miss_property(lua_State *L, lua_object_t *obj)
586 signal_object_emit(L, &global_signals, "debug::index::miss", 2);
587 return 0;
591 luaA_class_newindex_miss_property(lua_State *L, lua_object_t *obj)
593 signal_object_emit(L, &global_signals, "debug::newindex::miss", 3);
594 return 0;
597 void
598 luaA_emit_refresh()
600 signal_object_emit(globalconf.L, &global_signals, "refresh", 0);
604 luaA_default_index(lua_State *L)
606 return luaA_class_index_miss_property(L, NULL);
610 luaA_default_newindex(lua_State *L)
612 return luaA_class_newindex_miss_property(L, NULL);
615 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80