Index: uspace/srv/hid/display/cursor.c
===================================================================
--- uspace/srv/hid/display/cursor.c	(revision 4d8002de0e91d359818180c5e990eb5bf5e63aff)
+++ uspace/srv/hid/display/cursor.c	(revision 4912dd5936f00b272257e168f71279c68a96e1dd)
@@ -104,4 +104,6 @@
 
 	dgc = ds_display_get_gc(cursor->display); // XXX
+	if (dgc == NULL)
+		return EOK;
 
 	gfx_bitmap_params_init(&bparams);
@@ -144,6 +146,4 @@
 			}
 		}
-
-		return EOK;
 	}
 
Index: uspace/srv/hid/display/ddev.c
===================================================================
--- uspace/srv/hid/display/ddev.c	(revision 4d8002de0e91d359818180c5e990eb5bf5e63aff)
+++ uspace/srv/hid/display/ddev.c	(revision 4912dd5936f00b272257e168f71279c68a96e1dd)
@@ -42,4 +42,37 @@
 #include "display.h"
 #include "ddev.h"
+
+/** Create display device object.
+ *
+ * @param display Parent display
+ * @param dd Display device
+ * @param info Display device info
+ * @param svc_id Display device service ID
+ * @param svc_name Display device service name
+ * @param gc Display device GC
+ * @param rddev Place to store pointer to new display device.
+ * @return EOK on success, ENOMEM if out of memory
+ */
+errno_t ds_ddev_create(ds_display_t *display, ddev_t *dd,
+    ddev_info_t *info, char *svc_name, service_id_t svc_id,
+    gfx_context_t *gc, ds_ddev_t **rddev)
+{
+	ds_ddev_t *ddev;
+
+	ddev = calloc(1, sizeof(ds_ddev_t));
+	if (ddev == NULL)
+		return ENOMEM;
+
+	ddev->svc_name = svc_name;
+	ddev->svc_id = svc_id;
+	ddev->dd = dd;
+	ddev->gc = gc;
+	ddev->info = *info;
+
+	ds_display_add_ddev(display, ddev);
+
+	*rddev = ddev;
+	return EOK;
+}
 
 /** Open display device.
@@ -95,18 +128,11 @@
 	}
 
-	ddev = calloc(1, sizeof(ds_ddev_t));
-	if (ddev == NULL) {
+	rc = ds_ddev_create(display, dd, &info, name, svc_id, gc, &ddev);
+	if (rc != EOK) {
 		free(name);
 		ddev_close(dd);
-		return ENOMEM;
+		gfx_context_delete(gc);
+		return rc;
 	}
-
-	ddev->svc_name = name;
-	ddev->svc_id = svc_id;
-	ddev->dd = dd;
-	ddev->gc = gc;
-	ddev->info = info;
-
-	ds_display_add_ddev(display, ddev);
 
 	rc = ds_display_paint_bg(display, NULL);
Index: uspace/srv/hid/display/ddev.h
===================================================================
--- uspace/srv/hid/display/ddev.h	(revision 4d8002de0e91d359818180c5e990eb5bf5e63aff)
+++ uspace/srv/hid/display/ddev.h	(revision 4912dd5936f00b272257e168f71279c68a96e1dd)
@@ -42,4 +42,6 @@
 #include "types/display/display.h"
 
+extern errno_t ds_ddev_create(ds_display_t *, ddev_t *, ddev_info_t *,
+    char *, service_id_t, gfx_context_t *, ds_ddev_t **);
 extern errno_t ds_ddev_open(ds_display_t *, service_id_t, ds_ddev_t **);
 extern void ds_ddev_close(ds_ddev_t *);
Index: uspace/srv/hid/display/meson.build
===================================================================
--- uspace/srv/hid/display/meson.build	(revision 4d8002de0e91d359818180c5e990eb5bf5e63aff)
+++ uspace/srv/hid/display/meson.build	(revision 4912dd5936f00b272257e168f71279c68a96e1dd)
@@ -47,4 +47,5 @@
 	'cursimg.c',
 	'cursor.c',
+	'ddev.c',
 	'display.c',
 	'seat.c',
Index: uspace/srv/hid/display/test/cursor.c
===================================================================
--- uspace/srv/hid/display/test/cursor.c	(revision 4d8002de0e91d359818180c5e990eb5bf5e63aff)
+++ uspace/srv/hid/display/test/cursor.c	(revision 4912dd5936f00b272257e168f71279c68a96e1dd)
@@ -28,13 +28,40 @@
 
 #include <errno.h>
+#include <gfx/context.h>
+#include <stdbool.h>
 #include <pcut/pcut.h>
 
 #include "../cursor.h"
 #include "../cursimg.h"
+#include "../ddev.h"
 #include "../display.h"
+#include "../display.h"
 
 PCUT_INIT;
 
 PCUT_TEST_SUITE(cursor);
+
+static errno_t dummy_bitmap_create(void *, gfx_bitmap_params_t *,
+    gfx_bitmap_alloc_t *, void **);
+static errno_t dummy_bitmap_destroy(void *);
+static errno_t dummy_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
+static errno_t dummy_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
+
+static gfx_context_ops_t dummy_ops = {
+	.bitmap_create = dummy_bitmap_create,
+	.bitmap_destroy = dummy_bitmap_destroy,
+	.bitmap_render = dummy_bitmap_render,
+	.bitmap_get_alloc = dummy_bitmap_get_alloc
+};
+
+
+typedef struct {
+	bool render_called;
+} test_response_t;
+
+typedef struct {
+	test_response_t *resp;
+	gfx_bitmap_alloc_t alloc;
+} dummy_bitmap_t;
 
 /** Test ds_cursor_create(), ds_cursor_destroy(). */
