2006-06-15  Manu Cornet <manu@manucornet.net>

        Make the cursor stop blinking after a few seconds.

        * gtkentry.c: Add an XSetting "gtk-cursor-blink-lifetime", default 5
        seconds, and a timeout property in the private structure. Then, add a
        timeout to kill the blink ("kill_blink" function) after the idle time
        and let the cursor stay on.

        * gtktextview.c: Changes similar to gtkentry.c, but also created the
        private structure in which to add the blink_lifetime_timeout property.

Index: gtkentry.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkentry.c,v
retrieving revision 1.284.2.8
diff -u -r1.284.2.8 gtkentry.c
--- gtkentry.c	18 May 2006 16:44:24 -0000	1.284.2.8
+++ gtkentry.c	15 Jun 2006 19:16:35 -0000
@@ -77,7 +77,8 @@
 struct _GtkEntryPrivate 
 {
   gfloat xalign;
-  gint insert_pos;
+  gint   insert_pos;
+  guint  blink_lifetime_timeout;
 };
 
 enum {
@@ -829,12 +830,24 @@
   gtk_binding_entry_add_signal (binding_set, GDK_KP_Insert, 0,
 				"toggle_overwrite", 0);
 
+  /*
+   * XSettings
+   */
+
+
   gtk_settings_install_property (g_param_spec_boolean ("gtk-entry-select-on-focus",
 						       P_("Select on focus"),
 						       P_("Whether to select the contents of an entry when it is focused"),
 						       TRUE,
 						       GTK_PARAM_READWRITE));
 
+  gtk_settings_install_property (g_param_spec_uint ("gtk-cursor-blink-lifetime",
+						    P_("Cursor blink lifetime"),
+						    P_("Time before the cursor stops blinking, in milliseconds"),
+						    0, G_MAXUINT,
+						    5000,
+						    G_PARAM_READWRITE));
+
   g_type_class_add_private (gobject_class, sizeof (GtkEntryPrivate));
 }
 
@@ -4943,6 +4956,27 @@
     }
 }
 
+static gint
+kill_blink (gpointer data)
+{
+  /* 
+   * Stop blinking and don't start again until
+   * gtk_entry_check_cursor_blink is called again
+   */  
+  
+  GtkEntry *entry;
+  
+  entry = GTK_ENTRY (data);
+  
+  if (entry->blink_timeout != 0)
+    {
+      g_source_remove (entry->blink_timeout);
+      entry->blink_timeout = 0;
+    }
+  show_cursor (entry);
+  return FALSE;
+}
+
 /*
  * Blink!
  */
@@ -4989,8 +5023,18 @@
 static void
 gtk_entry_check_cursor_blink (GtkEntry *entry)
 {
+  guint            lifetime;
+  GtkEntryPrivate *priv;
+
+  priv = GTK_ENTRY_GET_PRIVATE (entry);
+
   if (cursor_blinks (entry))
     {
+      g_object_get (gtk_widget_get_settings (GTK_WIDGET (entry)),
+                    "gtk-cursor-blink-lifetime",
+                    &lifetime,
+                    NULL);
+
       if (!entry->blink_timeout)
 	{
 	  entry->blink_timeout = g_timeout_add (get_cursor_time (entry) * CURSOR_ON_MULTIPLIER,
@@ -4998,6 +5042,14 @@
 						entry);
 	  show_cursor (entry);
 	}
+      if (priv->blink_lifetime_timeout)
+	{
+	  g_source_remove (priv->blink_lifetime_timeout);
+	}
+      
+      priv->blink_lifetime_timeout = g_timeout_add (lifetime,
+                                                    kill_blink,
+                                                    entry);
     }
   else
     {
@@ -5006,23 +5058,41 @@
 	  g_source_remove (entry->blink_timeout);
 	  entry->blink_timeout = 0;
 	}
-      
+      if (priv->blink_lifetime_timeout)
+	{
+	  g_source_remove (priv->blink_lifetime_timeout);
+	}
+
       entry->cursor_visible = TRUE;
     }
-  
 }
 
 static void
 gtk_entry_pend_cursor_blink (GtkEntry *entry)
 {
+  guint            lifetime;
+  GtkEntryPrivate *priv;
+ 
+  priv = GTK_ENTRY_GET_PRIVATE (entry);
+
   if (cursor_blinks (entry))
     {
+      g_object_get (gtk_widget_get_settings (GTK_WIDGET (entry)),
+		    "gtk-cursor-blink-lifetime",
+		    &lifetime,
+		    NULL);
       if (entry->blink_timeout != 0)
 	g_source_remove (entry->blink_timeout);
       
       entry->blink_timeout = g_timeout_add (get_cursor_time (entry) * CURSOR_PEND_MULTIPLIER,
 					    blink_cb,
 					    entry);
+      if (priv->blink_lifetime_timeout != 0)
+	g_source_remove (priv->blink_lifetime_timeout);
+      
+      priv->blink_lifetime_timeout = g_timeout_add (lifetime,
+                                                    kill_blink,
+                                                    entry);
       show_cursor (entry);
     }
 }
