--- /dev/null
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <wayland-server.h>
+#include <tizen-surface-server-protocol.h>
+#include <libds/log.h>
+
+#include "util.h"
+#include "libds-tizen/memory_flusher.h"
+
+#define TIZEN_MEMORY_FLUSHER_VERSION 2
+
+struct ds_tizen_memory_flusher
+{
+ struct wl_global *global;
+
+ struct wl_list clients;
+
+ struct wl_listener destroy;
+
+ struct {
+ struct wl_signal destroy;
+ struct wl_signal get_flusher;
+ } events;
+};
+
+struct ds_tizen_memory_flusher_client
+{
+ struct ds_tizen_memory_flusher *memory_flusher;
+
+ struct wl_resource *resource;
+ struct wl_client *wl_client;
+
+ struct wl_list infos;
+
+ struct {
+ struct wl_signal destroy;
+ } events;
+
+ struct wl_list link; // ds_tizen_memory_flusher::clients
+};
+
+struct ds_tizen_memory_flusher_info
+{
+ struct ds_tizen_memory_flusher_client *client;
+
+ struct wl_resource *resource;
+
+ struct ds_surface *surface;
+
+ struct wl_list link; // ds_tizen_memory_flusher_client::infos
+};
+
+static void memory_flusher_handle_display_destroy(struct wl_listener *listener,
+ void *data);
+
+static void memory_flusher_bind(struct wl_client *wl_client, void *data,
+ uint32_t version, uint32_t id);
+
+static struct ds_tizen_memory_flusher_info *tizen_memory_flusher_client_find_info(
+ struct ds_tizen_memory_flusher_client *client,
+ struct ds_surface *surface);
+
+static struct ds_tizen_memory_flusher_info *tizen_memory_flusher_client_get_info(
+ struct ds_tizen_memory_flusher_client *client,
+ struct ds_surface *surface);
+
+WL_EXPORT struct ds_tizen_memory_flusher *
+ds_tizen_memory_flusher_create(struct wl_display *display)
+{
+ struct ds_tizen_memory_flusher *memory_flusher;
+
+ memory_flusher = calloc(1, sizeof *memory_flusher);
+ if (!memory_flusher) {
+ ds_err("calloc() failed.");
+ return NULL;
+ }
+
+ memory_flusher->global = wl_global_create(display, &tizen_surface_shm_interface,
+ TIZEN_MEMORY_FLUSHER_VERSION, memory_flusher, memory_flusher_bind);
+ if (!memory_flusher->global) {
+ ds_err("wl_global_create() failed. tizen_surface_shm_interface");
+ free(memory_flusher);
+ return NULL;
+ }
+
+ wl_list_init(&memory_flusher->clients);
+
+ memory_flusher->destroy.notify = memory_flusher_handle_display_destroy;
+ wl_display_add_destroy_listener(display, &memory_flusher->destroy);
+
+ wl_signal_init(&memory_flusher->events.destroy);
+ wl_signal_init(&memory_flusher->events.get_flusher);
+
+ ds_inf("Global created: tizen_memory_flusher(%p)", memory_flusher);
+
+ return memory_flusher;
+}
+
+WL_EXPORT void
+ds_tizen_memory_flusher_add_destroy_listener(
+ struct ds_tizen_memory_flusher *memory_flusher,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&memory_flusher->events.destroy, listener);
+}
+
+WL_EXPORT void
+ds_tizen_memory_flusher_add_get_flusher_info_listener(
+ struct ds_tizen_memory_flusher *memory_flusher,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&memory_flusher->events.get_flusher, listener);
+}
+
+WL_EXPORT void
+ds_tizen_memory_flusher_info_add_destroy_listener(
+ struct ds_tizen_memory_flusher_info *info,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&info->client->events.destroy, listener);
+}
+
+WL_EXPORT struct ds_surface *
+ds_tizen_memory_flusher_info_get_surface(
+ struct ds_tizen_memory_flusher_info *info)
+{
+ return info->surface;
+}
+
+WL_EXPORT void
+ds_tizen_memory_flusher_info_send_flush(
+ struct ds_tizen_memory_flusher_info *info)
+{
+ tizen_surface_shm_flusher_send_flush(info->resource);
+}
+
+WL_EXPORT void
+ds_tizen_memory_flusher_info_send_free_flush(
+ struct ds_tizen_memory_flusher_info *info)
+{
+ tizen_surface_shm_flusher_send_free_flush(info->resource);
+}
+
+static struct ds_tizen_memory_flusher_info *
+tizen_memory_flusher_client_find_info(struct ds_tizen_memory_flusher_client *client,
+ struct ds_surface *surface)
+{
+ struct ds_tizen_memory_flusher_info *info;
+
+ wl_list_for_each(info, &client->infos, link) {
+ if (surface == info->surface)
+ return info;
+ }
+
+ return NULL;
+}
+
+static struct ds_tizen_memory_flusher_info *
+tizen_memory_flusher_client_get_info(struct ds_tizen_memory_flusher_client *client,
+ struct ds_surface *surface)
+{
+ struct ds_tizen_memory_flusher_info *info;
+
+ info = tizen_memory_flusher_client_find_info(client, surface);
+ if (info)
+ return info;
+
+ info = calloc(1, sizeof *info);
+ if (info == NULL) {
+ ds_err("calloc() failed. tizen_memory_flusher");
+ return NULL;
+ }
+
+ info->client = client;
+ info->surface = surface;
+
+ wl_list_insert(&client->infos, &info->link);
+
+ return info;
+}
+
+static void
+memory_flusher_handle_display_destroy(struct wl_listener *listener, void *data)
+{
+ struct ds_tizen_memory_flusher *memory_flusher;
+
+ memory_flusher = wl_container_of(listener, memory_flusher, destroy);
+
+ ds_inf("Global destroy: memory_flusher(%p)", memory_flusher);
+
+ wl_signal_emit(&memory_flusher->events.destroy, memory_flusher);
+ wl_list_remove(&memory_flusher->destroy.link);
+ wl_global_destroy(memory_flusher->global);
+ free(memory_flusher);
+}
+
+static void
+flusher_handle_destroy(struct wl_client *wl_client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static const struct tizen_surface_shm_flusher_interface flusher_impl =
+{
+ flusher_handle_destroy,
+};
+
+static void
+_tizen_memory_flusher_info_handle_destroy(struct wl_resource *resource)
+{
+ struct ds_tizen_memory_flusher_info *info;
+
+ info = wl_resource_get_user_data(resource);
+
+ ds_inf("_tizen_memory_flusher_info_handle_destroy (info:%p)", info);
+
+ wl_signal_emit(&info->client->events.destroy, info);
+ wl_list_remove(&info->link);
+ free(info);
+}
+
+static void
+memory_flusher_handle_get_flusher(struct wl_client *wl_client,
+ struct wl_resource *resource,uint32_t id,
+ struct wl_resource *surface_resource)
+{
+ struct ds_tizen_memory_flusher_client *client;
+ struct ds_tizen_memory_flusher_info *info;
+ struct ds_surface *surface;
+
+ ds_inf("tizen_memory_flusher: get_flusher");
+
+ client = wl_resource_get_user_data(resource);
+ surface = ds_surface_from_resource(surface_resource);
+
+ info = tizen_memory_flusher_client_get_info(client, surface);
+ if (info == NULL) {
+ ds_err("tizen_memory_flusher_client_get_info() failed.");
+ wl_client_post_no_memory(wl_client);
+ return;
+ }
+
+ info->resource = wl_resource_create(wl_client,
+ &tizen_surface_shm_flusher_interface, wl_resource_get_version(resource),
+ id);
+ if (info->resource == NULL) {
+ ds_err("tizen_memory_flusher : wl_resource_create() failed.");
+ wl_list_remove(&info->link);
+ free(info);
+ wl_client_post_no_memory(wl_client);
+ return;
+ }
+
+ wl_resource_set_implementation(info->resource, &flusher_impl, info,
+ _tizen_memory_flusher_info_handle_destroy);
+
+ wl_signal_emit(&client->memory_flusher->events.get_flusher, info);
+}
+
+static void
+memory_flusher_handle_destroy(struct wl_client *wl_client,
+ struct wl_resource *resource)
+{
+ struct ds_tizen_memory_flusher_client *client;
+
+ client = wl_resource_get_user_data(resource);
+
+ if (!wl_list_empty(&client->infos)) {
+ ds_err("tizen_memory_flusher was destroyed before children");
+ return;
+ }
+
+ wl_resource_destroy(resource);
+}
+
+static const struct tizen_surface_shm_interface memory_flusher_impl =
+{
+ memory_flusher_handle_get_flusher,
+ memory_flusher_handle_destroy,
+};
+
+static void
+_tizen_memory_flusher_client_handle_destroy(struct wl_resource *resource)
+{
+ struct ds_tizen_memory_flusher_client *client;
+ struct ds_tizen_memory_flusher_info *info, *tmp;
+
+ client = wl_resource_get_user_data(resource);
+
+ ds_inf("_tizen_memory_flusher_client_handle_destroy (client:%p)", client);
+
+ wl_list_for_each_safe(info, tmp, &client->infos, link) {
+ wl_signal_emit(&client->events.destroy, info);
+ wl_list_remove(&info->link);
+ free(info);
+ }
+
+ wl_list_remove(&client->link);
+ free(client);
+}
+
+static void
+memory_flusher_bind(struct wl_client *wl_client, void *data, uint32_t version,
+ uint32_t id)
+{
+ struct ds_tizen_memory_flusher *memory_flusher = data;
+ struct ds_tizen_memory_flusher_client *client;
+
+ client = calloc(1, sizeof *client);
+ if (client == NULL) {
+ ds_err("calloc() failed. tizen_memory_flusher");
+ wl_client_post_no_memory(wl_client);
+ return;
+ }
+
+ ds_inf("tizen_memory_flusher_client binds. (client:%p)", client);
+
+ client->memory_flusher = memory_flusher;
+ client->wl_client = wl_client;
+
+ wl_list_init(&client->infos);
+
+ client->resource = wl_resource_create(wl_client, &tizen_surface_shm_interface,
+ MIN(version, TIZEN_MEMORY_FLUSHER_VERSION), id);
+
+ if (client->resource == NULL) {
+ ds_err("tizen_memory_flusher : wl_resource_create() failed.");
+ free(client);
+ wl_client_post_no_memory(wl_client);
+ return;
+ }
+
+ wl_resource_set_implementation(client->resource, &memory_flusher_impl, client,
+ _tizen_memory_flusher_client_handle_destroy);
+
+ wl_signal_init(&client->events.destroy);
+
+ wl_list_insert(&memory_flusher->clients, &client->link);
+}