[vte] widget: Add support for blinking text



commit 38396ef88ff44b447399b6abc562a22e07a27684
Author: Egmont Koblinger <egmont gmail com>
Date:   Sat Dec 23 22:41:24 2017 +0100

    widget: Add support for blinking text
    
    Also add an API to enable/disable this feature depending on the focused
    or unfocused state of the widget.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=579964

 doc/reference/vte-sections.txt |    5 ++
 src/app/app.cc                 |   15 +++++
 src/vte.cc                     |  126 ++++++++++++++++++++++++++++++++++++++--
 src/vte/vteenums.h             |   19 ++++++
 src/vte/vteterminal.h          |    5 ++
 src/vtegtk.cc                  |   55 +++++++++++++++++
 src/vtegtk.hh                  |    1 +
 src/vteinternal.hh             |   11 ++++
 8 files changed, 231 insertions(+), 6 deletions(-)
---
diff --git a/doc/reference/vte-sections.txt b/doc/reference/vte-sections.txt
index b87d249..a63fa34 100644
--- a/doc/reference/vte-sections.txt
+++ b/doc/reference/vte-sections.txt
@@ -5,6 +5,7 @@ VteTerminal
 VteCursorBlinkMode
 VteCursorShape
 VteEraseBinding
+VteTextBlinkMode
 VteFormat
 VteWriteFlags
 VteSelectionFunc
@@ -52,6 +53,8 @@ vte_terminal_set_cursor_shape
 vte_terminal_get_cursor_shape
 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_scrollback_lines
 vte_terminal_get_scrollback_lines
 vte_terminal_set_font
@@ -113,6 +116,8 @@ VTE_TYPE_CURSOR_SHAPE
 vte_cursor_shape_get_type
 VTE_TYPE_ERASE_BINDING
 vte_erase_binding_get_type
+VTE_TYPE_TEXT_BLINK_MODE
+vte_text_blink_mode_get_type
 VTE_TYPE_FORMAT
 vte_format_get_type
 VTE_TYPE_WRITE_FLAGS
diff --git a/src/app/app.cc b/src/app/app.cc
index 636df47..d63adb6 100644
--- a/src/app/app.cc
+++ b/src/app/app.cc
@@ -93,6 +93,7 @@ public:
         double cell_width_scale{1.0};
         VteCursorBlinkMode cursor_blink_mode{VTE_CURSOR_BLINK_SYSTEM};
         VteCursorShape cursor_shape{VTE_CURSOR_SHAPE_BLOCK};
+        VteTextBlinkMode text_blink_mode{VTE_TEXT_BLINK_ALWAYS};
 
         ~Options() {
                 g_clear_object(&background_pixbuf);
@@ -288,6 +289,17 @@ private:
         }
 
         static gboolean
+        parse_text_blink(char const* option, char const* value, void* data, GError** error)
+        {
+                Options* that = static_cast<Options*>(data);
+                int v;
+                auto rv = that->parse_enum(VTE_TYPE_TEXT_BLINK_MODE, value, v, error);
+                if (rv)
+                        that->text_blink_mode = VteTextBlinkMode(v);
+                return rv;
+        }
+
+        static gboolean
         parse_verbosity(char const* option, char const* value, void* data, GError** error)
         {
                 Options* that = static_cast<Options*>(data);
@@ -341,6 +353,8 @@ public:
                           "Set background image extend", "EXTEND" },
                         { "background-operator", 0, 0, G_OPTION_ARG_CALLBACK, 
(void*)parse_background_operator,
                           "Set background draw operator", "OPERATOR" },
