Skip to content

Commit

Permalink
wayland: Add support for text-input-unstable-v3
Browse files Browse the repository at this point in the history
  • Loading branch information
flibitijibibo committed Jul 29, 2021
1 parent 72ee0cc commit acc336d
Show file tree
Hide file tree
Showing 7 changed files with 679 additions and 4 deletions.
139 changes: 139 additions & 0 deletions src/video/wayland/SDL_waylandevents.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "relative-pointer-unstable-v1-client-protocol.h"
#include "xdg-shell-client-protocol.h"
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
#include "text-input-unstable-v3-client-protocol.h"

#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
Expand Down Expand Up @@ -229,6 +230,9 @@ Wayland_PumpEvents(_THIS)
if (input) {
uint32_t now = SDL_GetTicks();
keyboard_repeat_handle(&input->keyboard_repeat, now);
if (input->text_input != NULL) {
input->text_input->got_text = SDL_FALSE;
}
}

if (SDL_IOReady(WAYLAND_wl_display_get_fd(d->display), SDL_FALSE, 0)) {
Expand Down Expand Up @@ -760,6 +764,7 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,

/* This will release any keys still pressed */
SDL_SetKeyboardFocus(NULL);

#ifdef SDL_USE_IME
SDL_IME_SetFocus(SDL_FALSE);
#endif
Expand Down Expand Up @@ -1224,6 +1229,97 @@ static const struct wl_data_device_listener data_device_listener = {
data_device_handle_selection
};

static void
text_input_enter(void *data,
struct zwp_text_input_v3 *zwp_text_input_v3,
struct wl_surface *surface)
{
/* No-op */
}

static void
text_input_leave(void *data,
struct zwp_text_input_v3 *zwp_text_input_v3,
struct wl_surface *surface)
{
/* No-op */
}

static void
text_input_preedit_string(void *data,
struct zwp_text_input_v3 *zwp_text_input_v3,
const char *text,
int32_t cursor_begin,
int32_t cursor_end)
{
struct SDL_WaylandTextInput *text_input = data;
char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
if (text) {
size_t text_bytes = SDL_strlen(text), i = 0;
size_t cursor = 0;

do {
const size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
const size_t chars = SDL_utf8strlen(buf);

SDL_SendEditingText(buf, cursor, chars);

i += sz;
cursor += chars;
} while (i < text_bytes);
} else {
buf[0] = '\0';
SDL_SendEditingText(buf, 0, 0);
}
text_input->got_text = SDL_TRUE;
}

static void
text_input_commit_string(void *data,
struct zwp_text_input_v3 *zwp_text_input_v3,
const char *text)
{
struct SDL_WaylandTextInput *text_input = data;
if (text && *text) {
char buf[SDL_TEXTINPUTEVENT_TEXT_SIZE];
size_t text_bytes = SDL_strlen(text), i = 0;

while (i < text_bytes) {
size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
SDL_SendKeyboardText(buf);

i += sz;
}
text_input->got_text = SDL_TRUE;
}
}

static void
text_input_delete_surrounding_text(void *data,
struct zwp_text_input_v3 *zwp_text_input_v3,
uint32_t before_length,
uint32_t after_length)
{
/* FIXME: Do we care about this event? */
}

static void
text_input_done(void *data,
struct zwp_text_input_v3 *zwp_text_input_v3,
uint32_t serial)
{
/* No-op */
}

static const struct zwp_text_input_v3_listener text_input_listener = {
text_input_enter,
text_input_leave,
text_input_preedit_string,
text_input_commit_string,
text_input_delete_surrounding_text,
text_input_done
};

static void
Wayland_create_data_device(SDL_VideoData *d)
{
Expand All @@ -1249,6 +1345,31 @@ Wayland_create_data_device(SDL_VideoData *d)
}
}

static void
Wayland_create_text_input(SDL_VideoData *d)
{
SDL_WaylandTextInput *text_input = NULL;

text_input = SDL_calloc(1, sizeof *text_input);
if (text_input == NULL) {
return;
}

text_input->text_input = zwp_text_input_manager_v3_get_text_input(
d->text_input_manager, d->input->seat
);
text_input->video_data = d;

if (text_input->text_input == NULL) {
SDL_free(text_input);
} else {
zwp_text_input_v3_set_user_data(text_input->text_input, text_input);
zwp_text_input_v3_add_listener(text_input->text_input,
&text_input_listener, text_input);
d->input->text_input = text_input;
}
}

void
Wayland_add_data_device_manager(SDL_VideoData *d, uint32_t id, uint32_t version)
{
Expand All @@ -1259,6 +1380,16 @@ Wayland_add_data_device_manager(SDL_VideoData *d, uint32_t id, uint32_t version)
}
}

