/*********************************************************************** * * TITLE: * shellmgmt.c * * AUTHOR: * Kevin J. Miller * * DESCRIPTION: * Sets correct response for modal Window Manager shells Close * button. Each time you create an Application Shell or a * Modal Dialog, you should call ShellAddClose() to set the * MWM Close behavior correctly. When the Dialog is managed, * use ShellModalManage() instead of XtManageChild(), and * before unmanaging call ShellValidateClose() to see if * the MWM Close button was legally selected, and finally * unmanage with ShellModalUnmanage(). * * CHANGE HISTORY * * $Log: shellmgmt.c,v $ * Revision 1.8 1996/12/19 22:22:38 kevin * fixed compiler warnings * * Revision 1.7 1995/01/20 04:01:57 kevin * removed unused variables * * Revision 1.6 1994/11/22 00:36:30 kevin * added support for iconified main window * * Revision 1.5 1994/01/14 19:51:05 kevin * added per SGI warning * * Revision 1.4 1994/01/06 21:42:08 kevin * updates after SGI test * * Revision 1.3 1994/01/06 05:12:06 kevin * port for V20 * * Revision 1.2 1993/03/03 01:14:43 kevin * updated warning messages * * Revision 1.1 1993/03/02 02:40:55 kevin * Initial revision * *********************************************************************** * * WARNINGS: * none * * EXTERNAL CALLABLE COMPONENTS (PUBLIC): * ShellAddClose * ShellModalManage * ShellValidateClose * ShellModalUnmanage * ShellIsIconified * * GLOBALS: * none * * WAIVERS: * none * * NOTES: * none * * MANPAGE: * none * ***********************************************************************/ #ifndef lint static const char rcsid[] = "$Id: shellmgmt.c,v 1.8 1996/12/19 22:22:38 kevin OEL $"; #endif #include #include #include #include #include #include "shellmgmt.h" #include "message.h" #define BATCH_SIZE 16 /* * local function prototypes */ static void structCB(Widget, XtPointer, XEvent *, Boolean *); /* * local variables */ static struct stk { /* stack of managed widgets */ Widget (*w)[]; int count; int avail; } stack = { NULL, 0, 0 }; static int iconic; /* state of program */ /*********************************************************************** * * FUNCTION: * ShellAddClose * * INPUTS: * w - (Widget) dialog or top level widget * callback - (void (*)()) Close callback function * client_data - (Widget) client data for callback * * OUTPUTS: * none * * RETURNS: * none * * EXTERNALLY READ: * none * * EXTERNALLY MODIFIED: * stack - (static struct stk) add App. Shell * * DESCRIPTION: * The Motif dialog convenience functions do not return the * Dialog Shell which is needed in order to properly set the * Close response. This function will take either a Window * Manager Shell (usually an Applictaion Shell) or the child * of such a shell (usually the child of a Dialog Shell created * with a convenience function. */ void ShellAddClose(Widget w, XtCallbackProc callback, XtPointer client_data) { Atom deleteWindowAtom; /* window manager interaction */ Widget s; /* shell widget */ Arg args[1]; /* standard Xt argument list */ Cardinal n; /* standard Xt argument count */ s = w; if (!XtIsSubclass(s, (WidgetClass)wmShellWidgetClass)) { s = XtParent(s); } if (!XtIsSubclass(s, (WidgetClass)wmShellWidgetClass)) { Warning("INTERNAL: Widget or parent of %s is not a WMShell.", XrmQuarkToString(w->core.xrm_name)); } deleteWindowAtom = XmInternAtom(XtDisplay(w), "WM_DELETE_WINDOW", False); /* * if this is the Application Shell -> add it to the stack * also intern the WM_DELETE_WINDOW atom */ if (XtClass(s) == (WidgetClass)applicationShellWidgetClass) { if ((stack.avail == 0) && (stack.count == 0)) { stack.avail = BATCH_SIZE; stack.w = (Widget (*)[])XtMalloc((Cardinal)(sizeof(Widget) * stack.avail)); (*(stack.w))[(stack.count)++] = s; XtAddEventHandler(s, StructureNotifyMask, False, structCB, NULL); } else { Warning("INTERNAL: Multiple Application Shells have been defined."); } } n = 0; XtSetArg(args[n], XmNdeleteResponse, XmDO_NOTHING); n++; XtSetValues(s, args, n); XmAddWMProtocolCallback(s, deleteWindowAtom, callback, client_data); } /*********************************************************************** * * FUNCTION: * ShellModalManage * * INPUTS: * w - (Widget) the dialog widget to be managed * * OUTPUTS: * none * * RETURNS: * none * * EXTERNALLY READ: * none * * EXTERNALLY MODIFIED: * stack - (static struct stk) add Dialog Shell * * DESCRIPTION: * The widget w should be the child of a Dialog Shell. The * widget is managed and the parent shell is then placed on * the stack. */ void ShellModalManage(Widget w) { Widget s; /* * add parent (shell) to stack */ s = XtParent(w); if (!XtIsSubclass(s, (WidgetClass)wmShellWidgetClass)) { Warning("INTERNAL: Parent of managed widget (%s) is not a WMShell.", XrmQuarkToString(w->core.xrm_name)); } /* * add the current dialog to the stack */ if (stack.count >= stack.avail) { stack.avail += BATCH_SIZE; stack.w = (Widget (*)[])XtRealloc((char *)(stack.w), (Cardinal)(sizeof(Widget) * stack.avail)); } (*(stack.w))[(stack.count)++] = s; /* * manage the child widget */ XtManageChild(w); } /*********************************************************************** * * FUNCTION: * ShellValidateClose * * INPUTS: * w - (Widget) the dialog widget to be managed * * OUTPUTS: * none * * RETURNS: * True - (int) if this is a legal Close or not a Close * False - (int) if this is an illegal Close * * EXTERNALLY READ: * stack - (static struct stk) check WM Shell * * EXTERNALLY MODIFIED: * none * * DESCRIPTION: * A Boolean function that returns True if this dialog callback * had been called normally or by an active Close mechanism. */ int ShellValidateClose(Widget w) { int valid; valid = False; if (!XtIsSubclass(w, (WidgetClass)wmShellWidgetClass)) { /* * the callback was not called be the window manager */ valid = True; } else { /* * if this is a shell, then it should match the top * of the stack */ if ((stack.count > 0) && (w == (*(stack.w))[stack.count - 1])) { valid = True; if ((stack.count == 1) && ShellIsIconified()) { XMapRaised(XtDisplay(w), XtWindow(w)); } } } return valid; } /*********************************************************************** * * FUNCTION: * ShellModalUnmanage * * INPUTS: * w - (Widget) the dialog widget to be unmanaged * * OUTPUTS: * none * * RETURNS: * none * * EXTERNALLY READ: * none * * EXTERNALLY MODIFIED: * stack - (static struct stk) remove Dialog Shell * * DESCRIPTION: * Unmanage the dialog widget (child of a shell) and check and * remove the shell from the stack. */ void ShellModalUnmanage(Widget w) { Widget s; /* * get Dialog Shell */ s = XtParent(w); if (!XtIsSubclass(s, (WidgetClass)wmShellWidgetClass)) { Warning("INTERNAL: Parent of managed widget (%s) is not a WMShell.", XrmQuarkToString(w->core.xrm_name)); } /* * remove Dialog Shell from stack */ if ((stack.count > 0) && (s == (*(stack.w))[stack.count - 1])) { --(stack.count); } else { Warning("INTERNAL: Cannot remove widget (%s) from stack.", XrmQuarkToString(s->core.xrm_name)); } /* * unmanage the child widget */ XtUnmanageChild(w); } /*********************************************************************** * * FUNCTION: * ShellIsIconified * * INPUTS: * none * * OUTPUTS: * none * * RETURNS: * iconic - (static int) current state * * EXTERNALLY READ: * iconic - (static int) current state * * EXTERNALLY MODIFIED: * none * * DESCRIPTION: * Check if the application is iconified. */ int ShellIsIconified() { return iconic; } /*********************************************************************** * * FUNCTION: * structCB * * INPUTS: * w - (Widget) not used * client_data - (XtPointer) not used * event - (XEvent *) theis event * dispatch - (Boolean *) not used * * OUTPUTS: * none * * RETURNS: * none * * EXTERNALLY READ: * none * * EXTERNALLY MODIFIED: * iconic - (int) iconic state variable * * DESCRIPTION: * Set state of iconic variable when UnmapNotify and MapNotify * events come in. */ static void structCB(Widget w, XtPointer client_data, XEvent *event, Boolean *dispatch) { #if defined(spr) && defined(DEBUG) (void)w; (void)client_data; (void)dispatch; #endif switch (event->type) { case UnmapNotify: iconic = TRUE; break; case MapNotify: iconic = FALSE; break; } }