+                        { "blink", 0, 0, G_OPTION_ARG_CALLBACK, (void*)parse_text_blink,
+                          "Text blink mode (never|focused|unfocused|always)", "MODE" },
                         { "cell-height-scale", 0, 0, G_OPTION_ARG_DOUBLE, &cell_height_scale,
                           "Add extra line spacing", "1.0..2.0" },
                         { "cell-width-scale", 0, 0, G_OPTION_ARG_DOUBLE, &cell_width_scale,
@@ -1850,6 +1864,7 @@ vteapp_window_constructed(GObject *object)
         vte_terminal_set_scroll_on_output(window->terminal, false);
         vte_terminal_set_scroll_on_keystroke(window->terminal, true);
         vte_terminal_set_scrollback_lines(window->terminal, options.scrollback_lines);
+        vte_terminal_set_text_blink_mode(window->terminal, options.text_blink_mode);
 
         /* Style */
         if (options.font_string != nullptr) {
diff --git a/src/vte.cc b/src/vte.cc
index ccf00dc..2768954 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -4583,6 +4583,16 @@ VteTerminalPrivate::check_cursor_blink()
 }
 
 void
+VteTerminalPrivate::remove_text_blink_timeout()
+{
+        if (m_text_blink_tag == 0)
+                return;
+
+        g_source_remove (m_text_blink_tag);
+        m_text_blink_tag = 0;
+}
+
+void
 VteTerminalPrivate::beep()
 {
        if (m_audible_bell) {
@@ -7423,6 +7433,14 @@ VteTerminalPrivate::widget_focus_in(GdkEventFocus *event)
                m_cursor_blink_state = TRUE;
                m_has_focus = TRUE;
 
+                /* If blinking gets enabled now, do a full repaint.
+                 * If blinking gets disabled, only repaint if there's blinking stuff present
+                 * (we could further optimize by checking its current phase). */
+                if (m_text_blink_mode == VTE_TEXT_BLINK_FOCUSED ||
+                    (m_text_blink_mode == VTE_TEXT_BLINK_UNFOCUSED && m_text_blink_tag != 0)) {
+                        invalidate_all();
+                }
+
                check_cursor_blink();
 
                gtk_im_context_focus_in(m_im_context);
@@ -7446,6 +7464,14 @@ VteTerminalPrivate::widget_focus_out(GdkEventFocus *event)
 
                maybe_end_selection();
 
+                /* If blinking gets enabled now, do a full repaint.
+                 * If blinking gets disabled, only repaint if there's blinking stuff present
+                 * (we could further optimize by checking its current phase). */
+                if (m_text_blink_mode == VTE_TEXT_BLINK_UNFOCUSED ||
+                    (m_text_blink_mode == VTE_TEXT_BLINK_FOCUSED && m_text_blink_tag != 0)) {
+                        invalidate_all();
+                }
+
                gtk_im_context_focus_out(m_im_context);
                invalidate_cursor_once();
 
@@ -8157,6 +8183,7 @@ VteTerminalPrivate::VteTerminalPrivate(VteTerminal *t) :
        m_pending = g_array_new(FALSE, TRUE, sizeof(gunichar));
        m_max_input_bytes = VTE_MAX_INPUT_READ;
        m_cursor_blink_tag = 0;
+        m_text_blink_tag = 0;
        m_outgoing = _vte_byte_array_new();
        m_outgoing_conv = VTE_INVALID_CONV;
        m_conv_buffer = _vte_byte_array_new();
@@ -8198,6 +8225,7 @@ VteTerminalPrivate::VteTerminalPrivate(VteTerminal *t) :
        set_delete_binding(VTE_ERASE_AUTO);
        m_meta_sends_escape = TRUE;
        m_audible_bell = TRUE;
+        m_text_blink_mode = VTE_TEXT_BLINK_ALWAYS;
        m_allow_bold = TRUE;
         m_bold_is_bright = TRUE;
         m_deccolm_mode = FALSE;
@@ -8450,9 +8478,12 @@ VteTerminalPrivate::widget_unrealize()
                gtk_widget_unmap(m_widget);
        }
 
-       /* Remove the blink timeout function. */
+        /* Remove the cursor blink timeout function. */
        remove_cursor_timeout();
 
+        /* Remove the contents blink timeout function. */
+        remove_text_blink_timeout();
+
        /* Cancel any pending redraws. */
        remove_update_timeout(this);
 
@@ -8501,6 +8532,16 @@ VteTerminalPrivate::widget_settings_notify()
         m_cursor_blink_timeout = blink_timeout;
 
         update_cursor_blinks();
+
+        /* Misuse gtk-cursor-blink-time for text blinking as well. This might change in the future. */
+        m_text_blink_cycle = m_cursor_blink_cycle;
+        if (m_text_blink_tag != 0) {
+                /* The current phase might have changed, and an already installed
+                 * timer to blink might fire too late. So remove the timer and
+                 * repaint the contents (which will install a correct new timer). */
+                remove_text_blink_timeout();
+                invalidate_all();
+        }
 }
 
 void
@@ -8886,6 +8927,9 @@ VteTerminalPrivate::determine_colors(VteCellAttr const* attr,
        }
 
        /* Invisible? */
+        /* FIXME: This is dead code, this is not where we actually handle invisibile.
+         * Instead, draw_cells() is not called from draw_rows().
+         * That is required for the foreground to be transparent if so is the background. */
        if (attr->invisible) {
                 fore = deco = back;
        }
@@ -8919,6 +8963,14 @@ VteTerminalPrivate::determine_cursor_colors(VteCell const* cell,
                          fore, back, deco);
 }
 
