Index: uspace/lib/congfx/src/console.c
===================================================================
--- uspace/lib/congfx/src/console.c	(revision 0d62c10a4e92097fe235df71e74a4c547e7e9d71)
+++ uspace/lib/congfx/src/console.c	(revision bb14312c8c42ea170b99a8d6db9a607a3b2aba04)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2019 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * All rights reserved.
  *
@@ -48,6 +48,8 @@
 #include "../private/color.h"
 
+static errno_t console_gc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t console_gc_set_color(void *, gfx_color_t *);
 static errno_t console_gc_fill_rect(void *, gfx_rect_t *);
+static errno_t console_gc_update(void *);
 static errno_t console_gc_bitmap_create(void *, gfx_bitmap_params_t *,
     gfx_bitmap_alloc_t *, void **);
@@ -55,14 +57,41 @@
 static errno_t console_gc_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
 static errno_t console_gc_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
+static errno_t console_gc_cursor_get_pos(void *, gfx_coord2_t *);
+static errno_t console_gc_cursor_set_pos(void *, gfx_coord2_t *);
+static errno_t console_gc_cursor_set_visible(void *, bool);
 
 gfx_context_ops_t console_gc_ops = {
+	.set_clip_rect = console_gc_set_clip_rect,
 	.set_color = console_gc_set_color,
 	.fill_rect = console_gc_fill_rect,
+	.update = console_gc_update,
 	.bitmap_create = console_gc_bitmap_create,
 	.bitmap_destroy = console_gc_bitmap_destroy,
 	.bitmap_render = console_gc_bitmap_render,
-	.bitmap_get_alloc = console_gc_bitmap_get_alloc
+	.bitmap_get_alloc = console_gc_bitmap_get_alloc,
+	.cursor_get_pos = console_gc_cursor_get_pos,
+	.cursor_set_pos = console_gc_cursor_set_pos,
+	.cursor_set_visible = console_gc_cursor_set_visible
 };
 
+/** Set clipping rectangle on console GC.
+ *
+ * @param arg Console GC
+ * @param rect Rectangle
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t console_gc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	console_gc_t *cgc = (console_gc_t *) arg;
+
+	if (rect != NULL)
+		gfx_rect_clip(rect, &cgc->rect, &cgc->clip_rect);
+	else
+		cgc->clip_rect = cgc->rect;
+
+	return EOK;
+}
+
 /** Set color on console GC.
  *
@@ -92,23 +121,48 @@
 {
 	console_gc_t *cgc = (console_gc_t *) arg;
-	int rv;
 	gfx_coord_t x, y;
-
-	// XXX We should handle p0.x > p1.x and p0.y > p1.y
-
-	console_set_rgb_color(cgc->con, cgc->clr, cgc->clr);
-
-	for (y = rect->p0.y; y < rect->p1.y; y++) {
-		console_set_pos(cgc->con, rect->p0.x, y);
-
-		for (x = rect->p0.x; x < rect->p1.x; x++) {
-			rv = fputc('X', cgc->fout);
-			if (rv < 0)
-				return EIO;
+	gfx_coord_t cols;
+	gfx_rect_t crect;
+	charfield_t ch;
+
+	/* Make sure rectangle is clipped and sorted */
+	gfx_rect_clip(rect, &cgc->clip_rect, &crect);
+
+	cols = cgc->rect.p1.x - cgc->rect.p0.x;
+
+	ch.ch = cgc->clr >> 24;
+	ch.flags = CHAR_FLAG_DIRTY;
+	ch.attrs.type = CHAR_ATTR_RGB;
+	ch.attrs.val.rgb.fgcolor = cgc->clr ^ 0xffffff;
+	ch.attrs.val.rgb.bgcolor = cgc->clr;
+
+	for (y = crect.p0.y; y < crect.p1.y; y++) {
+		for (x = crect.p0.x; x < crect.p1.x; x++) {
+			cgc->buf[y * cols + x] = ch;
 		}
-
-		console_flush(cgc->con);
 	}
 
