1492e1cfeSmrg/*
23538fbe3Smrg *
3492e1cfeSmrgCopyright 1989, 1998  The Open Group
4492e1cfeSmrg
5492e1cfeSmrgPermission to use, copy, modify, distribute, and sell this software and its
6492e1cfeSmrgdocumentation for any purpose is hereby granted without fee, provided that
7492e1cfeSmrgthe above copyright notice appear in all copies and that both that
8492e1cfeSmrgcopyright notice and this permission notice appear in supporting
9492e1cfeSmrgdocumentation.
10492e1cfeSmrg
11492e1cfeSmrgThe above copyright notice and this permission notice shall be included in
12492e1cfeSmrgall copies or substantial portions of the Software.
13492e1cfeSmrg
14492e1cfeSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15492e1cfeSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16492e1cfeSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17492e1cfeSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18492e1cfeSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19492e1cfeSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20492e1cfeSmrg
21492e1cfeSmrgExcept as contained in this notice, the name of The Open Group shall not be
22492e1cfeSmrgused in advertising or otherwise to promote the sale, use or other dealings
23492e1cfeSmrgin this Software without prior written authorization from The Open Group.
241afad795Smrg *
25492e1cfeSmrg * Author:  Jim Fulton, MIT X Consortium
26492e1cfeSmrg */
27492e1cfeSmrg
28b78bb896Smrg#ifdef HAVE_CONFIG_H
29b78bb896Smrg# include "config.h"
30b78bb896Smrg#endif
31b78bb896Smrg
32492e1cfeSmrg#include <X11/IntrinsicP.h>
33492e1cfeSmrg#include <X11/StringDefs.h>
34492e1cfeSmrg#include <X11/Xaw/SimpleP.h>
35492e1cfeSmrg#include <X11/Xmu/Converters.h>
36492e1cfeSmrg#include <X11/Xos.h>
37492e1cfeSmrg#include "gridP.h"
38492e1cfeSmrg
39492e1cfeSmrg#ifdef XKB
40492e1cfeSmrg#include <X11/extensions/XKBbells.h>
41492e1cfeSmrg#else
42492e1cfeSmrg#define	XkbBI_MinorError		2
43492e1cfeSmrg#define	XkbBI_Ignore			11
44492e1cfeSmrg#endif
45492e1cfeSmrg
46492e1cfeSmrg#ifdef XKB
47492e1cfeSmrg#define Bell(w,n) XkbStdBell(XtDisplay(w), XtWindow(w), 50, n)
48492e1cfeSmrg#else
49492e1cfeSmrg#define Bell(w,n) XBell(XtDisplay(w), 0)
50492e1cfeSmrg#endif
51492e1cfeSmrg
52492e1cfeSmrgstatic GC get_gc(FontGridWidget fgw, Pixel fore);
53492e1cfeSmrgstatic void ClassInitialize(void);
543538fbe3Smrgstatic void Initialize(Widget request, Widget new, ArgList args,
55492e1cfeSmrg		       Cardinal *num_args);
563538fbe3Smrgstatic void Realize(Widget gw, Mask *valueMask,
57492e1cfeSmrg		    XSetWindowAttributes *attributes);
58492e1cfeSmrgstatic void Destroy(Widget gw);
59492e1cfeSmrgstatic void Resize(Widget gw);
60492e1cfeSmrgstatic void Redisplay(Widget gw, XEvent *event, Region region);
613538fbe3Smrgstatic void paint_grid(FontGridWidget fgw, int col, int row,
62492e1cfeSmrg		       int ncols, int nrows);
633538fbe3Smrgstatic Boolean SetValues(Widget current, Widget request, Widget new,
64492e1cfeSmrg			 ArgList args, Cardinal *num_args);
653538fbe3Smrgstatic void Notify(Widget gw, XEvent *event, String *params,
66492e1cfeSmrg		   Cardinal *nparams);
67492e1cfeSmrg
68492e1cfeSmrg#define Offset(field) XtOffsetOf(FontGridRec, fontgrid.field)
69492e1cfeSmrg
70492e1cfeSmrgstatic XtResource resources[] = {
71492e1cfeSmrg    { XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
72492e1cfeSmrg	Offset(text_font), XtRString, (XtPointer) NULL },
73492e1cfeSmrg    { XtNcellColumns, XtCCellColumns, XtRInt, sizeof(int),
74492e1cfeSmrg	Offset(cell_cols), XtRImmediate, (XtPointer) 0 },
75492e1cfeSmrg    { XtNcellRows, XtCCellRows, XtRInt, sizeof(int),
76492e1cfeSmrg	Offset(cell_rows), XtRImmediate, (XtPointer) 0 },
77492e1cfeSmrg    { XtNcellWidth, XtCCellWidth, XtRInt, sizeof(int),
78492e1cfeSmrg	Offset(cell_width), XtRImmediate, (XtPointer) 0 },
79492e1cfeSmrg    { XtNcellHeight, XtCCellHeight, XtRInt, sizeof(int),
80492e1cfeSmrg	Offset(cell_height), XtRImmediate, (XtPointer) 0 },
81492e1cfeSmrg    { XtNstartChar, XtCStartChar, XtRLong, sizeof(long),
82492e1cfeSmrg	Offset(start_char), XtRImmediate, (XtPointer) 0xffffffff },
83492e1cfeSmrg#ifndef XRENDER
84492e1cfeSmrg    { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
85492e1cfeSmrg	Offset(foreground_pixel), XtRString, (XtPointer) XtDefaultForeground },
86492e1cfeSmrg#endif
87492e1cfeSmrg    { XtNcenterChars, XtCCenterChars, XtRBoolean, sizeof(Boolean),
88492e1cfeSmrg	Offset(center_chars), XtRImmediate, (XtPointer) FALSE },
89492e1cfeSmrg    { XtNboxChars, XtCBoxChars, XtRBoolean, sizeof(Boolean),
90492e1cfeSmrg	Offset(box_chars), XtRImmediate, (XtPointer) FALSE },
91492e1cfeSmrg    { XtNboxColor, XtCForeground, XtRPixel, sizeof(Pixel),
92492e1cfeSmrg	Offset(box_pixel), XtRString, (XtPointer) XtDefaultForeground },
93492e1cfeSmrg    { XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer),
94492e1cfeSmrg	Offset(callbacks), XtRCallback, (XtPointer) NULL },
95492e1cfeSmrg    { XtNinternalPad, XtCInternalPad, XtRInt, sizeof(int),
96492e1cfeSmrg	Offset(internal_pad), XtRImmediate, (XtPointer) 4 },
97492e1cfeSmrg    { XtNgridWidth, XtCGridWidth, XtRInt, sizeof(int),
98492e1cfeSmrg	Offset(grid_width), XtRImmediate, (XtPointer) 1 },
99492e1cfeSmrg#ifdef XRENDER
100492e1cfeSmrg    {XtNforeground, XtCForeground, XtRXftColor, sizeof(XftColor),
101492e1cfeSmrg        Offset(fg_color), XtRString, XtDefaultForeground},
102492e1cfeSmrg    {XtNface, XtCFace, XtRXftFont, sizeof (XftFont *),
1039e0146f7Smrg	Offset (text_face), XtRString, NULL},
104492e1cfeSmrg#endif
105492e1cfeSmrg};
106492e1cfeSmrg
107492e1cfeSmrg#undef Offset
108492e1cfeSmrg
1093538fbe3Smrgstatic char defaultTranslations[] =
110492e1cfeSmrg  "<ButtonPress>:  notify()";
111492e1cfeSmrg
112492e1cfeSmrgstatic XtActionsRec actions_list[] = {
113492e1cfeSmrg    { "notify",		Notify },
114492e1cfeSmrg};
115492e1cfeSmrg
116492e1cfeSmrgFontGridClassRec fontgridClassRec = {
117492e1cfeSmrg  { /* core fields */
118492e1cfeSmrg    /* superclass               */      (WidgetClass) &simpleClassRec,
119492e1cfeSmrg    /* class_name               */      "FontGrid",
120492e1cfeSmrg    /* widget_size              */      sizeof(FontGridRec),
121492e1cfeSmrg    /* class_initialize         */      ClassInitialize,
122492e1cfeSmrg    /* class_part_initialize    */      NULL,
123492e1cfeSmrg    /* class_inited             */      FALSE,
124492e1cfeSmrg    /* initialize               */      Initialize,
125492e1cfeSmrg    /* initialize_hook          */      NULL,
126492e1cfeSmrg    /* realize                  */      Realize,
127492e1cfeSmrg    /* actions                  */      actions_list,
128492e1cfeSmrg    /* num_actions              */      XtNumber(actions_list),
129492e1cfeSmrg    /* resources                */      resources,
130492e1cfeSmrg    /* num_resources            */      XtNumber(resources),
131492e1cfeSmrg    /* xrm_class                */      NULLQUARK,
132492e1cfeSmrg    /* compress_motion          */      TRUE,
133492e1cfeSmrg    /* compress_exposure        */      TRUE,
134492e1cfeSmrg    /* compress_enterleave      */      TRUE,
135492e1cfeSmrg    /* visible_interest         */      FALSE,
136492e1cfeSmrg    /* destroy                  */      Destroy,
137492e1cfeSmrg    /* resize                   */      Resize,
138492e1cfeSmrg    /* expose                   */      Redisplay,
139492e1cfeSmrg    /* set_values               */      SetValues,
140492e1cfeSmrg    /* set_values_hook          */      NULL,
141492e1cfeSmrg    /* set_values_almost        */      XtInheritSetValuesAlmost,
142492e1cfeSmrg    /* get_values_hook          */      NULL,
143492e1cfeSmrg    /* accept_focus             */      NULL,
144492e1cfeSmrg    /* version                  */      XtVersion,
145492e1cfeSmrg    /* callback_private         */      NULL,
146492e1cfeSmrg    /* tm_table                 */      defaultTranslations,
147492e1cfeSmrg    /* query_geometry           */      XtInheritQueryGeometry,
148492e1cfeSmrg    /* display_accelerator      */      XtInheritDisplayAccelerator,
149492e1cfeSmrg    /* extension                */      NULL
150492e1cfeSmrg  },
151492e1cfeSmrg  { /* simple fields */
15231e5d586Smrg    /* change_sensitive		*/	XtInheritChangeSensitive,
15331e5d586Smrg    /* extension                */      NULL
154492e1cfeSmrg  }
155492e1cfeSmrg};
156492e1cfeSmrg
157492e1cfeSmrgWidgetClass fontgridWidgetClass = (WidgetClass) &fontgridClassRec;
158492e1cfeSmrg
159492e1cfeSmrg
160492e1cfeSmrglong
161492e1cfeSmrgGridFirstChar (Widget w)
162492e1cfeSmrg{
163492e1cfeSmrg    FontGridWidget	fgw = (FontGridWidget) w;
164492e1cfeSmrg    XFontStruct		*fs = fgw->fontgrid.text_font;
165492e1cfeSmrg#ifdef XRENDER
166492e1cfeSmrg    XftFont		*xft = fgw->fontgrid.text_face;
167492e1cfeSmrg    if (xft)
168492e1cfeSmrg    {
169492e1cfeSmrg	FcChar32    map[FC_CHARSET_MAP_SIZE];
170492e1cfeSmrg	FcChar32    next;
171492e1cfeSmrg	FcChar32    first;
172492e1cfeSmrg
173492e1cfeSmrg	first = FcCharSetFirstPage (xft->charset, map, &next);
17431e5d586Smrg	for (int i = 0; i < FC_CHARSET_MAP_SIZE; i++)
175492e1cfeSmrg	    if (map[i])
176492e1cfeSmrg	    {
177492e1cfeSmrg		FcChar32    bits = map[i];
178492e1cfeSmrg		first += i * 32;
179492e1cfeSmrg		while (!(bits & 0x1))
180492e1cfeSmrg		{
181492e1cfeSmrg		    bits >>= 1;
182492e1cfeSmrg		    first++;
183492e1cfeSmrg		}
184492e1cfeSmrg		break;
185492e1cfeSmrg	    }
186492e1cfeSmrg	return first;
187492e1cfeSmrg    }
188492e1cfeSmrg    else
189492e1cfeSmrg#endif
190492e1cfeSmrg    if (fs)
191492e1cfeSmrg    {
192492e1cfeSmrg	return (fs->min_byte1 << 8) | (fs->min_char_or_byte2);
193492e1cfeSmrg    }
194492e1cfeSmrg    else
195492e1cfeSmrg	return 0;
196492e1cfeSmrg}
197492e1cfeSmrg
198492e1cfeSmrglong
199492e1cfeSmrgGridLastChar (Widget w)
200492e1cfeSmrg{
201492e1cfeSmrg    FontGridWidget	fgw = (FontGridWidget) w;
202492e1cfeSmrg    XFontStruct		*fs = fgw->fontgrid.text_font;
203492e1cfeSmrg#ifdef XRENDER
204492e1cfeSmrg    XftFont		*xft = fgw->fontgrid.text_face;
205492e1cfeSmrg    if (xft)
206492e1cfeSmrg    {
207492e1cfeSmrg	FcChar32    this, last, next;
208492e1cfeSmrg	FcChar32    map[FC_CHARSET_MAP_SIZE];
20931e5d586Smrg
210492e1cfeSmrg	last = FcCharSetFirstPage (xft->charset, map, &next);
211492e1cfeSmrg	while ((this = FcCharSetNextPage (xft->charset, map, &next)) != FC_CHARSET_DONE)
212492e1cfeSmrg	    last = this;
213492e1cfeSmrg	last &= ~0xff;
21431e5d586Smrg	for (int i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--)
215492e1cfeSmrg	    if (map[i])
216492e1cfeSmrg	    {
217492e1cfeSmrg		FcChar32    bits = map[i];
218492e1cfeSmrg		last += i * 32 + 31;
219492e1cfeSmrg		while (!(bits & 0x80000000))
220492e1cfeSmrg		{
221492e1cfeSmrg		    last--;
222492e1cfeSmrg		    bits <<= 1;
223492e1cfeSmrg		}
224492e1cfeSmrg		break;
225492e1cfeSmrg	    }
226492e1cfeSmrg	return (long) last;
227492e1cfeSmrg    }
228492e1cfeSmrg    else
229492e1cfeSmrg#endif
230492e1cfeSmrg    if (fs)
231492e1cfeSmrg    {
232492e1cfeSmrg	return (fs->max_byte1 << 8) | (fs->max_char_or_byte2);
233492e1cfeSmrg    }
234492e1cfeSmrg    else
235492e1cfeSmrg	return 0;
236492e1cfeSmrg}
237492e1cfeSmrg
238492e1cfeSmrg/*
239492e1cfeSmrg * CI_GET_CHAR_INFO_1D - return the charinfo struct for the indicated 8bit
240492e1cfeSmrg * character.  If the character is in the column and exists, then return the
241492e1cfeSmrg * appropriate metrics (note that fonts with common per-character metrics will
242492e1cfeSmrg * return min_bounds).
243492e1cfeSmrg */
244492e1cfeSmrg
245492e1cfeSmrg#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
246492e1cfeSmrg			     (((cs)->rbearing|(cs)->lbearing| \
247492e1cfeSmrg			       (cs)->ascent|(cs)->descent) == 0))
248492e1cfeSmrg
249492e1cfeSmrg#define CI_GET_CHAR_INFO_1D(fs,col,cs) \
25031e5d586Smrgdo { \
2519e0146f7Smrg    cs = NULL; \
252492e1cfeSmrg    if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
253492e1cfeSmrg	if (fs->per_char == NULL) { \
254492e1cfeSmrg	    cs = &fs->min_bounds; \
255492e1cfeSmrg	} else { \
256492e1cfeSmrg	    cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
257492e1cfeSmrg	} \
258492e1cfeSmrg	if (CI_NONEXISTCHAR(cs)) \
2599e0146f7Smrg	    cs = NULL; \
260492e1cfeSmrg    } \
26131e5d586Smrg} while (0)
262492e1cfeSmrg
263492e1cfeSmrg/*
2643538fbe3Smrg * CI_GET_CHAR_INFO_2D - return the charinfo struct for the indicated row and
265492e1cfeSmrg * column.  This is used for fonts that have more than row zero.
266492e1cfeSmrg */
267492e1cfeSmrg#define CI_GET_CHAR_INFO_2D(fs,row,col,cs) \
26831e5d586Smrgdo { \
2699e0146f7Smrg    cs = NULL; \
270492e1cfeSmrg    if (row >= fs->min_byte1 && row <= fs->max_byte1 && \
271492e1cfeSmrg	col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
272492e1cfeSmrg	if (fs->per_char == NULL) { \
273492e1cfeSmrg	    cs = &fs->min_bounds; \
274492e1cfeSmrg	} else { \
275492e1cfeSmrg	    cs = &fs->per_char[((row - fs->min_byte1) * \
276492e1cfeSmrg			        (fs->max_char_or_byte2 - \
277492e1cfeSmrg				 fs->min_char_or_byte2 + 1)) + \
278492e1cfeSmrg			       (col - fs->min_char_or_byte2)]; \
279492e1cfeSmrg        } \
280492e1cfeSmrg	if (CI_NONEXISTCHAR(cs)) \
2819e0146f7Smrg	    cs = NULL; \
282492e1cfeSmrg    } \
28331e5d586Smrg} while (0)
284492e1cfeSmrg
285492e1cfeSmrgstatic Boolean
286492e1cfeSmrgGridHasChar (Widget w, long ch)
287492e1cfeSmrg{
288492e1cfeSmrg    FontGridWidget	fgw = (FontGridWidget) w;
289492e1cfeSmrg#ifdef XRENDER
290492e1cfeSmrg    XftFont		*xft = fgw->fontgrid.text_face;
291492e1cfeSmrg    if (xft)
292492e1cfeSmrg    {
293492e1cfeSmrg	return FcCharSetHasChar (xft->charset, (FcChar32) ch);
294492e1cfeSmrg    }
295492e1cfeSmrg    else
296492e1cfeSmrg#endif
297492e1cfeSmrg    {
298492e1cfeSmrg	XFontStruct	*fs = fgw->fontgrid.text_font;
299492e1cfeSmrg	XCharStruct	*cs;
3003538fbe3Smrg
301492e1cfeSmrg	if (!fs)
302492e1cfeSmrg	    return False;
303492e1cfeSmrg	if (fs->max_byte1 == 0)
304492e1cfeSmrg	{
305492e1cfeSmrg	    CI_GET_CHAR_INFO_1D (fs, ch, cs);
306492e1cfeSmrg	}
307492e1cfeSmrg	else
308492e1cfeSmrg	{
309492e1cfeSmrg	    unsigned int	r = (ch >> 8);
310492e1cfeSmrg	    unsigned int	c = (ch & 0xff);
311492e1cfeSmrg	    CI_GET_CHAR_INFO_2D (fs, r, c, cs);
312492e1cfeSmrg	}
3139e0146f7Smrg	return cs != NULL;
314492e1cfeSmrg    }
315492e1cfeSmrg}
316492e1cfeSmrg
317492e1cfeSmrg/*
318492e1cfeSmrg * public routines
319492e1cfeSmrg */
320492e1cfeSmrg
3213538fbe3Smrgvoid
3223538fbe3SmrgGetFontGridCellDimensions(Widget w, long *startp,
323492e1cfeSmrg			  int *ncolsp, int *nrowsp)
324492e1cfeSmrg{
325492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) w;
326492e1cfeSmrg    *startp = fgw->fontgrid.start_char;
327492e1cfeSmrg    *ncolsp = fgw->fontgrid.cell_cols;
328492e1cfeSmrg    *nrowsp = fgw->fontgrid.cell_rows;
329492e1cfeSmrg}
330492e1cfeSmrg
331492e1cfeSmrg
3323538fbe3Smrgvoid
333492e1cfeSmrgGetPrevNextStates(Widget w, Bool *prevvalidp, Bool *nextvalidp,
334492e1cfeSmrg		  Bool *prev16validp, Bool *next16validp)
335492e1cfeSmrg{
336492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) w;
337492e1cfeSmrg    long minn = (long) GridFirstChar (w);
338492e1cfeSmrg    long maxn = (long) GridLastChar (w);
339492e1cfeSmrg
340492e1cfeSmrg    *prev16validp = (fgw->fontgrid.start_char - 0xf00 > minn);
341492e1cfeSmrg    *prevvalidp = (fgw->fontgrid.start_char > minn);
342492e1cfeSmrg    *nextvalidp = (fgw->fontgrid.start_char +
343492e1cfeSmrg		   (fgw->fontgrid.cell_cols * fgw->fontgrid.cell_rows)
344492e1cfeSmrg		   < maxn);
345492e1cfeSmrg    *next16validp =((fgw->fontgrid.start_char + 0xf00 +
346492e1cfeSmrg		    (fgw->fontgrid.cell_cols * fgw->fontgrid.cell_rows))
347492e1cfeSmrg		   < maxn);
348492e1cfeSmrg}
349492e1cfeSmrg
350492e1cfeSmrg
351492e1cfeSmrg
352492e1cfeSmrg/*
353492e1cfeSmrg * private routines and methods
354492e1cfeSmrg */
355492e1cfeSmrg
356492e1cfeSmrg
3573538fbe3Smrgstatic GC
358492e1cfeSmrgget_gc(FontGridWidget fgw, Pixel fore)
359492e1cfeSmrg{
360492e1cfeSmrg    XtGCMask mask;
361492e1cfeSmrg    XGCValues gcv;
362492e1cfeSmrg
363492e1cfeSmrg    mask = (GCForeground | GCBackground | GCFunction);
364492e1cfeSmrg    gcv.foreground = fore;
365492e1cfeSmrg    gcv.background = fgw->core.background_pixel;
366492e1cfeSmrg    gcv.function = GXcopy;
367492e1cfeSmrg    if (fgw->fontgrid.text_font)
368492e1cfeSmrg    {
369492e1cfeSmrg	mask |= GCFont;
370492e1cfeSmrg	gcv.font = fgw->fontgrid.text_font->fid;
371492e1cfeSmrg    }
372492e1cfeSmrg    gcv.cap_style = CapProjecting;
373492e1cfeSmrg    mask |= GCCapStyle;
374492e1cfeSmrg    if (fgw->fontgrid.grid_width > 0) {
375492e1cfeSmrg	mask |= GCLineWidth;
3763538fbe3Smrg	gcv.line_width = ((fgw->fontgrid.grid_width < 2) ? 0 :
377492e1cfeSmrg			  fgw->fontgrid.grid_width);
378492e1cfeSmrg    }
379492e1cfeSmrg    return (XtGetGC ((Widget) fgw, mask, &gcv));
380492e1cfeSmrg}
381492e1cfeSmrg
382492e1cfeSmrg
383492e1cfeSmrg#ifdef XRENDER
3849e0146f7Smrgstatic XtConvertArgRec xftColorConvertArgs[] = {
385492e1cfeSmrg    {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen),
386492e1cfeSmrg     sizeof(Screen *)},
387492e1cfeSmrg    {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.colormap),
388492e1cfeSmrg     sizeof(Colormap)}
389492e1cfeSmrg};
390492e1cfeSmrg
391492e1cfeSmrg#define	donestr(type, value, tstr) \
39231e5d586Smrg	do {							\
393492e1cfeSmrg	    if (toVal->addr != NULL) {				\
394492e1cfeSmrg		if (toVal->size < sizeof(type)) {		\
395492e1cfeSmrg		    toVal->size = sizeof(type);			\
396492e1cfeSmrg		    XtDisplayStringConversionWarning(dpy, 	\
397492e1cfeSmrg			(char*) fromVal->addr, tstr);		\
398492e1cfeSmrg		    return False;				\
399492e1cfeSmrg		}						\
400492e1cfeSmrg		*(type*)(toVal->addr) = (value);		\
401492e1cfeSmrg	    }							\
402492e1cfeSmrg	    else {						\
403492e1cfeSmrg		static type static_val;				\
404492e1cfeSmrg		static_val = (value);				\
405492e1cfeSmrg		toVal->addr = (XPointer)&static_val;		\
406492e1cfeSmrg	    }							\
407492e1cfeSmrg	    toVal->size = sizeof(type);				\
408492e1cfeSmrg	    return True;					\
40931e5d586Smrg	} while (0)
410492e1cfeSmrg
411492e1cfeSmrgstatic void
41231e5d586SmrgXmuFreeXftColor (XtAppContext app, XrmValuePtr toVal,
41331e5d586Smrg		 XtPointer closure _X_UNUSED,
414492e1cfeSmrg		 XrmValuePtr args, Cardinal *num_args)
415492e1cfeSmrg{
416492e1cfeSmrg    Screen	*screen;
417492e1cfeSmrg    Colormap	colormap;
418492e1cfeSmrg    XftColor	*color;
4193538fbe3Smrg
420492e1cfeSmrg    if (*num_args != 2)
421492e1cfeSmrg    {
422492e1cfeSmrg	XtAppErrorMsg (app,
423492e1cfeSmrg		       "freeXftColor", "wrongParameters",
424492e1cfeSmrg		       "XtToolkitError",
425492e1cfeSmrg		       "Freeing an XftColor requires screen and colormap arguments",
426492e1cfeSmrg		       (String *) NULL, (Cardinal *)NULL);
427492e1cfeSmrg	return;
428492e1cfeSmrg    }
429492e1cfeSmrg
430492e1cfeSmrg    screen = *((Screen **) args[0].addr);
431492e1cfeSmrg    colormap = *((Colormap *) args[1].addr);
432492e1cfeSmrg    color = (XftColor *) toVal->addr;
433492e1cfeSmrg    XftColorFree (DisplayOfScreen (screen),
434492e1cfeSmrg		  DefaultVisual (DisplayOfScreen (screen),
435492e1cfeSmrg				 XScreenNumberOfScreen (screen)),
436492e1cfeSmrg		  colormap, color);
437492e1cfeSmrg}
4383538fbe3Smrg
439492e1cfeSmrgstatic Boolean
440492e1cfeSmrgXmuCvtStringToXftColor(Display *dpy,
441492e1cfeSmrg		       XrmValue *args, Cardinal *num_args,
442492e1cfeSmrg		       XrmValue *fromVal, XrmValue *toVal,
44331e5d586Smrg		       XtPointer *converter_data _X_UNUSED)
444492e1cfeSmrg{
445492e1cfeSmrg    char	    *spec;
446492e1cfeSmrg    XRenderColor    renderColor;
447492e1cfeSmrg    XftColor	    xftColor;
448492e1cfeSmrg    Screen	    *screen;
449492e1cfeSmrg    Colormap	    colormap;
4503538fbe3Smrg
451492e1cfeSmrg    if (*num_args != 2)
452492e1cfeSmrg    {
453492e1cfeSmrg	XtAppErrorMsg (XtDisplayToApplicationContext (dpy),
454492e1cfeSmrg		       "cvtStringToXftColor", "wrongParameters",
455492e1cfeSmrg		       "XtToolkitError",
456492e1cfeSmrg		       "String to render color conversion needs screen and colormap arguments",
457492e1cfeSmrg		       (String *) NULL, (Cardinal *)NULL);
458492e1cfeSmrg	return False;
459492e1cfeSmrg    }
460492e1cfeSmrg
461492e1cfeSmrg    screen = *((Screen **) args[0].addr);
462492e1cfeSmrg    colormap = *((Colormap *) args[1].addr);
463492e1cfeSmrg
464492e1cfeSmrg    spec = (char *) fromVal->addr;
465492e1cfeSmrg    if (strcasecmp (spec, XtDefaultForeground) == 0)
466492e1cfeSmrg    {
467492e1cfeSmrg	renderColor.red = 0;
468492e1cfeSmrg	renderColor.green = 0;
469492e1cfeSmrg	renderColor.blue = 0;
470492e1cfeSmrg	renderColor.alpha = 0xffff;
471492e1cfeSmrg    }
472492e1cfeSmrg    else if (strcasecmp (spec, XtDefaultBackground) == 0)
473492e1cfeSmrg    {
474492e1cfeSmrg	renderColor.red = 0xffff;
475492e1cfeSmrg	renderColor.green = 0xffff;
476492e1cfeSmrg	renderColor.blue = 0xffff;
477492e1cfeSmrg	renderColor.alpha = 0xffff;
478492e1cfeSmrg    }
479492e1cfeSmrg    else if (!XRenderParseColor (dpy, spec, &renderColor))
480492e1cfeSmrg	return False;
4813538fbe3Smrg    if (!XftColorAllocValue (dpy,
482492e1cfeSmrg			     DefaultVisual (dpy,
483492e1cfeSmrg					    XScreenNumberOfScreen (screen)),
484492e1cfeSmrg			     colormap,
485492e1cfeSmrg			     &renderColor,
486492e1cfeSmrg			     &xftColor))
487492e1cfeSmrg	return False;
4883538fbe3Smrg
489492e1cfeSmrg    donestr (XftColor, xftColor, XtRXftColor);
490492e1cfeSmrg}
491492e1cfeSmrg
492492e1cfeSmrgstatic void
49331e5d586SmrgXmuFreeXftFont (XtAppContext app, XrmValuePtr toVal, XtPointer closure _X_UNUSED,
494492e1cfeSmrg		XrmValuePtr args, Cardinal *num_args)
495492e1cfeSmrg{
496492e1cfeSmrg    Screen  *screen;
497492e1cfeSmrg    XftFont *font;
4983538fbe3Smrg
499492e1cfeSmrg    if (*num_args != 1)
500492e1cfeSmrg    {
501492e1cfeSmrg	XtAppErrorMsg (app,
502492e1cfeSmrg		       "freeXftFont", "wrongParameters",
503492e1cfeSmrg		       "XtToolkitError",
504492e1cfeSmrg		       "Freeing an XftFont requires screen argument",
505492e1cfeSmrg		       (String *) NULL, (Cardinal *)NULL);
506492e1cfeSmrg	return;
507492e1cfeSmrg    }
508492e1cfeSmrg
509492e1cfeSmrg    screen = *((Screen **) args[0].addr);
510492e1cfeSmrg    font = *((XftFont **) toVal->addr);
511492e1cfeSmrg    if (font)
512492e1cfeSmrg	XftFontClose (DisplayOfScreen (screen), font);
513492e1cfeSmrg}
514492e1cfeSmrg
515492e1cfeSmrgstatic Boolean
516492e1cfeSmrgXmuCvtStringToXftFont(Display *dpy,
517492e1cfeSmrg		      XrmValue *args, Cardinal *num_args,
518492e1cfeSmrg		      XrmValue *fromVal, XrmValue *toVal,
51931e5d586Smrg		      XtPointer *converter_data _X_UNUSED)
520492e1cfeSmrg{
521492e1cfeSmrg    char    *name;
522492e1cfeSmrg    XftFont *font;
523492e1cfeSmrg    Screen  *screen;
5243538fbe3Smrg
525492e1cfeSmrg    if (*num_args != 1)
526492e1cfeSmrg    {
527492e1cfeSmrg	XtAppErrorMsg (XtDisplayToApplicationContext (dpy),
528492e1cfeSmrg		       "cvtStringToXftFont", "wrongParameters",
529492e1cfeSmrg		       "XtToolkitError",
530492e1cfeSmrg		       "String to XftFont conversion needs screen argument",
531492e1cfeSmrg		       (String *) NULL, (Cardinal *)NULL);
532492e1cfeSmrg	return False;
533492e1cfeSmrg    }
534492e1cfeSmrg
535492e1cfeSmrg    screen = *((Screen **) args[0].addr);
536492e1cfeSmrg    name = (char *) fromVal->addr;
5379e0146f7Smrg
5389e0146f7Smrg    font = NULL;
539492e1cfeSmrg    if (name)
540492e1cfeSmrg    {
541492e1cfeSmrg	font = XftFontOpenName (dpy,
542492e1cfeSmrg				XScreenNumberOfScreen (screen),
543492e1cfeSmrg				name);
544492e1cfeSmrg	if (!font)
545492e1cfeSmrg	    XtDisplayStringConversionWarning(dpy, (char *) fromVal->addr, XtRXftFont);
546492e1cfeSmrg    }
547492e1cfeSmrg    donestr (XftFont *, font, XtRXftFont);
548492e1cfeSmrg}
549492e1cfeSmrg
550492e1cfeSmrgstatic XtConvertArgRec xftFontConvertArgs[] = {
551492e1cfeSmrg    {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen),
552492e1cfeSmrg     sizeof(Screen *)},
553492e1cfeSmrg};
554492e1cfeSmrg
555492e1cfeSmrg#endif
556492e1cfeSmrg
5573538fbe3Smrgstatic void
558492e1cfeSmrgClassInitialize(void)
559492e1cfeSmrg{
560492e1cfeSmrg    XtAddConverter (XtRString, XtRLong, XmuCvtStringToLong, NULL, 0);
561492e1cfeSmrg#ifdef XRENDER
5623538fbe3Smrg    XtSetTypeConverter (XtRString, XtRXftColor,
5633538fbe3Smrg			XmuCvtStringToXftColor,
564492e1cfeSmrg			xftColorConvertArgs, XtNumber(xftColorConvertArgs),
565492e1cfeSmrg			XtCacheByDisplay, XmuFreeXftColor);
566492e1cfeSmrg    XtSetTypeConverter (XtRString, XtRXftFont,
567492e1cfeSmrg			XmuCvtStringToXftFont,
568492e1cfeSmrg			xftFontConvertArgs, XtNumber(xftFontConvertArgs),
569492e1cfeSmrg			XtCacheByDisplay, XmuFreeXftFont);
570492e1cfeSmrg#endif
571492e1cfeSmrg}
572492e1cfeSmrg
573492e1cfeSmrg
5743538fbe3Smrgstatic void
57531e5d586SmrgInitialize(Widget request, Widget new,
57631e5d586Smrg           ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
577492e1cfeSmrg{
578492e1cfeSmrg    FontGridWidget reqfg = (FontGridWidget) request;
579492e1cfeSmrg    FontGridWidget newfg = (FontGridWidget) new;
580492e1cfeSmrg    XFontStruct *fs = newfg->fontgrid.text_font;
581492e1cfeSmrg#ifdef XRENDER
582492e1cfeSmrg    XftFont *xft = newfg->fontgrid.text_face;
583492e1cfeSmrg#endif
584492e1cfeSmrg    unsigned maxn;
585492e1cfeSmrg
586492e1cfeSmrg    if (reqfg->fontgrid.cell_cols <= 0)
587492e1cfeSmrg      newfg->fontgrid.cell_cols = 16;
588492e1cfeSmrg
589492e1cfeSmrg    if (reqfg->fontgrid.cell_rows <= 0) {
590492e1cfeSmrg#ifdef XRENDER
591492e1cfeSmrg	if (xft)
592492e1cfeSmrg	    newfg->fontgrid.cell_rows = 16;
593492e1cfeSmrg	else
594492e1cfeSmrg#endif
595492e1cfeSmrg	if (fs && fs->max_byte1 == 0) {
5963538fbe3Smrg	    newfg->fontgrid.cell_rows = (fs->max_char_or_byte2 /
597492e1cfeSmrg					 newfg->fontgrid.cell_cols) + 1;
598492e1cfeSmrg	    if (newfg->fontgrid.cell_rows > 16)
599492e1cfeSmrg	      newfg->fontgrid.cell_rows = 16;
600492e1cfeSmrg	} else
601492e1cfeSmrg	  newfg->fontgrid.cell_rows = 16;
602492e1cfeSmrg    }
603492e1cfeSmrg
604492e1cfeSmrg    if (reqfg->fontgrid.cell_width <= 0)
605492e1cfeSmrg      newfg->fontgrid.cell_width = DefaultCellWidth (newfg);
606492e1cfeSmrg    if (reqfg->fontgrid.cell_height <= 0)
607492e1cfeSmrg      newfg->fontgrid.cell_height = DefaultCellHeight (newfg);
608492e1cfeSmrg
609492e1cfeSmrg    /* give a nice size that fits one screen full */
610492e1cfeSmrg    if (newfg->core.width == 0)
611492e1cfeSmrg      newfg->core.width = (newfg->fontgrid.cell_width *
612492e1cfeSmrg			   newfg->fontgrid.cell_cols +
613492e1cfeSmrg			   newfg->fontgrid.grid_width *
614492e1cfeSmrg			   (newfg->fontgrid.cell_cols + 1));
615492e1cfeSmrg
6163538fbe3Smrg    if (newfg->core.height == 0)
6173538fbe3Smrg      newfg->core.height = (newfg->fontgrid.cell_height *
618492e1cfeSmrg			    newfg->fontgrid.cell_rows +
619492e1cfeSmrg			    newfg->fontgrid.grid_width *
620492e1cfeSmrg			    (newfg->fontgrid.cell_rows + 1));
621492e1cfeSmrg
622492e1cfeSmrg    /*
623492e1cfeSmrg     * select the first character
624492e1cfeSmrg     */
625492e1cfeSmrg
626492e1cfeSmrg    if (newfg->fontgrid.start_char == 0xffffffff)
627492e1cfeSmrg	newfg->fontgrid.start_char = GridFirstChar(new) & ~0xff;
628492e1cfeSmrg    maxn = GridLastChar (new);
6293538fbe3Smrg    if (newfg->fontgrid.start_char > maxn)
6303538fbe3Smrg	newfg->fontgrid.start_char = (maxn + 1 -
6313538fbe3Smrg				      (newfg->fontgrid.cell_cols *
632492e1cfeSmrg				       newfg->fontgrid.cell_rows));
633492e1cfeSmrg}
634492e1cfeSmrg
6353538fbe3Smrgstatic void
636492e1cfeSmrgRealize(Widget gw, Mask *valueMask, XSetWindowAttributes *attributes)
637492e1cfeSmrg{
638492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) gw;
639492e1cfeSmrg    FontGridPart *p = &fgw->fontgrid;
640492e1cfeSmrg
641492e1cfeSmrg    p->text_gc = get_gc (fgw, GridForeground (fgw));
642492e1cfeSmrg    p->box_gc = get_gc (fgw, p->box_pixel);
643492e1cfeSmrg    Resize (gw);
644492e1cfeSmrg
645492e1cfeSmrg    (*(XtSuperclass(gw)->core_class.realize)) (gw, valueMask, attributes);
646492e1cfeSmrg#ifdef XRENDER
647492e1cfeSmrg    p->draw = XftDrawCreate (XtDisplay (gw), XtWindow (gw),
648492e1cfeSmrg			     DefaultVisual (XtDisplay (gw),
649492e1cfeSmrg					    DefaultScreen(XtDisplay (gw))),
650492e1cfeSmrg			     fgw->core.colormap);
651492e1cfeSmrg#endif
652492e1cfeSmrg    return;
653492e1cfeSmrg}
654492e1cfeSmrg
655492e1cfeSmrg
656492e1cfeSmrg
6573538fbe3Smrgstatic void
658492e1cfeSmrgDestroy(Widget gw)
659492e1cfeSmrg{
660492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) gw;
661492e1cfeSmrg
662492e1cfeSmrg    XtReleaseGC (gw, fgw->fontgrid.text_gc);
663492e1cfeSmrg    XtReleaseGC (gw, fgw->fontgrid.box_gc);
664492e1cfeSmrg}
665492e1cfeSmrg
666492e1cfeSmrg
6673538fbe3Smrgstatic void
668492e1cfeSmrgResize(Widget gw)
669492e1cfeSmrg{
670492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) gw;
671492e1cfeSmrg
672492e1cfeSmrg    /* recompute in case we've changed size */
673492e1cfeSmrg    fgw->fontgrid.cell_width = CellWidth (fgw);
674492e1cfeSmrg    if (fgw->fontgrid.cell_width <= 0)
675492e1cfeSmrg	fgw->fontgrid.cell_width = 1;
676492e1cfeSmrg    fgw->fontgrid.cell_height = CellHeight (fgw);
677492e1cfeSmrg    if (fgw->fontgrid.cell_height <= 0)
678492e1cfeSmrg	fgw->fontgrid.cell_height = 1;
679492e1cfeSmrg    fgw->fontgrid.xoff = (fgw->fontgrid.cell_width -
680492e1cfeSmrg			    DefaultCellWidth (fgw)) / 2;
681492e1cfeSmrg    fgw->fontgrid.yoff = (fgw->fontgrid.cell_height -
682492e1cfeSmrg			    DefaultCellHeight (fgw)) / 2;
683492e1cfeSmrg
684492e1cfeSmrg}
685492e1cfeSmrg
686492e1cfeSmrg
687492e1cfeSmrg/* ARGSUSED */
6883538fbe3Smrgstatic void
68931e5d586SmrgRedisplay(Widget gw, XEvent *event _X_UNUSED, Region region)
690492e1cfeSmrg{
691492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) gw;
692492e1cfeSmrg    XRectangle rect;			/* bounding rect for region */
693492e1cfeSmrg    int left, right, top, bottom;	/* which cells were damaged */
694492e1cfeSmrg    int cw, ch;				/* cell size */
695492e1cfeSmrg
696492e1cfeSmrg#ifdef XRENDER
697492e1cfeSmrg    if (!fgw->fontgrid.text_face)
698492e1cfeSmrg#endif
699492e1cfeSmrg    if (!fgw->fontgrid.text_font) {
700492e1cfeSmrg	Bell (gw, XkbBI_BadValue);
701492e1cfeSmrg	return;
702492e1cfeSmrg    }
703492e1cfeSmrg
704492e1cfeSmrg    /*
705492e1cfeSmrg     * compute the left, right, top, and bottom cells that were damaged
706492e1cfeSmrg     */
707492e1cfeSmrg    XClipBox (region, &rect);
708492e1cfeSmrg    cw = fgw->fontgrid.cell_width + fgw->fontgrid.grid_width;
709492e1cfeSmrg    ch = fgw->fontgrid.cell_height + fgw->fontgrid.grid_width;
710492e1cfeSmrg    if ((left = (((int) rect.x) / cw)) < 0) left = 0;
711492e1cfeSmrg    right = (((int) (rect.x + rect.width - 1)) / cw);
712492e1cfeSmrg    if ((top = (((int) rect.y) / ch)) < 0) top = 0;
713492e1cfeSmrg    bottom = (((int) (rect.y + rect.height - 1)) / ch);
714492e1cfeSmrg
715492e1cfeSmrg    paint_grid (fgw, left, top, right - left + 1, bottom - top + 1);
716492e1cfeSmrg}
717492e1cfeSmrg
718492e1cfeSmrg
7193538fbe3Smrgstatic void
7203538fbe3Smrgpaint_grid(FontGridWidget fgw, 		/* widget in which to draw */
7213538fbe3Smrg	   int col, int row, 		/* where to start */
7223538fbe3Smrg	   int ncols, int nrows)	/* number of cells */
723492e1cfeSmrg{
724492e1cfeSmrg    FontGridPart *p = &fgw->fontgrid;
725492e1cfeSmrg    int i, j;
726492e1cfeSmrg    Display *dpy = XtDisplay(fgw);
727492e1cfeSmrg    Window wind = XtWindow(fgw);
728492e1cfeSmrg    int cw = p->cell_width + p->grid_width;
729492e1cfeSmrg    int ch = p->cell_height + p->grid_width;
730492e1cfeSmrg    int tcols = p->cell_cols;
731492e1cfeSmrg    int trows = p->cell_rows;
732492e1cfeSmrg    int x1, y1, x2, y2, x, y;
733492e1cfeSmrg    unsigned maxn = GridLastChar ((Widget) fgw);
734492e1cfeSmrg    unsigned n, prevn;
735492e1cfeSmrg    int startx;
736492e1cfeSmrg
737492e1cfeSmrg    if (col + ncols >= tcols) {
738492e1cfeSmrg	ncols = tcols - col;
739492e1cfeSmrg	if (ncols < 1) return;
740492e1cfeSmrg    }
741492e1cfeSmrg
742492e1cfeSmrg    if (row + nrows >= trows) {
743492e1cfeSmrg	nrows = trows - row;
744492e1cfeSmrg	if (nrows < 1) return;
745492e1cfeSmrg    }
746492e1cfeSmrg
747492e1cfeSmrg    /*
7483538fbe3Smrg     * paint the grid lines for the indicated rows
749492e1cfeSmrg     */
750492e1cfeSmrg    if (p->grid_width > 0) {
751492e1cfeSmrg	int half_grid_width = p->grid_width >> 1;
752492e1cfeSmrg	x1 = col * cw + half_grid_width;
753492e1cfeSmrg	y1 = row * ch + half_grid_width;
754492e1cfeSmrg	x2 = x1 + ncols * cw;
755492e1cfeSmrg	y2 = y1 + nrows * ch;
756492e1cfeSmrg	for (i = 0, x = x1; i <= ncols; i++, x += cw) {
757492e1cfeSmrg	    XDrawLine (dpy, wind, p->box_gc, x, y1, x, y2);
758492e1cfeSmrg	}
759492e1cfeSmrg	for (i = 0, y = y1; i <= nrows; i++, y += ch) {
760492e1cfeSmrg	    XDrawLine (dpy, wind, p->box_gc, x1, y, x2, y);
761492e1cfeSmrg	}
762492e1cfeSmrg    }
763492e1cfeSmrg    /*
764492e1cfeSmrg     * Draw a character in every box; treat all fonts as if they were 16bit
7653538fbe3Smrg     * fonts.  Store the high eight bits in byte1 and the low eight bits in
766492e1cfeSmrg     * byte2.
767492e1cfeSmrg     */
768492e1cfeSmrg    prevn = p->start_char + col + row * tcols;
769492e1cfeSmrg    startx = col * cw + p->internal_pad + p->grid_width;
770492e1cfeSmrg    for (j = 0,
771492e1cfeSmrg	 y = row * ch + p->internal_pad + p->grid_width + GridFontAscent (fgw);
772492e1cfeSmrg	 j < nrows; j++, y += ch) {
773492e1cfeSmrg	n = prevn;
774492e1cfeSmrg	for (i = 0, x = startx; i < ncols; i++, x += cw) {
775492e1cfeSmrg	    int xoff = p->xoff, yoff = p->yoff;
776492e1cfeSmrg	    if (n > maxn) goto done;	/* no break out of nested */
777492e1cfeSmrg
778492e1cfeSmrg#ifdef XRENDER
779492e1cfeSmrg	    if (fgw->fontgrid.text_face)
780492e1cfeSmrg	    {
781492e1cfeSmrg		XftFont *xft = p->text_face;
782492e1cfeSmrg		FcChar32    c = n;
783492e1cfeSmrg		XGlyphInfo  extents;
784492e1cfeSmrg		XftTextExtents32 (dpy, xft, &c, 1, &extents);
785492e1cfeSmrg		if (p->center_chars)
786492e1cfeSmrg		{
787492e1cfeSmrg		    xoff = (p->cell_width - extents.width) / 2 - extents.x;
788492e1cfeSmrg		    yoff = (p->cell_height - extents.height) / 2 - extents.y;
789492e1cfeSmrg		}
790492e1cfeSmrg		if (extents.width && extents.height)
791492e1cfeSmrg		{
7923538fbe3Smrg		    XClearArea (dpy, wind, x + xoff - extents.x,
793492e1cfeSmrg				y + yoff - extents.y,
794492e1cfeSmrg				extents.width, extents.height, False);
795492e1cfeSmrg		    if (p->box_chars)
796492e1cfeSmrg			XDrawRectangle (dpy, wind, p->box_gc,
7973538fbe3Smrg					x + xoff - extents.x,
798492e1cfeSmrg					y + yoff - extents.y,
799492e1cfeSmrg					extents.width - 1,
800492e1cfeSmrg					extents.height - 1);
801492e1cfeSmrg		}
802492e1cfeSmrg		XftDrawString32 (p->draw, &p->fg_color, xft,
803492e1cfeSmrg				 x + xoff, y + yoff, &c, 1);
804492e1cfeSmrg	    }
805492e1cfeSmrg	    else
806492e1cfeSmrg#endif
807492e1cfeSmrg	    {
808492e1cfeSmrg	    XChar2b thechar;
809492e1cfeSmrg
810492e1cfeSmrg	    thechar.byte1 = (n >> 8);	/* high eight bits */
811492e1cfeSmrg	    thechar.byte2 = (n & 255);	/* low eight bits */
812492e1cfeSmrg	    if (p->box_chars || p->center_chars) {
813492e1cfeSmrg		XCharStruct metrics;
814492e1cfeSmrg		int direction, fontascent, fontdescent;
815492e1cfeSmrg
816492e1cfeSmrg		XTextExtents16 (p->text_font, &thechar, 1, &direction,
817492e1cfeSmrg				&fontascent, &fontdescent, &metrics);
818492e1cfeSmrg
819492e1cfeSmrg		if (p->center_chars) {
820492e1cfeSmrg		    /*
821492e1cfeSmrg		     * We want to move the origin by enough to center the ink
8223538fbe3Smrg		     * within the cell.  The left edge will then be at
823492e1cfeSmrg		     * (cell_width - (rbearing - lbearing)) / 2; so we subtract
824492e1cfeSmrg		     * the lbearing to find the origin.  Ditto for vertical.
825492e1cfeSmrg		     */
826492e1cfeSmrg		    xoff = (((p->cell_width -
827492e1cfeSmrg			      (metrics.rbearing - metrics.lbearing)) / 2) -
828492e1cfeSmrg			    p->internal_pad - metrics.lbearing);
8293538fbe3Smrg		    yoff = (((p->cell_height -
830492e1cfeSmrg			      (metrics.descent + metrics.ascent)) / 2) -
831492e1cfeSmrg			    p->internal_pad -
832492e1cfeSmrg			    p->text_font->ascent + metrics.ascent);
833492e1cfeSmrg		}
834492e1cfeSmrg		if (p->box_chars) {
835492e1cfeSmrg		    XDrawRectangle (dpy, wind, p->box_gc,
8363538fbe3Smrg				    x + xoff, y + yoff - p->text_font->ascent,
837492e1cfeSmrg				    metrics.width - 1,
838492e1cfeSmrg				    fontascent + fontdescent - 1);
839492e1cfeSmrg		}
840492e1cfeSmrg	    }
841492e1cfeSmrg	    XDrawString16 (dpy, wind, p->text_gc, x + xoff, y + yoff,
842492e1cfeSmrg			   &thechar, 1);
843492e1cfeSmrg	    }
844492e1cfeSmrg	    n++;
845492e1cfeSmrg	}
846492e1cfeSmrg	prevn += tcols;
847492e1cfeSmrg    }
848492e1cfeSmrg
849492e1cfeSmrg  done:
850492e1cfeSmrg    /*
8513538fbe3Smrg     * paint the grid lines for the indicated rows
852492e1cfeSmrg     */
853492e1cfeSmrg    if (p->grid_width > 0) {
854492e1cfeSmrg	int half_grid_width = p->grid_width >> 1;
855492e1cfeSmrg	x1 = col * cw + half_grid_width;
856492e1cfeSmrg	y1 = row * ch + half_grid_width;
857492e1cfeSmrg	x2 = x1 + ncols * cw;
858492e1cfeSmrg	y2 = y1 + nrows * ch;
859492e1cfeSmrg	for (i = 0, x = x1; i <= ncols; i++, x += cw) {
860492e1cfeSmrg	    XDrawLine (dpy, wind, p->box_gc, x, y1, x, y2);
861492e1cfeSmrg	}
862492e1cfeSmrg	for (i = 0, y = y1; i <= nrows; i++, y += ch) {
863492e1cfeSmrg	    XDrawLine (dpy, wind, p->box_gc, x1, y, x2, y);
864492e1cfeSmrg	}
865492e1cfeSmrg    }
866492e1cfeSmrg
8673538fbe3Smrg
868492e1cfeSmrg    return;
869492e1cfeSmrg}
870492e1cfeSmrg
871492e1cfeSmrgstatic Boolean
872492e1cfeSmrgPageBlank (Widget w, long first, long last)
873492e1cfeSmrg{
874492e1cfeSmrg    while (first <= last)
875492e1cfeSmrg    {
876492e1cfeSmrg	if (GridHasChar (w, first))
877492e1cfeSmrg	    return False;
878492e1cfeSmrg	first++;
879492e1cfeSmrg    }
880492e1cfeSmrg    return True;
881492e1cfeSmrg}
882492e1cfeSmrg
883492e1cfeSmrg/*ARGSUSED*/
8843538fbe3Smrgstatic Boolean
88531e5d586SmrgSetValues(Widget current, Widget request _X_UNUSED, Widget new,
88631e5d586Smrg	  ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
887492e1cfeSmrg{
888492e1cfeSmrg    FontGridWidget curfg = (FontGridWidget) current;
889492e1cfeSmrg    FontGridWidget newfg = (FontGridWidget) new;
890492e1cfeSmrg    Boolean redisplay = FALSE;
891492e1cfeSmrg
892492e1cfeSmrg    if (curfg->fontgrid.text_font != newfg->fontgrid.text_font ||
893492e1cfeSmrg	curfg->fontgrid.internal_pad != newfg->fontgrid.internal_pad) {
894492e1cfeSmrg	newfg->fontgrid.cell_width = DefaultCellWidth (newfg);
895492e1cfeSmrg	newfg->fontgrid.cell_height = DefaultCellHeight (newfg);
896492e1cfeSmrg	redisplay = TRUE;
897492e1cfeSmrg    }
898492e1cfeSmrg
899492e1cfeSmrg    if (GridForeground(curfg) != GridForeground (newfg)) {
900492e1cfeSmrg	XtReleaseGC (new, curfg->fontgrid.text_gc);
901492e1cfeSmrg	newfg->fontgrid.text_gc = get_gc (newfg, GridForeground (newfg));
902492e1cfeSmrg	redisplay = TRUE;
903492e1cfeSmrg    }
904492e1cfeSmrg
905492e1cfeSmrg    if (curfg->fontgrid.box_pixel != newfg->fontgrid.box_pixel) {
906492e1cfeSmrg	XtReleaseGC (new, curfg->fontgrid.text_gc);
907492e1cfeSmrg	newfg->fontgrid.box_gc = get_gc (newfg, newfg->fontgrid.box_pixel);
908492e1cfeSmrg	redisplay = TRUE;
909492e1cfeSmrg    }
910492e1cfeSmrg
911492e1cfeSmrg    if (curfg->fontgrid.center_chars != newfg->fontgrid.center_chars ||
912492e1cfeSmrg	curfg->fontgrid.box_chars != newfg->fontgrid.box_chars)
913492e1cfeSmrg      redisplay = TRUE;
914492e1cfeSmrg
915492e1cfeSmrg    if (curfg->fontgrid.start_char != newfg->fontgrid.start_char) {
916492e1cfeSmrg	long maxn = GridLastChar (new);
917492e1cfeSmrg	long page = newfg->fontgrid.cell_cols * newfg->fontgrid.cell_rows;
918492e1cfeSmrg	long dir = page;
919492e1cfeSmrg	long start = newfg->fontgrid.start_char;
920492e1cfeSmrg
921492e1cfeSmrg	if (start < curfg->fontgrid.start_char)
922492e1cfeSmrg	    dir = -page;
923492e1cfeSmrg
924492e1cfeSmrg	if (start < 0)
925492e1cfeSmrg	    start = 0;
9263538fbe3Smrg	if (start > maxn)
927492e1cfeSmrg	  start = (maxn / page) * page;
9283538fbe3Smrg
929492e1cfeSmrg	while (PageBlank (new, start, start + page - 1))
930492e1cfeSmrg	{
931492e1cfeSmrg	    long    next = start + dir;
932492e1cfeSmrg
933492e1cfeSmrg	    if (next < 0 || maxn < next)
934492e1cfeSmrg		break;
935492e1cfeSmrg	    start = next;
936492e1cfeSmrg	}
937492e1cfeSmrg
938492e1cfeSmrg	newfg->fontgrid.start_char = start;
939492e1cfeSmrg	redisplay = (curfg->fontgrid.start_char != newfg->fontgrid.start_char);
940492e1cfeSmrg    }
941492e1cfeSmrg
942492e1cfeSmrg    return redisplay;
943492e1cfeSmrg}
944492e1cfeSmrg
945492e1cfeSmrg
946492e1cfeSmrg/* ARGSUSED */
9473538fbe3Smrgstatic void
94831e5d586SmrgNotify(Widget gw, XEvent *event,
94931e5d586Smrg       String *params _X_UNUSED, Cardinal *nparams _X_UNUSED)
950492e1cfeSmrg{
951492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) gw;
952492e1cfeSmrg    int x, y;				/* where the event happened */
953492e1cfeSmrg    FontGridCharRec rec;		/* callback data */
954492e1cfeSmrg
955492e1cfeSmrg    /*
956492e1cfeSmrg     * only allow events with (x,y)
957492e1cfeSmrg     */
958492e1cfeSmrg    switch (event->type) {
959492e1cfeSmrg      case KeyPress:
960492e1cfeSmrg      case KeyRelease:
961492e1cfeSmrg	x = event->xkey.x;
962492e1cfeSmrg	y = event->xkey.y;
963492e1cfeSmrg	break;
964492e1cfeSmrg      case ButtonPress:
965492e1cfeSmrg      case ButtonRelease:
966492e1cfeSmrg	x = event->xbutton.x;
967492e1cfeSmrg	y = event->xbutton.y;
968492e1cfeSmrg	break;
969492e1cfeSmrg      case MotionNotify:
970492e1cfeSmrg	x = event->xmotion.x;
971492e1cfeSmrg	y = event->xmotion.y;
972492e1cfeSmrg	break;
973492e1cfeSmrg      default:
974492e1cfeSmrg	Bell (gw, XkbBI_Ignore);
975492e1cfeSmrg	return;
976492e1cfeSmrg    }
977492e1cfeSmrg
978492e1cfeSmrg    /*
979492e1cfeSmrg     * compute the callback data
980492e1cfeSmrg     */
981492e1cfeSmrg    {
982492e1cfeSmrg	int cw = fgw->fontgrid.cell_width + fgw->fontgrid.grid_width;
983492e1cfeSmrg	int ch = fgw->fontgrid.cell_height + fgw->fontgrid.grid_width;
984492e1cfeSmrg	unsigned n;
985492e1cfeSmrg
986492e1cfeSmrg	if (x > (fgw->fontgrid.cell_cols * cw)) {
987492e1cfeSmrg	    Bell (gw, XkbBI_InvalidLocation);
988492e1cfeSmrg	    return;
989492e1cfeSmrg	}
990492e1cfeSmrg
9913538fbe3Smrg	n= (fgw->fontgrid.start_char +
992492e1cfeSmrg	    ((y / ch) * fgw->fontgrid.cell_cols) + (x / cw));
993492e1cfeSmrg
994492e1cfeSmrg	rec.thefont = fgw->fontgrid.text_font;
995492e1cfeSmrg#ifdef XRENDER
996492e1cfeSmrg	rec.theface = fgw->fontgrid.text_face;
997492e1cfeSmrg#endif
998492e1cfeSmrg	rec.thechar = n;
999492e1cfeSmrg    }
1000492e1cfeSmrg
1001492e1cfeSmrg    XtCallCallbacks (gw, XtNcallback, (XtPointer) &rec);
1002492e1cfeSmrg}
1003492e1cfeSmrg
1004