Blob Blame History Raw
From b0b746ddf50375173d0b98baf12740dc910745d2 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Wed, 7 Jan 2015 16:01:00 +0100
Subject: [PATCH 01/11] Add sequences and signals for desktop notification

Add sequences
  OSC 777 ; notify ; SUMMARY ; BODY BEL
  OSC 777 ; notify ; SUMMARY BEL
  OSC 777 ; notify ; SUMMARY ; BODY ST
  OSC 777 ; notify ; SUMMARY ST

that let terminal applications send a notification to the desktop
environment.

Based on Enlightenment's Terminology:
https://phab.enlightenment.org/T1765

https://bugzilla.gnome.org/show_bug.cgi?id=711059
---
 src/marshal.list      |  1 +
 src/vte.cc            |  8 ++++++++
 src/vte/vteterminal.h |  4 +++-
 src/vtegtk.cc         | 21 +++++++++++++++++++++
 src/vtegtk.hh         |  1 +
 src/vteinternal.hh    |  8 ++++++++
 src/vteseq.cc         | 32 +++++++++++++++++++++++++++++++-
 7 files changed, 73 insertions(+), 2 deletions(-)

diff --git a/src/marshal.list b/src/marshal.list
index 241128c3ccfe..4412cf3d5f5c 100644
--- a/src/marshal.list
+++ b/src/marshal.list
@@ -1,3 +1,4 @@
 VOID:STRING,BOXED
+VOID:STRING,STRING
 VOID:STRING,UINT
 VOID:UINT,UINT
diff --git a/src/vte.cc b/src/vte.cc
index 4ea466bd9360..033abcfe83cb 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -10100,6 +10100,14 @@ Terminal::emit_pending_signals()
 
 	emit_adjustment_changed();
 
+        if (m_pending_changes & vte::to_integral(PendingChanges::NOTIFICATION)) {
+                _vte_debug_print (VTE_DEBUG_SIGNALS,
+                                  "Emitting `notification-received'.\n");
+                g_signal_emit(freezer.get(), signals[SIGNAL_NOTIFICATION_RECEIVED], 0,
+                              m_notification_summary.c_str(),
+                              m_notification_body.c_str());
+        }
+
 	if (m_pending_changes & vte::to_integral(PendingChanges::TITLE)) {
                 if (m_window_title != m_window_title_pending) {
                         m_window_title.swap(m_window_title_pending);
diff --git a/src/vte/vteterminal.h b/src/vte/vteterminal.h
index e705ece69ad6..668a7dbeae96 100644
--- a/src/vte/vteterminal.h
+++ b/src/vte/vteterminal.h
@@ -102,8 +102,10 @@ struct _VteTerminalClass {
 
 	void (*bell)(VteTerminal* terminal);
 
+	void (*notification_received)(VteTerminal* terminal, const gchar *summary, const gchar *body);
+
         /* Padding for future expansion. */
-        gpointer padding[16];
+        gpointer padding[15];
 
         VteTerminalClassPrivate *priv;
 };
diff --git a/src/vtegtk.cc b/src/vtegtk.cc
index c68a0f1ac388..e3274ff3df90 100644
--- a/src/vtegtk.cc
+++ b/src/vtegtk.cc
@@ -983,6 +983,7 @@ vte_terminal_class_init(VteTerminalClass *klass)
 	klass->child_exited = NULL;
 	klass->encoding_changed = NULL;
 	klass->char_size_changed = NULL;
+	klass->notification_received = NULL;
 	klass->window_title_changed = NULL;
 	klass->icon_title_changed = NULL;
 	klass->selection_changed = NULL;
@@ -1064,6 +1065,26 @@ vte_terminal_class_init(VteTerminalClass *klass)
                                    G_OBJECT_CLASS_TYPE(klass),
                                    g_cclosure_marshal_VOID__INTv);
 
+        /**
+         * VteTerminal::notification-received:
+         * @vteterminal: the object which received the signal
+         * @summary: The summary
+         * @body: (allow-none): Extra optional text
+         *
+         * Emitted when a process running in the terminal wants to
+         * send a notification to the desktop environment.
+         */
+        signals[SIGNAL_NOTIFICATION_RECEIVED] =
+                g_signal_new(I_("notification-received"),
+                             G_OBJECT_CLASS_TYPE(klass),
+                             G_SIGNAL_RUN_LAST,
+                             G_STRUCT_OFFSET(VteTerminalClass, notification_received),
+                             NULL,
+                             NULL,
+                             _vte_marshal_VOID__STRING_STRING,
+                             G_TYPE_NONE,
+                             2, G_TYPE_STRING, G_TYPE_STRING);
+
         /**
          * VteTerminal::window-title-changed:
          * @vteterminal: the object which received the signal
diff --git a/src/vtegtk.hh b/src/vtegtk.hh
index 1cb8cb49967b..389b86d2e557 100644
--- a/src/vtegtk.hh
+++ b/src/vtegtk.hh
@@ -56,6 +56,7 @@ enum {
         SIGNAL_TEXT_INSERTED,
         SIGNAL_TEXT_MODIFIED,
         SIGNAL_TEXT_SCROLLED,
+        SIGNAL_NOTIFICATION_RECEIVED,
         SIGNAL_WINDOW_TITLE_CHANGED,
         LAST_SIGNAL
 };
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index 7a257afed861..38aaf421ec30 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -621,6 +621,10 @@ public:
         gboolean m_cursor_moved_pending;
         gboolean m_contents_changed_pending;
 
+        /* desktop notification */
+        std::string m_notification_summary;
+        std::string m_notification_body;
+
         std::string m_window_title{};
         std::string m_current_directory_uri{};
         std::string m_current_file_uri{};
@@ -634,6 +638,7 @@ public:
                 TITLE = 1u << 0,
                 CWD   = 1u << 1,
                 CWF   = 1u << 2,
+                NOTIFICATION = 1u << 3,
         };
         unsigned m_pending_changes{0};
 
@@ -1358,6 +1363,9 @@ public:
                              int osc) noexcept;
 
         /* OSC handlers */
+        void handle_urxvt_extension(vte::parser::Sequence const& seq,
+                                    vte::parser::StringTokeniser::const_iterator& token,
+                                    vte::parser::StringTokeniser::const_iterator const& endtoken) noexcept;
         void set_color(vte::parser::Sequence const& seq,
                        vte::parser::StringTokeniser::const_iterator& token,
                        vte::parser::StringTokeniser::const_iterator const& endtoken,
diff --git a/src/vteseq.cc b/src/vteseq.cc
index bde2fa7ba0ab..7ab65b6d204a 100644
--- a/src/vteseq.cc
+++ b/src/vteseq.cc
@@ -1377,6 +1377,33 @@ Terminal::delete_lines(vte::grid::row_t param)
         m_text_deleted_flag = TRUE;
 }
 
