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
->startup_id
);
58 p_delete(&c
->instance
);
59 p_delete(&c
->icon_name
);
61 return luaA_object_gc(L
);
64 /** Change the client opacity.
65 * \param L The Lua VM state.
66 * \param cidx The client index.
67 * \param opacity The opacity.
70 client_set_opacity(lua_State
*L
, int cidx
, double opacity
)
72 client_t
*c
= luaA_client_checkudata(L
, cidx
);
74 if(c
->opacity
!= opacity
)
77 window_opacity_set(c
->window
, opacity
);
78 luaA_object_emit_signal(L
, cidx
, "property::opacity", 0);
82 /** Change the clients urgency flag.
83 * \param L The Lua VM state.
84 * \param cidx The client index on the stack.
85 * \param urgent The new flag state.
88 client_set_urgent(lua_State
*L
, int cidx
, bool urgent
)
90 client_t
*c
= luaA_client_checkudata(L
, cidx
);
92 if(c
->urgent
!= urgent
)
94 xcb_get_property_cookie_t hints
=
95 xcb_get_wm_hints_unchecked(globalconf
.connection
, c
->window
);
98 ewmh_client_update_hints(c
);
100 /* update ICCCM hints */
102 xcb_get_wm_hints_reply(globalconf
.connection
, hints
, &wmh
, NULL
);
105 wmh
.flags
|= XCB_WM_HINT_X_URGENCY
;
107 wmh
.flags
&= ~XCB_WM_HINT_X_URGENCY
;
109 xcb_set_wm_hints(globalconf
.connection
, c
->window
, &wmh
);
111 hook_property(c
, "urgent");
112 luaA_object_emit_signal(L
, cidx
, "property::urgent", 0);
117 client_set_group_window(lua_State
*L
, int cidx
, xcb_window_t window
)
119 client_t
*c
= luaA_client_checkudata(L
, cidx
);
121 if(c
->group_window
!= window
)
123 c
->group_window
= window
;
124 luaA_object_emit_signal(L
, cidx
, "property::group_window", 0);
129 client_set_type(lua_State
*L
, int cidx
, window_type_t type
)
131 client_t
*c
= luaA_client_checkudata(L
, cidx
);
136 luaA_object_emit_signal(L
, cidx
, "property::type", 0);
141 client_set_pid(lua_State
*L
, int cidx
, uint32_t pid
)
143 client_t
*c
= luaA_client_checkudata(L
, cidx
);
148 luaA_object_emit_signal(L
, cidx
, "property::pid", 0);
153 client_set_icon_name(lua_State
*L
, int cidx
, const char *icon_name
)
155 client_t
*c
= luaA_client_checkudata(L
, cidx
);
156 p_delete(&c
->icon_name
);
157 c
->icon_name
= a_strdup(icon_name
);
158 luaA_object_emit_signal(L
, cidx
, "property::icon_name", 0);
159 hook_property(c
, "icon_name");
163 client_set_role(lua_State
*L
, int cidx
, const char *role
)
165 client_t
*c
= luaA_client_checkudata(L
, cidx
);
167 luaA_object_emit_signal(L
, cidx
, "property::role", 0);
168 c
->role
= a_strdup(role
);
172 client_set_machine(lua_State
*L
, int cidx
, const char *machine
)
174 client_t
*c
= luaA_client_checkudata(L
, cidx
);
175 p_delete(&c
->machine
);
176 c
->machine
= a_strdup(machine
);
177 luaA_object_emit_signal(L
, cidx
, "property::machine", 0);
181 client_set_class_instance(lua_State
*L
, int cidx
, const char *class, const char *instance
)
183 client_t
*c
= luaA_client_checkudata(L
, cidx
);
185 p_delete(&c
->instance
);
186 c
->class = a_strdup(class);
187 c
->instance
= a_strdup(instance
);
188 luaA_object_emit_signal(L
, cidx
, "property::class", 0);
189 luaA_object_emit_signal(L
, cidx
, "property::instance", 0);
193 client_set_transient_for(lua_State
*L
, int cidx
, client_t
*transient_for
)
195 client_t
*c
= luaA_client_checkudata(L
, cidx
);
197 if(c
->transient_for
!= transient_for
)
199 c
->transient_for
= transient_for
;
200 luaA_object_emit_signal(L
, cidx
, "property::transient_for", 0);
205 client_set_name(lua_State
*L
, int cidx
, const char *name
)
207 client_t
*c
= luaA_client_checkudata(L
, cidx
);
209 c
->name
= a_strdup(name
);
210 hook_property(c
, "name");
211 luaA_object_emit_signal(L
, cidx
, "property::name", 0);
214 /** Returns true if a client is tagged
215 * with one of the tags of the specified screen.
216 * \param c The client to check.
217 * \param screen Virtual screen.
218 * \return true if the client is visible, false otherwise.
221 client_maybevisible(client_t
*c
, screen_t
*screen
)
223 if(screen
&& c
->screen
== screen
)
225 if(c
->sticky
|| c
->type
== WINDOW_TYPE_DESKTOP
)
228 foreach(tag
, screen
->tags
)
229 if(tag_get_selected(*tag
) && is_client_tagged(c
, *tag
))
235 /** Get a client by its window.
236 * \param w The client window to find.
237 * \return A client pointer if found, NULL otherwise.
240 client_getbywin(xcb_window_t w
)
242 foreach(c
, globalconf
.clients
)
243 if((*c
)->window
== w
)
249 /** Record that a client lost focus.
250 * \param c Client being unfocused
253 client_unfocus_update(client_t
*c
)
255 globalconf
.screens
.tab
[c
->phys_screen
].client_focus
= NULL
;
256 ewmh_update_net_active_window(c
->phys_screen
);
259 if(globalconf
.hooks
.unfocus
!= LUA_REFNIL
)
261 luaA_object_push(globalconf
.L
, c
);
262 luaA_dofunction_from_registry(globalconf
.L
, globalconf
.hooks
.unfocus
, 1, 0);
265 luaA_object_push(globalconf
.L
, c
);
266 luaA_class_emit_signal(globalconf
.L
, &client_class
, "unfocus", 1);
269 /** Unfocus a client.
270 * \param c The client.
273 client_unfocus(client_t
*c
)
276 xcb_window_t root_win
= xutil_screen_get(globalconf
.connection
, c
->phys_screen
)->root
;
277 /* Set focus on root window, so no events leak to the current window.
278 * This kind of inlines client_set_focus(), but a root window will never have
279 * the WM_TAKE_FOCUS protocol.
281 xcb_set_input_focus(globalconf
.connection
, XCB_INPUT_FOCUS_PARENT
,
282 root_win
, XCB_CURRENT_TIME
);
284 client_unfocus_update(c
);
287 /** Check if client supports protocol a protocole in WM_PROTOCOL.
288 * \param c The client.
289 * \param atom The protocol atom to check for.
290 * \return True if client has the atom in protocol, false otherwise.
293 client_hasproto(client_t
*c
, xcb_atom_t atom
)
297 for(i
= 0; i
< c
->protocols
.atoms_len
; i
++)
298 if(c
->protocols
.atoms
[i
] == atom
)
303 /** Sets focus on window - using xcb_set_input_focus or WM_TAKE_FOCUS
304 * \param c Client that should get focus
305 * \param set_input_focus Should we call xcb_set_input_focus
308 client_set_focus(client_t
*c
, bool set_input_focus
)
310 bool takefocus
= client_hasproto(c
, WM_TAKE_FOCUS
);
312 xcb_set_input_focus(globalconf
.connection
, XCB_INPUT_FOCUS_PARENT
,
313 c
->window
, XCB_CURRENT_TIME
);
315 window_takefocus(c
->window
);
318 /** Ban client and move it out of the viewport.
319 * \param c The client.
322 client_ban(client_t
*c
)
326 xcb_unmap_window(globalconf
.connection
, c
->window
);
330 if(globalconf
.screens
.tab
[c
->phys_screen
].prev_client_focus
== c
)
331 globalconf
.screens
.tab
[c
->phys_screen
].prev_client_focus
= NULL
;
333 /* Wait until the last moment to take away the focus from the window. */
334 if(globalconf
.screens
.tab
[c
->phys_screen
].client_focus
== c
)
339 /** This is part of The Bob Marley Algorithmm: we ignore enter and leave window
340 * in certain cases, like map/unmap or move, so we don't get spurious events.
343 client_ignore_enterleave_events(void)
345 foreach(c
, globalconf
.clients
)
346 xcb_change_window_attributes(globalconf
.connection
,
349 (const uint32_t []) { CLIENT_SELECT_INPUT_EVENT_MASK
& ~(XCB_EVENT_MASK_ENTER_WINDOW
| XCB_EVENT_MASK_LEAVE_WINDOW
) });
353 client_restore_enterleave_events(void)
355 foreach(c
, globalconf
.clients
)
356 xcb_change_window_attributes(globalconf
.connection
,
359 (const uint32_t []) { CLIENT_SELECT_INPUT_EVENT_MASK
});
362 /** Record that a client got focus.
363 * \param c The client.
366 client_focus_update(client_t
*c
)
368 if(!client_maybevisible(c
, c
->screen
))
370 /* Focus previously focused client */
371 client_focus(globalconf
.screen_focus
->prev_client_focus
);
375 if(globalconf
.screen_focus
376 && globalconf
.screen_focus
->client_focus
)
378 if (globalconf
.screen_focus
->client_focus
!= c
)
379 client_unfocus_update(globalconf
.screen_focus
->client_focus
);
381 /* Already focused */
384 luaA_object_push(globalconf
.L
, c
);
385 client_set_minimized(globalconf
.L
, -1, false);
387 /* unban the client before focusing for consistency */
390 globalconf
.screen_focus
= &globalconf
.screens
.tab
[c
->phys_screen
];
391 globalconf
.screen_focus
->prev_client_focus
= c
;
392 globalconf
.screen_focus
->client_focus
= c
;
394 /* according to EWMH, we have to remove the urgent state from a client */
395 client_set_urgent(globalconf
.L
, -1, false);
397 ewmh_update_net_active_window(c
->phys_screen
);
400 if(globalconf
.hooks
.focus
!= LUA_REFNIL
)
402 luaA_object_push(globalconf
.L
, c
);
403 luaA_dofunction_from_registry(globalconf
.L
, globalconf
.hooks
.focus
, 1, 0);
406 luaA_object_push(globalconf
.L
, c
);
407 luaA_class_emit_signal(globalconf
.L
, &client_class
, "focus", 1);
410 /** Give focus to client, or to first client if client is NULL.
411 * \param c The client.
414 client_focus(client_t
*c
)
416 /* We have to set focus on first client */
417 if(!c
&& globalconf
.clients
.len
&& !(c
= globalconf
.clients
.tab
[0]))
420 if(!client_maybevisible(c
, c
->screen
))
424 client_focus_update(c
);
426 client_set_focus(c
, !c
->nofocus
);
429 /** Stack a window below.
430 * \param c The client.
431 * \param previous The previous window on the stack.
432 * \return The next-previous!
435 client_stack_above(client_t
*c
, xcb_window_t previous
)
437 uint32_t config_win_vals
[2];
439 config_win_vals
[0] = previous
;
440 config_win_vals
[1] = XCB_STACK_MODE_ABOVE
;
442 xcb_configure_window(globalconf
.connection
, c
->window
,
443 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
446 config_win_vals
[0] = c
->window
;
450 xcb_configure_window(globalconf
.connection
,
452 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
454 previous
= c
->titlebar
->window
;
457 previous
= c
->window
;
459 /* stack transient window on top of their parents */
460 foreach(node
, globalconf
.stack
)
461 if((*node
)->transient_for
== c
)
462 previous
= client_stack_above(*node
, previous
);
467 /** Stacking layout layers */
470 /** This one is a special layer */
478 /** This one only used for counting and is not a real layer */
482 /** Get the real layer of a client according to its attribute (fullscreen, …)
483 * \param c The client.
484 * \return The real layer.
487 client_layer_translator(client_t
*c
)
489 /* first deal with user set attributes */
492 else if(c
->fullscreen
)
493 return LAYER_FULLSCREEN
;
499 /* check for transient attr */
503 /* then deal with windows type */
506 case WINDOW_TYPE_DESKTOP
:
507 return LAYER_DESKTOP
;
516 * \todo It might be worth stopping to restack everyone and only stack `c'
517 * relatively to the first matching in the list.
520 client_stack_refresh()
522 uint32_t config_win_vals
[2];
525 if (!globalconf
.client_need_stack_refresh
)
527 globalconf
.client_need_stack_refresh
= false;
529 config_win_vals
[0] = XCB_NONE
;
530 config_win_vals
[1] = XCB_STACK_MODE_ABOVE
;
532 /* stack desktop windows */
533 for(layer
= LAYER_DESKTOP
; layer
< LAYER_BELOW
; layer
++)
534 foreach(node
, globalconf
.stack
)
535 if(client_layer_translator(*node
) == layer
)
536 config_win_vals
[0] = client_stack_above(*node
,
539 /* first stack not ontop wibox window */
540 foreach(_sb
, globalconf
.wiboxes
)
545 xcb_configure_window(globalconf
.connection
,
547 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
549 config_win_vals
[0] = sb
->window
;
553 /* then stack clients */
554 for(layer
= LAYER_BELOW
; layer
< LAYER_COUNT
; layer
++)
555 foreach(node
, globalconf
.stack
)
556 if(client_layer_translator(*node
) == layer
)
557 config_win_vals
[0] = client_stack_above(*node
,
560 /* then stack ontop wibox window */
561 foreach(_sb
, globalconf
.wiboxes
)
566 xcb_configure_window(globalconf
.connection
,
568 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
570 config_win_vals
[0] = sb
->window
;
575 /** Manage a new client.
576 * \param w The window.
577 * \param wgeom Window geometry.
578 * \param phys_screen Physical screen number.
579 * \param startup True if we are managing at startup time.
582 client_manage(xcb_window_t w
, xcb_get_geometry_reply_t
*wgeom
, int phys_screen
, bool startup
)
585 const uint32_t select_input_val
[] = { CLIENT_SELECT_INPUT_EVENT_MASK
};
587 if(systray_iskdedockapp(w
))
589 systray_request_handle(w
, phys_screen
, NULL
);
593 xcb_change_window_attributes(globalconf
.connection
, w
, XCB_CW_EVENT_MASK
, select_input_val
);
595 client_t
*c
= client_new(globalconf
.L
);
596 /* Push client in client list */
597 client_array_push(&globalconf
.clients
, luaA_object_ref(globalconf
.L
, -1));
600 screen
= c
->screen
= screen_getbycoord(&globalconf
.screens
.tab
[phys_screen
],
603 c
->phys_screen
= phys_screen
;
605 /* consider the window banned */
610 c
->geometry
.x
= wgeom
->x
;
611 c
->geometry
.y
= wgeom
->y
;
612 /* Border will be added later. */
613 c
->geometry
.width
= wgeom
->width
;
614 c
->geometry
.height
= wgeom
->height
;
615 /* Also set internal geometry (client_ban() needs it). */
616 c
->geometries
.internal
.x
= wgeom
->x
;
617 c
->geometries
.internal
.y
= wgeom
->y
;
618 c
->geometries
.internal
.width
= wgeom
->width
;
619 c
->geometries
.internal
.height
= wgeom
->height
;
622 luaA_object_push(globalconf
.L
, c
);
623 client_set_border_width(globalconf
.L
, -1, wgeom
->border_width
);
624 lua_pop(globalconf
.L
, 1);
626 /* we honor size hints by default */
627 c
->size_hints_honor
= true;
630 property_update_wm_normal_hints(c
, NULL
);
631 property_update_wm_hints(c
, NULL
);
632 property_update_wm_transient_for(c
, NULL
);
633 property_update_wm_client_leader(c
, NULL
);
634 property_update_wm_client_machine(c
);
635 property_update_wm_window_role(c
);
636 property_update_net_wm_pid(c
, NULL
);
637 property_update_net_wm_icon(c
, NULL
);
640 c
->opacity
= window_opacity_get(c
->window
);
642 /* Then check clients hints */
643 ewmh_client_check_hints(c
);
645 /* move client to screen, but do not tag it */
646 screen_client_moveto(c
, screen
, false, true);
648 /* Push client in stack */
651 /* update window title */
652 property_update_wm_name(c
);
653 property_update_wm_icon_name(c
);
654 property_update_wm_class(c
, NULL
);
655 property_update_wm_protocols(c
);
657 xutil_text_prop_get(globalconf
.connection
, c
->window
, _NET_STARTUP_ID
, &c
->startup_id
, NULL
);
660 ewmh_process_client_strut(c
, NULL
);
662 ewmh_update_net_client_list(c
->phys_screen
);
664 /* Always stay in NORMAL_STATE. Even though iconified seems more
665 * appropriate sometimes. The only possible loss is that clients not using
666 * visibility events may continue to proces data (when banned).
667 * Without any exposes or other events the cost should be fairly limited though.
669 * Some clients may expect the window to be unmapped when STATE_ICONIFIED.
670 * Two conflicting parts of the ICCCM v2.0 (section 4.1.4):
672 * "Normal -> Iconic - The client should send a ClientMessage event as described later in this section."
673 * (note no explicit mention of unmapping, while Normal->Widthdrawn does mention that)
675 * "Once a client's window has left the Withdrawn state, the window will be mapped
676 * if it is in the Normal state and the window will be unmapped if it is in the Iconic state."
678 * At this stage it's just safer to keep it in normal state and avoid confusion.
680 window_state_set(c
->window
, XCB_WM_STATE_NORMAL
);
683 spawn_start_notify(c
);
685 /* Call hook to notify list change */
686 if(globalconf
.hooks
.clients
!= LUA_REFNIL
)
687 luaA_dofunction_from_registry(globalconf
.L
, globalconf
.hooks
.clients
, 0, 0);
689 luaA_class_emit_signal(globalconf
.L
, &client_class
, "list", 0);
692 if(globalconf
.hooks
.manage
!= LUA_REFNIL
)
694 luaA_object_push(globalconf
.L
, c
);
695 lua_pushboolean(globalconf
.L
, startup
);
696 luaA_dofunction_from_registry(globalconf
.L
, globalconf
.hooks
.manage
, 2, 0);
699 luaA_object_push(globalconf
.L
, c
);
700 lua_pushboolean(globalconf
.L
, startup
);
701 luaA_class_emit_signal(globalconf
.L
, &client_class
, "manage", 2);
704 /** Compute client geometry with respect to its geometry hints.
705 * \param c The client.
706 * \param geometry The geometry that the client might receive.
707 * \return The geometry the client must take respecting its hints.
710 client_geometry_hints(client_t
*c
, area_t geometry
)
712 int32_t basew
, baseh
, minw
, minh
;
714 /* base size is substituted with min size if not specified */
715 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_SIZE
)
717 basew
= c
->size_hints
.base_width
;
718 baseh
= c
->size_hints
.base_height
;
720 else if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MIN_SIZE
)
722 basew
= c
->size_hints
.min_width
;
723 baseh
= c
->size_hints
.min_height
;
728 /* min size is substituted with base size if not specified */
729 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MIN_SIZE
)
731 minw
= c
->size_hints
.min_width
;
732 minh
= c
->size_hints
.min_height
;
734 else if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_SIZE
)
736 minw
= c
->size_hints
.base_width
;
737 minh
= c
->size_hints
.base_height
;
742 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_ASPECT
743 && c
->size_hints
.min_aspect_num
> 0
744 && c
->size_hints
.min_aspect_den
> 0
745 && geometry
.height
- baseh
> 0
746 && geometry
.width
- basew
> 0)
748 double dx
= (double) (geometry
.width
- basew
);
749 double dy
= (double) (geometry
.height
- baseh
);
750 double min
= (double) c
->size_hints
.min_aspect_num
/ (double) c
->size_hints
.min_aspect_den
;
751 double max
= (double) c
->size_hints
.max_aspect_num
/ (double) c
->size_hints
.min_aspect_den
;
752 double ratio
= dx
/ dy
;
753 if(max
> 0 && min
> 0 && ratio
> 0)
757 dy
= (dx
* min
+ dy
) / (min
* min
+ 1);
759 geometry
.width
= (int) dx
+ basew
;
760 geometry
.height
= (int) dy
+ baseh
;
764 dy
= (dx
* min
+ dy
) / (max
* max
+ 1);
766 geometry
.width
= (int) dx
+ basew
;
767 geometry
.height
= (int) dy
+ baseh
;
773 geometry
.width
= MAX(geometry
.width
, minw
);
775 geometry
.height
= MAX(geometry
.height
, minh
);
777 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MAX_SIZE
)
779 if(c
->size_hints
.max_width
)
780 geometry
.width
= MIN(geometry
.width
, c
->size_hints
.max_width
);
781 if(c
->size_hints
.max_height
)
782 geometry
.height
= MIN(geometry
.height
, c
->size_hints
.max_height
);
785 if(c
->size_hints
.flags
& (XCB_SIZE_HINT_P_RESIZE_INC
| XCB_SIZE_HINT_BASE_SIZE
)
786 && c
->size_hints
.width_inc
&& c
->size_hints
.height_inc
)
788 uint16_t t1
= geometry
.width
, t2
= geometry
.height
;
789 unsigned_subtract(t1
, basew
);
790 unsigned_subtract(t2
, baseh
);
791 geometry
.width
-= t1
% c
->size_hints
.width_inc
;
792 geometry
.height
-= t2
% c
->size_hints
.height_inc
;
798 /** Resize client window.
799 * The sizse given as parameters are with titlebar and borders!
800 * \param c Client to resize.
801 * \param geometry New window geometry.
802 * \param hints Use size hints.
803 * \return true if an actual resize occurred.
806 client_resize(client_t
*c
, area_t geometry
, bool hints
)
808 area_t geometry_internal
;
811 /* offscreen appearance fixes */
812 area
= display_area_get(c
->phys_screen
);
814 if(geometry
.x
> area
.width
)
815 geometry
.x
= area
.width
- geometry
.width
;
816 if(geometry
.y
> area
.height
)
817 geometry
.y
= area
.height
- geometry
.height
;
818 if(geometry
.x
+ geometry
.width
< 0)
820 if(geometry
.y
+ geometry
.height
< 0)
823 /* Real client geometry, please keep it contained to C code at the very least. */
824 geometry_internal
= titlebar_geometry_remove(c
->titlebar
, c
->border_width
, geometry
);
827 geometry_internal
= client_geometry_hints(c
, geometry_internal
);
829 if(geometry_internal
.width
== 0 || geometry_internal
.height
== 0)
832 /* Also let client hints propegate to the "official" geometry. */
833 geometry
= titlebar_geometry_add(c
->titlebar
, c
->border_width
, geometry_internal
);
835 if(c
->geometries
.internal
.x
!= geometry_internal
.x
836 || c
->geometries
.internal
.y
!= geometry_internal
.y
837 || c
->geometries
.internal
.width
!= geometry_internal
.width
838 || c
->geometries
.internal
.height
!= geometry_internal
.height
)
840 screen_t
*new_screen
= screen_getbycoord(c
->screen
,
841 geometry_internal
.x
, geometry_internal
.y
);
843 /* Values to configure a window is an array where values are
844 * stored according to 'value_mask' */
847 c
->geometries
.internal
.x
= values
[0] = geometry_internal
.x
;
848 c
->geometries
.internal
.y
= values
[1] = geometry_internal
.y
;
849 c
->geometries
.internal
.width
= values
[2] = geometry_internal
.width
;
850 c
->geometries
.internal
.height
= values
[3] = geometry_internal
.height
;
852 /* Also store geometry including border and titlebar. */
853 c
->geometry
= geometry
;
855 titlebar_update_geometry(c
);
857 /* Ignore all spurious enter/leave notify events */
858 client_ignore_enterleave_events();
860 xcb_configure_window(globalconf
.connection
, c
->window
,
861 XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
862 | XCB_CONFIG_WINDOW_WIDTH
| XCB_CONFIG_WINDOW_HEIGHT
,
865 client_restore_enterleave_events();
867 screen_client_moveto(c
, new_screen
, true, false);
870 hook_property(c
, "geometry");
878 /** Set a client minimized, or not.
879 * \param L The Lua VM state.
880 * \param cidx The client index.
881 * \param s Set or not the client minimized.
884 client_set_minimized(lua_State
*L
, int cidx
, bool s
)
886 client_t
*c
= luaA_client_checkudata(L
, cidx
);
888 if(c
->minimized
!= s
)
890 client_need_reban(c
);
892 client_need_reban(c
);
894 window_state_set(c
->window
, XCB_WM_STATE_ICONIC
);
896 window_state_set(c
->window
, XCB_WM_STATE_NORMAL
);
897 ewmh_client_update_hints(c
);
899 hook_property(c
, "minimized");
900 luaA_object_emit_signal(L
, cidx
, "property::minimized", 0);
904 /** Set a client sticky, or not.
905 * \param L The Lua VM state.
906 * \param cidx The client index.
907 * \param s Set or not the client sticky.
910 client_set_sticky(lua_State
*L
, int cidx
, bool s
)
912 client_t
*c
= luaA_client_checkudata(L
, cidx
);
916 client_need_reban(c
);
918 client_need_reban(c
);
919 ewmh_client_update_hints(c
);
920 hook_property(c
, "sticky");
921 luaA_object_emit_signal(L
, cidx
, "property::sticky", 0);
925 /** Set a client fullscreen, or not.
926 * \param L The Lua VM state.
927 * \param cidx The client index.
928 * \param s Set or not the client fullscreen.
931 client_set_fullscreen(lua_State
*L
, int cidx
, bool s
)
933 client_t
*c
= luaA_client_checkudata(L
, cidx
);
935 if(c
->fullscreen
!= s
)
939 /* become fullscreen! */
942 /* Make sure the current geometry is stored without titlebar. */
943 titlebar_ban(c
->titlebar
);
944 /* remove any max state */
945 client_set_maximized_horizontal(L
, cidx
, false);
946 client_set_maximized_vertical(L
, cidx
, false);
947 /* You can only be part of one of the special layers. */
948 client_set_below(L
, cidx
, false);
949 client_set_above(L
, cidx
, false);
950 client_set_ontop(L
, cidx
, false);
952 geometry
= screen_area_get(c
->screen
, false);
953 c
->geometries
.fullscreen
= c
->geometry
;
954 c
->border_width_fs
= c
->border_width
;
955 client_set_border_width(L
, cidx
, 0);
956 c
->fullscreen
= true;
960 geometry
= c
->geometries
.fullscreen
;
961 c
->fullscreen
= false;
962 client_set_border_width(L
, cidx
, c
->border_width_fs
);
964 client_resize(c
, geometry
, false);
966 ewmh_client_update_hints(c
);
967 hook_property(c
, "fullscreen");
968 luaA_object_emit_signal(L
, cidx
, "property::fullscreen", 0);
972 /** Set a client horizontally maximized.
973 * \param L The Lua VM state.
974 * \param cidx The client index.
975 * \param s The maximized status.
978 client_set_maximized_horizontal(lua_State
*L
, int cidx
, bool s
)
980 client_t
*c
= luaA_client_checkudata(L
, cidx
);
982 if(c
->maximized_horizontal
!= s
)
986 if((c
->maximized_horizontal
= s
))
988 /* remove fullscreen mode */
989 client_set_fullscreen(L
, cidx
, false);
991 geometry
= screen_area_get(c
->screen
, true);
992 geometry
.y
= c
->geometry
.y
;
993 geometry
.height
= c
->geometry
.height
;
994 c
->geometries
.max
.x
= c
->geometry
.x
;
995 c
->geometries
.max
.width
= c
->geometry
.width
;
999 geometry
= c
->geometry
;
1000 geometry
.x
= c
->geometries
.max
.x
;
1001 geometry
.width
= c
->geometries
.max
.width
;
1004 client_resize(c
, geometry
, c
->size_hints_honor
);
1006 ewmh_client_update_hints(c
);
1007 hook_property(c
, "maximized_horizontal");
1008 luaA_object_emit_signal(L
, cidx
, "property::maximized_horizontal", 0);
1012 /** Set a client vertically maximized.
1013 * \param L The Lua VM state.
1014 * \param cidx The client index.
1015 * \param s The maximized status.
1018 client_set_maximized_vertical(lua_State
*L
, int cidx
, bool s
)
1020 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1022 if(c
->maximized_vertical
!= s
)
1026 if((c
->maximized_vertical
= s
))
1028 /* remove fullscreen mode */
1029 client_set_fullscreen(L
, cidx
, false);
1031 geometry
= screen_area_get(c
->screen
, true);
1032 geometry
.x
= c
->geometry
.x
;
1033 geometry
.width
= c
->geometry
.width
;
1034 c
->geometries
.max
.y
= c
->geometry
.y
;
1035 c
->geometries
.max
.height
= c
->geometry
.height
;
1039 geometry
= c
->geometry
;
1040 geometry
.y
= c
->geometries
.max
.y
;
1041 geometry
.height
= c
->geometries
.max
.height
;
1044 client_resize(c
, geometry
, c
->size_hints_honor
);
1046 ewmh_client_update_hints(c
);
1047 hook_property(c
, "maximized_vertical");
1048 luaA_object_emit_signal(L
, cidx
, "property::maximized_vertical", 0);
1052 /** Set a client above, or not.
1053 * \param L The Lua VM state.
1054 * \param cidx The client index.
1055 * \param s Set or not the client above.
1058 client_set_above(lua_State
*L
, int cidx
, bool s
)
1060 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1064 /* You can only be part of one of the special layers. */
1067 client_set_below(L
, cidx
, false);
1068 client_set_ontop(L
, cidx
, false);
1069 client_set_fullscreen(L
, cidx
, false);
1073 ewmh_client_update_hints(c
);
1075 hook_property(c
, "above");
1076 luaA_object_emit_signal(L
, cidx
, "property::above", 0);
1080 /** Set a client below, or not.
1081 * \param L The Lua VM state.
1082 * \param cidx The client index.
1083 * \param s Set or not the client below.
1086 client_set_below(lua_State
*L
, int cidx
, bool s
)
1088 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1092 /* You can only be part of one of the special layers. */
1095 client_set_above(L
, cidx
, false);
1096 client_set_ontop(L
, cidx
, false);
1097 client_set_fullscreen(L
, cidx
, false);
1101 ewmh_client_update_hints(c
);
1103 hook_property(c
, "below");
1104 luaA_object_emit_signal(L
, cidx
, "property::below", 0);
1108 /** Set a client modal, or not.
1109 * \param L The Lua VM state.
1110 * \param cidx The client index.
1111 * \param s Set or not the client modal attribute.
1114 client_set_modal(lua_State
*L
, int cidx
, bool s
)
1116 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1122 ewmh_client_update_hints(c
);
1124 hook_property(c
, "modal");
1125 luaA_object_emit_signal(L
, cidx
, "property::modal", 0);
1129 /** Set a client ontop, or not.
1130 * \param L The Lua VM state.
1131 * \param cidx The client index.
1132 * \param s Set or not the client ontop attribute.
1135 client_set_ontop(lua_State
*L
, int cidx
, bool s
)
1137 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1141 /* You can only be part of one of the special layers. */
1144 client_set_above(L
, cidx
, false);
1145 client_set_below(L
, cidx
, false);
1146 client_set_fullscreen(L
, cidx
, false);
1151 hook_property(c
, "ontop");
1152 luaA_object_emit_signal(L
, cidx
, "property::ontop", 0);
1156 /** Set a client skip taskbar attribute.
1157 * \param L Tha Lua VM state.
1158 * \param cidx The client index.
1159 * \param s Set or not the client skip taskbar attribute.
1162 client_set_skip_taskbar(lua_State
*L
, int cidx
, bool s
)
1164 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1166 if(c
->skip_taskbar
!= s
)
1168 c
->skip_taskbar
= s
;
1169 luaA_object_emit_signal(L
, cidx
, "property::skip_taskbar", 0);
1173 /** Unban a client and move it back into the viewport.
1174 * \param c The client.
1177 client_unban(client_t
*c
)
1181 xcb_map_window(globalconf
.connection
, c
->window
);
1183 c
->isbanned
= false;
1187 /** Unmanage a client.
1188 * \param c The client.
1191 client_unmanage(client_t
*c
)
1193 tag_array_t
*tags
= &c
->screen
->tags
;
1195 /* Reset transient_for attributes of widows that maybe refering to us */
1196 foreach(_tc
, globalconf
.clients
)
1198 client_t
*tc
= *_tc
;
1199 if(tc
->transient_for
== c
)
1200 tc
->transient_for
= NULL
;
1203 if(globalconf
.screens
.tab
[c
->phys_screen
].prev_client_focus
== c
)
1204 globalconf
.screens
.tab
[c
->phys_screen
].prev_client_focus
= NULL
;
1206 if(globalconf
.screens
.tab
[c
->phys_screen
].client_focus
== c
)
1209 /* remove client from global list and everywhere else */
1210 foreach(elem
, globalconf
.clients
)
1213 client_array_remove(&globalconf
.clients
, elem
);
1216 stack_client_remove(c
);
1217 for(int i
= 0; i
< tags
->len
; i
++)
1218 untag_client(c
, tags
->tab
[i
]);
1221 if(globalconf
.hooks
.unmanage
!= LUA_REFNIL
)
1223 luaA_object_push(globalconf
.L
, c
);
1224 luaA_dofunction_from_registry(globalconf
.L
, globalconf
.hooks
.unmanage
, 1, 0);
1227 luaA_object_push(globalconf
.L
, c
);
1228 luaA_class_emit_signal(globalconf
.L
, &client_class
, "unmanage", 1);
1230 /* Call hook to notify list change */
1231 if(globalconf
.hooks
.clients
!= LUA_REFNIL
)
1232 luaA_dofunction_from_registry(globalconf
.L
, globalconf
.hooks
.clients
, 0, 0);
1234 luaA_class_emit_signal(globalconf
.L
, &client_class
, "list", 0);
1236 window_state_set(c
->window
, XCB_WM_STATE_WITHDRAWN
);
1238 titlebar_client_detach(c
);
1240 ewmh_update_net_client_list(c
->phys_screen
);
1242 /* set client as invalid */
1245 luaA_object_unref(globalconf
.L
, c
);
1248 /** Kill a client via a WM_DELETE_WINDOW request or KillClient if not
1250 * \param c The client to kill.
1253 client_kill(client_t
*c
)
1255 if(client_hasproto(c
, WM_DELETE_WINDOW
))
1257 xcb_client_message_event_t ev
;
1259 /* Initialize all of event's fields first */
1262 ev
.response_type
= XCB_CLIENT_MESSAGE
;
1263 ev
.window
= c
->window
;
1265 ev
.data
.data32
[1] = XCB_CURRENT_TIME
;
1266 ev
.type
= WM_PROTOCOLS
;
1267 ev
.data
.data32
[0] = WM_DELETE_WINDOW
;
1269 xcb_send_event(globalconf
.connection
, false, c
->window
,
1270 XCB_EVENT_MASK_NO_EVENT
, (char *) &ev
);
1273 xcb_kill_client(globalconf
.connection
, c
->window
);
1276 /** Get all clients into a table.
1277 * \param L The Lua VM state.
1278 * \return The number of elements pushed on stack.
1280 * \lparam An optional screen nunmber.
1281 * \lreturn A table with all clients.
1284 luaA_client_get(lua_State
*L
)
1288 screen
= luaL_optnumber(L
, 1, 0) - 1;
1293 foreach(c
, globalconf
.clients
)
1295 luaA_object_push(L
, *c
);
1296 lua_rawseti(L
, -2, i
++);
1300 luaA_checkscreen(screen
);
1301 foreach(c
, globalconf
.clients
)
1302 if((*c
)->screen
== &globalconf
.screens
.tab
[screen
])
1304 luaA_object_push(L
, *c
);
1305 lua_rawseti(L
, -2, i
++);
1312 /** Check if a client is visible on its screen.
1313 * \param L The Lua VM state.
1314 * \return The number of elements pushed on stack.
1317 * \lreturn A boolean value, true if the client is visible, false otherwise.
1320 luaA_client_isvisible(lua_State
*L
)
1322 client_t
*c
= luaA_client_checkudata(L
, 1);
1323 lua_pushboolean(L
, client_isvisible(c
, c
->screen
));
1327 /** Set client border width.
1328 * \param L The Lua VM state.
1329 * \param cidx The client index.
1330 * \param width The border width.
1333 client_set_border_width(lua_State
*L
, int cidx
, int width
)
1335 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1338 if(width
> 0 && (c
->type
== WINDOW_TYPE_DOCK
1339 || c
->type
== WINDOW_TYPE_SPLASH
1340 || c
->type
== WINDOW_TYPE_DESKTOP
1344 if(width
== c
->border_width
|| width
< 0)
1347 /* disallow change of border width if the client is fullscreen */
1351 /* Update geometry with the new border. */
1352 c
->geometry
.width
-= 2 * c
->border_width
;
1353 c
->geometry
.height
-= 2 * c
->border_width
;
1355 c
->border_width
= width
;
1356 xcb_configure_window(globalconf
.connection
, c
->window
,
1357 XCB_CONFIG_WINDOW_BORDER_WIDTH
, &w
);
1359 c
->geometry
.width
+= 2 * c
->border_width
;
1360 c
->geometry
.height
+= 2 * c
->border_width
;
1362 /* Changing border size also affects the size of the titlebar. */
1363 titlebar_update_geometry(c
);
1365 hook_property(c
, "border_width");
1366 luaA_object_emit_signal(L
, cidx
, "property::border_width", 0);
1369 /** Set a client icon.
1370 * \param L The Lua VM state.
1371 * \param cidx The client index on the stack.
1372 * \para iidx The image index on the stack.
1375 client_set_icon(lua_State
*L
, int cidx
, int iidx
)
1377 client_t
*c
= luaA_client_checkudata(L
, cidx
);
1378 luaA_checkudata(L
, iidx
, &image_class
);
1379 luaA_object_unref_item(L
, cidx
, c
->icon
);
1380 c
->icon
= luaA_object_ref_item(L
, cidx
, iidx
);
1381 luaA_object_emit_signal(L
, cidx
, "property::icon", 0);
1383 hook_property(c
, "icon");
1387 * \param L The Lua VM state.
1393 luaA_client_kill(lua_State
*L
)
1395 client_t
*c
= luaA_client_checkudata(L
, 1);
1400 /** Swap a client with another one.
1401 * \param L The Lua VM state.
1404 * \lparam A client to swap with.
1407 luaA_client_swap(lua_State
*L
)
1409 client_t
*c
= luaA_client_checkudata(L
, 1);
1410 client_t
*swap
= luaA_client_checkudata(L
, 2);
1414 client_t
**ref_c
= NULL
, **ref_swap
= NULL
;
1415 foreach(item
, globalconf
.clients
)
1419 else if(*item
== swap
)
1421 if(ref_c
&& ref_swap
)
1428 /* Call hook to notify list change */
1429 if(globalconf
.hooks
.clients
!= LUA_REFNIL
)
1430 luaA_dofunction_from_registry(L
, globalconf
.hooks
.clients
, 0, 0);
1432 luaA_class_emit_signal(globalconf
.L
, &client_class
, "list", 0);
1438 /** Access or set the client tags.
1439 * \param L The Lua VM state.
1440 * \return The number of elements pushed on stack.
1441 * \lparam A table with tags to set, or none to get the current tags table.
1442 * \return The clients tag.
1445 luaA_client_tags(lua_State
*L
)
1447 client_t
*c
= luaA_client_checkudata(L
, 1);
1448 tag_array_t
*tags
= &c
->screen
->tags
;
1451 if(lua_gettop(L
) == 2)
1453 luaA_checktable(L
, 2);
1454 for(int i
= 0; i
< tags
->len
; i
++)
1455 untag_client(c
, tags
->tab
[i
]);
1457 while(lua_next(L
, 2))
1464 if(is_client_tagged(c
, *tag
))
1466 luaA_object_push(L
, *tag
);
1467 lua_rawseti(L
, -2, ++j
);
1473 /** Raise a client on top of others which are on the same layer.
1474 * \param L The Lua VM state.
1479 luaA_client_raise(lua_State
*L
)
1481 client_t
*c
= luaA_client_checkudata(L
, 1);
1486 /** Lower a client on bottom of others which are on the same layer.
1487 * \param L The Lua VM state.
1492 luaA_client_lower(lua_State
*L
)
1494 client_t
*c
= luaA_client_checkudata(L
, 1);
1499 /** Redraw a client by unmapping and mapping it quickly.
1500 * \param L The Lua VM state.
1506 luaA_client_redraw(lua_State
*L
)
1508 client_t
*c
= luaA_client_checkudata(L
, 1);
1510 xcb_unmap_window(globalconf
.connection
, c
->window
);
1511 xcb_map_window(globalconf
.connection
, c
->window
);
1513 /* Set the focus on the current window if the redraw has been
1514 performed on the window where the pointer is currently on
1515 because after the unmapping/mapping, the focus is lost */
1516 if(globalconf
.screen_focus
->client_focus
== c
)
1525 /** Stop managing a client.
1526 * \param L The Lua VM state.
1527 * \return The number of elements pushed on stack.
1532 luaA_client_unmanage(lua_State
*L
)
1534 client_t
*c
= luaA_client_checkudata(L
, 1);
1539 /** Return client geometry.
1540 * \param L The Lua VM state.
1541 * \return The number of elements pushed on stack.
1543 * \lparam A table with new coordinates, or none.
1544 * \lreturn A table with client coordinates.
1547 luaA_client_geometry(lua_State
*L
)
1549 client_t
*c
= luaA_client_checkudata(L
, 1);
1551 if(lua_gettop(L
) == 2)
1555 luaA_checktable(L
, 2);
1556 geometry
.x
= luaA_getopt_number(L
, 2, "x", c
->geometry
.x
);
1557 geometry
.y
= luaA_getopt_number(L
, 2, "y", c
->geometry
.y
);
1558 if(client_isfixed(c
))
1560 geometry
.width
= c
->geometry
.width
;
1561 geometry
.height
= c
->geometry
.height
;
1565 geometry
.width
= luaA_getopt_number(L
, 2, "width", c
->geometry
.width
);
1566 geometry
.height
= luaA_getopt_number(L
, 2, "height", c
->geometry
.height
);
1569 client_resize(c
, geometry
, c
->size_hints_honor
);
1572 return luaA_pusharea(L
, c
->geometry
);
1575 /** Return client struts (reserved space at the edge of the screen).
1576 * \param L The Lua VM state.
1577 * \return The number of elements pushed on stack.
1579 * \lparam A table with new strut values, or none.
1580 * \lreturn A table with strut values.
1583 luaA_client_struts(lua_State
*L
)
1585 client_t
*c
= luaA_client_checkudata(L
, 1);
1587 if(lua_gettop(L
) == 2)
1589 luaA_tostrut(L
, 2, &c
->strut
);
1590 ewmh_update_strut(c
->window
, &c
->strut
);
1591 hook_property(c
, "struts");
1592 luaA_object_emit_signal(L
, 1, "property::struts", 0);
1593 screen_emit_signal(L
, c
->screen
, "property::workarea", 0);
1596 return luaA_pushstrut(L
, c
->strut
);
1600 luaA_client_set_screen(lua_State
*L
, client_t
*c
)
1602 if(globalconf
.xinerama_is_active
)
1604 int screen
= luaL_checknumber(L
, -1) - 1;
1605 luaA_checkscreen(screen
);
1606 screen_client_moveto(c
, &globalconf
.screens
.tab
[screen
], true, true);
1612 luaA_client_set_hidden(lua_State
*L
, client_t
*c
)
1614 bool b
= luaA_checkboolean(L
, -1);
1617 client_need_reban(c
);
1619 client_need_reban(c
);
1620 hook_property(c
, "hidden");
1621 luaA_object_emit_signal(L
, -3, "property::screen", 0);
1627 luaA_client_set_minimized(lua_State
*L
, client_t
*c
)
1629 client_set_minimized(L
, -3, luaA_checkboolean(L
, -1));
1634 luaA_client_set_fullscreen(lua_State
*L
, client_t
*c
)
1636 client_set_fullscreen(L
, -3, luaA_checkboolean(L
, -1));
1641 luaA_client_set_modal(lua_State
*L
, client_t
*c
)
1643 client_set_modal(L
, -3, luaA_checkboolean(L
, -1));
1648 luaA_client_set_maximized_horizontal(lua_State
*L
, client_t
*c
)
1650 client_set_maximized_horizontal(L
, -3, luaA_checkboolean(L
, -1));
1655 luaA_client_set_maximized_vertical(lua_State
*L
, client_t
*c
)
1657 client_set_maximized_vertical(L
, -3, luaA_checkboolean(L
, -1));
1662 luaA_client_set_icon(lua_State
*L
, client_t
*c
)
1664 client_set_icon(L
, -3, -1);
1669 luaA_client_set_opacity(lua_State
*L
, client_t
*c
)
1671 if(lua_isnil(L
, -1))
1672 client_set_opacity(L
, -3, -1);
1674 client_set_opacity(L
, -3, luaL_checknumber(L
, -1));
1679 luaA_client_set_sticky(lua_State
*L
, client_t
*c
)
1681 client_set_sticky(L
, -3, luaA_checkboolean(L
, -1));
1686 luaA_client_set_size_hints_honor(lua_State
*L
, client_t
*c
)
1688 c
->size_hints_honor
= luaA_checkboolean(L
, -1);
1689 hook_property(c
, "size_hints_honor");
1690 luaA_object_emit_signal(L
, -3, "property::size_hints_honor", 0);
1695 luaA_client_set_border_width(lua_State
*L
, client_t
*c
)
1697 client_set_border_width(L
, -3, luaL_checknumber(L
, -1));
1702 luaA_client_set_ontop(lua_State
*L
, client_t
*c
)
1704 client_set_ontop(L
, -3, luaA_checkboolean(L
, -1));
1709 luaA_client_set_below(lua_State
*L
, client_t
*c
)
1711 client_set_below(L
, -3, luaA_checkboolean(L
, -1));
1716 luaA_client_set_above(lua_State
*L
, client_t
*c
)
1718 client_set_above(L
, -3, luaA_checkboolean(L
, -1));
1723 luaA_client_set_urgent(lua_State
*L
, client_t
*c
)
1725 client_set_urgent(L
, -3, luaA_checkboolean(L
, -1));
1730 luaA_client_set_border_color(lua_State
*L
, client_t
*c
)
1734 if((buf
= luaL_checklstring(L
, -1, &len
))
1735 && xcolor_init_reply(xcolor_init_unchecked(&c
->border_color
, buf
, len
)))
1737 xcb_change_window_attributes(globalconf
.connection
, c
->window
,
1738 XCB_CW_BORDER_PIXEL
, &c
->border_color
.pixel
);
1739 luaA_object_emit_signal(L
, -3, "property::border_color", 0);
1745 luaA_client_set_titlebar(lua_State
*L
, client_t
*c
)
1747 if(lua_isnil(L
, -1))
1748 titlebar_client_detach(c
);
1750 titlebar_client_attach(c
);
1755 luaA_client_set_skip_taskbar(lua_State
*L
, client_t
*c
)
1757 client_set_skip_taskbar(L
, -3, luaA_checkboolean(L
, -1));
1761 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, name
, lua_pushstring
)
1762 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, icon_name
, lua_pushstring
)
1763 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, class, lua_pushstring
)
1764 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, instance
, lua_pushstring
)
1765 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, machine
, lua_pushstring
)
1766 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, role
, lua_pushstring
)
1767 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, transient_for
, luaA_object_push
)
1768 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, skip_taskbar
, lua_pushboolean
)
1769 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, window
, lua_pushnumber
)
1770 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, leader_window
, lua_pushnumber
)
1771 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, group_window
, lua_pushnumber
)
1772 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, pid
, lua_pushnumber
)
1773 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, hidden
, lua_pushboolean
)
1774 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, minimized
, lua_pushboolean
)
1775 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, fullscreen
, lua_pushboolean
)
1776 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, modal
, lua_pushboolean
)
1777 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, ontop
, lua_pushboolean
)
1778 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, urgent
, lua_pushboolean
)
1779 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, above
, lua_pushboolean
)
1780 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, below
, lua_pushboolean
)
1781 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, sticky
, lua_pushboolean
)
1782 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, size_hints_honor
, lua_pushboolean
)
1783 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, maximized_horizontal
, lua_pushboolean
)
1784 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, maximized_vertical
, lua_pushboolean
)
1785 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, opacity
, lua_pushnumber
)
1786 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, border_width
, lua_pushnumber
)
1787 LUA_OBJECT_EXPORT_PROPERTY(client
, client_t
, border_color
, luaA_pushxcolor
)
1790 luaA_client_get_content(lua_State
*L
, client_t
*c
)
1792 xcb_image_t
*ximage
= xcb_image_get(globalconf
.connection
,
1795 c
->geometries
.internal
.width
,
1796 c
->geometries
.internal
.height
,
1797 ~0, XCB_IMAGE_FORMAT_Z_PIXMAP
);
1802 if(ximage
->bpp
>= 24)
1804 uint32_t *data
= p_alloca(uint32_t, ximage
->width
* ximage
->height
);
1806 for(int y
= 0; y
< ximage
->height
; y
++)
1807 for(int x
= 0; x
< ximage
->width
; x
++)
1809 data
[y
* ximage
->width
+ x
] = xcb_image_get_pixel(ximage
, x
, y
);
1810 data
[y
* ximage
->width
+ x
] |= 0xff000000; /* set alpha to 0xff */
1813 retval
= image_new_from_argb32(ximage
->width
, ximage
->height
, data
);
1815 xcb_image_destroy(ximage
);
1822 luaA_client_get_type(lua_State
*L
, client_t
*c
)
1826 case WINDOW_TYPE_DESKTOP
:
1827 lua_pushliteral(L
, "desktop");
1829 case WINDOW_TYPE_DOCK
:
1830 lua_pushliteral(L
, "dock");
1832 case WINDOW_TYPE_SPLASH
:
1833 lua_pushliteral(L
, "splash");
1835 case WINDOW_TYPE_DIALOG
:
1836 lua_pushliteral(L
, "dialog");
1838 case WINDOW_TYPE_MENU
:
1839 lua_pushliteral(L
, "menu");
1841 case WINDOW_TYPE_TOOLBAR
:
1842 lua_pushliteral(L
, "toolbar");
1844 case WINDOW_TYPE_UTILITY
:
1845 lua_pushliteral(L
, "utility");
1847 case WINDOW_TYPE_DROPDOWN_MENU
:
1848 lua_pushliteral(L
, "dropdown_menu");
1850 case WINDOW_TYPE_POPUP_MENU
:
1851 lua_pushliteral(L
, "popup_menu");
1853 case WINDOW_TYPE_TOOLTIP
:
1854 lua_pushliteral(L
, "tooltip");
1856 case WINDOW_TYPE_NOTIFICATION
:
1857 lua_pushliteral(L
, "notification");
1859 case WINDOW_TYPE_COMBO
:
1860 lua_pushliteral(L
, "combo");
1862 case WINDOW_TYPE_DND
:
1863 lua_pushliteral(L
, "dnd");
1865 case WINDOW_TYPE_NORMAL
:
1866 lua_pushliteral(L
, "normal");
1873 luaA_client_get_screen(lua_State
*L
, client_t
*c
)
1875 lua_pushnumber(L
, 1 + screen_array_indexof(&globalconf
.screens
, c
->screen
));
1880 luaA_client_get_icon(lua_State
*L
, client_t
*c
)
1882 return luaA_object_push_item(L
, -2, c
->icon
);
1886 luaA_client_get_titlebar(lua_State
*L
, client_t
*c
)
1888 return luaA_object_push_item(L
, -2, c
->titlebar
);
1892 luaA_client_get_size_hints(lua_State
*L
, client_t
*c
)
1894 const char *u_or_p
= NULL
;
1896 lua_createtable(L
, 0, 1);
1898 if(c
->size_hints
.flags
& XCB_SIZE_HINT_US_POSITION
)
1899 u_or_p
= "user_position";
1900 else if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_POSITION
)
1901 u_or_p
= "program_position";
1905 lua_createtable(L
, 0, 2);
1906 lua_pushnumber(L
, c
->size_hints
.x
);
1907 lua_setfield(L
, -2, "x");
1908 lua_pushnumber(L
, c
->size_hints
.y
);
1909 lua_setfield(L
, -2, "y");
1910 lua_setfield(L
, -2, u_or_p
);
1914 if(c
->size_hints
.flags
& XCB_SIZE_HINT_US_SIZE
)
1915 u_or_p
= "user_size";
1916 else if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_SIZE
)
1917 u_or_p
= "program_size";
1921 lua_createtable(L
, 0, 2);
1922 lua_pushnumber(L
, c
->size_hints
.width
);
1923 lua_setfield(L
, -2, "width");
1924 lua_pushnumber(L
, c
->size_hints
.height
);
1925 lua_setfield(L
, -2, "height");
1926 lua_setfield(L
, -2, u_or_p
);
1929 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MIN_SIZE
)
1931 lua_pushnumber(L
, c
->size_hints
.min_width
);
1932 lua_setfield(L
, -2, "min_width");
1933 lua_pushnumber(L
, c
->size_hints
.min_height
);
1934 lua_setfield(L
, -2, "min_height");
1937 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MAX_SIZE
)
1939 lua_pushnumber(L
, c
->size_hints
.max_width
);
1940 lua_setfield(L
, -2, "max_width");
1941 lua_pushnumber(L
, c
->size_hints
.max_height
);
1942 lua_setfield(L
, -2, "max_height");
1945 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_RESIZE_INC
)
1947 lua_pushnumber(L
, c
->size_hints
.width_inc
);
1948 lua_setfield(L
, -2, "width_inc");
1949 lua_pushnumber(L
, c
->size_hints
.height_inc
);
1950 lua_setfield(L
, -2, "height_inc");
1953 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_ASPECT
)
1955 lua_pushnumber(L
, c
->size_hints
.min_aspect_num
);
1956 lua_setfield(L
, -2, "min_aspect_num");
1957 lua_pushnumber(L
, c
->size_hints
.min_aspect_den
);
1958 lua_setfield(L
, -2, "min_aspect_den");
1959 lua_pushnumber(L
, c
->size_hints
.max_aspect_num
);
1960 lua_setfield(L
, -2, "max_aspect_num");
1961 lua_pushnumber(L
, c
->size_hints
.max_aspect_den
);
1962 lua_setfield(L
, -2, "max_aspect_den");
1965 if(c
->size_hints
.flags
& XCB_SIZE_HINT_BASE_SIZE
)
1967 lua_pushnumber(L
, c
->size_hints
.base_width
);
1968 lua_setfield(L
, -2, "base_width");
1969 lua_pushnumber(L
, c
->size_hints
.base_height
);
1970 lua_setfield(L
, -2, "base_height");
1973 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_WIN_GRAVITY
)
1975 switch(c
->size_hints
.win_gravity
)
1978 lua_pushliteral(L
, "north_west");
1980 case XCB_GRAVITY_NORTH
:
1981 lua_pushliteral(L
, "north");
1983 case XCB_GRAVITY_NORTH_EAST
:
1984 lua_pushliteral(L
, "north_east");
1986 case XCB_GRAVITY_WEST
:
1987 lua_pushliteral(L
, "west");
1989 case XCB_GRAVITY_CENTER
:
1990 lua_pushliteral(L
, "center");
1992 case XCB_GRAVITY_EAST
:
1993 lua_pushliteral(L
, "east");
1995 case XCB_GRAVITY_SOUTH_WEST
:
1996 lua_pushliteral(L
, "south_west");
1998 case XCB_GRAVITY_SOUTH
:
1999 lua_pushliteral(L
, "south");
2001 case XCB_GRAVITY_SOUTH_EAST
:
2002 lua_pushliteral(L
, "south_east");
2004 case XCB_GRAVITY_STATIC
:
2005 lua_pushliteral(L
, "static");
2008 lua_setfield(L
, -2, "win_gravity");
2014 /** Get or set mouse buttons bindings for a client.
2015 * \param L The Lua VM state.
2016 * \return The number of element pushed on stack.
2019 * \lparam An array of mouse button bindings objects, or nothing.
2020 * \return The array of mouse button bindings objects of this client.
2023 luaA_client_buttons(lua_State
*L
)
2025 client_t
*client
= luaA_client_checkudata(L
, 1);
2026 button_array_t
*buttons
= &client
->buttons
;
2028 if(lua_gettop(L
) == 2)
2030 luaA_button_array_set(L
, 1, 2, buttons
);
2031 luaA_object_emit_signal(L
, 1, "property::buttons", 0);
2032 window_buttons_grab(client
->window
, &client
->buttons
);
2035 return luaA_button_array_get(L
, 1, buttons
);
2038 /** Get or set keys bindings for a client.
2039 * \param L The Lua VM state.
2040 * \return The number of element pushed on stack.
2043 * \lparam An array of key bindings objects, or nothing.
2044 * \return The array of key bindings objects of this client.
2047 luaA_client_keys(lua_State
*L
)
2049 client_t
*c
= luaA_client_checkudata(L
, 1);
2050 key_array_t
*keys
= &c
->keys
;
2052 if(lua_gettop(L
) == 2)
2054 luaA_key_array_set(L
, 1, 2, keys
);
2055 luaA_object_emit_signal(L
, 1, "property::keys", 0);
2056 xcb_ungrab_key(globalconf
.connection
, XCB_GRAB_ANY
, c
->window
, XCB_BUTTON_MASK_ANY
);
2057 window_grabkeys(c
->window
, keys
);
2060 return luaA_key_array_get(L
, 1, keys
);
2064 * \param L The Lua VM state.
2065 * \return The number of pushed elements.
2068 luaA_client_module_index(lua_State
*L
)
2071 const char *buf
= luaL_checklstring(L
, 2, &len
);
2073 switch(a_tokenize(buf
, len
))
2076 return luaA_object_push(globalconf
.L
, globalconf
.screen_focus
->client_focus
);
2083 /* Client module new index.
2084 * \param L The Lua VM state.
2085 * \return The number of pushed elements.
2088 luaA_client_module_newindex(lua_State
*L
)
2091 const char *buf
= luaL_checklstring(L
, 2, &len
);
2094 switch(a_tokenize(buf
, len
))
2097 c
= luaA_client_checkudata(L
, 3);
2108 client_class_setup(lua_State
*L
)
2110 static const struct luaL_reg client_methods
[] =
2112 LUA_CLASS_METHODS(client
)
2113 { "get", luaA_client_get
},
2114 { "__index", luaA_client_module_index
},
2115 { "__newindex", luaA_client_module_newindex
},
2119 static const struct luaL_reg client_meta
[] =
2121 LUA_OBJECT_META(client
)
2123 { "buttons", luaA_client_buttons
},
2124 { "keys", luaA_client_keys
},
2125 { "isvisible", luaA_client_isvisible
},
2126 { "geometry", luaA_client_geometry
},
2127 { "struts", luaA_client_struts
},
2128 { "tags", luaA_client_tags
},
2129 { "kill", luaA_client_kill
},
2130 { "swap", luaA_client_swap
},
2131 { "raise", luaA_client_raise
},
2132 { "lower", luaA_client_lower
},
2133 { "redraw", luaA_client_redraw
},
2134 { "unmanage", luaA_client_unmanage
},
2135 { "__gc", luaA_client_gc
},
2139 luaA_class_setup(L
, &client_class
, "client", (lua_class_allocator_t
) client_new
,
2140 luaA_class_index_miss_property
, luaA_class_newindex_miss_property
,
2141 client_methods
, client_meta
);
2142 luaA_class_add_property(&client_class
, A_TK_NAME
,
2144 (lua_class_propfunc_t
) luaA_client_get_name
,
2146 luaA_class_add_property(&client_class
, A_TK_TRANSIENT_FOR
,
2148 (lua_class_propfunc_t
) luaA_client_get_transient_for
,
2150 luaA_class_add_property(&client_class
, A_TK_SKIP_TASKBAR
,
2151 (lua_class_propfunc_t
) luaA_client_set_skip_taskbar
,
2152 (lua_class_propfunc_t
) luaA_client_get_skip_taskbar
,
2153 (lua_class_propfunc_t
) luaA_client_set_skip_taskbar
);
2154 luaA_class_add_property(&client_class
, A_TK_CONTENT
,
2156 (lua_class_propfunc_t
) luaA_client_get_content
,
2158 luaA_class_add_property(&client_class
, A_TK_TYPE
,
2160 (lua_class_propfunc_t
) luaA_client_get_type
,
2162 luaA_class_add_property(&client_class
, A_TK_CLASS
,
2164 (lua_class_propfunc_t
) luaA_client_get_class
,
2166 luaA_class_add_property(&client_class
, A_TK_INSTANCE
,
2168 (lua_class_propfunc_t
) luaA_client_get_instance
,
2170 luaA_class_add_property(&client_class
, A_TK_ROLE
,
2172 (lua_class_propfunc_t
) luaA_client_get_role
,
2174 luaA_class_add_property(&client_class
, A_TK_PID
,
2176 (lua_class_propfunc_t
) luaA_client_get_pid
,
2178 luaA_class_add_property(&client_class
, A_TK_WINDOW
,
2180 (lua_class_propfunc_t
) luaA_client_get_window
,
2182 luaA_class_add_property(&client_class
, A_TK_LEADER_WINDOW
,
2184 (lua_class_propfunc_t
) luaA_client_get_leader_window
,
2186 luaA_class_add_property(&client_class
, A_TK_MACHINE
,
2188 (lua_class_propfunc_t
) luaA_client_get_machine
,
2190 luaA_class_add_property(&client_class
, A_TK_ICON_NAME
,
2192 (lua_class_propfunc_t
) luaA_client_get_icon_name
,
2194 luaA_class_add_property(&client_class
, A_TK_SCREEN
,
2196 (lua_class_propfunc_t
) luaA_client_get_screen
,
2197 (lua_class_propfunc_t
) luaA_client_set_screen
);
2198 luaA_class_add_property(&client_class
, A_TK_HIDDEN
,
2199 (lua_class_propfunc_t
) luaA_client_set_hidden
,
2200 (lua_class_propfunc_t
) luaA_client_get_hidden
,
2201 (lua_class_propfunc_t
) luaA_client_set_hidden
);
2202 luaA_class_add_property(&client_class
, A_TK_MINIMIZED
,
2203 (lua_class_propfunc_t
) luaA_client_set_minimized
,
2204 (lua_class_propfunc_t
) luaA_client_get_minimized
,
2205 (lua_class_propfunc_t
) luaA_client_set_minimized
);
2206 luaA_class_add_property(&client_class
, A_TK_FULLSCREEN
,
2207 (lua_class_propfunc_t
) luaA_client_set_fullscreen
,
2208 (lua_class_propfunc_t
) luaA_client_get_fullscreen
,
2209 (lua_class_propfunc_t
) luaA_client_set_fullscreen
);
2210 luaA_class_add_property(&client_class
, A_TK_MODAL
,
2211 (lua_class_propfunc_t
) luaA_client_set_modal
,
2212 (lua_class_propfunc_t
) luaA_client_get_modal
,
2213 (lua_class_propfunc_t
) luaA_client_set_modal
);
2214 luaA_class_add_property(&client_class
, A_TK_GROUP_WINDOW
,
2216 (lua_class_propfunc_t
) luaA_client_get_group_window
,
2218 luaA_class_add_property(&client_class
, A_TK_MAXIMIZED_HORIZONTAL
,
2219 (lua_class_propfunc_t
) luaA_client_set_maximized_horizontal
,
2220 (lua_class_propfunc_t
) luaA_client_get_maximized_horizontal
,
2221 (lua_class_propfunc_t
) luaA_client_set_maximized_horizontal
);
2222 luaA_class_add_property(&client_class
, A_TK_MAXIMIZED_VERTICAL
,
2223 (lua_class_propfunc_t
) luaA_client_set_maximized_vertical
,
2224 (lua_class_propfunc_t
) luaA_client_get_maximized_vertical
,
2225 (lua_class_propfunc_t
) luaA_client_set_maximized_vertical
);
2226 luaA_class_add_property(&client_class
, A_TK_ICON
,
2227 (lua_class_propfunc_t
) luaA_client_set_icon
,
2228 (lua_class_propfunc_t
) luaA_client_get_icon
,
2229 (lua_class_propfunc_t
) luaA_client_set_icon
);
2230 luaA_class_add_property(&client_class
, A_TK_OPACITY
,
2231 (lua_class_propfunc_t
) luaA_client_set_opacity
,
2232 (lua_class_propfunc_t
) luaA_client_get_opacity
,
2233 (lua_class_propfunc_t
) luaA_client_set_opacity
);
2234 luaA_class_add_property(&client_class
, A_TK_ONTOP
,
2235 (lua_class_propfunc_t
) luaA_client_set_ontop
,
2236 (lua_class_propfunc_t
) luaA_client_get_ontop
,
2237 (lua_class_propfunc_t
) luaA_client_set_ontop
);
2238 luaA_class_add_property(&client_class
, A_TK_ABOVE
,
2239 (lua_class_propfunc_t
) luaA_client_set_above
,
2240 (lua_class_propfunc_t
) luaA_client_get_above
,
2241 (lua_class_propfunc_t
) luaA_client_set_above
);
2242 luaA_class_add_property(&client_class
, A_TK_BELOW
,
2243 (lua_class_propfunc_t
) luaA_client_set_below
,
2244 (lua_class_propfunc_t
) luaA_client_get_below
,
2245 (lua_class_propfunc_t
) luaA_client_set_below
);
2246 luaA_class_add_property(&client_class
, A_TK_STICKY
,
2247 (lua_class_propfunc_t
) luaA_client_set_sticky
,
2248 (lua_class_propfunc_t
) luaA_client_get_sticky
,
2249 (lua_class_propfunc_t
) luaA_client_set_sticky
);
2250 luaA_class_add_property(&client_class
, A_TK_SIZE_HINTS_HONOR
,
2251 (lua_class_propfunc_t
) luaA_client_set_size_hints_honor
,
2252 (lua_class_propfunc_t
) luaA_client_get_size_hints_honor
,
2253 (lua_class_propfunc_t
) luaA_client_set_size_hints_honor
);
2254 luaA_class_add_property(&client_class
, A_TK_BORDER_WIDTH
,
2255 (lua_class_propfunc_t
) luaA_client_set_border_width
,
2256 (lua_class_propfunc_t
) luaA_client_get_border_width
,
2257 (lua_class_propfunc_t
) luaA_client_set_border_width
);
2258 luaA_class_add_property(&client_class
, A_TK_BORDER_COLOR
,
2259 (lua_class_propfunc_t
) luaA_client_set_border_color
,
2260 (lua_class_propfunc_t
) luaA_client_get_border_color
,
2261 (lua_class_propfunc_t
) luaA_client_set_border_color
);
2262 luaA_class_add_property(&client_class
, A_TK_TITLEBAR
,
2263 (lua_class_propfunc_t
) luaA_client_set_titlebar
,
2264 (lua_class_propfunc_t
) luaA_client_get_titlebar
,
2265 (lua_class_propfunc_t
) luaA_client_set_titlebar
);
2266 luaA_class_add_property(&client_class
, A_TK_URGENT
,
2267 (lua_class_propfunc_t
) luaA_client_set_urgent
,
2268 (lua_class_propfunc_t
) luaA_client_get_urgent
,
2269 (lua_class_propfunc_t
) luaA_client_set_urgent
);
2270 luaA_class_add_property(&client_class
, A_TK_SIZE_HINTS
,
2272 (lua_class_propfunc_t
) luaA_client_get_size_hints
,
2276 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80