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