1 /* Built with libmng-1.0.9
2 * Compiled on linux with gcc-3.3.4
3 * james@blastwave.org suggested the single step mode and wrote:
4 * "xmngview works on Solaris both Sparc and Intel and compiles with Sun's cc"
5 *
6 * <szukw000@students.uni-mainz.de>
7 * This program my be redistributed under the terms of the
8 * GNU General Public Licence, version 2, or at your preference,
9 * any later version.
10 *
11 * For more information about libmng please visit:
12 *
13 * The official libmng web-site:
14 * http://www.libmng.com
15 *
16 * Libmng on SourceForge:
17 * http://libmng.sourceforge.net
18 *
19 * The official MNG homepage:
20 * http://www.libpng.org/pub/mng
21 *
22 * The official PNG homepage:
23 * http://www.libpng.org/pub/png
24 */
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <sys/time.h>
28 #include <ctype.h>
29 #include <libmng.h>
30
31 #include <X11/StringDefs.h>
32 #include <X11/Intrinsic.h>
33 #include <Xm/Xm.h>
34 #include <X11/Xutil.h>
35 #include <Xm/DrawingA.h>
36 #include <Xm/Form.h>
37 #include <Xm/PushB.h>
38 #include <Xm/Frame.h>
39 #include <Xm/RowColumn.h>
40 #include <Xm/FileSB.h>
41 #include <Xm/Label.h>
42 #include <X11/extensions/XShm.h>
43
44 #include "xmng.h"
45
46 #define DEFAULT_BACKGROUND "grey77"
47 static char version[]={"0.6"};
48
49 static void run_viewer(FILE *reader, char *read_idf);
50
51 static mng_handle user_handle;
52 static ImageInfo img;
53 static struct timeval start_tv, now_tv;
54 static XtIntervalId timeout_ID;
55 static char *prg_idf;
56
57 static XtAppContext app_context;
58 static Widget toplevel, main_form, canvas, file_label;
59 static XmFontList file_font;
60 static Dimension start_width;
61
62 #define SLASH '/'
63 /*
64 * Cnf: XQueryColor(3X11)
65 */
parse_rgb_color(char * val)66 static char *parse_rgb_color(char *val)
67 {
68 char *s, *d;
69 int ch;
70 char status, rgb_type;
71 char r[6], g[6], b[6], rgb[24];
72
73 rgb_type = 0;
74 status = 1;
75 s = val;
76 memset(r, 0, 6);
77 memset(g, 0, 6);
78 memset(b, 0, 6);
79
80 if(strncasecmp(s, "rgb:", 4) == 0)
81 {
82 rgb_type = 1;
83 s += 4;
84 if((d = strchr(s, SLASH)))
85 {
86 *d = 0;
87
88 if(d - s > 4)
89 s[4] = 0;
90 strcpy(r, s);
91
92 s = ++d;
93
94 if((d = strchr(s, SLASH)))
95 {
96 *d = 0;
97 if(d - s > 4)
98 s[4] = 0;
99 strcpy(g, s);
100
101 s = d + 1;
102 while((ch = *++d) && isxdigit(ch));
103 *d = 0;
104 if(d - s > 4)
105 s[4] = 0;
106 strcpy(b, s);
107
108 }
109 if(*r == 0 || *g == 0 || *b == 0)
110 return NULL;
111
112 s = r - 1;
113 while((ch = *++s))
114 {
115 if(isxdigit(ch)) continue;
116 status = rgb_type = 0;
117 break;
118 }
119 s = g - 1;
120 while((ch = *++s))
121 {
122 if(isxdigit(ch)) continue;
123 status = rgb_type = 0;
124 break;
125 }
126 s = b - 1;
127 while((ch = *++s))
128 {
129 if(isxdigit(ch)) continue;
130 status = rgb_type = 0;
131 break;
132 }
133 if(status)
134 {
135 strcpy(rgb, "rgb:");
136 d = rgb + 4;
137 s = r;
138 while(*s) *d++ = *s++;
139 *d++ = SLASH;
140 s = g;
141 while(*s) *d++ = *s++;
142 *d++ = SLASH;
143 s = b;
144 while(*s) *d++ = *s++;
145 *d = 0;
146
147 return strdup(rgb);
148 }
149 } /* if((slash = strchr(s, SLASH))) */
150 return NULL;
151 }
152
153 s = val;
154 if(*s == '#' || isdigit(*s))
155 {
156 if(*s != '#')
157 --s;
158 while((ch = *++s))
159 {
160 if(isxdigit(ch)) continue;
161 status = 0;
162 break;
163 }
164 if(status)
165 {
166 d = rgb;
167 s = val;
168 if(*s == '#')
169 ++s;
170 /*
171 * #RGB (4 bits each)
172 * #RRGGBB (8 bits each)
173 * #RRRGGGBBB (12 bits each)
174 * #RRRRGGGGBBBB (16 bits each)
175 */
176 if(strlen(s) > 12)
177 s[12] = 0;
178 *d++ = '#';
179 strcpy(d, s);
180 return strdup(rgb);
181 }
182 return NULL;
183 }
184
185 /*
186 * 'white', 'LavenderBlush', 'dark slate gray', 'grey12'
187 */
188 s = val - 1;
189 while((ch = *++s))
190 {
191 if(isalnum(ch) || isspace(ch)) continue;
192 status = 0;
193 break;
194 }
195 if(!status)
196 return NULL;
197 return strdup(val);
198
199 }/* parse_rgb_color() */
200
set_bg_pixel(ImageInfo * img)201 static void set_bg_pixel(ImageInfo *img)
202 {
203 XColor xcolor;
204 Widget w;
205 char *s, *d;
206 int found;
207
208 w = img->canvas;
209
210 if(!img->has_bg_pixel)
211 {
212 if(img->has_bg_color)
213 {
214 s = strdup(img->bg_color);
215
216 d = parse_rgb_color(s);
217
218 free(s);
219
220 if(d)
221 {
222 strcpy(img->bg_color, d);
223 free(d);
224 }
225 else
226 img->has_bg_color = 0;
227 }
228 if(!img->has_bg_color)
229 {
230 strcpy(img->bg_color, DEFAULT_BACKGROUND);
231 img->has_bg_color = 1;
232 }
233
234 found = XParseColor(img->dpy,
235 DefaultColormap(img->dpy, DefaultScreen(img->dpy)),
236 img->bg_color, &xcolor);
237
238 if(!found)
239 {
240 strcpy(img->bg_color, DEFAULT_BACKGROUND);
241
242 found = XParseColor(img->dpy,
243 DefaultColormap(img->dpy, DefaultScreen(img->dpy)),
244 img->bg_color, &xcolor);
245
246 }
247 xcolor.flags = DoRed | DoGreen | DoBlue;
248
249 XAllocColor(img->dpy,
250 DefaultColormap(img->dpy, DefaultScreen(img->dpy)),
251 &xcolor);
252 }
253 else
254 {
255 xcolor.pixel = img->bg_pixel;
256 xcolor.flags = DoRed|DoGreen|DoBlue;
257
258 found = XQueryColor(img->dpy,
259 DefaultColormap(img->dpy, DefaultScreen(img->dpy)),
260 &xcolor);
261 }
262 img->bg_pixel = xcolor.pixel;
263 img->xbg_red = xcolor.red;
264 img->xbg_green = xcolor.green;
265 img->xbg_blue = xcolor.blue;
266 img->bg_red = (unsigned char)xcolor.red&0xff;
267 img->bg_green = (unsigned char)xcolor.green&0xff;
268 img->bg_blue = (unsigned char)xcolor.blue&0xff;
269 img->has_bg_pixel = 1;
270
271 }/* set_bg_pixel() */
272
fsb_cancel_cb(Widget w,XtPointer client,XtPointer call)273 static void fsb_cancel_cb(Widget w, XtPointer client, XtPointer call)
274 {
275 XtUnmanageChild(w);
276 }
277
create_file_dialog(Widget w,char * button_text,char * title_text,void (* fsb_select_cb)(Widget,XtPointer,XtPointer))278 void create_file_dialog(Widget w, char *button_text, char *title_text,
279 void(*fsb_select_cb)(Widget,XtPointer,XtPointer))
280 {
281 Arg args[4];
282 int cnt;
283 Widget dialog;
284 XmString button_str, title_str, filter;
285 Widget child;
286
287 cnt = 0;
288 dialog = XmCreateFileSelectionDialog(w, "Files", args, cnt);
289
290 XtUnmanageChild(XmFileSelectionBoxGetChild(dialog,XmDIALOG_HELP_BUTTON));
291 XtAddCallback(dialog, XmNcancelCallback, fsb_cancel_cb, NULL);
292 XtAddCallback(dialog, XmNokCallback, fsb_select_cb, NULL);
293 button_str = XmStringCreateLocalized(button_text);
294 title_str = XmStringCreateLocalized(title_text);
295 filter = XmStringCreateLocalized("*.[jmp]ng");
296 XtVaSetValues(dialog,
297 XmNokLabelString, button_str,
298 XmNdialogTitle, title_str,
299 XmNpattern, filter,
300 XmNfileFilterStyle, XmFILTER_NONE,
301 NULL);
302 XmStringFree(button_str);
303 XmStringFree(title_str);
304 XmStringFree(filter);
305 child = XmFileSelectionBoxGetChild(dialog, XmDIALOG_FILTER_TEXT);
306 XtVaSetValues(child, XmNfontList, file_font, NULL);
307 child = XmFileSelectionBoxGetChild(dialog, XmDIALOG_DIR_LIST);
308 XtVaSetValues(child, XmNfontList, file_font, NULL);
309 child = XmFileSelectionBoxGetChild(dialog, XmDIALOG_LIST);
310 XtVaSetValues(child, XmNfontList, file_font, NULL);
311 child = XmFileSelectionBoxGetChild(dialog, XmDIALOG_TEXT);
312 XtVaSetValues(child, XmNfontList, file_font, NULL);
313
314 XtManageChild(dialog);
315 XMapRaised(XtDisplay (dialog), XtWindow (XtParent (dialog)));
316 }
317
run_mng_file_cb(Widget w,XtPointer client,XtPointer call)318 void run_mng_file_cb(Widget w, XtPointer client, XtPointer call)
319 {
320 XmFileSelectionBoxCallbackStruct *fsb;
321 char *read_idf;
322 FILE *reader;
323
324 XtUnmanageChild(w);
325 fsb = (XmFileSelectionBoxCallbackStruct *)call;
326 XmStringGetLtoR(fsb->value, XmSTRING_DEFAULT_CHARSET, &read_idf);
327
328 if(read_idf == NULL || *read_idf == 0) return;
329
330 reader = fopen(read_idf, "r");
331 if(reader == NULL)
332 {
333 perror(read_idf);
334 fprintf(stderr, "\n\n%s: cannot open file '%s'\n\n", prg_idf, read_idf);
335 return;
336 }
337 run_viewer(reader, read_idf);
338
339 free(read_idf);
340 }
341
user_reset_data(void)342 static void user_reset_data(void)
343 {
344 if(timeout_ID) XtRemoveTimeOut(timeout_ID);
345 timeout_ID = 0;
346 mng_cleanup(&img.user_handle);
347
348 img.read_pos = 0;
349 free(img.read_buf);
350 img.read_buf = NULL;
351 img.read_len = 0;
352 img.img_width = 0;
353 img.img_height = 0;
354 img.mng_bytes_per_line = 0;
355 img.read_idf = NULL;
356 img.frozen = 0;
357 img.restarted = 0;
358 img.single_step_wanted = 0;
359 img.single_step_served = 0;
360
361 XClearWindow(img.dpy, img.win);
362 }
363
browse_file_cb(Widget w,XtPointer client,XtPointer call)364 void browse_file_cb(Widget w, XtPointer client, XtPointer call)
365 {
366 if(img.user_handle)
367 user_reset_data();
368
369 img.stopped = 0;
370 img.frozen = 0;
371 img.restarted = 0;
372 create_file_dialog(w, "Select", "Select MNG file", run_mng_file_cb);
373 }
374
Viewer_postlude(void)375 void Viewer_postlude(void)
376 {
377 if(timeout_ID) XtRemoveTimeOut(timeout_ID);
378 mng_cleanup(&img.user_handle);
379 if(img.reader) fclose(img.reader);
380 if(img.ximage) XDestroyImage(img.ximage);
381 if(img.read_buf) free(img.read_buf);
382 if(img.mng_buf) free(img.mng_buf);
383 if(img.dither_line) free(img.dither_line);
384 if(!img.external_win && img.dpy) XtCloseDisplay(img.dpy);
385 fputc('\n', stderr);
386 }
387
user_init_data(ImageInfo * img)388 static void user_init_data(ImageInfo *img)
389 {
390 unsigned int depth;
391 int screen;
392 Display *dpy;
393
394 dpy = img->dpy;
395 screen = DefaultScreen(dpy);
396 depth = DefaultDepth(dpy, screen);
397 img->depth = depth;
398
399 if(!img->visual)
400 {
401 img->visual = DefaultVisual(dpy, screen);
402 img->gc = DefaultGC(dpy, DefaultScreen(dpy));
403 }
404 else
405 {
406 if(img->mng_buf) free(img->mng_buf);
407 if(img->dither_line) free(img->dither_line);
408
409 x11_destroy_ximage(img);
410 }
411
412 set_bg_pixel(img);
413
414 mng_set_bgcolor(img->user_handle,
415 img->xbg_red, img->xbg_green, img->xbg_blue);
416
417 img->mng_bytes_per_line = img->img_width * img->mng_rgb_size;
418 img->mng_buf = (unsigned char*)
419 calloc(1, img->mng_bytes_per_line * img->img_height);
420 img->dither_line = (unsigned char*)
421 calloc(1, img->mng_bytes_per_line);
422
423 if(!img->x11_init)
424 {
425 x11_init_color(img);
426
427 img->x11_init = 1;
428 }
429 img->ximage = x11_create_ximage(img);
430
431 if(img->ximage == NULL)
432 {
433 Viewer_postlude();
434 exit(0);
435 }
436 }
437
player_exit_cb(Widget w,XtPointer client,XtPointer call)438 static void player_exit_cb(Widget w, XtPointer client, XtPointer call)
439 {
440 Viewer_postlude();
441 exit(0);
442 }
443
player_stop_cb(Widget w,XtPointer client,XtPointer call)444 static void player_stop_cb(Widget w, XtPointer client, XtPointer call)
445 {
446 if(img.type != MNG_TYPE) return;
447 if(!img.user_handle) return;
448 if(img.stopped) return;
449
450 user_reset_data();
451 img.stopped = 1;
452 }
453
player_single_step_cb(Widget w,XtPointer client,XtPointer call)454 static void player_single_step_cb(Widget w, XtPointer client, XtPointer call)
455 {
456 if(img.type != MNG_TYPE) return;
457 if(!img.user_handle) return;
458 if(img.stopped) return;
459
460 if(img.single_step_served)
461 {
462 img.single_step_served = 0;
463 img.frozen = 0;
464
465 img.single_step_wanted = 1;
466 return;
467 }
468 if(timeout_ID) XtRemoveTimeOut(timeout_ID);
469 timeout_ID = 0;
470 img.single_step_wanted = 1;
471 mng_display_resume(img.user_handle);
472 }
473
player_pause_cb(Widget w,XtPointer client,XtPointer call)474 static void player_pause_cb(Widget w, XtPointer client, XtPointer call)
475 {
476 if(img.type != MNG_TYPE) return;
477 if(!img.user_handle) return;
478 if(img.stopped) return;
479 if(img.frozen) return;
480
481 if(timeout_ID) XtRemoveTimeOut(timeout_ID);
482 timeout_ID = 0;
483 img.frozen = 1;
484 img.single_step_served = 0;
485 img.single_step_wanted = 0;
486 }
487
player_resume_cb(Widget w,XtPointer client,XtPointer call)488 static void player_resume_cb(Widget w, XtPointer client, XtPointer call)
489 {
490 if(img.type != MNG_TYPE) return;
491 if(!img.user_handle) return;
492 if(img.stopped) return;
493
494 if(!img.frozen
495 && !img.single_step_served)
496 return;
497 img.frozen = 0;
498
499 if(img.single_step_served
500 || img.single_step_wanted)
501 {
502 img.single_step_served = 0;
503 img.single_step_wanted = 0;
504
505 if(timeout_ID) XtRemoveTimeOut(timeout_ID);
506 timeout_ID = 0;
507 }
508 mng_display_resume(img.user_handle);
509 }
510
player_restart_cb(Widget w,XtPointer client,XtPointer call)511 static void player_restart_cb(Widget w, XtPointer client, XtPointer call)
512 {
513 if(img.type != MNG_TYPE) return;
514 if(!img.user_handle) return;
515 if(img.stopped) return;
516
517 img.frozen = 1;
518 if(timeout_ID) XtRemoveTimeOut(timeout_ID);
519 timeout_ID = 0;
520
521 img.frozen = 0;
522 img.single_step_served = 0;
523 img.single_step_wanted = 0;
524
525 img.read_pos = 0;
526 mng_reset(img.user_handle);
527 img.restarted = 1;
528 gettimeofday(&start_tv, NULL);
529 mng_read(img.user_handle);
530 mng_display(img.user_handle);
531 }
532
release_event_cb(Widget w,XtPointer client,XEvent * event,Boolean * cont)533 static void release_event_cb(Widget w, XtPointer client, XEvent *event,
534 Boolean *cont)
535 {
536 Viewer_postlude();
537 exit(0);
538 }
539
redraw(int type)540 static void redraw(int type)
541 {
542 if((type == Expose || type == GraphicsExpose)
543 && img.ximage)
544 {
545 XPutImage(img.dpy, img.win, img.gc, img.ximage,
546 0, 0, 0, 0, img.img_width, img.img_height);
547 }
548 }
549
exposures_cb(Widget w,XtPointer client,XmDrawingAreaCallbackStruct * cbs)550 static void exposures_cb(Widget w, XtPointer client,
551 XmDrawingAreaCallbackStruct *cbs)
552 {
553
554 redraw(cbs->event->xany.type);
555 }
556
user_alloc(mng_size_t len)557 static mng_ptr user_alloc(mng_size_t len)
558 {
559 return calloc(1, len + 2);
560 }
561
user_free(mng_ptr buf,mng_size_t len)562 static void user_free(mng_ptr buf, mng_size_t len)
563 {
564 free(buf);
565 }
566
user_read(mng_handle user_handle,mng_ptr out_buf,mng_uint32 req_len,mng_uint32 * out_len)567 static mng_bool user_read(mng_handle user_handle, mng_ptr out_buf,
568 mng_uint32 req_len, mng_uint32 *out_len)
569 {
570 mng_uint32 more;
571 ImageInfo *img;
572
573 img = (ImageInfo *)mng_get_userdata(user_handle);
574
575 more = img->read_len - img->read_pos;
576
577 if(more > 0
578 && img->read_buf != NULL)
579 {
580 if(req_len < more)
581 more = req_len;
582 memcpy(out_buf, img->read_buf + img->read_pos, more);
583 img->read_pos += more;
584 *out_len = more;
585
586 return MNG_TRUE;
587 }
588 return MNG_FALSE;
589 }
590
user_open_stream(mng_handle user_handle)591 static mng_bool user_open_stream(mng_handle user_handle)
592 {
593 return MNG_TRUE;
594 }
595
user_close_stream(mng_handle user_handle)596 static mng_bool user_close_stream(mng_handle user_handle)
597 {
598 return MNG_TRUE;
599 }
600
create_widgets(mng_uint32 width,mng_uint32 height)601 static void create_widgets(mng_uint32 width, mng_uint32 height)
602 {
603 Widget but_rc, but_frame, canvas_frame;
604 Widget but1, but2, but3, but4, but5, but6, but7;
605
606 toplevel = XtAppInitialize(&app_context, "xmngview", NULL, 0,
607 img.argc_ptr, img.argv,
608 0, 0, 0);
609
610 main_form = XtVaCreateManagedWidget("main_form",
611 xmFormWidgetClass, toplevel,
612 XmNhorizontalSpacing, SPACE_X,
613 XmNverticalSpacing, SPACE_Y,
614 XmNresizable, True,
615 NULL);
616 but_frame = XtVaCreateManagedWidget("but_frame",
617 xmFrameWidgetClass, main_form,
618 XmNshadowType, XmSHADOW_ETCHED_OUT,
619 XmNtopAttachment, XmATTACH_FORM,
620 XmNleftAttachment, XmATTACH_FORM,
621 XmNrightAttachment, XmATTACH_FORM,
622 XmNshadowThickness, FRAME_SHADOW_WIDTH,
623 NULL);
624 but_rc = XtVaCreateManagedWidget("but_rc",
625 xmRowColumnWidgetClass, but_frame,
626 XmNentryAlignment, XmALIGNMENT_CENTER,
627 XmNorientation, XmHORIZONTAL,
628 XmNpacking, XmPACK_COLUMN,
629 XmNnumColumns, 1,
630 XmNresizeWidth, True,
631 XmNentryBorder, BUT_ENTRY_BORDER,
632 NULL);
633 but1 = XtVaCreateManagedWidget("Exit",
634 xmPushButtonWidgetClass, but_rc,
635 NULL);
636 XtAddCallback(but1, XmNactivateCallback,
637 player_exit_cb, (XtPointer)toplevel);
638
639 but2 = XtVaCreateManagedWidget("Pause",
640 xmPushButtonWidgetClass, but_rc,
641 NULL);
642 XtAddCallback(but2, XmNactivateCallback,
643 player_pause_cb, (XtPointer)toplevel);
644
645 but3 = XtVaCreateManagedWidget("GoOn",
646 xmPushButtonWidgetClass, but_rc,
647 NULL);
648 XtAddCallback(but3, XmNactivateCallback,
649 player_resume_cb, NULL);
650
651 but4 = XtVaCreateManagedWidget("Restart",
652 xmPushButtonWidgetClass, but_rc,
653 NULL);
654 XtAddCallback(but4, XmNactivateCallback,
655 player_restart_cb, NULL);
656
657 but5 = XtVaCreateManagedWidget("Step",
658 xmPushButtonWidgetClass, but_rc,
659 NULL);
660 XtAddCallback(but5, XmNactivateCallback,
661 player_single_step_cb, NULL);
662
663 but6 = XtVaCreateManagedWidget("Finish",
664 xmPushButtonWidgetClass, but_rc,
665 NULL);
666 XtAddCallback(but6, XmNactivateCallback,
667 player_stop_cb, NULL);
668
669 but7 = XtVaCreateManagedWidget("Browse",
670 xmPushButtonWidgetClass, but_rc,
671 NULL);
672 XtAddCallback(but7, XmNactivateCallback,
673 browse_file_cb, NULL);
674
675 file_label = XtVaCreateManagedWidget("FILE: ",
676 xmLabelWidgetClass, main_form,
677 XmNalignment, XmALIGNMENT_BEGINNING,
678 XmNtopAttachment, XmATTACH_WIDGET,
679 XmNtopWidget, but_frame,
680 XmNleftAttachment, XmATTACH_FORM,
681 XmNrightAttachment, XmATTACH_FORM,
682 NULL);
683
684 canvas_frame = XtVaCreateManagedWidget("canvas_frame",
685 xmFrameWidgetClass, main_form,
686 XmNshadowType, XmSHADOW_ETCHED_OUT,
687 XmNtopAttachment, XmATTACH_WIDGET,
688 XmNtopWidget, file_label,
689 XmNbottomAttachment, XmATTACH_FORM,
690 XmNleftAttachment, XmATTACH_FORM,
691 XmNrightAttachment, XmATTACH_FORM,
692 NULL);
693
694 canvas = XtVaCreateManagedWidget("canvas",
695 xmDrawingAreaWidgetClass, canvas_frame,
696 XmNheight, height,
697 XmNwidth, width,
698 NULL);
699
700 XtAddEventHandler(canvas,
701 ButtonReleaseMask|ButtonPressMask,
702 False, release_event_cb, (XtPointer)toplevel);
703
704 XtAddCallback(canvas,
705 XmNexposeCallback, (XtCallbackProc)exposures_cb, (XtPointer)&img);
706
707 XtRealizeWidget(toplevel);
708
709 if(start_width == 0)
710 {
711 width = height = 0;
712
713 start_width = (FRAME_SHADOW_WIDTH<<1);
714 XtVaGetValues(but1, XmNwidth, &width, NULL);
715 start_width += width + (BUT_ENTRY_BORDER<<1) + ANY_WIDTH;
716 XtVaGetValues(but2, XmNwidth, &width, NULL);
717 start_width += width + (BUT_ENTRY_BORDER<<1) + ANY_WIDTH;
718 XtVaGetValues(but3, XmNwidth, &width, NULL);
719 start_width += width + (BUT_ENTRY_BORDER<<1) + ANY_WIDTH;
720 XtVaGetValues(but4, XmNwidth, &width, NULL);
721 start_width += width + (BUT_ENTRY_BORDER<<1) + ANY_WIDTH;
722 XtVaGetValues(but5, XmNwidth, &width, NULL);
723 start_width += width + (BUT_ENTRY_BORDER<<1) + ANY_WIDTH;
724 XtVaGetValues(but6, XmNwidth, &width, NULL);
725 start_width += width + (BUT_ENTRY_BORDER<<1);
726 XtVaGetValues(but7, XmNwidth, &width, NULL);
727 start_width += width + (BUT_ENTRY_BORDER<<1);
728 }
729 img.canvas = canvas;
730 img.dpy = XtDisplay(img.canvas);
731 img.win = XtWindow(img.canvas);
732 file_font = XmFontListAppendEntry(NULL,
733 XmFontListEntryCreate(XmFONTLIST_DEFAULT_TAG,
734 XmFONT_IS_FONT,
735 XLoadQueryFont(img.dpy,
736 "-*-helvetica-medium-r-*-*-12-*-*-*-*-*-iso8859-1")));
737 }
738
user_process_header(mng_handle user_handle,mng_uint32 width,mng_uint32 height)739 static mng_bool user_process_header(mng_handle user_handle,
740 mng_uint32 width, mng_uint32 height)
741 {
742 ImageInfo *img;
743 Dimension cw, ch, tw, th, dh, dw, fw, fh;
744 XmString xmstr;
745 char *s, buf[128];
746
747 img = (ImageInfo*)mng_get_userdata(user_handle);
748
749 if(img->restarted)
750 {
751 img->restarted = 0;
752 return MNG_TRUE;
753 }
754 img->img_width = width;
755 img->img_height = height;
756
757 if(!img->external_win)
758 {
759 if(!img->canvas)
760 create_widgets(width, height);
761 else
762 {
763 tw = th = fw = fh = cw = ch = 0;
764
765 XtVaGetValues(toplevel, XmNwidth, &tw, XmNheight, &th, NULL);
766 XtVaGetValues(main_form, XmNwidth, &fw, XmNheight, &fh, NULL);
767 XtVaGetValues(img->canvas, XmNwidth, &cw, XmNheight, &ch, NULL);
768
769 if(height > ch)
770 {
771 dh = height - ch;
772 th += dh;
773 fh += dh;
774 } else
775 if(ch > height)
776 {
777 dh = ch - height;
778 th -= dh;
779 fh -= dh;
780 }
781 if(width > cw)
782 {
783 dw = width - cw;
784 tw += dw;
785 fw += dw;
786 } else
787 if(cw > width)
788 {
789 if(width > start_width)
790 dw = cw - width;
791 else
792 dw = cw - start_width;
793 tw -= dw;
794 fw -= dw;
795 }
796 if(fw < start_width)
797 {
798 tw = start_width + (SPACE_X<<1);
799 fw = start_width;
800 }
801 XtVaSetValues(toplevel, XmNwidth,tw , XmNheight,th , NULL);
802 XtVaSetValues(main_form, XmNwidth,fw , XmNheight,fh , NULL);
803 XtVaSetValues(img->canvas, XmNwidth,width , XmNheight,height , NULL);
804 }
805 }
806 else
807 if(img->external_win)
808 {
809 Display *dpy;
810
811 XtToolkitInitialize();
812 app_context = XtCreateApplicationContext();
813 dpy = XtOpenDisplay(app_context, NULL,NULL,"xmngview",
814 NULL, 0, img->argc_ptr, img->argv);
815 img->dpy = dpy;
816 img->win = img->external_win;
817
818 XSelectInput(dpy, img->win, ExposureMask);
819 }
820 user_init_data(img);
821
822 if(img->canvas)
823 {
824 s = strrchr(img->read_idf, '/');
825 if(s == NULL) s = img->read_idf; else ++s;
826 s = strdup(s);
827 if(strlen(s) > 64) s[64] = 0;
828 sprintf(buf, "%s (%d x %d)", s, img->img_width, img->img_height);
829 xmstr = XmStringCreateLtoR((char*)buf, XmSTRING_DEFAULT_CHARSET);
830 XtVaSetValues(file_label, XmNlabelString, xmstr, NULL);
831 XmStringFree(xmstr);
832 free(s);
833 }
834 gettimeofday(&start_tv, NULL);
835 return MNG_TRUE;
836 }
837
wait_cb(XtPointer client,XtIntervalId * id)838 static void wait_cb(XtPointer client, XtIntervalId * id)
839 {
840 timeout_ID = 0;
841
842 if(img.frozen
843 || img.single_step_served)
844 {
845 // gettimeofday(&start_tv, NULL);
846
847 timeout_ID = XtAppAddTimeOut(app_context,
848 img.delay, wait_cb, NULL);
849 }
850 else
851 {
852 mng_display_resume(img.user_handle);
853 }
854 }
855
user_set_timer(mng_handle user_handle,mng_uint32 delay)856 static mng_bool user_set_timer(mng_handle user_handle, mng_uint32 delay)
857 {
858 ImageInfo *img;
859
860 img = (ImageInfo*)mng_get_userdata(user_handle);
861 img->delay = delay;
862
863 timeout_ID = XtAppAddTimeOut(app_context,
864 delay, wait_cb, NULL);
865
866 return MNG_TRUE;
867 }
868
user_get_tick_count(mng_handle user_handle)869 static mng_uint32 user_get_tick_count(mng_handle user_handle)
870 {
871 double sec, usec;
872 mng_uint32 ticks;
873
874 gettimeofday(&now_tv, NULL);
875
876 sec = (double)(now_tv.tv_sec - start_tv.tv_sec);
877 usec = (double)now_tv.tv_usec - (double)start_tv.tv_usec;
878 ticks = (mng_uint32)(sec * 1000.0 + usec/1000.0);
879 //fprintf(stderr,"TICKS %u (%f:%f)\n", ticks, sec, usec);
880 return ticks;
881 }
882
user_get_canvas_line(mng_handle user_handle,mng_uint32 line)883 static mng_ptr user_get_canvas_line(mng_handle user_handle, mng_uint32 line)
884 {
885 ImageInfo *img;
886
887 img = (ImageInfo*)mng_get_userdata(user_handle);
888
889 return img->mng_buf + img->mng_bytes_per_line * line;
890 }
891
user_refresh(mng_handle user_handle,mng_uint32 x,mng_uint32 y,mng_uint32 width,mng_uint32 height)892 static mng_bool user_refresh(mng_handle user_handle, mng_uint32 x,
893 mng_uint32 y, mng_uint32 width, mng_uint32 height)
894 {
895 ImageInfo *img;
896 mng_uint32 src_len;
897 unsigned char *src_start, *src_buf;
898 int row, max_row;
899 Display *dpy;
900 GC gc;
901 Window win;
902 XImage *ximage;
903 Visual *visual;
904 int have_shmem;
905
906 img = (ImageInfo*)mng_get_userdata(user_handle);
907
908 if(img->single_step_wanted)
909 img->single_step_served = 1;
910
911 win = img->win;
912 gc = img->gc;
913 dpy = img->dpy;
914 ximage = img->ximage;
915 visual = img->visual;
916 have_shmem = img->have_shmem;
917
918 max_row = y + height;
919 row = y;
920 src_len = img->mng_bytes_per_line;
921 src_buf = src_start = img->mng_buf + img->mng_rgb_size * x + y * src_len;
922
923 while(row < max_row)
924 {
925 viewer_renderline(img, src_start, row, x, width);
926
927 ++row;
928 src_start += src_len;
929 }
930 XPUTIMAGE(dpy, win, gc, ximage, x, y, x, y, width, height);
931 XSync(dpy, False);
932 return MNG_TRUE;
933 }
934
user_error(mng_handle user_handle,mng_int32 code,mng_int8 severity,mng_chunkid chunktype,mng_uint32 chunkseq,mng_int32 extra1,mng_int32 extra2,mng_pchar text)935 static mng_bool user_error(mng_handle user_handle, mng_int32 code,
936 mng_int8 severity,
937 mng_chunkid chunktype, mng_uint32 chunkseq,
938 mng_int32 extra1, mng_int32 extra2, mng_pchar text)
939 {
940 ImageInfo *img;
941 unsigned char chunk[5];
942
943 img = (ImageInfo*)mng_get_userdata(user_handle);
944
945 chunk[0] = (char)((chunktype >> 24) & 0xFF);
946 chunk[1] = (char)((chunktype >> 16) & 0xFF);
947 chunk[2] = (char)((chunktype >> 8) & 0xFF);
948 chunk[3] = (char)((chunktype ) & 0xFF);
949 chunk[4] = '\0';
950
951 fprintf(stderr, "\n\n%s: error playing(%s) chunk[%d]'%s':\n",
952 prg_idf, img->read_idf, chunkseq, chunk);
953 fprintf(stderr, "code(%d) severity(%d) extra1(%d) extra2(%d)"
954 "\ntext:'%s'\n\n", code, severity, extra1, extra2, text);
955 return 0;
956 }
957
prelude(void)958 static mng_bool prelude(void)
959 {
960 #define MAXBUF 8
961 unsigned char buf[MAXBUF];
962
963 if(fread(buf, 1, MAXBUF, img.reader) != MAXBUF)
964 {
965 fprintf(stderr,"\n%s:prelude\n\tcannot read signature \n",
966 prg_idf);
967 return MNG_FALSE;
968 }
969
970 if(memcmp(buf, MNG_MAGIC, 8) == 0)
971 img.type = MNG_TYPE;
972 else
973 if(memcmp(buf, JNG_MAGIC, 8) == 0)
974 img.type = JNG_TYPE;
975 else
976 if(memcmp(buf, PNG_MAGIC, 8) == 0)
977 img.type = PNG_TYPE;
978 if(!img.type)
979 {
980 fprintf(stderr,"\n%s:'%s' is no MNG / JNG / PNG file\n",
981 prg_idf, img.read_idf);
982 return MNG_FALSE;
983 }
984 fseek(img.reader, 0, SEEK_SET);
985 fseek(img.reader, 0, SEEK_END);
986 img.read_len = ftell(img.reader);
987 fseek(img.reader, 0, SEEK_SET);
988
989 if(!img.user_handle)
990 {
991 user_handle = mng_initialize(&img, user_alloc, user_free, MNG_NULL);
992
993 if(user_handle == MNG_NULL)
994 {
995 fprintf(stderr, "\n%s: cannot initialize libmng.\n", prg_idf);
996 return MNG_FALSE;
997 }
998 img.user_handle = user_handle;
999
1000 mng_set_canvasstyle(user_handle, MNG_CANVAS_RGB8);
1001 img.mng_rgb_size = CANVAS_RGB8_SIZE;
1002
1003 if(mng_setcb_openstream(user_handle, user_open_stream) != OK
1004 || mng_setcb_closestream(user_handle, user_close_stream) != OK
1005 || mng_setcb_readdata(user_handle, user_read) != OK
1006 || mng_setcb_settimer(user_handle, user_set_timer) != OK
1007 || mng_setcb_gettickcount(user_handle, user_get_tick_count) != OK
1008 || mng_setcb_processheader(user_handle, user_process_header) != OK
1009 || mng_setcb_getcanvasline(user_handle, user_get_canvas_line) != OK
1010 || mng_setcb_refresh(user_handle, user_refresh) != OK
1011 || mng_setcb_errorproc(user_handle, user_error) != OK
1012 )
1013 {
1014 fprintf(stderr,"\n%s: cannot set callbacks for libmng.\n",
1015 prg_idf);
1016 return MNG_FALSE;
1017 }
1018 }
1019 img.read_buf = (unsigned char*)calloc(1, img.read_len + 2);
1020 fread(img.read_buf, 1, img.read_len, img.reader);
1021 fclose(img.reader);
1022 img.reader = NULL;
1023
1024 return MNG_TRUE;
1025 }
1026
run_viewer(FILE * reader,char * read_idf)1027 static void run_viewer(FILE *reader, char *read_idf)
1028 {
1029 XEvent event;
1030
1031 img.read_idf = read_idf;
1032 img.reader = reader;
1033
1034 if(read_idf != NULL)
1035 {
1036 if(prelude() == MNG_FALSE)
1037 return ;
1038
1039 gettimeofday(&start_tv, NULL);
1040
1041 mng_read(img.user_handle);
1042 mng_display(img.user_handle);
1043 }
1044
1045 if(!img.external_win)
1046 {
1047 XtAppMainLoop(app_context);
1048 }
1049 else
1050 while(1)
1051 {
1052 XtAppNextEvent(app_context, &event);
1053
1054 redraw(event.type);
1055 }
1056 }
1057
usage(const char * prg)1058 static void usage(const char *prg)
1059 {
1060 const char *bar=
1061 "\n------------------------------------------------------------------------\n";
1062
1063 fputs(bar, stderr);
1064 fprintf(stderr,"%s version %s\n"
1065 "USAGE: %s [--w WINDOW] [--bg BACKGROUND_COLOR] [FILE]\n",
1066 prg, version, prg);
1067 fputs("\twith BACKGROUND_COLOR = "
1068 "(\"TEXT\" | \"#RGB\" | \"rgb:R/G/B\" | \"PIXEL\")\n"
1069 "\te.g.\n\t(--bg \"red\" | --bg \"#ff0000\" "
1070 "| --bg \"rgb:ff/00/00\" | --bg \"0xf800\")\n"
1071 "\twith FILE=(idf.mng | idf.jng | idf.png)",stderr);
1072 fputs(bar, stderr);
1073 }
1074
shrink_name(char * buf)1075 static void shrink_name(char *buf)
1076 {
1077 char *s, *d;
1078 int ch;
1079
1080 s = d = buf;
1081 while((ch = *s++))
1082 {
1083 if(isspace(ch)) continue;
1084 *d++ = tolower(ch);
1085 }
1086 *d = 0;
1087 }
1088
main(int argc,char ** argv)1089 int main(int argc, char **argv)
1090 {
1091 FILE *reader;
1092 char *read_idf, *s;
1093 char *ok;
1094 int i;
1095 unsigned char has_bg_color, has_bg_pixel;
1096 Window external_win;
1097 Pixel bg_pixel;
1098
1099 if((prg_idf = strrchr(argv[0], '/')) == NULL)
1100 prg_idf = argv[0];
1101 else
1102 ++prg_idf;
1103
1104 memset(&img, 0, sizeof(ImageInfo));
1105 external_win = 0; read_idf = NULL; reader = NULL;
1106 has_bg_color = has_bg_pixel = 0;
1107 bg_pixel = 0;
1108 i = 0;
1109
1110 while(++i < argc)
1111 {
1112 s = argv[i];
1113
1114 if(strcmp(s, "--help") == 0
1115 || strcmp(s, "-help") == 0
1116 || *s == '?')
1117 {
1118 usage(prg_idf);
1119 return 0;
1120 }
1121 if(strcasecmp(s, "--w") == 0)
1122 {
1123 ++i;
1124 s = argv[i];
1125 external_win = strtoul(s, &ok, 10);
1126 if(*ok)
1127 return 0;
1128 continue;
1129 }
1130 if(strcasecmp(s, "--bg") == 0)
1131 {
1132 ++i;
1133 s = argv[i];
1134 if(*s == '#' || strncasecmp(s, "rgb:", 4) == 0 || isalpha(*s))
1135 {
1136 strncpy(img.bg_color, s, MAX_COLORBUF);
1137 img.bg_color[MAX_COLORBUF] = 0;
1138 has_bg_color = 1;
1139
1140 if(*s != '#')
1141 shrink_name(img.bg_color);
1142 continue;
1143 }
1144 bg_pixel = strtoul(s, &ok, 16);
1145
1146 if(*ok == 0)
1147 has_bg_pixel = 1;
1148 continue;
1149 }
1150 if(*s != '-')
1151 {
1152 read_idf = s; continue;
1153 }
1154 }
1155 if(read_idf != NULL)
1156 {
1157 reader = fopen(read_idf, "rb");
1158 if(reader == NULL)
1159 {
1160 perror(read_idf);
1161 fprintf(stderr, "\n\n%s: cannot open file '%s'\n\n", prg_idf, read_idf);
1162 return 0;
1163 }
1164 }
1165 img.argv = argv;
1166 img.argc_ptr = &argc;
1167 img.external_win = external_win;
1168 img.has_bg_pixel = has_bg_pixel;
1169 img.bg_pixel = bg_pixel;
1170 img.has_bg_color = has_bg_color;
1171
1172 if(!has_bg_pixel && !has_bg_color)
1173 {
1174 strcpy(img.bg_color, DEFAULT_BACKGROUND);
1175 img.has_bg_color = 1;
1176 }
1177
1178 if(read_idf == NULL && external_win == 0)
1179 create_widgets(5,5);
1180
1181 run_viewer(reader, read_idf);
1182
1183 Viewer_postlude();
1184 return 0;
1185 }
1186