+void
+Terminal::handle_urxvt_extension(vte::parser::Sequence const& seq,
+                                 vte::parser::StringTokeniser::const_iterator& token,
+                                 vte::parser::StringTokeniser::const_iterator const& endtoken) noexcept
+{
+        if (token == endtoken)
+                return;
+
+        if (*token == "notify") {
+                ++token;
+
+                if (token == endtoken)
+                        return;
+
+                m_notification_summary = *token;
+                m_notification_body.clear();
+                m_pending_changes |= vte::to_integral(PendingChanges::NOTIFICATION);
+                ++token;
+
+                if (token == endtoken)
+                        return;
+
+                m_notification_body = *token;
+                return;
+        }
+}
+
 bool
 Terminal::get_osc_color_index(int osc,
                                         int value,
@@ -6519,6 +6546,10 @@ Terminal::OSC(vte::parser::Sequence const& seq)
                 reset_color(VTE_HIGHLIGHT_FG, VTE_COLOR_SOURCE_ESCAPE);
                 break;
 
+        case VTE_OSC_URXVT_EXTENSION:
+                handle_urxvt_extension(seq, it, cend);
+                break;
+
         case VTE_OSC_XTERM_SET_ICON_TITLE:
         case VTE_OSC_XTERM_SET_XPROPERTY:
         case VTE_OSC_XTERM_SET_COLOR_MOUSE_CURSOR_FG:
@@ -6559,7 +6590,6 @@ Terminal::OSC(vte::parser::Sequence const& seq)
         case VTE_OSC_URXVT_SET_FONT_BOLD_ITALIC:
         case VTE_OSC_URXVT_VIEW_UP:
         case VTE_OSC_URXVT_VIEW_DOWN:
-        case VTE_OSC_URXVT_EXTENSION:
         case VTE_OSC_YF_RQGWR:
         default:
                 break;
-- 
2.31.1


From f1ba75377276560079af1d8f615380abd5fc9438 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Thu, 29 Jan 2015 13:09:17 +0100
Subject: [PATCH 02/11] vte.sh: Emit OSC 777 from PROMPT_COMMAND

For some reason, the three consecutive backslashes break the parsing.
As Christian Persch suggested, replacing the double quotes with
singles fixes it.

https://bugzilla.gnome.org/show_bug.cgi?id=711059
---
 src/vte.sh.in | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/vte.sh.in b/src/vte.sh.in
index 3ac99d7ec04f..2c6f668142c3 100644
--- a/src/vte.sh.in
+++ b/src/vte.sh.in
@@ -27,10 +27,12 @@ __vte_osc7 () {
 }
 
 __vte_prompt_command() {
+  local command=$(HISTTIMEFORMAT= history 1 | sed 's/^ *[0-9]\+ *//')
+  command="${command//;/ }"
   local pwd='~'
   [ "$PWD" != "$HOME" ] && pwd=${PWD/#$HOME\//\~\/}
   pwd="${pwd//[[:cntrl:]]}"
-  printf "\033]0;%s@%s:%s\033\\" "${USER}" "${HOSTNAME%%.*}" "${pwd}"
+  printf '\033]777;notify;Command completed;%s\033\\\033]0;%s@%s:%s\033\\' "${command}" "${USER}" "${HOSTNAME%%.*}" "${pwd}"
   __vte_osc7
 }
 
-- 
2.31.1


From 5c825104d44100b72d98cf02ea0751065576af4e Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Thu, 22 Jan 2015 16:37:10 +0100
Subject: [PATCH 03/11] Test the notification-received signal

---
 bindings/vala/app.vala |  7 +++++++
 src/app/app.cc         | 10 ++++++++++
 2 files changed, 17 insertions(+)

diff --git a/bindings/vala/app.vala b/bindings/vala/app.vala
index 8ab27e5aaf9a..025f971b2eb0 100644
--- a/bindings/vala/app.vala
+++ b/bindings/vala/app.vala
@@ -309,6 +309,8 @@ class Window : Gtk.ApplicationWindow
     if (Options.object_notifications)
       terminal.notify.connect(notify_cb);
 
+    terminal.notification_received.connect(notification_received_cb);
+
     /* Settings */
     if (Options.no_double_buffer)
       terminal.set_double_buffered(false);
@@ -780,6 +782,11 @@ class Window : Gtk.ApplicationWindow
     set_title(terminal.get_window_title());
   }
 
+  private void notification_received_cb(Vte.Terminal terminal, string summary, string? body)
+  {
+    print ("[%s]: %s\n", summary, body);
+  }
+
 } /* class Window */
 
 class App : Gtk.Application
diff --git a/src/app/app.cc b/src/app/app.cc
index 37d51c6b8963..73810251a4d0 100644
--- a/src/app/app.cc
+++ b/src/app/app.cc
@@ -1877,6 +1877,14 @@ window_window_title_changed_cb(VteTerminal* terminal,
                              vte_terminal_get_window_title(window->terminal));
 }
 
+static void
+notification_received_cb(VteTerminal *terminal,
+                         const gchar *summary,
+                         const gchar *body)
+{
+        g_print("[%s]: %s\n", summary, body);
+}
+
 static void
 window_lower_window_cb(VteTerminal* terminal,
                        VteappWindow* window)
@@ -2115,6 +2123,8 @@ vteapp_window_constructed(GObject *object)
         if (options.object_notifications)
                 g_signal_connect(window->terminal, "notify", G_CALLBACK(window_notify_cb), window);
 
+        g_signal_connect(window->terminal, "notification-received", G_CALLBACK(notification_received_cb), NULL);
+
         /* Settings */
         if (options.no_double_buffer) {
                 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
-- 
2.31.1


From aa647920fe6dc8ee0f4d23d8d90bafc649d01efe Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Fri, 13 May 2016 17:53:54 +0200
Subject: [PATCH 04/11] Add a property to configure the scroll speed

By default, it is set to zero which gives the current behaviour of
moving the buffer by a function of the number of visible rows.

https://bugzilla.redhat.com/show_bug.cgi?id=1103380
---
 doc/reference/vte-sections.txt |  1 +
 src/vte.cc                     | 19 ++++++++++++-
 src/vte/vteterminal.h          |  4 +++
 src/vtegtk.cc                  | 51 ++++++++++++++++++++++++++++++++++
 src/vtegtk.hh                  |  1 +
 src/vteinternal.hh             |  2 ++
 6 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/doc/reference/vte-sections.txt b/doc/reference/vte-sections.txt
index c69181da7c78..dba88c156fe8 100644
--- a/doc/reference/vte-sections.txt
+++ b/doc/reference/vte-sections.txt
@@ -54,6 +54,7 @@ vte_terminal_get_cursor_blink_mode
 vte_terminal_set_cursor_blink_mode
 vte_terminal_get_text_blink_mode
 vte_terminal_set_text_blink_mode
+vte_terminal_set_scroll_speed
 vte_terminal_set_scrollback_lines
 vte_terminal_get_scrollback_lines
 vte_terminal_set_font
diff --git a/src/vte.cc b/src/vte.cc
index 033abcfe83cb..02fe5cbf2df7 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -9293,6 +9293,7 @@ vte_cairo_get_clip_region (cairo_t *cr)
 bool
 Terminal::widget_mouse_scroll(vte::platform::ScrollEvent const& event)
 {
+	gdouble scroll_speed;
 	gdouble v;
 	gint cnt, i;
 	int button;
@@ -9327,7 +9328,13 @@ Terminal::widget_mouse_scroll(vte::platform::ScrollEvent const& event)
 		return true;
 	}
 
-        v = MAX (1., ceil (gtk_adjustment_get_page_increment (m_vadjustment.get()) / 10.));
+	if (m_scroll_speed == 0) {
+		scroll_speed = ceil (gtk_adjustment_get_page_increment (m_vadjustment.get()) / 10.);
+	} else {
+		scroll_speed = m_scroll_speed;
+	}
+
+	v = MAX (1., scroll_speed);
 	_vte_debug_print(VTE_DEBUG_EVENTS,
 			"Scroll speed is %d lines per non-smooth scroll unit\n",
 			(int) v);
@@ -9641,6 +9648,16 @@ Terminal::decscusr_cursor_shape() const noexcept
         }
 }
 
