From: jxt@ornl.gov (TOLLIVER J S)
Newsgroups: fj.mail-lists.x-window
Subject: Problems detecting events in InputOnly windows
Date: 20 Aug 92 23:09:21 GMT
Distribution: fj
Organization: Oak Ridge National Laboratory

Date: Thu, 20 Aug 1992 16:27:06 GMT
Message-Id: <1992Aug20.162706.20276@ornl.gov>
Newsgroups: comp.windows.x,comp.windows.x.motif

I am having problems reliably detecting events in InputOnly windows being used
to block input while the application is busy. This is a Motif application but
the InputOnly window is an Xlib issue so I am cross-posting to comp.windows.x
and comp.windows.x.motif. Sorry for the length, but it takes a while to
describe what I'm doing.

Here is a summary of what I'm trying to do along with some pseudo-code of how
I'm trying to do it. Any suggestions would be greatly appreciated. My app has
three windows and must communicate with another app with one window up. The
communication is done with an XtWorkProc that sends and receives data via
shared memory. When the other app is busy, two out of three of my windows
should be disabled but the third window should remain active. While busy, the
other app may send me information via a shared memory message, which my
workProc receives and processes, such that I have to put up yet another window
-- a dialog box, for example. Eventually, the other app informs me that it is
no longer busy. Then I re-enable the two blocked windows.

To accomplish this, I cover each of the two blocked windows with InputOnly
windows with cursor and event mask attributes, setting the cursor and selecting
for ButtonPress and KeyPress events. I do this for both windows to be blocked,
creating two InputOnly windows. (I also install an event handler to detect
StructureNotify events on the two windows to be blocked so I can resize the
matching InputOnly window whenever the window it is covering gets resized.)

Then I install a timer to periodically check for events (every second, say).
Since my workProc needs to be running, I can't just loop and sleep.

The timer does an XFlush and an XmUpdateDisplay and then an XCheckMaskEvent,
masking for ButtonPress and KeyPress events. This is patterned somewhat after
Dan Heller's code in O'Reilly Vol. 6, pp 680-683. If the event is for one of
the InputOnly windows, I beep. If not, I XtDispatch it.

Pseudo-code:

if (time_to_be_busy) {

    iow1 = XCreateWindow (...);    // create an InputOnly window to cover shell1
    iow2 = XCreateWindow (...);    // create an InputOnly window to cover shell2

    // shell1 and shell2 are really top level shell widgets with lots of
    // widgets in them (actually, they are created with XtCreatePopupShell
	// as applicationShellWidgetClass widgets -- see Doug Young's new book
	// on Object Oriented Programming with C++ and OSF/Motif).

    XtAddEventHandler (shell1, StructureNotifyMask, ...);
    XtAddEventHandler (shell2, StructureNotifyMask, ...);

    XMapRaised (iow1);
    XMapRaised (iow2);

    still_busy = True;
    timerId = XtAppAddTimeOut (appContext, 1000, checkForEvents, NULL);
}
else {
    XUnmapWindow (iow1);
    XUnmapWindow (iow2);
    still_busy = False;
}

...

void checkForEvents (...)
{
    XFlush (dpy);

    XmUpdateDisplay (shell1);
    XmUpdateDisplay (shell2);

    Boolean in_a_blocked_window;
    while (XCheckMaskEvent (dpy, ButtonPressMask | KeyPressMask, &event)) {
        in_a_blocked_window = False;
        if (event.xany.window == iow1) in_a_blocked_window = True;
        if (event.xany.window == iow2) in_a_blocked_window = True;

        if (in_a_blocked_window)
            XBell (dpy, 50);
        else
            XtDispatchEvent (&event);
    }

    if (still_busy) XtAppAddTimeOut (...);      //reinstall timer...
}

Makes sense to me...

One other note before getting to the results/symptoms. This is all really done
in C++ (see the //-style comments?) in a general way. The repetitions of the
same code for iow1 and iow2, etc., are really loops over all needed iow's, etc.
In fact, blocking of shell1 and shell2 need not happen consecutively. First one
could be blocked and later another. I've considerably simplified the real code
to make more clear what (I think) is really germaine to my problem.

Here are the results:

Creating the InputOnly windows works fine. The cursors change fine. The
event handler resizes the InputOnly windows fine. Putting up and handling a
dialog box while the two windows are blocked works fine. Getting unbusy works
fine (i.e., the InputOnly windows get unmapped and the cursors change back
successfully) While busy, the timer fires as expected.

BUT! The timer doesn't RELIABLY detect button presses and key presses in the
InputOnly windows. SOMETIMES (say, 1 out of 5 to 100 button presses) I hear a
beep (and write a message to diagnostics). But the rest of the 4 to 99 times
I hear no beep. What's more, I can interact with my third window and the
event-checker never sees it -- i.e., never sees and dispatches the event but
yet the event obviously gets to that third window fine. MOST of the time, the
XCheckMaskEvent returns False -- no event matched the mask -- even though I am
wildly clicking away in one of the blocked windows.

Obviously there is something going on here that I do not understand. Probably
Xt and Motif getting into the act. If you've had the patience to read this far
and are willing to help, I will be most thankful. Specific questions are:

1. What happens to all those events I am generating but not seeing with
XCheckMaskEvent?
2. How do events get to the third, unblocked, window?
3. Most importantly, how can I beep when the user clicks in one of the blocked
windows?

Alternate approaches for dealing with my basic goals -- two or more blocked
windows out of N (>2) total windows while workProc keeps running -- are
welcomed too. Maybe not REAL welcome, but if I have to trash what I've already
done to get it to work, then I have to trash it. But I hope not...

I don't really want to put up a "Busy" dialog box because it adds to the already
cluttered screen, because one of the windows is valid for user-interaction (so
a FULL_APPLICATION_MODAL dialog is out of the question), because other dialogs
may need to come up that require responses, because the user will always have
initiated the busy condition, and because I just don't want to :-)

Thanks,
Johnny Tolliver
Oak Ridge National Laboratory
jxt@ornl.gov