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 /** Load windows properties, restoring client's tag
44 * and floating state before awesome was restarted if any.
45 * \param c A client pointer.
46 * \param screen A virtual screen.
47 * \return True if client had property, false otherwise.
50 client_loadprops(client_t
* c
, screen_t
*screen
)
53 tag_array_t
*tags
= &screen
->tags
;
55 xcb_get_property_cookie_t fullscreen_q
;
56 xcb_get_property_reply_t
*reply
;
59 if(!xutil_text_prop_get(globalconf
.connection
, c
->win
, _AWESOME_TAGS
,
63 /* Send the GetProperty requests which will be processed later */
64 fullscreen_q
= xcb_get_property_unchecked(globalconf
.connection
, false, c
->win
,
65 _AWESOME_FULLSCREEN
, CARDINAL
, 0, 1);
67 /* ignore property if the tag count isn't matching */
69 for(int i
= 0; i
< tags
->len
; i
++)
71 tag_client(c
, tags
->tab
[i
]);
73 untag_client(c
, tags
->tab
[i
]);
77 /* check for fullscreen */
78 reply
= xcb_get_property_reply(globalconf
.connection
, fullscreen_q
, NULL
);
80 if(reply
&& reply
->value_len
&& (data
= xcb_get_property_value(reply
)))
81 client_setfullscreen(c
, *(bool *) data
);
87 /** Check if client supports protocol a protocole in WM_PROTOCOL.
88 * \param win The window.
89 * \return True if client has the atom in protocol, false otherwise.
92 window_hasproto(xcb_window_t win
, xcb_atom_t atom
)
95 xcb_get_wm_protocols_reply_t protocols
;
98 if(xcb_get_wm_protocols_reply(globalconf
.connection
,
99 xcb_get_wm_protocols_unchecked(globalconf
.connection
,
103 for(i
= 0; !ret
&& i
< protocols
.atoms_len
; i
++)
104 if(protocols
.atoms
[i
] == atom
)
106 xcb_get_wm_protocols_reply_wipe(&protocols
);
111 /** Returns true if a client is tagged
112 * with one of the tags of the specified screen.
113 * \param c The client to check.
114 * \param screen Virtual screen number.
115 * \return true if the client is visible, false otherwise.
118 client_maybevisible(client_t
*c
, int screen
)
120 if(c
->screen
== screen
)
122 if(c
->issticky
|| c
->type
== WINDOW_TYPE_DESKTOP
)
125 tag_array_t
*tags
= &globalconf
.screens
[screen
].tags
;
127 for(int i
= 0; i
< tags
->len
; i
++)
128 if(tags
->tab
[i
]->selected
&& is_client_tagged(c
, tags
->tab
[i
]))
134 /** Return the content of a client as an image.
135 * That's just take a screenshot.
136 * \param c The client.
140 client_getcontent(client_t
*c
)
142 xcb_image_t
*ximage
= xcb_image_get(globalconf
.connection
,
145 c
->geometries
.internal
.width
,
146 c
->geometries
.internal
.height
,
147 ~0, XCB_IMAGE_FORMAT_Z_PIXMAP
);
149 if(!ximage
|| ximage
->bpp
< 24)
152 uint32_t *data
= p_alloca(uint32_t, ximage
->width
* ximage
->height
);
154 for(int y
= 0; y
< ximage
->height
; y
++)
155 for(int x
= 0; x
< ximage
->width
; x
++)
157 data
[y
* ximage
->width
+ x
] = xcb_image_get_pixel(ximage
, x
, y
);
158 data
[y
* ximage
->width
+ x
] |= 0xff000000; /* set alpha to 0xff */
161 image_t
*image
= image_new_from_argb32(ximage
->width
, ximage
->height
, data
);
163 xcb_image_destroy(ximage
);
168 /** Get a client by its window.
169 * \param w The client window to find.
170 * \return A client pointer if found, NULL otherwise.
173 client_getbywin(xcb_window_t w
)
176 for(c
= globalconf
.clients
; c
&& c
->win
!= w
; c
= c
->next
);
180 /** Unfocus a client.
181 * \param c The client.
184 client_unfocus(client_t
*c
)
186 xcb_window_t root_win
= xutil_screen_get(globalconf
.connection
, c
->phys_screen
)->root
;
187 globalconf
.screens
[c
->phys_screen
].client_focus
= NULL
;
189 /* Set focus on root window, so no events leak to the current window. */
191 xcb_set_input_focus(globalconf
.connection
, XCB_INPUT_FOCUS_POINTER_ROOT
,
192 root_win
, XCB_CURRENT_TIME
);
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);
201 ewmh_update_net_active_window(c
->phys_screen
);
204 /** Ban client and move it out of the viewport.
205 * \param c The client.
208 client_ban(client_t
*c
)
212 /* Move all clients out of the physical viewport into negative coordinate space. */
213 /* They will all be put on top of each other. */
214 uint32_t request
[2] = { - (c
->geometries
.internal
.width
+ 2 * c
->border
),
215 - (c
->geometries
.internal
.height
+ 2 * c
->border
) };
217 xcb_configure_window(globalconf
.connection
, c
->win
,
218 XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
,
221 /* Do it manually because client geometry remains unchanged. */
224 simple_window_t
*sw
= &c
->titlebar
->sw
;
228 request
[0] = - (sw
->geometry
.width
);
229 request
[1] = - (sw
->geometry
.height
);
230 /* Move the titlebar to the same place as the window. */
231 xcb_configure_window(globalconf
.connection
, sw
->window
,
232 XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
,
239 /* All the wiboxes (may) need to be repositioned. */
240 if(client_hasstrut(c
))
241 wibox_update_positions();
244 /* Wait until the last moment to take away the focus from the window. */
245 if (globalconf
.screens
[c
->phys_screen
].client_focus
== c
)
249 /** Give focus to client, or to first client if client is NULL.
250 * \param c The client or NULL.
251 * \return True if a window (even root) has received focus, false otherwise.
254 client_focus(client_t
*c
)
256 if(!client_maybevisible(c
, c
->screen
))
259 /* unfocus current selected client */
260 if(globalconf
.screen_focus
->client_focus
261 && c
!= globalconf
.screen_focus
->client_focus
)
262 client_unfocus(globalconf
.screen_focus
->client_focus
);
266 client_setminimized(c
, false);
268 /* unban the client before focusing or it will fail */
271 globalconf
.screen_focus
= &globalconf
.screens
[c
->phys_screen
];
272 globalconf
.screen_focus
->client_focus
= c
;
275 xcb_set_input_focus(globalconf
.connection
, XCB_INPUT_FOCUS_POINTER_ROOT
,
276 c
->win
, XCB_CURRENT_TIME
);
278 /* Some layouts use focused client differently, so call them back.
279 * And anyway, we have maybe unhidden */
280 client_need_arrange(c
);
283 if(globalconf
.hooks
.focus
!= LUA_REFNIL
)
285 luaA_client_userdata_new(globalconf
.L
, globalconf
.screen_focus
->client_focus
);
286 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.focus
, 1, 0);
289 ewmh_update_net_active_window(c
->phys_screen
);
292 /** Stack a window below.
293 * \param c The client.
294 * \param previous The previous window on the stack.
295 * \param return The next-previous!
298 client_stack_above(client_t
*c
, xcb_window_t previous
)
300 uint32_t config_win_vals
[2];
302 config_win_vals
[0] = previous
;
303 config_win_vals
[1] = XCB_STACK_MODE_ABOVE
;
305 xcb_configure_window(globalconf
.connection
, c
->win
,
306 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
309 config_win_vals
[0] = c
->win
;
313 xcb_configure_window(globalconf
.connection
,
314 c
->titlebar
->sw
.window
,
315 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
317 previous
= c
->titlebar
->sw
.window
;
322 /* stack transient window on top of their parents */
323 for(client_node_t
*node
= *client_node_list_last(&globalconf
.stack
);
324 node
; node
= node
->prev
)
325 if(node
->client
->transient_for
== c
)
327 client_stack_above(node
->client
,
329 previous
= node
->client
->win
;
335 /** Stacking layout layers */
338 /** This one is a special layer */
349 /** Get the real layer of a client according to its attribute (fullscreen, …)
350 * \param c The client.
351 * \return The real layer.
354 client_layer_translator(client_t
*c
)
356 /* first deal with user set attributes */
359 else if(c
->isfullscreen
)
360 return LAYER_FULLSCREEN
;
366 /* check for transient attr */
370 /* then deal with windows type */
373 case WINDOW_TYPE_DOCK
:
375 case WINDOW_TYPE_DESKTOP
:
376 return LAYER_DESKTOP
;
377 case WINDOW_TYPE_DIALOG
:
378 case WINDOW_TYPE_MENU
:
379 case WINDOW_TYPE_TOOLBAR
:
380 case WINDOW_TYPE_UTILITY
:
390 * \todo It might be worth stopping to restack everyone and only stack `c'
391 * relatively to the first matching in the list.
396 uint32_t config_win_vals
[2];
397 client_node_t
*node
, *last
= *client_node_list_last(&globalconf
.stack
);
401 config_win_vals
[0] = XCB_NONE
;
402 config_win_vals
[1] = XCB_STACK_MODE_ABOVE
;
404 /* stack desktop windows */
405 for(layer
= LAYER_DESKTOP
; layer
< LAYER_BELOW
; layer
++)
406 for(node
= last
; node
; node
= node
->prev
)
407 if(client_layer_translator(node
->client
) == layer
)
408 config_win_vals
[0] = client_stack_above(node
->client
,
411 /* first stack not ontop wibox window */
412 for(screen
= 0; screen
< globalconf
.nscreen
; screen
++)
413 for(int i
= 0; i
< globalconf
.screens
[screen
].wiboxes
.len
; i
++)
415 wibox_t
*sb
= globalconf
.screens
[screen
].wiboxes
.tab
[i
];
418 xcb_configure_window(globalconf
.connection
,
420 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
422 config_win_vals
[0] = sb
->sw
.window
;
426 /* stack bottom layers */
427 for(layer
= LAYER_BELOW
; layer
< LAYER_FULLSCREEN
; layer
++)
428 for(node
= last
; node
; node
= node
->prev
)
429 if(client_layer_translator(node
->client
) == layer
)
430 config_win_vals
[0] = client_stack_above(node
->client
,
433 /* then stack ontop wibox window */
434 for(screen
= 0; screen
< globalconf
.nscreen
; screen
++)
435 for(int i
= 0; i
< globalconf
.screens
[screen
].wiboxes
.len
; i
++)
437 wibox_t
*sb
= globalconf
.screens
[screen
].wiboxes
.tab
[i
];
440 xcb_configure_window(globalconf
.connection
,
442 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
444 config_win_vals
[0] = sb
->sw
.window
;
448 /* finally stack ontop and fullscreen windows */
449 for(layer
= LAYER_FULLSCREEN
; layer
< LAYER_OUTOFSPACE
; layer
++)
450 for(node
= last
; node
; node
= node
->prev
)
451 if(client_layer_translator(node
->client
) == layer
)
452 config_win_vals
[0] = client_stack_above(node
->client
,
456 /** Copy tags from one client to another client on the same screen.
457 * Be careful: this does not untag!
458 * \param src_c The source client.
459 * \param dst_c The destination client.
462 client_duplicate_tags(client_t
*src_c
, client_t
*dst_c
)
465 tag_array_t
*tags
= &globalconf
.screens
[src_c
->screen
].tags
;
467 /* Avoid doing dangerous things. */
468 if (src_c
->screen
!= dst_c
->screen
)
471 for(i
= 0; i
< tags
->len
; i
++)
472 if(is_client_tagged(src_c
, tags
->tab
[i
]))
473 tag_client(dst_c
, tags
->tab
[i
]);
476 /** Manage a new client.
477 * \param w The window.
478 * \param wgeom Window geometry.
479 * \param phys_screen Physical screen number.
480 * \param startup True if we are managing at startup time.
483 client_manage(xcb_window_t w
, xcb_get_geometry_reply_t
*wgeom
, int phys_screen
, bool startup
)
485 xcb_get_property_cookie_t ewmh_icon_cookie
;
486 client_t
*c
, *tc
= NULL
, *group
= NULL
;
489 const uint32_t select_input_val
[] =
491 XCB_EVENT_MASK_STRUCTURE_NOTIFY
492 | XCB_EVENT_MASK_PROPERTY_CHANGE
493 | XCB_EVENT_MASK_ENTER_WINDOW
494 | XCB_EVENT_MASK_LEAVE_WINDOW
498 if(systray_iskdedockapp(w
))
500 systray_request_handle(w
, phys_screen
, NULL
);
504 /* Send request to get NET_WM_ICON property as soon as possible... */
505 ewmh_icon_cookie
= ewmh_window_icon_get_unchecked(w
);
506 xcb_change_window_attributes(globalconf
.connection
, w
, XCB_CW_EVENT_MASK
, select_input_val
);
507 c
= p_new(client_t
, 1);
509 screen
= c
->screen
= screen_getbycoord(phys_screen
, wgeom
->x
, wgeom
->y
);
511 c
->phys_screen
= phys_screen
;
515 c
->geometry
.x
= wgeom
->x
;
516 c
->geometry
.y
= wgeom
->y
;
517 c
->geometry
.width
= wgeom
->width
+ 2 * wgeom
->border_width
;
518 c
->geometry
.height
= wgeom
->height
+ 2 * wgeom
->border_width
;
519 /* Also set internal geometry (client_ban() needs it). */
520 c
->geometries
.internal
.x
= wgeom
->x
;
521 c
->geometries
.internal
.y
= wgeom
->y
;
522 c
->geometries
.internal
.width
= wgeom
->width
;
523 c
->geometries
.internal
.height
= wgeom
->height
;
524 client_setborder(c
, wgeom
->border_width
);
525 if((icon
= ewmh_window_icon_get_reply(ewmh_icon_cookie
)))
526 c
->icon
= image_ref(&icon
);
528 /* we honor size hints by default */
529 c
->size_hints_honor
= true;
532 property_update_wm_normal_hints(c
, NULL
);
533 property_update_wm_hints(c
, NULL
);
534 property_update_wm_transient_for(c
, NULL
);
535 property_update_wm_client_leader(c
, NULL
);
537 /* Recursively find the parent. */
538 for(tc
= c
; tc
->transient_for
; tc
= tc
->transient_for
);
542 /* Try to load props, if it fails check for group windows.
543 * transient_for windows are excluded, because they inherit the parent tags. */
544 if(!client_loadprops(c
, &globalconf
.screens
[screen
])
546 && !c
->transient_for
)
547 /* Try to find a group of windows for better initial placement. */
548 for(group
= globalconf
.clients
; group
; group
= group
->next
)
549 if(group
->group_win
== c
->group_win
)
552 /* Move to the right screen.
553 * Assumption: Window groups do not span multiple logical screens. */
555 screen
= group
->screen
;
557 /* Then check clients hints */
558 ewmh_client_check_hints(c
);
560 /* move client to screen, but do not tag it for now */
561 screen_client_moveto(c
, screen
, false, true);
563 /* Duplicate the tags of either the parent or a group window.
564 * Otherwise check for existing tags, if that fails tag it with the current tag.
565 * This could be done lua side, but it's sane behaviour. */
569 client_duplicate_tags(tc
, c
);
571 client_duplicate_tags(group
, c
);
575 tag_array_t
*tags
= &globalconf
.screens
[screen
].tags
;
576 for(i
= 0; i
< tags
->len
; i
++)
577 if(is_client_tagged(c
, tags
->tab
[i
]))
580 /* if no tag, set current selected */
582 for(i
= 0; i
< tags
->len
; i
++)
583 if(tags
->tab
[i
]->selected
)
584 tag_client(c
, tags
->tab
[i
]);
588 /* Push client in client list */
589 client_list_push(&globalconf
.clients
, client_ref(&c
));
591 /* Push client in stack */
594 /* update window title */
595 property_update_wm_name(c
);
596 property_update_wm_icon_name(c
);
599 ewmh_client_strut_update(c
, NULL
);
601 ewmh_update_net_client_list(c
->phys_screen
);
603 /* Always stay in NORMAL_STATE. Even though iconified seems more
604 * appropriate sometimes. The only possible loss is that clients not using
605 * visibility events may continue to proces data (when banned).
606 * Without any exposes or other events the cost should be fairly limited though.
608 * Some clients may expect the window to be unmapped when STATE_ICONIFIED.
609 * Two conflicting parts of the ICCCM v2.0 (section 4.1.4):
611 * "Normal -> Iconic - The client should send a ClientMessage event as described later in this section."
612 * (note no explicit mention of unmapping, while Normal->Widthdrawn does mention that)
614 * "Once a client's window has left the Withdrawn state, the window will be mapped
615 * if it is in the Normal state and the window will be unmapped if it is in the Iconic state."
617 * At this stage it's just safer to keep it in normal state and avoid confusion.
619 window_state_set(c
->win
, XCB_WM_STATE_NORMAL
);
621 /* Move window outside the viewport before mapping it. */
623 xcb_map_window(globalconf
.connection
, c
->win
);
625 /* Call hook to notify list change */
626 if(globalconf
.hooks
.clients
!= LUA_REFNIL
)
627 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.clients
, 0, 0);
630 if(globalconf
.hooks
.manage
!= LUA_REFNIL
)
632 luaA_client_userdata_new(globalconf
.L
, c
);
633 lua_pushboolean(globalconf
.L
, startup
);
634 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.manage
, 2, 0);
638 /** Compute client geometry with respect to its geometry hints.
639 * \param c The client.
640 * \param geometry The geometry that the client might receive.
641 * \return The geometry the client must take respecting its hints.
644 client_geometry_hints(client_t
*c
, area_t geometry
)
646 int32_t basew
, baseh
, minw
, minh
;
648 /* base size is substituted with min size if not specified */
649 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_SIZE
)
651 basew
= c
->size_hints
.base_width
;
652 baseh
= c
->size_hints
.base_height
;
654 else if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MIN_SIZE
)
656 basew
= c
->size_hints
.min_width
;
657 baseh
= c
->size_hints
.min_height
;
662 /* min size is substituted with base size if not specified */
663 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MIN_SIZE
)
665 minw
= c
->size_hints
.min_width
;
666 minh
= c
->size_hints
.min_height
;
668 else if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_SIZE
)
670 minw
= c
->size_hints
.base_width
;
671 minh
= c
->size_hints
.base_height
;
676 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_ASPECT
677 && c
->size_hints
.min_aspect_num
> 0
678 && c
->size_hints
.min_aspect_den
> 0
679 && geometry
.height
- baseh
> 0
680 && geometry
.width
- basew
> 0)
682 double dx
= (double) (geometry
.width
- basew
);
683 double dy
= (double) (geometry
.height
- baseh
);
684 double min
= (double) c
->size_hints
.min_aspect_num
/ (double) c
->size_hints
.min_aspect_den
;
685 double max
= (double) c
->size_hints
.max_aspect_num
/ (double) c
->size_hints
.min_aspect_den
;
686 double ratio
= dx
/ dy
;
687 if(max
> 0 && min
> 0 && ratio
> 0)
691 dy
= (dx
* min
+ dy
) / (min
* min
+ 1);
693 geometry
.width
= (int) dx
+ basew
;
694 geometry
.height
= (int) dy
+ baseh
;
698 dy
= (dx
* min
+ dy
) / (max
* max
+ 1);
700 geometry
.width
= (int) dx
+ basew
;
701 geometry
.height
= (int) dy
+ baseh
;
707 geometry
.width
= MAX(geometry
.width
, minw
);
709 geometry
.height
= MAX(geometry
.height
, minh
);
711 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MAX_SIZE
)
713 if(c
->size_hints
.max_width
)
714 geometry
.width
= MIN(geometry
.width
, c
->size_hints
.max_width
);
715 if(c
->size_hints
.max_height
)
716 geometry
.height
= MIN(geometry
.height
, c
->size_hints
.max_height
);
719 if(c
->size_hints
.flags
& (XCB_SIZE_HINT_P_RESIZE_INC
| XCB_SIZE_HINT_BASE_SIZE
)
720 && c
->size_hints
.width_inc
&& c
->size_hints
.height_inc
)
722 uint16_t t1
= geometry
.width
, t2
= geometry
.height
;
723 unsigned_subtract(t1
, basew
);
724 unsigned_subtract(t2
, baseh
);
725 geometry
.width
-= t1
% c
->size_hints
.width_inc
;
726 geometry
.height
-= t2
% c
->size_hints
.height_inc
;
732 /** Resize client window.
733 * \param c Client to resize.
734 * \param geometry New window geometry.
735 * \param hints Use size hints.
738 client_resize(client_t
*c
, area_t geometry
, bool hints
)
741 area_t geometry_internal
;
744 /* offscreen appearance fixes */
745 area
= display_area_get(c
->phys_screen
, NULL
,
746 &globalconf
.screens
[c
->screen
].padding
);
748 if(geometry
.x
> area
.width
)
749 geometry
.x
= area
.width
- geometry
.width
;
750 if(geometry
.y
> area
.height
)
751 geometry
.y
= area
.height
- geometry
.height
;
752 if(geometry
.x
+ geometry
.width
< 0)
754 if(geometry
.y
+ geometry
.height
< 0)
757 /* Real client geometry, please keep it contained to C code at the very least. */
758 geometry_internal
= titlebar_geometry_remove(c
->titlebar
, c
->border
, geometry
);
761 geometry_internal
= client_geometry_hints(c
, geometry_internal
);
763 if(geometry_internal
.width
== 0 || geometry_internal
.height
== 0)
766 /* Also let client hints propegate to the "official" geometry. */
767 geometry
= titlebar_geometry_add(c
->titlebar
, c
->border
, geometry_internal
);
769 if(c
->geometries
.internal
.x
!= geometry_internal
.x
770 || c
->geometries
.internal
.y
!= geometry_internal
.y
771 || c
->geometries
.internal
.width
!= geometry_internal
.width
772 || c
->geometries
.internal
.height
!= geometry_internal
.height
)
774 new_screen
= screen_getbycoord(c
->screen
, geometry_internal
.x
, geometry_internal
.y
);
776 /* Values to configure a window is an array where values are
777 * stored according to 'value_mask' */
780 c
->geometries
.internal
.x
= values
[0] = geometry_internal
.x
;
781 c
->geometries
.internal
.y
= values
[1] = geometry_internal
.y
;
782 c
->geometries
.internal
.width
= values
[2] = geometry_internal
.width
;
783 c
->geometries
.internal
.height
= values
[3] = geometry_internal
.height
;
785 /* Also store geometry including border and titlebar. */
786 c
->geometry
= geometry
;
788 titlebar_update_geometry(c
);
790 /* The idea is to give a client a resize even when banned. */
791 /* We just have to move the (x,y) to keep it out of the viewport. */
792 /* This at least doesn't break expectations about events. */
795 geometry
.x
= values
[0] = - (geometry_internal
.width
+ 2 * c
->border
);
796 geometry
.y
= values
[1] = - (geometry_internal
.height
+ 2 * c
->border
);
799 xcb_configure_window(globalconf
.connection
, c
->win
,
800 XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
801 | XCB_CONFIG_WINDOW_WIDTH
| XCB_CONFIG_WINDOW_HEIGHT
,
803 window_configure(c
->win
, geometry_internal
, c
->border
);
805 screen_client_moveto(c
, new_screen
, true, false);
808 hooks_property(c
, "geometry");
812 /** Set a client minimized, or not.
813 * \param c The client.
814 * \param s Set or not the client minimized.
817 client_setminimized(client_t
*c
, bool s
)
819 if(c
->isminimized
!= s
)
821 client_need_arrange(c
);
823 client_need_arrange(c
);
824 ewmh_client_update_hints(c
);
826 hooks_property(c
, "minimized");
830 /** Set a client sticky, or not.
831 * \param c The client.
832 * \param s Set or not the client sticky.
835 client_setsticky(client_t
*c
, bool s
)
839 client_need_arrange(c
);
841 client_need_arrange(c
);
842 ewmh_client_update_hints(c
);
843 hooks_property(c
, "sticky");
847 /** Set a client fullscreen, or not.
848 * \param c The client.
849 * \param s Set or not the client fullscreen.
852 client_setfullscreen(client_t
*c
, bool s
)
854 if(c
->isfullscreen
!= s
)
858 /* become fullscreen! */
859 if((c
->isfullscreen
= s
))
861 /* remove any max state */
862 client_setmaxhoriz(c
, false);
863 client_setmaxvert(c
, false);
865 geometry
= screen_area_get(c
->screen
, NULL
, NULL
, false);
866 c
->geometries
.fullscreen
= c
->geometry
;
867 c
->border_fs
= c
->border
;
868 client_setborder(c
, 0);
872 geometry
= c
->geometries
.fullscreen
;
873 client_setborder(c
, c
->border_fs
);
875 client_resize(c
, geometry
, false);
876 client_need_arrange(c
);
878 xcb_change_property(globalconf
.connection
,
879 XCB_PROP_MODE_REPLACE
,
880 c
->win
, _AWESOME_FULLSCREEN
, CARDINAL
, 8, 1,
882 ewmh_client_update_hints(c
);
883 hooks_property(c
, "fullscreen");
887 /** Set a client horizontally maximized.
888 * \param c The client.
889 * \param s The maximized status.
892 client_setmaxhoriz(client_t
*c
, bool s
)
894 if(c
->ismaxhoriz
!= s
)
898 if((c
->ismaxhoriz
= s
))
900 /* remove fullscreen mode */
901 client_setfullscreen(c
, false);
903 geometry
= screen_area_get(c
->screen
,
904 &globalconf
.screens
[c
->screen
].wiboxes
,
905 &globalconf
.screens
[c
->screen
].padding
,
907 geometry
.y
= c
->geometry
.y
;
908 geometry
.height
= c
->geometry
.height
;
909 c
->geometries
.max
.x
= c
->geometry
.x
;
910 c
->geometries
.max
.width
= c
->geometry
.width
;
914 geometry
= c
->geometry
;
915 geometry
.x
= c
->geometries
.max
.x
;
916 geometry
.width
= c
->geometries
.max
.width
;
919 client_resize(c
, geometry
, c
->size_hints_honor
);
920 client_need_arrange(c
);
922 ewmh_client_update_hints(c
);
923 hooks_property(c
, "maximized_horizontal");
927 /** Set a client vertically maximized.
928 * \param c The client.
929 * \param s The maximized status.
932 client_setmaxvert(client_t
*c
, bool s
)
934 if(c
->ismaxvert
!= s
)
938 if((c
->ismaxvert
= s
))
940 /* remove fullscreen mode */
941 client_setfullscreen(c
, false);
943 geometry
= screen_area_get(c
->screen
,
944 &globalconf
.screens
[c
->screen
].wiboxes
,
945 &globalconf
.screens
[c
->screen
].padding
,
947 geometry
.x
= c
->geometry
.x
;
948 geometry
.width
= c
->geometry
.width
;
949 c
->geometries
.max
.y
= c
->geometry
.y
;
950 c
->geometries
.max
.height
= c
->geometry
.height
;
954 geometry
= c
->geometry
;
955 geometry
.y
= c
->geometries
.max
.y
;
956 geometry
.height
= c
->geometries
.max
.height
;
959 client_resize(c
, geometry
, c
->size_hints_honor
);
960 client_need_arrange(c
);
962 ewmh_client_update_hints(c
);
963 hooks_property(c
, "maximized_vertical");
967 /** Set a client above, or not.
968 * \param c The client.
969 * \param s Set or not the client above.
972 client_setabove(client_t
*c
, bool s
)
978 ewmh_client_update_hints(c
);
980 hooks_property(c
, "above");
984 /** Set a client below, or not.
985 * \param c The client.
986 * \param s Set or not the client below.
989 client_setbelow(client_t
*c
, bool s
)
995 ewmh_client_update_hints(c
);
997 hooks_property(c
, "below");
1001 /** Set a client modal, or not.
1002 * \param c The client.
1003 * \param s Set or not the client moda.
1006 client_setmodal(client_t
*c
, bool s
)
1012 ewmh_client_update_hints(c
);
1014 hooks_property(c
, "modal");
1018 /** Set a client ontop, or not.
1019 * \param c The client.
1020 * \param s Set or not the client moda.
1023 client_setontop(client_t
*c
, bool s
)
1030 hooks_property(c
, "ontop");
1034 /** Save client properties as an X property.
1035 * \param c The client.
1038 client_saveprops_tags(client_t
*c
)
1040 tag_array_t
*tags
= &globalconf
.screens
[c
->screen
].tags
;
1041 unsigned char *prop
= p_alloca(unsigned char, tags
->len
+ 1);
1044 for(i
= 0; i
< tags
->len
; i
++)
1045 prop
[i
] = is_client_tagged(c
, tags
->tab
[i
]) ? '1' : '0';
1047 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
, c
->win
, _AWESOME_TAGS
, STRING
, 8, i
, prop
);
1050 /** Unban a client and move it back into the viewport.
1051 * \param c The client.
1054 client_unban(client_t
*c
)
1058 /* Move the client back where it belongs. */
1059 uint32_t request
[2] = { c
->geometries
.internal
.x
, c
->geometries
.internal
.y
};
1061 xcb_configure_window(globalconf
.connection
, c
->win
,
1062 XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
,
1064 window_configure(c
->win
, c
->geometries
.internal
, c
->border
);
1066 /* Do this manually because the system doesn't know we moved the toolbar.
1067 * Note that !isvisible titlebars are unmapped and for fullscreen it'll
1068 * end up offscreen anyway. */
1071 simple_window_t
*sw
= &c
->titlebar
->sw
;
1072 /* All resizing is done, so only move now. */
1073 request
[0] = sw
->geometry
.x
;
1074 request
[1] = sw
->geometry
.y
;
1076 xcb_configure_window(globalconf
.connection
, sw
->window
,
1077 XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
,
1081 c
->isbanned
= false;
1083 /* All the wiboxes (may) need to be repositioned. */
1084 if(client_hasstrut(c
))
1085 wibox_update_positions();
1089 /** Unmanage a client.
1090 * \param c The client.
1093 client_unmanage(client_t
*c
)
1095 tag_array_t
*tags
= &globalconf
.screens
[c
->screen
].tags
;
1097 if(globalconf
.screens
[c
->phys_screen
].client_focus
== c
)
1100 /* remove client everywhere */
1101 client_list_detach(&globalconf
.clients
, c
);
1102 stack_client_delete(c
);
1103 for(int i
= 0; i
< tags
->len
; i
++)
1104 untag_client(c
, tags
->tab
[i
]);
1107 if(globalconf
.hooks
.unmanage
!= LUA_REFNIL
)
1109 luaA_client_userdata_new(globalconf
.L
, c
);
1110 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.unmanage
, 1, 0);
1113 /* Call hook to notify list change */
1114 if(globalconf
.hooks
.clients
!= LUA_REFNIL
)
1115 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.clients
, 0, 0);
1117 /* The server grab construct avoids race conditions. */
1118 xcb_grab_server(globalconf
.connection
);
1120 xcb_ungrab_button(globalconf
.connection
, XCB_BUTTON_INDEX_ANY
, c
->win
,
1121 XCB_BUTTON_MASK_ANY
);
1122 window_state_set(c
->win
, XCB_WM_STATE_WITHDRAWN
);
1124 xcb_flush(globalconf
.connection
);
1125 xcb_ungrab_server(globalconf
.connection
);
1127 titlebar_client_detach(c
);
1129 ewmh_update_net_client_list(c
->phys_screen
);
1131 /* delete properties */
1132 xcb_delete_property(globalconf
.connection
, c
->win
, _AWESOME_TAGS
);
1133 xcb_delete_property(globalconf
.connection
, c
->win
, _AWESOME_FLOATING
);
1135 /* All the wiboxes (may) need to be repositioned. */
1136 if(client_hasstrut(c
))
1137 wibox_update_positions();
1139 /* set client as invalid */
1145 /** Kill a client via a WM_DELETE_WINDOW request or KillClient if not
1147 * \param c The client to kill.
1150 client_kill(client_t
*c
)
1152 if(window_hasproto(c
->win
, WM_DELETE_WINDOW
))
1154 xcb_client_message_event_t ev
;
1156 /* Initialize all of event's fields first */
1159 ev
.response_type
= XCB_CLIENT_MESSAGE
;
1162 ev
.data
.data32
[1] = XCB_CURRENT_TIME
;
1163 ev
.type
= WM_PROTOCOLS
;
1164 ev
.data
.data32
[0] = WM_DELETE_WINDOW
;
1166 xcb_send_event(globalconf
.connection
, false, c
->win
,
1167 XCB_EVENT_MASK_NO_EVENT
, (char *) &ev
);
1170 xcb_kill_client(globalconf
.connection
, c
->win
);
1173 /** Get all clients into a table.
1174 * \param L The Lua VM state.
1175 * \return The number of elements pushed on stack.
1177 * \lparam An optional screen nunmber.
1178 * \lreturn A table with all clients.
1181 luaA_client_get(lua_State
*L
)
1186 screen
= luaL_optnumber(L
, 1, 0) - 1;
1190 if(screen
== SCREEN_UNDEF
)
1191 for(c
= globalconf
.clients
; c
; c
= c
->next
)
1193 luaA_client_userdata_new(globalconf
.L
, c
);
1194 lua_rawseti(L
, -2, i
++);
1198 luaA_checkscreen(screen
);
1199 for(c
= globalconf
.clients
; c
; c
= c
->next
)
1200 if(c
->screen
== screen
)
1202 luaA_client_userdata_new(globalconf
.L
, c
);
1203 lua_rawseti(L
, -2, i
++);
1210 /** Check if a client is visible on its screen.
1211 * \param L The Lua VM state.
1212 * \return The number of elements pushed on stack.
1215 * \lreturn A boolean value, true if the client is visible, false otherwise.
1218 luaA_client_isvisible(lua_State
*L
)
1220 client_t
**c
= luaA_checkudata(L
, 1, "client");
1221 lua_pushboolean(L
, client_isvisible(*c
, (*c
)->screen
));
1225 /** Set client border width.
1226 * \param c The client.
1227 * \param width The border width.
1230 client_setborder(client_t
*c
, int width
)
1234 if(width
> 0 && (c
->type
== WINDOW_TYPE_DOCK
1235 || c
->type
== WINDOW_TYPE_SPLASH
1236 || c
->type
== WINDOW_TYPE_DESKTOP
1237 || c
->isfullscreen
))
1240 if(width
== c
->border
|| width
< 0)
1244 xcb_configure_window(globalconf
.connection
, c
->win
,
1245 XCB_CONFIG_WINDOW_BORDER_WIDTH
, &w
);
1247 client_need_arrange(c
);
1249 hooks_property(c
, "border_width");
1253 * \param L The Lua VM state.
1259 luaA_client_kill(lua_State
*L
)
1261 client_t
**c
= luaA_checkudata(L
, 1, "client");
1266 /** Swap a client with another one.
1267 * \param L The Lua VM state.
1270 * \lparam A client to swap with.
1273 luaA_client_swap(lua_State
*L
)
1275 client_t
**c
= luaA_checkudata(L
, 1, "client");
1276 client_t
**swap
= luaA_checkudata(L
, 2, "client");
1280 client_list_swap(&globalconf
.clients
, *swap
, *c
);
1281 client_need_arrange(*c
);
1282 client_need_arrange(*swap
);
1284 /* Call hook to notify list change */
1285 if(globalconf
.hooks
.clients
!= LUA_REFNIL
)
1286 luaA_dofunction(L
, globalconf
.hooks
.clients
, 0, 0);
1292 /** Access or set the client tags.
1293 * \param L The Lua VM state.
1294 * \return The number of elements pushed on stack.
1295 * \lparam A table with tags to set, or none to get the current tags table.
1296 * \return The clients tag.
1299 luaA_client_tags(lua_State
*L
)
1303 client_t
**c
= luaA_checkudata(L
, 1, "client");
1306 if(lua_gettop(L
) == 2)
1308 luaA_checktable(L
, 2);
1309 tags
= &globalconf
.screens
[(*c
)->screen
].tags
;
1310 for(int i
= 0; i
< tags
->len
; i
++)
1311 untag_client(*c
, tags
->tab
[i
]);
1313 while(lua_next(L
, 2))
1315 tag
= luaA_checkudata(L
, -1, "tag");
1316 tag_client(*c
, *tag
);
1322 tags
= &globalconf
.screens
[(*c
)->screen
].tags
;
1324 for(int i
= 0; i
< tags
->len
; i
++)
1325 if(is_client_tagged(*c
, tags
->tab
[i
]))
1327 luaA_tag_userdata_new(L
, tags
->tab
[i
]);
1328 lua_rawseti(L
, -2, ++j
);
1334 /** Raise a client on top of others which are on the same layer.
1335 * \param L The Lua VM state.
1340 luaA_client_raise(lua_State
*L
)
1342 client_t
**c
= luaA_checkudata(L
, 1, "client");
1347 /** Lower a client on bottom of others which are on the same layer.
1348 * \param L The Lua VM state.
1353 luaA_client_lower(lua_State
*L
)
1355 client_t
**c
= luaA_checkudata(L
, 1, "client");
1360 /** Redraw a client by unmapping and mapping it quickly.
1361 * \param L The Lua VM state.
1367 luaA_client_redraw(lua_State
*L
)
1369 client_t
**c
= luaA_checkudata(L
, 1, "client");
1371 xcb_unmap_window(globalconf
.connection
, (*c
)->win
);
1372 xcb_map_window(globalconf
.connection
, (*c
)->win
);
1374 /* Set the focus on the current window if the redraw has been
1375 performed on the window where the pointer is currently on
1376 because after the unmapping/mapping, the focus is lost */
1377 if(globalconf
.screen_focus
->client_focus
== *c
)
1378 xcb_set_input_focus(globalconf
.connection
, XCB_INPUT_FOCUS_POINTER_ROOT
,
1379 (*c
)->win
, XCB_CURRENT_TIME
);
1384 /** Stop managing a client.
1385 * \param L The Lua VM state.
1386 * \return The number of elements pushed on stack.
1391 luaA_client_unmanage(lua_State
*L
)
1393 client_t
**c
= luaA_checkudata(L
, 1, "client");
1394 client_unmanage(*c
);
1398 /** Return client geometry.
1399 * \param L The Lua VM state.
1400 * \return The number of elements pushed on stack.
1402 * \lparam A table with new coordinates, or none.
1403 * \lreturn A table with client coordinates.
1406 luaA_client_geometry(lua_State
*L
)
1408 client_t
**c
= luaA_checkudata(L
, 1, "client");
1410 if(lua_gettop(L
) == 2)
1414 luaA_checktable(L
, 2);
1415 geometry
.x
= luaA_getopt_number(L
, 2, "x", (*c
)->geometry
.x
);
1416 geometry
.y
= luaA_getopt_number(L
, 2, "y", (*c
)->geometry
.y
);
1417 if(client_isfixed(*c
))
1419 geometry
.width
= (*c
)->geometry
.width
;
1420 geometry
.height
= (*c
)->geometry
.height
;
1424 geometry
.width
= luaA_getopt_number(L
, 2, "width", (*c
)->geometry
.width
);
1425 geometry
.height
= luaA_getopt_number(L
, 2, "height", (*c
)->geometry
.height
);
1428 client_resize(*c
, geometry
, (*c
)->size_hints_honor
);
1431 return luaA_pusharea(L
, (*c
)->geometry
);
1434 /** Client newindex.
1435 * \param L The Lua VM state.
1436 * \return The number of elements pushed on stack.
1439 luaA_client_newindex(lua_State
*L
)
1442 client_t
**c
= luaA_checkudata(L
, 1, "client");
1443 const char *buf
= luaL_checklstring(L
, 2, &len
);
1451 luaL_error(L
, "client is invalid\n");
1453 switch(a_tokenize(buf
, len
))
1456 if(globalconf
.xinerama_is_active
)
1458 i
= luaL_checknumber(L
, 3) - 1;
1459 luaA_checkscreen(i
);
1460 screen_client_moveto(*c
, i
, true, true);
1464 b
= luaA_checkboolean(L
, 3);
1465 if(b
!= (*c
)->ishidden
)
1467 client_need_arrange(*c
);
1469 client_need_arrange(*c
);
1473 luaA_deprecate(L
, "client.minimized");
1474 case A_TK_MINIMIZED
:
1475 client_setminimized(*c
, luaA_checkboolean(L
, 3));
1477 case A_TK_FULLSCREEN
:
1478 client_setfullscreen(*c
, luaA_checkboolean(L
, 3));
1480 case A_TK_MAXIMIZED_HORIZONTAL
:
1481 client_setmaxhoriz(*c
, luaA_checkboolean(L
, 3));
1483 case A_TK_MAXIMIZED_VERTICAL
:
1484 client_setmaxvert(*c
, luaA_checkboolean(L
, 3));
1487 image
= luaA_checkudata(L
, 3, "image");
1488 image_unref(&(*c
)->icon
);
1490 (*c
)->icon
= *image
;
1492 hooks_property(*c
, "icon");
1496 window_opacity_set((*c
)->win
, -1);
1499 d
= luaL_checknumber(L
, 3);
1500 if(d
>= 0 && d
<= 1)
1501 window_opacity_set((*c
)->win
, d
);
1505 client_setsticky(*c
, luaA_checkboolean(L
, 3));
1507 case A_TK_HONORSIZEHINTS
:
1508 (*c
)->size_hints_honor
= luaA_checkboolean(L
, 3);
1509 client_need_arrange(*c
);
1511 case A_TK_BORDER_WIDTH
:
1512 client_setborder(*c
, luaL_checknumber(L
, 3));
1515 client_setontop(*c
, luaA_checkboolean(L
, 3));
1517 case A_TK_BORDER_COLOR
:
1518 if((buf
= luaL_checklstring(L
, 3, &len
))
1519 && xcolor_init_reply(xcolor_init_unchecked(&(*c
)->border_color
, buf
, len
)))
1520 xcb_change_window_attributes(globalconf
.connection
, (*c
)->win
,
1521 XCB_CW_BORDER_PIXEL
, &(*c
)->border_color
.pixel
);
1525 titlebar_client_detach(*c
);
1528 t
= luaA_checkudata(L
, 3, "wibox");
1529 titlebar_client_attach(*c
, *t
);
1540 * \param L The Lua VM state.
1541 * \return The number of elements pushed on stack.
1543 * \lfield name The client title.
1544 * \lfield skip_taskbar True if the client does not want to be in taskbar.
1545 * \lfield type The window type (desktop, normal, dock, …).
1546 * \lfield class The client class.
1547 * \lfield instance The client instance.
1548 * \lfield pid The client PID, if available.
1549 * \lfield role The window role, if available.
1550 * \lfield machine The machine client is running on.
1551 * \lfield icon_name The client name when iconified.
1552 * \lfield screen Client screen number.
1553 * \lfield hide Define if the client must be hidden, i.e. never mapped,
1554 * invisible in taskbar.
1555 * \lfield minimize Define it the client must be iconify, i.e. only visible in
1557 * \lfield icon_path Path to the icon used to identify.
1558 * \lfield size_hints_honor Honor size hints, i.e. respect size ratio.
1559 * \lfield border_width The client border width.
1560 * \lfield border_color The client border color.
1561 * \lfield titlebar The client titlebar.
1562 * \lfield urgent The client urgent state.
1563 * \lfield content An image representing the client window content (screenshot).
1564 * \lfield focus The focused client.
1565 * \lfield opacity The client opacity between 0 and 1.
1566 * \lfield ontop The client is on top of every other windows.
1567 * \lfield fullscreen The client is fullscreen or not.
1568 * \lfield maximized_horizontal The client is maximized horizontally or not.
1569 * \lfield maximized_vertical The client is maximized vertically or not.
1570 * \lfield transient_for Return the client the window is transient for.
1571 * \lfield group_id Identification unique to a group of windows.
1572 * \lfield leader_id Identification unique to windows spawned by the same command.
1573 * \lfield size_hints A table with size hints of the client: user_position,
1574 * user_size, program_position, program_size, etc.
1577 luaA_client_index(lua_State
*L
)
1581 client_t
**c
= luaA_checkudata(L
, 1, "client");
1582 const char *buf
= luaL_checklstring(L
, 2, &len
);
1585 xcb_get_wm_class_reply_t hint
;
1586 xcb_get_property_cookie_t prop_c
;
1587 xcb_get_property_reply_t
*prop_r
= NULL
;
1591 luaL_error(L
, "client is invalid\n");
1593 if(luaA_usemetatable(L
, 1, 2))
1596 switch(a_tokenize(buf
, len
))
1601 lua_pushstring(L
, (*c
)->name
);
1603 case A_TK_TRANSIENT_FOR
:
1604 if((*c
)->transient_for
)
1605 return luaA_client_userdata_new(L
, (*c
)->transient_for
);
1607 case A_TK_SKIP_TASKBAR
:
1608 lua_pushboolean(L
, (*c
)->skiptb
);
1611 if((image
= client_getcontent(*c
)))
1612 return luaA_image_userdata_new(L
, image
);
1617 case WINDOW_TYPE_DESKTOP
:
1618 lua_pushliteral(L
, "desktop");
1620 case WINDOW_TYPE_DOCK
:
1621 lua_pushliteral(L
, "dock");
1623 case WINDOW_TYPE_SPLASH
:
1624 lua_pushliteral(L
, "splash");
1626 case WINDOW_TYPE_DIALOG
:
1627 lua_pushliteral(L
, "dialog");
1629 case WINDOW_TYPE_MENU
:
1630 lua_pushliteral(L
, "menu");
1632 case WINDOW_TYPE_TOOLBAR
:
1633 lua_pushliteral(L
, "toolbar");
1635 case WINDOW_TYPE_UTILITY
:
1636 lua_pushliteral(L
, "utility");
1639 lua_pushliteral(L
, "normal");
1644 if(!xcb_get_wm_class_reply(globalconf
.connection
,
1645 xcb_get_wm_class_unchecked(globalconf
.connection
, (*c
)->win
),
1648 lua_pushstring(L
, hint
.class);
1649 xcb_get_wm_class_reply_wipe(&hint
);
1652 if(!xcb_get_wm_class_reply(globalconf
.connection
,
1653 xcb_get_wm_class_unchecked(globalconf
.connection
, (*c
)->win
),
1656 lua_pushstring(L
, hint
.name
);
1657 xcb_get_wm_class_reply_wipe(&hint
);
1660 if(!xutil_text_prop_get(globalconf
.connection
, (*c
)->win
,
1661 WM_WINDOW_ROLE
, &value
, &slen
))
1663 lua_pushlstring(L
, value
, slen
);
1667 prop_c
= xcb_get_property_unchecked(globalconf
.connection
, false, (*c
)->win
, _NET_WM_PID
, CARDINAL
, 0L, 1L);
1668 prop_r
= xcb_get_property_reply(globalconf
.connection
, prop_c
, NULL
);
1670 if(prop_r
&& prop_r
->value_len
&& (data
= xcb_get_property_value(prop_r
)))
1671 lua_pushnumber(L
, *(uint32_t *)data
);
1678 case A_TK_LEADER_ID
:
1679 lua_pushnumber(L
, (*c
)->leader_win
);
1682 if(!xutil_text_prop_get(globalconf
.connection
, (*c
)->win
,
1683 WM_CLIENT_MACHINE
, &value
, &slen
))
1685 lua_pushlstring(L
, value
, slen
);
1688 case A_TK_ICON_NAME
:
1689 lua_pushstring(L
, (*c
)->icon_name
);
1692 lua_pushnumber(L
, 1 + (*c
)->screen
);
1695 lua_pushboolean(L
, (*c
)->ishidden
);
1698 luaA_deprecate(L
, "client.minimized");
1699 case A_TK_MINIMIZED
:
1700 lua_pushboolean(L
, (*c
)->isminimized
);
1702 case A_TK_FULLSCREEN
:
1703 lua_pushboolean(L
, (*c
)->isfullscreen
);
1707 lua_pushnumber(L
, (*c
)->group_win
);
1711 case A_TK_MAXIMIZED_HORIZONTAL
:
1712 lua_pushboolean(L
, (*c
)->ismaxhoriz
);
1714 case A_TK_MAXIMIZED_VERTICAL
:
1715 lua_pushboolean(L
, (*c
)->ismaxvert
);
1719 luaA_image_userdata_new(L
, (*c
)->icon
);
1724 if((d
= window_opacity_get((*c
)->win
)) >= 0)
1725 lua_pushnumber(L
, d
);
1730 lua_pushboolean(L
, (*c
)->isontop
);
1733 lua_pushboolean(L
, (*c
)->issticky
);
1735 case A_TK_HONORSIZEHINTS
:
1736 luaA_deprecate(L
, "size_hints_honor");
1737 case A_TK_SIZE_HINTS_HONOR
:
1738 lua_pushboolean(L
, (*c
)->size_hints_honor
);
1740 case A_TK_BORDER_WIDTH
:
1741 lua_pushnumber(L
, (*c
)->border
);
1743 case A_TK_BORDER_COLOR
:
1744 luaA_pushcolor(L
, &(*c
)->border_color
);
1748 return luaA_wibox_userdata_new(L
, (*c
)->titlebar
);
1751 lua_pushboolean(L
, (*c
)->isurgent
);
1753 case A_TK_SIZE_HINTS
:
1755 const char *u_or_p
= NULL
;
1759 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_US_POSITION
)
1760 u_or_p
= "user_position";
1761 else if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_POSITION
)
1762 u_or_p
= "program_position";
1767 lua_pushnumber(L
, (*c
)->size_hints
.x
);
1768 lua_setfield(L
, -2, "x");
1769 lua_pushnumber(L
, (*c
)->size_hints
.y
);
1770 lua_setfield(L
, -2, "y");
1771 lua_setfield(L
, -2, u_or_p
);
1775 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_US_SIZE
)
1776 u_or_p
= "user_size";
1777 else if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_SIZE
)
1778 u_or_p
= "program_size";
1783 lua_pushnumber(L
, (*c
)->size_hints
.width
);
1784 lua_setfield(L
, -2, "width");
1785 lua_pushnumber(L
, (*c
)->size_hints
.height
);
1786 lua_setfield(L
, -2, "height");
1787 lua_setfield(L
, -2, u_or_p
);
1790 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_MIN_SIZE
)
1792 lua_pushnumber(L
, (*c
)->size_hints
.min_width
);
1793 lua_setfield(L
, -2, "min_width");
1794 lua_pushnumber(L
, (*c
)->size_hints
.min_height
);
1795 lua_setfield(L
, -2, "min_height");
1798 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_MAX_SIZE
)
1800 lua_pushnumber(L
, (*c
)->size_hints
.max_width
);
1801 lua_setfield(L
, -2, "max_width");
1802 lua_pushnumber(L
, (*c
)->size_hints
.max_height
);
1803 lua_setfield(L
, -2, "max_height");
1806 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_RESIZE_INC
)
1808 lua_pushnumber(L
, (*c
)->size_hints
.width_inc
);
1809 lua_setfield(L
, -2, "width_inc");
1810 lua_pushnumber(L
, (*c
)->size_hints
.height_inc
);
1811 lua_setfield(L
, -2, "height_inc");
1814 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_ASPECT
)
1816 lua_pushnumber(L
, (*c
)->size_hints
.min_aspect_num
);
1817 lua_setfield(L
, -2, "min_aspect_num");
1818 lua_pushnumber(L
, (*c
)->size_hints
.min_aspect_den
);
1819 lua_setfield(L
, -2, "min_aspect_den");
1820 lua_pushnumber(L
, (*c
)->size_hints
.max_aspect_num
);
1821 lua_setfield(L
, -2, "max_aspect_num");
1822 lua_pushnumber(L
, (*c
)->size_hints
.max_aspect_den
);
1823 lua_setfield(L
, -2, "max_aspect_den");
1826 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_BASE_SIZE
)
1828 lua_pushnumber(L
, (*c
)->size_hints
.base_width
);
1829 lua_setfield(L
, -2, "base_width");
1830 lua_pushnumber(L
, (*c
)->size_hints
.base_height
);
1831 lua_setfield(L
, -2, "base_height");
1834 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_WIN_GRAVITY
)
1836 switch((*c
)->size_hints
.win_gravity
)
1839 lua_pushliteral(L
, "north_west");
1841 case XCB_GRAVITY_NORTH
:
1842 lua_pushliteral(L
, "north");
1844 case XCB_GRAVITY_NORTH_EAST
:
1845 lua_pushliteral(L
, "north_east");
1847 case XCB_GRAVITY_WEST
:
1848 lua_pushliteral(L
, "west");
1850 case XCB_GRAVITY_CENTER
:
1851 lua_pushliteral(L
, "center");
1853 case XCB_GRAVITY_EAST
:
1854 lua_pushliteral(L
, "east");
1856 case XCB_GRAVITY_SOUTH_WEST
:
1857 lua_pushliteral(L
, "south_west");
1859 case XCB_GRAVITY_SOUTH
:
1860 lua_pushliteral(L
, "south");
1862 case XCB_GRAVITY_SOUTH_EAST
:
1863 lua_pushliteral(L
, "south_east");
1865 case XCB_GRAVITY_STATIC
:
1866 lua_pushliteral(L
, "static");
1869 lua_setfield(L
, -2, "win_gravity");
1880 /** Get or set mouse buttons bindings for a client.
1881 * \param L The Lua VM state.
1882 * \return The number of element pushed on stack.
1885 * \lparam An array of mouse button bindings objects, or nothing.
1886 * \return The array of mouse button bindings objects of this client.
1889 luaA_client_buttons(lua_State
*L
)
1891 client_t
**client
= luaA_checkudata(L
, 1, "client");
1892 button_array_t
*buttons
= &(*client
)->buttons
;
1894 if(lua_gettop(L
) == 2)
1895 luaA_button_array_set(L
, 2, buttons
);
1897 return luaA_button_array_get(L
, buttons
);
1900 /** Get or set keys bindings for a client.
1901 * \param L The Lua VM state.
1902 * \return The number of element pushed on stack.
1905 * \lparam An array of key bindings objects, or nothing.
1906 * \return The array of key bindings objects of this client.
1909 luaA_client_keys(lua_State
*L
)
1911 client_t
**c
= luaA_checkudata(L
, 1, "client");
1912 keybindings_t
*keys
= &(*c
)->keys
;
1914 if(lua_gettop(L
) == 2)
1916 luaA_key_array_set(L
, 2, keys
);
1917 xcb_ungrab_key(globalconf
.connection
, XCB_GRAB_ANY
, (*c
)->win
, XCB_BUTTON_MASK_ANY
);
1918 window_grabkeys((*c
)->win
, keys
);
1921 return luaA_key_array_get(L
, keys
);
1924 /** Send fake events to a client.
1925 * \param L The Lua VM state.
1926 * \return The number of element pushed on stack.
1929 * \param The event type: key_press, key_release, button_press, button_release
1931 * \param The detail: in case of a key event, this is the keycode to send, in
1932 * case of a button event this is the number of the button. In case of a motion
1933 * event, this is a boolean value which if true make the coordinates relatives.
1934 * \param In case of a motion event, this is the X coordinate.
1935 * \param In case of a motion event, this is the Y coordinate.
1938 luaA_client_fake_input(lua_State
*L
)
1940 if(!globalconf
.have_xtest
)
1942 luaA_warn(L
, "XTest extension is not available, cannot fake input.");
1946 client_t
**c
= luaA_checkudata(L
, 1, "client");
1948 const char *stype
= luaL_checklstring(L
, 2, &tlen
);
1949 uint8_t type
, detail
;
1952 switch(a_tokenize(stype
, tlen
))
1954 case A_TK_KEY_PRESS
:
1955 type
= XCB_KEY_PRESS
;
1956 detail
= luaL_checknumber(L
, 3); /* keycode */
1958 case A_TK_KEY_RELEASE
:
1959 type
= XCB_KEY_RELEASE
;
1960 detail
= luaL_checknumber(L
, 3); /* keycode */
1962 case A_TK_BUTTON_PRESS
:
1963 type
= XCB_BUTTON_PRESS
;
1964 detail
= luaL_checknumber(L
, 3); /* button number */
1966 case A_TK_BUTTON_RELEASE
:
1967 type
= XCB_BUTTON_RELEASE
;
1968 detail
= luaL_checknumber(L
, 3); /* button number */
1970 case A_TK_MOTION_NOTIFY
:
1971 type
= XCB_MOTION_NOTIFY
;
1972 detail
= luaA_checkboolean(L
, 3); /* relative to the current position or not */
1973 x
= luaL_checknumber(L
, 4);
1974 y
= luaL_checknumber(L
, 5);
1980 xcb_test_fake_input(globalconf
.connection
,
1991 * \param L The Lua VM state.
1992 * \return The number of pushed elements.
1995 luaA_client_module_index(lua_State
*L
)
1998 const char *buf
= luaL_checklstring(L
, 2, &len
);
2000 switch(a_tokenize(buf
, len
))
2003 if(globalconf
.screen_focus
->client_focus
)
2004 luaA_client_userdata_new(L
, globalconf
.screen_focus
->client_focus
);
2015 /* Client module new index.
2016 * \param L The Lua VM state.
2017 * \return The number of pushed elements.
2020 luaA_client_module_newindex(lua_State
*L
)
2023 const char *buf
= luaL_checklstring(L
, 2, &len
);
2026 switch(a_tokenize(buf
, len
))
2029 c
= luaA_checkudata(L
, 3, "client");
2039 /** Move a client with mouse (DEPRECATED).
2040 * \param L The Lua VM state.
2043 luaA_client_mouse_move(lua_State
*L
)
2045 luaA_deprecate(L
, "awful.mouse.client.move()");
2049 /** Resize a client with mouse (DEPRECATED).
2050 * \param L The Lua VM state.
2051 * \return The number of pushed elements.
2054 luaA_client_mouse_resize(lua_State
*L
)
2056 luaA_deprecate(L
, "awful.mouse.client.resize()");
2060 const struct luaL_reg awesome_client_methods
[] =
2062 { "get", luaA_client_get
},
2063 { "__index", luaA_client_module_index
},
2064 { "__newindex", luaA_client_module_newindex
},
2067 const struct luaL_reg awesome_client_meta
[] =
2069 { "isvisible", luaA_client_isvisible
},
2070 { "geometry", luaA_client_geometry
},
2071 { "buttons", luaA_client_buttons
},
2072 { "keys", luaA_client_keys
},
2073 { "tags", luaA_client_tags
},
2074 { "kill", luaA_client_kill
},
2075 { "swap", luaA_client_swap
},
2076 { "raise", luaA_client_raise
},
2077 { "lower", luaA_client_lower
},
2078 { "redraw", luaA_client_redraw
},
2079 { "mouse_resize", luaA_client_mouse_resize
},
2080 { "mouse_move", luaA_client_mouse_move
},
2081 { "unmanage", luaA_client_unmanage
},
2082 { "fake_input", luaA_client_fake_input
},
2083 { "__index", luaA_client_index
},
2084 { "__newindex", luaA_client_newindex
},
2085 { "__eq", luaA_client_eq
},
2086 { "__gc", luaA_client_gc
},
2087 { "__tostring", luaA_client_tostring
},
2091 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80