From: kevin@modcomp.uucp (Kevin Smith)
Subject: Xmlist code for you to compile and run.
Organization: MODCOMP, an AEG company
Date: Tue, 21 Jul 1992 12:09:36 GMT

First off this is from a X11R4 motif 1.1.3  88open
certified machine.

Since I have had only one response on my XmList problems so far I
thought I would include some code that could be compiled on 
various machines and then the results could be email'd or posted 
back to me.

There were two basic problems I have noted in my previous posts:


	Problem 1:

	I have a program that uses the list widget and I use
	the SingleSelect and DefaultSelection callbacks to 
	the same routine.  I have found that sometimes the
	callback routine gets called multiple times from a
	single selection of an item in the list when using
	the mouse.  Keyboard use doesn't have a problem.

	In the callback routine I check the reason, and it is
	SINGLE_SELECT as expected each time but the event
	pointer is only valid coming through the first time and
	after that it is NULL.  I put a check in for that NULL
	along with the SINGLE_SELECT check so that I will ignore
	the multiple call problem.  Why is it doing this and is
	it supposed to do this?  According to the OSF manuals
	I should only need to check the reason in the callbackdata
	structure and go from there.  It does say that *event may
	return NULL.


Problem 2:


My strlist1 variable is an XmStringTable variable that has been malloc'd to 
hold the appropriate number of items.  The data items in this list happen
to all be the same thing, "0000" for example.

My callback routine has been set up to use the XmListReplaceItemPos() call
to replace the entire list with another list, strlist2 which holds the same
list of ten items, each item being "0000".

The problem is that when I select any item in the list, it highlights this
item while mouse and button are pressed on it and then when you let go
it goes through the callback routine, uses the Replace routine and then
commences to highlight all items in the new list which match the one 
that was selected.  Thus any item you pick that matches items in the list
will get highlighted.  Pick any of the highlighted ones and they will all
be de-highlighted.  I am using SINGLE_SELECT and do not expect this kind
of matching behaviour, is this a bug or undocumented annoying feature. 

I have come up with a temporary fix to this behaviour to put in the List.c
Motif source and am working on understanding the entire scope of the problem.
The problem appears to have to do with the selected list stuff which is
getting messed up or then again maybe it is supposed to do this.  I have
found no reference to this matching type behaviour except in the ListAdd()
routines.  IMHO it should not be doing this for the ReplaceItemPos routine
and especially not in SINGLE_SELECT mode. 

Using the DeleteList and AddList functions do not cause this behaviour
but they don't work well for real-time updates (blinkity, blinkity, blink).

-----------------------------------------------------------------------

Here is a small program to demonstrate both problems.  

#define LIST_SELECTION_DEBUG to see if problem 1 occurs.  Select
various items in the list with mouse and watch the output.  Move your mouse
a bit too when you select the item.  

If multiple callbacks are happening you get the following message:

"FOUND UNRECOGNIZED SELECT OR NULL EVENT, IGNORED! NO CALLBACK ACTION" 

Please send me email and what machine/environment it was run in
if this code runs as described or whether it does what I have described.

Thanks,
Kevin Smith				uunet!modcomp!glsdev!kevin

<<<<<<<CUT HERE >>>>>>>>

#include <stdio.h>
#include <Xm/Xm.h>
#include <Xm/PushB.h>
#include <Xm/LabelG.h>
#include <Xm/List.h>
#include <Xm/Form.h>
#include <X11/StringDefs.h>

void create_dummy_str_lst();

void update_data();
void decode_list_selection();
void quit();

	char    max_string[10];
	char    max_string2[10];
	int number_of_rows;
	int k;

	XmStringTable strlist1;
	XmStringTable strlist2;


	XmString	quit_text;

	Widget 	toplevel, 
		mainform, 
		subform,
		quitbutton,
		list1, 
main(argc,argv)
int argc;
char *argv[];

{
	XtAppContext app;


	number_of_rows = 10;
	
	strcpy(max_string,"0000"); 
	strcpy(max_string2,"0000"); 

	create_dummy_str_lst();
	

	toplevel = XtVaAppInitialize(&app,"XList5",NULL,0,(Cardinal *)&argc,argv,
					NULL,NULL);

/*****************************************************************************/
        mainform =  XtVaCreateManagedWidget("maxpagenumwidget",
                xmFormWidgetClass, toplevel,
                NULL);

/*****************************************************************************/
        	list1  = XtVaCreateWidget("list1",
                	xmListWidgetClass,mainform,
                	XmNvisibleItemCount,number_of_rows,
                	XmNitemCount,number_of_rows,
                	XmNitems,strlist1,

                	XmNtraversalOn, TRUE,
                	XmNselectionPolicy, XmSINGLE_SELECT,
			XmNshadowThickness, 0,
                	XmNtopAttachment, XmATTACH_FORM,
                	XmNleftAttachment, XmATTACH_FORM,
                	NULL);

	
	XtManageChild(list1);

        XtAddCallback(list1,XmNsingleSelectionCallback,decode_list_selection,NULL);
        XtAddCallback(list1,XmNdefaultActionCallback,decode_list_selection,NULL);

/*****************************************************************************/

        subform =  XtVaCreateManagedWidget("maxpagenumwidget",
                xmFormWidgetClass, mainform,
                XmNtopAttachment, XmATTACH_FORM,
                XmNtopOffset, 190,
                NULL);

/*****************************************************************************/


        quit_text = XmStringCreateSimple("QUIT");

        quitbutton = XtVaCreateManagedWidget("quitbutton",
                xmPushButtonWidgetClass,subform,
                XmNlabelString,quit_text,
                XmNtopAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_FORM,
                NULL);

        XmStringFree(quit_text);

        XtAddCallback(quitbutton,XmNactivateCallback,quit,NULL);

/*****************************************************************************/


	XtRealizeWidget(toplevel);
	XtAppMainLoop(app);
}

