pH/sommelier/sommelier-text-input.cc

552 lines
22 KiB
C++

// Copyright 2018 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "sommelier.h" // NOLINT(build/include_directory)
#include "sommelier-transform.h" // NOLINT(build/include_directory)
#include "weak-resource-ptr.h" // NOLINT(build/include_directory)
#include <algorithm>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "text-input-extension-unstable-v1-client-protocol.h" // NOLINT(build/include_directory)
#include "text-input-extension-unstable-v1-server-protocol.h" // NOLINT(build/include_directory)
#include "text-input-unstable-v1-client-protocol.h" // NOLINT(build/include_directory)
#include "text-input-unstable-v1-server-protocol.h" // NOLINT(build/include_directory)
#include "text-input-x11-unstable-v1-server-protocol.h" // NOLINT(build/include_directory)
namespace {
// Versions supported by sommelier.
constexpr uint32_t kTextInputManagerVersion = 1;
constexpr uint32_t kTextInputExtensionVersion = 4;
constexpr uint32_t kTextInputX11Version = 1;
} // namespace
struct sl_host_text_input_manager {
struct sl_context* ctx;
struct wl_resource* resource;
struct zwp_text_input_manager_v1* proxy;
};
struct sl_host_text_input {
struct sl_context* ctx;
struct wl_resource* resource;
struct zwp_text_input_v1* proxy;
WeakResourcePtr<sl_host_surface> active_surface;
};
MAP_STRUCTS(zwp_text_input_v1, sl_host_text_input);
struct sl_host_text_input_extension {
struct sl_context* ctx;
struct wl_resource* resource;
struct zcr_text_input_extension_v1* proxy;
};
struct sl_host_extended_text_input {
struct sl_context* ctx;
struct wl_resource* resource;
struct sl_host_text_input* host_text_input;
struct zcr_extended_text_input_v1* proxy;
};
MAP_STRUCTS(zcr_extended_text_input_v1, sl_host_extended_text_input);
static void sl_text_input_activate(wl_client* client,
wl_resource* resource,
wl_resource* seat,
wl_resource* surface) {
struct sl_host_text_input* host =
static_cast<sl_host_text_input*>(wl_resource_get_user_data(resource));
struct sl_host_seat* host_seat =
static_cast<sl_host_seat*>(wl_resource_get_user_data(seat));
struct sl_host_surface* host_surface =
static_cast<sl_host_surface*>(wl_resource_get_user_data(surface));
host->active_surface = host_surface;
zwp_text_input_v1_activate(host->proxy, host_seat->proxy,
host_surface->proxy);
}
static void sl_text_input_deactivate(wl_client* client,
wl_resource* resource,
wl_resource* seat) {
struct sl_host_text_input* host =
static_cast<sl_host_text_input*>(wl_resource_get_user_data(resource));
struct sl_host_seat* host_seat =
static_cast<sl_host_seat*>(wl_resource_get_user_data(seat));
host->active_surface.Reset();
zwp_text_input_v1_deactivate(host->proxy, host_seat->proxy);
}
static void sl_text_input_set_cursor_rectangle(wl_client* client,
wl_resource* resource,
int32_t x,
int32_t y,
int32_t width,
int32_t height) {
struct sl_host_text_input* host =
static_cast<sl_host_text_input*>(wl_resource_get_user_data(resource));
if (!host->active_surface)
return;
int32_t x1 = x;
int32_t y1 = y;
int32_t x2 = x + width;
int32_t y2 = y + height;
sl_transform_guest_to_host(host->ctx, host->active_surface.get(), &x1, &y1);
sl_transform_guest_to_host(host->ctx, host->active_surface.get(), &x2, &y2);
zwp_text_input_v1_set_cursor_rectangle(host->proxy, x1, y1, x2 - x1, y2 - y1);
}
static const struct zwp_text_input_v1_interface sl_text_input_implementation = {
sl_text_input_activate,
sl_text_input_deactivate,
ForwardRequest<zwp_text_input_v1_show_input_panel>,
ForwardRequest<zwp_text_input_v1_hide_input_panel>,
ForwardRequest<zwp_text_input_v1_reset>,
ForwardRequest<zwp_text_input_v1_set_surrounding_text>,
ForwardRequest<zwp_text_input_v1_set_content_type>,
sl_text_input_set_cursor_rectangle,
ForwardRequest<zwp_text_input_v1_set_preferred_language>,
ForwardRequest<zwp_text_input_v1_commit_state>,
ForwardRequest<zwp_text_input_v1_invoke_action>,
};
static void sl_text_input_enter(void* data,
struct zwp_text_input_v1* text_input,
struct wl_surface* surface) {
// This is not currently used by cros_im. We can't simply forward the event
// as for an x11-hosted cros_im instance the text_input and wl_surface
// objects will be on different clients. We could add a corresponding event
// to text_input_x11 if needed.
}
static void sl_text_input_leave(void* data,
struct zwp_text_input_v1* text_input) {
struct sl_host_text_input* host = static_cast<sl_host_text_input*>(
zwp_text_input_v1_get_user_data(text_input));
zwp_text_input_v1_send_leave(host->resource);
}
static void sl_text_input_modifiers_map(void* data,
struct zwp_text_input_v1* text_input,
struct wl_array* map) {
struct sl_host_text_input* host = static_cast<sl_host_text_input*>(
zwp_text_input_v1_get_user_data(text_input));
zwp_text_input_v1_send_modifiers_map(host->resource, map);
}
static void sl_text_input_input_panel_state(
void* data, struct zwp_text_input_v1* text_input, uint32_t state) {
struct sl_host_text_input* host = static_cast<sl_host_text_input*>(
zwp_text_input_v1_get_user_data(text_input));
zwp_text_input_v1_send_input_panel_state(host->resource, state);
}
static void sl_text_input_preedit_string(void* data,
struct zwp_text_input_v1* text_input,
uint32_t serial,
const char* text,
const char* commit) {
struct sl_host_text_input* host = static_cast<sl_host_text_input*>(
zwp_text_input_v1_get_user_data(text_input));
zwp_text_input_v1_send_preedit_string(host->resource, serial, text, commit);
}
static void sl_text_input_preedit_styling(void* data,
struct zwp_text_input_v1* text_input,
uint32_t index,
uint32_t length,
uint32_t style) {
struct sl_host_text_input* host = static_cast<sl_host_text_input*>(
zwp_text_input_v1_get_user_data(text_input));
zwp_text_input_v1_send_preedit_styling(host->resource, index, length, style);
}
static void sl_text_input_preedit_cursor(void* data,
struct zwp_text_input_v1* text_input,
int32_t index) {
struct sl_host_text_input* host = static_cast<sl_host_text_input*>(
zwp_text_input_v1_get_user_data(text_input));
zwp_text_input_v1_send_preedit_cursor(host->resource, index);
}
static void sl_text_input_commit_string(void* data,
struct zwp_text_input_v1* text_input,
uint32_t serial,
const char* text) {
struct sl_host_text_input* host = static_cast<sl_host_text_input*>(
zwp_text_input_v1_get_user_data(text_input));
zwp_text_input_v1_send_commit_string(host->resource, serial, text);
}
static void sl_text_input_cursor_position(void* data,
struct zwp_text_input_v1* text_input,
int32_t index,
int32_t anchor) {
struct sl_host_text_input* host = static_cast<sl_host_text_input*>(
zwp_text_input_v1_get_user_data(text_input));
zwp_text_input_v1_send_cursor_position(host->resource, index, anchor);
}
static void sl_text_input_delete_surrounding_text(
void* data,
struct zwp_text_input_v1* text_input,
int32_t index,
uint32_t length) {
struct sl_host_text_input* host = static_cast<sl_host_text_input*>(
zwp_text_input_v1_get_user_data(text_input));
zwp_text_input_v1_send_delete_surrounding_text(host->resource, index, length);
}
static void sl_text_input_keysym(void* data,
struct zwp_text_input_v1* text_input,
uint32_t serial,
uint32_t time,
uint32_t sym,
uint32_t state,
uint32_t modifiers) {
struct sl_host_text_input* host = static_cast<sl_host_text_input*>(
zwp_text_input_v1_get_user_data(text_input));
zwp_text_input_v1_send_keysym(host->resource, serial, time, sym, state,
modifiers);
}
static void sl_text_input_language(void* data,
struct zwp_text_input_v1* text_input,
uint32_t serial,
const char* language) {
struct sl_host_text_input* host = static_cast<sl_host_text_input*>(
zwp_text_input_v1_get_user_data(text_input));
zwp_text_input_v1_send_language(host->resource, serial, language);
}
static void sl_text_input_text_direction(void* data,
struct zwp_text_input_v1* text_input,
uint32_t serial,
uint32_t direction) {
struct sl_host_text_input* host = static_cast<sl_host_text_input*>(
zwp_text_input_v1_get_user_data(text_input));
zwp_text_input_v1_send_text_direction(host->resource, serial, direction);
}
static const struct zwp_text_input_v1_listener sl_text_input_listener = {
sl_text_input_enter, sl_text_input_leave,
sl_text_input_modifiers_map, sl_text_input_input_panel_state,
sl_text_input_preedit_string, sl_text_input_preedit_styling,
sl_text_input_preedit_cursor, sl_text_input_commit_string,
sl_text_input_cursor_position, sl_text_input_delete_surrounding_text,
sl_text_input_keysym, sl_text_input_language,
sl_text_input_text_direction,
};
static void sl_destroy_host_text_input(struct wl_resource* resource) {
struct sl_host_text_input* host =
static_cast<sl_host_text_input*>(wl_resource_get_user_data(resource));
zwp_text_input_v1_destroy(host->proxy);
wl_resource_set_user_data(resource, NULL);
delete host;
}
static void sl_text_input_manager_create_text_input(
struct wl_client* client, struct wl_resource* resource, uint32_t id) {
struct sl_host_text_input_manager* host =
static_cast<sl_host_text_input_manager*>(
wl_resource_get_user_data(resource));
struct wl_resource* text_input_resource =
wl_resource_create(client, &zwp_text_input_v1_interface,
wl_resource_get_version(resource), id);
struct sl_host_text_input* text_input_host = new sl_host_text_input();
text_input_host->resource = text_input_resource;
text_input_host->ctx = host->ctx;
text_input_host->proxy =
zwp_text_input_manager_v1_create_text_input(host->proxy);
wl_resource_set_implementation(text_input_resource,
&sl_text_input_implementation, text_input_host,
sl_destroy_host_text_input);
zwp_text_input_v1_add_listener(text_input_host->proxy,
&sl_text_input_listener, text_input_host);
}
static void sl_destroy_host_text_input_manager(struct wl_resource* resource) {
struct sl_host_text_input_manager* host =
static_cast<sl_host_text_input_manager*>(
wl_resource_get_user_data(resource));
zwp_text_input_manager_v1_destroy(host->proxy);
wl_resource_set_user_data(resource, NULL);
delete host;
}
static struct zwp_text_input_manager_v1_interface
sl_text_input_manager_implementation = {
sl_text_input_manager_create_text_input,
};
static void sl_bind_host_text_input_manager(struct wl_client* client,
void* data,
uint32_t version,
uint32_t id) {
struct sl_context* ctx = (struct sl_context*)data;
struct sl_text_input_manager* text_input_manager = ctx->text_input_manager;
struct sl_host_text_input_manager* host = new sl_host_text_input_manager();
host->ctx = ctx;
host->resource =
wl_resource_create(client, &zwp_text_input_manager_v1_interface,
std::min(version, kTextInputManagerVersion), id);
wl_resource_set_implementation(host->resource,
&sl_text_input_manager_implementation, host,
sl_destroy_host_text_input_manager);
host->proxy = static_cast<zwp_text_input_manager_v1*>(wl_registry_bind(
wl_display_get_registry(ctx->display), text_input_manager->id,
&zwp_text_input_manager_v1_interface,
wl_resource_get_version(host->resource)));
zwp_text_input_manager_v1_set_user_data(host->proxy, host);
}
struct sl_global* sl_text_input_manager_global_create(struct sl_context* ctx) {
return sl_global_create(ctx, &zwp_text_input_manager_v1_interface,
kTextInputManagerVersion, ctx,
sl_bind_host_text_input_manager);
}
static void sl_extended_text_input_destroy(struct wl_client* client,
struct wl_resource* resource) {
wl_resource_destroy(resource);
}
static const struct zcr_extended_text_input_v1_interface
sl_extended_text_input_implementation = {
sl_extended_text_input_destroy,
ForwardRequest<zcr_extended_text_input_v1_set_input_type>,
ForwardRequest<
zcr_extended_text_input_v1_set_grammar_fragment_at_cursor>,
ForwardRequest<zcr_extended_text_input_v1_set_autocorrect_info>,
};
static void sl_extended_text_input_set_preedit_region(
void* data,
struct zcr_extended_text_input_v1* extended_text_input,
int32_t index,
uint32_t length) {
struct sl_host_extended_text_input* host =
static_cast<sl_host_extended_text_input*>(
zcr_extended_text_input_v1_get_user_data(extended_text_input));
zcr_extended_text_input_v1_send_set_preedit_region(host->resource, index,
length);
}
static void sl_extended_text_input_clear_grammar_fragments(
void* data,
struct zcr_extended_text_input_v1* extended_text_input,
uint32_t start,
uint32_t end) {
struct sl_host_extended_text_input* host =
static_cast<sl_host_extended_text_input*>(
zcr_extended_text_input_v1_get_user_data(extended_text_input));
zcr_extended_text_input_v1_send_clear_grammar_fragments(host->resource, start,
end);
}
static void sl_extended_text_input_add_grammar_fragment(
void* data,
struct zcr_extended_text_input_v1* extended_text_input,
uint32_t start,
uint32_t end,
const char* suggestion) {
struct sl_host_extended_text_input* host =
static_cast<sl_host_extended_text_input*>(
zcr_extended_text_input_v1_get_user_data(extended_text_input));
zcr_extended_text_input_v1_send_add_grammar_fragment(host->resource, start,
end, suggestion);
}
static void sl_extended_text_input_set_autocorrect_range(
void* data,
struct zcr_extended_text_input_v1* extended_text_input,
uint32_t start,
uint32_t end) {
struct sl_host_extended_text_input* host =
static_cast<sl_host_extended_text_input*>(
zcr_extended_text_input_v1_get_user_data(extended_text_input));
zcr_extended_text_input_v1_send_set_autocorrect_range(host->resource, start,
end);
}
static const struct zcr_extended_text_input_v1_listener
sl_extended_text_input_listener = {
sl_extended_text_input_set_preedit_region,
sl_extended_text_input_clear_grammar_fragments,
sl_extended_text_input_add_grammar_fragment,
sl_extended_text_input_set_autocorrect_range,
};
static void sl_destroy_host_extended_text_input(struct wl_resource* resource) {
struct sl_host_extended_text_input* host =
static_cast<sl_host_extended_text_input*>(
wl_resource_get_user_data(resource));
zcr_extended_text_input_v1_destroy(host->proxy);
wl_resource_set_user_data(resource, NULL);
delete host;
}
static void sl_text_input_extension_get_extended_text_input(
struct wl_client* client,
struct wl_resource* resource,
uint32_t id,
struct wl_resource* text_input) {
struct sl_host_text_input_extension* host =
static_cast<sl_host_text_input_extension*>(
wl_resource_get_user_data(resource));
struct sl_host_text_input* host_text_input =
static_cast<sl_host_text_input*>(wl_resource_get_user_data(text_input));
struct wl_resource* extended_text_input_resource =
wl_resource_create(client, &zcr_extended_text_input_v1_interface,
wl_resource_get_version(resource), id);
struct sl_host_extended_text_input* extended_text_input_host =
new sl_host_extended_text_input();
extended_text_input_host->resource = extended_text_input_resource;
extended_text_input_host->ctx = host->ctx;
extended_text_input_host->proxy =
zcr_text_input_extension_v1_get_extended_text_input(
host->proxy, host_text_input->proxy);
wl_resource_set_implementation(
extended_text_input_resource, &sl_extended_text_input_implementation,
extended_text_input_host, sl_destroy_host_extended_text_input);
zcr_extended_text_input_v1_add_listener(extended_text_input_host->proxy,
&sl_extended_text_input_listener,
extended_text_input_host);
} // NOLINT(whitespace/indent)
static void sl_destroy_host_text_input_extension(struct wl_resource* resource) {
struct sl_host_text_input_extension* host =
static_cast<sl_host_text_input_extension*>(
wl_resource_get_user_data(resource));
zcr_text_input_extension_v1_destroy(host->proxy);
wl_resource_set_user_data(resource, NULL);
delete host;
}
static struct zcr_text_input_extension_v1_interface
sl_text_input_extension_implementation = {
sl_text_input_extension_get_extended_text_input,
};
static void sl_bind_host_text_input_extension(struct wl_client* client,
void* data,
uint32_t version,
uint32_t id) {
struct sl_context* ctx = (struct sl_context*)data;
struct sl_text_input_extension* text_input_extension =
ctx->text_input_extension;
struct sl_host_text_input_extension* host =
new sl_host_text_input_extension();
host->ctx = ctx;
host->resource =
wl_resource_create(client, &zcr_text_input_extension_v1_interface,
std::min(version, kTextInputExtensionVersion), id);
wl_resource_set_implementation(host->resource,
&sl_text_input_extension_implementation, host,
sl_destroy_host_text_input_extension);
host->proxy = static_cast<zcr_text_input_extension_v1*>(wl_registry_bind(
wl_display_get_registry(ctx->display), text_input_extension->id,
&zcr_text_input_extension_v1_interface,
wl_resource_get_version(host->resource)));
zcr_text_input_extension_v1_set_user_data(host->proxy, host);
}
struct sl_global* sl_text_input_extension_global_create(
struct sl_context* ctx) {
return sl_global_create(ctx, &zcr_text_input_extension_v1_interface,
kTextInputExtensionVersion, ctx,
sl_bind_host_text_input_extension);
}
static void sl_text_input_x11_activate(wl_client* client,
wl_resource* resource,
wl_resource* text_input,
wl_resource* seat,
uint32_t x11_window_id) {
struct sl_host_text_input* host_text_input =
static_cast<sl_host_text_input*>(wl_resource_get_user_data(text_input));
struct sl_host_seat* host_seat =
static_cast<sl_host_seat*>(wl_resource_get_user_data(seat));
assert(host_text_input);
assert(host_seat);
struct sl_context* ctx = host_text_input->ctx;
struct sl_window* window;
wl_list_for_each(window, &ctx->windows, link) {
if (window->id != x11_window_id)
continue;
if (!window->host_surface_id)
return;
struct wl_resource* host_window_resource =
wl_client_get_object(ctx->client, window->host_surface_id);
if (!host_window_resource)
return;
sl_host_surface* host_surface = static_cast<sl_host_surface*>(
wl_resource_get_user_data(host_window_resource));
host_text_input->active_surface = host_surface;
zwp_text_input_v1_activate(host_text_input->proxy, host_seat->proxy,
host_surface->proxy);
return;
}
}
static const struct zcr_text_input_x11_v1_interface
sl_text_input_x11_implementation = {
sl_text_input_x11_activate,
};
static void sl_bind_host_text_input_x11(struct wl_client* client,
void* data,
uint32_t version,
uint32_t id) {
// This exists only between sommelier and its clients and there is no proxy
// to the host. For simplicity we don't use a sl_host_text_input_x11
// type as it is not needed.
wl_resource* resource =
wl_resource_create(client, &zcr_text_input_x11_v1_interface,
std::min(version, kTextInputX11Version), id);
wl_resource_set_implementation(resource, &sl_text_input_x11_implementation,
nullptr, nullptr);
}
struct sl_global* sl_text_input_x11_global_create(struct sl_context* ctx) {
return sl_global_create(ctx, &zcr_text_input_x11_v1_interface,
kTextInputX11Version, ctx,
sl_bind_host_text_input_x11);
}