elementary: adding const to accessor of elm_video
[framework/uifw/elementary.git] / src / lib / elm_video.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 #ifdef HAVE_EMOTION
5 # include <Emotion.h>
6 #endif
7
8 /* TODO: add buffering support to Emotion and display buffering progression in the theme when needed */
9
10 typedef struct _Widget_Data Widget_Data;
11 struct _Widget_Data
12 {
13    Evas_Object *layout;
14    Evas_Object *emotion;
15
16    Ecore_Timer *timer;
17
18    Eina_Bool stop : 1;
19    Eina_Bool remember : 1;
20 };
21
22 #ifdef HAVE_EMOTION
23 static const char *widtype = NULL;
24
25 static const Evas_Smart_Cb_Description _signals[] = {
26   { NULL, NULL }
27 };
28
29 static void _del_hook(Evas_Object *obj);
30 static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
31 static void _theme_hook(Evas_Object *obj);
32 static void _sizing_eval(Evas_Object *obj);
33 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
34 static void _on_focus_hook(void *data, Evas_Object *obj);
35 static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src,
36                              Evas_Callback_Type type, void *event_info);
37
38 static Eina_Bool
39 _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info)
40 {
41    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
42    Evas_Event_Key_Down *ev = event_info;
43    Widget_Data *wd = elm_widget_data_get(obj);
44    if (!wd) return EINA_FALSE;
45    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
46    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
47    if ((!strcmp(ev->keyname, "Left")) || (!strcmp(ev->keyname, "KP_Left")))
48      {
49         double current, last;
50
51         current = elm_video_play_position_get(obj);
52         last = elm_video_play_length_get(obj);
53
54         if (current < last)
55           {
56              current += last / 100;
57              elm_video_play_position_set(obj, current);
58           }
59
60         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
61         return EINA_TRUE;
62      }
63    if ((!strcmp(ev->keyname, "Right")) || (!strcmp(ev->keyname, "KP_Right")))
64      {
65         double current, last;
66
67         current = elm_video_play_position_get(obj);
68         last = elm_video_play_length_get(obj);
69
70         if (current > 0)
71           {
72              current -= last / 100;
73              if (current < 0) current = 0;
74              elm_video_play_position_set(obj, current);
75           }
76
77         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
78         return EINA_TRUE;
79      }
80    if (!strcmp(ev->keyname, "space"))
81      {
82         if (elm_video_is_playing(obj))
83           elm_video_pause(obj);
84         else
85           elm_video_play(obj);
86         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
87         return EINA_TRUE;
88      }
89    fprintf(stderr, "keyname: '%s' not handle\n", ev->keyname);
90    return EINA_FALSE;
91 }
92
93 static void
94 _del_hook(Evas_Object *obj)
95 {
96    Widget_Data *wd = elm_widget_data_get(obj);
97
98    if (!wd) return;
99    if (wd->timer) ecore_timer_del(wd->timer);
100    free(wd);
101 }
102
103 static void
104 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
105 {
106    Widget_Data *wd = elm_widget_data_get(obj);
107    if (!wd) return;
108    if (elm_widget_focus_get(obj))
109      {
110         edje_object_signal_emit(wd->layout, "elm,action,focus", "elm");
111         evas_object_focus_set(wd->layout, EINA_TRUE);
112      }
113    else
114      {
115         edje_object_signal_emit(wd->layout, "elm,action,unfocus", "elm");
116         evas_object_focus_set(wd->layout, EINA_FALSE);
117      }
118 }
119
120 static void
121 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
122 {
123    Widget_Data *wd = elm_widget_data_get(obj);
124    if (!wd) return;
125    edje_object_mirrored_set(wd->layout, rtl);
126 }
127
128 static void
129 _theme_hook(Evas_Object *obj)
130 {
131    Widget_Data *wd = elm_widget_data_get(obj);
132    if (!wd) return;
133    _elm_widget_mirrored_reload(obj);
134    _mirrored_set(obj, elm_widget_mirrored_get(obj));
135    _elm_theme_object_set(obj, wd->layout, "video", "base", elm_widget_style_get(obj));
136    edje_object_scale_set(wd->layout, elm_widget_scale_get(obj) *
137                          _elm_config->scale);
138    _sizing_eval(obj);
139 }
140
141 static void
142 _sizing_eval(Evas_Object *obj)
143 {
144    Widget_Data *wd = elm_widget_data_get(obj);
145    Evas_Coord minw = -1, minh = -1;
146    Evas_Coord w, h;
147
148    if (!wd) return;
149    evas_object_size_hint_request_get(wd->emotion, &minw, &minh);
150    evas_object_size_hint_aspect_set(wd->emotion, EVAS_ASPECT_CONTROL_BOTH, minw, minh);
151    edje_object_size_min_calc(wd->layout, &w, &h);
152
153    if (w != 0 && h != 0)
154      {
155         minw = w;
156         minh = h;
157      }
158    evas_object_size_hint_aspect_set(obj, EVAS_ASPECT_CONTROL_BOTH, minw, minh);
159 }
160
161 static void
162 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
163 {
164    _sizing_eval(data);
165 }
166
167 static void
168 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
169 {
170    Widget_Data *wd = elm_widget_data_get(obj);
171
172    if (wd->remember) emotion_object_last_position_save(wd->emotion);
173 }
174
175 static void
176 _open_done(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
177 {
178    Widget_Data *wd = elm_widget_data_get(data);
179
180    edje_object_signal_emit(wd->layout, "elm,video,open", "elm");
181 }
182
183 static void
184 _playback_started(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
185 {
186    Widget_Data *wd = elm_widget_data_get(data);
187
188    edje_object_signal_emit(wd->layout, "elm,video,play", "elm");
189 }
190
191 static void
192 _playback_finished(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
193 {
194    Widget_Data *wd = elm_widget_data_get(data);
195
196    edje_object_signal_emit(wd->layout, "elm,video,end", "elm");
197 }
198
199 static void
200 _update_aspect_ratio(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
201 {
202    _sizing_eval(data);
203 }
204
205 static void
206 _title_change(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
207 {
208    Widget_Data *wd = elm_widget_data_get(data);
209    const char *title;
210
211    title = emotion_object_title_get(wd->emotion);
212    edje_object_part_text_set(wd->layout, "elm,title", title);
213    edje_object_signal_emit(wd->layout, "elm,video,title", "elm");
214 }
215
216 static void
217 _audio_level_change(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
218 {
219    (void) data;
220 }
221
222 static Eina_Bool
223 _suspend_cb(void *data)
224 {
225    Widget_Data *wd = elm_widget_data_get(data);
226    double interval;
227
228    interval = ecore_timer_interval_get(wd->timer);
229    if (interval <= 20)
230      emotion_object_suspend_set(wd->emotion, EMOTION_SLEEP);
231    else if (interval <= 30)
232      emotion_object_suspend_set(wd->emotion, EMOTION_DEEP_SLEEP);
233    else
234      {
235         emotion_object_suspend_set(wd->emotion, EMOTION_HIBERNATE);
236         wd->timer = NULL;
237         return ECORE_CALLBACK_CANCEL;
238      }
239
240    ecore_timer_interval_set(wd->timer, interval + 10);
241    return ECORE_CALLBACK_RENEW;
242 }
243 #endif
244
245 Eina_Bool
246 _elm_video_check(Evas_Object *video)
247 {
248 #ifdef HAVE_EMOTION
249   ELM_CHECK_WIDTYPE(video, widtype) EINA_FALSE;
250   return EINA_TRUE;
251 #else
252   (void) video;
253   return EINA_FALSE;
254 #endif
255 }
256
257 EAPI Evas_Object *
258 elm_video_add(Evas_Object *parent)
259 {
260 #ifdef HAVE_EMOTION
261    Evas_Object *obj;
262    Evas *e;
263    Widget_Data *wd;
264
265    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
266    ELM_SET_WIDTYPE(widtype, "video");
267    elm_widget_type_set(obj, "video");
268    elm_widget_sub_object_add(parent, obj);
269    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
270    elm_widget_data_set(obj, wd);
271    elm_widget_del_hook_set(obj, _del_hook);
272    elm_widget_theme_hook_set(obj, _theme_hook);
273    elm_widget_can_focus_set(obj, EINA_TRUE);
274    elm_widget_event_hook_set(obj, _event_hook);
275
276    wd->stop = EINA_FALSE;
277    wd->remember = EINA_FALSE;
278
279    wd->layout = edje_object_add(e);
280    _elm_theme_object_set(obj, wd->layout, "video", "base", "default");
281    elm_widget_resize_object_set(obj, wd->layout);
282    evas_object_show(wd->layout);
283    evas_object_size_hint_weight_set(wd->layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
284
285    wd->emotion = emotion_object_add(e);
286    emotion_object_init(wd->emotion, NULL);
287    elm_widget_sub_object_add(obj, wd->emotion);
288    edje_object_part_swallow(wd->layout, "elm.swallow.video", wd->emotion);
289
290    evas_object_smart_callback_add(wd->emotion, "open_done", _open_done, obj);
291    evas_object_smart_callback_add(wd->emotion, "playback_started", _playback_started, obj);
292    evas_object_smart_callback_add(wd->emotion, "playback_finished", _playback_finished, obj);
293    evas_object_smart_callback_add(wd->emotion, "frame_resize", _update_aspect_ratio, obj);
294    evas_object_smart_callback_add(wd->emotion, "title_change", _title_change, obj);
295    evas_object_smart_callback_add(wd->emotion, "audio_level_change", _audio_level_change, obj);
296
297    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
298    evas_object_event_callback_add(obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, NULL);
299    evas_object_smart_callbacks_descriptions_set(obj, _signals);
300
301    _mirrored_set(obj, elm_widget_mirrored_get(obj));
302    _sizing_eval(obj);
303
304    wd->timer = ecore_timer_add(20.0, _suspend_cb, obj);
305
306    return obj;
307 #else
308    (void) parent;
309    return NULL;
310 #endif
311 }
312
313 EAPI void
314 elm_video_file_set(Evas_Object *video, const char *filename)
315 {
316 #ifdef HAVE_EMOTION
317    ELM_CHECK_WIDTYPE(video, widtype);
318    Widget_Data *wd = elm_widget_data_get(video);
319
320    if (wd->remember) emotion_object_last_position_save(wd->emotion);
321    wd->stop = EINA_FALSE;
322    emotion_object_file_set(wd->emotion, filename);
323    emotion_object_last_position_load(wd->emotion);
324    edje_object_signal_emit(wd->layout, "elm,video,load", "elm");
325 #else
326    (void) video;
327    (void) filename;
328 #endif
329 }
330
331 EAPI void
332 elm_video_uri_set(Evas_Object *video, const char *uri)
333 {
334 #ifdef HAVE_EMOTION
335    ELM_CHECK_WIDTYPE(video, widtype);
336    Widget_Data *wd = elm_widget_data_get(video);
337
338    if (wd->remember) emotion_object_last_position_save(wd->emotion);
339    wd->stop = EINA_FALSE;
340    emotion_object_file_set(wd->emotion, uri);
341    edje_object_signal_emit(wd->layout, "elm,video,load", "elm");
342 #else
343    (void) video;
344    (void) uri;
345 #endif
346 }
347
348 EAPI Evas_Object *
349 elm_video_emotion_get(const Evas_Object *video)
350 {
351 #ifdef HAVE_EMOTION
352    ELM_CHECK_WIDTYPE(video, widtype) NULL;
353    Widget_Data *wd = elm_widget_data_get(video);
354
355    return wd->emotion;
356 #else
357    (void) video;
358    return NULL;
359 #endif
360 }
361
362 EAPI void
363 elm_video_play(Evas_Object *video)
364 {
365 #ifdef HAVE_EMOTION
366    ELM_CHECK_WIDTYPE(video, widtype);
367    Widget_Data *wd = elm_widget_data_get(video);
368
369    if (emotion_object_play_get(wd->emotion)) return ;
370
371    if (wd->timer) ecore_timer_del(wd->timer);
372    wd->timer = NULL;
373    wd->stop = EINA_FALSE;
374    emotion_object_play_set(wd->emotion, EINA_TRUE);
375 #else
376    (void) video;
377 #endif
378 }
379
380 /* FIXME: pause will setup timer and go into sleep or
381  * hibernate after a while without activity.
382  */
383
384 EAPI void
385 elm_video_pause(Evas_Object *video)
386 {
387 #ifdef HAVE_EMOTION
388    ELM_CHECK_WIDTYPE(video, widtype);
389    Widget_Data *wd = elm_widget_data_get(video);
390
391    if (!emotion_object_play_get(wd->emotion)) return ;
392
393    if (!wd->timer) wd->timer = ecore_timer_add(20.0, _suspend_cb, video);
394    emotion_object_play_set(wd->emotion, EINA_FALSE);
395    edje_object_signal_emit(wd->layout, "elm,video,pause", "elm");
396 #else
397    (void) video;
398 #endif
399 }
400
401 /* FIXME: stop should go into hibernate state directly.
402  */
403 EAPI void
404 elm_video_stop(Evas_Object *video)
405 {
406 #ifdef HAVE_EMOTION
407    ELM_CHECK_WIDTYPE(video, widtype);
408    Widget_Data *wd = elm_widget_data_get(video);
409
410    if (!emotion_object_play_get(wd->emotion) && wd->stop) return ;
411
412    if (wd->timer) ecore_timer_del(wd->timer);
413    wd->timer = NULL;
414    wd->stop = EINA_TRUE;
415    emotion_object_play_set(wd->emotion, EINA_FALSE);
416    edje_object_signal_emit(wd->layout, "elm,video,stop", "elm");
417    emotion_object_suspend_set(wd->emotion, EMOTION_HIBERNATE);
418 #else
419    (void) video;
420 #endif
421 }
422
423 EAPI Eina_Bool
424 elm_video_is_playing(const Evas_Object *video)
425 {
426 #ifdef HAVE_EMOTION
427    ELM_CHECK_WIDTYPE(video, widtype) EINA_FALSE;
428    Widget_Data *wd = elm_widget_data_get(video);
429
430    return emotion_object_play_get(wd->emotion);
431 #else
432    (void) video;
433    return EINA_FALSE;
434 #endif
435 }
436
437 EAPI Eina_Bool
438 elm_video_is_seekable(const Evas_Object *video)
439 {
440 #ifdef HAVE_EMOTION
441    ELM_CHECK_WIDTYPE(video, widtype) EINA_FALSE;
442    Widget_Data *wd = elm_widget_data_get(video);
443
444    return emotion_object_seekable_get(wd->emotion);
445 #else
446    (void) video;
447    return EINA_FALSE;
448 #endif
449 }
450
451 EAPI Eina_Bool
452 elm_video_audio_mute_get(const Evas_Object *video)
453 {
454 #ifdef HAVE_EMOTION
455    ELM_CHECK_WIDTYPE(video, widtype) EINA_FALSE;
456    Widget_Data *wd = elm_widget_data_get(video);
457
458    return emotion_object_audio_mute_get(wd->emotion);
459 #else
460    (void) video;
461    return EINA_FALSE;
462 #endif
463 }
464
465 EAPI void
466 elm_video_audio_mute_set(Evas_Object *video, Eina_Bool mute)
467 {
468 #ifdef HAVE_EMOTION
469    ELM_CHECK_WIDTYPE(video, widtype);
470    Widget_Data *wd = elm_widget_data_get(video);
471
472    emotion_object_audio_mute_set(wd->emotion, mute);
473 #else
474    (void) video;
475    (void) mute;
476 #endif
477 }
478
479 EAPI double
480 elm_video_audio_level_get(const Evas_Object *video)
481 {
482 #ifdef HAVE_EMOTION
483    ELM_CHECK_WIDTYPE(video, widtype) 0.0;
484    Widget_Data *wd = elm_widget_data_get(video);
485
486    return emotion_object_audio_volume_get(wd->emotion);
487 #else
488    (void) video;
489    return 0.0;
490 #endif
491 }
492
493 EAPI void
494 elm_video_audio_level_set(Evas_Object *video, double volume)
495 {
496 #ifdef HAVE_EMOTION
497    ELM_CHECK_WIDTYPE(video, widtype);
498    Widget_Data *wd = elm_widget_data_get(video);
499
500    emotion_object_audio_volume_set(wd->emotion, volume);
501 #else
502    (void) video;
503    (void) volume;
504 #endif
505 }
506
507 EAPI double
508 elm_video_play_position_get(const Evas_Object *video)
509 {
510 #ifdef HAVE_EMOTION
511    ELM_CHECK_WIDTYPE(video, widtype) 0.0;
512    Widget_Data *wd = elm_widget_data_get(video);
513
514    return emotion_object_position_get(wd->emotion);
515 #else
516    (void) video;
517    return 0.0;
518 #endif
519 }
520
521 EAPI void
522 elm_video_play_position_set(Evas_Object *video, double position)
523 {
524 #ifdef HAVE_EMOTION
525    ELM_CHECK_WIDTYPE(video, widtype);
526    Widget_Data *wd = elm_widget_data_get(video);
527
528    emotion_object_position_set(wd->emotion, position);
529 #else
530    (void) video;
531    (void) position;
532 #endif
533 }
534
535 EAPI double
536 elm_video_play_length_get(const Evas_Object *video)
537 {
538 #ifdef HAVE_EMOTION
539    ELM_CHECK_WIDTYPE(video, widtype) 0.0;
540    Widget_Data *wd = elm_widget_data_get(video);
541
542    return emotion_object_play_length_get(wd->emotion);
543 #else
544    (void) video;
545    return 0.0;
546 #endif
547 }
548
549 EAPI const char *
550 elm_video_title_get(const Evas_Object *video)
551 {
552 #ifdef HAVE_EMOTION
553    ELM_CHECK_WIDTYPE(video, widtype) NULL;
554    Widget_Data *wd = elm_widget_data_get(video);
555
556    return emotion_object_title_get(wd->emotion);
557 #else
558    (void) video;
559    return NULL;
560 #endif
561 }
562
563 EAPI void
564 elm_video_remember_position_set(Evas_Object *video, Eina_Bool remember)
565 {
566 #ifdef HAVE_EMOTION
567    ELM_CHECK_WIDTYPE(video, widtype);
568    Widget_Data *wd = elm_widget_data_get(video);
569
570    wd->remember = remember;
571 #else
572    (void) video;
573    (void) remember;
574 #endif
575 }
576
577 EAPI Eina_Bool
578 elm_video_remember_position_get(const Evas_Object *video)
579 {
580 #ifdef HAVE_EMOTION
581    ELM_CHECK_WIDTYPE(video, widtype) EINA_FALSE;
582    Widget_Data *wd = elm_widget_data_get(video);
583
584    return wd->remember;
585 #else
586    (void) video;
587    return EINA_FALSE;
588 #endif
589 }