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.
28 #include <basedir_fs.h>
30 #include <xcb/xcb_atom.h>
34 #include "objects/timer.h"
35 #include "awesome-version-internal.h"
39 #include "objects/tag.h"
40 #include "objects/client.h"
41 #include "objects/drawin.h"
42 #include "objects/drawable.h"
46 #include "selection.h"
48 #include "common/xcursor.h"
49 #include "common/buffer.h"
50 #include "common/backtrace.h"
53 extern const struct luaL_Reg awesome_dbus_lib
[];
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.
70 composite_manager_running(void)
72 xcb_intern_atom_reply_t
*atom_r
;
73 xcb_get_selection_owner_reply_t
*selection_r
;
77 if(!(atom_name
= xcb_atom_name_by_screen("_NET_WM_CM", globalconf
.default_screen
)))
79 warn("error getting composite manager atom");
83 atom_r
= xcb_intern_atom_reply(globalconf
.connection
,
84 xcb_intern_atom_unchecked(globalconf
.connection
, false,
85 a_strlen(atom_name
), atom_name
),
91 selection_r
= xcb_get_selection_owner_reply(globalconf
.connection
,
92 xcb_get_selection_owner_unchecked(globalconf
.connection
,
97 result
= selection_r
!= NULL
&& selection_r
->owner
!= XCB_NONE
;
98 p_delete(&selection_r
);
104 * \param L The Lua VM state.
105 * \return The number of elements pushed on stack.
108 luaA_quit(lua_State
*L
)
110 g_main_loop_quit(globalconf
.loop
);
114 /** Execute another application, probably a window manager, to replace
116 * \param L The Lua VM state.
117 * \return The number of elements pushed on stack.
119 * \lparam The command line to execute.
122 luaA_exec(lua_State
*L
)
124 const char *cmd
= luaL_checkstring(L
, 1);
126 awesome_atexit(false);
135 luaA_restart(lua_State
*L
)
141 /** Load an image from a given path.
142 * \param L The Lua VM state.
143 * \return The number of elements pushed on stack.
145 * \lparam The command line to execute.
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
);
154 /* lua has to make sure to free the ref or we have a leak */
155 lua_pushlightuserdata(L
, surface
);
159 /** UTF-8 aware string length computing.
160 * \param L The Lua VM state.
161 * \return The number of elements pushed on stack.
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));
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.
176 luaAe_type(lua_State
*L
)
179 lua_pushstring(L
, luaA_typename(L
, 1));
183 /** Replace various standards Lua functions with our own.
184 * \param L The Lua VM state.
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");
195 lua_pushcfunction(L
, luaAe_type
);
196 lua_setglobal(L
, "type");
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.
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.
214 luaA_awesome_index(lua_State
*L
)
216 if(luaA_usemetatable(L
, 1, 2))
219 const char *buf
= luaL_checkstring(L
, 2);
221 if(A_STREQ(buf
, "conffile"))
223 lua_pushstring(L
, conffile
);
227 if(A_STREQ(buf
, "version"))
229 lua_pushliteral(L
, AWESOME_VERSION
);
233 if(A_STREQ(buf
, "release"))
235 lua_pushliteral(L
, AWESOME_RELEASE
);
239 if(A_STREQ(buf
, "startup"))
241 lua_pushboolean(L
, globalconf
.loop
== NULL
);
245 if(A_STREQ(buf
, "startup_errors"))
247 if (globalconf
.startup_errors
.len
== 0)
249 lua_pushstring(L
, globalconf
.startup_errors
.s
);
253 if(A_STREQ(buf
, "composite_manager_running"))
255 lua_pushboolean(L
, composite_manager_running());
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.
266 * \lparam A string with the event name.
267 * \lparam The function to call.
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));
278 /** Remove a global signal.
279 * \param L The Lua VM state.
280 * \return The number of elements pushed on stack.
282 * \lparam A string with the event name.
283 * \lparam The function to call.
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
);
296 /** Emit a global signal.
297 * \param L The Lua VM state.
298 * \return The number of elements pushed on stack.
300 * \lparam A string with the event name.
301 * \lparam The function to call.
304 luaA_awesome_emit_signal(lua_State
*L
)
306 signal_object_emit(L
, &global_signals
, luaL_checkstring(L
, 1), lua_gettop(L
) - 1);
311 luaA_panic(lua_State
*L
)
313 warn("unprotected error in call to Lua API (%s)",
314 lua_tostring(L
, -1));
317 warn("dumping backtrace\n%s", buf
.s
);
318 warn("restarting awesome");
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 */
335 /* Insert sentence */
336 lua_pushliteral(L
, "\nerror: ");
337 /* Move it before error */
344 /** Initialize the Lua VM
345 * \param xdg An xdg handle to use to get XDG basedir.
348 luaA_init(xdgHandle
* xdg
)
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
},
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
;
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 */
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 */
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 */
406 luaA_openlib(L
, "screen", awesome_screen_methods
, awesome_screen_meta
);
409 luaA_openlib(L
, "mouse", awesome_mouse_methods
, awesome_mouse_meta
);
412 button_class_setup(L
);
418 window_class_setup(L
);
420 /* Export drawable */
421 drawable_class_setup(L
);
424 drawin_class_setup(L
);
427 client_class_setup(L
);
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");
442 lua_getfield(L
, 1, "path");
443 if (LUA_TSTRING
!= lua_type(L
, 2))
445 warn("package.path is not a string");
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");
460 lua_pushliteral(L
, ";");
461 lua_pushlstring(L
, *xdgconfigdirs
, len
);
462 lua_pushliteral(L
, "/awesome/?/init.lua");
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");
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
);
497 luaA_loadrc(const char *confpath
, bool run
)
499 if(!luaL_loadfile(globalconf
.L
, confpath
))
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. */
522 lua_pop(globalconf
.L
, 1);
528 const char *err
= lua_tostring(globalconf
.L
, -1);
529 luaA_startup_error(err
);
530 fprintf(stderr
, "%s\n", err
);
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.
542 luaA_parserc(xdgHandle
* xdg
, const char *confpatharg
, bool run
)
544 char *confpath
= NULL
;
547 /* try to load, return if it's ok */
550 if(luaA_loadrc(confpatharg
, run
))
559 confpath
= xdgConfigFind("awesome/rc.lua", xdg
);
561 char *tmp
= confpath
;
563 /* confpath is "string1\0string2\0string3\0\0" */
566 if(luaA_loadrc(tmp
, run
))
573 tmp
+= a_strlen(tmp
) + 1;
584 luaA_class_index_miss_property(lua_State
*L
, lua_object_t
*obj
)
586 signal_object_emit(L
, &global_signals
, "debug::index::miss", 2);
591 luaA_class_newindex_miss_property(lua_State
*L
, lua_object_t
*obj
)
593 signal_object_emit(L
, &global_signals
, "debug::newindex::miss", 3);
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