| /* Copyright (c) 1994-1996 David Hogan, see README for licence details */ | 
 | #include <stdio.h> | 
 | #include <unistd.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 | #include <X11/X.h> | 
 | #include <X11/Xlib.h> | 
 | #include <X11/Xutil.h> | 
 | #include "dat.h" | 
 | #include "fns.h" | 
 |  | 
 | Client	*clients; | 
 | Client	*current; | 
 |  | 
 | void | 
 | setactive(Client *c, int on) | 
 | { | 
 | /*	dbg("setactive client %x %d", c->window, c->on); */ | 
 |  | 
 | 	if(c->parent == c->screen->root) | 
 | 		return; | 
 | 	 | 
 | 	if(on){ | 
 | 		XUngrabButton(dpy, AnyButton, AnyModifier, c->parent); | 
 | 		XSetInputFocus(dpy, c->window, RevertToPointerRoot, timestamp()); | 
 | 		if(c->proto & Ptakefocus) | 
 | 			sendcmessage(c->window, wm_protocols, wm_take_focus, 0, 1); | 
 | 		cmapfocus(c); | 
 | 	}else{ | 
 | 		if(c->proto & Plosefocus) | 
 | 			sendcmessage(c->window, wm_protocols, wm_lose_focus, 0, 1); | 
 | 		XGrabButton(dpy, AnyButton, AnyModifier, c->parent, False, | 
 | 			ButtonMask, GrabModeAsync, GrabModeSync, None, None); | 
 | 	} | 
 | 	draw_border(c, on); | 
 | } | 
 |  | 
 | void | 
 | draw_border(Client *c, int active) | 
 | { | 
 | 	unsigned long pixel; | 
 |  | 
 | 	if(active){ | 
 | 		if(c->hold) | 
 | 			pixel = c->screen->activeholdborder; | 
 | 		else | 
 | 			pixel = c->screen->activeborder; | 
 | 	}else{ | 
 | 		if(c->hold) | 
 | 			pixel = c->screen->inactiveholdborder; | 
 | 		else | 
 | 			pixel = c->screen->inactiveborder; | 
 | 	} | 
 |  | 
 | 	if(debug) fprintf(stderr, "draw_border %p pixel %ld active %d hold %d\n", (void*)c, pixel, active, c->hold); | 
 | 	XSetWindowBackground(dpy, c->parent, pixel); | 
 | 	XClearWindow(dpy, c->parent); | 
 | } | 
 |  | 
 | void | 
 | active(Client *c) | 
 | { | 
 | 	Client *cc; | 
 |  | 
 | 	if(c == 0){ | 
 | 		fprintf(stderr, "rio: active(c==0)\n"); | 
 | 		return; | 
 | 	} | 
 | 	if(c == current) | 
 | 		return; | 
 | 	if(current){ | 
 | 		setactive(current, 0); | 
 | 		if(current->screen != c->screen) | 
 | 			cmapnofocus(current->screen); | 
 | 	} | 
 | 	setactive(c, 1); | 
 | 	for(cc = clients; cc; cc = cc->next) | 
 | 		if(cc->revert == c) | 
 | 			cc->revert = c->revert; | 
 | 	c->revert = current; | 
 | 	while(c->revert && !normal(c->revert)) | 
 | 		c->revert = c->revert->revert; | 
 | 	current = c; | 
 | #ifdef	DEBUG | 
 | 	if(debug) | 
 | 		dump_revert(); | 
 | #endif | 
 | } | 
 |  | 
 | void | 
 | nofocus(void) | 
 | { | 
 | 	static Window w = 0; | 
 | 	int mask; | 
 | 	XSetWindowAttributes attr; | 
 | 	Client *c; | 
 |  | 
 | 	if(current){ | 
 | 		setactive(current, 0); | 
 | 		for(c = current->revert; c; c = c->revert) | 
 | 			if(normal(c)){ | 
 | 				active(c); | 
 | 				return; | 
 | 			} | 
 | 		cmapnofocus(current->screen); | 
 | 		/* if no candidates to revert to, fall through */ | 
 | 	} | 
 | 	current = 0; | 
 | 	if(w == 0){ | 
 | 		mask = CWOverrideRedirect/*|CWColormap*/; | 
 | 		attr.override_redirect = 1; | 
 | 		/* attr.colormap = screens[0].def_cmap;*/ | 
 | 		w = XCreateWindow(dpy, screens[0].root, 0, 0, 1, 1, 0, | 
 | 			0 /*screens[0].depth*/, InputOnly, 	screens[0].vis, mask, &attr); | 
 | 		XMapWindow(dpy, w); | 
 | 	} | 
 | 	XSetInputFocus(dpy, w, RevertToPointerRoot, timestamp()); | 
 | } | 
 |  | 
 | void | 
 | top(Client *c) | 
 | { | 
 | 	Client **l, *cc; | 
 |  | 
 | 	l = &clients; | 
 | 	for(cc = *l; cc; cc = *l){ | 
 | 		if(cc == c){ | 
 | 			*l = c->next; | 
 | 			c->next = clients; | 
 | 			clients = c; | 
 | 			return; | 
 | 		} | 
 | 		l = &cc->next; | 
 | 	} | 
 | 	fprintf(stderr, "rio: %p not on client list in top()\n", (void*)c); | 
 | } | 
 |  | 
 | Client * | 
 | getclient(Window w, int create) | 
 | { | 
 | 	Client *c; | 
 |  | 
 | 	if(w == 0 || getscreen(w)) | 
 | 		return 0; | 
 |  | 
 | 	for(c = clients; c; c = c->next) | 
 | 		if(c->window == w || c->parent == w) | 
 | 			return c; | 
 |  | 
 | 	if(!create) | 
 | 		return 0; | 
 |  | 
 | 	c = (Client *)malloc(sizeof(Client)); | 
 | 	memset(c, 0, sizeof(Client)); | 
 | 	c->window = w; | 
 | 	/* c->parent will be set by the caller */ | 
 | 	c->parent = None; | 
 | 	c->reparenting = 0; | 
 | 	c->state = WithdrawnState; | 
 | 	c->init = 0; | 
 | 	c->cmap = None; | 
 | 	c->label = c->class = 0; | 
 | 	c->revert = 0; | 
 | 	c->is9term = 0; | 
 | 	c->hold = 0; | 
 | 	c->ncmapwins = 0; | 
 | 	c->cmapwins = 0; | 
 | 	c->wmcmaps = 0; | 
 | 	c->next = clients; | 
 | 	c->virt = virt; | 
 | 	clients = c; | 
 | 	return c; | 
 | } | 
 |  | 
 | void | 
 | rmclient(Client *c) | 
 | { | 
 | 	Client *cc; | 
 |  | 
 | 	for(cc = current; cc && cc->revert; cc = cc->revert) | 
 | 		if(cc->revert == c) | 
 | 			cc->revert = cc->revert->revert; | 
 |  | 
 | 	if(c == clients) | 
 | 		clients = c->next; | 
 | 	for(cc = clients; cc && cc->next; cc = cc->next) | 
 | 		if(cc->next == c) | 
 | 			cc->next = cc->next->next; | 
 |  | 
 | 	if(hidden(c)) | 
 | 		unhidec(c, 0); | 
 |  | 
 | 	if(c->parent != c->screen->root) | 
 | 		XDestroyWindow(dpy, c->parent); | 
 |  | 
 | 	c->parent = c->window = None;		/* paranoia */ | 
 | 	if(current == c){ | 
 | 		current = c->revert; | 
 | 		if(current == 0) | 
 | 			nofocus(); | 
 | 		else { | 
 | 			if(current->screen != c->screen) | 
 | 				cmapnofocus(c->screen); | 
 | 			setactive(current, 1); | 
 | 		} | 
 | 	} | 
 | 	if(c->ncmapwins != 0){ | 
 | 		XFree((char *)c->cmapwins); | 
 | 		free((char *)c->wmcmaps); | 
 | 	} | 
 | 	if(c->iconname != 0) | 
 | 		XFree((char*) c->iconname); | 
 | 	if(c->name != 0) | 
 | 		XFree((char*) c->name); | 
 | 	if(c->instance != 0) | 
 | 		XFree((char*) c->instance); | 
 | 	if(c->class != 0) | 
 | 		XFree((char*) c->class); | 
 | 	memset(c, 0, sizeof(Client));		/* paranoia */ | 
 | 	free(c); | 
 | } | 
 |  | 
 | #ifdef	DEBUG | 
 | void | 
 | dump_revert(void) | 
 | { | 
 | 	Client *c; | 
 | 	int i; | 
 |  | 
 | 	i = 0; | 
 | 	for(c = current; c; c = c->revert){ | 
 | 		fprintf(stderr, "%s(%x:%d)", c->label ? c->label : "?", (int)c->window, c->state); | 
 | 		if(i++ > 100) | 
 | 			break; | 
 | 		if(c->revert) | 
 | 			fprintf(stderr, " -> "); | 
 | 	} | 
 | 	if(current == 0) | 
 | 		fprintf(stderr, "empty"); | 
 | 	fprintf(stderr, "\n"); | 
 | } | 
 |  | 
 | void | 
 | dump_clients(void) | 
 | { | 
 | 	Client *c; | 
 |  | 
 | 	for(c = clients; c; c = c->next) | 
 | 		fprintf(stderr, "w 0x%x parent 0x%x @ (%d, %d)\n", (int)c->window, (int)c->parent, c->x, c->y); | 
 | } | 
 | #endif | 
 |  | 
 | void | 
 | shuffle(int up) | 
 | { | 
 | 	Client **l, *c; | 
 | 	 | 
 | 	if(clients == 0 || clients->next == 0) | 
 | 		return; | 
 | 	if(!up){ | 
 | 		c = 0; | 
 | 		/*for(c=clients; c->next; c=c->next) */ | 
 | 		/*	; */ | 
 | 		for(l=&clients; (*l)->next; l=&(*l)->next) | 
 | 			if ((*l)->state == 1) | 
 | 				c = *l; | 
 | 		if (c == 0) | 
 | 			return; | 
 | 		XMapRaised(dpy, c->parent); | 
 | 		top(c); | 
 | 		active(c); | 
 | 	}else{ | 
 | 		c = clients; | 
 | 		for(l=&clients; *l; l=&(*l)->next) | 
 | 			; | 
 | 		clients = c->next; | 
 | 		*l = c; | 
 | 		c->next = 0; | 
 | 		XLowerWindow(dpy, c->window); | 
 | 	} | 
 | /*	XMapRaised(dpy, clients->parent); */ | 
 | /*	top(clients);	 */ | 
 | /*	active(clients); */ | 
 | } | 
 |  |