[comp.windows.x] HP's Xtk Fixes

fred@hpcvlx.HP.COM (Fred Taft) (08/20/88)

Earlier in the week, we posted a set of patches for bugs which HP had
fixed within their version of the toolkit intrinsics; these were fixes
which MIT had not yet officially blessed.  Unfortunately, the patches
which were posted were not context sensitive diffs.  So ... here are
the patches again, and this time they are context sensitive diffs.  Hope
these are of more use to people!


 - Fred Taft

fred@hpcvlx.HP.COM (Fred Taft) (08/20/88)

VERSION:
	Xtk release 2

SYNOPSIS:
	XtConvertStringToBoolean() does an incorrect variable
        cast.

DESCRIPTION:
        XtConvertStringToBoolean() miscasts a boolean pointer as an
        integer pointer, and thus extracts the wrong byte on 68000
        architectures. This shows up it you attempt to use the MenuPopup
        action exported by the translation manager.

REPEAT BY:
        Attempt to use the MenuPopup action; the shell does not get
        marked as sticky, and it does not get put on the grab list.

FIX:

*** TMstate.c	Fri Aug 19 12:40:40 1988
--- TMstate.new.c	Fri Aug 19 12:40:15 1988
***************
*** 1287,1293
      XtConvert((Widget) NULL, XtRString, &fromVal, XtRBoolean, &toVal);
      if (toVal.addr == NULL) return FALSE;
  
!     *bP = (Boolean) *(int *)toVal.addr;
  
      return TRUE;
  }

--- 1341,1347 -----
      XtConvert((Widget) NULL, XtRString, &fromVal, XtRBoolean, &toVal);
      if (toVal.addr == NULL) return FALSE;
  
!     *bP = *(Boolean *)toVal.addr;
  
      return TRUE;
  }

fred@hpcvlx.HP.COM (Fred Taft) (08/20/88)

VERSION:
	Xtk release 2

SYNOPSIS:
	CoreDestroy() should free up the memory occupied by the
        widget's destroy callback list.

DESCRIPTION:
        The CoreDestroy() routine fails to free up the memory occupied
        by a widget's destroy callback list, thus cause a memory leak.

REPEAT BY:
        Write a program which creates a bunch of widgets, and then adds
        destroy callbacks to each widget; then destroy the widgets.
        (Have the program repeat this several times). 

FIX:

*** Core.c	Fri Aug 19 11:26:00 1988
--- Core.new.c	Fri Aug 19 11:25:42 1988
***************
*** 289,294
  	if (win) XDestroyWindow(XtDisplay(widget), win);
      }
      if (widget->core.popup_list != NULL) XtFree(widget->core.popup_list);
      XtFree((char *) widget);
  } /* CoreDestroy */
  

--- 297,306 -----
  	if (win) XDestroyWindow(XtDisplay(widget), win);
      }
      if (widget->core.popup_list != NULL) XtFree(widget->core.popup_list);
+ 
+     /* Remove the destroy_callbacks list */
+     XtRemoveAllCallbacks(widget, XtNdestroyCallback);
+ 
      XtFree((char *) widget);
  } /* CoreDestroy */
  

fred@hpcvlx.HP.COM (Fred Taft) (08/20/88)

VERSION:
	Xtk release 2

SYNOPSIS:
	AddForwardingHandler() does not take window borders into
        consideration when checking if cursor is in a window.

DESCRIPTION:
	AddForwardingHandler(), which is part of the input focus
        mechanism within Xtk, does not take window borders into
        consideration when it checks to see if the cursor is already
        in the window to which the focus is being set.  This causes
        the widget to not get the initial FocusIn event, which is also
        generated by AddForwardingHandler().

FIX:

*** Event.c	Fri Aug 19 11:31:15 1988
--- Event.new.c	Fri Aug 19 11:30:57 1988
***************
*** 995,1000
      Boolean might_have_focus = False;
      Boolean had_focus_already = False;
      register XtEventHandler proc = ForwardEvent; /* compiler bug */
  
      /* %%%
         Until we implement a mechanism for propagating keyboard event

--- 995,1001 -----
      Boolean might_have_focus = False;
      Boolean had_focus_already = False;
      register XtEventHandler proc = ForwardEvent; /* compiler bug */
+     int	ul_x,lr_x,ul_y,lr_y;
  
      /* %%%
         Until we implement a mechanism for propagating keyboard event
***************
*** 1044,1051
  	XQueryPointer( XtDisplay(widget), XtWindow(widget),
  		       &root, &child, &root_x, &root_y,
  		       &win_x, &win_y, &mask );
! 	if (win_x >= 0 && win_x < widget->core.width &&
! 	    win_y >= 0 && win_y < widget->core.height) {
  	    had_focus_already = True;
  	}
      }

--- 1045,1064 -----
  	XQueryPointer( XtDisplay(widget), XtWindow(widget),
  		       &root, &child, &root_x, &root_y,
  		       &win_x, &win_y, &mask );
! 
! 	/*
! 	 * The work vars are necessary because the core height
! 	 * and width fields are unsigned, and win_x and win_y
! 	 * may be negative; if they are, then the comparison can
! 	 * fail when it shouldn't. Also, border width needs to
! 	 * be considered.
!   	 */
! 	ul_x = (int ) (0 - widget->core.border_width);
! 	ul_y = (int ) (0 - widget->core.border_width);
! 	lr_x = (int ) (widget->core.width - (widget->core.border_width << 1));
! 	lr_y = (int ) (widget->core.height - (widget->core.border_width << 1));
! 	if ((win_x >= ul_x) && (win_x < lr_x) &&
! 	    (win_y >= ul_y) && (win_y < lr_y)) {
  	    had_focus_already = True;
  	}
      }

fred@hpcvlx.HP.COM (Fred Taft) (08/20/88)

VERSION:
	Xtk release 2

SYNOPSIS:
	Using XtParseTranslationTable() causes a program to grow without
        an upper bound.

