1 #include <Ecore_Evas.h>
7 #include <livebox-service.h>
8 #include <livebox-errno.h>
13 #define QUALITY_N_COMPRESS "quality=100 compress=1"
14 #define PUBLIC __attribute__((visibility("default")))
16 struct snapshot_info {
18 void (*flush_cb)(Evas_Object *snapshot_window, const char *id, int status, void *data);
21 Ecore_Timer *flush_timer;
27 static void post_render_cb(void *data, Evas *e, void *event_info);
28 static void pre_render_cb(void *data, Evas *e, void *event_info);
32 static inline Evas *create_virtual_canvas(int w, int h)
34 Ecore_Evas *internal_ee;
37 // Create virtual canvas
38 internal_ee = ecore_evas_buffer_new(w, h);
40 LOGD("Failed to create a new canvas buffer\n");
44 ecore_evas_alpha_set(internal_ee, EINA_TRUE);
45 ecore_evas_manual_render_set(internal_ee, EINA_FALSE);
47 // Get the "Evas" object from a virtual canvas
48 internal_e = ecore_evas_get(internal_ee);
50 ecore_evas_free(internal_ee);
51 LOGD("Faield to get Evas object\n");
60 static inline int flush_data_to_file(Evas *e, char *data, const char *filename, int w, int h)
64 output = evas_object_image_add(e);
66 LOGD("Failed to create an image object\n");
67 return LB_STATUS_ERROR_FAULT;
70 evas_object_image_data_set(output, NULL);
71 evas_object_image_colorspace_set(output, EVAS_COLORSPACE_ARGB8888);
72 evas_object_image_alpha_set(output, EINA_TRUE);
73 evas_object_image_size_set(output, w, h);
74 evas_object_image_smooth_scale_set(output, EINA_TRUE);
75 evas_object_image_data_set(output, data);
76 evas_object_image_fill_set(output, 0, 0, w, h);
77 evas_object_image_data_update_add(output, 0, 0, w, h);
79 if (evas_object_image_save(output, filename, NULL, QUALITY_N_COMPRESS) == EINA_FALSE) {
80 evas_object_del(output);
81 SECURE_LOGD("Faield to save a captured image (%s)\n", filename);
82 return LB_STATUS_ERROR_IO;
85 evas_object_del(output);
87 if (access(filename, F_OK) != 0) {
88 SECURE_LOGD("File %s is not found\n", filename);
89 return LB_STATUS_ERROR_IO;
92 SECURE_LOGD("Flush data to a file (%s)\n", filename);
93 return LB_STATUS_SUCCESS;
98 static inline int destroy_virtual_canvas(Evas *e)
102 ee = ecore_evas_ecore_evas_get(e);
104 LOGD("Failed to ecore evas object\n");
105 return LB_STATUS_ERROR_FAULT;
109 return LB_STATUS_SUCCESS;
114 static inline int flush_to_file(void *canvas, const char *filename, int w, int h)
120 shot_e = create_virtual_canvas(w, h);
122 LOGE("Unable to create a new virtual window\n");
123 return LB_STATUS_ERROR_FAULT;
126 shot_ee = ecore_evas_ecore_evas_get(shot_e);
128 LOGE("Unable to get Ecore_Evas\n");
129 destroy_virtual_canvas(shot_e);
130 return LB_STATUS_ERROR_FAULT;
133 ecore_evas_manual_render_set(shot_ee, EINA_TRUE);
135 status = flush_data_to_file(shot_e, canvas, filename, w, h);
136 destroy_virtual_canvas(shot_e);
143 static void del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
145 struct snapshot_info *info;
147 info = evas_object_data_del(obj, "snapshot,info");
152 SECURE_LOGD("Delete object (%s)\n", info->id);
154 if (info->flush_cb) {
155 info->flush_cb(obj, info->id, LB_STATUS_ERROR_CANCEL, info->data);
156 LOGD("Flush is canceled\n");
161 * Render callback will be deleted.
163 destroy_virtual_canvas(e);
170 static Eina_Bool direct_snapshot_cb(void *data)
178 void (*flush_cb)(Evas_Object *snapshot_window, const char *id, int status, void *data);
179 Evas_Object *snapshot_win = data;
180 struct snapshot_info *info;
182 info = evas_object_data_get(snapshot_win, "snapshot,info");
184 LOGE("Unable to get snapshot info\n");
185 return ECORE_CALLBACK_CANCEL;
188 info->flush_timer = NULL;
189 flush_cb = info->flush_cb;
190 info->flush_cb = NULL; /* To prevent call this from the delete callback */
192 e = evas_object_evas_get(snapshot_win);
194 LOGE("Invalid object, failed to get Evas\n");
196 flush_cb(snapshot_win, info->id, LB_STATUS_ERROR_FAULT, info->data);
198 return ECORE_CALLBACK_CANCEL;
201 ee = ecore_evas_ecore_evas_get(e);
203 LOGE("Unable to get Ecore_Evas object\n");
205 flush_cb(snapshot_win, info->id, LB_STATUS_ERROR_FAULT, info->data);
207 return ECORE_CALLBACK_CANCEL;
210 ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
211 ecore_evas_manual_render_set(ee, EINA_TRUE);
213 canvas = ecore_evas_buffer_pixels_get(ee);
215 LOGE("Failed to get canvas\n");
217 flush_cb(snapshot_win, info->id, LB_STATUS_ERROR_FAULT, info->data);
219 return ECORE_CALLBACK_CANCEL;
222 status = flush_to_file(canvas, info->id, w, h);
224 flush_cb(snapshot_win, info->id, status, info->data);
226 return ECORE_CALLBACK_CANCEL;
231 static Eina_Bool snapshot_cb(void *data)
233 Evas_Object *snapshot_win = data;
234 struct snapshot_info *info;
238 void (*flush_cb)(Evas_Object *snapshot_window, const char *id, int status, void *data);
240 info = evas_object_data_get(snapshot_win, "snapshot,info");
242 LOGE("Invalid object\n");
243 return ECORE_CALLBACK_CANCEL;
246 info->flush_timer = NULL;
247 flush_cb = info->flush_cb;
248 info->flush_cb = NULL; /* To prevent call this from the delete callback */
250 e = evas_object_evas_get(snapshot_win);
252 LOGE("Invalid object\n");
254 flush_cb(snapshot_win, info->id, LB_STATUS_ERROR_FAULT, info->data);
256 return ECORE_CALLBACK_CANCEL;
259 ee = ecore_evas_ecore_evas_get(e);
261 LOGE("Invalid object (ee)\n");
263 flush_cb(snapshot_win, info->id, LB_STATUS_ERROR_FAULT, info->data);
265 return ECORE_CALLBACK_CANCEL;
268 canvas = (void*)ecore_evas_buffer_pixels_get(ee);
270 LOGD("Failed to get pixel canvas\n");
272 flush_cb(snapshot_win, info->id, LB_STATUS_ERROR_FAULT, info->data);
274 return ECORE_CALLBACK_CANCEL;
282 ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
284 SECURE_LOGD("Flush size: %dx%d\n", w, h);
285 status = flush_to_file(canvas, info->id, w, h);
287 flush_cb(snapshot_win, info->id, status, info->data);
289 * Do not access info after this.
293 return ECORE_CALLBACK_CANCEL;
298 static void post_render_cb(void *data, Evas *e, void *event_info)
300 Evas_Object *snapshot_win = data;
301 struct snapshot_info *info;
303 info = evas_object_data_get(snapshot_win, "snapshot,info");
305 LOGE("snapshot info is not valid\n");
311 if (info->flush_timer) {
313 * This has not to be happens.
315 LOGE("Flush timer is not cleared\n");
316 ecore_timer_del(info->flush_timer);
317 info->flush_timer = NULL;
320 if (!info->flush_cb) {
321 LOGD("Flush request is not initiated yet\n");
327 * Even if tehre is no timer registered, we should capture the content
328 * from out of this callback.
329 * Or we can met unexpected problems.
330 * To avoid it, use the 0.0001f to get timer callback ASAP, not in this function.
332 LOGD("Fire the flush timer %lf (%d)\n", info->timeout, info->render_cnt);
333 info->flush_timer = ecore_timer_add(info->timeout, snapshot_cb, snapshot_win);
334 if (!info->flush_timer) {
335 void (*flush_cb)(Evas_Object *snapshot_window, const char *id, int status, void *data);
337 LOGE("Unalbe to add timer for getting the snapshot\n");
338 flush_cb = info->flush_cb;
339 info->flush_cb = NULL;
341 flush_cb(snapshot_win, info->id, LB_STATUS_ERROR_FAULT, info->data);
344 * Do not access info after from here.
351 static void pre_render_cb(void *data, Evas *e, void *event_info)
353 Evas_Object *snapshot_win = data;
354 struct snapshot_info *info;
356 info = evas_object_data_get(snapshot_win, "snapshot,info");
358 LOGE("snapshot info is not valid\n");
362 if (info->flush_timer) {
363 ecore_timer_del(info->flush_timer);
364 info->flush_timer = NULL;
365 LOGD("Clear the flush timer\n");
368 LOGD("Pre-render callback\n");
373 static void resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
381 ee = ecore_evas_ecore_evas_get(e);
386 ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
387 evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
388 if (ow == w && oh == h) {
389 SECURE_LOGD("Size is not changed: %dx%d\n", w, h);
394 * Box(parent object) is resized.
395 * Try to resize the canvas too.
397 ecore_evas_resize(ee, w, h);
398 SECURE_LOGD("Canvas is resized to %dx%d\n", w, h);
403 PUBLIC Evas_Object *livebox_snapshot_window_add(const char *id, int size_type)
405 struct snapshot_info *info;
406 Evas_Object *snapshot_win;
411 if (livebox_service_get_size(size_type, &w, &h) != LB_STATUS_SUCCESS) {
412 LOGE("Invalid size\n");
416 info = malloc(sizeof(*info));
418 LOGE("Heap: %s\n", strerror(errno));
422 info->id = strdup(id);
424 LOGE("Heap: %s\n", strerror(errno));
429 info->flush_cb = NULL;
431 info->flush_timer = NULL;
432 info->render_cnt = 0;
434 e = create_virtual_canvas(w, h);
441 snapshot_win = evas_object_rectangle_add(e);
443 destroy_virtual_canvas(e);
449 SECURE_LOGD("Add new window %dx%d\n", w, h);
450 evas_object_event_callback_add(snapshot_win, EVAS_CALLBACK_DEL, del_cb, NULL);
451 evas_object_event_callback_add(snapshot_win, EVAS_CALLBACK_RESIZE, resize_cb, NULL);
452 evas_object_resize(snapshot_win, w, h);
453 evas_object_show(snapshot_win);
455 evas_object_data_set(snapshot_win, "snapshot,info", info);
457 evas_event_callback_add(e, EVAS_CALLBACK_RENDER_POST, post_render_cb, snapshot_win);
458 evas_event_callback_add(e, EVAS_CALLBACK_RENDER_PRE, pre_render_cb, snapshot_win);
465 PUBLIC int livebox_snapshot_window_flush(Evas_Object *snapshot_win, double timeout, void (*flush_cb)(Evas_Object *snapshot_window, const char *id, int status, void *data), void *data)
467 struct snapshot_info *info;
469 if (!flush_cb || timeout < 0.0f) {
470 LOGE("Invalid argument (%p, %lf)\n", flush_cb, timeout);
471 return LB_STATUS_ERROR_INVALID;
474 info = evas_object_data_get(snapshot_win, "snapshot,info");
476 LOGE("Invalid argument\n");
477 return LB_STATUS_ERROR_INVALID;
480 info->timeout = timeout;
482 if (timeout == 0.0f) {
484 * This timer is just used for guarantees same behavious even if it flushes content directly,
485 * The callback should be called from next loop.
486 * or the developer will get confused
488 info->flush_timer = ecore_timer_add(0.0001f, direct_snapshot_cb, snapshot_win);
489 if (!info->flush_timer) {
490 return LB_STATUS_ERROR_FAULT;
492 } else if (info->render_cnt) {
494 * Try to watit pre-render callback.
495 * If there is rendered contents.
497 DbgPrint("Rendered %d times already\n", info->render_cnt);
498 info->flush_timer = ecore_timer_add(info->timeout, snapshot_cb, snapshot_win);
499 if (!info->flush_timer) {
500 return LB_STATUS_ERROR_FAULT;
504 info->flush_cb = flush_cb;
507 return LB_STATUS_SUCCESS;
512 PUBLIC int livebox_snapshot_window_del(Evas_Object *snapshot_win)
515 if (!snapshot_win || !evas_object_data_get(snapshot_win, "snapshot,info")) {
516 return LB_STATUS_ERROR_INVALID;
519 e = evas_object_evas_get(snapshot_win);
520 evas_event_callback_del(e, EVAS_CALLBACK_RENDER_POST, post_render_cb);
521 evas_event_callback_del(e, EVAS_CALLBACK_RENDER_PRE, pre_render_cb);
523 evas_object_del(snapshot_win);
524 return LB_STATUS_SUCCESS;