1 /* Copyright (c) 1994-1996 David Hogan, see README for licence details */
2 #include <stdio.h>
3 #include <stdlib.h>
4
5 #include <X11/X.h>
6 #include <X11/Xos.h>
7 #include <X11/Xlib.h>
8 #include <X11/Xutil.h>
9 #include <X11/Xatom.h>
10 #include <X11/extensions/shape.h>
11
12 #include "dat.h"
13 #include "fns.h"
14
15
16 void
mainloop(int shape_event)17 mainloop (int shape_event)
18 {
19 Client *c = 0;
20 ScreenInfo *s = 0;
21 XEvent ev;
22
23 for (;;)
24 {
25 XNextEvent (dpy, &ev);
26
27 switch (ev.type)
28 {
29 case KeyPress:
30 keyevent (&ev.xkey);
31 break;
32 case KeyRelease:
33 break;
34 case ButtonPress:
35 button (&ev.xbutton);
36 XAllowEvents (dpy, SyncPointer, ev.xbutton.time);
37 break;
38 case ButtonRelease:
39 break;
40 case MapRequest:
41 mapreq (&ev.xmaprequest);
42
43 if ((c = getclient (ev.xmaprequest.window, 0)) != 0)
44 {
45 if (normal (c) && ((s = c->screen) != 0))
46 {
47 if (c == current)
48 {
49 if (c->isnotile)
50 {
51 raise_notile (s);
52 }
53 else
54 {
55 raise_tile (s, 0);
56 }
57 }
58
59 if (!c->isnotile || c->istool)
60 {
61 tile_all (s);
62 }
63 }
64 }
65 break;
66 case ConfigureRequest:
67 configurereq (&ev.xconfigurerequest);
68 break;
69 case UnmapNotify:
70 unmap (&ev.xunmap);
71
72 if ((c = getclient (ev.xunmap.window, 0)) != 0)
73 {
74 if ((s = c->screen) != 0)
75 {
76 if (!c->isnotile || c->istool)
77 {
78 tile_all (s);
79 }
80
81 if (!current)
82 {
83 revert_window (s);
84 }
85 }
86 }
87 break;
88 case PropertyNotify:
89 property (&ev.xproperty);
90 break;
91 case Expose:
92 expose (&ev.xexpose);
93 break;
94 case CreateNotify:
95 newwindow (&ev.xcreatewindow);
96 break;
97 case DestroyNotify:
98 destroy (ev.xdestroywindow.window);
99 break;
100 case ClientMessage:
101 clientmesg (&ev.xclient);
102 break;
103 case ColormapNotify:
104 cmap (&ev.xcolormap);
105 break;
106 case ReparentNotify:
107 reparent (&ev.xreparent);
108 break;
109 case SelectionNotify:
110 break;
111 case EnterNotify:
112 enter (&ev.xcrossing);
113 break;
114 case FocusIn:
115 focusin (&ev.xfocus);
116 break;
117 default:
118 if (shape && ev.type == shape_event)
119 {
120 shapenotify ((XShapeEvent *) & ev);
121 }
122 break;
123 }
124 }
125 }
126
127 void
expose(XExposeEvent * e)128 expose (XExposeEvent * e)
129 {
130 Client *c;
131 ScreenInfo *s;
132
133 if ((c = getclient (e->window, 0)))
134 draw_border (c, c == current ? 1 : 0);
135 else if ((s = getbarscreen (e->window)))
136 draw_tbar (s);
137 }
138
139 void
configurereq(XConfigureRequestEvent * e)140 configurereq (XConfigureRequestEvent * e)
141 {
142 XWindowChanges wc;
143 Client *c;
144
145 c = getclient (e->window, 0);
146 e->value_mask &= ~CWSibling;
147
148 if (c)
149 {
150 gravitate (c, 1);
151
152 if (e->value_mask & CWX)
153 c->x = e->x;
154
155 if (e->value_mask & CWY)
156 c->y = e->y;
157
158 if (e->value_mask & CWWidth)
159 c->dx = e->width;
160
161 if (e->value_mask & CWHeight)
162 c->dy = e->height;
163
164 if (e->value_mask & CWBorderWidth)
165 c->border = e->border_width;
166
167 gravitate (c, 0);
168
169 if (e->value_mask & CWStackMode)
170 {
171 if (wc.stack_mode == Above)
172 top (c);
173 else
174 e->value_mask &= ~CWStackMode;
175 }
176
177 if (c->parent != c->screen->root && c->window == e->window)
178 {
179 wc.x = c->x - BORDER;
180 wc.y = c->y - BORDER;
181 wc.width = c->dx + 2 * BORDER;
182 wc.height = c->dy + 2 * BORDER;
183 wc.border_width = 1;
184 wc.sibling = None;
185 wc.stack_mode = e->detail;
186 XConfigureWindow (dpy, c->parent, e->value_mask, &wc);
187 sendconfig (c);
188 }
189 }
190
191 if (c && c->init)
192 {
193 wc.x = BORDER;
194 wc.y = BORDER;
195 }
196 else
197 {
198 wc.x = e->x;
199 wc.y = e->y;
200 }
201
202 wc.width = e->width;
203 wc.height = e->height;
204 wc.border_width = 0;
205 wc.sibling = None;
206 wc.stack_mode = Above;
207 e->value_mask &= ~CWStackMode;
208 e->value_mask |= CWBorderWidth;
209
210 XConfigureWindow (dpy, e->window, e->value_mask, &wc);
211 }
212
213 void
mapreq(XMapRequestEvent * e)214 mapreq (XMapRequestEvent * e)
215 {
216 Client *c;
217
218 c = getclient (e->window, 0);
219
220 if (c == 0 || c->window != e->window)
221 {
222 return;
223 }
224
225 switch (c->state)
226 {
227 case WithdrawnState:
228 if (c->parent == c->screen->root)
229 {
230 if (!manage (c, 0))
231 return;
232 break;
233 }
234 XReparentWindow (dpy, c->window, c->parent, BORDER, BORDER);
235 XAddToSaveSet (dpy, c->window);
236 /* fall through... */
237
238 case NormalState:
239 if (c->trans != None)
240 {
241 Client *p = getclient (c->trans, 0);
242
243 if (p)
244 {
245 c->desktop = p->desktop;
246 }
247 }
248
249 raise_tbar (c->screen);
250 XMapWindow (dpy, c->window);
251 XMapRaised (dpy, c->parent);
252 top (c);
253 wmsetstate (c, NormalState);
254
255 if ((mouse_on_screen () == c->screen)
256 || (current && (current->screen == c->screen)))
257 {
258 active (c);
259 }
260 break;
261
262 case IconicState:
263 unhidec (c, 1);
264 break;
265 }
266 }
267
268 void
unmap(XUnmapEvent * e)269 unmap (XUnmapEvent * e)
270 {
271 Client *c;
272
273 c = getclient (e->window, 0);
274
275 if (c)
276 {
277 switch (c->state)
278 {
279 case IconicState:
280 if (e->send_event)
281 {
282 unhidec (c, 0);
283 withdraw (c);
284 }
285 break;
286
287 case NormalState:
288 if (c == current)
289 current = 0;
290
291 if (!c->reparenting)
292 withdraw (c);
293 break;
294 }
295
296 c->reparenting = 0;
297 }
298 }
299
300 void
newwindow(XCreateWindowEvent * e)301 newwindow (XCreateWindowEvent * e)
302 {
303 Client *c;
304 ScreenInfo *s;
305
306 if (e->override_redirect)
307 return;
308 c = getclient (e->window, 1);
309
310 /* Crashing bug patch by MG has been applied here. */
311 if (c && c->window == e->window)
312 {
313 c->x = e->x;
314 c->y = e->y;
315 c->dx = e->width;
316 c->dy = e->height;
317 c->border = e->border_width;
318
319 if (0 != (s = getscreen (e->parent)))
320 c->screen = s;
321 else
322 c->screen = &screens[0];
323
324 if (c->parent == None)
325 c->parent = c->screen->root;
326 }
327 }
328
329 void
destroy(Window w)330 destroy (Window w)
331 {
332 Client *c;
333
334 if (!(c = getclient (w, 0)))
335 return;
336
337 rmclient (c);
338
339 ignore_badwindow = 1;
340 XSync (dpy, False);
341 ignore_badwindow = 0;
342 }
343
344 void
clientmesg(XClientMessageEvent * e)345 clientmesg (XClientMessageEvent * e)
346 {
347 Client *c;
348
349 if (e->message_type == exit_larswm)
350 {
351 cleanup ();
352 exit (0);
353 }
354 else if (e->message_type == restart_larswm)
355 {
356 cleanup ();
357 execvp (myargv[0], myargv);
358 perror ("larswm: exec failed");
359 exit (1);
360 }
361 else if (e->message_type == wm_change_state)
362 {
363 c = getclient (e->window, 0);
364
365 if (e->format == 32 && e->data.l[0] == IconicState && c != 0)
366 {
367 if (normal (c))
368 hide (c);
369 }
370 }
371 }
372
373 void
cmap(XColormapEvent * e)374 cmap (XColormapEvent * e)
375 {
376 Client *c;
377 int i;
378
379 if (e->new)
380 {
381 c = getclient (e->window, 0);
382 if (c)
383 {
384 c->cmap = e->colormap;
385 if (c == current)
386 cmapfocus (c);
387 }
388 else
389 for (c = clients; c; c = c->next)
390 {
391 for (i = 0; i < c->ncmapwins; i++)
392 if (c->cmapwins[i] == e->window)
393 {
394 c->wmcmaps[i] = e->colormap;
395 if (c == current)
396 cmapfocus (c);
397 return;
398 }
399 }
400 }
401 }
402
403 void
property(XPropertyEvent * e)404 property (XPropertyEvent * e)
405 {
406 Client *c;
407 long msize;
408
409 /* check if text to be displayed on status bar was just changed */
410 if ((e->atom == bartext_larswm) && (e->window == DefaultRootWindow (dpy)))
411 {
412 update_cmd_output ();
413 return;
414 }
415
416 if (!(c = getclient (e->window, 0)))
417 return;
418
419 switch (e->atom)
420 {
421 case XA_WM_ICON_NAME:
422 if (c->iconname != 0)
423 XFree ((char *) c->iconname);
424 c->iconname =
425 (e->state == PropertyDelete) ? 0 : getprop (c->window, e->atom);
426 setlabel (c);
427 renamec (c, c->label);
428 break;
429
430 case XA_WM_NAME:
431 if (c->name != 0)
432 XFree ((char *) c->name);
433 c->name =
434 (e->state == PropertyDelete) ? 0 : getprop (c->window, e->atom);
435 setlabel (c);
436 renamec (c, c->label);
437 break;
438
439 case XA_WM_TRANSIENT_FOR:
440 gettrans (c);
441 break;
442
443 case XA_WM_NORMAL_HINTS:
444 if (XGetWMNormalHints (dpy, c->window, &c->size, &msize) == 0
445 || c->size.flags == 0)
446 {
447 c->size.flags = PSize;
448 }
449
450 if (c->size.flags & PBaseSize)
451 {
452 c->min_dx = c->size.base_width;
453 c->min_dy = c->size.base_height;
454 }
455 else if (c->size.flags & PMinSize)
456 {
457 c->min_dx = c->size.min_width;
458 c->min_dy = c->size.min_height;
459 }
460 else
461 {
462 c->min_dx = c->min_dy = 1;
463 }
464 break;
465
466 default:
467 if (e->atom == wm_colormaps)
468 {
469 getcmaps (c);
470
471 if (c == current)
472 {
473 cmapfocus (c);
474 }
475 }
476 break;
477 }
478 }
479
480 void
reparent(XReparentEvent * e)481 reparent (XReparentEvent * e)
482 {
483 Client *c;
484 XWindowAttributes attr;
485 ScreenInfo *s;
486
487 if (!getscreen (e->event) || e->override_redirect)
488 return;
489 if ((s = getscreen (e->parent)) != 0)
490 {
491 c = getclient (e->window, 1);
492 if (c != 0 && (c->dx == 0 || c->dy == 0))
493 {
494 XGetWindowAttributes (dpy, c->window, &attr);
495 c->x = attr.x;
496 c->y = attr.y;
497 c->dx = attr.width;
498 c->dy = attr.height;
499 c->border = attr.border_width;
500 c->screen = s;
501 if (c->parent == None)
502 c->parent = c->screen->root;
503 }
504 }
505 else
506 {
507 c = getclient (e->window, 0);
508 if (c != 0 && (c->parent == c->screen->root || withdrawn (c)))
509 rmclient (c);
510 }
511 }
512
513 void
shapenotify(XShapeEvent * e)514 shapenotify (XShapeEvent * e)
515 {
516 Client *c;
517
518 c = getclient (e->window, 0);
519 if (c == 0)
520 return;
521
522 setshape (c);
523 }
524
525 void
enter(XCrossingEvent * e)526 enter (XCrossingEvent * e)
527 {
528 Client *c;
529
530 if (e->mode != NotifyGrab || e->detail != NotifyNonlinearVirtual)
531 return;
532
533 c = getclient (e->window, 0);
534
535 if (c && c->parent && (c != current))
536 {
537 XMapRaised (dpy, c->parent);
538 active (c);
539 }
540 else
541 {
542 XSetInputFocus (dpy, e->window, RevertToPointerRoot, e->time);
543 }
544 }
545
546 void
focusin(XFocusChangeEvent * e)547 focusin (XFocusChangeEvent * e)
548 {
549 Client *c;
550
551 if (e->detail != NotifyNonlinearVirtual)
552 return;
553
554 c = getclient (e->window, 0);
555
556 if (c && c->window && c->parent && (c->window == e->window)
557 && (c != current))
558 {
559 XMapRaised (dpy, c->parent);
560 active (c);
561 }
562 else
563 {
564 XSetInputFocus (dpy, e->window, RevertToPointerRoot, CurrentTime);
565 }
566 }
567