view lwlib/lwlib-Xm.c @ 169:15872534500d r20-3b11

Import from CVS: tag r20-3b11
author cvs
date Mon, 13 Aug 2007 09:46:53 +0200
parents 5a88923fcbfe
children 929b76928fce
line wrap: on
line source

/* The lwlib interface to Motif widgets.
   Copyright (C) 1992, 1993, 1994 Lucid, Inc.
   Copyright (C) 1995 Tinker Systems and INS Engineering Corp.

This file is part of the Lucid Widget Library.

The Lucid Widget Library is free software; you can redistribute it and/or 
modify it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

The Lucid Widget Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with XEmacs; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */

#include <config.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include <X11/StringDefs.h>
#include <X11/IntrinsicP.h>
#include <X11/ObjectP.h>
#include <X11/CoreP.h>
#include <X11/CompositeP.h>

#include "lwlib-Xm.h"
#include "lwlib-utils.h"

#include <Xm/Xm.h>
#include <Xm/BulletinB.h>
#include <Xm/CascadeB.h>
#include <Xm/DrawingA.h>
#include <Xm/FileSB.h>
#include <Xm/Label.h>
#include <Xm/List.h>
#include <Xm/MenuShell.h>
#include <Xm/MessageB.h>
#include <Xm/PushB.h>
#include <Xm/PushBG.h>
#include <Xm/ArrowB.h>
#include <Xm/ScrollBar.h>
#include <Xm/SelectioB.h>
#include <Xm/Text.h>
#include <Xm/TextF.h>
#include <Xm/ToggleB.h>
#include <Xm/ToggleBG.h>
#include <Xm/RowColumn.h>
#include <Xm/ScrolledW.h>
#include <Xm/Separator.h>
#include <Xm/DialogS.h>
#include <Xm/Form.h>

#ifdef MENUBARS_MOTIF
static void xm_pull_down_callback (Widget, XtPointer, XtPointer);
#if 0
static void xm_pop_down_callback (Widget, XtPointer, XtPointer);
#endif /* 0 */
#endif
static void xm_internal_update_other_instances (Widget, XtPointer,
						XtPointer);
static void xm_generic_callback (Widget, XtPointer, XtPointer);
#ifdef DIALOGS_MOTIF
static void xm_nosel_callback (Widget, XtPointer, XtPointer);
#endif
#ifdef SCROLLBARS_MOTIF
static void xm_scrollbar_callback (Widget, XtPointer, XtPointer);
#endif

#ifdef MENUBARS_MOTIF
static void
xm_update_menu (widget_instance* instance, Widget widget, widget_value* val,
		Boolean deep_p);
#endif

/* Structures to keep destroyed instances */
typedef struct _destroyed_instance 
{
  char*		name;
  char*		type;
  Widget 	widget;
  Widget	parent;
  Boolean	pop_up_p;
  struct _destroyed_instance*	next;
} destroyed_instance;

static destroyed_instance*
all_destroyed_instances = NULL;

/* Utility function. */
static char *
safe_strdup (char* s)
{
  char *result;
  if (! s) return 0;
  result = (char *) malloc (strlen (s) + 1);
  if (! result)
    return 0;
  strcpy (result, s);
  return result;
}

static destroyed_instance*
make_destroyed_instance (char* name, char* type, Widget widget, Widget parent,
			 Boolean pop_up_p)
{
  destroyed_instance* instance =
    (destroyed_instance*) malloc (sizeof (destroyed_instance));
  instance->name = safe_strdup (name);
  instance->type = safe_strdup (type);
  instance->widget = widget;
  instance->parent = parent;
  instance->pop_up_p = pop_up_p;
  instance->next = NULL;
  return instance;
}
			 
static void
free_destroyed_instance (destroyed_instance* instance)
{
  free (instance->name);
  free (instance->type);
  free (instance);
}

/* motif utility functions */
Widget
first_child (Widget widget)
{
  return ((CompositeWidget)widget)->composite.children [0];
}