+bool
+Terminal::set_scroll_speed(unsigned int scroll_speed)
+{
+        if (scroll_speed == m_scroll_speed)
+                return false;
+
+        m_scroll_speed = scroll_speed;
+        return true;
+}
+
 bool
 Terminal::set_scrollback_lines(long lines)
 {
diff --git a/src/vte/vteterminal.h b/src/vte/vteterminal.h
index 668a7dbeae96..0143f0b9dd4d 100644
--- a/src/vte/vteterminal.h
+++ b/src/vte/vteterminal.h
@@ -310,6 +310,10 @@ void vte_terminal_set_cursor_shape(VteTerminal *terminal,
 _VTE_PUBLIC
 VteCursorShape vte_terminal_get_cursor_shape(VteTerminal *terminal) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1);
 
+_VTE_PUBLIC
+void vte_terminal_set_scroll_speed(VteTerminal *terminal,
+                                   guint scroll_speed) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1);
+
 /* Set the number of scrollback lines, above or at an internal minimum. */
 _VTE_PUBLIC
 void vte_terminal_set_scrollback_lines(VteTerminal *terminal,
diff --git a/src/vtegtk.cc b/src/vtegtk.cc
index e3274ff3df90..b4bcd3d9a1d5 100644
--- a/src/vtegtk.cc
+++ b/src/vtegtk.cc
@@ -758,6 +758,9 @@ try
                 case PROP_REWRAP_ON_RESIZE:
                         g_value_set_boolean (value, vte_terminal_get_rewrap_on_resize (terminal));
                         break;
+                case PROP_SCROLL_SPEED:
+                        g_value_set_uint (value, impl->m_scroll_speed);
+                        break;
                 case PROP_SCROLLBACK_LINES:
                         g_value_set_uint (value, vte_terminal_get_scrollback_lines(terminal));
                         break;
@@ -876,6 +879,9 @@ try
                 case PROP_REWRAP_ON_RESIZE:
                         vte_terminal_set_rewrap_on_resize (terminal, g_value_get_boolean (value));
                         break;
+                case PROP_SCROLL_SPEED:
+                        vte_terminal_set_scroll_speed (terminal, g_value_get_uint (value));
+                        break;
                 case PROP_SCROLLBACK_LINES:
                         vte_terminal_set_scrollback_lines (terminal, g_value_get_uint (value));
                         break;
@@ -1966,6 +1972,21 @@ vte_terminal_class_init(VteTerminalClass *klass)
                                       TRUE,
                                       (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY));
 
+        /**
+         * VteTerminal:scroll-speed:
+         *
+         * The number of lines by which the buffer is moved when
+         * scrolling with a mouse wheel on top of the terminal
+         * Setting it to zero will cause the buffer to be moved by an
+         * amount depending on the number of visible rows the widget
+         * can display.
+         */
+        pspecs[PROP_SCROLL_SPEED] =
+                g_param_spec_uint ("scroll-speed", NULL, NULL,
+                                   0, G_MAXUINT,
+                                   0,
+                                   (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY));
+
         /**
          * VteTerminal:scrollback-lines:
          *
@@ -5367,6 +5388,36 @@ catch (...)
         return -1;
 }
 
+/**
+ * vte_terminal_set_scroll_speed:
+ * @terminal: a #VteTerminal
+ * @scroll_speed: move the buffer by this number of lines while scrolling
+ *
+ * Sets the number of lines by which the buffer is moved when
+ * scrolling with a mouse wheel. Setting it to zero will cause the
+ * buffer to be moved by an amount depending on the number of visible
+ * rows the widget can display.
+ */
+void
+vte_terminal_set_scroll_speed(VteTerminal *terminal,
+                              guint scroll_speed) noexcept
+try
+{
+        g_return_if_fail(VTE_IS_TERMINAL(terminal));
+
+        GObject *object = G_OBJECT(terminal);
+        g_object_freeze_notify(object);
+
+        if (IMPL(terminal)->set_scroll_speed(scroll_speed))
+                g_object_notify_by_pspec(object, pspecs[PROP_SCROLL_SPEED]);
+
+        g_object_thaw_notify(object);
+}
+catch (...)
+{
+        vte::log_exception();
+}
+
 /**
  * vte_terminal_set_scrollback_lines:
  * @terminal: a #VteTerminal
diff --git a/src/vtegtk.hh b/src/vtegtk.hh
index 389b86d2e557..24063c3060da 100644
--- a/src/vtegtk.hh
+++ b/src/vtegtk.hh
@@ -90,6 +90,7 @@ enum {
         PROP_MOUSE_POINTER_AUTOHIDE,
         PROP_PTY,
         PROP_REWRAP_ON_RESIZE,
+        PROP_SCROLL_SPEED,
         PROP_SCROLLBACK_LINES,
         PROP_SCROLL_ON_KEYSTROKE,
         PROP_SCROLL_ON_OUTPUT,
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index 38aaf421ec30..fd1a8b9008cf 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -399,6 +399,7 @@ public:
         bool m_fallback_scrolling{true};
         bool m_scroll_on_output{false};
         bool m_scroll_on_keystroke{true};
+        guint m_scroll_speed;
         vte::grid::row_t m_scrollback_lines{0};
 
         /* Restricted scrolling */
@@ -1232,6 +1233,7 @@ public:
         bool set_input_enabled(bool enabled);
         bool set_mouse_autohide(bool autohide);
         bool set_rewrap_on_resize(bool rewrap);
+        bool set_scroll_speed(unsigned int scroll_speed);
         bool set_scrollback_lines(long lines);
         bool set_fallback_scrolling(bool set);
         auto fallback_scrolling() const noexcept { return m_fallback_scrolling; }
-- 
2.31.1


From f080a7417f8f657778916219ad06ab184c53ff9a Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Fri, 13 May 2016 17:54:57 +0200
Subject: [PATCH 05/11] Test the scroll-speed property

https://bugzilla.redhat.com/show_bug.cgi?id=1103380
---
 bindings/vala/app.vala | 4 ++++
 src/app/app.cc         | 4 ++++
 2 files changed, 8 insertions(+)

