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 KeyPress:
38 keypress(&ev.xkey);
39 break;
40 case KeyRelease:
41 keyrelease(&ev.xkey);
42 break;
43 case ButtonPress:
44 button(&ev.xbutton);
45 break;
46 case ButtonRelease:
47 break;
48 case MapRequest:
49 mapreq(&ev.xmaprequest);
50 break;
51 case ConfigureRequest:
52 configurereq(&ev.xconfigurerequest);
53 break;
54 case CirculateRequest:
55 circulatereq(&ev.xcirculaterequest);
56 break;
57 case UnmapNotify:
58 unmap(&ev.xunmap);
59 break;
60 case CreateNotify:
61 newwindow(&ev.xcreatewindow);
62 break;
63 case DestroyNotify:
64 destroy(ev.xdestroywindow.window);
65 break;
66 case ClientMessage:
67 clientmesg(&ev.xclient);
68 break;
69 case ColormapNotify:
70 cmap(&ev.xcolormap);
71 break;
72 case PropertyNotify:
73 property(&ev.xproperty);
74 break;
75 case SelectionClear:
76 fprintf(stderr, "rio: SelectionClear (this should not happen)\n");
77 break;
78 case SelectionNotify:
79 fprintf(stderr, "rio: SelectionNotify (this should not happen)\n");
80 break;
81 case SelectionRequest:
82 fprintf(stderr, "rio: SelectionRequest (this should not happen)\n");
83 break;
84 case EnterNotify:
85 enter(&ev.xcrossing);
86 break;
87 case LeaveNotify:
88 leave(&ev.xcrossing);
89 break;
90 case ReparentNotify:
91 reparent(&ev.xreparent);
92 break;
93 case FocusIn:
94 focusin(&ev.xfocus);
95 break;
96 case MotionNotify:
97 motionnotify(&ev.xmotion);
98 break;
99 case Expose:
100 case NoExpose:
101 case FocusOut:
102 case ConfigureNotify:
103 case MapNotify:
104 case MappingNotify:
105 case GraphicsExpose:
106 /* not interested */
107 trace("ignore", 0, &ev);
108 break;
114 void
115 configurereq(XConfigureRequestEvent *e)
117 XWindowChanges wc;
118 Client *c;
120 /* we don't set curtime as nothing here uses it */
121 c = getclient(e->window, 0);
122 trace("configurereq", c, e);
124 e->value_mask &= ~CWSibling;
126 if(c){
127 gravitate(c, 1);
128 if(e->value_mask & CWX)
129 c->x = e->x;
130 if(e->value_mask & CWY)
131 c->y = e->y;
132 if(e->value_mask & CWWidth)
133 c->dx = e->width;
134 if(e->value_mask & CWHeight)
135 c->dy = e->height;
136 if(e->value_mask & CWBorderWidth)
137 c->border = e->border_width;
138 gravitate(c, 0);
139 if(e->value_mask & CWStackMode){
140 if(e->detail == Above)
141 top(c);
142 else
143 e->value_mask &= ~CWStackMode;
145 if(c->parent != c->screen->root && c->window == e->window){
146 wc.x = c->x-BORDER;
147 wc.y = c->y-BORDER;
148 wc.width = c->dx+2*BORDER;
149 wc.height = c->dy+2*BORDER;
150 wc.border_width = 1;
151 wc.sibling = None;
152 wc.stack_mode = e->detail;
153 XConfigureWindow(dpy, c->parent, e->value_mask, &wc);
154 sendconfig(c);
155 if(e->value_mask & CWStackMode){
156 top(c);
157 active(c);
162 if(c && c->init){
163 wc.x = BORDER;
164 wc.y = BORDER;
166 else {
167 wc.x = e->x;
168 wc.y = e->y;
170 wc.width = e->width;
171 wc.height = e->height;
172 wc.border_width = 0;
173 wc.sibling = None;
174 wc.stack_mode = Above;
175 e->value_mask &= ~CWStackMode;
176 e->value_mask |= CWBorderWidth;
178 XConfigureWindow(dpy, e->window, e->value_mask, &wc);
181 void
182 mapreq(XMapRequestEvent *e)
184 Client *c;
185 int i;
187 curtime = CurrentTime;
188 c = getclient(e->window, 0);
189 trace("mapreq", c, e);
191 if(c == 0 || c->window != e->window){
192 /* workaround for stupid NCDware */
193 fprintf(stderr, "rio: bad mapreq c %p w %x, rescanning\n",
194 (void*)c, (int)e->window);
195 for(i = 0; i < num_screens; i++)
196 scanwins(&screens[i]);
197 c = getclient(e->window, 0);
198 if(c == 0 || c->window != e->window){
199 fprintf(stderr, "rio: window not found after rescan\n");
200 return;
204 switch (c->state){
205 case WithdrawnState:
206 if(c->parent == c->screen->root){
207 if(!manage(c, 0))
208 return;
209 break;
211 XReparentWindow(dpy, c->window, c->parent, BORDER-1, BORDER-1);
212 XAddToSaveSet(dpy, c->window);
213 /* fall through... */
214 case NormalState:
215 XMapWindow(dpy, c->window);
216 XMapRaised(dpy, c->parent);
217 top(c);
218 setstate(c, NormalState);
219 if(c->trans != None && current && c->trans == current->window)
220 active(c);
221 break;
222 case IconicState:
223 unhidec(c, 1);
224 break;
228 void
229 unmap(XUnmapEvent *e)
231 Client *c;
233 curtime = CurrentTime;
234 c = getclient(e->window, 0);
235 if(c){
236 switch (c->state){
237 case IconicState:
238 if(e->send_event){
239 unhidec(c, 0);
240 withdraw(c);
242 break;
243 case NormalState:
244 if(c == current)
245 nofocus();
246 if(!c->reparenting)
247 withdraw(c);
248 break;
250 c->reparenting = 0;
254 void
255 circulatereq(XCirculateRequestEvent *e)
257 fprintf(stderr, "It must be the warlock Krill!\n"); /* ☺ */
260 void
261 newwindow(XCreateWindowEvent *e)
263 Client *c;
264 ScreenInfo *s;
266 /* we don't set curtime as nothing here uses it */
267 if(e->override_redirect)
268 return;
269 c = getclient(e->window, 1);
270 if(c && c->window == e->window && (s = getscreen(e->parent))){
271 c->x = e->x;
272 c->y = e->y;
273 c->dx = e->width;
274 c->dy = e->height;
275 c->border = e->border_width;
276 c->screen = s;
277 if(c->parent == None)
278 c->parent = c->screen->root;
282 void
283 destroy(Window w)
285 int i;
286 Client *c;
288 curtime = CurrentTime;
289 c = getclient(w, 0);
290 if(c == 0)
291 return;
293 if(numvirtuals > 1)
294 for(i=0; i<numvirtuals; i++)
295 if(currents[i] == c)
296 currents[i] = 0;
298 rmclient(c);
300 /* flush any errors generated by the window's sudden demise */
301 ignore_badwindow = 1;
302 XSync(dpy, False);
303 ignore_badwindow = 0;
306 void
307 clientmesg(XClientMessageEvent *e)
309 Client *c;
311 curtime = CurrentTime;
312 if(e->message_type == exit_rio){
313 cleanup();
314 exit(0);
316 if(e->message_type == restart_rio){
317 fprintf(stderr, "*** rio restarting ***\n");
318 cleanup();
319 execvp(myargv[0], myargv);
320 perror("rio: exec failed");
321 exit(1);
323 if(e->message_type == wm_protocols)
324 return;
325 if(e->message_type == wm_change_state){
326 c = getclient(e->window, 0);
327 if(e->format == 32 && e->data.l[0] == IconicState && c != 0){
328 if(normal(c))
329 hide(c);
331 else
332 fprintf(stderr, "rio: WM_CHANGE_STATE: format %d data %d w 0x%x\n",
333 (int)e->format, (int)e->data.l[0], (int)e->window);
334 return;
336 fprintf(stderr, "rio: strange ClientMessage, type 0x%x window 0x%x\n",
337 (int)e->message_type, (int)e->window);
340 void
341 cmap(XColormapEvent *e)
343 Client *c;
344 int i;
346 /* we don't set curtime as nothing here uses it */
347 if(e->new){
348 c = getclient(e->window, 0);
349 if(c){
350 c->cmap = e->colormap;
351 if(c == current)
352 cmapfocus(c);
354 else
355 for(c = clients; c; c = c->next){
356 for(i = 0; i < c->ncmapwins; i++)
357 if(c->cmapwins[i] == e->window){
358 c->wmcmaps[i] = e->colormap;
359 if(c == current)
360 cmapfocus(c);
361 return;
367 void
368 property(XPropertyEvent *e)
370 Atom a;
371 int delete;
372 Client *c;
373 long msize;
375 /* we don't set curtime as nothing here uses it */
376 a = e->atom;
377 delete = (e->state == PropertyDelete);
378 c = getclient(e->window, 0);
379 if(c == 0)
380 return;
382 switch (a){
383 case XA_WM_ICON_NAME:
384 if(c->iconname != 0)
385 XFree((char*) c->iconname);
386 c->iconname = delete ? 0 : getprop(c->window, a);
387 setlabel(c);
388 renamec(c, c->label);
389 return;
390 case XA_WM_NAME:
391 if(c->name != 0)
392 XFree((char*) c->name);
393 c->name = delete ? 0 : getprop(c->window, a);
394 setlabel(c);
395 renamec(c, c->label);
396 return;
397 case XA_WM_TRANSIENT_FOR:
398 gettrans(c);
399 return;
400 case XA_WM_HINTS:
401 case XA_WM_SIZE_HINTS:
402 case XA_WM_ZOOM_HINTS:
403 /* placeholders to not forget. ignore for now. -Axel */
404 return;
405 case XA_WM_NORMAL_HINTS:
406 if(XGetWMNormalHints(dpy, c->window, &c->size, &msize) == 0 || c->size.flags == 0)
407 c->size.flags = PSize; /* not specified - punt */
408 return;
410 if(a == _rio_hold_mode){
411 c->hold = getiprop(c->window, _rio_hold_mode);
412 if(c == current)
413 draw_border(c, 1);
415 else if(a == wm_colormaps){
416 getcmaps(c);
417 if(c == current)
418 cmapfocus(c);
422 void
423 reparent(XReparentEvent *e)
425 Client *c;
426 XWindowAttributes attr;
427 ScreenInfo *s;
429 /* we don't set curtime as nothing here uses it */
430 if(!getscreen(e->event) || e->override_redirect)
431 return;
432 if((s = getscreen(e->parent)) != 0){
433 c = getclient(e->window, 1);
434 if(c != 0 && (c->dx == 0 || c->dy == 0)){
435 /* flush any errors */
436 ignore_badwindow = 1;
437 XGetWindowAttributes(dpy, c->window, &attr);
438 XSync(dpy, False);
439 ignore_badwindow = 0;
441 c->x = attr.x;
442 c->y = attr.y;
443 c->dx = attr.width;
444 c->dy = attr.height;
445 c->border = attr.border_width;
446 c->screen = s;
447 if(c->parent == None)
448 c->parent = c->screen->root;
451 else {
452 c = getclient(e->window, 0);
453 if(c != 0 && (c->parent == c->screen->root || withdrawn(c)))
454 rmclient(c);
458 #ifdef SHAPE
459 void
460 shapenotify(XShapeEvent *e)
462 Client *c;
464 /* we don't set curtime as nothing here uses it */
465 c = getclient(e->window, 0);
466 if(c == 0)
467 return;
469 setshape(c);
471 #endif
473 void
474 enter(XCrossingEvent *e)
476 Client *c;
478 curtime = e->time;
479 if(!ffm)
480 if(e->mode != NotifyGrab || e->detail != NotifyNonlinearVirtual)
481 return;
482 c = getclient(e->window, 0);
483 if(c != 0 && c != current){
484 /* someone grabbed the pointer; make them current */
485 if(!ffm)
486 XMapRaised(dpy, c->parent);
487 top(c);
488 active(c);
492 void
493 leave(XCrossingEvent *e)
495 Client *c;
497 c = getclient(e->window, 0);
498 if(c)
499 XUndefineCursor(dpy, c->parent);
500 /* XDefineCursor(dpy, c->parent, c->screen->arrow); */
503 void
504 focusin(XFocusChangeEvent *e)
506 Client *c;
508 curtime = CurrentTime;
509 if(e->detail != NotifyNonlinearVirtual)
510 return;
511 c = getclient(e->window, 0);
512 if(c != 0 && c->window == e->window && c != current){
513 /* someone grabbed keyboard or seized focus; make them current */
514 XMapRaised(dpy, c->parent);
515 top(c);
516 active(c);
520 BorderOrient
521 borderorient(Client *c, int x, int y)
523 if(x <= BORDER){
524 if(y <= CORNER){
525 if(debug) fprintf(stderr, "topleft\n");
526 return BorderWNW;
528 if(y >= (c->dy + 2*BORDER) - CORNER){
529 if(debug) fprintf(stderr, "botleft\n");
530 return BorderWSW;
532 if(y > CORNER &&
533 y < (c->dy + 2*BORDER) - CORNER){
534 if(debug) fprintf(stderr, "left\n");
535 return BorderW;
537 } else if(x <= CORNER){
538 if(y <= BORDER){
539 if(debug) fprintf(stderr, "topleft\n");
540 return BorderNNW;
542 if (y >= (c->dy + BORDER)){
543 if(debug) fprintf(stderr, "botleft\n");
544 return BorderSSW;
546 } else if(x >= (c->dx + BORDER)){
547 if(y <= CORNER){
548 if(debug) fprintf(stderr, "topright\n");
549 return BorderENE;
551 if(y >= (c->dy + 2*BORDER) - CORNER){
552 if(debug) fprintf(stderr, "botright\n");
553 return BorderESE;
555 if(y > CORNER &&
556 y < (c->dy + 2*BORDER) - CORNER){
557 if(debug) fprintf(stderr, "right\n");
558 return BorderE;
560 } else if(x >= (c->dx + 2*BORDER) - CORNER){
561 if(y <= BORDER){
562 if(debug) fprintf(stderr, "topright\n");
563 return BorderNNE;
565 if (y >= (c->dy + BORDER)){
566 if(debug) fprintf(stderr, "botright\n");
567 return BorderSSE;
569 } else if(x > CORNER &&
570 x < (c->dx + 2*BORDER) - CORNER){
571 if(y <= BORDER){
572 if(debug) fprintf(stderr, "top\n");
573 return BorderN;
575 if(y >= (c->dy + BORDER)){
576 if(debug) fprintf(stderr, "bot\n");
577 return BorderS;
580 return BorderUnknown;
583 void
584 motionnotify(XMotionEvent *e)
586 Client *c;
587 BorderOrient bl;
589 c = getclient(e->window, 0);
590 if(c){
591 bl = borderorient(c, e->x, e->y);
592 if(bl == BorderUnknown)
593 XUndefineCursor(dpy, c->parent);
594 else
595 XDefineCursor(dpy, c->parent, c->screen->bordcurs[bl]);