Init tizen-screenshooter 71/281271/1
authorJunkyeong Kim <jk0430.kim@samsung.com>
Wed, 7 Sep 2022 08:33:30 +0000 (17:33 +0900)
committerTizen Window System <tizen.windowsystem@gmail.com>
Thu, 15 Sep 2022 06:08:48 +0000 (15:08 +0900)
Change-Id: I438cd7e690f93bc9f64894c968bbd8dedcc7c919
Signed-off-by: Junkyeong Kim <jk0430.kim@samsung.com>
include/libds-tizen/screenshooter.h [new file with mode: 0644]
packaging/libds-tizen.spec
src/meson.build
src/screenshooter/meson.build [new file with mode: 0644]
src/screenshooter/screenmirror.c [new file with mode: 0644]
src/screenshooter/screenshooter.c [new file with mode: 0644]
src/screenshooter/screenshooter.h [new file with mode: 0644]
tests/meson.build
tests/tc_screenshooter.cpp [new file with mode: 0644]

diff --git a/include/libds-tizen/screenshooter.h b/include/libds-tizen/screenshooter.h
new file mode 100644 (file)
index 0000000..d16b899
--- /dev/null
@@ -0,0 +1,97 @@
+#ifndef LIBDS_TIZEN_SCREENSHOOTER_H
+#define LIBDS_TIZEN_SCREENSHOOTER_H
+
+#include <stdint.h>
+#include <wayland-server.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ds_tizen_screenshooter;
+struct ds_tizen_screenmirror;
+struct ds_tizen_screenshooter_client;
+
+enum ds_tizen_screenmirror_stretch
+{
+    DS_TIZEN_SCREENMIRROR_STRETCH_KEEP_RATIO,
+    DS_TIZEN_SCREENMIRROR_STRETCH_FULLY,
+};
+
+enum ds_tizen_screenmirror_content
+{
+    DS_TIZEN_SCREENMIRROR_CONTENT_NORMAL,
+    DS_TIZEN_SCREENMIRROR_CONTENT_VIDEO,
+};
+
+struct ds_tizen_screenshooter_shoot_event
+{
+    struct ds_output *output;
+    struct ds_buffer *buffer;
+    struct ds_tizen_screenshooter_client *client;
+    bool auto_rotation;
+};
+
+struct ds_tizen_screenshooter *
+ds_tizen_screenshooter_create(struct wl_display *display);
+
+void
+ds_tizen_screenshooter_add_destroy_listener(struct ds_tizen_screenshooter *shot,
+        struct wl_listener *listener);
+
+void
+ds_tizen_screenshooter_add_get_screenmirror_listener(struct ds_tizen_screenshooter *shot,
+        struct wl_listener *listener);
+
+void
+ds_tizen_screenshooter_add_shoot_listener(struct ds_tizen_screenshooter *shot,
+        struct wl_listener *listener);
+
+void
+ds_tizen_screenshooter_send_shoot_done(struct ds_tizen_screenshooter *shot,
+        struct ds_tizen_screenshooter_client *client);
+
+void
+ds_tizen_screenmirror_add_destroy_listener(struct ds_tizen_screenmirror *mirror,
+        struct wl_listener *listener);
+
+void
+ds_tizen_screenmirror_add_set_stretch_listener(struct ds_tizen_screenmirror *mirror,
+        struct wl_listener *listener);
+
+void
+ds_tizen_screenmirror_add_queue_listener(struct ds_tizen_screenmirror *mirror,
+        struct wl_listener *listener);
+
+void
+ds_tizen_screenmirror_add_dequeue_listener(struct ds_tizen_screenmirror *mirror,
+        struct wl_listener *listener);
+
+void
+ds_tizen_screenmirror_add_start_listener(struct ds_tizen_screenmirror *mirror,
+        struct wl_listener *listener);
+
+void
+ds_tizen_screenmirror_add_stop_listener(struct ds_tizen_screenmirror *mirror,
+        struct wl_listener *listener);
+
+void
+ds_tizen_screenmirror_add_auto_rotation_listener(struct ds_tizen_screenmirror *mirror,
+        struct wl_listener *listener);
+
+void
+ds_tizen_screenmirror_send_content(struct ds_tizen_screenmirror *mirror,
+        enum ds_tizen_screenmirror_content content);
+
+void
+ds_tizen_screenmirror_send_dequeued(struct ds_tizen_screenmirror *mirror,
+        struct ds_buffer *buffer);
+
+void
+ds_tizen_screenmirror_send_stop(struct ds_tizen_screenmirror *mirror);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index e1d4c2592a81b8cd6b81388b1d8654caa383fe60..485abfc8cabcc20f4b90011f5182fdc4cce2ef79 100644 (file)
@@ -327,6 +327,21 @@ Group:   Development/Libraries
 %description policy-devel
 Development package for tizen policy
 
+## libds-tizen-screenshooter
+%package screenshooter
+Summary: Library for tizen screenshooter
+Group:   Development/Libraries
+
+%description screenshooter
+Library for tizen screenshooter
+
+%package screenshooter-devel
+Summary: Development package for tizen screenshooter
+Group:   Development/Libraries
+
+%description screenshooter-devel
+Development package for tizen screenshooter
+
 %prep
 %setup -q
 cp %{SOURCE1001} .
@@ -631,3 +646,18 @@ ninja -C builddir install
 %{_libdir}/pkgconfig/libds-tizen-policy.pc
 %{_libdir}/libds-tizen-policy.so
 %{_bindir}/libds-tizen-policy-tests
+
+%files screenshooter
+%manifest %{name}.manifest
+%defattr(-,root,root,-)
+%license LICENSE
+%{_libdir}/libds-tizen-screenshooter.so.*
+
+%files screenshooter-devel
+%manifest %{name}.manifest
+%defattr(-,root,root,-)
+%license LICENSE
+%{_includedir}/libds-tizen/screenshooter.h
+%{_libdir}/pkgconfig/libds-tizen-screenshooter.pc
+%{_libdir}/libds-tizen-screenshooter.so
+%{_bindir}/libds-tizen-screenshooter-tests
index 227b7a9ed7fb04b7b1a783dae0e24cecccf2c638..9cc81b5b77b979163d94a3e33261a9c20087dc86 100644 (file)
@@ -46,3 +46,4 @@ subdir('input_method')
 subdir('text_input')
 subdir('hwc')
 subdir('policy')
