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