Index: gtktextview.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktextview.c,v
retrieving revision 1.286.2.11
diff -u -r1.286.2.11 gtktextview.c
--- gtktextview.c	12 Apr 2006 02:53:45 -0000	1.286.2.11
+++ gtktextview.c	15 Jun 2006 19:16:38 -0000
@@ -99,6 +99,15 @@
 
 #define SPACE_FOR_CURSOR 1
 
+typedef struct _GtkTextViewPrivate GtkTextViewPrivate;
+
+#define GTK_TEXT_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_TEXT_VIEW, GtkTextViewPrivate))
+
+struct _GtkTextViewPrivate 
+{
+  guint  blink_lifetime_timeout;
+};
+
 struct _GtkTextPendingScroll
 {
   GtkTextMark   *mark;
@@ -677,7 +686,17 @@
 							       P_("Color with which to draw error-indication underlines"),
 							       GDK_TYPE_COLOR,
 							       GTK_PARAM_READABLE));
+  /*
+   * XSettings
+   */
   
+  gtk_settings_install_property (g_param_spec_uint ("gtk-cursor-blink-lifetime",
+						    P_("Cursor blink lifetime"),
+						    P_("Time before the cursor stops blinking, in milliseconds"),
+						    0, G_MAXUINT,
+						    5000,
+						    G_PARAM_READWRITE));
+
   /*
    * Signals
    */
@@ -1035,6 +1054,7 @@
   gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
 				"move_focus", 1,
 				GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD);
+  g_type_class_add_private (gobject_class, sizeof (GtkTextViewPrivate));
 }
 
 static void
@@ -4467,6 +4487,44 @@
   return time;
 }
 
+static gint
+kill_blink (gpointer data)
+{
+  /* 
+   * Stop blinking and don't start again until
+   * gtk_text_view_check_cursor_blink is called again
+   */  
+  
+  GtkTextView *text_view;
+
+  text_view = GTK_TEXT_VIEW (data);
+
+  if (text_view->blink_timeout != 0)
+    {
+      g_source_remove (text_view->blink_timeout);
+      text_view->blink_timeout = 0;
+    }
+
+  /* Block changed_handler while changing the layout's cursor visibility
+   * because it would expose the whole paragraph. Instead, we expose
+   * the cursor's area(s) manually below.
+   */
+
+  g_signal_handlers_block_by_func (text_view->layout,
+                                   changed_handler,
+                                   text_view);
+
+  gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
+
+  g_signal_handlers_unblock_by_func (text_view->layout,
+                                     changed_handler,
+                                     text_view);
+
+  text_window_invalidate_cursors (text_view->text_window);
+
+  return FALSE;
+}
+
 /*
  * Blink!
  */
@@ -4529,22 +4587,41 @@
 static void
 gtk_text_view_stop_cursor_blink (GtkTextView *text_view)
 {
-  if (text_view->blink_timeout)  
+  GtkTextViewPrivate *priv;
+
+  priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
+
+  if (text_view->blink_timeout)
     { 
       g_source_remove (text_view->blink_timeout);
       text_view->blink_timeout = 0;
     }
+
+  if (priv->blink_lifetime_timeout)
+    {
+      g_source_remove (priv->blink_lifetime_timeout);
+    }
 }
 
 static void
 gtk_text_view_check_cursor_blink (GtkTextView *text_view)
 {
+  guint lifetime;
+  GtkTextViewPrivate *priv;
+
+  priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
+
   if (text_view->layout != NULL &&
       text_view->cursor_visible &&
       GTK_WIDGET_HAS_FOCUS (text_view))
     {
       if (cursor_blinks (text_view))
 	{
+	  g_object_get (gtk_widget_get_settings (GTK_WIDGET (text_view)),
+			"gtk-cursor-blink-lifetime",
+			&lifetime,
+			NULL);
+
 	  if (text_view->blink_timeout == 0)
 	    {
 	      gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
@@ -4553,6 +4630,14 @@
 							blink_cb,
 							text_view);
 	    }
+
+	  if (priv->blink_lifetime_timeout)
+	    {
+	      g_source_remove (priv->blink_lifetime_timeout);
+	    }
+	  priv->blink_lifetime_timeout = g_timeout_add (lifetime,
+							kill_blink,
+							text_view);
 	}
       else
 	gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);	
@@ -4566,17 +4651,33 @@
 static void
 gtk_text_view_pend_cursor_blink(GtkTextView *text_view)
 {
+  guint lifetime;
+  GtkTextViewPrivate *priv;
+
+  priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
+
   if (text_view->layout != NULL &&
       text_view->cursor_visible &&
       GTK_WIDGET_HAS_FOCUS (text_view) &&
       cursor_blinks (text_view))
     {
+      g_object_get (gtk_widget_get_settings (GTK_WIDGET (text_view)),
+		    "gtk-cursor-blink-lifetime",
+		    &lifetime,
+		    NULL);
+
       if (text_view->blink_timeout != 0)
 	{
 	  g_source_remove (text_view->blink_timeout);
 	  text_view->blink_timeout = 0;
 	}
       
+      if (priv->blink_lifetime_timeout != 0)
+	g_source_remove (priv->blink_lifetime_timeout);
+      
+      priv->blink_lifetime_timeout = g_timeout_add (lifetime,
+						    kill_blink,
+						    text_view);
       gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
       
       text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_PEND_MULTIPLIER,