diff --git a/bindings/vala/app.vala b/bindings/vala/app.vala
index 025f971b2eb0..51b5d6410503 100644
--- a/bindings/vala/app.vala
+++ b/bindings/vala/app.vala
@@ -335,6 +335,7 @@ class Window : Gtk.ApplicationWindow
     terminal.set_rewrap_on_resize(!Options.no_rewrap);
     terminal.set_scroll_on_output(false);
     terminal.set_scroll_on_keystroke(true);
+    terminal.set_scroll_speed(Options.scroll_speed);
     terminal.set_scrollback_lines(Options.scrollback_lines);
 
     /* Style */
@@ -857,6 +858,7 @@ class App : Gtk.Application
     public static bool object_notifications = false;
     public static string? output_filename = null;
     public static bool reverse = false;
+    public static uint scroll_speed = 0;
     public static int scrollback_lines = 512;
     public static int transparency_percent = 0;
     public static bool version = false;
@@ -1050,6 +1052,8 @@ class App : Gtk.Application
         "Save terminal contents to file at exit", null },
       { "reverse", 0, 0, OptionArg.NONE, ref reverse,
         "Reverse foreground/background colors", null },
+      { "scroll-speed", 0, 0, OptionArg.INT, ref scroll_speed,
+        "Specify the scroll speed", null },
       { "scrollback-lines", 'n', 0, OptionArg.INT, ref scrollback_lines,
         "Specify the number of scrollback-lines", null },
       { "transparent", 'T', 0, OptionArg.INT, ref transparency_percent,
diff --git a/src/app/app.cc b/src/app/app.cc
index 73810251a4d0..90421730a66a 100644
--- a/src/app/app.cc
+++ b/src/app/app.cc
@@ -116,6 +116,7 @@ public:
         int verbosity{0};
         double cell_height_scale{1.0};
         double cell_width_scale{1.0};
+        unsigned int scroll_speed{0};
         VteCursorBlinkMode cursor_blink_mode{VTE_CURSOR_BLINK_SYSTEM};
         VteCursorShape cursor_shape{VTE_CURSOR_SHAPE_BLOCK};
         VteTextBlinkMode text_blink_mode{VTE_TEXT_BLINK_ALWAYS};
@@ -590,6 +591,8 @@ public:
                           "Reverse foreground/background colors", nullptr },
                         { "require-systemd-scope", 0, 0, G_OPTION_ARG_NONE, &require_systemd_scope,
                           "Require use of a systemd user scope", nullptr },
+                        { "scroll-speed", 0, 0, G_OPTION_ARG_INT, &scroll_speed,
+                          "Specify the scroll speed", nullptr },
                         { "scrollback-lines", 'n', 0, G_OPTION_ARG_INT, &scrollback_lines,
                           "Specify the number of scrollback-lines (-1 for infinite)", nullptr },
                         { "transparent", 'T', 0, G_OPTION_ARG_INT, &transparency_percent,
@@ -2157,6 +2160,7 @@ vteapp_window_constructed(GObject *object)
         vte_terminal_set_rewrap_on_resize(window->terminal, !options.no_rewrap);
         vte_terminal_set_scroll_on_output(window->terminal, false);
         vte_terminal_set_scroll_on_keystroke(window->terminal, true);
+        vte_terminal_set_scroll_speed(window->terminal, options.scroll_speed);
         vte_terminal_set_scrollback_lines(window->terminal, options.scrollback_lines);
         vte_terminal_set_text_blink_mode(window->terminal, options.text_blink_mode);
 
-- 
2.31.1


From b77827bf39fcf7b27f548a5472802371196801d3 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Wed, 7 Jan 2015 16:01:00 +0100
Subject: [PATCH 06/11] Support preexec notifications from an interactive shell

Add sequences
  OSC 777 ; preexec BEL
  OSC 777 ; preexec ST

that can be used from an interactive shell's preexec hook to notify
the terminal emulator that a new command is about to be executed.
Examples of such hooks are Bash's PS0 and Zsh's preexec.

The OSC 777 escape sequence is taken from Enlightenment's Terminology:
https://phab.enlightenment.org/T1765

https://bugzilla.gnome.org/show_bug.cgi?id=711059
https://bugzilla.gnome.org/show_bug.cgi?id=711060
---
 src/vte.cc            |  6 ++++++
 src/vte.sh.in         |  2 +-
 src/vte/vteterminal.h |  3 ++-
 src/vtegtk.cc         | 18 ++++++++++++++++++
 src/vtegtk.hh         |  1 +
 src/vteinternal.hh    |  1 +
 src/vteseq.cc         |  4 ++++
 7 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/src/vte.cc b/src/vte.cc
index 02fe5cbf2df7..38a64d17a0bf 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -10125,6 +10125,12 @@ Terminal::emit_pending_signals()
                               m_notification_body.c_str());
         }
 
