xmngview.c 27 KB

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