#line 42 "xbm-w3a.c-nw" #include #include #include #include #include /* Defined in w3a.h: */ /* #define POINT_SELECT 5000 /* W3A event type */ /* #define own_widget */ typedef struct { /* A viewer instance */ char *buf; /* Image source data */ size_t buflen; /* Length of buf in bytes */ Widget canvas; /* The widget to draw into */ Pixmap mask; /* Holds decoded image */ Pixmap bground; /* Same, but with depth */ } *Buffer; #define min(a, b) ((a) < (b) ? (a) : (b)) typedef struct _Assoc {long id; Buffer b; struct _Assoc *next;} *Assoc; static Assoc assoclist = NULL; /* store -- store an ID/Buffer combination */ static void store(Buffer b, long id) { Assoc h; new(h); h->id = id; h->b = b; h->next = assoclist; assoclist = h; } /* delete -- delete an ID/Buffer combination */ static void delete(long id) { Assoc g, h; assert(assoclist); if (assoclist->id == id) { h = assoclist; assoclist = assoclist->next; dispose(h); } else { assert(assoclist->next); for (h = assoclist; h->next->id != id; h = h->next) assert(h->next); g = h->next; h->next = g->next; dispose(g); } } /* find -- find the Buffer associated with an ID */ static Buffer find(long id) { Assoc h; assert(assoclist); for (h = assoclist; h->id != id; h = h->next) assert(h->next); return h->b; } /* parseXBM -- decode XBM image data and create a Pixmap from it */ static Bool parseXBM(Buffer b) { Display *dpy = XtDisplay(b->canvas); int screen = XScreenNumberOfScreen(XtScreen(b->canvas)); unsigned int depth = DefaultDepth(dpy, screen); Window root = RootWindow(dpy, screen); int i, width, height, dummy, j, n; GC gc = DefaultGC(dpy, screen); char *s, c, *data; b->buf[b->buflen] = '\0'; s = b->buf; /* Find width of bitmap */ if (sscanf(s, "# define %*s %i %n", &width, &i) != 1) return FALSE; s += i; /* Find height of bitmap */ if (sscanf(s, "# define %*s %i %n", &height, &i) != 1) return FALSE; s += i; /* Skip possible hotspot */ if (*s == '#') { if (sscanf(s, "# define %*s %i %n", &dummy, &i) != 1) return FALSE; s += i; if (sscanf(s, "# define %*s %i %n", &dummy, &i) != 1) return FALSE; s += i; } /* Read data bytes, no error checking... */ newarray(data, (width + 7)/8 * height); while (*s && *s != '{') s++; if (*s) s++; j = 0; while (sscanf(s, " %i %c %n", &n, &c, &i) == 2) { data[j] = n; s += i; j++; } /* Call X routine to parse data */ b->mask = XCreateBitmapFromData(dpy, root, data, width, height); if (!b->mask) return FALSE; /* Create Pixmap from Bitmap, to set background */ b->bground = XCreatePixmap(dpy, root, width, height, depth); if (b->bground == None) { if (b->mask) XFreePixmap(dpy, b->mask); return FALSE; } XCopyPlane(dpy, b->mask, b->bground, gc, 0, 0, width, height, 0, 0, 1); /* Try to set widget size & shape; set image as background */ XtVaSetValues(b->canvas, XtNwidth, width, XtNheight, height, XtNbackgroundPixmap, b->bground, NULL); if (XtIsRealized(b->canvas)) { XShapeCombineMask(dpy, XtWindow(b->canvas), ShapeBounding, 0, 0, b->mask, ShapeSet); XFreePixmap(dpy, b->mask); b->mask = None; } dispose(b->buf); /* Remove source data */ return TRUE; } /* map -- set the shape mask when the window is mapped */ static void map(Widget w, XEvent *ev, String *parms, Cardinal *nparms) { Buffer b; /* Decode string argument as a Buffer pointer */ assert(*nparms == 1); if (sscanf(parms[0], "%ld", &b) != 1) assert(!"Missing parameter"); if (b->mask == None) return; /* Set the window shape */ XShapeCombineMask(XtDisplay(w), XtWindow(w), ShapeBounding, 0, 0, b->mask, ShapeSet); XFreePixmap(XtDisplay(w), b->mask); b->mask = None; } /* click -- action for mouse clicks on canvas */ /* ARGSUSED */ static void click(Widget w, XEvent *ev, String *params, Cardinal *nparams) { long b; struct {int x, y;} coords; assert(*nparams == 1); if (sscanf(params[0], "%ld", &b) != 1) assert(!"Missing parameter"); coords.x = ev->xbutton.x; coords.y = ev->xbutton.y; debug("Clicked on image: (%d,%d)\n", coords.x, coords.y); W3Aevent(b, POINT_SELECT, &coords); } static XtActionsRec actions[] = { {"XBM_map", map}, {"XBM_click", click} }; static char translations[] = ": XBM_map(%ld)\n\ ,: XBM_click(%ld)"; /* initXBM -- initialize the XBM viewer class */ EXPORT Bool initXBM(char ***mime_types, int *nrtypes, float **prefs) { static char *types[] = {"image/x-xbitmap"}; static float pref[] = {1.0}; *mime_types = types; *nrtypes = 1; *prefs = pref; XtAppAddActions(XtWidgetToApplicationContext(W3Atoplevel()), actions, XtNumber(actions)); return TRUE; } /* openXBM -- start a new XBM viewer, return its ID */ EXPORT Bool openXBM(const W3ADocumentInfo doc, W3AWindow window, long id) { int screen = XScreenNumberOfScreen(XtScreen(window)); Display *dpy = XtDisplay(window); Buffer b; char s[256]; /* Create buffer for data */ new(b); store(b, id); b->buf = NULL; b->buflen = 0; b->mask = None; b->bground = None; #ifdef own_widget b->canvas = XtVaCreateManagedWidget ("xbm", coreWidgetClass, window, XtNwidth, 40, XtNheight, 40, NULL); /* Initial size != 0 */ #else b->canvas = window; #endif /* Install our own event handlers on the window */ sprintf(s, translations, (long) b, (long) b); XtOverrideTranslations(b->canvas, XtParseTranslationTable(s)); return TRUE; } /* writeXBM -- add image data to the buffer, decode when complete */ EXPORT int writeXBM(long id, const char *buf, size_t nbytes) { Buffer b = find(id); if (nbytes != 0) { /* Add data to buffer */ renewarray(b->buf, b->buflen + nbytes + 1); /* +1 needed in parseXBM */ memcpy(b->buf + b->buflen, buf, nbytes); b->buflen += nbytes; return nbytes; /* All bytes processed */ } else if (parseXBM(b)) { /* Parse data */ return 0; /* Data OK */ } else { /* Error while parsing */ errno = EFORMAT; return -1; } } /* closeXBM -- close an XBM viewer */ EXPORT Bool closeXBM(long id) { Buffer b = find(id); if (b->bground != None) XFreePixmap(XtDisplay(b->canvas), b->bground); if (b->mask != None) XFreePixmap(XtDisplay(b->canvas), b->mask); #ifdef own_widget XtDestroyWidget(b->canvas); #else /* Remove shape mask */ XShapeCombineMask(XtDisplay(b->canvas), XtWindow(b->canvas), ShapeBounding, 0, 0, None, ShapeSet); #endif delete(id); return TRUE; } /* eventXBM -- react to events happening elsewhere */ /* ARGSUSED */ EXPORT void eventXBM(long id, long source, long eventtype, void *params) { /* Doesn't handle events */ } /* infoXBM -- a chance to modify the document info based on the contents */ /* ARGSUSED */ EXPORT Bool infoXBM(long id, W3ADocumentInfo *doc) { /* No modifications */ return TRUE; }