+static gboolean
+invalidate_text_blink_cb(VteTerminalPrivate *that)
+{
+        that->m_text_blink_tag = 0;
+        that->invalidate_all();
+        return G_SOURCE_REMOVE;
+}
+
 /* Draw a string of characters with similar attributes. */
 void
 VteTerminalPrivate::draw_cells(struct _vte_draw_text_request *items,
@@ -8933,6 +8985,7 @@ VteTerminalPrivate::draw_cells(struct _vte_draw_text_request *items,
                                guint underline,
                                bool strikethrough,
                                bool overline,
+                               bool blink,
                                bool hyperlink,
                                bool hilite,
                                bool boxed,
@@ -8952,10 +9005,10 @@ VteTerminalPrivate::draw_cells(struct _vte_draw_text_request *items,
                }
                tmp = g_string_free (str, FALSE);
                 g_printerr ("draw_cells('%s', fore=%d, back=%d, deco=%d, bold=%d,"
-                                " ul=%d, strike=%d, ol=%d"
+                                " ul=%d, strike=%d, ol=%d, blink=%d,"
                                 " hyperlink=%d, hilite=%d, boxed=%d)\n",
                                 tmp, fore, back, deco, bold,
-                                underline, strikethrough, overline,
+                                underline, strikethrough, overline, blink,
                                 hyperlink, hilite, boxed);
                g_free (tmp);
        }
@@ -8984,6 +9037,21 @@ VteTerminalPrivate::draw_cells(struct _vte_draw_text_request *items,
                }
        } while (i < n);
 
+        if (blink) {
+                /* Notify the caller that cells with the "blink" attribute were encountered (regardless of
+                 * whether they're actually painted or skipped now), so that the caller can set up a timer
+                 * to make them blink if it wishes to. */
+                m_text_to_blink = true;
+
+                /* This is for the "off" state of blinking text. Invisible text could also be handled here,
+                 * but it's not, it's handled outside by not even calling this method.
+                 * Setting fg = bg and painting the text would not work for two reasons: it'd be opaque
+                 * even if the background is translucent, and this method can be called with a continuous
+                 * run of identical fg, yet different bg colored cells. So we simply bail out. */
+                if (!m_text_blink_state)
+                        return;
+        }
+
         /* Draw whatever SFX are required. Do this before drawing the letters,
          * so that if the descent of a letter crosses an underline of a different color,
          * it's the letter's color that wins. Other kinds of decorations always have the
@@ -9304,6 +9372,7 @@ VteTerminalPrivate::draw_cells_with_attributes(struct _vte_draw_text_request *it
                                        cells[j].attr.underline,
                                        cells[j].attr.strikethrough,
                                         cells[j].attr.overline,
+                                        cells[j].attr.blink,
                                         m_allow_hyperlink && cells[j].attr.hyperlink_idx != 0,
                                        FALSE, FALSE, column_width, height);
                j += g_unichar_to_utf8(items[i].c, scratch_buf);
@@ -9334,7 +9403,7 @@ VteTerminalPrivate::draw_rows(VteScreen *screen_,
         gboolean bold, nbold, italic, nitalic,
                  hyperlink, nhyperlink, hilite, nhilite,
                 selected, nselected, strikethrough, nstrikethrough,
-                 overline, noverline, invisible, ninvisible;
+                 overline, noverline, invisible, ninvisible, blink, nblink;
        guint item_count;
        const VteCell *cell;
        VteRowData const* row_data;
@@ -9490,6 +9559,7 @@ VteTerminalPrivate::draw_rows(VteScreen *screen_,
                         hyperlink = (m_allow_hyperlink && cell->attr.hyperlink_idx != 0);
                        bold = cell->attr.bold;
                        italic = cell->attr.italic;
+                        blink = cell->attr.blink;
                         if (cell->attr.hyperlink_idx != 0 && cell->attr.hyperlink_idx == 
m_hyperlink_hover_idx) {
                                 hilite = true;
                         } else if (m_hyperlink_hover_idx == 0 && m_show_match) {
@@ -9562,6 +9632,10 @@ VteTerminalPrivate::draw_rows(VteScreen *screen_,
                                         if (noverline != overline) {
                                                 break;
                                         }
+                                        nblink = cell->attr.blink;
+                                        if (nblink != blink) {
+                                                break;
+                                        }
                                         nhyperlink = (m_allow_hyperlink && cell->attr.hyperlink_idx != 0);
                                         if (nhyperlink != hyperlink) {
                                                 break;
@@ -9622,8 +9696,8 @@ fg_draw:
                                        items,
                                        item_count,
                                         fore, back, deco, FALSE, FALSE,
-                                       bold, italic, underline,
-                                        strikethrough, overline, hyperlink, hilite, FALSE,
+                                        bold, italic, underline, strikethrough,
+                                        overline, blink, hyperlink, hilite, FALSE,
                                        column_width, row_height);
                        item_count = 1;
                        /* We'll need to continue at the first cell which didn't
@@ -9856,6 +9930,7 @@ VteTerminalPrivate::paint_cursor()
                                                         cell->attr.underline,
                                                         cell->attr.strikethrough,
                                                         cell->attr.overline,
+                                                        cell->attr.blink,
                                                         m_allow_hyperlink && cell->attr.hyperlink_idx != 0,
                                                         FALSE,
                                                         FALSE,
@@ -9947,6 +10022,7 @@ VteTerminalPrivate::paint_im_preedit_string()
                                                 0,     /* underline */
                                                 FALSE, /* strikethrough */
                                                 FALSE, /* overline */
