diff --git a/src/conio/bitmap_con.c b/src/conio/bitmap_con.c
index 84e12872684fc4999a9ca831cf5ec235a97e66ce..e74a53103ebf7ec9b9c8f4f41ec77745b9f743f5 100644
--- a/src/conio/bitmap_con.c
+++ b/src/conio/bitmap_con.c
@@ -93,8 +93,11 @@ static struct bitmap_callbacks callbacks;
 static unsigned char *font[4];
 static int force_redraws=0;
 static int force_cursor=0;
-struct rectlist *free_rects;
-pthread_mutex_t free_rect_lock;
+static struct rectlist *free_rects;
+static pthread_mutex_t free_rect_lock;
+static bool throttled;
+static int outstanding_rects;
+#define MAX_OUTSTANDING 1
 
 /* The read lock must be held here. */
 #define PIXEL_OFFSET(screen, x, y)	( (y)*(screen).screenwidth+(x) )
@@ -419,17 +422,31 @@ static void request_redraw(void)
 /*
  * Called with the screen lock held
  */
-static struct rectlist *alloc_full_rect(struct bitmap_screen *screen)
+static struct rectlist *alloc_full_rect(struct bitmap_screen *screen, bool allow_throttle)
 {
 	struct rectlist * ret;
 
 	pthread_mutex_lock(&free_rect_lock);
+	if (allow_throttle) {
+		if (throttled) {
+			pthread_mutex_unlock(&free_rect_lock);
+			return NULL;
+		}
+		if (outstanding_rects >= MAX_OUTSTANDING) {
+			throttled = true;
+			pthread_mutex_unlock(&free_rect_lock);
+			return NULL;
+		}
+	}
 	while (free_rects) {
 		if (free_rects->rect.width == screen->screenwidth && free_rects->rect.height == screen->screenheight) {
 			ret = free_rects;
 			free_rects = free_rects->next;
 			ret->next = NULL;
 			ret->rect.x = ret->rect.y = 0;
+			ret->throttle = allow_throttle;
+			if (allow_throttle)
+				outstanding_rects++;
 			pthread_mutex_unlock(&free_rect_lock);
 			return ret;
 		}
@@ -444,6 +461,7 @@ static struct rectlist *alloc_full_rect(struct bitmap_screen *screen)
 
 	ret = malloc(sizeof(struct rectlist));
 	ret->next = NULL;
+	ret->throttle = allow_throttle;
 	ret->rect.x = 0;
 	ret->rect.y = 0;
 	ret->rect.width = screen->screenwidth;
@@ -451,6 +469,12 @@ static struct rectlist *alloc_full_rect(struct bitmap_screen *screen)
 	ret->data = malloc(ret->rect.width * ret->rect.height * sizeof(ret->data[0]));
 	if (ret->data == NULL)
 		FREE_AND_NULL(ret);
+	pthread_mutex_lock(&free_rect_lock);
+	if (allow_throttle) {
+		if (ret)
+			outstanding_rects++;
+	}
+	pthread_mutex_unlock(&free_rect_lock);
 	return ret;
 }
 
@@ -472,7 +496,7 @@ static struct rectlist *get_full_rectangle_locked(struct bitmap_screen *screen)
 
 	// TODO: Some sort of caching here would make things faster...?
 	if(callbacks.drawrect) {
-		rect = alloc_full_rect(screen);
+		rect = alloc_full_rect(screen, true);
 		if (!rect)
 			return rect;
 		for (pos = 0; pos < sz; pos++)
@@ -715,14 +739,26 @@ static void blinker_thread(void *data)
 		}
 		// TODO: Maybe we can optimize the blink_changed forced update?
 		if (screen->update_pixels || curs_changed || blink_changed || lfc) {
-			// If the other screen is update_pixels == 2, clear it.
-			if (ncscreen->update_pixels == 2)
-				ncscreen->update_pixels = 0;
 			rect = get_full_rectangle_locked(screen);
-			screen->update_pixels = 0;
-			pthread_mutex_unlock(&screenlock);
-			cb_drawrect(rect);
-			cb_flush();
+			/*
+			 * TODO: It would be more effective to wait when we're bing throttled
+			 *       and make up for cursor/blink based on elapsed time, but that's
+			 *       getting complicated enough that I don't want do do a quick
+			 *       hack for it.  Ideally this would be done as part of pegging
+			 *       the blink rate to the wall clock rather than the free-running
+			 *       sleep-based method it currently uses.
+			 */
+			if (rect) {
+				// If the other screen is update_pixels == 2, clear it.
+				if (ncscreen->update_pixels == 2)
+					ncscreen->update_pixels = 0;
+				screen->update_pixels = 0;
+				pthread_mutex_unlock(&screenlock);
+				cb_drawrect(rect);
+				cb_flush();
+			}
+			else
+				pthread_mutex_unlock(&screenlock);
 		}
 		else {
 			pthread_mutex_unlock(&screenlock);
@@ -1597,12 +1633,12 @@ static int init_screens(int *width, int *height)
 	screenb.update_pixels = 1;
 	bitmap_drv_free_rect(screena.rect);
 	bitmap_drv_free_rect(screenb.rect);
-	screena.rect = alloc_full_rect(&screena);
+	screena.rect = alloc_full_rect(&screena, false);
 	if (screena.rect == NULL) {
 		pthread_mutex_unlock(&screenlock);
 		return(-1);
 	}
-	screenb.rect = alloc_full_rect(&screenb);
+	screenb.rect = alloc_full_rect(&screenb, false);
 	if (screenb.rect == NULL) {
 		bitmap_drv_free_rect(screena.rect);
 		screena.rect = NULL;
@@ -1910,6 +1946,12 @@ void bitmap_drv_free_rect(struct rectlist *rect)
 	if (rect == NULL)
 		return;
 	pthread_mutex_lock(&free_rect_lock);
+	if (rect->throttle) {
+		outstanding_rects--;
+		if (outstanding_rects < MAX_OUTSTANDING && throttled) {
+			throttled = false;
+		}
+	}
 	rect->next = free_rects;
 	free_rects = rect;
 	pthread_mutex_unlock(&free_rect_lock);
diff --git a/src/conio/bitmap_con.h b/src/conio/bitmap_con.h
index 9ce1e0f95969903d036918930fbf505d8aba5c94..b4d20121d8efb77acd69f697d0e3e8a1784f01c9 100644
--- a/src/conio/bitmap_con.h
+++ b/src/conio/bitmap_con.h
@@ -15,6 +15,7 @@ struct rectlist {
 	struct rectangle rect;
 	uint32_t *data;
 	struct rectlist *next;
+	bool throttle;
 };
 
 extern struct video_stats vstat;