void
Wayland_add_text_input_manager(SDL_VideoData *d, uint32_t id, uint32_t version)
{
d->text_input_manager = wl_registry_bind(d->registry, id, &zwp_text_input_manager_v3_interface, 1);

if (d->input != NULL) {
Wayland_create_text_input(d);
}
}

void
Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
{
Expand All @@ -1277,6 +1408,9 @@ Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
if (d->data_device_manager != NULL) {
Wayland_create_data_device(d);
}
if (d->text_input_manager != NULL) {
Wayland_create_text_input(d);
}

wl_seat_add_listener(input->seat, &seat_listener, input);
wl_seat_set_user_data(input->seat, input);
Expand Down Expand Up @@ -1305,6 +1439,11 @@ void Wayland_display_destroy_input(SDL_VideoData *d)
SDL_free(input->data_device);
}

if (input->text_input != NULL) {
zwp_text_input_v3_destroy(input->text_input->text_input);
SDL_free(input->text_input);
}

if (input->keyboard)
wl_keyboard_destroy(input->keyboard);

Expand Down
3 changes: 3 additions & 0 deletions src/video/wayland/SDL_waylandevents_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "SDL_waylandvideo.h"
#include "SDL_waylandwindow.h"
#include "SDL_waylanddatamanager.h"
#include "SDL_waylandkeyboard.h"

