XBM viewer This is a WWW applet (conforming to the W3A API) for viewing images in XBM format. Apart from showing the image, it also accepts mouse clicks, which it passes to the browser by means of the [[W3Aevent]] function. Note that this viewer is not interested in the information about the document that it is viewing. It simply ignores the [[W3ADocumentInfo]] that is passed to [[openXBM]]. A mouse click causes a call to [[W3Aevent]], with event type 5000 and a pointer to a pair (x,y) of integers as parameter. The viewer draws directly into the widget that is provided by the main browser. Since it is not known what kind of widget it is (probably Composite or XmManager), the viewer assumes only that it is a subclass of Core. It installs a set of translations and actions to override whatever the widget already has. The action functions are registered only once, when the viewer is initialized ([[initXBM]]). The translations are installed in every widget that is passed to [[openXBM]]. The action functions have a single parameter, which is used to pass the Buffer with info about the image to the action function. Since action functions can only have string arguments, the pointer to the Buffer is encoded as a decimal number. The [[XBM_map]] action is invoked when the window is mapped. It is used to set the shape mask, because the mask can only be applied after the widget has been realized. The Map event seems a good place for it. Bert Bos , 14 Sep 1994 <<*>>= #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; }