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