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 screen_client_moveto(c
, screen
, true);
651 /* Push client in stack */
654 /* update window title */
655 property_update_wm_name(c
, NULL
);
656 property_update_wm_icon_name(c
, NULL
);
657 property_update_wm_class(c
, NULL
);
658 property_update_wm_protocols(c
, NULL
);
661 ewmh_process_client_strut(c
, NULL
);
663 ewmh_update_net_client_list(c
->phys_screen
);
665 /* Always stay in NORMAL_STATE. Even though iconified seems more
666 * appropriate sometimes. The only possible loss is that clients not using
667 * visibility events may continue to proces data (when banned).
668 * Without any exposes or other events the cost should be fairly limited though.
670 * Some clients may expect the window to be unmapped when STATE_ICONIFIED.
671 * Two conflicting parts of the ICCCM v2.0 (section 4.1.4):
673 * "Normal -> Iconic - The client should send a ClientMessage event as described later in this section."
674 * (note no explicit mention of unmapping, while Normal->Widthdrawn does mention that)
676 * "Once a client's window has left the Withdrawn state, the window will be mapped
677 * if it is in the Normal state and the window will be unmapped if it is in the Iconic state."
679 * At this stage it's just safer to keep it in normal state and avoid confusion.
681 window_state_set(c
->window
, XCB_WM_STATE_NORMAL
);
685 /* Request our response */
686 xcb_get_property_reply_t
*reply
=
687 xcb_get_property_reply(globalconf
.connection
, startup_id_q
, NULL
);
688 /* Say spawn that a client has been started, with startup id as argument */
689 char *startup_id
= xutil_get_text_property_from_reply(reply
);
691 spawn_start_notify(c
, startup_id
);
692 p_delete(&startup_id
);
695 /* Call hook to notify list change */
696 if(globalconf
.hooks
.clients
!= LUA_REFNIL
)
697 luaA_dofunction_from_registry(globalconf
.L
, globalconf
.hooks
.clients
, 0, 0);
699 luaA_class_emit_signal(globalconf
.L
, &client_class
, "list", 0);
702 if(globalconf
.hooks
.manage
!= LUA_REFNIL
)
704 luaA_object_push(globalconf
.L
, c
);
705 lua_pushboolean(globalconf
.L
, startup
);
706 luaA_dofunction_from_registry(globalconf
.L
, globalconf
.hooks
.manage
, 2, 0);
709 luaA_object_push(globalconf
.L
, c
);
710 lua_pushboolean(globalconf
.L
, startup
);
711 luaA_class_emit_signal(globalconf
.L
, &client_class
, "manage", 2);
714 /** Compute client geometry with respect to its geometry hints.
715 * \param c The client.
716 * \param geometry The geometry that the client might receive.
717 * \return The geometry the client must take respecting its hints.
720 client_geometry_hints(client_t
*c
, area_t geometry
)
722 int32_t basew
, baseh
, minw
, minh
;
724 /* base size is substituted with min size if not specified */
725 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_SIZE
)
727 basew
= c
->size_hints
.base_width
;
728 baseh
= c
->size_hints
.base_height
;
730 else if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MIN_SIZE
)
732 basew
= c
->size_hints
.min_width
;
733 baseh
= c
->size_hints
.min_height
;
738 /* min size is substituted with base size if not specified */
739 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MIN_SIZE
)
741 minw
= c
->size_hints
.min_width
;
742 minh
= c
->size_hints
.min_height
;
744 else if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_SIZE
)
746 minw
= c
->size_hints
.base_width
;
747 minh
= c
->size_hints
.base_height
;
752 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_ASPECT
753 && c
->size_hints
.min_aspect_num
> 0
754 && c
->size_hints
.min_aspect_den
> 0
755 && geometry
.height
- baseh
> 0
756 && geometry
.width
- basew
> 0)
758 double dx
= (double) (geometry
.width
- basew
);
759 double dy
= (double) (geometry
.height
- baseh
);
760 double min
= (double) c
->size_hints
.min_aspect_num
/ (double) c
->size_hints
.min_aspect_den
;
761 double max
= (double) c
->size_hints
.max_aspect_num
/ (double) c
->size_hints
.min_aspect_den
;
762 double ratio
= dx
/ dy
;
763 if(max
> 0 && min
> 0 && ratio
> 0)
767 dy
= (dx
* min
+ dy
) / (min
* min
+ 1);
769 geometry
.width
= (int) dx
+ basew
;
770 geometry
.height
= (int) dy
+ baseh
;
774 dy
= (dx
* min
+ dy
) / (max
* max
+ 1);
776 geometry
.width
= (int) dx
+ basew
;
777 geometry
.height
= (int) dy
+ baseh
;
783 geometry
.width
= MAX(geometry
.width
, minw
);
785 geometry
.height
= MAX(geometry
.height
, minh
);
787 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MAX_SIZE
)
789 if(c
->size_hints
.max_width
)
790 geometry
.width
= MIN(geometry
.width
, c
->size_hints
.max_width
);
791 if(c
->size_hints
.max_height
)
792 geometry
.height
= MIN(geometry
.height
, c
->size_hints
.max_height
);
795 if(c
->size_hints
.flags
& (XCB_SIZE_HINT_P_RESIZE_INC
| XCB_SIZE_HINT_BASE_SIZE
)
796 && c
->size_hints
.width_inc
&& c
->size_hints
.height_inc
)
798 uint16_t t1
= geometry
.width
, t2
= geometry
.height
;
799 unsigned_subtract(t1
, basew
);
800 unsigned_subtract(t2
, baseh
);
801 geometry
.width
-= t1
% c
->size_hints
.width_inc
;
802 geometry
.height
-= t2
% c
->size_hints
.height_inc
;
808 /** Resize client window.
809 * The sizse given as parameters are with titlebar and borders!
810 * \param c Client to resize.
811 * \param geometry New window geometry.
812 * \param hints Use size hints.
813 * \return true if an actual resize occurred.
816 client_resize(client_t
*c
, area_t geometry
, bool hints
)
818 area_t geometry_internal
;
821 /* offscreen appearance fixes */
822 area
= display_area_get(c
->phys_screen
);
824 if(geometry
.x
> area
.width
)
825 geometry
.x
= area
.width
- geometry
.width
;
826 if(geometry
.y
> area
.height
)
827 geometry
.y
= area
.height
- geometry
.height
;
828 if(geometry
.x
+ geometry
.width
< 0)
830 if(geometry
.y
+ geometry
.height
< 0)
833 /* Real client geometry, please keep it contained to C code at the very least. */
834 geometry_internal
= titlebar_geometry_remove(c
->titlebar
, c
->border_width
, geometry
);
837 geometry_internal
= client_geometry_hints(c
, geometry_internal
);
839 if(geometry_internal
.width
== 0 || geometry_internal
.height
== 0)
842 /* Also let client hints propegate to the "official" geometry. */
843 geometry
= titlebar_geometry_add(c
->titlebar
, c
->border_width
, geometry_internal
);
845 if(c
->geometries
.internal
.x
!= geometry_internal
.x
846 || c
->geometries
.internal
.y
!= geometry_internal
.y
847 || c
->geometries
.internal
.width
!= geometry_internal
.width
848 || c
->geometries
.internal
.height
!= geometry_internal
.height
)
850 screen_t
*new_screen
= screen_getbycoord(c
->screen
,
851 geometry_internal
.x
, geometry_internal
.y
);
853 /* Values to configure a window is an array where values are
854 * stored according to 'value_mask' */
857 c
->geometries
.internal
.x
= values
[0] = geometry_internal
.x
;
858 c
->geometries
.internal
.y
= values
[1] = geometry_internal
.y
;
859 c
->geometries
.internal
.width
= values
[2] = geometry_internal
.width
;
860 c
->geometries
.internal
.height
= values
[3] = geometry_internal
.height
;
862 /* Also store geometry including border and titlebar. */
863 c
->geometry
= geometry
;
865 titlebar_update_geometry(c
);
867 /* Ignore all spurious enter/leave notify events */
868 client_ignore_enterleave_events();
870 xcb_configure_window(globalconf
.connection
, c
->window
,
871 XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
872 | XCB_CONFIG_WINDOW_WIDTH
| XCB_CONFIG_WINDOW_HEIGHT
,
875 client_restore_enterleave_events();
877 screen_client_moveto(c
, new_screen
, false);
880 hook_property(c
, "geometry");
888 /** Set a client minimized, or not.
889 * \param L The Lua VM state.
890 * \param cidx The client index.
891 * \param s Set or not the client minimized.
894 client_set_minimized(lua_State
*L
, int cidx
, bool s
)
896 client_t
*c
= luaA_client_checkudata(L
, cidx
);
898 if(c
->minimized
!= s
)
900 client_need_reban(c
);
902 client_need_reban(c
);
904 window_state_set(c
->window
, XCB_WM_STATE_ICONIC
);
906 window_state_set(c
->window
, XCB_WM_STATE_NORMAL
);
907 ewmh_client_update_hints(c
);
909 hook_property(c
, "minimized");
910 luaA_object_emit_signal(L
, cidx
, "property::minimized", 0);
914 /** Set a client sticky, or not.
915 * \param L The Lua VM state.
916 * \param cidx The client index.
917 * \param s Set or not the client sticky.
920 client_set_sticky(lua_State
*L
, int cidx
, bool s
)
922 client_t
*c
= luaA_client_checkudata(L
, cidx
);
926 client_need_reban(c
);
928 client_need_reban(c
);
929 ewmh_client_update_hints(c
);
930 hook_property(c
, "sticky");
931 luaA_object_emit_signal(L
, cidx
, "property::sticky", 0);
935 /** Set a client fullscreen, or not.
936 * \param L The Lua VM state.
937 * \param cidx The client index.
938 * \param s Set or not the client fullscreen.
941 client_set_fullscreen(lua_State
*L
, int cidx
, bool s
)
943 client_t
*c
= luaA_client_checkudata(L
, cidx
);
945 if(c
->fullscreen
!= s
)
949 /* become fullscreen! */
952 /* Make sure the current geometry is stored without titlebar. */
953 titlebar_ban(c
->titlebar
);
954 /* remove any max state */
955 client_set_maximized_horizontal(L
, cidx
, false);
956 client_set_maximized_vertical(L
, cidx
, false);
957 /* You can only be part of one of the special layers. */
958 client_set_below(L
, cidx
, false);
959 client_set_above(L
, cidx
, false);
960 client_set_ontop(L
, cidx
, false);
962 geometry
= screen_area_get(c
->screen
, false);
963 c
->geometries
.fullscreen
= c
->geometry
;
964 c
->border_width_fs
= c
->border_width
;
965 client_set_border_width(L
, cidx
, 0);
966 c
->fullscreen
= true;
970 geometry
= c
->geometries
.fullscreen
;
971 c
->fullscreen
= false;
972 client_set_border_width(L
, cidx
, c
->border_width_fs
);
974 client_resize(c
, geometry
, false);
976 ewmh_client_update_hints(c
);
977 hook_property(c
, "fullscreen");
978 luaA_object_emit_signal(L
, cidx
, "property::fullscreen", 0);
982 /** Set a client horizontally maximized.
983 * \param L The Lua VM state.
984 * \param cidx The client index.
985 * \param s The maximized status.
988 client_set_maximized_horizontal(lua_State
*L
, int cidx
, bool s
)
990 client_t
*c
= luaA_client_checkudata(L
, cidx
);
992 if(c
->maximized_horizontal
!= s
)
996 if((c
->maximized_horizontal
= s
))
998 /* remove fullscreen mode */
999 client_set_fullscreen(L
, cidx
, false);
1001 geometry
= screen_area_get(c
->screen
, true);
1002 geometry
.y
= c
->geometry
.y
;
1003 geometry
.height
= c
->geometry
.height
;
1004 c
->geometries
.max
.x
= c
->geometry
.x
;
1005 c
->geometries
.max
.width
= c
->geometry
.width
;
1009 geometry
= c
->geometry
;
1010 geometry
.x
= c
->geometries
.max
.x
;
1011 geometry
.width
= c
->geometries
.max
.width
;
1014 client_resize(c
, geometry
, c
->size_hints_honor
);
1016 ewmh_client_update_hints(c
);
1017 hook_property(c
, "maximized_horizontal");
1018 luaA_object_emit_signal(L
, cidx
, "property::maximized_horizontal", 0);
1022 /** Set a client vertically maximized.
1023 * \param L The Lua VM state.
1024 * \param cidx The client index.
1025 * \param s The maximized status.
1028 client_set_maximized_vertical(lua_State
*L
, int cidx
, bool s
)
1030 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1032 if(c
->maximized_vertical
!= s
)
1036 if((c
->maximized_vertical
= s
))
1038 /* remove fullscreen mode */
1039 client_set_fullscreen(L
, cidx
, false);
1041 geometry
= screen_area_get(c
->screen
, true);
1042 geometry
.x
= c
->geometry
.x
;
1043 geometry
.width
= c
->geometry
.width
;
1044 c
->geometries
.max
.y
= c
->geometry
.y
;
1045 c
->geometries
.max
.height
= c
->geometry
.height
;
1049 geometry
= c
->geometry
;
1050 geometry
.y
= c
->geometries
.max
.y
;
1051 geometry
.height
= c
->geometries
.max
.height
;
1054 client_resize(c
, geometry
, c
->size_hints_honor
);
1056 ewmh_client_update_hints(c
);
1057 hook_property(c
, "maximized_vertical");
1058 luaA_object_emit_signal(L
, cidx
, "property::maximized_vertical", 0);
1062 /** Set a client above, or not.
1063 * \param L The Lua VM state.
1064 * \param cidx The client index.
1065 * \param s Set or not the client above.
1068 client_set_above(lua_State
*L
, int cidx
, bool s
)
1070 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1074 /* You can only be part of one of the special layers. */
1077 client_set_below(L
, cidx
, false);
1078 client_set_ontop(L
, cidx
, false);
1079 client_set_fullscreen(L
, cidx
, false);
1083 ewmh_client_update_hints(c
);
1085 hook_property(c
, "above");
1086 luaA_object_emit_signal(L
, cidx
, "property::above", 0);
1090 /** Set a client below, or not.
1091 * \param L The Lua VM state.
1092 * \param cidx The client index.
1093 * \param s Set or not the client below.
1096 client_set_below(lua_State
*L
, int cidx
, bool s
)
1098 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1102 /* You can only be part of one of the special layers. */
1105 client_set_above(L
, cidx
, false);
1106 client_set_ontop(L
, cidx
, false);
1107 client_set_fullscreen(L
, cidx
, false);
1111 ewmh_client_update_hints(c
);
1113 hook_property(c
, "below");
1114 luaA_object_emit_signal(L
, cidx
, "property::below", 0);
1118 /** Set a client modal, or not.
1119 * \param L The Lua VM state.
1120 * \param cidx The client index.
1121 * \param s Set or not the client modal attribute.
1124 client_set_modal(lua_State
*L
, int cidx
, bool s
)
1126 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1132 ewmh_client_update_hints(c
);
1134 hook_property(c
, "modal");
1135 luaA_object_emit_signal(L
, cidx
, "property::modal", 0);
1139 /** Set a client ontop, or not.
1140 * \param L The Lua VM state.
1141 * \param cidx The client index.
1142 * \param s Set or not the client ontop attribute.
1145 client_set_ontop(lua_State
*L
, int cidx
, bool s
)
1147 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1151 /* You can only be part of one of the special layers. */
1154 client_set_above(L
, cidx
, false);
1155 client_set_below(L
, cidx
, false);
1156 client_set_fullscreen(L
, cidx
, false);
1161 hook_property(c
, "ontop");
1162 luaA_object_emit_signal(L
, cidx
, "property::ontop", 0);
1166 /** Set a client skip taskbar attribute.
1167 * \param L Tha Lua VM state.
1168 * \param cidx The client index.
1169 * \param s Set or not the client skip taskbar attribute.
1172 client_set_skip_taskbar(lua_State
*L
, int cidx
, bool s
)
1174 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1176 if(c
->skip_taskbar
!= s
)
1178 c
->skip_taskbar
= s
;
1179 luaA_object_emit_signal(L
, cidx
, "property::skip_taskbar", 0);
1183 /** Unban a client and move it back into the viewport.
1184 * \param c The client.
1187 client_unban(client_t
*c
)
1191 xcb_map_window(globalconf
.connection
, c
->window
);
1193 c
->isbanned
= false;
1197 /** Unmanage a client.
1198 * \param c The client.
1201 client_unmanage(client_t
*c
)
1203 tag_array_t
*tags
= &c
->screen
->tags
;
1205 /* Reset transient_for attributes of widows that maybe refering to us */
1206 foreach(_tc
, globalconf
.clients
)
1208 client_t
*tc
= *_tc
;
1209 if(tc
->transient_for
== c
)
1210 tc
->transient_for
= NULL
;
1213 if(globalconf
.screens
.tab
[c
->phys_screen
].prev_client_focus
== c
)
1214 globalconf
.screens
.tab
[c
->phys_screen
].prev_client_focus
= NULL
;
1216 if(globalconf
.screens
.tab
[c
->phys_screen
].client_focus
== c
)
1219 /* remove client from global list and everywhere else */
1220 foreach(elem
, globalconf
.clients
)
1223 client_array_remove(&globalconf
.clients
, elem
);
1226 stack_client_remove(c
);
1227 for(int i
= 0; i
< tags
->len
; i
++)
1228 untag_client(c
, tags
->tab
[i
]);
1231 if(globalconf
.hooks
.unmanage
!= LUA_REFNIL
)
1233 luaA_object_push(globalconf
.L
, c
);
1234 luaA_dofunction_from_registry(globalconf
.L
, globalconf
.hooks
.unmanage
, 1, 0);
1237 luaA_object_push(globalconf
.L
, c
);
1238 luaA_class_emit_signal(globalconf
.L
, &client_class
, "unmanage", 1);
1240 /* Call hook to notify list change */
1241 if(globalconf
.hooks
.clients
!= LUA_REFNIL
)
1242 luaA_dofunction_from_registry(globalconf
.L
, globalconf
.hooks
.clients
, 0, 0);
1244 luaA_class_emit_signal(globalconf
.L
, &client_class
, "list", 0);
1246 window_state_set(c
->window
, XCB_WM_STATE_WITHDRAWN
);
1248 titlebar_client_detach(c
);
1250 ewmh_update_net_client_list(c
->phys_screen
);
1252 /* set client as invalid */
1255 luaA_object_unref(globalconf
.L
, c
);
1258 /** Kill a client via a WM_DELETE_WINDOW request or KillClient if not
1260 * \param c The client to kill.
1263 client_kill(client_t
*c
)
1265 if(client_hasproto(c
, WM_DELETE_WINDOW
))
1267 xcb_client_message_event_t ev
;
1269 /* Initialize all of event's fields first */
1272 ev
.response_type
= XCB_CLIENT_MESSAGE
;
1273 ev
.window
= c
->window
;
1275 ev
.data
.data32
[1] = XCB_CURRENT_TIME
;
1276 ev
.type
= WM_PROTOCOLS
;
1277 ev
.data
.data32
[0] = WM_DELETE_WINDOW
;
1279 xcb_send_event(globalconf
.connection
, false, c
->window
,
1280 XCB_EVENT_MASK_NO_EVENT
, (char *) &ev
);
1283 xcb_kill_client(globalconf
.connection
, c
->window
);
1286 /** Get all clients into a table.
1287 * \param L The Lua VM state.
1288 * \return The number of elements pushed on stack.
1290 * \lparam An optional screen nunmber.
1291 * \lreturn A table with all clients.
1294 luaA_client_get(lua_State
*L
)
1298 screen
= luaL_optnumber(L
, 1, 0) - 1;
1303 foreach(c
, globalconf
.clients
)
1305 luaA_object_push(L
, *c
);
1306 lua_rawseti(L
, -2, i
++);
1310 luaA_checkscreen(screen
);
1311 foreach(c
, globalconf
.clients
)
1312 if((*c
)->screen
== &globalconf
.screens
.tab
[screen
])
1314 luaA_object_push(L
, *c
);
1315 lua_rawseti(L
, -2, i
++);
1322 /** Check if a client is visible on its screen.
1323 * \param L The Lua VM state.
1324 * \return The number of elements pushed on stack.
1327 * \lreturn A boolean value, true if the client is visible, false otherwise.
1330 luaA_client_isvisible(lua_State
*L
)
1332 client_t
*c
= luaA_client_checkudata(L
, 1);
1333 lua_pushboolean(L
, client_isvisible(c
, c
->screen
));
1337 /** Set client border width.
1338 * \param L The Lua VM state.
1339 * \param cidx The client index.
1340 * \param width The border width.
1343 client_set_border_width(lua_State
*L
, int cidx
, int width
)
1345 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1348 if(width
> 0 && (c
->type
== WINDOW_TYPE_DOCK
1349 || c
->type
== WINDOW_TYPE_SPLASH
1350 || c
->type
== WINDOW_TYPE_DESKTOP
1354 if(width
== c
->border_width
|| width
< 0)
1357 /* disallow change of border width if the client is fullscreen */
1361 /* Update geometry with the new border. */
1362 c
->geometry
.width
-= 2 * c
->border_width
;
1363 c
->geometry
.height
-= 2 * c
->border_width
;
1365 c
->border_width
= width
;
1366 xcb_configure_window(globalconf
.connection
, c
->window
,
1367 XCB_CONFIG_WINDOW_BORDER_WIDTH
, &w
);
1369 c
->geometry
.width
+= 2 * c
->border_width
;
1370 c
->geometry
.height
+= 2 * c
->border_width
;
1372 /* Changing border size also affects the size of the titlebar. */
1373 titlebar_update_geometry(c
);
1375 hook_property(c
, "border_width");
1376 luaA_object_emit_signal(L
, cidx
, "property::border_width", 0);
1379 /** Set a client icon.
1380 * \param L The Lua VM state.
1381 * \param cidx The client index on the stack.
1382 * \para iidx The image index on the stack.
1385 client_set_icon(lua_State
*L
, int cidx
, int iidx
)
1387 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1388 /* convert index to absolute */
1389 cidx
= luaA_absindex(L
, cidx
);
1390 iidx
= luaA_absindex(L
, iidx
);
1391 luaA_checkudata(L
, iidx
, &image_class
);
1392 luaA_object_unref_item(L
, cidx
, c
->icon
);
1393 c
->icon
= luaA_object_ref_item(L
, cidx
, iidx
);
1394 luaA_object_emit_signal(L
, cidx
< iidx
? cidx
: cidx
- 1, "property::icon", 0);
1396 hook_property(c
, "icon");
1400 * \param L The Lua VM state.
1406 luaA_client_kill(lua_State
*L
)
1408 client_t
*c
= luaA_client_checkudata(L
, 1);
1413 /** Swap a client with another one.
1414 * \param L The Lua VM state.
1417 * \lparam A client to swap with.
1420 luaA_client_swap(lua_State
*L
)
1422 client_t
*c
= luaA_client_checkudata(L
, 1);
1423 client_t
*swap
= luaA_client_checkudata(L
, 2);
1427 client_t
**ref_c
= NULL
, **ref_swap
= NULL
;
1428 foreach(item
, globalconf
.clients
)
1432 else if(*item
== swap
)
1434 if(ref_c
&& ref_swap
)
1441 /* Call hook to notify list change */
1442 if(globalconf
.hooks
.clients
!= LUA_REFNIL
)
1443 luaA_dofunction_from_registry(L
, globalconf
.hooks
.clients
, 0, 0);
1445 luaA_class_emit_signal(globalconf
.L
, &client_class
, "list", 0);
1451 /** Access or set the client tags.
1452 * \param L The Lua VM state.
1453 * \return The number of elements pushed on stack.
1454 * \lparam A table with tags to set, or none to get the current tags table.
1455 * \return The clients tag.
1458 luaA_client_tags(lua_State
*L
)
1460 client_t
*c
= luaA_client_checkudata(L
, 1);
1461 tag_array_t
*tags
= &c
->screen
->tags
;
1464 if(lua_gettop(L
) == 2)
1466 luaA_checktable(L
, 2);
1467 for(int i
= 0; i
< tags
->len
; i
++)
1468 untag_client(c
, tags
->tab
[i
]);
1470 while(lua_next(L
, 2))
1477 if(is_client_tagged(c
, *tag
))
1479 luaA_object_push(L
, *tag
);
1480 lua_rawseti(L
, -2, ++j
);
1486 /** Raise a client on top of others which are on the same layer.
1487 * \param L The Lua VM state.
1492 luaA_client_raise(lua_State
*L
)
1494 client_t
*c
= luaA_client_checkudata(L
, 1);
1499 /** Lower a client on bottom of others which are on the same layer.
1500 * \param L The Lua VM state.
1505 luaA_client_lower(lua_State
*L
)
1507 client_t
*c
= luaA_client_checkudata(L
, 1);
1512 /** Redraw a client by unmapping and mapping it quickly.
1513 * \param L The Lua VM state.
1519 luaA_client_redraw(lua_State
*L
)
1521 client_t
*c
= luaA_client_checkudata(L
, 1);
1523 xcb_unmap_window(globalconf
.connection
, c
->window
);
1524 xcb_map_window(globalconf
.connection
, c
->window
);
1526 /* Set the focus on the current window if the redraw has been
1527 performed on the window where the pointer is currently on
1528 because after the unmapping/mapping, the focus is lost */
1529 if(globalconf
.screen_focus
->client_focus
== c
)
1538 /** Stop managing a client.
1539 * \param L The Lua VM state.
1540 * \return The number of elements pushed on stack.
1545 luaA_client_unmanage(lua_State
*L
)
1547 client_t
*c
= luaA_client_checkudata(L
, 1);
1552 /** Return client geometry.
1553 * \param L The Lua VM state.
1554 * \return The number of elements pushed on stack.
1556 * \lparam A table with new coordinates, or none.
1557 * \lreturn A table with client coordinates.
1560 luaA_client_geometry(lua_State
*L
)
1562 client_t
*c
= luaA_client_checkudata(L
, 1);
1564 if(lua_gettop(L
) == 2)
1568 luaA_checktable(L
, 2);
1569 geometry
.x
= luaA_getopt_number(L
, 2, "x", c
->geometry
.x
);
1570 geometry
.y
= luaA_getopt_number(L
, 2, "y", c
->geometry
.y
);
1571 if(client_isfixed(c
))
1573 geometry
.width
= c
->geometry
.width
;
1574 geometry
.height
= c
->geometry
.height
;
1578 geometry
.width
= luaA_getopt_number(L
, 2, "width", c
->geometry
.width
);
1579 geometry
.height
= luaA_getopt_number(L
, 2, "height", c
->geometry
.height
);
1582 client_resize(c
, geometry
, c
->size_hints_honor
);
1585 return luaA_pusharea(L
, c
->geometry
);
1588 /** Return client struts (reserved space at the edge of the screen).
1589 * \param L The Lua VM state.
1590 * \return The number of elements pushed on stack.
1592 * \lparam A table with new strut values, or none.
1593 * \lreturn A table with strut values.
1596 luaA_client_struts(lua_State
*L
)
1598 client_t
*c
= luaA_client_checkudata(L
, 1);
1600 if(lua_gettop(L
) == 2)
1602 luaA_tostrut(L
, 2, &c
->strut
);
1603 ewmh_update_strut(c
->window
, &c
->strut
);
1604 hook_property(c
, "struts");
1605 luaA_object_emit_signal(L
, 1, "property::struts", 0);
1606 screen_emit_signal(L
, c
->screen
, "property::workarea", 0);
1609 return luaA_pushstrut(L
, c
->strut
);
1613 luaA_client_set_screen(lua_State
*L
, client_t
*c
)
1615 if(globalconf
.xinerama_is_active
)
1617 int screen
= luaL_checknumber(L
, -1) - 1;
1618 luaA_checkscreen(screen
);
1619 screen_client_moveto(c
, &globalconf
.screens
.tab
[screen
], true);
1625 luaA_client_set_hidden(lua_State
*L
, client_t
*c
)
1627 bool b
= luaA_checkboolean(L
, -1);
1630 client_need_reban(c
);
1632 client_need_reban(c
);
1633 hook_property(c
, "hidden");
1634 luaA_object_emit_signal(L
, -3, "property::screen", 0);
1640 luaA_client_set_minimized(lua_State
*L
, client_t
*c
)
1642 client_set_minimized(L
, -3, luaA_checkboolean(L
, -1));
1647 luaA_client_set_fullscreen(lua_State
*L
, client_t
*c
)
1649 client_set_fullscreen(L
, -3, luaA_checkboolean(L
, -1));
1654 luaA_client_set_modal(lua_State
*L
, client_t
*c
)
1656 client_set_modal(L
, -3, luaA_checkboolean(L
, -1));
1661 luaA_client_set_maximized_horizontal(lua_State
*L
, client_t
*c
)
1663 client_set_maximized_horizontal(L
, -3, luaA_checkboolean(L
, -1));
1668 luaA_client_set_maximized_vertical(lua_State
*L
, client_t
*c
)
1670 client_set_maximized_vertical(L
, -3, luaA_checkboolean(L
, -1));
1675 luaA_client_set_icon(lua_State
*L
, client_t
*c
)
1677 client_set_icon(L
, -3, -1);
1682 luaA_client_set_opacity(lua_State
*L
, client_t
*c
)
1684 if(lua_isnil(L
, -1))
1685 client_set_opacity(L
, -3, -1);
1687 client_set_opacity(L
, -3, luaL_checknumber(L
, -1));
1692 luaA_client_set_sticky(lua_State
*L
, client_t
*c
)
1694 client_set_sticky(L
, -3, luaA_checkboolean(L
, -1));
1699 luaA_client_set_size_hints_honor(lua_State
*L
, client_t
*c
)
1701 c
->size_hints_honor
= luaA_checkboolean(L
, -1);
1702 hook_property(c
, "size_hints_honor");
1703 luaA_object_emit_signal(L
, -3, "property::size_hints_honor", 0);
1708 luaA_client_set_border_width(lua_State
*L
, client_t
*c
)
1710 client_set_border_width(L
, -3, luaL_checknumber(L
, -1));
1715 luaA_client_set_ontop(lua_State
*L
, client_t
*c
)
1717 client_set_ontop(L
, -3, luaA_checkboolean(L
, -1));
1722 luaA_client_set_below(lua_State
*L
, client_t
*c
)
1724 client_set_below(L
, -3, luaA_checkboolean(L
, -1));
1729 luaA_client_set_above(lua_State
*L
, client_t
*c
)
1731 client_set_above(L
, -3, luaA_checkboolean(L
, -1));
1736 luaA_client_set_urgent(lua_State
*L
, client_t
*c
)
1738 client_set_urgent(L
, -3, luaA_checkboolean(L
, -1));
1743 luaA_client_set_border_color(lua_State
*L
, client_t
*c
)
1747 if((buf
= luaL_checklstring(L
, -1, &len
))
1748 && xcolor_init_reply(xcolor_init_unchecked(&c
->border_color
, buf
, len
)))
1750 xcb_change_window_attributes(globalconf
.connection
, c
->window
,
1751 XCB_CW_BORDER_PIXEL
, &c
->border_color
.pixel
);
1752 luaA_object_emit_signal(L
, -3, "property::border_color", 0);
1758 luaA_client_set_titlebar(lua_State
*L
, client_t
*c
)
1760 if(lua_isnil(L
, -1))
1761 titlebar_client_detach(c
);
1763 titlebar_client_attach(c
);
1768 luaA_client_set_skip_taskbar(lua_State
*L
, client_t
*c
)
1770 client_set_skip_taskbar(L
, -3, luaA_checkboolean(L
, -1));
1774 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, name
, lua_pushstring
)
1775 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, icon_name
, lua_pushstring
)
1776 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, class, lua_pushstring
)
1777 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, instance
, lua_pushstring
)
1778 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, machine
, lua_pushstring
)
1779 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, role
, lua_pushstring
)
1780 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, transient_for
, luaA_object_push
)
1781 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, skip_taskbar
, lua_pushboolean
)
1782 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, window
, lua_pushnumber
)
1783 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, leader_window
, lua_pushnumber
)
1784 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, group_window
, lua_pushnumber
)
1785 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, pid
, lua_pushnumber
)
1786 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, hidden
, lua_pushboolean
)
1787 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, minimized
, lua_pushboolean
)
1788 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, fullscreen
, lua_pushboolean
)
1789 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, modal
, lua_pushboolean
)
1790 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, ontop
, lua_pushboolean
)
1791 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, urgent
, lua_pushboolean
)
1792 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, above
, lua_pushboolean
)
1793 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, below
, lua_pushboolean
)
1794 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, sticky
, lua_pushboolean
)
1795 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, size_hints_honor
, lua_pushboolean
)
1796 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, maximized_horizontal
, lua_pushboolean
)
1797 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, maximized_vertical
, lua_pushboolean
)
1798 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, opacity
, lua_pushnumber
)
1799 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, border_width
, lua_pushnumber
)
1800 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, border_color
, luaA_pushxcolor
)
1803 luaA_client_get_content(lua_State
*L
, client_t
*c
)
1805 xcb_image_t
*ximage
= xcb_image_get(globalconf
.connection
,
1808 c
->geometries
.internal
.width
,
1809 c
->geometries
.internal
.height
,
1810 ~0, XCB_IMAGE_FORMAT_Z_PIXMAP
);
1815 if(ximage
->bpp
>= 24)
1817 uint32_t *data
= p_alloca(uint32_t, ximage
->width
* ximage
->height
);
1819 for(int y
= 0; y
< ximage
->height
; y
++)
1820 for(int x
= 0; x
< ximage
->width
; x
++)
1822 data
[y
* ximage
->width
+ x
] = xcb_image_get_pixel(ximage
, x
, y
);
1823 data
[y
* ximage
->width
+ x
] |= 0xff000000; /* set alpha to 0xff */
1826 retval
= image_new_from_argb32(ximage
->width
, ximage
->height
, data
);
1828 xcb_image_destroy(ximage
);
1835 luaA_client_get_type(lua_State
*L
, client_t
*c
)
1839 case WINDOW_TYPE_DESKTOP
:
1840 lua_pushliteral(L
, "desktop");
1842 case WINDOW_TYPE_DOCK
:
1843 lua_pushliteral(L
, "dock");
1845 case WINDOW_TYPE_SPLASH
:
1846 lua_pushliteral(L
, "splash");
1848 case WINDOW_TYPE_DIALOG
:
1849 lua_pushliteral(L
, "dialog");
1851 case WINDOW_TYPE_MENU
:
1852 lua_pushliteral(L
, "menu");
1854 case WINDOW_TYPE_TOOLBAR
:
1855 lua_pushliteral(L
, "toolbar");
1857 case WINDOW_TYPE_UTILITY
:
1858 lua_pushliteral(L
, "utility");
1860 case WINDOW_TYPE_DROPDOWN_MENU
:
1861 lua_pushliteral(L
, "dropdown_menu");
1863 case WINDOW_TYPE_POPUP_MENU
:
1864 lua_pushliteral(L
, "popup_menu");
1866 case WINDOW_TYPE_TOOLTIP
:
1867 lua_pushliteral(L
, "tooltip");
1869 case WINDOW_TYPE_NOTIFICATION
:
1870 lua_pushliteral(L
, "notification");
1872 case WINDOW_TYPE_COMBO
:
1873 lua_pushliteral(L
, "combo");
1875 case WINDOW_TYPE_DND
:
1876 lua_pushliteral(L
, "dnd");
1878 case WINDOW_TYPE_NORMAL
:
1879 lua_pushliteral(L
, "normal");
1886 luaA_client_get_screen(lua_State
*L
, client_t
*c
)
1888 lua_pushnumber(L
, 1 + screen_array_indexof(&globalconf
.screens
, c
->screen
));
1893 luaA_client_get_icon(lua_State
*L
, client_t
*c
)
1895 return luaA_object_push_item(L
, -2, c
->icon
);
1899 luaA_client_get_titlebar(lua_State
*L
, client_t
*c
)
1901 return luaA_object_push(L
, c
->titlebar
);
1905 luaA_client_get_size_hints(lua_State
*L
, client_t
*c
)
1907 const char *u_or_p
= NULL
;
1909 lua_createtable(L
, 0, 1);
1911 if(c
->size_hints
.flags
& XCB_SIZE_HINT_US_POSITION
)
1912 u_or_p
= "user_position";
1913 else if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_POSITION
)
1914 u_or_p
= "program_position";
1918 lua_createtable(L
, 0, 2);
1919 lua_pushnumber(L
, c
->size_hints
.x
);
1920 lua_setfield(L
, -2, "x");
1921 lua_pushnumber(L
, c
->size_hints
.y
);
1922 lua_setfield(L
, -2, "y");
1923 lua_setfield(L
, -2, u_or_p
);
1927 if(c
->size_hints
.flags
& XCB_SIZE_HINT_US_SIZE
)
1928 u_or_p
= "user_size";
1929 else if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_SIZE
)
1930 u_or_p
= "program_size";
1934 lua_createtable(L
, 0, 2);
1935 lua_pushnumber(L
, c
->size_hints
.width
);
1936 lua_setfield(L
, -2, "width");
1937 lua_pushnumber(L
, c
->size_hints
.height
);
1938 lua_setfield(L
, -2, "height");
1939 lua_setfield(L
, -2, u_or_p
);
1942 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MIN_SIZE
)
1944 lua_pushnumber(L
, c
->size_hints
.min_width
);
1945 lua_setfield(L
, -2, "min_width");
1946 lua_pushnumber(L
, c
->size_hints
.min_height
);
1947 lua_setfield(L
, -2, "min_height");
1950 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MAX_SIZE
)
1952 lua_pushnumber(L
, c
->size_hints
.max_width
);
1953 lua_setfield(L
, -2, "max_width");
1954 lua_pushnumber(L
, c
->size_hints
.max_height
);
1955 lua_setfield(L
, -2, "max_height");
1958 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_RESIZE_INC
)
1960 lua_pushnumber(L
, c
->size_hints
.width_inc
);
1961 lua_setfield(L
, -2, "width_inc");
1962 lua_pushnumber(L
, c
->size_hints
.height_inc
);
1963 lua_setfield(L
, -2, "height_inc");
1966 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_ASPECT
)
1968 lua_pushnumber(L
, c
->size_hints
.min_aspect_num
);
1969 lua_setfield(L
, -2, "min_aspect_num");
1970 lua_pushnumber(L
, c
->size_hints
.min_aspect_den
);
1971 lua_setfield(L
, -2, "min_aspect_den");
1972 lua_pushnumber(L
, c
->size_hints
.max_aspect_num
);
1973 lua_setfield(L
, -2, "max_aspect_num");
1974 lua_pushnumber(L
, c
->size_hints
.max_aspect_den
);
1975 lua_setfield(L
, -2, "max_aspect_den");
1978 if(c
->size_hints
.flags
& XCB_SIZE_HINT_BASE_SIZE
)
1980 lua_pushnumber(L
, c
->size_hints
.base_width
);
1981 lua_setfield(L
, -2, "base_width");
1982 lua_pushnumber(L
, c
->size_hints
.base_height
);
1983 lua_setfield(L
, -2, "base_height");
1986 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_WIN_GRAVITY
)
1988 switch(c
->size_hints
.win_gravity
)
1991 lua_pushliteral(L
, "north_west");
1993 case XCB_GRAVITY_NORTH
:
1994 lua_pushliteral(L
, "north");
1996 case XCB_GRAVITY_NORTH_EAST
:
1997 lua_pushliteral(L
, "north_east");
1999 case XCB_GRAVITY_WEST
:
2000 lua_pushliteral(L
, "west");
2002 case XCB_GRAVITY_CENTER
:
2003 lua_pushliteral(L
, "center");
2005 case XCB_GRAVITY_EAST
:
2006 lua_pushliteral(L
, "east");
2008 case XCB_GRAVITY_SOUTH_WEST
:
2009 lua_pushliteral(L
, "south_west");
2011 case XCB_GRAVITY_SOUTH
:
2012 lua_pushliteral(L
, "south");
2014 case XCB_GRAVITY_SOUTH_EAST
:
2015 lua_pushliteral(L
, "south_east");
2017 case XCB_GRAVITY_STATIC
:
2018 lua_pushliteral(L
, "static");
2021 lua_setfield(L
, -2, "win_gravity");
2027 /** Get or set mouse buttons bindings for a client.
2028 * \param L The Lua VM state.
2029 * \return The number of element pushed on stack.
2032 * \lparam An array of mouse button bindings objects, or nothing.
2033 * \return The array of mouse button bindings objects of this client.
2036 luaA_client_buttons(lua_State
*L
)
2038 client_t
*client
= luaA_client_checkudata(L
, 1);
2039 button_array_t
*buttons
= &client
->buttons
;
2041 if(lua_gettop(L
) == 2)
2043 luaA_button_array_set(L
, 1, 2, buttons
);
2044 luaA_object_emit_signal(L
, 1, "property::buttons", 0);
2045 window_buttons_grab(client
->window
, &client
->buttons
);
2048 return luaA_button_array_get(L
, 1, buttons
);
2051 /** Get or set keys bindings for a client.
2052 * \param L The Lua VM state.
2053 * \return The number of element pushed on stack.
2056 * \lparam An array of key bindings objects, or nothing.
2057 * \return The array of key bindings objects of this client.
2060 luaA_client_keys(lua_State
*L
)
2062 client_t
*c
= luaA_client_checkudata(L
, 1);
2063 key_array_t
*keys
= &c
->keys
;
2065 if(lua_gettop(L
) == 2)
2067 luaA_key_array_set(L
, 1, 2, keys
);
2068 luaA_object_emit_signal(L
, 1, "property::keys", 0);
2069 xcb_ungrab_key(globalconf
.connection
, XCB_GRAB_ANY
, c
->window
, XCB_BUTTON_MASK_ANY
);
2070 window_grabkeys(c
->window
, keys
);
2073 return luaA_key_array_get(L
, 1, keys
);
2077 * \param L The Lua VM state.
2078 * \return The number of pushed elements.
2081 luaA_client_module_index(lua_State
*L
)
2084 const char *buf
= luaL_checklstring(L
, 2, &len
);
2086 switch(a_tokenize(buf
, len
))
2089 return luaA_object_push(globalconf
.L
, globalconf
.screen_focus
->client_focus
);
2096 /* Client module new index.
2097 * \param L The Lua VM state.
2098 * \return The number of pushed elements.
2101 luaA_client_module_newindex(lua_State
*L
)
2104 const char *buf
= luaL_checklstring(L
, 2, &len
);
2107 switch(a_tokenize(buf
, len
))
2110 c
= luaA_client_checkudata(L
, 3);
2121 client_class_setup(lua_State
*L
)
2123 static const struct luaL_reg client_methods
[] =
2125 LUA_CLASS_METHODS(client
)
2126 { "get", luaA_client_get
},
2127 { "__index", luaA_client_module_index
},
2128 { "__newindex", luaA_client_module_newindex
},
2132 static const struct luaL_reg client_meta
[] =
2134 LUA_OBJECT_META(client
)
2136 { "buttons", luaA_client_buttons
},
2137 { "keys", luaA_client_keys
},
2138 { "isvisible", luaA_client_isvisible
},
2139 { "geometry", luaA_client_geometry
},
2140 { "struts", luaA_client_struts
},
2141 { "tags", luaA_client_tags
},
2142 { "kill", luaA_client_kill
},
2143 { "swap", luaA_client_swap
},
2144 { "raise", luaA_client_raise
},
2145 { "lower", luaA_client_lower
},
2146 { "redraw", luaA_client_redraw
},
2147 { "unmanage", luaA_client_unmanage
},
2148 { "__gc", luaA_client_gc
},
2152 luaA_class_setup(L
, &client_class
, "client", (lua_class_allocator_t
) client_new
,
2153 luaA_class_index_miss_property
, luaA_class_newindex_miss_property
,
2154 client_methods
, client_meta
);
2155 luaA_class_add_property(&client_class
, A_TK_NAME
,
2157 (lua_class_propfunc_t
) luaA_client_get_name
,
2159 luaA_class_add_property(&client_class
, A_TK_TRANSIENT_FOR
,
2161 (lua_class_propfunc_t
) luaA_client_get_transient_for
,
2163 luaA_class_add_property(&client_class
, A_TK_SKIP_TASKBAR
,
2164 (lua_class_propfunc_t
) luaA_client_set_skip_taskbar
,
2165 (lua_class_propfunc_t
) luaA_client_get_skip_taskbar
,
2166 (lua_class_propfunc_t
) luaA_client_set_skip_taskbar
);
2167 luaA_class_add_property(&client_class
, A_TK_CONTENT
,
2169 (lua_class_propfunc_t
) luaA_client_get_content
,
2171 luaA_class_add_property(&client_class
, A_TK_TYPE
,
2173 (lua_class_propfunc_t
) luaA_client_get_type
,
2175 luaA_class_add_property(&client_class
, A_TK_CLASS
,
2177 (lua_class_propfunc_t
) luaA_client_get_class
,
2179 luaA_class_add_property(&client_class
, A_TK_INSTANCE
,
2181 (lua_class_propfunc_t
) luaA_client_get_instance
,
2183 luaA_class_add_property(&client_class
, A_TK_ROLE
,
2185 (lua_class_propfunc_t
) luaA_client_get_role
,
2187 luaA_class_add_property(&client_class
, A_TK_PID
,
2189 (lua_class_propfunc_t
) luaA_client_get_pid
,
2191 luaA_class_add_property(&client_class
, A_TK_WINDOW
,
2193 (lua_class_propfunc_t
) luaA_client_get_window
,
2195 luaA_class_add_property(&client_class
, A_TK_LEADER_WINDOW
,
2197 (lua_class_propfunc_t
) luaA_client_get_leader_window
,
2199 luaA_class_add_property(&client_class
, A_TK_MACHINE
,
2201 (lua_class_propfunc_t
) luaA_client_get_machine
,
2203 luaA_class_add_property(&client_class
, A_TK_ICON_NAME
,
2205 (lua_class_propfunc_t
) luaA_client_get_icon_name
,
2207 luaA_class_add_property(&client_class
, A_TK_SCREEN
,
2209 (lua_class_propfunc_t
) luaA_client_get_screen
,
2210 (lua_class_propfunc_t
) luaA_client_set_screen
);
2211 luaA_class_add_property(&client_class
, A_TK_HIDDEN
,
2212 (lua_class_propfunc_t
) luaA_client_set_hidden
,
2213 (lua_class_propfunc_t
) luaA_client_get_hidden
,
2214 (lua_class_propfunc_t
) luaA_client_set_hidden
);
2215 luaA_class_add_property(&client_class
, A_TK_MINIMIZED
,
2216 (lua_class_propfunc_t
) luaA_client_set_minimized
,
2217 (lua_class_propfunc_t
) luaA_client_get_minimized
,
2218 (lua_class_propfunc_t
) luaA_client_set_minimized
);
2219 luaA_class_add_property(&client_class
, A_TK_FULLSCREEN
,
2220 (lua_class_propfunc_t
) luaA_client_set_fullscreen
,
2221 (lua_class_propfunc_t
) luaA_client_get_fullscreen
,
2222 (lua_class_propfunc_t
) luaA_client_set_fullscreen
);
2223 luaA_class_add_property(&client_class
, A_TK_MODAL
,
2224 (lua_class_propfunc_t
) luaA_client_set_modal
,
2225 (lua_class_propfunc_t
) luaA_client_get_modal
,
2226 (lua_class_propfunc_t
) luaA_client_set_modal
);
2227 luaA_class_add_property(&client_class
, A_TK_GROUP_WINDOW
,
2229 (lua_class_propfunc_t
) luaA_client_get_group_window
,
2231 luaA_class_add_property(&client_class
, A_TK_MAXIMIZED_HORIZONTAL
,
2232 (lua_class_propfunc_t
) luaA_client_set_maximized_horizontal
,
2233 (lua_class_propfunc_t
) luaA_client_get_maximized_horizontal
,
2234 (lua_class_propfunc_t
) luaA_client_set_maximized_horizontal
);
2235 luaA_class_add_property(&client_class
, A_TK_MAXIMIZED_VERTICAL
,
2236 (lua_class_propfunc_t
) luaA_client_set_maximized_vertical
,
2237 (lua_class_propfunc_t
) luaA_client_get_maximized_vertical
,
2238 (lua_class_propfunc_t
) luaA_client_set_maximized_vertical
);
2239 luaA_class_add_property(&client_class
, A_TK_ICON
,
2240 (lua_class_propfunc_t
) luaA_client_set_icon
,
2241 (lua_class_propfunc_t
) luaA_client_get_icon
,
2242 (lua_class_propfunc_t
) luaA_client_set_icon
);
2243 luaA_class_add_property(&client_class
, A_TK_OPACITY
,
2244 (lua_class_propfunc_t
) luaA_client_set_opacity
,
2245 (lua_class_propfunc_t
) luaA_client_get_opacity
,
2246 (lua_class_propfunc_t
) luaA_client_set_opacity
);
2247 luaA_class_add_property(&client_class
, A_TK_ONTOP
,
2248 (lua_class_propfunc_t
) luaA_client_set_ontop
,
2249 (lua_class_propfunc_t
) luaA_client_get_ontop
,
2250 (lua_class_propfunc_t
) luaA_client_set_ontop
);
2251 luaA_class_add_property(&client_class
, A_TK_ABOVE
,
2252 (lua_class_propfunc_t
) luaA_client_set_above
,
2253 (lua_class_propfunc_t
) luaA_client_get_above
,
2254 (lua_class_propfunc_t
) luaA_client_set_above
);
2255 luaA_class_add_property(&client_class
, A_TK_BELOW
,
2256 (lua_class_propfunc_t
) luaA_client_set_below
,
2257 (lua_class_propfunc_t
) luaA_client_get_below
,
2258 (lua_class_propfunc_t
) luaA_client_set_below
);
2259 luaA_class_add_property(&client_class
, A_TK_STICKY
,
2260 (lua_class_propfunc_t
) luaA_client_set_sticky
,
2261 (lua_class_propfunc_t
) luaA_client_get_sticky
,
2262 (lua_class_propfunc_t
) luaA_client_set_sticky
);
2263 luaA_class_add_property(&client_class
, A_TK_SIZE_HINTS_HONOR
,
2264 (lua_class_propfunc_t
) luaA_client_set_size_hints_honor
,
2265 (lua_class_propfunc_t
) luaA_client_get_size_hints_honor
,
2266 (lua_class_propfunc_t
) luaA_client_set_size_hints_honor
);
2267 luaA_class_add_property(&client_class
, A_TK_BORDER_WIDTH
,
2268 (lua_class_propfunc_t
) luaA_client_set_border_width
,
2269 (lua_class_propfunc_t
) luaA_client_get_border_width
,
2270 (lua_class_propfunc_t
) luaA_client_set_border_width
);
2271 luaA_class_add_property(&client_class
, A_TK_BORDER_COLOR
,
2272 (lua_class_propfunc_t
) luaA_client_set_border_color
,
2273 (lua_class_propfunc_t
) luaA_client_get_border_color
,
2274 (lua_class_propfunc_t
) luaA_client_set_border_color
);
2275 luaA_class_add_property(&client_class
, A_TK_TITLEBAR
,
2276 (lua_class_propfunc_t
) luaA_client_set_titlebar
,
2277 (lua_class_propfunc_t
) luaA_client_get_titlebar
,
2278 (lua_class_propfunc_t
) luaA_client_set_titlebar
);
2279 luaA_class_add_property(&client_class
, A_TK_URGENT
,
2280 (lua_class_propfunc_t
) luaA_client_set_urgent
,
2281 (lua_class_propfunc_t
) luaA_client_get_urgent
,
2282 (lua_class_propfunc_t
) luaA_client_set_urgent
);
2283 luaA_class_add_property(&client_class
, A_TK_SIZE_HINTS
,
2285 (lua_class_propfunc_t
) luaA_client_get_size_hints
,
2289 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80