diff --git a/inc/app.h b/inc/app.h
index 4fdceb037d5e54c3e0a5f78fe4e05135635af8b0..73971394e2ddd47ee720260138811405ec3ec491 100644
--- a/inc/app.h
+++ b/inc/app.h
@@ -13,6 +13,7 @@ G_DECLARE_FINAL_TYPE(
 
 GameApp* game_app_new();
 void game_app_button_press( GameApp* app, int pin );
+void game_app_button_release( GameApp* app, int pin );
 
 #ifdef __cplusplus
 }
diff --git a/inc/window.h b/inc/window.h
index e84493498c95e6e528bd356afc78045b227af93d..bd9804efca43fef7a66702bce4f00a0e07ab075c 100644
--- a/inc/window.h
+++ b/inc/window.h
@@ -15,6 +15,7 @@ G_DECLARE_FINAL_TYPE( GameWindow,
 
 GameWindow* game_window_new( GameApp* app );
 void game_window_button_press( GameWindow* window, int pin );
+void game_window_button_release( GameWindow* window, int pin );
 
 #ifdef __cplusplus
 }
diff --git a/src/app.c b/src/app.c
index 6ab728d6812ba1f2db809d198e08aee49f1eaff0..8e4dfe7c641a9a718eec90bb8535998ce0d8a19d 100644
--- a/src/app.c
+++ b/src/app.c
@@ -36,6 +36,12 @@ void game_app_button_press( GameApp* app, int pin ) {
 
 }
 
