mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
render: don’t let URL jump label sub-surfaces extend outside window geometry
We have no guarantee that sub-surfaces extending outside the window geometry are rendered correctly (if at all). For example, both Sway and River will render the window border on top of the sub-surface. Future versions of Sway may clip the sub-surface. Since jump-labels are positioned slightly above, and to the left of the URLs first character, having a label on either the top row, or on the first column, will likely position it outside the window. This is handled by simply setting x/y to 0 (or, to -margin, since the label coordinate is later offsetted with the window margins). Second, if the label is very long, it may extend outside the window. This is very unusual for labels only showing the key, and not the URL itself, but could happen in this case too, if e.g. the user has configured double-width key characters. This is handled by calculating its maximum width, and then truncating the label. Although very unlikely, it is possible for a label to also extend outside the window’s vertical size. This could happen for very small font sizes, where the label’s own margins are large, relative to the font size. This case is currently not handled. Closes #443
This commit is contained in:
parent
610b96b39d
commit
c6848678ad
2 changed files with 60 additions and 27 deletions
|
|
@ -40,6 +40,8 @@
|
|||
|
||||
* Underline cursor is now rendered below text underline
|
||||
(https://codeberg.org/dnkl/foot/issues/415).
|
||||
* Foot now tries much harder to keep URL jump labels inside the window
|
||||
geometry (https://codeberg.org/dnkl/foot/issues/443).
|
||||
|
||||
|
||||
### Deprecated
|
||||
|
|
|
|||
85
render.c
85
render.c
|
|
@ -2632,6 +2632,26 @@ render_urls(struct terminal *term)
|
|||
continue;
|
||||
}
|
||||
|
||||
int col = pos->col;
|
||||
int row = pos->row - term->grid->view;
|
||||
while (row < 0)
|
||||
row += term->grid->num_rows;
|
||||
row &= (term->grid->num_rows - 1);
|
||||
|
||||
/* Position label slightly above and to the left */
|
||||
int x = col * term->cell_width - 15 * term->cell_width / 10;
|
||||
int y = row * term->cell_height - 5 * term->cell_height / 10;
|
||||
|
||||
/* Don’t position it outside our window */
|
||||
if (x < -term->margins.left)
|
||||
x = -term->margins.left;
|
||||
if (y < -term->margins.top)
|
||||
y = -term->margins.top;
|
||||
|
||||
/* Maximum width of label, in pixels */
|
||||
const int max_width =
|
||||
term->width - term->margins.left - term->margins.right - x;
|
||||
|
||||
const size_t key_len = wcslen(key);
|
||||
|
||||
size_t url_len = mbstowcs(NULL, url->url, 0);
|
||||
|
|
@ -2641,32 +2661,59 @@ render_urls(struct terminal *term)
|
|||
wchar_t url_wchars[url_len + 1];
|
||||
mbstowcs(url_wchars, url->url, url_len + 1);
|
||||
|
||||
/* Format label, not yet subject to any size limitations */
|
||||
size_t chars = key_len + (show_url ? (2 + url_len) : 0);
|
||||
|
||||
const size_t max_chars = 50;
|
||||
chars = min(chars, max_chars);
|
||||
|
||||
wchar_t label[chars + 2];
|
||||
label[chars] = L'…';
|
||||
label[chars + 1] = L'\0';
|
||||
wchar_t label[chars + 1];
|
||||
label[chars] = L'\0';
|
||||
|
||||
if (show_url)
|
||||
swprintf(label, chars + 1, L"%ls: %ls", key, url_wchars);
|
||||
else
|
||||
wcsncpy(label, key, chars + 1);
|
||||
wcsncpy(label, key, chars);
|
||||
|
||||
/* Upper case the key characters */
|
||||
for (size_t i = 0; i < wcslen(key); i++)
|
||||
label[i] = towupper(label[i]);
|
||||
|
||||
/* Blank already entered key characters */
|
||||
for (size_t i = 0; i < entered_key_len; i++)
|
||||
label[i] = L' ';
|
||||
|
||||
size_t len = wcslen(label);
|
||||
int cols = wcswidth(label, len);
|
||||
|
||||
/*
|
||||
* Don’t extend outside our window
|
||||
*
|
||||
* Truncate label so that it doesn’t extend outside our
|
||||
* window.
|
||||
*
|
||||
* Do it in a way such that we don’t cut the label in the
|
||||
* middle of a double-width character.
|
||||
*/
|
||||
const int scale = term->scale;
|
||||
const int x_margin = 2 * scale;
|
||||
const int y_margin = 1 * scale;
|
||||
const int max_cols = max_width / term->cell_width;
|
||||
|
||||
int cols = 0;
|
||||
|
||||
for (size_t i = 0; i <= wcslen(label); i++) {
|
||||
int _cols = wcswidth(label, i);
|
||||
|
||||
if (_cols == (size_t)-1)
|
||||
continue;
|
||||
|
||||
if (_cols >= max_cols) {
|
||||
if (i > 0)
|
||||
label[i - 1] = L'…';
|
||||
label[i] = L'\0';
|
||||
cols = max_cols;
|
||||
break;
|
||||
}
|
||||
cols = _cols;
|
||||
}
|
||||
|
||||
if (cols == 0)
|
||||
continue;
|
||||
|
||||
const int width =
|
||||
(2 * x_margin + cols * term->cell_width + scale - 1) / scale * scale;
|
||||
const int height =
|
||||
|
|
@ -2675,22 +2722,6 @@ render_urls(struct terminal *term)
|
|||
struct buffer *buf = shm_get_buffer(
|
||||
term->wl->shm, width, height, shm_cookie_url(url), false, 1);
|
||||
|
||||
int col = pos->col;
|
||||
int row = pos->row - term->grid->view;
|
||||
while (row < 0)
|
||||
row += term->grid->num_rows;
|
||||
row &= (term->grid->num_rows - 1);
|
||||
|
||||
int x = col * term->cell_width - 15 * term->cell_width / 10;
|
||||
int y = row * term->cell_height - 5 * term->cell_height / 10;
|
||||
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
#if 0
|
||||
if (y < 0)
|
||||
y += 15 * term->cell_height / 10;
|
||||
#endif
|
||||
|
||||
wl_subsurface_set_position(
|
||||
sub_surf,
|
||||
(term->margins.left + x) / term->scale,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue