psgeom.c revision 3e6697d4
1/* $Xorg: psgeom.c,v 1.4 2000/08/17 19:54:50 cpqbld Exp $ */
2/************************************************************
3 Copyright (c) 1995 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/programs/xkbprint/psgeom.c,v 1.5 2001/07/25 15:05:25 dawes Exp $ */
28
29#define	XK_TECHNICAL
30#define	XK_PUBLISHING
31#define	XK_KATAKANA
32#include <stdio.h>
33#include <ctype.h>
34#include <X11/X.h>
35#include <X11/Xlib.h>
36#include <X11/XKBlib.h>
37#include <X11/extensions/XKBgeom.h>
38#include <X11/extensions/XKM.h>
39#include <X11/extensions/XKBfile.h>
40#include <X11/keysym.h>
41#include <X11/Xutil.h>
42
43#if defined(sgi)
44#include <malloc.h>
45#endif
46
47#define	DEBUG_VAR_NOT_LOCAL
48#define	DEBUG_VAR debugFlags
49#include <stdlib.h>
50
51#include "utils.h"
52#include "xkbprint.h"
53#include "isokeys.h"
54
55#define	FONT_NONE	-1
56#define	FONT_TEXT	0
57#define	FONT_LATIN1	1
58#define	FONT_SYMBOL	2
59#define	FONT_ISOCAPS	3
60#define	FONT_MOUSECAPS	4
61
62typedef struct {
63	Display *	dpy;
64	XkbDescPtr	xkb;
65	XkbGeometryPtr	geom;
66	int		totalKB;
67	int		kbPerPage;
68	int		black;
69	int		white;
70	int		color;
71	int		font;
72	int		fontSize;
73	int		nPages;
74	int		x1,y1;
75	int		x2,y2;
76	XKBPrintArgs *	args;
77} PSState;
78
79#define	G1L1		0
80#define	G1L2		1
81#define	G2L1		2
82#define	G2L2		3
83#define	CENTER		4
84
85#define	G1L1_MASK	(1<<G1L1)
86#define	G1L2_MASK	(1<<G1L2)
87#define	G2L1_MASK	(1<<G2L1)
88#define	G2L2_MASK	(1<<G2L2)
89#define	CENTER_MASK	(1<<CENTER)
90
91#define	LABEL_MASK	(0x1f)
92#define	GXL1_MASK	(G1L1_MASK|G2L1_MASK)
93#define	GXL2_MASK	(G1L2_MASK|G2L2_MASK)
94#define	G1LX_MASK	(G1L1_MASK|G1L2_MASK)
95#define	G2LX_MASK	(G2L1_MASK|G2L2_MASK)
96#define	GXLX_MASK	(0x0f)
97
98#define	NLABELS		5
99#define	LABEL_LEN	30
100
101#define	SZ_AUTO		0
102#define	SZ_TINY		1
103#define	SZ_SMALL	2
104#define	SZ_MEDIUM	3
105#define	SZ_LARGE	4
106#define	SZ_XLARGE	5
107
108typedef struct {
109	unsigned	present;
110	Bool		alpha[2];
111	char 		label[NLABELS][LABEL_LEN];
112	int		font[NLABELS];
113	int		size[NLABELS];
114} KeyTop;
115
116#define	DFLT_LABEL_FONT "Helvetica-Narrow-Bold"
117#define DFLT_LABEL_FONT_SIZE 10
118
119/***====================================================================***/
120
121typedef struct _PSFontDef {
122    char *name;
123    char **def;
124} PSFontDef;
125
126static PSFontDef internalFonts[] = {
127	{ "IsoKeyCaps", IsoKeyCaps }
128};
129static int nInternalFonts =	(sizeof(internalFonts)/sizeof(PSFontDef));
130
131static void
132ListInternalFonts(FILE *out, int first, int indent)
133{
134register int i,n,nThisLine;
135
136    for (n=0;n<first;n++) {
137	putc(' ',out);
138    }
139
140    for (nThisLine=i=0;i<nInternalFonts;i++) {
141	if (nThisLine==4) {
142	    fprintf(out,",\n");
143	    for (n=0;n<indent;n++) {
144		putc(' ',out);
145	    }
146	    nThisLine= 0;
147	}
148	if (nThisLine==0)
149	     fprintf(out,"%s",internalFonts[i].name);
150	else fprintf(out,", %s",internalFonts[i].name);
151	nThisLine++;
152    }
153    if (nThisLine!=0)
154	fprintf(out,"\n");
155    return;
156}
157
158static Bool
159PSIncludeFont(FILE *out, char *font)
160{
161char **		pstr;
162register int	i;
163
164    pstr= NULL;
165    for (i=0;(i<nInternalFonts)&&(pstr==NULL);i++) {
166	if (uStringEqual(internalFonts[i].name,font))
167	    pstr= internalFonts[i].def;
168    }
169    if (pstr!=NULL) {
170	fprintf(out,"%%%%BeginFont: %s\n",font);
171	while (*pstr!=NULL) {
172	    fprintf(out,"%s\n",*pstr);
173	    pstr++;
174	}
175	fprintf(out,"%%%%EndFont\n");
176	return True;
177    }
178    return False;
179}
180
181Bool
182DumpInternalFont(FILE *out, char *fontName)
183{
184    if (strcmp(fontName,"IsoKeyCaps")!=0) {
185	uError("No internal font named \"%s\"\n",fontName);
186	uAction("No font dumped\n");
187	fprintf(stderr,"Current internal fonts are: ");
188	ListInternalFonts(stderr,0,8);
189	return False;
190    }
191    PSIncludeFont(out,fontName);
192    return True;
193}
194
195/***====================================================================***/
196
197static void
198PSColorDef(FILE *out, PSState *state, XkbColorPtr color)
199{
200int	tmp;
201
202    fprintf(out,"/C%03d ",color->pixel);
203    if (uStrCaseEqual(color->spec,"black")) {
204	state->black= color->pixel;
205	fprintf(out,"{ 0 setgray } def      %% %s\n",color->spec);
206    }
207    else if (uStrCaseEqual(color->spec,"white")) {
208	state->white= color->pixel;
209	fprintf(out,"{ 1 setgray } def      %% %s\n",color->spec);
210    }
211    else if ((sscanf(color->spec,"grey%d",&tmp)==1)||
212	(sscanf(color->spec,"gray%d",&tmp)==1)||
213	(sscanf(color->spec,"Grey%d",&tmp)==1)||
214	(sscanf(color->spec,"Gray%d",&tmp)==1)) {
215	fprintf(out,"{ %f setgray } def	    %% %s\n",1.0-(((float)tmp)/100.0),
216								color->spec);
217    }
218    else if ((tmp=(uStrCaseEqual(color->spec,"red")*100))||
219	     (sscanf(color->spec,"red%d",&tmp)==1)) {
220	 fprintf(out,"{ %f 0 0 setrgbcolor } def %% %s\n",(((float)tmp)/100.0),
221								color->spec);
222    }
223    else if ((tmp=(uStrCaseEqual(color->spec,"green")*100))||
224	     (sscanf(color->spec,"green%d",&tmp)==1)) {
225	 fprintf(out,"{ 0 %f 0 setrgbcolor } def %% %s\n",(((float)tmp)/100.0),
226								color->spec);
227    }
228    else if ((tmp=(uStrCaseEqual(color->spec,"blue")*100))||
229	     (sscanf(color->spec,"blue%d",&tmp)==1)) {
230	 fprintf(out,"{ 0 0 %f setrgbcolor } def %% %s\n",(((float)tmp)/100.0),
231								color->spec);
232    }
233    else fprintf(out,"{ 0.9 setgray       } def %% BOGUS! %s\n",color->spec);
234}
235
236static void
237PSSetColor(FILE *out,PSState *state,int color)
238{
239    if ((state->args->wantColor)&&(state->color!=color)) {
240	fprintf(out,"C%03d %% set color\n",color);
241	state->color= color;
242    }
243    return;
244}
245
246static void
247PSGSave(FILE *out, PSState *state)
248{
249    fprintf(out,"gsave\n");
250    return;
251}
252
253static void
254PSGRestore(FILE *out, PSState *state)
255{
256    fprintf(out,"grestore\n");
257    state->color= -1;
258    state->font= FONT_NONE;
259    state->fontSize= -1;
260    return;
261}
262
263static void
264PSShapeDef(FILE *out, PSState *state, XkbShapePtr shape)
265{
266int		o,p;
267XkbOutlinePtr	ol;
268
269    fprintf(out,"/%s {\n",XkbAtomGetString(state->dpy,shape->name));
270    fprintf(out,"	gsave translate rotate /SOLID exch def\n");
271    for (o=0,ol=shape->outlines;o<shape->num_outlines;o++,ol++) {
272	XkbPointPtr	pt;
273	if ((shape->num_outlines>1)&&(ol==shape->approx))
274	    continue;
275	pt=ol->points;
276	fprintf(out,"%%	Outline %d\n",o+1);
277	if (ol->num_points==1) {
278	    if (ol->corner_radius<1) {
279		fprintf(out,"	  0   0 moveto\n");
280		fprintf(out,"	%3d   0 lineto\n",pt->x);
281		fprintf(out,"	%3d %3d lineto\n",pt->x,pt->y);
282		fprintf(out,"	  0 %3d lineto\n",pt->y);
283		fprintf(out,"	  0   0 lineto\n");
284		fprintf(out,"	SOLID { fill } { stroke } ifelse\n");
285	    }
286	    else {
287		fprintf(out,"	mark\n");
288		fprintf(out,"	%3d   0 moveto\n",ol->corner_radius);
289		fprintf(out,"	%3d   0 %3d %3d %3d arcto\n",pt->x,pt->x,pt->y,
290							ol->corner_radius);
291		fprintf(out,"	%3d %3d   0 %3d %3d arcto\n",pt->x,pt->y,pt->y,
292							ol->corner_radius);
293		fprintf(out,"	  0 %3d   0   0 %3d arcto\n",pt->y,
294							ol->corner_radius);
295		fprintf(out,"     0   0 %3d   0 %3d arcto\n",pt->x,
296							ol->corner_radius);
297		fprintf(out,"	SOLID { fill } { stroke } ifelse\n");
298		fprintf(out,"	cleartomark\n");
299	    }
300	}
301	else if (ol->num_points==2) {
302	    if (ol->corner_radius<1) {
303		fprintf(out,"	%3d %3d moveto\n",pt[0].x,pt[0].y);
304		fprintf(out,"	%3d %3d lineto\n",pt[1].x,pt[0].y);
305		fprintf(out,"	%3d %3d lineto\n",pt[1].x,pt[1].y);
306		fprintf(out,"	%3d %3d lineto\n",pt[0].x,pt[1].y);
307		fprintf(out,"	%3d %3d lineto\n",pt[0].x,pt[0].y);
308		fprintf(out,"	SOLID { fill } { stroke } ifelse\n");
309	    }
310	    else {
311		fprintf(out,"	mark\n");
312		fprintf(out,"	%3d %3d moveto\n",pt[0].x + ol->corner_radius,pt[0].y);
313		fprintf(out,"	%3d %3d %3d %3d %3d arcto\n",pt[1].x,pt[0].y,
314							pt[1].x,pt[1].y,
315							ol->corner_radius);
316		fprintf(out,"	%3d %3d %3d %3d %3d arcto\n",pt[1].x,pt[1].y,
317							pt[0].x,pt[1].y,
318							ol->corner_radius);
319		fprintf(out,"	%3d %3d %3d %3d %3d arcto\n",pt[0].x,pt[1].y,
320							pt[0].x,pt[0].y,
321							ol->corner_radius);
322		fprintf(out,"   %3d %3d %3d %3d %3d arcto\n",pt[0].x,pt[0].y,
323							pt[1].x,pt[0].y,
324							ol->corner_radius);
325		fprintf(out,"	SOLID { fill } { stroke } ifelse\n");
326		fprintf(out,"	cleartomark\n");
327	    }
328	}
329	else {
330	    if (ol->corner_radius<1) {
331		fprintf(out,"	%3d %3d moveto\n",pt->x,pt->y);
332		pt++;
333		for (p=1;p<ol->num_points;p++,pt++) {
334		    fprintf(out,"	%3d %3d lineto\n",pt->x,pt->y);
335		}
336		if ((pt->x!=ol->points[0].x)||(pt->y!=ol->points[0].y))
337		    fprintf(out,"	closepath\n");
338		fprintf(out,"	SOLID { fill } { stroke } ifelse\n");
339	    }
340	    else {
341		XkbPointPtr	last;
342		last= &pt[ol->num_points-1];
343		if ((last->x==pt->x)&&(last->y==pt->y))
344		    last--;
345		fprintf(out,"	mark\n");
346		fprintf(out,"	%% Determine tangent point of first corner\n");
347		fprintf(out,"	%3d %3d moveto %d %d %d %d %d arcto\n",
348					last->x,last->y,
349					pt[0].x,pt[0].y,pt[1].x,pt[1].y,
350					ol->corner_radius);
351		fprintf(out,"	/TY exch def /TX exch def pop pop newpath\n");
352		fprintf(out,"	%% Now draw the shape\n");
353		fprintf(out,"	TX TY moveto\n");
354		for (p=1;p<ol->num_points;p++) {
355		    if (p<(ol->num_points-1))	last= &pt[p+1];
356		    else			last= &pt[0];
357		    fprintf(out,"	%3d %3d %3d %3d %3d arcto\n",
358						pt[p].x,pt[p].y,
359						last->x,last->y,
360						ol->corner_radius);
361		}
362		last= &pt[ol->num_points-1];
363		if ((last->x!=pt->x)||(last->y!=pt->y)) {
364		    fprintf(out,"	%3d %3d %3d %3d %3d arcto\n",
365						pt[0].x,pt[0].y,
366						pt[1].x,pt[1].y,
367						ol->corner_radius);
368		}
369		fprintf(out,"	SOLID { fill } { stroke } ifelse\n");
370		fprintf(out,"	cleartomark\n");
371	    }
372	}
373    }
374    fprintf(out,"	grestore\n");
375    fprintf(out,"} def\n");
376    return;
377}
378
379/***====================================================================***/
380
381typedef	struct {
382	char *		foundry;
383	char *		face;
384	char *		weight;
385	char *		slant;
386	char *		setWidth;
387	char *		variant;
388	int		pixelSize;
389	int		ptSize;
390	int		resX;
391	int		resY;
392	char *		spacing;
393	int		avgWidth;
394	char *		encoding;
395} FontStuff;
396
397static void
398ClearFontStuff(FontStuff *stuff)
399{
400    if (stuff && stuff->foundry)
401	uFree(stuff->foundry);
402    bzero(stuff,sizeof(FontStuff));
403    return;
404}
405
406static Bool
407CrackXLFDName(char *name, FontStuff *stuff)
408{
409char *tmp;
410    if ((name==NULL)||(stuff==NULL))
411	return False;
412    if (name[0]=='-')	tmp= uStringDup(&name[1]);
413    else		tmp= uStringDup(name);
414    if (tmp==NULL)
415	return False;
416    stuff->foundry= tmp;
417
418    if ((tmp= index(tmp,'-'))==NULL)			goto BAILOUT;
419    else 						*tmp++= '\0';
420    stuff->face= tmp;
421
422    if ((tmp= index(tmp,'-'))==NULL)			goto BAILOUT;
423    else 						*tmp++= '\0';
424    stuff->weight= tmp;
425
426    if ((tmp= index(tmp,'-'))==NULL)			goto BAILOUT;
427    else						*tmp++= '\0';
428    stuff->slant= tmp;
429
430    if ((tmp= index(tmp,'-'))==NULL)			goto BAILOUT;
431    else						*tmp++= '\0';
432    stuff->setWidth= tmp;
433
434    if ((tmp= index(tmp,'-'))==NULL)			goto BAILOUT;
435    else						*tmp++= '\0';
436    stuff->variant= tmp;
437
438    if ((tmp= index(tmp,'-'))==NULL)			goto BAILOUT;
439    else						*tmp++= '\0';
440    if (*tmp=='*')					stuff->pixelSize= 0;
441    else if (sscanf(tmp,"%i",&stuff->pixelSize)!=1)	goto BAILOUT;
442
443    if ((tmp= index(tmp,'-'))==NULL)			goto BAILOUT;
444    else 						*tmp++= '\0';
445    if (*tmp=='*')					stuff->ptSize= 0;
446    else if (sscanf(tmp,"%i",&stuff->ptSize)!=1)	goto BAILOUT;
447
448    if ((tmp= index(tmp,'-'))==NULL)			goto BAILOUT;
449    else						*tmp++= '\0';
450    if (*tmp=='*')					stuff->resX= 0;
451    else if (sscanf(tmp,"%i",&stuff->resX)!=1)		goto BAILOUT;
452
453    if ((tmp= index(tmp,'-'))==NULL)			goto BAILOUT;
454    else 						*tmp++= '\0';
455    if (*tmp=='*')					stuff->resY= 0;
456    else if (sscanf(tmp,"%i",&stuff->resY)!=1)		goto BAILOUT;
457
458    if ((tmp= index(tmp,'-'))==NULL)			goto BAILOUT;
459    else						*tmp++= '\0';
460    stuff->spacing= tmp;
461
462    if ((tmp= index(tmp,'-'))==NULL)			goto BAILOUT;
463    else						*tmp++= '\0';
464    if (*tmp=='*')					stuff->avgWidth= 0;
465    else if (sscanf(tmp,"%i",&stuff->avgWidth)!=1)	goto BAILOUT;
466
467    if ((tmp= index(tmp,'-'))==NULL)			goto BAILOUT;
468    else						 *tmp++= '\0';
469    stuff->encoding= tmp;
470    return True;
471BAILOUT:
472    ClearFontStuff(stuff);
473    return False;
474}
475
476static void
477PSSetUpForLatin1(FILE *out, PSState *state)
478{
479    fprintf(out,"save\n");
480    fprintf(out,"/ISOLatin1Encoding where {pop save true}{false} ifelse\n");
481    fprintf(out,"/ISOLatin1Encoding [\n");
482    fprintf(out,"   /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
483    fprintf(out,"   /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
484    fprintf(out,"   /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
485    fprintf(out,"   /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
486    fprintf(out,"   /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
487    fprintf(out,"   /.notdef /.notdef /space /exclam /quotedbl /numbersign\n");
488    fprintf(out,"   /dollar /percent /ampersand /quoteright /parenleft\n");
489    fprintf(out,"   /parenright /asterisk /plus /comma /minus /period\n");
490    fprintf(out,"   /slash /zero /one /two /three /four /five /six /seven\n");
491    fprintf(out,"   /eight /nine /colon /semicolon /less /equal /greater\n");
492    fprintf(out,"   /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M\n");
493    fprintf(out,"   /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft\n");
494    fprintf(out,"   /backslash /bracketright /asciicircum /underscore\n");
495    fprintf(out,"   /quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m\n");
496    fprintf(out,"   /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft\n");
497    fprintf(out,"   /bar /braceright /asciitilde /guilsinglright /fraction\n");
498    fprintf(out,"   /florin /quotesingle /quotedblleft /guilsinglleft /fi\n");
499    fprintf(out,"   /fl /endash /dagger /daggerdbl /bullet /quotesinglbase\n");
500    fprintf(out,"   /quotedblbase /quotedblright /ellipsis /trademark\n");
501    fprintf(out,"   /perthousand /grave /scaron /circumflex /Scaron /tilde\n");
502    fprintf(out,"   /breve /zcaron /dotaccent /dotlessi /Zcaron /ring\n");
503    fprintf(out,"   /hungarumlaut /ogonek /caron /emdash /space /exclamdown\n");
504    fprintf(out,"   /cent /sterling /currency /yen /brokenbar /section\n");
505    fprintf(out,"   /dieresis /copyright /ordfeminine /guillemotleft\n");
506    fprintf(out,"   /logicalnot /hyphen /registered /macron /degree\n");
507    fprintf(out,"   /plusminus /twosuperior /threesuperior /acute /mu\n");
508    fprintf(out,"   /paragraph /periodcentered /cedilla /onesuperior\n");
509    fprintf(out,"   /ordmasculine /guillemotright /onequarter /onehalf\n");
510    fprintf(out,"   /threequarters /questiondown /Agrave /Aacute\n");
511    fprintf(out,"   /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n");
512    fprintf(out,"   /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute\n");
513    fprintf(out,"   /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute\n");
514    fprintf(out,"   /Ocircumflex /Otilde /Odieresis /multiply /Oslash\n");
515    fprintf(out,"   /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn\n");
516    fprintf(out,"   /germandbls /agrave /aacute /acircumflex /atilde\n");
517    fprintf(out,"   /adieresis /aring /ae /ccedilla /egrave /eacute\n");
518    fprintf(out,"   /ecircumflex /edieresis /igrave /iacute /icircumflex\n");
519    fprintf(out,"   /idieresis /eth /ntilde /ograve /oacute /ocircumflex\n");
520    fprintf(out,"   /otilde /odieresis /divide /oslash /ugrave /uacute\n");
521    fprintf(out,"   /ucircumflex /udieresis /yacute /thorn /ydieresis\n");
522    fprintf(out,"] def {restore} if\n");
523    fprintf(out,"/reencodeISO-1 {\n");
524    fprintf(out,"    dup length dict begin\n");
525    fprintf(out,"        {1 index /FID ne {def}{pop pop} ifelse} forall\n");
526    fprintf(out,"        /Encoding ISOLatin1Encoding def\n");
527    fprintf(out,"        currentdict\n");
528    fprintf(out,"    end\n");
529    fprintf(out,"} def\n");
530}
531
532static void
533PSReencodeLatin1Font(FILE *out, char *font)
534{
535    fprintf(out,"/%s findfont reencodeISO-1\n",font);
536    fprintf(out,"	/%s-8859-1 exch definefont pop\n",font);
537    return;
538}
539
540static void
541PSSetUpFonts(FILE *out, char *textFont, int size)
542{
543    fprintf(out,"/F%d { /%s findfont exch scalefont setfont } def\n",
544						FONT_TEXT,textFont);
545    fprintf(out,"/F%d { /%s-8859-1 findfont exch scalefont setfont } def\n",
546						FONT_LATIN1,textFont);
547    fprintf(out,"/F%d { /%s findfont exch scalefont setfont } def\n",
548						FONT_SYMBOL,"Symbol");
549    fprintf(out,"/F%d { /%s findfont exch scalefont setfont } def\n",
550						FONT_ISOCAPS,"IsoKeyCaps");
551    return;
552}
553
554static void
555PSSetFont(FILE *out, PSState *state, int font, int size, int pts)
556{
557    if ((state->font!=font)||(state->fontSize!=size)) {
558	fprintf(out,"%d %sF%d\n",size,(pts?"pts ":""),font);
559	state->font= font;
560	state->fontSize= size;
561    }
562    return;
563}
564
565
566static void
567PSProlog(FILE *out, PSState *state)
568{
569register int	i;
570
571    if (!state->args->wantEPS) {
572	fprintf(out,"%%!PS-Adobe-2.0\n");
573	fprintf(out,"%%%%Creator: xkbprint\n");
574	if (state->geom->name!=None)
575	    fprintf(out,"%%%%Title: %s\n",
576				XkbAtomGetString(state->dpy,state->geom->name));
577	fprintf(out,"%%%%BoundingBox: (atend)\n");
578	fprintf(out,"%%%%Pages: 1\n");
579	fprintf(out,"%%%%PageOrder: Ascend\n");
580	fprintf(out,"%%%%DocumentFonts: (atend)\n");
581	fprintf(out,"%%%%DocumentData: Clean7Bit\n");
582	fprintf(out,"%%%%Orientation: Landscape\n");
583	fprintf(out,"%%%%EndComments\n");
584	fprintf(out,"%%%%BeginProlog\n");
585	fprintf(out,"%% Resolution is 1/10mm -- need pt sizes for fonts\n");
586	fprintf(out,"clippath pathbbox\n");
587	fprintf(out,"    /ury exch def /urx exch def\n");
588	fprintf(out,"    /llx exch def /lly exch def\n");
589	fprintf(out,"    newpath\n");
590	fprintf(out,"/devwidth  urx llx sub def\n");
591	fprintf(out,"/devheight ury lly sub def\n");
592    }
593    else {
594	int w,h;
595	int pw,ph;
596
597	w= (((state->geom->width_mm*72)/254)*11)/10;
598	h= (((state->geom->height_mm*72)/254)*11)/10;
599	if (state->kbPerPage>1)
600	    h*= (state->kbPerPage+1);
601
602	if (w<=h) {
603	    pw= 7.5*72;
604	    ph= 10*72;
605	}
606	else {
607	    pw= 10*72;
608	    ph= 7.5*72;
609	}
610	while ((w>pw)||(h>ph)) {
611	   w= (w*9)/10;
612	   h= (h*9)/10;
613	}
614
615	fprintf(out,"%%!PS-Adobe-2.0 EPSF-2.0\n");
616	fprintf(out,"%%%%BoundingBox: 0 0 %d %d\n",w,h);
617	fprintf(out,"%%%%Creator: xkbprint\n");
618	if (state->geom->name!=None)
619	    fprintf(out,"%%%%Title: %s\n",
620				XkbAtomGetString(state->dpy,state->geom->name));
621	fprintf(out,"%%%%Pages: 1\n");
622	fprintf(out,"%%%%EndComments\n");
623	fprintf(out,"%%%%BeginProlog\n");
624	fprintf(out,"/ury 0 def /urx 0 def\n");
625	fprintf(out,"/llx %d def /lly %d def\n",w,h);
626	fprintf(out,"/devwidth %d def /devheight %d def\n",w,h);
627    }
628    fprintf(out,"/kbdwidth %d def\n",state->geom->width_mm);
629    fprintf(out,"/kbdheight %d def\n",state->geom->height_mm);
630    fprintf(out,"/pts { 254 mul 72 div } def\n");
631    fprintf(out,"/mm10 { 72 mul 254 div } def\n");
632    fprintf(out,"/landscape? {\n");
633    fprintf(out,"	devheight devwidth gt {\n");
634    fprintf(out,"		/pwidth devheight def /pheight devwidth def\n");
635    fprintf(out,"		0 devheight translate\n");
636    fprintf(out,"		-90 rotate\n");
637    fprintf(out,"	} {\n");
638    fprintf(out,"		/pwidth devwidth def /pheight devheight def\n");
639    fprintf(out,"	} ifelse\n");
640    fprintf(out,"	0 pheight translate\n");
641    fprintf(out,"	1 -1 scale\n");
642    fprintf(out,"} def\n");
643    fprintf(out,"/centeroffset {\n");
644    fprintf(out,"    /S     exch def\n");
645    fprintf(out,"    /HEIGHT exch def\n");
646    fprintf(out,"    /WIDTH exch def\n");
647    fprintf(out,"    S stringwidth /SH exch def /SW exch def\n");
648    fprintf(out,"    WIDTH SW sub 2 div\n");
649    fprintf(out,"    HEIGHT SH sub 2 div\n");
650    fprintf(out,"} def\n");
651    PSSetUpForLatin1(out,state);
652    PSReencodeLatin1Font(out,DFLT_LABEL_FONT);
653    if (state->args->wantColor) {
654	XkbGeometryPtr geom= state->geom;
655	for (i=0;i<geom->num_colors;i++) {
656	    PSColorDef(out,state,&geom->colors[i]);
657	}
658	if (state->black<0) {
659	    XkbColorPtr	color;
660	    if (!(color= XkbAddGeomColor(geom,"black",geom->num_colors)))
661		uFatalError("Couldn't allocate black color!\n");
662	    PSColorDef(out,state,color);
663	}
664	if (state->white<0) {
665	    XkbColorPtr	color;
666	    if (!(color= XkbAddGeomColor(geom,"white",geom->num_colors)))
667		uFatalError("Couldn't allocate white color!\n");
668	    PSColorDef(out,state,color);
669	}
670    }
671    for (i=0;i<state->geom->num_shapes;i++) {
672	PSShapeDef(out,state,&state->geom->shapes[i]);
673    }
674    if (state->args->label==LABEL_SYMBOLS) {
675	PSIncludeFont(out,"IsoKeyCaps");
676    }
677    PSSetUpFonts(out,DFLT_LABEL_FONT, DFLT_LABEL_FONT_SIZE);
678    fprintf(out,"%%%%EndProlog\n");
679    return;
680}
681
682static void
683PSFileTrailer(FILE *out, PSState *state)
684{
685    fprintf(out,"restore\n");
686    if (!state->args->wantEPS)
687	fprintf(out,"%%%%Trailer\n");
688    fprintf(out,"%%%%EOF\n");
689#ifdef NOTYET
690    fprintf(out,"%%%%BoundingBox %d %d\n");
691    fprintf(out,"%%%%DocumentFonts: \n");
692#endif
693    return;
694}
695
696static void
697PSPageSetup(FILE *out, PSState *state, Bool drawBorder)
698{
699XkbGeometryPtr	geom;
700
701    geom= state->geom;
702    if (state->kbPerPage==1) {
703	fprintf(out,"%%%%Page: %d %d\n",state->nPages+1,state->nPages+1);
704	fprintf(out,"%%%%BeginPageSetup\n");
705    }
706    else if ((state->nPages&1)==0) { /* even page */
707	int realPage;
708	realPage= state->nPages/2+1;
709	fprintf(out,"%%%%Page: %d %d\n",realPage,realPage);
710	fprintf(out,"%%%%BeginPageSetup\n");
711	fprintf(out,"%% Keyboard %d\n",state->nPages+1);
712	if (state->nPages==0) {
713	    fprintf(out,"/realwidth devwidth def\n");
714	    fprintf(out,"/realheight devheight def\n");
715	    fprintf(out,"/devheight realheight 3 div def\n");
716	}
717	fprintf(out,"0 devheight dup 2 div add translate\n");
718    }
719    else  {
720	fprintf(out,"%% Keyboard %d\n",state->nPages+1);
721    }
722    fprintf(out,"save\n");
723    fprintf(out,"landscape?\n");
724    if (state->args->scaleToFit) {
725	fprintf(out,"%% Scale keyboard to fit on the page\n");
726	fprintf(out,"/kbdscale pwidth 72 sub kbdwidth div def\n");
727	fprintf(out,"/kbdscalewidth kbdwidth kbdscale mul def\n");
728	fprintf(out,"/kbdscaleheight kbdheight kbdscale mul def\n");
729	fprintf(out,"/kbx 36 def\n");
730	fprintf(out,"/kby pheight kbdscaleheight sub 2 div def\n");
731	PSGSave(out,state);
732	fprintf(out,"kbx kby translate\n");
733	fprintf(out,"kbdscale kbdscale scale\n");
734    }
735    else {
736	fprintf(out,"%% Draw keyboard full size\n");
737	fprintf(out,"/kbdscale 1 def\n");
738	fprintf(out,"/kbdscalewidth kbdwidth mm10 def\n");
739	fprintf(out,"/kbdscaleheight kbdheight mm10 def\n");
740	fprintf(out,"/kbx pwidth kbdscalewidth sub 2 div def\n");
741	fprintf(out,"/kby pheight kbdscaleheight sub 2 div def\n");
742	PSGSave(out,state);
743	fprintf(out,"kbx kby translate\n");
744	fprintf(out,"72 254 div dup scale\n");
745    }
746    if (drawBorder) {
747	if (state->args->wantColor) {
748	    PSSetColor(out,state,geom->base_color->pixel);
749	    fprintf(out,"  0   0 moveto\n");
750	    fprintf(out,"%3d   0 lineto\n",geom->width_mm);
751	    fprintf(out,"%3d %3d lineto\n",geom->width_mm,geom->height_mm);
752	    fprintf(out,"  0 %3d lineto\n",geom->height_mm);
753	    fprintf(out,"closepath fill\n");
754	}
755	PSSetColor(out,state,state->black);
756	fprintf(out,"  0   0 moveto\n");
757	fprintf(out,"%3d   0 lineto\n",geom->width_mm);
758    	fprintf(out,"%3d %3d lineto\n",geom->width_mm,geom->height_mm);
759	fprintf(out,"  0 %3d lineto\n",geom->height_mm);
760	fprintf(out,"closepath stroke\n");
761    }
762    fprintf(out,"%%%%EndPageSetup\n");
763    return;
764}
765
766static void
767PSPageTrailer(FILE *out, PSState *state)
768{
769char *		name;
770XkbDescPtr	xkb;
771XkbGeometryPtr	geom;
772XkbPropertyPtr	prop;
773int		p,baseline;
774
775    xkb= state->xkb;
776    geom= state->geom;
777    if (state->args->grid>0) {
778	fprintf(out,"%% Draw a %dmm grid\n",state->args->grid);
779	fprintf(out,"0 setlinewidth\n");
780	fprintf(out,"0.25 setgray\n");
781	fprintf(out," 0 %d %d {\n",state->args->grid*10,geom->width_mm);
782	fprintf(out,"    /GX exch def\n");
783	fprintf(out,"    GX 0 moveto GX %d lineto stroke\n",geom->height_mm);
784	fprintf(out,"} for\n");
785	fprintf(out," 0 %d %d {\n",state->args->grid*10,geom->height_mm);
786	fprintf(out,"    /GY exch def\n");
787	fprintf(out,"    0 GY moveto %d GY lineto stroke\n",geom->width_mm);
788	fprintf(out,"} for\n");
789    }
790    PSGRestore(out,state);
791    name= NULL;
792    for (p=0,prop=geom->properties;p<geom->num_properties;p++,prop++) {
793	if ((prop->value!=NULL)&&(uStrCaseEqual(prop->name,"description"))) {
794	    name= prop->value;
795	    break;
796	}
797    }
798    if ((!state->args->wantEPS)&&
799			((state->kbPerPage==1)||((state->nPages&1)==1)||
800					(state->nPages==state->totalKB))) {
801	if ((name==NULL)&&(geom->name!=None))
802	    name= XkbAtomGetString(state->dpy,geom->name);
803
804	baseline= 16;
805	if ((name!=NULL)||(state->args->label==LABEL_SYMBOLS)) {
806	    PSSetColor(out,state,state->black);
807	    PSSetFont(out,state,FONT_LATIN1,14,False);
808	}
809	if (state->args->label==LABEL_SYMBOLS) {
810	    char buf[40],*sName= NULL, *lbuf;
811	    Atom sAtom;
812
813	    if (state->args->nLabelGroups==1)
814		sprintf(buf,"Group %d",state->args->baseLabelGroup+1);
815	    else sprintf(buf,"Groups %d-%d",state->args->baseLabelGroup+1,
816		state->args->baseLabelGroup+state->args->nLabelGroups);
817	    fprintf(out,"kbx kbdscalewidth 0 (%s) centeroffset pop add\n",buf);
818	    fprintf(out,"    kby kbdscaleheight add %d add\n",baseline);
819	    fprintf(out,"    moveto\n");
820	    fprintf(out,"1 -1 scale (%s) show 1 -1 scale\n",buf);
821	    baseline+= 16;
822
823	    if (xkb->names!=NULL)	sAtom= xkb->names->symbols;
824	    else			sAtom= None;
825	    if (sAtom!=None)
826		sName= XkbAtomGetString(state->dpy,sAtom);
827	    if (sName==NULL)
828		sName= "(unknown)";
829
830	    lbuf = uAlloc(10+strlen(sName));
831	    if (!lbuf) {
832	    	uFatalError("Can't allocate memory for string\n");
833	    }
834	    sprintf(lbuf,"Layout: %s",sName);
835	    fprintf(out,"kbx kbdscalewidth 0 (%s) centeroffset pop add\n",lbuf);
836	    fprintf(out,"    kby kbdscaleheight add %d add\n",baseline);
837	    fprintf(out,"    moveto\n");
838	    fprintf(out,"1 -1 scale (%s) show 1 -1 scale\n",lbuf);
839	    baseline+= 16;
840	    free(lbuf);
841	}
842	if (name!=NULL) {
843	    fprintf(out,"kbx kbdscalewidth 0 (%s) centeroffset pop add\n",name);
844	    fprintf(out,"    kby kbdscaleheight add %d add\n",baseline);
845	    fprintf(out,"    moveto\n");
846	    fprintf(out,"1 -1 scale (%s) show 1 -1 scale\n",name);
847	    baseline+= 16;
848	}
849	if (state->args->label==LABEL_KEYCODE) {
850	    char *sName= NULL, *lbuf;
851	    Atom sAtom;
852
853	    if (xkb->names!=NULL)	sAtom= xkb->names->keycodes;
854	    else			sAtom= None;
855	    if (sAtom!=None)
856		sName= XkbAtomGetString(state->dpy,sAtom);
857	    if (sName==NULL)
858		sName= "(unknown)";
859
860	    lbuf = uAlloc(12+strlen(sName));
861	    if (!lbuf) {
862	    	uFatalError("Can't allocate memory for string\n");
863	    }
864	    sprintf(lbuf,"Keycodes: %s",sName);
865	    fprintf(out,"kbx kbdscalewidth 0 (%s) centeroffset pop add\n",lbuf);
866	    fprintf(out,"    kby kbdscaleheight add %d add\n",baseline);
867	    fprintf(out,"    moveto\n");
868	    fprintf(out,"1 -1 scale (%s) show 1 -1 scale\n",lbuf);
869	    baseline+= 16;
870	    free(lbuf);
871	}
872	if (state->args->copies>1) {
873	    for (p=1;p<state->args->copies;p++)
874		fprintf(out,"copypage\n");
875	}
876	fprintf(out,"showpage\n");
877	fprintf(out,"restore\n");
878	fprintf(out,"%% Done with keyboard/page %d\n",state->nPages+1);
879    }
880    else {
881	if ((!state->args->wantEPS)&&(state->args->label==LABEL_SYMBOLS)) {
882	    char buf[40];
883	    baseline= 16;
884	    PSSetColor(out,state,state->black);
885	    PSSetFont(out,state,FONT_LATIN1,14,False);
886	    if (state->args->nLabelGroups==1)
887		sprintf(buf,"Group %d",state->args->baseLabelGroup+1);
888	    else sprintf(buf,"Groups %d-%d",state->args->baseLabelGroup+1,
889		state->args->baseLabelGroup+state->args->nLabelGroups+1);
890	    fprintf(out,"kbx kbdscalewidth 0 (%s) centeroffset pop add\n",buf);
891	    fprintf(out,"    kby kbdscaleheight add %d add\n",baseline);
892	    fprintf(out,"    moveto\n");
893	    fprintf(out,"1 -1 scale (%s) show 1 -1 scale\n",buf);
894	    baseline+= 16;
895	}
896	fprintf(out,"restore\n");
897	fprintf(out,"%% Done with keyboard %d\n",state->nPages+1);
898	fprintf(out,"0 devheight -1 mul translate %% next keyboard\n");
899    }
900    state->nPages++;
901    state->color= state->black;
902    state->font= -1;
903    return;
904}
905
906static void
907PSDoodad(FILE *out, PSState *state, XkbDoodadPtr doodad)
908{
909XkbDescPtr	xkb;
910char		*name,*dname;
911int		sz,leading;
912
913    xkb= state->xkb;
914    if (doodad->any.name!=None)
915	 dname= XkbAtomGetString(xkb->dpy,doodad->any.name);
916    else dname= "NoName";
917    switch (doodad->any.type) {
918	case XkbOutlineDoodad:
919	case XkbSolidDoodad:
920	    name= XkbAtomGetString(xkb->dpy,
921			XkbShapeDoodadShape(xkb->geom,&doodad->shape)->name);
922	    if (state->args->wantColor) {
923		PSSetColor(out,state,doodad->shape.color_ndx);
924		if (doodad->any.type!=XkbOutlineDoodad) {
925		    fprintf(out,"true %d %d %d %s %% Doodad %s\n",
926					doodad->shape.angle,
927					doodad->shape.left,doodad->shape.top,
928					name,dname);
929		    PSSetColor(out,state,state->black);
930		}
931		fprintf(out,"false %d %d %d %s %% Doodad %s\n",
932			doodad->shape.angle,
933			doodad->shape.left,doodad->shape.top,
934			name,dname);
935	    }
936	    else {
937		fprintf(out,"false %d %d %d %s %% Doodad %s\n",
938			doodad->shape.angle,
939			doodad->shape.left,doodad->shape.top,
940			name,dname);
941	    }
942	    break;
943	case XkbTextDoodad:
944	    fprintf(out,"%% Doodad %s\n",dname);
945	    PSSetColor(out,state,doodad->text.color_ndx);
946	    PSGSave(out,state);
947	    fprintf(out,"%d %d translate\n",doodad->text.left,doodad->text.top);
948	    if (doodad->text.angle!=0)
949		fprintf(out,"%s rotate\n",
950				XkbGeomFPText(doodad->text.angle,XkbMessage));
951	    sz= 14;
952	    if (doodad->text.font) {
953		FontStuff stuff;
954		if (CrackXLFDName(doodad->text.font,&stuff)) {
955		    if (stuff.ptSize>0)
956			sz= stuff.ptSize/10;
957		    ClearFontStuff(&stuff);
958		}
959	    }
960	    PSSetFont(out,state,FONT_LATIN1,sz,True);
961	    leading= (sz*12)/10;
962	    if (strchr(doodad->text.text,'\n')==NULL) {
963		fprintf(out,"0 %d pts moveto 1 -1 scale\n",(leading*8)/10);
964		fprintf(out,"(%s) show\n",doodad->text.text);
965	    }
966	    else {
967		char *tmp,*buf,*end;
968		int   offset= (leading*8/10);
969		tmp= buf= uStringDup(doodad->text.text);
970		while (tmp!=NULL) {
971		    end= strchr(tmp,'\n');
972		    if (end!=NULL)
973			*end++= '\0';
974		    fprintf(out,"0 %d pts moveto 1 -1 scale\n",offset);
975		    fprintf(out,"(%s) show 1 -1 scale\n",tmp);
976		    offset+= leading;
977		    tmp= end;
978		}
979		free(buf);
980	    }
981	    PSGRestore(out,state);
982	    break;
983	case XkbIndicatorDoodad:
984	    name= XkbAtomGetString(xkb->dpy,
985		XkbIndicatorDoodadShape(xkb->geom,&doodad->indicator)->name);
986	    if (state->args->wantColor) {
987		PSSetColor(out,state,doodad->indicator.off_color_ndx);
988		fprintf(out,"true 0 %d %d %s %% Doodad %s\n",
989			doodad->indicator.left,doodad->indicator.top,
990			name,dname);
991		PSSetColor(out,state,state->black);
992	    }
993	    fprintf(out,"false 0 %d %d %s %% Doodad %s\n",
994			doodad->indicator.left,doodad->indicator.top,
995			name,dname);
996	    break;
997	case XkbLogoDoodad:
998	    name= XkbAtomGetString(xkb->dpy,
999			XkbLogoDoodadShape(xkb->geom,&doodad->logo)->name);
1000	    if (state->args->wantColor)
1001		PSSetColor(out,state,doodad->shape.color_ndx);
1002	    fprintf(out,"false %d %d %d %s %% Doodad %s\n",
1003			doodad->shape.angle,
1004			doodad->shape.left,doodad->shape.top,
1005			name,dname);
1006	    break;
1007    }
1008    return;
1009}
1010
1011/***====================================================================***/
1012
1013static Bool
1014PSKeycapsSymbol(KeySym sym, unsigned char *buf,
1015		int *font_rtrn, int *sz_rtrn, PSState *state)
1016{
1017    if (state->args->wantSymbols==NO_SYMBOLS)
1018	return False;
1019
1020    if (font_rtrn!=NULL)
1021	*font_rtrn= FONT_ISOCAPS;
1022    if (sz_rtrn!=NULL)
1023	*sz_rtrn= SZ_LARGE;
1024    buf[1]= '\0';
1025    switch (sym) {
1026	case XK_Shift_L: case XK_Shift_R:
1027		buf[0]= XKC_ISO_Shift;		return True;
1028	case XK_Shift_Lock:
1029		buf[0]= XKC_ISO_Shift_Lock;	return True;
1030	case XK_ISO_Lock:
1031		buf[0]= XKC_ISO_Caps_Lock;	return True;
1032	case XK_BackSpace:
1033		buf[0]= XKC_ISO_Backspace;	return True;
1034	case XK_Return:
1035		buf[0]= XKC_ISO_Return;		return True;
1036	case XK_Up: case XK_KP_Up:
1037		buf[0]= XKC_ISO_Up;		return True;
1038	case XK_Down: case XK_KP_Down:
1039		buf[0]= XKC_ISO_Down;		return True;
1040	case XK_Left: case XK_KP_Left:
1041		buf[0]= XKC_ISO_Left;		return True;
1042	case XK_Right: case XK_KP_Right:
1043		buf[0]= XKC_ISO_Right;		return True;
1044	case XK_Tab:
1045		buf[0]= XKC_ISO_Tab;		return True;
1046	case XK_ISO_Left_Tab:
1047		buf[0]= XKC_ISO_Left_Tab;	return True;
1048    }
1049    if (state->args->wantSymbols!=ALL_SYMBOLS)
1050	return False;
1051    switch (sym) {
1052	case XK_Caps_Lock:
1053		buf[0]= XKC_ISO_Caps_Lock;	return True;
1054	case XK_Num_Lock:
1055		buf[0]= XKC_ISO_Num_Lock;	return True;
1056	case XK_ISO_Level3_Shift:
1057		buf[0]= XKC_ISO_Level3_Shift;	return True;
1058	case XK_ISO_Level3_Lock:
1059		buf[0]= XKC_ISO_Level3_Lock;	return True;
1060	case XK_ISO_Next_Group: case XK_ISO_Group_Shift:
1061		buf[0]= XKC_ISO_Next_Group;	return True;
1062	case XK_ISO_Next_Group_Lock:
1063		buf[0]= XKC_ISO_Next_Group_Lock;return True;
1064	case XK_space:
1065		buf[0]= XKC_ISO_Space;		return True;
1066	case XK_nobreakspace:
1067		buf[0]= XKC_ISO_No_Break_Space;	return True;
1068	case XK_Insert:
1069		buf[0]= XKC_ISO_Insert;		return True;
1070	case XK_ISO_Continuous_Underline:
1071		buf[0]= XKC_ISO_Continuous_Underline;return True;
1072	case XK_ISO_Discontinuous_Underline:
1073		buf[0]= XKC_ISO_Discontinuous_Underline;return True;
1074	case XK_ISO_Emphasize:
1075		buf[0]= XKC_ISO_Emphasize;	return True;
1076	case XK_Multi_key:
1077		buf[0]= XKC_ISO_Compose;	return True;
1078	case XK_ISO_Center_Object:
1079		buf[0]= XKC_ISO_Center_Object;	return True;
1080	case XK_Delete:
1081		buf[0]= XKC_ISO_Delete;		return True;
1082	case XK_Clear:
1083		buf[0]= XKC_ISO_Clear_Screen;	return True;
1084	case XK_Scroll_Lock:
1085		buf[0]= XKC_ISO_Scroll_Lock;	return True;
1086	case XK_Help:
1087		buf[0]= XKC_ISO_Help;		return True;
1088	case XK_Print:
1089		buf[0]= XKC_ISO_Print_Screen;	return True;
1090	case XK_ISO_Enter:
1091		buf[0]= XKC_ISO_Enter;		return True;
1092	case XK_Alt_L: case XK_Alt_R:
1093		buf[0]= XKC_ISO_Alt;		return True;
1094	case XK_Control_L: case XK_Control_R:
1095		buf[0]= XKC_ISO_Control;	return True;
1096	case XK_Pause:
1097		buf[0]= XKC_ISO_Pause;		return True;
1098	case XK_Break:
1099		buf[0]= XKC_ISO_Break;		return True;
1100	case XK_Escape:
1101		buf[0]= XKC_ISO_Escape;		return True;
1102	case XK_Undo:
1103		buf[0]= XKC_ISO_Undo;		return True;
1104	case XK_ISO_Fast_Cursor_Up:
1105		buf[0]= XKC_ISO_Fast_Cursor_Up;	return True;
1106	case XK_ISO_Fast_Cursor_Down:
1107		buf[0]= XKC_ISO_Fast_Cursor_Down;return True;
1108	case XK_ISO_Fast_Cursor_Left:
1109		buf[0]= XKC_ISO_Fast_Cursor_Left;return True;
1110	case XK_ISO_Fast_Cursor_Right:
1111		buf[0]= XKC_ISO_Fast_Cursor_Right;return True;
1112	case XK_Home:
1113		buf[0]= XKC_ISO_Home;		return True;
1114	case XK_End:
1115		buf[0]= XKC_ISO_End;		return True;
1116	case XK_Page_Up:
1117		buf[0]= XKC_ISO_Page_Up;	return True;
1118	case XK_Page_Down:
1119		buf[0]= XKC_ISO_Page_Down;	return True;
1120	case XK_ISO_Move_Line_Up:
1121		buf[0]= XKC_ISO_Move_Line_Up;	return True;
1122	case XK_ISO_Move_Line_Down:
1123		buf[0]= XKC_ISO_Move_Line_Down;	return True;
1124	case XK_ISO_Partial_Line_Up:
1125		buf[0]= XKC_ISO_Partial_Line_Up;return True;
1126	case XK_ISO_Partial_Line_Down:
1127		buf[0]= XKC_ISO_Partial_Line_Down;return True;
1128	case XK_ISO_Partial_Space_Left:
1129		buf[0]= XKC_ISO_Partial_Space_Left;return True;
1130	case XK_ISO_Partial_Space_Right:
1131		buf[0]= XKC_ISO_Partial_Space_Right;return True;
1132	case XK_ISO_Set_Margin_Left:
1133		buf[0]= XKC_ISO_Set_Margin_Left;return True;
1134	case XK_ISO_Set_Margin_Right:
1135		buf[0]= XKC_ISO_Set_Margin_Right;return True;
1136	case XK_ISO_Release_Margin_Left:
1137		buf[0]= XKC_ISO_Release_Margin_Left;return True;
1138	case XK_ISO_Release_Margin_Right:
1139		buf[0]= XKC_ISO_Release_Margin_Right;return True;
1140	case XK_ISO_Release_Both_Margins:
1141		buf[0]= XKC_ISO_Release_Both_Margins;return True;
1142	case XK_ISO_Prev_Group:
1143		buf[0]= XKC_ISO_Prev_Group;	return True;
1144	case XK_ISO_Prev_Group_Lock:
1145		buf[0]= XKC_ISO_Prev_Group_Lock;	return True;
1146    }
1147#ifdef NOTYET
1148    if (font_rtrn!=NULL)
1149	font_rtrn= FONT_MOUSECAPS;
1150    switch (sym) {
1151	case XK_Pointer_Up:
1152		buf[0]= XKC_Mouse_Pointer_Up;	return True;
1153	case XK_Pointer_Down:
1154		buf[0]= XKC_Mouse_Pointer_Down;	return True;
1155	case XK_Pointer_Left:
1156		buf[0]= XKC_Mouse_Pointer_Left;	return True;
1157	case XK_Pointer_Right:
1158		buf[0]= XKC_Mouse_Pointer_Right;return True;
1159	case XK_Pointer_Button1:
1160		buf[0]= XKC_Mouse_Pointer_Button1;return True;
1161	case XK_Pointer_Button2:
1162		buf[0]= XKC_Mouse_Pointer_Button2;return True;
1163	case XK_Pointer_Button3:
1164		buf[0]= XKC_Mouse_Pointer_Button3;return True;
1165	case XK_Pointer_Button4:
1166		buf[0]= XKC_Mouse_Pointer_Button4;return True;
1167    }
1168#endif
1169    return False;
1170}
1171
1172static Bool
1173PSNonLatin1Symbol(KeySym sym, unsigned char *buf,
1174		  int *font_rtrn, int *sz_rtrn, PSState *state)
1175{
1176    if (state->args->wantSymbols==NO_SYMBOLS)
1177	return False;
1178
1179    if (font_rtrn!=NULL)
1180	*font_rtrn= FONT_TEXT;
1181    if (sz_rtrn!=NULL)
1182	*sz_rtrn= SZ_LARGE;
1183    buf[1]= '\0';
1184    switch (sym) {
1185	case XK_breve:		buf[0]= 0xC6;	return True;
1186	case XK_abovedot:	buf[0]= 0xC7;	return True;
1187	case XK_doubleacute:	buf[0]= 0xCD;	return True;
1188	case XK_ogonek:		buf[0]= 0xCE;	return True;
1189	case XK_caron:		buf[0]= 0xCF;	return True;
1190	case XK_Lstroke:	buf[0]= 0xE8;	return True;
1191	case XK_idotless:	buf[0]= 0xF5;	return True;
1192	case XK_lstroke:	buf[0]= 0xF8;	return True;
1193    }
1194    if (font_rtrn!=NULL)
1195	*font_rtrn= FONT_SYMBOL;
1196    if (sz_rtrn!=NULL)
1197	*sz_rtrn= SZ_MEDIUM;
1198    if ((sym&(~0xff))==0x700) {
1199	switch (sym) {
1200	    /* Greek symbol */
1201	    case XK_Greek_ALPHA:	buf[0]= 0x41;	return True;
1202	    case XK_Greek_BETA:		buf[0]= 0x42;	return True;
1203	    case XK_Greek_CHI:		buf[0]= 0x43;	return True;
1204	    case XK_Greek_DELTA:	buf[0]= 0x44;	return True;
1205	    case XK_Greek_EPSILON:	buf[0]= 0x45;	return True;
1206	    case XK_Greek_PHI:		buf[0]= 0x46;	return True;
1207	    case XK_Greek_GAMMA:	buf[0]= 0x47;	return True;
1208	    case XK_Greek_ETA:		buf[0]= 0x48;	return True;
1209	    case XK_Greek_IOTA:		buf[0]= 0x49;	return True;
1210	    case XK_Greek_KAPPA:	buf[0]= 0x4B;	return True;
1211	    case XK_Greek_LAMDA:	buf[0]= 0x4C;	return True;
1212	    case XK_Greek_MU:		buf[0]= 0x4D;	return True;
1213	    case XK_Greek_NU:		buf[0]= 0x4E;	return True;
1214	    case XK_Greek_OMICRON:	buf[0]= 0x4F;	return True;
1215	    case XK_Greek_PI:		buf[0]= 0x50;	return True;
1216	    case XK_Greek_THETA:	buf[0]= 0x51;	return True;
1217	    case XK_Greek_RHO:		buf[0]= 0x52;	return True;
1218	    case XK_Greek_SIGMA:	buf[0]= 0x53;	return True;
1219	    case XK_Greek_TAU:		buf[0]= 0x54;	return True;
1220	    case XK_Greek_UPSILON:	buf[0]= 0x55;	return True;
1221	    case XK_Greek_OMEGA:	buf[0]= 0x57;	return True;
1222	    case XK_Greek_XI:		buf[0]= 0x58;	return True;
1223	    case XK_Greek_PSI:		buf[0]= 0x59;	return True;
1224	    case XK_Greek_ZETA:		buf[0]= 0x5A;	return True;
1225
1226	    case XK_Greek_alpha:	buf[0]= 0x61;	return True;
1227	    case XK_Greek_beta:		buf[0]= 0x62;	return True;
1228	    case XK_Greek_chi:		buf[0]= 0x63;	return True;
1229	    case XK_Greek_delta:	buf[0]= 0x64;	return True;
1230	    case XK_Greek_epsilon:	buf[0]= 0x65;	return True;
1231	    case XK_Greek_phi:		buf[0]= 0x66;	return True;
1232	    case XK_Greek_gamma:	buf[0]= 0x67;	return True;
1233	    case XK_Greek_eta:		buf[0]= 0x68;	return True;
1234	    case XK_Greek_iota:		buf[0]= 0x69;	return True;
1235	    case XK_Greek_kappa:	buf[0]= 0x6B;	return True;
1236	    case XK_Greek_lamda:	buf[0]= 0x6C;	return True;
1237	    case XK_Greek_mu:		buf[0]= 0x6D;	return True;
1238	    case XK_Greek_nu:		buf[0]= 0x6E;	return True;
1239	    case XK_Greek_omicron:	buf[0]= 0x6F;	return True;
1240	    case XK_Greek_pi:		buf[0]= 0x70;	return True;
1241	    case XK_Greek_theta:	buf[0]= 0x71;	return True;
1242	    case XK_Greek_rho:		buf[0]= 0x72;	return True;
1243	    case XK_Greek_sigma:	buf[0]= 0x73;	return True;
1244	    case XK_Greek_tau:		buf[0]= 0x74;	return True;
1245	    case XK_Greek_upsilon:	buf[0]= 0x75;	return True;
1246	    case XK_Greek_omega:	buf[0]= 0x77;	return True;
1247	    case XK_Greek_xi:		buf[0]= 0x78;	return True;
1248	    case XK_Greek_psi:		buf[0]= 0x79;	return True;
1249	    case XK_Greek_zeta:		buf[0]= 0x7A;	return True;
1250	}
1251    }
1252    switch (sym) {
1253	case XK_leftarrow:	buf[0]= 0xAC;	return True;
1254	case XK_uparrow:	buf[0]= 0xAD;	return True;
1255	case XK_rightarrow:	buf[0]= 0xAE;	return True;
1256	case XK_downarrow:	buf[0]= 0xAF;	return True;
1257	case XK_horizconnector:	buf[0]= 0xBE;	return True;
1258	case XK_trademark:	buf[0]= 0xE4;	return True;
1259    }
1260    return False;
1261}
1262
1263static KeySym
1264CheckSymbolAlias(KeySym sym, PSState *state)
1265{
1266    if (XkbKSIsKeypad(sym)) {
1267	if ((sym>=XK_KP_0)&&(sym<=XK_KP_9))
1268	     sym= (sym-XK_KP_0)+XK_0;
1269	else switch (sym) {
1270		case XK_KP_Space:	return XK_space;
1271		case XK_KP_Tab:		return XK_Tab;
1272		case XK_KP_Enter:	return XK_Return;
1273		case XK_KP_F1:		return XK_F1;
1274		case XK_KP_F2:		return XK_F2;
1275		case XK_KP_F3:		return XK_F3;
1276		case XK_KP_F4:		return XK_F4;
1277		case XK_KP_Home:	return XK_Home;
1278		case XK_KP_Left:	return XK_Left;
1279		case XK_KP_Up:		return XK_Up;
1280		case XK_KP_Right:	return XK_Right;
1281		case XK_KP_Down:	return XK_Down;
1282		case XK_KP_Page_Up:	return XK_Page_Up;
1283		case XK_KP_Page_Down:	return XK_Page_Down;
1284		case XK_KP_End:		return XK_End;
1285		case XK_KP_Begin:	return XK_Begin;
1286		case XK_KP_Insert:	return XK_Insert;
1287		case XK_KP_Delete:	return XK_Delete;
1288		case XK_KP_Equal:	return XK_equal;
1289		case XK_KP_Multiply:	return XK_asterisk;
1290		case XK_KP_Add:		return XK_plus;
1291		case XK_KP_Subtract:	return XK_minus;
1292		case XK_KP_Divide:	return XK_slash;
1293	}
1294    }
1295    else if (XkbKSIsDeadKey(sym)) {
1296	switch (sym) {
1297		     case XK_dead_grave:	sym= XK_grave; break;
1298		     case XK_dead_acute:	sym= XK_acute; break;
1299		     case XK_dead_circumflex:	sym= XK_asciicircum; break;
1300		     case XK_dead_tilde:	sym= XK_asciitilde; break;
1301		     case XK_dead_macron:	sym= XK_macron; break;
1302		     case XK_dead_breve:	sym= XK_breve; break;
1303		     case XK_dead_abovedot:	sym= XK_abovedot; break;
1304		     case XK_dead_diaeresis:	sym= XK_diaeresis; break;
1305		     case XK_dead_abovering:	sym= XK_degree; break;
1306		     case XK_dead_doubleacute:	sym= XK_doubleacute; break;
1307		     case XK_dead_caron:	sym= XK_caron; break;
1308		     case XK_dead_cedilla:	sym= XK_cedilla; break;
1309		     case XK_dead_ogonek:	sym= XK_ogonek; break;
1310		     case XK_dead_iota:		sym= XK_Greek_iota; break;
1311		     case XK_dead_voiced_sound:
1312				sym= XK_voicedsound;
1313				break;
1314		     case XK_dead_semivoiced_sound:
1315				sym= XK_semivoicedsound;
1316				break;
1317	}
1318    }
1319    return sym;
1320}
1321
1322static Bool
1323FindKeysymsByName(XkbDescPtr xkb, char *name, PSState *state, KeyTop *top)
1324{
1325static unsigned char buf[30];
1326int	kc;
1327KeySym	sym,*syms,topSyms[NLABELS];
1328int	level,group;
1329int	eG,nG,gI,l,g;
1330
1331    bzero(top,sizeof(KeyTop));
1332    kc= XkbFindKeycodeByName(xkb,name,True);
1333    if (state->args!=NULL) {
1334	level= state->args->labelLevel;
1335	group= state->args->baseLabelGroup;
1336    }
1337    else level= group= 0;
1338    syms= XkbKeySymsPtr(xkb,kc);
1339    eG= group;
1340    nG= XkbKeyNumGroups(xkb,kc);
1341    gI= XkbKeyGroupInfo(xkb,kc);
1342    if ((state->args->wantDiffs)&&(eG>=XkbKeyNumGroups(xkb,kc)))
1343	return False;		/* XXX was a return with no value */
1344    if (nG==0) {
1345	return False;
1346    }
1347    else if (nG==1) {
1348	eG= 0;
1349    }
1350    else if (eG>=XkbKeyNumGroups(xkb,kc)) {
1351	switch (XkbOutOfRangeGroupAction(gI)) {
1352	    default:
1353		eG%= nG;
1354		break;
1355	    case XkbClampIntoRange:
1356		eG= nG-1;
1357	        break;
1358	    case XkbRedirectIntoRange:
1359		eG= XkbOutOfRangeGroupNumber(gI);
1360		if (eG>=nG)
1361		    eG= 0;
1362		break;
1363	}
1364    }
1365    for (g=0;g<state->args->nLabelGroups;g++) {
1366	if ((eG+g)>=nG)
1367	    continue;
1368	for (l=0;l<2;l++) {
1369	    int font,sz;
1370	    if (level+l>=XkbKeyGroupWidth(xkb,kc,(eG+g)))
1371		continue;
1372	    sym= syms[((eG+g)*XkbKeyGroupsWidth(xkb,kc))+(level+l)];
1373
1374	    if (state->args->wantSymbols!=NO_SYMBOLS)
1375		sym= CheckSymbolAlias(sym,state);
1376	    topSyms[(g*2)+l]= sym;
1377
1378	    if (PSKeycapsSymbol(sym,buf,&font,&sz,state)) {
1379		top->font[(g*2)+l]= font;
1380		top->size[(g*2)+l]= sz;
1381	    }
1382	    else if (((sym&(~0xff))==0)&&isprint(sym)&&(!isspace(sym))) {
1383		if (sym=='(')		sprintf((char *)buf,"\\(");
1384		else if (sym==')')	sprintf((char *)buf,"\\)");
1385		else if (sym=='\\')	sprintf((char *)buf,"\\\\");
1386		else			sprintf((char *)buf,"%c",(char)sym);
1387		top->font[(g*2)+l]= FONT_LATIN1;
1388		top->size[(g*2)+l]= SZ_MEDIUM;
1389		switch (buf[0]) {
1390		    case '.': case ':': case ',': case ';':
1391		    case '\'': case '"': case '`': case '~':
1392		    case '^': case 0250: case 0270: case 0267:
1393		    case 0260: case 0252: case 0272: case 0271:
1394		    case 0262: case 0263: case 0264: case 0255:
1395		    case 0254: case 0257:
1396			top->size[(g*2)+l]= SZ_LARGE;
1397			break;
1398		}
1399	    }
1400	    else if (PSNonLatin1Symbol(sym,buf,&font,&sz,state)) {
1401		top->font[(g*2)+l]= font;
1402		top->size[(g*2)+l]= sz;
1403	    }
1404	    else {
1405		char 		*tmp;
1406		tmp= XKeysymToString(sym);
1407		if (tmp!=NULL)	strcpy((char *)buf,tmp);
1408		else		sprintf((char *)buf,"(%ld)",sym);
1409		top->font[(g*2)+l]= FONT_LATIN1;
1410		if (strlen((char *)buf)<9)
1411		     top->size[(g*2)+l]= SZ_SMALL;
1412		else top->size[(g*2)+l]= SZ_TINY;
1413	    }
1414	    top->present|= (1<<((g*2)+l));
1415	    strncpy(top->label[(g*2)+l],(char *)buf,LABEL_LEN-1);
1416	    top->label[(g*2)+l][LABEL_LEN-1]= '\0';
1417	}
1418	if (((g==0)&&(top->present&G1LX_MASK)==G1LX_MASK)||
1419	    ((g==1)&&(top->present&G2LX_MASK)==G2LX_MASK)) {
1420	    KeySym	lower,upper;
1421	    XConvertCase(topSyms[(g*2)],&lower,&upper);
1422	    if ((topSyms[(g*2)]==lower)&&(topSyms[(g*2)+1]==upper)) {
1423		top->alpha[g]= True;
1424	    }
1425	}
1426    }
1427    return True;
1428}
1429
1430static void
1431PSDrawLabel(FILE *out, char *label, int x, int y, int w, int h)
1432{
1433    fprintf(out,"%d %d (%s) centeroffset\n",w,h,label);
1434    fprintf(out,"%d add exch\n",y);
1435    fprintf(out,"%d add exch moveto\n",x);
1436    fprintf(out,"1 -1 scale (%s) show 1 -1 scale\n",label);
1437    return;
1438}
1439
1440#define	TOP_ROW		0
1441#define	BOTTOM_ROW	1
1442#define	CENTER_ROW	2
1443
1444#define	LEFT_COL	0
1445#define	RIGHT_COL	1
1446#define	CENTER_COL	2
1447
1448static void
1449PSLabelKey(FILE *out, PSState *state, KeyTop *top, int x, int y,
1450	   XkbBoundsPtr bounds, int kc, int btm)
1451{
1452char	keycode[10];
1453int	w,h,i;
1454int	row_y[3];
1455int	col_x[3];
1456int	row_h[3];
1457int	col_w[3];
1458Bool	present[NLABELS];
1459int	sym_row[NLABELS];
1460int	sym_col[NLABELS];
1461
1462    w= XkbBoundsWidth(bounds);
1463    h= XkbBoundsHeight(bounds);
1464    row_y[TOP_ROW]=	y+bounds->y1+(h/10);
1465    row_y[BOTTOM_ROW]=	y+bounds->y1+(h/2)+(h/10);
1466    row_y[CENTER_ROW]=	y+bounds->y1+(h/10);
1467    row_h[TOP_ROW]=	h/2;
1468    row_h[BOTTOM_ROW]=	h/2;
1469    row_h[CENTER_ROW]=	h;
1470
1471    col_x[LEFT_COL]= 	x+bounds->x1;
1472    col_x[RIGHT_COL]= 	x+bounds->x1+w/2;
1473    col_x[CENTER_COL]= 	x+bounds->x1;
1474    col_w[LEFT_COL]= 	w/2;
1475    col_w[RIGHT_COL]= 	w/2;
1476    col_w[CENTER_COL]= 	w;
1477
1478    present[G1L1]= False;
1479    sym_row[G1L1]= BOTTOM_ROW;
1480    sym_col[G1L1]= LEFT_COL;
1481
1482    present[G1L2]= False;
1483    sym_row[G1L2]= TOP_ROW;
1484    sym_col[G1L2]= LEFT_COL;
1485
1486    present[G2L1]= False;
1487    sym_row[G2L1]= BOTTOM_ROW;
1488    sym_col[G2L1]= RIGHT_COL;
1489
1490    present[G2L2]= False;
1491    sym_row[G2L2]= TOP_ROW;
1492    sym_col[G2L2]= RIGHT_COL;
1493
1494    present[CENTER]= False;
1495    sym_row[CENTER]= CENTER_ROW;
1496    sym_col[CENTER]= CENTER_COL;
1497
1498    if (top->present&CENTER_MASK) {
1499	present[CENTER]= True;
1500    }
1501    else switch (top->present&GXLX_MASK) {
1502	case G1L1_MASK:
1503	    present[G1L1]= True;
1504	    sym_row[G1L1]= CENTER_ROW;
1505	    sym_col[G1L1]= CENTER_COL;
1506	    break;
1507	case G1LX_MASK:
1508	    present[G1L2]= True;
1509	    if (!top->alpha[0]) {
1510		present[G1L1]= True;
1511		if ((strlen(top->label[G1L1])>1)&&(top->label[G1L1][0]!='\\'))
1512		    sym_col[G1L1]= CENTER_COL;
1513		if ((strlen(top->label[G1L2])>1)&&(top->label[G1L1][0]!='\\'))
1514		    sym_col[G1L2]= CENTER_COL;
1515	    }
1516	    break;
1517	default:
1518	    if ((top->present&G1LX_MASK)==G1LX_MASK) {
1519		present[G1L2]= True;
1520		if (!top->alpha[0])
1521		    present[G1L1]= True;
1522	    }
1523	    else if ((top->present&G1LX_MASK)==G1L1_MASK) {
1524		present[G1L1]= True;
1525	    }
1526	    else if ((top->present&G1LX_MASK)==G1L2_MASK) {
1527		present[G1L2]= True;
1528	    }
1529	    if ((top->present&G2LX_MASK)==G2LX_MASK) {
1530		present[G2L2]= True;
1531		if (!top->alpha[1])
1532		    present[G2L1]= True;
1533	    }
1534	    else if ((top->present&G2LX_MASK)==G2L1_MASK) {
1535		present[G2L1]= True;
1536	    }
1537	    else if ((top->present&G2LX_MASK)==G2L2_MASK) {
1538		present[G2L2]= True;
1539	    }
1540	    break;
1541	case 0:
1542	    return;
1543    }
1544    for (i=0;i<NLABELS;i++) {
1545	if (present[i]) {
1546	    int len,size;
1547	    if (top->size[i]==SZ_AUTO) {
1548		len= strlen(top->label[i]);
1549		if (len==1) {
1550		    if (top->font[i]==FONT_ISOCAPS)
1551			 size= 18;
1552		    else size= 14;
1553		}
1554		else if (len<10)	size= 12;
1555		else		size= 10;
1556	    }
1557	    else if (top->size[i]==SZ_TINY)
1558		 size= 10;
1559	    else if (top->size[i]==SZ_SMALL)
1560		 size= 12;
1561	    else if (top->size[i]==SZ_LARGE)
1562		 size= 18;
1563	    else if (top->size[i]==SZ_XLARGE)
1564		 size= 24;
1565	    else size= 14;
1566	    PSSetFont(out,state,top->font[i],size,True);
1567	    PSDrawLabel(out,top->label[i],col_x[sym_col[i]],row_y[sym_row[i]],
1568					  col_w[sym_col[i]],row_h[sym_row[i]]);
1569	}
1570    }
1571    if (state->args->wantKeycodes) {
1572	sprintf(keycode,"%d",kc);
1573	PSSetFont(out,state,FONT_LATIN1,8,True);
1574	PSDrawLabel(out,keycode,x+bounds->x1,y+btm-5,w,0);
1575    }
1576    return;
1577}
1578
1579static void
1580PSSection(FILE *out, PSState *state, XkbSectionPtr section)
1581{
1582int		r,offset;
1583XkbRowPtr	row;
1584Display *	dpy;
1585XkbDescPtr	xkb;
1586
1587    xkb= state->xkb;
1588    dpy= xkb->dpy;
1589    fprintf(out,"%% Begin Section '%s'\n",(section->name!=None?
1590					XkbAtomGetString(dpy,section->name):
1591					"NoName"));
1592    PSGSave(out,state);
1593    fprintf(out,"%d %d translate\n",section->left,section->top);
1594    if (section->angle!=0)
1595	fprintf(out,"%s rotate\n",XkbGeomFPText(section->angle,XkbMessage));
1596    if (section->doodads) {
1597	XkbDrawablePtr	first,draw;
1598	first= draw= XkbGetOrderedDrawables(NULL,section);
1599	while (draw) {
1600	    if (draw->type==XkbDW_Section)
1601		 PSSection(out,state,draw->u.section);
1602	    else PSDoodad(out,state,draw->u.doodad);
1603	    draw= draw->next;
1604	}
1605	XkbFreeOrderedDrawables(first);
1606    }
1607    for (r=0,row=section->rows;r<section->num_rows;r++,row++) {
1608	int 		k;
1609	XkbKeyPtr	key;
1610	XkbShapePtr	shape;
1611	if (row->vertical)	offset= row->top;
1612	else			offset= row->left;
1613	fprintf(out,"%% Begin %s %d\n",row->vertical?"column":"row",r+1);
1614	for (k=0,key=row->keys;k<row->num_keys;k++,key++) {
1615	    shape= XkbKeyShape(xkb->geom,key);
1616	    offset+= key->gap;
1617	    if (row->vertical) {
1618		if (state->args->wantColor) {
1619		    if (key->color_ndx!=state->white) {
1620			PSSetColor(out,state,key->color_ndx);
1621			fprintf(out,"true 0 %d %d %s %% %s\n",
1622				row->left,offset,
1623	     			XkbAtomGetString(dpy,shape->name),
1624				XkbKeyNameText(key->name.name,XkbMessage));
1625		    }
1626		    PSSetColor(out,state,state->black);
1627		}
1628		fprintf(out,"false 0 %d %d %s %% %s\n",row->left,offset,
1629	     			XkbAtomGetString(dpy,shape->name),
1630				XkbKeyNameText(key->name.name,XkbMessage));
1631		offset+= shape->bounds.y2;
1632	    }
1633	    else {
1634		if (state->args->wantColor) {
1635		    if (key->color_ndx!=state->white) {
1636			PSSetColor(out,state,key->color_ndx);
1637			fprintf(out,"true 0 %d %d %s %% %s\n",offset,row->top,
1638	     			XkbAtomGetString(dpy,shape->name),
1639				XkbKeyNameText(key->name.name,XkbMessage));
1640		    }
1641		    PSSetColor(out,state,state->black);
1642		}
1643		fprintf(out,"false 0 %d %d %s %% %s\n",offset,row->top,
1644	     			XkbAtomGetString(dpy,shape->name),
1645				XkbKeyNameText(key->name.name,XkbMessage));
1646		offset+= shape->bounds.x2;
1647	    }
1648	}
1649    }
1650    for (r=0,row=section->rows;r<section->num_rows;r++,row++) {
1651	int 		k,kc=0;
1652	XkbKeyPtr	key;
1653	XkbShapePtr	shape;
1654	XkbBoundsRec	bounds;
1655	if (state->args->label==LABEL_NONE)
1656	    break;
1657	if (row->vertical)	offset= row->top;
1658	else			offset= row->left;
1659	fprintf(out,"%% Begin %s %d labels\n",row->vertical?"column":"row",r+1);
1660	PSSetColor(out,state,xkb->geom->label_color->pixel);
1661	PSSetFont(out,state,FONT_LATIN1,12,True);
1662	for (k=0,key=row->keys;k<row->num_keys;k++,key++) {
1663	    char *	name,*name2,buf[30],buf2[30];
1664	    int		x,y;
1665	    KeyTop	top;
1666
1667	    shape= XkbKeyShape(xkb->geom,key);
1668	    XkbComputeShapeTop(shape,&bounds);
1669	    offset+= key->gap;
1670	    name= name2= NULL;
1671	    if (state->args->label==LABEL_SYMBOLS) {
1672		if (!FindKeysymsByName(xkb,key->name.name,state,&top)) {
1673		    fprintf(out,"%% No label for %s\n",
1674				XkbKeyNameText(key->name.name,XkbMessage));
1675		}
1676	    }
1677	    else {
1678		char *olKey;
1679
1680		if (section->num_overlays>0)
1681		     olKey= XkbFindOverlayForKey(xkb->geom,section,
1682							   key->name.name);
1683		else olKey= NULL;
1684
1685		if (state->args->label==LABEL_KEYNAME) {
1686		    name= XkbKeyNameText(key->name.name,XkbMessage);
1687		    if (olKey)
1688			name2= XkbKeyNameText(olKey,XkbMessage);
1689		}
1690		else if (state->args->label==LABEL_KEYCODE) {
1691		    name= buf;
1692		    sprintf(name,"%d",XkbFindKeycodeByName(xkb,key->name.name,
1693									True));
1694		    if (olKey) {
1695			name2= buf2;
1696			sprintf(name,"%d",XkbFindKeycodeByName(xkb,olKey,True));
1697		    }
1698		}
1699		bzero(&top,sizeof(KeyTop));
1700		if (name2!=NULL) {
1701		    top.present|= G1LX_MASK;
1702		    strncpy(top.label[G1L1],name,LABEL_LEN-1);
1703		    top.label[G1L1][LABEL_LEN-1]= '\0';
1704		    strncpy(top.label[G1L2],name2,LABEL_LEN-1);
1705		    top.label[G1L2][LABEL_LEN-1]= '\0';
1706		}
1707		else if (name!=NULL) {
1708		    top.present|= CENTER_MASK;
1709		    strncpy(top.label[CENTER],name,LABEL_LEN-1);
1710		    top.label[CENTER][LABEL_LEN-1]= '\0';
1711		}
1712		else {
1713		    fprintf(out,"%% No label for %s\n",
1714				XkbKeyNameText(key->name.name,XkbMessage));
1715		}
1716	    }
1717	    if (row->vertical) {
1718		x= row->left;
1719		y= offset;
1720		offset+= shape->bounds.y2;
1721	    }
1722	    else {
1723		x= offset;
1724		y= row->top;
1725		offset+= shape->bounds.x2;
1726	    }
1727	    name= key->name.name;
1728	    fprintf(out,"%% %s\n",XkbKeyNameText(name,XkbMessage));
1729	    if (state->args->wantKeycodes)
1730		kc= XkbFindKeycodeByName(xkb,key->name.name,True);
1731	    PSLabelKey(out,state,&top,x,y,&bounds,kc,shape->bounds.y2);
1732	}
1733    }
1734    PSGRestore(out,state);
1735    return;
1736}
1737
1738Bool
1739GeometryToPostScript(FILE *out, XkbFileInfo *pResult, XKBPrintArgs *args)
1740{
1741XkbDrawablePtr	first,draw;
1742PSState		state;
1743Bool		dfltBorder;
1744int		i;
1745
1746    if ((!pResult)||(!pResult->xkb)||(!pResult->xkb->geom))
1747	return False;
1748    state.xkb=   pResult->xkb;
1749    state.dpy=   pResult->xkb->dpy;
1750    state.geom=  pResult->xkb->geom;
1751    state.color= state.black= state.white= -1;
1752    state.font=  -1;
1753    state.nPages= 0;
1754    state.totalKB= 1;
1755    state.kbPerPage= 1;
1756    state.x1= state.y1= state.x2= state.y2= 0;
1757    state.args= args;
1758
1759    if ((args->label==LABEL_SYMBOLS)&&(pResult->xkb->ctrls)) {
1760	if (args->nTotalGroups==0)
1761	     state.totalKB= pResult->xkb->ctrls->num_groups/args->nLabelGroups;
1762	else state.totalKB= args->nTotalGroups;
1763	if (state.totalKB<1)
1764	    state.totalKB= 1;
1765	else if (state.totalKB>1)
1766	    state.kbPerPage= 2;
1767    }
1768    if (args->nKBPerPage!=0)
1769	state.kbPerPage= args->nKBPerPage;
1770
1771    PSProlog(out,&state);
1772    first= XkbGetOrderedDrawables(state.geom,NULL);
1773
1774    for (draw=first,dfltBorder=True;draw!=NULL;draw=draw->next) {
1775	if ((draw->type!=XkbDW_Section)&&
1776	    ((draw->u.doodad->any.type==XkbOutlineDoodad)||
1777	     (draw->u.doodad->any.type==XkbSolidDoodad))) {
1778	    char *name;
1779	    name= XkbAtomGetString(state.dpy,draw->u.doodad->any.name);
1780	    if ((name!=NULL)&&(uStrCaseEqual(name,"edges"))) {
1781		dfltBorder= False;
1782		break;
1783	    }
1784	}
1785    }
1786    for (i=0;i<state.totalKB;i++) {
1787	PSPageSetup(out,&state,dfltBorder);
1788	for (draw=first;draw!=NULL;draw=draw->next) {
1789	    if (draw->type==XkbDW_Section)
1790		PSSection(out,&state,draw->u.section);
1791	    else {
1792		PSDoodad(out,&state,draw->u.doodad);
1793	    }
1794	}
1795	PSPageTrailer(out,&state);
1796	state.args->baseLabelGroup+= state.args->nLabelGroups;
1797    }
1798    XkbFreeOrderedDrawables(first);
1799    PSFileTrailer(out,&state);
1800    return True;
1801}
1802