Boolean
lw_motif_widget_p (Widget widget)
{
  return 
#ifdef DIALOGS_MOTIF
    XtClass (widget) == xmDialogShellWidgetClass ||
#endif
      XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
}

static char *
resource_string (Widget widget, char *name)
{
  XtResource resource;
  char *result = NULL;
  
  resource.resource_name  = "labelString";
  resource.resource_class = "LabelString"; /* #### should be Xmsomething... */
  resource.resource_type = XtRString;
  resource.resource_size = sizeof (String);
  resource.resource_offset = 0;
  resource.default_type = XtRImmediate;
  resource.default_addr = 0;

  XtGetSubresources (widget, (XtPointer)&result, name,
		     name, &resource, 1, NULL, 0);
  return result;
}

#ifdef MENUBARS_MOTIF

static void
destroy_all_children (Widget widget)
{
  Widget* children;
  unsigned int number;
  int i;

  children = XtCompositeChildren (widget, &number);
  if (children)
    {
      /* Unmanage all children and destroy them.  They will only be 
       * really destroyed when we get out of DispatchEvent. */
      for (i = 0; i < number; i++)
	{
	  Widget child = children [i];
	  if (!child->core.being_destroyed)
	    {
	      XtUnmanageChild (child);
	      XtDestroyWidget (child);
	    }
	}
      XtFree ((char *) children);
    }
}

#endif /* MENUBARS_MOTIF */



#ifdef DIALOGS_MOTIF

static Boolean
is_in_dialog_box (Widget w)
{
  Widget wmshell;

  wmshell = XtParent (w);
  while (wmshell && (XtClass (wmshell) != xmDialogShellWidgetClass))
    wmshell = XtParent (wmshell);

  if (wmshell && XtClass (wmshell) == xmDialogShellWidgetClass)
    return True;
  else
    return False;
}

#endif /* DIALOGS_MOTIF */

#if defined (DIALOGS_MOTIF) || defined (MENUBARS_MOTIF)

/* update the label of anything subclass of a label */
static void
xm_update_label (widget_instance* instance, Widget widget, widget_value* val)
{
  XmString built_string = NULL;
  XmString key_string   = NULL;
  XmString val_string   = NULL;
  XmString name_string  = NULL;
  Arg al [20];
  int ac = 0;

  if (val->value)
    {
#ifdef DIALOGS_MOTIF
      /*
       * Sigh.  The main text of a label is the name field for menubar
       * entries.  The value field is a possible additional field to be
       * concatenated on to the name field.  HOWEVER, with dialog boxes
       * the value field is the complete text which is supposed to be
       * displayed as the label.  Yuck.
       */
      if (is_in_dialog_box (widget))
	{
	  char *value_name = NULL;

	  value_name = resource_string (widget, val->value);
	  if (!value_name)
	    value_name = val->value;

	  built_string =
	    XmStringCreateLtoR (value_name, XmSTRING_DEFAULT_CHARSET);
	}
      else
#endif /* DIALOGS_MOTIF */
	{
	  char *value_name = NULL;
	  char *res_name = NULL;

	  res_name = resource_string (widget, val->name);
	  if (!res_name)
	    res_name = val->name;

	  name_string =
	    XmStringCreateLtoR (res_name, XmSTRING_DEFAULT_CHARSET);

	  value_name = XtMalloc (strlen (val->value) + 2);
	  *value_name = 0;
	  strcat (value_name, " ");
	  strcat (value_name, val->value);

	  val_string =
	    XmStringCreateLtoR (value_name, XmSTRING_DEFAULT_CHARSET);

	  built_string =
	    XmStringConcat (name_string, val_string);

	  XtFree (value_name);
	}

      XtSetArg (al [ac], XmNlabelString, built_string); ac++;
      XtSetArg (al [ac], XmNlabelType, XmSTRING);	ac++;
    }
  
  if (val->key)
    {
      key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
      XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
    }

  if (ac)
    XtSetValues (widget, al, ac);

  if (built_string)
    XmStringFree (built_string);

  if (key_string)
    XmStringFree (key_string);

  if (name_string)
    XmStringFree (name_string);
}

