veerabad@buster.cps.msu.edu (Vibhu Veerabadrappa) (02/24/91)
Hi, Here is a question on X window programming: I have a program in which I pop up a dialog window from which I expect the user to input some data which I need, later in the program. But since X window programs are event driven, the program does not "Block" ubtil the user types in the required data, but goes on. . . . popupwindow (); /* some processing which requires the user's data ... */ . . . I tried to have a loop after the pop up, waiting until the data is input. But the pop up window was never popped up !! Young's book has an example in which the program does not block, and he also says that it is difficult to simulate "blocked" i/o ... but does not say it is impossible !! So there must be a way out. Can anyone provide me with a hint how it can be done? Thank you very much. My e_mail address is: veerabad@buster.cps.msu.edu ------Vibhu.
cs@cbnewsh.att.com (cetin.seren) (02/25/91)
In article <1991Feb23.213455.19457@msuinfo.cl.msu.edu>, veerabad@buster.cps.msu.edu (Vibhu Veerabadrappa) writes: > > Hi, > Here is a question on X window programming: > > I have a program in which I pop up a dialog window from which > I expect the user to input some data which I need, later in the program. > But since X window programs are event driven, the program does not "Block" > ubtil the user types in the required data, but goes on. > > . > . > . > popupwindow (); > /* > some processing > which requires > the user's data ... > */ > . > . > . > I tried to have a loop after the pop up, waiting until the data is > input. But the pop up window was never popped up !! > > Young's book has an example in which the program does not block, > and he also says that it is difficult to simulate "blocked" i/o ... but > does not say it is impossible !! So there must be a way out. > > Can anyone provide me with a hint how it can be done? > > Thank you very much. > > My e_mail address is: veerabad@buster.cps.msu.edu > > ------Vibhu. > Disclaimer: The only half-acceptable argument to doing something like what you want is that you want to port an old, dumb- terminal based application or application support library to a windowed environment. In case you are designing something from scratch, think carefully; you WILL find a BETTER paradigm to do what you want to accomplish. The concurrency involved in multi-window style programming requires that the program designer approaches the problem differently. As a hint, approach your problem with the question: -- What should happen once the user has decided to pick one of the options available in the popupwindow?? as opposed to: -- Now we have to get the users' choice... There has been a lot said and done on the style of multi-window style programming. I can send you a list of references dating back to '85 or even earlier if you want. Having said that, I admit I've had to deal with the problem; it pops up when one tries to port an old, dumb-terminal based user interface support library to a graphical widowing environment like X windows. The programs based on old support libraries count on the popupwindows to be blocking; the popupwindow() call is expected to return the choice. The solution I came up with works fairly well, although if abused, it will come to a point where some stack will overflow and a core dump will follow. Neverthless, it handles one problem fairly well: The event-processing necessary to keep the other windows operating, especially the expose events that have to be dealt with right away. A conventional blocking call would cause all the expose events to be queued, but not be processed; That is why poele NOTE: The code is for example only; you'll have fill in the blanks from the man pages. Also, it is kind of backwards, so you'll have to read all of it before it makes sense: AnyWay, here's how you do it: /* define a global var. to keep reqired action */ int MainLoopContinue = 1; /* write your own equivalent of XtMainLoop() function: */ void MyXtMainLoop(............) { while ( MainLoopContinue ) { /* wait until there's something to read at the X socket */ select ( /* put the fd for the X connection socket in the readfds field, set everything else to NULL for sysV, use poll() instead... */ ); /* since select broke, we have an event: */ XNextEvent(.....&event.....); XtDispactEvent( .....&event......); } MainLoopContinue = 1; } /* now define your own popupwindow's callback. Arrange your ** popupwindow so that this gets called when the user types ** something or select something in the popupwindow: */ void popupwindowcallback(...../* the Xt args */......) { /* ** if you want, you can do some initial processing ** of the user input here */ MainLoopContinue=0; /* next time the while in MyXtMainLoop() is ** encountered, it will return.. */ } /* ** now define your popupwindow() function that actually pops up the ** window: */ int /* or char or ZONK*, or whatever */ popupwindow(.................) { /* set up your pop-up window widget, etc. suppose you call ** your popupwin widget popeye: ** also, the popupwindowcallback() ** function defined above has to be defined as the ** event callback function in your XtCreateManagedWidget() ** call. */ . . . XtRealizeWidget(.......popeye.......); MyXtMainLoop(....); /* defined above */ return /* whatever it is you want your popupwindow call ** to actually return, after seemingly blocking ** until the user types in something */ } /* ** Your MAIN() function would look like this: ** (I guess, since that is dependent on how you really want to use ** the stuff above. Here's one scenario anyway: */ main( int argc, char** argv) /* O.K., so I'm too used to C++ !! */ { /* ** set up your initial widgets, etc... */ . . . MyXtMainLoop(....) /* defined above */ } /* ** and I assume you would actually want to use the blocking ** popupwindow() functionthrough one of the other callbacks: */ void SomeOtherCallBackThatGetsCalled(...........) { /* ** do your other stuff, computation, etc., ** and realize that you actually want to ** use the popupwindow() function */ . . . ZONK* UserResponse = popupwindw(........); . . . some more computation, etc.. . . } That's it. The idea is to call MyXtMainLoop() function recursively and use the the MainLoopContinue global variable as cotrol for breaking out of MyXtMainLoop() at each level. PitFall: If too many blocking popupwindow() calls are made within each other, you will blow away the program stack (eventually, anyway. Never happened to me yet). Good Luck!!! Cetin Seren cs%speedy@att.com
mouse@lightning.mcrcim.mcgill.EDU (02/25/91)
>> popupwindow (); >> /* some processing which requires the user's data ... */ > The only half-acceptable argument to doing something like what you > want is that you want to port an old, dumb-terminal based application > or application support library to a windowed environment. > In case you are designing something from scratch, think carefully; > you WILL find a BETTER paradigm to do what you want to accomplish. This sounds to me like a comment coming from limited experience. It's true that this is *usually* the wrong paradigm, but there are occasional cases where it's the least of the available evils. (The alternatives in such circumstances generally involve deeply-nested control structure or large amounts of data in local variables; in all of these cases, turning the control structure into something event-driven results in painful code.) To pick an example that is somewhat too simple but will perhaps give some of the flavor of what I'm trying to say, suppose some code is doing a three-dimensional convolution and finds some exceptional condition that the user must resolve: for (var1=min1;var1<=max1;var1++) for (var2=min2;var2<=max2;var2++) for (var3=min3;var3<=max3;var3++) { if (special(elt[var1][var2][var3])) user_resolve(var1,var2,var3); do_voxel(var1,var2,var3); } Making this event-driven wrt user interaction involves breaking out of the loops and then arranging to re-enter them later. As I indicated, in this example it is not excessively painful. But it can get so. > As a hint, approach your problem with the question: > -- What should happen once the user has decided to pick one of the > options available in the popupwindow?? And if the answer is "pick up where we left off with <foo>", where <foo> is complicated? You are generally correct; I don't mean to give the impression that blocking popups are always a good thing. But they are not quite of as little utility as you indicate. Of course, this is all opinion. der Mouse old: mcgill-vision!mouse new: mouse@larry.mcrcim.mcgill.edu
josh@concept.viewlogic.com (Josh Marantz) (03/01/91)
The nested loop approach described by cs@cbnewsh.att.com is probably the best way to approach this problem in C. But when using Scheme, which support lexical scoping and first class procedures, there is a better way. Instead of "blocking", have the popup routine take a function as an argument, and run that function when the popup is activated. (define (SomeOtherCallBackThatGetsCalled ...) ; do your other stuff, computation, etc., ; and realize that you actually want to ; use the popupwindow() function (popwindow ... (lambda (UserResponse) ; some other computation, etc. ))) (popwindow ...) returns immediately, but its procedure argument gets called when the popup is terminated. The body of the procedure gets to use all the local variables in SomeOtherCallBackThatGetsCalled, and generally behave as if it was code that followed a blocking call to popwindow. No nested main loops are required. This can be done in C too, its just too clumsy to be used very much: typedef struct { ... Local variable declarations for SomeOtherCallbackThatGetsCalled ... } SomeOtherCallbackLocals; static void continuation(); void SomeOtherCallBackThatGetsCalled(...........) { SomeOtherCallbackLocals args; /* ** do your other stuff, computation, etc., ** and realize that you actually want to ** use the popupwindow() function */ . . . ZONK* UserResponse = popupwindw(........, continuation, &args); } static void continuation(UserResponse, args) ZONK* UserResponse; SomeOtherCallbackLocals *args; { . . . some more computation, etc.. . . } -- Joshua Marantz Viewlogic Systems, Inc. josh@viewlogic.com Why not pass the time by playing a little solitaire?