+        if (m_pending_changes & vte::to_integral(PendingChanges::SHELL_PREEXEC)) {
+                _vte_debug_print (VTE_DEBUG_SIGNALS,
+                                  "Emitting `shell-preexec'.\n");
+                g_signal_emit(freezer.get(), signals[SIGNAL_SHELL_PREEXEC], 0);
+        }
+
 	if (m_pending_changes & vte::to_integral(PendingChanges::TITLE)) {
                 if (m_window_title != m_window_title_pending) {
                         m_window_title.swap(m_window_title_pending);
diff --git a/src/vte.sh.in b/src/vte.sh.in
index 2c6f668142c3..fc33a63f1f84 100644
--- a/src/vte.sh.in
+++ b/src/vte.sh.in
@@ -38,7 +38,7 @@ __vte_prompt_command() {
 
 case "$TERM" in
   xterm*|vte*)
-    [ -n "${BASH_VERSION:-}" ] && PROMPT_COMMAND="__vte_prompt_command"
+    [ -n "${BASH_VERSION:-}" ] && PROMPT_COMMAND="__vte_prompt_command" && PS0=$(printf "\033]777;preexec\033\\")
     [ -n "${ZSH_VERSION:-}"  ] && precmd_functions+=(__vte_osc7)
     ;;
 esac
diff --git a/src/vte/vteterminal.h b/src/vte/vteterminal.h
index 0143f0b9dd4d..2d1017f4a216 100644
--- a/src/vte/vteterminal.h
+++ b/src/vte/vteterminal.h
@@ -103,9 +103,10 @@ struct _VteTerminalClass {
 	void (*bell)(VteTerminal* terminal);
 
 	void (*notification_received)(VteTerminal* terminal, const gchar *summary, const gchar *body);
+	void (*shell_preexec)(VteTerminal* terminal);
 
         /* Padding for future expansion. */
-        gpointer padding[15];
+        gpointer padding[14];
 
         VteTerminalClassPrivate *priv;
 };
diff --git a/src/vtegtk.cc b/src/vtegtk.cc
index b4bcd3d9a1d5..ce95126b37b8 100644
--- a/src/vtegtk.cc
+++ b/src/vtegtk.cc
@@ -990,6 +990,7 @@ vte_terminal_class_init(VteTerminalClass *klass)
 	klass->encoding_changed = NULL;
 	klass->char_size_changed = NULL;
 	klass->notification_received = NULL;
+	klass->shell_preexec = NULL;
 	klass->window_title_changed = NULL;
 	klass->icon_title_changed = NULL;
 	klass->selection_changed = NULL;
@@ -1091,6 +1092,23 @@ vte_terminal_class_init(VteTerminalClass *klass)
                              G_TYPE_NONE,
                              2, G_TYPE_STRING, G_TYPE_STRING);
 
+        /**
+         * VteTerminal::shell-preexec:
+         * @vteterminal: the object which received the signal
+         *
+         * Emitted when the interactive shell has read in a complete
+         * command and is about to execute it.
+         */
+        signals[SIGNAL_SHELL_PREEXEC] =
+                g_signal_new(I_("shell-preexec"),
+                             G_OBJECT_CLASS_TYPE(klass),
+                             G_SIGNAL_RUN_LAST,
+                             G_STRUCT_OFFSET(VteTerminalClass, shell_preexec),
+                             NULL,
+                             NULL,
+                             g_cclosure_marshal_VOID__VOID,
+                             G_TYPE_NONE, 0);
+
         /**
          * VteTerminal::window-title-changed:
          * @vteterminal: the object which received the signal
diff --git a/src/vtegtk.hh b/src/vtegtk.hh
index 24063c3060da..e90e183e7c2d 100644
--- a/src/vtegtk.hh
+++ b/src/vtegtk.hh
@@ -52,6 +52,7 @@ enum {
         SIGNAL_RESIZE_WINDOW,
         SIGNAL_RESTORE_WINDOW,
         SIGNAL_SELECTION_CHANGED,
+        SIGNAL_SHELL_PREEXEC,
         SIGNAL_TEXT_DELETED,
         SIGNAL_TEXT_INSERTED,
         SIGNAL_TEXT_MODIFIED,
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index fd1a8b9008cf..bb98f8bc0903 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -640,6 +640,7 @@ public:
                 CWD   = 1u << 1,
                 CWF   = 1u << 2,
                 NOTIFICATION = 1u << 3,
+                SHELL_PREEXEC = 1u << 4,
         };
         unsigned m_pending_changes{0};
 
diff --git a/src/vteseq.cc b/src/vteseq.cc
index 7ab65b6d204a..51ca37bdc748 100644
--- a/src/vteseq.cc
+++ b/src/vteseq.cc
@@ -1402,6 +1402,10 @@ Terminal::handle_urxvt_extension(vte::parser::Sequence const& seq,
                 m_notification_body = *token;
                 return;
         }
+
+        if (*token == "preexec") {
+                m_pending_changes |= vte::to_integral(PendingChanges::SHELL_PREEXEC);
+        }
 }
 
 bool
-- 
2.31.1


From d2e780db838ead280cf5657c49b0d63dd0683f5f Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Fri, 20 Apr 2018 18:21:53 +0200
Subject: [PATCH 07/11] Test the shell-preexec signal

https://bugzilla.gnome.org/show_bug.cgi?id=711059
https://bugzilla.gnome.org/show_bug.cgi?id=711060
---
 bindings/vala/app.vala | 6 ++++++
 src/app/app.cc         | 7 +++++++
 2 files changed, 13 insertions(+)

diff --git a/bindings/vala/app.vala b/bindings/vala/app.vala
index 51b5d6410503..3975b9886d77 100644
--- a/bindings/vala/app.vala
+++ b/bindings/vala/app.vala
@@ -310,6 +310,7 @@ class Window : Gtk.ApplicationWindow
       terminal.notify.connect(notify_cb);
 
     terminal.notification_received.connect(notification_received_cb);
+    terminal.shell_preexec.connect(shell_preexec_cb);
 
     /* Settings */
     if (Options.no_double_buffer)
@@ -788,6 +789,11 @@ class Window : Gtk.ApplicationWindow
     print ("[%s]: %s\n", summary, body);
   }
 
+  private void shell_preexec_cb(Vte.Terminal terminal)
+  {
+    print("[shell] executing command\n");
+  }
+
 } /* class Window */
 
 class App : Gtk.Application
diff --git a/src/app/app.cc b/src/app/app.cc
index 90421730a66a..3caec42e5877 100644
--- a/src/app/app.cc
+++ b/src/app/app.cc
@@ -1888,6 +1888,12 @@ notification_received_cb(VteTerminal *terminal,
         g_print("[%s]: %s\n", summary, body);
 }
 
+static void
+shell_preexec_cb(VteTerminal *terminal)
+{
+        g_print("[shell] executing command\n");
+}
+
 static void
 window_lower_window_cb(VteTerminal* terminal,
                        VteappWindow* window)
@@ -2127,6 +2133,7 @@ vteapp_window_constructed(GObject *object)
                 g_signal_connect(window->terminal, "notify", G_CALLBACK(window_notify_cb), window);
 
         g_signal_connect(window->terminal, "notification-received", G_CALLBACK(notification_received_cb), NULL);
+        g_signal_connect(window->terminal, "shell-preexec", G_CALLBACK(shell_preexec_cb), NULL);
 
         /* Settings */
         if (options.no_double_buffer) {
-- 
2.31.1


From 949d4552c4ab66e02ba03024091f21bd35c199d8 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Wed, 2 May 2018 17:20:30 +0200
Subject: [PATCH 08/11] Support precmd notifications from an interactive shell

Add sequences
  OSC 777 ; precmd BEL
  OSC 777 ; precmd ST

that can be used from an interactive shell's precmd hook to notify the
terminal emulator that a first level prompt is about to be shown.
Examples of such hooks are Bash's PROMPT_COMMAND and Zsh's precmd.

The OSC 777 escape sequence is taken from Enlightenment's Terminology:
https://phab.enlightenment.org/T1765

https://bugzilla.gnome.org/show_bug.cgi?id=711059
https://bugzilla.gnome.org/show_bug.cgi?id=711060
---
 src/vte.cc            |  6 ++++++
 src/vte.sh.in         |  2 +-
 src/vte/vteterminal.h |  3 ++-
 src/vtegtk.cc         | 18 ++++++++++++++++++
 src/vtegtk.hh         |  1 +
 src/vteinternal.hh    |  1 +
 src/vteseq.cc         |  4 +++-
 7 files changed, 32 insertions(+), 3 deletions(-)

diff --git a/src/vte.cc b/src/vte.cc
index 38a64d17a0bf..6b3e1336ca15 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -10131,6 +10131,12 @@ Terminal::emit_pending_signals()
                 g_signal_emit(freezer.get(), signals[SIGNAL_SHELL_PREEXEC], 0);
         }
 
