1 /* evilwm - Minimalist Window Manager for X
2 * Copyright (C) 1999-2009 Ciaran Anscomb <evilwm@6809.org.uk>
3 * see README for license and other details. */
10 static int send_xmessage(Window w
, Atom a
, long x
);
12 /* used all over the place. return the client that has specified window as
13 * either window or parent */
15 Client
*find_client(Window w
) {
18 for (iter
= clients_tab_order
; iter
; iter
= iter
->next
) {
19 Client
*c
= iter
->data
;
20 if (w
== c
->parent
|| w
== c
->window
)
26 void client_hide(Client
*c
) {
27 c
->ignore_unmap
++; /* Ignore unmap so we don't remove client */
28 XUnmapWindow(dpy
, c
->parent
);
29 set_wm_state(c
, IconicState
);
32 void client_show(Client
*c
) {
33 XMapWindow(dpy
, c
->parent
);
34 set_wm_state(c
, NormalState
);
37 void client_raise(Client
*c
) {
38 XRaiseWindow(dpy
, c
->parent
);
39 clients_stacking_order
= list_to_tail(clients_stacking_order
, c
);
40 ewmh_set_net_client_list_stacking(c
->screen
);
43 void client_lower(Client
*c
) {
44 XLowerWindow(dpy
, c
->parent
);
45 clients_stacking_order
= list_to_head(clients_stacking_order
, c
);
46 ewmh_set_net_client_list_stacking(c
->screen
);
49 void set_wm_state(Client
*c
, int state
) {
50 /* Using "long" for the type of "data" looks wrong, but the
51 * fine people in the X Consortium defined it this way
52 * (even on 64-bit machines).
57 XChangeProperty(dpy
, c
->window
, xa_wm_state
, xa_wm_state
, 32,
58 PropModeReplace
, (unsigned char *)data
, 2);
61 void send_config(Client
*c
) {
64 ce
.type
= ConfigureNotify
;
66 ce
.window
= c
->window
;
70 ce
.height
= c
->height
;
73 ce
.override_redirect
= False
;
75 XSendEvent(dpy
, c
->window
, False
, StructureNotifyMask
, (XEvent
*)&ce
);
78 /* Support for 'gravitating' clients based on their original border width and
79 * configured window manager frame width. If the 'gravity' arg is non-zero,
80 * the win_gravity hint read when the client was initialised is used. Set sign
81 * = 1 to gravitate or sign = -1 to reverse the process. */
82 void gravitate_client(Client
*c
, int sign
, int gravity
) {
83 int d0
= sign
* c
->border
;
84 int d1
= sign
* c
->old_border
;
85 int d2
= sign
* (2*c
->old_border
- c
->border
);
87 gravity
= c
->win_gravity_hint
;
88 c
->win_gravity
= gravity
;
94 case NorthEastGravity
:
102 case SouthEastGravity
:
110 case SouthWestGravity
:
118 case NorthWestGravity
:
126 void select_client(Client
*c
) {
128 XSetWindowBorder(dpy
, current
->parent
, current
->screen
->bg
.pixel
);
130 unsigned long bpixel
;
133 bpixel
= c
->screen
->fc
.pixel
;
136 bpixel
= c
->screen
->fg
.pixel
;
137 XSetWindowBorder(dpy
, c
->parent
, bpixel
);
138 XInstallColormap(dpy
, c
->cmap
);
139 XSetInputFocus(dpy
, c
->window
, RevertToPointerRoot
, CurrentTime
);
142 ewmh_set_net_active_window(c
);
146 void client_to_vdesk(Client
*c
, unsigned int vdesk
) {
147 if (valid_vdesk(vdesk
)) {
149 if (c
->vdesk
== c
->screen
->vdesk
|| c
->vdesk
== VDESK_FIXED
) {
154 ewmh_set_net_wm_desktop(c
);
155 select_client(current
);
160 void remove_client(Client
*c
) {
161 LOG_ENTER("remove_client(window=%lx, %s)", c
->window
, c
->remove
? "withdrawing" : "wm quitting");
167 * "When the window is withdrawn, the window manager will either
168 * change the state field's value to WithdrawnState or it will
169 * remove the WM_STATE property entirely."
171 * "The Window Manager should remove the property whenever a
172 * window is withdrawn but it should leave the property in
173 * place when it is shutting down." (both _NET_WM_DESKTOP and
176 LOG_DEBUG("setting WithdrawnState\n");
177 set_wm_state(c
, WithdrawnState
);
178 ewmh_withdraw_client(c
);
180 ewmh_deinit_client(c
);
184 XReparentWindow(dpy
, c
->window
, c
->screen
->root
, c
->x
, c
->y
);
185 XSetWindowBorderWidth(dpy
, c
->window
, c
->old_border
);
186 XRemoveFromSaveSet(dpy
, c
->window
);
188 XDestroyWindow(dpy
, c
->parent
);
190 clients_tab_order
= list_delete(clients_tab_order
, c
);
191 clients_mapping_order
= list_delete(clients_mapping_order
, c
);
192 clients_stacking_order
= list_delete(clients_stacking_order
, c
);
193 /* If the wm is quitting, we'll remove the client list properties
194 * soon enough, otherwise: */
196 ewmh_set_net_client_list(c
->screen
);
200 current
= NULL
; /* an enter event should set this up again */
206 for (iter
= clients_tab_order
; iter
; iter
= iter
->next
)
208 LOG_DEBUG("free(), window count now %d\n", i
);
218 void send_wm_delete(Client
*c
, int kill_client
) {
222 if (!kill_client
&& XGetWMProtocols(dpy
, c
->window
, &protocols
, &n
)) {
223 for (i
= 0; i
< n
; i
++)
224 if (protocols
[i
] == xa_wm_delete
)
229 send_xmessage(c
->window
, xa_wm_protos
, xa_wm_delete
);
231 XKillClient(dpy
, c
->window
);
234 static int send_xmessage(Window w
, Atom a
, long x
) {
237 ev
.type
= ClientMessage
;
238 ev
.xclient
.window
= w
;
239 ev
.xclient
.message_type
= a
;
240 ev
.xclient
.format
= 32;
241 ev
.xclient
.data
.l
[0] = x
;
242 ev
.xclient
.data
.l
[1] = CurrentTime
;
244 return XSendEvent(dpy
, w
, False
, NoEventMask
, &ev
);
248 void set_shape(Client
*c
) {
250 int i
, b
; unsigned int u
; /* dummies */
252 if (!have_shape
) return;
253 /* Logic to decide if we have a shaped window cribbed from fvwm-2.5.10.
254 * Previous method (more than one rectangle returned from
255 * XShapeGetRectangles) worked _most_ of the time. */
256 if (XShapeQueryExtents(dpy
, c
->window
, &bounding_shaped
, &i
, &i
,
257 &u
, &u
, &b
, &i
, &i
, &u
, &u
) && bounding_shaped
) {
258 LOG_DEBUG("%d shape extents\n", bounding_shaped
);
259 XShapeCombineShape(dpy
, c
->parent
, ShapeBounding
, 0, 0,
260 c
->window
, ShapeBounding
, ShapeSet
);