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