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.
25 #include "globalconf.h"
27 #include "common/backtrace.h"
28 #include "common/version.h"
31 #include "objects/client.h"
32 #include "objects/drawable.h"
33 #include "objects/drawin.h"
34 #include "objects/screen.h"
35 #include "objects/tag.h"
36 #include "objects/timer.h"
38 #include "selection.h"
46 #include <basedir_fs.h>
48 #include <xcb/xcb_atom.h>
51 extern const struct luaL_Reg awesome_dbus_lib
[];
53 extern const struct luaL_Reg awesome_keygrabber_lib
[];
54 extern const struct luaL_Reg awesome_mousegrabber_lib
[];
55 extern const struct luaL_Reg awesome_root_lib
[];
56 extern const struct luaL_Reg awesome_mouse_methods
[];
57 extern const struct luaL_Reg awesome_mouse_meta
[];
59 /** Path to config file */
60 static char *conffile
;
62 /** Check whether a composite manager is running.
63 * \return True if such a manager is running.
66 composite_manager_running(void)
68 xcb_intern_atom_reply_t
*atom_r
;
69 xcb_get_selection_owner_reply_t
*selection_r
;
73 if(!(atom_name
= xcb_atom_name_by_screen("_NET_WM_CM", globalconf
.default_screen
)))
75 warn("error getting composite manager atom");
79 atom_r
= xcb_intern_atom_reply(globalconf
.connection
,
80 xcb_intern_atom_unchecked(globalconf
.connection
, false,
81 a_strlen(atom_name
), atom_name
),
87 selection_r
= xcb_get_selection_owner_reply(globalconf
.connection
,
88 xcb_get_selection_owner_unchecked(globalconf
.connection
,
93 result
= selection_r
!= NULL
&& selection_r
->owner
!= XCB_NONE
;
94 p_delete(&selection_r
);
100 * \param L The Lua VM state.
101 * \return The number of elements pushed on stack.
104 luaA_quit(lua_State
*L
)
106 g_main_loop_quit(globalconf
.loop
);
110 /** Execute another application, probably a window manager, to replace
112 * \param L The Lua VM state.
113 * \return The number of elements pushed on stack.
115 * \lparam The command line to execute.
118 luaA_exec(lua_State
*L
)
120 const char *cmd
= luaL_checkstring(L
, 1);
122 awesome_atexit(false);
131 luaA_restart(lua_State
*L
)
137 /** Load an image from a given path.
138 * \param L The Lua VM state.
139 * \return The number of elements pushed on stack.
141 * \lparam The command line to execute.
144 luaA_load_image(lua_State
*L
)
146 const char *filename
= luaL_checkstring(L
, 1);
147 cairo_surface_t
*surface
= draw_load_image(L
, filename
);
150 /* lua has to make sure to free the ref or we have a leak */
151 lua_pushlightuserdata(L
, surface
);
155 /** UTF-8 aware string length computing.
156 * \param L The Lua VM state.
157 * \return The number of elements pushed on stack.
160 luaA_mbstrlen(lua_State
*L
)
162 const char *cmd
= luaL_checkstring(L
, 1);
163 lua_pushnumber(L
, (ssize_t
) mbstowcs(NULL
, NONULL(cmd
), 0));
167 /** Enhanced type() function which recognize awesome objects.
168 * \param L The Lua VM state.
169 * \return The number of arguments pushed on the stack.
172 luaAe_type(lua_State
*L
)
175 lua_pushstring(L
, luaA_typename(L
, 1));
179 /** Replace various standards Lua functions with our own.
180 * \param L The Lua VM state.
183 luaA_fixups(lua_State
*L
)
185 /* export string.wlen */
186 lua_getglobal(L
, "string");
187 lua_pushcfunction(L
, luaA_mbstrlen
);
188 lua_setfield(L
, -2, "wlen");
191 lua_pushcfunction(L
, luaAe_type
);
192 lua_setglobal(L
, "type");
194 lua_pushcfunction(L
, luaA_selection_get
);
195 lua_setglobal(L
, "selection");
198 /** awesome global table.
199 * \param L The Lua VM state.
200 * \return The number of elements pushed on stack.
202 * \lfield conffile The configuration file which has been loaded.
203 * \lfield version The version of awesome.
204 * \lfield release The release name of awesome.
205 * \lfield startup True if we are still in startup, false otherwise.
206 * \lfield startup_errors Error message for errors that occured during startup.
207 * \lfield composite_manager_running True if a composite manager is running.
210 luaA_awesome_index(lua_State
*L
)
212 if(luaA_usemetatable(L
, 1, 2))
215 const char *buf
= luaL_checkstring(L
, 2);
217 if(A_STREQ(buf
, "conffile"))
219 lua_pushstring(L
, conffile
);
223 if(A_STREQ(buf
, "version"))
225 lua_pushstring(L
, awesome_version_string());
229 if(A_STREQ(buf
, "release"))
231 lua_pushstring(L
, awesome_release_string());
235 if(A_STREQ(buf
, "startup"))
237 lua_pushboolean(L
, globalconf
.loop
== NULL
);
241 if(A_STREQ(buf
, "startup_errors"))
243 if (globalconf
.startup_errors
.len
== 0)
245 lua_pushstring(L
, globalconf
.startup_errors
.s
);
249 if(A_STREQ(buf
, "composite_manager_running"))
251 lua_pushboolean(L
, composite_manager_running());
255 return luaA_default_index(L
);
258 /** Add a global signal.
259 * \param L The Lua VM state.
260 * \return The number of elements pushed on stack.
262 * \lparam A string with the event name.
263 * \lparam The function to call.
266 luaA_awesome_connect_signal(lua_State
*L
)
268 const char *name
= luaL_checkstring(L
, 1);
269 luaA_checkfunction(L
, 2);
270 signal_connect(&global_signals
, name
, luaA_object_ref(L
, 2));
274 /** Remove a global signal.
275 * \param L The Lua VM state.
276 * \return The number of elements pushed on stack.
278 * \lparam A string with the event name.
279 * \lparam The function to call.
282 luaA_awesome_disconnect_signal(lua_State
*L
)
284 const char *name
= luaL_checkstring(L
, 1);
285 luaA_checkfunction(L
, 2);
286 const void *func
= lua_topointer(L
, 2);
287 signal_disconnect(&global_signals
, name
, func
);
288 luaA_object_unref(L
, (void *) func
);
292 /** Emit a global signal.
293 * \param L The Lua VM state.
294 * \return The number of elements pushed on stack.
296 * \lparam A string with the event name.
297 * \lparam The function to call.
300 luaA_awesome_emit_signal(lua_State
*L
)
302 signal_object_emit(L
, &global_signals
, luaL_checkstring(L
, 1), lua_gettop(L
) - 1);
307 luaA_panic(lua_State
*L
)
309 warn("unprotected error in call to Lua API (%s)",
310 lua_tostring(L
, -1));
313 warn("dumping backtrace\n%s", buf
.s
);
314 warn("restarting awesome");
320 luaA_dofunction_on_error(lua_State
*L
)
322 /* duplicate string error */
323 lua_pushvalue(L
, -1);
324 /* emit error signal */
325 signal_object_emit(L
, &global_signals
, "debug::error", 1);
327 if(!luaL_dostring(L
, "return debug.traceback(\"error while running function\", 3)"))
329 /* Move traceback before error */
331 /* Insert sentence */
332 lua_pushliteral(L
, "\nerror: ");
333 /* Move it before error */
340 /** Initialize the Lua VM
341 * \param xdg An xdg handle to use to get XDG basedir.
344 luaA_init(xdgHandle
* xdg
)
347 static const struct luaL_Reg awesome_lib
[] =
349 { "quit", luaA_quit
},
350 { "exec", luaA_exec
},
351 { "spawn", luaA_spawn
},
352 { "restart", luaA_restart
},
353 { "connect_signal", luaA_awesome_connect_signal
},
354 { "disconnect_signal", luaA_awesome_disconnect_signal
},
355 { "emit_signal", luaA_awesome_emit_signal
},
356 { "systray", luaA_systray
},
357 { "load_image", luaA_load_image
},
358 { "register_xproperty", luaA_register_xproperty
},
359 { "set_xproperty", luaA_set_xproperty
},
360 { "get_xproperty", luaA_get_xproperty
},
361 { "__index", luaA_awesome_index
},
362 { "__newindex", luaA_default_newindex
},
366 L
= globalconf
.L
= luaL_newstate();
368 /* Set panic function */
369 lua_atpanic(L
, luaA_panic
);
371 /* Set error handling function */
372 lualib_dofunction_on_error
= luaA_dofunction_on_error
;
378 luaA_object_setup(L
);
380 /* Export awesome lib */
381 luaA_openlib(L
, "awesome", awesome_lib
, awesome_lib
);
383 /* Export root lib */
384 luaA_registerlib(L
, "root", awesome_root_lib
);
385 lua_pop(L
, 1); /* luaA_registerlib() leaves the table on stack */
388 /* Export D-Bus lib */
389 luaA_registerlib(L
, "dbus", awesome_dbus_lib
);
390 lua_pop(L
, 1); /* luaA_registerlib() leaves the table on stack */
393 /* Export keygrabber lib */
394 luaA_registerlib(L
, "keygrabber", awesome_keygrabber_lib
);
395 lua_pop(L
, 1); /* luaA_registerlib() leaves the table on stack */
397 /* Export mousegrabber lib */
398 luaA_registerlib(L
, "mousegrabber", awesome_mousegrabber_lib
);
399 lua_pop(L
, 1); /* luaA_registerlib() leaves the table on stack */
402 luaA_openlib(L
, "mouse", awesome_mouse_methods
, awesome_mouse_meta
);
405 screen_class_setup(L
);
408 button_class_setup(L
);
414 window_class_setup(L
);
416 /* Export drawable */
417 drawable_class_setup(L
);
420 drawin_class_setup(L
);
423 client_class_setup(L
);
429 timer_class_setup(L
);
431 /* add Lua search paths */
432 lua_getglobal(L
, "package");
433 if (LUA_TTABLE
!= lua_type(L
, 1))
435 warn("package is not a table");
438 lua_getfield(L
, 1, "path");
439 if (LUA_TSTRING
!= lua_type(L
, 2))
441 warn("package.path is not a string");
446 /* add XDG_CONFIG_DIR as include path */
447 const char * const *xdgconfigdirs
= xdgSearchableConfigDirectories(xdg
);
448 for(; *xdgconfigdirs
; xdgconfigdirs
++)
450 size_t len
= a_strlen(*xdgconfigdirs
);
451 lua_pushliteral(L
, ";");
452 lua_pushlstring(L
, *xdgconfigdirs
, len
);
453 lua_pushliteral(L
, "/awesome/?.lua");
456 lua_pushliteral(L
, ";");
457 lua_pushlstring(L
, *xdgconfigdirs
, len
);
458 lua_pushliteral(L
, "/awesome/?/init.lua");
461 lua_concat(L
, 3); /* concatenate with package.path */
464 /* add Lua lib path (/usr/share/awesome/lib by default) */
465 lua_pushliteral(L
, ";" AWESOME_LUA_LIB_PATH
"/?.lua");
466 lua_pushliteral(L
, ";" AWESOME_LUA_LIB_PATH
"/?/init.lua");
467 lua_concat(L
, 3); /* concatenate with package.path */
468 lua_setfield(L
, 1, "path"); /* package.path = "concatenated string" */
470 lua_getfield(L
, 1, "loaded");
472 lua_pop(L
, 2); /* pop "package" and "package.loaded" */
474 signal_add(&global_signals
, "debug::error");
475 signal_add(&global_signals
, "debug::deprecation");
476 signal_add(&global_signals
, "debug::index::miss");
477 signal_add(&global_signals
, "debug::newindex::miss");
478 signal_add(&global_signals
, "systray::update");
479 signal_add(&global_signals
, "wallpaper_changed");
480 signal_add(&global_signals
, "refresh");
481 signal_add(&global_signals
, "exit");
485 luaA_startup_error(const char *err
)
487 if (globalconf
.startup_errors
.len
> 0)
488 buffer_addsl(&globalconf
.startup_errors
, "\n\n");
489 buffer_adds(&globalconf
.startup_errors
, err
);
493 luaA_loadrc(const char *confpath
, bool run
)
495 if(!luaL_loadfile(globalconf
.L
, confpath
))
499 /* Set the conffile right now so it can be used inside the
500 * configuration file. */
501 conffile
= a_strdup(confpath
);
502 /* Move error handling function before function */
503 lua_pushcfunction(globalconf
.L
, luaA_dofunction_on_error
);
504 lua_insert(globalconf
.L
, -2);
505 if(lua_pcall(globalconf
.L
, 0, LUA_MULTRET
, -2))
507 const char *err
= lua_tostring(globalconf
.L
, -1);
508 luaA_startup_error(err
);
509 fprintf(stderr
, "%s\n", err
);
510 /* An error happened, so reset this. */
518 lua_pop(globalconf
.L
, 1);
524 const char *err
= lua_tostring(globalconf
.L
, -1);
525 luaA_startup_error(err
);
526 fprintf(stderr
, "%s\n", err
);
532 /** Load a configuration file.
533 * \param xdg An xdg handle to use to get XDG basedir.
534 * \param confpatharg The configuration file to load.
535 * \param run Run the configuration file.
538 luaA_parserc(xdgHandle
* xdg
, const char *confpatharg
, bool run
)
540 char *confpath
= NULL
;
543 /* try to load, return if it's ok */
546 if(luaA_loadrc(confpatharg
, run
))
555 confpath
= xdgConfigFind("awesome/rc.lua", xdg
);
557 char *tmp
= confpath
;
559 /* confpath is "string1\0string2\0string3\0\0" */
562 if(luaA_loadrc(tmp
, run
))
569 tmp
+= a_strlen(tmp
) + 1;
580 luaA_class_index_miss_property(lua_State
*L
, lua_object_t
*obj
)
582 signal_object_emit(L
, &global_signals
, "debug::index::miss", 2);
587 luaA_class_newindex_miss_property(lua_State
*L
, lua_object_t
*obj
)
589 signal_object_emit(L
, &global_signals
, "debug::newindex::miss", 3);
596 signal_object_emit(globalconf
.L
, &global_signals
, "refresh", 0);
600 luaA_default_index(lua_State
*L
)
602 return luaA_class_index_miss_property(L
, NULL
);
606 luaA_default_newindex(lua_State
*L
)
608 return luaA_class_newindex_miss_property(L
, NULL
);
611 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80