(3)

NAME
XfwfAnimator

DESCRIPTION
The animator widget cycles through a series of images (XImage structures). Each image is displayed for a certain number of milliseconds. After the last image, the animation can either start over or stop with the last image displayed. The animation must be started with XfwfStartAnimation and it may be stopped with XfwfStopAnimation. The widget uses the location resources (see XfwfBoard(3)) for positioning only; the preferred size of the widget will be the size of the largest image, plus room for the frame.

  Public variables
XfwfAnimator
Name | Class | Type | Default
XtNimages | XtCImages | ImageList | NULL
XtNintervals | XtCIntervals | CardinalList | NULL
XtNdefaultInterval | XtCDefaultInterval | Cardinal | 500
XtNcycle | XtCCycle | Boolean | True

XtNimages
    The list of images can be specified in the resource file as a series of filenames of files in XPM format. If it is set from an application, the list must end with a NULL. Every element is a pointer to an XImage structure.
    <ImageList> XImage ** images = NULL

XtNintervals
    The time that each image will be displayed can be set with intervals. It is a list of cardinals, each representing a number of milliseconds. The list must end with a zero. If there are insufficient numbers in the list, the last number will be used as the interval for any remaining images. If the list is empty (NULL), the interval will be defaultInterval (normally 500).
    <CardinalList> Cardinal * intervals = NULL

XtNdefaultInterval
    If the list of intervals is empty, the interval will be defaultInterval milliseconds.
    Cardinal  defaultInterval = 500

XtNcycle
    The animation repeats indefinitely by default. When the cycle resource is set to False the animation sequence is shown once only, for every call to XfwfStartAnimation.
    Boolean  cycle = True

