mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-16 09:04:38 +00:00
1185 lines
26 KiB
C
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;
|
|
}
|