DESCRIPTION:
        XtParseTranslationTable() returns a pointer to a translation
        state table, which in turn contains potentially many other
        pointers to blocks of memory (state records, action records, etc).
        Unfortunately, the toolkit does not provide a mechanism for 
        freeing up this memory once an application is done with it.

        It appears that the reason the memory is not freed up is because
        the toolkit caches these parsed translation table, thus
        potentially saving time (and space) if the same translation
        is ever parsed again.  However, our widget set parses many 
        (possibly 100 or more, depending upon what widgets you use),
        and each of the translation tables are unique.  
    
        If an application, such as a window manager, is creating and 
        destroying alot of widgets, it's size continues to grow because 
        all of these state tables are cached, but never used again after 
        the associated widget is destroyed.

        The patches which follow affect the following files:

           1) TMstate.c - Added XtDestroyStateTable(), which frees up
                       a translation state table and all underlying
                       malloc memory.

                       Modified MergeStates() to create new copies
                       of the parameter strings and array of string
                       pointers, rather than just copying the existing
                       pointers.

                       Removed the caching of the parsed event state
                       tables in XtOverrideTranslations and
                       XtAugmentTranslations.

                       Added a call to XtDestroyStateTable() in both
                       XtOverrideTranslations and XtAugmentTranslations,
                       to free up the widgets old translation state table.

           2) TMparse.c - Removed the caching of the parsed event state
                       table in XtParseTranslationTable().

           3) Core.c - Added a call to XtDestroyStateTable() in
                       CoreDestroy(), to free up the widgets state
                       table.

REPEAT-BY:
        Have a program which parses several unique translation tables,
        and watch the size of the program grow.

FIX:

*** Core.c	Fri Aug 19 11:26:00 1988
--- Core.new.c	Fri Aug 19 11:25:42 1988
***************
*** 277,282
      }
      XtFree((char *) widget->core.tm.proc_table);
      _XtUnregisterWindow(widget->core.window, widget);
      if (widget->core.constraints != NULL)
  	XtFree((char *) widget->core.constraints);
      for (i = 0; i < widget->core.num_popups; i++) {

--- 277,290 -----
      }
      XtFree((char *) widget->core.tm.proc_table);
      _XtUnregisterWindow(widget->core.window, widget);
+ 
+ 
+     /*  Destroy the translation state table  */
+ 
+     XtDestroyStateTable (widget->core.widget_class, 
+                          widget->core.tm.translations);
+ 
+ 
      if (widget->core.constraints != NULL)
  	XtFree((char *) widget->core.constraints);
      for (i = 0; i < widget->core.num_popups; i++) {
  
*** TMparse.c	Fri Aug 19 11:34:09 1988
--- TMparse.new.c	Fri Aug 19 11:33:50 1988
***************
*** 1418,1423
  XtTranslations XtParseTranslationTable(source)
      String source;
  {
      XrmValue from,to;
      from.addr = source;
      from.size = strlen(source)+1;

--- 1418,1424 -----
  XtTranslations XtParseTranslationTable(source)
      String source;
  {
+     int noArgs = 0;
      XrmValue from,to;
      from.addr = source;
      from.size = strlen(source)+1;
***************
*** 1421,1426
      XrmValue from,to;
      from.addr = source;
      from.size = strlen(source)+1;
      XtDirectConvert((XtConverter) _CompileTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
      return (*(XtTranslations*)(to.addr));

--- 1422,1431 -----
      XrmValue from,to;
      from.addr = source;
      from.size = strlen(source)+1;
+     to.addr = NULL;
+     to.size = 0;
+     _CompileTranslations (NULL, &noArgs, &from, &to);
+ /*
      XtDirectConvert((XtConverter) _CompileTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
  */
***************
*** 1423,1428
      from.size = strlen(source)+1;
      XtDirectConvert((XtConverter) _CompileTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
      return (*(XtTranslations*)(to.addr));
  
  }

--- 1428,1434 -----
  /*
      XtDirectConvert((XtConverter) _CompileTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
+ */
      return (*(XtTranslations*)(to.addr));
  
  }

*** TMstate.c	Fri Aug 19 11:40:59 1988
--- TMstate.new.c	Fri Aug 19 11:40:31 1988
***************
*** 39,44
  #include "TMprivate.h"
  #include <X11/Convert.h>
  
  
  #define StringToAction(string)	((XtAction) StringToQuark(string))
  

--- 38,47 -----
  #include "TMprivate.h"
  #include <X11/Convert.h>
  
+ typedef struct _DestroyListEntry {
+    XtTranslations      stateTable;
+    struct _DestroyListEntry * next;
+ } DestroyListEntry;
  
  /* List of state tables waiting to be destroyed */
  static DestroyListEntry * st_destroy_list = NULL;
***************
*** 40,45
  #include <X11/Convert.h>
  
  
  #define StringToAction(string)	((XtAction) StringToQuark(string))
  
  static void FreeActions(action)

--- 43,55 -----
     struct _DestroyListEntry * next;
  } DestroyListEntry;
  
+ /* List of state tables waiting to be destroyed */
+ static DestroyListEntry * st_destroy_list = NULL;
+ static int entryCount = 0;
+ static Boolean safe = FALSE;
+ static _DestroyStateTable();
+ 
+ 
  #define StringToAction(string)	((XtAction) StringToQuark(string))
  
  static void FreeActions(action)
***************
*** 332,338
      EventRec curEvent;
      StatePtr current_state = ((TMRec*)closure)->current_state;
      int     index;
!     register ActionPtr actions;
      XtActionProc* proc_table = ((TMRec*)closure)->proc_table;
      TMRec* tm = (TMRec*)closure;
  /* gross disgusting special case ||| */

--- 342,348 -----
      EventRec curEvent;
      StatePtr current_state = ((TMRec*)closure)->current_state;
      int     index;
!     register ActionPtr actions, nextAction;
      XtActionProc* proc_table = ((TMRec*)closure)->proc_table;
      TMRec* tm = (TMRec*)closure;
  /* gross disgusting special case ||| */
***************
*** 340,345
          && event->xcrossing.detail == NotifyInferior)
  	return;
  
      XEventToTMEvent (event, &curEvent);
  
  #ifdef notdef

--- 350,357 -----
          && event->xcrossing.detail == NotifyInferior)
  	return;
  
+     entryCount++;
+ 
      XEventToTMEvent (event, &curEvent);
  
  #ifdef notdef
***************
*** 360,365
  
      index = MatchEvent (stateTable, &curEvent);
      if (index == -1)
  	/* some event came in that we don't have any states for */
  	/* ignore it. */
  	return;

--- 372,378 -----
  
      index = MatchEvent (stateTable, &curEvent);
      if (index == -1)
