gtk-mng-view.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. /* Toy widget for GTK+ for displaying MNG animations.
  2. *
  3. * Copyright (C) 2000 The Free Software Foundation
  4. *
  5. * Author(s): Volodymyr Babin <vb :at: dwuj.ichf.edu.pl>
  6. *
  7. * This code is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Library General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Library General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Library General Public
  18. * License along with this library; if not, write to the
  19. * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20. * Boston, MA 02111-1307, USA.
  21. */
  22. #include <gtk/gtkmain.h>
  23. #include "gtk-mng-view.h"
  24. #include <gdk-pixbuf/gdk-pixbuf.h>
  25. /* MNG callbacks */
  26. static mng_ptr
  27. mng_malloc_callback (mng_size_t how_many)
  28. {
  29. return (mng_ptr) g_new0 (gchar, how_many);
  30. }
  31. static void
  32. mng_free_callback (mng_ptr pointer, mng_size_t number)
  33. {
  34. g_free (pointer);
  35. }
  36. static mng_bool
  37. mng_open_stream_callback (mng_handle mng_h)
  38. {
  39. return MNG_TRUE;
  40. }
  41. static mng_bool
  42. mng_close_stream_callback (mng_handle mng_h)
  43. {
  44. return MNG_TRUE;
  45. }
  46. static mng_bool
  47. mng_read_data_callback (mng_handle mng_h,
  48. mng_ptr buffer,
  49. mng_uint32 bytes_requested,
  50. mng_uint32 * bytes_read)
  51. {
  52. guint available_mng_food;
  53. GtkMngView * mng_view = GTK_MNG_VIEW (mng_get_userdata (mng_h));
  54. available_mng_food = mng_view->bytes_to_eat - mng_view->bytes_eaten;
  55. if (available_mng_food > 0 && mng_view->mng_food != NULL)
  56. {
  57. * bytes_read = (mng_uint32) MIN ((mng_uint32) available_mng_food, bytes_requested);
  58. memcpy (buffer, mng_view->mng_food + mng_view->bytes_eaten, * bytes_read);
  59. mng_view->bytes_eaten += * bytes_read;
  60. return MNG_TRUE;
  61. }
  62. else
  63. return MNG_FALSE;
  64. }
  65. static mng_bool
  66. mng_process_header_callback (mng_handle mng_h,
  67. mng_uint32 width,
  68. mng_uint32 height)
  69. {
  70. GtkMngView * mng_view;
  71. mng_view = GTK_MNG_VIEW (mng_get_userdata (mng_h));
  72. mng_view->width = width;
  73. mng_view->height = height;
  74. g_free (mng_view->MNG_drawing_buffer);
  75. mng_view->MNG_drawing_buffer = g_new0 (guchar, 3 * width * height);
  76. gtk_widget_queue_resize (GTK_WIDGET (mng_view));
  77. return MNG_TRUE;
  78. }
  79. static gboolean
  80. gtk_mng_view_animator (GtkMngView * mng_view)
  81. {
  82. mng_retcode retcode;
  83. retcode = mng_display_resume (mng_view->MNG_handle);
  84. if (retcode == MNG_NOERROR)
  85. {
  86. mng_view->timeout_ID = 0;
  87. return FALSE;
  88. }
  89. else if (retcode == MNG_NEEDTIMERWAIT)
  90. return FALSE;
  91. else
  92. g_warning ("mng_display_resume() return not good value");
  93. return FALSE;
  94. }
  95. static mng_bool
  96. mng_set_timer_callback (mng_handle mng_h,
  97. mng_uint32 delay)
  98. {
  99. GtkMngView * mng_view;
  100. mng_view = GTK_MNG_VIEW (mng_get_userdata (mng_h));
  101. mng_view->timeout_ID = gtk_timeout_add (delay,
  102. (GtkFunction) gtk_mng_view_animator,
  103. mng_view);
  104. return MNG_TRUE;
  105. }
  106. static mng_uint32
  107. mng_get_tickcount_callback (mng_handle mng_h)
  108. {
  109. gdouble seconds;
  110. gulong microseconds;
  111. GtkMngView * mng_view;
  112. mng_view = GTK_MNG_VIEW (mng_get_userdata (mng_h));
  113. seconds = g_timer_elapsed (mng_view->timer,
  114. &microseconds);
  115. return ((mng_uint32) (seconds*1000.0 + ((gdouble) microseconds)/1000.0));
  116. }
  117. static mng_ptr
  118. mng_get_canvas_line_callback (mng_handle mng_h,
  119. mng_uint32 line)
  120. {
  121. GtkMngView * mng_view;
  122. mng_view = GTK_MNG_VIEW (mng_get_userdata (mng_h));
  123. return mng_view->MNG_drawing_buffer + 3 * line * mng_view->width;
  124. }
  125. static void gtk_mng_view_paint (GtkMngView *, GdkRectangle *);
  126. static mng_bool
  127. mng_refresh_callback (mng_handle mng_h,
  128. mng_uint32 x,
  129. mng_uint32 y,
  130. mng_uint32 width,
  131. mng_uint32 height)
  132. {
  133. GtkMngView * mng_view;
  134. mng_view = GTK_MNG_VIEW (mng_get_userdata (mng_h));
  135. if (GTK_WIDGET_REALIZED (mng_view))
  136. {
  137. GdkRectangle rectangle;
  138. rectangle.x = x;
  139. rectangle.y = y;
  140. rectangle.width = width;
  141. rectangle.height = height;
  142. gtk_mng_view_paint (mng_view, &rectangle);
  143. }
  144. return MNG_TRUE;
  145. }
  146. static gboolean
  147. gtk_mng_view_init_libmng (GtkMngView * mng_view)
  148. {
  149. GtkWidget * widget;
  150. g_return_val_if_fail (IS_GTK_MNG_VIEW (mng_view), FALSE);
  151. if (mng_view->MNG_handle)
  152. mng_cleanup (&mng_view->MNG_handle);
  153. mng_view->MNG_handle = mng_initialize (mng_view,
  154. mng_malloc_callback,
  155. mng_free_callback,
  156. MNG_NULL);
  157. if (mng_view->MNG_handle == MNG_NULL)
  158. return FALSE;
  159. if (mng_setcb_openstream (mng_view->MNG_handle, mng_open_stream_callback) != MNG_NOERROR ||
  160. mng_setcb_closestream (mng_view->MNG_handle, mng_close_stream_callback) != MNG_NOERROR ||
  161. mng_setcb_readdata (mng_view->MNG_handle, mng_read_data_callback) != MNG_NOERROR ||
  162. mng_setcb_processheader (mng_view->MNG_handle, mng_process_header_callback) != MNG_NOERROR ||
  163. mng_setcb_settimer (mng_view->MNG_handle, mng_set_timer_callback) != MNG_NOERROR ||
  164. mng_setcb_gettickcount (mng_view->MNG_handle, mng_get_tickcount_callback) != MNG_NOERROR ||
  165. mng_setcb_getcanvasline (mng_view->MNG_handle, mng_get_canvas_line_callback) != MNG_NOERROR ||
  166. mng_setcb_refresh (mng_view->MNG_handle, mng_refresh_callback) != MNG_NOERROR)
  167. {
  168. mng_cleanup (&mng_view->MNG_handle);
  169. return FALSE;
  170. }
  171. mng_set_canvasstyle (mng_view->MNG_handle, MNG_CANVAS_RGB8);
  172. widget = GTK_WIDGET (mng_view);
  173. if (!GTK_WIDGET_REALIZED (widget))
  174. gtk_widget_realize (widget);
  175. mng_set_bgcolor (mng_view->MNG_handle,
  176. widget->style->bg[GTK_STATE_NORMAL].red,
  177. widget->style->bg[GTK_STATE_NORMAL].green,
  178. widget->style->bg[GTK_STATE_NORMAL].blue);
  179. return TRUE;
  180. }
  181. /* GTK+ widget methods */
  182. static GtkWidgetClass * parent_class = NULL;
  183. static void
  184. gtk_mng_view_finalize (GObject * obj)
  185. {
  186. GtkMngView * mng_view = GTK_MNG_VIEW (obj);
  187. g_timer_destroy (mng_view->timer);
  188. if (mng_view->timeout_ID)
  189. gtk_timeout_remove (mng_view->timeout_ID);
  190. g_free (mng_view->MNG_drawing_buffer);
  191. if (mng_view->MNG_handle)
  192. mng_cleanup (&mng_view->MNG_handle);
  193. G_OBJECT_CLASS (parent_class)->finalize (obj);
  194. }
  195. static void
  196. gtk_mng_view_size_request (GtkWidget * widget, GtkRequisition * requisition)
  197. {
  198. GtkMngView * mng_view;
  199. g_return_if_fail (IS_GTK_MNG_VIEW (widget));
  200. g_return_if_fail (requisition != NULL);
  201. mng_view = (GtkMngView *) widget;
  202. requisition->width = mng_view->width;
  203. requisition->height = mng_view->height;
  204. }
  205. static void
  206. gtk_mng_view_size_allocate (GtkWidget * widget, GtkAllocation * allocation)
  207. {
  208. g_return_if_fail (IS_GTK_MNG_VIEW (widget));
  209. g_return_if_fail (allocation != NULL);
  210. if (GTK_WIDGET_REALIZED (widget))
  211. gdk_window_move_resize (widget->window,
  212. allocation->x,
  213. allocation->y,
  214. allocation->width,
  215. allocation->height);
  216. }
  217. static void
  218. gtk_mng_view_paint (GtkMngView * mng_view,
  219. GdkRectangle * area)
  220. {
  221. GtkWidget * widget;
  222. guint rowstride;
  223. guchar * buffer;
  224. register guchar * ptr;
  225. register guchar * bptr;
  226. widget = GTK_WIDGET (mng_view);
  227. g_assert (GTK_WIDGET_REALIZED (widget));
  228. rowstride = 3 * area->width;
  229. buffer = g_new (guchar, rowstride * area->height);
  230. bptr = buffer;
  231. ptr = mng_view->MNG_drawing_buffer
  232. + 3 * (area->y * mng_view->width + area->x);
  233. while (bptr < buffer + rowstride * area->height)
  234. {
  235. memcpy (bptr, ptr, rowstride);
  236. bptr += rowstride;
  237. ptr += 3 * mng_view->width;
  238. }
  239. gdk_draw_rgb_image (widget->window,
  240. widget->style->white_gc,
  241. area->x,
  242. area->y,
  243. area->width,
  244. area->height,
  245. GDK_RGB_DITHER_NORMAL,
  246. buffer,
  247. rowstride);
  248. g_free (buffer);
  249. gdk_flush ();
  250. }
  251. static gboolean
  252. gtk_mng_view_expose (GtkWidget * widget, GdkEventExpose * event)
  253. {
  254. g_return_val_if_fail (IS_GTK_MNG_VIEW (widget), FALSE);
  255. g_return_val_if_fail (event != NULL, FALSE);
  256. if (GTK_WIDGET_REALIZED (widget))
  257. {
  258. GdkRectangle dummy;
  259. GdkRectangle rectangle;
  260. GtkMngView * mng_view;
  261. mng_view = GTK_MNG_VIEW (widget);
  262. dummy.x = dummy.y = 0;
  263. dummy.width = mng_view->width;
  264. dummy.height = mng_view->height;
  265. if (gdk_rectangle_intersect (&dummy, &event->area, &rectangle))
  266. gtk_mng_view_paint (mng_view, &rectangle);
  267. }
  268. return FALSE;
  269. }
  270. static void
  271. gtk_mng_view_realize (GtkWidget * widget)
  272. {
  273. GdkWindowAttr attributes;
  274. gint attributes_mask;
  275. g_return_if_fail (IS_GTK_MNG_VIEW (widget));
  276. GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
  277. attributes.window_type = GDK_WINDOW_CHILD;
  278. attributes.x = widget->allocation.x;
  279. attributes.y = widget->allocation.y;
  280. attributes.width = widget->allocation.width;
  281. attributes.height = widget->allocation.height;
  282. attributes.wclass = GDK_INPUT_OUTPUT;
  283. attributes.visual = gtk_widget_get_visual (widget);
  284. attributes.colormap = gtk_widget_get_colormap (widget);
  285. attributes.event_mask = gtk_widget_get_events (widget);
  286. attributes.event_mask |= GDK_EXPOSURE_MASK;
  287. attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
  288. widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
  289. &attributes, attributes_mask);
  290. gdk_window_set_user_data (widget->window, widget);
  291. widget->style = gtk_style_attach (widget->style, widget->window);
  292. gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
  293. }
  294. static void
  295. gtk_mng_view_init (GtkMngView * mng_view)
  296. {
  297. g_return_if_fail (IS_GTK_MNG_VIEW (mng_view));
  298. GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (mng_view), GTK_NO_WINDOW);
  299. mng_view->MNG_handle = NULL;
  300. mng_view->MNG_drawing_buffer = NULL;
  301. mng_view->timeout_ID = 0;
  302. mng_view->timer = g_timer_new ();
  303. g_timer_start (mng_view->timer);
  304. mng_view->mng_food = NULL;
  305. }
  306. static void
  307. gtk_mng_view_class_init (GtkMngViewClass * klass)
  308. {
  309. GObjectClass * object_class;
  310. GtkWidgetClass * widget_class;
  311. parent_class = g_type_class_peek_parent (klass);
  312. object_class = G_OBJECT_CLASS (klass);
  313. object_class->finalize = gtk_mng_view_finalize;
  314. widget_class = GTK_WIDGET_CLASS (klass);
  315. widget_class->size_request = gtk_mng_view_size_request;
  316. widget_class->size_allocate = gtk_mng_view_size_allocate;
  317. widget_class->expose_event = gtk_mng_view_expose;
  318. widget_class->realize = gtk_mng_view_realize;
  319. }
  320. GtkType
  321. gtk_mng_view_get_type (void)
  322. {
  323. static GtkType type = 0;
  324. if (!type)
  325. {
  326. static const GtkTypeInfo type_info =
  327. {
  328. "GtkMngView",
  329. sizeof (GtkMngView),
  330. sizeof (GtkMngViewClass),
  331. (GtkClassInitFunc) gtk_mng_view_class_init,
  332. (GtkObjectInitFunc) gtk_mng_view_init,
  333. NULL, NULL,
  334. (GtkClassInitFunc) NULL
  335. };
  336. type = gtk_type_unique (GTK_TYPE_WIDGET, &type_info);
  337. }
  338. return type;
  339. }
  340. GtkWidget *
  341. gtk_mng_view_new (void)
  342. {
  343. return GTK_WIDGET (gtk_type_new (GTK_MNG_VIEW_TYPE));
  344. }
  345. gboolean
  346. gtk_mng_view_load_mng_from_memory (GtkMngView * mng_view,
  347. guchar * data_to_eat,
  348. guint data_size)
  349. {
  350. g_return_val_if_fail (IS_GTK_MNG_VIEW (mng_view), FALSE);
  351. g_return_val_if_fail (data_size > 27, FALSE);
  352. g_return_val_if_fail (data_to_eat != NULL, FALSE);
  353. if (data_to_eat[0] != 0x8a ||
  354. data_to_eat[1] != 'M' ||
  355. data_to_eat[2] != 'N' ||
  356. data_to_eat[3] != 'G' ||
  357. data_to_eat[4] != 0x0d ||
  358. data_to_eat[5] != 0x0a ||
  359. data_to_eat[6] != 0x1a ||
  360. data_to_eat[7] != 0x0a)
  361. {
  362. g_warning ("not mng format");
  363. return FALSE;
  364. }
  365. if (gtk_mng_view_init_libmng (mng_view))
  366. {
  367. mng_view->bytes_to_eat = data_size;
  368. mng_view->bytes_eaten = 0;
  369. mng_view->mng_food = data_to_eat;
  370. if (mng_read (mng_view->MNG_handle) != MNG_NOERROR)
  371. {
  372. g_warning ("libmng read error");
  373. mng_cleanup (&mng_view->MNG_handle);
  374. return FALSE;
  375. }
  376. else
  377. return mng_display (mng_view->MNG_handle);
  378. }
  379. else
  380. {
  381. g_warning ("error initializing libmng");
  382. return FALSE;
  383. }
  384. return TRUE;
  385. }