2 * lua.c - Lua configuration management
4 * Copyright © 2008 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.
24 #include <sys/socket.h>
35 #include <xcb/xcb_aux.h>
37 #include "awesome-version-internal.h"
43 #include "statusbar.h"
46 #include "layouts/tile.h"
47 #include "common/socket.h"
49 extern awesome_t globalconf
;
51 extern const struct luaL_reg awesome_keygrabber_lib
[];
52 extern const struct luaL_reg awesome_mouse_methods
[];
53 extern const struct luaL_reg awesome_mouse_meta
[];
54 extern const struct luaL_reg awesome_client_methods
[];
55 extern const struct luaL_reg awesome_client_meta
[];
56 extern const struct luaL_reg awesome_titlebar_methods
[];
57 extern const struct luaL_reg awesome_titlebar_meta
[];
58 extern const struct luaL_reg awesome_tag_methods
[];
59 extern const struct luaL_reg awesome_tag_meta
[];
60 extern const struct luaL_reg awesome_widget_methods
[];
61 extern const struct luaL_reg awesome_widget_meta
[];
62 extern const struct luaL_reg awesome_statusbar_methods
[];
63 extern const struct luaL_reg awesome_statusbar_meta
[];
64 extern const struct luaL_reg awesome_keybinding_methods
[];
65 extern const struct luaL_reg awesome_keybinding_meta
[];
67 static struct sockaddr_un
*addr
;
68 static ev_io csio
= { .fd
= -1 };
70 /** Add a global mouse binding. This binding will be available when you'll
71 * click on root window.
72 * \param L The Lua VM state.
75 * \lparam A mouse button binding.
78 luaA_mouse_add(lua_State
*L
)
80 button_t
**button
= luaA_checkudata(L
, 1, "mouse");
82 button_list_push(&globalconf
.buttons
.root
, *button
);
91 luaA_quit(lua_State
*L
__attribute__ ((unused
)))
93 ev_unloop(globalconf
.loop
, 1);
97 /** Execute another application, probably a window manager, to replace
99 * \param L The Lua VM state.
102 * \lparam The command line to execute.
105 luaA_exec(lua_State
*L
)
108 const char *cmd
= luaL_checkstring(L
, 1);
110 for(c
= globalconf
.clients
; c
; c
= c
->next
)
113 xcb_aux_sync(globalconf
.connection
);
114 xcb_disconnect(globalconf
.connection
);
123 luaA_restart(lua_State
*L
__attribute__ ((unused
)))
129 /** Set the screen padding. This can be used to define margin around the
130 * screen. awesome will not use this area.
131 * \param L The Lua VM state.
132 * \return The number of elements pushed on stack.
135 * \lparam A screen number.
136 * \lparam A table with a list of margin for `right', `left', `top' and
140 luaA_screen_padding_set(lua_State
*L
)
142 int screen
= luaL_checknumber(L
, 1) - 1;
144 luaA_checkscreen(screen
);
146 luaA_checktable(L
, 2);
148 globalconf
.screens
[screen
].padding
.right
= luaA_getopt_number(L
, 2, "right", 0);
149 globalconf
.screens
[screen
].padding
.left
= luaA_getopt_number(L
, 2, "left", 0);
150 globalconf
.screens
[screen
].padding
.top
= luaA_getopt_number(L
, 2, "top", 0);
151 globalconf
.screens
[screen
].padding
.bottom
= luaA_getopt_number(L
, 2, "bottom", 0);
153 ewmh_update_workarea(screen_virttophys(screen
));
158 /** Get the screen count.
159 * \param L The Lua VM state.
160 * \return The number of elements pushed on stack.
163 * \lreturn The screen count, at least 1.
166 luaA_screen_count(lua_State
*L
)
168 lua_pushnumber(L
, globalconf
.screens_info
->nscreen
);
172 /** Return screen coordinates.
173 * \param L The Lua VM state.
174 * \return The number of elements pushed on stack.
176 * \lparam A screen number.
177 * \lreturn A table with the screen geometry: x, y, width and height.
180 luaA_screen_coords_get(lua_State
*L
)
182 int screen
= luaL_checknumber(L
, 1) - 1;
183 luaA_checkscreen(screen
);
185 lua_pushnumber(L
, globalconf
.screens_info
->geometry
[screen
].x
);
186 lua_setfield(L
, -2, "x");
187 lua_pushnumber(L
, globalconf
.screens_info
->geometry
[screen
].y
);
188 lua_setfield(L
, -2, "y");
189 lua_pushnumber(L
, globalconf
.screens_info
->geometry
[screen
].width
);
190 lua_setfield(L
, -2, "width");
191 lua_pushnumber(L
, globalconf
.screens_info
->geometry
[screen
].height
);
192 lua_setfield(L
, -2, "height");
196 /** Return the geometry of the workspace, i.e. where applications live.
197 * \param L The Lua VM state.
198 * \return The number of elements pushed on stack.
200 * \lparam A screen number.
201 * \lreturn A table with the workspace geometry.
204 luaA_screen_workspace_get(lua_State
*L
)
207 int screen
= luaL_checknumber(L
, 1) - 1;
208 luaA_checkscreen(screen
);
209 g
= screen_area_get(screen
,
210 globalconf
.screens
[screen
].statusbar
,
211 &globalconf
.screens
[screen
].padding
);
213 lua_pushnumber(L
, g
.x
);
214 lua_setfield(L
, -2, "x");
215 lua_pushnumber(L
, g
.y
);
216 lua_setfield(L
, -2, "y");
217 lua_pushnumber(L
, g
.width
);
218 lua_setfield(L
, -2, "width");
219 lua_pushnumber(L
, g
.height
);
220 lua_setfield(L
, -2, "height");
224 /** Set the function called each time a client gets focus. This function is
225 * called with the client object as argument.
226 * \param L The Lua VM state.
227 * \return The number of elements pushed on stack.
230 * \lparam A function to call each time a client gets focus.
233 luaA_hooks_focus(lua_State
*L
)
235 return luaA_registerfct(L
, &globalconf
.hooks
.focus
);
238 /** Set the function called each time a client loses focus. This function is
239 * called with the client object as argument.
240 * \param L The Lua VM state.
243 * \lparam A function to call each time a client loses focus.
246 luaA_hooks_unfocus(lua_State
*L
)
248 return luaA_registerfct(L
, &globalconf
.hooks
.unfocus
);
251 /** Set the function called each time a new client appears. This function is
252 * called with the client object as argument.
253 * \param L The Lua VM state.
256 * \lparam A function to call on each new client.
259 luaA_hooks_manage(lua_State
*L
)
261 return luaA_registerfct(L
, &globalconf
.hooks
.manage
);
264 /** Set the function called each time a client goes away. This function is
265 * called with the client object as argument.
266 * \param L The Lua VM state.
269 * \lparam A function to call when a client goes away.
272 luaA_hooks_unmanage(lua_State
*L
)
274 return luaA_registerfct(L
, &globalconf
.hooks
.unmanage
);
277 /** Set the function called each time the mouse enter a new window. This
278 * function is called with the client object as argument.
279 * \param L The Lua VM state.
282 * \lparam A function to call each time a client gets mouse over it.
285 luaA_hooks_mouseover(lua_State
*L
)
287 return luaA_registerfct(L
, &globalconf
.hooks
.mouseover
);
290 /** Set the function called on each screen arrange. This function is called
291 * with the screen number as argument.
292 * \param L The Lua VM state.
295 * \lparam A function to call on each screen arrange.
298 luaA_hooks_arrange(lua_State
*L
)
300 return luaA_registerfct(L
, &globalconf
.hooks
.arrange
);
303 /** Set the function called on each title update. This function is called with
304 * the client object as argument.
305 * \param L The Lua VM state.
308 * \lparam A function to call on each title update of each client.
311 luaA_hooks_titleupdate(lua_State
*L
)
313 return luaA_registerfct(L
, &globalconf
.hooks
.titleupdate
);
316 /** Set the function called when a client get urgency flag. This function is called with
317 * the client object as argument.
318 * \param L The Lua VM state.
321 * \lparam A function to call when a client get the urgent flag.
324 luaA_hooks_urgent(lua_State
*L
)
326 return luaA_registerfct(L
, &globalconf
.hooks
.urgent
);
329 /** Set the function to be called every N seconds.
330 * \param L The Lua VM state.
333 * \lparam The number of seconds to run function every. Set 0 to disable.
334 * \lparam A function to call every N seconds (optional).
337 luaA_hooks_timer(lua_State
*L
)
339 globalconf
.timer
.repeat
= luaL_checknumber(L
, 1);
341 if(lua_gettop(L
) == 2 && !lua_isnil(L
, 2))
342 luaA_registerfct(L
, &globalconf
.hooks
.timer
);
344 ev_timer_again(globalconf
.loop
, &globalconf
.timer
);
348 /** Set default font.
349 * \param L The Lua VM state.
352 * \lparam A string with a font name in Pango format.
355 luaA_font_set(lua_State
*L
)
357 const char *font
= luaL_checkstring(L
, 1);
358 draw_font_delete(&globalconf
.font
);
359 globalconf
.font
= draw_font_new(globalconf
.connection
,
360 globalconf
.default_screen
, font
);
364 /** Set default colors.
365 * \param L The Lua VM state.
368 * \lparam A table with `fg' and `bg' elements, containing colors.
371 luaA_colors_set(lua_State
*L
)
376 luaA_checktable(L
, 1);
378 if((buf
= luaA_getopt_lstring(L
, 1, "fg", NULL
, &len
)))
379 xcolor_init(&globalconf
.colors
.fg
, globalconf
.connection
,
380 globalconf
.default_screen
, buf
, len
);
382 if((buf
= luaA_getopt_lstring(L
, 1, "bg", NULL
, &len
)))
383 xcolor_init(&globalconf
.colors
.bg
, globalconf
.connection
,
384 globalconf
.default_screen
, buf
, len
);
388 /** Push a pointer onto the stack according to its type.
389 * \param p The pointer.
390 * \param type Its type.
393 luaA_pushpointer(lua_State
*L
, void *p
, awesome_type_t type
)
397 case AWESOME_TYPE_STATUSBAR
:
398 luaA_statusbar_userdata_new(L
, p
);
400 case AWESOME_TYPE_TITLEBAR
:
401 luaA_titlebar_userdata_new(L
, p
);
407 luaA_openlib(lua_State
*L
, const char *name
,
408 const struct luaL_reg methods
[],
409 const struct luaL_reg meta
[])
411 luaL_newmetatable(L
, name
); /* 1 */
412 lua_pushvalue(L
, -1); /* dup metatable 2 */
413 lua_setfield(L
, -2, "__index"); /* metatable.__index = metatable 1 */
415 luaL_register(L
, NULL
, meta
); /* 1 */
416 luaL_register(L
, name
, methods
); /* 2 */
417 lua_pushvalue(L
, -1); /* dup self as metatable 3 */
418 lua_setmetatable(L
, -2); /* set self as metatable 2 */
423 luaA_mbstrlen(lua_State
*L
)
425 const char *cmd
= luaL_checkstring(L
, 1);
426 lua_pushnumber(L
, mbstowcs(NULL
, NONULL(cmd
), 0));
431 luaA_fixups(lua_State
*L
)
433 lua_getglobal(L
, "string");
434 lua_pushcfunction(L
, luaA_mbstrlen
);
435 lua_setfield(L
, -2, "len");
439 /** Initialize the Lua VM
446 static const struct luaL_reg awesome_lib
[] =
448 { "quit", luaA_quit
},
449 { "exec", luaA_exec
},
450 { "restart", luaA_restart
},
451 { "mouse_add", luaA_mouse_add
},
452 { "font_set", luaA_font_set
},
453 { "colors_set", luaA_colors_set
},
456 static const struct luaL_reg awesome_screen_lib
[] =
458 { "padding_set", luaA_screen_padding_set
},
459 { "coords_get", luaA_screen_coords_get
},
460 { "workspace_get", luaA_screen_workspace_get
},
461 { "count", luaA_screen_count
},
464 static const struct luaL_reg awesome_hooks_lib
[] =
466 { "focus", luaA_hooks_focus
},
467 { "unfocus", luaA_hooks_unfocus
},
468 { "manage", luaA_hooks_manage
},
469 { "unmanage", luaA_hooks_unmanage
},
470 { "mouseover", luaA_hooks_mouseover
},
471 { "arrange", luaA_hooks_arrange
},
472 { "titleupdate", luaA_hooks_titleupdate
},
473 { "urgent", luaA_hooks_urgent
},
474 { "timer", luaA_hooks_timer
},
478 L
= globalconf
.L
= luaL_newstate();
484 /* Export awesome lib */
485 luaL_register(L
, "awesome", awesome_lib
);
487 /* Export screen lib */
488 luaL_register(L
, "screen", awesome_screen_lib
);
490 /* Export hooks lib */
491 luaL_register(L
, "hooks", awesome_hooks_lib
);
493 /* Export keygrabber lib */
494 luaL_register(L
, "keygrabber", awesome_keygrabber_lib
);
497 luaA_openlib(L
, "mouse", awesome_mouse_methods
, awesome_mouse_meta
);
500 luaA_openlib(L
, "tag", awesome_tag_methods
, awesome_tag_meta
);
502 /* Export statusbar */
503 luaA_openlib(L
, "statusbar", awesome_statusbar_methods
, awesome_statusbar_meta
);
506 luaA_openlib(L
, "widget", awesome_widget_methods
, awesome_widget_meta
);
509 luaA_openlib(L
, "client", awesome_client_methods
, awesome_client_meta
);
511 /* Export titlebar */
512 luaA_openlib(L
, "titlebar", awesome_titlebar_methods
, awesome_titlebar_meta
);
515 luaA_openlib(L
, "keybinding", awesome_keybinding_methods
, awesome_keybinding_meta
);
517 lua_pushliteral(L
, "AWESOME_VERSION");
518 lua_pushstring(L
, AWESOME_VERSION
);
519 lua_settable(L
, LUA_GLOBALSINDEX
);
521 luaA_dostring(L
, "package.path = package.path .. \";" AWESOME_LUA_LIB_PATH
"/?.lua\"");
522 luaA_dostring(L
, "package.path = package.path .. \";" AWESOME_LUA_LIB_PATH
"/?/init.lua\"");
525 globalconf
.hooks
.manage
= LUA_REFNIL
;
526 globalconf
.hooks
.unmanage
= LUA_REFNIL
;
527 globalconf
.hooks
.focus
= LUA_REFNIL
;
528 globalconf
.hooks
.unfocus
= LUA_REFNIL
;
529 globalconf
.hooks
.mouseover
= LUA_REFNIL
;
530 globalconf
.hooks
.arrange
= LUA_REFNIL
;
531 globalconf
.hooks
.titleupdate
= LUA_REFNIL
;
532 globalconf
.hooks
.urgent
= LUA_REFNIL
;
533 globalconf
.hooks
.timer
= LUA_REFNIL
;
536 #define XDG_CONFIG_HOME_DEFAULT "/.config"
538 #define AWESOME_CONFIG_FILE "/awesome/rc.lua"
540 /** Load a configuration file.
541 * \param rcfile The configuration file to load.
544 luaA_parserc(const char *confpatharg
)
547 const char *confdir
, *xdg_config_dirs
;
548 char *confpath
= NULL
, **xdg_files
, **buf
, path
[1024];
553 if(luaL_dofile(globalconf
.L
, confpatharg
))
554 fprintf(stderr
, "%s\n", lua_tostring(globalconf
.L
, -1));
559 confdir
= getenv("XDG_CONFIG_HOME");
561 if((len
= a_strlen(confdir
)))
563 len
+= sizeof(AWESOME_CONFIG_FILE
);
564 confpath
= p_new(char, len
);
565 a_strcpy(confpath
, len
, confdir
);
566 /* update package.path */
567 snprintf(path
, sizeof(path
) - 1, "package.path = package.path .. \";%s/awesome/?.lua\"", confdir
);
568 luaA_dostring(globalconf
.L
, path
);
572 confdir
= getenv("HOME");
573 len
= a_strlen(confdir
) + sizeof(AWESOME_CONFIG_FILE
)-1 + sizeof(XDG_CONFIG_HOME_DEFAULT
);
574 confpath
= p_new(char, len
);
575 a_strcpy(confpath
, len
, confdir
);
576 a_strcat(confpath
, len
, XDG_CONFIG_HOME_DEFAULT
);
577 /* update package.path */
578 snprintf(path
, sizeof(path
) - 1, "package.path = package.path .. \";%s" XDG_CONFIG_HOME_DEFAULT
"/awesome/?.lua\"", confdir
);
579 luaA_dostring(globalconf
.L
, path
);
581 a_strcat(confpath
, len
, AWESOME_CONFIG_FILE
);
583 if(luaL_dofile(globalconf
.L
, confpath
))
584 fprintf(stderr
, "%s\n", lua_tostring(globalconf
.L
, -1));
588 xdg_config_dirs
= getenv("XDG_CONFIG_DIRS");
590 if(!(len
= a_strlen(xdg_config_dirs
)))
592 xdg_config_dirs
= XDG_CONFIG_DIR
;
593 len
= sizeof(XDG_CONFIG_DIR
) - 1;
596 xdg_files
= a_strsplit(xdg_config_dirs
, len
, ':');
598 for(buf
= xdg_files
; *buf
; buf
++)
601 len
= a_strlen(*buf
) + sizeof("AWESOME_CONFIG_FILE");
602 confpath
= p_new(char, len
);
603 a_strcpy(confpath
, len
, *buf
);
604 a_strcat(confpath
, len
, AWESOME_CONFIG_FILE
);
605 snprintf(path
, sizeof(path
) - 1, "package.path = package.path .. \";%s/awesome/?.lua\"", *buf
);
606 luaA_dostring(globalconf
.L
, path
);
607 if(luaL_dofile(globalconf
.L
, confpath
))
608 fprintf(stderr
, "%s\n", lua_tostring(globalconf
.L
, -1));
613 for(buf
= xdg_files
; *buf
; buf
++)
615 p_delete(&xdg_files
);
618 /* Assure there's at least one tag */
619 for(screen
= 0; screen
< globalconf
.screens_info
->nscreen
; screen
++)
620 if(!globalconf
.screens
[screen
].tags
.len
)
621 tag_append_to_screen(tag_new("default", sizeof("default")-1, layout_tile
, 0.5, 1, 0), screen
);
627 * \param cmd The buffer to parse.
628 * \return true on succes, false on failure.
631 luaA_docmd(const char *cmd
)
635 while((p
= strchr(cmd
, '\n')))
638 luaA_dostring(globalconf
.L
, cmd
);
644 luaA_cb(EV_P_ ev_io
*w
, int revents
)
649 switch(r
= recv(w
->fd
, buf
, sizeof(buf
)-1, MSG_TRUNC
))
652 warn("error reading UNIX domain socket: %s", strerror(errno
));
658 if(r
>= ssizeof(buf
))
668 int csfd
= socket_getclient();
672 addr
= socket_getaddr(getenv("DISPLAY"));
674 if(bind(csfd
, (const struct sockaddr
*) addr
, SUN_LEN(addr
)))
676 if(errno
== EADDRINUSE
)
678 if(unlink(addr
->sun_path
))
679 warn("error unlinking existing file: %s", strerror(errno
));
680 if(bind(csfd
, (const struct sockaddr
*) addr
, SUN_LEN(addr
)))
681 warn("error binding UNIX domain socket: %s", strerror(errno
));
684 warn("error binding UNIX domain socket: %s", strerror(errno
));
686 ev_io_init(&csio
, &luaA_cb
, csfd
, EV_READ
);
687 ev_io_start(EV_DEFAULT_UC_
&csio
);
688 ev_unref(EV_DEFAULT_UC
);
692 luaA_cs_cleanup(void)
696 ev_ref(EV_DEFAULT_UC
);
697 ev_io_stop(EV_DEFAULT_UC_
&csio
);
699 warn("error closing UNIX domain socket: %s", strerror(errno
));
700 if(unlink(addr
->sun_path
))
701 warn("error unlinking UNIX domain socket: %s", strerror(errno
));
707 luaA_on_timer(EV_P_ ev_timer
*w
, int revents
)
709 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.timer
, 0, 0);
713 luaA_pushcolor(lua_State
*L
, const xcolor_t
*c
)
715 uint8_t r
= (unsigned)c
->red
* 0xff / 0xffff;
716 uint8_t g
= (unsigned)c
->green
* 0xff / 0xffff;
717 uint8_t b
= (unsigned)c
->blue
* 0xff / 0xffff;
718 uint8_t a
= (unsigned)c
->alpha
* 0xff / 0xffff;
720 snprintf(s
, sizeof(s
), "#%02x%02x%02x%02x", r
, g
, b
, a
);
721 lua_pushlstring(L
, s
, sizeof(s
));