diff --git a/src/conio/bitmap_con.c b/src/conio/bitmap_con.c
index 7e6589fca4517e0d53285fe8bf3c0145fc5bf95b..f3a3263ed3afe2f5c8dd4fab582ecf121221f708 100644
--- a/src/conio/bitmap_con.c
+++ b/src/conio/bitmap_con.c
@@ -1,5 +1,6 @@
 /* $Id: bitmap_con.c,v 1.148 2020/06/27 00:04:44 deuce Exp $ */
 
+#include <assert.h>
 #include <math.h>
 #include <stdarg.h>
 #include <stdbool.h>
@@ -74,6 +75,7 @@ struct bitmap_screen {
 	//uint32_t *screen;
 	int		screenwidth;
 	int		screenheight;
+	int		toprow;
 	int		update_pixels;
 	struct rectlist *rect;
 };
@@ -104,9 +106,6 @@ static int outstanding_rects;
 // win32gdi requires two rects...
 #define MAX_OUTSTANDING 2
 
-/* The read lock must be held here. */
-#define PIXEL_OFFSET(screen, x, y)	( (y)*(screen).screenwidth+(x) )
-
 /* Exported globals */
 
 pthread_mutex_t		vstatlock;
@@ -120,7 +119,6 @@ static void	cb_drawrect(struct rectlist *data);
 static void request_redraw_locked(void);
 static void request_redraw(void);
 static void memset_u32(void *buf, uint32_t u, size_t len);
-static int bitmap_draw_one_char(struct vmem_cell *vc, unsigned int xpos, unsigned int ypos);
 static void cb_flush(void);
 static int check_redraw(void);
 static void blinker_thread(void *data);
