diff options
author | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 16:49:22 +0000 |
---|---|---|
committer | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 16:49:22 +0000 |
commit | ec7cff5eb04007f30e0fa732bca8a55882f5482f (patch) | |
tree | 5192e7a29d7555162fffc2a4428894a8d5ac206f /xfontsel.c |
Initial revisionXORG-STABLE
Diffstat (limited to 'xfontsel.c')
-rw-r--r-- | xfontsel.c | 1532 |
1 files changed, 1532 insertions, 0 deletions
diff --git a/xfontsel.c b/xfontsel.c new file mode 100644 index 0000000..12c437d --- /dev/null +++ b/xfontsel.c @@ -0,0 +1,1532 @@ +/* $XConsortium: xfontsel.c,v 1.35 94/04/17 20:43:41 rws Exp $ */ +/* + +Copyright (c) 1985-1989 X Consortium + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the X Consortium. + +Author: Ralph R. Swick, DEC/MIT Project Athena + one weekend in November, 1989 +Modified: Mark Leisher <mleisher@crl.nmsu.edu> to deal with UCS sample text. +*/ +/* $XFree86: xc/programs/xfontsel/xfontsel.c,v 1.7 2001/10/28 03:34:32 tsi Exp $ */ + +#include <stdio.h> +#include <stdlib.h> +#include <X11/Intrinsic.h> +#include <X11/StringDefs.h> +#include <X11/Xatom.h> +#include <X11/Xaw/AsciiText.h> +#include <X11/Xaw/Box.h> +#include <X11/Xaw/Cardinals.h> +#include <X11/Xaw/Command.h> +#include <X11/Xaw/Form.h> +#include <X11/Xaw/MenuButton.h> +#include <X11/Xaw/Paned.h> +#include <X11/Xaw/SimpleMenu.h> +#include <X11/Xaw/SmeBSB.h> +#include <X11/Xaw/Toggle.h> +#include <X11/Xaw/Viewport.h> +#include <X11/Xmu/Atoms.h> +#include <X11/Xmu/StdSel.h> +#include <X11/Xfuncs.h> +#include "ULabel.h" + +#define MIN_APP_DEFAULTS_VERSION 1 +#define FIELD_COUNT 14 +#define DELIM '-' + +/* number of font names to parse in each background iteration */ +#ifndef PARSE_QUANTUM +#define PARSE_QUANTUM 25 +#endif + +#define NZ NULL,ZERO +#define BACKGROUND 10 + +void GetFontNames(); +Boolean Matches(); +Boolean DoWorkPiece(); +void Quit(); +void OwnSelection(); +void SelectField(); +void ParseFontNames(); +void SortFields(); +void FixScalables(); +void MakeFieldMenu(); +void SelectValue(); +void AnyValue(); +void EnableOtherValues(); +void EnableMenu(); +void SetCurrentFont(); +void QuitAction(); + +XtActionsRec xfontsel_actions[] = { + {"Quit", QuitAction} +}; + +Atom wm_delete_window; + +Boolean IsXLFDFontName(); + +typedef void (*XtProc)(); + +static struct _appRes { + int app_defaults_version; + Cursor cursor; + String pattern; + String pixelSizeList; + String pointSizeList; + Boolean print_on_quit; + String sample_text; + String sample_text16; + String sample_textUCS; + Boolean scaled_fonts; +} AppRes; + +#define DEFAULTPATTERN "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" + +static XtResource resources[] = { + { "cursor", "Cursor", XtRCursor, sizeof(Cursor), + XtOffsetOf( struct _appRes, cursor ), + XtRImmediate, NULL }, + { "pattern", "Pattern", XtRString, sizeof(String), + XtOffsetOf( struct _appRes, pattern ), + XtRString, (XtPointer)DEFAULTPATTERN }, + { "pixelSizeList", "PixelSizeList", XtRString, sizeof(String), + XtOffsetOf( struct _appRes, pixelSizeList ), + XtRString, (XtPointer)"" }, + { "pointSizeList", "PointSizeList", XtRString, sizeof(String), + XtOffsetOf( struct _appRes, pointSizeList ), + XtRString, (XtPointer)"" }, + { "printOnQuit", "PrintOnQuit", XtRBoolean, sizeof(Boolean), + XtOffsetOf( struct _appRes, print_on_quit ), + XtRImmediate, (XtPointer)False }, + { "appDefaultsVersion", "AppDefaultsVersion", XtRInt, sizeof(int), + XtOffsetOf( struct _appRes, app_defaults_version ), + XtRImmediate, (XtPointer)0 }, + { "sampleText", "Text", XtRString, sizeof(String), + XtOffsetOf( struct _appRes, sample_text ), + XtRString, (XtPointer)"" }, + { "sampleText16", "Text16", XtRString, sizeof(String), + XtOffsetOf( struct _appRes, sample_text16 ), + XtRString, (XtPointer)"" }, + { "sampleTextUCS", "TextUCS", XtRString, sizeof(String), + XtOffsetOf( struct _appRes, sample_textUCS ), + XtRString, (XtPointer)"" }, + { "scaledFonts", "ScaledFonts", XtRBoolean, sizeof(Boolean), + XtOffsetOf( struct _appRes, scaled_fonts ), + XtRImmediate, (XtPointer)False }, +}; + +static XrmOptionDescRec options[] = { +{"-pattern", "pattern", XrmoptionSepArg, NULL}, +{"-print", "printOnQuit", XrmoptionNoArg, "True"}, +{"-sample", "sampleText", XrmoptionSepArg, NULL}, +{"-sample16", "sampleText16", XrmoptionSepArg, NULL}, +{"-sampleUCS", "sampleTextUCS",XrmoptionSepArg, NULL}, +{"-scaled", "scaledFonts", XrmoptionNoArg, "True"}, +}; + +static void Syntax(call) + char *call; +{ + fprintf (stderr, "usage: %s [-options ...] -fn font\n\n", call); + fprintf (stderr, "where options include:\n"); + fprintf (stderr, + " -display dpy X server to contact\n"); + fprintf (stderr, + " -geometry geom size and location of window\n"); + fprintf (stderr, + " -pattern fontspec font name pattern to match against\n"); + fprintf (stderr, + " -print print selected font name on exit\n"); + fprintf (stderr, + " -sample string sample text to use for 1-byte fonts\n"); + fprintf (stderr, + " -sample16 string sample text to use for 2-byte fonts\n"); + fprintf (stderr, + " -sampleUCS string sample text to use for ISO10646 fonts\n"); + fprintf (stderr, + " -scaled use scaled instances of fonts\n"); + fprintf (stderr, "\n"); + exit (1); +} + + +typedef struct FieldValue FieldValue; +struct FieldValue { + int field; + String string; + Widget menu_item; + int count; /* of fonts */ + int allocated; + int *font; + Boolean enable; +}; + + +typedef struct FieldValueList FieldValueList; +struct FieldValueList { + int count; /* of values */ + int allocated; + Boolean show_unselectable; + FieldValue value[1]; /* really [allocated] */ +}; + + +typedef struct FontValues FontValues; +struct FontValues { + int value_index[FIELD_COUNT]; +}; + + +typedef struct FieldMenuRec FieldMenuRec; +struct FieldMenuRec { + int field; + Widget button; +}; + + +typedef struct Choice Choice; +struct Choice { + Choice *prev; + FieldValue *value; +}; + + +static XtResource menuResources[] = { + { "showUnselectable", "ShowUnselectable", XtRBoolean, sizeof(Boolean), + XtOffsetOf( FieldValueList, show_unselectable ), + XtRImmediate, (XtPointer)True }, +}; + + +typedef enum {ValidateCurrentField, SkipCurrentField} ValidateAction; + +static void EnableAllItems(int field); +static void EnableRemainingItems(ValidateAction current_field_action); +static void FlushXqueue(Display *dpy); +static void MarkInvalidFonts(Boolean *set, FieldValue *val); +static void ScheduleWork(XtProc proc, XtPointer closure, int priority); +static void SetCurrentFontCount(void); +static void SetNoFonts(void); +static void SetParsingFontCount(int count); + +XtAppContext appCtx; +int numFonts; +int numBadFonts; +FontValues *fonts; +int *scaledFonts; +int numScaledFonts; +FieldValueList *fieldValues[FIELD_COUNT]; +FontValues currentFont; +int matchingFontCount; +static Boolean anyDisabled = False; +Widget ownButton; +Widget fieldBox; +Widget countLabel; +Widget currentFontName; +String currentFontNameString; +int currentFontNameSize; +Widget sampleText; +int textEncoding = -1; +static XFontStruct *sampleFont = NULL; +Boolean *fontInSet; +static Choice *choiceList = NULL; +int enabledMenuIndex; +static Boolean patternFieldSpecified[FIELD_COUNT]; /* = 0 */ + +int +main(argc, argv) + int argc; + char **argv; +{ + Widget topLevel, pane; + + XtSetLanguageProc(NULL, (XtLanguageProc) NULL, NULL); + + topLevel = XtAppInitialize(&appCtx, "XFontSel", options, XtNumber(options), + &argc, argv, NULL, NULL, 0); + + if (argc != 1) Syntax(argv[0]); + + XtAppAddActions(appCtx, xfontsel_actions, XtNumber(xfontsel_actions)); + XtOverrideTranslations + (topLevel, XtParseTranslationTable ("<Message>WM_PROTOCOLS: Quit()")); + + XtGetApplicationResources( topLevel, (XtPointer)&AppRes, + resources, XtNumber(resources), NZ ); + if (AppRes.app_defaults_version < MIN_APP_DEFAULTS_VERSION) { + XrmDatabase rdb = XtDatabase(XtDisplay(topLevel)); + XtWarning( "app-defaults file not properly installed." ); + XrmPutLineResource( &rdb, +"*sampleText*UCSLabel:XFontSel app-defaults file not properly installed;\\n\ +see 'xfontsel' manual page." + ); + } + + ScheduleWork(GetFontNames, (XtPointer)XtDisplay(topLevel), 0); + + pane = XtCreateManagedWidget("pane",panedWidgetClass,topLevel,NZ); + { + Widget commandBox, /* fieldBox, currentFontName,*/ viewPort; + + commandBox = XtCreateManagedWidget("commandBox",formWidgetClass,pane,NZ); + { + Widget quitButton /*, ownButton , countLabel*/; + + quitButton = + XtCreateManagedWidget("quitButton",commandWidgetClass,commandBox,NZ); + + ownButton = + XtCreateManagedWidget("ownButton",toggleWidgetClass,commandBox,NZ); + + countLabel = + XtCreateManagedWidget("countLabel",labelWidgetClass,commandBox,NZ); + + XtAddCallback(quitButton, XtNcallback, Quit, NULL); + XtAddCallback(ownButton,XtNcallback,OwnSelection,(XtPointer)True); + } + + fieldBox = XtCreateManagedWidget("fieldBox", boxWidgetClass, pane, NZ); + { + Widget /*dash,*/ field /*[FIELD_COUNT]*/; + int f; + + for (f = 0; f < FIELD_COUNT; f++) { + char name[10]; + FieldMenuRec *makeRec = XtNew(FieldMenuRec); + sprintf( name, "field%d", f ); + XtCreateManagedWidget("dash",labelWidgetClass,fieldBox,NZ); + field = XtCreateManagedWidget(name, menuButtonWidgetClass, + fieldBox, NZ); + XtAddCallback(field, XtNcallback, SelectField, + (XtPointer)(long)f); + makeRec->field = f; + makeRec->button = field; + ScheduleWork(MakeFieldMenu, (XtPointer)makeRec, 2); + ScheduleWork(XtFree, (XtPointer)makeRec, 2); + } + } + + /* currentFontName = */ + { + Arg args[1]; + currentFontNameSize = strlen(AppRes.pattern); + if (currentFontNameSize < 128) currentFontNameSize = 128; + currentFontNameString = (String)XtMalloc(currentFontNameSize); + strcpy(currentFontNameString, AppRes.pattern); + XtSetArg(args[0], XtNlabel, currentFontNameString); + currentFontName = + XtCreateManagedWidget("fontName",labelWidgetClass,pane,args,ONE); + } + + viewPort = + XtCreateManagedWidget("viewPort",viewportWidgetClass,pane,NZ); + { +#ifdef USE_TEXT_WIDGET + Widget text = + XtCreateManagedWidget("sampleText",asciiTextWidgetClass,viewPort,NZ); + Arg args[1]; + XtSetArg( args[0], XtNtextSink, &sampleText ); + XtGetValues( text, args, ONE ); +#else + sampleText = + XtCreateManagedWidget("sampleText",ucsLabelWidgetClass,viewPort,NZ); +#endif + } + } + + XtRealizeWidget(topLevel); + XDefineCursor( XtDisplay(topLevel), XtWindow(topLevel), AppRes.cursor ); + { + int f; + for (f = 0; f < FIELD_COUNT; f++) currentFont.value_index[f] = -1; + } + wm_delete_window = XInternAtom(XtDisplay(topLevel), "WM_DELETE_WINDOW", + False); + (void) XSetWMProtocols (XtDisplay(topLevel), XtWindow(topLevel), + &wm_delete_window, 1); + XtAppMainLoop(appCtx); + + return 0; +} + + +typedef struct WorkPiece WorkPieceRec, *WorkPiece; +struct WorkPiece { + WorkPiece next; + int priority; + XtProc proc; + XtPointer closure; +}; +static WorkPiece workQueue = NULL; + + +/* + * ScheduleWork( XtProc proc, XtPointer closure, int priority ) + * + * Adds a WorkPiece to the workQueue in FIFO order by priority. + * Lower numbered priority work is completed before higher numbered + * priorities. + * + * If the workQueue was previously empty, then makes sure that + * Xt knows we have (background) work to do. + */ + +static void ScheduleWork( proc, closure, priority ) + XtProc proc; + XtPointer closure; + int priority; +{ + WorkPiece piece = XtNew(WorkPieceRec); + + piece->priority = priority; + piece->proc = proc; + piece->closure = closure; + if (workQueue == NULL) { + piece->next = NULL; + workQueue = piece; + XtAppAddWorkProc(appCtx, DoWorkPiece, NULL); + } else { + if (workQueue->priority > priority) { + piece->next = workQueue; + workQueue = piece; + } + else { + WorkPiece n; + for (n = workQueue; n->next && n->next->priority <= priority;) + n = n->next; + piece->next = n->next; + n->next = piece; + } + } +} + +/* ARGSUSED */ +Boolean DoWorkPiece(closure) + XtPointer closure; /* unused */ +{ + WorkPiece piece = workQueue; + + if (piece) { + (*piece->proc)(piece->closure); + workQueue = piece->next; + XtFree((XtPointer)piece); + if (workQueue != NULL) + return False; + } + return True; +} + + +/* + * FinishWork() + * + * Drains foreground tasks from the workQueue. + * Foreground == (priority < BACKGROUND) + */ + +void FinishWork() +{ + while (workQueue && workQueue->priority < BACKGROUND) + DoWorkPiece(NULL); +} + + +typedef struct ParseRec ParseRec; +struct ParseRec { + char **fontNames; + int num_fonts; + int start, end; + FontValues *fonts; + FieldValueList **fieldValues; +}; + + +void GetFontNames( closure ) + XtPointer closure; +{ + Display *dpy = (Display*)closure; + ParseRec *parseRec = XtNew(ParseRec); + int f, field, count; + String *fontNames; + Boolean *b; + int work_priority = 0; + + fontNames = parseRec->fontNames = + XListFonts(dpy, AppRes.pattern, 32767, &numFonts); + + fonts = (FontValues*)XtMalloc( numFonts*sizeof(FontValues) ); + fontInSet = (Boolean*)XtMalloc( numFonts*sizeof(Boolean) ); + for (f = numFonts, b = fontInSet; f; f--, b++) *b = True; + for (field = 0; field < FIELD_COUNT; field++) { + fieldValues[field] = (FieldValueList*)XtMalloc(sizeof(FieldValueList)); + fieldValues[field]->allocated = 1; + fieldValues[field]->count = 0; + } + if (numFonts == 0) { + SetNoFonts(); + return; + } + numBadFonts = 0; + parseRec->fonts = fonts; + parseRec->num_fonts = count = matchingFontCount = numFonts; + parseRec->fieldValues = fieldValues; + parseRec->start = 0; + /* this is bogus; the task should be responsible for quantizing...*/ + while (count > PARSE_QUANTUM) { + ParseRec *prevRec = parseRec; + parseRec->end = parseRec->start + PARSE_QUANTUM; + ScheduleWork(ParseFontNames, (XtPointer)parseRec, work_priority); + ScheduleWork(XtFree, (XtPointer)parseRec, work_priority); + parseRec = XtNew(ParseRec); + *parseRec = *prevRec; + parseRec->start += PARSE_QUANTUM; + parseRec->fonts += PARSE_QUANTUM; + parseRec->fontNames += PARSE_QUANTUM; + count -= PARSE_QUANTUM; + work_priority = 1; + } + parseRec->end = numFonts; + ScheduleWork(ParseFontNames,(XtPointer)parseRec,work_priority); + ScheduleWork((XtProc)XFreeFontNames,(XtPointer)fontNames,work_priority); + ScheduleWork(XtFree, (XtPointer)parseRec, work_priority); + if (AppRes.scaled_fonts) + ScheduleWork(FixScalables,(XtPointer)0,work_priority); + ScheduleWork(SortFields,(XtPointer)0,work_priority); + SetParsingFontCount(matchingFontCount); + if (strcmp(AppRes.pattern, DEFAULTPATTERN)) { + int maxField, f; + for (f = 0; f < numFonts && !IsXLFDFontName(fontNames[f]); f++); + if (f != numFonts) { + if (Matches(AppRes.pattern, fontNames[f], + patternFieldSpecified, &maxField)) { + for (f = 0; f <= maxField; f++) { + if (patternFieldSpecified[f]) + currentFont.value_index[f] = 0; + } + } + else + XtAppWarning( appCtx, + "internal error; pattern didn't match first font" ); + } + else { + SetNoFonts(); + return; + } + } + ScheduleWork(SetCurrentFont, NULL, 1); +} + + +void ParseFontNames( closure ) + XtPointer closure; +{ + ParseRec *parseRec = (ParseRec*)closure; + char **fontNames = parseRec->fontNames; + int num_fonts = parseRec->end; + FieldValueList **fieldValues = parseRec->fieldValues; + FontValues *fontValues = parseRec->fonts - numBadFonts; + int i, font; + + for (font = parseRec->start; font < num_fonts; font++) { + char *p; + int f, len; + FieldValue *v; + + if (!IsXLFDFontName(*fontNames)) { + numFonts--; + numBadFonts++; + continue; + } + + for (f = 0, p = *fontNames++; f < FIELD_COUNT; f++) { + char *fieldP; + + if (*p) ++p; + if (*p == DELIM || *p == '\0') { + fieldP = ""; + len = 0; + } else { + fieldP = p; + while (*p && *++p != DELIM); + len = p - fieldP; + } + for (i=fieldValues[f]->count,v=fieldValues[f]->value; i;i--,v++) { + if (len == 0) { + if (v->string == NULL) break; + } + else + if (v->string && + strncmp( v->string, fieldP, len ) == 0 && + (v->string)[len] == '\0') + break; + } + if (i == 0) { + int count = fieldValues[f]->count++; + if (count == fieldValues[f]->allocated) { + int allocated = (fieldValues[f]->allocated += 10); + fieldValues[f] = (FieldValueList*) + XtRealloc( (char *) fieldValues[f], + sizeof(FieldValueList) + + (allocated-1) * sizeof(FieldValue) ); + } + v = &fieldValues[f]->value[count]; + v->field = f; + if (len == 0) + v->string = NULL; + else { + v->string = (String)XtMalloc( len+1 ); + strncpy( v->string, fieldP, len ); + v->string[len] = '\0'; + } + v->font = (int*)XtMalloc( 10*sizeof(int) ); + v->allocated = 10; + v->count = 0; + v->enable = True; + i = 1; + } + fontValues->value_index[f] = fieldValues[f]->count - i; + if ((i = v->count++) == v->allocated) { + int allocated = (v->allocated += 10); + v->font = (int*)XtRealloc( (char *) v->font, + allocated * sizeof(int) ); + } + v->font[i] = font - numBadFonts; + } + fontValues++; + } + SetParsingFontCount(numFonts - num_fonts); +} + + +/* Add the list of scalable fonts to the match-list of every value instance + * for field f. Must produce sorted order. Must deal with duplicates + * since we need to do this for resolution fields which can be nonzero in + * the scalable fonts. + */ +void AddScalables(f) + int f; +{ + int i; + int max = fieldValues[f]->count; + FieldValue *fval = fieldValues[f]->value; + + for (i = 0; i < max; i++, fval++) { + int *oofonts, *ofonts, *nfonts, *fonts; + int ocount, ncount, count; + + if (fval->string && !strcmp(fval->string, "0")) + continue; + count = numScaledFonts; + fonts = scaledFonts; + ocount = fval->count; + ncount = ocount + count; + nfonts = (int *)XtMalloc( ncount * sizeof(int) ); + oofonts = ofonts = fval->font; + fval->font = nfonts; + fval->count = ncount; + fval->allocated = ncount; + while (count && ocount) { + if (*fonts < *ofonts) { + *nfonts++ = *fonts++; + count--; + } else if (*fonts == *ofonts) { + *nfonts++ = *fonts++; + count--; + ofonts++; + ocount--; + fval->count--; + } else { + *nfonts++ = *ofonts++; + ocount--; + } + } + while (ocount) { + *nfonts++ = *ofonts++; + ocount--; + } + while (count) { + *nfonts++ = *fonts++; + count--; + } + XtFree((char *)oofonts); + } +} + + +/* Merge in specific scaled sizes (specified in a comma-separated string) + * for field f. Weed out duplicates. The set of matching fonts is just + * the set of scalable fonts. + */ +void NewScalables(f, slist) + int f; + char *slist; +{ + char endc = 1; + char *str; + int i, count; + FieldValue *v; + + while (endc) { + while (*slist == ' ' || *slist == ',') + slist++; + if (!*slist) + break; + str = slist; + while ((endc = *slist) && endc != ' ' && endc != ',') + slist++; + *slist++ = '\0'; + for (i=fieldValues[f]->count,v=fieldValues[f]->value; --i >= 0; v++) { + if (v->string && !strcmp(v->string, str)) + break; + } + if (i >= 0) + continue; + count = fieldValues[f]->count++; + if (count == fieldValues[f]->allocated) { + int allocated = (fieldValues[f]->allocated += 10); + fieldValues[f] = (FieldValueList*) + XtRealloc( (char *) fieldValues[f], + sizeof(FieldValueList) + + (allocated-1) * sizeof(FieldValue) ); + } + v = &fieldValues[f]->value[count]; + v->field = f; + v->string = str; + v->count = numScaledFonts; + v->font = scaledFonts; + v->allocated = 0; + v->enable = True; + } +} + + +/* Find all scalable fonts, defined as the set matching "0" in the pixel + * size field (field 6). Augment the match-lists for all other fields + * that are scalable. Add in new scalable pixel and point sizes given + * in resources. + */ +/*ARGSUSED*/ +void FixScalables( closure ) + XtPointer closure; +{ + int i; + FieldValue *fval = fieldValues[6]->value; + + for (i = fieldValues[6]->count; --i >= 0; fval++) { + if (fval->string && !strcmp(fval->string, "0")) { + scaledFonts = fval->font; + numScaledFonts = fval->count; + AddScalables(6); + NewScalables(6, AppRes.pixelSizeList); + AddScalables(7); + NewScalables(7, AppRes.pointSizeList); + AddScalables(8); + AddScalables(9); + AddScalables(11); + break; + } + } +} + + +/* A verbatim copy from xc/lib/font/fontfile/fontdir.c */ + +/* + * Compare two strings just like strcmp, but preserve decimal integer + * sorting order, i.e. "2" < "10" or "iso8859-2" < "iso8859-10" < + * "iso10646-1". Strings are sorted as if sequences of digits were + * prefixed by a length indicator (i.e., does not ignore leading zeroes). + * + * Markus Kuhn <Markus.Kuhn@cl.cam.ac.uk> + */ +#define Xisdigit(c) ('\060' <= (c) && (c) <= '\071') + +static int strcmpn(const char *s1, const char *s2) +{ + int digits, predigits = 0; + const char *ss1, *ss2; + + while (1) { + if (*s1 == 0 && *s2 == 0) + return 0; + digits = Xisdigit(*s1) && Xisdigit(*s2); + if (digits && !predigits) { + ss1 = s1; + ss2 = s2; + while (Xisdigit(*ss1) && Xisdigit(*ss2)) + ss1++, ss2++; + if (!Xisdigit(*ss1) && Xisdigit(*ss2)) + return -1; + if (Xisdigit(*ss1) && !Xisdigit(*ss2)) + return 1; + } + if ((unsigned char)*s1 < (unsigned char)*s2) + return -1; + if ((unsigned char)*s1 > (unsigned char)*s2) + return 1; + predigits = digits; + s1++, s2++; + } +} + + +/* Order is *, (nil), rest */ +int AlphabeticSort(fval1, fval2) + FieldValue *fval1, *fval2; +{ + if (fval1->string && !strcmp(fval1->string, "*")) + return -1; + if (fval2->string && !strcmp(fval2->string, "*")) + return 1; + if (!fval1->string) + return -1; + if (!fval2->string) + return 1; + return strcmpn(fval1->string, fval2->string); +} + + +/* Order is *, (nil), rest */ +int NumericSort(fval1, fval2) + FieldValue *fval1, *fval2; +{ + if (fval1->string && !strcmp(fval1->string, "*")) + return -1; + if (fval2->string && !strcmp(fval2->string, "*")) + return 1; + if (!fval1->string) + return -1; + if (!fval2->string) + return 1; + return atoi(fval1->string) - atoi(fval2->string); +} + + +/* Resort each field, to get reasonable menus. Sort alphabetically or + * numerically, depending on the field. Since the fonts have indexes + * into the fields, we need to deal with updating those indexes after the + * sort. + */ +/*ARGSUSED*/ +void SortFields( closure ) + XtPointer closure; +{ + int i, j, count; + FieldValue *vals; + int *indexes; + int *idx; + + for (i = 0; i < FIELD_COUNT; i++) { + count = fieldValues[i]->count; + vals = fieldValues[i]->value; + indexes = (int *)XtMalloc(count * sizeof(int)); + /* temporarily use the field component, will restore it below */ + for (j = 0; j < count; j++) + vals[j].field = j; + switch (i) { + case 6: case 7: case 8: case 9: case 11: + qsort((char *)vals, count, sizeof(FieldValue), NumericSort); + break; + default: + qsort((char *)vals, count, sizeof(FieldValue), AlphabeticSort); + break; + } + for (j = 0; j < count; j++) { + indexes[vals[j].field] = j; + vals[j].field = i; + } + for (j = 0; j < numFonts; j++) { + idx = &fonts[j].value_index[i]; + if (*idx >= 0) + *idx = indexes[*idx]; + } + XtFree((char *)indexes); + } +} + + +Boolean IsXLFDFontName(fontName) + String fontName; +{ + int f; + for (f = 0; *fontName;) if (*fontName++ == DELIM) f++; + return (f == FIELD_COUNT); +} + + +void MakeFieldMenu(closure) + XtPointer closure; +{ + FieldMenuRec *makeRec = (FieldMenuRec*)closure; + Widget menu; + FieldValueList *values = fieldValues[makeRec->field]; + FieldValue *val = values->value; + int i; + Arg args[1]; + register Widget item; + + if (numFonts) + menu = + XtCreatePopupShell("menu",simpleMenuWidgetClass,makeRec->button,NZ); + else { + SetNoFonts(); + return; + } + XtGetSubresources(menu, (XtPointer) values, "options", "Options", + menuResources, XtNumber(menuResources), NZ); + XtAddCallback(menu, XtNpopupCallback, EnableOtherValues, + (XtPointer)(long)makeRec->field ); + + if (!patternFieldSpecified[val->field]) { + XtSetArg( args[0], XtNlabel, "*" ); + item = XtCreateManagedWidget("any",smeBSBObjectClass,menu,args,ONE); + XtAddCallback(item, XtNcallback, AnyValue, (XtPointer)(long)val->field); + } + + for (i = values->count; i; i--, val++) { + XtSetArg( args[0], XtNlabel, val->string ? val->string : "(nil)" ); + item = + XtCreateManagedWidget(val->string ? val->string : "nil", + smeBSBObjectClass, menu, args, ONE); + XtAddCallback(item, XtNcallback, SelectValue, (XtPointer)val); + val->menu_item = item; + } +} + + +static void SetNoFonts(void) +{ + matchingFontCount = 0; + SetCurrentFontCount(); + XtSetSensitive(fieldBox, False); + XtSetSensitive(ownButton, False); + if (AppRes.app_defaults_version >= MIN_APP_DEFAULTS_VERSION) { +#ifdef USE_TEXT_WIDGET + XtUnmapWidget(XtParent(sampleText)); +#else + XtUnmapWidget(sampleText); +#endif + } +} + + +Boolean Matches(pattern, fontName, fields, maxField) + register String pattern, fontName; + Boolean fields[/*FIELD_COUNT*/]; + int *maxField; +{ + register int field = (*fontName == DELIM) ? -1 : 0; + register Boolean marked_this_field = False; + + while (*pattern) { + if (*pattern == *fontName || *pattern == '?') { + pattern++; + if (*fontName++ == DELIM) { + field++; + marked_this_field = False; + } + else if (!marked_this_field) + fields[field] = marked_this_field = True; + continue; + } + if (*pattern == '*') { + if (*++pattern == '\0') { + *maxField = field; + return True; + } + while (*fontName) { + Boolean field_bits[FIELD_COUNT]; + int max_field; + if (*fontName == DELIM) field++; + bzero( field_bits, sizeof(field_bits) ); + if (Matches(pattern, fontName++, field_bits, &max_field)) { + int f; + *maxField = field + max_field; + for (f = 0; f <= max_field; field++, f++) + fields[field] = field_bits[f]; + return True; + } + } + return False; + } + else /* (*pattern != '*') */ + return False; + } + if (*fontName) + return False; + + *maxField = field; + return True; +} + + +/* ARGSUSED */ +void SelectValue(w, closure, callData) + Widget w; + XtPointer closure, callData; +{ + FieldValue *val = (FieldValue*)closure; +#ifdef LOG_CHOICES + Choice *choice = XtNew(Choice); +#else + static Choice pChoice; + Choice *choice = &pChoice; +#endif + +#ifdef notdef + Widget button = XtParent(XtParent(w)); + Arg args[1]; + + XtSetArg(args[0], XtNlabel, val->string); + XtSetValues( button, args, ONE ); +#endif + + currentFont.value_index[val->field] = val - fieldValues[val->field]->value; + + choice->prev = choiceList; + choice->value = val; + choiceList = choice; + + SetCurrentFont(NULL); + EnableRemainingItems(SkipCurrentField); +} + + +/* ARGSUSED */ +void AnyValue(w, closure, callData) + Widget w; + XtPointer closure, callData; +{ + int field = (long)closure; + currentFont.value_index[field] = -1; + SetCurrentFont(NULL); + EnableAllItems(field); + EnableRemainingItems(ValidateCurrentField); +} + + +static void SetCurrentFontCount(void) +{ + char label[80]; + Arg args[1]; + if (matchingFontCount == 1) + strcpy( label, "1 name matches" ); + else if (matchingFontCount) + sprintf( label, "%d names match", matchingFontCount ); + else + strcpy( label, "no names match" ); + XtSetArg( args[0], XtNlabel, label ); + XtSetValues( countLabel, args, ONE ); +} + + +static void SetParsingFontCount(int count) +{ + char label[80]; + Arg args[1]; + if (count == 1) + strcpy( label, "1 name to parse" ); + else + sprintf( label, "%d names to parse", count ); + XtSetArg( args[0], XtNlabel, label ); + XtSetValues( countLabel, args, ONE ); + FlushXqueue(XtDisplay(countLabel)); +} + +/* ARGSUSED */ +static Boolean IsISO10646(dpy, font) + Display *dpy; + XFontStruct *font; +{ + Boolean ok; + int i; + char *regname; + Atom registry; + XFontProp *xfp; + + ok = False; + registry = XInternAtom(dpy, "CHARSET_REGISTRY", False); + + for (i = 0, xfp = font->properties; + ok == False && i < font->n_properties; xfp++, i++) { + if (xfp->name == registry) { + regname = XGetAtomName(dpy, (Atom) xfp->card32); + if (strcmp(regname, "ISO10646") == 0 || + strcmp(regname, "iso10646") == 0) + ok = True; + XFree(regname); + } + } + return ok; +} + +/* ARGSUSED */ +void SetCurrentFont(closure) + XtPointer closure; /* unused */ +{ + int f; + Boolean *b; + + if (numFonts == 0) { + SetNoFonts(); + return; + } + for (f = numFonts, b = fontInSet; f; f--, b++) *b = True; + + { + int bytesLeft = currentFontNameSize; + int pos = 0; + + for (f = 0; f < FIELD_COUNT; f++) { + int len, i; + String str; + + currentFontNameString[pos++] = DELIM; + if ((i = currentFont.value_index[f]) != -1) { + FieldValue *val = &fieldValues[f]->value[i]; + if ((str = val->string)) + len = strlen(str); + else { + str = ""; + len = 0; + } + MarkInvalidFonts(fontInSet, val); + } else { + str = "*"; + len = 1; + } + if (len+1 > --bytesLeft) { + currentFontNameString = (String) + XtRealloc(currentFontNameString, currentFontNameSize+=128); + bytesLeft += 128; + } + strcpy( ¤tFontNameString[pos], str ); + pos += len; + bytesLeft -= len; + } + } + { + Arg args[1]; + XtSetArg( args[0], XtNlabel, currentFontNameString ); + XtSetValues( currentFontName, args, ONE ); + } + matchingFontCount = 0; + for (f = numFonts, b = fontInSet; f; f--, b++) { + if (*b) matchingFontCount++; + } + + SetCurrentFontCount(); + + { +#ifdef USE_TEXT_WIDGET + Widget mapWidget = XtParent(sampleText); +#else + Widget mapWidget = sampleText; +#endif + Display *dpy = XtDisplay(mapWidget); + XFontStruct *font = XLoadQueryFont(dpy, currentFontNameString); + String sample_text; + if (font == NULL) + XtUnmapWidget(mapWidget); + else { + int nargs = 1; + Arg args[3]; + int encoding; + if (font->min_byte1 || font->max_byte1) { + if (IsISO10646(dpy, font) == True) { + encoding = XawTextEncodingUCS; + sample_text = AppRes.sample_textUCS; + } else { + encoding = XawTextEncodingChar2b; + sample_text = AppRes.sample_text16; + } + } else { + encoding = XawTextEncoding8bit; + sample_text = AppRes.sample_text; + } + XtSetArg( args[0], XtNfont, font ); + if (encoding != textEncoding) { + XtSetArg(args[1], XtNencoding, encoding); + XtSetArg(args[2], XtNlabel, sample_text); + textEncoding = encoding; + nargs = 3; + } + XtSetValues( sampleText, args, nargs ); + XtMapWidget(mapWidget); + if (sampleFont) XFreeFont( dpy, sampleFont ); + sampleFont = font; + OwnSelection( sampleText, (XtPointer)False, (XtPointer)True ); + } + FlushXqueue(dpy); + } +} + + +static void MarkInvalidFonts( set, val ) + Boolean *set; + FieldValue *val; +{ + int fi = 0, vi; + int *fp = val->font; + for (vi = val->count; vi; vi--, fp++) { + while (fi < *fp) { + set[fi] = False; + fi++; + } + fi++; + } + while (fi < numFonts) { + set[fi] = False; + fi++; + } +} + + +static void EnableRemainingItems(current_field_action) + ValidateAction current_field_action; +{ + if (matchingFontCount == 0 || matchingFontCount == numFonts) { + if (anyDisabled) { + int field; + for (field = 0; field < FIELD_COUNT; field++) { + EnableAllItems(field); + } + anyDisabled = False; + } + } + else { + int field; + for (field = 0; field < FIELD_COUNT; field++) { + FieldValue *value = fieldValues[field]->value; + int count; + if (current_field_action == SkipCurrentField && + field == choiceList->value->field) + continue; + for (count = fieldValues[field]->count; count; count--, value++) { + int *fp = value->font; + int fontCount; + for (fontCount = value->count; fontCount; fontCount--, fp++) { + if (fontInSet[*fp]) { + value->enable = True; + goto NextValue; + } + } + value->enable = False; + NextValue:; + } + } + anyDisabled = True; + } + enabledMenuIndex = -1; + { + int f; + for (f = 0; f < FIELD_COUNT; f++) + ScheduleWork(EnableMenu, (XtPointer)(long)f, BACKGROUND); + } +} + + +static void EnableAllItems(int field) +{ + FieldValue *value = fieldValues[field]->value; + int count; + for (count = fieldValues[field]->count; count; count--, value++) { + value->enable = True; + } +} + + +/* ARGSUSED */ +void SelectField(w, closure, callData) + Widget w; + XtPointer closure, callData; +{ + int field = (long)closure; + FieldValue *values = fieldValues[field]->value; + int count = fieldValues[field]->count; + printf( "field %d:\n", field ); + while (count--) { + printf( " %s: %d fonts\n", values->string, values->count ); + values++; + } + printf( "\n" ); +} + + +/* When 2 out of 3 y-related scalable fields are set, we need to restrict + * the third set to only match on exact matches, that is, ignore the + * matching to scalable fonts. Because choosing a random third value + * will almost always produce an illegal font name, and it isn't worth + * trying to compute which choices might be legal to the font scaler. + */ +void DisableScaled(f, f1, f2) + int f, f1, f2; +{ + int i, j; + FieldValue *v; + int *font; + + for (i = fieldValues[f]->count, v = fieldValues[f]->value; --i >= 0; v++) { + if (!v->enable || !v->string || !strcmp(v->string, "0")) + continue; + for (j = v->count, font = v->font; --j >= 0; font++) { + if (fontInSet[*font] && + fonts[*font].value_index[f1] == currentFont.value_index[f1] && + fonts[*font].value_index[f2] == currentFont.value_index[f2]) + break; + } + if (j < 0) { + v->enable = False; + XtSetSensitive(v->menu_item, False); + } + } +} + +/* ARGSUSED */ +void EnableOtherValues(w, closure, callData) + Widget w; + XtPointer closure, callData; +{ + int field = (long)closure; + Boolean *font_in_set = (Boolean*)XtMalloc(numFonts*sizeof(Boolean)); + Boolean *b; + int f, count; + + FinishWork(); + for (f = numFonts, b = font_in_set; f; f--, b++) *b = True; + for (f = 0; f < FIELD_COUNT; f++) { + int i; + if (f != field && (i = currentFont.value_index[f]) != -1) { + MarkInvalidFonts( font_in_set, &fieldValues[f]->value[i] ); + } + } + if (scaledFonts) + { + /* Check for 2 out of 3 scalable y fields being set */ + char *str; + Bool specificPxl, specificPt, specificY; + + f = currentFont.value_index[6]; + specificPxl = (f >= 0 && + (str = fieldValues[6]->value[f].string) && + strcmp(str, "0")); + f = currentFont.value_index[7]; + specificPt = (f >= 0 && + (str = fieldValues[7]->value[f].string) && + strcmp(str, "0")); + f = currentFont.value_index[9]; + specificY = (f >= 0 && + (str = fieldValues[9]->value[f].string) && + strcmp(str, "0")); + if (specificPt && specificY) + DisableScaled(6, 7, 9); + if (specificPxl && specificY) + DisableScaled(7, 6, 9); + if (specificPxl && specificPt) + DisableScaled(9, 6, 7); + } + count = 0; + for (f = numFonts, b = font_in_set; f; f--, b++) { + if (*b) count++; + } + if (count != matchingFontCount) { + Boolean *sp = fontInSet; + FieldValueList *fieldValue = fieldValues[field]; + for (b = font_in_set, f = 0; f < numFonts; f++, b++, sp++) { + if (*b != *sp) { + int i = fonts[f].value_index[field]; + FieldValue *val = &fieldValue->value[i]; + val->enable = True; + XtSetSensitive(val->menu_item, True); + if (++count == matchingFontCount) break; + } + } + } + XtFree((char *)font_in_set); + if (enabledMenuIndex < field) + EnableMenu((XtPointer)(long)field); +} + + +void EnableMenu(closure) + XtPointer closure; +{ + int field = (long)closure; + FieldValue *val = fieldValues[field]->value; + int f; + Widget *managed = NULL, *pManaged = NULL; + Widget *unmanaged = NULL, *pUnmanaged = NULL; + Boolean showUnselectable = fieldValues[field]->show_unselectable; + + for (f = fieldValues[field]->count; f; f--, val++) { + if (showUnselectable) { + if (val->enable != XtIsSensitive(val->menu_item)) + XtSetSensitive(val->menu_item, val->enable); + } + else { + if (val->enable != XtIsManaged(val->menu_item)) { + if (val->enable) { + if (managed == NULL) { + managed = (Widget*) + XtMalloc(fieldValues[field]->count*sizeof(Widget)); + pManaged = managed; + } + *pManaged++ = val->menu_item; + } + else { + if (unmanaged == NULL) { + unmanaged = (Widget*) + XtMalloc(fieldValues[field]->count*sizeof(Widget)); + pUnmanaged = unmanaged; + } + *pUnmanaged++ = val->menu_item; + } + } + } + } + if (pManaged != managed) { + XtManageChildren(managed, pManaged - managed); + XtFree((char *) managed); + } + if (pUnmanaged != unmanaged) { + XtUnmanageChildren(unmanaged, pUnmanaged - unmanaged); + XtFree((char *) unmanaged); + } + enabledMenuIndex = field; +} + + +static void FlushXqueue(dpy) + Display *dpy; +{ + XSync(dpy, False); + while (XtAppPending(appCtx)) XtAppProcessEvent(appCtx, XtIMAll); +} + + +/* ARGSUSED */ +void Quit(w, closure, callData) + Widget w; + XtPointer closure, callData; +{ + XtCloseDisplay(XtDisplay(w)); + if (AppRes.print_on_quit) printf( "%s", currentFontNameString ); + exit(0); +} + + +Boolean ConvertSelection(w, selection, target, type, value, length, format) + Widget w; + Atom *selection, *target, *type; + XtPointer *value; + unsigned long *length; + int *format; +{ + /* XmuConvertStandardSelection will use the second parameter only when + * converting to the target TIMESTAMP. However, it will never be + * called upon to perform this conversion, because Xt will handle it + * internally. CurrentTime will never be used. + */ + if (XmuConvertStandardSelection(w, CurrentTime, selection, target, type, + (XPointer *) value, length, format)) + return True; + + if (*target == XA_STRING) { + *type = XA_STRING; + *value = currentFontNameString; + *length = strlen(*value); + *format = 8; + return True; + } + else { + return False; + } +} + +static AtomPtr _XA_PRIMARY_FONT = NULL; +#define XA_PRIMARY_FONT XmuInternAtom(XtDisplay(w),_XA_PRIMARY_FONT) + +/* ARGSUSED */ +void LoseSelection(w, selection) + Widget w; + Atom *selection; +{ + Arg args[1]; + XtSetArg( args[0], XtNstate, False ); + XtSetValues( w, args, ONE ); + if (*selection == XA_PRIMARY_FONT) { + XtSetSensitive(currentFontName, False); + } +} + + +/* ARGSUSED */ +void DoneSelection(w, selection, target) + Widget w; + Atom *selection, *target; +{ + /* do nothing */ +} + + +/* ARGSUSED */ +void OwnSelection(w, closure, callData) + Widget w; + XtPointer closure, callData; +{ + Time time = XtLastTimestampProcessed(XtDisplay(w)); + Boolean primary = (Boolean) (long) closure; + Boolean own = (Boolean) (long) callData; + + if (_XA_PRIMARY_FONT == NULL) + _XA_PRIMARY_FONT = XmuMakeAtom("PRIMARY_FONT"); + + if (own) { + XtOwnSelection( w, XA_PRIMARY_FONT, time, + ConvertSelection, LoseSelection, DoneSelection ); + if (primary) + XtOwnSelection( w, XA_PRIMARY, time, + ConvertSelection, LoseSelection, DoneSelection ); + if (!XtIsSensitive(currentFontName)) { + XtSetSensitive(currentFontName, True); + } + } + else { + XtDisownSelection(w, XA_PRIMARY_FONT, time); + if (primary) + XtDisownSelection(w, XA_PRIMARY, time); + XtSetSensitive(currentFontName, False); + } +} + +void +QuitAction () +{ + exit (0); +} |