1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stddef.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <errno.h>
7 #include <math.h>
8 #include <signal.h>
9
10 #include <X11/X.h>
11 #include <X11/Xlib.h>
12 #include <X11/Intrinsic.h>
13 #include <X11/StringDefs.h>
14 #include <X11/cursorfont.h>
15 #include <X11/extensions/XShm.h>
16
17 #include "ida.h"
18 #include "x11.h"
19 #include "dither.h"
20 #include "readers.h"
21 #include "viewer.h"
22 #include "hex.h"
23 #include "idaconfig.h"
24
25 /* ----------------------------------------------------------------------- */
26
27 #define POINTER_NORMAL 0
28 #define POINTER_BUSY 1
29 #define POINTER_PICK 2
30 #define RUBBER_NEW 3
31 #define RUBBER_MOVE 4
32 #define RUBBER_X1 5
33 #define RUBBER_Y1 6
34 #define RUBBER_X2 7
35 #define RUBBER_Y2 8
36
37 #define RUBBER_RANGE 6
38 #define RUBBER_INTERVAL 100
39
40 #define PROCESS_LINES 16
41
42 extern int debug;
43 Cursor ptrs[POINTER_COUNT];
44
45 /* ----------------------------------------------------------------------- */
46
image_to_pixmap(struct ida_image * img)47 Pixmap image_to_pixmap(struct ida_image *img)
48 {
49 unsigned char line[256],*src;
50 XImage *ximage;
51 void *shm;
52 Pixmap pix;
53 GC gc;
54 unsigned int x,y;
55
56 ximage = x11_create_ximage(app_shell, img->i.width, img->i.height, &shm);
57 for (y = 0; y < img->i.height; y++) {
58 src = ida_image_scanline(img, y);
59 if (display_type == PSEUDOCOLOR) {
60 dither_line(src, line, y, img->i.width);
61 for (x = 0; x < img->i.width; x++)
62 XPutPixel(ximage, x, y, x11_map[line[x]]);
63 } else {
64 for (x = 0; x < img->i.width; x++, src += 3) {
65 pix = x11_lut_red[src[0]] |
66 x11_lut_green[src[1]] |
67 x11_lut_blue[src[2]];
68 XPutPixel(ximage, x, y, pix);
69 }
70 }
71 }
72 pix = XCreatePixmap(dpy,XtWindow(app_shell),img->i.width, img->i.height,
73 DefaultDepthOfScreen(XtScreen(app_shell)));
74 gc = XCreateGC(dpy, pix, 0, NULL);
75 XPUTIMAGE(dpy, pix, gc, ximage, 0, 0, 0, 0, img->i.width, img->i.height);
76 XFreeGC(dpy, gc);
77 x11_destroy_ximage(app_shell, ximage, shm);
78 return pix;
79 }
80
81 /* ----------------------------------------------------------------------- */
82
viewer_i2s(int zoom,int val)83 int viewer_i2s(int zoom, int val)
84 {
85 if (0 > zoom)
86 return val/(-zoom+1);
87 if (0 < zoom)
88 return val*(zoom+1);
89 return val;
90 }
91
92 /* ----------------------------------------------------------------------- */
93
94 static void
viewer_renderline(struct ida_viewer * ida,char * scanline)95 viewer_renderline(struct ida_viewer *ida, char *scanline)
96 {
97 unsigned char *src,*dst,*rgb;
98 unsigned long pix;
99 unsigned int x,s,scrline;
100
101 src = scanline;
102
103 if (0 == ida->zoom) {
104 /* as-is */
105 if (display_type == PSEUDOCOLOR) {
106 dst = ida->dither_line;
107 dither_line(src, dst, ida->line, ida->scrwidth);
108 for (x = 0; x < ida->scrwidth; x++, dst++)
109 XPutPixel(ida->ximage, x, ida->line, x11_map[*dst]);
110 } else {
111 for (x = 0; x < ida->scrwidth; x++, src += 3) {
112 pix = x11_lut_red[src[0]] |
113 x11_lut_green[src[1]] |
114 x11_lut_blue[src[2]];
115 XPutPixel(ida->ximage, x, ida->line, pix);
116 }
117 }
118
119 } else if (ida->zoom < 0) {
120 /* zoom out */
121 s = -ida->zoom+1;
122 if (s-1 != (ida->line % s))
123 return;
124 scrline = ida->line/s;
125 if (display_type == PSEUDOCOLOR) {
126 rgb = ida->rgb_line;
127 for (x = 0; x < ida->scrwidth; x++, rgb += 3, src += 3*s) {
128 rgb[0] = src[0];
129 rgb[1] = src[1];
130 rgb[2] = src[2];
131 }
132 rgb = ida->rgb_line;
133 dst = ida->dither_line;
134 dither_line(rgb, dst, scrline, ida->scrwidth);
135 for (x = 0; x < ida->scrwidth; x++, dst++)
136 XPutPixel(ida->ximage, x, scrline, x11_map[*dst]);
137 } else {
138 #if 0
139 /* just drop pixels */
140 for (x = 0; x < ida->scrwidth; x++, src += 3*s) {
141 pix = x11_lut_red[src[0]] |
142 x11_lut_green[src[1]] |
143 x11_lut_blue[src[2]];
144 XPutPixel(ida->ximage, x, scrline, pix);
145 }
146 #else
147 /* horizontal interpolation (vertical is much harder ...) */
148 for (x = 0; x < ida->scrwidth; x++, src += 3*s) {
149 int red,green,blue,count,ix;
150 red = 0;
151 green = 0;
152 blue = 0;
153 count = 0;
154 for (ix = 0; ix < 3*s; ix += 3) {
155 red += src[ix+0];
156 green += src[ix+1];
157 blue += src[ix+2];
158 count += 1;
159 }
160 pix = x11_lut_red[red/count] |
161 x11_lut_green[green/count] |
162 x11_lut_blue[blue/count];
163 XPutPixel(ida->ximage, x, scrline, pix);
164 }
165 #endif
166 }
167
168 } else {
169 /* zoom in */
170 s = ida->zoom+1;
171 if (display_type == PSEUDOCOLOR) {
172 rgb = ida->rgb_line;
173 for (x = 0; x < ida->scrwidth; rgb += 3) {
174 rgb[0] = src[0];
175 rgb[1] = src[1];
176 rgb[2] = src[2];
177 x++;
178 if (0 == (x%s))
179 src += 3;
180 }
181 for (scrline = ida->line*s; scrline < ida->line*s+s; scrline++) {
182 rgb = ida->rgb_line;
183 dst = ida->dither_line;
184 dither_line(rgb, dst, scrline, ida->scrwidth);
185 for (x = 0; x < ida->scrwidth; x++, dst++)
186 XPutPixel(ida->ximage, x, scrline, x11_map[*dst]);
187 }
188 } else {
189 for (scrline = ida->line*s; scrline < ida->line*s+s; scrline++) {
190 src = scanline;
191 for (x = 0; x < ida->scrwidth; src += 3) {
192 unsigned int i;
193 pix = x11_lut_red[src[0]] |
194 x11_lut_green[src[1]] |
195 x11_lut_blue[src[2]];
196 for (i = 0; i < s; i++, x++)
197 XPutPixel(ida->ximage, x, scrline, pix);
198 }
199 }
200 }
201 }
202 }
203
204 /* ----------------------------------------------------------------------- */
205
206 static void
viewer_cleanup(struct ida_viewer * ida)207 viewer_cleanup(struct ida_viewer *ida)
208 {
209 if (ida->load_read) {
210 ida->load_done(ida->load_data);
211 ida->load_line = 0;
212 ida->load_read = NULL;
213 ida->load_done = NULL;
214 ida->load_data = NULL;
215 }
216 if (ida->op_work) {
217 ida->op_done(ida->op_data);
218 ida->op_line = 0;
219 ida->op_work = NULL;
220 ida->op_done = NULL;
221 ida->op_data = NULL;
222 if (ida->op_src.p) {
223 if (ida->undo.p) {
224 fprintf(stderr,"have undo buffer /* shouldn't happen */");
225 ida_image_free(&ida->undo);
226 }
227 ida->undo = ida->op_src;
228 memset(&ida->op_src,0,sizeof(ida->op_src));
229 }
230 }
231 }
232
233 static Boolean
viewer_workproc(XtPointer client_data)234 viewer_workproc(XtPointer client_data)
235 {
236 struct ida_viewer *ida = client_data;
237 unsigned int start,end;
238 char *scanline;
239
240 start = ida->line;
241 end = ida->line + ida->steps;
242 if (end > ida->img.i.height)
243 end = ida->img.i.height;
244
245 /* image loading */
246 if (ida->load_read) {
247 for (ida->line = start; ida->line < end; ida->line++) {
248 if (ida->load_line > ida->line)
249 continue;
250 scanline = ida_image_scanline(&ida->img, ida->load_line);
251 ida->load_read(scanline,ida->load_line,ida->load_data);
252 ida->load_line++;
253 }
254 }
255
256 /* image processing */
257 if (ida->op_work && 0 == ida->op_preview) {
258 for (ida->line = start; ida->line < end; ida->line++) {
259 if (ida->op_line > ida->line)
260 continue;
261 scanline = ida_image_scanline(&ida->img, ida->op_line);
262 ida->op_work(&ida->op_src,&ida->op_rect,
263 scanline,ida->op_line,ida->op_data);
264 ida->op_line++;
265 }
266 }
267
268 /* image rendering */
269 if (ida->op_work && ida->op_preview) {
270 for (ida->line = start; ida->line < end; ida->line++) {
271 ida->op_line = ida->line;
272 ida->op_work(&ida->img,&ida->op_rect,
273 ida->preview_line,ida->line,ida->op_data);
274 viewer_renderline(ida,ida->preview_line);
275 }
276 } else {
277 for (ida->line = start; ida->line < end; ida->line++) {
278 scanline = ida_image_scanline(&ida->img, ida->line);
279 viewer_renderline(ida,scanline);
280 }
281 }
282
283 /* trigger redraw */
284 XClearArea(XtDisplay(ida->widget), XtWindow(ida->widget),
285 0, viewer_i2s(ida->zoom,start),
286 ida->scrwidth, viewer_i2s(ida->zoom,ida->steps), True);
287
288 /* all done ? */
289 if (ida->line == ida->img.i.height) {
290 viewer_cleanup(ida);
291 ida->wproc = 0;
292 #if 1
293 if (args.testload)
294 XtCallActionProc(ida->widget,"Next",NULL,NULL,0);
295 #endif
296 return TRUE;
297 }
298 return FALSE;
299 }
300
viewer_workstart(struct ida_viewer * ida)301 static void viewer_workstart(struct ida_viewer *ida)
302 {
303 /* (re-) start */
304 ida->line = 0;
305 if (!ida->wproc)
306 ida->wproc = XtAppAddWorkProc(app_context,viewer_workproc,ida);
307 }
308
viewer_workstop(struct ida_viewer * ida)309 static void viewer_workstop(struct ida_viewer *ida)
310 {
311 if (!ida->wproc)
312 return;
313
314 viewer_cleanup(ida);
315 XtRemoveWorkProc(ida->wproc);
316 ida->wproc = 0;
317 }
318
viewer_workfinish(struct ida_viewer * ida)319 static void viewer_workfinish(struct ida_viewer *ida)
320 {
321 char *scanline;
322
323 if (ida->load_read) {
324 for (ida->line = ida->load_line; ida->line < ida->img.i.height;) {
325 scanline = ida_image_scanline(&ida->img, ida->line);
326 ida->load_read(scanline,ida->load_line,ida->load_data);
327 ida->line++;
328 ida->load_line++;
329 }
330 }
331 if (ida->op_work && 0 == ida->op_preview) {
332 for (ida->line = ida->op_line; ida->line < ida->img.i.height;) {
333 scanline = ida_image_scanline(&ida->img, ida->line);
334 ida->op_work(&ida->op_src,&ida->op_rect,
335 scanline,ida->op_line,ida->op_data);
336 ida->line++;
337 ida->op_line++;
338 }
339 }
340 viewer_workstop(ida);
341 }
342
343 /* ----------------------------------------------------------------------- */
344
345 static void
viewer_new_view(struct ida_viewer * ida)346 viewer_new_view(struct ida_viewer *ida)
347 {
348 if (NULL != ida->ximage)
349 x11_destroy_ximage(ida->widget,ida->ximage,ida->ximage_shm);
350 if (NULL != ida->rgb_line)
351 free(ida->rgb_line);
352 if (NULL != ida->dither_line)
353 free(ida->dither_line);
354 if (NULL != ida->preview_line)
355 free(ida->preview_line);
356
357 ida->scrwidth = viewer_i2s(ida->zoom,ida->img.i.width);
358 ida->scrheight = viewer_i2s(ida->zoom,ida->img.i.height);
359 ida->steps = PROCESS_LINES;
360 if (ida->zoom < 0)
361 while ((ida->steps % (-ida->zoom+1)) != 0)
362 ida->steps++;
363
364 ida->rgb_line = malloc(ida->scrwidth*3);
365 ida->dither_line = malloc(ida->scrwidth);
366 ida->preview_line = malloc(ida->img.i.width*3);
367 ida->ximage = x11_create_ximage(ida->widget, ida->scrwidth, ida->scrheight,
368 &ida->ximage_shm);
369 if (NULL == ida->ximage) {
370 ida->zoom--;
371 return viewer_new_view(ida);
372 }
373 XtVaSetValues(ida->widget,
374 XtNwidth, ida->scrwidth,
375 XtNheight, ida->scrheight,
376 NULL);
377 viewer_workstart(ida);
378 }
379
380 static void
381 viewer_timeout(XtPointer client_data, XtIntervalId *id);
382
383 static int
viewer_rubber_draw(struct ida_viewer * ida)384 viewer_rubber_draw(struct ida_viewer *ida)
385 {
386 XGCValues values;
387 struct ida_rect r = ida->current;
388 int x,y,w,h;
389
390 values.function = GXxor;
391 values.foreground = ida->mask;
392 XChangeGC(dpy,ida->wgc,GCFunction|GCForeground,&values);
393 if (r.x1 < r.x2) {
394 x = viewer_i2s(ida->zoom,r.x1);
395 w = viewer_i2s(ida->zoom,r.x2 - r.x1);
396 } else {
397 x = viewer_i2s(ida->zoom,r.x2);
398 w = viewer_i2s(ida->zoom,r.x1 - r.x2);
399 }
400 if (r.y1 < r.y2) {
401 y = viewer_i2s(ida->zoom,r.y1);
402 h = viewer_i2s(ida->zoom,r.y2 - r.y1);
403 } else {
404 y = viewer_i2s(ida->zoom,r.y2);
405 h = viewer_i2s(ida->zoom,r.y1 - r.y2);
406 }
407 if (0 == h && 0 == w)
408 return 0;
409 if (w)
410 w--;
411 if (h)
412 h--;
413 XDrawRectangle(dpy,XtWindow(ida->widget),ida->wgc,x,y,w,h);
414 return 1;
415 }
416
417 static void
viewer_rubber_off(struct ida_viewer * ida)418 viewer_rubber_off(struct ida_viewer *ida)
419 {
420 if (ida->marked)
421 viewer_rubber_draw(ida);
422 ida->marked = 0;
423 if (ida->timer)
424 XtRemoveTimeOut(ida->timer);
425 ida->timer = 0;
426 }
427
428 static void
viewer_rubber_on(struct ida_viewer * ida)429 viewer_rubber_on(struct ida_viewer *ida)
430 {
431 ida->marked = viewer_rubber_draw(ida);
432 if (ida->marked)
433 ida->timer = XtAppAddTimeOut(app_context,RUBBER_INTERVAL,
434 viewer_timeout,ida);
435 }
436
437 static void
viewer_timeout(XtPointer client_data,XtIntervalId * id)438 viewer_timeout(XtPointer client_data, XtIntervalId *id)
439 {
440 struct ida_viewer *ida = client_data;
441
442 ida->timer = 0;
443 viewer_rubber_off(ida);
444 ida->mask <<= 1;
445 if ((ida->mask & 0x10) == 0x10)
446 ida->mask |= 0x01;
447 viewer_rubber_on(ida);
448 }
449
450 static void
viewer_redraw(Widget widget,XtPointer client_data,XEvent * ev,Boolean * cont)451 viewer_redraw(Widget widget, XtPointer client_data,
452 XEvent *ev, Boolean *cont)
453 {
454 struct ida_viewer *ida = client_data;
455 XExposeEvent *event;
456 XGCValues values;
457
458 if (ev->type != Expose)
459 return;
460 event = (XExposeEvent*)ev;
461
462 if (NULL == ida->ximage)
463 return;
464 if (event->x + event->width > (int)ida->scrwidth)
465 return;
466 if (event->y + event->height > (int)ida->scrheight)
467 return;
468 if (NULL == ida->wgc)
469 ida->wgc = XCreateGC(XtDisplay(widget), XtWindow(widget), 0, NULL);
470
471 viewer_rubber_off(ida);
472 values.function = GXcopy;
473 XChangeGC(dpy,ida->wgc,GCFunction,&values);
474 XPUTIMAGE(XtDisplay(ida->widget), XtWindow(widget),
475 ida->wgc, ida->ximage,
476 event->x, event->y, event->x, event->y,
477 event->width, event->height);
478 viewer_rubber_on(ida);
479 }
480
481 static int
viewer_pos2state(struct ida_viewer * ida,int x,int y)482 viewer_pos2state(struct ida_viewer *ida, int x, int y)
483 {
484 int x1,x2,y1,y2;
485
486 if (POINTER_PICK == ida->state)
487 return ida->state;
488
489 x1 = viewer_i2s(ida->zoom,ida->current.x1);
490 x2 = viewer_i2s(ida->zoom,ida->current.x2);
491 y1 = viewer_i2s(ida->zoom,ida->current.y1);
492 y2 = viewer_i2s(ida->zoom,ida->current.y2);
493 if ((x1 < x && x < x2) || (x2 < x && x < x1)) {
494 if (y1-RUBBER_RANGE < y && y < y1+RUBBER_RANGE)
495 return RUBBER_Y1;
496 if (y2-RUBBER_RANGE < y && y < y2+RUBBER_RANGE)
497 return RUBBER_Y2;
498 }
499 if ((y1 < y && y < y2) || (y2 < y && y < y1)) {
500 if (x1-RUBBER_RANGE < x && x < x1+RUBBER_RANGE)
501 return RUBBER_X1;
502 if (x2-RUBBER_RANGE < x && x < x2+RUBBER_RANGE)
503 return RUBBER_X2;
504 }
505 if (((x1 < x && x < x2) || (x2 < x && x < x1)) &&
506 ((y1 < y && y < y2) || (y2 < y && y < y1)))
507 return RUBBER_MOVE;
508 return RUBBER_NEW;
509 }
510
511 static void
viewer_mouse(Widget widget,XtPointer client_data,XEvent * ev,Boolean * cont)512 viewer_mouse(Widget widget, XtPointer client_data,
513 XEvent *ev, Boolean *cont)
514 {
515 struct ida_viewer *ida = client_data;
516 int state = POINTER_NORMAL;
517 unsigned char *pix;
518 int x,y;
519
520 viewer_rubber_off(ida);
521
522 switch (ev->type) {
523 case ButtonPress:
524 {
525 XButtonEvent *eb = (XButtonEvent*)ev;
526
527 if (eb->button != Button1)
528 goto out;
529 ida->state = viewer_pos2state(ida,eb->x,eb->y);
530 switch (ida->state) {
531 case POINTER_PICK:
532 x = viewer_i2s(-ida->zoom,eb->x);
533 y = viewer_i2s(-ida->zoom,eb->y);
534 pix = ida_image_scanline(&ida->img, y) + x * 3;
535 ida->pick_cb(x,y,pix,ida->pick_data);
536 ida->pick_cb = NULL;
537 ida->pick_data = NULL;
538 ida->state = POINTER_NORMAL;
539 state = POINTER_NORMAL;
540 break;
541 case RUBBER_NEW:
542 ida->mask = 0x33333333;
543 ida->current.x1 = ida->current.x2 = viewer_i2s(-ida->zoom,eb->x);
544 ida->current.y1 = ida->current.y2 = viewer_i2s(-ida->zoom,eb->y);
545 break;
546 case RUBBER_MOVE:
547 ida->last_x = viewer_i2s(-ida->zoom,eb->x);
548 ida->last_y = viewer_i2s(-ida->zoom,eb->y);
549 break;
550 case RUBBER_X1:
551 ida->current.x1 = viewer_i2s(-ida->zoom,eb->x);
552 break;
553 case RUBBER_Y1:
554 ida->current.y1 = viewer_i2s(-ida->zoom,eb->y);
555 break;
556 case RUBBER_X2:
557 ida->current.x2 = viewer_i2s(-ida->zoom,eb->x);
558 break;
559 case RUBBER_Y2:
560 ida->current.y2 = viewer_i2s(-ida->zoom,eb->y);
561 break;
562 }
563 state = ida->state;
564 break;
565 }
566 case MotionNotify:
567 {
568 XMotionEvent *em = (XMotionEvent*)ev;
569
570 if (!(em->state & Button1Mask)) {
571 state = viewer_pos2state(ida,em->x,em->y);
572 goto out;
573 }
574 switch (ida->state) {
575 case RUBBER_NEW:
576 ida->current.x2 = viewer_i2s(-ida->zoom,em->x);
577 ida->current.y2 = viewer_i2s(-ida->zoom,em->y);
578 if (em->state & ShiftMask) {
579 /* square selection */
580 int xlen,ylen;
581 xlen = abs(ida->current.x1 - ida->current.x2);
582 ylen = abs(ida->current.y1 - ida->current.y2);
583 if (ylen > xlen) {
584 if (ida->current.x1 < ida->current.x2)
585 ida->current.x2 -= (xlen - ylen);
586 else
587 ida->current.x2 += (xlen - ylen);
588 } else {
589 if (ida->current.y1 < ida->current.y2)
590 ida->current.y2 -= (ylen - xlen);
591 else
592 ida->current.y2 += (ylen - xlen);
593 }
594 }
595 break;
596 case RUBBER_MOVE:
597 x = viewer_i2s(-ida->zoom,em->x);
598 y = viewer_i2s(-ida->zoom,em->y);
599 ida->current.x1 += (x - ida->last_x);
600 ida->current.x2 += (x - ida->last_x);
601 ida->current.y1 += (y - ida->last_y);
602 ida->current.y2 += (y - ida->last_y);
603 ida->last_x = x;
604 ida->last_y = y;
605 break;
606 case RUBBER_X1:
607 ida->current.x1 = viewer_i2s(-ida->zoom,em->x);
608 break;
609 case RUBBER_Y1:
610 ida->current.y1 = viewer_i2s(-ida->zoom,em->y);
611 break;
612 case RUBBER_X2:
613 ida->current.x2 = viewer_i2s(-ida->zoom,em->x);
614 break;
615 case RUBBER_Y2:
616 ida->current.y2 = viewer_i2s(-ida->zoom,em->y);
617 break;
618 }
619 state = ida->state;
620 break;
621 }
622 case ButtonRelease:
623 {
624 XButtonEvent *eb = (XButtonEvent*)ev;
625
626 if (eb->button != Button1)
627 goto out;
628 ida->state = POINTER_NORMAL;
629 state = ida->state;
630 break;
631 }
632 }
633
634 if (ida->current.x1 < 0)
635 ida->current.x1 = 0;
636 if (ida->current.x1 > ida->img.i.width)
637 ida->current.x1 = ida->img.i.width;
638 if (ida->current.x2 < 0)
639 ida->current.x2 = 0;
640 if (ida->current.x2 > ida->img.i.width)
641 ida->current.x2 = ida->img.i.width;
642 if (ida->current.y1 < 0)
643 ida->current.y1 = 0;
644 if (ida->current.y1 > ida->img.i.height)
645 ida->current.y1 = ida->img.i.height;
646 if (ida->current.y2 < 0)
647 ida->current.y2 = 0;
648 if (ida->current.y2 > ida->img.i.height)
649 ida->current.y2 = ida->img.i.height;
650
651 out:
652 XDefineCursor(dpy, XtWindow(widget), ptrs[state]);
653 viewer_rubber_on(ida);
654 }
655
656 /* ----------------------------------------------------------------------- */
657 /* public stuff */
658
viewer_pick(struct ida_viewer * ida,viewer_pick_cb cb,XtPointer data)659 void viewer_pick(struct ida_viewer *ida, viewer_pick_cb cb, XtPointer data)
660 {
661 if (POINTER_NORMAL != ida->state)
662 return;
663 if (debug)
664 fprintf(stderr,"viewer_pick\n");
665 ida->state = POINTER_PICK;
666 ida->pick_cb = cb;
667 ida->pick_data = data;
668 }
669
viewer_unpick(struct ida_viewer * ida)670 void viewer_unpick(struct ida_viewer *ida)
671 {
672 if (POINTER_PICK != ida->state)
673 return;
674 if (debug)
675 fprintf(stderr,"viewer_unpick\n");
676 ida->state = POINTER_NORMAL;
677 ida->pick_cb = NULL;
678 ida->pick_data = NULL;
679 }
680
681 void
viewer_autozoom(struct ida_viewer * ida)682 viewer_autozoom(struct ida_viewer *ida)
683 {
684 if (GET_AUTOZOOM()) {
685 ida->zoom = 0;
686 while (XtScreen(ida->widget)->width < viewer_i2s(ida->zoom,ida->img.i.width) ||
687 XtScreen(ida->widget)->height < viewer_i2s(ida->zoom,ida->img.i.height))
688 ida->zoom--;
689 }
690 viewer_new_view(ida);
691 }
692
693 void
viewer_setzoom(struct ida_viewer * ida,int zoom)694 viewer_setzoom(struct ida_viewer *ida, int zoom)
695 {
696 ida->zoom = zoom;
697 viewer_new_view(ida);
698 }
699
700 static void
viewer_op_rect(struct ida_viewer * ida)701 viewer_op_rect(struct ida_viewer *ida)
702 {
703 if (ida->current.x1 == ida->current.x2 &&
704 ida->current.y1 == ida->current.y2) {
705 /* full image */
706 ida->op_rect.x1 = 0;
707 ida->op_rect.x2 = ida->img.i.width;
708 ida->op_rect.y1 = 0;
709 ida->op_rect.y2 = ida->img.i.height;
710 return;
711 } else {
712 /* have selection */
713 if (ida->current.x1 < ida->current.x2) {
714 ida->op_rect.x1 = ida->current.x1;
715 ida->op_rect.x2 = ida->current.x2;
716 } else {
717 ida->op_rect.x1 = ida->current.x2;
718 ida->op_rect.x2 = ida->current.x1;
719 }
720 if (ida->current.y1 < ida->current.y2) {
721 ida->op_rect.y1 = ida->current.y1;
722 ida->op_rect.y2 = ida->current.y2;
723 } else {
724 ida->op_rect.y1 = ida->current.y2;
725 ida->op_rect.y2 = ida->current.y1;
726 }
727 }
728 }
729
730 int
viewer_start_op(struct ida_viewer * ida,struct ida_op * op,void * parm)731 viewer_start_op(struct ida_viewer *ida, struct ida_op *op, void *parm)
732 {
733 struct ida_image dst;
734
735 ptr_busy();
736 viewer_workfinish(ida);
737 viewer_rubber_off(ida);
738
739 /* try init */
740 viewer_op_rect(ida);
741 if (debug)
742 fprintf(stderr,"viewer_start_op: init %s(%p)\n",op->name,parm);
743 memset(&dst, 0, sizeof(dst));
744 ida->op_data = op->init(&ida->img,&ida->op_rect,&dst.i,parm);
745 ptr_idle();
746 if (NULL == ida->op_data)
747 return -1;
748 ida_image_alloc(&dst);
749
750 /* prepare background processing */
751 if (ida->undo.p) {
752 ida_image_free(&ida->undo);
753 memset(&ida->undo,0,sizeof(ida->undo));
754 }
755 if (ida->op_src.p) {
756 fprintf(stderr,"have op_src buffer /* shouldn't happen */");
757 ida_image_free(&ida->op_src);
758 }
759 ida->op_src = ida->img;
760 ida->img = dst;
761 ida->op_line = 0;
762 ida->op_work = op->work;
763 ida->op_done = op->done;
764 ida->op_preview = 0;
765
766 if (ida->op_src.i.width != ida->img.i.width ||
767 ida->op_src.i.height != ida->img.i.height) {
768 memset(&ida->current,0,sizeof(ida->current));
769 viewer_autozoom(ida);
770 } else
771 viewer_new_view(ida);
772 return 0;
773 }
774
775 int
viewer_undo(struct ida_viewer * ida)776 viewer_undo(struct ida_viewer *ida)
777 {
778 int resize;
779
780 viewer_workfinish(ida);
781 if (NULL == ida->undo.p)
782 return -1;
783 viewer_rubber_off(ida);
784 memset(&ida->current,0,sizeof(ida->current));
785
786 resize = (ida->undo.i.width != ida->img.i.width ||
787 ida->undo.i.height != ida->img.i.height);
788 ida_image_free(&ida->img);
789 ida->img = ida->undo;
790 memset(&ida->undo,0,sizeof(ida->undo));
791
792 if (resize)
793 viewer_autozoom(ida);
794 else
795 viewer_new_view(ida);
796 return 0;
797 }
798
799 int
viewer_start_preview(struct ida_viewer * ida,struct ida_op * op,void * parm)800 viewer_start_preview(struct ida_viewer *ida, struct ida_op *op, void *parm)
801 {
802 struct ida_image dst;
803
804 viewer_workfinish(ida);
805
806 /* try init */
807 viewer_op_rect(ida);
808 ida->op_data = op->init(&ida->img,&ida->op_rect,&dst.i,parm);
809 if (NULL == ida->op_data)
810 return -1;
811
812 /* prepare background preview */
813 ida->op_line = 0;
814 ida->op_work = op->work;
815 ida->op_done = op->done;
816 ida->op_preview = 1;
817
818 viewer_workstart(ida);
819 return 0;
820 }
821
822 int
viewer_cancel_preview(struct ida_viewer * ida)823 viewer_cancel_preview(struct ida_viewer *ida)
824 {
825 viewer_workstop(ida);
826 viewer_workstart(ida);
827 return 0;
828 }
829
830 int
viewer_loader_start(struct ida_viewer * ida,struct ida_loader * loader,FILE * fp,char * filename,unsigned int page)831 viewer_loader_start(struct ida_viewer *ida, struct ida_loader *loader,
832 FILE *fp, char *filename, unsigned int page)
833 {
834 struct ida_image_info info;
835 void *data;
836
837 /* init loader */
838 ptr_busy();
839 memset(&info,0,sizeof(info));
840 data = loader->init(fp,filename,page,&info,0);
841 ptr_idle();
842 if (NULL == data) {
843 fprintf(stderr,"loading %s [%s] FAILED\n",filename,loader->name);
844 if (fp)
845 hex_display(filename);
846 return -1;
847 }
848
849 /* ok, going to load new image */
850 viewer_workstop(ida);
851 viewer_rubber_off(ida);
852 memset(&ida->current,0,sizeof(ida->current));
853 if (ida->undo.p) {
854 ida_image_free(&ida->undo);
855 memset(&ida->undo,0,sizeof(ida->undo));
856 }
857 if (NULL != ida->img.p)
858 ida_image_free(&ida->img);
859 ida->file = filename;
860 ida->img.i = info;
861 ida_image_alloc(&ida->img);
862
863 /* prepare background loading */
864 ida->load_line = 0;
865 ida->load_read = loader->read;
866 ida->load_done = loader->done;
867 ida->load_data = data;
868
869 viewer_autozoom(ida);
870 return info.npages;
871 }
872
873 int
viewer_loadimage(struct ida_viewer * ida,char * filename,unsigned int page)874 viewer_loadimage(struct ida_viewer *ida, char *filename, unsigned int page)
875 {
876 struct list_head *item;
877 struct ida_loader *loader;
878 char blk[512];
879 FILE *fp;
880
881 if (NULL == (fp = fopen(filename, "r"))) {
882 fprintf(stderr,"fopen %s: %s\n",filename,strerror(errno));
883 return -1;
884 }
885 if (debug)
886 fprintf(stderr,"load: %s\n",filename);
887 memset(blk,0,sizeof(blk));
888 fread(blk,1,sizeof(blk),fp);
889 rewind(fp);
890
891 /* pick loader */
892 list_for_each(item,&loaders) {
893 loader = list_entry(item, struct ida_loader, list);
894 #if 0
895 if (NULL == loader->magic)
896 break;
897 #else
898 if (NULL == loader->magic)
899 continue;
900 #endif
901 if (0 == memcmp(blk+loader->moff,loader->magic,loader->mlen))
902 return viewer_loader_start(ida,loader,fp,filename,page);
903 }
904 fprintf(stderr,"%s: unknown format\n",filename);
905 hex_display(filename);
906 fclose(fp);
907 return -1;
908 }
909
910 int
viewer_setimage(struct ida_viewer * ida,struct ida_image * img,char * name)911 viewer_setimage(struct ida_viewer *ida, struct ida_image *img, char *name)
912 {
913 /* ok, going to load new image */
914 viewer_workstop(ida);
915 viewer_rubber_off(ida);
916 memset(&ida->current,0,sizeof(ida->current));
917 if (ida->undo.p) {
918 ida_image_free(&ida->undo);
919 memset(&ida->undo,0,sizeof(ida->undo));
920 }
921
922 if (NULL != ida->img.p)
923 ida_image_free(&ida->img);
924 ida->file = name;
925 ida->img = *img;
926
927 viewer_autozoom(ida);
928 return 0;
929 }
930
931 struct ida_viewer*
viewer_init(Widget widget)932 viewer_init(Widget widget)
933 {
934 Colormap cmap = DefaultColormapOfScreen(XtScreen(widget));
935 struct ida_viewer *ida;
936 XColor white,red,dummy;
937 unsigned int i;
938
939 ida = malloc(sizeof(*ida));
940 memset(ida,0,sizeof(*ida));
941 ida->widget = widget;
942 XtAddEventHandler(widget,ExposureMask,False,viewer_redraw,ida);
943 XtAddEventHandler(widget,
944 ButtonPressMask |
945 ButtonReleaseMask |
946 PointerMotionMask,
947 False,viewer_mouse,ida);
948
949 ptrs[POINTER_NORMAL] = XCreateFontCursor(dpy,XC_left_ptr);
950 ptrs[POINTER_BUSY] = XCreateFontCursor(dpy,XC_watch);
951 ptrs[POINTER_PICK] = XCreateFontCursor(dpy,XC_tcross);
952 ptrs[RUBBER_NEW] = XCreateFontCursor(dpy,XC_left_ptr);
953 ptrs[RUBBER_MOVE] = XCreateFontCursor(dpy,XC_fleur);
954 ptrs[RUBBER_X1] = XCreateFontCursor(dpy,XC_sb_h_double_arrow);
955 ptrs[RUBBER_X2] = XCreateFontCursor(dpy,XC_sb_h_double_arrow);
956 ptrs[RUBBER_Y1] = XCreateFontCursor(dpy,XC_sb_v_double_arrow);
957 ptrs[RUBBER_Y2] = XCreateFontCursor(dpy,XC_sb_v_double_arrow);
958 if (XAllocNamedColor(dpy,cmap,"white",&white,&dummy) &&
959 XAllocNamedColor(dpy,cmap,"red",&red,&dummy))
960 for (i = 0; i < sizeof(ptrs)/sizeof(Cursor); i++)
961 XRecolorCursor(dpy,ptrs[i],&red,&white);
962
963 return ida;
964 }
965