From c742f640af4c636985b0a2cb09a4a5269ec374d7 Mon Sep 17 00:00:00 2001 From: Raimund Sacherer Date: Sun, 8 Oct 2023 21:20:48 +0200 Subject: [PATCH] Added crosshair implementation. --- config.c | 25 ++++++++++++- config.h | 4 ++- doc/foot.ini.5.scd | 42 ++++++++++++++++++++++ foot.ini | 6 ++++ input.c | 18 +++++++++- key-binding.h | 4 +++ render.c | 90 +++++++++++++++++++++++++++++++++++++++++++--- terminal.c | 14 +++++--- terminal.h | 17 +++++++-- 9 files changed, 206 insertions(+), 14 deletions(-) diff --git a/config.c b/config.c index e5cd6723..36f58662 100644 --- a/config.c +++ b/config.c @@ -101,6 +101,10 @@ static const char *const binding_action_map[] = { [BIND_ACTION_CLIPBOARD_PASTE] = "clipboard-paste", [BIND_ACTION_PRIMARY_PASTE] = "primary-paste", [BIND_ACTION_SEARCH_START] = "search-start", + [BIND_ACTION_CROSSHAIR] = "crosshair", + [BIND_ACTION_CROSSHAIR_FIX_POSITION] = "crosshair-fix-position", + [BIND_ACTION_CROSSHAIR_PIXEL_POSITION] = "crosshair-use-pixel-position", + [BIND_ACTION_CROSSHAIR_MOUSE_POSITION] = "crosshair-use-mouse-position", [BIND_ACTION_FONT_SIZE_UP] = "font-increase", [BIND_ACTION_FONT_SIZE_DOWN] = "font-decrease", [BIND_ACTION_FONT_SIZE_RESET] = "font-reset", @@ -1252,6 +1256,7 @@ parse_section_colors(struct context *ctx) } else if (strcmp(key, "flash") == 0) color = &conf->colors.flash; + else if (strcmp(key, "crosshair") == 0) color = &conf->colors.crosshair; else if (strcmp(key, "foreground") == 0) color = &conf->colors.fg; else if (strcmp(key, "background") == 0) color = &conf->colors.bg; else if (strcmp(key, "selection-foreground") == 0) color = &conf->colors.selection_fg; @@ -1349,6 +1354,19 @@ parse_section_colors(struct context *ctx) return true; } + else if (strcmp(key, "crosshair-alpha") == 0) { + float alpha; + if (!value_to_float(ctx, &alpha)) + return false; + + if (alpha < 0. || alpha > 1.) { + LOG_CONTEXTUAL_ERR("not in range 0.0-1.0"); + return false; + } + + conf->colors.crosshair_alpha = alpha * 65535.; + return true; + } else { LOG_CONTEXTUAL_ERR("not valid option"); @@ -2846,6 +2864,10 @@ add_default_key_bindings(struct config *conf) {BIND_ACTION_CLIPBOARD_PASTE, m_none, {{XKB_KEY_XF86Paste}}}, {BIND_ACTION_PRIMARY_PASTE, m_shift, {{XKB_KEY_Insert}}}, {BIND_ACTION_SEARCH_START, m_ctrl_shift, {{XKB_KEY_r}}}, + {BIND_ACTION_CROSSHAIR, m_ctrl_shift, {{XKB_KEY_i}}}, + {BIND_ACTION_CROSSHAIR_FIX_POSITION, m_ctrl_shift, {{XKB_KEY_f}}}, + {BIND_ACTION_CROSSHAIR_MOUSE_POSITION, m_ctrl_shift, {{XKB_KEY_m}}}, + {BIND_ACTION_CROSSHAIR_PIXEL_POSITION, m_ctrl_shift, {{XKB_KEY_p}}}, {BIND_ACTION_FONT_SIZE_UP, m_ctrl, {{XKB_KEY_plus}}}, {BIND_ACTION_FONT_SIZE_UP, m_ctrl, {{XKB_KEY_equal}}}, {BIND_ACTION_FONT_SIZE_UP, m_ctrl, {{XKB_KEY_KP_Add}}}, @@ -3036,6 +3058,8 @@ config_load(struct config *conf, const char *conf_path, .bg = default_background, .flash = 0x7f7f00, .flash_alpha = 0x7fff, + .crosshair = default_foreground, + .crosshair_alpha = 0xffff, .alpha = 0xffff, .selection_fg = 0x80000000, /* Use default bg */ .selection_bg = 0x80000000, /* Use default fg */ @@ -3077,7 +3101,6 @@ config_load(struct config *conf, const char *conf_path, .border_width_visible = 0, .button_width = 26, }, - .render_worker_count = sysconf(_SC_NPROCESSORS_ONLN), .server_socket_path = get_server_socket_path(), .presentation_timings = false, diff --git a/config.h b/config.h index 3c5b3df7..04b57667 100644 --- a/config.h +++ b/config.h @@ -204,7 +204,9 @@ struct config { uint32_t fg; uint32_t bg; uint32_t flash; - uint32_t flash_alpha; + uint16_t flash_alpha; + uint32_t crosshair; + uint16_t crosshair_alpha; uint32_t table[256]; uint16_t alpha; uint32_t selection_fg; diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index 3c151732..6ea7b9a4 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -625,6 +625,13 @@ can configure the background transparency with the _alpha_ option. Default: _0.5_. +*crosshair* + Color to use for the crosshair cursor. + +*crosshair-alpha* + Crosshair translucency. A value in the range 0.0-1.0, where 0.0 + means completely transparent, and 1.0 is opaque. + *alpha* Background translucency. A value in the range 0.0-1.0, where 0.0 means completely transparent, and 1.0 is opaque. Default: _1.0_. @@ -906,6 +913,41 @@ e.g. *search-start=none*. Default: _Control+Shift+u_. +*crosshair* + Activates a crosshair on the current cursor position. Helps to + line up horizontal and vertical lines. + + Default: _Control+Shift+i_. + +*crosshair-fix-position* + A toggle switch to freeze the crosshair to the current cursor + location. The location is remembered even if the crosshair is + deactivated. Press the keyboard combination again to unfreeze + the crosshair. + + Default: _Control+Shift+f_. + +*crosshair-use-mouse-position* + By default the crosshair uses the current text cursor position. + This keybinding activates the mouse cursor position instead. If + the mouse option *hide-when-typing* is active, once the mouse + cursor is hidden by starting to type, the crosshair falls back to + the text cursor. This can be used for example to quickly check an + alignment on another part of the screen. To have the crosshair + remain on the new position use the *crosshair-fix-position* + keybinding. + + The crosshair will be drawn at the cursor row and column the mouse + cursor points to. + + Default: _Control+Shift+m_. + +*crosshair-use-pixel-position* + Activates pixel precision for the crosshair when + *crosshair-use-mouse-position* is used. + + Default: _Control+Shift+p_. + # SECTION: search-bindings This section lets you override the default key bindings used in diff --git a/foot.ini b/foot.ini index 55eb42de..c9e8bd72 100644 --- a/foot.ini +++ b/foot.ini @@ -80,6 +80,8 @@ # foreground=ffffff # flash=7f7f00 # flash-alpha=0.5 +# crosshair=ffffff +# crosshair_alpha=1.0 ## Normal/regular colors (color palette 0-7) # regular0=242424 # black @@ -164,6 +166,10 @@ # prompt-prev=Control+Shift+z # prompt-next=Control+Shift+x # unicode-input=Control+Shift+u +# crosshair=Control+Shift+i +# crosshair-fix-position=Control+Shift+f +# crosshair-use-pixel-position=Control+Shift+p +# crosshair-use-mouse-position=Control+Shift+m # noop=none [search-bindings] diff --git a/input.c b/input.c index e3613a90..188e96c7 100644 --- a/input.c +++ b/input.c @@ -186,6 +186,22 @@ execute_binding(struct seat *seat, struct terminal *term, search_begin(term); return true; + case BIND_ACTION_CROSSHAIR: + term->crosshair.active = !term->crosshair.active; + return true; + + case BIND_ACTION_CROSSHAIR_FIX_POSITION: + term->crosshair.position_fixed = !term->crosshair.position_fixed; + return true; + + case BIND_ACTION_CROSSHAIR_MOUSE_POSITION: + term->crosshair.use_mouse_position = !term->crosshair.use_mouse_position; + return true; + + case BIND_ACTION_CROSSHAIR_PIXEL_POSITION: + term->crosshair.use_mouse_pixel_coordinates = !term->crosshair.use_mouse_pixel_coordinates; + return true; + case BIND_ACTION_FONT_SIZE_UP: term_font_size_increase(term); return true; @@ -429,7 +445,7 @@ execute_binding(struct seat *seat, struct terminal *term, term_damage_view(term); render_refresh(term); - break; + break; } return true; diff --git a/key-binding.h b/key-binding.h index 050c80a6..5cb6f68b 100644 --- a/key-binding.h +++ b/key-binding.h @@ -22,6 +22,10 @@ enum bind_action_normal { BIND_ACTION_CLIPBOARD_PASTE, BIND_ACTION_PRIMARY_PASTE, BIND_ACTION_SEARCH_START, + BIND_ACTION_CROSSHAIR, + BIND_ACTION_CROSSHAIR_MOUSE_POSITION, + BIND_ACTION_CROSSHAIR_FIX_POSITION, + BIND_ACTION_CROSSHAIR_PIXEL_POSITION, BIND_ACTION_FONT_SIZE_UP, BIND_ACTION_FONT_SIZE_DOWN, BIND_ACTION_FONT_SIZE_RESET, diff --git a/render.c b/render.c index d679b5e8..19cbae63 100644 --- a/render.c +++ b/render.c @@ -362,6 +362,7 @@ draw_underline_cursor(const struct terminal *term, pixman_image_t *pix, PIXMAN_OP_SRC, pix, color, 1, &(pixman_rectangle16_t){ x, y + y_ofs, cols * term->cell_width, thickness}); + } static void @@ -1565,6 +1566,7 @@ render_overlay(struct terminal *term) term->is_searching ? OVERLAY_SEARCH : term->flash.active ? OVERLAY_FLASH : unicode_mode_active ? OVERLAY_UNICODE_MODE : + term->crosshair.active ? OVERLAY_CROSSHAIR : OVERLAY_NONE; if (likely(style == OVERLAY_NONE)) { @@ -1582,6 +1584,7 @@ render_overlay(struct terminal *term) return; } + struct buffer *buf = shm_get_buffer( term->render.chains.overlay, term->width, term->height); @@ -1603,6 +1606,13 @@ render_overlay(struct terminal *term) term->conf->colors.flash, term->conf->colors.flash_alpha); break; + + case OVERLAY_CROSSHAIR: + color = color_hex_to_pixman_with_alpha( + term->conf->colors.crosshair, + term->conf->colors.crosshair_alpha); + break; + } /* Bounding rectangle of damaged areas - for wl_surface_damage_buffer() */ @@ -1725,7 +1735,8 @@ render_overlay(struct terminal *term) } else if (buf == term->render.last_overlay_buf && - style == term->render.last_overlay_style) + style == term->render.last_overlay_style && + style != OVERLAY_CROSSHAIR) { xassert(style == OVERLAY_FLASH || style == OVERLAY_UNICODE_MODE); shm_did_not_use_buf(buf); @@ -1735,9 +1746,78 @@ render_overlay(struct terminal *term) damage_bounds = (pixman_box32_t){0, 0, buf->width, buf->height}; } - pixman_image_fill_rectangles( - PIXMAN_OP_SRC, buf->pix[0], &color, 1, - &(pixman_rectangle16_t){0, 0, term->width, term->height}); + + if (style == OVERLAY_CROSSHAIR) { + int cursor_row = term->grid->cursor.point.row; + int cursor_col = term->grid->cursor.point.col; + int mouse_x = 0; + int mouse_y = 0; + + tll_foreach(term->wl->seats, it) { + if (it->item.kbd_focus == term) { + if (it->item.pointer.hidden == 0 && + term->crosshair.use_mouse_position == true) { + + cursor_row = it->item.mouse.row > 0 ? it->item.mouse.row : 0; + cursor_col = it->item.mouse.col > 0 ? it->item.mouse.col : 0; + mouse_x = it->item.mouse.x; + mouse_y = it->item.mouse.y; + break; + } + } + } + + if (term->crosshair.position_fixed == true) { + cursor_row = term->render.last_crosshair.row; + cursor_col = term->render.last_crosshair.col; + mouse_x = term->render.last_crosshair.mouse_x; + mouse_y = term->render.last_crosshair.mouse_y; + } + + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, buf->pix[0], &(pixman_color_t){0}, 1, + &(pixman_rectangle16_t){0, 0, term->width, term->height}); + + if (term->crosshair.use_mouse_pixel_coordinates == false) { + int y = term->margins.top + (cursor_row * term->cell_height) + term->cell_height; + int y2 = 1; // --FIXME-- maybe define crosshair thickness? + + if (y + y2 > term->height) + y = term->height - 1; + + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, buf->pix[0], &color, 1, + &(pixman_rectangle16_t){term->margins.left, y, term->width, y2} ); + + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, buf->pix[0], &color, 1, + &(pixman_rectangle16_t){term->margins.left + (cursor_col * term->cell_width), + term->margins.top, 1, term->height} ); + + } else { + if (mouse_x > 0 || mouse_y > 0) { + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, buf->pix[0], &color, 1, + &(pixman_rectangle16_t){term->margins.left, mouse_y, term->width, 1} ); + + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, buf->pix[0], &color, 1, + &(pixman_rectangle16_t){mouse_x, term->margins.top, 1, term->height} ); + } + } + + if (term->crosshair.position_fixed == false) { + term->render.last_crosshair.row = cursor_row; + term->render.last_crosshair.col = cursor_col; + term->render.last_crosshair.mouse_x = mouse_x; + term->render.last_crosshair.mouse_y = mouse_y; + } + + } else { + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, buf->pix[0], &color, 1, + &(pixman_rectangle16_t){0, 0, term->width, term->height}); + } quirk_weston_subsurface_desync_on(overlay->sub); wayl_surface_scale( @@ -2234,7 +2314,7 @@ render_csd_button_maximize_window( pixman_image_fill_rectangles( PIXMAN_OP_SRC, buf->pix[0], &color, 4, (pixman_rectangle16_t[]) { - {x_margin, y_margin, width, thick}, + { x_margin, y_margin, width, thick }, { x_margin, y_margin + thick, thick, width - 2 * thick }, { x_margin + width - thick, y_margin + thick, thick, width - 2 * thick }, { x_margin, y_margin + width - thick, width, thick } diff --git a/terminal.c b/terminal.c index c7836d91..4d7b7579 100644 --- a/terminal.c +++ b/terminal.c @@ -1172,8 +1172,6 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper, .colors = { .fg = conf->colors.fg, .bg = conf->colors.bg, - .flash = conf->colors.flash, - .flash_alpha = conf->colors.flash_alpha, .alpha = conf->colors.alpha, .selection_fg = conf->colors.selection_fg, .selection_bg = conf->colors.selection_bg, @@ -1215,6 +1213,10 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper, }, .num_lock_modifier = true, .bell_action_enabled = true, + .crosshair.active = false, + .crosshair.position_fixed = false, + .crosshair.use_mouse_position = false, + .crosshair.use_mouse_pixel_coordinates = false, .tab_stops = tll_init(), .wl = wayl, .render = { @@ -1926,9 +1928,7 @@ term_reset(struct terminal *term, bool hard) fdm_del(term->fdm, term->blink.fd); term->blink.fd = -1; term->colors.fg = term->conf->colors.fg; term->colors.bg = term->conf->colors.bg; - term->colors.flash = term->conf->colors.flash; term->colors.alpha = term->conf->colors.alpha; - term->colors.flash_alpha = term->conf->colors.flash_alpha; term->colors.selection_fg = term->conf->colors.selection_fg; term->colors.selection_bg = term->conf->colors.selection_bg; term->colors.use_custom_selection = term->conf->colors.use_custom.selection; @@ -1968,6 +1968,12 @@ term_reset(struct terminal *term, bool hard) } term->normal.cur_row = term->normal.rows[0]; term->alt.cur_row = term->alt.rows[0]; + + term->crosshair.active = false; + term->crosshair.position_fixed = false; + term->crosshair.use_mouse_position = false; + term->crosshair.use_mouse_pixel_coordinates = false; + tll_free(term->normal.scroll_damage); tll_free(term->alt.scroll_damage); term->render.last_cursor.row = NULL; diff --git a/terminal.h b/terminal.h index 97f2c475..064ef3fb 100644 --- a/terminal.h +++ b/terminal.h @@ -332,6 +332,7 @@ enum overlay_style { OVERLAY_SEARCH, OVERLAY_FLASH, OVERLAY_UNICODE_MODE, + OVERLAY_CROSSHAIR, }; typedef tll(struct ptmx_buffer) ptmx_buffer_list_t; @@ -509,8 +510,6 @@ struct terminal { struct { uint32_t fg; uint32_t bg; - uint32_t flash; - uint32_t flash_alpha; uint32_t table[256]; uint16_t alpha; uint32_t selection_fg; @@ -564,6 +563,13 @@ struct terminal { } last; } search; + struct { + bool active; + bool position_fixed; + bool use_mouse_position; + bool use_mouse_pixel_coordinates; + } crosshair; + struct wayland *wl; struct wl_window *window; bool visual_focus; @@ -637,6 +643,13 @@ struct terminal { struct buffer *last_overlay_buf; pixman_region32_t last_overlay_clip; + struct { + int row; + int col; + int mouse_x; + int mouse_y; + } last_crosshair; + size_t search_glyph_offset; struct timespec input_time;