[comp.windows.x] Crash-Problem with the Athena Dialog Widget

hoenig@tsetse.informatik.uni-kl.de (Helmut Hoenig) (10/22/90)

X11R4 - Is there a bug in the Athena Dialog Widget ?

The following program queries some strings by using the dialog-widget. 
On my Sun, it crashes exactly when querying the 4th string, during the
dispatch of the first KeyPress-Event for the popup-widget. 

As the program didn't crash so exactly all the time I wrote a small
recorder, which stores the events for the first popup-widgets and lets
them be dispatched again for the following popups.  (It can be enabled
by setting the RECORDER-macro.)

Even if the program doesn't crash one can see, that the
memory-size of the program slowly rises without any reason. 

Has somebody already had that Problem ?
How can I solve it ?
Or is it just a foolish mistake of mine in the use the dialog-widget in
the do_string_query()-function ? I just tried to use it similary to the
popup-example of the Athena Widget Set. 

I hope somebody could help me as I don't want to miss the
popup-up widgets in my programs and I could not find a bug in my source.

Helmut Hoenig
hoenig@informatik.uni-kl.de

(just to be compiled and linked with -lXaw -lXmu -lXt -lXext -lX11)

---------------------------------- CUT HERE ------------------------------------

#define	_RECORDER	/* no events will be recorded when the RECORDER-macro
			   is not set */

#include <stdio.h>
#include <strings.h>

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>

#include <X11/Xaw/Cardinals.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Dialog.h>

static XtAppContext	app_con;
Widget			toplevel;

static int  return_button = 0;

static void return_key();

static String fallback_resources[] = {
	"*string*Dialog*translations:	#override\\n \
		<Key>Return: 		ReturnKey()",
	NULL
};

static XtActionsRec actionTable[] = {
{	"ReturnKey",		return_key	},
};

/******************************************************************************
 * event-recorder: To record the events independend to their
 * window-ids, the window-entries are converted through a
 * window-table, which is set after realizing the widget.
 * All arriving events are stored, when the popup-widget is used
 * for the first time. The next time, the stored events are
 * dispatched with exchanged window-ids.
 */

#define MAX_EVENTS 200
#define MAX_WINDOWS 10

static XEvent	event_list[MAX_EVENTS];
static int	write_index = 0;
static int	read_index;

static Window	window_table[MAX_WINDOWS];	/* stores the windows of a
						   window-tree */
static int	len;			/* number of ids in the table */

/*----------------------------------------------------------------------------*/

static Window	wid_to_window( wid )
	int	wid;
{
	return( window_table[wid] );
}

static int window_to_wid( window )
	Window	window;
{
int	wid;

	for (wid=0;wid<len;wid++) {
		if (window==window_table[wid])	break;
	}
	if (wid==len) {
		fprintf( stderr, "window not in window-tree\n" );
		return(-1);
	}
	else	return( wid );
}

/*--------------------*/

static void store_tree( display, window )
	Display	*display;
	Window	window;
{
Window	 root, parent;
Window	 *children;
unsigned nchildren;
int	 i;

	if (len==MAX_WINDOWS) {
		fprintf( stderr, "*** too many windows.\n" );
		exit(-1);
	}
	window_table[len++] = window;

	XQueryTree( display, window, &root, &parent,
		&children, &nchildren );
	for (i=0;i<nchildren;i++) {
		store_tree( display, children[i] );
	}
	XFree( (char*)children );	
}

/*--------------------*/

void init_window_table( display, root )
	Display	*display;
	Window	root;
/*
 * constructs a table containing the window and all its subwindows
 * to convert the subwindows to a unique id, depending on the tree-structure.
 */
{
	len = 0;
	store_tree( display, root );
}

/*----------------------------------------------------------------------------*/

int store_event( event )
	XEvent	*event;
{
	if (write_index==MAX_EVENTS) {
		fprintf( stderr, "*** too many events.\n" );
		exit (-1);
	}
	memcpy( &event_list[write_index], event, sizeof(XEvent) );
	event_list[write_index].xany.window = window_to_wid( event->xany.window );
	write_index++;
	return(0);
}

int read_event( event )
	XEvent	*event;
{
	if (read_index<write_index) {
		memcpy( event, event_list+read_index, sizeof(XEvent) );
		event->xany.window = wid_to_window( event->xany.window );
		read_index++;
		return(0);
	}
	else	return(1);
}

int rewind()
{
	if (write_index) {
		read_index = 0;
		return(0);
	}
	else	return(-1);
}

void init_event_list()
{
	write_index = 0;
	read_index  = 0;
}

/******************************************************************************
* callbacks for the buttons and for pressing the return-key
*/

static void button_selected( widget, client_data, call_data )
	Widget		widget;
	XtPointer	client_data, call_data;
{
	return_button = (int)client_data;
}

/*--------------------*/

static void return_key( widget, event, params, num_params )
	Widget		widget;
	XEvent		*event;
	String		*params;
	Cardinal	num_params;
{
	return_button = 0;
}

/******************************************************************************
* function to create a dialog-widget, execute events 
* and destroying the widget again.
*/

void do_string_query( label, default_string )
	char	 *label;
	char	 *default_string;
{
Arg		args[5];
Widget		popup, dialog;
Cardinal	n;
XEvent		event;
int		root_x, root_y;
/*
 * create the widgets and realize it
 */
	n = 0;
	XtSetArg(args[n], XtNallowShellResize, True );	n++;

	popup  = XtCreatePopupShell( "string", transientShellWidgetClass,
			toplevel, args, n);

	n = 0;
	XtSetArg(args[n], XtNlabel, label );			n++;
	XtSetArg(args[n], XtNvalue, default_string );		n++;
	dialog = XtCreateManagedWidget( "dialog", dialogWidgetClass,
			popup, args, n);

	XawDialogAddButton(dialog, "ok",     button_selected, 0 );
	XawDialogAddButton(dialog, "cancel", button_selected, 1 );

	XtRealizeWidget( popup );
/*
 * map it.
 */
	XtPopup(popup,XtGrabNone);
	return_button = -1;

#ifndef RECORDER
	while(return_button<0)
	{
		XNextEvent( XtDisplay(popup), &event );
		XtDispatchEvent( &event );
	}
#else
{
int store_mode;

	init_window_table( XtDisplay(popup), XtWindow(popup) );
	if (rewind()) {
		init_event_list();
		store_mode = 1;
	}
	else	store_mode = 0;


	while(return_button<0)
	{
		if (store_mode)
		{	XNextEvent( XtDisplay(popup), &event );
			store_event( &event );
		}
		else
		{	if (read_event(&event)) {
				fprintf( stderr, "*** out of events.\n" );
				exit(0);
			}
		}
		XtDispatchEvent( &event );
		XSync( XtDisplay(popup), 0 );
	}
}
#endif
/*
 * ignore rest of the events to be sure that no events have to be
 * queued, when the recorder is working.
 */
	XSync( XtDisplay(popup), 1 );

	XtDestroyWidget( popup );
}

/*----------------------------------------------------------------------------*/

main( argc, argv )
	int	argc;
	char	**argv;
{
char	*ret;
int	count = 0;
char	label[BUFSIZ];
/*
 * initialize the toolkit
 */
    toplevel = XtAppInitialize(&app_con, "Test",
		NULL, ZERO,
    		&argc, argv, fallback_resources, NULL, ZERO);

    if (!toplevel)	exit(-1);

    XtAppAddActions(app_con, actionTable, XtNumber(actionTable));
/*
 * endless loop to query strings
 */
    while(1) {
    	sprintf( label, "Enter String %d:", ++count );
    	do_string_query( label, "" );
    }
}