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 set_wm_state(Client
*c
, int state
) {
27 /* Using "long" for the type of "data" looks wrong, but the
28 * fine people in the X Consortium defined it this way
29 * (even on 64-bit machines).
34 XChangeProperty(dpy
, c
->window
, xa_wm_state
, xa_wm_state
, 32,
35 PropModeReplace
, (unsigned char *)data
, 2);
38 void send_config(Client
*c
) {
41 ce
.type
= ConfigureNotify
;
43 ce
.window
= c
->window
;
47 ce
.height
= c
->height
;
50 ce
.override_redirect
= False
;
52 XSendEvent(dpy
, c
->window
, False
, StructureNotifyMask
, (XEvent
*)&ce
);
55 /* Support for 'gravitating' clients based on their original border width and
56 * configured window manager frame width. If the 'gravity' arg is non-zero,
57 * the win_gravity hint read when the client was initialised is used. Set sign
58 * = 1 to gravitate or sign = -1 to reverse the process. */
59 void gravitate_client(Client
*c
, int sign
, int gravity
) {
60 int d0
= sign
* c
->border
;
61 int d1
= sign
* c
->old_border
;
62 int d2
= sign
* (2*c
->old_border
- c
->border
);
64 gravity
= c
->win_gravity_hint
;
65 c
->win_gravity
= gravity
;
71 case NorthEastGravity
:
79 case SouthEastGravity
:
87 case SouthWestGravity
:
95 case NorthWestGravity
:
103 void select_client(Client
*c
) {
105 XSetWindowBorder(dpy
, current
->parent
, current
->screen
->bg
.pixel
);
107 unsigned long bpixel
;
110 bpixel
= c
->screen
->fc
.pixel
;
113 bpixel
= c
->screen
->fg
.pixel
;
114 XSetWindowBorder(dpy
, c
->parent
, bpixel
);
115 XInstallColormap(dpy
, c
->cmap
);
116 XSetInputFocus(dpy
, c
->window
, RevertToPointerRoot
, CurrentTime
);
119 ewmh_set_net_active_window(c
);
123 void fix_client(Client
*c
, int action
) {
126 case NET_WM_STATE_REMOVE
: remove_sticky(c
); break;
127 case NET_WM_STATE_ADD
: add_sticky(c
); break;
128 case NET_WM_STATE_TOGGLE
: toggle_sticky(c
); break;
131 ewmh_set_net_wm_state(c
);
135 void remove_client(Client
*c
) {
136 LOG_ENTER("remove_client(window=%lx, %s)", c
->window
, c
->remove
? "withdrawing" : "wm quitting");
142 * "When the window is withdrawn, the window manager will either
143 * change the state field's value to WithdrawnState or it will
144 * remove the WM_STATE property entirely."
146 * "The Window Manager should remove the property whenever a
147 * window is withdrawn but it should leave the property in
148 * place when it is shutting down." (both _NET_WM_DESKTOP and
151 LOG_DEBUG("setting WithdrawnState\n");
152 set_wm_state(c
, WithdrawnState
);
153 ewmh_withdraw_client(c
);
155 ewmh_deinit_client(c
);
159 XReparentWindow(dpy
, c
->window
, c
->screen
->root
, c
->x
, c
->y
);
160 XSetWindowBorderWidth(dpy
, c
->window
, c
->old_border
);
161 XRemoveFromSaveSet(dpy
, c
->window
);
163 XDestroyWindow(dpy
, c
->parent
);
165 clients_tab_order
= list_delete(clients_tab_order
, c
);
166 clients_mapping_order
= list_delete(clients_mapping_order
, c
);
167 clients_stacking_order
= list_delete(clients_stacking_order
, c
);
168 /* If the wm is quitting, we'll remove the client list properties
169 * soon enough, otherwise: */
171 ewmh_set_net_client_list(c
->screen
);
175 current
= NULL
; /* an enter event should set this up again */
181 for (iter
= clients_tab_order
; iter
; iter
= iter
->next
)
183 LOG_DEBUG("free(), window count now %d\n", i
);
193 void send_wm_delete(Client
*c
, int kill_client
) {
197 if (!kill_client
&& XGetWMProtocols(dpy
, c
->window
, &protocols
, &n
)) {
198 for (i
= 0; i
< n
; i
++)
199 if (protocols
[i
] == xa_wm_delete
)
204 send_xmessage(c
->window
, xa_wm_protos
, xa_wm_delete
);
206 XKillClient(dpy
, c
->window
);
209 static int send_xmessage(Window w
, Atom a
, long x
) {
212 ev
.type
= ClientMessage
;
213 ev
.xclient
.window
= w
;
214 ev
.xclient
.message_type
= a
;
215 ev
.xclient
.format
= 32;
216 ev
.xclient
.data
.l
[0] = x
;
217 ev
.xclient
.data
.l
[1] = CurrentTime
;
219 return XSendEvent(dpy
, w
, False
, NoEventMask
, &ev
);
223 void set_shape(Client
*c
) {
225 int i
, b
; unsigned int u
; /* dummies */
227 if (!have_shape
) return;
228 /* Logic to decide if we have a shaped window cribbed from fvwm-2.5.10.
229 * Previous method (more than one rectangle returned from
230 * XShapeGetRectangles) worked _most_ of the time. */
231 if (XShapeQueryExtents(dpy
, c
->window
, &bounding_shaped
, &i
, &i
,
232 &u
, &u
, &b
, &i
, &i
, &u
, &u
) && bounding_shaped
) {
233 LOG_DEBUG("%d shape extents\n", bounding_shaped
);
234 XShapeCombineShape(dpy
, c
->parent
, ShapeBounding
, 0, 0,
235 c
->window
, ShapeBounding
, ShapeSet
);