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