From 549d46bda4465c49dffdbc4349cff71c40e869d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 10 Oct 2020 11:29:04 +0200 Subject: [PATCH 01/12] shm: MAP_UNINITIALIZED is a linux only mmap flag --- shm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/shm.c b/shm.c index 8a0a136d..751e265d 100644 --- a/shm.c +++ b/shm.c @@ -25,6 +25,10 @@ #include "macros.h" #include "xmalloc.h" +#if !defined(MAP_UNINITIALIZED) + #define MAP_UNINITIALIZED 0 +#endif + #define TIME_SCROLL 0 /* From e85ace0b0d0bc50cd8ddfbd27586b298f22cb7ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 6 Nov 2020 20:06:31 +0100 Subject: [PATCH 02/12] changelog: prepare for 1.5.3 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d43150f..62679e3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Changelog +* [1.5.3](#1-5-3) * [1.5.2](#1-5-2) * [1.5.1](#1-5-1) * [1.5.0](#1-5-0) @@ -14,6 +15,10 @@ * [1.2.1](#1-2-1) * [1.2.0](#1-2-0) +## 1.5.3 + +### Fixed + ## 1.5.2 From 9e7783596aad33fcb5564186feb93d94e465627b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 19 Oct 2020 18:30:19 +0200 Subject: [PATCH 03/12] =?UTF-8?q?input:=20don=E2=80=99t=20crash=20if=20xkb?= =?UTF-8?q?common=20cannot=20find=20a=20compose=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handle xkb_compose_table_new_from_locale() returning NULL. When this happens, log a warning that “dead keys” will be disabled, and make sure to never de-reference the compose table pointer. Closes #170 --- CHANGELOG.md | 4 ++++ input.c | 32 ++++++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62679e3d..9b610573 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,10 @@ ### Fixed +* Crash when libxkbcommon cannot find a suitable libX11 _compose_ + file. Note that foot will run, but without support for dead keys. + (https://codeberg.org/dnkl/foot/issues/170). + ## 1.5.2 diff --git a/input.c b/input.c index 160c78a7..7042f645 100644 --- a/input.c +++ b/input.c @@ -504,8 +504,13 @@ keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, /* Compose (dead keys) */ seat->kbd.xkb_compose_table = xkb_compose_table_new_from_locale( seat->kbd.xkb, setlocale(LC_CTYPE, NULL), XKB_COMPOSE_COMPILE_NO_FLAGS); - seat->kbd.xkb_compose_state = xkb_compose_state_new( - seat->kbd.xkb_compose_table, XKB_COMPOSE_STATE_NO_FLAGS); + + if (seat->kbd.xkb_compose_table == NULL) { + LOG_WARN("failed to instantiate compose table; dead keys will not work"); + } else { + seat->kbd.xkb_compose_state = xkb_compose_state_new( + seat->kbd.xkb_compose_table, XKB_COMPOSE_STATE_NO_FLAGS); + } munmap(map_str, size); close(fd); @@ -604,7 +609,8 @@ keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, seat->kbd.alt = false; seat->kbd.ctrl = false; seat->kbd.meta = false; - xkb_compose_state_reset(seat->kbd.xkb_compose_state); + if (seat->kbd.xkb_compose_state != NULL) + xkb_compose_state_reset(seat->kbd.xkb_compose_state); if (old_focused != NULL) { seat->pointer.hidden = false; @@ -782,9 +788,13 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, LOG_INFO("%s", foo); #endif - xkb_compose_state_feed(seat->kbd.xkb_compose_state, sym); - enum xkb_compose_status compose_status = xkb_compose_state_get_status( - seat->kbd.xkb_compose_state); + enum xkb_compose_status compose_status = XKB_COMPOSE_NOTHING; + + if (seat->kbd.xkb_compose_state != NULL) { + xkb_compose_state_feed(seat->kbd.xkb_compose_state, sym); + compose_status = xkb_compose_state_get_status( + seat->kbd.xkb_compose_state); + } if (compose_status == XKB_COMPOSE_COMPOSING) { /* TODO: goto maybe_repeat? */ @@ -868,12 +878,18 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, int count = 0; if (compose_status == XKB_COMPOSE_COMPOSED) { + assert(seat->kbd.xkb_compose_state != NULL); + count = xkb_compose_state_get_utf8( seat->kbd.xkb_compose_state, (char *)buf, sizeof(buf)); xkb_compose_state_reset(seat->kbd.xkb_compose_state); - } else if (compose_status == XKB_COMPOSE_CANCELLED) { + } + + else if (compose_status == XKB_COMPOSE_CANCELLED) { goto maybe_repeat; - } else { + } + + else { count = xkb_state_key_get_utf8( seat->kbd.xkb_state, key, (char *)buf, sizeof(buf)); } From ebd4a32768ba1e587fb884b58819605f4ef87c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 20 Oct 2020 20:58:03 +0200 Subject: [PATCH 04/12] wayland: properly restore window size when being un-tiled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bind to xdg-shell version 2 if available, as this enables us to track our window’s ‘tiled’ state in the ‘configure’ events. This in turn allows us to stash the ‘old’ window size when being tiled, to be used again when restoring the window size when un-tiled. --- CHANGELOG.md | 1 + render.c | 17 +++++++++++------ terminal.h | 4 ++-- wayland.c | 38 +++++++++++++++++++++++++++++--------- wayland.h | 9 +++++++++ 5 files changed, 52 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b610573..31da15a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ * Crash when libxkbcommon cannot find a suitable libX11 _compose_ file. Note that foot will run, but without support for dead keys. (https://codeberg.org/dnkl/foot/issues/170). +* Restored window size when window is un-tiled. ## 1.5.2 diff --git a/render.c b/render.c index a5df70f7..819a249b 100644 --- a/render.c +++ b/render.c @@ -2038,9 +2038,9 @@ maybe_resize(struct terminal *term, int width, int height, bool force) * If we have a "last" used size - use that. Otherwise, use * the size from the user configuration. */ - if (term->unmaximized_width != 0 && term->unmaximized_height != 0) { - width = term->unmaximized_width; - height = term->unmaximized_height; + if (term->stashed_width != 0 && term->stashed_height != 0) { + width = term->stashed_width; + height = term->stashed_height; } else { switch (term->conf->size.type) { case CONF_SIZE_PX: @@ -2193,9 +2193,14 @@ maybe_resize(struct terminal *term, int width, int height, bool force) term->render.last_cursor.row = NULL; damage_view: - if (!term->window->is_maximized && !term->window->is_fullscreen) { - term->unmaximized_width = term->width; - term->unmaximized_height = term->height; + if (!term->window->is_maximized && + !term->window->is_fullscreen && + !term->window->is_tiled) + { + /* Stash current size, to enable us to restore it when we're + * being un-maximized/fullscreened/tiled */ + term->stashed_width = term->width; + term->stashed_height = term->height; } #if 0 diff --git a/terminal.h b/terminal.h index 2d199fcb..eede87c1 100644 --- a/terminal.h +++ b/terminal.h @@ -295,8 +295,8 @@ struct terminal { int scale; int width; /* pixels */ int height; /* pixels */ - int unmaximized_width; /* last unmaximized size, pixels */ - int unmaximized_height; /* last unmaximized size, pixels */ + int stashed_width; + int stashed_height; struct { int left; int right; diff --git a/wayland.c b/wayland.c index dce240d3..a663db4d 100644 --- a/wayland.c +++ b/wayland.c @@ -485,6 +485,10 @@ xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel, bool is_activated = false; bool is_fullscreen = false; bool is_maximized = false; + bool is_tiled_top = false; + bool is_tiled_bottom = false; + bool is_tiled_left = false; + bool is_tiled_right = false; #if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG char state_str[2048]; @@ -505,16 +509,17 @@ xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel, enum xdg_toplevel_state *state; wl_array_for_each(state, states) { switch (*state) { - case XDG_TOPLEVEL_STATE_ACTIVATED: is_activated = true; break; - case XDG_TOPLEVEL_STATE_FULLSCREEN: is_fullscreen = true; break; - case XDG_TOPLEVEL_STATE_MAXIMIZED: is_maximized = true; break; + case XDG_TOPLEVEL_STATE_ACTIVATED: is_activated = true; break; + case XDG_TOPLEVEL_STATE_FULLSCREEN: is_fullscreen = true; break; + case XDG_TOPLEVEL_STATE_MAXIMIZED: is_maximized = true; break; + case XDG_TOPLEVEL_STATE_TILED_LEFT: is_tiled_left = true; break; + case XDG_TOPLEVEL_STATE_TILED_RIGHT: is_tiled_right = true; break; + case XDG_TOPLEVEL_STATE_TILED_TOP: is_tiled_top = true; break; + case XDG_TOPLEVEL_STATE_TILED_BOTTOM: is_tiled_bottom = true; break; case XDG_TOPLEVEL_STATE_RESIZING: - case XDG_TOPLEVEL_STATE_TILED_LEFT: - case XDG_TOPLEVEL_STATE_TILED_RIGHT: - case XDG_TOPLEVEL_STATE_TILED_TOP: - case XDG_TOPLEVEL_STATE_TILED_BOTTOM: /* Ignored */ + /* TODO: throttle? */ break; } @@ -535,7 +540,7 @@ xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel, else state_str[0] = '\0'; - LOG_DBG("xdg-toplevel: configure: size=%dx%d, states=%s", + LOG_DBG("xdg-toplevel: configure: size=%dx%d, states=[%s]", width, height, state_str); #endif @@ -559,6 +564,10 @@ xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel, win->configure.is_activated = is_activated; win->configure.is_fullscreen = is_fullscreen; win->configure.is_maximized = is_maximized; + win->configure.is_tiled_top = is_tiled_top; + win->configure.is_tiled_bottom = is_tiled_bottom; + win->configure.is_tiled_left = is_tiled_left; + win->configure.is_tiled_right = is_tiled_right; win->configure.width = width; win->configure.height = height; } @@ -589,6 +598,11 @@ xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, bool wasnt_configured = !win->is_configured; win->is_configured = true; win->is_maximized = win->configure.is_maximized; + win->is_tiled_top = win->configure.is_tiled_top; + win->is_tiled_bottom = win->configure.is_tiled_bottom; + win->is_tiled_left = win->configure.is_tiled_left; + win->is_tiled_right = win->configure.is_tiled_right; + win->is_tiled = win->is_tiled_top || win->is_tiled_bottom || win->is_tiled_left || win->is_tiled_right; if (win->is_fullscreen != win->configure.is_fullscreen && win->use_csd == CSD_YES) { if (win->configure.is_fullscreen) @@ -736,8 +750,14 @@ handle_global(void *data, struct wl_registry *registry, if (!verify_iface_version(interface, version, required)) return; + /* + * We *require* version 1, but _can_ use version 2. Version 2 + * adds 'tiled' window states. We use that information to + * restore the window size when window is un-tiled. + */ + wayl->shell = wl_registry_bind( - wayl->registry, name, &xdg_wm_base_interface, required); + wayl->registry, name, &xdg_wm_base_interface, min(version, 2)); xdg_wm_base_add_listener(wayl->shell, &xdg_wm_base_listener, wayl); } diff --git a/wayland.h b/wayland.h index 7d512ba0..70c2098a 100644 --- a/wayland.h +++ b/wayland.h @@ -314,10 +314,19 @@ struct wl_window { bool is_configured; bool is_fullscreen; bool is_maximized; + bool is_tiled_top; + bool is_tiled_bottom; + bool is_tiled_left; + bool is_tiled_right; + bool is_tiled; /* At least one of is_tiled_{top,bottom,left,right} is true */ struct { bool is_activated; bool is_fullscreen; bool is_maximized; + bool is_tiled_top; + bool is_tiled_bottom; + bool is_tiled_left; + bool is_tiled_right; int width; int height; } configure; From 90544ef391f0c546e831255036a939ac5314f6a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 20 Oct 2020 21:00:19 +0200 Subject: [PATCH 05/12] =?UTF-8?q?input:=20don=E2=80=99t=20allow=20diagonal?= =?UTF-8?q?=20resize=20when=20tiled?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + input.c | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31da15a9..afc400bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ file. Note that foot will run, but without support for dead keys. (https://codeberg.org/dnkl/foot/issues/170). * Restored window size when window is un-tiled. +* XCursor shape in CSD corners when window is tiled. ## 1.5.2 diff --git a/input.c b/input.c index 7042f645..0ade6db0 100644 --- a/input.c +++ b/input.c @@ -1049,8 +1049,9 @@ is_top_left(const struct terminal *term, int x, int y) { int csd_border_size = term->conf->csd.border_width; return ( - (term->active_surface == TERM_SURF_BORDER_LEFT && y < 10 * term->scale) || - (term->active_surface == TERM_SURF_BORDER_TOP && x < (10 + csd_border_size) * term->scale)); + (!term->window->is_tiled_top && !term->window->is_tiled_left) && + ((term->active_surface == TERM_SURF_BORDER_LEFT && y < 10 * term->scale) || + (term->active_surface == TERM_SURF_BORDER_TOP && x < (10 + csd_border_size) * term->scale))); } static bool @@ -1058,8 +1059,9 @@ is_top_right(const struct terminal *term, int x, int y) { int csd_border_size = term->conf->csd.border_width; return ( - (term->active_surface == TERM_SURF_BORDER_RIGHT && y < 10 * term->scale) || - (term->active_surface == TERM_SURF_BORDER_TOP && x > term->width + 1 * csd_border_size * term->scale - 10 * term->scale)); + (!term->window->is_tiled_top && !term->window->is_tiled_right) && + ((term->active_surface == TERM_SURF_BORDER_RIGHT && y < 10 * term->scale) || + (term->active_surface == TERM_SURF_BORDER_TOP && x > term->width + 1 * csd_border_size * term->scale - 10 * term->scale))); } static bool @@ -1068,8 +1070,9 @@ is_bottom_left(const struct terminal *term, int x, int y) int csd_title_size = term->conf->csd.title_height; int csd_border_size = term->conf->csd.border_width; return ( - (term->active_surface == TERM_SURF_BORDER_LEFT && y > csd_title_size * term->scale + term->height) || - (term->active_surface == TERM_SURF_BORDER_BOTTOM && x < (10 + csd_border_size) * term->scale)); + (!term->window->is_tiled_bottom && !term->window->is_tiled_left) && + ((term->active_surface == TERM_SURF_BORDER_LEFT && y > csd_title_size * term->scale + term->height) || + (term->active_surface == TERM_SURF_BORDER_BOTTOM && x < (10 + csd_border_size) * term->scale))); } static bool @@ -1078,8 +1081,9 @@ is_bottom_right(const struct terminal *term, int x, int y) int csd_title_size = term->conf->csd.title_height; int csd_border_size = term->conf->csd.border_width; return ( - (term->active_surface == TERM_SURF_BORDER_RIGHT && y > csd_title_size * term->scale + term->height) || - (term->active_surface == TERM_SURF_BORDER_BOTTOM && x > term->width + 1 * csd_border_size * term->scale - 10 * term->scale)); + (!term->window->is_tiled_bottom && !term->window->is_tiled_right) && + ((term->active_surface == TERM_SURF_BORDER_RIGHT && y > csd_title_size * term->scale + term->height) || + (term->active_surface == TERM_SURF_BORDER_BOTTOM && x > term->width + 1 * csd_border_size * term->scale - 10 * term->scale))); } static const char * From 30f23a3b743525bf7daf4334a549030956146b15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 20 Oct 2020 21:01:33 +0200 Subject: [PATCH 06/12] input: handle XKB errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Don’t de-reference the xkb context/keymap/state if we failed to instantiate them. * Don’t try to send a translated utf8 key sequence if the translation failed. * Handle xkb_compose_state_get_utf8() and xkb_state_key_get_utf8() returning more than 64 bytes. This _may_ fix #171. --- CHANGELOG.md | 2 + input.c | 134 ++++++++++++++++++++++++++++----------------------- 2 files changed, 76 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index afc400bc..2c0d03aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ (https://codeberg.org/dnkl/foot/issues/170). * Restored window size when window is un-tiled. * XCursor shape in CSD corners when window is tiled. +* Error handling when processing keyboard input (maybe + https://codeberg.org/dnkl/foot/issues/171). ## 1.5.2 diff --git a/input.c b/input.c index 0ade6db0..afd641ca 100644 --- a/input.c +++ b/input.c @@ -487,29 +487,34 @@ keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, tll_free(seat->mouse.bindings); seat->kbd.xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - seat->kbd.xkb_keymap = xkb_keymap_new_from_buffer( - seat->kbd.xkb, map_str, size, XKB_KEYMAP_FORMAT_TEXT_V1, - XKB_KEYMAP_COMPILE_NO_FLAGS); - seat->kbd.xkb_state = xkb_state_new(seat->kbd.xkb_keymap); + if (seat->kbd.xkb != NULL) { + seat->kbd.xkb_keymap = xkb_keymap_new_from_buffer( + seat->kbd.xkb, map_str, size, XKB_KEYMAP_FORMAT_TEXT_V1, + XKB_KEYMAP_COMPILE_NO_FLAGS); - seat->kbd.mod_shift = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Shift"); - seat->kbd.mod_alt = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Mod1") ; - seat->kbd.mod_ctrl = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Control"); - seat->kbd.mod_meta = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Mod4"); + /* Compose (dead keys) */ + seat->kbd.xkb_compose_table = xkb_compose_table_new_from_locale( + seat->kbd.xkb, setlocale(LC_CTYPE, NULL), XKB_COMPOSE_COMPILE_NO_FLAGS); - seat->kbd.key_arrow_up = xkb_keymap_key_by_name(seat->kbd.xkb_keymap, "UP"); - seat->kbd.key_arrow_down = xkb_keymap_key_by_name(seat->kbd.xkb_keymap, "DOWN"); + if (seat->kbd.xkb_compose_table == NULL) { + LOG_WARN("failed to instantiate compose table; dead keys will not work"); + } else { + seat->kbd.xkb_compose_state = xkb_compose_state_new( + seat->kbd.xkb_compose_table, XKB_COMPOSE_STATE_NO_FLAGS); + } + } - /* Compose (dead keys) */ - seat->kbd.xkb_compose_table = xkb_compose_table_new_from_locale( - seat->kbd.xkb, setlocale(LC_CTYPE, NULL), XKB_COMPOSE_COMPILE_NO_FLAGS); + if (seat->kbd.xkb_keymap != NULL) { + seat->kbd.xkb_state = xkb_state_new(seat->kbd.xkb_keymap); - if (seat->kbd.xkb_compose_table == NULL) { - LOG_WARN("failed to instantiate compose table; dead keys will not work"); - } else { - seat->kbd.xkb_compose_state = xkb_compose_state_new( - seat->kbd.xkb_compose_table, XKB_COMPOSE_STATE_NO_FLAGS); + seat->kbd.mod_shift = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Shift"); + seat->kbd.mod_alt = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Mod1") ; + seat->kbd.mod_ctrl = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Control"); + seat->kbd.mod_meta = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Mod4"); + + seat->kbd.key_arrow_up = xkb_keymap_key_by_name(seat->kbd.xkb_keymap, "UP"); + seat->kbd.key_arrow_down = xkb_keymap_key_by_name(seat->kbd.xkb_keymap, "DOWN"); } munmap(map_str, size); @@ -749,8 +754,12 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct seat *seat = data; struct terminal *term = seat->kbd_focus; - if (seat->kbd.xkb == NULL) + if (seat->kbd.xkb == NULL || + seat->kbd.xkb_keymap == NULL || + seat->kbd.xkb_state == NULL) + { return; + } assert(term != NULL); @@ -870,39 +879,43 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, goto maybe_repeat; } + if (compose_status == XKB_COMPOSE_CANCELLED) + goto maybe_repeat; + /* * Compose, and maybe emit "normal" character */ - uint8_t buf[64] = {0}; - int count = 0; + assert(seat->kbd.xkb_compose_state != NULL || + compose_status != XKB_COMPOSE_COMPOSED); - if (compose_status == XKB_COMPOSE_COMPOSED) { - assert(seat->kbd.xkb_compose_state != NULL); + int count = compose_status == XKB_COMPOSE_COMPOSED + ? xkb_compose_state_get_utf8(seat->kbd.xkb_compose_state, NULL, 0) + : xkb_state_key_get_utf8(seat->kbd.xkb_state, key, NULL, 0); - count = xkb_compose_state_get_utf8( - seat->kbd.xkb_compose_state, (char *)buf, sizeof(buf)); + if (count <= 0) + goto maybe_repeat; + + /* Buffer for translated key. Use a static buffer in most cases, + * and use a malloc:ed buffer when necessary */ + uint8_t buf[32]; + uint8_t *utf8 = count < sizeof(buf) ? buf : xmalloc(count + 1); + + compose_status == XKB_COMPOSE_COMPOSED + ? xkb_compose_state_get_utf8( + seat->kbd.xkb_compose_state, (char *)utf8, count + 1) + : xkb_state_key_get_utf8( + seat->kbd.xkb_state, key, (char *)utf8, count + 1); + + if (seat->kbd.xkb_compose_state != NULL) xkb_compose_state_reset(seat->kbd.xkb_compose_state); - } - - else if (compose_status == XKB_COMPOSE_CANCELLED) { - goto maybe_repeat; - } - - else { - count = xkb_state_key_get_utf8( - seat->kbd.xkb_state, key, (char *)buf, sizeof(buf)); - } - - if (count == 0) - goto maybe_repeat; #define is_control_key(x) ((x) >= 0x40 && (x) <= 0x7f) #define IS_CTRL(x) ((x) < 0x20 || ((x) >= 0x7f && (x) <= 0x9f)) if ((keymap_mods & MOD_CTRL) && !is_control_key(sym) && - (count == 1 && !IS_CTRL(buf[0])) && + (count == 1 && !IS_CTRL(utf8[0])) && sym < 256) { static const int mod_param_map[32] = { @@ -953,11 +966,11 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, */ if (term->meta.esc_prefix) { term_to_slave(term, "\x1b", 1); - term_to_slave(term, buf, count); + term_to_slave(term, utf8, count); } else if (term->meta.eight_bit && count == 1) { - const wchar_t wc = 0x80 | buf[0]; + const wchar_t wc = 0x80 | utf8[0]; char utf8[8]; mbstate_t ps = {0}; @@ -966,17 +979,20 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, if (chars != (size_t)-1) term_to_slave(term, utf8, chars); else - term_to_slave(term, buf, count); + term_to_slave(term, utf8, count); } else { /* Alt ignored */ - term_to_slave(term, buf, count); + term_to_slave(term, utf8, count); } } else - term_to_slave(term, buf, count); + term_to_slave(term, utf8, count); } + if (utf8 != buf) + free(utf8); + term_reset_view(term); selection_cancel(term); @@ -986,7 +1002,6 @@ maybe_repeat: if (should_repeat) start_repeater(seat, key - 8); - } static void @@ -999,21 +1014,20 @@ keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, LOG_DBG("modifiers: depressed=0x%x, latched=0x%x, locked=0x%x, group=%u", mods_depressed, mods_latched, mods_locked, group); - if (seat->kbd.xkb == NULL) - return; + if (seat->kbd.xkb_state != NULL) { + xkb_state_update_mask( + seat->kbd.xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group); - xkb_state_update_mask( - seat->kbd.xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group); - - /* Update state of modifiers we're interested in for e.g mouse events */ - seat->kbd.shift = xkb_state_mod_index_is_active( - seat->kbd.xkb_state, seat->kbd.mod_shift, XKB_STATE_MODS_DEPRESSED); - seat->kbd.alt = xkb_state_mod_index_is_active( - seat->kbd.xkb_state, seat->kbd.mod_alt, XKB_STATE_MODS_DEPRESSED); - seat->kbd.ctrl = xkb_state_mod_index_is_active( - seat->kbd.xkb_state, seat->kbd.mod_ctrl, XKB_STATE_MODS_DEPRESSED); - seat->kbd.meta = xkb_state_mod_index_is_active( - seat->kbd.xkb_state, seat->kbd.mod_meta, XKB_STATE_MODS_DEPRESSED); + /* Update state of modifiers we're interested in for e.g mouse events */ + seat->kbd.shift = xkb_state_mod_index_is_active( + seat->kbd.xkb_state, seat->kbd.mod_shift, XKB_STATE_MODS_DEPRESSED); + seat->kbd.alt = xkb_state_mod_index_is_active( + seat->kbd.xkb_state, seat->kbd.mod_alt, XKB_STATE_MODS_DEPRESSED); + seat->kbd.ctrl = xkb_state_mod_index_is_active( + seat->kbd.xkb_state, seat->kbd.mod_ctrl, XKB_STATE_MODS_DEPRESSED); + seat->kbd.meta = xkb_state_mod_index_is_active( + seat->kbd.xkb_state, seat->kbd.mod_meta, XKB_STATE_MODS_DEPRESSED); + } if (seat->kbd_focus && seat->kbd_focus->active_surface == TERM_SURF_GRID) term_xcursor_update_for_seat(seat->kbd_focus, seat); @@ -1535,7 +1549,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, switch (state) { case WL_POINTER_BUTTON_STATE_PRESSED: { if (!seat->mouse.consumed) { - if (seat->wl_keyboard != NULL) { + if (seat->wl_keyboard != NULL && seat->kbd.xkb_state != NULL) { /* Seat has keyboard - use mouse bindings *with* modifiers */ xkb_mod_mask_t mods = xkb_state_serialize_mods( From d31139515fadd8d79e5eb014d6ac188f98fc6b94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 25 Oct 2020 19:27:57 +0100 Subject: [PATCH 07/12] =?UTF-8?q?main:=20remove=20trailing=20=E2=80=98,=20?= =?UTF-8?q?=E2=80=99=20from=20arch=20log=20line?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.c b/main.c index 192a00f0..450b5818 100644 --- a/main.c +++ b/main.c @@ -349,7 +349,7 @@ main(int argc, char *const *argv) if (uname(&name) < 0) LOG_ERRNO("uname() failed"); else - LOG_INFO("arch: %s/%zu-bit, ", name.machine, sizeof(void *) * 8); + LOG_INFO("arch: %s/%zu-bit", name.machine, sizeof(void *) * 8); } struct config conf = {NULL}; From 273f105af5861e35f58b6a37e9b1b576dd9adaec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 29 Oct 2020 18:06:04 +0100 Subject: [PATCH 08/12] tiocswinsz: fix compilation error on e.g. ppc64 On some platforms, TIOCSWINSZ has a very large value, > 0x80000000. On some platforms, the `request` argument to `ioctl(3)` is an `int`. For platforms where both of the above is true, gcc will warn (and error out if compiled with `-Werror`) on: ioctl(fd, TIOCSWINSZ, ...) To silence this warning, we need to cast `TIOCSWINSZ` to an integer. However, doing this on platforms where `request` is an `unsigned long` will result in `TIOCSWINSZ` being sign-extended (and thus we end up with an invalid value). It seems that casting to `unsigned int` works in both cases; it silences the long -> int conversion warning, while also preserving the correct value in all cases. --- CHANGELOG.md | 3 +++ render.c | 2 +- terminal.c | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c0d03aa..02cab39e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,9 @@ * XCursor shape in CSD corners when window is tiled. * Error handling when processing keyboard input (maybe https://codeberg.org/dnkl/foot/issues/171). +* Compilation error _"overflow in conversion from long 'unsigned int' + to 'int' changes value... "_ seen on platforms where the `request` + argument in `ioctl(3)` is an `int` (for example: linux/ppc64). ## 1.5.2 diff --git a/render.c b/render.c index 819a249b..bad3e218 100644 --- a/render.c +++ b/render.c @@ -2174,7 +2174,7 @@ maybe_resize(struct terminal *term, int width, int height, bool force) term->margins.left, term->margins.right, term->margins.top, term->margins.bottom); /* Signal TIOCSWINSZ */ - if (term->ptmx >= 0 && ioctl(term->ptmx, TIOCSWINSZ, + if (term->ptmx >= 0 && ioctl(term->ptmx, (unsigned int)TIOCSWINSZ, &(struct winsize){ .ws_row = term->rows, .ws_col = term->cols, diff --git a/terminal.c b/terminal.c index f931ba7d..4651fc1a 100644 --- a/terminal.c +++ b/terminal.c @@ -883,7 +883,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper, goto close_fds; } - if (ioctl(ptmx, TIOCSWINSZ, + if (ioctl(ptmx, (unsigned int)TIOCSWINSZ, &(struct winsize){.ws_row = 24, .ws_col = 80}) < 0) { LOG_ERRNO("failed to set initial TIOCSWINSZ"); From c512dc4490b552c535636563db28b74b258ec0fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 3 Nov 2020 19:44:51 +0100 Subject: [PATCH 09/12] =?UTF-8?q?input:=20don=E2=80=99t=20use=20seat->kbd?= =?UTF-8?q?=5Ffocus=20as=20terminal=20when=20processing=20a=20key=20press?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When converting mouse scroll events to keyboard input (in alternate scroll mode), we need to use seat->mouse_focus, not seat->kbd_focus. To enable this, break out key press/release handling code to a separate function that takes an explicit term argument. Call this function from keyboard_key(), input_repeat() and in alternate scroll mode. Closes #179 --- CHANGELOG.md | 2 ++ input.c | 40 +++++++++++++++++++++++++--------------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02cab39e..fc372e5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,8 @@ * Compilation error _"overflow in conversion from long 'unsigned int' to 'int' changes value... "_ seen on platforms where the `request` argument in `ioctl(3)` is an `int` (for example: linux/ppc64). +* Crash when using the mouse in alternate scroll mode in an unfocused + window (https://codeberg.org/dnkl/foot/issues/179). ## 1.5.2 diff --git a/input.c b/input.c index afd641ca..24ae5d87 100644 --- a/input.c +++ b/input.c @@ -748,12 +748,9 @@ keymap_lookup(struct terminal *term, xkb_keysym_t sym, enum modifier mods) } static void -keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, - uint32_t time, uint32_t key, uint32_t state) +key_press_release(struct seat *seat, struct terminal *term, uint32_t serial, + uint32_t key, uint32_t state) { - struct seat *seat = data; - struct terminal *term = seat->kbd_focus; - if (seat->kbd.xkb == NULL || seat->kbd.xkb_keymap == NULL || seat->kbd.xkb_state == NULL) @@ -761,8 +758,6 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, return; } - assert(term != NULL); - const xkb_mod_mask_t ctrl = 1 << seat->kbd.mod_ctrl; const xkb_mod_mask_t alt = 1 << seat->kbd.mod_alt; const xkb_mod_mask_t shift = 1 << seat->kbd.mod_shift; @@ -773,7 +768,6 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, return; } - key += 8; bool should_repeat = xkb_keymap_key_repeats(seat->kbd.xkb_keymap, key); xkb_keysym_t sym = xkb_state_key_get_one_sym(seat->kbd.xkb_state, key); @@ -819,7 +813,7 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, if (term->is_searching) { if (should_repeat) - start_repeater(seat, key - 8); + start_repeater(seat, key); search_input(seat, term, key, sym, effective_mods, serial); return; } @@ -832,10 +826,10 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, } #endif - LOG_DBG("keyboard_key: keyboard=%p, serial=%u, " + LOG_DBG("seat: %s, term=%p, serial=%u, " "sym=%u, mod=0x%08x, consumed=0x%08x, significant=0x%08x, " "effective=0x%08x, repeats=%d", - (void *)wl_keyboard, serial, + seat->name, (void *)term, serial, sym, mods, consumed, significant, effective_mods, should_repeat); /* @@ -1001,7 +995,15 @@ maybe_repeat: term->wl->presentation_clock_id, &term->render.input_time); if (should_repeat) - start_repeater(seat, key - 8); + start_repeater(seat, key); +} + +static void +keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, + uint32_t time, uint32_t key, uint32_t state) +{ + struct seat *seat = data; + key_press_release(seat, seat->kbd_focus, serial, key + 8, state); } static void @@ -1055,7 +1057,11 @@ const struct wl_keyboard_listener keyboard_listener = { void input_repeat(struct seat *seat, uint32_t key) { - keyboard_key(seat, NULL, seat->kbd.serial, 0, key, XKB_KEY_DOWN); + /* Should be cleared as soon as we loose focus */ + assert(seat->kbd_focus != NULL); + struct terminal *term = seat->kbd_focus; + + key_press_release(seat, term, seat->kbd.serial, key, XKB_KEY_DOWN); } static bool @@ -1667,12 +1673,16 @@ alternate_scroll(struct seat *seat, int amount, int button) if (seat->wl_keyboard == NULL) return; + /* Should be cleared in leave event */ + assert(seat->mouse_focus != NULL); + struct terminal *term = seat->mouse_focus; + xkb_keycode_t key = button == BTN_BACK ? seat->kbd.key_arrow_up : seat->kbd.key_arrow_down; for (int i = 0; i < amount; i++) - keyboard_key(seat, NULL, seat->kbd.serial, 0, key - 8, XKB_KEY_DOWN); - keyboard_key(seat, NULL, seat->kbd.serial, 0, key - 8, XKB_KEY_UP); + key_press_release(seat, term, seat->kbd.serial, key, XKB_KEY_DOWN); + key_press_release(seat, term, seat->kbd.serial, key, XKB_KEY_UP); } static void From 66f846d72324ecb030236e3dd0b7001c0840a7a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 4 Nov 2020 19:01:59 +0100 Subject: [PATCH 10/12] selection: explicitly set direction when right-click extending Fixes an issue where right-click-and-dragging to extend a selection caused one cell being removed from the selection. Closes #180 --- CHANGELOG.md | 2 ++ selection.c | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc372e5e..d1e6c992 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,8 @@ argument in `ioctl(3)` is an `int` (for example: linux/ppc64). * Crash when using the mouse in alternate scroll mode in an unfocused window (https://codeberg.org/dnkl/foot/issues/179). +* Character dropped from selection when "right-click-hold"-extending a + selection (https://codeberg.org/dnkl/foot/issues/180). ## 1.5.2 diff --git a/selection.c b/selection.c index 7c814467..17d47cfe 100644 --- a/selection.c +++ b/selection.c @@ -475,17 +475,20 @@ selection_extend_normal(struct terminal *term, int col, int row, uint32_t serial assert(start->row < end->row || start->col < end->col); struct coord new_start, new_end; + enum selection_scroll_direction direction; if (row < start->row || (row == start->row && col < start->col)) { /* Extend selection to start *before* current start */ new_start = *end; new_end = (struct coord){col, row}; + direction = SELECTION_LEFT; } else if (row > end->row || (row == end->row && col > end->col)) { /* Extend selection to end *after* current end */ new_start = *start; new_end = (struct coord){col, row}; + direction = SELECTION_RIGHT; } else { @@ -499,15 +502,18 @@ selection_extend_normal(struct terminal *term, int col, int row, uint32_t serial /* Move start point */ new_start = *end; new_end = (struct coord){col, row}; + direction = SELECTION_LEFT; } else { /* Move end point */ new_start = *start; new_end = (struct coord){col, row}; + direction = SELECTION_RIGHT; } } + term->selection.direction = direction; selection_modify(term, new_start, new_end); } From 442e10dd2801b05ba90bccbe21162af048329a1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 6 Nov 2020 20:12:15 +0100 Subject: [PATCH 11/12] selection: fix enum type enum selection_scroll_direction is used when extending a selection by auto-scrolling the terminal content while the mouse is outside the grid. What we want is enum selection_direction. --- selection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selection.c b/selection.c index 17d47cfe..6ac9042e 100644 --- a/selection.c +++ b/selection.c @@ -475,7 +475,7 @@ selection_extend_normal(struct terminal *term, int col, int row, uint32_t serial assert(start->row < end->row || start->col < end->col); struct coord new_start, new_end; - enum selection_scroll_direction direction; + enum selection_direction direction; if (row < start->row || (row == start->row && col < start->col)) { /* Extend selection to start *before* current start */ From 90abdab345d0aad0d28345557061bc07af15c268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 6 Nov 2020 20:16:27 +0100 Subject: [PATCH 12/12] meson/pkgbuild: bump version to 1.5.3 --- PKGBUILD | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PKGBUILD b/PKGBUILD index bc9d6465..976e4620 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,5 +1,5 @@ pkgname=('foot-git' 'foot-terminfo-git') -pkgver=1.5.2 +pkgver=1.5.3 pkgrel=1 arch=('x86_64' 'aarch64') url=https://codeberg.org/dnkl/foot diff --git a/meson.build b/meson.build index 16a42150..d5e219e8 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('foot', 'c', - version: '1.5.2', + version: '1.5.3', license: 'MIT', meson_version: '>=0.53.0', default_options: [