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#include <X11/keysym.h>
38#include <X11/Xproto.h>
39#include <X11/extensions/XKMformat.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",NameForAtom(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    if (!xkb) {
357	_XkbLibError(_XkbErrMissingSymbols,"XkbWriteXKBSymbols",0);
358	return FALSE;
359    }
360
361    map= xkb->map;
362    if ((!map)||(!map->syms)||(!map->key_sym_map)) {
363	_XkbLibError(_XkbErrMissingSymbols,"XkbWriteXKBSymbols",0);
364	return FALSE;
365    }
366    if ((!xkb->names)||(!xkb->names->keys)) {
367	_XkbLibError(_XkbErrMissingNames,"XkbWriteXKBSymbols",0);
368	return FALSE;
369    }
370    if ((xkb->names==NULL)||(xkb->names->symbols==None))
371	 fprintf(file,"xkb_symbols {\n\n");
372    else fprintf(file,"xkb_symbols \"%s\" {\n\n",
373			XkbAtomText(xkb->names->symbols,XkbXKBFile));
374    for (tmp=i=0;i<XkbNumKbdGroups;i++) {
375	if (xkb->names->groups[i]!=None) {
376	    fprintf(file,"    name[group%d]=\"%s\";\n",i+1,
377			XkbAtomText(xkb->names->groups[i],XkbXKBFile));
378	    tmp++;
379	}
380    }
381    if (tmp>0)
382	fprintf(file,"\n");
383    srv= xkb->server;
384    for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
385	Bool	simple;
386	if ((int)XkbKeyNumSyms(xkb,i)<1)
387	    continue;
388	if (XkbFindKeycodeByName(xkb,xkb->names->keys[i].name,TRUE)!=i)
389	    continue;
390	simple= TRUE;
391	fprintf(file,"    key %6s {",
392			XkbKeyNameText(xkb->names->keys[i].name,XkbXKBFile));
393	if (srv->explicit) {
394	    if (((srv->explicit[i]&XkbExplicitKeyTypesMask)!=0)||
395	   						(showImplicit)) {
396		int 	typeNdx,g;
397		Bool	multi;
398		char *	comment="  ";
399
400		if ((srv->explicit[i]&XkbExplicitKeyTypesMask)==0)
401		    comment= "//";
402		multi= FALSE;
403		typeNdx= XkbKeyKeyTypeIndex(xkb,i,0);
404		for (g=1;(g<XkbKeyNumGroups(xkb,i))&&(!multi);g++) {
405		    if (XkbKeyKeyTypeIndex(xkb,i,g)!=typeNdx)
406			multi= TRUE;
407		}
408		if (multi) {
409		    for (g=0;g<XkbKeyNumGroups(xkb,i);g++) {
410			typeNdx= XkbKeyKeyTypeIndex(xkb,i,g);
411			if (srv->explicit[i]&(1<<g)) {
412			    fprintf(file,"\n%s      type[group%d]= \"%s\",",
413			    	comment,g+1,
414				XkbAtomText(map->types[typeNdx].name,
415			    	XkbXKBFile));
416			}
417			else if (showImplicit) {
418			    fprintf(file,"\n//      type[group%d]= \"%s\",",g+1,
419				XkbAtomText(map->types[typeNdx].name,
420			    	XkbXKBFile));
421			}
422		    }
423		}
424		else {
425		    fprintf(file,"\n%s      type= \"%s\",",comment,
426				XkbAtomText(map->types[typeNdx].name,
427			    	XkbXKBFile));
428		}
429		simple= FALSE;
430	    }
431	    if (((srv->explicit[i]&XkbExplicitAutoRepeatMask)!=0)&&
432		    					  (xkb->ctrls!=NULL)) {
433		if (xkb->ctrls->per_key_repeat[i/8]&(1<<(i%8)))
434		     fprintf(file,"\n        repeat= Yes,");
435		else fprintf(file,"\n        repeat= No,");
436		simple= FALSE;
437	    }
438	    if ((xkb->server!=NULL)&&(xkb->server->vmodmap!=NULL)&&
439					(xkb->server->vmodmap[i]!=0)) {
440		if ((srv->explicit[i]&XkbExplicitVModMapMask)!=0) {
441		    fprintf(file,"\n        virtualMods= %s,",
442				XkbVModMaskText(xkb,0,
443						xkb->server->vmodmap[i],
444						XkbXKBFile));
445		}
446		else if (showImplicit) {
447		    fprintf(file,"\n//      virtualMods= %s,",
448				XkbVModMaskText(xkb,0,
449						xkb->server->vmodmap[i],
450						XkbXKBFile));
451		}
452	    }
453	}
454	switch (XkbOutOfRangeGroupAction(XkbKeyGroupInfo(xkb,i))) {
455	    case XkbClampIntoRange:
456		fprintf(file,"\n        groupsClamp,");
457		break;
458	    case XkbRedirectIntoRange:
459		fprintf(file,"\n        groupsRedirect= Group%d,",
460			XkbOutOfRangeGroupNumber(XkbKeyGroupInfo(xkb,i))+1);
461		break;
462	}
463	if (srv->behaviors!=NULL) {
464	    unsigned type;
465	    type= srv->behaviors[i].type&XkbKB_OpMask;
466
467	    if (type!=XkbKB_Default) {
468		simple= FALSE;
469		fprintf(file,"\n        %s,",
470			XkbBehaviorText(xkb,&srv->behaviors[i],XkbXKBFile));
471	    }
472	}
473	if ((srv->explicit==NULL) || showImplicit ||
474	    ((srv->explicit[i]&XkbExplicitInterpretMask)!=0))
475	     showActions= XkbKeyHasActions(xkb,i);
476	else showActions= FALSE;
477
478	if (((unsigned)XkbKeyNumGroups(xkb,i)>1)||showActions)
479	    simple= FALSE;
480	if (simple) {
481	    KeySym *syms;
482	    unsigned s;
483
484	    syms= XkbKeySymsPtr(xkb,i);
485	    fprintf(file,"         [ ");
486	    for (s=0;s<XkbKeyGroupWidth(xkb,i,XkbGroup1Index);s++) {
487		if (s!=0)
488		    fprintf(file,", ");
489		fprintf(file,"%15s",XkbKeysymText(*syms++,XkbXKBFile));
490	    }
491	    fprintf(file," ] };\n");
492	}
493	else {
494	    unsigned g,s;
495	    KeySym *syms;
496	    XkbAction *acts;
497	    syms= XkbKeySymsPtr(xkb,i);
498	    acts= XkbKeyActionsPtr(xkb,i);
499	    for (g=0;g<XkbKeyNumGroups(xkb,i);g++) {
500		if (g!=0)
501		    fprintf(file,",");
502		fprintf(file,"\n        symbols[Group%d]= [ ",g+1);
503		for (s=0;s<XkbKeyGroupWidth(xkb,i,g);s++) {
504		    if (s!=0)
505			fprintf(file,", ");
506		    fprintf(file,"%15s",XkbKeysymText(syms[s],XkbXKBFile));
507		}
508		fprintf(file," ]");
509		syms+= XkbKeyGroupsWidth(xkb,i);
510		if (showActions) {
511		    fprintf(file,",\n        actions[Group%d]= [ ",g+1);
512		    for (s=0;s<XkbKeyGroupWidth(xkb,i,g);s++) {
513			if (s!=0)
514			    fprintf(file,", ");
515			WriteXKBAction(file,xkb,(XkbAnyAction *)&acts[s]);
516		    }
517		    fprintf(file," ]");
518		    acts+= XkbKeyGroupsWidth(xkb,i);
519		}
520	    }
521	    fprintf(file,"\n    };\n");
522	}
523    }
524    if (map && map->modmap) {
525	for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
526	    if (map->modmap[i]!=0) {
527		register int n,bit;
528		for (bit=1,n=0;n<XkbNumModifiers;n++,bit<<=1) {
529		    if (map->modmap[i]&bit) {
530			char buf[5];
531			memcpy(buf,xkb->names->keys[i].name,4);
532			buf[4]= '\0';
533			fprintf(file,"    modifier_map %s { <%s> };\n",
534					XkbModIndexText(n,XkbXKBFile),buf);
535		    }
536		}
537	    }
538	}
539    }
540    if (addOn)
541	(*addOn)(file,xkb,topLevel,showImplicit,XkmSymbolsIndex,priv);
542    fprintf(file,"};\n\n");
543    return TRUE;
544}
545
546static Bool
547WriteXKBOutline(	FILE *		file,
548			XkbShapePtr	shape,
549			XkbOutlinePtr	outline,
550			int		lastRadius,
551			int		first,
552			int		indent)
553{
554register int	i;
555XkbPointPtr	pt;
556char *		iStr;
557
558    fprintf(file,"%s",iStr= XkbIndentText(first));
559    if (first!=indent)
560	iStr= XkbIndentText(indent);
561    if (outline->corner_radius!=lastRadius) {
562	fprintf(file,"corner= %s,",
563			XkbGeomFPText(outline->corner_radius,XkbMessage));
564	if (shape!=NULL) {
565	    fprintf(file,"\n%s",iStr);
566	}
567    }
568    if (shape) {
569	if (outline==shape->approx)
570	    fprintf(file,"approx= ");
571	else if (outline==shape->primary)
572	    fprintf(file,"primary= ");
573    }
574    fprintf(file,"{");
575    for (pt=outline->points,i=0;i<outline->num_points;i++,pt++) {
576	if (i==0)		fprintf(file," ");
577	else if ((i%4)==0)	fprintf(file,",\n%s  ",iStr);
578	else			fprintf(file,", ");
579	fprintf(file,"[ %3s, %3s ]",XkbGeomFPText(pt->x,XkbXKBFile),
580				  XkbGeomFPText(pt->y,XkbXKBFile));
581    }
582    fprintf(file," }");
583    return TRUE;
584}
585
586static Bool
587WriteXKBDoodad(	FILE *		file,
588		unsigned	indent,
589		XkbGeometryPtr	geom,
590		XkbDoodadPtr	doodad)
591{
592register char *	i_str;
593XkbShapePtr	shape;
594XkbColorPtr	color;
595
596    i_str= XkbIndentText(indent);
597    fprintf(file,"%s%s \"%s\" {\n",i_str,
598				XkbDoodadTypeText(doodad->any.type,XkbMessage),
599				XkbAtomText(doodad->any.name,XkbMessage));
600    fprintf(file,"%s    top=      %s;\n",i_str,
601				 XkbGeomFPText(doodad->any.top,XkbXKBFile));
602    fprintf(file,"%s    left=     %s;\n",i_str,
603				XkbGeomFPText(doodad->any.left,XkbXKBFile));
604    fprintf(file,"%s    priority= %d;\n",i_str,doodad->any.priority);
605    switch (doodad->any.type) {
606	case XkbOutlineDoodad:
607	case XkbSolidDoodad:
608	    if (doodad->shape.angle!=0) {
609		fprintf(file,"%s    angle=  %s;\n",i_str,
610			     XkbGeomFPText(doodad->shape.angle,XkbXKBFile));
611	    }
612	    if (doodad->shape.color_ndx!=0) {
613		fprintf(file,"%s    color= \"%s\";\n",i_str,
614			     XkbShapeDoodadColor(geom,&doodad->shape)->spec);
615	    }
616	    shape= XkbShapeDoodadShape(geom,&doodad->shape);
617	    fprintf(file,"%s    shape= \"%s\";\n",i_str,
618			    XkbAtomText(shape->name,XkbXKBFile));
619	    break;
620	case XkbTextDoodad:
621	    if (doodad->text.angle!=0) {
622		fprintf(file,"%s    angle=  %s;\n",i_str,
623			     XkbGeomFPText(doodad->text.angle,XkbXKBFile));
624	    }
625	    if (doodad->text.width!=0) {
626		fprintf(file,"%s    width=  %s;\n",i_str,
627			     XkbGeomFPText(doodad->text.width,XkbXKBFile));
628
629	    }
630	    if (doodad->text.height!=0) {
631		fprintf(file,"%s    height=  %s;\n",i_str,
632			     XkbGeomFPText(doodad->text.height,XkbXKBFile));
633
634	    }
635	    if (doodad->text.color_ndx!=0) {
636		color= XkbTextDoodadColor(geom,&doodad->text);
637		fprintf(file,"%s    color= \"%s\";\n",i_str,
638			     XkbStringText(color->spec,XkbXKBFile));
639	    }
640	    fprintf(file,"%s    XFont= \"%s\";\n",i_str,
641	    		     XkbStringText(doodad->text.font,XkbXKBFile));
642	    fprintf(file,"%s    text=  \"%s\";\n",i_str,
643	    		    XkbStringText(doodad->text.text,XkbXKBFile));
644	    break;
645	case XkbIndicatorDoodad:
646	    shape= XkbIndicatorDoodadShape(geom,&doodad->indicator);
647	    color= XkbIndicatorDoodadOnColor(geom,&doodad->indicator);
648	    fprintf(file,"%s    onColor= \"%s\";\n",i_str,
649	    		    XkbStringText(color->spec,XkbXKBFile));
650	    color= XkbIndicatorDoodadOffColor(geom,&doodad->indicator);
651	    fprintf(file,"%s    offColor= \"%s\";\n",i_str,
652	    		    XkbStringText(color->spec,XkbXKBFile));
653	    fprintf(file,"%s    shape= \"%s\";\n",i_str,
654			     XkbAtomText(shape->name,XkbXKBFile));
655	    break;
656	case XkbLogoDoodad:
657	    fprintf(file,"%s    logoName= \"%s\";\n",i_str,
658			     XkbStringText(doodad->logo.logo_name,XkbXKBFile));
659	    if (doodad->shape.angle!=0) {
660		fprintf(file,"%s    angle=  %s;\n",i_str,
661			     XkbGeomFPText(doodad->logo.angle,XkbXKBFile));
662	    }
663	    if (doodad->shape.color_ndx!=0) {
664		fprintf(file,"%s    color= \"%s\";\n",i_str,
665			     XkbLogoDoodadColor(geom,&doodad->logo)->spec);
666	    }
667	    shape= XkbLogoDoodadShape(geom,&doodad->logo);
668	    fprintf(file,"%s    shape= \"%s\";\n",i_str,
669			    XkbAtomText(shape->name,XkbXKBFile));
670	    break;
671    }
672    fprintf(file,"%s};\n",i_str);
673    return TRUE;
674}
675
676/*ARGSUSED*/
677static Bool
678WriteXKBOverlay(	FILE *		file,
679			unsigned	indent,
680			XkbGeometryPtr	geom,
681			XkbOverlayPtr	ol)
682{
683register char *		i_str;
684int			r,k,nOut;
685XkbOverlayRowPtr	row;
686XkbOverlayKeyPtr	key;
687
688    i_str= XkbIndentText(indent);
689    if (ol->name!=None) {
690	 fprintf(file,"%soverlay \"%s\" {\n",i_str,
691    					XkbAtomText(ol->name,XkbMessage));
692    }
693    else fprintf(file,"%soverlay {\n",i_str);
694    for (nOut=r=0,row=ol->rows;r<ol->num_rows;r++,row++) {
695	for (k=0,key=row->keys;k<row->num_keys;k++,key++) {
696	    char *over,*under;
697	    over= XkbKeyNameText(key->over.name,XkbXKBFile);
698	    under= XkbKeyNameText(key->under.name,XkbXKBFile);
699	    if (nOut==0)
700		 fprintf(file,"%s    %6s=%6s",i_str,under,over);
701	    else if ((nOut%4)==0)
702		 fprintf(file,",\n%s    %6s=%6s",i_str,under,over);
703	    else fprintf(file,", %6s=%6s",under,over);
704	    nOut++;
705	}
706    }
707    fprintf(file,"\n%s};\n",i_str);
708    return TRUE;
709}
710
711static Bool
712WriteXKBSection(	FILE *		file,
713			XkbSectionPtr 	s,
714			XkbGeometryPtr	geom)
715{
716register int	i;
717XkbRowPtr	row;
718int		dfltKeyColor = 0;
719
720    fprintf(file,"    section \"%s\" {\n",
721				XkbAtomText(s->name,XkbXKBFile));
722    if (s->rows&&(s->rows->num_keys>0)) {
723	dfltKeyColor= s->rows->keys[0].color_ndx;
724	fprintf(file,"        key.color= \"%s\";\n",
725		XkbStringText(geom->colors[dfltKeyColor].spec,XkbXKBFile));
726    }
727    fprintf(file,"        priority=  %d;\n",s->priority);
728    fprintf(file,"        top=       %s;\n",XkbGeomFPText(s->top,XkbXKBFile));
729    fprintf(file,"        left=      %s;\n",XkbGeomFPText(s->left,XkbXKBFile));
730    fprintf(file,"        width=     %s;\n",XkbGeomFPText(s->width,XkbXKBFile));
731    fprintf(file,"        height=    %s;\n",
732					XkbGeomFPText(s->height,XkbXKBFile));
733    if (s->angle!=0) {
734	fprintf(file,"        angle=  %s;\n",
735					XkbGeomFPText(s->angle,XkbXKBFile));
736    }
737    for (i=0,row=s->rows;i<s->num_rows;i++,row++) {
738	fprintf(file,"        row {\n");
739	fprintf(file,"            top=  %s;\n",
740					XkbGeomFPText(row->top,XkbXKBFile));
741	fprintf(file,"            left= %s;\n",
742					XkbGeomFPText(row->left,XkbXKBFile));
743	if (row->vertical)
744	    fprintf(file,"            vertical;\n");
745	if (row->num_keys>0) {
746	    register int 	k;
747	    register XkbKeyPtr	key;
748	    int			forceNL=0;
749	    int			nThisLine= 0;
750	    fprintf(file,"            keys {\n");
751	    for (k=0,key=row->keys;k<row->num_keys;k++,key++) {
752		XkbShapePtr	shape;
753		if (key->color_ndx!=dfltKeyColor)
754		    forceNL= 1;
755		if (k==0) {
756		     fprintf(file,"                ");
757		     nThisLine= 0;
758		}
759		else if (((nThisLine%2)==1)||(forceNL)) {
760		     fprintf(file,",\n                ");
761		     forceNL= nThisLine= 0;
762		}
763		else {
764		     fprintf(file,", ");
765		     nThisLine++;
766		}
767		shape= XkbKeyShape(geom,key);
768		fprintf(file,"{ %6s, \"%s\", %3s",
769		      XkbKeyNameText(key->name.name,XkbXKBFile),
770		      XkbAtomText(shape->name,XkbXKBFile),
771		      XkbGeomFPText(key->gap,XkbXKBFile));
772		if (key->color_ndx!=dfltKeyColor) {
773		    fprintf(file,", color=\"%s\"",XkbKeyColor(geom,key)->spec);
774		    forceNL= 1;
775		}
776		fprintf(file," }");
777	    }
778	    fprintf(file,"\n            };\n");
779	}
780	fprintf(file,"        };\n");
781    }
782    if (s->doodads!=NULL) {
783	XkbDoodadPtr	doodad;
784	for (i=0,doodad=s->doodads;i<s->num_doodads;i++,doodad++) {
785	    WriteXKBDoodad(file,8,geom,doodad);
786	}
787    }
788    if (s->overlays!=NULL) {
789	XkbOverlayPtr	ol;
790	for (i=0,ol=s->overlays;i<s->num_overlays;i++,ol++) {
791	    WriteXKBOverlay(file,8,geom,ol);
792	}
793    }
794    fprintf(file,"    }; // End of \"%s\" section\n\n",
795				XkbAtomText(s->name,XkbXKBFile));
796    return TRUE;
797}
798
799Bool
800XkbWriteXKBGeometry(	FILE *			file,
801			XkbDescPtr              xkb,
802			Bool			topLevel,
803			Bool			showImplicit,
804			XkbFileAddOnFunc	addOn,
805			void *			priv)
806{
807register unsigned	i,n;
808XkbGeometryPtr		geom;
809
810    if ((!xkb)||(!xkb->geom)) {
811	_XkbLibError(_XkbErrMissingGeometry,"XkbWriteXKBGeometry",0);
812	return FALSE;
813    }
814    geom= xkb->geom;
815    if (geom->name==None)
816	 fprintf(file,"xkb_geometry {\n\n");
817    else fprintf(file,"xkb_geometry \"%s\" {\n\n",
818				XkbAtomText(geom->name,XkbXKBFile));
819    fprintf(file,"    width=       %s;\n",
820				XkbGeomFPText(geom->width_mm,XkbXKBFile));
821    fprintf(file,"    height=      %s;\n\n",
822				XkbGeomFPText(geom->height_mm,XkbXKBFile));
823
824    if (geom->key_aliases!=NULL) {
825	XkbKeyAliasPtr	pAl;
826	pAl= geom->key_aliases;
827	for (i=0;i<geom->num_key_aliases;i++,pAl++) {
828	    fprintf(file,"    alias %6s = %6s;\n",
829				XkbKeyNameText(pAl->alias,XkbXKBFile),
830				XkbKeyNameText(pAl->real,XkbXKBFile));
831	}
832	fprintf(file,"\n");
833    }
834
835    if (geom->base_color!=NULL)
836	fprintf(file,"    baseColor=   \"%s\";\n",
837			XkbStringText(geom->base_color->spec,XkbXKBFile));
838    if (geom->label_color!=NULL)
839	fprintf(file,"    labelColor=  \"%s\";\n",
840			XkbStringText(geom->label_color->spec,XkbXKBFile));
841    if (geom->label_font!=NULL)
842	fprintf(file,"    xfont=       \"%s\";\n",
843			XkbStringText(geom->label_font,XkbXKBFile));
844    if ((geom->num_colors>0)&&(showImplicit)) {
845	XkbColorPtr	color;
846	for (color=geom->colors,i=0;i<geom->num_colors;i++,color++) {
847		fprintf(file,"//     color[%d]= \"%s\"\n",i,
848				XkbStringText(color->spec,XkbXKBFile));
849	}
850	fprintf(file,"\n");
851    }
852    if (geom->num_properties>0) {
853	XkbPropertyPtr	prop;
854	for (prop=geom->properties,i=0;i<geom->num_properties;i++,prop++) {
855	    fprintf(file,"    %s= \"%s\";\n",prop->name,
856    				XkbStringText(prop->value,XkbXKBFile));
857	}
858	fprintf(file,"\n");
859    }
860    if (geom->num_shapes>0) {
861	XkbShapePtr	shape;
862	XkbOutlinePtr	outline;
863	int		lastR;
864	for (shape=geom->shapes,i=0;i<geom->num_shapes;i++,shape++) {
865	    lastR=0;
866	    fprintf(file,"    shape \"%s\" {",
867				   XkbAtomText(shape->name,XkbXKBFile));
868	    outline= shape->outlines;
869	    if (shape->num_outlines>1) {
870		for (n=0;n<shape->num_outlines;n++,outline++) {
871		    if (n==0)	fprintf(file,"\n");
872		    else	fprintf(file,",\n");
873		    WriteXKBOutline(file,shape,outline,lastR,8,8);
874		    lastR= outline->corner_radius;
875		}
876		fprintf(file,"\n    };\n");
877	    }
878	    else {
879		WriteXKBOutline(file,NULL,outline,lastR,1,8);
880		fprintf(file," };\n");
881	    }
882	}
883    }
884    if (geom->num_sections>0) {
885	XkbSectionPtr	section;
886	for (section=geom->sections,i=0;i<geom->num_sections;i++,section++){
887	    WriteXKBSection(file,section,geom);
888	}
889    }
890    if (geom->num_doodads>0) {
891	XkbDoodadPtr	doodad;
892	for (i=0,doodad=geom->doodads;i<geom->num_doodads;i++,doodad++) {
893	    WriteXKBDoodad(file,4,geom,doodad);
894	}
895    }
896    if (addOn)
897	(*addOn)(file,xkb,topLevel,showImplicit,XkmGeometryIndex,priv);
898    fprintf(file,"};\n\n");
899    return TRUE;
900}
901