+	console_update(cgc->con, crect.p0.x, crect.p0.y,
+	    crect.p1.x, crect.p1.y);
+
+	return EOK;
+}
+
+/** Update console GC.
+ *
+ * @param arg Console GC
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t console_gc_update(void *arg)
+{
+	console_gc_t *cgc = (console_gc_t *) arg;
+
+	/*
+	 * XXX Before actually deferring update to here (and similarly other
+	 * GC implementations) need to make sure all consumers properly
+	 * call update.
+	 */
+	(void) cgc;
 	return EOK;
 }
@@ -131,4 +185,5 @@
 	sysarg_t rows;
 	sysarg_t cols;
+	charfield_t *buf = NULL;
 	errno_t rc;
 
@@ -140,4 +195,10 @@
 
 	rc = console_get_size(con, &cols, &rows);
+	if (rc != EOK)
+		goto error;
+
+	console_clear(con);
+
+	rc = console_map(con, cols, rows, &buf);
 	if (rc != EOK)
 		goto error;
@@ -153,9 +214,13 @@
 	cgc->rect.p0.y = 0;
 	cgc->rect.p1.x = cols;
-	cgc->rect.p1.y = rows - 1; /* make sure we avoid bottom-right corner */
+	cgc->rect.p1.y = rows;
+	cgc->clip_rect = cgc->rect;
+	cgc->buf = buf;
 
 	*rgc = cgc;
 	return EOK;
 error:
+	if (buf != NULL)
+		console_unmap(cgc->con, buf);
 	if (cgc != NULL)
 		free(cgc);
@@ -175,4 +240,7 @@
 	if (rc != EOK)
 		return rc;
+
+	console_clear(cgc->con);
+	console_unmap(cgc->con, cgc->buf);
 
 	free(cgc);
@@ -268,6 +336,6 @@
 	console_gc_bitmap_t *cbm = (console_gc_bitmap_t *)bm;
 	gfx_coord_t x, y;
-	int rv;
 	pixel_t clr;
+	charfield_t ch;
 	pixelmap_t pixelmap;
 	gfx_rect_t srect;
@@ -275,4 +343,5 @@
 	gfx_rect_t crect;
 	gfx_coord2_t offs;
+	gfx_coord_t cols;
 
 	if (srect0 != NULL)
@@ -289,5 +358,5 @@
 
 	gfx_rect_translate(&offs, &srect, &drect);
-	gfx_rect_clip(&drect, &cbm->cgc->rect, &crect);
+	gfx_rect_clip(&drect, &cbm->cgc->clip_rect, &crect);
 
 	pixelmap.width = cbm->rect.p1.x - cbm->rect.p0.x;
@@ -295,20 +364,21 @@
 	pixelmap.data = cbm->alloc.pixels;
 
+	cols = cbm->cgc->rect.p1.x - cbm->cgc->rect.p0.x;
+
 	if ((cbm->flags & bmpf_color_key) == 0) {
 		/* Simple copy */
 		for (y = crect.p0.y; y < crect.p1.y; y++) {
-			console_set_pos(cbm->cgc->con, crect.p0.x, y);
-
 			for (x = crect.p0.x; x < crect.p1.x; x++) {
 				clr = pixelmap_get_pixel(&pixelmap,
 				    x - offs.x - cbm->rect.p0.x,
 				    y - offs.y - cbm->rect.p0.y);
-				console_set_rgb_color(cbm->cgc->con, clr, clr);
-
-				rv = fputc('X', cbm->cgc->fout);
-				if (rv < 0)
-					return EIO;
-
-				console_flush(cbm->cgc->con);
+
+				ch.ch = clr >> 24;
+				ch.flags = CHAR_FLAG_DIRTY;
+				ch.attrs.type = CHAR_ATTR_RGB;
+				ch.attrs.val.rgb.fgcolor = clr ^ 0xffffff;
+				ch.attrs.val.rgb.bgcolor = clr;
+
+				cbm->cgc->buf[y * cols + x] = ch;
 			}
 		}
@@ -321,42 +391,38 @@
 				    x - offs.x - cbm->rect.p0.x,
 				    y - offs.y - cbm->rect.p0.y);