+                                                FALSE, /* blink */
                                                 FALSE, /* hyperlink */
                                                 FALSE, /* hilite */
                                                 TRUE,  /* boxed */
@@ -9963,6 +10039,8 @@ VteTerminalPrivate::widget_draw(cairo_t *cr)
         cairo_region_t *region;
         int allocated_width, allocated_height;
         int extra_area_for_cursor;
+        bool text_blink_enabled_now;
+        gint64 now = 0;
 
         if (!gdk_cairo_get_clip_rectangle (cr, &clip_rect))
                 return;
@@ -10029,6 +10107,17 @@ VteTerminalPrivate::widget_draw(cairo_t *cr)
                 cairo_region_destroy(rr);
         }
 
+        /* Whether blinking text should be visible now */
+        m_text_blink_state = true;
+        text_blink_enabled_now = m_text_blink_mode & (m_has_focus ? VTE_TEXT_BLINK_FOCUSED : 
VTE_TEXT_BLINK_UNFOCUSED);
+        if (text_blink_enabled_now) {
+                now = g_get_monotonic_time() / 1000;
+                if (now % (m_text_blink_cycle * 2) >= m_text_blink_cycle)
+                        m_text_blink_state = false;
+        }
+        /* Painting will flip this if it encounters any cell with blink attribute */
+        m_text_to_blink = false;
+
         /* and now paint them */
         for (n = 0; n < n_rectangles; n++) {
                 paint_area(&rectangles[n]);
@@ -10057,6 +10146,19 @@ VteTerminalPrivate::widget_draw(cairo_t *cr)
 
         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
+         * for an explicit step to stop the timer when blinking cells are no longer present, this happens
+         * implicitly by the timer not getting reinstalled anymore (often after a final unnecessary but
+         * harmless repaint). */
+        if (G_UNLIKELY (m_text_to_blink && text_blink_enabled_now && m_text_blink_tag == 0))
+                m_text_blink_tag = g_timeout_add_full(G_PRIORITY_LOW,
+                                                      m_text_blink_cycle - now % m_text_blink_cycle,
+                                                      (GSourceFunc)invalidate_text_blink_cb,
+                                                      this,
+                                                      NULL);
+
         m_invalidated_all = FALSE;
 }
 
@@ -10210,6 +10312,18 @@ VteTerminalPrivate::set_audible_bell(bool setting)
 }
 
 bool
+VteTerminalPrivate::set_text_blink_mode(VteTextBlinkMode setting)
+{
+        if (setting == m_text_blink_mode)
+                return false;
+
+        m_text_blink_mode = setting;
+        invalidate_all();
+
+        return true;
+}
+
+bool
 VteTerminalPrivate::set_allow_bold(bool setting)
 {
         if (setting == m_allow_bold)
diff --git a/src/vte/vteenums.h b/src/vte/vteenums.h
index 0e71715..54c4ee0 100644
--- a/src/vte/vteenums.h
+++ b/src/vte/vteenums.h
@@ -59,6 +59,25 @@ typedef enum {
 } VteCursorShape;
 
 /**
+ * VteTextBlinkMode:
+ * @VTE_TEXT_BLINK_NEVER: Do not blink the text.
+ * @VTE_TEXT_BLINK_FOCUSED: Allow blinking text only if the terminal is focused.
+ * @VTE_TEXT_BLINK_UNFOCUSED: Allow blinking text only if the terminal is unfocused.
+ * @VTE_TEXT_BLINK_ALWAYS: Allow blinking text. This is the default.
+ *
+ * An enumerated type which can be used to indicate whether the terminal allows
+ * the text contents to be blinked.
+ *
+ * Since: 0.52
+ */
+typedef enum {
+        VTE_TEXT_BLINK_NEVER     = 0,
+        VTE_TEXT_BLINK_FOCUSED   = 1,
+        VTE_TEXT_BLINK_UNFOCUSED = 2,
+        VTE_TEXT_BLINK_ALWAYS    = 3
+} VteTextBlinkMode;
+
+/**
  * VteEraseBinding:
  * @VTE_ERASE_AUTO: For backspace, attempt to determine the right value from the terminal's IO settings.  
For delete, use the control sequence.
  * @VTE_ERASE_ASCII_BACKSPACE: Send an ASCII backspace character (0x08).
diff --git a/src/vte/vteterminal.h b/src/vte/vteterminal.h
index 7d85474..b96999f 100644
--- a/src/vte/vteterminal.h
+++ b/src/vte/vteterminal.h
@@ -223,6 +223,11 @@ double vte_terminal_get_cell_height_scale(VteTerminal *terminal) _VTE_GNUC_NONNU
 
 /* Set various on-off settings. */
 _VTE_PUBLIC
+void vte_terminal_set_text_blink_mode(VteTerminal *terminal,
+                                      VteTextBlinkMode text_blink_mode) _VTE_GNUC_NONNULL(1);
+_VTE_PUBLIC
+VteTextBlinkMode vte_terminal_get_text_blink_mode(VteTerminal *terminal) _VTE_GNUC_NONNULL(1);
+_VTE_PUBLIC
 void vte_terminal_set_audible_bell(VteTerminal *terminal,
                                    gboolean is_audible) _VTE_GNUC_NONNULL(1);
 _VTE_PUBLIC
diff --git a/src/vtegtk.cc b/src/vtegtk.cc
index a7dcd9b..83fdfc8 100644
--- a/src/vtegtk.cc
+++ b/src/vtegtk.cc
@@ -499,6 +499,9 @@ vte_terminal_get_property (GObject *object,
                 case PROP_SCROLL_ON_OUTPUT:
                         g_value_set_boolean (value, vte_terminal_get_scroll_on_output(terminal));
                         break;
+                case PROP_TEXT_BLINK_MODE:
+                        g_value_set_enum (value, vte_terminal_get_text_blink_mode (terminal));
+                        break;
                 case PROP_WINDOW_TITLE:
                         g_value_set_string (value, vte_terminal_get_window_title (terminal));
                         break;
@@ -597,6 +600,9 @@ vte_terminal_set_property (GObject *object,
                 case PROP_SCROLL_ON_OUTPUT:
                         vte_terminal_set_scroll_on_output (terminal, g_value_get_boolean (value));
                         break;
+                case PROP_TEXT_BLINK_MODE:
+                        vte_terminal_set_text_blink_mode (terminal, (VteTextBlinkMode)g_value_get_enum 
(value));
+                        break;
                 case PROP_WORD_CHAR_EXCEPTIONS:
                         vte_terminal_set_word_char_exceptions (terminal, g_value_get_string (value));
                         break;
@@ -1547,6 +1553,19 @@ vte_terminal_class_init(VteTerminalClass *klass)
                                       (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | 
G_PARAM_EXPLICIT_NOTIFY));
 
         /**
+         * VteTerminal:text-blink-mode:
+         *
+         * Controls whether or not the terminal will allow blinking text.
+         *
+         * Since: 0.52
+         */
+        pspecs[PROP_TEXT_BLINK_MODE] =
+                g_param_spec_enum ("text-blink-mode", NULL, NULL,
+                                   VTE_TYPE_TEXT_BLINK_MODE,
+                                   VTE_TEXT_BLINK_ALWAYS,
+                                   (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | 
G_PARAM_EXPLICIT_NOTIFY));
+
+        /**
          * VteTerminal:window-title:
          *
          * The terminal's title.
@@ -2903,6 +2922,42 @@ vte_terminal_set_size(VteTerminal *terminal,
 }
 
 /**
+ * vte_terminal_get_text_blink_mode:
+ * @terminal: a #VteTerminal
+ *
+ * Checks whether or not the terminal will allow blinking text.
+ *
+ * Returns: the blinking setting
+ *
+ * Since: 0.52
+ */
+VteTextBlinkMode
+vte_terminal_get_text_blink_mode(VteTerminal *terminal)
+{
+        g_return_val_if_fail(VTE_IS_TERMINAL(terminal), VTE_TEXT_BLINK_ALWAYS);
+        return IMPL(terminal)->m_text_blink_mode;
+}
+
+/**
+ * vte_terminal_set_text_blink_mode:
+ * @terminal: a #VteTerminal
+ * @text_blink_mode: the #VteTextBlinkMode to use
+ *
+ * Controls whether or not the terminal will allow blinking text.
+ *
+ * Since: 0.52
+ */
+void
+vte_terminal_set_text_blink_mode(VteTerminal *terminal,
+                                     VteTextBlinkMode text_blink_mode)
+{
+        g_return_if_fail(VTE_IS_TERMINAL(terminal));
+
+        if (IMPL(terminal)->set_text_blink_mode(text_blink_mode))
+                g_object_notify_by_pspec(G_OBJECT(terminal), pspecs[PROP_TEXT_BLINK_MODE]);
+}
+
+/**
  * vte_terminal_get_allow_bold:
  * @terminal: a #VteTerminal
  *
diff --git a/src/vtegtk.hh b/src/vtegtk.hh
index 7adadfe..c49754e 100644
--- a/src/vtegtk.hh
+++ b/src/vtegtk.hh
@@ -88,6 +88,7 @@ enum {
         PROP_SCROLLBACK_LINES,
         PROP_SCROLL_ON_KEYSTROKE,
         PROP_SCROLL_ON_OUTPUT,
+        PROP_TEXT_BLINK_MODE,
         PROP_WINDOW_TITLE,
         PROP_WORD_CHAR_EXCEPTIONS,
         LAST_PROP,
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index 446204c..5d8731e 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -519,6 +519,13 @@ public:
         gboolean m_cursor_visible;
         gboolean m_has_focus;               /* is the terminal window focused */
 
+        /* Contents blinking */
+        VteTextBlinkMode m_text_blink_mode;
+        gint m_text_blink_cycle;  /* gtk-cursor-blink-time / 2 */
+        bool m_text_blink_state;  /* whether blinking text should be visible at this very moment */
+        bool m_text_to_blink;     /* drawing signals here if it encounters any cell with blink attribute */
+        guint m_text_blink_tag;   /* timeout ID for redrawing due to blinking */
+
         /* DECSCUSR cursor style (shape and blinking possibly overridden
          * via escape sequence) */
         VteCursorStyle m_cursor_style;
@@ -749,6 +756,8 @@ public:
         VteCursorBlinkMode decscusr_cursor_blink();
         VteCursorShape decscusr_cursor_shape();
 
+        void remove_text_blink_timeout();
+
         /* The allocation of the widget */
         cairo_rectangle_int_t m_allocated_rect;
         /* The usable view area. This is the allocation, minus the padding, but
@@ -844,6 +853,7 @@ public:
                         guint underline,
                         bool strikethrough,
                         bool overline,
+                        bool blink,
                         bool hyperlink,
                         bool hilite,
                         bool boxed,
@@ -1222,6 +1232,7 @@ public:
                          int source);
 
         bool set_audible_bell(bool setting);
+        bool set_text_blink_mode(VteTextBlinkMode setting);
         bool set_allow_bold(bool setting);
         bool set_allow_hyperlink(bool setting);
         bool set_backspace_binding(VteEraseBinding binding);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]