Eyes.c revision 2ddb6cf1
1/* $XConsortium: Eyes.c,v 1.28 94/04/17 20:45:22 eswu Exp $ */
2/* $XFree86: xc/programs/xeyes/Eyes.c,v 1.3 2001/07/25 15:05:21 dawes Exp $ */
3/*
4
5Copyright (c) 1991  X Consortium
6
7Permission is hereby granted, free of charge, to any person obtaining
8a copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, sublicense, and/or sell copies of the Software, and to
12permit persons to whom the Software is furnished to do so, subject to
13the following conditions:
14
15The above copyright notice and this permission notice shall be included
16in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
22OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24OTHER DEALINGS IN THE SOFTWARE.
25
26Except as contained in this notice, the name of the X Consortium shall
27not be used in advertising or otherwise to promote the sale, use or
28other dealings in this Software without prior written authorization
29from the X Consortium.
30
31*/
32
33/*
34 * Eyes.c
35 *
36 * a widget which follows the mouse around
37 */
38
39#ifdef HAVE_CONFIG_H
40# include "config.h"
41#endif
42
43# include <X11/Xos.h>
44# include <stdio.h>
45# include <X11/IntrinsicP.h>
46# include <X11/StringDefs.h>
47# include <X11/Xmu/Converters.h>
48# include "EyesP.h"
49# include <math.h>
50# include <X11/extensions/shape.h>
51# include <X11/Xlibint.h>
52# include <stdlib.h>
53
54#if (defined(SVR4) || defined(SYSV) && defined(i386))
55extern double hypot(double, double);
56#endif
57
58#define offset(field) XtOffsetOf(EyesRec, eyes.field)
59#define goffset(field) XtOffsetOf(WidgetRec, core.field)
60
61static XtResource resources[] = {
62    {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
63	goffset(width), XtRImmediate, (XtPointer) 150},
64    {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
65	goffset(height), XtRImmediate, (XtPointer) 100},
66    {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
67        offset(pixel[PART_PUPIL]), XtRString, XtDefaultForeground},
68    {XtNoutline, XtCForeground, XtRPixel, sizeof(Pixel),
69        offset(pixel[PART_OUTLINE]), XtRString, XtDefaultForeground},
70    {XtNcenterColor, XtCBackground, XtRPixel, sizeof (Pixel),
71	offset(pixel[PART_CENTER]), XtRString, XtDefaultBackground},
72    {XtNreverseVideo, XtCReverseVideo, XtRBoolean, sizeof (Boolean),
73	offset (reverse_video), XtRImmediate, (XtPointer) FALSE},
74    {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int),
75    	offset (backing_store), XtRString, "default"},
76    {XtNshapeWindow, XtCShapeWindow, XtRBoolean, sizeof (Boolean),
77	offset (shape_window), XtRImmediate, (XtPointer) TRUE},
78#ifdef XRENDER
79    {XtNrender, XtCBoolean, XtRBoolean, sizeof(Boolean),
80	offset(render), XtRImmediate, (XtPointer) TRUE },
81#endif
82    {XtNdistance, XtCBoolean, XtRBoolean, sizeof(Boolean),
83	offset(distance), XtRImmediate, (XtPointer) FALSE },
84};
85
86#undef offset
87#undef goffset
88
89# define EYE_X(n)	((n) * 2.0)
90# define EYE_Y(n)	(0.0)
91# define EYE_OFFSET	(0.1)	/* padding between eyes */
92# define EYE_THICK	(0.175)	/* thickness of eye rim */
93# define BALL_DIAM	(0.3)
94# define BALL_PAD	(0.175)
95# define EYE_DIAM	(2.0 - (EYE_THICK + EYE_OFFSET) * 2)
96# define BALL_DIST	((EYE_DIAM - BALL_DIAM) / 2.0 - BALL_PAD)
97# define W_MIN_X	(-1.0 + EYE_OFFSET)
98# define W_MAX_X	(3.0 - EYE_OFFSET)
99# define W_MIN_Y	(-1.0 + EYE_OFFSET)
100# define W_MAX_Y	(1.0 - EYE_OFFSET)
101
102# define TPOINT_NONE	(-1000)	/* special value meaning "not yet set" */
103# define TPointEqual(a, b)  ((a).x == (b).x && (a).y == (b).y)
104# define XPointEqual(a, b)  ((a).x == (b).x && (a).y == (b).y)
105# define AngleBetween(A, A0, A1) (A0 <= A1 ? A0 <= A && A <= A1 : \
106					     A0 <= A || A <= A1)
107
108static int delays[] = { 50, 100, 200, 400, 0 };
109
110static void ClassInitialize(void)
111{
112    XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
113		    NULL, 0 );
114}
115
116WidgetClass eyesWidgetClass = (WidgetClass) &eyesClassRec;
117
118/* ARGSUSED */
119static void Initialize (
120    Widget greq,
121    Widget gnew,
122    ArgList args,
123    Cardinal *num_args)
124{
125    EyesWidget w = (EyesWidget)gnew;
126    XtGCMask	valuemask;
127    XGCValues	myXGCV;
128    int shape_event_base, shape_error_base;
129#ifdef XRENDER
130    enum EyesPart i;
131#endif
132
133    /*
134     * set the colors if reverse video; these are the colors used:
135     *
136     *     background - paper		white
137     *     foreground - text, ticks	black
138     *     border - border		black (foreground)
139     *
140     * This doesn't completely work since the parent has already made up a
141     * border.  Sigh.
142     */
143    if (w->eyes.reverse_video) {
144	Pixel fg = w->eyes.pixel[PART_PUPIL];
145	Pixel bg = w->core.background_pixel;
146
147	if (w->core.border_pixel == fg)
148 	    w->core.border_pixel = bg;
149	if (w->eyes.pixel[PART_OUTLINE] == fg)
150	    w->eyes.pixel[PART_OUTLINE] = bg;
151	if (w->eyes.pixel[PART_CENTER] == bg)
152	    w->eyes.pixel[PART_CENTER] = fg;
153	w->eyes.pixel[PART_PUPIL] = bg;
154	w->core.background_pixel = fg;
155    }
156
157    myXGCV.foreground = w->eyes.pixel[PART_PUPIL];
158    myXGCV.background = w->core.background_pixel;
159    valuemask = GCForeground | GCBackground;
160    w->eyes.gc[PART_PUPIL] = XtGetGC(gnew, valuemask, &myXGCV);
161
162    myXGCV.foreground = w->eyes.pixel[PART_OUTLINE];
163    valuemask = GCForeground | GCBackground;
164    w->eyes.gc[PART_OUTLINE] = XtGetGC(gnew, valuemask, &myXGCV);
165
166    myXGCV.foreground = w->eyes.pixel[PART_CENTER];
167    myXGCV.background = w->eyes.pixel[PART_PUPIL];
168    valuemask = GCForeground | GCBackground;
169    w->eyes.gc[PART_CENTER] = XtGetGC(gnew, valuemask, &myXGCV);
170
171    w->eyes.update = 0;
172    /* wait for Realize to add the timeout */
173    w->eyes.interval_id = 0;
174
175    w->eyes.pupil[0].x = w->eyes.pupil[1].x = TPOINT_NONE;
176    w->eyes.pupil[0].y = w->eyes.pupil[1].y = TPOINT_NONE;
177
178    w->eyes.mouse.x = w->eyes.mouse.y = TPOINT_NONE;
179
180    if (w->eyes.shape_window && !XShapeQueryExtension (XtDisplay (w),
181						       &shape_event_base,
182						       &shape_error_base))
183	w->eyes.shape_window = False;
184    w->eyes.shape_mask = 0;
185    w->eyes.gc[PART_SHAPE] = NULL;
186
187#ifdef XRENDER
188    for (i = 0; i < PART_SHAPE; i ++) {
189	XColor c;
190	XRenderColor rc;
191
192	c.pixel = w->eyes.pixel[i];
193	XQueryColor(XtDisplay (w), w->core.colormap, &c);
194
195	rc.red = c.red;
196	rc.green = c.green;
197	rc.blue = c.blue;
198	rc.alpha = -1;
199	w->eyes.fill[i] = XRenderCreateSolidFill(XtDisplay (w), &rc);
200    }
201#endif
202}
203
204static void
205drawEllipse(EyesWidget w, enum EyesPart part,
206	    double centerx, double centery,
207	    double oldx, double oldy,
208	    double diam)
209{
210    const TRectangle tpos = {
211	centerx - diam/2.0,
212	centery - diam/2.0,
213	diam, diam };
214    TRectangle pos;
215    Trectangle(&w->eyes.t, &tpos, &pos);
216
217    if (part == PART_CLEAR) {
218	XFillRectangle(XtDisplay(w), XtWindow(w),
219		       w->eyes.gc[PART_CENTER],
220		       (int)pos.x, (int)pos.y,
221		       (int)pos.width+2, (int)pos.height+2);
222	return;
223    }
224#ifdef XRENDER
225    if (w->eyes.render && part != PART_SHAPE && (!w->eyes.shape_window ||
226						 part != PART_OUTLINE) &&
227	w->eyes.picture) {
228	int n, i;
229	double hd, c, s, sx, sy, x, y, px, py;
230	XPointDouble *p;
231
232	pos.x = pos.x + pos.width/2.0;
233	pos.y = pos.y + pos.height/2.0;
234
235	/* determine number of segments to draw */
236	hd = hypot(pos.width, pos.height)/2;
237	n = (M_PI / acos(hd/(hd+1.0))) + 0.5;
238	if (n < 2) n = 2;
239
240	c = cos(M_PI/n);
241	s = sin(M_PI/n);
242	sx = -(pos.width*s)/pos.height;
243	sy = (pos.height*s)/pos.width;
244
245	n *= 2;
246	p = Xmalloc(sizeof(*p)*n);
247	if (!p)
248	    return;
249	x = 0;
250	y = pos.height/2.0;
251	for (i = 0; i < n; i ++)
252	{
253	    p[i].x = x + pos.x;
254	    p[i].y = y + pos.y;
255	    px = x;
256	    py = y;
257	    x = c*px + sx*py;
258	    y = c*py + sy*px;
259	}
260
261	if (oldx != TPOINT_NONE || oldy != TPOINT_NONE)
262	    drawEllipse(w, PART_CLEAR, oldx, oldy,
263			TPOINT_NONE, TPOINT_NONE, diam);
264
265	XRenderCompositeDoublePoly(XtDisplay(w), PictOpOver,
266				   w->eyes.fill[part], w->eyes.picture,
267				   XRenderFindStandardFormat(XtDisplay(w),
268							     PictStandardA8),
269				   0, 0, 0, 0, p, n, 0);
270
271	Xfree(p);
272	return;
273    }
274#endif
275    if (oldx != TPOINT_NONE || oldy != TPOINT_NONE)
276	drawEllipse(w, PART_CLEAR, oldx, oldy,
277		    TPOINT_NONE, TPOINT_NONE, diam);
278
279    XFillArc(XtDisplay(w),
280	     part == PART_SHAPE ? w->eyes.shape_mask : XtWindow(w),
281	     w->eyes.gc[part],
282	     (int)(pos.x + 0.5), (int)(pos.y + 0.5),
283	     (int)(pos.width + 0.0), (int)(pos.height + 0.0),
284	     90*64, 360*64);
285}
286
287
288static void
289eyeLiner(EyesWidget	w,
290	 Boolean	draw,
291	 int		num)
292{
293    drawEllipse(w, draw ? PART_OUTLINE : PART_SHAPE,
294		EYE_X(num), EYE_Y(num),
295		TPOINT_NONE, TPOINT_NONE,
296		EYE_DIAM + 2.0*EYE_THICK);
297    if (draw) {
298	drawEllipse(w, PART_CENTER, EYE_X(num), EYE_Y(num),
299		    TPOINT_NONE, TPOINT_NONE,
300		    EYE_DIAM);
301    }
302}
303
304static TPoint computePupil (
305    int		num,
306    TPoint	mouse,
307    const TRectangle *screen)
308{
309	double	cx, cy;
310	double	dist;
311	double	angle;
312	double	dx, dy;
313	double	cosa, sina;
314	TPoint	ret;
315
316	cx = EYE_X(num); dx = mouse.x - cx;
317	cy = EYE_Y(num); dy = mouse.y - cy;
318	if (dx == 0 && dy == 0);
319	else {
320		angle = atan2 ((double) dy, (double) dx);
321		cosa = cos (angle);
322		sina = sin (angle);
323		dist = BALL_DIST;
324		if (screen)
325		{
326		    /* use distance mapping */
327		    double x0, y0, x1, y1;
328		    double a[4];
329		    x0 = screen->x - cx;
330		    y0 = screen->y - cy;
331		    x1 = x0 + screen->width;
332		    y1 = y0 + screen->height;
333		    a[0] = atan2(y0, x0);
334		    a[1] = atan2(y1, x0);
335		    a[2] = atan2(y1, x1);
336		    a[3] = atan2(y0, x1);
337		    if (AngleBetween(angle, a[0], a[1]))
338		    {
339			/* left */
340			dist *= dx / x0;
341		    }
342		    else if (AngleBetween(angle, a[1], a[2]))
343		    {
344			/* bottom */
345			dist *= dy / y1;
346		    }
347		    else if (AngleBetween(angle, a[2], a[3]))
348		    {
349			/* right */
350			dist *= dx / x1;
351		    }
352		    else if (AngleBetween(angle, a[3], a[0]))
353		    {
354			/* top */
355			dist *= dy / y0;
356		    }
357		    if (dist > BALL_DIST)
358			dist = BALL_DIST;
359		}
360		if (dist > hypot ((double) dx, (double) dy)) {
361			cx += dx;
362			cy += dy;
363		} else {
364			cx += dist * cosa;
365			cy += dist * sina;
366		}
367	}
368	ret.x = cx;
369	ret.y = cy;
370	return ret;
371}
372
373static void computePupils (
374    EyesWidget	w,
375    TPoint	mouse,
376    TPoint	pupils[2])
377{
378    TRectangle screen, *sp = NULL;
379    if (w->eyes.distance) {
380	Window r, cw;
381	int x, y;
382	r = RootWindowOfScreen(w->core.screen);
383	XTranslateCoordinates(XtDisplay(w), XtWindow(w), r, 0, 0, &x, &y, &cw);
384	screen.x = Tx(-x, -y, &w->eyes.t);
385	screen.y = Ty(-x, -y, &w->eyes.t);
386	screen.width  = Twidth (w->core.screen->width, w->core.screen->height,
387				&w->eyes.t);
388	screen.height = Theight(w->core.screen->width, w->core.screen->height,
389				&w->eyes.t);
390	sp = &screen;
391    }
392    pupils[0] = computePupil (0, mouse, sp);
393    pupils[1] = computePupil (1, mouse, sp);
394}
395
396static void
397eyeBall(EyesWidget	w,
398	Boolean draw,
399	TPoint	*old,
400	int	num)
401{
402    drawEllipse(w, draw ? PART_PUPIL : PART_CLEAR,
403		w->eyes.pupil[num].x, w->eyes.pupil[num].y,
404		old ? old->x : TPOINT_NONE, old ? old->y : TPOINT_NONE,
405		BALL_DIAM);
406}
407
408static void repaint_window (EyesWidget w)
409{
410	if (XtIsRealized ((Widget) w)) {
411		eyeLiner (w, TRUE, 0);
412		eyeLiner (w, TRUE, 1);
413		computePupils (w, w->eyes.mouse, w->eyes.pupil);
414		eyeBall (w, TRUE, NULL, 0);
415		eyeBall (w, TRUE, NULL, 1);
416	}
417}
418
419static void
420drawEye(EyesWidget w, TPoint newpupil, int num)
421{
422    XPoint		xnewpupil, xpupil;
423
424    xpupil.x = Xx(w->eyes.pupil[num].x, w->eyes.pupil[num].y, &w->eyes.t);
425    xpupil.y = Xy(w->eyes.pupil[num].x, w->eyes.pupil[num].y, &w->eyes.t);
426    xnewpupil.x = Xx(newpupil.x, newpupil.y, &w->eyes.t);
427    xnewpupil.y = Xy(newpupil.x, newpupil.y, &w->eyes.t);
428    if (
429#ifdef XRENDER
430	w->eyes.picture ? !TPointEqual(w->eyes.pupil[num], newpupil) :
431#endif
432	!XPointEqual(xpupil, xnewpupil)) {
433	TPoint oldpupil = w->eyes.pupil[num];
434	w->eyes.pupil[num] = newpupil;
435	eyeBall (w, TRUE, &oldpupil, num);
436    }
437}
438
439static void
440drawEyes(EyesWidget w, TPoint mouse)
441{
442    TPoint		newpupil[2];
443    int			num;
444
445    if (TPointEqual (mouse, w->eyes.mouse)) {
446	if (delays[w->eyes.update + 1] != 0)
447	    ++w->eyes.update;
448	return;
449    }
450    computePupils (w, mouse, newpupil);
451    for (num = 0; num < 2; num ++) {
452	drawEye(w, newpupil[num], num);
453    }
454
455    w->eyes.mouse = mouse;
456    w->eyes.update = 0;
457}
458
459static void draw_it_core(EyesWidget w)
460{
461    Window		rep_root, rep_child;
462    int			rep_rootx, rep_rooty;
463    unsigned int	rep_mask;
464    int			dx, dy;
465    TPoint		mouse;
466    Display		*dpy = XtDisplay (w);
467    Window		win = XtWindow (w);
468
469    XQueryPointer (dpy, win, &rep_root, &rep_child,
470	    &rep_rootx, &rep_rooty, &dx, &dy, &rep_mask);
471    mouse.x = Tx(dx, dy, &w->eyes.t);
472    mouse.y = Ty(dx, dy, &w->eyes.t);
473
474    drawEyes(w, mouse);
475}
476
477/* ARGSUSED */
478static void draw_it (
479     XtPointer client_data,
480     XtIntervalId *id)		/* unused */
481{
482        EyesWidget	w = (EyesWidget)client_data;
483
484	if (XtIsRealized((Widget)w)) {
485	        draw_it_core(w);
486	}
487	w->eyes.interval_id =
488		XtAppAddTimeOut(XtWidgetToApplicationContext((Widget) w),
489				delays[w->eyes.update], draw_it, (XtPointer)w);
490} /* draw_it */
491
492static void Resize (Widget gw)
493{
494    EyesWidget	w = (EyesWidget) gw;
495    XGCValues	xgcv;
496    Widget	parent;
497    Display	*dpy = XtDisplay (w);
498    int		x, y;
499
500    if (XtIsRealized (gw))
501    {
502	XClearWindow (dpy, XtWindow (w));
503    	SetTransform (&w->eyes.t,
504		    	0, w->core.width,
505 		    	w->core.height, 0,
506		    	W_MIN_X, W_MAX_X,
507		    	W_MIN_Y, W_MAX_Y);
508#ifdef XRENDER
509	if (w->eyes.picture) {
510	    XRenderFreePicture(dpy, w->eyes.picture);
511	    w->eyes.picture = 0;
512	}
513#endif
514    	if (w->eyes.shape_window) {
515	    w->eyes.shape_mask = XCreatePixmap (dpy, XtWindow (w),
516	    	    w->core.width, w->core.height, 1);
517	    if (!w->eyes.gc[PART_SHAPE])
518		w->eyes.gc[PART_SHAPE] = XCreateGC (dpy, w->eyes.shape_mask,
519						    0, &xgcv);
520	    XSetForeground (dpy, w->eyes.gc[PART_SHAPE], 0);
521	    XFillRectangle (dpy, w->eyes.shape_mask, w->eyes.gc[PART_SHAPE],
522			    0, 0, w->core.width, w->core.height);
523	    XSetForeground (dpy, w->eyes.gc[PART_SHAPE], 1);
524	    eyeLiner (w, FALSE, 0);
525	    eyeLiner (w, FALSE, 1);
526	    x = y = 0;
527	    for (parent = (Widget) w; XtParent (parent); parent = XtParent (parent)) {
528	    	x += parent->core.x + parent->core.border_width;
529	    	x += parent->core.y + parent->core.border_width;
530	    }
531    	    XShapeCombineMask (XtDisplay (parent), XtWindow (parent), ShapeBounding,
532		       	       x, y, w->eyes.shape_mask, ShapeSet);
533	    XFreePixmap (dpy, w->eyes.shape_mask);
534    	}
535#ifdef XRENDER
536	if (w->eyes.render) {
537	    XRenderPictureAttributes pa;
538	    XRenderPictFormat *pf;
539	    pf = XRenderFindVisualFormat(dpy,
540					 DefaultVisualOfScreen(w->core.screen));
541	    if (pf)
542		w->eyes.picture = XRenderCreatePicture(dpy, XtWindow (w),
543						       pf, 0, &pa);
544	}
545#endif
546    }
547}
548
549static void Realize (
550     Widget gw,
551     XtValueMask *valueMask,
552     XSetWindowAttributes *attrs)
553{
554    EyesWidget	w = (EyesWidget)gw;
555
556    if (w->eyes.backing_store != Always + WhenMapped + NotUseful) {
557     	attrs->backing_store = w->eyes.backing_store;
558	*valueMask |= CWBackingStore;
559    }
560    XtCreateWindow( gw, (unsigned)InputOutput, (Visual *)CopyFromParent,
561		     *valueMask, attrs );
562    Resize (gw);
563    w->eyes.interval_id =
564	XtAppAddTimeOut(XtWidgetToApplicationContext(gw),
565			delays[w->eyes.update], draw_it, (XtPointer)gw);
566}
567
568static void Destroy (Widget gw)
569{
570     EyesWidget w = (EyesWidget)gw;
571     int i;
572
573     if (w->eyes.interval_id)
574	XtRemoveTimeOut (w->eyes.interval_id);
575     for (i = 0; i < PART_MAX; i ++)
576	     XtReleaseGC(gw, w->eyes.gc[i]);
577#ifdef XRENDER
578     if (w->eyes.picture)
579	     XRenderFreePicture (XtDisplay(w), w->eyes.picture);
580#endif
581}
582
583/* ARGSUSED */
584static void Redisplay(
585     Widget gw,
586     XEvent *event,
587     Region region)
588{
589    EyesWidget	w;
590
591    w = (EyesWidget) gw;
592    w->eyes.pupil[0].x = TPOINT_NONE;
593    w->eyes.pupil[0].y = TPOINT_NONE;
594    w->eyes.pupil[1].x = TPOINT_NONE;
595    w->eyes.pupil[1].y = TPOINT_NONE;
596    (void) repaint_window ((EyesWidget)gw);
597}
598
599/* ARGSUSED */
600static Boolean SetValues (
601    Widget current,
602    Widget request,
603    Widget new,
604    ArgList args,
605    Cardinal *num_args)
606{
607    return( FALSE );
608}
609
610EyesClassRec eyesClassRec = {
611    { /* core fields */
612    /* superclass		*/	&widgetClassRec,
613    /* class_name		*/	"Eyes",
614    /* size			*/	sizeof(EyesRec),
615    /* class_initialize		*/	ClassInitialize,
616    /* class_part_initialize	*/	NULL,
617    /* class_inited		*/	FALSE,
618    /* initialize		*/	Initialize,
619    /* initialize_hook		*/	NULL,
620    /* realize			*/	Realize,
621    /* actions			*/	NULL,
622    /* num_actions		*/	0,
623    /* resources		*/	resources,
624    /* num_resources		*/	XtNumber(resources),
625    /* xrm_class		*/	NULLQUARK,
626    /* compress_motion		*/	TRUE,
627    /* compress_exposure	*/	TRUE,
628    /* compress_enterleave	*/	TRUE,
629    /* visible_interest		*/	FALSE,
630    /* destroy			*/	Destroy,
631    /* resize			*/	Resize,
632    /* expose			*/	Redisplay,
633    /* set_values		*/	SetValues,
634    /* set_values_hook		*/	NULL,
635    /* set_values_almost	*/	NULL,
636    /* get_values_hook		*/	NULL,
637    /* accept_focus		*/	NULL,
638    /* version			*/	XtVersion,
639    /* callback_private		*/	NULL,
640    /* tm_table			*/	NULL,
641    /* query_geometry		*/	XtInheritQueryGeometry,
642    }
643};
644