launch: implement tizen_launch_effect, tizen_launch_splash 98/279198/1 accepted/tizen/unified/20220808.135412 submit/tizen/20220805.072229
authorduna.oh <duna.oh@samsung.com>
Thu, 28 Jul 2022 05:54:09 +0000 (14:54 +0900)
committerJunseok Kim <juns.kim@samsung.com>
Wed, 3 Aug 2022 09:05:17 +0000 (18:05 +0900)
Change-Id: I58c4c5e3b56237d370f56d0b7b96a5e8b058bfcc

examples/meson.build
examples/tinyds-tdm-libinput.c
include/libds-tizen/launch/effect.h [new file with mode: 0644]
packaging/libds-tizen.spec
src/launch/effect.c [new file with mode: 0644]
src/launch/meson.build
tests/meson.build
tests/tc_launch_effect.cpp [new file with mode: 0644]

index d9fca10..4d90eb7 100644 (file)
@@ -48,6 +48,7 @@ executable('tinyds-tdm-libinput',
     common_deps,
     deps_libds_tizen_backend_tdm,
     deps_libds_tizen_input_devicemgr,
+    deps_libds_tizen_launch,
     dependency('pixman-1', required: true),
     dependency('threads', required: true),
   ],
index 10c02bb..faf666b 100644 (file)
@@ -26,6 +26,7 @@
 #include <libds-tizen/input_devicemgr.h>
 #include <xkbcommon/xkbcommon.h>
 #include <libds/interfaces/keyboard.h>
+#include <libds-tizen/launch/effect.h>
 
 #define USE_TDM_BUFFER_QUEUE
 
@@ -79,6 +80,8 @@ struct tinyds_server
     uint32_t seat_caps;
     double output_x, output_y;
     struct ds_tizen_input_devicemgr *devicemgr;
+    struct ds_tizen_effect *effect;
+    struct ds_tizen_splash *splash;
 
     struct tinyds_output *output;
     struct wl_event_source *stdin_source;
@@ -90,6 +93,11 @@ struct tinyds_server
     struct wl_listener new_xdg_surface;
     struct wl_listener devicemgr_destroy;
     struct wl_listener pointer_warp;
+    struct wl_listener effect_destroy;
+    struct wl_listener effect_type_set;
+    struct wl_listener effect_type_unset;
+    struct wl_listener new_splash;
+    struct wl_listener splash_owner;
 
     struct wl_list keyboards;
     struct wl_list pointers;
@@ -110,6 +118,9 @@ struct tinyds_view
 
     int x, y;
     bool mapped;
+
+    pid_t pid;
+    int effect_type;
 };
 
 struct tinyds_pointer
@@ -219,6 +230,25 @@ main(void)
 }
 
 static void