/*****************************************************************************/
void
create_dummy_str_lst()
{

        int     i,j;


#ifdef DEBUG
	printf("create_dummy_str_lst: Entering\n");
	printf(" entry c[0] = %x %x\n",*c,c);
	printf("will malloc %x\n",(sizeof(XmString) * number_of_rows));
#endif

        strlist1 = (XmStringTable ) XtMalloc((sizeof(XmString) * (number_of_rows + 1)));
        strlist2 = (XmStringTable ) XtMalloc((sizeof(XmString) * (number_of_rows + 1)));

#ifdef DEBUG
	printf(" strlist1 at %x\n",&strlist1);
	printf(" strlist1 points at %x\n",strlist1);
#endif

        
	for (i=0;i<number_of_rows;i++) {

            	strlist1[i] = XmStringCreateSimple(&max_string[0]);
            	strlist2[i] = XmStringCreateSimple(&max_string2[0]);
/*
		printf(" strlist1[%d] at %x\n",i,&strlist1[i]);
		printf(" strlist2[%d] at %x\n",i,&strlist2[i]);
*/
#ifdef DEBUG
printf(" strlist1[%d] at %x\n",i,&strlist1[i]);
#endif
        }

#ifdef DEBUG
printf("create_dummy_str_lst: Leaving\n");
#endif
}

/*****************************************************************************/
void
update_data(list_w,client_data,call_data)
Widget 			list_w;
XtPointer 		client_data;
XmListCallbackStruct	*call_data;
{
        int j;

#ifdef DEBUG
printf("update data: Entering\n");
#endif

	
		/* Free up string memory, will reallocate in create_str_list */
        	for (j = 0; j < number_of_rows; j++) {
                	XmStringFree(strlist1[j]);
                	XmStringFree(strlist2[j]);
#ifdef DEBUG
			printf("freeing %x\n",&strlist1[j]);
#endif
		}	
        	XtFree(strlist1);
        	XtFree(strlist2);

        	create_dummy_str_lst();

            	XmListReplaceItemsPos(list1,strlist2,number_of_rows,1);
		     
#ifdef DEBUG
printf("update data: Leaving\n");
#endif
}

/*****************************************************************************/
void
decode_list_selection(list_w,client_data,call_data)
Widget                  list_w;
XtPointer               client_data;
XmListCallbackStruct    *call_data;

{
        char    *list_text;

#ifdef LIST_SELECTION_DEBUG


	printf("decode_list_selection: Entering Widget = %s %x\n",XtName(list_w),list_w);
	printf("decode_list_selection: Widget List item position = %x\n",call_data->item_position);
	printf("decode_list_selection: Widget List item length = %x\n",call_data->item_length);
	printf("decode_list_selection: Widget List reason = %d\n",call_data->reason);
	printf("decode_list_selection: Widget List event  = %x\n",call_data->event);

#endif


        /* PAY ATTENTION HERE!  The check for the event being NULL is crucial since
         * there is some kind of bug in the list widget when selecting with a
         * mouse sometimes the callback is called multiple times, with SINGLE_SELECT
         * but the extra time the event comes through as NULL!  I ignore these,
         * otherwise the goto selection will hop through several pages.
         * DON'T know why this happens but it does! Can you say Motif bug?
         */
        if ( ((call_data->reason == XmCR_SINGLE_SELECT) || (call_data->reason == XmCR_DEFAULT_ACTION) ) && (call_data->event != NULL) ) 
	{

                XmStringGetLtoR (call_data->item, XmSTRING_DEFAULT_CHARSET, &list_text);
#ifdef LIST_SELECTION_DEBUG
                	printf("decode_list_selection:  item selected = %s\n",list_text);
#endif

#ifdef LIST_SELECTION_DEBUG
/*
                            printf("decode_list_selection:  new_page_addr after = %x \n",new_page_addr);
*/
#endif

	update_data();
        }
#ifdef LIST_SELECTION_DEBUG
	else
             printf("FOUND UNRECOGNIZED SELECT OR NULL EVENT, IGNORED! NO CALLBACK ACTION\n");
#endif

#ifdef LIST_SELECTION_DEBUG
printf("decode_list_selection: Leaving \n");
#endif
}
/*****************************************************************************/
void
quit()
{
exit(0);
}