10bbfda8aSnia/*
20bbfda8aSnia * Colormap handling
30bbfda8aSnia */
40bbfda8aSnia
50bbfda8aSnia#include "ctwm.h"
60bbfda8aSnia
70bbfda8aSnia#include <stdio.h>
80bbfda8aSnia#include <stdlib.h>
90bbfda8aSnia
100bbfda8aSnia#include "colormaps.h"
110bbfda8aSnia#include "screen.h"
120bbfda8aSnia
130bbfda8aSnia
140bbfda8aSnia/*
150bbfda8aSnia * From events.c; imported manually since I'm not listing it in events.h
160bbfda8aSnia * because nowhere but here needs it.
170bbfda8aSnia */
180bbfda8aSniaextern bool ColortableThrashing;
190bbfda8aSnia
200bbfda8aSniastatic Bool UninstallRootColormapQScanner(Display *display, XEvent *ev,
210bbfda8aSnia                char *args);
220bbfda8aSnia
230bbfda8aSnia
240bbfda8aSnia/***********************************************************************
250bbfda8aSnia *
260bbfda8aSnia *  Procedure:
270bbfda8aSnia *      InstallWindowColormaps - install the colormaps for one twm window
280bbfda8aSnia *
290bbfda8aSnia *  Inputs:
300bbfda8aSnia *      type    - type of event that caused the installation
310bbfda8aSnia *      tmp     - for a subset of event types, the address of the
320bbfda8aSnia *                window structure, whose colormaps are to be installed.
330bbfda8aSnia *
340bbfda8aSnia ***********************************************************************
350bbfda8aSnia *
360bbfda8aSnia * Previously in events.c
370bbfda8aSnia */
380bbfda8aSniabool
390bbfda8aSniaInstallWindowColormaps(int type, TwmWindow *tmp)
400bbfda8aSnia{
410bbfda8aSnia	if(tmp) {
420bbfda8aSnia		return InstallColormaps(type, &tmp->cmaps);
430bbfda8aSnia	}
440bbfda8aSnia	else {
450bbfda8aSnia		return InstallColormaps(type, NULL);
460bbfda8aSnia	}
470bbfda8aSnia}
480bbfda8aSnia
490bbfda8aSnia
500bbfda8aSniabool
510bbfda8aSniaInstallColormaps(int type, Colormaps *cmaps)
520bbfda8aSnia{
530bbfda8aSnia	int i, j, n, number_cwins, state;
540bbfda8aSnia	ColormapWindow **cwins, *cwin, **maxcwin = NULL;
550bbfda8aSnia	TwmColormap *cmap;
560bbfda8aSnia	char *row, *scoreboard;
570bbfda8aSnia
580bbfda8aSnia	switch(type) {
590bbfda8aSnia		case EnterNotify:
600bbfda8aSnia		case LeaveNotify:
610bbfda8aSnia		case DestroyNotify:
620bbfda8aSnia		default:
630bbfda8aSnia			/* Save the colormap to be loaded for when force loading of
640bbfda8aSnia			 * root colormap(s) ends.
650bbfda8aSnia			 */
660bbfda8aSnia			Scr->cmapInfo.pushed_cmaps = cmaps;
670bbfda8aSnia			/* Don't load any new colormap if root colormap(s) has been
680bbfda8aSnia			 * force loaded.
690bbfda8aSnia			 */
700bbfda8aSnia			if(Scr->cmapInfo.root_pushes) {
710bbfda8aSnia				return false;
720bbfda8aSnia			}
730bbfda8aSnia			/* Don't reload the current window colormap list.
740bbfda8aSnia			if (Scr->cmapInfo.cmaps == cmaps)
750bbfda8aSnia			    return false;
760bbfda8aSnia			 */
770bbfda8aSnia			if(Scr->cmapInfo.cmaps) {
780bbfda8aSnia				for(i = Scr->cmapInfo.cmaps->number_cwins,
790bbfda8aSnia				                cwins = Scr->cmapInfo.cmaps->cwins; i-- > 0; cwins++) {
800bbfda8aSnia					(*cwins)->colormap->state &= ~CM_INSTALLABLE;
810bbfda8aSnia				}
820bbfda8aSnia			}
830bbfda8aSnia			Scr->cmapInfo.cmaps = cmaps;
840bbfda8aSnia			break;
850bbfda8aSnia
860bbfda8aSnia		case PropertyNotify:
870bbfda8aSnia		case VisibilityNotify:
880bbfda8aSnia		case ColormapNotify:
890bbfda8aSnia			break;
900bbfda8aSnia	}
910bbfda8aSnia
920bbfda8aSnia	number_cwins = Scr->cmapInfo.cmaps->number_cwins;
930bbfda8aSnia	cwins = Scr->cmapInfo.cmaps->cwins;
940bbfda8aSnia	scoreboard = Scr->cmapInfo.cmaps->scoreboard;
950bbfda8aSnia
960bbfda8aSnia	ColortableThrashing = false; /* in case installation aborted */
970bbfda8aSnia
980bbfda8aSnia	state = CM_INSTALLED;
990bbfda8aSnia
100b18c2d1eSnia	for(i = 0; i < number_cwins; i++) {
1010bbfda8aSnia		cwins[i]->colormap->state &= ~CM_INSTALL;
1020bbfda8aSnia	}
1030bbfda8aSnia	for(i = n = 0; i < number_cwins && n < Scr->cmapInfo.maxCmaps; i++) {
1040bbfda8aSnia		cwin = cwins[i];
1050bbfda8aSnia		cmap = cwin->colormap;
1060bbfda8aSnia		if(cmap->state & CM_INSTALL) {
1070bbfda8aSnia			continue;
1080bbfda8aSnia		}
1090bbfda8aSnia		cmap->state |= CM_INSTALLABLE;
1100bbfda8aSnia		cmap->w = cwin->w;
1110bbfda8aSnia		if(cwin->visibility != VisibilityFullyObscured) {
1120bbfda8aSnia			row = scoreboard + (i * (i - 1) / 2);
1130bbfda8aSnia			for(j = 0; j < i; j++)
1140bbfda8aSnia				if(row[j] && (cwins[j]->colormap->state & CM_INSTALL)) {
1150bbfda8aSnia					break;
1160bbfda8aSnia				}
1170bbfda8aSnia			if(j != i) {
1180bbfda8aSnia				continue;
1190bbfda8aSnia			}
1200bbfda8aSnia			n++;
1210bbfda8aSnia			maxcwin = &cwins[i];
1220bbfda8aSnia			state &= (cmap->state & CM_INSTALLED);
1230bbfda8aSnia			cmap->state |= CM_INSTALL;
1240bbfda8aSnia		}
1250bbfda8aSnia	}
126b18c2d1eSnia
127b18c2d1eSnia	// Hack: special-case startup
128b18c2d1eSnia	if(!dpy) {
129b18c2d1eSnia		return true;
130b18c2d1eSnia	}
131b18c2d1eSnia
1320bbfda8aSnia	Scr->cmapInfo.first_req = NextRequest(dpy);
1330bbfda8aSnia
1340bbfda8aSnia	for(; n > 0 && maxcwin >= &cwins[0]; maxcwin--) {
1350bbfda8aSnia		cmap = (*maxcwin)->colormap;
1360bbfda8aSnia		if(cmap->state & CM_INSTALL) {
1370bbfda8aSnia			cmap->state &= ~CM_INSTALL;
1380bbfda8aSnia			if(!(state & CM_INSTALLED)) {
1390bbfda8aSnia				cmap->install_req = NextRequest(dpy);
1400bbfda8aSnia				/* printf ("XInstallColormap : %x, %x\n", cmap, cmap->c); */
1410bbfda8aSnia				XInstallColormap(dpy, cmap->c);
1420bbfda8aSnia			}
1430bbfda8aSnia			cmap->state |= CM_INSTALLED;
1440bbfda8aSnia			n--;
1450bbfda8aSnia		}
1460bbfda8aSnia	}
1470bbfda8aSnia	return true;
1480bbfda8aSnia}
1490bbfda8aSnia
1500bbfda8aSnia
1510bbfda8aSnia
1520bbfda8aSnia/***********************************************************************
1530bbfda8aSnia *
1540bbfda8aSnia *  Procedures:
1550bbfda8aSnia *      <Uni/I>nstallRootColormap - Force (un)loads root colormap(s)
1560bbfda8aSnia *
1570bbfda8aSnia *         These matching routines provide a mechanism to insure that
1580bbfda8aSnia *         the root colormap(s) is installed during operations like
1590bbfda8aSnia *         rubber banding or menu display that require colors from
1600bbfda8aSnia *         that colormap.  Calls may be nested arbitrarily deeply,
1610bbfda8aSnia *         as long as there is one UninstallRootColormap call per
1620bbfda8aSnia *         InstallRootColormap call.
1630bbfda8aSnia *
1640bbfda8aSnia *         The final UninstallRootColormap will cause the colormap list
1650bbfda8aSnia *         which would otherwise have be loaded to be loaded, unless
1660bbfda8aSnia *         Enter or Leave Notify events are queued, indicating some
1670bbfda8aSnia *         other colormap list would potentially be loaded anyway.
1680bbfda8aSnia ***********************************************************************
1690bbfda8aSnia *
1700bbfda8aSnia * Previously in events.c
1710bbfda8aSnia */
1720bbfda8aSniavoid
1730bbfda8aSniaInstallRootColormap(void)
1740bbfda8aSnia{
1750bbfda8aSnia	Colormaps *tmp;
1760bbfda8aSnia	if(Scr->cmapInfo.root_pushes == 0) {
1770bbfda8aSnia		/*
1780bbfda8aSnia		 * The saving and restoring of cmapInfo.pushed_window here
1790bbfda8aSnia		 * is a slimy way to remember the actual pushed list and
1800bbfda8aSnia		 * not that of the root window.
1810bbfda8aSnia		 */
1820bbfda8aSnia		tmp = Scr->cmapInfo.pushed_cmaps;
1830bbfda8aSnia		InstallColormaps(0, &Scr->RootColormaps);
1840bbfda8aSnia		Scr->cmapInfo.pushed_cmaps = tmp;
1850bbfda8aSnia	}
1860bbfda8aSnia	Scr->cmapInfo.root_pushes++;
1870bbfda8aSnia}
1880bbfda8aSnia
1890bbfda8aSnia
1900bbfda8aSnia/* ARGSUSED*/
1910bbfda8aSniastatic Bool
1920bbfda8aSniaUninstallRootColormapQScanner(Display *display, XEvent *ev,
1930bbfda8aSnia                              char *args)
1940bbfda8aSnia{
1950bbfda8aSnia	if(!*args) {
1960bbfda8aSnia		if(ev->type == EnterNotify) {
1970bbfda8aSnia			if(ev->xcrossing.mode != NotifyGrab) {
1980bbfda8aSnia				*args = 1;
1990bbfda8aSnia			}
2000bbfda8aSnia		}
2010bbfda8aSnia		else if(ev->type == LeaveNotify) {
2020bbfda8aSnia			if(ev->xcrossing.mode == NotifyNormal) {
2030bbfda8aSnia				*args = 1;
2040bbfda8aSnia			}
2050bbfda8aSnia		}
2060bbfda8aSnia	}
2070bbfda8aSnia
2080bbfda8aSnia	return (False);
2090bbfda8aSnia}
2100bbfda8aSnia
2110bbfda8aSnia
2120bbfda8aSniavoid
2130bbfda8aSniaUninstallRootColormap(void)
2140bbfda8aSnia{
2150bbfda8aSnia	char args;
2160bbfda8aSnia	XEvent dummy;
2170bbfda8aSnia
2180bbfda8aSnia	if(Scr->cmapInfo.root_pushes) {
2190bbfda8aSnia		Scr->cmapInfo.root_pushes--;
2200bbfda8aSnia	}
2210bbfda8aSnia
2220bbfda8aSnia	if(!Scr->cmapInfo.root_pushes) {
2230bbfda8aSnia		/*
2240bbfda8aSnia		 * If we have subsequent Enter or Leave Notify events,
2250bbfda8aSnia		 * we can skip the reload of pushed colormaps.
2260bbfda8aSnia		 */
2270bbfda8aSnia		XSync(dpy, 0);
2280bbfda8aSnia		args = 0;
2290bbfda8aSnia		XCheckIfEvent(dpy, &dummy, UninstallRootColormapQScanner, &args);
2300bbfda8aSnia
2310bbfda8aSnia		if(!args) {
2320bbfda8aSnia			InstallColormaps(0, Scr->cmapInfo.pushed_cmaps);
2330bbfda8aSnia		}
2340bbfda8aSnia	}
2350bbfda8aSnia}
2360bbfda8aSnia
2370bbfda8aSnia
2380bbfda8aSnia/*
2390bbfda8aSnia * Create a TwmColormap struct and tie it to an [X] Colormap.  Places
2400bbfda8aSnia * that need to mess with colormaps and look up the metainfo we hang off
2410bbfda8aSnia * them need to look this up and find it via the X Context.
2420bbfda8aSnia *
2430bbfda8aSnia * Previously in add_window.c
2440bbfda8aSnia */
2450bbfda8aSniaTwmColormap *
2460bbfda8aSniaCreateTwmColormap(Colormap c)
2470bbfda8aSnia{
2480bbfda8aSnia	TwmColormap *cmap;
2490bbfda8aSnia	cmap = malloc(sizeof(TwmColormap));
250b18c2d1eSnia	if(!cmap) {
251b18c2d1eSnia		return NULL;
2520bbfda8aSnia	}
2530bbfda8aSnia	cmap->c = c;
2540bbfda8aSnia	cmap->state = 0;
2550bbfda8aSnia	cmap->install_req = 0;
2560bbfda8aSnia	cmap->w = None;
2570bbfda8aSnia	cmap->refcnt = 1;
258b18c2d1eSnia
259b18c2d1eSnia	if(XSaveContext(dpy, c, ColormapContext, (XPointer) cmap)) {
260b18c2d1eSnia		free(cmap);
261b18c2d1eSnia		return NULL;
262b18c2d1eSnia	}
2630bbfda8aSnia	return (cmap);
2640bbfda8aSnia}
2650bbfda8aSnia
2660bbfda8aSnia
2670bbfda8aSnia/*
2680bbfda8aSnia * Put together a ColormapWindow struct.  This is a thing we hang off a
2690bbfda8aSnia * TwmWindow for some colormap tracking stuff.
2700bbfda8aSnia *
2710bbfda8aSnia * Previously in add_window.c
2720bbfda8aSnia */
2730bbfda8aSniaColormapWindow *
2740bbfda8aSniaCreateColormapWindow(Window w, bool creating_parent, bool property_window)
2750bbfda8aSnia{
2760bbfda8aSnia	ColormapWindow *cwin;
2770bbfda8aSnia	TwmColormap *cmap;
2780bbfda8aSnia	XWindowAttributes attributes;
2790bbfda8aSnia
2800bbfda8aSnia	cwin = malloc(sizeof(ColormapWindow));
281b18c2d1eSnia	if(cwin == NULL) {
282b18c2d1eSnia		return NULL;
283b18c2d1eSnia	}
2840bbfda8aSnia
285b18c2d1eSnia	// Common
286b18c2d1eSnia	cwin->w = w;
2870bbfda8aSnia
288b18c2d1eSnia	/*
289b18c2d1eSnia	 * Assume that windows in colormap list are
290b18c2d1eSnia	 * obscured if we are creating the parent window.
291b18c2d1eSnia	 * Otherwise, we assume they are unobscured.
292b18c2d1eSnia	 */
293b18c2d1eSnia	cwin->visibility = creating_parent ?
294b18c2d1eSnia	                   VisibilityPartiallyObscured : VisibilityUnobscured;
295b18c2d1eSnia	cwin->refcnt = 1;
2960bbfda8aSnia
297b18c2d1eSnia
298b18c2d1eSnia	// Stub for special cases
299b18c2d1eSnia	if(dpy == NULL) {
300b18c2d1eSnia		cwin->colormap = NULL;
301b18c2d1eSnia		cwin->colormap = calloc(1, sizeof(TwmColormap));
302b18c2d1eSnia		cwin->colormap->refcnt = 1;
303b18c2d1eSnia
304b18c2d1eSnia		return cwin;
305b18c2d1eSnia	}
306b18c2d1eSnia
307b18c2d1eSnia
308b18c2d1eSnia	if(!XGetWindowAttributes(dpy, w, &attributes) ||
309b18c2d1eSnia	                XSaveContext(dpy, w, ColormapContext, (XPointer) cwin)) {
310b18c2d1eSnia		free(cwin);
311b18c2d1eSnia		return (NULL);
312b18c2d1eSnia	}
313b18c2d1eSnia
314b18c2d1eSnia	if(XFindContext(dpy, attributes.colormap,  ColormapContext,
315b18c2d1eSnia	                (XPointer *)&cwin->colormap) == XCNOENT) {
316b18c2d1eSnia		cwin->colormap = cmap = CreateTwmColormap(attributes.colormap);
317b18c2d1eSnia		if(!cmap) {
318b18c2d1eSnia			XDeleteContext(dpy, w, ColormapContext);
319b18c2d1eSnia			free(cwin);
320b18c2d1eSnia			return (NULL);
3210bbfda8aSnia		}
3220bbfda8aSnia	}
323b18c2d1eSnia	else {
324b18c2d1eSnia		cwin->colormap->refcnt++;
325b18c2d1eSnia	}
326b18c2d1eSnia
327b18c2d1eSnia	/*
328b18c2d1eSnia	 * If this is a ColormapWindow property window and we
329b18c2d1eSnia	 * are not monitoring ColormapNotify or VisibilityNotify
330b18c2d1eSnia	 * events, we need to.
331b18c2d1eSnia	 */
332b18c2d1eSnia	if(property_window &&
333b18c2d1eSnia	                (attributes.your_event_mask &
334b18c2d1eSnia	                 (ColormapChangeMask | VisibilityChangeMask)) !=
335b18c2d1eSnia	                (ColormapChangeMask | VisibilityChangeMask)) {
336b18c2d1eSnia		XSelectInput(dpy, w, attributes.your_event_mask |
337b18c2d1eSnia		             (ColormapChangeMask | VisibilityChangeMask));
338b18c2d1eSnia	}
3390bbfda8aSnia
3400bbfda8aSnia	return (cwin);
3410bbfda8aSnia}
3420bbfda8aSnia
3430bbfda8aSnia
3440bbfda8aSnia/*
3450bbfda8aSnia * Do something with looking up stuff from WM_COLORMAPS_WINDOWS (relating
3460bbfda8aSnia * to windows with their own colormap) and finding or putting this window
3470bbfda8aSnia * into it.
3480bbfda8aSnia *
3490bbfda8aSnia * XXX Someone should figure it out better than that...
3500bbfda8aSnia *
3510bbfda8aSnia * Previously in add_window.c
3520bbfda8aSnia */
3530bbfda8aSniavoid
3540bbfda8aSniaFetchWmColormapWindows(TwmWindow *tmp)
3550bbfda8aSnia{
3560bbfda8aSnia	int i, j;
3570bbfda8aSnia	Window *cmap_windows = NULL;
3580bbfda8aSnia	bool can_free_cmap_windows = false;
3590bbfda8aSnia	int number_cmap_windows = 0;
3600bbfda8aSnia	ColormapWindow **cwins = NULL;
3610bbfda8aSnia	bool previnst;
3620bbfda8aSnia
3630bbfda8aSnia	number_cmap_windows = 0;
3640bbfda8aSnia
3650bbfda8aSnia	previnst = (Scr->cmapInfo.cmaps == &tmp->cmaps && tmp->cmaps.number_cwins);
3660bbfda8aSnia	if(previnst) {
3670bbfda8aSnia		cwins = tmp->cmaps.cwins;
3680bbfda8aSnia		for(i = 0; i < tmp->cmaps.number_cwins; i++) {
3690bbfda8aSnia			cwins[i]->colormap->state = 0;
3700bbfda8aSnia		}
3710bbfda8aSnia	}
3720bbfda8aSnia
3730bbfda8aSnia	if(XGetWMColormapWindows(dpy, tmp->w, &cmap_windows,
3740bbfda8aSnia	                         &number_cmap_windows) &&
3750bbfda8aSnia	                number_cmap_windows > 0) {
3760bbfda8aSnia
3770bbfda8aSnia		/*
3780bbfda8aSnia		 * check if the top level is in the list, add to front if not
3790bbfda8aSnia		 */
3800bbfda8aSnia		for(i = 0; i < number_cmap_windows; i++) {
3810bbfda8aSnia			if(cmap_windows[i] == tmp->w) {
3820bbfda8aSnia				break;
3830bbfda8aSnia			}
3840bbfda8aSnia		}
3850bbfda8aSnia		if(i == number_cmap_windows) {   /* not in list */
3860bbfda8aSnia			Window *new_cmap_windows =
3870bbfda8aSnia			        calloc((number_cmap_windows + 1), sizeof(Window));
3880bbfda8aSnia
3890bbfda8aSnia			if(!new_cmap_windows) {
3900bbfda8aSnia				fprintf(stderr,
3910bbfda8aSnia				        "%s:  unable to allocate %d element colormap window array\n",
3920bbfda8aSnia				        ProgramName, number_cmap_windows + 1);
3930bbfda8aSnia				goto done;
3940bbfda8aSnia			}
3950bbfda8aSnia			new_cmap_windows[0] = tmp->w;  /* add to front */
3960bbfda8aSnia			for(i = 0; i < number_cmap_windows; i++) {   /* append rest */
3970bbfda8aSnia				new_cmap_windows[i + 1] = cmap_windows[i];
3980bbfda8aSnia			}
3990bbfda8aSnia			XFree(cmap_windows);
4000bbfda8aSnia			can_free_cmap_windows = true;  /* do not use XFree any more */
4010bbfda8aSnia			cmap_windows = new_cmap_windows;
4020bbfda8aSnia			number_cmap_windows++;
4030bbfda8aSnia		}
4040bbfda8aSnia
4050bbfda8aSnia		cwins = calloc(number_cmap_windows, sizeof(ColormapWindow *));
4060bbfda8aSnia		if(cwins) {
4070bbfda8aSnia			for(i = 0; i < number_cmap_windows; i++) {
4080bbfda8aSnia
4090bbfda8aSnia				/*
4100bbfda8aSnia				 * Copy any existing entries into new list.
4110bbfda8aSnia				 */
4120bbfda8aSnia				for(j = 0; j < tmp->cmaps.number_cwins; j++) {
4130bbfda8aSnia					if(tmp->cmaps.cwins[j]->w == cmap_windows[i]) {
4140bbfda8aSnia						cwins[i] = tmp->cmaps.cwins[j];
4150bbfda8aSnia						cwins[i]->refcnt++;
4160bbfda8aSnia						break;
4170bbfda8aSnia					}
4180bbfda8aSnia				}
4190bbfda8aSnia
4200bbfda8aSnia				/*
4210bbfda8aSnia				 * If the colormap window is not being pointed by
4220bbfda8aSnia				 * some other applications colormap window list,
4230bbfda8aSnia				 * create a new entry.
4240bbfda8aSnia				 */
4250bbfda8aSnia				if(j == tmp->cmaps.number_cwins) {
4260bbfda8aSnia					if(XFindContext(dpy, cmap_windows[i], ColormapContext,
4270bbfda8aSnia					                (XPointer *)&cwins[i]) == XCNOENT) {
4280bbfda8aSnia						if((cwins[i] = CreateColormapWindow(cmap_windows[i],
4290bbfda8aSnia						                                    tmp->cmaps.number_cwins == 0,
4300bbfda8aSnia						                                    true)) == NULL) {
4310bbfda8aSnia							int k;
4320bbfda8aSnia							for(k = i + 1; k < number_cmap_windows; k++) {
4330bbfda8aSnia								cmap_windows[k - 1] = cmap_windows[k];
4340bbfda8aSnia							}
4350bbfda8aSnia							i--;
4360bbfda8aSnia							number_cmap_windows--;
4370bbfda8aSnia						}
4380bbfda8aSnia					}
4390bbfda8aSnia					else {
4400bbfda8aSnia						cwins[i]->refcnt++;
4410bbfda8aSnia					}
4420bbfda8aSnia				}
4430bbfda8aSnia			}
4440bbfda8aSnia		}
4450bbfda8aSnia	}
4460bbfda8aSnia
4470bbfda8aSnia	/* No else here, in case we bailed out of clause above.
4480bbfda8aSnia	 */
4490bbfda8aSnia	if(number_cmap_windows == 0) {
4500bbfda8aSnia
4510bbfda8aSnia		number_cmap_windows = 1;
4520bbfda8aSnia
4530bbfda8aSnia		cwins = malloc(sizeof(ColormapWindow *));
4540bbfda8aSnia		if(XFindContext(dpy, tmp->w, ColormapContext, (XPointer *)&cwins[0]) ==
4550bbfda8aSnia		                XCNOENT)
4560bbfda8aSnia			cwins[0] = CreateColormapWindow(tmp->w,
4570bbfda8aSnia			                                tmp->cmaps.number_cwins == 0, false);
4580bbfda8aSnia		else {
4590bbfda8aSnia			cwins[0]->refcnt++;
4600bbfda8aSnia		}
4610bbfda8aSnia	}
4620bbfda8aSnia
4630bbfda8aSnia	if(tmp->cmaps.number_cwins) {
4640bbfda8aSnia		free_cwins(tmp);
4650bbfda8aSnia	}
4660bbfda8aSnia
4670bbfda8aSnia	tmp->cmaps.cwins = cwins;
4680bbfda8aSnia	tmp->cmaps.number_cwins = number_cmap_windows;
4690bbfda8aSnia	if(number_cmap_windows > 1)
4700bbfda8aSnia		tmp->cmaps.scoreboard =
4710bbfda8aSnia		        calloc(1, ColormapsScoreboardLength(&tmp->cmaps));
4720bbfda8aSnia
4730bbfda8aSnia	if(previnst) {
4740bbfda8aSnia		InstallColormaps(PropertyNotify, NULL);
4750bbfda8aSnia	}
4760bbfda8aSnia
4770bbfda8aSniadone:
4780bbfda8aSnia	if(cmap_windows) {
4790bbfda8aSnia		if(can_free_cmap_windows) {
4800bbfda8aSnia			free(cmap_windows);
4810bbfda8aSnia		}
4820bbfda8aSnia		else {
4830bbfda8aSnia			XFree(cmap_windows);
4840bbfda8aSnia		}
4850bbfda8aSnia	}
4860bbfda8aSnia}
4870bbfda8aSnia
4880bbfda8aSnia
4890bbfda8aSnia/*
4900bbfda8aSnia * BumpWindowColormap - rotate our internal copy of WM_COLORMAP_WINDOWS.
4910bbfda8aSnia * This is the backend for f.colormap.
4920bbfda8aSnia *
4930bbfda8aSnia * Previously in functions.c
4940bbfda8aSnia */
4950bbfda8aSniavoid
4960bbfda8aSniaBumpWindowColormap(TwmWindow *tmp, int inc)
4970bbfda8aSnia{
4980bbfda8aSnia	int i, j;
4990bbfda8aSnia	bool previously_installed;
5000bbfda8aSnia	ColormapWindow **cwins;
5010bbfda8aSnia
5020bbfda8aSnia	if(!tmp) {
5030bbfda8aSnia		return;
5040bbfda8aSnia	}
5050bbfda8aSnia
5060bbfda8aSnia	if(inc && tmp->cmaps.number_cwins > 0) {
5070bbfda8aSnia		cwins = calloc(tmp->cmaps.number_cwins, sizeof(ColormapWindow *));
5080bbfda8aSnia		if(cwins) {
5090bbfda8aSnia			previously_installed = (Scr->cmapInfo.cmaps == &tmp->cmaps &&
5100bbfda8aSnia			                        tmp->cmaps.number_cwins);
5110bbfda8aSnia			if(previously_installed) {
5120bbfda8aSnia				for(i = tmp->cmaps.number_cwins; i-- > 0;) {
5130bbfda8aSnia					tmp->cmaps.cwins[i]->colormap->state = 0;
5140bbfda8aSnia				}
5150bbfda8aSnia			}
5160bbfda8aSnia
5170bbfda8aSnia			for(i = 0; i < tmp->cmaps.number_cwins; i++) {
5180bbfda8aSnia				j = i - inc;
5190bbfda8aSnia				if(j >= tmp->cmaps.number_cwins) {
5200bbfda8aSnia					j -= tmp->cmaps.number_cwins;
5210bbfda8aSnia				}
5220bbfda8aSnia				else if(j < 0) {
5230bbfda8aSnia					j += tmp->cmaps.number_cwins;
5240bbfda8aSnia				}
5250bbfda8aSnia				cwins[j] = tmp->cmaps.cwins[i];
5260bbfda8aSnia			}
5270bbfda8aSnia
5280bbfda8aSnia			free(tmp->cmaps.cwins);
5290bbfda8aSnia
5300bbfda8aSnia			tmp->cmaps.cwins = cwins;
5310bbfda8aSnia
5320bbfda8aSnia			if(tmp->cmaps.number_cwins > 1)
5330bbfda8aSnia				memset(tmp->cmaps.scoreboard, 0,
5340bbfda8aSnia				       ColormapsScoreboardLength(&tmp->cmaps));
5350bbfda8aSnia
5360bbfda8aSnia			if(previously_installed) {
5370bbfda8aSnia				InstallColormaps(PropertyNotify, NULL);
5380bbfda8aSnia			}
5390bbfda8aSnia		}
5400bbfda8aSnia	}
5410bbfda8aSnia	else {
5420bbfda8aSnia		FetchWmColormapWindows(tmp);
5430bbfda8aSnia	}
5440bbfda8aSnia	return;
5450bbfda8aSnia}
5460bbfda8aSnia
5470bbfda8aSnia
5480bbfda8aSnia/*
5490bbfda8aSnia * Handlers for creating and linkin in, as well as deleting, a StdCmap
5500bbfda8aSnia * for a given XStandardColormap.
5510bbfda8aSnia *
5520bbfda8aSnia * Previously in util.c
5530bbfda8aSnia */
5540bbfda8aSniavoid
5550bbfda8aSniaInsertRGBColormap(Atom a, XStandardColormap *maps, int nmaps,
5560bbfda8aSnia                  bool replace)
5570bbfda8aSnia{
5580bbfda8aSnia	StdCmap *sc = NULL;
5590bbfda8aSnia
5600bbfda8aSnia	if(replace) {                       /* locate existing entry */
5610bbfda8aSnia		for(sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
5620bbfda8aSnia			if(sc->atom == a) {
5630bbfda8aSnia				break;
5640bbfda8aSnia			}
5650bbfda8aSnia		}
5660bbfda8aSnia	}
5670bbfda8aSnia
5680bbfda8aSnia	if(!sc) {                           /* no existing, allocate new */
5690bbfda8aSnia		sc = calloc(1, sizeof(StdCmap));
5700bbfda8aSnia		if(!sc) {
5710bbfda8aSnia			fprintf(stderr, "%s:  unable to allocate %lu bytes for StdCmap\n",
5720bbfda8aSnia			        ProgramName, (unsigned long) sizeof(StdCmap));
5730bbfda8aSnia			return;
5740bbfda8aSnia		}
575b18c2d1eSnia		replace = false;  // Didn't find one, can't replace
5760bbfda8aSnia	}
5770bbfda8aSnia
5780bbfda8aSnia	if(replace) {                       /* just update contents */
5790bbfda8aSnia		if(sc->maps) {
580b18c2d1eSnia			XFree(sc->maps);
5810bbfda8aSnia		}
5820bbfda8aSnia		if(sc == Scr->StdCmapInfo.mru) {
5830bbfda8aSnia			Scr->StdCmapInfo.mru = NULL;
5840bbfda8aSnia		}
5850bbfda8aSnia	}
5860bbfda8aSnia	else {                              /* else appending */
5870bbfda8aSnia		sc->next = NULL;
5880bbfda8aSnia		sc->atom = a;
5890bbfda8aSnia		if(Scr->StdCmapInfo.tail) {
5900bbfda8aSnia			Scr->StdCmapInfo.tail->next = sc;
5910bbfda8aSnia		}
5920bbfda8aSnia		else {
5930bbfda8aSnia			Scr->StdCmapInfo.head = sc;
5940bbfda8aSnia		}
5950bbfda8aSnia		Scr->StdCmapInfo.tail = sc;
5960bbfda8aSnia	}
5970bbfda8aSnia	sc->nmaps = nmaps;
5980bbfda8aSnia	sc->maps = maps;
5990bbfda8aSnia
6000bbfda8aSnia	return;
6010bbfda8aSnia}
6020bbfda8aSnia
6030bbfda8aSnia
6040bbfda8aSniavoid
6050bbfda8aSniaRemoveRGBColormap(Atom a)
6060bbfda8aSnia{
6070bbfda8aSnia	StdCmap *sc, *prev;
6080bbfda8aSnia
6090bbfda8aSnia	prev = NULL;
6100bbfda8aSnia	for(sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
6110bbfda8aSnia		if(sc->atom == a) {
6120bbfda8aSnia			break;
6130bbfda8aSnia		}
6140bbfda8aSnia		prev = sc;
6150bbfda8aSnia	}
6160bbfda8aSnia	if(sc) {                            /* found one */
6170bbfda8aSnia		if(sc->maps) {
6180bbfda8aSnia			XFree(sc->maps);
6190bbfda8aSnia		}
6200bbfda8aSnia		if(prev) {
6210bbfda8aSnia			prev->next = sc->next;
6220bbfda8aSnia		}
6230bbfda8aSnia		if(Scr->StdCmapInfo.head == sc) {
6240bbfda8aSnia			Scr->StdCmapInfo.head = sc->next;
6250bbfda8aSnia		}
6260bbfda8aSnia		if(Scr->StdCmapInfo.tail == sc) {
6270bbfda8aSnia			Scr->StdCmapInfo.tail = prev;
6280bbfda8aSnia		}
6290bbfda8aSnia		if(Scr->StdCmapInfo.mru == sc) {
6300bbfda8aSnia			Scr->StdCmapInfo.mru = NULL;
6310bbfda8aSnia		}
6320bbfda8aSnia	}
6330bbfda8aSnia	return;
6340bbfda8aSnia}
6350bbfda8aSnia
6360bbfda8aSnia
6370bbfda8aSnia/*
6380bbfda8aSnia * Go through all the properties of the root window and setup
6390bbfda8aSnia * XStandardColormap's and our StdCmap's for any of them that are
6400bbfda8aSnia * actually RGB_COLORMAP types.  We're not actually _checking_ the types,
6410bbfda8aSnia * just letting XGetRGBColormaps() refuse to handle probably most of
6420bbfda8aSnia * them.  Called during startup.
6430bbfda8aSnia *
6440bbfda8aSnia * Previouly in util.c
6450bbfda8aSnia */
6460bbfda8aSniavoid
6470bbfda8aSniaLocateStandardColormaps(void)
6480bbfda8aSnia{
6490bbfda8aSnia	Atom *atoms;
6500bbfda8aSnia	int natoms;
6510bbfda8aSnia	int i;
6520bbfda8aSnia
6530bbfda8aSnia	atoms = XListProperties(dpy, Scr->Root, &natoms);
6540bbfda8aSnia	for(i = 0; i < natoms; i++) {
6550bbfda8aSnia		XStandardColormap *maps = NULL;
6560bbfda8aSnia		int nmaps;
6570bbfda8aSnia
6580bbfda8aSnia		if(XGetRGBColormaps(dpy, Scr->Root, &maps, &nmaps, atoms[i])) {
6590bbfda8aSnia			/* if got one, then append to current list */
6600bbfda8aSnia			InsertRGBColormap(atoms[i], maps, nmaps, false);
6610bbfda8aSnia		}
6620bbfda8aSnia	}
6630bbfda8aSnia	if(atoms) {
6640bbfda8aSnia		XFree(atoms);
6650bbfda8aSnia	}
6660bbfda8aSnia	return;
6670bbfda8aSnia}
6680bbfda8aSnia
6690bbfda8aSnia
6700bbfda8aSnia/*
6710bbfda8aSnia * Clear out and free TwmWindow.cmaps (struct Colormaps) bits for a window.
6720bbfda8aSnia *
6730bbfda8aSnia * Previously in events.c
6740bbfda8aSnia */
6750bbfda8aSniavoid
6760bbfda8aSniafree_cwins(TwmWindow *tmp)
6770bbfda8aSnia{
6780bbfda8aSnia	int i;
6790bbfda8aSnia	TwmColormap *cmap;
6800bbfda8aSnia
6810bbfda8aSnia	if(tmp->cmaps.number_cwins) {
6820bbfda8aSnia		for(i = 0; i < tmp->cmaps.number_cwins; i++) {
6830bbfda8aSnia			if(--tmp->cmaps.cwins[i]->refcnt == 0) {
6840bbfda8aSnia				cmap = tmp->cmaps.cwins[i]->colormap;
6850bbfda8aSnia				if(--cmap->refcnt == 0) {
6860bbfda8aSnia					XDeleteContext(dpy, cmap->c, ColormapContext);
6870bbfda8aSnia					free(cmap);
6880bbfda8aSnia				}
6890bbfda8aSnia				XDeleteContext(dpy, tmp->cmaps.cwins[i]->w, ColormapContext);
6900bbfda8aSnia				free(tmp->cmaps.cwins[i]);
6910bbfda8aSnia			}
6920bbfda8aSnia		}
6930bbfda8aSnia		free(tmp->cmaps.cwins);
6940bbfda8aSnia		if(tmp->cmaps.number_cwins > 1) {
6950bbfda8aSnia			free(tmp->cmaps.scoreboard);
6960bbfda8aSnia			tmp->cmaps.scoreboard = NULL;
6970bbfda8aSnia		}
6980bbfda8aSnia		tmp->cmaps.number_cwins = 0;
6990bbfda8aSnia	}
7000bbfda8aSnia}
701