@@ -59,9 +86,22 @@
 PCUT_TEST(cursor_paint)
 {
+	gfx_context_t *gc;
 	ds_display_t *disp;
 	ds_cursor_t *cursor;
+	ds_ddev_t *ddev;
+	ddev_info_t ddinfo;
+	gfx_coord2_t pos;
+	test_response_t resp;
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = gfx_context_new(&dummy_ops, &resp, &gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_display_create(gc, &disp);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	ddev_info_init(&ddinfo);
+
+	rc = ds_ddev_create(disp, NULL, &ddinfo, NULL, 0, gc, &ddev);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -70,4 +110,12 @@
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
+	resp.render_called = false;
+
+	pos.x = 0;
+	pos.y = 0;
+	ds_cursor_paint(cursor, &pos);
+
+	PCUT_ASSERT_TRUE(resp.render_called);
+
 	ds_cursor_destroy(cursor);
 	ds_display_destroy(disp);
@@ -79,4 +127,6 @@
 	ds_display_t *disp;
 	ds_cursor_t *cursor;
+	gfx_coord2_t pos1, pos2;
+	gfx_rect_t rect1, rect2;
 	errno_t rc;
 
@@ -88,7 +138,76 @@
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
+	pos1.x = 10;
+	pos1.y = 11;
+
+	pos2.x = 22;
+	pos2.y = 23;
+
+	ds_cursor_get_rect(cursor, &pos1, &rect1);
+	ds_cursor_get_rect(cursor, &pos2, &rect2);
+
+	PCUT_ASSERT_FALSE(gfx_rect_is_empty(&rect1));
+	PCUT_ASSERT_FALSE(gfx_rect_is_empty(&rect2));
+
+	PCUT_ASSERT_INT_EQUALS(pos2.x - pos1.x, rect2.p0.x - rect1.p0.x);
+	PCUT_ASSERT_INT_EQUALS(pos2.y - pos1.y, rect2.p0.y - rect1.p0.y);
+	PCUT_ASSERT_INT_EQUALS(pos2.x - pos1.x, rect2.p1.x - rect1.p1.x);
+	PCUT_ASSERT_INT_EQUALS(pos2.y - pos1.y, rect2.p1.y - rect1.p1.y);
+
 	ds_cursor_destroy(cursor);
 	ds_display_destroy(disp);
 }
 
+static errno_t dummy_bitmap_create(void *arg, gfx_bitmap_params_t *params,
+    gfx_bitmap_alloc_t *alloc, void **rbm)
+{
+	test_response_t *resp = (test_response_t *) arg;
+	dummy_bitmap_t *bm;
+	gfx_coord2_t dims;
+
+	gfx_rect_dims(&params->rect, &dims);
+	bm = calloc(1, sizeof(dummy_bitmap_t));
+	if (bm == NULL)
+		return ENOMEM;
+
+	bm->resp = resp;
+	bm->alloc.pitch = dims.x * sizeof(uint32_t);
+	bm->alloc.off0 = 0;
+
+	bm->alloc.pixels = malloc(bm->alloc.pitch * dims.y * sizeof(uint32_t));
+	if (bm->alloc.pixels == NULL) {
+		free(bm);
+		return ENOMEM;
+	}
+
+	*rbm = (void *) bm;
+	return EOK;
+}
+
+static errno_t dummy_bitmap_destroy(void *arg)
+{
+	dummy_bitmap_t *bm = (dummy_bitmap_t *) arg;
+
+	free(bm);
+	return EOK;
+}
+
+static errno_t dummy_bitmap_render(void *arg, gfx_rect_t *rect,
+    gfx_coord2_t *dpos)
+{
+	dummy_bitmap_t *bm = (dummy_bitmap_t *) arg;
+
+	bm->resp->render_called = true;
+	return EOK;
+}
+
+static errno_t dummy_bitmap_get_alloc(void *arg, gfx_bitmap_alloc_t *alloc)
+{
+	dummy_bitmap_t *bm = (dummy_bitmap_t *) arg;
+
+	*alloc = bm->alloc;
+	return EOK;
+}
+
+
 PCUT_EXPORT(cursor);
Index: uspace/srv/hid/display/test/main.c
===================================================================
--- uspace/srv/hid/display/test/main.c	(revision 4d8002de0e91d359818180c5e990eb5bf5e63aff)
+++ uspace/srv/hid/display/test/main.c	(revision 4912dd5936f00b272257e168f71279c68a96e1dd)
@@ -32,4 +32,5 @@
 
 PCUT_IMPORT(client);
+PCUT_IMPORT(cursor);
 PCUT_IMPORT(display);
 PCUT_IMPORT(window);
