1/* 2 3Copyright (c) 1985-1989 X Consortium 4 5Permission is hereby granted, free of charge, to any person obtaining 6a copy of this software and associated documentation files (the 7"Software"), to deal in the Software without restriction, including 8without limitation the rights to use, copy, modify, merge, publish, 9distribute, sublicense, and/or sell copies of the Software, and to 10permit persons to whom the Software is furnished to do so, subject to 11the following conditions: 12 13The above copyright notice and this permission notice shall be included 14in all copies or substantial portions of the Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR 20OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22OTHER DEALINGS IN THE SOFTWARE. 23 24Except as contained in this notice, the name of the X Consortium shall 25not be used in advertising or otherwise to promote the sale, use or 26other dealings in this Software without prior written authorization 27from the X Consortium. 28 29Author: Ralph R. Swick, DEC/MIT Project Athena 30 one weekend in November, 1989 31Modified: Mark Leisher <mleisher@crl.nmsu.edu> to deal with UCS sample text. 32*/ 33 34/* 35 * Copyright (c) 2000, 2022, Oracle and/or its affiliates. 36 * 37 * Permission is hereby granted, free of charge, to any person obtaining a 38 * copy of this software and associated documentation files (the "Software"), 39 * to deal in the Software without restriction, including without limitation 40 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 41 * and/or sell copies of the Software, and to permit persons to whom the 42 * Software is furnished to do so, subject to the following conditions: 43 * 44 * The above copyright notice and this permission notice (including the next 45 * paragraph) shall be included in all copies or substantial portions of the 46 * Software. 47 * 48 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 49 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 50 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 51 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 52 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 53 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 54 * DEALINGS IN THE SOFTWARE. 55 * 56 * Modifications by Jay Hobson (Sun Microsystems) to internationalize messages 57 */ 58 59#ifdef HAVE_CONFIG_H 60# include "config.h" 61#endif 62 63#include <stdio.h> 64#include <stdlib.h> 65#include <X11/Intrinsic.h> 66#include <X11/StringDefs.h> 67#include <X11/Xatom.h> 68#include <X11/Xaw/AsciiText.h> 69#include <X11/Xaw/Box.h> 70#include <X11/Xaw/Cardinals.h> 71#include <X11/Xaw/Command.h> 72#include <X11/Xaw/Form.h> 73#include <X11/Xaw/MenuButton.h> 74#include <X11/Xaw/Paned.h> 75#include <X11/Xaw/SimpleMenu.h> 76#include <X11/Xaw/SmeBSB.h> 77#include <X11/Xaw/Toggle.h> 78#include <X11/Xaw/Viewport.h> 79#include <X11/Xmu/Atoms.h> 80#include <X11/Xmu/StdSel.h> 81#include <X11/Xfuncs.h> 82#include <X11/Xlib.h> 83#include "ULabel.h" 84 85#ifdef USE_GETTEXT 86# include <locale.h> /* setlocale() */ 87# include <libintl.h> /* gettext(), textdomain(), etc. */ 88#else 89# define gettext(a) (a) 90#endif 91 92#define MIN_APP_DEFAULTS_VERSION 1 93#define FIELD_COUNT 14 94#define DELIM '-' 95 96/* number of font names to parse in each background iteration */ 97#ifndef PARSE_QUANTUM 98#define PARSE_QUANTUM 25 99#endif 100 101#define NZ NULL,ZERO 102#define BACKGROUND 10 103 104void GetFontNames(XtPointer closure); 105Boolean Matches(String pattern, String fontName, Boolean fields[], int *maxfields); 106Boolean DoWorkPiece(XtPointer closure); 107void Quit(Widget w, XtPointer closure, XtPointer callData) _X_NORETURN; 108void Reset(Widget w, XtPointer closure, XtPointer callData); 109void OwnSelection(Widget w, XtPointer closure, XtPointer callData); 110void SelectField(Widget w, XtPointer closure, XtPointer callData); 111void ParseFontNames(XtPointer closure); 112void SortFields(XtPointer closure); 113void FixScalables(XtPointer closure); 114void MakeFieldMenu(XtPointer closure); 115void SelectValue(Widget w, XtPointer closure, XtPointer callData); 116void AnyValue(Widget w, XtPointer closure, XtPointer callData); 117void EnableOtherValues(Widget w, XtPointer closure, XtPointer callData); 118void EnableMenu(XtPointer closure); 119void SetCurrentFont(XtPointer closure); 120void QuitAction(Widget w, XEvent *event, String *params, Cardinal *num_params) 121 _X_NORETURN; 122 123static XtActionsRec xfontsel_actions[] = { 124 {"Quit", QuitAction} 125}; 126 127static Atom wm_delete_window; 128 129Boolean IsXLFDFontName(String fontName); 130 131typedef void (*XtProc)(XtPointer closure); 132 133static struct _appRes { 134 int app_defaults_version; 135 Cursor cursor; 136 String pattern; 137 char *pixelSizeList; 138 char *pointSizeList; 139 Boolean print_on_quit; 140 String sample_text; 141 String sample_text16; 142 String sample_textUCS; 143 Boolean scaled_fonts; 144} AppRes; 145 146#define DEFAULTPATTERN "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" 147 148static XtResource resources[] = { 149 { "cursor", "Cursor", XtRCursor, sizeof(Cursor), 150 XtOffsetOf( struct _appRes, cursor ), 151 XtRImmediate, NULL }, 152 { "pattern", "Pattern", XtRString, sizeof(String), 153 XtOffsetOf( struct _appRes, pattern ), 154 XtRString, (XtPointer)DEFAULTPATTERN }, 155 { "pixelSizeList", "PixelSizeList", XtRString, sizeof(String), 156 XtOffsetOf( struct _appRes, pixelSizeList ), 157 XtRString, (XtPointer)"" }, 158 { "pointSizeList", "PointSizeList", XtRString, sizeof(String), 159 XtOffsetOf( struct _appRes, pointSizeList ), 160 XtRString, (XtPointer)"" }, 161 { "printOnQuit", "PrintOnQuit", XtRBoolean, sizeof(Boolean), 162 XtOffsetOf( struct _appRes, print_on_quit ), 163 XtRImmediate, (XtPointer)False }, 164 { "appDefaultsVersion", "AppDefaultsVersion", XtRInt, sizeof(int), 165 XtOffsetOf( struct _appRes, app_defaults_version ), 166 XtRImmediate, (XtPointer)0 }, 167 { "sampleText", "Text", XtRString, sizeof(String), 168 XtOffsetOf( struct _appRes, sample_text ), 169 XtRString, (XtPointer)"" }, 170 { "sampleText16", "Text16", XtRString, sizeof(String), 171 XtOffsetOf( struct _appRes, sample_text16 ), 172 XtRString, (XtPointer)"" }, 173 { "sampleTextUCS", "TextUCS", XtRString, sizeof(String), 174 XtOffsetOf( struct _appRes, sample_textUCS ), 175 XtRString, (XtPointer)"" }, 176 { "scaledFonts", "ScaledFonts", XtRBoolean, sizeof(Boolean), 177 XtOffsetOf( struct _appRes, scaled_fonts ), 178 XtRImmediate, (XtPointer)False }, 179}; 180 181static XrmOptionDescRec options[] = { 182{"-pattern", "pattern", XrmoptionSepArg, NULL}, 183{"-print", "printOnQuit", XrmoptionNoArg, "True"}, 184{"-sample", "sampleText", XrmoptionSepArg, NULL}, 185{"-sample16", "sampleText16", XrmoptionSepArg, NULL}, 186{"-sampleUCS", "sampleTextUCS",XrmoptionSepArg, NULL}, 187{"-scaled", "scaledFonts", XrmoptionNoArg, "True"}, 188}; 189 190static void Syntax(const char *call, int exitval) 191{ 192 fprintf (stderr, "usage: %s [-options ...] -fn font\n\n%s\n", call, 193 gettext( 194 "where options include:\n" 195 " -display dpy X server to contact\n" 196 " -geometry geom size and location of window\n" 197 " -pattern fontspec font name pattern to match against\n" 198 " -print print selected font name on exit\n" 199 " -sample string sample text to use for 1-byte fonts\n" 200 " -sample16 string sample text to use for 2-byte fonts\n" 201 " -sampleUCS string sample text to use for ISO10646 fonts\n" 202 " -scaled use scaled instances of fonts\n" 203 "plus any standard toolkit options\n")); 204 exit (exitval); 205} 206 207 208typedef struct FieldValue FieldValue; 209struct FieldValue { 210 int field; 211 String string; 212 Widget menu_item; 213 int count; /* of fonts */ 214 int allocated; 215 int *font; 216 Boolean enable; 217}; 218 219 220typedef struct FieldValueList FieldValueList; 221struct FieldValueList { 222 int count; /* of values */ 223 int allocated; 224 Boolean show_unselectable; 225 FieldValue value[1]; /* really [allocated] */ 226}; 227 228 229typedef struct FontValues FontValues; 230struct FontValues { 231 int value_index[FIELD_COUNT]; 232}; 233 234 235typedef struct FieldMenuRec FieldMenuRec; 236struct FieldMenuRec { 237 int field; 238 Widget button; 239}; 240 241 242typedef struct Choice Choice; 243struct Choice { 244 Choice *prev; 245 FieldValue *value; 246}; 247 248 249static XtResource menuResources[] = { 250 { "showUnselectable", "ShowUnselectable", XtRBoolean, sizeof(Boolean), 251 XtOffsetOf( FieldValueList, show_unselectable ), 252 XtRImmediate, (XtPointer)True }, 253}; 254 255 256typedef enum {ValidateCurrentField, SkipCurrentField} ValidateAction; 257 258static void EnableAllItems(int field); 259static void EnableRemainingItems(ValidateAction current_field_action); 260static void FlushXqueue(Display *dpy); 261static void MarkInvalidFonts(Boolean *set, FieldValue *val); 262static void ScheduleWork(XtProc proc, XtPointer closure, int priority); 263static void SetCurrentFontCount(void); 264static void SetNoFonts(void); 265static void SetParsingFontCount(int count); 266static void reset_currentFontNameString(void); 267 268static XtAppContext appCtx; 269static int numFonts; 270static int numBadFonts; 271static FontValues *fonts; 272static int *scaledFonts; 273static int numScaledFonts; 274static FieldValueList *fieldValues[FIELD_COUNT]; 275static FontValues currentFont; 276static int matchingFontCount; 277static Boolean anyDisabled = False; 278static Widget resetButton; 279static Widget ownButton; 280static Widget fieldBox; 281static Widget countLabel; 282static Widget currentFontName; 283static char *currentFontNameString; 284static int currentFontNameSize; 285static Widget sampleText; 286static int textEncoding = -1; 287static XFontStruct *sampleFont = NULL; 288static Boolean *fontInSet; 289static Choice *choiceList = NULL; 290static int enabledMenuIndex; 291static Boolean patternFieldSpecified[FIELD_COUNT]; /* = 0 */ 292 293int 294main(int argc, char **argv) 295{ 296 Widget topLevel, pane; 297 298 XtSetLanguageProc(NULL, (XtLanguageProc) NULL, NULL); 299 300 /* Handle args that don't require opening a display */ 301 for (int n = 1; n < argc; n++) { 302 const char *argn = argv[n]; 303 /* accept single or double dash for -help & -version */ 304 if (argn[0] == '-' && argn[1] == '-') { 305 argn++; 306 } 307 if (strcmp(argn, "-help") == 0) { 308 Syntax(argv[0], 0); 309 } 310 if (strcmp(argn, "-version") == 0) { 311 puts(PACKAGE_STRING); 312 exit(0); 313 } 314 } 315 316 topLevel = XtAppInitialize(&appCtx, "XFontSel", options, XtNumber(options), 317 &argc, argv, NULL, NULL, 0); 318 319#ifdef USE_GETTEXT 320 /* 321 * Set up internationalized messages Jhobson 8/23/00 322 * 323 * Do this after the AppInitialize since setlocale is setup by 324 * XtSetLanguageProc, but does not occur until XtAppInitialize happens. 325 */ 326 textdomain("xfontsel"); 327 328 { 329 const char *domaindir; 330 331 if ((domaindir = getenv("TEXTDOMAINDIR")) == NULL) { 332 domaindir = LOCALEDIR; 333 } 334 bindtextdomain("xfontsel", domaindir); 335 } 336#endif 337 338 if (argc != 1) { 339 fputs(gettext("Unknown argument(s):"), stderr); 340 for (int n = 1; n < argc; n++) { 341 fprintf(stderr, " %s", argv[n]); 342 } 343 fputs("\n\n", stderr); 344 Syntax(argv[0], 1); 345 } 346 347 XtAppAddActions(appCtx, xfontsel_actions, XtNumber(xfontsel_actions)); 348 XtOverrideTranslations 349 (topLevel, XtParseTranslationTable ("<Message>WM_PROTOCOLS: Quit()")); 350 351 XtGetApplicationResources( topLevel, (XtPointer)&AppRes, 352 resources, XtNumber(resources), NZ ); 353 if (AppRes.app_defaults_version < MIN_APP_DEFAULTS_VERSION) { 354 char full_message[300]; 355 XrmDatabase rdb = XtDatabase(XtDisplay(topLevel)); 356 357 XtWarning(gettext("app-defaults file not properly installed.")); 358 359 snprintf(full_message, sizeof(full_message), 360 "*sampleText*UCSLabel:%s", 361 gettext("XFontSel app-defaults file not properly installed;\\n" 362 "see 'xfontsel' manual page.")); 363 XrmPutLineResource(&rdb, full_message); 364 } 365 366 ScheduleWork(GetFontNames, (XtPointer)topLevel, 0); 367 368 pane = XtCreateManagedWidget("pane",panedWidgetClass,topLevel,NZ); 369 { 370 Widget commandBox, /* fieldBox, currentFontName,*/ viewPort; 371 372 commandBox = XtCreateManagedWidget("commandBox",formWidgetClass,pane,NZ); 373 { 374 Widget quitButton /*, resetButton, ownButton , countLabel*/; 375 376 quitButton = 377 XtCreateManagedWidget("quitButton",commandWidgetClass,commandBox,NZ); 378 379 resetButton = 380 XtCreateManagedWidget("resetButton",commandWidgetClass,commandBox,NZ); 381 382 ownButton = 383 XtCreateManagedWidget("ownButton",toggleWidgetClass,commandBox,NZ); 384 385 countLabel = 386 XtCreateManagedWidget("countLabel",labelWidgetClass,commandBox,NZ); 387 388 XtAddCallback(quitButton, XtNcallback, Quit, NULL); 389 XtAddCallback(resetButton, XtNcallback, Reset, NULL); 390 XtAddCallback(ownButton,XtNcallback,OwnSelection,(XtPointer)True); 391 } 392 393 fieldBox = XtCreateManagedWidget("fieldBox", boxWidgetClass, pane, NZ); 394 { 395 Widget /*dash,*/ field /*[FIELD_COUNT]*/; 396 int f; 397 398 for (f = 0; f < FIELD_COUNT; f++) { 399 char name[10]; 400 FieldMenuRec *makeRec = XtNew(FieldMenuRec); 401 snprintf( name, sizeof(name), "field%d", f ); 402 XtCreateManagedWidget("dash",labelWidgetClass,fieldBox,NZ); 403 field = XtCreateManagedWidget(name, menuButtonWidgetClass, 404 fieldBox, NZ); 405 XtAddCallback(field, XtNcallback, SelectField, 406 (XtPointer)(long)f); 407 makeRec->field = f; 408 makeRec->button = field; 409 ScheduleWork(MakeFieldMenu, (XtPointer)makeRec, 2); 410 ScheduleWork((XtProc)XtFree, (XtPointer)makeRec, 2); 411 } 412 } 413 414 /* currentFontName = */ 415 { 416 Arg args[1]; 417 reset_currentFontNameString(); 418 XtSetArg(args[0], XtNlabel, currentFontNameString); 419 currentFontName = 420 XtCreateManagedWidget("fontName",labelWidgetClass,pane,args,ONE); 421 } 422 423 viewPort = 424 XtCreateManagedWidget("viewPort",viewportWidgetClass,pane,NZ); 425 sampleText = 426 XtCreateManagedWidget("sampleText",ucsLabelWidgetClass,viewPort,NZ); 427 } 428 429 XtRealizeWidget(topLevel); 430 XDefineCursor( XtDisplay(topLevel), XtWindow(topLevel), AppRes.cursor ); 431 { 432 int f; 433 for (f = 0; f < FIELD_COUNT; f++) currentFont.value_index[f] = -1; 434 } 435 wm_delete_window = XInternAtom(XtDisplay(topLevel), "WM_DELETE_WINDOW", 436 False); 437 (void) XSetWMProtocols (XtDisplay(topLevel), XtWindow(topLevel), 438 &wm_delete_window, 1); 439 XtAppMainLoop(appCtx); 440 441 exit(0); 442} 443 444 445typedef struct WorkPiece WorkPieceRec, *WorkPiece; 446struct WorkPiece { 447 WorkPiece next; 448 int priority; 449 XtProc proc; 450 XtPointer closure; 451}; 452static WorkPiece workQueue = NULL; 453 454 455/* 456 * ScheduleWork( XtProc proc, XtPointer closure, int priority ) 457 * 458 * Adds a WorkPiece to the workQueue in FIFO order by priority. 459 * Lower numbered priority work is completed before higher numbered 460 * priorities. 461 * 462 * If the workQueue was previously empty, then makes sure that 463 * Xt knows we have (background) work to do. 464 */ 465 466static void ScheduleWork(XtProc proc, XtPointer closure, int priority) 467{ 468 WorkPiece piece = XtNew(WorkPieceRec); 469 470 piece->priority = priority; 471 piece->proc = proc; 472 piece->closure = closure; 473 if (workQueue == NULL) { 474 piece->next = NULL; 475 workQueue = piece; 476 XtAppAddWorkProc(appCtx, DoWorkPiece, NULL); 477 } else { 478 if (workQueue->priority > priority) { 479 piece->next = workQueue; 480 workQueue = piece; 481 } 482 else { 483 WorkPiece n; 484 for (n = workQueue; n->next && n->next->priority <= priority;) 485 n = n->next; 486 piece->next = n->next; 487 n->next = piece; 488 } 489 } 490} 491 492/* ARGSUSED */ 493Boolean DoWorkPiece(XtPointer closure) 494{ 495 WorkPiece piece = workQueue; 496 497 if (piece) { 498 (*piece->proc)(piece->closure); 499 workQueue = piece->next; 500 XtFree((XtPointer)piece); 501 if (workQueue != NULL) 502 return False; 503 } 504 return True; 505} 506 507 508/* 509 * FinishWork() 510 * 511 * Drains foreground tasks from the workQueue. 512 * Foreground == (priority < BACKGROUND) 513 */ 514 515static void FinishWork(void) 516{ 517 while (workQueue && workQueue->priority < BACKGROUND) 518 DoWorkPiece(NULL); 519} 520 521 522typedef struct ParseRec ParseRec; 523struct ParseRec { 524 char **fontNames; 525 int num_fonts; 526 int start, end; 527 FontValues *fonts; 528 FieldValueList **fieldValues; 529}; 530 531 532void GetFontNames(XtPointer closure) 533{ 534 Widget topLevel = (Widget)closure; 535 Display *dpy = XtDisplay(topLevel); 536 ParseRec *parseRec; 537 int count; 538 char **fontNames; 539 int work_priority = 0; 540 541 fontNames = XListFonts(dpy, AppRes.pattern, 32767, &numFonts); 542 543 fonts = (FontValues*)XtMalloc( numFonts*sizeof(FontValues) ); 544 fontInSet = (Boolean*)XtMalloc( numFonts*sizeof(Boolean) ); 545 { 546 int f; 547 Boolean *b; 548 for (f = numFonts, b = fontInSet; f; f--, b++) 549 *b = True; 550 } 551 for (int field = 0; field < FIELD_COUNT; field++) { 552 fieldValues[field] = (FieldValueList*)XtMalloc(sizeof(FieldValueList)); 553 fieldValues[field]->allocated = 1; 554 fieldValues[field]->count = 0; 555 } 556 if (numFonts == 0) { 557 SetNoFonts(); 558 return; 559 } 560 count = matchingFontCount = numFonts; 561 numBadFonts = 0; 562 parseRec = XtNew(ParseRec); 563 *parseRec = (ParseRec) { 564 .fontNames = fontNames, 565 .num_fonts = count, 566 .start = 0, 567 .fonts = fonts, 568 .fieldValues = fieldValues 569 }; 570 /* this is bogus; the task should be responsible for quantizing...*/ 571 while (count > PARSE_QUANTUM) { 572 ParseRec *prevRec = parseRec; 573 parseRec->end = parseRec->start + PARSE_QUANTUM; 574 ScheduleWork(ParseFontNames, (XtPointer)parseRec, work_priority); 575 ScheduleWork((XtProc)XtFree, (XtPointer)parseRec, work_priority); 576 parseRec = XtNew(ParseRec); 577 *parseRec = *prevRec; 578 parseRec->start += PARSE_QUANTUM; 579 parseRec->fonts += PARSE_QUANTUM; 580 parseRec->fontNames += PARSE_QUANTUM; 581 count -= PARSE_QUANTUM; 582 work_priority = 1; 583 } 584 parseRec->end = numFonts; 585 ScheduleWork(ParseFontNames,(XtPointer)parseRec,work_priority); 586 ScheduleWork((XtProc)XFreeFontNames,(XtPointer)fontNames,work_priority); 587 ScheduleWork((XtProc)XtFree, (XtPointer)parseRec, work_priority); 588 if (AppRes.scaled_fonts) 589 ScheduleWork(FixScalables,(XtPointer)topLevel, work_priority); 590 ScheduleWork(SortFields,(XtPointer)0,work_priority); 591 SetParsingFontCount(matchingFontCount); 592 if (strcmp(AppRes.pattern, DEFAULTPATTERN)) { 593 int maxField, f; 594 for (f = 0; f < numFonts && !IsXLFDFontName(fontNames[f]); f++); 595 if (f != numFonts) { 596 if (Matches(AppRes.pattern, fontNames[f], 597 patternFieldSpecified, &maxField)) { 598 for (f = 0; f <= maxField; f++) { 599 if (patternFieldSpecified[f]) 600 currentFont.value_index[f] = 0; 601 } 602 } 603 else 604 XtAppWarning( appCtx, 605 gettext("internal error; pattern didn't match first font" )); 606 } 607 else { 608 SetNoFonts(); 609 return; 610 } 611 } 612 ScheduleWork(SetCurrentFont, NULL, 1); 613} 614 615 616void ParseFontNames(XtPointer closure) 617{ 618 ParseRec *parseRec = (ParseRec*)closure; 619 char **fontNames = parseRec->fontNames; 620 int num_fonts = parseRec->end; 621 FieldValueList **fValues = parseRec->fieldValues; 622 FontValues *fontValues = parseRec->fonts - numBadFonts; 623 int i, font; 624 625 for (font = parseRec->start; font < num_fonts; font++) { 626 char *p; 627 int f, len; 628 FieldValue *v; 629 630 if (!IsXLFDFontName(*fontNames)) { 631 numFonts--; 632 numBadFonts++; 633 continue; 634 } 635 636 for (f = 0, p = *fontNames++; f < FIELD_COUNT; f++) { 637 const char *fieldP; 638 639 if (*p) ++p; 640 if (*p == DELIM || *p == '\0') { 641 fieldP = ""; 642 len = 0; 643 } else { 644 fieldP = p; 645 while (*p && *++p != DELIM); 646 len = p - fieldP; 647 } 648 for (i=fValues[f]->count,v=fValues[f]->value; i;i--,v++) { 649 if (len == 0) { 650 if (v->string == NULL) break; 651 } 652 else 653 if (v->string && 654 strncmp( v->string, fieldP, len ) == 0 && 655 (v->string)[len] == '\0') 656 break; 657 } 658 if (i == 0) { 659 int count = fValues[f]->count++; 660 if (count == fValues[f]->allocated) { 661 int allocated = (fValues[f]->allocated += 10); 662 fValues[f] = (FieldValueList*) 663 XtRealloc( (char *) fValues[f], 664 sizeof(FieldValueList) + 665 (allocated-1) * sizeof(FieldValue) ); 666 } 667 v = &fValues[f]->value[count]; 668 v->field = f; 669 if (len == 0) 670 v->string = NULL; 671 else { 672 char *s = XtMalloc(len + 1); 673 strncpy( s, fieldP, len ); 674 s[len] = '\0'; 675 v->string = (String) s; 676 } 677 v->font = (int*)XtMalloc( 10*sizeof(int) ); 678 v->allocated = 10; 679 v->count = 0; 680 v->enable = True; 681 i = 1; 682 } 683 fontValues->value_index[f] = fValues[f]->count - i; 684 if ((i = v->count++) == v->allocated) { 685 int allocated = (v->allocated += 10); 686 v->font = (int*)XtRealloc( (char *) v->font, 687 allocated * sizeof(int) ); 688 } 689 v->font[i] = font - numBadFonts; 690 } 691 fontValues++; 692 } 693 SetParsingFontCount(numFonts - num_fonts); 694} 695 696 697/* Add the list of scalable fonts to the match-list of every value instance 698 * for field f. Must produce sorted order. Must deal with duplicates 699 * since we need to do this for resolution fields which can be nonzero in 700 * the scalable fonts. 701 */ 702static void AddScalables(int f) 703{ 704 int i; 705 int max = fieldValues[f]->count; 706 FieldValue *fval = fieldValues[f]->value; 707 708 for (i = 0; i < max; i++, fval++) { 709 int *oofonts, *ofonts, *nfonts, *sfonts; 710 int ocount, ncount, count; 711 712 if (fval->string && !strcmp(fval->string, "0")) 713 continue; 714 count = numScaledFonts; 715 sfonts = scaledFonts; 716 ocount = fval->count; 717 ncount = ocount + count; 718 nfonts = (int *)XtMalloc( ncount * sizeof(int) ); 719 oofonts = ofonts = fval->font; 720 fval->font = nfonts; 721 fval->count = ncount; 722 fval->allocated = ncount; 723 while (count && ocount) { 724 if (*sfonts < *ofonts) { 725 *nfonts++ = *sfonts++; 726 count--; 727 } else if (*sfonts == *ofonts) { 728 *nfonts++ = *sfonts++; 729 count--; 730 ofonts++; 731 ocount--; 732 fval->count--; 733 } else { 734 *nfonts++ = *ofonts++; 735 ocount--; 736 } 737 } 738 while (ocount) { 739 *nfonts++ = *ofonts++; 740 ocount--; 741 } 742 while (count) { 743 *nfonts++ = *sfonts++; 744 count--; 745 } 746 XtFree((char *)oofonts); 747 } 748} 749 750 751/* Merge in specific scaled sizes (specified in a comma-separated string) 752 * for field f. Weed out duplicates. The set of matching fonts is just 753 * the set of scalable fonts. 754 */ 755static void NewScalables(int f, char *slist) 756{ 757 char endc = 1; 758 char *str; 759 int i, count; 760 FieldValue *v; 761 762 while (endc) { 763 while (*slist == ' ' || *slist == ',') 764 slist++; 765 if (!*slist) 766 break; 767 str = slist; 768 while ((endc = *slist) && endc != ' ' && endc != ',') 769 slist++; 770 *slist++ = '\0'; 771 for (i=fieldValues[f]->count,v=fieldValues[f]->value; --i >= 0; v++) { 772 if (v->string && !strcmp(v->string, str)) 773 break; 774 } 775 if (i >= 0) 776 continue; 777 count = fieldValues[f]->count++; 778 if (count == fieldValues[f]->allocated) { 779 int allocated = (fieldValues[f]->allocated += 10); 780 fieldValues[f] = (FieldValueList*) 781 XtRealloc( (char *) fieldValues[f], 782 sizeof(FieldValueList) + 783 (allocated-1) * sizeof(FieldValue) ); 784 } 785 v = &fieldValues[f]->value[count]; 786 v->field = f; 787 v->string = str; 788 v->count = numScaledFonts; 789 v->font = scaledFonts; 790 v->allocated = 0; 791 v->enable = True; 792 } 793} 794 795 796/* Find all scalable fonts, defined as the set matching "0" in the pixel 797 * size field (field 6). Augment the match-lists for all other fields 798 * that are scalable. Add in new scalable pixel and point sizes given 799 * in resources, along with the current Screen's actual resX and resY 800 * values. 801 */ 802/*ARGSUSED*/ 803void FixScalables(XtPointer closure) 804{ 805 int i; 806 FieldValue *fval = fieldValues[6]->value; 807 Widget topLevel = (Widget) closure; 808 Display *dpy = XtDisplay(topLevel); 809 int scr = XScreenNumberOfScreen(XtScreenOfObject(topLevel)); 810 double xres, yres; 811 static char xreslist[21]; /* log10(UINT64_MAX) == 19 */ 812 static char yreslist[21]; 813 814 /* from xdpyinfo.c: 815 * there are 2.54 centimeters to an inch; so there are 25.4 millimeters. 816 * 817 * dpi = N pixels / (M millimeters / (25.4 millimeters / 1 inch)) 818 * = N pixels / (M inch / 25.4) 819 * = N * 25.4 pixels / M inch 820 */ 821 xres = ((((double) DisplayWidth(dpy, scr)) * 25.4) / 822 ((double) DisplayWidthMM(dpy, scr))); 823 yres = ((((double) DisplayHeight(dpy, scr)) * 25.4) / 824 ((double) DisplayHeightMM(dpy, scr))); 825 826 /* 827 * xxx the "0" element is always added, so we can't force these here.... 828 * 829 * However, what's interesting is that if the pattern contains '*' for these 830 * fields (i.e. instead of '0') then we end up with the menu containing "0, 831 * 100, xres", which makes for a really good demonstration of how scaling 832 * fonts without knowing the true screen resolution leads to very wonky 833 * results. 834 * 835 * xxx obviously these are static and related only to the screen of the 836 * Widget at the time this code executes and so you can't drag the Xfontsel 837 * winto to another screen with a different resolution and see things change 838 * dynamically -- you have to instantiate a new Xfontsel process on each 839 * different screen as desired. 840 */ 841 sprintf(xreslist, "%d", (int) (xres + 0.5)); 842 sprintf(yreslist, "%d", (int) (yres + 0.5)); 843 844 for (i = fieldValues[6]->count; --i >= 0; fval++) { 845 if (fval->string && !strcmp(fval->string, "0")) { 846 scaledFonts = fval->font; 847 numScaledFonts = fval->count; 848 AddScalables(6); 849 NewScalables(6, AppRes.pixelSizeList); 850 AddScalables(7); 851 NewScalables(7, AppRes.pointSizeList); 852 NewScalables(8, xreslist); 853 NewScalables(9, yreslist); 854 AddScalables(11); 855 break; 856 } 857 } 858} 859 860 861/* A verbatim copy from xc/lib/font/fontfile/fontdir.c */ 862 863/* 864 * Compare two strings just like strcmp, but preserve decimal integer 865 * sorting order, i.e. "2" < "10" or "iso8859-2" < "iso8859-10" < 866 * "iso10646-1". Strings are sorted as if sequences of digits were 867 * prefixed by a length indicator (i.e., does not ignore leading zeroes). 868 * 869 * Markus Kuhn <Markus.Kuhn@cl.cam.ac.uk> 870 */ 871#define Xisdigit(c) ('\060' <= (c) && (c) <= '\071') 872 873static int strcmpn(const char *s1, const char *s2) 874{ 875 int digits, predigits = 0; 876 const char *ss1, *ss2; 877 878 while (1) { 879 if (*s1 == 0 && *s2 == 0) 880 return 0; 881 digits = Xisdigit(*s1) && Xisdigit(*s2); 882 if (digits && !predigits) { 883 ss1 = s1; 884 ss2 = s2; 885 while (Xisdigit(*ss1) && Xisdigit(*ss2)) 886 ss1++, ss2++; 887 if (!Xisdigit(*ss1) && Xisdigit(*ss2)) 888 return -1; 889 if (Xisdigit(*ss1) && !Xisdigit(*ss2)) 890 return 1; 891 } 892 if ((unsigned char)*s1 < (unsigned char)*s2) 893 return -1; 894 if ((unsigned char)*s1 > (unsigned char)*s2) 895 return 1; 896 predigits = digits; 897 s1++, s2++; 898 } 899} 900 901 902/* Order is *, (nil), rest */ 903static int AlphabeticSort(_Xconst void *fval1, _Xconst void *fval2) 904{ 905# define fval1 ((_Xconst FieldValue *)fval1) 906# define fval2 ((_Xconst FieldValue *)fval2) 907 908 if (fval1->string && !strcmp(fval1->string, "*")) 909 return -1; 910 if (fval2->string && !strcmp(fval2->string, "*")) 911 return 1; 912 if (!fval1->string) 913 return -1; 914 if (!fval2->string) 915 return 1; 916 917 return strcmpn(fval1->string, fval2->string); 918 919# undef fval1 920# undef fval2 921} 922 923 924/* Order is *, (nil), rest */ 925static int NumericSort(_Xconst void *fval1, _Xconst void *fval2) 926{ 927# define fval1 ((_Xconst FieldValue *)fval1) 928# define fval2 ((_Xconst FieldValue *)fval2) 929 930 if (fval1->string && !strcmp(fval1->string, "*")) 931 return -1; 932 if (fval2->string && !strcmp(fval2->string, "*")) 933 return 1; 934 if (!fval1->string) 935 return -1; 936 if (!fval2->string) 937 return 1; 938 939 return atoi(fval1->string) - atoi(fval2->string); 940 941# undef fval1 942# undef fval2 943} 944 945 946/* Resort each field, to get reasonable menus. Sort alphabetically or 947 * numerically, depending on the field. Since the fonts have indexes 948 * into the fields, we need to deal with updating those indexes after the 949 * sort. 950 */ 951/*ARGSUSED*/ 952void SortFields(XtPointer closure) 953{ 954 int i, j, count; 955 FieldValue *vals; 956 int *indexes; 957 int *idx; 958 959 for (i = 0; i < FIELD_COUNT; i++) { 960 count = fieldValues[i]->count; 961 vals = fieldValues[i]->value; 962 indexes = (int *)XtMalloc(count * sizeof(int)); 963 /* temporarily use the field component, will restore it below */ 964 for (j = 0; j < count; j++) 965 vals[j].field = j; 966 switch (i) { 967 case 6: case 7: case 8: case 9: case 11: 968 qsort((char *)vals, count, sizeof(FieldValue), NumericSort); 969 break; 970 default: 971 qsort((char *)vals, count, sizeof(FieldValue), AlphabeticSort); 972 break; 973 } 974 for (j = 0; j < count; j++) { 975 indexes[vals[j].field] = j; 976 vals[j].field = i; 977 } 978 for (j = 0; j < numFonts; j++) { 979 idx = &fonts[j].value_index[i]; 980 if (*idx >= 0) 981 *idx = indexes[*idx]; 982 } 983 XtFree((char *)indexes); 984 } 985} 986 987 988Boolean IsXLFDFontName(String fontName) 989{ 990 int f; 991 for (f = 0; *fontName;) if (*fontName++ == DELIM) f++; 992 return (f == FIELD_COUNT); 993} 994 995 996void MakeFieldMenu(XtPointer closure) 997{ 998 FieldMenuRec *makeRec = (FieldMenuRec*)closure; 999 Widget menu; 1000 FieldValueList *values = fieldValues[makeRec->field]; 1001 FieldValue *val = values->value; 1002 int i; 1003 Arg args[1]; 1004 register Widget item; 1005 1006 if (numFonts) 1007 menu = 1008 XtCreatePopupShell("menu",simpleMenuWidgetClass,makeRec->button,NZ); 1009 else { 1010 SetNoFonts(); 1011 return; 1012 } 1013 XtGetSubresources(menu, (XtPointer) values, "options", "Options", 1014 menuResources, XtNumber(menuResources), NZ); 1015 XtAddCallback(menu, XtNpopupCallback, EnableOtherValues, 1016 (XtPointer)(long)makeRec->field ); 1017 1018 if (!patternFieldSpecified[val->field]) { 1019 XtSetArg( args[0], XtNlabel, "*" ); 1020 item = XtCreateManagedWidget("any",smeBSBObjectClass,menu,args,ONE); 1021 XtAddCallback(item, XtNcallback, AnyValue, (XtPointer)(long)val->field); 1022 } 1023 1024 for (i = values->count; i; i--, val++) { 1025 XtSetArg( args[0], XtNlabel, val->string ? val->string : "(nil)" ); 1026 item = 1027 XtCreateManagedWidget(val->string ? val->string : "nil", 1028 smeBSBObjectClass, menu, args, ONE); 1029 XtAddCallback(item, XtNcallback, SelectValue, (XtPointer)val); 1030 val->menu_item = item; 1031 } 1032} 1033 1034 1035static void SetNoFonts(void) 1036{ 1037 matchingFontCount = 0; 1038 SetCurrentFontCount(); 1039 XtSetSensitive(fieldBox, False); 1040 XtSetSensitive(resetButton, False); 1041 XtSetSensitive(ownButton, False); 1042 if (AppRes.app_defaults_version >= MIN_APP_DEFAULTS_VERSION) { 1043 XtUnmapWidget(sampleText); 1044 } 1045} 1046 1047 1048Boolean Matches(register String pattern, register String fontName, 1049 Boolean fields[/*FIELD_COUNT*/], int *maxField) 1050{ 1051 register int field = (*fontName == DELIM) ? -1 : 0; 1052 register Boolean marked_this_field = False; 1053 1054 while (*pattern) { 1055 if (*pattern == *fontName || *pattern == '?') { 1056 pattern++; 1057 if (*fontName++ == DELIM) { 1058 field++; 1059 marked_this_field = False; 1060 } 1061 else if (!marked_this_field) 1062 fields[field] = marked_this_field = True; 1063 continue; 1064 } 1065 if (*pattern == '*') { 1066 if (*++pattern == '\0') { 1067 *maxField = field; 1068 return True; 1069 } 1070 while (*fontName) { 1071 Boolean field_bits[FIELD_COUNT]; 1072 int max_field; 1073 if (*fontName == DELIM) field++; 1074 bzero( field_bits, sizeof(field_bits) ); 1075 if (Matches(pattern, fontName++, field_bits, &max_field)) { 1076 int f; 1077 *maxField = field + max_field; 1078 for (f = 0; f <= max_field; field++, f++) 1079 fields[field] = field_bits[f]; 1080 return True; 1081 } 1082 } 1083 return False; 1084 } 1085 else /* (*pattern != '*') */ 1086 return False; 1087 } 1088 if (*fontName) 1089 return False; 1090 1091 *maxField = field; 1092 return True; 1093} 1094 1095 1096/* ARGSUSED */ 1097void SelectValue(Widget w, XtPointer closure, XtPointer callData) 1098{ 1099 FieldValue *val = (FieldValue*)closure; 1100#ifdef LOG_CHOICES 1101 Choice *choice = XtNew(Choice); 1102#else 1103 static Choice pChoice; 1104 Choice *choice = &pChoice; 1105#endif 1106 1107#ifdef notdef 1108 Widget button = XtParent(XtParent(w)); 1109 Arg args[1]; 1110 1111 XtSetArg(args[0], XtNlabel, val->string); 1112 XtSetValues( button, args, ONE ); 1113#endif 1114 1115 currentFont.value_index[val->field] = val - fieldValues[val->field]->value; 1116 1117 choice->prev = choiceList; 1118 choice->value = val; 1119 choiceList = choice; 1120 1121 SetCurrentFont(NULL); 1122 EnableRemainingItems(SkipCurrentField); 1123} 1124 1125 1126/* ARGSUSED */ 1127void AnyValue(Widget w, XtPointer closure, XtPointer callData) 1128{ 1129 int field = (long)closure; 1130 currentFont.value_index[field] = -1; 1131 SetCurrentFont(NULL); 1132 EnableAllItems(field); 1133 EnableRemainingItems(ValidateCurrentField); 1134} 1135 1136 1137static void SetCurrentFontCount(void) 1138{ 1139 char label[80]; 1140 Arg args[1]; 1141 if (matchingFontCount == 1) 1142 strcpy( label, gettext("1 name matches") ); 1143 else if (matchingFontCount) 1144 snprintf( label, sizeof(label), gettext("%d names match"), matchingFontCount); 1145 else 1146 strcpy( label, gettext("no names match") ); 1147 XtSetArg( args[0], XtNlabel, label ); 1148 XtSetValues( countLabel, args, ONE ); 1149} 1150 1151 1152static void SetParsingFontCount(int count) 1153{ 1154 char label[80]; 1155 Arg args[1]; 1156 if (count == 1) 1157 strcpy( label, gettext("1 name to parse") ); 1158 else 1159 snprintf( label, sizeof(label), gettext("%d names to parse"), count ); 1160 XtSetArg( args[0], XtNlabel, label ); 1161 XtSetValues( countLabel, args, ONE ); 1162 FlushXqueue(XtDisplay(countLabel)); 1163} 1164 1165/* ARGSUSED */ 1166static Boolean IsISO10646(Display *dpy, XFontStruct *font) 1167{ 1168 Boolean ok; 1169 int i; 1170 char *regname; 1171 Atom registry; 1172 XFontProp *xfp; 1173 1174 ok = False; 1175 registry = XInternAtom(dpy, "CHARSET_REGISTRY", False); 1176 1177 for (i = 0, xfp = font->properties; 1178 ok == False && i < font->n_properties; xfp++, i++) { 1179 if (xfp->name == registry) { 1180 regname = XGetAtomName(dpy, (Atom) xfp->card32); 1181 if (strcmp(regname, "ISO10646") == 0 || 1182 strcmp(regname, "iso10646") == 0) 1183 ok = True; 1184 XFree(regname); 1185 } 1186 } 1187 return ok; 1188} 1189 1190/* ARGSUSED */ 1191void SetCurrentFont(XtPointer closure) 1192{ 1193 int f; 1194 Boolean *b; 1195 1196 if (numFonts == 0) { 1197 SetNoFonts(); 1198 return; 1199 } 1200 for (f = numFonts, b = fontInSet; f; f--, b++) *b = True; 1201 1202 { 1203 int bytesLeft = currentFontNameSize; 1204 int pos = 0; 1205 1206 for (f = 0; f < FIELD_COUNT; f++) { 1207 int len, i; 1208 String str; 1209 1210 currentFontNameString[pos++] = DELIM; 1211 if ((i = currentFont.value_index[f]) != -1) { 1212 FieldValue *val = &fieldValues[f]->value[i]; 1213 if ((str = val->string)) 1214 len = strlen(str); 1215 else { 1216 str = ""; 1217 len = 0; 1218 } 1219 MarkInvalidFonts(fontInSet, val); 1220 } else { 1221 str = "*"; 1222 len = 1; 1223 } 1224 if (len+1 > --bytesLeft) { 1225 currentFontNameString = 1226 XtRealloc(currentFontNameString, currentFontNameSize+=128); 1227 bytesLeft += 128; 1228 } 1229 strcpy( ¤tFontNameString[pos], str ); 1230 pos += len; 1231 bytesLeft -= len; 1232 } 1233 } 1234 { 1235 Arg args[1]; 1236 XtSetArg( args[0], XtNlabel, currentFontNameString ); 1237 XtSetValues( currentFontName, args, ONE ); 1238 } 1239 matchingFontCount = 0; 1240 for (f = numFonts, b = fontInSet; f; f--, b++) { 1241 if (*b) matchingFontCount++; 1242 } 1243 1244 SetCurrentFontCount(); 1245 1246 { 1247 Widget mapWidget = sampleText; 1248 Display *dpy = XtDisplay(mapWidget); 1249 XFontStruct *font = XLoadQueryFont(dpy, currentFontNameString); 1250 String sample_text; 1251 if (font == NULL) 1252 XtSetSensitive(mapWidget, False); 1253 else { 1254 int nargs = 1; 1255 Arg args[3]; 1256 int encoding; 1257 if (font->min_byte1 || font->max_byte1) { 1258 if (IsISO10646(dpy, font) == True) { 1259 encoding = XawTextEncodingUCS; 1260 sample_text = AppRes.sample_textUCS; 1261 } else { 1262 encoding = XawTextEncodingChar2b; 1263 sample_text = AppRes.sample_text16; 1264 } 1265 } else { 1266 encoding = XawTextEncoding8bit; 1267 sample_text = AppRes.sample_text; 1268 } 1269 XtSetArg( args[0], XtNfont, font ); 1270 if (encoding != textEncoding) { 1271 XtSetArg(args[1], XtNencoding, encoding); 1272 XtSetArg(args[2], XtNlabel, sample_text); 1273 textEncoding = encoding; 1274 nargs = 3; 1275 } 1276 XtSetValues( sampleText, args, nargs ); 1277 XtSetSensitive(mapWidget, True); 1278 XtMapWidget(mapWidget); 1279 if (sampleFont) XFreeFont( dpy, sampleFont ); 1280 sampleFont = font; 1281 OwnSelection( sampleText, (XtPointer)False, (XtPointer)True ); 1282 } 1283 FlushXqueue(dpy); 1284 } 1285} 1286 1287 1288static void MarkInvalidFonts(Boolean *set, FieldValue *val) 1289{ 1290 int fi = 0, vi; 1291 int *fp = val->font; 1292 for (vi = val->count; vi; vi--, fp++) { 1293 while (fi < *fp) { 1294 set[fi] = False; 1295 fi++; 1296 } 1297 fi++; 1298 } 1299 while (fi < numFonts) { 1300 set[fi] = False; 1301 fi++; 1302 } 1303} 1304 1305 1306static void EnableRemainingItems(ValidateAction current_field_action) 1307{ 1308 if (matchingFontCount == 0 || matchingFontCount == numFonts) { 1309 if (anyDisabled) { 1310 int field; 1311 for (field = 0; field < FIELD_COUNT; field++) { 1312 EnableAllItems(field); 1313 } 1314 anyDisabled = False; 1315 } 1316 } 1317 else { 1318 int field; 1319 for (field = 0; field < FIELD_COUNT; field++) { 1320 FieldValue *value = fieldValues[field]->value; 1321 int count; 1322 if (current_field_action == SkipCurrentField && 1323 field == choiceList->value->field) 1324 continue; 1325 for (count = fieldValues[field]->count; count; count--, value++) { 1326 int *fp = value->font; 1327 int fontCount; 1328 for (fontCount = value->count; fontCount; fontCount--, fp++) { 1329 if (fontInSet[*fp]) { 1330 value->enable = True; 1331 goto NextValue; 1332 } 1333 } 1334 value->enable = False; 1335 NextValue:; 1336 } 1337 } 1338 anyDisabled = True; 1339 } 1340 enabledMenuIndex = -1; 1341 { 1342 int f; 1343 for (f = 0; f < FIELD_COUNT; f++) 1344 ScheduleWork(EnableMenu, (XtPointer)(long)f, BACKGROUND); 1345 } 1346} 1347 1348 1349static void EnableAllItems(int field) 1350{ 1351 FieldValue *value = fieldValues[field]->value; 1352 int count; 1353 for (count = fieldValues[field]->count; count; count--, value++) { 1354 value->enable = True; 1355 } 1356} 1357 1358 1359/* ARGSUSED */ 1360void SelectField(Widget w, XtPointer closure, XtPointer callData) 1361{ 1362 int field = (long)closure; 1363 FieldValue *values = fieldValues[field]->value; 1364 int count = fieldValues[field]->count; 1365 printf(gettext("field %d:\n"), field ); 1366 while (count--) { 1367 printf( gettext(" %s: %d fonts\n"), values->string, values->count ); 1368 values++; 1369 } 1370 printf( "\n" ); 1371} 1372 1373 1374/* When 2 out of 3 y-related scalable fields are set, we need to restrict 1375 * the third set to only match on exact matches, that is, ignore the 1376 * matching to scalable fonts. Because choosing a random third value 1377 * will almost always produce an illegal font name, and it isn't worth 1378 * trying to compute which choices might be legal to the font scaler. 1379 */ 1380static void DisableScaled(int f, int f1, int f2) 1381{ 1382 int i, j; 1383 FieldValue *v; 1384 int *font; 1385 1386 for (i = fieldValues[f]->count, v = fieldValues[f]->value; --i >= 0; v++) { 1387 if (!v->enable || !v->string || !strcmp(v->string, "0")) 1388 continue; 1389 for (j = v->count, font = v->font; --j >= 0; font++) { 1390 if (fontInSet[*font] && 1391 fonts[*font].value_index[f1] == currentFont.value_index[f1] && 1392 fonts[*font].value_index[f2] == currentFont.value_index[f2]) 1393 break; 1394 } 1395 if (j < 0) { 1396 v->enable = False; 1397 XtSetSensitive(v->menu_item, False); 1398 } 1399 } 1400} 1401 1402/* ARGSUSED */ 1403void EnableOtherValues(Widget w, XtPointer closure, XtPointer callData) 1404{ 1405 int field = (long)closure; 1406 Boolean *font_in_set = (Boolean*)XtMalloc(numFonts*sizeof(Boolean)); 1407 Boolean *b; 1408 int f, count; 1409 1410 FinishWork(); 1411 for (f = numFonts, b = font_in_set; f; f--, b++) *b = True; 1412 for (f = 0; f < FIELD_COUNT; f++) { 1413 int i; 1414 if (f != field && (i = currentFont.value_index[f]) != -1) { 1415 MarkInvalidFonts( font_in_set, &fieldValues[f]->value[i] ); 1416 } 1417 } 1418 if (scaledFonts) 1419 { 1420 /* Check for 2 out of 3 scalable y fields being set */ 1421 const char *str; 1422 Bool specificPxl, specificPt, specificY; 1423 1424 f = currentFont.value_index[6]; 1425 specificPxl = (f >= 0 && 1426 (str = fieldValues[6]->value[f].string) && 1427 strcmp(str, "0")); 1428 f = currentFont.value_index[7]; 1429 specificPt = (f >= 0 && 1430 (str = fieldValues[7]->value[f].string) && 1431 strcmp(str, "0")); 1432 f = currentFont.value_index[9]; 1433 specificY = (f >= 0 && 1434 (str = fieldValues[9]->value[f].string) && 1435 strcmp(str, "0")); 1436 if (specificPt && specificY) 1437 DisableScaled(6, 7, 9); 1438 if (specificPxl && specificY) 1439 DisableScaled(7, 6, 9); 1440 if (specificPxl && specificPt) 1441 DisableScaled(9, 6, 7); 1442 } 1443 count = 0; 1444 for (f = numFonts, b = font_in_set; f; f--, b++) { 1445 if (*b) count++; 1446 } 1447 if (count != matchingFontCount) { 1448 Boolean *sp = fontInSet; 1449 FieldValueList *fieldValue = fieldValues[field]; 1450 for (b = font_in_set, f = 0; f < numFonts; f++, b++, sp++) { 1451 if (*b != *sp) { 1452 int i = fonts[f].value_index[field]; 1453 FieldValue *val = &fieldValue->value[i]; 1454 val->enable = True; 1455 XtSetSensitive(val->menu_item, True); 1456 if (++count == matchingFontCount) break; 1457 } 1458 } 1459 } 1460 XtFree((char *)font_in_set); 1461 if (enabledMenuIndex < field) 1462 EnableMenu((XtPointer)(long)field); 1463} 1464 1465 1466void EnableMenu(XtPointer closure) 1467{ 1468 int field = (long)closure; 1469 FieldValue *val = fieldValues[field]->value; 1470 int f; 1471 Widget *managed = NULL, *pManaged = NULL; 1472 Widget *unmanaged = NULL, *pUnmanaged = NULL; 1473 Boolean showUnselectable = fieldValues[field]->show_unselectable; 1474 1475 for (f = fieldValues[field]->count; f; f--, val++) { 1476 if (showUnselectable) { 1477 if (val->enable != XtIsSensitive(val->menu_item)) 1478 XtSetSensitive(val->menu_item, val->enable); 1479 } 1480 else { 1481 if (val->enable != XtIsManaged(val->menu_item)) { 1482 if (val->enable) { 1483 if (managed == NULL) { 1484 managed = (Widget*) 1485 XtMalloc(fieldValues[field]->count*sizeof(Widget)); 1486 pManaged = managed; 1487 } 1488 *pManaged++ = val->menu_item; 1489 } 1490 else { 1491 if (unmanaged == NULL) { 1492 unmanaged = (Widget*) 1493 XtMalloc(fieldValues[field]->count*sizeof(Widget)); 1494 pUnmanaged = unmanaged; 1495 } 1496 *pUnmanaged++ = val->menu_item; 1497 } 1498 } 1499 } 1500 } 1501 if (pManaged != managed) { 1502 XtManageChildren(managed, pManaged - managed); 1503 XtFree((char *) managed); 1504 } 1505 if (pUnmanaged != unmanaged) { 1506 XtUnmanageChildren(unmanaged, pUnmanaged - unmanaged); 1507 XtFree((char *) unmanaged); 1508 } 1509 enabledMenuIndex = field; 1510} 1511 1512 1513static void FlushXqueue(Display *dpy) 1514{ 1515 XSync(dpy, False); 1516 while (XtAppPending(appCtx)) XtAppProcessEvent(appCtx, XtIMAll); 1517} 1518 1519 1520/* ARGSUSED */ 1521void Quit(Widget w, XtPointer closure, XtPointer callData) 1522{ 1523 XtCloseDisplay(XtDisplay(w)); 1524 if (AppRes.print_on_quit) printf( "%s", currentFontNameString ); 1525 exit(0); 1526} 1527 1528 1529void Reset(Widget w, XtPointer closure, XtPointer callData) { 1530 Arg args[1]; 1531 reset_currentFontNameString(); 1532 XtSetArg(args[0], XtNlabel, currentFontNameString); 1533 XtSetValues(currentFontName, args, ONE); 1534 1535 for (int f = 0; f < FIELD_COUNT; f++) 1536 currentFont.value_index[f] = patternFieldSpecified[f] ? 0 : -1; 1537 1538 SetCurrentFont(NULL); 1539 EnableRemainingItems(SkipCurrentField); /* menu */ 1540} 1541 1542static void reset_currentFontNameString(void) { 1543 currentFontNameSize = strlen(AppRes.pattern); 1544 if (currentFontNameSize < 128) currentFontNameSize = 128; 1545 XtFree(currentFontNameString); 1546 currentFontNameString = XtMalloc(currentFontNameSize); 1547 strcpy(currentFontNameString, AppRes.pattern); 1548} 1549 1550 1551static Boolean 1552ConvertSelection(Widget w, Atom *selection, Atom *target, Atom *type, 1553 XtPointer *value, unsigned long *length, int *format) 1554{ 1555 /* XmuConvertStandardSelection will use the second parameter only when 1556 * converting to the target TIMESTAMP. However, it will never be 1557 * called upon to perform this conversion, because Xt will handle it 1558 * internally. CurrentTime will never be used. 1559 */ 1560 if (XmuConvertStandardSelection(w, CurrentTime, selection, target, type, 1561 (XPointer *) value, length, format)) 1562 return True; 1563 1564 if (*target == XA_STRING) { 1565 *type = XA_STRING; 1566 *value = currentFontNameString; 1567 *length = strlen(*value); 1568 *format = 8; 1569 return True; 1570 } 1571 else { 1572 return False; 1573 } 1574} 1575 1576static AtomPtr _XA_PRIMARY_FONT = NULL; 1577#define XA_PRIMARY_FONT XmuInternAtom(XtDisplay(w),_XA_PRIMARY_FONT) 1578 1579/* ARGSUSED */ 1580static void LoseSelection(Widget w, Atom *selection) 1581{ 1582 Arg args[1]; 1583 XtSetArg( args[0], XtNstate, False ); 1584 XtSetValues( w, args, ONE ); 1585 if (*selection == XA_PRIMARY_FONT) { 1586 XtSetSensitive(currentFontName, False); 1587 } 1588} 1589 1590 1591/* ARGSUSED */ 1592static void DoneSelection(Widget w, Atom *selection, Atom *target) 1593{ 1594 /* do nothing */ 1595} 1596 1597 1598/* ARGSUSED */ 1599void OwnSelection(Widget w, XtPointer closure, XtPointer callData) 1600{ 1601 Time time = XtLastTimestampProcessed(XtDisplay(w)); 1602 Boolean primary = (Boolean) (long) closure; 1603 Boolean own = (Boolean) (long) callData; 1604 1605 if (_XA_PRIMARY_FONT == NULL) 1606 _XA_PRIMARY_FONT = XmuMakeAtom("PRIMARY_FONT"); 1607 1608 if (own) { 1609 XtOwnSelection( w, XA_PRIMARY_FONT, time, 1610 ConvertSelection, LoseSelection, DoneSelection ); 1611 if (primary) 1612 XtOwnSelection( w, XA_PRIMARY, time, 1613 ConvertSelection, LoseSelection, DoneSelection ); 1614 if (!XtIsSensitive(currentFontName)) { 1615 XtSetSensitive(currentFontName, True); 1616 } 1617 } 1618 else { 1619 XtDisownSelection(w, XA_PRIMARY_FONT, time); 1620 if (primary) 1621 XtDisownSelection(w, XA_PRIMARY, time); 1622 XtSetSensitive(currentFontName, False); 1623 } 1624} 1625 1626/*ARGSUSED*/ 1627void 1628QuitAction(Widget w, XEvent *event, String *params, Cardinal *num_params) 1629{ 1630 exit (0); 1631} 1632