Index: uspace/lib/memgfx/include/memgfx/memgc.h
===================================================================
--- uspace/lib/memgfx/include/memgfx/memgc.h	(revision bb14312c8c42ea170b99a8d6db9a607a3b2aba04)
+++ uspace/lib/memgfx/include/memgfx/memgc.h	(revision 1215db9d1ade6fae2cbc2685459e7ecd9b62efef)
@@ -46,5 +46,5 @@
 
 extern errno_t mem_gc_create(gfx_rect_t *, gfx_bitmap_alloc_t *,
-    mem_gc_invalidate_cb_t, mem_gc_update_cb_t, void *, mem_gc_t **);
+    mem_gc_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 bb14312c8c42ea170b99a8d6db9a607a3b2aba04)
+++ uspace/lib/memgfx/include/types/memgfx/memgc.h	(revision 1215db9d1ade6fae2cbc2685459e7ecd9b62efef)
@@ -37,4 +37,6 @@
 #define _MEMGFX_TYPES_MEMGC_H
 
+#include <errno.h>
+#include <stdbool.h>
 #include <types/gfx/coord.h>
 
@@ -42,6 +44,16 @@
 typedef struct mem_gc mem_gc_t;
 
-typedef void (*mem_gc_invalidate_cb_t)(void *, gfx_rect_t *);
-typedef void (*mem_gc_update_cb_t)(void *);
+typedef struct {
+	/** Invalidate rectangle */
+	void (*invalidate)(void *, gfx_rect_t *);
+	/** Update display */
+	void (*update)(void *);
+	/** Get cursor position */
+	errno_t (*cursor_get_pos)(void *, gfx_coord2_t *);
+	/** Set cursor position */
+	errno_t (*cursor_set_pos)(void *, gfx_coord2_t *);
+	/** Set cursor visibility */
+	errno_t (*cursor_set_visible)(void *, bool);
+} mem_gc_cb_t;
 
 #endif
Index: uspace/lib/memgfx/private/memgc.h
===================================================================
--- uspace/lib/memgfx/private/memgc.h	(revision bb14312c8c42ea170b99a8d6db9a607a3b2aba04)
+++ uspace/lib/memgfx/private/memgc.h	(revision 1215db9d1ade6fae2cbc2685459e7ecd9b62efef)
@@ -53,9 +53,7 @@
 	/** Allocation info */
 	gfx_bitmap_alloc_t alloc;
-	/** Invalidate callback */
-	mem_gc_invalidate_cb_t invalidate;
-	/** Update callback */
-	mem_gc_update_cb_t update;
-	/** Argument to callback */
+	/** Callbacks */
+	mem_gc_cb_t *cb;
+	/** Argument to callbacks */
 	void *cb_arg;
 	/** Current drawing color */
Index: uspace/lib/memgfx/src/memgc.c
===================================================================
--- uspace/lib/memgfx/src/memgc.c	(revision bb14312c8c42ea170b99a8d6db9a607a3b2aba04)
+++ uspace/lib/memgfx/src/memgc.c	(revision 1215db9d1ade6fae2cbc2685459e7ecd9b62efef)
@@ -57,4 +57,7 @@
 static errno_t mem_gc_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
 static errno_t mem_gc_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
+static errno_t mem_gc_cursor_get_pos(void *, gfx_coord2_t *);
+static errno_t mem_gc_cursor_set_pos(void *, gfx_coord2_t *);
+static errno_t mem_gc_cursor_set_visible(void *, bool);
 static void mem_gc_invalidate_rect(mem_gc_t *, gfx_rect_t *);
 
@@ -67,5 +70,8 @@
 	.bitmap_destroy = mem_gc_bitmap_destroy,
 	.bitmap_render = mem_gc_bitmap_render,
-	.bitmap_get_alloc = mem_gc_bitmap_get_alloc
+	.bitmap_get_alloc = mem_gc_bitmap_get_alloc,
+	.cursor_get_pos = mem_gc_cursor_get_pos,
+	.cursor_set_pos = mem_gc_cursor_set_pos,
+	.cursor_set_visible = mem_gc_cursor_set_visible
 };
 
@@ -152,5 +158,5 @@
 	mem_gc_t *mgc = (mem_gc_t *) arg;
 
-	mgc->update(mgc->cb_arg);
+	mgc->cb->update(mgc->cb_arg);
 	return EOK;
 }
