awesomerc.lua: use nano by default if no editor found in env
[awesome.git] / client.c
blobc8c854727aaae228207d90b10b2717d23d4b331a
1 /*
2 * client.c - client management
4 * Copyright © 2007-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.
22 #include <stdio.h>
24 #include <xcb/xcb.h>
25 #include <xcb/xcb_atom.h>
27 #include "image.h"
28 #include "client.h"
29 #include "tag.h"
30 #include "window.h"
31 #include "ewmh.h"
32 #include "widget.h"
33 #include "screen.h"
34 #include "titlebar.h"
35 #include "luaa.h"
36 #include "mouse.h"
37 #include "systray.h"
38 #include "wibox.h"
39 #include "property.h"
40 #include "layouts/floating.h"
41 #include "common/markup.h"
42 #include "common/atoms.h"
44 extern awesome_t globalconf;
46 /** Create a new client userdata.
47 * \param L The Lua VM state.
48 * \param p A client pointer.
49 * \param The number of elements pushed on the stack.
51 int
52 luaA_client_userdata_new(lua_State *L, client_t *p)
54 client_t **pp = lua_newuserdata(L, sizeof(client_t *));
55 *pp = p;
56 client_ref(pp);
57 return luaA_settype(L, "client");
60 DO_LUA_EQ(client_t, client, "client")
61 DO_LUA_GC(client_t, client, "client", client_unref)
63 /** Load windows properties, restoring client's tag
64 * and floating state before awesome was restarted if any.
65 * \param c A client pointer.
66 * \param screen A virtual screen.
67 * \return True if client had property, false otherwise.
69 static bool
70 client_loadprops(client_t * c, screen_t *screen)
72 ssize_t len;
73 tag_array_t *tags = &screen->tags;
74 char *prop = NULL;
75 xcb_get_property_cookie_t floating_q, fullscreen_q;
76 xcb_get_property_reply_t *reply;
77 void *data;
79 if(!xutil_text_prop_get(globalconf.connection, c->win, _AWESOME_TAGS,
80 &prop, &len))
81 return false;
83 /* Send the GetProperty requests which will be processed later */
84 floating_q = xcb_get_property_unchecked(globalconf.connection, false, c->win,
85 _AWESOME_FLOATING, CARDINAL, 0, 1);
87 fullscreen_q = xcb_get_property_unchecked(globalconf.connection, false, c->win,
88 _AWESOME_FULLSCREEN, CARDINAL, 0, 1);
90 /* ignore property if the tag count isn't matching */
91 if(len == tags->len)
92 for(int i = 0; i < tags->len; i++)
93 if(prop[i] == '1')
94 tag_client(c, tags->tab[i]);
95 else
96 untag_client(c, tags->tab[i]);
98 p_delete(&prop);
100 /* check for floating */
101 reply = xcb_get_property_reply(globalconf.connection, floating_q, NULL);
103 if(reply && reply->value_len && (data = xcb_get_property_value(reply)))
104 client_setfloating(c, *(bool *) data);
105 p_delete(&reply);
107 /* check for fullscreen */
108 reply = xcb_get_property_reply(globalconf.connection, fullscreen_q, NULL);
110 if(reply && reply->value_len && (data = xcb_get_property_value(reply)))
111 client_setfullscreen(c, *(bool *) data);
112 p_delete(&reply);
114 return true;
117 /** Check if client supports protocol a protocole in WM_PROTOCOL.
118 * \param win The window.
119 * \return True if client has the atom in protocol, false otherwise.
121 static bool
122 window_hasproto(xcb_window_t win, xcb_atom_t atom)
124 uint32_t i;
125 xcb_get_wm_protocols_reply_t protocols;
126 bool ret = false;
128 if(xcb_get_wm_protocols_reply(globalconf.connection,
129 xcb_get_wm_protocols_unchecked(globalconf.connection,
130 win, WM_PROTOCOLS),
131 &protocols, NULL))
133 for(i = 0; !ret && i < protocols.atoms_len; i++)
134 if(protocols.atoms[i] == atom)
135 ret = true;
136 xcb_get_wm_protocols_reply_wipe(&protocols);
138 return ret;
141 /** Returns true if a client is tagged
142 * with one of the tags of the specified screen.
143 * \param c The client to check.
144 * \param screen Virtual screen number.
145 * \return true if the client is visible, false otherwise.
147 bool
148 client_maybevisible(client_t *c, int screen)
150 if(c->screen == screen)
152 if(c->issticky || c->type == WINDOW_TYPE_DESKTOP)
153 return true;
155 tag_array_t *tags = &globalconf.screens[screen].tags;
157 for(int i = 0; i < tags->len; i++)
158 if(tags->tab[i]->selected && is_client_tagged(c, tags->tab[i]))
159 return true;
161 return false;
164 /** Get a client by its window.
165 * \param w The client window to find.
166 * \return A client pointer if found, NULL otherwise.
168 client_t *
169 client_getbywin(xcb_window_t w)
171 client_t *c;
172 for(c = globalconf.clients; c && c->win != w; c = c->next);
173 return c;
176 /** Unfocus a client.
177 * \param c The client.
179 static void
180 client_unfocus(client_t *c)
182 globalconf.screens[c->phys_screen].client_focus = NULL;
184 /* Call hook */
185 luaA_client_userdata_new(globalconf.L, c);
186 luaA_dofunction(globalconf.L, globalconf.hooks.unfocus, 1, 0);
188 ewmh_update_net_active_window(c->phys_screen);
191 /** Ban client and unmap it.
192 * \param c The client.
194 void
195 client_ban(client_t *c)
197 if(globalconf.screen_focus->client_focus == c)
198 client_unfocus(c);
199 xcb_unmap_window(globalconf.connection, c->win);
200 if(c->ishidden)
201 window_state_set(c->win, XCB_WM_STATE_ICONIC);
202 else
203 window_state_set(c->win, XCB_WM_STATE_WITHDRAWN);
204 if(c->titlebar)
205 xcb_unmap_window(globalconf.connection, c->titlebar->sw.window);
208 /** Give focus to client, or to first client if client is NULL.
209 * \param c The client or NULL.
210 * \return True if a window (even root) has received focus, false otherwise.
212 static void
213 client_focus(client_t *c)
215 if(!client_maybevisible(c, c->screen) || c->nofocus)
216 return;
218 /* unfocus current selected client */
219 if(globalconf.screen_focus->client_focus
220 && c != globalconf.screen_focus->client_focus)
221 client_unfocus(globalconf.screen_focus->client_focus);
223 /* stop hiding c */
224 c->ishidden = false;
225 client_setminimized(c, false);
227 /* unban the client before focusing or it will fail */
228 client_unban(c);
230 globalconf.screen_focus = &globalconf.screens[c->phys_screen];
231 globalconf.screen_focus->client_focus = c;
233 xcb_set_input_focus(globalconf.connection, XCB_INPUT_FOCUS_POINTER_ROOT,
234 c->win, XCB_CURRENT_TIME);
236 /* Some layouts use focused client differently, so call them back.
237 * And anyway, we have maybe unhidden */
238 client_need_arrange(c);
240 /* execute hook */
241 luaA_client_userdata_new(globalconf.L, globalconf.screen_focus->client_focus);
242 luaA_dofunction(globalconf.L, globalconf.hooks.focus, 1, 0);
244 ewmh_update_net_active_window(c->phys_screen);
247 /** Stack a window below.
248 * \param c The client.
249 * \param previous The previous window on the stack.
250 * \param return The next-previous!
252 static xcb_window_t
253 client_stack_below(client_t *c, xcb_window_t previous)
255 uint32_t config_win_vals[2];
257 config_win_vals[0] = previous;
258 config_win_vals[1] = XCB_STACK_MODE_BELOW;
260 if(c->titlebar)
262 xcb_configure_window(globalconf.connection,
263 c->titlebar->sw.window,
264 XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE,
265 config_win_vals);
266 config_win_vals[0] = c->titlebar->sw.window;
268 xcb_configure_window(globalconf.connection, c->win,
269 XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE,
270 config_win_vals);
271 config_win_vals[0] = c->win;
273 return c->win;
276 /** Stacking layout layers */
277 typedef enum
279 LAYER_DESKTOP = 1,
280 LAYER_BELOW,
281 LAYER_TILE,
282 LAYER_FLOAT,
283 LAYER_ABOVE,
284 LAYER_FULLSCREEN,
285 LAYER_MODAL,
286 LAYER_ONTOP,
287 LAYER_OUTOFSPACE
288 } layer_t;
290 /** Get the real layer of a client according to its attribute (fullscreen, …)
291 * \param c The client.
292 * \return The real layer.
294 static layer_t
295 client_layer_translator(client_t *c)
297 if(c->isontop)
298 return LAYER_ONTOP;
299 else if(c->ismodal)
300 return LAYER_MODAL;
301 else if(c->isfullscreen)
302 return LAYER_FULLSCREEN;
303 else if(c->isabove)
304 return LAYER_ABOVE;
305 else if(c->isfloating)
306 return LAYER_FLOAT;
308 switch(c->type)
310 case WINDOW_TYPE_DOCK:
311 return LAYER_ABOVE;
312 case WINDOW_TYPE_SPLASH:
313 case WINDOW_TYPE_DIALOG:
314 return LAYER_MODAL;
315 case WINDOW_TYPE_DESKTOP:
316 return LAYER_DESKTOP;
317 default:
318 return LAYER_TILE;
322 /** Restack clients.
323 * \todo It might be worth stopping to restack everyone and only stack `c'
324 * relatively to the first matching in the list.
326 void
327 client_stack()
329 uint32_t config_win_vals[2];
330 client_node_t *node;
331 layer_t layer;
332 int screen;
334 config_win_vals[0] = XCB_NONE;
335 config_win_vals[1] = XCB_STACK_MODE_BELOW;
337 /* first stack modal and fullscreen windows */
338 for(layer = LAYER_OUTOFSPACE - 1; layer >= LAYER_FULLSCREEN; layer--)
339 for(node = globalconf.stack; node; node = node->next)
340 if(client_layer_translator(node->client) == layer)
341 config_win_vals[0] = client_stack_below(node->client, config_win_vals[0]);
343 /* then stack ontop wibox window */
344 for(screen = 0; screen < globalconf.nscreen; screen++)
345 for(int i = 0; i < globalconf.screens[screen].wiboxes.len; i++)
347 wibox_t *sb = globalconf.screens[screen].wiboxes.tab[i];
348 if(sb->ontop)
350 xcb_configure_window(globalconf.connection,
351 sb->sw.window,
352 XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE,
353 config_win_vals);
354 config_win_vals[0] = sb->sw.window;
358 /* finally stack everything else */
359 for(layer = LAYER_FULLSCREEN - 1; layer >= LAYER_TILE; layer--)
360 for(node = globalconf.stack; node; node = node->next)
361 if(client_layer_translator(node->client) == layer)
362 config_win_vals[0] = client_stack_below(node->client, config_win_vals[0]);
364 /* then stack not ontop wibox window */
365 for(screen = 0; screen < globalconf.nscreen; screen++)
366 for(int i = 0; i < globalconf.screens[screen].wiboxes.len; i++)
368 wibox_t *sb = globalconf.screens[screen].wiboxes.tab[i];
369 if(!sb->ontop)
371 xcb_configure_window(globalconf.connection,
372 sb->sw.window,
373 XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE,
374 config_win_vals);
375 config_win_vals[0] = sb->sw.window;
379 /* finally stack everything else */
380 for(layer = LAYER_TILE - 1; layer >= LAYER_DESKTOP; layer--)
381 for(node = globalconf.stack; node; node = node->next)
382 if(client_layer_translator(node->client) == layer)
383 config_win_vals[0] = client_stack_below(node->client, config_win_vals[0]);
386 /** Manage a new client.
387 * \param w The window.
388 * \param wgeom Window geometry.
389 * \param phys_screen Physical screen number.
390 * \param screen Virtual screen number where to manage client.
392 void
393 client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, int phys_screen, int screen)
395 xcb_get_property_cookie_t ewmh_icon_cookie;
396 client_t *c;
397 image_t *icon;
398 const uint32_t select_input_val[] =
400 XCB_EVENT_MASK_STRUCTURE_NOTIFY
401 | XCB_EVENT_MASK_PROPERTY_CHANGE
402 | XCB_EVENT_MASK_ENTER_WINDOW
405 /* Send request to get NET_WM_ICON property as soon as possible... */
406 ewmh_icon_cookie = ewmh_window_icon_get_unchecked(w);
407 xcb_change_window_attributes(globalconf.connection, w, XCB_CW_EVENT_MASK, select_input_val);
409 if(systray_iskdedockapp(w))
411 systray_request_handle(w, phys_screen, NULL);
412 return;
415 c = p_new(client_t, 1);
417 c->screen = screen_getbycoord(screen, wgeom->x, wgeom->y);
419 c->phys_screen = phys_screen;
421 /* Initial values */
422 c->win = w;
423 c->geometry.x = c->f_geometry.x = c->m_geometry.x = wgeom->x;
424 c->geometry.y = c->f_geometry.y = c->m_geometry.y = wgeom->y;
425 c->geometry.width = c->f_geometry.width = c->m_geometry.width = wgeom->width;
426 c->geometry.height = c->f_geometry.height = c->m_geometry.height = wgeom->height;
427 client_setborder(c, wgeom->border_width);
428 if((icon = ewmh_window_icon_get_reply(ewmh_icon_cookie)))
429 c->icon = image_ref(&icon);
431 /* we honor size hints by default */
432 c->honorsizehints = true;
434 /* update hints */
435 property_update_wm_normal_hints(c, NULL);
436 property_update_wm_hints(c, NULL);
437 property_update_wm_transient_for(c, NULL);
439 if(c->transient_for)
440 screen = c->transient_for->screen;
442 /* Try to load props if any */
443 client_loadprops(c, &globalconf.screens[screen]);
445 /* move client to screen, but do not tag it for now */
446 screen_client_moveto(c, screen, false, true);
448 /* Then check clients hints */
449 ewmh_client_check_hints(c);
451 /* Check if client has been tagged by loading props, or maybe with its
452 * hints.
453 * If not, we tag it with current selected ones.
454 * This could be done on Lua side, but it's a sane behaviour. */
455 if(!c->issticky)
457 int i;
458 tag_array_t *tags = &globalconf.screens[screen].tags;
459 for(i = 0; i < tags->len; i++)
460 if(is_client_tagged(c, tags->tab[i]))
461 break;
463 /* if no tag, set current selected */
464 if(i == tags->len)
465 for(i = 0; i < tags->len; i++)
466 if(tags->tab[i]->selected)
467 tag_client(c, tags->tab[i]);
470 /* Push client in client list */
471 client_list_push(&globalconf.clients, client_ref(&c));
473 /* Push client in stack */
474 client_raise(c);
476 /* update window title */
477 property_update_wm_name(c);
478 property_update_wm_icon_name(c);
480 /* update strut */
481 ewmh_client_strut_update(c, NULL);
483 ewmh_update_net_client_list(c->phys_screen);
485 /* Call hook to notify list change */
486 luaA_dofunction(globalconf.L, globalconf.hooks.clients, 0, 0);
488 /* call hook */
489 luaA_client_userdata_new(globalconf.L, c);
490 luaA_dofunction(globalconf.L, globalconf.hooks.manage, 1, 0);
493 /** Compute client geometry with respect to its geometry hints.
494 * \param c The client.
495 * \param geometry The geometry that the client might receive.
496 * \return The geometry the client must take respecting its hints.
498 area_t
499 client_geometry_hints(client_t *c, area_t geometry)
501 double dx, dy, max, min, ratio;
503 if(c->minay > 0 && c->maxay > 0 && (geometry.height - c->baseh) > 0
504 && (geometry.width - c->basew) > 0)
506 dx = (double) (geometry.width - c->basew);
507 dy = (double) (geometry.height - c->baseh);
508 min = (double) (c->minax) / (double) (c->minay);
509 max = (double) (c->maxax) / (double) (c->maxay);
510 ratio = dx / dy;
511 if(max > 0 && min > 0 && ratio > 0)
513 if(ratio < min)
515 dy = (dx * min + dy) / (min * min + 1);
516 dx = dy * min;
517 geometry.width = (int) dx + c->basew;
518 geometry.height = (int) dy + c->baseh;
520 else if(ratio > max)
522 dy = (dx * min + dy) / (max * max + 1);
523 dx = dy * min;
524 geometry.width = (int) dx + c->basew;
525 geometry.height = (int) dy + c->baseh;
529 if(c->minw && geometry.width < c->minw)
530 geometry.width = c->minw;
531 if(c->minh && geometry.height < c->minh)
532 geometry.height = c->minh;
533 if(c->maxw && geometry.width > c->maxw)
534 geometry.width = c->maxw;
535 if(c->maxh && geometry.height > c->maxh)
536 geometry.height = c->maxh;
537 if(c->incw)
538 geometry.width -= (geometry.width - c->basew) % c->incw;
539 if(c->inch)
540 geometry.height -= (geometry.height - c->baseh) % c->inch;
542 return geometry;
545 /** Resize client window.
546 * \param c Client to resize.
547 * \param geometry New window geometry.
548 * \param hints Use size hints.
550 void
551 client_resize(client_t *c, area_t geometry, bool hints)
553 int new_screen;
554 area_t area;
555 layout_t *layout = layout_get_current(c->screen);
556 bool fixed;
557 /* Values to configure a window is an array where values are
558 * stored according to 'value_mask' */
559 uint32_t values[5];
561 if(c->titlebar && !c->ismoving && !client_isfloating(c) && layout != layout_floating)
562 geometry = titlebar_geometry_remove(c->titlebar, c->border, geometry);
564 if(hints)
565 geometry = client_geometry_hints(c, geometry);
567 if(geometry.width <= 0 || geometry.height <= 0)
568 return;
570 /* offscreen appearance fixes */
571 area = display_area_get(c->phys_screen, NULL,
572 &globalconf.screens[c->screen].padding);
574 fixed = client_isfixed(c);
576 if(geometry.x > area.width)
577 geometry.x = area.width - geometry.width - 2 * c->border;
578 if(geometry.y > area.height)
579 geometry.y = area.height - geometry.height - 2 * c->border;
580 if(geometry.x + geometry.width + 2 * c->border < 0)
581 geometry.x = 0;
582 if(geometry.y + geometry.height + 2 * c->border < 0)
583 geometry.y = 0;
585 /* fixed windows can only change their x,y */
586 if((fixed && (c->geometry.x != geometry.x || c->geometry.y != geometry.y))
587 || (!fixed && (c->geometry.x != geometry.x
588 || c->geometry.y != geometry.y
589 || c->geometry.width != geometry.width
590 || c->geometry.height != geometry.height)))
592 new_screen = screen_getbycoord(c->screen, geometry.x, geometry.y);
594 c->geometry.x = values[0] = geometry.x;
595 c->geometry.width = values[2] = geometry.width;
596 c->geometry.y = values[1] = geometry.y;
597 c->geometry.height = values[3] = geometry.height;
598 values[4] = c->border;
600 /* save the floating geometry if the window is floating but not
601 * maximized */
602 if(c->ismoving || client_isfloating(c)
603 || layout_get_current(new_screen) == layout_floating)
604 if(!c->isfullscreen)
605 c->f_geometry = geometry;
607 titlebar_update_geometry_floating(c);
609 xcb_configure_window(globalconf.connection, c->win,
610 XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
611 XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT |
612 XCB_CONFIG_WINDOW_BORDER_WIDTH,
613 values);
614 window_configure(c->win, geometry, c->border);
616 if(c->screen != new_screen)
617 screen_client_moveto(c, new_screen, true, false);
619 /* execute hook */
620 hooks_property(c, "geometry");
624 /** Set a clinet floating.
625 * \param c The client.
626 * \param floating Set floating, or not.
627 * \param layer Layer to put the floating window onto.
629 void
630 client_setfloating(client_t *c, bool floating)
632 if(c->isfloating != floating
633 && (c->type == WINDOW_TYPE_NORMAL))
635 if((c->isfloating = floating))
636 if(!c->isfullscreen)
637 client_resize(c, c->f_geometry, false);
638 client_need_arrange(c);
639 client_stack();
640 xcb_change_property(globalconf.connection,
641 XCB_PROP_MODE_REPLACE,
642 c->win, _AWESOME_FLOATING, CARDINAL, 8, 1,
643 &c->isfloating);
644 /* execute hook */
645 hooks_property(c, "floating");
649 /** Set a client minimized, or not.
650 * \param c The client.
651 * \param s Set or not the client minimized.
653 void
654 client_setminimized(client_t *c, bool s)
656 if(c->isminimized != s)
658 client_need_arrange(c);
659 c->isminimized = s;
660 client_need_arrange(c);
661 ewmh_client_update_hints(c);
662 /* execute hook */
663 hooks_property(c, "minimized");
667 /** Set a client sticky, or not.
668 * \param c The client.
669 * \param s Set or not the client sticky.
671 void
672 client_setsticky(client_t *c, bool s)
674 if(c->issticky != s)
676 client_need_arrange(c);
677 c->issticky = s;
678 client_need_arrange(c);
679 ewmh_client_update_hints(c);
680 hooks_property(c, "sticky");
684 /** Set a client fullscreen, or not.
685 * \param c The client.
686 * \param s Set or not the client fullscreen.
688 void
689 client_setfullscreen(client_t *c, bool s)
691 if(c->isfullscreen != s)
693 area_t geometry;
695 /* become fullscreen! */
696 if((c->isfullscreen = s))
698 geometry = screen_area_get(c->screen, NULL, &globalconf.screens[c->screen].padding, false);
699 c->m_geometry = c->geometry;
700 c->oldborder = c->border;
701 client_setborder(c, 0);
703 else
705 geometry = c->m_geometry;
706 client_setborder(c, c->oldborder);
707 client_resize(c, c->m_geometry, false);
709 client_resize(c, geometry, false);
710 client_need_arrange(c);
711 client_stack();
712 xcb_change_property(globalconf.connection,
713 XCB_PROP_MODE_REPLACE,
714 c->win, _AWESOME_FULLSCREEN, CARDINAL, 8, 1,
715 &c->isfullscreen);
716 ewmh_client_update_hints(c);
717 hooks_property(c, "fullscreen");
721 /** Set a client above, or not.
722 * \param c The client.
723 * \param s Set or not the client above.
725 void
726 client_setabove(client_t *c, bool s)
728 if(c->isabove != s)
730 c->isabove = s;
731 client_stack();
732 ewmh_client_update_hints(c);
733 /* execute hook */
734 hooks_property(c, "above");
738 /** Set a client below, or not.
739 * \param c The client.
740 * \param s Set or not the client below.
742 void
743 client_setbelow(client_t *c, bool s)
745 if(c->isbelow != s)
747 c->isbelow = s;
748 client_stack();
749 ewmh_client_update_hints(c);
750 /* execute hook */
751 hooks_property(c, "below");
755 /** Set a client modal, or not.
756 * \param c The client.
757 * \param s Set or not the client moda.
759 void
760 client_setmodal(client_t *c, bool s)
762 if(c->ismodal != s)
764 c->ismodal = s;
765 client_stack();
766 ewmh_client_update_hints(c);
767 /* execute hook */
768 hooks_property(c, "modal");
772 /** Set a client ontop, or not.
773 * \param c The client.
774 * \param s Set or not the client moda.
776 void
777 client_setontop(client_t *c, bool s)
779 if(c->isontop != s)
781 c->isontop = s;
782 client_stack();
783 /* execute hook */
784 hooks_property(c, "ontop");
788 /** Save client properties as an X property.
789 * \param c The client.
791 void
792 client_saveprops_tags(client_t *c)
794 tag_array_t *tags = &globalconf.screens[c->screen].tags;
795 unsigned char *prop = p_alloca(unsigned char, tags->len + 1);
796 int i;
798 for(i = 0; i < tags->len; i++)
799 prop[i] = is_client_tagged(c, tags->tab[i]) ? '1' : '0';
801 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, c->win, _AWESOME_TAGS, STRING, 8, i, prop);
804 /** Unban a client.
805 * \param c The client.
807 void
808 client_unban(client_t *c)
810 xcb_map_window(globalconf.connection, c->win);
811 window_state_set(c->win, XCB_WM_STATE_NORMAL);
812 if(c->titlebar)
814 if(c->isfullscreen || !c->titlebar->isvisible)
815 xcb_unmap_window(globalconf.connection, c->titlebar->sw.window);
816 else
817 xcb_map_window(globalconf.connection, c->titlebar->sw.window);
821 /** Unmanage a client.
822 * \param c The client.
824 void
825 client_unmanage(client_t *c)
827 tag_array_t *tags = &globalconf.screens[c->screen].tags;
829 if(globalconf.screens[c->phys_screen].client_focus == c)
830 client_unfocus(c);
832 /* remove client everywhere */
833 client_list_detach(&globalconf.clients, c);
834 stack_client_delete(c);
835 for(int i = 0; i < tags->len; i++)
836 untag_client(c, tags->tab[i]);
838 /* call hook */
839 luaA_client_userdata_new(globalconf.L, c);
840 luaA_dofunction(globalconf.L, globalconf.hooks.unmanage, 1, 0);
842 /* Call hook to notify list change */
843 luaA_dofunction(globalconf.L, globalconf.hooks.clients, 0, 0);
845 /* The server grab construct avoids race conditions. */
846 xcb_grab_server(globalconf.connection);
848 xcb_configure_window(globalconf.connection, c->win,
849 XCB_CONFIG_WINDOW_BORDER_WIDTH,
850 (uint32_t *) &c->oldborder);
852 xcb_ungrab_button(globalconf.connection, XCB_BUTTON_INDEX_ANY, c->win,
853 XCB_BUTTON_MASK_ANY);
854 window_state_set(c->win, XCB_WM_STATE_WITHDRAWN);
856 xcb_flush(globalconf.connection);
857 xcb_ungrab_server(globalconf.connection);
859 titlebar_client_detach(c);
861 ewmh_update_net_client_list(c->phys_screen);
863 /* delete properties */
864 xcb_delete_property(globalconf.connection, c->win, _AWESOME_TAGS);
865 xcb_delete_property(globalconf.connection, c->win, _AWESOME_FLOATING);
867 if(client_hasstrut(c))
868 /* All the wiboxes (may) need to be repositioned */
869 for(int screen = 0; screen < globalconf.nscreen; screen++)
870 for(int i = 0; i < globalconf.screens[screen].wiboxes.len; i++)
872 wibox_t *s = globalconf.screens[screen].wiboxes.tab[i];
873 wibox_position_update(s);
876 /* set client as invalid */
877 c->invalid = true;
879 client_unref(&c);
882 /** Kill a client via a WM_DELETE_WINDOW request or KillClient if not
883 * supported.
884 * \param c The client to kill.
886 void
887 client_kill(client_t *c)
889 if(window_hasproto(c->win, WM_DELETE_WINDOW))
891 xcb_client_message_event_t ev;
893 /* Initialize all of event's fields first */
894 p_clear(&ev, 1);
896 ev.response_type = XCB_CLIENT_MESSAGE;
897 ev.window = c->win;
898 ev.format = 32;
899 ev.data.data32[1] = XCB_CURRENT_TIME;
900 ev.type = WM_PROTOCOLS;
901 ev.data.data32[0] = WM_DELETE_WINDOW;
903 xcb_send_event(globalconf.connection, false, c->win,
904 XCB_EVENT_MASK_NO_EVENT, (char *) &ev);
906 else
907 xcb_kill_client(globalconf.connection, c->win);
910 /** Get all clients into a table.
911 * \param L The Lua VM state.
912 * \return The number of elements pushed on stack.
913 * \luastack
914 * \lparam An optional screen nunmber.
915 * \lreturn A table with all clients.
917 static int
918 luaA_client_get(lua_State *L)
920 int i = 1, screen;
921 client_t *c;
923 screen = luaL_optnumber(L, 1, 0) - 1;
925 lua_newtable(L);
927 if(screen == SCREEN_UNDEF)
928 for(c = globalconf.clients; c; c = c->next)
930 luaA_client_userdata_new(globalconf.L, c);
931 lua_rawseti(L, -2, i++);
933 else
935 luaA_checkscreen(screen);
936 for(c = globalconf.clients; c; c = c->next)
937 if(c->screen == screen)
939 luaA_client_userdata_new(globalconf.L, c);
940 lua_rawseti(L, -2, i++);
944 return 1;
947 /** Get only visible clients for a screen (DEPRECATED).
948 * \param L The Lua VM state.
949 * \return The number of elements pushed on stack.
950 * \luastack
951 * \lparam A screen number.
952 * \lreturn A table with all visible clients for this screen.
954 static int
955 luaA_client_visible_get(lua_State *L)
957 int i = 1;
958 client_t *c;
959 int screen = luaL_checknumber(L, 1) - 1;
961 luaA_checkscreen(screen);
963 deprecate();
965 lua_newtable(L);
967 for(c = globalconf.clients; c; c = c->next)
968 if(client_isvisible(c, screen))
970 luaA_client_userdata_new(L, c);
971 lua_rawseti(L, -2, i++);
974 return 1;
977 /** Check if a client is visible on its screen.
978 * \param L The Lua VM state.
979 * \return The number of elements pushed on stack.
980 * \luastack
981 * \lvalue A client.
982 * \lreturn A boolean value, true if the client is visible, false otherwise.
984 static int
985 luaA_client_isvisible(lua_State *L)
987 client_t **c = luaA_checkudata(L, 1, "client");
988 lua_pushboolean(L, client_isvisible(*c, (*c)->screen));
989 return 1;
992 /** Set client border width.
993 * \param c The client.
994 * \param width The border width.
996 void
997 client_setborder(client_t *c, int width)
999 uint32_t w = width;
1001 if(width > 0 && (c->type == WINDOW_TYPE_DOCK
1002 || c->type == WINDOW_TYPE_SPLASH
1003 || c->type == WINDOW_TYPE_DESKTOP
1004 || c->isfullscreen))
1005 return;
1007 if(width == c->border || width < 0)
1008 return;
1010 c->border = width;
1011 xcb_configure_window(globalconf.connection, c->win,
1012 XCB_CONFIG_WINDOW_BORDER_WIDTH, &w);
1014 if(client_isvisible(c, c->screen))
1016 if(client_isfloating(c) || layout_get_current(c->screen) == layout_floating)
1017 titlebar_update_geometry_floating(c);
1018 else
1019 globalconf.screens[c->screen].need_arrange = true;
1022 hooks_property(c, "border_width");
1025 /** Kill a client.
1026 * \param L The Lua VM state.
1028 * \luastack
1029 * \lvalue A client.
1031 static int
1032 luaA_client_kill(lua_State *L)
1034 client_t **c = luaA_checkudata(L, 1, "client");
1035 client_kill(*c);
1036 return 0;
1039 /** Swap a client with another one.
1040 * \param L The Lua VM state.
1041 * \luastack
1042 * \lvalue A client.
1043 * \lparam A client to swap with.
1045 static int
1046 luaA_client_swap(lua_State *L)
1048 client_t **c = luaA_checkudata(L, 1, "client");
1049 client_t **swap = luaA_checkudata(L, 2, "client");
1050 client_list_swap(&globalconf.clients, *swap, *c);
1051 client_need_arrange(*c);
1052 client_need_arrange(*swap);
1054 /* Call hook to notify list change */
1055 luaA_dofunction(L, globalconf.hooks.clients, 0, 0);
1057 return 0;
1060 /** Access or set the client tags.
1061 * \param L The Lua VM state.
1062 * \return The number of elements pushed on stack.
1063 * \lparam A table with tags to set, or none to get the current tags table.
1064 * \return The clients tag.
1066 static int
1067 luaA_client_tags(lua_State *L)
1069 tag_array_t *tags;
1070 tag_t **tag;
1071 client_t **c = luaA_checkudata(L, 1, "client");
1072 int j = 0;
1074 if(lua_gettop(L) == 2)
1076 luaA_checktable(L, 2);
1077 tags = &globalconf.screens[(*c)->screen].tags;
1078 for(int i = 0; i < tags->len; i++)
1079 untag_client(*c, tags->tab[i]);
1080 lua_pushnil(L);
1081 while(lua_next(L, 2))
1083 tag = luaA_checkudata(L, -1, "tag");
1084 tag_client(*c, *tag);
1085 lua_pop(L, 1);
1087 lua_pop(L, 1);
1090 tags = &globalconf.screens[(*c)->screen].tags;
1091 luaA_otable_new(L);
1092 for(int i = 0; i < tags->len; i++)
1093 if(is_client_tagged(*c, tags->tab[i]))
1095 luaA_tag_userdata_new(L, tags->tab[i]);
1096 lua_rawseti(L, -2, ++j);
1099 return 1;
1102 /** Raise a client on top of others which are on the same layer.
1103 * \param L The Lua VM state.
1105 * \luastack
1106 * \lvalue A client.
1108 static int
1109 luaA_client_raise(lua_State *L)
1111 client_t **c = luaA_checkudata(L, 1, "client");
1112 client_raise(*c);
1113 return 0;
1116 /** Redraw a client by unmapping and mapping it quickly.
1117 * \param L The Lua VM state.
1119 * \luastack
1120 * \lvalue A client.
1122 static int
1123 luaA_client_redraw(lua_State *L)
1125 client_t **c = luaA_checkudata(L, 1, "client");
1127 xcb_unmap_window(globalconf.connection, (*c)->win);
1128 xcb_map_window(globalconf.connection, (*c)->win);
1130 /* Set the focus on the current window if the redraw has been
1131 performed on the window where the pointer is currently on
1132 because after the unmapping/mapping, the focus is lost */
1133 if(globalconf.screen_focus->client_focus == *c)
1134 xcb_set_input_focus(globalconf.connection, XCB_INPUT_FOCUS_POINTER_ROOT,
1135 (*c)->win, XCB_CURRENT_TIME);
1137 return 0;
1140 /** Return a formated string for a client.
1141 * \param L The Lua VM state.
1142 * \luastack
1143 * \lvalue A client.
1144 * \lreturn A string.
1146 static int
1147 luaA_client_tostring(lua_State *L)
1149 client_t **p = luaA_checkudata(L, 1, "client");
1150 lua_pushfstring(L, "[client udata(%p) name(%s)]", *p, (*p)->name);
1151 return 1;
1154 /** Stop managing a client.
1155 * \param L The Lua VM state.
1156 * \return The number of elements pushed on stack.
1157 * \luastack
1158 * \lvalue A client.
1160 static int
1161 luaA_client_unmanage(lua_State *L)
1163 client_t **c = luaA_checkudata(L, 1, "client");
1164 client_unmanage(*c);
1165 return 0;
1168 /** Return client geometry.
1169 * \param L The Lua VM state.
1170 * \return The number of elements pushed on stack.
1171 * \luastack
1172 * \lparam A table with new coordinates, or none.
1173 * \lreturn A table with client coordinates.
1175 static int
1176 luaA_client_geometry(lua_State *L)
1178 client_t **c = luaA_checkudata(L, 1, "client");
1180 if(lua_gettop(L) == 2)
1182 if((*c)->isfloating || layout_get_current((*c)->screen) == layout_floating)
1184 area_t geometry;
1186 luaA_checktable(L, 2);
1187 geometry.x = luaA_getopt_number(L, 2, "x", (*c)->geometry.x);
1188 geometry.y = luaA_getopt_number(L, 2, "y", (*c)->geometry.y);
1189 geometry.width = luaA_getopt_number(L, 2, "width", (*c)->geometry.width);
1190 geometry.height = luaA_getopt_number(L, 2, "height", (*c)->geometry.height);
1191 client_resize(*c, geometry, false);
1195 return luaA_pusharea(L, (*c)->geometry);
1198 static int
1199 luaA_client_coords(lua_State *L)
1201 deprecate();
1202 return luaA_client_geometry(L);
1205 /** Return client geometry, using also titlebar and border width.
1206 * \param L The Lua VM state.
1207 * \return The number of elements pushed on stack.
1208 * \luastack
1209 * \lparam A table with new coordinates, or none.
1210 * \lreturn A table with client coordinates.
1212 static int
1213 luaA_client_fullgeometry(lua_State *L)
1215 client_t **c = luaA_checkudata(L, 1, "client");
1216 area_t geometry;
1218 if(lua_gettop(L) == 2)
1220 if((*c)->isfloating || layout_get_current((*c)->screen) == layout_floating)
1222 luaA_checktable(L, 2);
1223 geometry.x = luaA_getopt_number(L, 2, "x", (*c)->geometry.x);
1224 geometry.y = luaA_getopt_number(L, 2, "y", (*c)->geometry.y);
1225 geometry.width = luaA_getopt_number(L, 2, "width", (*c)->geometry.width);
1226 geometry.height = luaA_getopt_number(L, 2, "height", (*c)->geometry.height);
1227 geometry = titlebar_geometry_remove((*c)->titlebar,
1228 (*c)->border,
1229 geometry);
1230 client_resize(*c, geometry, false);
1234 return luaA_pusharea(L, titlebar_geometry_add((*c)->titlebar,
1235 (*c)->border,
1236 (*c)->geometry));
1239 static int
1240 luaA_client_fullcoords(lua_State *L)
1242 deprecate();
1243 return luaA_client_fullgeometry(L);
1246 /** Client newindex.
1247 * \param L The Lua VM state.
1248 * \return The number of elements pushed on stack.
1251 luaA_client_newindex(lua_State *L)
1253 size_t len;
1254 client_t **c = luaA_checkudata(L, 1, "client");
1255 const char *buf = luaL_checklstring(L, 2, &len);
1256 bool b;
1257 double d;
1258 int i;
1259 wibox_t **t = NULL;
1260 image_t **image;
1262 if((*c)->invalid)
1263 luaL_error(L, "client is invalid\n");
1265 switch(a_tokenize(buf, len))
1267 case A_TK_SCREEN:
1268 if(globalconf.xinerama_is_active)
1270 i = luaL_checknumber(L, 3) - 1;
1271 luaA_checkscreen(i);
1272 if(i != (*c)->screen)
1273 screen_client_moveto(*c, i, true, true);
1275 break;
1276 case A_TK_HIDE:
1277 b = luaA_checkboolean(L, 3);
1278 if(b != (*c)->ishidden)
1280 client_need_arrange(*c);
1281 (*c)->ishidden = b;
1282 client_need_arrange(*c);
1284 break;
1285 case A_TK_MINIMIZE:
1286 client_setminimized(*c, luaA_checkboolean(L, 3));
1287 break;
1288 case A_TK_FULLSCREEN:
1289 client_setfullscreen(*c, luaA_checkboolean(L, 3));
1290 break;
1291 case A_TK_ICON:
1292 image = luaA_checkudata(L, 3, "image");
1293 image_unref(&(*c)->icon);
1294 image_ref(image);
1295 (*c)->icon = *image;
1296 /* execute hook */
1297 hooks_property(*c, "icon");
1298 break;
1299 case A_TK_OPACITY:
1300 if(lua_isnil(L, 3))
1301 window_opacity_set((*c)->win, -1);
1302 else
1304 d = luaL_checknumber(L, 3);
1305 if(d >= 0 && d <= 1)
1306 window_opacity_set((*c)->win, d);
1308 break;
1309 case A_TK_FLOATING:
1310 client_setfloating(*c, luaA_checkboolean(L, 3));
1311 break;
1312 case A_TK_STICKY:
1313 client_setsticky(*c, luaA_checkboolean(L, 3));
1314 break;
1315 case A_TK_HONORSIZEHINTS:
1316 (*c)->honorsizehints = luaA_checkboolean(L, 3);
1317 client_need_arrange(*c);
1318 break;
1319 case A_TK_BORDER_WIDTH:
1320 client_setborder(*c, luaL_checknumber(L, 3));
1321 break;
1322 case A_TK_ONTOP:
1323 client_setontop(*c, luaA_checkboolean(L, 3));
1324 break;
1325 case A_TK_BORDER_COLOR:
1326 if((buf = luaL_checklstring(L, 3, &len))
1327 && xcolor_init_reply(xcolor_init_unchecked(&(*c)->border_color, buf, len)))
1328 xcb_change_window_attributes(globalconf.connection, (*c)->win,
1329 XCB_CW_BORDER_PIXEL, &(*c)->border_color.pixel);
1330 break;
1331 case A_TK_TITLEBAR:
1332 if(lua_isnil(L, 3))
1333 titlebar_client_detach(*c);
1334 else
1336 t = luaA_checkudata(L, 3, "wibox");
1337 titlebar_client_attach(*c, *t);
1339 break;
1340 default:
1341 return 0;
1344 return 0;
1347 /** Client object.
1348 * \param L The Lua VM state.
1349 * \return The number of elements pushed on stack.
1350 * \luastack
1351 * \lfield name The client title.
1352 * \lfield skip_taskbar True if the client does not want to be in taskbar.
1353 * \lfield type The window type (desktop, normal, dock, …).
1354 * \lfield class The client class.
1355 * \lfield instance The client instance.
1356 * \lfield pid The client PID, if available.
1357 * \lfield role The window role, if available.
1358 * \lfield machine The machine client is running on.
1359 * \lfield icon_name The client name when iconified.
1360 * \lfield screen Client screen number.
1361 * \lfield hide Define if the client must be hidden, i.e. never mapped,
1362 * invisible in taskbar.
1363 * \lfield minimize Define it the client must be iconify, i.e. only visible in
1364 * taskbar.
1365 * \lfield icon_path Path to the icon used to identify.
1366 * \lfield floating True always floating.
1367 * \lfield honorsizehints Honor size hints, i.e. respect size ratio.
1368 * \lfield border_width The client border width.
1369 * \lfield border_color The client border color.
1370 * \lfield titlebar The client titlebar.
1371 * \lfield urgent The client urgent state.
1372 * \lfield focus The focused client.
1373 * \lfield opacity The client opacity between 0 and 1.
1374 * \lfield ontop The client is on top of every other windows.
1375 * \lfield fullscreen The client is fullscreen or not.
1377 static int
1378 luaA_client_index(lua_State *L)
1380 size_t len;
1381 ssize_t slen;
1382 client_t **c = luaA_checkudata(L, 1, "client");
1383 const char *buf = luaL_checklstring(L, 2, &len);
1384 char *value;
1385 void *data;
1386 xcb_get_wm_class_reply_t hint;
1387 xcb_get_property_cookie_t prop_c;
1388 xcb_get_property_reply_t *prop_r = NULL;
1389 double d;
1391 if((*c)->invalid)
1392 luaL_error(L, "client is invalid\n");
1394 if(luaA_usemetatable(L, 1, 2))
1395 return 1;
1397 switch(a_tokenize(buf, len))
1399 case A_TK_NAME:
1400 lua_pushstring(L, (*c)->name);
1401 break;
1402 case A_TK_SKIP_TASKBAR:
1403 lua_pushboolean(L, (*c)->skiptb);
1404 break;
1405 case A_TK_TYPE:
1406 switch((*c)->type)
1408 case WINDOW_TYPE_DESKTOP:
1409 lua_pushliteral(L, "desktop");
1410 break;
1411 case WINDOW_TYPE_DOCK:
1412 lua_pushliteral(L, "dock");
1413 break;
1414 case WINDOW_TYPE_SPLASH:
1415 lua_pushliteral(L, "splash");
1416 break;
1417 case WINDOW_TYPE_DIALOG:
1418 lua_pushliteral(L, "dialog");
1419 break;
1420 default:
1421 lua_pushliteral(L, "normal");
1422 break;
1424 break;
1425 case A_TK_CLASS:
1426 if(!xcb_get_wm_class_reply(globalconf.connection,
1427 xcb_get_wm_class_unchecked(globalconf.connection, (*c)->win),
1428 &hint, NULL))
1429 return 0;
1430 lua_pushstring(L, hint.class);
1431 xcb_get_wm_class_reply_wipe(&hint);
1432 break;
1433 case A_TK_INSTANCE:
1434 if(!xcb_get_wm_class_reply(globalconf.connection,
1435 xcb_get_wm_class_unchecked(globalconf.connection, (*c)->win),
1436 &hint, NULL))
1437 return 0;
1438 lua_pushstring(L, hint.name);
1439 xcb_get_wm_class_reply_wipe(&hint);
1440 break;
1441 case A_TK_ROLE:
1442 if(!xutil_text_prop_get(globalconf.connection, (*c)->win,
1443 WM_WINDOW_ROLE, &value, &slen))
1444 return 0;
1445 lua_pushlstring(L, value, slen);
1446 p_delete(&value);
1447 break;
1448 case A_TK_PID:
1449 prop_c = xcb_get_property_unchecked(globalconf.connection, false, (*c)->win, _NET_WM_PID, CARDINAL, 0L, 1L);
1450 prop_r = xcb_get_property_reply(globalconf.connection, prop_c, NULL);
1452 if(prop_r && prop_r->value_len && (data = xcb_get_property_value(prop_r)))
1453 lua_pushnumber(L, *(uint32_t *)data);
1454 else
1456 p_delete(&prop_r);
1457 return 0;
1459 break;
1460 case A_TK_MACHINE:
1461 if(!xutil_text_prop_get(globalconf.connection, (*c)->win,
1462 WM_CLIENT_MACHINE, &value, &slen))
1463 return 0;
1464 lua_pushlstring(L, value, slen);
1465 p_delete(&value);
1466 break;
1467 case A_TK_ICON_NAME:
1468 lua_pushstring(L, (*c)->icon_name);
1469 break;
1470 case A_TK_SCREEN:
1471 lua_pushnumber(L, 1 + (*c)->screen);
1472 break;
1473 case A_TK_HIDE:
1474 lua_pushboolean(L, (*c)->ishidden);
1475 break;
1476 case A_TK_MINIMIZE:
1477 lua_pushboolean(L, (*c)->isminimized);
1478 break;
1479 case A_TK_FULLSCREEN:
1480 lua_pushboolean(L, (*c)->isfullscreen);
1481 break;
1482 case A_TK_ICON:
1483 if((*c)->icon)
1484 luaA_image_userdata_new(L, (*c)->icon);
1485 else
1486 return 0;
1487 break;
1488 case A_TK_OPACITY:
1489 if((d = window_opacity_get((*c)->win)) >= 0)
1490 lua_pushnumber(L, d);
1491 else
1492 return 0;
1493 break;
1494 case A_TK_FLOATING:
1495 lua_pushboolean(L, (*c)->isfloating);
1496 break;
1497 case A_TK_ONTOP:
1498 lua_pushboolean(L, (*c)->isontop);
1499 break;
1500 case A_TK_STICKY:
1501 lua_pushboolean(L, (*c)->issticky);
1502 break;
1503 case A_TK_HONORSIZEHINTS:
1504 lua_pushboolean(L, (*c)->honorsizehints);
1505 break;
1506 case A_TK_BORDER_WIDTH:
1507 lua_pushnumber(L, (*c)->border);
1508 break;
1509 case A_TK_BORDER_COLOR:
1510 luaA_pushcolor(L, &(*c)->border_color);
1511 break;
1512 case A_TK_TITLEBAR:
1513 if((*c)->titlebar)
1514 return luaA_wibox_userdata_new(L, (*c)->titlebar);
1515 return 0;
1516 case A_TK_URGENT:
1517 lua_pushboolean(L, (*c)->isurgent);
1518 break;
1519 case A_TK_SIZEHINTS:
1520 lua_newtable(L);
1521 lua_pushboolean(L, (*c)->size_hints.flags & XCB_SIZE_HINT_US_POSITION);
1522 lua_setfield(L, -2, "user_position");
1523 lua_pushboolean(L, (*c)->size_hints.flags & XCB_SIZE_HINT_US_SIZE);
1524 lua_setfield(L, -2, "user_size");
1525 lua_pushboolean(L, (*c)->size_hints.flags & XCB_SIZE_HINT_P_POSITION);
1526 lua_setfield(L, -2, "program_position");
1527 lua_pushboolean(L, (*c)->size_hints.flags & XCB_SIZE_HINT_P_SIZE);
1528 lua_setfield(L, -2, "program_size");
1529 break;
1530 default:
1531 return 0;
1534 return 1;
1537 /** Get or set mouse buttons bindings for a client.
1538 * \param L The Lua VM state.
1539 * \return The number of element pushed on stack.
1540 * \luastack
1541 * \lvalue A client.
1542 * \lparam An array of mouse button bindings objects, or nothing.
1543 * \return The array of mouse button bindings objects of this client.
1545 static int
1546 luaA_client_buttons(lua_State *L)
1548 client_t **client = luaA_checkudata(L, 1, "client");
1549 button_array_t *buttons = &(*client)->buttons;
1551 if(lua_gettop(L) == 2)
1552 luaA_button_array_set(L, 2, buttons);
1554 return luaA_button_array_get(L, buttons);
1557 /* Client module.
1558 * \param L The Lua VM state.
1559 * \return The number of pushed elements.
1561 static int
1562 luaA_client_module_index(lua_State *L)
1564 size_t len;
1565 const char *buf = luaL_checklstring(L, 2, &len);
1567 switch(a_tokenize(buf, len))
1569 case A_TK_FOCUS:
1570 if(globalconf.screen_focus->client_focus)
1571 luaA_client_userdata_new(L, globalconf.screen_focus->client_focus);
1572 else
1573 return 0;
1574 break;
1575 default:
1576 return 0;
1579 return 1;
1582 /* Client module new index.
1583 * \param L The Lua VM state.
1584 * \return The number of pushed elements.
1586 static int
1587 luaA_client_module_newindex(lua_State *L)
1589 size_t len;
1590 const char *buf = luaL_checklstring(L, 2, &len);
1591 client_t **c;
1593 switch(a_tokenize(buf, len))
1595 case A_TK_FOCUS:
1596 c = luaA_checkudata(L, 3, "client");
1597 client_focus(*c);
1598 break;
1599 default:
1600 break;
1603 return 0;
1606 const struct luaL_reg awesome_client_methods[] =
1608 { "get", luaA_client_get },
1609 { "visible_get", luaA_client_visible_get },
1610 { "__index", luaA_client_module_index },
1611 { "__newindex", luaA_client_module_newindex },
1612 { NULL, NULL }
1614 const struct luaL_reg awesome_client_meta[] =
1616 { "isvisible", luaA_client_isvisible },
1617 { "geometry", luaA_client_geometry },
1618 { "fullgeometry", luaA_client_fullgeometry },
1619 { "buttons", luaA_client_buttons },
1620 { "tags", luaA_client_tags },
1621 { "kill", luaA_client_kill },
1622 { "swap", luaA_client_swap },
1623 { "raise", luaA_client_raise },
1624 { "redraw", luaA_client_redraw },
1625 { "mouse_resize", luaA_client_mouse_resize },
1626 { "mouse_move", luaA_client_mouse_move },
1627 { "unmanage", luaA_client_unmanage },
1628 { "__index", luaA_client_index },
1629 { "__newindex", luaA_client_newindex },
1630 { "__eq", luaA_client_eq },
1631 { "__gc", luaA_client_gc },
1632 { "__tostring", luaA_client_tostring },
1633 /* deprecated */
1634 { "coords", luaA_client_coords },
1635 { "fullcoords", luaA_client_fullcoords },
1636 { NULL, NULL }
1639 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80