+view_populate_pid(struct tinyds_view *view)
+{
+    pid_t pid;
+    struct wl_client *client = NULL;
+    struct ds_surface *surface = ds_xdg_surface_get_surface(view->xdg_surface);
+
+    if (surface)
+        client = wl_resource_get_client(ds_surface_get_wl_resource(surface));
+    wl_client_get_credentials(client, &pid, NULL, NULL);
+
+    ds_inf("view pid(%u)", pid);
+    view->pid = pid;
+
+    view->effect_type = ds_tizen_effect_get_effect_type(view->server->effect, pid);
+    ds_tizen_effect_unset_effect_type(view->server->effect, pid);
+    ds_inf("view effect_type(%d)", view->effect_type);
+}
+
+static void
 view_handle_xdg_surface_map(struct wl_listener *listener,
         void *data TINYDS_UNUSED)
 {
@@ -228,6 +258,8 @@ view_handle_xdg_surface_map(struct wl_listener *listener,
     view = wl_container_of(listener, view, xdg_surface_map);
     view->mapped = true;
 
+    view_populate_pid(view);
+
     wl_list_for_each(kbd, &view->server->keyboards, link) {
         keyboard = ds_input_device_get_keyboard(kbd->dev);
         if (keyboard != NULL) {
@@ -320,6 +352,9 @@ server_new_xdg_surface(struct wl_listener *listener, void *data)
     view->x = rand() % 1000;
     view->y = rand() % 500;
 
+    view->pid = 0;
+    view->effect_type = -1;
+
     ds_inf("view at (%d, %d)", view->x, view->y);
 }
 
@@ -508,6 +543,113 @@ devicemgr_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED)
     server->devicemgr = NULL;
 }
 
+static void
+launch_effect_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED)
+{
+    struct tinyds_server *server =
+        wl_container_of(listener, server, effect_destroy);
+
+    wl_list_remove(&server->effect_destroy.link);
+    wl_list_remove(&server->effect_type_set.link);
+    wl_list_remove(&server->effect_type_unset.link);
+    wl_list_remove(&server->new_splash.link);
+
+    server->effect = NULL;
+}
+
+static void
+launch_effect_handle_type_set(struct wl_listener *listener, void *data)
+{
+    struct tinyds_server *server;
+    struct ds_tizen_effect_event_type_set *event = data;
+    struct tinyds_view *view = NULL;
+    bool existing = false;
+
+    server = wl_container_of(listener, server, effect_type_set);
+
+    ds_inf("Launch effect. type_set: pid(%u) type:%s", event->pid, (event->effect_type == 1) ? "depth-in" : "launch");
+
+    wl_list_for_each(view, &server->views, link) {
+        if (view->pid == event->pid) {
+            view->effect_type = event->effect_type;
+            ds_inf("Launch effect. existing pid");
+            existing = true;
+        }
+    }
+    if (existing) {
+        ds_tizen_effect_unset_effect_type(server->effect, event->pid);
+    } else {
+        ds_tizen_effect_set_effect_type(server->effect, event->pid, event->effect_type);
+    }
+}
+
+static void
+launch_effect_handle_type_unset(struct wl_listener *listener, void *data)
+{
+    struct tinyds_server *server;
+    struct ds_tizen_effect_event_type_unset *event = data;
+    struct tinyds_view *view = NULL;
+
+    server = wl_container_of(listener, server, effect_type_unset);
+
+    ds_inf("Launch effect. type_unset: pid(%u)", event->pid);
+
+    wl_list_for_each(view, &server->views, link) {
+        if (view->pid == event->pid) {
+            view->effect_type = -1;
+            ds_inf("Launch effect. pid found");
+        }
+    }
+    ds_tizen_effect_unset_effect_type(server->effect, event->pid);
+}
+
+static void
+launch_splash_handle_owner(struct wl_listener *listener, void *data)
+{
+    struct tinyds_server *server;
+    struct ds_tizen_splash_event_owner *event = data;
+    struct tinyds_view *view = NULL;
+
+    server = wl_container_of(listener, server, splash_owner);
+
+    ds_inf("Splash owner. pid(%u)", event->pid);
+
+    wl_list_for_each(view, &server->views, link) {
+        if (view->pid == event->pid) {
+            if (event->pid == ds_tizen_splash_get_pid(server->splash))
+                ;//
+            else {
+                ds_tizen_splash_set_pid(server->splash, event->pid);
+            }
+        }
+    }
+}
+
+static void
+launch_effect_handle_new_splash(struct wl_listener *listener, void *data)
+{
+    struct tinyds_server *server;
+    struct ds_tizen_effect_event_new_splash *event = data;
+    struct tinyds_view *view = NULL;
+
+    server = wl_container_of(listener, server, new_splash);
+
+    ds_inf("Launch new splash. splash(%p)", event->splash);
+    if (!event->splash) return;
+
+    server->splash = event->splash;
+
+    // new view for "Launchscreen"
+    view = calloc(1, sizeof *view);
+    assert(view);
+    wl_list_insert(server->views.prev, &view->link);
+    view->pid = ds_tizen_splash_get_pid(event->splash);
+
+    server->splash_owner.notify = launch_splash_handle_owner;
+    ds_tizen_splash_add_owner_listener(server->splash,
+            &server->splash_owner);
+}
+
 static bool
 init_server(struct tinyds_server *server, struct wl_display *display)
 {
@@ -574,6 +716,27 @@ init_server(struct tinyds_server *server, struct wl_display *display)
     ds_tizen_input_devicemgr_add_pointer_warp_listener(server->devicemgr,
             &server->pointer_warp);
 
+    server->effect = ds_tizen_effect_create(display);
+    if (!server->effect) {
+        goto err;
+    }
+
+    server->effect_destroy.notify = launch_effect_handle_destroy;
+    ds_tizen_effect_add_destroy_listener(server->effect,
+            &server->effect_destroy);
+
+    server->effect_type_set.notify = launch_effect_handle_type_set;
+    ds_tizen_effect_add_type_set_listener(server->effect,
+            &server->effect_type_set);
+
+    server->effect_type_unset.notify = launch_effect_handle_type_unset;
+    ds_tizen_effect_add_type_unset_listener(server->effect,
+            &server->effect_type_unset);
+
+    server->new_splash.notify = launch_effect_handle_new_splash;
+    ds_tizen_effect_add_new_splash_listener(server->effect,
+            &server->new_splash);
+
     return true;
 
 err:
diff --git a/include/libds-tizen/launch/effect.h b/include/libds-tizen/launch/effect.h
new file mode 100644 (file)
index 0000000..d49fa33
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef LIBDS_TIZEN_EFFECT_H
+#define LIBDS_TIZEN_EFFECT_H
+
+#include <stdint.h>
+#include <wayland-server.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ds_tizen_effect;
+struct ds_tizen_splash;
+
+enum ds_tizen_effect_type
+{
+    DS_TIZEN_EFFECT_TYPE_LAUNCH = 0,
+    DS_TIZEN_EFFECT_TYPE_DEPTH_IN,
+};
+
+struct ds_tizen_effect_event_type_set
+{
+    uint32_t pid;
+    enum ds_tizen_effect_type effect_type;
+};
+
+struct ds_tizen_effect_event_type_unset
+{
+    uint32_t pid;
+};
+
+struct ds_tizen_effect_event_new_splash
+{
+    struct ds_tizen_splash *splash;
+};
+
+enum ds_tizen_splash_file_type
+{
+    DS_TIZEN_SPLASH_FILE_TYPE_ERR = -1,
+    DS_TIZEN_SPLASH_FILE_TYPE_IMG,
+    DS_TIZEN_SPLASH_FILE_TYPE_EDJ,
+};
+
+struct ds_tizen_splash_event_owner
+{
+    uint32_t pid;
+};
+
+// launch_effect
+struct ds_tizen_effect *
+ds_tizen_effect_create(struct wl_display *display);
+
+void
+ds_tizen_effect_add_destroy_listener(
+    struct ds_tizen_effect *effect, struct wl_listener *listener);
+void
+ds_tizen_effect_add_type_set_listener(
+    struct ds_tizen_effect *effect, struct wl_listener *listener);
+void
+ds_tizen_effect_add_type_unset_listener(struct ds_tizen_effect *effect,
+    struct wl_listener *listener);
+void
+ds_tizen_effect_add_new_splash_listener(struct ds_tizen_effect *effect,
+    struct wl_listener *listener);
+
+void
+ds_tizen_effect_set_effect_type(struct ds_tizen_effect *effect,
+    uint32_t pid, int effect_type);
+void
+ds_tizen_effect_unset_effect_type(struct ds_tizen_effect *effect,
+    uint32_t pid);
+int
+ds_tizen_effect_get_effect_type(struct ds_tizen_effect *effect,
+    uint32_t pid);
+
+// launch_splash
+void
+ds_tizen_splash_add_destroy_listener(
+    struct ds_tizen_splash *splash, struct wl_listener *listener);
+void
+ds_tizen_splash_add_owner_listener(
+    struct ds_tizen_splash *splash, struct wl_listener *listener);
+
+uint32_t
+ds_tizen_splash_get_pid(struct ds_tizen_splash *splash);
+void
+ds_tizen_splash_set_pid(struct ds_tizen_splash *splash, uint32_t pid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index 546a832..b76d434 100644 (file)
@@ -398,9 +398,11 @@ ninja -C builddir install
 %defattr(-,root,root,-)
 %license LICENSE
 %{_includedir}/libds-tizen/launch/appinfo.h
+%{_includedir}/libds-tizen/launch/effect.h
 %{_libdir}/pkgconfig/libds-tizen-launch.pc
 %{_libdir}/libds-tizen-launch.so
 %{_bindir}/libds-tizen-launch-appinfo-tests
+%{_bindir}/libds-tizen-launch-effect-tests
 
 %files display-policy
 %manifest %{name}.manifest
diff --git a/src/launch/effect.c b/src/launch/effect.c
new file mode 100644 (file)
index 0000000..fc38c77
--- /dev/null
@@ -0,0 +1,557 @@
+#include <stdlib.h>
+#include <wayland-server.h>
+#include <tizen-launch-server-protocol.h>
+#include <libds/log.h>
+
+#include "util.h"
+#include <libds-tizen/launch/effect.h>
+
+#define TIZEN_EFFECT_VERSION 1
+#define SPLASH_CLIENT_PID 321 // no meaning
+#define CUSTOM_EFFECT_CALLEE "_CUSTOM_EFFECT_CALLEE_"
+
+struct ds_tizen_effect
+{
+    struct wl_global *global;
+
+    struct wl_list clients;
+    struct wl_list infos;
+
+    struct wl_listener destroy;
+
+    struct {
+        struct wl_signal destroy;
+        struct wl_signal type_set;
+        struct wl_signal type_unset;
+        struct wl_signal new_splash;
+    } events;
+};
+
+struct ds_tizen_effect_client
+{
+    struct ds_tizen_effect *effect;
+
+    struct wl_resource *resource;
+    struct wl_client *wl_client;
+
+    struct wl_list splashs;
+
+    struct wl_list link; // ds_tizen_effect::clients
+};
+
+struct ds_tizen_effect_info
+{
+    uint32_t pid;
+    int effect_type;
+
+    struct wl_list link; // ds_tizen_effect::infos
+};
+
+struct ds_tizen_splash
+{
+    struct ds_tizen_effect *effect;
+
+    struct ds_tizen_effect_client *client;
+    struct wl_resource *resource;
+
+    uint32_t pid;
+    char *appid;
+    bool custom_effect_callee;
+
+    struct {
+        struct wl_signal destroy;
+        struct wl_signal owner;
+    } events;
+
+    struct wl_list link; // ds_tizen_effect_client::splashs
+};
+
+static void effect_handle_display_destroy(struct wl_listener *listener,
+        void *data);
+
+static void effect_bind(struct wl_client *wl_client, void *data,
+        uint32_t version, uint32_t id);
+
+WL_EXPORT struct ds_tizen_effect *
+ds_tizen_effect_create(struct wl_display *display)
+{
+    struct ds_tizen_effect *effect;
+
+    effect = calloc(1, sizeof *effect);
+    if (!effect) {
+        ds_err("calloc() failed.");
+        return NULL;
+    }
+
+    effect->global = wl_global_create(display, &tizen_launch_effect_interface,
+            TIZEN_EFFECT_VERSION, effect, effect_bind);
+    if (!effect->global) {
+        ds_err("wl_global_create() failed. tizen_launch_effect_interface");
+        free(effect);
+        return NULL;
+    }
+
+    wl_list_init(&effect->clients);
+    wl_list_init(&effect->infos);
+
+    effect->destroy.notify = effect_handle_display_destroy;
+    wl_display_add_destroy_listener(display, &effect->destroy);
+
+    wl_signal_init(&effect->events.destroy);
+    wl_signal_init(&effect->events.type_set);
+    wl_signal_init(&effect->events.type_unset);
+    wl_signal_init(&effect->events.new_splash);
+
+    ds_inf("Global create: tizen_launch_effect. effect(%p)", effect);
+
+    return effect;
+}
+
+//launch_effect
+WL_EXPORT void
+ds_tizen_effect_add_destroy_listener(
+    struct ds_tizen_effect *effect, struct wl_listener *listener)
+{
+    wl_signal_add(&effect->events.destroy, listener);
+}
+
+WL_EXPORT void
+ds_tizen_effect_add_type_set_listener(
+    struct ds_tizen_effect *effect, struct wl_listener *listener)
+{
+    wl_signal_add(&effect->events.type_set, listener);
+}
+
+WL_EXPORT void
+ds_tizen_effect_add_type_unset_listener(
+    struct ds_tizen_effect *effect, struct wl_listener *listener)
+{
+    wl_signal_add(&effect->events.type_unset, listener);
+}
+
+WL_EXPORT void
+ds_tizen_effect_add_new_splash_listener(
+    struct ds_tizen_effect *effect, struct wl_listener *listener)
+{
+    wl_signal_add(&effect->events.new_splash, listener);
+}
+
+WL_EXPORT void
+ds_tizen_effect_set_effect_type(struct ds_tizen_effect *effect,
+    uint32_t pid, int effect_type)
+{
+    struct ds_tizen_effect_info *info;
+
+    ds_inf("ds_tizen_effect_set_effect_type() pid(%u), effect_type(%d)", pid, effect_type);
+
+    info = calloc(1, sizeof *info);
+    if (info == NULL) {
+        ds_err("calloc() failed. tizen_effect_info");
+        return;
+    }
+    info->pid = pid;
+    info->effect_type = effect_type;
+
+    wl_list_insert(&effect->infos, &info->link);
+}
+
+WL_EXPORT void
+ds_tizen_effect_unset_effect_type(struct ds_tizen_effect *effect,
+    uint32_t pid)
+{
+    struct ds_tizen_effect_info *info, *tmp;
+
+    ds_inf("ds_tizen_effect_unset_effect_type() pid(%u)", pid);
+
+    wl_list_for_each_safe(info, tmp, &effect->infos, link) {
+        if (info->pid == pid) {
+            ds_inf("ds_tizen_effect_unset_effect_type() pid found.", pid);
+            wl_list_remove(&info->link);
+            free(info);
+        }
+    }
+}
+
+WL_EXPORT int
+ds_tizen_effect_get_effect_type(struct ds_tizen_effect *effect,
+    uint32_t pid)
+{
+    struct ds_tizen_effect_info *info;
+
+    ds_inf("ds_tizen_effect_get_effect_type() pid(%u)", pid);
+
+    wl_list_for_each(info, &effect->infos, link) {
+        if (info->pid == pid) {
+            return info->effect_type;
+        }
+    }
+    return -1;
+}
+
+//launch_splash
+WL_EXPORT void
+ds_tizen_splash_add_destroy_listener(
+    struct ds_tizen_splash *splash, struct wl_listener *listener)
+{
+    wl_signal_add(&splash->events.destroy, listener);
+}
+
+WL_EXPORT void
+ds_tizen_splash_add_owner_listener(
+    struct ds_tizen_splash *splash, struct wl_listener *listener)
+{
+    wl_signal_add(&splash->events.owner, listener);
+}
+
+WL_EXPORT uint32_t
+ds_tizen_splash_get_pid(struct ds_tizen_splash *splash)
+{
+    return splash->pid;
+}
+
+WL_EXPORT void
+ds_tizen_splash_set_pid(struct ds_tizen_splash *splash, uint32_t pid)
+{
+    splash->pid = pid;
+}
+
+static void
+effect_client_destroy(struct ds_tizen_effect_client *client)
+{
+    struct ds_tizen_splash *splash, *tmp;
+
+    wl_list_for_each_safe(splash, tmp, &client->splashs, link) {
+        wl_signal_emit(&splash->events.destroy, splash);
+        wl_list_remove(&splash->link);
+        free(splash);
+    }
+
+    wl_list_remove(&client->link);
+    free(client);
+}
+
+static void effect_handle_display_destroy(struct wl_listener *listener,
+    void *data)
+{
+    struct ds_tizen_effect *effect;
+    struct ds_tizen_effect_client *client, *tmp_client;
+    struct ds_tizen_effect_info *info, *tmp_info;
+
+    effect = wl_container_of(listener, effect, destroy);
+
+    ds_inf("Global destroy: effect(%p)", effect);
+
+    wl_signal_emit(&effect->events.destroy, effect);
+    wl_list_remove(&effect->destroy.link);
+
+    wl_list_for_each_safe(client, tmp_client, &effect->clients, link) {
+        effect_client_destroy(client);
+    }
+
+    wl_list_for_each_safe(info, tmp_info, &effect->infos, link) {
+        wl_list_remove(&info->link);
+        free(info);
+    }
+
+    wl_global_destroy(effect->global);
+    free(effect);
+}
+
+static int
+effect_get_effect_type(const char *effect_type)
+{
+    enum ds_tizen_effect_type type = 0;
+
+    if (!effect_type) return 0;
+
+    if (!strncmp(effect_type, "launch", sizeof("launch"))) type =  DS_TIZEN_EFFECT_TYPE_LAUNCH;
+    else if (!strncmp(effect_type, "depth-in", sizeof("depth-in"))) type = DS_TIZEN_EFFECT_TYPE_DEPTH_IN;
+
+    return type;
+}
+
+static void
+splash_handle_destroy(struct wl_client *wl_client, struct wl_resource *resource)
+{
+    wl_resource_destroy(resource);
+}
+
+static void
+splash_handle_launch(struct wl_client *wl_client,
+    struct wl_resource *resource, const char *pfname, uint32_t ftype,
+    uint32_t depth, uint32_t angle, uint32_t indicator,
+    const char *effect_type, const char *theme_type,
+    struct wl_array *options)
+{
+    struct ds_tizen_effect_event_type_set ds_event;
+    struct ds_tizen_splash *splash;
+    struct ds_tizen_effect *effect;
+
+    ds_inf("splash launch");
+    ds_inf("path %s(%s), indicator(%d), angle(%d), effect_type(%s)",
+        pfname, (ftype == DS_TIZEN_SPLASH_FILE_TYPE_IMG) ? "IMG" : "EDC", indicator, angle, effect_type);
+    ds_inf("theme_type(%s), options(%p)",theme_type, options);
+
+    splash = wl_resource_get_user_data(resource);
+    splash->pid = SPLASH_CLIENT_PID;
+    effect = splash->effect;
+    if (effect) {
+        ds_event.pid = SPLASH_CLIENT_PID;
+        ds_event.effect_type = effect_get_effect_type(effect_type);
+
+        ds_inf("Effect type_set. pid:%u type:%s", ds_event.pid, effect_type);
+
+        wl_signal_emit(&effect->events.type_set, &ds_event);
+    }
+}
+
+static void
+splash_handle_owner(struct wl_client *wl_client,
+    struct wl_resource *resource, uint32_t pid)
+{
+    struct ds_tizen_splash *splash;
+    struct ds_tizen_splash_event_owner ds_event;
+
+    ds_inf("splash set owner. pid:%u", pid);
+
+    splash = wl_resource_get_user_data(resource);
+
+    ds_event.pid = pid;
+    wl_signal_emit(&splash->events.owner, &ds_event);
+}
+
+static void
+splash_handle_launch_v2(struct wl_client *wl_client,
+    struct wl_resource *resource, const char *pfname, uint32_t ftype,
+    uint32_t depth, uint32_t angle, uint32_t indicator,
+    const char *effect_type, const char *theme_type,
+    struct wl_array *options, struct wl_array *extra_config)
+{
+    struct ds_tizen_effect_event_type_set ds_event;
+    struct ds_tizen_splash *splash;
+    struct ds_tizen_effect *effect;
+
+    ds_inf("splash launch_v2");
+    ds_inf("path %s(%s), indicator(%d), angle(%d), effect_type(%s)",
+        pfname, (ftype == DS_TIZEN_SPLASH_FILE_TYPE_IMG) ? "IMG" : "EDC", indicator, angle, effect_type);
+    ds_inf("theme_type(%s) options(%p) extra_config(%p)", theme_type, options, extra_config);
+
+    splash = wl_resource_get_user_data(resource);
+    splash->pid = SPLASH_CLIENT_PID;
+    effect = splash->effect;
+    if (effect) {
+        ds_event.pid = SPLASH_CLIENT_PID;
+        ds_event.effect_type = effect_get_effect_type(effect_type);
+
+        ds_inf("Effect type_set. pid:%u type:%s", ds_event.pid, effect_type);
+
+        wl_signal_emit(&effect->events.type_set, &ds_event);
+    }
+
+    //Parse extra config
+    if ((extra_config) && (extra_config->size)) {
+        char *p_char;
+        int len = 0;
+        int size = extra_config->size;
+
+        while (size > 0) {
+            p_char = extra_config->data + len;
+            len = strlen(p_char) + 1;
+            size -= len;
+
+            if (!strcmp(p_char, CUSTOM_EFFECT_CALLEE)) {
+                //parse next data(appid) from array
+                if (size > 0) {
+                    p_char = p_char + len;
+                    len = strlen(p_char) + 1;
+                    size -= len;
+
+                    splash->appid = strdup(p_char);
+                    splash->custom_effect_callee = true;
+
+                    ds_inf("custom effect callee set appid(%s)",
+                        splash->appid);
+                    }
+                else break;
+            }
+        }
+    }
+}
+
+static const struct tizen_launch_splash_interface splash_impl =
+{
+    splash_handle_destroy,
+    splash_handle_launch,
+    splash_handle_owner,
+    splash_handle_launch_v2,
+};
+
+static void
+splash_client_handle_destroy(struct wl_resource *resource)
+{
+    struct ds_tizen_splash *splash;
+
+    splash = wl_resource_get_user_data(resource);
+
+    ds_inf("splash_client_handle_destroy (client:%p)", splash->client);
+
+    wl_signal_emit(&splash->events.destroy, splash);
+    wl_list_remove(&splash->link);
+    free(splash);
+}
+
+struct ds_tizen_splash*
+splash_create_splash_img(struct ds_tizen_effect_client *client, uint32_t id)
+{
+    struct ds_tizen_splash *splash;
+
+    splash = calloc(1, sizeof *splash);
+    if (!splash) {
+        wl_client_post_no_memory(client->wl_client);
+        return NULL;
+    }
+
+    splash->resource = wl_resource_create(client->wl_client,
+            &tizen_launch_splash_interface, wl_resource_get_version(client->resource),
+            id);
+    if (!splash->resource) {
+        free(splash);
+        wl_client_post_no_memory(client->wl_client);
+        return NULL;
+    }
+    splash->client = client;
+    splash->effect = client->effect;
+    splash->pid = SPLASH_CLIENT_PID;
+
+    wl_signal_init(&splash->events.destroy);
+    wl_signal_init(&splash->events.owner);
+
+    wl_resource_set_implementation(splash->resource, &splash_impl,
+            splash, splash_client_handle_destroy);
+
+    wl_list_insert(&client->splashs, &splash->link);
+
+    ds_inf("New Splash img %p (res %p)", splash, splash->resource);
+
+    return splash;
+}
+
+static void
+effect_handle_create_splash_img(struct wl_client *wl_client,
+    struct wl_resource *resource, uint32_t id)
+{
+    struct ds_tizen_effect *effect;
+    struct ds_tizen_effect_client *client;
+    struct ds_tizen_effect_event_new_splash ds_event;
+    struct ds_tizen_splash *splash;
+
+    client = wl_resource_get_user_data(resource);
+    splash = splash_create_splash_img(client, id);
+    if (!splash) return;
+
+    effect = client->effect;
+    ds_event.splash  = splash;
+    wl_signal_emit(&effect->events.new_splash, &ds_event);
+}
+
+static void
+effect_handle_type_set(struct wl_client *wl_client,
+    struct wl_resource *resource, const char *effect_type, uint32_t pid,
+    struct wl_array *options)
+{
+    struct ds_tizen_effect *effect;
+    struct ds_tizen_effect_client *client;
+    struct ds_tizen_effect_event_type_set ds_event;
+
+    client = wl_resource_get_user_data(resource);
+    effect = client->effect;
+
+    ds_event.pid = pid;
+    ds_event.effect_type = effect_get_effect_type(effect_type);
+
+    ds_inf("Effect type_set. pid:%u type:%s", pid, effect_type);
+
+    wl_signal_emit(&effect->events.type_set, &ds_event);
+}
+
+static void
+effect_handle_type_unset(struct wl_client *wl_client,
+    struct wl_resource *resource, uint32_t pid)
+{
+    struct ds_tizen_effect *effect;
+    struct ds_tizen_effect_client *client;
+    struct ds_tizen_effect_event_type_unset ds_event;
+
+    client = wl_resource_get_user_data(resource);
+    effect = client->effect;
+
+    ds_event.pid = pid;
+
+    ds_inf("Effect type_unset. pid:%u", pid);
+
+    wl_signal_emit(&effect->events.type_unset, &ds_event);
+}
+
+static void
+effect_handle_destroy(struct wl_client *wl_client,
+    struct wl_resource *resource)
+{
+    wl_resource_destroy(resource);
+}
+
+static const struct tizen_launch_effect_interface effect_impl =
+{
+    effect_handle_create_splash_img,
+    effect_handle_type_set,
+    effect_handle_type_unset,
+    effect_handle_destroy,
+};
+
+static void
+effect_client_handle_destroy(struct wl_resource *resource)
+{
+    struct ds_tizen_effect_client *client;
+
+    client = wl_resource_get_user_data(resource);
+
+    ds_inf("effect_client_handle_destroy (client:%p)", client);
+
+    effect_client_destroy(client);
+}
+
+static void effect_bind(struct wl_client *wl_client, void *data,
+        uint32_t version, uint32_t id)
+{
+    struct ds_tizen_effect *effect = data;
+    struct ds_tizen_effect_client *client;
+
+    client = calloc(1, sizeof *client);
+    if (client == NULL) {
+        ds_err("calloc() failed. tizen_,launch_effect");
+        wl_client_post_no_memory(wl_client);
+        return;
+    }
+
+    ds_inf("tizen_effect. client binds. (client:%p)", client);
+
+    client->effect = effect;
+    client->wl_client = wl_client;
+
+    client->resource = wl_resource_create(wl_client,
+            &tizen_launch_effect_interface,
+            MIN(version, TIZEN_EFFECT_VERSION), id);
+
+    if (client->resource == NULL) {
+        ds_err("tizen_effect : wl_resource_create() failed.");
+        free(client);
+        wl_client_post_no_memory(wl_client);
+        return;
+    }
+
+    wl_list_init(&client->splashs);
+
+    wl_resource_set_implementation(client->resource, &effect_impl, client,
+            effect_client_handle_destroy);
+
+    wl_list_insert(&effect->clients, &client->link);
+}
index b3e2efd..494a933 100644 (file)
@@ -1,5 +1,6 @@
 libds_tizen_launch_files = [
   'appinfo.c',
+  'effect.c',
 ]
 
 libds_tizen_launch_deps = [
index 40e737e..58051f6 100644 (file)
@@ -85,6 +85,25 @@ executable('libds-tizen-launch-appinfo-tests',
   install : true
 )
 
+## launch effect tests
+tc_launch_effect_files = [
+  'tc_main.cpp',
+  'tc_launch_effect.cpp',
+]
+
+executable('libds-tizen-launch-effect-tests',
+  [
+    tc_mock_files,
+    tc_launch_effect_files
+  ],
+  dependencies: [
+    deps_test_common,
+    deps_libds_tizen_launch,
+  ],
+  install_dir: libds_tizen_bindir,
+  install : true
+)
+
 ## display-policy tests
 tc_display_policy_files = [
   'tc_main.cpp',
diff --git a/tests/tc_launch_effect.cpp b/tests/tc_launch_effect.cpp
new file mode 100644 (file)
index 0000000..ebfd8ca
--- /dev/null
@@ -0,0 +1,476 @@
+#include "tc_main.h"
+#include "mockclient.h"
+#include "mockcompositor.h"
+#include <libds-tizen/launch/effect.h>
+#include <tizen-launch-server-protocol.h>
+#include <tizen-launch-client-protocol.h>
+
+#define TIZEN_EFFECT_VERSION 1
+#define SPLASH_CLIENT_PID 321 // no meaning
+#define CUSTOM_EFFECT_CALLEE "_CUSTOM_EFFECT_CALLEE_"
+#define SPLASH_TYPE_IMG 0
+#define SPLASH_TYPE_EDC 1
+
+//code from e-tizen-testcase
+char const *path_edc = "/usr/share/e_tizen_unittests/data/launch_splash.edj";
+char const *path_img = "/usr/share/e_tizen_unittests/data/launchimg_splash.png";
+
+class MockEffectCompositor : public MockCompositor
+{
+public:
+    MockEffectCompositor()
+        : MockCompositor(&MockEffectCompositor::TestSetup, this)
+    {
+        ds_inf("%s : this(%p)", __func__, this);
+
+        // initialize the flags to check
+        bDestroyed = false;
+        bTypeSet = false;
+        bNewSplash = false;
+        bOwner = false;
+
+        mPid = 0;
+        mEffectType = -1;
+    }
+
+    ~MockEffectCompositor()
+    {
+        ds_inf("%s : this(%p)", __func__, this);
+    }
+
+    static void TestSetup(void *data)
+    {
+        MockEffectCompositor *mockComp =
+            static_cast<MockEffectCompositor *>(data);
+        Compositor *comp = mockComp->compositor;
+
+        ds_inf("%s: mockComp(%p)", __func__, mockComp);
+
+        mockComp->mEffect = ds_tizen_effect_create(comp->display);
+
+        // destroy listener
+        mockComp->mDestroyListener.notify =
+            MockEffectCompositor::DestroyCallback;
+        mockComp->mDestroyListener.parent = mockComp;
+        ds_tizen_effect_add_destroy_listener(mockComp->mEffect,
+            &mockComp->mDestroyListener);
+
+        // type_set listener
+        mockComp->mTypeSetListener.notify =
+            MockEffectCompositor::TypeSetCallback;
+        mockComp->mTypeSetListener.parent = mockComp;
+        ds_tizen_effect_add_type_set_listener(mockComp->mEffect,
+            &mockComp->mTypeSetListener);
+
+        // type_unset listener
+        mockComp->mTypeUnsetListener.notify =
+            MockEffectCompositor::TypeUnsetCallback;
+        mockComp->mTypeUnsetListener.parent = mockComp;
+        ds_tizen_effect_add_type_unset_listener(mockComp->mEffect,
+            &mockComp->mTypeUnsetListener);
+
+        // new_splash listener
+        mockComp->mNewSplashListener.notify =
+            MockEffectCompositor::NewSplashCallback;
+        mockComp->mNewSplashListener.parent = mockComp;
+        ds_tizen_effect_add_new_splash_listener(mockComp->mEffect,
+            &mockComp->mNewSplashListener);
+    }
+
+    static void DestroyCallback(struct wl_listener *listener, void *data)
+    {
+        ds_inf("%s", __func__);
+
+        MockEffectCompositor *mockComp =
+            reinterpret_cast<DestroyListener *>(listener)->parent;
+
+        mockComp->bDestroyed = true;
+    }
+
+    static void TypeSetCallback(struct wl_listener *listener, void *data)
+    {
+        struct ds_tizen_effect_event_type_set *event = (ds_tizen_effect_event_type_set *)data;
+        ds_inf("%s", __func__);
+
+        MockEffectCompositor *mockComp =
+            reinterpret_cast<TypeSetListener *>(listener)->parent;
+
+        mockComp->bTypeSet = true;
+        mockComp->mPid = event->pid;
+        mockComp->mEffectType = event->effect_type;
+    }
+
+    static void TypeUnsetCallback(struct wl_listener *listener, void *data)
+    {
+        struct ds_tizen_effect_event_type_unset *event = (ds_tizen_effect_event_type_unset *)data;
+        ds_inf("%s", __func__);
+
+        MockEffectCompositor *mockComp =
+            reinterpret_cast<TypeUnsetListener *>(listener)->parent;
+
+        mockComp->bTypeSet = false;
+        mockComp->mPid = event->pid;
+        mockComp->mEffectType = -1;
+    }
+
+
+    static void NewSplashCallback(struct wl_listener *listener, void *data)
+    {
+        struct ds_tizen_effect_event_new_splash *event = (ds_tizen_effect_event_new_splash *)data;
+        ds_inf("%s", __func__);
+
+        MockEffectCompositor *mockComp =
+            reinterpret_cast<NewSplashListener *>(listener)->parent;
+
+        mockComp->bNewSplash = true;
+        mockComp->mSplash = event->splash;
+
+        // owner listener
+        mockComp->mOwnerListener.notify =
+            MockEffectCompositor::OwnerCallback;
+        mockComp->mOwnerListener.parent = mockComp;
+        ds_tizen_splash_add_owner_listener(mockComp->mSplash,
+            &mockComp->mOwnerListener);
+    }
+
+    static void OwnerCallback(struct wl_listener *listener, void *data)
+    {
+        struct ds_tizen_splash_event_owner *event = (ds_tizen_splash_event_owner *)data;
+        ds_inf("%s", __func__);
+
+        MockEffectCompositor *mockComp =
+            reinterpret_cast<OwnerListener *>(listener)->parent;
+
+        mockComp->mPid = event->pid;
+    }
+
+public:
+    bool bDestroyed;
+    bool bTypeSet;
+    bool bNewSplash;
+    bool bOwner;
+
+    uint32_t mPid;
+    int mEffectType;
+
+private:
+    struct ds_tizen_effect *mEffect;
+    struct ds_tizen_splash *mSplash;
+    struct DestroyListener: ::wl_listener {
+        MockEffectCompositor *parent;
+    };
+    DestroyListener mDestroyListener;
+
+    struct TypeSetListener: ::wl_listener {
+        MockEffectCompositor *parent;
+    };
+    TypeSetListener mTypeSetListener;
+
+    struct TypeUnsetListener: ::wl_listener {
+        MockEffectCompositor *parent;
+    };
+    TypeUnsetListener mTypeUnsetListener;
+
+    struct NewSplashListener: ::wl_listener {
+        MockEffectCompositor *parent;
+    };
+    NewSplashListener mNewSplashListener;
+
+    struct OwnerListener: ::wl_listener {
+        MockEffectCompositor *parent;
+    };
+    OwnerListener mOwnerListener;
+};
+
+class MockEffectClient : public MockClient
+{
+public:
+    MockEffectClient()
+        : compositor_res(nullptr),
+          tizen_launch_effect(nullptr)
+    {}
+
+    MockEffectClient(const struct wl_registry_listener *listener)
+        : MockClient(listener, this)
+    {
+        ds_inf("%s", __func__);
+    }
+
+    ~MockEffectClient()
+    {
+        ds_inf("%s", __func__);
+    }
+
+    void SetWlCompositor(struct wl_compositor *global_res)
+    {
+        ds_inf("%s", __func__);
+
+        compositor_res = global_res;
+    }
+
+    struct wl_compositor *GetWlCompositor()
+    {
+        ds_inf("%s", __func__);
+
+        return compositor_res;
+    }
+
+    void SetTizenEffect(struct tizen_launch_effect *global_res)
+    {
+        ds_inf("%s", __func__);
+        tizen_launch_effect = global_res;
+    }
+
+    struct tizen_launch_effect *GetTizenEffect()
+    {
+        ds_inf("%s", __func__);
+
+        return tizen_launch_effect;
+    }
+
+public:
+
+private:
+    struct wl_compositor *compositor_res;
+    struct tizen_launch_effect *tizen_launch_effect;
+};
+
+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__);
+
+    MockEffectClient *client = static_cast<MockEffectClient *>(data);
+    struct wl_compositor *compositor_res;
+    struct tizen_launch_effect *tizen_launch_effect;
+
+    if (!strcmp(interface, "wl_compositor")) {
+        compositor_res = (struct wl_compositor *)wl_registry_bind(registry,
+            name, &wl_compositor_interface, 1);
+        if (compositor_res == nullptr) {
+            ds_err("wl_registry_bind() failed. wl_compositor resource.");
+            return;
+        }
+        client->SetWlCompositor(compositor_res);
+    } else if (!strcmp(interface, "tizen_launch_effect")) {
+        tizen_launch_effect = (struct tizen_launch_effect *)wl_registry_bind(registry,
+            name, &tizen_launch_effect_interface, TIZEN_EFFECT_VERSION);
+        if (tizen_launch_effect == nullptr) {
+            ds_err("wl_registry_bind() failed. tizen_launch_effect resource.");
+            return;
+        }
+        client->SetTizenEffect(tizen_launch_effect);
+    }
+}
+
+static void
+client_registry_cb_global_remove(void *data, struct wl_registry *registry,
+    uint32_t name)
+{
+    ds_inf("%s", __func__);
+
+    MockEffectClient *client = static_cast<MockEffectClient *>(data);
+    struct wl_compositor *compositor_res = client->GetWlCompositor();
+    struct tizen_launch_effect *effect_res = client->GetTizenEffect();
+
+    tizen_launch_effect_destroy(effect_res);
+    wl_compositor_destroy(compositor_res);
+}
+
+static const struct wl_registry_listener registry_listener = {
+    .global = client_registry_cb_global,
+    .global_remove = client_registry_cb_global_remove
+};
+
+class EffectTest : public ::testing::Test
+{
+public:
+    void SetUp(void) override;
+    void TearDown(void) override;
+
+    MockEffectCompositor *comp;
+    MockEffectClient *client;
+    struct wl_compositor *compositor_res;
+    struct tizen_launch_effect *effect_res;
+};
+
+void
+EffectTest::SetUp(void)
+{
+    ds_inf("%s", __func__);
+
+    comp = new MockEffectCompositor();
+    client = new MockEffectClient(&registry_listener);
+    compositor_res = client->GetWlCompositor();
+    effect_res = client->GetTizenEffect();
+
+    client->RoundTrip();
+}
+
+void
+EffectTest::TearDown(void)
+{
+    ds_inf("%s", __func__);
+
+    client->RoundTrip();
+
+    delete client;
+    delete comp;
+}
+
+TEST_F(EffectTest, Create_P)
+{
+    EXPECT_TRUE(true);
+}
+
+TEST_F(EffectTest, Req_TizenEffectTypeSet)
+{
+    uint pid = 12345;
+    const char *effect_type;
+
+    effect_type = "launch";
+    tizen_launch_effect_type_set(effect_res, effect_type, pid, NULL);
+    client->RoundTrip();
+    EXPECT_TRUE(comp->bTypeSet);
+    EXPECT_TRUE(comp->mPid == pid);
+    EXPECT_TRUE(comp->mEffectType == DS_TIZEN_EFFECT_TYPE_LAUNCH);
+}
+
+TEST_F(EffectTest, Req_TizenEffectTypeUnSet)
+{
+    uint pid = 12345;
+    const char *effect_type;
+
+    effect_type = "depth-in";
+    tizen_launch_effect_type_set(effect_res, effect_type, pid, NULL);
+    client->RoundTrip();
+    EXPECT_TRUE(comp->bTypeSet);
+    EXPECT_TRUE(comp->mPid == pid);
+    EXPECT_TRUE(comp->mEffectType == DS_TIZEN_EFFECT_TYPE_DEPTH_IN);
+
+    tizen_launch_effect_type_unset(effect_res, pid);
+    client->RoundTrip();
+    EXPECT_FALSE(comp->bTypeSet);
+    EXPECT_TRUE(comp->mPid == pid);
+    EXPECT_TRUE(comp->mEffectType == -1);
+}
+
+TEST_F(EffectTest, Req_TizenEffectCreateSplashImg)
+{
+    struct tizen_launch_splash *splash = NULL;
+
+    splash = tizen_launch_effect_create_splash_img(effect_res);
+    client->RoundTrip();
+    EXPECT_TRUE(splash != NULL);
+    EXPECT_TRUE(comp->bNewSplash);
+}
+
+TEST_F(EffectTest, Req_TizenSplashLaunch_EDC)
+{
+    struct tizen_launch_splash *splash = NULL;
+    struct wl_array options;
+
+    splash = tizen_launch_effect_create_splash_img(effect_res);
+    client->RoundTrip();
+    EXPECT_TRUE(splash != NULL);
+    EXPECT_TRUE(comp->bNewSplash);
+
+    wl_array_init(&options);
+
+    tizen_launch_splash_launch(splash, path_edc,\
+        SPLASH_TYPE_EDC, 24, 0, 0, "launch", "default", &options);
+    client->RoundTrip();
+    wl_array_release(&options);
+    EXPECT_TRUE(comp->mPid == SPLASH_CLIENT_PID);
+    EXPECT_TRUE(comp->mEffectType == DS_TIZEN_EFFECT_TYPE_LAUNCH);
+}
+
+TEST_F(EffectTest, Req_TizenSplashLaunch_IMG)
+{
+    struct tizen_launch_splash *splash = NULL;
+    struct wl_array options;
+
+    splash = tizen_launch_effect_create_splash_img(effect_res);
+    client->RoundTrip();
+    EXPECT_TRUE(splash != NULL);
+    EXPECT_TRUE(comp->bNewSplash);
+
+    wl_array_init(&options);
+
+    tizen_launch_splash_launch(splash, path_img,\
+        SPLASH_TYPE_IMG, 24, 0, 0, "launch", "default", &options);
+    client->RoundTrip();
+    wl_array_release(&options);
+    EXPECT_TRUE(comp->mPid == SPLASH_CLIENT_PID);
+    EXPECT_TRUE(comp->mEffectType == DS_TIZEN_EFFECT_TYPE_LAUNCH);
+}
+
+TEST_F(EffectTest, Req_TizenSplashSetOwner)
+{
+    struct tizen_launch_splash *splash = NULL;
+    struct wl_array options;
+    uint32_t pid = 12345;
+
+    splash = tizen_launch_effect_create_splash_img(effect_res);
+    client->RoundTrip();
+    EXPECT_TRUE(splash != NULL);
+    EXPECT_TRUE(comp->bNewSplash);
+
+    wl_array_init(&options);
+
+    tizen_launch_splash_launch(splash, path_img,\
+        SPLASH_TYPE_IMG, 24, 0, 0, "depth-in", "default", &options);
+    client->RoundTrip();
+    wl_array_release(&options);
+    EXPECT_TRUE(comp->mPid == SPLASH_CLIENT_PID);
+    EXPECT_TRUE(comp->mEffectType == DS_TIZEN_EFFECT_TYPE_DEPTH_IN);
+
+    tizen_launch_splash_owner(splash, pid);
+    client->RoundTrip();
+    EXPECT_TRUE(comp->mPid == pid);
+    EXPECT_TRUE(comp->mEffectType == DS_TIZEN_EFFECT_TYPE_DEPTH_IN);
+}
+
+TEST_F(EffectTest, Req_TizenSplashLaunch_v2)
+
+{
+    struct tizen_launch_splash *splash = NULL;
+    struct wl_array options;
+    struct wl_array extra_config;
+    int custom_effect = 0;
+    void *data;
+    int size;
+    const char *appid = "org.tizen.libds-tizen-launch-effect-test";
+
+    splash = tizen_launch_effect_create_splash_img(effect_res);
+    client->RoundTrip();
+    EXPECT_TRUE(splash != NULL);
+    EXPECT_TRUE(comp->bNewSplash);
+
+    // set
+    wl_array_init(&options);
+    size = strlen(appid) + 1;
+    data = wl_array_add(&options, size);
+    memcpy(data, appid, size);
+
+    wl_array_init(&extra_config);
+    size = strlen(CUSTOM_EFFECT_CALLEE) + 1;
+    data = wl_array_add(&extra_config, size);
+    memcpy(data, CUSTOM_EFFECT_CALLEE, size);
+
+    size = strlen(appid) + 1;
+    data = wl_array_add(&extra_config, size);
+    memcpy(data, appid, size);
+
+    if (extra_config.size > 0)
+        custom_effect = 1;
+
+    tizen_launch_splash_launch_v2(splash, path_edc,\
+        SPLASH_TYPE_EDC, 24, 0, 0, "depth-in", "default", &options, custom_effect ? &extra_config : NULL);
+    client->RoundTrip();
+    wl_array_release(&options);
+    wl_array_release(&extra_config);
+    EXPECT_TRUE(comp->mPid == SPLASH_CLIENT_PID);
+    EXPECT_TRUE(comp->mEffectType == DS_TIZEN_EFFECT_TYPE_DEPTH_IN);
+}