awful.tag: fix withcurrent screen choice (FS#616)
[awesome.git] / client.c
blob6e8c955c2b5e1dc61fafc44bcc2327b83295ae22
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->machine);
57 p_delete(&c->class);
58 p_delete(&c->instance);
59 p_delete(&c->icon_name);
60 p_delete(&c->alt_icon_name);
61 p_delete(&c->name);
62 p_delete(&c->alt_name);
63 return luaA_object_gc(L);
66 /** Change the client opacity.
67 * \param L The Lua VM state.
68 * \param cidx The client index.
69 * \param opacity The opacity.
71 void
72 client_set_opacity(lua_State *L, int cidx, double opacity)
74 client_t *c = luaA_client_checkudata(L, cidx);
76 if(c->opacity != opacity)
78 c->opacity = opacity;
79 window_opacity_set(c->window, opacity);
80 luaA_object_emit_signal(L, cidx, "property::opacity", 0);
84 /** Change the clients urgency flag.
85 * \param L The Lua VM state.
86 * \param cidx The client index on the stack.
87 * \param urgent The new flag state.
89 void
90 client_set_urgent(lua_State *L, int cidx, bool urgent)
92 client_t *c = luaA_client_checkudata(L, cidx);
94 if(c->urgent != urgent)
96 xcb_get_property_cookie_t hints =
97 xcb_get_wm_hints_unchecked(globalconf.connection, c->window);
99 c->urgent = urgent;
100 ewmh_client_update_hints(c);
102 /* update ICCCM hints */
103 xcb_wm_hints_t wmh;
104 xcb_get_wm_hints_reply(globalconf.connection, hints, &wmh, NULL);
106 if(urgent)
107 wmh.flags |= XCB_WM_HINT_X_URGENCY;
108 else
109 wmh.flags &= ~XCB_WM_HINT_X_URGENCY;
111 xcb_set_wm_hints(globalconf.connection, c->window, &wmh);
113 hook_property(c, "urgent");
114 luaA_object_emit_signal(L, cidx, "property::urgent", 0);
118 void
119 client_set_group_window(lua_State *L, int cidx, xcb_window_t window)
121 client_t *c = luaA_client_checkudata(L, cidx);
123 if(c->group_window != window)
125 c->group_window = window;
126 luaA_object_emit_signal(L, cidx, "property::group_window", 0);
130 void
131 client_set_type(lua_State *L, int cidx, window_type_t type)
133 client_t *c = luaA_client_checkudata(L, cidx);
135 if(c->type != type)
137 c->type = type;
138 luaA_object_emit_signal(L, cidx, "property::type", 0);
142 void
143 client_set_pid(lua_State *L, int cidx, uint32_t pid)
145 client_t *c = luaA_client_checkudata(L, cidx);
147 if(c->pid != pid)
149 c->pid = pid;
150 luaA_object_emit_signal(L, cidx, "property::pid", 0);
154 void
155 client_set_icon_name(lua_State *L, int cidx, char *icon_name)
157 client_t *c = luaA_client_checkudata(L, cidx);
158 p_delete(&c->icon_name);
159 c->icon_name = icon_name;
160 luaA_object_emit_signal(L, cidx, "property::icon_name", 0);
161 hook_property(c, "icon_name");
164 void
165 client_set_alt_icon_name(lua_State *L, int cidx, char *icon_name)
167 client_t *c = luaA_client_checkudata(L, cidx);
168 p_delete(&c->alt_icon_name);
169 c->alt_icon_name = icon_name;
170 luaA_object_emit_signal(L, cidx, "property::icon_name", 0);
171 hook_property(c, "icon_name");
174 void
175 client_set_role(lua_State *L, int cidx, char *role)
177 client_t *c = luaA_client_checkudata(L, cidx);
178 p_delete(&c->role);
179 c->role = role;
180 luaA_object_emit_signal(L, cidx, "property::role", 0);
183 void
184 client_set_machine(lua_State *L, int cidx, char *machine)
186 client_t *c = luaA_client_checkudata(L, cidx);
187 p_delete(&c->machine);
188 c->machine = machine;
189 luaA_object_emit_signal(L, cidx, "property::machine", 0);
192 void
193 client_set_class_instance(lua_State *L, int cidx, const char *class, const char *instance)
195 client_t *c = luaA_client_checkudata(L, cidx);
196 p_delete(&c->class);
197 p_delete(&c->instance);
198 c->class = a_strdup(class);
199 c->instance = a_strdup(instance);
200 luaA_object_emit_signal(L, cidx, "property::class", 0);
201 luaA_object_emit_signal(L, cidx, "property::instance", 0);
204 void
205 client_set_transient_for(lua_State *L, int cidx, client_t *transient_for)
207 client_t *c = luaA_client_checkudata(L, cidx);
209 if(c->transient_for != transient_for)
211 c->transient_for = transient_for;
212 luaA_object_emit_signal(L, cidx, "property::transient_for", 0);
216 void
217 client_set_name(lua_State *L, int cidx, char *name)
219 client_t *c = luaA_client_checkudata(L, cidx);
220 p_delete(&c->name);
221 c->name = name;
222 hook_property(c, "name");
223 luaA_object_emit_signal(L, cidx, "property::name", 0);
226 void
227 client_set_alt_name(lua_State *L, int cidx, char *name)
229 client_t *c = luaA_client_checkudata(L, cidx);
230 p_delete(&c->alt_name);
231 c->alt_name = name;
232 hook_property(c, "name");
233 luaA_object_emit_signal(L, cidx, "property::name", 0);
236 /** Returns true if a client is tagged
237 * with one of the tags of the specified screen.
238 * \param c The client to check.
239 * \param screen Virtual screen.
240 * \return true if the client is visible, false otherwise.
242 bool
243 client_maybevisible(client_t *c, screen_t *screen)
245 if(screen && c->screen == screen)
247 if(c->sticky || c->type == WINDOW_TYPE_DESKTOP)
248 return true;
250 foreach(tag, screen->tags)
251 if(tag_get_selected(*tag) && is_client_tagged(c, *tag))
252 return true;
254 return false;
257 /** Get a client by its window.
258 * \param w The client window to find.
259 * \return A client pointer if found, NULL otherwise.
261 client_t *
262 client_getbywin(xcb_window_t w)
264 foreach(c, globalconf.clients)
265 if((*c)->window == w)
266 return *c;
268 return NULL;
271 /** Record that a client lost focus.
272 * \param c Client being unfocused
274 void
275 client_unfocus_update(client_t *c)
277 globalconf.screens.tab[c->phys_screen].client_focus = NULL;
278 ewmh_update_net_active_window(c->phys_screen);
280 /* Call hook */
281 if(globalconf.hooks.unfocus != LUA_REFNIL)
283 luaA_object_push(globalconf.L, c);
284 luaA_dofunction_from_registry(globalconf.L, globalconf.hooks.unfocus, 1, 0);
287 luaA_object_push(globalconf.L, c);
288 luaA_class_emit_signal(globalconf.L, &client_class, "unfocus", 1);
291 /** Unfocus a client.
292 * \param c The client.
294 void
295 client_unfocus(client_t *c)
298 xcb_window_t root_win = xutil_screen_get(globalconf.connection, c->phys_screen)->root;
299 /* Set focus on root window, so no events leak to the current window.
300 * This kind of inlines client_set_focus(), but a root window will never have
301 * the WM_TAKE_FOCUS protocol.
303 xcb_set_input_focus(globalconf.connection, XCB_INPUT_FOCUS_PARENT,
304 root_win, XCB_CURRENT_TIME);
306 client_unfocus_update(c);
309 /** Check if client supports atom a protocol in WM_PROTOCOL.
310 * \param c The client.
311 * \param atom The protocol atom to check for.
312 * \return True if client has the atom in protocol, false otherwise.
314 bool
315 client_hasproto(client_t *c, xcb_atom_t atom)
317 for(uint32_t i = 0; i < c->protocols.atoms_len; i++)
318 if(c->protocols.atoms[i] == atom)
319 return true;
320 return false;
323 /** Sets focus on window - using xcb_set_input_focus or WM_TAKE_FOCUS
324 * \param c Client that should get focus
325 * \param set_input_focus Should we call xcb_set_input_focus
327 void
328 client_set_focus(client_t *c, bool set_input_focus)
330 bool takefocus = client_hasproto(c, WM_TAKE_FOCUS);
331 if(set_input_focus)
332 xcb_set_input_focus(globalconf.connection, XCB_INPUT_FOCUS_PARENT,
333 c->window, XCB_CURRENT_TIME);
334 if(takefocus)
335 window_takefocus(c->window);
338 /** Ban client and move it out of the viewport.
339 * \param c The client.
341 void
342 client_ban(client_t *c)
344 if(!c->isbanned)
346 xcb_unmap_window(globalconf.connection, c->window);
348 c->isbanned = true;
350 if(globalconf.screens.tab[c->phys_screen].prev_client_focus == c)
351 globalconf.screens.tab[c->phys_screen].prev_client_focus = NULL;
353 /* Wait until the last moment to take away the focus from the window. */
354 if(globalconf.screens.tab[c->phys_screen].client_focus == c)
355 client_unfocus(c);
359 /** This is part of The Bob Marley Algorithm: we ignore enter and leave window
360 * in certain cases, like map/unmap or move, so we don't get spurious events.
362 void
363 client_ignore_enterleave_events(void)
365 foreach(c, globalconf.clients)
366 xcb_change_window_attributes(globalconf.connection,
367 (*c)->window,
368 XCB_CW_EVENT_MASK,
369 (const uint32_t []) { CLIENT_SELECT_INPUT_EVENT_MASK & ~(XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW) });
372 void
373 client_restore_enterleave_events(void)
375 foreach(c, globalconf.clients)
376 xcb_change_window_attributes(globalconf.connection,
377 (*c)->window,
378 XCB_CW_EVENT_MASK,
379 (const uint32_t []) { CLIENT_SELECT_INPUT_EVENT_MASK });
382 /** Record that a client got focus.
383 * \param c The client.
385 void
386 client_focus_update(client_t *c)
388 if(!client_maybevisible(c, c->screen))
390 /* Focus previously focused client */
391 client_focus(globalconf.screen_focus->prev_client_focus);
392 return;
395 if(globalconf.screen_focus
396 && globalconf.screen_focus->client_focus)
398 if (globalconf.screen_focus->client_focus != c)
399 client_unfocus_update(globalconf.screen_focus->client_focus);
400 else
401 /* Already focused */
402 return;
404 luaA_object_push(globalconf.L, c);
405 client_set_minimized(globalconf.L, -1, false);
407 /* unban the client before focusing for consistency */
408 client_unban(c);
410 globalconf.screen_focus = &globalconf.screens.tab[c->phys_screen];
411 globalconf.screen_focus->prev_client_focus = c;
412 globalconf.screen_focus->client_focus = c;
414 /* according to EWMH, we have to remove the urgent state from a client */
415 client_set_urgent(globalconf.L, -1, false);
417 ewmh_update_net_active_window(c->phys_screen);
419 /* execute hook */
420 if(globalconf.hooks.focus != LUA_REFNIL)
422 luaA_object_push(globalconf.L, c);
423 luaA_dofunction_from_registry(globalconf.L, globalconf.hooks.focus, 1, 0);
426 luaA_object_push(globalconf.L, c);
427 luaA_class_emit_signal(globalconf.L, &client_class, "focus", 1);
430 /** Give focus to client, or to first client if client is NULL.
431 * \param c The client.
433 void
434 client_focus(client_t *c)
436 /* We have to set focus on first client */
437 if(!c && globalconf.clients.len && !(c = globalconf.clients.tab[0]))
438 return;
440 if(!client_maybevisible(c, c->screen))
441 return;
443 if (!c->nofocus)
444 client_focus_update(c);
446 client_set_focus(c, !c->nofocus);
449 /** Stack a window below.
450 * \param c The client.
451 * \param previous The previous window on the stack.
452 * \return The next-previous!
454 static xcb_window_t
455 client_stack_above(client_t *c, xcb_window_t previous)
457 uint32_t config_win_vals[2];
459 config_win_vals[0] = previous;
460 config_win_vals[1] = XCB_STACK_MODE_ABOVE;
462 xcb_configure_window(globalconf.connection, c->window,
463 XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE,
464 config_win_vals);
466 config_win_vals[0] = c->window;
468 if(c->titlebar)
470 xcb_configure_window(globalconf.connection,
471 c->titlebar->window,
472 XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE,
473 config_win_vals);
474 previous = c->titlebar->window;
476 else
477 previous = c->window;
479 /* stack transient window on top of their parents */
480 foreach(node, globalconf.stack)
481 if((*node)->transient_for == c)
482 previous = client_stack_above(*node, previous);
484 return previous;
487 /** Stacking layout layers */
488 typedef enum
490 /** This one is a special layer */
491 LAYER_IGNORE,
492 LAYER_DESKTOP,
493 LAYER_BELOW,
494 LAYER_NORMAL,
495 LAYER_ABOVE,
496 LAYER_FULLSCREEN,
497 LAYER_ONTOP,
498 /** This one only used for counting and is not a real layer */
499 LAYER_COUNT
500 } layer_t;
502 /** Get the real layer of a client according to its attribute (fullscreen, …)
503 * \param c The client.
504 * \return The real layer.
506 static layer_t
507 client_layer_translator(client_t *c)
509 /* first deal with user set attributes */
510 if(c->ontop)
511 return LAYER_ONTOP;
512 else if(c->fullscreen)
513 return LAYER_FULLSCREEN;
514 else if(c->above)
515 return LAYER_ABOVE;
516 else if(c->below)
517 return LAYER_BELOW;
519 /* check for transient attr */
520 if(c->transient_for)
521 return LAYER_IGNORE;
523 /* then deal with windows type */
524 switch(c->type)
526 case WINDOW_TYPE_DESKTOP:
527 return LAYER_DESKTOP;
528 default:
529 break;
532 return LAYER_NORMAL;
535 /** Restack clients.
536 * \todo It might be worth stopping to restack everyone and only stack `c'
537 * relatively to the first matching in the list.
539 void
540 client_stack_refresh()
542 uint32_t config_win_vals[2];
543 layer_t layer;
545 if (!globalconf.client_need_stack_refresh)
546 return;
547 globalconf.client_need_stack_refresh = false;
549 config_win_vals[0] = XCB_NONE;
550 config_win_vals[1] = XCB_STACK_MODE_ABOVE;
552 /* stack desktop windows */
553 for(layer = LAYER_DESKTOP; layer < LAYER_BELOW; layer++)
554 foreach(node, globalconf.stack)
555 if(client_layer_translator(*node) == layer)
556 config_win_vals[0] = client_stack_above(*node,
557 config_win_vals[0]);
559 /* first stack not ontop wibox window */
560 foreach(_sb, globalconf.wiboxes)
562 wibox_t *sb = *_sb;
563 if(!sb->ontop)
565 xcb_configure_window(globalconf.connection,
566 sb->window,
567 XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE,
568 config_win_vals);
569 config_win_vals[0] = sb->window;
573 /* then stack clients */
574 for(layer = LAYER_BELOW; layer < LAYER_COUNT; layer++)
575 foreach(node, globalconf.stack)
576 if(client_layer_translator(*node) == layer)
577 config_win_vals[0] = client_stack_above(*node,
578 config_win_vals[0]);
580 /* then stack ontop wibox window */
581 foreach(_sb, globalconf.wiboxes)
583 wibox_t *sb = *_sb;
584 if(sb->ontop)
586 xcb_configure_window(globalconf.connection,
587 sb->window,
588 XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE,
589 config_win_vals);
590 config_win_vals[0] = sb->window;
595 /** Manage a new client.
596 * \param w The window.
597 * \param wgeom Window geometry.
598 * \param phys_screen Physical screen number.
599 * \param startup True if we are managing at startup time.
601 void
602 client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, int phys_screen, bool startup)
604 screen_t *screen;
605 const uint32_t select_input_val[] = { CLIENT_SELECT_INPUT_EVENT_MASK };
607 if(systray_iskdedockapp(w))
609 systray_request_handle(w, phys_screen, NULL);
610 return;
613 /* If this is a new client that just has been launched, then request its
614 * startup id. */
615 xcb_get_property_cookie_t startup_id_q = { 0 };
616 if(!startup)
617 startup_id_q = xcb_get_any_property(globalconf.connection,
618 false, w, _NET_STARTUP_ID, UINT_MAX);
620 xcb_change_window_attributes(globalconf.connection, w, XCB_CW_EVENT_MASK, select_input_val);
622 client_t *c = client_new(globalconf.L);
623 /* Push client in client list */
624 client_array_push(&globalconf.clients, luaA_object_ref(globalconf.L, -1));
627 screen = c->screen = screen_getbycoord(&globalconf.screens.tab[phys_screen],
628 wgeom->x, wgeom->y);
630 c->phys_screen = phys_screen;
632 /* consider the window banned */
633 c->isbanned = true;
635 /* Initial values */
636 c->window = w;
637 c->geometry.x = wgeom->x;
638 c->geometry.y = wgeom->y;
639 /* Border will be added later. */
640 c->geometry.width = wgeom->width;
641 c->geometry.height = wgeom->height;
642 /* Also set internal geometry (client_ban() needs it). */
643 c->geometries.internal.x = wgeom->x;
644 c->geometries.internal.y = wgeom->y;
645 c->geometries.internal.width = wgeom->width;
646 c->geometries.internal.height = wgeom->height;
648 /* Push client */
649 luaA_object_push(globalconf.L, c);
650 client_set_border_width(globalconf.L, -1, wgeom->border_width);
651 lua_pop(globalconf.L, 1);
653 /* we honor size hints by default */
654 c->size_hints_honor = true;
656 /* update hints */
657 property_update_wm_normal_hints(c, NULL);
658 property_update_wm_hints(c, NULL);
659 property_update_wm_transient_for(c, NULL);
660 property_update_wm_client_leader(c, NULL);
661 property_update_wm_client_machine(c, NULL);
662 property_update_wm_window_role(c, NULL);
663 property_update_net_wm_pid(c, NULL);
664 property_update_net_wm_icon(c, NULL);
666 /* get opacity */
667 c->opacity = window_opacity_get(c->window);
669 /* Then check clients hints */
670 ewmh_client_check_hints(c);
672 screen_client_moveto(c, screen, true);
674 /* Push client in stack */
675 client_raise(c);
677 /* update window title */
678 property_update_wm_name(c, NULL);
679 property_update_net_wm_name(c, NULL);
680 property_update_wm_icon_name(c, NULL);
681 property_update_net_wm_icon_name(c, NULL);
682 property_update_wm_class(c, NULL);
683 property_update_wm_protocols(c, NULL);
685 /* update strut */
686 ewmh_process_client_strut(c, NULL);
688 ewmh_update_net_client_list(c->phys_screen);
690 /* Always stay in NORMAL_STATE. Even though iconified seems more
691 * appropriate sometimes. The only possible loss is that clients not using
692 * visibility events may continue to process data (when banned).
693 * Without any exposes or other events the cost should be fairly limited though.
695 * Some clients may expect the window to be unmapped when STATE_ICONIFIED.
696 * Two conflicting parts of the ICCCM v2.0 (section 4.1.4):
698 * "Normal -> Iconic - The client should send a ClientMessage event as described later in this section."
699 * (note no explicit mention of unmapping, while Normal->Widthdrawn does mention that)
701 * "Once a client's window has left the Withdrawn state, the window will be mapped
702 * if it is in the Normal state and the window will be unmapped if it is in the Iconic state."
704 * At this stage it's just safer to keep it in normal state and avoid confusion.
706 window_state_set(c->window, XCB_WM_STATE_NORMAL);
708 if(!startup)
710 /* Request our response */
711 xcb_get_property_reply_t *reply =
712 xcb_get_property_reply(globalconf.connection, startup_id_q, NULL);
713 /* Say spawn that a client has been started, with startup id as argument */
714 char *startup_id = xutil_get_text_property_from_reply(reply);
715 p_delete(&reply);
716 spawn_start_notify(c, startup_id);
717 p_delete(&startup_id);
720 /* Call hook to notify list change */
721 if(globalconf.hooks.clients != LUA_REFNIL)
722 luaA_dofunction_from_registry(globalconf.L, globalconf.hooks.clients, 0, 0);
724 luaA_class_emit_signal(globalconf.L, &client_class, "list", 0);
726 /* call hook */
727 if(globalconf.hooks.manage != LUA_REFNIL)
729 luaA_object_push(globalconf.L, c);
730 lua_pushboolean(globalconf.L, startup);
731 luaA_dofunction_from_registry(globalconf.L, globalconf.hooks.manage, 2, 0);
734 luaA_object_push(globalconf.L, c);
735 lua_pushboolean(globalconf.L, startup);
736 luaA_class_emit_signal(globalconf.L, &client_class, "manage", 2);
739 /** Compute client geometry with respect to its geometry hints.
740 * \param c The client.
741 * \param geometry The geometry that the client might receive.
742 * \return The geometry the client must take respecting its hints.
744 area_t
745 client_geometry_hints(client_t *c, area_t geometry)
747 int32_t basew, baseh, minw, minh;
749 /* base size is substituted with min size if not specified */
750 if(c->size_hints.flags & XCB_SIZE_HINT_P_SIZE)
752 basew = c->size_hints.base_width;
753 baseh = c->size_hints.base_height;
755 else if(c->size_hints.flags & XCB_SIZE_HINT_P_MIN_SIZE)
757 basew = c->size_hints.min_width;
758 baseh = c->size_hints.min_height;
760 else
761 basew = baseh = 0;
763 /* min size is substituted with base size if not specified */
764 if(c->size_hints.flags & XCB_SIZE_HINT_P_MIN_SIZE)
766 minw = c->size_hints.min_width;
767 minh = c->size_hints.min_height;
769 else if(c->size_hints.flags & XCB_SIZE_HINT_P_SIZE)
771 minw = c->size_hints.base_width;
772 minh = c->size_hints.base_height;
774 else
775 minw = minh = 0;
777 if(c->size_hints.flags & XCB_SIZE_HINT_P_ASPECT
778 && c->size_hints.min_aspect_num > 0
779 && c->size_hints.min_aspect_den > 0
780 && geometry.height - baseh > 0
781 && geometry.width - basew > 0)
783 double dx = (double) (geometry.width - basew);
784 double dy = (double) (geometry.height - baseh);
785 double min = (double) c->size_hints.min_aspect_num / (double) c->size_hints.min_aspect_den;
786 double max = (double) c->size_hints.max_aspect_num / (double) c->size_hints.min_aspect_den;
787 double ratio = dx / dy;
788 if(max > 0 && min > 0 && ratio > 0)
790 if(ratio < min)
792 dy = (dx * min + dy) / (min * min + 1);
793 dx = dy * min;
794 geometry.width = (int) dx + basew;
795 geometry.height = (int) dy + baseh;
797 else if(ratio > max)
799 dy = (dx * min + dy) / (max * max + 1);
800 dx = dy * min;
801 geometry.width = (int) dx + basew;
802 geometry.height = (int) dy + baseh;
807 if(minw)
808 geometry.width = MAX(geometry.width, minw);
809 if(minh)
810 geometry.height = MAX(geometry.height, minh);
812 if(c->size_hints.flags & XCB_SIZE_HINT_P_MAX_SIZE)
814 if(c->size_hints.max_width)
815 geometry.width = MIN(geometry.width, c->size_hints.max_width);
816 if(c->size_hints.max_height)
817 geometry.height = MIN(geometry.height, c->size_hints.max_height);
820 if(c->size_hints.flags & (XCB_SIZE_HINT_P_RESIZE_INC | XCB_SIZE_HINT_BASE_SIZE)
821 && c->size_hints.width_inc && c->size_hints.height_inc)
823 uint16_t t1 = geometry.width, t2 = geometry.height;
824 unsigned_subtract(t1, basew);
825 unsigned_subtract(t2, baseh);
826 geometry.width -= t1 % c->size_hints.width_inc;
827 geometry.height -= t2 % c->size_hints.height_inc;
830 return geometry;
833 /** Resize client window.
834 * The sizes given as parameters are with titlebar and borders!
835 * \param c Client to resize.
836 * \param geometry New window geometry.
837 * \param hints Use size hints.
838 * \return true if an actual resize occurred.
840 bool
841 client_resize(client_t *c, area_t geometry, bool hints)
843 area_t geometry_internal;
844 area_t area;
846 /* offscreen appearance fixes */
847 area = display_area_get(c->phys_screen);
849 if(geometry.x > area.width)
850 geometry.x = area.width - geometry.width;
851 if(geometry.y > area.height)
852 geometry.y = area.height - geometry.height;
853 if(geometry.x + geometry.width < 0)
854 geometry.x = 0;
855 if(geometry.y + geometry.height < 0)
856 geometry.y = 0;
858 /* Real client geometry, please keep it contained to C code at the very least. */
859 geometry_internal = titlebar_geometry_remove(c->titlebar, c->border_width, geometry);
861 if(hints)
862 geometry_internal = client_geometry_hints(c, geometry_internal);
864 if(geometry_internal.width == 0 || geometry_internal.height == 0)
865 return false;
867 /* Also let client hints propagate to the "official" geometry. */
868 geometry = titlebar_geometry_add(c->titlebar, c->border_width, geometry_internal);
870 if(c->geometries.internal.x != geometry_internal.x
871 || c->geometries.internal.y != geometry_internal.y
872 || c->geometries.internal.width != geometry_internal.width
873 || c->geometries.internal.height != geometry_internal.height)
875 screen_t *new_screen = screen_getbycoord(c->screen,
876 geometry_internal.x, geometry_internal.y);
878 /* Values to configure a window is an array where values are
879 * stored according to 'value_mask' */
880 uint32_t values[4];
882 c->geometries.internal.x = values[0] = geometry_internal.x;
883 c->geometries.internal.y = values[1] = geometry_internal.y;
884 c->geometries.internal.width = values[2] = geometry_internal.width;
885 c->geometries.internal.height = values[3] = geometry_internal.height;
887 /* Also store geometry including border and titlebar. */
888 c->geometry = geometry;
890 titlebar_update_geometry(c);
892 /* Ignore all spurious enter/leave notify events */
893 client_ignore_enterleave_events();
895 xcb_configure_window(globalconf.connection, c->window,
896 XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y
897 | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
898 values);
900 client_restore_enterleave_events();
902 screen_client_moveto(c, new_screen, false);
904 /* execute hook */
905 hook_property(c, "geometry");
907 luaA_object_push(globalconf.L, c);
908 luaA_object_emit_signal(globalconf.L, -1, "property::x", 0);
909 luaA_object_emit_signal(globalconf.L, -1, "property::y", 0);
910 luaA_object_emit_signal(globalconf.L, -1, "property::width", 0);
911 luaA_object_emit_signal(globalconf.L, -1, "property::height", 0);
912 lua_pop(globalconf.L, 1);
914 return true;
917 return false;
920 /** Set a client minimized, or not.
921 * \param L The Lua VM state.
922 * \param cidx The client index.
923 * \param s Set or not the client minimized.
925 void
926 client_set_minimized(lua_State *L, int cidx, bool s)
928 client_t *c = luaA_client_checkudata(L, cidx);
930 if(c->minimized != s)
932 client_need_reban(c);
933 c->minimized = s;
934 client_need_reban(c);
935 if(s)
936 window_state_set(c->window, XCB_WM_STATE_ICONIC);
937 else
938 window_state_set(c->window, XCB_WM_STATE_NORMAL);
939 ewmh_client_update_hints(c);
940 if(strut_has_value(&c->strut))
941 screen_emit_signal(globalconf.L, c->screen, "property::workarea", 0);
942 /* execute hook */
943 hook_property(c, "minimized");
944 luaA_object_emit_signal(L, cidx, "property::minimized", 0);
948 /** Set a client sticky, or not.
949 * \param L The Lua VM state.
950 * \param cidx The client index.
951 * \param s Set or not the client sticky.
953 void
954 client_set_sticky(lua_State *L, int cidx, bool s)
956 client_t *c = luaA_client_checkudata(L, cidx);
958 if(c->sticky != s)
960 client_need_reban(c);
961 c->sticky = s;
962 client_need_reban(c);
963 ewmh_client_update_hints(c);
964 hook_property(c, "sticky");
965 luaA_object_emit_signal(L, cidx, "property::sticky", 0);
969 /** Set a client fullscreen, or not.
970 * \param L The Lua VM state.
971 * \param cidx The client index.
972 * \param s Set or not the client fullscreen.
974 void
975 client_set_fullscreen(lua_State *L, int cidx, bool s)
977 client_t *c = luaA_client_checkudata(L, cidx);
979 if(c->fullscreen != s)
981 area_t geometry;
983 /* become fullscreen! */
984 if(s)
986 /* Make sure the current geometry is stored without titlebar. */
987 titlebar_ban(c->titlebar);
988 /* remove any max state */
989 client_set_maximized_horizontal(L, cidx, false);
990 client_set_maximized_vertical(L, cidx, false);
991 /* You can only be part of one of the special layers. */
992 client_set_below(L, cidx, false);
993 client_set_above(L, cidx, false);
994 client_set_ontop(L, cidx, false);
996 geometry = screen_area_get(c->screen, false);
997 c->geometries.fullscreen = c->geometry;
998 c->border_width_fs = c->border_width;
999 client_set_border_width(L, cidx, 0);
1000 c->fullscreen = true;
1002 else
1004 geometry = c->geometries.fullscreen;
1005 c->fullscreen = false;
1006 client_set_border_width(L, cidx, c->border_width_fs);
1008 client_resize(c, geometry, false);
1009 client_stack();
1010 ewmh_client_update_hints(c);
1011 hook_property(c, "fullscreen");
1012 luaA_object_emit_signal(L, cidx, "property::fullscreen", 0);
1016 /** Set a client horizontally maximized.
1017 * \param L The Lua VM state.
1018 * \param cidx The client index.
1019 * \param s The maximized status.
1021 void
1022 client_set_maximized_horizontal(lua_State *L, int cidx, bool s)
1024 client_t *c = luaA_client_checkudata(L, cidx);
1026 if(c->maximized_horizontal != s)
1028 area_t geometry;
1030 if((c->maximized_horizontal = s))
1032 /* remove fullscreen mode */
1033 client_set_fullscreen(L, cidx, false);
1035 geometry = screen_area_get(c->screen, true);
1036 geometry.y = c->geometry.y;
1037 geometry.height = c->geometry.height;
1038 c->geometries.max.x = c->geometry.x;
1039 c->geometries.max.width = c->geometry.width;
1041 else
1043 geometry = c->geometry;
1044 geometry.x = c->geometries.max.x;
1045 geometry.width = c->geometries.max.width;
1048 client_resize(c, geometry, c->size_hints_honor);
1049 client_stack();
1050 ewmh_client_update_hints(c);
1051 hook_property(c, "maximized_horizontal");
1052 luaA_object_emit_signal(L, cidx, "property::maximized_horizontal", 0);
1056 /** Set a client vertically maximized.
1057 * \param L The Lua VM state.
1058 * \param cidx The client index.
1059 * \param s The maximized status.
1061 void
1062 client_set_maximized_vertical(lua_State *L, int cidx, bool s)
1064 client_t *c = luaA_client_checkudata(L, cidx);
1066 if(c->maximized_vertical != s)
1068 area_t geometry;
1070 if((c->maximized_vertical = s))
1072 /* remove fullscreen mode */
1073 client_set_fullscreen(L, cidx, false);
1075 geometry = screen_area_get(c->screen, true);
1076 geometry.x = c->geometry.x;
1077 geometry.width = c->geometry.width;
1078 c->geometries.max.y = c->geometry.y;
1079 c->geometries.max.height = c->geometry.height;
1081 else
1083 geometry = c->geometry;
1084 geometry.y = c->geometries.max.y;
1085 geometry.height = c->geometries.max.height;
1088 client_resize(c, geometry, c->size_hints_honor);
1089 client_stack();
1090 ewmh_client_update_hints(c);
1091 hook_property(c, "maximized_vertical");
1092 luaA_object_emit_signal(L, cidx, "property::maximized_vertical", 0);
1096 /** Set a client above, or not.
1097 * \param L The Lua VM state.
1098 * \param cidx The client index.
1099 * \param s Set or not the client above.
1101 void
1102 client_set_above(lua_State *L, int cidx, bool s)
1104 client_t *c = luaA_client_checkudata(L, cidx);
1106 if(c->above != s)
1108 /* You can only be part of one of the special layers. */
1109 if(s)
1111 client_set_below(L, cidx, false);
1112 client_set_ontop(L, cidx, false);
1113 client_set_fullscreen(L, cidx, false);
1115 c->above = s;
1116 client_stack();
1117 ewmh_client_update_hints(c);
1118 /* execute hook */
1119 hook_property(c, "above");
1120 luaA_object_emit_signal(L, cidx, "property::above", 0);
1124 /** Set a client below, or not.
1125 * \param L The Lua VM state.
1126 * \param cidx The client index.
1127 * \param s Set or not the client below.
1129 void
1130 client_set_below(lua_State *L, int cidx, bool s)
1132 client_t *c = luaA_client_checkudata(L, cidx);
1134 if(c->below != s)
1136 /* You can only be part of one of the special layers. */
1137 if(s)
1139 client_set_above(L, cidx, false);
1140 client_set_ontop(L, cidx, false);
1141 client_set_fullscreen(L, cidx, false);
1143 c->below = s;
1144 client_stack();
1145 ewmh_client_update_hints(c);
1146 /* execute hook */
1147 hook_property(c, "below");
1148 luaA_object_emit_signal(L, cidx, "property::below", 0);
1152 /** Set a client modal, or not.
1153 * \param L The Lua VM state.
1154 * \param cidx The client index.
1155 * \param s Set or not the client modal attribute.
1157 void
1158 client_set_modal(lua_State *L, int cidx, bool s)
1160 client_t *c = luaA_client_checkudata(L, cidx);
1162 if(c->modal != s)
1164 c->modal = s;
1165 client_stack();
1166 ewmh_client_update_hints(c);
1167 /* execute hook */
1168 hook_property(c, "modal");
1169 luaA_object_emit_signal(L, cidx, "property::modal", 0);
1173 /** Set a client ontop, or not.
1174 * \param L The Lua VM state.
1175 * \param cidx The client index.
1176 * \param s Set or not the client ontop attribute.
1178 void
1179 client_set_ontop(lua_State *L, int cidx, bool s)
1181 client_t *c = luaA_client_checkudata(L, cidx);
1183 if(c->ontop != s)
1185 /* You can only be part of one of the special layers. */
1186 if(s)
1188 client_set_above(L, cidx, false);
1189 client_set_below(L, cidx, false);
1190 client_set_fullscreen(L, cidx, false);
1192 c->ontop = s;
1193 client_stack();
1194 /* execute hook */
1195 hook_property(c, "ontop");
1196 luaA_object_emit_signal(L, cidx, "property::ontop", 0);
1200 /** Set a client skip taskbar attribute.
1201 * \param L Tha Lua VM state.
1202 * \param cidx The client index.
1203 * \param s Set or not the client skip taskbar attribute.
1205 void
1206 client_set_skip_taskbar(lua_State *L, int cidx, bool s)
1208 client_t *c = luaA_client_checkudata(L, cidx);
1210 if(c->skip_taskbar != s)
1212 c->skip_taskbar = s;
1213 ewmh_client_update_hints(c);
1214 luaA_object_emit_signal(L, cidx, "property::skip_taskbar", 0);
1218 /** Unban a client and move it back into the viewport.
1219 * \param c The client.
1221 void
1222 client_unban(client_t *c)
1224 if(c->isbanned)
1226 xcb_map_window(globalconf.connection, c->window);
1228 c->isbanned = false;
1232 /** Unmanage a client.
1233 * \param c The client.
1235 void
1236 client_unmanage(client_t *c)
1238 tag_array_t *tags = &c->screen->tags;
1240 /* Reset transient_for attributes of widows that maybe referring to us */
1241 foreach(_tc, globalconf.clients)
1243 client_t *tc = *_tc;
1244 if(tc->transient_for == c)
1245 tc->transient_for = NULL;
1248 if(globalconf.screens.tab[c->phys_screen].prev_client_focus == c)
1249 globalconf.screens.tab[c->phys_screen].prev_client_focus = NULL;
1251 if(globalconf.screens.tab[c->phys_screen].client_focus == c)
1252 client_unfocus(c);
1254 /* remove client from global list and everywhere else */
1255 foreach(elem, globalconf.clients)
1256 if(*elem == c)
1258 client_array_remove(&globalconf.clients, elem);
1259 break;
1261 stack_client_remove(c);
1262 for(int i = 0; i < tags->len; i++)
1263 untag_client(c, tags->tab[i]);
1265 /* call hook */
1266 if(globalconf.hooks.unmanage != LUA_REFNIL)
1268 luaA_object_push(globalconf.L, c);
1269 luaA_dofunction_from_registry(globalconf.L, globalconf.hooks.unmanage, 1, 0);
1272 luaA_object_push(globalconf.L, c);
1273 luaA_class_emit_signal(globalconf.L, &client_class, "unmanage", 1);
1275 /* Call hook to notify list change */
1276 if(globalconf.hooks.clients != LUA_REFNIL)
1277 luaA_dofunction_from_registry(globalconf.L, globalconf.hooks.clients, 0, 0);
1279 luaA_class_emit_signal(globalconf.L, &client_class, "list", 0);
1281 if(strut_has_value(&c->strut))
1282 screen_emit_signal(globalconf.L, c->screen, "property::workarea", 0);
1284 window_state_set(c->window, XCB_WM_STATE_WITHDRAWN);
1286 titlebar_client_detach(c);
1288 ewmh_update_net_client_list(c->phys_screen);
1290 /* set client as invalid */
1291 c->invalid = true;
1293 luaA_object_unref(globalconf.L, c);
1296 /** Kill a client via a WM_DELETE_WINDOW request or KillClient if not
1297 * supported.
1298 * \param c The client to kill.
1300 void
1301 client_kill(client_t *c)
1303 if(client_hasproto(c, WM_DELETE_WINDOW))
1305 xcb_client_message_event_t ev;
1307 /* Initialize all of event's fields first */
1308 p_clear(&ev, 1);
1310 ev.response_type = XCB_CLIENT_MESSAGE;
1311 ev.window = c->window;
1312 ev.format = 32;
1313 ev.data.data32[1] = XCB_CURRENT_TIME;
1314 ev.type = WM_PROTOCOLS;
1315 ev.data.data32[0] = WM_DELETE_WINDOW;
1317 xcb_send_event(globalconf.connection, false, c->window,
1318 XCB_EVENT_MASK_NO_EVENT, (char *) &ev);
1320 else
1321 xcb_kill_client(globalconf.connection, c->window);
1324 /** Get all clients into a table.
1325 * \param L The Lua VM state.
1326 * \return The number of elements pushed on stack.
1327 * \luastack
1328 * \lparam An optional screen number.
1329 * \lreturn A table with all clients.
1331 static int
1332 luaA_client_get(lua_State *L)
1334 int i = 1, screen;
1336 screen = luaL_optnumber(L, 1, 0) - 1;
1338 lua_newtable(L);
1340 if(screen == -1)
1341 foreach(c, globalconf.clients)
1343 luaA_object_push(L, *c);
1344 lua_rawseti(L, -2, i++);
1346 else
1348 luaA_checkscreen(screen);
1349 foreach(c, globalconf.clients)
1350 if((*c)->screen == &globalconf.screens.tab[screen])
1352 luaA_object_push(L, *c);
1353 lua_rawseti(L, -2, i++);
1357 return 1;
1360 /** Check if a client is visible on its screen.
1361 * \param L The Lua VM state.
1362 * \return The number of elements pushed on stack.
1363 * \luastack
1364 * \lvalue A client.
1365 * \lreturn A boolean value, true if the client is visible, false otherwise.
1367 static int
1368 luaA_client_isvisible(lua_State *L)
1370 client_t *c = luaA_client_checkudata(L, 1);
1371 lua_pushboolean(L, client_isvisible(c, c->screen));
1372 return 1;
1375 /** Set client border width.
1376 * \param L The Lua VM state.
1377 * \param cidx The client index.
1378 * \param width The border width.
1380 void
1381 client_set_border_width(lua_State *L, int cidx, int width)
1383 client_t *c = luaA_client_checkudata(L, cidx);
1384 uint32_t w = width;
1386 if(width > 0 && (c->type == WINDOW_TYPE_DOCK
1387 || c->type == WINDOW_TYPE_SPLASH
1388 || c->type == WINDOW_TYPE_DESKTOP
1389 || c->fullscreen))
1390 return;
1392 if(width == c->border_width || width < 0)
1393 return;
1395 /* disallow change of border width if the client is fullscreen */
1396 if(c->fullscreen)
1397 return;
1399 /* Update geometry with the new border. */
1400 c->geometry.width -= 2 * c->border_width;
1401 c->geometry.height -= 2 * c->border_width;
1403 c->border_width = width;
1404 xcb_configure_window(globalconf.connection, c->window,
1405 XCB_CONFIG_WINDOW_BORDER_WIDTH, &w);
1407 c->geometry.width += 2 * c->border_width;
1408 c->geometry.height += 2 * c->border_width;
1410 /* Changing border size also affects the size of the titlebar. */
1411 titlebar_update_geometry(c);
1413 hook_property(c, "border_width");
1414 luaA_object_emit_signal(L, cidx, "property::border_width", 0);
1417 /** Set a client icon.
1418 * \param L The Lua VM state.
1419 * \param cidx The client index on the stack.
1420 * \param iidx The image index on the stack.
1422 void
1423 client_set_icon(lua_State *L, int cidx, int iidx)
1425 client_t *c = luaA_client_checkudata(L, cidx);
1426 /* convert index to absolute */
1427 cidx = luaA_absindex(L, cidx);
1428 iidx = luaA_absindex(L, iidx);
1429 luaA_checkudata(L, iidx, &image_class);
1430 luaA_object_unref_item(L, cidx, c->icon);
1431 c->icon = luaA_object_ref_item(L, cidx, iidx);
1432 luaA_object_emit_signal(L, cidx < iidx ? cidx : cidx - 1, "property::icon", 0);
1433 /* execute hook */
1434 hook_property(c, "icon");
1437 /** Kill a client.
1438 * \param L The Lua VM state.
1440 * \luastack
1441 * \lvalue A client.
1443 static int
1444 luaA_client_kill(lua_State *L)
1446 client_t *c = luaA_client_checkudata(L, 1);
1447 client_kill(c);
1448 return 0;
1451 /** Swap a client with another one.
1452 * \param L The Lua VM state.
1453 * \luastack
1454 * \lvalue A client.
1455 * \lparam A client to swap with.
1457 static int
1458 luaA_client_swap(lua_State *L)
1460 client_t *c = luaA_client_checkudata(L, 1);
1461 client_t *swap = luaA_client_checkudata(L, 2);
1463 if(c != swap)
1465 client_t **ref_c = NULL, **ref_swap = NULL;
1466 foreach(item, globalconf.clients)
1468 if(*item == c)
1469 ref_c = item;
1470 else if(*item == swap)
1471 ref_swap = item;
1472 if(ref_c && ref_swap)
1473 break;
1475 /* swap ! */
1476 *ref_c = swap;
1477 *ref_swap = c;
1479 /* Call hook to notify list change */
1480 if(globalconf.hooks.clients != LUA_REFNIL)
1481 luaA_dofunction_from_registry(L, globalconf.hooks.clients, 0, 0);
1483 luaA_class_emit_signal(globalconf.L, &client_class, "list", 0);
1486 return 0;
1489 /** Access or set the client tags.
1490 * \param L The Lua VM state.
1491 * \return The number of elements pushed on stack.
1492 * \lparam A table with tags to set, or none to get the current tags table.
1493 * \return The clients tag.
1495 static int
1496 luaA_client_tags(lua_State *L)
1498 client_t *c = luaA_client_checkudata(L, 1);
1499 tag_array_t *tags = &c->screen->tags;
1500 int j = 0;
1502 if(lua_gettop(L) == 2)
1504 luaA_checktable(L, 2);
1505 for(int i = 0; i < tags->len; i++)
1506 untag_client(c, tags->tab[i]);
1507 lua_pushnil(L);
1508 while(lua_next(L, 2))
1509 tag_client(c);
1510 lua_pop(L, 1);
1513 lua_newtable(L);
1514 foreach(tag, *tags)
1515 if(is_client_tagged(c, *tag))
1517 luaA_object_push(L, *tag);
1518 lua_rawseti(L, -2, ++j);
1521 return 1;
1524 /** Raise a client on top of others which are on the same layer.
1525 * \param L The Lua VM state.
1526 * \luastack
1527 * \lvalue A client.
1529 static int
1530 luaA_client_raise(lua_State *L)
1532 client_t *c = luaA_client_checkudata(L, 1);
1533 client_raise(c);
1534 return 0;
1537 /** Lower a client on bottom of others which are on the same layer.
1538 * \param L The Lua VM state.
1539 * \luastack
1540 * \lvalue A client.
1542 static int
1543 luaA_client_lower(lua_State *L)
1545 client_t *c = luaA_client_checkudata(L, 1);
1547 stack_client_push(c);
1549 /* Traverse all transient layers. */
1550 for(client_t *tc = c->transient_for; tc; tc = tc->transient_for)
1551 stack_client_push(tc);
1553 client_stack();
1555 return 0;
1558 /** Redraw a client by unmapping and mapping it quickly.
1559 * \param L The Lua VM state.
1561 * \luastack
1562 * \lvalue A client.
1564 static int
1565 luaA_client_redraw(lua_State *L)
1567 client_t *c = luaA_client_checkudata(L, 1);
1569 xcb_unmap_window(globalconf.connection, c->window);
1570 xcb_map_window(globalconf.connection, c->window);
1572 /* Set the focus on the current window if the redraw has been
1573 performed on the window where the pointer is currently on
1574 because after the unmapping/mapping, the focus is lost */
1575 if(globalconf.screen_focus->client_focus == c)
1577 client_unfocus(c);
1578 client_focus(c);
1581 return 0;
1584 /** Stop managing a client.
1585 * \param L The Lua VM state.
1586 * \return The number of elements pushed on stack.
1587 * \luastack
1588 * \lvalue A client.
1590 static int
1591 luaA_client_unmanage(lua_State *L)
1593 client_t *c = luaA_client_checkudata(L, 1);
1594 client_unmanage(c);
1595 return 0;
1598 /** Return client geometry.
1599 * \param L The Lua VM state.
1600 * \return The number of elements pushed on stack.
1601 * \luastack
1602 * \lparam A table with new coordinates, or none.
1603 * \lreturn A table with client coordinates.
1605 static int
1606 luaA_client_geometry(lua_State *L)
1608 client_t *c = luaA_client_checkudata(L, 1);
1610 if(lua_gettop(L) == 2 && !lua_isnil(L, 2))
1612 area_t geometry;
1614 luaA_checktable(L, 2);
1615 geometry.x = luaA_getopt_number(L, 2, "x", c->geometry.x);
1616 geometry.y = luaA_getopt_number(L, 2, "y", c->geometry.y);
1617 if(client_isfixed(c))
1619 geometry.width = c->geometry.width;
1620 geometry.height = c->geometry.height;
1622 else
1624 geometry.width = luaA_getopt_number(L, 2, "width", c->geometry.width);
1625 geometry.height = luaA_getopt_number(L, 2, "height", c->geometry.height);
1628 client_resize(c, geometry, c->size_hints_honor);
1631 return luaA_pusharea(L, c->geometry);
1634 /** Return client struts (reserved space at the edge of the screen).
1635 * \param L The Lua VM state.
1636 * \return The number of elements pushed on stack.
1637 * \luastack
1638 * \lparam A table with new strut values, or none.
1639 * \lreturn A table with strut values.
1641 static int
1642 luaA_client_struts(lua_State *L)
1644 client_t *c = luaA_client_checkudata(L, 1);
1646 if(lua_gettop(L) == 2)
1648 luaA_tostrut(L, 2, &c->strut);
1649 ewmh_update_strut(c->window, &c->strut);
1650 hook_property(c, "struts");
1651 luaA_object_emit_signal(L, 1, "property::struts", 0);
1652 screen_emit_signal(L, c->screen, "property::workarea", 0);
1655 return luaA_pushstrut(L, c->strut);
1658 static int
1659 luaA_client_set_screen(lua_State *L, client_t *c)
1661 if(globalconf.xinerama_is_active)
1663 int screen = luaL_checknumber(L, -1) - 1;
1664 luaA_checkscreen(screen);
1665 screen_client_moveto(c, &globalconf.screens.tab[screen], true);
1667 return 0;
1670 static int
1671 luaA_client_set_hidden(lua_State *L, client_t *c)
1673 bool b = luaA_checkboolean(L, -1);
1674 if(b != c->hidden)
1676 client_need_reban(c);
1677 c->hidden = b;
1678 client_need_reban(c);
1679 hook_property(c, "hidden");
1680 if(strut_has_value(&c->strut))
1681 screen_emit_signal(globalconf.L, c->screen, "property::workarea", 0);
1682 luaA_object_emit_signal(L, -3, "property::hidden", 0);
1684 return 0;
1687 static int
1688 luaA_client_set_minimized(lua_State *L, client_t *c)
1690 client_set_minimized(L, -3, luaA_checkboolean(L, -1));
1691 return 0;
1694 static int
1695 luaA_client_set_fullscreen(lua_State *L, client_t *c)
1697 client_set_fullscreen(L, -3, luaA_checkboolean(L, -1));
1698 return 0;
1701 static int
1702 luaA_client_set_modal(lua_State *L, client_t *c)
1704 client_set_modal(L, -3, luaA_checkboolean(L, -1));
1705 return 0;
1708 static int
1709 luaA_client_set_maximized_horizontal(lua_State *L, client_t *c)
1711 client_set_maximized_horizontal(L, -3, luaA_checkboolean(L, -1));
1712 return 0;
1715 static int
1716 luaA_client_set_maximized_vertical(lua_State *L, client_t *c)
1718 client_set_maximized_vertical(L, -3, luaA_checkboolean(L, -1));
1719 return 0;
1722 static int
1723 luaA_client_set_icon(lua_State *L, client_t *c)
1725 client_set_icon(L, -3, -1);
1726 return 0;
1729 static int
1730 luaA_client_set_opacity(lua_State *L, client_t *c)
1732 if(lua_isnil(L, -1))
1733 client_set_opacity(L, -3, -1);
1734 else
1735 client_set_opacity(L, -3, luaL_checknumber(L, -1));
1736 return 0;
1739 static int
1740 luaA_client_set_sticky(lua_State *L, client_t *c)
1742 client_set_sticky(L, -3, luaA_checkboolean(L, -1));
1743 return 0;
1746 static int
1747 luaA_client_set_size_hints_honor(lua_State *L, client_t *c)
1749 c->size_hints_honor = luaA_checkboolean(L, -1);
1750 hook_property(c, "size_hints_honor");
1751 luaA_object_emit_signal(L, -3, "property::size_hints_honor", 0);
1752 return 0;
1755 static int
1756 luaA_client_set_border_width(lua_State *L, client_t *c)
1758 client_set_border_width(L, -3, luaL_checknumber(L, -1));
1759 return 0;
1762 static int
1763 luaA_client_set_ontop(lua_State *L, client_t *c)
1765 client_set_ontop(L, -3, luaA_checkboolean(L, -1));
1766 return 0;
1769 static int
1770 luaA_client_set_below(lua_State *L, client_t *c)
1772 client_set_below(L, -3, luaA_checkboolean(L, -1));
1773 return 0;
1776 static int
1777 luaA_client_set_above(lua_State *L, client_t *c)
1779 client_set_above(L, -3, luaA_checkboolean(L, -1));
1780 return 0;
1783 static int
1784 luaA_client_set_urgent(lua_State *L, client_t *c)
1786 client_set_urgent(L, -3, luaA_checkboolean(L, -1));
1787 return 0;
1790 static int
1791 luaA_client_set_border_color(lua_State *L, client_t *c)
1793 size_t len;
1794 const char *buf;
1795 if((buf = luaL_checklstring(L, -1, &len))
1796 && xcolor_init_reply(xcolor_init_unchecked(&c->border_color, buf, len)))
1798 xcb_change_window_attributes(globalconf.connection, c->window,
1799 XCB_CW_BORDER_PIXEL, &c->border_color.pixel);
1800 luaA_object_emit_signal(L, -3, "property::border_color", 0);
1802 return 0;
1805 static int
1806 luaA_client_set_titlebar(lua_State *L, client_t *c)
1808 if(lua_isnil(L, -1))
1809 titlebar_client_detach(c);
1810 else
1811 titlebar_client_attach(c);
1812 return 0;
1815 static int
1816 luaA_client_set_skip_taskbar(lua_State *L, client_t *c)
1818 client_set_skip_taskbar(L, -3, luaA_checkboolean(L, -1));
1819 return 0;
1822 static int
1823 luaA_client_get_name(lua_State *L, client_t *c)
1825 lua_pushstring(L, c->name ? c->name : c->alt_name);
1826 return 1;
1829 static int
1830 luaA_client_get_icon_name(lua_State *L, client_t *c)
1832 lua_pushstring(L, c->icon_name ? c->icon_name : c->alt_icon_name);
1833 return 1;
1836 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, class, lua_pushstring)
1837 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, instance, lua_pushstring)
1838 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, machine, lua_pushstring)
1839 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, role, lua_pushstring)
1840 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, transient_for, luaA_object_push)
1841 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, skip_taskbar, lua_pushboolean)
1842 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, window, lua_pushnumber)
1843 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, leader_window, lua_pushnumber)
1844 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, group_window, lua_pushnumber)
1845 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, pid, lua_pushnumber)
1846 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, hidden, lua_pushboolean)
1847 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, minimized, lua_pushboolean)
1848 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, fullscreen, lua_pushboolean)
1849 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, modal, lua_pushboolean)
1850 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, ontop, lua_pushboolean)
1851 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, urgent, lua_pushboolean)
1852 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, above, lua_pushboolean)
1853 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, below, lua_pushboolean)
1854 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, sticky, lua_pushboolean)
1855 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, size_hints_honor, lua_pushboolean)
1856 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, maximized_horizontal, lua_pushboolean)
1857 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, maximized_vertical, lua_pushboolean)
1858 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, opacity, lua_pushnumber)
1859 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, border_width, lua_pushnumber)
1860 LUA_OBJECT_EXPORT_PROPERTY(client, client_t, border_color, luaA_pushxcolor)
1862 static int
1863 luaA_client_get_content(lua_State *L, client_t *c)
1865 xcb_image_t *ximage = xcb_image_get(globalconf.connection,
1866 c->window,
1867 0, 0,
1868 c->geometries.internal.width,
1869 c->geometries.internal.height,
1870 ~0, XCB_IMAGE_FORMAT_Z_PIXMAP);
1871 int retval = 0;
1873 if(ximage)
1875 if(ximage->bpp >= 24)
1877 uint32_t *data = p_alloca(uint32_t, ximage->width * ximage->height);
1879 for(int y = 0; y < ximage->height; y++)
1880 for(int x = 0; x < ximage->width; x++)
1882 data[y * ximage->width + x] = xcb_image_get_pixel(ximage, x, y);
1883 data[y * ximage->width + x] |= 0xff000000; /* set alpha to 0xff */
1886 retval = image_new_from_argb32(ximage->width, ximage->height, data);
1888 xcb_image_destroy(ximage);
1891 return retval;
1894 static int
1895 luaA_client_get_type(lua_State *L, client_t *c)
1897 switch(c->type)
1899 case WINDOW_TYPE_DESKTOP:
1900 lua_pushliteral(L, "desktop");
1901 break;
1902 case WINDOW_TYPE_DOCK:
1903 lua_pushliteral(L, "dock");
1904 break;
1905 case WINDOW_TYPE_SPLASH:
1906 lua_pushliteral(L, "splash");
1907 break;
1908 case WINDOW_TYPE_DIALOG:
1909 lua_pushliteral(L, "dialog");
1910 break;
1911 case WINDOW_TYPE_MENU:
1912 lua_pushliteral(L, "menu");
1913 break;
1914 case WINDOW_TYPE_TOOLBAR:
1915 lua_pushliteral(L, "toolbar");
1916 break;
1917 case WINDOW_TYPE_UTILITY:
1918 lua_pushliteral(L, "utility");
1919 break;
1920 case WINDOW_TYPE_DROPDOWN_MENU:
1921 lua_pushliteral(L, "dropdown_menu");
1922 break;
1923 case WINDOW_TYPE_POPUP_MENU:
1924 lua_pushliteral(L, "popup_menu");
1925 break;
1926 case WINDOW_TYPE_TOOLTIP:
1927 lua_pushliteral(L, "tooltip");
1928 break;
1929 case WINDOW_TYPE_NOTIFICATION:
1930 lua_pushliteral(L, "notification");
1931 break;
1932 case WINDOW_TYPE_COMBO:
1933 lua_pushliteral(L, "combo");
1934 break;
1935 case WINDOW_TYPE_DND:
1936 lua_pushliteral(L, "dnd");
1937 break;
1938 case WINDOW_TYPE_NORMAL:
1939 lua_pushliteral(L, "normal");
1940 break;
1942 return 1;
1945 static int
1946 luaA_client_get_screen(lua_State *L, client_t *c)
1948 if(!c->screen)
1949 return 0;
1950 lua_pushnumber(L, 1 + screen_array_indexof(&globalconf.screens, c->screen));
1951 return 1;
1954 static int
1955 luaA_client_get_icon(lua_State *L, client_t *c)
1957 return luaA_object_push_item(L, -2, c->icon);
1960 static int
1961 luaA_client_get_titlebar(lua_State *L, client_t *c)
1963 return luaA_object_push(L, c->titlebar);
1966 static int
1967 luaA_client_get_size_hints(lua_State *L, client_t *c)
1969 const char *u_or_p = NULL;
1971 lua_createtable(L, 0, 1);
1973 if(c->size_hints.flags & XCB_SIZE_HINT_US_POSITION)
1974 u_or_p = "user_position";
1975 else if(c->size_hints.flags & XCB_SIZE_HINT_P_POSITION)
1976 u_or_p = "program_position";
1978 if(u_or_p)
1980 lua_createtable(L, 0, 2);
1981 lua_pushnumber(L, c->size_hints.x);
1982 lua_setfield(L, -2, "x");
1983 lua_pushnumber(L, c->size_hints.y);
1984 lua_setfield(L, -2, "y");
1985 lua_setfield(L, -2, u_or_p);
1986 u_or_p = NULL;
1989 if(c->size_hints.flags & XCB_SIZE_HINT_US_SIZE)
1990 u_or_p = "user_size";
1991 else if(c->size_hints.flags & XCB_SIZE_HINT_P_SIZE)
1992 u_or_p = "program_size";
1994 if(u_or_p)
1996 lua_createtable(L, 0, 2);
1997 lua_pushnumber(L, c->size_hints.width);
1998 lua_setfield(L, -2, "width");
1999 lua_pushnumber(L, c->size_hints.height);
2000 lua_setfield(L, -2, "height");
2001 lua_setfield(L, -2, u_or_p);
2004 if(c->size_hints.flags & XCB_SIZE_HINT_P_MIN_SIZE)
2006 lua_pushnumber(L, c->size_hints.min_width);
2007 lua_setfield(L, -2, "min_width");
2008 lua_pushnumber(L, c->size_hints.min_height);
2009 lua_setfield(L, -2, "min_height");
2012 if(c->size_hints.flags & XCB_SIZE_HINT_P_MAX_SIZE)
2014 lua_pushnumber(L, c->size_hints.max_width);
2015 lua_setfield(L, -2, "max_width");
2016 lua_pushnumber(L, c->size_hints.max_height);
2017 lua_setfield(L, -2, "max_height");
2020 if(c->size_hints.flags & XCB_SIZE_HINT_P_RESIZE_INC)
2022 lua_pushnumber(L, c->size_hints.width_inc);
2023 lua_setfield(L, -2, "width_inc");
2024 lua_pushnumber(L, c->size_hints.height_inc);
2025 lua_setfield(L, -2, "height_inc");
2028 if(c->size_hints.flags & XCB_SIZE_HINT_P_ASPECT)
2030 lua_pushnumber(L, c->size_hints.min_aspect_num);
2031 lua_setfield(L, -2, "min_aspect_num");
2032 lua_pushnumber(L, c->size_hints.min_aspect_den);
2033 lua_setfield(L, -2, "min_aspect_den");
2034 lua_pushnumber(L, c->size_hints.max_aspect_num);
2035 lua_setfield(L, -2, "max_aspect_num");
2036 lua_pushnumber(L, c->size_hints.max_aspect_den);
2037 lua_setfield(L, -2, "max_aspect_den");
2040 if(c->size_hints.flags & XCB_SIZE_HINT_BASE_SIZE)
2042 lua_pushnumber(L, c->size_hints.base_width);
2043 lua_setfield(L, -2, "base_width");
2044 lua_pushnumber(L, c->size_hints.base_height);
2045 lua_setfield(L, -2, "base_height");
2048 if(c->size_hints.flags & XCB_SIZE_HINT_P_WIN_GRAVITY)
2050 switch(c->size_hints.win_gravity)
2052 default:
2053 lua_pushliteral(L, "north_west");
2054 break;
2055 case XCB_GRAVITY_NORTH:
2056 lua_pushliteral(L, "north");
2057 break;
2058 case XCB_GRAVITY_NORTH_EAST:
2059 lua_pushliteral(L, "north_east");
2060 break;
2061 case XCB_GRAVITY_WEST:
2062 lua_pushliteral(L, "west");
2063 break;
2064 case XCB_GRAVITY_CENTER:
2065 lua_pushliteral(L, "center");
2066 break;
2067 case XCB_GRAVITY_EAST:
2068 lua_pushliteral(L, "east");
2069 break;
2070 case XCB_GRAVITY_SOUTH_WEST:
2071 lua_pushliteral(L, "south_west");
2072 break;
2073 case XCB_GRAVITY_SOUTH:
2074 lua_pushliteral(L, "south");
2075 break;
2076 case XCB_GRAVITY_SOUTH_EAST:
2077 lua_pushliteral(L, "south_east");
2078 break;
2079 case XCB_GRAVITY_STATIC:
2080 lua_pushliteral(L, "static");
2081 break;
2083 lua_setfield(L, -2, "win_gravity");
2086 return 1;
2089 /** Get or set mouse buttons bindings for a client.
2090 * \param L The Lua VM state.
2091 * \return The number of element pushed on stack.
2092 * \luastack
2093 * \lvalue A client.
2094 * \lparam An array of mouse button bindings objects, or nothing.
2095 * \return The array of mouse button bindings objects of this client.
2097 static int
2098 luaA_client_buttons(lua_State *L)
2100 client_t *client = luaA_client_checkudata(L, 1);
2101 button_array_t *buttons = &client->buttons;
2103 if(lua_gettop(L) == 2)
2105 luaA_button_array_set(L, 1, 2, buttons);
2106 luaA_object_emit_signal(L, 1, "property::buttons", 0);
2107 window_buttons_grab(client->window, &client->buttons);
2110 return luaA_button_array_get(L, 1, buttons);
2113 /** Get or set keys bindings for a client.
2114 * \param L The Lua VM state.
2115 * \return The number of element pushed on stack.
2116 * \luastack
2117 * \lvalue A client.
2118 * \lparam An array of key bindings objects, or nothing.
2119 * \return The array of key bindings objects of this client.
2121 static int
2122 luaA_client_keys(lua_State *L)
2124 client_t *c = luaA_client_checkudata(L, 1);
2125 key_array_t *keys = &c->keys;
2127 if(lua_gettop(L) == 2)
2129 luaA_key_array_set(L, 1, 2, keys);
2130 luaA_object_emit_signal(L, 1, "property::keys", 0);
2131 xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, c->window, XCB_BUTTON_MASK_ANY);
2132 window_grabkeys(c->window, keys);
2135 return luaA_key_array_get(L, 1, keys);
2138 /* Client module.
2139 * \param L The Lua VM state.
2140 * \return The number of pushed elements.
2142 static int
2143 luaA_client_module_index(lua_State *L)
2145 size_t len;
2146 const char *buf = luaL_checklstring(L, 2, &len);
2148 switch(a_tokenize(buf, len))
2150 case A_TK_FOCUS:
2151 return luaA_object_push(globalconf.L, globalconf.screen_focus->client_focus);
2152 break;
2153 default:
2154 return 0;
2158 /* Client module new index.
2159 * \param L The Lua VM state.
2160 * \return The number of pushed elements.
2162 static int
2163 luaA_client_module_newindex(lua_State *L)
2165 size_t len;
2166 const char *buf = luaL_checklstring(L, 2, &len);
2167 client_t *c;
2169 switch(a_tokenize(buf, len))
2171 case A_TK_FOCUS:
2172 c = luaA_client_checkudata(L, 3);
2173 client_focus(c);
2174 break;
2175 default:
2176 break;
2179 return 0;
2182 void
2183 client_class_setup(lua_State *L)
2185 static const struct luaL_reg client_methods[] =
2187 LUA_CLASS_METHODS(client)
2188 { "get", luaA_client_get },
2189 { "__index", luaA_client_module_index },
2190 { "__newindex", luaA_client_module_newindex },
2191 { NULL, NULL }
2194 static const struct luaL_reg client_meta[] =
2196 LUA_OBJECT_META(client)
2197 LUA_CLASS_META
2198 { "buttons", luaA_client_buttons },
2199 { "keys", luaA_client_keys },
2200 { "isvisible", luaA_client_isvisible },
2201 { "geometry", luaA_client_geometry },
2202 { "struts", luaA_client_struts },
2203 { "tags", luaA_client_tags },
2204 { "kill", luaA_client_kill },
2205 { "swap", luaA_client_swap },
2206 { "raise", luaA_client_raise },
2207 { "lower", luaA_client_lower },
2208 { "redraw", luaA_client_redraw },
2209 { "unmanage", luaA_client_unmanage },
2210 { "__gc", luaA_client_gc },
2211 { NULL, NULL }
2214 luaA_class_setup(L, &client_class, "client", (lua_class_allocator_t) client_new,
2215 luaA_class_index_miss_property, luaA_class_newindex_miss_property,
2216 client_methods, client_meta);
2217 luaA_class_add_property(&client_class, A_TK_NAME,
2218 NULL,
2219 (lua_class_propfunc_t) luaA_client_get_name,
2220 NULL);
2221 luaA_class_add_property(&client_class, A_TK_TRANSIENT_FOR,
2222 NULL,
2223 (lua_class_propfunc_t) luaA_client_get_transient_for,
2224 NULL);
2225 luaA_class_add_property(&client_class, A_TK_SKIP_TASKBAR,
2226 (lua_class_propfunc_t) luaA_client_set_skip_taskbar,
2227 (lua_class_propfunc_t) luaA_client_get_skip_taskbar,
2228 (lua_class_propfunc_t) luaA_client_set_skip_taskbar);
2229 luaA_class_add_property(&client_class, A_TK_CONTENT,
2230 NULL,
2231 (lua_class_propfunc_t) luaA_client_get_content,
2232 NULL);
2233 luaA_class_add_property(&client_class, A_TK_TYPE,
2234 NULL,
2235 (lua_class_propfunc_t) luaA_client_get_type,
2236 NULL);
2237 luaA_class_add_property(&client_class, A_TK_CLASS,
2238 NULL,
2239 (lua_class_propfunc_t) luaA_client_get_class,
2240 NULL);
2241 luaA_class_add_property(&client_class, A_TK_INSTANCE,
2242 NULL,
2243 (lua_class_propfunc_t) luaA_client_get_instance,
2244 NULL);
2245 luaA_class_add_property(&client_class, A_TK_ROLE,
2246 NULL,
2247 (lua_class_propfunc_t) luaA_client_get_role,
2248 NULL);
2249 luaA_class_add_property(&client_class, A_TK_PID,
2250 NULL,
2251 (lua_class_propfunc_t) luaA_client_get_pid,
2252 NULL);
2253 luaA_class_add_property(&client_class, A_TK_WINDOW,
2254 NULL,
2255 (lua_class_propfunc_t) luaA_client_get_window,
2256 NULL);
2257 luaA_class_add_property(&client_class, A_TK_LEADER_WINDOW,
2258 NULL,
2259 (lua_class_propfunc_t) luaA_client_get_leader_window,
2260 NULL);
2261 luaA_class_add_property(&client_class, A_TK_MACHINE,
2262 NULL,
2263 (lua_class_propfunc_t) luaA_client_get_machine,
2264 NULL);
2265 luaA_class_add_property(&client_class, A_TK_ICON_NAME,
2266 NULL,
2267 (lua_class_propfunc_t) luaA_client_get_icon_name,
2268 NULL);
2269 luaA_class_add_property(&client_class, A_TK_SCREEN,
2270 NULL,
2271 (lua_class_propfunc_t) luaA_client_get_screen,
2272 (lua_class_propfunc_t) luaA_client_set_screen);
2273 luaA_class_add_property(&client_class, A_TK_HIDDEN,
2274 (lua_class_propfunc_t) luaA_client_set_hidden,
2275 (lua_class_propfunc_t) luaA_client_get_hidden,
2276 (lua_class_propfunc_t) luaA_client_set_hidden);
2277 luaA_class_add_property(&client_class, A_TK_MINIMIZED,
2278 (lua_class_propfunc_t) luaA_client_set_minimized,
2279 (lua_class_propfunc_t) luaA_client_get_minimized,
2280 (lua_class_propfunc_t) luaA_client_set_minimized);
2281 luaA_class_add_property(&client_class, A_TK_FULLSCREEN,
2282 (lua_class_propfunc_t) luaA_client_set_fullscreen,
2283 (lua_class_propfunc_t) luaA_client_get_fullscreen,
2284 (lua_class_propfunc_t) luaA_client_set_fullscreen);
2285 luaA_class_add_property(&client_class, A_TK_MODAL,
2286 (lua_class_propfunc_t) luaA_client_set_modal,
2287 (lua_class_propfunc_t) luaA_client_get_modal,
2288 (lua_class_propfunc_t) luaA_client_set_modal);
2289 luaA_class_add_property(&client_class, A_TK_GROUP_WINDOW,
2290 NULL,
2291 (lua_class_propfunc_t) luaA_client_get_group_window,
2292 NULL);
2293 luaA_class_add_property(&client_class, A_TK_MAXIMIZED_HORIZONTAL,
2294 (lua_class_propfunc_t) luaA_client_set_maximized_horizontal,
2295 (lua_class_propfunc_t) luaA_client_get_maximized_horizontal,
2296 (lua_class_propfunc_t) luaA_client_set_maximized_horizontal);
2297 luaA_class_add_property(&client_class, A_TK_MAXIMIZED_VERTICAL,
2298 (lua_class_propfunc_t) luaA_client_set_maximized_vertical,
2299 (lua_class_propfunc_t) luaA_client_get_maximized_vertical,
2300 (lua_class_propfunc_t) luaA_client_set_maximized_vertical);
2301 luaA_class_add_property(&client_class, A_TK_ICON,
2302 (lua_class_propfunc_t) luaA_client_set_icon,
2303 (lua_class_propfunc_t) luaA_client_get_icon,
2304 (lua_class_propfunc_t) luaA_client_set_icon);
2305 luaA_class_add_property(&client_class, A_TK_OPACITY,
2306 (lua_class_propfunc_t) luaA_client_set_opacity,
2307 (lua_class_propfunc_t) luaA_client_get_opacity,
2308 (lua_class_propfunc_t) luaA_client_set_opacity);
2309 luaA_class_add_property(&client_class, A_TK_ONTOP,
2310 (lua_class_propfunc_t) luaA_client_set_ontop,
2311 (lua_class_propfunc_t) luaA_client_get_ontop,
2312 (lua_class_propfunc_t) luaA_client_set_ontop);
2313 luaA_class_add_property(&client_class, A_TK_ABOVE,
2314 (lua_class_propfunc_t) luaA_client_set_above,
2315 (lua_class_propfunc_t) luaA_client_get_above,
2316 (lua_class_propfunc_t) luaA_client_set_above);
2317 luaA_class_add_property(&client_class, A_TK_BELOW,
2318 (lua_class_propfunc_t) luaA_client_set_below,
2319 (lua_class_propfunc_t) luaA_client_get_below,
2320 (lua_class_propfunc_t) luaA_client_set_below);
2321 luaA_class_add_property(&client_class, A_TK_STICKY,
2322 (lua_class_propfunc_t) luaA_client_set_sticky,
2323 (lua_class_propfunc_t) luaA_client_get_sticky,
2324 (lua_class_propfunc_t) luaA_client_set_sticky);
2325 luaA_class_add_property(&client_class, A_TK_SIZE_HINTS_HONOR,
2326 (lua_class_propfunc_t) luaA_client_set_size_hints_honor,
2327 (lua_class_propfunc_t) luaA_client_get_size_hints_honor,
2328 (lua_class_propfunc_t) luaA_client_set_size_hints_honor);
2329 luaA_class_add_property(&client_class, A_TK_BORDER_WIDTH,
2330 (lua_class_propfunc_t) luaA_client_set_border_width,
2331 (lua_class_propfunc_t) luaA_client_get_border_width,
2332 (lua_class_propfunc_t) luaA_client_set_border_width);
2333 luaA_class_add_property(&client_class, A_TK_BORDER_COLOR,
2334 (lua_class_propfunc_t) luaA_client_set_border_color,
2335 (lua_class_propfunc_t) luaA_client_get_border_color,
2336 (lua_class_propfunc_t) luaA_client_set_border_color);
2337 luaA_class_add_property(&client_class, A_TK_TITLEBAR,
2338 (lua_class_propfunc_t) luaA_client_set_titlebar,
2339 (lua_class_propfunc_t) luaA_client_get_titlebar,
2340 (lua_class_propfunc_t) luaA_client_set_titlebar);
2341 luaA_class_add_property(&client_class, A_TK_URGENT,
2342 (lua_class_propfunc_t) luaA_client_set_urgent,
2343 (lua_class_propfunc_t) luaA_client_get_urgent,
2344 (lua_class_propfunc_t) luaA_client_set_urgent);
2345 luaA_class_add_property(&client_class, A_TK_SIZE_HINTS,
2346 NULL,
2347 (lua_class_propfunc_t) luaA_client_get_size_hints,
2348 NULL);
2351 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80