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