#line 39 "xpm-w3a.c-nw" #include #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 */ XpmAttributes attr; /* Holds size of image */ Pixmap image; /* Holds decoded image */ Pixmap mask; /* For transparency */ GC gc; /* GC for image */ } *Buffer; #define abs(a) ((a) < 0 ? -(a) : (a)) #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; } /* parseXPM -- decode XPM image data and create a Pixmap from it */ static int parseXPM(Buffer b) { int status; /* Call XPM routine to parse data */ b->buf[b->buflen] = '\0'; b->attr.valuemask = 0; b->mask = None; status = XpmCreatePixmapFromBuffer (XtDisplay(b->canvas), RootWindowOfScreen(XtScreen(b->canvas)), b->buf, &b->image, &b->mask, &b->attr); if (status != XpmSuccess) return status; /* Try to set widget size & shape; draw image */ XtVaSetValues(b->canvas, XtNwidth, b->attr.width, XtNheight, b->attr.height, NULL); if (XtIsRealized(b->canvas) && b->mask != None) { XShapeCombineMask(XtDisplay(b->canvas), XtWindow(b->canvas), ShapeBounding, 0, 0, b->mask, ShapeSet); XFreePixmap(XtDisplay(b->canvas), b->mask); b->mask = None; } if (XtIsRealized(b->canvas)) XCopyArea(XtDisplay(b->canvas), b->image, XtWindow(b->canvas), b->gc, 0, 0, b->attr.width, b->attr.height, 0, 0); dispose(b->buf); /* Remove source data */ return status; } /* expose -- redraw the exposed area of an XPM image */ static void redraw(Widget w, XEvent *ev, String *parms, Cardinal *nparms) { Buffer b; int wd, ht, x, y; /* Decode string argument as a Buffer pointer */ assert(*nparms == 1); if (sscanf(parms[0], "%ld", &b) != 1) assert(!"Missing parameter"); if (! XtIsRealized(w) || b->image == None) return; /* Only on the first ExposeEvent: set the window shape */ if (b->mask != None) { XShapeCombineMask(XtDisplay(w), XtWindow(w), ShapeBounding, 0, 0, b->mask, ShapeSet); XFreePixmap(XtDisplay(w), b->mask); b->mask = None; } /* Draw image to exposed rectangle */ x = ev->xexpose.x; y = ev->xexpose.y; wd = min(b->attr.width, ev->xexpose.width); ht = min(b->attr.height, ev->xexpose.height); XCopyArea(XtDisplay(w), b->image, XtWindow(w), b->gc, x, y, wd, ht, x, y); } /* 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; W3Aevent(b, POINT_SELECT, &coords); } static XtActionsRec actions[] = { {"XPM_expose", redraw}, {"XPM_click", click} }; static char translations[] = ": XPM_expose(%ld)\n\ ,: XPM_click(%ld)"; /* initXPM -- initialize the XPM viewer class */ EXPORT Bool initXPM(char ***mime_types, int *nrtypes, float **prefs) { static char *types[] = {"image/x-xpixmap"}; static float pref[] = {1.0}; *mime_types = types; *nrtypes = 1; *prefs = pref; XtAppAddActions(XtWidgetToApplicationContext(W3Atoplevel()), actions, XtNumber(actions)); return TRUE; } /* openXPM -- start a new XPM viewer, return its ID */ EXPORT Bool openXPM(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->image = None; #ifdef own_widget b->canvas = XtVaCreateManagedWidget ("xpm", coreWidgetClass, window, XtNwidth, 40, XtNheight, 40, NULL); /* Initial size != 0 */ #else b->canvas = window; #endif b->gc = DefaultGC(dpy, screen); /* Install our own event handlers on the window */ sprintf(s, translations, (long) b, (long) b); XtOverrideTranslations(b->canvas, XtParseTranslationTable(s)); return TRUE; } /* writeXPM -- add image data to the buffer, decode when complete */ EXPORT int writeXPM(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); memcpy(b->buf + b->buflen, buf, nbytes); b->buflen += nbytes; return nbytes; /* All bytes processed */ } else if (parseXPM(b) == XpmSuccess) { /* Parse data */ return 0; /* Data OK */ } else { /* Error while parsing */ errno = EFORMAT; return -1; } } /* closeXPM -- close an XPM viewer */ EXPORT Bool closeXPM(long id) { Buffer b = find(id); XpmFreeAttributes(&b->attr); XFreePixmap(XtDisplay(b->canvas), b->mask); XFreePixmap(XtDisplay(b->canvas), b->image); #ifdef own_widget XtDestroyWidget(b->canvas); #else /* Remove shape mask */ XShapeCombineMask(XtDisplay(b->canvas), XtWindow(b->canvas), ShapeBounding, 0, 0, None, ShapeSet); #endif return TRUE; } /* eventXPM -- react to events happening elsewhere */ /* ARGSUSED */ EXPORT void eventXPM(long id, long source, long eventtype, void *params) { /* Doesn't handle events */ } /* infoXPM -- a chance to modify the document info based on the contents */ /* ARGSUSED */ EXPORT Bool infoXPM(long id, W3ADocumentInfo *doc) { /* No modifications */ return TRUE; }