Inline g_spawn_command_line_async() into awesome
[awesome.git] / client.c
bloba1d60250533b2a7acdfa34f5d311cb43e74ae186
1 /*
2 * client.c - client management
4 * Copyright © 2007-2009 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 <xcb/xcb_atom.h>
23 #include <xcb/xcb_image.h>
25 #include "tag.h"
26 #include "ewmh.h"
27 #include "screen.h"
28 #include "titlebar.h"
29 #include "systray.h"
30 #include "property.h"
31 #include "spawn.h"
32 #include "luaa.h"
33 #include "common/atoms.h"
34 #include "common/xutil.h"
36 client_t *
37 luaA_client_checkudata(lua_State *L, int ud)
39 client_t *c = luaA_checkudata(L, ud, &client_class);
40 if(c->invalid)
41 luaL_error(L, "client is invalid\n");
42 return c;
45 /** Collect a client.
46 * \param L The Lua VM state.
47 * \return The number of element pushed on stack.
49 static int
50 luaA_client_gc(lua_State *L)
52 client_t *c = luaA_checkudata(L, 1, &client_class);
53 button_array_wipe(&c->buttons);
54 key_array_wipe(&c->keys);
55 xcb_get_wm_protocols_reply_wipe(&c->protocols);
56 p_delete(&c->class);
57 p_delete(&c->instance);
58 p_delete(&c->icon_name);
59 p_delete(&c->name);
60 return luaA_object_gc(L);
63 /** Change the client opacity.
64 * \param L The Lua VM state.
65 * \param cidx The client index.
66 * \param opacity The opacity.
68 void
69 client_set_opacity(lua_State *L, int cidx, double opacity)
71 client_t *c = luaA_client_checkudata(L, cidx);
73 if(c->opacity != opacity)
75 c->opacity = opacity;
76 window_opacity_set(c->window, opacity);
77 luaA_object_emit_signal(L, cidx, "property::opacity", 0);
81 /** Change the clients urgency flag.
82 * \param L The Lua VM state.
83 * \param cidx The client index on the stack.
84 * \param urgent The new flag state.
86 void
87 client_set_urgent(lua_State *L, int cidx, bool urgent)
89 client_t *c = luaA_client_checkudata(L, cidx);
91 if(c->urgent != urgent)
93 xcb_get_property_cookie_t hints =
94 xcb_get_wm_hints_unchecked(globalconf.connection, c->window);
96 c->urgent = urgent;
97 ewmh_client_update_hints(c);
99 /* update ICCCM hints */
100 xcb_wm_hints_t wmh;
101 xcb_get_wm_hints_reply(globalconf.connection, hints, &wmh, NULL);
103 if(urgent)
104 wmh.flags |= XCB_WM_HINT_X_URGENCY;
105 else
106 wmh.flags &= ~XCB_WM_HINT_X_URGENCY;
108 xcb_set_wm_hints(globalconf.connection, c->window, &wmh);
110 hook_property(c, "urgent");
111 luaA_object_emit_signal(L, cidx, "property::urgent", 0);
115 void
116 client_set_group_window(lua_State *L, int cidx, xcb_window_t window)
118 client_t *c = luaA_client_checkudata(L, cidx);
120 if(c->group_window != window)
122 c->group_window = window;
123 luaA_object_emit_signal(L, cidx, "property::group_window", 0);
127 void
128 client_set_type(lua_State *L, int cidx, window_type_t type)
130 client_t *c = luaA_client_checkudata(L, cidx);
132 if(c->type != type)
134 c->type = type;
135 luaA_object_emit_signal(L, cidx, "property::type", 0);
139 void
140 client_set_pid(lua_State *L, int cidx, uint32_t pid)
142 client_t *c = luaA_client_checkudata(L, cidx);
144 if(c->pid != pid)
146 c->pid = pid;
147 luaA_object_emit_signal(L, cidx, "property::pid", 0);
151 void
152 client_set_icon_name(lua_State *L, int cidx, char *icon_name)
154 client_t *c = luaA_client_checkudata(L, cidx);
155 p_delete(&c->icon_name);
156 c->icon_name = icon_name;
157 luaA_object_emit_signal(L, cidx, "property::icon_name", 0);
158 hook_property(c, "icon_name");
161 void
162 client_set_role(lua_State *L, int cidx, char *role)
164 client_t *c = luaA_client_checkudata(L, cidx);
165 p_delete(&c->role);
166 c->role = role;
167 luaA_object_emit_signal(L, cidx, "property::role", 0);
170 void
171 client_set_machine(lua_State *L, int cidx, char *machine)
173 client_t *c = luaA_client_checkudata(L, cidx);
174 p_delete(&c->machine);
175 c->machine = machine;
176 luaA_object_emit_signal(L, cidx, "property::machine", 0);
179 void
180 client_set_class_instance(lua_State *L, int cidx, const char *class, const char *instance)
182 client_t *c = luaA_client_checkudata(L, cidx);
183 p_delete(&c->class);
184 p_delete(&c->instance);
185 c->class = a_strdup(class);
186 c->instance = a_strdup(instance);
187 luaA_object_emit_signal(L, cidx, "property::class", 0);
188 luaA_object_emit_signal(L, cidx, "property::instance", 0);
191 void
192 client_set_transient_for(lua_State *L, int cidx, client_t *transient_for)
194 client_t *c = luaA_client_checkudata(L, cidx);
196 if(c->transient_for != transient_for)
198 c->transient_for = transient_for;
199 luaA_object_emit_signal(L, cidx, "property::transient_for", 0);
203 void
204 client_set_name(lua_State *L, int cidx, char *name)
206 client_t *c = luaA_client_checkudata(L, cidx);
207 p_delete(&c->name);
208 c->name = name;
209 hook_property(c, "name");
210 luaA_object_emit_signal(L, cidx, "property::name", 0);
213 /** Returns true if a client is tagged
214 * with one of the tags of the specified screen.
215 * \param c The client to check.
216 * \param screen Virtual screen.
217 * \return true if the client is visible, false otherwise.
219 bool
220 client_maybevisible(client_t *c, screen_t *screen)
222 if(screen && c->screen == screen)
224 if(c->sticky || c->type == WINDOW_TYPE_DESKTOP)
225 return true;
227 foreach(tag, screen->tags)
228 if(tag_get_selected(*tag) && is_client_tagged(c, *tag))
229 return true;
231 return false;
234 /** Get a client by its window.
235 * \param w The client window to find.
236 * \return A client pointer if found, NULL otherwise.
238 client_t *
239 client_getbywin(xcb_window_t w)
241 foreach(c, globalconf.clients)
242 if((*c)->window == w)
243 return *c;
245 return NULL;
248 /** Record that a client lost focus.
249 * \param c Client being unfocused
251 void
252 client_unfocus_update(client_t *c)
254 globalconf.screens.tab[c->phys_screen].client_focus = NULL;
255 ewmh_update_net_active_window(c->phys_screen);
257 /* Call hook */
258 if(globalconf.hooks.unfocus != LUA_REFNIL)
260 luaA_object_push(globalconf.L, c);
261 luaA_dofunction_from_registry(globalconf.L, globalconf.hooks.unfocus, 1, 0);
264 luaA_object_push(globalconf.L, c);
265 luaA_class_emit_signal(globalconf.L, &client_class, "unfocus", 1);
268 /** Unfocus a client.
269 * \param c The client.
271 void
272 client_unfocus(client_t *c)
275 xcb_window_t root_win = xutil_screen_get(globalconf.connection, c->phys_screen)->root;
276 /* Set focus on root window, so no events leak to the current window.
277 * This kind of inlines client_set_focus(), but a root window will never have
278 * the WM_TAKE_FOCUS protocol.
280 xcb_set_input_focus(globalconf.connection, XCB_INPUT_FOCUS_PARENT,
281 root_win, XCB_CURRENT_TIME);
283 client_unfocus_update(c);
286 /** Check if client supports protocol a protocole in WM_PROTOCOL.
287 * \param c The client.
288 * \param atom The protocol atom to check for.
289 * \return True if client has the atom in protocol, false otherwise.
291 bool
292 client_hasproto(client_t *c, xcb_atom_t atom)
294 for(uint32_t i = 0; i < c->protocols.atoms_len; i++)
295 if(c->protocols.atoms[i] == atom)
296 return true;
297 return false;
300 /** Sets focus on window - using xcb_set_input_focus or WM_TAKE_FOCUS
301 * \param c Client that should get focus
302 * \param set_input_focus Should we call xcb_set_input_focus
304 void
305 client_set_focus(client_t *c, bool set_input_focus)
307 bool takefocus = client_hasproto(c, WM_TAKE_FOCUS);
308 if(set_input_focus)
309 xcb_set_input_focus(globalconf.connection, XCB_INPUT_FOCUS_PARENT,
310 c->window, XCB_CURRENT_TIME);
311 if(takefocus)
312 window_takefocus(c->window);
315 /** Ban client and move it out of the viewport.
316 * \param c The client.
318 void
319 client_ban(client_t *c)
321 if(!c->isbanned)
323 xcb_unmap_window(globalconf.connection, c->window);
325 c->isbanned = true;
327 if(globalconf.screens.tab[c->phys_screen].prev_client_focus == c)
328 globalconf.screens.tab[c->phys_screen].prev_client_focus = NULL;
330 /* Wait until the last moment to take away the focus from the window. */
331 if(globalconf.screens.tab[c->phys_screen].client_focus == c)
332 client_unfocus(c);
336 /** This is part of The Bob Marley Algorithmm: we ignore enter and leave window
337 * in certain cases, like map/unmap or move, so we don't get spurious events.
339 void
340 client_ignore_enterleave_events(void)
342 foreach(c, globalconf.clients)
343 xcb_change_window_attributes(globalconf.connection,
344 (*c)->window,
345 XCB_CW_EVENT_MASK,
346 (const uint32_t []) { CLIENT_SELECT_INPUT_EVENT_MASK & ~(XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW) });
349 void
350 client_restore_enterleave_events(void)
352 foreach(c, globalconf.clients)
353 xcb_change_window_attributes(globalconf.connection,
354 (*c)->window,
355 XCB_CW_EVENT_MASK,
356 (const uint32_t []) { CLIENT_SELECT_INPUT_EVENT_MASK });
359 /** Record that a client got focus.
360 * \param c The client.
362 void
363 client_focus_update(client_t *c)
365 if(!client_maybevisible(c, c->screen))
367 /* Focus previously focused client */
368 client_focus(globalconf.screen_focus->prev_client_focus);
369 return;
372 if(globalconf.screen_focus
373 && globalconf.screen_focus->client_focus)
375 if (globalconf.screen_focus->client_focus != c)
376 client_unfocus_update(globalconf.screen_focus->client_focus);
377 else
378 /* Already focused */
379 return;
381 luaA_object_push(globalconf.L, c);
382 client_set_minimized(globalconf.L, -1, false);
384 /* unban the client before focusing for consistency */
385 client_unban(c);
387 globalconf.screen_focus = &globalconf.screens.tab[c->phys_screen];
388 globalconf.screen_focus->prev_client_focus = c;
389 globalconf.screen_focus->client_focus = c;
391 /* according to EWMH, we have to remove the urgent state from a client */
392 client_set_urgent(globalconf.L, -1, false);
394 ewmh_update_net_active_window(c->phys_screen);
396 /* execute hook */
397 if(globalconf.hooks.focus != LUA_REFNIL)
399 luaA_object_push(globalconf.L, c);
400 luaA_dofunction_from_registry(globalconf.L, globalconf.hooks.focus, 1, 0);
403 luaA_object_push(globalconf.L, c);
404 luaA_class_emit_signal(globalconf.L, &client_class, "focus", 1);
407 /** Give focus to client, or to first client if client is NULL.
408 * \param c The client.
410 void
411 client_focus(client_t *c)
413 /* We have to set focus on first client */
414 if(!c && globalconf.clients.len && !(c = globalconf.clients.tab[0]))
415 return;
417 if(!client_maybevisible(c, c->screen))
418 return;
420 if (!c->nofocus)
421 client_focus_update(c);
423 client_set_focus(c, !c->nofocus);
426 /** Stack a window below.
427 * \param c The client.
428 * \param previous The previous window on the stack.
429 * \return The next-previous!
431 static xcb_window_t
432 client_stack_above(client_t *c, xcb_window_t previous)
434 uint32_t config_win_vals[2];
436 config_win_vals[0] = previous;
437 config_win_vals[1] = XCB_STACK_MODE_ABOVE;
439 xcb_configure_window(globalconf.connection, c->window,
440 XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE,
441 config_win_vals);
443 config_win_vals[0] = c->window;
445 if(c->titlebar)
447 xcb_configure_window(globalconf.connection,
448 c->titlebar->window,
449 XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE,
450 config_win_vals);
451 previous = c->titlebar->window;
453 else
454 previous = c->window;
456 /* stack transient window on top of their parents */
457 foreach(node, globalconf.stack)
458 if((*node)->transient_for == c)
459 previous = client_stack_above(*node, previous);
461 return previous;
464 /** Stacking layout layers */
465 typedef enum
467 /** This one is a special layer */
468 LAYER_IGNORE,
469 LAYER_DESKTOP,
470 LAYER_BELOW,
471 LAYER_NORMAL,
472 LAYER_ABOVE,
473 LAYER_FULLSCREEN,
474 LAYER_ONTOP,
475 /** This one only used for counting and is not a real layer */
476 LAYER_COUNT
477 } layer_t;
479 /** Get the real layer of a client according to its attribute (fullscreen, …)
480 * \param c The client.
481 * \return The real layer.
483 static layer_t
484 client_layer_translator(client_t *c)
486 /* first deal with user set attributes */
487 if(c->ontop)
488 return LAYER_ONTOP;
489 else if(c->fullscreen)
490 return LAYER_FULLSCREEN;
491 else if(c->above)
492 return LAYER_ABOVE;
493 else if(c->below)
494 return LAYER_BELOW;
496 /* check for transient attr */
497 if(c->transient_for)
498 return LAYER_IGNORE;
500 /* then deal with windows type */
501 switch(c->type)
503 case WINDOW_TYPE_DESKTOP:
504 return LAYER_DESKTOP;
505 default:
506 break;
509 return LAYER_NORMAL;
512 /** Restack clients.
513 * \todo It might be worth stopping to restack everyone and only stack `c'
514 * relatively to the first matching in the list.
516 void
517 client_stack_refresh()
519 uint32_t config_win_vals[2];
520 layer_t layer;
522 if (!globalconf.client_need_stack_refresh)
523 return;
524 globalconf.client_need_stack_refresh = false;
526 config_win_vals[0] = XCB_NONE;
527 config_win_vals[1] = XCB_STACK_MODE_ABOVE;
529 /* stack desktop windows */
530 for(layer = LAYER_DESKTOP; layer < LAYER_BELOW; layer++)
531 foreach(node, globalconf.stack)
532 if(client_layer_translator(*node) == layer)
533 config_win_vals[0] = client_stack_above(*node,
534 config_win_vals[0]);
536 /* first stack not ontop wibox window */
537 foreach(_sb, globalconf.wiboxes)
539 wibox_t *sb = *_sb;
540 if(!sb->ontop)
542 xcb_configure_window(globalconf.connection,
543 sb->window,
544 XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE,
545 config_win_vals);
546 config_win_vals[0] = sb->window;
550 /* then stack clients */
551 for(layer = LAYER_BELOW; layer < LAYER_COUNT; layer++)
552 foreach(node, globalconf.stack)
553 if(client_layer_translator(*node) == layer)
554 config_win_vals[0] = client_stack_above(*node,
555 config_win_vals[0]);
557 /* then stack ontop wibox window */
558 foreach(_sb, globalconf.wiboxes)
560 wibox_t *sb = *_sb;
561 if(sb->ontop)
563 xcb_configure_window(globalconf.connection,
564 sb->window,
565 XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE,
566 config_win_vals);
567 config_win_vals[0] = sb->window;
572 /** Manage a new client.
573 * \param w The window.
574 * \param wgeom Window geometry.
575 * \param phys_screen Physical screen number.
576 * \param startup True if we are managing at startup time.
578 void
579 client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, int phys_screen, bool startup)
581 screen_t *screen;
582 const uint32_t select_input_val[] = { CLIENT_SELECT_INPUT_EVENT_MASK };
584 if(systray_iskdedockapp(w))
586 systray_request_handle(w, phys_screen, NULL);
587 return;
590 /* If this is a new client that just has been launched, then request its
591 * startup id. */
592 xcb_get_property_cookie_t startup_id_q = { 0 };
593 if(!startup)
594 startup_id_q = xcb_get_any_property(globalconf.connection,
595 false, w, _NET_STARTUP_ID, UINT_MAX);
597 xcb_change_window_attributes(globalconf.connection, w, XCB_CW_EVENT_MASK, select_input_val);
599 client_t *c = client_new(globalconf.L);
600 /* Push client in client list */
601 client_array_push(&globalconf.clients, luaA_object_ref(globalconf.L, -1));
604 screen = c->screen = screen_getbycoord(&globalconf.screens.tab[phys_screen],
605 wgeom->x, wgeom->y);
607 c->phys_screen = phys_screen;
609 /* consider the window banned */
610 c->isbanned = true;
612 /* Initial values */
613 c->window = w;
614 c->geometry.x = wgeom->x;
615 c->geometry.y = wgeom->y;
616 /* Border will be added later. */
617 c->geometry.width = wgeom->width;
618 c->geometry.height = wgeom->height;
619 /* Also set internal geometry (client_ban() needs it). */
620 c->geometries.internal.x = wgeom->x;
621 c->geometries.internal.y = wgeom->y;
622 c->geometries.internal.width = wgeom->width;
623 c->geometries.internal.height = wgeom->height;
625 /* Push client */
626 luaA_object_push(globalconf.L, c);
627 client_set_border_width(globalconf.L, -1, wgeom->border_width);
628 lua_pop(globalconf.L, 1);
630 /* we honor size hints by default */
631 c->size_hints_honor = true;
633 /* update hints */
634 property_update_wm_normal_hints(c, NULL);
635 property_update_wm_hints(c, NULL);
636 property_update_wm_transient_for(c, NULL);
637 property_update_wm_client_leader(c, NULL);
638 property_update_wm_client_machine(c, NULL);
639 property_update_wm_window_role(c, NULL);
640 property_update_net_wm_pid(c, NULL);
641 property_update_net_wm_icon(c, NULL);
643 /* get opacity */
644 c->opacity = window_opacity_get(c->window);
646 /* Then check clients hints */
647 ewmh_client_check_hints(c);
649 screen_client_moveto(c, screen, true);
651 /* Push client in stack */
652 client_raise(c);
654 /* update window title */
655 property_update_wm_name(c, NULL);
656 property_update_wm_icon_name(c, NULL);
657 property_update_wm_class(c, NULL);
658 property_update_wm_protocols(c, NULL);
660 /* update strut */
661 ewmh_process_client_strut(c, NULL);
663 ewmh_update_net_client_list(c->phys_screen);
665 /* Always stay in NORMAL_STATE. Even though iconified seems more
666 * appropriate sometimes. The only possible loss is that clients not using
667 * visibility events may continue to proces data (when banned).
668 * Without any exposes or other events the cost should be fairly limited though.
670 * Some clients may expect the window to be unmapped when STATE_ICONIFIED.
671 * Two conflicting parts of the ICCCM v2.0 (section 4.1.4):
673 * "Normal -> Iconic - The client should send a ClientMessage event as described later in this section."
674 * (note no explicit mention of unmapping, while Normal->Widthdrawn does mention that)
676 * "Once a client's window has left the Withdrawn state, the window will be mapped
677 * if it is in the Normal state and the window will be unmapped if it is in the Iconic state."
679 * At this stage it's just safer to keep it in normal state and avoid confusion.
681 window_state_set(c->window, XCB_WM_STATE_NORMAL);
683 if(!startup)
685 /* Request our response */
686 xcb_get_property_reply_t *reply =
687 xcb_get_property_reply(globalconf.connection, startup_id_q, NULL);
688 /* Say spawn that a client has been started, with startup id as argument */
689 char *startup_id = xutil_get_text_property_from_reply(reply);
690 p_delete(&reply);
691 spawn_start_notify(c, startup_id);
692 p_delete(&startup_id);
695 /* Call hook to notify list change */
696 if(globalconf.hooks.clients != LUA_REFNIL)
697 luaA_dofunction_from_registry(globalconf.L, globalconf.hooks.clients, 0, 0);
699 luaA_class_emit_signal(globalconf.L, &client_class, "list", 0);
701 /* call hook */
702 if(globalconf.hooks.manage != LUA_REFNIL)
704 luaA_object_push(globalconf.L, c);
705 lua_pushboolean(globalconf.L, startup);
706 luaA_dofunction_from_registry(globalconf.L, globalconf.hooks.manage, 2, 0);
709 luaA_object_push(globalconf.L, c);
710 lua_pushboolean(globalconf.L, startup);
711 luaA_class_emit_signal(globalconf.L, &client_class, "manage", 2);
714 /** Compute client geometry with respect to its geometry hints.
715 * \param c The client.
716 * \param geometry The geometry that the client might receive.
717 * \return The geometry the client must take respecting its hints.
719 area_t
720 client_geometry_hints(client_t *c, area_t geometry)
722 int32_t basew, baseh, minw, minh;
724 /* base size is substituted with min size if not specified */
725 if(c->size_hints.flags & XCB_SIZE_HINT_P_SIZE)
727 basew = c->size_hints.base_width;
728 baseh = c->size_hints.base_height;
730 else if(c->size_hints.flags & XCB_SIZE_HINT_P_MIN_SIZE)
732 basew = c->size_hints.min_width;
733 baseh = c->size_hints.min_height;
735 else
736 basew = baseh = 0;
738 /* min size is substituted with base size if not specified */
739 if(c->size_hints.flags & XCB_SIZE_HINT_P_MIN_SIZE)
741 minw = c->size_hints.min_width;
742 minh = c->size_hints.min_height;
744 else if(c->size_hints.flags & XCB_SIZE_HINT_P_SIZE)
746 minw = c->size_hints.base_width;
747 minh = c->size_hints.base_height;
749 else
750 minw = minh = 0;
752 if(c->size_hints.flags & XCB_SIZE_HINT_P_ASPECT
753 && c->size_hints.min_aspect_num > 0
754 && c->size_hints.min_aspect_den > 0
755 && geometry.height - baseh > 0
756 && geometry.width - basew > 0)
758 double dx = (double) (geometry.width - basew);
759 double dy = (double) (geometry.height - baseh);
760 double min = (double) c->size_hints.min_aspect_num / (double) c->size_hints.min_aspect_den;
761 double max = (double) c->size_hints.max_aspect_num / (double) c->size_hints.min_aspect_den;
762 double ratio = dx / dy;
763 if(max > 0 && min > 0 && ratio > 0)
765 if(ratio < min)
767 dy = (dx * min + dy) / (min * min + 1);
768 dx = dy * min;
769 geometry.width = (int) dx + basew;
770 geometry.height = (int) dy + baseh;
772 else if(ratio > max)
774 dy = (dx * min + dy) / (max * max + 1);
775 dx = dy * min;
776 geometry.width = (int) dx + basew;
777 geometry.height = (int) dy + baseh;
782 if(minw)
783 geometry.width = MAX(geometry.width, minw);
784 if(minh)
785 geometry.height = MAX(geometry.height, minh);
787 if(c->size_hints.flags & XCB_SIZE_HINT_P_MAX_SIZE)
789 if(c->size_hints.max_width)
790 geometry.width = MIN(geometry.width, c->size_hints.max_width);
791 if(c->size_hints.max_height)
792 geometry.height = MIN(geometry.height, c->size_hints.max_height);
795 if(c->size_hints.flags & (XCB_SIZE_HINT_P_RESIZE_INC | XCB_SIZE_HINT_BASE_SIZE)
796 && c->size_hints.width_inc && c->size_hints.height_inc)
798 uint16_t t1 = geometry.width, t2 = geometry.height;
799 unsigned_subtract(t1, basew);
800 unsigned_subtract(t2, baseh);
801 geometry.width -= t1 % c->size_hints.width_inc;
802 geometry.height -= t2 % c->size_hints.height_inc;
805 return geometry;
808 /** Resize client window.
809 * The sizse given as parameters are with titlebar and borders!
810 * \param c Client to resize.
811 * \param geometry New window geometry.
812 * \param hints Use size hints.
813 * \return true if an actual resize occurred.
815 bool
816 client_resize(client_t *c, area_t geometry, bool hints)
818 area_t geometry_internal;
819 area_t area;
821 /* offscreen appearance fixes */
822 area = display_area_get(c->phys_screen);
824 if(geometry.x > area.width)
825 geometry.x = area.width - geometry.width;
826 if(geometry.y > area.height)
827 geometry.y = area.height - geometry.height;
828 if(geometry.x + geometry.width < 0)
829 geometry.x = 0;
830 if(geometry.y + geometry.height < 0)
831 geometry.y = 0;
833 /* Real client geometry, please keep it contained to C code at the very least. */
834 geometry_internal = titlebar_geometry_remove(c->titlebar, c->border_width, geometry);
836 if(hints)
837 geometry_internal = client_geometry_hints(c, geometry_internal);
839 if(geometry_internal.width == 0 || geometry_internal.height == 0)
840 return false;
842 /* Also let client hints propegate to the "official" geometry. */
843 geometry = titlebar_geometry_add(c->titlebar, c->border_width, geometry_internal);
845 if(c->geometries.internal.x != geometry_internal.x
846 || c->geometries.internal.y != geometry_internal.y
847 || c->geometries.internal.width != geometry_internal.width
848 || c->geometries.internal.height != geometry_internal.height)
850 screen_t *new_screen = screen_getbycoord(c->screen,
851 geometry_internal.x, geometry_internal.y);
853 /* Values to configure a window is an array where values are
854 * stored according to 'value_mask' */
855 uint32_t values[4];
857 c->geometries.internal.x = values[0] = geometry_internal.x;
858 c->geometries.internal.y = values[1] = geometry_internal.y;
859 c->geometries.internal.width = values[2] = geometry_internal.width;
860 c->geometries.internal.height = values[3] = geometry_internal.height;
862 /* Also store geometry including border and titlebar. */
863 c->geometry = geometry;
865 titlebar_update_geometry(c);
867 /* Ignore all spurious enter/leave notify events */
868 client_ignore_enterleave_events();
870 xcb_configure_window(globalconf.connection, c->window,
871 XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y
872 | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
873 values);
875 client_restore_enterleave_events();
877 screen_client_moveto(c, new_screen, false);
879 /* execute hook */
880 hook_property(c, "geometry");
882 return true;
885 return false;
888 /** Set a client minimized, or not.
889 * \param L The Lua VM state.
890 * \param cidx The client index.
891 * \param s Set or not the client minimized.
893 void
894 client_set_minimized(lua_State *L, int cidx, bool s)
896 client_t *c = luaA_client_checkudata(L, cidx);
898 if(c->minimized != s)
900 client_need_reban(c);
901 c->minimized = s;
902 client_need_reban(c);
903 if(s)
904 window_state_set(c->window, XCB_WM_STATE_ICONIC);
905 else
906 window_state_set(c->window, XCB_WM_STATE_NORMAL);
907 ewmh_client_update_hints(c);
908 /* execute hook */
909 hook_property(c, "minimized");
910 luaA_object_emit_signal(L, cidx, "property::minimized", 0);
914 /** Set a client sticky, or not.
915 * \param L The Lua VM state.
916 * \param cidx The client index.
917 * \param s Set or not the client sticky.
919 void
920 client_set_sticky(lua_State *L, int cidx, bool s)
922 client_t *c = luaA_client_checkudata(L, cidx);
924 if(c->sticky != s)
926 client_need_reban(c);
927 c->sticky = s;
928 client_need_reban(c);
929 ewmh_client_update_hints(c);
930 hook_property(c, "sticky");
931 luaA_object_emit_signal(L, cidx, "property::sticky", 0);
935 /** Set a client fullscreen, or not.
936 * \param L The Lua VM state.
937 * \param cidx The client index.
938 * \param s Set or not the client fullscreen.
940 void
941 client_set_fullscreen(lua_State *L, int cidx, bool s)
943 client_t *c = luaA_client_checkudata(L, cidx);
945 if(c->fullscreen != s)
947 area_t geometry;
949 /* become fullscreen! */
950 if(s)
952 /* Make sure the current geometry is stored without titlebar. */
953 titlebar_ban(c->titlebar);
954 /* remove any max state */
955 client_set_maximized_horizontal(L, cidx, false);
956 client_set_maximized_vertical(L, cidx, false);
957 /* You can only be part of one of the special layers. */
958 client_set_below(L, cidx, false);
959 client_set_above(L, cidx, false);
960 client_set_ontop(L, cidx, false);
962 geometry = screen_area_get(c->screen, false);
963 c->geometries.fullscreen = c->geometry;
964 c->border_width_fs = c->border_width;
965 client_set_border_width(L, cidx, 0);
966 c->fullscreen = true;
968 else
970 geometry = c->geometries.fullscreen;
971 c->fullscreen = false;
972 client_set_border_width(L, cidx, c->border_width_fs);
974 client_resize(c, geometry, false);
975 client_stack();
976 ewmh_client_update_hints(c);
977 hook_property(c, "fullscreen");
978 luaA_object_emit_signal(L, cidx, "property::fullscreen", 0);
982 /** Set a client horizontally maximized.
983 * \param L The Lua VM state.
984 * \param cidx The client index.
985 * \param s The maximized status.
987 void
988 client_set_maximized_horizontal(lua_State *L, int cidx, bool s)
990 client_t *c = luaA_client_checkudata(L, cidx);
992 if(c->maximized_horizontal != s)
994 area_t geometry;
996 if((c->maximized_horizontal = s))
998 /* remove fullscreen mode */
999 client_set_fullscreen(L, cidx, false);
1001 geometry = screen_area_get(c->screen, true);
1002 geometry.y = c->geometry.y;
1003 geometry.height = c->geometry.height;
1004 c->geometries.max.x = c->geometry.x;
1005 c->geometries.max.width = c->geometry.width;
1007 else
1009 geometry = c->geometry;
1010 geometry.x = c->geometries.max.x;
1011 geometry.width = c->geometries.max.width;
1014 client_resize(c, geometry, c->size_hints_honor);
1015 client_stack();
1016 ewmh_client_update_hints(c);
1017 hook_property(c, "maximized_horizontal");
1018 luaA_object_emit_signal(L, cidx, "property::maximized_horizontal", 0);
1022 /** Set a client vertically maximized.
1023 * \param L The Lua VM state.
1024 * \param cidx The client index.
1025 * \param s The maximized status.
1027 void
1028 client_set_maximized_vertical(lua_State *L, int cidx, bool s)
1030 client_t *c = luaA_client_checkudata(L, cidx);
1032 if(c->maximized_vertical != s)
1034 area_t geometry;
1036 if((c->maximized_vertical = s))
1038 /* remove fullscreen mode */
1039 client_set_fullscreen(L, cidx, false);
1041 geometry = screen_area_get(c->screen, true);
1042 geometry.x = c->geometry.x;
1043 geometry.width = c->geometry.width;
1044 c->geometries.max.y = c->geometry.y;
1045 c->geometries.max.height = c->geometry.height;
1047 else
1049 geometry = c->geometry;
1050 geometry.y = c->geometries.max.y;
1051 geometry.height = c->geometries.max.height;
1054 client_resize(c, geometry, c->size_hints_honor);
1055 client_stack();
1056 ewmh_client_update_hints(c);
1057 hook_property(c, "maximized_vertical");
1058 luaA_object_emit_signal(L, cidx, "property::maximized_vertical", 0);
1062 /** Set a client above, or not.
1063 * \param L The Lua VM state.
1064 * \param cidx The client index.
1065 * \param s Set or not the client above.
1067 void
1068 client_set_above(lua_State *L, int cidx, bool s)
1070 client_t *c = luaA_client_checkudata(L, cidx);
1072 if(c->above != s)
1074 /* You can only be part of one of the special layers. */
1075 if(s)
1077 client_set_below(L, cidx, false);
1078 client_set_ontop(L, cidx, false);
1079 client_set_fullscreen(L, cidx, false);
1081 c->above = s;
1082 client_stack();
1083 ewmh_client_update_hints(c);
1084 /* execute hook */
1085 hook_property(c, "above");
1086 luaA_object_emit_signal(L, cidx, "property::above", 0);
1090 /** Set a client below, or not.
1091 * \param L The Lua VM state.
1092 * \param cidx The client index.
1093 * \param s Set or not the client below.
1095 void
1096 client_set_below(lua_State *L, int cidx, bool s)
1098 client_t *c = luaA_client_checkudata(L, cidx);
1100 if(c->below != s)
1102 /* You can only be part of one of the special layers. */
1103 if(s)
1105 client_set_above(L, cidx, false);
1106 client_set_ontop(L, cidx, false);
1107 client_set_fullscreen(L, cidx, false);
1109 c->below = s;
1110 client_stack();
1111 ewmh_client_update_hints(c);
1112 /* execute hook */
1113 hook_property(c, "below");
1114 luaA_object_emit_signal(L, cidx, "property::below", 0);
1118 /** Set a client modal, or not.
1119 * \param L The Lua VM state.
1120 * \param cidx The client index.
1121 * \param s Set or not the client modal attribute.
1123 void
1124 client_set_modal(lua_State *L, int cidx, bool s)
1126 client_t *c = luaA_client_checkudata(L, cidx);
1128 if(c->modal != s)
1130 c->modal = s;
1131 client_stack();
1132 ewmh_client_update_hints(c);
1133 /* execute hook */
1134 hook_property(c, "modal");
1135 luaA_object_emit_signal(L, cidx, "property::modal", 0);
1139 /** Set a client ontop, or not.
1140 * \param L The Lua VM state.
1141 * \param cidx The client index.
1142 * \param s Set or not the client ontop attribute.
1144 void
1145 client_set_ontop(lua_State *L, int cidx, bool s)
1147 client_t *c = luaA_client_checkudata(L, cidx);
1149 if(c->ontop != s)
1151 /* You can only be part of one of the special layers. */
1152 if(s)
1154 client_set_above(L, cidx, false);
1155 client_set_below(L, cidx, false);
1156 client_set_fullscreen(L, cidx, false);
1158 c->ontop = s;
1159 client_stack();
1160 /* execute hook */
1161 hook_property(c, "ontop");
1162 luaA_object_emit_signal(L, cidx, "property::ontop", 0);
1166 /** Set a client skip taskbar attribute.
1167 * \param L Tha Lua VM state.
1168 * \param cidx The client index.
1169 * \param s Set or not the client skip taskbar attribute.
1171 void
1172 client_set_skip_taskbar(lua_State *L, int cidx, bool s)
1174 client_t *c = luaA_client_checkudata(L, cidx);
1176 if(c->skip_taskbar != s)
1178 c->skip_taskbar = s;
1179 ewmh_client_update_hints(c);
1180 luaA_object_emit_signal(L, cidx, "property::skip_taskbar", 0);
1184 /** Unban a client and move it back into the viewport.
1185 * \param c The client.
1187 void
1188 client_unban(client_t *c)
1190 if(c->isbanned)
1192 xcb_map_window(globalconf.connection, c->window);
1194 c->isbanned = false;
1198 /** Unmanage a client.
1199 * \param c The client.
1201 void
1202 client_unmanage(client_t *c)
1204 tag_array_t *tags = &c->screen->tags;
1206 /* Reset transient_for attributes of widows that maybe refering to us */
1207 foreach(_tc, globalconf.clients)
1209 client_t *tc = *_tc;
1210 if(tc->transient_for == c)
1211 tc->transient_for = NULL;
1214 if(globalconf.screens.tab[c->phys_screen].prev_client_focus == c)
1215 globalconf.screens.tab[c->phys_screen].prev_client_focus = NULL;
1217 if(globalconf.screens.tab[c->phys_screen].client_focus == c)
1218 client_unfocus(c);
1220 /* remove client from global list and everywhere else */
1221 foreach(elem, globalconf.clients)
1222 if(*elem == c)
1224 client_array_remove(&globalconf.clients, elem);
1225 break;
1227 stack_client_remove(c);
1228 for(int i = 0; i < tags->len; i++)
1229 untag_client(c, tags->tab[i]);
1231 /* call hook */
1232 if(globalconf.hooks.unmanage != LUA_REFNIL)
1234 luaA_object_push(globalconf.L, c);
1235 luaA_dofunction_from_registry(globalconf.L, globalconf.hooks.unmanage, 1, 0);
1238 luaA_object_push(globalconf.L, c);
1239 luaA_class_emit_signal(globalconf.L, &client_class, "unmanage", 1);
1241 /* Call hook to notify list change */
1242 if(globalconf.hooks.clients != LUA_REFNIL)
1243 luaA_dofunction_from_registry(globalconf.L, globalconf.hooks.clients, 0, 0);
1245 luaA_class_emit_signal(globalconf.L, &client_class, "list", 0);
1247 window_state_set(c->window, XCB_WM_STATE_WITHDRAWN);
1249 titlebar_client_detach(c);
1251 ewmh_update_net_client_list(c->phys_screen);
1253 /* set client as invalid */
1254 c->invalid = true;
1256 luaA_object_unref(globalconf.L, c);
1259 /** Kill a client via a WM_DELETE_WINDOW request or KillClient if not
1260 * supported.
1261 * \param c The client to kill.
1263 void
1264 client_kill(client_t *c)
1266 if(client_hasproto(c, WM_DELETE_WINDOW))
1268 xcb_client_message_event_t ev;
1270 /* Initialize all of event's fields first */
1271 p_clear(&ev, 1);
1273 ev.response_type = XCB_CLIENT_MESSAGE;
1274 ev.window = c->window;
1275 ev.format = 32;
1276 ev.data.data32[1] = XCB_CURRENT_TIME;
1277 ev.type = WM_PROTOCOLS;
1278 ev.data.data32[0] = WM_DELETE_WINDOW;
1280 xcb_send_event(globalconf.connection, false, c->window,
1281 XCB_EVENT_MASK_NO_EVENT, (char *) &ev);
1283 else
1284 xcb_kill_client(globalconf.connection, c->window);
1287 /** Get all clients into a table.
1288 * \param L The Lua VM state.
1289 * \return The number of elements pushed on stack.
1290 * \luastack
1291 * \lparam An optional screen nunmber.
1292 * \lreturn A table with all clients.
1294 static int
1295 luaA_client_get(lua_State *L)
1297 int i = 1, screen;
1299 screen = luaL_optnumber(L, 1, 0) - 1;
1301 lua_newtable(L);
1303 if(screen == -1)
1304 foreach(c, globalconf.clients)
1306 luaA_object_push(L, *c);
1307 lua_rawseti(L, -2, i++);
1309 else
1311 luaA_checkscreen(screen);
1312 foreach(c, globalconf.clients)
1313 if((*c)->screen == &globalconf.screens.tab[screen])
1315 luaA_object_push(L, *c);
1316 lua_rawseti(L, -2, i++);
1320 return 1;
1323 /** Check if a client is visible on its screen.
1324 * \param L The Lua VM state.
1325 * \return The number of elements pushed on stack.
1326 * \luastack
1327 * \lvalue A client.
1328 * \lreturn A boolean value, true if the client is visible, false otherwise.
1330 static int
1331 luaA_client_isvisible(lua_State *L)
1333 client_t *c = luaA_client_checkudata(L, 1);
1334 lua_pushboolean(L, client_isvisible(c, c->screen));
1335 return 1;
1338 /** Set client border width.
1339 * \param L The Lua VM state.
1340 * \param cidx The client index.
1341 * \param width The border width.
1343 void
1344 client_set_border_width(lua_State *L, int cidx, int width)
1346 client_t *c = luaA_client_checkudata(L, cidx);
1347 uint32_t w = width;
1349 if(width > 0 && (c->type == WINDOW_TYPE_DOCK
1350 || c->type == WINDOW_TYPE_SPLASH
1351 || c->type == WINDOW_TYPE_DESKTOP
1352 || c->fullscreen))
1353 return;
1355 if(width == c->border_width || width < 0)
1356 return;
1358 /* disallow change of border width if the client is fullscreen */
1359 if(c->fullscreen)
1360 return;
1362 /* Update geometry with the new border. */
1363 c->geometry.width -= 2 * c->border_width;
1364 c->geometry.height -= 2 * c->border_width;
1366 c->border_width = width;
1367 xcb_configure_window(globalconf.connection, c->window,
1368 XCB_CONFIG_WINDOW_BORDER_WIDTH, &w);
1370 c->geometry.width += 2 * c->border_width;
1371 c->geometry.height += 2 * c->border_width;
1373 /* Changing border size also affects the size of the titlebar. */
1374 titlebar_update_geometry(c);
1376 hook_property(c, "border_width");
1377 luaA_object_emit_signal(L, cidx, "property::border_width", 0);
1380 /** Set a client icon.
1381 * \param L The Lua VM state.
1382 * \param cidx The client index on the stack.
1383 * \para iidx The image index on the stack.
1385 void
1386 client_set_icon(lua_State *L, int cidx, int iidx)
1388 client_t *c = luaA_client_checkudata(L, cidx);
1389 /* convert index to absolute */
1390 cidx = luaA_absindex(L, cidx);
1391 iidx = luaA_absindex(L, iidx);
1392 luaA_checkudata(L, iidx, &image_class);
1393 luaA_object_unref_item(L, cidx, c->icon);
1394 c->icon = luaA_object_ref_item(L, cidx, iidx);
1395 luaA_object_emit_signal(L, cidx < iidx ? cidx : cidx - 1, "property::icon", 0);
1396 /* execute hook */
1397 hook_property(c, "icon");
1400 /** Kill a client.
1401 * \param L The Lua VM state.
1403 * \luastack
1404 * \lvalue A client.
1406 static int
1407 luaA_client_kill(lua_State *L)
1409 client_t *c = luaA_client_checkudata(L, 1);
1410 client_kill(c);
1411 return 0;
1414 /** Swap a client with another one.
1415 * \param L The Lua VM state.
1416 * \luastack
1417 * \lvalue A client.
1418 * \lparam A client to swap with.
1420 static int
1421 luaA_client_swap(lua_State *L)
1423 client_t *c = luaA_client_checkudata(L, 1);
1424 client_t *swap = luaA_client_checkudata(L, 2);
1426 if(c != swap)
1428 client_t **ref_c = NULL, **ref_swap = NULL;
1429 foreach(item, globalconf.clients)
1431 if(*item == c)
1432 ref_c = item;
1433 else if(*item == swap)
1434 ref_swap = item;
1435 if(ref_c && ref_swap)
1436 break;
1438 /* swap ! */
1439 *ref_c = swap;
1440 *ref_swap = c;
1442 /* Call hook to notify list change */
1443 if(globalconf.hooks.clients != LUA_REFNIL)
1444 luaA_dofunction_from_registry(L, globalconf.hooks.clients, 0, 0);
1446 luaA_class_emit_signal(globalconf.L, &client_class, "list", 0);
1449 return 0;
1452 /** Access or set the client tags.
1453 * \param L The Lua VM state.
1454 * \return The number of elements pushed on stack.
1455 * \lparam A table with tags to set, or none to get the current tags table.
1456 * \return The clients tag.
1458 static int
1459 luaA_client_tags(lua_State *L)
1461 client_t *c = luaA_client_checkudata(L, 1);
1462 tag_array_t *tags = &c->screen->tags;
1463 int j = 0;
1465 if(lua_gettop(L) == 2)
1467 luaA_checktable(L, 2);
1468 for(int i = 0; i < tags->len; i++)
1469 untag_client(c, tags->tab[i]);
1470 lua_pushnil(L);
1471 while(lua_next(L, 2))
1472 tag_client(c);
1473 lua_pop(L, 1);
1476 lua_newtable(L);
1477 foreach(tag, *tags)
1478 if(is_client_tagged(c, *tag))
1480 luaA_object_push(L, *tag);
1481 lua_rawseti(L, -2, ++j);
1484 return 1;
1487 /** Raise a client on top of others which are on the same layer.
1488 * \param L The Lua VM state.
1489 * \luastack
1490 * \lvalue A client.
1492 static int
1493 luaA_client_raise(lua_State *L)
1495 client_t *c = luaA_client_checkudata(L, 1);
1496 client_raise(c);
1497 return 0;
1500 /** Lower a client on bottom of others which are on the same layer.
1501 * \param L The Lua VM state.
1502 * \luastack
1503 * \lvalue A client.
1505 static int
1506 luaA_client_lower(lua_State *L)
1508 client_t *c = luaA_client_checkudata(L, 1);
1509 client_lower(c);
1510 return 0;
1513 /** Redraw a client by unmapping and mapping it quickly.
1514 * \param L The Lua VM state.
1516 * \luastack
1517 * \lvalue A client.
1519 static int
1520 luaA_client_redraw(lua_State *L)
1522 client_t *c = luaA_client_checkudata(L, 1);
1524 xcb_unmap_window(globalconf.connection, c->window);
1525 xcb_map_window(globalconf.connection, c->window);
1527 /* Set the focus on the current window if the redraw has been
1528 performed on the window where the pointer is currently on
1529 because after the unmapping/mapping, the focus is lost */
1530 if(globalconf.screen_focus->client_focus == c)
1532 client_unfocus(c);
1533 client_focus(c);
1536 return 0;
1539 /** Stop managing a client.
1540 * \param L The Lua VM state.
1541 * \return The number of elements pushed on stack.
1542 * \luastack
1543 * \lvalue A client.
1545 static int
1546 luaA_client_unmanage(lua_State *L)
1548 client_t *c = luaA_client_checkudata(L, 1);
1549 client_unmanage(c);
1550 return 0;
1553 /** Return client geometry.
1554 * \param L The Lua VM state.
1555 * \return The number of elements pushed on stack.
1556 * \luastack
1557 * \lparam A table with new coordinates, or none.
1558 * \lreturn A table with client coordinates.
1560 static int
1561 luaA_client_geometry(lua_State *L)
1563 client_t *c = luaA_client_checkudata(L, 1);
1565 if(lua_gettop(L) == 2)
1567 area_t geometry;
1569 luaA_checktable(L, 2);
1570 geometry.x = luaA_getopt_number(L, 2, "x", c->geometry.x);
1571 geometry.y = luaA_getopt_number(L, 2, "y", c->geometry.y);
1572 if(client_isfixed(c))
1574 geometry.width = c->geometry.width;
1575 geometry.height = c->geometry.height;
1577 else
1579 geometry.width = luaA_getopt_number(L, 2, "width", c->geometry.width);
1580 geometry.height = luaA_getopt_number(L, 2, "height", c->geometry.height);
1583 client_resize(c, geometry, c->size_hints_honor);
1586 return luaA_pusharea(L, c->geometry);
1589 /** Return client struts (reserved space at the edge of the screen).
1590 * \param L The Lua VM state.
1591 * \return The number of elements pushed on stack.
1592 * \luastack
1593 * \lparam A table with new strut values, or none.
1594 * \lreturn A table with strut values.
1596 static int
1597 luaA_client_struts(lua_State *L)
1599 client_t *c = luaA_client_checkudata(L, 1);
1601 if(lua_gettop(L) == 2)
1603 luaA_tostrut(L, 2, &c->strut);
1604 ewmh_update_strut(c->window, &c->strut);
1605 hook_property(c, "struts");
1606 luaA_object_emit_signal(L, 1, "property::struts", 0);
1607 screen_emit_signal(L, c->screen, "property::workarea", 0);
1610 return luaA_pushstrut(L, c->strut);
1613 static int
1614 luaA_client_set_screen(lua_State *L, client_t *c)
1616 if(globalconf.xinerama_is_active)
1618 int screen = luaL_checknumber(L, -1) - 1;
1619 luaA_checkscreen(screen);
1620 screen_client_moveto(c, &globalconf.screens.tab[screen], true);
1622 return 0;
1625 static int
1626 luaA_client_set_hidden(lua_State *L, client_t *c)
1628 bool b = luaA_checkboolean(L, -1);
1629 if(b != c->hidden)
1631 client_need_reban(c);
1632 c->hidden = b;
1633 client_need_reban(c);
1634 hook_property(c, "hidden");
1635 luaA_object_emit_signal(L, -3, "property::hidden", 0);
1637 return 0;
1640 static int
1641 luaA_client_set_minimized(lua_State *L, client_t *c)
1643 client_set_minimized(L, -3, luaA_checkboolean(L, -1));
1644 return 0;
1647 static int
1648 luaA_client_set_fullscreen(lua_State *L, client_t *c)
1650 client_set_fullscreen(L, -3, luaA_checkboolean(L, -1));
1651 return 0;
1654 static int
1655 luaA_client_set_modal(lua_State *L, client_t *c)
1657 client_set_modal(L, -3, luaA_checkboolean(L, -1));
1658 return 0;
1661 static int
1662 luaA_client_set_maximized_horizontal(lua_State *L, client_t *c)
1664 client_set_maximized_horizontal(L, -3, luaA_checkboolean(L, -1));
1665 return 0;
1668 static int
1669 luaA_client_set_maximized_vertical(lua_State *L, client_t *c)
1671 client_set_maximized_vertical(L, -3, luaA_checkboolean(L, -1));
1672 return 0;
1675 static int
1676 luaA_client_set_icon(lua_State *L, client_t *c)
1678 client_set_icon(L, -3, -1);
1679 return 0;
1682 static int
1683 luaA_client_set_opacity(lua_State *L, client_t *c)
1685 if(lua_isnil(L, -1))
1686 client_set_opacity(L, -3, -1);
1687 else
1688 client_set_opacity(L, -3, luaL_checknumber(L, -1));
1689 return 0;
1692 static int
1693 luaA_client_set_sticky(lua_State *L, client_t *c)
1695 client_set_sticky(L, -3, luaA_checkboolean(L, -1));
1696 return 0;
1699 static int
1700 luaA_client_set_size_hints_honor(lua_State *L, client_t *c)
1702 c->size_hints_honor = luaA_checkboolean(L, -1);
1703 hook_property(c, "size_hints_honor");
1704 luaA_object_emit_signal(L, -3, "property::size_hints_honor", 0);
1705 return 0;
1708 static int
1709 luaA_client_set_border_width(lua_State *L, client_t *c)
1711 client_set_border_width(L, -3, luaL_checknumber(L, -1));
1712 return 0;
1715 static int
1716 luaA_client_set_ontop(lua_State *L, client_t *c)
1718 client_set_ontop(L, -3, luaA_checkboolean(L, -1));
1719 return 0;
1722 static int
1723 luaA_client_set_below(lua_State *L, client_t *c)
1725 client_set_below(L, -3, luaA_checkboolean(L, -1));
1726 return 0;
1729 static int
1730 luaA_client_set_above(lua_State *L, client_t *c)
1732 client_set_above(L, -3, luaA_checkboolean(L, -1));
1733 return 0;
1736 static int
1737 luaA_client_set_urgent(lua_State *L, client_t *c)
1739 client_set_urgent(L, -3, luaA_checkboolean(L, -1));
1740 return 0;
1743 static int
1744 luaA_client_set_border_color(lua_State *L, client_t *c)
1746 size_t len;
1747 const char *buf;
1748 if((buf = luaL_checklstring(L, -1, &len))
1749 && xcolor_init_reply(xcolor_init_unchecked(&c->border_color, buf, len)))
1751 xcb_change_window_attributes(globalconf.connection, c->window,
1752 XCB_CW_BORDER_PIXEL, &c->border_color.pixel);
1753 luaA_object_emit_signal(L, -3, "property::border_color", 0);
1755 return 0;
1758 static int
1759 luaA_client_set_titlebar(lua_State *L, client_t *c)
1761 if(lua_isnil(L, -1))
1762 titlebar_client_detach(c);
1763 else
1764 titlebar_client_attach(c);
1765 return 0;
1768 static int
1769 luaA_client_set_skip_taskbar(lua_State *L, client_t *c)
1771 client_set_skip_taskbar(L, -3, luaA_checkboolean(L, -1));
1772 return 0;
1775 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, name, lua_pushstring)
1776 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, icon_name, lua_pushstring)
1777 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, class, lua_pushstring)
1778 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, instance, lua_pushstring)
1779 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, machine, lua_pushstring)
1780 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, role, lua_pushstring)
1781 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, transient_for, luaA_object_push)
1782 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, skip_taskbar, lua_pushboolean)
1783 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, window, lua_pushnumber)
1784 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, leader_window, lua_pushnumber)
1785 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, group_window, lua_pushnumber)
1786 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, pid, lua_pushnumber)
1787 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, hidden, lua_pushboolean)
1788 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, minimized, lua_pushboolean)
1789 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, fullscreen, lua_pushboolean)
1790 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, modal, lua_pushboolean)
1791 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, ontop, lua_pushboolean)
1792 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, urgent, lua_pushboolean)
1793 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, above, lua_pushboolean)
1794 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, below, lua_pushboolean)
1795 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, sticky, lua_pushboolean)
1796 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, size_hints_honor, lua_pushboolean)
1797 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, maximized_horizontal, lua_pushboolean)
1798 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, maximized_vertical, lua_pushboolean)
1799 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, opacity, lua_pushnumber)
1800 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, border_width, lua_pushnumber)
1801 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, border_color, luaA_pushxcolor)
1803 static int
1804 luaA_client_get_content(lua_State *L, client_t *c)
1806 xcb_image_t *ximage = xcb_image_get(globalconf.connection,
1807 c->window,
1808 0, 0,
1809 c->geometries.internal.width,
1810 c->geometries.internal.height,
1811 ~0, XCB_IMAGE_FORMAT_Z_PIXMAP);
1812 int retval = 0;
1814 if(ximage)
1816 if(ximage->bpp >= 24)
1818 uint32_t *data = p_alloca(uint32_t, ximage->width * ximage->height);
1820 for(int y = 0; y < ximage->height; y++)
1821 for(int x = 0; x < ximage->width; x++)
1823 data[y * ximage->width + x] = xcb_image_get_pixel(ximage, x, y);
1824 data[y * ximage->width + x] |= 0xff000000; /* set alpha to 0xff */
1827 retval = image_new_from_argb32(ximage->width, ximage->height, data);
1829 xcb_image_destroy(ximage);
1832 return retval;
1835 static int
1836 luaA_client_get_type(lua_State *L, client_t *c)
1838 switch(c->type)
1840 case WINDOW_TYPE_DESKTOP:
1841 lua_pushliteral(L, "desktop");
1842 break;
1843 case WINDOW_TYPE_DOCK:
1844 lua_pushliteral(L, "dock");
1845 break;
1846 case WINDOW_TYPE_SPLASH:
1847 lua_pushliteral(L, "splash");
1848 break;
1849 case WINDOW_TYPE_DIALOG:
1850 lua_pushliteral(L, "dialog");
1851 break;
1852 case WINDOW_TYPE_MENU:
1853 lua_pushliteral(L, "menu");
1854 break;
1855 case WINDOW_TYPE_TOOLBAR:
1856 lua_pushliteral(L, "toolbar");
1857 break;
1858 case WINDOW_TYPE_UTILITY:
1859 lua_pushliteral(L, "utility");
1860 break;
1861 case WINDOW_TYPE_DROPDOWN_MENU:
1862 lua_pushliteral(L, "dropdown_menu");
1863 break;
1864 case WINDOW_TYPE_POPUP_MENU:
1865 lua_pushliteral(L, "popup_menu");
1866 break;
1867 case WINDOW_TYPE_TOOLTIP:
1868 lua_pushliteral(L, "tooltip");
1869 break;
1870 case WINDOW_TYPE_NOTIFICATION:
1871 lua_pushliteral(L, "notification");
1872 break;
1873 case WINDOW_TYPE_COMBO:
1874 lua_pushliteral(L, "combo");
1875 break;
1876 case WINDOW_TYPE_DND:
1877 lua_pushliteral(L, "dnd");
1878 break;
1879 case WINDOW_TYPE_NORMAL:
1880 lua_pushliteral(L, "normal");
1881 break;
1883 return 1;
1886 static int
1887 luaA_client_get_screen(lua_State *L, client_t *c)
1889 lua_pushnumber(L, 1 + screen_array_indexof(&globalconf.screens, c->screen));
1890 return 1;
1893 static int
1894 luaA_client_get_icon(lua_State *L, client_t *c)
1896 return luaA_object_push_item(L, -2, c->icon);
1899 static int
1900 luaA_client_get_titlebar(lua_State *L, client_t *c)
1902 return luaA_object_push(L, c->titlebar);
1905 static int
1906 luaA_client_get_size_hints(lua_State *L, client_t *c)
1908 const char *u_or_p = NULL;
1910 lua_createtable(L, 0, 1);
1912 if(c->size_hints.flags & XCB_SIZE_HINT_US_POSITION)
1913 u_or_p = "user_position";
1914 else if(c->size_hints.flags & XCB_SIZE_HINT_P_POSITION)
1915 u_or_p = "program_position";
1917 if(u_or_p)
1919 lua_createtable(L, 0, 2);
1920 lua_pushnumber(L, c->size_hints.x);
1921 lua_setfield(L, -2, "x");
1922 lua_pushnumber(L, c->size_hints.y);
1923 lua_setfield(L, -2, "y");
1924 lua_setfield(L, -2, u_or_p);
1925 u_or_p = NULL;
1928 if(c->size_hints.flags & XCB_SIZE_HINT_US_SIZE)
1929 u_or_p = "user_size";
1930 else if(c->size_hints.flags & XCB_SIZE_HINT_P_SIZE)
1931 u_or_p = "program_size";
1933 if(u_or_p)
1935 lua_createtable(L, 0, 2);
1936 lua_pushnumber(L, c->size_hints.width);
1937 lua_setfield(L, -2, "width");
1938 lua_pushnumber(L, c->size_hints.height);
1939 lua_setfield(L, -2, "height");
1940 lua_setfield(L, -2, u_or_p);
1943 if(c->size_hints.flags & XCB_SIZE_HINT_P_MIN_SIZE)
1945 lua_pushnumber(L, c->size_hints.min_width);
1946 lua_setfield(L, -2, "min_width");
1947 lua_pushnumber(L, c->size_hints.min_height);
1948 lua_setfield(L, -2, "min_height");
1951 if(c->size_hints.flags & XCB_SIZE_HINT_P_MAX_SIZE)
1953 lua_pushnumber(L, c->size_hints.max_width);
1954 lua_setfield(L, -2, "max_width");
1955 lua_pushnumber(L, c->size_hints.max_height);
1956 lua_setfield(L, -2, "max_height");
1959 if(c->size_hints.flags & XCB_SIZE_HINT_P_RESIZE_INC)
1961 lua_pushnumber(L, c->size_hints.width_inc);
1962 lua_setfield(L, -2, "width_inc");
1963 lua_pushnumber(L, c->size_hints.height_inc);
1964 lua_setfield(L, -2, "height_inc");
1967 if(c->size_hints.flags & XCB_SIZE_HINT_P_ASPECT)
1969 lua_pushnumber(L, c->size_hints.min_aspect_num);
1970 lua_setfield(L, -2, "min_aspect_num");
1971 lua_pushnumber(L, c->size_hints.min_aspect_den);
1972 lua_setfield(L, -2, "min_aspect_den");
1973 lua_pushnumber(L, c->size_hints.max_aspect_num);
1974 lua_setfield(L, -2, "max_aspect_num");
1975 lua_pushnumber(L, c->size_hints.max_aspect_den);
1976 lua_setfield(L, -2, "max_aspect_den");
1979 if(c->size_hints.flags & XCB_SIZE_HINT_BASE_SIZE)
1981 lua_pushnumber(L, c->size_hints.base_width);
1982 lua_setfield(L, -2, "base_width");
1983 lua_pushnumber(L, c->size_hints.base_height);
1984 lua_setfield(L, -2, "base_height");
1987 if(c->size_hints.flags & XCB_SIZE_HINT_P_WIN_GRAVITY)
1989 switch(c->size_hints.win_gravity)
1991 default:
1992 lua_pushliteral(L, "north_west");
1993 break;
1994 case XCB_GRAVITY_NORTH:
1995 lua_pushliteral(L, "north");
1996 break;
1997 case XCB_GRAVITY_NORTH_EAST:
1998 lua_pushliteral(L, "north_east");
1999 break;
2000 case XCB_GRAVITY_WEST:
2001 lua_pushliteral(L, "west");
2002 break;
2003 case XCB_GRAVITY_CENTER:
2004 lua_pushliteral(L, "center");
2005 break;
2006 case XCB_GRAVITY_EAST:
2007 lua_pushliteral(L, "east");
2008 break;
2009 case XCB_GRAVITY_SOUTH_WEST:
2010 lua_pushliteral(L, "south_west");
2011 break;
2012 case XCB_GRAVITY_SOUTH:
2013 lua_pushliteral(L, "south");
2014 break;
2015 case XCB_GRAVITY_SOUTH_EAST:
2016 lua_pushliteral(L, "south_east");
2017 break;
2018 case XCB_GRAVITY_STATIC:
2019 lua_pushliteral(L, "static");
2020 break;
2022 lua_setfield(L, -2, "win_gravity");
2025 return 1;
2028 /** Get or set mouse buttons bindings for a client.
2029 * \param L The Lua VM state.
2030 * \return The number of element pushed on stack.
2031 * \luastack
2032 * \lvalue A client.
2033 * \lparam An array of mouse button bindings objects, or nothing.
2034 * \return The array of mouse button bindings objects of this client.
2036 static int
2037 luaA_client_buttons(lua_State *L)
2039 client_t *client = luaA_client_checkudata(L, 1);
2040 button_array_t *buttons = &client->buttons;
2042 if(lua_gettop(L) == 2)
2044 luaA_button_array_set(L, 1, 2, buttons);
2045 luaA_object_emit_signal(L, 1, "property::buttons", 0);
2046 window_buttons_grab(client->window, &client->buttons);
2049 return luaA_button_array_get(L, 1, buttons);
2052 /** Get or set keys bindings for a client.
2053 * \param L The Lua VM state.
2054 * \return The number of element pushed on stack.
2055 * \luastack
2056 * \lvalue A client.
2057 * \lparam An array of key bindings objects, or nothing.
2058 * \return The array of key bindings objects of this client.
2060 static int
2061 luaA_client_keys(lua_State *L)
2063 client_t *c = luaA_client_checkudata(L, 1);
2064 key_array_t *keys = &c->keys;
2066 if(lua_gettop(L) == 2)
2068 luaA_key_array_set(L, 1, 2, keys);
2069 luaA_object_emit_signal(L, 1, "property::keys", 0);
2070 xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, c->window, XCB_BUTTON_MASK_ANY);
2071 window_grabkeys(c->window, keys);
2074 return luaA_key_array_get(L, 1, keys);
2077 /* Client module.
2078 * \param L The Lua VM state.
2079 * \return The number of pushed elements.
2081 static int
2082 luaA_client_module_index(lua_State *L)
2084 size_t len;
2085 const char *buf = luaL_checklstring(L, 2, &len);
2087 switch(a_tokenize(buf, len))
2089 case A_TK_FOCUS:
2090 return luaA_object_push(globalconf.L, globalconf.screen_focus->client_focus);
2091 break;
2092 default:
2093 return 0;
2097 /* Client module new index.
2098 * \param L The Lua VM state.
2099 * \return The number of pushed elements.
2101 static int
2102 luaA_client_module_newindex(lua_State *L)
2104 size_t len;
2105 const char *buf = luaL_checklstring(L, 2, &len);
2106 client_t *c;
2108 switch(a_tokenize(buf, len))
2110 case A_TK_FOCUS:
2111 c = luaA_client_checkudata(L, 3);
2112 client_focus(c);
2113 break;
2114 default:
2115 break;
2118 return 0;
2121 void
2122 client_class_setup(lua_State *L)
2124 static const struct luaL_reg client_methods[] =
2126 LUA_CLASS_METHODS(client)
2127 { "get", luaA_client_get },
2128 { "__index", luaA_client_module_index },
2129 { "__newindex", luaA_client_module_newindex },
2130 { NULL, NULL }
2133 static const struct luaL_reg client_meta[] =
2135 LUA_OBJECT_META(client)
2136 LUA_CLASS_META
2137 { "buttons", luaA_client_buttons },
2138 { "keys", luaA_client_keys },
2139 { "isvisible", luaA_client_isvisible },
2140 { "geometry", luaA_client_geometry },
2141 { "struts", luaA_client_struts },
2142 { "tags", luaA_client_tags },
2143 { "kill", luaA_client_kill },
2144 { "swap", luaA_client_swap },
2145 { "raise", luaA_client_raise },
2146 { "lower", luaA_client_lower },
2147 { "redraw", luaA_client_redraw },
2148 { "unmanage", luaA_client_unmanage },
2149 { "__gc", luaA_client_gc },
2150 { NULL, NULL }
2153 luaA_class_setup(L, &client_class, "client", (lua_class_allocator_t) client_new,
2154 luaA_class_index_miss_property, luaA_class_newindex_miss_property,
2155 client_methods, client_meta);
2156 luaA_class_add_property(&client_class, A_TK_NAME,
2157 NULL,
2158 (lua_class_propfunc_t) luaA_client_get_name,
2159 NULL);
2160 luaA_class_add_property(&client_class, A_TK_TRANSIENT_FOR,
2161 NULL,
2162 (lua_class_propfunc_t) luaA_client_get_transient_for,
2163 NULL);
2164 luaA_class_add_property(&client_class, A_TK_SKIP_TASKBAR,
2165 (lua_class_propfunc_t) luaA_client_set_skip_taskbar,
2166 (lua_class_propfunc_t) luaA_client_get_skip_taskbar,
2167 (lua_class_propfunc_t) luaA_client_set_skip_taskbar);
2168 luaA_class_add_property(&client_class, A_TK_CONTENT,
2169 NULL,
2170 (lua_class_propfunc_t) luaA_client_get_content,
2171 NULL);
2172 luaA_class_add_property(&client_class, A_TK_TYPE,
2173 NULL,
2174 (lua_class_propfunc_t) luaA_client_get_type,
2175 NULL);
2176 luaA_class_add_property(&client_class, A_TK_CLASS,
2177 NULL,
2178 (lua_class_propfunc_t) luaA_client_get_class,
2179 NULL);
2180 luaA_class_add_property(&client_class, A_TK_INSTANCE,
2181 NULL,
2182 (lua_class_propfunc_t) luaA_client_get_instance,
2183 NULL);
2184 luaA_class_add_property(&client_class, A_TK_ROLE,
2185 NULL,
2186 (lua_class_propfunc_t) luaA_client_get_role,
2187 NULL);
2188 luaA_class_add_property(&client_class, A_TK_PID,
2189 NULL,
2190 (lua_class_propfunc_t) luaA_client_get_pid,
2191 NULL);
2192 luaA_class_add_property(&client_class, A_TK_WINDOW,
2193 NULL,
2194 (lua_class_propfunc_t) luaA_client_get_window,
2195 NULL);
2196 luaA_class_add_property(&client_class, A_TK_LEADER_WINDOW,
2197 NULL,
2198 (lua_class_propfunc_t) luaA_client_get_leader_window,
2199 NULL);
2200 luaA_class_add_property(&client_class, A_TK_MACHINE,
2201 NULL,
2202 (lua_class_propfunc_t) luaA_client_get_machine,
2203 NULL);
2204 luaA_class_add_property(&client_class, A_TK_ICON_NAME,
2205 NULL,
2206 (lua_class_propfunc_t) luaA_client_get_icon_name,
2207 NULL);
2208 luaA_class_add_property(&client_class, A_TK_SCREEN,
2209 NULL,
2210 (lua_class_propfunc_t) luaA_client_get_screen,
2211 (lua_class_propfunc_t) luaA_client_set_screen);
2212 luaA_class_add_property(&client_class, A_TK_HIDDEN,
2213 (lua_class_propfunc_t) luaA_client_set_hidden,
2214 (lua_class_propfunc_t) luaA_client_get_hidden,
2215 (lua_class_propfunc_t) luaA_client_set_hidden);
2216 luaA_class_add_property(&client_class, A_TK_MINIMIZED,
2217 (lua_class_propfunc_t) luaA_client_set_minimized,
2218 (lua_class_propfunc_t) luaA_client_get_minimized,
2219 (lua_class_propfunc_t) luaA_client_set_minimized);
2220 luaA_class_add_property(&client_class, A_TK_FULLSCREEN,
2221 (lua_class_propfunc_t) luaA_client_set_fullscreen,
2222 (lua_class_propfunc_t) luaA_client_get_fullscreen,
2223 (lua_class_propfunc_t) luaA_client_set_fullscreen);
2224 luaA_class_add_property(&client_class, A_TK_MODAL,
2225 (lua_class_propfunc_t) luaA_client_set_modal,
2226 (lua_class_propfunc_t) luaA_client_get_modal,
2227 (lua_class_propfunc_t) luaA_client_set_modal);
2228 luaA_class_add_property(&client_class, A_TK_GROUP_WINDOW,
2229 NULL,
2230 (lua_class_propfunc_t) luaA_client_get_group_window,
2231 NULL);
2232 luaA_class_add_property(&client_class, A_TK_MAXIMIZED_HORIZONTAL,
2233 (lua_class_propfunc_t) luaA_client_set_maximized_horizontal,
2234 (lua_class_propfunc_t) luaA_client_get_maximized_horizontal,
2235 (lua_class_propfunc_t) luaA_client_set_maximized_horizontal);
2236 luaA_class_add_property(&client_class, A_TK_MAXIMIZED_VERTICAL,
2237 (lua_class_propfunc_t) luaA_client_set_maximized_vertical,
2238 (lua_class_propfunc_t) luaA_client_get_maximized_vertical,
2239 (lua_class_propfunc_t) luaA_client_set_maximized_vertical);
2240 luaA_class_add_property(&client_class, A_TK_ICON,
2241 (lua_class_propfunc_t) luaA_client_set_icon,
2242 (lua_class_propfunc_t) luaA_client_get_icon,
2243 (lua_class_propfunc_t) luaA_client_set_icon);
2244 luaA_class_add_property(&client_class, A_TK_OPACITY,
2245 (lua_class_propfunc_t) luaA_client_set_opacity,
2246 (lua_class_propfunc_t) luaA_client_get_opacity,
2247 (lua_class_propfunc_t) luaA_client_set_opacity);
2248 luaA_class_add_property(&client_class, A_TK_ONTOP,
2249 (lua_class_propfunc_t) luaA_client_set_ontop,
2250 (lua_class_propfunc_t) luaA_client_get_ontop,
2251 (lua_class_propfunc_t) luaA_client_set_ontop);
2252 luaA_class_add_property(&client_class, A_TK_ABOVE,
2253 (lua_class_propfunc_t) luaA_client_set_above,
2254 (lua_class_propfunc_t) luaA_client_get_above,
2255 (lua_class_propfunc_t) luaA_client_set_above);
2256 luaA_class_add_property(&client_class, A_TK_BELOW,
2257 (lua_class_propfunc_t) luaA_client_set_below,
2258 (lua_class_propfunc_t) luaA_client_get_below,
2259 (lua_class_propfunc_t) luaA_client_set_below);
2260 luaA_class_add_property(&client_class, A_TK_STICKY,
2261 (lua_class_propfunc_t) luaA_client_set_sticky,
2262 (lua_class_propfunc_t) luaA_client_get_sticky,
2263 (lua_class_propfunc_t) luaA_client_set_sticky);
2264 luaA_class_add_property(&client_class, A_TK_SIZE_HINTS_HONOR,
2265 (lua_class_propfunc_t) luaA_client_set_size_hints_honor,
2266 (lua_class_propfunc_t) luaA_client_get_size_hints_honor,
2267 (lua_class_propfunc_t) luaA_client_set_size_hints_honor);
2268 luaA_class_add_property(&client_class, A_TK_BORDER_WIDTH,
2269 (lua_class_propfunc_t) luaA_client_set_border_width,
2270 (lua_class_propfunc_t) luaA_client_get_border_width,
2271 (lua_class_propfunc_t) luaA_client_set_border_width);
2272 luaA_class_add_property(&client_class, A_TK_BORDER_COLOR,
2273 (lua_class_propfunc_t) luaA_client_set_border_color,
2274 (lua_class_propfunc_t) luaA_client_get_border_color,
2275 (lua_class_propfunc_t) luaA_client_set_border_color);
2276 luaA_class_add_property(&client_class, A_TK_TITLEBAR,
2277 (lua_class_propfunc_t) luaA_client_set_titlebar,
2278 (lua_class_propfunc_t) luaA_client_get_titlebar,
2279 (lua_class_propfunc_t) luaA_client_set_titlebar);
2280 luaA_class_add_property(&client_class, A_TK_URGENT,
2281 (lua_class_propfunc_t) luaA_client_set_urgent,
2282 (lua_class_propfunc_t) luaA_client_get_urgent,
2283 (lua_class_propfunc_t) luaA_client_set_urgent);
2284 luaA_class_add_property(&client_class, A_TK_SIZE_HINTS,
2285 NULL,
2286 (lua_class_propfunc_t) luaA_client_get_size_hints,
2287 NULL);
2290 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80