+        if (m_pending_changes & vte::to_integral(PendingChanges::SHELL_PRECMD)) {
+                _vte_debug_print (VTE_DEBUG_SIGNALS,
+                                  "Emitting `shell-precmd'.\n");
+                g_signal_emit(freezer.get(), signals[SIGNAL_SHELL_PRECMD], 0);
+        }
+
 	if (m_pending_changes & vte::to_integral(PendingChanges::TITLE)) {
                 if (m_window_title != m_window_title_pending) {
                         m_window_title.swap(m_window_title_pending);
diff --git a/src/vte.sh.in b/src/vte.sh.in
index fc33a63f1f84..359afbc4645c 100644
--- a/src/vte.sh.in
+++ b/src/vte.sh.in
@@ -32,7 +32,7 @@ __vte_prompt_command() {
   local pwd='~'
   [ "$PWD" != "$HOME" ] && pwd=${PWD/#$HOME\//\~\/}
   pwd="${pwd//[[:cntrl:]]}"
-  printf '\033]777;notify;Command completed;%s\033\\\033]0;%s@%s:%s\033\\' "${command}" "${USER}" "${HOSTNAME%%.*}" "${pwd}"
+  printf '\033]777;notify;Command completed;%s\033\\\033]777;precmd\033\\\033]0;%s@%s:%s\033\\' "${command}" "${USER}" "${HOSTNAME%%.*}" "${pwd}"
   __vte_osc7
 }
 
diff --git a/src/vte/vteterminal.h b/src/vte/vteterminal.h
index 2d1017f4a216..5e413393f7ec 100644
--- a/src/vte/vteterminal.h
+++ b/src/vte/vteterminal.h
@@ -103,10 +103,11 @@ struct _VteTerminalClass {
 	void (*bell)(VteTerminal* terminal);
 
 	void (*notification_received)(VteTerminal* terminal, const gchar *summary, const gchar *body);
+	void (*shell_precmd)(VteTerminal* terminal);
 	void (*shell_preexec)(VteTerminal* terminal);
 
         /* Padding for future expansion. */
-        gpointer padding[14];
+        gpointer padding[13];
 
         VteTerminalClassPrivate *priv;
 };
diff --git a/src/vtegtk.cc b/src/vtegtk.cc
index ce95126b37b8..a84f17e21f65 100644
--- a/src/vtegtk.cc
+++ b/src/vtegtk.cc
@@ -990,6 +990,7 @@ vte_terminal_class_init(VteTerminalClass *klass)
 	klass->encoding_changed = NULL;
 	klass->char_size_changed = NULL;
 	klass->notification_received = NULL;
+	klass->shell_precmd = NULL;
 	klass->shell_preexec = NULL;
 	klass->window_title_changed = NULL;
 	klass->icon_title_changed = NULL;
@@ -1092,6 +1093,23 @@ vte_terminal_class_init(VteTerminalClass *klass)
                              G_TYPE_NONE,
                              2, G_TYPE_STRING, G_TYPE_STRING);
 
+        /**
+         * VteTerminal::shell-precmd:
+         * @vteterminal: the object which received the signal
+         *
+         * Emitted right before an interactive shell shows a
+         * first-level prompt.
+         */
+        signals[SIGNAL_SHELL_PRECMD] =
+                g_signal_new(I_("shell-precmd"),
+                             G_OBJECT_CLASS_TYPE(klass),
+                             G_SIGNAL_RUN_LAST,
+                             G_STRUCT_OFFSET(VteTerminalClass, shell_precmd),
+                             NULL,
+                             NULL,
+                             g_cclosure_marshal_VOID__VOID,
+                             G_TYPE_NONE, 0);
+
         /**
          * VteTerminal::shell-preexec:
          * @vteterminal: the object which received the signal
diff --git a/src/vtegtk.hh b/src/vtegtk.hh
index e90e183e7c2d..93a6dde3e19a 100644
--- a/src/vtegtk.hh
+++ b/src/vtegtk.hh
@@ -52,6 +52,7 @@ enum {
         SIGNAL_RESIZE_WINDOW,
         SIGNAL_RESTORE_WINDOW,
         SIGNAL_SELECTION_CHANGED,
+        SIGNAL_SHELL_PRECMD,
         SIGNAL_SHELL_PREEXEC,
         SIGNAL_TEXT_DELETED,
         SIGNAL_TEXT_INSERTED,
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index bb98f8bc0903..25253c0af95b 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -641,6 +641,7 @@ public:
                 CWF   = 1u << 2,
                 NOTIFICATION = 1u << 3,
                 SHELL_PREEXEC = 1u << 4,
+                SHELL_PRECMD = 1u << 5,
         };
         unsigned m_pending_changes{0};
 
diff --git a/src/vteseq.cc b/src/vteseq.cc
index 51ca37bdc748..10b494bddb47 100644
--- a/src/vteseq.cc
+++ b/src/vteseq.cc
@@ -1403,7 +1403,9 @@ Terminal::handle_urxvt_extension(vte::parser::Sequence const& seq,
                 return;
         }
 
-        if (*token == "preexec") {
+        if (*token == "precmd") {
+                m_pending_changes |= vte::to_integral(PendingChanges::SHELL_PRECMD);
+        } else if (*token == "preexec") {
                 m_pending_changes |= vte::to_integral(PendingChanges::SHELL_PREEXEC);
         }
 }
-- 
2.31.1


From 28518832a97fc3ff2760de36cc13586c12555b62 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Wed, 2 May 2018 17:30:48 +0200
Subject: [PATCH 09/11] Test the shell-precmd signal

https://bugzilla.gnome.org/show_bug.cgi?id=711059
https://bugzilla.gnome.org/show_bug.cgi?id=711060
---
 bindings/vala/app.vala | 6 ++++++
 src/app/app.cc         | 7 +++++++
 2 files changed, 13 insertions(+)

diff --git a/bindings/vala/app.vala b/bindings/vala/app.vala
index 3975b9886d77..ff5fb5df052e 100644
--- a/bindings/vala/app.vala
+++ b/bindings/vala/app.vala
@@ -310,6 +310,7 @@ class Window : Gtk.ApplicationWindow
       terminal.notify.connect(notify_cb);
 
     terminal.notification_received.connect(notification_received_cb);
+    terminal.shell_precmd.connect(shell_precmd_cb);
     terminal.shell_preexec.connect(shell_preexec_cb);
 
     /* Settings */
@@ -789,6 +790,11 @@ class Window : Gtk.ApplicationWindow
     print ("[%s]: %s\n", summary, body);
   }
 
+  private void shell_precmd_cb(Vte.Terminal terminal)
+  {
+    print("[shell] showing command prompt\n");
+  }
+
   private void shell_preexec_cb(Vte.Terminal terminal)
   {
     print("[shell] executing command\n");
diff --git a/src/app/app.cc b/src/app/app.cc
index 3caec42e5877..0ae59d2526cb 100644
--- a/src/app/app.cc
+++ b/src/app/app.cc
@@ -1888,6 +1888,12 @@ notification_received_cb(VteTerminal *terminal,
         g_print("[%s]: %s\n", summary, body);
 }
 
+static void
+shell_precmd_cb(VteTerminal *terminal)
+{
+        g_print("[shell] showing command prompt\n");
+}
+
 static void
 shell_preexec_cb(VteTerminal *terminal)
 {
@@ -2133,6 +2139,7 @@ vteapp_window_constructed(GObject *object)
                 g_signal_connect(window->terminal, "notify", G_CALLBACK(window_notify_cb), window);
 
         g_signal_connect(window->terminal, "notification-received", G_CALLBACK(notification_received_cb), NULL);
+        g_signal_connect(window->terminal, "shell-precmd", G_CALLBACK(shell_precmd_cb), NULL);
         g_signal_connect(window->terminal, "shell-preexec", G_CALLBACK(shell_preexec_cb), NULL);
 
         /* Settings */
-- 
2.31.1


From e1c687e0651c06b72c7197e9f8f4a91122e8451c Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Mon, 10 Jun 2019 20:30:18 +0200
Subject: [PATCH 10/11] Support tracking the active container inside the
 terminal

Add sequences

  OSC 777 ; container ; push ; NAME ; RUNTIME ; UID BEL
  OSC 777 ; container ; push ; NAME ; RUNTIME ; UID ST
  OSC 777 ; container ; pop ; NAME ; RUNTIME ; UID BEL
  OSC 777 ; container ; pop ; NAME ; RUNTIME ; UID ST

  OSC 777 ; container ; push ; NAME ; RUNTIME BEL
  OSC 777 ; container ; push ; NAME ; RUNTIME ST
  OSC 777 ; container ; pop ; NAME ; RUNTIME BEL
  OSC 777 ; container ; pop ; NAME ; RUNTIME ST

that let container tools notify the terminal emulator when entering and
leaving a container environment. The RUNTIME argument namespaces the
NAME and identifies the container tooling being used. eg., docker,
flatpak, podman, toolbox, etc.. The UID argument is the real UID of the
container tools. Only those containers that are used with the same real
UID as the VTE process are tracked.

The OSC 777 escape sequence is taken from Enlightenment's Terminology:
https://phab.enlightenment.org/T1765

It's a VTE-specific extension until a standard escape sequence is
agreed upon across multiple different terminal emulators [1].

[1] https://gitlab.freedesktop.org/terminal-wg/specifications/issues/17
---
 src/vte.cc            |  8 ++++
 src/vte/vteterminal.h |  4 ++
 src/vtegtk.cc         | 77 ++++++++++++++++++++++++++++++++++++++
 src/vtegtk.hh         |  2 +
 src/vteinternal.hh    | 16 ++++++++
 src/vteseq.cc         | 86 +++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 193 insertions(+)

diff --git a/src/vte.cc b/src/vte.cc
index 6b3e1336ca15..abd6b449ae48 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -10150,6 +10150,14 @@ Terminal::emit_pending_signals()
                 m_window_title_pending.clear();
 	}
 
+	if (m_pending_changes & vte::to_integral(PendingChanges::CONTAINERS)) {
+                _vte_debug_print(VTE_DEBUG_SIGNALS,
+                                 "Notifying `current-container-name' and `current-container-runtime'.\n");
+
+                g_object_notify_by_pspec(freezer.get(), pspecs[PROP_CURRENT_CONTAINER_NAME]);
+                g_object_notify_by_pspec(freezer.get(), pspecs[PROP_CURRENT_CONTAINER_RUNTIME]);
+        }
+
 	if (m_pending_changes & vte::to_integral(PendingChanges::CWD)) {
                 if (m_current_directory_uri != m_current_directory_uri_pending) {
                         m_current_directory_uri.swap(m_current_directory_uri_pending);
diff --git a/src/vte/vteterminal.h b/src/vte/vteterminal.h
index 5e413393f7ec..32b2f32eef9d 100644
--- a/src/vte/vteterminal.h
+++ b/src/vte/vteterminal.h
@@ -488,6 +488,10 @@ glong vte_terminal_get_column_count(VteTerminal *terminal) _VTE_CXX_NOEXCEPT _VT
 _VTE_PUBLIC
 const char *vte_terminal_get_window_title(VteTerminal *terminal) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1);
 _VTE_PUBLIC
+const char *vte_terminal_get_current_container_name(VteTerminal *terminal) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1);
+_VTE_PUBLIC
+const char *vte_terminal_get_current_container_runtime(VteTerminal *terminal) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1);
+_VTE_PUBLIC
 const char *vte_terminal_get_current_directory_uri(VteTerminal *terminal) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1);
 _VTE_PUBLIC
 const char *vte_terminal_get_current_file_uri(VteTerminal *terminal) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1);
