Set c.screen in ewmh.tag and before tags in rules.execute
[awesome.git] / luaa.c
blob01b08d2fc87f860cd202edf43bab0b63b03646b2
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") && globalconf.startup_errors.len != 0)
247 lua_pushstring(L, globalconf.startup_errors.s);
248 return 1;
251 if(A_STREQ(buf, "composite_manager_running"))
253 lua_pushboolean(L, composite_manager_running());
254 return 1;
257 return 0;
260 /** Add a global signal.
261 * \param L The Lua VM state.
262 * \return The number of elements pushed on stack.
263 * \luastack
264 * \lparam A string with the event name.
265 * \lparam The function to call.
267 static int
268 luaA_awesome_connect_signal(lua_State *L)
270 const char *name = luaL_checkstring(L, 1);
271 luaA_checkfunction(L, 2);
272 signal_connect(&global_signals, name, luaA_object_ref(L, 2));
273 return 0;
276 /** Remove a global signal.
277 * \param L The Lua VM state.
278 * \return The number of elements pushed on stack.
279 * \luastack
280 * \lparam A string with the event name.
281 * \lparam The function to call.
283 static int
284 luaA_awesome_disconnect_signal(lua_State *L)
286 const char *name = luaL_checkstring(L, 1);
287 luaA_checkfunction(L, 2);
288 const void *func = lua_topointer(L, 2);
289 signal_disconnect(&global_signals, name, func);
290 luaA_object_unref(L, (void *) func);
291 return 0;
294 /** Emit a global signal.
295 * \param L The Lua VM state.
296 * \return The number of elements pushed on stack.
297 * \luastack
298 * \lparam A string with the event name.
299 * \lparam The function to call.
301 static int
302 luaA_awesome_emit_signal(lua_State *L)
304 signal_object_emit(L, &global_signals, luaL_checkstring(L, 1), lua_gettop(L) - 1);
305 return 0;
308 static int
309 luaA_panic(lua_State *L)
311 warn("unprotected error in call to Lua API (%s)",
312 lua_tostring(L, -1));
313 buffer_t buf;
314 backtrace_get(&buf);
315 warn("dumping backtrace\n%s", buf.s);
316 warn("restarting awesome");
317 awesome_restart();
318 return 0;
321 static int
322 luaA_dofunction_on_error(lua_State *L)
324 /* duplicate string error */
325 lua_pushvalue(L, -1);
326 /* emit error signal */
327 signal_object_emit(L, &global_signals, "debug::error", 1);
329 if(!luaL_dostring(L, "return debug.traceback(\"error while running function\", 3)"))
331 /* Move traceback before error */
332 lua_insert(L, -2);
333 /* Insert sentence */
334 lua_pushliteral(L, "\nerror: ");
335 /* Move it before error */
336 lua_insert(L, -2);
337 lua_concat(L, 3);
339 return 1;
342 /** Initialize the Lua VM
343 * \param xdg An xdg handle to use to get XDG basedir.
345 void
346 luaA_init(xdgHandle* xdg)
348 lua_State *L;
349 static const struct luaL_Reg awesome_lib[] =
351 { "quit", luaA_quit },
352 { "exec", luaA_exec },
353 { "spawn", luaA_spawn },
354 { "restart", luaA_restart },
355 { "connect_signal", luaA_awesome_connect_signal },
356 { "disconnect_signal", luaA_awesome_disconnect_signal },
357 { "emit_signal", luaA_awesome_emit_signal },
358 { "systray", luaA_systray },
359 { "load_image", luaA_load_image },
360 { "register_xproperty", luaA_register_xproperty },
361 { "set_xproperty", luaA_set_xproperty },
362 { "get_xproperty", luaA_get_xproperty },
363 { "__index", luaA_awesome_index },
364 { NULL, NULL }
367 L = globalconf.L = luaL_newstate();
369 /* Set panic function */
370 lua_atpanic(L, luaA_panic);
372 /* Set error handling function */
373 lualib_dofunction_on_error = luaA_dofunction_on_error;
375 luaL_openlibs(L);
377 luaA_fixups(L);
379 luaA_object_setup(L);
381 /* Export awesome lib */
382 luaA_openlib(L, "awesome", awesome_lib, awesome_lib);
384 /* Export root lib */
385 luaA_registerlib(L, "root", awesome_root_lib);
386 lua_pop(L, 1); /* luaA_registerlib() leaves the table on stack */
388 #ifdef WITH_DBUS
389 /* Export D-Bus lib */
390 luaA_registerlib(L, "dbus", awesome_dbus_lib);
391 lua_pop(L, 1); /* luaA_registerlib() leaves the table on stack */
392 #endif
394 /* Export keygrabber lib */
395 luaA_registerlib(L, "keygrabber", awesome_keygrabber_lib);
396 lua_pop(L, 1); /* luaA_registerlib() leaves the table on stack */
398 /* Export mousegrabber lib */
399 luaA_registerlib(L, "mousegrabber", awesome_mousegrabber_lib);
400 lua_pop(L, 1); /* luaA_registerlib() leaves the table on stack */
402 /* Export screen */
403 luaA_openlib(L, "screen", awesome_screen_methods, awesome_screen_meta);
405 /* Export mouse */
406 luaA_openlib(L, "mouse", awesome_mouse_methods, awesome_mouse_meta);
408 /* Export button */
409 button_class_setup(L);
411 /* Export tag */
412 tag_class_setup(L);
414 /* Export window */
415 window_class_setup(L);
417 /* Export drawable */
418 drawable_class_setup(L);
420 /* Export drawin */
421 drawin_class_setup(L);
423 /* Export client */
424 client_class_setup(L);
426 /* Export keys */
427 key_class_setup(L);
429 /* Export timer */
430 timer_class_setup(L);
432 /* add Lua search paths */
433 lua_getglobal(L, "package");
434 if (LUA_TTABLE != lua_type(L, 1))
436 warn("package is not a table");
437 return;
439 lua_getfield(L, 1, "path");
440 if (LUA_TSTRING != lua_type(L, 2))
442 warn("package.path is not a string");
443 lua_pop(L, 1);
444 return;
447 /* add XDG_CONFIG_DIR as include path */
448 const char * const *xdgconfigdirs = xdgSearchableConfigDirectories(xdg);
449 for(; *xdgconfigdirs; xdgconfigdirs++)
451 size_t len = a_strlen(*xdgconfigdirs);
452 lua_pushliteral(L, ";");
453 lua_pushlstring(L, *xdgconfigdirs, len);
454 lua_pushliteral(L, "/awesome/?.lua");
455 lua_concat(L, 3);
457 lua_pushliteral(L, ";");
458 lua_pushlstring(L, *xdgconfigdirs, len);
459 lua_pushliteral(L, "/awesome/?/init.lua");
460 lua_concat(L, 3);
462 lua_concat(L, 3); /* concatenate with package.path */
465 /* add Lua lib path (/usr/share/awesome/lib by default) */
466 lua_pushliteral(L, ";" AWESOME_LUA_LIB_PATH "/?.lua");
467 lua_pushliteral(L, ";" AWESOME_LUA_LIB_PATH "/?/init.lua");
468 lua_concat(L, 3); /* concatenate with package.path */
469 lua_setfield(L, 1, "path"); /* package.path = "concatenated string" */
471 lua_getfield(L, 1, "loaded");
473 lua_pop(L, 2); /* pop "package" and "package.loaded" */
475 signal_add(&global_signals, "debug::error");
476 signal_add(&global_signals, "debug::deprecation");
477 signal_add(&global_signals, "debug::index::miss");
478 signal_add(&global_signals, "debug::newindex::miss");
479 signal_add(&global_signals, "systray::update");
480 signal_add(&global_signals, "wallpaper_changed");
481 signal_add(&global_signals, "refresh");
482 signal_add(&global_signals, "exit");
485 static void
486 luaA_startup_error(const char *err)
488 if (globalconf.startup_errors.len > 0)
489 buffer_addsl(&globalconf.startup_errors, "\n\n");
490 buffer_adds(&globalconf.startup_errors, err);
493 static bool
494 luaA_loadrc(const char *confpath, bool run)
496 if(!luaL_loadfile(globalconf.L, confpath))
498 if(run)
500 /* Set the conffile right now so it can be used inside the
501 * configuration file. */
502 conffile = a_strdup(confpath);
503 /* Move error handling function before function */
504 lua_pushcfunction(globalconf.L, luaA_dofunction_on_error);
505 lua_insert(globalconf.L, -2);
506 if(lua_pcall(globalconf.L, 0, LUA_MULTRET, -2))
508 const char *err = lua_tostring(globalconf.L, -1);
509 luaA_startup_error(err);
510 fprintf(stderr, "%s\n", err);
511 /* An error happened, so reset this. */
512 conffile = NULL;
514 else
515 return true;
517 else
519 lua_pop(globalconf.L, 1);
520 return true;
523 else
525 const char *err = lua_tostring(globalconf.L, -1);
526 luaA_startup_error(err);
527 fprintf(stderr, "%s\n", err);
530 return false;
533 /** Load a configuration file.
534 * \param xdg An xdg handle to use to get XDG basedir.
535 * \param confpatharg The configuration file to load.
536 * \param run Run the configuration file.
538 bool
539 luaA_parserc(xdgHandle* xdg, const char *confpatharg, bool run)
541 char *confpath = NULL;
542 bool ret = false;
544 /* try to load, return if it's ok */
545 if(confpatharg)
547 if(luaA_loadrc(confpatharg, run))
549 ret = true;
550 goto bailout;
552 else if(!run)
553 goto bailout;
556 confpath = xdgConfigFind("awesome/rc.lua", xdg);
558 char *tmp = confpath;
560 /* confpath is "string1\0string2\0string3\0\0" */
561 while(*tmp)
563 if(luaA_loadrc(tmp, run))
565 ret = true;
566 goto bailout;
568 else if(!run)
569 goto bailout;
570 tmp += a_strlen(tmp) + 1;
573 bailout:
575 p_delete(&confpath);
577 return ret;
581 luaA_class_index_miss_property(lua_State *L, lua_object_t *obj)
583 signal_object_emit(L, &global_signals, "debug::index::miss", 2);
584 return 0;
588 luaA_class_newindex_miss_property(lua_State *L, lua_object_t *obj)
590 signal_object_emit(L, &global_signals, "debug::newindex::miss", 3);
591 return 0;
594 void
595 luaA_emit_refresh()
597 signal_object_emit(globalconf.L, &global_signals, "refresh", 0);
600 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80