aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/lib/dpstk/FontSB.c
diff options
context:
space:
mode:
Diffstat (limited to 'nx-X11/lib/dpstk/FontSB.c')
-rw-r--r--nx-X11/lib/dpstk/FontSB.c4884
1 files changed, 4884 insertions, 0 deletions
diff --git a/nx-X11/lib/dpstk/FontSB.c b/nx-X11/lib/dpstk/FontSB.c
new file mode 100644
index 000000000..a529f3af0
--- /dev/null
+++ b/nx-X11/lib/dpstk/FontSB.c
@@ -0,0 +1,4884 @@
+/*
+ * FontSB.c
+ *
+ * (c) Copyright 1991-1994 Adobe Systems Incorporated.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sublicense this software
+ * and its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notices appear in all copies and that
+ * both those copyright notices and this permission notice appear in
+ * supporting documentation and that the name of Adobe Systems Incorporated
+ * not be used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. No trademark license
+ * to use the Adobe trademarks is hereby granted. If the Adobe trademark
+ * "Display PostScript"(tm) is used to describe this software, its
+ * functionality or for any other purpose, such use shall be limited to a
+ * statement that this software works in conjunction with the Display
+ * PostScript system. Proper trademark attribution to reflect Adobe's
+ * ownership of the trademark shall be given whenever any such reference to
+ * the Display PostScript system is made.
+ *
+ * ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR
+ * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
+ * ADOBE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON- INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE
+ * TO YOU OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE, STRICT LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT
+ * PROVIDE ANY TRAINING OR OTHER SUPPORT FOR THE SOFTWARE.
+ *
+ * Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems
+ * Incorporated which may be registered in certain jurisdictions
+ *
+ * Author: Adobe Systems Incorporated
+ */
+/* $XFree86$ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <math.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <Xm/Xm.h>
+
+/* There are no words to describe how I feel about having to do this */
+
+#if XmVersion > 1001
+#include <Xm/ManagerP.h>
+#else
+#include <Xm/XmP.h>
+#endif
+
+#include <Xm/Form.h>
+#include <Xm/List.h>
+#include <Xm/Label.h>
+#include <Xm/LabelG.h>
+#include <Xm/PushB.h>
+#include <Xm/PanedW.h>
+#include <Xm/PushBG.h>
+#include <Xm/SeparatoG.h>
+#include <Xm/TextF.h>
+#include <Xm/RowColumn.h>
+#include <Xm/DrawingA.h>
+#include <Xm/MessageB.h>
+#include <DPS/dpsXclient.h>
+#include "dpsXcommonI.h"
+#include <DPS/dpsXcommon.h>
+#include <DPS/dpsXshare.h>
+#include <DPS/PSres.h>
+#include <DPS/FontSBP.h>
+#include "FSBwraps.h"
+#include "FontSBI.h"
+#include <DPS/FontSample.h>
+#include <DPS/FontCreato.h>
+#include <pwd.h>
+
+#define PATH_BUF_SIZE 1024
+
+/* Turn a string into a compound string */
+#define UnsharedCS(str) XmStringCreate(str, XmSTRING_DEFAULT_CHARSET)
+#define CS(str, w) _FSBCreateSharedCS(str, w)
+static XmString CSempty;
+
+/* Create a canonical representation of a string, and as a side effect
+ make sure the string is in permanent storage. This implementation may
+ not work under all Xlibs */
+
+#define Canonical(str) XrmQuarkToString(XrmStringToQuark(str))
+
+static float defaultSizeList[] = {
+#ifndef DEFAULT_SIZE_LIST
+ 8, 10, 12, 14, 16, 18, 24, 36, 48, 72
+#else
+ DEFAULT_SIZE_LIST
+#endif /* DEFAULT_SIZE_LIST */
+};
+
+#ifndef DEFAULT_SIZE_LIST_COUNT
+#define DEFAULT_SIZE_LIST_COUNT 10
+#endif /* DEFAULT_SIZE_LIST_COUNT */
+
+#ifndef DEFAULT_SIZE
+static float default_size = 12.0;
+#else
+static float default_size = DEFAULT_SIZE
+#endif /* DEFAULT_SIZE */
+
+#ifndef DEFAULT_RESOURCE_PATH
+#define DEFAULT_RESOURCE_PATH NULL
+#endif /* DEFAULT_RESOURCE_PATH */
+
+#ifndef DEFAULT_MAX_PENDING
+#define DEFAULT_MAX_PENDING 10
+#endif /* DEFAULT_MAX_PENDING */
+
+#define Offset(field) XtOffsetOf(FontSelectionBoxRec, fsb.field)
+
+static XtResource resources[] = {
+ {XtNcontext, XtCContext, XtRDPSContext, sizeof(DPSContext),
+ Offset(context), XtRDPSContext, (XtPointer) NULL},
+ {XtNpreviewString, XtCPreviewString, XtRString, sizeof(String),
+ Offset(preview_string), XtRString, (XtPointer) NULL},
+ {XtNsizes, XtCSizes, XtRFloatList, sizeof(float*),
+ Offset(sizes), XtRImmediate, (XtPointer) defaultSizeList},
+ {XtNsizeCount, XtCSizeCount, XtRInt, sizeof(int),
+ Offset(size_count), XtRImmediate, (XtPointer) DEFAULT_SIZE_LIST_COUNT},
+ {XtNdefaultResourcePath, XtCDefaultResourcePath, XtRString, sizeof(String),
+ Offset(default_resource_path), XtRImmediate,
+ (XtPointer) DEFAULT_RESOURCE_PATH},
+ {XtNresourcePathOverride, XtCResourcePathOverride,
+ XtRString, sizeof(String),
+ Offset(resource_path_override), XtRString, (XtPointer) NULL},
+ {XtNuseFontName, XtCUseFontName, XtRBoolean, sizeof(Boolean),
+ Offset(use_font_name), XtRImmediate, (XtPointer) True},
+ {XtNfontName, XtCFontName, XtRString, sizeof(String),
+ Offset(font_name), XtRString, (XtPointer) NULL},
+ {XtNfontFamily, XtCFontFamily, XtRString, sizeof(String),
+ Offset(font_family), XtRString, (XtPointer) NULL},
+ {XtNfontFace, XtCFontFace, XtRString, sizeof(String),
+ Offset(font_face), XtRString, (XtPointer) NULL},
+ {XtNfontBlend, XtCFontBlend, XtRString, sizeof(String),
+ Offset(font_blend), XtRString, (XtPointer) NULL},
+ {XtNfontSize, XtCFontSize, XtRFloat, sizeof(String),
+ Offset(font_size), XtRFloat, (XtPointer) &default_size},
+ {XtNfontNameMultiple, XtCFontNameMultiple, XtRBoolean, sizeof(Boolean),
+ Offset(font_name_multiple), XtRImmediate, (XtPointer) False},
+ {XtNfontFamilyMultiple, XtCFontFamilyMultiple, XtRBoolean, sizeof(Boolean),
+ Offset(font_family_multiple), XtRImmediate, (XtPointer) False},
+ {XtNfontFaceMultiple, XtCFontFaceMultiple, XtRBoolean, sizeof(Boolean),
+ Offset(font_face_multiple), XtRImmediate, (XtPointer) False},
+ {XtNfontSizeMultiple, XtCFontSizeMultiple, XtRBoolean, sizeof(Boolean),
+ Offset(font_size_multiple), XtRImmediate, (XtPointer) False},
+ {XtNgetServerFonts, XtCGetServerFonts, XtRBoolean, sizeof(Boolean),
+ Offset(get_server_fonts), XtRImmediate, (XtPointer) True},
+ {XtNgetAFM, XtCGetAFM, XtRBoolean, sizeof(Boolean),
+ Offset(get_afm), XtRImmediate, (XtPointer) False},
+ {XtNautoPreview, XtCAutoPreview, XtRBoolean, sizeof(Boolean),
+ Offset(auto_preview), XtRImmediate, (XtPointer) True},
+ {XtNpreviewOnChange, XtCPreviewOnChange, XtRBoolean, sizeof(Boolean),
+ Offset(preview_on_change), XtRImmediate, (XtPointer) True},
+ {XtNundefUnusedFonts, XtCUndefUnusedFonts, XtRBoolean, sizeof(Boolean),
+ Offset(undef_unused_fonts), XtRImmediate, (XtPointer) True},
+ {XtNmaxPendingDeletes, XtCMaxPendingDeletes, XtRCardinal, sizeof(Cardinal),
+ Offset(max_pending_deletes), XtRImmediate,
+ (XtPointer) DEFAULT_MAX_PENDING},
+ {XtNmakeFontsShared, XtCMakeFontsShared, XtRBoolean, sizeof(Boolean),
+ Offset(make_fonts_shared), XtRImmediate, (XtPointer) True},
+ {XtNshowSampler, XtCShowSampler, XtRBoolean, sizeof(Boolean),
+ Offset(show_sampler), XtRImmediate, (XtPointer) False},
+ {XtNshowSamplerButton, XtCShowSamplerButton, XtRBoolean, sizeof(Boolean),
+ Offset(show_sampler_button), XtRImmediate, (XtPointer) True},
+ {XtNtypographicSort, XtCTypographicSort, XtRBoolean, sizeof(Boolean),
+ Offset(typographic_sort), XtRImmediate, (XtPointer) True},
+
+ {XtNokCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
+ Offset(ok_callback), XtRCallback, (XtPointer) NULL},
+ {XtNapplyCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
+ Offset(apply_callback), XtRCallback, (XtPointer) NULL},
+ {XtNresetCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
+ Offset(reset_callback), XtRCallback, (XtPointer) NULL},
+ {XtNcancelCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
+ Offset(cancel_callback), XtRCallback, (XtPointer) NULL},
+ {XtNvalidateCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
+ Offset(validate_callback), XtRCallback, (XtPointer) NULL},
+ {XtNfaceSelectCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
+ Offset(face_select_callback), XtRCallback, (XtPointer) NULL},
+ {XtNcreateSamplerCallback, XtCCallback, XtRCallback,
+ sizeof(XtCallbackList), Offset(create_sampler_callback),
+ XtRCallback, (XtPointer) NULL},
+ {XtNcreateCreatorCallback, XtCCallback, XtRCallback,
+ sizeof(XtCallbackList), Offset(create_creator_callback),
+ XtRCallback, (XtPointer) NULL},
+ {XtNvalueChangedCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
+ Offset(value_changed_callback), XtRCallback, (XtPointer) NULL},
+
+ {XtNpaneChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(pane_child), XtRWidget, (XtPointer) NULL},
+ {XtNpreviewChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(preview_child), XtRWidget, (XtPointer) NULL},
+ {XtNpanelChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(panel_child), XtRWidget, (XtPointer) NULL},
+ {XtNfamilyLabelChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(family_label_child), XtRWidget, (XtPointer) NULL},
+ {XtNfamilyMultipleLabelChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(family_multiple_label_child), XtRWidget, (XtPointer) NULL},
+ {XtNfamilyScrolledListChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(family_scrolled_list_child), XtRWidget, (XtPointer) NULL},
+ {XtNfaceLabelChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(face_label_child), XtRWidget, (XtPointer) NULL},
+ {XtNfaceMultipleLabelChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(face_multiple_label_child), XtRWidget, (XtPointer) NULL},
+ {XtNfaceScrolledListChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(face_scrolled_list_child), XtRWidget, (XtPointer) NULL},
+ {XtNsizeLabelChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(size_label_child), XtRWidget, (XtPointer) NULL},
+ {XtNsizeTextFieldChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(size_text_field_child), XtRWidget, (XtPointer) NULL},
+ {XtNsizeOptionMenuChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(size_option_menu_child), XtRWidget, (XtPointer) NULL},
+ {XtNsizeMultipleLabelChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(size_multiple_label_child), XtRWidget, (XtPointer) NULL},
+ {XtNpreviewButtonChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(preview_button_child), XtRWidget, (XtPointer) NULL},
+ {XtNsamplerButtonChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(sampler_button_child), XtRWidget, (XtPointer) NULL},
+ {XtNseparatorChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(separator_child), XtRWidget, (XtPointer) NULL},
+ {XtNokButtonChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(ok_button_child), XtRWidget, (XtPointer) NULL},
+ {XtNapplyButtonChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(apply_button_child), XtRWidget, (XtPointer) NULL},
+ {XtNresetButtonChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(reset_button_child), XtRWidget, (XtPointer) NULL},
+ {XtNcancelButtonChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(cancel_button_child), XtRWidget, (XtPointer) NULL},
+ {XtNmultipleMasterButtonChild, XtCReadOnly, XtRWidget, sizeof(Widget),
+ Offset(multiple_master_button_child), XtRWidget, (XtPointer) NULL}
+};
+
+/* Forward declarations */
+
+static Boolean ChangeBlends(Widget w, String base_name, String blend_name, FSBBlendAction action, int *axis_values, float *axis_percents);
+static Boolean DownloadFontName(Widget w, String name);
+static Boolean MatchFontFace(Widget w, String old_face, String new_family, String *new_face);
+static Boolean SetValues(Widget old, Widget req, Widget new, ArgList args, Cardinal *num_args);
+static Boolean Verify(FontSelectionBoxWidget fsb, FSBValidateCallbackRec *cb, String afm, Boolean doIt);
+static String FindAFM(Widget w, String name);
+static String FindFontFile(Widget w, String name);
+static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *desired, XtWidgetGeometry *allowed);
+static void ChangeManaged(Widget w);
+static void ClassInitialize(void);
+static void ClassPartInitialize(WidgetClass widget_class);
+static void Destroy(Widget widget);
+static void DisplayFontFamilies(FontSelectionBoxWidget fsb);
+static void FontFamilyFaceBlendToName(Widget w, String family, String face, String blend, String *font_name);
+static void FontFamilyFaceToName(Widget w, String family, String face, String *font_name);
+static void FontNameToFamilyFace(Widget w, String font_name, String *family, String *face);
+static void FontNameToFamilyFaceBlend(Widget w, String font_name, String *family, String *face, String *blend);
+static void FreeFontRec(FontRec *f);
+static void GetBlendInfo(Widget w, String name, int *num_axes_return, int *num_designs_return, String **axis_names_return, float **blend_positions_return, int **blend_map_count_return, int **blend_design_coords_return, float **blend_normalized_coords_return);
+static void GetBlendList(Widget w, String name, int *count_return, String **blend_return, String **font_name_return, float **axis_values_return);
+static void GetFaceList(Widget w, String family, int *count, String **face_list, String **font_list);
+static void GetFamilyList(Widget w, int *count, String **list);
+static void GetTextDimensions(Widget w, String text, String font, double size, double x, double y, float *dx, float *dy, float *left, float *right, float *top, float *bottom);
+static void Initialize(Widget request, Widget new, ArgList args, Cardinal *num_args);
+static void ReadBlends(FontSelectionBoxWidget fsb);
+static void RefreshFontList(Widget w);
+static void Resize(Widget widget);
+static void SetFontFamilyFace(Widget w, String family, String face, Bool family_multiple, Bool face_multiple);
+static void SetFontFamilyFaceBlend(Widget w, String family, String face, String blend, Bool family_multiple, Bool face_multiple);
+static void SetFontName(Widget w, String name, Bool name_multiple);
+static void SetFontSize(Widget w, double size, Bool size_multiple);
+static void SetUpCurrentSelections(FontSelectionBoxWidget fsb);
+static void UndefUnusedFonts(Widget w);
+static void WriteBlends(FontSelectionBoxWidget fsb);
+
+FontSelectionBoxClassRec fontSelectionBoxClassRec = {
+ /* Core class part */
+ {
+ /* superclass */ (WidgetClass) &xmManagerClassRec,
+ /* class_name */ "FontSelectionBox",
+ /* widget_size */ sizeof(FontSelectionBoxRec),
+ /* class_initialize */ ClassInitialize,
+ /* class_part_initialize */ ClassPartInitialize,
+ /* class_inited */ False,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ XtInheritRealize,
+ /* actions */ NULL,
+ /* num_actions */ 0,
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ True,
+ /* compress_exposure */ XtExposeCompressMultiple,
+ /* compress_enterleave */ True,
+ /* visible_interest */ False,
+ /* destroy */ Destroy,
+ /* resize */ Resize,
+ /* expose */ NULL,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback offsets */ NULL,
+ /* tm_table */ NULL,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator */ NULL,
+ /* extension */ NULL,
+ },
+ /* Composite class part */
+ {
+ /* geometry_manager */ GeometryManager,
+ /* change_managed */ ChangeManaged,
+ /* insert_child */ XtInheritInsertChild,
+ /* delete_child */ XtInheritDeleteChild,
+ /* extension */ NULL,
+ },
+ /* Constraint class part */
+ {
+ /* resources */ NULL,
+ /* num_resources */ 0,
+ /* constraint_size */ 0,
+ /* initialize */ NULL,
+ /* destroy */ NULL,
+ /* set_values */ NULL,
+ /* extension */ NULL,
+ },
+ /* Manager class part */
+ {
+ /* translations */ XtInheritTranslations,
+ /* syn_resources */ NULL,
+ /* num_syn_resources */ 0,
+ /* syn_constraint_resources */ NULL,
+ /* num_syn_constraint_resources */ 0,
+ /* parent_process */ XmInheritParentProcess,
+ /* extension */ NULL,
+ },
+ /* FontSelectionBox class part */
+ {
+ /* set_font_name */ SetFontName,
+ /* set_font_family_face */ SetFontFamilyFace,
+ /* set_font_size */ SetFontSize,
+ /* refresh_font_list */ RefreshFontList,
+ /* get_family_list */ GetFamilyList,
+ /* get_face_list */ GetFaceList,
+ /* undef_unused_fonts */ UndefUnusedFonts,
+ /* download_font_name */ DownloadFontName,
+ /* match_font_face */ MatchFontFace,
+ /* font_name_to_family_face */ FontNameToFamilyFace,
+ /* font_family_face_to_name */ FontFamilyFaceToName,
+ /* find_afm */ FindAFM,
+ /* find_font_file */ FindFontFile,
+ /* get_text_dimensions */ GetTextDimensions,
+ /* set_font_family_face_blend */ SetFontFamilyFaceBlend,
+ /* font_name_to_family_face_blend */ FontNameToFamilyFaceBlend,
+ /* font_family_face_blend_to_name */ FontFamilyFaceBlendToName,
+ /* get_blend_list */ GetBlendList,
+ /* get_blend_info */ GetBlendInfo,
+ /* change_blends */ ChangeBlends,
+ /* extension */ NULL,
+ }
+};
+
+WidgetClass fontSelectionBoxWidgetClass =
+ (WidgetClass) &fontSelectionBoxClassRec;
+
+/* ARGSUSED */
+
+static Boolean CvtStringToFloatList(
+ Display *dpy,
+ XrmValuePtr args,
+ Cardinal *num_args,
+ XrmValuePtr from,
+ XrmValuePtr to,
+ XtPointer *data)
+{
+ register int i, count = 1;
+ register char *ch, *start = from->addr;
+ static float *list;
+ char save;
+
+ if (*num_args != 0) { /* Check for correct number */
+ XtAppErrorMsg(XtDisplayToApplicationContext(dpy),
+ "cvtStringToFloatList", "wrongParameters",
+ "XtToolkitError",
+ "String to integer list conversion needs no extra arguments",
+ (String *) NULL, (Cardinal *) NULL);
+ }
+
+ if (to->addr != NULL && to->size < sizeof(int *)) {
+ to->size = sizeof(int *);
+ return False;
+ }
+ if (start == NULL || *start == '\0') list = NULL;
+ else {
+ for (ch = start; *ch != '\0'; ch++) { /* Count floats */
+ if (!isdigit(*ch) && *ch != '.' && *ch != ',') {
+ XtDisplayStringConversionWarning(dpy, from->addr, "FloatList");
+ return False;
+ }
+ if (*ch == ',') count++;
+ }
+ list = (float *) XtCalloc(count+1, sizeof(float));
+
+ for (i = 0; i < count; i++) {
+ for (ch = start; *ch != ',' && *ch != '\0'; ch++) {}
+ save = *ch;
+ *ch = '\0';
+ list[i] = atof(start);
+ *ch = save;
+ start = ch + 1;
+ }
+ }
+ if (to->addr == NULL) to->addr = (caddr_t) &list;
+ else *(float **) to->addr = list;
+ to->size = sizeof(int *);
+ return True;
+}
+
+/* ARGSUSED */
+
+static void FloatListDestructor(
+ XtAppContext app,
+ XrmValuePtr to,
+ XtPointer converter_data,
+ XrmValuePtr args,
+ Cardinal *num_args)
+{
+ float *list = (float *) to->addr;
+
+ if (list == NULL) return;
+ XtFree((XtPointer) list);
+}
+
+XmString _FSBCreateSharedCS(String str, Widget w)
+{
+ XrmValue src, dst;
+ XmString result;
+
+ src.addr = str;
+ src.size = strlen(str);
+
+ dst.addr = (caddr_t) &result;
+ dst.size = sizeof(result);
+
+ if (XtConvertAndStore(w, XtRString, &src, XmRXmString, &dst)) {
+ return result;
+ } else return NULL;
+}
+
+static Boolean ScanFloat(char *src, float *f, char **past)
+{
+ char buf[20], *ch;
+ int countDecimals;
+
+ ch = buf;
+ countDecimals = 0;
+ while (*src == '.' || isdigit(*src)) {
+ if (*src == '.') {
+ if (countDecimals) return False;
+ else countDecimals++;
+ }
+ *ch++ = *src++;
+ }
+ if (ch == buf) return False;
+ *ch++ = '\0';
+ *f = atof(buf);
+ *past = src;
+ return True;
+}
+
+static Boolean ScanInt(char *src, int *i, char **past)
+{
+ char buf[20], *ch;
+
+ ch = buf;
+ while (isdigit(*src)) *ch++ = *src++;
+ if (ch == buf) return False;
+ *ch++ = '\0';
+ *i = atoi(buf);
+ *past = src;
+ return True;
+}
+
+static void ClassInitialize(void)
+{
+ /* Register a converter for string to int list */
+
+ XtSetTypeConverter(XtRString, XtRFloatList,
+ CvtStringToFloatList, (XtConvertArgList) NULL, 0,
+ XtCacheAll | XtCacheRefCount, FloatListDestructor);
+
+ CSempty = UnsharedCS("");
+}
+
+static void ClassPartInitialize(WidgetClass widget_class)
+{
+ register FontSelectionBoxWidgetClass wc =
+ (FontSelectionBoxWidgetClass) widget_class;
+ FontSelectionBoxWidgetClass super =
+ (FontSelectionBoxWidgetClass) wc->core_class.superclass;
+
+ if (wc->fsb_class.set_font_name == InheritSetFontName) {
+ wc->fsb_class.set_font_name = super->fsb_class.set_font_name;
+ }
+ if (wc->fsb_class.set_font_family_face == InheritSetFontFamilyFace) {
+ wc->fsb_class.set_font_family_face =
+ super->fsb_class.set_font_family_face;
+ }
+ if (wc->fsb_class.set_font_size == InheritSetFontSize) {
+ wc->fsb_class.set_font_size = super->fsb_class.set_font_size;
+ }
+ if (wc->fsb_class.refresh_font_list == InheritRefreshFontList) {
+ wc->fsb_class.refresh_font_list = super->fsb_class.refresh_font_list;
+ }
+ if (wc->fsb_class.get_family_list == InheritGetFamilyList) {
+ wc->fsb_class.get_family_list = super->fsb_class.get_family_list;
+ }
+ if (wc->fsb_class.get_face_list == InheritGetFaceList) {
+ wc->fsb_class.get_face_list = super->fsb_class.get_face_list;
+ }
+ if (wc->fsb_class.undef_unused_fonts == InheritUndefUnusedFonts) {
+ wc->fsb_class.undef_unused_fonts = super->fsb_class.undef_unused_fonts;
+ }
+ if (wc->fsb_class.download_font_name == InheritDownloadFontName) {
+ wc->fsb_class.download_font_name = super->fsb_class.download_font_name;
+ }
+ if (wc->fsb_class.match_font_face == InheritMatchFontFace) {
+ wc->fsb_class.match_font_face = super->fsb_class.match_font_face;
+ }
+ if (wc->fsb_class.font_name_to_family_face ==
+ InheritFontNameToFamilyFace) {
+ wc->fsb_class.font_name_to_family_face =
+ super->fsb_class.font_name_to_family_face;
+ }
+ if (wc->fsb_class.font_family_face_to_name ==
+ InheritFontFamilyFaceToName) {
+ wc->fsb_class.font_family_face_to_name =
+ super->fsb_class.font_family_face_to_name;
+ }
+ if (wc->fsb_class.find_afm == InheritFindAFM) {
+ wc->fsb_class.find_afm = super->fsb_class.find_afm;
+ }
+ if (wc->fsb_class.find_font_file == InheritFindFontFile) {
+ wc->fsb_class.find_font_file = super->fsb_class.find_font_file;
+ }
+ if (wc->fsb_class.get_text_dimensions == InheritGetTextDimensions) {
+ wc->fsb_class.get_text_dimensions =
+ super->fsb_class.get_text_dimensions;
+ }
+ if (wc->fsb_class.set_font_family_face_blend ==
+ InheritSetFontFamilyFaceBlend) {
+ wc->fsb_class.set_font_family_face_blend =
+ super->fsb_class.set_font_family_face_blend;
+ }
+ if (wc->fsb_class.font_name_to_family_face_blend ==
+ InheritFontNameToFamilyFaceBlend) {
+ wc->fsb_class.font_name_to_family_face_blend =
+ super->fsb_class.font_name_to_family_face_blend;
+ }
+ if (wc->fsb_class.font_family_face_blend_to_name ==
+ InheritFontFamilyFaceBlendToName) {
+ wc->fsb_class.font_family_face_blend_to_name =
+ super->fsb_class.font_family_face_blend_to_name;
+ }
+ if (wc->fsb_class.get_blend_list == InheritGetBlendList) {
+ wc->fsb_class.get_blend_list =
+ super->fsb_class.get_blend_list;
+ }
+ if (wc->fsb_class.get_blend_info == InheritGetBlendInfo) {
+ wc->fsb_class.get_blend_info =
+ super->fsb_class.get_blend_info;
+ }
+ if (wc->fsb_class.change_blends == InheritChangeBlends) {
+ wc->fsb_class.change_blends =
+ super->fsb_class.change_blends;
+ }
+}
+
+static String bugFamilies[] = {
+ "Berkeley", "CaslonFiveForty", "CaslonThree", "GaramondThree",
+ "Music", "TimesTen", NULL
+};
+
+static String fixedFamilies[] = {
+ "ITC Berkeley Oldstyle", "Caslon 540", "Caslon 3", "Garamond 3",
+ "Sonata", "Times 10", NULL
+};
+
+static String missingFoundries[] = {
+ "Berthold ", "ITC ", "Linotype ", NULL
+};
+
+static int missingFoundryLen[] = {
+ 9, 4, 9, 0
+};
+
+/* I wish we didn't have to do this! */
+
+static void MungeFontNames(
+ String name, String family, String fullname, String weight,
+ String *familyReturn, String *fullnameReturn, String *faceReturn)
+{
+ register char *src, *dst, prev;
+ char buf[256];
+ int digits = 0;
+ int i, diff;
+ static Bool inited = False;
+ static String FetteFrakturDfr, LinotextDfr;
+
+ /* Don't make bugFamilies canonical; we'd have to make the initial
+ family canonical to do anything with it and there's no point in that */
+
+ if (!inited) {
+ for (i = 0; fixedFamilies[i] != NULL; i++) {
+ fixedFamilies[i] = Canonical(fixedFamilies[i]);
+ }
+ FetteFrakturDfr = Canonical("FetteFraktur-Dfr");
+ LinotextDfr = Canonical("Linotext-Dfr");
+ inited = True;
+ }
+
+ /* Copy the fullname into buf, enforcing one space between words.
+ Eliminate leading digits and spaces, ignore asterisks, if the
+ full name ends with 5 digits strip them, and replace periods that
+ aren't followed by a space with a space. If leading digits are
+ followed by " pt " skip that too. */
+
+ dst = buf;
+ prev = ' ';
+ src = fullname;
+ while (isdigit(*src)) src++;
+ while (*src == ' ' || *src == '\t') src++;
+ if (strncmp(src, "pt ", 3) == 0) src += 3;
+ else if (strncmp(src, "pt. ", 4) == 0) src += 4;
+
+ while (*src != '\0') {
+ if (*src == '*') {
+ src++;
+ continue;
+ }
+
+ if (*src == '.') {
+ if (*(src+1) != ' ') {
+ prev = *dst++ = ' ';
+ } else prev = *dst++ = '.';
+ src++;
+ continue;
+ }
+
+ if (isdigit(*src)) digits++;
+ else digits = 0;
+
+ if (isupper(*src)) {
+ if (prev != ' ' && (islower(*(src+1)) || islower(prev))) {
+ *dst++ = ' ';
+ prev = *dst++ = *src++;
+ } else prev = *dst++ = *src++;
+
+ } else if (*src == ' ' || *src == '\t') {
+ if (prev == ' ') {
+ src++;
+ continue;
+ }
+ prev = *dst++ = ' ';
+ src++;
+
+ } else prev = *dst++ = *src++;
+ }
+
+ if (digits == 5) {
+ dst -= 5;
+ }
+ if (dst > buf && *(dst-1) == ' ') dst--;
+
+ *dst = '\0';
+
+ /* Stupid Fette Fraktur */
+
+ if (name == FetteFrakturDfr) {
+ strcat(buf, " Black Dfr");
+ } else if (name == LinotextDfr) {
+ strcat(buf, " Dfr");
+ }
+
+ if (strncmp(fullname, "pt ", 3) == 0) {
+ src = buf + 2;
+ while (*++src != '\0') *(src-3) = *src;
+ *(src-3) = '\0';
+ }
+ *fullnameReturn = XtNewString(buf);
+
+ /* From here on fullname should not be used */
+
+ /* Done with the full name; now onto the family */
+
+ for (i = 0; bugFamilies[i] != NULL; i++) {
+ diff = strcmp(family, bugFamilies[i]);
+ if (diff < 0) break;
+ if (diff == 0) {
+ *familyReturn = fixedFamilies[i];
+ goto FAMILY_DONE;
+ }
+ }
+
+ /* Copy the family into buf, enforcing one space between words */
+
+ dst = buf;
+ prev = ' ';
+ src = family;
+
+ while (*src != '\0') {
+ if (isupper(*src)) {
+ if (prev != ' ' && (islower(*(src+1)) || islower(prev))) {
+ *dst++ = ' ';
+ prev = *dst++ = *src++;
+ } else prev = *dst++ = *src++;
+
+ } else if (*src == ' ' || *src == '\t') {
+ if (prev == ' ') {
+ src++;
+ continue;
+ }
+ prev = *dst++ = ' ';
+ src++;
+
+ } else prev = *dst++ = *src++;
+ }
+
+ if (dst > buf && *(dst-1) == ' ') dst--;
+ *dst = '\0';
+
+ /* Compensate for fonts with foundries in the full name but not the
+ family name by adding to the family name */
+
+ for (i = 0; missingFoundries[i] != NULL; i++) {
+ diff = strncmp(*fullnameReturn, missingFoundries[i],
+ missingFoundryLen[i]);
+ if (diff > 0) continue;
+ if (diff == 0 && strncmp(buf, missingFoundries[i],
+ missingFoundryLen[i] != 0)) {
+ while (dst >= buf) {
+ *(dst+missingFoundryLen[i]) = *dst;
+ dst--;
+ }
+ strncpy(buf, missingFoundries[i], missingFoundryLen[i]);
+ }
+ break;
+ }
+
+ /* From here on dst no longer points to the end of the buffer */
+
+ /* Stupid Helvetica Rounded! */
+
+ if (strncmp(*fullnameReturn, "Helvetica Rounded ", 18) == 0) {
+ strcat(buf, " Rounded");
+ }
+
+ *familyReturn = Canonical(buf);
+
+ /* From here on family should not be used */
+
+FAMILY_DONE:
+
+ /* Now to find the face in all this */
+
+ src = *fullnameReturn;
+ dst = *familyReturn;
+ while (*dst == *src && *dst != '\0') {
+ src++;
+ dst++;
+ }
+ if (*src == ' ') src++;
+
+ if (*src != '\0') *faceReturn = Canonical(src);
+ else if (*weight != '\0') {
+ /* Handle Multiple Master fonts */
+ if (strcmp(weight, "All") == 0) *faceReturn = Canonical("Roman");
+ else {
+ if (islower(weight[0])) weight[0] = toupper(weight[0]);
+ *faceReturn = Canonical(weight);
+ }
+ } else *faceReturn = Canonical("Medium");
+}
+
+static String strip[] = {
+ "Adobe ", "Bauer ", "Berthold ", "ITC ", "Linotype ",
+ "New ", "Simoncini ", "Stempel ", NULL};
+
+static int striplen[] = {6, 6, 9, 4, 9, 4, 10, 8, 0};
+
+#define STEMPELINDEX 7
+
+static Boolean CreateSortKey(String family, String key)
+{
+ char newkey[256];
+ int len = strlen(family);
+ register int i, diff;
+
+ if (family[len-2] == 'P' && family[len-1] == 'i') {
+ key[0] = 'P';
+ key[1] = 'i';
+ key[2] = ' ';
+ strcpy(key+3, family);
+ key[len] = '\0';
+ return True;
+ }
+
+ for (i = 0; strip[i] != NULL; i++) {
+ diff = strncmp(family, strip[i], striplen[i]);
+ if (diff < 0) break;
+ if (diff == 0) {
+ if (i == STEMPELINDEX) {
+ if (strcmp(family, "Stempel Schneidler") == 0) break;
+ }
+ strcpy(key, family + striplen[i]);
+ key[len - striplen[i]] = ' ';
+ strcpy(key + len - striplen[i] + 1, strip[i]);
+ key[len] = '\0';
+ if (CreateSortKey(key, newkey)) strcpy(key, newkey);
+ return True;
+ }
+ }
+ strcpy(key, family);
+ return False;
+}
+
+#define SKIP_SPACE(buf) while (*buf == ' ' || *buf == '\t') buf++;
+
+static int CountAxes(char *buf)
+{
+ int count = 0;
+
+ while (*buf != '\0') {
+ SKIP_SPACE(buf)
+ if (*buf != '/') return 0;
+ buf++;
+ count++;
+ if (*buf == ' ' || *buf == '\t' || *buf == '\0') return 0;
+ while (*buf != ' ' && *buf != '\t' && *buf != '\0') buf++;
+ }
+ return count;
+}
+
+static Boolean ParseBlendPositions(
+ char *buf,
+ float *blendPos,
+ int *axes, int *designs)
+{
+ int i, j = 0;
+ float f;
+
+ *designs = 0;
+
+ while (*buf != '\0') {
+ SKIP_SPACE(buf)
+ if (*buf++ != '[') return True;
+
+ /* Now there should be *axes positive floats, separated by space */
+ SKIP_SPACE(buf)
+ for (i = 0; i < *axes; i++) {
+ if (!ScanFloat(buf, &f, &buf)) return True;
+ blendPos[j++] = f;
+ SKIP_SPACE(buf)
+ }
+ if (*buf++ != ']') return True;
+ (*designs)++;
+ }
+ return False;
+}
+
+static Boolean ParseBlendMap(
+ char *buf,
+ int *breakCount,
+ int *blendBreak,
+ float *blendBreakValue,
+ int *axes)
+{
+ int i, j = 0;
+ int n;
+ float f;
+
+ /* OK. What we expect to see here is *axes arrays. Each one contains at
+ least 2 and no more than 12 subarrays, each of which contains 2 values,
+ an int and a float */
+
+ for (i = 0; i < *axes; i++) {
+
+ breakCount[i] = 0;
+
+ SKIP_SPACE(buf)
+ if (*buf++ != '[') return True;
+ SKIP_SPACE(buf)
+
+ while (*buf == '[') {
+ buf++;
+ SKIP_SPACE(buf)
+ /* Now there should be an integer */
+ if (!ScanInt(buf, &n, &buf)) return True;
+ blendBreak[j] = n;
+
+ SKIP_SPACE(buf)
+
+ /* Now there should be a float */
+ if (!ScanFloat(buf, &f, &buf)) return True;
+ blendBreakValue[j++] = f;
+ SKIP_SPACE(buf)
+
+ /* Nothing more in the array */
+ if (*buf++ != ']') return True;
+ SKIP_SPACE(buf)
+
+ breakCount[i]++;
+ if (breakCount[i] == 12 && *buf != ']') return True;
+ }
+ if (*buf++ != ']') return True;
+ }
+ SKIP_SPACE(buf)
+ if (*buf != '\0') return True;
+ return False;
+}
+
+static Boolean ParseAxisNames(
+ int axes,
+ char *buf,
+ char *names[])
+{
+ int i = 0;
+
+ /* We expect to see axes names, each optionally preceded with a / and
+ separated by space */
+
+ while (*buf != '\0') {
+ SKIP_SPACE(buf)
+ if (*buf == '/') buf++;
+ names[i] = buf;
+ while (*buf != ' ' && *buf != '\t' && *buf != '\0') buf++;
+ if (buf != names[i]) i++;
+ if (*buf != '\0') *buf++ = '\0';
+ if (i >= axes) return True;
+ }
+ return False;
+}
+#undef SKIP_SPACE
+
+static void GetPSFontInfo(
+ FontSelectionBoxWidget fsb,
+ char *name,
+ int *axes,
+ int *designs,
+ char *axisNames,
+ float *blendPos,
+ int *breakCount,
+ int *blendBreak,
+ float *blendBreakValue)
+{
+ int entries;
+ char **names, **data;
+
+ entries = ListPSResourceFiles(fsb->fsb.resource_path_override,
+ fsb->fsb.default_resource_path,
+ "FontAxes", name,
+ &names, &data);
+ if (entries < 1) {
+ *axes = 0;
+ return;
+ }
+ *axes = CountAxes(data[0]);
+ if (*axes == 0) return;
+ strcpy(axisNames, data[0]);
+
+ entries = ListPSResourceFiles(fsb->fsb.resource_path_override,
+ fsb->fsb.default_resource_path,
+ "FontBlendMap", name,
+ &names, &data);
+ if (entries < 1) {
+ *axes = 0;
+ return;
+ }
+ if (ParseBlendMap(data[0], breakCount,
+ blendBreak, blendBreakValue, axes)) {
+ *axes = 0;
+ return;
+ }
+
+ entries = ListPSResourceFiles(fsb->fsb.resource_path_override,
+ fsb->fsb.default_resource_path,
+ "FontBlendPositions", name,
+ &names, &data);
+ if (entries < 1) {
+ *axes = 0;
+ return;
+ }
+ if (ParseBlendPositions(data[0], blendPos, axes, designs)) {
+ *axes = 0;
+ return;
+ }
+}
+
+static void AddFontRecord(
+ FontSelectionBoxWidget fsb,
+ int serverNum,
+ String name, String family, String fullname, String weight,
+ Boolean resident)
+{
+ FontFamilyRec *ff;
+ FontRec *f;
+ String familyReturn, fullnameReturn, faceReturn;
+ char axisNameBuf[256];
+ char *axisName[MAX_AXES];
+ int blendedFont, undefineIt, brokenFont;
+ int axes, designs, breakCount[MAX_AXES],
+ blendBreak[12 * MAX_AXES];
+ float blendBreakValue[12 * MAX_AXES], blendPos[MAX_AXES * MAX_BLENDS];
+ char key[256];
+ int i, j, k, n;
+
+ name = Canonical(name);
+
+ /* First see if it's there already */
+
+ for (ff = fsb->fsb.known_families; ff != NULL; ff = ff->next) {
+ for (f = ff->fonts; f != NULL; f = f->next) {
+ if (f->font_name == name) {
+ if (!f->resident && resident) f->resident = True;
+ return;
+ }
+ }
+ }
+
+ /* We believe that names gotten from PS resource files have been
+ pre-munged, so no need to do it again */
+
+ if (resident) {
+ /* Have to get the info from the server */
+ _DPSFGetFontInfo(fsb->fsb.context, serverNum, fsb->fsb.old_server,
+ family, fullname,
+ weight, &blendedFont, &undefineIt, &brokenFont);
+
+ if (brokenFont) return;
+
+ /* Deal with fonts that don't have useful information */
+
+ if (family[0] == '\0') {
+ if (fullname[0] == '\0') {
+ strcpy(family, name);
+ strcpy(fullname, name);
+ } else strcpy(family, fullname);
+ } else if (fullname[0] == '\0') strcpy(fullname, family);
+
+ MungeFontNames(name, family, fullname, weight,
+ &familyReturn, &fullnameReturn, &faceReturn);
+ if (blendedFont) {
+ _DPSFGetBlendedFontInfo(fsb->fsb.context, serverNum,
+ undefineIt, fsb->fsb.old_server,
+ &axes, &designs, axisNameBuf,
+ blendPos, breakCount, blendBreak,
+ blendBreakValue, &brokenFont);
+ if (brokenFont) axes = 0;
+ } else axes = 0;
+
+ } else {
+ familyReturn = Canonical(family);
+ fullnameReturn = XtNewString(fullname);
+ faceReturn = Canonical(weight);
+ GetPSFontInfo(fsb, name, &axes, &designs, axisNameBuf, blendPos,
+ breakCount, blendBreak, blendBreakValue);
+ }
+
+ /* We didn't get an exact match, go for family match */
+
+ for (ff = fsb->fsb.known_families; ff != NULL; ff = ff->next) {
+ if (ff->family_name == familyReturn) break;
+ }
+
+ if (ff == NULL) {
+ ff = (FontFamilyRec *) XtMalloc(sizeof(FontFamilyRec));
+ ff->next = fsb->fsb.known_families;
+ ff->family_name = familyReturn;
+ ff->fonts = NULL;
+ ff->font_count = 0;
+ ff->blend_count = 0;
+ if (fsb->fsb.typographic_sort) {
+ (void) CreateSortKey(familyReturn, key);
+ ff->sort_key = XtNewString(key);
+ } else ff->sort_key = ff->family_name;
+ fsb->fsb.known_families = ff;
+ fsb->fsb.family_count++;
+ }
+
+ f = (FontRec *) XtMalloc(sizeof(FontRec));
+ f->next = ff->fonts;
+ f->font_name = name;
+ f->full_name = fullnameReturn;
+ f->resident = resident;
+ f->temp_resident = False;
+ f->in_font_creator = False;
+ f->pending_delete_next = NULL;
+ f->face_name = faceReturn;
+ f->CS_face_name = CS(f->face_name, (Widget) fsb);
+ f->blend_count = 0;
+
+ if (axes != 0 && ParseAxisNames(axes, axisNameBuf, axisName)) {
+ BlendDataRec *b;
+
+ f->blend_data = b = XtNew(BlendDataRec);
+ b->num_axes = axes;
+ b->num_designs = designs;
+ k = 0;
+
+ for (i = 0; i < axes; i++) {
+ b->internal_points[i] = breakCount[i] - 2;
+ if (b->internal_points[i] <= 0) {
+ b->internal_break[i] = NULL;
+ b->internal_value[i] = NULL;
+ b->internal_points[i] = 0;
+ } else {
+ b->internal_break[i] = (int *)
+ XtMalloc(b->internal_points[i] * sizeof(int));
+ b->internal_value[i] = (float *)
+ XtMalloc(b->internal_points[i] * sizeof(float));
+ }
+
+ n = 0;
+ for (j = 0; j < breakCount[i]; j++) {
+ if (blendBreakValue[k] == 0.0) b->min[i] = blendBreak[k];
+ else if (blendBreakValue[k] == 1.0) b->max[i] = blendBreak[k];
+ else {
+ b->internal_break[i][n] = blendBreak[k];
+ b->internal_value[i][n++] = blendBreakValue[k];
+ }
+ k++;
+ }
+ b->name[i] = Canonical(axisName[i]);
+ }
+
+ b->design_positions =
+ (float *) XtMalloc(axes * designs * sizeof(float));
+ for (i = 0; i < axes * designs; i++) {
+ b->design_positions[i] = blendPos[i];
+ }
+ b->blends = NULL;
+ } else f->blend_data = NULL;
+
+ ff->fonts = f;
+ ff->font_count++;
+}
+
+static void SortFontNames(FontFamilyRec *ff)
+{
+ FontRec *f, *highest, **prev, **highestPrev;
+ FontRec *newFontList = NULL;
+
+ while (ff->fonts != NULL) {
+ prev = highestPrev = &ff->fonts;
+ highest = ff->fonts;
+
+ for (f = ff->fonts->next; f != NULL; f = f->next) {
+ prev = &(*prev)->next;
+ if (strcmp(f->face_name, highest->face_name) > 0) {
+ highest = f;
+ highestPrev = prev;
+ }
+ }
+
+ *highestPrev = highest->next;
+ highest->next = newFontList;
+ newFontList = highest;
+ }
+ ff->fonts = newFontList;
+}
+
+static void SortFontFamilies(FontSelectionBoxWidget fsb)
+{
+ FontFamilyRec *ff, *highest, **prev, **highestPrev;
+ FontFamilyRec *newFamilyList = NULL;
+
+ while (fsb->fsb.known_families != NULL) {
+ prev = highestPrev = &fsb->fsb.known_families;
+ highest = fsb->fsb.known_families;
+
+ for (ff = fsb->fsb.known_families->next; ff != NULL; ff = ff->next) {
+ prev = &(*prev)->next;
+ if (strcmp(ff->sort_key, highest->sort_key) > 0) {
+ highest = ff;
+ highestPrev = prev;
+ }
+ }
+
+ *highestPrev = highest->next;
+ highest->next = newFamilyList;
+ newFamilyList = highest;
+ SortFontNames(highest);
+ if (fsb->fsb.typographic_sort) XtFree(highest->sort_key);
+ highest->sort_key = NULL;
+ }
+ fsb->fsb.known_families = newFamilyList;
+}
+
+static void AddFamily(
+ FontSelectionBoxWidget fsb,
+ char *family, char *fonts, char *weight, char *fullname, char *name)
+{
+ int j;
+ char *ch;
+
+ ch = fonts;
+ while (*ch != '\0') {
+ j = 0;
+ while (1) {
+ if (*ch == '\\' && (*(ch+1) == '\\' || *(ch+1) == ',')) {
+ ch++;
+ weight[j++] = *ch++;
+ } else if (*ch == '\0' || *ch == ',') {
+ weight[j] = '\0';
+ break;
+ } else weight[j++] = *ch++;
+ }
+ if (*ch == ',') {
+ j = 0;
+ ch++;
+ while (1) {
+ if (*ch == '\\' && (*(ch+1) == '\\' || *(ch+1) == ',')) {
+ ch++;
+ name[j++] = *ch++;
+ } else if (*ch == '\0' || *ch == ',') {
+ name[j] = '\0';
+ break;
+ } else name[j++] = *ch++;
+ }
+ strcpy(fullname, family);
+ strcat(fullname, " ");
+ strcat(fullname, weight);
+ AddFontRecord(fsb, 0, name, family, fullname, weight, False);
+ if (*ch == ',') ch++;
+ }
+ }
+}
+
+static void GetFontNames(FontSelectionBoxWidget fsb)
+{
+ int i;
+ char name[256], family[256], fullname[256], weight[256];
+ char *buffer, *ch, *start;
+ int fontCount, totalLength;
+ char **loadableFamilies = NULL, **loadableFamilyFonts = NULL;
+
+ fsb->fsb.family_count = 0;
+
+ fontCount = ListPSResourceFiles(fsb->fsb.resource_path_override,
+ fsb->fsb.default_resource_path,
+ PSResFontFamily, NULL,
+ &loadableFamilies, &loadableFamilyFonts);
+ for (i = 0; i < fontCount; i++) {
+ AddFamily(fsb, loadableFamilies[i], loadableFamilyFonts[i],
+ weight, fullname, name);
+ }
+
+ XtFree((XtPointer) loadableFamilies);
+ XtFree((XtPointer) loadableFamilyFonts);
+ FreePSResourceStorage(False);
+
+ if (fsb->fsb.get_server_fonts) {
+ _DPSFEnumFonts(fsb->fsb.context, &fontCount, &totalLength);
+
+ buffer = XtMalloc(totalLength);
+ _DPSFGetAllFontNames(fsb->fsb.context, fontCount, totalLength, buffer);
+ ch = start = buffer;
+ for (i = 0; i < fontCount; i++) {
+ while (*ch != ' ') ch++;
+ *ch = '\0';
+ AddFontRecord(fsb, i, start, family, fullname, weight, True);
+ start = ch+1;
+ }
+ XtFree(buffer);
+ }
+
+ _DPSFFreeFontInfo(fsb->fsb.context);
+ SortFontFamilies(fsb);
+ ReadBlends(fsb);
+}
+
+static void SensitizeReset(FontSelectionBoxWidget fsb)
+{
+ XtSetSensitive(fsb->fsb.reset_button_child, True);
+}
+
+static void DesensitizeReset(FontSelectionBoxWidget fsb)
+{
+ XtSetSensitive(fsb->fsb.reset_button_child, False);
+}
+
+static void ManageFamilyMultiple(FontSelectionBoxWidget fsb)
+{
+ XtManageChild(fsb->fsb.family_multiple_label_child);
+
+ XtVaSetValues(XtParent(fsb->fsb.family_scrolled_list_child),
+ XmNtopWidget, fsb->fsb.family_multiple_label_child, NULL);
+}
+
+static void ManageFaceMultiple(FontSelectionBoxWidget fsb)
+{
+ XtManageChild(fsb->fsb.face_multiple_label_child);
+
+ XtVaSetValues(XtParent(fsb->fsb.face_scrolled_list_child),
+ XmNtopWidget, fsb->fsb.face_multiple_label_child, NULL);
+}
+
+static void ManageMultipleMaster(FontSelectionBoxWidget fsb)
+{
+ XtManageChild(fsb->fsb.multiple_master_button_child);
+
+ XtVaSetValues(XtParent(fsb->fsb.face_scrolled_list_child),
+ XmNbottomWidget, fsb->fsb.multiple_master_button_child,
+ NULL);
+}
+
+static void ManageSizeMultiple(FontSelectionBoxWidget fsb)
+{
+ XtManageChild(fsb->fsb.size_multiple_label_child);
+}
+
+static void UnmanageFamilyMultiple(FontSelectionBoxWidget fsb)
+{
+ XtVaSetValues(XtParent(fsb->fsb.family_scrolled_list_child),
+ XmNtopWidget, fsb->fsb.family_label_child, NULL);
+
+ XtUnmanageChild(fsb->fsb.family_multiple_label_child);
+}
+
+static void UnmanageFaceMultiple(FontSelectionBoxWidget fsb)
+{
+ XtVaSetValues(XtParent(fsb->fsb.face_scrolled_list_child),
+ XmNtopWidget, fsb->fsb.face_label_child, NULL);
+
+ XtUnmanageChild(fsb->fsb.face_multiple_label_child);
+}
+
+static void UnmanageMultipleMaster(FontSelectionBoxWidget fsb)
+{
+ XtUnmanageChild(fsb->fsb.multiple_master_button_child);
+
+ XtVaSetValues(XtParent(fsb->fsb.face_scrolled_list_child),
+ XmNbottomWidget, fsb->fsb.size_text_field_child, NULL);
+}
+
+static void UnmanageSizeMultiple(FontSelectionBoxWidget fsb)
+{
+ XtUnmanageChild(fsb->fsb.size_multiple_label_child);
+}
+
+/* Callbacks for subwidgets */
+
+static Boolean DownloadFont(
+ FontSelectionBoxWidget fsb,
+ String name,
+ DPSContext ctxt,
+ Boolean make_shared)
+{
+ int count;
+ char **names, **files;
+ FILE *f;
+#define BUFLEN 256
+ char buf[BUFLEN];
+ static char eobuf[] = "\n$Adobe$DPS$Lib$Dict /downloadSuccess true put\n\
+stop\n\
+Magic end of data line )))))))))) 99#2 2#99 <xyz> // 7gsad,32h4ghNmndFgj2\n";
+ int currentShared, ok;
+
+ /* Assume context is correct */
+
+ count = ListPSResourceFiles(fsb->fsb.resource_path_override,
+ fsb->fsb.default_resource_path,
+ PSResFontOutline, name,
+ &names, &files);
+ if (count == 0) return False;
+
+ f = fopen(files[0], "r");
+ if (f == NULL) return False;
+
+ /* A bug in 1006.9 and earlier servers prevents the more robust
+ downloading method from working reliably. */
+
+ if (fsb->fsb.old_server) {
+ DPSPrintf(ctxt, "\ncurrentshared %s setshared\n",
+ (make_shared ? "true" : "false"));
+ while (fgets(buf, BUFLEN, f) != NULL) {
+ DPSWritePostScript(ctxt, buf, strlen(buf));
+ }
+ DPSWritePostScript(ctxt, "\nsetshared\n", 11);
+ ok = True;
+
+ } else {
+ _DPSFPrepareToDownload(ctxt, make_shared, &currentShared);
+ DPSWriteData(ctxt, "\nexec\n", 6);
+
+ while (fgets(buf, BUFLEN, f) != NULL) {
+ DPSWriteData(ctxt, buf, strlen(buf));
+ }
+
+ /* This marks the end of the data stream */
+ DPSWriteData(ctxt, eobuf, strlen(eobuf));
+
+ /* Check the results of the download by getting the error status */
+ _DPSFFinishDownload(ctxt, currentShared, &ok);
+ }
+
+ fclose (f);
+ free(names);
+ free(files);
+ return ok;
+
+#undef BUFLEN
+}
+
+static void UndefSomeUnusedFonts(
+ FontSelectionBoxWidget fsb,
+ Boolean all)
+{
+ FontRec *f, *nextf, **start;
+ int i;
+
+ if (!all
+ && (Cardinal)fsb->fsb.pending_delete_count < fsb->fsb.max_pending_deletes) {
+ return;
+ }
+
+ if (all) start = &fsb->fsb.pending_delete_font;
+ else {
+ /* Skip to the end of the ones we're keeping */
+ f = fsb->fsb.pending_delete_font;
+ for (i = 1; f != NULL && (Cardinal)i < fsb->fsb.max_pending_deletes; i++) {
+ f = f->pending_delete_next;
+ }
+ if (f == NULL) return;
+ start = &f->pending_delete_next;
+ }
+
+ for (f = *start; f != NULL; f = nextf) {
+ nextf = f->pending_delete_next;
+ if (f == fsb->fsb.currently_previewed) {
+ start = &f->pending_delete_next;
+ continue;
+ }
+ *start = nextf;
+ if (!f->resident && !f->in_font_creator) {
+ _DPSFUndefineFont(fsb->fsb.context, f->font_name,
+ fsb->fsb.old_server);
+ }
+ f->temp_resident = False;
+ fsb->fsb.pending_delete_count--;
+ f->pending_delete_next = NULL;
+ }
+}
+
+static void UndefUnusedFonts(Widget w)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) w;
+
+ UndefSomeUnusedFonts(fsb, True);
+}
+
+Boolean _FSBDownloadFontIfNecessary(
+ FontRec *f,
+ FontSelectionBoxWidget fsb)
+{
+ Boolean shared;
+
+ if (!f->resident && !f->temp_resident) {
+
+ shared = fsb->fsb.make_fonts_shared && !fsb->fsb.undef_unused_fonts;
+ if (!fsb->fsb.get_server_fonts) {
+ int resident;
+ /* This font might already be there, so check before downloading */
+ _DPSFIsFontResident(fsb->fsb.context, f->font_name, &resident);
+ if (resident) {
+ f->resident = True;
+ return True;
+ }
+ }
+ if (!DownloadFont(fsb, f->font_name, fsb->fsb.context, shared)) {
+ _FSBFlushFont(fsb, f);
+ return False;
+ }
+ if (shared) f->resident = True;
+ else f->temp_resident = True;
+
+ if (f->pending_delete_next == NULL && fsb->fsb.undef_unused_fonts) {
+ f->pending_delete_next = fsb->fsb.pending_delete_font;
+ fsb->fsb.pending_delete_font = f;
+ fsb->fsb.pending_delete_count++;
+ UndefSomeUnusedFonts(fsb, False);
+ }
+ }
+ return True;
+}
+
+static void DoPreview(
+ FontSelectionBoxWidget fsb,
+ Boolean override)
+{
+ int i, n;
+ int *selectList, selectCount;
+ float size;
+ FontFamilyRec *ff = fsb->fsb.known_families;
+ FontRec *f;
+ BlendRec *b;
+ char *chSize, *fontName;
+ Dimension height;
+ Cardinal depth;
+ int bogusFont;
+
+ if (!XtIsRealized(fsb)) return;
+
+ XtVaGetValues(fsb->fsb.preview_child, XmNheight, &height,
+ XmNdepth, &depth, NULL);
+
+ if (fsb->fsb.gstate == 0) {
+ XDPSSetContextParameters(fsb->fsb.context, XtScreen(fsb), depth,
+ XtWindow(fsb->fsb.preview_child), height,
+ (XDPSStandardColormap *) NULL,
+ (XDPSStandardColormap *) NULL,
+ XDPSContextScreenDepth | XDPSContextDrawable |
+ XDPSContextRGBMap | XDPSContextGrayMap);
+ XDPSCaptureContextGState(fsb->fsb.context, &fsb->fsb.gstate);
+ } else XDPSSetContextGState(fsb->fsb.context, fsb->fsb.gstate);
+
+ _DPSFClearWindow(fsb->fsb.context);
+
+ if (override) {
+ if (fsb->fsb.current_family_multiple ||
+ fsb->fsb.current_face_multiple ||
+ fsb->fsb.current_size_multiple) return;
+ f = fsb->fsb.currently_previewed;
+ size = fsb->fsb.currently_previewed_size;
+ b = fsb->fsb.currently_previewed_blend;
+ }
+
+ if (!override || f == NULL || size == 0.0) {
+ if (!XmListGetSelectedPos(fsb->fsb.family_scrolled_list_child,
+ &selectList, &selectCount)) return;
+ if (selectCount == 0 ||
+ *selectList < 1 || *selectList > fsb->fsb.family_count) return;
+
+ for (i = 1; i < *selectList; i++) ff = ff->next;
+
+ XtFree((XtPointer) selectList);
+
+ if (!XmListGetSelectedPos(fsb->fsb.face_scrolled_list_child,
+ &selectList, &selectCount)) return;
+ if (selectCount == 0 ||
+ *selectList < 1 ||
+ *selectList > ff->font_count + ff->blend_count) return;
+
+ f = ff->fonts;
+ n = 0;
+ while (1) {
+ n += f->blend_count + 1;
+ if (n >= *selectList) {
+ n -= f->blend_count;
+ if (n == *selectList) b = NULL;
+ else for (b = f->blend_data->blends;
+ n < *selectList - 1; b = b->next) n++;
+ break;
+ }
+ f = f->next;
+ }
+
+ XtFree((XtPointer) selectList);
+
+ XtVaGetValues(fsb->fsb.size_text_field_child,
+ XmNvalue, &chSize, NULL);
+
+ if (chSize == NULL || *chSize == '\0') return;
+ size = atof(chSize);
+ }
+
+ if (size <= 0.0) return;
+
+ fsb->fsb.currently_previewed = f;
+ fsb->fsb.currently_previewed_blend = b;
+ fsb->fsb.currently_previewed_size = size;
+
+ if (!_FSBDownloadFontIfNecessary(f, fsb)) return;
+
+ if (b == NULL) fontName = f->font_name;
+ else fontName = b->font_name;
+
+ if (fsb->fsb.preview_string == NULL) {
+ _DPSFPreviewString(fsb->fsb.context, fontName, size,
+ f->full_name, height, &bogusFont);
+ } else _DPSFPreviewString(fsb->fsb.context, fontName, size,
+ fsb->fsb.preview_string, height, &bogusFont);
+ if (bogusFont) {
+ _FSBBogusFont(fsb, f);
+ }
+}
+
+static void DoValueChangedCallback(FontSelectionBoxWidget fsb)
+{
+ String afm = NULL;
+ FSBValidateCallbackRec cb;
+
+ if (fsb->fsb.get_afm) {
+ if (fsb->fsb.currently_selected_face == NULL) afm = NULL;
+ else afm = FindAFM((Widget) fsb,
+ fsb->fsb.currently_selected_face->font_name);
+ }
+
+ (void) Verify(fsb, &cb, afm, False);
+ cb.reason = FSBValueChanged;
+
+ XtCallCallbackList((Widget) fsb, fsb->fsb.value_changed_callback, &cb);
+}
+
+static void ValueChanged(FontSelectionBoxWidget fsb)
+{
+ if (fsb->fsb.auto_preview) DoPreview(fsb, False);
+ DoValueChangedCallback(fsb);
+}
+
+/* ARGSUSED */
+
+static void PreviewText(
+ Widget widget,
+ XtPointer clientData, XtPointer callData)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) clientData;
+ XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *) callData;
+
+ if (!fsb->fsb.preview_fixed) {
+ XSetWindowAttributes att;
+ att.bit_gravity = ForgetGravity;
+ XChangeWindowAttributes(XtDisplay(fsb),
+ XtWindow(fsb->fsb.preview_child),
+ CWBitGravity, &att);
+ fsb->fsb.preview_fixed = True;
+ }
+
+ if (cb != NULL && cb->event->type == Expose &&
+ cb->event->xexpose.count != 0) return;
+
+ DoPreview(fsb, True);
+}
+
+/* ARGSUSED */
+
+static void PreviewCallback(
+ Widget widget,
+ XtPointer clientData, XtPointer callData)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) clientData;
+
+ DoPreview(fsb, False);
+}
+
+/* ARGSUSED */
+
+static void DismissSamplerCallback(
+ Widget widget,
+ XtPointer clientData, XtPointer callData)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) clientData;
+
+ fsb->fsb.show_sampler = False;
+}
+
+static void ShowSampler(FontSelectionBoxWidget fsb)
+{
+ int i;
+ Arg args[2];
+ Widget s;
+
+ if (fsb->fsb.sampler == NULL) {
+ FSBCreateSamplerCallbackRec cs;
+
+ cs.sampler_shell = NULL;
+
+ XtCallCallbackList((Widget) fsb, fsb->fsb.create_sampler_callback,
+ (XtPointer) &cs);
+
+ if (cs.sampler_shell == NULL || cs.sampler == NULL) {
+ fsb->fsb.sampler =
+ XtCreatePopupShell("samplerShell",
+ transientShellWidgetClass,
+ (Widget) fsb, (ArgList) NULL, 0);
+ i = 0;
+ XtSetArg(args[i], XtNfontSelectionBox, fsb); i++;
+ s = XtCreateManagedWidget("sampler", fontSamplerWidgetClass,
+ fsb->fsb.sampler, args, i);
+ XtAddCallback(s, XtNdismissCallback,
+ DismissSamplerCallback, (XtPointer) fsb);
+ } else {
+ fsb->fsb.sampler = cs.sampler_shell;
+ XtAddCallback(cs.sampler, XtNdismissCallback,
+ DismissSamplerCallback, (XtPointer) fsb);
+ }
+ }
+ XtPopup(fsb->fsb.sampler, XtGrabNone);
+ XRaiseWindow(XtDisplay(fsb->fsb.sampler), XtWindow(fsb->fsb.sampler));
+ fsb->fsb.show_sampler = True;
+}
+
+static void ShowCreator(FontSelectionBoxWidget fsb)
+{
+ int i;
+ Arg args[2];
+ FSBCreateCreatorCallbackRec cc;
+
+ if (fsb->fsb.creator == NULL) {
+
+ cc.creator_shell = NULL;
+
+ XtCallCallbackList((Widget) fsb, fsb->fsb.create_creator_callback,
+ (XtPointer) &cc);
+
+ if (cc.creator_shell == NULL || cc.creator == NULL) {
+ cc.creator_shell =
+ XtCreatePopupShell("creatorShell",
+ transientShellWidgetClass,
+ (Widget) fsb, (ArgList) NULL, 0);
+ i = 0;
+ XtSetArg(args[i], XtNfontSelectionBox, fsb); i++;
+ cc.creator =
+ XtCreateManagedWidget("creator", fontCreatorWidgetClass,
+ cc.creator_shell, args, i);
+ }
+ fsb->fsb.creator_shell = cc.creator_shell;
+ fsb->fsb.creator = cc.creator;
+ }
+
+ XtPopup(fsb->fsb.creator_shell, XtGrabNone);
+ XRaiseWindow(XtDisplay(fsb->fsb.creator_shell),
+ XtWindow(fsb->fsb.creator_shell));
+
+ _FSBSetCreatorFamily(fsb->fsb.creator, fsb->fsb.currently_selected_family);
+}
+
+/* ARGSUSED */
+
+static void ShowCreatorCallback(
+ Widget widget,
+ XtPointer clientData, XtPointer callData)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) clientData;
+
+ ShowCreator(fsb);
+}
+
+/* ARGSUSED */
+
+static void ShowSamplerCallback(
+ Widget widget,
+ XtPointer clientData, XtPointer callData)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) clientData;
+
+ ShowSampler(fsb);
+}
+
+/* ARGSUSED */
+
+static void PreviewDoubleClick(
+ Widget widget,
+ XtPointer clientData, XtPointer callData)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) clientData;
+
+ DoPreview(fsb, False);
+}
+
+/* ARGSUSED */
+
+static void ResizePreview(
+ Widget widget,
+ XtPointer clientData, XtPointer callData)
+{
+ Dimension height;
+ Cardinal depth;
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) clientData;
+
+ if (!XtIsRealized(widget) || fsb->fsb.gstate == 0) return;
+
+ XtVaGetValues(widget, XmNheight, &height, XmNdepth, &depth, NULL);
+
+ XDPSSetContextGState(fsb->fsb.context, fsb->fsb.gstate);
+
+ XDPSSetContextParameters(fsb->fsb.context, XtScreen(widget), depth,
+ XtWindow(widget), height,
+ (XDPSStandardColormap *) NULL,
+ (XDPSStandardColormap *) NULL,
+ XDPSContextScreenDepth | XDPSContextDrawable);
+
+ _DPSFReclip(fsb->fsb.context);
+
+ XDPSUpdateContextGState(fsb->fsb.context, fsb->fsb.gstate);
+}
+
+static String FindAFMRecursive(
+ Widget w,
+ String name,
+ Boolean recur)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) w;
+ int count;
+ char **names, **files;
+ String ret, ch;
+
+ if (name == NULL) return NULL;
+
+ count = ListPSResourceFiles(fsb->fsb.resource_path_override,
+ fsb->fsb.default_resource_path,
+ PSResFontAFM,
+ name,
+ &names, &files);
+
+ if (count == 0 && recur) {
+ for (ch = name; *ch != '_' && *ch != '\0'; ch++) {}
+ if (*ch == '\0') return NULL;
+ *ch = '\0';
+ ret = FindAFMRecursive(w, name, False);
+ *ch = '_';
+ return ret;
+ }
+
+ if (count == 0) return NULL;
+ ret = files[0];
+ free(names);
+ free(files);
+ return ret;
+}
+
+static String FindAFM(Widget w, String name)
+{
+ return FindAFMRecursive(w, name, True);
+}
+
+static String FindFontFileRecursive(
+ Widget w,
+ String name,
+ Boolean recur)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) w;
+ int count;
+ char **names, **files;
+ String ret, ch;
+
+ if (name == NULL) return NULL;
+
+ count = ListPSResourceFiles(fsb->fsb.resource_path_override,
+ fsb->fsb.default_resource_path,
+ PSResFontOutline,
+ name,
+ &names, &files);
+
+ if (count == 0 && recur) {
+ for (ch = name; *ch != '_' && *ch != '\0'; ch++) {}
+ if (*ch == '\0') return NULL;
+ *ch = '\0';
+ ret = FindFontFileRecursive(w, name, False);
+ *ch = '_';
+ return ret;
+ }
+
+ if (count == 0) return NULL;
+ ret = files[0];
+ free(names);
+ free(files);
+ return ret;
+}
+
+static String FindFontFile(Widget w, String name)
+{
+ return FindFontFileRecursive(w, name, True);
+}
+
+static Boolean Verify(
+ FontSelectionBoxWidget fsb,
+ FSBValidateCallbackRec *cb,
+ String afm,
+ Boolean doIt)
+{
+ char *chSize;
+ int i;
+
+ if (fsb->fsb.current_family_multiple) {
+ cb->family = NULL;
+ cb->family_selection = FSBMultiple;
+ } else if (fsb->fsb.currently_selected_family == NULL) {
+ cb->family = NULL;
+ cb->family_selection = FSBNone;
+ } else {
+ cb->family = fsb->fsb.currently_selected_family->family_name;
+ cb->family_selection = FSBOne;
+ }
+
+ if (fsb->fsb.current_face_multiple) {
+ cb->face = NULL;
+ cb->face_selection = FSBMultiple;
+ } else if (fsb->fsb.currently_selected_face == NULL) {
+ cb->face = NULL;
+ cb->face_selection = FSBNone;
+ } else {
+ cb->face = fsb->fsb.currently_selected_face->face_name;
+ cb->face_selection = FSBOne;
+ }
+
+ if (cb->family_selection == FSBMultiple ||
+ cb->face_selection == FSBMultiple) {
+ cb->name = NULL;
+ cb->name_selection = FSBMultiple;
+ } else if (fsb->fsb.currently_selected_face == NULL) {
+ cb->name = NULL;
+ cb->name_selection = FSBNone;
+ } else {
+ if (fsb->fsb.currently_selected_blend != NULL) {
+ cb->name = fsb->fsb.currently_selected_blend->font_name;
+ } else cb->name = fsb->fsb.currently_selected_face->font_name;
+ cb->name_selection = FSBOne;
+ }
+
+ if (fsb->fsb.current_size_multiple) {
+ cb->size = 0.0;
+ cb->size_selection = FSBMultiple;
+ } else {
+ XtVaGetValues(fsb->fsb.size_text_field_child, XmNvalue, &chSize, NULL);
+
+ if (chSize == NULL || *chSize == '\0') {
+ cb->size = 0.0;
+ cb->size_selection = FSBNone;
+ } else {
+ cb->size = atof(chSize);
+ cb->size_selection = FSBOne;
+ }
+ }
+
+ cb->afm_filename = afm;
+ cb->afm_present = (afm != NULL);
+ cb->doit = True;
+
+ if (fsb->fsb.currently_selected_blend == NULL) {
+ cb->blend = cb->base_name = NULL;
+ for (i = 0; i < MAX_AXES; i++) cb->axis_percent[i] = 0.0;
+ } else {
+ cb->blend = fsb->fsb.currently_selected_blend->blend_name;
+ cb->base_name = fsb->fsb.currently_selected_face->font_name;
+ for (i = 0; i < MAX_AXES; i++) {
+ cb->axis_percent[i] = fsb->fsb.currently_selected_blend->data[i];
+ }
+ }
+
+ if (doIt) XtCallCallbackList((Widget) fsb, fsb->fsb.validate_callback, cb);
+ return cb->doit;
+}
+
+static Boolean VerifyAndCallback(
+ FontSelectionBoxWidget fsb,
+ FSBCallbackReason reason,
+ XtCallbackList callback)
+{
+ String afm = NULL;
+ FSBValidateCallbackRec cb;
+ FontRec *fsave, *face;
+
+ if (fsb->fsb.get_afm) {
+ if (fsb->fsb.currently_selected_face == NULL) afm = NULL;
+ else afm = FindAFM((Widget) fsb,
+ fsb->fsb.currently_selected_face->font_name);
+ }
+
+ DoPreview(fsb, False);
+
+ cb.reason = reason;
+ if (!Verify(fsb, &cb, afm, True)) return False;
+
+ fsb->fsb.font_family_multiple = fsb->fsb.current_family_multiple;
+ if (!fsb->fsb.font_family_multiple &&
+ fsb->fsb.currently_selected_family != NULL) {
+ fsb->fsb.font_family =
+ fsb->fsb.currently_selected_family->family_name;
+ } else fsb->fsb.font_family = NULL;
+
+ fsb->fsb.font_face_multiple = fsb->fsb.current_face_multiple;
+ if (!fsb->fsb.font_face_multiple &&
+ fsb->fsb.currently_selected_face != NULL) {
+ fsb->fsb.font_face = fsb->fsb.currently_selected_face->face_name;
+ } else fsb->fsb.font_face = NULL;
+
+ fsb->fsb.font_name_multiple =
+ fsb->fsb.font_family_multiple || fsb->fsb.font_face_multiple;
+ if (!fsb->fsb.font_name_multiple &&
+ fsb->fsb.currently_selected_face != NULL) {
+ fsb->fsb.font_name = fsb->fsb.currently_selected_face->font_name;
+ } else fsb->fsb.font_name = NULL;
+
+ fsb->fsb.font_size_multiple = fsb->fsb.current_size_multiple;
+ if (!fsb->fsb.font_size_multiple) {
+ fsb->fsb.font_size = cb.size;
+ }
+
+ if (fsb->fsb.currently_selected_blend != NULL) {
+ fsb->fsb.font_blend = fsb->fsb.currently_selected_blend->blend_name;
+ } else fsb->fsb.font_blend = NULL;
+
+ if (fsb->fsb.undef_unused_fonts) {
+ fsave = fsb->fsb.currently_previewed;
+ if (fsb->fsb.make_fonts_shared) {
+ fsb->fsb.currently_previewed = NULL;
+ }
+ UndefUnusedFonts((Widget)fsb);
+ fsb->fsb.currently_previewed = fsave;
+ face = fsb->fsb.currently_selected_face;
+ if (face != NULL && !face->resident) {
+ face->resident = True;
+ if (fsb->fsb.make_fonts_shared) {
+ (void) DownloadFont(fsb, face->font_name,
+ fsb->fsb.context, True);
+ /* If making it shared, be sure to synchronize with
+ the caller who might be using a different context */
+ DPSWaitContext(fsb->fsb.context);
+ }
+ }
+ }
+
+ XtCallCallbackList((Widget) fsb, callback, &cb);
+ return True;
+}
+
+/* ARGSUSED */
+
+static void OKCallback(
+ Widget widget,
+ XtPointer clientData, XtPointer callData)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) clientData;
+
+ if (!VerifyAndCallback(fsb, FSBOK, fsb->fsb.ok_callback)) return;
+ if (XtIsShell(XtParent(fsb))) XtPopdown(XtParent(fsb));
+ WriteBlends(fsb);
+ DesensitizeReset(fsb);
+ if (fsb->fsb.show_sampler) XtPopdown(fsb->fsb.sampler);
+}
+
+/* ARGSUSED */
+
+static void ApplyCallback(
+ Widget widget,
+ XtPointer clientData, XtPointer callData)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) clientData;
+
+ (void) VerifyAndCallback(fsb, FSBApply, fsb->fsb.apply_callback);
+ WriteBlends(fsb);
+ DesensitizeReset(fsb);
+}
+
+static void ResetFSB(
+ FontSelectionBoxWidget fsb,
+ FSBCallbackReason reason)
+{
+ FSBCallbackRec cb;
+ int i;
+
+ fsb->fsb.currently_previewed = NULL;
+ fsb->fsb.currently_previewed_size = fsb->fsb.currently_selected_size = 0.0;
+ SetUpCurrentSelections(fsb);
+ if (fsb->fsb.undef_unused_fonts) UndefUnusedFonts((Widget)fsb);
+
+ cb.reason = reason;
+ if (fsb->fsb.font_family_multiple) {
+ cb.family = NULL;
+ cb.family_selection = FSBMultiple;
+ } else if (fsb->fsb.font_family == NULL) {
+ cb.family = NULL;
+ cb.family_selection = FSBNone;
+ } else {
+ cb.family = fsb->fsb.font_family;
+ cb.family_selection = FSBOne;
+ }
+
+ if (fsb->fsb.font_face_multiple) {
+ cb.face = NULL;
+ cb.face_selection = FSBMultiple;
+ } else if (fsb->fsb.font_face == NULL) {
+ cb.face = NULL;
+ cb.face_selection = FSBNone;
+ } else {
+ cb.face = fsb->fsb.font_face;
+ cb.face_selection = FSBOne;
+ }
+
+ if (cb.family_selection == FSBMultiple ||
+ cb.face_selection == FSBMultiple) {
+ cb.name = NULL;
+ cb.name_selection = FSBMultiple;
+ } else if (fsb->fsb.font_face == NULL) {
+ cb.name = NULL;
+ cb.name_selection = FSBNone;
+ } else {
+ cb.name = fsb->fsb.font_name;
+ cb.name_selection = FSBOne;
+ }
+
+ if (fsb->fsb.font_size_multiple) {
+ cb.size = 0.0;
+ cb.size_selection = FSBMultiple;
+ } else {
+ cb.size = fsb->fsb.font_size;
+ cb.size_selection = FSBOne;
+ }
+
+ cb.afm_filename = NULL;
+ cb.afm_present = False;
+
+ cb.blend = fsb->fsb.font_blend;
+ if (cb.blend == NULL || fsb->fsb.currently_selected_blend == NULL) {
+ cb.base_name = NULL;
+ for (i = 0; i < MAX_AXES; i++) cb.axis_percent[i] = 0;
+ } else {
+ cb.base_name = fsb->fsb.currently_selected_face->font_name;
+ for (i = 0; i < MAX_AXES; i++) {
+ cb.axis_percent[i] = fsb->fsb.currently_selected_blend->data[i];
+ }
+ }
+
+ if (reason == FSBReset) {
+ XtCallCallbackList((Widget) fsb, fsb->fsb.reset_callback, &cb);
+ } else XtCallCallbackList((Widget) fsb, fsb->fsb.cancel_callback, &cb);
+}
+
+/* ARGSUSED */
+
+static void ResetCallback(
+ Widget widget,
+ XtPointer clientData, XtPointer callData)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) clientData;
+
+ ResetFSB(fsb, FSBReset);
+ DesensitizeReset(fsb);
+}
+
+/* ARGSUSED */
+
+static void CancelCallback(
+ Widget widget,
+ XtPointer clientData, XtPointer callData)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) clientData;
+
+ ResetFSB(fsb, FSBCancel);
+ if (XtIsShell(XtParent(fsb))) XtPopdown(XtParent(fsb));
+ DesensitizeReset(fsb);
+ if (fsb->fsb.show_sampler) XtPopdown(fsb->fsb.sampler);
+}
+
+/* There's a problem; sometimes the change has already been made in the field,
+ and sometimes it hasn't. The times when it has seem to correspond to
+ making changes with the size option menu, so we use this disgusting
+ global flag to notice when this happens. We also use this to tell whether
+ or not the change is coming from internal to the widget or as a result
+ of user interaction. */
+
+static Boolean changingSize = False;
+
+/* ARGSUSED */
+
+static void SizeSelect(
+ Widget widget,
+ XtPointer clientData, XtPointer callData)
+{
+ String value;
+ Widget option;
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) clientData;
+ char *ch;
+
+ XtVaGetValues(widget, XmNvalue, &value, NULL);
+
+ if (value == NULL) option = fsb->fsb.other_size;
+ else {
+ if (value[0] != '\0' && fsb->fsb.current_size_multiple) {
+ fsb->fsb.current_size_multiple = False;
+ UnmanageSizeMultiple(fsb);
+ }
+ for (ch = value; *ch != '\0'; ch++) if (*ch == '.') *ch = '-';
+
+ option = XtNameToWidget(fsb->fsb.size_menu, value);
+ if (option == NULL) option = fsb->fsb.other_size;
+ }
+
+ XtVaSetValues(fsb->fsb.size_option_menu_child,
+ XmNmenuHistory, option, NULL);
+
+ if (value != NULL && value[0] != '\0') {
+ fsb->fsb.currently_selected_size = atof(value);
+ } else fsb->fsb.currently_selected_size = 0.0;
+
+ if (!changingSize) SensitizeReset(fsb);
+ fsb->fsb.current_size_multiple = False;
+}
+
+/* ARGSUSED */
+
+static void TextVerify(
+ Widget widget,
+ XtPointer clientData, XtPointer callData)
+{
+ int i;
+ XmTextVerifyPtr v = (XmTextVerifyPtr) callData;
+ char ch, *cp;
+ int decimalPoints = 0;
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) clientData;
+
+ if (changingSize) return; /* We know what we're doing; allow it */
+
+ /* Should probably look at format field, but seems to contain garbage */
+
+ if (v->text->length == 0) return;
+
+ if (v->text->length == 1) {
+ ch = v->text->ptr[0];
+ if (ch == 'p' || ch == 'P') {
+ XtCallCallbacks(fsb->fsb.preview_button_child,
+ XmNactivateCallback, NULL);
+ v->doit = False;
+ return;
+ }
+ }
+
+ for (i = 0; i < v->text->length; i++) {
+ ch = v->text->ptr[i];
+ if (ch == '.') decimalPoints++;
+ else if (!isdigit(ch)) {
+ v->doit = False;
+ return;
+ }
+ }
+
+ if (decimalPoints > 1) {
+ v->doit = False;
+ return;
+ }
+
+ XtVaGetValues(widget, XmNvalue, &cp, NULL);
+
+ for (/**/; *cp != '\0'; cp++) {
+ if (*cp == '.') decimalPoints++;
+ }
+
+ if (decimalPoints > 1) v->doit = False;
+}
+
+/* ARGSUSED */
+
+static void SetSize(
+ Widget widget,
+ XtPointer clientData, XtPointer callData)
+{
+ char buf[20];
+ char *ch;
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) clientData;
+
+ if (fsb->fsb.current_size_multiple) {
+ fsb->fsb.current_size_multiple = False;
+ UnmanageSizeMultiple(fsb);
+ }
+
+ strcpy(buf, XtName(widget));
+ for (ch = buf; *ch != '\0'; ch++) if (*ch == '-') *ch++ = '.';
+
+ changingSize = True;
+ XtVaSetValues(fsb->fsb.size_text_field_child, XmNvalue, buf, NULL);
+ changingSize = False;
+
+ SensitizeReset(fsb);
+ ValueChanged(fsb);
+}
+
+/* This makes sure the selected item is visible */
+
+static void ListSelectPos(
+ Widget w,
+ int pos,
+ Boolean notify)
+{
+ int topPos, items, visible;
+
+ XmListSelectPos(w, pos, notify);
+
+ XtVaGetValues(w, XmNtopItemPosition, &topPos,
+ XmNvisibleItemCount, &visible, XmNitemCount, &items, NULL);
+
+ if (pos >= topPos && pos < topPos + visible) return;
+ topPos = pos - (visible-1)/2;
+ if (topPos + visible > items) topPos = items - visible + 1;
+ if (topPos < 1) topPos = 1;
+
+ XtVaSetValues(w, XmNtopItemPosition, topPos, NULL);
+}
+
+/* The following function Copyright 1987, 1988 by Digital Equipment
+Corporation, Maynard, Massachusetts, and the Massachusetts Institute of
+Technology, Cambridge, Massachusetts. */
+
+static String GetRootDirName(String buf)
+{
+#ifndef X_NOT_POSIX
+ uid_t uid;
+#else
+ int uid;
+ extern int getuid();
+#ifndef SYSV386
+ extern struct passwd *getpwuid(), *getpwnam();
+#endif
+#endif
+ struct passwd *pw;
+ static char *ptr = NULL;
+
+ if (ptr == NULL) {
+ if (!(ptr = getenv("HOME"))) {
+ if ((ptr = getenv("USER")) != NULL) pw = getpwnam(ptr);
+ else {
+ uid = getuid();
+ pw = getpwuid(uid);
+ }
+ if (pw) ptr = pw->pw_dir;
+ else {
+ ptr = NULL;
+ *buf = '\0';
+ }
+ }
+ }
+
+ if (ptr)
+ (void) strcpy(buf, ptr);
+
+ buf += strlen(buf);
+ *buf = '/';
+ buf++;
+ *buf = '\0';
+ return buf;
+}
+
+static void WriteBlendLine(
+ FILE *f,
+ String family, String face, String blend, String name,
+ int axes,
+ float *p)
+{
+ register char *ch;
+ int i;
+
+ ch = family;
+ while (*ch != '\0') {
+ if (*ch == ',' || *ch == '\\') (void) putc('\\', f);
+ (void) putc(*ch++, f);
+ }
+ putc(',', f);
+ ch = face;
+ while (*ch != '\0') {
+ if (*ch == ',' || *ch == '\\') (void) putc('\\', f);
+ (void) putc(*ch++, f);
+ }
+ putc(',', f);
+ ch = blend;
+ while (*ch != '\0') {
+ if (*ch == ',' || *ch == '\\') (void) putc('\\', f);
+ (void) putc(*ch++, f);
+ }
+ (void) putc(',', f);
+ ch = name;
+ while (*ch != '\0') {
+ if (*ch == ',' || *ch == '\\') (void) putc('\\', f);
+ (void) putc(*ch++, f);
+ }
+ for (i = 0; i < axes; i++) fprintf(f, ",%f", p[i]);
+ (void) putc('\n', f);
+}
+
+static void WriteBlends(FontSelectionBoxWidget fsb)
+{
+ FontFamilyRec *ff;
+ FontRec *f;
+ BlendRec *b;
+ String blendEnv;
+ char homeDir[PATH_BUF_SIZE];
+ FILE *blendFile = NULL;
+ char fileName[PATH_BUF_SIZE];
+
+ if (!fsb->fsb.blends_changed) return;
+
+ blendEnv = getenv("DPSFONTRC");
+
+ if (blendEnv != NULL) blendFile = fopen(blendEnv, "w");
+
+ if (blendFile == NULL) {
+ (void) GetRootDirName(homeDir);
+ sprintf(fileName, "%s/.dpsfontrc", homeDir);
+ blendFile = fopen(fileName, "w");
+
+ if (blendFile == NULL) return;
+ }
+
+ for (ff = fsb->fsb.known_families; ff != NULL; ff = ff->next) {
+ for (f = ff->fonts; f != NULL; f = f->next) {
+ if (f->blend_data != NULL) {
+ for (b = f->blend_data->blends; b != NULL; b = b->next) {
+ WriteBlendLine(blendFile, ff->family_name, f->face_name,
+ b->blend_name, b->font_name,
+ f->blend_data->num_axes, b->data);
+ }
+ }
+ }
+ }
+
+ fclose(blendFile);
+ fsb->fsb.blends_changed = False;
+}
+
+static Boolean ParseBlendLine(
+ String buf, String family, String face, String blend, String name,
+ float *p)
+{
+ char *src, *dst;
+ int i;
+ float f;
+
+ src = buf;
+ dst = family;
+ while (*src != ',' && *src != '\0') {
+ if (*src == '\\') src++;
+ if (*src == '\0') return False;
+ *dst++ = *src++;
+ }
+ if (*src == '\0') return False;
+ *dst = '\0';
+ src++;
+ dst = face;
+ while (*src != ',' && *src != '\0') {
+ if (*src == '\\') src++;
+ if (*src == '\0') return False;
+ *dst++ = *src++;
+ }
+ if (*src == '\0') return False;
+ *dst = '\0';
+ src++;
+ dst = blend;
+ while (*src != ',' && *src != '\0') {
+ if (*src == '\\') src++;
+ if (*src == '\0') return False;
+ *dst++ = *src++;
+ }
+ if (*src == '\0') return False;
+ *dst = '\0';
+ src++;
+ dst = name;
+ while (*src != ',' && *src != '\0') {
+ if (*src == '\\') src++;
+ if (*src == '\0') return False;
+ *dst++ = *src++;
+ }
+ if (*src == '\0') return False;
+ *dst = '\0';
+ for (i = 0; i < MAX_AXES; i++) {
+ src++;
+ if (!ScanFloat(src, &f, &src)) {
+ for (/**/; i < MAX_AXES; i++) p[i] = 0;
+ return True;;
+ }
+ else p[i] = f;
+ }
+ return True;
+}
+
+static void ReadBlends(FontSelectionBoxWidget fsb)
+{
+ String blendEnv;
+ char homeDir[PATH_BUF_SIZE];
+ FILE *blendFile = NULL;
+ char fileName[PATH_BUF_SIZE];
+#define BUF 256
+ char buf[BUF+1], family[BUF+1], face[BUF+1], blend[BUF+1], name[BUF+1];
+ char *cfamily, *cface;
+ float p[MAX_AXES];
+ FontRec *f;
+ FontFamilyRec *ff = 0;
+ BlendRec *b, *newb, **lastb;
+ char *spaceBlend;
+ char *lastFamily = NULL;
+ int cmp, i;
+
+ blendEnv = getenv("DPSFONTRC");
+
+ if (blendEnv != NULL) blendFile = fopen(blendEnv, "r");
+
+ if (blendFile == NULL) {
+ (void) GetRootDirName(homeDir);
+ sprintf(fileName, "%s/.dpsfontrc", homeDir);
+ blendFile = fopen(fileName, "r");
+
+ if (blendFile == NULL) return;
+ }
+
+ while (1) {
+ if (fgets(buf, BUF, blendFile) == NULL) {
+ fclose(blendFile);
+ return;
+ }
+ if (ParseBlendLine(buf, family, face, blend, name, p)) {
+ cfamily = Canonical(family);
+ if (cfamily != lastFamily) {
+ for (ff = fsb->fsb.known_families;
+ ff != NULL && ff->family_name != cfamily;
+ ff = ff->next) {}
+ }
+ if (ff == NULL) continue;
+ lastFamily = cfamily;
+ cface = Canonical(face);
+ for (f = ff->fonts; f != NULL && f->face_name != cface;
+ f = f->next) {}
+ /* If the blend data is NULL, we have a blend line for a font
+ that we don't believe is a MM font. Ignore it */
+ if (f != NULL && f->blend_data != NULL) {
+ lastb = &f->blend_data->blends;
+ cmp = -1;
+ for (b = f->blend_data->blends; b != NULL; b = b->next) {
+ cmp = strcmp(blend, b->blend_name);
+ if (cmp < 0) break;
+ lastb = &b->next;
+ }
+ if (cmp != 0) {
+ newb = XtNew(BlendRec);
+ newb->blend_name = Canonical(blend);
+ newb->CS_blend_name = CS(newb->blend_name, (Widget) fsb);
+
+ spaceBlend = (char *) XtMalloc(strlen(blend) + 4);
+ spaceBlend[0] = spaceBlend[1] = spaceBlend[2] = ' ';
+ strcpy(spaceBlend+3, blend);
+ newb->CS_space_blend_name = CS(spaceBlend, (Widget) fsb);
+ XtFree((XtPointer) spaceBlend);
+
+ for (i = 0; i < MAX_AXES; i++) newb->data[i] = p[i];
+ newb->font_name = Canonical(name);
+
+ f->blend_count++;
+ ff->blend_count++;
+
+ newb->next = b;
+ *lastb = newb;
+ }
+ }
+ }
+ }
+}
+
+static void SetUpFaceList(
+ FontSelectionBoxWidget fsb,
+ FontFamilyRec *ff)
+{
+ FontRec *f;
+ BlendRec *b;
+ XmString *CSfaces;
+ Boolean multiple = False;
+ int i;
+
+ for (f = ff->fonts; f != NULL; f = f->next) {
+ if (f->blend_data != NULL) {
+ multiple = True;
+ break;
+ }
+ }
+ if (multiple) ManageMultipleMaster(fsb);
+ else UnmanageMultipleMaster(fsb);
+
+ CSfaces = (XmString *) XtCalloc(ff->font_count + ff->blend_count,
+ sizeof(XmString));
+
+ i = 0;
+ for (f = ff->fonts; f != NULL; f = f->next) {
+ CSfaces[i++] = f->CS_face_name;
+ if (f->blend_data != NULL) {
+ for (b = f->blend_data->blends; b != NULL; b = b->next) {
+ CSfaces[i++] = b->CS_space_blend_name;
+ }
+ }
+ }
+
+ XtVaSetValues(fsb->fsb.face_scrolled_list_child,
+ XmNitemCount, ff->font_count + ff->blend_count,
+ XmNitems, CSfaces, NULL);
+ XtFree((XtPointer) CSfaces);
+}
+
+/* ARGSUSED */
+
+static void DeleteMessage(
+ Widget widget,
+ XtPointer clientData, XtPointer callData)
+{
+ XtDestroyWidget(widget);
+}
+
+static void FlushFont(
+ FontSelectionBoxWidget fsb,
+ FontRec *font)
+{
+ FontRec *f = 0, *f1;
+ FontFamilyRec *ff, *ff1;
+ Boolean previewedFamily = False;
+
+ for (ff = fsb->fsb.known_families; ff != NULL; ff = ff->next) {
+ for (f = ff->fonts; f != NULL; f = f->next) {
+ if (f == font) goto FOUND_BOGUS;
+ }
+ }
+
+FOUND_BOGUS:
+ if (f != NULL) {
+ for (f1 = ff->fonts; f1 != NULL; f1 = f1->next) {
+ if (f1 == fsb->fsb.currently_previewed) {
+ previewedFamily = True;
+ break;
+ }
+ }
+
+ if (ff->fonts == f) {
+ ff->fonts = f->next;
+ } else {
+ for (f1 = ff->fonts; f1 != NULL && f1->next != f; f1 = f1->next) {}
+ if (f1 != NULL) f1->next = f->next;
+ }
+
+ ff->font_count--;
+ ff->blend_count -= f->blend_count;
+
+ if (f == fsb->fsb.currently_selected_face) {
+ fsb->fsb.currently_selected_face = NULL;
+ fsb->fsb.currently_selected_blend = NULL;
+ }
+
+ if (previewedFamily) SetUpFaceList(fsb, ff);
+
+ if (f == fsb->fsb.currently_previewed) {
+ fsb->fsb.currently_previewed = NULL;
+ fsb->fsb.currently_previewed_blend = NULL;
+ ValueChanged(fsb);
+ }
+
+ /* We do not free the FontRec or FontFamilyRec. In the long
+ run we don't expect to leak much storage this way, since we
+ shouldn't have many bogus fonts, and invalidating every
+ reference here, in the sampler, and in the creator isn't
+ worth the small storage waste. */
+
+ if (ff->fonts == NULL) {
+ if (fsb->fsb.known_families == ff) {
+ fsb->fsb.known_families = ff->next;
+ } else {
+ for (ff1 = fsb->fsb.known_families;
+ ff1 != NULL && ff1->next != ff; ff1 = ff1->next) {}
+ if (ff1 != NULL) ff1->next = ff->next;
+ }
+
+ fsb->fsb.family_count--;
+
+ if (ff == fsb->fsb.currently_selected_family) {
+ fsb->fsb.currently_selected_family = NULL;
+ }
+
+ DisplayFontFamilies(fsb);
+ }
+ }
+}
+
+void _FSBFlushFont(
+ FontSelectionBoxWidget fsb,
+ FontRec *font)
+{
+ if (font == fsb->fsb.currently_previewed) _FSBBogusFont(fsb, font);
+ else FlushFont(fsb, font);
+}
+
+void _FSBBogusFont(
+ FontSelectionBoxWidget fsb,
+ FontRec *font)
+{
+ Widget message, w;
+
+ message = XmCreateInformationDialog((Widget) fsb, "invalidFontMessage",
+ (ArgList) NULL, 0);
+ w = XmMessageBoxGetChild(message, XmDIALOG_CANCEL_BUTTON);
+ XtUnmanageChild(w);
+ w = XmMessageBoxGetChild(message, XmDIALOG_HELP_BUTTON);
+ XtUnmanageChild(w);
+ XtAddCallback(message, XmNokCallback, DeleteMessage, (XtPointer) NULL);
+
+ XtManageChild(message);
+
+ /* Now get this blasted thing out of here */
+ FlushFont(fsb, font);
+}
+
+void _FSBSetUpFaceList(
+ FontSelectionBoxWidget fsb,
+ Bool redisplay)
+{
+ FontRec *f;
+ BlendRec *b;
+ int i;
+
+ SetUpFaceList(fsb, fsb->fsb.currently_selected_family);
+
+ f = fsb->fsb.currently_selected_family->fonts;
+ i = 1;
+ while (f != NULL) {
+ if (f == fsb->fsb.currently_selected_face) {
+ if (f->blend_data != NULL) {
+ b = f->blend_data->blends;
+ if (fsb->fsb.currently_selected_blend != NULL) {
+ i++;
+ while (b != NULL &&
+ b != fsb->fsb.currently_selected_blend) {
+ i++;
+ b = b->next;
+ }
+ }
+ }
+ break;
+ } else {
+ i += f->blend_count+1;
+ f = f->next;
+ }
+ }
+
+ ListSelectPos(fsb->fsb.face_scrolled_list_child, i, False);
+ if (redisplay) ValueChanged(fsb);
+ fsb->fsb.blends_changed = True;
+}
+
+static String categories[][6] = {
+ {"Regular", "Roman", "Medium", "Book", "Light", NULL},
+ {"Italic", "Slanted", "Oblique", NULL},
+ {"Demi", "Semibold", "Heavy", "Bold", NULL},
+ {NULL},
+};
+
+#define NORMALINDEX 0][0
+#define ITALICINDEX 1][0
+#define BOLDINDEX 2][3
+#define DEMIINDEX 2][0
+#define LIGHTINDEX 0][4
+#define BOOKINDEX 0][3
+
+static String extraNormalFaces[] = {"Demi", "Semibold", NULL};
+
+static int MatchFaceName(
+ FSBFaceSelectCallbackRec *rec,
+ Boolean *gaveUp)
+{
+ int i, j, k, face;
+#define PIECEMAX 10
+ String pieces[PIECEMAX];
+ int numPieces;
+ int pass;
+ char *ch, *start, *compare;
+ char save;
+ static Boolean categoriesInited = False;
+ static char *canonicalBold, *canonicalLight, *canonicalBook;
+
+ *gaveUp = False;
+
+ if (!categoriesInited) {
+ for (i = 0; categories[i][0] != NULL; i++) {
+ for (j = 0; categories[i][j] != NULL; j++) {
+ categories[i][j] = Canonical(categories[i][j]);
+ }
+ }
+ for (i = 0; extraNormalFaces[i] != NULL; i++) {
+ extraNormalFaces[i] = Canonical(extraNormalFaces[i]);
+ }
+ canonicalBold = categories[BOLDINDEX];
+ canonicalLight = categories[LIGHTINDEX];
+ canonicalBook = categories[BOOKINDEX];
+ categoriesInited = True;
+ }
+
+ if (rec->current_face == NULL || rec->current_face[0] == '\0') {
+ goto GIVE_UP;
+ }
+
+ /* First check for an exact match */
+
+ for (i = 0; i < rec->num_available_faces; i++) {
+ if (rec->available_faces[i] == rec->current_face) return i;
+ }
+
+ /* Try some category matching. We make two passes; in the first pass
+ we remove "Bold" from the "Demi" family and "Light" and "Book" from
+ the "Regular" family; in the second pass we include them. We ignore
+ leading digits in the face name. */
+
+ categories[BOLDINDEX] = categories[LIGHTINDEX] =
+ categories[BOOKINDEX] = NULL;
+
+ i = 0;
+ ch = rec->current_face;
+ while (*ch == ' ' || isdigit(*ch)) ch++;
+ start = ch;
+
+ while (1) {
+ while (*ch != ' ' && *ch != '\0') ch++;
+ save = *ch;
+ *ch = '\0';
+ compare = Canonical(start);
+ for (j = 0; categories[j][0] != NULL; j++) {
+ for (k = 0; categories[j][k] != NULL; k++) {
+ if (compare == categories[j][k]) {
+ pieces[i++] = categories[j][0];
+ goto FOUND_PIECE;
+ }
+ }
+ }
+ pieces[i++] = compare; /* A unique piece */
+FOUND_PIECE:
+ *ch = save;
+ while (*ch == ' ') ch++;
+ if (*ch == '\0') break;
+ if (i >= PIECEMAX) goto GIVE_UP;
+ start = ch;
+ }
+ numPieces = i;
+ if (numPieces == 0) goto GIVE_UP;
+
+ /* Special case starting with the italic category */
+
+ if (pieces[0] == categories[ITALICINDEX] && numPieces < PIECEMAX-1) {
+ for (i = numPieces; i > 0; i--) pieces[i] = pieces[i-1];
+ pieces[0] = categories[NORMALINDEX];
+ numPieces++;
+ }
+
+ for (pass = 0; pass < 2; pass++) {
+ if (pass == 1) {
+ categories[BOLDINDEX] = canonicalBold;
+ categories[LIGHTINDEX] = canonicalLight;
+ categories[BOOKINDEX] = canonicalBook;
+ for (i = 0; i < numPieces; i++) {
+ if (pieces[i] == canonicalBold) {
+ pieces[i] = categories[DEMIINDEX];
+ } else if (pieces[i] == canonicalLight) {
+ pieces[i] = categories[NORMALINDEX];
+ } else if (pieces[i] == canonicalBook) {
+ pieces[i] = categories[NORMALINDEX];
+ }
+ }
+ }
+
+ /* Now match against each face */
+
+ for (face = 0; face < rec->num_available_faces; face++) {
+ i = 0;
+ ch = rec->available_faces[face];
+ while (*ch == ' ' || isdigit(*ch)) ch++;
+ start = ch;
+
+ while (1) {
+ while (*ch != ' ' && *ch != '\0') ch++;
+ save = *ch;
+ *ch = '\0';
+ compare = Canonical(start);
+ for (j = 0; categories[j][0] != NULL; j++) {
+ for (k = 0; categories[j][k] != NULL; k++) {
+ if (compare == categories[j][k]) {
+ compare = categories[j][0];
+ goto MATCH;
+ }
+ }
+ }
+ MATCH:
+ /* Special case matching the italic category again */
+
+ if (i == 0 && compare == categories[ITALICINDEX] &&
+ pieces[0] == categories[NORMALINDEX] &&
+ numPieces > 1 &&
+ pieces[1] == categories[ITALICINDEX]) i = 1;
+
+ if (pieces[i] != compare) {
+ *ch = save;
+ goto NEXT_FACE;
+ } else i++;
+
+ *ch = save;
+ while (*ch == ' ') ch++;
+ if (*ch == '\0') break;
+ if (i >= numPieces) goto NEXT_FACE;
+ start = ch;
+ }
+ if (i == numPieces) return face; /* Found a match! */
+ NEXT_FACE:
+ ;
+ }
+ }
+
+ /* Couldn't find a match. Look for a "normal face". Make sure "Light"
+ and "Book" are installed. Again, ignore leading spaces. */
+GIVE_UP:
+ *gaveUp = True;
+ categories[LIGHTINDEX] = canonicalLight;
+ categories[BOOKINDEX] = canonicalBook;
+
+ for (i = 0; categories[0][i] != NULL; i++) {
+ for (face = 0; face < rec->num_available_faces; face++) {
+ compare = rec->available_faces[face];
+ while (*compare == ' ' || isdigit(*compare)) compare++;
+ if (compare != rec->available_faces[face]) {
+ compare = Canonical(compare);
+ }
+ if (categories[0][i] == compare) return face;
+ }
+ }
+
+ for (i = 0; extraNormalFaces[i] != NULL; i++) {
+ for (face = 0; face < rec->num_available_faces; face++) {
+ compare = rec->available_faces[face];
+ while (*compare == ' ' || isdigit(*compare)) compare++;
+ if (compare != rec->available_faces[face]) {
+ compare = Canonical(compare);
+ }
+ if (extraNormalFaces[i] == compare) return face;
+ }
+ }
+
+ /* Oh, well. Use the first one */
+ return 0;
+}
+
+static void GetInitialFace(
+ FontSelectionBoxWidget fsb,
+ FontFamilyRec *ff)
+{
+ FSBFaceSelectCallbackRec rec;
+ String *faces;
+ int i, j;
+ FontRec *f;
+ Boolean junk;
+
+ faces = (String *) XtMalloc(ff->font_count * sizeof(String));
+ i = 0;
+ for (f = ff->fonts; f != NULL; f = f->next) faces[i++] = f->face_name;
+
+ rec.available_faces = faces;
+ rec.num_available_faces = ff->font_count;
+
+ if (fsb->fsb.currently_selected_face != NULL) {
+ rec.current_face = fsb->fsb.currently_selected_face->face_name;
+ } else rec.current_face = fsb->fsb.font_face;
+
+ rec.new_face = NULL;
+
+ XtCallCallbackList((Widget) fsb, fsb->fsb.face_select_callback, &rec);
+ if (rec.new_face != NULL) {
+ for (i = 0; i < ff->font_count; i++) {
+ if (rec.new_face == faces[i]) break;
+ }
+ }
+ if (rec.new_face == NULL || i >= ff->font_count) {
+ i = MatchFaceName(&rec, &junk);
+ }
+ XtFree((XtPointer) faces);
+
+ j = 0;
+ for (f = ff->fonts; i != 0; f= f->next) {
+ j += f->blend_count + 1;
+ i--;
+ }
+
+ ListSelectPos(fsb->fsb.face_scrolled_list_child, j+1, False);
+ fsb->fsb.currently_selected_face = f;
+ fsb->fsb.currently_selected_blend = NULL;
+}
+
+/* ARGSUSED */
+
+static void FamilySelect(
+ Widget widget,
+ XtPointer clientData, XtPointer callData)
+{
+ XmListCallbackStruct *listCB = (XmListCallbackStruct *) callData;
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) clientData;
+ FontFamilyRec *ff = fsb->fsb.known_families;
+ int i;
+
+ if (fsb->fsb.current_family_multiple) {
+ fsb->fsb.current_family_multiple = False;
+ UnmanageFamilyMultiple(fsb);
+ }
+
+ /* List uses 1-based addressing!! */
+ for (i = 1; i < listCB->item_position; i++) ff = ff->next;
+
+ fsb->fsb.currently_selected_family = ff;
+
+ SensitizeReset(fsb);
+ SetUpFaceList(fsb, ff);
+ if (!fsb->fsb.current_face_multiple) GetInitialFace(fsb, ff);
+ ValueChanged(fsb);
+}
+
+/* ARGSUSED */
+
+static void FaceSelect(
+ Widget widget,
+ XtPointer clientData, XtPointer callData)
+{
+ XmListCallbackStruct *listCB = (XmListCallbackStruct *) callData;
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) clientData;
+ FontRec *f;
+ BlendRec *b;
+ int n;
+
+ if (fsb->fsb.currently_selected_family == NULL) return;
+ f = fsb->fsb.currently_selected_family->fonts;
+
+ if (fsb->fsb.current_face_multiple) {
+ fsb->fsb.current_face_multiple = False;
+ UnmanageFaceMultiple(fsb);
+ }
+
+ /* List uses 1-based addressing!! */
+ n = 0;
+ while (1) {
+ n += f->blend_count + 1;
+ if (n >= listCB->item_position) {
+ n -= f->blend_count;
+ if (n == listCB->item_position) b = NULL;
+ else for (b = f->blend_data->blends; n < listCB->item_position - 1;
+ b = b->next) n++;
+ break;
+ }
+ f = f->next;
+ }
+
+ fsb->fsb.currently_selected_face = f;
+ fsb->fsb.currently_selected_blend = b;
+
+ SensitizeReset(fsb);
+ ValueChanged(fsb);
+}
+
+static void CreateSizeMenu(
+ FontSelectionBoxWidget fsb,
+ Boolean destroyOldChildren)
+{
+ Arg args[20];
+ int i, j;
+ Widget *sizes;
+ char buf[20];
+ Widget *children;
+ Cardinal num_children;
+ XmString csName;
+ char *ch;
+
+ if (destroyOldChildren) {
+ XtVaGetValues(fsb->fsb.size_menu, XtNchildren, &children,
+ XtNnumChildren, &num_children, NULL);
+
+ /* Don't destroy first child ("other") */
+ for (j = 1; (Cardinal)j < num_children; j++) XtDestroyWidget(children[j]);
+
+ sizes = (Widget *) XtMalloc((fsb->fsb.size_count+1) * sizeof(Widget));
+ sizes[0] = children[0];
+ } else {
+ i = 0;
+ sizes = (Widget *) XtMalloc((fsb->fsb.size_count+1) * sizeof(Widget));
+ fsb->fsb.other_size = sizes[0] =
+ XtCreateManagedWidget("other", xmPushButtonGadgetClass,
+ fsb->fsb.size_menu, args, i);
+ }
+
+ for (j = 0; j < fsb->fsb.size_count; j++) {
+ (void) sprintf(buf, "%g", fsb->fsb.sizes[j]);
+ csName = UnsharedCS(buf);
+ for (ch = buf; *ch != '\0'; ch++) if (*ch == '.') *ch = '-';
+ i = 0;
+ XtSetArg(args[i], XmNlabelString, csName); i++;
+ sizes[j+1] =
+ XmCreatePushButtonGadget(fsb->fsb.size_menu, buf, args, i);
+ XmStringFree(csName);
+ XtAddCallback(sizes[j+1], XmNactivateCallback,
+ SetSize, (XtPointer) fsb);
+ }
+ XtManageChildren(sizes, j+1);
+ XtFree((char *) sizes);
+}
+
+static void CreateChildren(FontSelectionBoxWidget fsb)
+{
+ Arg args[20];
+ int i;
+ Widget form;
+
+ i = 0;
+ fsb->fsb.pane_child =
+ XtCreateManagedWidget("pane", xmPanedWindowWidgetClass,
+ (Widget) fsb, args, i);
+
+ i = 0;
+ fsb->fsb.preview_child =
+ XtCreateManagedWidget("preview", xmDrawingAreaWidgetClass,
+ fsb->fsb.pane_child, args, i);
+ XtAddCallback(fsb->fsb.preview_child, XmNexposeCallback,
+ PreviewText, (XtPointer) fsb);
+ XtAddCallback(fsb->fsb.preview_child, XmNresizeCallback,
+ ResizePreview, (XtPointer) fsb);
+
+ i = 0;
+ form = XtCreateManagedWidget("panel", xmFormWidgetClass,
+ fsb->fsb.pane_child, args, i);
+ fsb->fsb.panel_child = form;
+
+ i = 0;
+ XtSetArg(args[i], XmNleftAttachment, XmATTACH_FORM); i++;
+ XtSetArg(args[i], XmNbottomAttachment, XmATTACH_FORM); i++;
+ fsb->fsb.ok_button_child =
+ XtCreateManagedWidget("okButton", xmPushButtonWidgetClass,
+ form, args, i);
+ XtAddCallback(fsb->fsb.ok_button_child, XmNactivateCallback,
+ OKCallback, (XtPointer) fsb);
+
+ i = 0;
+ XtSetArg(args[i], XmNleftAttachment, XmATTACH_WIDGET); i++;
+ XtSetArg(args[i], XmNleftWidget,fsb->fsb.ok_button_child ); i++;
+ XtSetArg(args[i], XmNbottomAttachment, XmATTACH_FORM); i++;
+ fsb->fsb.apply_button_child =
+ XtCreateManagedWidget("applyButton", xmPushButtonWidgetClass,
+ form, args, i);
+ XtAddCallback(fsb->fsb.apply_button_child, XmNactivateCallback,
+ ApplyCallback, (XtPointer) fsb);
+
+ i = 0;
+ XtSetArg(args[i], XmNleftAttachment, XmATTACH_WIDGET); i++;
+ XtSetArg(args[i], XmNleftWidget,fsb->fsb.apply_button_child ); i++;
+ XtSetArg(args[i], XmNbottomAttachment, XmATTACH_FORM); i++;
+ fsb->fsb.reset_button_child =
+ XtCreateManagedWidget("resetButton", xmPushButtonWidgetClass,
+ form, args, i);
+ XtAddCallback(fsb->fsb.reset_button_child, XmNactivateCallback,
+ ResetCallback, (XtPointer) fsb);
+
+ i = 0;
+ XtSetArg(args[i], XmNleftAttachment, XmATTACH_WIDGET); i++;
+ XtSetArg(args[i], XmNleftWidget,fsb->fsb.reset_button_child ); i++;
+ XtSetArg(args[i], XmNbottomAttachment, XmATTACH_FORM); i++;
+ fsb->fsb.cancel_button_child =
+ XtCreateManagedWidget("cancelButton", xmPushButtonWidgetClass,
+ form, args, i);
+ XtAddCallback(fsb->fsb.cancel_button_child, XmNactivateCallback,
+ CancelCallback, (XtPointer) fsb);
+
+ i = 0;
+ XtSetArg(args[i], XmNleftAttachment, XmATTACH_FORM); i++;
+ XtSetArg(args[i], XmNrightAttachment, XmATTACH_FORM); i++;
+ XtSetArg(args[i], XmNbottomAttachment, XmATTACH_WIDGET); i++;
+ XtSetArg(args[i], XmNbottomWidget, fsb->fsb.ok_button_child); i++;
+ fsb->fsb.separator_child =
+ XtCreateManagedWidget("separator", xmSeparatorGadgetClass,
+ form, args, i);
+
+ i = 0;
+ XtSetArg(args[i], XmNleftAttachment, XmATTACH_FORM); i++;
+ XtSetArg(args[i], XmNbottomAttachment, XmATTACH_WIDGET); i++;
+ XtSetArg(args[i], XmNbottomWidget, fsb->fsb.separator_child); i++;
+ fsb->fsb.size_label_child =
+ XtCreateManagedWidget("sizeLabel", xmLabelWidgetClass,
+ form, args, i);
+
+ i = 0;
+ XtSetArg(args[i], XmNleftAttachment, XmATTACH_WIDGET); i++;
+ XtSetArg(args[i], XmNleftWidget, fsb->fsb.size_label_child); i++;
+ XtSetArg(args[i], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); i++;
+ XtSetArg(args[i], XmNbottomWidget, fsb->fsb.size_label_child); i++;
+ fsb->fsb.size_text_field_child =
+ XtCreateManagedWidget("sizeTextField", xmTextFieldWidgetClass,
+ form, args, i);
+ XtAddCallback(fsb->fsb.size_text_field_child, XmNvalueChangedCallback,
+ SizeSelect, (XtPointer) fsb);
+ XtAddCallback(fsb->fsb.size_text_field_child, XmNmodifyVerifyCallback,
+ TextVerify, (XtPointer) fsb);
+
+ i = 0;
+ fsb->fsb.size_menu = XmCreatePulldownMenu(form, "sizeMenu", args, i);
+
+ CreateSizeMenu(fsb, False);
+
+ i = 0;
+ XtSetArg(args[i], XmNleftAttachment, XmATTACH_WIDGET); i++;
+ XtSetArg(args[i], XmNleftWidget, fsb->fsb.size_text_field_child); i++;
+ XtSetArg(args[i], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); i++;
+ XtSetArg(args[i], XmNbottomWidget, fsb->fsb.size_label_child); i++;
+ XtSetArg(args[i], XmNsubMenuId, fsb->fsb.size_menu); i++;
+ fsb->fsb.size_option_menu_child =
+ XmCreateOptionMenu(form, "sizeOptionMenu", args, i);
+ XtManageChild(fsb->fsb.size_option_menu_child);
+
+ i = 0;
+ XtSetArg(args[i], XmNleftAttachment, XmATTACH_WIDGET); i++;
+ XtSetArg(args[i], XmNleftWidget, fsb->fsb.size_option_menu_child); i++;
+ XtSetArg(args[i], XmNbottomAttachment, XmATTACH_WIDGET); i++;
+ XtSetArg(args[i], XmNbottomWidget, fsb->fsb.separator_child); i++;
+ fsb->fsb.size_multiple_label_child =
+ XtCreateWidget("sizeMultipleLabel", xmLabelWidgetClass,
+ form, args, i);
+
+ i = 0;
+ XtSetArg(args[i], XmNrightAttachment, XmATTACH_FORM); i++;
+ XtSetArg(args[i], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); i++;
+ XtSetArg(args[i], XmNbottomWidget, fsb->fsb.size_label_child); i++;
+ fsb->fsb.preview_button_child =
+ XtCreateManagedWidget("previewButton", xmPushButtonWidgetClass,
+ form, args, i);
+ XtAddCallback(fsb->fsb.preview_button_child, XmNactivateCallback,
+ PreviewCallback, (XtPointer) fsb);
+
+ i = 0;
+ XtSetArg(args[i], XmNrightAttachment, XmATTACH_WIDGET); i++;
+ XtSetArg(args[i], XmNrightWidget, fsb->fsb.preview_button_child); i++;
+ XtSetArg(args[i], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); i++;
+ XtSetArg(args[i], XmNbottomWidget, fsb->fsb.preview_button_child); i++;
+ fsb->fsb.sampler_button_child =
+ XtCreateWidget("samplerButton", xmPushButtonWidgetClass,
+ form, args, i);
+ if (fsb->fsb.show_sampler_button) {
+ XtManageChild(fsb->fsb.sampler_button_child);
+ }
+ XtAddCallback(fsb->fsb.sampler_button_child, XmNactivateCallback,
+ ShowSamplerCallback, (XtPointer) fsb);
+
+ i = 0;
+ XtSetArg(args[i], XmNtopAttachment, XmATTACH_FORM); i++;
+ XtSetArg(args[i], XmNleftAttachment, XmATTACH_FORM); i++;
+ XtSetArg(args[i], XmNrightAttachment, XmATTACH_POSITION); i++;
+ XtSetArg(args[i], XmNrightPosition, 50); i++;
+ fsb->fsb.family_label_child =
+ XtCreateManagedWidget("familyLabel", xmLabelGadgetClass,
+ form, args, i);
+
+ i = 0;
+ XtSetArg(args[i], XmNtopAttachment, XmATTACH_FORM); i++;
+ XtSetArg(args[i], XmNleftAttachment, XmATTACH_POSITION); i++;
+ XtSetArg(args[i], XmNleftPosition, 50); i++;
+ XtSetArg(args[i], XmNrightAttachment, XmATTACH_FORM); i++;
+ fsb->fsb.face_label_child =
+ XtCreateManagedWidget("faceLabel", xmLabelGadgetClass,
+ form, args, i);
+
+ /* The next two must be widgets in order to be reversed in color */
+
+ i = 0;
+ XtSetArg(args[i], XmNtopAttachment, XmATTACH_WIDGET); i++;
+ XtSetArg(args[i], XmNtopWidget, fsb->fsb.family_label_child); i++;
+ XtSetArg(args[i], XmNleftAttachment, XmATTACH_FORM); i++;
+ XtSetArg(args[i], XmNrightAttachment, XmATTACH_POSITION); i++;
+ XtSetArg(args[i], XmNrightPosition, 50); i++;
+ fsb->fsb.family_multiple_label_child =
+ XtCreateWidget("familyMultipleLabel", xmLabelWidgetClass,
+ form, args, i);
+
+ i = 0;
+ XtSetArg(args[i], XmNtopAttachment, XmATTACH_WIDGET); i++;
+ XtSetArg(args[i], XmNtopWidget, fsb->fsb.face_label_child); i++;
+ XtSetArg(args[i], XmNleftAttachment, XmATTACH_POSITION); i++;
+ XtSetArg(args[i], XmNleftPosition, 50); i++;
+ XtSetArg(args[i], XmNrightAttachment, XmATTACH_FORM); i++;
+ fsb->fsb.face_multiple_label_child =
+ XtCreateWidget("faceMultipleLabel", xmLabelWidgetClass,
+ form, args, i);
+
+ i = 0;
+ XtSetArg(args[i], XmNitemCount, 1); i++;
+ XtSetArg(args[i], XmNitems, &CSempty); i++;
+ fsb->fsb.family_scrolled_list_child =
+ XmCreateScrolledList(form, "familyScrolledList", args, i);
+ XtAddCallback(fsb->fsb.family_scrolled_list_child,
+ XmNbrowseSelectionCallback, FamilySelect, (XtPointer) fsb);
+ XtAddCallback(fsb->fsb.family_scrolled_list_child,
+ XmNdefaultActionCallback,
+ PreviewDoubleClick, (XtPointer) fsb);
+
+ i = 0;
+ XtSetArg(args[i], XmNtopAttachment, XmATTACH_WIDGET); i++;
+ XtSetArg(args[i], XmNtopWidget, fsb->fsb.family_label_child); i++;
+ XtSetArg(args[i], XmNbottomAttachment, XmATTACH_WIDGET); i++;
+ XtSetArg(args[i], XmNbottomWidget, fsb->fsb.size_text_field_child); i++;
+ XtSetArg(args[i], XmNleftAttachment, XmATTACH_FORM); i++;
+ XtSetArg(args[i], XmNrightAttachment, XmATTACH_POSITION); i++;
+ XtSetArg(args[i], XmNrightPosition, 50); i++;
+ XtSetValues(XtParent(fsb->fsb.family_scrolled_list_child), args, i);
+ XtManageChild(fsb->fsb.family_scrolled_list_child);
+
+ i = 0;
+ XtSetArg(args[i], XmNitemCount, 1); i++;
+ XtSetArg(args[i], XmNitems, &CSempty); i++;
+ fsb->fsb.face_scrolled_list_child =
+ XmCreateScrolledList(form, "faceScrolledList", args, i);
+ XtAddCallback(fsb->fsb.face_scrolled_list_child,
+ XmNbrowseSelectionCallback, FaceSelect, (XtPointer) fsb);
+ XtAddCallback(fsb->fsb.face_scrolled_list_child,
+ XmNdefaultActionCallback, PreviewDoubleClick,
+ (XtPointer) fsb);
+
+ i = 0;
+ XtSetArg(args[i], XmNtopAttachment, XmATTACH_WIDGET); i++;
+ XtSetArg(args[i], XmNtopWidget, fsb->fsb.face_label_child); i++;
+ XtSetArg(args[i], XmNbottomAttachment, XmATTACH_WIDGET); i++;
+ XtSetArg(args[i], XmNbottomWidget, fsb->fsb.size_text_field_child); i++;
+ XtSetArg(args[i], XmNleftAttachment, XmATTACH_POSITION); i++;
+ XtSetArg(args[i], XmNleftPosition, 50); i++;
+ XtSetArg(args[i], XmNrightAttachment, XmATTACH_FORM); i++;
+ XtSetValues(XtParent(fsb->fsb.face_scrolled_list_child), args, i);
+ XtManageChild(fsb->fsb.face_scrolled_list_child);
+
+ i = 0;
+ XtSetArg(args[i], XmNbottomAttachment, XmATTACH_WIDGET); i++;
+ XtSetArg(args[i], XmNbottomWidget, fsb->fsb.size_text_field_child); i++;
+ XtSetArg(args[i], XmNleftAttachment, XmATTACH_POSITION); i++;
+ XtSetArg(args[i], XmNleftPosition, 50); i++;
+ XtSetArg(args[i], XmNrightAttachment, XmATTACH_FORM); i++;
+ fsb->fsb.multiple_master_button_child =
+ XtCreateWidget("multipleMasterButton", xmPushButtonWidgetClass,
+ form, args, i);
+ XtAddCallback(fsb->fsb.multiple_master_button_child, XmNactivateCallback,
+ ShowCreatorCallback, (XtPointer) fsb);
+
+ i = 0;
+ XtSetArg(args[i], XmNdefaultButton, fsb->fsb.ok_button_child); i++;
+ XtSetValues(form, args, i);
+}
+
+static void DisplayFontFamilies(FontSelectionBoxWidget fsb)
+{
+ FontFamilyRec *ff;
+ XmString *CSlist, *str;
+
+ CSlist = (XmString *) XtMalloc(fsb->fsb.family_count * sizeof(XmString));
+ str = CSlist;
+ for (ff = fsb->fsb.known_families; ff != NULL; ff = ff->next) {
+ *str++ = UnsharedCS(ff->family_name);
+ }
+
+ XtVaSetValues(fsb->fsb.family_scrolled_list_child,
+ XmNitemCount, fsb->fsb.family_count,
+ XmNitems, CSlist, NULL);
+
+ /* The list makes a copy, so we can delete the list */
+ XtFree((char *) CSlist);
+}
+
+static void SetUpCurrentFontFromName(FontSelectionBoxWidget fsb)
+{
+ FontFamilyRec *ff;
+ FontRec *f;
+ BlendRec *b;
+ int i, j;
+
+ fsb->fsb.currently_selected_face = NULL;
+ fsb->fsb.currently_selected_family = NULL;
+ fsb->fsb.currently_selected_blend = NULL;
+
+ if (fsb->fsb.font_name_multiple || fsb->fsb.font_name == NULL) {
+ fsb->fsb.font_name = NULL;
+ fsb->fsb.font_family = NULL;
+ fsb->fsb.font_blend = NULL;
+ fsb->fsb.font_face = NULL;
+ if (fsb->fsb.font_name_multiple) {
+ fsb->fsb.current_family_multiple = True;
+ fsb->fsb.current_face_multiple = True;
+ ManageFamilyMultiple(fsb);
+ ManageFaceMultiple(fsb);
+ }
+ XmListDeselectAllItems(fsb->fsb.family_scrolled_list_child);
+ XmListDeselectAllItems(fsb->fsb.face_scrolled_list_child);
+ XmListDeleteAllItems(fsb->fsb.face_scrolled_list_child);
+ XmListAddItem(fsb->fsb.face_scrolled_list_child, CSempty, 1);
+ return;
+ }
+
+ if (!fsb->fsb.font_name_multiple) {
+ fsb->fsb.current_family_multiple = False;
+ fsb->fsb.current_face_multiple = False;
+ UnmanageFamilyMultiple(fsb);
+ UnmanageFaceMultiple(fsb);
+ }
+
+ fsb->fsb.font_name = Canonical(fsb->fsb.font_name);
+ i = 1;
+ for (ff = fsb->fsb.known_families; ff != NULL; ff = ff->next) {
+ j = 1;
+ for (f = ff->fonts; f != NULL; f = f->next) {
+ if (f->font_name == fsb->fsb.font_name) {
+ fsb->fsb.font_family = ff->family_name;
+ fsb->fsb.font_face = f->face_name;
+ SetUpFaceList(fsb, ff);
+ ListSelectPos(fsb->fsb.family_scrolled_list_child, i, False);
+ ListSelectPos(fsb->fsb.face_scrolled_list_child, j, False);
+ fsb->fsb.currently_selected_face = f;
+ fsb->fsb.currently_selected_family = ff;
+ fsb->fsb.currently_selected_blend = NULL;
+ return;
+ }
+ j++;
+ if (f->blend_data != NULL && f->blend_data->blends != NULL) {
+ for (b = f->blend_data->blends; b != NULL; b = b->next) {
+ if (b->font_name == fsb->fsb.font_name) {
+ fsb->fsb.font_family = ff->family_name;
+ fsb->fsb.font_face = f->face_name;
+ SetUpFaceList(fsb, ff);
+ ListSelectPos(fsb->fsb.family_scrolled_list_child, i,
+ False);
+ ListSelectPos(fsb->fsb.face_scrolled_list_child, j,
+ False);
+ fsb->fsb.currently_selected_face = f;
+ fsb->fsb.currently_selected_family = ff;
+ fsb->fsb.currently_selected_blend = b;
+ return;
+ }
+ j++;
+ }
+ }
+
+ }
+ i++;
+ }
+
+ /* Didn't find it! */
+ fsb->fsb.font_name = NULL;
+ fsb->fsb.font_family = NULL;
+ fsb->fsb.font_face = NULL;
+ fsb->fsb.font_blend = NULL;
+ XmListDeselectAllItems(fsb->fsb.family_scrolled_list_child);
+ XmListDeselectAllItems(fsb->fsb.face_scrolled_list_child);
+ XmListDeleteAllItems(fsb->fsb.face_scrolled_list_child);
+ XmListAddItem(fsb->fsb.face_scrolled_list_child, CSempty, 1);
+}
+
+static void SetUpCurrentFontFromFamilyFace(FontSelectionBoxWidget fsb)
+{
+ FontFamilyRec *ff;
+ FontRec *f;
+ BlendRec *b;
+ int i;
+
+ fsb->fsb.currently_selected_face = NULL;
+ fsb->fsb.currently_selected_family = NULL;
+ fsb->fsb.currently_selected_blend = NULL;
+
+ if (fsb->fsb.font_family_multiple) {
+ fsb->fsb.font_family = NULL;
+ fsb->fsb.current_family_multiple = True;
+ ManageFamilyMultiple(fsb);
+ } else {
+ fsb->fsb.current_family_multiple = False;
+ UnmanageFamilyMultiple(fsb);
+ }
+
+ if (fsb->fsb.font_face_multiple) {
+ fsb->fsb.font_face = NULL;
+ fsb->fsb.current_face_multiple = True;
+ ManageFaceMultiple(fsb);
+ } else {
+ fsb->fsb.current_face_multiple = False;
+ UnmanageFaceMultiple(fsb);
+ }
+
+ fsb->fsb.font_name_multiple =
+ fsb->fsb.font_family_multiple || fsb->fsb.font_face_multiple;
+
+ if (fsb->fsb.font_family != NULL) {
+ fsb->fsb.font_family = Canonical(fsb->fsb.font_family);
+ i = 1;
+ for (ff = fsb->fsb.known_families; ff != NULL; ff = ff->next) {
+ if (fsb->fsb.font_family == ff->family_name) {
+ ListSelectPos(fsb->fsb.family_scrolled_list_child, i, False);
+ fsb->fsb.currently_selected_family = ff;
+ SetUpFaceList(fsb, ff);
+ break;
+ }
+ i++;
+ }
+ if (ff == NULL) fsb->fsb.font_family = NULL;
+ }
+
+ if (fsb->fsb.font_family == NULL) {
+ fsb->fsb.font_face = NULL;
+ fsb->fsb.font_blend = NULL;
+ fsb->fsb.font_name = NULL;
+ XmListDeselectAllItems(fsb->fsb.family_scrolled_list_child);
+ XmListDeselectAllItems(fsb->fsb.face_scrolled_list_child);
+ XmListDeleteAllItems(fsb->fsb.face_scrolled_list_child);
+ XmListAddItem(fsb->fsb.face_scrolled_list_child, CSempty, 1);
+ return;
+ }
+
+ if (fsb->fsb.font_face != NULL) {
+ fsb->fsb.font_face = Canonical(fsb->fsb.font_face);
+
+ i = 1;
+ for (f = ff->fonts; f != NULL; f = f->next) {
+ if (fsb->fsb.font_face == f->face_name) {
+ fsb->fsb.currently_selected_face = f;
+ if (fsb->fsb.font_blend != NULL) {
+ fsb->fsb.font_blend = Canonical(fsb->fsb.font_blend);
+ for (b = f->blend_data->blends; b != NULL; b = b->next) {
+ i++;
+ if (b->blend_name == fsb->fsb.font_blend) {
+ fsb->fsb.currently_selected_blend = b;
+ break;
+ }
+ }
+ if (b == NULL) {
+ fsb->fsb.font_blend = NULL;
+ i -= f->blend_count;
+ }
+ }
+ ListSelectPos(fsb->fsb.face_scrolled_list_child, i, False);
+ break;
+ }
+ i += f->blend_count + 1;
+ }
+ if (f == NULL) fsb->fsb.font_face = NULL;
+ } else {
+ f = NULL;
+ XmListDeselectAllItems(fsb->fsb.face_scrolled_list_child);
+ }
+
+ if (f == NULL && !fsb->fsb.font_face_multiple) GetInitialFace(fsb, ff);
+}
+
+static void SetUpCurrentFont(FontSelectionBoxWidget fsb)
+{
+ if (fsb->fsb.use_font_name) SetUpCurrentFontFromName(fsb);
+ else SetUpCurrentFontFromFamilyFace(fsb);
+}
+
+static void SetUpCurrentSize(FontSelectionBoxWidget fsb)
+{
+ char buf[20];
+
+ if (fsb->fsb.font_size_multiple) {
+ changingSize = True;
+ XtVaSetValues(fsb->fsb.size_text_field_child, XmNvalue, "", NULL);
+ changingSize = False;
+ fsb->fsb.current_size_multiple = True;
+ ManageSizeMultiple(fsb);
+ return;
+ } else UnmanageSizeMultiple(fsb);
+
+ if (fsb->fsb.currently_selected_size == 0.0) {
+ sprintf(buf, "%g", fsb->fsb.font_size);
+ } else sprintf(buf, "%g", fsb->fsb.currently_selected_size);
+
+ changingSize = True;
+ XtVaSetValues(fsb->fsb.size_text_field_child, XmNvalue, buf, NULL);
+ changingSize = False;
+}
+
+static void SetUpCurrentSelections(FontSelectionBoxWidget fsb)
+{
+ SetUpCurrentFont(fsb);
+ SetUpCurrentSize(fsb);
+ if (fsb->fsb.preview_on_change) DoPreview(fsb, False);
+ DoValueChangedCallback(fsb);
+}
+
+/* ARGSUSED */
+
+static void Initialize(
+ Widget request, Widget new,
+ ArgList args,
+ Cardinal *num_args)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) new;
+ Bool inited;
+ char version[20];
+
+ /* Verify size list */
+
+ if (fsb->fsb.size_count > 0 && fsb->fsb.sizes == NULL) {
+ XtAppWarningMsg(XtWidgetToApplicationContext(new),
+ "initializeFontBox", "sizeMismatch",
+ "FontSelectionBoxError",
+ "Size count specified but no sizes present",
+ (String *) NULL, (Cardinal *) NULL);
+ fsb->fsb.size_count = 0;
+ }
+
+ if (fsb->fsb.size_count < 0) {
+ XtAppWarningMsg(XtWidgetToApplicationContext(new),
+ "initializeFontBox", "negativeSize",
+ "FontSelectionBoxError",
+ "Size count should not be negative",
+ (String *) NULL, (Cardinal *) NULL);
+ fsb->fsb.size_count = 0;
+ }
+
+ if (fsb->fsb.max_pending_deletes <= 0) {
+ XtAppWarningMsg(XtWidgetToApplicationContext(new),
+ "initializeFontBox", "nonPositivePendingDelete",
+ "FontSelectionBoxError",
+ "Pending delete max must be positive",
+ (String *) NULL, (Cardinal *) NULL);
+ fsb->fsb.max_pending_deletes = 1;
+ }
+
+ /* Copy strings. SetUpCurrentSelection will copy the font strings */
+
+ if (fsb->fsb.preview_string != NULL) {
+ fsb->fsb.preview_string = XtNewString(fsb->fsb.preview_string);
+ }
+ if (fsb->fsb.default_resource_path != NULL) {
+ fsb->fsb.default_resource_path =
+ XtNewString(fsb->fsb.default_resource_path);
+ }
+ if (fsb->fsb.resource_path_override != NULL) {
+ fsb->fsb.resource_path_override =
+ XtNewString(fsb->fsb.resource_path_override);
+ }
+
+ /* Get the context */
+
+ if (fsb->fsb.context == NULL) {
+ fsb->fsb.context = XDPSGetSharedContext(XtDisplay(fsb));
+ }
+
+ if (_XDPSTestComponentInitialized(fsb->fsb.context,
+ dps_init_bit_fsb, &inited) ==
+ dps_status_unregistered_context) {
+ XDPSRegisterContext(fsb->fsb.context, False);
+ }
+
+ if (!inited) {
+ (void) _XDPSSetComponentInitialized(fsb->fsb.context,
+ dps_init_bit_fsb);
+ _DPSFDefineFontEnumFunctions(fsb->fsb.context);
+ }
+
+ DPSversion(fsb->fsb.context, 20, version);
+ fsb->fsb.old_server = (atof(version) < 1007);
+
+ /* Initialize non-resource fields */
+
+ fsb->fsb.gstate = 0;
+ fsb->fsb.sampler = fsb->fsb.creator = NULL;
+ fsb->fsb.known_families = NULL;
+ fsb->fsb.family_count = 0;
+ fsb->fsb.currently_previewed = NULL;
+ fsb->fsb.currently_selected_face = NULL;
+ fsb->fsb.currently_selected_family = NULL;
+ fsb->fsb.currently_previewed_blend = NULL;
+ fsb->fsb.currently_selected_blend = NULL;
+ fsb->fsb.currently_previewed_size = 0.0;
+ fsb->fsb.currently_selected_size = 0.0;
+ fsb->fsb.pending_delete_count = 0;
+ fsb->fsb.pending_delete_font = NULL;
+ fsb->fsb.preview_fixed = False;
+ fsb->fsb.current_family_multiple = False;
+ fsb->fsb.current_face_multiple = False;
+ fsb->fsb.current_size_multiple = False;
+ fsb->fsb.blends_changed = False;
+
+ GetFontNames(fsb);
+ CreateChildren(fsb);
+
+ DisplayFontFamilies(fsb);
+ SetUpCurrentSelections(fsb);
+ DesensitizeReset(fsb);
+ if (fsb->fsb.show_sampler) ShowSampler(fsb);
+}
+
+static void FreeFontRec(FontRec *f)
+{
+ BlendDataRec *bd;
+ BlendRec *b, *next_b;
+
+ if (f->blend_data != NULL) {
+ bd = f->blend_data;
+ for (b = bd->blends; b != NULL; b = next_b) {
+ next_b = b->next;
+ XtFree((char *) b);
+ }
+ XtFree((char *) bd->internal_break);
+ XtFree((char *) bd->internal_value);
+ XtFree((char *) bd->design_positions);
+ XtFree((char *) bd);
+ }
+ XtFree(f->full_name);
+}
+
+static void FreeFontLists(
+ FontSelectionBoxWidget fsb)
+{
+ FontFamilyRec *ff, *next_ff;
+ FontRec *f, *next_f;
+
+ /* font_name, face_name, family_name, and blend_name are canonical
+ strings and so should not be freed. The face and blend compound
+ strings were gotten from converters and so should likewise remain. */
+
+ for (ff = fsb->fsb.known_families; ff != NULL; ff = next_ff) {
+ for (f = ff->fonts; f != NULL; f = next_f) {
+ FreeFontRec(f);
+ next_f = f->next;
+ XtFree((char *) f);
+ }
+ next_ff = ff->next;
+ XtFree((char *) ff);
+ }
+ fsb->fsb.known_families = NULL;
+}
+
+static void Destroy(Widget widget)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) widget;
+
+ /* Lots of stuff to destroy! */
+
+ if (fsb->fsb.gstate != 0) XDPSFreeContextGState(fsb->fsb.context,
+ fsb->fsb.gstate);
+ if (fsb->fsb.preview_string != NULL) XtFree(fsb->fsb.preview_string);
+ if (fsb->fsb.default_resource_path != NULL) {
+ XtFree(fsb->fsb.default_resource_path);
+ }
+ if (fsb->fsb.resource_path_override != NULL) {
+ XtFree(fsb->fsb.resource_path_override);
+ }
+
+ FreeFontLists(fsb);
+}
+
+static void Resize(Widget widget)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) widget;
+
+ XtResizeWidget(fsb->fsb.pane_child, fsb->core.width, fsb->core.height, 0);
+}
+
+/* ARGSUSED */
+
+static Boolean SetValues(
+ Widget old, Widget req, Widget new,
+ ArgList args,
+ Cardinal *num_args)
+{
+ FontSelectionBoxWidget oldfsb = (FontSelectionBoxWidget) old;
+ FontSelectionBoxWidget newfsb = (FontSelectionBoxWidget) new;
+ Boolean refreshLists = False, setSelection = False, do_preview = False;
+ Bool inited;
+
+#define NE(field) newfsb->fsb.field != oldfsb->fsb.field
+#define DONT_CHANGE(field) \
+ if (NE(field)) newfsb->fsb.field = oldfsb->fsb.field;
+
+ DONT_CHANGE(typographic_sort);
+ DONT_CHANGE(pane_child);
+ DONT_CHANGE(preview_child);
+ DONT_CHANGE(panel_child);
+ DONT_CHANGE(family_label_child);
+ DONT_CHANGE(family_multiple_label_child);
+ DONT_CHANGE(family_scrolled_list_child);
+ DONT_CHANGE(face_label_child);
+ DONT_CHANGE(face_multiple_label_child);
+ DONT_CHANGE(face_scrolled_list_child);
+ DONT_CHANGE(size_label_child);
+ DONT_CHANGE(size_text_field_child);
+ DONT_CHANGE(size_option_menu_child);
+ DONT_CHANGE(preview_button_child);
+ DONT_CHANGE(sampler_button_child);
+ DONT_CHANGE(separator_child);
+ DONT_CHANGE(ok_button_child);
+ DONT_CHANGE(apply_button_child);
+ DONT_CHANGE(reset_button_child);
+ DONT_CHANGE(cancel_button_child);
+#undef DONT_CHANGE
+
+ if (newfsb->fsb.size_count > 0 && newfsb->fsb.sizes == NULL) {
+ XtAppWarningMsg(XtWidgetToApplicationContext(new),
+ "setValuesFontBox", "sizeMismatch",
+ "FontSelectionBoxError",
+ "Size count specified but no sizes present",
+ (String *) NULL, (Cardinal *) NULL);
+ newfsb->fsb.size_count = 0;
+ }
+
+ if (newfsb->fsb.size_count < 0) {
+ XtAppWarningMsg(XtWidgetToApplicationContext(new),
+ "setValuesFontBox", "negativeSize",
+ "FontSelectionBoxError",
+ "Size count should not be negative",
+ (String *) NULL, (Cardinal *) NULL);
+ newfsb->fsb.size_count = 0;
+ }
+
+ if (newfsb->fsb.max_pending_deletes <= 0) {
+ XtAppWarningMsg(XtWidgetToApplicationContext(new),
+ "setValuesFontBox", "nonPositivePendingDelete",
+ "FontSelectionBoxError",
+ "Pending delete max must be positive",
+ (String *) NULL, (Cardinal *) NULL);
+ newfsb->fsb.max_pending_deletes = 1;
+ }
+
+ if (NE(preview_string)) {
+ XtFree(oldfsb->fsb.preview_string);
+ newfsb->fsb.preview_string = XtNewString(newfsb->fsb.preview_string);
+ do_preview = True;
+ }
+
+ if (NE(default_resource_path)) {
+ XtFree(oldfsb->fsb.default_resource_path);
+ newfsb->fsb.default_resource_path =
+ XtNewString(newfsb->fsb.default_resource_path);
+ refreshLists = True;
+ }
+
+ if (NE(resource_path_override)) {
+ XtFree(oldfsb->fsb.resource_path_override);
+ newfsb->fsb.resource_path_override =
+ XtNewString(newfsb->fsb.resource_path_override);
+ refreshLists = True;
+ }
+
+ if (newfsb->fsb.undef_unused_fonts) UndefSomeUnusedFonts(newfsb, False);
+
+ if (NE(context)) {
+ if (newfsb->fsb.context == NULL) {
+ newfsb->fsb.context = XDPSGetSharedContext(XtDisplay(newfsb));
+ }
+ if (_XDPSTestComponentInitialized(newfsb->fsb.context,
+ dps_init_bit_fsb, &inited) ==
+ dps_status_unregistered_context) {
+ XDPSRegisterContext(newfsb->fsb.context, False);
+ }
+ if (!inited) {
+ (void) _XDPSSetComponentInitialized(newfsb->fsb.context,
+ dps_init_bit_fsb);
+ _DPSFDefineFontEnumFunctions(newfsb->fsb.context);
+ }
+ }
+
+ if (refreshLists) {
+ UndefUnusedFonts((Widget)newfsb);
+ newfsb->fsb.pending_delete_font = NULL;
+ newfsb->fsb.pending_delete_count = 0;
+ FreeFontLists(newfsb);
+ GetFontNames(newfsb);
+ DisplayFontFamilies(newfsb);
+ setSelection = True;
+ }
+
+ if (NE(sizes)) {
+ CreateSizeMenu(newfsb, True);
+ setSelection = True;
+ }
+
+ if (NE(show_sampler)) {
+ if (newfsb->fsb.show_sampler) ShowSampler(newfsb);
+ else XtPopdown(newfsb->fsb.sampler);
+ }
+
+ if (NE(show_sampler_button)) {
+ if (newfsb->fsb.show_sampler_button) {
+ XtManageChild(newfsb->fsb.sampler_button_child);
+ } else XtUnmanageChild(newfsb->fsb.sampler_button_child);
+ }
+
+ if (NE(font_size)) newfsb->fsb.currently_selected_size = 0.0;
+
+ if (NE(use_font_name) || NE(font_name) || NE(font_family) ||
+ NE(font_face) || NE(font_size) || NE(font_name_multiple) ||
+ NE(font_family_multiple) || NE(font_face_multiple) ||
+ NE(font_size_multiple) || NE(font_blend)) setSelection = True;
+
+ if (setSelection) SetUpCurrentSelections(newfsb);
+ else if (do_preview && newfsb->fsb.preview_on_change) {
+ DoPreview(newfsb, False);
+ }
+
+ if ((NE(font_name) || NE(font_size)) &&
+ XtIsSensitive(newfsb->fsb.reset_button_child)) {
+
+ if ((newfsb->fsb.font_size_multiple ||
+ newfsb->fsb.font_size == newfsb->fsb.currently_selected_size) &&
+ (newfsb->fsb.font_name_multiple ||
+ newfsb->fsb.currently_selected_face == NULL ||
+ newfsb->fsb.font_name ==
+ newfsb->fsb.currently_selected_face->font_name)) {
+ DesensitizeReset(newfsb);
+ }
+ }
+
+ return False;
+#undef NE
+}
+
+/* ARGSUSED */
+
+static XtGeometryResult GeometryManager(
+ Widget w,
+ XtWidgetGeometry *desired, XtWidgetGeometry *allowed)
+{
+#define WANTS(flag) (desired->request_mode & flag)
+
+ if (WANTS(XtCWQueryOnly)) return XtGeometryYes;
+
+ if (WANTS(CWWidth)) w->core.width = desired->width;
+ if (WANTS(CWHeight)) w->core.height = desired->height;
+ if (WANTS(CWX)) w->core.x = desired->x;
+ if (WANTS(CWY)) w->core.y = desired->y;
+ if (WANTS(CWBorderWidth)) {
+ w->core.border_width = desired->border_width;
+ }
+
+ return XtGeometryYes;
+#undef WANTS
+}
+
+static void ChangeManaged(Widget w)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) w;
+
+ w->core.width = fsb->composite.children[0]->core.width;
+ w->core.height = fsb->composite.children[0]->core.height;
+}
+
+static void SetFontName(
+ Widget w,
+ String name,
+ Bool name_multiple)
+{
+ XtVaSetValues(w, XtNfontName, name, XtNuseFontName, True,
+ XtNfontNameMultiple, name_multiple, NULL);
+}
+
+void FSBSetFontName(
+ Widget w,
+ String name,
+ Bool name_multiple)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ (*((FontSelectionBoxWidgetClass) XtClass(w))->fsb_class.set_font_name)
+ (w, name, name_multiple);
+}
+
+static void SetFontFamilyFace(
+ Widget w,
+ String family, String face,
+ Bool family_multiple, Bool face_multiple)
+{
+ XtVaSetValues(w, XtNfontFamily, family, XtNfontFace, face,
+ XtNuseFontName, False,
+ XtNfontFamilyMultiple, family_multiple,
+ XtNfontFaceMultiple, face_multiple, NULL);
+}
+
+void FSBSetFontFamilyFace(
+ Widget w,
+ String family, String face,
+ Bool family_multiple, Bool face_multiple)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ (*((FontSelectionBoxWidgetClass)
+ XtClass(w))->fsb_class.set_font_family_face)
+ (w, family, face, family_multiple, face_multiple);
+}
+
+static void SetFontSize(
+ Widget w,
+ double size,
+ Bool size_multiple)
+{
+ int i;
+ Arg args[2];
+
+ union {
+ int i;
+ float f;
+ } kludge;
+
+ kludge.f = size;
+
+ i = 0;
+ if (sizeof(float) > sizeof(XtArgVal)) {
+ XtSetArg(args[i], XtNfontSize, &kludge.f); i++;
+ } else XtSetArg(args[i], XtNfontSize, kludge.i); i++;
+ XtSetArg(args[i], XtNfontSizeMultiple, size_multiple); i++;
+ XtSetValues(w, args, i);
+}
+
+void FSBSetFontSize(
+ Widget w,
+ double size,
+ Bool size_multiple)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ (*((FontSelectionBoxWidgetClass) XtClass(w))->fsb_class.set_font_size)
+ (w, size, size_multiple);
+}
+
+static void RefreshFontList(Widget w)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) w;
+
+ UndefUnusedFonts((Widget)fsb);
+ fsb->fsb.pending_delete_font = NULL;
+ fsb->fsb.pending_delete_count = 0;
+ FreeFontLists(fsb);
+ FreePSResourceStorage(True);
+ GetFontNames(fsb);
+ DisplayFontFamilies(fsb);
+ SetUpCurrentSelections(fsb);
+}
+
+void FSBRefreshFontList(
+ Widget w)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ (*((FontSelectionBoxWidgetClass)
+ XtClass(w))->fsb_class.refresh_font_list) (w);
+}
+
+static void GetFamilyList(
+ Widget w,
+ int *count,
+ String **list)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) w;
+ String *buf;
+ FontFamilyRec *ff;
+
+ *count = fsb->fsb.family_count;
+ *list = buf = (String *) XtMalloc(*count * sizeof(String));
+
+ for (ff = fsb->fsb.known_families; ff != NULL; ff = ff->next) {
+ *buf++ = ff->family_name;
+ }
+}
+
+void FSBGetFamilyList(
+ Widget w,
+ int *count,
+ String **list)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ (*((FontSelectionBoxWidgetClass)
+ XtClass(w))->fsb_class.get_family_list) (w, count, list);
+}
+
+static void GetFaceList(
+ Widget w,
+ String family,
+ int *count,
+ String **face_list, String **font_list)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) w;
+ String *buf1, *buf2;
+ FontFamilyRec *ff;
+ FontRec *f;
+
+ family = Canonical(family);
+ for (ff = fsb->fsb.known_families; ff != NULL; ff = ff->next) {
+ if (ff->family_name == family) break;
+ }
+
+ if (ff == NULL) {
+ *count = 0;
+ *face_list = *font_list = NULL;
+ return;
+ }
+
+ *count = ff->font_count;
+ *face_list = buf1 = (String *) XtMalloc(*count * sizeof(String));
+ *font_list = buf2 = (String *) XtMalloc(*count * sizeof(String));
+
+ for (f = ff->fonts; f != NULL; f = f->next) {
+ *buf1++ = f->face_name;
+ *buf2++ = f->font_name;
+ }
+}
+
+void FSBGetFaceList(
+ Widget w,
+ String family,
+ int *count_return,
+ String **face_list, String **font_list)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ (*((FontSelectionBoxWidgetClass)
+ XtClass(w))->fsb_class.get_face_list) (w, family, count_return,
+ face_list, font_list);
+}
+
+void FSBUndefineUnusedFonts(
+ Widget w)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ (*((FontSelectionBoxWidgetClass)
+ XtClass(w))->fsb_class.undef_unused_fonts) (w);
+}
+
+static Boolean DownloadFontName(Widget w, String name)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) w;
+ FontFamilyRec *ff;
+ FontRec *f;
+ Boolean ret;
+
+ name = Canonical(name);
+ for (ff = fsb->fsb.known_families; ff != NULL; ff = ff->next) {
+ for (f = ff->fonts; f != NULL; f = f->next) {
+ if (f->font_name == name) {
+ if (!fsb->fsb.get_server_fonts) {
+ int resident;
+ _DPSFIsFontResident(fsb->fsb.context, f->font_name,
+ &resident);
+ if (resident) f->resident = True;
+ }
+ if (f->resident) return True;
+ else {
+ ret = DownloadFont(fsb, name, fsb->fsb.context,
+ fsb->fsb.make_fonts_shared);
+ if (fsb->fsb.make_fonts_shared && ret) f->resident = True;
+ return ret;
+ }
+ }
+ }
+ }
+
+ return DownloadFont(fsb, name, fsb->fsb.context,
+ fsb->fsb.make_fonts_shared);
+}
+
+Boolean FSBDownloadFontName(
+ Widget w,
+ String name)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ if (name == NULL) return False;
+ return (*((FontSelectionBoxWidgetClass)
+ XtClass(w))->fsb_class.download_font_name) (w, name);
+}
+
+static Boolean MatchFontFace(
+ Widget w,
+ String old_face, String new_family,
+ String *new_face)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) w;
+ FSBFaceSelectCallbackRec rec;
+ String *faces;
+ int i;
+ FontFamilyRec *ff;
+ FontRec *f;
+ Boolean retVal;
+
+ new_family = Canonical(new_family);
+ old_face = Canonical(old_face);
+ for (ff = fsb->fsb.known_families; ff != NULL; ff = ff->next) {
+ if (ff->family_name == new_family) break;
+ }
+ if (ff == NULL) {
+ *new_face = NULL;
+ return False;
+ }
+
+ faces = (String *) XtMalloc(ff->font_count * sizeof(String));
+ i = 0;
+ for (f = ff->fonts; f != NULL; f = f->next) faces[i++] = f->face_name;
+
+ rec.available_faces = faces;
+ rec.num_available_faces = ff->font_count;
+ rec.current_face = old_face;
+ rec.new_face = NULL;
+
+ i = MatchFaceName(&rec, &retVal);
+ *new_face = faces[i];
+ XtFree((XtPointer) faces);
+ return !retVal;
+}
+
+Boolean FSBMatchFontFace(
+ Widget w,
+ String old_face, String new_family,
+ String *new_face)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ return (*((FontSelectionBoxWidgetClass)
+ XtClass(w))->fsb_class.match_font_face) (w, old_face,
+ new_family, new_face);
+}
+
+static void FontNameToFamilyFaceBlend(
+ Widget w,
+ String font_name,
+ String *family, String *face, String *blend)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) w;
+ FontFamilyRec *ff;
+ FontRec *f;
+ BlendRec *b;
+
+ font_name = Canonical(font_name);
+ for (ff = fsb->fsb.known_families; ff != NULL; ff = ff->next) {
+ for (f = ff->fonts; f != NULL; f = f->next) {
+ if (f->font_name == font_name) {
+ *family = ff->family_name;
+ *face = f->face_name;
+ *blend = NULL;
+ return;
+ }
+ if (f->blend_data != NULL) {
+ for (b = f->blend_data->blends; b != NULL; b = b->next) {
+ if (b->font_name == font_name) {
+ *family = ff->family_name;
+ *face = f->face_name;
+ *blend = b->blend_name;
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ *family = NULL;
+ *face = NULL;
+ *blend = NULL;
+}
+
+static void FontNameToFamilyFace(
+ Widget w,
+ String font_name,
+ String *family, String *face)
+{
+ String blend;
+
+ FontNameToFamilyFaceBlend(w, font_name, family, face, &blend);
+}
+
+void FSBFontNameToFamilyFace(
+ Widget w,
+ String font_name,
+ String *family, String *face)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ (*((FontSelectionBoxWidgetClass)
+ XtClass(w))->fsb_class.font_name_to_family_face) (w, font_name,
+ family, face);
+}
+
+static void FontFamilyFaceBlendToName(
+ Widget w,
+ String family, String face, String blend,
+ String *font_name)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) w;
+ FontFamilyRec *ff;
+ FontRec *f;
+ BlendRec *b;
+
+ family = Canonical(family);
+ for (ff = fsb->fsb.known_families; ff != NULL; ff = ff->next) {
+ if (ff->family_name == family) break;
+ }
+ if (ff == NULL) {
+ *font_name = NULL;
+ return;
+ }
+
+ face = Canonical(face);
+ for (f = ff->fonts; f != NULL; f = f->next) {
+ if (f->face_name == face) break;
+ }
+ if (f == NULL) {
+ *font_name = NULL;
+ return;
+ }
+
+ if (blend == NULL) {
+ *font_name = f->font_name;
+ return;
+ }
+ if (f->blend_data == NULL) {
+ *font_name = NULL;
+ return;
+ }
+
+ blend = Canonical(blend);
+ for (b = f->blend_data->blends; b != NULL; b = b->next) {
+ if (b->blend_name == blend) {
+ *font_name = b->font_name;
+ return;
+ }
+ }
+ *font_name = NULL;
+}
+
+static void FontFamilyFaceToName(
+ Widget w,
+ String family, String face,
+ String *font_name)
+{
+ FontFamilyFaceBlendToName(w, family, face, NULL, font_name);
+}
+
+void FSBFontFamilyFaceToName(
+ Widget w,
+ String family, String face,
+ String *font_name)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ (*((FontSelectionBoxWidgetClass)
+ XtClass(w))->fsb_class.font_family_face_to_name) (w, family, face,
+ font_name);
+}
+
+String FSBFindAFM(
+ Widget w,
+ String font_name)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ return (*((FontSelectionBoxWidgetClass) XtClass(w))->
+ fsb_class.find_afm) (w, font_name);
+}
+
+String FSBFindFontFile(
+ Widget w,
+ String font_name)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ return (*((FontSelectionBoxWidgetClass) XtClass(w))->
+ fsb_class.find_font_file) (w, font_name);
+}
+
+static void GetTextDimensions(
+ Widget w,
+ String text, String font,
+ double size, double x, double y,
+ float *dx, float *dy, float *left, float *right, float *top, float *bottom)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) w;
+ int bogusFont;
+
+ _DPSFGetTextDimensions(fsb->fsb.context, text, font, size, x, y,
+ dx, dy, left, right, top, bottom, &bogusFont);
+}
+
+void FSBGetTextDimensions(
+ Widget w,
+ String text, String font,
+ double size, double x, double y,
+ float *dx, float *dy, float *left, float *right, float *top, float *bottom)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ (*((FontSelectionBoxWidgetClass) XtClass(w))->
+ fsb_class.get_text_dimensions) (w, text, font, size, x, y,
+ dx, dy, left, right, top, bottom);
+}
+
+static void SetFontFamilyFaceBlend(
+ Widget w,
+ String family,
+ String face,
+ String blend,
+ Bool family_multiple,
+ Bool face_multiple)
+{
+ XtVaSetValues(w, XtNfontFamily, family, XtNfontFace, face,
+ XtNfontBlend, blend, XtNuseFontName, False,
+ XtNfontFamilyMultiple, family_multiple,
+ XtNfontFaceMultiple, face_multiple, NULL);
+}
+
+void FSBSetFontFamilyFaceBlend(
+ Widget w,
+ String font_family,
+ String font_face,
+ String font_blend,
+ Bool font_family_multiple,
+ Bool font_face_multiple)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ (*((FontSelectionBoxWidgetClass) XtClass(w))->
+ fsb_class.set_font_family_face_blend) (w, font_family, font_face,
+ font_blend,
+ font_family_multiple,
+ font_face_multiple);
+}
+
+void FSBFontNameToFamilyFaceBlend(
+ Widget w,
+ String font_name,
+ String *family,
+ String *face,
+ String *blend)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ (*((FontSelectionBoxWidgetClass) XtClass(w))->
+ fsb_class.font_name_to_family_face_blend) (w, font_name, family,
+ face, blend);
+}
+
+void FSBFontFamilyFaceBlendToName(
+ Widget w,
+ String family,
+ String face,
+ String blend,
+ String *font_name)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ (*((FontSelectionBoxWidgetClass) XtClass(w))->
+ fsb_class.font_family_face_blend_to_name) (w, family, face,
+ blend, font_name);
+}
+
+static void GetBlendList(
+ Widget w,
+ String name,
+ int *count_return,
+ String **blend_return,
+ String **font_name_return,
+ float **axis_values_return)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) w;
+ String *buf1, *buf2;
+ float *buf3;
+ FontFamilyRec *ff;
+ FontRec *f;
+ BlendRec *b;
+ int i;
+
+ name = Canonical(name);
+ for (ff = fsb->fsb.known_families; ff != NULL; ff = ff->next) {
+ for (f = ff->fonts; f != NULL; f = f->next) {
+ if (f->font_name == name) break;
+ }
+ }
+
+ if (ff == NULL || f == NULL || f->blend_data == NULL) {
+ *count_return = 0;
+ *blend_return = *font_name_return = NULL;
+ *axis_values_return = NULL;
+ return;
+ }
+
+ *count_return = f->blend_count;
+ *blend_return = buf1 = (String *) XtMalloc(*count_return * sizeof(String));
+ *font_name_return = buf2 =
+ (String *) XtMalloc(*count_return * sizeof(String));
+ *axis_values_return = buf3 =
+ (float *) XtMalloc(*count_return * MAX_AXES * sizeof(float));
+
+
+ for (b = f->blend_data->blends; b != NULL; b = b->next) {
+ *buf1++ = b->blend_name;
+ *buf2++ = b->font_name;
+ for (i = 0; i < MAX_AXES; i++) *buf3++ = b->data[i];
+ }
+}
+
+void FSBGetBlendList(
+ Widget w,
+ String name,
+ int *count_return,
+ String **blend_return,
+ String **font_name_return,
+ float **axis_values_return)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ (*((FontSelectionBoxWidgetClass) XtClass(w))->
+ fsb_class.get_blend_list) (w, name, count_return, blend_return,
+ font_name_return, axis_values_return);
+}
+
+static void GetBlendInfo(
+ Widget w,
+ String name,
+ int *num_axes_return,
+ int *num_designs_return,
+ String **axis_names_return,
+ float **blend_positions_return,
+ int **blend_map_count_return,
+ int **blend_design_coords_return,
+ float **blend_normalized_coords_return)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) w;
+ FontFamilyRec *ff;
+ FontRec *f;
+ BlendDataRec *bd;
+ int i, j;
+ float *fbuf;
+ int *ibuf;
+ String *sbuf;
+ int coords;
+
+ name = Canonical(name);
+ if (fsb->fsb.currently_selected_face->font_name == name) {
+ bd = fsb->fsb.currently_selected_face->blend_data;
+ } else {
+
+ for (ff = fsb->fsb.known_families; ff != NULL; ff = ff->next) {
+ for (f = ff->fonts; f != NULL; f = f->next) {
+ if (f->font_name == name) goto FOUND_IT;
+ }
+ }
+ *num_axes_return = *num_designs_return = 0;
+ *axis_names_return = NULL;
+ *blend_positions_return = *blend_normalized_coords_return = NULL;
+ *blend_map_count_return = *blend_design_coords_return = NULL;
+ return;
+
+FOUND_IT:
+ bd = f->blend_data;
+ }
+
+ *num_axes_return = bd->num_axes;
+ *num_designs_return = bd->num_designs;
+
+ *axis_names_return = sbuf =
+ (String *) XtMalloc(bd->num_axes * sizeof(String));
+ *blend_map_count_return = ibuf =
+ (int *) XtMalloc(bd->num_axes * sizeof(int));
+ coords = 0;
+ for (i = 0; i < bd->num_axes; i++) {
+ *sbuf++ = bd->name[i];
+ *ibuf++ = bd->internal_points[i] + 2;
+ coords += bd->internal_points[i] + 2;
+ }
+
+ *blend_positions_return = fbuf =
+ (float *) XtMalloc(bd->num_axes * bd->num_designs * sizeof(float));
+ for (i = 0; i < bd->num_axes * bd->num_designs; i++) {
+ *fbuf++ = bd->design_positions[i];
+ }
+
+ *blend_design_coords_return = ibuf =
+ (int *) XtMalloc(coords * sizeof(int));
+ *blend_normalized_coords_return = fbuf =
+ (float *) XtMalloc(coords * sizeof(float));
+
+ for (i = 0; i < bd->num_axes; i++) {
+ *ibuf++ = bd->min[i];
+ *fbuf++ = 0.0;
+ for (j = 0; j < bd->internal_points[i]; j++) {
+ *ibuf++ = bd->internal_break[i][j];
+ *fbuf++ = bd->internal_value[i][j];
+ }
+ *ibuf++ = bd->max[i];
+ *fbuf++ = 1.0;
+ }
+}
+
+void FSBGetBlendInfo(
+ Widget w,
+ String name,
+ int *num_axes_return,
+ int *num_designs_return,
+ String **axis_names_return,
+ float **blend_positions_return,
+ int **blend_map_count_return,
+ int **blend_design_coords_return,
+ float **blend_normalized_coords_return)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ (*((FontSelectionBoxWidgetClass) XtClass(w))->
+ fsb_class.get_blend_info) (w, name, num_axes_return,
+ num_designs_return, axis_names_return,
+ blend_positions_return,
+ blend_map_count_return,
+ blend_design_coords_return,
+ blend_normalized_coords_return);
+}
+
+static Boolean ChangeBlends(
+ Widget w,
+ String base_name,
+ String blend_name,
+ FSBBlendAction action,
+ int *axis_values,
+ float *axis_percents)
+{
+ FontSelectionBoxWidget fsb = (FontSelectionBoxWidget) w;
+ FontFamilyRec *ff;
+ FontRec *f;
+ BlendRec *b = NULL, *newb, **lastb;
+ BlendDataRec *bd;
+ String spaceBlend;
+ int val[4];
+ float pct[4];
+ int i;
+
+ base_name = Canonical(base_name);
+ blend_name = Canonical(blend_name);
+
+ for (ff = fsb->fsb.known_families; ff != NULL; ff = ff->next) {
+ for (f = ff->fonts; f != NULL; f = f->next) {
+ if (f->font_name == base_name) {
+ if ((bd = f->blend_data) == NULL) return False;
+
+ for (b = f->blend_data->blends; b != NULL; b = b->next) {
+ if (b->blend_name == blend_name) break;
+ }
+ goto FOUND_BASE;
+ }
+ }
+ }
+ return False;
+
+FOUND_BASE:
+ if (action != FSBDeleteBlend) {
+ if (axis_values != NULL) {
+ for (i = 0; i < bd->num_axes; i++) {
+ val[i] = axis_values[i];
+ pct[i] = _FSBNormalize(val[i], bd, i);
+ }
+ for (/**/; i < 4; i++) pct[i] = 0.0;
+ } else {
+ if (axis_percents == NULL) return False;
+ for (i = 0; i < bd->num_axes; i++) {
+ pct[i] = axis_percents[i];
+ val[i] = _FSBUnnormalize(pct[i], bd, i);
+ }
+ for (/**/; i < 4; i++) pct[i] = 0.0;
+ }
+ }
+
+ switch (action) {
+ case FSBAddBlend:
+ if (b != NULL) return False;
+ newb = XtNew(BlendRec);
+ newb->blend_name = blend_name;
+ newb->CS_blend_name = CS(blend_name, (Widget) fsb);
+
+ spaceBlend = (char *) XtMalloc(strlen(blend_name) + 4);
+ spaceBlend[0] = spaceBlend[1] = spaceBlend[2] = ' ';
+ strcpy(spaceBlend+3, blend_name);
+ newb->CS_space_blend_name = CS(spaceBlend, (Widget) fsb);
+ XtFree((XtPointer) spaceBlend);
+
+ for (i = 0; i < MAX_AXES; i++) newb->data[i] = pct[i];
+ newb->font_name = _FSBGenFontName(base_name, val, bd);
+
+ f->blend_count++;
+ ff->blend_count++;
+
+ lastb = &bd->blends;
+ for (b = bd->blends; b != NULL; b = b->next) {
+ if (strcmp(blend_name, b->blend_name) < 0) break;
+ lastb = &b->next;
+ }
+
+ newb->next = b;
+ *lastb = newb;
+ break;
+
+ case FSBReplaceBlend:
+ if (b == NULL) return False;
+
+ for (i = 0; i < MAX_AXES; i++) b->data[i] = pct[i];
+ b->font_name = _FSBGenFontName(base_name, val, bd);
+ if (b == fsb->fsb.currently_previewed_blend) DoPreview(fsb, False);
+
+ break;
+
+ case FSBDeleteBlend:
+ if (b == NULL) return False;
+
+ if (bd->blends == b) {
+ bd->blends = b->next;
+ } else {
+ for (newb = bd->blends; newb->next != b; newb = newb->next) {}
+ newb->next = b->next;
+ }
+
+ f->blend_count--;
+ ff->blend_count--;
+
+ /* Don't actually delete the blend record, in case it's displayed
+ in the sampler. */
+ break;
+ }
+ if (f->in_font_creator) _FSBSetCreatorFamily(fsb->fsb.creator, ff);
+ if (ff == fsb->fsb.currently_selected_family) SetUpFaceList(fsb, ff);
+ fsb->fsb.blends_changed = True;
+ WriteBlends(fsb);
+ return True;
+}
+
+Boolean FSBChangeBlends(
+ Widget w,
+ String base_name,
+ String blend_name,
+ FSBBlendAction action,
+ int *axis_values,
+ float *axis_percents)
+{
+ XtCheckSubclass(w, fontSelectionBoxWidgetClass, NULL);
+
+ return (*((FontSelectionBoxWidgetClass) XtClass(w))->
+ fsb_class.change_blends) (w, base_name, blend_name, action,
+ axis_values, axis_percents);
+}
+
+void _FSBSetCurrentFont(
+ FontSelectionBoxWidget fsb,
+ String name)
+{
+ FontFamilyRec *ff;
+ FontRec *f;
+ BlendRec *b;
+ int i, j;
+
+ fsb->fsb.current_family_multiple = False;
+ fsb->fsb.current_face_multiple = False;
+ UnmanageFamilyMultiple(fsb);
+ UnmanageFaceMultiple(fsb);
+
+ name = Canonical(name);
+ i = 1;
+ for (ff = fsb->fsb.known_families; ff != NULL; ff = ff->next) {
+ j = 1;
+ for (f = ff->fonts; f != NULL; f = f->next) {
+ if (f->font_name == name) {
+ b = NULL;
+ goto FOUND_NAME;
+ }
+ j++;
+ if (f->blend_data != NULL && f->blend_data->blends != NULL) {
+ for (b = f->blend_data->blends; b != NULL; b = b->next) {
+ if (b->font_name == name) {
+ goto FOUND_NAME;
+ }
+ j++;
+ }
+ }
+
+ }
+ i++;
+ }
+ return;
+FOUND_NAME:
+ SetUpFaceList(fsb, ff);
+ ListSelectPos(fsb->fsb.family_scrolled_list_child, i, False);
+ ListSelectPos(fsb->fsb.face_scrolled_list_child, j, False);
+ fsb->fsb.currently_selected_face = f;
+ fsb->fsb.currently_selected_family = ff;
+ fsb->fsb.currently_selected_blend = b;
+ SensitizeReset(fsb);
+ DoPreview(fsb, False);
+}
+
+float _FSBNormalize(
+ int val,
+ BlendDataRec *bd,
+ int i)
+{
+ int j;
+ int lessBreak, moreBreak;
+ float lessValue, moreValue;
+
+ if (bd->internal_points[i] == 0) {
+ return ((float) (val - bd->min[i])) /
+ ((float) (bd->max[i] - bd->min[i]));
+ }
+
+ /* Find the largest breakpoint less than val and the smallest one greater
+ than it */
+
+ lessBreak = bd->min[i];
+ lessValue = 0.0;
+ moreBreak = bd->max[i];
+ moreValue = 1.0;
+
+ for (j = 0; j < bd->internal_points[i]; j++) {
+ if (bd->internal_break[i][j] > lessBreak &&
+ bd->internal_break[i][j] <= val) {
+ lessBreak = bd->internal_break[i][j];
+ lessValue = bd->internal_value[i][j];
+ }
+ if (bd->internal_break[i][j] < moreBreak &&
+ bd->internal_break[i][j] >= val) {
+ moreBreak = bd->internal_break[i][j];
+ moreValue = bd->internal_value[i][j];
+ }
+ }
+
+ if (moreBreak == lessBreak) return moreValue;
+
+ return lessValue + (moreValue - lessValue) *
+ ((float) (val - lessBreak)) / ((float) (moreBreak - lessBreak));
+}
+
+int _FSBUnnormalize(val, bd, i)
+ float val;
+ BlendDataRec *bd;
+ int i;
+{
+ int j;
+ int lessBreak, moreBreak;
+ float lessValue, moreValue;
+
+ if (bd->internal_points[i] == 0) {
+ return val * (bd->max[i] - bd->min[i]) + bd->min[i] + 0.5;
+ }
+
+ /* Find the largest breakpoint less than val and the smallest one greater
+ than it */
+
+ lessBreak = bd->min[i];
+ lessValue = 0.0;
+ moreBreak = bd->max[i];
+ moreValue = 1.0;
+
+ for (j = 0; j < bd->internal_points[i]; j++) {
+ if (bd->internal_value[i][j] > lessValue &&
+ bd->internal_value[i][j] <= val) {
+ lessBreak = bd->internal_break[i][j];
+ lessValue = bd->internal_value[i][j];
+ }
+ if (bd->internal_value[i][j] < moreBreak &&
+ bd->internal_value[i][j] >= val) {
+ moreBreak = bd->internal_break[i][j];
+ moreValue = bd->internal_value[i][j];
+ }
+ }
+
+ if (moreBreak == lessBreak) return moreBreak;
+
+ return ((float) (val - lessValue)) / ((float) (moreValue - lessValue)) *
+ (moreBreak - lessBreak) + lessBreak + 0.5;
+}
+
+String _FSBGenFontName(
+ String name,
+ int *val,
+ BlendDataRec *bd)
+{
+ char nameBuf[256];
+ int i;
+ char *ch;
+
+ strcpy(nameBuf, name);
+ ch = nameBuf + strlen(nameBuf);
+
+ for (i = 0; i < bd->num_axes; i++) {
+ sprintf(ch, "_%d_%s", val[i], bd->name[i]);
+ ch = ch + strlen(ch);
+ }
+
+ return Canonical(nameBuf);
+}