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>
27 #include <sys/types.h>
37 #include <xcb/xcb_aux.h>
39 #include "awesome-version-internal.h"
45 #include "statusbar.h"
48 #include "layouts/tile.h"
49 #include "common/socket.h"
51 extern awesome_t globalconf
;
53 extern const struct luaL_reg awesome_keygrabber_lib
[];
54 extern const struct luaL_reg awesome_mouse_methods
[];
55 extern const struct luaL_reg awesome_mouse_meta
[];
56 extern const struct luaL_reg awesome_screen_methods
[];
57 extern const struct luaL_reg awesome_screen_meta
[];
58 extern const struct luaL_reg awesome_client_methods
[];
59 extern const struct luaL_reg awesome_client_meta
[];
60 extern const struct luaL_reg awesome_titlebar_methods
[];
61 extern const struct luaL_reg awesome_titlebar_meta
[];
62 extern const struct luaL_reg awesome_tag_methods
[];
63 extern const struct luaL_reg awesome_tag_meta
[];
64 extern const struct luaL_reg awesome_widget_methods
[];
65 extern const struct luaL_reg awesome_widget_meta
[];
66 extern const struct luaL_reg awesome_statusbar_methods
[];
67 extern const struct luaL_reg awesome_statusbar_meta
[];
68 extern const struct luaL_reg awesome_keybinding_methods
[];
69 extern const struct luaL_reg awesome_keybinding_meta
[];
71 static struct sockaddr_un
*addr
;
72 static ev_io csio
= { .fd
= -1 };
74 /** Add a global mouse binding. This binding will be available when you'll
75 * click on root window.
76 * \param L The Lua VM state.
79 * \lparam A mouse button binding.
82 luaA_mouse_add(lua_State
*L
)
84 button_t
**button
= luaA_checkudata(L
, 1, "mouse");
86 button_list_push(&globalconf
.buttons
.root
, *button
);
95 luaA_quit(lua_State
*L
__attribute__ ((unused
)))
97 ev_unloop(globalconf
.loop
, 1);
101 /** Execute another application, probably a window manager, to replace
103 * \param L The Lua VM state.
106 * \lparam The command line to execute.
109 luaA_exec(lua_State
*L
)
112 const char *cmd
= luaL_checkstring(L
, 1);
114 for(c
= globalconf
.clients
; c
; c
= c
->next
)
117 xcb_aux_sync(globalconf
.connection
);
118 xcb_disconnect(globalconf
.connection
);
127 luaA_restart(lua_State
*L
__attribute__ ((unused
)))
133 /** Set the function called each time a client gets focus. This function is
134 * called with the client object as argument.
135 * \param L The Lua VM state.
136 * \return The number of elements pushed on stack.
139 * \lparam A function to call each time a client gets focus.
142 luaA_hooks_focus(lua_State
*L
)
144 return luaA_registerfct(L
, &globalconf
.hooks
.focus
);
147 /** Set the function called each time a client loses focus. This function is
148 * called with the client object as argument.
149 * \param L The Lua VM state.
152 * \lparam A function to call each time a client loses focus.
155 luaA_hooks_unfocus(lua_State
*L
)
157 return luaA_registerfct(L
, &globalconf
.hooks
.unfocus
);
160 /** Set the function called each time a new client appears. This function is
161 * called with the client object as argument.
162 * \param L The Lua VM state.
165 * \lparam A function to call on each new client.
168 luaA_hooks_manage(lua_State
*L
)
170 return luaA_registerfct(L
, &globalconf
.hooks
.manage
);
173 /** Set the function called each time a client goes away. This function is
174 * called with the client object as argument.
175 * \param L The Lua VM state.
178 * \lparam A function to call when a client goes away.
181 luaA_hooks_unmanage(lua_State
*L
)
183 return luaA_registerfct(L
, &globalconf
.hooks
.unmanage
);
186 /** Set the function called each time the mouse enter a new window. This
187 * function is called with the client object as argument.
188 * \param L The Lua VM state.
191 * \lparam A function to call each time a client gets mouse over it.
194 luaA_hooks_mouseover(lua_State
*L
)
196 return luaA_registerfct(L
, &globalconf
.hooks
.mouseover
);
199 /** Set the function called on each screen arrange. This function is called
200 * with the screen number as argument.
201 * \param L The Lua VM state.
204 * \lparam A function to call on each screen arrange.
207 luaA_hooks_arrange(lua_State
*L
)
209 return luaA_registerfct(L
, &globalconf
.hooks
.arrange
);
212 /** Set the function called on each title update. This function is called with
213 * the client object as argument.
214 * \param L The Lua VM state.
217 * \lparam A function to call on each title update of each client.
220 luaA_hooks_titleupdate(lua_State
*L
)
222 return luaA_registerfct(L
, &globalconf
.hooks
.titleupdate
);
225 /** Set the function called when a client get urgency flag. This function is called with
226 * the client object as argument.
227 * \param L The Lua VM state.
230 * \lparam A function to call when a client get the urgent flag.
233 luaA_hooks_urgent(lua_State
*L
)
235 return luaA_registerfct(L
, &globalconf
.hooks
.urgent
);
238 /** Set the function to be called every N seconds.
239 * \param L The Lua VM state.
242 * \lparam The number of seconds to run function every. Set 0 to disable.
243 * \lparam A function to call every N seconds (optional).
246 luaA_hooks_timer(lua_State
*L
)
248 globalconf
.timer
.repeat
= luaL_checknumber(L
, 1);
250 if(lua_gettop(L
) == 2 && !lua_isnil(L
, 2))
251 luaA_registerfct(L
, &globalconf
.hooks
.timer
);
253 ev_timer_again(globalconf
.loop
, &globalconf
.timer
);
257 /** Set default font.
258 * \param L The Lua VM state.
261 * \lparam A string with a font name in Pango format.
264 luaA_font_set(lua_State
*L
)
266 const char *font
= luaL_checkstring(L
, 1);
267 draw_font_delete(&globalconf
.font
);
268 globalconf
.font
= draw_font_new(globalconf
.connection
,
269 globalconf
.default_screen
, font
);
273 /** Set default colors.
274 * \param L The Lua VM state.
277 * \lparam A table with `fg' and `bg' elements, containing colors.
280 luaA_colors_set(lua_State
*L
)
284 int8_t colors_nbr
= -1, i
;
285 xcolor_init_request_t reqs
[2];
287 luaA_checktable(L
, 1);
289 if((buf
= luaA_getopt_lstring(L
, 1, "fg", NULL
, &len
)))
290 reqs
[++colors_nbr
] = xcolor_init_unchecked(globalconf
.connection
,
291 &globalconf
.colors
.fg
,
292 globalconf
.default_screen
,
295 if((buf
= luaA_getopt_lstring(L
, 1, "bg", NULL
, &len
)))
296 reqs
[++colors_nbr
] = xcolor_init_unchecked(globalconf
.connection
,
297 &globalconf
.colors
.bg
,
298 globalconf
.default_screen
,
301 for(i
= 0; i
<= colors_nbr
; i
++)
302 xcolor_init_reply(globalconf
.connection
, reqs
[i
]);
307 /** Push a pointer onto the stack according to its type.
308 * \param p The pointer.
309 * \param type Its type.
312 luaA_pushpointer(lua_State
*L
, void *p
, awesome_type_t type
)
316 case AWESOME_TYPE_STATUSBAR
:
317 luaA_statusbar_userdata_new(L
, p
);
319 case AWESOME_TYPE_TITLEBAR
:
320 luaA_titlebar_userdata_new(L
, p
);
326 luaA_openlib(lua_State
*L
, const char *name
,
327 const struct luaL_reg methods
[],
328 const struct luaL_reg meta
[])
330 luaL_newmetatable(L
, name
); /* 1 */
331 lua_pushvalue(L
, -1); /* dup metatable 2 */
332 lua_setfield(L
, -2, "__index"); /* metatable.__index = metatable 1 */
334 luaL_register(L
, NULL
, meta
); /* 1 */
335 luaL_register(L
, name
, methods
); /* 2 */
336 lua_pushvalue(L
, -1); /* dup self as metatable 3 */
337 lua_setmetatable(L
, -2); /* set self as metatable 2 */
342 luaA_mbstrlen(lua_State
*L
)
344 const char *cmd
= luaL_checkstring(L
, 1);
345 lua_pushnumber(L
, mbstowcs(NULL
, NONULL(cmd
), 0));
350 luaA_next(lua_State
*L
)
352 if(luaL_getmetafield(L
, 1, "__next"))
355 lua_call(L
, lua_gettop(L
) - 1, LUA_MULTRET
);
356 return lua_gettop(L
);
359 luaL_checktype(L
, 1, LUA_TTABLE
);
368 luaA_pairs(lua_State
*L
)
370 if(luaL_getmetafield(L
, 1, "__pairs"))
373 lua_call(L
, lua_gettop(L
) - 1, LUA_MULTRET
);
374 return lua_gettop(L
);
377 luaL_checktype(L
, 1, LUA_TTABLE
);
378 return luaA_generic_pairs(L
);
382 luaA_fixups(lua_State
*L
)
384 lua_getglobal(L
, "string");
385 lua_pushcfunction(L
, luaA_mbstrlen
);
386 lua_setfield(L
, -2, "len");
388 lua_pushliteral(L
, "next");
389 lua_pushcfunction(L
, luaA_next
);
390 lua_settable(L
, LUA_GLOBALSINDEX
);
391 lua_pushliteral(L
, "pairs");
392 lua_pushcfunction(L
, luaA_next
);
393 lua_pushcclosure(L
, luaA_pairs
, 1); /* pairs get next as upvalue */
394 lua_settable(L
, LUA_GLOBALSINDEX
);
398 * This table can use safely object as key.
399 * \param L The Lua VM state.
400 * \return The number of elements pushed on stack.
403 luaA_otable_index(lua_State
*L
)
407 if((obj
= lua_touserdata(L
, 2)))
411 while(lua_next(L
, 1))
413 /* check the key against the key if the key is a userdata,
414 * otherwise check it again the value. */
415 if((v
= lua_touserdata(L
, -2))
419 else if((v
= lua_touserdata(L
, -1))
426 /* removes 'value'; keeps 'key' for next iteration */
437 * This table can use safely object as key.
438 * \param L The Lua VM state.
439 * \return The number of elements pushed on stack.
442 luaA_otable_newindex(lua_State
*L
)
446 if((obj
= lua_touserdata(L
, 2)))
450 while(lua_next(L
, 1))
452 if((v
= lua_touserdata(L
, -2))
457 /* push new value on top */
459 /* set in table key = value */
463 /* removes 'value'; keeps 'key' for next iteration */
474 * This function is multi-head (Zaphod) aware and will set display to
475 * the right screen according to mouse position.
476 * \param L The Lua VM state.
477 * \return The number of elements pushed on stack
479 * \lparam The command to launch.
480 * \lparam The optional screen number to spawn the command on.
483 luaA_spawn(lua_State
*L
)
485 static const char *shell
= NULL
;
486 char display
[128], *tmp
, newdisplay
[128];
490 if(!shell
&& !(shell
= getenv("SHELL")))
493 if(lua_gettop(L
) == 2)
495 screen
= luaL_checknumber(L
, 2) - 1;
496 luaA_checkscreen(screen
);
499 cmd
= luaL_checkstring(L
, 1);
501 if(!globalconf
.screens_info
->xinerama_is_active
502 && (tmp
= getenv("DISPLAY")))
504 a_strcpy(display
, sizeof(display
) - 1, tmp
);
505 if((tmp
= strrchr(display
, '.')))
507 snprintf(newdisplay
, sizeof(newdisplay
) - 1, "%s.%d", display
, screen
);
508 setenv("DISPLAY", newdisplay
, 1);
511 /* The double-fork construct avoids zombie processes and keeps the code
512 * clean from stupid signal handlers. */
517 if(globalconf
.connection
)
518 xcb_disconnect(globalconf
.connection
);
520 execl(shell
, shell
, "-c", cmd
, NULL
);
521 warn("execl '%s -c %s' failed: %s\n", shell
, cmd
, strerror(errno
));
530 /** Initialize the Lua VM
537 static const struct luaL_reg otable_methods
[] =
539 { "__call", luaA_otable_new
},
542 static const struct luaL_reg otable_meta
[] =
544 { "__index", luaA_otable_index
},
545 { "__newindex", luaA_otable_newindex
},
548 static const struct luaL_reg awesome_lib
[] =
550 { "quit", luaA_quit
},
551 { "exec", luaA_exec
},
552 { "spawn", luaA_spawn
},
553 { "restart", luaA_restart
},
554 { "mouse_add", luaA_mouse_add
},
555 { "font_set", luaA_font_set
},
556 { "colors_set", luaA_colors_set
},
559 static const struct luaL_reg awesome_hooks_lib
[] =
561 { "focus", luaA_hooks_focus
},
562 { "unfocus", luaA_hooks_unfocus
},
563 { "manage", luaA_hooks_manage
},
564 { "unmanage", luaA_hooks_unmanage
},
565 { "mouseover", luaA_hooks_mouseover
},
566 { "arrange", luaA_hooks_arrange
},
567 { "titleupdate", luaA_hooks_titleupdate
},
568 { "urgent", luaA_hooks_urgent
},
569 { "timer", luaA_hooks_timer
},
573 L
= globalconf
.L
= luaL_newstate();
579 /* Export awesome lib */
580 luaL_register(L
, "awesome", awesome_lib
);
582 /* Export hooks lib */
583 luaL_register(L
, "hooks", awesome_hooks_lib
);
585 /* Export keygrabber lib */
586 luaL_register(L
, "keygrabber", awesome_keygrabber_lib
);
588 /* Export otable lib */
589 luaA_openlib(L
, "otable", otable_methods
, otable_meta
);
592 luaA_openlib(L
, "screen", awesome_screen_methods
, awesome_screen_meta
);
595 luaA_openlib(L
, "mouse", awesome_mouse_methods
, awesome_mouse_meta
);
598 luaA_openlib(L
, "tag", awesome_tag_methods
, awesome_tag_meta
);
600 /* Export statusbar */
601 luaA_openlib(L
, "statusbar", awesome_statusbar_methods
, awesome_statusbar_meta
);
604 luaA_openlib(L
, "widget", awesome_widget_methods
, awesome_widget_meta
);
607 luaA_openlib(L
, "client", awesome_client_methods
, awesome_client_meta
);
609 /* Export titlebar */
610 luaA_openlib(L
, "titlebar", awesome_titlebar_methods
, awesome_titlebar_meta
);
613 luaA_openlib(L
, "keybinding", awesome_keybinding_methods
, awesome_keybinding_meta
);
615 lua_pushliteral(L
, "AWESOME_VERSION");
616 lua_pushstring(L
, AWESOME_VERSION
);
617 lua_settable(L
, LUA_GLOBALSINDEX
);
619 luaA_dostring(L
, "package.path = package.path .. \";" AWESOME_LUA_LIB_PATH
"/?.lua\"");
620 luaA_dostring(L
, "package.path = package.path .. \";" AWESOME_LUA_LIB_PATH
"/?/init.lua\"");
623 globalconf
.hooks
.manage
= LUA_REFNIL
;
624 globalconf
.hooks
.unmanage
= LUA_REFNIL
;
625 globalconf
.hooks
.focus
= LUA_REFNIL
;
626 globalconf
.hooks
.unfocus
= LUA_REFNIL
;
627 globalconf
.hooks
.mouseover
= LUA_REFNIL
;
628 globalconf
.hooks
.arrange
= LUA_REFNIL
;
629 globalconf
.hooks
.titleupdate
= LUA_REFNIL
;
630 globalconf
.hooks
.urgent
= LUA_REFNIL
;
631 globalconf
.hooks
.timer
= LUA_REFNIL
;
634 #define XDG_CONFIG_HOME_DEFAULT "/.config"
636 #define AWESOME_CONFIG_FILE "/awesome/rc.lua"
638 /** Load a configuration file.
639 * \param rcfile The configuration file to load.
642 luaA_parserc(const char *confpatharg
)
645 const char *confdir
, *xdg_config_dirs
;
646 char *confpath
= NULL
, **xdg_files
, **buf
, path
[1024];
651 if(luaL_dofile(globalconf
.L
, confpatharg
))
652 fprintf(stderr
, "%s\n", lua_tostring(globalconf
.L
, -1));
657 confdir
= getenv("XDG_CONFIG_HOME");
659 if((len
= a_strlen(confdir
)))
661 len
+= sizeof(AWESOME_CONFIG_FILE
);
662 confpath
= p_new(char, len
);
663 a_strcpy(confpath
, len
, confdir
);
664 /* update package.path */
665 snprintf(path
, sizeof(path
) - 1, "package.path = package.path .. \";%s/awesome/?.lua\"", confdir
);
666 luaA_dostring(globalconf
.L
, path
);
670 confdir
= getenv("HOME");
671 len
= a_strlen(confdir
) + sizeof(AWESOME_CONFIG_FILE
)-1 + sizeof(XDG_CONFIG_HOME_DEFAULT
);
672 confpath
= p_new(char, len
);
673 a_strcpy(confpath
, len
, confdir
);
674 a_strcat(confpath
, len
, XDG_CONFIG_HOME_DEFAULT
);
675 /* update package.path */
676 snprintf(path
, sizeof(path
) - 1, "package.path = package.path .. \";%s" XDG_CONFIG_HOME_DEFAULT
"/awesome/?.lua\"", confdir
);
677 luaA_dostring(globalconf
.L
, path
);
679 a_strcat(confpath
, len
, AWESOME_CONFIG_FILE
);
681 if(luaL_dofile(globalconf
.L
, confpath
))
682 fprintf(stderr
, "%s\n", lua_tostring(globalconf
.L
, -1));
686 xdg_config_dirs
= getenv("XDG_CONFIG_DIRS");
688 if(!(len
= a_strlen(xdg_config_dirs
)))
690 xdg_config_dirs
= XDG_CONFIG_DIR
;
691 len
= sizeof(XDG_CONFIG_DIR
) - 1;
694 xdg_files
= a_strsplit(xdg_config_dirs
, len
, ':');
696 for(buf
= xdg_files
; *buf
; buf
++)
699 len
= a_strlen(*buf
) + sizeof("AWESOME_CONFIG_FILE");
700 confpath
= p_new(char, len
);
701 a_strcpy(confpath
, len
, *buf
);
702 a_strcat(confpath
, len
, AWESOME_CONFIG_FILE
);
703 snprintf(path
, sizeof(path
) - 1, "package.path = package.path .. \";%s/awesome/?.lua\"", *buf
);
704 luaA_dostring(globalconf
.L
, path
);
705 if(luaL_dofile(globalconf
.L
, confpath
))
706 fprintf(stderr
, "%s\n", lua_tostring(globalconf
.L
, -1));
711 for(buf
= xdg_files
; *buf
; buf
++)
713 p_delete(&xdg_files
);
716 /* Assure there's at least one tag */
717 for(screen
= 0; screen
< globalconf
.screens_info
->nscreen
; screen
++)
718 if(!globalconf
.screens
[screen
].tags
.len
)
719 tag_append_to_screen(tag_new("default", sizeof("default")-1, layout_tile
, 0.5, 1, 0),
720 &globalconf
.screens
[screen
]);
726 * \param cmd The buffer to parse.
727 * \return true on succes, false on failure.
730 luaA_docmd(const char *cmd
)
734 while((p
= strchr(cmd
, '\n')))
737 luaA_dostring(globalconf
.L
, cmd
);
743 luaA_cb(EV_P_ ev_io
*w
, int revents
)
748 switch(r
= recv(w
->fd
, buf
, sizeof(buf
)-1, MSG_TRUNC
))
751 warn("error reading UNIX domain socket: %s", strerror(errno
));
757 if(r
>= ssizeof(buf
))
770 int csfd
= socket_getclient();
774 addr
= socket_getaddr(getenv("DISPLAY"));
776 if(bind(csfd
, (const struct sockaddr
*) addr
, SUN_LEN(addr
)))
778 if(errno
== EADDRINUSE
)
780 if(unlink(addr
->sun_path
))
781 warn("error unlinking existing file: %s", strerror(errno
));
782 if(bind(csfd
, (const struct sockaddr
*) addr
, SUN_LEN(addr
)))
783 warn("error binding UNIX domain socket: %s", strerror(errno
));
786 warn("error binding UNIX domain socket: %s", strerror(errno
));
788 ev_io_init(&csio
, &luaA_cb
, csfd
, EV_READ
);
789 ev_io_start(EV_DEFAULT_UC_
&csio
);
790 ev_unref(EV_DEFAULT_UC
);
794 luaA_cs_cleanup(void)
798 ev_ref(EV_DEFAULT_UC
);
799 ev_io_stop(EV_DEFAULT_UC_
&csio
);
801 warn("error closing UNIX domain socket: %s", strerror(errno
));
802 if(unlink(addr
->sun_path
))
803 warn("error unlinking UNIX domain socket: %s", strerror(errno
));
809 luaA_on_timer(EV_P_ ev_timer
*w
, int revents
)
811 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.timer
, 0, 0);
818 luaA_pushcolor(lua_State
*L
, const xcolor_t
*c
)
820 uint8_t r
= (unsigned)c
->red
* 0xff / 0xffff;
821 uint8_t g
= (unsigned)c
->green
* 0xff / 0xffff;
822 uint8_t b
= (unsigned)c
->blue
* 0xff / 0xffff;
823 uint8_t a
= (unsigned)c
->alpha
* 0xff / 0xffff;
825 snprintf(s
, sizeof(s
), "#%02x%02x%02x%02x", r
, g
, b
, a
);
826 lua_pushlstring(L
, s
, sizeof(s
));