elementary/elm_entry : Fix a bug in filter callback. There can be a
[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_get(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 Eina_Bool
314 elm_video_file_set(Evas_Object *video, const char *filename)
315 {
316 #ifdef HAVE_EMOTION
317    ELM_CHECK_WIDTYPE(video, widtype) EINA_FALSE;
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    if (!emotion_object_file_set(wd->emotion, filename)) return EINA_FALSE;
323
324    if ((!strncmp(filename, "file://", 7)) || (!strstr(filename, "://")))
325      emotion_object_last_position_load(wd->emotion);
326
327    edje_object_signal_emit(wd->layout, "elm,video,load", "elm");
328
329    return EINA_TRUE;
330 #else
331    (void) video;
332    (void) filename;
333
334    return EINA_FALSE;
335 #endif
336 }
337
338 EAPI Evas_Object *
339 elm_video_emotion_get(const Evas_Object *video)
340 {
341 #ifdef HAVE_EMOTION
342    ELM_CHECK_WIDTYPE(video, widtype) NULL;
343    Widget_Data *wd = elm_widget_data_get(video);
344
345    return wd->emotion;
346 #else
347    (void) video;
348    return NULL;
349 #endif
350 }
351
352 EAPI void
353 elm_video_play(Evas_Object *video)
354 {
355 #ifdef HAVE_EMOTION
356    ELM_CHECK_WIDTYPE(video, widtype);
357    Widget_Data *wd = elm_widget_data_get(video);
358
359    if (emotion_object_play_get(wd->emotion)) return ;
360
361    if (wd->timer) ecore_timer_del(wd->timer);
362    wd->timer = NULL;
363    wd->stop = EINA_FALSE;
364    emotion_object_play_set(wd->emotion, EINA_TRUE);
365 #else
366    (void) video;
367 #endif
368 }
369
370 /* FIXME: pause will setup timer and go into sleep or
371  * hibernate after a while without activity.
372  */
373
374 EAPI void
375 elm_video_pause(Evas_Object *video)
376 {
377 #ifdef HAVE_EMOTION
378    ELM_CHECK_WIDTYPE(video, widtype);
379    Widget_Data *wd = elm_widget_data_get(video);
380
381    if (!emotion_object_play_get(wd->emotion)) return ;
382
383    if (!wd->timer) wd->timer = ecore_timer_add(20.0, _suspend_cb, video);
384    emotion_object_play_set(wd->emotion, EINA_FALSE);
385    edje_object_signal_emit(wd->layout, "elm,video,pause", "elm");
386 #else
387    (void) video;
388 #endif
389 }
390
391 /* FIXME: stop should go into hibernate state directly.
392  */
393 EAPI void
394 elm_video_stop(Evas_Object *video)
395 {
396 #ifdef HAVE_EMOTION
397    ELM_CHECK_WIDTYPE(video, widtype);
398    Widget_Data *wd = elm_widget_data_get(video);
399
400    if (!emotion_object_play_get(wd->emotion) && wd->stop) return ;
401
402    if (wd->timer) ecore_timer_del(wd->timer);
403    wd->timer = NULL;
404    wd->stop = EINA_TRUE;
405    emotion_object_play_set(wd->emotion, EINA_FALSE);
406    edje_object_signal_emit(wd->layout, "elm,video,stop", "elm");
407    emotion_object_suspend_set(wd->emotion, EMOTION_HIBERNATE);
408 #else
409    (void) video;
410 #endif
411 }
412
413 EAPI Eina_Bool
414 elm_video_is_playing_get(const Evas_Object *video)
415 {
416 #ifdef HAVE_EMOTION
417    ELM_CHECK_WIDTYPE(video, widtype) EINA_FALSE;
418    Widget_Data *wd = elm_widget_data_get(video);
419
420    return emotion_object_play_get(wd->emotion);
421 #else
422    (void) video;
423    return EINA_FALSE;
424 #endif
425 }
426
427 EAPI Eina_Bool
428 elm_video_is_seekable_get(const Evas_Object *video)
429 {
430 #ifdef HAVE_EMOTION
431    ELM_CHECK_WIDTYPE(video, widtype) EINA_FALSE;
432    Widget_Data *wd = elm_widget_data_get(video);
433
434    return emotion_object_seekable_get(wd->emotion);
435 #else
436    (void) video;
437    return EINA_FALSE;
438 #endif
439 }
440
441 EAPI Eina_Bool
442 elm_video_audio_mute_get(const Evas_Object *video)
443 {
444 #ifdef HAVE_EMOTION
445    ELM_CHECK_WIDTYPE(video, widtype) EINA_FALSE;
446    Widget_Data *wd = elm_widget_data_get(video);
447
448    return emotion_object_audio_mute_get(wd->emotion);
449 #else
450    (void) video;
451    return EINA_FALSE;
452 #endif
453 }
454
455 EAPI void
456 elm_video_audio_mute_set(Evas_Object *video, Eina_Bool mute)
457 {
458 #ifdef HAVE_EMOTION
459    ELM_CHECK_WIDTYPE(video, widtype);
460    Widget_Data *wd = elm_widget_data_get(video);
461
462    emotion_object_audio_mute_set(wd->emotion, mute);
463 #else
464    (void) video;
465    (void) mute;
466 #endif
467 }
468
469 EAPI double
470 elm_video_audio_level_get(const Evas_Object *video)
471 {
472 #ifdef HAVE_EMOTION
473    ELM_CHECK_WIDTYPE(video, widtype) 0.0;
474    Widget_Data *wd = elm_widget_data_get(video);
475
476    return emotion_object_audio_volume_get(wd->emotion);
477 #else
478    (void) video;
479    return 0.0;
480 #endif
481 }
482
483 EAPI void
484 elm_video_audio_level_set(Evas_Object *video, double volume)
485 {
486 #ifdef HAVE_EMOTION
487    ELM_CHECK_WIDTYPE(video, widtype);
488    Widget_Data *wd = elm_widget_data_get(video);
489
490    emotion_object_audio_volume_set(wd->emotion, volume);
491 #else
492    (void) video;
493    (void) volume;
494 #endif
495 }
496
497 EAPI double
498 elm_video_play_position_get(const Evas_Object *video)
499 {
500 #ifdef HAVE_EMOTION
501    ELM_CHECK_WIDTYPE(video, widtype) 0.0;
502    Widget_Data *wd = elm_widget_data_get(video);
503
504    return emotion_object_position_get(wd->emotion);
505 #else
506    (void) video;
507    return 0.0;
508 #endif
509 }
510
511 EAPI void
512 elm_video_play_position_set(Evas_Object *video, double position)
513 {
514 #ifdef HAVE_EMOTION
515    ELM_CHECK_WIDTYPE(video, widtype);
516    Widget_Data *wd = elm_widget_data_get(video);
517
518    emotion_object_position_set(wd->emotion, position);
519 #else
520    (void) video;
521    (void) position;
522 #endif
523 }
524
525 EAPI double
526 elm_video_play_length_get(const Evas_Object *video)
527 {
528 #ifdef HAVE_EMOTION
529    ELM_CHECK_WIDTYPE(video, widtype) 0.0;
530    Widget_Data *wd = elm_widget_data_get(video);
531
532    return emotion_object_play_length_get(wd->emotion);
533 #else
534    (void) video;
535    return 0.0;
536 #endif
537 }
538
539 EAPI const char *
540 elm_video_title_get(const Evas_Object *video)
541 {
542 #ifdef HAVE_EMOTION
543    ELM_CHECK_WIDTYPE(video, widtype) NULL;
544    Widget_Data *wd = elm_widget_data_get(video);
545
546    return emotion_object_title_get(wd->emotion);
547 #else
548    (void) video;
549    return NULL;
550 #endif
551 }
552
553 EAPI void
554 elm_video_remember_position_set(Evas_Object *video, Eina_Bool remember)
555 {
556 #ifdef HAVE_EMOTION
557    ELM_CHECK_WIDTYPE(video, widtype);
558    Widget_Data *wd = elm_widget_data_get(video);
559
560    wd->remember = remember;
561 #else
562    (void) video;
563    (void) remember;
564 #endif
565 }
566
567 EAPI Eina_Bool
568 elm_video_remember_position_get(const Evas_Object *video)
569 {
570 #ifdef HAVE_EMOTION
571    ELM_CHECK_WIDTYPE(video, widtype) EINA_FALSE;
572    Widget_Data *wd = elm_widget_data_get(video);
573
574    return wd->remember;
575 #else
576    (void) video;
577    return EINA_FALSE;
578 #endif
579 }