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, "" );
}
}