#include <stdlib.h> /* malloc */
#include <string.h> /* strdup */
#include <libgen.h>
+#include <unistd.h> /* access */
#include <dlog.h>
#include <livebox-service.h>
#include "dlist.h"
#include "util.h"
-#define EAPI __attribute__((visibility("default")))
+#define PUBLIC __attribute__((visibility("default")))
#define FILE_SCHEMA "file://"
int accelerated;
};
-EAPI const int DONE = 0x00;
-EAPI const int OUTPUT_UPDATED = 0x02;
-EAPI const int USE_NET = 0x04;
+PUBLIC const int DONE = 0x00;
+PUBLIC const int OUTPUT_UPDATED = 0x02;
+PUBLIC const int USE_NET = 0x04;
-EAPI const int NEED_TO_SCHEDULE = 0x01;
-EAPI const int NEED_TO_CREATE = 0x01;
-EAPI const int NEED_TO_DESTROY = 0x01;
-EAPI const int NEED_TO_UPDATE = 0x01;
+PUBLIC const int NEED_TO_SCHEDULE = 0x01;
+PUBLIC const int NEED_TO_CREATE = 0x01;
+PUBLIC const int NEED_TO_DESTROY = 0x01;
+PUBLIC const int NEED_TO_UPDATE = 0x01;
-EAPI const int LB_SYS_EVENT_FONT_CHANGED = 0x01;
-EAPI const int LB_SYS_EVENT_LANG_CHANGED = 0x02;
-EAPI const int LB_SYS_EVENT_TIME_CHANGED = 0x04;
-EAPI const int LB_SYS_EVENT_REGION_CHANGED = 0x08;
-EAPI const int LB_SYS_EVENT_PAUSED = 0x0100;
-EAPI const int LB_SYS_EVENT_RESUMED = 0x0200;
+PUBLIC const int LB_SYS_EVENT_FONT_CHANGED = 0x01;
+PUBLIC const int LB_SYS_EVENT_LANG_CHANGED = 0x02;
+PUBLIC const int LB_SYS_EVENT_TIME_CHANGED = 0x04;
+PUBLIC const int LB_SYS_EVENT_REGION_CHANGED = 0x08;
+PUBLIC const int LB_SYS_EVENT_PAUSED = 0x0100;
+PUBLIC const int LB_SYS_EVENT_RESUMED = 0x0200;
-EAPI struct livebox_desc *livebox_desc_open(const char *filename, int for_pd)
+PUBLIC struct livebox_desc *livebox_desc_open(const char *filename, int for_pd)
{
struct livebox_desc *handle;
char *new_fname;
}
}
- DbgPrint("Open a new file: %s\n", new_fname);
- handle->fp = fopen(new_fname, "w+t");
+ DbgPrint("Open a file %s with merge mode %s\n",
+ new_fname,
+ access(new_fname, F_OK) == 0 ? "enabled" : "disabled");
+
+ handle->fp = fopen(new_fname, "at");
free(new_fname);
if (!handle->fp) {
ErrPrint("Failed to open a file: %s\n", strerror(errno));
return handle;
}
-EAPI int livebox_desc_close(struct livebox_desc *handle)
+PUBLIC int livebox_desc_close(struct livebox_desc *handle)
{
struct dlist *l;
struct dlist *n;
return LB_STATUS_SUCCESS;
}
-EAPI int livebox_desc_set_category(struct livebox_desc *handle, const char *id, const char *category)
+PUBLIC int livebox_desc_set_category(struct livebox_desc *handle, const char *id, const char *category)
{
struct block *block;
return block->idx;
}
-EAPI int livebox_desc_set_size(struct livebox_desc *handle, const char *id, int w, int h)
+PUBLIC int livebox_desc_set_size(struct livebox_desc *handle, const char *id, int w, int h)
{
struct block *block;
char buffer[BUFSIZ];
return block->idx;
}
-EAPI char *livebox_util_nl2br(const char *str)
+PUBLIC char *livebox_util_nl2br(const char *str)
{
int len;
register int i;
return ret;
}
-EAPI int livebox_desc_set_id(struct livebox_desc *handle, int idx, const char *id)
+PUBLIC int livebox_desc_set_id(struct livebox_desc *handle, int idx, const char *id)
{
struct dlist *l;
struct block *block;
/*!
* \return idx
*/
-EAPI int livebox_desc_add_block(struct livebox_desc *handle, const char *id, const char *type, const char *part, const char *data, const char *option)
+PUBLIC int livebox_desc_add_block(struct livebox_desc *handle, const char *id, const char *type, const char *part, const char *data, const char *option)
{
struct block *block;
return block->idx;
}
-EAPI int livebox_desc_del_block(struct livebox_desc *handle, int idx)
+PUBLIC int livebox_desc_del_block(struct livebox_desc *handle, int idx)
{
struct dlist *l;
struct block *block;
return LB_STATUS_ERROR_NOT_EXIST;
}
-EAPI struct livebox_buffer *livebox_acquire_buffer(const char *filename, int is_pd, int width, int height, int (*handler)(struct livebox_buffer *, enum buffer_event, double, double, double, void *), void *data)
+PUBLIC struct livebox_buffer *livebox_acquire_buffer(const char *filename, int is_pd, int width, int height, int (*handler)(struct livebox_buffer *, enum buffer_event, double, double, double, void *), void *data)
{
struct livebox_buffer_data *user_data;
const char *pkgname;
return handle;
}
-EAPI int livebox_request_update(const char *filename)
+PUBLIC int livebox_request_update(const char *filename)
{
int uri_len;
char *uri;
return ret;
}
-EAPI unsigned long livebox_pixmap_id(struct livebox_buffer *handle)
+PUBLIC unsigned long livebox_pixmap_id(struct livebox_buffer *handle)
{
return provider_buffer_pixmap_id(handle);
}
-EAPI int livebox_release_buffer(struct livebox_buffer *handle)
+PUBLIC int livebox_release_buffer(struct livebox_buffer *handle)
{
struct livebox_buffer_data *user_data;
return provider_buffer_release(handle);
}
-EAPI void *livebox_ref_buffer(struct livebox_buffer *handle)
+PUBLIC void *livebox_ref_buffer(struct livebox_buffer *handle)
{
struct livebox_buffer_data *user_data;
void *data;
return data;
}
-EAPI int livebox_unref_buffer(void *buffer)
+PUBLIC int livebox_unref_buffer(void *buffer)
{
if (!buffer)
return LB_STATUS_ERROR_INVALID;
return provider_buffer_unref(buffer);
}
-EAPI int livebox_sync_buffer(struct livebox_buffer *handle)
+PUBLIC int livebox_sync_buffer(struct livebox_buffer *handle)
{
struct livebox_buffer_data *user_data;
const char *pkgname;
return LB_STATUS_SUCCESS;
}
-EAPI int livebox_support_hw_buffer(struct livebox_buffer *handle)
+PUBLIC int livebox_support_hw_buffer(struct livebox_buffer *handle)
{
if (!handle)
return LB_STATUS_ERROR_INVALID;
return provider_buffer_pixmap_is_support_hw(handle);
}
-EAPI int livebox_create_hw_buffer(struct livebox_buffer *handle)
+PUBLIC int livebox_create_hw_buffer(struct livebox_buffer *handle)
{
struct livebox_buffer_data *user_data;
int ret;
return ret;
}
-EAPI int livebox_destroy_hw_buffer(struct livebox_buffer *handle)
+PUBLIC int livebox_destroy_hw_buffer(struct livebox_buffer *handle)
{
struct livebox_buffer_data *user_data;
if (!handle)
return provider_buffer_pixmap_destroy_hw(handle);
}
-EAPI void *livebox_buffer_hw_buffer(struct livebox_buffer *handle)
+PUBLIC void *livebox_buffer_hw_buffer(struct livebox_buffer *handle)
{
struct livebox_buffer_data *user_data;
return provider_buffer_pixmap_hw_addr(handle);
}
-EAPI int livebox_buffer_pre_render(struct livebox_buffer *handle)
+PUBLIC int livebox_buffer_pre_render(struct livebox_buffer *handle)
{
struct livebox_buffer_data *user_data;
return provider_buffer_pre_render(handle);
}
-EAPI int livebox_buffer_post_render(struct livebox_buffer *handle)
+PUBLIC int livebox_buffer_post_render(struct livebox_buffer *handle)
{
int ret;
const char *pkgname;
--- /dev/null
+#include <Ecore_Evas.h>
+#include <Evas.h>
+#include <Ecore.h>
+#include <unistd.h>
+
+#include <dlog.h>
+#include <livebox-service.h>
+#include <livebox-errno.h>
+
+#include "livebox.h"
+#include "debug.h"
+
+#define QUALITY_N_COMPRESS "quality=100 compress=1"
+#define PUBLIC __attribute__((visibility("default")))
+
+struct snapshot_info {
+ char *id;
+ void (*flush_cb)(Evas_Object *snapshot_window, const char *id, int status, void *data);
+ void *data;
+
+ Ecore_Timer *flush_timer;
+
+ int render_cnt;
+ double timeout;
+};
+
+static void post_render_cb(void *data, Evas *e, void *event_info);
+static void pre_render_cb(void *data, Evas *e, void *event_info);
+
+
+
+static inline Evas *create_virtual_canvas(int w, int h)
+{
+ Ecore_Evas *internal_ee;
+ Evas *internal_e;
+
+ // Create virtual canvas
+ internal_ee = ecore_evas_buffer_new(w, h);
+ if (!internal_ee) {
+ LOGD("Failed to create a new canvas buffer\n");
+ return NULL;
+ }
+
+ ecore_evas_alpha_set(internal_ee, EINA_TRUE);
+ ecore_evas_manual_render_set(internal_ee, EINA_FALSE);
+
+ // Get the "Evas" object from a virtual canvas
+ internal_e = ecore_evas_get(internal_ee);
+ if (!internal_e) {
+ ecore_evas_free(internal_ee);
+ LOGD("Faield to get Evas object\n");
+ return NULL;
+ }
+
+ return internal_e;
+}
+
+
+
+static inline int flush_data_to_file(Evas *e, char *data, const char *filename, int w, int h)
+{
+ Evas_Object *output;
+
+ output = evas_object_image_add(e);
+ if (!output) {
+ LOGD("Failed to create an image object\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ evas_object_image_data_set(output, NULL);
+ evas_object_image_colorspace_set(output, EVAS_COLORSPACE_ARGB8888);
+ evas_object_image_alpha_set(output, EINA_TRUE);
+ evas_object_image_size_set(output, w, h);
+ evas_object_image_smooth_scale_set(output, EINA_TRUE);
+ evas_object_image_data_set(output, data);
+ evas_object_image_fill_set(output, 0, 0, w, h);
+ evas_object_image_data_update_add(output, 0, 0, w, h);
+
+ if (evas_object_image_save(output, filename, NULL, QUALITY_N_COMPRESS) == EINA_FALSE) {
+ evas_object_del(output);
+ LOGD("Faield to save a captured image (%s)\n", filename);
+ return LB_STATUS_ERROR_IO;
+ }
+
+ evas_object_del(output);
+
+ if (access(filename, F_OK) != 0) {
+ LOGD("File %s is not found\n", filename);
+ return LB_STATUS_ERROR_IO;
+ }
+
+ LOGD("Flush data to a file (%s)\n", filename);
+ return LB_STATUS_SUCCESS;
+}
+
+
+
+static inline int destroy_virtual_canvas(Evas *e)
+{
+ Ecore_Evas *ee;
+
+ ee = ecore_evas_ecore_evas_get(e);
+ if (!ee) {
+ LOGD("Failed to ecore evas object\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ ecore_evas_free(ee);
+ return LB_STATUS_SUCCESS;
+}
+
+
+
+static inline int flush_to_file(void *canvas, const char *filename, int w, int h)
+{
+ int status;
+ Evas *shot_e;
+ Ecore_Evas *shot_ee;
+
+ shot_e = create_virtual_canvas(w, h);
+ if (!shot_e) {
+ LOGE("Unable to create a new virtual window\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ shot_ee = ecore_evas_ecore_evas_get(shot_e);
+ if (!shot_ee) {
+ LOGE("Unable to get Ecore_Evas\n");
+ destroy_virtual_canvas(shot_e);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ ecore_evas_manual_render_set(shot_ee, EINA_TRUE);
+
+ status = flush_data_to_file(shot_e, canvas, filename, w, h);
+ destroy_virtual_canvas(shot_e);
+
+ return status;
+}
+
+
+
+static void del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+ struct snapshot_info *info;
+
+ info = evas_object_data_del(obj, "snapshot,info");
+ if (!info)
+ return;
+
+ LOGD("Delete object (%s)\n", info->id);
+
+ if (info->flush_cb) {
+ info->flush_cb(obj, info->id, LB_STATUS_ERROR_CANCEL, info->data);
+ LOGD("Flush is canceled\n");
+ }
+
+ /*!
+ * \note
+ * Render callback will be deleted.
+ */
+ destroy_virtual_canvas(e);
+ free(info->id);
+ free(info);
+}
+
+
+
+static Eina_Bool direct_snapshot_cb(void *data)
+{
+ Evas *e;
+ Ecore_Evas *ee;
+ void *canvas;
+ int status;
+ int w;
+ int h;
+ void (*flush_cb)(Evas_Object *snapshot_window, const char *id, int status, void *data);
+ Evas_Object *snapshot_win = data;
+ struct snapshot_info *info;
+
+ info = evas_object_data_get(snapshot_win, "snapshot,info");
+ if (!info) {
+ LOGE("Unable to get snapshot info\n");
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ info->flush_timer = NULL;
+ flush_cb = info->flush_cb;
+ info->flush_cb = NULL; /* To prevent call this from the delete callback */
+
+ e = evas_object_evas_get(snapshot_win);
+ if (!e) {
+ LOGE("Invalid object, failed to get Evas\n");
+ if (flush_cb)
+ flush_cb(snapshot_win, info->id, LB_STATUS_ERROR_FAULT, info->data);
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ ee = ecore_evas_ecore_evas_get(e);
+ if (!ee) {
+ LOGE("Unable to get Ecore_Evas object\n");
+ if (flush_cb)
+ flush_cb(snapshot_win, info->id, LB_STATUS_ERROR_FAULT, info->data);
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
+ ecore_evas_manual_render_set(ee, EINA_TRUE);
+
+ canvas = ecore_evas_buffer_pixels_get(ee);
+ if (!canvas) {
+ LOGE("Failed to get canvas\n");
+ if (flush_cb)
+ flush_cb(snapshot_win, info->id, LB_STATUS_ERROR_FAULT, info->data);
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ status = flush_to_file(canvas, info->id, w, h);
+ if (flush_cb)
+ flush_cb(snapshot_win, info->id, status, info->data);
+ return ECORE_CALLBACK_CANCEL;
+}
+
+
+
+static Eina_Bool snapshot_cb(void *data)
+{
+ Evas_Object *snapshot_win = data;
+ struct snapshot_info *info;
+ Evas *e;
+ Ecore_Evas *ee;
+ void *canvas;
+ void (*flush_cb)(Evas_Object *snapshot_window, const char *id, int status, void *data);
+
+ info = evas_object_data_get(snapshot_win, "snapshot,info");
+ if (!info) {
+ LOGE("Invalid object\n");
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ info->flush_timer = NULL;
+ flush_cb = info->flush_cb;
+ info->flush_cb = NULL; /* To prevent call this from the delete callback */
+
+ e = evas_object_evas_get(snapshot_win);
+ if (!e) {
+ LOGE("Invalid object\n");
+ if (flush_cb)
+ flush_cb(snapshot_win, info->id, LB_STATUS_ERROR_FAULT, info->data);
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ ee = ecore_evas_ecore_evas_get(e);
+ if (!ee) {
+ LOGE("Invalid object (ee)\n");
+ if (flush_cb)
+ flush_cb(snapshot_win, info->id, LB_STATUS_ERROR_FAULT, info->data);
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ canvas = (void*)ecore_evas_buffer_pixels_get(ee);
+ if (!canvas) {
+ LOGD("Failed to get pixel canvas\n");
+ if (flush_cb)
+ flush_cb(snapshot_win, info->id, LB_STATUS_ERROR_FAULT, info->data);
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ if (flush_cb) {
+ int w;
+ int h;
+ int status;
+
+ ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
+
+ LOGD("Flush size: %dx%d\n", w, h);
+ status = flush_to_file(canvas, info->id, w, h);
+
+ flush_cb(snapshot_win, info->id, status, info->data);
+ /*!
+ * Do not access info after this.
+ */
+ }
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+
+
+static void post_render_cb(void *data, Evas *e, void *event_info)
+{
+ Evas_Object *snapshot_win = data;
+ struct snapshot_info *info;
+
+ info = evas_object_data_get(snapshot_win, "snapshot,info");
+ if (!info) {
+ LOGE("snapshot info is not valid\n");
+ return;
+ }
+
+ info->render_cnt++;
+
+ if (info->flush_timer) {
+ /*!
+ * This has not to be happens.
+ */
+ LOGE("Flush timer is not cleared\n");
+ ecore_timer_del(info->flush_timer);
+ info->flush_timer = NULL;
+ }
+
+ if (!info->flush_cb) {
+ LOGD("Flush request is not initiated yet\n");
+ return;
+ }
+
+ /*!
+ * \NOTE
+ * Even if tehre is no timer registered, we should capture the content
+ * from out of this callback.
+ * Or we can met unexpected problems.
+ * To avoid it, use the 0.0001f to get timer callback ASAP, not in this function.
+ */
+ LOGD("Fire the flush timer %lf (%d)\n", info->timeout, info->render_cnt);
+ info->flush_timer = ecore_timer_add(info->timeout, snapshot_cb, snapshot_win);
+ if (!info->flush_timer) {
+ void (*flush_cb)(Evas_Object *snapshot_window, const char *id, int status, void *data);
+
+ LOGE("Unalbe to add timer for getting the snapshot\n");
+ flush_cb = info->flush_cb;
+ info->flush_cb = NULL;
+
+ flush_cb(snapshot_win, info->id, LB_STATUS_ERROR_FAULT, info->data);
+ /*!
+ * \note
+ * Do not access info after from here.
+ */
+ }
+}
+
+
+
+static void pre_render_cb(void *data, Evas *e, void *event_info)
+{
+ Evas_Object *snapshot_win = data;
+ struct snapshot_info *info;
+
+ info = evas_object_data_get(snapshot_win, "snapshot,info");
+ if (!info) {
+ LOGE("snapshot info is not valid\n");
+ return;
+ }
+
+ if (info->flush_timer) {
+ ecore_timer_del(info->flush_timer);
+ info->flush_timer = NULL;
+ LOGD("Clear the flush timer\n");
+ }
+
+ LOGD("Pre-render callback\n");
+}
+
+
+
+static void resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+ Ecore_Evas *ee;
+ int w;
+ int h;
+ int ow;
+ int oh;
+
+ ee = ecore_evas_ecore_evas_get(e);
+ if (!ee)
+ return;
+
+ ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
+ evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
+ if (ow == w && oh == h) {
+ LOGD("Size is not changed: %dx%d\n", w, h);
+ return;
+ }
+
+ /*!
+ * Box(parent object) is resized.
+ * Try to resize the canvas too.
+ */
+ ecore_evas_resize(ee, w, h);
+ LOGD("Canvas is resized to %dx%d\n", w, h);
+}
+
+
+
+PUBLIC Evas_Object *livebox_snapshot_window_add(const char *id, int size_type)
+{
+ struct snapshot_info *info;
+ Evas_Object *snapshot_win;
+ Evas *e;
+ int w;
+ int h;
+
+ if (livebox_service_get_size(size_type, &w, &h) != LB_STATUS_SUCCESS) {
+ LOGE("Invalid size\n");
+ return NULL;
+ }
+
+ info = malloc(sizeof(*info));
+ if (!info) {
+ LOGE("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ info->id = strdup(id);
+ if (!info->id) {
+ LOGE("Heap: %s\n", strerror(errno));
+ free(info);
+ return NULL;
+ }
+
+ info->flush_cb = NULL;
+ info->data = NULL;
+ info->flush_timer = NULL;
+ info->render_cnt = 0;
+
+ e = create_virtual_canvas(w, h);
+ if (!e) {
+ free(info->id);
+ free(info);
+ return NULL;
+ }
+
+ snapshot_win = evas_object_rectangle_add(e);
+ if (!snapshot_win) {
+ destroy_virtual_canvas(e);
+ free(info->id);
+ free(info);
+ return NULL;
+ }
+
+ LOGD("Add new window %dx%d\n", w, h);
+ evas_object_event_callback_add(snapshot_win, EVAS_CALLBACK_DEL, del_cb, NULL);
+ evas_object_event_callback_add(snapshot_win, EVAS_CALLBACK_RESIZE, resize_cb, NULL);
+ evas_object_resize(snapshot_win, w, h);
+ evas_object_show(snapshot_win);
+
+ evas_object_data_set(snapshot_win, "snapshot,info", info);
+
+ evas_event_callback_add(e, EVAS_CALLBACK_RENDER_POST, post_render_cb, snapshot_win);
+ evas_event_callback_add(e, EVAS_CALLBACK_RENDER_PRE, pre_render_cb, snapshot_win);
+
+ return snapshot_win;
+}
+
+
+
+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)
+{
+ struct snapshot_info *info;
+
+ if (!flush_cb || timeout < 0.0f) {
+ LOGE("Invalid argument (%p, %lf)\n", flush_cb, timeout);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ info = evas_object_data_get(snapshot_win, "snapshot,info");
+ if (!info) {
+ LOGE("Invalid argument\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ info->timeout = timeout;
+
+ if (timeout == 0.0f) {
+ /*!
+ * This timer is just used for guarantees same behavious even if it flushes content directly,
+ * The callback should be called from next loop.
+ * or the developer will get confused
+ */
+ info->flush_timer = ecore_timer_add(0.0001f, direct_snapshot_cb, snapshot_win);
+ if (!info->flush_timer)
+ return LB_STATUS_ERROR_FAULT;
+ } else if (info->render_cnt) {
+ /*!
+ * Try to watit pre-render callback.
+ * If there is rendered contents.
+ */
+ DbgPrint("Rendered %d times already\n", info->render_cnt);
+ info->flush_timer = ecore_timer_add(info->timeout, snapshot_cb, snapshot_win);
+ if (!info->flush_timer)
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ info->flush_cb = flush_cb;
+ info->data = data;
+
+ return LB_STATUS_SUCCESS;
+}
+
+
+
+PUBLIC int livebox_snapshot_window_del(Evas_Object *snapshot_win)
+{
+ Evas *e;
+ if (!snapshot_win || !evas_object_data_get(snapshot_win, "snapshot,info"))
+ return LB_STATUS_ERROR_INVALID;
+
+ e = evas_object_evas_get(snapshot_win);
+ evas_event_callback_del(e, EVAS_CALLBACK_RENDER_POST, post_render_cb);
+ evas_event_callback_del(e, EVAS_CALLBACK_RENDER_PRE, pre_render_cb);
+
+ evas_object_del(snapshot_win);
+ return LB_STATUS_SUCCESS;
+}
+
+
+
+// End of a file
--- /dev/null
+#include <Ecore_Evas.h>
+#include <Evas.h>
+
+#include <dlog.h>
+#include <livebox-errno.h>
+
+#include "livebox.h"
+
+#define IS_PD 1
+
+#define PUBLIC __attribute__((visibility("default")))
+/*!
+ * \brief
+ * Abstracted Data Type of Virtual Window
+ */
+struct info {
+ char *id; /*!< Identification */
+ int width; /*!< Width */
+ int height; /*!< Height */
+ struct livebox_buffer *handle; /*!< Livebox buffer handle */
+ Evas_Object *window; /*!< Parent evas object - WARN: Incompatible with the elm_win object */
+ int is_hw; /*!< 1 if a buffer is created on the H/W accelerated place or 0 */
+};
+
+/*!
+ * \note
+ * Every user event (mouse) on the buffer will be passed via this event callback
+ */
+static int event_handler_cb(struct livebox_buffer *handler, enum buffer_event evt, double timestamp, double x, double y, void *data)
+{
+ struct info *info = data;
+ Evas *e;
+ int ix;
+ int iy;
+
+ if (!info->handle) {
+ /* Just ignore this event */
+ return 0;
+ }
+
+ /*!
+ * \note
+ * Calculate the event occurred X & Y on the buffer
+ */
+ ix = info->width * x;
+ iy = info->height * y;
+
+ e = evas_object_evas_get(info->window);
+
+ /*!
+ * \note
+ * Feed up events
+ */
+ switch (evt) {
+ case BUFFER_EVENT_ENTER:
+ evas_event_feed_mouse_in(e, timestamp, NULL);
+ break;
+ case BUFFER_EVENT_LEAVE:
+ evas_event_feed_mouse_out(e, timestamp, NULL);
+ break;
+ case BUFFER_EVENT_DOWN:
+ evas_event_feed_mouse_in(e, timestamp, NULL);
+ evas_event_feed_mouse_move(e, ix, iy, timestamp + 0.01f, NULL); /* + 0.1f just for fake event */
+ evas_event_feed_mouse_down(e, 1, EVAS_BUTTON_NONE, timestamp + 0.02f, NULL); /* + 0.2f just for fake event */
+ break;
+ case BUFFER_EVENT_MOVE:
+ evas_event_feed_mouse_move(e, ix, iy, timestamp, NULL);
+ break;
+ case BUFFER_EVENT_UP:
+ evas_event_feed_mouse_up(e, 1, EVAS_BUTTON_NONE, timestamp, NULL);
+ evas_event_feed_mouse_out(e, timestamp + 0.01f, NULL); /* + 0.1f just for fake event */
+ break;
+ default:
+ LOGD("Unhandled buffer event (%d)\n", evt);
+ break;
+ }
+
+ return 0;
+}
+
+static void *alloc_fb(void *data, int size)
+{
+ struct info *info = data;
+ void *buffer;
+
+ /*!
+ * Acquire a buffer for canvas.
+ */
+ info->handle = livebox_acquire_buffer(info->id, IS_PD,
+ info->width, info->height,
+ event_handler_cb, info);
+
+ /*!
+ * If it supports the H/W accelerated buffer,
+ * Use it.
+ */
+ if (livebox_support_hw_buffer(info->handle)) {
+ if (livebox_create_hw_buffer(info->handle) == 0) {
+ buffer = livebox_buffer_hw_buffer(info->handle);
+ if (buffer) {
+ LOGD("HW Accelerated buffer is created\n");
+ info->is_hw = 1;
+ return buffer;
+ }
+ }
+
+ LOGE("Failed to allocate HW Accelerated buffer\n");
+ }
+
+ /*!
+ * Or use the buffer of a S/W backend.
+ */
+ buffer = livebox_ref_buffer(info->handle);
+ LOGD("SW buffer is created\n");
+ info->is_hw = 0;
+ return buffer;
+}
+
+static void free_fb(void *data, void *ptr)
+{
+ struct info *info = data;
+
+ if (!info->handle)
+ return;
+
+ if (info->is_hw) {
+ if (livebox_destroy_hw_buffer(info->handle) == 0) {
+ LOGD("HW Accelerated buffer is destroyed\n");
+ goto out;
+ }
+ }
+
+ livebox_unref_buffer(ptr);
+ LOGD("SW buffer is destroyed\n");
+out:
+ livebox_release_buffer(info->handle);
+ info->handle = NULL;
+}
+
+static void resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+ struct info *info = data;
+ Ecore_Evas *ee;
+
+ ee = ecore_evas_ecore_evas_get(e);
+ if (!ee)
+ return;
+
+ evas_object_geometry_get(obj, NULL, NULL, &info->width, &info->height);
+ LOGD("Resize to %dx%d\n", info->width, info->height);
+ /*!
+ * Box(parent object) is resized.
+ * Try to resize the canvas too.
+ */
+ ecore_evas_resize(ee, info->width, info->height);
+}
+
+/*!
+ * If a canvas is destroyed,
+ * Free all buffer of canvas.
+ */
+static void del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+ Ecore_Evas *ee;
+ struct info *info = data;
+
+ ee = ecore_evas_ecore_evas_get(e);
+ if (!ee)
+ return;
+
+ LOGD("Try to release the ECORE_EVAS\n");
+ ecore_evas_free(ee);
+ free(info->id);
+ free(info);
+ LOGD("ECORE_EVAS is released\n");
+}
+
+static void pre_render_cb(void *data, Evas *e, void *event_info)
+{
+ struct info *info = data;
+
+ if (!info->handle)
+ return;
+
+ if (info->is_hw)
+ livebox_buffer_pre_render(info->handle);
+}
+
+static void post_render_cb(void *data, Evas *e, void *event_info)
+{
+ struct info *info = data;
+
+ if (!info->handle)
+ return;
+
+ if (info->is_hw)
+ livebox_buffer_post_render(info->handle);
+ else
+ livebox_sync_buffer(info->handle);
+}
+
+PUBLIC Evas_Object *livebox_virtual_window_add(const char *id, int width, int height)
+{
+ Ecore_Evas *ee;
+ Evas *e;
+ struct info *info;
+
+ info = calloc(1, sizeof(*info));
+ if (!info) {
+ return NULL;
+ }
+
+ info->id = strdup(id);
+ if (!info->id) {
+ free(info);
+ return NULL;
+ }
+
+ info->width = width;
+ info->height = height;
+
+ ee = ecore_evas_buffer_allocfunc_new(width, height, alloc_fb, free_fb, info);
+ if (!ee) {
+ free(info->id);
+ free(info);
+ return NULL;
+ }
+
+ pre_render_cb(info, NULL, NULL);
+ ecore_evas_alpha_set(ee, EINA_TRUE);
+ post_render_cb(info, NULL, NULL);
+
+ ecore_evas_manual_render_set(ee, EINA_FALSE);
+ ecore_evas_resize(ee, width, height);
+
+ e = ecore_evas_get(ee);
+ if (!e) {
+ ecore_evas_free(ee);
+ return NULL;
+ }
+
+ evas_event_callback_add(e, EVAS_CALLBACK_RENDER_POST, post_render_cb, info);
+ evas_event_callback_add(e, EVAS_CALLBACK_RENDER_PRE, pre_render_cb, info);
+
+ info->window = evas_object_rectangle_add(e);
+ if (!info->window) {
+ ecore_evas_free(ee);
+ return NULL;
+ }
+
+ evas_object_resize(info->window, width, height);
+ evas_object_color_set(info->window, 0, 0, 0, 0);
+ evas_object_event_callback_add(info->window, EVAS_CALLBACK_DEL, del_cb, info);
+ evas_object_event_callback_add(info->window, EVAS_CALLBACK_RESIZE, resize_cb, info);
+
+ return info->window;
+}
+
+PUBLIC int livebox_virtual_window_del(Evas_Object *virtual_win)
+{
+ evas_object_del(virtual_win);
+ return LB_STATUS_SUCCESS;
+}
+
+/* End of a file */