Index: uspace/lib/memgfx/include/memgfx/memgc.h
===================================================================
--- uspace/lib/memgfx/include/memgfx/memgc.h	(revision 0d62c10a4e92097fe235df71e74a4c547e7e9d71)
+++ uspace/lib/memgfx/include/memgfx/memgc.h	(revision 9c7dc8e93da9abc90efb24bba56e275432050f20)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * All rights reserved.
  *
@@ -46,5 +46,5 @@
 
 extern errno_t mem_gc_create(gfx_rect_t *, gfx_bitmap_alloc_t *,
-    mem_gc_update_cb_t, void *, mem_gc_t **);
+    mem_gc_invalidate_cb_t, mem_gc_update_cb_t, void *, mem_gc_t **);
 extern errno_t mem_gc_delete(mem_gc_t *);
 extern void mem_gc_retarget(mem_gc_t *, gfx_rect_t *, gfx_bitmap_alloc_t *);
Index: uspace/lib/memgfx/include/types/memgfx/memgc.h
===================================================================
--- uspace/lib/memgfx/include/types/memgfx/memgc.h	(revision 0d62c10a4e92097fe235df71e74a4c547e7e9d71)
+++ uspace/lib/memgfx/include/types/memgfx/memgc.h	(revision 9c7dc8e93da9abc90efb24bba56e275432050f20)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * All rights reserved.
  *
@@ -42,5 +42,6 @@
 typedef struct mem_gc mem_gc_t;
 
-typedef void (*mem_gc_update_cb_t)(void *, gfx_rect_t *);
+typedef void (*mem_gc_invalidate_cb_t)(void *, gfx_rect_t *);
+typedef void (*mem_gc_update_cb_t)(void *);
 
 #endif
Index: uspace/lib/memgfx/private/memgc.h
===================================================================
--- uspace/lib/memgfx/private/memgc.h	(revision 0d62c10a4e92097fe235df71e74a4c547e7e9d71)
+++ uspace/lib/memgfx/private/memgc.h	(revision 9c7dc8e93da9abc90efb24bba56e275432050f20)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * All rights reserved.
  *
@@ -51,4 +51,6 @@
 	/** Allocation info */
 	gfx_bitmap_alloc_t alloc;
+	/** Invalidate callback */
+	mem_gc_invalidate_cb_t invalidate;
 	/** Update callback */
 	mem_gc_update_cb_t update;
Index: uspace/lib/memgfx/src/memgc.c
===================================================================
--- uspace/lib/memgfx/src/memgc.c	(revision 0d62c10a4e92097fe235df71e74a4c547e7e9d71)
+++ uspace/lib/memgfx/src/memgc.c	(revision 9c7dc8e93da9abc90efb24bba56e275432050f20)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * All rights reserved.
  *
@@ -50,4 +50,5 @@
 static errno_t mem_gc_set_color(void *, gfx_color_t *);
 static errno_t mem_gc_fill_rect(void *, gfx_rect_t *);
+static errno_t mem_gc_update(void *);
 static errno_t mem_gc_bitmap_create(void *, gfx_bitmap_params_t *,
     gfx_bitmap_alloc_t *, void **);
@@ -60,4 +61,5 @@
 	.set_color = mem_gc_set_color,
 	.fill_rect = mem_gc_fill_rect,
+	.update = mem_gc_update,
 	.bitmap_create = mem_gc_bitmap_create,
 	.bitmap_destroy = mem_gc_bitmap_destroy,
@@ -119,4 +121,18 @@
 }
 
+/** Update memory GC.
+ *
+ * @param arg Memory GC
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t mem_gc_update(void *arg)
+{
+	mem_gc_t *mgc = (mem_gc_t *) arg;
+
+	mgc->update(mgc->cb_arg);
+	return EOK;
+}
+
 /** Create memory GC.
  *
@@ -132,5 +148,6 @@
  */
 errno_t mem_gc_create(gfx_rect_t *rect, gfx_bitmap_alloc_t *alloc,
-    mem_gc_update_cb_t update_cb, void *cb_arg, mem_gc_t **rgc)
+    mem_gc_invalidate_cb_t invalidate_cb, mem_gc_update_cb_t update_cb,
+    void *cb_arg, mem_gc_t **rgc)
 {
 	mem_gc_t *mgc = NULL;
@@ -152,4 +169,5 @@
 	mgc->alloc = *alloc;
 
+	mgc->invalidate = invalidate_cb;
 	mgc->update = update_cb;
 	mgc->cb_arg = cb_arg;
@@ -205,5 +223,5 @@
 static void mem_gc_invalidate_rect(mem_gc_t *mgc, gfx_rect_t *rect)
 {
-	mgc->update(mgc->cb_arg, rect);
+	mgc->invalidate(mgc->cb_arg, rect);
 }
 
Index: uspace/lib/memgfx/test/memgfx.c
===================================================================
--- uspace/lib/memgfx/test/memgfx.c	(revision 0d62c10a4e92097fe235df71e74a4c547e7e9d71)
+++ uspace/lib/memgfx/test/memgfx.c	(revision 9c7dc8e93da9abc90efb24bba56e275432050f20)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * All rights reserved.
  *
@@ -42,12 +42,15 @@
 PCUT_TEST_SUITE(memgfx);
 
-static void test_update_rect(void *arg, gfx_rect_t *rect);
+static void test_invalidate_rect(void *arg, gfx_rect_t *rect);
+static void test_update(void *arg);
 
 typedef struct {
+	/** True if invalidate was called */
+	bool invalidate_called;
+	/** Invalidate rectangle */
+	gfx_rect_t inv_rect;
 	/** True if update was called */
 	bool update_called;
-	/** Update rectangle */
-	gfx_rect_t rect;
-} test_update_t;
+} test_resp_t;
 
 /** Test creating and deleting a memory GC */
@@ -69,5 +72,5 @@
 	PCUT_ASSERT_NOT_NULL(alloc.pixels);
 
-	rc = mem_gc_create(&rect, &alloc, NULL, NULL, &mgc);
+	rc = mem_gc_create(&rect, &alloc, NULL, NULL, NULL, &mgc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -89,5 +92,5 @@
 	pixel_t pixel;
 	pixel_t expected;
-	test_update_t update;
+	test_resp_t resp;
 	errno_t rc;
 
@@ -103,5 +106,6 @@
 	PCUT_ASSERT_NOT_NULL(alloc.pixels);
 
-	rc = mem_gc_create(&rect, &alloc, test_update_rect, &update, &mgc);
+	rc = mem_gc_create(&rect, &alloc, test_invalidate_rect,
+	    test_update, &resp, &mgc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -122,5 +126,5 @@
 	frect.p1.y = 5;
 
-	memset(&update, 0, sizeof(update));
+	memset(&resp, 0, sizeof(resp));
 
 	rc = gfx_fill_rect(gc, &frect);
@@ -141,10 +145,10 @@
 	}
 
-	/* Check that the update rect is equal to the filled rect */
-	PCUT_ASSERT_TRUE(update.update_called);
-	PCUT_ASSERT_INT_EQUALS(frect.p0.x, update.rect.p0.x);
-	PCUT_ASSERT_INT_EQUALS(frect.p0.y, update.rect.p0.y);
-	PCUT_ASSERT_INT_EQUALS(frect.p1.x, update.rect.p1.x);
-	PCUT_ASSERT_INT_EQUALS(frect.p1.y, update.rect.p1.y);
+	/* Check that the invalidate rect is equal to the filled rect */
+	PCUT_ASSERT_TRUE(resp.invalidate_called);
+	PCUT_ASSERT_INT_EQUALS(frect.p0.x, resp.inv_rect.p0.x);
+	PCUT_ASSERT_INT_EQUALS(frect.p0.y, resp.inv_rect.p0.y);
+	PCUT_ASSERT_INT_EQUALS(frect.p1.x, resp.inv_rect.p1.x);
+	PCUT_ASSERT_INT_EQUALS(frect.p1.y, resp.inv_rect.p1.y);
 
 	/* TODO: Check clipping once memgc can support pitch != width etc. */
@@ -169,5 +173,5 @@
 	pixel_t pixel;
 	pixel_t expected;
-	test_update_t update;
+	test_resp_t resp;
 	errno_t rc;
 
@@ -183,5 +187,6 @@
 	PCUT_ASSERT_NOT_NULL(alloc.pixels);
 
-	rc = mem_gc_create(&rect, &alloc, test_update_rect, &update, &mgc);
+	rc = mem_gc_create(&rect, &alloc, test_invalidate_rect,
+	    test_update, &resp, &mgc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -191,4 +196,5 @@
 	/* Create bitmap */
 
+	gfx_bitmap_params_init(&params);
 	params.rect.p0.x = 0;
 	params.rect.p0.y = 0;
@@ -219,5 +225,5 @@
 	dpmap.data = alloc.pixels;
 
-	memset(&update, 0, sizeof(update));
+	memset(&resp, 0, sizeof(resp));
 
 	/* Render the bitmap */
@@ -237,10 +243,10 @@
 	}
 
-	/* Check that the update rect is equal to the filled rect */
-	PCUT_ASSERT_TRUE(update.update_called);
-	PCUT_ASSERT_INT_EQUALS(params.rect.p0.x, update.rect.p0.x);
-	PCUT_ASSERT_INT_EQUALS(params.rect.p0.y, update.rect.p0.y);
-	PCUT_ASSERT_INT_EQUALS(params.rect.p1.x, update.rect.p1.x);
-	PCUT_ASSERT_INT_EQUALS(params.rect.p1.y, update.rect.p1.y);
+	/* Check that the invalidate rect is equal to the filled rect */
+	PCUT_ASSERT_TRUE(resp.invalidate_called);
+	PCUT_ASSERT_INT_EQUALS(params.rect.p0.x, resp.inv_rect.p0.x);
+	PCUT_ASSERT_INT_EQUALS(params.rect.p0.y, resp.inv_rect.p0.y);
+	PCUT_ASSERT_INT_EQUALS(params.rect.p1.x, resp.inv_rect.p1.x);
+	PCUT_ASSERT_INT_EQUALS(params.rect.p1.y, resp.inv_rect.p1.y);
 
 	/* TODO: Check clipping once memgc can support pitch != width etc. */
@@ -250,11 +256,57 @@
 }
 