-				console_set_rgb_color(cbm->cgc->con, clr, clr);
-
-				if (clr != cbm->key_color) {
-					console_set_pos(cbm->cgc->con, x, y);
-					rv = fputc('X', cbm->cgc->fout);
-					if (rv < 0)
-						return EIO;
-
-					console_flush(cbm->cgc->con);
-				}
-
+
+				ch.ch = clr >> 24;
+				ch.flags = CHAR_FLAG_DIRTY;
+				ch.attrs.type = CHAR_ATTR_RGB;
+				ch.attrs.val.rgb.fgcolor = clr ^ 0xffffff;
+				ch.attrs.val.rgb.bgcolor = clr;
+
+				if (clr != cbm->key_color)
+					cbm->cgc->buf[y * cols + x] = ch;
 			}
 		}
 	} else {
 		/* Color key & colorize */
-		console_set_rgb_color(cbm->cgc->con, cbm->cgc->clr,
-		    cbm->cgc->clr);
+		ch.ch = 0;
+		ch.flags = CHAR_FLAG_DIRTY;
+		ch.attrs.type = CHAR_ATTR_RGB;
+		ch.attrs.val.rgb.fgcolor = cbm->cgc->clr;
+		ch.attrs.val.rgb.bgcolor = cbm->cgc->clr;
 
 		for (y = crect.p0.y; y < crect.p1.y; y++) {
 			for (x = crect.p0.x; x < crect.p1.x; x++) {
-
 				clr = pixelmap_get_pixel(&pixelmap,
 				    x - offs.x - cbm->rect.p0.x,
 				    y - offs.y - cbm->rect.p0.y);
 
-				if (clr != cbm->key_color) {
-					console_set_pos(cbm->cgc->con, x, y);
-					rv = fputc('X', cbm->cgc->fout);
-					if (rv < 0)
-						return EIO;
-
-					console_flush(cbm->cgc->con);
-				}
-
+				if (clr != cbm->key_color)
+					cbm->cgc->buf[y * cols + x] = ch;
 			}
 		}
 	}
 
+	console_update(cbm->cgc->con, crect.p0.x, crect.p0.y, crect.p1.x,
+	    crect.p1.y);
+
 	return EOK;
 }
@@ -375,4 +441,57 @@
 }
 
+/** Get cursor position on console GC.
+ *
+ * @param arg Console GC
+ * @param pos Place to store position
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t console_gc_cursor_get_pos(void *arg, gfx_coord2_t *pos)
+{
+	console_gc_t *cgc = (console_gc_t *) arg;
+	sysarg_t col;
+	sysarg_t row;
+	errno_t rc;
+
+	rc = console_get_pos(cgc->con, &col, &row);
+	if (rc != EOK)
+		return rc;
+
+	pos->x = col;
+	pos->y = row;
+	return EOK;
+}
+
+/** Set cursor position on console GC.
+ *
+ * @param arg Console GC
+ * @param pos New cursor position
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t console_gc_cursor_set_pos(void *arg, gfx_coord2_t *pos)
+{
+	console_gc_t *cgc = (console_gc_t *) arg;
+
+	console_set_pos(cgc->con, pos->x, pos->y);
+	return EOK;
+}
+
+/** Set cursor visibility on console GC.
+ *
+ * @param arg Console GC
+ * @param visible @c true iff cursor should be made visible
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t console_gc_cursor_set_visible(void *arg, bool visible)
+{
+	console_gc_t *cgc = (console_gc_t *) arg;
+
+	console_cursor_visibility(cgc->con, visible);
+	return EOK;
+}
+
 /** @}
  */