#endif /* defined (DIALOGS_MOTIF) || defined (MENUBARS_MOTIF) */

/* update of list */
static void
xm_update_list (widget_instance* instance, Widget widget, widget_value* val)
{
  widget_value* cur;
  int i;
  XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
  XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
		 instance);
  for (cur = val->contents, i = 0; cur; cur = cur->next)
    if (cur->value)
      {
	XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET);
	i += 1;
	XmListAddItem (widget, xmstr, 0);
	if (cur->selected)
	  XmListSelectPos (widget, i, False);
	XmStringFree (xmstr);
      }
}

/* update of buttons */
static void
xm_update_pushbutton (widget_instance* instance, Widget widget,
		      widget_value* val)
{
  Arg al [1];
  XtSetArg (al [0], XmNalignment, XmALIGNMENT_CENTER);
  XtSetValues (widget, al, 1);
  XtRemoveAllCallbacks (widget, XmNactivateCallback);
  XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
}

#ifdef MENUBARS_MOTIF

static void
xm_update_cascadebutton (widget_instance* instance, Widget widget,
			 widget_value* val)
{
  /* Should also rebuild the menu by calling ...update_menu... */
  if (val
      && val->type == CASCADE_TYPE
      && val->contents
      && val->contents->type == INCREMENTAL_TYPE)
    {
      /* okay, we're now doing a lisp callback to incrementally generate
	 more of the menu. */
      XtRemoveAllCallbacks (widget, XmNcascadingCallback);
      XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
		     instance);
      XtCallCallbacks ((Widget)widget,
		      XmNcascadingCallback,
		      (XtPointer)val->contents);

    } else {
      XtRemoveAllCallbacks (widget, XmNcascadingCallback);
      XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
		     instance);
    }      
}

#endif /* MENUBARS_MOTIF */

/* update toggle and radiobox */
static void
xm_update_toggle (widget_instance* instance, Widget widget, widget_value* val)
{
  Arg al [2];
  XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
#ifndef ENERGIZE
  XtAddCallback (widget, XmNvalueChangedCallback, xm_generic_callback,
		 instance);
#else
  XtAddCallback (widget, XmNvalueChangedCallback,
		 xm_internal_update_other_instances, instance);
#endif
  XtSetArg (al [0], XmNset, val->selected);
  XtSetArg (al [1], XmNalignment, XmALIGNMENT_BEGINNING);
  XtSetValues (widget, al, 2);
}

static void
xm_update_radiobox (widget_instance* instance, Widget widget,
		    widget_value* val)
{
  Widget toggle;
  widget_value* cur;

  /* update the callback */
  XtRemoveAllCallbacks (widget, XmNentryCallback);
  XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);

  /* first update all the toggles */
  /* Energize kernel interface is currently bad.  It sets the selected widget
     with the selected flag but returns it by its name.  So we currently
     have to support both setting the selection with the selected slot
     of val contents and setting it with the "value" slot of val.  The latter
     has a higher priority.  This to be removed when the kernel is fixed. */
  for (cur = val->contents; cur; cur = cur->next)
    {
      toggle = XtNameToWidget (widget, cur->value);
      if (toggle)
	{
	  Arg al [2];
	  XtSetArg (al [0], XmNsensitive, cur->enabled);
	  XtSetArg (al [1], XmNset, (!val->value && cur->selected ? cur->selected : False));
	  XtSetValues (toggle, al, 2);
	}
    }

  /* The selected was specified by the value slot */
  if (val->value)
    {
      toggle = XtNameToWidget (widget, val->value);
      if (toggle)
	{
	  Arg al [1];
	  XtSetArg (al [0], XmNset, True);
	  XtSetValues (toggle, al, 1);
	}
    }
}

#ifdef MENUBARS_MOTIF