+     {
  	/* some event came in that we don't have any states for */
  	/* ignore it. */
          entryCount--;
***************
*** 362,367
      if (index == -1)
  	/* some event came in that we don't have any states for */
  	/* ignore it. */
  	return;
  
      /* are we currently in some state other than ground? */

--- 375,381 -----
      {
  	/* some event came in that we don't have any states for */
  	/* ignore it. */
+         entryCount--;
  	return;
      }
  
***************
*** 363,368
  	/* some event came in that we don't have any states for */
  	/* ignore it. */
  	return;
  
      /* are we currently in some state other than ground? */
      if (current_state != NULL) {

--- 377,383 -----
  	/* ignore it. */
          entryCount--;
  	return;
+     }
  
      /* are we currently in some state other than ground? */
      if (current_state != NULL) {
***************
*** 404,409
  	    if (Ignore(&curEvent)) {
  		/* ignore it. */
  	        current_state = oldState;
  		return;
  	    } /* do ground state */
      }

--- 419,425 -----
  	    if (Ignore(&curEvent)) {
  		/* ignore it. */
  	        current_state = oldState;
+                 entryCount--;
  		return;
  	    } /* do ground state */
      }
***************
*** 411,417
      if (current_state == NULL) {
  	/* check ground level */
  	current_state = stateTable->eventObjTbl[index].state;
! 	if (current_state == NULL) return;
      }
  
      tm->lastEventTime = GetTime (tm, event);

--- 427,437 -----
      if (current_state == NULL) {
  	/* check ground level */
  	current_state = stateTable->eventObjTbl[index].state;
! 	if (current_state == NULL) 
!         {
!            entryCount--;
!            return;
!         }
      }
  
      tm->lastEventTime = GetTime (tm, event);
***************
*** 419,427
      /* perform any actions */
      actions = current_state->actions;
      while (actions != NULL) {
! 	/* perform any actions */
!      if (proc_table[actions->index] != NULL)
!         (*(proc_table[actions->index]))(
  		w, event, actions->params, &actions->num_params);
  	actions = actions->next;
      }

--- 439,455 -----
      /* perform any actions */
      actions = current_state->actions;
      while (actions != NULL) {
!        nextAction = actions->next;
! 
!        /* Flag used during destroy of state tables */
!        if (nextAction == NULL)
!           safe = TRUE;
!        else
!           safe = FALSE;
! 
!        /* perform any actions */
!        if (proc_table[actions->index] != NULL)
!           (*(proc_table[actions->index]))(
  		w, event, actions->params, &actions->num_params);
  
         actions = nextAction;
***************
*** 423,429
       if (proc_table[actions->index] != NULL)
          (*(proc_table[actions->index]))(
  		w, event, actions->params, &actions->num_params);
! 	actions = actions->next;
      }
  
      /* move into successor state */

--- 451,458 -----
         if (proc_table[actions->index] != NULL)
            (*(proc_table[actions->index]))(
  		w, event, actions->params, &actions->num_params);
! 
!        actions = nextAction;
      }
  
      /*
***************
*** 426,433
  	actions = actions->next;
      }
  
!     /* move into successor state */
!     ((TMRec*)tm)->current_state = current_state->nextLevel;
  }
  
  static Boolean EqualEvents(event1, event2)

--- 455,486 -----
         actions = nextAction;
      }
  
!     /*
!      * If the state table for this widget has changed, then we
!      * need to drop back to the ground level, and start over.
!      */
!     if (stateTable != tm->translations)
!        ((TMRec*)tm)->current_state = NULL;
!     else
!        /* move into successor state */
!        ((TMRec*)tm)->current_state = current_state->nextLevel;
! 
!     entryCount--;
!     if ((entryCount == 0) && st_destroy_list)
!     {
!        /* It is now safe to destroy any state tables on the destroy list */
!        DestroyListEntry * current, * next;
! 
!        current = st_destroy_list;
!        while (current)
!        {
!           next = current->next;
!           _DestroyStateTable(current->stateTable);
!           XtFree(current);
!           current = next;
!        }
!        st_destroy_list = NULL;
!     }
  }
  
  static Boolean EqualEvents(event1, event2)
***************
*** 863,868
      register StatePtr state;
      StateMap oldStateMap = stateMap;
      ActionRec *a,**aa,*b;
  
      while (new != NULL) {
  	register int index = indexMap[new->index];

--- 916,922 -----
      register StatePtr state;
      StateMap oldStateMap = stateMap;
      ActionRec *a,**aa,*b;
+     register int i;
  
      while (new != NULL) {
  	register int index = indexMap[new->index];
***************
*** 902,908
             a = XtNew(ActionRec); 
             a->token = NULL;
             a->index = quarkIndexMap[b->index];
!            a->params = b->params;
             a->num_params=b->num_params;
             a->next = NULL;
             *aa = a;

--- 956,964 -----
             a = XtNew(ActionRec); 
             a->token = NULL;
             a->index = quarkIndexMap[b->index];
! 
! 
! /*         a->params = b->params;   */
             a->num_params=b->num_params;
             if (a->num_params > 0)
                a->params = (char **) XtMalloc (sizeof (char *) * b->num_params);
***************
*** 904,909
             a->index = quarkIndexMap[b->index];
             a->params = b->params;
             a->num_params=b->num_params;
             a->next = NULL;
             *aa = a;
             aa = &a->next;

--- 960,975 -----
  
  /*         a->params = b->params;   */
             a->num_params=b->num_params;
+            if (a->num_params > 0)
+               a->params = (char **) XtMalloc (sizeof (char *) * b->num_params);
+            else
+               a->params = NULL;
+            for (i = 0; i < b->num_params; i++)
+            {
+               a->params[i] = (char *) XtMalloc (strlen (b->params[i]) + 1);
+               strcpy (a->params[i], b->params[i]);
+            }
+ 
             a->next = NULL;
             *aa = a;
             aa = &a->next;
***************
*** 1080,1085
      Cardinal  numQuarks = 0;
      XrmValue from,to;
      TMConvertRec foo;
  
      from.addr = (caddr_t)&foo;
      from.size = sizeof(TMConvertRec);

--- 1146,1152 -----
      Cardinal  numQuarks = 0;
      XrmValue from,to;
      TMConvertRec foo;
+     int noArgs = 0;
  
      from.addr = (caddr_t)&foo;
      from.size = sizeof(TMConvertRec);
***************
*** 1090,1095
      if (widget->core.tm.translations != NULL)
        numQuarks = widget->core.tm.translations->numQuarks;
  
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
  

--- 1157,1164 -----
      if (widget->core.tm.translations != NULL)
        numQuarks = widget->core.tm.translations->numQuarks;
  
+     _MergeTranslations (NULL, &noArgs, &from, &to);
+ /*
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
  */
***************
*** 1092,1097
  
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
  
      widget->core.tm.translations =(*(XtTranslations*)to.addr);
  

--- 1161,1167 -----
  /*
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
+ */
  
  
      /*  Destroy the translation state table  */
***************
*** 1093,1098
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
  
      widget->core.tm.translations =(*(XtTranslations*)to.addr);
  
      if (XtIsRealized(widget))

--- 1163,1175 -----
  	    0, &from, &to);
  */
  
+ 
+     /*  Destroy the translation state table  */
+ 
+     XtDestroyStateTable (widget->core.widget_class, 
+                          widget->core.tm.translations);
+ 
+ 
      widget->core.tm.translations =(*(XtTranslations*)to.addr);
  
      if (XtIsRealized(widget))
***************
*** 1134,1139
      Cardinal  numQuarks = 0;
      XrmValue from,to;
      TMConvertRec foo;
  
      from.addr = (caddr_t)&foo;
      from.size = sizeof(TMConvertRec);

--- 1211,1217 -----
      Cardinal  numQuarks = 0;
      XrmValue from,to;
      TMConvertRec foo;
+     int noArgs = 0;
  
      from.addr = (caddr_t)&foo;
      from.size = sizeof(TMConvertRec);
***************
*** 1144,1149
      if (widget->core.tm.translations != NULL)
        numQuarks = widget->core.tm.translations->numQuarks;
  
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
  

--- 1222,1229 -----
      if (widget->core.tm.translations != NULL)
        numQuarks = widget->core.tm.translations->numQuarks;
  
+     _MergeTranslations (NULL, &noArgs, &from, &to);
+ /*
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
  */
***************
*** 1146,1151
  
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
  
      widget->core.tm.translations = (*(XtTranslations*)to.addr);
  

--- 1226,1232 -----
  /*
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
+ */
  
  
      /*  Destroy the translation state table  */
***************
*** 1147,1152
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
  
      widget->core.tm.translations = (*(XtTranslations*)to.addr);
  
      if (XtIsRealized(widget)) 

--- 1228,1240 -----
  	    0, &from, &to);
  */
  
