#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ida.h" #include "x11.h" #include "dither.h" #include "readers.h" #include "viewer.h" #include "hex.h" #include "idaconfig.h" /* ----------------------------------------------------------------------- */ #define POINTER_NORMAL 0 #define POINTER_BUSY 1 #define POINTER_PICK 2 #define RUBBER_NEW 3 #define RUBBER_MOVE 4 #define RUBBER_X1 5 #define RUBBER_Y1 6 #define RUBBER_X2 7 #define RUBBER_Y2 8 #define RUBBER_RANGE 6 #define RUBBER_INTERVAL 100 #define PROCESS_LINES 16 int debug; Cursor ptrs[POINTER_COUNT]; /* ----------------------------------------------------------------------- */ Pixmap image_to_pixmap(struct ida_image *img) { unsigned char line[256],*src; XImage *ximage; void *shm; Pixmap pix; GC gc; unsigned int x,y; ximage = x11_create_ximage(app_shell, img->i.width, img->i.height, &shm); for (y = 0; y < img->i.height; y++) { src = img->data + 3*y*img->i.width; if (display_type == PSEUDOCOLOR) { dither_line(src, line, y, img->i.width); for (x = 0; x < img->i.width; x++) XPutPixel(ximage, x, y, x11_map[line[x]]); } else { for (x = 0; x < img->i.width; x++, src += 3) { pix = x11_lut_red[src[0]] | x11_lut_green[src[1]] | x11_lut_blue[src[2]]; XPutPixel(ximage, x, y, pix); } } } pix = XCreatePixmap(dpy,XtWindow(app_shell),img->i.width, img->i.height, DefaultDepthOfScreen(XtScreen(app_shell))); gc = XCreateGC(dpy, pix, 0, NULL); XPUTIMAGE(dpy, pix, gc, ximage, 0, 0, 0, 0, img->i.width, img->i.height); XFreeGC(dpy, gc); x11_destroy_ximage(app_shell, ximage, shm); return pix; } /* ----------------------------------------------------------------------- */ int viewer_i2s(int zoom, int val) { if (0 > zoom) return val/(-zoom+1); if (0 < zoom) return val*(zoom+1); return val; } /* ----------------------------------------------------------------------- */ static void viewer_renderline(struct ida_viewer *ida, char *scanline) { unsigned char *src,*dst,*rgb; unsigned long pix; unsigned int x,s,scrline; src = scanline; if (0 == ida->zoom) { /* as-is */ if (display_type == PSEUDOCOLOR) { dst = ida->dither_line; dither_line(src, dst, ida->line, ida->scrwidth); for (x = 0; x < ida->scrwidth; x++, dst++) XPutPixel(ida->ximage, x, ida->line, x11_map[*dst]); } else { for (x = 0; x < ida->scrwidth; x++, src += 3) { pix = x11_lut_red[src[0]] | x11_lut_green[src[1]] | x11_lut_blue[src[2]]; XPutPixel(ida->ximage, x, ida->line, pix); } } } else if (ida->zoom < 0) { /* zoom out */ s = -ida->zoom+1; if (s-1 != (ida->line % s)) return; scrline = ida->line/s; if (display_type == PSEUDOCOLOR) { rgb = ida->rgb_line; for (x = 0; x < ida->scrwidth; x++, rgb += 3, src += 3*s) { rgb[0] = src[0]; rgb[1] = src[1]; rgb[2] = src[2]; } rgb = ida->rgb_line; dst = ida->dither_line; dither_line(rgb, dst, scrline, ida->scrwidth); for (x = 0; x < ida->scrwidth; x++, dst++) XPutPixel(ida->ximage, x, scrline, x11_map[*dst]); } else { #if 0 /* just drop pixels */ for (x = 0; x < ida->scrwidth; x++, src += 3*s) { pix = x11_lut_red[src[0]] | x11_lut_green[src[1]] | x11_lut_blue[src[2]]; XPutPixel(ida->ximage, x, scrline, pix); } #else /* horizontal interpolation (vertical is much harder ...) */ for (x = 0; x < ida->scrwidth; x++, src += 3*s) { int red,green,blue,count,ix; red = 0; green = 0; blue = 0; count = 0; for (ix = 0; ix < 3*s; ix += 3) { red += src[ix+0]; green += src[ix+1]; blue += src[ix+2]; count += 1; } pix = x11_lut_red[red/count] | x11_lut_green[green/count] | x11_lut_blue[blue/count]; XPutPixel(ida->ximage, x, scrline, pix); } #endif } } else { /* zoom in */ s = ida->zoom+1; if (display_type == PSEUDOCOLOR) { rgb = ida->rgb_line; for (x = 0; x < ida->scrwidth; rgb += 3) { rgb[0] = src[0]; rgb[1] = src[1]; rgb[2] = src[2]; x++; if (0 == (x%s)) src += 3; } for (scrline = ida->line*s; scrline < ida->line*s+s; scrline++) { rgb = ida->rgb_line; dst = ida->dither_line; dither_line(rgb, dst, scrline, ida->scrwidth); for (x = 0; x < ida->scrwidth; x++, dst++) XPutPixel(ida->ximage, x, scrline, x11_map[*dst]); } } else { for (scrline = ida->line*s; scrline < ida->line*s+s; scrline++) { src = scanline; for (x = 0; x < ida->scrwidth; src += 3) { unsigned int i; pix = x11_lut_red[src[0]] | x11_lut_green[src[1]] | x11_lut_blue[src[2]]; for (i = 0; i < s; i++, x++) XPutPixel(ida->ximage, x, scrline, pix); } } } } } /* ----------------------------------------------------------------------- */ static void viewer_cleanup(struct ida_viewer *ida) { if (ida->load_read) { ida->load_done(ida->load_data); ida->load_line = 0; ida->load_read = NULL; ida->load_done = NULL; ida->load_data = NULL; } if (ida->op_work) { ida->op_done(ida->op_data); ida->op_line = 0; ida->op_work = NULL; ida->op_done = NULL; ida->op_data = NULL; if (ida->op_src.data) { if (ida->undo.data) { fprintf(stderr,"have undo buffer /* shouldn't happen */"); free(ida->undo.data); } ida->undo = ida->op_src; memset(&ida->op_src,0,sizeof(ida->op_src)); } } } static Boolean viewer_workproc(XtPointer client_data) { struct ida_viewer *ida = client_data; unsigned int start,end; char *scanline; start = ida->line; end = ida->line + ida->steps; if (end > ida->img.i.height) end = ida->img.i.height; /* image loading */ if (ida->load_read) { for (ida->line = start; ida->line < end; ida->line++) { if (ida->load_line > ida->line) continue; scanline = ida->img.data + ida->img.i.width * ida->load_line * 3; ida->load_read(scanline,ida->load_line,ida->load_data); ida->load_line++; } } /* image processing */ if (ida->op_work && 0 == ida->op_preview) { for (ida->line = start; ida->line < end; ida->line++) { if (ida->op_line > ida->line) continue; scanline = ida->img.data + ida->img.i.width * ida->op_line * 3; ida->op_work(&ida->op_src,&ida->op_rect, scanline,ida->op_line,ida->op_data); ida->op_line++; } } /* image rendering */ if (ida->op_work && ida->op_preview) { for (ida->line = start; ida->line < end; ida->line++) { ida->op_line = ida->line; ida->op_work(&ida->img,&ida->op_rect, ida->preview_line,ida->line,ida->op_data); viewer_renderline(ida,ida->preview_line); } } else { for (ida->line = start; ida->line < end; ida->line++) { scanline = ida->img.data + ida->img.i.width * ida->line * 3; viewer_renderline(ida,scanline); } } /* trigger redraw */ XClearArea(XtDisplay(ida->widget), XtWindow(ida->widget), 0, viewer_i2s(ida->zoom,start), ida->scrwidth, viewer_i2s(ida->zoom,ida->steps), True); /* all done ? */ if (ida->line == ida->img.i.height) { viewer_cleanup(ida); ida->wproc = 0; #if 1 if (args.testload) XtCallActionProc(ida->widget,"Next",NULL,NULL,0); #endif return TRUE; } return FALSE; } static void viewer_workstart(struct ida_viewer *ida) { /* (re-) start */ ida->line = 0; if (!ida->wproc) ida->wproc = XtAppAddWorkProc(app_context,viewer_workproc,ida); } static void viewer_workstop(struct ida_viewer *ida) { if (!ida->wproc) return; viewer_cleanup(ida); XtRemoveWorkProc(ida->wproc); ida->wproc = 0; } static void viewer_workfinish(struct ida_viewer *ida) { char *scanline; if (ida->load_read) { for (ida->line = ida->load_line; ida->line < ida->img.i.height;) { scanline = ida->img.data + ida->img.i.width * ida->line * 3; ida->load_read(scanline,ida->load_line,ida->load_data); ida->line++; ida->load_line++; } } if (ida->op_work && 0 == ida->op_preview) { for (ida->line = ida->op_line; ida->line < ida->img.i.height;) { scanline = ida->img.data + ida->img.i.width * ida->line * 3; ida->op_work(&ida->op_src,&ida->op_rect, scanline,ida->op_line,ida->op_data); ida->line++; ida->op_line++; } } viewer_workstop(ida); } /* ----------------------------------------------------------------------- */ static void viewer_new_view(struct ida_viewer *ida) { if (NULL != ida->ximage) x11_destroy_ximage(ida->widget,ida->ximage,ida->ximage_shm); if (NULL != ida->rgb_line) free(ida->rgb_line); if (NULL != ida->dither_line) free(ida->dither_line); if (NULL != ida->preview_line) free(ida->preview_line); ida->scrwidth = viewer_i2s(ida->zoom,ida->img.i.width); ida->scrheight = viewer_i2s(ida->zoom,ida->img.i.height); ida->steps = PROCESS_LINES; if (ida->zoom < 0) while ((ida->steps % (-ida->zoom+1)) != 0) ida->steps++; ida->rgb_line = malloc(ida->scrwidth*3); ida->dither_line = malloc(ida->scrwidth); ida->preview_line = malloc(ida->img.i.width*3); ida->ximage = x11_create_ximage(ida->widget, ida->scrwidth, ida->scrheight, &ida->ximage_shm); if (NULL == ida->ximage) { ida->zoom--; return viewer_new_view(ida); } XtVaSetValues(ida->widget, XtNwidth, ida->scrwidth, XtNheight, ida->scrheight, NULL); viewer_workstart(ida); } static void viewer_timeout(XtPointer client_data, XtIntervalId *id); static int viewer_rubber_draw(struct ida_viewer *ida) { XGCValues values; struct ida_rect r = ida->current; int x,y,w,h; values.function = GXxor; values.foreground = ida->mask; XChangeGC(dpy,ida->wgc,GCFunction|GCForeground,&values); if (r.x1 < r.x2) { x = viewer_i2s(ida->zoom,r.x1); w = viewer_i2s(ida->zoom,r.x2 - r.x1); } else { x = viewer_i2s(ida->zoom,r.x2); w = viewer_i2s(ida->zoom,r.x1 - r.x2); } if (r.y1 < r.y2) { y = viewer_i2s(ida->zoom,r.y1); h = viewer_i2s(ida->zoom,r.y2 - r.y1); } else { y = viewer_i2s(ida->zoom,r.y2); h = viewer_i2s(ida->zoom,r.y1 - r.y2); } if (0 == h && 0 == w) return 0; if (w) w--; if (h) h--; XDrawRectangle(dpy,XtWindow(ida->widget),ida->wgc,x,y,w,h); return 1; } static void viewer_rubber_off(struct ida_viewer *ida) { if (ida->marked) viewer_rubber_draw(ida); ida->marked = 0; if (ida->timer) XtRemoveTimeOut(ida->timer); ida->timer = 0; } static void viewer_rubber_on(struct ida_viewer *ida) { ida->marked = viewer_rubber_draw(ida); if (ida->marked) ida->timer = XtAppAddTimeOut(app_context,RUBBER_INTERVAL, viewer_timeout,ida); } static void viewer_timeout(XtPointer client_data, XtIntervalId *id) { struct ida_viewer *ida = client_data; ida->timer = 0; viewer_rubber_off(ida); ida->mask <<= 1; if ((ida->mask & 0x10) == 0x10) ida->mask |= 0x01; viewer_rubber_on(ida); } static void viewer_redraw(Widget widget, XtPointer client_data, XEvent *ev, Boolean *cont) { struct ida_viewer *ida = client_data; XExposeEvent *event; XGCValues values; if (ev->type != Expose) return; event = (XExposeEvent*)ev; if (NULL == ida->ximage) return; if (event->x + event->width > (int)ida->scrwidth) return; if (event->y + event->height > (int)ida->scrheight) return; if (NULL == ida->wgc) ida->wgc = XCreateGC(XtDisplay(widget), XtWindow(widget), 0, NULL); viewer_rubber_off(ida); values.function = GXcopy; XChangeGC(dpy,ida->wgc,GCFunction,&values); XPUTIMAGE(XtDisplay(ida->widget), XtWindow(widget), ida->wgc, ida->ximage, event->x, event->y, event->x, event->y, event->width, event->height); viewer_rubber_on(ida); } static int viewer_pos2state(struct ida_viewer *ida, int x, int y) { int x1,x2,y1,y2; if (POINTER_PICK == ida->state) return ida->state; x1 = viewer_i2s(ida->zoom,ida->current.x1); x2 = viewer_i2s(ida->zoom,ida->current.x2); y1 = viewer_i2s(ida->zoom,ida->current.y1); y2 = viewer_i2s(ida->zoom,ida->current.y2); if ((x1 < x && x < x2) || (x2 < x && x < x1)) { if (y1-RUBBER_RANGE < y && y < y1+RUBBER_RANGE) return RUBBER_Y1; if (y2-RUBBER_RANGE < y && y < y2+RUBBER_RANGE) return RUBBER_Y2; } if ((y1 < y && y < y2) || (y2 < y && y < y1)) { if (x1-RUBBER_RANGE < x && x < x1+RUBBER_RANGE) return RUBBER_X1; if (x2-RUBBER_RANGE < x && x < x2+RUBBER_RANGE) return RUBBER_X2; } if (((x1 < x && x < x2) || (x2 < x && x < x1)) && ((y1 < y && y < y2) || (y2 < y && y < y1))) return RUBBER_MOVE; return RUBBER_NEW; } static void viewer_mouse(Widget widget, XtPointer client_data, XEvent *ev, Boolean *cont) { struct ida_viewer *ida = client_data; int state = POINTER_NORMAL; unsigned char *pix; int x,y; viewer_rubber_off(ida); switch (ev->type) { case ButtonPress: { XButtonEvent *eb = (XButtonEvent*)ev; if (eb->button != Button1) goto out; ida->state = viewer_pos2state(ida,eb->x,eb->y); switch (ida->state) { case POINTER_PICK: x = viewer_i2s(-ida->zoom,eb->x); y = viewer_i2s(-ida->zoom,eb->y); pix = ida->img.data + ida->img.i.width*y*3 + x*3; ida->pick_cb(x,y,pix,ida->pick_data); ida->pick_cb = NULL; ida->pick_data = NULL; ida->state = POINTER_NORMAL; state = POINTER_NORMAL; break; case RUBBER_NEW: ida->mask = 0x33333333; ida->current.x1 = ida->current.x2 = viewer_i2s(-ida->zoom,eb->x); ida->current.y1 = ida->current.y2 = viewer_i2s(-ida->zoom,eb->y); break; case RUBBER_MOVE: ida->last_x = viewer_i2s(-ida->zoom,eb->x); ida->last_y = viewer_i2s(-ida->zoom,eb->y); break; case RUBBER_X1: ida->current.x1 = viewer_i2s(-ida->zoom,eb->x); break; case RUBBER_Y1: ida->current.y1 = viewer_i2s(-ida->zoom,eb->y); break; case RUBBER_X2: ida->current.x2 = viewer_i2s(-ida->zoom,eb->x); break; case RUBBER_Y2: ida->current.y2 = viewer_i2s(-ida->zoom,eb->y); break; } state = ida->state; break; } case MotionNotify: { XMotionEvent *em = (XMotionEvent*)ev; if (!(em->state & Button1Mask)) { state = viewer_pos2state(ida,em->x,em->y); goto out; } switch (ida->state) { case RUBBER_NEW: ida->current.x2 = viewer_i2s(-ida->zoom,em->x); ida->current.y2 = viewer_i2s(-ida->zoom,em->y); if (em->state & ShiftMask) { /* square selection */ int xlen,ylen; xlen = abs(ida->current.x1 - ida->current.x2); ylen = abs(ida->current.y1 - ida->current.y2); if (ylen > xlen) { if (ida->current.x1 < ida->current.x2) ida->current.x2 -= (xlen - ylen); else ida->current.x2 += (xlen - ylen); } else { if (ida->current.y1 < ida->current.y2) ida->current.y2 -= (ylen - xlen); else ida->current.y2 += (ylen - xlen); } } break; case RUBBER_MOVE: x = viewer_i2s(-ida->zoom,em->x); y = viewer_i2s(-ida->zoom,em->y); ida->current.x1 += (x - ida->last_x); ida->current.x2 += (x - ida->last_x); ida->current.y1 += (y - ida->last_y); ida->current.y2 += (y - ida->last_y); ida->last_x = x; ida->last_y = y; break; case RUBBER_X1: ida->current.x1 = viewer_i2s(-ida->zoom,em->x); break; case RUBBER_Y1: ida->current.y1 = viewer_i2s(-ida->zoom,em->y); break; case RUBBER_X2: ida->current.x2 = viewer_i2s(-ida->zoom,em->x); break; case RUBBER_Y2: ida->current.y2 = viewer_i2s(-ida->zoom,em->y); break; } state = ida->state; break; } case ButtonRelease: { XButtonEvent *eb = (XButtonEvent*)ev; if (eb->button != Button1) goto out; ida->state = POINTER_NORMAL; state = ida->state; break; } } if (ida->current.x1 < 0) ida->current.x1 = 0; if (ida->current.x1 > ida->img.i.width) ida->current.x1 = ida->img.i.width; if (ida->current.x2 < 0) ida->current.x2 = 0; if (ida->current.x2 > ida->img.i.width) ida->current.x2 = ida->img.i.width; if (ida->current.y1 < 0) ida->current.y1 = 0; if (ida->current.y1 > ida->img.i.height) ida->current.y1 = ida->img.i.height; if (ida->current.y2 < 0) ida->current.y2 = 0; if (ida->current.y2 > ida->img.i.height) ida->current.y2 = ida->img.i.height; out: XDefineCursor(dpy, XtWindow(widget), ptrs[state]); viewer_rubber_on(ida); } /* ----------------------------------------------------------------------- */ /* public stuff */ void viewer_pick(struct ida_viewer *ida, viewer_pick_cb cb, XtPointer data) { if (POINTER_NORMAL != ida->state) return; if (debug) fprintf(stderr,"viewer_pick\n"); ida->state = POINTER_PICK; ida->pick_cb = cb; ida->pick_data = data; } void viewer_unpick(struct ida_viewer *ida) { if (POINTER_PICK != ida->state) return; if (debug) fprintf(stderr,"viewer_unpick\n"); ida->state = POINTER_NORMAL; ida->pick_cb = NULL; ida->pick_data = NULL; } void viewer_autozoom(struct ida_viewer *ida) { if (GET_AUTOZOOM()) { ida->zoom = 0; while (XtScreen(ida->widget)->width < viewer_i2s(ida->zoom,ida->img.i.width) || XtScreen(ida->widget)->height < viewer_i2s(ida->zoom,ida->img.i.height)) ida->zoom--; } viewer_new_view(ida); } void viewer_setzoom(struct ida_viewer *ida, int zoom) { ida->zoom = zoom; viewer_new_view(ida); } static void viewer_op_rect(struct ida_viewer *ida) { if (ida->current.x1 == ida->current.x2 && ida->current.y1 == ida->current.y2) { /* full image */ ida->op_rect.x1 = 0; ida->op_rect.x2 = ida->img.i.width; ida->op_rect.y1 = 0; ida->op_rect.y2 = ida->img.i.height; return; } else { /* have selection */ if (ida->current.x1 < ida->current.x2) { ida->op_rect.x1 = ida->current.x1; ida->op_rect.x2 = ida->current.x2; } else { ida->op_rect.x1 = ida->current.x2; ida->op_rect.x2 = ida->current.x1; } if (ida->current.y1 < ida->current.y2) { ida->op_rect.y1 = ida->current.y1; ida->op_rect.y2 = ida->current.y2; } else { ida->op_rect.y1 = ida->current.y2; ida->op_rect.y2 = ida->current.y1; } } } int viewer_start_op(struct ida_viewer *ida, struct ida_op *op, void *parm) { struct ida_image dst; ptr_busy(); viewer_workfinish(ida); viewer_rubber_off(ida); /* try init */ viewer_op_rect(ida); if (debug) fprintf(stderr,"viewer_start_op: init %s(%p)\n",op->name,parm); ida->op_data = op->init(&ida->img,&ida->op_rect,&dst.i,parm); ptr_idle(); if (NULL == ida->op_data) return -1; dst.data = malloc(dst.i.width * dst.i.height * 3); /* prepare background processing */ if (ida->undo.data) { free(ida->undo.data); memset(&ida->undo,0,sizeof(ida->undo)); } if (ida->op_src.data) { fprintf(stderr,"have op_src buffer /* shouldn't happen */"); free(ida->op_src.data); } ida->op_src = ida->img; ida->img = dst; ida->op_line = 0; ida->op_work = op->work; ida->op_done = op->done; ida->op_preview = 0; if (ida->op_src.i.width != ida->img.i.width || ida->op_src.i.height != ida->img.i.height) { memset(&ida->current,0,sizeof(ida->current)); viewer_autozoom(ida); } else viewer_new_view(ida); return 0; } int viewer_undo(struct ida_viewer *ida) { int resize; viewer_workfinish(ida); if (NULL == ida->undo.data) return -1; viewer_rubber_off(ida); memset(&ida->current,0,sizeof(ida->current)); resize = (ida->undo.i.width != ida->img.i.width || ida->undo.i.height != ida->img.i.height); free(ida->img.data); ida->img = ida->undo; memset(&ida->undo,0,sizeof(ida->undo)); if (resize) viewer_autozoom(ida); else viewer_new_view(ida); return 0; } int viewer_start_preview(struct ida_viewer *ida, struct ida_op *op, void *parm) { struct ida_image dst; viewer_workfinish(ida); /* try init */ viewer_op_rect(ida); ida->op_data = op->init(&ida->img,&ida->op_rect,&dst.i,parm); if (NULL == ida->op_data) return -1; /* prepare background preview */ ida->op_line = 0; ida->op_work = op->work; ida->op_done = op->done; ida->op_preview = 1; viewer_workstart(ida); return 0; } int viewer_cancel_preview(struct ida_viewer *ida) { viewer_workstop(ida); viewer_workstart(ida); return 0; } int viewer_loader_start(struct ida_viewer *ida, struct ida_loader *loader, FILE *fp, char *filename, unsigned int page) { struct ida_image_info info; void *data; /* init loader */ ptr_busy(); memset(&info,0,sizeof(info)); data = loader->init(fp,filename,page,&info,0); ptr_idle(); if (NULL == data) { fprintf(stderr,"loading %s [%s] FAILED\n",filename,loader->name); if (fp) hex_display(filename); return -1; } /* ok, going to load new image */ viewer_workstop(ida); viewer_rubber_off(ida); memset(&ida->current,0,sizeof(ida->current)); if (ida->undo.data) { free(ida->undo.data); memset(&ida->undo,0,sizeof(ida->undo)); } if (NULL != ida->img.data) free(ida->img.data); ida->file = filename; ida->img.i = info; ida->img.data = malloc(ida->img.i.width * ida->img.i.height * 3); /* prepare background loading */ ida->load_line = 0; ida->load_read = loader->read; ida->load_done = loader->done; ida->load_data = data; viewer_autozoom(ida); return info.npages; } int viewer_loadimage(struct ida_viewer *ida, char *filename, unsigned int page) { struct list_head *item; struct ida_loader *loader; char blk[512]; FILE *fp; if (NULL == (fp = fopen(filename, "r"))) { fprintf(stderr,"fopen %s: %s\n",filename,strerror(errno)); return -1; } if (debug) fprintf(stderr,"load: %s\n",filename); memset(blk,0,sizeof(blk)); fread(blk,1,sizeof(blk),fp); rewind(fp); /* pick loader */ list_for_each(item,&loaders) { loader = list_entry(item, struct ida_loader, list); #if 0 if (NULL == loader->magic) break; #else if (NULL == loader->magic) continue; #endif if (0 == memcmp(blk+loader->moff,loader->magic,loader->mlen)) return viewer_loader_start(ida,loader,fp,filename,page); } fprintf(stderr,"%s: unknown format\n",filename); hex_display(filename); fclose(fp); return -1; } int viewer_setimage(struct ida_viewer *ida, struct ida_image *img, char *name) { /* ok, going to load new image */ viewer_workstop(ida); viewer_rubber_off(ida); memset(&ida->current,0,sizeof(ida->current)); if (ida->undo.data) { free(ida->undo.data); memset(&ida->undo,0,sizeof(ida->undo)); } if (NULL != ida->img.data) free(ida->img.data); ida->file = name; ida->img = *img; viewer_autozoom(ida); return 0; } struct ida_viewer* viewer_init(Widget widget) { Colormap cmap = DefaultColormapOfScreen(XtScreen(widget)); struct ida_viewer *ida; XColor white,red,dummy; unsigned int i; ida = malloc(sizeof(*ida)); memset(ida,0,sizeof(*ida)); ida->widget = widget; XtAddEventHandler(widget,ExposureMask,False,viewer_redraw,ida); XtAddEventHandler(widget, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, False,viewer_mouse,ida); ptrs[POINTER_NORMAL] = XCreateFontCursor(dpy,XC_left_ptr); ptrs[POINTER_BUSY] = XCreateFontCursor(dpy,XC_watch); ptrs[POINTER_PICK] = XCreateFontCursor(dpy,XC_tcross); ptrs[RUBBER_NEW] = XCreateFontCursor(dpy,XC_left_ptr); ptrs[RUBBER_MOVE] = XCreateFontCursor(dpy,XC_fleur); ptrs[RUBBER_X1] = XCreateFontCursor(dpy,XC_sb_h_double_arrow); ptrs[RUBBER_X2] = XCreateFontCursor(dpy,XC_sb_h_double_arrow); ptrs[RUBBER_Y1] = XCreateFontCursor(dpy,XC_sb_v_double_arrow); ptrs[RUBBER_Y2] = XCreateFontCursor(dpy,XC_sb_v_double_arrow); if (XAllocNamedColor(dpy,cmap,"white",&white,&dummy) && XAllocNamedColor(dpy,cmap,"red",&red,&dummy)) for (i = 0; i < sizeof(ptrs)/sizeof(Cursor); i++) XRecolorCursor(dpy,ptrs[i],&red,&white); return ida; }