Search the FAQ Archives

3 - A - B - C - D - E - F - G - H - I - J - K - L - M
N - O - P - Q - R - S - T - U - V - W - X - Y - Z
faqs.org - Internet FAQ Archives

Motif FAQ (Part 3 of 9)
Section - 66) How can I tell if the user has selected "Close" from the system

( Part1 - Part2 - Part3 - Part4 - Part5 - Part6 - Part7 - Part8 - Part9 - Single Page )
[ Usenet FAQs | Web FAQs | Documents | RFC Index | Houses ]


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:

Comment about this article, ask questions, or add new information about this topic:

CAPTCHA




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