/libview/ev-timeline.c

https://github.com/mate-desktop/atril · C · 440 lines · 327 code · 91 blank · 22 comment · 17 complexity · 67a66823ca07426dc89ba4bf14b78737 MD5 · raw file

  1. /* ev-timeline.c
  2. * this file is part of atril, a mate document viewer
  3. *
  4. * Copyright (C) 2007 Carlos Garnacho <carlos@imendio.com>
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Library General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Library General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Library General Public
  17. * License along with this library; if not, write to the
  18. * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  19. * Boston, MA 02110-1301, USA.
  20. */
  21. #include <glib.h>
  22. #include <math.h>
  23. #include "ev-timeline.h"
  24. #define MSECS_PER_SEC 1000
  25. #define FRAME_INTERVAL(nframes) (MSECS_PER_SEC / nframes)
  26. #define DEFAULT_FPS 30
  27. typedef struct EvTimelinePrivate EvTimelinePrivate;
  28. struct EvTimelinePrivate {
  29. guint duration;
  30. guint fps;
  31. guint source_id;
  32. GTimer *timer;
  33. guint loop : 1;
  34. };
  35. enum {
  36. PROP_0,
  37. PROP_FPS,
  38. PROP_DURATION,
  39. PROP_LOOP
  40. };
  41. enum {
  42. STARTED,
  43. PAUSED,
  44. FINISHED,
  45. FRAME,
  46. LAST_SIGNAL
  47. };
  48. static guint signals [LAST_SIGNAL] = { 0, };
  49. G_DEFINE_TYPE_WITH_PRIVATE (EvTimeline, ev_timeline, G_TYPE_OBJECT)
  50. static void
  51. ev_timeline_init (EvTimeline *timeline)
  52. {
  53. EvTimelinePrivate *priv;
  54. priv = ev_timeline_get_instance_private (timeline);
  55. priv->fps = DEFAULT_FPS;
  56. priv->duration = 0;
  57. }
  58. static void
  59. ev_timeline_set_property (GObject *object,
  60. guint prop_id,
  61. const GValue *value,
  62. GParamSpec *pspec)
  63. {
  64. EvTimeline *timeline;
  65. timeline = EV_TIMELINE (object);
  66. switch (prop_id) {
  67. case PROP_FPS:
  68. ev_timeline_set_fps (timeline, g_value_get_uint (value));
  69. break;
  70. case PROP_DURATION:
  71. ev_timeline_set_duration (timeline, g_value_get_uint (value));
  72. break;
  73. case PROP_LOOP:
  74. ev_timeline_set_loop (timeline, g_value_get_boolean (value));
  75. break;
  76. default:
  77. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  78. }
  79. }
  80. static void
  81. ev_timeline_get_property (GObject *object,
  82. guint prop_id,
  83. GValue *value,
  84. GParamSpec *pspec)
  85. {
  86. EvTimeline *timeline;
  87. EvTimelinePrivate *priv;
  88. timeline = EV_TIMELINE (object);
  89. priv = ev_timeline_get_instance_private (timeline);
  90. switch (prop_id) {
  91. case PROP_FPS:
  92. g_value_set_uint (value, priv->fps);
  93. break;
  94. case PROP_DURATION:
  95. g_value_set_uint (value, priv->duration);
  96. break;
  97. case PROP_LOOP:
  98. g_value_set_boolean (value, priv->loop);
  99. break;
  100. default:
  101. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  102. }
  103. }
  104. static void
  105. ev_timeline_finalize (GObject *object)
  106. {
  107. EvTimelinePrivate *priv;
  108. priv = ev_timeline_get_instance_private (EV_TIMELINE (object));
  109. if (priv->source_id) {
  110. g_source_remove (priv->source_id);
  111. priv->source_id = 0;
  112. }
  113. if (priv->timer)
  114. g_timer_destroy (priv->timer);
  115. G_OBJECT_CLASS (ev_timeline_parent_class)->finalize (object);
  116. }
  117. static gboolean
  118. ev_timeline_run_frame (EvTimeline *timeline)
  119. {
  120. EvTimelinePrivate *priv;
  121. gdouble progress;
  122. guint elapsed_time;
  123. priv = ev_timeline_get_instance_private (timeline);
  124. elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000);
  125. progress = (gdouble) elapsed_time / priv->duration;
  126. progress = CLAMP (progress, 0., 1.);
  127. g_signal_emit (timeline, signals [FRAME], 0, progress);
  128. if (progress >= 1.0) {
  129. if (!priv->loop) {
  130. if (priv->source_id) {
  131. g_source_remove (priv->source_id);
  132. priv->source_id = 0;
  133. }
  134. g_signal_emit (timeline, signals [FINISHED], 0);
  135. return FALSE;
  136. } else {
  137. ev_timeline_rewind (timeline);
  138. }
  139. }
  140. return TRUE;
  141. }
  142. static void
  143. ev_timeline_real_start (EvTimeline *timeline)
  144. {
  145. EvTimelinePrivate *priv;
  146. priv = ev_timeline_get_instance_private (timeline);
  147. if (!priv->source_id) {
  148. if (priv->timer)
  149. g_timer_continue (priv->timer);
  150. else
  151. priv->timer = g_timer_new ();
  152. /* sanity check */
  153. g_assert (priv->fps > 0);
  154. g_signal_emit (timeline, signals [STARTED], 0);
  155. priv->source_id = g_timeout_add (FRAME_INTERVAL (priv->fps),
  156. (GSourceFunc) ev_timeline_run_frame,
  157. timeline);
  158. }
  159. }
  160. static void
  161. ev_timeline_class_init (EvTimelineClass *class)
  162. {
  163. GObjectClass *object_class = G_OBJECT_CLASS (class);
  164. object_class->set_property = ev_timeline_set_property;
  165. object_class->get_property = ev_timeline_get_property;
  166. object_class->finalize = ev_timeline_finalize;
  167. class->start = ev_timeline_real_start;
  168. g_object_class_install_property (object_class,
  169. PROP_FPS,
  170. g_param_spec_uint ("fps",
  171. "FPS",
  172. "Frames per second for the timeline",
  173. 1,
  174. G_MAXUINT,
  175. DEFAULT_FPS,
  176. G_PARAM_READWRITE));
  177. g_object_class_install_property (object_class,
  178. PROP_DURATION,
  179. g_param_spec_uint ("duration",
  180. "Animation Duration",
  181. "Animation Duration",
  182. 0,
  183. G_MAXUINT,
  184. 0,
  185. G_PARAM_READWRITE));
  186. g_object_class_install_property (object_class,
  187. PROP_LOOP,
  188. g_param_spec_boolean ("loop",
  189. "Loop",
  190. "Whether the timeline loops or not",
  191. FALSE,
  192. G_PARAM_READWRITE));
  193. signals[STARTED] =
  194. g_signal_new ("started",
  195. G_TYPE_FROM_CLASS (object_class),
  196. G_SIGNAL_RUN_LAST,
  197. G_STRUCT_OFFSET (EvTimelineClass, started),
  198. NULL, NULL,
  199. g_cclosure_marshal_VOID__VOID,
  200. G_TYPE_NONE, 0);
  201. signals[PAUSED] =
  202. g_signal_new ("paused",
  203. G_TYPE_FROM_CLASS (object_class),
  204. G_SIGNAL_RUN_LAST,
  205. G_STRUCT_OFFSET (EvTimelineClass, paused),
  206. NULL, NULL,
  207. g_cclosure_marshal_VOID__VOID,
  208. G_TYPE_NONE, 0);
  209. signals[FINISHED] =
  210. g_signal_new ("finished",
  211. G_TYPE_FROM_CLASS (object_class),
  212. G_SIGNAL_RUN_LAST,
  213. G_STRUCT_OFFSET (EvTimelineClass, finished),
  214. NULL, NULL,
  215. g_cclosure_marshal_VOID__VOID,
  216. G_TYPE_NONE, 0);
  217. signals[FRAME] =
  218. g_signal_new ("frame",
  219. G_TYPE_FROM_CLASS (object_class),
  220. G_SIGNAL_RUN_LAST,
  221. G_STRUCT_OFFSET (EvTimelineClass, frame),
  222. NULL, NULL,
  223. g_cclosure_marshal_VOID__DOUBLE,
  224. G_TYPE_NONE, 1,
  225. G_TYPE_DOUBLE);
  226. }
  227. EvTimeline *
  228. ev_timeline_new (guint duration)
  229. {
  230. return g_object_new (EV_TYPE_TIMELINE,
  231. "duration", duration,
  232. NULL);
  233. }
  234. void
  235. ev_timeline_start (EvTimeline *timeline)
  236. {
  237. g_return_if_fail (EV_IS_TIMELINE (timeline));
  238. EV_TIMELINE_GET_CLASS (timeline)->start (timeline);
  239. }
  240. void
  241. ev_timeline_pause (EvTimeline *timeline)
  242. {
  243. EvTimelinePrivate *priv;
  244. g_return_if_fail (EV_IS_TIMELINE (timeline));
  245. priv = ev_timeline_get_instance_private (timeline);
  246. if (priv->source_id) {
  247. g_source_remove (priv->source_id);
  248. priv->source_id = 0;
  249. g_timer_stop (priv->timer);
  250. g_signal_emit (timeline, signals [PAUSED], 0);
  251. }
  252. }
  253. void
  254. ev_timeline_rewind (EvTimeline *timeline)
  255. {
  256. EvTimelinePrivate *priv;
  257. g_return_if_fail (EV_IS_TIMELINE (timeline));
  258. priv = ev_timeline_get_instance_private (timeline);
  259. /* destroy and re-create timer if neccesary */
  260. if (priv->timer) {
  261. g_timer_destroy (priv->timer);
  262. if (ev_timeline_is_running (timeline))
  263. priv->timer = g_timer_new ();
  264. else
  265. priv->timer = NULL;
  266. }
  267. }
  268. gboolean
  269. ev_timeline_is_running (EvTimeline *timeline)
  270. {
  271. EvTimelinePrivate *priv;
  272. g_return_val_if_fail (EV_IS_TIMELINE (timeline), FALSE);
  273. priv = ev_timeline_get_instance_private (timeline);
  274. return (priv->source_id != 0);
  275. }
  276. guint
  277. ev_timeline_get_fps (EvTimeline *timeline)
  278. {
  279. EvTimelinePrivate *priv;
  280. g_return_val_if_fail (EV_IS_TIMELINE (timeline), 1);
  281. priv = ev_timeline_get_instance_private (timeline);
  282. return priv->fps;
  283. }
  284. void
  285. ev_timeline_set_fps (EvTimeline *timeline,
  286. guint fps)
  287. {
  288. EvTimelinePrivate *priv;
  289. g_return_if_fail (EV_IS_TIMELINE (timeline));
  290. priv = ev_timeline_get_instance_private (timeline);
  291. priv->fps = fps;
  292. if (ev_timeline_is_running (timeline)) {
  293. g_source_remove (priv->source_id);
  294. priv->source_id = g_timeout_add (FRAME_INTERVAL (priv->fps),
  295. (GSourceFunc) ev_timeline_run_frame,
  296. timeline);
  297. }
  298. g_object_notify (G_OBJECT (timeline), "fps");
  299. }
  300. gboolean
  301. ev_timeline_get_loop (EvTimeline *timeline)
  302. {
  303. EvTimelinePrivate *priv;
  304. g_return_val_if_fail (EV_IS_TIMELINE (timeline), FALSE);
  305. priv = ev_timeline_get_instance_private (timeline);
  306. return priv->loop;
  307. }
  308. void
  309. ev_timeline_set_loop (EvTimeline *timeline,
  310. gboolean loop)
  311. {
  312. EvTimelinePrivate *priv;
  313. g_return_if_fail (EV_IS_TIMELINE (timeline));
  314. priv = ev_timeline_get_instance_private (timeline);
  315. priv->loop = (loop != FALSE);
  316. g_object_notify (G_OBJECT (timeline), "loop");
  317. }
  318. void
  319. ev_timeline_set_duration (EvTimeline *timeline,
  320. guint duration)
  321. {
  322. EvTimelinePrivate *priv;
  323. g_return_if_fail (EV_IS_TIMELINE (timeline));
  324. priv = ev_timeline_get_instance_private (timeline);
  325. priv->duration = duration;
  326. g_object_notify (G_OBJECT (timeline), "duration");
  327. }
  328. guint
  329. ev_timeline_get_duration (EvTimeline *timeline)
  330. {
  331. EvTimelinePrivate *priv;
  332. g_return_val_if_fail (EV_IS_TIMELINE (timeline), 0);
  333. priv = ev_timeline_get_instance_private (timeline);
  334. return priv->duration;
  335. }
  336. gdouble
  337. ev_timeline_get_progress (EvTimeline *timeline)
  338. {
  339. EvTimelinePrivate *priv;
  340. gdouble progress;
  341. guint elapsed_time;
  342. g_return_val_if_fail (EV_IS_TIMELINE (timeline), 0.0);
  343. priv = ev_timeline_get_instance_private (timeline);
  344. if (!priv->timer)
  345. return 0.;
  346. elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000);
  347. progress = (gdouble) elapsed_time / priv->duration;
  348. return CLAMP (progress, 0., 1.);
  349. }