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