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