grid.c revision 1afad795
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
28492e1cfeSmrg#include <X11/IntrinsicP.h>
29492e1cfeSmrg#include <X11/StringDefs.h>
30492e1cfeSmrg#include <X11/Xaw/SimpleP.h>
31492e1cfeSmrg#include <X11/Xmu/Converters.h>
32492e1cfeSmrg#include <X11/Xos.h>
33492e1cfeSmrg#include "gridP.h"
34492e1cfeSmrg
35492e1cfeSmrg#ifdef XKB
36492e1cfeSmrg#include <X11/extensions/XKBbells.h>
37492e1cfeSmrg#else
38492e1cfeSmrg#define	XkbBI_MinorError		2
39492e1cfeSmrg#define	XkbBI_Ignore			11
40492e1cfeSmrg#endif
41492e1cfeSmrg
42492e1cfeSmrg#ifdef XKB
43492e1cfeSmrg#define Bell(w,n) XkbStdBell(XtDisplay(w), XtWindow(w), 50, n)
44492e1cfeSmrg#else
45492e1cfeSmrg#define Bell(w,n) XBell(XtDisplay(w), 0)
46492e1cfeSmrg#endif
47492e1cfeSmrg
48492e1cfeSmrgstatic GC get_gc(FontGridWidget fgw, Pixel fore);
49492e1cfeSmrgstatic void ClassInitialize(void);
503538fbe3Smrgstatic void Initialize(Widget request, Widget new, ArgList args,
51492e1cfeSmrg		       Cardinal *num_args);
523538fbe3Smrgstatic void Realize(Widget gw, Mask *valueMask,
53492e1cfeSmrg		    XSetWindowAttributes *attributes);
54492e1cfeSmrgstatic void Destroy(Widget gw);
55492e1cfeSmrgstatic void Resize(Widget gw);
56492e1cfeSmrgstatic void Redisplay(Widget gw, XEvent *event, Region region);
573538fbe3Smrgstatic void paint_grid(FontGridWidget fgw, int col, int row,
58492e1cfeSmrg		       int ncols, int nrows);
593538fbe3Smrgstatic Boolean SetValues(Widget current, Widget request, Widget new,
60492e1cfeSmrg			 ArgList args, Cardinal *num_args);
613538fbe3Smrgstatic void Notify(Widget gw, XEvent *event, String *params,
62492e1cfeSmrg		   Cardinal *nparams);
63492e1cfeSmrg
64492e1cfeSmrg#define Offset(field) XtOffsetOf(FontGridRec, fontgrid.field)
65492e1cfeSmrg
66492e1cfeSmrgstatic XtResource resources[] = {
67492e1cfeSmrg    { XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
68492e1cfeSmrg	Offset(text_font), XtRString, (XtPointer) NULL },
69492e1cfeSmrg    { XtNcellColumns, XtCCellColumns, XtRInt, sizeof(int),
70492e1cfeSmrg	Offset(cell_cols), XtRImmediate, (XtPointer) 0 },
71492e1cfeSmrg    { XtNcellRows, XtCCellRows, XtRInt, sizeof(int),
72492e1cfeSmrg	Offset(cell_rows), XtRImmediate, (XtPointer) 0 },
73492e1cfeSmrg    { XtNcellWidth, XtCCellWidth, XtRInt, sizeof(int),
74492e1cfeSmrg	Offset(cell_width), XtRImmediate, (XtPointer) 0 },
75492e1cfeSmrg    { XtNcellHeight, XtCCellHeight, XtRInt, sizeof(int),
76492e1cfeSmrg	Offset(cell_height), XtRImmediate, (XtPointer) 0 },
77492e1cfeSmrg    { XtNstartChar, XtCStartChar, XtRLong, sizeof(long),
78492e1cfeSmrg	Offset(start_char), XtRImmediate, (XtPointer) 0xffffffff },
79492e1cfeSmrg#ifndef XRENDER
80492e1cfeSmrg    { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
81492e1cfeSmrg	Offset(foreground_pixel), XtRString, (XtPointer) XtDefaultForeground },
82492e1cfeSmrg#endif
83492e1cfeSmrg    { XtNcenterChars, XtCCenterChars, XtRBoolean, sizeof(Boolean),
84492e1cfeSmrg	Offset(center_chars), XtRImmediate, (XtPointer) FALSE },
85492e1cfeSmrg    { XtNboxChars, XtCBoxChars, XtRBoolean, sizeof(Boolean),
86492e1cfeSmrg	Offset(box_chars), XtRImmediate, (XtPointer) FALSE },
87492e1cfeSmrg    { XtNboxColor, XtCForeground, XtRPixel, sizeof(Pixel),
88492e1cfeSmrg	Offset(box_pixel), XtRString, (XtPointer) XtDefaultForeground },
89492e1cfeSmrg    { XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer),
90492e1cfeSmrg	Offset(callbacks), XtRCallback, (XtPointer) NULL },
91492e1cfeSmrg    { XtNinternalPad, XtCInternalPad, XtRInt, sizeof(int),
92492e1cfeSmrg	Offset(internal_pad), XtRImmediate, (XtPointer) 4 },
93492e1cfeSmrg    { XtNgridWidth, XtCGridWidth, XtRInt, sizeof(int),
94492e1cfeSmrg	Offset(grid_width), XtRImmediate, (XtPointer) 1 },
95492e1cfeSmrg#ifdef XRENDER
96492e1cfeSmrg    {XtNforeground, XtCForeground, XtRXftColor, sizeof(XftColor),
97492e1cfeSmrg        Offset(fg_color), XtRString, XtDefaultForeground},
98492e1cfeSmrg    {XtNface, XtCFace, XtRXftFont, sizeof (XftFont *),
999e0146f7Smrg	Offset (text_face), XtRString, NULL},
100492e1cfeSmrg#endif
101492e1cfeSmrg};
102492e1cfeSmrg
103492e1cfeSmrg#undef Offset
104492e1cfeSmrg
1053538fbe3Smrgstatic char defaultTranslations[] =
106492e1cfeSmrg  "<ButtonPress>:  notify()";
107492e1cfeSmrg
108492e1cfeSmrgstatic XtActionsRec actions_list[] = {
109492e1cfeSmrg    { "notify",		Notify },
110492e1cfeSmrg};
111492e1cfeSmrg
112492e1cfeSmrgFontGridClassRec fontgridClassRec = {
113492e1cfeSmrg  { /* core fields */
114492e1cfeSmrg    /* superclass               */      (WidgetClass) &simpleClassRec,
115492e1cfeSmrg    /* class_name               */      "FontGrid",
116492e1cfeSmrg    /* widget_size              */      sizeof(FontGridRec),
117492e1cfeSmrg    /* class_initialize         */      ClassInitialize,
118492e1cfeSmrg    /* class_part_initialize    */      NULL,
119492e1cfeSmrg    /* class_inited             */      FALSE,
120492e1cfeSmrg    /* initialize               */      Initialize,
121492e1cfeSmrg    /* initialize_hook          */      NULL,
122492e1cfeSmrg    /* realize                  */      Realize,
123492e1cfeSmrg    /* actions                  */      actions_list,
124492e1cfeSmrg    /* num_actions              */      XtNumber(actions_list),
125492e1cfeSmrg    /* resources                */      resources,
126492e1cfeSmrg    /* num_resources            */      XtNumber(resources),
127492e1cfeSmrg    /* xrm_class                */      NULLQUARK,
128492e1cfeSmrg    /* compress_motion          */      TRUE,
129492e1cfeSmrg    /* compress_exposure        */      TRUE,
130492e1cfeSmrg    /* compress_enterleave      */      TRUE,
131492e1cfeSmrg    /* visible_interest         */      FALSE,
132492e1cfeSmrg    /* destroy                  */      Destroy,
133492e1cfeSmrg    /* resize                   */      Resize,
134492e1cfeSmrg    /* expose                   */      Redisplay,
135492e1cfeSmrg    /* set_values               */      SetValues,
136492e1cfeSmrg    /* set_values_hook          */      NULL,
137492e1cfeSmrg    /* set_values_almost        */      XtInheritSetValuesAlmost,
138492e1cfeSmrg    /* get_values_hook          */      NULL,
139492e1cfeSmrg    /* accept_focus             */      NULL,
140492e1cfeSmrg    /* version                  */      XtVersion,
141492e1cfeSmrg    /* callback_private         */      NULL,
142492e1cfeSmrg    /* tm_table                 */      defaultTranslations,
143492e1cfeSmrg    /* query_geometry           */      XtInheritQueryGeometry,
144492e1cfeSmrg    /* display_accelerator      */      XtInheritDisplayAccelerator,
145492e1cfeSmrg    /* extension                */      NULL
146492e1cfeSmrg  },
147492e1cfeSmrg  { /* simple fields */
148492e1cfeSmrg    /* change_sensitive		*/	XtInheritChangeSensitive
149492e1cfeSmrg  }
150492e1cfeSmrg};
151492e1cfeSmrg
152492e1cfeSmrgWidgetClass fontgridWidgetClass = (WidgetClass) &fontgridClassRec;
153492e1cfeSmrg
154492e1cfeSmrg
155492e1cfeSmrglong
156492e1cfeSmrgGridFirstChar (Widget w)
157492e1cfeSmrg{
158492e1cfeSmrg    FontGridWidget	fgw = (FontGridWidget) w;
159492e1cfeSmrg    XFontStruct		*fs = fgw->fontgrid.text_font;
160492e1cfeSmrg#ifdef XRENDER
161492e1cfeSmrg    XftFont		*xft = fgw->fontgrid.text_face;
162492e1cfeSmrg    if (xft)
163492e1cfeSmrg    {
164492e1cfeSmrg	FcChar32    map[FC_CHARSET_MAP_SIZE];
165492e1cfeSmrg	FcChar32    next;
166492e1cfeSmrg	FcChar32    first;
167492e1cfeSmrg	int	    i;
168492e1cfeSmrg
169492e1cfeSmrg	first = FcCharSetFirstPage (xft->charset, map, &next);
170492e1cfeSmrg	for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
171492e1cfeSmrg	    if (map[i])
172492e1cfeSmrg	    {
173492e1cfeSmrg		FcChar32    bits = map[i];
174492e1cfeSmrg		first += i * 32;
175492e1cfeSmrg		while (!(bits & 0x1))
176492e1cfeSmrg		{
177492e1cfeSmrg		    bits >>= 1;
178492e1cfeSmrg		    first++;
179492e1cfeSmrg		}
180492e1cfeSmrg		break;
181492e1cfeSmrg	    }
182492e1cfeSmrg	return first;
183492e1cfeSmrg    }
184492e1cfeSmrg    else
185492e1cfeSmrg#endif
186492e1cfeSmrg    if (fs)
187492e1cfeSmrg    {
188492e1cfeSmrg	return (fs->min_byte1 << 8) | (fs->min_char_or_byte2);
189492e1cfeSmrg    }
190492e1cfeSmrg    else
191492e1cfeSmrg	return 0;
192492e1cfeSmrg}
193492e1cfeSmrg
194492e1cfeSmrglong
195492e1cfeSmrgGridLastChar (Widget w)
196492e1cfeSmrg{
197492e1cfeSmrg    FontGridWidget	fgw = (FontGridWidget) w;
198492e1cfeSmrg    XFontStruct		*fs = fgw->fontgrid.text_font;
199492e1cfeSmrg#ifdef XRENDER
200492e1cfeSmrg    XftFont		*xft = fgw->fontgrid.text_face;
201492e1cfeSmrg    if (xft)
202492e1cfeSmrg    {
203492e1cfeSmrg	FcChar32    this, last, next;
204492e1cfeSmrg	FcChar32    map[FC_CHARSET_MAP_SIZE];
205492e1cfeSmrg	int	    i;
206492e1cfeSmrg	last = FcCharSetFirstPage (xft->charset, map, &next);
207492e1cfeSmrg	while ((this = FcCharSetNextPage (xft->charset, map, &next)) != FC_CHARSET_DONE)
208492e1cfeSmrg	    last = this;
209492e1cfeSmrg	last &= ~0xff;
210492e1cfeSmrg	for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--)
211492e1cfeSmrg	    if (map[i])
212492e1cfeSmrg	    {
213492e1cfeSmrg		FcChar32    bits = map[i];
214492e1cfeSmrg		last += i * 32 + 31;
215492e1cfeSmrg		while (!(bits & 0x80000000))
216492e1cfeSmrg		{
217492e1cfeSmrg		    last--;
218492e1cfeSmrg		    bits <<= 1;
219492e1cfeSmrg		}
220492e1cfeSmrg		break;
221492e1cfeSmrg	    }
222492e1cfeSmrg	return (long) last;
223492e1cfeSmrg    }
224492e1cfeSmrg    else
225492e1cfeSmrg#endif
226492e1cfeSmrg    if (fs)
227492e1cfeSmrg    {
228492e1cfeSmrg	return (fs->max_byte1 << 8) | (fs->max_char_or_byte2);
229492e1cfeSmrg    }
230492e1cfeSmrg    else
231492e1cfeSmrg	return 0;
232492e1cfeSmrg}
233492e1cfeSmrg
234492e1cfeSmrg/*
235492e1cfeSmrg * CI_GET_CHAR_INFO_1D - return the charinfo struct for the indicated 8bit
236492e1cfeSmrg * character.  If the character is in the column and exists, then return the
237492e1cfeSmrg * appropriate metrics (note that fonts with common per-character metrics will
238492e1cfeSmrg * return min_bounds).
239492e1cfeSmrg */
240492e1cfeSmrg
241492e1cfeSmrg#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
242492e1cfeSmrg			     (((cs)->rbearing|(cs)->lbearing| \
243492e1cfeSmrg			       (cs)->ascent|(cs)->descent) == 0))
244492e1cfeSmrg
245492e1cfeSmrg#define CI_GET_CHAR_INFO_1D(fs,col,cs) \
246492e1cfeSmrg{ \
2479e0146f7Smrg    cs = NULL; \
248492e1cfeSmrg    if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
249492e1cfeSmrg	if (fs->per_char == NULL) { \
250492e1cfeSmrg	    cs = &fs->min_bounds; \
251492e1cfeSmrg	} else { \
252492e1cfeSmrg	    cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
253492e1cfeSmrg	} \
254492e1cfeSmrg	if (CI_NONEXISTCHAR(cs)) \
2559e0146f7Smrg	    cs = NULL; \
256492e1cfeSmrg    } \
257492e1cfeSmrg}
258492e1cfeSmrg
259492e1cfeSmrg/*
2603538fbe3Smrg * CI_GET_CHAR_INFO_2D - return the charinfo struct for the indicated row and
261492e1cfeSmrg * column.  This is used for fonts that have more than row zero.
262492e1cfeSmrg */
263492e1cfeSmrg#define CI_GET_CHAR_INFO_2D(fs,row,col,cs) \
264492e1cfeSmrg{ \
2659e0146f7Smrg    cs = NULL; \
266492e1cfeSmrg    if (row >= fs->min_byte1 && row <= fs->max_byte1 && \
267492e1cfeSmrg	col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
268492e1cfeSmrg	if (fs->per_char == NULL) { \
269492e1cfeSmrg	    cs = &fs->min_bounds; \
270492e1cfeSmrg	} else { \
271492e1cfeSmrg	    cs = &fs->per_char[((row - fs->min_byte1) * \
272492e1cfeSmrg			        (fs->max_char_or_byte2 - \
273492e1cfeSmrg				 fs->min_char_or_byte2 + 1)) + \
274492e1cfeSmrg			       (col - fs->min_char_or_byte2)]; \
275492e1cfeSmrg        } \
276492e1cfeSmrg	if (CI_NONEXISTCHAR(cs)) \
2779e0146f7Smrg	    cs = NULL; \
278492e1cfeSmrg    } \
279492e1cfeSmrg}
280492e1cfeSmrg
281492e1cfeSmrgstatic Boolean
282492e1cfeSmrgGridHasChar (Widget w, long ch)
283492e1cfeSmrg{
284492e1cfeSmrg    FontGridWidget	fgw = (FontGridWidget) w;
285492e1cfeSmrg#ifdef XRENDER
286492e1cfeSmrg    XftFont		*xft = fgw->fontgrid.text_face;
287492e1cfeSmrg    if (xft)
288492e1cfeSmrg    {
289492e1cfeSmrg	return FcCharSetHasChar (xft->charset, (FcChar32) ch);
290492e1cfeSmrg    }
291492e1cfeSmrg    else
292492e1cfeSmrg#endif
293492e1cfeSmrg    {
294492e1cfeSmrg	XFontStruct	*fs = fgw->fontgrid.text_font;
295492e1cfeSmrg	XCharStruct	*cs;
2963538fbe3Smrg
297492e1cfeSmrg	if (!fs)
298492e1cfeSmrg	    return False;
299492e1cfeSmrg	if (fs->max_byte1 == 0)
300492e1cfeSmrg	{
301492e1cfeSmrg	    CI_GET_CHAR_INFO_1D (fs, ch, cs);
302492e1cfeSmrg	}
303492e1cfeSmrg	else
304492e1cfeSmrg	{
305492e1cfeSmrg	    unsigned int	r = (ch >> 8);
306492e1cfeSmrg	    unsigned int	c = (ch & 0xff);
307492e1cfeSmrg	    CI_GET_CHAR_INFO_2D (fs, r, c, cs);
308492e1cfeSmrg	}
3099e0146f7Smrg	return cs != NULL;
310492e1cfeSmrg    }
311492e1cfeSmrg}
312492e1cfeSmrg
313492e1cfeSmrg/*
314492e1cfeSmrg * public routines
315492e1cfeSmrg */
316492e1cfeSmrg
3173538fbe3Smrgvoid
3183538fbe3SmrgGetFontGridCellDimensions(Widget w, long *startp,
319492e1cfeSmrg			  int *ncolsp, int *nrowsp)
320492e1cfeSmrg{
321492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) w;
322492e1cfeSmrg    *startp = fgw->fontgrid.start_char;
323492e1cfeSmrg    *ncolsp = fgw->fontgrid.cell_cols;
324492e1cfeSmrg    *nrowsp = fgw->fontgrid.cell_rows;
325492e1cfeSmrg}
326492e1cfeSmrg
327492e1cfeSmrg
3283538fbe3Smrgvoid
329492e1cfeSmrgGetPrevNextStates(Widget w, Bool *prevvalidp, Bool *nextvalidp,
330492e1cfeSmrg		  Bool *prev16validp, Bool *next16validp)
331492e1cfeSmrg{
332492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) w;
333492e1cfeSmrg    long minn = (long) GridFirstChar (w);
334492e1cfeSmrg    long maxn = (long) GridLastChar (w);
335492e1cfeSmrg
336492e1cfeSmrg    *prev16validp = (fgw->fontgrid.start_char - 0xf00 > minn);
337492e1cfeSmrg    *prevvalidp = (fgw->fontgrid.start_char > minn);
338492e1cfeSmrg    *nextvalidp = (fgw->fontgrid.start_char +
339492e1cfeSmrg		   (fgw->fontgrid.cell_cols * fgw->fontgrid.cell_rows)
340492e1cfeSmrg		   < maxn);
341492e1cfeSmrg    *next16validp =((fgw->fontgrid.start_char + 0xf00 +
342492e1cfeSmrg		    (fgw->fontgrid.cell_cols * fgw->fontgrid.cell_rows))
343492e1cfeSmrg		   < maxn);
344492e1cfeSmrg}
345492e1cfeSmrg
346492e1cfeSmrg
347492e1cfeSmrg
348492e1cfeSmrg/*
349492e1cfeSmrg * private routines and methods
350492e1cfeSmrg */
351492e1cfeSmrg
352492e1cfeSmrg
3533538fbe3Smrgstatic GC
354492e1cfeSmrgget_gc(FontGridWidget fgw, Pixel fore)
355492e1cfeSmrg{
356492e1cfeSmrg    XtGCMask mask;
357492e1cfeSmrg    XGCValues gcv;
358492e1cfeSmrg
359492e1cfeSmrg    mask = (GCForeground | GCBackground | GCFunction);
360492e1cfeSmrg    gcv.foreground = fore;
361492e1cfeSmrg    gcv.background = fgw->core.background_pixel;
362492e1cfeSmrg    gcv.function = GXcopy;
363492e1cfeSmrg    if (fgw->fontgrid.text_font)
364492e1cfeSmrg    {
365492e1cfeSmrg	mask |= GCFont;
366492e1cfeSmrg	gcv.font = fgw->fontgrid.text_font->fid;
367492e1cfeSmrg    }
368492e1cfeSmrg    gcv.cap_style = CapProjecting;
369492e1cfeSmrg    mask |= GCCapStyle;
370492e1cfeSmrg    if (fgw->fontgrid.grid_width > 0) {
371492e1cfeSmrg	mask |= GCLineWidth;
3723538fbe3Smrg	gcv.line_width = ((fgw->fontgrid.grid_width < 2) ? 0 :
373492e1cfeSmrg			  fgw->fontgrid.grid_width);
374492e1cfeSmrg    }
375492e1cfeSmrg    return (XtGetGC ((Widget) fgw, mask, &gcv));
376492e1cfeSmrg}
377492e1cfeSmrg
378492e1cfeSmrg
379492e1cfeSmrg#ifdef XRENDER
3809e0146f7Smrgstatic XtConvertArgRec xftColorConvertArgs[] = {
381492e1cfeSmrg    {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen),
382492e1cfeSmrg     sizeof(Screen *)},
383492e1cfeSmrg    {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.colormap),
384492e1cfeSmrg     sizeof(Colormap)}
385492e1cfeSmrg};
386492e1cfeSmrg
387492e1cfeSmrg#define	donestr(type, value, tstr) \
388492e1cfeSmrg	{							\
389492e1cfeSmrg	    if (toVal->addr != NULL) {				\
390492e1cfeSmrg		if (toVal->size < sizeof(type)) {		\
391492e1cfeSmrg		    toVal->size = sizeof(type);			\
392492e1cfeSmrg		    XtDisplayStringConversionWarning(dpy, 	\
393492e1cfeSmrg			(char*) fromVal->addr, tstr);		\
394492e1cfeSmrg		    return False;				\
395492e1cfeSmrg		}						\
396492e1cfeSmrg		*(type*)(toVal->addr) = (value);		\
397492e1cfeSmrg	    }							\
398492e1cfeSmrg	    else {						\
399492e1cfeSmrg		static type static_val;				\
400492e1cfeSmrg		static_val = (value);				\
401492e1cfeSmrg		toVal->addr = (XPointer)&static_val;		\
402492e1cfeSmrg	    }							\
403492e1cfeSmrg	    toVal->size = sizeof(type);				\
404492e1cfeSmrg	    return True;					\
405492e1cfeSmrg	}
406492e1cfeSmrg
407492e1cfeSmrgstatic void
408492e1cfeSmrgXmuFreeXftColor (XtAppContext app, XrmValuePtr toVal, XtPointer closure,
409492e1cfeSmrg		 XrmValuePtr args, Cardinal *num_args)
410492e1cfeSmrg{
411492e1cfeSmrg    Screen	*screen;
412492e1cfeSmrg    Colormap	colormap;
413492e1cfeSmrg    XftColor	*color;
4143538fbe3Smrg
415492e1cfeSmrg    if (*num_args != 2)
416492e1cfeSmrg    {
417492e1cfeSmrg	XtAppErrorMsg (app,
418492e1cfeSmrg		       "freeXftColor", "wrongParameters",
419492e1cfeSmrg		       "XtToolkitError",
420492e1cfeSmrg		       "Freeing an XftColor requires screen and colormap arguments",
421492e1cfeSmrg		       (String *) NULL, (Cardinal *)NULL);
422492e1cfeSmrg	return;
423492e1cfeSmrg    }
424492e1cfeSmrg
425492e1cfeSmrg    screen = *((Screen **) args[0].addr);
426492e1cfeSmrg    colormap = *((Colormap *) args[1].addr);
427492e1cfeSmrg    color = (XftColor *) toVal->addr;
428492e1cfeSmrg    XftColorFree (DisplayOfScreen (screen),
429492e1cfeSmrg		  DefaultVisual (DisplayOfScreen (screen),
430492e1cfeSmrg				 XScreenNumberOfScreen (screen)),
431492e1cfeSmrg		  colormap, color);
432492e1cfeSmrg}
4333538fbe3Smrg
434492e1cfeSmrgstatic Boolean
435492e1cfeSmrgXmuCvtStringToXftColor(Display *dpy,
436492e1cfeSmrg		       XrmValue *args, Cardinal *num_args,
437492e1cfeSmrg		       XrmValue *fromVal, XrmValue *toVal,
438492e1cfeSmrg		       XtPointer *converter_data)
439492e1cfeSmrg{
440492e1cfeSmrg    char	    *spec;
441492e1cfeSmrg    XRenderColor    renderColor;
442492e1cfeSmrg    XftColor	    xftColor;
443492e1cfeSmrg    Screen	    *screen;
444492e1cfeSmrg    Colormap	    colormap;
4453538fbe3Smrg
446492e1cfeSmrg    if (*num_args != 2)
447492e1cfeSmrg    {
448492e1cfeSmrg	XtAppErrorMsg (XtDisplayToApplicationContext (dpy),
449492e1cfeSmrg		       "cvtStringToXftColor", "wrongParameters",
450492e1cfeSmrg		       "XtToolkitError",
451492e1cfeSmrg		       "String to render color conversion needs screen and colormap arguments",
452492e1cfeSmrg		       (String *) NULL, (Cardinal *)NULL);
453492e1cfeSmrg	return False;
454492e1cfeSmrg    }
455492e1cfeSmrg
456492e1cfeSmrg    screen = *((Screen **) args[0].addr);
457492e1cfeSmrg    colormap = *((Colormap *) args[1].addr);
458492e1cfeSmrg
459492e1cfeSmrg    spec = (char *) fromVal->addr;
460492e1cfeSmrg    if (strcasecmp (spec, XtDefaultForeground) == 0)
461492e1cfeSmrg    {
462492e1cfeSmrg	renderColor.red = 0;
463492e1cfeSmrg	renderColor.green = 0;
464492e1cfeSmrg	renderColor.blue = 0;
465492e1cfeSmrg	renderColor.alpha = 0xffff;
466492e1cfeSmrg    }
467492e1cfeSmrg    else if (strcasecmp (spec, XtDefaultBackground) == 0)
468492e1cfeSmrg    {
469492e1cfeSmrg	renderColor.red = 0xffff;
470492e1cfeSmrg	renderColor.green = 0xffff;
471492e1cfeSmrg	renderColor.blue = 0xffff;
472492e1cfeSmrg	renderColor.alpha = 0xffff;
473492e1cfeSmrg    }
474492e1cfeSmrg    else if (!XRenderParseColor (dpy, spec, &renderColor))
475492e1cfeSmrg	return False;
4763538fbe3Smrg    if (!XftColorAllocValue (dpy,
477492e1cfeSmrg			     DefaultVisual (dpy,
478492e1cfeSmrg					    XScreenNumberOfScreen (screen)),
479492e1cfeSmrg			     colormap,
480492e1cfeSmrg			     &renderColor,
481492e1cfeSmrg			     &xftColor))
482492e1cfeSmrg	return False;
4833538fbe3Smrg
484492e1cfeSmrg    donestr (XftColor, xftColor, XtRXftColor);
485492e1cfeSmrg}
486492e1cfeSmrg
487492e1cfeSmrgstatic void
488492e1cfeSmrgXmuFreeXftFont (XtAppContext app, XrmValuePtr toVal, XtPointer closure,
489492e1cfeSmrg		XrmValuePtr args, Cardinal *num_args)
490492e1cfeSmrg{
491492e1cfeSmrg    Screen  *screen;
492492e1cfeSmrg    XftFont *font;
4933538fbe3Smrg
494492e1cfeSmrg    if (*num_args != 1)
495492e1cfeSmrg    {
496492e1cfeSmrg	XtAppErrorMsg (app,
497492e1cfeSmrg		       "freeXftFont", "wrongParameters",
498492e1cfeSmrg		       "XtToolkitError",
499492e1cfeSmrg		       "Freeing an XftFont requires screen argument",
500492e1cfeSmrg		       (String *) NULL, (Cardinal *)NULL);
501492e1cfeSmrg	return;
502492e1cfeSmrg    }
503492e1cfeSmrg
504492e1cfeSmrg    screen = *((Screen **) args[0].addr);
505492e1cfeSmrg    font = *((XftFont **) toVal->addr);
506492e1cfeSmrg    if (font)
507492e1cfeSmrg	XftFontClose (DisplayOfScreen (screen), font);
508492e1cfeSmrg}
509492e1cfeSmrg
510492e1cfeSmrgstatic Boolean
511492e1cfeSmrgXmuCvtStringToXftFont(Display *dpy,
512492e1cfeSmrg		      XrmValue *args, Cardinal *num_args,
513492e1cfeSmrg		      XrmValue *fromVal, XrmValue *toVal,
514492e1cfeSmrg		      XtPointer *converter_data)
515492e1cfeSmrg{
516492e1cfeSmrg    char    *name;
517492e1cfeSmrg    XftFont *font;
518492e1cfeSmrg    Screen  *screen;
5193538fbe3Smrg
520492e1cfeSmrg    if (*num_args != 1)
521492e1cfeSmrg    {
522492e1cfeSmrg	XtAppErrorMsg (XtDisplayToApplicationContext (dpy),
523492e1cfeSmrg		       "cvtStringToXftFont", "wrongParameters",
524492e1cfeSmrg		       "XtToolkitError",
525492e1cfeSmrg		       "String to XftFont conversion needs screen argument",
526492e1cfeSmrg		       (String *) NULL, (Cardinal *)NULL);
527492e1cfeSmrg	return False;
528492e1cfeSmrg    }
529492e1cfeSmrg
530492e1cfeSmrg    screen = *((Screen **) args[0].addr);
531492e1cfeSmrg    name = (char *) fromVal->addr;
5329e0146f7Smrg
5339e0146f7Smrg    font = NULL;
534492e1cfeSmrg    if (name)
535492e1cfeSmrg    {
536492e1cfeSmrg	font = XftFontOpenName (dpy,
537492e1cfeSmrg				XScreenNumberOfScreen (screen),
538492e1cfeSmrg				name);
539492e1cfeSmrg	if (!font)
540492e1cfeSmrg	    XtDisplayStringConversionWarning(dpy, (char *) fromVal->addr, XtRXftFont);
541492e1cfeSmrg    }
542492e1cfeSmrg    donestr (XftFont *, font, XtRXftFont);
543492e1cfeSmrg}
544492e1cfeSmrg
545492e1cfeSmrgstatic XtConvertArgRec xftFontConvertArgs[] = {
546492e1cfeSmrg    {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen),
547492e1cfeSmrg     sizeof(Screen *)},
548492e1cfeSmrg};
549492e1cfeSmrg
550492e1cfeSmrg#endif
551492e1cfeSmrg
5523538fbe3Smrgstatic void
553492e1cfeSmrgClassInitialize(void)
554492e1cfeSmrg{
555492e1cfeSmrg    XtAddConverter (XtRString, XtRLong, XmuCvtStringToLong, NULL, 0);
556492e1cfeSmrg#ifdef XRENDER
5573538fbe3Smrg    XtSetTypeConverter (XtRString, XtRXftColor,
5583538fbe3Smrg			XmuCvtStringToXftColor,
559492e1cfeSmrg			xftColorConvertArgs, XtNumber(xftColorConvertArgs),
560492e1cfeSmrg			XtCacheByDisplay, XmuFreeXftColor);
561492e1cfeSmrg    XtSetTypeConverter (XtRString, XtRXftFont,
562492e1cfeSmrg			XmuCvtStringToXftFont,
563492e1cfeSmrg			xftFontConvertArgs, XtNumber(xftFontConvertArgs),
564492e1cfeSmrg			XtCacheByDisplay, XmuFreeXftFont);
565492e1cfeSmrg#endif
566492e1cfeSmrg}
567492e1cfeSmrg
568492e1cfeSmrg
5693538fbe3Smrgstatic void
570492e1cfeSmrgInitialize(Widget request, Widget new, ArgList args, Cardinal *num_args)
571492e1cfeSmrg{
572492e1cfeSmrg    FontGridWidget reqfg = (FontGridWidget) request;
573492e1cfeSmrg    FontGridWidget newfg = (FontGridWidget) new;
574492e1cfeSmrg    XFontStruct *fs = newfg->fontgrid.text_font;
575492e1cfeSmrg#ifdef XRENDER
576492e1cfeSmrg    XftFont *xft = newfg->fontgrid.text_face;
577492e1cfeSmrg#endif
578492e1cfeSmrg    unsigned maxn;
579492e1cfeSmrg
580492e1cfeSmrg    if (reqfg->fontgrid.cell_cols <= 0)
581492e1cfeSmrg      newfg->fontgrid.cell_cols = 16;
582492e1cfeSmrg
583492e1cfeSmrg    if (reqfg->fontgrid.cell_rows <= 0) {
584492e1cfeSmrg#ifdef XRENDER
585492e1cfeSmrg	if (xft)
586492e1cfeSmrg	    newfg->fontgrid.cell_rows = 16;
587492e1cfeSmrg	else
588492e1cfeSmrg#endif
589492e1cfeSmrg	if (fs && fs->max_byte1 == 0) {
5903538fbe3Smrg	    newfg->fontgrid.cell_rows = (fs->max_char_or_byte2 /
591492e1cfeSmrg					 newfg->fontgrid.cell_cols) + 1;
592492e1cfeSmrg	    if (newfg->fontgrid.cell_rows > 16)
593492e1cfeSmrg	      newfg->fontgrid.cell_rows = 16;
594492e1cfeSmrg	} else
595492e1cfeSmrg	  newfg->fontgrid.cell_rows = 16;
596492e1cfeSmrg    }
597492e1cfeSmrg
598492e1cfeSmrg    if (reqfg->fontgrid.cell_width <= 0)
599492e1cfeSmrg      newfg->fontgrid.cell_width = DefaultCellWidth (newfg);
600492e1cfeSmrg    if (reqfg->fontgrid.cell_height <= 0)
601492e1cfeSmrg      newfg->fontgrid.cell_height = DefaultCellHeight (newfg);
602492e1cfeSmrg
603492e1cfeSmrg    /* give a nice size that fits one screen full */
604492e1cfeSmrg    if (newfg->core.width == 0)
605492e1cfeSmrg      newfg->core.width = (newfg->fontgrid.cell_width *
606492e1cfeSmrg			   newfg->fontgrid.cell_cols +
607492e1cfeSmrg			   newfg->fontgrid.grid_width *
608492e1cfeSmrg			   (newfg->fontgrid.cell_cols + 1));
609492e1cfeSmrg
6103538fbe3Smrg    if (newfg->core.height == 0)
6113538fbe3Smrg      newfg->core.height = (newfg->fontgrid.cell_height *
612492e1cfeSmrg			    newfg->fontgrid.cell_rows +
613492e1cfeSmrg			    newfg->fontgrid.grid_width *
614492e1cfeSmrg			    (newfg->fontgrid.cell_rows + 1));
615492e1cfeSmrg
616492e1cfeSmrg    /*
617492e1cfeSmrg     * select the first character
618492e1cfeSmrg     */
619492e1cfeSmrg
620492e1cfeSmrg    if (newfg->fontgrid.start_char == 0xffffffff)
621492e1cfeSmrg	newfg->fontgrid.start_char = GridFirstChar(new) & ~0xff;
622492e1cfeSmrg    maxn = GridLastChar (new);
6233538fbe3Smrg    if (newfg->fontgrid.start_char > maxn)
6243538fbe3Smrg	newfg->fontgrid.start_char = (maxn + 1 -
6253538fbe3Smrg				      (newfg->fontgrid.cell_cols *
626492e1cfeSmrg				       newfg->fontgrid.cell_rows));
627492e1cfeSmrg}
628492e1cfeSmrg
6293538fbe3Smrgstatic void
630492e1cfeSmrgRealize(Widget gw, Mask *valueMask, XSetWindowAttributes *attributes)
631492e1cfeSmrg{
632492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) gw;
633492e1cfeSmrg    FontGridPart *p = &fgw->fontgrid;
634492e1cfeSmrg
635492e1cfeSmrg    p->text_gc = get_gc (fgw, GridForeground (fgw));
636492e1cfeSmrg    p->box_gc = get_gc (fgw, p->box_pixel);
637492e1cfeSmrg    Resize (gw);
638492e1cfeSmrg
639492e1cfeSmrg    (*(XtSuperclass(gw)->core_class.realize)) (gw, valueMask, attributes);
640492e1cfeSmrg#ifdef XRENDER
641492e1cfeSmrg    p->draw = XftDrawCreate (XtDisplay (gw), XtWindow (gw),
642492e1cfeSmrg			     DefaultVisual (XtDisplay (gw),
643492e1cfeSmrg					    DefaultScreen(XtDisplay (gw))),
644492e1cfeSmrg			     fgw->core.colormap);
645492e1cfeSmrg#endif
646492e1cfeSmrg    return;
647492e1cfeSmrg}
648492e1cfeSmrg
649492e1cfeSmrg
650492e1cfeSmrg
6513538fbe3Smrgstatic void
652492e1cfeSmrgDestroy(Widget gw)
653492e1cfeSmrg{
654492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) gw;
655492e1cfeSmrg
656492e1cfeSmrg    XtReleaseGC (gw, fgw->fontgrid.text_gc);
657492e1cfeSmrg    XtReleaseGC (gw, fgw->fontgrid.box_gc);
658492e1cfeSmrg}
659492e1cfeSmrg
660492e1cfeSmrg
6613538fbe3Smrgstatic void
662492e1cfeSmrgResize(Widget gw)
663492e1cfeSmrg{
664492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) gw;
665492e1cfeSmrg
666492e1cfeSmrg    /* recompute in case we've changed size */
667492e1cfeSmrg    fgw->fontgrid.cell_width = CellWidth (fgw);
668492e1cfeSmrg    if (fgw->fontgrid.cell_width <= 0)
669492e1cfeSmrg	fgw->fontgrid.cell_width = 1;
670492e1cfeSmrg    fgw->fontgrid.cell_height = CellHeight (fgw);
671492e1cfeSmrg    if (fgw->fontgrid.cell_height <= 0)
672492e1cfeSmrg	fgw->fontgrid.cell_height = 1;
673492e1cfeSmrg    fgw->fontgrid.xoff = (fgw->fontgrid.cell_width -
674492e1cfeSmrg			    DefaultCellWidth (fgw)) / 2;
675492e1cfeSmrg    fgw->fontgrid.yoff = (fgw->fontgrid.cell_height -
676492e1cfeSmrg			    DefaultCellHeight (fgw)) / 2;
677492e1cfeSmrg
678492e1cfeSmrg}
679492e1cfeSmrg
680492e1cfeSmrg
681492e1cfeSmrg/* ARGSUSED */
6823538fbe3Smrgstatic void
683492e1cfeSmrgRedisplay(Widget gw, XEvent *event, Region region)
684492e1cfeSmrg{
685492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) gw;
686492e1cfeSmrg    XRectangle rect;			/* bounding rect for region */
687492e1cfeSmrg    int left, right, top, bottom;	/* which cells were damaged */
688492e1cfeSmrg    int cw, ch;				/* cell size */
689492e1cfeSmrg
690492e1cfeSmrg#ifdef XRENDER
691492e1cfeSmrg    if (!fgw->fontgrid.text_face)
692492e1cfeSmrg#endif
693492e1cfeSmrg    if (!fgw->fontgrid.text_font) {
694492e1cfeSmrg	Bell (gw, XkbBI_BadValue);
695492e1cfeSmrg	return;
696492e1cfeSmrg    }
697492e1cfeSmrg
698492e1cfeSmrg    /*
699492e1cfeSmrg     * compute the left, right, top, and bottom cells that were damaged
700492e1cfeSmrg     */
701492e1cfeSmrg    XClipBox (region, &rect);
702492e1cfeSmrg    cw = fgw->fontgrid.cell_width + fgw->fontgrid.grid_width;
703492e1cfeSmrg    ch = fgw->fontgrid.cell_height + fgw->fontgrid.grid_width;
704492e1cfeSmrg    if ((left = (((int) rect.x) / cw)) < 0) left = 0;
705492e1cfeSmrg    right = (((int) (rect.x + rect.width - 1)) / cw);
706492e1cfeSmrg    if ((top = (((int) rect.y) / ch)) < 0) top = 0;
707492e1cfeSmrg    bottom = (((int) (rect.y + rect.height - 1)) / ch);
708492e1cfeSmrg
709492e1cfeSmrg    paint_grid (fgw, left, top, right - left + 1, bottom - top + 1);
710492e1cfeSmrg}
711492e1cfeSmrg
712492e1cfeSmrg
7133538fbe3Smrgstatic void
7143538fbe3Smrgpaint_grid(FontGridWidget fgw, 		/* widget in which to draw */
7153538fbe3Smrg	   int col, int row, 		/* where to start */
7163538fbe3Smrg	   int ncols, int nrows)	/* number of cells */
717492e1cfeSmrg{
718492e1cfeSmrg    FontGridPart *p = &fgw->fontgrid;
719492e1cfeSmrg    int i, j;
720492e1cfeSmrg    Display *dpy = XtDisplay(fgw);
721492e1cfeSmrg    Window wind = XtWindow(fgw);
722492e1cfeSmrg    int cw = p->cell_width + p->grid_width;
723492e1cfeSmrg    int ch = p->cell_height + p->grid_width;
724492e1cfeSmrg    int tcols = p->cell_cols;
725492e1cfeSmrg    int trows = p->cell_rows;
726492e1cfeSmrg    int x1, y1, x2, y2, x, y;
727492e1cfeSmrg    unsigned maxn = GridLastChar ((Widget) fgw);
728492e1cfeSmrg    unsigned n, prevn;
729492e1cfeSmrg    int startx;
730492e1cfeSmrg
731492e1cfeSmrg    if (col + ncols >= tcols) {
732492e1cfeSmrg	ncols = tcols - col;
733492e1cfeSmrg	if (ncols < 1) return;
734492e1cfeSmrg    }
735492e1cfeSmrg
736492e1cfeSmrg    if (row + nrows >= trows) {
737492e1cfeSmrg	nrows = trows - row;
738492e1cfeSmrg	if (nrows < 1) return;
739492e1cfeSmrg    }
740492e1cfeSmrg
741492e1cfeSmrg    /*
7423538fbe3Smrg     * paint the grid lines for the indicated rows
743492e1cfeSmrg     */
744492e1cfeSmrg    if (p->grid_width > 0) {
745492e1cfeSmrg	int half_grid_width = p->grid_width >> 1;
746492e1cfeSmrg	x1 = col * cw + half_grid_width;
747492e1cfeSmrg	y1 = row * ch + half_grid_width;
748492e1cfeSmrg	x2 = x1 + ncols * cw;
749492e1cfeSmrg	y2 = y1 + nrows * ch;
750492e1cfeSmrg	for (i = 0, x = x1; i <= ncols; i++, x += cw) {
751492e1cfeSmrg	    XDrawLine (dpy, wind, p->box_gc, x, y1, x, y2);
752492e1cfeSmrg	}
753492e1cfeSmrg	for (i = 0, y = y1; i <= nrows; i++, y += ch) {
754492e1cfeSmrg	    XDrawLine (dpy, wind, p->box_gc, x1, y, x2, y);
755492e1cfeSmrg	}
756492e1cfeSmrg    }
757492e1cfeSmrg    /*
758492e1cfeSmrg     * Draw a character in every box; treat all fonts as if they were 16bit
7593538fbe3Smrg     * fonts.  Store the high eight bits in byte1 and the low eight bits in
760492e1cfeSmrg     * byte2.
761492e1cfeSmrg     */
762492e1cfeSmrg    prevn = p->start_char + col + row * tcols;
763492e1cfeSmrg    startx = col * cw + p->internal_pad + p->grid_width;
764492e1cfeSmrg    for (j = 0,
765492e1cfeSmrg	 y = row * ch + p->internal_pad + p->grid_width + GridFontAscent (fgw);
766492e1cfeSmrg	 j < nrows; j++, y += ch) {
767492e1cfeSmrg	n = prevn;
768492e1cfeSmrg	for (i = 0, x = startx; i < ncols; i++, x += cw) {
769492e1cfeSmrg	    int xoff = p->xoff, yoff = p->yoff;
770492e1cfeSmrg	    if (n > maxn) goto done;	/* no break out of nested */
771492e1cfeSmrg
772492e1cfeSmrg#ifdef XRENDER
773492e1cfeSmrg	    if (fgw->fontgrid.text_face)
774492e1cfeSmrg	    {
775492e1cfeSmrg		XftFont *xft = p->text_face;
776492e1cfeSmrg		FcChar32    c = n;
777492e1cfeSmrg		XGlyphInfo  extents;
778492e1cfeSmrg		XftTextExtents32 (dpy, xft, &c, 1, &extents);
779492e1cfeSmrg		if (p->center_chars)
780492e1cfeSmrg		{
781492e1cfeSmrg		    xoff = (p->cell_width - extents.width) / 2 - extents.x;
782492e1cfeSmrg		    yoff = (p->cell_height - extents.height) / 2 - extents.y;
783492e1cfeSmrg		}
784492e1cfeSmrg		if (extents.width && extents.height)
785492e1cfeSmrg		{
7863538fbe3Smrg		    XClearArea (dpy, wind, x + xoff - extents.x,
787492e1cfeSmrg				y + yoff - extents.y,
788492e1cfeSmrg				extents.width, extents.height, False);
789492e1cfeSmrg		    if (p->box_chars)
790492e1cfeSmrg			XDrawRectangle (dpy, wind, p->box_gc,
7913538fbe3Smrg					x + xoff - extents.x,
792492e1cfeSmrg					y + yoff - extents.y,
793492e1cfeSmrg					extents.width - 1,
794492e1cfeSmrg					extents.height - 1);
795492e1cfeSmrg		}
796492e1cfeSmrg		XftDrawString32 (p->draw, &p->fg_color, xft,
797492e1cfeSmrg				 x + xoff, y + yoff, &c, 1);
798492e1cfeSmrg	    }
799492e1cfeSmrg	    else
800492e1cfeSmrg#endif
801492e1cfeSmrg	    {
802492e1cfeSmrg	    XChar2b thechar;
803492e1cfeSmrg
804492e1cfeSmrg	    thechar.byte1 = (n >> 8);	/* high eight bits */
805492e1cfeSmrg	    thechar.byte2 = (n & 255);	/* low eight bits */
806492e1cfeSmrg	    if (p->box_chars || p->center_chars) {
807492e1cfeSmrg		XCharStruct metrics;
808492e1cfeSmrg		int direction, fontascent, fontdescent;
809492e1cfeSmrg
810492e1cfeSmrg		XTextExtents16 (p->text_font, &thechar, 1, &direction,
811492e1cfeSmrg				&fontascent, &fontdescent, &metrics);
812492e1cfeSmrg
813492e1cfeSmrg		if (p->center_chars) {
814492e1cfeSmrg		    /*
815492e1cfeSmrg		     * We want to move the origin by enough to center the ink
8163538fbe3Smrg		     * within the cell.  The left edge will then be at
817492e1cfeSmrg		     * (cell_width - (rbearing - lbearing)) / 2; so we subtract
818492e1cfeSmrg		     * the lbearing to find the origin.  Ditto for vertical.
819492e1cfeSmrg		     */
820492e1cfeSmrg		    xoff = (((p->cell_width -
821492e1cfeSmrg			      (metrics.rbearing - metrics.lbearing)) / 2) -
822492e1cfeSmrg			    p->internal_pad - metrics.lbearing);
8233538fbe3Smrg		    yoff = (((p->cell_height -
824492e1cfeSmrg			      (metrics.descent + metrics.ascent)) / 2) -
825492e1cfeSmrg			    p->internal_pad -
826492e1cfeSmrg			    p->text_font->ascent + metrics.ascent);
827492e1cfeSmrg		}
828492e1cfeSmrg		if (p->box_chars) {
829492e1cfeSmrg		    XDrawRectangle (dpy, wind, p->box_gc,
8303538fbe3Smrg				    x + xoff, y + yoff - p->text_font->ascent,
831492e1cfeSmrg				    metrics.width - 1,
832492e1cfeSmrg				    fontascent + fontdescent - 1);
833492e1cfeSmrg		}
834492e1cfeSmrg	    }
835492e1cfeSmrg	    XDrawString16 (dpy, wind, p->text_gc, x + xoff, y + yoff,
836492e1cfeSmrg			   &thechar, 1);
837492e1cfeSmrg	    }
838492e1cfeSmrg	    n++;
839492e1cfeSmrg	}
840492e1cfeSmrg	prevn += tcols;
841492e1cfeSmrg    }
842492e1cfeSmrg
843492e1cfeSmrg  done:
844492e1cfeSmrg    /*
8453538fbe3Smrg     * paint the grid lines for the indicated rows
846492e1cfeSmrg     */
847492e1cfeSmrg    if (p->grid_width > 0) {
848492e1cfeSmrg	int half_grid_width = p->grid_width >> 1;
849492e1cfeSmrg	x1 = col * cw + half_grid_width;
850492e1cfeSmrg	y1 = row * ch + half_grid_width;
851492e1cfeSmrg	x2 = x1 + ncols * cw;
852492e1cfeSmrg	y2 = y1 + nrows * ch;
853492e1cfeSmrg	for (i = 0, x = x1; i <= ncols; i++, x += cw) {
854492e1cfeSmrg	    XDrawLine (dpy, wind, p->box_gc, x, y1, x, y2);
855492e1cfeSmrg	}
856492e1cfeSmrg	for (i = 0, y = y1; i <= nrows; i++, y += ch) {
857492e1cfeSmrg	    XDrawLine (dpy, wind, p->box_gc, x1, y, x2, y);
858492e1cfeSmrg	}
859492e1cfeSmrg    }
860492e1cfeSmrg
8613538fbe3Smrg
862492e1cfeSmrg    return;
863492e1cfeSmrg}
864492e1cfeSmrg
865492e1cfeSmrgstatic Boolean
866492e1cfeSmrgPageBlank (Widget w, long first, long last)
867492e1cfeSmrg{
868492e1cfeSmrg    while (first <= last)
869492e1cfeSmrg    {
870492e1cfeSmrg	if (GridHasChar (w, first))
871492e1cfeSmrg	    return False;
872492e1cfeSmrg	first++;
873492e1cfeSmrg    }
874492e1cfeSmrg    return True;
875492e1cfeSmrg}
876492e1cfeSmrg
877492e1cfeSmrg/*ARGSUSED*/
8783538fbe3Smrgstatic Boolean
8793538fbe3SmrgSetValues(Widget current, Widget request, Widget new,
880492e1cfeSmrg	  ArgList args, Cardinal *num_args)
881492e1cfeSmrg{
882492e1cfeSmrg    FontGridWidget curfg = (FontGridWidget) current;
883492e1cfeSmrg    FontGridWidget newfg = (FontGridWidget) new;
884492e1cfeSmrg    Boolean redisplay = FALSE;
885492e1cfeSmrg
886492e1cfeSmrg    if (curfg->fontgrid.text_font != newfg->fontgrid.text_font ||
887492e1cfeSmrg	curfg->fontgrid.internal_pad != newfg->fontgrid.internal_pad) {
888492e1cfeSmrg	newfg->fontgrid.cell_width = DefaultCellWidth (newfg);
889492e1cfeSmrg	newfg->fontgrid.cell_height = DefaultCellHeight (newfg);
890492e1cfeSmrg	redisplay = TRUE;
891492e1cfeSmrg    }
892492e1cfeSmrg
893492e1cfeSmrg    if (GridForeground(curfg) != GridForeground (newfg)) {
894492e1cfeSmrg	XtReleaseGC (new, curfg->fontgrid.text_gc);
895492e1cfeSmrg	newfg->fontgrid.text_gc = get_gc (newfg, GridForeground (newfg));
896492e1cfeSmrg	redisplay = TRUE;
897492e1cfeSmrg    }
898492e1cfeSmrg
899492e1cfeSmrg    if (curfg->fontgrid.box_pixel != newfg->fontgrid.box_pixel) {
900492e1cfeSmrg	XtReleaseGC (new, curfg->fontgrid.text_gc);
901492e1cfeSmrg	newfg->fontgrid.box_gc = get_gc (newfg, newfg->fontgrid.box_pixel);
902492e1cfeSmrg	redisplay = TRUE;
903492e1cfeSmrg    }
904492e1cfeSmrg
905492e1cfeSmrg    if (curfg->fontgrid.center_chars != newfg->fontgrid.center_chars ||
906492e1cfeSmrg	curfg->fontgrid.box_chars != newfg->fontgrid.box_chars)
907492e1cfeSmrg      redisplay = TRUE;
908492e1cfeSmrg
909492e1cfeSmrg    if (curfg->fontgrid.start_char != newfg->fontgrid.start_char) {
910492e1cfeSmrg	long maxn = GridLastChar (new);
911492e1cfeSmrg	long page = newfg->fontgrid.cell_cols * newfg->fontgrid.cell_rows;
912492e1cfeSmrg	long dir = page;
913492e1cfeSmrg	long start = newfg->fontgrid.start_char;
914492e1cfeSmrg
915492e1cfeSmrg	if (start < curfg->fontgrid.start_char)
916492e1cfeSmrg	    dir = -page;
917492e1cfeSmrg
918492e1cfeSmrg	if (start < 0)
919492e1cfeSmrg	    start = 0;
9203538fbe3Smrg	if (start > maxn)
921492e1cfeSmrg	  start = (maxn / page) * page;
9223538fbe3Smrg
923492e1cfeSmrg	while (PageBlank (new, start, start + page - 1))
924492e1cfeSmrg	{
925492e1cfeSmrg	    long    next = start + dir;
926492e1cfeSmrg
927492e1cfeSmrg	    if (next < 0 || maxn < next)
928492e1cfeSmrg		break;
929492e1cfeSmrg	    start = next;
930492e1cfeSmrg	}
931492e1cfeSmrg
932492e1cfeSmrg	newfg->fontgrid.start_char = start;
933492e1cfeSmrg	redisplay = (curfg->fontgrid.start_char != newfg->fontgrid.start_char);
934492e1cfeSmrg    }
935492e1cfeSmrg
936492e1cfeSmrg    return redisplay;
937492e1cfeSmrg}
938492e1cfeSmrg
939492e1cfeSmrg
940492e1cfeSmrg/* ARGSUSED */
9413538fbe3Smrgstatic void
942492e1cfeSmrgNotify(Widget gw, XEvent *event, String *params, Cardinal *nparams)
943492e1cfeSmrg{
944492e1cfeSmrg    FontGridWidget fgw = (FontGridWidget) gw;
945492e1cfeSmrg    int x, y;				/* where the event happened */
946492e1cfeSmrg    FontGridCharRec rec;		/* callback data */
947492e1cfeSmrg
948492e1cfeSmrg    /*
949492e1cfeSmrg     * only allow events with (x,y)
950492e1cfeSmrg     */
951492e1cfeSmrg    switch (event->type) {
952492e1cfeSmrg      case KeyPress:
953492e1cfeSmrg      case KeyRelease:
954492e1cfeSmrg	x = event->xkey.x;
955492e1cfeSmrg	y = event->xkey.y;
956492e1cfeSmrg	break;
957492e1cfeSmrg      case ButtonPress:
958492e1cfeSmrg      case ButtonRelease:
959492e1cfeSmrg	x = event->xbutton.x;
960492e1cfeSmrg	y = event->xbutton.y;
961492e1cfeSmrg	break;
962492e1cfeSmrg      case MotionNotify:
963492e1cfeSmrg	x = event->xmotion.x;
964492e1cfeSmrg	y = event->xmotion.y;
965492e1cfeSmrg	break;
966492e1cfeSmrg      default:
967492e1cfeSmrg	Bell (gw, XkbBI_Ignore);
968492e1cfeSmrg	return;
969492e1cfeSmrg    }
970492e1cfeSmrg
971492e1cfeSmrg    /*
972492e1cfeSmrg     * compute the callback data
973492e1cfeSmrg     */
974492e1cfeSmrg    {
975492e1cfeSmrg	int cw = fgw->fontgrid.cell_width + fgw->fontgrid.grid_width;
976492e1cfeSmrg	int ch = fgw->fontgrid.cell_height + fgw->fontgrid.grid_width;
977492e1cfeSmrg	unsigned n;
978492e1cfeSmrg
979492e1cfeSmrg	if (x > (fgw->fontgrid.cell_cols * cw)) {
980492e1cfeSmrg	    Bell (gw, XkbBI_InvalidLocation);
981492e1cfeSmrg	    return;
982492e1cfeSmrg	}
983492e1cfeSmrg
9843538fbe3Smrg	n= (fgw->fontgrid.start_char +
985492e1cfeSmrg	    ((y / ch) * fgw->fontgrid.cell_cols) + (x / cw));
986492e1cfeSmrg
987492e1cfeSmrg	rec.thefont = fgw->fontgrid.text_font;
988492e1cfeSmrg#ifdef XRENDER
989492e1cfeSmrg	rec.theface = fgw->fontgrid.text_face;
990492e1cfeSmrg#endif
991492e1cfeSmrg	rec.thechar = n;
992492e1cfeSmrg    }
993492e1cfeSmrg
994492e1cfeSmrg    XtCallCallbacks (gw, XtNcallback, (XtPointer) &rec);
995492e1cfeSmrg}
996492e1cfeSmrg
997