[hitori] Fix race condition when requesting a new hint



commit 7f72414ed7318f6f2b9021ec50b2e20313f112a3
Author: Philip Withnall <philip tecnocode co uk>
Date:   Sun Oct 31 13:29:52 2010 +0000

    Fix race condition when requesting a new hint
    
    If a new hint was requested just as soon as an existing hint was finishing,
    the timeout for the old hint would never be removed, and the new hint would
    flash twice as fast as it should. This tidies up hinting so that this can't
    happen.

 src/interface.c |   37 +++++++++++++++++++++++++++----------
 src/main.h      |    1 +
 2 files changed, 28 insertions(+), 10 deletions(-)
---
diff --git a/src/interface.c b/src/interface.c
index 78c0157..e23a3ba 100644
--- a/src/interface.c
+++ b/src/interface.c
@@ -34,8 +34,11 @@
 #define TAG_OFFSET 0.75
 #define TAG_RADIUS 0.25
 #define HINT_FLASHES 6
+#define HINT_DISABLED 0
 #define HINT_INTERVAL 500
 
+static void hitori_cancel_hinting (Hitori *hitori);
+
 /* Declarations for GtkBuilder */
 gboolean hitori_draw_cb (GtkWidget *drawing_area, cairo_t *cr, Hitori *hitori);
 gboolean hitori_button_release_cb (GtkWidget *drawing_area, GdkEventButton *event, Hitori *hitori);
@@ -284,10 +287,7 @@ hitori_button_release_cb (GtkWidget *drawing_area, GdkEventButton *event, Hitori
 	gtk_action_set_sensitive (hitori->undo_action, TRUE);
 
 	/* Stop any current hints */
-	hitori->hint_status = HINT_FLASHES;
-
-	if (hitori->debug)
-		g_debug ("Stopping all current hints.");
+	hitori_cancel_hinting (hitori);
 
 	/* Redraw */
 	gtk_widget_queue_draw (hitori->drawing_area);
@@ -328,6 +328,18 @@ hitori_new_game_cb (GtkAction *action, Hitori *hitori)
 	hitori_new_game (hitori, hitori->board_size);
 }
 
+static void
+hitori_cancel_hinting (Hitori *hitori)
+{
+	if (hitori->debug)
+		g_debug ("Stopping all current hints.");
+
+	hitori->hint_status = HINT_DISABLED;
+	if (hitori->hint_timeout_id != 0)
+		g_source_remove (hitori->hint_timeout_id);
+	hitori->hint_timeout_id = 0;
+}
+
 static gboolean
 hitori_update_hint (Hitori *hitori)
 {
@@ -337,10 +349,10 @@ hitori_update_hint (Hitori *hitori)
 	gfloat cell_size;
 
 	/* Check to see if hinting's been stopped by a cell being changed (race condition) */
-	if (hitori->hint_status >= HINT_FLASHES)
+	if (hitori->hint_status == HINT_DISABLED)
 		return FALSE;
 
-	hitori->hint_status++;
+	hitori->hint_status--;
 
 	if (hitori->debug)
 		g_debug ("Updating hint status to %u.", hitori->hint_status);
@@ -372,7 +384,12 @@ hitori_update_hint (Hitori *hitori)
 	gtk_widget_queue_draw_area (hitori->drawing_area, hitori->hint_position.x * cell_size, hitori->hint_position.y * cell_size,
 	                            cell_size, cell_size);
 
-	return (hitori->hint_status < HINT_FLASHES) ? TRUE : FALSE;
+	if (hitori->hint_status == HINT_DISABLED) {
+		hitori_cancel_hinting (hitori);
+		return FALSE;
+	}
+
+	return TRUE;
 }
 
 void
@@ -381,7 +398,7 @@ hitori_hint_cb (GtkAction *action, Hitori *hitori)
 	HitoriVector iter;
 
 	/* Bail if we're already hinting */
-	if (hitori->hint_status > 0 && hitori->hint_status < HINT_FLASHES)
+	if (hitori->hint_status != HINT_DISABLED)
 		return;
 
 	/* Find the first cell which should be painted, but isn't (or vice-versa) */
@@ -395,9 +412,9 @@ hitori_hint_cb (GtkAction *action, Hitori *hitori)
 					g_debug ("Beginning hinting in cell (%u,%u).", iter.x, iter.y);
 
 				/* Set up the cell for hinting */
-				hitori->hint_status = 0;
+				hitori->hint_status = HINT_FLASHES;
 				hitori->hint_position = iter;
-				g_timeout_add (HINT_INTERVAL, (GSourceFunc) hitori_update_hint, hitori);
+				hitori->hint_timeout_id = g_timeout_add (HINT_INTERVAL, (GSourceFunc) hitori_update_hint, hitori);
 				hitori_update_hint ((gpointer) hitori);
 
 				return;
diff --git a/src/main.h b/src/main.h
index c487874..d27d1bd 100644
--- a/src/main.h
+++ b/src/main.h
@@ -86,6 +86,7 @@ typedef struct {
 
 	guint hint_status;
 	HitoriVector hint_position;
+	guint hint_timeout_id;
 
 	guint timer_value; /* seconds into the game */
 	GtkLabel *timer_label;



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