grid.c revision 9e0146f7
1492e1cfeSmrg/*
2492e1cfeSmrg * $XdotOrg: grid.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $
3492e1cfeSmrg * $Xorg: grid.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $
4492e1cfeSmrg *
5492e1cfeSmrg *
6492e1cfeSmrgCopyright 1989, 1998  The Open Group
7492e1cfeSmrg
8492e1cfeSmrgPermission to use, copy, modify, distribute, and sell this software and its
9492e1cfeSmrgdocumentation for any purpose is hereby granted without fee, provided that
10492e1cfeSmrgthe above copyright notice appear in all copies and that both that
11492e1cfeSmrgcopyright notice and this permission notice appear in supporting
12492e1cfeSmrgdocumentation.
13492e1cfeSmrg
14492e1cfeSmrgThe above copyright notice and this permission notice shall be included in
15492e1cfeSmrgall copies or substantial portions of the Software.
16492e1cfeSmrg
17492e1cfeSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18492e1cfeSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19492e1cfeSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
20492e1cfeSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21492e1cfeSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22492e1cfeSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23492e1cfeSmrg
24492e1cfeSmrgExcept as contained in this notice, the name of The Open Group shall not be
25492e1cfeSmrgused in advertising or otherwise to promote the sale, use or other dealings
26492e1cfeSmrgin this Software without prior written authorization from The Open Group.
27492e1cfeSmrg * *
28492e1cfeSmrg * Author:  Jim Fulton, MIT X Consortium
29492e1cfeSmrg */
30492e1cfeSmrg/* $XFree86: xc/programs/xfd/grid.c,v 1.9 2002/07/06 00:46:42 keithp Exp $ */
31492e1cfeSmrg
32492e1cfeSmrg
33492e1cfeSmrg#include <X11/IntrinsicP.h>
34492e1cfeSmrg#include <X11/StringDefs.h>
35492e1cfeSmrg#include <X11/Xaw/SimpleP.h>
36492e1cfeSmrg#include <X11/Xmu/Converters.h>
37492e1cfeSmrg#include <X11/Xos.h>
38492e1cfeSmrg#include "gridP.h"
39492e1cfeSmrg
40492e1cfeSmrg#ifdef XKB
41492e1cfeSmrg#include <X11/extensions/XKBbells.h>
42492e1cfeSmrg#else
43492e1cfeSmrg#define	XkbBI_MinorError		2
44492e1cfeSmrg#define	XkbBI_Ignore			11
45492e1cfeSmrg#endif
46492e1cfeSmrg
47492e1cfeSmrg#ifdef XKB
48492e1cfeSmrg#define Bell(w,n) XkbStdBell(XtDisplay(w), XtWindow(w), 50, n)
49492e1cfeSmrg#else
50492e1cfeSmrg#define Bell(w,n) XBell(XtDisplay(w), 0)
51492e1cfeSmrg#endif
52492e1cfeSmrg
53492e1cfeSmrgstatic GC get_gc(FontGridWidget fgw, Pixel fore);
54492e1cfeSmrgstatic void ClassInitialize(void);
55492e1cfeSmrgstatic void Initialize(Widget request, Widget new, ArgList args,
56492e1cfeSmrg		       Cardinal *num_args);
57492e1cfeSmrgstatic void Realize(Widget gw, Mask *valueMask,
58492e1cfeSmrg		    XSetWindowAttributes *attributes);
59492e1cfeSmrgstatic void Destroy(Widget gw);
60492e1cfeSmrgstatic void Resize(Widget gw);
61492e1cfeSmrgstatic void Redisplay(Widget gw, XEvent *event, Region region);
62492e1cfeSmrgstatic void paint_grid(FontGridWidget fgw, int col, int row,
63492e1cfeSmrg		       int ncols, int nrows);
64492e1cfeSmrgstatic Boolean SetValues(Widget current, Widget request, Widget new,
65492e1cfeSmrg			 ArgList args, Cardinal *num_args);
66492e1cfeSmrgstatic void Notify(Widget gw, XEvent *event, String *params,
67492e1cfeSmrg		   Cardinal *nparams);
68492e1cfeSmrg
69492e1cfeSmrg#define Offset(field) XtOffsetOf(FontGridRec, fontgrid.field)
70492e1cfeSmrg
71492e1cfeSmrgstatic XtResource resources[] = {
72492e1cfeSmrg    { XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
73492e1cfeSmrg	Offset(text_font), XtRString, (XtPointer) NULL },
74492e1cfeSmrg    { XtNcellColumns, XtCCellColumns, XtRInt, sizeof(int),
75492e1cfeSmrg	Offset(cell_cols), XtRImmediate, (XtPointer) 0 },
76492e1cfeSmrg    { XtNcellRows, XtCCellRows, XtRInt, sizeof(int),
77492e1cfeSmrg	Offset(cell_rows), XtRImmediate, (XtPointer) 0 },
78492e1cfeSmrg    { XtNcellWidth, XtCCellWidth, XtRInt, sizeof(int),
79492e1cfeSmrg	Offset(cell_width), XtRImmediate, (XtPointer) 0 },
80492e1cfeSmrg    { XtNcellHeight, XtCCellHeight, XtRInt, sizeof(int),
81492e1cfeSmrg	Offset(cell_height), XtRImmediate, (XtPointer) 0 },
82492e1cfeSmrg    { XtNstartChar, XtCStartChar, XtRLong, sizeof(long),
83492e1cfeSmrg	Offset(start_char), XtRImmediate, (XtPointer) 0xffffffff },
84492e1cfeSmrg#ifndef XRENDER
85492e1cfeSmrg    { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
86492e1cfeSmrg	Offset(foreground_pixel), XtRString, (XtPointer) XtDefaultForeground },
87492e1cfeSmrg#endif
88492e1cfeSmrg    { XtNcenterChars, XtCCenterChars, XtRBoolean, sizeof(Boolean),
89492e1cfeSmrg	Offset(center_chars), XtRImmediate, (XtPointer) FALSE },
90492e1cfeSmrg    { XtNboxChars, XtCBoxChars, XtRBoolean, sizeof(Boolean),
91492e1cfeSmrg	Offset(box_chars), XtRImmediate, (XtPointer) FALSE },
92492e1cfeSmrg    { XtNboxColor, XtCForeground, XtRPixel, sizeof(Pixel),
93492e1cfeSmrg	Offset(box_pixel), XtRString, (XtPointer) XtDefaultForeground },
94492e1cfeSmrg    { XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer),
95492e1cfeSmrg	Offset(callbacks), XtRCallback, (XtPointer) NULL },
96492e1cfeSmrg    { XtNinternalPad, XtCInternalPad, XtRInt, sizeof(int),
97492e1cfeSmrg	Offset(internal_pad), XtRImmediate, (XtPointer) 4 },
98492e1cfeSmrg    { XtNgridWidth, XtCGridWidth, XtRInt, sizeof(int),
99492e1cfeSmrg	Offset(grid_width), XtRImmediate, (XtPointer) 1 },
100492e1cfeSmrg#ifdef XRENDER
101492e1cfeSmrg    {XtNforeground, XtCForeground, XtRXftColor, sizeof(XftColor),
102492e1cfeSmrg        Offset(fg_color), XtRString, XtDefaultForeground},
103492e1cfeSmrg    {XtNface, XtCFace, XtRXftFont, sizeof (XftFont *),
1049e0146f7Smrg	Offset (text_face), XtRString, NULL},
105492e1cfeSmrg#endif
106492e1cfeSmrg};
107492e1cfeSmrg
108492e1cfeSmrg#undef Offset
109492e1cfeSmrg
110492e1cfeSmrgstatic char defaultTranslations[] =
111492e1cfeSmrg  "<ButtonPress>:  notify()";
112492e1cfeSmrg
113492e1cfeSmrgstatic XtActionsRec actions_list[] = {
114492e1cfeSmrg    { "notify",		Notify },
115492e1cfeSmrg};
116492e1cfeSmrg
117492e1cfeSmrgFontGridClassRec fontgridClassRec = {
118492e1cfeSmrg  { /* core fields */
119492e1cfeSmrg    /* superclass               */      (WidgetClass) &simpleClassRec,
120492e1cfeSmrg    /* class_name               */      "FontGrid",
121492e1cfeSmrg    /* widget_size              */      sizeof(FontGridRec),
122492e1cfeSmrg    /* class_initialize         */      ClassInitialize,
123492e1cfeSmrg    /* class_part_initialize    */      NULL,
124492e1cfeSmrg    /* class_inited             */      FALSE,
125492e1cfeSmrg    /* initialize               */      Initialize,
126492e1cfeSmrg    /* initialize_hook          */      NULL,
127492e1cfeSmrg    /* realize                  */      Realize,
128492e1cfeSmrg    /* actions                  */      actions_list,
129492e1cfeSmrg    /* num_actions              */      XtNumber(actions_list),
130492e1cfeSmrg    /* resources                */      resources,
131492e1cfeSmrg    /* num_resources            */      XtNumber(resources),
132492e1cfeSmrg    /* xrm_class                */      NULLQUARK,
133492e1cfeSmrg    /* compress_motion          */      TRUE,
134492e1cfeSmrg    /* compress_exposure        */      TRUE,
135492e1cfeSmrg    /* compress_enterleave      */      TRUE,
136492e1cfeSmrg    /* visible_interest         */      FALSE,
137492e1cfeSmrg    /* destroy                  */      Destroy,
138492e1cfeSmrg    /* resize                   */      Resize,
139492e1cfeSmrg    /* expose                   */      Redisplay,
140492e1cfeSmrg    /* set_values               */      SetValues,
141492e1cfeSmrg    /* set_values_hook          */      NULL,
142492e1cfeSmrg    /* set_values_almost        */      XtInheritSetValuesAlmost,
143492e1cfeSmrg    /* get_values_hook          */      NULL,
144492e1cfeSmrg    /* accept_focus             */      NULL,
145492e1cfeSmrg    /* version                  */      XtVersion,
146492e1cfeSmrg    /* callback_private         */      NULL,
147492e1cfeSmrg    /* tm_table                 */      defaultTranslations,
148492e1cfeSmrg    /* query_geometry           */      XtInheritQueryGeometry,
149492e1cfeSmrg    /* display_accelerator      */      XtInheritDisplayAccelerator,
150492e1cfeSmrg    /* extension                */      NULL
151492e1cfeSmrg  },
152492e1cfeSmrg  { /* simple fields */
153492e1cfeSmrg    /* change_sensitive		*/	XtInheritChangeSensitive
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	int	    i;
173492e1cfeSmrg
174492e1cfeSmrg	first = FcCharSetFirstPage (xft->charset, map, &next);
175492e1cfeSmrg	for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
176492e1cfeSmrg	    if (map[i])
177492e1cfeSmrg	    {
178492e1cfeSmrg		FcChar32    bits = map[i];
179492e1cfeSmrg		first += i * 32;
180492e1cfeSmrg		while (!(bits & 0x1))
181492e1cfeSmrg		{
182492e1cfeSmrg		    bits >>= 1;
183492e1cfeSmrg		    first++;
184492e1cfeSmrg		}
185492e1cfeSmrg		break;
186492e1cfeSmrg	    }
187492e1cfeSmrg	return first;
188492e1cfeSmrg    }
189492e1cfeSmrg    else
190492e1cfeSmrg#endif
191492e1cfeSmrg    if (fs)
192492e1cfeSmrg    {
193492e1cfeSmrg	return (fs->min_byte1 << 8) | (fs->min_char_or_byte2);
194492e1cfeSmrg    }
195492e1cfeSmrg    else
196492e1cfeSmrg	return 0;
197492e1cfeSmrg}
198492e1cfeSmrg
199492e1cfeSmrglong
200492e1cfeSmrgGridLastChar (Widget w)
201492e1cfeSmrg{
202492e1cfeSmrg    FontGridWidget	fgw = (FontGridWidget) w;
203492e1cfeSmrg    XFontStruct		*fs = fgw->fontgrid.text_font;
204492e1cfeSmrg#ifdef XRENDER
205492e1cfeSmrg    XftFont		*xft = fgw->fontgrid.text_face;
206492e1cfeSmrg    if (xft)
207492e1cfeSmrg    {
208492e1cfeSmrg	FcChar32    this, last, next;
209492e1cfeSmrg	FcChar32    map[FC_CHARSET_MAP_SIZE];
210492e1cfeSmrg	int	    i;
211492e1cfeSmrg	last = FcCharSetFirstPage (xft->charset, map, &next);
212492e1cfeSmrg	while ((this = FcCharSetNextPage (xft->charset, map, &next)) != FC_CHARSET_DONE)
213492e1cfeSmrg	    last = this;
214492e1cfeSmrg	last &= ~0xff;
215492e1cfeSmrg	for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--)
216492e1cfeSmrg	    if (map[i])
217492e1cfeSmrg	    {
218492e1cfeSmrg		FcChar32    bits = map[i];
219492e1cfeSmrg		last += i * 32 + 31;
220492e1cfeSmrg		while (!(bits & 0x80000000))
221492e1cfeSmrg		{
222492e1cfeSmrg		    last--;
223492e1cfeSmrg		    bits <<= 1;
224492e1cfeSmrg		}
225492e1cfeSmrg		break;
226492e1cfeSmrg	    }
227492e1cfeSmrg	return (long) last;
228492e1cfeSmrg    }
229492e1cfeSmrg    else
230492e1cfeSmrg#endif
231492e1cfeSmrg    if (fs)
232492e1cfeSmrg    {
233492e1cfeSmrg	return (fs->max_byte1 << 8) | (fs->max_char_or_byte2);
234492e1cfeSmrg    }
235492e1cfeSmrg    else
236492e1cfeSmrg	return 0;
237492e1cfeSmrg}
238492e1cfeSmrg
239492e1cfeSmrg/*
240492e1cfeSmrg * CI_GET_CHAR_INFO_1D - return the charinfo struct for the indicated 8bit
241492e1cfeSmrg * character.  If the character is in the column and exists, then return the
242492e1cfeSmrg * appropriate metrics (note that fonts with common per-character metrics will
243492e1cfeSmrg * return min_bounds).
244492e1cfeSmrg */
245492e1cfeSmrg
246492e1cfeSmrg#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
247492e1cfeSmrg			     (((cs)->rbearing|(cs)->lbearing| \
248492e1cfeSmrg			       (cs)->ascent|(cs)->descent) == 0))
249492e1cfeSmrg
250492e1cfeSmrg#define CI_GET_CHAR_INFO_1D(fs,col,cs) \
251492e1cfeSmrg{ \
2529e0146f7Smrg    cs = NULL; \
253492e1cfeSmrg    if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
254492e1cfeSmrg	if (fs->per_char == NULL) { \
255492e1cfeSmrg	    cs = &fs->min_bounds; \
256492e1cfeSmrg	} else { \
257492e1cfeSmrg	    cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
258492e1cfeSmrg	} \
259492e1cfeSmrg	if (CI_NONEXISTCHAR(cs)) \
2609e0146f7Smrg	    cs = NULL; \
261492e1cfeSmrg    } \
262492e1cfeSmrg}
263492e1cfeSmrg
264492e1cfeSmrg/*
265492e1cfeSmrg * CI_GET_CHAR_INFO_2D - return the charinfo struct for the indicated row and
266492e1cfeSmrg * column.  This is used for fonts that have more than row zero.
267492e1cfeSmrg */
268492e1cfeSmrg#define CI_GET_CHAR_INFO_2D(fs,row,col,cs) \
269492e1cfeSmrg{ \
2709e0146f7Smrg    cs = NULL; \
271492e1cfeSmrg    if (row >= fs->min_byte1 && row <= fs->max_byte1 && \
272492e1cfeSmrg	col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
273492e1cfeSmrg	if (fs->per_char == NULL) { \
274492e1cfeSmrg	    cs = &fs->min_bounds; \
275492e1cfeSmrg	} else { \
276492e1cfeSmrg	    cs = &fs->per_char[((row - fs->min_byte1) * \
277492e1cfeSmrg			        (fs->max_char_or_byte2 - \
278492e1cfeSmrg				 fs->min_char_or_byte2 + 1)) + \
279492e1cfeSmrg			       (col - fs->min_char_or_byte2)]; \
280492e1cfeSmrg        } \
281492e1cfeSmrg	if (CI_NONEXISTCHAR(cs)) \
2829e0146f7Smrg	    cs = NULL; \
283492e1cfeSmrg    } \
284492e1cfeSmrg}
285492e1cfeSmrg
286492e1cfeSmrgstatic Boolean
287492e1cfeSmrgGridHasChar (Widget w, long ch)
288492e1cfeSmrg{
289492e1cfeSmrg    FontGridWidget	fgw = (FontGridWidget) w;
290492e1cfeSmrg#ifdef XRENDER
291492e1cfeSmrg    XftFont		*xft = fgw->fontgrid.text_face;
292492e1cfeSmrg    if (xft)
293492e1cfeSmrg    {
294492e1cfeSmrg	return FcCharSetHasChar (xft->charset, (FcChar32) ch);
295492e1cfeSmrg    }
296492e1cfeSmrg    else
297492e1cfeSmrg#endif
298492e1cfeSmrg    {
299492e1cfeSmrg	XFontStruct	*fs = fgw->fontgrid.text_font;
300492e1cfeSmrg	XCharStruct	*cs;
301492e1cfeSmrg
302492e1cfeSmrg	if (!fs)
303492e1cfeSmrg	    return False;
304492e1cfeSmrg	if (fs->max_byte1 == 0)
305492e1cfeSmrg	{
306492e1cfeSmrg	    CI_GET_CHAR_INFO_1D (fs, ch, cs);
307492e1cfeSmrg	}
308492e1cfeSmrg	else
309492e1cfeSmrg	{
310492e1cfeSmrg	    unsigned int	r = (ch >> 8);
311492e1cfeSmrg	    unsigned int	c = (ch & 0xff);
312492e1cfeSmrg	    CI_GET_CHAR_INFO_2D (fs, r, c, cs);
313492e1cfeSmrg	}
3149e0146f7Smrg	return cs != NULL;
315492e1cfeSmrg    }
316492e1cfeSmrg}
317492e1cfeSmrg
318492e1cfeSmrg/*
319492e1cfeSmrg * public routines
320492e1cfeSmrg */
321492e1cfeSmrg
322492e1cfeSmrgvoid
323492e1cfeSmrgGetFontGridCellDimensions(Widget w, long *startp,
324492e1cfeSmrg			  int *ncolsp, int *nrowsp)
325492e1cfeSmrg{
326492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) w;
327492e1cfeSmrg    *startp = fgw->fontgrid.start_char;
328492e1cfeSmrg    *ncolsp = fgw->fontgrid.cell_cols;
329492e1cfeSmrg    *nrowsp = fgw->fontgrid.cell_rows;
330492e1cfeSmrg}
331492e1cfeSmrg
332492e1cfeSmrg
333492e1cfeSmrgvoid
334492e1cfeSmrgGetPrevNextStates(Widget w, Bool *prevvalidp, Bool *nextvalidp,
335492e1cfeSmrg		  Bool *prev16validp, Bool *next16validp)
336492e1cfeSmrg{
337492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) w;
338492e1cfeSmrg    long minn = (long) GridFirstChar (w);
339492e1cfeSmrg    long maxn = (long) GridLastChar (w);
340492e1cfeSmrg
341492e1cfeSmrg    *prev16validp = (fgw->fontgrid.start_char - 0xf00 > minn);
342492e1cfeSmrg    *prevvalidp = (fgw->fontgrid.start_char > minn);
343492e1cfeSmrg    *nextvalidp = (fgw->fontgrid.start_char +
344492e1cfeSmrg		   (fgw->fontgrid.cell_cols * fgw->fontgrid.cell_rows)
345492e1cfeSmrg		   < maxn);
346492e1cfeSmrg    *next16validp =((fgw->fontgrid.start_char + 0xf00 +
347492e1cfeSmrg		    (fgw->fontgrid.cell_cols * fgw->fontgrid.cell_rows))
348492e1cfeSmrg		   < maxn);
349492e1cfeSmrg}
350492e1cfeSmrg
351492e1cfeSmrg
352492e1cfeSmrg
353492e1cfeSmrg/*
354492e1cfeSmrg * private routines and methods
355492e1cfeSmrg */
356492e1cfeSmrg
357492e1cfeSmrg
358492e1cfeSmrgstatic GC
359492e1cfeSmrgget_gc(FontGridWidget fgw, Pixel fore)
360492e1cfeSmrg{
361492e1cfeSmrg    XtGCMask mask;
362492e1cfeSmrg    XGCValues gcv;
363492e1cfeSmrg
364492e1cfeSmrg    mask = (GCForeground | GCBackground | GCFunction);
365492e1cfeSmrg    gcv.foreground = fore;
366492e1cfeSmrg    gcv.background = fgw->core.background_pixel;
367492e1cfeSmrg    gcv.function = GXcopy;
368492e1cfeSmrg    if (fgw->fontgrid.text_font)
369492e1cfeSmrg    {
370492e1cfeSmrg	mask |= GCFont;
371492e1cfeSmrg	gcv.font = fgw->fontgrid.text_font->fid;
372492e1cfeSmrg    }
373492e1cfeSmrg    gcv.cap_style = CapProjecting;
374492e1cfeSmrg    mask |= GCCapStyle;
375492e1cfeSmrg    if (fgw->fontgrid.grid_width > 0) {
376492e1cfeSmrg	mask |= GCLineWidth;
377492e1cfeSmrg	gcv.line_width = ((fgw->fontgrid.grid_width < 2) ? 0 :
378492e1cfeSmrg			  fgw->fontgrid.grid_width);
379492e1cfeSmrg    }
380492e1cfeSmrg    return (XtGetGC ((Widget) fgw, mask, &gcv));
381492e1cfeSmrg}
382492e1cfeSmrg
383492e1cfeSmrg
384492e1cfeSmrg#ifdef XRENDER
3859e0146f7Smrgstatic XtConvertArgRec xftColorConvertArgs[] = {
386492e1cfeSmrg    {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen),
387492e1cfeSmrg     sizeof(Screen *)},
388492e1cfeSmrg    {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.colormap),
389492e1cfeSmrg     sizeof(Colormap)}
390492e1cfeSmrg};
391492e1cfeSmrg
392492e1cfeSmrg#define	donestr(type, value, tstr) \
393492e1cfeSmrg	{							\
394492e1cfeSmrg	    if (toVal->addr != NULL) {				\
395492e1cfeSmrg		if (toVal->size < sizeof(type)) {		\
396492e1cfeSmrg		    toVal->size = sizeof(type);			\
397492e1cfeSmrg		    XtDisplayStringConversionWarning(dpy, 	\
398492e1cfeSmrg			(char*) fromVal->addr, tstr);		\
399492e1cfeSmrg		    return False;				\
400492e1cfeSmrg		}						\
401492e1cfeSmrg		*(type*)(toVal->addr) = (value);		\
402492e1cfeSmrg	    }							\
403492e1cfeSmrg	    else {						\
404492e1cfeSmrg		static type static_val;				\
405492e1cfeSmrg		static_val = (value);				\
406492e1cfeSmrg		toVal->addr = (XPointer)&static_val;		\
407492e1cfeSmrg	    }							\
408492e1cfeSmrg	    toVal->size = sizeof(type);				\
409492e1cfeSmrg	    return True;					\
410492e1cfeSmrg	}
411492e1cfeSmrg
412492e1cfeSmrgstatic void
413492e1cfeSmrgXmuFreeXftColor (XtAppContext app, XrmValuePtr toVal, XtPointer closure,
414492e1cfeSmrg		 XrmValuePtr args, Cardinal *num_args)
415492e1cfeSmrg{
416492e1cfeSmrg    Screen	*screen;
417492e1cfeSmrg    Colormap	colormap;
418492e1cfeSmrg    XftColor	*color;
419492e1cfeSmrg
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}
438492e1cfeSmrg
439492e1cfeSmrgstatic Boolean
440492e1cfeSmrgXmuCvtStringToXftColor(Display *dpy,
441492e1cfeSmrg		       XrmValue *args, Cardinal *num_args,
442492e1cfeSmrg		       XrmValue *fromVal, XrmValue *toVal,
443492e1cfeSmrg		       XtPointer *converter_data)
444492e1cfeSmrg{
445492e1cfeSmrg    char	    *spec;
446492e1cfeSmrg    XRenderColor    renderColor;
447492e1cfeSmrg    XftColor	    xftColor;
448492e1cfeSmrg    Screen	    *screen;
449492e1cfeSmrg    Colormap	    colormap;
450492e1cfeSmrg
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;
481492e1cfeSmrg    if (!XftColorAllocValue (dpy,
482492e1cfeSmrg			     DefaultVisual (dpy,
483492e1cfeSmrg					    XScreenNumberOfScreen (screen)),
484492e1cfeSmrg			     colormap,
485492e1cfeSmrg			     &renderColor,
486492e1cfeSmrg			     &xftColor))
487492e1cfeSmrg	return False;
488492e1cfeSmrg
489492e1cfeSmrg    donestr (XftColor, xftColor, XtRXftColor);
490492e1cfeSmrg}
491492e1cfeSmrg
492492e1cfeSmrgstatic void
493492e1cfeSmrgXmuFreeXftFont (XtAppContext app, XrmValuePtr toVal, XtPointer closure,
494492e1cfeSmrg		XrmValuePtr args, Cardinal *num_args)
495492e1cfeSmrg{
496492e1cfeSmrg    Screen  *screen;
497492e1cfeSmrg    XftFont *font;
498492e1cfeSmrg
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,
519492e1cfeSmrg		      XtPointer *converter_data)
520492e1cfeSmrg{
521492e1cfeSmrg    char    *name;
522492e1cfeSmrg    XftFont *font;
523492e1cfeSmrg    Screen  *screen;
524492e1cfeSmrg
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	{
546492e1cfeSmrg	    XtDisplayStringConversionWarning(dpy, (char *) fromVal->addr, XtRXftFont);
547492e1cfeSmrg	    return False;
548492e1cfeSmrg	}
549492e1cfeSmrg    }
550492e1cfeSmrg    donestr (XftFont *, font, XtRXftFont);
551492e1cfeSmrg}
552492e1cfeSmrg
553492e1cfeSmrgstatic XtConvertArgRec xftFontConvertArgs[] = {
554492e1cfeSmrg    {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen),
555492e1cfeSmrg     sizeof(Screen *)},
556492e1cfeSmrg};
557492e1cfeSmrg
558492e1cfeSmrg#endif
559492e1cfeSmrg
560492e1cfeSmrgstatic void
561492e1cfeSmrgClassInitialize(void)
562492e1cfeSmrg{
563492e1cfeSmrg    XtAddConverter (XtRString, XtRLong, XmuCvtStringToLong, NULL, 0);
564492e1cfeSmrg#ifdef XRENDER
565492e1cfeSmrg    XtSetTypeConverter (XtRString, XtRXftColor,
566492e1cfeSmrg			XmuCvtStringToXftColor,
567492e1cfeSmrg			xftColorConvertArgs, XtNumber(xftColorConvertArgs),
568492e1cfeSmrg			XtCacheByDisplay, XmuFreeXftColor);
569492e1cfeSmrg    XtSetTypeConverter (XtRString, XtRXftFont,
570492e1cfeSmrg			XmuCvtStringToXftFont,
571492e1cfeSmrg			xftFontConvertArgs, XtNumber(xftFontConvertArgs),
572492e1cfeSmrg			XtCacheByDisplay, XmuFreeXftFont);
573492e1cfeSmrg#endif
574492e1cfeSmrg}
575492e1cfeSmrg
576492e1cfeSmrg
577492e1cfeSmrgstatic void
578492e1cfeSmrgInitialize(Widget request, Widget new, ArgList args, Cardinal *num_args)
579492e1cfeSmrg{
580492e1cfeSmrg    FontGridWidget reqfg = (FontGridWidget) request;
581492e1cfeSmrg    FontGridWidget newfg = (FontGridWidget) new;
582492e1cfeSmrg    XFontStruct *fs = newfg->fontgrid.text_font;
583492e1cfeSmrg#ifdef XRENDER
584492e1cfeSmrg    XftFont *xft = newfg->fontgrid.text_face;
585492e1cfeSmrg#endif
586492e1cfeSmrg    unsigned maxn;
587492e1cfeSmrg
588492e1cfeSmrg    if (reqfg->fontgrid.cell_cols <= 0)
589492e1cfeSmrg      newfg->fontgrid.cell_cols = 16;
590492e1cfeSmrg
591492e1cfeSmrg    if (reqfg->fontgrid.cell_rows <= 0) {
592492e1cfeSmrg#ifdef XRENDER
593492e1cfeSmrg	if (xft)
594492e1cfeSmrg	    newfg->fontgrid.cell_rows = 16;
595492e1cfeSmrg	else
596492e1cfeSmrg#endif
597492e1cfeSmrg	if (fs && fs->max_byte1 == 0) {
598492e1cfeSmrg	    newfg->fontgrid.cell_rows = (fs->max_char_or_byte2 /
599492e1cfeSmrg					 newfg->fontgrid.cell_cols) + 1;
600492e1cfeSmrg	    if (newfg->fontgrid.cell_rows > 16)
601492e1cfeSmrg	      newfg->fontgrid.cell_rows = 16;
602492e1cfeSmrg	} else
603492e1cfeSmrg	  newfg->fontgrid.cell_rows = 16;
604492e1cfeSmrg    }
605492e1cfeSmrg
606492e1cfeSmrg    if (reqfg->fontgrid.cell_width <= 0)
607492e1cfeSmrg      newfg->fontgrid.cell_width = DefaultCellWidth (newfg);
608492e1cfeSmrg    if (reqfg->fontgrid.cell_height <= 0)
609492e1cfeSmrg      newfg->fontgrid.cell_height = DefaultCellHeight (newfg);
610492e1cfeSmrg
611492e1cfeSmrg    /* give a nice size that fits one screen full */
612492e1cfeSmrg    if (newfg->core.width == 0)
613492e1cfeSmrg      newfg->core.width = (newfg->fontgrid.cell_width *
614492e1cfeSmrg			   newfg->fontgrid.cell_cols +
615492e1cfeSmrg			   newfg->fontgrid.grid_width *
616492e1cfeSmrg			   (newfg->fontgrid.cell_cols + 1));
617492e1cfeSmrg
618492e1cfeSmrg    if (newfg->core.height == 0)
619492e1cfeSmrg      newfg->core.height = (newfg->fontgrid.cell_height *
620492e1cfeSmrg			    newfg->fontgrid.cell_rows +
621492e1cfeSmrg			    newfg->fontgrid.grid_width *
622492e1cfeSmrg			    (newfg->fontgrid.cell_rows + 1));
623492e1cfeSmrg
624492e1cfeSmrg    /*
625492e1cfeSmrg     * select the first character
626492e1cfeSmrg     */
627492e1cfeSmrg
628492e1cfeSmrg    if (newfg->fontgrid.start_char == 0xffffffff)
629492e1cfeSmrg	newfg->fontgrid.start_char = GridFirstChar(new) & ~0xff;
630492e1cfeSmrg    maxn = GridLastChar (new);
631492e1cfeSmrg    if (newfg->fontgrid.start_char > maxn)
632492e1cfeSmrg	newfg->fontgrid.start_char = (maxn + 1 -
633492e1cfeSmrg				      (newfg->fontgrid.cell_cols *
634492e1cfeSmrg				       newfg->fontgrid.cell_rows));
635492e1cfeSmrg}
636492e1cfeSmrg
637492e1cfeSmrgstatic void
638492e1cfeSmrgRealize(Widget gw, Mask *valueMask, XSetWindowAttributes *attributes)
639492e1cfeSmrg{
640492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) gw;
641492e1cfeSmrg    FontGridPart *p = &fgw->fontgrid;
642492e1cfeSmrg
643492e1cfeSmrg    p->text_gc = get_gc (fgw, GridForeground (fgw));
644492e1cfeSmrg    p->box_gc = get_gc (fgw, p->box_pixel);
645492e1cfeSmrg    Resize (gw);
646492e1cfeSmrg
647492e1cfeSmrg    (*(XtSuperclass(gw)->core_class.realize)) (gw, valueMask, attributes);
648492e1cfeSmrg#ifdef XRENDER
649492e1cfeSmrg    p->draw = XftDrawCreate (XtDisplay (gw), XtWindow (gw),
650492e1cfeSmrg			     DefaultVisual (XtDisplay (gw),
651492e1cfeSmrg					    DefaultScreen(XtDisplay (gw))),
652492e1cfeSmrg			     fgw->core.colormap);
653492e1cfeSmrg#endif
654492e1cfeSmrg    return;
655492e1cfeSmrg}
656492e1cfeSmrg
657492e1cfeSmrg
658492e1cfeSmrg
659492e1cfeSmrgstatic void
660492e1cfeSmrgDestroy(Widget gw)
661492e1cfeSmrg{
662492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) gw;
663492e1cfeSmrg
664492e1cfeSmrg    XtReleaseGC (gw, fgw->fontgrid.text_gc);
665492e1cfeSmrg    XtReleaseGC (gw, fgw->fontgrid.box_gc);
666492e1cfeSmrg}
667492e1cfeSmrg
668492e1cfeSmrg
669492e1cfeSmrgstatic void
670492e1cfeSmrgResize(Widget gw)
671492e1cfeSmrg{
672492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) gw;
673492e1cfeSmrg
674492e1cfeSmrg    /* recompute in case we've changed size */
675492e1cfeSmrg    fgw->fontgrid.cell_width = CellWidth (fgw);
676492e1cfeSmrg    if (fgw->fontgrid.cell_width <= 0)
677492e1cfeSmrg	fgw->fontgrid.cell_width = 1;
678492e1cfeSmrg    fgw->fontgrid.cell_height = CellHeight (fgw);
679492e1cfeSmrg    if (fgw->fontgrid.cell_height <= 0)
680492e1cfeSmrg	fgw->fontgrid.cell_height = 1;
681492e1cfeSmrg    fgw->fontgrid.xoff = (fgw->fontgrid.cell_width -
682492e1cfeSmrg			    DefaultCellWidth (fgw)) / 2;
683492e1cfeSmrg    fgw->fontgrid.yoff = (fgw->fontgrid.cell_height -
684492e1cfeSmrg			    DefaultCellHeight (fgw)) / 2;
685492e1cfeSmrg
686492e1cfeSmrg}
687492e1cfeSmrg
688492e1cfeSmrg
689492e1cfeSmrg/* ARGSUSED */
690492e1cfeSmrgstatic void
691492e1cfeSmrgRedisplay(Widget gw, XEvent *event, Region region)
692492e1cfeSmrg{
693492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) gw;
694492e1cfeSmrg    XRectangle rect;			/* bounding rect for region */
695492e1cfeSmrg    int left, right, top, bottom;	/* which cells were damaged */
696492e1cfeSmrg    int cw, ch;				/* cell size */
697492e1cfeSmrg
698492e1cfeSmrg#ifdef XRENDER
699492e1cfeSmrg    if (!fgw->fontgrid.text_face)
700492e1cfeSmrg#endif
701492e1cfeSmrg    if (!fgw->fontgrid.text_font) {
702492e1cfeSmrg	Bell (gw, XkbBI_BadValue);
703492e1cfeSmrg	return;
704492e1cfeSmrg    }
705492e1cfeSmrg
706492e1cfeSmrg    /*
707492e1cfeSmrg     * compute the left, right, top, and bottom cells that were damaged
708492e1cfeSmrg     */
709492e1cfeSmrg    XClipBox (region, &rect);
710492e1cfeSmrg    cw = fgw->fontgrid.cell_width + fgw->fontgrid.grid_width;
711492e1cfeSmrg    ch = fgw->fontgrid.cell_height + fgw->fontgrid.grid_width;
712492e1cfeSmrg    if ((left = (((int) rect.x) / cw)) < 0) left = 0;
713492e1cfeSmrg    right = (((int) (rect.x + rect.width - 1)) / cw);
714492e1cfeSmrg    if ((top = (((int) rect.y) / ch)) < 0) top = 0;
715492e1cfeSmrg    bottom = (((int) (rect.y + rect.height - 1)) / ch);
716492e1cfeSmrg
717492e1cfeSmrg    paint_grid (fgw, left, top, right - left + 1, bottom - top + 1);
718492e1cfeSmrg}
719492e1cfeSmrg
720492e1cfeSmrg
721492e1cfeSmrgstatic void
722492e1cfeSmrgpaint_grid(FontGridWidget fgw, 		/* widget in which to draw */
723492e1cfeSmrg	   int col, int row, 		/* where to start */
724492e1cfeSmrg	   int ncols, int nrows)	/* number of cells */
725492e1cfeSmrg{
726492e1cfeSmrg    FontGridPart *p = &fgw->fontgrid;
727492e1cfeSmrg    int i, j;
728492e1cfeSmrg    Display *dpy = XtDisplay(fgw);
729492e1cfeSmrg    Window wind = XtWindow(fgw);
730492e1cfeSmrg    int cw = p->cell_width + p->grid_width;
731492e1cfeSmrg    int ch = p->cell_height + p->grid_width;
732492e1cfeSmrg    int tcols = p->cell_cols;
733492e1cfeSmrg    int trows = p->cell_rows;
734492e1cfeSmrg    int x1, y1, x2, y2, x, y;
735492e1cfeSmrg    unsigned maxn = GridLastChar ((Widget) fgw);
736492e1cfeSmrg    unsigned n, prevn;
737492e1cfeSmrg    int startx;
738492e1cfeSmrg
739492e1cfeSmrg    if (col + ncols >= tcols) {
740492e1cfeSmrg	ncols = tcols - col;
741492e1cfeSmrg	if (ncols < 1) return;
742492e1cfeSmrg    }
743492e1cfeSmrg
744492e1cfeSmrg    if (row + nrows >= trows) {
745492e1cfeSmrg	nrows = trows - row;
746492e1cfeSmrg	if (nrows < 1) return;
747492e1cfeSmrg    }
748492e1cfeSmrg
749492e1cfeSmrg    /*
750492e1cfeSmrg     * paint the grid lines for the indicated rows
751492e1cfeSmrg     */
752492e1cfeSmrg    if (p->grid_width > 0) {
753492e1cfeSmrg	int half_grid_width = p->grid_width >> 1;
754492e1cfeSmrg	x1 = col * cw + half_grid_width;
755492e1cfeSmrg	y1 = row * ch + half_grid_width;
756492e1cfeSmrg	x2 = x1 + ncols * cw;
757492e1cfeSmrg	y2 = y1 + nrows * ch;
758492e1cfeSmrg	for (i = 0, x = x1; i <= ncols; i++, x += cw) {
759492e1cfeSmrg	    XDrawLine (dpy, wind, p->box_gc, x, y1, x, y2);
760492e1cfeSmrg	}
761492e1cfeSmrg	for (i = 0, y = y1; i <= nrows; i++, y += ch) {
762492e1cfeSmrg	    XDrawLine (dpy, wind, p->box_gc, x1, y, x2, y);
763492e1cfeSmrg	}
764492e1cfeSmrg    }
765492e1cfeSmrg    /*
766492e1cfeSmrg     * Draw a character in every box; treat all fonts as if they were 16bit
767492e1cfeSmrg     * fonts.  Store the high eight bits in byte1 and the low eight bits in
768492e1cfeSmrg     * byte2.
769492e1cfeSmrg     */
770492e1cfeSmrg    prevn = p->start_char + col + row * tcols;
771492e1cfeSmrg    startx = col * cw + p->internal_pad + p->grid_width;
772492e1cfeSmrg    for (j = 0,
773492e1cfeSmrg	 y = row * ch + p->internal_pad + p->grid_width + GridFontAscent (fgw);
774492e1cfeSmrg	 j < nrows; j++, y += ch) {
775492e1cfeSmrg	n = prevn;
776492e1cfeSmrg	for (i = 0, x = startx; i < ncols; i++, x += cw) {
777492e1cfeSmrg	    int xoff = p->xoff, yoff = p->yoff;
778492e1cfeSmrg	    if (n > maxn) goto done;	/* no break out of nested */
779492e1cfeSmrg
780492e1cfeSmrg#ifdef XRENDER
781492e1cfeSmrg	    if (fgw->fontgrid.text_face)
782492e1cfeSmrg	    {
783492e1cfeSmrg		XftFont *xft = p->text_face;
784492e1cfeSmrg		FcChar32    c = n;
785492e1cfeSmrg		XGlyphInfo  extents;
786492e1cfeSmrg		XftTextExtents32 (dpy, xft, &c, 1, &extents);
787492e1cfeSmrg		if (p->center_chars)
788492e1cfeSmrg		{
789492e1cfeSmrg		    xoff = (p->cell_width - extents.width) / 2 - extents.x;
790492e1cfeSmrg		    yoff = (p->cell_height - extents.height) / 2 - extents.y;
791492e1cfeSmrg		}
792492e1cfeSmrg		if (extents.width && extents.height)
793492e1cfeSmrg		{
794492e1cfeSmrg		    XClearArea (dpy, wind, x + xoff - extents.x,
795492e1cfeSmrg				y + yoff - extents.y,
796492e1cfeSmrg				extents.width, extents.height, False);
797492e1cfeSmrg		    if (p->box_chars)
798492e1cfeSmrg			XDrawRectangle (dpy, wind, p->box_gc,
799492e1cfeSmrg					x + xoff - extents.x,
800492e1cfeSmrg					y + yoff - extents.y,
801492e1cfeSmrg					extents.width - 1,
802492e1cfeSmrg					extents.height - 1);
803492e1cfeSmrg		}
804492e1cfeSmrg		XftDrawString32 (p->draw, &p->fg_color, xft,
805492e1cfeSmrg				 x + xoff, y + yoff, &c, 1);
806492e1cfeSmrg	    }
807492e1cfeSmrg	    else
808492e1cfeSmrg#endif
809492e1cfeSmrg	    {
810492e1cfeSmrg	    XChar2b thechar;
811492e1cfeSmrg
812492e1cfeSmrg	    thechar.byte1 = (n >> 8);	/* high eight bits */
813492e1cfeSmrg	    thechar.byte2 = (n & 255);	/* low eight bits */
814492e1cfeSmrg	    if (p->box_chars || p->center_chars) {
815492e1cfeSmrg		XCharStruct metrics;
816492e1cfeSmrg		int direction, fontascent, fontdescent;
817492e1cfeSmrg
818492e1cfeSmrg		XTextExtents16 (p->text_font, &thechar, 1, &direction,
819492e1cfeSmrg				&fontascent, &fontdescent, &metrics);
820492e1cfeSmrg
821492e1cfeSmrg		if (p->center_chars) {
822492e1cfeSmrg		    /*
823492e1cfeSmrg		     * We want to move the origin by enough to center the ink
824492e1cfeSmrg		     * within the cell.  The left edge will then be at
825492e1cfeSmrg		     * (cell_width - (rbearing - lbearing)) / 2; so we subtract
826492e1cfeSmrg		     * the lbearing to find the origin.  Ditto for vertical.
827492e1cfeSmrg		     */
828492e1cfeSmrg		    xoff = (((p->cell_width -
829492e1cfeSmrg			      (metrics.rbearing - metrics.lbearing)) / 2) -
830492e1cfeSmrg			    p->internal_pad - metrics.lbearing);
831492e1cfeSmrg		    yoff = (((p->cell_height -
832492e1cfeSmrg			      (metrics.descent + metrics.ascent)) / 2) -
833492e1cfeSmrg			    p->internal_pad -
834492e1cfeSmrg			    p->text_font->ascent + metrics.ascent);
835492e1cfeSmrg		}
836492e1cfeSmrg		if (p->box_chars) {
837492e1cfeSmrg		    XDrawRectangle (dpy, wind, p->box_gc,
838492e1cfeSmrg				    x + xoff, y + yoff - p->text_font->ascent,
839492e1cfeSmrg				    metrics.width - 1,
840492e1cfeSmrg				    fontascent + fontdescent - 1);
841492e1cfeSmrg		}
842492e1cfeSmrg	    }
843492e1cfeSmrg	    XDrawString16 (dpy, wind, p->text_gc, x + xoff, y + yoff,
844492e1cfeSmrg			   &thechar, 1);
845492e1cfeSmrg	    }
846492e1cfeSmrg	    n++;
847492e1cfeSmrg	}
848492e1cfeSmrg	prevn += tcols;
849492e1cfeSmrg    }
850492e1cfeSmrg
851492e1cfeSmrg  done:
852492e1cfeSmrg    /*
853492e1cfeSmrg     * paint the grid lines for the indicated rows
854492e1cfeSmrg     */
855492e1cfeSmrg    if (p->grid_width > 0) {
856492e1cfeSmrg	int half_grid_width = p->grid_width >> 1;
857492e1cfeSmrg	x1 = col * cw + half_grid_width;
858492e1cfeSmrg	y1 = row * ch + half_grid_width;
859492e1cfeSmrg	x2 = x1 + ncols * cw;
860492e1cfeSmrg	y2 = y1 + nrows * ch;
861492e1cfeSmrg	for (i = 0, x = x1; i <= ncols; i++, x += cw) {
862492e1cfeSmrg	    XDrawLine (dpy, wind, p->box_gc, x, y1, x, y2);
863492e1cfeSmrg	}
864492e1cfeSmrg	for (i = 0, y = y1; i <= nrows; i++, y += ch) {
865492e1cfeSmrg	    XDrawLine (dpy, wind, p->box_gc, x1, y, x2, y);
866492e1cfeSmrg	}
867492e1cfeSmrg    }
868492e1cfeSmrg
869492e1cfeSmrg
870492e1cfeSmrg    return;
871492e1cfeSmrg}
872492e1cfeSmrg
873492e1cfeSmrgstatic Boolean
874492e1cfeSmrgPageBlank (Widget w, long first, long last)
875492e1cfeSmrg{
876492e1cfeSmrg    while (first <= last)
877492e1cfeSmrg    {
878492e1cfeSmrg	if (GridHasChar (w, first))
879492e1cfeSmrg	    return False;
880492e1cfeSmrg	first++;
881492e1cfeSmrg    }
882492e1cfeSmrg    return True;
883492e1cfeSmrg}
884492e1cfeSmrg
885492e1cfeSmrg/*ARGSUSED*/
886492e1cfeSmrgstatic Boolean
887492e1cfeSmrgSetValues(Widget current, Widget request, Widget new,
888492e1cfeSmrg	  ArgList args, Cardinal *num_args)
889492e1cfeSmrg{
890492e1cfeSmrg    FontGridWidget curfg = (FontGridWidget) current;
891492e1cfeSmrg    FontGridWidget newfg = (FontGridWidget) new;
892492e1cfeSmrg    Boolean redisplay = FALSE;
893492e1cfeSmrg
894492e1cfeSmrg    if (curfg->fontgrid.text_font != newfg->fontgrid.text_font ||
895492e1cfeSmrg	curfg->fontgrid.internal_pad != newfg->fontgrid.internal_pad) {
896492e1cfeSmrg	newfg->fontgrid.cell_width = DefaultCellWidth (newfg);
897492e1cfeSmrg	newfg->fontgrid.cell_height = DefaultCellHeight (newfg);
898492e1cfeSmrg	redisplay = TRUE;
899492e1cfeSmrg    }
900492e1cfeSmrg
901492e1cfeSmrg    if (GridForeground(curfg) != GridForeground (newfg)) {
902492e1cfeSmrg	XtReleaseGC (new, curfg->fontgrid.text_gc);
903492e1cfeSmrg	newfg->fontgrid.text_gc = get_gc (newfg, GridForeground (newfg));
904492e1cfeSmrg	redisplay = TRUE;
905492e1cfeSmrg    }
906492e1cfeSmrg
907492e1cfeSmrg    if (curfg->fontgrid.box_pixel != newfg->fontgrid.box_pixel) {
908492e1cfeSmrg	XtReleaseGC (new, curfg->fontgrid.text_gc);
909492e1cfeSmrg	newfg->fontgrid.box_gc = get_gc (newfg, newfg->fontgrid.box_pixel);
910492e1cfeSmrg	redisplay = TRUE;
911492e1cfeSmrg    }
912492e1cfeSmrg
913492e1cfeSmrg    if (curfg->fontgrid.center_chars != newfg->fontgrid.center_chars ||
914492e1cfeSmrg	curfg->fontgrid.box_chars != newfg->fontgrid.box_chars)
915492e1cfeSmrg      redisplay = TRUE;
916492e1cfeSmrg
917492e1cfeSmrg    if (curfg->fontgrid.start_char != newfg->fontgrid.start_char) {
918492e1cfeSmrg	long maxn = GridLastChar (new);
919492e1cfeSmrg	long page = newfg->fontgrid.cell_cols * newfg->fontgrid.cell_rows;
920492e1cfeSmrg	long dir = page;
921492e1cfeSmrg	long start = newfg->fontgrid.start_char;
922492e1cfeSmrg
923492e1cfeSmrg	if (start < curfg->fontgrid.start_char)
924492e1cfeSmrg	    dir = -page;
925492e1cfeSmrg
926492e1cfeSmrg	if (start < 0)
927492e1cfeSmrg	    start = 0;
928492e1cfeSmrg	if (start > maxn)
929492e1cfeSmrg	  start = (maxn / page) * page;
930492e1cfeSmrg
931492e1cfeSmrg	while (PageBlank (new, start, start + page - 1))
932492e1cfeSmrg	{
933492e1cfeSmrg	    long    next = start + dir;
934492e1cfeSmrg
935492e1cfeSmrg	    if (next < 0 || maxn < next)
936492e1cfeSmrg		break;
937492e1cfeSmrg	    start = next;
938492e1cfeSmrg	}
939492e1cfeSmrg
940492e1cfeSmrg	newfg->fontgrid.start_char = start;
941492e1cfeSmrg	redisplay = (curfg->fontgrid.start_char != newfg->fontgrid.start_char);
942492e1cfeSmrg    }
943492e1cfeSmrg
944492e1cfeSmrg    return redisplay;
945492e1cfeSmrg}
946492e1cfeSmrg
947492e1cfeSmrg
948492e1cfeSmrg/* ARGSUSED */
949492e1cfeSmrgstatic void
950492e1cfeSmrgNotify(Widget gw, XEvent *event, String *params, Cardinal *nparams)
951492e1cfeSmrg{
952492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) gw;
953492e1cfeSmrg    int x, y;				/* where the event happened */
954492e1cfeSmrg    FontGridCharRec rec;		/* callback data */
955492e1cfeSmrg
956492e1cfeSmrg    /*
957492e1cfeSmrg     * only allow events with (x,y)
958492e1cfeSmrg     */
959492e1cfeSmrg    switch (event->type) {
960492e1cfeSmrg      case KeyPress:
961492e1cfeSmrg      case KeyRelease:
962492e1cfeSmrg	x = event->xkey.x;
963492e1cfeSmrg	y = event->xkey.y;
964492e1cfeSmrg	break;
965492e1cfeSmrg      case ButtonPress:
966492e1cfeSmrg      case ButtonRelease:
967492e1cfeSmrg	x = event->xbutton.x;
968492e1cfeSmrg	y = event->xbutton.y;
969492e1cfeSmrg	break;
970492e1cfeSmrg      case MotionNotify:
971492e1cfeSmrg	x = event->xmotion.x;
972492e1cfeSmrg	y = event->xmotion.y;
973492e1cfeSmrg	break;
974492e1cfeSmrg      default:
975492e1cfeSmrg	Bell (gw, XkbBI_Ignore);
976492e1cfeSmrg	return;
977492e1cfeSmrg    }
978492e1cfeSmrg
979492e1cfeSmrg    /*
980492e1cfeSmrg     * compute the callback data
981492e1cfeSmrg     */
982492e1cfeSmrg    {
983492e1cfeSmrg	int cw = fgw->fontgrid.cell_width + fgw->fontgrid.grid_width;
984492e1cfeSmrg	int ch = fgw->fontgrid.cell_height + fgw->fontgrid.grid_width;
985492e1cfeSmrg	unsigned n;
986492e1cfeSmrg
987492e1cfeSmrg	if (x > (fgw->fontgrid.cell_cols * cw)) {
988492e1cfeSmrg	    Bell (gw, XkbBI_InvalidLocation);
989492e1cfeSmrg	    return;
990492e1cfeSmrg	}
991492e1cfeSmrg
992492e1cfeSmrg	n= (fgw->fontgrid.start_char +
993492e1cfeSmrg	    ((y / ch) * fgw->fontgrid.cell_cols) + (x / cw));
994492e1cfeSmrg
995492e1cfeSmrg	rec.thefont = fgw->fontgrid.text_font;
996492e1cfeSmrg#ifdef XRENDER
997492e1cfeSmrg	rec.theface = fgw->fontgrid.text_face;
998492e1cfeSmrg#endif
999492e1cfeSmrg	rec.thechar = n;
1000492e1cfeSmrg    }
1001492e1cfeSmrg
1002492e1cfeSmrg    XtCallCallbacks (gw, XtNcallback, (XtPointer) &rec);
1003492e1cfeSmrg}
1004492e1cfeSmrg
1005