@@ -162,6 +168,6 @@
  * @param rect Bounding rectangle
  * @param alloc Allocation info
- * @param update_cb Function called to update a rectangle
- * @param cb_arg Argument to callback function
+ * @param cb Pointer to memory GC callbacks
+ * @param cb_arg Argument to callback functions
  * @param rgc Place to store pointer to new memory GC
  *
@@ -169,6 +175,5 @@
  */
 errno_t mem_gc_create(gfx_rect_t *rect, gfx_bitmap_alloc_t *alloc,
-    mem_gc_invalidate_cb_t invalidate_cb, mem_gc_update_cb_t update_cb,
-    void *cb_arg, mem_gc_t **rgc)
+    mem_gc_cb_t *cb, void *cb_arg, mem_gc_t **rgc)
 {
 	mem_gc_t *mgc = NULL;
@@ -191,6 +196,5 @@
 	mgc->alloc = *alloc;
 
-	mgc->invalidate = invalidate_cb;
-	mgc->update = update_cb;
+	mgc->cb = cb;
 	mgc->cb_arg = cb_arg;
 
@@ -246,5 +250,5 @@
 static void mem_gc_invalidate_rect(mem_gc_t *mgc, gfx_rect_t *rect)
 {
-	mgc->invalidate(mgc->cb_arg, rect);
+	mgc->cb->invalidate(mgc->cb_arg, rect);
 }
 
@@ -464,4 +468,55 @@
 }
 
+/** Get cursor position on memory GC.
+ *
+ * @param arg Memory GC
+ * @param pos Place to store position
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t mem_gc_cursor_get_pos(void *arg, gfx_coord2_t *pos)
+{
+	mem_gc_t *mgc = (mem_gc_t *) arg;
+
+	if (mgc->cb->cursor_get_pos != NULL)
+		return mgc->cb->cursor_get_pos(mgc->cb_arg, pos);
+	else
+		return ENOTSUP;
+}
+
+/** Set cursor position on memory GC.
+ *
+ * @param arg Memory GC
+ * @param pos New position
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t mem_gc_cursor_set_pos(void *arg, gfx_coord2_t *pos)
+{
+	mem_gc_t *mgc = (mem_gc_t *) arg;
+
+	if (mgc->cb->cursor_set_pos != NULL)
+		return mgc->cb->cursor_set_pos(mgc->cb_arg, pos);
+	else
+		return ENOTSUP;
+}
+
+/** Set cursor visibility on memory GC.
+ *
+ * @param arg Memory GC
+ * @param visible @c true iff cursor should be made visible
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t mem_gc_cursor_set_visible(void *arg, bool visible)
+{
+	mem_gc_t *mgc = (mem_gc_t *) arg;
+
+	if (mgc->cb->cursor_set_visible != NULL)
+		return mgc->cb->cursor_set_visible(mgc->cb_arg, visible);
+	else
+		return ENOTSUP;
+}
+
 /** @}
  */
Index: uspace/lib/memgfx/test/memgfx.c
===================================================================
--- uspace/lib/memgfx/test/memgfx.c	(revision bb14312c8c42ea170b99a8d6db9a607a3b2aba04)
+++ uspace/lib/memgfx/test/memgfx.c	(revision 1215db9d1ade6fae2cbc2685459e7ecd9b62efef)
@@ -32,4 +32,5 @@
 #include <gfx/coord.h>
 #include <gfx/context.h>
+#include <gfx/cursor.h>
 #include <gfx/render.h>
 #include <io/pixelmap.h>
@@ -44,6 +45,19 @@
 static void test_invalidate_rect(void *arg, gfx_rect_t *rect);
 static void test_update(void *arg);
+static errno_t test_cursor_get_pos(void *arg, gfx_coord2_t *);
+static errno_t test_cursor_set_pos(void *arg, gfx_coord2_t *);
+static errno_t test_cursor_set_visible(void *arg, bool);
+
+static mem_gc_cb_t test_mem_gc_cb = {
+	.invalidate = test_invalidate_rect,
+	.update = test_update,
+	.cursor_get_pos = test_cursor_get_pos,
+	.cursor_set_pos = test_cursor_set_pos,
+	.cursor_set_visible = test_cursor_set_visible
+};
 
 typedef struct {
+	/** Return code to return */
+	errno_t rc;
 	/** True if invalidate was called */
 	bool invalidate_called;
@@ -52,4 +66,16 @@
 	/** True if update was called */
 	bool update_called;
+	/** True if cursor_get_pos was called */
+	bool cursor_get_pos_called;
+	/** Position to return from cursor_get_pos */
+	gfx_coord2_t get_pos_pos;
+	/** True if cursor_set_pos was called */
+	bool cursor_set_pos_called;
+	/** Position passed to cursor_set_pos */
+	gfx_coord2_t set_pos_pos;
+	/** True if cursor_set_visible was called */
+	bool cursor_set_visible_called;
+	/** Value passed to cursor_set_visible */
+	bool set_visible_vis;
 } test_resp_t;
 
@@ -72,5 +98,5 @@
 	PCUT_ASSERT_NOT_NULL(alloc.pixels);
 
