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
++)
72 tag_client(c
, tags
->tab
[i
]);
74 untag_client(c
, tags
->tab
[i
]);
79 /* check for fullscreen */
80 reply
= xcb_get_property_reply(globalconf
.connection
, fullscreen_q
, NULL
);
82 if(reply
&& reply
->value_len
&& (data
= xcb_get_property_value(reply
)))
83 client_setfullscreen(c
, *(bool *) data
);
89 /** Check if client supports protocol a protocole in WM_PROTOCOL.
90 * \param win The window.
91 * \return True if client has the atom in protocol, false otherwise.
94 window_hasproto(xcb_window_t win
, xcb_atom_t atom
)
97 xcb_get_wm_protocols_reply_t protocols
;
100 if(xcb_get_wm_protocols_reply(globalconf
.connection
,
101 xcb_get_wm_protocols_unchecked(globalconf
.connection
,
105 for(i
= 0; !ret
&& i
< protocols
.atoms_len
; i
++)
106 if(protocols
.atoms
[i
] == atom
)
108 xcb_get_wm_protocols_reply_wipe(&protocols
);
113 /** Returns true if a client is tagged
114 * with one of the tags of the specified screen.
115 * \param c The client to check.
116 * \param screen Virtual screen number.
117 * \return true if the client is visible, false otherwise.
120 client_maybevisible(client_t
*c
, int screen
)
122 if(c
->screen
== screen
)
124 if(c
->issticky
|| c
->type
== WINDOW_TYPE_DESKTOP
)
127 tag_array_t
*tags
= &globalconf
.screens
[screen
].tags
;
129 for(int i
= 0; i
< tags
->len
; i
++)
130 if(tags
->tab
[i
]->selected
&& is_client_tagged(c
, tags
->tab
[i
]))
136 /** Return the content of a client as an image.
137 * That's just take a screenshot.
138 * \param c The client.
142 client_getcontent(client_t
*c
)
144 xcb_image_t
*ximage
= xcb_image_get(globalconf
.connection
,
147 c
->geometries
.internal
.width
,
148 c
->geometries
.internal
.height
,
149 ~0, XCB_IMAGE_FORMAT_Z_PIXMAP
);
151 if(!ximage
|| ximage
->bpp
< 24)
154 uint32_t *data
= p_alloca(uint32_t, ximage
->width
* ximage
->height
);
156 for(int y
= 0; y
< ximage
->height
; y
++)
157 for(int x
= 0; x
< ximage
->width
; x
++)
159 data
[y
* ximage
->width
+ x
] = xcb_image_get_pixel(ximage
, x
, y
);
160 data
[y
* ximage
->width
+ x
] |= 0xff000000; /* set alpha to 0xff */
163 image_t
*image
= image_new_from_argb32(ximage
->width
, ximage
->height
, data
);
165 xcb_image_destroy(ximage
);
170 /** Get a client by its window.
171 * \param w The client window to find.
172 * \return A client pointer if found, NULL otherwise.
175 client_getbywin(xcb_window_t w
)
178 for(c
= globalconf
.clients
; c
&& c
->win
!= w
; c
= c
->next
);
182 /** Unfocus a client.
183 * \param c The client.
186 client_unfocus(client_t
*c
)
188 xcb_window_t root_win
= xutil_screen_get(globalconf
.connection
, c
->phys_screen
)->root
;
189 globalconf
.screens
[c
->phys_screen
].client_focus
= NULL
;
191 /* Set focus on root window, so no events leak to the current window. */
193 xcb_set_input_focus(globalconf
.connection
, XCB_INPUT_FOCUS_POINTER_ROOT
,
194 root_win
, XCB_CURRENT_TIME
);
197 if(globalconf
.hooks
.unfocus
!= LUA_REFNIL
)
199 luaA_client_userdata_new(globalconf
.L
, c
);
200 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.unfocus
, 1, 0);
203 ewmh_update_net_active_window(c
->phys_screen
);
206 /** Ban client and move it out of the viewport.
207 * \param c The client.
210 client_ban(client_t
*c
)
214 /* Move all clients out of the physical viewport into negative coordinate space. */
215 /* They will all be put on top of each other. */
216 uint32_t request
[2] = { - (c
->geometries
.internal
.width
+ 2 * c
->border
),
217 - (c
->geometries
.internal
.height
+ 2 * c
->border
) };
219 xcb_configure_window(globalconf
.connection
, c
->win
,
220 XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
,
223 titlebar_ban(c
->titlebar
);
227 /* All the wiboxes (may) need to be repositioned. */
228 if(client_hasstrut(c
))
229 wibox_update_positions();
232 /* Wait until the last moment to take away the focus from the window. */
233 if (globalconf
.screens
[c
->phys_screen
].client_focus
== c
)
237 /** Give focus to client, or to first client if client is NULL.
238 * \param c The client or NULL.
239 * \return True if a window (even root) has received focus, false otherwise.
242 client_focus(client_t
*c
)
244 if(!client_maybevisible(c
, c
->screen
))
247 /* unfocus current selected client */
248 if(globalconf
.screen_focus
->client_focus
249 && c
!= globalconf
.screen_focus
->client_focus
)
250 client_unfocus(globalconf
.screen_focus
->client_focus
);
254 client_setminimized(c
, false);
256 /* unban the client before focusing or it will fail */
259 globalconf
.screen_focus
= &globalconf
.screens
[c
->phys_screen
];
260 globalconf
.screen_focus
->client_focus
= c
;
263 xcb_set_input_focus(globalconf
.connection
, XCB_INPUT_FOCUS_POINTER_ROOT
,
264 c
->win
, XCB_CURRENT_TIME
);
266 /* Some layouts use focused client differently, so call them back.
267 * And anyway, we have maybe unhidden */
268 client_need_arrange(c
);
271 if(globalconf
.hooks
.focus
!= LUA_REFNIL
)
273 luaA_client_userdata_new(globalconf
.L
, globalconf
.screen_focus
->client_focus
);
274 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.focus
, 1, 0);
277 ewmh_update_net_active_window(c
->phys_screen
);
280 /** Stack a window below.
281 * \param c The client.
282 * \param previous The previous window on the stack.
283 * \param return The next-previous!
286 client_stack_above(client_t
*c
, xcb_window_t previous
)
288 uint32_t config_win_vals
[2];
290 config_win_vals
[0] = previous
;
291 config_win_vals
[1] = XCB_STACK_MODE_ABOVE
;
293 xcb_configure_window(globalconf
.connection
, c
->win
,
294 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
297 config_win_vals
[0] = c
->win
;
301 xcb_configure_window(globalconf
.connection
,
302 c
->titlebar
->sw
.window
,
303 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
305 previous
= c
->titlebar
->sw
.window
;
310 /* stack transient window on top of their parents */
311 for(client_node_t
*node
= *client_node_list_last(&globalconf
.stack
);
312 node
; node
= node
->prev
)
313 if(node
->client
->transient_for
== c
)
315 client_stack_above(node
->client
,
317 previous
= node
->client
->win
;
323 /** Stacking layout layers */
326 /** This one is a special layer */
337 /** Get the real layer of a client according to its attribute (fullscreen, …)
338 * \param c The client.
339 * \return The real layer.
342 client_layer_translator(client_t
*c
)
344 /* first deal with user set attributes */
347 else if(c
->isfullscreen
)
348 return LAYER_FULLSCREEN
;
354 /* check for transient attr */
358 /* then deal with windows type */
361 case WINDOW_TYPE_DOCK
:
363 case WINDOW_TYPE_DESKTOP
:
364 return LAYER_DESKTOP
;
365 case WINDOW_TYPE_DIALOG
:
366 case WINDOW_TYPE_MENU
:
367 case WINDOW_TYPE_TOOLBAR
:
368 case WINDOW_TYPE_UTILITY
:
378 * \todo It might be worth stopping to restack everyone and only stack `c'
379 * relatively to the first matching in the list.
384 uint32_t config_win_vals
[2];
385 client_node_t
*node
, *last
= *client_node_list_last(&globalconf
.stack
);
389 config_win_vals
[0] = XCB_NONE
;
390 config_win_vals
[1] = XCB_STACK_MODE_ABOVE
;
392 /* stack desktop windows */
393 for(layer
= LAYER_DESKTOP
; layer
< LAYER_BELOW
; layer
++)
394 for(node
= last
; node
; node
= node
->prev
)
395 if(client_layer_translator(node
->client
) == layer
)
396 config_win_vals
[0] = client_stack_above(node
->client
,
399 /* first stack not ontop wibox window */
400 for(screen
= 0; screen
< globalconf
.nscreen
; screen
++)
401 for(int i
= 0; i
< globalconf
.screens
[screen
].wiboxes
.len
; i
++)
403 wibox_t
*sb
= globalconf
.screens
[screen
].wiboxes
.tab
[i
];
406 xcb_configure_window(globalconf
.connection
,
408 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
410 config_win_vals
[0] = sb
->sw
.window
;
414 /* then stack clients */
415 for(layer
= LAYER_BELOW
; layer
< LAYER_OUTOFSPACE
; layer
++)
416 for(node
= last
; node
; node
= node
->prev
)
417 if(client_layer_translator(node
->client
) == layer
)
418 config_win_vals
[0] = client_stack_above(node
->client
,
421 /* then stack ontop wibox window */
422 for(screen
= 0; screen
< globalconf
.nscreen
; screen
++)
423 for(int i
= 0; i
< globalconf
.screens
[screen
].wiboxes
.len
; i
++)
425 wibox_t
*sb
= globalconf
.screens
[screen
].wiboxes
.tab
[i
];
428 xcb_configure_window(globalconf
.connection
,
430 XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE
,
432 config_win_vals
[0] = sb
->sw
.window
;
437 /** Manage a new client.
438 * \param w The window.
439 * \param wgeom Window geometry.
440 * \param phys_screen Physical screen number.
441 * \param startup True if we are managing at startup time.
444 client_manage(xcb_window_t w
, xcb_get_geometry_reply_t
*wgeom
, int phys_screen
, bool startup
)
446 xcb_get_property_cookie_t ewmh_icon_cookie
;
447 client_t
*c
, *tc
= NULL
;
450 const uint32_t select_input_val
[] =
452 XCB_EVENT_MASK_STRUCTURE_NOTIFY
453 | XCB_EVENT_MASK_PROPERTY_CHANGE
454 | XCB_EVENT_MASK_ENTER_WINDOW
455 | XCB_EVENT_MASK_LEAVE_WINDOW
459 if(systray_iskdedockapp(w
))
461 systray_request_handle(w
, phys_screen
, NULL
);
465 /* Send request to get NET_WM_ICON property as soon as possible... */
466 ewmh_icon_cookie
= ewmh_window_icon_get_unchecked(w
);
467 xcb_change_window_attributes(globalconf
.connection
, w
, XCB_CW_EVENT_MASK
, select_input_val
);
468 c
= p_new(client_t
, 1);
470 screen
= c
->screen
= screen_getbycoord(phys_screen
, wgeom
->x
, wgeom
->y
);
472 c
->phys_screen
= phys_screen
;
476 c
->geometry
.x
= wgeom
->x
;
477 c
->geometry
.y
= wgeom
->y
;
478 /* Border will be added later. */
479 c
->geometry
.width
= wgeom
->width
;
480 c
->geometry
.height
= wgeom
->height
;
481 /* Also set internal geometry (client_ban() needs it). */
482 c
->geometries
.internal
.x
= wgeom
->x
;
483 c
->geometries
.internal
.y
= wgeom
->y
;
484 c
->geometries
.internal
.width
= wgeom
->width
;
485 c
->geometries
.internal
.height
= wgeom
->height
;
486 client_setborder(c
, wgeom
->border_width
);
487 if((icon
= ewmh_window_icon_get_reply(ewmh_icon_cookie
)))
488 c
->icon
= image_ref(&icon
);
490 /* we honor size hints by default */
491 c
->size_hints_honor
= true;
494 property_update_wm_normal_hints(c
, NULL
);
495 property_update_wm_hints(c
, NULL
);
496 property_update_wm_transient_for(c
, NULL
);
497 property_update_wm_client_leader(c
, NULL
);
499 /* Recursively find the parent. */
500 for(tc
= c
; tc
->transient_for
; tc
= tc
->transient_for
);
501 if(tc
!= c
&& tc
->phys_screen
== c
->phys_screen
)
504 /* Try to load props */
505 client_loadprops(c
, &globalconf
.screens
[screen
]);
507 /* Then check clients hints */
508 ewmh_client_check_hints(c
);
510 /* move client to screen, but do not tag it */
511 screen_client_moveto(c
, screen
, false, true);
513 /* Push client in client list */
514 client_list_push(&globalconf
.clients
, client_ref(&c
));
516 /* Push client in stack */
519 /* update window title */
520 property_update_wm_name(c
);
521 property_update_wm_icon_name(c
);
524 ewmh_process_client_strut(c
, NULL
);
526 ewmh_update_net_client_list(c
->phys_screen
);
528 /* Always stay in NORMAL_STATE. Even though iconified seems more
529 * appropriate sometimes. The only possible loss is that clients not using
530 * visibility events may continue to proces data (when banned).
531 * Without any exposes or other events the cost should be fairly limited though.
533 * Some clients may expect the window to be unmapped when STATE_ICONIFIED.
534 * Two conflicting parts of the ICCCM v2.0 (section 4.1.4):
536 * "Normal -> Iconic - The client should send a ClientMessage event as described later in this section."
537 * (note no explicit mention of unmapping, while Normal->Widthdrawn does mention that)
539 * "Once a client's window has left the Withdrawn state, the window will be mapped
540 * if it is in the Normal state and the window will be unmapped if it is in the Iconic state."
542 * At this stage it's just safer to keep it in normal state and avoid confusion.
544 window_state_set(c
->win
, XCB_WM_STATE_NORMAL
);
546 /* Move window outside the viewport before mapping it. */
548 xcb_map_window(globalconf
.connection
, c
->win
);
550 /* Call hook to notify list change */
551 if(globalconf
.hooks
.clients
!= LUA_REFNIL
)
552 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.clients
, 0, 0);
555 if(globalconf
.hooks
.manage
!= LUA_REFNIL
)
557 luaA_client_userdata_new(globalconf
.L
, c
);
558 lua_pushboolean(globalconf
.L
, startup
);
559 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.manage
, 2, 0);
563 /** Compute client geometry with respect to its geometry hints.
564 * \param c The client.
565 * \param geometry The geometry that the client might receive.
566 * \return The geometry the client must take respecting its hints.
569 client_geometry_hints(client_t
*c
, area_t geometry
)
571 int32_t basew
, baseh
, minw
, minh
;
573 /* base size is substituted with min size if not specified */
574 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_SIZE
)
576 basew
= c
->size_hints
.base_width
;
577 baseh
= c
->size_hints
.base_height
;
579 else if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MIN_SIZE
)
581 basew
= c
->size_hints
.min_width
;
582 baseh
= c
->size_hints
.min_height
;
587 /* min size is substituted with base size if not specified */
588 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MIN_SIZE
)
590 minw
= c
->size_hints
.min_width
;
591 minh
= c
->size_hints
.min_height
;
593 else if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_SIZE
)
595 minw
= c
->size_hints
.base_width
;
596 minh
= c
->size_hints
.base_height
;
601 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_ASPECT
602 && c
->size_hints
.min_aspect_num
> 0
603 && c
->size_hints
.min_aspect_den
> 0
604 && geometry
.height
- baseh
> 0
605 && geometry
.width
- basew
> 0)
607 double dx
= (double) (geometry
.width
- basew
);
608 double dy
= (double) (geometry
.height
- baseh
);
609 double min
= (double) c
->size_hints
.min_aspect_num
/ (double) c
->size_hints
.min_aspect_den
;
610 double max
= (double) c
->size_hints
.max_aspect_num
/ (double) c
->size_hints
.min_aspect_den
;
611 double ratio
= dx
/ dy
;
612 if(max
> 0 && min
> 0 && ratio
> 0)
616 dy
= (dx
* min
+ dy
) / (min
* min
+ 1);
618 geometry
.width
= (int) dx
+ basew
;
619 geometry
.height
= (int) dy
+ baseh
;
623 dy
= (dx
* min
+ dy
) / (max
* max
+ 1);
625 geometry
.width
= (int) dx
+ basew
;
626 geometry
.height
= (int) dy
+ baseh
;
632 geometry
.width
= MAX(geometry
.width
, minw
);
634 geometry
.height
= MAX(geometry
.height
, minh
);
636 if(c
->size_hints
.flags
& XCB_SIZE_HINT_P_MAX_SIZE
)
638 if(c
->size_hints
.max_width
)
639 geometry
.width
= MIN(geometry
.width
, c
->size_hints
.max_width
);
640 if(c
->size_hints
.max_height
)
641 geometry
.height
= MIN(geometry
.height
, c
->size_hints
.max_height
);
644 if(c
->size_hints
.flags
& (XCB_SIZE_HINT_P_RESIZE_INC
| XCB_SIZE_HINT_BASE_SIZE
)
645 && c
->size_hints
.width_inc
&& c
->size_hints
.height_inc
)
647 uint16_t t1
= geometry
.width
, t2
= geometry
.height
;
648 unsigned_subtract(t1
, basew
);
649 unsigned_subtract(t2
, baseh
);
650 geometry
.width
-= t1
% c
->size_hints
.width_inc
;
651 geometry
.height
-= t2
% c
->size_hints
.height_inc
;
657 /** Resize client window.
658 * The sizse given as parameters are with titlebar and borders!
659 * \param c Client to resize.
660 * \param geometry New window geometry.
661 * \param hints Use size hints.
662 * \return true if an actual resize occurred.
665 client_resize(client_t
*c
, area_t geometry
, bool hints
)
668 area_t geometry_internal
;
671 /* offscreen appearance fixes */
672 area
= display_area_get(c
->phys_screen
, NULL
,
673 &globalconf
.screens
[c
->screen
].padding
);
675 if(geometry
.x
> area
.width
)
676 geometry
.x
= area
.width
- geometry
.width
;
677 if(geometry
.y
> area
.height
)
678 geometry
.y
= area
.height
- geometry
.height
;
679 if(geometry
.x
+ geometry
.width
< 0)
681 if(geometry
.y
+ geometry
.height
< 0)
684 /* Real client geometry, please keep it contained to C code at the very least. */
685 geometry_internal
= titlebar_geometry_remove(c
->titlebar
, c
->border
, geometry
);
688 geometry_internal
= client_geometry_hints(c
, geometry_internal
);
690 if(geometry_internal
.width
== 0 || geometry_internal
.height
== 0)
693 /* Also let client hints propegate to the "official" geometry. */
694 geometry
= titlebar_geometry_add(c
->titlebar
, c
->border
, geometry_internal
);
696 if(c
->geometries
.internal
.x
!= geometry_internal
.x
697 || c
->geometries
.internal
.y
!= geometry_internal
.y
698 || c
->geometries
.internal
.width
!= geometry_internal
.width
699 || c
->geometries
.internal
.height
!= geometry_internal
.height
)
701 new_screen
= screen_getbycoord(c
->screen
, geometry_internal
.x
, geometry_internal
.y
);
703 /* Values to configure a window is an array where values are
704 * stored according to 'value_mask' */
707 c
->geometries
.internal
.x
= values
[0] = geometry_internal
.x
;
708 c
->geometries
.internal
.y
= values
[1] = geometry_internal
.y
;
709 c
->geometries
.internal
.width
= values
[2] = geometry_internal
.width
;
710 c
->geometries
.internal
.height
= values
[3] = geometry_internal
.height
;
712 /* Also store geometry including border and titlebar. */
713 c
->geometry
= geometry
;
715 titlebar_update_geometry(c
);
717 /* The idea is to give a client a resize even when banned. */
718 /* We just have to move the (x,y) to keep it out of the viewport. */
719 /* This at least doesn't break expectations about events. */
722 geometry_internal
.x
= values
[0] = - (geometry_internal
.width
+ 2 * c
->border
);
723 geometry_internal
.y
= values
[1] = - (geometry_internal
.height
+ 2 * c
->border
);
726 xcb_configure_window(globalconf
.connection
, c
->win
,
727 XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
728 | XCB_CONFIG_WINDOW_WIDTH
| XCB_CONFIG_WINDOW_HEIGHT
,
730 window_configure(c
->win
, geometry_internal
, c
->border
);
732 screen_client_moveto(c
, new_screen
, true, false);
735 hooks_property(c
, "geometry");
743 /** Set a client minimized, or not.
744 * \param c The client.
745 * \param s Set or not the client minimized.
748 client_setminimized(client_t
*c
, bool s
)
750 if(c
->isminimized
!= s
)
752 client_need_arrange(c
);
754 client_need_arrange(c
);
755 ewmh_client_update_hints(c
);
757 hooks_property(c
, "minimized");
761 /** Set a client sticky, or not.
762 * \param c The client.
763 * \param s Set or not the client sticky.
766 client_setsticky(client_t
*c
, bool s
)
770 client_need_arrange(c
);
772 client_need_arrange(c
);
773 ewmh_client_update_hints(c
);
774 hooks_property(c
, "sticky");
778 /** Set a client fullscreen, or not.
779 * \param c The client.
780 * \param s Set or not the client fullscreen.
783 client_setfullscreen(client_t
*c
, bool s
)
785 if(c
->isfullscreen
!= s
)
789 /* become fullscreen! */
790 if((c
->isfullscreen
= s
))
792 /* remove any max state */
793 client_setmaxhoriz(c
, false);
794 client_setmaxvert(c
, false);
796 geometry
= screen_area_get(c
->screen
, NULL
, NULL
, false);
797 c
->geometries
.fullscreen
= c
->geometry
;
798 c
->border_fs
= c
->border
;
799 client_setborder(c
, 0);
803 geometry
= c
->geometries
.fullscreen
;
804 client_setborder(c
, c
->border_fs
);
806 client_resize(c
, geometry
, false);
807 client_need_arrange(c
);
809 xcb_change_property(globalconf
.connection
,
810 XCB_PROP_MODE_REPLACE
,
811 c
->win
, _AWESOME_FULLSCREEN
, CARDINAL
, 8, 1,
813 ewmh_client_update_hints(c
);
814 hooks_property(c
, "fullscreen");
818 /** Set a client horizontally maximized.
819 * \param c The client.
820 * \param s The maximized status.
823 client_setmaxhoriz(client_t
*c
, bool s
)
825 if(c
->ismaxhoriz
!= s
)
829 if((c
->ismaxhoriz
= s
))
831 /* remove fullscreen mode */
832 client_setfullscreen(c
, false);
834 geometry
= screen_area_get(c
->screen
,
835 &globalconf
.screens
[c
->screen
].wiboxes
,
836 &globalconf
.screens
[c
->screen
].padding
,
838 geometry
.y
= c
->geometry
.y
;
839 geometry
.height
= c
->geometry
.height
;
840 c
->geometries
.max
.x
= c
->geometry
.x
;
841 c
->geometries
.max
.width
= c
->geometry
.width
;
845 geometry
= c
->geometry
;
846 geometry
.x
= c
->geometries
.max
.x
;
847 geometry
.width
= c
->geometries
.max
.width
;
850 client_resize(c
, geometry
, c
->size_hints_honor
);
851 client_need_arrange(c
);
853 ewmh_client_update_hints(c
);
854 hooks_property(c
, "maximized_horizontal");
858 /** Set a client vertically maximized.
859 * \param c The client.
860 * \param s The maximized status.
863 client_setmaxvert(client_t
*c
, bool s
)
865 if(c
->ismaxvert
!= s
)
869 if((c
->ismaxvert
= s
))
871 /* remove fullscreen mode */
872 client_setfullscreen(c
, false);
874 geometry
= screen_area_get(c
->screen
,
875 &globalconf
.screens
[c
->screen
].wiboxes
,
876 &globalconf
.screens
[c
->screen
].padding
,
878 geometry
.x
= c
->geometry
.x
;
879 geometry
.width
= c
->geometry
.width
;
880 c
->geometries
.max
.y
= c
->geometry
.y
;
881 c
->geometries
.max
.height
= c
->geometry
.height
;
885 geometry
= c
->geometry
;
886 geometry
.y
= c
->geometries
.max
.y
;
887 geometry
.height
= c
->geometries
.max
.height
;
890 client_resize(c
, geometry
, c
->size_hints_honor
);
891 client_need_arrange(c
);
893 ewmh_client_update_hints(c
);
894 hooks_property(c
, "maximized_vertical");
898 /** Set a client above, or not.
899 * \param c The client.
900 * \param s Set or not the client above.
903 client_setabove(client_t
*c
, bool s
)
909 ewmh_client_update_hints(c
);
911 hooks_property(c
, "above");
915 /** Set a client below, or not.
916 * \param c The client.
917 * \param s Set or not the client below.
920 client_setbelow(client_t
*c
, bool s
)
926 ewmh_client_update_hints(c
);
928 hooks_property(c
, "below");
932 /** Set a client modal, or not.
933 * \param c The client.
934 * \param s Set or not the client moda.
937 client_setmodal(client_t
*c
, bool s
)
943 ewmh_client_update_hints(c
);
945 hooks_property(c
, "modal");
949 /** Set a client ontop, or not.
950 * \param c The client.
951 * \param s Set or not the client moda.
954 client_setontop(client_t
*c
, bool s
)
961 hooks_property(c
, "ontop");
965 /** Save client properties as an X property.
966 * \param c The client.
969 client_saveprops_tags(client_t
*c
)
971 tag_array_t
*tags
= &globalconf
.screens
[c
->screen
].tags
;
972 unsigned char *prop
= p_alloca(unsigned char, tags
->len
+ 1);
975 for(i
= 0; i
< tags
->len
; i
++)
976 prop
[i
] = is_client_tagged(c
, tags
->tab
[i
]) ? '1' : '0';
978 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
, c
->win
, _AWESOME_TAGS
, STRING
, 8, i
, prop
);
981 /** Unban a client and move it back into the viewport.
982 * \param c The client.
985 client_unban(client_t
*c
)
989 /* Move the client back where it belongs. */
990 uint32_t request
[] = { c
->geometries
.internal
.x
,
991 c
->geometries
.internal
.y
,
992 c
->geometries
.internal
.width
,
993 c
->geometries
.internal
.height
};
995 xcb_configure_window(globalconf
.connection
, c
->win
,
997 | XCB_CONFIG_WINDOW_Y
998 | XCB_CONFIG_WINDOW_WIDTH
999 | XCB_CONFIG_WINDOW_HEIGHT
,
1001 window_configure(c
->win
, c
->geometries
.internal
, c
->border
);
1003 /* Do this manually because the system doesn't know we moved the toolbar.
1004 * Note that !isvisible titlebars are unmapped and for fullscreen it'll
1005 * end up offscreen anyway. */
1008 simple_window_t
*sw
= &c
->titlebar
->sw
;
1009 /* All resizing is done, so only move now. */
1010 request
[0] = sw
->geometry
.x
;
1011 request
[1] = sw
->geometry
.y
;
1013 xcb_configure_window(globalconf
.connection
, sw
->window
,
1014 XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
,
1018 c
->isbanned
= false;
1020 /* All the wiboxes (may) need to be repositioned. */
1021 if(client_hasstrut(c
))
1022 wibox_update_positions();
1026 /** Unmanage a client.
1027 * \param c The client.
1030 client_unmanage(client_t
*c
)
1032 tag_array_t
*tags
= &globalconf
.screens
[c
->screen
].tags
;
1034 /* Reset transient_for attributes of widows that maybe refering to us */
1035 for(client_t
*tc
= globalconf
.clients
; tc
; tc
= tc
->next
)
1036 if(tc
->transient_for
== c
)
1037 tc
->transient_for
= NULL
;
1039 if(globalconf
.screens
[c
->phys_screen
].client_focus
== c
)
1042 /* remove client everywhere */
1043 client_list_detach(&globalconf
.clients
, c
);
1044 stack_client_delete(c
);
1045 for(int i
= 0; i
< tags
->len
; i
++)
1046 untag_client(c
, tags
->tab
[i
]);
1049 if(globalconf
.hooks
.unmanage
!= LUA_REFNIL
)
1051 luaA_client_userdata_new(globalconf
.L
, c
);
1052 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.unmanage
, 1, 0);
1055 /* Call hook to notify list change */
1056 if(globalconf
.hooks
.clients
!= LUA_REFNIL
)
1057 luaA_dofunction(globalconf
.L
, globalconf
.hooks
.clients
, 0, 0);
1059 /* The server grab construct avoids race conditions. */
1060 xcb_grab_server(globalconf
.connection
);
1062 xcb_ungrab_button(globalconf
.connection
, XCB_BUTTON_INDEX_ANY
, c
->win
,
1063 XCB_BUTTON_MASK_ANY
);
1064 window_state_set(c
->win
, XCB_WM_STATE_WITHDRAWN
);
1066 xcb_flush(globalconf
.connection
);
1067 xcb_ungrab_server(globalconf
.connection
);
1069 titlebar_client_detach(c
);
1071 ewmh_update_net_client_list(c
->phys_screen
);
1073 /* delete properties */
1074 xcb_delete_property(globalconf
.connection
, c
->win
, _AWESOME_TAGS
);
1075 xcb_delete_property(globalconf
.connection
, c
->win
, _AWESOME_FLOATING
);
1077 /* All the wiboxes (may) need to be repositioned. */
1078 if(client_hasstrut(c
))
1079 wibox_update_positions();
1081 /* set client as invalid */
1087 /** Kill a client via a WM_DELETE_WINDOW request or KillClient if not
1089 * \param c The client to kill.
1092 client_kill(client_t
*c
)
1094 if(window_hasproto(c
->win
, WM_DELETE_WINDOW
))
1096 xcb_client_message_event_t ev
;
1098 /* Initialize all of event's fields first */
1101 ev
.response_type
= XCB_CLIENT_MESSAGE
;
1104 ev
.data
.data32
[1] = XCB_CURRENT_TIME
;
1105 ev
.type
= WM_PROTOCOLS
;
1106 ev
.data
.data32
[0] = WM_DELETE_WINDOW
;
1108 xcb_send_event(globalconf
.connection
, false, c
->win
,
1109 XCB_EVENT_MASK_NO_EVENT
, (char *) &ev
);
1112 xcb_kill_client(globalconf
.connection
, c
->win
);
1115 /** Get all clients into a table.
1116 * \param L The Lua VM state.
1117 * \return The number of elements pushed on stack.
1119 * \lparam An optional screen nunmber.
1120 * \lreturn A table with all clients.
1123 luaA_client_get(lua_State
*L
)
1128 screen
= luaL_optnumber(L
, 1, 0) - 1;
1132 if(screen
== SCREEN_UNDEF
)
1133 for(c
= globalconf
.clients
; c
; c
= c
->next
)
1135 luaA_client_userdata_new(globalconf
.L
, c
);
1136 lua_rawseti(L
, -2, i
++);
1140 luaA_checkscreen(screen
);
1141 for(c
= globalconf
.clients
; c
; c
= c
->next
)
1142 if(c
->screen
== screen
)
1144 luaA_client_userdata_new(globalconf
.L
, c
);
1145 lua_rawseti(L
, -2, i
++);
1152 /** Check if a client is visible on its screen.
1153 * \param L The Lua VM state.
1154 * \return The number of elements pushed on stack.
1157 * \lreturn A boolean value, true if the client is visible, false otherwise.
1160 luaA_client_isvisible(lua_State
*L
)
1162 client_t
**c
= luaA_checkudata(L
, 1, "client");
1163 lua_pushboolean(L
, client_isvisible(*c
, (*c
)->screen
));
1167 /** Set client border width.
1168 * \param c The client.
1169 * \param width The border width.
1172 client_setborder(client_t
*c
, int width
)
1176 if(width
> 0 && (c
->type
== WINDOW_TYPE_DOCK
1177 || c
->type
== WINDOW_TYPE_SPLASH
1178 || c
->type
== WINDOW_TYPE_DESKTOP
1179 || c
->isfullscreen
))
1182 if(width
== c
->border
|| width
< 0)
1185 /* Update geometry with the new border. */
1186 c
->geometry
.width
-= c
->border
;
1187 c
->geometry
.height
-= c
->border
;
1190 xcb_configure_window(globalconf
.connection
, c
->win
,
1191 XCB_CONFIG_WINDOW_BORDER_WIDTH
, &w
);
1193 c
->geometry
.width
+= c
->border
;
1194 c
->geometry
.height
+= c
->border
;
1195 /* Tiled clients will be resized by the layout functions. */
1196 client_need_arrange(c
);
1198 /* Changing border size also affects the size of the titlebar. */
1200 titlebar_update_geometry(c
);
1202 hooks_property(c
, "border_width");
1206 * \param L The Lua VM state.
1212 luaA_client_kill(lua_State
*L
)
1214 client_t
**c
= luaA_checkudata(L
, 1, "client");
1219 /** Swap a client with another one.
1220 * \param L The Lua VM state.
1223 * \lparam A client to swap with.
1226 luaA_client_swap(lua_State
*L
)
1228 client_t
**c
= luaA_checkudata(L
, 1, "client");
1229 client_t
**swap
= luaA_checkudata(L
, 2, "client");
1233 client_list_swap(&globalconf
.clients
, *swap
, *c
);
1234 client_need_arrange(*c
);
1235 client_need_arrange(*swap
);
1237 /* Call hook to notify list change */
1238 if(globalconf
.hooks
.clients
!= LUA_REFNIL
)
1239 luaA_dofunction(L
, globalconf
.hooks
.clients
, 0, 0);
1245 /** Access or set the client tags.
1246 * \param L The Lua VM state.
1247 * \return The number of elements pushed on stack.
1248 * \lparam A table with tags to set, or none to get the current tags table.
1249 * \return The clients tag.
1252 luaA_client_tags(lua_State
*L
)
1256 client_t
**c
= luaA_checkudata(L
, 1, "client");
1259 if(lua_gettop(L
) == 2)
1261 luaA_checktable(L
, 2);
1262 tags
= &globalconf
.screens
[(*c
)->screen
].tags
;
1263 for(int i
= 0; i
< tags
->len
; i
++)
1264 untag_client(*c
, tags
->tab
[i
]);
1266 while(lua_next(L
, 2))
1268 tag
= luaA_checkudata(L
, -1, "tag");
1269 tag_client(*c
, *tag
);
1275 tags
= &globalconf
.screens
[(*c
)->screen
].tags
;
1277 for(int i
= 0; i
< tags
->len
; i
++)
1278 if(is_client_tagged(*c
, tags
->tab
[i
]))
1280 luaA_tag_userdata_new(L
, tags
->tab
[i
]);
1281 lua_rawseti(L
, -2, ++j
);
1287 /** Raise a client on top of others which are on the same layer.
1288 * \param L The Lua VM state.
1293 luaA_client_raise(lua_State
*L
)
1295 client_t
**c
= luaA_checkudata(L
, 1, "client");
1300 /** Lower a client on bottom of others which are on the same layer.
1301 * \param L The Lua VM state.
1306 luaA_client_lower(lua_State
*L
)
1308 client_t
**c
= luaA_checkudata(L
, 1, "client");
1313 /** Redraw a client by unmapping and mapping it quickly.
1314 * \param L The Lua VM state.
1320 luaA_client_redraw(lua_State
*L
)
1322 client_t
**c
= luaA_checkudata(L
, 1, "client");
1324 xcb_unmap_window(globalconf
.connection
, (*c
)->win
);
1325 xcb_map_window(globalconf
.connection
, (*c
)->win
);
1327 /* Set the focus on the current window if the redraw has been
1328 performed on the window where the pointer is currently on
1329 because after the unmapping/mapping, the focus is lost */
1330 if(globalconf
.screen_focus
->client_focus
== *c
)
1331 xcb_set_input_focus(globalconf
.connection
, XCB_INPUT_FOCUS_POINTER_ROOT
,
1332 (*c
)->win
, XCB_CURRENT_TIME
);
1337 /** Stop managing a client.
1338 * \param L The Lua VM state.
1339 * \return The number of elements pushed on stack.
1344 luaA_client_unmanage(lua_State
*L
)
1346 client_t
**c
= luaA_checkudata(L
, 1, "client");
1347 client_unmanage(*c
);
1351 /** Return client geometry.
1352 * \param L The Lua VM state.
1353 * \return The number of elements pushed on stack.
1355 * \lparam A table with new coordinates, or none.
1356 * \lreturn A table with client coordinates.
1359 luaA_client_geometry(lua_State
*L
)
1361 client_t
**c
= luaA_checkudata(L
, 1, "client");
1363 if(lua_gettop(L
) == 2)
1367 luaA_checktable(L
, 2);
1368 geometry
.x
= luaA_getopt_number(L
, 2, "x", (*c
)->geometry
.x
);
1369 geometry
.y
= luaA_getopt_number(L
, 2, "y", (*c
)->geometry
.y
);
1370 if(client_isfixed(*c
))
1372 geometry
.width
= (*c
)->geometry
.width
;
1373 geometry
.height
= (*c
)->geometry
.height
;
1377 geometry
.width
= luaA_getopt_number(L
, 2, "width", (*c
)->geometry
.width
);
1378 geometry
.height
= luaA_getopt_number(L
, 2, "height", (*c
)->geometry
.height
);
1381 client_resize(*c
, geometry
, (*c
)->size_hints_honor
);
1384 return luaA_pusharea(L
, (*c
)->geometry
);
1387 /** Push a strut type to a table on stack.
1388 * \param L The Lua VM state.
1389 * \param struts The struts to push.
1390 * \return The number of elements pushed on stack.
1393 luaA_pushstruts(lua_State
*L
, strut_t struts
)
1396 lua_pushnumber(L
, struts
.left
);
1397 lua_setfield(L
, -2, "left");
1398 lua_pushnumber(L
, struts
.right
);
1399 lua_setfield(L
, -2, "right");
1400 lua_pushnumber(L
, struts
.top
);
1401 lua_setfield(L
, -2, "top");
1402 lua_pushnumber(L
, struts
.bottom
);
1403 lua_setfield(L
, -2, "bottom");
1407 /** Return client struts (reserved space at the edge of the screen).
1408 * \param L The Lua VM state.
1409 * \return The number of elements pushed on stack.
1411 * \lparam A table with new strut values, or none.
1412 * \lreturn A table with strut values.
1415 luaA_client_struts(lua_State
*L
)
1417 client_t
**c
= luaA_checkudata(L
, 1, "client");
1419 if(lua_gettop(L
) == 2)
1422 area_t screen_area
= display_area_get((*c
)->phys_screen
, NULL
, NULL
);
1424 struts
.left
= luaA_getopt_number(L
, 2, "left", (*c
)->strut
.left
);
1425 struts
.right
= luaA_getopt_number(L
, 2, "right", (*c
)->strut
.right
);
1426 struts
.top
= luaA_getopt_number(L
, 2, "top", (*c
)->strut
.top
);
1427 struts
.bottom
= luaA_getopt_number(L
, 2, "bottom", (*c
)->strut
.bottom
);
1429 if (struts
.left
!= (*c
)->strut
.left
|| struts
.right
!= (*c
)->strut
.right
||
1430 struts
.top
!= (*c
)->strut
.top
|| struts
.bottom
!= (*c
)->strut
.bottom
) {
1431 /* Struts are not so well defined in the context of xinerama. So we just
1432 * give the entire root window and let the window manager decide. */
1433 struts
.left_start_y
= 0;
1434 struts
.left_end_y
= !struts
.left
? 0 : screen_area
.height
;
1435 struts
.right_start_y
= 0;
1436 struts
.right_end_y
= !struts
.right
? 0 : screen_area
.height
;
1437 struts
.top_start_x
= 0;
1438 struts
.top_end_x
= !struts
.top
? 0 : screen_area
.width
;
1439 struts
.bottom_start_x
= 0;
1440 struts
.bottom_end_x
= !struts
.bottom
? 0 : screen_area
.width
;
1442 (*c
)->strut
= struts
;
1444 ewmh_update_client_strut((*c
));
1446 client_need_arrange((*c
));
1447 /* All the wiboxes (may) need to be repositioned. */
1448 wibox_update_positions();
1452 return luaA_pushstruts(L
, (*c
)->strut
);
1455 /** Client newindex.
1456 * \param L The Lua VM state.
1457 * \return The number of elements pushed on stack.
1460 luaA_client_newindex(lua_State
*L
)
1463 client_t
**c
= luaA_checkudata(L
, 1, "client");
1464 const char *buf
= luaL_checklstring(L
, 2, &len
);
1472 luaL_error(L
, "client is invalid\n");
1474 switch(a_tokenize(buf
, len
))
1477 if(globalconf
.xinerama_is_active
)
1479 i
= luaL_checknumber(L
, 3) - 1;
1480 luaA_checkscreen(i
);
1481 screen_client_moveto(*c
, i
, true, true);
1485 b
= luaA_checkboolean(L
, 3);
1486 if(b
!= (*c
)->ishidden
)
1488 client_need_arrange(*c
);
1490 client_need_arrange(*c
);
1494 luaA_deprecate(L
, "client.minimized");
1495 case A_TK_MINIMIZED
:
1496 client_setminimized(*c
, luaA_checkboolean(L
, 3));
1498 case A_TK_FULLSCREEN
:
1499 client_setfullscreen(*c
, luaA_checkboolean(L
, 3));
1501 case A_TK_MAXIMIZED_HORIZONTAL
:
1502 client_setmaxhoriz(*c
, luaA_checkboolean(L
, 3));
1504 case A_TK_MAXIMIZED_VERTICAL
:
1505 client_setmaxvert(*c
, luaA_checkboolean(L
, 3));
1508 image
= luaA_checkudata(L
, 3, "image");
1509 image_unref(&(*c
)->icon
);
1511 (*c
)->icon
= *image
;
1513 hooks_property(*c
, "icon");
1517 window_opacity_set((*c
)->win
, -1);
1520 d
= luaL_checknumber(L
, 3);
1521 if(d
>= 0 && d
<= 1)
1522 window_opacity_set((*c
)->win
, d
);
1526 client_setsticky(*c
, luaA_checkboolean(L
, 3));
1528 case A_TK_HONORSIZEHINTS
:
1529 luaA_deprecate(L
, "size_hints_honor");
1530 case A_TK_SIZE_HINTS_HONOR
:
1531 (*c
)->size_hints_honor
= luaA_checkboolean(L
, 3);
1532 client_need_arrange(*c
);
1534 case A_TK_BORDER_WIDTH
:
1535 client_setborder(*c
, luaL_checknumber(L
, 3));
1538 client_setontop(*c
, luaA_checkboolean(L
, 3));
1540 case A_TK_BORDER_COLOR
:
1541 if((buf
= luaL_checklstring(L
, 3, &len
))
1542 && xcolor_init_reply(xcolor_init_unchecked(&(*c
)->border_color
, buf
, len
)))
1543 xcb_change_window_attributes(globalconf
.connection
, (*c
)->win
,
1544 XCB_CW_BORDER_PIXEL
, &(*c
)->border_color
.pixel
);
1548 titlebar_client_detach(*c
);
1551 t
= luaA_checkudata(L
, 3, "wibox");
1552 titlebar_client_attach(*c
, *t
);
1563 * \param L The Lua VM state.
1564 * \return The number of elements pushed on stack.
1566 * \lfield name The client title.
1567 * \lfield skip_taskbar True if the client does not want to be in taskbar.
1568 * \lfield type The window type (desktop, normal, dock, …).
1569 * \lfield class The client class.
1570 * \lfield instance The client instance.
1571 * \lfield pid The client PID, if available.
1572 * \lfield role The window role, if available.
1573 * \lfield machine The machine client is running on.
1574 * \lfield icon_name The client name when iconified.
1575 * \lfield screen Client screen number.
1576 * \lfield hide Define if the client must be hidden, i.e. never mapped,
1577 * invisible in taskbar.
1578 * \lfield minimize Define it the client must be iconify, i.e. only visible in
1580 * \lfield icon_path Path to the icon used to identify.
1581 * \lfield size_hints_honor Honor size hints, i.e. respect size ratio.
1582 * \lfield border_width The client border width.
1583 * \lfield border_color The client border color.
1584 * \lfield titlebar The client titlebar.
1585 * \lfield urgent The client urgent state.
1586 * \lfield content An image representing the client window content (screenshot).
1587 * \lfield focus The focused client.
1588 * \lfield opacity The client opacity between 0 and 1.
1589 * \lfield ontop The client is on top of every other windows.
1590 * \lfield fullscreen The client is fullscreen or not.
1591 * \lfield maximized_horizontal The client is maximized horizontally or not.
1592 * \lfield maximized_vertical The client is maximized vertically or not.
1593 * \lfield transient_for Return the client the window is transient for.
1594 * \lfield group_id Identification unique to a group of windows.
1595 * \lfield leader_id Identification unique to windows spawned by the same command.
1596 * \lfield size_hints A table with size hints of the client: user_position,
1597 * user_size, program_position, program_size, etc.
1600 luaA_client_index(lua_State
*L
)
1604 client_t
**c
= luaA_checkudata(L
, 1, "client");
1605 const char *buf
= luaL_checklstring(L
, 2, &len
);
1608 xcb_get_wm_class_reply_t hint
;
1609 xcb_get_property_cookie_t prop_c
;
1610 xcb_get_property_reply_t
*prop_r
= NULL
;
1614 luaL_error(L
, "client is invalid\n");
1616 if(luaA_usemetatable(L
, 1, 2))
1619 switch(a_tokenize(buf
, len
))
1624 lua_pushstring(L
, (*c
)->name
);
1626 case A_TK_TRANSIENT_FOR
:
1627 if((*c
)->transient_for
)
1628 return luaA_client_userdata_new(L
, (*c
)->transient_for
);
1630 case A_TK_SKIP_TASKBAR
:
1631 lua_pushboolean(L
, (*c
)->skiptb
);
1634 if((image
= client_getcontent(*c
)))
1635 return luaA_image_userdata_new(L
, image
);
1640 case WINDOW_TYPE_DESKTOP
:
1641 lua_pushliteral(L
, "desktop");
1643 case WINDOW_TYPE_DOCK
:
1644 lua_pushliteral(L
, "dock");
1646 case WINDOW_TYPE_SPLASH
:
1647 lua_pushliteral(L
, "splash");
1649 case WINDOW_TYPE_DIALOG
:
1650 lua_pushliteral(L
, "dialog");
1652 case WINDOW_TYPE_MENU
:
1653 lua_pushliteral(L
, "menu");
1655 case WINDOW_TYPE_TOOLBAR
:
1656 lua_pushliteral(L
, "toolbar");
1658 case WINDOW_TYPE_UTILITY
:
1659 lua_pushliteral(L
, "utility");
1662 lua_pushliteral(L
, "normal");
1667 if(!xcb_get_wm_class_reply(globalconf
.connection
,
1668 xcb_get_wm_class_unchecked(globalconf
.connection
, (*c
)->win
),
1671 lua_pushstring(L
, hint
.class_name
);
1672 xcb_get_wm_class_reply_wipe(&hint
);
1675 if(!xcb_get_wm_class_reply(globalconf
.connection
,
1676 xcb_get_wm_class_unchecked(globalconf
.connection
, (*c
)->win
),
1679 lua_pushstring(L
, hint
.instance_name
);
1680 xcb_get_wm_class_reply_wipe(&hint
);
1683 if(!xutil_text_prop_get(globalconf
.connection
, (*c
)->win
,
1684 WM_WINDOW_ROLE
, &value
, &slen
))
1686 lua_pushlstring(L
, value
, slen
);
1690 prop_c
= xcb_get_property_unchecked(globalconf
.connection
, false, (*c
)->win
, _NET_WM_PID
, CARDINAL
, 0L, 1L);
1691 prop_r
= xcb_get_property_reply(globalconf
.connection
, prop_c
, NULL
);
1693 if(prop_r
&& prop_r
->value_len
&& (data
= xcb_get_property_value(prop_r
)))
1694 lua_pushnumber(L
, *(uint32_t *)data
);
1701 case A_TK_LEADER_ID
:
1702 lua_pushnumber(L
, (*c
)->leader_win
);
1705 if(!xutil_text_prop_get(globalconf
.connection
, (*c
)->win
,
1706 WM_CLIENT_MACHINE
, &value
, &slen
))
1708 lua_pushlstring(L
, value
, slen
);
1711 case A_TK_ICON_NAME
:
1712 lua_pushstring(L
, (*c
)->icon_name
);
1715 lua_pushnumber(L
, 1 + (*c
)->screen
);
1718 lua_pushboolean(L
, (*c
)->ishidden
);
1721 luaA_deprecate(L
, "client.minimized");
1722 case A_TK_MINIMIZED
:
1723 lua_pushboolean(L
, (*c
)->isminimized
);
1725 case A_TK_FULLSCREEN
:
1726 lua_pushboolean(L
, (*c
)->isfullscreen
);
1730 lua_pushnumber(L
, (*c
)->group_win
);
1734 case A_TK_MAXIMIZED_HORIZONTAL
:
1735 lua_pushboolean(L
, (*c
)->ismaxhoriz
);
1737 case A_TK_MAXIMIZED_VERTICAL
:
1738 lua_pushboolean(L
, (*c
)->ismaxvert
);
1742 luaA_image_userdata_new(L
, (*c
)->icon
);
1747 if((d
= window_opacity_get((*c
)->win
)) >= 0)
1748 lua_pushnumber(L
, d
);
1753 lua_pushboolean(L
, (*c
)->isontop
);
1756 lua_pushboolean(L
, (*c
)->issticky
);
1758 case A_TK_HONORSIZEHINTS
:
1759 luaA_deprecate(L
, "size_hints_honor");
1760 case A_TK_SIZE_HINTS_HONOR
:
1761 lua_pushboolean(L
, (*c
)->size_hints_honor
);
1763 case A_TK_BORDER_WIDTH
:
1764 lua_pushnumber(L
, (*c
)->border
);
1766 case A_TK_BORDER_COLOR
:
1767 luaA_pushcolor(L
, &(*c
)->border_color
);
1771 return luaA_wibox_userdata_new(L
, (*c
)->titlebar
);
1774 lua_pushboolean(L
, (*c
)->isurgent
);
1776 case A_TK_SIZE_HINTS
:
1778 const char *u_or_p
= NULL
;
1782 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_US_POSITION
)
1783 u_or_p
= "user_position";
1784 else if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_POSITION
)
1785 u_or_p
= "program_position";
1790 lua_pushnumber(L
, (*c
)->size_hints
.x
);
1791 lua_setfield(L
, -2, "x");
1792 lua_pushnumber(L
, (*c
)->size_hints
.y
);
1793 lua_setfield(L
, -2, "y");
1794 lua_setfield(L
, -2, u_or_p
);
1798 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_US_SIZE
)
1799 u_or_p
= "user_size";
1800 else if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_SIZE
)
1801 u_or_p
= "program_size";
1806 lua_pushnumber(L
, (*c
)->size_hints
.width
);
1807 lua_setfield(L
, -2, "width");
1808 lua_pushnumber(L
, (*c
)->size_hints
.height
);
1809 lua_setfield(L
, -2, "height");
1810 lua_setfield(L
, -2, u_or_p
);
1813 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_MIN_SIZE
)
1815 lua_pushnumber(L
, (*c
)->size_hints
.min_width
);
1816 lua_setfield(L
, -2, "min_width");
1817 lua_pushnumber(L
, (*c
)->size_hints
.min_height
);
1818 lua_setfield(L
, -2, "min_height");
1821 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_MAX_SIZE
)
1823 lua_pushnumber(L
, (*c
)->size_hints
.max_width
);
1824 lua_setfield(L
, -2, "max_width");
1825 lua_pushnumber(L
, (*c
)->size_hints
.max_height
);
1826 lua_setfield(L
, -2, "max_height");
1829 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_RESIZE_INC
)
1831 lua_pushnumber(L
, (*c
)->size_hints
.width_inc
);
1832 lua_setfield(L
, -2, "width_inc");
1833 lua_pushnumber(L
, (*c
)->size_hints
.height_inc
);
1834 lua_setfield(L
, -2, "height_inc");
1837 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_ASPECT
)
1839 lua_pushnumber(L
, (*c
)->size_hints
.min_aspect_num
);
1840 lua_setfield(L
, -2, "min_aspect_num");
1841 lua_pushnumber(L
, (*c
)->size_hints
.min_aspect_den
);
1842 lua_setfield(L
, -2, "min_aspect_den");
1843 lua_pushnumber(L
, (*c
)->size_hints
.max_aspect_num
);
1844 lua_setfield(L
, -2, "max_aspect_num");
1845 lua_pushnumber(L
, (*c
)->size_hints
.max_aspect_den
);
1846 lua_setfield(L
, -2, "max_aspect_den");
1849 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_BASE_SIZE
)
1851 lua_pushnumber(L
, (*c
)->size_hints
.base_width
);
1852 lua_setfield(L
, -2, "base_width");
1853 lua_pushnumber(L
, (*c
)->size_hints
.base_height
);
1854 lua_setfield(L
, -2, "base_height");
1857 if((*c
)->size_hints
.flags
& XCB_SIZE_HINT_P_WIN_GRAVITY
)
1859 switch((*c
)->size_hints
.win_gravity
)
1862 lua_pushliteral(L
, "north_west");
1864 case XCB_GRAVITY_NORTH
:
1865 lua_pushliteral(L
, "north");
1867 case XCB_GRAVITY_NORTH_EAST
:
1868 lua_pushliteral(L
, "north_east");
1870 case XCB_GRAVITY_WEST
:
1871 lua_pushliteral(L
, "west");
1873 case XCB_GRAVITY_CENTER
:
1874 lua_pushliteral(L
, "center");
1876 case XCB_GRAVITY_EAST
:
1877 lua_pushliteral(L
, "east");
1879 case XCB_GRAVITY_SOUTH_WEST
:
1880 lua_pushliteral(L
, "south_west");
1882 case XCB_GRAVITY_SOUTH
:
1883 lua_pushliteral(L
, "south");
1885 case XCB_GRAVITY_SOUTH_EAST
:
1886 lua_pushliteral(L
, "south_east");
1888 case XCB_GRAVITY_STATIC
:
1889 lua_pushliteral(L
, "static");
1892 lua_setfield(L
, -2, "win_gravity");
1903 /** Get or set mouse buttons bindings for a client.
1904 * \param L The Lua VM state.
1905 * \return The number of element pushed on stack.
1908 * \lparam An array of mouse button bindings objects, or nothing.
1909 * \return The array of mouse button bindings objects of this client.
1912 luaA_client_buttons(lua_State
*L
)
1914 client_t
**client
= luaA_checkudata(L
, 1, "client");
1915 button_array_t
*buttons
= &(*client
)->buttons
;
1917 if(lua_gettop(L
) == 2)
1918 luaA_button_array_set(L
, 2, buttons
);
1920 return luaA_button_array_get(L
, buttons
);
1923 /** Get or set keys bindings for a client.
1924 * \param L The Lua VM state.
1925 * \return The number of element pushed on stack.
1928 * \lparam An array of key bindings objects, or nothing.
1929 * \return The array of key bindings objects of this client.
1932 luaA_client_keys(lua_State
*L
)
1934 client_t
**c
= luaA_checkudata(L
, 1, "client");
1935 keybindings_t
*keys
= &(*c
)->keys
;
1937 if(lua_gettop(L
) == 2)
1939 luaA_key_array_set(L
, 2, keys
);
1940 xcb_ungrab_key(globalconf
.connection
, XCB_GRAB_ANY
, (*c
)->win
, XCB_BUTTON_MASK_ANY
);
1941 window_grabkeys((*c
)->win
, keys
);
1944 return luaA_key_array_get(L
, keys
);
1947 /** Send fake events to a client.
1948 * \param L The Lua VM state.
1949 * \return The number of element pushed on stack.
1952 * \param The event type: key_press, key_release, button_press, button_release
1954 * \param The detail: in case of a key event, this is the keycode to send, in
1955 * case of a button event this is the number of the button. In case of a motion
1956 * event, this is a boolean value which if true make the coordinates relatives.
1957 * \param In case of a motion event, this is the X coordinate.
1958 * \param In case of a motion event, this is the Y coordinate.
1961 luaA_client_fake_input(lua_State
*L
)
1963 if(!globalconf
.have_xtest
)
1965 luaA_warn(L
, "XTest extension is not available, cannot fake input.");
1969 client_t
**c
= luaA_checkudata(L
, 1, "client");
1971 const char *stype
= luaL_checklstring(L
, 2, &tlen
);
1972 uint8_t type
, detail
;
1975 switch(a_tokenize(stype
, tlen
))
1977 case A_TK_KEY_PRESS
:
1978 type
= XCB_KEY_PRESS
;
1979 detail
= luaL_checknumber(L
, 3); /* keycode */
1981 case A_TK_KEY_RELEASE
:
1982 type
= XCB_KEY_RELEASE
;
1983 detail
= luaL_checknumber(L
, 3); /* keycode */
1985 case A_TK_BUTTON_PRESS
:
1986 type
= XCB_BUTTON_PRESS
;
1987 detail
= luaL_checknumber(L
, 3); /* button number */
1989 case A_TK_BUTTON_RELEASE
:
1990 type
= XCB_BUTTON_RELEASE
;
1991 detail
= luaL_checknumber(L
, 3); /* button number */
1993 case A_TK_MOTION_NOTIFY
:
1994 type
= XCB_MOTION_NOTIFY
;
1995 detail
= luaA_checkboolean(L
, 3); /* relative to the current position or not */
1996 x
= luaL_checknumber(L
, 4);
1997 y
= luaL_checknumber(L
, 5);
2003 xcb_test_fake_input(globalconf
.connection
,
2014 * \param L The Lua VM state.
2015 * \return The number of pushed elements.
2018 luaA_client_module_index(lua_State
*L
)
2021 const char *buf
= luaL_checklstring(L
, 2, &len
);
2023 switch(a_tokenize(buf
, len
))
2026 if(globalconf
.screen_focus
->client_focus
)
2027 luaA_client_userdata_new(L
, globalconf
.screen_focus
->client_focus
);
2038 /* Client module new index.
2039 * \param L The Lua VM state.
2040 * \return The number of pushed elements.
2043 luaA_client_module_newindex(lua_State
*L
)
2046 const char *buf
= luaL_checklstring(L
, 2, &len
);
2049 switch(a_tokenize(buf
, len
))
2052 c
= luaA_checkudata(L
, 3, "client");
2062 /** Move a client with mouse (DEPRECATED).
2063 * \param L The Lua VM state.
2066 luaA_client_mouse_move(lua_State
*L
)
2068 luaA_deprecate(L
, "awful.mouse.client.move()");
2072 /** Resize a client with mouse (DEPRECATED).
2073 * \param L The Lua VM state.
2074 * \return The number of pushed elements.
2077 luaA_client_mouse_resize(lua_State
*L
)
2079 luaA_deprecate(L
, "awful.mouse.client.resize()");
2083 const struct luaL_reg awesome_client_methods
[] =
2085 { "get", luaA_client_get
},
2086 { "__index", luaA_client_module_index
},
2087 { "__newindex", luaA_client_module_newindex
},
2090 const struct luaL_reg awesome_client_meta
[] =
2092 { "isvisible", luaA_client_isvisible
},
2093 { "geometry", luaA_client_geometry
},
2094 { "struts", luaA_client_struts
},
2095 { "buttons", luaA_client_buttons
},
2096 { "keys", luaA_client_keys
},
2097 { "tags", luaA_client_tags
},
2098 { "kill", luaA_client_kill
},
2099 { "swap", luaA_client_swap
},
2100 { "raise", luaA_client_raise
},
2101 { "lower", luaA_client_lower
},
2102 { "redraw", luaA_client_redraw
},
2103 { "mouse_resize", luaA_client_mouse_resize
},
2104 { "mouse_move", luaA_client_mouse_move
},
2105 { "unmanage", luaA_client_unmanage
},
2106 { "fake_input", luaA_client_fake_input
},
2107 { "__index", luaA_client_index
},
2108 { "__newindex", luaA_client_newindex
},
2109 { "__eq", luaA_client_eq
},
2110 { "__gc", luaA_client_gc
},
2111 { "__tostring", luaA_client_tostring
},
2115 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80