git: initial import (.gitignore)
[evilwm.git] / client.c
blobc3705746c23c2030c2057aa77450bcbb895fec7e
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. */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include "evilwm.h"
8 #include "log.h"
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) {
16 struct list *iter;
18 for (iter = clients_tab_order; iter; iter = iter->next) {
19 Client *c = iter->data;
20 if (w == c->parent || w == c->window)
21 return c;
23 return NULL;
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).
54 long data[2];
55 data[0] = state;
56 data[1] = None;
57 XChangeProperty(dpy, c->window, xa_wm_state, xa_wm_state, 32,
58 PropModeReplace, (unsigned char *)data, 2);
61 void send_config(Client *c) {
62 XConfigureEvent ce;
64 ce.type = ConfigureNotify;
65 ce.event = c->window;
66 ce.window = c->window;
67 ce.x = c->x;
68 ce.y = c->y;
69 ce.width = c->width;
70 ce.height = c->height;
71 ce.border_width = 0;
72 ce.above = None;
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);
86 if (gravity == 0)
87 gravity = c->win_gravity_hint;
88 c->win_gravity = gravity;
89 switch (gravity) {
90 case NorthGravity:
91 c->x += d1;
92 c->y += d0;
93 break;
94 case NorthEastGravity:
95 c->x += d2;
96 c->y += d0;
97 break;
98 case EastGravity:
99 c->x += d2;
100 c->y += d1;
101 break;
102 case SouthEastGravity:
103 c->x += d2;
104 c->y += d2;
105 break;
106 case SouthGravity:
107 c->x += d1;
108 c->y += d2;
109 break;
110 case SouthWestGravity:
111 c->x += d0;
112 c->y += d2;
113 break;
114 case WestGravity:
115 c->x += d0;
116 c->y += d1;
117 break;
118 case NorthWestGravity:
119 default:
120 c->x += d0;
121 c->y += d0;
122 break;
126 void select_client(Client *c) {
127 if (current)
128 XSetWindowBorder(dpy, current->parent, current->screen->bg.pixel);
129 if (c) {
130 unsigned long bpixel;
131 #ifdef VWM
132 if (is_fixed(c))
133 bpixel = c->screen->fc.pixel;
134 else
135 #endif
136 bpixel = c->screen->fg.pixel;
137 XSetWindowBorder(dpy, c->parent, bpixel);
138 XInstallColormap(dpy, c->cmap);
139 XSetInputFocus(dpy, c->window, RevertToPointerRoot, CurrentTime);
141 current = c;
142 ewmh_set_net_active_window(c);
145 #ifdef VWM
146 void client_to_vdesk(Client *c, unsigned int vdesk) {
147 if (valid_vdesk(vdesk)) {
148 c->vdesk = vdesk;
149 if (c->vdesk == c->screen->vdesk || c->vdesk == VDESK_FIXED) {
150 client_show(c);
151 } else {
152 client_hide(c);
154 ewmh_set_net_wm_desktop(c);
155 select_client(current);
158 #endif
160 void remove_client(Client *c) {
161 LOG_ENTER("remove_client(window=%lx, %s)", c->window, c->remove ? "withdrawing" : "wm quitting");
163 XGrabServer(dpy);
164 ignore_xerror = 1;
166 /* ICCCM 4.1.3.1
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."
170 * EWMH 1.3
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
174 * _NET_WM_STATE) */
175 if (c->remove) {
176 LOG_DEBUG("setting WithdrawnState\n");
177 set_wm_state(c, WithdrawnState);
178 ewmh_withdraw_client(c);
179 } else {
180 ewmh_deinit_client(c);
183 ungravitate(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);
187 if (c->parent)
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: */
195 if (c->remove) {
196 ewmh_set_net_client_list(c->screen);
199 if (current == c)
200 current = NULL; /* an enter event should set this up again */
201 free(c);
202 #ifdef DEBUG
204 struct list *iter;
205 int i = 0;
206 for (iter = clients_tab_order; iter; iter = iter->next)
207 i++;
208 LOG_DEBUG("free(), window count now %d\n", i);
210 #endif
212 XUngrabServer(dpy);
213 XSync(dpy, False);
214 ignore_xerror = 0;
215 LOG_LEAVE();
218 void send_wm_delete(Client *c, int kill_client) {
219 int i, n, found = 0;
220 Atom *protocols;
222 if (!kill_client && XGetWMProtocols(dpy, c->window, &protocols, &n)) {
223 for (i = 0; i < n; i++)
224 if (protocols[i] == xa_wm_delete)
225 found++;
226 XFree(protocols);
228 if (found)
229 send_xmessage(c->window, xa_wm_protos, xa_wm_delete);
230 else
231 XKillClient(dpy, c->window);
234 static int send_xmessage(Window w, Atom a, long x) {
235 XEvent ev;
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);
247 #ifdef SHAPE
248 void set_shape(Client *c) {
249 int bounding_shaped;
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);
263 #endif