Skip to content

Commit

Permalink
Implement input_method_v2 popups
Browse files Browse the repository at this point in the history
  • Loading branch information
tadeokondrak committed Dec 16, 2020
1 parent a33c796 commit e399a4c
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 1 deletion.
2 changes: 1 addition & 1 deletion include/log.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,6 @@ bool _sway_assert(bool condition, const char* format, ...) ATTRIB_PRINTF(2, 3);
_sway_abort("[%s:%d] " FMT, _SWAY_FILENAME, __LINE__, ##__VA_ARGS__)

#define sway_assert(COND, FMT, ...) \
_sway_assert(COND, "[%s:%d] %s:" FMT, _SWAY_FILENAME, __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__)
_sway_assert(COND, "[%s:%d] %s: " FMT, _SWAY_FILENAME, __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__)

#endif
17 changes: 17 additions & 0 deletions include/sway/input/text_input.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,35 @@ struct sway_input_method_relay {
struct sway_seat *seat;

struct wl_list text_inputs; // sway_text_input::link
struct wl_list input_popups; // sway_input_popup::link
struct wlr_input_method_v2 *input_method; // doesn't have to be present

struct wl_listener text_input_new;

struct wl_listener input_method_new;
struct wl_listener input_method_commit;
struct wl_listener input_method_popup_surface;
struct wl_listener input_method_grab_keyboard;
struct wl_listener input_method_destroy;

struct wl_listener input_method_keyboard_grab_destroy;
};

struct sway_input_popup {
struct sway_input_method_relay *relay;
struct wlr_input_popup_surface_v2 *popup_surface;
struct sway_text_input *text_input;

int x, y;

struct wl_list link;

struct wl_listener popup_map;
struct wl_listener popup_unmap;
struct wl_listener popup_destroy;
struct wl_listener popup_surface_commit;
};

struct sway_text_input {
struct sway_input_method_relay *relay;

Expand Down
33 changes: 33 additions & 0 deletions sway/desktop/render.c
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,37 @@ static void render_seatops(struct sway_output *output,
}
}

static void render_im_popups(struct sway_output *output,
pixman_region32_t *damage) {
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
struct sway_input_popup *popup;
wl_list_for_each(popup, &seat->im_relay.input_popups, link) {
if (!popup->popup_surface->mapped) {
continue;
}
struct render_data data = {
.damage = damage,
.alpha = 1.0f,
};
struct sway_view *view = view_from_wlr_surface(
popup->text_input->input->focused_surface);
struct wlr_surface *popup_surface =
popup->popup_surface->surface;
struct wlr_box box = {
.x = output->lx + view->geometry.x
+ view->container->surface_x + popup->x,
.y = output->ly + view->geometry.y
+ view->container->surface_y + popup->y,
.width = popup_surface->current.width,
.height = popup_surface->current.height,
};
render_surface_iterator(output, view,
popup->popup_surface->surface, &box, 0.0, &data);
}
}
}

void output_render(struct sway_output *output, struct timespec *when,
pixman_region32_t *damage) {
struct wlr_output *wlr_output = output->wlr_output;
Expand Down Expand Up @@ -1097,6 +1128,8 @@ void output_render(struct sway_output *output, struct timespec *when,
render_view_popups(focus->view, output, damage, focus->alpha);
}

render_im_popups(output, damage);

render_overlay:
render_layer_toplevel(output, damage,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]);
Expand Down
135 changes: 135 additions & 0 deletions sway/input/text_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
#include "log.h"
#include "sway/input/seat.h"
#include "sway/input/text_input.h"
#include "sway/tree/view.h"
#include "sway/tree/container.h"
#include "sway/tree/workspace.h"
#include "sway/desktop.h"
#include "sway/output.h"