-	rc = mem_gc_create(&rect, &alloc, NULL, NULL, NULL, &mgc);
+	rc = mem_gc_create(&rect, &alloc, NULL, NULL, &mgc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -106,6 +132,5 @@
 	PCUT_ASSERT_NOT_NULL(alloc.pixels);
 
-	rc = mem_gc_create(&rect, &alloc, test_invalidate_rect,
-	    test_update, &resp, &mgc);
+	rc = mem_gc_create(&rect, &alloc, &test_mem_gc_cb, &resp, &mgc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -187,6 +212,5 @@
 	PCUT_ASSERT_NOT_NULL(alloc.pixels);
 
-	rc = mem_gc_create(&rect, &alloc, test_invalidate_rect,
-	    test_update, &resp, &mgc);
+	rc = mem_gc_create(&rect, &alloc, &test_mem_gc_cb, &resp, &mgc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -277,6 +301,5 @@
 	PCUT_ASSERT_NOT_NULL(alloc.pixels);
 
-	rc = mem_gc_create(&rect, &alloc, test_invalidate_rect,
-	    test_update, &resp, &mgc);
+	rc = mem_gc_create(&rect, &alloc, &test_mem_gc_cb, &resp, &mgc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -294,4 +317,135 @@
 }
 
+/** Test gfx_cursor_get_pos() on a memory GC */
+PCUT_TEST(gfx_cursor_get_pos)
+{
+	mem_gc_t *mgc;
+	gfx_rect_t rect;
+	gfx_bitmap_alloc_t alloc;
+	gfx_coord2_t pos;
+	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_mem_gc_cb, &resp, &mgc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	gc = mem_gc_get_ctx(mgc);
+	PCUT_ASSERT_NOT_NULL(gc);
+
+	memset(&resp, 0, sizeof(resp));
+	resp.rc = EOK;
+	resp.get_pos_pos.x = 1;
+	resp.get_pos_pos.y = 2;
+	PCUT_ASSERT_FALSE(resp.cursor_get_pos_called);
+
+	rc = gfx_cursor_get_pos(gc, &pos);
+	PCUT_ASSERT_TRUE(resp.cursor_get_pos_called);
+	PCUT_ASSERT_INT_EQUALS(resp.get_pos_pos.x, pos.x);
+	PCUT_ASSERT_INT_EQUALS(resp.get_pos_pos.y, pos.y);
+
+	mem_gc_delete(mgc);
+	free(alloc.pixels);
+}
+
+/** Test gfx_cursor_set_pos() on a memory GC */
+PCUT_TEST(gfx_cursor_set_pos)
+{
+	mem_gc_t *mgc;
+	gfx_rect_t rect;
+	gfx_bitmap_alloc_t alloc;
+	gfx_coord2_t pos;
+	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_mem_gc_cb, &resp, &mgc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	gc = mem_gc_get_ctx(mgc);
+	PCUT_ASSERT_NOT_NULL(gc);
+
+	memset(&resp, 0, sizeof(resp));
+	resp.rc = EOK;
+	pos.x = 1;
+	pos.y = 2;
+	PCUT_ASSERT_FALSE(resp.cursor_set_pos_called);
+
+	rc = gfx_cursor_set_pos(gc, &pos);
+	PCUT_ASSERT_TRUE(resp.cursor_set_pos_called);
+	PCUT_ASSERT_INT_EQUALS(pos.x, resp.set_pos_pos.x);
+	PCUT_ASSERT_INT_EQUALS(pos.y, resp.set_pos_pos.y);
+
+	mem_gc_delete(mgc);
+	free(alloc.pixels);
+}
+
+/** Test gfx_cursor_set_visible() on a memory GC */
+PCUT_TEST(gfx_cursor_set_visible)
+{
+	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_mem_gc_cb, &resp, &mgc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	gc = mem_gc_get_ctx(mgc);
+	PCUT_ASSERT_NOT_NULL(gc);
+
+	memset(&resp, 0, sizeof(resp));
+	resp.rc = EOK;
+	PCUT_ASSERT_FALSE(resp.cursor_set_visible_called);
+
+	rc = gfx_cursor_set_visible(gc, true);
+	PCUT_ASSERT_TRUE(resp.cursor_set_visible_called);
+	PCUT_ASSERT_TRUE(resp.set_visible_vis);
+
+	resp.cursor_set_visible_called = false;
+
+	rc = gfx_cursor_set_visible(gc, false);
+	PCUT_ASSERT_TRUE(resp.cursor_set_visible_called);
+	PCUT_ASSERT_FALSE(resp.set_visible_vis);
+
+	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)
@@ -311,3 +465,33 @@
 }
 
+/** Called by memory GC when cursor_get_pos is called. */
+static errno_t test_cursor_get_pos(void *arg, gfx_coord2_t *pos)
+{
+	test_resp_t *resp = (test_resp_t *)arg;
+
+	resp->cursor_get_pos_called = true;
+	*pos = resp->get_pos_pos;
+	return resp->rc;
+}
+
+/** Called by memory GC when cursor_set_pos is called. */
+static errno_t test_cursor_set_pos(void *arg, gfx_coord2_t *pos)
+{
+	test_resp_t *resp = (test_resp_t *)arg;
+
+	resp->cursor_set_pos_called = true;
+	resp->set_pos_pos = *pos;
+	return resp->rc;
+}
+
+/** Called by memory GC when cursor_set_visible is called. */
+static errno_t test_cursor_set_visible(void *arg, bool visible)
+{
+	test_resp_t *resp = (test_resp_t *)arg;
+
+	resp->cursor_set_visible_called = true;
+	resp->set_visible_vis = visible;
+	return resp->rc;
+}
+
 PCUT_EXPORT(memgfx);
Index: uspace/lib/ui/src/window.c
===================================================================
--- uspace/lib/ui/src/window.c	(revision bb14312c8c42ea170b99a8d6db9a607a3b2aba04)
+++ uspace/lib/ui/src/window.c	(revision 1215db9d1ade6fae2cbc2685459e7ecd9b62efef)
@@ -39,4 +39,5 @@
 #include <gfx/bitmap.h>
 #include <gfx/context.h>
+#include <gfx/cursor.h>
 #include <gfx/render.h>
 #include <io/kbd_event.h>
@@ -88,6 +89,26 @@
 static void ui_window_invalidate(void *, gfx_rect_t *);
 static void ui_window_update(void *);
+static errno_t ui_window_cursor_get_pos(void *, gfx_coord2_t *);
+static errno_t ui_window_cursor_set_pos(void *, gfx_coord2_t *);
+static errno_t ui_window_cursor_set_visible(void *, bool);
+
+/** Window memory GC callbacks */
+static mem_gc_cb_t ui_window_mem_gc_cb = {
+	.invalidate = ui_window_invalidate,
+	.update = ui_window_update,
+	.cursor_get_pos = ui_window_cursor_get_pos,
+	.cursor_set_pos = ui_window_cursor_set_pos,
+	.cursor_set_visible = ui_window_cursor_set_visible
+};
+
 static void ui_window_app_invalidate(void *, gfx_rect_t *);
 static void ui_window_app_update(void *);
+
+/** Application area memory GC callbacks */
+static mem_gc_cb_t ui_window_app_mem_gc_cb = {
+	.invalidate = ui_window_app_invalidate,
+	.update = ui_window_app_update
+};
+
 static void ui_window_expose_cb(void *);
 
@@ -255,6 +276,6 @@
 	}
 
-	rc = mem_gc_create(&bparams.rect, &alloc, ui_window_invalidate,
-	    ui_window_update, (void *) window, &memgc);
+	rc = mem_gc_create(&bparams.rect, &alloc, &ui_window_mem_gc_cb,
+	    (void *) window, &memgc);
 	if (rc != EOK) {
 		gfx_bitmap_destroy(window->app_bmp);
@@ -267,6 +288,5 @@
 	window->realgc = gc;
 #else
-	(void) ui_window_update;
-	(void) ui_window_invalidate;
+	(void) ui_window_mem_gc_cb;
 	(void) alloc;
 	(void) bparams;
@@ -618,6 +638,6 @@
 		}
 
-		rc = mem_gc_create(&params.rect, &alloc, ui_window_app_invalidate,
-		    ui_window_app_update, (void *) window, &memgc);
+		rc = mem_gc_create(&params.rect, &alloc,
+		    &ui_window_app_mem_gc_cb, (void *) window, &memgc);
 		if (rc != EOK) {
 			gfx_bitmap_destroy(window->app_bmp);
@@ -1003,4 +1023,40 @@
 }
 
+/** Window cursor get position callback
+ *
+ * @param arg Argument (ui_window_t *)
+ * @param pos Place to store position
+ */
+static errno_t ui_window_cursor_get_pos(void *arg, gfx_coord2_t *pos)
+{
+	ui_window_t *window = (ui_window_t *) arg;
+
+	return gfx_cursor_get_pos(window->realgc, pos);
+}
+
+/** Window cursor set position callback
+ *
+ * @param arg Argument (ui_window_t *)
+ * @param pos New position
+ */
+static errno_t ui_window_cursor_set_pos(void *arg, gfx_coord2_t *pos)
+{
+	ui_window_t *window = (ui_window_t *) arg;
+
+	return gfx_cursor_set_pos(window->realgc, pos);
+}
+
+/** Window cursor set visibility callback
+ *
+ * @param arg Argument (ui_window_t *)
+ * @param visible @c true iff cursor is to be made visible
+ */
+static errno_t ui_window_cursor_set_visible(void *arg, bool visible)
+{
+	ui_window_t *window = (ui_window_t *) arg;
+
+	return gfx_cursor_set_visible(window->realgc, visible);
+}
+
 /** Application area invalidate callback
  *
Index: uspace/srv/hid/display/display.c
===================================================================
--- uspace/srv/hid/display/display.c	(revision bb14312c8c42ea170b99a8d6db9a607a3b2aba04)
+++ uspace/srv/hid/display/display.c	(revision 1215db9d1ade6fae2cbc2685459e7ecd9b62efef)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2019 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * All rights reserved.
  *
@@ -53,4 +53,9 @@
 static void ds_display_update_cb(void *);
 
+static mem_gc_cb_t ds_display_mem_gc_cb = {
+	.invalidate = ds_display_invalidate_cb,
+	.update = ds_display_update_cb
+};
+
 /** Create display.
  *
@@ -459,7 +464,6 @@
 		goto error;
 
-	rc = mem_gc_create(&disp->rect, &alloc,
-	    ds_display_invalidate_cb, ds_display_update_cb, (void *) disp,
-	    &disp->bbgc);
+	rc = mem_gc_create(&disp->rect, &alloc, &ds_display_mem_gc_cb,
+	    (void *) disp, &disp->bbgc);
 	if (rc != EOK)
 		goto error;
Index: uspace/srv/hid/display/window.c
===================================================================
--- uspace/srv/hid/display/window.c	(revision bb14312c8c42ea170b99a8d6db9a607a3b2aba04)
+++ uspace/srv/hid/display/window.c	(revision 1215db9d1ade6fae2cbc2685459e7ecd9b62efef)
@@ -53,4 +53,9 @@
 static void ds_window_get_preview_rect(ds_window_t *, gfx_rect_t *);
 
+static mem_gc_cb_t ds_window_mem_gc_cb = {
+	.invalidate = ds_window_invalidate_cb,
+	.update = ds_window_update_cb
+};
+
 /** Create window.
  *
@@ -108,6 +113,6 @@
 	}
 
-	rc = mem_gc_create(&params->rect, &alloc, ds_window_invalidate_cb,
-	    ds_window_update_cb, (void *)wnd, &wnd->mgc);
+	rc = mem_gc_create(&params->rect, &alloc, &ds_window_mem_gc_cb,
+	    (void *)wnd, &wnd->mgc);
 	if (rc != EOK)
 		goto error;
