+#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);
+}