1 /*
2 * luah.c - Lua helper functions
3 *
4 * Copyright © 2010-2011 Mason Larobina <mason.larobina@gmail.com>
5 * Copyright © 2008-2009 Julien Danjou <julien@danjou.info>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include "ipc.h"
23 #include "luah.h"
24 #include "log.h"
25 #include "common/luah.h"
26 #include "common/luautil.h"
27 #include "common/luayield.h"
28
29 /* include clib headers */
30 #include "clib/download.h"
31 #include "clib/luakit.h"
32 #include "clib/request.h"
33 #include "clib/sqlite3.h"
34 #include "clib/soup.h"
35 #include "clib/unique.h"
36 #include "clib/widget.h"
37 #include "clib/xdg.h"
38 #include "clib/stylesheet.h"
39 #include "clib/web_module.h"
40 #include "clib/msg.h"
41 #include "common/clib/ipc.h"
42 #include "common/clib/timer.h"
43 #include "common/clib/regex.h"
44 #include "common/clib/utf8.h"
45 #include "globalconf.h"
46
47 #include <glib.h>
48 #include <gtk/gtk.h>
49 #include <stdlib.h>
50
51 void
luaH_modifier_table_push(lua_State * L,guint state)52 luaH_modifier_table_push(lua_State *L, guint state) {
53 gint i = 1;
54 lua_newtable(L);
55 if (state & GDK_MODIFIER_MASK) {
56
57 #define MODKEY(key, name) \
58 if (state & GDK_##key##_MASK) { \
59 lua_pushstring(L, name); \
60 lua_rawseti(L, -2, i++); \
61 }
62
63 MODKEY(SHIFT, "Shift");
64 MODKEY(LOCK, "Lock");
65 MODKEY(CONTROL, "Control");
66 MODKEY(MOD1, "Mod1");
67 MODKEY(MOD2, "Mod2");
68 MODKEY(MOD3, "Mod3");
69 MODKEY(MOD4, "Mod4");
70 MODKEY(MOD5, "Mod5");
71
72 #undef MODKEY
73
74 }
75 }
76
77 void
luaH_keystr_push(lua_State * L,guint keyval)78 luaH_keystr_push(lua_State *L, guint keyval)
79 {
80 gchar ucs[7];
81 guint ulen;
82 guint32 ukval = gdk_keyval_to_unicode(keyval);
83
84 /* check for printable unicode character */
85 if (g_unichar_isgraph(ukval)) {
86 ulen = g_unichar_to_utf8(ukval, ucs);
87 ucs[ulen] = 0;
88 lua_pushstring(L, ucs);
89 }
90 /* sent keysym for non-printable characters */
91 else
92 lua_pushstring(L, gdk_keyval_name(keyval));
93 }
94
95 void
luaH_init(gchar ** uris)96 luaH_init(gchar ** uris)
97 {
98 /* Lua VM init */
99 lua_State *L = common.L = luaL_newstate();
100
101 /* Set panic fuction */
102 lua_atpanic(L, luaH_panic);
103
104 luaL_openlibs(L);
105
106 luaH_fixups(L);
107
108 luaH_object_setup(L);
109
110 /* Export luakit lib */
111 luakit_lib_setup(L);
112
113 /* Export xdg lib */
114 xdg_lib_setup(L);
115
116 /* Export soup lib */
117 soup_lib_setup(L);
118
119 if (!globalconf.nounique)
120 /* Export unique lib */
121 unique_lib_setup(L);
122
123 /* Export widget */
124 widget_class_setup(L);
125
126 /* Export download */
127 download_class_setup(L);
128
129 /* Export sqlite3 */
130 sqlite3_class_setup(L);
131
132 /* Export timer */
133 timer_class_setup(L);
134
135 /* Export regex */
136 regex_class_setup(L);
137
138 /* Export utf8 */
139 utf8_lib_setup(L);
140
141 /* Export request */
142 request_class_setup(L);
143
144 /* Export stylesheet */
145 stylesheet_class_setup(L);
146
147 /* Export web module */
148 web_module_lib_setup(L);
149 ipc_channel_class_setup(L);
150
151 /* Export web module */
152 msg_lib_setup(L);
153
154 luaH_yield_setup(L);
155
156 /* add Lua search paths */
157 luaH_add_paths(L, globalconf.config_dir);
158
159 /* push a table of the startup uris */
160 const gchar *uri;
161 lua_newtable(L);
162 for (gint i = 0; uris && (uri = uris[i]); i++) {
163 lua_pushstring(L, uri);
164 lua_rawseti(L, -2, i + 1);
165 }
166 lua_setglobal(L, "uris");
167 }
168
169 static gboolean
luaH_loadrc(const gchar * confpath,gboolean run)170 luaH_loadrc(const gchar *confpath, gboolean run)
171 {
172 info("Loading rc: %s", confpath);
173
174 lua_State *L = common.L;
175
176 if (luaL_loadfile(L, confpath)) {
177 error("Error loading rc: %s", lua_tostring(L, -1));
178 return FALSE;
179 }
180
181 if (!run) {
182 lua_pop(L, 1);
183 return TRUE;
184 }
185
186 return luaH_dofunction(L, 0, 0);
187 }
188
189 /* Load a configuration file. */
190 gboolean
luaH_parserc(const gchar * confpath,gboolean run)191 luaH_parserc(const gchar *confpath, gboolean run)
192 {
193 const gchar* const *config_dirs = NULL;
194 gboolean ret = FALSE;
195 GPtrArray *paths = NULL;
196
197 /* try to load, return if it's ok */
198 if (confpath) {
199 ret = luaH_loadrc(confpath, run);
200 goto bailout;
201 }
202
203 /* compile list of config search paths */
204 paths = g_ptr_array_new_with_free_func(g_free);
205
206 #if DEVELOPMENT_PATHS
207 /* allows for testing luakit in the project directory */
208 g_ptr_array_add(paths, g_strdup("./config/rc.lua"));
209 #endif
210
211 /* search users config dir (see: XDG_CONFIG_HOME) */
212 g_ptr_array_add(paths, g_build_filename(globalconf.config_dir, "rc.lua", NULL));
213
214 /* search system config dirs (see: XDG_CONFIG_DIRS) */
215 config_dirs = g_get_system_config_dirs();
216 for(; *config_dirs; config_dirs++)
217 g_ptr_array_add(paths, g_build_filename(*config_dirs, "luakit", "rc.lua", NULL));
218
219 /* get continuation variable; bail out if invalid */
220 char *i_str = getenv("LUAKIT_NEXT_CONFIG_INDEX");
221 gint i = i_str ? atoi(i_str) : 0;
222 if (i_str && (i <= 0 || i >= (gint)paths->len))
223 goto bailout;
224
225 /* Loop through paths until we have a config that exists: avoid needless execs */
226 for (; i < (gint)paths->len; i++) {
227 const gchar *path = paths->pdata[i];
228 if (file_exists(path))
229 break;
230 verbose("rc file '%s' does not exist", path);
231 }
232
233 if (i == (gint)paths->len) {
234 warn("couldn't load any rc file");
235 goto bailout;
236 }
237
238 /* attempt to load the indicated config file */
239 const gchar *path = paths->pdata[i++];
240 if (luaH_loadrc(path, run)) {
241 unsetenv("LUAKIT_NEXT_CONFIG_INDEX");
242 globalconf.confpath = g_strdup(path);
243 ret = TRUE;
244 goto bailout;
245 } else
246 warn("loading rc '%s' failed, falling back...", path);
247
248 /* set continuation variable for replacement process */
249 i_str = g_strdup_printf("%i", i);
250 setenv("LUAKIT_NEXT_CONFIG_INDEX", i_str, TRUE);
251 g_free(i_str);
252
253 /* exec path: escape spaces (why?) */
254 gchar **parts = g_strsplit(globalconf.execpath, " ", -1);
255 gchar *escaped_execpath = g_strjoinv("\\ ", parts);
256 g_strfreev(parts);
257
258 /* rebuild argv */
259 GPtrArray *argv = globalconf.argv;
260 g_ptr_array_insert(argv, 0, escaped_execpath);
261 g_ptr_array_add(argv, NULL);
262
263 verbose("exec: %s", g_strjoinv(" ", (gchar**)argv->pdata));
264
265 char *log_dump_file = log_dump_queued_emissions();
266 if (log_dump_file) {
267 setenv("LUAKIT_QUEUED_EMISSIONS_FILE", log_dump_file, TRUE);
268 g_free(log_dump_file);
269 }
270 ipc_remove_socket_file();
271 execvp(escaped_execpath, (gchar**)argv->pdata);
272
273 bailout:
274
275 if (paths) g_ptr_array_free(paths, TRUE);
276 return ret;
277 }
278
279 // vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
280