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"
13 
14 void
mainloop(int shape_event)15 mainloop(int shape_event)
16 {
17 	XEvent ev;
18 
19 	for(;;){
20 		getevent(&ev);
21 
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;
109 		}
110 	}
111 }
112 
113 
114 void
configurereq(XConfigureRequestEvent * e)115 configurereq(XConfigureRequestEvent *e)
116 {
117 	XWindowChanges wc;
118 	Client *c;
119 
120 	/* we don't set curtime as nothing here uses it */
121 	c = getclient(e->window, 0);
122 	trace("configurereq", c, e);
123 
124 	e->value_mask &= ~CWSibling;
125 
126 	if(c){
127 		if(e->value_mask & CWX)
128 			c->x = e->x;
129 		if(e->value_mask & CWY)
130 			c->y = e->y;
131 		if(e->value_mask & CWWidth)
132 			c->dx = e->width;
133 		if(e->value_mask & CWHeight)
134 			c->dy = e->height;
135 		if(e->value_mask & CWBorderWidth)
136 			c->border = e->border_width;
137 
138 		if(c->dx >= c->screen->width && c->dy >= c->screen->height)
139 			c->border = 0;
140 		else
141 			c->border = BORDER;
142 
143 		if(e->value_mask & CWStackMode){
144 			if(e->detail == Above)
145 				top(c);
146 			else
147 				e->value_mask &= ~CWStackMode;
148 		}
149 		e->value_mask |= CWX|CWY|CWHeight|CWWidth;
150 
151 		if(c->parent != c->screen->root && c->window == e->window){
152 			wc.x = c->x - c->border;
153 			wc.y = c->y - c->border;
154 			wc.width = c->dx+c->border+c->border;
155 			wc.height = c->dy+c->border+c->border;
156 			wc.border_width = 1;
157 			wc.sibling = None;
158 			wc.stack_mode = e->detail;
159 			XConfigureWindow(dpy, c->parent, e->value_mask, &wc);
160 
161 			if(e->value_mask & CWStackMode){
162 				top(c);
163 				active(c);
164 			}
165 		}
166 	}
167 
168 	if(c && c->parent != c->screen->root){
169 		wc.x = c->border;
170 		wc.y = c->border;
171 	}else {
172 		wc.x = c->x;
173 		wc.y = c->y;
174 	}
175 	wc.width = c->dx;
176 	wc.height = c->dy;
177 	wc.border_width = 0;
178 	wc.sibling = None;
179 	wc.stack_mode = Above;
180 	e->value_mask &= ~CWStackMode;
181 	e->value_mask |= CWBorderWidth;
182 	XConfigureWindow(dpy, c->window, e->value_mask, &wc);
183 }
184 
185 void
mapreq(XMapRequestEvent * e)186 mapreq(XMapRequestEvent *e)
187 {
188 	Client *c;
189 	int i;
190 
191 	curtime = CurrentTime;
192 	c = getclient(e->window, 0);
193 	trace("mapreq", c, e);
194 
195 	if(c == 0 || c->window != e->window){
196 		/* workaround for stupid NCDware */
197 		fprintf(stderr, "rio: bad mapreq c %p w %x, rescanning\n",
198 			(void*)c, (int)e->window);
199 		for(i = 0; i < num_screens; i++)
200 			scanwins(&screens[i]);
201 		c = getclient(e->window, 0);
202 		if(c == 0 || c->window != e->window){
203 			fprintf(stderr, "rio: window not found after rescan\n");
204 			return;
205 		}
206 	}
207 
208 	switch (c->state){
209 	case WithdrawnState:
210 		if(c->parent == c->screen->root){
211 			if(!manage(c, 0))
212 				return;
213 			break;
214 		}
215 		XReparentWindow(dpy, c->window, c->parent, BORDER-1, BORDER-1);
216 		XAddToSaveSet(dpy, c->window);
217 		/* fall through... */
218 	case NormalState:
219 		XMapWindow(dpy, c->window);
220 		XMapRaised(dpy, c->parent);
221 		top(c);
222 		setstate(c, NormalState);
223 		if(c->trans != None && current && c->trans == current->window)
224 				active(c);
225 		break;
226 	case IconicState:
227 		unhidec(c, 1);
228 		break;
229 	}
230 }
231 
232 void
unmap(XUnmapEvent * e)233 unmap(XUnmapEvent *e)
234 {
235 	Client *c;
236 
237 	curtime = CurrentTime;
238 	c = getclient(e->window, 0);
239 	if(c){
240 		switch (c->state){
241 		case IconicState:
242 			if(e->send_event){
243 				unhidec(c, 0);
244 				withdraw(c);
245 			}
246 			break;
247 		case NormalState:
248 			if(c == current)
249 				nofocus();
250 			if(!c->reparenting)
251 				withdraw(c);
252 			break;
253 		}
254 		c->reparenting = 0;
255 	}
256 }
257 
258 void
circulatereq(XCirculateRequestEvent * e)259 circulatereq(XCirculateRequestEvent *e)
260 {
261 	fprintf(stderr, "It must be the warlock Krill!\n");  /* ☺ */
262 }
263 
264 void
newwindow(XCreateWindowEvent * e)265 newwindow(XCreateWindowEvent *e)
266 {
267 	Client *c;
268 	ScreenInfo *s;
269 
270 	/* we don't set curtime as nothing here uses it */
271 	if(e->override_redirect)
272 		return;
273 	c = getclient(e->window, 1);
274 	if(c && c->window == e->window && (s = getscreen(e->parent))){
275 		c->x = e->x;
276 		c->y = e->y;
277 		c->dx = e->width;
278 		c->dy = e->height;
279 		c->border = e->border_width;
280 		c->screen = s;
281 		if(c->parent == None)
282 			c->parent = c->screen->root;
283 	}
284 }
285 
286 void
destroy(Window w)287 destroy(Window w)
288 {
289 	int i;
290 	Client *c;
291 
292 	curtime = CurrentTime;
293 	c = getclient(w, 0);
294 	if(c == 0)
295 		return;
296 
297 	if(numvirtuals > 1)
298 		for(i=0; i<numvirtuals; i++)
299 			if(currents[i] == c)
300 				currents[i] = 0;
301 
302 	rmclient(c);
303 
304 	/* flush any errors generated by the window's sudden demise */
305 	ignore_badwindow = 1;
306 	XSync(dpy, False);
307 	ignore_badwindow = 0;
308 }
309 
310 void
clientmesg(XClientMessageEvent * e)311 clientmesg(XClientMessageEvent *e)
312 {
313 	Client *c;
314 
315 	curtime = CurrentTime;
316 	if(e->message_type == exit_rio){
317 		cleanup();
318 		exit(0);
319 	}
320 	if(e->message_type == restart_rio){
321 		fprintf(stderr, "*** rio restarting ***\n");
322 		cleanup();
323 		execvp(myargv[0], myargv);
324 		perror("rio: exec failed");
325 		exit(1);
326 	}
327 	if(e->message_type == wm_protocols)
328 		return;
329 	if(e->message_type == wm_change_state){
330 		c = getclient(e->window, 0);
331 		if(e->format == 32 && e->data.l[0] == IconicState && c != 0){
332 			if(normal(c))
333 				hide(c);
334 		}
335 		else
336 			fprintf(stderr, "rio: WM_CHANGE_STATE: format %d data %d w 0x%x\n",
337 				(int)e->format, (int)e->data.l[0], (int)e->window);
338 		return;
339 	}
340 	if(e->message_type == wm_state){
341 //		c = getclient(e->window, 0);
342 //		if(e->format == 32 && e->data.l[1] == wm_state_fullscreen){
343 //		}else
344 		fprintf(stderr, "rio: WM_STATE: format %d data %d %d w 0x%x\n",
345 			(int)e->format, (int)e->data.l[0], (int)e->data.l[1],
346 			(int)e->window);
347 		return;
348 	}
349 	fprintf(stderr, "rio: strange ClientMessage, type 0x%x window 0x%x\n",
350 		(int)e->message_type, (int)e->window);
351 }
352 
353 void
cmap(XColormapEvent * e)354 cmap(XColormapEvent *e)
355 {
356 	Client *c;
357 	int i;
358 
359 	/* we don't set curtime as nothing here uses it */
360 	if(e->new){
361 		c = getclient(e->window, 0);
362 		if(c){
363 			c->cmap = e->colormap;
364 			if(c == current)
365 				cmapfocus(c);
366 		}
367 		else
368 			for(c = clients; c; c = c->next){
369 				for(i = 0; i < c->ncmapwins; i++)
370 					if(c->cmapwins[i] == e->window){
371 						c->wmcmaps[i] = e->colormap;
372 						if(c == current)
373 							cmapfocus(c);
374 						return;
375 					}
376 			}
377 	}
378 }
379 
380 void
property(XPropertyEvent * e)381 property(XPropertyEvent *e)
382 {
383 	Atom a;
384 	int delete;
385 	Client *c;
386 	long msize;
387 
388 	/* we don't set curtime as nothing here uses it */
389 	a = e->atom;
390 	delete = (e->state == PropertyDelete);
391 	c = getclient(e->window, 0);
392 	if(c == 0)
393 		return;
394 
395 	switch (a){
396 	case XA_WM_ICON_NAME:
397 		if(c->iconname != 0)
398 			XFree((char*) c->iconname);
399 		c->iconname = delete ? 0 : getprop(c->window, a);
400 		setlabel(c);
401 		renamec(c, c->label);
402 		return;
403 	case XA_WM_NAME:
404 		if(c->name != 0)
405 			XFree((char*) c->name);
406 		c->name = delete ? 0 : getprop(c->window, a);
407 		setlabel(c);
408 		renamec(c, c->label);
409 		return;
410 	case XA_WM_TRANSIENT_FOR:
411 		gettrans(c);
412 		return;
413 	case XA_WM_HINTS:
414 	case XA_WM_SIZE_HINTS:
415 	case XA_WM_ZOOM_HINTS:
416 		/* placeholders to not forget.  ignore for now.  -Axel */
417 		return;
418 	case XA_WM_NORMAL_HINTS:
419 		if(XGetWMNormalHints(dpy, c->window, &c->size, &msize) == 0 || c->size.flags == 0)
420 			c->size.flags = PSize;	/* not specified - punt */
421 		return;
422 	}
423 	if(a == _rio_hold_mode){
424 		c->hold = getiprop(c->window, _rio_hold_mode);
425 		if(c == current)
426 			draw_border(c, 1);
427 	}
428 	else if(a == wm_colormaps){
429 		getcmaps(c);
430 		if(c == current)
431 			cmapfocus(c);
432 	}
433 }
434 
435 void
reparent(XReparentEvent * e)436 reparent(XReparentEvent *e)
437 {
438 	Client *c;
439 	XWindowAttributes attr;
440 	ScreenInfo *s;
441 
442 	/* we don't set curtime as nothing here uses it */
443 	if(!getscreen(e->event) || e->override_redirect)
444 		return;
445 	if((s = getscreen(e->parent)) != 0){
446 		c = getclient(e->window, 1);
447 		if(c != 0 && (c->dx == 0 || c->dy == 0)){
448 			/* flush any errors */
449 			ignore_badwindow = 1;
450 			XGetWindowAttributes(dpy, c->window, &attr);
451 			XSync(dpy, False);
452 			ignore_badwindow = 0;
453 
454 			c->x = attr.x;
455 			c->y = attr.y;
456 			c->dx = attr.width;
457 			c->dy = attr.height;
458 			c->border = attr.border_width;
459 			c->screen = s;
460 			if(c->parent == None)
461 				c->parent = c->screen->root;
462 		}
463 	}
464 	else {
465 		c = getclient(e->window, 0);
466 		if(c != 0 && (c->parent == c->screen->root || withdrawn(c)))
467 			rmclient(c);
468 	}
469 }
470 
471 #ifdef	SHAPE
472 void
shapenotify(XShapeEvent * e)473 shapenotify(XShapeEvent *e)
474 {
475 	Client *c;
476 
477 	/* we don't set curtime as nothing here uses it */
478 	c = getclient(e->window, 0);
479 	if(c == 0)
480 		return;
481 
482 	setshape(c);
483 }
484 #endif
485 
486 void
enter(XCrossingEvent * e)487 enter(XCrossingEvent *e)
488 {
489 	Client *c;
490 
491 	curtime = e->time;
492 	if(!ffm)
493 	if(e->mode != NotifyGrab || e->detail != NotifyNonlinearVirtual)
494 		return;
495 	c = getclient(e->window, 0);
496 	if(c != 0 && c != current){
497 		/* someone grabbed the pointer; make them current */
498 		if(!ffm)
499 			XMapRaised(dpy, c->parent);
500 		top(c);
501 		active(c);
502 	}
503 }
504 
505 void
leave(XCrossingEvent * e)506 leave(XCrossingEvent *e)
507 {
508 	Client *c;
509 
510 	c = getclient(e->window, 0);
511 	if(c)
512 		XUndefineCursor(dpy, c->parent);
513 /* 	XDefineCursor(dpy, c->parent, c->screen->arrow); */
514 }
515 
516 void
focusin(XFocusChangeEvent * e)517 focusin(XFocusChangeEvent *e)
518 {
519 	Client *c;
520 
521 	curtime = CurrentTime;
522 	if(e->detail != NotifyNonlinearVirtual)
523 		return;
524 	c = getclient(e->window, 0);
525 	if(c != 0 && c->window == e->window && c != current){
526 		/* someone grabbed keyboard or seized focus; make them current */
527 		XMapRaised(dpy, c->parent);
528 		top(c);
529 		active(c);
530 	}
531 }
532 
533 BorderOrient
borderorient(Client * c,int x,int y)534 borderorient(Client *c, int x, int y)
535 {
536 	if(x <= BORDER){
537 		if(y <= CORNER){
538 			if(debug) fprintf(stderr, "topleft\n");
539 			return BorderWNW;
540 		}
541 		if(y >= (c->dy + 2*BORDER) - CORNER){
542 			if(debug) fprintf(stderr, "botleft\n");
543 			return BorderWSW;
544 		}
545 		if(y > CORNER &&
546 			y < (c->dy + 2*BORDER) - CORNER){
547 			if(debug) fprintf(stderr, "left\n");
548 			return BorderW;
549 		}
550 	} else if(x <= CORNER){
551 		if(y <= BORDER){
552 			if(debug) fprintf(stderr, "topleft\n");
553 			return BorderNNW;
554 		}
555 		if  (y >= (c->dy + BORDER)){
556 			if(debug) fprintf(stderr, "botleft\n");
557 			return BorderSSW;
558 		}
559 	} else if(x >= (c->dx + BORDER)){
560 		if(y <= CORNER){
561 			if(debug) fprintf(stderr, "topright\n");
562 			return BorderENE;
563 		}
564 		if(y >= (c->dy + 2*BORDER) - CORNER){
565 			if(debug) fprintf(stderr, "botright\n");
566 			return BorderESE;
567 		}
568 		if(y > CORNER &&
569 			y < (c->dy + 2*BORDER) - CORNER){
570 			if(debug) fprintf(stderr, "right\n");
571 			return BorderE;
572 		}
573 	} else if(x >= (c->dx + 2*BORDER) - CORNER){
574 		if(y <= BORDER){
575 			if(debug) fprintf(stderr, "topright\n");
576 			return BorderNNE;
577 		}
578 		if  (y >= (c->dy + BORDER)){
579 			if(debug) fprintf(stderr, "botright\n");
580 			return BorderSSE;
581 		}
582 	} else if(x > CORNER &&
583 			x < (c->dx + 2*BORDER) - CORNER){
584 		if(y <= BORDER){
585 			if(debug) fprintf(stderr, "top\n");
586 			return BorderN;
587 		}
588 		if(y >= (c->dy + BORDER)){
589 			if(debug) fprintf(stderr, "bot\n");
590 			return BorderS;
591 		}
592 	}
593 	return BorderUnknown;
594 }
595 
596 void
motionnotify(XMotionEvent * e)597 motionnotify(XMotionEvent *e)
598 {
599 	Client *c;
600 	BorderOrient bl;
601 
602 	c = getclient(e->window, 0);
603 	if(c){
604 		bl = borderorient(c, e->x, e->y);
605 		if(bl == BorderUnknown)
606 			XUndefineCursor(dpy, c->parent);
607 		else
608 			XDefineCursor(dpy, c->parent, c->screen->bordcurs[bl]);
609 	}
610 }
611