home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / lib / Xmu / CloseHook.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-28  |  8.0 KB  |  294 lines

  1. /*
  2.  * $XConsortium: CloseHook.c,v 1.7 91/05/28 16:15:34 converse Exp $
  3.  *
  4.  * CloseDisplayHook package - provide callback on XCloseDisplay
  5.  *
  6.  * Copyright 1989 Massachusetts Institute of Technology
  7.  *
  8.  * Permission to use, copy, modify, and distribute this software and its
  9.  * documentation for any purpose and without fee is hereby granted, provided
  10.  * that the above copyright notice appear in all copies and that both that
  11.  * copyright notice and this permission notice appear in supporting
  12.  * documentation, and that the name of M.I.T. not be used in advertising
  13.  * or publicity pertaining to distribution of the software without specific,
  14.  * written prior permission.  M.I.T. makes no representations about the
  15.  * suitability of this software for any purpose.  It is provided "as is"
  16.  * without express or implied warranty.
  17.  *
  18.  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  19.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
  20.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  21.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  22.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
  23.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  24.  *
  25.  * Author:  Jim Fulton, MIT X Consortium
  26.  * 
  27.  * 
  28.  *                  Public Entry Points
  29.  * 
  30.  * CloseHook XmuAddCloseDisplayHook (dpy, func, arg)
  31.  *     Display *dpy;
  32.  *     XmuCloseHookProc func;
  33.  *     caddr_t arg;
  34.  * 
  35.  * Bool XmuRemoveCloseDisplayHook (dpy, hook, func, arg)
  36.  *     Display *dpy;
  37.  *     CloseHook hook;
  38.  *     XmuCloseHookProc func;
  39.  *     caddr_t arg;
  40.  * 
  41.  * Bool XmuLookupCloseDisplayHook (dpy, hook, func, arg)
  42.  *     Display *dpy;
  43.  *     CloseHook hook;
  44.  *     XmuCloseHookProc func;
  45.  *     caddr_t arg;
  46.  * 
  47.  */
  48.  
  49. #include <stdio.h>                    /* for NULL */
  50. #include <X11/Xos.h>
  51. #include <X11/Xlib.h>
  52. #include <X11/Xmu/CloseHook.h>
  53.  
  54. extern char *malloc();                    /* should be void * */
  55.  
  56. /*
  57.  *                 Private data
  58.  *
  59.  * This is a list of display entries, each of which contains a list of callback
  60.  * records.
  61.  */
  62.  
  63. typedef struct _CallbackRec {
  64.     struct _CallbackRec *next;        /* next link in chain */
  65.     XmuCloseHookProc func;        /* function to call */
  66.     caddr_t arg;            /* argument to pass with function */
  67. } CallbackRec;
  68.  
  69.  
  70. typedef struct _DisplayEntry {
  71.     struct _DisplayEntry *next;        /* next link in chain */
  72.     Display *dpy;            /* the display this represents */
  73.     int extension;            /* from XAddExtension */
  74.     struct _CallbackRec *start, *end;    /* linked list of callbacks */
  75.     struct _CallbackRec *calling;    /* currently being called back */
  76. } DisplayEntry;
  77.  
  78.  
  79. static DisplayEntry *elist = NULL;
  80. static Bool _MakeExtension();
  81. static DisplayEntry *_FindDisplayEntry();
  82.  
  83.  
  84. /*
  85.  *****************************************************************************
  86.  *                  Public Entry Points                            *
  87.  *****************************************************************************
  88.  */
  89.  
  90. /*
  91.  * Add - add a callback for the given display.  When the display is closed,
  92.  * the given function will be called as:
  93.  *
  94.  *         (*func) (dpy, arg)
  95.  *
  96.  * This function is declared to return an int even though the value is ignored
  97.  * because some compilers have problems with functions returning void.
  98.  *
  99.  * This routine returns NULL if it was unable to add the callback, otherwise
  100.  * it returns an untyped pointer that can be used with Remove or Lookup, but
  101.  * not dereferenced.
  102.  */
  103. CloseHook XmuAddCloseDisplayHook (dpy, func, arg)
  104.     Display *dpy;
  105.     XmuCloseHookProc func;        /* function to call on close display */
  106.     caddr_t arg;            /* arg to pass */
  107. {
  108.     DisplayEntry *de;
  109.     CallbackRec *cb;
  110.  
  111.     /* allocate ahead of time so that we can fail atomically */
  112.     cb = (CallbackRec *) malloc (sizeof (CallbackRec));
  113.     if (!cb) return ((caddr_t) NULL);
  114.  
  115.     de = _FindDisplayEntry (dpy, NULL);
  116.     if (!de) {
  117.     if ((de = (DisplayEntry *) malloc (sizeof (DisplayEntry))) == NULL ||
  118.         !_MakeExtension (dpy, &de->extension)) {
  119.         free ((char *) cb);
  120.         if (de) free ((char *) de);
  121.         return ((CloseHook) NULL);
  122.     }
  123.     de->dpy = dpy;
  124.     de->start = de->end = NULL;
  125.     de->calling = NULL;
  126.     de->next = elist;
  127.     elist = de;
  128.     }
  129.  
  130.     /* add to end of list of callback recordss */
  131.     cb->func = func;
  132.     cb->arg = arg;
  133.     cb->next = NULL;
  134.     if (de->end) {
  135.     de->end->next = cb;
  136.     } else {
  137.     de->start = cb;
  138.     }
  139.     de->end = cb;
  140.  
  141.     return ((CloseHook) cb);
  142. }
  143.  
  144.  
  145. /*
  146.  * Remove - get rid of a callback.  If handle is non-null, use that to compare
  147.  * entries.  Otherwise, remove first instance of the function/argument pair.
  148.  */
  149. Bool XmuRemoveCloseDisplayHook (dpy, handle, func, arg)
  150.     Display *dpy;
  151.     CloseHook handle;            /* value from XmuAddCloseDisplayHook */
  152.     XmuCloseHookProc func;        /* function to call on close display */
  153.     caddr_t arg;            /* arg to pass */
  154. {
  155.     DisplayEntry *de = _FindDisplayEntry (dpy, NULL);
  156.     register CallbackRec *h, *prev;
  157.  
  158.     if (!de) return False;
  159.  
  160.     /* look for handle or function/argument pair */
  161.     for (h = de->start, prev = NULL; h; h = h->next) {
  162.     if (handle) {
  163.         if (h == (CallbackRec *) handle) break;
  164.     } else {
  165.         if (h->func == func && h->arg == arg) break;
  166.     }
  167.     prev = h;
  168.     }
  169.     if (!h) return False;
  170.  
  171.  
  172.     /* remove from list, watch head and tail */
  173.     if (de->start == h) {
  174.     de->start = h->next;
  175.     } else {
  176.     prev->next = h->next;
  177.     }
  178.     if (de->end == h) de->end = prev;
  179.     if (de->calling != h) free ((char *) h);
  180.     return True;
  181. }
  182.  
  183.  
  184. /*
  185.  * Lookup - see whether or not a handle has been installed.  If handle is 
  186.  * non-NULL, look for an entry that matches it; otherwise look for an entry 
  187.  * with the same function/argument pair.
  188.  */
  189. Bool XmuLookupCloseDisplayHook (dpy, handle, func, arg)
  190.     Display *dpy;
  191.     CloseHook handle;            /* value from XmuAddCloseDisplayHook */
  192.     XmuCloseHookProc func;        /* function to call on close display */
  193.     caddr_t arg;            /* arg to pass */
  194. {
  195.     DisplayEntry *de = _FindDisplayEntry (dpy, NULL);
  196.     register CallbackRec *h;
  197.  
  198.     if (!de) return False;
  199.  
  200.     for (h = de->start; h; h = h->next) {
  201.     if (handle) {
  202.         if (h == (CallbackRec *) handle) break;
  203.     } else {
  204.         if (h->func == func && h->arg == arg) break;
  205.     }
  206.     }
  207.     return (h ? True : False);
  208. }
  209.  
  210.  
  211. /*
  212.  *****************************************************************************
  213.  *                   internal routines                             *
  214.  *****************************************************************************
  215.  */
  216.  
  217.  
  218. /*
  219.  * Find the specified display on the linked list of displays.  Also return
  220.  * the preceeding link so that the display can be unlinked without having
  221.  * back pointers.
  222.  */
  223. static DisplayEntry *_FindDisplayEntry (dpy, prevp)
  224.     register Display *dpy;
  225.     DisplayEntry **prevp;
  226. {
  227.     register DisplayEntry *d, *prev;
  228.  
  229.     for (d = elist, prev = NULL; d; d = d->next) {
  230.     if (d->dpy == dpy) {
  231.         if (prevp) *prevp = prev;
  232.         return d;
  233.     }
  234.     prev = d;
  235.     }
  236.     return NULL;
  237. }
  238.  
  239.  
  240.  
  241. /*
  242.  * _DoCallbacks - process all of the callbacks for this display and free
  243.  * the associated callback data (callback records and display entries).
  244.  */
  245. /* ARGSUSED */
  246. static int _DoCallbacks (dpy, codes)
  247.     Display *dpy;
  248.     XExtCodes *codes;
  249. {
  250.     register CallbackRec *h;
  251.     DisplayEntry *prev;
  252.     DisplayEntry *de = _FindDisplayEntry (dpy, &prev);
  253.  
  254.     if (!de) return 0;
  255.  
  256.     /* walk the list doing the callbacks and freeing callback record */
  257.     for (h = de->start; h;) {
  258.     register CallbackRec *nexth = h->next;
  259.     de->calling = h;        /* let remove know we'll free it */
  260.     (*(h->func)) (dpy, h->arg);
  261.     de->calling = NULL;
  262.     free ((char *) h);
  263.     h = nexth;
  264.     }
  265.  
  266.     /* unlink this display from chain */
  267.     if (elist == de) {
  268.     elist = de->next;
  269.     } else {
  270.     prev->next = de->next;
  271.     }
  272.     free ((char *) de);
  273.     return 1;
  274. }
  275.  
  276.  
  277. /*
  278.  * _MakeExtension - create an extension for this display; done once per display
  279.  */
  280. static Bool _MakeExtension (dpy, extensionp)
  281.     Display *dpy;
  282.     int *extensionp;
  283. {
  284.     XExtCodes *codes;
  285.  
  286.     codes = XAddExtension (dpy);
  287.     if (!codes) return False;
  288.  
  289.     (void) XESetCloseDisplay (dpy, codes->extension, _DoCallbacks);
  290.  
  291.     *extensionp = codes->extension;
  292.     return True;
  293. }
  294.