--- /dev/null
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <wayland-server.h>
+#include <wtz-screen-server-protocol.h>
+#include <libds/log.h>
+
+#include "util.h"
+#include "libds-tizen/screen.h"
+
+#define TIZEN_SCREEN_VERSION 1
+
+struct ds_tizen_screen
+{
+ struct wl_global *global;
+
+ struct wl_list clients;
+
+ struct wl_listener destroy;
+
+ struct wl_array capabilities;
+
+ uint32_t splitscreen_capability;
+
+ bool splitscreen_enabled;
+
+ struct {
+ struct wl_signal destroy;
+ struct wl_signal get_splitscreen;
+ } events;
+};
+
+struct ds_tizen_screen_client
+{
+ struct ds_tizen_screen *screen;
+
+ struct wl_resource *resource;
+ struct wl_client *client;
+
+ struct {
+ struct wl_signal destroy;
+ } events;
+
+ struct wl_list link; // ds_tizen_screen::clients
+};
+
+struct ds_tizen_splitscreen
+{
+ struct wl_resource *resource;
+
+ struct ds_tizen_screen_client *screen_client;
+ struct ds_tizen_screen *screen;
+
+ struct {
+ struct wl_signal destroy;
+ struct wl_signal activate;
+ struct wl_signal deactivate;
+ } events;
+};
+
+struct ds_tizen_splitscreen_region
+{
+ struct wl_resource *resource;
+
+ const char *appid;
+
+ struct {
+ struct wl_signal destroy;
+ struct wl_signal assign_appid;
+ } events;
+};
+
+static void
+splitscreen_handle_destroy(struct wl_client *client,
+ struct wl_resource *splitscreen_resource)
+{
+ wl_resource_destroy(splitscreen_resource);
+}
+
+static void
+splitscreen_handle_activate(struct wl_client *client,
+ struct wl_resource *splitscreen_resource)
+{
+ struct ds_tizen_splitscreen *splitscreen;
+
+ splitscreen = wl_resource_get_user_data(splitscreen_resource);
+
+ ds_inf("screen_splitscreen:%p activate", splitscreen);
+
+ wl_signal_emit_mutable(&splitscreen->events.activate, splitscreen);
+}
+
+static void
+splitscreen_handle_deactivate(struct wl_client *client,
+ struct wl_resource *splitscreen_resource)
+{
+ struct ds_tizen_splitscreen *splitscreen;
+
+ splitscreen = wl_resource_get_user_data(splitscreen_resource);
+
+ ds_inf("screen_splitscreen:%p deactivate", splitscreen);
+
+ wl_signal_emit_mutable(&splitscreen->events.deactivate, splitscreen);
+}
+
+static const struct wtz_splitscreen_interface splitscreen_impl =
+{
+ .destroy = splitscreen_handle_destroy,
+ .activate = splitscreen_handle_activate,
+ .deactivate = splitscreen_handle_deactivate,
+};
+
+static void
+_tizen_screen_splitscreen_handle_resource_destroy(struct wl_resource *splitscreen_resource)
+{
+ struct ds_tizen_splitscreen *splitscreen;
+ struct ds_tizen_screen *screen;
+
+ splitscreen = wl_resource_get_user_data(splitscreen_resource);
+
+ ds_inf("screen_splitscreen:%p destroy", splitscreen);
+
+ wl_signal_emit_mutable(&splitscreen->events.destroy, splitscreen);
+
+ screen = splitscreen->screen;
+ screen->splitscreen_enabled = false; // unset splitscreen resource on a screen
+
+ free(splitscreen);
+}
+
+static void
+screen_handle_get_splitscreen(struct wl_client *client,
+ struct wl_resource *screen_client_resource,
+ uint32_t id)
+{
+ struct ds_tizen_screen_client *screen_client;
+ struct ds_tizen_splitscreen *splitscreen;
+ struct ds_tizen_screen *screen;
+
+ screen_client = wl_resource_get_user_data(screen_client_resource);
+
+ screen = screen_client->screen;
+
+ if (!screen->splitscreen_capability) {
+ wl_resource_post_error(screen_client_resource, WTZ_SCREEN_ERROR_NOT_SUPPORTED,
+ "Not Supported");
+ return;
+ }
+
+ // check splitscreen resource on a screen
+ // splitscreen resource is only one per a screen.
+ if (screen->splitscreen_enabled) {
+ wl_resource_post_error(screen_client_resource, WTZ_SCREEN_ERROR_INVALID_PARAMETER,
+ "Already Occupied");
+ return;
+ }
+
+ splitscreen = calloc(1, sizeof *splitscreen);
+ if (!splitscreen) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ splitscreen->resource = wl_resource_create(client, &wtz_splitscreen_interface,
+ wl_resource_get_version(screen_client_resource), id);
+ if (!splitscreen->resource) {
+ wl_client_post_no_memory(client);
+ free(splitscreen);
+ return;
+ }
+
+ splitscreen->screen_client = screen_client;
+ splitscreen->screen = screen;
+
+ wl_resource_set_implementation(splitscreen->resource, &splitscreen_impl,
+ splitscreen, _tizen_screen_splitscreen_handle_resource_destroy);
+
+ ds_inf("screen_splitscreen:%p create", splitscreen);
+
+ wl_signal_init(&splitscreen->events.destroy);
+ wl_signal_init(&splitscreen->events.activate);
+ wl_signal_init(&splitscreen->events.deactivate);
+
+ screen->splitscreen_enabled = true; // set splitscreen resource on a screen
+
+ wl_signal_emit_mutable(&screen_client->screen->events.get_splitscreen, splitscreen);
+}
+
+static void
+screen_handle_destroy(struct wl_client *wl_client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static const struct wtz_screen_interface screen_impl =
+{
+ .destroy = screen_handle_destroy,
+ .get_splitscreen = screen_handle_get_splitscreen,
+};
+
+static void
+_tizen_screen_client_handle_resource_destroy(struct wl_resource *resource)
+{
+ struct ds_tizen_screen_client *client;
+
+ client = wl_resource_get_user_data(resource);
+
+ ds_inf("_tizen_screen_client_handle_destroy (client:%p)", client);
+
+ wl_list_remove(&client->link);
+ free(client);
+}
+
+static void
+screen_bind(struct wl_client *wl_client, void *data, uint32_t version,
+ uint32_t id)
+{
+ struct ds_tizen_screen *screen = data;
+ struct ds_tizen_screen_client *screen_client;
+
+ screen_client = calloc(1, sizeof *screen_client);
+ if (screen_client == NULL) {
+ ds_err("calloc() failed. tizen_screen");
+ wl_client_post_no_memory(wl_client);
+ return;
+ }
+
+ ds_inf("tizen_screen_client binds. (screen_client:%p)", screen_client);
+
+ screen_client->screen = screen;
+ screen_client->client = wl_client;
+
+ screen_client->resource = wl_resource_create(wl_client, &wtz_screen_interface,
+ MIN(version, TIZEN_SCREEN_VERSION), id);
+ if (screen_client->resource == NULL) {
+ ds_err("tizen_screen : wl_resource_create() failed.");
+ free(screen_client);
+ wl_client_post_no_memory(wl_client);
+ return;
+ }
+
+ wl_resource_set_implementation(screen_client->resource, &screen_impl, screen_client,
+ _tizen_screen_client_handle_resource_destroy);
+
+ // send the capabilities of the screen
+ wtz_screen_send_capabilities(screen_client->resource, &screen->capabilities);
+
+ wl_signal_init(&screen_client->events.destroy);
+
+ wl_list_insert(&screen->clients, &screen_client->link);
+}
+
+static void
+screen_handle_display_destroy(struct wl_listener *listener, void *data)
+{
+ struct ds_tizen_screen *screen;
+
+ screen = wl_container_of(listener, screen, destroy);
+
+ ds_inf("Global destroy: screen(%p)", screen);
+
+ wl_signal_emit_mutable(&screen->events.destroy, screen);
+ wl_list_remove(&screen->destroy.link);
+ wl_global_destroy(screen->global);
+ free(screen);
+}
+
+WL_EXPORT struct ds_tizen_screen *
+ds_tizen_screen_create(struct wl_display *display)
+{
+ struct ds_tizen_screen *screen;
+
+ screen = calloc(1, sizeof *screen);
+ if (!screen) {
+ ds_err("calloc() failed.");
+ return NULL;
+ }
+
+ screen->global = wl_global_create(display, &wtz_screen_interface,
+ TIZEN_SCREEN_VERSION, screen, screen_bind);
+ if (!screen->global) {
+ ds_err("wl_global_create() failed. wtz_screen_interface");
+ free(screen);
+ return NULL;
+ }
+
+ wl_list_init(&screen->clients);
+
+ screen->destroy.notify = screen_handle_display_destroy;
+ wl_display_add_destroy_listener(display, &screen->destroy);
+
+ wl_array_init(&screen->capabilities);
+
+ wl_signal_init(&screen->events.destroy);
+ wl_signal_init(&screen->events.get_splitscreen);
+
+ ds_inf("Global created: tizen_screen(%p)", screen);
+
+ return screen;
+}
+
+static void
+_screen_capability_add(struct wl_array *capabilities, uint32_t cap)
+{
+ uint32_t *c;
+
+ c = wl_array_add(capabilities, sizeof(*c));
+ if (c)
+ *c = cap;
+ else
+ ds_err("wl_array_add() failed");
+}
+
+WL_EXPORT void
+ds_tizen_screen_add_capability(
+ struct ds_tizen_screen *screen,
+ enum ds_tizen_screen_capability cap)
+{
+ uint32_t capability;
+
+ ds_inf("screen:%p add capability(%d)", screen, cap);
+
+ if (cap == DS_TIZEN_SCREEN_CAPABILITY_SPLITSCREEN) {
+ capability = WTZ_SCREEN_CAPABILITY_SPLITSCREEN;
+ screen->splitscreen_capability = 1;
+ } else
+ capability = WTZ_SCREEN_CAPABILITY_NONE;
+
+ _screen_capability_add(&screen->capabilities, capability);
+}
+
+WL_EXPORT void
+ds_tizen_screen_add_destroy_listener(
+ struct ds_tizen_screen *screen,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&screen->events.destroy, listener);
+}
+
+WL_EXPORT void
+ds_tizen_screen_add_get_splitscreen_listener(
+ struct ds_tizen_screen *screen,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&screen->events.get_splitscreen, listener);
+}
+
+WL_EXPORT void
+ds_tizen_splitscreen_add_destroy_listener(
+ struct ds_tizen_splitscreen *splitscreen,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&splitscreen->events.destroy, listener);
+}
+
+WL_EXPORT void
+ds_tizen_splitscreen_add_activate_listener(
+ struct ds_tizen_splitscreen *splitscreen,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&splitscreen->events.activate, listener);
+}
+
+WL_EXPORT void
+ds_tizen_splitscreen_add_deactivate_listener(
+ struct ds_tizen_splitscreen *splitscreen,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&splitscreen->events.deactivate, listener);
+}
+
+static void
+splitscreen_region_handle_destroy(struct wl_client *client,
+ struct wl_resource *splitscreen_region_resource)
+{
+ wl_resource_destroy(splitscreen_region_resource);
+}
+
+static void
+splitscreen_region_handle_assign_appid(struct wl_client *client,
+ struct wl_resource *splitscreen_region_resource, const char *appid)
+{
+ struct ds_tizen_splitscreen_region *splitscreen_region;
+
+ splitscreen_region = wl_resource_get_user_data(splitscreen_region_resource);
+
+ ds_inf("screen_splitscreen_region:%p assign_appid", splitscreen_region);
+
+ splitscreen_region->appid = appid;
+
+ wl_signal_emit_mutable(&splitscreen_region->events.assign_appid, (void *)appid);
+}
+
+static const struct wtz_splitscreen_region_interface splitscreen_region_impl =
+{
+ .destroy = splitscreen_region_handle_destroy,
+ .assign_appid = splitscreen_region_handle_assign_appid,
+};
+
+static void
+_tizen_screen_splitscreen_region_handle_resource_destroy(
+ struct wl_resource *splitscreen_region_resource)
+{
+ struct ds_tizen_splitscreen_region *splitscreen_region;
+
+ splitscreen_region = wl_resource_get_user_data(splitscreen_region_resource);
+
+ ds_inf("screen_splitscreen_region:%p destroy", splitscreen_region);
+
+ wl_signal_emit_mutable(&splitscreen_region->events.destroy,
+ splitscreen_region);
+
+ free(splitscreen_region);
+}
+
+WL_EXPORT struct ds_tizen_splitscreen_region *
+ds_tizen_splitscreen_region_create(
+ struct ds_tizen_splitscreen *splitscreen,
+ const char *name, int32_t x, int32_t y, uint32_t w, uint32_t h)
+{
+ struct ds_tizen_splitscreen_region *splitscreen_region;
+ struct ds_tizen_screen_client *screen_client;
+
+ splitscreen_region = calloc(1, sizeof *splitscreen_region);
+ if (!splitscreen_region) {
+ ds_err("calloc() failed.");
+ return NULL;
+ }
+
+ screen_client = splitscreen->screen_client;
+
+ splitscreen_region->resource = wl_resource_create(screen_client->client,
+ &wtz_splitscreen_region_interface,
+ TIZEN_SCREEN_VERSION, 0);
+ if (!splitscreen_region->resource) {
+ ds_err("wl_resource_create() failed. wtz_splitscreen_region_interface");
+ free(splitscreen_region);
+ return NULL;
+ }
+
+ wl_resource_set_implementation(splitscreen_region->resource,
+ &splitscreen_region_impl, splitscreen_region,
+ _tizen_screen_splitscreen_region_handle_resource_destroy);
+
+ // send the splitscreen_region resources
+ wtz_splitscreen_send_region(splitscreen->resource, splitscreen_region->resource);
+
+ // send the name of the split_screen_region
+ wtz_splitscreen_region_send_name(splitscreen_region->resource, name);
+
+ // send the geometry of the split_screen_region
+ wtz_splitscreen_region_send_geometry(
+ splitscreen_region->resource, x, y, w, h);
+
+ return splitscreen_region;
+}
+
+WL_EXPORT void
+ds_tizen_splitscreen_region_add_destroy_listener(
+ struct ds_tizen_splitscreen_region *splitscreen_region,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&splitscreen_region->events.destroy, listener);
+}
+
+WL_EXPORT void
+ds_tizen_splitscreen_region_add_assign_appid_listener(
+ struct ds_tizen_splitscreen_region *splitscreen_region,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&splitscreen_region->events.assign_appid, listener);
+}
\ No newline at end of file