Path: utzoo!attcan!uunet!husc6!bloom-beacon!apple!rutgers!ucsd!ucbvax!hplabs!hp-pcd!hpcvlx!fred
From: fred@hpcvlx.HP.COM (Fred Taft)
Newsgroups: comp.windows.x
Subject: Re: HP's Xtk Bug Fixes
Message-ID: <1610040@hpcvlx.HP.COM>
Date: 15 Aug 88 18:13:20 GMT
References: <1610032@hpcvlx.HP.COM>
Organization: Hewlett-Packard Co., Corvallis, OR, USA
Lines: 160


### 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;
}