1
/* $XConsortium: xfontsel.c,v 1.35 94/04/17 20:43:41 rws Exp $ */
4
Copyright (c) 1985-1989 X Consortium
6
Permission is hereby granted, free of charge, to any person obtaining
7
a copy of this software and associated documentation files (the
8
"Software"), to deal in the Software without restriction, including
9
without limitation the rights to use, copy, modify, merge, publish,
10
distribute, sublicense, and/or sell copies of the Software, and to
11
permit persons to whom the Software is furnished to do so, subject to
12
the following conditions:
14
The above copyright notice and this permission notice shall be included
15
in all copies or substantial portions of the Software.
17
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20
IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
21
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
OTHER DEALINGS IN THE SOFTWARE.
25
Except as contained in this notice, the name of the X Consortium shall
26
not be used in advertising or otherwise to promote the sale, use or
27
other dealings in this Software without prior written authorization
28
from the X Consortium.
30
Author: Ralph R. Swick, DEC/MIT Project Athena
31
one weekend in November, 1989
32
Modified: Mark Leisher <mleisher@crl.nmsu.edu> to deal with UCS sample text.
34
/* $XFree86: xc/programs/xfontsel/xfontsel.c,v 1.7 2001/10/28 03:34:32 tsi Exp $ */
38
#include <X11/Intrinsic.h>
39
#include <X11/StringDefs.h>
40
#include <X11/Xatom.h>
41
#include <X11/Xaw/AsciiText.h>
42
#include <X11/Xaw/Box.h>
43
#include <X11/Xaw/Cardinals.h>
44
#include <X11/Xaw/Command.h>
45
#include <X11/Xaw/Form.h>
46
#include <X11/Xaw/MenuButton.h>
47
#include <X11/Xaw/Paned.h>
48
#include <X11/Xaw/SimpleMenu.h>
49
#include <X11/Xaw/SmeBSB.h>
50
#include <X11/Xaw/Toggle.h>
51
#include <X11/Xaw/Viewport.h>
52
#include <X11/Xmu/Atoms.h>
53
#include <X11/Xmu/StdSel.h>
54
#include <X11/Xfuncs.h>
57
#define MIN_APP_DEFAULTS_VERSION 1
58
#define FIELD_COUNT 14
61
/* number of font names to parse in each background iteration */
63
#define PARSE_QUANTUM 25
71
Boolean DoWorkPiece();
75
void ParseFontNames();
81
void EnableOtherValues();
83
void SetCurrentFont();
86
XtActionsRec xfontsel_actions[] = {
90
Atom wm_delete_window;
92
Boolean IsXLFDFontName();
94
typedef void (*XtProc)();
96
static struct _appRes {
97
int app_defaults_version;
100
String pixelSizeList;
101
String pointSizeList;
102
Boolean print_on_quit;
104
String sample_text16;
105
String sample_textUCS;
106
Boolean scaled_fonts;
109
#define DEFAULTPATTERN "-*-*-*-*-*-*-*-*-*-*-*-*-*-*"
111
static XtResource resources[] = {
112
{ "cursor", "Cursor", XtRCursor, sizeof(Cursor),
113
XtOffsetOf( struct _appRes, cursor ),
114
XtRImmediate, NULL },
115
{ "pattern", "Pattern", XtRString, sizeof(String),
116
XtOffsetOf( struct _appRes, pattern ),
117
XtRString, (XtPointer)DEFAULTPATTERN },
118
{ "pixelSizeList", "PixelSizeList", XtRString, sizeof(String),
119
XtOffsetOf( struct _appRes, pixelSizeList ),
120
XtRString, (XtPointer)"" },
121
{ "pointSizeList", "PointSizeList", XtRString, sizeof(String),
122
XtOffsetOf( struct _appRes, pointSizeList ),
123
XtRString, (XtPointer)"" },
124
{ "printOnQuit", "PrintOnQuit", XtRBoolean, sizeof(Boolean),
125
XtOffsetOf( struct _appRes, print_on_quit ),
126
XtRImmediate, (XtPointer)False },
127
{ "appDefaultsVersion", "AppDefaultsVersion", XtRInt, sizeof(int),
128
XtOffsetOf( struct _appRes, app_defaults_version ),
129
XtRImmediate, (XtPointer)0 },
130
{ "sampleText", "Text", XtRString, sizeof(String),
131
XtOffsetOf( struct _appRes, sample_text ),
132
XtRString, (XtPointer)"" },
133
{ "sampleText16", "Text16", XtRString, sizeof(String),
134
XtOffsetOf( struct _appRes, sample_text16 ),
135
XtRString, (XtPointer)"" },
136
{ "sampleTextUCS", "TextUCS", XtRString, sizeof(String),
137
XtOffsetOf( struct _appRes, sample_textUCS ),
138
XtRString, (XtPointer)"" },
139
{ "scaledFonts", "ScaledFonts", XtRBoolean, sizeof(Boolean),
140
XtOffsetOf( struct _appRes, scaled_fonts ),
141
XtRImmediate, (XtPointer)False },
144
static XrmOptionDescRec options[] = {
145
{"-pattern", "pattern", XrmoptionSepArg, NULL},
146
{"-print", "printOnQuit", XrmoptionNoArg, "True"},
147
{"-sample", "sampleText", XrmoptionSepArg, NULL},
148
{"-sample16", "sampleText16", XrmoptionSepArg, NULL},
149
{"-sampleUCS", "sampleTextUCS",XrmoptionSepArg, NULL},
150
{"-scaled", "scaledFonts", XrmoptionNoArg, "True"},
153
static void Syntax(call)
156
fprintf (stderr, "usage: %s [-options ...] -fn font\n\n", call);
157
fprintf (stderr, "where options include:\n");
159
" -display dpy X server to contact\n");
161
" -geometry geom size and location of window\n");
163
" -pattern fontspec font name pattern to match against\n");
165
" -print print selected font name on exit\n");
167
" -sample string sample text to use for 1-byte fonts\n");
169
" -sample16 string sample text to use for 2-byte fonts\n");
171
" -sampleUCS string sample text to use for ISO10646 fonts\n");
173
" -scaled use scaled instances of fonts\n");
174
fprintf (stderr, "\n");
179
typedef struct FieldValue FieldValue;
184
int count; /* of fonts */
191
typedef struct FieldValueList FieldValueList;
192
struct FieldValueList {
193
int count; /* of values */
195
Boolean show_unselectable;
196
FieldValue value[1]; /* really [allocated] */
200
typedef struct FontValues FontValues;
202
int value_index[FIELD_COUNT];
206
typedef struct FieldMenuRec FieldMenuRec;
207
struct FieldMenuRec {
213
typedef struct Choice Choice;
220
static XtResource menuResources[] = {
221
{ "showUnselectable", "ShowUnselectable", XtRBoolean, sizeof(Boolean),
222
XtOffsetOf( FieldValueList, show_unselectable ),
223
XtRImmediate, (XtPointer)True },
227
typedef enum {ValidateCurrentField, SkipCurrentField} ValidateAction;
229
static void EnableAllItems(int field);
230
static void EnableRemainingItems(ValidateAction current_field_action);
231
static void FlushXqueue(Display *dpy);
232
static void MarkInvalidFonts(Boolean *set, FieldValue *val);
233
static void ScheduleWork(XtProc proc, XtPointer closure, int priority);
234
static void SetCurrentFontCount(void);
235
static void SetNoFonts(void);
236
static void SetParsingFontCount(int count);
244
FieldValueList *fieldValues[FIELD_COUNT];
245
FontValues currentFont;
246
int matchingFontCount;
247
static Boolean anyDisabled = False;
251
Widget currentFontName;
252
String currentFontNameString;
253
int currentFontNameSize;
255
int textEncoding = -1;
256
static XFontStruct *sampleFont = NULL;
258
static Choice *choiceList = NULL;
259
int enabledMenuIndex;
260
static Boolean patternFieldSpecified[FIELD_COUNT]; /* = 0 */
267
Widget topLevel, pane;
269
XtSetLanguageProc(NULL, (XtLanguageProc) NULL, NULL);
271
topLevel = XtAppInitialize(&appCtx, "XFontSel", options, XtNumber(options),
272
&argc, argv, NULL, NULL, 0);
274
if (argc != 1) Syntax(argv[0]);
276
XtAppAddActions(appCtx, xfontsel_actions, XtNumber(xfontsel_actions));
277
XtOverrideTranslations
278
(topLevel, XtParseTranslationTable ("<Message>WM_PROTOCOLS: Quit()"));
280
XtGetApplicationResources( topLevel, (XtPointer)&AppRes,
281
resources, XtNumber(resources), NZ );
282
if (AppRes.app_defaults_version < MIN_APP_DEFAULTS_VERSION) {
283
XrmDatabase rdb = XtDatabase(XtDisplay(topLevel));
284
XtWarning( "app-defaults file not properly installed." );
285
XrmPutLineResource( &rdb,
286
"*sampleText*UCSLabel:XFontSel app-defaults file not properly installed;\\n\
287
see 'xfontsel' manual page."
291
ScheduleWork(GetFontNames, (XtPointer)XtDisplay(topLevel), 0);
293
pane = XtCreateManagedWidget("pane",panedWidgetClass,topLevel,NZ);
295
Widget commandBox, /* fieldBox, currentFontName,*/ viewPort;
297
commandBox = XtCreateManagedWidget("commandBox",formWidgetClass,pane,NZ);
299
Widget quitButton /*, ownButton , countLabel*/;
302
XtCreateManagedWidget("quitButton",commandWidgetClass,commandBox,NZ);
305
XtCreateManagedWidget("ownButton",toggleWidgetClass,commandBox,NZ);
308
XtCreateManagedWidget("countLabel",labelWidgetClass,commandBox,NZ);
310
XtAddCallback(quitButton, XtNcallback, Quit, NULL);
311
XtAddCallback(ownButton,XtNcallback,OwnSelection,(XtPointer)True);
314
fieldBox = XtCreateManagedWidget("fieldBox", boxWidgetClass, pane, NZ);
316
Widget /*dash,*/ field /*[FIELD_COUNT]*/;
319
for (f = 0; f < FIELD_COUNT; f++) {
321
FieldMenuRec *makeRec = XtNew(FieldMenuRec);
322
sprintf( name, "field%d", f );
323
XtCreateManagedWidget("dash",labelWidgetClass,fieldBox,NZ);
324
field = XtCreateManagedWidget(name, menuButtonWidgetClass,
326
XtAddCallback(field, XtNcallback, SelectField,
329
makeRec->button = field;
330
ScheduleWork(MakeFieldMenu, (XtPointer)makeRec, 2);
331
ScheduleWork(XtFree, (XtPointer)makeRec, 2);
335
/* currentFontName = */
338
currentFontNameSize = strlen(AppRes.pattern);
339
if (currentFontNameSize < 128) currentFontNameSize = 128;
340
currentFontNameString = (String)XtMalloc(currentFontNameSize);
341
strcpy(currentFontNameString, AppRes.pattern);
342
XtSetArg(args[0], XtNlabel, currentFontNameString);
344
XtCreateManagedWidget("fontName",labelWidgetClass,pane,args,ONE);
348
XtCreateManagedWidget("viewPort",viewportWidgetClass,pane,NZ);
350
#ifdef USE_TEXT_WIDGET
352
XtCreateManagedWidget("sampleText",asciiTextWidgetClass,viewPort,NZ);
354
XtSetArg( args[0], XtNtextSink, &sampleText );
355
XtGetValues( text, args, ONE );
358
XtCreateManagedWidget("sampleText",ucsLabelWidgetClass,viewPort,NZ);
363
XtRealizeWidget(topLevel);
364
XDefineCursor( XtDisplay(topLevel), XtWindow(topLevel), AppRes.cursor );
367
for (f = 0; f < FIELD_COUNT; f++) currentFont.value_index[f] = -1;
369
wm_delete_window = XInternAtom(XtDisplay(topLevel), "WM_DELETE_WINDOW",
371
(void) XSetWMProtocols (XtDisplay(topLevel), XtWindow(topLevel),
372
&wm_delete_window, 1);
373
XtAppMainLoop(appCtx);
379
typedef struct WorkPiece WorkPieceRec, *WorkPiece;
386
static WorkPiece workQueue = NULL;
390
* ScheduleWork( XtProc proc, XtPointer closure, int priority )
392
* Adds a WorkPiece to the workQueue in FIFO order by priority.
393
* Lower numbered priority work is completed before higher numbered
396
* If the workQueue was previously empty, then makes sure that
397
* Xt knows we have (background) work to do.
400
static void ScheduleWork( proc, closure, priority )
405
WorkPiece piece = XtNew(WorkPieceRec);
407
piece->priority = priority;
409
piece->closure = closure;
410
if (workQueue == NULL) {
413
XtAppAddWorkProc(appCtx, DoWorkPiece, NULL);
415
if (workQueue->priority > priority) {
416
piece->next = workQueue;
421
for (n = workQueue; n->next && n->next->priority <= priority;)
423
piece->next = n->next;
430
Boolean DoWorkPiece(closure)
431
XtPointer closure; /* unused */
433
WorkPiece piece = workQueue;
436
(*piece->proc)(piece->closure);
437
workQueue = piece->next;
438
XtFree((XtPointer)piece);
439
if (workQueue != NULL)
449
* Drains foreground tasks from the workQueue.
450
* Foreground == (priority < BACKGROUND)
455
while (workQueue && workQueue->priority < BACKGROUND)
460
typedef struct ParseRec ParseRec;
466
FieldValueList **fieldValues;
470
void GetFontNames( closure )
473
Display *dpy = (Display*)closure;
474
ParseRec *parseRec = XtNew(ParseRec);
478
int work_priority = 0;
480
fontNames = parseRec->fontNames =
481
XListFonts(dpy, AppRes.pattern, 32767, &numFonts);
483
fonts = (FontValues*)XtMalloc( numFonts*sizeof(FontValues) );
484
fontInSet = (Boolean*)XtMalloc( numFonts*sizeof(Boolean) );
485
for (f = numFonts, b = fontInSet; f; f--, b++) *b = True;
486
for (field = 0; field < FIELD_COUNT; field++) {
487
fieldValues[field] = (FieldValueList*)XtMalloc(sizeof(FieldValueList));
488
fieldValues[field]->allocated = 1;
489
fieldValues[field]->count = 0;
496
parseRec->fonts = fonts;
497
parseRec->num_fonts = count = matchingFontCount = numFonts;
498
parseRec->fieldValues = fieldValues;
500
/* this is bogus; the task should be responsible for quantizing...*/
501
while (count > PARSE_QUANTUM) {
502
ParseRec *prevRec = parseRec;
503
parseRec->end = parseRec->start + PARSE_QUANTUM;
504
ScheduleWork(ParseFontNames, (XtPointer)parseRec, work_priority);
505
ScheduleWork(XtFree, (XtPointer)parseRec, work_priority);
506
parseRec = XtNew(ParseRec);
507
*parseRec = *prevRec;
508
parseRec->start += PARSE_QUANTUM;
509
parseRec->fonts += PARSE_QUANTUM;
510
parseRec->fontNames += PARSE_QUANTUM;
511
count -= PARSE_QUANTUM;
514
parseRec->end = numFonts;
515
ScheduleWork(ParseFontNames,(XtPointer)parseRec,work_priority);
516
ScheduleWork((XtProc)XFreeFontNames,(XtPointer)fontNames,work_priority);
517
ScheduleWork(XtFree, (XtPointer)parseRec, work_priority);
518
if (AppRes.scaled_fonts)
519
ScheduleWork(FixScalables,(XtPointer)0,work_priority);
520
ScheduleWork(SortFields,(XtPointer)0,work_priority);
521
SetParsingFontCount(matchingFontCount);
522
if (strcmp(AppRes.pattern, DEFAULTPATTERN)) {
524
for (f = 0; f < numFonts && !IsXLFDFontName(fontNames[f]); f++);
526
if (Matches(AppRes.pattern, fontNames[f],
527
patternFieldSpecified, &maxField)) {
528
for (f = 0; f <= maxField; f++) {
529
if (patternFieldSpecified[f])
530
currentFont.value_index[f] = 0;
534
XtAppWarning( appCtx,
535
"internal error; pattern didn't match first font" );
542
ScheduleWork(SetCurrentFont, NULL, 1);
546
void ParseFontNames( closure )
549
ParseRec *parseRec = (ParseRec*)closure;
550
char **fontNames = parseRec->fontNames;
551
int num_fonts = parseRec->end;
552
FieldValueList **fieldValues = parseRec->fieldValues;
553
FontValues *fontValues = parseRec->fonts - numBadFonts;
556
for (font = parseRec->start; font < num_fonts; font++) {
561
if (!IsXLFDFontName(*fontNames)) {
567
for (f = 0, p = *fontNames++; f < FIELD_COUNT; f++) {
571
if (*p == DELIM || *p == '\0') {
576
while (*p && *++p != DELIM);
579
for (i=fieldValues[f]->count,v=fieldValues[f]->value; i;i--,v++) {
581
if (v->string == NULL) break;
585
strncmp( v->string, fieldP, len ) == 0 &&
586
(v->string)[len] == '\0')
590
int count = fieldValues[f]->count++;
591
if (count == fieldValues[f]->allocated) {
592
int allocated = (fieldValues[f]->allocated += 10);
593
fieldValues[f] = (FieldValueList*)
594
XtRealloc( (char *) fieldValues[f],
595
sizeof(FieldValueList) +
596
(allocated-1) * sizeof(FieldValue) );
598
v = &fieldValues[f]->value[count];
603
v->string = (String)XtMalloc( len+1 );
604
strncpy( v->string, fieldP, len );
605
v->string[len] = '\0';
607
v->font = (int*)XtMalloc( 10*sizeof(int) );
613
fontValues->value_index[f] = fieldValues[f]->count - i;
614
if ((i = v->count++) == v->allocated) {
615
int allocated = (v->allocated += 10);
616
v->font = (int*)XtRealloc( (char *) v->font,
617
allocated * sizeof(int) );
619
v->font[i] = font - numBadFonts;
623
SetParsingFontCount(numFonts - num_fonts);
627
/* Add the list of scalable fonts to the match-list of every value instance
628
* for field f. Must produce sorted order. Must deal with duplicates
629
* since we need to do this for resolution fields which can be nonzero in
630
* the scalable fonts.
636
int max = fieldValues[f]->count;
637
FieldValue *fval = fieldValues[f]->value;
639
for (i = 0; i < max; i++, fval++) {
640
int *oofonts, *ofonts, *nfonts, *fonts;
641
int ocount, ncount, count;
643
if (fval->string && !strcmp(fval->string, "0"))
645
count = numScaledFonts;
647
ocount = fval->count;
648
ncount = ocount + count;
649
nfonts = (int *)XtMalloc( ncount * sizeof(int) );
650
oofonts = ofonts = fval->font;
652
fval->count = ncount;
653
fval->allocated = ncount;
654
while (count && ocount) {
655
if (*fonts < *ofonts) {
656
*nfonts++ = *fonts++;
658
} else if (*fonts == *ofonts) {
659
*nfonts++ = *fonts++;
665
*nfonts++ = *ofonts++;
670
*nfonts++ = *ofonts++;
674
*nfonts++ = *fonts++;
677
XtFree((char *)oofonts);
682
/* Merge in specific scaled sizes (specified in a comma-separated string)
683
* for field f. Weed out duplicates. The set of matching fonts is just
684
* the set of scalable fonts.
686
void NewScalables(f, slist)
696
while (*slist == ' ' || *slist == ',')
701
while ((endc = *slist) && endc != ' ' && endc != ',')
704
for (i=fieldValues[f]->count,v=fieldValues[f]->value; --i >= 0; v++) {
705
if (v->string && !strcmp(v->string, str))
710
count = fieldValues[f]->count++;
711
if (count == fieldValues[f]->allocated) {
712
int allocated = (fieldValues[f]->allocated += 10);
713
fieldValues[f] = (FieldValueList*)
714
XtRealloc( (char *) fieldValues[f],
715
sizeof(FieldValueList) +
716
(allocated-1) * sizeof(FieldValue) );
718
v = &fieldValues[f]->value[count];
721
v->count = numScaledFonts;
722
v->font = scaledFonts;
729
/* Find all scalable fonts, defined as the set matching "0" in the pixel
730
* size field (field 6). Augment the match-lists for all other fields
731
* that are scalable. Add in new scalable pixel and point sizes given
735
void FixScalables( closure )
739
FieldValue *fval = fieldValues[6]->value;
741
for (i = fieldValues[6]->count; --i >= 0; fval++) {
742
if (fval->string && !strcmp(fval->string, "0")) {
743
scaledFonts = fval->font;
744
numScaledFonts = fval->count;
746
NewScalables(6, AppRes.pixelSizeList);
748
NewScalables(7, AppRes.pointSizeList);
758
/* A verbatim copy from xc/lib/font/fontfile/fontdir.c */
761
* Compare two strings just like strcmp, but preserve decimal integer
762
* sorting order, i.e. "2" < "10" or "iso8859-2" < "iso8859-10" <
763
* "iso10646-1". Strings are sorted as if sequences of digits were
764
* prefixed by a length indicator (i.e., does not ignore leading zeroes).
766
* Markus Kuhn <Markus.Kuhn@cl.cam.ac.uk>
768
#define Xisdigit(c) ('\060' <= (c) && (c) <= '\071')
770
static int strcmpn(const char *s1, const char *s2)
772
int digits, predigits = 0;
773
const char *ss1, *ss2;
776
if (*s1 == 0 && *s2 == 0)
778
digits = Xisdigit(*s1) && Xisdigit(*s2);
779
if (digits && !predigits) {
782
while (Xisdigit(*ss1) && Xisdigit(*ss2))
784
if (!Xisdigit(*ss1) && Xisdigit(*ss2))
786
if (Xisdigit(*ss1) && !Xisdigit(*ss2))
789
if ((unsigned char)*s1 < (unsigned char)*s2)
791
if ((unsigned char)*s1 > (unsigned char)*s2)
799
/* Order is *, (nil), rest */
800
int AlphabeticSort(fval1, fval2)
801
FieldValue *fval1, *fval2;
803
if (fval1->string && !strcmp(fval1->string, "*"))
805
if (fval2->string && !strcmp(fval2->string, "*"))
811
return strcmpn(fval1->string, fval2->string);
815
/* Order is *, (nil), rest */
816
int NumericSort(fval1, fval2)
817
FieldValue *fval1, *fval2;
819
if (fval1->string && !strcmp(fval1->string, "*"))
821
if (fval2->string && !strcmp(fval2->string, "*"))
827
return atoi(fval1->string) - atoi(fval2->string);
831
/* Resort each field, to get reasonable menus. Sort alphabetically or
832
* numerically, depending on the field. Since the fonts have indexes
833
* into the fields, we need to deal with updating those indexes after the
837
void SortFields( closure )
845
for (i = 0; i < FIELD_COUNT; i++) {
846
count = fieldValues[i]->count;
847
vals = fieldValues[i]->value;
848
indexes = (int *)XtMalloc(count * sizeof(int));
849
/* temporarily use the field component, will restore it below */
850
for (j = 0; j < count; j++)
853
case 6: case 7: case 8: case 9: case 11:
854
qsort((char *)vals, count, sizeof(FieldValue), NumericSort);
857
qsort((char *)vals, count, sizeof(FieldValue), AlphabeticSort);
860
for (j = 0; j < count; j++) {
861
indexes[vals[j].field] = j;
864
for (j = 0; j < numFonts; j++) {
865
idx = &fonts[j].value_index[i];
867
*idx = indexes[*idx];
869
XtFree((char *)indexes);
874
Boolean IsXLFDFontName(fontName)
878
for (f = 0; *fontName;) if (*fontName++ == DELIM) f++;
879
return (f == FIELD_COUNT);
883
void MakeFieldMenu(closure)
886
FieldMenuRec *makeRec = (FieldMenuRec*)closure;
888
FieldValueList *values = fieldValues[makeRec->field];
889
FieldValue *val = values->value;
892
register Widget item;
896
XtCreatePopupShell("menu",simpleMenuWidgetClass,makeRec->button,NZ);
901
XtGetSubresources(menu, (XtPointer) values, "options", "Options",
902
menuResources, XtNumber(menuResources), NZ);
903
XtAddCallback(menu, XtNpopupCallback, EnableOtherValues,
904
(XtPointer)(long)makeRec->field );
906
if (!patternFieldSpecified[val->field]) {
907
XtSetArg( args[0], XtNlabel, "*" );
908
item = XtCreateManagedWidget("any",smeBSBObjectClass,menu,args,ONE);
909
XtAddCallback(item, XtNcallback, AnyValue, (XtPointer)(long)val->field);
912
for (i = values->count; i; i--, val++) {
913
XtSetArg( args[0], XtNlabel, val->string ? val->string : "(nil)" );
915
XtCreateManagedWidget(val->string ? val->string : "nil",
916
smeBSBObjectClass, menu, args, ONE);
917
XtAddCallback(item, XtNcallback, SelectValue, (XtPointer)val);
918
val->menu_item = item;
923
static void SetNoFonts(void)
925
matchingFontCount = 0;
926
SetCurrentFontCount();
927
XtSetSensitive(fieldBox, False);
928
XtSetSensitive(ownButton, False);
929
if (AppRes.app_defaults_version >= MIN_APP_DEFAULTS_VERSION) {
930
#ifdef USE_TEXT_WIDGET
931
XtUnmapWidget(XtParent(sampleText));
933
XtUnmapWidget(sampleText);
939
Boolean Matches(pattern, fontName, fields, maxField)
940
register String pattern, fontName;
941
Boolean fields[/*FIELD_COUNT*/];
944
register int field = (*fontName == DELIM) ? -1 : 0;
945
register Boolean marked_this_field = False;
948
if (*pattern == *fontName || *pattern == '?') {
950
if (*fontName++ == DELIM) {
952
marked_this_field = False;
954
else if (!marked_this_field)
955
fields[field] = marked_this_field = True;
958
if (*pattern == '*') {
959
if (*++pattern == '\0') {
964
Boolean field_bits[FIELD_COUNT];
966
if (*fontName == DELIM) field++;
967
bzero( field_bits, sizeof(field_bits) );
968
if (Matches(pattern, fontName++, field_bits, &max_field)) {
970
*maxField = field + max_field;
971
for (f = 0; f <= max_field; field++, f++)
972
fields[field] = field_bits[f];
978
else /* (*pattern != '*') */
990
void SelectValue(w, closure, callData)
992
XtPointer closure, callData;
994
FieldValue *val = (FieldValue*)closure;
996
Choice *choice = XtNew(Choice);
998
static Choice pChoice;
999
Choice *choice = &pChoice;
1003
Widget button = XtParent(XtParent(w));
1006
XtSetArg(args[0], XtNlabel, val->string);
1007
XtSetValues( button, args, ONE );
1010
currentFont.value_index[val->field] = val - fieldValues[val->field]->value;
1012
choice->prev = choiceList;
1013
choice->value = val;
1014
choiceList = choice;
1016
SetCurrentFont(NULL);
1017
EnableRemainingItems(SkipCurrentField);
1022
void AnyValue(w, closure, callData)
1024
XtPointer closure, callData;
1026
int field = (long)closure;
1027
currentFont.value_index[field] = -1;
1028
SetCurrentFont(NULL);
1029
EnableAllItems(field);
1030
EnableRemainingItems(ValidateCurrentField);
1034
static void SetCurrentFontCount(void)
1038
if (matchingFontCount == 1)
1039
strcpy( label, "1 name matches" );
1040
else if (matchingFontCount)
1041
sprintf( label, "%d names match", matchingFontCount );
1043
strcpy( label, "no names match" );
1044
XtSetArg( args[0], XtNlabel, label );
1045
XtSetValues( countLabel, args, ONE );
1049
static void SetParsingFontCount(int count)
1054
strcpy( label, "1 name to parse" );
1056
sprintf( label, "%d names to parse", count );
1057
XtSetArg( args[0], XtNlabel, label );
1058
XtSetValues( countLabel, args, ONE );
1059
FlushXqueue(XtDisplay(countLabel));
1063
static Boolean IsISO10646(dpy, font)
1074
registry = XInternAtom(dpy, "CHARSET_REGISTRY", False);
1076
for (i = 0, xfp = font->properties;
1077
ok == False && i < font->n_properties; xfp++, i++) {
1078
if (xfp->name == registry) {
1079
regname = XGetAtomName(dpy, (Atom) xfp->card32);
1080
if (strcmp(regname, "ISO10646") == 0 ||
1081
strcmp(regname, "iso10646") == 0)
1090
void SetCurrentFont(closure)
1091
XtPointer closure; /* unused */
1096
if (numFonts == 0) {
1100
for (f = numFonts, b = fontInSet; f; f--, b++) *b = True;
1103
int bytesLeft = currentFontNameSize;
1106
for (f = 0; f < FIELD_COUNT; f++) {
1110
currentFontNameString[pos++] = DELIM;
1111
if ((i = currentFont.value_index[f]) != -1) {
1112
FieldValue *val = &fieldValues[f]->value[i];
1113
if ((str = val->string))
1119
MarkInvalidFonts(fontInSet, val);
1124
if (len+1 > --bytesLeft) {
1125
currentFontNameString = (String)
1126
XtRealloc(currentFontNameString, currentFontNameSize+=128);
1129
strcpy( ¤tFontNameString[pos], str );
1136
XtSetArg( args[0], XtNlabel, currentFontNameString );
1137
XtSetValues( currentFontName, args, ONE );
1139
matchingFontCount = 0;
1140
for (f = numFonts, b = fontInSet; f; f--, b++) {
1141
if (*b) matchingFontCount++;
1144
SetCurrentFontCount();
1147
#ifdef USE_TEXT_WIDGET
1148
Widget mapWidget = XtParent(sampleText);
1150
Widget mapWidget = sampleText;
1152
Display *dpy = XtDisplay(mapWidget);
1153
XFontStruct *font = XLoadQueryFont(dpy, currentFontNameString);
1156
XtUnmapWidget(mapWidget);
1161
if (font->min_byte1 || font->max_byte1) {
1162
if (IsISO10646(dpy, font) == True) {
1163
encoding = XawTextEncodingUCS;
1164
sample_text = AppRes.sample_textUCS;
1166
encoding = XawTextEncodingChar2b;
1167
sample_text = AppRes.sample_text16;
1170
encoding = XawTextEncoding8bit;
1171
sample_text = AppRes.sample_text;
1173
XtSetArg( args[0], XtNfont, font );
1174
if (encoding != textEncoding) {
1175
XtSetArg(args[1], XtNencoding, encoding);
1176
XtSetArg(args[2], XtNlabel, sample_text);
1177
textEncoding = encoding;
1180
XtSetValues( sampleText, args, nargs );
1181
XtMapWidget(mapWidget);
1182
if (sampleFont) XFreeFont( dpy, sampleFont );
1184
OwnSelection( sampleText, (XtPointer)False, (XtPointer)True );
1191
static void MarkInvalidFonts( set, val )
1196
int *fp = val->font;
1197
for (vi = val->count; vi; vi--, fp++) {
1204
while (fi < numFonts) {
1211
static void EnableRemainingItems(current_field_action)
1212
ValidateAction current_field_action;
1214
if (matchingFontCount == 0 || matchingFontCount == numFonts) {
1217
for (field = 0; field < FIELD_COUNT; field++) {
1218
EnableAllItems(field);
1220
anyDisabled = False;
1225
for (field = 0; field < FIELD_COUNT; field++) {
1226
FieldValue *value = fieldValues[field]->value;
1228
if (current_field_action == SkipCurrentField &&
1229
field == choiceList->value->field)
1231
for (count = fieldValues[field]->count; count; count--, value++) {
1232
int *fp = value->font;
1234
for (fontCount = value->count; fontCount; fontCount--, fp++) {
1235
if (fontInSet[*fp]) {
1236
value->enable = True;
1240
value->enable = False;
1246
enabledMenuIndex = -1;
1249
for (f = 0; f < FIELD_COUNT; f++)
1250
ScheduleWork(EnableMenu, (XtPointer)(long)f, BACKGROUND);
1255
static void EnableAllItems(int field)
1257
FieldValue *value = fieldValues[field]->value;
1259
for (count = fieldValues[field]->count; count; count--, value++) {
1260
value->enable = True;
1266
void SelectField(w, closure, callData)
1268
XtPointer closure, callData;
1270
int field = (long)closure;
1271
FieldValue *values = fieldValues[field]->value;
1272
int count = fieldValues[field]->count;
1273
printf( "field %d:\n", field );
1275
printf( " %s: %d fonts\n", values->string, values->count );
1282
/* When 2 out of 3 y-related scalable fields are set, we need to restrict
1283
* the third set to only match on exact matches, that is, ignore the
1284
* matching to scalable fonts. Because choosing a random third value
1285
* will almost always produce an illegal font name, and it isn't worth
1286
* trying to compute which choices might be legal to the font scaler.
1288
void DisableScaled(f, f1, f2)
1295
for (i = fieldValues[f]->count, v = fieldValues[f]->value; --i >= 0; v++) {
1296
if (!v->enable || !v->string || !strcmp(v->string, "0"))
1298
for (j = v->count, font = v->font; --j >= 0; font++) {
1299
if (fontInSet[*font] &&
1300
fonts[*font].value_index[f1] == currentFont.value_index[f1] &&
1301
fonts[*font].value_index[f2] == currentFont.value_index[f2])
1306
XtSetSensitive(v->menu_item, False);
1312
void EnableOtherValues(w, closure, callData)
1314
XtPointer closure, callData;
1316
int field = (long)closure;
1317
Boolean *font_in_set = (Boolean*)XtMalloc(numFonts*sizeof(Boolean));
1322
for (f = numFonts, b = font_in_set; f; f--, b++) *b = True;
1323
for (f = 0; f < FIELD_COUNT; f++) {
1325
if (f != field && (i = currentFont.value_index[f]) != -1) {
1326
MarkInvalidFonts( font_in_set, &fieldValues[f]->value[i] );
1331
/* Check for 2 out of 3 scalable y fields being set */
1333
Bool specificPxl, specificPt, specificY;
1335
f = currentFont.value_index[6];
1336
specificPxl = (f >= 0 &&
1337
(str = fieldValues[6]->value[f].string) &&
1339
f = currentFont.value_index[7];
1340
specificPt = (f >= 0 &&
1341
(str = fieldValues[7]->value[f].string) &&
1343
f = currentFont.value_index[9];
1344
specificY = (f >= 0 &&
1345
(str = fieldValues[9]->value[f].string) &&
1347
if (specificPt && specificY)
1348
DisableScaled(6, 7, 9);
1349
if (specificPxl && specificY)
1350
DisableScaled(7, 6, 9);
1351
if (specificPxl && specificPt)
1352
DisableScaled(9, 6, 7);
1355
for (f = numFonts, b = font_in_set; f; f--, b++) {
1358
if (count != matchingFontCount) {
1359
Boolean *sp = fontInSet;
1360
FieldValueList *fieldValue = fieldValues[field];
1361
for (b = font_in_set, f = 0; f < numFonts; f++, b++, sp++) {
1363
int i = fonts[f].value_index[field];
1364
FieldValue *val = &fieldValue->value[i];
1366
XtSetSensitive(val->menu_item, True);
1367
if (++count == matchingFontCount) break;
1371
XtFree((char *)font_in_set);
1372
if (enabledMenuIndex < field)
1373
EnableMenu((XtPointer)(long)field);
1377
void EnableMenu(closure)
1380
int field = (long)closure;
1381
FieldValue *val = fieldValues[field]->value;
1383
Widget *managed = NULL, *pManaged = NULL;
1384
Widget *unmanaged = NULL, *pUnmanaged = NULL;
1385
Boolean showUnselectable = fieldValues[field]->show_unselectable;
1387
for (f = fieldValues[field]->count; f; f--, val++) {
1388
if (showUnselectable) {
1389
if (val->enable != XtIsSensitive(val->menu_item))
1390
XtSetSensitive(val->menu_item, val->enable);
1393
if (val->enable != XtIsManaged(val->menu_item)) {
1395
if (managed == NULL) {
1397
XtMalloc(fieldValues[field]->count*sizeof(Widget));
1400
*pManaged++ = val->menu_item;
1403
if (unmanaged == NULL) {
1404
unmanaged = (Widget*)
1405
XtMalloc(fieldValues[field]->count*sizeof(Widget));
1406
pUnmanaged = unmanaged;
1408
*pUnmanaged++ = val->menu_item;
1413
if (pManaged != managed) {
1414
XtManageChildren(managed, pManaged - managed);
1415
XtFree((char *) managed);
1417
if (pUnmanaged != unmanaged) {
1418
XtUnmanageChildren(unmanaged, pUnmanaged - unmanaged);
1419
XtFree((char *) unmanaged);
1421
enabledMenuIndex = field;
1425
static void FlushXqueue(dpy)
1429
while (XtAppPending(appCtx)) XtAppProcessEvent(appCtx, XtIMAll);
1434
void Quit(w, closure, callData)
1436
XtPointer closure, callData;
1438
XtCloseDisplay(XtDisplay(w));
1439
if (AppRes.print_on_quit) printf( "%s", currentFontNameString );
1444
Boolean ConvertSelection(w, selection, target, type, value, length, format)
1446
Atom *selection, *target, *type;
1448
unsigned long *length;
1451
/* XmuConvertStandardSelection will use the second parameter only when
1452
* converting to the target TIMESTAMP. However, it will never be
1453
* called upon to perform this conversion, because Xt will handle it
1454
* internally. CurrentTime will never be used.
1456
if (XmuConvertStandardSelection(w, CurrentTime, selection, target, type,
1457
(XPointer *) value, length, format))
1460
if (*target == XA_STRING) {
1462
*value = currentFontNameString;
1463
*length = strlen(*value);
1472
static AtomPtr _XA_PRIMARY_FONT = NULL;
1473
#define XA_PRIMARY_FONT XmuInternAtom(XtDisplay(w),_XA_PRIMARY_FONT)
1476
void LoseSelection(w, selection)
1481
XtSetArg( args[0], XtNstate, False );
1482
XtSetValues( w, args, ONE );
1483
if (*selection == XA_PRIMARY_FONT) {
1484
XtSetSensitive(currentFontName, False);
1490
void DoneSelection(w, selection, target)
1492
Atom *selection, *target;
1499
void OwnSelection(w, closure, callData)
1501
XtPointer closure, callData;
1503
Time time = XtLastTimestampProcessed(XtDisplay(w));
1504
Boolean primary = (Boolean) (long) closure;
1505
Boolean own = (Boolean) (long) callData;
1507
if (_XA_PRIMARY_FONT == NULL)
1508
_XA_PRIMARY_FONT = XmuMakeAtom("PRIMARY_FONT");
1511
XtOwnSelection( w, XA_PRIMARY_FONT, time,
1512
ConvertSelection, LoseSelection, DoneSelection );
1514
XtOwnSelection( w, XA_PRIMARY, time,
1515
ConvertSelection, LoseSelection, DoneSelection );
1516
if (!XtIsSensitive(currentFontName)) {
1517
XtSetSensitive(currentFontName, True);
1521
XtDisownSelection(w, XA_PRIMARY_FONT, time);
1523
XtDisownSelection(w, XA_PRIMARY, time);
1524
XtSetSensitive(currentFontName, False);