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>
33 #include "common/atoms.h"
34 #include "common/xutil.h"
37 luaA_client_checkudata(lua_State
*L
, int ud
)
39 client_t
*c
= luaA_checkudata(L
, ud
, &client_class
);
41 luaL_error(L
, "client is invalid\n");
46 * \param L The Lua VM state.
47 * \return The number of element pushed on stack.
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
);
57 p_delete(&c
->instance
);
58 p_delete(&c
->icon_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.
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
)
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.
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
);
97 ewmh_client_update_hints(c
);
99 /* update ICCCM hints */
101 xcb_get_wm_hints_reply(globalconf
.connection
, hints
, &wmh
, NULL
);
104 wmh
.flags
|= XCB_WM_HINT_X_URGENCY
;
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);
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);
128 client_set_type(lua_State
*L
, int cidx
, window_type_t type
)
130 client_t
*c
= luaA_client_checkudata(L
, cidx
);
135 luaA_object_emit_signal(L
, cidx
, "property::type", 0);
140 client_set_pid(lua_State
*L
, int cidx
, uint32_t pid
)
142 client_t
*c
= luaA_client_checkudata(L
, cidx
);
147 luaA_object_emit_signal(L
, cidx
, "property::pid", 0);
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");
162 client_set_role(lua_State
*L
, int cidx
, char *role
)
164 client_t
*c
= luaA_client_checkudata(L
, cidx
);
167 luaA_object_emit_signal(L
, cidx
, "property::role", 0);
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);
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
);
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);
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);
204 client_set_name(lua_State
*L
, int cidx
, char *name
)
206 client_t
*c
= luaA_client_checkudata(L
, cidx
);
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.
220 client_maybevisible(client_t
*c
, screen_t
*screen
)
222 if(screen
&& c
->screen
== screen
)
224 if(c
->sticky
|| c
->type
== WINDOW_TYPE_DESKTOP
)
227 foreach(tag
, screen
->tags
)
228 if(tag_get_selected(*tag
) && is_client_tagged(c
, *tag
))
234 /** Get a client by its window.
235 * \param w The client window to find.
236 * \return A client pointer if found, NULL otherwise.
239 client_getbywin(xcb_window_t w
)
241 foreach(c
, globalconf
.clients
)
242 if((*c
)->window
== w
)
248 /** Record that a client lost focus.
249 * \param c Client being unfocused
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
);
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.
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.
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
)
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
305 client_set_focus(client_t
*c
, bool set_input_focus
)
307 bool takefocus
= client_hasproto(c
, WM_TAKE_FOCUS
);
309 xcb_set_input_focus(globalconf
.connection
, XCB_INPUT_FOCUS_PARENT
,
310 c
->window
, XCB_CURRENT_TIME
);
312 window_takefocus(c
->window
);
315 /** Ban client and move it out of the viewport.
316 * \param c The client.
319 client_ban(client_t
*c
)
323 xcb_unmap_window(globalconf
.connection
, c
->window
);
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
)
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.
340 client_ignore_enterleave_events(void)
342 foreach(c
, globalconf
.clients
)
343 xcb_change_window_attributes(globalconf
.connection
,
346 (const uint32_t []) { CLIENT_SELECT_INPUT_EVENT_MASK
& ~(XCB_EVENT_MASK_ENTER_WINDOW
| XCB_EVENT_MASK_LEAVE_WINDOW
) });
350 client_restore_enterleave_events(void)
352 foreach(c
, globalconf
.clients
)
353 xcb_change_window_attributes(globalconf
.connection
,
356 (const uint32_t []) { CLIENT_SELECT_INPUT_EVENT_MASK
});
359 /** Record that a client got focus.
360 * \param c The client.
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
);
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
);
378 /* Already focused */
381 luaA_object_push(globalconf
.L
, c
);
382 client_set_minimized(globalconf
.L
, -1, false);
384 /* unban the client before focusing for consistency */
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
);
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.
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]))
417 if(!client_maybevisible(c
, c
->screen
))
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!
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
,
443 config_win_vals
[0] = c
->window
;
447 xcb_configure_window(globalconf
.connection
,
449 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
451 previous
= c
->titlebar
->window
;
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
);
464 /** Stacking layout layers */
467 /** This one is a special layer */
475 /** This one only used for counting and is not a real layer */
479 /** Get the real layer of a client according to its attribute (fullscreen, …)
480 * \param c The client.
481 * \return The real layer.
484 client_layer_translator(client_t
*c
)
486 /* first deal with user set attributes */
489 else if(c
->fullscreen
)
490 return LAYER_FULLSCREEN
;
496 /* check for transient attr */
500 /* then deal with windows type */
503 case WINDOW_TYPE_DESKTOP
:
504 return LAYER_DESKTOP
;
513 * \todo It might be worth stopping to restack everyone and only stack `c'
514 * relatively to the first matching in the list.
517 client_stack_refresh()
519 uint32_t config_win_vals
[2];
522 if (!globalconf
.client_need_stack_refresh
)
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
,
536 /* first stack not ontop wibox window */
537 foreach(_sb
, globalconf
.wiboxes
)
542 xcb_configure_window(globalconf
.connection
,
544 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
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
,
557 /* then stack ontop wibox window */
558 foreach(_sb
, globalconf
.wiboxes
)
563 xcb_configure_window(globalconf
.connection
,
565 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
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.
579 client_manage(xcb_window_t w
, xcb_get_geometry_reply_t
*wgeom
, int phys_screen
, bool startup
)
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
);
590 /* If this is a new client that just has been launched, then request its
592 xcb_get_property_cookie_t startup_id_q
= { 0 };
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
],
607 c
->phys_screen
= phys_screen
;
609 /* consider the window banned */
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
;
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;
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
);
644 c
->opacity
= window_opacity_get(c
->window
);
646 /* Then check clients hints */
647 ewmh_client_check_hints(c
);
649 /* move client to screen, but do not tag it */
650 screen_client_moveto(c
, screen
, false, true);
652 /* Push client in stack */
655 /* update window title */
656 property_update_wm_name(c
, NULL
);
657 property_update_wm_icon_name(c
, NULL
);
658 property_update_wm_class(c
, NULL
);
659 property_update_wm_protocols(c
, NULL
);
662 ewmh_process_client_strut(c
, NULL
);
664 ewmh_update_net_client_list(c
->phys_screen
);
666 /* Always stay in NORMAL_STATE. Even though iconified seems more
667 * appropriate sometimes. The only possible loss is that clients not using
668 * visibility events may continue to proces data (when banned).
669 * Without any exposes or other events the cost should be fairly limited though.
671 * Some clients may expect the window to be unmapped when STATE_ICONIFIED.
672 * Two conflicting parts of the ICCCM v2.0 (section 4.1.4):
674 * "Normal -> Iconic - The client should send a ClientMessage event as described later in this section."
675 * (note no explicit mention of unmapping, while Normal->Widthdrawn does mention that)
677 * "Once a client's window has left the Withdrawn state, the window will be mapped
678 * if it is in the Normal state and the window will be unmapped if it is in the Iconic state."
680 * At this stage it's just safer to keep it in normal state and avoid confusion.
682 window_state_set(c
->window
, XCB_WM_STATE_NORMAL
);
686 /* Request our response */
687 xcb_get_property_reply_t
*reply
=
688 xcb_get_property_reply(globalconf
.connection
, startup_id_q
, NULL
);
689 /* Say spawn that a client has been started, with startup id as argument */
690 char *startup_id
= xutil_get_text_property_from_reply(reply
);
692 spawn_start_notify(c
, startup_id
);
693 p_delete(&startup_id
);
696 /* Call hook to notify list change */
697 if(globalconf
.hooks
.clients
!= LUA_REFNIL
)
698 luaA_dofunction_from_registry(globalconf
.L
, globalconf
.hooks
.clients
, 0, 0);
700 luaA_class_emit_signal(globalconf
.L
, &client_class
, "list", 0);
703 if(globalconf
.hooks
.manage
!= LUA_REFNIL
)
705 luaA_object_push(globalconf
.L
, c
);
706 lua_pushboolean(globalconf
.L
, startup
);
707 luaA_dofunction_from_registry(globalconf
.L
, globalconf
.hooks
.manage
, 2, 0);
710 luaA_object_push(globalconf
.L
, c
);
711 lua_pushboolean(globalconf
.L
, startup
);
712 luaA_class_emit_signal(globalconf
.L
, &client_class
, "manage", 2);
715 /** Compute client geometry with respect to its geometry hints.
716 * \param c The client.
717 * \param geometry The geometry that the client might receive.
718 * \return The geometry the client must take respecting its hints.
721 client_geometry_hints(client_t
*c
, area_t geometry
)
723 int32_t basew
, baseh
, minw
, minh
;
725 /* base size is substituted with min size if not specified */
726 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_SIZE
)
728 basew
= c
->size_hints
.base_width
;
729 baseh
= c
->size_hints
.base_height
;
731 else if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MIN_SIZE
)
733 basew
= c
->size_hints
.min_width
;
734 baseh
= c
->size_hints
.min_height
;
739 /* min size is substituted with base size if not specified */
740 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MIN_SIZE
)
742 minw
= c
->size_hints
.min_width
;
743 minh
= c
->size_hints
.min_height
;
745 else if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_SIZE
)
747 minw
= c
->size_hints
.base_width
;
748 minh
= c
->size_hints
.base_height
;
753 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_ASPECT
754 && c
->size_hints
.min_aspect_num
> 0
755 && c
->size_hints
.min_aspect_den
> 0
756 && geometry
.height
- baseh
> 0
757 && geometry
.width
- basew
> 0)
759 double dx
= (double) (geometry
.width
- basew
);
760 double dy
= (double) (geometry
.height
- baseh
);
761 double min
= (double) c
->size_hints
.min_aspect_num
/ (double) c
->size_hints
.min_aspect_den
;
762 double max
= (double) c
->size_hints
.max_aspect_num
/ (double) c
->size_hints
.min_aspect_den
;
763 double ratio
= dx
/ dy
;
764 if(max
> 0 && min
> 0 && ratio
> 0)
768 dy
= (dx
* min
+ dy
) / (min
* min
+ 1);
770 geometry
.width
= (int) dx
+ basew
;
771 geometry
.height
= (int) dy
+ baseh
;
775 dy
= (dx
* min
+ dy
) / (max
* max
+ 1);
777 geometry
.width
= (int) dx
+ basew
;
778 geometry
.height
= (int) dy
+ baseh
;
784 geometry
.width
= MAX(geometry
.width
, minw
);
786 geometry
.height
= MAX(geometry
.height
, minh
);
788 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MAX_SIZE
)
790 if(c
->size_hints
.max_width
)
791 geometry
.width
= MIN(geometry
.width
, c
->size_hints
.max_width
);
792 if(c
->size_hints
.max_height
)
793 geometry
.height
= MIN(geometry
.height
, c
->size_hints
.max_height
);
796 if(c
->size_hints
.flags
& (XCB_SIZE_HINT_P_RESIZE_INC
| XCB_SIZE_HINT_BASE_SIZE
)
797 && c
->size_hints
.width_inc
&& c
->size_hints
.height_inc
)
799 uint16_t t1
= geometry
.width
, t2
= geometry
.height
;
800 unsigned_subtract(t1
, basew
);
801 unsigned_subtract(t2
, baseh
);
802 geometry
.width
-= t1
% c
->size_hints
.width_inc
;
803 geometry
.height
-= t2
% c
->size_hints
.height_inc
;
809 /** Resize client window.
810 * The sizse given as parameters are with titlebar and borders!
811 * \param c Client to resize.
812 * \param geometry New window geometry.
813 * \param hints Use size hints.
814 * \return true if an actual resize occurred.
817 client_resize(client_t
*c
, area_t geometry
, bool hints
)
819 area_t geometry_internal
;
822 /* offscreen appearance fixes */
823 area
= display_area_get(c
->phys_screen
);
825 if(geometry
.x
> area
.width
)
826 geometry
.x
= area
.width
- geometry
.width
;
827 if(geometry
.y
> area
.height
)
828 geometry
.y
= area
.height
- geometry
.height
;
829 if(geometry
.x
+ geometry
.width
< 0)
831 if(geometry
.y
+ geometry
.height
< 0)
834 /* Real client geometry, please keep it contained to C code at the very least. */
835 geometry_internal
= titlebar_geometry_remove(c
->titlebar
, c
->border_width
, geometry
);
838 geometry_internal
= client_geometry_hints(c
, geometry_internal
);
840 if(geometry_internal
.width
== 0 || geometry_internal
.height
== 0)
843 /* Also let client hints propegate to the "official" geometry. */
844 geometry
= titlebar_geometry_add(c
->titlebar
, c
->border_width
, geometry_internal
);
846 if(c
->geometries
.internal
.x
!= geometry_internal
.x
847 || c
->geometries
.internal
.y
!= geometry_internal
.y
848 || c
->geometries
.internal
.width
!= geometry_internal
.width
849 || c
->geometries
.internal
.height
!= geometry_internal
.height
)
851 screen_t
*new_screen
= screen_getbycoord(c
->screen
,
852 geometry_internal
.x
, geometry_internal
.y
);
854 /* Values to configure a window is an array where values are
855 * stored according to 'value_mask' */
858 c
->geometries
.internal
.x
= values
[0] = geometry_internal
.x
;
859 c
->geometries
.internal
.y
= values
[1] = geometry_internal
.y
;
860 c
->geometries
.internal
.width
= values
[2] = geometry_internal
.width
;
861 c
->geometries
.internal
.height
= values
[3] = geometry_internal
.height
;
863 /* Also store geometry including border and titlebar. */
864 c
->geometry
= geometry
;
866 titlebar_update_geometry(c
);
868 /* Ignore all spurious enter/leave notify events */
869 client_ignore_enterleave_events();
871 xcb_configure_window(globalconf
.connection
, c
->window
,
872 XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
873 | XCB_CONFIG_WINDOW_WIDTH
| XCB_CONFIG_WINDOW_HEIGHT
,
876 client_restore_enterleave_events();
878 screen_client_moveto(c
, new_screen
, true, false);
881 hook_property(c
, "geometry");
889 /** Set a client minimized, or not.
890 * \param L The Lua VM state.
891 * \param cidx The client index.
892 * \param s Set or not the client minimized.
895 client_set_minimized(lua_State
*L
, int cidx
, bool s
)
897 client_t
*c
= luaA_client_checkudata(L
, cidx
);
899 if(c
->minimized
!= s
)
901 client_need_reban(c
);
903 client_need_reban(c
);
905 window_state_set(c
->window
, XCB_WM_STATE_ICONIC
);
907 window_state_set(c
->window
, XCB_WM_STATE_NORMAL
);
908 ewmh_client_update_hints(c
);
910 hook_property(c
, "minimized");
911 luaA_object_emit_signal(L
, cidx
, "property::minimized", 0);
915 /** Set a client sticky, or not.
916 * \param L The Lua VM state.
917 * \param cidx The client index.
918 * \param s Set or not the client sticky.
921 client_set_sticky(lua_State
*L
, int cidx
, bool s
)
923 client_t
*c
= luaA_client_checkudata(L
, cidx
);
927 client_need_reban(c
);
929 client_need_reban(c
);
930 ewmh_client_update_hints(c
);
931 hook_property(c
, "sticky");
932 luaA_object_emit_signal(L
, cidx
, "property::sticky", 0);
936 /** Set a client fullscreen, or not.
937 * \param L The Lua VM state.
938 * \param cidx The client index.
939 * \param s Set or not the client fullscreen.
942 client_set_fullscreen(lua_State
*L
, int cidx
, bool s
)
944 client_t
*c
= luaA_client_checkudata(L
, cidx
);
946 if(c
->fullscreen
!= s
)
950 /* become fullscreen! */
953 /* Make sure the current geometry is stored without titlebar. */
954 titlebar_ban(c
->titlebar
);
955 /* remove any max state */
956 client_set_maximized_horizontal(L
, cidx
, false);
957 client_set_maximized_vertical(L
, cidx
, false);
958 /* You can only be part of one of the special layers. */
959 client_set_below(L
, cidx
, false);
960 client_set_above(L
, cidx
, false);
961 client_set_ontop(L
, cidx
, false);
963 geometry
= screen_area_get(c
->screen
, false);
964 c
->geometries
.fullscreen
= c
->geometry
;
965 c
->border_width_fs
= c
->border_width
;
966 client_set_border_width(L
, cidx
, 0);
967 c
->fullscreen
= true;
971 geometry
= c
->geometries
.fullscreen
;
972 c
->fullscreen
= false;
973 client_set_border_width(L
, cidx
, c
->border_width_fs
);
975 client_resize(c
, geometry
, false);
977 ewmh_client_update_hints(c
);
978 hook_property(c
, "fullscreen");
979 luaA_object_emit_signal(L
, cidx
, "property::fullscreen", 0);
983 /** Set a client horizontally maximized.
984 * \param L The Lua VM state.
985 * \param cidx The client index.
986 * \param s The maximized status.
989 client_set_maximized_horizontal(lua_State
*L
, int cidx
, bool s
)
991 client_t
*c
= luaA_client_checkudata(L
, cidx
);
993 if(c
->maximized_horizontal
!= s
)
997 if((c
->maximized_horizontal
= s
))
999 /* remove fullscreen mode */
1000 client_set_fullscreen(L
, cidx
, false);
1002 geometry
= screen_area_get(c
->screen
, true);
1003 geometry
.y
= c
->geometry
.y
;
1004 geometry
.height
= c
->geometry
.height
;
1005 c
->geometries
.max
.x
= c
->geometry
.x
;
1006 c
->geometries
.max
.width
= c
->geometry
.width
;
1010 geometry
= c
->geometry
;
1011 geometry
.x
= c
->geometries
.max
.x
;
1012 geometry
.width
= c
->geometries
.max
.width
;
1015 client_resize(c
, geometry
, c
->size_hints_honor
);
1017 ewmh_client_update_hints(c
);
1018 hook_property(c
, "maximized_horizontal");
1019 luaA_object_emit_signal(L
, cidx
, "property::maximized_horizontal", 0);
1023 /** Set a client vertically maximized.
1024 * \param L The Lua VM state.
1025 * \param cidx The client index.
1026 * \param s The maximized status.
1029 client_set_maximized_vertical(lua_State
*L
, int cidx
, bool s
)
1031 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1033 if(c
->maximized_vertical
!= s
)
1037 if((c
->maximized_vertical
= s
))
1039 /* remove fullscreen mode */
1040 client_set_fullscreen(L
, cidx
, false);
1042 geometry
= screen_area_get(c
->screen
, true);
1043 geometry
.x
= c
->geometry
.x
;
1044 geometry
.width
= c
->geometry
.width
;
1045 c
->geometries
.max
.y
= c
->geometry
.y
;
1046 c
->geometries
.max
.height
= c
->geometry
.height
;
1050 geometry
= c
->geometry
;
1051 geometry
.y
= c
->geometries
.max
.y
;
1052 geometry
.height
= c
->geometries
.max
.height
;
1055 client_resize(c
, geometry
, c
->size_hints_honor
);
1057 ewmh_client_update_hints(c
);
1058 hook_property(c
, "maximized_vertical");
1059 luaA_object_emit_signal(L
, cidx
, "property::maximized_vertical", 0);
1063 /** Set a client above, or not.
1064 * \param L The Lua VM state.
1065 * \param cidx The client index.
1066 * \param s Set or not the client above.
1069 client_set_above(lua_State
*L
, int cidx
, bool s
)
1071 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1075 /* You can only be part of one of the special layers. */
1078 client_set_below(L
, cidx
, false);
1079 client_set_ontop(L
, cidx
, false);
1080 client_set_fullscreen(L
, cidx
, false);
1084 ewmh_client_update_hints(c
);
1086 hook_property(c
, "above");
1087 luaA_object_emit_signal(L
, cidx
, "property::above", 0);
1091 /** Set a client below, or not.
1092 * \param L The Lua VM state.
1093 * \param cidx The client index.
1094 * \param s Set or not the client below.
1097 client_set_below(lua_State
*L
, int cidx
, bool s
)
1099 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1103 /* You can only be part of one of the special layers. */
1106 client_set_above(L
, cidx
, false);
1107 client_set_ontop(L
, cidx
, false);
1108 client_set_fullscreen(L
, cidx
, false);
1112 ewmh_client_update_hints(c
);
1114 hook_property(c
, "below");
1115 luaA_object_emit_signal(L
, cidx
, "property::below", 0);
1119 /** Set a client modal, or not.
1120 * \param L The Lua VM state.
1121 * \param cidx The client index.
1122 * \param s Set or not the client modal attribute.
1125 client_set_modal(lua_State
*L
, int cidx
, bool s
)
1127 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1133 ewmh_client_update_hints(c
);
1135 hook_property(c
, "modal");
1136 luaA_object_emit_signal(L
, cidx
, "property::modal", 0);
1140 /** Set a client ontop, or not.
1141 * \param L The Lua VM state.
1142 * \param cidx The client index.
1143 * \param s Set or not the client ontop attribute.
1146 client_set_ontop(lua_State
*L
, int cidx
, bool s
)
1148 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1152 /* You can only be part of one of the special layers. */
1155 client_set_above(L
, cidx
, false);
1156 client_set_below(L
, cidx
, false);
1157 client_set_fullscreen(L
, cidx
, false);
1162 hook_property(c
, "ontop");
1163 luaA_object_emit_signal(L
, cidx
, "property::ontop", 0);
1167 /** Set a client skip taskbar attribute.
1168 * \param L Tha Lua VM state.
1169 * \param cidx The client index.
1170 * \param s Set or not the client skip taskbar attribute.
1173 client_set_skip_taskbar(lua_State
*L
, int cidx
, bool s
)
1175 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1177 if(c
->skip_taskbar
!= s
)
1179 c
->skip_taskbar
= s
;
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.
1188 client_unban(client_t
*c
)
1192 xcb_map_window(globalconf
.connection
, c
->window
);
1194 c
->isbanned
= false;
1198 /** Unmanage a client.
1199 * \param c The client.
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
)
1220 /* remove client from global list and everywhere else */
1221 foreach(elem
, globalconf
.clients
)
1224 client_array_remove(&globalconf
.clients
, elem
);
1227 stack_client_remove(c
);
1228 for(int i
= 0; i
< tags
->len
; i
++)
1229 untag_client(c
, tags
->tab
[i
]);
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 */
1256 luaA_object_unref(globalconf
.L
, c
);
1259 /** Kill a client via a WM_DELETE_WINDOW request or KillClient if not
1261 * \param c The client to kill.
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 */
1273 ev
.response_type
= XCB_CLIENT_MESSAGE
;
1274 ev
.window
= c
->window
;
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
);
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.
1291 * \lparam An optional screen nunmber.
1292 * \lreturn A table with all clients.
1295 luaA_client_get(lua_State
*L
)
1299 screen
= luaL_optnumber(L
, 1, 0) - 1;
1304 foreach(c
, globalconf
.clients
)
1306 luaA_object_push(L
, *c
);
1307 lua_rawseti(L
, -2, i
++);
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
++);
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.
1328 * \lreturn A boolean value, true if the client is visible, false otherwise.
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
));
1338 /** Set client border width.
1339 * \param L The Lua VM state.
1340 * \param cidx The client index.
1341 * \param width The border width.
1344 client_set_border_width(lua_State
*L
, int cidx
, int width
)
1346 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1349 if(width
> 0 && (c
->type
== WINDOW_TYPE_DOCK
1350 || c
->type
== WINDOW_TYPE_SPLASH
1351 || c
->type
== WINDOW_TYPE_DESKTOP
1355 if(width
== c
->border_width
|| width
< 0)
1358 /* disallow change of border width if the client is fullscreen */
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.
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);
1397 hook_property(c
, "icon");
1401 * \param L The Lua VM state.
1407 luaA_client_kill(lua_State
*L
)
1409 client_t
*c
= luaA_client_checkudata(L
, 1);
1414 /** Swap a client with another one.
1415 * \param L The Lua VM state.
1418 * \lparam A client to swap with.
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);
1428 client_t
**ref_c
= NULL
, **ref_swap
= NULL
;
1429 foreach(item
, globalconf
.clients
)
1433 else if(*item
== swap
)
1435 if(ref_c
&& ref_swap
)
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);
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.
1459 luaA_client_tags(lua_State
*L
)
1461 client_t
*c
= luaA_client_checkudata(L
, 1);
1462 tag_array_t
*tags
= &c
->screen
->tags
;
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
]);
1471 while(lua_next(L
, 2))
1478 if(is_client_tagged(c
, *tag
))
1480 luaA_object_push(L
, *tag
);
1481 lua_rawseti(L
, -2, ++j
);
1487 /** Raise a client on top of others which are on the same layer.
1488 * \param L The Lua VM state.
1493 luaA_client_raise(lua_State
*L
)
1495 client_t
*c
= luaA_client_checkudata(L
, 1);
1500 /** Lower a client on bottom of others which are on the same layer.
1501 * \param L The Lua VM state.
1506 luaA_client_lower(lua_State
*L
)
1508 client_t
*c
= luaA_client_checkudata(L
, 1);
1513 /** Redraw a client by unmapping and mapping it quickly.
1514 * \param L The Lua VM state.
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
)
1539 /** Stop managing a client.
1540 * \param L The Lua VM state.
1541 * \return The number of elements pushed on stack.
1546 luaA_client_unmanage(lua_State
*L
)
1548 client_t
*c
= luaA_client_checkudata(L
, 1);
1553 /** Return client geometry.
1554 * \param L The Lua VM state.
1555 * \return The number of elements pushed on stack.
1557 * \lparam A table with new coordinates, or none.
1558 * \lreturn A table with client coordinates.
1561 luaA_client_geometry(lua_State
*L
)
1563 client_t
*c
= luaA_client_checkudata(L
, 1);
1565 if(lua_gettop(L
) == 2)
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
;
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.
1593 * \lparam A table with new strut values, or none.
1594 * \lreturn A table with strut values.
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
);
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, true);
1626 luaA_client_set_hidden(lua_State
*L
, client_t
*c
)
1628 bool b
= luaA_checkboolean(L
, -1);
1631 client_need_reban(c
);
1633 client_need_reban(c
);
1634 hook_property(c
, "hidden");
1635 luaA_object_emit_signal(L
, -3, "property::screen", 0);
1641 luaA_client_set_minimized(lua_State
*L
, client_t
*c
)
1643 client_set_minimized(L
, -3, luaA_checkboolean(L
, -1));
1648 luaA_client_set_fullscreen(lua_State
*L
, client_t
*c
)
1650 client_set_fullscreen(L
, -3, luaA_checkboolean(L
, -1));
1655 luaA_client_set_modal(lua_State
*L
, client_t
*c
)
1657 client_set_modal(L
, -3, luaA_checkboolean(L
, -1));
1662 luaA_client_set_maximized_horizontal(lua_State
*L
, client_t
*c
)
1664 client_set_maximized_horizontal(L
, -3, luaA_checkboolean(L
, -1));
1669 luaA_client_set_maximized_vertical(lua_State
*L
, client_t
*c
)
1671 client_set_maximized_vertical(L
, -3, luaA_checkboolean(L
, -1));
1676 luaA_client_set_icon(lua_State
*L
, client_t
*c
)
1678 client_set_icon(L
, -3, -1);
1683 luaA_client_set_opacity(lua_State
*L
, client_t
*c
)
1685 if(lua_isnil(L
, -1))
1686 client_set_opacity(L
, -3, -1);
1688 client_set_opacity(L
, -3, luaL_checknumber(L
, -1));
1693 luaA_client_set_sticky(lua_State
*L
, client_t
*c
)
1695 client_set_sticky(L
, -3, luaA_checkboolean(L
, -1));
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);
1709 luaA_client_set_border_width(lua_State
*L
, client_t
*c
)
1711 client_set_border_width(L
, -3, luaL_checknumber(L
, -1));
1716 luaA_client_set_ontop(lua_State
*L
, client_t
*c
)
1718 client_set_ontop(L
, -3, luaA_checkboolean(L
, -1));
1723 luaA_client_set_below(lua_State
*L
, client_t
*c
)
1725 client_set_below(L
, -3, luaA_checkboolean(L
, -1));
1730 luaA_client_set_above(lua_State
*L
, client_t
*c
)
1732 client_set_above(L
, -3, luaA_checkboolean(L
, -1));
1737 luaA_client_set_urgent(lua_State
*L
, client_t
*c
)
1739 client_set_urgent(L
, -3, luaA_checkboolean(L
, -1));
1744 luaA_client_set_border_color(lua_State
*L
, client_t
*c
)
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);
1759 luaA_client_set_titlebar(lua_State
*L
, client_t
*c
)
1761 if(lua_isnil(L
, -1))
1762 titlebar_client_detach(c
);
1764 titlebar_client_attach(c
);
1769 luaA_client_set_skip_taskbar(lua_State
*L
, client_t
*c
)
1771 client_set_skip_taskbar(L
, -3, luaA_checkboolean(L
, -1));
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
)
1804 luaA_client_get_content(lua_State
*L
, client_t
*c
)
1806 xcb_image_t
*ximage
= xcb_image_get(globalconf
.connection
,
1809 c
->geometries
.internal
.width
,
1810 c
->geometries
.internal
.height
,
1811 ~0, XCB_IMAGE_FORMAT_Z_PIXMAP
);
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
);
1836 luaA_client_get_type(lua_State
*L
, client_t
*c
)
1840 case WINDOW_TYPE_DESKTOP
:
1841 lua_pushliteral(L
, "desktop");
1843 case WINDOW_TYPE_DOCK
:
1844 lua_pushliteral(L
, "dock");
1846 case WINDOW_TYPE_SPLASH
:
1847 lua_pushliteral(L
, "splash");
1849 case WINDOW_TYPE_DIALOG
:
1850 lua_pushliteral(L
, "dialog");
1852 case WINDOW_TYPE_MENU
:
1853 lua_pushliteral(L
, "menu");
1855 case WINDOW_TYPE_TOOLBAR
:
1856 lua_pushliteral(L
, "toolbar");
1858 case WINDOW_TYPE_UTILITY
:
1859 lua_pushliteral(L
, "utility");
1861 case WINDOW_TYPE_DROPDOWN_MENU
:
1862 lua_pushliteral(L
, "dropdown_menu");
1864 case WINDOW_TYPE_POPUP_MENU
:
1865 lua_pushliteral(L
, "popup_menu");
1867 case WINDOW_TYPE_TOOLTIP
:
1868 lua_pushliteral(L
, "tooltip");
1870 case WINDOW_TYPE_NOTIFICATION
:
1871 lua_pushliteral(L
, "notification");
1873 case WINDOW_TYPE_COMBO
:
1874 lua_pushliteral(L
, "combo");
1876 case WINDOW_TYPE_DND
:
1877 lua_pushliteral(L
, "dnd");
1879 case WINDOW_TYPE_NORMAL
:
1880 lua_pushliteral(L
, "normal");
1887 luaA_client_get_screen(lua_State
*L
, client_t
*c
)
1889 lua_pushnumber(L
, 1 + screen_array_indexof(&globalconf
.screens
, c
->screen
));
1894 luaA_client_get_icon(lua_State
*L
, client_t
*c
)
1896 return luaA_object_push_item(L
, -2, c
->icon
);
1900 luaA_client_get_titlebar(lua_State
*L
, client_t
*c
)
1902 return luaA_object_push_item(L
, -2, c
->titlebar
);
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";
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
);
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";
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
)
1992 lua_pushliteral(L
, "north_west");
1994 case XCB_GRAVITY_NORTH
:
1995 lua_pushliteral(L
, "north");
1997 case XCB_GRAVITY_NORTH_EAST
:
1998 lua_pushliteral(L
, "north_east");
2000 case XCB_GRAVITY_WEST
:
2001 lua_pushliteral(L
, "west");
2003 case XCB_GRAVITY_CENTER
:
2004 lua_pushliteral(L
, "center");
2006 case XCB_GRAVITY_EAST
:
2007 lua_pushliteral(L
, "east");
2009 case XCB_GRAVITY_SOUTH_WEST
:
2010 lua_pushliteral(L
, "south_west");
2012 case XCB_GRAVITY_SOUTH
:
2013 lua_pushliteral(L
, "south");
2015 case XCB_GRAVITY_SOUTH_EAST
:
2016 lua_pushliteral(L
, "south_east");
2018 case XCB_GRAVITY_STATIC
:
2019 lua_pushliteral(L
, "static");
2022 lua_setfield(L
, -2, "win_gravity");
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.
2033 * \lparam An array of mouse button bindings objects, or nothing.
2034 * \return The array of mouse button bindings objects of this client.
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.
2057 * \lparam An array of key bindings objects, or nothing.
2058 * \return The array of key bindings objects of this client.
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
);
2078 * \param L The Lua VM state.
2079 * \return The number of pushed elements.
2082 luaA_client_module_index(lua_State
*L
)
2085 const char *buf
= luaL_checklstring(L
, 2, &len
);
2087 switch(a_tokenize(buf
, len
))
2090 return luaA_object_push(globalconf
.L
, globalconf
.screen_focus
->client_focus
);
2097 /* Client module new index.
2098 * \param L The Lua VM state.
2099 * \return The number of pushed elements.
2102 luaA_client_module_newindex(lua_State
*L
)
2105 const char *buf
= luaL_checklstring(L
, 2, &len
);
2108 switch(a_tokenize(buf
, len
))
2111 c
= luaA_client_checkudata(L
, 3);
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
},
2133 static const struct luaL_reg client_meta
[] =
2135 LUA_OBJECT_META(client
)
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
},
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
,
2158 (lua_class_propfunc_t
) luaA_client_get_name
,
2160 luaA_class_add_property(&client_class
, A_TK_TRANSIENT_FOR
,
2162 (lua_class_propfunc_t
) luaA_client_get_transient_for
,
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
,
2170 (lua_class_propfunc_t
) luaA_client_get_content
,
2172 luaA_class_add_property(&client_class
, A_TK_TYPE
,
2174 (lua_class_propfunc_t
) luaA_client_get_type
,
2176 luaA_class_add_property(&client_class
, A_TK_CLASS
,
2178 (lua_class_propfunc_t
) luaA_client_get_class
,
2180 luaA_class_add_property(&client_class
, A_TK_INSTANCE
,
2182 (lua_class_propfunc_t
) luaA_client_get_instance
,
2184 luaA_class_add_property(&client_class
, A_TK_ROLE
,
2186 (lua_class_propfunc_t
) luaA_client_get_role
,
2188 luaA_class_add_property(&client_class
, A_TK_PID
,
2190 (lua_class_propfunc_t
) luaA_client_get_pid
,
2192 luaA_class_add_property(&client_class
, A_TK_WINDOW
,
2194 (lua_class_propfunc_t
) luaA_client_get_window
,
2196 luaA_class_add_property(&client_class
, A_TK_LEADER_WINDOW
,
2198 (lua_class_propfunc_t
) luaA_client_get_leader_window
,
2200 luaA_class_add_property(&client_class
, A_TK_MACHINE
,
2202 (lua_class_propfunc_t
) luaA_client_get_machine
,
2204 luaA_class_add_property(&client_class
, A_TK_ICON_NAME
,
2206 (lua_class_propfunc_t
) luaA_client_get_icon_name
,
2208 luaA_class_add_property(&client_class
, A_TK_SCREEN
,
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
,
2230 (lua_class_propfunc_t
) luaA_client_get_group_window
,
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
,
2286 (lua_class_propfunc_t
) luaA_client_get_size_hints
,
2290 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80