static struct sway_text_input *relay_get_focusable_text_input(
struct sway_input_method_relay *relay) {
Expand All @@ -26,6 +31,98 @@ static struct sway_text_input *relay_get_focused_text_input(
return NULL;
}

static void input_popup_damage(struct sway_input_popup *popup) {
if (!popup->popup_surface->mapped) {
return;
}
desktop_damage_surface(popup->popup_surface->surface,
popup->x, popup->y, true);
if (popup->text_input == NULL ||
popup->text_input->input->focused_surface == NULL) {
return;
}

struct sway_view *view =
view_from_wlr_surface(popup->text_input->input->focused_surface);
desktop_damage_view(view);
}

static void input_popup_update(struct sway_input_popup *popup) {
input_popup_damage(popup);

if (popup->text_input == NULL ||
popup->text_input->input->focused_surface == NULL) {
return;
}

struct sway_view *view =
view_from_wlr_surface(popup->text_input->input->focused_surface);
if (view == NULL) {
return;
}

struct wlr_box cursor_rectangle =
popup->text_input->input->current.cursor_rectangle;
popup->x = cursor_rectangle.x;
popup->y = cursor_rectangle.y + cursor_rectangle.height;

input_popup_damage(popup);
}

static void handle_im_popup_map(struct wl_listener *listener, void *data) {
struct sway_input_popup *popup =
wl_container_of(listener, popup, popup_map);
input_popup_damage(popup);
}

static void handle_im_popup_unmap(struct wl_listener *listener, void *data) {
struct sway_input_popup *popup =
wl_container_of(listener, popup, popup_unmap);
input_popup_damage(popup);
}

static void handle_im_popup_destroy(struct wl_listener *listener, void *data) {
struct sway_input_popup *popup =
wl_container_of(listener, popup, popup_destroy);
popup->popup_surface->data = NULL;
wl_list_remove(&popup->popup_surface_commit.link);
wl_list_remove(&popup->popup_destroy.link);
wl_list_remove(&popup->popup_unmap.link);
wl_list_remove(&popup->popup_map.link);
if (popup->text_input != NULL) {
}
wl_list_remove(&popup->link);
free(popup);
}

static void handle_im_popup_surface_commit(struct wl_listener *listener,
void *data) {
struct sway_input_popup *popup =
wl_container_of(listener, popup, popup_surface_commit);
input_popup_update(popup);
}

static void handle_im_popup(struct wl_listener *listener, void *data) {
struct sway_input_method_relay *relay = wl_container_of(listener, relay,
input_method_popup_surface);
struct sway_input_popup *popup = calloc(1, sizeof(*popup));
popup->relay = relay;
popup->popup_surface = data;
popup->popup_surface->data = popup;
wl_signal_add(&popup->popup_surface->events.map, &popup->popup_map);
popup->popup_map.notify = handle_im_popup_map;
wl_signal_add(
&popup->popup_surface->events.unmap, &popup->popup_unmap);
popup->popup_unmap.notify = handle_im_popup_unmap;
wl_signal_add(
&popup->popup_surface->events.destroy, &popup->popup_destroy);
popup->popup_destroy.notify = handle_im_popup_destroy;
wl_signal_add(&popup->popup_surface->surface->events.destroy,
&popup->popup_surface_commit);
popup->popup_surface_commit.notify = handle_im_popup_surface_commit;
wl_list_insert(&relay->input_popups, &popup->link);
}

static void handle_im_commit(struct wl_listener *listener, void *data) {
struct sway_input_method_relay *relay = wl_container_of(listener, relay,
input_method_commit);
Expand Down Expand Up @@ -53,6 +150,13 @@ static void handle_im_commit(struct wl_listener *listener, void *data) {
context->current.delete.after_length);
}
wlr_text_input_v3_send_done(text_input->input);

struct sway_input_popup *popup;
wl_list_for_each(popup, &text_input->relay->input_popups, link) {
if (popup->text_input == text_input) {
input_popup_update(popup);
}
}
}

static void handle_im_keyboard_grab_destroy(struct wl_listener *listener, void *data) {
Expand Down Expand Up @@ -85,6 +189,7 @@ static void handle_im_grab_keyboard(struct wl_listener *listener, void *data) {
relay->input_method_keyboard_grab_destroy.notify =
handle_im_keyboard_grab_destroy;
}

static void text_input_set_pending_focused_surface(
struct sway_text_input *text_input, struct wlr_surface *surface) {
wl_list_remove(&text_input->pending_focused_surface_destroy.link);
Expand Down Expand Up @@ -140,8 +245,15 @@ static void handle_text_input_enable(struct wl_listener *listener, void *data) {
sway_log(SWAY_INFO, "Enabling text input when input method is gone");
return;
}

wlr_input_method_v2_send_activate(text_input->relay->input_method);
relay_send_im_state(text_input->relay, text_input->input);

struct sway_input_popup *popup;
wl_list_for_each(popup, &text_input->relay->input_popups, link) {
popup->text_input = text_input;
input_popup_update(popup);
}
}

static void handle_text_input_commit(struct wl_listener *listener,
Expand All @@ -158,6 +270,14 @@ static void handle_text_input_commit(struct wl_listener *listener,
return;
}
relay_send_im_state(text_input->relay, text_input->input);

// Text location may have changed, update popup
struct sway_input_popup *popup;
wl_list_for_each(popup, &text_input->relay->input_popups, link) {
if (popup->text_input == text_input) {
input_popup_update(popup);
}
}
}

static void relay_disable_text_input(struct sway_input_method_relay *relay,
Expand All @@ -166,6 +286,17 @@ static void relay_disable_text_input(struct sway_input_method_relay *relay,
sway_log(SWAY_DEBUG, "Disabling text input, but input method is gone");
return;
}
if (text_input->input->focused_surface == NULL) {
return;
}

struct sway_input_popup *popup;
wl_list_for_each(popup, &text_input->relay->input_popups, link) {
if (popup->text_input == text_input) {
popup->text_input = NULL;
}
}

wlr_input_method_v2_send_deactivate(relay->input_method);
relay_send_im_state(relay, text_input->input);
}
Expand Down Expand Up @@ -266,6 +397,9 @@ static void relay_handle_input_method(struct wl_listener *listener,
wl_signal_add(&relay->input_method->events.commit,
&relay->input_method_commit);
relay->input_method_commit.notify = handle_im_commit;
wl_signal_add(&relay->input_method->events.popup_surface,
&relay->input_method_popup_surface);
relay->input_method_popup_surface.notify = handle_im_popup;
wl_signal_add(&relay->input_method->events.grab_keyboard,
&relay->input_method_grab_keyboard);
relay->input_method_grab_keyboard.notify = handle_im_grab_keyboard;
Expand All @@ -285,6 +419,7 @@ void sway_input_method_relay_init(struct sway_seat *seat,
struct sway_input_method_relay *relay) {
relay->seat = seat;
wl_list_init(&relay->text_inputs);
wl_list_init(&relay->input_popups);

relay->text_input_new.notify = relay_handle_text_input;
wl_signal_add(&server.text_input->events.text_input,
Expand Down

0 comments on commit e399a4c

Please sign in to comment.