-/** Called by memory GC when a rectangle is updated. */
-static void test_update_rect(void *arg, gfx_rect_t *rect)
-{
-	test_update_t *update = (test_update_t *)arg;
-
-	update->update_called = true;
-	update->rect = *rect;
+/** Test gfx_update() on a memory GC */
+PCUT_TEST(gfx_update)
+{
+	mem_gc_t *mgc;
+	gfx_rect_t rect;
+	gfx_bitmap_alloc_t alloc;
+	gfx_context_t *gc;
+	test_resp_t resp;
+	errno_t rc;
+
+	/* Bounding rectangle for memory GC */
+	rect.p0.x = 0;
+	rect.p0.y = 0;
+	rect.p1.x = 10;
+	rect.p1.y = 10;
+
+	alloc.pitch = (rect.p1.x - rect.p0.x) * sizeof(uint32_t);
+	alloc.off0 = 0;
+	alloc.pixels = calloc(1, alloc.pitch * (rect.p1.y - rect.p0.y));
+	PCUT_ASSERT_NOT_NULL(alloc.pixels);
+
+	rc = mem_gc_create(&rect, &alloc, test_invalidate_rect,
+	    test_update, &resp, &mgc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	gc = mem_gc_get_ctx(mgc);
+	PCUT_ASSERT_NOT_NULL(gc);
+
+	memset(&resp, 0, sizeof(resp));
+	PCUT_ASSERT_FALSE(resp.update_called);
+
+	gfx_update(gc);
+	PCUT_ASSERT_TRUE(resp.update_called);
+
+	mem_gc_delete(mgc);
+	free(alloc.pixels);
+}
+
+/** Called by memory GC when a rectangle is modified. */
+static void test_invalidate_rect(void *arg, gfx_rect_t *rect)
+{
+	test_resp_t *resp = (test_resp_t *)arg;
+
+	resp->invalidate_called = true;
+	resp->inv_rect = *rect;
+}
+
+/** Called by memory GC when update is called. */
+static void test_update(void *arg)
+{
+	test_resp_t *resp = (test_resp_t *)arg;
+
+	resp->update_called = true;
 }
 
