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

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