micmap.c revision 05b261ec
1/************************************************************
2Copyright 1987 by Sun Microsystems, Inc. Mountain View, CA.
3
4                    All Rights Reserved
5
6Permission  to  use,  copy,  modify,  and  distribute   this
7software  and  its documentation for any purpose and without
8fee is hereby granted, provided that the above copyright no-
9tice  appear  in all copies and that both that copyright no-
10tice and this permission notice appear in  supporting  docu-
11mentation,  and  that the names of Sun or X Consortium
12not be used in advertising or publicity pertaining to
13distribution  of  the software  without specific prior
14written permission. Sun and X Consortium make no
15representations about the suitability of this software for
16any purpose. It is provided "as is" without any express or
17implied warranty.
18
19SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO  THIS  SOFTWARE,
20INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
21NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE  LI-
22ABLE  FOR  ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
23ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,  DATA  OR
24PROFITS,  WHETHER  IN  AN  ACTION OF CONTRACT, NEGLIGENCE OR
25OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
26THE USE OR PERFORMANCE OF THIS SOFTWARE.
27
28********************************************************/
29
30/*
31 * This is based on cfbcmap.c.  The functions here are useful independently
32 * of cfb, which is the reason for including them here.  How "mi" these
33 * are may be debatable.
34 */
35
36
37#ifdef HAVE_DIX_CONFIG_H
38#include <dix-config.h>
39#endif
40
41#include <X11/X.h>
42#include <X11/Xproto.h>
43#include "scrnintstr.h"
44#include "colormapst.h"
45#include "resource.h"
46#include "globals.h"
47#include "micmap.h"
48
49_X_EXPORT ColormapPtr miInstalledMaps[MAXSCREENS];
50
51static Bool miDoInitVisuals(VisualPtr *visualp, DepthPtr *depthp, int *nvisualp,
52		int *ndepthp, int *rootDepthp, VisualID *defaultVisp,
53		unsigned long sizes, int bitsPerRGB, int preferredVis);
54
55_X_EXPORT miInitVisualsProcPtr miInitVisualsProc = miDoInitVisuals;
56
57_X_EXPORT int
58miListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps)
59{
60    if (miInstalledMaps[pScreen->myNum]) {
61	*pmaps = miInstalledMaps[pScreen->myNum]->mid;
62	return (1);
63    }
64    return 0;
65}
66
67_X_EXPORT void
68miInstallColormap(ColormapPtr pmap)
69{
70    int index = pmap->pScreen->myNum;
71    ColormapPtr oldpmap = miInstalledMaps[index];
72
73    if(pmap != oldpmap)
74    {
75	/* Uninstall pInstalledMap. No hardware changes required, just
76	 * notify all interested parties. */
77	if(oldpmap != (ColormapPtr)None)
78	    WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid);
79	/* Install pmap */
80	miInstalledMaps[index] = pmap;
81	WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid);
82
83    }
84}
85
86_X_EXPORT void
87miUninstallColormap(ColormapPtr pmap)
88{
89    int index = pmap->pScreen->myNum;
90    ColormapPtr curpmap = miInstalledMaps[index];
91
92    if(pmap == curpmap)
93    {
94	if (pmap->mid != pmap->pScreen->defColormap)
95	{
96	    curpmap = (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap,
97						   RT_COLORMAP);
98	    (*pmap->pScreen->InstallColormap)(curpmap);
99	}
100    }
101}
102
103_X_EXPORT void
104miResolveColor(unsigned short *pred, unsigned short *pgreen,
105		unsigned short *pblue, VisualPtr pVisual)
106{
107    int shift = 16 - pVisual->bitsPerRGBValue;
108    unsigned lim = (1 << pVisual->bitsPerRGBValue) - 1;
109
110    if ((pVisual->class | DynamicClass) == GrayScale)
111    {
112	/* rescale to gray then rgb bits */
113	*pred = (30L * *pred + 59L * *pgreen + 11L * *pblue) / 100;
114	*pblue = *pgreen = *pred = ((*pred >> shift) * 65535) / lim;
115    }
116    else
117    {
118	/* rescale to rgb bits */
119	*pred = ((*pred >> shift) * 65535) / lim;
120	*pgreen = ((*pgreen >> shift) * 65535) / lim;
121	*pblue = ((*pblue >> shift) * 65535) / lim;
122    }
123}
124
125_X_EXPORT Bool
126miInitializeColormap(ColormapPtr pmap)
127{
128    unsigned i;
129    VisualPtr pVisual;
130    unsigned lim, maxent, shift;
131
132    pVisual = pmap->pVisual;
133    lim = (1 << pVisual->bitsPerRGBValue) - 1;
134    shift = 16 - pVisual->bitsPerRGBValue;
135    maxent = pVisual->ColormapEntries - 1;
136    if (pVisual->class == TrueColor)
137    {
138	unsigned limr, limg, limb;
139
140	limr = pVisual->redMask >> pVisual->offsetRed;
141	limg = pVisual->greenMask >> pVisual->offsetGreen;
142	limb = pVisual->blueMask >> pVisual->offsetBlue;
143	for(i = 0; i <= maxent; i++)
144	{
145	    /* rescale to [0..65535] then rgb bits */
146	    pmap->red[i].co.local.red =
147		((((i * 65535) / limr) >> shift) * 65535) / lim;
148	    pmap->green[i].co.local.green =
149		((((i * 65535) / limg) >> shift) * 65535) / lim;
150	    pmap->blue[i].co.local.blue =
151		((((i * 65535) / limb) >> shift) * 65535) / lim;
152	}
153    }
154    else if (pVisual->class == StaticColor)
155    {
156	unsigned limr, limg, limb;
157
158	limr = pVisual->redMask >> pVisual->offsetRed;
159	limg = pVisual->greenMask >> pVisual->offsetGreen;
160	limb = pVisual->blueMask >> pVisual->offsetBlue;
161	for(i = 0; i <= maxent; i++)
162	{
163	    /* rescale to [0..65535] then rgb bits */
164	    pmap->red[i].co.local.red =
165		((((((i & pVisual->redMask) >> pVisual->offsetRed)
166		    * 65535) / limr) >> shift) * 65535) / lim;
167	    pmap->red[i].co.local.green =
168		((((((i & pVisual->greenMask) >> pVisual->offsetGreen)
169		    * 65535) / limg) >> shift) * 65535) / lim;
170	    pmap->red[i].co.local.blue =
171		((((((i & pVisual->blueMask) >> pVisual->offsetBlue)
172		    * 65535) / limb) >> shift) * 65535) / lim;
173	}
174    }
175    else if (pVisual->class == StaticGray)
176    {
177	for(i = 0; i <= maxent; i++)
178	{
179	    /* rescale to [0..65535] then rgb bits */
180	    pmap->red[i].co.local.red = ((((i * 65535) / maxent) >> shift)
181					 * 65535) / lim;
182	    pmap->red[i].co.local.green = pmap->red[i].co.local.red;
183	    pmap->red[i].co.local.blue = pmap->red[i].co.local.red;
184	}
185    }
186    return TRUE;
187}
188
189/* When simulating DirectColor on PseudoColor hardware, multiple
190   entries of the colormap must be updated
191 */
192
193#define AddElement(mask) { \
194    pixel = red | green | blue; \
195    for (i = 0; i < nresult; i++) \
196  	if (outdefs[i].pixel == pixel) \
197    	    break; \
198    if (i == nresult) \
199    { \
200   	nresult++; \
201	outdefs[i].pixel = pixel; \
202	outdefs[i].flags = 0; \
203    } \
204    outdefs[i].flags |= (mask); \
205    outdefs[i].red = pmap->red[red >> pVisual->offsetRed].co.local.red; \
206    outdefs[i].green = pmap->green[green >> pVisual->offsetGreen].co.local.green; \
207    outdefs[i].blue = pmap->blue[blue >> pVisual->offsetBlue].co.local.blue; \
208}
209
210_X_EXPORT int
211miExpandDirectColors(ColormapPtr pmap, int ndef, xColorItem *indefs,
212			xColorItem *outdefs)
213{
214    int	        red, green, blue;
215    int	        maxred, maxgreen, maxblue;
216    int	        stepred, stepgreen, stepblue;
217    VisualPtr   pVisual;
218    int         pixel;
219    int         nresult;
220    int         i;
221
222    pVisual = pmap->pVisual;
223
224    stepred = 1 << pVisual->offsetRed;
225    stepgreen = 1 << pVisual->offsetGreen;
226    stepblue = 1 << pVisual->offsetBlue;
227    maxred = pVisual->redMask;
228    maxgreen = pVisual->greenMask;
229    maxblue = pVisual->blueMask;
230    nresult = 0;
231    for (;ndef--; indefs++)
232    {
233	if (indefs->flags & DoRed)
234	{
235	    red = indefs->pixel & pVisual->redMask;
236    	    for (green = 0; green <= maxgreen; green += stepgreen)
237    	    {
238	    	for (blue = 0; blue <= maxblue; blue += stepblue)
239	    	{
240		    AddElement (DoRed)
241	    	}
242    	    }
243	}
244	if (indefs->flags & DoGreen)
245	{
246	    green = indefs->pixel & pVisual->greenMask;
247    	    for (red = 0; red <= maxred; red += stepred)
248    	    {
249	    	for (blue = 0; blue <= maxblue; blue += stepblue)
250	    	{
251		    AddElement (DoGreen)
252	    	}
253    	    }
254	}
255	if (indefs->flags & DoBlue)
256	{
257	    blue = indefs->pixel & pVisual->blueMask;
258    	    for (red = 0; red <= maxred; red += stepred)
259    	    {
260	    	for (green = 0; green <= maxgreen; green += stepgreen)
261	    	{
262		    AddElement (DoBlue)
263	    	}
264    	    }
265	}
266    }
267    return nresult;
268}
269
270_X_EXPORT Bool
271miCreateDefColormap(ScreenPtr pScreen)
272{
273/*
274 * In the following sources PC X server vendors may want to delete
275 * "_not_tog" from "#ifdef WIN32_not_tog"
276 */
277#ifdef WIN32_not_tog
278    /*
279     * these are the MS-Windows desktop colors, adjusted for X's 16-bit
280     * color specifications.
281     */
282    static xColorItem citems[] = {
283	{   0,      0,      0,      0, 0, 0 },
284	{   1, 0x8000,      0,      0, 0, 0 },
285	{   2,      0, 0x8000,      0, 0, 0 },
286	{   3, 0x8000, 0x8000,      0, 0, 0 },
287	{   4,      0,      0, 0x8000, 0, 0 },
288	{   5, 0x8000,      0, 0x8000, 0, 0 },
289	{   6,      0, 0x8000, 0x8000, 0, 0 },
290	{   7, 0xc000, 0xc000, 0xc000, 0, 0 },
291	{   8, 0xc000, 0xdc00, 0xc000, 0, 0 },
292	{   9, 0xa600, 0xca00, 0xf000, 0, 0 },
293	{ 246, 0xff00, 0xfb00, 0xf000, 0, 0 },
294	{ 247, 0xa000, 0xa000, 0xa400, 0, 0 },
295	{ 248, 0x8000, 0x8000, 0x8000, 0, 0 },
296	{ 249, 0xff00,      0,      0, 0, 0 },
297	{ 250,      0, 0xff00,      0, 0, 0 },
298	{ 251, 0xff00, 0xff00,      0, 0, 0 },
299	{ 252,      0,      0, 0xff00, 0, 0 },
300	{ 253, 0xff00,      0, 0xff00, 0, 0 },
301	{ 254,      0, 0xff00, 0xff00, 0, 0 },
302	{ 255, 0xff00, 0xff00, 0xff00, 0, 0 }
303    };
304#define NUM_DESKTOP_COLORS sizeof citems / sizeof citems[0]
305    int i;
306#else
307    unsigned short	zero = 0, ones = 0xFFFF;
308#endif
309    Pixel wp, bp;
310    VisualPtr	pVisual;
311    ColormapPtr	cmap;
312    int alloctype;
313
314    for (pVisual = pScreen->visuals;
315	 pVisual->vid != pScreen->rootVisual;
316	 pVisual++)
317	;
318
319    if (pScreen->rootDepth == 1 || (pVisual->class & DynamicClass))
320	alloctype = AllocNone;
321    else
322	alloctype = AllocAll;
323
324    if (CreateColormap(pScreen->defColormap, pScreen, pVisual, &cmap,
325		       alloctype, 0) != Success)
326	return FALSE;
327
328    if (pScreen->rootDepth > 1) {
329	wp = pScreen->whitePixel;
330	bp = pScreen->blackPixel;
331#ifdef WIN32_not_tog
332	for (i = 0; i < NUM_DESKTOP_COLORS; i++) {
333	    if (AllocColor (cmap,
334			    &citems[i].red, &citems[i].green, &citems[i].blue,
335			    &citems[i].pixel, 0) != Success)
336		return FALSE;
337	}
338#else
339	if ((AllocColor(cmap, &ones, &ones, &ones, &wp, 0) !=
340       	       Success) ||
341	    (AllocColor(cmap, &zero, &zero, &zero, &bp, 0) !=
342       	       Success))
343    	    return FALSE;
344	pScreen->whitePixel = wp;
345	pScreen->blackPixel = bp;
346#endif
347    }
348
349    (*pScreen->InstallColormap)(cmap);
350    return TRUE;
351}
352
353/*
354 * Default true color bitmasks, should be overridden by
355 * driver
356 */
357
358#define _RZ(d) ((d + 2) / 3)
359#define _RS(d) 0
360#define _RM(d) ((1 << _RZ(d)) - 1)
361#define _GZ(d) ((d - _RZ(d) + 1) / 2)
362#define _GS(d) _RZ(d)
363#define _GM(d) (((1 << _GZ(d)) - 1) << _GS(d))
364#define _BZ(d) (d - _RZ(d) - _GZ(d))
365#define _BS(d) (_RZ(d) + _GZ(d))
366#define _BM(d) (((1 << _BZ(d)) - 1) << _BS(d))
367#define _CE(d) (1 << _RZ(d))
368
369typedef struct _miVisuals {
370    struct _miVisuals	*next;
371    int			depth;
372    int			bitsPerRGB;
373    int			visuals;
374    int			count;
375    int			preferredCVC;
376    Pixel		redMask, greenMask, blueMask;
377} miVisualsRec, *miVisualsPtr;
378
379static int  miVisualPriority[] = {
380    PseudoColor, GrayScale, StaticColor, TrueColor, DirectColor, StaticGray
381};
382
383#define NUM_PRIORITY	6
384
385static miVisualsPtr	miVisuals;
386
387_X_EXPORT void
388miClearVisualTypes(void)
389{
390    miVisualsPtr v;
391
392    while ((v = miVisuals)) {
393	miVisuals = v->next;
394	xfree(v);
395    }
396}
397
398
399_X_EXPORT Bool
400miSetVisualTypesAndMasks(int depth, int visuals, int bitsPerRGB,
401			 int preferredCVC,
402			 Pixel redMask, Pixel greenMask, Pixel blueMask)
403{
404    miVisualsPtr   new, *prev, v;
405    int		    count;
406
407    new = (miVisualsPtr) xalloc (sizeof *new);
408    if (!new)
409	return FALSE;
410    if (!redMask || !greenMask || !blueMask)
411    {
412	redMask = _RM(depth);
413	greenMask = _GM(depth);
414	blueMask = _BM(depth);
415    }
416    new->next = 0;
417    new->depth = depth;
418    new->visuals = visuals;
419    new->bitsPerRGB = bitsPerRGB;
420    new->preferredCVC = preferredCVC;
421    new->redMask = redMask;
422    new->greenMask = greenMask;
423    new->blueMask = blueMask;
424    count = (visuals >> 1) & 033333333333;
425    count = visuals - count - ((count >> 1) & 033333333333);
426    count = (((count + (count >> 3)) & 030707070707) % 077);	/* HAKMEM 169 */
427    new->count = count;
428    for (prev = &miVisuals; (v = *prev); prev = &v->next);
429    *prev = new;
430    return TRUE;
431}
432
433_X_EXPORT Bool
434miSetVisualTypes(int depth, int visuals, int bitsPerRGB, int preferredCVC)
435{
436    return miSetVisualTypesAndMasks (depth, visuals, bitsPerRGB,
437				     preferredCVC, 0, 0, 0);
438}
439
440_X_EXPORT int
441miGetDefaultVisualMask(int depth)
442{
443    if (depth > MAX_PSEUDO_DEPTH)
444	return LARGE_VISUALS;
445    else if (depth >= MIN_TRUE_DEPTH)
446	return ALL_VISUALS;
447    else if (depth == 1)
448	return StaticGrayMask;
449    else
450	return SMALL_VISUALS;
451}
452
453static Bool
454miVisualTypesSet (int depth)
455{
456    miVisualsPtr    visuals;
457
458    for (visuals = miVisuals; visuals; visuals = visuals->next)
459	if (visuals->depth == depth)
460	    return TRUE;
461    return FALSE;
462}
463
464_X_EXPORT Bool
465miSetPixmapDepths (void)
466{
467    int	d, f;
468
469    /* Add any unlisted depths from the pixmap formats */
470    for (f = 0; f < screenInfo.numPixmapFormats; f++)
471    {
472	d = screenInfo.formats[f].depth;
473	if (!miVisualTypesSet (d))
474	{
475	    if (!miSetVisualTypes (d, 0, 0, -1))
476		return FALSE;
477	}
478    }
479    return TRUE;
480}
481
482_X_EXPORT Bool
483miInitVisuals(VisualPtr *visualp, DepthPtr *depthp, int *nvisualp,
484		int *ndepthp, int *rootDepthp, VisualID *defaultVisp,
485		unsigned long sizes, int bitsPerRGB, int preferredVis)
486
487{
488    if (miInitVisualsProc)
489	return miInitVisualsProc(visualp, depthp, nvisualp, ndepthp,
490				 rootDepthp, defaultVisp, sizes, bitsPerRGB,
491				 preferredVis);
492    else
493	return FALSE;
494}
495
496/*
497 * Distance to least significant one bit
498 */
499static int
500maskShift (Pixel p)
501{
502    int	s;
503
504    if (!p) return 0;
505    s = 0;
506    while (!(p & 1))
507    {
508	s++;
509	p >>= 1;
510    }
511    return s;
512}
513
514/*
515 * Given a list of formats for a screen, create a list
516 * of visuals and depths for the screen which corespond to
517 * the set which can be used with this version of cfb.
518 */
519
520static Bool
521miDoInitVisuals(VisualPtr *visualp, DepthPtr *depthp, int *nvisualp,
522		int *ndepthp, int *rootDepthp, VisualID *defaultVisp,
523		unsigned long sizes, int bitsPerRGB, int preferredVis)
524{
525    int		i, j = 0, k;
526    VisualPtr	visual;
527    DepthPtr	depth;
528    VisualID	*vid;
529    int		d, b;
530    int		f;
531    int		ndepth, nvisual;
532    int		nvtype;
533    int		vtype;
534    miVisualsPtr   visuals, nextVisuals;
535    int		*preferredCVCs, *prefp;
536    int		first_depth;
537
538    /* none specified, we'll guess from pixmap formats */
539    if (!miVisuals)
540    {
541    	for (f = 0; f < screenInfo.numPixmapFormats; f++)
542    	{
543	    d = screenInfo.formats[f].depth;
544	    b = screenInfo.formats[f].bitsPerPixel;
545	    if (sizes & (1 << (b - 1)))
546		vtype = miGetDefaultVisualMask(d);
547	    else
548		vtype = 0;
549	    if (!miSetVisualTypes (d, vtype, bitsPerRGB, -1))
550		return FALSE;
551    	}
552    }
553    nvisual = 0;
554    ndepth = 0;
555    for (visuals = miVisuals; visuals; visuals = nextVisuals)
556    {
557	nextVisuals = visuals->next;
558	ndepth++;
559	nvisual += visuals->count;
560    }
561    depth = (DepthPtr) xalloc (ndepth * sizeof (DepthRec));
562    visual = (VisualPtr) xalloc (nvisual * sizeof (VisualRec));
563    preferredCVCs = (int *)xalloc(ndepth * sizeof(int));
564    if (!depth || !visual || !preferredCVCs)
565    {
566	xfree (depth);
567	xfree (visual);
568	xfree (preferredCVCs);
569	return FALSE;
570    }
571    *depthp = depth;
572    *visualp = visual;
573    *ndepthp = ndepth;
574    *nvisualp = nvisual;
575    prefp = preferredCVCs;
576    for (visuals = miVisuals; visuals; visuals = nextVisuals)
577    {
578	nextVisuals = visuals->next;
579	d = visuals->depth;
580	vtype = visuals->visuals;
581	nvtype = visuals->count;
582	*prefp = visuals->preferredCVC;
583	prefp++;
584	vid = NULL;
585	if (nvtype)
586	{
587	    vid = (VisualID *) xalloc (nvtype * sizeof (VisualID));
588	    if (!vid) {
589		xfree(preferredCVCs);
590		return FALSE;
591	    }
592	}
593	depth->depth = d;
594	depth->numVids = nvtype;
595	depth->vids = vid;
596	depth++;
597	for (i = 0; i < NUM_PRIORITY; i++) {
598	    if (! (vtype & (1 << miVisualPriority[i])))
599		continue;
600	    visual->class = miVisualPriority[i];
601	    visual->bitsPerRGBValue = visuals->bitsPerRGB;
602	    visual->ColormapEntries = 1 << d;
603	    visual->nplanes = d;
604	    visual->vid = *vid = FakeClientID (0);
605	    switch (visual->class) {
606	    case PseudoColor:
607	    case GrayScale:
608	    case StaticGray:
609		visual->redMask = 0;
610		visual->greenMask =  0;
611		visual->blueMask =  0;
612		visual->offsetRed  =  0;
613		visual->offsetGreen = 0;
614		visual->offsetBlue =  0;
615		break;
616	    case DirectColor:
617	    case TrueColor:
618		visual->ColormapEntries = _CE(d);
619		/* fall through */
620	    case StaticColor:
621		visual->redMask =  visuals->redMask;
622		visual->greenMask =  visuals->greenMask;
623		visual->blueMask =  visuals->blueMask;
624		visual->offsetRed  =  maskShift (visuals->redMask);
625		visual->offsetGreen = maskShift (visuals->greenMask);
626		visual->offsetBlue =  maskShift (visuals->blueMask);
627	    }
628	    vid++;
629	    visual++;
630	}
631	xfree (visuals);
632    }
633    miVisuals = NULL;
634    visual = *visualp;
635    depth = *depthp;
636
637    /*
638     * if we did not supplyied by a preferred visual class
639     * check if there is a preferred class in one of the depth
640     * structures - if there is, we want to start looking for the
641     * default visual/depth from that depth.
642     */
643    first_depth = 0;
644    if (preferredVis < 0 && defaultColorVisualClass < 0 ) {
645       for (i = 0; i < ndepth; i++) {
646	  if (preferredCVCs[i] >= 0) {
647	     first_depth = i;
648	     break;
649	  }
650       }
651    }
652
653    for (i = first_depth; i < ndepth; i++)
654    {
655	int prefColorVisualClass = -1;
656
657	if (defaultColorVisualClass >= 0)
658	    prefColorVisualClass = defaultColorVisualClass;
659	else if (preferredVis >= 0)
660	    prefColorVisualClass = preferredVis;
661	else if (preferredCVCs[i] >= 0)
662	    prefColorVisualClass = preferredCVCs[i];
663
664	if (*rootDepthp && *rootDepthp != depth[i].depth)
665	    continue;
666
667	for (j = 0; j < depth[i].numVids; j++)
668	{
669	    for (k = 0; k < nvisual; k++)
670		if (visual[k].vid == depth[i].vids[j])
671		    break;
672	    if (k == nvisual)
673		continue;
674	    if (prefColorVisualClass < 0 ||
675		visual[k].class == prefColorVisualClass)
676		break;
677	}
678	if (j != depth[i].numVids)
679	    break;
680    }
681    if (i == ndepth) {
682	i = 0;
683	j = 0;
684    }
685    *rootDepthp = depth[i].depth;
686    *defaultVisp = depth[i].vids[j];
687    xfree(preferredCVCs);
688
689    return TRUE;
690}
691
692void
693miResetInitVisuals(void)
694{
695    miInitVisualsProc = miDoInitVisuals;
696}
697
698