aewl

view client.c @ 30:2e0fb4130bfb

new stuff, fixed several issues
author Anselm R. Garbe <garbeam@wmii.de>
date Wed, 12 Jul 2006 17:50:31 +0200
parents 8ad86d0a6a53
children 386649deb651
line source
1 /*
2 * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
3 * See LICENSE file for license details.
4 */
6 #include <math.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <X11/Xatom.h>
11 #include "util.h"
12 #include "wm.h"
14 void
15 max(void *aux)
16 {
17 if(!stack)
18 return;
19 stack->x = sx;
20 stack->y = bh;
21 stack->w = sw - 2 * stack->border;
22 stack->h = sh - bh - 2 * stack->border;
23 resize(stack);
24 discard_events(EnterWindowMask);
25 }
27 void
28 arrange(void *aux)
29 {
30 Client *c;
31 int n, cols, rows, gw, gh, i, j;
32 float rt, fd;
34 if(!clients)
35 return;
36 for(n = 0, c = clients; c; c = c->next, n++);
37 rt = sqrt(n);
38 if(modff(rt, &fd) < 0.5)
39 rows = floor(rt);
40 else
41 rows = ceil(rt);
42 if(rows * rows < n)
43 cols = rows + 1;
44 else
45 cols = rows;
47 gw = (sw - 2) / cols;
48 gh = (sh - bh - 2) / rows;
50 for(i = j = 0, c = clients; c; c = c->next) {
51 c->x = i * gw;
52 c->y = j * gh + bh;
53 c->w = gw;
54 c->h = gh;
55 resize(c);
56 if(++i == cols) {
57 j++;
58 i = 0;
59 }
60 }
61 discard_events(EnterWindowMask);
62 }
64 void
65 sel(void *aux)
66 {
67 const char *arg = aux;
68 Client *c = NULL;
70 if(!arg || !stack)
71 return;
72 if(!strncmp(arg, "next", 5))
73 c = stack->snext ? stack->snext : stack;
74 else if(!strncmp(arg, "prev", 5))
75 for(c = stack; c && c->snext; c = c->snext);
76 if(!c)
77 c = stack;
78 raise(c);
79 focus(c);
80 }
82 void
83 kill(void *aux)
84 {
85 Client *c = stack;
87 if(!c)
88 return;
89 if(c->proto & WM_PROTOCOL_DELWIN)
90 send_message(c->win, wm_atom[WMProtocols], wm_atom[WMDelete]);
91 else
92 XKillClient(dpy, c->win);
93 }
95 static void
96 resize_title(Client *c)
97 {
98 c->tw = textw(&brush.font, c->name) + bh;
99 if(c->tw > c->w)
100 c->tw = c->w + 2;
101 c->tx = c->x + c->w - c->tw + 2;
102 c->ty = c->y;
103 XMoveResizeWindow(dpy, c->title, c->tx, c->ty, c->tw, c->th);
104 }
106 void
107 update_name(Client *c)
108 {
109 XTextProperty name;
110 int n;
111 char **list = NULL;
113 name.nitems = 0;
114 c->name[0] = 0;
115 XGetTextProperty(dpy, c->win, &name, net_atom[NetWMName]);
116 if(!name.nitems)
117 XGetWMName(dpy, c->win, &name);
118 if(!name.nitems)
119 return;
120 if(name.encoding == XA_STRING)
121 strncpy(c->name, (char *)name.value, sizeof(c->name));
122 else {
123 if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
124 && n > 0 && *list)
125 {
126 strncpy(c->name, *list, sizeof(c->name));
127 XFreeStringList(list);
128 }
129 }
130 XFree(name.value);
131 resize_title(c);
132 }
134 void
135 update_size(Client *c)
136 {
137 XSizeHints size;
138 long msize;
139 if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
140 size.flags = PSize;
141 c->flags = size.flags;
142 if(c->flags & PBaseSize) {
143 c->basew = size.base_width;
144 c->baseh = size.base_height;
145 }
146 else
147 c->basew = c->baseh = 0;
148 if(c->flags & PResizeInc) {
149 c->incw = size.width_inc;
150 c->inch = size.height_inc;
151 }
152 else
153 c->incw = c->inch = 0;
154 if(c->flags & PMaxSize) {
155 c->maxw = size.max_width;
156 c->maxh = size.max_height;
157 }
158 else
159 c->maxw = c->maxh = 0;
160 if(c->flags & PMinSize) {
161 c->minw = size.min_width;
162 c->minh = size.min_height;
163 }
164 else
165 c->minw = c->minh = 0;
166 if(c->flags & PWinGravity)
167 c->grav = size.win_gravity;
168 else
169 c->grav = NorthWestGravity;
170 }
172 void
173 raise(Client *c)
174 {
175 XRaiseWindow(dpy, c->win);
176 XRaiseWindow(dpy, c->title);
177 }
179 void
180 lower(Client *c)
181 {
182 XLowerWindow(dpy, c->title);
183 XLowerWindow(dpy, c->win);
184 }
186 void
187 focus(Client *c)
188 {
189 Client **l, *old;
191 old = stack;
192 for(l = &stack; *l && *l != c; l = &(*l)->snext);
193 eassert(*l == c);
194 *l = c->snext;
195 c->snext = stack;
196 stack = c;
197 if(old && old != c) {
198 XMapWindow(dpy, old->title);
199 draw_client(old);
200 }
201 XUnmapWindow(dpy, c->title);
202 draw_client(c);
203 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
204 XFlush(dpy);
205 }
207 void
208 manage(Window w, XWindowAttributes *wa)
209 {
210 Client *c, **l;
211 XSetWindowAttributes twa;
213 c = emallocz(sizeof(Client));
214 c->win = w;
215 c->tx = c->x = wa->x;
216 c->ty = c->y = wa->y;
217 if(c->y < bh)
218 c->ty = c->y += bh;
219 c->tw = c->w = wa->width;
220 c->h = wa->height;
221 c->th = bh;
222 c->border = 1;
223 update_size(c);
224 XSetWindowBorderWidth(dpy, c->win, 1);
225 XSetWindowBorder(dpy, c->win, brush.border);
226 XSelectInput(dpy, c->win,
227 StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
228 XGetTransientForHint(dpy, c->win, &c->trans);
229 twa.override_redirect = 1;
230 twa.background_pixmap = ParentRelative;
231 twa.event_mask = ExposureMask;
233 c->title = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
234 0, DefaultDepth(dpy, screen), CopyFromParent,
235 DefaultVisual(dpy, screen),
236 CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
237 update_name(c);
239 for(l=&clients; *l; l=&(*l)->next);
240 c->next = *l; /* *l == nil */
241 *l = c;
242 c->snext = stack;
243 stack = c;
244 XMapRaised(dpy, c->win);
245 XMapRaised(dpy, c->title);
246 XGrabButton(dpy, Button1, Mod1Mask, c->win, False, ButtonPressMask,
247 GrabModeAsync, GrabModeSync, None, None);
248 XGrabButton(dpy, Button2, Mod1Mask, c->win, False, ButtonPressMask,
249 GrabModeAsync, GrabModeSync, None, None);
250 XGrabButton(dpy, Button3, Mod1Mask, c->win, False, ButtonPressMask,
251 GrabModeAsync, GrabModeSync, None, None);
252 resize(c);
253 focus(c);
254 }
256 void
257 gravitate(Client *c, Bool invert)
258 {
259 int dx = 0, dy = 0;
261 switch(c->grav) {
262 case StaticGravity:
263 case NorthWestGravity:
264 case NorthGravity:
265 case NorthEastGravity:
266 dy = c->border;
267 break;
268 case EastGravity:
269 case CenterGravity:
270 case WestGravity:
271 dy = -(c->h / 2) + c->border;
272 break;
273 case SouthEastGravity:
274 case SouthGravity:
275 case SouthWestGravity:
276 dy = -c->h;
277 break;
278 default:
279 break;
280 }
282 switch (c->grav) {
283 case StaticGravity:
284 case NorthWestGravity:
285 case WestGravity:
286 case SouthWestGravity:
287 dx = c->border;
288 break;
289 case NorthGravity:
290 case CenterGravity:
291 case SouthGravity:
292 dx = -(c->w / 2) + c->border;
293 break;
294 case NorthEastGravity:
295 case EastGravity:
296 case SouthEastGravity:
297 dx = -(c->w + c->border);
298 break;
299 default:
300 break;
301 }
303 if(invert) {
304 dx = -dx;
305 dy = -dy;
306 }
307 c->x += dx;
308 c->y += dy;
309 }
311 void
312 resize(Client *c)
313 {
314 XConfigureEvent e;
316 resize_title(c);
317 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
318 e.type = ConfigureNotify;
319 e.event = c->win;
320 e.window = c->win;
321 e.x = c->x;
322 e.y = c->y;
323 e.width = c->w;
324 e.height = c->h;
325 e.border_width = c->border;
326 e.above = None;
327 e.override_redirect = False;
328 XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e);
329 XFlush(dpy);
330 }
332 static int
333 dummy_error_handler(Display *dpy, XErrorEvent *error)
334 {
335 return 0;
336 }
338 void
339 unmanage(Client *c)
340 {
341 Client **l;
343 XGrabServer(dpy);
344 XSetErrorHandler(dummy_error_handler);
346 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
347 XDestroyWindow(dpy, c->title);
349 for(l=&clients; *l && *l != c; l=&(*l)->next);
350 eassert(*l == c);
351 *l = c->next;
352 for(l=&stack; *l && *l != c; l=&(*l)->snext);
353 eassert(*l == c);
354 *l = c->snext;
355 free(c);
357 XFlush(dpy);
358 XSetErrorHandler(error_handler);
359 XUngrabServer(dpy);
360 if(stack)
361 focus(stack);
362 }
364 Client *
365 gettitle(Window w)
366 {
367 Client *c;
368 for(c = clients; c; c = c->next)
369 if(c->title == w)
370 return c;
371 return NULL;
372 }
374 Client *
375 getclient(Window w)
376 {
377 Client *c;
378 for(c = clients; c; c = c->next)
379 if(c->win == w)
380 return c;
381 return NULL;
382 }
384 void
385 draw_client(Client *c)
386 {
387 if(c == stack) {
388 draw_bar();
389 return;
390 }
392 brush.x = brush.y = 0;
393 brush.w = c->tw;
394 brush.h = c->th;
396 draw(dpy, &brush, True, c->name);
397 XCopyArea(dpy, brush.drawable, c->title, brush.gc,
398 0, 0, c->tw, c->th, 0, 0);
399 XFlush(dpy);
400 }