From 0effa40fd9520e7e9af83d5a26d0d7be58b4094e Mon Sep 17 00:00:00 2001 From: Christian Persch Date: Sun, 24 Jul 2022 14:45:57 +0200 Subject: widget: gtk4: Add API to check event context https://gitlab.gnome.org/GNOME/vte/-/issues/2530 --- src/vte.cc | 33 +++++++++ src/vte/vteterminal.h | 33 +++++++++ src/vtegtk.cc | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/vteinternal.hh | 20 +++--- src/widget.hh | 27 ++++++++ 5 files changed, 288 insertions(+), 8 deletions(-) diff --git a/src/vte.cc b/src/vte.cc index 00cd243b..ed99daf6 100644 --- a/src/vte.cc +++ b/src/vte.cc @@ -1866,6 +1866,39 @@ Terminal::regex_match_check(vte::platform::MouseEvent const& event, return regex_match_check(col, row - (long)m_screen->scroll_delta, tag); } +#if VTE_GTK == 4 + +char* +Terminal::regex_match_check_at(double x, + double y, + int *tag) +{ + long col, row; + if (!rowcol_at(x, y, &col, &row)) + return nullptr; + + /* FIXME Shouldn't rely on a deprecated, not sub-row aware method. */ + // FIXMEchpe fix this scroll_delta substraction! + return regex_match_check(col, row - (long)m_screen->scroll_delta, tag); +} + +bool +Terminal::regex_match_check_extra_at(double x, + double y, + vte::base::Regex const** regexes, + size_t n_regexes, + uint32_t match_flags, + char** matches) +{ + long col, row; + if (!rowcol_at(x, y, &col, &row)) + return false; + + return regex_match_check_extra(col, row, regexes, n_regexes, match_flags, matches); +} + +#endif /* VTE_GTK == 4 */ + bool Terminal::regex_match_check_extra(vte::platform::MouseEvent const& event, vte::base::Regex const** regexes, diff --git a/src/vte/vteterminal.h b/src/vte/vteterminal.h index c71658d2..d2d9a736 100644 --- a/src/vte/vteterminal.h +++ b/src/vte/vteterminal.h @@ -425,6 +425,13 @@ _VTE_PUBLIC char *vte_terminal_hyperlink_check_event(VteTerminal *terminal, GdkEvent *event) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1, 2) G_GNUC_MALLOC; +#elif _VTE_GTK == 4 + +_VTE_PUBLIC +char* vte_terminal_hyperlink_check_at(VteTerminal* terminal, + double x, + double y) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1) G_GNUC_MALLOC; + #endif /* _VTE_GTK */ /* Add a matching expression, returning the tag the widget assigns to that @@ -469,6 +476,32 @@ gboolean vte_terminal_event_check_regex_simple(VteTerminal *terminal, guint32 match_flags, char **matches) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1, 2); +#elif _VTE_GTK == 4 + +_VTE_PUBLIC +char* vte_terminal_match_check_at(VteTerminal* terminal, + double x, + double y, + int* tag) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1) G_GNUC_MALLOC; + +_VTE_PUBLIC +char** vte_terminal_regex_array_check_at(VteTerminal* terminal, + double x, + double y, + VteRegex** regexes, + gsize n_regexes, + guint32 match_flags, + gsize* n_matches) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1) G_GNUC_MALLOC; + +_VTE_PUBLIC +gboolean vte_terminal_regex_simple_check_at(VteTerminal* terminal, + double x, + double y, + VteRegex** regexes, + gsize n_regexes, + guint32 match_flags, + char** matches) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1); + #endif /* _VTE_GTK */ _VTE_PUBLIC diff --git a/src/vtegtk.cc b/src/vtegtk.cc index f12ee256..8a50360e 100644 --- a/src/vtegtk.cc +++ b/src/vtegtk.cc @@ -3137,6 +3137,189 @@ catch (...) return false; } +#elif VTE_GTK == 4 + +/** + * vte_terminal_match_check_at: + * @terminal: a #VteTerminal + * @x: + * @y: + * @tag: (out) (allow-none): a location to store the tag, or %NULL + * + * Checks if the text in and around the position (x, y) matches any of the + * regular expressions previously set using vte_terminal_match_add(). If a + * match exists, the text string is returned and if @tag is not %NULL, the number + * associated with the matched regular expression will be stored in @tag. + * + * If more than one regular expression has been set with + * vte_terminal_match_add(), then expressions are checked in the order in + * which they were added. + * + * Returns: (transfer full) (nullable): a newly allocated string which matches one of the previously + * set regular expressions, or %NULL if there is no match + * + * Since: 0.70 + */ +char* +vte_terminal_match_check_at(VteTerminal* terminal, + double x, + double y, + int* tag) noexcept +try +{ + g_return_val_if_fail(VTE_IS_TERMINAL(terminal), FALSE); + return WIDGET(terminal)->regex_match_check_at(x, y, tag); +} +catch (...) +{ + vte::log_exception(); + return nullptr; +} + +/** + * vte_terminal_hyperlink_check_at: + * @terminal: a #VteTerminal + * @x: + * @y: + * + * Returns a nonempty string: the target of the explicit hyperlink (printed using the OSC 8 + * escape sequence) at the position (x, y), or %NULL. + * + * Proper use of the escape sequence should result in URI-encoded URIs with a proper scheme + * like "http://", "https://", "file://", "mailto:" etc. This is, however, not enforced by VTE. + * The caller must tolerate the returned string potentially not being a valid URI. + * + * Returns: (transfer full) (nullable): a newly allocated string containing the target of the hyperlink, + * or %NULL + * + * Since: 0.70 + */ +char* +vte_terminal_hyperlink_check_at(VteTerminal* terminal, + double x, + double y) noexcept +try +{ + g_return_val_if_fail(VTE_IS_TERMINAL(terminal), nullptr); + return WIDGET(terminal)->hyperlink_check_at(x, y); +} +catch (...) +{ + vte::log_exception(); + return nullptr; +} + +/** + * vte_terminal_regex_array_check_at: (rename-to vte_terminal_check_regex_simple_at) + * @terminal: a #VteTerminal + * @x: + * @y: + * @regexes: (array length=n_regexes): an array of #VteRegex + * @n_regexes: number of items in @regexes + * @match_flags: PCRE2 match flags, or 0 + * @n_matches: (out) (optional): number of items in @matches, which is always equal to @n_regexes + * + * Like vte_terminal_check_regex_simple_at(), but returns an array of strings, + * containing the matching text (or %NULL if no match) corresponding to each of the + * regexes in @regexes. + * + * You must free each string and the array; but note that this is *not* a %NULL-terminated + * string array, and so you must *not* use g_strfreev() on it. + * + * Returns: (nullable) (transfer full) (array length=n_matches): a newly allocated array of strings, + * or %NULL if none of the regexes matched + * + * Since: 0.70 + */ +char** +vte_terminal_regex_array_check_at(VteTerminal* terminal, + double x, + double y, + VteRegex** regexes, + gsize n_regexes, + guint32 match_flags, + gsize* n_matches) noexcept +try +{ + if (n_matches) + *n_matches = n_regexes; + + if (n_regexes == 0) + return nullptr; + + auto matches = vte::glib::take_free_ptr(g_new0(char*, n_regexes)); + if (!vte_terminal_regex_simple_check_at(terminal, + x, y, + regexes, + n_regexes, + match_flags, + matches.get())) + return nullptr; + + return matches.release(); +} +catch (...) +{ + vte::log_exception(); + return nullptr; +} + +/** + * vte_terminal_regex_simple_check_at: (skip) + * @terminal: a #VteTerminal + * @x: + * @y: + * @regexes: (array length=n_regexes): an array of #VteRegex + * @n_regexes: number of items in @regexes + * @match_flags: PCRE2 match flags, or 0 + * @matches: (out caller-allocates) (array length=n_regexes) (transfer full): a location to store the matches + * + * Checks each regex in @regexes if the text in and around the position (x, y) + * matches the regular expressions. If a match exists, the matched + * text is stored in @matches at the position of the regex in @regexes; otherwise + * %NULL is stored there. Each non-%NULL element of @matches should be freed with + * g_free(). + * + * Note that the regexes in @regexes should have been created using the %PCRE2_MULTILINE flag. + * + * Returns: %TRUE iff any of the regexes produced a match + * + * Since: 0.70 + */ +gboolean +vte_terminal_regex_simple_check_at(VteTerminal* terminal, + double x, + double y, + VteRegex** regexes, + gsize n_regexes, + guint32 match_flags, + char** matches) noexcept +try +{ + g_return_val_if_fail(VTE_IS_TERMINAL(terminal), FALSE); + g_return_val_if_fail(regexes != NULL || n_regexes == 0, FALSE); + for (gsize i = 0; i < n_regexes; i++) { + g_return_val_if_fail(_vte_regex_has_purpose(regexes[i], vte::base::Regex::Purpose::eMatch), -1); + g_warn_if_fail(_vte_regex_has_multiline_compile_flag(regexes[i])); + } + g_return_val_if_fail(matches != NULL, FALSE); + + return WIDGET(terminal)->regex_match_check_extra_at(x, y, + regex_array_from_wrappers(regexes), + n_regexes, + match_flags, + matches); +} +catch (...) +{ + vte::log_exception(); + return false; +} + +#endif /* VTE_GTK */ + +#if VTE_GTK == 3 + /** * vte_terminal_event_check_gregex_simple: * @terminal: a #VteTerminal diff --git a/src/vteinternal.hh b/src/vteinternal.hh index 5037096d..fbe696b1 100644 --- a/src/vteinternal.hh +++ b/src/vteinternal.hh @@ -1244,8 +1244,6 @@ public: #endif char *hyperlink_check(vte::platform::MouseEvent const& event); - char *hyperlink_check_at(double x, - double y); char *hyperlink_check(vte::grid::column_t column, vte::grid::row_t row); @@ -1254,12 +1252,6 @@ public: size_t n_regexes, uint32_t match_flags, char** matches); - bool regex_match_check_extra_at(double x, - double y, - vte::base::Regex const** regexes, - size_t n_regexes, - uint32_t match_flags, - char** matches); bool regex_match_check_extra(vte::grid::column_t column, vte::grid::row_t row, vte::base::Regex const** regexes, @@ -1272,9 +1264,21 @@ public: int *tag); char *regex_match_check(vte::platform::MouseEvent const& event, int *tag); + +#if VTE_GTK == 4 + char *hyperlink_check_at(double x, + double y); + bool regex_match_check_extra_at(double x, + double y, + vte::base::Regex const** regexes, + size_t n_regexes, + uint32_t match_flags, + char** matches); char *regex_match_check_at(double x, double y, int *tag); +#endif /* VTE_GTK == 4 */ + void regex_match_remove(int tag) noexcept; void regex_match_remove_all() noexcept; void regex_match_set_cursor(int tag, diff --git a/src/widget.hh b/src/widget.hh index 5e6b1bdc..308edb57 100644 --- a/src/widget.hh +++ b/src/widget.hh @@ -469,6 +469,33 @@ public: return terminal()->hyperlink_check(mouse_event_from_gdk(event)); } +#elif VTE_GTK == 4 + + char* regex_match_check_at(double x, + double y, + int* tag) + { + return terminal()->regex_match_check(x, y, tag); + } + + bool regex_match_check_extra_at(double x, + double y, + vte::base::Regex const** regexes, + size_t n_regexes, + uint32_t match_flags, + char** matches) + { + return terminal()->regex_match_check_extra_at(x, y, + regexes, n_regexes, + match_flags, matches); + } + + char* hyperlink_check_at(double x, + double y) + { + return terminal()->hyperlink_check_at(x, y); + } + #endif /* VTE_GTK */ bool should_emit_signal(int id) noexcept; -- cgit v1.2.1