#include "nawm.h" #include "cache.h" #include typedef struct _cache_entry { cache_key key; struct _cache_entry *next; cache_data data; } cache_entry; static cache_entry *cache=NULL; static cache_data_free(); /* returns NULL on failure */ static cache_entry *cache_lookup(key) cache_key key; { cache_entry *ptr; for(ptr=cache; ptr && (ptr->key != key); ptr = ptr->next); return ptr; } static cache_insert(key, data) cache_key key; cache_data data; { cache_entry *entry = malloc(sizeof(*entry)); if (!entry) return; /* cache is non-critical */ entry->key = key; entry->data = data; entry->next = cache; cache = entry; } static cache_delete(key) cache_key key; { cache_entry **ptr,*tmp; for(ptr=&cache; *ptr && (*ptr)->key != key; ptr=&(*ptr)->next ); tmp = *ptr; /* the linked list free shuffle */ *ptr=(*ptr)->next; cache_data_free(tmp->data); free(tmp); } static cache_data_free(data) cache_data data; { XFree(data.name); } static cache_update(key,data) cache_key key; cache_data data; { cache_entry *entry; entry = cache_lookup(key); if (!entry) cache_insert(key,data); else { cache_data_free(entry->data); entry->data = data; } } /* interface stuff */ cache_data cached_get_data(key) cache_key key; { cache_entry *entry = cache_lookup(key); if (entry) return entry->data; else { cache_data data = { 0,0 }; XWindowAttributes attr; /* XX have no good way to report errors, consider changing interface */ if (!XGetWindowAttributes(dpy, key, &attr)) return data ; data.x = attr.x; data.y = attr.y; data.name = NULL; XFetchName(dpy, key, &data.name); cache_insert(key,data); return data; } } /* XXX does reparenting mean we have to create/destroy cache entries? what do we do with unmapped windows? */ update_cache(ev) XEvent *ev; { switch (ev->type) { case MapNotify: case UnmapNotify: case CirculateNotify: break; case ConfigureNotify: { cache_data data; data.x = ev->xconfigure.x; data.y = ev->xconfigure.y; data.name=NULL; XFetchName(dpy, ev->xconfigure.window, &data.name); cache_update(ev->xconfigure.window,data); } break; case CreateNotify: { cache_data data; data.x = ev->xconfigure.x; data.y = ev->xconfigure.y; data.name=NULL; XFetchName(dpy, ev->xconfigure.window, &data.name); cache_update(ev->xconfigure.window,data); } break; case DestroyNotify: cache_delete(ev->xdestroywindow.window); break; case ReparentNotify: if (ev->xreparent.parent == root) printf("Got reparent on %d to root\n", ev->xreparent.window); else printf("Got reparent on %d to %d\n", ev->xreparent.window, ev->xreparent.parent); break; } } start_cache() { Window *children; unsigned int numchildren, n; Window rootret; Window parent; XWindowAttributes attr; cache_data data; XSelectInput(dpy, root, SubstructureNotifyMask); /* Xsync(dpy,False); */ /* race condition possible i think ? */ XQueryTree (dpy, root, &rootret, &parent, &children, &numchildren); for (n = 0; n < numchildren; n++) { XGetWindowAttributes(dpy, children[n], &attr); data.x = attr.x; data.y = attr.y; data.name = NULL; XFetchName(dpy, children[n], &data.name); cache_insert(children[n],data); } XFree ((char *) children); } dump_cache() { cache_entry *ptr; printf("\ncache dump\n"); for (ptr=cache; ptr ; ptr = ptr->next) printf("window id %10d (name:%s) at x,y %d,%d\n", ptr->key, (ptr->data.name? ptr->data.name : "NULL"), ptr->data.x, ptr->data.y); printf("\n"); } dump_query() { Window *children; unsigned int numchildren, n; Window rootret; Window parent; XWindowAttributes attr; printf("\nquery dump\n"); XQueryTree (dpy, root, &rootret, &parent, &children, &numchildren); for (n = 0; n < numchildren; n++) { XGetWindowAttributes(dpy, children[n], &attr); printf("window %10d at x,y %d,%d\n", children[n], attr.x, attr.y); } XFree ((char *) children); printf("\n"); } cache_iter(func,stuff) void (*func)(); void *stuff; { cache_entry *ptr; for (ptr=cache; ptr ; ptr=ptr->next) func(ptr->key,&ptr->data,stuff); }