2
This software may only be used by you under license from AT&T Corp.
3
("AT&T"). A copy of AT&T's Source Code Agreement is available at
4
AT&T's Internet website having the URL:
5
<http://www.research.att.com/sw/tools/graphviz/license/source.html>
6
If you received this software without first entering into a license
7
with AT&T, you have an infringing copy of this software and cannot use
8
it without violating AT&T's intellectual property rights.
16
static char DRName[] = "_AG_pending";
18
typedef struct symlist_s {Agsym_t *sym; struct symlist_s *link;} symlist_t;
22
Agobj_t *key; /* i.e. the root obj */
23
Agobj_t *obj; /* may be a subgraph obj */
30
struct {Dict_t *g,*n,*e;} pending;
33
static void clean_symlist(pending_cb_t *pcb)
38
g = agroot(agraphof(pcb->obj));
39
for (s = pcb->symlist; s; s = t) {
45
static void freef(Dict_t *dict, void *ptr, Dtdisc_t *disc)
53
agfree(agraphof(pcb->obj),pcb);
56
static Dtdisc_t Disc = {
57
offsetof(pending_cb_t,key), /* sort by 'key' */
66
static Dict_t *dictof(dirtyset_t *ds, Agobj_t *obj)
68
Dict_t **dict_ref = NIL(Dict_t**);
70
case AGRAPH: dict_ref = &(ds->pending.g); break;
71
case AGNODE: dict_ref = &(ds->pending.n); break;
72
case AGINEDGE: case AGOUTEDGE: dict_ref = &(ds->pending.e); break;
74
if (*dict_ref == NIL(Dict_t*))
75
*dict_ref = agdtopen(agraphof(obj),&Disc,Dttree);
79
static Agobj_t* genkey(Agobj_t *obj)
81
switch (AGTYPE(obj)) {
82
case AGRAPH: return obj;
84
return (Agobj_t*)agsubnode(agroot(agraphof(obj)),(Agnode_t*)obj,FALSE);
85
case AGINEDGE: case AGOUTEDGE:
86
return (Agobj_t*)agsubedge(agroot(agraphof(obj)),(Agedge_t*)obj,FALSE);
91
static pending_cb_t *lookup(Dict_t *dict, Agobj_t *obj)
93
pending_cb_t key, *rv;
95
key.key = genkey(obj);
96
rv = (pending_cb_t*) dtsearch(dict,&key);
100
static void resolve(Dict_t *dict, pending_cb_t *handle, Agobj_t *obj, int cbkind, Agsym_t *optsym)
102
symlist_t *sym,*nsym,*psym;
105
case CB_INITIALIZE: /* dominate CB_UPDATE */
106
clean_symlist(handle);
107
handle->callback_kind = cbkind;
109
case CB_DELETION: /* cancels all pending callbacks */
110
dtdelete(dict,handle);
112
case CB_UPDATE: /* least strength */
113
if (handle->callback_kind == CB_UPDATE) {
114
psym = NIL(symlist_t*);
115
for (sym = handle->symlist; sym; psym = sym, sym = sym->link)
116
if (sym->sym == optsym) break;
117
if (sym == NIL(symlist_t*)) {
118
nsym = agalloc(agraphof(obj),sizeof(symlist_t));
120
if (psym) psym->link = nsym;
121
else handle->symlist = nsym;
123
/* else we already have a callback registered */
125
/* else update is dominated by CB_INITIALIZE or CB_DELETION */
130
static void insert(Dict_t *dict, Agobj_t *obj, int cbkind, Agsym_t *optsym)
132
pending_cb_t *handle;
133
handle = agalloc(agraphof(obj),sizeof(pending_cb_t));
135
handle->key = genkey(obj);
137
handle->symlist = (symlist_t*)agalloc(agraphof(obj),sizeof(symlist_t));
138
handle->symlist->sym = optsym;
140
handle->callback_kind = cbkind;
141
dtinsert(dict,handle);
144
void agrecord_callback(Agobj_t *obj, int kind, Agsym_t *optsym)
148
pending_cb_t *handle;
152
dirty = (dirtyset_t*) agbindrec(g,DRName,sizeof(dirtyset_t),FALSE);
153
dict = dictof(dirty,obj);
154
if ((handle = lookup(dict,obj))) resolve(dict,handle,obj,kind,optsym);
155
else insert(dict,obj,kind,optsym);
158
static void cb(Dict_t *dict)
165
if (dict) while ((pcb = (pending_cb_t*)dtfirst(dict))) {
166
g = agraphof(pcb->obj);
168
switch(pcb->callback_kind) {
169
case CB_INITIALIZE: aginitcb(pcb->obj,stack); break;
171
for (psym = pcb->symlist; psym; psym = psym->link)
172
agupdcb(pcb->obj, psym->sym, stack);
174
case CB_DELETION: agdelcb(pcb->obj,stack); break;
180
static void agrelease_callbacks(Agraph_t *g)
183
if (NOT(g->clos->callbacks_enabled)) {
184
g->clos->callbacks_enabled = TRUE;
185
dirty = (dirtyset_t*) agbindrec(g,DRName,sizeof(dirtyset_t),FALSE);
186
cb (dirty->pending.g);
187
cb (dirty->pending.n);
188
cb (dirty->pending.e);
192
int agcallbacks(Agraph_t *g, int flag)
195
if (flag && NOT(g->clos->callbacks_enabled))
196
agrelease_callbacks(g);
197
else if (NOT(flag) && g->clos->callbacks_enabled)
198
g->clos->callbacks_enabled = FALSE;
200
if (flag && NOT(g->clos->callbacks_enabled))
201
agrelease_callbacks(g);
202
if (g->clos->callbacks_enabled) {
203
g->clos->callbacks_enabled = flag;
206
g->clos->callbacks_enabled = flag;