Blob


1 /* Copyright (c) 1994-1996 David Hogan, see README for licence details */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <X11/X.h>
5 #include <X11/Xos.h>
6 #include <X11/Xlib.h>
7 #include <X11/Xutil.h>
8 #include <X11/Xatom.h>
9 #include <X11/extensions/shape.h>
10 #include "dat.h"
11 #include "fns.h"
12 #include "patchlevel.h"
14 void
15 mainloop(int shape_event)
16 {
17 XEvent ev;
19 for (;;) {
20 getevent(&ev);
22 #ifdef DEBUG_EV
23 if (debug) {
24 ShowEvent(&ev);
25 printf("\n");
26 }
27 #endif
28 switch (ev.type) {
29 default:
30 #ifdef SHAPE
31 if (shape && ev.type == shape_event)
32 shapenotify((XShapeEvent *)&ev);
33 else
34 #endif
35 fprintf(stderr, "9wm: unknown ev.type %d\n", ev.type);
36 break;
37 case ButtonPress:
38 button(&ev.xbutton);
39 break;
40 case ButtonRelease:
41 break;
42 case MapRequest:
43 mapreq(&ev.xmaprequest);
44 break;
45 case ConfigureRequest:
46 configurereq(&ev.xconfigurerequest);
47 break;
48 case CirculateRequest:
49 circulatereq(&ev.xcirculaterequest);
50 break;
51 case UnmapNotify:
52 unmap(&ev.xunmap);
53 break;
54 case CreateNotify:
55 newwindow(&ev.xcreatewindow);
56 break;
57 case DestroyNotify:
58 destroy(ev.xdestroywindow.window);
59 break;
60 case ClientMessage:
61 clientmesg(&ev.xclient);
62 break;
63 case ColormapNotify:
64 cmap(&ev.xcolormap);
65 break;
66 case PropertyNotify:
67 property(&ev.xproperty);
68 break;
69 case SelectionClear:
70 fprintf(stderr, "9wm: SelectionClear (this should not happen)\n");
71 break;
72 case SelectionNotify:
73 fprintf(stderr, "9wm: SelectionNotify (this should not happen)\n");
74 break;
75 case SelectionRequest:
76 fprintf(stderr, "9wm: SelectionRequest (this should not happen)\n");
77 break;
78 case EnterNotify:
79 enter(&ev.xcrossing);
80 break;
81 case LeaveNotify:
82 leave(&ev.xcrossing);
83 break;
84 case ReparentNotify:
85 reparent(&ev.xreparent);
86 break;
87 case FocusIn:
88 focusin(&ev.xfocus);
89 break;
90 case MotionNotify:
91 motionnotify(&ev.xmotion);
92 break;
93 case Expose:
94 case NoExpose:
95 case FocusOut:
96 case ConfigureNotify:
97 case MapNotify:
98 case MappingNotify:
99 case GraphicsExpose:
100 /* not interested */
101 trace("ignore", 0, &ev);
102 break;
108 void
109 configurereq(XConfigureRequestEvent *e)
111 XWindowChanges wc;
112 Client *c;
114 /* we don't set curtime as nothing here uses it */
115 c = getclient(e->window, 0);
116 trace("configurereq", c, e);
118 e->value_mask &= ~CWSibling;
120 if (c) {
121 gravitate(c, 1);
122 if (e->value_mask & CWX)
123 c->x = e->x;
124 if (e->value_mask & CWY)
125 c->y = e->y;
126 if (e->value_mask & CWWidth)
127 c->dx = e->width;
128 if (e->value_mask & CWHeight)
129 c->dy = e->height;
130 if (e->value_mask & CWBorderWidth)
131 c->border = e->border_width;
132 gravitate(c, 0);
133 if (e->value_mask & CWStackMode) {
134 if (wc.stack_mode == Above)
135 top(c);
136 else
137 e->value_mask &= ~CWStackMode;
139 if (c->parent != c->screen->root && c->window == e->window) {
140 wc.x = c->x-BORDER;
141 wc.y = c->y-BORDER;
142 wc.width = c->dx+2*BORDER;
143 wc.height = c->dy+2*BORDER;
144 wc.border_width = 1;
145 wc.sibling = None;
146 wc.stack_mode = e->detail;
147 XConfigureWindow(dpy, c->parent, e->value_mask, &wc);
148 sendconfig(c);
152 if (c && c->init) {
153 wc.x = BORDER;
154 wc.y = BORDER;
156 else {
157 wc.x = e->x;
158 wc.y = e->y;
160 wc.width = e->width;
161 wc.height = e->height;
162 wc.border_width = 0;
163 wc.sibling = None;
164 wc.stack_mode = Above;
165 e->value_mask &= ~CWStackMode;
166 e->value_mask |= CWBorderWidth;
168 XConfigureWindow(dpy, e->window, e->value_mask, &wc);
171 void
172 mapreq(XMapRequestEvent *e)
174 Client *c;
175 int i;
177 curtime = CurrentTime;
178 c = getclient(e->window, 0);
179 trace("mapreq", c, e);
181 if (c == 0 || c->window != e->window) {
182 /* workaround for stupid NCDware */
183 fprintf(stderr, "9wm: bad mapreq c %p w %x, rescanning\n",
184 c, (int)e->window);
185 for (i = 0; i < num_screens; i++)
186 scanwins(&screens[i]);
187 c = getclient(e->window, 0);
188 if (c == 0 || c->window != e->window) {
189 fprintf(stderr, "9wm: window not found after rescan\n");
190 return;
194 switch (c->state) {
195 case WithdrawnState:
196 if (c->parent == c->screen->root) {
197 if (!manage(c, 0))
198 return;
199 break;
201 XReparentWindow(dpy, c->window, c->parent, BORDER-1, BORDER-1);
202 XAddToSaveSet(dpy, c->window);
203 /* fall through... */
204 case NormalState:
205 XMapWindow(dpy, c->window);
206 XMapRaised(dpy, c->parent);
207 top(c);
208 setstate(c, NormalState);
209 if (c->trans != None && current && c->trans == current->window)
210 active(c);
211 break;
212 case IconicState:
213 unhidec(c, 1);
214 break;
218 void
219 unmap(XUnmapEvent *e)
221 Client *c;
223 curtime = CurrentTime;
224 c = getclient(e->window, 0);
225 if (c) {
226 switch (c->state) {
227 case IconicState:
228 if (e->send_event) {
229 unhidec(c, 0);
230 withdraw(c);
232 break;
233 case NormalState:
234 if (c == current)
235 nofocus();
236 if (!c->reparenting)
237 withdraw(c);
238 break;
240 c->reparenting = 0;
244 void
245 circulatereq(XCirculateRequestEvent *e)
247 fprintf(stderr, "It must be the warlock Krill!\n"); /* ☺ */
250 void
251 newwindow(XCreateWindowEvent *e)
253 Client *c;
254 ScreenInfo *s;
256 /* we don't set curtime as nothing here uses it */
257 if (e->override_redirect)
258 return;
259 c = getclient(e->window, 1);
260 if (c && c->window == e->window && (s = getscreen(e->parent))) {
261 c->x = e->x;
262 c->y = e->y;
263 c->dx = e->width;
264 c->dy = e->height;
265 c->border = e->border_width;
266 c->screen = s;
267 if (c->parent == None)
268 c->parent = c->screen->root;
272 void
273 destroy(Window w)
275 Client *c;
277 curtime = CurrentTime;
278 c = getclient(w, 0);
279 if (c == 0)
280 return;
282 rmclient(c);
284 /* flush any errors generated by the window's sudden demise */
285 ignore_badwindow = 1;
286 XSync(dpy, False);
287 ignore_badwindow = 0;
290 void
291 clientmesg(XClientMessageEvent *e)
293 Client *c;
295 curtime = CurrentTime;
296 if (e->message_type == exit_9wm) {
297 cleanup();
298 exit(0);
300 if (e->message_type == restart_9wm) {
301 fprintf(stderr, "*** 9wm restarting ***\n");
302 cleanup();
303 execvp(myargv[0], myargv);
304 perror("9wm: exec failed");
305 exit(1);
307 if (e->message_type == wm_change_state) {
308 c = getclient(e->window, 0);
309 if (e->format == 32 && e->data.l[0] == IconicState && c != 0) {
310 if (normal(c))
311 hide(c);
313 else
314 fprintf(stderr, "9wm: WM_CHANGE_STATE: format %d data %d w 0x%x\n",
315 (int)e->format, (int)e->data.l[0], (int)e->window);
316 return;
318 fprintf(stderr, "9wm: strange ClientMessage, type 0x%x window 0x%x\n",
319 (int)e->message_type, (int)e->window);
322 void
323 cmap(XColormapEvent *e)
325 Client *c;
326 int i;
328 /* we don't set curtime as nothing here uses it */
329 if (e->new) {
330 c = getclient(e->window, 0);
331 if (c) {
332 c->cmap = e->colormap;
333 if (c == current)
334 cmapfocus(c);
336 else
337 for (c = clients; c; c = c->next) {
338 for (i = 0; i < c->ncmapwins; i++)
339 if (c->cmapwins[i] == e->window) {
340 c->wmcmaps[i] = e->colormap;
341 if (c == current)
342 cmapfocus(c);
343 return;
349 void
350 property(XPropertyEvent *e)
352 Atom a;
353 int delete;
354 Client *c;
356 /* we don't set curtime as nothing here uses it */
357 a = e->atom;
358 delete = (e->state == PropertyDelete);
359 c = getclient(e->window, 0);
360 if (c == 0)
361 return;
363 switch (a) {
364 case XA_WM_ICON_NAME:
365 if (c->iconname != 0)
366 XFree((char*) c->iconname);
367 c->iconname = delete ? 0 : getprop(c->window, a);
368 setlabel(c);
369 renamec(c, c->label);
370 return;
371 case XA_WM_NAME:
372 if (c->name != 0)
373 XFree((char*) c->name);
374 c->name = delete ? 0 : getprop(c->window, a);
375 setlabel(c);
376 renamec(c, c->label);
377 return;
378 case XA_WM_TRANSIENT_FOR:
379 gettrans(c);
380 return;
382 if (a == _9wm_hold_mode) {
383 c->hold = getiprop(c->window, _9wm_hold_mode);
384 if (c == current)
385 draw_border(c, 1);
387 else if (a == wm_colormaps) {
388 getcmaps(c);
389 if (c == current)
390 cmapfocus(c);
394 void
395 reparent(XReparentEvent *e)
397 Client *c;
398 XWindowAttributes attr;
399 ScreenInfo *s;
401 /* we don't set curtime as nothing here uses it */
402 if (!getscreen(e->event) || e->override_redirect)
403 return;
404 if ((s = getscreen(e->parent)) != 0) {
405 c = getclient(e->window, 1);
406 if (c != 0 && (c->dx == 0 || c->dy == 0)) {
407 XGetWindowAttributes(dpy, c->window, &attr);
408 c->x = attr.x;
409 c->y = attr.y;
410 c->dx = attr.width;
411 c->dy = attr.height;
412 c->border = attr.border_width;
413 c->screen = s;
414 if (c->parent == None)
415 c->parent = c->screen->root;
418 else {
419 c = getclient(e->window, 0);
420 if (c != 0 && (c->parent == c->screen->root || withdrawn(c)))
421 rmclient(c);
425 #ifdef SHAPE
426 void
427 shapenotify(XShapeEvent *e)
429 Client *c;
431 /* we don't set curtime as nothing here uses it */
432 c = getclient(e->window, 0);
433 if (c == 0)
434 return;
436 setshape(c);
438 #endif
440 void
441 enter(XCrossingEvent *e)
443 Client *c;
445 curtime = e->time;
446 if (e->mode != NotifyGrab || e->detail != NotifyNonlinearVirtual)
447 return;
448 c = getclient(e->window, 0);
449 if (c != 0 && c != current) {
450 /* someone grabbed the pointer; make them current */
451 XMapRaised(dpy, c->parent);
452 top(c);
453 active(c);
457 void
458 leave(XCrossingEvent *e)
460 Client *c;
462 c = getclient(e->window, 0);
463 if (c)
464 XUndefineCursor(dpy, c->parent);
465 /* XDefineCursor(dpy, c->parent, c->screen->arrow); */
468 void
469 focusin(XFocusChangeEvent *e)
471 Client *c;
473 curtime = CurrentTime;
474 if (e->detail != NotifyNonlinearVirtual)
475 return;
476 c = getclient(e->window, 0);
477 if (c != 0 && c->window == e->window && c != current) {
478 /* someone grabbed keyboard or seized focus; make them current */
479 XMapRaised(dpy, c->parent);
480 top(c);
481 active(c);
485 BorderOrient
486 borderorient(Client *c, int x, int y)
488 if (x <= BORDER) {
489 if (y <= CORNER) {
490 if (debug) fprintf(stderr, "topleft\n");
491 return BorderWNW;
493 if (y >= (c->dy + 2*BORDER) - CORNER) {
494 if (debug) fprintf(stderr, "botleft\n");
495 return BorderWSW;
497 if (y > CORNER &&
498 y < (c->dy + 2*BORDER) - CORNER) {
499 if (debug) fprintf(stderr, "left\n");
500 return BorderW;
502 } else if (x <= CORNER) {
503 if (y <= BORDER) {
504 if (debug) fprintf(stderr, "topleft\n");
505 return BorderNNW;
507 if (y >= (c->dy + BORDER)) {
508 if (debug) fprintf(stderr, "botleft\n");
509 return BorderSSW;
511 } else if (x >= (c->dx + BORDER)) {
512 if (y <= CORNER) {
513 if (debug) fprintf(stderr, "topright\n");
514 return BorderENE;
516 if (y >= (c->dy + 2*BORDER) - CORNER) {
517 if (debug) fprintf(stderr, "botright\n");
518 return BorderESE;
520 if (y > CORNER &&
521 y < (c->dy + 2*BORDER) - CORNER) {
522 if (debug) fprintf(stderr, "right\n");
523 return BorderE;
525 } else if (x >= (c->dx + 2*BORDER) - CORNER) {
526 if (y <= BORDER) {
527 if (debug) fprintf(stderr, "topright\n");
528 return BorderNNE;
530 if (y >= (c->dy + BORDER)) {
531 if (debug) fprintf(stderr, "botright\n");
532 return BorderSSE;
534 } else if (x > CORNER &&
535 x < (c->dx + 2*BORDER) - CORNER) {
536 if (y <= BORDER) {
537 if (debug) fprintf(stderr, "top\n");
538 return BorderN;
540 if (y >= (c->dy + BORDER)) {
541 if (debug) fprintf(stderr, "bot\n");
542 return BorderS;
545 return BorderUnknown;
548 void
549 motionnotify(XMotionEvent *e)
551 Client *c;
552 BorderOrient bl;
554 c = getclient(e->window, 0);
555 if (c) {
556 bl = borderorient(c, e->x, e->y);
557 if (bl == BorderUnknown)
558 XUndefineCursor(dpy, c->parent);
559 else
560 XDefineCursor(dpy, c->parent, c->screen->bordcurs[bl]);