/* update a popup menu, pulldown menu or a menubar */
static void
make_menu_in_widget (widget_instance* instance, Widget widget,
		     widget_value* val)
{
  Widget* children = 0;
  int num_children;
  int child_index;
  widget_value* cur;
  Widget button = 0;
  Widget menu;
  Arg al [256];
  int ac;
  Boolean menubar_p = False;

  /* Allocate the children array */
  for (num_children = 0, cur = val; cur; num_children++, cur = cur->next);
  children = (Widget*)XtMalloc (num_children * sizeof (Widget));

  /* tricky way to know if this RowColumn is a menubar or a pulldown... */
  XtSetArg (al [0], XmNisHomogeneous, &menubar_p);
  XtGetValues (widget, al, 1);

  /* add the unmap callback for popups and pulldowns */
  /*** this sounds bogus ***/
  /* probably because it is -- cet */
/*
  if (!menubar_p)
    XtAddCallback (XtParent (widget), XmNpopdownCallback,
		   xm_pop_down_callback, (XtPointer)instance);
*/

  num_children = 0;
  for (child_index = 0, cur = val; cur; child_index++, cur = cur->next)
    {    
      ac = 0;
      button = 0;
      XtSetArg (al [ac], XmNsensitive, cur->enabled);		ac++;
      XtSetArg (al [ac], XmNalignment, XmALIGNMENT_BEGINNING);	ac++;
      XtSetArg (al [ac], XmNuserData, cur->call_data);		ac++;

      switch (cur->type)
	{
	case PUSHRIGHT_TYPE:
	  /* A pushright marker which is not needed for the real Motif
             menubar. */
	  break;
	case SEPARATOR_TYPE:
	  ac = 0;
	  if (cur->value)
	    {
	      /* #### - xlwmenu.h supports several types that motif does
		 not.  Also, motif supports pixmaps w/ type NO_LINE and
		 lwlib provides no way to access that functionality. --Stig */
	      XtSetArg (al [ac], XmNseparatorType, cur->value), ac++;
	    }
	  button = XmCreateSeparator (widget, "separator", al, ac);
	  break;
	case CASCADE_TYPE:
	  menu = XmCreatePulldownMenu (widget, "pulldown", NULL, 0);
	  make_menu_in_widget (instance, menu, cur->contents);
	  XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
	  button = XmCreateCascadeButton (widget, cur->name, al, ac);

	  xm_update_label (instance, button, cur);

	  XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
			 (XtPointer)instance);
	  break;
	default:
	  if (menubar_p)
	    button = XmCreateCascadeButton (widget, cur->name, al, ac);
	  else if (!cur->call_data)
	    button = XmCreateLabel (widget, cur->name, al, ac);
	  else if (cur->type == TOGGLE_TYPE || cur->type == RADIO_TYPE)
	    {
	      XtSetArg (al [ac], XmNindicatorType,
			(cur->type == TOGGLE_TYPE ?
			 XmN_OF_MANY : XmONE_OF_MANY));    ac++;
	      XtSetArg (al [ac], XmNvisibleWhenOff, True); ac++;
	      button = XmCreateToggleButtonGadget (widget, cur->name, al, ac);
	    }
	  else
	    button = XmCreatePushButtonGadget (widget, cur->name, al, ac);

	  xm_update_label (instance, button, cur);

	  /* don't add a callback to a simple label */
	  if (cur->type == TOGGLE_TYPE || cur->type == RADIO_TYPE)
	    xm_update_toggle (instance, button, cur);
	  else if (cur->call_data)
	    XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
			   (XtPointer)instance);
	} /* switch (cur->type) */

      if (button)
	children [num_children++] = button;
    }

  /* Last entry is the help button.  This used be done after managing
     the buttons.  The comment claimed that it had to be done this way
     otherwise the menubar ended up only 4 pixels high.  That must
     have been in the Old World.  In the New World it stays the proper
     height if you don't manage them until after you set this and as a
     bonus the Help menu ends up where it is supposed to. */
  if (button)
    {
      ac = 0;
      XtSetArg (al [ac], XmNmenuHelpWidget, button); ac++;
      XtSetValues (widget, al, ac);
    }

  if (num_children)
    XtManageChildren (children, num_children);

  XtFree ((char *) children);
}

