Torque3D/Engine/lib/lmng/contrib/gcc/xmngview/xmngview.c
2012-09-19 11:15:01 -04:00

1185 lines
26 KiB
C

/* Built with libmng-1.0.9
* Compiled on linux with gcc-3.3.4
* james@blastwave.org suggested the single step mode and wrote:
* "xmngview works on Solaris both Sparc and Intel and compiles with Sun's cc"
*
* <szukw000@students.uni-mainz.de>
* This program my be redistributed under the terms of the
* GNU General Public Licence, version 2, or at your preference,
* any later version.
*
* For more information about libmng please visit:
*
* The official libmng web-site:
* http://www.libmng.com
*
* Libmng on SourceForge:
* http://libmng.sourceforge.net
*
* The official MNG homepage:
* http://www.libpng.org/pub/mng
*
* The official PNG homepage:
* http://www.libpng.org/pub/png
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#include <ctype.h>
#include <libmng.h>
#include <X11/StringDefs.h>
#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <X11/Xutil.h>
#include <Xm/DrawingA.h>
#include <Xm/Form.h>
#include <Xm/PushB.h>
#include <Xm/Frame.h>
#include <Xm/RowColumn.h>
#include <Xm/FileSB.h>
#include <Xm/Label.h>
#include <X11/extensions/XShm.h>
#include "xmng.h"
#define DEFAULT_BACKGROUND "grey77"
static char version[]={"0.6"};
static void run_viewer(FILE *reader, char *read_idf);
static mng_handle user_handle;
static ImageInfo img;
static struct timeval start_tv, now_tv;
static XtIntervalId timeout_ID;
static char *prg_idf;
static XtAppContext app_context;
static Widget toplevel, main_form, canvas, file_label;
static XmFontList file_font;
static Dimension start_width;
#define SLASH '/'
/*
* Cnf: XQueryColor(3X11)
*/
static char *parse_rgb_color(char *val)
{
char *s, *d;
int ch;
char status, rgb_type;
char r[6], g[6], b[6], rgb[24];
rgb_type = 0;
status = 1;
s = val;
memset(r, 0, 6);
memset(g, 0, 6);
memset(b, 0, 6);
if(strncasecmp(s, "rgb:", 4) == 0)
{
rgb_type = 1;
s += 4;
if((d = strchr(s, SLASH)))
{
*d = 0;
if(d - s > 4)
s[4] = 0;
strcpy(r, s);
s = ++d;
if((d = strchr(s, SLASH)))
{
*d = 0;
if(d - s > 4)
s[4] = 0;
strcpy(g, s);
s = d + 1;
while((ch = *++d) && isxdigit(ch));
*d = 0;
if(d - s > 4)
s[4] = 0;
strcpy(b, s);
}
if(*r == 0 || *g == 0 || *b == 0)
return NULL;
s = r - 1;
while((ch = *++s))
{
if(isxdigit(ch)) continue;
status = rgb_type = 0;
break;
}
s = g - 1;
while((ch = *++s))
{
if(isxdigit(ch)) continue;
status = rgb_type = 0;
break;
}
s = b - 1;
while((ch = *++s))
{
if(isxdigit(ch)) continue;
status = rgb_type = 0;
break;
}
if(status)
{
strcpy(rgb, "rgb:");
d = rgb + 4;
s = r;
while(*s) *d++ = *s++;
*d++ = SLASH;
s = g;
while(*s) *d++ = *s++;
*d++ = SLASH;
s = b;
while(*s) *d++ = *s++;
*d = 0;
return strdup(rgb);
}
} /* if((slash = strchr(s, SLASH))) */
return NULL;
}
s = val;
if(*s == '#' || isdigit(*s))
{
if(*s != '#')
--s;
while((ch = *++s))
{
if(isxdigit(ch)) continue;
status = 0;
break;
}
if(status)
{
d = rgb;
s = val;
if(*s == '#')
++s;
/*
* #RGB (4 bits each)
* #RRGGBB (8 bits each)
* #RRRGGGBBB (12 bits each)
* #RRRRGGGGBBBB (16 bits each)
*/
if(strlen(s) > 12)
s[12] = 0;
*d++ = '#';
strcpy(d, s);
return strdup(rgb);
}
return NULL;
}
/*
* 'white', 'LavenderBlush', 'dark slate gray', 'grey12'
*/
s = val - 1;
while((ch = *++s))
{
if(isalnum(ch) || isspace(ch)) continue;
status = 0;
break;
}
if(!status)
return NULL;
return strdup(val);
}/* parse_rgb_color() */
static void set_bg_pixel(ImageInfo *img)
{
XColor xcolor;
Widget w;
char *s, *d;
int found;
w = img->canvas;
if(!img->has_bg_pixel)
{
if(img->has_bg_color)
{
s = strdup(img->bg_color);
d = parse_rgb_color(s);
free(s);
if(d)
{
strcpy(img->bg_color, d);
free(d);
}
else
img->has_bg_color = 0;
}
if(!img->has_bg_color)
{
strcpy(img->bg_color, DEFAULT_BACKGROUND);
img->has_bg_color = 1;
}
found = XParseColor(img->dpy,
DefaultColormap(img->dpy, DefaultScreen(img->dpy)),
img->bg_color, &xcolor);
if(!found)
{
strcpy(img->bg_color, DEFAULT_BACKGROUND);
found = XParseColor(img->dpy,
DefaultColormap(img->dpy, DefaultScreen(img->dpy)),
img->bg_color, &xcolor);
}
xcolor.flags = DoRed | DoGreen | DoBlue;
XAllocColor(img->dpy,
DefaultColormap(img->dpy, DefaultScreen(img->dpy)),
&xcolor);
}
else
{
xcolor.pixel = img->bg_pixel;
xcolor.flags = DoRed|DoGreen|DoBlue;
found = XQueryColor(img->dpy,
DefaultColormap(img->dpy, DefaultScreen(img->dpy)),
&xcolor);
}
img->bg_pixel = xcolor.pixel;
img->xbg_red = xcolor.red;
img->xbg_green = xcolor.green;
img->xbg_blue = xcolor.blue;
img->bg_red = (unsigned char)xcolor.red&0xff;
img->bg_green = (unsigned char)xcolor.green&0xff;
img->bg_blue = (unsigned char)xcolor.blue&0xff;
img->has_bg_pixel = 1;
}/* set_bg_pixel() */
static void fsb_cancel_cb(Widget w, XtPointer client, XtPointer call)
{
XtUnmanageChild(w);
}
void create_file_dialog(Widget w, char *button_text, char *title_text,
void(*fsb_select_cb)(Widget,XtPointer,XtPointer))
{
Arg args[4];
int cnt;
Widget dialog;
XmString button_str, title_str, filter;
Widget child;
cnt = 0;
dialog = XmCreateFileSelectionDialog(w, "Files", args, cnt);
XtUnmanageChild(XmFileSelectionBoxGetChild(dialog,XmDIALOG_HELP_BUTTON));
XtAddCallback(dialog, XmNcancelCallback, fsb_cancel_cb, NULL);
XtAddCallback(dialog, XmNokCallback, fsb_select_cb, NULL);
button_str = XmStringCreateLocalized(button_text);
title_str = XmStringCreateLocalized(title_text);
filter = XmStringCreateLocalized("*.[jmp]ng");
XtVaSetValues(dialog,
XmNokLabelString, button_str,
XmNdialogTitle, title_str,
XmNpattern, filter,
XmNfileFilterStyle, XmFILTER_NONE,
NULL);
XmStringFree(button_str);
XmStringFree(title_str);
XmStringFree(filter);
child = XmFileSelectionBoxGetChild(dialog, XmDIALOG_FILTER_TEXT);
XtVaSetValues(child, XmNfontList, file_font, NULL);
child = XmFileSelectionBoxGetChild(dialog, XmDIALOG_DIR_LIST);
XtVaSetValues(child, XmNfontList, file_font, NULL);
child = XmFileSelectionBoxGetChild(dialog, XmDIALOG_LIST);
XtVaSetValues(child, XmNfontList, file_font, NULL);
child = XmFileSelectionBoxGetChild(dialog, XmDIALOG_TEXT);
XtVaSetValues(child, XmNfontList, file_font, NULL);
XtManageChild(dialog);
XMapRaised(XtDisplay (dialog), XtWindow (XtParent (dialog)));
}
void run_mng_file_cb(Widget w, XtPointer client, XtPointer call)
{
XmFileSelectionBoxCallbackStruct *fsb;
char *read_idf;
FILE *reader;
XtUnmanageChild(w);
fsb = (XmFileSelectionBoxCallbackStruct *)call;
XmStringGetLtoR(fsb->value, XmSTRING_DEFAULT_CHARSET, &read_idf);
if(read_idf == NULL || *read_idf == 0) return;
reader = fopen(read_idf, "r");
if(reader == NULL)
{
perror(read_idf);
fprintf(stderr, "\n\n%s: cannot open file '%s'\n\n", prg_idf, read_idf);
return;
}
run_viewer(reader, read_idf);
free(read_idf);
}
static void user_reset_data(void)
{
if(timeout_ID) XtRemoveTimeOut(timeout_ID);
timeout_ID = 0;
mng_cleanup(&img.user_handle);
img.read_pos = 0;
free(img.read_buf);
img.read_buf = NULL;
img.read_len = 0;
img.img_width = 0;
img.img_height = 0;
img.mng_bytes_per_line = 0;
img.read_idf = NULL;
img.frozen = 0;
img.restarted = 0;
img.single_step_wanted = 0;
img.single_step_served = 0;
XClearWindow(img.dpy, img.win);
}
void browse_file_cb(Widget w, XtPointer client, XtPointer call)
{
if(img.user_handle)
user_reset_data();
img.stopped = 0;
img.frozen = 0;
img.restarted = 0;
create_file_dialog(w, "Select", "Select MNG file", run_mng_file_cb);
}
void Viewer_postlude(void)
{
if(timeout_ID) XtRemoveTimeOut(timeout_ID);
mng_cleanup(&img.user_handle);
if(img.reader) fclose(img.reader);
if(img.ximage) XDestroyImage(img.ximage);
if(img.read_buf) free(img.read_buf);
if(img.mng_buf) free(img.mng_buf);
if(img.dither_line) free(img.dither_line);
if(!img.external_win && img.dpy) XtCloseDisplay(img.dpy);
fputc('\n', stderr);
}
static void user_init_data(ImageInfo *img)
{
unsigned int depth;
int screen;
Display *dpy;
dpy = img->dpy;
screen = DefaultScreen(dpy);
depth = DefaultDepth(dpy, screen);
img->depth = depth;
if(!img->visual)
{
img->visual = DefaultVisual(dpy, screen);
img->gc = DefaultGC(dpy, DefaultScreen(dpy));
}
else
{
if(img->mng_buf) free(img->mng_buf);
if(img->dither_line) free(img->dither_line);
x11_destroy_ximage(img);
}
set_bg_pixel(img);
mng_set_bgcolor(img->user_handle,
img->xbg_red, img->xbg_green, img->xbg_blue);
img->mng_bytes_per_line = img->img_width * img->mng_rgb_size;
img->mng_buf = (unsigned char*)
calloc(1, img->mng_bytes_per_line * img->img_height);
img->dither_line = (unsigned char*)
calloc(1, img->mng_bytes_per_line);
if(!img->x11_init)
{
x11_init_color(img);
img->x11_init = 1;
}
img->ximage = x11_create_ximage(img);
if(img->ximage == NULL)
{
Viewer_postlude();
exit(0);
}
}
static void player_exit_cb(Widget w, XtPointer client, XtPointer call)
{
Viewer_postlude();
exit(0);
}
static void player_stop_cb(Widget w, XtPointer client, XtPointer call)
{
if(img.type != MNG_TYPE) return;
if(!img.user_handle) return;
if(img.stopped) return;
user_reset_data();
img.stopped = 1;
}
static void player_single_step_cb(Widget w, XtPointer client, XtPointer call)
{
if(img.type != MNG_TYPE) return;
if(!img.user_handle) return;
if(img.stopped) return;
if(img.single_step_served)
{
img.single_step_served = 0;
img.frozen = 0;
img.single_step_wanted = 1;
return;
}
if(timeout_ID) XtRemoveTimeOut(timeout_ID);
timeout_ID = 0;
img.single_step_wanted = 1;
mng_display_resume(img.user_handle);
}
static void player_pause_cb(Widget w, XtPointer client, XtPointer call)
{
if(img.type != MNG_TYPE) return;
if(!img.user_handle) return;
if(img.stopped) return;
if(img.frozen) return;
if(timeout_ID) XtRemoveTimeOut(timeout_ID);
timeout_ID = 0;
img.frozen = 1;
img.single_step_served = 0;
img.single_step_wanted = 0;
}
static void player_resume_cb(Widget w, XtPointer client, XtPointer call)
{
if(img.type != MNG_TYPE) return;
if(!img.user_handle) return;
if(img.stopped) return;
if(!img.frozen
&& !img.single_step_served)
return;
img.frozen = 0;
if(img.single_step_served
|| img.single_step_wanted)
{
img.single_step_served = 0;
img.single_step_wanted = 0;
if(timeout_ID) XtRemoveTimeOut(timeout_ID);
timeout_ID = 0;
}
mng_display_resume(img.user_handle);
}
static void player_restart_cb(Widget w, XtPointer client, XtPointer call)
{
if(img.type != MNG_TYPE) return;
if(!img.user_handle) return;
if(img.stopped) return;
img.frozen = 1;
if(timeout_ID) XtRemoveTimeOut(timeout_ID);
timeout_ID = 0;
img.frozen = 0;
img.single_step_served = 0;
img.single_step_wanted = 0;
img.read_pos = 0;
mng_reset(img.user_handle);
img.restarted = 1;
gettimeofday(&start_tv, NULL);
mng_read(img.user_handle);
mng_display(img.user_handle);
}
static void release_event_cb(Widget w, XtPointer client, XEvent *event,
Boolean *cont)
{
Viewer_postlude();
exit(0);
}
static void redraw(int type)
{
if((type == Expose || type == GraphicsExpose)
&& img.ximage)
{
XPutImage(img.dpy, img.win, img.gc, img.ximage,
0, 0, 0, 0, img.img_width, img.img_height);
}
}
static void exposures_cb(Widget w, XtPointer client,
XmDrawingAreaCallbackStruct *cbs)
{
redraw(cbs->event->xany.type);
}
static mng_ptr user_alloc(mng_size_t len)
{
return calloc(1, len + 2);
}
static void user_free(mng_ptr buf, mng_size_t len)
{
free(buf);
}
static mng_bool user_read(mng_handle user_handle, mng_ptr out_buf,
mng_uint32 req_len, mng_uint32 *out_len)
{
mng_uint32 more;
ImageInfo *img;
img = (ImageInfo *)mng_get_userdata(user_handle);
more = img->read_len - img->read_pos;
if(more > 0
&& img->read_buf != NULL)
{
if(req_len < more)
more = req_len;
memcpy(out_buf, img->read_buf + img->read_pos, more);
img->read_pos += more;
*out_len = more;
return MNG_TRUE;
}
return MNG_FALSE;
}
static mng_bool user_open_stream(mng_handle user_handle)
{
return MNG_TRUE;
}
static mng_bool user_close_stream(mng_handle user_handle)
{
return MNG_TRUE;
}
static void create_widgets(mng_uint32 width, mng_uint32 height)
{
Widget but_rc, but_frame, canvas_frame;
Widget but1, but2, but3, but4, but5, but6, but7;
toplevel = XtAppInitialize(&app_context, "xmngview", NULL, 0,
img.argc_ptr, img.argv,
0, 0, 0);
main_form = XtVaCreateManagedWidget("main_form",
xmFormWidgetClass, toplevel,
XmNhorizontalSpacing, SPACE_X,
XmNverticalSpacing, SPACE_Y,
XmNresizable, True,
NULL);
but_frame = XtVaCreateManagedWidget("but_frame",
xmFrameWidgetClass, main_form,
XmNshadowType, XmSHADOW_ETCHED_OUT,
XmNtopAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
XmNshadowThickness, FRAME_SHADOW_WIDTH,
NULL);
but_rc = XtVaCreateManagedWidget("but_rc",
xmRowColumnWidgetClass, but_frame,
XmNentryAlignment, XmALIGNMENT_CENTER,
XmNorientation, XmHORIZONTAL,
XmNpacking, XmPACK_COLUMN,
XmNnumColumns, 1,
XmNresizeWidth, True,
XmNentryBorder, BUT_ENTRY_BORDER,
NULL);
but1 = XtVaCreateManagedWidget("Exit",
xmPushButtonWidgetClass, but_rc,
NULL);
XtAddCallback(but1, XmNactivateCallback,
player_exit_cb, (XtPointer)toplevel);
but2 = XtVaCreateManagedWidget("Pause",
xmPushButtonWidgetClass, but_rc,
NULL);
XtAddCallback(but2, XmNactivateCallback,
player_pause_cb, (XtPointer)toplevel);
but3 = XtVaCreateManagedWidget("GoOn",
xmPushButtonWidgetClass, but_rc,
NULL);
XtAddCallback(but3, XmNactivateCallback,
player_resume_cb, NULL);
but4 = XtVaCreateManagedWidget("Restart",
xmPushButtonWidgetClass, but_rc,
NULL);
XtAddCallback(but4, XmNactivateCallback,
player_restart_cb, NULL);
but5 = XtVaCreateManagedWidget("Step",
xmPushButtonWidgetClass, but_rc,
NULL);
XtAddCallback(but5, XmNactivateCallback,
player_single_step_cb, NULL);
but6 = XtVaCreateManagedWidget("Finish",
xmPushButtonWidgetClass, but_rc,
NULL);
XtAddCallback(but6, XmNactivateCallback,
player_stop_cb, NULL);
but7 = XtVaCreateManagedWidget("Browse",
xmPushButtonWidgetClass, but_rc,
NULL);
XtAddCallback(but7, XmNactivateCallback,
browse_file_cb, NULL);
file_label = XtVaCreateManagedWidget("FILE: ",
xmLabelWidgetClass, main_form,
XmNalignment, XmALIGNMENT_BEGINNING,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, but_frame,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
NULL);
canvas_frame = XtVaCreateManagedWidget("canvas_frame",
xmFrameWidgetClass, main_form,
XmNshadowType, XmSHADOW_ETCHED_OUT,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, file_label,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
NULL);
canvas = XtVaCreateManagedWidget("canvas",
xmDrawingAreaWidgetClass, canvas_frame,
XmNheight, height,
XmNwidth, width,
NULL);
XtAddEventHandler(canvas,
ButtonReleaseMask|ButtonPressMask,
False, release_event_cb, (XtPointer)toplevel);
XtAddCallback(canvas,
XmNexposeCallback, (XtCallbackProc)exposures_cb, (XtPointer)&img);
XtRealizeWidget(toplevel);
if(start_width == 0)
{
width = height = 0;
start_width = (FRAME_SHADOW_WIDTH<<1);
XtVaGetValues(but1, XmNwidth, &width, NULL);
start_width += width + (BUT_ENTRY_BORDER<<1) + ANY_WIDTH;
XtVaGetValues(but2, XmNwidth, &width, NULL);
start_width += width + (BUT_ENTRY_BORDER<<1) + ANY_WIDTH;
XtVaGetValues(but3, XmNwidth, &width, NULL);
start_width += width + (BUT_ENTRY_BORDER<<1) + ANY_WIDTH;
XtVaGetValues(but4, XmNwidth, &width, NULL);
start_width += width + (BUT_ENTRY_BORDER<<1) + ANY_WIDTH;
XtVaGetValues(but5, XmNwidth, &width, NULL);
start_width += width + (BUT_ENTRY_BORDER<<1) + ANY_WIDTH;
XtVaGetValues(but6, XmNwidth, &width, NULL);
start_width += width + (BUT_ENTRY_BORDER<<1);
XtVaGetValues(but7, XmNwidth, &width, NULL);
start_width += width + (BUT_ENTRY_BORDER<<1);
}
img.canvas = canvas;
img.dpy = XtDisplay(img.canvas);
img.win = XtWindow(img.canvas);
file_font = XmFontListAppendEntry(NULL,
XmFontListEntryCreate(XmFONTLIST_DEFAULT_TAG,
XmFONT_IS_FONT,
XLoadQueryFont(img.dpy,
"-*-helvetica-medium-r-*-*-12-*-*-*-*-*-iso8859-1")));
}
static mng_bool user_process_header(mng_handle user_handle,
mng_uint32 width, mng_uint32 height)
{
ImageInfo *img;
Dimension cw, ch, tw, th, dh, dw, fw, fh;
XmString xmstr;
char *s, buf[128];
img = (ImageInfo*)mng_get_userdata(user_handle);
if(img->restarted)
{
img->restarted = 0;
return MNG_TRUE;
}
img->img_width = width;
img->img_height = height;
if(!img->external_win)
{
if(!img->canvas)
create_widgets(width, height);
else
{
tw = th = fw = fh = cw = ch = 0;
XtVaGetValues(toplevel, XmNwidth, &tw, XmNheight, &th, NULL);
XtVaGetValues(main_form, XmNwidth, &fw, XmNheight, &fh, NULL);
XtVaGetValues(img->canvas, XmNwidth, &cw, XmNheight, &ch, NULL);
if(height > ch)
{
dh = height - ch;
th += dh;
fh += dh;
} else
if(ch > height)
{
dh = ch - height;
th -= dh;
fh -= dh;
}
if(width > cw)
{
dw = width - cw;
tw += dw;
fw += dw;
} else
if(cw > width)
{
if(width > start_width)
dw = cw - width;
else
dw = cw - start_width;
tw -= dw;
fw -= dw;
}
if(fw < start_width)
{
tw = start_width + (SPACE_X<<1);
fw = start_width;
}
XtVaSetValues(toplevel, XmNwidth,tw , XmNheight,th , NULL);
XtVaSetValues(main_form, XmNwidth,fw , XmNheight,fh , NULL);
XtVaSetValues(img->canvas, XmNwidth,width , XmNheight,height , NULL);
}
}
else
if(img->external_win)
{
Display *dpy;
XtToolkitInitialize();
app_context = XtCreateApplicationContext();
dpy = XtOpenDisplay(app_context, NULL,NULL,"xmngview",
NULL, 0, img->argc_ptr, img->argv);
img->dpy = dpy;
img->win = img->external_win;
XSelectInput(dpy, img->win, ExposureMask);
}
user_init_data(img);
if(img->canvas)
{
s = strrchr(img->read_idf, '/');
if(s == NULL) s = img->read_idf; else ++s;
s = strdup(s);
if(strlen(s) > 64) s[64] = 0;
sprintf(buf, "%s (%d x %d)", s, img->img_width, img->img_height);
xmstr = XmStringCreateLtoR((char*)buf, XmSTRING_DEFAULT_CHARSET);
XtVaSetValues(file_label, XmNlabelString, xmstr, NULL);
XmStringFree(xmstr);
free(s);
}
gettimeofday(&start_tv, NULL);
return MNG_TRUE;
}
static void wait_cb(XtPointer client, XtIntervalId * id)
{
timeout_ID = 0;
if(img.frozen
|| img.single_step_served)
{
// gettimeofday(&start_tv, NULL);
timeout_ID = XtAppAddTimeOut(app_context,
img.delay, wait_cb, NULL);
}
else
{
mng_display_resume(img.user_handle);
}
}
static mng_bool user_set_timer(mng_handle user_handle, mng_uint32 delay)
{
ImageInfo *img;
img = (ImageInfo*)mng_get_userdata(user_handle);
img->delay = delay;
timeout_ID = XtAppAddTimeOut(app_context,
delay, wait_cb, NULL);
return MNG_TRUE;
}
static mng_uint32 user_get_tick_count(mng_handle user_handle)
{
double sec, usec;
mng_uint32 ticks;
gettimeofday(&now_tv, NULL);
sec = (double)(now_tv.tv_sec - start_tv.tv_sec);
usec = (double)now_tv.tv_usec - (double)start_tv.tv_usec;
ticks = (mng_uint32)(sec * 1000.0 + usec/1000.0);
//fprintf(stderr,"TICKS %u (%f:%f)\n", ticks, sec, usec);
return ticks;
}
static mng_ptr user_get_canvas_line(mng_handle user_handle, mng_uint32 line)
{
ImageInfo *img;
img = (ImageInfo*)mng_get_userdata(user_handle);
return img->mng_buf + img->mng_bytes_per_line * line;
}
static mng_bool user_refresh(mng_handle user_handle, mng_uint32 x,
mng_uint32 y, mng_uint32 width, mng_uint32 height)
{
ImageInfo *img;
mng_uint32 src_len;
unsigned char *src_start, *src_buf;
int row, max_row;
Display *dpy;
GC gc;
Window win;
XImage *ximage;
Visual *visual;
int have_shmem;
img = (ImageInfo*)mng_get_userdata(user_handle);
if(img->single_step_wanted)
img->single_step_served = 1;
win = img->win;
gc = img->gc;
dpy = img->dpy;
ximage = img->ximage;
visual = img->visual;
have_shmem = img->have_shmem;
max_row = y + height;
row = y;
src_len = img->mng_bytes_per_line;
src_buf = src_start = img->mng_buf + img->mng_rgb_size * x + y * src_len;
while(row < max_row)
{
viewer_renderline(img, src_start, row, x, width);
++row;
src_start += src_len;
}
XPUTIMAGE(dpy, win, gc, ximage, x, y, x, y, width, height);
XSync(dpy, False);
return MNG_TRUE;
}
static mng_bool 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)
{
ImageInfo *img;
unsigned char chunk[5];
img = (ImageInfo*)mng_get_userdata(user_handle);
chunk[0] = (char)((chunktype >> 24) & 0xFF);
chunk[1] = (char)((chunktype >> 16) & 0xFF);
chunk[2] = (char)((chunktype >> 8) & 0xFF);
chunk[3] = (char)((chunktype ) & 0xFF);
chunk[4] = '\0';
fprintf(stderr, "\n\n%s: error playing(%s) chunk[%d]'%s':\n",
prg_idf, img->read_idf, chunkseq, chunk);
fprintf(stderr, "code(%d) severity(%d) extra1(%d) extra2(%d)"
"\ntext:'%s'\n\n", code, severity, extra1, extra2, text);
return 0;
}
static mng_bool prelude(void)
{
#define MAXBUF 8
unsigned char buf[MAXBUF];
if(fread(buf, 1, MAXBUF, img.reader) != MAXBUF)
{
fprintf(stderr,"\n%s:prelude\n\tcannot read signature \n",
prg_idf);
return MNG_FALSE;
}
if(memcmp(buf, MNG_MAGIC, 8) == 0)
img.type = MNG_TYPE;
else
if(memcmp(buf, JNG_MAGIC, 8) == 0)
img.type = JNG_TYPE;
else
if(memcmp(buf, PNG_MAGIC, 8) == 0)
img.type = PNG_TYPE;
if(!img.type)
{
fprintf(stderr,"\n%s:'%s' is no MNG / JNG / PNG file\n",
prg_idf, img.read_idf);
return MNG_FALSE;
}
fseek(img.reader, 0, SEEK_SET);
fseek(img.reader, 0, SEEK_END);
img.read_len = ftell(img.reader);
fseek(img.reader, 0, SEEK_SET);
if(!img.user_handle)
{
user_handle = mng_initialize(&img, user_alloc, user_free, MNG_NULL);
if(user_handle == MNG_NULL)
{
fprintf(stderr, "\n%s: cannot initialize libmng.\n", prg_idf);
return MNG_FALSE;
}
img.user_handle = user_handle;
mng_set_canvasstyle(user_handle, MNG_CANVAS_RGB8);
img.mng_rgb_size = CANVAS_RGB8_SIZE;
if(mng_setcb_openstream(user_handle, user_open_stream) != OK
|| mng_setcb_closestream(user_handle, user_close_stream) != OK
|| mng_setcb_readdata(user_handle, user_read) != OK
|| mng_setcb_settimer(user_handle, user_set_timer) != OK
|| mng_setcb_gettickcount(user_handle, user_get_tick_count) != OK
|| mng_setcb_processheader(user_handle, user_process_header) != OK
|| mng_setcb_getcanvasline(user_handle, user_get_canvas_line) != OK
|| mng_setcb_refresh(user_handle, user_refresh) != OK
|| mng_setcb_errorproc(user_handle, user_error) != OK
)
{
fprintf(stderr,"\n%s: cannot set callbacks for libmng.\n",
prg_idf);
return MNG_FALSE;
}
}
img.read_buf = (unsigned char*)calloc(1, img.read_len + 2);
fread(img.read_buf, 1, img.read_len, img.reader);
fclose(img.reader);
img.reader = NULL;
return MNG_TRUE;
}
static void run_viewer(FILE *reader, char *read_idf)
{
XEvent event;
img.read_idf = read_idf;
img.reader = reader;
if(read_idf != NULL)
{
if(prelude() == MNG_FALSE)
return ;
gettimeofday(&start_tv, NULL);
mng_read(img.user_handle);
mng_display(img.user_handle);
}
if(!img.external_win)
{
XtAppMainLoop(app_context);
}
else
while(1)
{
XtAppNextEvent(app_context, &event);
redraw(event.type);
}
}
static void usage(const char *prg)
{
const char *bar=
"\n------------------------------------------------------------------------\n";
fputs(bar, stderr);
fprintf(stderr,"%s version %s\n"
"USAGE: %s [--w WINDOW] [--bg BACKGROUND_COLOR] [FILE]\n",
prg, version, prg);
fputs("\twith BACKGROUND_COLOR = "
"(\"TEXT\" | \"#RGB\" | \"rgb:R/G/B\" | \"PIXEL\")\n"
"\te.g.\n\t(--bg \"red\" | --bg \"#ff0000\" "
"| --bg \"rgb:ff/00/00\" | --bg \"0xf800\")\n"
"\twith FILE=(idf.mng | idf.jng | idf.png)",stderr);
fputs(bar, stderr);
}
static void shrink_name(char *buf)
{
char *s, *d;
int ch;
s = d = buf;
while((ch = *s++))
{
if(isspace(ch)) continue;
*d++ = tolower(ch);
}
*d = 0;
}
int main(int argc, char **argv)
{
FILE *reader;
char *read_idf, *s;
char *ok;
int i;
unsigned char has_bg_color, has_bg_pixel;
Window external_win;
Pixel bg_pixel;
if((prg_idf = strrchr(argv[0], '/')) == NULL)
prg_idf = argv[0];
else
++prg_idf;
memset(&img, 0, sizeof(ImageInfo));
external_win = 0; read_idf = NULL; reader = NULL;
has_bg_color = has_bg_pixel = 0;
bg_pixel = 0;
i = 0;
while(++i < argc)
{
s = argv[i];
if(strcmp(s, "--help") == 0
|| strcmp(s, "-help") == 0
|| *s == '?')
{
usage(prg_idf);
return 0;
}
if(strcasecmp(s, "--w") == 0)
{
++i;
s = argv[i];
external_win = strtoul(s, &ok, 10);
if(*ok)
return 0;
continue;
}
if(strcasecmp(s, "--bg") == 0)
{
++i;
s = argv[i];
if(*s == '#' || strncasecmp(s, "rgb:", 4) == 0 || isalpha(*s))
{
strncpy(img.bg_color, s, MAX_COLORBUF);
img.bg_color[MAX_COLORBUF] = 0;
has_bg_color = 1;
if(*s != '#')
shrink_name(img.bg_color);
continue;
}
bg_pixel = strtoul(s, &ok, 16);
if(*ok == 0)
has_bg_pixel = 1;
continue;
}
if(*s != '-')
{
read_idf = s; continue;
}
}
if(read_idf != NULL)
{
reader = fopen(read_idf, "rb");
if(reader == NULL)
{
perror(read_idf);
fprintf(stderr, "\n\n%s: cannot open file '%s'\n\n", prg_idf, read_idf);
return 0;
}
}
img.argv = argv;
img.argc_ptr = &argc;
img.external_win = external_win;
img.has_bg_pixel = has_bg_pixel;
img.bg_pixel = bg_pixel;
img.has_bg_color = has_bg_color;
if(!has_bg_pixel && !has_bg_color)
{
strcpy(img.bg_color, DEFAULT_BACKGROUND);
img.has_bg_color = 1;
}
if(read_idf == NULL && external_win == 0)
create_widgets(5,5);
run_viewer(reader, read_idf);
Viewer_postlude();
return 0;
}