+void game_app_button_release( GameApp* app, int pin ) {
+
+	game_window_button_release( app->window, pin );
+
+}
+
 /* PRIVATE FUNK!!! */
 
 static void game_app_class_init( GameAppClass* class ) {
diff --git a/src/main.c b/src/main.c
index 588c6a364132f18d4876585e3a545c24ffbfee15..5ee8f2de7c3cc12791d914ed6cd94ab504ba27ea 100644
--- a/src/main.c
+++ b/src/main.c
@@ -12,6 +12,8 @@ static GameApp* app = NULL;
 
 /* PROTOTYPES!!! */
 
+static int button_down_cb( void* pin );
+static int button_up_cb( void* pin );
 static void isr_g1();
 static void isr_r1();
 static void isr_g2();
@@ -46,10 +48,10 @@ int main( int argc, char** argv ) {
 	pullUpDnControl( BUTTON_G2, PUD_UP );
 	pullUpDnControl( BUTTON_R2, PUD_UP );
 
-	wiringPiISR( BUTTON_G1, INT_EDGE_FALLING, &isr_g1 );
-	wiringPiISR( BUTTON_R1, INT_EDGE_FALLING, &isr_r1 );
-	wiringPiISR( BUTTON_G2, INT_EDGE_FALLING, &isr_g2 );
-	wiringPiISR( BUTTON_R2, INT_EDGE_FALLING, &isr_r2 );
+	wiringPiISR( BUTTON_G1, INT_EDGE_BOTH, &isr_g1 );
+	wiringPiISR( BUTTON_R1, INT_EDGE_BOTH, &isr_r1 );
+	wiringPiISR( BUTTON_G2, INT_EDGE_BOTH, &isr_g2 );
+	wiringPiISR( BUTTON_R2, INT_EDGE_BOTH, &isr_r2 );
 
 	app = game_app_new();
 	int ret = g_application_run( G_APPLICATION( app ), argc, argv );
@@ -69,7 +71,7 @@ int main( int argc, char** argv ) {
 
 /* PRIVATE FUNK!!! */
 
-static int button_cb( void* pin ) {
+static int button_down_cb( void* pin ) {
 
 	game_app_button_press( app, *( (int*) pin ) );
 
@@ -77,30 +79,54 @@ static int button_cb( void* pin ) {
 
 }
 
+static int button_up_cb( void* pin ) {
+
+	game_app_button_release( app, *( (int*) pin ) );
+
+	return G_SOURCE_REMOVE;
+
+}
+
 static void isr_g1() {
 
 	static int pin = BUTTON_G1;
-	g_idle_add( &button_cb, &pin );
+	if ( HIGH == digitalRead( pin ) ) {
+		g_idle_add( &button_up_cb, &pin );
+	} else {
+		g_idle_add( &button_down_cb, &pin );
+	}
 
 }
 
 static void isr_r1() {
 
 	static int pin = BUTTON_R1;
-	g_idle_add( &button_cb, &pin );
+	if ( HIGH == digitalRead( pin ) ) {
+		g_idle_add( &button_up_cb, &pin );
+	} else {
+		g_idle_add( &button_down_cb, &pin );
+	}
 
 }
 
 static void isr_g2() {
 
 	static int pin = BUTTON_G2;
-	g_idle_add( &button_cb, &pin );
+	if ( HIGH == digitalRead( pin ) ) {
+		g_idle_add( &button_up_cb, &pin );
+	} else {
+		g_idle_add( &button_down_cb, &pin );
+	}
 
 }
 
 static void isr_r2() {
 
 	static int pin = BUTTON_R2;
-	g_idle_add( &button_cb, &pin );
+	if ( HIGH == digitalRead( pin ) ) {
+		g_idle_add( &button_up_cb, &pin );
+	} else {
+		g_idle_add( &button_down_cb, &pin );
+	}
 
 }
diff --git a/src/window.c b/src/window.c
index 6a6e7ddf084ef80ab5531be42f79c434c5432531..f0c0a6856397573e1d77565d9aa60dddf083c280 100644
--- a/src/window.c
+++ b/src/window.c
@@ -9,6 +9,12 @@
 
 /* TYPES!!! */
 
+struct button_state {
+	GameWindow* window;
+	bool bouncing;
+	bool pressed;
+};
+
 struct _GameWindow {
 
 	GtkWindow parent;
@@ -35,6 +41,7 @@ struct _GameWindow {
 
 	enum { RED, GREEN } colour;
 
+	struct button_state g1, r1, g2, r2;
 	bool g1_bouncing;
 	bool r1_bouncing;
 	bool g2_bouncing;
@@ -56,6 +63,8 @@ static void game_window_init( GameWindow* window );
 
 static void realise( GtkWidget* widget, void* data );
 
+static void handle_press( GameWindow* window, int pin );
+
 static void draw( GtkDrawingArea* area, cairo_t* cr,
 	int width, int height, void* data );
 
@@ -75,39 +84,153 @@ GameWindow* game_window_new( GameApp* app ) {
 
 void game_window_button_press( GameWindow* window, int pin ) {
 
-	bool* bouncing = NULL;
+	fprintf( stderr, "Pressed %d", pin );
+
+	struct button_state* button_state = NULL;
 
 	switch ( pin ) {
 
 		case BUTTON_G1:
-			bouncing = &window->g1_bouncing;
+			button_state = &window->g1;
 			break;
 
 		case BUTTON_R1:
-			bouncing = &window->r1_bouncing;
+			button_state = &window->r1;
 			break;
 
 		case BUTTON_G2:
-			bouncing = &window->g2_bouncing;
+			button_state = &window->g2;
 			break;
 
 		case BUTTON_R2:
-			bouncing = &window->r2_bouncing;
+			button_state = &window->r2;
 			break;
 
 	}
 
-	assert( NULL != bouncing );
+	assert( NULL != button_state );
+
+	if ( button_state->bouncing ) {
+		fprintf( stderr, "(bouncing)\n" );
+		return;
+	} else {
+		fprintf( stderr, "\n" );
+	}
 
-	if ( *bouncing ) {
+	if ( button_state->pressed ) {
 		return;
 	}
 
 	fprintf( stderr, "Ping %d\n", pin );
 
-	*bouncing = true;
+	button_state->bouncing = true;
+	button_state->pressed = true;
+
+	g_timeout_add( 200, bounce_reset, button_state );
+
+	handle_press( window, pin );
+
+}
+
+void game_window_button_release( GameWindow* window, int pin ) {
+
+	fprintf( stderr, "Rele'ed %d", pin );
+
+	struct button_state* button_state = NULL;
+
+	switch ( pin ) {
+
+		case BUTTON_G1:
+			button_state = &window->g1;
+			break;
+
+		case BUTTON_R1:
+			button_state = &window->r1;
+			break;
+
+		case BUTTON_G2:
+			button_state = &window->g2;
+			break;
+
+		case BUTTON_R2:
+			button_state = &window->r2;
+			break;
+
+	}
+
+	assert( NULL != button_state );
+
+	if ( button_state->bouncing ) {
+		fprintf( stderr, "(bouncing)\n" );
+		return;
+	} else {
+		fprintf( stderr, "\n" );
+	}
+
+	if ( !button_state->pressed ) {
+		return;
+	}
+
+	button_state->bouncing = true;
+	button_state->pressed = false;
+
+	g_timeout_add( 200, bounce_reset, button_state );
+
+}
+
+/* PRIVATE FUNK!!! */
 
-	g_timeout_add( 200, bounce_reset, bouncing );
+static void game_window_class_init( GameWindowClass* class ) {
+
+	gtk_widget_class_set_template_from_resource(
+		GTK_WIDGET_CLASS( class ), "/xyz/tomg/game/res/window.ui" );
+	gtk_widget_class_bind_template_child(
+		GTK_WIDGET_CLASS( class ), GameWindow, area );
+
+	gtk_widget_class_bind_template_callback_full(
+		GTK_WIDGET_CLASS( class ), "realise",
+		G_CALLBACK( &realise ) );
+
+}
+
+static void game_window_init( GameWindow* window ) {
+
+	gtk_widget_init_template( GTK_WIDGET( window ) );
+
+	GBytes* logo_svg = g_resources_lookup_data(
+		"/xyz/tomg/game/res/logo.svg", 0, NULL );
+	GError* error = NULL;
+	const char* data = g_bytes_get_data( logo_svg, NULL );
+	window->logo = rsvg_handle_new_from_data(
+		(const unsigned char*) data, strlen( data ), &error );
+	if ( NULL != error ) {
+		fprintf( stderr, "%s\n", error->message );
+	}
+	g_bytes_unref( logo_svg );
+
+	window->state = SPLASH;
+
+	window->g1.window = window;
+	window->r1.window = window;
+	window->g2.window = window;
+	window->r2.window = window;
+
+	gtk_drawing_area_set_draw_func(
+		window->area, &draw, (void*) window, NULL );
+
+	gtk_widget_set_cursor( GTK_WIDGET( window ),
+		gdk_cursor_new_from_name( "none", NULL ) );
+
+}
+
+static void realise( GtkWidget* widget, void* data ) {
+
+	gtk_window_fullscreen( GTK_WINDOW( widget ) );
+	(void) data;
+
+}
+
+static void handle_press( GameWindow* window, int pin ) {
 
 	if ( !digitalRead( BUTTON_G1 ) && !digitalRead( BUTTON_R1 ) &&
 			!digitalRead( BUTTON_G2 ) && !digitalRead( BUTTON_R2 ) ) {
@@ -278,53 +401,6 @@ void game_window_button_press( GameWindow* window, int pin ) {
 
 }
 
-/* PRIVATE FUNK!!! */
-
-static void game_window_class_init( GameWindowClass* class ) {
-
-	gtk_widget_class_set_template_from_resource(
-		GTK_WIDGET_CLASS( class ), "/xyz/tomg/game/res/window.ui" );
-	gtk_widget_class_bind_template_child(
-		GTK_WIDGET_CLASS( class ), GameWindow, area );
-
-	gtk_widget_class_bind_template_callback_full(
-		GTK_WIDGET_CLASS( class ), "realise",
-		G_CALLBACK( &realise ) );
-
-}
-
-static void game_window_init( GameWindow* window ) {
-
-	gtk_widget_init_template( GTK_WIDGET( window ) );
-
-	GBytes* logo_svg = g_resources_lookup_data(
-		"/xyz/tomg/game/res/logo.svg", 0, NULL );
-	GError* error = NULL;
-	const char* data = g_bytes_get_data( logo_svg, NULL );
-	window->logo = rsvg_handle_new_from_data(
-		(const unsigned char*) data, strlen( data ), &error );
-	if ( NULL != error ) {
-		fprintf( stderr, "%s\n", error->message );
-	}
-	g_bytes_unref( logo_svg );
-
-	window->state = SPLASH;
-
-	gtk_drawing_area_set_draw_func(
-		window->area, &draw, (void*) window, NULL );
-
-	gtk_widget_set_cursor( GTK_WIDGET( window ),
-		gdk_cursor_new_from_name( "none", NULL ) );
-
-}
-
-static void realise( GtkWidget* widget, void* data ) {
-
-	gtk_window_fullscreen( GTK_WINDOW( widget ) );
-	(void) data;
-
-}
-
 static void draw( GtkDrawingArea* area, cairo_t* cr,
 		int width, int height, void* data ) {
 
@@ -363,7 +439,6 @@ static void draw( GtkDrawingArea* area, cairo_t* cr,
 
 			pango_layout_set_text( layout, buffer, -1 );
 			pango_layout_get_pixel_size( layout, &lw, &lh );
-			fprintf( stderr, "Layout %s size %d, %d\n", buffer, lw, lh );
 
 			cairo_move_to( cr, 0.25 * width - lw / 2.,
 				0.5 * height - lh / 2. );
@@ -445,7 +520,39 @@ static void set_cario_colour( cairo_t* cr, enum colour colour ) {
 
 static int bounce_reset( void* data ) {
 
-	*( (bool*) data ) = false;
+	struct button_state* state = (struct button_state*) data;
+
+	state->bouncing = false;
+
+	int button = -1;
+	if ( state == &( state->window->g1 ) ) {
+		button = BUTTON_G1;
+	} else if ( state == &( state->window->r1 ) ) {
+		button = BUTTON_R1;
+	} else if ( state == &( state->window->g2 ) ) {
+		button = BUTTON_G2;
+	} else if ( state == &( state->window->r2 ) ) {
+		button = BUTTON_R2;
+	}
+	assert( -1 != button );
+
+	bool pressed = ( LOW == digitalRead( button ) );
+
+	fprintf( stderr, "Done bouncing: %s",
+		pressed ? "pressed" : "released" );
+
+	if ( pressed != state->pressed ) {
+
+		fprintf( stderr, " (adjusting)\n" );
+
+		state->pressed = pressed;
+		if ( pressed ) {
+			handle_press( state->window, button );
+		}
+
+	} else {
+		fprintf( stderr, "\n" );
+	}
 
 	return G_SOURCE_REMOVE;