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