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