--- /dev/null
+#define E_COMP_WL
+#include "e.h"
+#include <wayland-server.h>
+#include <Ecore_Wayland.h>
+#include "e_tizen_screenshooter_server_protocol.h"
+#include "e_tizen_screenshooter_server.h"
+
+#define SW_DUMP_FPS 30
+#define SW_DUMP_TIMEOUT ((double)1/SW_DUMP_FPS)
+
+typedef struct _Mirror
+{
+ struct wl_resource *resource;
+ struct wl_resource *shooter;
+ struct wl_resource *output;
+
+ Eina_Bool started;
+
+ Ecore_Timer *sw_timer;
+
+ Eina_List *buffer_queue;
+} Mirror;
+
+typedef struct _Mirror_Buffer
+{
+ struct wl_resource *resource;
+
+ Mirror *mirror;
+
+ struct wl_shm_buffer *shm_buffer;
+ int32_t stride;
+ int32_t w, h;
+ uint32_t format;
+ void *data;
+ Eina_Bool in_use;
+
+ struct wl_signal destroy_signal;
+ struct wl_listener destroy_listener;
+} Mirror_Buffer;
+
+static void _e_tizen_screenmirror_buffer_dequeue(Mirror_Buffer *buffer);
+
+static void
+_e_tizen_screenmirror_center_rect (int src_w, int src_h, int dst_w, int dst_h, Eina_Rectangle *fit)
+{
+ float rw, rh;
+
+ if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0 || !fit)
+ return;
+
+ rw = (float)src_w / dst_w;
+ rh = (float)src_h / dst_h;
+
+ if (rw > rh)
+ {
+ fit->w = dst_w;
+ fit->h = src_h * rw;
+ fit->x = 0;
+ fit->y = (dst_h - fit->h) / 2;
+ }
+ else if (rw < rh)
+ {
+ fit->w = src_w * rw;
+ fit->h = dst_h;
+ fit->x = (dst_w - fit->w) / 2;
+ fit->y = 0;
+ }
+ else
+ {
+ fit->w = dst_w;
+ fit->h = dst_h;
+ fit->x = 0;
+ fit->y = 0;
+ }
+}
+
+static void
+_e_tizen_screenmirror_sw_dump(Mirror_Buffer *buffer)
+{
+ Mirror *mirror = buffer->mirror;
+ E_Comp_Wl_Output *output = wl_resource_get_user_data(mirror->output);
+ Eina_Rectangle center = {0,};
+
+ _e_tizen_screenmirror_center_rect(output->w, output->h, buffer->w, buffer->h, ¢er);
+
+ printf ("@@@ %s(%d) %dx%d %dx%d d(%d,%d,%d,%d)\n", __FUNCTION__, __LINE__,
+ output->w, output->h, buffer->w, buffer->h,
+ center.x, center.y, center.w, center.h);
+
+ wl_shm_buffer_begin_access(buffer->shm_buffer);
+ evas_render_copy(e_comp->evas, buffer->data, buffer->stride,
+ buffer->w, buffer->h, buffer->format,
+ output->x, output->y, output->w, output->h,
+ center.x, center.y, center.w, center.h);
+ wl_shm_buffer_end_access(buffer->shm_buffer);
+}
+
+static Eina_Bool
+_e_tizen_screenmirror_sw_do_dump(void *data)
+{
+ Mirror *mirror = data;
+ Mirror_Buffer *buffer;
+
+ buffer = eina_list_nth(mirror->buffer_queue, 0);
+ if (buffer)
+ {
+ _e_tizen_screenmirror_sw_dump(buffer);
+ _e_tizen_screenmirror_buffer_dequeue(buffer);
+ }
+
+ if (!eina_list_nth_list(mirror->buffer_queue, 0))
+ {
+ mirror->sw_timer = NULL;
+ return ECORE_CALLBACK_CANCEL;
+ }
+ else
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_e_tizen_screenmirror_buffer_queue(Mirror_Buffer *buffer)
+{
+ Mirror *mirror = buffer->mirror;
+
+ if (mirror->started && !mirror->sw_timer)
+ mirror->sw_timer = ecore_timer_add(SW_DUMP_TIMEOUT,
+ _e_tizen_screenmirror_sw_do_dump, mirror);
+
+ mirror->buffer_queue = eina_list_append(mirror->buffer_queue, buffer);
+
+ return EINA_TRUE;
+}
+
+static void
+_e_tizen_screenmirror_buffer_dequeue(Mirror_Buffer *buffer)
+{
+ Mirror *mirror = buffer->mirror;
+
+ if (!eina_list_data_find_list(mirror->buffer_queue, buffer))
+ return;
+
+ mirror->buffer_queue = eina_list_remove(mirror->buffer_queue, buffer);
+ tizen_screenmirror_send_dequeued(mirror->resource, buffer->resource);
+
+ if (!eina_list_nth_list(mirror->buffer_queue, 0))
+ if (mirror->sw_timer)
+ {
+ ecore_timer_del(mirror->sw_timer);
+ mirror->sw_timer = NULL;
+ }
+}
+
+static void
+_e_tizen_screenmirror_buffer_cb_destroy(struct wl_listener *listener, void *data)
+{
+ Mirror_Buffer *buffer = container_of(listener, Mirror_Buffer, destroy_listener);
+
+ /* first, inform to other */
+ wl_signal_emit(&buffer->destroy_signal, buffer);
+
+ if (buffer->in_use) printf("%s: buffer in use\n", __FUNCTION__);
+
+ /* then, dequeue and send dequeue event */
+ _e_tizen_screenmirror_buffer_dequeue(buffer);
+
+ free(buffer);
+}
+
+static Mirror_Buffer*
+_e_tizen_screenmirror_buffer_get(Mirror *mirror, struct wl_resource *resource)
+{
+ Mirror_Buffer *buffer = NULL;
+ struct wl_listener *listener;
+
+ listener = wl_resource_get_destroy_listener(resource, _e_tizen_screenmirror_buffer_cb_destroy);
+ if (listener)
+ return container_of(listener, Mirror_Buffer, destroy_listener);
+
+ if (!(buffer = E_NEW(Mirror_Buffer, 1))) return NULL;
+
+ buffer->mirror = mirror;
+ buffer->resource = resource;
+
+ buffer->shm_buffer = wl_shm_buffer_get(resource);
+ buffer->stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
+ buffer->w = wl_shm_buffer_get_width(buffer->shm_buffer);
+ buffer->h = wl_shm_buffer_get_height(buffer->shm_buffer);
+ buffer->format = wl_shm_buffer_get_format(buffer->shm_buffer);
+ buffer->data = wl_shm_buffer_get_data(buffer->shm_buffer);
+
+ wl_signal_init(&buffer->destroy_signal);
+
+ buffer->destroy_listener.notify = _e_tizen_screenmirror_buffer_cb_destroy;
+ wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
+
+ return buffer;
+}
+
+static Mirror*
+_e_tizen_screenmirror_create(void)
+{
+ Mirror *mirror;
+
+ if (!(mirror = E_NEW(Mirror, 1))) return NULL;
+
+ return mirror;
+}
+
+static void
+_e_tizen_screenmirror_destroy(Mirror *mirror)
+{
+ Mirror_Buffer *buffer;
+
+ if (mirror->sw_timer) ecore_timer_del(mirror->sw_timer);
+
+ EINA_LIST_FREE(mirror->buffer_queue, buffer)
+ if (buffer) _e_tizen_screenmirror_buffer_dequeue(buffer);
+
+ free(mirror);
+}
+
+static void
+destroy_screenmirror(struct wl_resource *resource)
+{
+ Mirror *mirror = wl_resource_get_user_data(resource);
+
+ _e_tizen_screenmirror_destroy(mirror);
+}
+
+static void
+_e_tizen_screenmirror_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+_e_tizen_screenmirror_cb_queue(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *buffer_resource)
+{
+ Mirror *mirror = wl_resource_get_user_data(resource);
+ Mirror_Buffer *buffer;
+
+ if (!wl_shm_buffer_get(buffer_resource))
+ {
+ wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "tizen_screenshooter failed: wrong buffer resource");
+ return;
+ }
+
+ buffer = _e_tizen_screenmirror_buffer_get(mirror, buffer_resource);
+ if (!buffer)
+ {
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+
+ _e_tizen_screenmirror_buffer_queue(buffer);
+}
+
+static void
+_e_tizen_screenmirror_cb_dequeue(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *buffer_resource)
+{
+ Mirror *mirror = wl_resource_get_user_data(resource);
+ Mirror_Buffer *buffer;
+
+ if (!wl_shm_buffer_get(buffer_resource))
+ {
+ wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "tizen_screenshooter failed: wrong buffer resource");
+ return;
+ }
+
+ buffer = _e_tizen_screenmirror_buffer_get(mirror, buffer_resource);
+ if (!eina_list_data_find_list(mirror->buffer_queue, buffer))
+ return;
+
+ _e_tizen_screenmirror_buffer_dequeue(buffer);
+}
+
+static void
+_e_tizen_screenmirror_cb_start(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
+{
+ Mirror *mirror = wl_resource_get_user_data(resource);
+
+ if (mirror->started) return;
+
+ mirror->sw_timer = ecore_timer_add(SW_DUMP_TIMEOUT,
+ _e_tizen_screenmirror_sw_do_dump, mirror);
+ if (mirror->sw_timer)
+ tizen_screenmirror_send_content(resource, TIZEN_SCREENMIRROR_CONTENT_NORMAL);
+
+ mirror->started = EINA_TRUE;
+}
+
+static void
+_e_tizen_screenmirror_cb_stop(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
+{
+ Mirror *mirror = wl_resource_get_user_data(resource);
+
+ if (!mirror->started) return;
+
+ mirror->started = EINA_FALSE;
+
+ tizen_screenmirror_send_stop(resource);
+}
+
+static const struct tizen_screenmirror_interface _e_tizen_screenmirror_interface = {
+ _e_tizen_screenmirror_cb_destroy,
+ _e_tizen_screenmirror_cb_queue,
+ _e_tizen_screenmirror_cb_dequeue,
+ _e_tizen_screenmirror_cb_start,
+ _e_tizen_screenmirror_cb_stop
+};
+
+static void
+_e_tizen_screenshooter_get_screenmirror(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *output)
+{
+ int version = wl_resource_get_version(resource);
+ struct wl_resource *res;
+ Mirror *mirror;
+
+ mirror = _e_tizen_screenmirror_create();
+ if (!mirror)
+ {
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+
+ res = wl_resource_create(client, &tizen_screenmirror_interface, version, id);
+ if (res == NULL)
+ {
+ _e_tizen_screenmirror_destroy(mirror);
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ mirror->resource = res;
+ mirror->shooter = resource;
+ mirror->output = output;
+
+ wl_resource_set_implementation(res, &_e_tizen_screenmirror_interface,
+ mirror, destroy_screenmirror);
+}
+
+static const struct tizen_screenshooter_interface _e_tizen_screenshooter_interface =
+{
+ _e_tizen_screenshooter_get_screenmirror
+};
+
+static void
+_e_tizen_screenshooter_cb_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+ E_Comp_Data *cdata;
+ struct wl_resource *res;
+
+ if (!(cdata = data))
+ {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ if (!(res = wl_resource_create(client, &tizen_screenshooter_interface, MIN(version, 1), id)))
+ {
+ ERR("Could not create tizen_screenshooter resource: %m");
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(res, &_e_tizen_screenshooter_interface, cdata, NULL);
+}
+
+void*
+e_tizen_screenshooter_server_init(E_Module *m)
+{
+ E_Comp_Data *cdata;
+
+ if (!e_comp) return EINA_FALSE;
+ if (!(cdata = e_comp->wl_comp_data)) return EINA_FALSE;
+ if (!cdata->wl.disp) return EINA_FALSE;
+
+ /* try to add tizen_screenshooter to wayland globals */
+ if (!wl_global_create(cdata->wl.disp, &tizen_screenshooter_interface, 1,
+ cdata, _e_tizen_screenshooter_cb_bind))
+ {
+ ERR("Could not add tizen_screenshooter to wayland globals: %m");
+ return EINA_FALSE;
+ }
+
+ return m;
+}
+
+int
+e_tizen_screenshooter_server_shutdown(E_Module *m)
+{
+ return 1;
+}
--- /dev/null
+#ifndef TIZEN_SCREENSHOOTER_SERVER_PROTOCOL_H
+#define TIZEN_SCREENSHOOTER_SERVER_PROTOCOL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-server.h"
+
+struct wl_client;
+struct wl_resource;
+
+struct tizen_screenshooter;
+struct tizen_screenmirror;
+
+extern const struct wl_interface tizen_screenshooter_interface;
+extern const struct wl_interface tizen_screenmirror_interface;
+
+/**
+ * tizen_screenshooter - interface for tizen-screenshooter
+ * @get_screenmirror: create a screenmirror object
+ *
+ * Clients can get a screenmirror object from this interface.
+ */
+struct tizen_screenshooter_interface {
+ /**
+ * get_screenmirror - create a screenmirror object
+ * @id: new screenmirror object
+ * @output: output object for screenmirror
+ *
+ * Before using screenmirror, a client should get a screenmirror
+ * object from display server.
+ */
+ void (*get_screenmirror)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *output);
+};
+
+
+#ifndef TIZEN_SCREENMIRROR_CONTENT_ENUM
+#define TIZEN_SCREENMIRROR_CONTENT_ENUM
+enum tizen_screenmirror_content {
+ TIZEN_SCREENMIRROR_CONTENT_NORMAL = 0,
+ TIZEN_SCREENMIRROR_CONTENT_VIDEO = 1,
+};
+#endif /* TIZEN_SCREENMIRROR_CONTENT_ENUM */
+
+/**
+ * tizen_screenmirror - interface for screenmirror
+ * @destroy: (none)
+ * @queue: queue a buffer
+ * @dequeue: dequeue a buffer
+ * @start: (none)
+ * @stop: (none)
+ *
+ * A client can use this interface to get stream images of screen. Before
+ * starting, queue all buffers. Then, start a screenmirror. After starting,
+ * a dequeued event will occur when drawing a captured image on a buffer is
+ * finished. You might need to queue the dequeued buffer again to get a new
+ * image from display server.
+ */
+struct tizen_screenmirror_interface {
+ /**
+ * destroy - (none)
+ */
+ void (*destroy)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * queue - queue a buffer
+ * @buffer: buffer object for screenmirror
+ *
+ *
+ */
+ void (*queue)(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *buffer);
+ /**
+ * dequeue - dequeue a buffer
+ * @buffer: buffer object for screenmirror
+ *
+ * A user can dequeue a buffer from display server when he wants
+ * to take back it from server.
+ */
+ void (*dequeue)(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *buffer);
+ /**
+ * start - (none)
+ */
+ void (*start)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * stop - (none)
+ */
+ void (*stop)(struct wl_client *client,
+ struct wl_resource *resource);
+};
+
+#define TIZEN_SCREENMIRROR_DEQUEUED 0
+#define TIZEN_SCREENMIRROR_CONTENT 1
+#define TIZEN_SCREENMIRROR_STOP 2
+
+#define TIZEN_SCREENMIRROR_DEQUEUED_SINCE_VERSION 1
+#define TIZEN_SCREENMIRROR_CONTENT_SINCE_VERSION 1
+#define TIZEN_SCREENMIRROR_STOP_SINCE_VERSION 1
+
+static inline void
+tizen_screenmirror_send_dequeued(struct wl_resource *resource_, struct wl_resource *buffer)
+{
+ wl_resource_post_event(resource_, TIZEN_SCREENMIRROR_DEQUEUED, buffer);
+}
+
+static inline void
+tizen_screenmirror_send_content(struct wl_resource *resource_, uint32_t content)
+{
+ wl_resource_post_event(resource_, TIZEN_SCREENMIRROR_CONTENT, content);
+}
+
+static inline void
+tizen_screenmirror_send_stop(struct wl_resource *resource_)
+{
+ wl_resource_post_event(resource_, TIZEN_SCREENMIRROR_STOP);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif