2 * client.c - client management
4 * Copyright © 2007-2008 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/xtest.h>
23 #include <xcb/xcb_atom.h>
24 #include <xcb/xcb_image.h>
35 #include "common/atoms.h"
37 extern awesome_t globalconf
;
39 DO_LUA_NEW(extern, client_t
, client
, "client", client_ref
)
40 DO_LUA_EQ(client_t
, client
, "client")
41 DO_LUA_GC(client_t
, client
, "client", client_unref
)
43 /** Check if client supports protocol a protocole in WM_PROTOCOL.
44 * \param win The window.
45 * \return True if client has the atom in protocol, false otherwise.
48 window_hasproto(xcb_window_t win
, xcb_atom_t atom
)
51 xcb_get_wm_protocols_reply_t protocols
;
54 if(xcb_get_wm_protocols_reply(globalconf
.connection
,
55 xcb_get_wm_protocols_unchecked(globalconf
.connection
,
59 for(i
= 0; !ret
&& i
< protocols
.atoms_len
; i
++)
60 if(protocols
.atoms
[i
] == atom
)
62 xcb_get_wm_protocols_reply_wipe(&protocols
);
67 /** Send WM_TAKE_FOCUS client message to window
68 * \param win destination window
71 window_takefocus(xcb_window_t win
)
73 xcb_client_message_event_t ev
;
75 /* Initialize all of event's fields first */
78 ev
.response_type
= XCB_CLIENT_MESSAGE
;
81 ev
.data
.data32
[1] = XCB_CURRENT_TIME
;
82 ev
.type
= WM_PROTOCOLS
;
83 ev
.data
.data32
[0] = WM_TAKE_FOCUS
;
85 xcb_send_event(globalconf
.connection
, false, win
,
86 XCB_EVENT_MASK_NO_EVENT
, (char *) &ev
);
89 /** Change the clients urgency flag.
91 * \param urgent The new flag state
94 client_seturgent(client_t
*c
, bool urgent
)
96 if(c
->isurgent
!= urgent
)
98 xcb_get_property_cookie_t hints
=
99 xcb_get_wm_hints_unchecked(globalconf
.connection
, c
->win
);
101 c
->isurgent
= urgent
;
102 ewmh_client_update_hints(c
);
104 /* update ICCCM hints */
106 xcb_get_wm_hints_reply(globalconf
.connection
, hints
, &wmh
, NULL
);
109 wmh
.flags
|= XCB_WM_HINT_X_URGENCY
;
111 wmh
.flags
&= ~XCB_WM_HINT_X_URGENCY
;
113 xcb_set_wm_hints(globalconf
.connection
, c
->win
, &wmh
);
115 hooks_property(c
, "urgent");
119 /** Returns true if a client is tagged
120 * with one of the tags of the specified screen.
121 * \param c The client to check.
122 * \param screen Virtual screen number.
123 * \return true if the client is visible, false otherwise.
126 client_maybevisible(client_t
*c
, int screen
)
128 if(c
->screen
== screen
)
130 if(c
->issticky
|| c
->type
== WINDOW_TYPE_DESKTOP
)
133 tag_array_t
*tags
= &globalconf
.screens
[screen
].tags
;
135 for(int i
= 0; i
< tags
->len
; i
++)
136 if(tags
->tab
[i
]->selected
&& is_client_tagged(c
, tags
->tab
[i
]))
142 /** Return the content of a client as an image.
143 * That's just take a screenshot.
144 * \param c The client.
148 client_getcontent(client_t
*c
)
150 xcb_image_t
*ximage
= xcb_image_get(globalconf
.connection
,
153 c
->geometries
.internal
.width
,
154 c
->geometries
.internal
.height
,
155 ~0, XCB_IMAGE_FORMAT_Z_PIXMAP
);
157 if(!ximage
|| ximage
->bpp
< 24)
160 uint32_t *data
= p_alloca(uint32_t, ximage
->width
* ximage
->height
);
162 for(int y
= 0; y
< ximage
->height
; y
++)
163 for(int x
= 0; x
< ximage
->width
; x
++)
165 data
[y
* ximage
->width
+ x
] = xcb_image_get_pixel(ximage
, x
, y
);
166 data
[y
* ximage
->width
+ x
] |= 0xff000000; /* set alpha to 0xff */
169 image_t
*image
= image_new_from_argb32(ximage
->width
, ximage
->height
, data
);
171 xcb_image_destroy(ximage
);
176 /** Get a client by its window.
177 * \param w The client window to find.
178 * \return A client pointer if found, NULL otherwise.
181 client_getbywin(xcb_window_t w
)
184 for(c
= globalconf
.clients
; c
&& c
->win
!= w
; c
= c
->next
);
188 /** Call unfocus hook.
189 * \param c Client being unfocused
192 client_unfocus_hook(client_t
*c
)
195 if(globalconf
.hooks
.unfocus
!= LUA_REFNIL
)
197 luaA_client_userdata_new(globalconf
.L
, c
);
198 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.unfocus
, 1, 0);
202 /** Unfocus a client.
203 * \param c The client.
206 client_unfocus(client_t
*c
)
208 xcb_window_t root_win
= xutil_screen_get(globalconf
.connection
, c
->phys_screen
)->root
;
209 globalconf
.screens
[c
->phys_screen
].client_focus
= NULL
;
211 /* Set focus on root window, so no events leak to the current window. */
212 xcb_set_input_focus(globalconf
.connection
, XCB_INPUT_FOCUS_POINTER_ROOT
,
213 root_win
, XCB_CURRENT_TIME
);
215 client_unfocus_hook(c
);
217 ewmh_update_net_active_window(c
->phys_screen
);
220 /** Ban client and move it out of the viewport.
221 * \param c The client.
224 client_ban(client_t
*c
)
228 /* Move all clients out of the physical viewport into negative coordinate space. */
229 /* They will all be put on top of each other. */
230 uint32_t request
[2] = { - (c
->geometries
.internal
.width
+ 2 * c
->border
),
231 - (c
->geometries
.internal
.height
+ 2 * c
->border
) };
233 xcb_configure_window(globalconf
.connection
, c
->win
,
234 XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
,
237 titlebar_ban(c
->titlebar
);
241 /* All the wiboxes (may) need to be repositioned. */
242 if(client_hasstrut(c
))
243 wibox_update_positions();
246 /* Wait until the last moment to take away the focus from the window. */
247 if (globalconf
.screens
[c
->phys_screen
].client_focus
== c
)
252 * \param c Client being focused.
255 client_focus_hook(client_t
*c
)
258 if(globalconf
.hooks
.focus
!= LUA_REFNIL
)
260 luaA_client_userdata_new(globalconf
.L
, c
);
261 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.focus
, 1, 0);
265 /** Give focus to client, or to first client if client is NULL.
266 * \param c The client or NULL.
267 * \param sendmessage true, if we should send message.
270 client_focus(client_t
*c
, bool sendmessage
)
272 /* Handle c == NULL case */
276 c
= globalconf
.clients
;
282 if(!client_maybevisible(c
, c
->screen
))
285 /* Does client window support WM_TAKE_FOCUS protocol ? */
286 bool takefocus
= window_hasproto(c
->win
, WM_TAKE_FOCUS
);
288 /* Disallow setting focus on client with No Input Model */
289 if(sendmessage
&& !takefocus
&& c
->nofocus
)
292 /* Save current focused client */
293 client_t
*focused_before
= globalconf
.screen_focus
->client_focus
;
295 if(c
== focused_before
)
300 client_setminimized(c
, false);
302 /* unban the client before focusing or it will fail */
305 globalconf
.screen_focus
= &globalconf
.screens
[c
->phys_screen
];
306 globalconf
.screen_focus
->client_focus
= c
;
311 /* Input models: Passive, Locally Active */
312 xcb_set_input_focus(globalconf
.connection
, XCB_INPUT_FOCUS_POINTER_ROOT
,
313 c
->win
, XCB_CURRENT_TIME
);
316 /* Input models: No Input, Globally Active */
317 window_takefocus(c
->win
);
320 /* Some layouts use focused client differently, so call them back.
321 * And anyway, we have maybe unhidden */
322 client_need_arrange(c
);
324 /* unfocus current selected client
325 * We don't really need to unfocus here,
326 * because client already received FocusOut event.
327 * What we need to do is call unfocus hook, to
328 * inform lua script, about this event.
331 client_unfocus_hook(focused_before
);
333 client_focus_hook(c
);
335 /* according to EWMH, we have to remove the urgent state from a client */
336 client_seturgent(c
, false);
338 ewmh_update_net_active_window(c
->phys_screen
);
342 /** Stack a window below.
343 * \param c The client.
344 * \param previous The previous window on the stack.
345 * \param return The next-previous!
348 client_stack_above(client_t
*c
, xcb_window_t previous
)
350 uint32_t config_win_vals
[2];
352 config_win_vals
[0] = previous
;
353 config_win_vals
[1] = XCB_STACK_MODE_ABOVE
;
355 xcb_configure_window(globalconf
.connection
, c
->win
,
356 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
359 config_win_vals
[0] = c
->win
;
363 xcb_configure_window(globalconf
.connection
,
364 c
->titlebar
->sw
.window
,
365 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
367 previous
= c
->titlebar
->sw
.window
;
372 /* stack transient window on top of their parents */
373 for(client_node_t
*node
= *client_node_list_last(&globalconf
.stack
);
374 node
; node
= node
->prev
)
375 if(node
->client
->transient_for
== c
)
376 previous
= client_stack_above(node
->client
, previous
);
381 /** Stacking layout layers */
384 /** This one is a special layer */
395 /** Get the real layer of a client according to its attribute (fullscreen, …)
396 * \param c The client.
397 * \return The real layer.
400 client_layer_translator(client_t
*c
)
402 /* first deal with user set attributes */
405 else if(c
->isfullscreen
)
406 return LAYER_FULLSCREEN
;
412 /* check for transient attr */
416 /* then deal with windows type */
419 case WINDOW_TYPE_DOCK
:
421 case WINDOW_TYPE_DESKTOP
:
422 return LAYER_DESKTOP
;
423 case WINDOW_TYPE_DIALOG
:
424 case WINDOW_TYPE_MENU
:
425 case WINDOW_TYPE_TOOLBAR
:
426 case WINDOW_TYPE_UTILITY
:
436 * \todo It might be worth stopping to restack everyone and only stack `c'
437 * relatively to the first matching in the list.
442 uint32_t config_win_vals
[2];
443 client_node_t
*node
, *last
= *client_node_list_last(&globalconf
.stack
);
447 config_win_vals
[0] = XCB_NONE
;
448 config_win_vals
[1] = XCB_STACK_MODE_ABOVE
;
450 /* stack desktop windows */
451 for(layer
= LAYER_DESKTOP
; layer
< LAYER_BELOW
; layer
++)
452 for(node
= last
; node
; node
= node
->prev
)
453 if(client_layer_translator(node
->client
) == layer
)
454 config_win_vals
[0] = client_stack_above(node
->client
,
457 /* first stack not ontop wibox window */
458 for(screen
= 0; screen
< globalconf
.nscreen
; screen
++)
459 for(int i
= 0; i
< globalconf
.screens
[screen
].wiboxes
.len
; i
++)
461 wibox_t
*sb
= globalconf
.screens
[screen
].wiboxes
.tab
[i
];
464 xcb_configure_window(globalconf
.connection
,
466 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
468 config_win_vals
[0] = sb
->sw
.window
;
472 /* then stack clients */
473 for(layer
= LAYER_BELOW
; layer
< LAYER_OUTOFSPACE
; layer
++)
474 for(node
= last
; node
; node
= node
->prev
)
475 if(client_layer_translator(node
->client
) == layer
)
476 config_win_vals
[0] = client_stack_above(node
->client
,
479 /* then stack ontop wibox window */
480 for(screen
= 0; screen
< globalconf
.nscreen
; screen
++)
481 for(int i
= 0; i
< globalconf
.screens
[screen
].wiboxes
.len
; i
++)
483 wibox_t
*sb
= globalconf
.screens
[screen
].wiboxes
.tab
[i
];
486 xcb_configure_window(globalconf
.connection
,
488 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
490 config_win_vals
[0] = sb
->sw
.window
;
495 /** Manage a new client.
496 * \param w The window.
497 * \param wgeom Window geometry.
498 * \param phys_screen Physical screen number.
499 * \param startup True if we are managing at startup time.
502 client_manage(xcb_window_t w
, xcb_get_geometry_reply_t
*wgeom
, int phys_screen
, bool startup
)
504 xcb_get_property_cookie_t ewmh_icon_cookie
;
505 client_t
*c
, *tc
= NULL
;
508 const uint32_t select_input_val
[] = { CLIENT_SELECT_INPUT_EVENT_MASK
};
510 if(systray_iskdedockapp(w
))
512 systray_request_handle(w
, phys_screen
, NULL
);
516 /* Send request to get NET_WM_ICON property as soon as possible... */
517 ewmh_icon_cookie
= ewmh_window_icon_get_unchecked(w
);
518 xcb_change_window_attributes(globalconf
.connection
, w
, XCB_CW_EVENT_MASK
, select_input_val
);
519 c
= p_new(client_t
, 1);
521 screen
= c
->screen
= screen_getbycoord(phys_screen
, wgeom
->x
, wgeom
->y
);
523 c
->phys_screen
= phys_screen
;
527 c
->geometry
.x
= wgeom
->x
;
528 c
->geometry
.y
= wgeom
->y
;
529 /* Border will be added later. */
530 c
->geometry
.width
= wgeom
->width
;
531 c
->geometry
.height
= wgeom
->height
;
532 /* Also set internal geometry (client_ban() needs it). */
533 c
->geometries
.internal
.x
= wgeom
->x
;
534 c
->geometries
.internal
.y
= wgeom
->y
;
535 c
->geometries
.internal
.width
= wgeom
->width
;
536 c
->geometries
.internal
.height
= wgeom
->height
;
537 client_setborder(c
, wgeom
->border_width
);
538 if((icon
= ewmh_window_icon_get_reply(ewmh_icon_cookie
)))
539 c
->icon
= image_ref(&icon
);
541 /* we honor size hints by default */
542 c
->size_hints_honor
= true;
545 property_update_wm_normal_hints(c
, NULL
);
546 property_update_wm_hints(c
, NULL
);
547 property_update_wm_transient_for(c
, NULL
);
548 property_update_wm_client_leader(c
, NULL
);
550 /* Recursively find the parent. */
551 for(tc
= c
; tc
->transient_for
; tc
= tc
->transient_for
);
552 if(tc
!= c
&& tc
->phys_screen
== c
->phys_screen
)
555 /* Then check clients hints */
556 ewmh_client_check_hints(c
);
558 /* move client to screen, but do not tag it */
559 screen_client_moveto(c
, screen
, false, true);
561 /* Push client in client list */
562 client_list_push(&globalconf
.clients
, client_ref(&c
));
564 /* Push client in stack */
567 /* update window title */
568 property_update_wm_name(c
);
569 property_update_wm_icon_name(c
);
572 ewmh_process_client_strut(c
, NULL
);
574 ewmh_update_net_client_list(c
->phys_screen
);
576 /* Always stay in NORMAL_STATE. Even though iconified seems more
577 * appropriate sometimes. The only possible loss is that clients not using
578 * visibility events may continue to proces data (when banned).
579 * Without any exposes or other events the cost should be fairly limited though.
581 * Some clients may expect the window to be unmapped when STATE_ICONIFIED.
582 * Two conflicting parts of the ICCCM v2.0 (section 4.1.4):
584 * "Normal -> Iconic - The client should send a ClientMessage event as described later in this section."
585 * (note no explicit mention of unmapping, while Normal->Widthdrawn does mention that)
587 * "Once a client's window has left the Withdrawn state, the window will be mapped
588 * if it is in the Normal state and the window will be unmapped if it is in the Iconic state."
590 * At this stage it's just safer to keep it in normal state and avoid confusion.
592 window_state_set(c
->win
, XCB_WM_STATE_NORMAL
);
594 /* Move window outside the viewport before mapping it. */
596 xcb_map_window(globalconf
.connection
, c
->win
);
598 /* Call hook to notify list change */
599 if(globalconf
.hooks
.clients
!= LUA_REFNIL
)
600 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.clients
, 0, 0);
603 if(globalconf
.hooks
.manage
!= LUA_REFNIL
)
605 luaA_client_userdata_new(globalconf
.L
, c
);
606 lua_pushboolean(globalconf
.L
, startup
);
607 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.manage
, 2, 0);
611 /** Compute client geometry with respect to its geometry hints.
612 * \param c The client.
613 * \param geometry The geometry that the client might receive.
614 * \return The geometry the client must take respecting its hints.
617 client_geometry_hints(client_t
*c
, area_t geometry
)
619 int32_t basew
, baseh
, minw
, minh
;
621 /* base size is substituted with min size if not specified */
622 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_SIZE
)
624 basew
= c
->size_hints
.base_width
;
625 baseh
= c
->size_hints
.base_height
;
627 else if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MIN_SIZE
)
629 basew
= c
->size_hints
.min_width
;
630 baseh
= c
->size_hints
.min_height
;
635 /* min size is substituted with base size if not specified */
636 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MIN_SIZE
)
638 minw
= c
->size_hints
.min_width
;
639 minh
= c
->size_hints
.min_height
;
641 else if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_SIZE
)
643 minw
= c
->size_hints
.base_width
;
644 minh
= c
->size_hints
.base_height
;
649 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_ASPECT
650 && c
->size_hints
.min_aspect_num
> 0
651 && c
->size_hints
.min_aspect_den
> 0
652 && geometry
.height
- baseh
> 0
653 && geometry
.width
- basew
> 0)
655 double dx
= (double) (geometry
.width
- basew
);
656 double dy
= (double) (geometry
.height
- baseh
);
657 double min
= (double) c
->size_hints
.min_aspect_num
/ (double) c
->size_hints
.min_aspect_den
;
658 double max
= (double) c
->size_hints
.max_aspect_num
/ (double) c
->size_hints
.min_aspect_den
;
659 double ratio
= dx
/ dy
;
660 if(max
> 0 && min
> 0 && ratio
> 0)
664 dy
= (dx
* min
+ dy
) / (min
* min
+ 1);
666 geometry
.width
= (int) dx
+ basew
;
667 geometry
.height
= (int) dy
+ baseh
;
671 dy
= (dx
* min
+ dy
) / (max
* max
+ 1);
673 geometry
.width
= (int) dx
+ basew
;
674 geometry
.height
= (int) dy
+ baseh
;
680 geometry
.width
= MAX(geometry
.width
, minw
);
682 geometry
.height
= MAX(geometry
.height
, minh
);
684 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MAX_SIZE
)
686 if(c
->size_hints
.max_width
)
687 geometry
.width
= MIN(geometry
.width
, c
->size_hints
.max_width
);
688 if(c
->size_hints
.max_height
)
689 geometry
.height
= MIN(geometry
.height
, c
->size_hints
.max_height
);
692 if(c
->size_hints
.flags
& (XCB_SIZE_HINT_P_RESIZE_INC
| XCB_SIZE_HINT_BASE_SIZE
)
693 && c
->size_hints
.width_inc
&& c
->size_hints
.height_inc
)
695 uint16_t t1
= geometry
.width
, t2
= geometry
.height
;
696 unsigned_subtract(t1
, basew
);
697 unsigned_subtract(t2
, baseh
);
698 geometry
.width
-= t1
% c
->size_hints
.width_inc
;
699 geometry
.height
-= t2
% c
->size_hints
.height_inc
;
705 /** Resize client window.
706 * The sizse given as parameters are with titlebar and borders!
707 * \param c Client to resize.
708 * \param geometry New window geometry.
709 * \param hints Use size hints.
710 * \return true if an actual resize occurred.
713 client_resize(client_t
*c
, area_t geometry
, bool hints
)
716 area_t geometry_internal
;
719 /* offscreen appearance fixes */
720 area
= display_area_get(c
->phys_screen
, NULL
,
721 &globalconf
.screens
[c
->screen
].padding
);
723 if(geometry
.x
> area
.width
)
724 geometry
.x
= area
.width
- geometry
.width
;
725 if(geometry
.y
> area
.height
)
726 geometry
.y
= area
.height
- geometry
.height
;
727 if(geometry
.x
+ geometry
.width
< 0)
729 if(geometry
.y
+ geometry
.height
< 0)
732 /* Real client geometry, please keep it contained to C code at the very least. */
733 geometry_internal
= titlebar_geometry_remove(c
->titlebar
, c
->border
, geometry
);
736 geometry_internal
= client_geometry_hints(c
, geometry_internal
);
738 if(geometry_internal
.width
== 0 || geometry_internal
.height
== 0)
741 /* Also let client hints propegate to the "official" geometry. */
742 geometry
= titlebar_geometry_add(c
->titlebar
, c
->border
, geometry_internal
);
744 if(c
->geometries
.internal
.x
!= geometry_internal
.x
745 || c
->geometries
.internal
.y
!= geometry_internal
.y
746 || c
->geometries
.internal
.width
!= geometry_internal
.width
747 || c
->geometries
.internal
.height
!= geometry_internal
.height
)
749 new_screen
= screen_getbycoord(c
->screen
, geometry_internal
.x
, geometry_internal
.y
);
751 /* Values to configure a window is an array where values are
752 * stored according to 'value_mask' */
755 c
->geometries
.internal
.x
= values
[0] = geometry_internal
.x
;
756 c
->geometries
.internal
.y
= values
[1] = geometry_internal
.y
;
757 c
->geometries
.internal
.width
= values
[2] = geometry_internal
.width
;
758 c
->geometries
.internal
.height
= values
[3] = geometry_internal
.height
;
760 /* Also store geometry including border and titlebar. */
761 c
->geometry
= geometry
;
763 titlebar_update_geometry(c
);
765 /* The idea is to give a client a resize even when banned. */
766 /* We just have to move the (x,y) to keep it out of the viewport. */
767 /* This at least doesn't break expectations about events. */
770 geometry_internal
.x
= values
[0] = - (geometry_internal
.width
+ 2 * c
->border
);
771 geometry_internal
.y
= values
[1] = - (geometry_internal
.height
+ 2 * c
->border
);
774 xcb_configure_window(globalconf
.connection
, c
->win
,
775 XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
776 | XCB_CONFIG_WINDOW_WIDTH
| XCB_CONFIG_WINDOW_HEIGHT
,
778 window_configure(c
->win
, geometry_internal
, c
->border
);
780 screen_client_moveto(c
, new_screen
, true, false);
783 hooks_property(c
, "geometry");
791 /** Set a client minimized, or not.
792 * \param c The client.
793 * \param s Set or not the client minimized.
796 client_setminimized(client_t
*c
, bool s
)
798 if(c
->isminimized
!= s
)
800 client_need_arrange(c
);
802 client_need_arrange(c
);
803 ewmh_client_update_hints(c
);
805 hooks_property(c
, "minimized");
809 /** Set a client sticky, or not.
810 * \param c The client.
811 * \param s Set or not the client sticky.
814 client_setsticky(client_t
*c
, bool s
)
818 client_need_arrange(c
);
820 client_need_arrange(c
);
821 ewmh_client_update_hints(c
);
822 hooks_property(c
, "sticky");
826 /** Set a client fullscreen, or not.
827 * \param c The client.
828 * \param s Set or not the client fullscreen.
831 client_setfullscreen(client_t
*c
, bool s
)
833 if(c
->isfullscreen
!= s
)
837 /* become fullscreen! */
838 if((c
->isfullscreen
= s
))
840 /* remove any max state */
841 client_setmaxhoriz(c
, false);
842 client_setmaxvert(c
, false);
843 /* You can only be part of one of the special layers. */
844 client_setbelow(c
, false);
845 client_setabove(c
, false);
846 client_setontop(c
, false);
848 geometry
= screen_area_get(c
->screen
, NULL
, NULL
, false);
849 c
->geometries
.fullscreen
= c
->geometry
;
850 c
->border_fs
= c
->border
;
851 client_setborder(c
, 0);
855 geometry
= c
->geometries
.fullscreen
;
856 client_setborder(c
, c
->border_fs
);
858 client_resize(c
, geometry
, false);
859 client_need_arrange(c
);
861 ewmh_client_update_hints(c
);
862 hooks_property(c
, "fullscreen");
866 /** Set a client horizontally maximized.
867 * \param c The client.
868 * \param s The maximized status.
871 client_setmaxhoriz(client_t
*c
, bool s
)
873 if(c
->ismaxhoriz
!= s
)
877 if((c
->ismaxhoriz
= s
))
879 /* remove fullscreen mode */
880 client_setfullscreen(c
, false);
882 geometry
= screen_area_get(c
->screen
,
883 &globalconf
.screens
[c
->screen
].wiboxes
,
884 &globalconf
.screens
[c
->screen
].padding
,
886 geometry
.y
= c
->geometry
.y
;
887 geometry
.height
= c
->geometry
.height
;
888 c
->geometries
.max
.x
= c
->geometry
.x
;
889 c
->geometries
.max
.width
= c
->geometry
.width
;
893 geometry
= c
->geometry
;
894 geometry
.x
= c
->geometries
.max
.x
;
895 geometry
.width
= c
->geometries
.max
.width
;
898 client_resize(c
, geometry
, c
->size_hints_honor
);
899 client_need_arrange(c
);
901 ewmh_client_update_hints(c
);
902 hooks_property(c
, "maximized_horizontal");
906 /** Set a client vertically maximized.
907 * \param c The client.
908 * \param s The maximized status.
911 client_setmaxvert(client_t
*c
, bool s
)
913 if(c
->ismaxvert
!= s
)
917 if((c
->ismaxvert
= s
))
919 /* remove fullscreen mode */
920 client_setfullscreen(c
, false);
922 geometry
= screen_area_get(c
->screen
,
923 &globalconf
.screens
[c
->screen
].wiboxes
,
924 &globalconf
.screens
[c
->screen
].padding
,
926 geometry
.x
= c
->geometry
.x
;
927 geometry
.width
= c
->geometry
.width
;
928 c
->geometries
.max
.y
= c
->geometry
.y
;
929 c
->geometries
.max
.height
= c
->geometry
.height
;
933 geometry
= c
->geometry
;
934 geometry
.y
= c
->geometries
.max
.y
;
935 geometry
.height
= c
->geometries
.max
.height
;
938 client_resize(c
, geometry
, c
->size_hints_honor
);
939 client_need_arrange(c
);
941 ewmh_client_update_hints(c
);
942 hooks_property(c
, "maximized_vertical");
946 /** Set a client above, or not.
947 * \param c The client.
948 * \param s Set or not the client above.
951 client_setabove(client_t
*c
, bool s
)
955 /* You can only be part of one of the special layers. */
958 client_setbelow(c
, false);
959 client_setontop(c
, false);
960 client_setfullscreen(c
, false);
964 ewmh_client_update_hints(c
);
966 hooks_property(c
, "above");
970 /** Set a client below, or not.
971 * \param c The client.
972 * \param s Set or not the client below.
975 client_setbelow(client_t
*c
, bool s
)
979 /* You can only be part of one of the special layers. */
982 client_setabove(c
, false);
983 client_setontop(c
, false);
984 client_setfullscreen(c
, false);
988 ewmh_client_update_hints(c
);
990 hooks_property(c
, "below");
994 /** Set a client modal, or not.
995 * \param c The client.
996 * \param s Set or not the client moda.
999 client_setmodal(client_t
*c
, bool s
)
1005 ewmh_client_update_hints(c
);
1007 hooks_property(c
, "modal");
1011 /** Set a client ontop, or not.
1012 * \param c The client.
1013 * \param s Set or not the client moda.
1016 client_setontop(client_t
*c
, bool s
)
1020 /* You can only be part of one of the special layers. */
1023 client_setabove(c
, false);
1024 client_setbelow(c
, false);
1025 client_setfullscreen(c
, false);
1030 hooks_property(c
, "ontop");
1034 /** Unban a client and move it back into the viewport.
1035 * \param c The client.
1038 client_unban(client_t
*c
)
1042 /* Move the client back where it belongs. */
1043 uint32_t request
[] = { c
->geometries
.internal
.x
,
1044 c
->geometries
.internal
.y
,
1045 c
->geometries
.internal
.width
,
1046 c
->geometries
.internal
.height
};
1048 xcb_configure_window(globalconf
.connection
, c
->win
,
1050 | XCB_CONFIG_WINDOW_Y
1051 | XCB_CONFIG_WINDOW_WIDTH
1052 | XCB_CONFIG_WINDOW_HEIGHT
,
1054 window_configure(c
->win
, c
->geometries
.internal
, c
->border
);
1056 /* Do this manually because the system doesn't know we moved the toolbar.
1057 * Note that !isvisible titlebars are unmapped and for fullscreen it'll
1058 * end up offscreen anyway. */
1061 simple_window_t
*sw
= &c
->titlebar
->sw
;
1062 /* All resizing is done, so only move now. */
1063 request
[0] = sw
->geometry
.x
;
1064 request
[1] = sw
->geometry
.y
;
1066 xcb_configure_window(globalconf
.connection
, sw
->window
,
1067 XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
,
1071 c
->isbanned
= false;
1073 /* All the wiboxes (may) need to be repositioned. */
1074 if(client_hasstrut(c
))
1075 wibox_update_positions();
1079 /** Unmanage a client.
1080 * \param c The client.
1083 client_unmanage(client_t
*c
)
1085 tag_array_t
*tags
= &globalconf
.screens
[c
->screen
].tags
;
1087 /* Reset transient_for attributes of widows that maybe refering to us */
1088 for(client_t
*tc
= globalconf
.clients
; tc
; tc
= tc
->next
)
1089 if(tc
->transient_for
== c
)
1090 tc
->transient_for
= NULL
;
1092 if(globalconf
.screens
[c
->phys_screen
].client_focus
== c
)
1095 /* remove client everywhere */
1096 client_list_detach(&globalconf
.clients
, c
);
1097 stack_client_delete(c
);
1098 for(int i
= 0; i
< tags
->len
; i
++)
1099 untag_client(c
, tags
->tab
[i
]);
1102 if(globalconf
.hooks
.unmanage
!= LUA_REFNIL
)
1104 luaA_client_userdata_new(globalconf
.L
, c
);
1105 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.unmanage
, 1, 0);
1108 /* Call hook to notify list change */
1109 if(globalconf
.hooks
.clients
!= LUA_REFNIL
)
1110 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.clients
, 0, 0);
1112 /* The server grab construct avoids race conditions. */
1113 xcb_grab_server(globalconf
.connection
);
1115 xcb_ungrab_button(globalconf
.connection
, XCB_BUTTON_INDEX_ANY
, c
->win
,
1116 XCB_BUTTON_MASK_ANY
);
1117 window_state_set(c
->win
, XCB_WM_STATE_WITHDRAWN
);
1119 xcb_flush(globalconf
.connection
);
1120 xcb_ungrab_server(globalconf
.connection
);
1122 titlebar_client_detach(c
);
1124 ewmh_update_net_client_list(c
->phys_screen
);
1126 /* All the wiboxes (may) need to be repositioned. */
1127 if(client_hasstrut(c
))
1128 wibox_update_positions();
1130 /* set client as invalid */
1136 /** Kill a client via a WM_DELETE_WINDOW request or KillClient if not
1138 * \param c The client to kill.
1141 client_kill(client_t
*c
)
1143 if(window_hasproto(c
->win
, WM_DELETE_WINDOW
))
1145 xcb_client_message_event_t ev
;
1147 /* Initialize all of event's fields first */
1150 ev
.response_type
= XCB_CLIENT_MESSAGE
;
1153 ev
.data
.data32
[1] = XCB_CURRENT_TIME
;
1154 ev
.type
= WM_PROTOCOLS
;
1155 ev
.data
.data32
[0] = WM_DELETE_WINDOW
;
1157 xcb_send_event(globalconf
.connection
, false, c
->win
,
1158 XCB_EVENT_MASK_NO_EVENT
, (char *) &ev
);
1161 xcb_kill_client(globalconf
.connection
, c
->win
);
1164 /** Get all clients into a table.
1165 * \param L The Lua VM state.
1166 * \return The number of elements pushed on stack.
1168 * \lparam An optional screen nunmber.
1169 * \lreturn A table with all clients.
1172 luaA_client_get(lua_State
*L
)
1177 screen
= luaL_optnumber(L
, 1, 0) - 1;
1181 if(screen
== SCREEN_UNDEF
)
1182 for(c
= globalconf
.clients
; c
; c
= c
->next
)
1184 luaA_client_userdata_new(globalconf
.L
, c
);
1185 lua_rawseti(L
, -2, i
++);
1189 luaA_checkscreen(screen
);
1190 for(c
= globalconf
.clients
; c
; c
= c
->next
)
1191 if(c
->screen
== screen
)
1193 luaA_client_userdata_new(globalconf
.L
, c
);
1194 lua_rawseti(L
, -2, i
++);
1201 /** Check if a client is visible on its screen.
1202 * \param L The Lua VM state.
1203 * \return The number of elements pushed on stack.
1206 * \lreturn A boolean value, true if the client is visible, false otherwise.
1209 luaA_client_isvisible(lua_State
*L
)
1211 client_t
**c
= luaA_checkudata(L
, 1, "client");
1212 lua_pushboolean(L
, client_isvisible(*c
, (*c
)->screen
));
1216 /** Set client border width.
1217 * \param c The client.
1218 * \param width The border width.
1221 client_setborder(client_t
*c
, int width
)
1225 if(width
> 0 && (c
->type
== WINDOW_TYPE_DOCK
1226 || c
->type
== WINDOW_TYPE_SPLASH
1227 || c
->type
== WINDOW_TYPE_DESKTOP
1228 || c
->isfullscreen
))
1231 if(width
== c
->border
|| width
< 0)
1234 /* Update geometry with the new border. */
1235 c
->geometry
.width
-= 2 * c
->border
;
1236 c
->geometry
.height
-= 2 * c
->border
;
1239 xcb_configure_window(globalconf
.connection
, c
->win
,
1240 XCB_CONFIG_WINDOW_BORDER_WIDTH
, &w
);
1242 c
->geometry
.width
+= 2 * c
->border
;
1243 c
->geometry
.height
+= 2 * c
->border
;
1244 /* Tiled clients will be resized by the layout functions. */
1245 client_need_arrange(c
);
1247 /* Changing border size also affects the size of the titlebar. */
1249 titlebar_update_geometry(c
);
1251 hooks_property(c
, "border_width");
1255 * \param L The Lua VM state.
1261 luaA_client_kill(lua_State
*L
)
1263 client_t
**c
= luaA_checkudata(L
, 1, "client");
1268 /** Swap a client with another one.
1269 * \param L The Lua VM state.
1272 * \lparam A client to swap with.
1275 luaA_client_swap(lua_State
*L
)
1277 client_t
**c
= luaA_checkudata(L
, 1, "client");
1278 client_t
**swap
= luaA_checkudata(L
, 2, "client");
1282 client_list_swap(&globalconf
.clients
, *swap
, *c
);
1283 client_need_arrange(*c
);
1284 client_need_arrange(*swap
);
1286 /* Call hook to notify list change */
1287 if(globalconf
.hooks
.clients
!= LUA_REFNIL
)
1288 luaA_dofunction(L
, globalconf
.hooks
.clients
, 0, 0);
1294 /** Access or set the client tags.
1295 * \param L The Lua VM state.
1296 * \return The number of elements pushed on stack.
1297 * \lparam A table with tags to set, or none to get the current tags table.
1298 * \return The clients tag.
1301 luaA_client_tags(lua_State
*L
)
1305 client_t
**c
= luaA_checkudata(L
, 1, "client");
1308 if(lua_gettop(L
) == 2)
1310 luaA_checktable(L
, 2);
1311 tags
= &globalconf
.screens
[(*c
)->screen
].tags
;
1312 for(int i
= 0; i
< tags
->len
; i
++)
1313 untag_client(*c
, tags
->tab
[i
]);
1315 while(lua_next(L
, 2))
1317 tag
= luaA_checkudata(L
, -1, "tag");
1318 tag_client(*c
, *tag
);
1324 tags
= &globalconf
.screens
[(*c
)->screen
].tags
;
1326 for(int i
= 0; i
< tags
->len
; i
++)
1327 if(is_client_tagged(*c
, tags
->tab
[i
]))
1329 luaA_tag_userdata_new(L
, tags
->tab
[i
]);
1330 lua_rawseti(L
, -2, ++j
);
1336 /** Raise a client on top of others which are on the same layer.
1337 * \param L The Lua VM state.
1342 luaA_client_raise(lua_State
*L
)
1344 client_t
**c
= luaA_checkudata(L
, 1, "client");
1349 /** Lower a client on bottom of others which are on the same layer.
1350 * \param L The Lua VM state.
1355 luaA_client_lower(lua_State
*L
)
1357 client_t
**c
= luaA_checkudata(L
, 1, "client");
1362 /** Redraw a client by unmapping and mapping it quickly.
1363 * \param L The Lua VM state.
1369 luaA_client_redraw(lua_State
*L
)
1371 client_t
**c
= luaA_checkudata(L
, 1, "client");
1373 xcb_unmap_window(globalconf
.connection
, (*c
)->win
);
1374 xcb_map_window(globalconf
.connection
, (*c
)->win
);
1376 /* Set the focus on the current window if the redraw has been
1377 performed on the window where the pointer is currently on
1378 because after the unmapping/mapping, the focus is lost */
1379 if(globalconf
.screen_focus
->client_focus
== *c
)
1382 client_focus(*c
, true);
1388 /** Stop managing a client.
1389 * \param L The Lua VM state.
1390 * \return The number of elements pushed on stack.
1395 luaA_client_unmanage(lua_State
*L
)
1397 client_t
**c
= luaA_checkudata(L
, 1, "client");
1398 client_unmanage(*c
);
1402 /** Return client geometry.
1403 * \param L The Lua VM state.
1404 * \return The number of elements pushed on stack.
1406 * \lparam A table with new coordinates, or none.
1407 * \lreturn A table with client coordinates.
1410 luaA_client_geometry(lua_State
*L
)
1412 client_t
**c
= luaA_checkudata(L
, 1, "client");
1414 if(lua_gettop(L
) == 2)
1418 luaA_checktable(L
, 2);
1419 geometry
.x
= luaA_getopt_number(L
, 2, "x", (*c
)->geometry
.x
);
1420 geometry
.y
= luaA_getopt_number(L
, 2, "y", (*c
)->geometry
.y
);
1421 if(client_isfixed(*c
))
1423 geometry
.width
= (*c
)->geometry
.width
;
1424 geometry
.height
= (*c
)->geometry
.height
;
1428 geometry
.width
= luaA_getopt_number(L
, 2, "width", (*c
)->geometry
.width
);
1429 geometry
.height
= luaA_getopt_number(L
, 2, "height", (*c
)->geometry
.height
);
1432 client_resize(*c
, geometry
, (*c
)->size_hints_honor
);
1435 return luaA_pusharea(L
, (*c
)->geometry
);
1438 /** Push a strut type to a table on stack.
1439 * \param L The Lua VM state.
1440 * \param struts The struts to push.
1441 * \return The number of elements pushed on stack.
1444 luaA_pushstruts(lua_State
*L
, strut_t struts
)
1447 lua_pushnumber(L
, struts
.left
);
1448 lua_setfield(L
, -2, "left");
1449 lua_pushnumber(L
, struts
.right
);
1450 lua_setfield(L
, -2, "right");
1451 lua_pushnumber(L
, struts
.top
);
1452 lua_setfield(L
, -2, "top");
1453 lua_pushnumber(L
, struts
.bottom
);
1454 lua_setfield(L
, -2, "bottom");
1458 /** Return client struts (reserved space at the edge of the screen).
1459 * \param L The Lua VM state.
1460 * \return The number of elements pushed on stack.
1462 * \lparam A table with new strut values, or none.
1463 * \lreturn A table with strut values.
1466 luaA_client_struts(lua_State
*L
)
1468 client_t
**c
= luaA_checkudata(L
, 1, "client");
1470 if(lua_gettop(L
) == 2)
1473 area_t screen_area
= display_area_get((*c
)->phys_screen
, NULL
, NULL
);
1475 struts
.left
= luaA_getopt_number(L
, 2, "left", (*c
)->strut
.left
);
1476 struts
.right
= luaA_getopt_number(L
, 2, "right", (*c
)->strut
.right
);
1477 struts
.top
= luaA_getopt_number(L
, 2, "top", (*c
)->strut
.top
);
1478 struts
.bottom
= luaA_getopt_number(L
, 2, "bottom", (*c
)->strut
.bottom
);
1480 if (struts
.left
!= (*c
)->strut
.left
|| struts
.right
!= (*c
)->strut
.right
||
1481 struts
.top
!= (*c
)->strut
.top
|| struts
.bottom
!= (*c
)->strut
.bottom
) {
1482 /* Struts are not so well defined in the context of xinerama. So we just
1483 * give the entire root window and let the window manager decide. */
1484 struts
.left_start_y
= 0;
1485 struts
.left_end_y
= !struts
.left
? 0 : screen_area
.height
;
1486 struts
.right_start_y
= 0;
1487 struts
.right_end_y
= !struts
.right
? 0 : screen_area
.height
;
1488 struts
.top_start_x
= 0;
1489 struts
.top_end_x
= !struts
.top
? 0 : screen_area
.width
;
1490 struts
.bottom_start_x
= 0;
1491 struts
.bottom_end_x
= !struts
.bottom
? 0 : screen_area
.width
;
1493 (*c
)->strut
= struts
;
1495 ewmh_update_client_strut((*c
));
1497 client_need_arrange((*c
));
1498 /* All the wiboxes (may) need to be repositioned. */
1499 wibox_update_positions();
1503 return luaA_pushstruts(L
, (*c
)->strut
);
1506 /** Client newindex.
1507 * \param L The Lua VM state.
1508 * \return The number of elements pushed on stack.
1511 luaA_client_newindex(lua_State
*L
)
1514 client_t
**c
= luaA_checkudata(L
, 1, "client");
1515 const char *buf
= luaL_checklstring(L
, 2, &len
);
1523 luaL_error(L
, "client is invalid\n");
1525 switch(a_tokenize(buf
, len
))
1528 if(globalconf
.xinerama_is_active
)
1530 i
= luaL_checknumber(L
, 3) - 1;
1531 luaA_checkscreen(i
);
1532 screen_client_moveto(*c
, i
, true, true);
1536 b
= luaA_checkboolean(L
, 3);
1537 if(b
!= (*c
)->ishidden
)
1539 client_need_arrange(*c
);
1541 client_need_arrange(*c
);
1544 case A_TK_MINIMIZED
:
1545 client_setminimized(*c
, luaA_checkboolean(L
, 3));
1547 case A_TK_FULLSCREEN
:
1548 client_setfullscreen(*c
, luaA_checkboolean(L
, 3));
1550 case A_TK_MAXIMIZED_HORIZONTAL
:
1551 client_setmaxhoriz(*c
, luaA_checkboolean(L
, 3));
1553 case A_TK_MAXIMIZED_VERTICAL
:
1554 client_setmaxvert(*c
, luaA_checkboolean(L
, 3));
1557 image
= luaA_checkudata(L
, 3, "image");
1558 image_unref(&(*c
)->icon
);
1560 (*c
)->icon
= *image
;
1562 hooks_property(*c
, "icon");
1566 window_opacity_set((*c
)->win
, -1);
1569 d
= luaL_checknumber(L
, 3);
1570 if(d
>= 0 && d
<= 1)
1571 window_opacity_set((*c
)->win
, d
);
1575 client_setsticky(*c
, luaA_checkboolean(L
, 3));
1577 case A_TK_SIZE_HINTS_HONOR
:
1578 (*c
)->size_hints_honor
= luaA_checkboolean(L
, 3);
1579 client_need_arrange(*c
);
1581 case A_TK_BORDER_WIDTH
:
1582 client_setborder(*c
, luaL_checknumber(L
, 3));
1585 client_setontop(*c
, luaA_checkboolean(L
, 3));
1588 client_setabove(*c
, luaA_checkboolean(L
, 3));
1591 client_setbelow(*c
, luaA_checkboolean(L
, 3));
1593 case A_TK_BORDER_COLOR
:
1594 if((buf
= luaL_checklstring(L
, 3, &len
))
1595 && xcolor_init_reply(xcolor_init_unchecked(&(*c
)->border_color
, buf
, len
)))
1596 xcb_change_window_attributes(globalconf
.connection
, (*c
)->win
,
1597 XCB_CW_BORDER_PIXEL
, &(*c
)->border_color
.pixel
);
1601 titlebar_client_detach(*c
);
1604 t
= luaA_checkudata(L
, 3, "wibox");
1605 titlebar_client_attach(*c
, *t
);
1616 * \param L The Lua VM state.
1617 * \return The number of elements pushed on stack.
1619 * \lfield id The window X id.
1620 * \lfield name The client title.
1621 * \lfield skip_taskbar True if the client does not want to be in taskbar.
1622 * \lfield type The window type (desktop, normal, dock, …).
1623 * \lfield class The client class.
1624 * \lfield instance The client instance.
1625 * \lfield pid The client PID, if available.
1626 * \lfield role The window role, if available.
1627 * \lfield machine The machine client is running on.
1628 * \lfield icon_name The client name when iconified.
1629 * \lfield screen Client screen number.
1630 * \lfield hide Define if the client must be hidden, i.e. never mapped,
1631 * invisible in taskbar.
1632 * \lfield minimize Define it the client must be iconify, i.e. only visible in
1634 * \lfield icon_path Path to the icon used to identify.
1635 * \lfield size_hints_honor Honor size hints, i.e. respect size ratio.
1636 * \lfield border_width The client border width.
1637 * \lfield border_color The client border color.
1638 * \lfield titlebar The client titlebar.
1639 * \lfield urgent The client urgent state.
1640 * \lfield content An image representing the client window content (screenshot).
1641 * \lfield focus The focused client.
1642 * \lfield opacity The client opacity between 0 and 1.
1643 * \lfield ontop The client is on top of every other windows.
1644 * \lfield above The client is above normal windows.
1645 * \lfield below The client is below normal windows.
1646 * \lfield fullscreen The client is fullscreen or not.
1647 * \lfield maximized_horizontal The client is maximized horizontally or not.
1648 * \lfield maximized_vertical The client is maximized vertically or not.
1649 * \lfield transient_for Return the client the window is transient for.
1650 * \lfield group_id Identification unique to a group of windows.
1651 * \lfield leader_id Identification unique to windows spawned by the same command.
1652 * \lfield size_hints A table with size hints of the client: user_position,
1653 * user_size, program_position, program_size, etc.
1656 luaA_client_index(lua_State
*L
)
1660 client_t
**c
= luaA_checkudata(L
, 1, "client");
1661 const char *buf
= luaL_checklstring(L
, 2, &len
);
1664 xcb_get_wm_class_reply_t hint
;
1665 xcb_get_property_cookie_t prop_c
;
1666 xcb_get_property_reply_t
*prop_r
= NULL
;
1670 luaL_error(L
, "client is invalid\n");
1672 if(luaA_usemetatable(L
, 1, 2))
1675 switch(a_tokenize(buf
, len
))
1680 lua_pushstring(L
, (*c
)->name
);
1682 case A_TK_TRANSIENT_FOR
:
1683 if((*c
)->transient_for
)
1684 return luaA_client_userdata_new(L
, (*c
)->transient_for
);
1686 case A_TK_SKIP_TASKBAR
:
1687 lua_pushboolean(L
, (*c
)->skiptb
);
1690 if((image
= client_getcontent(*c
)))
1691 return luaA_image_userdata_new(L
, image
);
1696 case WINDOW_TYPE_DESKTOP
:
1697 lua_pushliteral(L
, "desktop");
1699 case WINDOW_TYPE_DOCK
:
1700 lua_pushliteral(L
, "dock");
1702 case WINDOW_TYPE_SPLASH
:
1703 lua_pushliteral(L
, "splash");
1705 case WINDOW_TYPE_DIALOG
:
1706 lua_pushliteral(L
, "dialog");
1708 case WINDOW_TYPE_MENU
:
1709 lua_pushliteral(L
, "menu");
1711 case WINDOW_TYPE_TOOLBAR
:
1712 lua_pushliteral(L
, "toolbar");
1714 case WINDOW_TYPE_UTILITY
:
1715 lua_pushliteral(L
, "utility");
1717 case WINDOW_TYPE_DROPDOWN_MENU
:
1718 lua_pushliteral(L
, "dropdown_menu");
1720 case WINDOW_TYPE_POPUP_MENU
:
1721 lua_pushliteral(L
, "popup_menu");
1723 case WINDOW_TYPE_TOOLTIP
:
1724 lua_pushliteral(L
, "tooltip");
1726 case WINDOW_TYPE_NOTIFICATION
:
1727 lua_pushliteral(L
, "notification");
1729 case WINDOW_TYPE_COMBO
:
1730 lua_pushliteral(L
, "combo");
1732 case WINDOW_TYPE_DND
:
1733 lua_pushliteral(L
, "dnd");
1735 case WINDOW_TYPE_NORMAL
:
1736 lua_pushliteral(L
, "normal");
1741 if(!xcb_get_wm_class_reply(globalconf
.connection
,
1742 xcb_get_wm_class_unchecked(globalconf
.connection
, (*c
)->win
),
1745 lua_pushstring(L
, hint
.class_name
);
1746 xcb_get_wm_class_reply_wipe(&hint
);
1749 if(!xcb_get_wm_class_reply(globalconf
.connection
,
1750 xcb_get_wm_class_unchecked(globalconf
.connection
, (*c
)->win
),
1753 lua_pushstring(L
, hint
.instance_name
);
1754 xcb_get_wm_class_reply_wipe(&hint
);
1757 if(!xutil_text_prop_get(globalconf
.connection
, (*c
)->win
,
1758 WM_WINDOW_ROLE
, &value
, &slen
))
1760 lua_pushlstring(L
, value
, slen
);
1764 prop_c
= xcb_get_property_unchecked(globalconf
.connection
, false, (*c
)->win
, _NET_WM_PID
, CARDINAL
, 0L, 1L);
1765 prop_r
= xcb_get_property_reply(globalconf
.connection
, prop_c
, NULL
);
1767 if(prop_r
&& prop_r
->value_len
&& (data
= xcb_get_property_value(prop_r
)))
1768 lua_pushnumber(L
, *(uint32_t *)data
);
1776 lua_pushnumber(L
, (*c
)->win
);
1778 case A_TK_LEADER_ID
:
1779 lua_pushnumber(L
, (*c
)->leader_win
);
1782 if(!xutil_text_prop_get(globalconf
.connection
, (*c
)->win
,
1783 WM_CLIENT_MACHINE
, &value
, &slen
))
1785 lua_pushlstring(L
, value
, slen
);
1788 case A_TK_ICON_NAME
:
1789 lua_pushstring(L
, (*c
)->icon_name
);
1792 lua_pushnumber(L
, 1 + (*c
)->screen
);
1795 lua_pushboolean(L
, (*c
)->ishidden
);
1797 case A_TK_MINIMIZED
:
1798 lua_pushboolean(L
, (*c
)->isminimized
);
1800 case A_TK_FULLSCREEN
:
1801 lua_pushboolean(L
, (*c
)->isfullscreen
);
1805 lua_pushnumber(L
, (*c
)->group_win
);
1809 case A_TK_MAXIMIZED_HORIZONTAL
:
1810 lua_pushboolean(L
, (*c
)->ismaxhoriz
);
1812 case A_TK_MAXIMIZED_VERTICAL
:
1813 lua_pushboolean(L
, (*c
)->ismaxvert
);
1817 luaA_image_userdata_new(L
, (*c
)->icon
);
1822 if((d
= window_opacity_get((*c
)->win
)) >= 0)
1823 lua_pushnumber(L
, d
);
1828 lua_pushboolean(L
, (*c
)->isontop
);
1831 lua_pushboolean(L
, (*c
)->isabove
);
1834 lua_pushboolean(L
, (*c
)->isbelow
);
1837 lua_pushboolean(L
, (*c
)->issticky
);
1839 case A_TK_SIZE_HINTS_HONOR
:
1840 lua_pushboolean(L
, (*c
)->size_hints_honor
);
1842 case A_TK_BORDER_WIDTH
:
1843 lua_pushnumber(L
, (*c
)->border
);
1845 case A_TK_BORDER_COLOR
:
1846 luaA_pushcolor(L
, &(*c
)->border_color
);
1850 return luaA_wibox_userdata_new(L
, (*c
)->titlebar
);
1853 lua_pushboolean(L
, (*c
)->isurgent
);
1855 case A_TK_SIZE_HINTS
:
1857 const char *u_or_p
= NULL
;
1861 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_US_POSITION
)
1862 u_or_p
= "user_position";
1863 else if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_POSITION
)
1864 u_or_p
= "program_position";
1869 lua_pushnumber(L
, (*c
)->size_hints
.x
);
1870 lua_setfield(L
, -2, "x");
1871 lua_pushnumber(L
, (*c
)->size_hints
.y
);
1872 lua_setfield(L
, -2, "y");
1873 lua_setfield(L
, -2, u_or_p
);
1877 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_US_SIZE
)
1878 u_or_p
= "user_size";
1879 else if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_SIZE
)
1880 u_or_p
= "program_size";
1885 lua_pushnumber(L
, (*c
)->size_hints
.width
);
1886 lua_setfield(L
, -2, "width");
1887 lua_pushnumber(L
, (*c
)->size_hints
.height
);
1888 lua_setfield(L
, -2, "height");
1889 lua_setfield(L
, -2, u_or_p
);
1892 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_MIN_SIZE
)
1894 lua_pushnumber(L
, (*c
)->size_hints
.min_width
);
1895 lua_setfield(L
, -2, "min_width");
1896 lua_pushnumber(L
, (*c
)->size_hints
.min_height
);
1897 lua_setfield(L
, -2, "min_height");
1900 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_MAX_SIZE
)
1902 lua_pushnumber(L
, (*c
)->size_hints
.max_width
);
1903 lua_setfield(L
, -2, "max_width");
1904 lua_pushnumber(L
, (*c
)->size_hints
.max_height
);
1905 lua_setfield(L
, -2, "max_height");
1908 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_RESIZE_INC
)
1910 lua_pushnumber(L
, (*c
)->size_hints
.width_inc
);
1911 lua_setfield(L
, -2, "width_inc");
1912 lua_pushnumber(L
, (*c
)->size_hints
.height_inc
);
1913 lua_setfield(L
, -2, "height_inc");
1916 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_ASPECT
)
1918 lua_pushnumber(L
, (*c
)->size_hints
.min_aspect_num
);
1919 lua_setfield(L
, -2, "min_aspect_num");
1920 lua_pushnumber(L
, (*c
)->size_hints
.min_aspect_den
);
1921 lua_setfield(L
, -2, "min_aspect_den");
1922 lua_pushnumber(L
, (*c
)->size_hints
.max_aspect_num
);
1923 lua_setfield(L
, -2, "max_aspect_num");
1924 lua_pushnumber(L
, (*c
)->size_hints
.max_aspect_den
);
1925 lua_setfield(L
, -2, "max_aspect_den");
1928 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_BASE_SIZE
)
1930 lua_pushnumber(L
, (*c
)->size_hints
.base_width
);
1931 lua_setfield(L
, -2, "base_width");
1932 lua_pushnumber(L
, (*c
)->size_hints
.base_height
);
1933 lua_setfield(L
, -2, "base_height");
1936 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_WIN_GRAVITY
)
1938 switch((*c
)->size_hints
.win_gravity
)
1941 lua_pushliteral(L
, "north_west");
1943 case XCB_GRAVITY_NORTH
:
1944 lua_pushliteral(L
, "north");
1946 case XCB_GRAVITY_NORTH_EAST
:
1947 lua_pushliteral(L
, "north_east");
1949 case XCB_GRAVITY_WEST
:
1950 lua_pushliteral(L
, "west");
1952 case XCB_GRAVITY_CENTER
:
1953 lua_pushliteral(L
, "center");
1955 case XCB_GRAVITY_EAST
:
1956 lua_pushliteral(L
, "east");
1958 case XCB_GRAVITY_SOUTH_WEST
:
1959 lua_pushliteral(L
, "south_west");
1961 case XCB_GRAVITY_SOUTH
:
1962 lua_pushliteral(L
, "south");
1964 case XCB_GRAVITY_SOUTH_EAST
:
1965 lua_pushliteral(L
, "south_east");
1967 case XCB_GRAVITY_STATIC
:
1968 lua_pushliteral(L
, "static");
1971 lua_setfield(L
, -2, "win_gravity");
1982 /** Get or set mouse buttons bindings for a client.
1983 * \param L The Lua VM state.
1984 * \return The number of element pushed on stack.
1987 * \lparam An array of mouse button bindings objects, or nothing.
1988 * \return The array of mouse button bindings objects of this client.
1991 luaA_client_buttons(lua_State
*L
)
1993 client_t
**client
= luaA_checkudata(L
, 1, "client");
1994 button_array_t
*buttons
= &(*client
)->buttons
;
1996 if(lua_gettop(L
) == 2)
1997 luaA_button_array_set(L
, 2, buttons
);
1999 window_buttons_grab((*client
)->win
, &(*client
)->buttons
);
2001 return luaA_button_array_get(L
, buttons
);
2004 /** Get or set keys bindings for a client.
2005 * \param L The Lua VM state.
2006 * \return The number of element pushed on stack.
2009 * \lparam An array of key bindings objects, or nothing.
2010 * \return The array of key bindings objects of this client.
2013 luaA_client_keys(lua_State
*L
)
2015 client_t
**c
= luaA_checkudata(L
, 1, "client");
2016 keybindings_t
*keys
= &(*c
)->keys
;
2018 if(lua_gettop(L
) == 2)
2020 luaA_key_array_set(L
, 2, keys
);
2021 xcb_ungrab_key(globalconf
.connection
, XCB_GRAB_ANY
, (*c
)->win
, XCB_BUTTON_MASK_ANY
);
2022 window_grabkeys((*c
)->win
, keys
);
2025 return luaA_key_array_get(L
, keys
);
2028 /** Send fake events to a client.
2029 * \param L The Lua VM state.
2030 * \return The number of element pushed on stack.
2033 * \param The event type: key_press, key_release, button_press, button_release
2035 * \param The detail: in case of a key event, this is the keycode to send, in
2036 * case of a button event this is the number of the button. In case of a motion
2037 * event, this is a boolean value which if true make the coordinates relatives.
2038 * \param In case of a motion event, this is the X coordinate.
2039 * \param In case of a motion event, this is the Y coordinate.
2042 luaA_client_fake_input(lua_State
*L
)
2044 if(!globalconf
.have_xtest
)
2046 luaA_warn(L
, "XTest extension is not available, cannot fake input.");
2050 client_t
**c
= luaA_checkudata(L
, 1, "client");
2052 const char *stype
= luaL_checklstring(L
, 2, &tlen
);
2053 uint8_t type
, detail
;
2056 switch(a_tokenize(stype
, tlen
))
2058 case A_TK_KEY_PRESS
:
2059 type
= XCB_KEY_PRESS
;
2060 detail
= luaL_checknumber(L
, 3); /* keycode */
2062 case A_TK_KEY_RELEASE
:
2063 type
= XCB_KEY_RELEASE
;
2064 detail
= luaL_checknumber(L
, 3); /* keycode */
2066 case A_TK_BUTTON_PRESS
:
2067 type
= XCB_BUTTON_PRESS
;
2068 detail
= luaL_checknumber(L
, 3); /* button number */
2070 case A_TK_BUTTON_RELEASE
:
2071 type
= XCB_BUTTON_RELEASE
;
2072 detail
= luaL_checknumber(L
, 3); /* button number */
2074 case A_TK_MOTION_NOTIFY
:
2075 type
= XCB_MOTION_NOTIFY
;
2076 detail
= luaA_checkboolean(L
, 3); /* relative to the current position or not */
2077 x
= luaL_checknumber(L
, 4);
2078 y
= luaL_checknumber(L
, 5);
2084 xcb_test_fake_input(globalconf
.connection
,
2095 * \param L The Lua VM state.
2096 * \return The number of pushed elements.
2099 luaA_client_module_index(lua_State
*L
)
2102 const char *buf
= luaL_checklstring(L
, 2, &len
);
2104 switch(a_tokenize(buf
, len
))
2107 if(globalconf
.screen_focus
->client_focus
)
2108 luaA_client_userdata_new(L
, globalconf
.screen_focus
->client_focus
);
2119 /* Client module new index.
2120 * \param L The Lua VM state.
2121 * \return The number of pushed elements.
2124 luaA_client_module_newindex(lua_State
*L
)
2127 const char *buf
= luaL_checklstring(L
, 2, &len
);
2130 switch(a_tokenize(buf
, len
))
2133 c
= luaA_checkudata(L
, 3, "client");
2134 client_focus(*c
, true);
2143 const struct luaL_reg awesome_client_methods
[] =
2145 { "get", luaA_client_get
},
2146 { "__index", luaA_client_module_index
},
2147 { "__newindex", luaA_client_module_newindex
},
2150 const struct luaL_reg awesome_client_meta
[] =
2152 { "isvisible", luaA_client_isvisible
},
2153 { "geometry", luaA_client_geometry
},
2154 { "struts", luaA_client_struts
},
2155 { "buttons", luaA_client_buttons
},
2156 { "keys", luaA_client_keys
},
2157 { "tags", luaA_client_tags
},
2158 { "kill", luaA_client_kill
},
2159 { "swap", luaA_client_swap
},
2160 { "raise", luaA_client_raise
},
2161 { "lower", luaA_client_lower
},
2162 { "redraw", luaA_client_redraw
},
2163 { "unmanage", luaA_client_unmanage
},
2164 { "fake_input", luaA_client_fake_input
},
2165 { "__index", luaA_client_index
},
2166 { "__newindex", luaA_client_newindex
},
2167 { "__eq", luaA_client_eq
},
2168 { "__gc", luaA_client_gc
},
2169 { "__tostring", luaA_client_tostring
},
2173 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80