diff --git a/include/wlr/types/wlr_text_input_v3.h b/include/wlr/types/wlr_text_input_v3.h index 29feb7e6c..82578c8dd 100644 --- a/include/wlr/types/wlr_text_input_v3.h +++ b/include/wlr/types/wlr_text_input_v3.h @@ -21,6 +21,16 @@ enum wlr_text_input_v3_features { WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE = 1 << 2, }; +enum wlr_text_input_v3_commit_type { + WLR_TEXT_INPUT_V3_COMMIT_TYPE_NONE = 0, + WLR_TEXT_INPUT_V3_COMMIT_TYPE_ENABLE, + WLR_TEXT_INPUT_V3_COMMIT_TYPE_DISABLE, +}; + +struct wlr_text_input_v3_commit_event { + enum wlr_text_input_v3_commit_type type; +}; + struct wlr_text_input_v3_state { struct { char *text; // NULL is allowed and equivalent to empty string @@ -49,17 +59,15 @@ struct wlr_text_input_v3 { struct wlr_text_input_v3_state pending; struct wlr_text_input_v3_state current; uint32_t current_serial; // next in line to send - bool pending_enabled; - bool current_enabled; + enum wlr_text_input_v3_commit_type next_commit_type; + bool enabled; // supported in the current text input, more granular than surface uint32_t active_features; // bitfield of enum wlr_text_input_v3_features struct wl_list link; struct { - struct wl_signal enable; - struct wl_signal commit; - struct wl_signal disable; + struct wl_signal commit; // struct wlr_text_input_v3_commit_event struct wl_signal destroy; } events; diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index e460bbb63..73f440d29 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -164,6 +164,7 @@ struct wlr_xwm { struct wl_listener drop_focus_destroy; }; +// xwm_create takes ownership of wm_fd and will close it under all circumstances. struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland, int wm_fd); void xwm_destroy(struct wlr_xwm *xwm); diff --git a/types/wlr_text_input_v3.c b/types/wlr_text_input_v3.c index bbae3a076..87841a6b1 100644 --- a/types/wlr_text_input_v3.c +++ b/types/wlr_text_input_v3.c @@ -66,9 +66,7 @@ void wlr_text_input_v3_send_done(struct wlr_text_input_v3 *text_input) { static void wlr_text_input_destroy(struct wlr_text_input_v3 *text_input) { wl_signal_emit_mutable(&text_input->events.destroy, NULL); - assert(wl_list_empty(&text_input->events.enable.listener_list)); assert(wl_list_empty(&text_input->events.commit.listener_list)); - assert(wl_list_empty(&text_input->events.disable.listener_list)); assert(wl_list_empty(&text_input->events.destroy.listener_list)); text_input_clear_focused_surface(text_input); @@ -102,7 +100,7 @@ static void text_input_enable(struct wl_client *client, struct wlr_text_input_v3_state defaults = {0}; free(text_input->pending.surrounding.text); text_input->pending = defaults; - text_input->pending_enabled = true; + text_input->next_commit_type = WLR_TEXT_INPUT_V3_COMMIT_TYPE_ENABLE; } static void text_input_disable(struct wl_client *client, @@ -111,7 +109,7 @@ static void text_input_disable(struct wl_client *client, if (!text_input) { return; } - text_input->pending_enabled = false; + text_input->next_commit_type = WLR_TEXT_INPUT_V3_COMMIT_TYPE_DISABLE; } static void text_input_set_surrounding_text(struct wl_client *client, @@ -182,23 +180,27 @@ static void text_input_commit(struct wl_client *client, } } - bool old_enabled = text_input->current_enabled; - text_input->current_enabled = text_input->pending_enabled; text_input->current_serial++; if (text_input->focused_surface == NULL) { wlr_log(WLR_DEBUG, "Text input commit received without focus"); } - if (!old_enabled && text_input->current_enabled) { - text_input->active_features = text_input->current.features; - wl_signal_emit_mutable(&text_input->events.enable, NULL); - } else if (old_enabled && !text_input->current_enabled) { - text_input->active_features = 0; - wl_signal_emit_mutable(&text_input->events.disable, NULL); - } else { // including never enabled - wl_signal_emit_mutable(&text_input->events.commit, NULL); - } + enum wlr_text_input_v3_commit_type commit_type = text_input->next_commit_type; + text_input->next_commit_type = WLR_TEXT_INPUT_V3_COMMIT_TYPE_NONE; + + if (commit_type == WLR_TEXT_INPUT_V3_COMMIT_TYPE_ENABLE) { + text_input->active_features = text_input->current.features; + text_input->enabled = true; + } else if (commit_type == WLR_TEXT_INPUT_V3_COMMIT_TYPE_DISABLE) { + text_input->active_features = 0; + text_input->enabled = false; + } + + struct wlr_text_input_v3_commit_event event = { + .type = commit_type, + }; + wl_signal_emit_mutable(&text_input->events.commit, &event); } static const struct zwp_text_input_v3_interface text_input_impl = { @@ -265,9 +267,7 @@ static void text_input_manager_get_text_input(struct wl_client *client, return; } - wl_signal_init(&text_input->events.enable); wl_signal_init(&text_input->events.commit); - wl_signal_init(&text_input->events.disable); wl_signal_init(&text_input->events.destroy); text_input->resource = text_input_resource; diff --git a/xwayland/xwayland.c b/xwayland/xwayland.c index 5d51df074..3aa47bac2 100644 --- a/xwayland/xwayland.c +++ b/xwayland/xwayland.c @@ -42,6 +42,9 @@ static void handle_server_start(struct wl_listener *listener, void *data) { static void xwayland_mark_ready(struct wlr_xwayland *xwayland) { assert(xwayland->server->wm_fd[0] >= 0); xwayland->xwm = xwm_create(xwayland, xwayland->server->wm_fd[0]); + // xwm_create takes ownership of wm_fd[0] under all circumstances + xwayland->server->wm_fd[0] = -1; + if (!xwayland->xwm) { return; } diff --git a/xwayland/xwm.c b/xwayland/xwm.c index a82e8b145..2bb4e4c64 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -2530,6 +2530,7 @@ void xwm_set_cursor(struct wlr_xwm *xwm, const uint8_t *pixels, uint32_t stride, struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) { struct wlr_xwm *xwm = calloc(1, sizeof(*xwm)); if (xwm == NULL) { + close(wm_fd); return NULL; } @@ -2544,11 +2545,13 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) { xwm->ping_timeout = 10000; + // xcb_connect_to_fd takes ownership of the FD regardless of success/failure xwm->xcb_conn = xcb_connect_to_fd(wm_fd, NULL); int rc = xcb_connection_has_error(xwm->xcb_conn); if (rc) { wlr_log(WLR_ERROR, "xcb connect failed: %d", rc); + xcb_disconnect(xwm->xcb_conn); free(xwm); return NULL; }