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, "rio: 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, "rio: SelectionClear (this should not happen)\n");
71 break;
72 case SelectionNotify:
73 fprintf(stderr, "rio: SelectionNotify (this should not happen)\n");
74 break;
75 case SelectionRequest:
76 fprintf(stderr, "rio: 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 (e->detail == 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);
149 if (e->value_mask & CWStackMode) {
150 top(c);
151 active(c);
156 if (c && c->init) {
157 wc.x = BORDER;
158 wc.y = BORDER;
160 else {
161 wc.x = e->x;
162 wc.y = e->y;
164 wc.width = e->width;
165 wc.height = e->height;
166 wc.border_width = 0;
167 wc.sibling = None;
168 wc.stack_mode = Above;
169 e->value_mask &= ~CWStackMode;
170 e->value_mask |= CWBorderWidth;
172 XConfigureWindow(dpy, e->window, e->value_mask, &wc);
175 void
176 mapreq(XMapRequestEvent *e)
178 Client *c;
179 int i;
181 curtime = CurrentTime;
182 c = getclient(e->window, 0);
183 trace("mapreq", c, e);
185 if (c == 0 || c->window != e->window) {
186 /* workaround for stupid NCDware */
187 fprintf(stderr, "rio: bad mapreq c %p w %x, rescanning\n",
188 c, (int)e->window);
189 for (i = 0; i < num_screens; i++)
190 scanwins(&screens[i]);
191 c = getclient(e->window, 0);
192 if (c == 0 || c->window != e->window) {
193 fprintf(stderr, "rio: window not found after rescan\n");
194 return;
198 switch (c->state) {
199 case WithdrawnState:
200 if (c->parent == c->screen->root) {
201 if (!manage(c, 0))
202 return;
203 break;
205 XReparentWindow(dpy, c->window, c->parent, BORDER-1, BORDER-1);
206 XAddToSaveSet(dpy, c->window);
207 /* fall through... */
208 case NormalState:
209 XMapWindow(dpy, c->window);
210 XMapRaised(dpy, c->parent);
211 top(c);
212 setstate(c, NormalState);
213 if (c->trans != None && current && c->trans == current->window)
214 active(c);
215 break;
216 case IconicState:
217 unhidec(c, 1);
218 break;
222 void
223 unmap(XUnmapEvent *e)
225 Client *c;
227 curtime = CurrentTime;
228 c = getclient(e->window, 0);
229 if (c) {
230 switch (c->state) {
231 case IconicState:
232 if (e->send_event) {
233 unhidec(c, 0);
234 withdraw(c);
236 break;
237 case NormalState:
238 if (c == current)
239 nofocus();
240 if (!c->reparenting)
241 withdraw(c);
242 break;
244 c->reparenting = 0;
248 void
249 circulatereq(XCirculateRequestEvent *e)
251 fprintf(stderr, "It must be the warlock Krill!\n"); /* ☺ */
254 void
255 newwindow(XCreateWindowEvent *e)
257 Client *c;
258 ScreenInfo *s;
260 /* we don't set curtime as nothing here uses it */
261 if (e->override_redirect)
262 return;
263 c = getclient(e->window, 1);
264 if (c && c->window == e->window && (s = getscreen(e->parent))) {
265 c->x = e->x;
266 c->y = e->y;
267 c->dx = e->width;
268 c->dy = e->height;
269 c->border = e->border_width;
270 c->screen = s;
271 if (c->parent == None)
272 c->parent = c->screen->root;
276 void
277 destroy(Window w)
279 Client *c;
281 curtime = CurrentTime;
282 c = getclient(w, 0);
283 if (c == 0)
284 return;
286 rmclient(c);
288 /* flush any errors generated by the window's sudden demise */
289 ignore_badwindow = 1;
290 XSync(dpy, False);
291 ignore_badwindow = 0;
294 void
295 clientmesg(XClientMessageEvent *e)
297 Client *c;
299 curtime = CurrentTime;
300 if (e->message_type == exit_rio) {
301 cleanup();
302 exit(0);
304 if (e->message_type == restart_rio) {
305 fprintf(stderr, "*** rio restarting ***\n");
306 cleanup();
307 execvp(myargv[0], myargv);
308 perror("rio: exec failed");
309 exit(1);
311 if (e->message_type == wm_change_state) {
312 c = getclient(e->window, 0);
313 if (e->format == 32 && e->data.l[0] == IconicState && c != 0) {
314 if (normal(c))
315 hide(c);
317 else
318 fprintf(stderr, "rio: WM_CHANGE_STATE: format %d data %d w 0x%x\n",
319 (int)e->format, (int)e->data.l[0], (int)e->window);
320 return;
322 fprintf(stderr, "rio: strange ClientMessage, type 0x%x window 0x%x\n",
323 (int)e->message_type, (int)e->window);
326 void
327 cmap(XColormapEvent *e)
329 Client *c;
330 int i;
332 /* we don't set curtime as nothing here uses it */
333 if (e->new) {
334 c = getclient(e->window, 0);
335 if (c) {
336 c->cmap = e->colormap;
337 if (c == current)
338 cmapfocus(c);
340 else
341 for (c = clients; c; c = c->next) {
342 for (i = 0; i < c->ncmapwins; i++)
343 if (c->cmapwins[i] == e->window) {
344 c->wmcmaps[i] = e->colormap;
345 if (c == current)
346 cmapfocus(c);
347 return;
353 void
354 property(XPropertyEvent *e)
356 Atom a;
357 int delete;
358 Client *c;
359 long msize;
361 /* we don't set curtime as nothing here uses it */
362 a = e->atom;
363 delete = (e->state == PropertyDelete);
364 c = getclient(e->window, 0);
365 if (c == 0)
366 return;
368 switch (a) {
369 case XA_WM_ICON_NAME:
370 if (c->iconname != 0)
371 XFree((char*) c->iconname);
372 c->iconname = delete ? 0 : getprop(c->window, a);
373 setlabel(c);
374 renamec(c, c->label);
375 return;
376 case XA_WM_NAME:
377 if (c->name != 0)
378 XFree((char*) c->name);
379 c->name = delete ? 0 : getprop(c->window, a);
380 setlabel(c);
381 renamec(c, c->label);
382 return;
383 case XA_WM_TRANSIENT_FOR:
384 gettrans(c);
385 return;
386 case XA_WM_HINTS:
387 case XA_WM_SIZE_HINTS:
388 case XA_WM_ZOOM_HINTS:
389 /* placeholders to not forget. ignore for now. -Axel */
390 return;
391 case XA_WM_NORMAL_HINTS:
392 if (XGetWMNormalHints(dpy, c->window, &c->size, &msize) == 0 || c->size.flags == 0)
393 c->size.flags = PSize; /* not specified - punt */
394 return;
396 if (a == _rio_hold_mode) {
397 c->hold = getiprop(c->window, _rio_hold_mode);
398 if (c == current)
399 draw_border(c, 1);
401 else if (a == wm_colormaps) {
402 getcmaps(c);
403 if (c == current)
404 cmapfocus(c);
408 void
409 reparent(XReparentEvent *e)
411 Client *c;
412 XWindowAttributes attr;
413 ScreenInfo *s;
415 /* we don't set curtime as nothing here uses it */
416 if (!getscreen(e->event) || e->override_redirect)
417 return;
418 if ((s = getscreen(e->parent)) != 0) {
419 c = getclient(e->window, 1);
420 if (c != 0 && (c->dx == 0 || c->dy == 0)) {
421 /* flush any errors */
422 ignore_badwindow = 1;
423 XGetWindowAttributes(dpy, c->window, &attr);
424 XSync(dpy, False);
425 ignore_badwindow = 0;
427 c->x = attr.x;
428 c->y = attr.y;
429 c->dx = attr.width;
430 c->dy = attr.height;
431 c->border = attr.border_width;
432 c->screen = s;
433 if (c->parent == None)
434 c->parent = c->screen->root;
437 else {
438 c = getclient(e->window, 0);
439 if (c != 0 && (c->parent == c->screen->root || withdrawn(c)))
440 rmclient(c);
444 #ifdef SHAPE
445 void
446 shapenotify(XShapeEvent *e)
448 Client *c;
450 /* we don't set curtime as nothing here uses it */
451 c = getclient(e->window, 0);
452 if (c == 0)
453 return;
455 setshape(c);
457 #endif
459 void
460 enter(XCrossingEvent *e)
462 Client *c;
464 curtime = e->time;
465 if (e->mode != NotifyGrab || e->detail != NotifyNonlinearVirtual)
466 return;
467 c = getclient(e->window, 0);
468 if (c != 0 && c != current) {
469 /* someone grabbed the pointer; make them current */
470 XMapRaised(dpy, c->parent);
471 top(c);
472 active(c);
476 void
477 leave(XCrossingEvent *e)
479 Client *c;
481 c = getclient(e->window, 0);
482 if (c)
483 XUndefineCursor(dpy, c->parent);
484 /* XDefineCursor(dpy, c->parent, c->screen->arrow); */
487 void
488 focusin(XFocusChangeEvent *e)
490 Client *c;
492 curtime = CurrentTime;
493 if (e->detail != NotifyNonlinearVirtual)
494 return;
495 c = getclient(e->window, 0);
496 if (c != 0 && c->window == e->window && c != current) {
497 /* someone grabbed keyboard or seized focus; make them current */
498 XMapRaised(dpy, c->parent);
499 top(c);
500 active(c);
504 BorderOrient
505 borderorient(Client *c, int x, int y)
507 if (x <= BORDER) {
508 if (y <= CORNER) {
509 if (debug) fprintf(stderr, "topleft\n");
510 return BorderWNW;
512 if (y >= (c->dy + 2*BORDER) - CORNER) {
513 if (debug) fprintf(stderr, "botleft\n");
514 return BorderWSW;
516 if (y > CORNER &&
517 y < (c->dy + 2*BORDER) - CORNER) {
518 if (debug) fprintf(stderr, "left\n");
519 return BorderW;
521 } else if (x <= CORNER) {
522 if (y <= BORDER) {
523 if (debug) fprintf(stderr, "topleft\n");
524 return BorderNNW;
526 if (y >= (c->dy + BORDER)) {
527 if (debug) fprintf(stderr, "botleft\n");
528 return BorderSSW;
530 } else if (x >= (c->dx + BORDER)) {
531 if (y <= CORNER) {
532 if (debug) fprintf(stderr, "topright\n");
533 return BorderENE;
535 if (y >= (c->dy + 2*BORDER) - CORNER) {
536 if (debug) fprintf(stderr, "botright\n");
537 return BorderESE;
539 if (y > CORNER &&
540 y < (c->dy + 2*BORDER) - CORNER) {
541 if (debug) fprintf(stderr, "right\n");
542 return BorderE;
544 } else if (x >= (c->dx + 2*BORDER) - CORNER) {
545 if (y <= BORDER) {
546 if (debug) fprintf(stderr, "topright\n");
547 return BorderNNE;
549 if (y >= (c->dy + BORDER)) {
550 if (debug) fprintf(stderr, "botright\n");
551 return BorderSSE;
553 } else if (x > CORNER &&
554 x < (c->dx + 2*BORDER) - CORNER) {
555 if (y <= BORDER) {
556 if (debug) fprintf(stderr, "top\n");
557 return BorderN;
559 if (y >= (c->dy + BORDER)) {
560 if (debug) fprintf(stderr, "bot\n");
561 return BorderS;
564 return BorderUnknown;
567 void
568 motionnotify(XMotionEvent *e)
570 Client *c;
571 BorderOrient bl;
573 c = getclient(e->window, 0);
574 if (c) {
575 bl = borderorient(c, e->x, e->y);
576 if (bl == BorderUnknown)
577 XUndefineCursor(dpy, c->parent);
578 else
579 XDefineCursor(dpy, c->parent, c->screen->bordcurs[bl]);