Install .desktop files to correct filenames
[evilwm.git] / client.c
blob9e8b480ee923a86419f96d23ff81d974d52a8ebf
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 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).
31 long data[2];
32 data[0] = state;
33 data[1] = None;
34 XChangeProperty(dpy, c->window, xa_wm_state, xa_wm_state, 32,
35 PropModeReplace, (unsigned char *)data, 2);
38 void send_config(Client *c) {
39 XConfigureEvent ce;
41 ce.type = ConfigureNotify;
42 ce.event = c->window;
43 ce.window = c->window;
44 ce.x = c->x;
45 ce.y = c->y;
46 ce.width = c->width;
47 ce.height = c->height;
48 ce.border_width = 0;
49 ce.above = None;
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);
63 if (gravity == 0)
64 gravity = c->win_gravity_hint;
65 c->win_gravity = gravity;
66 switch (gravity) {
67 case NorthGravity:
68 c->x += d1;
69 c->y += d0;
70 break;
71 case NorthEastGravity:
72 c->x += d2;
73 c->y += d0;
74 break;
75 case EastGravity:
76 c->x += d2;
77 c->y += d1;
78 break;
79 case SouthEastGravity:
80 c->x += d2;
81 c->y += d2;
82 break;
83 case SouthGravity:
84 c->x += d1;
85 c->y += d2;
86 break;
87 case SouthWestGravity:
88 c->x += d0;
89 c->y += d2;
90 break;
91 case WestGravity:
92 c->x += d0;
93 c->y += d1;
94 break;
95 case NorthWestGravity:
96 default:
97 c->x += d0;
98 c->y += d0;
99 break;
103 void select_client(Client *c) {
104 if (current)
105 XSetWindowBorder(dpy, current->parent, current->screen->bg.pixel);
106 if (c) {
107 unsigned long bpixel;
108 #ifdef VWM
109 if (is_sticky(c))
110 bpixel = c->screen->fc.pixel;
111 else
112 #endif
113 bpixel = c->screen->fg.pixel;
114 XSetWindowBorder(dpy, c->parent, bpixel);
115 XInstallColormap(dpy, c->cmap);
116 XSetInputFocus(dpy, c->window, RevertToPointerRoot, CurrentTime);
118 current = c;
119 ewmh_set_net_active_window(c);
122 #ifdef VWM
123 void fix_client(Client *c, int action) {
124 switch (action) {
125 default:
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;
130 select_client(c);
131 ewmh_set_net_wm_state(c);
133 #endif
135 void remove_client(Client *c) {
136 LOG_ENTER("remove_client(window=%lx, %s)", c->window, c->remove ? "withdrawing" : "wm quitting");
138 XGrabServer(dpy);
139 ignore_xerror = 1;
141 /* ICCCM 4.1.3.1
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."
145 * EWMH 1.3
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
149 * _NET_WM_STATE) */
150 if (c->remove) {
151 LOG_DEBUG("setting WithdrawnState\n");
152 set_wm_state(c, WithdrawnState);
153 ewmh_withdraw_client(c);
154 } else {
155 ewmh_deinit_client(c);
158 ungravitate(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);
162 if (c->parent)
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: */
170 if (c->remove) {
171 ewmh_set_net_client_list(c->screen);
174 if (current == c)
175 current = NULL; /* an enter event should set this up again */
176 free(c);
177 #ifdef DEBUG
179 struct list *iter;
180 int i = 0;
181 for (iter = clients_tab_order; iter; iter = iter->next)
182 i++;
183 LOG_DEBUG("free(), window count now %d\n", i);
185 #endif
187 XUngrabServer(dpy);
188 XSync(dpy, False);
189 ignore_xerror = 0;
190 LOG_LEAVE();
193 void send_wm_delete(Client *c, int kill_client) {
194 int i, n, found = 0;
195 Atom *protocols;
197 if (!kill_client && XGetWMProtocols(dpy, c->window, &protocols, &n)) {
198 for (i = 0; i < n; i++)
199 if (protocols[i] == xa_wm_delete)
200 found++;
201 XFree(protocols);
203 if (found)
204 send_xmessage(c->window, xa_wm_protos, xa_wm_delete);
205 else
206 XKillClient(dpy, c->window);
209 static int send_xmessage(Window w, Atom a, long x) {
210 XEvent ev;
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);
222 #ifdef SHAPE
223 void set_shape(Client *c) {
224 int bounding_shaped;
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);
238 #endif