]> git.mdlowis.com Git - proto/labwc.git/commitdiff
IME: support multiple IME popups
authortokyo4j <hrak1529@gmail.com>
Thu, 16 May 2024 05:57:31 +0000 (14:57 +0900)
committerHiroaki Yamamoto <hrak1529@gmail.com>
Mon, 20 May 2024 00:35:26 +0000 (09:35 +0900)
We didn't support multiple IME popups since input-method-v2 protocol
has no way to position them individually, but we should support it to
provide IME developers with more programming flexibility.

include/input/ime.h
src/input/ime.c

index 06dd16ff86c3c85d1a88b345f4b1043485e2eeab..189f51f152176d51ac4d830bacc51e2c124c1931 100644 (file)
@@ -29,7 +29,7 @@ struct input_method_relay {
         */
        struct text_input *active_text_input;
 
-       struct wlr_input_popup_surface_v2 *popup_surface;
+       struct wl_list popups; /* input_method_popup.link */
        struct wlr_scene_tree *popup_tree;
 
        struct wl_listener new_text_input;
@@ -40,13 +40,20 @@ struct input_method_relay {
        struct wl_listener input_method_destroy;
        struct wl_listener input_method_new_popup_surface;
 
-       struct wl_listener popup_surface_destroy;
-       struct wl_listener popup_surface_commit;
-
        struct wl_listener keyboard_grab_destroy;
        struct wl_listener focused_surface_destroy;
 };
 
+struct input_method_popup {
+       struct wlr_input_popup_surface_v2 *popup_surface;
+       struct wlr_scene_tree *tree;
+       struct input_method_relay *relay;
+       struct wl_list link; /* input_method_relay.popups */
+
+       struct wl_listener destroy;
+       struct wl_listener commit;
+};
+
 struct text_input {
        struct input_method_relay *relay;
        struct wlr_text_input_v3 *input;
index b3d6410d6eff60d10753c99034d028e1e0d38b90..9f57e5303140c5744c1a33d4609510540c48af07 100644 (file)
@@ -164,13 +164,14 @@ update_text_inputs_focused_surface(struct input_method_relay *relay)
 }
 
 static void
-update_popup_position(struct input_method_relay *relay)
+update_popup_position(struct input_method_popup *popup)
 {
+       struct input_method_relay *relay = popup->relay;
        struct server *server = relay->seat->server;
        struct text_input *text_input = relay->active_text_input;
 
-       if (!text_input || !relay->focused_surface || !relay->popup_surface
-                       || !relay->popup_surface->surface->mapped) {
+       if (!text_input || !relay->focused_surface
+                       || !popup->popup_surface->surface->mapped) {
                return;
        }
 
@@ -225,8 +226,8 @@ update_popup_position(struct input_method_relay *relay)
                .anchor = XDG_POSITIONER_ANCHOR_BOTTOM_LEFT,
                .gravity = XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT,
                .size = {
-                       .width = relay->popup_surface->surface->current.width,
-                       .height = relay->popup_surface->surface->current.height,
+                       .width = popup->popup_surface->surface->current.width,
+                       .height = popup->popup_surface->surface->current.height,
                },
                .constraint_adjustment =
                        XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y
@@ -238,12 +239,12 @@ update_popup_position(struct input_method_relay *relay)
        wlr_xdg_positioner_rules_unconstrain_box(&rules, &output_box, &popup_box);
 
        wlr_scene_node_set_position(
-               &relay->popup_tree->node, popup_box.x, popup_box.y);
-       /* Make sure IME popup is always on top, above layer-shell surfaces */
+               &popup->tree->node, popup_box.x, popup_box.y);
+       /* Make sure IME popups are always on top, above layer-shell surfaces */
        wlr_scene_node_raise_to_top(&relay->popup_tree->node);
 
        wlr_input_popup_surface_v2_send_text_input_rectangle(
-               relay->popup_surface, &(struct wlr_box){
+               popup->popup_surface, &(struct wlr_box){
                        .x = cursor_rect.x - popup_box.x,
                        .y = cursor_rect.y - popup_box.y,
                        .width = cursor_rect.width,
@@ -251,6 +252,15 @@ update_popup_position(struct input_method_relay *relay)
                });
 }
 
+static void
+update_popups_position(struct input_method_relay *relay)
+{
+       struct input_method_popup *popup;
+       wl_list_for_each(popup, &relay->popups, link) {
+               update_popup_position(popup);
+       }
+}
+
 static void
 handle_input_method_commit(struct wl_listener *listener, void *data)
 {
@@ -342,20 +352,20 @@ handle_input_method_destroy(struct wl_listener *listener, void *data)
 static void
 handle_popup_surface_destroy(struct wl_listener *listener, void *data)
 {
-       struct input_method_relay *relay =
-               wl_container_of(listener, relay, popup_surface_destroy);
-       wl_list_remove(&relay->popup_surface_destroy.link);
-       wl_list_remove(&relay->popup_surface_commit.link);
-       relay->popup_surface = NULL;
-       relay->popup_tree = NULL;
+       struct input_method_popup *popup =
+               wl_container_of(listener, popup, destroy);
+       wl_list_remove(&popup->destroy.link);
+       wl_list_remove(&popup->commit.link);
+       wl_list_remove(&popup->link);
+       free(popup);
 }
 
 static void
 handle_popup_surface_commit(struct wl_listener *listener, void *data)
 {
-       struct input_method_relay *relay =
-               wl_container_of(listener, relay, popup_surface_commit);
-       update_popup_position(relay);
+       struct input_method_popup *popup =
+               wl_container_of(listener, popup, commit);
+       update_popup_position(popup);
 }
 
 static void
@@ -364,32 +374,22 @@ handle_input_method_new_popup_surface(struct wl_listener *listener, void *data)
        struct input_method_relay *relay = wl_container_of(listener, relay,
                input_method_new_popup_surface);
 
-       if (relay->popup_surface) {
-               /*
-                * With current input-method-v2 protocol, creating multiple IME
-                * popups is not useful because they just stack up at the same
-                * position.
-                *
-                * Discussed here:
-                * https://gitlab.freedesktop.org/wayland/wayland-protocols/-/issues/40#note_847039
-                */
-               wlr_log(WLR_INFO,
-                       "Creating multiple IME popups is not supported");
-               return;
-       }
+       struct input_method_popup *popup = znew(*popup);
+       popup->popup_surface = data;
+       popup->relay = relay;
+
+       popup->destroy.notify = handle_popup_surface_destroy;
+       wl_signal_add(&popup->popup_surface->events.destroy, &popup->destroy);
 
-       relay->popup_surface = data;
+       popup->commit.notify = handle_popup_surface_commit;
+       wl_signal_add(&popup->popup_surface->surface->events.commit,
+               &popup->commit);
 
-       wl_signal_add(&relay->popup_surface->events.destroy,
-               &relay->popup_surface_destroy);
-       wl_signal_add(&relay->popup_surface->surface->events.commit,
-               &relay->popup_surface_commit);
+       popup->tree = wlr_scene_subsurface_tree_create(
+               relay->popup_tree, popup->popup_surface->surface);
+       node_descriptor_create(&popup->tree->node, LAB_NODE_DESC_IME_POPUP, NULL);
 
-       relay->popup_tree = wlr_scene_subsurface_tree_create(
-               &relay->seat->server->scene->tree,
-               relay->popup_surface->surface);
-       node_descriptor_create(
-               &relay->popup_tree->node, LAB_NODE_DESC_IME_POPUP, NULL);
+       wl_list_insert(&relay->popups, &popup->link);
 }
 
 static void
@@ -469,7 +469,7 @@ handle_text_input_enable(struct wl_listener *listener, void *data)
 
        update_active_text_input(relay);
        if (relay->active_text_input == text_input) {
-               update_popup_position(relay);
+               update_popups_position(relay);
                send_state_to_input_method(relay);
        }
 }
@@ -495,7 +495,7 @@ handle_text_input_commit(struct wl_listener *listener, void *data)
        struct input_method_relay *relay = text_input->relay;
 
        if (relay->active_text_input == text_input) {
-               update_popup_position(relay);
+               update_popups_position(relay);
                send_state_to_input_method(relay);
        }
 }
@@ -565,6 +565,8 @@ input_method_relay_create(struct seat *seat)
        struct input_method_relay *relay = znew(*relay);
        relay->seat = seat;
        wl_list_init(&relay->text_inputs);
+       wl_list_init(&relay->popups);
+       relay->popup_tree = wlr_scene_tree_create(&seat->server->scene->tree);
 
        relay->new_text_input.notify = handle_new_text_input;
        wl_signal_add(&seat->server->text_input_manager->events.text_input,
@@ -575,8 +577,6 @@ input_method_relay_create(struct seat *seat)
                &relay->new_input_method);
 
        relay->focused_surface_destroy.notify = handle_focused_surface_destroy;
-       relay->popup_surface_destroy.notify = handle_popup_surface_destroy;
-       relay->popup_surface_commit.notify = handle_popup_surface_commit;
 
        return relay;
 }