+ 
+     /*  Destroy the translation state table  */
+ 
+     XtDestroyStateTable (widget->core.widget_class, 
+                          widget->core.tm.translations);
+ 
+ 
      widget->core.tm.translations = (*(XtTranslations*)to.addr);
  
      if (XtIsRealized(widget)) 
***************
*** 1415,1417
  
  
  void _XtPopupInitialize() { XtAddActions(tmActions, XtNumber(tmActions)); }

--- 1503,1568 -----
  
  
  void _XtPopupInitialize() { XtAddActions(tmActions, XtNumber(tmActions)); }
+ 
+ 
+ /*  HP added translation state table deallocation procedure.  */
+ /*  This is used by both toolkit functions and widgets to     */
+ /*  eliminate a huge memory whole.                            */
+ 
+ XtDestroyStateTable (class, stateTable)
+ 
+    WidgetClass    class;
+    XtTranslations stateTable;
+ 
+ {
+    register StatePtr  state, nextState;
+    register ActionPtr action, nextAction;
+ 
+    /* Don't do anything if the state table is the widget class's state table */
+    if (stateTable && (stateTable != (XtTranslations)class->core_class.tm_table))
+    {
+       if ((entryCount == 0) || safe)
+       {
+          _DestroyStateTable(stateTable);
+       }
+       else
+       {
+          DestroyListEntry * new;
+ 
+          new = XtNew(DestroyListEntry);
+          new->next = st_destroy_list;
+          new->stateTable = stateTable;
+          st_destroy_list = new;
+       }
+    }
+ }
+ 
+ 
+ static _DestroyStateTable (stateTable)
+ 
+    XtTranslations stateTable;
+ 
+ {
+    register StatePtr  state, nextState;
+    register ActionPtr action, nextAction;
+ 
+    /* Free up each state record and all associated action records */
+    for (state = stateTable->head; state != NULL; )
+    {
+       for (action = state->actions; action != NULL; )
+       {
+          nextAction = action->next;
+          FreeActions(action);
+          action = nextAction;
+       }
+ 
+       nextState = state->forw;
+       XtFree(state);
+       state = nextState;
+    }
+ 
+    /* Free up quark Table, event object array and the state table */
+    XtFree(stateTable->quarkTable);
+    XtFree(stateTable->eventObjTbl);
+    XtFree(stateTable);
+ }

fred@hpcvlx.HP.COM (Fred Taft) (08/20/88)

### bug number:   649
### area:         Xt
### severity:     low
### comments:     

VERSION:
	X Window System, Version 11, Release 2

AREA:
	Xt

SYNOPSIS:
	XtNameToWidget fails on primitives with popup children

DESCRIPTION:
	The XtNameToWidget function that translates a widget name 
        to a widget instance doesn't take into account a primitive 
        widget with popup childrens. This is used, for instance, with 
        the HP Widget set when using their menu manager, menu panels, etc...  

	Is the "if (!XtIsComposite(root)) return NULL;" to strong in 
        NameListToWidget?

FIX:

*** Intrinsic.c	Fri Aug 19 12:13:12 1988
--- Intrinsic.new.c	Fri Aug 19 12:12:57 1988
***************
*** 249,255
  
      name = *names;
      if (name == NULLQUARK) return root;
-     if (! XtIsComposite(root)) return NULL;
  
      children = ((CompositeWidget) root)->composite.children;
      for (i = 0; i < ((CompositeWidget) root)->composite.num_children; i++) {

--- 249,254 -----
  
      name = *names;
      if (name == NULLQUARK) return root;
  
      /* Check normal children only if this is a composite widget */
      if (XtIsComposite(root))
***************
*** 251,260
      if (name == NULLQUARK) return root;
      if (! XtIsComposite(root)) return NULL;
  
!     children = ((CompositeWidget) root)->composite.children;
!     for (i = 0; i < ((CompositeWidget) root)->composite.num_children; i++) {
! 	if (name == children[i]->core.xrm_name)
! 	    return NameListToWidget(children[i], &names[1]);
      }
      children = root->core.popup_list;
      for (i = 0; i < root->core.num_popups; i++) {

--- 250,263 -----
      name = *names;
      if (name == NULLQUARK) return root;
  
!     /* Check normal children only if this is a composite widget */
!     if (XtIsComposite(root))
!     {
!        children = ((CompositeWidget) root)->composite.children;
!        for (i = 0; i < ((CompositeWidget) root)->composite.num_children; i++) {
! 	   if (name == children[i]->core.xrm_name)
! 	       return NameListToWidget(children[i], &names[1]);
!        }
      }
  
      /* Even non-composite widgets may have popup children */
***************
*** 256,261
  	if (name == children[i]->core.xrm_name)
  	    return NameListToWidget(children[i], &names[1]);
      }
      children = root->core.popup_list;
      for (i = 0; i < root->core.num_popups; i++) {
  	if (name == children[i]->core.xrm_name)

--- 259,266 -----
  	       return NameListToWidget(children[i], &names[1]);
         }
      }