+subdir('screenshooter')
diff --git a/src/screenshooter/meson.build b/src/screenshooter/meson.build
new file mode 100644 (file)
index 0000000..4a5f619
--- /dev/null
@@ -0,0 +1,31 @@
+libds_tizen_screenshooter_files = [
+  'screenshooter.c',
+  'screenmirror.c',
+]
+
+libds_tizen_screenshooter_deps = [
+  deps_libds_tizen,
+  dependency('tizen-extension-server', required: true),
+  dependency('wayland-tbm-server', required: true),
+]
+
+lib_libds_tizen_screenshooter = shared_library('ds-tizen-screenshooter', libds_tizen_screenshooter_files,
+  dependencies: libds_tizen_screenshooter_deps,
+  include_directories: [ common_inc, include_directories('.'), include_directories('..') ],
+  version: meson.project_version(),
+  install: true
+)
+
+deps_libds_tizen_screenshooter = declare_dependency(
+  link_with: lib_libds_tizen_screenshooter,
+  dependencies: libds_tizen_screenshooter_deps,
+  include_directories: [ common_inc, include_directories('.') ],
+)
+
+pkgconfig = import('pkgconfig')
+pkgconfig.generate(lib_libds_tizen_screenshooter,
+  version: meson.project_version(),
+  filebase: 'libds-tizen-screenshooter',
+  name: 'libds-tizen-screenshooter',
+  description: 'tizen screenshooter extension of libds-tizen for tizen platform',
+)
diff --git a/src/screenshooter/screenmirror.c b/src/screenshooter/screenmirror.c
new file mode 100644 (file)
index 0000000..4d15d87
--- /dev/null
@@ -0,0 +1,247 @@
+#include <tizen-extension-server-protocol.h>
+#include "screenshooter.h"
+#include "util.h"
+
+static const struct tizen_screenmirror_interface _screenmirror_interface;
+
+WL_EXPORT void
+ds_tizen_screenmirror_add_destroy_listener(struct ds_tizen_screenmirror *mirror,
+        struct wl_listener *listener)
+{
+    wl_signal_add(&mirror->events.destroy, listener);
+}
+
+WL_EXPORT void
+ds_tizen_screenmirror_add_set_stretch_listener(struct ds_tizen_screenmirror *mirror,
+        struct wl_listener *listener)
+{
+    wl_signal_add(&mirror->events.set_stretch, listener);
+}
+
+WL_EXPORT void
+ds_tizen_screenmirror_add_queue_listener(struct ds_tizen_screenmirror *mirror,
+        struct wl_listener *listener)
+{
+    wl_signal_add(&mirror->events.queue, listener);
+}
+
+WL_EXPORT void
+ds_tizen_screenmirror_add_dequeue_listener(struct ds_tizen_screenmirror *mirror,
+        struct wl_listener *listener)
+{
+    wl_signal_add(&mirror->events.dequeue, listener);
+}
+
+WL_EXPORT void
+ds_tizen_screenmirror_add_start_listener(struct ds_tizen_screenmirror *mirror,
+        struct wl_listener *listener)
+{
+    wl_signal_add(&mirror->events.start, listener);
+}
+
+WL_EXPORT void
+ds_tizen_screenmirror_add_stop_listener(struct ds_tizen_screenmirror *mirror,
+        struct wl_listener *listener)
+{
+    wl_signal_add(&mirror->events.stop, listener);
+}
+
+WL_EXPORT void
+ds_tizen_screenmirror_add_auto_rotation_listener(struct ds_tizen_screenmirror *mirror,
+        struct wl_listener *listener)
+{
+    wl_signal_add(&mirror->events.set_auto_rotation, listener);
+}
+
+WL_EXPORT void
+ds_tizen_screenmirror_send_content(struct ds_tizen_screenmirror *mirror,
+        enum ds_tizen_screenmirror_content content)
+{
+    if (content == DS_TIZEN_SCREENMIRROR_CONTENT_NORMAL)
+      tizen_screenmirror_send_content(mirror->resource, TIZEN_SCREENMIRROR_CONTENT_NORMAL);
+    else if (content == DS_TIZEN_SCREENMIRROR_CONTENT_VIDEO)
+      tizen_screenmirror_send_content(mirror->resource, TIZEN_SCREENMIRROR_CONTENT_VIDEO);
+}
+
+WL_EXPORT void
+ds_tizen_screenmirror_send_dequeued(struct ds_tizen_screenmirror *mirror,
+        struct ds_buffer *buffer)
+{
+    struct wl_resource *wl_buffer;
+
+    wl_buffer = ds_buffer_get_resource(buffer);
+    tizen_screenmirror_send_dequeued(mirror->resource, wl_buffer);
+}
+
+WL_EXPORT void
+ds_tizen_screenmirror_send_stop(struct ds_tizen_screenmirror *mirror)
+{
+    tizen_screenmirror_send_stop(mirror->resource);
+}
+
+void
+ds_tizen_screenmirror_destroy(struct ds_tizen_screenmirror *mirror)
+{
+    if (mirror == NULL)
+        return;
+
+    if (mirror->client_destroy_listener.notify)
+        wl_list_remove(&mirror->client_destroy_listener.link);
+    mirror->client_destroy_listener.notify = NULL;
+
+    if (mirror->resource)
+        wl_resource_set_destructor(mirror->resource, NULL);
+
+    wl_signal_emit(&mirror->events.destroy, NULL);
+    //should be called buffer_dequeued from server(ds_tizen_screenmirror_send_dequeued)
+
+    free(mirror);
+}
+
+static void
+screenmirror_handle_resource_destroy(struct wl_resource *resource)
+{
+    struct ds_tizen_screenmirror *mirror = wl_resource_get_user_data(resource);
+    ds_tizen_screenmirror_destroy(mirror);
+}
+
+static void
+screenmirror_handle_client_destroy(struct wl_listener *listener, void *data)
+{
+    struct ds_tizen_screenmirror *mirror = wl_container_of(listener, mirror, client_destroy_listener);
+    ds_tizen_screenmirror_destroy(mirror);
+}
+
+struct ds_tizen_screenmirror *
+ds_tizen_screenmirror_create(struct ds_tizen_screenshooter_client *client,
+        int version, uint32_t id)
+{
+    struct ds_tizen_screenmirror *mirror;
+
+    mirror = calloc(1, sizeof *mirror);
+    if (!mirror) {
+        ds_err("screenmirror create fail : memory alloc failed");
+        return NULL;
+    }
+    mirror->resource = wl_resource_create(client->client, &tizen_screenmirror_interface,
+                                          version, id);
+    if (mirror->resource == NULL) {
+        ds_err("screenmirror wl_resource create fail : memory alloc failed");
+        free(mirror);
+        return NULL;
+    }
+
+    wl_signal_init(&mirror->events.destroy);
+    wl_signal_init(&mirror->events.set_stretch);
+    wl_signal_init(&mirror->events.queue);
+    wl_signal_init(&mirror->events.dequeue);
+    wl_signal_init(&mirror->events.start);
+    wl_signal_init(&mirror->events.stop);
+    wl_signal_init(&mirror->events.set_auto_rotation);
+
+    wl_resource_set_implementation(mirror->resource, &_screenmirror_interface,
+                                   mirror, screenmirror_handle_resource_destroy);
+
+
+    ds_inf("create : tizen_screenmirror(%p)", mirror);
+
+    mirror->client_destroy_listener.notify = screenmirror_handle_client_destroy;
+    wl_client_add_destroy_listener(client->client, &mirror->client_destroy_listener);
+
+    return mirror;
+}
+
+static void
+_tizen_screenmirror_handle_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+    ds_inf("_tizen_screenmirror_handle_destroy (res:%p)", resource);
+    wl_resource_destroy(resource);
+}
+
+static void
+_tizen_screenmirror_handle_set_stretch(struct wl_client *client, struct wl_resource *resource, uint32_t stretch)
+{
+    struct ds_tizen_screenmirror *mirror = wl_resource_get_user_data(resource);
+    enum ds_tizen_screenmirror_stretch ds_stretch;
+
+    if (stretch > TIZEN_SCREENMIRROR_STRETCH_FULLY) {
+        ds_err("set stretch error : not supported stretch(%d)", stretch);
+        return;
+    }
+    if (stretch == TIZEN_SCREENMIRROR_STRETCH_KEEP_RATIO)
+        ds_stretch = DS_TIZEN_SCREENMIRROR_STRETCH_KEEP_RATIO;
+    else
+        ds_stretch = DS_TIZEN_SCREENMIRROR_STRETCH_FULLY;
+
+    wl_signal_emit(&mirror->events.set_stretch, &ds_stretch);
+}
+
+static void
+_tizen_screenmirror_handle_queue(struct wl_client *client, struct wl_resource *resource, struct wl_resource *wl_buffer)
+{
+    struct ds_tizen_screenmirror *mirror;
+    struct ds_buffer *buffer;
+
+    mirror = wl_resource_get_user_data(resource);
+    buffer = ds_buffer_from_resource(wl_buffer);
+    if (!buffer) {
+        ds_err("ds_buffer_from_resource fail");
+        return;
+    }
+
+    wl_signal_emit(&mirror->events.queue, &buffer);
+}
+
+static void
+_tizen_screenmirror_handle_dequeue(struct wl_client *client, struct wl_resource *resource, struct wl_resource *wl_buffer)
+{
+    struct ds_tizen_screenmirror *mirror;
+    struct ds_buffer *buffer;
+
+    mirror = wl_resource_get_user_data(resource);
+    buffer = ds_buffer_from_resource(wl_buffer);
+    if (!buffer) {
+        ds_err("ds_buffer_from_resource fail");
+        return;
+    }
+
+    wl_signal_emit(&mirror->events.dequeue, &buffer);
+}
+
+static void
+_tizen_screenmirror_handle_start(struct wl_client *client, struct wl_resource *resource)
+{
+    struct ds_tizen_screenmirror *mirror;
+
+    mirror = wl_resource_get_user_data(resource);
+    wl_signal_emit(&mirror->events.start, NULL);
+}
+
+static void
+_tizen_screenmirror_handle_stop(struct wl_client *client, struct wl_resource *resource)
+{
+    struct ds_tizen_screenmirror *mirror;
+
+    mirror = wl_resource_get_user_data(resource);
+    wl_signal_emit(&mirror->events.stop, NULL);
+}
+
+static void
+_tizen_screenmirror_handle_set_auto_rotation(struct wl_client *client, struct wl_resource *resource, uint32_t set)
+{
+    struct ds_tizen_screenmirror *mirror;
+
+    mirror = wl_resource_get_user_data(resource);
+    wl_signal_emit(&mirror->events.set_auto_rotation, &set);
+}
+
+static const struct tizen_screenmirror_interface _screenmirror_interface = {
+     _tizen_screenmirror_handle_destroy,
+     _tizen_screenmirror_handle_set_stretch,
+     _tizen_screenmirror_handle_queue,
+     _tizen_screenmirror_handle_dequeue,
+     _tizen_screenmirror_handle_start,
+     _tizen_screenmirror_handle_stop,
+     _tizen_screenmirror_handle_set_auto_rotation
+};
diff --git a/src/screenshooter/screenshooter.c b/src/screenshooter/screenshooter.c
new file mode 100644 (file)
index 0000000..890bd2f
--- /dev/null
@@ -0,0 +1,215 @@
+#include <tizen-extension-server-protocol.h>
+#include "screenshooter.h"
+#include "util.h"
+
+#define TIZEN_SCREENSHOOTER_VERSION 3
+
+static void screenshooter_handle_display_destroy(struct wl_listener *listener,
+        void *data);
+
+static void screenshooter_bind(struct wl_client *wl_client, void *data,
+        uint32_t version, uint32_t id);
+
+WL_EXPORT struct ds_tizen_screenshooter *
+ds_tizen_screenshooter_create(struct wl_display *display)
+{
+    struct ds_tizen_screenshooter *shot;
+
+    shot = calloc(1, sizeof *shot);
+    if (!shot) {
+        ds_err("screenshooter create fail : memory alloc failed");
+        return NULL;
+    }
+
+    shot->global = wl_global_create(display, &tizen_screenshooter_interface,
+                                    TIZEN_SCREENSHOOTER_VERSION, NULL, screenshooter_bind);
+
+    wl_list_init(&shot->clients);
+    wl_signal_init(&shot->events.destroy);
+    wl_signal_init(&shot->events.shoot);
+
+    shot->destroy.notify = screenshooter_handle_display_destroy;
+    wl_display_add_destroy_listener(display, &shot->destroy);
+
+    ds_inf("create : tizen_screenshooter(%p)", shot);
+
+    return shot;
+}
+
+WL_EXPORT void
+ds_tizen_screenshooter_add_destroy_listener(struct ds_tizen_screenshooter *shot,
+        struct wl_listener *listener)
+{
+    wl_signal_add(&shot->events.destroy, listener);
+}
+
+WL_EXPORT void
+ds_tizen_screenshooter_add_get_screenmirror_listener(struct ds_tizen_screenshooter *shot,
+        struct wl_listener *listener)
+{
+    wl_signal_add(&shot->events.get_screenmirror, listener);
+}
+
+WL_EXPORT void
+ds_tizen_screenshooter_add_shoot_listener(struct ds_tizen_screenshooter *shot,
+        struct wl_listener *listener)
+{
+    wl_signal_add(&shot->events.shoot, listener);
+}
+
+WL_EXPORT void
+ds_tizen_screenshooter_send_shoot_done(struct ds_tizen_screenshooter *shot,
+        struct ds_tizen_screenshooter_client *client)
+{
+    struct ds_tizen_screenshooter_client *temp;
+
+    wl_list_for_each(temp, &shot->clients, link) {
+        if (temp == client) {
+            ds_dbg("screenshooter send shoot done");
+            tizen_screenshooter_send_done(client->res);
+        }
+    }
+}
+
+static void
+screenshooter_handle_display_destroy(struct wl_listener *listener, void *data)
+{
+    struct ds_tizen_screenshooter *shot;
+
+    shot = wl_container_of(listener, shot, destroy);
+
+    ds_inf("global destroy : tizen_screenshooter(%p)", shot);
+
+    wl_signal_emit(&shot->events.destroy, shot);
+    wl_list_remove(&shot->destroy.link);
+    wl_global_destroy(shot->global);
+    free(shot);
+}
+
+static void
+_tizen_screenshooter_handle_get_screenmirror(struct wl_client *client,
+        struct wl_resource *resource, uint32_t id, struct wl_resource *output)
+{
+    struct ds_tizen_screenshooter *shot;
+    struct ds_tizen_screenshooter_client *shot_client;
+    int version = wl_resource_get_version(resource);
+
+    shot_client = wl_resource_get_user_data(resource);
+    shot = shot_client->shot;
+
+    if (shot_client->mirror) {
+        ds_err("screenshooter get_screenmirror error : already created");
+        return;
+    }
+
+    shot_client->mirror = ds_tizen_screenmirror_create(shot_client, version, id);
+    if (shot_client->mirror == NULL)
+        wl_client_post_no_memory(client);
+    else
+        wl_signal_emit(&shot->events.get_screenmirror, shot_client->mirror);
+}
+
+static void
+_tizen_screenshooter_handle_set_oneshot_auto_rotation(struct wl_client *client,
+        struct wl_resource *resource, uint32_t set)
+{
+    struct ds_tizen_screenshooter *shot;
+    struct ds_tizen_screenshooter_client *shot_client;
+
+    shot_client = wl_resource_get_user_data(resource);
+    shot = shot_client->shot;
+    if (set)
+        shot->auto_rotation = true;
+    else
+        shot->auto_rotation = false;
+}
+
+static void
+_tizen_screenshooter_handle_destroy(struct wl_client *client,
+        struct wl_resource *resource)
+{
+    ds_inf("_tizen_screenshooter_handle_destroy (res:%p)", resource);
+    wl_resource_destroy(resource);
+}
+
+static void
+_tizen_screenshooter_handle_shoot(struct wl_client *client,
+        struct wl_resource *resource, struct wl_resource *wl_output,
+        struct wl_resource *wl_buffer)
+{
+    struct ds_tizen_screenshooter *shot;
+    struct ds_tizen_screenshooter_client *shot_client;
+    struct ds_output *output = NULL;
+    struct ds_buffer *buffer = NULL;
+
+    shot_client = wl_resource_get_user_data(resource);
+    shot = shot_client->shot;
+    output = wl_resource_get_user_data(wl_output);
+    buffer = ds_buffer_from_resource(wl_buffer);
+    if (!buffer) {
+        ds_err("ds_buffer_from_resource fail");
+        return;
+    }
+
+    struct ds_tizen_screenshooter_shoot_event event = {
+        .output = output,
+        .buffer = buffer,
+        .client = shot_client,
+        .auto_rotation = shot->auto_rotation,
+    };
+
+    wl_signal_emit(&shot->events.shoot, &event);
+}
+
+static const struct tizen_screenshooter_interface _tizen_screenshooter_interface =
+{
+   _tizen_screenshooter_handle_get_screenmirror,
+   _tizen_screenshooter_handle_set_oneshot_auto_rotation,
+   _tizen_screenshooter_handle_destroy,
+   _tizen_screenshooter_handle_shoot,
+};
+
+static void
+_screenshooter_client_cb_destroy(struct wl_resource *resource)
+{
+    struct ds_tizen_screenshooter_client *shot_client;
+
+    ds_inf("_screenshooter_client_cb_destroy (res:%p)", resource);
+
+    shot_client = wl_resource_get_user_data(resource);
+    if (shot_client) {
+        wl_list_remove(&shot_client->link);
+        free(shot_client);
+    }
+}
+
+static void
+screenshooter_bind(struct wl_client *client, void *data, uint32_t version,
+        uint32_t id)
+{
+    struct ds_tizen_screenshooter *shot = data;
+    struct ds_tizen_screenshooter_client *shot_client;
+
+    shot_client = calloc(1, sizeof *shot_client);
+    if (shot_client == NULL) {
+        wl_client_post_no_memory(client);
+        return;
+    }
+
+    shot_client->shot = shot;
+    shot_client->client = client;
+
+    shot_client->res = wl_resource_create(client, &tizen_screenshooter_interface,
+            MIN(version, TIZEN_SCREENSHOOTER_VERSION), id);
+    if (shot_client->res == NULL) {
+        ds_err("screenshooter bind error : wl_resource_create failed.");
+        wl_client_post_no_memory(client);
+        free(shot_client);
+        return;
+    }
+
+    wl_resource_set_implementation(shot_client->res, &_tizen_screenshooter_interface,
+            shot_client, _screenshooter_client_cb_destroy);
+
+    wl_list_insert(&shot->clients, &shot_client->link);
+}
diff --git a/src/screenshooter/screenshooter.h b/src/screenshooter/screenshooter.h
new file mode 100644 (file)
index 0000000..bdc52bd
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef DS_TIZEN_SCREENSHOOTER_H
+#define DS_TIZEN_SCREENSHOOTER_H
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <wayland-server.h>
+#include <libds/log.h>
+#include <libds/output.h>
+#include <libds/buffer.h>
+#include <libds-tizen/screenshooter.h>
+
+struct ds_tizen_screenshooter
+{
+    struct wl_global *global;
+    struct wl_list clients;
+
+    struct wl_listener destroy;
+
+    struct {
+        struct wl_signal destroy;
+        struct wl_signal get_screenmirror;
+        struct wl_signal shoot;
+    } events;
+
+    bool auto_rotation;
+};
+
+struct ds_tizen_screenshooter_client
+{
+    struct ds_tizen_screenshooter *shot;
+    struct ds_tizen_screenmirror *mirror;
+    struct wl_resource *res;
+    struct wl_client *client;
+    struct wl_list link; // ds_tizen_screenshooter::clients
+};
+
+struct ds_tizen_screenmirror
+{
+    struct wl_resource *resource;
+    struct ds_tizen_screenshooter_client *client;
+    struct wl_listener client_destroy_listener;
+
+    struct {
+        struct wl_signal destroy;
+        struct wl_signal set_stretch;
+        struct wl_signal queue;
+        struct wl_signal dequeue;
+        struct wl_signal start;
+        struct wl_signal stop;
+        struct wl_signal set_auto_rotation;
+    } events;
+};
+
+struct ds_tizen_screenmirror *
+ds_tizen_screenmirror_create(struct ds_tizen_screenshooter_client *client,
+        int version, uint32_t id);
+
+void
+ds_tizen_screenmirror_destroy(struct ds_tizen_screenmirror *mirror);
+
+#endif
index 030c3b0f4968128816910a198a0d1df64a472753..e620eb0bd220e63d1898f555859d2256e2fe6bb9 100644 (file)
@@ -324,3 +324,23 @@ executable('libds-tizen-policy-tests',
   install_dir: libds_tizen_bindir,
   install : true
 )
