Mirror of Awesome WM window manager
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

luaa.c 31KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215
  1. /*
  2. * luaa.c - Lua configuration management
  3. *
  4. * Copyright © 2008-2009 Julien Danjou <julien@danjou.info>
  5. *
  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.
  10. *
  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.
  15. *
  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.
  19. *
  20. */
  21. /** AwesomeWM lifecycle API.
  22. *
  23. * This module contains the functions and signal to manage the lifecycle of the
  24. * AwesomeWM process. It allows to execute code at specific point from the early
  25. * initialization all the way to the last events before exiting or restarting.
  26. *
  27. * Additionally it handles signals for spawn and keyboard related events.
  28. *
  29. * @author Julien Danjou &lt;julien@danjou.info&gt;
  30. * @copyright 2008-2009 Julien Danjou
  31. * @coreclassmod awesome
  32. */
  33. /** Register a new xproperty.
  34. *
  35. * @tparam string name The name of the X11 property.
  36. * @tparam string type One of "string", "number" or "boolean".
  37. * @staticfct register_xproperty
  38. */
  39. #define _GNU_SOURCE
  40. #include "luaa.h"
  41. #include "globalconf.h"
  42. #include "awesome.h"
  43. #include "common/backtrace.h"
  44. #include "common/version.h"
  45. #include "config.h"
  46. #include "event.h"
  47. #include "objects/client.h"
  48. #include "objects/drawable.h"
  49. #include "objects/drawin.h"
  50. #include "objects/selection_getter.h"
  51. #include "objects/screen.h"
  52. #include "objects/selection_acquire.h"
  53. #include "objects/selection_transfer.h"
  54. #include "objects/selection_watcher.h"
  55. #include "objects/tag.h"
  56. #include "property.h"
  57. #include "selection.h"
  58. #include "spawn.h"
  59. #include "systray.h"
  60. #include "xkb.h"
  61. #include "xrdb.h"
  62. #include <lua.h>
  63. #include <lauxlib.h>
  64. #include <lualib.h>
  65. #include <basedir_fs.h>
  66. #include <xcb/xcb_atom.h>
  67. #include <xcb/xcb_aux.h>
  68. #include <unistd.h> /* for gethostname() */
  69. #ifdef WITH_DBUS
  70. extern const struct luaL_Reg awesome_dbus_lib[];
  71. #endif
  72. extern const struct luaL_Reg awesome_keygrabber_lib[];
  73. extern const struct luaL_Reg awesome_mousegrabber_lib[];
  74. extern const struct luaL_Reg awesome_mouse_methods[];
  75. extern const struct luaL_Reg awesome_mouse_meta[];
  76. extern const struct luaL_Reg awesome_root_methods[];
  77. extern const struct luaL_Reg awesome_root_meta[];
  78. /** A call into the Lua code aborted with an error.
  79. *
  80. * This signal is used in the example configuration, @{05-awesomerc.md},
  81. * to let a notification box pop up.
  82. * @param err Table with the error object, can be converted to a string with
  83. * `tostring(err)`.
  84. * @signal debug::error
  85. */
  86. /** A deprecated Lua function was called.
  87. *
  88. * @tparam string hint String with a hint on what to use instead of the
  89. * deprecated functionality.
  90. * @tparam[opt=nil] string|nil see The name of the newer API
  91. * @tparam[opt=nil] table|nil args The name of the newer API
  92. * @signal debug::deprecation
  93. */
  94. /** An invalid key was read from an object.
  95. *
  96. * This can happen if `foo` in an `c.foo` access does not exist.
  97. * @param unknown1 Class?
  98. * @param unknown2 Key?
  99. * @signal debug::index::miss
  100. */
  101. /** An invalid key was written to an object.
  102. *
  103. * This can happen if `foo` in an `c.foo = "bar"` assignment doesn't exist.
  104. * @param unknown1 Class?
  105. * @param unknown2 Key?
  106. * @param unknown3 Value?
  107. * @signal debug::newindex::miss
  108. */
  109. /** The systray should be updated.
  110. *
  111. * This signal is used in `wibox.widget.systray`.
  112. * @signal systray::update
  113. */
  114. /** The wallpaper has changed.
  115. *
  116. * This signal is used for pseudo-transparency in `wibox.drawable` if no
  117. * composite manager is running.
  118. * @signal wallpaper_changed
  119. */
  120. /** Keyboard map has changed.
  121. *
  122. * This signal is sent after the new keymap has been loaded. It is used in
  123. * `awful.widget.keyboardlayout` to redraw the layout.
  124. * @signal xkb::map_changed
  125. */
  126. /** Keyboard group has changed.
  127. *
  128. * It's used in `awful.widget.keyboardlayout` to redraw the layout.
  129. * @param group Integer containing the changed group
  130. * @signal xkb::group_changed.
  131. */
  132. /** Refresh.
  133. *
  134. * This signal is emitted as a kind of idle signal in the event loop.
  135. * One example usage is in `gears.timer` to executed delayed calls.
  136. * @signal refresh
  137. */
  138. /** AwesomeWM is about to enter the event loop.
  139. *
  140. * This means all initialization has been done.
  141. * @signal startup
  142. */
  143. /** AwesomeWM is exiting / about to restart.
  144. *
  145. * This signal is emitted in the `atexit` handler as well when awesome
  146. * restarts.
  147. * @param reason_restart Boolean value is true if the signal was sent
  148. * because of a restart.
  149. * @signal exit
  150. */
  151. /** The output status of a screen has changed.
  152. *
  153. * @tparam string output String containing which output has changed.
  154. * @tparam string connection_state String containing the connection status of
  155. * the output: It will be either "Connected", "Disconnected" or
  156. * "Unknown".
  157. * @signal screen::change
  158. */
  159. /** Path to config file */
  160. static char *conffile;
  161. /** Check whether a composite manager is running.
  162. * \return True if such a manager is running.
  163. */
  164. static bool
  165. composite_manager_running(void)
  166. {
  167. xcb_intern_atom_reply_t *atom_r;
  168. xcb_get_selection_owner_reply_t *selection_r;
  169. char *atom_name;
  170. bool result;
  171. if(!(atom_name = xcb_atom_name_by_screen("_NET_WM_CM", globalconf.default_screen)))
  172. {
  173. warn("error getting composite manager atom");
  174. return false;
  175. }
  176. atom_r = xcb_intern_atom_reply(globalconf.connection,
  177. xcb_intern_atom_unchecked(globalconf.connection, false,
  178. a_strlen(atom_name), atom_name),
  179. NULL);
  180. p_delete(&atom_name);
  181. if(!atom_r)
  182. return false;
  183. selection_r = xcb_get_selection_owner_reply(globalconf.connection,
  184. xcb_get_selection_owner_unchecked(globalconf.connection,
  185. atom_r->atom),
  186. NULL);
  187. p_delete(&atom_r);
  188. result = selection_r != NULL && selection_r->owner != XCB_NONE;
  189. p_delete(&selection_r);
  190. return result;
  191. }
  192. /** Quit awesome.
  193. * @tparam[opt=0] integer code The exit code to use when exiting.
  194. * @staticfct quit
  195. */
  196. static int
  197. luaA_quit(lua_State *L)
  198. {
  199. if (!lua_isnoneornil(L, 1))
  200. globalconf.exit_code = luaL_checkinteger(L, 1);
  201. if (globalconf.loop == NULL)
  202. globalconf.loop = g_main_loop_new(NULL, FALSE);
  203. g_main_loop_quit(globalconf.loop);
  204. return 0;
  205. }
  206. /** Execute another application, probably a window manager, to replace
  207. * awesome.
  208. *
  209. * @param cmd The command line to execute.
  210. * @staticfct exec
  211. */
  212. static int
  213. luaA_exec(lua_State *L)
  214. {
  215. const char *cmd = luaL_checkstring(L, 1);
  216. awesome_atexit(false);
  217. a_exec(cmd);
  218. return 0;
  219. }
  220. /** Restart awesome.
  221. * @staticfct restart
  222. */
  223. static int
  224. luaA_restart(lua_State *L)
  225. {
  226. awesome_restart();
  227. return 0;
  228. }
  229. /** Send a signal to a process.
  230. * @tparam integer pid Process identifier. 0 and negative values have special
  231. * meaning. See `man 3 kill`.
  232. * @tparam integer sig Signal number.
  233. * See `awesome.unix_signal` for a list of signals.
  234. * @treturn boolean true if the signal was successfully sent, else false
  235. * @staticfct kill
  236. */
  237. static int
  238. luaA_kill(lua_State *L)
  239. {
  240. int pid = luaL_checknumber(L, 1);
  241. int sig = luaA_checknumber_range(L, 2, 0, INT_MAX);
  242. int result = kill(pid, sig);
  243. lua_pushboolean(L, result == 0);
  244. return 1;
  245. }
  246. /** Synchronize with the X11 server. This is needed in the test suite to avoid
  247. * some race conditions. You should never need to use this function.
  248. * @staticfct sync
  249. */
  250. static int
  251. luaA_sync(lua_State *L)
  252. {
  253. xcb_aux_sync(globalconf.connection);
  254. return 0;
  255. }
  256. /** Translate a GdkPixbuf to a cairo image surface..
  257. *
  258. * @param pixbuf The pixbuf as a light user datum.
  259. * @param path The pixbuf origin path
  260. * @return A cairo surface as light user datum.
  261. * @staticfct pixbuf_to_surface
  262. */
  263. static int
  264. luaA_pixbuf_to_surface(lua_State *L)
  265. {
  266. GdkPixbuf *pixbuf = (GdkPixbuf *) lua_touserdata(L, 1);
  267. cairo_surface_t *surface = draw_surface_from_pixbuf(pixbuf);
  268. /* lua has to make sure to free the ref or we have a leak */
  269. lua_pushlightuserdata(L, surface);
  270. return 1;
  271. }
  272. /** Load an image from a given path.
  273. *
  274. * @param name The file name.
  275. * @return[1] A cairo surface as light user datum.
  276. * @return[2] nil
  277. * @treturn[2] string Error message
  278. * @staticfct load_image
  279. */
  280. static int
  281. luaA_load_image(lua_State *L)
  282. {
  283. /* TODO: Deprecate this function, Lua can use GdkPixbuf directly plus
  284. * awesome.pixbuf_to_surface
  285. */
  286. GError *error = NULL;
  287. const char *filename = luaL_checkstring(L, 1);
  288. cairo_surface_t *surface = draw_load_image(L, filename, &error);
  289. if (!surface) {
  290. lua_pushnil(L);
  291. lua_pushstring(L, error->message);
  292. g_error_free(error);
  293. return 2;
  294. }
  295. /* lua has to make sure to free the ref or we have a leak */
  296. lua_pushlightuserdata(L, surface);
  297. return 1;
  298. }
  299. /** Set the preferred size for client icons.
  300. *
  301. * The closest equal or bigger size is picked if present, otherwise the closest
  302. * smaller size is picked. The default is 0 pixels, ie. the smallest icon.
  303. *
  304. * @param size The size of the icons in pixels.
  305. * @staticfct set_preferred_icon_size
  306. */
  307. static int
  308. luaA_set_preferred_icon_size(lua_State *L)
  309. {
  310. globalconf.preferred_icon_size = luaA_checkinteger_range(L, 1, 0, UINT32_MAX);
  311. return 0;
  312. }
  313. /** UTF-8 aware string length computing.
  314. * \param L The Lua VM state.
  315. * \return The number of elements pushed on stack.
  316. */
  317. static int
  318. luaA_mbstrlen(lua_State *L)
  319. {
  320. const char *cmd = luaL_checkstring(L, 1);
  321. lua_pushinteger(L, (ssize_t) mbstowcs(NULL, NONULL(cmd), 0));
  322. return 1;
  323. }
  324. /** Enhanced type() function which recognize awesome objects.
  325. * \param L The Lua VM state.
  326. * \return The number of arguments pushed on the stack.
  327. */
  328. static int
  329. luaAe_type(lua_State *L)
  330. {
  331. luaL_checkany(L, 1);
  332. lua_pushstring(L, luaA_typename(L, 1));
  333. return 1;
  334. }
  335. /** Replace various standards Lua functions with our own.
  336. * \param L The Lua VM state.
  337. */
  338. static void
  339. luaA_fixups(lua_State *L)
  340. {
  341. /* export string.wlen */
  342. lua_getglobal(L, "string");
  343. lua_pushcfunction(L, luaA_mbstrlen);
  344. lua_setfield(L, -2, "wlen");
  345. lua_pop(L, 1);
  346. /* replace type */
  347. lua_pushcfunction(L, luaAe_type);
  348. lua_setglobal(L, "type");
  349. }
  350. static const char *
  351. get_modifier_name(int map_index)
  352. {
  353. switch (map_index) {
  354. case XCB_MAP_INDEX_SHIFT: return "Shift";
  355. case XCB_MAP_INDEX_LOCK: return "Lock";
  356. case XCB_MAP_INDEX_CONTROL: return "Control";
  357. case XCB_MAP_INDEX_1: return "Mod1"; /* Alt */
  358. case XCB_MAP_INDEX_2: return "Mod2";
  359. case XCB_MAP_INDEX_3: return "Mod3";
  360. case XCB_MAP_INDEX_4: return "Mod4";
  361. case XCB_MAP_INDEX_5: return "Mod5";
  362. }
  363. return 0; /* \0 */
  364. }
  365. /* Undocumented */
  366. /*
  367. * The table of keybindings modifiers.
  368. *
  369. * Each modifier has zero to many entries depending on the keyboard layout.
  370. * For example, `Shift` usually both has a left and right variant. Each
  371. * modifier entry has a `keysym` and `keycode` entry. For the US PC 105
  372. * keyboard, it looks like:
  373. *
  374. * awesome.modifiers = {
  375. * Shift = {
  376. * {keycode = 50 , keysym = 'Shift_L' },
  377. * {keycode = 62 , keysym = 'Shift_R' },
  378. * },
  379. * Lock = {},
  380. * Control = {
  381. * {keycode = 37 , keysym = 'Control_L' },
  382. * {keycode = 105, keysym = 'Control_R' },
  383. * },
  384. * Mod1 = {
  385. * {keycode = 64 , keysym = 'Alt_L' },
  386. * {keycode = 108, keysym = 'Alt_R' },
  387. * },
  388. * Mod2 = {
  389. * {keycode = 77 , keysym = 'Num_Lock' },
  390. * },
  391. * Mod3 = {},
  392. * Mod4 = {
  393. * {keycode = 133, keysym = 'Super_L' },
  394. * {keycode = 134, keysym = 'Super_R' },
  395. * },
  396. * Mod5 = {
  397. * {keycode = 203, keysym = 'Mode_switch'},
  398. * },
  399. * };
  400. *
  401. * @tfield table modifiers
  402. * @tparam table modifiers.Shift The Shift modifiers.
  403. * @tparam table modifiers.Lock The Lock modifiers.
  404. * @tparam table modifiers.Control The Control modifiers.
  405. * @tparam table modifiers.Mod1 The Mod1 (Alt) modifiers.
  406. * @tparam table modifiers.Mod2 The Mod2 modifiers.
  407. * @tparam table modifiers.Mod3 The Mod3 modifiers.
  408. * @tparam table modifiers.Mod4 The Mod4 modifiers.
  409. * @tparam table modifiers.Mod5 The Mod5 modifiers.
  410. */
  411. /*
  412. * Modifiers can change over time, given they are currently not tracked, just
  413. * query them each time. Use with moderation.
  414. */
  415. static int luaA_get_modifiers(lua_State *L)
  416. {
  417. xcb_get_modifier_mapping_reply_t *mods = xcb_get_modifier_mapping_reply(globalconf.connection,
  418. xcb_get_modifier_mapping(globalconf.connection), NULL);
  419. if (!mods)
  420. return 0;
  421. xcb_keycode_t *mappings = xcb_get_modifier_mapping_keycodes(mods);
  422. struct xkb_keymap *keymap = xkb_state_get_keymap(globalconf.xkb_state);
  423. lua_newtable(L);
  424. /* This get the MAPPED modifiers, not all of them are */
  425. for (int i = XCB_MAP_INDEX_SHIFT; i <= XCB_MAP_INDEX_5; i++) {
  426. lua_pushstring(L, get_modifier_name(i));
  427. lua_newtable(L);
  428. for (int j = 0; j < mods->keycodes_per_modifier; j++) {
  429. const xkb_keysym_t *keysyms;
  430. const xcb_keycode_t key_code = mappings[i * mods->keycodes_per_modifier + j];
  431. xkb_keymap_key_get_syms_by_level(keymap, key_code, 0, 0, &keysyms);
  432. if (keysyms != NULL) {
  433. /* The +1 because j starts at zero and Lua at 1 */
  434. lua_pushinteger(L, j+1);
  435. lua_newtable(L);
  436. lua_pushstring(L, "keycode");
  437. lua_pushinteger(L, key_code);
  438. lua_settable(L, -3);
  439. /* Technically it is possible to get multiple keysyms here,
  440. * but... we just use the first one.
  441. */
  442. lua_pushstring(L, "keysym");
  443. char *string = key_get_keysym_name(keysyms[0]);
  444. lua_pushstring(L, string);
  445. p_delete(&string);
  446. lua_settable(L, -3);
  447. lua_settable(L, -3);
  448. }
  449. }
  450. lua_settable(L, -3);
  451. }
  452. free(mods);
  453. return 0;
  454. }
  455. /* Undocumented */
  456. /*
  457. * A table with the currently active modifier names.
  458. *
  459. * @tfield table _active_modifiers
  460. */
  461. static int luaA_get_active_modifiers(lua_State *L)
  462. {
  463. int count = 1;
  464. lua_newtable(L);
  465. for (int i = XCB_MAP_INDEX_SHIFT; i <= XCB_MAP_INDEX_5; i++) {
  466. const int active = xkb_state_mod_index_is_active (globalconf.xkb_state, i,
  467. XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_EFFECTIVE
  468. );
  469. if (active) {
  470. lua_pushstring(L, get_modifier_name(i));
  471. lua_rawseti(L,-2, count++);
  472. }
  473. }
  474. return 0;
  475. }
  476. /**
  477. * The version of awesome.
  478. * @tfield string version
  479. */
  480. /**
  481. * The release name of awesome.
  482. * @tfield string release
  483. */
  484. /**
  485. * The configuration file which has been loaded.
  486. * @tfield string conffile
  487. */
  488. /**
  489. * True if we are still in startup, false otherwise.
  490. * @tfield boolean startup
  491. */
  492. /**
  493. * Error message for errors that occured during
  494. * startup.
  495. * @tfield string startup_errors
  496. */
  497. /**
  498. * True if a composite manager is running.
  499. * @tfield boolean composite_manager_running
  500. */
  501. /**
  502. * Table mapping between signal numbers and signal identifiers.
  503. * @tfield table unix_signal
  504. */
  505. /**
  506. * The hostname of the computer on which we are running.
  507. * @tfield string hostname
  508. */
  509. /**
  510. * The path where themes were installed to.
  511. * @tfield string themes_path
  512. */
  513. /**
  514. * The path where icons were installed to.
  515. * @tfield string icon_path
  516. */
  517. static int
  518. luaA_awesome_index(lua_State *L)
  519. {
  520. if(luaA_usemetatable(L, 1, 2))
  521. return 1;
  522. const char *buf = luaL_checkstring(L, 2);
  523. if(A_STREQ(buf, "conffile"))
  524. {
  525. lua_pushstring(L, conffile);
  526. return 1;
  527. }
  528. if(A_STREQ(buf, "version"))
  529. {
  530. lua_pushstring(L, awesome_version_string());
  531. return 1;
  532. }
  533. if(A_STREQ(buf, "release"))
  534. {
  535. lua_pushstring(L, awesome_release_string());
  536. return 1;
  537. }
  538. if(A_STREQ(buf, "startup"))
  539. {
  540. lua_pushboolean(L, globalconf.loop == NULL);
  541. return 1;
  542. }
  543. if(A_STREQ(buf, "_modifiers"))
  544. {
  545. luaA_get_modifiers(L);
  546. return 1;
  547. }
  548. if(A_STREQ(buf, "_active_modifiers"))
  549. {
  550. luaA_get_active_modifiers(L);
  551. return 1;
  552. }
  553. if(A_STREQ(buf, "startup_errors"))
  554. {
  555. if (globalconf.startup_errors.len == 0)
  556. return 0;
  557. lua_pushstring(L, globalconf.startup_errors.s);
  558. return 1;
  559. }
  560. if(A_STREQ(buf, "composite_manager_running"))
  561. {
  562. lua_pushboolean(L, composite_manager_running());
  563. return 1;
  564. }
  565. if(A_STREQ(buf, "hostname"))
  566. {
  567. /* No good way to handle failures... */
  568. char hostname[256] = "";
  569. gethostname(&hostname[0], countof(hostname));
  570. hostname[countof(hostname) - 1] = '\0';
  571. lua_pushstring(L, hostname);
  572. return 1;
  573. }
  574. if(A_STREQ(buf, "themes_path"))
  575. {
  576. lua_pushliteral(L, AWESOME_THEMES_PATH);
  577. return 1;
  578. }
  579. if(A_STREQ(buf, "icon_path"))
  580. {
  581. lua_pushliteral(L, AWESOME_ICON_PATH);
  582. return 1;
  583. }
  584. return luaA_default_index(L);
  585. }
  586. /** Add a global signal.
  587. *
  588. * @param name A string with the event name.
  589. * @param func The function to call.
  590. * @staticfct connect_signal
  591. */
  592. static int
  593. luaA_awesome_connect_signal(lua_State *L)
  594. {
  595. const char *name = luaL_checkstring(L, 1);
  596. luaA_checkfunction(L, 2);
  597. signal_connect(&global_signals, name, luaA_object_ref(L, 2));
  598. return 0;
  599. }
  600. /** Remove a global signal.
  601. *
  602. * @param name A string with the event name.
  603. * @param func The function to call.
  604. * @staticfct disconnect_signal
  605. */
  606. static int
  607. luaA_awesome_disconnect_signal(lua_State *L)
  608. {
  609. const char *name = luaL_checkstring(L, 1);
  610. luaA_checkfunction(L, 2);
  611. const void *func = lua_topointer(L, 2);
  612. if (signal_disconnect(&global_signals, name, func))
  613. luaA_object_unref(L, (void *) func);
  614. return 0;
  615. }
  616. /** Emit a global signal.
  617. *
  618. * @param name A string with the event name.
  619. * @param ... The signal arguments.
  620. * @staticfct emit_signal
  621. */
  622. static int
  623. luaA_awesome_emit_signal(lua_State *L)
  624. {
  625. signal_object_emit(L, &global_signals, luaL_checkstring(L, 1), lua_gettop(L) - 1);
  626. return 0;
  627. }
  628. static int
  629. luaA_panic(lua_State *L)
  630. {
  631. warn("unprotected error in call to Lua API (%s)",
  632. lua_tostring(L, -1));
  633. buffer_t buf;
  634. backtrace_get(&buf);
  635. warn("dumping backtrace\n%s", buf.s);
  636. warn("restarting awesome");
  637. awesome_restart();
  638. return 0;
  639. }
  640. #if LUA_VERSION_NUM >= 502
  641. static const char *
  642. luaA_tolstring(lua_State *L, int idx, size_t *len)
  643. {
  644. return luaL_tolstring(L, idx, len);
  645. }
  646. #else
  647. static const char *
  648. luaA_tolstring(lua_State *L, int idx, size_t *len)
  649. {
  650. /* Try using the metatable. If that fails, push the value itself onto
  651. * the stack.
  652. */
  653. if (!luaL_callmeta(L, idx, "__tostring"))
  654. lua_pushvalue(L, idx);
  655. switch (lua_type(L, -1)) {
  656. case LUA_TSTRING:
  657. lua_pushvalue(L, -1);
  658. break;
  659. case LUA_TBOOLEAN:
  660. if (lua_toboolean(L, -1))
  661. lua_pushliteral(L, "true");
  662. else
  663. lua_pushliteral(L, "false");
  664. break;
  665. case LUA_TNUMBER:
  666. lua_pushfstring(L, "%f", lua_tonumber(L, -1));
  667. break;
  668. case LUA_TNIL:
  669. lua_pushstring(L, "nil");
  670. break;
  671. default:
  672. lua_pushfstring(L, "%s: %p",
  673. lua_typename(L, lua_type(L, -1)),
  674. lua_topointer(L, -1));
  675. break;
  676. }
  677. lua_remove(L, -2);
  678. return lua_tolstring(L, -1, len);
  679. }
  680. #endif
  681. static int
  682. luaA_dofunction_on_error(lua_State *L)
  683. {
  684. /* Convert error to string, to prevent a follow-up error with lua_concat. */
  685. luaA_tolstring(L, -1, NULL);
  686. /* duplicate string error */
  687. lua_pushvalue(L, -1);
  688. /* emit error signal */
  689. signal_object_emit(L, &global_signals, "debug::error", 1);
  690. if(!luaL_dostring(L, "return debug.traceback(\"error while running function!\", 3)"))
  691. {
  692. /* Move traceback before error */
  693. lua_insert(L, -2);
  694. /* Insert sentence */
  695. lua_pushliteral(L, "\nerror: ");
  696. /* Move it before error */
  697. lua_insert(L, -2);
  698. lua_concat(L, 3);
  699. }
  700. return 1;
  701. }
  702. static void
  703. setup_awesome_signals(lua_State *L)
  704. {
  705. lua_getglobal(L, "awesome");
  706. lua_pushstring(L, "unix_signal");
  707. lua_newtable(L);
  708. #define SETUP_SIGNAL(sig) \
  709. do { \
  710. /* Set awesome.unix_signal["SIGSTOP"] = 42 */ \
  711. lua_pushinteger(L, sig); \
  712. lua_setfield(L, -2, #sig); \
  713. /* Set awesome.unix_signal[42] = "SIGSTOP" */ \
  714. lua_pushinteger(L, sig); \
  715. lua_pushstring(L, #sig); \
  716. lua_settable(L, -3); \
  717. } while (0)
  718. /* Non-standard signals. These are first so that e.g. (on my system)
  719. * signals[29] is SIGPOLL and not SIGIO (the value gets overwritten).
  720. */
  721. #ifdef SIGIOT
  722. SETUP_SIGNAL(SIGIOT);
  723. #endif
  724. #ifdef SIGEMT
  725. SETUP_SIGNAL(SIGEMT);
  726. #endif
  727. #ifdef SIGSTKFLT
  728. SETUP_SIGNAL(SIGSTKFLT);
  729. #endif
  730. #ifdef SIGIO
  731. SETUP_SIGNAL(SIGIO);
  732. #endif
  733. #ifdef SIGCLD
  734. SETUP_SIGNAL(SIGCLD);
  735. #endif
  736. #ifdef SIGPWR
  737. SETUP_SIGNAL(SIGPWR);
  738. #endif
  739. #ifdef SIGINFO
  740. SETUP_SIGNAL(SIGINFO);
  741. #endif
  742. #ifdef SIGLOST
  743. SETUP_SIGNAL(SIGLOST);
  744. #endif
  745. #ifdef SIGWINCH
  746. SETUP_SIGNAL(SIGWINCH);
  747. #endif
  748. #ifdef SIGUNUSED
  749. SETUP_SIGNAL(SIGUNUSED);
  750. #endif
  751. /* POSIX.1-1990, according to man 7 signal */
  752. SETUP_SIGNAL(SIGHUP);
  753. SETUP_SIGNAL(SIGINT);
  754. SETUP_SIGNAL(SIGQUIT);
  755. SETUP_SIGNAL(SIGILL);
  756. SETUP_SIGNAL(SIGABRT);
  757. SETUP_SIGNAL(SIGFPE);
  758. SETUP_SIGNAL(SIGKILL);
  759. SETUP_SIGNAL(SIGSEGV);
  760. SETUP_SIGNAL(SIGPIPE);
  761. SETUP_SIGNAL(SIGALRM);
  762. SETUP_SIGNAL(SIGTERM);
  763. SETUP_SIGNAL(SIGUSR1);
  764. SETUP_SIGNAL(SIGUSR2);
  765. SETUP_SIGNAL(SIGCHLD);
  766. SETUP_SIGNAL(SIGCONT);
  767. SETUP_SIGNAL(SIGSTOP);
  768. SETUP_SIGNAL(SIGTSTP);
  769. SETUP_SIGNAL(SIGTTIN);
  770. SETUP_SIGNAL(SIGTTOU);
  771. /* POSIX.1-2001, according to man 7 signal */
  772. SETUP_SIGNAL(SIGBUS);
  773. /* Some Operating Systems doesn't have SIGPOLL (e.g. FreeBSD) */
  774. #ifdef SIGPOLL
  775. SETUP_SIGNAL(SIGPOLL);
  776. #endif
  777. SETUP_SIGNAL(SIGPROF);
  778. SETUP_SIGNAL(SIGSYS);
  779. SETUP_SIGNAL(SIGTRAP);
  780. SETUP_SIGNAL(SIGURG);
  781. SETUP_SIGNAL(SIGVTALRM);
  782. SETUP_SIGNAL(SIGXCPU);
  783. SETUP_SIGNAL(SIGXFSZ);
  784. #undef SETUP_SIGNAL
  785. /* Set awesome.signal to the table we just created, key was already pushed */
  786. lua_rawset(L, -3);
  787. /* Pop "awesome" */
  788. lua_pop(L, 1);
  789. }
  790. /* Add things to the string on top of the stack */
  791. static void
  792. add_to_search_path(lua_State *L, string_array_t *searchpath, bool for_lua)
  793. {
  794. if (LUA_TSTRING != lua_type(L, -1))
  795. {
  796. warn("package.path is not a string");
  797. return;
  798. }
  799. foreach(entry, *searchpath)
  800. {
  801. int components;
  802. size_t len = a_strlen(*entry);
  803. lua_pushliteral(L, ";");
  804. lua_pushlstring(L, *entry, len);
  805. if (for_lua)
  806. lua_pushliteral(L, "/?.lua");
  807. else
  808. lua_pushliteral(L, "/?.so");
  809. lua_concat(L, 3);
  810. if (for_lua)
  811. {
  812. lua_pushliteral(L, ";");
  813. lua_pushlstring(L, *entry, len);
  814. lua_pushliteral(L, "/?/init.lua");
  815. lua_concat(L, 3);
  816. components = 2;
  817. } else {
  818. components = 1;
  819. }
  820. lua_concat(L, components + 1); /* concatenate with string on top of the stack */
  821. }
  822. /* add Lua lib path (/usr/share/awesome/lib by default) */
  823. if (for_lua)
  824. {
  825. lua_pushliteral(L, ";" AWESOME_LUA_LIB_PATH "/?.lua");
  826. lua_pushliteral(L, ";" AWESOME_LUA_LIB_PATH "/?/init.lua");
  827. lua_concat(L, 3); /* concatenate with thing on top of the stack when we were called */
  828. } else {
  829. lua_pushliteral(L, ";" AWESOME_LUA_LIB_PATH "/?.so");
  830. lua_concat(L, 2); /* concatenate with thing on top of the stack when we were called */
  831. }
  832. }
  833. /** Initialize the Lua VM
  834. * \param xdg An xdg handle to use to get XDG basedir.
  835. */
  836. void
  837. luaA_init(xdgHandle* xdg, string_array_t *searchpath)
  838. {
  839. lua_State *L;
  840. static const struct luaL_Reg awesome_lib[] =
  841. {
  842. { "quit", luaA_quit },
  843. { "exec", luaA_exec },
  844. { "spawn", luaA_spawn },
  845. { "restart", luaA_restart },
  846. { "connect_signal", luaA_awesome_connect_signal },
  847. { "disconnect_signal", luaA_awesome_disconnect_signal },
  848. { "emit_signal", luaA_awesome_emit_signal },
  849. { "systray", luaA_systray },
  850. { "load_image", luaA_load_image },
  851. { "pixbuf_to_surface", luaA_pixbuf_to_surface },
  852. { "set_preferred_icon_size", luaA_set_preferred_icon_size },
  853. { "register_xproperty", luaA_register_xproperty },
  854. { "set_xproperty", luaA_set_xproperty },
  855. { "get_xproperty", luaA_get_xproperty },
  856. { "__index", luaA_awesome_index },
  857. { "__newindex", luaA_default_newindex },
  858. { "xkb_set_layout_group", luaA_xkb_set_layout_group},
  859. { "xkb_get_layout_group", luaA_xkb_get_layout_group},
  860. { "xkb_get_group_names", luaA_xkb_get_group_names},
  861. { "xrdb_get_value", luaA_xrdb_get_value},
  862. { "kill", luaA_kill},
  863. { "sync", luaA_sync},
  864. { NULL, NULL }
  865. };
  866. L = globalconf.L.real_L_dont_use_directly = luaL_newstate();
  867. /* Set panic function */
  868. lua_atpanic(L, luaA_panic);
  869. /* Set error handling function */
  870. lualib_dofunction_on_error = luaA_dofunction_on_error;
  871. luaL_openlibs(L);
  872. luaA_fixups(L);
  873. luaA_object_setup(L);
  874. /* Export awesome lib */
  875. luaA_openlib(L, "awesome", awesome_lib, awesome_lib);
  876. setup_awesome_signals(L);
  877. /* Export root lib */
  878. luaA_openlib(L, "root", awesome_root_methods, awesome_root_meta);
  879. #ifdef WITH_DBUS
  880. /* Export D-Bus lib */
  881. luaA_registerlib(L, "dbus", awesome_dbus_lib);
  882. lua_pop(L, 1); /* luaA_registerlib() leaves the table on stack */
  883. #endif
  884. /* Export keygrabber lib */
  885. luaA_registerlib(L, "keygrabber", awesome_keygrabber_lib);
  886. lua_pop(L, 1); /* luaA_registerlib() leaves the table on stack */
  887. /* Export mousegrabber lib */
  888. luaA_registerlib(L, "mousegrabber", awesome_mousegrabber_lib);
  889. lua_pop(L, 1); /* luaA_registerlib() leaves the table on stack */
  890. /* Export mouse */
  891. luaA_openlib(L, "mouse", awesome_mouse_methods, awesome_mouse_meta);
  892. /* Export screen */
  893. screen_class_setup(L);
  894. /* Export button */
  895. button_class_setup(L);
  896. /* Export tag */
  897. tag_class_setup(L);
  898. /* Export window */
  899. window_class_setup(L);
  900. /* Export drawable */
  901. drawable_class_setup(L);
  902. /* Export drawin */
  903. drawin_class_setup(L);
  904. /* Export client */
  905. client_class_setup(L);
  906. /* Export selection getter */
  907. selection_getter_class_setup(L);
  908. /* Export keys */
  909. key_class_setup(L);
  910. /* Export selection acquire */
  911. selection_acquire_class_setup(L);
  912. /* Export selection transfer */
  913. selection_transfer_class_setup(L);
  914. /* Export selection watcher */
  915. selection_watcher_class_setup(L);
  916. /* Setup the selection interface */
  917. selection_setup(L);
  918. /* add Lua search paths */
  919. lua_getglobal(L, "package");
  920. if (LUA_TTABLE != lua_type(L, 1))
  921. {
  922. warn("package is not a table");
  923. return;
  924. }
  925. lua_getfield(L, 1, "path");
  926. add_to_search_path(L, searchpath, true);
  927. lua_setfield(L, 1, "path"); /* package.path = "concatenated string" */
  928. lua_getfield(L, 1, "cpath");
  929. add_to_search_path(L, searchpath, false);
  930. lua_setfield(L, 1, "cpath"); /* package.cpath = "concatenated string" */
  931. lua_pop(L, 1); /* pop "package" */
  932. }
  933. static void
  934. luaA_startup_error(const char *err)
  935. {
  936. if (globalconf.startup_errors.len > 0)
  937. buffer_addsl(&globalconf.startup_errors, "\n\n");
  938. buffer_adds(&globalconf.startup_errors, err);
  939. }
  940. static bool
  941. luaA_loadrc(const char *confpath)
  942. {
  943. lua_State *L = globalconf_get_lua_State();
  944. if(luaL_loadfile(L, confpath))
  945. {
  946. const char *err = lua_tostring(L, -1);
  947. luaA_startup_error(err);
  948. fprintf(stderr, "%s\n", err);
  949. lua_pop(L, 1);
  950. return false;
  951. }
  952. /* Set the conffile right now so it can be used inside the
  953. * configuration file. */
  954. conffile = a_strdup(confpath);
  955. /* Move error handling function before function */
  956. lua_pushcfunction(L, luaA_dofunction_on_error);
  957. lua_insert(L, -2);
  958. if(!lua_pcall(L, 0, 0, -2))
  959. {
  960. /* Pop luaA_dofunction_on_error */
  961. lua_pop(L, 1);
  962. return true;
  963. }
  964. const char *err = lua_tostring(L, -1);
  965. luaA_startup_error(err);
  966. fprintf(stderr, "%s\n", err);
  967. /* An error happened, so reset this. */
  968. conffile = NULL;
  969. /* Pop luaA_dofunction_on_error() and the error message */
  970. lua_pop(L, 2);
  971. return false;
  972. }
  973. /** Load a configuration file.
  974. * \param xdg An xdg handle to use to get XDG basedir.
  975. * \param confpatharg The configuration file to load.
  976. * \param run Run the configuration file.
  977. */
  978. bool
  979. luaA_parserc(xdgHandle* xdg, const char *confpatharg)
  980. {
  981. const char *confpath = luaA_find_config(xdg, confpatharg, luaA_loadrc);
  982. bool ret = confpath != NULL;
  983. p_delete(&confpath);
  984. return ret;
  985. }
  986. /** Find a config file for which the given callback returns true.
  987. * \param xdg An xdg handle to use to get XDG basedir.
  988. * \param confpatharg The configuration file to load.
  989. * \param callback The callback to call.
  990. */
  991. const char *
  992. luaA_find_config(xdgHandle* xdg, const char *confpatharg, luaA_config_callback *callback)
  993. {
  994. char *confpath = NULL;
  995. if(confpatharg && callback(confpatharg))
  996. {
  997. return a_strdup(confpatharg);
  998. }
  999. confpath = xdgConfigFind("awesome/rc.lua", xdg);
  1000. char *tmp = confpath;
  1001. /* confpath is "string1\0string2\0string3\0\0" */
  1002. while(*tmp)
  1003. {
  1004. if(callback(tmp))
  1005. {
  1006. const char *ret = a_strdup(tmp);
  1007. p_delete(&confpath);
  1008. return ret;
  1009. }
  1010. tmp += a_strlen(tmp) + 1;
  1011. }
  1012. p_delete(&confpath);
  1013. if(callback(AWESOME_DEFAULT_CONF))
  1014. {
  1015. return a_strdup(AWESOME_DEFAULT_CONF);
  1016. }
  1017. return NULL;
  1018. }
  1019. int
  1020. luaA_class_index_miss_property(lua_State *L, lua_object_t *obj)
  1021. {
  1022. signal_object_emit(L, &global_signals, "debug::index::miss", 2);
  1023. return 0;
  1024. }
  1025. int
  1026. luaA_class_newindex_miss_property(lua_State *L, lua_object_t *obj)
  1027. {
  1028. signal_object_emit(L, &global_signals, "debug::newindex::miss", 3);
  1029. return 0;
  1030. }
  1031. void
  1032. luaA_emit_startup()
  1033. {
  1034. lua_State *L = globalconf_get_lua_State();
  1035. signal_object_emit(L, &global_signals, "startup", 0);
  1036. }
  1037. void
  1038. luaA_emit_refresh()
  1039. {
  1040. lua_State *L = globalconf_get_lua_State();
  1041. signal_object_emit(L, &global_signals, "refresh", 0);
  1042. }
  1043. int
  1044. luaA_default_index(lua_State *L)
  1045. {
  1046. return luaA_class_index_miss_property(L, NULL);
  1047. }
  1048. int
  1049. luaA_default_newindex(lua_State *L)
  1050. {
  1051. return luaA_class_newindex_miss_property(L, NULL);
  1052. }
  1053. // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80