CloseHook.c revision 6c321187
16c321187Smrg/* $Xorg: CloseHook.c,v 1.4 2001/02/09 02:03:51 xorgcvs Exp $ */
26c321187Smrg
36c321187Smrg/*
46c321187SmrgCopyright 1989, 1998  The Open Group
56c321187Smrg
66c321187SmrgPermission to use, copy, modify, distribute, and sell this software and its
76c321187Smrgdocumentation for any purpose is hereby granted without fee, provided that
86c321187Smrgthe above copyright notice appear in all copies and that both that
96c321187Smrgcopyright notice and this permission notice appear in supporting
106c321187Smrgdocumentation.
116c321187Smrg
126c321187SmrgThe above copyright notice and this permission notice shall be included in
136c321187Smrgall copies or substantial portions of the Software.
146c321187Smrg
156c321187SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
166c321187SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
176c321187SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
186c321187SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
196c321187SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
206c321187SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
216c321187Smrg
226c321187SmrgExcept as contained in this notice, the name of The Open Group shall not be
236c321187Smrgused in advertising or otherwise to promote the sale, use or other dealings
246c321187Smrgin this Software without prior written authorization from The Open Group.
256c321187Smrg
266c321187Smrg*/
276c321187Smrg/* $XFree86: xc/lib/Xmu/CloseHook.c,v 3.5 2001/07/25 15:04:50 dawes Exp $ */
286c321187Smrg
296c321187Smrg/*
306c321187Smrg * CloseDisplayHook package - provide callback on XCloseDisplay
316c321187Smrg *
326c321187Smrg * *
336c321187Smrg * Author:  Jim Fulton, MIT X Consortium
346c321187Smrg *
356c321187Smrg *
366c321187Smrg *			      Public Entry Points
376c321187Smrg *
386c321187Smrg * CloseHook XmuAddCloseDisplayHook (dpy, func, arg)
396c321187Smrg *     Display *dpy;
406c321187Smrg *     XmuCloseHookProc func;
416c321187Smrg *     XPointer arg;
426c321187Smrg *
436c321187Smrg * Bool XmuRemoveCloseDisplayHook (dpy, hook, func, arg)
446c321187Smrg *     Display *dpy;
456c321187Smrg *     CloseHook hook;
466c321187Smrg *     XmuCloseHookProc func;
476c321187Smrg *     XPointer arg;
486c321187Smrg *
496c321187Smrg * Bool XmuLookupCloseDisplayHook (dpy, hook, func, arg)
506c321187Smrg *     Display *dpy;
516c321187Smrg *     CloseHook hook;
526c321187Smrg *     XmuCloseHookProc func;
536c321187Smrg *     XPointer arg;
546c321187Smrg *
556c321187Smrg */
566c321187Smrg
576c321187Smrg#ifdef HAVE_CONFIG_H
586c321187Smrg#include <config.h>
596c321187Smrg#endif
606c321187Smrg#include <stdio.h>					/* for NULL */
616c321187Smrg#include <X11/Xos.h>
626c321187Smrg#include <X11/Xlib.h>
636c321187Smrg#include <X11/Xmu/CloseHook.h>
646c321187Smrg#include <stdlib.h>
656c321187Smrg
666c321187Smrg/*
676c321187Smrg *				 Private data
686c321187Smrg *
696c321187Smrg * This is a list of display entries, each of which contains a list of callback
706c321187Smrg * records.
716c321187Smrg */
726c321187Smrg
736c321187Smrgtypedef struct _CallbackRec {
746c321187Smrg    struct _CallbackRec *next;		/* next link in chain */
756c321187Smrg    XmuCloseHookProc func;		/* function to call */
766c321187Smrg    XPointer arg;			/* argument to pass with function */
776c321187Smrg} CallbackRec;
786c321187Smrg
796c321187Smrg
806c321187Smrgtypedef struct _DisplayEntry {
816c321187Smrg    struct _DisplayEntry *next;		/* next link in chain */
826c321187Smrg    Display *dpy;			/* the display this represents */
836c321187Smrg    int extension;			/* from XAddExtension */
846c321187Smrg    struct _CallbackRec *start, *end;	/* linked list of callbacks */
856c321187Smrg    struct _CallbackRec *calling;	/* currently being called back */
866c321187Smrg} DisplayEntry;
876c321187Smrg
886c321187Smrg/*
896c321187Smrg * Prototypes
906c321187Smrg */
916c321187Smrgstatic DisplayEntry *_FindDisplayEntry(Display*, DisplayEntry**);
926c321187Smrgstatic Bool _MakeExtension(Display*, int*);
936c321187Smrg
946c321187Smrgstatic DisplayEntry *elist = NULL;
956c321187Smrg
966c321187Smrg
976c321187Smrg/*
986c321187Smrg *****************************************************************************
996c321187Smrg *			      Public Entry Points                            *
1006c321187Smrg *****************************************************************************
1016c321187Smrg */
1026c321187Smrg
1036c321187Smrg/*
1046c321187Smrg * Add - add a callback for the given display.  When the display is closed,
1056c321187Smrg * the given function will be called as:
1066c321187Smrg *
1076c321187Smrg *         (*func) (dpy, arg)
1086c321187Smrg *
1096c321187Smrg * This function is declared to return an int even though the value is ignored
1106c321187Smrg * because some compilers have problems with functions returning void.
1116c321187Smrg *
1126c321187Smrg * This routine returns NULL if it was unable to add the callback, otherwise
1136c321187Smrg * it returns an untyped pointer that can be used with Remove or Lookup, but
1146c321187Smrg * not dereferenced.
1156c321187Smrg */
1166c321187SmrgCloseHook
1176c321187SmrgXmuAddCloseDisplayHook(Display *dpy, XmuCloseHookProc func, XPointer arg)
1186c321187Smrg{
1196c321187Smrg    DisplayEntry *de;
1206c321187Smrg    CallbackRec *cb;
1216c321187Smrg
1226c321187Smrg    /* allocate ahead of time so that we can fail atomically */
1236c321187Smrg    cb = (CallbackRec *) malloc (sizeof (CallbackRec));
1246c321187Smrg    if (!cb) return ((XPointer) NULL);
1256c321187Smrg
1266c321187Smrg    de = _FindDisplayEntry (dpy, NULL);
1276c321187Smrg    if (!de) {
1286c321187Smrg	if ((de = (DisplayEntry *) malloc (sizeof (DisplayEntry))) == NULL ||
1296c321187Smrg	    !_MakeExtension (dpy, &de->extension)) {
1306c321187Smrg	    free ((char *) cb);
1316c321187Smrg	    if (de) free ((char *) de);
1326c321187Smrg	    return ((CloseHook) NULL);
1336c321187Smrg	}
1346c321187Smrg	de->dpy = dpy;
1356c321187Smrg	de->start = de->end = NULL;
1366c321187Smrg	de->calling = NULL;
1376c321187Smrg	de->next = elist;
1386c321187Smrg	elist = de;
1396c321187Smrg    }
1406c321187Smrg
1416c321187Smrg    /* add to end of list of callback recordss */
1426c321187Smrg    cb->func = func;
1436c321187Smrg    cb->arg = arg;
1446c321187Smrg    cb->next = NULL;
1456c321187Smrg    if (de->end) {
1466c321187Smrg	de->end->next = cb;
1476c321187Smrg    } else {
1486c321187Smrg	de->start = cb;
1496c321187Smrg    }
1506c321187Smrg    de->end = cb;
1516c321187Smrg
1526c321187Smrg    return ((CloseHook) cb);
1536c321187Smrg}
1546c321187Smrg
1556c321187Smrg
1566c321187Smrg/*
1576c321187Smrg * Remove - get rid of a callback.  If handle is non-null, use that to compare
1586c321187Smrg * entries.  Otherwise, remove first instance of the function/argument pair.
1596c321187Smrg */
1606c321187SmrgBool
1616c321187SmrgXmuRemoveCloseDisplayHook(Display *dpy, CloseHook handle,
1626c321187Smrg			  XmuCloseHookProc func, XPointer arg)
1636c321187Smrg{
1646c321187Smrg    DisplayEntry *de = _FindDisplayEntry (dpy, NULL);
1656c321187Smrg    register CallbackRec *h, *prev;
1666c321187Smrg
1676c321187Smrg    if (!de) return False;
1686c321187Smrg
1696c321187Smrg    /* look for handle or function/argument pair */
1706c321187Smrg    for (h = de->start, prev = NULL; h; h = h->next) {
1716c321187Smrg	if (handle) {
1726c321187Smrg	    if (h == (CallbackRec *) handle) break;
1736c321187Smrg	} else {
1746c321187Smrg	    if (h->func == func && h->arg == arg) break;
1756c321187Smrg	}
1766c321187Smrg	prev = h;
1776c321187Smrg    }
1786c321187Smrg    if (!h) return False;
1796c321187Smrg
1806c321187Smrg
1816c321187Smrg    /* remove from list, watch head and tail */
1826c321187Smrg    if (de->start == h) {
1836c321187Smrg	de->start = h->next;
1846c321187Smrg    } else {
1856c321187Smrg	prev->next = h->next;
1866c321187Smrg    }
1876c321187Smrg    if (de->end == h) de->end = prev;
1886c321187Smrg    if (de->calling != h) free ((char *) h);
1896c321187Smrg    return True;
1906c321187Smrg}
1916c321187Smrg
1926c321187Smrg
1936c321187Smrg/*
1946c321187Smrg * Lookup - see whether or not a handle has been installed.  If handle is
1956c321187Smrg * non-NULL, look for an entry that matches it; otherwise look for an entry
1966c321187Smrg * with the same function/argument pair.
1976c321187Smrg */
1986c321187SmrgBool
1996c321187SmrgXmuLookupCloseDisplayHook(Display *dpy, CloseHook handle,
2006c321187Smrg			  XmuCloseHookProc func, XPointer arg)
2016c321187Smrg{
2026c321187Smrg    DisplayEntry *de = _FindDisplayEntry (dpy, NULL);
2036c321187Smrg    register CallbackRec *h;
2046c321187Smrg
2056c321187Smrg    if (!de) return False;
2066c321187Smrg
2076c321187Smrg    for (h = de->start; h; h = h->next) {
2086c321187Smrg	if (handle) {
2096c321187Smrg	    if (h == (CallbackRec *) handle) break;
2106c321187Smrg	} else {
2116c321187Smrg	    if (h->func == func && h->arg == arg) break;
2126c321187Smrg	}
2136c321187Smrg    }
2146c321187Smrg    return (h ? True : False);
2156c321187Smrg}
2166c321187Smrg
2176c321187Smrg
2186c321187Smrg/*
2196c321187Smrg *****************************************************************************
2206c321187Smrg *			       internal routines                             *
2216c321187Smrg *****************************************************************************
2226c321187Smrg */
2236c321187Smrg
2246c321187Smrg
2256c321187Smrg/*
2266c321187Smrg * Find the specified display on the linked list of displays.  Also return
2276c321187Smrg * the preceeding link so that the display can be unlinked without having
2286c321187Smrg * back pointers.
2296c321187Smrg */
2306c321187Smrgstatic DisplayEntry *
2316c321187Smrg_FindDisplayEntry(register Display *dpy, DisplayEntry **prevp)
2326c321187Smrg{
2336c321187Smrg    register DisplayEntry *d, *prev;
2346c321187Smrg
2356c321187Smrg    for (d = elist, prev = NULL; d; d = d->next) {
2366c321187Smrg	if (d->dpy == dpy) {
2376c321187Smrg	    if (prevp) *prevp = prev;
2386c321187Smrg	    return d;
2396c321187Smrg	}
2406c321187Smrg	prev = d;
2416c321187Smrg    }
2426c321187Smrg    return NULL;
2436c321187Smrg}
2446c321187Smrg
2456c321187Smrg
2466c321187Smrg
2476c321187Smrg/*
2486c321187Smrg * _DoCallbacks - process all of the callbacks for this display and free
2496c321187Smrg * the associated callback data (callback records and display entries).
2506c321187Smrg */
2516c321187Smrg/* ARGSUSED */
2526c321187Smrgstatic int
2536c321187Smrg_DoCallbacks(Display *dpy, XExtCodes *codes)
2546c321187Smrg{
2556c321187Smrg    register CallbackRec *h;
2566c321187Smrg    DisplayEntry *prev;
2576c321187Smrg    DisplayEntry *de = _FindDisplayEntry (dpy, &prev);
2586c321187Smrg
2596c321187Smrg    if (!de) return 0;
2606c321187Smrg
2616c321187Smrg    /* walk the list doing the callbacks and freeing callback record */
2626c321187Smrg    for (h = de->start; h;) {
2636c321187Smrg	register CallbackRec *nexth = h->next;
2646c321187Smrg	de->calling = h;		/* let remove know we'll free it */
2656c321187Smrg	(*(h->func)) (dpy, h->arg);
2666c321187Smrg	de->calling = NULL;
2676c321187Smrg	free ((char *) h);
2686c321187Smrg	h = nexth;
2696c321187Smrg    }
2706c321187Smrg
2716c321187Smrg    /* unlink this display from chain */
2726c321187Smrg    if (elist == de) {
2736c321187Smrg	elist = de->next;
2746c321187Smrg    } else {
2756c321187Smrg	prev->next = de->next;
2766c321187Smrg    }
2776c321187Smrg    free ((char *) de);
2786c321187Smrg    return 1;
2796c321187Smrg}
2806c321187Smrg
2816c321187Smrg
2826c321187Smrg/*
2836c321187Smrg * _MakeExtension - create an extension for this display; done once per display
2846c321187Smrg */
2856c321187Smrgstatic Bool
2866c321187Smrg_MakeExtension(Display *dpy, int *extensionp)
2876c321187Smrg{
2886c321187Smrg    XExtCodes *codes;
2896c321187Smrg
2906c321187Smrg    codes = XAddExtension (dpy);
2916c321187Smrg    if (!codes) return False;
2926c321187Smrg
2936c321187Smrg    (void) XESetCloseDisplay (dpy, codes->extension, _DoCallbacks);
2946c321187Smrg
2956c321187Smrg    *extensionp = codes->extension;
2966c321187Smrg    return True;
2976c321187Smrg}
298