static void
update_one_menu_entry (widget_instance* instance, Widget widget,
		       widget_value* val, Boolean deep_p)
{
  Arg al [2];
  Widget menu;
  widget_value* contents;

  if (val->change == NO_CHANGE)
    return;

  /* update the sensitivity and userdata */
  /* Common to all widget types */
  XtSetArg (al [0], XmNsensitive, val->enabled);
  XtSetArg (al [1], XmNuserData,  val->call_data);
  XtSetValues (widget, al, 2);

  /* update the menu button as a label. */
  if (val->change >= VISIBLE_CHANGE)
    {
      xm_update_label (instance, widget, val);
      if (XtClass (widget) == xmToggleButtonWidgetClass
	  || XtClass (widget) == xmToggleButtonGadgetClass)
	{
	  xm_update_toggle (instance, widget, val);
	}
    }


  /* update the pulldown/pullaside as needed */
  menu = NULL;
  XtSetArg (al [0], XmNsubMenuId, &menu);
  XtGetValues (widget, al, 1);
  
  contents = val->contents;

  if (!menu)
    {
      if (contents)
	{
	  menu = XmCreatePulldownMenu (widget, "pulldown", NULL, 0);
	  make_menu_in_widget (instance, menu, contents);
	  ac = 0;
	  XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
	  XtSetValues (widget, al, ac);
	}
    }
  else if (!contents)
    {
      ac = 0;
      XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
      XtSetValues (widget, al, ac);
      XtDestroyWidget (menu);
    }
  else if (deep_p && contents->change != NO_CHANGE)
    xm_update_menu (instance, menu, val, 1);
}

static void
xm_update_menu (widget_instance* instance, Widget widget, widget_value* val,
		Boolean deep_p)
{
  /* Widget is a RowColumn widget whose contents have to be updated
   * to reflect the list of items in val->contents */
  if (val->contents->change == STRUCTURAL_CHANGE)
    {
      destroy_all_children (widget);
      make_menu_in_widget (instance, widget, val->contents);
    }
  else
    {
      /* Update all the buttons of the RowColumn in order. */
      Widget* children;
      unsigned int num_children;
      int i;
      widget_value *cur = 0;

      children = XtCompositeChildren (widget, &num_children);
      if (children)
	{
	  for (i = 0, cur = val->contents; i < num_children; i++)
	    {
	      if (!cur)
		abort ();
	      /* skip if this is a pushright marker or a separator */
	      if (cur->type == PUSHRIGHT_TYPE || cur->type == SEPARATOR_TYPE)
		{
		  cur = cur->next;
#if 0
		  /* #### - this could puke if you have a separator as the
		     last item on a pullright menu. */
		  if (!cur)
		    abort ();
#else
		  if (!cur)
		    continue;
#endif
		}
	      if (children [i]->core.being_destroyed
		  || strcmp (XtName (children [i]), cur->name))
		continue;
	      update_one_menu_entry (instance, children [i], cur, deep_p);
	      cur = cur->next;
	    }
	  XtFree ((char *) children);
	}
      if (cur)
	abort ();
    }
}

#endif /* MENUBARS_MOTIF */


#ifdef DIALOGS_MOTIF

/* update text widgets */

static void
xm_update_text (widget_instance* instance, Widget widget, widget_value* val)
{
  XmTextSetString (widget, val->value ? val->value : "");
  XtRemoveAllCallbacks (widget, XmNactivateCallback);
  XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
  XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
  XtAddCallback (widget, XmNvalueChangedCallback,
		 xm_internal_update_other_instances, instance);
}

