2021-01-31 11:12:07 +01:00
|
|
|
|
#include "url-mode.h"
|
|
|
|
|
|
|
2021-02-13 13:45:59 +01:00
|
|
|
|
#include <stdlib.h>
|
2021-01-31 11:12:07 +01:00
|
|
|
|
#include <string.h>
|
|
|
|
|
|
#include <wctype.h>
|
2021-02-24 21:30:58 +01:00
|
|
|
|
#include <unistd.h>
|
2025-01-30 09:06:47 +01:00
|
|
|
|
#include <regex.h>
|
2021-02-24 21:30:58 +01:00
|
|
|
|
|
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
#include <fcntl.h>
|
2021-01-31 11:12:07 +01:00
|
|
|
|
|
|
|
|
|
|
#define LOG_MODULE "url-mode"
|
2021-02-23 14:59:54 +01:00
|
|
|
|
#define LOG_ENABLE_DBG 0
|
2021-01-31 11:12:07 +01:00
|
|
|
|
#include "log.h"
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
#include "char32.h"
|
2021-01-31 11:12:07 +01:00
|
|
|
|
#include "grid.h"
|
key-binding: new API, for handling sets of key bindings
Up until now, our Wayland seats have been tracking key bindings. This
makes sense, since the seat’s keymap determines how the key bindings
are resolved.
However, tying bindings to the seat/keymap alone isn’t enough, since
we also depend on the current configuration (i.e. user settings) when
resolving a key binding.
This means configurations that doesn’t match the wayland object’s
configuration, currently don’t resolve key bindings correctly. This
applies to footclients where the user has overridden key bindings on
the command line (e.g. --override key-bindings.foo=bar).
Thus, to correctly resolve key bindings, each set of key bindings must
be tied *both* to a seat/keymap, *and* a configuration.
This patch introduces a key-binding manager, with an API to
add/remove/lookup, and load/unload keymaps from sets of key bindings.
In the API, sets are tied to a seat and terminal instance, since this
makes the most sense (we need to instantiate, or incref a set whenever
a new terminal instance is created). Internally, the set is tied to a
seat and the terminal’s configuration.
Sets are *added* when a new seat is added, and when a new terminal
instance is created. Since there can only be one instance of each
seat, sets are always removed when a seat is removed.
Terminals on the other hand can re-use the same configuration (and
typically do). Thus, sets ref-count the configuration. In other words,
when instantiating a new terminal, we may not have to instantiate a
new set of key bindings, but can often be incref:ed instead.
Whenever the keymap changes on a seat, all key bindings sets
associated with that seat reloads (re-resolves) their key bindings.
Closes #931
2022-04-17 15:39:51 +02:00
|
|
|
|
#include "key-binding.h"
|
2023-04-25 21:33:45 +02:00
|
|
|
|
#include "quirks.h"
|
2021-02-06 11:51:58 +01:00
|
|
|
|
#include "render.h"
|
2021-02-04 20:55:08 +01:00
|
|
|
|
#include "selection.h"
|
2021-01-31 11:12:07 +01:00
|
|
|
|
#include "spawn.h"
|
|
|
|
|
|
#include "terminal.h"
|
2021-02-13 12:28:53 +01:00
|
|
|
|
#include "uri.h"
|
2021-01-31 11:12:07 +01:00
|
|
|
|
#include "util.h"
|
|
|
|
|
|
#include "xmalloc.h"
|
|
|
|
|
|
|
2021-02-14 13:42:37 +01:00
|
|
|
|
static void url_destroy(struct url *url);
|
|
|
|
|
|
|
2021-01-31 11:12:07 +01:00
|
|
|
|
static bool
|
|
|
|
|
|
execute_binding(struct seat *seat, struct terminal *term,
|
2022-02-08 19:43:00 +01:00
|
|
|
|
const struct key_binding *binding, uint32_t serial)
|
2021-01-31 11:12:07 +01:00
|
|
|
|
{
|
2022-02-08 19:43:00 +01:00
|
|
|
|
const enum bind_action_url action = binding->action;
|
|
|
|
|
|
|
2021-01-31 11:12:07 +01:00
|
|
|
|
switch (action) {
|
|
|
|
|
|
case BIND_ACTION_URL_NONE:
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
case BIND_ACTION_URL_CANCEL:
|
|
|
|
|
|
urls_reset(term);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
2021-02-14 14:18:11 +01:00
|
|
|
|
case BIND_ACTION_URL_TOGGLE_URL_ON_JUMP_LABEL:
|
|
|
|
|
|
term->urls_show_uri_on_jump_label = !term->urls_show_uri_on_jump_label;
|
|
|
|
|
|
render_refresh_urls(term);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
2021-01-31 11:12:07 +01:00
|
|
|
|
case BIND_ACTION_URL_COUNT:
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
url-mode: add support for XDG activation when opening URLs
First, add a ‘token’ argument to spawn(). When non-NULL, spawn() will
set the ‘XDG_ACTIVATION_TOKEN’ environment variable in the forked
process. If DISPLAY is non-NULL, we also set DESKTOP_STARTUP_ID, for
compatibility with X11 applications. Note that failing to set either
of these environment variables are considered non-fatal - i.e. we
ignore failures.
Next, add a helper function, wayl_get_activation_token(), to generate
an XDG activation token, and call a user-provided callback when it’s
‘done (since token generation is asynchronous). This function takes an
optional ‘seat’ and ‘serial’ arguments - when both are non-NULL/zero,
we set the serial on the token. ‘win’ is a required argument, used to
set the surface on the token.
Re-write wayl_win_set_urgent() to use the new helper function.
Finally, rewrite activate_url() to first try to get an activation
token (and spawn the URL launcher in the token callback). If that
fails, or if we don’t have XDG activation support, spawn the URL
launcher immediately (like before this patch).
Closes #1058
2022-05-03 19:37:04 +02:00
|
|
|
|
static bool
|
|
|
|
|
|
spawn_url_launcher_with_token(struct terminal *term,
|
|
|
|
|
|
const char *url,
|
|
|
|
|
|
const char *xdg_activation_token)
|
|
|
|
|
|
{
|
|
|
|
|
|
size_t argc;
|
|
|
|
|
|
char **argv;
|
|
|
|
|
|
|
|
|
|
|
|
int dev_null = open("/dev/null", O_RDWR);
|
|
|
|
|
|
|
|
|
|
|
|
if (dev_null < 0) {
|
|
|
|
|
|
LOG_ERRNO("failed to open /dev/null");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
|
|
|
|
if (spawn_expand_template(
|
|
|
|
|
|
&term->conf->url.launch, 1,
|
|
|
|
|
|
(const char *[]){"url"},
|
|
|
|
|
|
(const char *[]){url},
|
|
|
|
|
|
&argc, &argv))
|
|
|
|
|
|
{
|
2024-07-23 06:57:30 +02:00
|
|
|
|
ret = spawn(
|
|
|
|
|
|
term->reaper, term->cwd, argv,
|
|
|
|
|
|
dev_null, dev_null, dev_null, NULL, NULL, xdg_activation_token) >= 0;
|
url-mode: add support for XDG activation when opening URLs
First, add a ‘token’ argument to spawn(). When non-NULL, spawn() will
set the ‘XDG_ACTIVATION_TOKEN’ environment variable in the forked
process. If DISPLAY is non-NULL, we also set DESKTOP_STARTUP_ID, for
compatibility with X11 applications. Note that failing to set either
of these environment variables are considered non-fatal - i.e. we
ignore failures.
Next, add a helper function, wayl_get_activation_token(), to generate
an XDG activation token, and call a user-provided callback when it’s
‘done (since token generation is asynchronous). This function takes an
optional ‘seat’ and ‘serial’ arguments - when both are non-NULL/zero,
we set the serial on the token. ‘win’ is a required argument, used to
set the surface on the token.
Re-write wayl_win_set_urgent() to use the new helper function.
Finally, rewrite activate_url() to first try to get an activation
token (and spawn the URL launcher in the token callback). If that
fails, or if we don’t have XDG activation support, spawn the URL
launcher immediately (like before this patch).
Closes #1058
2022-05-03 19:37:04 +02:00
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < argc; i++)
|
|
|
|
|
|
free(argv[i]);
|
|
|
|
|
|
free(argv);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
close(dev_null);
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct spawn_activation_context {
|
|
|
|
|
|
struct terminal *term;
|
|
|
|
|
|
char *url;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
activation_token_done(const char *token, void *data)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct spawn_activation_context *ctx = data;
|
|
|
|
|
|
|
|
|
|
|
|
spawn_url_launcher_with_token(ctx->term, ctx->url, token);
|
|
|
|
|
|
free(ctx->url);
|
|
|
|
|
|
free(ctx);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
|
spawn_url_launcher(struct seat *seat, struct terminal *term, const char *url,
|
|
|
|
|
|
uint32_t serial)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct spawn_activation_context *ctx = xmalloc(sizeof(*ctx));
|
|
|
|
|
|
*ctx = (struct spawn_activation_context){
|
|
|
|
|
|
.term = term,
|
|
|
|
|
|
.url = xstrdup(url),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if (wayl_get_activation_token(
|
|
|
|
|
|
seat->wayl, seat, serial, term->window, &activation_token_done, ctx))
|
|
|
|
|
|
{
|
|
|
|
|
|
/* Context free:d by callback */
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
free(ctx->url);
|
|
|
|
|
|
free(ctx);
|
|
|
|
|
|
|
|
|
|
|
|
return spawn_url_launcher_with_token(term, url, NULL);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-02-04 21:19:30 +01:00
|
|
|
|
static void
|
url-mode: add support for XDG activation when opening URLs
First, add a ‘token’ argument to spawn(). When non-NULL, spawn() will
set the ‘XDG_ACTIVATION_TOKEN’ environment variable in the forked
process. If DISPLAY is non-NULL, we also set DESKTOP_STARTUP_ID, for
compatibility with X11 applications. Note that failing to set either
of these environment variables are considered non-fatal - i.e. we
ignore failures.
Next, add a helper function, wayl_get_activation_token(), to generate
an XDG activation token, and call a user-provided callback when it’s
‘done (since token generation is asynchronous). This function takes an
optional ‘seat’ and ‘serial’ arguments - when both are non-NULL/zero,
we set the serial on the token. ‘win’ is a required argument, used to
set the surface on the token.
Re-write wayl_win_set_urgent() to use the new helper function.
Finally, rewrite activate_url() to first try to get an activation
token (and spawn the URL launcher in the token callback). If that
fails, or if we don’t have XDG activation support, spawn the URL
launcher immediately (like before this patch).
Closes #1058
2022-05-03 19:37:04 +02:00
|
|
|
|
activate_url(struct seat *seat, struct terminal *term, const struct url *url,
|
|
|
|
|
|
uint32_t serial)
|
2021-02-04 21:19:30 +01:00
|
|
|
|
{
|
2024-10-23 08:46:30 +02:00
|
|
|
|
char *url_string = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
char *scheme, *host, *path;
|
|
|
|
|
|
if (uri_parse(url->url, strlen(url->url), &scheme, NULL, NULL,
|
|
|
|
|
|
&host, NULL, &path, NULL, NULL))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (strcmp(scheme, "file") == 0 && hostname_is_localhost(host)) {
|
|
|
|
|
|
/*
|
|
|
|
|
|
* This is a file in *this* computer. Pass only the
|
|
|
|
|
|
* filename to the URL-launcher.
|
|
|
|
|
|
*
|
|
|
|
|
|
* I.e. strip the ‘file://user@host/’ prefix.
|
|
|
|
|
|
*/
|
|
|
|
|
|
url_string = path;
|
|
|
|
|
|
} else
|
|
|
|
|
|
free(path);
|
|
|
|
|
|
|
|
|
|
|
|
free(scheme);
|
|
|
|
|
|
free(host);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (url_string == NULL)
|
|
|
|
|
|
url_string = xstrdup(url->url);
|
|
|
|
|
|
|
2021-02-13 12:28:53 +01:00
|
|
|
|
switch (url->action) {
|
|
|
|
|
|
case URL_ACTION_COPY:
|
2024-10-23 08:46:30 +02:00
|
|
|
|
if (text_to_clipboard(seat, term, url_string, seat->kbd.serial)) {
|
|
|
|
|
|
/* Now owned by our clipboard “manager” */
|
|
|
|
|
|
url_string = NULL;
|
|
|
|
|
|
}
|
2021-02-13 12:28:53 +01:00
|
|
|
|
break;
|
2021-02-04 21:19:30 +01:00
|
|
|
|
|
2022-03-22 19:07:06 +01:00
|
|
|
|
case URL_ACTION_LAUNCH:
|
|
|
|
|
|
case URL_ACTION_PERSISTENT: {
|
2024-10-23 08:46:30 +02:00
|
|
|
|
spawn_url_launcher(seat, term, url_string, serial);
|
2021-02-13 12:28:53 +01:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
2021-02-04 21:19:30 +01:00
|
|
|
|
}
|
2024-10-23 08:46:30 +02:00
|
|
|
|
|
|
|
|
|
|
free(url_string);
|
2021-02-04 21:19:30 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-01-31 11:12:07 +01:00
|
|
|
|
void
|
key-binding: new API, for handling sets of key bindings
Up until now, our Wayland seats have been tracking key bindings. This
makes sense, since the seat’s keymap determines how the key bindings
are resolved.
However, tying bindings to the seat/keymap alone isn’t enough, since
we also depend on the current configuration (i.e. user settings) when
resolving a key binding.
This means configurations that doesn’t match the wayland object’s
configuration, currently don’t resolve key bindings correctly. This
applies to footclients where the user has overridden key bindings on
the command line (e.g. --override key-bindings.foo=bar).
Thus, to correctly resolve key bindings, each set of key bindings must
be tied *both* to a seat/keymap, *and* a configuration.
This patch introduces a key-binding manager, with an API to
add/remove/lookup, and load/unload keymaps from sets of key bindings.
In the API, sets are tied to a seat and terminal instance, since this
makes the most sense (we need to instantiate, or incref a set whenever
a new terminal instance is created). Internally, the set is tied to a
seat and the terminal’s configuration.
Sets are *added* when a new seat is added, and when a new terminal
instance is created. Since there can only be one instance of each
seat, sets are always removed when a seat is removed.
Terminals on the other hand can re-use the same configuration (and
typically do). Thus, sets ref-count the configuration. In other words,
when instantiating a new terminal, we may not have to instantiate a
new set of key bindings, but can often be incref:ed instead.
Whenever the keymap changes on a seat, all key bindings sets
associated with that seat reloads (re-resolves) their key bindings.
Closes #931
2022-04-17 15:39:51 +02:00
|
|
|
|
urls_input(struct seat *seat, struct terminal *term,
|
|
|
|
|
|
const struct key_binding_set *bindings, uint32_t key,
|
input: rewrite of how we match foot’s own key bindings
Bindings are matched in one out of three ways:
* By translated (by XKB) symbols
* By untranslated symbols
* By raw key codes
A translated symbol is affected by pressed modifiers, some of which
can be “consumed”. Consumed modifiers to not partake in the comparison
with the binding’s modifiers. In this mode, ctrl+shift+2 maps to
ctrl+@ on a US layout.
Untranslated symbols, or un-shifted symbols refer to the “base” symbol
of the pressed key, i.e. it’s unaffected by modifiers. In this mode,
consumed modifiers *do* partake in the comparison with the binding’s
modifiers, and ctrl+shift+2 maps to ctrl+shift+2 on a US layout.
More examples: ctrl+shift+u maps to ctrl+U in the translated lookup,
while ctrl+shift+u maps to ctrl+shift+u in the untranslated lookup.
Finally, we also match raw key codes. This allows our bindings to work
using the same physical keys when the user switches between latin and
non-latin layouts.
This means key bindings in foot.ini *must* not include both +shift+
and a *shifted* key. I.e. ctrl+shift+U is not a valid combo as it
cannot be triggered. Unfortunately, this was how you were supposed to
write bindings up until now... so, we try to detect such bindings, log
a deprecation warning and then “fix” the binding for the user.
When specifying bindings in foot.ini, both ctrl+U and ctrl+shift+u are
valid, and will work. The latter is preferred though, since we cannot
detect the raw key code for the former variant. Personally, I also
prefer the latter one because it is more explicit; it’s more obvious
which keys are involved.
However, in some cases it makes more sense to use the other
variant. Typically for non-letter combos.
2021-02-27 20:42:31 +01:00
|
|
|
|
xkb_keysym_t sym, xkb_mod_mask_t mods, xkb_mod_mask_t consumed,
|
|
|
|
|
|
const xkb_keysym_t *raw_syms, size_t raw_count,
|
|
|
|
|
|
uint32_t serial)
|
2021-01-31 11:12:07 +01:00
|
|
|
|
{
|
2025-01-27 10:51:03 +01:00
|
|
|
|
/*
|
|
|
|
|
|
* Key bindings
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/* Match untranslated symbols */
|
|
|
|
|
|
tll_foreach(bindings->url, it) {
|
|
|
|
|
|
const struct key_binding *bind = &it->item;
|
2025-01-31 07:35:54 +01:00
|
|
|
|
if (bind->mods != mods || bind->mods == 0)
|
input: rewrite of how we match foot’s own key bindings
Bindings are matched in one out of three ways:
* By translated (by XKB) symbols
* By untranslated symbols
* By raw key codes
A translated symbol is affected by pressed modifiers, some of which
can be “consumed”. Consumed modifiers to not partake in the comparison
with the binding’s modifiers. In this mode, ctrl+shift+2 maps to
ctrl+@ on a US layout.
Untranslated symbols, or un-shifted symbols refer to the “base” symbol
of the pressed key, i.e. it’s unaffected by modifiers. In this mode,
consumed modifiers *do* partake in the comparison with the binding’s
modifiers, and ctrl+shift+2 maps to ctrl+shift+2 on a US layout.
More examples: ctrl+shift+u maps to ctrl+U in the translated lookup,
while ctrl+shift+u maps to ctrl+shift+u in the untranslated lookup.
Finally, we also match raw key codes. This allows our bindings to work
using the same physical keys when the user switches between latin and
non-latin layouts.
This means key bindings in foot.ini *must* not include both +shift+
and a *shifted* key. I.e. ctrl+shift+U is not a valid combo as it
cannot be triggered. Unfortunately, this was how you were supposed to
write bindings up until now... so, we try to detect such bindings, log
a deprecation warning and then “fix” the binding for the user.
When specifying bindings in foot.ini, both ctrl+U and ctrl+shift+u are
valid, and will work. The latter is preferred though, since we cannot
detect the raw key code for the former variant. Personally, I also
prefer the latter one because it is more explicit; it’s more obvious
which keys are involved.
However, in some cases it makes more sense to use the other
variant. Typically for non-letter combos.
2021-02-27 20:42:31 +01:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < raw_count; i++) {
|
2022-02-07 19:41:33 +01:00
|
|
|
|
if (bind->k.sym == raw_syms[i]) {
|
2022-02-08 19:43:00 +01:00
|
|
|
|
execute_binding(seat, term, bind, serial);
|
input: rewrite of how we match foot’s own key bindings
Bindings are matched in one out of three ways:
* By translated (by XKB) symbols
* By untranslated symbols
* By raw key codes
A translated symbol is affected by pressed modifiers, some of which
can be “consumed”. Consumed modifiers to not partake in the comparison
with the binding’s modifiers. In this mode, ctrl+shift+2 maps to
ctrl+@ on a US layout.
Untranslated symbols, or un-shifted symbols refer to the “base” symbol
of the pressed key, i.e. it’s unaffected by modifiers. In this mode,
consumed modifiers *do* partake in the comparison with the binding’s
modifiers, and ctrl+shift+2 maps to ctrl+shift+2 on a US layout.
More examples: ctrl+shift+u maps to ctrl+U in the translated lookup,
while ctrl+shift+u maps to ctrl+shift+u in the untranslated lookup.
Finally, we also match raw key codes. This allows our bindings to work
using the same physical keys when the user switches between latin and
non-latin layouts.
This means key bindings in foot.ini *must* not include both +shift+
and a *shifted* key. I.e. ctrl+shift+U is not a valid combo as it
cannot be triggered. Unfortunately, this was how you were supposed to
write bindings up until now... so, we try to detect such bindings, log
a deprecation warning and then “fix” the binding for the user.
When specifying bindings in foot.ini, both ctrl+U and ctrl+shift+u are
valid, and will work. The latter is preferred though, since we cannot
detect the raw key code for the former variant. Personally, I also
prefer the latter one because it is more explicit; it’s more obvious
which keys are involved.
However, in some cases it makes more sense to use the other
variant. Typically for non-letter combos.
2021-02-27 20:42:31 +01:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-01-27 10:51:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
input: match unshifted key-bindings before shifted
That is, try to match e.g. Control+shift+a, before trying to match
Control+A.
In most cases, order doesn't matter. There are however a couple of
symbols where the layout consumes the shift-modifier, and the
generated symbol is the same in both the shifted and unshifted
form. One such example is backspace.
Before this patch, key-bindings with shift-backspace would be ignored,
if there were another key-binding with backspace.
So, for example, if we had one key-binding with Control+Backspace, and
another with Control+Shift+Backspace, the latter would never trigger,
as we would always match the first one.
By checking for unshifted matches first, we ensure
Control+Shift+Backspace does match.
2025-01-31 09:07:42 +01:00
|
|
|
|
/* Match translated symbol */
|
|
|
|
|
|
tll_foreach(bindings->url, it) {
|
|
|
|
|
|
const struct key_binding *bind = &it->item;
|
|
|
|
|
|
|
|
|
|
|
|
if (bind->k.sym == sym &&
|
|
|
|
|
|
bind->mods == (mods & ~consumed))
|
|
|
|
|
|
{
|
|
|
|
|
|
execute_binding(seat, term, bind, serial);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-27 10:51:03 +01:00
|
|
|
|
/* Match raw key code */
|
|
|
|
|
|
tll_foreach(bindings->url, it) {
|
|
|
|
|
|
const struct key_binding *bind = &it->item;
|
2025-01-31 07:35:54 +01:00
|
|
|
|
if (bind->mods != mods || bind->mods == 0)
|
2025-01-27 10:51:03 +01:00
|
|
|
|
continue;
|
input: rewrite of how we match foot’s own key bindings
Bindings are matched in one out of three ways:
* By translated (by XKB) symbols
* By untranslated symbols
* By raw key codes
A translated symbol is affected by pressed modifiers, some of which
can be “consumed”. Consumed modifiers to not partake in the comparison
with the binding’s modifiers. In this mode, ctrl+shift+2 maps to
ctrl+@ on a US layout.
Untranslated symbols, or un-shifted symbols refer to the “base” symbol
of the pressed key, i.e. it’s unaffected by modifiers. In this mode,
consumed modifiers *do* partake in the comparison with the binding’s
modifiers, and ctrl+shift+2 maps to ctrl+shift+2 on a US layout.
More examples: ctrl+shift+u maps to ctrl+U in the translated lookup,
while ctrl+shift+u maps to ctrl+shift+u in the untranslated lookup.
Finally, we also match raw key codes. This allows our bindings to work
using the same physical keys when the user switches between latin and
non-latin layouts.
This means key bindings in foot.ini *must* not include both +shift+
and a *shifted* key. I.e. ctrl+shift+U is not a valid combo as it
cannot be triggered. Unfortunately, this was how you were supposed to
write bindings up until now... so, we try to detect such bindings, log
a deprecation warning and then “fix” the binding for the user.
When specifying bindings in foot.ini, both ctrl+U and ctrl+shift+u are
valid, and will work. The latter is preferred though, since we cannot
detect the raw key code for the former variant. Personally, I also
prefer the latter one because it is more explicit; it’s more obvious
which keys are involved.
However, in some cases it makes more sense to use the other
variant. Typically for non-letter combos.
2021-02-27 20:42:31 +01:00
|
|
|
|
|
2021-01-31 11:12:07 +01:00
|
|
|
|
/* Match raw key code */
|
2022-02-07 19:41:33 +01:00
|
|
|
|
tll_foreach(bind->k.key_codes, code) {
|
2021-01-31 11:12:07 +01:00
|
|
|
|
if (code->item == key) {
|
2022-02-08 19:43:00 +01:00
|
|
|
|
execute_binding(seat, term, bind, serial);
|
2021-01-31 11:12:07 +01:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
size_t seq_len = c32len(term->url_keys);
|
2021-02-07 10:32:56 +01:00
|
|
|
|
|
|
|
|
|
|
if (sym == XKB_KEY_BackSpace) {
|
|
|
|
|
|
if (seq_len > 0) {
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
term->url_keys[seq_len - 1] = U'\0';
|
2021-02-07 10:32:56 +01:00
|
|
|
|
render_refresh_urls(term);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-02-06 10:41:01 +01:00
|
|
|
|
if (mods & ~consumed)
|
2021-03-04 09:36:25 +01:00
|
|
|
|
return;
|
|
|
|
|
|
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
char32_t wc = xkb_state_key_get_utf32(seat->kbd.xkb_state, key);
|
2021-01-31 11:12:07 +01:00
|
|
|
|
|
|
|
|
|
|
/*
|
2024-02-06 12:36:45 +01:00
|
|
|
|
* Determine if this is a "valid" key. I.e. if there is a URL
|
2021-01-31 11:12:07 +01:00
|
|
|
|
* label with a key combo where this key is the next in
|
|
|
|
|
|
* sequence.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
bool is_valid = false;
|
|
|
|
|
|
const struct url *match = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
tll_foreach(term->urls, it) {
|
2021-02-13 13:45:59 +01:00
|
|
|
|
if (it->item.key == NULL)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
2021-01-31 11:12:07 +01:00
|
|
|
|
const struct url *url = &it->item;
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
const size_t key_len = c32len(it->item.key);
|
2021-01-31 11:12:07 +01:00
|
|
|
|
|
|
|
|
|
|
if (key_len >= seq_len + 1 &&
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
c32ncasecmp(url->key, term->url_keys, seq_len) == 0 &&
|
|
|
|
|
|
toc32lower(url->key[seq_len]) == toc32lower(wc))
|
2021-01-31 11:12:07 +01:00
|
|
|
|
{
|
|
|
|
|
|
is_valid = true;
|
|
|
|
|
|
if (key_len == seq_len + 1) {
|
|
|
|
|
|
match = url;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (match) {
|
url-mode: add support for XDG activation when opening URLs
First, add a ‘token’ argument to spawn(). When non-NULL, spawn() will
set the ‘XDG_ACTIVATION_TOKEN’ environment variable in the forked
process. If DISPLAY is non-NULL, we also set DESKTOP_STARTUP_ID, for
compatibility with X11 applications. Note that failing to set either
of these environment variables are considered non-fatal - i.e. we
ignore failures.
Next, add a helper function, wayl_get_activation_token(), to generate
an XDG activation token, and call a user-provided callback when it’s
‘done (since token generation is asynchronous). This function takes an
optional ‘seat’ and ‘serial’ arguments - when both are non-NULL/zero,
we set the serial on the token. ‘win’ is a required argument, used to
set the surface on the token.
Re-write wayl_win_set_urgent() to use the new helper function.
Finally, rewrite activate_url() to first try to get an activation
token (and spawn the URL launcher in the token callback). If that
fails, or if we don’t have XDG activation support, spawn the URL
launcher immediately (like before this patch).
Closes #1058
2022-05-03 19:37:04 +02:00
|
|
|
|
activate_url(seat, term, match, serial);
|
2022-03-22 19:07:06 +01:00
|
|
|
|
|
|
|
|
|
|
switch (match->action) {
|
|
|
|
|
|
case URL_ACTION_COPY:
|
|
|
|
|
|
case URL_ACTION_LAUNCH:
|
|
|
|
|
|
urls_reset(term);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case URL_ACTION_PERSISTENT:
|
|
|
|
|
|
term->url_keys[0] = U'\0';
|
|
|
|
|
|
render_refresh_urls(term);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2021-01-31 11:38:56 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
else if (is_valid) {
|
2021-01-31 11:12:07 +01:00
|
|
|
|
xassert(seq_len + 1 <= ALEN(term->url_keys));
|
|
|
|
|
|
term->url_keys[seq_len] = wc;
|
2021-02-06 20:53:06 +01:00
|
|
|
|
render_refresh_urls(term);
|
2021-01-31 11:12:07 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-30 09:06:47 +01:00
|
|
|
|
struct vline {
|
|
|
|
|
|
char *utf8;
|
2025-01-30 09:51:50 +01:00
|
|
|
|
size_t len; /* Length of utf8[] */
|
|
|
|
|
|
size_t sz; /* utf8[] allocated size */
|
|
|
|
|
|
struct coord *map; /* Maps utf8[ofs] to grid coordinates */
|
2025-01-30 09:06:47 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
regex_detected(const struct terminal *term, enum url_action action, url_list_t *urls)
|
|
|
|
|
|
{
|
2025-01-30 09:51:50 +01:00
|
|
|
|
/*
|
|
|
|
|
|
* Use regcomp()+regexec() to find patterns.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Since we can't feed regexec() one character at a time, and
|
|
|
|
|
|
* since it doesn't accept wide characters, we need to build utf8
|
|
|
|
|
|
* strings.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Each string represents a logical line (i.e. handle line-wrap).
|
|
|
|
|
|
* To be able to map regex matches back to the grid, we store the
|
|
|
|
|
|
* grid coordinates of *each* character, in the line struct as
|
|
|
|
|
|
* well. This is offset based; utf8[ofs] has its grid coordinates
|
|
|
|
|
|
* in map[ofs.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/* There is *at most* term->rows logical lines */
|
2025-01-30 09:06:47 +01:00
|
|
|
|
struct vline vlines[term->rows];
|
|
|
|
|
|
size_t vline_idx = 0;
|
|
|
|
|
|
|
|
|
|
|
|
memset(vlines, 0, sizeof(vlines));
|
|
|
|
|
|
struct vline *vline = &vlines[vline_idx];
|
|
|
|
|
|
|
|
|
|
|
|
mbstate_t ps = {0};
|
|
|
|
|
|
|
2025-01-30 09:51:50 +01:00
|
|
|
|
for (int r = 0; r < term->rows; r++) {
|
|
|
|
|
|
const struct row *row = grid_row_in_view(term->grid, r);
|
2025-01-30 09:06:47 +01:00
|
|
|
|
|
|
|
|
|
|
for (int c = 0; c < term->cols; c++) {
|
|
|
|
|
|
const struct cell *cell = &row->cells[c];
|
|
|
|
|
|
const char32_t *wc = &cell->wc;
|
|
|
|
|
|
size_t wc_count = 1;
|
|
|
|
|
|
|
2025-01-30 09:51:50 +01:00
|
|
|
|
/* Expand combining characters */
|
2025-01-30 09:06:47 +01:00
|
|
|
|
if (wc[0] >= CELL_COMB_CHARS_LO && wc[0] <= CELL_COMB_CHARS_HI) {
|
|
|
|
|
|
const struct composed *composed =
|
|
|
|
|
|
composed_lookup(term->composed, wc[0] - CELL_COMB_CHARS_LO);
|
|
|
|
|
|
xassert(composed != NULL);
|
|
|
|
|
|
|
|
|
|
|
|
wc = composed->chars;
|
|
|
|
|
|
wc_count = composed->count;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-30 09:51:50 +01:00
|
|
|
|
/* Convert wide character to utf8 */
|
2025-01-30 09:06:47 +01:00
|
|
|
|
for (size_t i = 0; i < wc_count; i++) {
|
|
|
|
|
|
char buf[16];
|
|
|
|
|
|
size_t char_len = c32rtomb(buf, wc[i], &ps);
|
|
|
|
|
|
|
2025-01-30 09:51:50 +01:00
|
|
|
|
if (char_len == (size_t)-1)
|
2025-01-30 09:06:47 +01:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
for (size_t j = 0; j < char_len; j++) {
|
2025-01-30 09:51:50 +01:00
|
|
|
|
const size_t requires_size = vline->len + char_len;
|
|
|
|
|
|
|
2025-01-31 13:10:58 +01:00
|
|
|
|
/* Need to grow? Remember to save at least one byte for terminator */
|
|
|
|
|
|
if (vline->sz == 0 || requires_size > vline->sz - 1) {
|
2025-01-30 09:51:50 +01:00
|
|
|
|
const size_t new_size = requires_size * 2;
|
|
|
|
|
|
vline->utf8 = xreallocarray(vline->utf8, new_size, 1);
|
|
|
|
|
|
vline->map = xreallocarray(vline->map, new_size, sizeof(vline->map[0]));
|
|
|
|
|
|
vline->sz = new_size;
|
2025-01-30 09:06:47 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
vline->utf8[vline->len + j] = buf[j];
|
2025-01-30 09:51:50 +01:00
|
|
|
|
vline->map[vline->len + j] = (struct coord){c, term->grid->view + r};
|
2025-01-30 09:06:47 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
vline->len += char_len;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (row->linebreak) {
|
|
|
|
|
|
if (vline->len > 0) {
|
|
|
|
|
|
vline->utf8[vline->len++] = '\0';
|
|
|
|
|
|
ps = (mbstate_t){0};
|
|
|
|
|
|
|
|
|
|
|
|
vline_idx++;
|
|
|
|
|
|
vline = &vlines[vline_idx];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-30 12:26:23 +01:00
|
|
|
|
const regex_t *preg = &term->conf->url.preg;
|
2025-01-30 09:51:50 +01:00
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < ALEN(vlines); i++) {
|
|
|
|
|
|
const struct vline *v = &vlines[i];
|
|
|
|
|
|
if (v->utf8 == NULL)
|
|
|
|
|
|
continue;;
|
|
|
|
|
|
|
|
|
|
|
|
const char *search_string = v->utf8;
|
|
|
|
|
|
while (true) {
|
2025-01-30 12:26:23 +01:00
|
|
|
|
regmatch_t matches[preg->re_nsub + 1];
|
|
|
|
|
|
int r = regexec(preg, search_string, preg->re_nsub + 1, matches, 0);
|
2025-01-30 09:06:47 +01:00
|
|
|
|
|
|
|
|
|
|
if (r == REG_NOMATCH)
|
2025-01-30 09:51:50 +01:00
|
|
|
|
break;
|
2025-01-30 09:06:47 +01:00
|
|
|
|
|
2025-01-30 09:51:50 +01:00
|
|
|
|
const size_t mlen = matches[0].rm_eo - matches[0].rm_so;
|
|
|
|
|
|
const size_t start = &search_string[matches[0].rm_so] - v->utf8;
|
|
|
|
|
|
const size_t end = start + mlen;
|
|
|
|
|
|
|
|
|
|
|
|
LOG_DBG(
|
2025-01-30 11:55:09 +01:00
|
|
|
|
"regex match at row %d: %.*srow/col = %dx%d",
|
2025-01-30 09:51:50 +01:00
|
|
|
|
matches[0].rm_so, (int)mlen, &search_string[matches[0].rm_so],
|
2025-01-30 11:55:09 +01:00
|
|
|
|
v->map[start].row, v->map[start].col);
|
2025-01-30 09:51:50 +01:00
|
|
|
|
|
|
|
|
|
|
tll_push_back(
|
|
|
|
|
|
*urls,
|
|
|
|
|
|
((struct url){
|
|
|
|
|
|
.id = (uint64_t)rand() << 32 | rand(),
|
|
|
|
|
|
.url = xstrndup(&v->utf8[start], mlen),
|
|
|
|
|
|
.range = {
|
|
|
|
|
|
.start = v->map[start],
|
|
|
|
|
|
.end = v->map[end - 1], /* Inclusive */
|
|
|
|
|
|
},
|
|
|
|
|
|
.action = action,
|
|
|
|
|
|
.osc8 = false}));
|
|
|
|
|
|
|
|
|
|
|
|
search_string += matches[0].rm_eo;
|
2025-01-30 09:06:47 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
free(v->utf8);
|
|
|
|
|
|
free(v->map);
|
|
|
|
|
|
}
|
2021-08-09 18:25:36 +02:00
|
|
|
|
}
|
2025-01-30 12:26:23 +01:00
|
|
|
|
|
2021-02-13 12:42:35 +01:00
|
|
|
|
static void
|
|
|
|
|
|
osc8_uris(const struct terminal *term, enum url_action action, url_list_t *urls)
|
|
|
|
|
|
{
|
2021-02-14 21:29:22 +01:00
|
|
|
|
bool dont_touch_url_attr = false;
|
|
|
|
|
|
|
2021-05-20 17:56:56 +02:00
|
|
|
|
switch (term->conf->url.osc8_underline) {
|
2021-02-14 21:29:22 +01:00
|
|
|
|
case OSC8_UNDERLINE_URL_MODE:
|
|
|
|
|
|
dont_touch_url_attr = false;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case OSC8_UNDERLINE_ALWAYS:
|
|
|
|
|
|
dont_touch_url_attr = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-02-13 12:42:35 +01:00
|
|
|
|
for (int r = 0; r < term->rows; r++) {
|
|
|
|
|
|
const struct row *row = grid_row_in_view(term->grid, r);
|
2021-11-26 19:55:27 +01:00
|
|
|
|
const struct row_data *extra = row->extra;
|
2021-02-13 12:42:35 +01:00
|
|
|
|
|
2021-11-26 19:55:27 +01:00
|
|
|
|
if (extra == NULL)
|
2021-02-13 12:42:35 +01:00
|
|
|
|
continue;
|
|
|
|
|
|
|
2021-11-26 19:55:27 +01:00
|
|
|
|
for (size_t i = 0; i < extra->uri_ranges.count; i++) {
|
2024-06-23 13:29:12 +02:00
|
|
|
|
const struct row_range *range = &extra->uri_ranges.v[i];
|
2021-11-26 19:55:27 +01:00
|
|
|
|
|
2021-02-13 12:42:35 +01:00
|
|
|
|
struct coord start = {
|
2021-11-26 19:55:27 +01:00
|
|
|
|
.col = range->start,
|
2021-02-13 12:42:35 +01:00
|
|
|
|
.row = r + term->grid->view,
|
|
|
|
|
|
};
|
|
|
|
|
|
struct coord end = {
|
2021-11-26 19:55:27 +01:00
|
|
|
|
.col = range->end,
|
2021-02-13 12:42:35 +01:00
|
|
|
|
.row = r + term->grid->view,
|
|
|
|
|
|
};
|
|
|
|
|
|
tll_push_back(
|
|
|
|
|
|
*urls,
|
|
|
|
|
|
((struct url){
|
2024-06-23 13:29:12 +02:00
|
|
|
|
.id = range->uri.id,
|
|
|
|
|
|
.url = xstrdup(range->uri.uri),
|
2022-04-09 15:09:02 +02:00
|
|
|
|
.range = {
|
|
|
|
|
|
.start = start,
|
|
|
|
|
|
.end = end,
|
|
|
|
|
|
},
|
2021-02-14 21:29:22 +01:00
|
|
|
|
.action = action,
|
2021-05-22 16:42:43 +02:00
|
|
|
|
.url_mode_dont_change_url_attr = dont_touch_url_attr,
|
|
|
|
|
|
.osc8 = true}));
|
2021-02-13 12:42:35 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-02-14 13:36:07 +01:00
|
|
|
|
static void
|
2021-05-22 16:42:43 +02:00
|
|
|
|
remove_overlapping(url_list_t *urls, int cols)
|
2021-02-14 13:36:07 +01:00
|
|
|
|
{
|
|
|
|
|
|
tll_foreach(*urls, outer) {
|
|
|
|
|
|
tll_foreach(*urls, inner) {
|
|
|
|
|
|
if (outer == inner)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
2021-05-22 16:42:43 +02:00
|
|
|
|
const struct url *out = &outer->item;
|
|
|
|
|
|
const struct url *in = &inner->item;
|
|
|
|
|
|
|
2022-04-09 15:09:02 +02:00
|
|
|
|
uint64_t in_start = in->range.start.row * cols + in->range.start.col;
|
|
|
|
|
|
uint64_t in_end = in->range.end.row * cols + in->range.end.col;
|
2021-05-22 16:42:43 +02:00
|
|
|
|
|
2022-04-09 15:09:02 +02:00
|
|
|
|
uint64_t out_start = out->range.start.row * cols + out->range.start.col;
|
|
|
|
|
|
uint64_t out_end = out->range.end.row * cols + out->range.end.col;
|
2021-05-22 16:42:43 +02:00
|
|
|
|
|
|
|
|
|
|
if ((in_start <= out_start && in_end >= out_start) ||
|
|
|
|
|
|
(in_start <= out_end && in_end >= out_end) ||
|
|
|
|
|
|
(in_start >= out_start && in_end <= out_end))
|
2021-02-14 13:36:07 +01:00
|
|
|
|
{
|
2021-05-22 16:42:43 +02:00
|
|
|
|
/*
|
2024-02-06 12:36:45 +01:00
|
|
|
|
* OSC-8 URLs can't overlap with each
|
2021-05-22 16:42:43 +02:00
|
|
|
|
* other.
|
|
|
|
|
|
*
|
2021-05-22 17:08:14 +02:00
|
|
|
|
* Similarly, auto-detected URLs cannot overlap with
|
2021-05-22 16:42:43 +02:00
|
|
|
|
* each other.
|
|
|
|
|
|
*
|
|
|
|
|
|
* But OSC-8 URLs can overlap with auto-detected ones.
|
|
|
|
|
|
*/
|
|
|
|
|
|
xassert(in->osc8 || out->osc8);
|
|
|
|
|
|
|
2021-07-11 10:06:12 +02:00
|
|
|
|
if (in->osc8)
|
|
|
|
|
|
outer->item.duplicate = true;
|
|
|
|
|
|
else
|
|
|
|
|
|
inner->item.duplicate = true;
|
2021-02-14 13:36:07 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2021-07-11 10:06:12 +02:00
|
|
|
|
|
|
|
|
|
|
tll_foreach(*urls, it) {
|
|
|
|
|
|
if (it->item.duplicate) {
|
|
|
|
|
|
url_destroy(&it->item);
|
|
|
|
|
|
tll_remove(*urls, it);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2021-02-14 13:36:07 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-01-31 11:12:07 +01:00
|
|
|
|
void
|
2021-02-06 20:01:52 +01:00
|
|
|
|
urls_collect(const struct terminal *term, enum url_action action, url_list_t *urls)
|
2021-01-31 11:12:07 +01:00
|
|
|
|
{
|
|
|
|
|
|
xassert(tll_length(term->urls) == 0);
|
2021-02-13 12:42:35 +01:00
|
|
|
|
osc8_uris(term, action, urls);
|
2025-01-30 09:06:47 +01:00
|
|
|
|
regex_detected(term, action, urls);
|
2021-05-22 16:42:43 +02:00
|
|
|
|
remove_overlapping(urls, term->grid->num_cols);
|
2021-02-06 20:01:52 +01:00
|
|
|
|
}
|
2021-01-31 11:12:07 +01:00
|
|
|
|
|
2021-02-07 00:01:29 +01:00
|
|
|
|
static int
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
c32cmp_qsort_wrapper(const void *_a, const void *_b)
|
2021-02-07 00:01:29 +01:00
|
|
|
|
{
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
const char32_t *a = *(const char32_t **)_a;
|
|
|
|
|
|
const char32_t *b = *(const char32_t **)_b;
|
|
|
|
|
|
return c32cmp(a, b);
|
2021-02-07 00:01:29 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-02-06 21:37:26 +01:00
|
|
|
|
static void
|
2021-02-13 11:43:28 +01:00
|
|
|
|
generate_key_combos(const struct config *conf,
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
size_t count, char32_t *combos[static count])
|
2021-02-06 21:37:26 +01:00
|
|
|
|
{
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
const char32_t *alphabet = conf->url.label_letters;
|
|
|
|
|
|
const size_t alphabet_len = c32len(alphabet);
|
2021-02-07 00:01:29 +01:00
|
|
|
|
|
|
|
|
|
|
size_t hints_count = 1;
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
char32_t **hints = xmalloc(hints_count * sizeof(hints[0]));
|
2021-02-06 21:37:26 +01:00
|
|
|
|
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
hints[0] = xc32dup(U"");
|
2021-02-06 21:37:26 +01:00
|
|
|
|
|
|
|
|
|
|
size_t offset = 0;
|
2021-02-07 16:03:11 +01:00
|
|
|
|
do {
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
const char32_t *prefix = hints[offset++];
|
|
|
|
|
|
const size_t prefix_len = c32len(prefix);
|
2021-02-06 21:37:26 +01:00
|
|
|
|
|
2021-02-07 15:10:48 +01:00
|
|
|
|
hints = xrealloc(hints, (hints_count + alphabet_len) * sizeof(hints[0]));
|
2021-02-07 00:01:29 +01:00
|
|
|
|
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
const char32_t *wc = &alphabet[0];
|
2021-02-07 16:03:11 +01:00
|
|
|
|
for (size_t i = 0; i < alphabet_len; i++, wc++) {
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
char32_t *hint = xmalloc((prefix_len + 1 + 1) * sizeof(char32_t));
|
2021-02-07 16:03:11 +01:00
|
|
|
|
hints[hints_count + i] = hint;
|
2021-02-07 00:01:29 +01:00
|
|
|
|
|
|
|
|
|
|
/* Will be reversed later */
|
2021-02-07 16:03:11 +01:00
|
|
|
|
hint[0] = *wc;
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
c32cpy(&hint[1], prefix);
|
2021-02-06 21:37:26 +01:00
|
|
|
|
}
|
2021-02-07 00:01:29 +01:00
|
|
|
|
hints_count += alphabet_len;
|
2021-02-07 16:03:11 +01:00
|
|
|
|
} while (hints_count - offset < count);
|
2021-02-06 21:37:26 +01:00
|
|
|
|
|
2021-02-07 00:01:29 +01:00
|
|
|
|
xassert(hints_count - offset >= count);
|
2021-02-06 21:37:26 +01:00
|
|
|
|
|
2024-02-06 12:36:45 +01:00
|
|
|
|
/* Copy slice of 'hints' array to the caller provided array */
|
2021-02-07 00:01:29 +01:00
|
|
|
|
for (size_t i = 0; i < hints_count; i++) {
|
|
|
|
|
|
if (i >= offset && i < offset + count)
|
|
|
|
|
|
combos[i - offset] = hints[i];
|
2021-02-06 21:37:26 +01:00
|
|
|
|
else
|
2021-02-07 00:01:29 +01:00
|
|
|
|
free(hints[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
free(hints);
|
|
|
|
|
|
|
2024-02-06 12:36:45 +01:00
|
|
|
|
/* Sorting is a kind of shuffle, since we're sorting on the
|
2021-02-07 00:01:29 +01:00
|
|
|
|
* *reversed* strings */
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
qsort(combos, count, sizeof(char32_t *), &c32cmp_qsort_wrapper);
|
2021-02-07 00:01:29 +01:00
|
|
|
|
|
|
|
|
|
|
/* Reverse all strings */
|
|
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
const size_t len = c32len(combos[i]);
|
2021-02-07 00:01:29 +01:00
|
|
|
|
for (size_t j = 0; j < len / 2; j++) {
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
char32_t tmp = combos[i][j];
|
2021-02-07 00:01:29 +01:00
|
|
|
|
combos[i][j] = combos[i][len - j - 1];
|
|
|
|
|
|
combos[i][len - j - 1] = tmp;
|
|
|
|
|
|
}
|
2021-02-06 21:37:26 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-02-06 20:01:52 +01:00
|
|
|
|
void
|
2021-02-13 11:43:28 +01:00
|
|
|
|
urls_assign_key_combos(const struct config *conf, url_list_t *urls)
|
2021-02-06 20:01:52 +01:00
|
|
|
|
{
|
2021-02-07 00:01:29 +01:00
|
|
|
|
const size_t count = tll_length(*urls);
|
2021-02-07 14:29:34 +01:00
|
|
|
|
if (count == 0)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
char32_t *combos[count];
|
2021-02-13 11:43:28 +01:00
|
|
|
|
generate_key_combos(conf, count, combos);
|
2021-01-31 11:12:07 +01:00
|
|
|
|
|
2021-02-21 20:10:24 +01:00
|
|
|
|
size_t combo_idx = 0;
|
|
|
|
|
|
|
2021-02-13 13:45:59 +01:00
|
|
|
|
tll_foreach(*urls, it) {
|
|
|
|
|
|
bool id_already_seen = false;
|
2021-02-21 20:10:24 +01:00
|
|
|
|
|
2022-08-30 17:48:04 +02:00
|
|
|
|
/* Look for already processed URLs where both the URI and the
|
|
|
|
|
|
* ID matches */
|
|
|
|
|
|
tll_foreach(*urls, it2) {
|
|
|
|
|
|
if (&it->item == &it2->item)
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
if (it->item.id == it2->item.id &&
|
2024-01-24 23:17:28 +00:00
|
|
|
|
streq(it->item.url, it2->item.url))
|
2022-08-30 17:48:04 +02:00
|
|
|
|
{
|
2021-02-13 13:45:59 +01:00
|
|
|
|
id_already_seen = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (id_already_seen)
|
|
|
|
|
|
continue;
|
2021-02-21 20:10:24 +01:00
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* Scan previous URLs, and check if *this* URL matches any of
|
2023-10-03 14:11:55 +02:00
|
|
|
|
* them; if so, reuse the *same* key combo.
|
2021-02-21 20:10:24 +01:00
|
|
|
|
*/
|
|
|
|
|
|
bool url_already_seen = false;
|
|
|
|
|
|
tll_foreach(*urls, it2) {
|
|
|
|
|
|
if (&it->item == &it2->item)
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2024-01-24 23:17:28 +00:00
|
|
|
|
if (streq(it->item.url, it2->item.url)) {
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
it->item.key = xc32dup(it2->item.key);
|
2021-02-21 20:10:24 +01:00
|
|
|
|
url_already_seen = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2021-02-13 13:45:59 +01:00
|
|
|
|
|
2021-02-21 20:10:24 +01:00
|
|
|
|
if (!url_already_seen)
|
|
|
|
|
|
it->item.key = combos[combo_idx++];
|
2021-02-13 13:45:59 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-02-06 12:36:45 +01:00
|
|
|
|
/* Free combos we didn't use up */
|
2021-02-21 20:10:24 +01:00
|
|
|
|
for (size_t i = combo_idx; i < count; i++)
|
2021-02-13 13:45:59 +01:00
|
|
|
|
free(combos[i]);
|
2021-01-31 11:12:07 +01:00
|
|
|
|
|
|
|
|
|
|
#if defined(_DEBUG) && LOG_ENABLE_DBG
|
2021-02-06 20:01:52 +01:00
|
|
|
|
tll_foreach(*urls, it) {
|
2021-02-13 13:45:59 +01:00
|
|
|
|
if (it->item.key == NULL)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
char *key = ac32tombs(it->item.key);
|
|
|
|
|
|
xassert(key != NULL);
|
|
|
|
|
|
|
2022-08-30 17:48:04 +02:00
|
|
|
|
LOG_DBG("URL: %s (key=%s, id=%"PRIu64")", it->item.url, key, it->item.id);
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
|
free(key);
|
2021-01-31 11:12:07 +01:00
|
|
|
|
}
|
|
|
|
|
|
#endif
|
2021-02-06 20:01:52 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
tag_cells_for_url(struct terminal *term, const struct url *url, bool value)
|
|
|
|
|
|
{
|
2021-02-14 21:29:22 +01:00
|
|
|
|
if (url->url_mode_dont_change_url_attr)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2022-11-30 10:51:45 +01:00
|
|
|
|
struct grid *grid = term->url_grid_snapshot;
|
|
|
|
|
|
xassert(grid != NULL);
|
|
|
|
|
|
|
2022-04-09 15:09:02 +02:00
|
|
|
|
const struct coord *start = &url->range.start;
|
|
|
|
|
|
const struct coord *end = &url->range.end;
|
2021-02-06 20:01:52 +01:00
|
|
|
|
|
2022-11-30 10:51:45 +01:00
|
|
|
|
size_t end_r = end->row & (grid->num_rows - 1);
|
2021-02-06 20:01:52 +01:00
|
|
|
|
|
2022-11-30 10:51:45 +01:00
|
|
|
|
size_t r = start->row & (grid->num_rows - 1);
|
2021-02-06 20:01:52 +01:00
|
|
|
|
size_t c = start->col;
|
|
|
|
|
|
|
2022-11-30 10:51:45 +01:00
|
|
|
|
struct row *row = grid->rows[r];
|
2021-02-06 20:01:52 +01:00
|
|
|
|
row->dirty = true;
|
|
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
|
struct cell *cell = &row->cells[c];
|
|
|
|
|
|
cell->attrs.url = value;
|
|
|
|
|
|
cell->attrs.clean = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (r == end_r && c == end->col)
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
if (++c >= term->cols) {
|
2022-11-30 10:51:45 +01:00
|
|
|
|
r = (r + 1) & (grid->num_rows - 1);
|
2021-02-06 20:01:52 +01:00
|
|
|
|
c = 0;
|
|
|
|
|
|
|
2022-11-30 10:51:45 +01:00
|
|
|
|
row = grid->rows[r];
|
url-mode: abort when running into un-allocated scrollback memory
When tagging URL cells (in preparation for rendering URL mode), we
loop the URL’s entire range, setting the `url` attribute of all cells,
and dirtying the rows.
It is possible to create URLs that are invalid, and wrap around the
scrollback, even though the scrollback hasn’t yet been filled. For
example, by starting an OSC-8 URL, moving the cursor, and then closing
the OSC-8 URL.
These URLs are invalid, but are still rendered just fine. “Fine” being
relative - they will typically fill the entire screen. But at least
that’s a very clear indication for the user that’s something is wrong.
The problem is when we hit un-allocated scrollback rows. We didn’t
check for NULL rows, and crashed.
This has now been fixed.
2021-07-11 11:31:11 +02:00
|
|
|
|
if (row == NULL) {
|
|
|
|
|
|
/* Un-allocated scrollback. This most likely means a
|
|
|
|
|
|
* runaway OSC-8 URL. */
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2021-02-06 20:01:52 +01:00
|
|
|
|
row->dirty = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
urls_render(struct terminal *term)
|
|
|
|
|
|
{
|
2021-01-31 11:12:07 +01:00
|
|
|
|
struct wl_window *win = term->window;
|
|
|
|
|
|
|
2021-02-07 16:05:02 +01:00
|
|
|
|
if (tll_length(win->term->urls) == 0)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2024-05-21 06:18:00 +02:00
|
|
|
|
/* Disable IME while in URL-mode */
|
|
|
|
|
|
if (term_ime_is_enabled(term)) {
|
|
|
|
|
|
term->ime_reenable_after_url_mode = true;
|
|
|
|
|
|
term_ime_disable(term);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-02-23 09:24:50 +01:00
|
|
|
|
/* Dirty the last cursor, to ensure it is erased */
|
|
|
|
|
|
{
|
|
|
|
|
|
struct row *cursor_row = term->render.last_cursor.row;
|
|
|
|
|
|
if (cursor_row != NULL) {
|
|
|
|
|
|
struct cell *cell = &cursor_row->cells[term->render.last_cursor.col];
|
|
|
|
|
|
cell->attrs.clean = 0;
|
|
|
|
|
|
cursor_row->dirty = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
term->render.last_cursor.row = NULL;
|
|
|
|
|
|
|
2024-02-06 12:36:45 +01:00
|
|
|
|
/* Clear scroll damage, to ensure we don't apply it twice (once on
|
2021-02-24 21:39:29 +01:00
|
|
|
|
* the snapshot:ed grid, and then later again on the real grid) */
|
|
|
|
|
|
tll_free(term->grid->scroll_damage);
|
|
|
|
|
|
|
|
|
|
|
|
/* Damage the entire view, to ensure a full screen redraw, both
|
|
|
|
|
|
* now, when entering URL mode, and later, when exiting it. */
|
|
|
|
|
|
term_damage_view(term);
|
|
|
|
|
|
|
url-mode: snapshot screen state when entering URL mode
Previously, we automatically exited URL mode whenever we received data
on the PTY. This was done since we don’t know _what_ has changed on
the screen, and we don’t want to display misleading jump labels.
However, this becomes a problem in curses-like applications that
periodically updates part of the screen. For example, a statusbar with
a clock.
This patch changes this behavior; instead of cancelling URL mode when
receiving PTY data, we snapshot the grid when entering URL mode.
When *rendering*, we use the snapshot:ed grid, while PTY updates
modify the “real” grid.
Snapshot:ing the grid means taking a full/deep copy of the current
grid, including sixel images etc.
Finally, it isn’t necessary to “damage” the entire view
when *entering* URL mode, since we’re at that point the renderer is in
sync with the grid. But we *do* need to damage the entire view when
exiting URL mode, since the grid changes on the “real” grid hasn’t
been tracked by the renderer.
2021-02-22 10:22:41 +01:00
|
|
|
|
/* Snapshot the current grid */
|
|
|
|
|
|
term->url_grid_snapshot = grid_snapshot(term->grid);
|
|
|
|
|
|
|
2022-11-30 10:51:45 +01:00
|
|
|
|
xassert(tll_length(win->urls) == 0);
|
|
|
|
|
|
tll_foreach(win->term->urls, it) {
|
|
|
|
|
|
struct wl_url url = {.url = &it->item};
|
|
|
|
|
|
wayl_win_subsurface_new(win, &url.surf, false);
|
|
|
|
|
|
|
|
|
|
|
|
tll_push_back(win->urls, url);
|
|
|
|
|
|
tag_cells_for_url(term, &it->item, true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-02-06 20:01:52 +01:00
|
|
|
|
render_refresh_urls(term);
|
2021-02-06 11:51:58 +01:00
|
|
|
|
render_refresh(term);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-02-06 20:26:01 +01:00
|
|
|
|
static void
|
|
|
|
|
|
url_destroy(struct url *url)
|
|
|
|
|
|
{
|
|
|
|
|
|
free(url->url);
|
2021-02-07 00:01:29 +01:00
|
|
|
|
free(url->key);
|
2021-02-06 20:26:01 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-01-31 11:12:07 +01:00
|
|
|
|
void
|
|
|
|
|
|
urls_reset(struct terminal *term)
|
|
|
|
|
|
{
|
url-mode: snapshot screen state when entering URL mode
Previously, we automatically exited URL mode whenever we received data
on the PTY. This was done since we don’t know _what_ has changed on
the screen, and we don’t want to display misleading jump labels.
However, this becomes a problem in curses-like applications that
periodically updates part of the screen. For example, a statusbar with
a clock.
This patch changes this behavior; instead of cancelling URL mode when
receiving PTY data, we snapshot the grid when entering URL mode.
When *rendering*, we use the snapshot:ed grid, while PTY updates
modify the “real” grid.
Snapshot:ing the grid means taking a full/deep copy of the current
grid, including sixel images etc.
Finally, it isn’t necessary to “damage” the entire view
when *entering* URL mode, since we’re at that point the renderer is in
sync with the grid. But we *do* need to damage the entire view when
exiting URL mode, since the grid changes on the “real” grid hasn’t
been tracked by the renderer.
2021-02-22 10:22:41 +01:00
|
|
|
|
if (likely(tll_length(term->urls) == 0)) {
|
|
|
|
|
|
xassert(term->url_grid_snapshot == NULL);
|
2021-01-31 11:39:23 +01:00
|
|
|
|
return;
|
url-mode: snapshot screen state when entering URL mode
Previously, we automatically exited URL mode whenever we received data
on the PTY. This was done since we don’t know _what_ has changed on
the screen, and we don’t want to display misleading jump labels.
However, this becomes a problem in curses-like applications that
periodically updates part of the screen. For example, a statusbar with
a clock.
This patch changes this behavior; instead of cancelling URL mode when
receiving PTY data, we snapshot the grid when entering URL mode.
When *rendering*, we use the snapshot:ed grid, while PTY updates
modify the “real” grid.
Snapshot:ing the grid means taking a full/deep copy of the current
grid, including sixel images etc.
Finally, it isn’t necessary to “damage” the entire view
when *entering* URL mode, since we’re at that point the renderer is in
sync with the grid. But we *do* need to damage the entire view when
exiting URL mode, since the grid changes on the “real” grid hasn’t
been tracked by the renderer.
2021-02-22 10:22:41 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
grid_free(term->url_grid_snapshot);
|
|
|
|
|
|
free(term->url_grid_snapshot);
|
|
|
|
|
|
term->url_grid_snapshot = NULL;
|
2021-02-23 09:24:50 +01:00
|
|
|
|
|
|
|
|
|
|
/*
|
2024-02-06 12:36:45 +01:00
|
|
|
|
* Make sure "last cursor" doesn't point to a row in the just
|
2021-02-23 09:24:50 +01:00
|
|
|
|
* free:d snapshot grid.
|
|
|
|
|
|
*
|
2024-02-06 12:36:45 +01:00
|
|
|
|
* Note that it will still be erased properly (if hasn't already),
|
2021-02-23 09:24:50 +01:00
|
|
|
|
* since we marked the cell as dirty *before* taking the grid
|
|
|
|
|
|
* snapshot.
|
|
|
|
|
|
*/
|
url-mode: snapshot screen state when entering URL mode
Previously, we automatically exited URL mode whenever we received data
on the PTY. This was done since we don’t know _what_ has changed on
the screen, and we don’t want to display misleading jump labels.
However, this becomes a problem in curses-like applications that
periodically updates part of the screen. For example, a statusbar with
a clock.
This patch changes this behavior; instead of cancelling URL mode when
receiving PTY data, we snapshot the grid when entering URL mode.
When *rendering*, we use the snapshot:ed grid, while PTY updates
modify the “real” grid.
Snapshot:ing the grid means taking a full/deep copy of the current
grid, including sixel images etc.
Finally, it isn’t necessary to “damage” the entire view
when *entering* URL mode, since we’re at that point the renderer is in
sync with the grid. But we *do* need to damage the entire view when
exiting URL mode, since the grid changes on the “real” grid hasn’t
been tracked by the renderer.
2021-02-22 10:22:41 +01:00
|
|
|
|
term->render.last_cursor.row = NULL;
|
2021-01-31 11:39:23 +01:00
|
|
|
|
|
2021-01-31 11:12:07 +01:00
|
|
|
|
if (term->window != NULL) {
|
|
|
|
|
|
tll_foreach(term->window->urls, it) {
|
2021-02-12 11:31:31 +01:00
|
|
|
|
wayl_win_subsurface_destroy(&it->item.surf);
|
2021-02-07 14:52:04 +01:00
|
|
|
|
tll_remove(term->window->urls, it);
|
2023-04-25 21:33:45 +02:00
|
|
|
|
|
|
|
|
|
|
/* Work around Sway bug - unmapping a sub-surface does not
|
|
|
|
|
|
* damage the underlying surface */
|
|
|
|
|
|
quirk_sway_subsurface_unmap(term);
|
2021-01-31 11:12:07 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
tll_foreach(term->urls, it) {
|
2021-02-06 20:26:01 +01:00
|
|
|
|
url_destroy(&it->item);
|
2021-02-07 14:52:04 +01:00
|
|
|
|
tll_remove(term->urls, it);
|
2021-01-31 11:12:07 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-02-14 14:18:11 +01:00
|
|
|
|
term->urls_show_uri_on_jump_label = false;
|
2021-01-31 11:12:07 +01:00
|
|
|
|
memset(term->url_keys, 0, sizeof(term->url_keys));
|
url-mode: snapshot screen state when entering URL mode
Previously, we automatically exited URL mode whenever we received data
on the PTY. This was done since we don’t know _what_ has changed on
the screen, and we don’t want to display misleading jump labels.
However, this becomes a problem in curses-like applications that
periodically updates part of the screen. For example, a statusbar with
a clock.
This patch changes this behavior; instead of cancelling URL mode when
receiving PTY data, we snapshot the grid when entering URL mode.
When *rendering*, we use the snapshot:ed grid, while PTY updates
modify the “real” grid.
Snapshot:ing the grid means taking a full/deep copy of the current
grid, including sixel images etc.
Finally, it isn’t necessary to “damage” the entire view
when *entering* URL mode, since we’re at that point the renderer is in
sync with the grid. But we *do* need to damage the entire view when
exiting URL mode, since the grid changes on the “real” grid hasn’t
been tracked by the renderer.
2021-02-22 10:22:41 +01:00
|
|
|
|
|
2024-05-21 06:18:00 +02:00
|
|
|
|
/* Re-enable IME, if it was enabled before we entered URL-mode */
|
|
|
|
|
|
if (term->ime_reenable_after_url_mode) {
|
|
|
|
|
|
term->ime_reenable_after_url_mode = false;
|
|
|
|
|
|
term_ime_enable(term);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-02-06 11:51:58 +01:00
|
|
|
|
render_refresh(term);
|
2021-01-31 11:12:07 +01:00
|
|
|
|
}
|