diff options
Diffstat (limited to 'nx-X11/lib/dpstk/FontSample.c')
-rw-r--r-- | nx-X11/lib/dpstk/FontSample.c | 1814 |
1 files changed, 1814 insertions, 0 deletions
diff --git a/nx-X11/lib/dpstk/FontSample.c b/nx-X11/lib/dpstk/FontSample.c new file mode 100644 index 000000000..9bccdf30d --- /dev/null +++ b/nx-X11/lib/dpstk/FontSample.c @@ -0,0 +1,1814 @@ +/* + * FontSample.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 <ctype.h> +#include <stdio.h> +#include <X11/Xos.h> +#include <stdlib.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/ScrolledW.h> +#include <Xm/ToggleBG.h> +#include <Xm/Frame.h> +#include <Xm/RowColumn.h> +#include <DPS/dpsXclient.h> +#include <DPS/dpsops.h> +#include <DPS/dpsXcommon.h> +#include <DPS/dpsXshare.h> +#include <DPS/FontSBP.h> +#include "FSBwraps.h" +#include "FontSBI.h" +#include <DPS/FontSamplP.h> + +#if 0 +/* This is not in Xos.h for some reason */ +char *strstr(); +#endif + +#undef MAX +#define MAX(x,y) ((x) > (y) ? (x) : (y)) + +#define UnsharedCS(str) XmStringCreate(str, XmSTRING_DEFAULT_CHARSET) + +static float defaultSizeList[] = { +#ifndef SAMPLER_DEFAULT_SIZE_LIST + 8, 10, 12, 14, 16, 18, 24, 36, 48, 72 +#else + SAMPLER_DEFAULT_SIZE_LIST +#endif /* DEFAULT_SIZE_LIST */ +}; + +#ifndef SAMPLER_DEFAULT_SIZE_LIST_COUNT +#define SAMPLER_DEFAULT_SIZE_LIST_COUNT 10 +#endif /* DEFAULT_SIZE_LIST_COUNT */ + +#ifndef SAMPLER_DEFAULT_SIZE +#define SAMPLER_DEFAULT_SIZE 24.0 +#endif /* SAMPLER_DEFAULT_SIZE */ + +static Boolean DisplayAllWorkProc(XtPointer client_data); +static Boolean DisplaySelectedWorkProc(XtPointer client_data); +static Boolean DisplaySelectedFamilyWorkProc(XtPointer client_data); +static Boolean DisplayFilteredWorkProc(XtPointer client_data); + +#define Offset(field) XtOffsetOf(FontSamplerRec, sampler.field) + +static XtResource resources[] = { + {XtNsizes, XtCSizes, XtRFloatList, sizeof(float*), + Offset(sizes), XtRImmediate, (XtPointer) defaultSizeList}, + {XtNsizeCount, XtCSizeCount, XtRInt, sizeof(int), + Offset(size_count), XtRImmediate, + (XtPointer) SAMPLER_DEFAULT_SIZE_LIST_COUNT}, + {XtNdismissCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), + Offset(dismiss_callback), XtRCallback, (XtPointer) NULL}, + {XtNfontSelectionBox, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(fsb), XtRWidget, (XtPointer) NULL}, + {XtNminimumWidth, XtCMinimumWidth, XtRDimension, sizeof(Dimension), + Offset(minimum_width), XtRImmediate, (XtPointer) 100}, + {XtNminimumHeight, XtCMinimumHeight, XtRDimension, sizeof(Dimension), + Offset(minimum_height), XtRImmediate, (XtPointer) 100}, + {XtNnoRoomMessage, XtCMessage, XmRXmString, sizeof(XmString), + Offset(no_room_message), XtRString, + "Current size is too large or panel is too small"}, + {XtNnoFontMessage, XtCMessage, XmRXmString, sizeof(XmString), + Offset(no_font_message), XtRString, + "There are no fonts!"}, + {XtNnoSelectedFontMessage, XtCMessage, XmRXmString, sizeof(XmString), + Offset(no_selected_font_message), XtRString, + "No font is currently selected"}, + {XtNnoSelectedFamilyMessage, XtCMessage, XmRXmString, sizeof(XmString), + Offset(no_selected_family_message), XtRString, + "No family is currently selected"}, + {XtNnoFamilyFontMessage, XtCMessage, XmRXmString, sizeof(XmString), + Offset(no_family_font_message), XtRString, + "Selected family has no fonts!"}, + {XtNnoMatchMessage, XtCMessage, XmRXmString, sizeof(XmString), + Offset(no_match_message), XtRString, + "No fonts match filters"}, + {XtNpanelChild, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(panel_child), XtRImmediate, (XtPointer) NULL}, + {XtNareaChild, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(area_child), XtRImmediate, (XtPointer) NULL}, + {XtNtextChild, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(text_child), XtRImmediate, (XtPointer) NULL}, + {XtNfontLabelChild, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(font_label_child), XtRImmediate, (XtPointer) NULL}, + {XtNscrolledWindowChild, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(scrolled_window_child), XtRImmediate, (XtPointer) NULL}, + {XtNdisplayButtonChild, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(display_button_child), XtRImmediate, (XtPointer) NULL}, + {XtNdismissButtonChild, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(dismiss_button_child), XtRImmediate, (XtPointer) NULL}, + {XtNstopButtonChild, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(stop_button_child), XtRImmediate, (XtPointer) NULL}, + {XtNclearButtonChild, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(clear_button_child), XtRImmediate, (XtPointer) NULL}, + {XtNradioFrameChild, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(radio_frame_child), XtRImmediate, (XtPointer) NULL}, + {XtNradioBoxChild, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(radio_box_child), XtRImmediate, (XtPointer) NULL}, + {XtNallToggleChild, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(all_toggle_child), XtRImmediate, (XtPointer) NULL}, + {XtNselectedToggleChild, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(selected_toggle_child), XtRImmediate, (XtPointer) NULL}, + {XtNselectedFamilyToggleChild, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(selected_family_toggle_child), XtRImmediate, (XtPointer) NULL}, + {XtNfilterToggleChild, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(filter_toggle_child), XtRImmediate, (XtPointer) NULL}, + {XtNfilterTextChild, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(filter_text_child), XtRImmediate, (XtPointer) NULL}, + {XtNfilterBoxChild, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(filter_box_child), XtRImmediate, (XtPointer) NULL}, + {XtNfilterFrameChild, XtCReadOnly, XtRWidget, sizeof(Widget), + Offset(filter_frame_child), XtRImmediate, (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}, +}; + +/* Forward declarations */ + +static Boolean SetValues(Widget old, Widget req, Widget new, ArgList args, Cardinal *num_args); +static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *desired, XtWidgetGeometry *allowed); +static void Cancel(Widget w); +static void ChangeManaged(Widget w); +static void ClassInitialize(void); +static void ClassPartInitialize(WidgetClass widget_class); +static void ClickAction(Widget widget, XEvent *event, String *params, Cardinal *num_params); +static void Destroy(Widget widget); +static void Initialize(Widget request, Widget new, ArgList args, Cardinal *num_args); +static void Resize(Widget widget); + +static XtActionsRec actions[] = { + {"FSBClickAction", ClickAction} +}; + +FontSamplerClassRec fontSamplerClassRec = { + /* Core class part */ + { + /* superclass */ (WidgetClass) &xmManagerClassRec, + /* class_name */ "FontSampler", + /* widget_size */ sizeof(FontSamplerRec), + /* class_initialize */ ClassInitialize, + /* class_part_initialize */ ClassPartInitialize, + /* class_inited */ False, + /* initialize */ Initialize, + /* initialize_hook */ NULL, + /* realize */ XtInheritRealize, + /* actions */ actions, + /* num_actions */ XtNumber(actions), + /* 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, + }, + /* FontSampler class part */ + { + /* cancel */ Cancel, + /* extension */ NULL, + } +}; + +WidgetClass fontSamplerWidgetClass = + (WidgetClass) &fontSamplerClassRec; + +struct _FilterRec; + +typedef Boolean (*MatchProc)(String name, struct _FilterRec *filter); + +typedef struct _FilterRec { + char *name; + char *particles[9]; + MatchProc special; +} FilterRec; + +static Boolean MatchRoman(String name, FilterRec *filter); +static Boolean MatchMedium(String name, FilterRec *filter); +static Boolean MatchBlack(String name, FilterRec *filter); + +FilterRec filters[] = { + {"roman", {"Roman", NULL}, MatchRoman}, + {"italic", {"Italic", "Kursiv", "Oblique", "Slanted", NULL}}, + {"symbol", {"Pi", "Symbol", "Logo", "Math", "Ornaments", + "Carta", "Sonata", "Dingbats", NULL}}, + {"display", {"Display", "Titling", NULL}}, + {"alternate", {"Alternate", NULL}}, + {"expert", {"Expert", NULL}}, + {"oldstyle", {"Oldstyle Figures", "Old Style Figures", + "Expert", NULL}}, + {"smallcaps", {"Small Caps", NULL}}, + {"swash", {"Swash", NULL}}, + {"script", {"Script", NULL}}, + {"separator1", { NULL}}, + {"condensed", {"Condensed", "Compressed", "Narrow", NULL}}, + {"extended", {"Extended", NULL}}, + {"separator2", { NULL}}, + {"light", {"Light", "Thin", NULL}}, + {"book", {"Book", NULL}}, + {"medium", {"Medium", "Normal", "Regular", + "Roman", NULL}, MatchMedium}, + {"demi", {"Demi", "Semi", "Demibold", "Semibold", NULL}}, + {"bold", {"Bold", NULL}}, + {"black", {"Black", "Heavy", "Poster", "Scal", + "Ultra", NULL}, MatchBlack}, + {"separator3", { NULL}}, + { NULL, { NULL}} +}; + +#define ITALIC_FILTER 1 +#define SYMBOL_FILTER 2 +#define TYPE_FILTERS 0 +#define WIDTH_FILTERS 11 +#define WEIGHT_FILTERS 14 + +static int class_indices[] = {TYPE_FILTERS, WIDTH_FILTERS, WEIGHT_FILTERS, -1}; + +static void ShowLabel(FontSamplerWidget s, XmString string) +{ + XtVaSetValues(s->sampler.font_label_child, XmNlabelString, string, NULL); +} + +static void UnhighlightFont(FontSamplerWidget s) +{ + DisplayedFontRec *d = s->sampler.highlighted_font; + + XCopyArea(XtDisplay(s->sampler.area_child), s->sampler.pixmap, + XtWindow(s->sampler.area_child), + s->sampler.gc, d->l-1, d->t-1, d->r - d->l + 2, d->b - d->t + 2, + d->l-1, d->t-1); +} + +static void HighlightFont(FontSamplerWidget s) +{ + DisplayedFontRec *d = s->sampler.highlighted_font; + FontRec *f = d->font; + BlendRec *b = d->blend; + String fontName; + int bogusFont; + + if (b == NULL) fontName = f->font_name; + else fontName = b->font_name; + + (void) _FSBDownloadFontIfNecessary(d->font, s->sampler.fsb); + + XDPSSetContextGState(s->sampler.fsb->fsb.context, s->sampler.gstate); + DPSsetrgbcolor(s->sampler.fsb->fsb.context, 1.0, 0.0, 0.0); + _DPSFShowText(s->sampler.fsb->fsb.context, d->text->str, + fontName, d->text->size, d->x, d->y, &bogusFont); +} + +/* ARGSUSED */ + +static void ClickAction( + Widget widget, + XEvent *event, + String *params, + Cardinal *num_params) +{ + XButtonEvent *b = (XButtonEvent *) event; + DisplayedFontRec *f; + FontSamplerWidget s = + (FontSamplerWidget) XtParent(XtParent(XtParent(XtParent(widget)))); + XmString CSname; + char buf[512]; + + if (event->type != ButtonPress) return; + + if (s->sampler.current_display_info == NULL) return; + + f = s->sampler.current_display_info->shown_fonts; + + while (f != NULL && + (b->x < f->l || b->y < f->t || b->x > f->r || b->y > f->b)) { + f = f->next; + } + + if (f != NULL) { + if (s->sampler.highlighted_font == f) return; + if (s->sampler.highlighted_font != NULL) UnhighlightFont(s); + s->sampler.highlighted_font = f; + HighlightFont(s); + if (f->blend == NULL) CSname = UnsharedCS(f->font->full_name); + else { + sprintf(buf, "%s %s", f->font->full_name, f->blend->blend_name); + CSname = UnsharedCS(buf); + } + ShowLabel(s, CSname); + XmStringFree(CSname); + if (f->blend == NULL) { + _FSBSetCurrentFont(s->sampler.fsb, f->font->font_name); + } else { + _FSBSetCurrentFont(s->sampler.fsb, f->blend->font_name); + } + } +} + +static void UpdateDisplayedFontRecs( + DisplayRecord *info, + Position newHeight, + Position oldHeight, + Position newWidth) +{ + float *m = info->sampler->sampler.invctm; + float h, w; + Position oldInfoHeight = info->height; + DisplayedFontRec *f; + + info->window_height = newHeight; + h = newHeight; + w = newWidth; + + info->width = (int) (m[0] * w - m[2] * h + m[4]); + info->height = (int) (m[1] * w - m[3] * h + m[5]); + + info->y += info->height - oldInfoHeight; + + for (f = info->shown_fonts; f != NULL; f = f->next) { + f->y += info->height - oldInfoHeight; + } +} + +/* ARGSUSED */ + +static void ResizeEventHandler( + Widget widget, + XtPointer clientData, + XEvent *event, + Boolean *continueToDispatch) +{ + Dimension clip_width, clip_height, new_width, new_height, + area_width, area_height; + int depth; + FontSamplerWidget s = (FontSamplerWidget) clientData; + Pixmap p; + + if (event->type != ConfigureNotify) return; + + XtVaGetValues(s->sampler.clip_widget, XtNwidth, &clip_width, + XtNheight, &clip_height, NULL); + XtVaGetValues(s->sampler.area_child, XtNwidth, &area_width, + XtNheight, &area_height, XtNdepth, &depth, NULL); + + /* Trying to make it fit exactly causes looooping... */ + + new_width = clip_width-2; + new_height = clip_height-2; + + if (clip_width < s->sampler.minimum_width) { + new_width = s->sampler.minimum_width; + } + if (clip_height < s->sampler.minimum_height) { + new_height = s->sampler.minimum_height; + } + + if (new_height != area_height || new_width != area_width) { + XtVaSetValues(s->sampler.area_child, XtNwidth, new_width, + XtNheight, new_height, NULL); + + p = XCreatePixmap(XtDisplay(s->sampler.area_child), + RootWindowOfScreen(XtScreen(s->sampler.area_child)), + new_width, new_height, depth); + + if (s->sampler.gstate != 0) { + XDPSSetContextGState(s->sampler.fsb->fsb.context, + s->sampler.gstate); + XDPSSetContextParameters(s->sampler.fsb->fsb.context, + XtScreen(s->sampler.area_child), depth, + XtWindow(s->sampler.area_child), + new_height, + (XDPSStandardColormap *) NULL, + (XDPSStandardColormap *) NULL, + XDPSContextScreenDepth | XDPSContextDrawable | + XDPSContextRGBMap | XDPSContextGrayMap); + _DPSFReclip(s->sampler.fsb->fsb.context); + _DPSFGetCTM(s->sampler.fsb->fsb.context, + s->sampler.ctm, s->sampler.invctm); + XDPSUpdateContextGState(s->sampler.fsb->fsb.context, + s->sampler.gstate); + XDPSSetContextGState(s->sampler.fsb->fsb.context, + s->sampler.pixmap_gstate); + XDPSSetContextParameters(s->sampler.fsb->fsb.context, + (Screen *) NULL, 0, + p, new_height, + (XDPSStandardColormap *) NULL, + (XDPSStandardColormap *) NULL, + XDPSContextDrawable); + XDPSUpdateContextGState(s->sampler.fsb->fsb.context, + s->sampler.pixmap_gstate); + + _DPSFClearWindow(s->sampler.fsb->fsb.context); + /* La di dah */ + DPSWaitContext(s->sampler.fsb->fsb.context); + XCopyArea(XtDisplay(s), s->sampler.pixmap, p, + s->sampler.gc, 0, 0, new_width, new_height, 0, 0); + } + XFreePixmap(XtDisplay(s), s->sampler.pixmap); + s->sampler.pixmap = p; + UpdateDisplayedFontRecs(s->sampler.current_display_info, + new_height, area_height, new_width); + } +} + +static void ClassInitialize(void) +{ + XtInitializeWidgetClass(fontSelectionBoxWidgetClass); +} + +static void ClassPartInitialize(WidgetClass widget_class) +{ + register FontSamplerWidgetClass wc = + (FontSamplerWidgetClass) widget_class; + FontSamplerWidgetClass super = + (FontSamplerWidgetClass) wc->core_class.superclass; + + if (wc->sampler_class.cancel == InheritCancel) { + wc->sampler_class.cancel = super->sampler_class.cancel; + } +} + +static void FreeDisplayInfo(DisplayRecord *info) +{ + DisplayedFontRec *f; + DisplayedTextRec *t; + + if (info == NULL) return; + + XtVaSetValues(info->sampler->sampler.font_label_child, + XtVaTypedArg, XmNlabelString, XtRString, + " ", 2, NULL); + + while ((f = info->shown_fonts) != NULL) { + info->shown_fonts = f->next; + XtFree((char *) f); + } + + while ((t = info->text_list) != NULL) { + info->text_list = t->next; + XtFree((char *) t->str); + XtFree((char *) t); + } + + XtFree((char *) info); +} + +static Boolean IsSet(Widget widget) +{ + return XmToggleButtonGadgetGetState(widget); +} + +/* ARGSUSED */ + +static void DisplayCallback(Widget widget, XtPointer clientData, XtPointer callData) +{ + XtAppContext app; + float h, w; + DisplayRecord *info; + FontSamplerWidget s = (FontSamplerWidget) clientData; + float *m; + char *value; + DisplayedTextRec *t; + + if (s->sampler.current_display_proc != None) { + XtRemoveWorkProc(s->sampler.current_display_proc); + } + FreeDisplayInfo(s->sampler.current_display_info); + s->sampler.highlighted_font = NULL; + + app = XtDisplayToApplicationContext(XtDisplay(widget)); + + info = s->sampler.current_display_info = + (DisplayRecord *) XtNew(DisplayRecord); + + XtVaGetValues(s->sampler.area_child, + XtNwidth, &info->width, + XtNheight, &info->window_height, + XtNdepth, &info->depth, + NULL); + + if (s->sampler.gstate == 0) { + XDPSSetContextParameters(s->sampler.fsb->fsb.context, + XtScreen(s->sampler.area_child), info->depth, + XtWindow(s->sampler.area_child), + info->window_height, + (XDPSStandardColormap *) NULL, + (XDPSStandardColormap *) NULL, + XDPSContextScreenDepth | XDPSContextDrawable | + XDPSContextRGBMap | XDPSContextGrayMap); + DPSsetgray(s->sampler.fsb->fsb.context, 0.0); + XDPSCaptureContextGState(s->sampler.fsb->fsb.context, + &s->sampler.gstate); + _DPSFGetCTM(s->sampler.fsb->fsb.context, + s->sampler.ctm, s->sampler.invctm); + XDPSSetContextParameters(s->sampler.fsb->fsb.context, + (Screen *) NULL, 0, + s->sampler.pixmap, info->window_height, + (XDPSStandardColormap *) NULL, + (XDPSStandardColormap *) NULL, + XDPSContextDrawable); + DPSsetgray(s->sampler.fsb->fsb.context, 0.0); + XDPSCaptureContextGState(s->sampler.fsb->fsb.context, + &s->sampler.pixmap_gstate); + } + + h = info->window_height; + w = info->width; + + m = s->sampler.invctm; + + info->width = (int) (m[0] * w - m[2] * h + m[4]); + info->height = (int) (m[1] * w - m[3] * h + m[5]); + info->sampler = s; + info->inited = info->any_shown = False; + info->column_width = 0; + info->x = 5; + info->y = info->height; + info->shown_fonts = NULL; + + t = info->text_list = XtNew(DisplayedTextRec); + t->next = NULL; + value = XmTextFieldGetString(s->sampler.text_child); + t->str = XtNewString(value); + + value = XmTextFieldGetString(s->sampler.size_text_field_child); + + if (value == NULL || *value == '\0') t->size = SAMPLER_DEFAULT_SIZE; + else { + t->size = atof(value); + if (t->size <= 0) t->size = SAMPLER_DEFAULT_SIZE; + } + + s->sampler.displaying = True; + + XDPSSetContextGState(s->sampler.fsb->fsb.context, s->sampler.gstate); + _DPSFClearWindow(s->sampler.fsb->fsb.context); + XDPSSetContextGState(s->sampler.fsb->fsb.context, + s->sampler.pixmap_gstate); + _DPSFClearWindow(s->sampler.fsb->fsb.context); + + XtSetSensitive(s->sampler.stop_button_child, True); + + if (IsSet(s->sampler.all_toggle_child)) { + s->sampler.current_display_proc = + XtAppAddWorkProc(app, DisplayAllWorkProc, + (XtPointer) info); + } else if (IsSet(s->sampler.selected_toggle_child)) { + s->sampler.current_display_proc = + XtAppAddWorkProc(app, DisplaySelectedWorkProc, + (XtPointer) info); + } else if (IsSet(s->sampler.selected_family_toggle_child)) { + s->sampler.current_display_proc = + XtAppAddWorkProc(app, DisplaySelectedFamilyWorkProc, + (XtPointer) info); + } else if (IsSet(s->sampler.filter_toggle_child)) { + s->sampler.current_display_proc = + XtAppAddWorkProc(app, DisplayFilteredWorkProc, + (XtPointer) info); + } +} + +static void FinishUpDisplaying(FontSamplerWidget s) +{ + XtSetSensitive(s->sampler.stop_button_child, False); + s->sampler.current_display_proc = None; +} + +/* ARGSUSED */ + +static void FilterCallback(Widget widget, XtPointer clientData, XtPointer callData) +{ + FontSamplerWidget s = (FontSamplerWidget) clientData; + + s->sampler.filters_changed = True; + + if (IsSet(s->sampler.filter_toggle_child)) return; + + XmToggleButtonGadgetSetState(s->sampler.filter_toggle_child, True, True); + + XmToggleButtonGadgetSetState(s->sampler.all_toggle_child, False, False); + XmToggleButtonGadgetSetState(s->sampler.selected_toggle_child, + False, False); + XmToggleButtonGadgetSetState(s->sampler.selected_family_toggle_child, + False, False); +} + +/* ARGSUSED */ + +static void TextCallback(Widget widget, XtPointer clientData, XtPointer callData) +{ + FontSamplerWidget s = (FontSamplerWidget) clientData; + DisplayedTextRec *t; + char *value; + + if (!s->sampler.displaying) return; + + t = XtNew(DisplayedTextRec); + + value = XmTextFieldGetString(s->sampler.text_child); + t->str = XtNewString(value); + t->size = s->sampler.current_display_info->text_list->size; + t->next = s->sampler.current_display_info->text_list; + s->sampler.current_display_info->text_list = t; +} + +/* ARGSUSED */ + +static void StopCallback(Widget widget, XtPointer clientData, XtPointer callData) +{ + FontSamplerWidget s = (FontSamplerWidget) clientData; + + if (s->sampler.current_display_proc == None) return; + + XtRemoveWorkProc(s->sampler.current_display_proc); + FinishUpDisplaying(s); +} + +/* ARGSUSED */ + +static void DismissCallback(Widget widget, XtPointer clientData, XtPointer callData) +{ + FontSamplerWidget s = (FontSamplerWidget) clientData; + + if (XtIsShell(XtParent(s))) XtPopdown(XtParent(s)); + + if (s->sampler.current_display_proc != None) { + XtRemoveWorkProc(s->sampler.current_display_proc); + } + FinishUpDisplaying(s); + + XtCallCallbackList(widget, s->sampler.dismiss_callback, (XtPointer) NULL); +} + +/* ARGSUSED */ + +static void PopdownCallback(Widget widget, XtPointer clientData, XtPointer callData) +{ + FontSamplerWidget s = + (FontSamplerWidget) + (((CompositeWidget) widget)->composite.children[0]); + + if (s->sampler.current_display_proc != None) { + XtRemoveWorkProc(s->sampler.current_display_proc); + } +} + +/* ARGSUSED */ + +static void ExposeCallback(Widget widget, XtPointer clientData, XtPointer callData) +{ + XmDrawingAreaCallbackStruct *da = (XmDrawingAreaCallbackStruct *) callData; + XExposeEvent *ev = (XExposeEvent *) da->event; + FontSamplerWidget s = (FontSamplerWidget) clientData; + + if (ev->type != Expose || !s->sampler.displaying) return; + + XCopyArea(XtDisplay(widget), s->sampler.pixmap, XtWindow(widget), + s->sampler.gc, ev->x, ev->y, ev->width, ev->height, + ev->x, ev->y); + if (s->sampler.highlighted_font != NULL) HighlightFont(s); +} + +/* ARGSUSED */ + +static void ClearCallback(Widget widget, XtPointer clientData, XtPointer callData) +{ + int j; + FontSamplerWidget s = (FontSamplerWidget) clientData; + + for (j = 0; filters[j].name != NULL; j++) { + if (filters[j].particles[0] != NULL) { + XmToggleButtonGadgetSetState(s->sampler.filter_widgets[j], + False, False); + } + } + + XmTextFieldSetString(s->sampler.filter_text_child, ""); +} + +/* ARGSUSED */ + +static void SizeSelect(Widget widget, XtPointer clientData, XtPointer callData) +{ + FontSamplerWidget s = (FontSamplerWidget) clientData; + String value; + Widget option; + char *ch; + DisplayedTextRec *t; + + value = XmTextFieldGetString(widget); + + if (value == NULL) option = s->sampler.other_size; + else { + for (ch = value; *ch != '\0'; ch++) if (*ch == '.') *ch = '-'; + + option = XtNameToWidget(s->sampler.size_menu, value); + if (option == NULL) option = s->sampler.other_size; + } + + XtVaSetValues(s->sampler.size_option_menu_child, + XmNmenuHistory, option, NULL); + + if (!s->sampler.displaying) return; + + t = XtNew(DisplayedTextRec); + + t->str = XtNewString(s->sampler.current_display_info->text_list->str); + if (value == NULL || *value == '\0') t->size = SAMPLER_DEFAULT_SIZE; + else { + t->size = atof(value); + if (t->size <= 0) t->size = SAMPLER_DEFAULT_SIZE; + } + t->next = s->sampler.current_display_info->text_list; + s->sampler.current_display_info->text_list = t; +} + +/* 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. */ + +static Boolean changingSize = False; + +/* ARGSUSED */ + +static void TextVerify(Widget widget, XtPointer clientData, XtPointer callData) +{ + int i; + XmTextVerifyPtr v = (XmTextVerifyPtr) callData; + char ch, *cp; + int decimalPoints = 0; + + 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; + + 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; + } + + cp = XmTextFieldGetString(widget); + + 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], *ch; + FontSamplerWidget s = (FontSamplerWidget) clientData; + + strcpy(buf, XtName(widget)); + for (ch = buf; *ch != '\0'; ch++) if (*ch == '-') *ch++ = '.'; + + changingSize = True; + XmTextFieldSetString(s->sampler.size_text_field_child, buf); + changingSize = False; +} + +static void CreateSizeMenu(FontSamplerWidget s, 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(s->sampler.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((s->sampler.size_count+1) * + sizeof(Widget)); + sizes[0] = children[0]; + } else { + i = 0; + sizes = (Widget *) XtMalloc((s->sampler.size_count+1) * + sizeof(Widget)); + s->sampler.other_size = sizes[0] = + XtCreateManagedWidget("other", xmPushButtonGadgetClass, + s->sampler.size_menu, args, i); + } + + for (j = 0; j < s->sampler.size_count; j++) { + (void) sprintf(buf, "%g", s->sampler.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(s->sampler.size_menu, buf, args, i); + XmStringFree(csName); + XtAddCallback(sizes[j+1], XmNactivateCallback, SetSize, (XtPointer) s); + } + XtManageChildren(sizes, j+1); + XtFree((char *) sizes); +} + +static void CreateFilters(FontSamplerWidget s) +{ + FilterRec *f; + int i; + + s->sampler.filter_widgets = + (Widget *) XtCalloc(XtNumber(filters)-1, sizeof(Widget)); + + s->sampler.filter_flags = + (Boolean *) XtCalloc(XtNumber(filters)-1, sizeof(Boolean)); + + for (i = 0; filters[i].name != NULL; i++) { + f = filters+i; + if (f->particles[0] == NULL) { + s->sampler.filter_widgets[i] = + XtCreateManagedWidget(f->name, xmSeparatorGadgetClass, + s->sampler.filter_box_child, + (ArgList) NULL, 0); + } else { + s->sampler.filter_widgets[i] = + XtCreateManagedWidget(f->name, xmToggleButtonGadgetClass, + s->sampler.filter_box_child, + (ArgList) NULL, 0); + XtAddCallback(s->sampler.filter_widgets[i], + XmNvalueChangedCallback, + FilterCallback, (XtPointer) s); + } + } +} + +static void CreateChildren(FontSamplerWidget s) +{ + Arg args[20]; + int i; + Widget form; + Dimension area_width, area_height; + int depth; + Widget w, rowcol; + + form = s->sampler.panel_child = + XtCreateManagedWidget("panel", xmFormWidgetClass, + (Widget) s, (ArgList) NULL, 0); + + i = 0; + XtSetArg(args[i], XmNleftAttachment, XmATTACH_FORM); i++; + XtSetArg(args[i], XmNbottomAttachment, XmATTACH_FORM); i++; + s->sampler.display_button_child = + XtCreateManagedWidget("displayButton", xmPushButtonWidgetClass, + form, args, i); + XtAddCallback(s->sampler.display_button_child, XmNactivateCallback, + DisplayCallback, (XtPointer) s); + + i = 0; + XtSetArg(args[i], XmNleftAttachment, XmATTACH_WIDGET); i++; + XtSetArg(args[i], XmNleftWidget, s->sampler.display_button_child); i++; + XtSetArg(args[i], XmNbottomAttachment, XmATTACH_FORM); i++; + XtSetArg(args[i], XtNsensitive, False); i++; + s->sampler.stop_button_child = + XtCreateManagedWidget("stopButton", xmPushButtonWidgetClass, + form, args, i); + XtAddCallback(s->sampler.stop_button_child, XmNactivateCallback, + StopCallback, (XtPointer) s); + + i = 0; + XtSetArg(args[i], XmNleftAttachment, XmATTACH_WIDGET); i++; + XtSetArg(args[i], XmNleftWidget, s->sampler.stop_button_child); i++; + XtSetArg(args[i], XmNbottomAttachment, XmATTACH_FORM); i++; + s->sampler.dismiss_button_child = + XtCreateManagedWidget("dismissButton", xmPushButtonWidgetClass, + form, args, i); + XtAddCallback(s->sampler.dismiss_button_child, XmNactivateCallback, + DismissCallback, (XtPointer) s); + + i = 0; + XtSetArg(args[i], XmNleftAttachment, XmATTACH_WIDGET); i++; + XtSetArg(args[i], XmNleftWidget, s->sampler.dismiss_button_child); i++; + XtSetArg(args[i], XmNbottomAttachment, XmATTACH_FORM); i++; + s->sampler.size_label_child = + XtCreateManagedWidget("sizeLabel", xmLabelWidgetClass, + form, args, i); + + i = 0; + XtSetArg(args[i], XmNleftAttachment, XmATTACH_WIDGET); i++; + XtSetArg(args[i], XmNleftWidget, s->sampler.size_label_child); i++; + XtSetArg(args[i], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); i++; + XtSetArg(args[i], XmNbottomWidget, s->sampler.size_label_child); i++; + s->sampler.size_text_field_child = + XtCreateManagedWidget("sizeTextField", + xmTextFieldWidgetClass, + form, args, i); + XtAddCallback(s->sampler.size_text_field_child, XmNvalueChangedCallback, + SizeSelect, (XtPointer) s); + XtAddCallback(s->sampler.size_text_field_child, XmNmodifyVerifyCallback, + TextVerify, (XtPointer) NULL); + + i = 0; + s->sampler.size_menu = XmCreatePulldownMenu(form, "sizeMenu", args, i); + + CreateSizeMenu(s, False); + + i = 0; + XtSetArg(args[i], XmNleftAttachment, XmATTACH_WIDGET); i++; + XtSetArg(args[i], XmNleftWidget, s->sampler.size_text_field_child); i++; + XtSetArg(args[i], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); i++; + XtSetArg(args[i], XmNbottomWidget, s->sampler.size_label_child); i++; + XtSetArg(args[i], XmNsubMenuId, s->sampler.size_menu); i++; + s->sampler.size_option_menu_child = + XmCreateOptionMenu(form, "sizeOptionMenu", args, i); + XtManageChild(s->sampler.size_option_menu_child); + + SizeSelect(s->sampler.size_text_field_child, (XtPointer) s, + (XtPointer) NULL); + + i = 0; + XtSetArg(args[i], XmNtopAttachment, XmATTACH_FORM); i++; + XtSetArg(args[i], XmNrightAttachment, XmATTACH_FORM); i++; + rowcol = XtCreateManagedWidget("rowColumn", xmRowColumnWidgetClass, + form, args, i); + + i = 0; + s->sampler.radio_frame_child = + XtCreateManagedWidget("radioFrame", xmFrameWidgetClass, + rowcol, args, i); + + i = 0; + s->sampler.radio_box_child = XmCreateRadioBox(s->sampler.radio_frame_child, + "radioBox", args, i); + XtManageChild(s->sampler.radio_box_child); + + i = 0; + s->sampler.all_toggle_child = + XtCreateManagedWidget("allToggle", xmToggleButtonGadgetClass, + s->sampler.radio_box_child, args, i); + + i = 0; + s->sampler.selected_toggle_child = + XtCreateManagedWidget("selectedToggle", xmToggleButtonGadgetClass, + s->sampler.radio_box_child, args, i); + + i = 0; + s->sampler.selected_family_toggle_child = + XtCreateManagedWidget("selectedFamilyToggle", + xmToggleButtonGadgetClass, + s->sampler.radio_box_child, args, i); + + i = 0; + s->sampler.filter_toggle_child = + XtCreateManagedWidget("filterToggle", + xmToggleButtonGadgetClass, + s->sampler.radio_box_child, args, i); + + i = 0; + s->sampler.filter_frame_child = + XtCreateManagedWidget("filterFrame", xmFrameWidgetClass, + rowcol, args, i); + + i = 0; + s->sampler.filter_box_child = + XtCreateManagedWidget("filterBox", xmRowColumnWidgetClass, + s->sampler.filter_frame_child, args, i); + + CreateFilters(s); + + i = 0; + s->sampler.filter_text_child = + XtCreateManagedWidget("filterText", xmTextFieldWidgetClass, + s->sampler.filter_box_child, args, i); + XtAddCallback(s->sampler.filter_text_child, + XmNvalueChangedCallback, + FilterCallback, (XtPointer) s); + + i = 0; + XtSetArg(args[i], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); i++; + XtSetArg(args[i], XmNleftWidget, rowcol); i++; + XtSetArg(args[i], XmNbottomAttachment, XmATTACH_FORM); i++; + XtSetArg(args[i], XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET); i++; + XtSetArg(args[i], XmNrightWidget, rowcol); i++; + s->sampler.clear_button_child = + XtCreateManagedWidget("clearButton", xmPushButtonWidgetClass, + form, args, i); + XtAddCallback(s->sampler.clear_button_child, XmNactivateCallback, + ClearCallback, (XtPointer) s); + + i = 0; + XtSetArg(args[i], XmNtopAttachment, XmATTACH_FORM); i++; + XtSetArg(args[i], XmNleftAttachment, XmATTACH_FORM); i++; + XtSetArg(args[i], XmNrightAttachment, XmATTACH_WIDGET); i++; + XtSetArg(args[i], XmNrightWidget, rowcol); i++; + s->sampler.text_child = + XtCreateManagedWidget("text", xmTextFieldWidgetClass, + form, args, i); + XtAddCallback(s->sampler.text_child, + XmNvalueChangedCallback, + TextCallback, (XtPointer) s); + + i = 0; + XtSetArg(args[i], XmNtopAttachment, XmATTACH_WIDGET); i++; + XtSetArg(args[i], XmNtopWidget, s->sampler.text_child); i++; + XtSetArg(args[i], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); i++; + XtSetArg(args[i], XmNleftWidget, s->sampler.text_child); i++; + XtSetArg(args[i], XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET); i++; + XtSetArg(args[i], XmNrightWidget, s->sampler.text_child); i++; + s->sampler.font_label_child = + XtCreateManagedWidget("fontLabel", xmLabelGadgetClass, + form, args, i); + + i = 0; + XtSetArg(args[i], XmNtopAttachment, XmATTACH_WIDGET); i++; + XtSetArg(args[i], XmNtopWidget, s->sampler.font_label_child); i++; + XtSetArg(args[i], XmNleftAttachment, XmATTACH_FORM); i++; + XtSetArg(args[i], XmNrightAttachment, XmATTACH_WIDGET); i++; + XtSetArg(args[i], XmNrightWidget, rowcol); i++; + XtSetArg(args[i], XmNbottomAttachment, XmATTACH_WIDGET); i++; + XtSetArg(args[i], XmNbottomWidget, s->sampler.display_button_child);i++; + XtSetArg(args[i], XmNscrollingPolicy, XmAUTOMATIC); i++; + s->sampler.scrolled_window_child = + XtCreateManagedWidget("scrolledWindow", + xmScrolledWindowWidgetClass, + form, args, i); + i = 0; + s->sampler.area_child = + XtCreateManagedWidget("area", xmDrawingAreaWidgetClass, + s->sampler.scrolled_window_child, args, i); + XtAddCallback(s->sampler.area_child, XmNexposeCallback, + ExposeCallback, (XtPointer) s); + + XtVaGetValues(s->sampler.scrolled_window_child, + XmNclipWindow, &s->sampler.clip_widget, + NULL); + + /* I would like to use translations for this, but Motif overwrites the + clip window's translation. Grr... */ + + XtAddEventHandler(s->sampler.clip_widget, StructureNotifyMask, False, + ResizeEventHandler, (XtPointer) s); + + XtVaSetValues(s->sampler.scrolled_window_child, + XmNworkWindow, s->sampler.area_child, NULL); + + XtVaGetValues(s->sampler.area_child, + XtNheight, &area_height, + XtNwidth, &area_width, + XtNdepth, &depth, + NULL); + + if (area_height < s->sampler.minimum_height || + area_width < s->sampler.minimum_width) { + area_height = MAX(area_height, s->sampler.minimum_height); + area_width = MAX(area_width, s->sampler.minimum_width); + + XtVaSetValues(s->sampler.area_child, XtNwidth, area_width, + XtNheight, area_height, NULL); + } + + s->sampler.pixmap = + XCreatePixmap(XtDisplay(s->sampler.area_child), + RootWindowOfScreen(XtScreen(s->sampler.area_child)), + area_width, area_height, depth); + + XtVaSetValues(form, XmNdefaultButton, s->sampler.display_button_child, + NULL); + + s->sampler.gc = XtGetGC(s->sampler.area_child, 0, (XGCValues *) NULL); + + for (w = XtParent(s); !XtIsShell(w); w = XtParent(w)) {} + XtAddCallback(w, XtNpopdownCallback, PopdownCallback, (XtPointer) NULL); +} + +/* ARGSUSED */ + +static void Initialize( + Widget request, Widget new, + ArgList args, + Cardinal *num_args) +{ + FontSamplerWidget sampler = (FontSamplerWidget) new; + + /* Must have a fsb */ + + if (sampler->sampler.fsb == NULL) { + XtAppErrorMsg(XtWidgetToApplicationContext(new), + "initializeFontSampler", "noFontSelectionBox", + "FontSelectionBoxError", + "No font selection box given to font sampler", + (String *) NULL, (Cardinal *) NULL); + } + + /* Verify size list */ + + if (sampler->sampler.size_count > 0 && sampler->sampler.sizes == NULL) { + XtAppWarningMsg(XtWidgetToApplicationContext(new), + "initializeFontSampler", "sizeMismatch", + "FontSelectionBoxError", + "Size count specified but no sizes present", + (String *) NULL, (Cardinal *) NULL); + sampler->sampler.size_count = 0; + } + + if (sampler->sampler.size_count < 0) { + XtAppWarningMsg(XtWidgetToApplicationContext(new), + "initializeFontSampler", "negativeSize", + "FontSelectionBoxError", + "Size count should not be negative", + (String *) NULL, (Cardinal *) NULL); + sampler->sampler.size_count = 0; + } + + /* Initialize non-resource fields */ + + sampler->sampler.displaying = False; + sampler->sampler.current_display_proc = None; + sampler->sampler.current_display_info = NULL; + sampler->sampler.gstate = sampler->sampler.pixmap_gstate = 0; + + CreateChildren(sampler); +} + +static void AdvanceInfoToNextFont(DisplayRecord *info) +{ + if (info->current_font->blend_data != NULL) { + if (info->current_blend == NULL) { + info->current_blend = info->current_font->blend_data->blends; + } else info->current_blend = info->current_blend->next; + if (info->current_blend == NULL) { + info->current_font = info->current_font->next; + } + } else info->current_font = info->current_font->next; + + if (info->current_font == NULL) { + info->current_family = info->current_family->next; + if (info->current_family != NULL) { + info->current_font = info->current_family->fonts; + } + } +} + +static Boolean ShowFont(DisplayRecord *info) +{ + float width, left, right, top, bottom; + FontRec *f = info->current_font; + BlendRec *b = info->current_blend; + DisplayedFontRec *d; + FontSamplerWidget s = info->sampler; + float *m; + DisplayedTextRec *t = info->text_list; + String fontName; + int bogusFont; + int oldx, oldy; + + if (f == NULL) return True; + + oldx = info->x; + oldy = info->y; + + info->y -= t->size * 5 / 4; + + if (info->y < 0) { + if (info->column_width == 0) return False; + info->y = info->height - (t->size * 5 / 4); + info->x += info->column_width + (t->size / 4); + if (info->x > (int) info->width) return False; + info->column_width = 0; + } + + if (!_FSBDownloadFontIfNecessary(f, s->sampler.fsb)) { + AdvanceInfoToNextFont(info); + return True; + } + + if (b == NULL) fontName = f->font_name; + else fontName = b->font_name; + + /* Do ...AndGetDimensions on the pixmap to make sure that it's synced. + That way we can reliably do an XCopyArea without first doing a + WaitContext. */ + + XDPSSetContextGState(s->sampler.fsb->fsb.context, s->sampler.gstate); + _DPSFShowText(s->sampler.fsb->fsb.context, t->str, fontName, + t->size, info->x, info->y, &bogusFont); + + AdvanceInfoToNextFont(info); + + if (bogusFont) { + info->x = oldx; + info->y = oldy; + + XCopyArea(XtDisplay(s), s->sampler.pixmap, + XtWindow(s->sampler.area_child), + s->sampler.gc, 0, 0, info->width, info->height, 0, 0); + + if (info->current_font == f) { + /* Must be the same font, different blend */ + info->current_font = info->current_font->next; + + if (info->current_font == NULL) { + info->current_family = info->current_family->next; + if (info->current_family != NULL) { + info->current_font = info->current_family->fonts; + } + } + } + + _FSBFlushFont(s->sampler.fsb, f); + return True; + } + + XDPSSetContextGState(s->sampler.fsb->fsb.context, + s->sampler.pixmap_gstate); + _DPSFShowTextAndGetDimensions(s->sampler.fsb->fsb.context, + t->str, fontName, + t->size, info->x, info->y, + &width, &left, &right, &top, &bottom); + + width = ceil(width); + + if (width > (int) info->column_width) info->column_width = (int) width; + + d = XtNew(DisplayedFontRec); + + m = s->sampler.ctm; + + d->l = (int) (m[0] * left + m[2] * top + m[4]); + d->r = (int) ceil(m[0] * right + m[2] * bottom + m[4]); + d->t = (int) ceil(m[1] * left + m[3] * top + m[5] + info->window_height); + d->b = (int) (m[1] * right + m[3] * bottom + m[5] + info->window_height); + d->x = info->x; + d->y = info->y; + d->font = f; + d->blend = b; + d->text = info->text_list; + d->next = info->shown_fonts; + info->shown_fonts = d; + + return True; +} + +static Boolean DisplayAllWorkProc(XtPointer client_data) +{ + DisplayRecord *info = (DisplayRecord *) client_data; + FontSamplerWidget s = info->sampler; + + if (!info->inited) { + info->inited = True; + info->current_family = s->sampler.fsb->fsb.known_families; + info->current_font = info->current_family->fonts; + info->current_blend = NULL; + } + + if (!ShowFont(info)) { + if (!info->any_shown) ShowLabel(s, s->sampler.no_room_message); + FinishUpDisplaying(s); + return True; + } + + info->any_shown = True; + if (info->current_family == NULL) { + if (!info->any_shown) ShowLabel(s, s->sampler.no_font_message); + FinishUpDisplaying(s); + return True; + } + return False; +} + +static Boolean DisplaySelectedWorkProc(XtPointer client_data) +{ + DisplayRecord *info = (DisplayRecord *) client_data; + FontSamplerWidget s = info->sampler; + + info->current_family = s->sampler.fsb->fsb.currently_selected_family; + info->current_font = s->sampler.fsb->fsb.currently_selected_face; + info->current_blend = s->sampler.fsb->fsb.currently_selected_blend; + + if (info->current_font != NULL) { + if (!ShowFont(info)) ShowLabel(s, s->sampler.no_room_message); + } else ShowLabel(s, s->sampler.no_selected_font_message); + + FinishUpDisplaying(s); + return True; +} + +static Boolean DisplaySelectedFamilyWorkProc(XtPointer client_data) +{ + DisplayRecord *info = (DisplayRecord *) client_data; + FontSamplerWidget s = info->sampler; + FontFamilyRec *currentFamily; + + if (!info->inited) { + info->inited = True; + info->current_family = s->sampler.fsb->fsb.currently_selected_family; + if (info->current_family != NULL) { + info->current_font = info->current_family->fonts; + info->current_blend = NULL; + } else { + ShowLabel(s, s->sampler.no_selected_family_message); + FinishUpDisplaying(s); + return True; + } + } + + currentFamily = info->current_family; + + if (!ShowFont(info)) { + if (!info->any_shown) ShowLabel(s, s->sampler.no_room_message); + FinishUpDisplaying(s); + return True; + } + + info->any_shown = True; + if (info->current_family != currentFamily) { + if (!info->any_shown) ShowLabel(s, s->sampler.no_family_font_message); + FinishUpDisplaying(s); + return True; + } + return False; +} + +/* ARGSUSED */ + +static Boolean MatchRoman(String name, FilterRec *filter) +{ + FilterRec *f; + char *ch, **search, *start; + int len; + + /* Roman means not italic and not symbol */ + + for (f = filters + ITALIC_FILTER; f <= filters + SYMBOL_FILTER; f++) { + for (search = f->particles; *search != NULL; search++) { + start = name; + do { + ch = strstr(start, *search); + if (ch != NULL) { + len = strlen(*search); + if (ch[len] == ' ' || ch[len] == '\0') return False; + else start = ch+1; + } + } while (ch != NULL); + } + } + return True; +} + +static Boolean MatchMedium(String name, FilterRec *filter) +{ + FilterRec *f; + char *ch, **search, *start; + int len; + + for (search = filter->particles; *search != NULL; search++) { + start = name; + do { + ch = strstr(start, *search); + if (ch != NULL) { + len = strlen(*search); + if (ch[len] == ' ' || ch[len] == '\0') return True; + else start = ch+1; + } + } while (ch != NULL); + } + + /* Also match anything that has none of the other weight particles */ + + for (f = filters + WEIGHT_FILTERS; f->name != NULL; f++) { + if (f == filter) continue; + for (search = f->particles; *search != NULL; search++) { + start = name; + do { + ch = strstr(start, *search); + if (ch != NULL) { + len = strlen(*search); + if (ch[len] == ' ' || ch[len] == '\0') return False; + else start = ch+1; + } + } while (ch != NULL); + } + } + return True; +} + +static Boolean MatchBlack(String name, FilterRec *filter) +{ + char *ch, **search, *start; + int len; + Boolean ultra; + + for (search = filter->particles; *search != NULL; search++) { + ultra = (strcmp(*search, "Ultra") == 0); + start = name; + do { + ch = strstr(start, *search); + if (ch != NULL) { + len = strlen(*search); + if (ch[len] == '\0') return True; + if (ch[len] == ' ') { + if (!ultra) return True; + /* Only match "Ultra" if not followed by "Compressed" or + "Light". We'd also like to add "Condensed" to this + list, but some fonts use "Ultra Condensed" to mean + "Ultra & Condensed" while others use it to mean "Very + much Condensed". Sigh... */ + start = ch+len+1; + if (strncmp(start, "Compressed", 10) != 0 && + strncmp(start, "Light", 5) != 0) return True; + else start = ch+1; + } + else start = ch+1; + } + } while (ch != NULL); + } + return False; +} + +static void UpdateFilters(FontSamplerWidget s) +{ + int i; + + for (i = 0; filters[i].name != NULL; i++) { + if (filters[i].particles[0] != NULL) { + s->sampler.filter_flags[i] = IsSet(s->sampler.filter_widgets[i]); + } + } + + s->sampler.filter_text = + XmTextFieldGetString(s->sampler.filter_text_child); +} + +static Boolean FontMatchesFilters( + FontRec *font, + BlendRec *blend, + FontSamplerWidget s) +{ + int *cl, i; + FilterRec *f; + char *ch, **search, *start; + int len; + Boolean anyset, foundone, allmatch; + char *name; + char buf[512]; + + if (blend != NULL) { + sprintf(buf, "%s %s", font->full_name, blend->blend_name); + name = buf; + } else name = font->full_name; + + allmatch = False; + if (s->sampler.filters_changed) UpdateFilters(s); + + for (cl = class_indices; *cl != -1; cl++) { + anyset = foundone = False; + for (i = *cl; + filters[i].particles[0] != NULL && filters[i].name != NULL; i++) { + + f = filters+i; + + if (!s->sampler.filter_flags[i]) continue; + anyset = True; + + if (f->special != NULL) { + if ((*f->special)(name, f)) { + foundone = True; + goto NEXT_CLASS; + } + continue; + } + + for (search = f->particles; *search != NULL; search++) { + start = name; + do { + ch = strstr(start, *search); + if (ch != NULL) { + len = strlen(*search); + if (ch[len] == ' ' || ch[len] == '\0') { + foundone = True; + goto NEXT_CLASS; + } + else start = ch+1; + } + } while (ch != NULL); + } + } +NEXT_CLASS: ; + /* If there were any filters set in this class, but we didn't match, + return False */ + if (anyset && !foundone) return False; + if (anyset && foundone) allmatch = True; + } + + /* Now check against the text field */ + + if (s->sampler.filter_text == NULL || s->sampler.filter_text[0] == '\0') { + return allmatch; + } + + ch = strstr(name, s->sampler.filter_text); + + return (ch != NULL); +} + +static Boolean DisplayFilteredWorkProc(XtPointer client_data) +{ + DisplayRecord *info = (DisplayRecord *) client_data; + FontSamplerWidget s = info->sampler; + + if (!info->inited) { + info->inited = True; + info->current_family = s->sampler.fsb->fsb.known_families; + info->current_font = info->current_family->fonts; + info->current_blend = NULL; + s->sampler.filters_changed = True; + } + + if (FontMatchesFilters(info->current_font, info->current_blend, s)) { + if (!ShowFont(info)) { + if (!info->any_shown) ShowLabel(s, s->sampler.no_room_message); + FinishUpDisplaying(s); + return True; + } + info->any_shown = True; + } else AdvanceInfoToNextFont(info); + + if (info->current_font == NULL) { + if (!info->any_shown) ShowLabel(s, s->sampler.no_match_message); + FinishUpDisplaying(s); + return True; + } + return False; +} + +static void Destroy(Widget widget) +{ + FontSamplerWidget s = (FontSamplerWidget) widget; + + if (s->sampler.gstate != 0) { + XDPSFreeContextGState(s->sampler.fsb->fsb.context, + s->sampler.pixmap_gstate); + XDPSFreeContextGState(s->sampler.fsb->fsb.context, s->sampler.gstate); + } + XtReleaseGC(widget, s->sampler.gc); + XFreePixmap(XtDisplay(widget), s->sampler.pixmap); + if (s->sampler.current_display_proc != None) { + XtRemoveWorkProc(s->sampler.current_display_proc); + } + if (s->sampler.current_display_info != NULL) { + FreeDisplayInfo(s->sampler.current_display_info); + } + XtFree((char *) s->sampler.filter_widgets); + XtFree((char *) s->sampler.filter_flags); +} + +static void Resize(Widget widget) +{ + FontSamplerWidget s = (FontSamplerWidget) widget; + + XtResizeWidget(s->sampler.panel_child, s->core.width, s->core.height, 0); +} + +/* 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) +{ + FontSamplerWidget s = (FontSamplerWidget) w; + + w->core.width = s->composite.children[0]->core.width; + w->core.height = s->composite.children[0]->core.height; +} + +/* ARGSUSED */ + +static Boolean SetValues( + Widget old, Widget req, Widget new, + ArgList args, + Cardinal *num_args) +{ + FontSamplerWidget olds = (FontSamplerWidget) old; + FontSamplerWidget news = (FontSamplerWidget) new; + +#define NE(field) news->sampler.field != olds->sampler.field +#define DONT_CHANGE(field) \ + if (NE(field)) news->sampler.field = olds->sampler.field; + + DONT_CHANGE(panel_child); + DONT_CHANGE(area_child); + DONT_CHANGE(text_child); + DONT_CHANGE(font_label_child); + DONT_CHANGE(scrolled_window_child); + DONT_CHANGE(display_button_child); + DONT_CHANGE(dismiss_button_child); + DONT_CHANGE(stop_button_child); + DONT_CHANGE(clear_button_child); + DONT_CHANGE(radio_frame_child); + DONT_CHANGE(radio_box_child); + DONT_CHANGE(all_toggle_child); + DONT_CHANGE(selected_toggle_child); + DONT_CHANGE(selected_family_toggle_child); + DONT_CHANGE(filter_toggle_child); + DONT_CHANGE(filter_box_child); + DONT_CHANGE(filter_frame_child); + DONT_CHANGE(size_option_menu_child); + DONT_CHANGE(size_text_field_child); + DONT_CHANGE(size_label_child); + DONT_CHANGE(fsb); +#undef DONT_CHANGE + + if (news->sampler.size_count > 0 && news->sampler.sizes == NULL) { + XtAppWarningMsg(XtWidgetToApplicationContext(new), + "setValuesFontSampler", "sizeMismatch", + "FontSelectionBoxError", + "Size count specified but no sizes present", + (String *) NULL, (Cardinal *) NULL); + news->sampler.size_count = 0; + } + + if (news->sampler.size_count < 0) { + XtAppWarningMsg(XtWidgetToApplicationContext(new), + "setValuesFontSampler", "negativeSize", + "FontSelectionBoxError", + "Size count should not be negative", + (String *) NULL, (Cardinal *) NULL); + news->sampler.size_count = 0; + } + + if (NE(sizes)) CreateSizeMenu(news, True); + + return False; +#undef NE +} + +static void Cancel(Widget w) +{ + FontSamplerWidget s = (FontSamplerWidget) w; + + if (s->sampler.current_display_proc != None) { + XtRemoveWorkProc(s->sampler.current_display_proc); + } +} + +void FSBCancelSampler(Widget w) +{ + XtCheckSubclass(w, fontSamplerWidgetClass, NULL); + + (*((FontSamplerWidgetClass) XtClass(w))->sampler_class.cancel) (w); +} + +#ifdef NO_STRSTR_AVAILABLE +String strstr(String s1, String s2) +{ + register int len1, len2; + + len1 = strlen(s1); + len2 = strlen(s2); + + while (len1 >= len2) { + if (*s1 == *s2) { + if (strncmp(s1+1, s2+1, len2-1) == 0) return s1; + } + len1--; + s1++; + } +} +#endif /* NO_STRSTR_AVAILABLE */ |