diff --git a/src/vtegtk.cc b/src/vtegtk.cc
index a84f17e21f65..aa3f04c6a02a 100644
--- a/src/vtegtk.cc
+++ b/src/vtegtk.cc
@@ -707,6 +707,12 @@ try
                 case PROP_CURSOR_BLINK_MODE:
                         g_value_set_enum (value, vte_terminal_get_cursor_blink_mode (terminal));
                         break;
+                case PROP_CURRENT_CONTAINER_NAME:
+                        g_value_set_string (value, vte_terminal_get_current_container_name (terminal));
+                        break;
+                case PROP_CURRENT_CONTAINER_RUNTIME:
+                        g_value_set_string (value, vte_terminal_get_current_container_runtime (terminal));
+                        break;
                 case PROP_CURRENT_DIRECTORY_URI:
                         g_value_set_string (value, vte_terminal_get_current_directory_uri (terminal));
                         break;
@@ -2099,6 +2105,27 @@ vte_terminal_class_init(VteTerminalClass *klass)
                                      NULL,
                                      (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY));
 
+        /**
+         * VteTerminal:current-container-name:
+         *
+         * The name of the current container, or %NULL if unset.
+         */
+        pspecs[PROP_CURRENT_CONTAINER_NAME] =
+                g_param_spec_string ("current-container-name", NULL, NULL,
+                                     NULL,
+                                     (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY));
+
+        /**
+         * VteTerminal:current-container-runtime:
+         *
+         * The name of the runtime toolset used to set up the current
+         * container, or %NULL if unset.
+         */
+        pspecs[PROP_CURRENT_CONTAINER_RUNTIME] =
+                g_param_spec_string ("current-container-runtime", NULL, NULL,
+                                     NULL,
+                                     (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY));
+
         /**
          * VteTerminal:current-directory-uri:
          *
@@ -4574,6 +4601,56 @@ catch (...)
         return -1;
 }
 
+/**
+ * vte_terminal_get_current_container_name:
+ * @terminal: a #VteTerminal
+ *
+ * Returns: (nullable) (transfer none): the name of the current
+ *   container, or %NULL
+ */
+const char *
+vte_terminal_get_current_container_name(VteTerminal *terminal) noexcept
+try
+{
+        g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
+        auto impl = IMPL(terminal);
+        if (impl->m_containers.empty())
+                return NULL;
+
+        const VteContainer &container = impl->m_containers.top();
+        return container.m_name.c_str();
+}
+catch (...)
+{
+        vte::log_exception();
+        return NULL;
+}
+
+/**
+ * vte_terminal_get_current_container_runtime:
+ * @terminal: a #VteTerminal
+ *
+ * Returns: (nullable) (transfer none): the name of the runtime
+ *   toolset used to set up the current container, or %NULL
+ */
+const char *
+vte_terminal_get_current_container_runtime(VteTerminal *terminal) noexcept
+try
+{
+        g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
+        auto impl = IMPL(terminal);
+        if (impl->m_containers.empty())
+                return NULL;
+
+        const VteContainer &container = impl->m_containers.top();
+        return container.m_runtime.c_str();
+}
+catch (...)
+{
+        vte::log_exception();
+        return NULL;
+}
+
 /**
  * vte_terminal_get_current_directory_uri:
  * @terminal: a #VteTerminal
diff --git a/src/vtegtk.hh b/src/vtegtk.hh
index 93a6dde3e19a..651961436225 100644
--- a/src/vtegtk.hh
+++ b/src/vtegtk.hh
@@ -76,6 +76,8 @@ enum {
         PROP_CJK_AMBIGUOUS_WIDTH,
         PROP_CURSOR_BLINK_MODE,
         PROP_CURSOR_SHAPE,
+        PROP_CURRENT_CONTAINER_NAME,
+        PROP_CURRENT_CONTAINER_RUNTIME,
         PROP_CURRENT_DIRECTORY_URI,
         PROP_CURRENT_FILE_URI,
         PROP_DELETE_BINDING,
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index 25253c0af95b..570c70b0c9e7 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -59,6 +59,7 @@
 #include <list>
 #include <queue>
 #include <optional>
+#include <stack>
 #include <string>
 #include <variant>
 #include <vector>
@@ -97,6 +98,18 @@ typedef enum _VteCharacterReplacement {
         VTE_CHARACTER_REPLACEMENT_LINE_DRAWING
 } VteCharacterReplacement;
 
+struct VteContainer {
+public:
+        VteContainer(const std::string &name, const std::string &runtime) :
+                m_name{name},
+                m_runtime{runtime}
+        {
+        }
+
+        std::string m_name;
+        std::string m_runtime;
+};
+
 typedef struct _VtePaletteColor {
 	struct {
 		vte::color::rgb color;
@@ -622,6 +635,8 @@ public:
         gboolean m_cursor_moved_pending;
         gboolean m_contents_changed_pending;
 
+        std::stack<VteContainer> m_containers;
+
         /* desktop notification */
         std::string m_notification_summary;
         std::string m_notification_body;