@@ -128,6 +126,7 @@ static __inline void both_screens(int blink, struct bitmap_screen** current, str
 static int update_from_vmem(int force);
 static uint32_t color_value(uint32_t col);
 void bitmap_drv_free_rect(struct rectlist *rect);
+static void bitmap_draw_vmem(int sx, int sy, int ex, int ey, struct vmem_cell *fill);
 
 /**************************************************************/
 /* These functions get called from the driver and ciolib only */
@@ -269,6 +268,7 @@ bitmap_vmem_puttext_locked(int sx, int sy, int ex, int ey, struct vmem_cell *fil
 	int x,y;
 	struct vstat_vmem *vmem_ptr;
 	struct vmem_cell *vc;
+	struct vmem_cell *fi = fill;
 
 	if(!bitmap_initialized)
 		return(0);
@@ -288,10 +288,10 @@ bitmap_vmem_puttext_locked(int sx, int sy, int ex, int ey, struct vmem_cell *fil
 	for(y=sy-1;y<ey;y++) {
 		for(x=sx-1;x<ex;x++) {
 			vc = &vmem_ptr->vmem[y*cio_textinfo.screenwidth+x];
-			memcpy(vc, fill++, sizeof(*fill));
-			bitmap_draw_one_char(vc, x+1, y+1);
+			memcpy(vc, fi++, sizeof(*fi));
 		}
 	}
+	bitmap_draw_vmem(sx, sy, ex, ey, fill);
 	release_vmem(vmem_ptr);
 	return(1);
 }
@@ -497,15 +497,18 @@ static struct rectlist *get_full_rectangle_locked(struct bitmap_screen *screen)
 {
 	struct rectlist *rect;
 	size_t sz = screen->screenwidth * screen->screenheight;
-	size_t pos;
+	size_t pos, spos;
 
 	// TODO: Some sort of caching here would make things faster...?
 	if(callbacks.drawrect) {
 		rect = alloc_full_rect(screen, true);
 		if (!rect)
 			return rect;
-		for (pos = 0; pos < sz; pos++)
-			rect->data[pos] = color_value(screen->rect->data[pos]);
+		for (pos = 0, spos = screen->screenwidth * screen->toprow; pos < sz; pos++, spos++) {
+			if (spos >= sz)
+				spos -= sz;
+			rect->data[pos] = color_value(screen->rect->data[spos]);
+		}
 		return rect;
 	}
 	return NULL;
@@ -522,90 +525,90 @@ static void memset_u32(void *buf, uint32_t u, size_t len)
 	}
 }
 
-// vstatlock must be held
-static int bitmap_draw_one_char(struct vmem_cell *vc, unsigned int xpos, unsigned int ypos)
+/* The read lock must be held here. */
+static int
+pixel_offset(struct bitmap_screen *screen, int x, int y)
 {
-	uint32_t fg;
+	y += screen->toprow;
+	if (y >= screen->screenheight)
+		y -= screen->screenheight;
+	return y * screen->screenwidth + x;
+}
+
+struct charstate {
+	unsigned char *font;
+	uint32_t afc;
+	uint32_t bfc;
 	uint32_t bg;
-	int fdw;
-	int		xoffset;
-	int		yoffset;
-	int		x;
-	int		fdx;
-	uint8_t fb = 0;
-	uint8_t fbb = 0;
-	int		y;
-	int		fontoffset;
-	int		pixeloffset;
-	unsigned char *this_font;
-	WORD	sch;
-	BOOL	draw_fg = TRUE;
-	size_t rsz;
-	bool double_height = false;
-	bool bottom = false;
-	bool top = false;
-	bool not_hidden = true;
+	uint32_t fontoffset;
+	int8_t extra_rows;
+	bool double_height;
+	bool gexpand;
+};
 
-	if(!bitmap_initialized) {
-		return(-1);
-	}
+struct blockstate {
+	int pixeloffset;
+	int maxpix;
+	int font_data_width;
+	uint32_t cheat_colour;
+	bool expand;
+};
 
-	xoffset=(xpos-1)*vstat.charwidth;
-	yoffset=(ypos-1)*vstat.charheight;
-	draw_fg = ((!(vc->legacy_attr & 0x80)) || vstat.no_blink);
-	sch = vc->ch;
-	fg = vc->fg;
-	bg = vc->bg;
+static bool
+can_cheat(struct blockstate *bs, struct vmem_cell *vc)
+{
+	return vc->bg == bs->cheat_colour && (vc->ch == ' ') && (vc->font < CONIO_FIRST_FREE_FONT) && !(vc->bg & 0x02000000);
+}
+
+// Returns false if we can't chate, true otherwise
+static void
+calc_charstate(struct blockstate *bs, struct vmem_cell *vc, struct charstate *cs, int xpos, int ypos)
+{
+	bool not_hidden = true;
 
 	if (vstat.forced_font) {
-		this_font = vstat.forced_font;
+		cs->font = vstat.forced_font;
 	}
 	else {
 		if (current_font[0] == -1)
-			this_font = font[0];
+			cs->font = font[0];
 		else {
 			switch (vstat.charheight) {
 				case 8:
-					this_font = (unsigned char *)conio_fontdata[vc->font].eight_by_eight;
+					cs->font = (unsigned char *)conio_fontdata[vc->font].eight_by_eight;
 					break;
 				case 14:
-					this_font = (unsigned char *)conio_fontdata[vc->font].eight_by_fourteen;
+					cs->font = (unsigned char *)conio_fontdata[vc->font].eight_by_fourteen;
 					break;
 				case 16:
-					this_font = (unsigned char *)conio_fontdata[vc->font].eight_by_sixteen;
+					cs->font = (unsigned char *)conio_fontdata[vc->font].eight_by_sixteen;
 					break;
 				default:
-					return(-1);
+					assert(0);
 			}
 		}
 	}
-	if (this_font == NULL) {
-		this_font = font[0];
-	}
-	if (this_font == NULL)
-		return(-1);
-	fdw = vstat.charwidth - (vstat.flags & VIDMODES_FLAG_EXPAND) ? 1 : 0;
-	fontoffset=(sch) * (vstat.charheight * ((fdw + 7) / 8));
-
-	pthread_mutex_lock(&screenlock);
-
-	if ((xoffset + vstat.charwidth > screena.screenwidth) || (yoffset + vstat.charheight > screena.screenheight) ||
-	    (xoffset + vstat.charwidth > screenb.screenwidth) || (yoffset + vstat.charheight > screenb.screenheight)) {
-		pthread_mutex_unlock(&screenlock);
-		return(-1);
-	}
-
-	if((!screena.rect) || (!screenb.rect)) {
-		pthread_mutex_unlock(&screenlock);
-		return(-1);
+	if (cs->font == NULL) {
+		cs->font = font[0];
 	}
+	assert(cs->font);
+	bool draw_fg = ((!(vc->legacy_attr & 0x80)) || vstat.no_blink);
+	cs->fontoffset = (vc->ch) * (vstat.charheight * ((bs->font_data_width + 7) / 8));
+	cs->double_height = false;
+	if ((vstat.flags & VIDMODES_FLAG_LINE_GRAPHICS_EXPAND) && (vc->ch) >= 0xC0 && (vc->ch) <= 0xDF)
+		cs->gexpand = true;
+	else
+		cs->gexpand = false;
+	uint32_t fg = vc->fg;
+	cs->bg = vc->bg;
+	cs->extra_rows = 0;
 
-	pixeloffset = PIXEL_OFFSET(screena, xoffset, yoffset);
-	rsz = screena.screenwidth - vstat.charwidth;
-	// PRESTEL!
-	if (vstat.mode == PRESTEL_40X24) {
+	if (vstat.mode == PRESTEL_40X24 && (vc->bg & 0x02000000)) {
 		struct vstat_vmem *vmem_ptr = get_vmem(&vstat);
 		unsigned char lattr = vc->legacy_attr;
+		int x, y;
+		bool top = false;
+		bool bottom = false;
 
 		for (y = 0; y < ypos; y++) {
 			if (top) {
@@ -625,29 +628,27 @@ static int bitmap_draw_one_char(struct vmem_cell *vc, unsigned int xpos, unsigne
 		}
 		if (bottom) {
 			if (vmem_ptr->vmem[(ypos - 2) * vstat.cols + (xpos - 1)].bg & 0x01000000) {
-				double_height = true;
+				cs->double_height = true;
+				cs->extra_rows = -(vstat.charheight);
+				cs->fontoffset = (vmem_ptr->vmem[(ypos - 2) * vstat.cols + (xpos - 1)].ch) * (vstat.charheight * ((bs->font_data_width + 7) / 8));
+				// TODO: Update FS etc.
+			}
+			else {
+				// Draw as space if not double-bottom
+				cs->fontoffset=(32) * (vstat.charheight * ((bs->font_data_width + 7) / 8));
 			}
 			fg = vmem_ptr->vmem[(ypos - 2) * vstat.cols + (xpos - 1)].fg;
-			bg = vmem_ptr->vmem[(ypos - 2) * vstat.cols + (xpos - 1)].bg;
+			cs->bg = vmem_ptr->vmem[(ypos - 2) * vstat.cols + (xpos - 1)].bg;
 			lattr = vmem_ptr->vmem[(ypos - 2) * vstat.cols + (xpos - 1)].legacy_attr;
 		}
 		else {
 			if (ypos != vstat.rows) {
 				if (vmem_ptr->vmem[(ypos - 1) * vstat.cols + (xpos - 1)].bg & 0x01000000) {
 					top = true;
-					double_height = true;
+					cs->double_height = true;
 				}
 			}
 		}
-		// Draw as space if not double-bottom
-		if (bottom) {
-			if (double_height) {
-				pixeloffset -= vstat.charheight * vstat.scrnwidth;
-				fontoffset=(vmem_ptr->vmem[(ypos - 2) * vstat.cols + (xpos - 1)].ch) * (vstat.charheight * ((fdw + 7) / 8));
-			}
-			else
-				fontoffset=(32) * (vstat.charheight * ((fdw + 7) / 8));
-		}
 		release_vmem(vmem_ptr);
 		if (lattr & 0x08) {
 			if (!(cio_api.options & CONIO_OPT_PRESTEL_REVEAL)) {
@@ -656,92 +657,207 @@ static int bitmap_draw_one_char(struct vmem_cell *vc, unsigned int xpos, unsigne
 			}
 		}
 	}
-	for (y = 0; y < vstat.charheight; y++) {
-		for(x = 0; x < vstat.charwidth; x++) {
-			fdx = x;
-			fb = this_font[fontoffset];
-			if ((x & 0x07) == 7)
-				fontoffset++;
-			if (vstat.flags & VIDMODES_FLAG_EXPAND) {
-				if (x == vstat.charwidth - 1) {
-					fontoffset--;
-					fdx--;
-					if (!(vstat.flags & VIDMODES_FLAG_LINE_GRAPHICS_EXPAND)) {
-						fb = 0;
-					}
-					else if ((sch) >= 0xC0 && (sch) <= 0xDF) {
-						fb = this_font[fontoffset];
-					}
-					else
-						fb = 0;
+	cs->afc = draw_fg ? fg : cs->bg;
+	cs->bfc = not_hidden ? fg : cs->bg;
+}
 
-				}
-			}
-			fbb = fb & (0x80 >> (fdx & 7));
+static void
+draw_char_row(struct blockstate *bs, struct charstate *cs, uint32_t y)
+{
+	bool fbb;
 
-			if(fbb && draw_fg) {
-				if (screena.rect->data[pixeloffset] != fg) {
-					screena.update_pixels = 1;
-					screena.rect->data[pixeloffset] = fg;
-				}
-				if (double_height) {
-					if (screena.rect->data[pixeloffset+screena.screenwidth] != fg) {
-						screena.update_pixels = 1;
-						screena.rect->data[pixeloffset+screena.screenwidth] = fg;
-					}
-				}
+	uint8_t fb = cs->font[cs->fontoffset];
+	for(unsigned x = 0; x < vstat.charwidth; x++) {
+		if (bs->expand && x == bs->font_data_width) {
+			if (cs->gexpand)
+				fbb = cs->font[cs->fontoffset - 1] & (0x80 >> ((x - 1) & 7));
+			else
+				fbb = 0;
+		}
+		else
+			fbb = fb & (0x80 >> (x & 7));
+
+		if ((x & 0x07) == 7) {
+			cs->fontoffset++;
+			fb = cs->font[cs->fontoffset];
+		}
+
+		uint32_t ac, bc;
+
+		if (fbb) {
+			ac = cs->afc;
+			bc = cs->bfc;
+		}
+		else {
+			ac = cs->bg;
+			bc = cs->bg;
+		}
+
+		if (screena.rect->data[bs->pixeloffset] != ac) {
+			screena.rect->data[bs->pixeloffset] = ac;
+			screena.update_pixels = 1;
+		}
+		if (screenb.rect->data[bs->pixeloffset] != bc) {
+			screenb.rect->data[bs->pixeloffset] = bc;
+			screenb.update_pixels = 1;
+		}
+
+		bs->pixeloffset++;
+		assert(bs->pixeloffset < bs->maxpix || x == (vstat.charwidth - 1));
+	}
+}
+
+static void
+draw_char_row_double(struct blockstate *bs, struct charstate *cs, uint32_t y)
+{
+	bool fbb;
+
+	ssize_t pixeloffset = bs->pixeloffset + (cs->extra_rows * screena.screenwidth);
+	if (pixeloffset >= bs->maxpix)
+		pixeloffset -= bs->maxpix;
+	if (pixeloffset < 0)
+		pixeloffset += bs->maxpix;
+	ssize_t pixeloffset2 = bs->pixeloffset + (cs->extra_rows + 1) * screena.screenwidth;
+	if (pixeloffset2 < 0)
+		pixeloffset2 += bs->maxpix;
+	if (pixeloffset2 >= bs->maxpix)
+		pixeloffset2 -= bs->maxpix;
+
+	uint8_t fb = cs->font[cs->fontoffset];
+	for(unsigned x = 0; x < vstat.charwidth; x++) {
+		if (bs->expand && x == bs->font_data_width) {
+			if (cs->gexpand)
+				fbb = cs->font[cs->fontoffset - 1] & (0x80 >> ((x - 1) & 7));
+			else
+				fbb = 0;
+		}
+		else
+			fbb = fb & (0x80 >> (x & 7));
+
+		if ((x & 0x07) == 7) {
+			cs->fontoffset++;
+			fb = cs->font[cs->fontoffset];
+		}
+
+		uint32_t ac, bc;
+
+		if (fbb) {
+			ac = cs->afc;
+			bc = cs->bfc;
+		}
+		else {
+			ac = cs->bg;
+			bc = cs->bg;
+		}
+
+		if (screena.rect->data[pixeloffset] != ac) {
+			screena.rect->data[pixeloffset] = ac;
+			screena.update_pixels = 1;
+		}
+		if (screenb.rect->data[pixeloffset] != bc) {
+			screenb.rect->data[pixeloffset] = bc;
+			screenb.update_pixels = 1;
+		}
+		pixeloffset++;
+		assert(pixeloffset < bs->maxpix || x == (vstat.charwidth - 1));
+		if (screena.rect->data[pixeloffset2] != ac) {
+			screena.rect->data[pixeloffset2] = ac;
+			screena.update_pixels = 1;
+		}
+		if (screenb.rect->data[pixeloffset2] != bc) {
+			screenb.rect->data[pixeloffset2] = bc;
+			screenb.update_pixels = 1;
+		}
+		pixeloffset2++;
+		assert(pixeloffset2 < bs->maxpix || x == (vstat.charwidth - 1));
+	}
+	cs->extra_rows++;
+	bs->pixeloffset += vstat.charwidth;
+	assert(bs->pixeloffset <= bs->maxpix);
+}
+
+static void
+bitmap_draw_vmem(int sx, int sy, int ex, int ey, struct vmem_cell *fill)
+{
+	struct charstate charstate[255]; // ciolib only supports 255 columns
+	struct blockstate bs;
+	size_t vwidth = ex - sx + 1;
+	size_t vheight  = ey - sy + 1;
+
+	size_t xoffset = (sx-1) * vstat.charwidth;
+	size_t yoffset = (sy-1) * vstat.charheight;
+	assert(xoffset + vstat.charwidth <= screena.screenwidth);
+	assert(xoffset + vstat.charwidth <= screenb.screenwidth);
+	assert(yoffset + vstat.charheight <= screena.screenheight);
+	assert(yoffset + vstat.charheight <= screenb.screenheight);
+	bs.maxpix = screena.screenwidth * screena.screenheight;
+	bs.expand = vstat.flags & VIDMODES_FLAG_EXPAND;
+	bs.font_data_width = vstat.charwidth - (bs.expand ? 1 : 0);
+
+	pthread_mutex_lock(&screenlock);
+	bs.pixeloffset = pixel_offset(&screena, xoffset, yoffset);
+	bs.cheat_colour = fill[0].bg;
+	size_t rsz = screena.screenwidth - vstat.charwidth * vwidth;
+
+	// Fill in charstate for this pass
+	bool cheat = true; // If the whole thing is spaces in compiled in fonts, we can just fill.
+	for (size_t vy = 0; vy < vheight; vy++) {
+		for (size_t vx = 0; vx < vwidth; vx++) {
+			if (!can_cheat(&bs, &fill[vy * vwidth + vx])) {
+				cheat = false;
+				break;
 			}
-			else {
-				if (screena.rect->data[pixeloffset] != bg) {
-					screena.update_pixels = 1;
-					screena.rect->data[pixeloffset] = bg;
-				}
-				if (double_height) {
-					if (screena.rect->data[pixeloffset+screena.screenwidth] != bg) {
-						screena.update_pixels = 1;
-						screena.rect->data[pixeloffset+screena.screenwidth] = bg;
-					}
-				}
+		}
+		if (!cheat)
+			break;
+	}
+	if (cheat) {
+		size_t ylim = vheight * vstat.charheight;
+		size_t xlim = vwidth * vstat.charwidth;
+		for (uint32_t y = 0; y < ylim; y++) {
+			for (size_t vx = 0; vx < xlim; vx++) {
+				screena.rect->data[bs.pixeloffset] = bs.cheat_colour;
+				bs.pixeloffset++;
+				assert(bs.pixeloffset < bs.maxpix || vx == (xlim - 1));
 			}
-
-			if(fbb && not_hidden) {
-				if (screenb.rect->data[pixeloffset] != fg) {
-					screenb.update_pixels = 1;
-					screenb.rect->data[pixeloffset] = fg;
-				}
-				if (double_height) {
-					if (screenb.rect->data[pixeloffset+screena.screenwidth] != fg) {
-						screenb.update_pixels = 1;
-						screenb.rect->data[pixeloffset+screena.screenwidth] = fg;
-					}
-				}
+			bs.pixeloffset += rsz;
+			if (bs.pixeloffset >= bs.maxpix)
+				bs.pixeloffset -= bs.maxpix;
+		}
+		screena.update_pixels = 1;
+		bs.pixeloffset = pixel_offset(&screena, xoffset, yoffset);
+		for (uint32_t y = 0; y < ylim; y++) {
+			for (size_t vx = 0; vx < xlim; vx++) {
+				screenb.rect->data[bs.pixeloffset] = bs.cheat_colour;
+				bs.pixeloffset++;
+				assert(bs.pixeloffset < bs.maxpix || vx == (xlim - 1));
 			}
-			else {
-				if (screenb.rect->data[pixeloffset] != bg) {
-					screenb.update_pixels = 1;
-					screenb.rect->data[pixeloffset] = bg;
-				}
-				if (double_height) {
-					if (screenb.rect->data[pixeloffset+screena.screenwidth] != bg) {
-						screenb.update_pixels = 1;
-						screenb.rect->data[pixeloffset+screena.screenwidth] = bg;
-					}
+			bs.pixeloffset += rsz;
+			if (bs.pixeloffset >= bs.maxpix)
+				bs.pixeloffset -= bs.maxpix;
+		}
+		screenb.update_pixels = 1;
+	}
+	else {
+		for (size_t vy = 0; vy < vheight; vy++) {
+			// Fill in charstate for this pass
+			for (size_t vx = 0; vx < vwidth; vx++)
+				calc_charstate(&bs, &fill[vy * vwidth + vx], &charstate[vx], sx + vx, sy + vy);
+			// Draw the characters...
+			for (uint32_t y = 0; y < vstat.charheight; y++) {
+				for (size_t vx = 0; vx < vwidth; vx++) {
+					if (charstate[vx].double_height)
+						draw_char_row_double(&bs, &charstate[vx], y);
+					else
+						draw_char_row(&bs, &charstate[vx], y);
 				}
+				bs.pixeloffset += rsz;
+				if (bs.pixeloffset >= bs.maxpix)
+					bs.pixeloffset -= bs.maxpix;
 			}
-			pixeloffset++;
 		}
-		if (x & 0x07) {
-			fontoffset++;
-			if (double_height && ((y & 1) == 0))
-				fontoffset--;
-		}
-		pixeloffset += rsz;
-		if (double_height)
-			pixeloffset += screena.screenwidth;
 	}
 	pthread_mutex_unlock(&screenlock);
-
-	return(0);
 }
 
 /***********************************************************/
@@ -954,7 +1070,7 @@ static int update_from_vmem(int force)
 			    || ((vmem_ptr->vmem[pos].legacy_attr & 0x80) && blink_attr_changed)
 			    || ((vmem_ptr->vmem[pos].legacy_attr & 0x08) && bright_attr_changed))	/* Bright char */
 			    {
-				bitmap_draw_one_char(&vmem_ptr->vmem[pos], x+1,y+1);
+				bitmap_draw_vmem(x + 1, y + 1, x + 1, y + 1, &vmem_ptr->vmem[pos]);
 			}
 			pos++;
 		}
@@ -977,7 +1093,9 @@ int bitmap_puttext(int sx, int sy, int ex, int ey, void *fill)
 	int ret = 1;
 	uint16_t *buf = fill;
 	struct vstat_vmem *vmem_ptr;
-	struct vmem_cell *vc;
+
+	if(!bitmap_initialized)
+		return(0);
 
 	if (sx < 1
 	    || sy < 1
@@ -993,12 +1111,14 @@ int bitmap_puttext(int sx, int sy, int ex, int ey, void *fill)
 
 	pthread_mutex_lock(&vstatlock);
 	vmem_ptr = get_vmem(&vstat);
+	struct vmem_cell va[(ex - sx + 1) * (ey - sy + 1)];
+	size_t c = 0;
 	for (y = sy - 1; y < ey; y++) {
 		for (x = sx - 1; x < ex; x++) {
-			vc = set_vmem_cell(vmem_ptr, y * cio_textinfo.screenwidth + x, *(buf++), 0x00ffffff, 0x00ffffff);
-			bitmap_draw_one_char(vc, x+1, y+1);
+			va[c++] = *set_vmem_cell(vmem_ptr, y * cio_textinfo.screenwidth + x, *(buf++), 0x00ffffff, 0x00ffffff);
 		}
 	}
+	bitmap_draw_vmem(sx, sy, ex, ey, va);
 	release_vmem(vmem_ptr);
 	pthread_mutex_unlock(&vstatlock);
 	return ret;
@@ -1252,32 +1372,57 @@ static void
 bitmap_movetext_screen(int x, int y, int tox, int toy, int direction, int height, int width)
 {
 	int32_t sdestoffset;
-	size_t ssourcepos;
+	ssize_t ssourcepos;
 	int step;
 	int32_t screeny;
 
 	pthread_mutex_lock(&screenlock);
-	if (width == cio_textinfo.screenwidth) {
-		ssourcepos =  ((  y - 1) * vstat.scrnwidth * vstat.charheight + (  x - 1) * vstat.charwidth);
-		sdestoffset = ((toy - 1) * vstat.scrnwidth * vstat.charheight + (tox - 1) * vstat.charwidth) - ssourcepos;
-		memmove(&(screena.rect->data[ssourcepos+sdestoffset]), &(screena.rect->data[ssourcepos]), sizeof(screena.rect->data[0])*width*vstat.charwidth*height*vstat.charheight);
-		memmove(&(screenb.rect->data[ssourcepos+sdestoffset]), &(screenb.rect->data[ssourcepos]), sizeof(screenb.rect->data[0])*width*vstat.charwidth*height*vstat.charheight);
+	if (width == cio_textinfo.screenwidth && (height > vstat.rows / 2) && toy == 1) {
+		screena.toprow += (y - toy) * vstat.charheight;
+		if (screena.toprow >= screena.screenheight)
+			screena.toprow -= screena.screenheight;
+		if (screena.toprow < 0)
+			screena.toprow += screena.screenheight;
+		screenb.toprow += (y - toy) * vstat.charheight;
+		if (screenb.toprow >= screenb.screenheight)
+			screenb.toprow -= screenb.screenheight;
+		if (screena.toprow < 0)
+			screena.toprow += screena.screenheight;
+
+		if (direction == -1)
+			direction = 1;
+		else
+			direction = -1;
+		height = vstat.rows - height;
+		int otoy = toy;
+		toy = vstat.rows - (y - toy);
+		y = toy - (y - otoy);
+	}
+
+	int maxpos = screena.screenwidth * screena.screenheight;
+	if (direction == -1) {
+		ssourcepos = ((y + height - 1)      * vstat.charheight - 1) * vstat.scrnwidth + (x -   1) * vstat.charwidth;
+		sdestoffset = ((((toy + height - 1) * vstat.charheight - 1) * vstat.scrnwidth + (tox - 1) * vstat.charwidth) - ssourcepos);
 	}
 	else {
-		if (direction == -1) {
-			ssourcepos=((y + height - 2)      * vstat.charheight - 1) * vstat.scrnwidth + (x -   1) * vstat.charwidth;
-			sdestoffset=((((toy + height - 2) * vstat.charheight - 1) * vstat.scrnwidth + (tox - 1) * vstat.charwidth) - ssourcepos);
-		}
-		else {
-			ssourcepos=(y - 1)     * vstat.scrnwidth * vstat.charheight + (x - 1)  * vstat.charwidth;
-			sdestoffset=(((toy - 1) * vstat.scrnwidth * vstat.charheight + (tox - 1) * vstat.charwidth) - ssourcepos);
-		}
-		step = direction * vstat.scrnwidth;
-		for(screeny=0; screeny < height*vstat.charheight; screeny++) {
-			memmove(&(screena.rect->data[ssourcepos+sdestoffset]), &(screena.rect->data[ssourcepos]), sizeof(screena.rect->data[0])*width*vstat.charwidth);
-			memmove(&(screenb.rect->data[ssourcepos+sdestoffset]), &(screenb.rect->data[ssourcepos]), sizeof(screenb.rect->data[0])*width*vstat.charwidth);
-			ssourcepos += step;
-		}
+		ssourcepos=(y - 1)     * vstat.scrnwidth * vstat.charheight + (x - 1)  * vstat.charwidth;
+		sdestoffset=(((toy - 1) * vstat.scrnwidth * vstat.charheight + (tox - 1) * vstat.charwidth) - ssourcepos);
+	}
+	ssourcepos += screena.toprow * screena.screenwidth;
+	step = direction * vstat.scrnwidth;
+	for(screeny=0; screeny < height*vstat.charheight; screeny++) {
+		if (ssourcepos >= maxpos)
+			ssourcepos -= maxpos;
+		if (ssourcepos < 0)
+			ssourcepos += maxpos;
+		int dest = ssourcepos + sdestoffset;
+		if (dest >= maxpos)
+			dest -= maxpos;
+		if (dest < 0)
+			dest += maxpos;
+		memmove(&(screena.rect->data[dest]), &(screena.rect->data[ssourcepos]), sizeof(screena.rect->data[0])*width*vstat.charwidth);
+		memmove(&(screenb.rect->data[dest]), &(screenb.rect->data[ssourcepos]), sizeof(screenb.rect->data[0])*width*vstat.charwidth);
+		ssourcepos += step;
 	}
 	screena.update_pixels = 1;
 	screenb.update_pixels = 1;
@@ -1353,17 +1498,21 @@ void bitmap_clreol(void)
 	int pos,x;
 	WORD fill=(cio_textinfo.attribute<<8)|' ';
 	struct vstat_vmem *vmem_ptr;
-	struct vmem_cell *vc;
 	int row;
 
+	if(!bitmap_initialized)
+		return;
+
 	row = cio_textinfo.cury + cio_textinfo.wintop - 1;
 	pos=(row - 1)*cio_textinfo.screenwidth;
 	pthread_mutex_lock(&vstatlock);
 	vmem_ptr = get_vmem(&vstat);
+	struct vmem_cell va[cio_textinfo.winright - (cio_textinfo.curx + cio_textinfo.winleft - 1) + 1];
+	int c = 0;
 	for(x=cio_textinfo.curx+cio_textinfo.winleft-2; x<cio_textinfo.winright; x++) {
-		vc = set_vmem_cell(vmem_ptr, pos+x, fill, ciolib_fg, ciolib_bg);
-		bitmap_draw_one_char(vc, x+1, row);
+		va[c++] = *set_vmem_cell(vmem_ptr, pos+x, fill, ciolib_fg, ciolib_bg);
 	}
+	bitmap_draw_vmem(cio_textinfo.curx + cio_textinfo.winleft - 1, row, cio_textinfo.winright, row, va);
 	release_vmem(vmem_ptr);
 	pthread_mutex_unlock(&vstatlock);
 }
@@ -1373,19 +1522,23 @@ void bitmap_clrscr(void)
 	size_t x, y;
 	WORD fill = (cio_textinfo.attribute << 8) | ' ';
 	struct vstat_vmem *vmem_ptr;
-	struct vmem_cell *vc;
+	struct vmem_cell va[(cio_textinfo.winright - cio_textinfo.winleft + 1) * (cio_textinfo.winbottom - cio_textinfo.wintop + 1)];
+	size_t c = 0;
 	int rows, cols;
 
+	if(!bitmap_initialized)
+		return;
+
 	pthread_mutex_lock(&vstatlock);
 	vmem_ptr = get_vmem(&vstat);
 	rows = vstat.rows;
 	cols = vstat.cols;
 	for (y = cio_textinfo.wintop - 1; y < cio_textinfo.winbottom && y < rows; y++) {
 		for (x = cio_textinfo.winleft - 1; x < cio_textinfo.winright && x < cols; x++) {
-			vc = set_vmem_cell(vmem_ptr, y * cio_textinfo.screenwidth + x, fill, ciolib_fg, ciolib_bg);
-			bitmap_draw_one_char(vc, x+1, y+1);
+			va[c++] = *set_vmem_cell(vmem_ptr, y * cio_textinfo.screenwidth + x, fill, ciolib_fg, ciolib_bg);
 		}
 	}
+	bitmap_draw_vmem(cio_textinfo.winleft, cio_textinfo.wintop, cio_textinfo.winright, cio_textinfo.winbottom, va);
 	release_vmem(vmem_ptr);
 	pthread_mutex_unlock(&vstatlock);
 }
@@ -1491,16 +1644,16 @@ int bitmap_setpixel(uint32_t x, uint32_t y, uint32_t colour)
 {
 	pthread_mutex_lock(&screenlock);
 	if (x < screena.screenwidth && y < screena.screenheight) {
-		if (screena.rect->data[PIXEL_OFFSET(screena, x, y)] != colour) {
+		if (screena.rect->data[pixel_offset(&screena, x, y)] != colour) {
 			screena.update_pixels = 1;
-			screena.rect->data[PIXEL_OFFSET(screena, x, y)] = colour;
+			screena.rect->data[pixel_offset(&screena, x, y)] = colour;
 		}
 	}
 
 	if (x < screenb.screenwidth && y < screenb.screenheight) {
-		if (screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] != colour) {
+		if (screenb.rect->data[pixel_offset(&screenb, x, y)] != colour) {
 			screenb.update_pixels = 1;
-			screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] = colour;
+			screenb.rect->data[pixel_offset(&screenb, x, y)] = colour;
 		}
 	}
 	pthread_mutex_unlock(&screenlock);
@@ -1549,19 +1702,19 @@ int bitmap_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_
 		pos = pixels->width*(y-sy+y_off)+x_off;
 		if (mask == NULL) {
 			for (x = sx; x <= ex; x++) {
-				if (screena.rect->data[PIXEL_OFFSET(screena, x, y)] != pixels->pixels[pos]) {
-					screena.rect->data[PIXEL_OFFSET(screena, x, y)] = pixels->pixels[pos];
+				if (screena.rect->data[pixel_offset(&screena, x, y)] != pixels->pixels[pos]) {
+					screena.rect->data[pixel_offset(&screena, x, y)] = pixels->pixels[pos];
 					screena.update_pixels = 1;
 				}
 				if (pixels->pixelsb) {
-					if (screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] != pixels->pixelsb[pos]) {
-						screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] = pixels->pixelsb[pos];
+					if (screenb.rect->data[pixel_offset(&screenb, x, y)] != pixels->pixelsb[pos]) {
+						screenb.rect->data[pixel_offset(&screenb, x, y)] = pixels->pixelsb[pos];
 						screenb.update_pixels = 1;
 					}
 				}
 				else {
-					if (screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] != pixels->pixels[pos]) {
-						screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] = pixels->pixels[pos];
+					if (screenb.rect->data[pixel_offset(&screenb, x, y)] != pixels->pixels[pos]) {
+						screenb.rect->data[pixel_offset(&screenb, x, y)] = pixels->pixels[pos];
 						screenb.update_pixels = 1;
 					}
 				}
@@ -1575,19 +1728,19 @@ int bitmap_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_
 				mask_bit = mpos % 8;
 				mask_bit = 0x80 >> mask_bit;
 				if (mask->bits[mask_byte] & mask_bit) {
-					if (screena.rect->data[PIXEL_OFFSET(screena, x, y)] != pixels->pixels[pos]) {
-						screena.rect->data[PIXEL_OFFSET(screena, x, y)] = pixels->pixels[pos];
+					if (screena.rect->data[pixel_offset(&screena, x, y)] != pixels->pixels[pos]) {
+						screena.rect->data[pixel_offset(&screena, x, y)] = pixels->pixels[pos];
 						screena.update_pixels = 1;
 					}
 					if (pixels->pixelsb) {
-						if (screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] != pixels->pixelsb[pos]) {
-							screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] = pixels->pixelsb[pos];
+						if (screenb.rect->data[pixel_offset(&screenb, x, y)] != pixels->pixelsb[pos]) {
+							screenb.rect->data[pixel_offset(&screenb, x, y)] = pixels->pixelsb[pos];
 							screenb.update_pixels = 1;
 						}
 					}
 					else {
-						if (screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] != pixels->pixels[pos]) {
-							screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] = pixels->pixels[pos];
+						if (screenb.rect->data[pixel_offset(&screenb, x, y)] != pixels->pixels[pos]) {
+							screenb.rect->data[pixel_offset(&screenb, x, y)] = pixels->pixels[pos];
 							screenb.update_pixels = 1;
 						}
 					}
@@ -1648,8 +1801,8 @@ struct ciolib_pixels *bitmap_getpixels(uint32_t sx, uint32_t sy, uint32_t ex, ui
 
 	for (y = sy; y <= ey; y++) {
 		// TODO: This is the place where screen vs. buffer matters. :(
-		memcpy(&pixels->pixels[width*(y-sy)], &screena.rect->data[PIXEL_OFFSET(screena, sx, y)], width * sizeof(pixels->pixels[0]));
-		memcpy(&pixels->pixelsb[width*(y-sy)], &screenb.rect->data[PIXEL_OFFSET(screenb, sx, y)], width * sizeof(pixels->pixelsb[0]));
+		memcpy(&pixels->pixels[width*(y-sy)], &screena.rect->data[pixel_offset(&screena, sx, y)], width * sizeof(pixels->pixels[0]));
+		memcpy(&pixels->pixelsb[width*(y-sy)], &screenb.rect->data[pixel_offset(&screenb, sx, y)], width * sizeof(pixels->pixelsb[0]));
 	}
 	pthread_mutex_unlock(&screenlock);
 
diff --git a/src/conio/cterm.c b/src/conio/cterm.c
index 590b3f03b2dfad2cb0af4e0028660d8e123f794c..54142b92abf96c5720d5b0f7dd3ec7b4aaac2e34 100644
--- a/src/conio/cterm.c
+++ b/src/conio/cterm.c
@@ -799,6 +799,7 @@ set_attr(struct cterminal *cterm, unsigned char colour, bool bg)
 	if (cterm->emulation == CTERM_EMULATION_PRESTEL) {
 		if (cterm->extattr & CTERM_EXTATTR_PRESTEL_DOUBLE_HEIGHT)
 			cterm->bg_color |= 0x01000000;
+		cterm->bg_color |= 0x02000000;
 	}
 	if (bg)
 		FREE_AND_NULL(cterm->bg_tc_str);
@@ -824,6 +825,7 @@ prestel_new_line(struct cterminal *cterm)
 	cterm->extattr &= ~(CTERM_EXTATTR_PRESTEL_CONCEAL | CTERM_EXTATTR_PRESTEL_DOUBLE_HEIGHT | CTERM_EXTATTR_PRESTEL_HOLD | CTERM_EXTATTR_PRESTEL_MOSAIC | CTERM_EXTATTR_PRESTEL_SEPARATED);
 	cterm->attr = 7;
 	attr2palette(cterm->attr, &cterm->fg_color, &cterm->bg_color);
+	cterm->bg_color |= 0x02000000;
 	cterm->prestel_last_mosaic = 0;
 	TEXTATTR(cterm->attr);
 	setcolour(cterm->fg_color, cterm->bg_color);
@@ -869,6 +871,7 @@ prestel_apply_ctrl_before(struct cterminal *cterm, uint8_t ch)
 			cterm->extattr |= CTERM_EXTATTR_PRESTEL_HOLD;
 			break;
 	}
+	cterm->bg_color |= 0x02000000;
 }
 
 static void
@@ -950,6 +953,7 @@ prestel_apply_ctrl_after(struct cterminal *cterm, uint8_t ch)
 			cterm->extattr &= ~(CTERM_EXTATTR_PRESTEL_HOLD);
 			break;
 	}
+	cterm->bg_color |= 0x02000000;
 }
 
 static void