From e1cf7db447a9c1a944eba060478185f35ea179a8 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 12 Mar 2025 10:53:30 +0800 Subject: [PATCH] feat: use keyboard group and support select close animaiton type --- IM.h | 1062 +++++++++++++++++++++++------------------------ README.md | 28 +- config.conf | 12 +- maomao.c | 487 ++++++++++++---------- parse_config.h | 30 +- preset_config.h | 4 +- 6 files changed, 856 insertions(+), 767 deletions(-) diff --git a/IM.h b/IM.h index f1bd9ad7..4c1c61ed 100644 --- a/IM.h +++ b/IM.h @@ -1,7 +1,11 @@ #ifdef IM #include -#include #include +#include + +#ifdef HANDWRITE +#include +#endif /** * The relay structure manages the relationship between text-input and @@ -19,291 +23,308 @@ // 但这个代码最初是日本人从sway那边抄过来的,sway的架构比较大,我猜会不会是考虑到会有两个input_method实例才这么定义 // 为了考虑万一以后哪个版本要扩充,就保留外层的结构 struct dwl_input_method_relay { - struct wl_list text_inputs; // dwl_text_input::link - struct wlr_input_method_v2 *input_method; // doesn't have to be present + struct wl_list text_inputs; // dwl_text_input::link + struct wlr_input_method_v2 *input_method; // doesn't have to be present - struct dwl_input_popup *popup; + struct dwl_input_popup *popup; - struct wl_listener text_input_new; + struct wl_listener text_input_new; - struct wl_listener input_method_new; - struct wl_listener input_method_commit; - struct wl_listener input_method_destroy; - struct wl_listener input_method_new_popup_surface; - struct wl_listener input_method_grab_keyboard; - struct wl_listener input_method_keyboard_grab_destroy; + struct wl_listener input_method_new; + struct wl_listener input_method_commit; + struct wl_listener input_method_destroy; + struct wl_listener input_method_new_popup_surface; + struct wl_listener input_method_grab_keyboard; + struct wl_listener input_method_keyboard_grab_destroy; }; struct dwl_text_input { - struct dwl_input_method_relay *relay; + struct dwl_input_method_relay *relay; - struct wlr_text_input_v3 *input; - // The surface getting seat's focus. Stored for when text-input cannot - // be sent an enter event immediately after getting focus, e.g. when - // there's no input method available. Cleared once text-input is entered. - struct wlr_surface *pending_focused_surface; + struct wlr_text_input_v3 *input; + // The surface getting seat's focus. Stored for when text-input cannot + // be sent an enter event immediately after getting focus, e.g. when + // there's no input method available. Cleared once text-input is entered. + struct wlr_surface *pending_focused_surface; - struct wl_list link; + struct wl_list link; - struct wl_listener pending_focused_surface_destroy; + struct wl_listener pending_focused_surface_destroy; - struct wl_listener text_input_enable; - // struct wl_listener text_input_commit; - // struct wl_listener text_input_disable; - struct wl_listener text_input_destroy; + struct wl_listener text_input_enable; + //struct wl_listener text_input_commit; + //struct wl_listener text_input_disable; + struct wl_listener text_input_destroy; }; + struct dwl_input_popup { - struct dwl_input_method_relay *relay; - struct wlr_input_popup_surface_v2 *popup_surface; + struct dwl_input_method_relay *relay; + struct wlr_input_popup_surface_v2 *popup_surface; - // struct wlr_scene_node *scene; - struct wlr_scene_tree *scene; - // struct wlr_scene_node *scene_surface; - struct wlr_scene_tree *scene_surface; + //struct wlr_scene_node *scene; + struct wlr_scene_tree *scene; + //struct wlr_scene_node *scene_surface; + struct wlr_scene_tree *scene_surface; - int x, y; - bool visible; + int x, y; + bool visible; - struct wl_listener popup_map; - struct wl_listener popup_unmap; - struct wl_listener popup_destroy; - // struct wl_listener popup_surface_commit; - // struct wl_listener focused_surface_unmap; + + struct wl_listener popup_map; + struct wl_listener popup_unmap; + struct wl_listener popup_destroy; + //struct wl_listener popup_surface_commit; + //struct wl_listener focused_surface_unmap; }; + void dwl_input_method_relay_init(struct dwl_input_method_relay *relay); // Updates currently focused surface. Surface must belong to the same // seat. void dwl_input_method_relay_set_focus(struct dwl_input_method_relay *relay, - struct wlr_surface *surface); + struct wlr_surface *surface); static void handle_im_grab_keyboard(struct wl_listener *listener, void *data); static void handle_im_keyboard_grab_destroy(struct wl_listener *listener, void *data); static void input_popup_update(struct dwl_input_popup *popup); +static struct dwl_text_input *relay_get_focused_text_input(struct dwl_input_method_relay *relay); struct wlr_input_method_manager_v2 *input_method_manager; struct wlr_text_input_manager_v3 *text_input_manager; struct dwl_input_method_relay *input_relay; +// static int NO_printstatus=0; // i suspect that printstatus will make dwl hang with fcitx5 + +#ifdef HANDWRITE +static void receive_handwrite_text_from_handwrite_input_app(struct wl_client *client, struct wl_resource *resource, const char *text){ + struct dwl_text_input *text_input; + + wlr_log(WLR_INFO,"receive_handwrite_text_from_handwrite_input_app called with:%s",text); + text_input = relay_get_focused_text_input(input_relay); + + if (text_input){ + wlr_log(WLR_INFO,"receive_handwrite_text_from_handwrite_input_app will commit %s",text); + wlr_text_input_v3_send_commit_string(text_input->input,text); + wlr_text_input_v3_send_done(text_input->input); + }else wlr_log(WLR_INFO, "no focused text_input for handwrite"); +} + +const struct zwp_handwrite_v1_interface handwrite_interface_impl = { + .send_handwrite_text = receive_handwrite_text_from_handwrite_input_app, +}; + +// struct wl_client* handwrite_app=NULL;//TODO: multiple handwrite app instance? +// void zwp_handwrite_v1_handle_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id){ +// wlr_log(WLR_INFO,"zwp_handwrite_v1_handle_bind called"); +// handwrite_app = client; +// struct wl_resource *resource = wl_resource_create(client, &zwp_handwrite_v1_interface, zwp_handwrite_v1_interface.version, id); +// wl_resource_set_implementation(resource, &handwrite_interface_impl, NULL, NULL); +// } +#endif + + /** * Get keyboard grab of the seat from sway_keyboard if we should forward events * to it. * * Returns NULL if the keyboard is not grabbed by an input method, - * or if event is from virtual keyboard of the same client as grab. - * TODO: see https://github.com/swaywm/wlroots/issues/2322 + * or if event is from virtual keyboard */ -static struct wlr_input_method_keyboard_grab_v2 * -keyboard_get_im_grab(Keyboard *kb) { - struct wlr_input_method_v2 *input_method = input_relay->input_method; - struct wlr_virtual_keyboard_v1 *virtual_keyboard = - wlr_input_device_get_virtual_keyboard(&kb->wlr_keyboard->base); - if (!input_method || !input_method->keyboard_grab || - (virtual_keyboard && - wl_resource_get_client(virtual_keyboard->resource) == - wl_resource_get_client(input_method->keyboard_grab->resource))) { - if (!input_method) { - wlr_log(WLR_DEBUG, - "keypress keyboard_get_im_grab return NULL:no input_method"); - } else if (!input_method->keyboard_grab) { - wlr_log(WLR_DEBUG, "keypress keyboard_get_im_grab return NULL:no " - "input_method->keyboard_grab"); - } +static struct wlr_input_method_keyboard_grab_v2 *keyboard_get_im_grab(KeyboardGroup* kb) { + struct wlr_input_method_v2 *input_method = input_relay->input_method; - if (virtual_keyboard) { - wlr_log(WLR_DEBUG, - "keypress keyboard_get_im_grab return NULL:virtual_keyboard"); - } - - return NULL; - } - return input_method->keyboard_grab; + if (!input_method){ + wlr_log(WLR_DEBUG, "keypress keyboard_get_im_grab return NULL:no input_method"); + return NULL; + } else if (!input_method->keyboard_grab){ + wlr_log(WLR_DEBUG, "keypress keyboard_get_im_grab return NULL:no input_method->keyboard_grab"); + return NULL; + } else if (kb != kb_group) { + wlr_log(WLR_DEBUG, "keypress keyboard_get_im_grab return NULL:virtual_keyboard"); + return NULL; + } else return input_method->keyboard_grab; } static void handle_im_grab_keyboard(struct wl_listener *listener, void *data) { - struct dwl_input_method_relay *relay = - wl_container_of(listener, relay, input_method_grab_keyboard); - // wl_container_of 宏的第二个参数sample, - // 这里是relay,无须是已经初始化的变量,只要是返回值类型的变量就可以了,这里就是dwl_input_method_relay类型的变量 - struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; + struct dwl_input_method_relay *relay = wl_container_of(listener, relay, + input_method_grab_keyboard); + //wl_container_of 宏的第二个参数sample, 这里是relay,无须是已经初始化的变量,只要是返回值类型的变量就可以了,这里就是dwl_input_method_relay类型的变量 + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; - // send modifier state to grab - struct wlr_keyboard *active_keyboard = wlr_seat_get_keyboard(seat); - if (active_keyboard) { - wlr_log(WLR_INFO, "im_grab_keyboard"); - wlr_input_method_keyboard_grab_v2_set_keyboard(keyboard_grab, - active_keyboard); - wlr_input_method_keyboard_grab_v2_send_modifiers( - keyboard_grab, &active_keyboard->modifiers); - } else - wlr_log(WLR_INFO, "im_grab_keyboard but no active keyboard"); + // send modifier state to grab + struct wlr_keyboard *active_keyboard = wlr_seat_get_keyboard(seat); + if (active_keyboard){ + wlr_log(WLR_INFO,"im_grab_keyboard"); + wlr_input_method_keyboard_grab_v2_set_keyboard(keyboard_grab,active_keyboard); + wlr_input_method_keyboard_grab_v2_send_modifiers(keyboard_grab, &active_keyboard->modifiers); + } + else + wlr_log(WLR_INFO,"im_grab_keyboard but no active keyboard"); + - wl_signal_add(&keyboard_grab->events.destroy, - &relay->input_method_keyboard_grab_destroy); - relay->input_method_keyboard_grab_destroy.notify = - handle_im_keyboard_grab_destroy; + wl_signal_add(&keyboard_grab->events.destroy, + &relay->input_method_keyboard_grab_destroy); + relay->input_method_keyboard_grab_destroy.notify = + handle_im_keyboard_grab_destroy; } -static void handle_im_keyboard_grab_destroy(struct wl_listener *listener, - void *data) { - struct dwl_input_method_relay *relay = - wl_container_of(listener, relay, input_method_keyboard_grab_destroy); - struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; - wlr_log(WLR_DEBUG, "im_keyboard_grab_destroy"); - wl_list_remove(&relay->input_method_keyboard_grab_destroy.link); - if (keyboard_grab->keyboard) { - // send modifier state to original client - wlr_seat_keyboard_notify_modifiers(keyboard_grab->input_method->seat, - &keyboard_grab->keyboard->modifiers); - } +static void handle_im_keyboard_grab_destroy(struct wl_listener *listener, void *data) { + struct dwl_input_method_relay *relay = wl_container_of(listener, relay, + input_method_keyboard_grab_destroy); + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; + wlr_log(WLR_DEBUG,"im_keyboard_grab_destroy"); + wl_list_remove(&relay->input_method_keyboard_grab_destroy.link); + if (keyboard_grab->keyboard) { + // send modifier state to original client + wlr_seat_keyboard_notify_modifiers(keyboard_grab->input_method->seat, + &keyboard_grab->keyboard->modifiers); + } } -static struct dwl_text_input * -relay_get_focusable_text_input(struct dwl_input_method_relay *relay) { - struct dwl_text_input *text_input = NULL; - wl_list_for_each(text_input, &relay->text_inputs, link) { - if (text_input->pending_focused_surface) { - return text_input; - } - } - return NULL; + +static struct dwl_text_input *relay_get_focusable_text_input( + struct dwl_input_method_relay *relay) { + struct dwl_text_input *text_input = NULL; + wl_list_for_each(text_input, &relay->text_inputs, link) { + if (text_input->pending_focused_surface) { + return text_input; + } + } + return NULL; } -static struct dwl_text_input * -relay_get_focused_text_input(struct dwl_input_method_relay *relay) { - struct dwl_text_input *text_input = NULL; - wl_list_for_each(text_input, &relay->text_inputs, link) { - if (text_input->input->focused_surface) { - return text_input; - } - } - return NULL; +static struct dwl_text_input *relay_get_focused_text_input( + struct dwl_input_method_relay *relay) { + struct dwl_text_input *text_input = NULL; + wl_list_for_each(text_input, &relay->text_inputs, link) { + if (text_input->input->focused_surface) { + return text_input; + } + } + return NULL; } static void handle_im_commit(struct wl_listener *listener, void *data) { - struct wlr_input_method_v2 *context; + struct wlr_input_method_v2 *context; - struct dwl_input_method_relay *relay = - wl_container_of(listener, relay, input_method_commit); + struct dwl_input_method_relay *relay = wl_container_of(listener, relay, + input_method_commit); - struct dwl_text_input *text_input = relay_get_focused_text_input(relay); - if (!text_input) { - return; - } + struct dwl_text_input *text_input = relay_get_focused_text_input(relay); + if (!text_input) { + return; + } - context = data; - assert(context == relay->input_method); - if (context->current.preedit.text) { - wlr_text_input_v3_send_preedit_string(text_input->input, - context->current.preedit.text, - context->current.preedit.cursor_begin, - context->current.preedit.cursor_end); - wlr_log(WLR_DEBUG, "preedit_text: %s", context->current.preedit.text); - } - if (context->current.commit_text) { - wlr_text_input_v3_send_commit_string(text_input->input, - context->current.commit_text); - wlr_log(WLR_DEBUG, "commit_text: %s", context->current.commit_text); - } - if (context->current.delete.before_length || - context->current.delete.after_length) { - wlr_text_input_v3_send_delete_surrounding_text( - text_input->input, context->current.delete.before_length, - context->current.delete.after_length); - } - wlr_text_input_v3_send_done(text_input->input); + context = data; + assert(context == relay->input_method); + if (context->current.preedit.text) { + wlr_text_input_v3_send_preedit_string(text_input->input, + context->current.preedit.text, + context->current.preedit.cursor_begin, + context->current.preedit.cursor_end); + wlr_log(WLR_DEBUG,"preedit_text: %s", context->current.preedit.text); + } + if (context->current.commit_text) { + wlr_text_input_v3_send_commit_string(text_input->input, + context->current.commit_text); + wlr_log(WLR_DEBUG,"commit_text: %s", context->current.commit_text); + } + if (context->current.delete.before_length + || context->current.delete.after_length) { + wlr_text_input_v3_send_delete_surrounding_text(text_input->input, + context->current.delete.before_length, + context->current.delete.after_length); + } + wlr_text_input_v3_send_done(text_input->input); } -static void -text_input_set_pending_focused_surface(struct dwl_text_input *text_input, - struct wlr_surface *surface) { - wl_list_remove(&text_input->pending_focused_surface_destroy.link); - text_input->pending_focused_surface = surface; +static void text_input_set_pending_focused_surface( + struct dwl_text_input *text_input, struct wlr_surface *surface) { + wl_list_remove(&text_input->pending_focused_surface_destroy.link); + text_input->pending_focused_surface = surface; - if (surface) { - wl_signal_add(&surface->events.destroy, - &text_input->pending_focused_surface_destroy); - } else { - wl_list_init(&text_input->pending_focused_surface_destroy.link); - } + if (surface) { + wl_signal_add(&surface->events.destroy, + &text_input->pending_focused_surface_destroy); + } else { + wl_list_init(&text_input->pending_focused_surface_destroy.link); + } } static void handle_im_destroy(struct wl_listener *listener, void *data) { - struct dwl_text_input *text_input; + struct dwl_text_input *text_input; + + struct dwl_input_method_relay *relay = wl_container_of(listener, relay, + input_method_destroy); + struct wlr_input_method_v2 *context = data; + wlr_log(WLR_INFO,"IM destroy"); + assert(context == relay->input_method); - struct dwl_input_method_relay *relay = - wl_container_of(listener, relay, input_method_destroy); - struct wlr_input_method_v2 *context = data; - wlr_log(WLR_INFO, "IM destroy"); - assert(context == relay->input_method); wl_list_remove(&relay->input_method_commit.link); wl_list_remove(&relay->input_method_grab_keyboard.link); - wl_list_remove(&relay->input_method_destroy.link); wl_list_remove(&relay->input_method_new_popup_surface.link); + wl_list_remove(&relay->input_method_destroy.link); - relay->input_method = NULL; + relay->input_method = NULL; - text_input = relay_get_focused_text_input(relay); - if (text_input) { - // keyboard focus is still there, so keep the surface at hand in case - // the input method returns - text_input_set_pending_focused_surface(text_input, - text_input->input->focused_surface); - wlr_text_input_v3_send_leave(text_input->input); - } + text_input = relay_get_focused_text_input(relay); + if (text_input) { + // keyboard focus is still there, so keep the surface at hand in case + // the input method returns + text_input_set_pending_focused_surface(text_input, + text_input->input->focused_surface); + wlr_text_input_v3_send_leave(text_input->input); + } } static void relay_send_im_state(struct dwl_input_method_relay *relay, - struct wlr_text_input_v3 *input) { - struct wlr_input_method_v2 *input_method = relay->input_method; - if (!input_method) { - wlr_log(WLR_INFO, "Sending IM_DONE but im is gone"); - return; - } - // TODO: only send each of those if they were modified - wlr_input_method_v2_send_surrounding_text( - input_method, input->current.surrounding.text, - input->current.surrounding.cursor, input->current.surrounding.anchor); - wlr_input_method_v2_send_text_change_cause(input_method, - input->current.text_change_cause); - wlr_input_method_v2_send_content_type(input_method, - input->current.content_type.hint, - input->current.content_type.purpose); - wlr_input_method_v2_send_done(input_method); - // TODO: pass intent, display popup size + struct wlr_text_input_v3 *input) { + struct wlr_input_method_v2 *input_method = relay->input_method; + if (!input_method) { + wlr_log(WLR_INFO, "Sending IM_DONE but im is gone"); + return; + } + // TODO: only send each of those if they were modified + wlr_input_method_v2_send_surrounding_text(input_method, + input->current.surrounding.text, input->current.surrounding.cursor, + input->current.surrounding.anchor); + wlr_input_method_v2_send_text_change_cause(input_method, + input->current.text_change_cause); + wlr_input_method_v2_send_content_type(input_method, + input->current.content_type.hint, input->current.content_type.purpose); + wlr_input_method_v2_send_done(input_method); + // TODO: pass intent, display popup size } static void handle_text_input_enable(struct wl_listener *listener, void *data) { - struct dwl_text_input *text_input = - wl_container_of(listener, text_input, text_input_enable); - if (text_input->relay->input_method == NULL) { - wlr_log(WLR_INFO, "text_input_enable but input method is NULL"); - return; - } + struct dwl_text_input *text_input = wl_container_of(listener, text_input, + text_input_enable); + if (text_input->relay->input_method == NULL) { + wlr_log(WLR_INFO, "text_input_enable but input method is NULL"); + return; + } - wlr_log(WLR_INFO, "text_input_enable"); + wlr_log(WLR_INFO,"text_input_enable"); #ifdef XWAYLAND - wlr_input_method_v2_send_activate(text_input->relay->input_method); - wlr_log(WLR_INFO, "input_method activate for xwayland"); + wlr_input_method_v2_send_activate(text_input->relay->input_method); + wlr_log(WLR_INFO,"input_method activate for xwayland"); #endif - relay_send_im_state(text_input->relay, text_input->input); + relay_send_im_state(text_input->relay, text_input->input); } /* static void handle_text_input_commit(struct wl_listener *listener, */ /* void *data) { */ -/* struct dwl_text_input *text_input = wl_container_of(listener, - * text_input, */ +/* struct dwl_text_input *text_input = wl_container_of(listener, text_input, */ /* text_input_commit); */ /* if (!text_input->input->current_enabled) { */ /* wlr_log(WLR_INFO, "text_input_commit but not enabled"); */ /* return; */ /* } */ /* if (text_input->relay->input_method == NULL) { */ -/* wlr_log(WLR_INFO, "text_input_commit but input method is NULL"); - */ +/* wlr_log(WLR_INFO, "text_input_commit but input method is NULL"); */ /* return; */ /* } */ /* wlr_log(WLR_DEBUG, "text_input_commit"); */ @@ -311,427 +332,404 @@ static void handle_text_input_enable(struct wl_listener *listener, void *data) { /* } */ static void relay_disable_text_input(struct dwl_input_method_relay *relay, - struct dwl_text_input *text_input) { - if (relay->input_method == NULL) { - wlr_log(WLR_INFO, "text_input_disable, but input method is NULL"); - return; - } - wlr_log(WLR_INFO, "text_input_disable"); - + struct dwl_text_input *text_input) { + if (relay->input_method == NULL) { + wlr_log(WLR_INFO, "text_input_disable, but input method is NULL"); + return; + } + wlr_log(WLR_INFO,"text_input_disable"); + #ifdef XWAYLAND - // https://gitee.com/guyuming76/dwl/commit/59328d6ecbbef1b1cd6e5ea8d90d78ccddd5c263 - wlr_input_method_v2_send_deactivate(relay->input_method); - wlr_log(WLR_INFO, "input_method deactivate for xwayland"); + // https://gitee.com/guyuming76/dwl/commit/59328d6ecbbef1b1cd6e5ea8d90d78ccddd5c263 + wlr_input_method_v2_send_deactivate(relay->input_method); + wlr_log(WLR_INFO,"input_method deactivate for xwayland"); #endif - // but if you keep the line above while remove the line below, input Chinese - // in geogebra(xwayland) won't work - relay_send_im_state(relay, text_input->input); + //but if you keep the line above while remove the line below, input Chinese in geogebra(xwayland) won't work + relay_send_im_state(relay, text_input->input); } + static void handle_text_input_destroy(struct wl_listener *listener, - void *data) { - struct dwl_text_input *text_input = - wl_container_of(listener, text_input, text_input_destroy); + void *data) { + struct dwl_text_input *text_input = wl_container_of(listener, text_input, + text_input_destroy); - if (text_input->input->current_enabled) { - wlr_log(WLR_INFO, "text_input_destroy when still enabled"); - relay_disable_text_input(text_input->relay, text_input); - } else { - wlr_log(WLR_INFO, "text_input_destroy"); - } - - text_input_set_pending_focused_surface(text_input, NULL); - // wl_list_remove(&text_input->text_input_commit.link); - wl_list_remove(&text_input->text_input_destroy.link); - // wl_list_remove(&text_input->text_input_disable.link); - wl_list_remove(&text_input->text_input_enable.link); - wl_list_remove(&text_input->link); - free(text_input); + if (text_input->input->current_enabled) { + wlr_log(WLR_INFO,"text_input_destroy when still enabled"); + relay_disable_text_input(text_input->relay, text_input); + } + else { + wlr_log(WLR_INFO,"text_input_destroy"); + } + + text_input_set_pending_focused_surface(text_input, NULL); + //wl_list_remove(&text_input->text_input_commit.link); + wl_list_remove(&text_input->text_input_destroy.link); + //wl_list_remove(&text_input->text_input_disable.link); + wl_list_remove(&text_input->text_input_enable.link); + wl_list_remove(&text_input->link); + free(text_input); } static void handle_pending_focused_surface_destroy(struct wl_listener *listener, - void *data) { - struct dwl_text_input *text_input = - wl_container_of(listener, text_input, pending_focused_surface_destroy); - struct wlr_surface *surface = data; - assert(text_input->pending_focused_surface == surface); - text_input->pending_focused_surface = NULL; - wl_list_remove(&text_input->pending_focused_surface_destroy.link); - wl_list_init(&text_input->pending_focused_surface_destroy.link); + void *data) { + struct dwl_text_input *text_input = wl_container_of(listener, text_input, + pending_focused_surface_destroy); + struct wlr_surface *surface = data; + assert(text_input->pending_focused_surface == surface); + text_input->pending_focused_surface = NULL; + wl_list_remove(&text_input->pending_focused_surface_destroy.link); + wl_list_init(&text_input->pending_focused_surface_destroy.link); } + static void relay_handle_text_input_new(struct wl_listener *listener, - void *data) { - struct dwl_input_method_relay *relay = - wl_container_of(listener, relay, text_input_new); - struct wlr_text_input_v3 *wlr_text_input = data; - if (seat != wlr_text_input->seat) { - return; - } + void *data) { + struct dwl_input_method_relay *relay = wl_container_of(listener, relay, + text_input_new); + struct wlr_text_input_v3 *wlr_text_input = data; + if (seat != wlr_text_input->seat) { + return; + } - struct dwl_text_input *input; - input = calloc(1, sizeof(*input)); - if (!input) { - wlr_log(WLR_ERROR, "dwl_text_input calloc failed"); - return; - } - wlr_log(WLR_INFO, "dwl_text_input calloc"); - input->input = wlr_text_input; - input->relay = relay; + struct dwl_text_input *input; + input = calloc(1, sizeof(*input)); + if (!input) { + wlr_log(WLR_ERROR, "dwl_text_input calloc failed"); + return; + } + wlr_log(WLR_INFO, "dwl_text_input calloc"); + input->input = wlr_text_input; + input->relay = relay; - wl_list_insert(&relay->text_inputs, &input->link); + wl_list_insert(&relay->text_inputs, &input->link); - input->text_input_enable.notify = handle_text_input_enable; - wl_signal_add(&wlr_text_input->events.enable, &input->text_input_enable); + input->text_input_enable.notify = handle_text_input_enable; + wl_signal_add(&wlr_text_input->events.enable, &input->text_input_enable); - // input->text_input_commit.notify = handle_text_input_commit; - // wl_signal_add(&text_input->events.commit, &input->text_input_commit); + //input->text_input_commit.notify = handle_text_input_commit; + //wl_signal_add(&text_input->events.commit, &input->text_input_commit); - /* input->text_input_disable.notify = handle_text_input_disable; */ - /* wl_signal_add(&text_input->events.disable, &input->text_input_disable); */ + /* input->text_input_disable.notify = handle_text_input_disable; */ + /* wl_signal_add(&text_input->events.disable, &input->text_input_disable); */ - input->text_input_destroy.notify = handle_text_input_destroy; - wl_signal_add(&wlr_text_input->events.destroy, &input->text_input_destroy); + input->text_input_destroy.notify = handle_text_input_destroy; + wl_signal_add(&wlr_text_input->events.destroy, &input->text_input_destroy); - input->pending_focused_surface_destroy.notify = - handle_pending_focused_surface_destroy; - wl_list_init(&input->pending_focused_surface_destroy.link); + input->pending_focused_surface_destroy.notify = + handle_pending_focused_surface_destroy; + wl_list_init(&input->pending_focused_surface_destroy.link); } -static LayerSurface *layer_surface_from_wlr_layer_surface_v1( - struct wlr_layer_surface_v1 *layer_surface) { - return layer_surface->data; + +static LayerSurface* layer_surface_from_wlr_layer_surface_v1( + struct wlr_layer_surface_v1* layer_surface) { + return layer_surface->data; } + static void get_parent_and_output_box(struct wlr_surface *focused_surface, - struct wlr_box *parent, - struct wlr_box *output_box) { - struct wlr_output *output; - struct wlr_box output_box_tmp; - struct wlr_layer_surface_v1 *layer_surface; - Client *client = NULL; - LayerSurface *l = NULL; + struct wlr_box *parent, struct wlr_box *output_box) { + struct wlr_output *output; + struct wlr_box output_box_tmp; + struct wlr_layer_surface_v1 *layer_surface; - if ((layer_surface = - wlr_layer_surface_v1_try_from_wlr_surface(focused_surface))) { - LayerSurface *layer = - layer_surface_from_wlr_layer_surface_v1(layer_surface); - output = layer->layer_surface->output; - wlr_output_layout_get_box(output_layout, output, &output_box_tmp); - *parent = layer->geom; - parent->x += output_box_tmp.x; - parent->y += output_box_tmp.y; - wlr_log(WLR_INFO, - "get_parent_and_output_box layersurface output_box_tmp->x %d y %d", - output_box_tmp.x, output_box_tmp.y); - wlr_log(WLR_INFO, - "get_parent_and_output_box layersurface parent->x %d y %d", - parent->x, parent->y); - } else { - toplevel_from_wlr_surface(focused_surface, &client, &l); + if ((layer_surface=wlr_layer_surface_v1_try_from_wlr_surface(focused_surface))) { + LayerSurface* layer = + layer_surface_from_wlr_layer_surface_v1(layer_surface); + output = layer->layer_surface->output; + wlr_output_layout_get_box(output_layout, output,&output_box_tmp); + *parent = layer->geom; + parent->x += output_box_tmp.x; + parent->y += output_box_tmp.y; + wlr_log(WLR_INFO,"get_parent_and_output_box layersurface output_box_tmp->x %d y %d",output_box_tmp.x, output_box_tmp.y); + wlr_log(WLR_INFO,"get_parent_and_output_box layersurface parent->x %d y %d",parent->x,parent->y); + } else { + //Client *client = client_from_wlr_surface(focused_surface); + Client *client = NULL; + LayerSurface *l = NULL; + toplevel_from_wlr_surface(focused_surface, &client, &l); + + output = wlr_output_layout_output_at(output_layout, + client->geom.x, client->geom.y); + wlr_output_layout_get_box(output_layout, output,&output_box_tmp); + + parent->x = client->geom.x + client->bw; + parent->y = client->geom.y + client->bw; + parent->width = client->geom.width; + parent->height = client->geom.height; + wlr_log(WLR_INFO,"get_parent_and_output_box client output_box_tmp->x %d y %d",output_box_tmp.x, output_box_tmp.y); + wlr_log(WLR_INFO,"get_parent_and_output_box client client->geom.x %d y %d",client->geom.x,client->geom.y); + wlr_log(WLR_INFO,"get_parent_and_output_box client client->bw %d",client->bw); + wlr_log(WLR_INFO,"get_parent_and_output_box client parent->x %d y %d",parent->x,parent->y); + } - output = wlr_output_layout_output_at(output_layout, client->geom.x, - client->geom.y); - wlr_output_layout_get_box(output_layout, output, &output_box_tmp); - - parent->x = client->geom.x + client->bw; - parent->y = client->geom.y + client->bw; - parent->width = client->geom.width; - parent->height = client->geom.height; - wlr_log(WLR_INFO, - "get_parent_and_output_box client output_box_tmp->x %d y %d", - output_box_tmp.x, output_box_tmp.y); - wlr_log(WLR_INFO, - "get_parent_and_output_box client client->geom.x %d y %d", - client->geom.x, client->geom.y); - wlr_log(WLR_INFO, "get_parent_and_output_box client client->bw %d", - client->bw); - wlr_log(WLR_INFO, "get_parent_and_output_box client parent->x %d y %d", - parent->x, parent->y); - } - - //*output_box = output_box_tmp; - memcpy(output_box, &output_box_tmp, sizeof(struct wlr_box)); - wlr_log(WLR_INFO, - "get_parent_and_output_box output_box x %d y %d width %d height %d", - output_box->x, output_box->y, output_box->width, output_box->height); + //*output_box = output_box_tmp; + memcpy(output_box,&output_box_tmp,sizeof(struct wlr_box)); + wlr_log(WLR_INFO,"get_parent_and_output_box output_box x %d y %d width %d height %d",output_box->x,output_box->y,output_box->width,output_box->height); } -// 如果当前focused wlr_text_input_v3.features 满足 -// WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE, -// 不含这个feature就弹出在父窗口左上角 根据 -// wlr_text_input_v3.current.cursor_rectangle 计算出一个wlr_box 再调用 -// wlr_input_popup_surface_v2_send_text_input_rectangle 和 -// wlr_scene_node_set_position +// 如果当前focused wlr_text_input_v3.features 满足 WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE, 不含这个feature就弹出在父窗口左上角 +// 根据 wlr_text_input_v3.current.cursor_rectangle 计算出一个wlr_box +// 再调用 wlr_input_popup_surface_v2_send_text_input_rectangle 和 wlr_scene_node_set_position static void input_popup_update(struct dwl_input_popup *popup) { - struct wlr_surface *focused_surface; - struct wlr_box output_box, parent, input_cursor; - int x1, x2, y1, y2, x, y, available_right, available_left, available_down, - available_up, popup_width, popup_height; - bool cursor_rect, x1_in_bounds, y1_in_bounds, x2_in_bounds, y2_in_bounds; + struct wlr_surface* focused_surface; + struct wlr_box output_box, parent, cursor; + int x1, x2, y1, y2, x, y, available_right, available_left, available_down, + available_up, popup_width, popup_height; + bool cursor_rect, x1_in_bounds, y1_in_bounds, x2_in_bounds, y2_in_bounds; - struct dwl_text_input *text_input = - relay_get_focused_text_input(popup->relay); - if (!text_input || !text_input->input->focused_surface) { - return; - } + struct dwl_text_input *text_input = + relay_get_focused_text_input(popup->relay); + if (!text_input|| !text_input->input->focused_surface) { + return; + } - // TODO: - // https://gitlab.freedesktop.org/wlroots/wlroots/-/commit/743da5c0ae723098fe772aadb93810f60e700ab9 + //TODO: https://gitlab.freedesktop.org/wlroots/wlroots/-/commit/743da5c0ae723098fe772aadb93810f60e700ab9 - if (!popup->popup_surface->surface->mapped) { - return; - } + if (!popup->popup_surface->surface->mapped) { + return; + } - cursor_rect = text_input->input->current.features & - WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE; + cursor_rect = text_input->input->current.features + & WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE; - focused_surface = text_input->input->focused_surface; - input_cursor = text_input->input->current.cursor_rectangle; + focused_surface = text_input->input->focused_surface; + cursor = text_input->input->current.cursor_rectangle; - get_parent_and_output_box(focused_surface, &parent, &output_box); + get_parent_and_output_box(focused_surface, &parent, &output_box); - popup_width = popup->popup_surface->surface->current.width; - popup_height = popup->popup_surface->surface->current.height; + popup_width = popup->popup_surface->surface->current.width; + popup_height = popup->popup_surface->surface->current.height; - if (!cursor_rect) { - input_cursor.x = 0; - input_cursor.y = 0; - input_cursor.width = parent.width; - input_cursor.height = parent.height; - wlr_log(WLR_INFO, "input_popup_update !cursor_rect"); + if (!cursor_rect) { + cursor.x = 0; + cursor.y = 0; + cursor.width = parent.width; + cursor.height = parent.height; + wlr_log(WLR_INFO,"input_popup_update !cursor_rect"); - popup->x = parent.x; - popup->y = parent.y; - popup->visible = true; - } else { - wlr_log(WLR_INFO, - "input_popup_update input_cursor x %d y %d width %d height %d", - input_cursor.x, input_cursor.y, input_cursor.width, - input_cursor.height); + popup->x=parent.x; + popup->y=parent.y; + popup->visible=true; + } + else { + wlr_log(WLR_INFO,"input_popup_update cursor x %d y %d width %d height %d",cursor.x,cursor.y,cursor.width,cursor.height); - x1 = parent.x + input_cursor.x; - x2 = parent.x + input_cursor.x + input_cursor.width; - y1 = parent.y + input_cursor.y; - y2 = parent.y + input_cursor.y + input_cursor.height; - x = x1; - y = y2; + x1 = parent.x + cursor.x; + x2 = parent.x + cursor.x + cursor.width; + y1 = parent.y + cursor.y; + y2 = parent.y + cursor.y + cursor.height; + x = x1; + y = y2; - wlr_log(WLR_INFO, "input_popup_update x1 %d x2 %d y1 %d y2 %d; x %d y %d", - x1, x2, y1, y2, x, y); - available_right = output_box.x + output_box.width - x1; - available_left = x2 - output_box.x; - if (available_right < popup_width && available_left > available_right) { - x = x2 - popup_width; - wlr_log(WLR_INFO, - "input_popup_update available_left %d popup_width %d " - "available_right %d; x %d", - available_left, popup_width, available_right, x); - } + wlr_log(WLR_INFO,"input_popup_update x1 %d x2 %d y1 %d y2 %d; x %d y %d",x1,x2,y1,y2,x,y); + available_right = output_box.x + output_box.width - x1; + available_left = x2 - output_box.x; + if (available_right < popup_width && available_left > available_right) { + x = x2 - popup_width; + wlr_log(WLR_INFO,"input_popup_update available_left %d popup_width %d available_right %d; x %d",available_left,popup_width,available_right,x); + } - available_down = output_box.y + output_box.height - y2; - available_up = y1 - output_box.y; - if (available_down < popup_height && available_up > available_down) { - y = y1 - popup_height; - wlr_log(WLR_INFO, - "input_popup_update available up %d popup_height %d " - "available_down %d; y %d", - available_up, popup_height, available_down, y); - } + available_down = output_box.y + output_box.height - y2; + available_up = y1 - output_box.y; + if (available_down < popup_height && available_up > available_down) { + y = y1 - popup_height; + wlr_log(WLR_INFO,"input_popup_update available up %d popup_height %d available_down %d; y %d",available_up,popup_height,available_down,y); + } - popup->x = x; - popup->y = y; + popup->x = x; + popup->y = y; - // Hide popup if input_cursor position is completely out of bounds - x1_in_bounds = (input_cursor.x >= 0 && input_cursor.x < parent.width); - y1_in_bounds = (input_cursor.y >= 0 && input_cursor.y < parent.height); - x2_in_bounds = (input_cursor.x + input_cursor.width >= 0 && - input_cursor.x + input_cursor.width < parent.width); - y2_in_bounds = (input_cursor.y + input_cursor.height >= 0 && - input_cursor.y + input_cursor.height < parent.height); - popup->visible = - (x1_in_bounds && y1_in_bounds) || (x2_in_bounds && y2_in_bounds); + // Hide popup if cursor position is completely out of bounds + x1_in_bounds = (cursor.x >= 0 && cursor.x < parent.width); + y1_in_bounds = (cursor.y >= 0 && cursor.y < parent.height); + x2_in_bounds = (cursor.x + cursor.width >= 0 + && cursor.x + cursor.width < parent.width); + y2_in_bounds = (cursor.y + cursor.height >= 0 + && cursor.y + cursor.height < parent.height); + popup->visible = + (x1_in_bounds && y1_in_bounds) || (x2_in_bounds && y2_in_bounds); - struct wlr_box box = { - .x = x1 - x, - .y = y1 - y, - .width = input_cursor.width, - .height = input_cursor.height, - }; - wlr_input_popup_surface_v2_send_text_input_rectangle(popup->popup_surface, - &box); - wlr_log(WLR_INFO, - "input_popup_update send_text_input_rect box.x %d box.y %d", box.x, - box.y); - } + struct wlr_box box = { + .x = x1 - x, + .y = y1 - y, + .width = cursor.width, + .height = cursor.height, + }; + wlr_input_popup_surface_v2_send_text_input_rectangle( + popup->popup_surface, &box); + wlr_log(WLR_INFO,"input_popup_update send_text_input_rect box.x %d box.y %d",box.x,box.y); - wlr_log(WLR_INFO, "input_popup_update x %d y %d visible %s", popup->x, - popup->y, popup->visible ? "true" : "false"); - wlr_scene_node_set_position(&popup->scene->node, popup->x, popup->y); + } + + wlr_log(WLR_INFO,"input_popup_update x %d y %d visible %s",popup->x,popup->y,popup->visible?"true":"false"); + wlr_scene_node_set_position(&popup->scene->node, popup->x, popup->y); } static void handle_im_popup_map(struct wl_listener *listener, void *data) { - struct dwl_input_popup *popup = wl_container_of(listener, popup, popup_map); + struct dwl_input_popup *popup = + wl_container_of(listener, popup, popup_map); - wlr_log(WLR_INFO, "IM_popup_map"); + wlr_log(WLR_INFO, "IM_popup_map"); + + //popup->scene = &wlr_scene_tree_create(layers[LyrIMPopup])->node; + popup->scene = wlr_scene_tree_create(layers[LyrIMPopup]); + popup->scene_surface = wlr_scene_subsurface_tree_create(popup->scene,popup->popup_surface->surface); + //popup->scene_surface = &wlr_scene_subsurface_tree_create(popup->scene->parent,popup->popup_surface->surface)->node; + //popup->scene_surface->data = popup; + popup->scene_surface->node.data = popup; - // popup->scene = &wlr_scene_tree_create(layers[LyrIMPopup])->node; - popup->scene = wlr_scene_tree_create(layers[LyrIMPopup]); - popup->scene_surface = wlr_scene_subsurface_tree_create( - popup->scene, popup->popup_surface->surface); - // popup->scene_surface = - // &wlr_scene_subsurface_tree_create(popup->scene->parent,popup->popup_surface->surface)->node; - // popup->scene_surface->data = popup; - popup->scene_surface->node.data = popup; + input_popup_update(popup); - input_popup_update(popup); - - // wlr_scene_node_set_position(popup->scene, popup->x, popup->y); + //wlr_scene_node_set_position(popup->scene, popup->x, popup->y); } static void handle_im_popup_unmap(struct wl_listener *listener, void *data) { - struct dwl_input_popup *popup = wl_container_of(listener, popup, popup_unmap); - // input_popup_update(popup); + struct dwl_input_popup *popup = + wl_container_of(listener, popup, popup_unmap); + //input_popup_update(popup); - wlr_log(WLR_INFO, "im_popup_unmap"); - wlr_scene_node_destroy(&popup->scene->node); + wlr_log(WLR_INFO,"im_popup_unmap"); + wlr_scene_node_destroy(&popup->scene->node); } static void handle_im_popup_destroy(struct wl_listener *listener, void *data) { - struct dwl_input_method_relay *relay; - struct dwl_input_popup *popup = - wl_container_of(listener, popup, popup_destroy); + struct dwl_input_method_relay *relay; + struct dwl_input_popup *popup = + wl_container_of(listener, popup, popup_destroy); - wlr_log(WLR_INFO, "im_popup_destroy"); + wlr_log(WLR_INFO,"im_popup_destroy"); + + wl_list_remove(&popup->popup_destroy.link); + wl_list_remove(&popup->popup_unmap.link); + wl_list_remove(&popup->popup_map.link); - wl_list_remove(&popup->popup_destroy.link); - wl_list_remove(&popup->popup_unmap.link); - wl_list_remove(&popup->popup_map.link); - - relay = popup->relay; - free(popup->relay->popup); - relay->popup = NULL; + relay=popup->relay; + free(popup->relay->popup); + relay->popup=NULL; } -static void handle_im_new_popup_surface(struct wl_listener *listener, - void *data) { - // struct dwl_text_input* text_input; - struct dwl_input_method_relay *relay = - wl_container_of(listener, relay, input_method_new_popup_surface); - struct dwl_input_popup *popup = calloc(1, sizeof(*popup)); +static void handle_im_new_popup_surface(struct wl_listener *listener, void *data) { + // struct dwl_text_input* text_input; - wlr_log(WLR_INFO, "IM_new_popup_surface"); - relay->popup = popup; + struct dwl_input_method_relay *relay = wl_container_of(listener, relay, + input_method_new_popup_surface); + struct dwl_input_popup *popup = calloc(1, sizeof(*popup)); - popup->relay = relay; - popup->popup_surface = data; - popup->popup_surface->data = popup; + wlr_log(WLR_INFO, "IM_new_popup_surface"); + relay->popup = popup; + + popup->relay = relay; + popup->popup_surface = data; + popup->popup_surface->data = popup; - wl_signal_add(&popup->popup_surface->surface->events.map, &popup->popup_map); - popup->popup_map.notify = handle_im_popup_map; + + wl_signal_add(&popup->popup_surface->surface->events.map, &popup->popup_map); + popup->popup_map.notify = handle_im_popup_map; - wl_signal_add(&popup->popup_surface->surface->events.unmap, - &popup->popup_unmap); - popup->popup_unmap.notify = handle_im_popup_unmap; + wl_signal_add(&popup->popup_surface->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->events.destroy, &popup->popup_destroy); + popup->popup_destroy.notify = handle_im_popup_destroy; } + static void relay_handle_input_method_new(struct wl_listener *listener, - void *data) { - struct dwl_text_input *text_input; + void *data) { + struct dwl_text_input *text_input; - struct dwl_input_method_relay *relay = - wl_container_of(listener, relay, input_method_new); + struct dwl_input_method_relay *relay = wl_container_of(listener, relay, + input_method_new); - struct wlr_input_method_v2 *input_method = data; - if (seat != input_method->seat) { - wlr_log(WLR_INFO, "input_method_new Seat does not match"); - return; - } + struct wlr_input_method_v2 *input_method = data; + if (seat != input_method->seat) { + wlr_log(WLR_INFO,"input_method_new Seat does not match"); + return; + } - if (relay->input_method != NULL) { - wlr_log( - WLR_INFO, - "input_method_new Attempted to connect second input method to a seat"); - wlr_input_method_v2_send_unavailable(input_method); - return; - } + if (relay->input_method != NULL) { + wlr_log(WLR_INFO, "input_method_new Attempted to connect second input method to a seat"); + wlr_input_method_v2_send_unavailable(input_method); + return; + } - wlr_log(WLR_INFO, "input_method_new"); + wlr_log(WLR_INFO,"input_method_new"); + + relay->input_method = input_method; + 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.new_popup_surface, + &relay->input_method_new_popup_surface); + relay->input_method_new_popup_surface.notify = handle_im_new_popup_surface; + wl_signal_add(&relay->input_method->events.grab_keyboard, + &relay->input_method_grab_keyboard); + relay->input_method_grab_keyboard.notify = handle_im_grab_keyboard; + wl_signal_add(&relay->input_method->events.destroy, + &relay->input_method_destroy); + relay->input_method_destroy.notify = handle_im_destroy; - relay->input_method = input_method; - 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.new_popup_surface, - &relay->input_method_new_popup_surface); - relay->input_method_new_popup_surface.notify = handle_im_new_popup_surface; - wl_signal_add(&relay->input_method->events.grab_keyboard, - &relay->input_method_grab_keyboard); - relay->input_method_grab_keyboard.notify = handle_im_grab_keyboard; - wl_signal_add(&relay->input_method->events.destroy, - &relay->input_method_destroy); - relay->input_method_destroy.notify = handle_im_destroy; + wlr_input_method_v2_send_activate(relay->input_method); - wlr_input_method_v2_send_activate(relay->input_method); - - text_input = relay_get_focusable_text_input(relay); - if (text_input) { - wlr_text_input_v3_send_enter(text_input->input, - text_input->pending_focused_surface); - text_input_set_pending_focused_surface(text_input, NULL); - } + text_input = relay_get_focusable_text_input(relay); + if (text_input) { + wlr_text_input_v3_send_enter(text_input->input, + text_input->pending_focused_surface); + text_input_set_pending_focused_surface(text_input, NULL); + } } void dwl_input_method_relay_init(struct dwl_input_method_relay *relay) { - wl_list_init(&relay->text_inputs); + wl_list_init(&relay->text_inputs); - relay->popup = NULL; + relay->popup=NULL; - relay->text_input_new.notify = relay_handle_text_input_new; - wl_signal_add(&text_input_manager->events.text_input, &relay->text_input_new); + relay->text_input_new.notify = relay_handle_text_input_new; + wl_signal_add(&text_input_manager->events.text_input, + &relay->text_input_new); - relay->input_method_new.notify = relay_handle_input_method_new; - wl_signal_add(&input_method_manager->events.input_method, - &relay->input_method_new); + relay->input_method_new.notify = relay_handle_input_method_new; + wl_signal_add(&input_method_manager->events.input_method, + &relay->input_method_new); } void dwl_input_method_relay_set_focus(struct dwl_input_method_relay *relay, - struct wlr_surface *surface) { - struct dwl_text_input *text_input; - wl_list_for_each(text_input, &relay->text_inputs, link) { - if (text_input->pending_focused_surface) { - assert(text_input->input->focused_surface == NULL); - if (surface != text_input->pending_focused_surface) { - text_input_set_pending_focused_surface(text_input, NULL); - } - } else if (text_input->input->focused_surface) { - assert(text_input->pending_focused_surface == NULL); - if (surface != text_input->input->focused_surface) { - relay_disable_text_input(relay, text_input); - wlr_text_input_v3_send_leave(text_input->input); - wlr_log(WLR_INFO, "wlr_text_input_send_leave"); - } else { - wlr_log(WLR_INFO, "IM relay set_focus already focused"); - continue; - } - } + struct wlr_surface *surface) { + struct dwl_text_input *text_input; + wl_list_for_each(text_input, &relay->text_inputs, link) { + if (text_input->pending_focused_surface) { + assert(text_input->input->focused_surface == NULL); + if (surface != text_input->pending_focused_surface) { + text_input_set_pending_focused_surface(text_input, NULL); + } + } else if (text_input->input->focused_surface) { + assert(text_input->pending_focused_surface == NULL); + if (surface != text_input->input->focused_surface) { + relay_disable_text_input(relay, text_input); + wlr_text_input_v3_send_leave(text_input->input); + wlr_log(WLR_INFO, "wlr_text_input_send_leave"); + } else { + wlr_log(WLR_INFO, "IM relay set_focus already focused"); + continue; + } + } - if (surface && wl_resource_get_client(text_input->input->resource) == - wl_resource_get_client(surface->resource)) { - if (relay->input_method) { - wlr_text_input_v3_send_enter(text_input->input, surface); - wlr_log(WLR_INFO, "wlr_text_input_send_enter"); - if (relay->popup) - input_popup_update(relay->popup); - } else { - text_input_set_pending_focused_surface(text_input, surface); - } - } - } + if (surface + && wl_resource_get_client(text_input->input->resource) + == wl_resource_get_client(surface->resource)) { + if (relay->input_method) { + wlr_text_input_v3_send_enter(text_input->input, surface); + wlr_log(WLR_INFO, "wlr_text_input_send_enter"); + if (relay->popup) input_popup_update(relay->popup); + } else { + text_input_set_pending_focused_surface(text_input, surface); + } + } + } } #endif diff --git a/README.md b/README.md index 2b9416e2..df722f67 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,8 @@ See below for more features. - isfloating: type-num(0 or 1) - isfullscreen: type-num(0 or 1) - scroller_proportion: type-float(0.1-1.0) -- animation_type : type-string(zoom,slide) +- animation_type_open : type-string(zoom,slide) +- animation_type_close : type-string(zoom,slide) - isnoborder : type-num(0 or 1) - monitor : type-num(0-99999) - width : type-num(0-9999) @@ -62,17 +63,15 @@ See below for more features. - alt-tab switch window like gnome - niri like scroller layout -## suggest tools -``` -yay -S rofi foot xdg-desktop-portal-wlr swaybg waybar wl-clip-persist cliphist wl-clipboard wlsunset - -``` - # install ## stable - wlroots(0.17) Since 0.18 has some bugs that affect the experience, I chose the more stable 0.17.4. - +- Arch +``` +yay -S maomaowm-git +``` +- Other ``` yay -S libinput git clone -b 0.17.4 https://gitlab.freedesktop.org/wlroots/wlroots.git @@ -99,7 +98,18 @@ meson build -Dprefix=/usr sudo ninja -C build install ``` +## suggest tools +``` +yay -S rofi foot xdg-desktop-portal-wlr swaybg waybar wl-clip-persist cliphist wl-clipboard wlsunset + +``` + # config +``` +cp /etc/maomao/config.conf ~/.config/maomao/config.conf +touch ~/.config/maomao/autostart.sh +chmod +x ~/.config/maomao/autostart.sh +``` you can use `MAOMAOCONFIG` env to set the config-folder-path and the autostart-folder-patch like `MAOMAOCONFIG=/home/xxx/maomao` @@ -162,7 +172,7 @@ ov_tab_mode=0 ### notice when you in ov mode, you can use right mouse button to close window, and left mouse button to jump to a window. -# About warbar +# About waybar - you can also use the dwl moudle in waybar to show tags and window title refer to waybar wiki: [dwl-module](https://github.com/Alexays/Waybar/wiki/Module:-Dwl) diff --git a/config.conf b/config.conf index 4e363ac1..fcba18b1 100644 --- a/config.conf +++ b/config.conf @@ -1,12 +1,13 @@ # Animation Configuration animations=1 -animation_type=slide +animation_type_open=zoom +animation_type_close=slide animation_fade_in=1 zoom_initial_ratio=0.5 fadein_begin_opacity=0.5 fadeout_begin_opacity=0.8 -animation_duration_move=400 -animation_duration_open=350 +animation_duration_move=500 +animation_duration_open=400 animation_duration_tag=350 animation_duration_close=800 animation_curve_open=0.46,1.0,0.29,1 @@ -94,7 +95,8 @@ tags=id:9,layout_name:tile # isfloating: type-num(0 or 1) # isfullscreen: type-num(0 or 1) # scroller_proportion: type-float(0.1-1.0) -# animation_type : type-string(zoom,slide) +# animation_type_open : type-string(zoom,slide) +# animation_type_close : type-string(zoom,slide) # isnoborder : type-num(0 or 1) # monitor : type-int(0-99999) # width : type-num(0-9999) @@ -110,7 +112,7 @@ tags=id:9,layout_name:tile # windowrule=isfloating:1,appid:Rofi # windowrule=isfloating:1,appid:wofi # windowrule=isnoborder:1,appid:wofi -# windowrule=animation_type:zoom,appid:wofi +# windowrule=animation_type_open:zoom,appid:wofi # open in specific tag # windowrule=tags:4,appid:Google-chrome diff --git a/maomao.c b/maomao.c index 72bd9ac9..1a132a70 100644 --- a/maomao.c +++ b/maomao.c @@ -15,9 +15,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -232,7 +234,8 @@ struct Client { struct wl_listener destroy_decoration; unsigned int ignore_clear_fullscreen; - const char *animation_type; + const char *animation_type_open; + const char *animation_type_close; int is_in_scratchpad; int is_scratchpad_show; int isglobal; @@ -266,6 +269,19 @@ typedef struct { const Arg arg; } Key; +typedef struct { + struct wlr_keyboard_group *wlr_group; + + int nsyms; + const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */ + uint32_t mods; /* invalid if nsyms == 0 */ + struct wl_event_source *key_repeat_source; + + struct wl_listener modifiers; + struct wl_listener key; + struct wl_listener destroy; +} KeyboardGroup; + typedef struct { struct wl_list link; struct wlr_keyboard *wlr_keyboard; @@ -357,7 +373,8 @@ typedef struct { int isfloating; int isfullscreen; float scroller_proportion; - const char *animation_type; + const char *animation_type_open; + const char *animation_type_close; int isnoborder; int monitor; unsigned int width; @@ -425,6 +442,7 @@ static void destroylocksurface(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); static void destroypointerconstraint(struct wl_listener *listener, void *data); static void destroysessionlock(struct wl_listener *listener, void *data); +static void destroykeyboardgroup(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); static void setcursorshape(struct wl_listener *listener, void *data); static void dwl_ipc_manager_bind(struct wl_client *client, void *data, @@ -589,6 +607,7 @@ static const char broken[] = "broken"; // static const char *cursor_image = "left_ptr"; static pid_t child_pid = -1; static int locked; +static uint32_t locked_mods = 0; static void *exclusive_focus; static struct wl_display *dpy; static struct wl_event_loop *event_loop; @@ -633,6 +652,7 @@ static struct wlr_relative_pointer_manager_v1 *relative_pointer_mgr; static struct wlr_pointer_constraint_v1 *active_constraint; static struct wlr_seat *seat; +static KeyboardGroup *kb_group; static struct wl_list keyboards; static unsigned int cursor_mode; static Client *grabc; @@ -897,8 +917,8 @@ void fadeout_client_animation_next_tick(Client *c) { apply_opacity_to_rect_nodes(c, &c->scene->node, animation_passed); - if ((c->animation_type && strcmp(c->animation_type, "zoom") == 0) || - (!c->animation_type && strcmp(animation_type, "zoom") == 0)) { + if ((c->animation_type_close && strcmp(c->animation_type_close, "zoom") == 0) || + (!c->animation_type_close && strcmp(animation_type_close, "zoom") == 0)) { scale_data.width = width; scale_data.height = height; @@ -1015,12 +1035,12 @@ void apply_border(Client *c, struct wlr_box clip_box, int offsetx, if (c->animation.running && c->animation.action != MOVE) { if (c->animation.current.x < c->mon->m.x) { wlr_scene_rect_set_size(c->border[2], 0, 0); - } else if (c->animation.current.x + c->geom.width > + } else if (c->animation.current.x + c->animation.current.width > c->mon->m.x + c->mon->m.width) { wlr_scene_rect_set_size(c->border[3], 0, 0); } else if (c->animation.current.y < c->mon->m.y) { wlr_scene_rect_set_size(c->border[0], 0, 0); - } else if (c->animation.current.y + c->geom.height > + } else if (c->animation.current.y + c->animation.current.height > c->mon->m.y + c->mon->m.height) { wlr_scene_rect_set_size(c->border[1], 0, 0); } @@ -1070,13 +1090,13 @@ void client_apply_clip(Client *c) { clip_box.y = 0; } - // make tagout tagin animations not visible in other monitors + // // make tagout tagin animations not visible in other monitors if (c->animation.running && c->animation.action != MOVE) { if (c->animation.current.x <= c->mon->m.x) { offsetx = c->mon->m.x - c->animation.current.x; clip_box.x = clip_box.x + offsetx; clip_box.width = clip_box.width - offsetx; - } else if (c->animation.current.x + c->geom.width >= + } else if (c->animation.current.x + c->animation.current.width >= c->mon->m.x + c->mon->m.width) { clip_box.width = clip_box.width - (c->animation.current.x + c->animation.current.width - @@ -1087,7 +1107,7 @@ void client_apply_clip(Client *c) { offsety = c->mon->m.y - c->animation.current.y; clip_box.y = clip_box.y + offsety; clip_box.height = clip_box.height - offsety; - } else if (c->animation.current.y + c->geom.height >= + } else if (c->animation.current.y + c->animation.current.height >= c->mon->m.y + c->mon->m.height) { clip_box.height = clip_box.height - (c->animation.current.y + c->animation.current.height - @@ -1504,8 +1524,10 @@ applyrules(Client *c) { c->isterm = r->isterm > 0 ? r->isterm : c->isterm; c->noswallow = r->noswallow > 0? r->noswallow : c->noswallow; c->isfloating = r->isfloating > 0 ? r->isfloating : c->isfloating; - c->animation_type = - r->animation_type == NULL ? c->animation_type : r->animation_type; + c->animation_type_open = + r->animation_type_open == NULL ? c->animation_type_open : r->animation_type_open; + c->animation_type_close = + r->animation_type_close == NULL ? c->animation_type_close : r->animation_type_close; c->scroller_proportion = r->scroller_proportion > 0 ? r->scroller_proportion : scroller_default_proportion; @@ -2133,6 +2155,7 @@ cleanup(void) { waitpid(child_pid, NULL, 0); } + destroykeyboardgroup(&kb_group->destroy, NULL); wlr_backend_destroy(backend); wlr_scene_node_destroy(&scene->tree.node); wlr_renderer_destroy(drw); @@ -2381,50 +2404,72 @@ void createidleinhibitor(struct wl_listener *listener, void *data) { checkidleinhibitor(NULL); } -void // 17 -createkeyboard(struct wlr_keyboard *keyboard) { - struct xkb_context *context; - struct xkb_keymap *keymap; - Keyboard *kb = keyboard->data = ecalloc(1, sizeof(*kb)); - kb->wlr_keyboard = keyboard; +void +createkeyboard(struct wlr_keyboard *keyboard) +{ - /* Prepare an XKB keymap and assign it to the keyboard. */ - context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - keymap = xkb_keymap_new_from_names(context, &xkb_rules, - XKB_KEYMAP_COMPILE_NO_FLAGS); - wlr_keyboard_set_keymap(keyboard, keymap); - xkb_keymap_unref(keymap); - xkb_context_unref(context); - wlr_keyboard_set_repeat_info(keyboard, repeat_rate, repeat_delay); + /* Set the keymap to match the group keymap */ + wlr_keyboard_set_keymap(keyboard, kb_group->wlr_group->keyboard.keymap); - if (numlockon == 1) { - uint32_t leds = 0; - xkb_mod_mask_t locked_mods = 0; - leds = leds | WLR_LED_NUM_LOCK; - // 获取numlock所在的位置 - xkb_mod_index_t mod_index = xkb_map_mod_get_index(keymap, XKB_MOD_NAME_NUM); - if (mod_index != XKB_MOD_INVALID) { - locked_mods |= (uint32_t)1 - << mod_index; // 将该位置设置为1,默认为0表示锁住小键盘 - } - // 设置numlock为on - xkb_state_update_mask(keyboard->xkb_state, 0, 0, locked_mods, 0, 0, 0); - wlr_keyboard_led_update(keyboard, leds); // 将表示numlockon的灯打开 - } + wlr_keyboard_notify_modifiers(keyboard, 0, 0, locked_mods, 0); - /* Here we set up listeners for keyboard events. */ - LISTEN(&keyboard->events.modifiers, &kb->modifiers, keypressmod); - LISTEN(&keyboard->events.key, &kb->key, keypress); - LISTEN(&keyboard->base.events.destroy, &kb->destroy, cleanupkeyboard); + /* Add the new keyboard to the group */ + wlr_keyboard_group_add_keyboard(kb_group->wlr_group, keyboard); +} - wlr_seat_set_keyboard(seat, keyboard); - kb->key_repeat_source = - wl_event_loop_add_timer(wl_display_get_event_loop(dpy), keyrepeat, kb); +KeyboardGroup * +createkeyboardgroup(void) +{ + KeyboardGroup *group = ecalloc(1, sizeof(*group)); + struct xkb_context *context; + struct xkb_keymap *keymap; - /* And add the keyboard to our list of keyboards */ - wl_list_insert(&keyboards, &kb->link); + group->wlr_group = wlr_keyboard_group_create(); + group->wlr_group->data = group; + + /* Prepare an XKB keymap and assign it to the keyboard group. */ + context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules, + XKB_KEYMAP_COMPILE_NO_FLAGS))) + die("failed to compile keymap"); + + wlr_keyboard_set_keymap(&group->wlr_group->keyboard, keymap); + + if (numlockon) { + xkb_mod_index_t mod_index = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_NUM); + if (mod_index != XKB_MOD_INVALID) + locked_mods |= (uint32_t)1 << mod_index; + } + + if (capslock) { + xkb_mod_index_t mod_index = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); + if (mod_index != XKB_MOD_INVALID) + locked_mods |= (uint32_t)1 << mod_index; + } + + if (locked_mods) + wlr_keyboard_notify_modifiers(&group->wlr_group->keyboard, 0, 0, locked_mods, 0); + + xkb_keymap_unref(keymap); + xkb_context_unref(context); + + wlr_keyboard_set_repeat_info(&group->wlr_group->keyboard, repeat_rate, repeat_delay); + + /* Set up listeners for keyboard events */ + LISTEN(&group->wlr_group->keyboard.events.key, &group->key, keypress); + LISTEN(&group->wlr_group->keyboard.events.modifiers, &group->modifiers, keypressmod); + + group->key_repeat_source = wl_event_loop_add_timer(event_loop, keyrepeat, group); + + /* A seat can only have one keyboard, but this is a limitation of the + * Wayland protocol - not wlroots. We assign all connected keyboards to the + * same wlr_keyboard_group, which provides a single wlr_keyboard interface for + * all of them. Set this combined wlr_keyboard as the seat keyboard. + */ + wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); + return group; } void createlayersurface(struct wl_listener *listener, void *data) { @@ -2839,6 +2884,18 @@ void destroysessionlock(struct wl_listener *listener, void *data) { destroylock(lock, 0); } +void +destroykeyboardgroup(struct wl_listener *listener, void *data) +{ + KeyboardGroup *group = wl_container_of(listener, group, destroy); + wl_event_source_remove(group->key_repeat_source); + wl_list_remove(&group->key.link); + wl_list_remove(&group->modifiers.link); + wl_list_remove(&group->destroy.link); + wlr_keyboard_group_destroy(group->wlr_group); + free(group); +} + Monitor *dirtomon(enum wlr_direction dir) { struct wlr_output *next; if (!wlr_output_layout_get(output_layout, selmon->wlr_output)) @@ -3278,49 +3335,51 @@ void incovgaps(const Arg *arg) { setgaps(selmon->gappoh, selmon->gappov + arg->i, selmon->gappih, selmon->gappiv); } +void +inputdevice(struct wl_listener *listener, void *data) +{ + /* This event is raised by the backend when a new input device becomes + * available. */ + struct wlr_input_device *device = data; + uint32_t caps; -void // 17 -inputdevice(struct wl_listener *listener, void *data) { - /* This event is raised by the backend when a new input device becomes - * available. */ - struct wlr_input_device *device = data; - uint32_t caps; + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD: + createkeyboard(wlr_keyboard_from_input_device(device)); + break; + case WLR_INPUT_DEVICE_POINTER: + createpointer(wlr_pointer_from_input_device(device)); + break; + default: + /* TODO handle other input device types */ + break; + } - switch (device->type) { - case WLR_INPUT_DEVICE_KEYBOARD: - createkeyboard(wlr_keyboard_from_input_device(device)); - break; - case WLR_INPUT_DEVICE_POINTER: - createpointer(wlr_pointer_from_input_device(device)); - break; - default: - /* TODO handle other input device types */ - break; - } - - /* We need to let the wlr_seat know what our capabilities are, which is - * communiciated to the client. In dwl we always have a cursor, even if - * there are no pointer devices, so we always include that capability. */ - /* TODO do we actually require a cursor? */ - caps = WL_SEAT_CAPABILITY_POINTER; - if (!wl_list_empty(&keyboards)) - caps |= WL_SEAT_CAPABILITY_KEYBOARD; - wlr_seat_set_capabilities(seat, caps); + /* We need to let the wlr_seat know what our capabilities are, which is + * communiciated to the client. In dwl we always have a cursor, even if + * there are no pointer devices, so we always include that capability. */ + /* TODO do we actually require a cursor? */ + caps = WL_SEAT_CAPABILITY_POINTER; + if (!wl_list_empty(&kb_group->wlr_group->devices)) + caps |= WL_SEAT_CAPABILITY_KEYBOARD; + wlr_seat_set_capabilities(seat, caps); } -int keyrepeat(void *data) { - Keyboard *kb = data; - int i; - if (!kb->nsyms || kb->wlr_keyboard->repeat_info.rate <= 0) - return 0; +int +keyrepeat(void *data) +{ + KeyboardGroup *group = data; + int i; + if (!group->nsyms || group->wlr_group->keyboard.repeat_info.rate <= 0) + return 0; - wl_event_source_timer_update(kb->key_repeat_source, - 1000 / kb->wlr_keyboard->repeat_info.rate); + wl_event_source_timer_update(group->key_repeat_source, + 1000 / group->wlr_group->keyboard.repeat_info.rate); - for (i = 0; i < kb->nsyms; i++) - keybinding(kb->mods, kb->keysyms[i]); + for (i = 0; i < group->nsyms; i++) + keybinding(group->mods, group->keysyms[i]); - return 0; + return 0; } int // 17 @@ -3345,31 +3404,32 @@ keybinding(uint32_t mods, xkb_keysym_t sym) { return handled; } -void // 17 -keypress(struct wl_listener *listener, void *data) { - int i; - /* This event is raised when a key is pressed or released. */ - Keyboard *kb = wl_container_of(listener, kb, key); - struct wlr_keyboard_key_event *event = data; +void +keypress(struct wl_listener *listener, void *data) +{ + int i; + /* This event is raised when a key is pressed or released. */ + KeyboardGroup *group = wl_container_of(listener, group, key); + struct wlr_keyboard_key_event *event = data; - /* Translate libinput keycode -> xkbcommon */ - uint32_t keycode = event->keycode + 8; - /* Get a list of keysyms based on the keymap for this keyboard */ - const xkb_keysym_t *syms; - int nsyms = - xkb_state_key_get_syms(kb->wlr_keyboard->xkb_state, keycode, &syms); + /* Translate libinput keycode -> xkbcommon */ + uint32_t keycode = event->keycode + 8; + /* Get a list of keysyms based on the keymap for this keyboard */ + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms( + group->wlr_group->keyboard.xkb_state, keycode, &syms); - int handled = 0; - uint32_t mods = wlr_keyboard_get_modifiers(kb->wlr_keyboard); + int handled = 0; + uint32_t mods = wlr_keyboard_get_modifiers(&group->wlr_group->keyboard); - wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); // ov tab mode detect moe key release if (ov_tab_mode && !locked && - event->state == WL_KEYBOARD_KEY_STATE_RELEASED && - (keycode == 133 || keycode == 37 || keycode == 64 || keycode == 50 || - keycode == 134 || keycode == 105 || keycode == 108 || keycode == 62) && - selmon->sel) { + event->state == WL_KEYBOARD_KEY_STATE_RELEASED && + (keycode == 133 || keycode == 37 || keycode == 64 || keycode == 50 || + keycode == 134 || keycode == 105 || keycode == 108 || keycode == 62) && + selmon->sel) { if (selmon->isoverview && selmon->sel) { toggleoverview(&(Arg){.i = -1}); } @@ -3384,68 +3444,66 @@ keypress(struct wl_listener *listener, void *data) { } #endif - /* On _press_ if there is no active screen locker, - * attempt to process a compositor keybinding. */ - if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) - for (i = 0; i < nsyms; i++) - handled = keybinding(mods, syms[i]) || handled; - if (handled && kb->wlr_keyboard->repeat_info.delay > 0) { - kb->mods = mods; - kb->keysyms = syms; - kb->nsyms = nsyms; - wl_event_source_timer_update(kb->key_repeat_source, - kb->wlr_keyboard->repeat_info.delay); - } else { - kb->nsyms = 0; - wl_event_source_timer_update(kb->key_repeat_source, 0); - } + /* On _press_ if there is no active screen locker, + * attempt to process a compositor keybinding. */ + if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { + for (i = 0; i < nsyms; i++) + handled = keybinding(mods, syms[i]) || handled; + } - if (handled) - return; + if (handled && group->wlr_group->keyboard.repeat_info.delay > 0) { + group->mods = mods; + group->keysyms = syms; + group->nsyms = nsyms; + wl_event_source_timer_update(group->key_repeat_source, + group->wlr_group->keyboard.repeat_info.delay); + } else { + group->nsyms = 0; + wl_event_source_timer_update(group->key_repeat_source, 0); + } + + if (handled) + return; #ifdef IM - /* if there is a keyboard grab, we send the key there */ - struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(kb); - if (kb_grab) { - wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab, kb->wlr_keyboard); - wlr_input_method_keyboard_grab_v2_send_key(kb_grab, event->time_msec, - event->keycode, event->state); - wlr_log(WLR_DEBUG, "keypress send to IM:%u mods %u state %u", - event->keycode, mods, event->state); - return; - } + /* if there is a keyboard grab, we send the key there */ + struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(group); + if (kb_grab) { + wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab,&(group->wlr_group->keyboard)); + wlr_input_method_keyboard_grab_v2_send_key(kb_grab,event->time_msec, event->keycode, event->state); + wlr_log(WLR_DEBUG, "keypress send to IM:%u mods %u state %u",event->keycode, mods,event->state); + return; + } #endif - /* Pass unhandled keycodes along to the client. */ - wlr_seat_set_keyboard(seat, kb->wlr_keyboard); - wlr_seat_keyboard_notify_key(seat, event->time_msec, event->keycode, - event->state); + wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); + /* Pass unhandled keycodes along to the client. */ + wlr_seat_keyboard_notify_key(seat, event->time_msec, + event->keycode, event->state); } -void // 17 -keypressmod(struct wl_listener *listener, void *data) { - /* This event is raised when a modifier key, such as shift or alt, is - * pressed. We simply communicate this to the client. */ - Keyboard *kb = wl_container_of(listener, kb, modifiers); + +void +keypressmod(struct wl_listener *listener, void *data) +{ + /* This event is raised when a modifier key, such as shift or alt, is + * pressed. We simply communicate this to the client. */ + KeyboardGroup *group = wl_container_of(listener, group, modifiers); + #ifdef IM - struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(kb); - if (kb_grab) { - wlr_input_method_keyboard_grab_v2_send_modifiers( - kb_grab, &kb->wlr_keyboard->modifiers); - wlr_log(WLR_DEBUG, "keypressmod send to IM"); - return; - } + struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(group); + if (kb_grab) { + wlr_input_method_keyboard_grab_v2_send_modifiers(kb_grab, + &group->wlr_group->keyboard.modifiers); + wlr_log(WLR_DEBUG, "keypressmod send to IM"); + return; + } #endif - /* - * A seat can only have one keyboard, but this is a limitation of the - * Wayland protocol - not wlroots. We assign all connected keyboards to the - * same seat. You can swap out the underlying wlr_keyboard like this and - * wlr_seat handles this transparently. - */ - wlr_seat_set_keyboard(seat, kb->wlr_keyboard); - /* Send modifiers to the client. */ - wlr_seat_keyboard_notify_modifiers(seat, &kb->wlr_keyboard->modifiers); + wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); + /* Send modifiers to the client. */ + wlr_seat_keyboard_notify_modifiers(seat, + &group->wlr_group->keyboard.modifiers); } static bool scene_node_snapshot(struct wlr_scene_node *node, int lx, int ly, @@ -3981,38 +4039,32 @@ void outputmgrtest(struct wl_listener *listener, void *data) { outputmgrapplyortest(config, 1); } -void // 17 +void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, - uint32_t time) { - struct timespec now; - int internal_call = !time; + uint32_t time) +{ + struct timespec now; - if (surface != seat->pointer_state.focused_surface && sloppyfocus && time && - c && !client_is_unmanaged(c)) - focusclient(c, 0); + if (surface != seat->pointer_state.focused_surface && + sloppyfocus && time && c && !client_is_unmanaged(c)) + focusclient(c, 0); - /* If surface is NULL, try use the focused client surface to set pointer foucs - */ - if (time == 0 && !surface && selmon && selmon->sel) { - surface = client_surface(selmon->sel); - } + /* If surface is NULL, clear pointer focus */ + if (!surface) { + wlr_seat_pointer_notify_clear_focus(seat); + return; + } - /* If surface is still NULL, clear pointer focus */ - if (!surface) { - wlr_seat_pointer_notify_clear_focus(seat); - return; - } + if (!time) { + clock_gettime(CLOCK_MONOTONIC, &now); + time = now.tv_sec * 1000 + now.tv_nsec / 1000000; + } - if (internal_call) { - clock_gettime(CLOCK_MONOTONIC, &now); - time = now.tv_sec * 1000 + now.tv_nsec / 1000000; - } - - /* Let the client know that the mouse cursor has entered one - * of its surfaces, and make keyboard focus follow if desired. - * wlroots makes this a no-op if surface is already focused */ - wlr_seat_pointer_notify_enter(seat, surface, sx, sy); - wlr_seat_pointer_notify_motion(seat, time, sx, sy); + /* Let the client know that the mouse cursor has entered one + * of its surfaces, and make keyboard focus follow if desired. + * wlroots makes this a no-op if surface is already focused */ + wlr_seat_pointer_notify_enter(seat, surface, sx, sy); + wlr_seat_pointer_notify_motion(seat, time, sx, sy); } void // 17 @@ -4254,8 +4306,8 @@ void set_open_animaiton(Client *c, struct wlr_box geo) { int vertical, vertical_value; int special_direction; int center_x, center_y; - if (strcmp(animation_type, "zoom") == 0 || - (c->animation_type && strcmp(c->animation_type, "zoom") == 0)) { + if (strcmp(animation_type_open, "zoom") == 0 || + (c->animation_type_open && strcmp(c->animation_type_open, "zoom") == 0)) { c->animainit_geom.width = geo.width * zoom_initial_ratio; c->animainit_geom.height = geo.height * zoom_initial_ratio; c->animainit_geom.x = geo.x + (geo.width - c->animainit_geom.width) / 2; @@ -4746,24 +4798,26 @@ void setmon(Client *c, Monitor *m, uint32_t newtags) { focusclient(focustop(selmon), 1); } -void // 17 -setpsel(struct wl_listener *listener, void *data) { - /* This event is raised by the seat when a client wants to set the selection, - * usually when the user copies something. wlroots allows compositors to - * ignore such requests if they so choose, but in dwl we always honor - */ - struct wlr_seat_request_set_primary_selection_event *event = data; - wlr_seat_set_primary_selection(seat, event->source, event->serial); +void +setpsel(struct wl_listener *listener, void *data) +{ + /* This event is raised by the seat when a client wants to set the selection, + * usually when the user copies something. wlroots allows compositors to + * ignore such requests if they so choose, but in dwl we always honor + */ + struct wlr_seat_request_set_primary_selection_event *event = data; + wlr_seat_set_primary_selection(seat, event->source, event->serial); } -void // 17 -setsel(struct wl_listener *listener, void *data) { - /* This event is raised by the seat when a client wants to set the selection, - * usually when the user copies something. wlroots allows compositors to - * ignore such requests if they so choose, but in dwl we always honor - */ - struct wlr_seat_request_set_selection_event *event = data; - wlr_seat_set_selection(seat, event->source, event->serial); +void +setsel(struct wl_listener *listener, void *data) +{ + /* This event is raised by the seat when a client wants to set the selection, + * usually when the user copies something. wlroots allows compositors to + * ignore such requests if they so choose, but in dwl we always honor + */ + struct wlr_seat_request_set_selection_event *event = data; + wlr_seat_set_selection(seat, event->source, event->serial); } // 获取tags中最坐标的tag的tagmask @@ -5107,6 +5161,9 @@ void setup(void) { wl_signal_add(&seat->events.request_start_drag, &request_start_drag); wl_signal_add(&seat->events.start_drag, &start_drag); + kb_group = createkeyboardgroup(); + wl_list_init(&kb_group->destroy.link); + output_mgr = wlr_output_manager_v1_create(dpy); wl_signal_add(&output_mgr->events.apply, &output_mgr_apply); wl_signal_add(&output_mgr->events.test, &output_mgr_test); @@ -5922,7 +5979,7 @@ void init_fadeout_client(Client *c) { fadeout_cient->geom = fadeout_cient->current = fadeout_cient->animainit_geom = fadeout_cient->animation.initial = c->animation.current; fadeout_cient->mon = c->mon; - fadeout_cient->animation_type = c->animation_type; + fadeout_cient->animation_type_close = c->animation_type_close; fadeout_cient->animation.action = CLOSE; fadeout_cient->bw = c->bw; @@ -5931,8 +5988,8 @@ void init_fadeout_client(Client *c) { fadeout_cient->animation.initial.x = 0; fadeout_cient->animation.initial.y = 0; - if ((c->animation_type && strcmp(c->animation_type, "slide") == 0) || - (!c->animation_type && strcmp(animation_type, "slide") == 0)) { + if ((c->animation_type_close && strcmp(c->animation_type_close, "slide") == 0) || + (!c->animation_type_close && strcmp(animation_type_close, "slide") == 0)) { fadeout_cient->current.y = c->geom.y + c->geom.height / 2 > c->mon->m.y + c->mon->m.height / 2 ? c->mon->m.height - @@ -5941,11 +5998,11 @@ void init_fadeout_client(Client *c) { fadeout_cient->current.x = 0; // x无偏差,垂直划出 } else { fadeout_cient->current.y = - (c->geom.height - c->geom.height * zoom_initial_ratio) / 2; + (fadeout_cient->geom.height - fadeout_cient->geom.height * zoom_initial_ratio) / 2; fadeout_cient->current.x = - (c->geom.width - c->geom.width * zoom_initial_ratio) / 2; - fadeout_cient->current.width = c->geom.width * zoom_initial_ratio; - fadeout_cient->current.height = c->geom.height * zoom_initial_ratio; + (fadeout_cient->geom.width - fadeout_cient->geom.width * zoom_initial_ratio) / 2; + fadeout_cient->current.width = fadeout_cient->geom.width * zoom_initial_ratio; + fadeout_cient->current.height = fadeout_cient->geom.height * zoom_initial_ratio; } fadeout_cient->animation.passed_frames = 0; @@ -5956,6 +6013,7 @@ void init_fadeout_client(Client *c) { wl_list_insert(&fadeout_clients, &fadeout_cient->fadeout_link); } + void unmapnotify(struct wl_listener *listener, void *data) { /* Called when the surface is unmapped, and should no longer be shown. */ Client *c = wl_container_of(listener, c, unmap); @@ -6375,9 +6433,18 @@ void tagtoright(const Arg *arg) { } } -void virtualkeyboard(struct wl_listener *listener, void *data) { - struct wlr_virtual_keyboard_v1 *keyboard = data; - createkeyboard(&keyboard->keyboard); +void +virtualkeyboard(struct wl_listener *listener, void *data) +{ + struct wlr_virtual_keyboard_v1 *kb = data; + /* virtual keyboards shouldn't share keyboard group */ + KeyboardGroup *group = createkeyboardgroup(); + /* Set the keymap to match the group keymap */ + wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap); + LISTEN(&kb->keyboard.base.events.destroy, &group->destroy, destroykeyboardgroup); + + /* Add the new keyboard to the group */ + wlr_keyboard_group_add_keyboard(group->wlr_group, &kb->keyboard); } void warp_cursor(const Client *c) { diff --git a/parse_config.h b/parse_config.h index 9e42364b..8d0850ad 100644 --- a/parse_config.h +++ b/parse_config.h @@ -14,7 +14,8 @@ typedef struct { int isfloating; int isfullscreen; float scroller_proportion; - const char *animation_type; + const char *animation_type_open; + const char *animation_type_close; int isnoborder; int monitor; int width; @@ -71,7 +72,8 @@ typedef struct { typedef struct { int animations; - char animation_type[10]; + char animation_type_open[10]; + char animation_type_close[10]; char animation_fade_in; float zoom_initial_ratio; float fadein_begin_opacity; @@ -481,8 +483,10 @@ void parse_config_line(Config *config, const char *line) { if (strcmp(key, "animations") == 0) { config->animations = atoi(value); - } else if (strcmp(key, "animation_type") == 0) { - strncpy(config->animation_type, value, sizeof(config->animation_type)); + } else if (strcmp(key, "animation_type_open") == 0) { + strncpy(config->animation_type_open, value, sizeof(config->animation_type_open)); + } else if (strcmp(key, "animation_type_close") == 0) { + strncpy(config->animation_type_close, value, sizeof(config->animation_type_close)); } else if (strcmp(key, "animation_fade_in") == 0) { config->animation_fade_in = atoi(value); } else if (strcmp(key, "zoom_initial_ratio") == 0) { @@ -792,7 +796,8 @@ void parse_config_line(Config *config, const char *line) { rule->monitor = -1; rule->width = -1; rule->height = -1; - rule->animation_type = NULL; + rule->animation_type_open = NULL; + rule->animation_type_close = NULL; rule->scroller_proportion = -1; rule->id = NULL; rule->title = NULL; @@ -812,8 +817,10 @@ void parse_config_line(Config *config, const char *line) { rule->title = strdup(val); } else if (strcmp(key, "appid") == 0) { rule->id = strdup(val); - } else if (strcmp(key, "animation_type") == 0) { - rule->animation_type = strdup(val); + } else if (strcmp(key, "animation_type_open") == 0) { + rule->animation_type_open = strdup(val); + } else if (strcmp(key, "animation_type_close") == 0) { + rule->animation_type_close = strdup(val); } else if (strcmp(key, "tags") == 0) { rule->tags = 1 << (atoi(val) - 1); } else if (strcmp(key, "monitor") == 0) { @@ -1029,8 +1036,10 @@ void free_config(void) { free((void *)rule->id); if (rule->title) free((void *)rule->title); - if (rule->animation_type) - free((void *)rule->animation_type); + if (rule->animation_type_open) + free((void *)rule->animation_type_open); + if (rule->animation_type_close) + free((void *)rule->animation_type_close); } free(config.window_rules); @@ -1076,7 +1085,8 @@ void free_config(void) { void override_config(void) { animations = config.animations; - animation_type = config.animation_type; + animation_type_open = config.animation_type_open; + animation_type_close = config.animation_type_close; animation_fade_in = config.animation_fade_in; zoom_initial_ratio = config.zoom_initial_ratio; fadein_begin_opacity = config.fadein_begin_opacity; diff --git a/preset_config.h b/preset_config.h index fde26972..1f8cb639 100644 --- a/preset_config.h +++ b/preset_config.h @@ -5,7 +5,8 @@ ((hex >> 8) & 0xFF) / 255.0f, (hex & 0xFF) / 255.0f} /* animaion */ -char *animation_type = "slide"; // 是否启用动画 //slide,zoom +char *animation_type_open = "slide"; // 是否启用动画 //slide,zoom +char *animation_type_close = "slide"; // 是否启用动画 //slide,zoom int animations = 1; // 是否启用动画 char animation_fade_in = 1; // Enable animation fade in float zoom_initial_ratio = 0.5; // 动画起始窗口比例 @@ -30,6 +31,7 @@ unsigned int default_nmaster = 1; // 默认master数量 /* logging */ int log_level = WLR_ERROR; unsigned int numlockon = 1; // 是否打开右边小键盘 +unsigned int capslock = 0; // 是否打开大写锁定 unsigned int ov_tab_mode = 0; // alt tab切换模式 unsigned int hotarea_size = 10; // 热区大小,10x10