Xref: utzoo comp.windows.x:25840 comp.windows.x.motif:455 Path: utzoo!utgpu!news-server.csri.toronto.edu!mailrus!wuarchive!cs.utexas.edu!sun-barr!newstop!sun!argv From: argv@turnpike.Eng.Sun.COM (Dan Heller) Newsgroups: comp.windows.x,comp.windows.x.motif Subject: Re: Creating a Message Box Message-ID: <140782@sun.Eng.Sun.COM> Date: 16 Aug 90 18:30:54 GMT References: <1990Aug16.025738.13408@media.uucp> Sender: news@sun.Eng.Sun.COM Organization: O'Reilly && Associates Lines: 124 In article <1990Aug16.025738.13408@media.uucp> arthur@media.uucp (Art Poley) writes: > Can anyone show me exactly how one goes about creating a message box > under Motif that will not allow an application to continue until the > user replies? I'm trying to display some message to a user that must > be acknowledged before the underlying application resumes processing. > For example displaying a message such as, > > "File already exists. Overwrite existing file?" > > To which the user may reply Yes or No. At this point the application > must wait for the user to reply before continuing with the operation. Yet another candidate for the "most frequently asked questions." The answer is remarkably simple in design, altho your particular implemenatation may require more work. Simply -- create a dialog box with XmNdialogStyle to be either XmAPPLICATION_MODAL or XmSYSTEM_MODAL. I recommend the former unless you have a very severe system error where you don't want the user to interact with any application *at all* -- not just your particular application (e.g., use system-modal sparingly). Both modes will provide you with the ability to do what you want to do. Define a local variable: int answer = 0; Next, set the callback functions for XmNokCallback, XmNcancelCallback and XmNhelpCallback to go to *one* function, say: response(). XtAddCallback(dialog, XmNokCallback, response, &answer); XtAddCallback(dialog, XmNcancelCallback, response, &answer); XtAddCallback(dialog, XmNhelpCallback, response, &answer); The "client_data" for the function (in each case) is &answer. The idea is that the function itself is going to change the value of the variable when one of the buttons is selected. Thus: void response(w, answer, reason) Widget w; int *answer; XmAnyCallbackStruct *reason; { switch (reason->reason) { case XmCR_OK: *answer = 1; break; case XmCR_CANCEL: *answer = 2; break; case XmCR_HELP: *answer = 3; break; default: return; } XtDestroyWidget(XtParent(w)); } Next, back to your original function, Manage the dialog box, pop it up, and loop until the value of "answer" has changed. Thus: XtManageChild(dialog); XtPopup(XtParent(dialog), XtGrabNone); /* while the user hasn't provided an answer, simulate XtMainLoop. * The answer changes as soon as the user selects one of the * buttons and the callback routine changes its value. Don't * break loop until XtPending() also returns False to assure * widget destruction. */ while (answer == AskUnknown || XtPending()) { XEvent event; XtNextEvent(&event); XtDispatchEvent(&event); } You may or may not be using application contexts -- keep that in mind. And there you have it. After the loop exits, you have your answer. You have three possible answers -- if you want to provide help, then you've got your help answer. However, I have found that for such questions, many times they are clear enough that you don't need help. So what do you do with that extra button (the help button)? I use it to provide the user with the option to choose between "yes" "no" and "cancel". Consider this scenario: Do you want to overwrite file? Well, a yes answer is obvious. A no answer can imply: no, I don't want to overwrite the file, append to the file. Or use another file.. It depends on the context of your application. The "cancel" button would imply that the user doesn't want to do anything -- just abort the whole operation. Again, you have to decide what is appropriate for your application. You should use the resources XmNokLabelString, XmNcancelLabelString and XmNhelpLabelString to set these labels to be "Yes", "No", and "Cancel" or whatever you want. Another thing to note -- the destroy function destroys the dialog shell. This is to save on memory and other resources (free that which you don't use). If you generlize this routine to be callable from anywhere, you might wish to reconsider whether you want to destroy the widget or just unmanage it. If you just unmanage it, be sure to avoid recreating it every time the function is called. Also don't forget that the user can "close" the widget using the window manager menu. Here, you have the option of programmatically turning off the menu, removing the window manager decorations, or resetting what function is called when the "close" button is selected. As I said -- fundamentally the problem is simple. In reality, the problem is more complicated because you have to consider all those things that the user can do or what you want to provide for the user. Example code for this type of behavior is available in the WidgetWrap library I provided for the R3 distribution under contrib/widgets. This is also the predecessor for the new R4 varargs interface funcs. The examples are not specific to motif -- they use any arbitrary widget set. -- dan ---------------------------------------------------- O'Reilly && Associates argv@sun.com / argv@ora.com Opinions expressed reflect those of the author only.