static void
xm_update_text_field (widget_instance* instance, Widget widget,
		      widget_value* val)
{
  XmTextFieldSetString (widget, val->value ? val->value : "");
  XtRemoveAllCallbacks (widget, XmNactivateCallback);
  XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
  XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
  XtAddCallback (widget, XmNvalueChangedCallback,
		 xm_internal_update_other_instances, instance);
}

#endif /* DIALOGS_MOTIF */

#ifdef SCROLLBARS_MOTIF

/*
 * If this function looks like it does a lot more work than it needs to,
 * you're right.  Blame the Motif scrollbar for not being smart about
 * updating its appearance.
 */
static void
xm_update_scrollbar (widget_instance *instance, Widget widget,
		     widget_value *val)
{
  if (val->scrollbar_data)
    {
      scrollbar_values *data = val->scrollbar_data;
      int widget_sliderSize, widget_val;
      int new_sliderSize, new_value;
      double percent;
      double h_water, l_water;
      Arg al [4];

      /* First size and position the scrollbar widget. */
      XtSetArg (al [0], XtNx,      data->scrollbar_x);
      XtSetArg (al [1], XtNy,      data->scrollbar_y);
      XtSetArg (al [2], XtNwidth,  data->scrollbar_width);
      XtSetArg (al [3], XtNheight, data->scrollbar_height);
      XtSetValues (widget, al, 4);

      /* Now size the scrollbar's slider. */
      XtSetArg (al [0], XmNsliderSize, &widget_sliderSize);
      XtSetArg (al [1], XmNvalue,      &widget_val);
      XtGetValues (widget, al, 2);

      percent = (double) data->slider_size /
	(double) (data->maximum - data->minimum);
      new_sliderSize = (int) ((double) (INT_MAX - 1) * percent);

      percent = (double) (data->slider_position - data->minimum) /
	(double) (data->maximum - data->minimum);
      new_value = (int) ((double) (INT_MAX - 1) * percent);

      if (new_sliderSize > (INT_MAX - 1))
	new_sliderSize = INT_MAX - 1;
      else if (new_sliderSize < 1)
	new_sliderSize = 1;

      if (new_value > (INT_MAX - new_sliderSize))
	new_value = INT_MAX - new_sliderSize;
      else if (new_value < 1)
	new_value = 1;

      h_water = 1.05;
      l_water = 0.95;
      if (new_sliderSize != widget_sliderSize || new_value != widget_val)
	{
	  int force = ((INT_MAX - widget_sliderSize - widget_val)
		       ? 0
		       : (INT_MAX - new_sliderSize - new_value));

	  if (force
	      || (double)new_sliderSize < (l_water * (double)widget_sliderSize)
	      || (double)new_sliderSize > (h_water * (double)widget_sliderSize)
	      || (double)new_value < (l_water * (double)widget_val)
	      || (double)new_value > (h_water * (double)widget_val))
	    {
	      XmScrollBarSetValues (widget, new_value, new_sliderSize, 1, 1,
				    False);
	    }
	}
    }
}

#endif /* SCROLLBARS_MOTIF */


/* update a motif widget */

void
xm_update_one_widget (widget_instance* instance, Widget widget,
		      widget_value* val, Boolean deep_p)
{
  WidgetClass class;
  Arg al [2];
  
  /* Mark as not edited */
  val->edited = False;

  /* Common to all widget types */
  XtSetArg (al [0], XmNsensitive, val->enabled);
  XtSetArg (al [1], XmNuserData,  val->call_data);
  XtSetValues (widget, al, 2);

#if defined (DIALOGS_MOTIF) || defined (MENUBARS_MOTIF)
  /* Common to all label like widgets */
  if (XtIsSubclass (widget, xmLabelWidgetClass))
    xm_update_label (instance, widget, val);
#endif
  
  class = XtClass (widget);
  /* Class specific things */
  if (class == xmPushButtonWidgetClass ||
      class == xmArrowButtonWidgetClass)
    {
      xm_update_pushbutton (instance, widget, val);
    }