[comp.windows.x] Running Event Processing from a callback

rick@pcrat.uucp (Rick Richardson) (08/09/90)

This group is so full of useful information, I can't help
but ask another question:

Is it safe to run a pseudo-XtAppMainLoop() from a callback
that was itself triggered by a XtAppMainLoop()?  If safe,
are there any potentially ugly side-effects?

People may wonder why I want to do this.  In the context of
the entire application, there may be stylistic reasons to
want this.  I'm not 100% sure how I may end up proceeding,
and I just need to know my valid options.

E.G.:

main()
{
	- create command button with callback to button_pressed()
	- XtAppMainLoop(Context);
}

button_pressed()
{
	XtPopup(PopupShell);
	StayInPopup = 1;	/* When done, popup will set to 0 */
	while (StayInPopup)
	{
		XEvent	event;

		XtAppNextEvent(Context, &event);
		XtDispatchEvent(&event);
	}
	XtPopdown(PopupShell);
}
-- 
Rick Richardson - PC Research, Inc., uunet!pcrat!rick, (201) 389-8963

swick@ATHENA.MIT.EDU (Ralph Swick) (08/10/90)

    Is it safe to run a pseudo-XtAppMainLoop() from a callback
    that was itself triggered by a XtAppMainLoop()?

absolutely.  That's the typical place such things will appear.

    If safe,
    are there any potentially ugly side-effects?

possibly :-)  but they're likely to be considered bugs, when found.
The biggest warning with the R4 implementation is to make sure you
properly unwind the stack; i.e. always return, never longjmp().

bjaspan@athena.mit.edu (Barr3y Jaspan) (08/11/90)

In article <1990Aug9.162333.6049@pcrat.uucp>, rick@pcrat.uucp (Rick
Richardson) writes:
|> Is it safe to run a pseudo-XtAppMainLoop() from a callback
|> that was itself triggered by a XtAppMainLoop()?  If safe,
|> are there any potentially ugly side-effects?

Yes, it is safe to do that; in fact, I've written code that does.  I've
posted it here before, but it isn't long so I'll post it again. 
Disclaimer:  This code does what I need for an application that I wrote.
I made it as general as seemed like a good idea at the time.  Your
mileage may vary.

In any case, it should be a good example.

Barr3y Jaspan, bjaspan@mit.edu
Student Information Processing Board (SIPB)

--- snip snip ---

/* GetString.h */

#include <X11/Intrinsic.h>

#define GETSTRING_ACCEPT	-1000
#define GETSTRING_CANCEL	-1001

Widget InitGetString();
int GetString();

/* GetString.c */

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Command.h>

#include "GetString.h"

#define XVCMW XtVaCreateManagedWidget

static int accepted, cancelled;
static void Accept(), Cancel(), Focus();
static int HierEvent();

extern void Popup();

static XtActionsRec actionTable[] = {
     {"Accept", (XtActionProc) Accept},
     {"Cancel", (XtActionProc) Cancel},
     {"Focus", (XtActionProc) Focus},
};
     
Widget InitGetString(parent, name)
   Widget parent;
   char *name;
{
     static int first_time = 1;
     Widget getStringWindow, form, title, edit, accept, cancel;

     if (first_time) {
	  XtAppAddActions(XtWidgetToApplicationContext(parent), actionTable,
			  XtNumber(actionTable));
	  first_time = 0;
     };

     getStringWindow = XtVaCreatePopupShell(name,
transientShellWidgetClass,
					    parent,
					    XtNinput, True,
					    NULL);
     form = XVCMW("getStringForm", formWidgetClass, getStringWindow,
NULL);
     title = XVCMW("getStringTitle", labelWidgetClass, form, NULL);
     edit = XVCMW("getStringEdit", asciiTextWidgetClass, form, NULL);
     accept = XVCMW("getStringAccept", commandWidgetClass, form, NULL);
     cancel = XVCMW("getStringCancel", commandWidgetClass, form, NULL);
     XtSetKeyboardFocus(form, edit);

     return getStringWindow;
}

int GetString(getStringWindow, label, value, pop_type, buf, len)
   Widget getStringWindow;
   String label, value;
   int pop_type;
   char *buf;
   int len;
{
     XtAppContext app_con;
     Widget title, edit;
     XEvent event;

     app_con = XtWidgetToApplicationContext(getStringWindow);
     title = XtNameToWidget(getStringWindow,
"getStringForm.getStringTitle");
     edit = XtNameToWidget(getStringWindow,
"getStringForm.getStringEdit");

     XtVaSetValues(title, XtNlabel, label, NULL);
     XtVaSetValues(edit, XtNstring, value, NULL);

     XtRealizeWidget(getStringWindow);
     Popup(getStringWindow, XtGrabExclusive, pop_type);

     accepted = cancelled = 0;
     while (! accepted && ! cancelled) {
	  XtAppNextEvent(app_con, &event);
	  XtDispatchEvent(&event);
     }

     XtPopdown(getStringWindow);

     if (accepted) {
	  char *s;

	  XtVaGetValues(edit, XtNstring, (XtArgVal) &s, NULL);
	  strncpy(buf, s, len-2);
	  buf[len-1] = '\0';
	  XawAsciiSourceFreeString(edit);
	  
	  return GETSTRING_ACCEPT;
     }
     else
	  return GETSTRING_CANCEL;
}

/*
 * I thought I needed this routine becaues XtAppNextEvent was
 * returning events for widgets that should have been blocked by the
 * XtGrabExclusive.. but it turns out that XtDispatch deals with that
 * (correctly) so this code is useless.
 */
static int HierEvent(w, event)
   Widget w;
   XAnyEvent *event;
{
     Widget event_w;

     event_w = XtWindowToWidget(XtDisplay(w), event->window);

     while (event_w = XtParent(event_w)) {
	  if (w == event_w)
	       return 1;
	  else if (XtIsShell(event_w))
	       break;
     }

     return 0;
}

/* ARGSUSED */
static void Accept(w, e, p, n)
   Widget w;
   XEvent *e;
   String *p;
   Cardinal *n;
{
     accepted = 1;
}

/* ARGSUSED */
static void Cancel(w, e, p, n)
   Widget w;
   XEvent *e;
   String *p;
   Cardinal *n;
{
     cancelled = 1;
}

/* ARGSUSED */
static void Focus(w, e, p, n)
   Widget w;
   XEvent *e;
   String *p;
   Cardinal *n;
{
     XSetInputFocus(XtDisplay(w), XtWindow(w), RevertToPointerRoot,
		    CurrentTime);
}