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