x11-xserver-utils/xfd/grid.c

1005 lines
27 KiB
C
Raw Normal View History

/*
* $XdotOrg: grid.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $
* $Xorg: grid.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $
*
*
Copyright 1989, 1998 The Open Group
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
* *
* Author: Jim Fulton, MIT X Consortium
*/
/* $XFree86: xc/programs/xfd/grid.c,v 1.9 2002/07/06 00:46:42 keithp Exp $ */
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/SimpleP.h>
#include <X11/Xmu/Converters.h>
#include <X11/Xos.h>
#include "gridP.h"
#ifdef XKB
#include <X11/extensions/XKBbells.h>
#else
#define XkbBI_MinorError 2
#define XkbBI_Ignore 11
#endif
#ifdef XKB
#define Bell(w,n) XkbStdBell(XtDisplay(w), XtWindow(w), 50, n)
#else
#define Bell(w,n) XBell(XtDisplay(w), 0)
#endif
static GC get_gc(FontGridWidget fgw, Pixel fore);
static void ClassInitialize(void);
static void Initialize(Widget request, Widget new, ArgList args,
Cardinal *num_args);
static void Realize(Widget gw, Mask *valueMask,
XSetWindowAttributes *attributes);
static void Destroy(Widget gw);
static void Resize(Widget gw);
static void Redisplay(Widget gw, XEvent *event, Region region);
static void paint_grid(FontGridWidget fgw, int col, int row,
int ncols, int nrows);
static Boolean SetValues(Widget current, Widget request, Widget new,
ArgList args, Cardinal *num_args);
static void Notify(Widget gw, XEvent *event, String *params,
Cardinal *nparams);
#define Offset(field) XtOffsetOf(FontGridRec, fontgrid.field)
static XtResource resources[] = {
{ XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
Offset(text_font), XtRString, (XtPointer) NULL },
{ XtNcellColumns, XtCCellColumns, XtRInt, sizeof(int),
Offset(cell_cols), XtRImmediate, (XtPointer) 0 },
{ XtNcellRows, XtCCellRows, XtRInt, sizeof(int),
Offset(cell_rows), XtRImmediate, (XtPointer) 0 },
{ XtNcellWidth, XtCCellWidth, XtRInt, sizeof(int),
Offset(cell_width), XtRImmediate, (XtPointer) 0 },
{ XtNcellHeight, XtCCellHeight, XtRInt, sizeof(int),
Offset(cell_height), XtRImmediate, (XtPointer) 0 },
{ XtNstartChar, XtCStartChar, XtRLong, sizeof(long),
Offset(start_char), XtRImmediate, (XtPointer) 0xffffffff },
#ifndef XRENDER
{ XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
Offset(foreground_pixel), XtRString, (XtPointer) XtDefaultForeground },
#endif
{ XtNcenterChars, XtCCenterChars, XtRBoolean, sizeof(Boolean),
Offset(center_chars), XtRImmediate, (XtPointer) FALSE },
{ XtNboxChars, XtCBoxChars, XtRBoolean, sizeof(Boolean),
Offset(box_chars), XtRImmediate, (XtPointer) FALSE },
{ XtNboxColor, XtCForeground, XtRPixel, sizeof(Pixel),
Offset(box_pixel), XtRString, (XtPointer) XtDefaultForeground },
{ XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer),
Offset(callbacks), XtRCallback, (XtPointer) NULL },
{ XtNinternalPad, XtCInternalPad, XtRInt, sizeof(int),
Offset(internal_pad), XtRImmediate, (XtPointer) 4 },
{ XtNgridWidth, XtCGridWidth, XtRInt, sizeof(int),
Offset(grid_width), XtRImmediate, (XtPointer) 1 },
#ifdef XRENDER
{XtNforeground, XtCForeground, XtRXftColor, sizeof(XftColor),
Offset(fg_color), XtRString, XtDefaultForeground},
{XtNface, XtCFace, XtRXftFont, sizeof (XftFont *),
Offset (text_face), XtRString, 0},
#endif
};
#undef Offset
static char defaultTranslations[] =
"<ButtonPress>: notify()";
static XtActionsRec actions_list[] = {
{ "notify", Notify },
};
FontGridClassRec fontgridClassRec = {
{ /* core fields */
/* superclass */ (WidgetClass) &simpleClassRec,
/* class_name */ "FontGrid",
/* widget_size */ sizeof(FontGridRec),
/* class_initialize */ ClassInitialize,
/* class_part_initialize */ NULL,
/* class_inited */ FALSE,
/* initialize */ Initialize,
/* initialize_hook */ NULL,
/* realize */ Realize,
/* actions */ actions_list,
/* num_actions */ XtNumber(actions_list),
/* resources */ resources,
/* num_resources */ XtNumber(resources),
/* xrm_class */ NULLQUARK,
/* compress_motion */ TRUE,
/* compress_exposure */ TRUE,
/* compress_enterleave */ TRUE,
/* visible_interest */ FALSE,
/* destroy */ Destroy,
/* resize */ Resize,
/* expose */ Redisplay,
/* set_values */ SetValues,
/* set_values_hook */ NULL,
/* set_values_almost */ XtInheritSetValuesAlmost,
/* get_values_hook */ NULL,
/* accept_focus */ NULL,
/* version */ XtVersion,
/* callback_private */ NULL,
/* tm_table */ defaultTranslations,
/* query_geometry */ XtInheritQueryGeometry,
/* display_accelerator */ XtInheritDisplayAccelerator,
/* extension */ NULL
},
{ /* simple fields */
/* change_sensitive */ XtInheritChangeSensitive
}
};
WidgetClass fontgridWidgetClass = (WidgetClass) &fontgridClassRec;
long
GridFirstChar (Widget w)
{
FontGridWidget fgw = (FontGridWidget) w;
XFontStruct *fs = fgw->fontgrid.text_font;
#ifdef XRENDER
XftFont *xft = fgw->fontgrid.text_face;
if (xft)
{
FcChar32 map[FC_CHARSET_MAP_SIZE];
FcChar32 next;
FcChar32 first;
int i;
first = FcCharSetFirstPage (xft->charset, map, &next);
for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
if (map[i])
{
FcChar32 bits = map[i];
first += i * 32;
while (!(bits & 0x1))
{
bits >>= 1;
first++;
}
break;
}
return first;
}
else
#endif
if (fs)
{
return (fs->min_byte1 << 8) | (fs->min_char_or_byte2);
}
else
return 0;
}
long
GridLastChar (Widget w)
{
FontGridWidget fgw = (FontGridWidget) w;
XFontStruct *fs = fgw->fontgrid.text_font;
#ifdef XRENDER
XftFont *xft = fgw->fontgrid.text_face;
if (xft)
{
FcChar32 this, last, next;
FcChar32 map[FC_CHARSET_MAP_SIZE];
int i;
last = FcCharSetFirstPage (xft->charset, map, &next);
while ((this = FcCharSetNextPage (xft->charset, map, &next)) != FC_CHARSET_DONE)
last = this;
last &= ~0xff;
for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--)
if (map[i])
{
FcChar32 bits = map[i];
last += i * 32 + 31;
while (!(bits & 0x80000000))
{
last--;
bits <<= 1;
}
break;
}
return (long) last;
}
else
#endif
if (fs)
{
return (fs->max_byte1 << 8) | (fs->max_char_or_byte2);
}
else
return 0;
}
/*
* CI_GET_CHAR_INFO_1D - return the charinfo struct for the indicated 8bit
* character. If the character is in the column and exists, then return the
* appropriate metrics (note that fonts with common per-character metrics will
* return min_bounds).
*/
#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
(((cs)->rbearing|(cs)->lbearing| \
(cs)->ascent|(cs)->descent) == 0))
#define CI_GET_CHAR_INFO_1D(fs,col,cs) \
{ \
cs = 0; \
if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
if (fs->per_char == NULL) { \
cs = &fs->min_bounds; \
} else { \
cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
} \
if (CI_NONEXISTCHAR(cs)) \
cs = 0; \
} \
}
/*
* CI_GET_CHAR_INFO_2D - return the charinfo struct for the indicated row and
* column. This is used for fonts that have more than row zero.
*/
#define CI_GET_CHAR_INFO_2D(fs,row,col,cs) \
{ \
cs = 0; \
if (row >= fs->min_byte1 && row <= fs->max_byte1 && \
col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
if (fs->per_char == NULL) { \
cs = &fs->min_bounds; \
} else { \
cs = &fs->per_char[((row - fs->min_byte1) * \
(fs->max_char_or_byte2 - \
fs->min_char_or_byte2 + 1)) + \
(col - fs->min_char_or_byte2)]; \
} \
if (CI_NONEXISTCHAR(cs)) \
cs = 0; \
} \
}
static Boolean
GridHasChar (Widget w, long ch)
{
FontGridWidget fgw = (FontGridWidget) w;
#ifdef XRENDER
XftFont *xft = fgw->fontgrid.text_face;
if (xft)
{
return FcCharSetHasChar (xft->charset, (FcChar32) ch);
}
else
#endif
{
XFontStruct *fs = fgw->fontgrid.text_font;
XCharStruct *cs;
if (!fs)
return False;
if (fs->max_byte1 == 0)
{
CI_GET_CHAR_INFO_1D (fs, ch, cs);
}
else
{
unsigned int r = (ch >> 8);
unsigned int c = (ch & 0xff);
CI_GET_CHAR_INFO_2D (fs, r, c, cs);
}
return cs != 0;
}
}
/*
* public routines
*/
void
GetFontGridCellDimensions(Widget w, long *startp,
int *ncolsp, int *nrowsp)
{
FontGridWidget fgw = (FontGridWidget) w;
*startp = fgw->fontgrid.start_char;
*ncolsp = fgw->fontgrid.cell_cols;
*nrowsp = fgw->fontgrid.cell_rows;
}
void
GetPrevNextStates(Widget w, Bool *prevvalidp, Bool *nextvalidp,
Bool *prev16validp, Bool *next16validp)
{
FontGridWidget fgw = (FontGridWidget) w;
long minn = (long) GridFirstChar (w);
long maxn = (long) GridLastChar (w);
*prev16validp = (fgw->fontgrid.start_char - 0xf00 > minn);
*prevvalidp = (fgw->fontgrid.start_char > minn);
*nextvalidp = (fgw->fontgrid.start_char +
(fgw->fontgrid.cell_cols * fgw->fontgrid.cell_rows)
< maxn);
*next16validp =((fgw->fontgrid.start_char + 0xf00 +
(fgw->fontgrid.cell_cols * fgw->fontgrid.cell_rows))
< maxn);
}
/*
* private routines and methods
*/
static GC
get_gc(FontGridWidget fgw, Pixel fore)
{
XtGCMask mask;
XGCValues gcv;
mask = (GCForeground | GCBackground | GCFunction);
gcv.foreground = fore;
gcv.background = fgw->core.background_pixel;
gcv.function = GXcopy;
if (fgw->fontgrid.text_font)
{
mask |= GCFont;
gcv.font = fgw->fontgrid.text_font->fid;
}
gcv.cap_style = CapProjecting;
mask |= GCCapStyle;
if (fgw->fontgrid.grid_width > 0) {
mask |= GCLineWidth;
gcv.line_width = ((fgw->fontgrid.grid_width < 2) ? 0 :
fgw->fontgrid.grid_width);
}
return (XtGetGC ((Widget) fgw, mask, &gcv));
}
#ifdef XRENDER
XtConvertArgRec xftColorConvertArgs[] = {
{XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen),
sizeof(Screen *)},
{XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.colormap),
sizeof(Colormap)}
};
#define donestr(type, value, tstr) \
{ \
if (toVal->addr != NULL) { \
if (toVal->size < sizeof(type)) { \
toVal->size = sizeof(type); \
XtDisplayStringConversionWarning(dpy, \
(char*) fromVal->addr, tstr); \
return False; \
} \
*(type*)(toVal->addr) = (value); \
} \
else { \
static type static_val; \
static_val = (value); \
toVal->addr = (XPointer)&static_val; \
} \
toVal->size = sizeof(type); \
return True; \
}
static void
XmuFreeXftColor (XtAppContext app, XrmValuePtr toVal, XtPointer closure,
XrmValuePtr args, Cardinal *num_args)
{
Screen *screen;
Colormap colormap;
XftColor *color;
if (*num_args != 2)
{
XtAppErrorMsg (app,
"freeXftColor", "wrongParameters",
"XtToolkitError",
"Freeing an XftColor requires screen and colormap arguments",
(String *) NULL, (Cardinal *)NULL);
return;
}
screen = *((Screen **) args[0].addr);
colormap = *((Colormap *) args[1].addr);
color = (XftColor *) toVal->addr;
XftColorFree (DisplayOfScreen (screen),
DefaultVisual (DisplayOfScreen (screen),
XScreenNumberOfScreen (screen)),
colormap, color);
}
static Boolean
XmuCvtStringToXftColor(Display *dpy,
XrmValue *args, Cardinal *num_args,
XrmValue *fromVal, XrmValue *toVal,
XtPointer *converter_data)
{
char *spec;
XRenderColor renderColor;
XftColor xftColor;
Screen *screen;
Colormap colormap;
if (*num_args != 2)
{
XtAppErrorMsg (XtDisplayToApplicationContext (dpy),
"cvtStringToXftColor", "wrongParameters",
"XtToolkitError",
"String to render color conversion needs screen and colormap arguments",
(String *) NULL, (Cardinal *)NULL);
return False;
}
screen = *((Screen **) args[0].addr);
colormap = *((Colormap *) args[1].addr);
spec = (char *) fromVal->addr;
if (strcasecmp (spec, XtDefaultForeground) == 0)
{
renderColor.red = 0;
renderColor.green = 0;
renderColor.blue = 0;
renderColor.alpha = 0xffff;
}
else if (strcasecmp (spec, XtDefaultBackground) == 0)
{
renderColor.red = 0xffff;
renderColor.green = 0xffff;
renderColor.blue = 0xffff;
renderColor.alpha = 0xffff;
}
else if (!XRenderParseColor (dpy, spec, &renderColor))
return False;
if (!XftColorAllocValue (dpy,
DefaultVisual (dpy,
XScreenNumberOfScreen (screen)),
colormap,
&renderColor,
&xftColor))
return False;
donestr (XftColor, xftColor, XtRXftColor);
}
static void
XmuFreeXftFont (XtAppContext app, XrmValuePtr toVal, XtPointer closure,
XrmValuePtr args, Cardinal *num_args)
{
Screen *screen;
XftFont *font;
if (*num_args != 1)
{
XtAppErrorMsg (app,
"freeXftFont", "wrongParameters",
"XtToolkitError",
"Freeing an XftFont requires screen argument",
(String *) NULL, (Cardinal *)NULL);
return;
}
screen = *((Screen **) args[0].addr);
font = *((XftFont **) toVal->addr);
if (font)
XftFontClose (DisplayOfScreen (screen), font);
}
static Boolean
XmuCvtStringToXftFont(Display *dpy,
XrmValue *args, Cardinal *num_args,
XrmValue *fromVal, XrmValue *toVal,
XtPointer *converter_data)
{
char *name;
XftFont *font;
Screen *screen;
if (*num_args != 1)
{
XtAppErrorMsg (XtDisplayToApplicationContext (dpy),
"cvtStringToXftFont", "wrongParameters",
"XtToolkitError",
"String to XftFont conversion needs screen argument",
(String *) NULL, (Cardinal *)NULL);
return False;
}
screen = *((Screen **) args[0].addr);
name = (char *) fromVal->addr;
font = 0;
if (name)
{
font = XftFontOpenName (dpy,
XScreenNumberOfScreen (screen),
name);
if (!font)
{
XtDisplayStringConversionWarning(dpy, (char *) fromVal->addr, XtRXftFont);
return False;
}
}
donestr (XftFont *, font, XtRXftFont);
}
static XtConvertArgRec xftFontConvertArgs[] = {
{XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen),
sizeof(Screen *)},
};
#endif
static void
ClassInitialize(void)
{
XtAddConverter (XtRString, XtRLong, XmuCvtStringToLong, NULL, 0);
#ifdef XRENDER
XtSetTypeConverter (XtRString, XtRXftColor,
XmuCvtStringToXftColor,
xftColorConvertArgs, XtNumber(xftColorConvertArgs),
XtCacheByDisplay, XmuFreeXftColor);
XtSetTypeConverter (XtRString, XtRXftFont,
XmuCvtStringToXftFont,
xftFontConvertArgs, XtNumber(xftFontConvertArgs),
XtCacheByDisplay, XmuFreeXftFont);
#endif
}
static void
Initialize(Widget request, Widget new, ArgList args, Cardinal *num_args)
{
FontGridWidget reqfg = (FontGridWidget) request;
FontGridWidget newfg = (FontGridWidget) new;
XFontStruct *fs = newfg->fontgrid.text_font;
#ifdef XRENDER
XftFont *xft = newfg->fontgrid.text_face;
#endif
unsigned maxn;
if (reqfg->fontgrid.cell_cols <= 0)
newfg->fontgrid.cell_cols = 16;
if (reqfg->fontgrid.cell_rows <= 0) {
#ifdef XRENDER
if (xft)
newfg->fontgrid.cell_rows = 16;
else
#endif
if (fs && fs->max_byte1 == 0) {
newfg->fontgrid.cell_rows = (fs->max_char_or_byte2 /
newfg->fontgrid.cell_cols) + 1;
if (newfg->fontgrid.cell_rows > 16)
newfg->fontgrid.cell_rows = 16;
} else
newfg->fontgrid.cell_rows = 16;
}
if (reqfg->fontgrid.cell_width <= 0)
newfg->fontgrid.cell_width = DefaultCellWidth (newfg);
if (reqfg->fontgrid.cell_height <= 0)
newfg->fontgrid.cell_height = DefaultCellHeight (newfg);
/* give a nice size that fits one screen full */
if (newfg->core.width == 0)
newfg->core.width = (newfg->fontgrid.cell_width *
newfg->fontgrid.cell_cols +
newfg->fontgrid.grid_width *
(newfg->fontgrid.cell_cols + 1));
if (newfg->core.height == 0)
newfg->core.height = (newfg->fontgrid.cell_height *
newfg->fontgrid.cell_rows +
newfg->fontgrid.grid_width *
(newfg->fontgrid.cell_rows + 1));
/*
* select the first character
*/
if (newfg->fontgrid.start_char == 0xffffffff)
newfg->fontgrid.start_char = GridFirstChar(new) & ~0xff;
maxn = GridLastChar (new);
if (newfg->fontgrid.start_char > maxn)
newfg->fontgrid.start_char = (maxn + 1 -
(newfg->fontgrid.cell_cols *
newfg->fontgrid.cell_rows));
}
static void
Realize(Widget gw, Mask *valueMask, XSetWindowAttributes *attributes)
{
FontGridWidget fgw = (FontGridWidget) gw;
FontGridPart *p = &fgw->fontgrid;
p->text_gc = get_gc (fgw, GridForeground (fgw));
p->box_gc = get_gc (fgw, p->box_pixel);
Resize (gw);
(*(XtSuperclass(gw)->core_class.realize)) (gw, valueMask, attributes);
#ifdef XRENDER
p->draw = XftDrawCreate (XtDisplay (gw), XtWindow (gw),
DefaultVisual (XtDisplay (gw),
DefaultScreen(XtDisplay (gw))),
fgw->core.colormap);
#endif
return;
}
static void
Destroy(Widget gw)
{
FontGridWidget fgw = (FontGridWidget) gw;
XtReleaseGC (gw, fgw->fontgrid.text_gc);
XtReleaseGC (gw, fgw->fontgrid.box_gc);
}
static void
Resize(Widget gw)
{
FontGridWidget fgw = (FontGridWidget) gw;
/* recompute in case we've changed size */
fgw->fontgrid.cell_width = CellWidth (fgw);
if (fgw->fontgrid.cell_width <= 0)
fgw->fontgrid.cell_width = 1;
fgw->fontgrid.cell_height = CellHeight (fgw);
if (fgw->fontgrid.cell_height <= 0)
fgw->fontgrid.cell_height = 1;
fgw->fontgrid.xoff = (fgw->fontgrid.cell_width -
DefaultCellWidth (fgw)) / 2;
fgw->fontgrid.yoff = (fgw->fontgrid.cell_height -
DefaultCellHeight (fgw)) / 2;
}
/* ARGSUSED */
static void
Redisplay(Widget gw, XEvent *event, Region region)
{
FontGridWidget fgw = (FontGridWidget) gw;
XRectangle rect; /* bounding rect for region */
int left, right, top, bottom; /* which cells were damaged */
int cw, ch; /* cell size */
#ifdef XRENDER
if (!fgw->fontgrid.text_face)
#endif
if (!fgw->fontgrid.text_font) {
Bell (gw, XkbBI_BadValue);
return;
}
/*
* compute the left, right, top, and bottom cells that were damaged
*/
XClipBox (region, &rect);
cw = fgw->fontgrid.cell_width + fgw->fontgrid.grid_width;
ch = fgw->fontgrid.cell_height + fgw->fontgrid.grid_width;
if ((left = (((int) rect.x) / cw)) < 0) left = 0;
right = (((int) (rect.x + rect.width - 1)) / cw);
if ((top = (((int) rect.y) / ch)) < 0) top = 0;
bottom = (((int) (rect.y + rect.height - 1)) / ch);
paint_grid (fgw, left, top, right - left + 1, bottom - top + 1);
}
static void
paint_grid(FontGridWidget fgw, /* widget in which to draw */
int col, int row, /* where to start */
int ncols, int nrows) /* number of cells */
{
FontGridPart *p = &fgw->fontgrid;
int i, j;
Display *dpy = XtDisplay(fgw);
Window wind = XtWindow(fgw);
int cw = p->cell_width + p->grid_width;
int ch = p->cell_height + p->grid_width;
int tcols = p->cell_cols;
int trows = p->cell_rows;
int x1, y1, x2, y2, x, y;
unsigned maxn = GridLastChar ((Widget) fgw);
unsigned n, prevn;
int startx;
if (col + ncols >= tcols) {
ncols = tcols - col;
if (ncols < 1) return;
}
if (row + nrows >= trows) {
nrows = trows - row;
if (nrows < 1) return;
}
/*
* paint the grid lines for the indicated rows
*/
if (p->grid_width > 0) {
int half_grid_width = p->grid_width >> 1;
x1 = col * cw + half_grid_width;
y1 = row * ch + half_grid_width;
x2 = x1 + ncols * cw;
y2 = y1 + nrows * ch;
for (i = 0, x = x1; i <= ncols; i++, x += cw) {
XDrawLine (dpy, wind, p->box_gc, x, y1, x, y2);
}
for (i = 0, y = y1; i <= nrows; i++, y += ch) {
XDrawLine (dpy, wind, p->box_gc, x1, y, x2, y);
}
}
/*
* Draw a character in every box; treat all fonts as if they were 16bit
* fonts. Store the high eight bits in byte1 and the low eight bits in
* byte2.
*/
prevn = p->start_char + col + row * tcols;
startx = col * cw + p->internal_pad + p->grid_width;
for (j = 0,
y = row * ch + p->internal_pad + p->grid_width + GridFontAscent (fgw);
j < nrows; j++, y += ch) {
n = prevn;
for (i = 0, x = startx; i < ncols; i++, x += cw) {
int xoff = p->xoff, yoff = p->yoff;
if (n > maxn) goto done; /* no break out of nested */
#ifdef XRENDER
if (fgw->fontgrid.text_face)
{
XftFont *xft = p->text_face;
FcChar32 c = n;
XGlyphInfo extents;
XftTextExtents32 (dpy, xft, &c, 1, &extents);
if (p->center_chars)
{
xoff = (p->cell_width - extents.width) / 2 - extents.x;
yoff = (p->cell_height - extents.height) / 2 - extents.y;
}
if (extents.width && extents.height)
{
XClearArea (dpy, wind, x + xoff - extents.x,
y + yoff - extents.y,
extents.width, extents.height, False);
if (p->box_chars)
XDrawRectangle (dpy, wind, p->box_gc,
x + xoff - extents.x,
y + yoff - extents.y,
extents.width - 1,
extents.height - 1);
}
XftDrawString32 (p->draw, &p->fg_color, xft,
x + xoff, y + yoff, &c, 1);
}
else
#endif
{
XChar2b thechar;
thechar.byte1 = (n >> 8); /* high eight bits */
thechar.byte2 = (n & 255); /* low eight bits */
if (p->box_chars || p->center_chars) {
XCharStruct metrics;
int direction, fontascent, fontdescent;
XTextExtents16 (p->text_font, &thechar, 1, &direction,
&fontascent, &fontdescent, &metrics);
if (p->center_chars) {
/*
* We want to move the origin by enough to center the ink
* within the cell. The left edge will then be at
* (cell_width - (rbearing - lbearing)) / 2; so we subtract
* the lbearing to find the origin. Ditto for vertical.
*/
xoff = (((p->cell_width -
(metrics.rbearing - metrics.lbearing)) / 2) -
p->internal_pad - metrics.lbearing);
yoff = (((p->cell_height -
(metrics.descent + metrics.ascent)) / 2) -
p->internal_pad -
p->text_font->ascent + metrics.ascent);
}
if (p->box_chars) {
XDrawRectangle (dpy, wind, p->box_gc,
x + xoff, y + yoff - p->text_font->ascent,
metrics.width - 1,
fontascent + fontdescent - 1);
}
}
XDrawString16 (dpy, wind, p->text_gc, x + xoff, y + yoff,
&thechar, 1);
}
n++;
}
prevn += tcols;
}
done:
/*
* paint the grid lines for the indicated rows
*/
if (p->grid_width > 0) {
int half_grid_width = p->grid_width >> 1;
x1 = col * cw + half_grid_width;
y1 = row * ch + half_grid_width;
x2 = x1 + ncols * cw;
y2 = y1 + nrows * ch;
for (i = 0, x = x1; i <= ncols; i++, x += cw) {
XDrawLine (dpy, wind, p->box_gc, x, y1, x, y2);
}
for (i = 0, y = y1; i <= nrows; i++, y += ch) {
XDrawLine (dpy, wind, p->box_gc, x1, y, x2, y);
}
}
return;
}
static Boolean
PageBlank (Widget w, long first, long last)
{
while (first <= last)
{
if (GridHasChar (w, first))
return False;
first++;
}
return True;
}
/*ARGSUSED*/
static Boolean
SetValues(Widget current, Widget request, Widget new,
ArgList args, Cardinal *num_args)
{
FontGridWidget curfg = (FontGridWidget) current;
FontGridWidget newfg = (FontGridWidget) new;
Boolean redisplay = FALSE;
if (curfg->fontgrid.text_font != newfg->fontgrid.text_font ||
curfg->fontgrid.internal_pad != newfg->fontgrid.internal_pad) {
newfg->fontgrid.cell_width = DefaultCellWidth (newfg);
newfg->fontgrid.cell_height = DefaultCellHeight (newfg);
redisplay = TRUE;
}
if (GridForeground(curfg) != GridForeground (newfg)) {
XtReleaseGC (new, curfg->fontgrid.text_gc);
newfg->fontgrid.text_gc = get_gc (newfg, GridForeground (newfg));
redisplay = TRUE;
}
if (curfg->fontgrid.box_pixel != newfg->fontgrid.box_pixel) {
XtReleaseGC (new, curfg->fontgrid.text_gc);
newfg->fontgrid.box_gc = get_gc (newfg, newfg->fontgrid.box_pixel);
redisplay = TRUE;
}
if (curfg->fontgrid.center_chars != newfg->fontgrid.center_chars ||
curfg->fontgrid.box_chars != newfg->fontgrid.box_chars)
redisplay = TRUE;
if (curfg->fontgrid.start_char != newfg->fontgrid.start_char) {
long maxn = GridLastChar (new);
long page = newfg->fontgrid.cell_cols * newfg->fontgrid.cell_rows;
long dir = page;
long start = newfg->fontgrid.start_char;
if (start < curfg->fontgrid.start_char)
dir = -page;
if (start < 0)
start = 0;
if (start > maxn)
start = (maxn / page) * page;
while (PageBlank (new, start, start + page - 1))
{
long next = start + dir;
if (next < 0 || maxn < next)
break;
start = next;
}
newfg->fontgrid.start_char = start;
redisplay = (curfg->fontgrid.start_char != newfg->fontgrid.start_char);
}
return redisplay;
}
/* ARGSUSED */
static void
Notify(Widget gw, XEvent *event, String *params, Cardinal *nparams)
{
FontGridWidget fgw = (FontGridWidget) gw;
int x, y; /* where the event happened */
FontGridCharRec rec; /* callback data */
/*
* only allow events with (x,y)
*/
switch (event->type) {
case KeyPress:
case KeyRelease:
x = event->xkey.x;
y = event->xkey.y;
break;
case ButtonPress:
case ButtonRelease:
x = event->xbutton.x;
y = event->xbutton.y;
break;
case MotionNotify:
x = event->xmotion.x;
y = event->xmotion.y;
break;
default:
Bell (gw, XkbBI_Ignore);
return;
}
/*
* compute the callback data
*/
{
int cw = fgw->fontgrid.cell_width + fgw->fontgrid.grid_width;
int ch = fgw->fontgrid.cell_height + fgw->fontgrid.grid_width;
unsigned n;
if (x > (fgw->fontgrid.cell_cols * cw)) {
Bell (gw, XkbBI_InvalidLocation);
return;
}
n= (fgw->fontgrid.start_char +
((y / ch) * fgw->fontgrid.cell_cols) + (x / cw));
rec.thefont = fgw->fontgrid.text_font;
#ifdef XRENDER
rec.theface = fgw->fontgrid.text_face;
#endif
rec.thechar = n;
}
XtCallCallbacks (gw, XtNcallback, (XtPointer) &rec);
}