+
+## screenshooter-compositor tests
+tc_screenshooter_files = [
+  'tc_main.cpp',
+  'tc_screenshooter.cpp',
+]
+
+executable('libds-tizen-screenshooter-tests',
+  [
+    tc_mock_files,
+    tc_screenshooter_files
+  ],
+  dependencies: [
+    deps_test_common,
+    deps_libds_tizen_screenshooter,
+    dependency('tizen-extension-client', required: true),
+  ],
+  install_dir: libds_tizen_bindir,
+  install : true
+)
diff --git a/tests/tc_screenshooter.cpp b/tests/tc_screenshooter.cpp
new file mode 100644 (file)
index 0000000..929ecdf
--- /dev/null
@@ -0,0 +1,747 @@
+#include <libds/output.h>
+#include <libds/backend/wayland.h>
+#include <libds-tizen/screenshooter.h>
+#ifdef TIZEN_SCREENMIRROR_STOP
+#undef TIZEN_SCREENMIRROR_STOP
+#endif
+#include <tizen-extension-client-protocol.h>
+#include <wayland-tbm-client.h>
+#include <tbm_surface.h>
+#include <sys/mman.h>
+#include "tc_main.h"
+#include "mockclient.h"
+#include "mockcompositor.h"
+
+#define TIZEN_SCREENSHOOTER_VERSION 3
+#define SHM_BUF_WIDTH 1920
+#define SHM_BUF_HEIGHT 1080
+#define SHM_BUF_STRIDE 7680 //width * 4
+#define SHM_BUF_FORMAT WL_SHM_FORMAT_XRGB8888
+
+class MockScreenShooterCompositor : public MockCompositor
+{
+public:
+    MockScreenShooterCompositor()
+        : MockCompositor(&MockScreenShooterCompositor::TestSetup, this)
+    {
+        ds_inf("%s : this(%p)", __func__, this);
+
+        bDestroyed = false;
+        bMirror = false;
+        bDestroyMirror = false;
+        bShoot = false;
+        bStart = false;
+        bAutoRotation = false;
+        mBackend = nullptr;
+        mBuffer = nullptr;
+        mOutput = nullptr;;
+        mScreenShooter = nullptr;
+        mScreenMirror = nullptr;
+        new_output = {};
+
+        mDestroyListener = {};
+        mNewScreenMirrorListener = {};
+        mScreenShootListener = {};
+        mScreenMirrorDestroyListener = {};
+        mScreenMirrorSetStretchListener = {};
+        mScreenMirrorQueueListener = {};
+        mScreenMirrorDequeueListener = {};
+        mScreenMirrorStartListener = {};
+        mScreenMirrorStopListener = {};
+        mScreenMirrorAutoRotationListener = {};
+    }
+
+    ~MockScreenShooterCompositor()
+    {
+        ds_inf("%s : this(%p)", __func__, this);
+    }
+
+    static void TestSetup(void *data)
+    {
+        MockScreenShooterCompositor *mockComp =
+            static_cast<MockScreenShooterCompositor *>(data);
+        Compositor *comp = mockComp->compositor;
+
+        ds_inf("%s: mockComp(%p)", __func__, mockComp);
+
+        mockComp->mBackend = ds_wl_backend_create(comp->display, NULL);
+        mockComp->new_output.notify = screenshooter_backend_handle_new_output;
+        ds_backend_add_new_output_listener(mockComp->mBackend, &mockComp->new_output);
+        ds_backend_start(mockComp->mBackend);
+
+        mockComp->mScreenShooter =
+            ds_tizen_screenshooter_create(comp->display);
+
+        // add destroy listener
+        mockComp->mDestroyListener.notify =
+            MockScreenShooterCompositor::DestroyCallback;
+        mockComp->mDestroyListener.parent = mockComp;
+        ds_tizen_screenshooter_add_destroy_listener(mockComp->mScreenShooter,
+            &mockComp->mDestroyListener);
+
+        // add newscreenmirror listener
+        mockComp->mNewScreenMirrorListener.notify =
+            MockScreenShooterCompositor::NewScreenMirrorCallback;
+        mockComp->mNewScreenMirrorListener.parent = mockComp;
+        ds_tizen_screenshooter_add_get_screenmirror_listener(mockComp->mScreenShooter,
+            &mockComp->mNewScreenMirrorListener);
+
+        // add shoot listener
+        mockComp->mScreenShootListener.notify =
+            MockScreenShooterCompositor::ScreenShootCallback;
+        mockComp->mScreenShootListener.parent = mockComp;
+        ds_tizen_screenshooter_add_shoot_listener(mockComp->mScreenShooter,
+            &mockComp->mScreenShootListener);
+    }
+
+    static void screenshooter_backend_handle_new_output(struct wl_listener *listener,
+        void *data)
+    {
+        MockScreenShooterCompositor *mockComp;
+
+        mockComp = wl_container_of(listener, mockComp, new_output);
+        mockComp->mOutput = static_cast<struct ds_output *>(data);
+
+        ds_inf("New ds_output(%p)", mockComp->mOutput);
+
+        ds_output_create_global(mockComp->mOutput);
+        ds_inf("create output global");
+    }
+
+    static void DestroyCallback(struct wl_listener *listener, void *data)
+    {
+        ds_inf("%s", __func__);
+
+        MockScreenShooterCompositor *mockComp =
+            reinterpret_cast<DestroyListener *>(listener)->parent;
+
+        mockComp->bDestroyed = true;
+    }
+
+    static void NewScreenMirrorCallback(struct wl_listener *listener,
+        void *data)
+    {
+        ds_inf("%s", __func__);
+
+        MockScreenShooterCompositor *mockComp =
+            reinterpret_cast<NewScreenMirrorListener *>(listener)->parent;
+        struct ds_tizen_screenmirror *mirror =
+            static_cast<struct ds_tizen_screenmirror *>(data);
+
+        ds_inf("%s: mockComp(%p), mirror(%p)", __func__, mockComp, mirror);
+
+        mockComp->bMirror = true;
+        mockComp->mScreenMirror = mirror;
+
+        // add destroy listener
+        mockComp->mScreenMirrorDestroyListener.notify =
+            MockScreenShooterCompositor::ScreenMirrorDestroyCallback;
+        mockComp->mScreenMirrorDestroyListener.parent = mockComp;
+        ds_tizen_screenmirror_add_destroy_listener(mockComp->mScreenMirror,
+            &mockComp->mScreenMirrorDestroyListener);
+
+        // add set_stretch listener
+        mockComp->mScreenMirrorSetStretchListener.notify =
+            MockScreenShooterCompositor::ScreenMirrorSetStretchCallback;
+        mockComp->mScreenMirrorSetStretchListener.parent = mockComp;
+        ds_tizen_screenmirror_add_set_stretch_listener(mockComp->mScreenMirror,
+            &mockComp->mScreenMirrorSetStretchListener);
+
+        // add queue listener
+        mockComp->mScreenMirrorQueueListener.notify =
+            MockScreenShooterCompositor::ScreenMirrorQueueCallback;
+        mockComp->mScreenMirrorQueueListener.parent = mockComp;
+        ds_tizen_screenmirror_add_queue_listener(mockComp->mScreenMirror,
+            &mockComp->mScreenMirrorQueueListener);
+
+        // add dequeue listener
+        mockComp->mScreenMirrorDequeueListener.notify =
+            MockScreenShooterCompositor::ScreenMirrorDequeueCallback;
+        mockComp->mScreenMirrorDequeueListener.parent = mockComp;
+        ds_tizen_screenmirror_add_dequeue_listener(mockComp->mScreenMirror,
+            &mockComp->mScreenMirrorDequeueListener);
+
+        // add start listener
+        mockComp->mScreenMirrorStartListener.notify =
+            MockScreenShooterCompositor::ScreenMirrorStartCallback;
+        mockComp->mScreenMirrorStartListener.parent = mockComp;
+        ds_tizen_screenmirror_add_start_listener(mockComp->mScreenMirror,
+            &mockComp->mScreenMirrorStartListener);
+
+        // add stop listener
+        mockComp->mScreenMirrorStopListener.notify =
+            MockScreenShooterCompositor::ScreenMirrorStopCallback;
+        mockComp->mScreenMirrorStopListener.parent = mockComp;
+        ds_tizen_screenmirror_add_stop_listener(mockComp->mScreenMirror,
+            &mockComp->mScreenMirrorStopListener);
+
+        // add auto rotation listener
+        mockComp->mScreenMirrorAutoRotationListener.notify =
+            MockScreenShooterCompositor::ScreenMirrorAutoRotationCallback;
+        mockComp->mScreenMirrorAutoRotationListener.parent = mockComp;
+        ds_tizen_screenmirror_add_auto_rotation_listener(mockComp->mScreenMirror,
+            &mockComp->mScreenMirrorAutoRotationListener);
+    }
+
+    static void ScreenShootCallback(struct wl_listener *listener,
+        void *data)
+    {
+        ds_inf("%s", __func__);
+
+        MockScreenShooterCompositor *mockComp =
+            reinterpret_cast<ScreenShootListener *>(listener)->parent;
+        struct ds_tizen_screenshooter_shoot_event *event =
+            static_cast<struct ds_tizen_screenshooter_shoot_event *>(data);
+        
+
+        ds_inf("%s: mockComp(%p), output(%p), buffer(%p), client(%p), auto_rotate:%d",
+            __func__, mockComp, event->output, event->buffer, event->client,
+            event->auto_rotation ? 1 : 0);
+
+        mockComp->bShoot = true;
+        ds_tizen_screenshooter_send_shoot_done(mockComp->mScreenShooter, event->client);
+    }
+
+    static void ScreenMirrorDestroyCallback(struct wl_listener *listener,
+        void *data)
+    {
+        ds_inf("%s", __func__);
+
+        MockScreenShooterCompositor *mockComp =
+            reinterpret_cast<ScreenMirrorDestroyListener *>(listener)->parent;
+        struct ds_tizen_screenmirror *mirror =
+            static_cast<struct ds_tizen_screenmirror *>(data);
+
+        ds_inf("%s: mockComp(%p), info(%p)", __func__, mockComp, mirror);
+
+        if (mockComp->mScreenMirror == mirror) {
+            ds_inf("%s: info is deleted.", __func__);
+            mockComp->bDestroyMirror = true;
+        }
+    }
+
+    static void ScreenMirrorSetStretchCallback(struct wl_listener *listener,
+        void *data)
+    {
+        ds_inf("%s", __func__);
+
+        MockScreenShooterCompositor *mockComp =
+            reinterpret_cast<ScreenMirrorSetStretchListener *>(listener)->parent;
+        enum ds_tizen_screenmirror_stretch *stretch = (enum ds_tizen_screenmirror_stretch *)data;
+
+        ds_inf("%s: mockComp(%p), stretch(%d)", __func__, mockComp, *stretch);
+    }
+
+    static void ScreenMirrorQueueCallback(struct wl_listener *listener,
+        void *data)
+    {
+        ds_inf("%s", __func__);
+
+        MockScreenShooterCompositor *mockComp =
+            reinterpret_cast<ScreenMirrorQueueListener *>(listener)->parent;
+        struct ds_buffer *buffer =
+            static_cast<struct ds_buffer *>(data);
+
+        ds_inf("%s: mockComp(%p), queue(%p)", __func__, mockComp, buffer);
+    }
+
+    static void ScreenMirrorDequeueCallback(struct wl_listener *listener,
+        void *data)
+    {
+        ds_inf("%s", __func__);
+
+        MockScreenShooterCompositor *mockComp =
+            reinterpret_cast<ScreenMirrorDequeueListener *>(listener)->parent;
+        struct ds_buffer *buffer =
+            static_cast<struct ds_buffer *>(data);
+
+        ds_inf("%s: mockComp(%p), dequeue(%p)", __func__, mockComp, buffer);
+
+        ds_tizen_screenmirror_send_dequeued(mockComp->mScreenMirror, buffer);
+    }
+
+    static void ScreenMirrorStartCallback(struct wl_listener *listener,
+        void *data)
+    {
+        ds_inf("%s", __func__);
+
+        MockScreenShooterCompositor *mockComp =
+            reinterpret_cast<ScreenMirrorDequeueListener *>(listener)->parent;
+
+        ds_inf("%s: mockComp(%p), start", __func__, mockComp);
+
+        mockComp->bStart = true;
+    }
+
+    static void ScreenMirrorStopCallback(struct wl_listener *listener,
+        void *data)
+    {
+        ds_inf("%s", __func__);
+
+        MockScreenShooterCompositor *mockComp =
+            reinterpret_cast<ScreenMirrorDequeueListener *>(listener)->parent;
+
+        ds_inf("%s: mockComp(%p), stop", __func__, mockComp);
+
+        mockComp->bStart = false;
+    }
+
+    static void ScreenMirrorAutoRotationCallback(struct wl_listener *listener,
+        void *data)
+    {
+        ds_inf("%s", __func__);
+
+        MockScreenShooterCompositor *mockComp =
+            reinterpret_cast<ScreenMirrorDequeueListener *>(listener)->parent;
+        uint32_t *set = (uint32_t *)data;
+
+        ds_inf("%s: mockComp(%p), autorotation(%d)", __func__, mockComp, *set);
+
+        if (*set)
+            mockComp->bAutoRotation = true;
+        else
+            mockComp->bAutoRotation = false;
+    }
+
+public:
+    bool bDestroyed;
+
+    bool bMirror;
+    bool bDestroyMirror;
+    bool bShoot;
+    bool bStart;
+    bool bAutoRotation;
+
+private:
+    struct ds_backend *mBackend;
+    struct ds_buffer *mBuffer;
+    struct ds_output *mOutput;
+    struct ds_tizen_screenshooter *mScreenShooter;
+       struct ds_tizen_screenmirror *mScreenMirror;
+    struct wl_listener new_output;
+
+    struct DestroyListener : ::wl_listener {
+        MockScreenShooterCompositor *parent;
+    };
+    DestroyListener mDestroyListener;
+
+    struct NewScreenMirrorListener : ::wl_listener {
+        MockScreenShooterCompositor *parent;
+    };
+    NewScreenMirrorListener mNewScreenMirrorListener;
+
+    struct ScreenShootListener : ::wl_listener {
+        MockScreenShooterCompositor *parent;
+    };
+    ScreenShootListener mScreenShootListener;
+
+    struct ScreenMirrorDestroyListener : ::wl_listener {
+        MockScreenShooterCompositor *parent;
+    };
+    ScreenMirrorDestroyListener mScreenMirrorDestroyListener;
+
+    struct ScreenMirrorSetStretchListener : ::wl_listener {
+        MockScreenShooterCompositor *parent;
+    };
+    ScreenMirrorSetStretchListener mScreenMirrorSetStretchListener;
+
+    struct ScreenMirrorQueueListener : ::wl_listener {
+        MockScreenShooterCompositor *parent;
+    };
+    ScreenMirrorQueueListener mScreenMirrorQueueListener;
+    
+    struct ScreenMirrorDequeueListener : ::wl_listener {
+        MockScreenShooterCompositor *parent;
+    };
+    ScreenMirrorDequeueListener mScreenMirrorDequeueListener;
+
+    struct ScreenMirrorStartListener : ::wl_listener {
+        MockScreenShooterCompositor *parent;
+    };
+    ScreenMirrorStartListener mScreenMirrorStartListener;
+
+    struct ScreenMirrorStopListener : ::wl_listener {
+        MockScreenShooterCompositor *parent;
+    };
+    ScreenMirrorStopListener mScreenMirrorStopListener;
+
+    struct ScreenMirrorAutoRotationListener : ::wl_listener {
+        MockScreenShooterCompositor *parent;
+    };
+    ScreenMirrorAutoRotationListener mScreenMirrorAutoRotationListener;
+};
+
+class MockScreenShooterClient : public MockClient
+{
+public:
+    MockScreenShooterClient()
+        : bShootEvent(false),
+          bMirrorStartEvent(false),
+          bMirrorStopEvent(false),
+          output_res(nullptr),
+          shm_res(nullptr),
+          shm_pool(nullptr),
+          screenshooter_res(nullptr),
+          screenmirror_res(nullptr)
+    {}
+    MockScreenShooterClient(const struct wl_registry_listener *listener)
+        : MockClient(listener, this)
+    {
+        ds_inf("%s", __func__);
+
+        bShootEvent = false;
+        bMirrorStartEvent = false;
+        bMirrorStopEvent = false;
+        output_res = nullptr;
+        shm_res = nullptr;
+        shm_pool = nullptr;
+        screenshooter_res = nullptr;
+        screenmirror_res = nullptr;
+    }
+    ~MockScreenShooterClient()
+    {
+        ds_inf("%s", __func__);
+    }
+
+    void SetWlOutput(struct wl_output *global_res)
+    {
+        ds_inf("%s", __func__);
+
+        output_res = global_res;
+    }
+
+    struct wl_output *GetWlOutput()
+    {
+        ds_inf("%s", __func__);
+
+        return output_res;
+    }
+
+    void SetWlShm(struct wl_shm *global_res)
+    {
+        ds_inf("%s", __func__);
+
+        shm_res = global_res;
+    }
+
+    struct wl_shm *GetWlShm()
+    {
+        ds_inf("%s", __func__);
+
+        return shm_res;
+    }
+
+    void SetWlShmPool(struct wl_shm_pool *_shm_pool)
+    {
+        ds_inf("%s", __func__);
+
+        shm_pool = _shm_pool;
+    }
+
+    struct wl_shm_pool *GetWlShmPool()
+    {
+        ds_inf("%s", __func__);
+
+        return shm_pool;
+    }
+
+    void SetTizenScreenShooter(struct tizen_screenshooter *resource)
+    {
+        ds_inf("%s", __func__);
+
+        screenshooter_res = resource;
+    }
+
+    struct tizen_screenshooter *GetTizenScreenShooter()
+    {
+        ds_inf("%s", __func__);
+
+        return screenshooter_res;
+    }
+
+    
+    void SetTizenScreenMirror(struct tizen_screenmirror *resource)
+    {
+        ds_inf("%s", __func__);
+
+        screenmirror_res = resource;
+    }
+
+    struct tizen_screenmirror *GetTizenScreenMirror()
+    {
+        ds_inf("%s", __func__);
+
+        return screenmirror_res;
+    }
+
+public:
+    bool bShootEvent;
+    bool bMirrorStartEvent;
+    bool bMirrorStopEvent;
+
+private:
+    struct wl_output *output_res;
+    struct wl_shm *shm_res;
+    struct wl_shm_pool *shm_pool;
+    struct tizen_screenshooter *screenshooter_res;
+    struct tizen_screenmirror *screenmirror_res;
+};
+
+static void
+client_tizen_screenshooter_cb_format(void *data,
+    struct tizen_screenshooter *screenshooter_res, uint32_t format)
+{
+}
+
+static void
+client_tizen_screenshooter_cb_noti(void *data,
+    struct tizen_screenshooter *screenshooter_res, uint32_t noti)
+{
+    ds_inf("noti : %d");
+}
+
+static void
+client_tizen_screenshooter_cb_done(void *data,
+    struct tizen_screenshooter *screenshooter_res)
+{
+    MockScreenShooterClient *client = static_cast<MockScreenShooterClient *>(data);
+
+    client->bShootEvent = true;
+}
+
+static const struct
+tizen_screenshooter_listener screenshooter_cb_listener = {
+    client_tizen_screenshooter_cb_format,
+    client_tizen_screenshooter_cb_noti,
+    client_tizen_screenshooter_cb_done,
+};
+
+static void
+_client_tizen_screenshooter_destroy_anonymous_file(int fd)
+{
+    if (fd < 0)
+        return;
+
+    close(fd);
+}
+
+static int
+_client_tizen_screenshooter_create_anonymous_file(off_t size)
+{
+    static const char tempname[] = "/shooter-XXXXXX";
+    const char *path;
+    char *name = NULL;
+    int fd = -1;
+    int ret = -1;
+    int path_len = 0;
+
+    path = getenv("XDG_RUNTIME_DIR");
+    if (!path) {
+        errno = ENOENT;
+        return -1;
+    }
+    path_len = strlen(path);
+    if (path_len == 0)
+        return -1;
+
+    name = (char *)malloc(path_len + (int)sizeof(tempname));
+    if (name == NULL)
+        return -1;
+
+    strncpy(name, path, path_len);
+    strncat(name, tempname, (int)sizeof(tempname));
+
+    fd = mkstemp(name);
+    if (fd >= 0)
+        unlink(name);
+
+    free(name);
+
+    if (fd < 0)
+        return -1;
+
+    ret = ftruncate(fd, size);
+    if (ret < 0) {
+        close(fd);
+        return -1;
+    }
+
+    return fd;
+}
+
+static struct wl_shm_pool *
+_client_tizen_screenshooter_create_shm_pool(struct wl_shm *shm, int size)
+{
+    struct wl_shm_pool *shm_pool = NULL;
+    void *data = NULL;
+    int fd = -1;
+
+    fd = _client_tizen_screenshooter_create_anonymous_file(size);
+    if (fd < 0)
+        goto fail;
+
+    data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+    if (data == NULL)
+        goto fail;
+
+    memset(data, 0xff, size);
+    munmap(data, size);
+
+    shm_pool = wl_shm_create_pool(shm, fd, size);
+    if (shm_pool == NULL)
+        goto fail;
+
+    _client_tizen_screenshooter_destroy_anonymous_file(fd);
+
+    return shm_pool;
+
+fail:
+    if (fd > 0)
+        _client_tizen_screenshooter_destroy_anonymous_file(fd);
+
+    return NULL;
+}
+
+void
+_client_tizen_screenshooter_destroy_shm_pool(struct wl_shm_pool *shm_pool)
+{
+    if (!shm_pool)
+        return;
+
+    wl_shm_pool_destroy(shm_pool);
+}
+
+static void
+client_registry_cb_global(void *data, struct wl_registry *registry,
+    uint32_t name, const char *interface, uint32_t version)
+{
+    ds_inf("%s", __func__);
+
+    MockScreenShooterClient *client = static_cast<MockScreenShooterClient *>(data);
+    struct tizen_screenshooter *screenshooter_res;
+    struct wl_shm *shm_res;
+    struct wl_shm_pool *shm_pool;
+    struct wl_output *output_res;
+
+    if (!strcmp(interface, "wl_shm")) {
+        shm_res = (struct wl_shm *)wl_registry_bind(registry,
+            name, &wl_shm_interface, 1);
+        if (shm_res == nullptr) {
+            ds_err("wl_registry_bind() failed. wl_shm resource.");
+            return;
+        }
+        shm_pool = _client_tizen_screenshooter_create_shm_pool(shm_res, SHM_BUF_WIDTH * 4 * SHM_BUF_HEIGHT);
+        if (shm_pool == NULL) {
+            ds_err("wl_registry_bind() failed. wl_shm_pool create fail.");
+            wl_shm_destroy(shm_res);
+            return;
+        }
+        client->SetWlShm(shm_res);
+        client->SetWlShmPool(shm_pool);
+    }  else if (!strcmp(interface, "wl_output")) {
+        output_res = (struct wl_output *)wl_registry_bind(registry,
+            name, &wl_output_interface, 1);
+        if (output_res == nullptr) {
+            ds_err("wl_registry_bind() failed. wl_output resource.");
+            return;
+        }
+        client->SetWlOutput(output_res);
+    } else if (!strcmp(interface, "tizen_screenshooter")) {
+        screenshooter_res = (struct tizen_screenshooter *)wl_registry_bind(registry,
+            name, &tizen_screenshooter_interface, TIZEN_SCREENSHOOTER_VERSION);
+        if (screenshooter_res == nullptr) {
+            ds_err("wl_registry_bind() failed. tizen_screenshooter resource.");
+            return;
+        }
+        client->SetTizenScreenShooter(screenshooter_res);
+
+        tizen_screenshooter_add_listener(screenshooter_res,
+            &screenshooter_cb_listener, client);
+    }
+}
+
+static void
+client_registry_cb_global_remove(void *data, struct wl_registry *registry,
+    uint32_t name)
+{
+    ds_inf("%s", __func__);
+
+    MockScreenShooterClient *client = static_cast<MockScreenShooterClient *>(data);
+    struct wl_shm *shm_res = client->GetWlShm();
+    struct wl_shm_pool *shm_pool = client->GetWlShmPool();
+    struct tizen_screenshooter *screenshooter_res = client->GetTizenScreenShooter();
+    struct tizen_screenmirror *screenmirror_res = client->GetTizenScreenMirror();
+
+    if (screenmirror_res)
+        tizen_screenmirror_destroy(screenmirror_res);
+    tizen_screenshooter_destroy(screenshooter_res);
+    _client_tizen_screenshooter_destroy_shm_pool(shm_pool);
+    wl_shm_destroy(shm_res);
+}
+
+static const struct wl_registry_listener registry_listener = {
+    .global = client_registry_cb_global,
+    .global_remove = client_registry_cb_global_remove
+};
+
+class ScreenShooterTest : public ::testing::Test
+{
+public:
+    void SetUp(void) override;
+    void TearDown(void) override;
+
+    MockScreenShooterCompositor *comp;
+    MockScreenShooterClient *client;
+    struct wl_output *output_res;
+    struct wl_shm *shm_res;
+    struct wl_shm_pool *shm_pool;
+    struct wl_buffer *buffer_res1;
+    struct wl_buffer *buffer_res2;
+    struct wl_buffer *buffer_res3;
+    struct tizen_screenshooter *screenshooter_res;
+    struct tizen_screenmirror *screenmirror_res;
+};
+
+void
+ScreenShooterTest::SetUp(void)
+{
+    //ds_log_init(DS_DBG, NULL);
+
+    ds_inf("%s", __func__);
+
+    comp = new MockScreenShooterCompositor();
+    client = new MockScreenShooterClient(&registry_listener);
+    output_res = client->GetWlOutput();
+    shm_res = client->GetWlShm();
+    shm_pool = client->GetWlShmPool();
+    screenshooter_res = client->GetTizenScreenShooter();
+
+    client->RoundTrip();
+}
+
+void
+ScreenShooterTest::TearDown(void)
+{
+    ds_inf("%s", __func__);
+
+    client->RoundTrip();
+
+    delete client;
+    delete comp;
+}
+
+TEST_F(ScreenShooterTest, Create_P)
+{
+    EXPECT_TRUE(true);
+}
+
+TEST_F(ScreenShooterTest, Req_TizenScreenShooterShot)
+{
+    buffer_res1 = wl_shm_pool_create_buffer(shm_pool, 0,
+        SHM_BUF_WIDTH, SHM_BUF_HEIGHT, SHM_BUF_STRIDE, SHM_BUF_FORMAT);
+    tizen_screenshooter_shoot(screenshooter_res, output_res, buffer_res1);
+    client->RoundTrip();
+    EXPECT_TRUE(comp->bShoot);
+    comp->Process();
+    EXPECT_TRUE(client->bShootEvent);
+}