+ 
+     /* Even non-composite widgets may have popup children */
      children = root->core.popup_list;
      for (i = 0; i < root->core.num_popups; i++) {
  	if (name == children[i]->core.xrm_name)

fred@hpcvlx.HP.COM (Fred Taft) (08/20/88)

### bug number:   363
### area:         Xt
### severity:     
### assigned to:  swick
### status:       open
### comments:     


VERSION:
	Xtk release 2

SYNOPSIS:
        Adding a global translation to a realized widget destroys the
        widget's translations.

DESCRIPTION:
	As I reported in an earlier bug report, if a new translation is
        added to a realized widget (using XtOverrideTranslation), and the
        action to which the translation is tied has not been previously used
        for that widget, all of the translations for that widget get
        destroyed.

REPEAT-BY:
        Register a global action routine, and set up a translation for a
        realized widget which uses this action.

FIX:
        There were actually several problems in the translation
        manager which contributed to this problem.  They include:

        1) After the first time a widget's translations were bound, the
           proc_table size was never again changed; even if future translations
           referenced different action routines.

        2) After an augment or override request, the translations were not
           really being rebound; this is a result of the table being the
           wrong size and the fact that only NULL table entries are bound,
           and none of the entries had been NULL'ed out.

        3) The old event handler for the widget was not removed.

        4) The new translations were never installed.
        
*************************** diffs start here *******************************

*** TMstate.c	Fri Aug 19 12:19:50 1988
--- TMstate.new.c	Fri Aug 19 12:18:02 1988
***************
*** 725,730
  if (tm->proc_table == NULL) 
      tm->proc_table= (XtActionProc*) XtCalloc(
                        stateTable->numQuarks,sizeof(XtActionProc));
  do {
  /* ||| */
      class = w->core.widget_class;

--- 725,731 -----
  if (tm->proc_table == NULL) 
      tm->proc_table= (XtActionProc*) XtCalloc(
                        stateTable->numQuarks,sizeof(XtActionProc));
+ 
  do {
  /* ||| */
      class = w->core.widget_class;
***************
*** 1040,1046
      /* merge in extra bindings, keeping old binding if any */
      XtTranslations temp;
      _XtInitializeStateTable(&temp);
!     temp->clickTime = old->clickTime;
      MergeTables(temp, old, FALSE);
      MergeTables(temp, new, FALSE);
      *merged= temp;

--- 1041,1048 -----
      /* merge in extra bindings, keeping old binding if any */
      XtTranslations temp;
      _XtInitializeStateTable(&temp);
!     if (old != NULL)
! 	temp->clickTime = old->clickTime;
      MergeTables(temp, old, FALSE);
      MergeTables(temp, new, FALSE);
      *merged= temp;
***************
*** 1075,1084
      Widget widget;
      XtTranslations new;
  {
! /*
!     MergeTables(widget->core.translations, new, TRUE);
! */
!      Cardinal  numQuarks =0;
      XrmValue from,to;
      TMConvertRec foo;
      from.addr = (caddr_t)&foo;

--- 1077,1083 -----
      Widget widget;
      XtTranslations new;
  {
!     Cardinal  numQuarks = 0;
      XrmValue from,to;
      TMConvertRec foo;
  
***************
*** 1081,1086
       Cardinal  numQuarks =0;
      XrmValue from,to;
      TMConvertRec foo;
      from.addr = (caddr_t)&foo;
      from.size = sizeof(TMConvertRec);
      foo.old = widget->core.tm.translations;

--- 1080,1086 -----
      Cardinal  numQuarks = 0;
      XrmValue from,to;
      TMConvertRec foo;
+ 
      from.addr = (caddr_t)&foo;
      from.size = sizeof(TMConvertRec);
      foo.old = widget->core.tm.translations;
***************
*** 1086,1092
      foo.old = widget->core.tm.translations;
      foo.new = new;
      foo.operation = override;
!      if (widget->core.tm.translations != NULL)
        numQuarks = widget->core.tm.translations->numQuarks;
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);

--- 1086,1093 -----
      foo.old = widget->core.tm.translations;
      foo.new = new;
      foo.operation = override;
! 
!     if (widget->core.tm.translations != NULL)
        numQuarks = widget->core.tm.translations->numQuarks;
  
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
***************
*** 1088,1093
      foo.operation = override;
       if (widget->core.tm.translations != NULL)
        numQuarks = widget->core.tm.translations->numQuarks;
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
  /*    _XtOverrideTranslations(widget->core.tm.translations, new);*/

--- 1089,1095 -----
  
      if (widget->core.tm.translations != NULL)
        numQuarks = widget->core.tm.translations->numQuarks;
+ 
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
  
***************
*** 1090,1100
        numQuarks = widget->core.tm.translations->numQuarks;
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
! /*    _XtOverrideTranslations(widget->core.tm.translations, new);*/
!       widget->core.tm.translations =(*(XtTranslations*)to.addr);
!      if (XtIsRealized(widget))
!         _XtBindActions(widget,&widget->core.tm,numQuarks);
!         
  }
  
  void XtAugmentTranslations(widget, new)

--- 1092,1130 -----
  
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
! 
!     widget->core.tm.translations =(*(XtTranslations*)to.addr);
! 
!     if (XtIsRealized(widget))
!     {
!         int i;
! 
!         if (numQuarks != widget->core.tm.translations->numQuarks)
!         {
!            widget->core.tm.proc_table= (XtActionProc*) XtRealloc(
!                widget->core.tm.proc_table,
!                widget->core.tm.translations->numQuarks * sizeof(XtActionProc));
!         }
! 
!         /*
!          * Since the old table was merged into the new table,
!          * we need to force all translations to be rebound; this
!          * is because the indices into the proc_table have changed,
!          * and duplicate actions will have been removed by MergeTables().
!          */
!         for (i=0; i < widget->core.tm.translations->numQuarks; i++)
!            widget->core.tm.proc_table[i] = 0;
! 
!         /*
!          * Bind the new actions (rebind the old actions); we must
!          * also remove the old event handler, and then install the
!          * new set of translations.
!          */
!         _XtBindActions(widget, &widget->core.tm, 0);
!         XtRemoveEventHandler (widget, XtAllEvents, True, _XtTranslateEvent,
!                               (caddr_t)&widget->core.tm);
!         _XtInstallTranslations (widget, widget->core.tm.translations);
!     }
  }
  
  void XtAugmentTranslations(widget, new)
***************
*** 1101,1107
      Widget widget;
      XtTranslations new;
  {
!     Cardinal  numQuarks =0;
      XrmValue from,to;
      TMConvertRec foo;
      from.addr = (caddr_t)&foo;

--- 1131,1137 -----
      Widget widget;
      XtTranslations new;
  {
!     Cardinal  numQuarks = 0;
      XrmValue from,to;
      TMConvertRec foo;
  
***************
*** 1104,1109
      Cardinal  numQuarks =0;
      XrmValue from,to;
      TMConvertRec foo;
      from.addr = (caddr_t)&foo;
      from.size = sizeof(TMConvertRec);
      foo.old = widget->core.tm.translations;

--- 1134,1140 -----
      Cardinal  numQuarks = 0;
      XrmValue from,to;
      TMConvertRec foo;
+ 
      from.addr = (caddr_t)&foo;
      from.size = sizeof(TMConvertRec);
      foo.old = widget->core.tm.translations;
***************
*** 1109,1115
      foo.old = widget->core.tm.translations;
      foo.new = new;
      foo.operation = augment;
!      if (widget->core.tm.translations != NULL)
        numQuarks = widget->core.tm.translations->numQuarks;
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);

--- 1140,1147 -----
      foo.old = widget->core.tm.translations;
      foo.new = new;
      foo.operation = augment;
! 
!     if (widget->core.tm.translations != NULL)
        numQuarks = widget->core.tm.translations->numQuarks;
  
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
***************
*** 1111,1116
      foo.operation = augment;
       if (widget->core.tm.translations != NULL)
        numQuarks = widget->core.tm.translations->numQuarks;
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
  /*    _XtAugmentTranslations(widget->core.tm.translations, new);*/

--- 1143,1149 -----
  
      if (widget->core.tm.translations != NULL)
        numQuarks = widget->core.tm.translations->numQuarks;
+ 
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
  
***************
*** 1113,1122
        numQuarks = widget->core.tm.translations->numQuarks;
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
- /*    _XtAugmentTranslations(widget->core.tm.translations, new);*/
-      widget->core.tm.translations = (*(XtTranslations*)to.addr);
-      if (XtIsRealized(widget)) 
-         _XtBindActions(widget,&widget->core.tm,numQuarks);
  
  }
  

--- 1146,1151 -----
  
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
  
      widget->core.tm.translations = (*(XtTranslations*)to.addr);
  
***************
*** 1118,1123
       if (XtIsRealized(widget)) 
          _XtBindActions(widget,&widget->core.tm,numQuarks);
  
  }
  
  static void PrintState(start, str, state, quarkTable, eot)

