Top Document: Motif FAQ (Part 3 of 9) Previous Document: 65) How can my application know when the user has quit Mwm? See reader questions & answers on this topic! - Help others by sharing your knowledge menu? How do I catch the "Close"? I need to do some clean up before exiting. [Last modified: Aug 95] Answer: Catching the mwm Close involves using XmAddWMProtocolCallback and possibly setting the XmNdeleteResponse resource. Note that whether your application involves multiple applicationShells vs. a single applicationShell and multiple toplevelShells is significant. Following the two older code fragments is a complete test application which can be compiled with different #defines to alter the behavior. This works with R4 Intrinsics #include <Xm/Protocols.h> void FinalCleanupCB(w, client_data, call_data) Widget w; caddr_t client_data, call_data; { /* tidy up stuff here */ ... /* exit if you want to */ exit (0); } main() { Atom wm_delete_window; ... XtRealizeWidget(toplevel); ... wm_delete_window = XmInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW", False); XmAddWMProtocolCallback(toplevel, wm_delete_window, FinalCleanupCB, NULL); XtMainLoop(); } This will still kill the application. To turn this behaviour off so that the application is not killed, set the shell resource XmNdeleteResponse to XmDO_NOTHING. This means that users cannot kill your application via the system menu, and may be a bad thing. If you are running R3, Bob Hays (bobhays@spss.com) has suggested this: "Trapping on the delete window atom does not work as I cannot force my action routine to the top of the action list for the activity desired, so the window manager kills my window anyway BEFORE I can do anything about it. And, to make matters worse, the window manager (Motif in this case) tacks its atoms and handlers onto the window at some unknown point down the line after the creation of the shell widget as far as I can tell. So.... I have a procedure as an action routine for ClientMessage. Then, if I get a property change event on the window manager protocols, I then tack on WM_SAVE_YOURSELF. If I get this request, I clean up (it seems to happen on WM_DELETE_WINDOW, BTW, if you remove WM_DELETE_WINDOW from the WM protocols atom) and exit. Works great and is less filling overall:-)." The following similar code fragment is from Dave Mink (mink@cadcam.pms.ford.com): void setupCloseCallback(Widget shell, XtCallbackProc closeProc) { /* get window manager delete protocol atom */ Atom deletewin_protocol = XmInternAtom( XtDisplay(shell), "WM_DELETE_WINDOW", True ); /* turn off default delete response */ XtVaSetValues( shell, XmNdeleteResponse, XmDO_NOTHING, NULL); /* add callback for window manager delete protocol */ XmAddWMProtocolCallback(shell, deletewin_protocol, closeProc, NULL); } Here is a complete code example which can be compiled several different ways, as per the comments in the code. /* * MWM Close test program. * * Creates 4 shells, testing each of 3 different values of XmNdeleteResponse. * Compile will -DMULTIPLE_APP_SHELLS to make all 4 shells of type * applicationShellWidgetClass. Otherwise, first shell created is * applicationShellWidgetClass, but other 3 are topLevelShellWidgetClass. * Results differ. You can also experiment with #defining POPUP_SHELL, * BEFORE_CREATE, or AFTER_CREATE. * * Ken Sall (ksall@cen.com) */ #include <stdio.h> #include <X11/IntrinsicP.h> #include <X11/StringDefs.h> #include <X11/Shell.h> #include <Xm/Xm.h> #include <Xm/XmP.h> #include <Xm/RowColumn.h> /* for popup */ #include <Xm/Label.h> #include <X11/Protocols.h> #include <X11/AtomMgr.h> #include <X11/MwmUtil.h> void CloseCB(); void popup_handler(); #ifdef MULTIPLE_APP_SHELLS #define P1_TITLE "P1: applicationShell: XmDO_NOTHING" #define P2_TITLE "P2: applicationShell: XmDESTROY" #define P3_TITLE "P3: applicationShell: XmUNMAP" #define P4_TITLE "P4: applicationShell: default" #else #define P1_TITLE "P1: applicationShell: XmDO_NOTHING" #define P2_TITLE "P2: topLevelShell: XmDESTROY" #define P3_TITLE "P3: topLevelShell: XmUNMAP" #define P4_TITLE "P4: topLevelShell: XmDO_NOTHING" #endif void CloseCB (w, client_data, call_data) Widget w; /* widget id */ caddr_t client_data; /* data from application */ caddr_t call_data; /* data from widget class */ { XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *) call_data; printf ("caught Close from: %s\n", (char *)client_data ); if (strcmp ( P1_TITLE, (char *)client_data ) == 0 ) { /* do something */ } else if (strcmp ( P2_TITLE, (char *)client_data ) == 0 ) { /* do something else */ } else if (strcmp ( P3_TITLE, (char *)client_data ) == 0 ) { /* do something else */ } else if (strcmp ( P4_TITLE, (char *)client_data ) == 0 ) { /* do something else */ } else /* unreachable */ { printf ("oops\n"); } } void popup_handler() { printf ("popup handler\n"); } int main (argc,argv, envp) int argc; char **argv; char **envp; { XtAppContext app_context; Display *theDisplay; Widget shell1, shell2, shell3, shell4; Widget label, DrawWindow, WindowPopupMenu; Arg al[10]; int ac; Atom delwinAtom1, delwinAtom2, delwinAtom3, delwinAtom4; XmString xms; #ifdef MULTIPLE_APP_SHELLS printf ("This version will demonstrate a problem if you Close P2.\n"); printf ("Since there are multiple appshells, closing (destroying) P2 cause the app to exit.\n"); #else #ifdef POPUP_SHELL printf ("This version uses XtCreatePopupShell rather than XtAppCreateShell \n"); #else printf ("Compile with '-DMULTIPLE_APP_SHELLS' to demonstrate a problem.\n"); #endif #endif #ifdef BEFORE_CREATE printf ("This version adds the XmNdeleteResponse _before_ the shell is created.\n"); #else printf ("This version adds the XmNdeleteResponse _after the shell is created.\n"); #endif XtToolkitInitialize (); app_context = XtCreateApplicationContext (); theDisplay = XtOpenDisplay ( app_context, NULL, "my_program", "ProgramClass", NULL, 0, &argc, argv); /* --------------------- BEGIN P1 -------------------- */ ac = 0; XtSetArg(al[ac], XmNx, 0); ac++; XtSetArg(al[ac], XmNy, 0); ac++; XtSetArg(al[ac], XmNwidth, 350); ac++; XtSetArg(al[ac], XmNheight, 200); ac++; XtSetArg (al[ac], XmNtitle, P1_TITLE); ac++; #ifdef BEFORE_CREATE XtSetArg (al[ac], XmNdeleteResponse, XmDO_NOTHING); ac++; #endif /* The ONLY applicationShell unless MULTIPLE_APP_SHELLS is defined. */ shell1 = XtAppCreateShell ("shell1", "ProgramClass", applicationShellWidgetClass, theDisplay, al, ac); /* Tell mwm to exec CloseCB when close is detected. */ delwinAtom1 = XmInternAtom (XtDisplay(shell1), "WM_DELETE_WINDOW", False); XmAddWMProtocolCallback (shell1, delwinAtom1, CloseCB, P1_TITLE); #ifndef BEFORE_CREATE XtVaSetValues( shell1, XmNdeleteResponse, XmDO_NOTHING, NULL); #endif /* --------------------- BEGIN P2 -------------------- */ ac = 0; XtSetArg(al[ac], XmNx, 375); ac++; XtSetArg(al[ac], XmNy, 0); ac++; XtSetArg(al[ac], XmNwidth, 350); ac++; XtSetArg(al[ac], XmNheight, 200); ac++; XtSetArg (al[ac], XmNtitle, P2_TITLE); ac++; #ifdef BEFORE_CREATE XtSetArg (al[ac], XmNdeleteResponse, XmDESTROY); ac++; #endif #ifdef MULTIPLE_APP_SHELLS shell2 = XtAppCreateShell ("shell2", "ProgramClass", applicationShellWidgetClass, theDisplay, al, ac); #else #ifdef POPUP_SHELL /* * NOTE use of XtCreatePopupShell (not XtCreateMAnagedWidget) and * topLevelShellWidgetClass (not applicationShellWidgetClass). * Parent of topLevelShell is applicationShell. * Use XtPopup rather than XtRealize for topLevelShell. */ shell2 = XtCreatePopupShell ("shell2", topLevelShellWidgetClass, shell1, al, ac); #else shell2 = XtAppCreateShell ("shell2", "ProgramClass", topLevelShellWidgetClass, theDisplay, al, ac); #endif #endif /* Tell mwm to exec CloseCB when close is detected. */ delwinAtom2 = XmInternAtom (XtDisplay(shell2), "WM_DELETE_WINDOW", False); XmAddWMProtocolCallback (shell2, delwinAtom2, CloseCB, P2_TITLE); #ifndef BEFORE_CREATE XtVaSetValues( shell2, XmNdeleteResponse, XmDESTROY, NULL); #endif /* --------------------- BEGIN P3 -------------------- */ ac = 0; XtSetArg(al[ac], XmNx, 750); ac++; XtSetArg(al[ac], XmNy, 0); ac++; XtSetArg(al[ac], XmNwidth, 350); ac++; XtSetArg(al[ac], XmNheight, 200); ac++; XtSetArg (al[ac], XmNtitle, P3_TITLE); ac++; #ifdef BEFORE_CREATE XtSetArg (al[ac], XmNdeleteResponse, XmUNMAP); ac++; #endif #ifdef MULTIPLE_APP_SHELLS shell3 = XtAppCreateShell ("shell3", "ProgramClass", applicationShellWidgetClass, theDisplay, al, ac); #else #ifdef POPUP_SHELL /* See comments for shell2 */ shell3 = XtCreatePopupShell ("shell3", topLevelShellWidgetClass, shell1, al, ac); #else shell3 = XtAppCreateShell ("shell3", "ProgramClass", topLevelShellWidgetClass, theDisplay, al, ac); #endif #endif /* Tell mwm to exec CloseCB when close is detected. */ delwinAtom3 = XmInternAtom (XtDisplay(shell3), "WM_DELETE_WINDOW", False); XmAddWMProtocolCallback (shell3, delwinAtom3, CloseCB, P3_TITLE); #ifndef BEFORE_CREATE XtVaSetValues( shell3, XmNdeleteResponse, XmUNMAP, NULL); #endif /* --------------------- BEGIN P4 -------------------- */ ac = 0; XtSetArg(al[ac], XmNx, 0); ac++; XtSetArg(al[ac], XmNy, 250); ac++; XtSetArg(al[ac], XmNwidth, 350); ac++; XtSetArg(al[ac], XmNheight, 200); ac++; XtSetArg (al[ac], XmNtitle, P4_TITLE); ac++; #ifdef BEFORE_CREATE XtSetArg (al[ac], XmNdeleteResponse, XmDO_NOTHING); ac++; #endif #ifdef MULTIPLE_APP_SHELLS shell4 = XtAppCreateShell ("shell4", "ProgramClass", applicationShellWidgetClass, theDisplay, al, ac); #else #ifdef POPUP_SHELL /* See comments for shell2 */ shell4 = XtCreatePopupShell ("shell4", topLevelShellWidgetClass, shell1, al, ac); #else shell4 = XtAppCreateShell ("shell4", "ProgramClass", topLevelShellWidgetClass, theDisplay, al, ac); #endif #endif /* Tell mwm to exec CloseCB when close is detected. */ delwinAtom4 = XmInternAtom (XtDisplay(shell4), "WM_DELETE_WINDOW", False); XmAddWMProtocolCallback (shell4, delwinAtom4, CloseCB, P4_TITLE); #ifndef BEFORE_CREATE XtVaSetValues( shell4, XmNdeleteResponse, XmDO_NOTHING, NULL); #endif /* just for fun */ ac = 0; WindowPopupMenu = XmCreatePopupMenu(shell1, "PopupMenu", al, ac); XtAddEventHandler( shell1, ButtonPressMask, FALSE, popup_handler, WindowPopupMenu); ac = 0; xms = (XmString) XmStringCreateLocalized ( "Button3 = popup; Button2 = DnD."); XtSetArg(al[ac], XmNlabelString, xms); ac++; XtSetArg(al[ac], XmNshadowThickness, 2); ac++; label = XmCreateLabel (shell1, "label", al, ac); XtManageChild ( label ); XtRealizeWidget( shell1 ); /* NOTE use of XtPopup rather than XtRealizeWidget for topLevels */ #ifdef MULTIPLE_APP_SHELLS XtRealizeWidget( shell2 ); XtRealizeWidget( shell3 ); XtRealizeWidget( shell4 ); #else #ifdef POPUP_SHELL XtPopup ( shell2, XtGrabNone ); XtPopup ( shell3, XtGrabNone ); XtPopup ( shell4, XtGrabNone ); #else XtRealizeWidget( shell2 ); XtRealizeWidget( shell3 ); XtRealizeWidget( shell4 ); #endif #endif XtAppMainLoop (app_context); } ----------------------------------------------------------------------------- END OF PART THREE User Contributions:Top Document: Motif FAQ (Part 3 of 9) Previous Document: 65) How can my application know when the user has quit Mwm? Part1 - Part2 - Part3 - Part4 - Part5 - Part6 - Part7 - Part8 - Part9 - Single Page [ Usenet FAQs | Web FAQs | Documents | RFC Index ] Send corrections/additions to the FAQ Maintainer: kenton@rahul.net (Ken Lee)
Last Update March 27 2014 @ 02:11 PM
|
Comment about this article, ask questions, or add new information about this topic: