From b99723a14b9bd4d81ed34fbc4195ae99f3adeabb Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sat, 3 Feb 2018 23:52:41 +0100
Subject: Fixed the caret rendering for buffer displays.

---
 ChangeLog                     |   5 ++
 src/gtkext/gtkbufferdisplay.c | 161 +++++++++++++++++++++++++++---------------
 2 files changed, 108 insertions(+), 58 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index bcff8ed..9330f63 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+18-02-03  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/gtkext/gtkbufferdisplay.c:
+	Fix the caret rendering for buffer displays.
+
 18-01-31  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/gtkext/gtkbufferdisplay.c:
diff --git a/src/gtkext/gtkbufferdisplay.c b/src/gtkext/gtkbufferdisplay.c
index d941ff2..e2335af 100644
--- a/src/gtkext/gtkbufferdisplay.c
+++ b/src/gtkext/gtkbufferdisplay.c
@@ -24,6 +24,9 @@
 #include "gtkbufferdisplay.h"
 
 
+#include <assert.h>
+
+
 #include "gtkbufferdisplay-int.h"
 
 
@@ -90,11 +93,17 @@ static bool _gtk_buffer_display_move_caret_to(GtkBufferDisplay *, gint, gint);
 /* Déplace le curseur en effaçant son éventuelle position. */
 static void gtk_buffer_display_relocate_caret(GtkBufferDisplay *, const cairo_rectangle_int_t *, const vmpa2t *);
 
+/* Assure le clignotement du curseur à l'emplacement courant. */
+static gboolean gtk_buffer_display_refresh_caret(GtkBufferDisplay *);
+
 /* Redémarre l'affichage du curseur à l'emplacement courant. */
 static void gtk_buffer_display_restart_caret_blinking(GtkBufferDisplay *);
 
-/* Bascule et relance l'affichage du curseur. */
-static gboolean gtk_buffer_display_refresh_caret(GtkBufferDisplay *);
+/* Prépare l'actualisation de tout ou une partie de l'affichage. */
+static void gtk_buffer_display_queue_draw_caret(GtkBufferDisplay *, cairo_rectangle_int_t *);
+
+/* Affiche le curseur à l'écran, s'il doit l'être. */
+static void gtk_buffer_display_draw_caret(GtkBufferDisplay *, cairo_t *);
 
 
 
@@ -252,7 +261,7 @@ static gboolean gtk_buffer_display_focus(GtkWidget *widget, GdkEventFocus *event
         display->caret_timer = 0;
 
         display->show_caret = true;
-        gtk_buffer_display_refresh_caret(display);
+        gtk_buffer_display_queue_draw_caret(display, NULL);
 
     }
 
@@ -342,6 +351,7 @@ static gboolean gtk_buffer_display_draw(GtkWidget *widget, cairo_t *cr)
     window = gtk_widget_get_window(widget);
 
     cairo_save(cr);
+
     gtk_cairo_transform_to_window(cr, widget, window);
 
     region = gdk_window_get_clip_region(window);
@@ -435,17 +445,12 @@ static gboolean gtk_buffer_display_draw(GtkWidget *widget, cairo_t *cr)
 
     /* Curseur clignotant ? */
 
-    /*
     if (gtk_widget_is_focus(widget))
-    {
-        view->show_caret = !view->show_caret;
-        gtk_buffer_display_refresh_caret(view);
-    }
-    */
+        gtk_buffer_display_draw_caret(display, cr);
 
     cairo_restore(cr);
 
-    return TRUE;
+    return FALSE;
 
 }
 
@@ -942,19 +947,43 @@ static void gtk_buffer_display_relocate_caret(GtkBufferDisplay *display, const c
     else
         need_redraw = false;
 
+    if (!is_invalid_vmpa(&display->caret_addr))
+        gtk_buffer_display_restart_caret_blinking(display);
+
     if (need_redraw)
-        gtk_widget_queue_draw(GTK_WIDGET(display));
+        gtk_buffer_display_queue_draw_caret(display, NULL);
 
     else if (clear_old)
-    {
-        gtk_display_panel_compute_relative_coords(GTK_DISPLAY_PANEL(display), &old_area.x, &old_area.y);
+        gtk_buffer_display_queue_draw_caret(display, &old_area);
 
-        gtk_widget_queue_draw_area(GTK_WIDGET(display), old_area.x, old_area.y,
-                                   old_area.width, old_area.height);
+}
 
-    }
 
-    gtk_buffer_display_restart_caret_blinking(display);
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : display = composant GTK à manipuler.                         *
+*                                                                             *
+*  Description : Assure le clignotement du curseur à l'emplacement courant.   *
+*                                                                             *
+*  Retour      : TRUE pour poursuivre le clignotement.                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static gboolean gtk_buffer_display_refresh_caret(GtkBufferDisplay *display)
+{
+    /* Bascule l'affichage */
+    display->show_caret = !display->show_caret;
+
+    assert(!is_invalid_vmpa(&display->caret_addr));
+
+    if (!display->show_caret)
+        gtk_buffer_display_queue_draw_caret(display, &display->caret);
+    else
+        gtk_buffer_display_queue_draw_caret(display, NULL);
+
+    return TRUE;
 
 }
 
@@ -985,18 +1014,17 @@ static void gtk_buffer_display_restart_caret_blinking(GtkBufferDisplay *display)
 
     if (!is_invalid_vmpa(&display->caret_addr))
     {
-        display->show_caret = false;
-        gtk_buffer_display_refresh_caret(display);
-
         settings = gtk_settings_get_default();
 
         g_object_get(settings, "gtk-cursor-blink-time", &interval, NULL);
 
+        display->show_caret = true;
+
         g_object_ref(G_OBJECT(display));
 
-        display->caret_timer = g_timeout_add_full(G_PRIORITY_DEFAULT, interval,
-                                               (GSourceFunc)gtk_buffer_display_refresh_caret,
-                                               display, g_object_unref);
+        display->caret_timer = gdk_threads_add_timeout_full(G_PRIORITY_DEFAULT, interval,
+                                                            (GSourceFunc)gtk_buffer_display_refresh_caret,
+                                                            display, g_object_unref);
 
     }
 
@@ -1008,58 +1036,79 @@ static void gtk_buffer_display_restart_caret_blinking(GtkBufferDisplay *display)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : display = composant GTK à manipuler.                         *
+*                area    = emplacement du curseur ou NULL toute la région.    *
 *                                                                             *
-*  Description : Bascule et relance l'affichage du curseur.                   *
+*  Description : Prépare l'actualisation de tout ou une partie de l'affichage.*
 *                                                                             *
-*  Retour      : TRUE pour poursuivre les basculements automatiques.          *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static gboolean gtk_buffer_display_refresh_caret(GtkBufferDisplay *display)
+static void gtk_buffer_display_queue_draw_caret(GtkBufferDisplay *display, cairo_rectangle_int_t *area)
 {
     GtkWidget *widget;                      /* Autre version du composant  */
-    GdkWindow *window;                      /* Fenêtre de support associée */
-    cairo_rectangle_int_t area;             /* Zone adaptée à traiter      */
-    cairo_region_t *region;                 /* Région définie associée     */
-    GdkDrawingContext *drawing;             /* Mécanisme de dessins        */
-    cairo_t *cr;                            /* Contexte graphique          */
-    GdkRGBA *color;                         /* Couleur du curseur          */
+    cairo_rectangle_int_t rect;             /* Zone rectangulaire relative */
+    cairo_region_t *region;                 /* Zone précise à redessiner   */
 
     widget = GTK_WIDGET(display);
-    window = gtk_widget_get_window(widget);
 
-    /**
-     * Si le composant n'est pas encore réalisé (ou caché, en cas de
-     * basculement entre les types de vues), gdk_cairo_create() ne va
-     * pas apprécier l'argument NULL. Donc on écourte l'opération.
-     */
-    if (window == NULL)
+    if (area == NULL)
+        gtk_widget_queue_draw(widget);
+
+    else
     {
-        display->show_caret = !display->show_caret;
-        return TRUE;
-    }
+        rect = *area;
+        gtk_display_panel_compute_relative_coords(GTK_DISPLAY_PANEL(display), &rect.x, &rect.y);
 
-    area = display->caret;
-    gtk_display_panel_compute_relative_coords(GTK_DISPLAY_PANEL(display), &area.x, &area.y);
+        region = cairo_region_create_rectangle(&rect);
+        gtk_widget_queue_draw_region(widget, region);
+        cairo_region_destroy(region);
 
-    /* Réinitialisation de la surface */
-    if (display->show_caret)
-    {
-        display->show_caret = false;
-        gtk_widget_queue_draw_area(widget, area.x, area.y, area.width, area.height);
     }
 
-    /* Dessin */
-    else
+    /**
+     * Pour une raison non comprise, le redessin n'est pris en compte que
+     * si le parent est concerné également...
+     */
+
+    widget = gtk_widget_get_parent(widget);
+
+    if (GTK_IS_SCROLLED_WINDOW(widget))
+        gtk_widget_queue_draw(widget);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : display = composant GTK à manipuler.                         *
+*                cr     = contexte graphique disponible pour l'opération.     *
+*                                                                             *
+*  Description : Affiche le curseur à l'écran, s'il doit l'être.              *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void gtk_buffer_display_draw_caret(GtkBufferDisplay *display, cairo_t *cr)
+{
+    cairo_rectangle_int_t area;             /* Zone adaptée à traiter      */
+    cairo_region_t *region;                 /* Région définie associée     */
+    GtkWidget *widget;                      /* Autre version du composant  */
+    GdkRGBA *color;                         /* Couleur du curseur          */
+
+    if (!is_invalid_vmpa(&display->caret_addr) && display->show_caret)
     {
-        display->show_caret = true;
+        area = display->caret;
+        gtk_display_panel_compute_relative_coords(GTK_DISPLAY_PANEL(display), &area.x, &area.y);
 
         region = cairo_region_create_rectangle(&area);
 
-        drawing = gdk_window_begin_draw_frame(window, region);
-        cr = gdk_drawing_context_get_cairo_context(drawing);
+        widget = GTK_WIDGET(display);
 
         gtk_style_context_get(gtk_widget_get_style_context(widget),
                               gtk_widget_get_state_flags(widget),
@@ -1070,12 +1119,8 @@ static gboolean gtk_buffer_display_refresh_caret(GtkBufferDisplay *display)
         cairo_rectangle(cr, area.x, area.y, area.width, area.height);
         cairo_fill(cr);
 
-        gdk_window_end_draw_frame(window, drawing);
-
         cairo_region_destroy(region);
 
     }
 
-    return TRUE;
-
 }
-- 
cgit v0.11.2-87-g4458