-#include <assert.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <time.h>
-
-#include <drm_fourcc.h>
-#include <pixman.h>
-#include <wayland-server.h>
-#include <libds/log.h>
-#include <libds/backend.h>
-#include <libds/output.h>
-#include <libds/compositor.h>
-#include <libds/xdg_shell.h>
-#include <libds-tizen/allocator/tbm.h>
-#include <libds-tizen/backend/tdm.h>
-#include <libds-tizen/tbm_server.h>
-
-#define USE_TDM_BUFFER_QUEUE
-
-#ifdef USE_TDM_BUFFER_QUEUE
-#include "pixman-tbm-helper.h"
-#include "tinyds-tdm-renderer.h"
-#else
-#include <libds/swapchain.h>
-#endif
-
-#include "pixman-helper.h"
-
-#define TINYDS_UNUSED __attribute__((unused))
+#include "tinyds-tdm.h"
struct tinyds_output
{
int width, height;
- bool drawable;
+ struct wl_event_source *idle_commit;
+ bool committable;
bool damaged;
+ bool target_updated;
+
+ struct ds_tdm_output_hwc *hwc;
+ struct ds_tdm_output_hwc_window *bg_hwc_window;
+
+#ifdef USE_CURSOR
+ bool cursor_enabled;
+ struct ds_tdm_output_hwc_window *cursor_hwc_window;
+#endif
};
-struct tinyds_server
+struct tinyds_pointer
{
- struct ds_tbm_server *tbm_server;
-
- struct wl_display *display;
+ struct ds_input_device *dev;
+ struct tinyds_server *server;
- struct ds_backend *backend;
- struct ds_compositor *compositor;
- struct ds_xdg_shell *xdg_shell;
+ struct tinyds_view *focused_view;
- struct tinyds_output *output;
- struct wl_event_source *stdin_source;
+ struct wl_listener destroy;
+ struct wl_listener motion; //relative
+ struct wl_listener button;
+ struct wl_listener frame;
+ struct wl_list link; //tinyds_server::pointers
+};
- struct wl_list views;
+struct tinyds_keyboard
+{
+ struct ds_input_device *dev;
+ struct tinyds_server *server;
- struct wl_listener new_output;
- struct wl_listener new_xdg_surface;
+ struct wl_listener destroy;
+ struct wl_listener key;
+ struct wl_list link; //tinyds_server::keyboards
};
-struct tinyds_view
+struct tinyds_touch
{
+ struct ds_input_device *dev;
struct tinyds_server *server;
- struct tinyds_texture *texture;
- struct ds_xdg_surface *xdg_surface;
+ struct wl_listener destroy;
+ struct wl_listener down;
+ struct wl_listener up;
+ struct wl_listener motion;
+};
+
+struct tinyds_text_input {
+ struct ds_tizen_text_input *input;
+ struct ds_tizen_text_input_manager *text_input_mgr;
+
+ struct tinyds_server *server;
+ struct ds_surface *surface;
+
+ struct wl_list input_methods;
+
+ struct wl_listener mgr_destroy;
+ struct wl_listener new_text_input;
+
+ struct wl_listener destroy;
+ struct wl_listener text_input_activate;
+ struct wl_listener text_input_deactivate;
+ struct wl_listener text_input_reset;
+ struct wl_listener text_input_set_content_type;
+ struct wl_listener text_input_invoke_action;
+ struct wl_listener text_input_commit_state;
+ struct wl_listener text_input_set_preferred_language;
+};
+
+struct tinyds_input_method {
+ struct ds_tizen_input_method *input_method;
+ struct ds_tizen_input_method_manager *input_method_mgr;
+
+ struct tinyds_server *server;
+ struct tinyds_text_input *input;
+ struct tinyds_input_method_context *context;
- struct wl_listener xdg_surface_map;
- struct wl_listener xdg_surface_unmap;
- struct wl_listener xdg_surface_destroy;
- struct wl_listener surface_commit;
- struct wl_list link; // tinyds_server::views
+ struct wl_list link;
- int x, y;
- bool mapped;
+ struct wl_listener destroy;
+ struct wl_listener mgr_destroy;
+};
+
+struct tinyds_input_method_context {
+ struct ds_tizen_input_method_context *context;
+
+ struct tinyds_server *server;
+ struct tinyds_text_input *input;
+ struct tinyds_input_method *input_method;
+
+ struct wl_listener destroy;
+
+ struct wl_listener im_context_commit_string;
+ struct wl_listener im_context_preedit_string;
+ struct wl_listener im_context_preedit_styling;
+ struct wl_listener im_context_preedit_cursor;
+ struct wl_listener im_context_delete_surrounding_text;
+ struct wl_listener im_context_cursor_position;
+ struct wl_listener im_context_modifiers_map;
+ struct wl_listener im_context_keysym;
+ struct wl_listener im_context_grab_keyboard;
+ struct wl_listener im_context_key;
+ struct wl_listener im_context_modifiers;
+ struct wl_listener im_context_language;
+ struct wl_listener im_context_text_direction;
};
struct tinyds_server tinyds;
static void output_swap_buffer(struct tinyds_output *output,
struct ds_buffer *buffer);
static void view_send_frame_done(struct tinyds_view *view);
+static void output_hwc_init(struct tinyds_output *output);
+static void output_schedule_commit(struct tinyds_output *output);
+static void output_commit(struct tinyds_output *output);
#ifdef USE_TDM_BUFFER_QUEUE
static void output_buffer_queue_init(struct tinyds_output *output);
static void output_renderer_init(struct tinyds_output *output);
static void output_draw_with_swapchain(struct tinyds_output *output);
static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image);
#endif
+static void server_add_keyboard(struct tinyds_server *server,
+ struct ds_input_device *dev);
+static void server_add_pointer(struct tinyds_server *server,
+ struct ds_input_device *dev);
+static void server_add_touch(struct tinyds_server *server,
+ struct ds_input_device *dev);
+static bool add_new_text_input(struct tinyds_server *server);
+static bool add_new_input_method(struct tinyds_server *server);
+static bool add_new_input_method_context(
+ struct tinyds_input_method *input_method,
+ struct tinyds_text_input *text_input);
+
+static void text_input_mgr_handle_destroy(struct wl_listener *listener,
+ void *data TINYDS_UNUSED);
+static void text_input_mgr_handle_new_text_input(struct wl_listener *listener,
+ void *data TINYDS_UNUSED);
+
+static void input_method_mgr_handle_destroy(struct wl_listener *listener,
+ void *data TINYDS_UNUSED);
+
+static void input_method_handle_destroy(struct wl_listener *listener,
+ void *data TINYDS_UNUSED);
int
main(void)
assert(socket);
ds_backend_start(server->backend);
+ ds_backend_start(server->input_backend);
setenv("WAYLAND_DISPLAY", socket, true);
wl_display_run(display);
+ protocol_trace_enable(false);
+ protocol_trace_fini();
+
wl_display_destroy_clients(display);
wl_display_destroy(display);
}
static void
+view_populate_pid(struct tinyds_view *view)
+{
+ struct ds_surface *surface;
+ struct wl_client *client = NULL;
+ pid_t pid;
+
+ surface = ds_xdg_surface_get_surface(view->xdg_surface);
+ if (!surface)
+ return;
+
+ client = wl_resource_get_client(ds_surface_get_wl_resource(surface));
+ if (!client)
+ return;
+
+ wl_client_get_credentials(client, &pid, NULL, NULL);
+ view->pid = pid;
+
+ ds_inf("view pid(%u)", pid);
+
+ view->effect_type = tinyds_launch_get_effect_type(
+ view->server->launch, pid);
+ tinyds_launch_unset_effect_type(view->server->launch, 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)
{
struct tinyds_view *view;
+ struct ds_keyboard *keyboard;
+ struct tinyds_keyboard *kbd;
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) {
+ ds_seat_keyboard_notify_enter(view->server->seat,
+ ds_xdg_surface_get_surface(view->xdg_surface),
+ keyboard->keycodes, keyboard->num_keycodes,
+ &keyboard->modifiers);
+ return;
+ }
+ }
}
static void
void *data TINYDS_UNUSED)
{
struct tinyds_view *view;
- struct tinyds_server *server;
view = wl_container_of(listener, view, xdg_surface_destroy);
- server = view->server;
+
+ draw_server_with_damage(view->server);
+
+ ds_tdm_output_hwc_window_destroy(view->hwc_window);
wl_list_remove(&view->xdg_surface_destroy.link);
wl_list_remove(&view->xdg_surface_map.link);
wl_list_remove(&view->surface_commit.link);
wl_list_remove(&view->link);
free(view);
-
- draw_server_with_damage(server);
}
static void
static void
server_new_xdg_surface(struct wl_listener *listener, void *data)
{
+ static unsigned int seedx = 1;
+ static unsigned int seedy = 43210;
struct tinyds_server *server;
struct tinyds_view *view;
struct ds_xdg_surface *xdg_surface;
ds_xdg_surface_get_surface(xdg_surface),
&view->surface_commit);
+ view->x = rand_r(&seedx) % 1000;
+ view->y = rand_r(&seedy) % 500;
+
+ view->hwc_window = ds_tdm_output_hwc_window_create(server->output->hwc);
+ assert(view->hwc_window);
+
wl_list_insert(server->views.prev, &view->link);
- 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);
}
static void
struct tinyds_output *output;
struct ds_output *ds_output;
const struct ds_output_mode *mode;
+ struct ds_tdm_box src_box;
server = wl_container_of(listener, server, new_output);
ds_output = data;
output->ds_output = ds_output;
output->width = mode->width;
output->height = mode->height;
- output->drawable = true;
output->damaged = true;
+ output->committable = true;
+
+ output_hwc_init(output);
#ifdef USE_TDM_BUFFER_QUEUE
output_buffer_queue_init(output);
DRM_FORMAT_XRGB8888);
#endif
+ output->bg_hwc_window = ds_tdm_output_hwc_window_create(output->hwc);
+ assert(output->bg_hwc_window);
+
+ src_box.x = 0;
+ src_box.y = 0;
+ src_box.width = output->width;
+ src_box.height = output->height;
+
+ ds_tdm_output_hwc_window_set_src_box(output->bg_hwc_window, &src_box);
+ ds_tdm_output_hwc_window_set_position(output->bg_hwc_window, 0, 0);
+ ds_tdm_output_hwc_window_set_dest_size(output->bg_hwc_window, output->width, output->height);
+ ds_tdm_output_hwc_window_set_transform(output->bg_hwc_window, WL_OUTPUT_TRANSFORM_NORMAL);
+
+#ifdef USE_CURSOR
+ output->cursor_enabled = false;
+#endif
+
output->output_destroy.notify = output_handle_destroy;
ds_output_add_destroy_listener(ds_output, &output->output_destroy);
output->output_frame.notify = output_handle_frame;
ds_output_add_frame_listener(ds_output, &output->output_frame);
+ tinyds_input_devicemgr_set_output_size(server->input_devicemgr, (uint32_t)output->width, (uint32_t)output->height);
+
server->output = output;
+ server->output_x = (double)(output->width) / 2;
+ server->output_y = (double)(output->height) / 2;
+
+ output_schedule_commit(output);
+}
- draw_output(output);
+static void
+backend_handle_new_input(struct wl_listener *listener, void *data)
+{
+ struct tinyds_server *server;
+ struct ds_input_device *dev = data;
+ enum ds_input_device_type dev_type;
+
+ server = wl_container_of(listener, server, new_input);
+
+ dev_type = ds_input_device_get_type(dev);
+
+ switch (dev_type) {
+ case DS_INPUT_DEVICE_KEYBOARD:
+ server_add_keyboard(server, dev);
+ server->seat_caps |= WL_SEAT_CAPABILITY_KEYBOARD;
+ break;
+ case DS_INPUT_DEVICE_TOUCH:
+ server_add_touch(server, dev);
+ server->seat_caps |= WL_SEAT_CAPABILITY_TOUCH;
+ break;
+ case DS_INPUT_DEVICE_POINTER:
+ server_add_pointer(server, dev);
+ server->seat_caps |= WL_SEAT_CAPABILITY_POINTER;
+ break;
+ default:
+ ds_err("Unknown type(%d) of ds_input_device", dev_type);
+ break;
+ }
+
+ ds_seat_set_capabilities(server->seat, server->seat_caps);
+}
+
+static void
+dpms_free_func(void *data)
+{
+ struct tinyds_server *server = (struct tinyds_server *)data;
+
+ server->dpms = NULL;
+}
+
+static void
+policy_free_func(void *data)
+{
+ struct tinyds_server *server = (struct tinyds_server *)data;
+
+ server->policy = NULL;
+}
+
+static void
+launch_free_func(void *data)
+{
+ struct tinyds_server *server = (struct tinyds_server *)data;
+
+ server->launch = NULL;
+}
+
+static void
+input_devicemgr_free_func(void *data)
+{
+ struct tinyds_server *server = (struct tinyds_server *)data;
+
+ server->input_devicemgr = NULL;
}
static bool
if (!server->backend)
return false;
+ server->input_backend = ds_libinput_backend_create(display);
+ if (!server->input_backend) {
+ ds_backend_destroy(server->backend);
+ return false;
+ }
+
server->new_output.notify = backend_handle_new_output;
ds_backend_add_new_output_listener(server->backend,
&server->new_output);
+ wl_list_init(&server->keyboards);
+ wl_list_init(&server->pointers);
+ server->new_input.notify = backend_handle_new_input;
+ ds_backend_add_new_input_listener(server->input_backend, &server->new_input);
+
server->compositor = ds_compositor_create(display);
- if (!server->compositor) {
- ds_backend_destroy(server->backend);
- return false;
- }
+ if (!server->compositor)
+ goto err;
server->tbm_server = ds_tbm_server_create(display);
- if (!server->tbm_server) {
- ds_backend_destroy(server->backend);
- return false;
- }
+ if (!server->tbm_server)
+ goto err;
server->xdg_shell = ds_xdg_shell_create(display);
- if (!server->xdg_shell) {
- ds_backend_destroy(server->backend);
- return false;
- }
+ if (!server->xdg_shell)
+ goto err;
server->new_xdg_surface.notify = server_new_xdg_surface;
ds_xdg_shell_add_new_surface_listener(server->xdg_shell,
&server->new_xdg_surface);
+ server->dpms = tinyds_dpms_init(server->display, dpms_free_func, (void *)server);
+ if (!server->dpms)
+ goto err;
+
+ server->policy = tinyds_policy_init(server->display, policy_free_func, (void *)server);
+ if (!server->policy)
+ goto err;
+
+ server->launch = tinyds_launch_init(server->display, launch_free_func, (void *)server);
+ if (!server->launch)
+ goto err;
+
+ server->seat = ds_seat_create(display, "seat0" /* arbitrary name */);
+ if (!server->seat)
+ goto err;
+ server->seat_caps = 0;
+
+ server->input_devicemgr = tinyds_input_devicemgr_init(server->input_backend,
+ server->seat, input_devicemgr_free_func, (void *)server);
+ if (!server->input_devicemgr)
+ goto err;
+
+ if (!add_new_text_input(server))
+ goto err;
+
+ if (!add_new_input_method(server))
+ goto err;
+
+ if (protocol_trace_init(display))
+ protocol_trace_enable(true);
+
return true;
+
+err:
+ ds_backend_destroy(server->backend);
+ ds_backend_destroy(server->input_backend);
+
+ return false;
}
static void
struct tinyds_output *output =
wl_container_of(listener, output, output_destroy);
+ if (output->bg_hwc_window)
+ ds_tdm_output_hwc_window_destroy(output->bg_hwc_window);
+
wl_list_remove(&output->output_destroy.link);
wl_list_remove(&output->output_frame.link);
}
static void
+output_commit(struct tinyds_output *output)
+{
+ uint32_t num_changed = 0;
+ uint32_t num_windows = 0, current_num_windows = 0;
+ struct ds_tdm_output_hwc_window **composited_hwc_windows = NULL;
+ struct ds_tdm_output_hwc_window **changed_hwc_windows = NULL;
+ enum ds_tdm_output_hwc_window_composition composition;
+ struct tinyds_view *view;
+ size_t i;
+ bool need_target = false;
+ bool fully_obscured = false;
+ struct ds_buffer *ds_buffer;
+ struct ds_tdm_box src_box;
+ int w = 0, h = 0;
+
+ if (!output->committable)
+ return;
+
+ if (!output->damaged && !output->target_updated)
+ return;
+
+ wl_list_for_each_reverse(view, &output->server->views, link) {
+ if (!view->hwc_window)
+ continue;
+
+ ds_buffer = ds_surface_get_buffer(
+ ds_xdg_surface_get_surface(view->xdg_surface));
+ if (!ds_buffer)
+ continue;
+
+ if (!view->mapped)
+ continue;
+
+ num_windows++;
+
+ ds_buffer_get_size(ds_buffer, &w, &h);
+
+ if ((output->width <= w) && (output->height <= h))
+ fully_obscured = true;
+ }
+
+ if (fully_obscured) {
+ ds_tdm_output_hwc_window_set_composition(output->bg_hwc_window,
+ DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_NONE);
+ } else {
+ ds_tdm_output_hwc_window_set_composition(output->bg_hwc_window,
+ DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CLIENT);
+ num_windows++;
+ need_target = true;
+ }
+
+#ifdef USE_CURSOR
+ if (output->cursor_hwc_window) {
+ src_box.x = 0;
+ src_box.y = 0;
+ src_box.width = CURSOR_W;
+ src_box.height = CURSOR_H;
+
+ ds_tdm_output_hwc_window_set_src_box(output->cursor_hwc_window, &src_box);
+ ds_tdm_output_hwc_window_set_position(output->cursor_hwc_window, output->server->output_x, output->server->output_y);
+ ds_tdm_output_hwc_window_set_dest_size(output->cursor_hwc_window, CURSOR_W, CURSOR_H);
+ ds_tdm_output_hwc_window_set_transform(output->cursor_hwc_window, WL_OUTPUT_TRANSFORM_NORMAL);
+
+ ds_tdm_output_hwc_window_set_composition(output->cursor_hwc_window,
+ DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CLIENT);
+ num_windows++;
+ need_target = true;
+ }
+#endif
+
+ if (num_windows) {
+ composited_hwc_windows = calloc(num_windows, sizeof *composited_hwc_windows);
+ if (!composited_hwc_windows)
+ return;
+
+ wl_list_for_each_reverse(view, &output->server->views, link) {
+ if (!view->hwc_window)
+ continue;
+
+ ds_buffer = ds_surface_get_buffer(
+ ds_xdg_surface_get_surface(view->xdg_surface));
+ if (!ds_buffer)
+ continue;
+
+ ds_tdm_output_hwc_window_set_buffer(view->hwc_window, ds_buffer);
+
+ ds_buffer_get_size(ds_buffer, &w, &h);
+
+ src_box.x = 0;
+ src_box.y = 0;
+ src_box.width = w;
+ src_box.height = h;
+
+ ds_tdm_output_hwc_window_set_src_box(view->hwc_window, &src_box);
+ ds_tdm_output_hwc_window_set_position(view->hwc_window, view->x, view->y);
+ ds_tdm_output_hwc_window_set_dest_size(view->hwc_window, w, h);
+ ds_tdm_output_hwc_window_set_transform(view->hwc_window, WL_OUTPUT_TRANSFORM_NORMAL);
+
+ if (view->mapped) {
+#ifdef USE_CURSOR
+ ds_tdm_output_hwc_window_set_composition(view->hwc_window,
+ DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CLIENT);
+#endif
+ ds_tdm_output_hwc_window_set_composition(view->hwc_window,
+ DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_DEVICE);
+
+ composited_hwc_windows[current_num_windows] = view->hwc_window;
+ current_num_windows++;
+ } else {
+ ds_tdm_output_hwc_window_set_composition(view->hwc_window,
+ DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_NONE);
+ }
+ }
+
+ if (!fully_obscured) {
+ composited_hwc_windows[current_num_windows] = output->bg_hwc_window;
+ current_num_windows++;
+ }
+
+#ifdef USE_CURSOR
+ if (output->cursor_hwc_window) {
+ composited_hwc_windows[current_num_windows] = output->cursor_hwc_window;
+ current_num_windows++;
+ }
+#endif
+ }
+
+ if (!ds_tdm_output_hwc_validate(output->hwc, composited_hwc_windows,
+ num_windows, &num_changed)) {
+ free(composited_hwc_windows);
+ ds_err("Could not hwc validate");
+ return;
+ }
+
+ if (composited_hwc_windows)
+ free(composited_hwc_windows);
+
+ if (num_changed > 0) {
+ changed_hwc_windows = calloc(num_windows, sizeof *changed_hwc_windows);
+ if (!changed_hwc_windows)
+ return;
+
+ if (!ds_tdm_output_hwc_get_changed_composition(output->hwc, &num_changed,
+ changed_hwc_windows)) {
+ free(changed_hwc_windows);
+ ds_err("Could not get chaged composition");
+ return;
+ }
+
+ for (i = 0; i < (size_t)num_changed; i++) {
+ composition = ds_tdm_output_hwc_window_get_composition(changed_hwc_windows[i]);
+ if (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CLIENT) {
+ need_target = true;
+ break;
+ }
+ }
+ }
+
+ if (changed_hwc_windows)
+ free(changed_hwc_windows);
+
+ if (need_target && output->damaged)
+ draw_output(output);
+
+#ifdef USE_TDM_BUFFER_QUEUE
+ struct ds_buffer *buffer;
+
+ buffer = ds_tdm_buffer_queue_acquire(output->buffer_queue);
+ if (buffer) {
+ if (!ds_tdm_output_hwc_set_client_target_buffer(output->hwc, buffer)) {
+ ds_err("Could not set hwc client target buffer");
+ return;
+ }
+
+ output_swap_buffer(output, buffer);
+ }
+#endif
+
+ if (!ds_tdm_output_hwc_accept_validation(output->hwc)) {
+ ds_err("Could not hwc accept validateion");
+ return;
+ }
+
+ ds_output_commit(output->ds_output);
+
+ output->committable = false;
+ output->damaged = false;
+ output->target_updated = false;
+
+ wl_list_for_each(view, &output->server->views, link) {
+ if (!view->mapped)
+ continue;
+
+ composition = ds_tdm_output_hwc_window_get_composition(view->hwc_window);
+ if ((composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_DEVICE) ||
+ (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_VIDEO) ||
+ (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CURSOR))
+ view_send_frame_done(view);
+ }
+
+ ds_dbg("output:%p commit", output);
+}
+
+static void
output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED)
{
struct tinyds_output *output =
wl_container_of(listener, output, output_frame);
- output->drawable = true;
- draw_output(output);
+ ds_dbg("output:%p handle frame", output);
+
+ output->committable = true;
+
+ output_commit(output);
}
static void
draw_server_with_damage(struct tinyds_server *server)
{
server->output->damaged = true;
- draw_output(server->output);
+ output_schedule_commit(server->output);
+}
+
+static void
+output_hwc_init(struct tinyds_output *output)
+{
+ struct ds_tdm_output *tdm_output;
+
+ tdm_output = ds_tdm_output_from_output(output->ds_output);
+ assert(tdm_output);
+
+ output->hwc = ds_tdm_output_get_hwc(tdm_output);
+ assert(output->hwc);
+
+ ds_tdm_output_hwc_set_enabled(output->hwc, true);
}
#ifdef USE_TDM_BUFFER_QUEUE
void *data TINYDS_UNUSED)
{
struct tinyds_output *output;
- struct ds_buffer *buffer;
output = wl_container_of(listener, output, buffer_queue_acquirable);
- buffer = ds_tdm_buffer_queue_acquire(output->buffer_queue);
- assert(buffer);
-
- output_swap_buffer(output, buffer);
+ output->target_updated = true;
+ output_schedule_commit(output);
}
static void
struct ds_buffer *ds_buffer;
struct ds_tbm_client_buffer *tbm_buffer;
tbm_surface_h surface;
+ enum ds_tdm_output_hwc_window_composition composition;
if (!view->mapped)
continue;
+ composition = ds_tdm_output_hwc_window_get_composition(view->hwc_window);
+ if ((composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_DEVICE) ||
+ (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_VIDEO) ||
+ (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CURSOR))
+ continue;
+
ds_buffer = ds_surface_get_buffer(
ds_xdg_surface_get_surface(view->xdg_surface));
- assert(ds_buffer);
+ if (!ds_buffer)
+ continue;
tbm_buffer = ds_tbm_client_buffer_from_buffer(ds_buffer);
- assert(tbm_buffer);
+ if (!tbm_buffer)
+ continue;
surface = ds_tbm_client_buffer_get_tbm_surface(tbm_buffer);
+ if (!surface)
+ continue;
renderer_add_texture(&output->renderer, surface, view->x, view->y);
ds_dbg("<< END UPDATE TEXTURES");
renderer_draw(&output->renderer);
-
}
#else
static void
output_swapchain_init(struct tinyds_output *output,
- int width, int height, uint32_t format);
+ int width, int height, uint32_t format)
{
output->allocator = ds_tbm_allocator_create();
struct tinyds_view *view;
struct ds_buffer *output_buffer;
pixman_image_t *output_image;
+ enum ds_tdm_output_hwc_window_composition composition;
output_buffer = ds_swapchain_acquire(output->swapchain, NULL);
if (!output_buffer)
wl_list_for_each(view, &output->server->views, link) {
if (!view->mapped)
continue;
+
+ composition = ds_tdm_output_hwc_window_get_composition(view->hwc_window);
+ if ((composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_DEVICE) ||
+ (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_VIDEO) ||
+ (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CURSOR))
+ continue;
+
draw_view(view, output_image);
}
pixman_image_unref(output_image);
+ if (!ds_tdm_output_hwc_set_client_target_buffer(output->hwc, output_buffer)) {
+ ds_err("Could not set hwc client target buffer");
+ ds_buffer_unlock(output_buffer);
+ return;
+ }
+
output_swap_buffer(output, output_buffer);
}
static void
draw_output(struct tinyds_output *output)
{
-
- if (!output->drawable || !output->damaged)
- return;
-
#ifdef USE_TDM_BUFFER_QUEUE
output_draw_with_renderer(output);
#else
output_draw_with_swapchain(output);
#endif
- output->drawable = false;
- output->damaged = false;
+ ds_dbg("output:%p draw", output);
}
static void
output_swap_buffer(struct tinyds_output *output, struct ds_buffer *buffer)
{
ds_output_attach_buffer(output->ds_output, buffer);
- ds_output_commit(output->ds_output);
if (output->front_buffer)
ds_buffer_unlock(output->front_buffer);
return 1;
}
+
+static void
+keyboard_handle_device_destroy(struct wl_listener *listener, void *data)
+{
+ struct tinyds_keyboard *kbd;
+
+ kbd = wl_container_of(listener, kbd, destroy);
+
+ ds_inf("Keyboard(%p) destroyed", kbd);
+
+ wl_list_remove(&kbd->destroy.link);
+ wl_list_remove(&kbd->key.link);
+ wl_list_remove(&kbd->link);
+
+ free(kbd);
+}
+
+static bool
+server_handle_keybinding(struct tinyds_server *server, xkb_keysym_t sym)
+{
+ switch (sym) {
+ case XKB_KEY_BackSpace:
+ wl_display_terminate(server->display);
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+static void
+keyboard_handle_key(struct wl_listener *listener, void *data)
+{
+ struct tinyds_keyboard *kbd;
+ struct ds_keyboard_event_key *event = data;
+ struct ds_keyboard *ds_keyboard;
+ struct xkb_state *xkb_state;
+ const xkb_keysym_t *syms;
+ int nsyms;
+ bool handled = false;
+
+ kbd = wl_container_of(listener, kbd, key);
+
+ ds_inf("Keyboard(%p) event key: keycode(%d), state(%d), time_msec(%d), "
+ "update_state(%d)", kbd->dev,
+ event->keycode, event->state, event->time_msec,
+ event->update_state);
+
+ ds_keyboard = ds_input_device_get_keyboard(kbd->dev);
+
+ if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+ xkb_state = ds_keyboard_get_xkb_state(ds_keyboard);
+ if (xkb_state) {
+ nsyms = xkb_state_key_get_syms(xkb_state, event->keycode + 8,
+ &syms);
+ for (int i = 0; i < nsyms; i++) {
+ handled = server_handle_keybinding(kbd->server, syms[i]);
+ }
+ }
+ }
+
+ if (!handled) {
+ ds_seat_keyboard_notify_key(kbd->server->seat, event->time_msec,
+ event->keycode, event->state);
+ }
+}
+
+static void
+server_add_keyboard(struct tinyds_server *server, struct ds_input_device *dev)
+{
+ struct tinyds_keyboard *kbd;
+ struct xkb_context *context;
+ struct xkb_keymap *keymap;
+
+ kbd = calloc(1, sizeof *kbd);
+ assert(kbd);
+
+ kbd->dev = dev;
+ kbd->server = server;
+
+ context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+ if (!context)
+ goto err;
+
+ keymap = xkb_keymap_new_from_names(context, NULL,
+ XKB_KEYMAP_COMPILE_NO_FLAGS);
+
+ if (!keymap) {
+ ds_err("Failed to compile keymap");
+ xkb_context_unref(context);
+ goto err;
+ }
+
+ ds_keyboard_set_keymap(ds_input_device_get_keyboard(dev), keymap);
+
+ xkb_keymap_unref(keymap);
+ xkb_context_unref(context);
+
+ kbd->destroy.notify = keyboard_handle_device_destroy;
+ ds_input_device_add_destroy_listener(dev, &kbd->destroy);
+
+ kbd->key.notify = keyboard_handle_key;
+ ds_keyboard_add_key_listener(ds_input_device_get_keyboard(dev), &kbd->key);
+
+ wl_list_insert(&server->keyboards, &kbd->link);
+
+ ds_inf("Keyboard(%p) added", kbd);
+
+ return;
+
+err:
+ free(kbd);
+}
+
+struct tinyds_view *
+tinyds_server_view_at(struct tinyds_server *server, double lx, double ly,
+ double *sx, double *sy)
+{
+ struct tinyds_view *view;
+ struct ds_surface *surface;
+ struct ds_buffer *buffer;
+ int x, y, w = 0, h = 0;
+
+ wl_list_for_each(view, &server->views, link) {
+ surface = ds_xdg_surface_get_surface(view->xdg_surface);
+ buffer = ds_surface_get_buffer(surface);
+ ds_buffer_get_size(buffer, &w, &h);
+
+ x = view->x;
+ y = view->y;
+
+ if (lx >= x && lx <= x + w && ly >= y && ly <= y + h) {
+ *sx = lx - x;
+ *sy = ly - y;
+
+ return view;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+touch_handle_device_destroy(struct wl_listener *listener, void *data)
+{
+ struct tinyds_touch *touch;
+
+ touch = wl_container_of(listener, touch, destroy);
+
+ ds_inf("Touch(%p) destroyed", touch);
+
+ wl_list_remove(&touch->destroy.link);
+ wl_list_remove(&touch->down.link);
+ wl_list_remove(&touch->up.link);
+ wl_list_remove(&touch->motion.link);
+
+ free(touch);
+}
+
+static void
+touch_handle_down(struct wl_listener *listener, void *data)
+{
+ struct ds_touch_event_down *event = data;
+ struct tinyds_touch *touch;
+ struct tinyds_view *view;
+ struct tinyds_server *server;
+ double sx = 0.f, sy = 0.f;
+
+ touch = wl_container_of(listener, touch, down);
+
+ server = touch->server;
+ if (server->output) {
+ server->output_x = event->x * server->output->width;
+ server->output_y = event->y * server->output->height;
+ }
+
+ ds_inf("Touch(%p) event down: id(%d) x %.3f y %.3f output_x %.1f output_y %.1f",
+ touch->dev, event->id, event->x, event->y, server->output_x, server->output_y);
+
+ view = tinyds_server_view_at(server, server->output_x, server->output_y, &sx, &sy);
+
+ if (view) {
+ ds_seat_touch_notify_down(touch->server->seat, ds_xdg_surface_get_surface(view->xdg_surface),
+ event->time_msec, event->id, sx, sy);
+ }
+
+#ifdef USE_CURSOR
+ if (server->output && server->output->cursor_enabled) {
+ renderer_cursor_update(&server->output->renderer, server->output_x, server->output_y);
+ draw_server_with_damage(server);
+ }
+#endif
+}
+
+static void
+touch_handle_up(struct wl_listener *listener, void *data)
+{
+ struct ds_touch_event_up *event = data;
+ struct tinyds_touch *touch;
+
+ touch = wl_container_of(listener, touch, up);
+
+ ds_inf("Touch(%p) event up: id(%d) time_msec(%d)",
+ touch->dev, event->id, event->time_msec);
+
+ ds_seat_touch_notify_up(touch->server->seat, event->time_msec, event->id);
+}
+
+static void
+touch_handle_motion(struct wl_listener *listener, void *data)
+{
+ struct ds_touch_event_motion *event = data;
+ struct tinyds_touch *touch;
+ struct tinyds_view *view;
+ struct tinyds_server *server;
+ double sx = 0.f, sy = 0.f;
+
+ touch = wl_container_of(listener, touch, motion);
+
+ server = touch->server;
+ if (server->output) {
+ server->output_x = event->x * server->output->width;
+ server->output_y = event->y * server->output->height;
+ }
+
+ ds_inf("Touch(%p) event motion: id(%d) x %.3f y %.3f output_x %.1f output_y %.1f",
+ touch->dev, event->id, event->x, event->y, server->output_x, server->output_y);
+
+ view = tinyds_server_view_at(server, server->output_x, server->output_y, &sx, &sy);
+
+ if (view) {
+ ds_seat_touch_notify_motion(server->seat, event->time_msec,
+ event->id, sx, sy);
+ }
+
+#ifdef USE_CURSOR
+ if (server->output && server->output->cursor_enabled) {
+ renderer_cursor_update(&server->output->renderer, server->output_x, server->output_y);
+ draw_server_with_damage(server);
+ }
+#endif
+}
+
+static void
+server_add_touch(struct tinyds_server *server, struct ds_input_device *dev)
+{
+ struct tinyds_touch *touch;
+
+ touch = calloc(1, sizeof *touch);
+ assert(touch);
+
+ touch->dev = dev;
+ touch->server = server;
+
+ touch->destroy.notify = touch_handle_device_destroy;
+ ds_input_device_add_destroy_listener(dev, &touch->destroy);
+
+ touch->down.notify = touch_handle_down;
+ ds_touch_add_down_listener(ds_input_device_get_touch(dev), &touch->down);
+
+ touch->up.notify = touch_handle_up;
+ ds_touch_add_up_listener(ds_input_device_get_touch(dev), &touch->up);
+
+ touch->motion.notify = touch_handle_motion;
+ ds_touch_add_motion_listener(ds_input_device_get_touch(dev), &touch->motion);
+
+ ds_inf("Touch(%p) added", touch);
+}
+
+static void
+pointer_handle_device_destroy(struct wl_listener *listener, void *data)
+{
+ struct tinyds_pointer *pointer;
+ struct tinyds_server *server;
+
+ pointer = wl_container_of(listener, pointer, destroy);
+
+ ds_inf("Pointer(%p) destroyed", pointer);
+
+ wl_list_remove(&pointer->destroy.link);
+ wl_list_remove(&pointer->motion.link);
+ wl_list_remove(&pointer->button.link);
+ wl_list_remove(&pointer->frame.link);
+ wl_list_remove(&pointer->link);
+
+#ifdef USE_CURSOR
+ server = pointer->server;
+ if (server->output && wl_list_empty(&server->pointers))
+ {
+ server->output->cursor_enabled = false;
+ renderer_cursor_destroy(&server->output->renderer);
+
+ if (server->output->cursor_hwc_window)
+ {
+ ds_tdm_output_hwc_window_destroy(server->output->cursor_hwc_window);
+ server->output->cursor_hwc_window = NULL;
+ }
+ draw_server_with_damage(server);
+ }
+#endif
+
+ free(pointer);
+}
+
+static void
+pointer_handle_motion(struct wl_listener *listener, void *data)
+{
+ struct tinyds_pointer *pointer;
+ struct ds_pointer_event_motion *event = data;
+ struct tinyds_view *view;
+ struct tinyds_server *server;
+ int ow = 0, oh = 0;
+ double sx, sy;
+
+ pointer = wl_container_of(listener, pointer, motion);
+
+ server = pointer->server;
+ if (server->output) {
+ ow = server->output->width;
+ oh = server->output->height;
+ }
+
+ if (server->output_x + event->delta_x >= ow)
+ server->output_x = ow;
+ else if(server->output_x + event->delta_x <= 0.f)
+ server->output_x = 0.f;
+ else
+ server->output_x = server->output_x + event->delta_x ;
+ if (server->output_y + event->delta_y >= oh)
+ server->output_y = oh;
+ else if(server->output_y + event->delta_y <= 0.f)
+ server->output_y = 0.f;
+ else
+ server->output_y = server->output_y + event->delta_y ;
+
+ ds_inf("Pointer(%p) motion: (delta_x %.1f delta_y %.1f) output_x %.1f output_y %.1f",
+ pointer, event->delta_x, event->delta_y, server->output_x, server->output_y);
+
+ view = tinyds_server_view_at(pointer->server, server->output_x, server->output_y, &sx, &sy);
+
+ if (pointer->focused_view != view) {
+ if (pointer->focused_view) {
+ ds_inf("Clear pointer focus from view(%p)", pointer->focused_view);
+ ds_seat_pointer_notify_clear_focus(pointer->server->seat);
+ pointer->focused_view = NULL;
+ }
+
+ if (view) {
+ ds_inf("Set pointer focus to view(%p)", view);
+ ds_seat_pointer_notify_enter(pointer->server->seat,
+ ds_xdg_surface_get_surface(view->xdg_surface), sx, sy);
+ pointer->focused_view = view;
+ }
+ }
+
+ if (view) {
+ ds_seat_pointer_notify_motion(pointer->server->seat,
+ event->time_msec, sx, sy);
+ }
+
+#ifdef USE_CURSOR
+ if (server->output && server->output->cursor_enabled) {
+ renderer_cursor_update(&server->output->renderer, server->output_x, server->output_y);
+ draw_server_with_damage(server);
+ }
+#endif
+}
+
+static void
+pointer_handle_button(struct wl_listener *listener, void *data)
+{
+ struct tinyds_pointer *pointer;
+ struct ds_pointer_event_button *event = data;
+
+ pointer = wl_container_of(listener, pointer, button);
+
+ ds_inf("Pointer(%p) button(%d): state(%s) time(%d)",
+ pointer, event->button,
+ (event->state == DS_BUTTON_PRESSED) ? "Pressed" : "Released",
+ event->time_msec);
+
+ ds_seat_pointer_notify_button(pointer->server->seat, event->time_msec, event->button, event->state);
+}
+
+static void
+pointer_handle_frame(struct wl_listener *listener, void *data)
+{
+ struct tinyds_pointer *pointer;
+
+ pointer = wl_container_of(listener, pointer, frame);
+
+ ds_inf("Pointer(%p) frame", pointer);
+ ds_seat_pointer_notify_frame(pointer->server->seat);
+}
+
+static void
+server_add_pointer(struct tinyds_server *server, struct ds_input_device *dev)
+{
+ struct tinyds_pointer *pointer;
+
+ pointer = calloc(1, sizeof *pointer);
+ assert(pointer);
+
+ pointer->dev = dev;
+ pointer->server = server;
+
+ pointer->destroy.notify = pointer_handle_device_destroy;
+ ds_input_device_add_destroy_listener(dev, &pointer->destroy);
+
+ pointer->motion.notify = pointer_handle_motion;
+ ds_pointer_add_motion_listener(ds_input_device_get_pointer(dev),
+ &pointer->motion);
+
+ pointer->button.notify = pointer_handle_button;
+ ds_pointer_add_button_listener(ds_input_device_get_pointer(dev),
+ &pointer->button);
+
+ pointer->frame.notify = pointer_handle_frame;
+ ds_pointer_add_frame_listener(ds_input_device_get_pointer(dev),
+ &pointer->frame);
+
+ pointer->focused_view = NULL;
+
+#ifdef USE_CURSOR
+ if (server->output && wl_list_empty(&server->pointers)) {
+ server->output_x = (double)(server->output->width) / 2;
+ server->output_y = (double)(server->output->height) / 2;
+
+ server->output->cursor_enabled = true;
+ renderer_cursor_create(&server->output->renderer, 255, 0, 0, CURSOR_W, CURSOR_H);
+ renderer_cursor_update(&server->output->renderer, server->output_x, server->output_y);
+
+ server->output->cursor_hwc_window = ds_tdm_output_hwc_window_create(server->output->hwc);
+ assert(server->output->cursor_hwc_window);
+ draw_server_with_damage(server);
+ }
+#endif
+
+ wl_list_insert(&server->pointers, &pointer->link);
+
+ ds_inf("Pointer(%p) added", pointer);
+}
+
+static void
+output_schedule_commit_handle_idle_timer(void *data)
+{
+ struct tinyds_output *output = data;
+ output->idle_commit = NULL;
+
+ output_commit(output);
+}
+
+static void
+output_schedule_commit(struct tinyds_output *output)
+{
+ if (output->idle_commit)
+ return;
+
+ struct wl_event_loop *ev = wl_display_get_event_loop(output->server->display);
+ output->idle_commit =
+ wl_event_loop_add_idle(ev, output_schedule_commit_handle_idle_timer, output);
+}
+
+static void
+text_input_mgr_handle_destroy(struct wl_listener *listener, void *data)
+{
+ struct tinyds_text_input *text_input;
+ struct tinyds_server *server;
+
+ ds_inf("text_input_mgr_handle_destroy");
+ text_input = wl_container_of(listener, text_input, mgr_destroy);
+
+ wl_list_remove(&text_input->mgr_destroy.link);
+ wl_list_remove(&text_input->new_text_input.link);
+
+ server = text_input->server;
+ server->text_input = NULL;
+}
+
+static void
+text_input_handle_destroy(struct wl_listener *listener, void *data)
+{
+ struct tinyds_text_input *text_input;
+
+ ds_inf("text_input_handle_destroy");
+
+ text_input = wl_container_of(listener, text_input, destroy);
+
+ wl_list_remove(&text_input->destroy.link);
+ wl_list_remove(&text_input->text_input_activate.link);
+ wl_list_remove(&text_input->text_input_deactivate.link);
+ wl_list_remove(&text_input->text_input_reset.link);
+ wl_list_remove(&text_input->text_input_set_content_type.link);
+ wl_list_remove(&text_input->text_input_invoke_action.link);
+ wl_list_remove(&text_input->text_input_commit_state.link);
+ wl_list_remove(&text_input->text_input_set_preferred_language.link);
+
+ free(text_input);
+}
+
+static void
+text_input_handle_activate(struct wl_listener *listener, void *data)
+{
+ struct tinyds_text_input *text_input;
+ struct tinyds_input_method *input_method;
+ struct ds_tizen_text_input_event_activate *event = data;
+
+ text_input = wl_container_of(listener, text_input, text_input_activate);
+
+ input_method = text_input->server->input_method;
+
+ ds_inf("text_input_handle_activate. text_input(%p) seat(%p) surface(%p) text_input(%p)",
+ text_input, event->seat, event->surface, event->text_input);
+
+ if (input_method->input == text_input)
+ return;
+ if (input_method->input)
+ ;//deactivate_input_method(server->input_method);
+ input_method->input = text_input;
+ wl_list_insert(&text_input->input_methods, &input_method->link);
+
+ text_input->surface = event->surface;
+
+ if (!add_new_input_method_context(input_method, text_input))
+ return;
+
+ // ds_tizen_input_method_send_set_text_input_id();
+}
+
+static void
+text_input_handle_deactivate(struct wl_listener *listener, void *data)
+{
+ struct tinyds_text_input *text_input;
+ struct tinyds_input_method *input_method, *tmp;
+ struct ds_tizen_text_input_event_deactivate *event = data;
+
+ text_input = wl_container_of(listener, text_input, text_input_deactivate);
+ ds_inf("text_input_handle_deactivate. text_input(%p) seat(%p) text_input(%p)",
+ text_input, event->seat, event->text_input);
+
+ wl_list_for_each_safe(input_method, tmp, &text_input->input_methods, link) {
+ if (!input_method->input_method || !input_method->context->context) continue;
+ ds_tizen_input_method_send_deactivate(input_method->input_method, input_method->context->context);
+ input_method->input = NULL;
+ input_method->context = NULL;
+ wl_list_remove(&input_method->link);
+ }
+
+ text_input->surface = NULL;
+ // ds_tizen_input_method_send_close_connection();
+}
+
+static void
+text_input_handle_reset(struct wl_listener *listener, void *data)
+{
+ struct tinyds_text_input *text_input;
+ struct tinyds_input_method *input_method;
+
+ text_input = wl_container_of(listener, text_input, text_input_reset);
+
+ ds_inf("text_input_handle_reset. text_input(%p)", text_input);
+
+ wl_list_for_each(input_method, &text_input->input_methods, link) {
+ if (!input_method->context || !input_method->context->context) continue;
+ ds_tizen_input_method_context_send_reset(input_method->context->context);
+ }
+}
+
+static void
+text_input_handle_set_content_type(struct wl_listener *listener, void *data)
+{
+ struct tinyds_text_input *text_input;
+ struct ds_tizen_text_input_event_set_content_type *event = data;
+ struct tinyds_input_method *input_method;
+
+ text_input = wl_container_of(listener, text_input, text_input_set_content_type);
+
+ ds_inf("text_input_handle_content_type. text_input(%p) hint(%u) purpose(%u)",
+ text_input, event->hint, event->purpose);
+
+ wl_list_for_each(input_method, &text_input->input_methods, link) {
+ if (!input_method->context || !input_method->context->context) continue;
+ ds_tizen_input_method_context_send_content_type(input_method->context->context,
+ event->hint, event->purpose);
+ }
+}
+
+static void
+text_input_handle_invoke_action(struct wl_listener *listener, void *data)
+{
+ struct tinyds_text_input *text_input;
+ struct ds_tizen_text_input_event_invoke_action *event = data;
+ struct tinyds_input_method *input_method;
+
+ text_input = wl_container_of(listener, text_input, text_input_invoke_action);
+
+ ds_inf("text_input_handle_invoke_action. text_input(%p) button(%u) index(%u)",
+ text_input, event->button, event->index);
+
+ wl_list_for_each(input_method, &text_input->input_methods, link) {
+ if (!input_method->context || !input_method->context->context) continue;
+ ds_tizen_input_method_context_send_invoke_action(input_method->context->context,
+ event->button, event->index);
+ }
+}
+
+static void
+text_input_handle_commit_state(struct wl_listener *listener, void *data)
+{
+ struct tinyds_text_input *text_input;
+ struct ds_tizen_text_input_event_commit_state *event = data;
+ struct tinyds_input_method *input_method;
+
+ text_input = wl_container_of(listener, text_input, text_input_commit_state);
+
+ ds_inf("text_input_handle_commit_state. text_input(%p) serial(%u)",
+ text_input, event->serial);
+
+ wl_list_for_each(input_method, &text_input->input_methods, link) {
+ if (!input_method->context || !input_method->context->context) continue;
+ ds_tizen_input_method_context_send_commit_state(input_method->context->context,
+ event->serial);
+ }
+}
+
+static void
+text_input_handle_set_preferred_language(struct wl_listener *listener, void *data)
+{
+ struct tinyds_text_input *text_input;
+ struct ds_tizen_text_input_event_set_preferred_language *event = data;
+ struct tinyds_input_method *input_method;
+
+ text_input = wl_container_of(listener, text_input, text_input_set_preferred_language);
+
+ ds_inf("text_input_handle_set_preferred_language. text_input(%p) language(%s)",
+ text_input, event->language);
+
+ wl_list_for_each(input_method, &text_input->input_methods, link) {
+ if (!input_method->context || !input_method->context->context) continue;
+ ds_tizen_input_method_context_send_preferred_language(input_method->context->context,
+ event->language);
+ }
+}
+
+static void
+text_input_mgr_handle_new_text_input(struct wl_listener *listener, void *data)
+{
+ struct tinyds_text_input *text_input;
+ struct ds_tizen_text_input *input = data;
+
+ text_input = wl_container_of(listener, text_input, new_text_input);
+
+ ds_inf("text_input_mgr_handle_new_text_input");
+
+ text_input->input = input;
+
+ text_input->destroy.notify = text_input_handle_destroy;
+ ds_tizen_text_input_add_destroy_listener(text_input->input,
+ &text_input->destroy);
+
+ text_input->text_input_activate.notify = text_input_handle_activate;
+ ds_tizen_text_input_add_activate_listener(text_input->input,
+ &text_input->text_input_activate);
+
+ text_input->text_input_deactivate.notify = text_input_handle_deactivate;
+ ds_tizen_text_input_add_deactivate_listener(text_input->input,
+ &text_input->text_input_deactivate);
+
+ text_input->text_input_reset.notify = text_input_handle_reset;
+ ds_tizen_text_input_add_reset_listener(text_input->input,
+ &text_input->text_input_reset);
+
+ text_input->text_input_set_content_type.notify = text_input_handle_set_content_type;
+ ds_tizen_text_input_add_set_content_type_listener(text_input->input,
+ &text_input->text_input_set_content_type);
+
+ text_input->text_input_invoke_action.notify = text_input_handle_invoke_action;
+ ds_tizen_text_input_add_invoke_action_listener(text_input->input,
+ &text_input->text_input_invoke_action);
+
+ text_input->text_input_commit_state.notify = text_input_handle_commit_state;
+ ds_tizen_text_input_add_commit_state_listener(text_input->input,
+ &text_input->text_input_commit_state);
+
+ text_input->text_input_set_preferred_language.notify = text_input_handle_set_preferred_language;
+ ds_tizen_text_input_add_set_preferred_language_listener(text_input->input,
+ &text_input->text_input_set_preferred_language);
+}
+
+static void
+input_method_mgr_handle_destroy(struct wl_listener *listener, void *data)
+{
+ struct tinyds_input_method *input_method;
+
+ ds_inf("input_method_mgr_handle_destroy");
+
+ input_method = wl_container_of(listener, input_method, mgr_destroy);
+
+ wl_list_remove(&input_method->mgr_destroy.link);
+}
+
+static void
+input_method_handle_destroy(struct wl_listener *listener, void *data)
+{
+ struct tinyds_input_method *input_method;
+ struct tinyds_server *server;
+
+ ds_inf("input_method_handle_destroy");
+
+ input_method = wl_container_of(listener, input_method, destroy);
+
+ wl_list_remove(&input_method->destroy.link);
+
+ server = input_method->server;
+ server->input_method = NULL;
+
+ free(input_method);
+}
+
+static void
+context_handle_destroy(struct wl_listener *listener, void *data)
+{
+ struct tinyds_input_method_context *context;
+ struct tinyds_server *server;
+
+ ds_inf("context_handle_destroy");
+
+ context = wl_container_of(listener, context, destroy);
+
+ wl_list_remove(&context->destroy.link);
+
+ wl_list_remove(&context->im_context_commit_string.link);
+ wl_list_remove(&context->im_context_preedit_string.link);
+ wl_list_remove(&context->im_context_preedit_styling.link);
+ wl_list_remove(&context->im_context_preedit_cursor.link);
+ wl_list_remove(&context->im_context_delete_surrounding_text.link);
+ wl_list_remove(&context->im_context_cursor_position.link);
+ wl_list_remove(&context->im_context_modifiers_map.link);
+ wl_list_remove(&context->im_context_keysym.link);
+ wl_list_remove(&context->im_context_grab_keyboard.link);
+ wl_list_remove(&context->im_context_key.link);
+ wl_list_remove(&context->im_context_modifiers.link);
+ wl_list_remove(&context->im_context_language.link);
+ wl_list_remove(&context->im_context_text_direction.link);
+
+ server = context->server;
+ server->input_method->context = NULL;
+
+ free(context);
+}
+
+static void
+context_handle_commit_string(struct wl_listener *listener, void *data)
+{
+ struct tinyds_text_input *text_input;
+ struct tinyds_input_method_context *context;
+ struct ds_tizen_input_method_context_event_commit_string *event = data;
+
+ context = wl_container_of(listener, context, im_context_commit_string);
+ text_input = context->server->text_input;
+
+ ds_inf("context_handle_commit_string. text_input(%p) serial(%u) text(%s)",
+ text_input, event->serial, event->text);
+
+ ds_tizen_text_input_send_commit_string(text_input->input, event->serial, event->text);
+}
+
+static void
+context_handle_preedit_string(struct wl_listener *listener, void *data)
+{
+ struct tinyds_input_method_context *context;
+ struct tinyds_text_input *text_input;
+ struct ds_tizen_input_method_context_event_preedit_string *event = data;
+
+ context = wl_container_of(listener, context, im_context_preedit_string);
+ text_input = context->server->text_input;
+
+ ds_inf("context_handle_preedit_string. text_input(%p) serial(%u) text(%s) commit(%s)",
+ text_input, event->serial, event->text, event->commit);
+
+ ds_tizen_text_input_send_preedit_string(text_input->input, event->serial, event->text, event->commit);
+}
+
+static void
+context_handle_preedit_styling(struct wl_listener *listener, void *data)
+{
+ struct tinyds_input_method_context *context;
+ struct tinyds_text_input *text_input;
+ struct ds_tizen_input_method_context_event_preedit_styling *event = data;
+
+ context = wl_container_of(listener, context, im_context_preedit_styling);
+ text_input = context->server->text_input;
+
+ ds_inf("context_handle_preedit_styling. text_input(%p) index(%u) length(%u) style(%u)",
+ text_input, event->index, event->length, event->style);
+
+ ds_tizen_text_input_send_preedit_styling(text_input->input, event->index, event->length, event->style);
+}
+
+static void
+context_handle_preedit_cursor(struct wl_listener *listener, void *data)
+{
+ struct tinyds_input_method_context *context;
+ struct tinyds_text_input *text_input;
+ struct ds_tizen_input_method_context_event_preedit_cursor *event = data;
+
+ context = wl_container_of(listener, context, im_context_preedit_cursor);
+ text_input = context->server->text_input;
+
+ ds_inf("context_handle_preedit_cursor. text_input(%p) index(%u)",
+ text_input, event->index);
+
+ ds_tizen_text_input_send_preedit_cursor(text_input->input, event->index);
+}
+
+static void
+context_handle_delete_surrounding_text(struct wl_listener *listener, void *data)
+{
+ struct tinyds_input_method_context *context;
+ struct tinyds_text_input *text_input;
+ struct ds_tizen_input_method_context_event_delete_surrounding_text *event = data;
+
+ context = wl_container_of(listener, context, im_context_delete_surrounding_text);
+ text_input = context->server->text_input;
+
+ ds_inf("context_handle_delete_surrounding_text. text_input(%p) index(%d) length(%u)",
+ text_input, event->index, event->length);
+
+ ds_tizen_text_input_send_delete_surrounding_text(text_input->input, event->index, event->length);
+}
+
+static void
+context_handle_cursor_position(struct wl_listener *listener, void *data)
+{
+ struct tinyds_input_method_context *context;
+ struct tinyds_text_input *text_input;
+ struct ds_tizen_input_method_context_event_cursor_position *event = data;
+
+ context = wl_container_of(listener, context, im_context_cursor_position);
+ text_input = context->server->text_input;
+
+ ds_inf("context_handle_cursor_position. text_input(%p) index(%d) length(%d)",
+ text_input, event->index, event->anchor);
+
+ ds_tizen_text_input_send_cursor_position(text_input->input, event->index, event->anchor);
+}
+
+static void
+context_handle_modifiers_map(struct wl_listener *listener, void *data)
+{
+ struct tinyds_input_method_context *context;
+ struct tinyds_text_input *text_input;
+ struct ds_tizen_input_method_context_event_modifiers_map *event = data;
+
+ context = wl_container_of(listener, context, im_context_modifiers_map);
+ text_input = context->server->text_input;
+
+ ds_inf("context_handle_modifiers_map. text_input(%p) map(%p)",
+ text_input, event->map);
+
+ ds_tizen_text_input_send_modifiers_map(text_input->input, event->map);
+}
+
+static void
+context_handle_keysym(struct wl_listener *listener, void *data)
+{
+ struct tinyds_input_method_context *context;
+ struct tinyds_text_input *text_input;
+ struct ds_tizen_input_method_context_event_keysym *event = data;
+
+ context = wl_container_of(listener, context, im_context_keysym);
+ text_input = context->server->text_input;
+
+ ds_inf("context_handle_keysym. text_input(%p) serial(%u) time(%u) sysm(%u) state(%u) modifiers(%u)",
+ text_input, event->serial, event->time, event->sym, event->state, event->modifiers);
+
+ ds_tizen_text_input_send_keysym(text_input->input, event->serial, event->time, event->sym, event->state, event->modifiers);
+}
+
+static void
+context_handle_grab_keyboard(struct wl_listener *listener, void *data)
+{
+ struct tinyds_input_method_context *context;
+ struct tinyds_text_input *text_input;
+
+ context = wl_container_of(listener, context, im_context_grab_keyboard);
+ text_input = context->server->text_input;
+
+ ds_inf("context_handle_grab_keyboard. text_input(%p)",
+ text_input);
+
+ //TODO
+}
+
+static void
+context_handle_key(struct wl_listener *listener, void *data)
+{
+ struct tinyds_input_method_context *context;
+ struct tinyds_text_input *text_input;
+
+ context = wl_container_of(listener, context, im_context_key);
+ text_input = context->server->text_input;
+
+ ds_inf("context_handle_key. text_input(%p)",
+ text_input);
+
+ //TODO
+}
+
+static void
+context_handle_modifiers(struct wl_listener *listener, void *data)
+{
+ struct tinyds_input_method_context *context;
+ struct tinyds_text_input *text_input;
+
+ context = wl_container_of(listener, context, im_context_modifiers);
+ text_input = context->server->text_input;
+
+ ds_inf("context_handle_modifiers. text_input(%p)",
+ text_input);
+
+ //TODO
+}
+
+static void
+context_handle_language(struct wl_listener *listener, void *data)
+{
+ struct tinyds_input_method_context *context;
+ struct tinyds_text_input *text_input;
+ struct ds_tizen_input_method_context_event_language *event = data;
+
+ context = wl_container_of(listener, context, im_context_language);
+ text_input = context->server->text_input;
+
+ ds_inf("context_handle_language. text_input(%p) serial(%u), language(%s)",
+ text_input, event->serial, event->language);
+
+ ds_tizen_text_input_send_language(text_input->input, event->serial, event->language);
+}
+
+static void
+context_handle_text_direction(struct wl_listener *listener, void *data)
+{
+ struct tinyds_input_method_context *context;
+ struct tinyds_text_input *text_input;
+ struct ds_tizen_input_method_context_event_text_direction *event = data;
+
+ context = wl_container_of(listener, context, im_context_text_direction);
+ text_input = context->server->text_input;
+
+ ds_inf("context_handle_text_direction. text_input(%p) serial(%u), direction(%u)",
+ text_input, event->serial, event->direction);
+
+ ds_tizen_text_input_send_text_direction(text_input->input, event->serial, event->direction);
+}
+
+static bool
+add_new_text_input(struct tinyds_server *server)
+{
+ struct tinyds_text_input *text_input;
+
+ text_input = calloc(1, sizeof *text_input);
+ if (!text_input)
+ return false;
+
+ text_input->text_input_mgr = ds_tizen_text_input_manager_create(server->display);
+ if (!text_input->text_input_mgr) {
+ free(text_input);
+ ds_err("Could not create ds_tizen_text_input_manager");
+ return false;
+ }
+
+ wl_list_init(&text_input->input_methods);
+
+ text_input->mgr_destroy.notify = text_input_mgr_handle_destroy;
+ ds_tizen_text_input_manager_add_destroy_listener(text_input->text_input_mgr,
+ &text_input->mgr_destroy);
+
+ text_input->new_text_input.notify = text_input_mgr_handle_new_text_input;
+ ds_tizen_text_input_manager_add_new_text_input_listener(text_input->text_input_mgr,
+ &text_input->new_text_input);
+
+ text_input->server = server;
+ server->text_input = text_input;
+
+ ds_inf("Text_Input (%p) added", text_input);
+
+ return true;
+}
+
+static bool
+add_new_input_method(struct tinyds_server *server)
+{
+ struct tinyds_input_method *input_method;
+
+ input_method = calloc(1, sizeof *input_method);
+ if (!input_method)
+ return false;
+
+ input_method->input_method = ds_tizen_input_method_create(server->display);
+ if (!input_method->input_method) {
+ free(input_method);
+ ds_err("Could not create ds_tizen_input_method");
+ return false;
+ }
+ input_method->destroy.notify = input_method_handle_destroy;
+ ds_tizen_input_method_add_destroy_listener(input_method->input_method,
+ &input_method->destroy);
+
+ input_method->input_method_mgr = ds_tizen_input_method_manager_create(server->display);
+ if (!input_method->input_method_mgr) {
+ free(input_method);
+ ds_err("Could not create ds_tizen_input_method_manager");
+ return false;
+ }
+
+ input_method->mgr_destroy.notify = input_method_mgr_handle_destroy;
+ ds_tizen_input_method_manager_add_destroy_listener(input_method->input_method_mgr,
+ &input_method->mgr_destroy);
+
+ input_method->server = server;
+ server->input_method = input_method;
+
+ ds_inf("Input_Method (%p) added", input_method);
+
+ return true;
+}
+
+static bool
+add_new_input_method_context(struct tinyds_input_method *input_method,
+ struct tinyds_text_input *text_input)
+{
+ struct tinyds_input_method_context *context;
+
+ context = calloc(1, sizeof *context);
+ if (context == NULL)
+ {
+ ds_err("calloc is failed. tinyds_input_method_context");
+ return false;
+ }
+ input_method->context = context;
+ context->input_method = input_method;
+ context->server = input_method->server;
+ context->input = text_input;
+
+ context->context = ds_tizen_input_method_create_context(input_method->input_method);
+ if (context->context == NULL) {
+ ds_err("ds_tizen_input_method_create_context() failed.");
+ return false;
+ }
+
+ context->destroy.notify = context_handle_destroy;
+ ds_tizen_input_method_context_add_destroy_listener(context->context,
+ &context->destroy);
+
+ context->im_context_commit_string.notify = context_handle_commit_string;
+ ds_tizen_input_method_context_add_commit_string_listener(context->context,
+ &context->im_context_commit_string);
+
+ context->im_context_preedit_string.notify = context_handle_preedit_string;
+ ds_tizen_input_method_context_add_preedit_string_listener(context->context,
+ &context->im_context_preedit_string);
+
+ context->im_context_preedit_styling.notify = context_handle_preedit_styling;
+ ds_tizen_input_method_context_add_preedit_styling_listener(context->context,
+ &context->im_context_preedit_styling);
+
+ context->im_context_preedit_cursor.notify = context_handle_preedit_cursor;
+ ds_tizen_input_method_context_add_preedit_cursor_listener(context->context,
+ &context->im_context_preedit_cursor);
+
+ context->im_context_delete_surrounding_text.notify = context_handle_delete_surrounding_text;
+ ds_tizen_input_method_context_add_delete_surrounding_text_listener(context->context,
+ &context->im_context_delete_surrounding_text);
+
+ context->im_context_cursor_position.notify = context_handle_cursor_position;
+ ds_tizen_input_method_context_add_cursor_position_listener(context->context,
+ &context->im_context_cursor_position);
+
+ context->im_context_modifiers_map.notify = context_handle_modifiers_map;
+ ds_tizen_input_method_context_add_modifiers_map_listener(context->context,
+ &context->im_context_modifiers_map);
+
+ context->im_context_keysym.notify = context_handle_keysym;
+ ds_tizen_input_method_context_add_keysym_listener(context->context,
+ &context->im_context_keysym);
+
+ context->im_context_grab_keyboard.notify = context_handle_grab_keyboard;
+ ds_tizen_input_method_context_add_grab_keyboard_listener(context->context,
+ &context->im_context_grab_keyboard);
+
+ context->im_context_key.notify = context_handle_key;
+ ds_tizen_input_method_context_add_key_listener(context->context,
+ &context->im_context_key);
+
+ context->im_context_modifiers.notify = context_handle_modifiers;
+ ds_tizen_input_method_context_add_modifiers_listener(context->context,
+ &context->im_context_modifiers);
+
+ context->im_context_language.notify = context_handle_language;
+ ds_tizen_input_method_context_add_language_listener(context->context,
+ &context->im_context_language);
+
+ context->im_context_text_direction.notify = context_handle_text_direction;
+ ds_tizen_input_method_context_add_text_direction_listener(context->context,
+ &context->im_context_text_direction);
+
+ return true;
+}
+
+struct tinyds_view *
+tinyds_server_get_focused_view(struct tinyds_server *server)
+{
+ struct tinyds_view *view = NULL;
+ struct tinyds_pointer *pointer;
+
+ wl_list_for_each(pointer, &server->pointers, link){
+ if (!pointer->focused_view) continue;
+
+ view = pointer->focused_view;
+ }
+
+ return view;
+}
+
+void
+tinyds_server_get_output_size(struct tinyds_server *server,
+ int *output_w, int *output_h)
+{
+ *output_w = server->output->width;
+ *output_h = server->output->height;
+}