summaryrefslogtreecommitdiff
path: root/xfontsel.c
diff options
context:
space:
mode:
Diffstat (limited to 'xfontsel.c')
-rw-r--r--xfontsel.c1532
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( &currentFontNameString[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);
+}