XtNframeType
    The default type of frame is set to `sunken'.
     frameType = XfwfSunken

XtNrel_width
    If there is no image to display, the widget has no obvious size. The following defaults for the location resources create a 7 by 7 pixel widget.
     rel_width = <String>"0.0"

XtNabs_width
     abs_width = 7

XtNrel_height
     rel_height = <String>"0.0"

XtNabs_height
     abs_height = 7
    XfwfBoard
    Name | Class | Type | Default
    XtNabs_x | XtCAbs_x | Int | 0
    XtNrel_x | XtCRel_x | Float | "0.0"
    XtNabs_y | XtCAbs_y | Int | 0
    XtNrel_y | XtCRel_y | Float | "0.0"
    XtNabs_width | XtCAbs_width | Int | 0
    XtNrel_width | XtCRel_width | Float | "1.0"
    XtNabs_height | XtCAbs_height | Int | 0
    XtNrel_height | XtCRel_height | Float | "1.0"
    XtNhunit | XtCHunit | Float | "1.0"
    XtNvunit | XtCVunit | Float | "1.0"
    XtNlocation | XtCLocation | String | NULL
    XfwfFrame
    Name | Class | Type | Default
    XtNcursor | XtCCursor | Cursor | None
    XtNframeType | XtCFrameType | FrameType | XfwfRaised
    XtNframeWidth | XtCFrameWidth | Dimension | 0
    XtNframeOffset | XtCFrameOffset | Dimension | 0
    XtNshadowScheme | XtCShadowScheme | ShadowScheme | XfwfAuto
    XtNlightColor | XtCLightColor | Pixel | XtDefaultBackground
    XtNdarkColor | XtCDarkColor | Pixel | XtDefaultForeground
    XtNlightStipple | XtCLightStipple | Bitmap | NULL
    XtNdarkStipple | XtCDarkStipple | Bitmap | NULL
    XfwfCommon
    Name | Class | Type | Default
    XtNtraversalOn | XtCTraversalOn | Boolean | True
    XtNhighlightThickness | XtCHighlightThickness | Dimension | 2
    XtNhighlightColor | XtCHighlightColor | Pixel | XtDefaultForeground
    XtNhighlightPixmap | XtCHighlightPixmap | Pixmap | None
    XtNnextTop | XtCNextTop | Callback | NULL
    XtNuserData | XtCUserData | Pointer | NULL
    Composite
    Name | Class | Type | Default
    XtNchildren | XtCChildren | WidgetList | NULL
    insertPosition | XtCInsertPosition | XTOrderProc | NULL
    numChildren | XtCNumChildren | Cardinal | 0
    Core
    Name | Class | Type | Default
    XtNx | XtCX | Position | 0
    XtNy | XtCY | Position | 0
    XtNwidth | XtCWidth | Dimension | 0
    XtNheight | XtCHeight | Dimension | 0
    borderWidth | XtCBorderWidth | Dimension | 0
    XtNcolormap | XtCColormap | Colormap | NULL
    XtNdepth | XtCDepth | Int | 0
    destroyCallback | XtCDestroyCallback | XTCallbackList | NULL
    XtNsensitive | XtCSensitive | Boolean | True
    XtNtranslations | XtCTranslations | XTTranslations | NULL
    ancestorSensitive | XtCAncestorSensitive | Boolean | False
    accelerators | XtCAccelerators | XTTranslations | NULL
    borderColor | XtCBorderColor | Pixel | 0
    borderPixmap | XtCBorderPixmap | Pixmap | NULL
    background | XtCBackground | Pixel | 0
    backgroundPixmap | XtCBackgroundPixmap | Pixmap | NULL
    mappedWhenManaged | XtCMappedWhenManaged | Boolean | True
    XtNscreen | XtCScreen | Screen * | NULL

  Exports
To start the animation an application should call XfwfStartAnimation. If the animation is already running, it will be restarted from the beginning.
XfwfStartAnimation( $)
{
    if (! XtIsSubclass($, xfwfAnimatorWidgetClass))
    XtWarning("Illegal widget type in XfwfStartAnimation");
    else
    $start_animation($); } The animation can be stopped with XfwfStopAnimation.
XfwfStopAnimation( $)
{
    if (! XtIsSubclass($, xfwfAnimatorWidgetClass))
    XtWarning("Illegal widget type in XfwfStopAnimation");
    else
    $stop_animation($); }

Importss
incl
 <X11/xpm.h>
incl
 <stdio.h>

  Private variables
The images will be changed by a time-out routine. The timer for that routine is stored in timer.
XtIntervalId  timer
The current image.
int  cur_image
The current interval, if intervals is not NULL.
int  cur_interval
The GC for drawing the image.
GC  image_gc

  Methods
class_initialize installs the type converters for a list of images and a list of cardinal numbers.
class_initialize()
{
    XtSetTypeConverter(XtRString, XtRImageList, cvtStringToImageList,
		       NULL, 0, XtCacheNone, NULL);
    XtSetTypeConverter(XtRString, XtRCardinalList, cvtStringToCardinalList,
		       NULL, 0, XtCacheNone, NULL);
}
The initialize sets the (desired and actual) size of the widget to the size of the largest image. The GC is initialized to all default values.
initialize(Widget  request, $, ArgList  args, Cardinal * num_args)
{
    Dimension wd, ht, dummy1, dummy2;
    Position x, y;
    XImage **p;
    XtGCMask value_mask = 0;
    XGCValues values;
    $timer = NULL;
    $image_gc = XtGetGC($, value_mask, values);
    if ($images != NULL) {
	$compute_inside($, x, y, dummy1, dummy2);
	wd = 1; ht = 1;
	for (p = $images; *p; p++) {
	    if ((*p)->width > wd) wd = (*p)->width;
	    if ((*p)->height > ht) ht = (*p)->height;
	}
	XtVaSetValues($, XtNwidth, wd + 2*x, XtNheight, ht + 2*y, NULL);
    }
}
The start_animation method is usually called by the XfwfStartAnimation routine. If an animation is already running, the time-out function must be removed first. To draw the first image, the routine calls the expose method with the event and region parameters set to NULL.
start_animation($)
{
    Cardinal delay;
    if (! $images) return;
    if ($timer) XtRemoveTimeOut($timer);
    $cur_image = 0;
    $cur_interval = 0;
    if (! $intervals || $intervals[0] == 0)
	delay = $defaultInterval;
    else
	delay = $intervals[$cur_interval];
    $expose($, NULL, NULL);
    $timer = XtAppAddTimeOut(XtWidgetToApplicationContext($), delay,
			     next_image, $);
}
The stop_animation method simply removes the time-out function. It leaves the current image undisturbed.
stop_animation($)
{
    if ($timer) {
	XtRemoveTimeOut($timer);
	$timer = NULL;
    }
}
The expose method simply draws the current image (if any) against the top left corner of the widget. It then calls the superclass's expose method to draw the frame.
expose($, XEvent * event, Region  region)
{
    Dimension wd, ht;
    Position x, y;
    if (! XtIsRealized($)) return;
    if (region != NULL)
	XSetRegion(XtDisplay($), $image_gc, region);
    $compute_inside($, x, y, wd, ht);
    if ($images) XPutImage(XtDisplay($), XtWindow($), $image_gc,
			   $images[$cur_image], 0, 0, x, y,
			   $images[$cur_image]->width,
			   $images[$cur_image]->height);
    if (region != NULL)
	XSetClipMask(XtDisplay($), $image_gc, None);
    #expose($, event, region);
}
Boolean  set_values(Widget  old, Widget  request, $, ArgList  args, Cardinal * num_args)
{
    Dimension wd, ht, dummy1, dummy2;
    Position x, y;
    XImage **p;
    Boolean restart = False;
    if ($old$images != $images) {
	if ($timer) restart = True;
	$stop_animation($);
	$compute_inside($, x, y, dummy1, dummy2);
	wd = 1; ht = 1;
	for (p = $images; *p; p++) {
	    if ((*p)->width > wd) wd = (*p)->width;
	    if ((*p)->height > ht) ht = (*p)->height;
	}
	XtVaSetValues($, XtNwidth, wd + 2*x, XtNheight, ht + 2*y, NULL);
    }
    if ($old$intervals != $intervals) {
	if ($timer) restart = True;
	$stop_animation($);
    }
    if (restart) $start_animation($);
    return False;
}

Utilities
The timer callback routine checks if there is another image to display, either the next image or the first image, if cycle is True. It determines the correct interval for the new image, which can be the next number in intervals, or the previous number, if there is no next, or the defaultInterval, if there is no interval at all. It then re-installs itself as a time-out routine.
next_image(XtPointer  client_data, XtIntervalId * timer)
{
    Widget $ = (Widget) client_data;
    Cardinal delay;
    if ($images[$cur_image+1] == NULL) {
	if (! $cycle) return;			/* Nothing more */
	$cur_image = 0;
	$cur_interval = 0;
	if ($intervals == NULL || $intervals[0] == 0)
	    delay = $defaultInterval;
	else
	    delay = $intervals[0];
    } else {
	$cur_image++;
	if ($intervals == NULL)
	    delay = $defaultInterval;
	else if ($intervals[$cur_interval+1] == 0)
	    delay = $intervals[$cur_interval];
	else {
	    $cur_interval++;
	    delay = $intervals[$cur_interval];
	}
    }
    $expose($, NULL, NULL);
    $timer = XtAppAddTimeOut(XtWidgetToApplicationContext($), delay,
			     next_image, $);
}
The converter from a string to a list of images splits the string in words separated by spaces and/or commas. Each word must be the name of a file containing a pixmap in XPM format. The pixmap is read into an XImage. def done(type, value) = do {
      if (to->addr != NULL) {
      if (to->size < sizeof(type)) {
          to->size = sizeof(type);
          return False;
      }
      *(type*)(to->addr) = (value);
      } else {
      static type static_val;
      static_val = (value);
      to->addr = (XtPointer)static_val;
      }
      to->size = sizeof(type);
      return True;
  }while (0 )
Boolean  cvtStringToImageList(Display * display, XrmValuePtr  args, Cardinal * num_args, XrmValuePtr  from, XrmValuePtr  to, XtPointer * converter_data)
{
    String p;
    XImage *im, *shape, **list = NULL;
    int status, n = 0;
    Cardinal one = 1;
    if (*num_args != 0)
	XtAppErrorMsg
	    (XtDisplayToApplicationContext(display),
	     "cvtStringToImageList", "wrongParameters",
	     "XtToolkitError",
	     "String to image list type conversion needs no arguments",
	     (String*) NULL, (Cardinal*) NULL);
    p = strtok((String) from->addr, " \t\n,");
    while (p) {
	status = XpmReadFileToImage(display, p, im, shape, NULL);
	switch (status) {
	case XpmOpenFailed:
	case XpmFileInvalid:
	case XpmNoMemory:
	    XtAppWarningMsg
		(XtDisplayToApplicationContext(display),
		 "cvtStringToImageList", "fileError",
		 "XtToolkitError",
		 "Failed to read image from \"%s\"",
		 p, one);
	    break;
	case XpmColorError:
	case XpmColorFailed:
	    XtAppWarningMsg
		(XtDisplayToApplicationContext(display),
		 "cvtStringToImageList", "allocColor",
		 "XtToolkitError",
		 "Could not get (all) colors for image \"%s\"",
		 p, one);
	case XpmSuccess:
	    n++;
	    list = (XImage**) XtRealloc((char*) list, n * sizeof(im));
	    list[n-1] = im;
	}
	p = strtok(NULL, " \t\n,");
    }
    if (n > 0) {
	n++;
	list = (XImage**) XtRealloc((char*) list, n * sizeof(im));
	list[n-1] = NULL;
    }
    done(XImage**, list);
}
Boolean  cvtStringToCardinalList(Display * display, XrmValuePtr  args, Cardinal * num_args, XrmValuePtr  from, XrmValuePtr  to, XtPointer * converter_data)
{
    String p;
    Cardinal *list = NULL;
    int n = 0, h, stat;
    if (*num_args != 0)
	XtAppErrorMsg
	    (XtDisplayToApplicationContext(display),
	     "cvtStringToCardinalList", "wrongParameters",
	     "XtToolkitError",
	     "String to cardinal list type conversion needs no arguments",
	     (String*) NULL, (Cardinal*) NULL);
    p = (char *) from->addr;
    do {
	n++;
	list = (Cardinal*) XtRealloc((char*) list, n * sizeof(Cardinal));
	/* list[n-1] = strtoul(p, p, 0); */
	stat = sscanf(p, "%u%n", list[n-1], h);
	p = p + h;
	fprintf(stderr, "scanned %d (%u)\n", stat, list[n-1]);
    } while (stat == 1  list[n-1] != 0);
    list[n-1] = 0;
    done(Cardinal *, list);
}