[vte/wip/gtk4: 5/5] all: Initial port for gtk4
- From: Christian Persch <chpe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vte/wip/gtk4: 5/5] all: Initial port for gtk4
- Date: Mon, 4 Jan 2021 17:22:13 +0000 (UTC)
commit 5a65d2dc400893a7c030c37136960693187f938c
Author: Christian Persch <chpe src gnome org>
Date: Mon Jan 4 18:21:50 2021 +0100
all: Initial port for gtk4
Add meson changes to build a gtk4 variant of libvte, plus
a gtk4 variant of the test application.
Make the minimal code changes required to successfully build
and run on gtk4.
No event handlers yet, and no public API to replace the gtk3
specific APIs. That will come later.
This should be good enough to get non-terminal users of libvte
started on porting to gtk4.
terminal consumers of libvte
https://gitlab.gnome.org/GNOME/vte/-/issues/12
doc/reference/meson.build | 46 ++-
doc/reference/vte-sections.txt | 4 +
meson.build | 20 +-
po/POTFILES.skip | 6 +-
src/app/app-gtk4.gresource.xml | 24 ++
src/app/app.cc | 632 ++++++++++++++++++++++++++++++++++-------
src/app/appmenu-gtk4.ui | 33 +++
src/app/meson.build | 31 +-
src/app/search-popover-gtk3.ui | 1 -
src/app/search-popover-gtk4.ui | 169 +++++++++++
src/app/window-gtk3.ui | 1 -
src/app/window-gtk4.ui | 185 ++++++++++++
src/cairo-glue.hh | 4 +-
src/clipboard-gtk.cc | 39 ++-
src/clipboard-gtk.hh | 4 +
src/debug.h | 6 +
src/fonts-pangocairo.cc | 58 ++--
src/fonts-pangocairo.hh | 6 +-
src/graphene-glue.hh | 48 ++++
src/gtk-glue.hh | 6 +
src/keymap.h | 5 +
src/meson.build | 104 +++++--
src/vte.cc | 359 +++++++++++++++--------
src/vte/meson.build | 107 +++++--
src/vte/vte.h | 4 +
src/vte/vtedeprecated.h | 10 +
src/vte/vtemacros.h | 12 +
src/vte/vteterminal.h | 11 +
src/vte/vtetypebuiltins.h | 28 ++
src/vteaccess.h | 6 +-
src/vtedefines.hh | 3 +
src/vtegtk.cc | 398 ++++++++++++++++++++++----
src/vteinternal.hh | 65 ++++-
src/vteseq.cc | 5 +
src/widget.cc | 557 ++++++++++++++++++++++++++++++++----
src/widget.hh | 111 ++++++--
36 files changed, 2631 insertions(+), 477 deletions(-)
---
diff --git a/doc/reference/meson.build b/doc/reference/meson.build
index 5af8fa3d..6553ea48 100644
--- a/doc/reference/meson.build
+++ b/doc/reference/meson.build
@@ -63,6 +63,15 @@ scan_args = [
glib_prefix = glib_dep.get_pkgconfig_variable('prefix')
+gdk_pixbuf_dep = dependency('gdk-pixbuf-2.0')
+gdk_pixbuf_prefix = gdk_pixbuf_dep.get_pkgconfig_variable('prefix')
+
+fixxref_args = [
+ '--extra-dir=' + (glib_prefix / gnome.gtkdoc_html_dir('glib')),
+ '--extra-dir=' + (glib_prefix / gnome.gtkdoc_html_dir('gio')),
+ '--extra-dir=' + (gdk_pixbuf_prefix / gnome.gtkdoc_html_dir('gdk-pixbuf')),
+]
+
version_conf = configuration_data()
version_conf.set('VERSION', vte_version)
@@ -75,28 +84,25 @@ content_files = configure_file(
if get_option('gtk3')
gtk3_prefix = gtk3_dep.get_pkgconfig_variable('prefix')
- fixxref_args = [
+ fixxref_args_gtk3 = fixxref_args + [
'--html-dir=' + (vte_prefix / gnome.gtkdoc_html_dir(vte_gtk3_api_name)),
- '--extra-dir=' + (glib_prefix / gnome.gtkdoc_html_dir('glib')),
- '--extra-dir=' + (glib_prefix / gnome.gtkdoc_html_dir('gio')),
'--extra-dir=' + (gtk3_prefix / gnome.gtkdoc_html_dir('gdk')),
- '--extra-dir=' + (gtk3_prefix / gnome.gtkdoc_html_dir('gdk-pixbuf')),
'--extra-dir=' + (gtk3_prefix / gnome.gtkdoc_html_dir('gtk')),
]
gnome.gtkdoc(
- 'vte',
+ 'vte-gtk3',
main_xml: 'vte-docs.xml',
module_version: vte_api_version,
src_dir: [src_inc, vte_inc],
ignore_headers: private_headers,
include_directories: top_inc,
dependencies: libvte_gtk3_dep,
- c_args: '-DVTE_COMPILATION',
+ c_args: ['-DVTE_COMPILATION',],
namespace: 'vte',
scan_args: scan_args,
mkdb_args: '--source-suffixes=h,hh,c,cc',
- fixxref_args: fixxref_args,
+ fixxref_args: fixxref_args_gtk3,
gobject_typesfile: 'vte.types',
content_files: content_files,
install: true,
@@ -104,5 +110,29 @@ if get_option('gtk3')
endif
if get_option('gtk4')
- assert(false, 'not yet supported')
+ gtk4_prefix = gtk4_dep.get_pkgconfig_variable('prefix')
+
+ fixxref_args_gtk4 = fixxref_args + [
+ '--html-dir=' + (vte_prefix / gnome.gtkdoc_html_dir(vte_gtk4_api_name)),
+ '--extra-dir=' + (gtk4_prefix / gnome.gtkdoc_html_dir('gdk')),
+ '--extra-dir=' + (gtk4_prefix / gnome.gtkdoc_html_dir('gtk')),
+ ]
+
+ gnome.gtkdoc(
+ 'vte-gtk4',
+ main_xml: 'vte-docs.xml',
+ module_version: vte_api_version,
+ src_dir: [src_inc, vte_inc,],
+ ignore_headers: private_headers,
+ include_directories: top_inc,
+ dependencies: libvte_gtk4_dep,
+ c_args: ['-DVTE_COMPILATION',],
+ namespace: 'vte',
+ scan_args: scan_args,
+ mkdb_args: '--source-suffixes=h,hh,c,cc',
+ fixxref_args: fixxref_args_gtk4,
+ gobject_typesfile: 'vte.types',
+ content_files: content_files,
+ install: true,
+ )
endif
diff --git a/doc/reference/vte-sections.txt b/doc/reference/vte-sections.txt
index c69181da..14968fc9 100644
--- a/doc/reference/vte-sections.txt
+++ b/doc/reference/vte-sections.txt
@@ -72,11 +72,13 @@ vte_terminal_get_text
vte_terminal_get_text_range
vte_terminal_get_cursor_position
vte_terminal_hyperlink_check_event
+vte_terminal_hyperlink_check_at
vte_terminal_match_add_regex
vte_terminal_match_remove
vte_terminal_match_remove_all
vte_terminal_match_check
vte_terminal_match_check_event
+vte_terminal_match_check_at
vte_terminal_match_set_cursor_name
vte_terminal_set_cjk_ambiguous_width
vte_terminal_get_cjk_ambiguous_width
@@ -94,7 +96,9 @@ vte_terminal_search_get_wrap_around
vte_terminal_search_set_regex
vte_terminal_search_set_wrap_around
vte_terminal_event_check_regex_array
+vte_terminal_regex_array_check_at
vte_terminal_event_check_regex_simple
+vte_terminal_regex_simple_check_at
<SUBSECTION>
VteFeatureFlags
diff --git a/meson.build b/meson.build
index ce52cb8d..68aac6ab 100644
--- a/meson.build
+++ b/meson.build
@@ -34,7 +34,10 @@ project(
gtk3_req_version = '3.20.0'
gtk3_min_req_version = '3.18'
gtk3_max_allowed_version = '3.20'
+
gtk4_req_version = '4.0.0'
+gtk4_min_req_version = '4.0'
+gtk4_max_allowed_version = '4.0'
fribidi_req_version = '1.0.0'
gio_req_version = '2.52.0'
@@ -55,10 +58,10 @@ vte_api_version = '@0@.@1@'.format(vte_api_major_version, vte_api_minor_version)
vte_api_name = 'vte-@0@.@1@'.format(vte_api_major_version, vte_api_minor_version)
vte_gtk3_api_version = '@0@.@1@'.format(vte_api_major_version, vte_api_minor_version)
-vte_gtk4_api_version = '@0@.@1@'.format(vte_api_major_version + 1, vte_api_minor_version)
+vte_gtk4_api_version = '@0@.@1@'.format(vte_api_major_version, vte_api_minor_version)
vte_gtk3_api_name = 'vte-' + vte_gtk3_api_version
-vte_gtk4_api_name = 'vte-' + vte_gtk4_api_version
+vte_gtk4_api_name = 'vte-' + vte_gtk4_api_version + '-gtk4'
vte_gtk3_api_path = vte_gtk3_api_name / 'vte'
vte_gtk4_api_path = vte_gtk4_api_name / 'vte'
@@ -141,6 +144,17 @@ if get_option('gtk3')
gtk3_version_cppflags += '-DGDK_VERSION_MAX_ALLOWED=(G_ENCODE_VERSION(' + ver[0] + ',' + ver[1] + '))'
endif
+if get_option('gtk4')
+ gtk4_version_cppflags = []
+
+ ver = gtk4_min_req_version.split('.')
+ gtk4_version_cppflags += '-DGDK_VERSION_MIN_REQUIRED=(G_ENCODE_VERSION(' + ver[0] + ',' + ver[1] + '))'
+
+ ver = gtk4_max_allowed_version.split('.')
+ gtk4_version_cppflags += '-DGDK_VERSION_MAX_ALLOWED=(G_ENCODE_VERSION(' + ver[0] + ',' + ver[1] + '))'
+endif
+
+
# FIXME AC_USE_SYSTEM_EXTENSIONS also supported non-gnu systems
config_h.set10('_GNU_SOURCE', true)
@@ -427,7 +441,7 @@ else
endif
if get_option('gtk4')
- gtk4_dep = dependency('gtk+-4.0', version: '>=' + gtk4_req_version)
+ gtk4_dep = dependency('gtk4', version: '>=' + gtk4_req_version)
else
gtk4_dep = dependency('', required: false)
endif
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index fffa7710..13d510de 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -3,8 +3,8 @@ bindings/vala/search-popover.ui
src/vtespawn.cc
src/app/app.cc
src/app/appmenu-gtk3.ui
-src/app/appmenu.ui
+src/app/appmenu-gtk4.ui
src/app/search-popover-gtk3.ui
-src/app/search-popover.ui
+src/app/search-popover-gtk4.ui
src/app/window-gtk3.ui
-src/app/window.ui
+src/app/window-gtk4.ui
diff --git a/src/app/app-gtk4.gresource.xml b/src/app/app-gtk4.gresource.xml
new file mode 100644
index 00000000..dbf43e8b
--- /dev/null
+++ b/src/app/app-gtk4.gresource.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright © 2014, 2020 Christian Persch
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope conf it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+<gresources>
+ <gresource prefix="/org/gnome/vte/app">
+ <file alias="ui/search-popover.ui" compressed="true"
preprocess="xml-stripblanks">search-popover-gtk4.ui</file>
+ <file alias="ui/window.ui" compressed="true" preprocess="xml-stripblanks">window-gtk4.ui</file>
+ <file alias="gtk/menus.ui" compressed="true" preprocess="xml-stripblanks">appmenu-gtk4.ui</file>
+ </gresource>
+</gresources>
diff --git a/src/app/app.cc b/src/app/app.cc
index 23a297bc..91fa9b64 100644
--- a/src/app/app.cc
+++ b/src/app/app.cc
@@ -38,6 +38,7 @@
#include <vector>
#include "std-glue.hh"
+#include "cairo-glue.hh"
#include "glib-glue.hh"
#include "libc-glue.hh"
#include "pango-glue.hh"
@@ -61,13 +62,11 @@ public:
gboolean feed_stdin{false};
gboolean icon_title{false};
gboolean keep{false};
- gboolean no_argb_visual{false};
gboolean no_bidi{false};
gboolean no_bold{false};
gboolean no_builtin_dingus{false};
gboolean no_context_menu{false};
gboolean no_decorations{false};
- gboolean no_double_buffer{false};
gboolean no_fallback_scrolling{false};
gboolean no_geometry_hints{false};
gboolean no_hyperlink{false};
@@ -121,6 +120,11 @@ public:
VteTextBlinkMode text_blink_mode{VTE_TEXT_BLINK_ALWAYS};
vte::glib::RefPtr<GtkCssProvider> css{};
+#if VTE_GTK == 3
+ gboolean no_argb_visual{false};
+ gboolean no_double_buffer{false};
+#endif /* VTE_GTK == 3 */
+
~Options() {
g_clear_object(&background_pixbuf);
g_free(command);
@@ -371,8 +375,12 @@ private:
Options* that = static_cast<Options*>(data);
auto css = vte::glib::take_ref(gtk_css_provider_new());
+#if VTE_GTK == 3
if (!gtk_css_provider_load_from_path(css.get(), value, error))
return false;
+#elif VTE_GTK == 4
+ gtk_css_provider_load_from_path(css.get(), value);
+#endif /* VTE_GKT */
that->css = std::move(css);
return true;
@@ -550,8 +558,6 @@ public:
"Enable the setting of the icon title", nullptr },
{ "keep", 'k', 0, G_OPTION_ARG_NONE, &keep,
"Live on after the command exits", nullptr },
- { "no-argb-visual", 0, 0, G_OPTION_ARG_NONE, &no_argb_visual,
- "Don't use an ARGB visual", nullptr },
{ "no-bidi", 0, 0, G_OPTION_ARG_NONE, &no_bidi,
"Disable BiDi", nullptr },
{ "no-bold", 0, 0, G_OPTION_ARG_NONE, &no_bold,
@@ -562,8 +568,6 @@ public:
"Disable context menu", nullptr },
{ "no-decorations", 0, 0, G_OPTION_ARG_NONE, &no_decorations,
"Disable window decorations", nullptr },
- { "no-double-buffer", '2', 0, G_OPTION_ARG_NONE, &no_double_buffer,
- "Disable double-buffering", nullptr },
{ "no-fallback-scrolling", 0, 0, G_OPTION_ARG_NONE, &no_fallback_scrolling,
"Disable fallback scrolling", nullptr },
{ "no-geometry-hints", 'G', 0, G_OPTION_ARG_NONE, &no_geometry_hints,
@@ -617,8 +621,6 @@ public:
nullptr, nullptr },
{ "console", 'C', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &console,
nullptr, nullptr },
- { "double-buffer", '2', G_OPTION_FLAG_REVERSE | G_OPTION_FLAG_HIDDEN,
- G_OPTION_ARG_NONE, &no_double_buffer, nullptr, nullptr },
{ "pty-flags", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &dummy_string,
nullptr, nullptr },
{ "scrollbar-policy", 'P', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING,
@@ -633,6 +635,15 @@ public:
#endif
{ "use-theme-colors", 0, 0, G_OPTION_ARG_NONE, &use_theme_colors,
"Use foreground and background colors from the gtk+ theme", nullptr },
+
+#if VTE_GTK == 3
+ { "no-argb-visual", 0, 0, G_OPTION_ARG_NONE, &no_argb_visual,
+ "Don't use an ARGB visual", nullptr },
+ { "double-buffer", '2', G_OPTION_FLAG_REVERSE | G_OPTION_FLAG_HIDDEN,
+ G_OPTION_ARG_NONE, &no_double_buffer, nullptr, nullptr },
+ { "no-double-buffer", '2', 0, G_OPTION_ARG_NONE, &no_double_buffer,
+ "Disable double-buffering", nullptr },
+#endif /* VTE_GTK == 3 */
{ nullptr }
};
@@ -666,7 +677,9 @@ public:
g_option_group_add_entries(group, entries);
g_option_context_set_main_group(context.get(), group);
+#if VTE_GTK == 3
g_option_context_add_group(context.get(), gtk_get_option_group(true));
+#endif
bool rv = g_option_context_parse(context.get(), &argc, &argv, error);
@@ -677,6 +690,14 @@ public:
swap(fg_color, bg_color);
}
+#if VTE_GTK == 4
+ if (rv && !gtk_init_check()) {
+ g_set_error_literal(error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
+ "Failed to initialise gtk+");
+ rv = false;
+ }
+#endif /* VTE_GTK == 4 */
+
return rv;
}
};
@@ -808,7 +829,11 @@ vteapp_search_popover_update_sensitivity(VteappSearchPopover* popover)
static void
vteapp_search_popover_update_regex(VteappSearchPopover* popover)
{
- char const* search_text = gtk_entry_get_text(GTK_ENTRY(popover->search_entry));
+#if VTE_GTK == 3
+ auto search_text = gtk_entry_get_text(GTK_ENTRY(popover->search_entry));
+#elif VTE_GTK == 4
+ auto search_text = gtk_editable_get_text(GTK_EDITABLE(popover->search_entry));
+#endif /* VTE_GTK */
bool caseless = gtk_toggle_button_get_active(popover->match_case_checkbutton) == FALSE;
char* pattern;
@@ -971,10 +996,18 @@ static GtkWidget*
vteapp_search_popover_new(VteTerminal* terminal,
GtkWidget* relative_to)
{
- return reinterpret_cast<GtkWidget*>(g_object_new(VTEAPP_TYPE_SEARCH_POPOVER,
- "terminal", terminal,
- "relative-to", relative_to,
- nullptr));
+ auto popover = reinterpret_cast<GtkWidget*>(g_object_new(VTEAPP_TYPE_SEARCH_POPOVER,
+ "terminal", terminal,
+#if VTE_GTK == 3
+ "relative-to", relative_to,
+#endif
+ nullptr));
+
+#if VTE_GTK == 4
+ gtk_widget_set_parent(popover, relative_to);
+#endif
+
+ return popover;
}
/* terminal */
@@ -992,7 +1025,11 @@ typedef struct _VteappTerminalClass VteappTerminalClass;
struct _VteappTerminal {
VteTerminal parent;
+ //#if VTE_GTK == 3
cairo_pattern_t* background_pattern;
+ //#elif VTE_GTK == 4
+ // GdkTexture* background_texture;
+ //#endif
bool has_backdrop;
bool use_backdrop;
};
@@ -1012,35 +1049,57 @@ vteapp_terminal_realize(GtkWidget* widget)
{
GTK_WIDGET_CLASS(vteapp_terminal_parent_class)->realize(widget);
- VteappTerminal* terminal = VTEAPP_TERMINAL(widget);
- if (options.background_pixbuf != nullptr) {
- auto surface = gdk_cairo_surface_create_from_pixbuf(options.background_pixbuf,
- 0 /* take scale from window */,
- gtk_widget_get_window(widget));
- terminal->background_pattern = cairo_pattern_create_for_surface(surface);
- cairo_surface_destroy(surface);
+ if (!options.background_pixbuf)
+ return;
- cairo_pattern_set_extend(terminal->background_pattern, options.background_extend);
- }
+ auto terminal = VTEAPP_TERMINAL(widget);
+
+#if VTE_GTK == 3
+ auto surface = vte::take_freeable
+ (gdk_cairo_surface_create_from_pixbuf(options.background_pixbuf,
+ 0 /* take scale from window */,
+ gtk_widget_get_window(widget)));
+#elif VTE_GTK == 4
+ auto const width = gdk_pixbuf_get_width(options.background_pixbuf);
+ auto const height = gdk_pixbuf_get_height(options.background_pixbuf);
+ auto surface = vte::take_freeable(cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ width, height));
+ auto cr = vte::take_freeable(cairo_create(surface.get()));
+ gdk_cairo_set_source_pixbuf(cr.get(), options.background_pixbuf, 0, 0);
+ cairo_paint(cr.get());
+ cairo_surface_flush(surface.get()); // FIXME necessary?
+#endif
+ terminal->background_pattern = cairo_pattern_create_for_surface(surface.get());
+
+ cairo_pattern_set_extend(terminal->background_pattern, options.background_extend);
+
+
+ //#elif VTE_GTK == 4
+ // terminal->background_texture = gdk_texture_new_for_pixbuf(options.background_pixbuf);
+ //#endif /* VTE_GTK */
}
static void
vteapp_terminal_unrealize(GtkWidget* widget)
{
- VteappTerminal* terminal = VTEAPP_TERMINAL(widget);
+#if VTE_GTK == 3
+ auto terminal = VTEAPP_TERMINAL(widget);
+
if (terminal->background_pattern != nullptr) {
cairo_pattern_destroy(terminal->background_pattern);
terminal->background_pattern = nullptr;
}
+#endif /* VTE_GTK */
GTK_WIDGET_CLASS(vteapp_terminal_parent_class)->unrealize(widget);
}
-static gboolean
-vteapp_terminal_draw(GtkWidget* widget,
- cairo_t* cr)
+static void
+vteapp_terminal_draw_background(GtkWidget* widget,
+ cairo_t* cr)
{
- VteappTerminal* terminal = VTEAPP_TERMINAL(widget);
+ auto terminal = VTEAPP_TERMINAL(widget);
+
if (terminal->background_pattern != nullptr) {
cairo_push_group(cr);
@@ -1063,8 +1122,28 @@ vteapp_terminal_draw(GtkWidget* widget,
cairo_paint_with_alpha(cr, options.get_alpha_bg_for_draw());
}
+}
+
+#if VTE_GTK == 4
- auto rv = GTK_WIDGET_CLASS(vteapp_terminal_parent_class)->draw(widget, cr);
+static void
+vteapp_terminal_draw_background(GtkWidget* widget,
+ GtkSnapshot* snapshot)
+{
+ auto grect = GRAPHENE_RECT_INIT(float(0), float(0),
+ float(gtk_widget_get_allocated_width(widget)),
+ float(gtk_widget_get_allocated_height(widget)));
+ auto cr = vte::take_freeable(gtk_snapshot_append_cairo(snapshot, &grect));
+ vteapp_terminal_draw_background(widget, cr.get());
+}
+
+#endif /* VTE_GTK == 4 */
+
+static void
+vteapp_terminal_draw_backdrop(GtkWidget* widget,
+ cairo_t* cr)
+{
+ auto terminal = VTEAPP_TERMINAL(widget);
if (terminal->use_backdrop && terminal->has_backdrop) {
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
@@ -1074,49 +1153,162 @@ vteapp_terminal_draw(GtkWidget* widget,
gtk_widget_get_allocated_height(widget));
cairo_paint(cr);
}
+}
+
+#if VTE_GTK == 4
+
+static void
+vteapp_terminal_draw_backdrop(GtkWidget* widget,
+ GtkSnapshot* snapshot)
+{
+ auto grect = GRAPHENE_RECT_INIT(float(0), float(0),
+ float(gtk_widget_get_allocated_width(widget)),
+ float(gtk_widget_get_allocated_height(widget)));
+ auto cr = vte::take_freeable(gtk_snapshot_append_cairo(snapshot, &grect));
+ vteapp_terminal_draw_backdrop(widget, cr.get());
+}
+
+#endif /* VTE_GTK == 4 */
+
+#if VTE_GTK == 3
+
+static gboolean
+vteapp_terminal_draw(GtkWidget* widget,
+ cairo_t* cr)
+{
+ vteapp_terminal_draw_background(widget, cr);
+
+ auto const rv = GTK_WIDGET_CLASS(vteapp_terminal_parent_class)->draw(widget, cr);
+
+ vteapp_terminal_draw_backdrop(widget, cr);
return rv;
}
-static auto dti(double d) -> unsigned { return CLAMP((d*255), 0, 255); }
+#endif /* VTE_GTK == 3 */
+
+static void
+vteapp_terminal_update_theme_colors(GtkWidget* widget)
+{
+ if (!options.use_theme_colors)
+ return;
+
+ auto terminal = VTEAPP_TERMINAL(widget);
+ auto context = gtk_widget_get_style_context(widget);
+
+#if VTE_GTK == 3
+ auto const flags = gtk_style_context_get_state(context);
+#endif
+
+ auto theme_fg = GdkRGBA{};
+ gtk_style_context_get_color(context,
+#if VTE_GTK == 3
+ flags,
+#endif
+ &theme_fg);
+
+ auto theme_bg = GdkRGBA{};
+#if VTE_GTK == 3
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+ gtk_style_context_get_background_color(context, flags, &theme_bg);
+ G_GNUC_END_IGNORE_DEPRECATIONS;
+#elif VTE_GTK == 4
+ // FIXMEgtk4 "background-color" lookup always fails
+ if (!gtk_style_context_lookup_color(context, "text_view_bg", &theme_bg)) {
+ verbose_print("Failed to get theme background color\n");
+ return;
+ }
+#endif
+
+ auto dti = [](double d) -> unsigned { return std::clamp(unsigned(d*255), 0u, 255u); };
+
+ verbose_print("Theme colors: foreground is #%02X%02X%02X, background is #%02X%02X%02X\n",
+ dti(theme_fg.red), dti(theme_fg.green), dti(theme_fg.blue),
+ dti(theme_bg.red), dti(theme_bg.green), dti(theme_bg.blue));
+
+ theme_fg.alpha = 1.;
+ theme_bg.alpha = options.get_alpha_bg();
+ vte_terminal_set_colors(VTE_TERMINAL(terminal), &theme_fg, &theme_bg, nullptr, 0);
+}
+
+#if VTE_GTK == 3
static void
vteapp_terminal_style_updated(GtkWidget* widget)
{
GTK_WIDGET_CLASS(vteapp_terminal_parent_class)->style_updated(widget);
- auto context = gtk_widget_get_style_context(widget);
- auto flags = gtk_style_context_get_state(context);
+ auto terminal = VTEAPP_TERMINAL(widget);
- VteappTerminal* terminal = VTEAPP_TERMINAL(widget);
+ auto context = gtk_widget_get_style_context(widget);
+ auto const flags = gtk_style_context_get_state(context);
terminal->has_backdrop = (flags & GTK_STATE_FLAG_BACKDROP) != 0;
- if (options.use_theme_colors) {
- auto theme_fg = GdkRGBA{};
- gtk_style_context_get_color(context, flags, &theme_fg);
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
- auto theme_bg = GdkRGBA{};
- gtk_style_context_get_background_color(context, flags, &theme_bg);
- G_GNUC_END_IGNORE_DEPRECATIONS;
+ vteapp_terminal_update_theme_colors(widget);
+}
- verbose_print("Theme colors: foreground is #%02X%02X%02X, background is #%02X%02X%02X\n",
- dti(theme_fg.red), dti(theme_fg.green), dti(theme_fg.blue),
- dti(theme_bg.red), dti(theme_bg.green), dti(theme_bg.blue));
+#endif /* VTE_GTK == 3 */
- theme_fg.alpha = 1.;
- theme_bg.alpha = options.get_alpha_bg();
- vte_terminal_set_colors(VTE_TERMINAL(terminal), &theme_fg, &theme_bg, nullptr, 0);
- }
+#if VTE_GTK == 4
+
+static void
+vteapp_terminal_snapshot(GtkWidget* widget,
+ GtkSnapshot* snapshot_object)
+{
+ vteapp_terminal_draw_background(widget, snapshot_object);
+
+ GTK_WIDGET_CLASS(vteapp_terminal_parent_class)->snapshot(widget, snapshot_object);
+
+ vteapp_terminal_draw_backdrop(widget, snapshot_object);
}
+static void
+vteapp_terminal_css_changed(GtkWidget* widget,
+ GtkCssStyleChange* change)
+{
+ GTK_WIDGET_CLASS(vteapp_terminal_parent_class)->css_changed(widget, change);
+
+ vteapp_terminal_update_theme_colors(widget);
+}
+
+static void
+vteapp_terminal_state_flags_changed(GtkWidget* widget,
+ GtkStateFlags old_flags)
+{
+ GTK_WIDGET_CLASS(vteapp_terminal_parent_class)->state_flags_changed(widget, old_flags);
+
+ auto terminal = VTEAPP_TERMINAL(widget);
+ auto const flags = gtk_widget_get_state_flags(widget);
+ terminal->has_backdrop = (flags & GTK_STATE_FLAG_BACKDROP) != 0;
+}
+
+static void
+vteapp_terminal_system_setting_changed(GtkWidget* widget,
+ GtkSystemSetting setting)
+{
+ GTK_WIDGET_CLASS(vteapp_terminal_parent_class)->system_setting_changed(widget, setting);
+
+ // FIXMEgtk4 find a way to update colours on theme change like gtk3 above
+}
+
+#endif /* VTE_GTK == 4 */
+
static void
vteapp_terminal_class_init(VteappTerminalClass *klass)
{
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+ auto widget_class = GTK_WIDGET_CLASS(klass);
widget_class->realize = vteapp_terminal_realize;
widget_class->unrealize = vteapp_terminal_unrealize;
+
+#if VTE_GTK == 3
widget_class->draw = vteapp_terminal_draw;
widget_class->style_updated = vteapp_terminal_style_updated;
+#elif VTE_GTK == 4
+ widget_class->snapshot = vteapp_terminal_snapshot;
+ widget_class->css_changed = vteapp_terminal_css_changed;
+ widget_class->state_flags_changed = vteapp_terminal_state_flags_changed;
+ widget_class->system_setting_changed = vteapp_terminal_system_setting_changed;
+#endif
gtk_widget_class_set_css_name(widget_class, "vteapp-terminal");
}
@@ -1165,12 +1357,9 @@ struct _VteappWindow {
/* end */
VteTerminal* terminal;
- GtkClipboard* clipboard;
GPid child_pid;
GtkWidget* search_popover;
- bool fullscreen{false};
-
/* used for updating the geometry hints */
int cached_cell_width{0};
int cached_cell_height{0};
@@ -1178,6 +1367,15 @@ struct _VteappWindow {
int cached_chrome_height{0};
int cached_csd_width{0};
int cached_csd_height{0};
+
+#if VTE_GTK == 3
+ GtkClipboard* clipboard;
+ GdkWindowState window_state{GdkWindowState(0)};
+#endif
+#if VTE_GTK == 4
+ GdkClipboard* clipboard;
+ GdkToplevelState toplevel_state{GdkToplevelState(0)};
+#endif
};
struct _VteappWindowClass {
@@ -1221,6 +1419,7 @@ vteapp_window_add_dingus(VteappWindow* window,
static void
vteapp_window_update_geometry(VteappWindow* window)
{
+#if VTE_GTK == 3
GtkWidget* window_widget = GTK_WIDGET(window);
GtkWidget* terminal_widget = GTK_WIDGET(window->terminal);
@@ -1301,18 +1500,43 @@ vteapp_window_update_geometry(VteappWindow* window)
window->cached_cell_width, window->cached_cell_height,
window->cached_chrome_width, window->cached_chrome_height,
window->cached_csd_width, window->cached_csd_height);
+#elif VTE_GTK == 4
+ // FIXMEgtk4 there appears to be no way to do this with gtk4 ? maybe go to X/wayland
+ // directly to set the geometry hints?
+#endif
}
+#include <gdk/gdk.h>
+
static void
vteapp_window_resize(VteappWindow* window)
{
- /* Don't do this for maximised or tiled windows. */
- auto win = gtk_widget_get_window(GTK_WIDGET(window));
- if (win != nullptr &&
- (gdk_window_get_state(win) & (GDK_WINDOW_STATE_MAXIMIZED |
- GDK_WINDOW_STATE_FULLSCREEN |
- GDK_WINDOW_STATE_TILED)) != 0)
+ /* Don't do this for fullscreened, maximised, or tiled windows. */
+#if VTE_GTK == 3
+ if (window->window_state & (GDK_WINDOW_STATE_MAXIMIZED |
+ GDK_WINDOW_STATE_FULLSCREEN |
+ GDK_WINDOW_STATE_TILED |
+#if GTK_CHECK_VERSION(3,22,23)
+ GDK_WINDOW_STATE_TOP_TILED |
+ GDK_WINDOW_STATE_BOTTOM_TILED |
+ GDK_WINDOW_STATE_LEFT_TILED |
+ GDK_WINDOW_STATE_RIGHT_TILED |
+#endif
+ 0))
+ return;
+#elif VTE_GTK == 4
+ if (window->toplevel_state & (GDK_TOPLEVEL_STATE_MAXIMIZED |
+ GDK_TOPLEVEL_STATE_FULLSCREEN |
+ GDK_TOPLEVEL_STATE_TILED |
+ GDK_TOPLEVEL_STATE_TOP_TILED |
+ GDK_TOPLEVEL_STATE_BOTTOM_TILED |
+ GDK_TOPLEVEL_STATE_LEFT_TILED |
+ GDK_TOPLEVEL_STATE_RIGHT_TILED))
return;
+#endif /* VTE_GTK */
+
+#if VTE_GTK == 3
+ // FIXMEgtk4
/* First, update the geometry hints, so that the cached_* members are up-to-date */
vteapp_window_update_geometry(window);
@@ -1327,11 +1551,13 @@ vteapp_window_resize(VteappWindow* window)
columns, rows, pixel_width, pixel_height);
gtk_window_resize(GTK_WINDOW(window), pixel_width, pixel_height);
+#endif /* VTE_GTK == 3 FIXMEgtk4 */
}
static void
vteapp_window_parse_geometry(VteappWindow* window)
{
+#if VTE_GTK == 3
/* First update the geometry hints, so that gtk_window_parse_geometry()
* knows the char width/height and base size increments.
*/
@@ -1376,6 +1602,9 @@ vteapp_window_parse_geometry(VteappWindow* window)
vteapp_window_resize(window);
}
}
+#elif VTE_GTK == 4
+ // FIXMEgtk4 ????
+#endif /* VTE_GTK */
}
static void
@@ -1409,8 +1638,13 @@ window_spawn_cb(VteTerminal* terminal,
auto msg = vte::glib::take_string(g_strdup_printf("Spawning failed: %s", error->message));
if (options.keep)
vte_terminal_feed(window->terminal, msg.get(), -1);
- else
+ else {
+#if VTE_GTK == 3
gtk_widget_destroy(GTK_WIDGET(window));
+#elif VTE_GTK == 4
+ gtk_window_destroy(GTK_WINDOW(window));
+#endif
+ }
}
}
@@ -1567,17 +1801,35 @@ window_update_copy_sensitivity(VteappWindow* window)
vte_terminal_get_has_selection(window->terminal));
}
+static void
+window_update_fullscreen_state(VteappWindow* window)
+{
+#if VTE_GTK == 3
+ auto const fullscreen = (window->window_state & GDK_WINDOW_STATE_FULLSCREEN) != 0;
+#elif VTE_GTK == 4
+ auto const fullscreen = (window->toplevel_state & GDK_TOPLEVEL_STATE_FULLSCREEN) != 0;
+#endif
+ auto action = g_action_map_lookup_action(G_ACTION_MAP(window), "fullscreen");
+ g_simple_action_set_state(G_SIMPLE_ACTION(action), g_variant_new_boolean (fullscreen));
+}
+
static void
window_update_paste_sensitivity(VteappWindow* window)
{
+ bool can_paste = false;
+
+#if VTE_GTK == 3
GdkAtom* targets;
int n_targets;
- bool can_paste = false;
if (gtk_clipboard_wait_for_targets(window->clipboard, &targets, &n_targets)) {
can_paste = gtk_targets_include_text(targets, n_targets);
g_free(targets);
}
+#elif VTE_GTK == 4
+ auto formats = gdk_clipboard_get_formats(window->clipboard);
+ can_paste = gdk_content_formats_contain_gtype(formats, G_TYPE_STRING);
+#endif /* VTE_GTK */
auto action = g_action_map_lookup_action(G_ACTION_MAP(window), "paste");
g_simple_action_set_enabled(G_SIMPLE_ACTION(action), can_paste);
@@ -1603,10 +1855,15 @@ window_action_copy_match_cb(GSimpleAction* action,
GVariant* parameter,
void* data)
{
- VteappWindow* window = VTEAPP_WINDOW(data);
- gsize len;
- char const* str = g_variant_get_string(parameter, &len);
+ auto window = VTEAPP_WINDOW(data);
+
+ auto len = size_t{};
+ auto str = g_variant_get_string(parameter, &len);
+#if VTE_GTK == 3
gtk_clipboard_set_text(window->clipboard, str, len);
+#elif VTE_GTK == 4
+ gdk_clipboard_set_text(window->clipboard, str);
+#endif
}
static void
@@ -1623,16 +1880,23 @@ window_action_reset_cb(GSimpleAction* action,
GVariant* parameter,
void* data)
{
- VteappWindow* window = VTEAPP_WINDOW(data);
- bool clear;
- GdkModifierType modifiers;
+ auto window = VTEAPP_WINDOW(data);
+ auto clear = false;
if (parameter != nullptr)
clear = g_variant_get_boolean(parameter);
- else if (gtk_get_current_event_state(&modifiers))
+ else {
+ auto modifiers = GdkModifierType{};
+#if VTE_GTK == 3
+ if (!gtk_get_current_event_state(&modifiers))
+ modifiers = GdkModifierType(0);
+#elif VTE_GTK == 4
+ // FIXMEgtk4!
+ modifiers = GdkModifierType(0);
+#endif
+
clear = (modifiers & GDK_CONTROL_MASK) != 0;
- else
- clear = false;
+ }
vte_terminal_reset(window->terminal, true, clear);
}
@@ -1646,7 +1910,6 @@ window_action_find_cb(GSimpleAction* action,
gtk_toggle_button_set_active(window->find_button, true);
}
-
static void
window_action_fullscreen_state_cb (GSimpleAction *action,
GVariant *state,
@@ -1665,6 +1928,7 @@ window_action_fullscreen_state_cb (GSimpleAction *action,
/* The window-state-changed callback will update the action's actual state */
}
+#if VTE_GTK == 3
static bool
vteapp_window_show_context_menu(VteappWindow* window,
guint button,
@@ -1678,20 +1942,21 @@ vteapp_window_show_context_menu(VteappWindow* window,
g_menu_append(menu, "_Copy", "win.copy::text");
g_menu_append(menu, "Copy As _HTML", "win.copy::html");
- if (event != nullptr) {
- auto hyperlink = vte_terminal_hyperlink_check_event(window->terminal, event);
- if (hyperlink != nullptr) {
- verbose_print("Hyperlink: %s\n", hyperlink);
- auto target = g_variant_new_string(hyperlink); /* floating */
+ if (event != nullptr)
+ {
+ auto hyperlink = vte::glib::take_string(vte_terminal_hyperlink_check_event(window->terminal,
event));
+ if (hyperlink) {
+ verbose_print("Hyperlink: %s\n", hyperlink.get());
+ auto target = g_variant_new_string(hyperlink.get()); /* floating */
auto item = vte::glib::take_ref(g_menu_item_new("Copy _Hyperlink", nullptr));
g_menu_item_set_action_and_target_value(item.get(), "win.copy-match", target);
g_menu_append_item(menu, item.get());
}
- auto match = vte_terminal_match_check_event(window->terminal, event, nullptr);
- if (match != nullptr) {
- verbose_print("Match: %s\n", match);
- auto target = g_variant_new_string(match); /* floating */
+ auto match = vte::glib::take_string(vte_terminal_match_check_event(window->terminal, event,
nullptr));
+ if (match) {
+ verbose_print("Match: %s\n", match.get());
+ auto target = g_variant_new_string(match.get()); /* floating */
auto item = vte::glib::take_ref(g_menu_item_new("Copy _Match", nullptr));
g_menu_item_set_action_and_target_value(item.get(), "win.copy-match", target);
g_menu_append_item(menu, item.get());
@@ -1725,15 +1990,14 @@ vteapp_window_show_context_menu(VteappWindow* window,
else
verbose_print("%s match: %s\n", extra_pattern, extra_match);
}
- g_free(hyperlink);
- g_free(match);
g_free(extra_match);
g_free(extra_subst);
}
g_menu_append(menu, "_Paste", "win.paste");
- if (window->fullscreen)
+ auto const fullscreen = (window->window_state & GDK_WINDOW_STATE_FULLSCREEN) != 0;
+ if (fullscreen)
g_menu_append(menu, "_Fullscreen", "win.fullscreen");
auto popup = gtk_menu_new_from_model(G_MENU_MODEL(menu));
@@ -1744,13 +2008,23 @@ vteapp_window_show_context_menu(VteappWindow* window,
return true;
}
+#endif /* VTE_GTK */
+
+#if VTE_GTK == 3
static gboolean
window_popup_menu_cb(GtkWidget* widget,
VteappWindow* window)
{
- return vteapp_window_show_context_menu(window, 0, gtk_get_current_event_time(), nullptr);
+ auto const timestamp = gtk_get_current_event_time();
+
+ return vteapp_window_show_context_menu(window, 0, timestamp , nullptr);
}
+// FIXMEgtk4
+
+#endif /* VTE_GTK == 3 */
+
+#if VTE_GTK == 3
static gboolean
window_button_press_cb(GtkWidget* widget,
@@ -1764,6 +2038,8 @@ window_button_press_cb(GtkWidget* widget,
reinterpret_cast<GdkEvent*>(event));
}
+#endif /* VTE_GTK == 3 */
+
static void
window_cell_size_changed_cb(VteTerminal* term,
guint width,
@@ -1815,9 +2091,15 @@ window_child_exited_cb(VteTerminal* term,
if (options.keep)
return;
+#if VTE_GTK == 3
gtk_widget_destroy(GTK_WIDGET(window));
+#elif VTE_GTK == 4
+ gtk_window_destroy(GTK_WINDOW(window));
+#endif
}
+#if VTE_GTK == 3
+
static void
window_clipboard_owner_change_cb(GtkClipboard* clipboard,
GdkEvent* event,
@@ -1826,6 +2108,18 @@ window_clipboard_owner_change_cb(GtkClipboard* clipboard,
window_update_paste_sensitivity(window);
}
+#elif VTE_GTK == 4
+
+static void
+window_clipboard_formats_notify_cb(GdkClipboard* clipboard,
+ GParamSpec* pspec,
+ VteappWindow* window)
+{
+ window_update_paste_sensitivity(window);
+}
+
+#endif /* VTE_GTK */
+
static void
window_decrease_font_size_cb(VteTerminal* terminal,
VteappWindow* window)
@@ -1847,7 +2141,12 @@ window_deiconify_window_cb(VteTerminal* terminal,
if (!options.allow_window_ops)
return;
+#if VTE_GTK == 3
gtk_window_deiconify(GTK_WINDOW(window));
+#elif VTE_GTK == 4
+ auto toplevel = GDK_TOPLEVEL(gtk_native_get_surface(GTK_NATIVE(window)));
+ gdk_toplevel_present(toplevel, nullptr); // FIXMEgtk4 nullptr not allowed
+#endif
}
static void
@@ -1857,26 +2156,25 @@ window_iconify_window_cb(VteTerminal* terminal,
if (!options.allow_window_ops)
return;
+#if VTE_GTK == 3
gtk_window_iconify(GTK_WINDOW(window));
-}
-
-static void
-window_icon_title_changed_cb(VteTerminal* terminal,
- VteappWindow* window)
-{
- if (!options.icon_title)
- return;
-
- gdk_window_set_icon_name(gtk_widget_get_window(GTK_WIDGET(window)),
- vte_terminal_get_icon_title(window->terminal));
+#elif VTE_GTK == 4
+ auto toplevel = GDK_TOPLEVEL(gtk_native_get_surface(GTK_NATIVE(window)));
+ gdk_toplevel_minimize(toplevel);
+#endif
}
static void
window_window_title_changed_cb(VteTerminal* terminal,
VteappWindow* window)
{
- gtk_window_set_title(GTK_WINDOW(window),
- vte_terminal_get_window_title(window->terminal));
+ auto const title = vte_terminal_get_window_title(window->terminal);
+#if VTE_GTK == 3
+ gtk_window_set_title(GTK_WINDOW(window), title);
+#elif VTE_GTK == 4
+ auto toplevel = GDK_TOPLEVEL(gtk_native_get_surface(GTK_NATIVE(window)));
+ gdk_toplevel_set_title(toplevel, title);
+#endif
}
static void
@@ -1888,7 +2186,12 @@ window_lower_window_cb(VteTerminal* terminal,
if (!gtk_widget_get_realized(GTK_WIDGET(window)))
return;
+#if VTE_GTK == 3
gdk_window_lower(gtk_widget_get_window(GTK_WIDGET(window)));
+#elif VTE_GTK == 4
+ auto toplevel = GDK_TOPLEVEL(gtk_native_get_surface(GTK_NATIVE(window)));
+ gdk_toplevel_lower(toplevel);
+#endif
}
static void
@@ -1900,7 +2203,12 @@ window_raise_window_cb(VteTerminal* terminal,
if (!gtk_widget_get_realized(GTK_WIDGET(window)))
return;
+#if VTE_GTK == 3
gdk_window_raise(gtk_widget_get_window(GTK_WIDGET(window)));
+#elif VTE_GTK == 4
+ auto toplevel = GDK_TOPLEVEL(gtk_native_get_surface(GTK_NATIVE(window)));
+ gdk_toplevel_present(toplevel, nullptr); // FIXMEgtk4 gdk_toplevel_raise() doesn't exist??
+#endif
}
static void
@@ -1932,9 +2240,26 @@ window_move_window_cb(VteTerminal* terminal,
if (!options.allow_window_ops)
return;
+#if VTE_GTK == 3
gtk_window_move(GTK_WINDOW(window), x, y);
+#elif VTE_GTK == 4
+ // FIXMEgtk4
+#endif
}
+#if VTE_GTK == 4
+
+static void
+window_toplevel_notify_state_cb(GdkToplevel* toplevel,
+ GParamSpec* pspec,
+ VteappWindow* window)
+{
+ window->toplevel_state = gdk_toplevel_get_state(toplevel);
+ window_update_fullscreen_state(window);
+}
+
+#endif /* VTE_GTK == 4 */
+
static void
window_notify_cb(GObject* object,
GParamSpec* pspec,
@@ -2044,10 +2369,19 @@ vteapp_window_constructed(GObject *object)
gtk_widget_set_margin_bottom(GTK_WIDGET(window->terminal), margin);
}
- gtk_range_set_adjustment(GTK_RANGE(window->scrollbar),
- gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(window->terminal)));
+ auto vadj = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(window->terminal));
+#if VTE_GTK == 3
+ gtk_range_set_adjustment(GTK_RANGE(window->scrollbar), vadj);
+#elif VTE_GTK == 4
+ gtk_scrollbar_set_adjustment(GTK_SCROLLBAR(window->scrollbar), vadj);
+#endif
+
if (options.no_scrollbar) {
+#if VTE_GTK == 3
gtk_widget_destroy(GTK_WIDGET(window->scrollbar));
+#elif VTE_GTK == 4
+ // FIXMEgtk4
+#endif
window->scrollbar = nullptr;
}
@@ -2070,39 +2404,58 @@ vteapp_window_constructed(GObject *object)
g_action_map_add_action(map, G_ACTION(action.get()));
g_signal_connect(action.get(), "notify::state", G_CALLBACK(window_input_enabled_state_cb), window);
+#if VTE_GTK == 4
+ auto gear_popover = gtk_menu_button_get_popover(GTK_MENU_BUTTON(window->gear_button));
+ gtk_widget_set_halign(GTK_WIDGET(gear_popover), GTK_ALIGN_END);
+#endif
+
/* Find */
window->search_popover = vteapp_search_popover_new(window->terminal,
GTK_WIDGET(window->find_button));
+
g_signal_connect(window->search_popover, "closed",
G_CALLBACK(window_search_popover_closed_cb), window);
g_signal_connect(window->find_button, "toggled",
G_CALLBACK(window_find_button_toggled_cb), window);
/* Clipboard */
+#if VTE_GTK == 3
window->clipboard = gtk_widget_get_clipboard(GTK_WIDGET(window), GDK_SELECTION_CLIPBOARD);
g_signal_connect(window->clipboard, "owner-change", G_CALLBACK(window_clipboard_owner_change_cb),
window);
+#elif VTE_GTK == 4
+ window->clipboard = gtk_widget_get_clipboard(GTK_WIDGET(window));
+ g_signal_connect(window->clipboard, "notify::formats",
G_CALLBACK(window_clipboard_formats_notify_cb), window);
+#endif /* VTE_GTK */
/* Set ARGB visual */
if (options.transparency_percent >= 0) {
+#if VTE_GTK == 3
if (!options.no_argb_visual) {
auto screen = gtk_widget_get_screen(GTK_WIDGET(window));
auto visual = gdk_screen_get_rgba_visual(screen);
if (visual != nullptr)
gtk_widget_set_visual(GTK_WIDGET(window), visual);
- }
+ }
/* Without this transparency doesn't work; see bug #729884. */
gtk_widget_set_app_paintable(GTK_WIDGET(window), true);
+
+#elif VTE_GTK == 4
+ // FIXMEgtk4
+#endif /* VTE_GTK == 3 */
}
/* Signals */
+#if VTE_GTK == 3
g_signal_connect(window->terminal, "popup-menu", G_CALLBACK(window_popup_menu_cb), window);
g_signal_connect(window->terminal, "button-press-event", G_CALLBACK(window_button_press_cb), window);
+#elif VTE_GTK == 4
+ // FIXMEgtk4
+#endif
g_signal_connect(window->terminal, "char-size-changed", G_CALLBACK(window_cell_size_changed_cb),
window);
g_signal_connect(window->terminal, "child-exited", G_CALLBACK(window_child_exited_cb), window);
g_signal_connect(window->terminal, "decrease-font-size", G_CALLBACK(window_decrease_font_size_cb),
window);
g_signal_connect(window->terminal, "deiconify-window", G_CALLBACK(window_deiconify_window_cb),
window);
- g_signal_connect(window->terminal, "icon-title-changed", G_CALLBACK(window_icon_title_changed_cb),
window);
g_signal_connect(window->terminal, "iconify-window", G_CALLBACK(window_iconify_window_cb), window);
g_signal_connect(window->terminal, "increase-font-size", G_CALLBACK(window_increase_font_size_cb),
window);
g_signal_connect(window->terminal, "lower-window", G_CALLBACK(window_lower_window_cb), window);
@@ -2118,11 +2471,13 @@ vteapp_window_constructed(GObject *object)
g_signal_connect(window->terminal, "notify", G_CALLBACK(window_notify_cb), window);
/* Settings */
+#if VTE_GTK == 3
if (options.no_double_buffer) {
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
gtk_widget_set_double_buffered(GTK_WIDGET(window->terminal), false);
G_GNUC_END_IGNORE_DEPRECATIONS;
}
+#endif /* VTE_GTK == 3 */
if (options.encoding != nullptr) {
auto error = vte::glib::Error{};
@@ -2183,6 +2538,8 @@ vteapp_window_constructed(GObject *object)
/* Done! */
gtk_grid_attach(GTK_GRID(window->window_grid), GTK_WIDGET(window->terminal),
0, 0, 1, 1);
+ gtk_widget_set_halign(GTK_WIDGET(window->terminal), GTK_ALIGN_FILL);
+ gtk_widget_set_valign(GTK_WIDGET(window->terminal), GTK_ALIGN_FILL);
gtk_widget_show(GTK_WIDGET(window->terminal));
window_update_paste_sensitivity(window);
@@ -2201,13 +2558,21 @@ vteapp_window_dispose(GObject *object)
if (window->clipboard != nullptr) {
g_signal_handlers_disconnect_by_func(window->clipboard,
+#if VTE_GTK == 3
(void*)window_clipboard_owner_change_cb,
+#elif VTE_GTK == 4
+ (void*)window_clipboard_formats_notify_cb,
+#endif
window);
window->clipboard = nullptr;
}
if (window->search_popover != nullptr) {
+#if VTE_GTK == 3
gtk_widget_destroy(window->search_popover);
+#elif VTE_GTK == 4
+ gtk_widget_unparent(window->search_popover); // this destroys the popover
+#endif /* VTE_GTK */
window->search_popover = nullptr;
}
@@ -2222,9 +2587,36 @@ vteapp_window_realize(GtkWidget* widget)
/* Now we can know the CSD size, and thus apply the geometry. */
VteappWindow* window = VTEAPP_WINDOW(widget);
verbose_print("VteappWindow::realize\n");
+
+#if VTE_GTK == 3
+ auto win = gtk_widget_get_window(GTK_WIDGET(window));
+ window->window_state = gdk_window_get_state(win);
+#elif VTE_GTK == 4
+ auto surface = gtk_native_get_surface(GTK_NATIVE(widget));
+ window->toplevel_state = gdk_toplevel_get_state(GDK_TOPLEVEL(surface));
+ g_signal_connect(surface, "notify::state",
+ G_CALLBACK(window_toplevel_notify_state_cb), window);
+#endif
+
+ window_update_fullscreen_state(window);
+
vteapp_window_resize(window);
}
+static void
+vteapp_window_unrealize(GtkWidget* widget)
+{
+#if VTE_GTK == 4
+ auto window = VTEAPP_WINDOW(widget);
+ auto toplevel = gtk_native_get_surface(GTK_NATIVE(widget));
+ g_signal_handlers_disconnect_by_func(toplevel,
+ (void*)window_toplevel_notify_state_cb,
+ window);
+#endif
+
+ GTK_WIDGET_CLASS(vteapp_window_parent_class)->unrealize(widget);
+}
+
static void
vteapp_window_show(GtkWidget* widget)
{
@@ -2236,6 +2628,8 @@ vteapp_window_show(GtkWidget* widget)
vteapp_window_resize(window);
}
+#if VTE_GTK == 3
+
static void
vteapp_window_style_updated(GtkWidget* widget)
{
@@ -2251,18 +2645,17 @@ static gboolean
vteapp_window_state_event (GtkWidget* widget,
GdkEventWindowState* event)
{
- VteappWindow* window = VTEAPP_WINDOW(widget);
+ auto window = VTEAPP_WINDOW(widget);
+ window->window_state = event->new_window_state;
- if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
- window->fullscreen = (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) != 0;
-
- auto action =
reinterpret_cast<GSimpleAction*>(g_action_map_lookup_action(G_ACTION_MAP(window), "fullscreen"));
- g_simple_action_set_state(action, g_variant_new_boolean (window->fullscreen));
- }
+ if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
+ window_update_fullscreen_state(window);
return GTK_WIDGET_CLASS(vteapp_window_parent_class)->window_state_event(widget, event);
}
+#endif /* VTE_GTK == 3 */
+
static void
vteapp_window_class_init(VteappWindowClass* klass)
{
@@ -2272,9 +2665,15 @@ vteapp_window_class_init(VteappWindowClass* klass)
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
widget_class->realize = vteapp_window_realize;
+ widget_class->unrealize = vteapp_window_unrealize;
widget_class->show = vteapp_window_show;
+
+#if VTE_GTK == 3
widget_class->style_updated = vteapp_window_style_updated;
widget_class->window_state_event = vteapp_window_state_event;
+#elif VTE_GTK == 4
+ // FIXMEgtk4 window state event
+#endif
gtk_widget_class_set_template_from_resource(widget_class, "/org/gnome/vte/app/ui/window.ui");
gtk_widget_class_set_css_name(widget_class, "vteapp-window");
@@ -2340,8 +2739,14 @@ app_action_close_cb(GSimpleAction* action,
{
GtkApplication* application = GTK_APPLICATION(data);
auto window = gtk_application_get_active_window(application);
- if (window != nullptr)
- gtk_widget_destroy(GTK_WIDGET(window));
+ if (window == nullptr)
+ return;
+
+#if VTE_GTK == 3
+ gtk_widget_destroy(GTK_WIDGET(window));
+#elif VTE_GTK == 4
+ gtk_window_destroy(GTK_WINDOW(window));
+#endif
}
static gboolean
@@ -2381,16 +2786,24 @@ static void
vteapp_application_init(VteappApplication* application)
{
g_object_set(gtk_settings_get_default(),
- "gtk-enable-mnemonics", FALSE,
"gtk-enable-accels", FALSE,
+#if VTE_GTK == 3
+ "gtk-enable-mnemonics", FALSE,
/* Make gtk+ CSD not steal F10 from the terminal */
"gtk-menu-bar-accel", nullptr,
+#endif
nullptr);
if (options.css) {
+#if VTE_GTK == 3
gtk_style_context_add_provider_for_screen(gdk_screen_get_default (),
GTK_STYLE_PROVIDER(options.css.get()),
GTK_STYLE_PROVIDER_PRIORITY_USER);
+#elif VTE_GTK == 4
+ gtk_style_context_add_provider_for_display(gdk_display_get_default (),
+ GTK_STYLE_PROVIDER(options.css.get()),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+#endif
}
if (options.feed_stdin) {
@@ -2491,8 +2904,11 @@ main(int argc,
return EXIT_SUCCESS;
}
+#if VTE_GTK == 3
if (options.debug)
gdk_window_set_debug_updates(true);
+#endif /* VTE_GTK == 3 */
+
#ifdef VTE_DEBUG
if (options.test_mode) {
vte_set_test_flags(VTE_TEST_FLAGS_ALL);
diff --git a/src/app/appmenu-gtk4.ui b/src/app/appmenu-gtk4.ui
new file mode 100644
index 00000000..60d0e933
--- /dev/null
+++ b/src/app/appmenu-gtk4.ui
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright © 2017, 2020 Christian Persch
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+<interface>
+ <menu id="app-menu">
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_New Terminal</attribute>
+ <attribute name="action">app.new</attribute>
+ </item>
+ </section>
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_Close</attribute>
+ <attribute name="action">app.close</attribute>
+ </item>
+ </section>
+ </menu>
+</interface>
diff --git a/src/app/meson.build b/src/app/meson.build
index 41923442..2974b181 100644
--- a/src/app/meson.build
+++ b/src/app/meson.build
@@ -44,7 +44,7 @@ if get_option('gtk3')
)
app_gtk3_sources = app_sources + app_gtk3_resource_sources
- app_gtk3_cppflags = app_common_cppflags + gtk3_version_cppflags
+ app_gtk3_cppflags = app_common_cppflags + gtk3_version_cppflags + ['-DVTE_GTK=3',]
app_gtk3_deps = app_common_deps + [libvte_gtk3_dep]
app_gtk3 = executable(
@@ -56,3 +56,32 @@ if get_option('gtk3')
install: true,
)
endif
+
+if get_option('gtk4')
+
+ app_gtk4_resource_data = files(
+ 'appmenu-gtk4.ui',
+ 'search-popover-gtk4.ui',
+ 'window-gtk4.ui',
+ )
+
+ app_gtk4_resource_sources = gnome.compile_resources(
+ 'resources-gtk4.cc',
+ 'app-gtk4.gresource.xml',
+ c_name: 'app',
+ dependencies: app_gtk4_resource_data,
+ )
+
+ app_gtk4_sources = app_sources + [app_gtk4_resource_sources,]
+ app_gtk4_cppflags = app_common_cppflags + gtk4_version_cppflags + ['-DVTE_GTK=4',]
+ app_gtk4_deps = app_common_deps + [libvte_gtk4_dep]
+
+ app_gtk4 = executable(
+ 'vte-' + vte_gtk4_api_version + '-gtk4',
+ app_gtk4_sources,
+ dependencies: app_gtk4_deps,
+ cpp_args: app_gtk4_cppflags,
+ include_directories: top_inc,
+ install: true,
+ )
+endif
diff --git a/src/app/search-popover-gtk3.ui b/src/app/search-popover-gtk3.ui
index 0ecec701..9ca92e51 100644
--- a/src/app/search-popover-gtk3.ui
+++ b/src/app/search-popover-gtk3.ui
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.19.0 -->
<!--
Copyright © 2016, 2017 Christian Persch
diff --git a/src/app/search-popover-gtk4.ui b/src/app/search-popover-gtk4.ui
new file mode 100644
index 00000000..ed19a93b
--- /dev/null
+++ b/src/app/search-popover-gtk4.ui
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright © 2016, 2017, 2020 Christian Persch
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+<interface>
+ <requires lib="gtk+" version="3.16"/>
+ <template class="VteappSearchPopover" parent="GtkPopover">
+ <property name="can_focus">0</property>
+ <property name="child">
+ <object class="GtkBox" id="box1">
+ <property name="can_focus">0</property>
+ <property name="margin-start">12</property>
+ <property name="margin-end">12</property>
+ <property name="margin_top">12</property>
+ <property name="margin_bottom">12</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="can_focus">0</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkBox" id="box4">
+ <property name="hexpand">1</property>
+ <property name="can_focus">0</property>
+ <child>
+ <object class="GtkSearchEntry" id="search_entry">
+ <property name="hexpand">1</property>
+ <property name="activates_default">1</property>
+ <property name="width_chars">30</property>
+ <property name="placeholder_text" translatable="yes">Search</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="search_prev_button">
+ <property name="receives_default">1</property>
+ <property name="tooltip_text" translatable="yes">Search for previous
occurrence</property>
+ <property name="focus_on_click">0</property>
+ <child>
+ <object class="GtkImage" id="image2">
+ <property name="can_focus">0</property>
+ <property name="icon_name">go-up-symbolic</property>
+ <property name="use_fallback">1</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="search_next_button">
+ <property name="receives_default">1</property>
+ <property name="tooltip_text" translatable="yes">Search for next occurrence</property>
+ <property name="focus_on_click">0</property>
+ <child>
+ <object class="GtkImage" id="image3">
+ <property name="can_focus">0</property>
+ <property name="icon_name">go-down-symbolic</property>
+ <property name="use_fallback">1</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <style>
+ <class name="linked"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="reveal_button">
+ <property name="receives_default">1</property>
+ <property name="tooltip_text" translatable="yes">Toggle search options</property>
+ <property name="focus_on_click">0</property>
+ <child>
+ <object class="GtkImage" id="image1">
+ <property name="can_focus">0</property>
+ <property name="icon_name">open-menu-symbolic</property>
+ <property name="use_fallback">1</property>
+ </object>
+ </child>
+ <!--
+ <accessibility>
+ <relation type="controller-for" target="revealer"/>
+ </accessibility>
+ -->
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="close_button">
+ <property name="receives_default">1</property>
+ <property name="focus_on_click">0</property>
+ <child>
+ <object class="GtkImage" id="image4">
+ <property name="can_focus">0</property>
+ <property name="icon_name">window-close-symbolic</property>
+ <property name="use_fallback">1</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRevealer" id="revealer">
+ <property name="can_focus">0</property>
+ <property name="transition_type">none</property>
+ <property name="reveal_child">0</property>
+ <property name="child">
+ <object class="GtkBox" id="box3">
+ <property name="can_focus">0</property>
+ <property name="margin_top">18</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="match_case_checkbutton">
+ <property name="valign">center</property>
+ <property name="label" translatable="yes">_Match case</property>
+ <property name="use_underline">1</property>
+ <property name="focus_on_click">0</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="entire_word_checkbutton">
+ <property name="valign">center</property>
+ <property name="label" translatable="yes">Match _entire word only</property>
+ <property name="use_underline">1</property>
+ <property name="focus_on_click">0</property>
+ <property name="halign">start</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="regex_checkbutton">
+ <property name="valign">center</property>
+ <property name="label" translatable="yes">Match as _regular expression</property>
+ <property name="use_underline">1</property>
+ <property name="focus_on_click">0</property>
+ <property name="halign">start</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="wrap_around_checkbutton">
+ <property name="valign">center</property>
+ <property name="label" translatable="yes">_Wrap around</property>
+ <property name="use_underline">1</property>
+ <property name="focus_on_click">0</property>
+ <property name="halign">start</property>
+ <property name="active">1</property>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ </object>
+ </property>
+ </template>
+</interface>
diff --git a/src/app/window-gtk3.ui b/src/app/window-gtk3.ui
index 2d706966..d35528fc 100644
--- a/src/app/window-gtk3.ui
+++ b/src/app/window-gtk3.ui
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.19.0 -->
<!--
Copyright © 2014, 2017 Christian Persch
diff --git a/src/app/window-gtk4.ui b/src/app/window-gtk4.ui
new file mode 100644
index 00000000..b8e49b7c
--- /dev/null
+++ b/src/app/window-gtk4.ui
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright © 2014, 2017, 2020 Christian Persch
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+<interface>
+ <requires lib="gtk+" version="3.10"/>
+ <menu id="gear_menu_model">
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_New Terminal</attribute>
+ <attribute name="action">app.new</attribute>
+ </item>
+ </section>
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_Copy</attribute>
+ <attribute name="action">win.copy</attribute>
+ <attribute name="target">text</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">Copy As _HTML</attribute>
+ <attribute name="action">win.copy</attribute>
+ <attribute name="target">html</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">_Paste</attribute>
+ <attribute name="action">win.paste</attribute>
+ </item>
+ </section>
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_Find…</attribute>
+ <attribute name="action">win.find</attribute>
+ </item>
+ </section>
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_Reset</attribute>
+ <attribute name="action">win.reset</attribute>
+ <attribute name="target" type="b">false</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">Reset and Cl_ear</attribute>
+ <attribute name="action">win.reset</attribute>
+ <attribute name="target" type="b">true</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">_Input enabled</attribute>
+ <attribute name="action">win.input-enabled</attribute>
+ </item>
+ </section>
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_Fullscreen</attribute>
+ <attribute name="action">win.fullscreen</attribute>
+ </item>
+ </section>
+ </menu>
+ <template class="VteappWindow" parent="GtkApplicationWindow">
+ <property name="can_focus">0</property>
+ <property name="icon_name">utilities-terminal</property>
+ <child>
+ <object class="GtkGrid" id="window_grid">
+ <property name="can_focus">0</property>
+ <property name="halign">fill</property>
+ <property name="valign">fill</property>
+ <property name="hexpand">1</property>
+ <property name="vexpand">1</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <object class="GtkScrollbar" id="scrollbar">
+ <property name="can_focus">0</property>
+ <property name="orientation">vertical</property>
+ <property name="hexpand">0</property>
+ <property name="vexpand">1</property>
+ <layout>
+ <property name="column">1</property>
+ <property name="row">0</property>
+ </layout>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="titlebar">
+ <object class="GtkHeaderBar" id="headerbar">
+ <property name="can_focus">0</property>
+ <property name="decoration_layout">:close</property>
+ <child type="start">
+ <object class="GtkButton" id="copy_button">
+ <property name="receives_default">1</property>
+ <property name="tooltip_text" translatable="yes">Copy</property>
+ <property name="action_name">win.copy</property>
+ <property name="action_target">"text"</property>
+ <property name="focus_on_click">0</property>
+ <child>
+ <object class="GtkImage" id="image2">
+ <property name="can_focus">0</property>
+ <property name="icon_name">edit-copy-symbolic</property>
+ <property name="use_fallback">1</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="start">
+ <object class="GtkButton" id="paste_button">
+ <property name="receives_default">1</property>
+ <property name="tooltip_text" translatable="yes">Paste</property>
+ <property name="action_name">win.paste</property>
+ <property name="focus_on_click">0</property>
+ <child>
+ <object class="GtkImage" id="image3">
+ <property name="can_focus">0</property>
+ <property name="icon_name">edit-paste-symbolic</property>
+ <property name="use_fallback">1</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="start">
+ <object class="GtkToggleButton" id="find_button">
+ <property name="receives_default">1</property>
+ <property name="focus_on_click">0</property>
+ <child>
+ <object class="GtkImage" id="image5">
+ <property name="can_focus">0</property>
+ <property name="icon_name">edit-find-symbolic</property>
+ <property name="use_fallback">1</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="title">
+ <placeholder/>
+ </child>
+ <child type="end">
+ <object class="GtkMenuButton" id="gear_button">
+ <property name="receives_default">1</property>
+ <property name="focus_on_click">0</property>
+ <property name="menu-model">gear_menu_model</property>
+ <property name="icon_name">open-menu-symbolic</property>
+ </object>
+ </child>
+ <child type="end">
+ <object class="GtkGrid" id="notifications_grid">
+ <property name="can_focus">0</property>
+ <property name="column_spacing">6</property>
+ <property name="row_spacing">6</property>
+ <property name="hexpand">0</property>
+ <property name="vexpand">1</property>
+ <child>
+ <object class="GtkImage" id="readonly_emblem">
+ <property name="visible">0</property>
+ <property name="can_focus">0</property>
+ <property name="tooltip_text" translatable="yes">Read-only</property>
+ <property name="icon_name">emblem-readonly</property>
+ <property name="use_fallback">1</property>
+ <property name="hexpand">0</property>
+ <property name="vexpand">0</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">0</property>
+ </layout>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/cairo-glue.hh b/src/cairo-glue.hh
index 5fe0e764..c75a8083 100644
--- a/src/cairo-glue.hh
+++ b/src/cairo-glue.hh
@@ -23,7 +23,9 @@
namespace vte {
-VTE_DECLARE_FREEABLE(cairo_t, cairo_destroy);
+VTE_DECLARE_FREEABLE(cairo_rectangle_list_t, cairo_rectangle_list_destroy);
+VTE_DECLARE_FREEABLE(cairo_region_t, cairo_region_destroy);
VTE_DECLARE_FREEABLE(cairo_surface_t, cairo_surface_destroy);
+VTE_DECLARE_FREEABLE(cairo_t, cairo_destroy);
} // namespace vte::cairo
diff --git a/src/clipboard-gtk.cc b/src/clipboard-gtk.cc
index 0a998973..499c94ae 100644
--- a/src/clipboard-gtk.cc
+++ b/src/clipboard-gtk.cc
@@ -22,6 +22,7 @@
#include "widget.hh"
#include "vteinternal.hh"
+#include <new>
#include <stdexcept>
#include <utility>
@@ -42,12 +43,20 @@ Clipboard::Clipboard(Widget& delegate,
switch (type) {
case ClipboardType::PRIMARY:
- m_clipboard = vte::glib::make_ref(gtk_clipboard_get_for_display(display,
- GDK_SELECTION_PRIMARY));
+ m_clipboard = vte::glib::make_ref
+#if VTE_GTK == 3
+ (gtk_clipboard_get_for_display(display, GDK_SELECTION_PRIMARY));
+#elif VTE_GTK == 4
+ (gdk_display_get_primary_clipboard(display));
+#endif
break;
case ClipboardType::CLIPBOARD:
- m_clipboard = vte::glib::make_ref(gtk_clipboard_get_for_display(display,
- GDK_SELECTION_CLIPBOARD));
+ m_clipboard = vte::glib::make_ref
+#if VTE_GTK == 3
+ (gtk_clipboard_get_for_display(display, GDK_SELECTION_CLIPBOARD));
+#elif VTE_GTK == 4
+ (gdk_display_get_clipboard(display));
+#endif
break;
}
@@ -55,6 +64,8 @@ Clipboard::Clipboard(Widget& delegate,
throw std::runtime_error{"Failed to create clipboard"};
}
+#if VTE_GTK == 3
+
class Clipboard::Offer {
public:
Offer(Clipboard& clipboard,
@@ -75,7 +86,7 @@ public:
{
auto [targets, n_targets] = targets_for_format(format);
- // Transfers clipboardship of *offer to the clipboard. If setting succeeds,
+ // Transfers ownership of *offer to the clipboard. If setting succeeds,
// the clipboard will own *offer until the clipboard_data_clear_cb
// callback is called.
// If setting the clipboard fails, the clear callback will never be
@@ -150,8 +161,8 @@ private:
guint info,
void* user_data) noexcept
{
- if (info != vte::to_integral(ClipboardFormat::TEXT) &&
- info != vte::to_integral(ClipboardFormat::HTML))
+ if (int(info) != vte::to_integral(ClipboardFormat::TEXT) &&
+ int(info) != vte::to_integral(ClipboardFormat::HTML))
return;
reinterpret_cast<Offer*>(user_data)->dispatch_get(ClipboardFormat(info), data);
@@ -161,12 +172,11 @@ private:
clipboard_clear_cb(GtkClipboard* clipboard,
void* user_data) noexcept
{
- // Assume ownership of the Request, and delete it after dispatching the callback
+ // Assume ownership of the Offer, and delete it after dispatching the callback
auto offer = std::unique_ptr<Offer>{reinterpret_cast<Offer*>(user_data)};
offer->dispatch_clear();
}
-
static std::pair<GtkTargetEntry*, int>
targets_for_format(ClipboardFormat format)
{
@@ -227,6 +237,8 @@ private:
}; // class Clipboard::Offer
+#endif /* VTE_GTK == 3 */
+
class Clipboard::Request {
public:
Request(Clipboard& clipboard,
@@ -244,10 +256,12 @@ public:
static void run(std::unique_ptr<Request> request) noexcept
{
+#if VTE_GTK == 3
auto platform = request->clipboard().platform();
gtk_clipboard_request_text(platform,
text_received_cb,
request.release());
+#endif /* VTE_GTK */
}
private:
@@ -255,6 +269,7 @@ private:
RequestDoneCallback m_done_callback;
RequestFailedCallback m_failed_callback;
+#if VTE_GTK == 3
void dispatch(char const *text) noexcept
try
{
@@ -278,6 +293,8 @@ private:
request->dispatch(text);
}
+#endif /* VTE_GTK */
+
}; // class Clipboard::Request
void
@@ -285,13 +302,17 @@ Clipboard::offer_data(ClipboardFormat format,
OfferGetCallback get_callback,
OfferClearCallback clear_callback) /* throws */
{
+#if VTE_GTK == 3
Offer::run(std::make_unique<Offer>(*this, get_callback, clear_callback), format);
+#endif
}
void
Clipboard::set_text(std::string_view const& text) noexcept
{
+#if VTE_GTK == 3
gtk_clipboard_set_text(platform(), text.data(), text.size());
+#endif
}
void
diff --git a/src/clipboard-gtk.hh b/src/clipboard-gtk.hh
index c1c6b2ff..26c62655 100644
--- a/src/clipboard-gtk.hh
+++ b/src/clipboard-gtk.hh
@@ -75,7 +75,11 @@ public:
RequestFailedCallback failed_callback) /* throws */;
private:
+#if VTE_GTK == 3
vte::glib::RefPtr<GtkClipboard> m_clipboard;
+#elif VTE_GTK == 4
+ vte::glib::RefPtr<GdkClipboard> m_clipboard;
+#endif
std::weak_ptr<Widget> m_delegate;
ClipboardType m_type;
diff --git a/src/debug.h b/src/debug.h
index 4526bba6..58d929ba 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -114,6 +114,12 @@ static void _vte_debug_print(guint flags, const char *fmt, ...)
#define _vte_debug_print(args...) do { } while(0)
#endif /* VTE_DEBUG */
+static inline char const*
+_vte_debug_tf(bool v) noexcept
+{
+ return v ? "true" : "false";
+}
+
G_END_DECLS
#endif
diff --git a/src/fonts-pangocairo.cc b/src/fonts-pangocairo.cc
index 5592a4f7..69f8a7a7 100644
--- a/src/fonts-pangocairo.cc
+++ b/src/fonts-pangocairo.cc
@@ -214,13 +214,13 @@ FontInfo::measure_font()
(void*)this, m_width, m_height, m_ascent);
}
-FontInfo::FontInfo(PangoContext *context)
+FontInfo::FontInfo(vte::glib::RefPtr<PangoContext> context)
{
_vte_debug_print (VTE_DEBUG_PANGOCAIRO,
"vtepangocairo: %p allocating FontInfo\n",
(void*)this);
- m_layout = vte::glib::take_ref(pango_layout_new(context));
+ m_layout = vte::glib::take_ref(pango_layout_new(context.get()));
auto tabs = pango_tab_array_new_with_positions(1, FALSE, PANGO_TAB_LEFT, 1);
pango_layout_set_tabs(m_layout.get(), tabs);
@@ -308,27 +308,6 @@ context_equal (PangoContext *a,
}
// FIXMEchpe return vte::base::RefPtr<FontInfo>
-/* assumes ownership/reference of context */
-FontInfo*
-FontInfo::find_for_context(vte::glib::RefPtr<PangoContext>& context)
-{
- if (G_UNLIKELY (s_font_info_for_context == nullptr))
- s_font_info_for_context = g_hash_table_new((GHashFunc) context_hash, (GEqualFunc)
context_equal);
-
- auto info = reinterpret_cast<FontInfo*>(g_hash_table_lookup(s_font_info_for_context, context.get()));
- if (G_LIKELY(info)) {
- _vte_debug_print (VTE_DEBUG_PANGOCAIRO,
- "vtepangocairo: %p found font_info in cache\n",
- info);
- info = info->ref();
- } else {
- info = new FontInfo{context.release()};
- }
-
- return info;
-}
-
-/* assumes ownership/reference of context */
FontInfo*
FontInfo::create_for_context(vte::glib::RefPtr<PangoContext> context,
PangoFontDescription const* desc,
@@ -362,9 +341,23 @@ FontInfo::create_for_context(vte::glib::RefPtr<PangoContext> context,
cairo_font_options_destroy (font_options);
}
- return find_for_context(context);
+ if (G_UNLIKELY (s_font_info_for_context == nullptr))
+ s_font_info_for_context = g_hash_table_new((GHashFunc) context_hash, (GEqualFunc)
context_equal);
+
+ auto info = reinterpret_cast<FontInfo*>(g_hash_table_lookup(s_font_info_for_context, context.get()));
+ if (G_LIKELY(info)) {
+ _vte_debug_print (VTE_DEBUG_PANGOCAIRO,
+ "vtepangocairo: %p found font_info in cache\n",
+ info);
+ info = info->ref();
+ } else {
+ info = new FontInfo{std::move(context)};
+ }
+
+ return info;
}
+#if VTE_GTK == 3
FontInfo*
FontInfo::create_for_screen(GdkScreen* screen,
PangoFontDescription const* desc,
@@ -376,15 +369,28 @@ FontInfo::create_for_screen(GdkScreen* screen,
return create_for_context(vte::glib::take_ref(gdk_pango_context_get_for_screen(screen)),
desc, language, fontconfig_timestamp);
}
+#endif /* VTE_GTK */
FontInfo*
FontInfo::create_for_widget(GtkWidget* widget,
PangoFontDescription const* desc)
{
- auto screen = gtk_widget_get_screen(widget);
- auto language = pango_context_get_language(gtk_widget_get_pango_context(widget));
+ auto context = gtk_widget_get_pango_context(widget);
+ auto language = pango_context_get_language(context);
+#if VTE_GTK == 3
+ auto screen = gtk_widget_get_screen(widget);
return create_for_screen(screen, desc, language);
+#elif VTE_GTK == 4
+ auto display = gtk_widget_get_display(widget);
+ auto settings = gtk_settings_get_for_display(display);
+ auto fontconfig_timestamp = guint{};
+ g_object_get (settings, "gtk-fontconfig-timestamp", &fontconfig_timestamp, nullptr);
+ return create_for_context(vte::glib::make_ref(context),
+ desc, language, fontconfig_timestamp);
+ // FIXMEgtk4: this uses a per-widget context, while the gtk3 code uses a per-screen
+ // one. That means there may be a lot less sharing and a lot more FontInfo's around?
+#endif
}
FontInfo::UnistrInfo*
diff --git a/src/fonts-pangocairo.hh b/src/fonts-pangocairo.hh
index f703e589..55de50ff 100644
--- a/src/fonts-pangocairo.hh
+++ b/src/fonts-pangocairo.hh
@@ -119,7 +119,7 @@ class FontInfo {
int const font_cache_timeout = 30; // seconds
public:
- FontInfo(PangoContext* context);
+ FontInfo(vte::glib::RefPtr<PangoContext> context);
~FontInfo();
FontInfo* ref()
@@ -264,14 +264,16 @@ private:
int m_coverage_count[4]{0, 0, 0, 0};
#endif
- static FontInfo* find_for_context(vte::glib::RefPtr<PangoContext>& context);
static FontInfo* create_for_context(vte::glib::RefPtr<PangoContext> context,
PangoFontDescription const* desc,
PangoLanguage* language,
guint fontconfig_timestamp);
+#if VTE_GTK == 3
static FontInfo *create_for_screen(GdkScreen* screen,
PangoFontDescription const* desc,
PangoLanguage* language);
+#endif
+
public:
static FontInfo *create_for_widget(GtkWidget* widget,
diff --git a/src/graphene-glue.hh b/src/graphene-glue.hh
new file mode 100644
index 00000000..16456117
--- /dev/null
+++ b/src/graphene-glue.hh
@@ -0,0 +1,48 @@
+/*
+ * Copyright © 2020 Christian Persch
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <cairo.h>
+#include <graphene.h>
+
+#include "std-glue.hh"
+
+namespace vte::graphene {
+
+inline constexpr auto
+make_rect(int x,
+ int y,
+ int width,
+ int height)
+{
+ return GRAPHENE_RECT_INIT(float(x), float(y), float(width), float(height));
+}
+
+inline constexpr auto
+make_rect(cairo_rectangle_int_t const* rect)
+{
+ return make_rect(rect->x, rect->y, rect->width, rect->height);
+}
+
+} // namespace vte::graphene
+
+namespace vte {
+
+// VTE_DECLARE_FREEABLE(graphene_rect_t, graphene_rect_free);
+
+} // namespace vte::cairo
diff --git a/src/gtk-glue.hh b/src/gtk-glue.hh
index 9a2e2959..20ff757b 100644
--- a/src/gtk-glue.hh
+++ b/src/gtk-glue.hh
@@ -25,6 +25,12 @@ namespace vte::gtk {
namespace vte {
+#if VTE_GTK == 3
VTE_DECLARE_FREEABLE(GtkTargetList, gtk_target_list_unref);
+#endif /* VTE_GTK == 3 */
+
+#if VTE_GTK == 4
+VTE_DECLARE_FREEABLE(GdkContentFormats, gdk_content_formats_unref);
+#endif /* VTE_GTK == 4 */
} // namespace vte
diff --git a/src/keymap.h b/src/keymap.h
index 64cf8d03..f899270c 100644
--- a/src/keymap.h
+++ b/src/keymap.h
@@ -26,8 +26,13 @@
G_BEGIN_DECLS
+#if VTE_GTK == 3
#define VTE_ALT_MASK GDK_MOD1_MASK
#define VTE_NUMLOCK_MASK GDK_MOD2_MASK
+#elif VTE_GTK == 4
+#define VTE_ALT_MASK GDK_ALT_MASK
+#define VTE_NUMLOCK_MASK 0 /* FIXME */
+#endif
/* Map the specified keyval/modifier setup, dependent on the mode, to either
* a literal string or a capability name. */
diff --git a/src/meson.build b/src/meson.build
index 208e93a0..a7cf341f 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -32,6 +32,10 @@ glib_glue_sources = files(
'glib-glue.hh',
)
+graphene_glue_sources = files(
+ 'graphene-glue.hh',
+)
+
gtk_glue_sources = files(
'gtk-glue.hh',
)
@@ -200,10 +204,6 @@ libvte_common_sources = config_sources + debug_sources + glib_glue_sources + gtk
'widget.hh',
)
-if get_option('a11y')
- libvte_common_sources += a11y_sources
-endif
-
if get_option('icu')
libvte_common_sources += icu_sources
endif
@@ -282,9 +282,13 @@ libvte_common_cppflags = [
if get_option('gtk3')
libvte_gtk3_sources = libvte_common_sources + libvte_gtk3_public_headers + libvte_gtk3_enum_sources
- libvte_gtk3_cppflags = libvte_common_cppflags + gtk3_version_cppflags
- libvte_gtk3_deps = libvte_common_deps + [gtk3_dep]
- libvte_gtk3_public_deps = libvte_common_public_deps + [gtk3_dep]
+ libvte_gtk3_cppflags = libvte_common_cppflags + gtk3_version_cppflags + ['-DVTE_GTK=3',]
+ libvte_gtk3_deps = libvte_common_deps + [gtk3_dep,]
+ libvte_gtk3_public_deps = libvte_common_public_deps + [gtk3_dep,]
+
+ if get_option('a11y')
+ libvte_gtk3_sources += a11y_sources
+ endif
libvte_gtk3 = shared_library(
vte_gtk3_api_name,
@@ -298,7 +302,7 @@ if get_option('gtk3')
libvte_gtk3_dep = declare_dependency(
sources: libvte_gtk3_public_headers,
- include_directories: [src_inc, vte_inc],
+ include_directories: [src_inc, vte_inc,],
dependencies: libvte_gtk3_deps,
link_with: libvte_gtk3
)
@@ -315,6 +319,41 @@ if get_option('gtk3')
)
endif
+if get_option('gtk4')
+ libvte_gtk4_sources = libvte_common_sources + libvte_gtk4_public_headers + libvte_gtk4_enum_sources +
graphene_glue_sources
+ libvte_gtk4_cppflags = libvte_common_cppflags + gtk4_version_cppflags + ['-DVTE_GTK=4',]
+ libvte_gtk4_deps = libvte_common_deps + [gtk4_dep,]
+ libvte_gtk4_public_deps = libvte_common_public_deps + [gtk4_dep,]
+
+ libvte_gtk4 = shared_library(
+ vte_gtk4_api_name,
+ sources: libvte_gtk4_sources,
+ version: libvte_gtk4_soversion,
+ include_directories: incs,
+ dependencies: libvte_gtk4_deps,
+ cpp_args: libvte_gtk4_cppflags,
+ install: true,
+ )
+
+ libvte_gtk4_dep = declare_dependency(
+ sources: libvte_gtk4_public_headers,
+ include_directories: [src_inc, vte_inc,],
+ dependencies: libvte_gtk4_deps,
+ link_with: libvte_gtk4
+ )
+
+ pkg.generate(
+ libvte_gtk4,
+ version: vte_version,
+ name: 'vte',
+ description: 'VTE widget for GTK+ 4.0',
+ filebase: vte_gtk4_api_name,
+ subdirs: vte_gtk4_api_name,
+ requires: libvte_gtk4_public_deps,
+ variables: 'exec_prefix=${prefix}',
+ )
+endif
+
## Tests
# decoder cat
@@ -413,17 +452,19 @@ reflect_textview = executable(
install: false,
)
-reflect_vte = executable(
- 'reflect-vte',
- sources: reflect_sources,
- dependencies: [gtk3_dep, libvte_gtk3_dep],
- c_args: [
- '-DUSE_VTE',
- '-DVTE_DISABLE_DEPRECATION_WARNINGS',
- ],
- include_directories: top_inc,
- install: false,
-)
+if get_option('gtk3')
+ reflect_vte = executable(
+ 'reflect-vte',
+ sources: reflect_sources,
+ dependencies: [gtk3_dep, libvte_gtk3_dep,],
+ c_args: [
+ '-DUSE_VTE',
+ '-DVTE_DISABLE_DEPRECATION_WARNINGS',
+ ],
+ include_directories: [top_inc,],
+ install: false,
+ )
+endif
# vte-urlencode-cwd
@@ -587,14 +628,16 @@ test_vtetypes_sources = config_sources + libc_glue_sources + files(
'vtetypes.hh',
)
-test_vtetypes = executable(
- 'test-vtetypes',
- sources: test_vtetypes_sources,
- dependencies: [glib_dep, pango_dep, gtk3_dep],
- cpp_args: ['-DMAIN'],
- include_directories: top_inc,
- install: false,
-)
+if get_option('gtk3')
+ test_vtetypes = executable(
+ 'test-vtetypes',
+ sources: test_vtetypes_sources,
+ dependencies: [glib_dep, pango_dep, gtk3_dep,],
+ cpp_args: ['-DMAIN'],
+ include_directories: top_inc,
+ install: false,
+ )
+endif
test_env = [
'VTE_DEBUG=0'
@@ -609,9 +652,14 @@ test_units = [
['stream', test_stream],
['tabstops', test_tabstops],
['utf8', test_utf8],
- ['vtetypes', test_vtetypes],
]
+if get_option('gtk3')
+ test_units += [
+ ['vtetypes', test_vtetypes],
+ ]
+endif
+
if get_option('sixel')
test_units += [
['sixel', test_sixel],
diff --git a/src/vte.cc b/src/vte.cc
index c7ee93ab..49805ced 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -1,11 +1,11 @@
/*
* Copyright (C) 2001-2004,2009,2010 Red Hat, Inc.
- * Copyright © 2008, 2009, 2010 Christian Persch
+ * Copyright © 2008, 2009, 2010, 2020 Christian Persch
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -50,6 +50,7 @@
#include "ringview.hh"
#include "caps.hh"
#include "widget.hh"
+#include "cairo-glue.hh"
#ifdef HAVE_WCHAR_H
#include <wchar.h>
@@ -73,8 +74,12 @@
#include "gobject-glue.hh"
#ifdef WITH_A11Y
+#if VTE_GTK == 3
#include "vteaccess.h"
-#endif
+#else
+#undef WITH_A11Y
+#endif /* VTE_GTK == 3 */
+#endif /* WITH_A11Y */
#include <new> /* placement new */
@@ -96,6 +101,12 @@ static inline double round(double x) {
#define VTE_DRAW_OPAQUE (1.0)
+#if VTE_GTK == 3
+#define VTE_STYLE_CLASS_READ_ONLY GTK_STYLE_CLASS_READ_ONLY
+#elif VTE_GTK == 4
+#define VTE_STYLE_CLASS_READ_ONLY "read-only"
+#endif
+
namespace vte {
namespace terminal {
@@ -107,7 +118,10 @@ static void remove_update_timeout(vte::terminal::Terminal* that);
static gboolean process_timeout (gpointer data) noexcept;
static gboolean update_timeout (gpointer data) noexcept;
-static cairo_region_t *vte_cairo_get_clip_region (cairo_t *cr);
+
+#if VTE_GTK == 3
+static vte::Freeable<cairo_region_t> vte_cairo_get_clip_region(cairo_t* cr);
+#endif
/* these static variables are guarded by the GDK mutex */
static guint process_timeout_tag = 0;
@@ -439,7 +453,11 @@ Terminal::invalidate_rows(vte::grid::row_t row_start,
rect.x += allocation.x + m_padding.left;
rect.y += allocation.y + m_padding.top;
cairo_region_t *region = cairo_region_create_rectangle(&rect);
+#if VTE_GTK == 3
gtk_widget_queue_draw_region(m_widget, region);
+#elif VTE_GTK == 4
+ gtk_widget_queue_draw(m_widget); // FIXMEchpe
+#endif
cairo_region_destroy(region);
}
@@ -1529,6 +1547,9 @@ Terminal::regex_match_check(vte::grid::column_t column,
vte::grid::row_t row,
int* tag)
{
+ /* Need to ensure the ringview is updated. */
+ ringview_update();
+
long delta = m_screen->scroll_delta;
_vte_debug_print(VTE_DEBUG_EVENTS | VTE_DEBUG_REGEX,
"Checking for match at (%ld,%ld).\n",
@@ -1569,7 +1590,11 @@ Terminal::regex_match_check(vte::grid::column_t column,
vte::view::coords
Terminal::view_coords_from_event(vte::platform::MouseEvent const& event) const
{
+#if VTE_GTK == 3
return vte::view::coords(event.x() - m_padding.left, event.y() - m_padding.top);
+#elif VTE_GTK == 4
+ return vte::view::coords(event.x(), event.y());
+#endif
}
bool
@@ -1817,10 +1842,50 @@ Terminal::rowcol_from_event(vte::platform::MouseEvent const& event,
return true;
}
-char *
+#if VTE_GTK == 4
+
+bool
+Terminal::rowcol_at(double x,
+ double y,
+ long* column,
+ long* row)
+{
+ auto rowcol = grid_coords_from_view_coords(vte::view::coords(x, y));
+ if (!grid_coords_visible(rowcol))
+ return false;
+
+ *column = rowcol.column();
+ *row = rowcol.row();
+ return true;
+}
+
+char*
+Terminal::hyperlink_check_at(double x,
+ double y)
+{
+ long col, row;
+ if (!rowcol_at(x, y, &col, &row))
+ return nullptr;
+
+ return hyperlink_check(col, row);
+}
+
+#endif /* VTE_GTK == 4 */
+
+char*
Terminal::hyperlink_check(vte::platform::MouseEvent const& event)
{
long col, row;
+ if (!rowcol_from_event(event, &col, &row))
+ return nullptr;
+
+ return hyperlink_check(col, row);
+}
+
+char*
+Terminal::hyperlink_check(vte::grid::column_t col,
+ vte::grid::row_t row)
+{
const char *hyperlink;
const char *separator;
@@ -1830,9 +1895,6 @@ Terminal::hyperlink_check(vte::platform::MouseEvent const& event)
/* Need to ensure the ringview is updated. */
ringview_update();
- if (!rowcol_from_event(event, &col, &row))
- return NULL;
-
_vte_ring_get_hyperlink_at_position(m_screen->row_data, row, col, false, &hyperlink);
if (hyperlink != NULL) {
@@ -1849,15 +1911,12 @@ Terminal::hyperlink_check(vte::platform::MouseEvent const& event)
return g_strdup(hyperlink);
}
-char *
+char*
Terminal::regex_match_check(vte::platform::MouseEvent const& event,
int *tag)
{
long col, row;
- /* Need to ensure the ringview is updated. */
- ringview_update();
-
if (!rowcol_from_event(event, &col, &row))
return FALSE;
@@ -1872,10 +1931,24 @@ Terminal::regex_match_check_extra(vte::platform::MouseEvent const& event,
size_t n_regexes,
uint32_t match_flags,
char** matches)
+{
+ long col, row;
+ if (!rowcol_from_event(event, &col, &row))
+ return false;
+
+ return regex_match_check_extra(col, row, regexes, n_regexes, match_flags, matches);
+}
+
+bool
+Terminal::regex_match_check_extra(vte::grid::column_t col,
+ vte::grid::row_t row,
+ vte::base::Regex const** regexes,
+ size_t n_regexes,
+ uint32_t match_flags,
+ char** matches)
{
gsize offset, sattr, eattr;
bool any_matches = false;
- long col, row;
guint i;
assert(regexes != nullptr || n_regexes == 0);
@@ -1884,9 +1957,6 @@ Terminal::regex_match_check_extra(vte::platform::MouseEvent const& event,
/* Need to ensure the ringview is updated. */
ringview_update();
- if (!rowcol_from_event(event, &col, &row))
- return false;
-
if (m_match_contents == nullptr) {
match_contents_refresh();
}
@@ -4585,10 +4655,11 @@ Terminal::beep()
bool
Terminal::widget_key_press(vte::platform::KeyEvent const& event)
{
+ auto handled = false;
char *normal = NULL;
gsize normal_length = 0;
struct termios tio;
- gboolean scrolled = FALSE, steal = FALSE, modifier = FALSE, handled,
+ gboolean scrolled = FALSE, steal = FALSE, modifier = FALSE,
suppress_alt_esc = FALSE, add_modifiers = FALSE;
guint keyval = 0;
gunichar keychar = 0;
@@ -4616,12 +4687,6 @@ Terminal::widget_key_press(vte::platform::KeyEvent const& event)
set_pointer_autohidden(true);
}
- _vte_debug_print(VTE_DEBUG_EVENTS,
- "Keypress, modifiers=0x%x, "
- "keyval=0x%x\n",
- m_modifiers,
- keyval);
-
/* We steal many keypad keys here. */
if (!m_im_preedit_active) {
switch (keyval) {
@@ -4711,6 +4776,7 @@ Terminal::widget_key_press(vte::platform::KeyEvent const& event)
/* Let the input method at this one first. */
if (!steal && m_input_enabled) {
+ // FIXMEchpe FIXMEgtk4: update IM position? im_set_cursor_location()
if (m_real_widget->im_filter_keypress(event)) {
_vte_debug_print(VTE_DEBUG_EVENTS,
"Keypress taken by IM.\n");
@@ -5042,6 +5108,16 @@ Terminal::widget_key_press(vte::platform::KeyEvent const& event)
}
return true;
}
+
+#if VTE_GTK == 4
+ if (!handled &&
+ event.matches(GDK_KEY_Menu, 0)) {
+ _vte_debug_print(VTE_DEBUG_EVENTS, "Showing context menu\n");
+ // FIXMEgtk4 do context menu
+ handled = true;
+ }
+#endif
+
return false;
}
@@ -5962,6 +6038,8 @@ Terminal::invalidate_match_span()
void
Terminal::match_hilite_update()
{
+ _vte_debug_print(VTE_DEBUG_EVENTS, "Match hilite update\n");
+
/* Need to ensure the ringview is updated. */
ringview_update();
@@ -5975,10 +6053,6 @@ Terminal::match_hilite_update()
vte::base::BidiRow const* bidirow = m_ringview.get_bidirow(confine_grid_row(row));
col = bidirow->vis2log(col);
- _vte_debug_print(VTE_DEBUG_EVENTS,
- "Match hilite update (%ld, %ld) -> %ld, %ld\n",
- pos.x, pos.y, col, row);
-
/* Whether there's any chance we'd highlight something */
bool do_check_hilite = view_coords_visible(pos) &&
m_mouse_cursor_over_widget &&
@@ -6770,8 +6844,7 @@ Terminal::widget_mouse_motion(vte::platform::MouseEvent const& event)
auto rowcol = grid_coords_from_view_coords(pos);
_vte_debug_print(VTE_DEBUG_EVENTS,
- "Motion notify %s %s\n",
- pos.to_string(), rowcol.to_string());
+ "Motion grid %s\n", rowcol.to_string());
m_modifiers = event.modifiers();
@@ -6826,17 +6899,22 @@ Terminal::widget_mouse_press(vte::platform::MouseEvent const& event)
/* Need to ensure the ringview is updated. */
ringview_update();
+ /* Reset IM (like GtkTextView does) here */
+ if (event.press_count() == 1)
+ widget()->im_reset();
+
auto pos = view_coords_from_event(event);
auto rowcol = grid_coords_from_view_coords(pos);
+ _vte_debug_print(VTE_DEBUG_EVENTS,
+ "Click gesture pressed button=%d at grid %s\n",
+ event.button_value(),
+ rowcol.to_string());
+
m_modifiers = event.modifiers();
switch (event.press_count()) {
case 1: /* single click */
- _vte_debug_print(VTE_DEBUG_EVENTS,
- "Button %d single-click at %s\n",
- event.button_value(),
- rowcol.to_string());
/* Handle this event ourselves. */
switch (event.button()) {
case vte::platform::MouseEvent::Button::eLEFT:
@@ -6846,6 +6924,8 @@ Terminal::widget_mouse_press(vte::platform::MouseEvent const& event)
if (!m_has_focus)
widget()->grab_focus();
+ // FIXMEchpe FIXMEgtk do im_reset() here
+
/* If we're in event mode, and the user held down the
* shift key, we start selecting. */
if (m_mouse_tracking_mode != MouseTrackingMode::eNONE) {
@@ -6906,10 +6986,6 @@ Terminal::widget_mouse_press(vte::platform::MouseEvent const& event)
}
break;
case 2: /* double click */
- _vte_debug_print(VTE_DEBUG_EVENTS,
- "Button %d double-click at %s\n",
- event.button_value(),
- rowcol.to_string());
switch (event.button()) {
case vte::platform::MouseEvent::Button::eLEFT:
if (m_will_select_after_threshold) {
@@ -6930,10 +7006,6 @@ Terminal::widget_mouse_press(vte::platform::MouseEvent const& event)
}
break;
case 3: /* triple click */
- _vte_debug_print(VTE_DEBUG_EVENTS,
- "Button %d triple-click at %s\n",
- event.button_value(),
- rowcol.to_string());
switch (event.button()) {
case vte::platform::MouseEvent::Button::eLEFT:
if ((m_mouse_handled_buttons & 1) != 0) {
@@ -6951,6 +7023,16 @@ Terminal::widget_mouse_press(vte::platform::MouseEvent const& event)
break;
}
+#if VTE_GTK == 4
+ if (!handled &&
+ ((event.button() == vte::platform::MouseEvent::Button::eRIGHT) ||
+ !(event.modifiers() & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK)))) {
+ _vte_debug_print(VTE_DEBUG_EVENTS, "Showing context menu\n");
+ // FIXMEgtk4 context menu
+ handled = true;
+ }
+#endif /* VTE_GTK == 4 */
+
/* Save the pointer state for later use. */
if (event.button_value() >= 1 && event.button_value() <= 3)
m_mouse_pressed_buttons |= (1 << (event.button_value() - 1));
@@ -6975,15 +7057,16 @@ Terminal::widget_mouse_release(vte::platform::MouseEvent const& event)
auto pos = view_coords_from_event(event);
auto rowcol = grid_coords_from_view_coords(pos);
+ _vte_debug_print(VTE_DEBUG_EVENTS,
+ "Click gesture released button=%d at grid %s\n",
+ event.button_value(), rowcol.to_string());
+
stop_autoscroll();
m_modifiers = event.modifiers();
switch (event.type()) {
case vte::platform::EventBase::Type::eMOUSE_RELEASE:
- _vte_debug_print(VTE_DEBUG_EVENTS,
- "Button %d released at %s\n",
- event.button_value(), rowcol.to_string());
switch (event.button()) {
case vte::platform::MouseEvent::Button::eLEFT:
if ((m_mouse_handled_buttons & 1) != 0)
@@ -7022,8 +7105,6 @@ Terminal::widget_mouse_release(vte::platform::MouseEvent const& event)
void
Terminal::widget_focus_in()
{
- _vte_debug_print(VTE_DEBUG_EVENTS, "Focus in.\n");
-
m_has_focus = true;
widget()->grab_focus();
@@ -7051,8 +7132,6 @@ Terminal::widget_focus_in()
void
Terminal::widget_focus_out()
{
- _vte_debug_print(VTE_DEBUG_EVENTS, "Focus out.\n");
-
/* We only have an IM context when we're realized, and there's not much
* point to painting ourselves if we don't have a window. */
if (widget_realized()) {
@@ -7085,8 +7164,9 @@ Terminal::widget_mouse_enter(vte::platform::MouseEvent const& event)
auto pos = view_coords_from_event(event);
// FIXMEchpe read event modifiers here
+ // FIXMEgtk4 or maybe not since there is no event to read them from on gtk4
- _vte_debug_print(VTE_DEBUG_EVENTS, "Enter at %s\n", pos.to_string());
+ _vte_debug_print(VTE_DEBUG_EVENTS, "Motion enter at grid %s\n", pos.to_string());
m_mouse_cursor_over_widget = TRUE;
m_mouse_last_position = pos;
@@ -7100,14 +7180,23 @@ Terminal::widget_mouse_enter(vte::platform::MouseEvent const& event)
void
Terminal::widget_mouse_leave(vte::platform::MouseEvent const& event)
{
+#if VTE_GTK == 3
auto pos = view_coords_from_event(event);
// FIXMEchpe read event modifiers here
+ // FIXMEgtk4 or maybe not since there is no event to read them from on gtk4
- _vte_debug_print(VTE_DEBUG_EVENTS, "Leave at %s\n", pos.to_string());
+ _vte_debug_print(VTE_DEBUG_EVENTS, "Motion leave at grid %s\n", pos.to_string());
m_mouse_cursor_over_widget = FALSE;
m_mouse_last_position = pos;
+#elif VTE_GTK == 4
+ // FIXMEgtk4 !!!
+ m_mouse_cursor_over_widget = false;
+ // keep m_mouse_last_position since the event here has no position
+#endif
+
+ // FIXMEchpe: also set m_mouse_scroll_delta to 0 here?
hyperlink_hilite_update();
match_hilite_update();
@@ -7195,7 +7284,11 @@ Terminal::apply_font_metrics(int cell_width_unscaled,
/* Queue a resize if anything's changed. */
if (resize) {
if (widget_realized()) {
+#if VTE_GTK == 3
gtk_widget_queue_resize_no_redraw(m_widget);
+#elif VTE_GTK == 4
+ gtk_widget_queue_resize(m_widget); // FIXMEchpe?
+#endif
}
}
/* Emit a signal that the font changed. */
@@ -7301,6 +7394,7 @@ Terminal::update_font()
bool
Terminal::set_font_desc(PangoFontDescription const* font_desc)
{
+#if VTE_GTK == 3
auto desc = vte::Freeable<PangoFontDescription>{};
auto context = gtk_widget_get_style_context(m_widget);
@@ -7310,6 +7404,16 @@ Terminal::set_font_desc(PangoFontDescription const* font_desc)
&vte::get_freeable(desc),
nullptr);
gtk_style_context_restore(context);
+#elif VTE_GTK == 4
+ // FIXMEgtk4
+ // This is how gtktextview does it, but the APIs are private... thanks, gtk4!
+ // desc = vte::take_freeable
+ // (gtk_css_style_get_pango_font(gtk_style_context_lookup_style(context));
+
+ auto context = gtk_widget_get_pango_context(m_widget);
+ auto context_desc = pango_context_get_font_description(context);
+ auto desc = vte::take_freeable(pango_font_description_copy(context_desc));
+#endif /* VTE_GTK */
pango_font_description_set_family_static(desc.get(), "monospace");
if (font_desc != nullptr) {
@@ -7611,7 +7715,11 @@ Terminal::set_size(long columns,
_vte_ring_next (m_screen->row_data) - 1));
adjust_adjustments_full();
+#if VTE_GTK == 3
gtk_widget_queue_resize_no_redraw(m_widget);
+#elif VTE_GTK == 4
+ gtk_widget_queue_resize(m_widget); // FIXMEchpe?
+#endif
/* Our visible text changed. */
emit_text_modified();
}
@@ -7776,11 +7884,9 @@ Terminal::Terminal(vte::platform::Widget* w,
}
void
-Terminal::widget_get_preferred_width(int *minimum_width,
- int *natural_width)
+Terminal::widget_measure_width(int *minimum_width,
+ int *natural_width)
{
- _vte_debug_print(VTE_DEBUG_LIFECYCLE, "vte_terminal_get_preferred_width()\n");
-
ensure_font();
refresh_size();
@@ -7803,11 +7909,9 @@ Terminal::widget_get_preferred_width(int *minimum_width,
}
void
-Terminal::widget_get_preferred_height(int *minimum_height,
- int *natural_height)
+Terminal::widget_measure_height(int *minimum_height,
+ int *natural_height)
{
- _vte_debug_print(VTE_DEBUG_LIFECYCLE, "vte_terminal_get_preferred_height()\n");
-
ensure_font();
refresh_size();
@@ -7830,7 +7934,9 @@ Terminal::widget_get_preferred_height(int *minimum_height,
}
void
-Terminal::widget_size_allocate(GtkAllocation *allocation)
+Terminal::widget_size_allocate(int allocation_width,
+ int allocation_height,
+ int allocation_baseline)
{
glong width, height;
gboolean repaint, update_scrollback;
@@ -7838,9 +7944,9 @@ Terminal::widget_size_allocate(GtkAllocation *allocation)
_vte_debug_print(VTE_DEBUG_LIFECYCLE,
"vte_terminal_size_allocate()\n");
- width = (allocation->width - (m_padding.left + m_padding.right)) /
+ width = (allocation_width - (m_padding.left + m_padding.right)) /
m_cell_width;
- height = (allocation->height - (m_padding.top + m_padding.bottom)) /
+ height = (allocation_height - (m_padding.top + m_padding.bottom)) /
m_cell_height;
width = MAX(width, 1);
height = MAX(height, 1);
@@ -7848,19 +7954,26 @@ Terminal::widget_size_allocate(GtkAllocation *allocation)
_vte_debug_print(VTE_DEBUG_WIDGET_SIZE,
"[Terminal %p] Sizing window to %dx%d (%ldx%ld, padding %d,%d;%d,%d).\n",
m_terminal,
- allocation->width, allocation->height,
+ allocation_width, allocation_height,
width, height,
m_padding.left, m_padding.right, m_padding.top, m_padding.bottom);
auto current_allocation = get_allocated_rect();
- repaint = current_allocation.width != allocation->width
- || current_allocation.height != allocation->height;
- update_scrollback = current_allocation.height != allocation->height;
+ repaint = current_allocation.width != allocation_width ||
+ current_allocation.height != allocation_height;
+ update_scrollback = current_allocation.height != allocation_height;
- /* Set our allocation to match the structure. */
- gtk_widget_set_allocation(m_widget, allocation);
- set_allocated_rect(*allocation);
+#if VTE_GTK == 3
+ auto const allocation = GtkAllocation{0, 0, allocation_width, allocation_height};
+ gtk_widget_set_allocation(m_widget, &allocation);
+ set_allocated_rect(allocation);
+#elif VTE_GTK == 4
+ gtk_widget_allocate(m_widget,
+ allocation_width, allocation_height,
+ allocation_baseline, nullptr);
+ set_allocated_rect({0, 0, allocation_width, allocation_height});
+#endif
if (width != m_column_count
|| height != m_row_count
@@ -7927,8 +8040,9 @@ Terminal::set_blink_settings(bool blink,
int blink_time,
int blink_timeout) noexcept
{
- m_cursor_blink_cycle = blink_time / 2;
- m_cursor_blink_timeout = blink_timeout;
+ m_cursor_blinks = blink;
+ m_cursor_blink_cycle = std::max(blink_time / 2, VTE_MIN_CURSOR_BLINK_CYCLE);
+ m_cursor_blink_timeout = std::max(blink_timeout, VTE_MIN_CURSOR_BLINK_TIMEOUT);
update_cursor_blinks();
@@ -9200,6 +9314,7 @@ Terminal::paint_im_preedit_string()
height,
get_color(VTE_DEFAULT_BG), m_background_alpha);
}
+
draw_cells_with_attributes(
items, len,
m_im_preedit_attrs.get(),
@@ -9226,11 +9341,41 @@ Terminal::paint_im_preedit_string()
}
}
+#if VTE_GTK == 3
+
+void
+Terminal::widget_draw(cairo_t* cr)
+{
+#ifdef VTE_DEBUG
+ _VTE_DEBUG_IF(VTE_DEBUG_LIFECYCLE | VTE_DEBUG_WORK | VTE_DEBUG_UPDATES) do {
+ auto clip_rect = cairo_rectangle_int_t{};
+ if (!gdk_cairo_get_clip_rectangle (cr, &clip_rect))
+ break;
+
+ _vte_debug_print(VTE_DEBUG_LIFECYCLE, "vte_terminal_draw()\n");
+ _vte_debug_print (VTE_DEBUG_WORK, "+");
+ _vte_debug_print (VTE_DEBUG_UPDATES, "Draw (%d,%d)x(%d,%d)\n",
+ clip_rect.x, clip_rect.y,
+ clip_rect.width, clip_rect.height);
+ } while (0);
+#endif /* VTE_DEBUG */
+
+ auto region = vte_cairo_get_clip_region (cr);
+ if (!region)
+ return;
+
+ /* Transform to view coordinates */
+ cairo_region_translate(region.get(), -m_padding.left, -m_padding.top);
+
+ draw(cr, region.get());
+}
+
+#endif /* VTE_GTK == 3 */
+
void
-Terminal::widget_draw(cairo_t *cr)
+Terminal::draw(cairo_t* cr,
+ cairo_region_t const* region)
{
- cairo_rectangle_int_t clip_rect;
- cairo_region_t *region;
int allocated_width, allocated_height;
int extra_area_for_cursor;
bool text_blink_enabled_now;
@@ -9239,19 +9384,6 @@ Terminal::widget_draw(cairo_t *cr)
#endif
gint64 now = 0;
- if (!gdk_cairo_get_clip_rectangle (cr, &clip_rect))
- return;
-
- _vte_debug_print(VTE_DEBUG_LIFECYCLE, "vte_terminal_draw()\n");
- _vte_debug_print (VTE_DEBUG_WORK, "+");
- _vte_debug_print (VTE_DEBUG_UPDATES, "Draw (%d,%d)x(%d,%d)\n",
- clip_rect.x, clip_rect.y,
- clip_rect.width, clip_rect.height);
-
- region = vte_cairo_get_clip_region (cr);
- if (region == NULL)
- return;
-
allocated_width = get_allocated_width();
allocated_height = get_allocated_height();
@@ -9272,9 +9404,6 @@ Terminal::widget_draw(cairo_t *cr)
cairo_translate(cr, m_padding.left, m_padding.top);
- /* Transform to view coordinates */
- cairo_region_translate(region, -m_padding.left, -m_padding.top);
-
#ifdef WITH_SIXEL
/* Draw images */
if (m_images_enabled) {
@@ -9343,8 +9472,6 @@ Terminal::widget_draw(cairo_t *cr)
/* Done with various structures. */
m_draw.set_cairo(nullptr);
- cairo_region_destroy (region);
-
/* If painting encountered any cell with blink attribute, we might need to set up a timer.
* Blinking is implemented using a one-shot (not repeating) timer that keeps getting reinstalled
* here as long as blinking cells are encountered during (re)painting. This way there's no need
@@ -9358,47 +9485,43 @@ Terminal::widget_draw(cairo_t *cr)
m_invalidated_all = FALSE;
}
+#if VTE_GTK == 3
+
/* Handle an expose event by painting the exposed area. */
-static cairo_region_t *
+static vte::Freeable<cairo_region_t>
vte_cairo_get_clip_region (cairo_t *cr)
{
- cairo_rectangle_list_t *list;
- cairo_region_t *region;
- int i;
-
- list = cairo_copy_clip_rectangle_list (cr);
+ auto list = vte::take_freeable(cairo_copy_clip_rectangle_list(cr));
if (list->status == CAIRO_STATUS_CLIP_NOT_REPRESENTABLE) {
- cairo_rectangle_int_t clip_rect;
- cairo_rectangle_list_destroy (list);
+ auto clip_rect = cairo_rectangle_int_t{};
+ if (!gdk_cairo_get_clip_rectangle(cr, &clip_rect))
+ return nullptr;
- if (!gdk_cairo_get_clip_rectangle (cr, &clip_rect))
- return NULL;
- return cairo_region_create_rectangle (&clip_rect);
+ return vte::take_freeable(cairo_region_create_rectangle(&clip_rect));
}
+ auto region = vte::take_freeable(cairo_region_create());
+ for (auto i = list->num_rectangles - 1; i >= 0; --i) {
+ auto rect = &list->rectangles[i];
- region = cairo_region_create ();
- for (i = list->num_rectangles - 1; i >= 0; --i) {
- cairo_rectangle_t *rect = &list->rectangles[i];
cairo_rectangle_int_t clip_rect;
-
clip_rect.x = floor (rect->x);
clip_rect.y = floor (rect->y);
clip_rect.width = ceil (rect->x + rect->width) - clip_rect.x;
clip_rect.height = ceil (rect->y + rect->height) - clip_rect.y;
- if (cairo_region_union_rectangle (region, &clip_rect) != CAIRO_STATUS_SUCCESS) {
- cairo_region_destroy (region);
- region = NULL;
+ if (cairo_region_union_rectangle(region.get(), &clip_rect) != CAIRO_STATUS_SUCCESS) {
+ region.reset();
break;
}
}
- cairo_rectangle_list_destroy (list);
return region;
}
+#endif /* VTE_GTK == 3 */
+
bool
Terminal::widget_mouse_scroll(vte::platform::ScrollEvent const& event)
{
@@ -9626,15 +9749,11 @@ Terminal::set_rewrap_on_resize(bool rewrap)
void
Terminal::update_cursor_blinks()
{
- bool blink = false;
+ auto blink = false;
switch (decscusr_cursor_blink()) {
case CursorBlinkMode::eSYSTEM:
- gboolean v;
- g_object_get(gtk_widget_get_settings(m_widget),
- "gtk-cursor-blink",
- &v, nullptr);
- blink = v != FALSE;
+ blink = m_cursor_blinks_system;
break;
case CursorBlinkMode::eON:
blink = true;
@@ -10481,6 +10600,7 @@ Terminal::invalidate_dirty_rects_and_process_updates()
if (G_UNLIKELY (!m_update_rects->len))
return false;
+#if VTE_GTK == 3
auto region = cairo_region_create();
auto n_rects = m_update_rects->len;
for (guint i = 0; i < n_rects; i++) {
@@ -10498,6 +10618,9 @@ Terminal::invalidate_dirty_rects_and_process_updates()
/* and perform the merge with the window visible area */
gtk_widget_queue_draw_region(m_widget, region);
cairo_region_destroy (region);
+#elif VTE_GTK == 4
+ gtk_widget_queue_draw(m_widget);
+#endif
return true;
}
@@ -10902,7 +11025,7 @@ Terminal::set_input_enabled (bool enabled)
if (m_has_focus)
widget()->im_focus_in();
- gtk_style_context_remove_class (context, GTK_STYLE_CLASS_READ_ONLY);
+ gtk_style_context_remove_class (context, VTE_STYLE_CLASS_READ_ONLY);
} else {
im_reset();
if (m_has_focus)
@@ -10911,7 +11034,7 @@ Terminal::set_input_enabled (bool enabled)
disconnect_pty_write();
_vte_byte_array_clear(m_outgoing);
- gtk_style_context_add_class (context, GTK_STYLE_CLASS_READ_ONLY);
+ gtk_style_context_add_class (context, VTE_STYLE_CLASS_READ_ONLY);
}
return true;
diff --git a/src/vte/meson.build b/src/vte/meson.build
index 20ddabce..f3916e02 100644
--- a/src/vte/meson.build
+++ b/src/vte/meson.build
@@ -16,21 +16,6 @@
vte_inc = include_directories('.')
-libvte_common_enum_headers = files(
- # These files contain enums to be extracted by glib-mkenums
- 'vtedeprecated.h',
- 'vteenums.h',
-)
-
-libvte_gtk3_enum_sources = gnome.mkenums(
- 'vtetypebuiltins.h',
- sources: libvte_common_enum_headers,
- c_template: '../vtetypebuiltins.cc.template',
- h_template: '../vtetypebuiltins.h.template',
- install_header: true,
- install_dir: vte_includedir / vte_gtk3_api_path
-)
-
libvte_common_public_headers = files(
'vte.h',
'vtedeprecated.h',
@@ -40,31 +25,111 @@ libvte_common_public_headers = files(
'vtepty.h',
'vteregex.h',
'vteterminal.h',
+ 'vtetypebuiltins.h',
)
+libvte_common_enum_headers = files(
+ # These files contain enums to be extracted by glib-mkenums
+ 'vtedeprecated.h',
+ 'vteenums.h',
+)
+
+# Version header
+
vteversion_conf = configuration_data()
vteversion_conf.set('VTE_MAJOR_VERSION', vte_major_version)
vteversion_conf.set('VTE_MINOR_VERSION', vte_minor_version)
vteversion_conf.set('VTE_MICRO_VERSION', vte_micro_version)
-libvte_version_headers = configure_file(
+libvte_common_public_headers += configure_file(
input: 'vteversion.h.in',
output: '@BASENAME@',
configuration: vteversion_conf,
install: false,
)
+# Install headers, and create the type builtin files.
+# Note that we cannot use gnome.mkenums() to create the type builtins
+# files, since we need to install the generated header for both gtk3
+# and gtk4, and gnome.mkenums does not work with install_header()
+# [https://github.com/mesonbuild/meson/issues/1687]. However, neither does
+# custom_target() itself.
+# so we need to generate differently-named files for gtk3 and gtk4, and
+# install them sepearately, with an extra header that includes the right
+# one. And since gnome.mkenums() does not allow specifying the output names
+# when using templates, we need to use custom_target() for that.
+glib_mkenums = find_program('glib-mkenums')
+
if get_option('gtk3')
- libvte_gtk3_public_headers = libvte_common_public_headers + [libvte_version_headers]
+
+ libvte_gtk3_public_headers = libvte_common_public_headers
install_headers(
libvte_gtk3_public_headers,
subdir: vte_gtk3_api_path
)
- # BUG! Due to meson bug, this header cannot be installed with the rule above. Instead,
- # use the install_header attribute in the mkenums call, and add the header afterwards
- # to the list.
- libvte_gtk3_public_headers += libvte_gtk3_enum_sources[1]
+ libvte_gtk3_public_headers += custom_target(
+ 'vtetypebuiltins-gtk3.h',
+ command: [
+ glib_mkenums,
+ '--output', '@OUTPUT@',
+ '--template', meson.current_source_dir() / '..' / 'vtetypebuiltins.h.template',
+ '@INPUT@',
+ ],
+ input: libvte_common_enum_headers,
+ install: true,
+ install_dir: vte_includedir / vte_gtk3_api_path,
+ output: 'vtetypebuiltins-gtk3.h',
+ )
+
+ libvte_gtk3_enum_sources = [custom_target(
+ 'vtetypebuiltins-gtk3.cc',
+ command: [
+ glib_mkenums,
+ '--output', '@OUTPUT@',
+ '--template', meson.current_source_dir() / '..' / 'vtetypebuiltins.cc.template',
+ '@INPUT@',
+ ],
+ input: libvte_common_enum_headers,
+ install: false,
+ output: 'vtetypebuiltins-gtk3.cc',
+ ),]
+endif
+
+if get_option('gtk4')
+
+ libvte_gtk4_public_headers = libvte_common_public_headers
+
+ install_headers(
+ libvte_gtk4_public_headers,
+ subdir: vte_gtk4_api_path
+ )
+
+ libvte_gtk4_public_headers += custom_target(
+ 'vtetypebuiltins-gtk4.h',
+ command: [
+ glib_mkenums,
+ '--output', '@OUTPUT@',
+ '--template', meson.current_source_dir() / '..' / 'vtetypebuiltins.h.template',
+ '@INPUT@',
+ ],
+ input: libvte_common_enum_headers,
+ install: true,
+ install_dir: vte_includedir / vte_gtk4_api_path,
+ output: 'vtetypebuiltins-gtk4.h',
+ )
+ libvte_gtk4_enum_sources = [custom_target(
+ 'vtetypebuiltins-gtk4.cc',
+ command: [
+ glib_mkenums,
+ '--output', '@OUTPUT@',
+ '--template', meson.current_source_dir() / '..' / 'vtetypebuiltins.cc.template',
+ '@INPUT@',
+ ],
+ input: libvte_common_enum_headers,
+ install: false,
+ output: 'vtetypebuiltins-gtk4.cc',
+ ),]
endif
diff --git a/src/vte/vte.h b/src/vte/vte.h
index 1d7cb1b8..07f98d23 100644
--- a/src/vte/vte.h
+++ b/src/vte/vte.h
@@ -19,9 +19,13 @@
#pragma once
#include <glib.h>
+#include <gtk/gtk.h>
#define __VTE_VTE_H_INSIDE__ 1
+/* This must always be included first */
+#include "vtemacros.h"
+
#include "vteenums.h"
#include "vteglobals.h"
#include "vtepty.h"
diff --git a/src/vte/vtedeprecated.h b/src/vte/vtedeprecated.h
index 27e37199..aa6e6c51 100644
--- a/src/vte/vtedeprecated.h
+++ b/src/vte/vtedeprecated.h
@@ -46,11 +46,13 @@ void vte_terminal_match_set_cursor(VteTerminal *terminal,
int tag,
GdkCursor *cursor) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1);
+#if _VTE_GTK == 3
_VTE_DEPRECATED
_VTE_PUBLIC
void vte_terminal_match_set_cursor_type(VteTerminal *terminal,
int tag,
GdkCursorType cursor_type) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1);
+#endif
_VTE_DEPRECATED
_VTE_PUBLIC
@@ -58,6 +60,8 @@ char *vte_terminal_match_check(VteTerminal *terminal,
glong column, glong row,
int *tag) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1) G_GNUC_MALLOC;
+#if _VTE_GTK == 3
+
_VTE_DEPRECATED
_VTE_PUBLIC
gboolean vte_terminal_event_check_gregex_simple(VteTerminal *terminal,
@@ -67,6 +71,8 @@ gboolean vte_terminal_event_check_gregex_simple(VteTerminal *terminal,
GRegexMatchFlags match_flags,
char **matches) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1)
_VTE_GNUC_NONNULL(2);
+#endif /* _VTE_GTK == 3 */
+
_VTE_DEPRECATED
_VTE_PUBLIC
void vte_terminal_search_set_gregex (VteTerminal *terminal,
@@ -99,6 +105,8 @@ _VTE_DEPRECATED
_VTE_PUBLIC
void vte_terminal_copy_clipboard(VteTerminal *terminal) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1);
+#if _VTE_GTK == 3
+
_VTE_DEPRECATED
_VTE_PUBLIC
void vte_terminal_get_geometry_hints(VteTerminal *terminal,
@@ -111,6 +119,8 @@ _VTE_PUBLIC
void vte_terminal_set_geometry_hints_for_window(VteTerminal *terminal,
GtkWindow *window) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1)
_VTE_GNUC_NONNULL(2);
+#endif /* _VTE_GTK == 3 */
+
_VTE_DEPRECATED
_VTE_PUBLIC
const char *vte_terminal_get_icon_title(VteTerminal *terminal) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1);
diff --git a/src/vte/vtemacros.h b/src/vte/vtemacros.h
index 4e21ff04..7aac0655 100644
--- a/src/vte/vtemacros.h
+++ b/src/vte/vtemacros.h
@@ -22,6 +22,18 @@
#error "Only <vte/vte.h> can be included directly."
#endif
+#include <gtk/gtk.h>
+
+#if GTK_CHECK_VERSION(4,0,0)
+#define _VTE_GTK 4
+#elif GTK_CHECK_VERSION(3,90,0)
+#error gtk+ version not supported
+#elif GTK_CHECK_VERSION(3,0,0)
+#define _VTE_GTK 3
+#else
+#error gtk+ version unknown
+#endif
+
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 6)
#define _VTE_GNUC_PACKED __attribute__((__packed__))
#else
diff --git a/src/vte/vteterminal.h b/src/vte/vteterminal.h
index a5471fd0..6301172b 100644
--- a/src/vte/vteterminal.h
+++ b/src/vte/vteterminal.h
@@ -51,8 +51,10 @@ typedef struct _VteCharAttributes VteCharAttributes;
*/
struct _VteTerminal {
GtkWidget widget;
+#if _VTE_GTK == 3
/*< private >*/
gpointer *_unused_padding[1]; /* FIXMEchpe: remove this field on the next ABI break */
+#endif
};
/**
@@ -396,10 +398,14 @@ void vte_terminal_get_cursor_position(VteTerminal *terminal,
glong *column,
glong *row) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1);
+#if _VTE_GTK == 3
+
_VTE_PUBLIC
char *vte_terminal_hyperlink_check_event(VteTerminal *terminal,
GdkEvent *event) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1)
_VTE_GNUC_NONNULL(2) G_GNUC_MALLOC;
+#endif /* _VTE_GTK */
+
/* Add a matching expression, returning the tag the widget assigns to that
* expression. */
_VTE_PUBLIC
@@ -420,10 +426,13 @@ void vte_terminal_match_remove_all(VteTerminal *terminal) _VTE_CXX_NOEXCEPT _VTE
/* Check if a given cell on the screen contains part of a matched string. If
* it does, return the string, and store the match tag in the optional tag
* argument. */
+#if _VTE_GTK == 3
+
_VTE_PUBLIC
char *vte_terminal_match_check_event(VteTerminal *terminal,
GdkEvent *event,
int *tag) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1) _VTE_GNUC_NONNULL(2)
G_GNUC_MALLOC;
+
_VTE_PUBLIC
char **vte_terminal_event_check_regex_array(VteTerminal *terminal,
GdkEvent *event,
@@ -439,6 +448,8 @@ gboolean vte_terminal_event_check_regex_simple(VteTerminal *terminal,
guint32 match_flags,
char **matches) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1)
_VTE_GNUC_NONNULL(2);
+#endif /* _VTE_GTK */
+
_VTE_PUBLIC
void vte_terminal_search_set_regex (VteTerminal *terminal,
VteRegex *regex,
diff --git a/src/vte/vtetypebuiltins.h b/src/vte/vtetypebuiltins.h
new file mode 100644
index 00000000..8678cdae
--- /dev/null
+++ b/src/vte/vtetypebuiltins.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright © 2021 Christian Persch
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#if !defined (__VTE_VTE_H_INSIDE__) && !defined (VTE_COMPILATION)
+#error "Only <vte/vte.h> can be included directly."
+#endif
+
+#if _VTE_GTK == 3
+#include "vtetypebuiltins-gtk3.h"
+#elif _VTE_GTK == 4
+#include "vtetypebuiltins-gtk4.h"
+#endif
diff --git a/src/vteaccess.h b/src/vteaccess.h
index 351d0c82..6dd401db 100644
--- a/src/vteaccess.h
+++ b/src/vteaccess.h
@@ -16,9 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef vte_vteaccess_h_included
-#define vte_vteaccess_h_included
-
+#pragma once
#include <glib.h>
#include <gtk/gtk.h>
@@ -52,5 +50,3 @@ struct _VteTerminalAccessibleClass {
GType _vte_terminal_accessible_get_type(void);
G_END_DECLS
-
-#endif
diff --git a/src/vtedefines.hh b/src/vtedefines.hh
index 63150685..12d5ae99 100644
--- a/src/vtedefines.hh
+++ b/src/vtedefines.hh
@@ -149,3 +149,6 @@
#define VTE_SIXEL_MAX_WIDTH (2048)
#define VTE_SIXEL_MAX_HEIGHT (2052)
#define VTE_SIXEL_NUM_COLOR_REGISTERS (1024)
+
+#define VTE_MIN_CURSOR_BLINK_CYCLE (50 /* ms */)
+#define VTE_MIN_CURSOR_BLINK_TIMEOUT (50 /* ms */)
diff --git a/src/vtegtk.cc b/src/vtegtk.cc
index 7cc8fb9a..600fc435 100644
--- a/src/vtegtk.cc
+++ b/src/vtegtk.cc
@@ -5,7 +5,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -63,8 +63,12 @@
#include "vteregexinternal.hh"
#ifdef WITH_A11Y
+#if VTE_GTK == 3
#include "vteaccess.h"
-#endif
+#else
+#undef WITH_A11Y
+#endif /* VTE_GTK == 3 */
+#endif /* WITH_A11Y */
#ifdef WITH_ICU
#include "icu-glue.hh"
@@ -79,6 +83,19 @@ struct _VteTerminalClassPrivate {
GtkStyleProvider *style_provider;
};
+#if VTE_GTK == 4
+
+static void
+style_provider_parsing_error_cb(GtkCssProvider* provider,
+ void* section,
+ GError* error)
+{
+ g_assert_no_error(error);
+}
+
+#endif
+
+
class VteTerminalPrivate {
public:
VteTerminalPrivate(VteTerminal* terminal)
@@ -217,7 +234,6 @@ vte_terminal_set_hscroll_policy(VteTerminal *terminal,
try
{
WIDGET(terminal)->set_hscroll_policy(policy);
- gtk_widget_queue_resize_no_redraw (GTK_WIDGET (terminal));
}
catch (...)
{
@@ -230,7 +246,6 @@ vte_terminal_set_vscroll_policy(VteTerminal *terminal,
try
{
WIDGET(terminal)->set_vscroll_policy(policy);
- gtk_widget_queue_resize_no_redraw (GTK_WIDGET (terminal));
}
catch (...)
{
@@ -260,6 +275,8 @@ catch (...)
vte::log_exception();
}
+#if VTE_GTK == 3
+
static void
vte_terminal_style_updated (GtkWidget *widget) noexcept
try
@@ -298,7 +315,7 @@ try
}
}
- return WIDGET(terminal)->key_press(event);
+ return WIDGET(terminal)->event_key_press(event);
}
catch (...)
{
@@ -312,7 +329,7 @@ vte_terminal_key_release(GtkWidget *widget,
try
{
VteTerminal *terminal = VTE_TERMINAL(widget);
- return WIDGET(terminal)->key_release(event);
+ return WIDGET(terminal)->event_key_release(event);
}
catch (...)
{
@@ -326,7 +343,7 @@ vte_terminal_motion_notify(GtkWidget *widget,
try
{
VteTerminal *terminal = VTE_TERMINAL(widget);
- return WIDGET(terminal)->motion_notify(event);
+ return WIDGET(terminal)->event_motion_notify(event);
}
catch (...)
{
@@ -340,7 +357,7 @@ vte_terminal_button_press(GtkWidget *widget,
try
{
VteTerminal *terminal = VTE_TERMINAL(widget);
- return WIDGET(terminal)->button_press(event);
+ return WIDGET(terminal)->event_button_press(event);
}
catch (...)
{
@@ -354,7 +371,7 @@ vte_terminal_button_release(GtkWidget *widget,
try
{
VteTerminal *terminal = VTE_TERMINAL(widget);
- return WIDGET(terminal)->button_release(event);
+ return WIDGET(terminal)->event_button_release(event);
}
catch (...)
{
@@ -368,7 +385,7 @@ vte_terminal_scroll(GtkWidget *widget,
try
{
auto terminal = VTE_TERMINAL(widget);
- return WIDGET(terminal)->scroll(event);
+ return WIDGET(terminal)->event_scroll(event);
}
catch (...)
{
@@ -382,7 +399,7 @@ vte_terminal_focus_in(GtkWidget *widget,
try
{
VteTerminal *terminal = VTE_TERMINAL(widget);
- WIDGET(terminal)->focus_in(event);
+ WIDGET(terminal)->event_focus_in(event);
return FALSE;
}
catch (...)
@@ -397,7 +414,7 @@ vte_terminal_focus_out(GtkWidget *widget,
try
{
VteTerminal *terminal = VTE_TERMINAL(widget);
- WIDGET(terminal)->focus_out(event);
+ WIDGET(terminal)->event_focus_out(event);
return FALSE;
}
catch (...)
@@ -418,7 +435,7 @@ try
ret = GTK_WIDGET_CLASS (vte_terminal_parent_class)->enter_notify_event (widget, event);
}
- WIDGET(terminal)->enter(event);
+ WIDGET(terminal)->event_enter(event);
return ret;
}
@@ -440,7 +457,7 @@ try
ret = GTK_WIDGET_CLASS (vte_terminal_parent_class)->leave_notify_event (widget, event);
}
- WIDGET(terminal)->leave(event);
+ WIDGET(terminal)->event_leave(event);
return ret;
}
@@ -478,33 +495,7 @@ catch (...)
vte::log_exception();
}
-static void
-vte_terminal_size_allocate(GtkWidget *widget,
- GtkAllocation *allocation) noexcept
-try
-{
- VteTerminal *terminal = VTE_TERMINAL(widget);
- WIDGET(terminal)->size_allocate(allocation);
-}
-catch (...)
-{
- vte::log_exception();
-}
-
-static gboolean
-vte_terminal_draw(GtkWidget *widget,
- cairo_t *cr) noexcept
-try
-{
- VteTerminal *terminal = VTE_TERMINAL (widget);
- WIDGET(terminal)->draw(cr);
- return FALSE;
-}
-catch (...)
-{
- vte::log_exception();
- return false;
-}
+#endif /* VTE_GTK == 3 */
static void
vte_terminal_realize(GtkWidget *widget) noexcept
@@ -569,16 +560,105 @@ vte_terminal_unmap(GtkWidget *widget) noexcept
}
static void
-vte_terminal_screen_changed (GtkWidget *widget,
- GdkScreen *previous_screen) noexcept
+vte_terminal_state_flags_changed(GtkWidget* widget,
+ GtkStateFlags old_flags) noexcept
try
{
- VteTerminal *terminal = VTE_TERMINAL (widget);
+ GTK_WIDGET_CLASS(vte_terminal_parent_class)->state_flags_changed(widget, old_flags);
- if (GTK_WIDGET_CLASS (vte_terminal_parent_class)->screen_changed) {
- GTK_WIDGET_CLASS (vte_terminal_parent_class)->screen_changed (widget, previous_screen);
- }
+ auto terminal = VTE_TERMINAL(widget);
+ WIDGET(terminal)->state_flags_changed(old_flags);
+}
+catch (...)
+{
+ vte::log_exception();
+}
+
+static void
+vte_terminal_direction_changed(GtkWidget* widget,
+ GtkTextDirection old_direction) noexcept
+try
+{
+ auto const parent_class = GTK_WIDGET_CLASS(vte_terminal_parent_class);
+ if (parent_class->direction_changed)
+ parent_class->direction_changed(widget, old_direction);
+
+ auto terminal = VTE_TERMINAL(widget);
+ WIDGET(terminal)->direction_changed(old_direction);
+}
+catch (...)
+{
+ vte::log_exception();
+}
+
+static GtkSizeRequestMode
+vte_terminal_get_request_mode(GtkWidget* widget) noexcept
+{
+ return GTK_SIZE_REQUEST_CONSTANT_SIZE;
+}
+static gboolean
+vte_terminal_query_tooltip(GtkWidget* widget,
+ int x,
+ int y,
+ gboolean keyboard,
+ GtkTooltip* tooltip) noexcept
+try
+{
+ auto const parent_class = GTK_WIDGET_CLASS(vte_terminal_parent_class);
+ if (parent_class->query_tooltip(widget, x, y, keyboard, tooltip))
+ return true;
+
+ auto terminal = VTE_TERMINAL(widget);
+ return WIDGET(terminal)->query_tooltip(x, y, keyboard, tooltip);
+}
+catch (...)
+{
+ vte::log_exception();
+ return false;
+}
+
+
+#if VTE_GTK == 3
+
+static void
+vte_terminal_size_allocate(GtkWidget* widget,
+ GtkAllocation* allocation) noexcept
+try
+{
+ auto terminal = VTE_TERMINAL(widget);
+ WIDGET(terminal)->size_allocate(allocation);
+}
+catch (...)
+{
+ vte::log_exception();
+}
+
+static gboolean
+vte_terminal_draw(GtkWidget* widget,
+ cairo_t* cr) noexcept
+try
+{
+ auto terminal = VTE_TERMINAL(widget);
+ WIDGET(terminal)->draw(cr);
+ return FALSE;
+}
+catch (...)
+{
+ vte::log_exception();
+ return false;
+}
+
+static void
+vte_terminal_screen_changed(GtkWidget* widget,
+ GdkScreen* previous_screen) noexcept
+try
+{
+ auto const parent_class = GTK_WIDGET_CLASS(vte_terminal_parent_class);
+ if (parent_class->screen_changed)
+ parent_class->screen_changed(widget, previous_screen);
+
+ auto terminal = VTE_TERMINAL(widget);
WIDGET(terminal)->screen_changed(previous_screen);
}
catch (...)
@@ -586,6 +666,156 @@ catch (...)
vte::log_exception();
}
+#endif /* VTE_GTK == 3 */
+
+#if VTE_GTK == 4
+
+static void
+vte_terminal_size_allocate(GtkWidget *widget,
+ int width,
+ int height,
+ int baseline) noexcept
+try
+{
+ GTK_WIDGET_CLASS(vte_terminal_parent_class)->size_allocate(widget, width, height, baseline);
+
+ auto terminal = VTE_TERMINAL(widget);
+ WIDGET(terminal)->size_allocate(width, height, baseline);
+}
+catch (...)
+{
+ vte::log_exception();
+}
+
+static void
+vte_terminal_root(GtkWidget *widget) noexcept
+try
+{
+ GTK_WIDGET_CLASS(vte_terminal_parent_class)->root(widget);
+
+ auto terminal = VTE_TERMINAL(widget);
+ WIDGET(terminal)->root();
+}
+catch (...)
+{
+ vte::log_exception();
+}
+
+static void
+vte_terminal_unroot(GtkWidget *widget) noexcept
+{
+ _vte_debug_print(VTE_DEBUG_LIFECYCLE, "vte_terminal_unroot()\n");
+
+ auto terminal = VTE_TERMINAL(widget);
+ WIDGET(terminal)->unroot();
+
+ GTK_WIDGET_CLASS(vte_terminal_parent_class)->unroot(widget);
+}
+
+static void
+vte_terminal_measure(GtkWidget* widget,
+ GtkOrientation orientation,
+ int for_size,
+ int* minimum,
+ int* natural,
+ int* minimum_baseline,
+ int* natural_baseline) noexcept
+try
+{
+ auto terminal = VTE_TERMINAL(widget);
+ WIDGET(terminal)->measure(orientation, for_size,
+ minimum, natural,
+ minimum_baseline, natural_baseline);
+}
+catch (...)
+{
+ vte::log_exception();
+}
+
+static void
+vte_terminal_compute_expand(GtkWidget* widget,
+ gboolean* hexpand,
+ gboolean* vexpand) noexcept
+try
+{
+ auto terminal = VTE_TERMINAL(widget);
+ auto [h, v] = WIDGET(terminal)->compute_expand();
+ *hexpand = h;
+ *vexpand = v;
+}
+catch (...)
+{
+ vte::log_exception();
+ *hexpand = *vexpand = false;
+}
+
+static void
+vte_terminal_css_changed(GtkWidget* widget,
+ GtkCssStyleChange* change) noexcept
+try
+{
+ GTK_WIDGET_CLASS(vte_terminal_parent_class)->css_changed(widget, change);
+ auto terminal = VTE_TERMINAL(widget);
+ WIDGET(terminal)->css_changed(change);
+}
+catch (...)
+{
+ vte::log_exception();
+}
+
+static void
+vte_terminal_system_setting_changed(GtkWidget* widget,
+ GtkSystemSetting setting) noexcept
+try
+{
+ GTK_WIDGET_CLASS(vte_terminal_parent_class)->system_setting_changed(widget, setting);
+ auto terminal = VTE_TERMINAL(widget);
+ WIDGET(terminal)->system_setting_changed(setting);
+}
+catch (...)
+{
+ vte::log_exception();
+}
+
+static void
+vte_terminal_snapshot(GtkWidget* widget,
+ GtkSnapshot* snapshot_object) noexcept
+try
+{
+ GTK_WIDGET_CLASS(vte_terminal_parent_class)->snapshot(widget, snapshot_object);
+ auto terminal = VTE_TERMINAL(widget);
+ WIDGET(terminal)->snapshot(snapshot_object);
+}
+catch (...)
+{
+ vte::log_exception();
+}
+
+static gboolean
+vte_terminal_contains(GtkWidget* widget,
+ double x,
+ double y) noexcept
+try
+{
+ auto terminal = VTE_TERMINAL(widget);
+ if (WIDGET(terminal)->contains(x, y))
+ return true;
+
+ auto const parent_class = GTK_WIDGET_CLASS(vte_terminal_parent_class);
+ if (parent_class->contains &&
+ parent_class->contains(widget, x, y))
+ return true;
+
+ return false;
+}
+catch (...)
+{
+ vte::log_exception();
+ return false;
+}
+
+#endif /* VTE_GTK == 4 */
+
static void
vte_terminal_constructed (GObject *object) noexcept
try
@@ -615,7 +845,9 @@ try
VTE_TERMINAL_GET_CLASS (terminal)->priv->style_provider,
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+#if VTE_GTK == 3
gtk_widget_set_has_window(&terminal->widget, FALSE);
+#endif
place = vte_terminal_get_instance_private(terminal);
new (place) VteTerminalPrivate{terminal};
@@ -916,10 +1148,6 @@ catch (...)
static void
vte_terminal_class_init(VteTerminalClass *klass)
{
- GObjectClass *gobject_class;
- GtkWidgetClass *widget_class;
- GtkBindingSet *binding_set;
-
#ifdef VTE_DEBUG
{
_vte_debug_init();
@@ -943,13 +1171,15 @@ vte_terminal_class_init(VteTerminalClass *klass)
}
#endif
+#if VTE_GTK == 3
_VTE_DEBUG_IF (VTE_DEBUG_UPDATES) gdk_window_set_debug_updates(TRUE);
+#endif
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
- gobject_class = G_OBJECT_CLASS(klass);
- widget_class = GTK_WIDGET_CLASS(klass);
+ auto gobject_class = G_OBJECT_CLASS(klass);
+ auto widget_class = GTK_WIDGET_CLASS(klass);
/* Override some of the default handlers. */
gobject_class->constructed = vte_terminal_constructed;
@@ -957,12 +1187,21 @@ vte_terminal_class_init(VteTerminalClass *klass)
gobject_class->finalize = vte_terminal_finalize;
gobject_class->get_property = vte_terminal_get_property;
gobject_class->set_property = vte_terminal_set_property;
+
widget_class->realize = vte_terminal_realize;
widget_class->unrealize = vte_terminal_unrealize;
widget_class->map = vte_terminal_map;
widget_class->unmap = vte_terminal_unmap;
- widget_class->scroll_event = vte_terminal_scroll;
+
+ widget_class->size_allocate = vte_terminal_size_allocate;
+ widget_class->state_flags_changed = vte_terminal_state_flags_changed;
+ widget_class->direction_changed = vte_terminal_direction_changed;
+ widget_class->get_request_mode = vte_terminal_get_request_mode;
+ widget_class->query_tooltip = vte_terminal_query_tooltip;
+
+#if VTE_GTK == 3
widget_class->draw = vte_terminal_draw;
+ widget_class->scroll_event = vte_terminal_scroll;
widget_class->key_press_event = vte_terminal_key_press;
widget_class->key_release_event = vte_terminal_key_release;
widget_class->button_press_event = vte_terminal_button_press;
@@ -975,8 +1214,19 @@ vte_terminal_class_init(VteTerminalClass *klass)
widget_class->style_updated = vte_terminal_style_updated;
widget_class->get_preferred_width = vte_terminal_get_preferred_width;
widget_class->get_preferred_height = vte_terminal_get_preferred_height;
- widget_class->size_allocate = vte_terminal_size_allocate;
widget_class->screen_changed = vte_terminal_screen_changed;
+#endif
+
+#if VTE_GTK == 4
+ widget_class->root = vte_terminal_root;
+ widget_class->unroot = vte_terminal_unroot;
+ widget_class->measure = vte_terminal_measure;
+ widget_class->compute_expand = vte_terminal_compute_expand;
+ widget_class->css_changed = vte_terminal_css_changed;
+ widget_class->system_setting_changed = vte_terminal_system_setting_changed;
+ widget_class->snapshot = vte_terminal_snapshot;
+ widget_class->contains = vte_terminal_contains;
+#endif
gtk_widget_class_set_css_name(widget_class, VTE_TERMINAL_CSS_NAME);
@@ -2077,23 +2327,33 @@ vte_terminal_class_init(VteTerminalClass *klass)
g_object_class_install_properties(gobject_class, LAST_PROP, pspecs);
+#if VTE_GTK == 3
/* Disable GtkWidget's keybindings except for Shift-F10 and MenuKey
* which pop up the context menu.
*/
- binding_set = gtk_binding_set_by_class(vte_terminal_parent_class);
+ auto const binding_set = gtk_binding_set_by_class(vte_terminal_parent_class);
gtk_binding_entry_skip(binding_set, GDK_KEY_F1, GDK_CONTROL_MASK);
gtk_binding_entry_skip(binding_set, GDK_KEY_F1, GDK_SHIFT_MASK);
gtk_binding_entry_skip(binding_set, GDK_KEY_KP_F1, GDK_CONTROL_MASK);
gtk_binding_entry_skip(binding_set, GDK_KEY_KP_F1, GDK_SHIFT_MASK);
+#endif /* VTE_GTK == 3 */
process_timer = g_timer_new();
klass->priv = G_TYPE_CLASS_GET_PRIVATE (klass, VTE_TYPE_TERMINAL, VteTerminalClassPrivate);
klass->priv->style_provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
+#if VTE_GTK == 3
+ auto err = vte::glib::Error{};
+#elif VTE_GTK == 4
+ g_signal_connect(klass->priv->style_provider, "parsing-error",
+ G_CALLBACK(style_provider_parsing_error_cb), nullptr);
+#endif
gtk_css_provider_load_from_data (GTK_CSS_PROVIDER (klass->priv->style_provider),
"VteTerminal, " VTE_TERMINAL_CSS_NAME " {\n"
+#if VTE_GTK == 3
"padding: 1px 1px 1px 1px;\n"
+#endif
#if GTK_CHECK_VERSION (3, 24, 22)
"background-color: @text_view_bg;\n"
#else
@@ -2101,12 +2361,21 @@ vte_terminal_class_init(VteTerminalClass *klass)
#endif
"color: @theme_text_color;\n"
"}\n",
- -1, NULL);
+ -1
+#if VTE_GTK == 3
+ , NULL
+#endif
+ );
+#if VTE_GTK == 3
+ err.assert_no_error();
+#endif
+#if VTE_GTK == 3
#ifdef WITH_A11Y
/* a11y */
gtk_widget_class_set_accessible_type(widget_class, VTE_TYPE_TERMINAL_ACCESSIBLE);
#endif
+#endif
}
static gboolean
@@ -2600,6 +2869,8 @@ catch (...)
return nullptr;
}
+#if VTE_GTK == 3
+
/**
* vte_terminal_match_check_event:
* @terminal: a #VteTerminal
@@ -2768,6 +3039,10 @@ catch (...)
return false;
}
+#endif /* VTE_GTK */
+
+#if VTE_GTK == 3
+
/**
* vte_terminal_event_check_gregex_simple:
* @terminal: a #VteTerminal
@@ -2795,6 +3070,8 @@ vte_terminal_event_check_gregex_simple(VteTerminal *terminal,
return FALSE;
}
+#endif /* VTE_GTK == 3 */
+
/**
* vte_terminal_match_set_cursor:
* @terminal: a #VteTerminal
@@ -2823,6 +3100,8 @@ catch (...)
vte::log_exception();
}
+#if VTE_GTK == 3
+
/**
* vte_terminal_match_set_cursor_type:
* @terminal: a #VteTerminal
@@ -2849,6 +3128,7 @@ catch (...)
{
vte::log_exception();
}
+#endif /* VTE_GTK == 3 */
/**
* vte_terminal_match_set_cursor_name:
@@ -5046,6 +5326,8 @@ catch (...)
vte::log_exception();
}
+#if VTE_GTK == 3
+
/* Just some arbitrary minimum values */
#define MIN_COLUMNS (16)
#define MIN_ROWS (2)
@@ -5136,6 +5418,8 @@ vte_terminal_set_geometry_hints_for_window(VteTerminal *terminal,
GDK_HINT_BASE_SIZE));
}
+#endif /* VTE_GTK == 3 */
+
/**
* vte_terminal_get_has_selection:
* @terminal: a #VteTerminal
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index d3881e10..6e5e349c 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -4,7 +4,7 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -90,9 +90,14 @@ namespace platform {
* Holds a platform cursor. This is either a named cursor (string),
* a reference to a GdkCursor*, or a cursor type.
*/
+#if VTE_GTK == 3
using Cursor = std::variant<std::string,
vte::glib::RefPtr<GdkCursor>,
GdkCursorType>;
+#elif VTE_GTK == 4
+using Cursor = std::variant<std::string,
+ vte::glib::RefPtr<GdkCursor>>;
+#endif
} // namespace platform
} // namespace vte
@@ -426,9 +431,10 @@ public:
"cursor-blink-timer"};
CursorBlinkMode m_cursor_blink_mode{CursorBlinkMode::eSYSTEM};
bool m_cursor_blink_state{false};
- bool m_cursor_blinks{false}; /* whether the cursor is actually blinking */
- gint m_cursor_blink_cycle; /* gtk-cursor-blink-time / 2 */
- int m_cursor_blink_timeout{500}; /* gtk-cursor-blink-timeout */
+ bool m_cursor_blinks{false}; /* whether the cursor is actually blinking */
+ bool m_cursor_blinks_system{true}; /* gtk-cursor-blink */
+ gint m_cursor_blink_cycle{1000}; /* gtk-cursor-blink-time / 2 */
+ int m_cursor_blink_timeout{500}; /* gtk-cursor-blink-timeout */
gint64 m_cursor_blink_time; /* how long the cursor has been blinking yet */
bool m_has_focus{false}; /* is the widget focused */
@@ -689,7 +695,11 @@ public:
double m_undercurl_thickness{VTE_LINE_WIDTH};
/* Style stuff */
+#if VTE_GTK == 3
GtkBorder m_padding{1, 1, 1, 1};
+#elif VTE_GTK == 4
+ GtkBorder m_padding{0, 0, 0, 0};
+#endif
auto padding() const noexcept { return &m_padding; }
vte::glib::RefPtr<GtkAdjustment> m_vadjustment{};
@@ -804,6 +814,9 @@ public:
/* The allocation of the widget */
cairo_rectangle_int_t m_allocated_rect;
+
+ constexpr auto const* allocated_rect() const noexcept { return &m_allocated_rect; }
+
/* The usable view area. This is the allocation, minus the padding, but
* including additional right/bottom area if the allocation is not grid aligned.
*/
@@ -870,17 +883,24 @@ public:
void widget_mouse_enter(vte::platform::MouseEvent const& event);
void widget_mouse_leave(vte::platform::MouseEvent const& event);
bool widget_mouse_scroll(vte::platform::ScrollEvent const& event);
+#if VTE_GTK == 3
void widget_draw(cairo_t *cr);
- void widget_get_preferred_width(int *minimum_width,
- int *natural_width);
- void widget_get_preferred_height(int *minimum_height,
- int *natural_height);
- void widget_size_allocate(GtkAllocation *allocation);
+#endif /* VTE_GTK == 3 */
+ void widget_measure_width(int *minimum_width,
+ int *natural_width);
+ void widget_measure_height(int *minimum_height,
+ int *natural_height);
+
+ void widget_size_allocate(int width,
+ int height,
+ int baseline);
void set_blink_settings(bool blink,
int blink_time,
int blink_timeout) noexcept;
+ void draw(cairo_t *cr,
+ cairo_region_t const* region);
void paint_cursor();
void paint_im_preedit_string();
void draw_cells(vte::view::DrawingContext::TextRequest* items,
@@ -1117,26 +1137,53 @@ public:
bool rowcol_from_event(vte::platform::MouseEvent const& event,
long *column,
long *row);
+#if VTE_GTK == 4
+ bool rowcol_at(double x,
+ double y,
+ long* column,
+ long* row);
+#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);
bool regex_match_check_extra(vte::platform::MouseEvent const& event,
vte::base::Regex const** regexes,
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,
+ size_t n_regexes,
+ uint32_t match_flags,
+ char** matches);
char *regex_match_check(vte::grid::column_t column,
vte::grid::row_t row,
int *tag);
char *regex_match_check(vte::platform::MouseEvent const& event,
int *tag);
+ char *regex_match_check_at(double x,
+ double y,
+ int *tag);
void regex_match_remove(int tag) noexcept;
void regex_match_remove_all() noexcept;
void regex_match_set_cursor(int tag,
GdkCursor *gdk_cursor);
+ #if VTE_GTK == 3
void regex_match_set_cursor(int tag,
GdkCursorType cursor_type);
+ #endif
void regex_match_set_cursor(int tag,
char const* cursor_name);
bool match_rowcol_to_offset(vte::grid::column_t column,
diff --git a/src/vteseq.cc b/src/vteseq.cc
index 9a04e9aa..a5cbf8a6 100644
--- a/src/vteseq.cc
+++ b/src/vteseq.cc
@@ -9101,12 +9101,17 @@ Terminal::XTERM_WM(vte::parser::Sequence const& seq)
/* FIMXE: this should really report the monitor's workarea,
* or even just a fixed value.
*/
+#if VTE_GTK == 3
auto gdkscreen = gtk_widget_get_screen(m_widget);
int height = gdk_screen_get_height(gdkscreen);
int width = gdk_screen_get_width(gdkscreen);
_vte_debug_print(VTE_DEBUG_EMULATION,
"Reporting screen size as %dx%d cells.\n",
height / int(m_cell_height), width / int(m_cell_width));
+#elif VTE_GTK == 4
+ auto height = int(m_row_count * m_cell_height);
+ auto width = int(m_column_count * m_cell_width);
+#endif
reply(seq, VTE_REPLY_XTERM_WM,
{9, height / int(m_cell_height), width / int(m_cell_width)});
diff --git a/src/widget.cc b/src/widget.cc
index 959839d0..2e3e4b2b 100644
--- a/src/widget.cc
+++ b/src/widget.cc
@@ -32,6 +32,16 @@
#include "vteptyinternal.hh"
#include "debug.h"
+#if VTE_GTK == 4
+#include "graphene-glue.hh"
+#endif
+
+#if VTE_GTK == 3
+#define VTE_STYLE_CLASS_MONOSPACE GTK_STYLE_CLASS_MONOSPACE
+#elif VTE_GTK == 4
+#define VTE_STYLE_CLASS_MONOSPACE "monospace"
+#endif
+
using namespace std::literals;
namespace vte {
@@ -142,11 +152,19 @@ Widget::Widget(VteTerminal* t)
m_hscroll_policy{GTK_SCROLL_NATURAL},
m_vscroll_policy{GTK_SCROLL_NATURAL}
{
+#if VTE_GTK == 3
gtk_widget_set_can_focus(gtk(), true);
+#endif
+
+#if VTE_GTK == 4
+ gtk_widget_set_focusable(gtk(), true);
+#endif
+#if VTE_GTK == 3
/* We do our own redrawing. */
// FIXMEchpe is this still necessary?
gtk_widget_set_redraw_on_allocate(gtk(), false);
+#endif
/* Until Terminal init is completely fixed, use zero'd memory */
auto place = g_malloc0(sizeof(vte::terminal::Terminal));
@@ -156,7 +174,7 @@ Widget::Widget(VteTerminal* t)
Widget::~Widget() noexcept
try
{
- g_signal_handlers_disconnect_matched(gtk_widget_get_settings(m_widget),
+ g_signal_handlers_disconnect_matched(m_settings.get(),
G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
this);
@@ -175,19 +193,38 @@ void
Widget::beep() noexcept
{
if (realized())
- gdk_window_beep(gtk_widget_get_window(m_widget));
+ gtk_widget_error_bell(gtk());
}
+#if VTE_GTK == 4
+
+bool
+Widget::contains(double x,
+ double y)
+{
+ return false;
+}
+
+#endif /* VTE_GTK == 4 */
+
vte::glib::RefPtr<GdkCursor>
Widget::create_cursor(std::string const& name) const noexcept
{
+#if VTE_GTK == 3
return vte::glib::take_ref(gdk_cursor_new_from_name(gtk_widget_get_display(m_widget), name.c_str()));
+#elif VTE_GTK == 4
+ return vte::glib::take_ref(gdk_cursor_new_from_name(name.c_str(), nullptr /* fallback */));
+#endif
}
void
Widget::set_cursor(GdkCursor* cursor) noexcept
{
+#if VTE_GTK == 3
gdk_window_set_cursor(m_event_window, cursor);
+#elif VTE_GTK == 4
+ gtk_widget_set_cursor(gtk(), cursor);
+#endif
}
void
@@ -196,24 +233,36 @@ Widget::set_cursor(Cursor const& cursor) noexcept
if (!realized())
return;
- auto display = gtk_widget_get_display(m_widget);
GdkCursor* gdk_cursor{nullptr};
switch (cursor.index()) {
case 0:
- gdk_cursor = gdk_cursor_new_from_name(display, std::get<0>(cursor).c_str());
+#if VTE_GTK == 3
+ gdk_cursor = gdk_cursor_new_from_name(gtk_widget_get_display(gtk()),
+ std::get<0>(cursor).c_str());
+#elif VTE_GTK == 4
+ gdk_cursor = gdk_cursor_new_from_name(std::get<0>(cursor).c_str(),
+ nullptr /* fallback */);
+#endif /* VTE_GTK */
break;
+
case 1:
gdk_cursor = std::get<1>(cursor).get();
- if (gdk_cursor != nullptr &&
- gdk_cursor_get_display(gdk_cursor) == display) {
+ if (gdk_cursor != nullptr
+#if VTE_GTK == 3
+ && gdk_cursor_get_display(gdk_cursor) == gtk_widget_get_display(gtk())
+#endif
+ ) {
g_object_ref(gdk_cursor);
} else {
gdk_cursor = nullptr;
}
break;
+
+#if VTE_GTK == 3
case 2:
- gdk_cursor = gdk_cursor_new_for_display(display, std::get<2>(cursor));
+ gdk_cursor = gdk_cursor_new_for_display(gtk_widget_get_display(gtk()), std::get<2>(cursor));
break;
+#endif
}
set_cursor(gdk_cursor);
@@ -225,8 +274,8 @@ Clipboard&
Widget::clipboard_get(ClipboardType type) const
{
switch (type) {
- case ClipboardType::CLIPBOARD: return *m_clipboard;
case ClipboardType::PRIMARY: return *m_primary_clipboard;
+ case ClipboardType::CLIPBOARD: return *m_clipboard;
default: g_assert_not_reached(); throw std::runtime_error{""}; break;
}
}
@@ -290,15 +339,60 @@ Widget::clipboard_set_text(ClipboardType type,
clipboard_get(type).set_text(str);
}
+#if VTE_GTK == 4
+
+std::pair<bool, bool>
+Widget::compute_expand()
+{
+ return {true, true};
+}
+
+#endif /* VTE_GTK == 4 */
+
void
Widget::constructed() noexcept
{
+#if VTE_GTK == 3
+ auto context = gtk_widget_get_style_context(m_widget);
+ gtk_style_context_add_class (context, VTE_STYLE_CLASS_MONOSPACE);
+#elif VTE_GTK == 4
+ gtk_widget_add_css_class(gtk(), VTE_STYLE_CLASS_MONOSPACE);
+#endif /* VTE_GTK */
+
+#if VTE_GTK == 4
+
+ connect_settings();
+
+#endif /* VTE_GTK == 4 */
+
+#if VTE_GTK == 3
/* Set the style as early as possible, before GTK+ starts
* invoking various callbacks. This is needed in order to
* compute the initial geometry correctly in presence of
* non-default padding, see bug 787710.
*/
style_updated();
+#elif VTE_GTK == 4
+ padding_changed();
+#endif /* VTE_GTK */
+}
+
+#if VTE_GTK == 4
+
+void
+Widget::css_changed(GtkCssStyleChange* change)
+{
+ /* This function is mostly useless, since there's no public API for GtkCssStyleChange */
+
+ padding_changed();
+}
+
+#endif /* VTE_GTK == 4 */
+
+void
+Widget::direction_changed(GtkTextDirection old_direction) noexcept
+{
+ // FIXME: does this need to feed to BiDi somehow?
}
void
@@ -330,9 +424,122 @@ Widget::im_filter_keypress(KeyEvent const& event) noexcept
// FIXMEchpe this can only be called when realized, so the m_im_context check is redundant
return m_im_context &&
gtk_im_context_filter_keypress(m_im_context.get(),
- reinterpret_cast<GdkEventKey*>(event.platform_event()));
+#if VTE_GTK == 3
+ reinterpret_cast<GdkEventKey*>(event.platform_event())
+#elif VTE_GTK == 4
+ event.platform_event()
+#endif
+ );
+}
+
+#if VTE_GTK == 3
+
+void
+Widget::event_focus_in(GdkEventFocus *event)
+{
+ _vte_debug_print(VTE_DEBUG_EVENTS, "Focus In");
+
+ m_terminal->widget_focus_in();
+}
+
+void
+Widget::event_focus_out(GdkEventFocus *event)
+{
+ _vte_debug_print(VTE_DEBUG_EVENTS, "Focus Out");
+
+ m_terminal->widget_focus_out();
+}
+
+bool
+Widget::event_key_press(GdkEventKey *event)
+{
+ auto key_event = key_event_from_gdk(reinterpret_cast<GdkEvent*>(event));
+
+ _vte_debug_print(VTE_DEBUG_EVENTS, "Key press key=%x keycode=%x modifiers=%x\n",
+ key_event.keyval(), key_event.keycode(), key_event.modifiers());
+
+ return m_terminal->widget_key_press(key_event);
+}
+
+bool
+Widget::event_key_release(GdkEventKey *event)
+{
+ auto key_event = key_event_from_gdk(reinterpret_cast<GdkEvent*>(event));
+
+ _vte_debug_print(VTE_DEBUG_EVENTS, "Key release key=%x keycode=%x modifiers=%x\n",
+ key_event.keyval(), key_event.keycode(), key_event.modifiers());
+
+ return m_terminal->widget_key_release(key_event);
+}
+
+bool
+Widget::event_button_press(GdkEventButton *event)
+{
+ auto mouse_event = mouse_event_from_gdk(reinterpret_cast<GdkEvent*>(event));
+
+ _vte_debug_print(VTE_DEBUG_EVENTS, "Click press button=%d press_count=%d x=%.3f y=%.3f\n",
+ mouse_event.button_value(), mouse_event.press_count(),
+ mouse_event.x(), mouse_event.y());
+
+ return m_terminal->widget_mouse_press(mouse_event);
+}
+
+bool
+Widget::event_button_release(GdkEventButton *event)
+{
+ auto mouse_event = mouse_event_from_gdk(reinterpret_cast<GdkEvent*>(event));
+
+ _vte_debug_print(VTE_DEBUG_EVENTS, "Click release button=%d x=%.3f y=%.3f\n",
+ mouse_event.button_value(), mouse_event.x(), mouse_event.y());
+
+ return m_terminal->widget_mouse_release(mouse_event);
}
+void
+Widget::event_enter(GdkEventCrossing *event)
+{
+ auto mouse_event = mouse_event_from_gdk(reinterpret_cast<GdkEvent*>(event));
+
+ _vte_debug_print(VTE_DEBUG_EVENTS, "Motion enter x=%.3f y=%.3f\n",
+ mouse_event.x(), mouse_event.y());
+
+ m_terminal->widget_mouse_enter(mouse_event);
+}
+
+void
+Widget::event_leave(GdkEventCrossing *event)
+{
+ auto mouse_event = mouse_event_from_gdk(reinterpret_cast<GdkEvent*>(event));
+
+ _vte_debug_print(VTE_DEBUG_EVENTS, "Motion leave x=%.3f y=%.3f\n",
+ mouse_event.x(), mouse_event.y());
+
+ m_terminal->widget_mouse_leave(mouse_event);
+}
+bool
+Widget::event_scroll(GdkEventScroll *event)
+{
+ auto scroll_event = scroll_event_from_gdk(reinterpret_cast<GdkEvent*>(event));
+
+ _vte_debug_print(VTE_DEBUG_EVENTS, "Scroll delta_x=%.3f delta_y=%.3f\n",
+ scroll_event.dx(), scroll_event.dy());
+
+ return m_terminal->widget_mouse_scroll(scroll_event);
+}
+
+bool
+Widget::event_motion_notify(GdkEventMotion *event)
+{
+ auto mouse_event = mouse_event_from_gdk(reinterpret_cast<GdkEvent*>(event));
+
+ _vte_debug_print(VTE_DEBUG_EVENTS, "Motion x=%.3f y=%.3f\n",
+ mouse_event.x(), mouse_event.y());
+
+ return m_terminal->widget_mouse_motion(mouse_event);
+}
+
+#endif /* VTE_GTK == 3 */
+
void
Widget::im_focus_in() noexcept
{
@@ -368,6 +575,8 @@ Widget::im_set_cursor_location(cairo_rectangle_int_t const* rect) noexcept
gtk_im_context_set_cursor_location(m_im_context.get(), rect);
}
+#if VTE_GTK == 3
+
unsigned
Widget::read_modifiers_from_gdk(GdkEvent* event) const noexcept
{
@@ -376,11 +585,9 @@ Widget::read_modifiers_from_gdk(GdkEvent* event) const noexcept
if (!gdk_event_get_state(event, &mods))
return 0;
- #if 1
/* HACK! Treat META as ALT; see bug #663779. */
if (mods & GDK_META_MASK)
mods = GdkModifierType(mods | GDK_MOD1_MASK);
- #endif
/* Map non-virtual modifiers to virtual modifiers (Super, Hyper, Meta) */
auto display = gdk_window_get_display(gdk_event_get_window(event));
@@ -390,9 +597,12 @@ Widget::read_modifiers_from_gdk(GdkEvent* event) const noexcept
return unsigned(mods);
}
+#endif /* VTE_GTK == 3 */
+
unsigned
Widget::key_event_translate_ctrlkey(KeyEvent const& event) const noexcept
{
+#if VTE_GTK == 3
if (event.keyval() < 128)
return event.keyval();
@@ -417,33 +627,55 @@ Widget::key_event_translate_ctrlkey(KeyEvent const& event) const noexcept
}
return keyval;
+#elif VTE_GTK == 4
+ // FIXMEgtk4: find a way to do this on gtk4
+ return event.keyval();
+#endif
}
KeyEvent
-Widget::key_event_from_gdk(GdkEventKey* event) const
+Widget::key_event_from_gdk(GdkEvent* event) const
{
auto type = EventBase::Type{};
- switch (gdk_event_get_event_type(reinterpret_cast<GdkEvent*>(event))) {
+ switch (gdk_event_get_event_type(event)) {
case GDK_KEY_PRESS: type = KeyEvent::Type::eKEY_PRESS; break;
case GDK_KEY_RELEASE: type = KeyEvent::Type::eKEY_RELEASE; break;
default: g_assert_not_reached(); return {};
}
- auto base_event = reinterpret_cast<GdkEvent*>(event);
- return {base_event,
+#if VTE_GTK == 3
+ auto keyval = unsigned{};
+ gdk_event_get_keyval(event, &keyval);
+ auto const scancode = unsigned(reinterpret_cast<GdkEventKey*>(event)->hardware_keycode);
+ auto const group = reinterpret_cast<GdkEventKey*>(event)->group;
+ auto const is_modifier = reinterpret_cast<GdkEventKey*>(event)->is_modifier != 0;
+#elif VTE_GTK == 4
+ auto keyval = gdk_key_event_get_keyval(event);
+ auto scancode = gdk_key_event_get_keycode(event);
+ auto const group = gdk_key_event_get_level(event);
+ auto const is_modifier = gdk_key_event_is_modifier(event) != false;
+#endif /* VTE_GTK */
+
+ return {event,
type,
- read_modifiers_from_gdk(base_event),
- event->keyval,
- event->hardware_keycode, // gdk_event_get_scancode(event),
- event->group,
- event->is_modifier != 0};
+#if VTE_GTK == 3
+ read_modifiers_from_gdk(event),
+#elif VTE_GTK == 4
+ gdk_event_get_modifier_state(event),
+#endif
+ keyval,
+ scancode,
+ group,
+ is_modifier};
}
+#if VTE_GTK == 3
+
MouseEvent
Widget::mouse_event_from_gdk(GdkEvent* event) const /* throws */
{
auto type = EventBase::Type{};
- auto press_count = 0u;
+ auto press_count = 0;
switch (gdk_event_get_event_type(event)) {
case GDK_2BUTTON_PRESS:
type = MouseEvent::Type::eMOUSE_PRESS;
@@ -478,7 +710,7 @@ Widget::mouse_event_from_gdk(GdkEvent* event) const /* throws */
!gdk_event_get_coords(event, &x, &y))
x = y = -1.; // FIXMEchpe or throw?
- auto button = unsigned{0};
+ auto button = 0u;
(void)gdk_event_get_button(event, &button);
return {type,
@@ -512,24 +744,79 @@ Widget::scroll_event_from_gdk(GdkEvent* event) const /* throws */
dx, dy};
}
+#endif /* VTE_GTK == 3 */
+
void
Widget::map() noexcept
{
+#if VTE_GTK == 3
if (m_event_window)
gdk_window_show_unraised(m_event_window);
+#endif
+}
+
+#if VTE_GTK == 4
+
+void
+Widget::measure(GtkOrientation orientation,
+ int for_size,
+ int* minimum,
+ int* natural,
+ int* minimum_baseline,
+ int* natural_baseline)
+{
+ _vte_debug_print(VTE_DEBUG_WIDGET_SIZE, "Widget measure for_size=%d orientation=%s\n",
+ for_size,
+ orientation == GTK_ORIENTATION_HORIZONTAL ? "horizontal" : "vertical");
+
+ switch (orientation) {
+ case GTK_ORIENTATION_HORIZONTAL:
+ terminal()->widget_measure_width(minimum, natural);
+ break;
+ case GTK_ORIENTATION_VERTICAL:
+ *minimum_baseline = *natural_baseline = 0;
+ terminal()->widget_measure_height(minimum, natural);
+ break;
+ }
+}
+
+#endif /* VTE_GTK == 4 */
+
+void
+Widget::padding_changed()
+{
+#if VTE_GTK == 3
+ auto padding = GtkBorder{};
+ auto context = gtk_widget_get_style_context(gtk());
+ gtk_style_context_get_padding(context,
+#if VTE_GTK == 3
+ gtk_style_context_get_state(context),
+#endif
+ &padding);
+ terminal()->set_border_padding(&padding);
+#endif /* VTE_GTK FIXMEgtk4 how to handle margin/padding? */
}
bool
Widget::primary_paste_enabled() const noexcept
{
auto primary_paste = gboolean{};
- g_object_get(gtk_widget_get_settings(gtk()),
+ g_object_get(m_settings.get(),
"gtk-enable-primary-paste", &primary_paste,
nullptr);
return primary_paste != false;
}
+bool
+Widget::query_tooltip(int x,
+ int y,
+ bool keyboard,
+ GtkTooltip* tooltip) noexcept
+{
+ return false;
+}
+
void
Widget::realize() noexcept
{
@@ -545,6 +832,7 @@ Widget::realize() noexcept
else
m_hyperlink_cursor = create_cursor(VTE_HYPERLINK_CURSOR);
+#if VTE_GTK == 3
/* Create an input window for the widget. */
auto allocation = m_terminal->get_allocated_rect();
GdkWindowAttr attributes;
@@ -579,15 +867,21 @@ Widget::realize() noexcept
m_event_window = gdk_window_new(gtk_widget_get_parent_window (m_widget),
&attributes, attributes_mask);
gtk_widget_register_window(m_widget, m_event_window);
+#endif /* VTE_GTK == 3 */
assert(!m_im_context);
- m_im_context.reset(gtk_im_multicontext_new());
-#if GTK_CHECK_VERSION (3, 24, 14)
+ m_im_context = vte::glib::take_ref(gtk_im_multicontext_new());
+#if (VTE_GTK == 3 && GTK_CHECK_VERSION (3, 24, 14)) || VTE_GTK == 4
g_object_set(m_im_context.get(),
"input-purpose", GTK_INPUT_PURPOSE_TERMINAL,
nullptr);
#endif
+
+#if VTE_GTK == 3
gtk_im_context_set_client_window(m_im_context.get(), m_event_window);
+#elif VTE_GTK == 4
+ gtk_im_context_set_client_widget(m_im_context.get(), gtk());
+#endif
g_signal_connect(m_im_context.get(), "commit",
G_CALLBACK(im_commit_cb), this);
g_signal_connect(m_im_context.get(), "preedit-start",
@@ -608,42 +902,82 @@ Widget::realize() noexcept
m_terminal->widget_realize();
}
+#if VTE_GTK == 4
+
+void
+Widget::root()
+{
+}
+
+#endif /* VTE_GTK == 4 */
+
+#if VTE_GTK == 3
+
void
Widget::screen_changed(GdkScreen *previous_screen) noexcept
{
auto gdk_screen = gtk_widget_get_screen(m_widget);
- if (previous_screen != nullptr &&
- (gdk_screen != previous_screen || gdk_screen == nullptr)) {
- auto settings = gtk_settings_get_for_screen(previous_screen);
- g_signal_handlers_disconnect_matched(settings, G_SIGNAL_MATCH_DATA,
+ if (gdk_screen == previous_screen || gdk_screen == nullptr)
+ return;
+
+ connect_settings();
+}
+
+#elif VTE_GTK == 4
+
+void
+Widget::display_changed() noexcept
+{
+ /* There appears to be no way to retrieve the previous display */
+ connect_settings();
+}
+
+#endif /* VTE_GTK */
+
+void
+Widget::connect_settings()
+{
+ auto settings = vte::glib::make_ref(gtk_widget_get_settings(m_widget));
+ if (settings == m_settings)
+ return;
+
+ if (m_settings)
+ g_signal_handlers_disconnect_matched(m_settings.get(), G_SIGNAL_MATCH_DATA,
0, 0, nullptr, nullptr,
this);
- }
- if (gdk_screen == previous_screen || gdk_screen == nullptr)
- return;
+ m_settings = std::move(settings);
settings_changed();
- auto settings = gtk_widget_get_settings(m_widget);
- g_signal_connect (settings, "notify::gtk-cursor-blink",
- G_CALLBACK(settings_notify_cb), this);
- g_signal_connect (settings, "notify::gtk-cursor-blink-time",
- G_CALLBACK(settings_notify_cb), this);
- g_signal_connect (settings, "notify::gtk-cursor-blink-timeout",
- G_CALLBACK(settings_notify_cb), this);
+ g_signal_connect(m_settings.get(), "notify::gtk-cursor-blink",
+ G_CALLBACK(settings_notify_cb), this);
+ g_signal_connect(m_settings.get(), "notify::gtk-cursor-blink-time",
+ G_CALLBACK(settings_notify_cb), this);
+ g_signal_connect(m_settings.get(), "notify::gtk-cursor-blink-timeout",
+ G_CALLBACK(settings_notify_cb), this);
+#if VTE_GTK == 4
+ g_signal_connect(m_settings.get(), "notify::gtk-cursor-aspect-ratio",
+ G_CALLBACK(settings_notify_cb), this);
+#endif
}
void
-Widget::settings_changed() noexcept
+Widget::settings_changed()
{
auto blink = gboolean{};
auto blink_time = int{};
auto blink_timeout = int{};
- g_object_get(gtk_widget_get_settings(m_widget),
+#if VTE_GTK == 4
+ auto aspect = double{};
+#endif
+ g_object_get(m_settings.get(),
"gtk-cursor-blink", &blink,
"gtk-cursor-blink-time", &blink_time,
"gtk-cursor-blink-timeout", &blink_timeout,
+#if VTE_GTK == 4
+ "gtk-cursor-aspect-ratio", &aspect,
+#endif
nullptr);
_vte_debug_print(VTE_DEBUG_MISC,
@@ -651,6 +985,10 @@ Widget::settings_changed() noexcept
blink, blink_time, blink_timeout);
m_terminal->set_blink_settings(blink, blink_time, blink_timeout);
+
+#if VTE_GTK == 4
+ m_terminal->set_cursor_aspect(aspect);
+#endif
}
void
@@ -664,6 +1002,30 @@ Widget::set_cursor(CursorType type) noexcept
}
}
+void
+Widget::set_hscroll_policy(GtkScrollablePolicy policy)
+{
+ m_hscroll_policy = policy;
+
+#if VTE_GTK == 3
+ gtk_widget_queue_resize_no_redraw(gtk());
+#elif VTE_GTK == 4
+ gtk_widget_queue_resize(gtk());
+#endif
+}
+
+void
+Widget::set_vscroll_policy(GtkScrollablePolicy policy)
+{
+ m_vscroll_policy = policy;
+
+#if VTE_GTK == 3
+ gtk_widget_queue_resize_no_redraw(gtk());
+#elif VTE_GTK == 4
+ gtk_widget_queue_resize(gtk());
+#endif
+}
+
bool
Widget::set_pty(VtePty* pty_obj) noexcept
{
@@ -704,10 +1066,17 @@ Widget::unset_pty() noexcept
g_object_notify_by_pspec(object(), pspecs[PROP_PTY]);
}
+#if VTE_GTK == 3
+
void
-Widget::size_allocate(GtkAllocation* allocation) noexcept
+Widget::size_allocate(GtkAllocation* allocation)
{
- m_terminal->widget_size_allocate(allocation);
+ _vte_debug_print(VTE_DEBUG_WIDGET_SIZE, "Widget size allocate width=%d height=%d x=%d y=%d\n",
+ allocation->width, allocation->height, allocation->x, allocation->y);
+
+ m_terminal->widget_size_allocate(allocation->width, allocation->height, -1);
+
+ gtk_widget_set_allocation(gtk(), allocation);
if (realized())
gdk_window_move_resize(m_event_window,
@@ -717,6 +1086,21 @@ Widget::size_allocate(GtkAllocation* allocation) noexcept
allocation->height);
}
+#elif VTE_GTK == 4
+
+void
+Widget::size_allocate(int width,
+ int height,
+ int baseline)
+{
+ _vte_debug_print(VTE_DEBUG_WIDGET_SIZE, "Widget size allocate width=%d height=%d baseline=%d\n",
+ width, height, baseline);
+
+ terminal()->widget_size_allocate(width, height, baseline);
+}
+
+#endif /* VTE_GTK */
+
bool
Widget::should_emit_signal(int id) noexcept
{
@@ -726,14 +1110,36 @@ Widget::should_emit_signal(int id) noexcept
false /* not interested in blocked handlers */) != FALSE;
}
+void
+Widget::state_flags_changed(GtkStateFlags old_flags)
+{
+ _vte_debug_print(VTE_DEBUG_STYLE, "Widget state flags changed\n");
+}
+
+#if VTE_GTK == 4
+
+void
+Widget::snapshot(GtkSnapshot* snapshot_object)
+{
+ _vte_debug_print(VTE_DEBUG_DRAW, "Widget snapshot\n");
+
+ auto rect = terminal()->allocated_rect();
+ auto region = vte::take_freeable(cairo_region_create_rectangle(rect));
+ auto grect = vte::graphene::make_rect(rect);
+ auto cr = vte::take_freeable(gtk_snapshot_append_cairo(snapshot_object, &grect));
+ terminal()->draw(cr.get(), region.get());
+}
+
+#endif /* VTE_GTK == 4 */
+
+#if VTE_GTK == 3
+
void
Widget::style_updated() noexcept
{
- auto padding = GtkBorder{};
- auto context = gtk_widget_get_style_context(gtk());
- gtk_style_context_get_padding(context, gtk_style_context_get_state(context),
- &padding);
- m_terminal->set_border_padding(&padding);
+ _vte_debug_print(VTE_DEBUG_STYLE, "Widget style changed\n");
+
+ padding_changed();
auto aspect = float{};
gtk_widget_style_get(gtk(), "cursor-aspect-ratio", &aspect, nullptr);
@@ -742,13 +1148,48 @@ Widget::style_updated() noexcept
m_terminal->widget_style_updated();
}
+#endif /* VTE_GTK == 3 */
+
+#if VTE_GTK == 4
+
+void
+Widget::system_setting_changed(GtkSystemSetting setting)
+{
+ _vte_debug_print(VTE_DEBUG_STYLE, "Widget system settings %d changed\n", int(setting));
+
+ switch (setting) {
+ case GTK_SYSTEM_SETTING_DISPLAY:
+ display_changed();
+ break;
+
+ case GTK_SYSTEM_SETTING_DPI:
+ break;
+
+ case GTK_SYSTEM_SETTING_FONT_CONFIG:
+ break;
+
+ case GTK_SYSTEM_SETTING_FONT_NAME:
+ break;
+
+ case GTK_SYSTEM_SETTING_ICON_THEME:
+ break;
+
+ default:
+ break;
+ }
+}
+
+#endif /* VTE_GTK == 4 */
+
void
Widget::unmap() noexcept
{
m_terminal->widget_unmap();
+#if VTE_GTK == 3
if (m_event_window)
gdk_window_hide(m_event_window);
+#endif
}
void
@@ -756,16 +1197,17 @@ Widget::unrealize() noexcept
{
m_terminal->widget_unrealize();
+ // FIXMEgtk4 only withdraw content from clipboard, not unselect?
if (m_clipboard) {
terminal()->widget_clipboard_data_clear(*m_clipboard);
m_clipboard->disown();
+ m_clipboard.reset();
}
if (m_primary_clipboard) {
terminal()->widget_clipboard_data_clear(*m_primary_clipboard);
m_primary_clipboard->disown();
+ m_primary_clipboard.reset();
}
- m_clipboard.reset();
- m_primary_clipboard.reset();
m_default_cursor.reset();
m_invisible_cursor.reset();
@@ -779,15 +1221,30 @@ Widget::unrealize() noexcept
0, 0, NULL, NULL,
this);
m_terminal->im_preedit_reset();
+#if VTE_GTK == 3
gtk_im_context_set_client_window(m_im_context.get(), nullptr);
+#elif VTE_GTK == 4
+ gtk_im_context_set_client_widget(m_im_context.get(), nullptr);
+#endif
m_im_context.reset();
+#if VTE_GTK == 3
/* Destroy input window */
gtk_widget_unregister_window(m_widget, m_event_window);
gdk_window_destroy(m_event_window);
m_event_window = nullptr;
+#endif /* VTE_GTK == 3 */
}
+#if VTE_GTK == 4
+
+void
+Widget::unroot()
+{
+}
+
+#endif /* VTE_GTK == 4 */
+
} // namespace platform
} // namespace vte
diff --git a/src/widget.hh b/src/widget.hh
index 8f245154..144c1f55 100644
--- a/src/widget.hh
+++ b/src/widget.hh
@@ -20,6 +20,8 @@
#include <memory>
#include <optional>
#include <string>
+#include <tuple>
+#include <utility>
#include <variant>
#include "vteterminal.h"
@@ -95,7 +97,7 @@ protected:
unsigned modifiers,
unsigned keyval,
unsigned keycode,
- uint8_t group,
+ unsigned group,
bool is_modifier) noexcept
: EventBase{type},
m_platform_event{gdk_event},
@@ -126,12 +128,23 @@ public:
constexpr auto is_key_press() const noexcept { return type() == Type::eKEY_PRESS; }
constexpr auto is_key_release() const noexcept { return type() == Type::eKEY_RELEASE; }
+ bool matches(unsigned keyval,
+ unsigned modifiers) const noexcept
+ {
+#if VTE_GTK == 3
+ return false; // FIXMEgtk3
+#elif VTE_GTK == 4
+ return gdk_key_event_matches(platform_event(),
+ keyval, GdkModifierType(modifiers)) == GDK_KEY_MATCH_EXACT;
+#endif
+ }
+
private:
GdkEvent* m_platform_event;
unsigned m_modifiers;
unsigned m_keyval;
unsigned m_keycode;
- uint8_t m_group;
+ unsigned m_group;
bool m_is_modifier;
}; // class KeyEvent
@@ -154,7 +167,7 @@ protected:
MouseEvent() noexcept = default;
constexpr MouseEvent(Type type,
- unsigned press_count,
+ int press_count,
unsigned modifiers,
Button button,
double x,
@@ -190,7 +203,7 @@ public:
constexpr auto is_mouse_release() const noexcept { return type() == Type::eMOUSE_RELEASE; }
private:
- unsigned m_press_count;
+ int m_press_count;
unsigned m_modifiers;
Button m_button;
double m_x;
@@ -257,24 +270,60 @@ public:
void unrealize() noexcept;
void map() noexcept;
void unmap() noexcept;
+ void state_flags_changed(GtkStateFlags old_flags);
+ void direction_changed(GtkTextDirection old_direction) noexcept;
+ bool query_tooltip(int x,
+ int y,
+ bool keyboard,
+ GtkTooltip* tooltip) noexcept;
+
+ void connect_settings();
+ void padding_changed();
+ void settings_changed();
+
+#if VTE_GTK == 3
void style_updated() noexcept;
void draw(cairo_t *cr) noexcept { m_terminal->widget_draw(cr); }
void get_preferred_width(int *minimum_width,
- int *natural_width) const noexcept {
m_terminal->widget_get_preferred_width(minimum_width, natural_width); }
+ int *natural_width) const noexcept {
m_terminal->widget_measure_width(minimum_width, natural_width); }
void get_preferred_height(int *minimum_height,
- int *natural_height) const noexcept {
m_terminal->widget_get_preferred_height(minimum_height, natural_height); }
- void size_allocate(GtkAllocation *allocation) noexcept;
-
- void focus_in(GdkEventFocus *event) noexcept { m_terminal->widget_focus_in(); }
- void focus_out(GdkEventFocus *event) noexcept { m_terminal->widget_focus_out(); }
- bool key_press(GdkEventKey *event) noexcept { return
m_terminal->widget_key_press(key_event_from_gdk(event)); }
- bool key_release(GdkEventKey *event) noexcept { return
m_terminal->widget_key_release(key_event_from_gdk(event)); }
- bool button_press(GdkEventButton *event) noexcept { return
m_terminal->widget_mouse_press(mouse_event_from_gdk(reinterpret_cast<GdkEvent*>(event))); }
- bool button_release(GdkEventButton *event) noexcept { return
m_terminal->widget_mouse_release(mouse_event_from_gdk(reinterpret_cast<GdkEvent*>(event))); }
- void enter(GdkEventCrossing *event) noexcept {
m_terminal->widget_mouse_enter(mouse_event_from_gdk(reinterpret_cast<GdkEvent*>(event))); }
- void leave(GdkEventCrossing *event) noexcept {
m_terminal->widget_mouse_leave(mouse_event_from_gdk(reinterpret_cast<GdkEvent*>(event))); }
- bool scroll(GdkEventScroll *event) noexcept { return
m_terminal->widget_mouse_scroll(scroll_event_from_gdk(reinterpret_cast<GdkEvent*>(event))); }
- bool motion_notify(GdkEventMotion *event) noexcept { return
m_terminal->widget_mouse_motion(mouse_event_from_gdk(reinterpret_cast<GdkEvent*>(event))); }
+ int *natural_height) const noexcept {
m_terminal->widget_measure_height(minimum_height, natural_height); }
+ void size_allocate(GtkAllocation *allocation);
+
+ void event_focus_in(GdkEventFocus *event);
+ void event_focus_out(GdkEventFocus *event);
+ bool event_key_press(GdkEventKey *event);
+ bool event_key_release(GdkEventKey *event);
+ bool event_button_press(GdkEventButton *event);
+ bool event_button_release(GdkEventButton *event);
+ void event_enter(GdkEventCrossing *event);
+ void event_leave(GdkEventCrossing *event);
+ bool event_scroll(GdkEventScroll *event);
+ bool event_motion_notify(GdkEventMotion *event);
+
+ void screen_changed (GdkScreen *previous_screen) noexcept;
+#endif /* VTE_GTK == 3 */
+
+#if VTE_GTK == 4
+ void size_allocate(int width,
+ int height,
+ int baseline);
+ void root();
+ void unroot();
+ void measure(GtkOrientation orientation,
+ int for_size,
+ int* minimum,
+ int* natural,
+ int* minimum_baseline,
+ int* natural_baseline);
+ std::pair<bool, bool> compute_expand();
+ void css_changed(GtkCssStyleChange* change);
+ void system_setting_changed(GtkSystemSetting setting);
+ void snapshot(GtkSnapshot* snapshot_object);
+ bool contains(double x,
+ double y);
+ void display_changed() noexcept;
+#endif /* VTE_GTK == 4 */
void grab_focus() noexcept { gtk_widget_grab_focus(gtk()); }
@@ -291,17 +340,14 @@ public:
void copy(vte::platform::ClipboardType type,
vte::platform::ClipboardFormat format) noexcept { m_terminal->widget_copy(type, format); }
- void screen_changed (GdkScreen *previous_screen) noexcept;
- void settings_changed() noexcept;
-
void beep() noexcept;
- void set_hadjustment(vte::glib::RefPtr<GtkAdjustment>&& adjustment) noexcept { m_hadjustment =
std::move(adjustment); }
- void set_vadjustment(vte::glib::RefPtr<GtkAdjustment>&& adjustment) {
terminal()->widget_set_vadjustment(std::move(adjustment)); }
+ void set_hadjustment(vte::glib::RefPtr<GtkAdjustment> adjustment) noexcept { m_hadjustment =
std::move(adjustment); }
+ void set_vadjustment(vte::glib::RefPtr<GtkAdjustment> adjustment) {
terminal()->widget_set_vadjustment(std::move(adjustment)); }
auto hadjustment() noexcept { return m_hadjustment.get(); }
auto vadjustment() noexcept { return terminal()->vadjustment(); }
- void set_hscroll_policy(GtkScrollablePolicy policy) noexcept { m_hscroll_policy = policy; }
- void set_vscroll_policy(GtkScrollablePolicy policy) noexcept { m_vscroll_policy = policy; }
+ void set_hscroll_policy(GtkScrollablePolicy policy);
+ void set_vscroll_policy(GtkScrollablePolicy policy);
auto hscroll_policy() const noexcept { return m_hscroll_policy; }
auto vscroll_policy() const noexcept { return m_vscroll_policy; }
auto padding() const noexcept { return terminal()->padding(); }
@@ -346,12 +392,15 @@ public:
return terminal()->regex_match_check(column, row, tag);
}
+#if VTE_GTK == 3
+
char* regex_match_check(GdkEvent* event,
int* tag)
{
return terminal()->regex_match_check(mouse_event_from_gdk(event), tag);
}
+
bool regex_match_check_extra(GdkEvent* event,
vte::base::Regex const** regexes,
size_t n_regexes,
@@ -367,6 +416,8 @@ public:
return terminal()->hyperlink_check(mouse_event_from_gdk(event));
}
+#endif /* VTE_GTK */
+
bool should_emit_signal(int id) noexcept;
bool set_sixel_enabled(bool enabled) noexcept { return m_terminal->set_sixel_enabled(enabled); }
@@ -381,7 +432,9 @@ protected:
eHyperlink
};
+#if VTE_GTK == 3
GdkWindow* event_window() const noexcept { return m_event_window; }
+#endif
bool realized() const noexcept
{
@@ -415,10 +468,12 @@ public: // FIXMEchpe
void im_preedit_changed() noexcept;
private:
+ KeyEvent key_event_from_gdk(GdkEvent* event) const;
+#if VTE_GTK == 3
unsigned read_modifiers_from_gdk(GdkEvent* event) const noexcept;
- KeyEvent key_event_from_gdk(GdkEventKey* event) const;
MouseEvent mouse_event_from_gdk(GdkEvent* event) const /* throws */;
ScrollEvent scroll_event_from_gdk(GdkEvent* event) const /* throws */;
+#endif
void clipboard_request_received_cb(Clipboard const& clipboard,
std::string_view const& text);
@@ -432,8 +487,12 @@ private:
vte::terminal::Terminal* m_terminal;
+#if VTE_GTK == 3
/* Event window */
GdkWindow *m_event_window;
+#endif
+
+ vte::glib::RefPtr<GtkSettings> m_settings{nullptr};
/* Cursors */
vte::glib::RefPtr<GdkCursor> m_default_cursor;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]