--- 1147,1184 -----
      XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL,
  	    0, &from, &to);
  
+     widget->core.tm.translations = (*(XtTranslations*)to.addr);
+ 
+     if (XtIsRealized(widget)) 
+     {
+         int i;
+ 
+         if (numQuarks != widget->core.tm.translations->numQuarks)
+         {
+            widget->core.tm.proc_table= (XtActionProc*) XtRealloc(
+                widget->core.tm.proc_table,
+                widget->core.tm.translations->numQuarks * sizeof(XtActionProc));
+         }
+ 
+         /* Force all entries to be bound (see note below) */
+         for (i = 0; i < widget->core.tm.translations->numQuarks; i++)
+            widget->core.tm.proc_table[i] = 0;
+ 
+         /*
+          * Bind the new actions and all existing actions; we must rebind
+          * the old actions because MergeTables() may have compressed the
+          * proc_table, and we thus no longer know where the new entries
+          * start (This really is caused by a bug in ParseActionSeq(),
+          * which doesn't check to see if an action already has an entry
+          * in the proc_table; thus, an action can initially appear more
+          * than once).  We must also remove the old event handler, 
+          * and then install the new set of translations.
+          */
+         _XtBindActions(widget, &widget->core.tm, 0);
+         XtRemoveEventHandler (widget, XtAllEvents, True, _XtTranslateEvent,
+                               (caddr_t)&widget->core.tm);
+         _XtInstallTranslations (widget, widget->core.tm.translations);
+     }
  }
  
  static void PrintState(start, str, state, quarkTable, eot)

fred@hpcvlx.HP.COM (Fred Taft) (08/20/88)

### bug number:   549
### area:         Xt
### severity:     low
### comments:     


VERSION:
	Xtk Release 2

SYNOPSIS:
	Xtk will not allow a widget (during its phase 2 destroy) to destroy
      another, unrelated, widget.

DESCRIPTION:
	As XtNextEvent() currently implements the second phase of the destory
      process, it is not possible for a widget being destroyed to in turn
      initiate a destroy on another, unrelated widget (using XtDestroyWidget()).

      The problem arises because XtNextEvent() takes the current DestroyList,
      performs all of the callbacks, and then NULLs out the DestroyList; any
      new entries on the DestroyList are lost.

REPEAT-BY:
      Destroy a widget whose Destroy routine then attempts to destroy another
      widget.
	
FIX:

*** NextEvent.c	Fri Aug 19 12:23:57 1988
--- NextEvent.new.c	Fri Aug 19 12:23:41 1988
***************
*** 437,445
      struct timezone cur_timezone;
      register Boolean     Claims_X_is_pending = FALSE;
  
