xkbout.c revision 05b261ec
1/************************************************************
2 Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3
4 Permission to use, copy, modify, and distribute this
5 software and its documentation for any purpose and without
6 fee is hereby granted, provided that the above copyright
7 notice appear in all copies and that both that copyright
8 notice and this permission notice appear in supporting
9 documentation, and that the name of Silicon Graphics not be
10 used in advertising or publicity pertaining to distribution
11 of the software without specific prior written permission.
12 Silicon Graphics makes no representation about the suitability
13 of this software for any purpose. It is provided "as is"
14 without any express or implied warranty.
15
16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23 THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25 ********************************************************/
26
27#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#endif
30
31#include <stdio.h>
32#include <ctype.h>
33#include <stdlib.h>
34#include <X11/Xfuncs.h>
35
36#include <X11/X.h>
37#define	NEED_EVENTS
38#include <X11/keysym.h>
39#include <X11/Xproto.h>
40#include "misc.h"
41#include "inputstr.h"
42#include "dix.h"
43#include <X11/extensions/XKBstr.h>
44#define XKBSRV_NEED_FILE_FUNCS	1
45#include <xkbsrv.h>
46
47#include <X11/extensions/XKBgeom.h>
48#include <X11/extensions/XKBfile.h>
49
50#define	VMOD_HIDE_VALUE	0
51#define	VMOD_SHOW_VALUE	1
52#define	VMOD_COMMENT_VALUE 2
53
54static Bool
55WriteXKBVModDecl(FILE *file,Display *dpy,XkbDescPtr xkb,int showValue)
56{
57register int 	i,nMods;
58Atom *		vmodNames;
59
60    if (xkb==NULL)
61	return False;
62    if (xkb->names!=NULL)
63	 vmodNames= xkb->names->vmods;
64    else vmodNames= NULL;
65
66    for (i=nMods=0;i<XkbNumVirtualMods;i++) {
67	if ((vmodNames!=NULL)&&(vmodNames[i]!=None)) {
68	    if (nMods==0)	fprintf(file,"    virtual_modifiers ");
69	    else		fprintf(file,",");
70	    fprintf(file,"%s",XkbAtomText(dpy,vmodNames[i],XkbXKBFile));
71	    if ((showValue!=VMOD_HIDE_VALUE)&&
72		(xkb->server)&&(xkb->server->vmods[i]!=XkbNoModifierMask)) {
73		if (showValue==VMOD_COMMENT_VALUE) {
74		    fprintf(file,"/* = %s */",
75			XkbModMaskText(xkb->server->vmods[i],XkbXKBFile));
76		}
77		else  {
78		    fprintf(file,"= %s",
79			XkbModMaskText(xkb->server->vmods[i],XkbXKBFile));
80		}
81	    }
82	    nMods++;
83	}
84    }
85    if (nMods>0)
86	fprintf(file,";\n\n");
87    return True;
88}
89
90/***====================================================================***/
91
92static Bool
93WriteXKBAction(FILE *file,XkbFileInfo *result,XkbAnyAction *action)
94{
95XkbDescPtr	xkb;
96Display *	dpy;
97
98    xkb= result->xkb;
99    dpy= xkb->dpy;
100    fprintf(file,"%s",XkbActionText(dpy,xkb,(XkbAction *)action,XkbXKBFile));
101    return True;
102}
103
104/***====================================================================***/
105
106Bool
107XkbWriteXKBKeycodes(	FILE *			file,
108			XkbFileInfo *		result,
109			Bool			topLevel,
110			Bool			showImplicit,
111			XkbFileAddOnFunc	addOn,
112			void *			priv)
113{
114Atom			kcName;
115register unsigned 	i;
116XkbDescPtr		xkb;
117Display *		dpy;
118char *			alternate;
119
120    xkb= result->xkb;
121    dpy= xkb->dpy;
122    if ((!xkb)||(!xkb->names)||(!xkb->names->keys)) {
123	_XkbLibError(_XkbErrMissingNames,"XkbWriteXKBKeycodes",0);
124	return False;
125    }
126    kcName= xkb->names->keycodes;
127    if (kcName!=None)
128	 fprintf(file,"xkb_keycodes \"%s\" {\n",
129					XkbAtomText(dpy,kcName,XkbXKBFile));
130    else fprintf(file,"xkb_keycodes {\n");
131    fprintf(file,"    minimum = %d;\n",xkb->min_key_code);
132    fprintf(file,"    maximum = %d;\n",xkb->max_key_code);
133    for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
134	if (xkb->names->keys[i].name[0]!='\0') {
135	    if (XkbFindKeycodeByName(xkb,xkb->names->keys[i].name,True)!=i)
136		 alternate= "alternate ";
137	    else alternate= "";
138	    fprintf(file,"    %s%6s = %d;\n",alternate,
139			XkbKeyNameText(xkb->names->keys[i].name,XkbXKBFile),
140			i);
141	}
142    }
143    if (xkb->indicators!=NULL) {
144	for (i=0;i<XkbNumIndicators;i++) {
145	    char *type;
146	    if (xkb->indicators->phys_indicators&(1<<i))
147			type= "    ";
148	    else	type= "    virtual ";
149	    if (xkb->names->indicators[i]!=None) {
150		fprintf(file,"%sindicator %d = \"%s\";\n",type,i+1,
151			XkbAtomText(dpy,xkb->names->indicators[i],XkbXKBFile));
152	    }
153	}
154    }
155    if (xkb->names->key_aliases!=NULL) {
156	XkbKeyAliasPtr	pAl;
157	pAl= xkb->names->key_aliases;
158	for (i=0;i<xkb->names->num_key_aliases;i++,pAl++) {
159	    fprintf(file,"    alias %6s = %6s;\n",
160			XkbKeyNameText(pAl->alias,XkbXKBFile),
161			XkbKeyNameText(pAl->real,XkbXKBFile));
162	}
163    }
164    if (addOn)
165	(*addOn)(file,result,topLevel,showImplicit,XkmKeyNamesIndex,priv);
166    fprintf(file,"};\n\n");
167    return True;
168}
169
170Bool
171XkbWriteXKBKeyTypes(	FILE *			file,
172			XkbFileInfo *		result,
173			Bool			topLevel,
174			Bool			showImplicit,
175			XkbFileAddOnFunc	addOn,
176			void *			priv)
177{
178Display *		dpy;
179register unsigned	i,n;
180XkbKeyTypePtr		type;
181XkbKTMapEntryPtr	entry;
182XkbDescPtr		xkb;
183
184    xkb= result->xkb;
185    dpy= xkb->dpy;
186    if ((!xkb)||(!xkb->map)||(!xkb->map->types)) {
187	_XkbLibError(_XkbErrMissingTypes,"XkbWriteXKBKeyTypes",0);
188	return False;
189    }
190    if (xkb->map->num_types<XkbNumRequiredTypes) {
191	_XkbLibError(_XkbErrMissingReqTypes,"XkbWriteXKBKeyTypes",0);
192	return 0;
193    }
194    if ((xkb->names==NULL)||(xkb->names->types==None))
195	 fprintf(file,"xkb_types {\n\n");
196    else fprintf(file,"xkb_types \"%s\" {\n\n",
197			XkbAtomText(dpy,xkb->names->types,XkbXKBFile));
198    WriteXKBVModDecl(file,dpy,xkb,
199			(showImplicit?VMOD_COMMENT_VALUE:VMOD_HIDE_VALUE));
200
201    type= xkb->map->types;
202    for (i=0;i<xkb->map->num_types;i++,type++) {
203	fprintf(file,"    type \"%s\" {\n",
204		XkbAtomText(dpy,type->name,XkbXKBFile));
205	fprintf(file,"        modifiers= %s;\n",
206	       XkbVModMaskText(dpy,xkb,type->mods.real_mods,type->mods.vmods,
207								XkbXKBFile));
208	entry= type->map;
209	for (n=0;n<type->map_count;n++,entry++) {
210	    char *str;
211	    str=XkbVModMaskText(dpy,xkb,entry->mods.real_mods,entry->mods.vmods,
212								XkbXKBFile);
213	    fprintf(file,"        map[%s]= Level%d;\n",str,entry->level+1);
214	    if ((type->preserve)&&((type->preserve[n].real_mods)||
215				   (type->preserve[n].vmods))) {
216		fprintf(file,"        preserve[%s]= ",str);
217		fprintf(file,"%s;\n",XkbVModMaskText(dpy,xkb,
218					type->preserve[n].real_mods,
219					type->preserve[n].vmods,
220					XkbXKBFile));
221	    }
222	}
223	if (type->level_names!=NULL) {
224	    Atom *name= type->level_names;
225	    for (n=0;n<type->num_levels;n++,name++) {
226		if ((*name)==None)
227		    continue;
228		fprintf(file,"        level_name[Level%d]= \"%s\";\n",n+1,
229					XkbAtomText(dpy,*name,XkbXKBFile));
230	    }
231	}
232	fprintf(file,"    };\n");
233    }
234    if (addOn)
235	(*addOn)(file,result,topLevel,showImplicit,XkmTypesIndex,priv);
236    fprintf(file,"};\n\n");
237    return True;
238}
239
240static Bool
241WriteXKBIndicatorMap(	FILE *			file,
242			XkbFileInfo *		result,
243			Atom			name,
244			XkbIndicatorMapPtr	led,
245			XkbFileAddOnFunc	addOn,
246			void *			priv)
247{
248XkbDescPtr	xkb;
249
250    xkb= result->xkb;
251    fprintf(file,"    indicator \"%s\" {\n",XkbAtomGetString(xkb->dpy,name));
252    if (led->flags&XkbIM_NoExplicit)
253	fprintf(file,"        !allowExplicit;\n");
254    if (led->flags&XkbIM_LEDDrivesKB)
255	fprintf(file,"        indicatorDrivesKeyboard;\n");
256    if (led->which_groups!=0) {
257	if (led->which_groups!=XkbIM_UseEffective) {
258	    fprintf(file,"        whichGroupState= %s;\n",
259			XkbIMWhichStateMaskText(led->which_groups,XkbXKBFile));
260	}
261	fprintf(file,"        groups= 0x%02x;\n",led->groups);
262    }
263    if (led->which_mods!=0) {
264	if (led->which_mods!=XkbIM_UseEffective) {
265	    fprintf(file,"        whichModState= %s;\n",
266			XkbIMWhichStateMaskText(led->which_mods,XkbXKBFile));
267	}
268	fprintf(file,"        modifiers= %s;\n",
269			XkbVModMaskText(xkb->dpy,xkb,
270					led->mods.real_mods,led->mods.vmods,
271					XkbXKBFile));
272    }
273    if (led->ctrls!=0) {
274	fprintf(file,"        controls= %s;\n",
275			XkbControlsMaskText(led->ctrls,XkbXKBFile));
276    }
277    if (addOn)
278	(*addOn)(file,result,False,True,XkmIndicatorsIndex,priv);
279    fprintf(file,"    };\n");
280    return True;
281}
282
283Bool
284XkbWriteXKBCompatMap(	FILE *			file,
285			XkbFileInfo *		result,
286			Bool			topLevel,
287			Bool			showImplicit,
288			XkbFileAddOnFunc	addOn,
289			void *			priv)
290{
291Display *		dpy;
292register unsigned	i;
293XkbSymInterpretPtr	interp;
294XkbDescPtr		xkb;
295
296    xkb= result->xkb;
297    dpy= xkb->dpy;
298    if ((!xkb)||(!xkb->compat)||(!xkb->compat->sym_interpret)) {
299	_XkbLibError(_XkbErrMissingCompatMap,"XkbWriteXKBCompatMap",0);
300	return False;
301    }
302    if ((xkb->names==NULL)||(xkb->names->compat==None))
303	 fprintf(file,"xkb_compatibility {\n\n");
304    else fprintf(file,"xkb_compatibility \"%s\" {\n\n",
305			XkbAtomText(dpy,xkb->names->compat,XkbXKBFile));
306    WriteXKBVModDecl(file,dpy,xkb,
307			(showImplicit?VMOD_COMMENT_VALUE:VMOD_HIDE_VALUE));
308
309    fprintf(file,"    interpret.useModMapMods= AnyLevel;\n");
310    fprintf(file,"    interpret.repeat= False;\n");
311    fprintf(file,"    interpret.locking= False;\n");
312    interp= xkb->compat->sym_interpret;
313    for (i=0;i<xkb->compat->num_si;i++,interp++) {
314	fprintf(file,"    interpret %s+%s(%s) {\n",
315				((interp->sym==NoSymbol)?"Any":
316					XkbKeysymText(interp->sym,XkbXKBFile)),
317				XkbSIMatchText(interp->match,XkbXKBFile),
318				XkbModMaskText(interp->mods,XkbXKBFile));
319	if (interp->virtual_mod!=XkbNoModifier) {
320	    fprintf(file,"        virtualModifier= %s;\n",
321		XkbVModIndexText(dpy,xkb,interp->virtual_mod,XkbXKBFile));
322	}
323	if (interp->match&XkbSI_LevelOneOnly)
324	    fprintf(file,"        useModMapMods=level1;\n");
325	if (interp->flags&XkbSI_LockingKey)
326	    fprintf(file,"        locking= True;\n");
327	if (interp->flags&XkbSI_AutoRepeat)
328	    fprintf(file,"        repeat= True;\n");
329	fprintf(file,"        action= ");
330	WriteXKBAction(file,result,&interp->act);
331	fprintf(file,";\n");
332	fprintf(file,"    };\n");
333    }
334    for (i=0;i<XkbNumKbdGroups;i++) {
335	XkbModsPtr	gc;
336
337	gc= &xkb->compat->groups[i];
338	if ((gc->real_mods==0)&&(gc->vmods==0))
339	    continue;
340	fprintf(file,"    group %d = %s;\n",i+1,XkbVModMaskText(xkb->dpy,xkb,
341							gc->real_mods,gc->vmods,
342							XkbXKBFile));
343    }
344    if (xkb->indicators) {
345	for (i=0;i<XkbNumIndicators;i++) {
346	    XkbIndicatorMapPtr map= &xkb->indicators->maps[i];
347	    if ((map->flags!=0)||(map->which_groups!=0)||(map->groups!=0)||
348		(map->which_mods!=0)||
349		(map->mods.real_mods!=0)||(map->mods.vmods!=0)||
350		(map->ctrls!=0)) {
351		WriteXKBIndicatorMap(file,result,xkb->names->indicators[i],map,
352								addOn,priv);
353	    }
354	}
355    }
356    if (addOn)
357	(*addOn)(file,result,topLevel,showImplicit,XkmCompatMapIndex,priv);
358    fprintf(file,"};\n\n");
359    return True;
360}
361
362Bool
363XkbWriteXKBSymbols(	FILE *			file,
364			XkbFileInfo *		result,
365			Bool			topLevel,
366			Bool			showImplicit,
367			XkbFileAddOnFunc	addOn,
368			void *			priv)
369{
370Display *		dpy;
371register unsigned	i,tmp;
372XkbDescPtr		xkb;
373XkbClientMapPtr		map;
374XkbServerMapPtr		srv;
375Bool			showActions;
376
377    xkb= result->xkb;
378    map= xkb->map;
379    srv= xkb->server;
380    dpy= xkb->dpy;
381    if ((!xkb)||(!map)||(!map->syms)||(!map->key_sym_map)) {
382	_XkbLibError(_XkbErrMissingSymbols,"XkbWriteXKBSymbols",0);
383	return False;
384    }
385    if ((!xkb->names)||(!xkb->names->keys)) {
386	_XkbLibError(_XkbErrMissingNames,"XkbWriteXKBSymbols",0);
387	return False;
388    }
389    if ((xkb->names==NULL)||(xkb->names->symbols==None))
390	 fprintf(file,"xkb_symbols {\n\n");
391    else fprintf(file,"xkb_symbols \"%s\" {\n\n",
392			XkbAtomText(dpy,xkb->names->symbols,XkbXKBFile));
393    for (tmp=i=0;i<XkbNumKbdGroups;i++) {
394	if (xkb->names->groups[i]!=None) {
395	    fprintf(file,"    name[group%d]=\"%s\";\n",i+1,
396			XkbAtomText(dpy,xkb->names->groups[i],XkbXKBFile));
397	    tmp++;
398	}
399    }
400    if (tmp>0)
401	fprintf(file,"\n");
402    for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
403	Bool	simple;
404	if ((int)XkbKeyNumSyms(xkb,i)<1)
405	    continue;
406	if (XkbFindKeycodeByName(xkb,xkb->names->keys[i].name,True)!=i)
407	    continue;
408	simple= True;
409	fprintf(file,"    key %6s {",
410			XkbKeyNameText(xkb->names->keys[i].name,XkbXKBFile));
411	if (srv->explicit) {
412	    if (((srv->explicit[i]&XkbExplicitKeyTypesMask)!=0)||
413	   						(showImplicit)) {
414		int 	typeNdx,g;
415		Bool	multi;
416		char *	comment="  ";
417
418		if ((srv->explicit[i]&XkbExplicitKeyTypesMask)==0)
419		    comment= "//";
420		multi= False;
421		typeNdx= XkbKeyKeyTypeIndex(xkb,i,0);
422		for (g=1;(g<XkbKeyNumGroups(xkb,i))&&(!multi);g++) {
423		    if (XkbKeyKeyTypeIndex(xkb,i,g)!=typeNdx)
424			multi= True;
425		}
426		if (multi) {
427		    for (g=0;g<XkbKeyNumGroups(xkb,i);g++) {
428			typeNdx= XkbKeyKeyTypeIndex(xkb,i,g);
429			if (srv->explicit[i]&(1<<g)) {
430			    fprintf(file,"\n%s      type[group%d]= \"%s\",",
431			    	comment,g+1,
432				XkbAtomText(dpy,map->types[typeNdx].name,
433			    	XkbXKBFile));
434			}
435			else if (showImplicit) {
436			    fprintf(file,"\n//      type[group%d]= \"%s\",",g+1,
437				XkbAtomText(dpy,map->types[typeNdx].name,
438			    	XkbXKBFile));
439			}
440		    }
441		}
442		else {
443		    fprintf(file,"\n%s      type= \"%s\",",comment,
444				XkbAtomText(dpy,map->types[typeNdx].name,
445			    	XkbXKBFile));
446		}
447		simple= False;
448	    }
449	    if (((srv->explicit[i]&XkbExplicitAutoRepeatMask)!=0)&&
450		    					  (xkb->ctrls!=NULL)) {
451		if (xkb->ctrls->per_key_repeat[i/8]&(1<<(i%8)))
452		     fprintf(file,"\n        repeat= Yes,");
453		else fprintf(file,"\n        repeat= No,");
454		simple= False;
455	    }
456	    if ((xkb->server!=NULL)&&(xkb->server->vmodmap!=NULL)&&
457					(xkb->server->vmodmap[i]!=0)) {
458		if ((srv->explicit[i]&XkbExplicitVModMapMask)!=0) {
459		    fprintf(file,"\n        virtualMods= %s,",
460				XkbVModMaskText(dpy,xkb,0,
461						xkb->server->vmodmap[i],
462						XkbXKBFile));
463		}
464		else if (showImplicit) {
465		    fprintf(file,"\n//      virtualMods= %s,",
466				XkbVModMaskText(dpy,xkb,0,
467						xkb->server->vmodmap[i],
468						XkbXKBFile));
469		}
470	    }
471	}
472	switch (XkbOutOfRangeGroupAction(XkbKeyGroupInfo(xkb,i))) {
473	    case XkbClampIntoRange:
474		fprintf(file,"\n        groupsClamp,");
475		break;
476	    case XkbRedirectIntoRange:
477		fprintf(file,"\n        groupsRedirect= Group%d,",
478			XkbOutOfRangeGroupNumber(XkbKeyGroupInfo(xkb,i))+1);
479		break;
480	}
481	if (srv->behaviors!=NULL) {
482	    unsigned type;
483	    type= srv->behaviors[i].type&XkbKB_OpMask;
484
485	    if (type!=XkbKB_Default) {
486		simple= False;
487		fprintf(file,"\n        %s,",
488			XkbBehaviorText(xkb,&srv->behaviors[i],XkbXKBFile));
489	    }
490	}
491	if ((srv->explicit==NULL) || showImplicit ||
492	    ((srv->explicit[i]&XkbExplicitInterpretMask)!=0))
493	     showActions= XkbKeyHasActions(xkb,i);
494	else showActions= False;
495
496	if (((unsigned)XkbKeyNumGroups(xkb,i)>1)||showActions)
497	    simple= False;
498	if (simple) {
499	    KeySym *syms;
500	    unsigned s;
501
502	    syms= XkbKeySymsPtr(xkb,i);
503	    fprintf(file,"         [ ");
504	    for (s=0;s<XkbKeyGroupWidth(xkb,i,XkbGroup1Index);s++) {
505		if (s!=0)
506		    fprintf(file,", ");
507		fprintf(file,"%15s",XkbKeysymText(*syms++,XkbXKBFile));
508	    }
509	    fprintf(file," ] };\n");
510	}
511	else {
512	    unsigned g,s;
513	    KeySym *syms;
514	    XkbAction *acts;
515	    syms= XkbKeySymsPtr(xkb,i);
516	    acts= XkbKeyActionsPtr(xkb,i);
517	    for (g=0;g<XkbKeyNumGroups(xkb,i);g++) {
518		if (g!=0)
519		    fprintf(file,",");
520		fprintf(file,"\n        symbols[Group%d]= [ ",g+1);
521		for (s=0;s<XkbKeyGroupWidth(xkb,i,g);s++) {
522		    if (s!=0)
523			fprintf(file,", ");
524		    fprintf(file,"%15s",XkbKeysymText(syms[s],XkbXKBFile));
525		}
526		fprintf(file," ]");
527		syms+= XkbKeyGroupsWidth(xkb,i);
528		if (showActions) {
529		    fprintf(file,",\n        actions[Group%d]= [ ",g+1);
530		    for (s=0;s<XkbKeyGroupWidth(xkb,i,g);s++) {
531			if (s!=0)
532			    fprintf(file,", ");
533			WriteXKBAction(file,result,(XkbAnyAction *)&acts[s]);
534		    }
535		    fprintf(file," ]");
536		    acts+= XkbKeyGroupsWidth(xkb,i);
537		}
538	    }
539	    fprintf(file,"\n    };\n");
540	}
541    }
542    if (map && map->modmap) {
543	for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
544	    if (map->modmap[i]!=0) {
545		register int n,bit;
546		for (bit=1,n=0;n<XkbNumModifiers;n++,bit<<=1) {
547		    if (map->modmap[i]&bit) {
548			char buf[5];
549			memcpy(buf,xkb->names->keys[i].name,4);
550			buf[4]= '\0';
551			fprintf(file,"    modifier_map %s { <%s> };\n",
552					XkbModIndexText(n,XkbXKBFile),buf);
553		    }
554		}
555	    }
556	}
557    }
558    if (addOn)
559	(*addOn)(file,result,topLevel,showImplicit,XkmSymbolsIndex,priv);
560    fprintf(file,"};\n\n");
561    return True;
562}
563
564static Bool
565WriteXKBOutline(	FILE *		file,
566			XkbShapePtr	shape,
567			XkbOutlinePtr	outline,
568			int		lastRadius,
569			int		first,
570			int		indent)
571{
572register int	i;
573XkbPointPtr	pt;
574char *		iStr;
575
576    fprintf(file,"%s",iStr= XkbIndentText(first));
577    if (first!=indent)
578	iStr= XkbIndentText(indent);
579    if (outline->corner_radius!=lastRadius) {
580	fprintf(file,"corner= %s,",
581			XkbGeomFPText(outline->corner_radius,XkbMessage));
582	if (shape!=NULL) {
583	    fprintf(file,"\n%s",iStr);
584	}
585    }
586    if (shape) {
587	if (outline==shape->approx)
588	    fprintf(file,"approx= ");
589	else if (outline==shape->primary)
590	    fprintf(file,"primary= ");
591    }
592    fprintf(file,"{");
593    for (pt=outline->points,i=0;i<outline->num_points;i++,pt++) {
594	if (i==0)		fprintf(file," ");
595	else if ((i%4)==0)	fprintf(file,",\n%s  ",iStr);
596	else			fprintf(file,", ");
597	fprintf(file,"[ %3s, %3s ]",XkbGeomFPText(pt->x,XkbXKBFile),
598				  XkbGeomFPText(pt->y,XkbXKBFile));
599    }
600    fprintf(file," }");
601    return True;
602}
603
604static Bool
605WriteXKBDoodad(	FILE *		file,
606		Display *	dpy,
607		unsigned	indent,
608		XkbGeometryPtr	geom,
609		XkbDoodadPtr	doodad)
610{
611register char *	i_str;
612XkbShapePtr	shape;
613XkbColorPtr	color;
614
615    i_str= XkbIndentText(indent);
616    fprintf(file,"%s%s \"%s\" {\n",i_str,
617				XkbDoodadTypeText(doodad->any.type,XkbMessage),
618				XkbAtomText(dpy,doodad->any.name,XkbMessage));
619    fprintf(file,"%s    top=      %s;\n",i_str,
620				 XkbGeomFPText(doodad->any.top,XkbXKBFile));
621    fprintf(file,"%s    left=     %s;\n",i_str,
622				XkbGeomFPText(doodad->any.left,XkbXKBFile));
623    fprintf(file,"%s    priority= %d;\n",i_str,doodad->any.priority);
624    switch (doodad->any.type) {
625	case XkbOutlineDoodad:
626	case XkbSolidDoodad:
627	    if (doodad->shape.angle!=0) {
628		fprintf(file,"%s    angle=  %s;\n",i_str,
629			     XkbGeomFPText(doodad->shape.angle,XkbXKBFile));
630	    }
631	    if (doodad->shape.color_ndx!=0) {
632		fprintf(file,"%s    color= \"%s\";\n",i_str,
633			     XkbShapeDoodadColor(geom,&doodad->shape)->spec);
634	    }
635	    shape= XkbShapeDoodadShape(geom,&doodad->shape);
636	    fprintf(file,"%s    shape= \"%s\";\n",i_str,
637			    XkbAtomText(dpy,shape->name,XkbXKBFile));
638	    break;
639	case XkbTextDoodad:
640	    if (doodad->text.angle!=0) {
641		fprintf(file,"%s    angle=  %s;\n",i_str,
642			     XkbGeomFPText(doodad->text.angle,XkbXKBFile));
643	    }
644	    if (doodad->text.width!=0) {
645		fprintf(file,"%s    width=  %s;\n",i_str,
646			     XkbGeomFPText(doodad->text.width,XkbXKBFile));
647
648	    }
649	    if (doodad->text.height!=0) {
650		fprintf(file,"%s    height=  %s;\n",i_str,
651			     XkbGeomFPText(doodad->text.height,XkbXKBFile));
652
653	    }
654	    if (doodad->text.color_ndx!=0) {
655		color= XkbTextDoodadColor(geom,&doodad->text);
656		fprintf(file,"%s    color= \"%s\";\n",i_str,
657			     XkbStringText(color->spec,XkbXKBFile));
658	    }
659	    fprintf(file,"%s    XFont= \"%s\";\n",i_str,
660	    		     XkbStringText(doodad->text.font,XkbXKBFile));
661	    fprintf(file,"%s    text=  \"%s\";\n",i_str,
662	    		    XkbStringText(doodad->text.text,XkbXKBFile));
663	    break;
664	case XkbIndicatorDoodad:
665	    shape= XkbIndicatorDoodadShape(geom,&doodad->indicator);
666	    color= XkbIndicatorDoodadOnColor(geom,&doodad->indicator);
667	    fprintf(file,"%s    onColor= \"%s\";\n",i_str,
668	    		    XkbStringText(color->spec,XkbXKBFile));
669	    color= XkbIndicatorDoodadOffColor(geom,&doodad->indicator);
670	    fprintf(file,"%s    offColor= \"%s\";\n",i_str,
671	    		    XkbStringText(color->spec,XkbXKBFile));
672	    fprintf(file,"%s    shape= \"%s\";\n",i_str,
673			     XkbAtomText(dpy,shape->name,XkbXKBFile));
674	    break;
675	case XkbLogoDoodad:
676	    fprintf(file,"%s    logoName= \"%s\";\n",i_str,
677			     XkbStringText(doodad->logo.logo_name,XkbXKBFile));
678	    if (doodad->shape.angle!=0) {
679		fprintf(file,"%s    angle=  %s;\n",i_str,
680			     XkbGeomFPText(doodad->logo.angle,XkbXKBFile));
681	    }
682	    if (doodad->shape.color_ndx!=0) {
683		fprintf(file,"%s    color= \"%s\";\n",i_str,
684			     XkbLogoDoodadColor(geom,&doodad->logo)->spec);
685	    }
686	    shape= XkbLogoDoodadShape(geom,&doodad->logo);
687	    fprintf(file,"%s    shape= \"%s\";\n",i_str,
688			    XkbAtomText(dpy,shape->name,XkbXKBFile));
689	    break;
690    }
691    fprintf(file,"%s};\n",i_str);
692    return True;
693}
694
695/*ARGSUSED*/
696static Bool
697WriteXKBOverlay(	FILE *		file,
698			Display *	dpy,
699			unsigned	indent,
700			XkbGeometryPtr	geom,
701			XkbOverlayPtr	ol)
702{
703register char *		i_str;
704int			r,k,nOut;
705XkbOverlayRowPtr	row;
706XkbOverlayKeyPtr	key;
707
708    i_str= XkbIndentText(indent);
709    if (ol->name!=None) {
710	 fprintf(file,"%soverlay \"%s\" {\n",i_str,
711    					XkbAtomText(dpy,ol->name,XkbMessage));
712    }
713    else fprintf(file,"%soverlay {\n",i_str);
714    for (nOut=r=0,row=ol->rows;r<ol->num_rows;r++,row++) {
715	for (k=0,key=row->keys;k<row->num_keys;k++,key++) {
716	    char *over,*under;
717	    over= XkbKeyNameText(key->over.name,XkbXKBFile);
718	    under= XkbKeyNameText(key->under.name,XkbXKBFile);
719	    if (nOut==0)
720		 fprintf(file,"%s    %6s=%6s",i_str,under,over);
721	    else if ((nOut%4)==0)
722		 fprintf(file,",\n%s    %6s=%6s",i_str,under,over);
723	    else fprintf(file,", %6s=%6s",under,over);
724	    nOut++;
725	}
726    }
727    fprintf(file,"\n%s};\n",i_str);
728    return True;
729}
730
731static Bool
732WriteXKBSection(	FILE *		file,
733			Display *	dpy,
734			XkbSectionPtr 	s,
735			XkbGeometryPtr	geom)
736{
737register int	i;
738XkbRowPtr	row;
739int		dfltKeyColor = 0;
740
741    fprintf(file,"    section \"%s\" {\n",
742				XkbAtomText(dpy,s->name,XkbXKBFile));
743    if (s->rows&&(s->rows->num_keys>0)) {
744	dfltKeyColor= s->rows->keys[0].color_ndx;
745	fprintf(file,"        key.color= \"%s\";\n",
746		XkbStringText(geom->colors[dfltKeyColor].spec,XkbXKBFile));
747    }
748    fprintf(file,"        priority=  %d;\n",s->priority);
749    fprintf(file,"        top=       %s;\n",XkbGeomFPText(s->top,XkbXKBFile));
750    fprintf(file,"        left=      %s;\n",XkbGeomFPText(s->left,XkbXKBFile));
751    fprintf(file,"        width=     %s;\n",XkbGeomFPText(s->width,XkbXKBFile));
752    fprintf(file,"        height=    %s;\n",
753					XkbGeomFPText(s->height,XkbXKBFile));
754    if (s->angle!=0) {
755	fprintf(file,"        angle=  %s;\n",
756					XkbGeomFPText(s->angle,XkbXKBFile));
757    }
758    for (i=0,row=s->rows;i<s->num_rows;i++,row++) {
759	fprintf(file,"        row {\n");
760	fprintf(file,"            top=  %s;\n",
761					XkbGeomFPText(row->top,XkbXKBFile));
762	fprintf(file,"            left= %s;\n",
763					XkbGeomFPText(row->left,XkbXKBFile));
764	if (row->vertical)
765	    fprintf(file,"            vertical;\n");
766	if (row->num_keys>0) {
767	    register int 	k;
768	    register XkbKeyPtr	key;
769	    int			forceNL=0;
770	    int			nThisLine= 0;
771	    fprintf(file,"            keys {\n");
772	    for (k=0,key=row->keys;k<row->num_keys;k++,key++) {
773		XkbShapePtr	shape;
774		if (key->color_ndx!=dfltKeyColor)
775		    forceNL= 1;
776		if (k==0) {
777		     fprintf(file,"                ");
778		     nThisLine= 0;
779		}
780		else if (((nThisLine%2)==1)||(forceNL)) {
781		     fprintf(file,",\n                ");
782		     forceNL= nThisLine= 0;
783		}
784		else {
785		     fprintf(file,", ");
786		     nThisLine++;
787		}
788		shape= XkbKeyShape(geom,key);
789		fprintf(file,"{ %6s, \"%s\", %3s",
790		      XkbKeyNameText(key->name.name,XkbXKBFile),
791		      XkbAtomText(dpy,shape->name,XkbXKBFile),
792		      XkbGeomFPText(key->gap,XkbXKBFile));
793		if (key->color_ndx!=dfltKeyColor) {
794		    fprintf(file,", color=\"%s\"",XkbKeyColor(geom,key)->spec);
795		    forceNL= 1;
796		}
797		fprintf(file," }");
798	    }
799	    fprintf(file,"\n            };\n");
800	}
801	fprintf(file,"        };\n");
802    }
803    if (s->doodads!=NULL) {
804	XkbDoodadPtr	doodad;
805	for (i=0,doodad=s->doodads;i<s->num_doodads;i++,doodad++) {
806	    WriteXKBDoodad(file,dpy,8,geom,doodad);
807	}
808    }
809    if (s->overlays!=NULL) {
810	XkbOverlayPtr	ol;
811	for (i=0,ol=s->overlays;i<s->num_overlays;i++,ol++) {
812	    WriteXKBOverlay(file,dpy,8,geom,ol);
813	}
814    }
815    fprintf(file,"    }; // End of \"%s\" section\n\n",
816				XkbAtomText(dpy,s->name,XkbXKBFile));
817    return True;
818}
819
820Bool
821XkbWriteXKBGeometry(	FILE *			file,
822			XkbFileInfo *		result,
823			Bool			topLevel,
824			Bool			showImplicit,
825			XkbFileAddOnFunc	addOn,
826			void *			priv)
827{
828Display *		dpy;
829register unsigned	i,n;
830XkbDescPtr		xkb;
831XkbGeometryPtr		geom;
832
833    xkb= result->xkb;
834    if ((!xkb)||(!xkb->geom)) {
835	_XkbLibError(_XkbErrMissingGeometry,"XkbWriteXKBGeometry",0);
836 	return False;
837    }
838    dpy= xkb->dpy;
839    geom= xkb->geom;
840    if (geom->name==None)
841	 fprintf(file,"xkb_geometry {\n\n");
842    else fprintf(file,"xkb_geometry \"%s\" {\n\n",
843				XkbAtomText(dpy,geom->name,XkbXKBFile));
844    fprintf(file,"    width=       %s;\n",
845				XkbGeomFPText(geom->width_mm,XkbXKBFile));
846    fprintf(file,"    height=      %s;\n\n",
847				XkbGeomFPText(geom->height_mm,XkbXKBFile));
848
849    if (geom->key_aliases!=NULL) {
850	XkbKeyAliasPtr	pAl;
851	pAl= geom->key_aliases;
852	for (i=0;i<geom->num_key_aliases;i++,pAl++) {
853	    fprintf(file,"    alias %6s = %6s;\n",
854				XkbKeyNameText(pAl->alias,XkbXKBFile),
855				XkbKeyNameText(pAl->real,XkbXKBFile));
856	}
857	fprintf(file,"\n");
858    }
859
860    if (geom->base_color!=NULL)
861	fprintf(file,"    baseColor=   \"%s\";\n",
862			XkbStringText(geom->base_color->spec,XkbXKBFile));
863    if (geom->label_color!=NULL)
864	fprintf(file,"    labelColor=  \"%s\";\n",
865			XkbStringText(geom->label_color->spec,XkbXKBFile));
866    if (geom->label_font!=NULL)
867	fprintf(file,"    xfont=       \"%s\";\n",
868			XkbStringText(geom->label_font,XkbXKBFile));
869    if ((geom->num_colors>0)&&(showImplicit)) {
870	XkbColorPtr	color;
871	for (color=geom->colors,i=0;i<geom->num_colors;i++,color++) {
872		fprintf(file,"//     color[%d]= \"%s\"\n",i,
873				XkbStringText(color->spec,XkbXKBFile));
874	}
875	fprintf(file,"\n");
876    }
877    if (geom->num_properties>0) {
878	XkbPropertyPtr	prop;
879	for (prop=geom->properties,i=0;i<geom->num_properties;i++,prop++) {
880	    fprintf(file,"    %s= \"%s\";\n",prop->name,
881    				XkbStringText(prop->value,XkbXKBFile));
882	}
883	fprintf(file,"\n");
884    }
885    if (geom->num_shapes>0) {
886	XkbShapePtr	shape;
887	XkbOutlinePtr	outline;
888	int		lastR;
889	for (shape=geom->shapes,i=0;i<geom->num_shapes;i++,shape++) {
890	    lastR=0;
891	    fprintf(file,"    shape \"%s\" {",
892				   XkbAtomText(dpy,shape->name,XkbXKBFile));
893	    outline= shape->outlines;
894	    if (shape->num_outlines>1) {
895		for (n=0;n<shape->num_outlines;n++,outline++) {
896		    if (n==0)	fprintf(file,"\n");
897		    else	fprintf(file,",\n");
898		    WriteXKBOutline(file,shape,outline,lastR,8,8);
899		    lastR= outline->corner_radius;
900		}
901		fprintf(file,"\n    };\n");
902	    }
903	    else {
904		WriteXKBOutline(file,NULL,outline,lastR,1,8);
905		fprintf(file," };\n");
906	    }
907	}
908    }
909    if (geom->num_sections>0) {
910	XkbSectionPtr	section;
911	for (section=geom->sections,i=0;i<geom->num_sections;i++,section++){
912	    WriteXKBSection(file,dpy,section,geom);
913	}
914    }
915    if (geom->num_doodads>0) {
916	XkbDoodadPtr	doodad;
917	for (i=0,doodad=geom->doodads;i<geom->num_doodads;i++,doodad++) {
918	    WriteXKBDoodad(file,dpy,4,geom,doodad);
919	}
920    }
921    if (addOn)
922	(*addOn)(file,result,topLevel,showImplicit,XkmGeometryIndex,priv);
923    fprintf(file,"};\n\n");
924    return True;
925}
926