1 #include <Elementary.h>
9 * @defgroup Video Video
11 * This object take care of setting up an Emotion object to display it's content with the right
12 * aspect ratio. If build with eio, it also remember the last position that was played and start
13 * playing from this position. It expose the basic property of an Emotion and let the more complex
14 * accessible by retrieving the Emotion object. It also needed to link it with a Elementary @ref player.
17 /* TODO: add buffering support to Emotion and display buffering progression in the theme when needed */
19 typedef struct _Widget_Data Widget_Data;
28 Eina_Bool remember : 1;
32 static const char *widtype = NULL;
34 static const Evas_Smart_Cb_Description _signals[] = {
38 static void _del_hook(Evas_Object *obj);
39 static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
40 static void _theme_hook(Evas_Object *obj);
41 static void _sizing_eval(Evas_Object *obj);
42 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
43 static void _on_focus_hook(void *data, Evas_Object *obj);
44 static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src,
45 Evas_Callback_Type type, void *event_info);
48 _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info)
50 if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
51 Evas_Event_Key_Down *ev = event_info;
52 Widget_Data *wd = elm_widget_data_get(obj);
53 if (!wd) return EINA_FALSE;
54 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
55 if (elm_widget_disabled_get(obj)) return EINA_FALSE;
56 if ((!strcmp(ev->keyname, "Left")) || (!strcmp(ev->keyname, "KP_Left")))
60 current = elm_video_play_position_get(obj);
61 last = elm_video_play_length_get(obj);
65 current += last / 100;
66 elm_video_play_position_set(obj, current);
69 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
72 if ((!strcmp(ev->keyname, "Right")) || (!strcmp(ev->keyname, "KP_Right")))
76 current = elm_video_play_position_get(obj);
77 last = elm_video_play_length_get(obj);
81 current -= last / 100;
82 if (current < 0) current = 0;
83 elm_video_play_position_set(obj, current);
86 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
89 if (!strcmp(ev->keyname, "space"))
91 if (elm_video_is_playing(obj))
95 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
98 fprintf(stderr, "keyname: '%s' not handle\n", ev->keyname);
103 _del_hook(Evas_Object *obj)
105 Widget_Data *wd = elm_widget_data_get(obj);
108 if (wd->timer) ecore_timer_del(wd->timer);
113 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
115 Widget_Data *wd = elm_widget_data_get(obj);
117 if (elm_widget_focus_get(obj))
119 edje_object_signal_emit(wd->layout, "elm,action,focus", "elm");
120 evas_object_focus_set(wd->layout, EINA_TRUE);
124 edje_object_signal_emit(wd->layout, "elm,action,unfocus", "elm");
125 evas_object_focus_set(wd->layout, EINA_FALSE);
130 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
132 Widget_Data *wd = elm_widget_data_get(obj);
134 edje_object_mirrored_set(wd->layout, rtl);
138 _theme_hook(Evas_Object *obj)
140 Widget_Data *wd = elm_widget_data_get(obj);
142 _elm_widget_mirrored_reload(obj);
143 _mirrored_set(obj, elm_widget_mirrored_get(obj));
144 _elm_theme_object_set(obj, wd->layout, "video", "base", elm_widget_style_get(obj));
145 edje_object_scale_set(wd->layout, elm_widget_scale_get(obj) *
151 _sizing_eval(Evas_Object *obj)
153 Widget_Data *wd = elm_widget_data_get(obj);
154 Evas_Coord minw = -1, minh = -1;
158 evas_object_size_hint_request_get(wd->emotion, &minw, &minh);
159 evas_object_size_hint_aspect_set(wd->emotion, EVAS_ASPECT_CONTROL_BOTH, minw, minh);
160 edje_object_size_min_calc(wd->layout, &w, &h);
162 if (w != 0 && h != 0)
167 evas_object_size_hint_aspect_set(obj, EVAS_ASPECT_CONTROL_BOTH, minw, minh);
171 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
177 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
179 Widget_Data *wd = elm_widget_data_get(obj);
181 if (wd->remember) emotion_object_last_position_save(wd->emotion);
185 _open_done(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
187 Widget_Data *wd = elm_widget_data_get(data);
189 edje_object_signal_emit(wd->layout, "elm,video,open", "elm");
193 _playback_started(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
195 Widget_Data *wd = elm_widget_data_get(data);
197 edje_object_signal_emit(wd->layout, "elm,video,play", "elm");
201 _playback_finished(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
203 Widget_Data *wd = elm_widget_data_get(data);
205 edje_object_signal_emit(wd->layout, "elm,video,end", "elm");
209 _update_aspect_ratio(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
215 _title_change(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
217 Widget_Data *wd = elm_widget_data_get(data);
220 title = emotion_object_title_get(wd->emotion);
221 edje_object_part_text_set(wd->layout, "elm,title", title);
222 edje_object_signal_emit(wd->layout, "elm,video,title", "elm");
226 _audio_level_change(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
232 _suspend_cb(void *data)
234 Widget_Data *wd = elm_widget_data_get(data);
237 interval = ecore_timer_interval_get(wd->timer);
239 emotion_object_suspend_set(wd->emotion, EMOTION_SLEEP);
240 else if (interval <= 30)
241 emotion_object_suspend_set(wd->emotion, EMOTION_DEEP_SLEEP);
244 emotion_object_suspend_set(wd->emotion, EMOTION_HIBERNATE);
246 return ECORE_CALLBACK_CANCEL;
249 ecore_timer_interval_set(wd->timer, interval + 10);
250 return ECORE_CALLBACK_RENEW;
255 _elm_video_check(Evas_Object *video)
258 ELM_CHECK_WIDTYPE(video, widtype) EINA_FALSE;
267 elm_video_add(Evas_Object *parent)
274 ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
275 ELM_SET_WIDTYPE(widtype, "video");
276 elm_widget_type_set(obj, "video");
277 elm_widget_sub_object_add(parent, obj);
278 elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
279 elm_widget_data_set(obj, wd);
280 elm_widget_del_hook_set(obj, _del_hook);
281 elm_widget_theme_hook_set(obj, _theme_hook);
282 elm_widget_can_focus_set(obj, EINA_TRUE);
283 elm_widget_event_hook_set(obj, _event_hook);
285 wd->stop = EINA_FALSE;
286 wd->remember = EINA_FALSE;
288 wd->layout = edje_object_add(e);
289 _elm_theme_object_set(obj, wd->layout, "video", "base", "default");
290 elm_widget_resize_object_set(obj, wd->layout);
291 elm_widget_sub_object_add(obj, wd->layout);
292 evas_object_show(wd->layout);
293 evas_object_size_hint_weight_set(wd->layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
295 wd->emotion = emotion_object_add(e);
296 emotion_object_init(wd->emotion, NULL);
297 edje_object_part_swallow(wd->layout, "elm.swallow.video", wd->emotion);
298 elm_widget_sub_object_add(obj, wd->emotion);
300 evas_object_smart_callback_add(wd->emotion, "open_done", _open_done, obj);
301 evas_object_smart_callback_add(wd->emotion, "playback_started", _playback_started, obj);
302 evas_object_smart_callback_add(wd->emotion, "playback_finished", _playback_finished, obj);
303 evas_object_smart_callback_add(wd->emotion, "frame_resize", _update_aspect_ratio, obj);
304 evas_object_smart_callback_add(wd->emotion, "title_change", _title_change, obj);
305 evas_object_smart_callback_add(wd->emotion, "audio_level_change", _audio_level_change, obj);
307 evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
308 evas_object_event_callback_add(obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, NULL);
309 evas_object_smart_callbacks_descriptions_set(obj, _signals);
311 _mirrored_set(obj, elm_widget_mirrored_get(obj));
314 wd->timer = ecore_timer_add(20.0, _suspend_cb, obj);
324 elm_video_file_set(Evas_Object *video, const char *filename)
327 ELM_CHECK_WIDTYPE(video, widtype);
328 Widget_Data *wd = elm_widget_data_get(video);
330 if (wd->remember) emotion_object_last_position_save(wd->emotion);
331 wd->stop = EINA_FALSE;
332 emotion_object_file_set(wd->emotion, filename);
333 emotion_object_last_position_load(wd->emotion);
334 edje_object_signal_emit(wd->layout, "elm,video,load", "elm");
342 elm_video_uri_set(Evas_Object *video, const char *uri)
345 ELM_CHECK_WIDTYPE(video, widtype);
346 Widget_Data *wd = elm_widget_data_get(video);
348 if (wd->remember) emotion_object_last_position_save(wd->emotion);
349 wd->stop = EINA_FALSE;
350 emotion_object_file_set(wd->emotion, uri);
351 edje_object_signal_emit(wd->layout, "elm,video,load", "elm");
359 elm_video_emotion_get(Evas_Object *video)
362 ELM_CHECK_WIDTYPE(video, widtype) NULL;
363 Widget_Data *wd = elm_widget_data_get(video);
373 elm_video_play(Evas_Object *video)
376 ELM_CHECK_WIDTYPE(video, widtype);
377 Widget_Data *wd = elm_widget_data_get(video);
379 if (emotion_object_play_get(wd->emotion)) return ;
381 if (wd->timer) ecore_timer_del(wd->timer);
383 wd->stop = EINA_FALSE;
384 emotion_object_play_set(wd->emotion, EINA_TRUE);
390 /* FIXME: pause will setup timer and go into sleep or
391 * hibernate after a while without activity.
395 elm_video_pause(Evas_Object *video)
398 ELM_CHECK_WIDTYPE(video, widtype);
399 Widget_Data *wd = elm_widget_data_get(video);
401 if (!emotion_object_play_get(wd->emotion)) return ;
403 if (!wd->timer) wd->timer = ecore_timer_add(20.0, _suspend_cb, video);
404 emotion_object_play_set(wd->emotion, EINA_FALSE);
405 edje_object_signal_emit(wd->layout, "elm,video,pause", "elm");
411 /* FIXME: stop should go into hibernate state directly.
414 elm_video_stop(Evas_Object *video)
417 ELM_CHECK_WIDTYPE(video, widtype);
418 Widget_Data *wd = elm_widget_data_get(video);
420 if (!emotion_object_play_get(wd->emotion) && wd->stop) return ;
422 if (wd->timer) ecore_timer_del(wd->timer);
424 wd->stop = EINA_TRUE;
425 emotion_object_play_set(wd->emotion, EINA_FALSE);
426 edje_object_signal_emit(wd->layout, "elm,video,stop", "elm");
427 emotion_object_suspend_set(wd->emotion, EMOTION_HIBERNATE);
434 elm_video_is_playing(Evas_Object *video)
437 ELM_CHECK_WIDTYPE(video, widtype) EINA_FALSE;
438 Widget_Data *wd = elm_widget_data_get(video);
440 return emotion_object_play_get(wd->emotion);
448 elm_video_is_seekable(Evas_Object *video)
451 ELM_CHECK_WIDTYPE(video, widtype) EINA_FALSE;
452 Widget_Data *wd = elm_widget_data_get(video);
454 return emotion_object_seekable_get(wd->emotion);
462 elm_video_audio_mute_get(Evas_Object *video)
465 ELM_CHECK_WIDTYPE(video, widtype) EINA_FALSE;
466 Widget_Data *wd = elm_widget_data_get(video);
468 return emotion_object_audio_mute_get(wd->emotion);
476 elm_video_audio_mute_set(Evas_Object *video, Eina_Bool mute)
479 ELM_CHECK_WIDTYPE(video, widtype);
480 Widget_Data *wd = elm_widget_data_get(video);
482 emotion_object_audio_mute_set(wd->emotion, mute);
490 elm_video_audio_level_get(Evas_Object *video)
493 ELM_CHECK_WIDTYPE(video, widtype) 0.0;
494 Widget_Data *wd = elm_widget_data_get(video);
496 return emotion_object_audio_volume_get(wd->emotion);
504 elm_video_audio_level_set(Evas_Object *video, double volume)
507 ELM_CHECK_WIDTYPE(video, widtype);
508 Widget_Data *wd = elm_widget_data_get(video);
510 emotion_object_audio_volume_set(wd->emotion, volume);
518 elm_video_play_position_get(Evas_Object *video)
521 ELM_CHECK_WIDTYPE(video, widtype) 0.0;
522 Widget_Data *wd = elm_widget_data_get(video);
524 return emotion_object_position_get(wd->emotion);
532 elm_video_play_position_set(Evas_Object *video, double position)
535 ELM_CHECK_WIDTYPE(video, widtype);
536 Widget_Data *wd = elm_widget_data_get(video);
538 emotion_object_position_set(wd->emotion, position);
546 elm_video_play_length_get(Evas_Object *video)
549 ELM_CHECK_WIDTYPE(video, widtype) 0.0;
550 Widget_Data *wd = elm_widget_data_get(video);
552 return emotion_object_play_length_get(wd->emotion);
560 elm_video_title_get(Evas_Object *video)
563 ELM_CHECK_WIDTYPE(video, widtype) NULL;
564 Widget_Data *wd = elm_widget_data_get(video);
566 return emotion_object_title_get(wd->emotion);
574 elm_video_remember_position_set(Evas_Object *video, Eina_Bool remember)
577 ELM_CHECK_WIDTYPE(video, widtype);
578 Widget_Data *wd = elm_widget_data_get(video);
580 wd->remember = remember;
588 elm_video_remember_position_get(Evas_Object *video)
591 ELM_CHECK_WIDTYPE(video, widtype) EINA_FALSE;
592 Widget_Data *wd = elm_widget_data_get(video);