@@ -642,6 +657,7 @@ public:
                 NOTIFICATION = 1u << 3,
                 SHELL_PREEXEC = 1u << 4,
                 SHELL_PRECMD = 1u << 5,
+                CONTAINERS = 1u << 6,
         };
         unsigned m_pending_changes{0};
 
diff --git a/src/vteseq.cc b/src/vteseq.cc
index 10b494bddb47..2a2ba4b47441 100644
--- a/src/vteseq.cc
+++ b/src/vteseq.cc
@@ -19,10 +19,14 @@
 
 #include "config.h"
 
+#include <string>
+
 #include <search.h>
 #include <stdlib.h>
 #include <string.h>
 #include <limits.h>
+#include <unistd.h>
+#include <sys/types.h>
 #ifdef HAVE_SYS_SYSLIMITS_H
 #include <sys/syslimits.h>
 #endif
@@ -1385,6 +1389,88 @@ Terminal::handle_urxvt_extension(vte::parser::Sequence const& seq,
         if (token == endtoken)
                 return;
 
+        if (*token == "container") {
+                ++token;
+
+                if (token == endtoken)
+                        return;
+
+                const std::string sub_command = *token;
+                ++token;
+
+                if (sub_command == "pop") {
+                        if (token == endtoken)
+                                return;
+
+                        ++token;
+
+                        if (token == endtoken)
+                                return;
+
+                        ++token;
+
+                        if (token == endtoken) {
+                                if (!m_containers.empty()) {
+                                        m_containers.pop();
+                                        m_pending_changes |= vte::to_integral(PendingChanges::CONTAINERS);
+                                }
+
+                                return;
+                        }
+
+                        const std::string uid_token = *token;
+                        ++token;
+
+                        const uid_t uid = getuid();
+                        const std::string uid_str = std::to_string(uid);
+
+                        if (uid_token == uid_str) {
+                                if (!m_containers.empty()) {
+                                        m_containers.pop();
+                                        m_pending_changes |= vte::to_integral(PendingChanges::CONTAINERS);
+                                }
+
+                                return;
+                        }
+
+                        return;
+                } else if (sub_command == "push") {
+                        if (token == endtoken)
+                                return;
+
+                        const std::string name = *token;
+                        ++token;
+
+                        if (token == endtoken)
+                                return;
+
+                        const std::string runtime = *token;
+                        ++token;
+
+                        if (token == endtoken) {
+                                m_containers.emplace(name, runtime);
+                                m_pending_changes |= vte::to_integral(PendingChanges::CONTAINERS);
+                                return;
+                        }
+
+                        const std::string uid_token = *token;
+                        ++token;
+
+                        const uid_t uid = getuid();
+                        const std::string uid_str = std::to_string(uid);
+
+                        if (uid_token == uid_str) {
+                                m_containers.emplace(name, runtime);
+                                m_pending_changes |= vte::to_integral(PendingChanges::CONTAINERS);
+                                return;
+                        }
+
+                        return;
+                }
+
+                return;
+        }
+
         if (*token == "notify") {
                 ++token;
 
-- 
2.31.1


From 4a949461c975c2d062703e161f337d84f13a60d7 Mon Sep 17 00:00:00 2001
From: Kalev Lember <klember@redhat.com>
Date: Tue, 16 Feb 2021 16:30:44 +0100
Subject: [PATCH 11/11] Revert "widget: Limit select-all to the writable region
 not including the scrollback"

... as decided by Fedora Workstation WG.

https://pagure.io/fedora-workstation/issue/216

This reverts commit 73713ec0644e232fb740170e399282be778d97f9.
---
 src/vte.cc | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/src/vte.cc b/src/vte.cc
index abd6b449ae48..99ad5973c363 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -6595,10 +6595,7 @@ Terminal::maybe_end_selection()
 /*
  * Terminal::select_all:
  *
- * Selects all text within the terminal. Note that we only select the writable
- * region, *not* the scrollback buffer, due to this potentially selecting so
- * much data that putting it on the clipboard either hangs the process for a long
- * time or even crash it directly. (FIXME!)
+ * Selects all text within the terminal (including the scrollback buffer).
  */
 void
 Terminal::select_all()
@@ -6607,8 +6604,8 @@ Terminal::select_all()
 
 	m_selecting_had_delta = TRUE;
 
-        m_selection_resolved.set({m_screen->insert_delta, 0},
-                                 {_vte_ring_next(m_screen->row_data), 0});
+        m_selection_resolved.set ({ _vte_ring_delta (m_screen->row_data), 0 },
+                                  { _vte_ring_next  (m_screen->row_data), 0 });
 
 	_vte_debug_print(VTE_DEBUG_SELECTION, "Selecting *all* text.\n");
 
-- 
2.31.1