typedef struct {
// repeat_rate in range of [1, 1000]
Expand All @@ -47,6 +48,7 @@ struct SDL_WaylandInput {
struct wl_touch *touch;
struct wl_keyboard *keyboard;
SDL_WaylandDataDevice *data_device;
SDL_WaylandTextInput *text_input;
struct zwp_relative_pointer_v1 *relative_pointer;
struct zwp_confined_pointer_v1 *confined_pointer;
SDL_Window *confined_pointer_window;
Expand Down Expand Up @@ -83,6 +85,7 @@ struct SDL_WaylandInput {
extern void Wayland_PumpEvents(_THIS);

extern void Wayland_add_data_device_manager(SDL_VideoData *d, uint32_t id, uint32_t version);
extern void Wayland_add_text_input_manager(SDL_VideoData *d, uint32_t id, uint32_t version);

extern void Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version);
extern void Wayland_display_destroy_input(SDL_VideoData *d);
Expand Down
68 changes: 66 additions & 2 deletions src/video/wayland/SDL_waylandkeyboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

#include "../SDL_sysvideo.h"
#include "SDL_waylandvideo.h"
#include "SDL_waylandevents_c.h"
#include "text-input-unstable-v3-client-protocol.h"

int
Wayland_InitKeyboard(_THIS)
Expand All @@ -46,12 +48,52 @@ Wayland_QuitKeyboard(_THIS)
void
Wayland_StartTextInput(_THIS)
{
/* No-op */
SDL_VideoData *driverdata = _this->driverdata;

if (driverdata->text_input_manager) {
struct SDL_WaylandInput *input = driverdata->input;
if (input != NULL && input->text_input) {
const SDL_Rect *rect = &input->text_input->cursor_rect;

/* For some reason this has to be done twice, it appears to be a
* bug in mutter? Maybe?
* -flibit
*/
zwp_text_input_v3_enable(input->text_input->text_input);
zwp_text_input_v3_commit(input->text_input->text_input);
zwp_text_input_v3_enable(input->text_input->text_input);
zwp_text_input_v3_commit(input->text_input->text_input);

/* Now that it's enabled, set the input properties */
zwp_text_input_v3_set_content_type(input->text_input->text_input,
ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE,
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL);
if (!SDL_RectEmpty(rect)) {
/* This gets reset on enable so we have to cache it */
zwp_text_input_v3_set_cursor_rectangle(input->text_input->text_input,
rect->x,
rect->y,
rect->w,
rect->h);
}
zwp_text_input_v3_commit(input->text_input->text_input);
}
}
}

void
Wayland_StopTextInput(_THIS)
{
SDL_VideoData *driverdata = _this->driverdata;

if (driverdata->text_input_manager) {
struct SDL_WaylandInput *input = driverdata->input;
if (input != NULL && input->text_input) {
zwp_text_input_v3_disable(input->text_input->text_input);
zwp_text_input_v3_commit(input->text_input->text_input);
}
}

#ifdef SDL_USE_IME
SDL_IME_Reset();
#endif
Expand All @@ -60,16 +102,38 @@ Wayland_StopTextInput(_THIS)
void
Wayland_SetTextInputRect(_THIS, SDL_Rect *rect)
{
SDL_VideoData *driverdata = _this->driverdata;

if (!rect) {
SDL_InvalidParamError("rect");
return;
}


if (driverdata->text_input_manager) {
struct SDL_WaylandInput *input = driverdata->input;
if (input != NULL && input->text_input) {
SDL_memcpy(&input->text_input->cursor_rect, rect, sizeof(SDL_Rect));
zwp_text_input_v3_set_cursor_rectangle(input->text_input->text_input,
rect->x,
rect->y,
rect->w,
rect->h);
zwp_text_input_v3_commit(input->text_input->text_input);
}
}

#ifdef SDL_USE_IME
SDL_IME_UpdateTextRect(rect);
#endif
}

SDL_bool
Wayland_HasScreenKeyboardSupport(_THIS)
{
SDL_VideoData *driverdata = _this->driverdata;
return (driverdata->text_input_manager != NULL);
}

#endif /* SDL_VIDEO_DRIVER_WAYLAND */

/* vi: set ts=4 sw=4 expandtab: */
9 changes: 9 additions & 0 deletions src/video/wayland/SDL_waylandkeyboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,20 @@
#ifndef SDL_waylandkeyboard_h_
#define SDL_waylandkeyboard_h_

typedef struct SDL_WaylandTextInput
{
struct zwp_text_input_v3 *text_input;
SDL_bool got_text;
SDL_Rect cursor_rect;
SDL_VideoData *video_data;
} SDL_WaylandTextInput;

extern int Wayland_InitKeyboard(_THIS);
extern void Wayland_QuitKeyboard(_THIS);
extern void Wayland_StartTextInput(_THIS);
extern void Wayland_StopTextInput(_THIS);
extern void Wayland_SetTextInputRect(_THIS, SDL_Rect *rect);
extern SDL_bool Wayland_HasScreenKeyboardSupport(_THIS);

#endif /* SDL_waylandkeyboard_h_ */

Expand Down
11 changes: 9 additions & 2 deletions src/video/wayland/SDL_waylandvideo.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "xdg-activation-v1-client-protocol.h"
#include "text-input-unstable-v3-client-protocol.h"

#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
Expand Down Expand Up @@ -253,6 +254,7 @@ Wayland_CreateDevice(int devindex)
device->DestroyWindow = Wayland_DestroyWindow;
device->SetWindowHitTest = Wayland_SetWindowHitTest;
device->FlashWindow = Wayland_FlashWindow;
device->HasScreenKeyboardSupport = Wayland_HasScreenKeyboardSupport;

device->SetClipboardText = Wayland_SetClipboardText;
device->GetClipboardText = Wayland_GetClipboardText;
Expand Down Expand Up @@ -507,6 +509,8 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
d->idle_inhibit_manager = wl_registry_bind(d->registry, id, &zwp_idle_inhibit_manager_v1_interface, 1);
} else if (SDL_strcmp(interface, "xdg_activation_v1") == 0) {
d->activation_manager = wl_registry_bind(d->registry, id, &xdg_activation_v1_interface, 1);
} else if (strcmp(interface, "zwp_text_input_manager_v3") == 0) {
Wayland_add_text_input_manager(d, id, version);
} else if (SDL_strcmp(interface, "wl_data_device_manager") == 0) {
Wayland_add_data_device_manager(d, id, version);
} else if (SDL_strcmp(interface, "zxdg_decoration_manager_v1") == 0) {
Expand Down Expand Up @@ -642,6 +646,11 @@ Wayland_VideoQuit(_THIS)
if (data->key_inhibitor_manager)
zwp_keyboard_shortcuts_inhibit_manager_v1_destroy(data->key_inhibitor_manager);

Wayland_QuitKeyboard(_this);

if (data->text_input_manager)
zwp_text_input_manager_v3_destroy(data->text_input_manager);

if (data->xkb_context) {
WAYLAND_xkb_context_unref(data->xkb_context);
data->xkb_context = NULL;
Expand Down Expand Up @@ -684,8 +693,6 @@ Wayland_VideoQuit(_THIS)
if (data->registry)
wl_registry_destroy(data->registry);

Wayland_QuitKeyboard(_this);

SDL_free(data->classname);
}

Expand Down
1 change: 1 addition & 0 deletions src/video/wayland/SDL_waylandvideo.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ typedef struct {
struct zwp_keyboard_shortcuts_inhibit_manager_v1 *key_inhibitor_manager;
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager;
struct xdg_activation_v1 *activation_manager;
struct zwp_text_input_manager_v3 *text_input_manager;

EGLDisplay edpy;
EGLContext context;
Expand Down
Loading

0 comments on commit acc336d

Please sign in to comment.