!     if (DestroyList != NULL) {
! 	_XtCallCallbacks (&DestroyList, (caddr_t) NULL);
! 	_XtRemoveAllCallbacks (&DestroyList);
      }
  
      for (;;) {

--- 437,448 -----
      struct timezone cur_timezone;
      register Boolean     Claims_X_is_pending = FALSE;
  
!     while (DestroyList != NULL) {
!         CallbackList currentList = DestroyList;
! 
!         DestroyList = NULL;
! 	_XtCallCallbacks (&currentList, (caddr_t) NULL);
! 	_XtRemoveAllCallbacks (&currentList);
      }
  
      for (;;) {

fred@hpcvlx.HP.COM (Fred Taft) (08/20/88)

### bug number:   420
### area:         Xt
### severity:     medium
### comments:     workaround: don't reuse these resources


VERSION:
	Xtk release 2

SYNOPSIS:
	CoreDestroy() frees up resources owned by the application

DESCRIPTION:
	When a widget is destroyed, the CoreDestroy() routine frees up
        the background pixmap and the border pixmap, if they are defined.
        Unfortunately, these resource were owned by the application; the
        intrinsics had not ever made their own private copy.  The next
        time the application tries to use that pixmap, an X Error occurs.

REPEAT-BY:
	Create a widget and assign a background pixmap.
        Destroy the widget.
        Create a second widget using the same background pixmap.
        An X Error occurs.

FIX:

*** Core.c	Fri Aug 19 12:25:31 1988
--- Core.new.c	Fri Aug 19 12:25:26 1988
***************
*** 261,266
  
      if (*widget->core.name != '\0') /* special case; we didn't copy this */
  	XtFree((char *) (widget->core.name));
      if (widget->core.background_pixmap > UnspecifiedPixmap)
  	XFreePixmap(XtDisplay(widget), widget->core.background_pixmap);
      if (widget->core.border_pixmap > UnspecifiedPixmap)

--- 261,268 -----
  
      if (*widget->core.name != '\0') /* special case; we didn't copy this */
  	XtFree((char *) (widget->core.name));
+ /*
+     DON'T FREE UP RESOURCES WE DID NOT ALLOCATE!!!!
      if (widget->core.background_pixmap > UnspecifiedPixmap)
  	XFreePixmap(XtDisplay(widget), widget->core.background_pixmap);
      if (widget->core.border_pixmap > UnspecifiedPixmap)
***************
*** 265,270
  	XFreePixmap(XtDisplay(widget), widget->core.background_pixmap);
      if (widget->core.border_pixmap > UnspecifiedPixmap)
  	XFreePixmap(XtDisplay(widget), widget->core.border_pixmap);
      event = widget->core.event_table;
      while (event != NULL) {
  	next = event->next;

--- 267,273 -----
  	XFreePixmap(XtDisplay(widget), widget->core.background_pixmap);
      if (widget->core.border_pixmap > UnspecifiedPixmap)
  	XFreePixmap(XtDisplay(widget), widget->core.border_pixmap);
+ */
      event = widget->core.event_table;
      while (event != NULL) {
  	next = event->next;

fred@hpcvlx.HP.COM (Fred Taft) (08/20/88)

### bug number:   518
### area:         Xt
### severity:     low
### comments:     


VERSION:
	Xtk release 2

SYNOPSIS:
	Under certain conditions, it is possible for a widget to have 
        more than one keyboard focus entry on the grablist, when in fact
        only one should have been present.

DESCRIPTION:
	The current implementation of the input focus for Xtk enforces the
        rule that if a widget has a non-focus entry on the grab list, then
        a focus entry for that widget will always be placed after the
        non-focus entry.  Unfortunately, there are bugs in the current
        implementation, which may cause this rule to be broken.  Additionally,
        the current implementation looks on the grab list for an existing 
        focus entry before adding a new one; if an existing one is found,
        then it is replaced - you don't end up with duplicate focus entries
        for a widget; again, there is a bug which causes duplicate entries
        to be placed on the grablist.

        When a focus grab is to be added to the grablist, the current
        implementation searches the grab list to see if there is already
        a grab entry for this widget.  If there is, and the current entry
        is a non-focus entry, then it simply adds the focus entry after
        the non-focus entry; unfortunately, if there was already a focus
        entry after the non-focus entry, you now end up with 2 (or more)
        focus entries on the grab list.  At this point, the grablist has
        suffered irreparable damage.

        An additional problem can occur if a widget has multiple non-focus
        entries on the grab list.  To guarantee that the focus entry is
        always after the non-focus entries, the grablist must be searched
        until all non-focus grab list entries have been found for this
        widget; the focus entry must then be placed after the last non-focus
        entry.
        

FIX:

/* Patch to Event.c */

/* add a grab record to the list, or replace the focus widget in an
   existing grab record.  Returns True if the action was not a no-op.
 */
static Boolean InsertKeyboardGrab(widget, keyboard_focus)
    Widget  widget;
    Widget  keyboard_focus;
{
    register GrabRec *gl;
    register Widget w;
    GrabRec* ge;
    Boolean found = False;
    GrabRec * lastMatch = NULL;


    if (grabList == NULL) {
	AddGrab( widget, False, False, keyboard_focus );
	return True;
    }
    /* look for a keyboard grab entry for the same parent; if none,
       reposition this entry after any other entries for the same tree */
    for (w = widget; (w != NULL) && !((w != widget) && (lastMatch != NULL)); 
         w = w->core.parent) 
    {
	for (gl = grabList; gl != NULL; gl = gl->next)
        {
	    if (gl->widget == w) 
            {
               if (gl->widget == widget)
               {
                  /*
                   * Because we know that focus entries always appear
                   * after a normal grab entry for the same widget, we
                   * can't stop when we encounter the normal grab entry;
                   * we must continue checking until we either find a
                   * matching focus entry, or we find no more entries for
                   * this widget.
                   */
                  if (gl->keyboard_focus != NULL)
                  {
                     /*
                      * Since the widget in the grab entry matches the 
                      * passed-in widget, and since we know that a non-focus 
                      * entry always appears after a normal grab list entry, 
                      * we are assured that this is the only focus entry for 
                      * this widget, so we can update it and then return.
                      */
                     if (gl->keyboard_focus == keyboard_focus)
                     {
                        return False;
                     }
                     else
                     {
		        SendFocusNotify(gl->keyboard_focus, FocusOut);
		        gl->keyboard_focus = keyboard_focus;
                        return True;
                     }
                  }
                  else
                  {
                     /*
                      * Keep going, in case there is a focus entry
                      * following this one.
                      */
                     lastMatch = gl;
                     found = True;
                  }
               }
               else
               {
                  /*
                   * One of our parent widgets has an entry on the
                   * grab list; add our entry after its entry.
                   */
	          AddGrab( widget, False, False, keyboard_focus );
	          ge = grabList;
	          grabList = grabList->next;
	          ge->next = gl->next;
	          gl->next = ge;
                  return True;
               }
	    }
        }
    }

    if (found)
    {
       /*
        * The specified widget had a non-focus entry on the grab
        * list, but currently no focus grab.  Therefore, add the
        * focus entry after the non-focus entry.
        */
       AddGrab( widget, False, False, keyboard_focus );
       ge = grabList;
       grabList = grabList->next;
       ge->next = lastMatch->next;
       lastMatch->next = ge;
    }
    else 
    { 
        /* insert a new grab at end of list */
	AddGrab( widget, False, False, keyboard_focus );
	if (grabList->next != NULL) 
        {
	    ge = grabList;
	    grabList = grabList->next;
	    ge->next = NULL;
	    for (gl = grabList; gl->next != NULL; gl = gl->next);
	    gl->next = ge;
	}
    }
    return True;
}

fred@hpcvlx.HP.COM (Fred Taft) (08/20/88)

### bug number:   402
### area:         Xt
### severity:     medium
### comments:     


VERSION:
	Xtk release 2

SYNOPSIS:
	XtGetValues() returns bogus information on 68000 architecture
        machines, if the application queries a short or char value, and
        it also specifies within the arglist  a pointer to a short or char 
        variable, into which the result is to be placed.

DESCRIPTION:
   Several months ago, I reported a discrepancy in how XtGetValues() worked,
   versus how it was documented.  I received a message that the problem was
   being fixed, yet I notice that it is still present in the R2 toolkit,
   to a degree anyways.  According to the documentation, when you issue a 
   GetValue request, you pass in an arglist composed of an argument 
   name/address pair; the address indicates where the return value should be 
   placed.  If I don't supply a pointer (i.e. I pass in a NULL address),
   when I query a Boolean value, the value is always returned in the arglist;
   I noticed that CopyToArg() specifically tested for this case; I can live
   with this, since it allows old clients to continue to run.  However, if
   I do pass in an address, then the returned boolean value was always 0
   (FALSE).  

   After further investigation, I believe the problem lies in the following
   line of code which had been added to CopyToArg() to fix the original
   problem:

        if (*dst != NULL)
           dst = *(XtArgVal **)dst;

   The above statement treats everything as a pointer to a long variable;
   XtArgVal is typedef'ed to a long.  In the days where the values were
   always returned in the arglist, treating the destination as a long was 
   fine since the value field really was a long.  However, since the
   value now pointed to by dst can be a char, a short, a long, etc, this
   assumption is no longer valid.  For instance, assume the following:

     dst ----> arglist value entry ----> a boolean variable

        ("---->" denotes 'pointing to')

   When the buggy statement shown above is executed, the picture now
   looks like the following:

     dst ----> a boolean variable

   Since the argument being queried is a char, the following is used to
   copy the value into the specified destinatioin:

     *dst = (XtArgVal) *((char *) src);

   Since the value pointed to by dst is assumed to be a long, the following
   four bytes are copied into the location we specified:

      0x00, 0x00, 0x00, 0x01

   Unfortunately, at least for those of us using 68000 architecture, the
   first 0x00 is copied into our destination, instead of the 0x01.



REPEAT-BY:
   Boolean flag;
   Arg     arg[1];

   XtSetArg (arg[0], XtNsensitive, &flag);
   XtGetValues (w, arg, XtNumber(arg));

FIX:

*** Resources.c	Fri Aug 19 12:28:34 1988
--- Resources.new.	Fri Aug 19 12:28:20 1988
***************
*** 62,67
      XtArgVal src, *dst;
      register unsigned int size;
  {
      /* ||| Old semantics are yucky, but keep as long as NULL value */
      if (*dst != NULL) 
  	dst = *(XtArgVal **)dst;

--- 62,69 -----
      XtArgVal src, *dst;
      register unsigned int size;
  {
+     Boolean addrGiven = False;
+ 
      /* ||| Old semantics are yucky, but keep as long as NULL value */
      if (*dst != NULL) 
      {
***************
*** 64,69
  {
      /* ||| Old semantics are yucky, but keep as long as NULL value */
      if (*dst != NULL) 
  	dst = *(XtArgVal **)dst;
  
      if (size == sizeof(XtArgVal))

--- 66,72 -----
  
      /* ||| Old semantics are yucky, but keep as long as NULL value */
      if (*dst != NULL) 
+     {
  	dst = *(XtArgVal **)dst;
          addrGiven = True;
      }
***************
*** 65,70
      /* ||| Old semantics are yucky, but keep as long as NULL value */
      if (*dst != NULL) 
  	dst = *(XtArgVal **)dst;
  
      if (size == sizeof(XtArgVal))
  	*dst = *(XtArgVal *)src;

--- 68,75 -----
      if (*dst != NULL) 
      {
  	dst = *(XtArgVal **)dst;
+         addrGiven = True;
+     }
  
      if (size == sizeof(XtArgVal))
  	*dst = *(XtArgVal *)src;
***************
*** 69,75
      if (size == sizeof(XtArgVal))
  	*dst = *(XtArgVal *)src;
      else if (size == sizeof(short)) 
! 	*dst = (XtArgVal) *((short *) src);
      else if (size == sizeof(char))
          *dst = (XtArgVal) *((char *) src);
      else if (size < sizeof(XtArgVal))

--- 74,85 -----
      if (size == sizeof(XtArgVal))
  	*dst = *(XtArgVal *)src;
      else if (size == sizeof(short)) 
!     {
!         if (addrGiven)
! 	   *((short *)dst) = (short)*((short *) src);
!         else
! 	   *dst = (XtArgVal) *((short *) src);
!     }
      else if (size == sizeof(char))
      {
          if (addrGiven)
***************
*** 71,77
      else if (size == sizeof(short)) 
  	*dst = (XtArgVal) *((short *) src);
      else if (size == sizeof(char))
!         *dst = (XtArgVal) *((char *) src);
      else if (size < sizeof(XtArgVal))
  	bcopy((char *) src, (char *) dst, (int) size);
      else

--- 81,92 -----
  	   *dst = (XtArgVal) *((short *) src);
      }
      else if (size == sizeof(char))
!     {
!         if (addrGiven)
!            *((char *)dst) = (char)*((char *) src);
!         else
!            *dst = (XtArgVal) *((char *) src);
!     }
      else if (size < sizeof(XtArgVal))
  	bcopy((char *) src, (char *) dst, (int) size);
      else