/*
 * xutil.h - X/Motif debugging 
 *
 * Either include this file into your code ( #include "xutil.h" )
 * or cut and paste the functions as rerquired, to your code 
 *
 * Either use the provided callback and eventhandler template
 * or call the functions directly.
 *
 * By default all verbose gets printed out to "stdout" 
 * 
 * kishan@hackorama.com www.hackorama.com  November 2001
 *
 */
#ifndef _XUTIL_H
#define _XUTIl_H

#include <stdio.h>
#include <Xm/Xm.h>

void utilHandler(Widget w, XtPointer data, XEvent *event); 
void utilCB(Widget w, XtPointer client_data, XtPointer call_data);
void scanChildren( Widget w );
void processWidget( Widget w, int detail );
void fakeEvent( Widget w );


/* a widget callback template */
void utilCB(Widget w, XtPointer client_data, XtPointer call_data ) 
{
        if( w != NULL )
                scanChildren( w );
}

/* an event handler template */
void utilHandler(Widget w, XtPointer data, XEvent *event) 
{
        if( w != NULL )
                scanChildren( w );
}


/* recursive scan of all hierarchical children of a widget */

/* 
 * requires the function "processWidget" for printing
 * out the widget details, else process the widget yourself
 */

void scanChildren(Widget w )
{
        WidgetList children = NULL;
        Cardinal num_children = 0 ;
        int i = 0 , j = 0;
	static int level = 0 ;

	FILE *fp = stdout ; 
	if( fp == NULL ){  fp = fopen( "/tmp/debug.txt" , "r+"  ); } 

        if( w == NULL ){
                if(fp) { fprintf( fp, "\n ERROR:  NULL Widget\n" ); fflush(fp); }
                return ;
        }

        /* process the top */
        if( level == 0 )
                processWidget( w , 0 );

        /* get the children */
        XtVaGetValues( w,
                XmNchildren, &children,
                XmNnumChildren, &num_children,
                NULL);

        /* this is a leaf */
        if( num_children == 0 ){
                if(fp) { fprintf( fp, " [*]\n" ); fflush(fp); }
        }else{
                if(fp) { fprintf( fp, "\n" ); fflush(fp); }
	}
	
        /* process the children */
        for( i = 0 ; i < num_children ; i++ ){
                if(fp) { 
			/* spacing for readability */
			for( j = 1 ; j <= level ; j++ )
				fprintf( fp, "   " );
			fprintf( fp, "%2d ", i+1 ); 
			fflush(fp); 
		}
		/* use processWidget or process yourself like:
		 * if(fp) { fprintf( fp, "%s", XtName(children[i]) );  fflush(fp); } 
		 */
                processWidget( children[i], 0 ); 
        	level++; /* push */
                scanChildren( children[i] );
                level--; /* pop */
        }
}

/* prints the properties of a widget */

/* the second variable "detail" decides how much detail of the 
 * widget will be printed out "0" detail means only * the name 
 * will be printed , with higher values more details are printed.
 */
void processWidget(Widget w , int detail )
{
        Widget focus_widget = NULL;
        Widget parent_widget = NULL;
        Window window = NULL;
	int x = 0, y = 0, height = 0, width = 0;

	FILE *fp = stdout ;
	if( fp == NULL ){  fp = fopen( "/tmp/debug.txt" , "r+"  ); } 

	/* force the details */
	detail = 5; 

        if( w == NULL ){
                if(fp) { fprintf( fp, "\n ERROR [ processWidget ] :  NULL widget \n" ); fflush(fp); }
                return ;
        }

        /* 1. name */
        if(fp) { fprintf( fp, " %s  ", XtName(w) ); fflush(fp); }
	detail--; if( detail < 0 ) return;

        /* 2. parent */
        parent_widget = XtParent( w );
        if( parent_widget != NULL ){
                if(fp) { fprintf( fp, "| p-%s " , XtName(parent_widget) ); fflush(fp); }
        } else {
                if(fp) { fprintf( fp, "| p-NULL " ); fflush(fp); }
        }
	detail--; if( detail < 0 ) return;
	
        /* 3. geometry */
        XtVaGetValues( w,
		XtNx, &x,
		XtNy, &y,
		XtNheight, &height,
		XtNwidth, &width,
                NULL);
        if(fp) { fprintf( fp, "| x=%d y=%d w=%d h=%d ", x, y, width, height ); fflush(fp); }
	detail--; if( detail < 0 ) return;

        /* 4. focus */
        focus_widget = XmGetFocusWidget( w );
        if( focus_widget != NULL ){
                if(fp) { fprintf( fp, "| f-%s ", XtName(focus_widget) ); fflush(fp); }
        } else {
                if(fp) { fprintf( fp, "| f-NULL " ); fflush(fp); }
        }
	detail--; if( detail < 0 ) return;

}

/* send a synthesised event  */

void fakeEvent(Widget w  )
{
	FILE *fp = stdout ;
	if( fp == NULL ){  fp = fopen( "/tmp/debug.txt" , "r+"  ); } 

        XButtonEvent myevent;
        Position x = 1, y = 1;

        /* XtTranslateCoords( w, 5, 5, &x, &y ); */

        myevent.display = XtDisplay(w) ;
        myevent.window = XtWindow(w) ;
        myevent.root = DefaultRootWindow(XtDisplay(w));
        myevent.time = CurrentTime ;
        myevent.x = x ;
        myevent.y = y ;
        myevent.same_screen = TRUE ;
        myevent.type = ButtonPress ;
        myevent.button = Button1 ;
        myevent.send_event = TRUE ;
        /* myevent.window = DefaultRootWindow(XtDisplay(w)); */
        /* myevent.subwindow = None ; */
        /* myevent.state = Button1Mask ; */
	/* myevent.x_root = x ; */
        /* myevent.y_root = y ;*/

        /* XSetInputFocus(  XtDisplay(w), myevent.window, RevertToParent, CurrentTime ); */
        /* XWarpPointer(XtDisplay(w), None, XtWindow(w) , x, y, x, y, x, y); */

        if ( XtDispatchEvent( (XEvent*) &myevent ) == FALSE ){
                if(fp) { fprintf( fp , "failed to send\n" ); fflush(fp); }
        } 

        if ( XSendEvent(myevent.display, myevent.window, FALSE, 
		        ButtonPressMask, (XEvent *) &myevent) == 0 ){
             	if(fp) { fprintf( fp , "failed to send\n" ); fflush(fp); }
        }

        XFlush( XtDisplay(w) );
        XSync( XtDisplay(w), False );
	
}

#endif /* _XUTIL_H */


syntax highlighted by Code2HTML, v. 0.9