Index: uspace/drv/fb/amdm37x_dispc/amdm37x_dispc.c
===================================================================
--- uspace/drv/fb/amdm37x_dispc/amdm37x_dispc.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/drv/fb/amdm37x_dispc/amdm37x_dispc.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * Copyright (c) 2013 Jan Vesely
  * All rights reserved.
@@ -67,4 +67,5 @@
 static errno_t amdm37x_ddev_get_info(void *, ddev_info_t *);
 
+static errno_t amdm37x_gc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t amdm37x_gc_set_color(void *, gfx_color_t *);
 static errno_t amdm37x_gc_fill_rect(void *, gfx_rect_t *);
@@ -81,4 +82,5 @@
 
 gfx_context_ops_t amdm37x_gc_ops = {
+	.set_clip_rect = amdm37x_gc_set_clip_rect,
 	.set_color = amdm37x_gc_set_color,
 	.fill_rect = amdm37x_gc_fill_rect,
@@ -291,4 +293,5 @@
 	dispc->rect.p1.x = x;
 	dispc->rect.p1.y = y;
+	dispc->clip_rect = dispc->rect;
 	dispc->size = size;
 
@@ -321,4 +324,23 @@
 }
 
+/** Set clipping rectangle on AMDM37x display controller.
+ *
+ * @param arg AMDM37x display controller
+ * @param rect Rectangle
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t amdm37x_gc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	amdm37x_dispc_t *dispc = (amdm37x_dispc_t *) arg;
+
+	if (rect != NULL)
+		gfx_rect_clip(rect, &dispc->rect, &dispc->clip_rect);
+	else
+		dispc->clip_rect = dispc->rect;
+
+	return EOK;
+}
+
 /** Set color on AMDM37x display controller.
  *
@@ -354,5 +376,5 @@
 
 	/* Make sure we have a sorted, clipped rectangle */
-	gfx_rect_clip(rect, &dispc->rect, &crect);
+	gfx_rect_clip(rect, &dispc->clip_rect, &crect);
 
 	for (y = crect.p0.y; y < crect.p1.y; y++) {
@@ -479,6 +501,6 @@
 	pbm.data = dcbm->alloc.pixels;
 
-	/* Transform AMDM37x bounding rectangle back to bitmap coordinate system */
-	gfx_rect_rtranslate(&offs, &dispc->rect, &skfbrect);
+	/* Transform AMDM37x clipping rectangle back to bitmap coordinate system */
+	gfx_rect_rtranslate(&offs, &dispc->clip_rect, &skfbrect);
 
 	/*
Index: uspace/drv/fb/amdm37x_dispc/amdm37x_dispc.h
===================================================================
--- uspace/drv/fb/amdm37x_dispc/amdm37x_dispc.h	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/drv/fb/amdm37x_dispc/amdm37x_dispc.h	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * Copyright (c) 2013 Jan Vesely
  * All rights reserved.
@@ -63,4 +63,5 @@
 	pixel_t color;
 	gfx_rect_t rect;
+	gfx_rect_t clip_rect;
 	size_t size;
 	void *fb_data;
Index: uspace/drv/fb/kfb/port.c
===================================================================
--- uspace/drv/fb/kfb/port.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/drv/fb/kfb/port.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2019 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * Copyright (c) 2006 Jakub Vana
  * Copyright (c) 2006 Ondrej Palkovsky
@@ -69,4 +69,5 @@
 	sysarg_t paddr;
 	gfx_rect_t rect;
+	gfx_rect_t clip_rect;
 	size_t offset;
 	size_t scanline;
@@ -97,4 +98,5 @@
 static errno_t kfb_ddev_get_info(void *, ddev_info_t *);
 
+static errno_t kfb_gc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t kfb_gc_set_color(void *, gfx_color_t *);
 static errno_t kfb_gc_fill_rect(void *, gfx_rect_t *);
@@ -111,4 +113,5 @@
 
 static gfx_context_ops_t kfb_gc_ops = {
+	.set_clip_rect = kfb_gc_set_clip_rect,
 	.set_color = kfb_gc_set_color,
 	.fill_rect = kfb_gc_fill_rect,
@@ -134,4 +137,23 @@
 	ddev_info_init(info);
 	info->rect = kfb->rect;
+	return EOK;
+}
+
+/** Set clipping rectangle on KFB.
+ *
+ * @param arg KFB
+ * @param rect Rectangle or @c NULL
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t kfb_gc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	kfb_t *kfb = (kfb_t *) arg;
+
+	if (rect != NULL)
+		gfx_rect_clip(rect, &kfb->rect, &kfb->clip_rect);
+	else
+		kfb->clip_rect = kfb->rect;
+
 	return EOK;
 }
@@ -361,5 +383,4 @@
 }
 
-#include <stdio.h>
 static void kfb_client_conn(ipc_call_t *icall, void *arg)
 {
@@ -372,9 +393,4 @@
 	kfb = (kfb_t *) ddf_fun_data_get((ddf_fun_t *) arg);
 
-	printf("kfb_client_conn arg2=%lu arg3=%lu arg4=%lu\n",
-	    (unsigned long) ipc_get_arg2(icall),
-	    (unsigned long) ipc_get_arg3(icall),
-	    (unsigned long) ipc_get_arg4(icall));
-
 	gc_id = ipc_get_arg3(icall);
 
@@ -500,4 +516,6 @@
 	kfb->rect.p1.x = width;
 	kfb->rect.p1.y = height;
+
+	kfb->clip_rect = kfb->rect;
 
 	kfb->paddr = paddr;
Index: uspace/lib/congfx/private/console.h
===================================================================
--- uspace/lib/congfx/private/console.h	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/congfx/private/console.h	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -55,4 +55,6 @@
 	/** Console bounding rectangle */
 	gfx_rect_t rect;
+	/** Clipping rectangle */
+	gfx_rect_t clip_rect;
 	/** File for printing characters */
 	FILE *fout;
Index: uspace/lib/congfx/src/console.c
===================================================================
--- uspace/lib/congfx/src/console.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/congfx/src/console.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -48,4 +48,5 @@
 #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 *);
@@ -58,4 +59,5 @@
 
 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,
@@ -67,4 +69,23 @@
 };
 
+/** 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.
  *
@@ -100,5 +121,5 @@
 
 	/* Make sure rectangle is clipped and sorted */
-	gfx_rect_clip(rect, &cgc->rect, &crect);
+	gfx_rect_clip(rect, &cgc->clip_rect, &crect);
 
 	cols = cgc->rect.p1.x - cgc->rect.p0.x;
@@ -188,4 +209,5 @@
 	cgc->rect.p1.x = cols;
 	cgc->rect.p1.y = rows;
+	cgc->clip_rect = cgc->rect;
 	cgc->buf = buf;
 
@@ -330,5 +352,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;
Index: uspace/lib/gfx/include/gfx/render.h
===================================================================
--- uspace/lib/gfx/include/gfx/render.h	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/gfx/include/gfx/render.h	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -42,4 +42,5 @@
 #include <types/gfx/context.h>
 
+extern errno_t gfx_set_clip_rect(gfx_context_t *, gfx_rect_t *);
 extern errno_t gfx_set_color(gfx_context_t *, gfx_color_t *);
 extern errno_t gfx_fill_rect(gfx_context_t *, gfx_rect_t *);
Index: uspace/lib/gfx/include/types/gfx/ops/context.h
===================================================================
--- uspace/lib/gfx/include/types/gfx/ops/context.h	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/gfx/include/types/gfx/ops/context.h	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -47,4 +47,6 @@
 /** Graphics context ops */
 typedef struct {
+	/** Set clipping rectangle */
+	errno_t (*set_clip_rect)(void *, gfx_rect_t *);
 	/** Set drawing color */
 	errno_t (*set_color)(void *, gfx_color_t *);
Index: uspace/lib/gfx/src/render.c
===================================================================
--- uspace/lib/gfx/src/render.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/gfx/src/render.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -36,4 +36,17 @@
 #include <gfx/render.h>
 #include "../private/context.h"
+
+/** Set clipping rectangle.
+ *
+ * @param gc Graphic context
+ * @param rect Rectangle or @c NULL (no extra clipping)
+ *
+ * @return EOK on success, ENOMEM if insufficient resources,
+ *         EIO if grahic device connection was lost
+ */
+errno_t gfx_set_clip_rect(gfx_context_t *gc, gfx_rect_t *rect)
+{
+	return gc->ops->set_clip_rect(gc->arg, rect);
+}
 
 /** Set drawing color.
Index: uspace/lib/gfx/test/render.c
===================================================================
--- uspace/lib/gfx/test/render.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/gfx/test/render.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -38,4 +38,5 @@
 PCUT_TEST_SUITE(render);
 
+static errno_t testgc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t testgc_set_color(void *, gfx_color_t *);
 static errno_t testgc_fill_rect(void *, gfx_rect_t *);
@@ -43,4 +44,5 @@
 
 static gfx_context_ops_t ops = {
+	.set_clip_rect = testgc_set_clip_rect,
 	.set_color = testgc_set_color,
 	.fill_rect = testgc_fill_rect,
@@ -50,9 +52,100 @@
 /** Test graphics context data */
 typedef struct {
+	errno_t rc;
+
+	bool set_clip_rect;
+	gfx_rect_t crect;
+	bool do_clip;
+
+	bool set_color;
 	gfx_color_t *dclr;
-	gfx_rect_t *rect;
-	bool updated;
+
+	bool fill_rect;
+	gfx_rect_t frect;
+
+	bool update;
 } test_gc_t;
 
+/** Set clipping rectangle */
+PCUT_TEST(set_clip_rect)
+{
+	errno_t rc;
+	gfx_rect_t rect;
+	gfx_context_t *gc = NULL;
+	test_gc_t tgc;
+
+	memset(&tgc, 0, sizeof(tgc));
+
+	rc = gfx_context_new(&ops, &tgc, &gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rect.p0.x = 1;
+	rect.p0.y = 2;
+	rect.p1.x = 3;
+	rect.p1.y = 4;
+
+	tgc.rc = EOK;
+
+	rc = gfx_set_clip_rect(gc, &rect);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	PCUT_ASSERT_TRUE(tgc.set_clip_rect);
+	PCUT_ASSERT_TRUE(tgc.do_clip);
+	PCUT_ASSERT_INT_EQUALS(rect.p0.x, tgc.crect.p0.x);
+	PCUT_ASSERT_INT_EQUALS(rect.p0.y, tgc.crect.p0.y);
+	PCUT_ASSERT_INT_EQUALS(rect.p1.x, tgc.crect.p1.x);
+	PCUT_ASSERT_INT_EQUALS(rect.p1.y, tgc.crect.p1.y);
+
+	rc = gfx_context_delete(gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+/** Set null clipping rectangle */
+PCUT_TEST(set_clip_rect_null)
+{
+	errno_t rc;
+	gfx_context_t *gc = NULL;
+	test_gc_t tgc;
+
+	memset(&tgc, 0, sizeof(tgc));
+
+	rc = gfx_context_new(&ops, &tgc, &gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	tgc.rc = EOK;
+
+	rc = gfx_set_clip_rect(gc, NULL);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	PCUT_ASSERT_TRUE(tgc.set_clip_rect);
+	PCUT_ASSERT_FALSE(tgc.do_clip);
+
+	rc = gfx_context_delete(gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+/** Set clipping rectangle with error return */
+PCUT_TEST(set_clip_rect_failure)
+{
+	errno_t rc;
+	gfx_rect_t rect;
+	gfx_context_t *gc = NULL;
+	test_gc_t tgc;
+
+	memset(&tgc, 0, sizeof(tgc));
+
+	rc = gfx_context_new(&ops, &tgc, &gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	tgc.rc = EIO;
+
+	rc = gfx_set_clip_rect(gc, &rect);
+	PCUT_ASSERT_ERRNO_VAL(EIO, rc);
+
+	rc = gfx_context_delete(gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+/** Set drawing color */
 PCUT_TEST(set_color)
 {
@@ -60,4 +153,5 @@
 	gfx_color_t *color;
 	gfx_context_t *gc = NULL;
+	uint16_t r, g, b;
 	test_gc_t tgc;
 
@@ -70,8 +164,45 @@
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
+	PCUT_ASSERT_FALSE(tgc.set_color);
+
+	tgc.rc = EOK;
+
 	rc = gfx_set_color(gc, color);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-	PCUT_ASSERT_EQUALS(color, tgc.dclr);
-	PCUT_ASSERT_NULL(tgc.rect);
+
+	PCUT_ASSERT_TRUE(tgc.set_color);
+
+	gfx_color_get_rgb_i16(tgc.dclr, &r, &g, &b);
+
+	PCUT_ASSERT_INT_EQUALS(0xffff, r);
+	PCUT_ASSERT_INT_EQUALS(0xffff, g);
+	PCUT_ASSERT_INT_EQUALS(0xffff, b);
+
+	rc = gfx_context_delete(gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+/** Set drawing color with error return */
+PCUT_TEST(set_color_failure)
+{
+	errno_t rc;
+	gfx_color_t *color;
+	gfx_context_t *gc = NULL;
+	test_gc_t tgc;
+
+	memset(&tgc, 0, sizeof(tgc));
+
+	rc = gfx_context_new(&ops, &tgc, &gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = gfx_color_new_rgb_i16(0xffff, 0xffff, 0xffff, &color);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	PCUT_ASSERT_FALSE(tgc.set_color);
+
+	tgc.rc = EIO;
+
+	rc = gfx_set_color(gc, color);
+	PCUT_ASSERT_ERRNO_VAL(EIO, rc);
 
 	gfx_color_delete(color);
@@ -81,8 +212,8 @@
 }
 
+/** Fill rectangle */
 PCUT_TEST(fill_rect)
 {
 	errno_t rc;
-	gfx_color_t *color;
 	gfx_rect_t rect;
 	gfx_context_t *gc = NULL;
@@ -94,21 +225,56 @@
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
-	rc = gfx_color_new_rgb_i16(0xffff, 0xffff, 0xffff, &color);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	rc = gfx_set_color(gc, color);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-	PCUT_ASSERT_EQUALS(color, tgc.dclr);
+	rect.p0.x = 1;
+	rect.p0.y = 2;
+	rect.p1.x = 3;
+	rect.p1.y = 4;
+
+	PCUT_ASSERT_FALSE(tgc.fill_rect);
+
+	tgc.rc = EOK;
 
 	rc = gfx_fill_rect(gc, &rect);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-	PCUT_ASSERT_EQUALS(&rect, tgc.rect);
-
-	gfx_color_delete(color);
-
-	rc = gfx_context_delete(gc);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-}
-
+
+	PCUT_ASSERT_TRUE(tgc.fill_rect);
+	PCUT_ASSERT_INT_EQUALS(rect.p0.x, tgc.frect.p0.x);
+	PCUT_ASSERT_INT_EQUALS(rect.p0.y, tgc.frect.p0.y);
+	PCUT_ASSERT_INT_EQUALS(rect.p1.x, tgc.frect.p1.x);
+	PCUT_ASSERT_INT_EQUALS(rect.p1.y, tgc.frect.p1.y);
+
+	rc = gfx_context_delete(gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+/** Fill rectangle with error return */
+PCUT_TEST(fill_rect_failure)
+{
+	errno_t rc;
+	gfx_rect_t rect;
+	gfx_context_t *gc = NULL;
+	test_gc_t tgc;
+
+	memset(&tgc, 0, sizeof(tgc));
+
+	rc = gfx_context_new(&ops, &tgc, &gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rect.p0.x = 1;
+	rect.p0.y = 2;
+	rect.p1.x = 3;
+	rect.p1.y = 4;
+
+	PCUT_ASSERT_FALSE(tgc.fill_rect);
+
+	tgc.rc = EIO;
+
+	rc = gfx_fill_rect(gc, &rect);
+	PCUT_ASSERT_ERRNO_VAL(EIO, rc);
+
+	rc = gfx_context_delete(gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+/** Update GC */
 PCUT_TEST(update)
 {
@@ -122,10 +288,49 @@
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
-	PCUT_ASSERT_FALSE(tgc.updated);
-	gfx_update(gc);
-	PCUT_ASSERT_TRUE(tgc.updated);
-
-	rc = gfx_context_delete(gc);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	tgc.rc = EOK;
+
+	PCUT_ASSERT_FALSE(tgc.update);
+	rc = gfx_update(gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_TRUE(tgc.update);
+
+	rc = gfx_context_delete(gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+/** Update GC with error return */
+PCUT_TEST(update_failure)
+{
+	errno_t rc;
+	gfx_context_t *gc = NULL;
+	test_gc_t tgc;
+
+	memset(&tgc, 0, sizeof(tgc));
+
+	rc = gfx_context_new(&ops, &tgc, &gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	tgc.rc = EIO;
+	rc = gfx_update(gc);
+
+	PCUT_ASSERT_ERRNO_VAL(EIO, rc);
+
+	rc = gfx_context_delete(gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	test_gc_t *tgc = (test_gc_t *) arg;
+
+	tgc->set_clip_rect = true;
+	if (rect != NULL) {
+		tgc->do_clip = true;
+		tgc->crect = *rect;
+	} else {
+		tgc->do_clip = false;
+	}
+
+	return tgc->rc;
 }
 
@@ -133,8 +338,10 @@
 {
 	test_gc_t *tgc = (test_gc_t *) arg;
+
+	tgc->set_color = true;
 
 	/* Technically we should copy the data */
 	tgc->dclr = color;
-	return EOK;
+	return tgc->rc;
 }
 
@@ -143,7 +350,7 @@
 	test_gc_t *tgc = (test_gc_t *) arg;
 
-	/* Technically we should copy the data */
-	tgc->rect = rect;
-	return EOK;
+	tgc->fill_rect = true;
+	tgc->frect = *rect;
+	return tgc->rc;
 }
 
@@ -152,6 +359,6 @@
 	test_gc_t *tgc = (test_gc_t *) arg;
 
-	tgc->updated = true;
-	return EOK;
+	tgc->update = true;
+	return tgc->rc;
 }
 
Index: uspace/lib/gfxfont/test/font.c
===================================================================
--- uspace/lib/gfxfont/test/font.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/gfxfont/test/font.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * All rights reserved.
  *
@@ -39,4 +39,5 @@
 PCUT_TEST_SUITE(font);
 
+static errno_t testgc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t testgc_set_color(void *, gfx_color_t *);
 static errno_t testgc_fill_rect(void *, gfx_rect_t *);
@@ -48,4 +49,5 @@
 
 static gfx_context_ops_t test_ops = {
+	.set_clip_rect = testgc_set_clip_rect,
 	.set_color = testgc_set_color,
 	.fill_rect = testgc_fill_rect,
@@ -568,4 +570,9 @@
 		}
 	}
+}
+
+static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	return EOK;
 }
 
Index: uspace/lib/gfxfont/test/glyph.c
===================================================================
--- uspace/lib/gfxfont/test/glyph.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/gfxfont/test/glyph.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * All rights reserved.
  *
@@ -43,4 +43,5 @@
 PCUT_TEST_SUITE(glyph);
 
+static errno_t testgc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t testgc_set_color(void *, gfx_color_t *);
 static errno_t testgc_fill_rect(void *, gfx_rect_t *);
@@ -52,4 +53,5 @@
 
 static gfx_context_ops_t test_ops = {
+	.set_clip_rect = testgc_set_clip_rect,
 	.set_color = testgc_set_color,
 	.fill_rect = testgc_fill_rect,
@@ -567,4 +569,9 @@
 	rc = gfx_context_delete(gc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	return EOK;
 }
 
Index: uspace/lib/gfxfont/test/glyph_bmp.c
===================================================================
--- uspace/lib/gfxfont/test/glyph_bmp.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/gfxfont/test/glyph_bmp.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * All rights reserved.
  *
@@ -39,4 +39,5 @@
 PCUT_TEST_SUITE(glyph_bmp);
 
+static errno_t testgc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t testgc_set_color(void *, gfx_color_t *);
 static errno_t testgc_fill_rect(void *, gfx_rect_t *);
@@ -48,4 +49,5 @@
 
 static gfx_context_ops_t test_ops = {
+	.set_clip_rect = testgc_set_clip_rect,
 	.set_color = testgc_set_color,
 	.fill_rect = testgc_fill_rect,
@@ -581,4 +583,9 @@
 	rc = gfx_context_delete(gc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	return EOK;
 }
 
Index: uspace/lib/gfxfont/test/text.c
===================================================================
--- uspace/lib/gfxfont/test/text.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/gfxfont/test/text.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * All rights reserved.
  *
@@ -40,4 +40,5 @@
 PCUT_TEST_SUITE(text);
 
+static errno_t testgc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t testgc_set_color(void *, gfx_color_t *);
 static errno_t testgc_fill_rect(void *, gfx_rect_t *);
@@ -49,4 +50,5 @@
 
 static gfx_context_ops_t test_ops = {
+	.set_clip_rect = testgc_set_clip_rect,
 	.set_color = testgc_set_color,
 	.fill_rect = testgc_fill_rect,
@@ -145,4 +147,9 @@
 	rc = gfx_context_delete(gc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	return EOK;
 }
 
Index: uspace/lib/gfxfont/test/tpf.c
===================================================================
--- uspace/lib/gfxfont/test/tpf.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/gfxfont/test/tpf.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * All rights reserved.
  *
@@ -41,4 +41,5 @@
 PCUT_TEST_SUITE(tpf);
 
+static errno_t testgc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t testgc_set_color(void *, gfx_color_t *);
 static errno_t testgc_fill_rect(void *, gfx_rect_t *);
@@ -50,4 +51,5 @@
 
 static gfx_context_ops_t test_ops = {
+	.set_clip_rect = testgc_set_clip_rect,
 	.set_color = testgc_set_color,
 	.fill_rect = testgc_fill_rect,
@@ -208,4 +210,9 @@
 }
 
+static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	return EOK;
+}
+
 static errno_t testgc_set_color(void *arg, gfx_color_t *color)
 {
Index: uspace/lib/gfxfont/test/typeface.c
===================================================================
--- uspace/lib/gfxfont/test/typeface.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/gfxfont/test/typeface.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * All rights reserved.
  *
@@ -37,4 +37,5 @@
 PCUT_TEST_SUITE(typeface);
 
+static errno_t testgc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t testgc_set_color(void *, gfx_color_t *);
 static errno_t testgc_fill_rect(void *, gfx_rect_t *);
@@ -46,4 +47,5 @@
 
 static gfx_context_ops_t test_ops = {
+	.set_clip_rect = testgc_set_clip_rect,
 	.set_color = testgc_set_color,
 	.fill_rect = testgc_fill_rect,
@@ -94,4 +96,9 @@
 {
 	// TODO
+}
+
+static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	return EOK;
 }
 
Index: uspace/lib/ipcgfx/include/ipcgfx/ipc/gc.h
===================================================================
--- uspace/lib/ipcgfx/include/ipcgfx/ipc/gc.h	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/ipcgfx/include/ipcgfx/ipc/gc.h	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -39,5 +39,7 @@
 
 typedef enum {
-	GC_SET_RGB_COLOR = IPC_FIRST_USER_METHOD,
+	GC_SET_CLIP_RECT = IPC_FIRST_USER_METHOD,
+	GC_SET_CLIP_RECT_NULL,
+	GC_SET_RGB_COLOR,
 	GC_FILL_RECT,
 	GC_UPDATE,
Index: uspace/lib/ipcgfx/src/client.c
===================================================================
--- uspace/lib/ipcgfx/src/client.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/ipcgfx/src/client.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -45,4 +45,5 @@
 #include "../private/client.h"
 
+static errno_t ipc_gc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t ipc_gc_set_color(void *, gfx_color_t *);
 static errno_t ipc_gc_fill_rect(void *, gfx_rect_t *);
@@ -55,4 +56,5 @@
 
 gfx_context_ops_t ipc_gc_ops = {
+	.set_clip_rect = ipc_gc_set_clip_rect,
 	.set_color = ipc_gc_set_color,
 	.fill_rect = ipc_gc_fill_rect,
@@ -63,4 +65,30 @@
 	.bitmap_get_alloc = ipc_gc_bitmap_get_alloc
 };
+
+/** Set clipping rectangle on IPC GC.
+ *
+ * @param arg IPC GC
+ * @param rect Rectangle
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t ipc_gc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	ipc_gc_t *ipcgc = (ipc_gc_t *) arg;
+	async_exch_t *exch;
+	errno_t rc;
+
+	exch = async_exchange_begin(ipcgc->sess);
+	if (rect != NULL) {
+		rc = async_req_4_0(exch, GC_SET_CLIP_RECT, rect->p0.x, rect->p0.y,
+		    rect->p1.x, rect->p1.y);
+	} else {
+		rc = async_req_0_0(exch, GC_SET_CLIP_RECT_NULL);
+	}
+
+	async_exchange_end(exch);
+
+	return rc;
+}
 
 /** Set color on IPC GC.
Index: uspace/lib/ipcgfx/src/server.c
===================================================================
--- uspace/lib/ipcgfx/src/server.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/ipcgfx/src/server.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -52,4 +52,26 @@
 static ipc_gc_srv_bitmap_t *gc_bitmap_lookup(ipc_gc_srv_t *, sysarg_t);
 
+static void gc_set_clip_rect_srv(ipc_gc_srv_t *srvgc, ipc_call_t *call)
+{
+	gfx_rect_t rect;
+	errno_t rc;
+
+	rect.p0.x = ipc_get_arg1(call);
+	rect.p0.y = ipc_get_arg2(call);
+	rect.p1.x = ipc_get_arg3(call);
+	rect.p1.y = ipc_get_arg4(call);
+
+	rc = gfx_set_clip_rect(srvgc->gc, &rect);
+	async_answer_0(call, rc);
+}
+
+static void gc_set_clip_rect_null_srv(ipc_gc_srv_t *srvgc, ipc_call_t *call)
+{
+	errno_t rc;
+
+	rc = gfx_set_clip_rect(srvgc->gc, NULL);
+	async_answer_0(call, rc);
+}
+
 static void gc_set_rgb_color_srv(ipc_gc_srv_t *srvgc, ipc_call_t *call)
 {
@@ -361,4 +383,10 @@
 
 		switch (method) {
+		case GC_SET_CLIP_RECT:
+			gc_set_clip_rect_srv(&srvgc, &call);
+			break;
+		case GC_SET_CLIP_RECT_NULL:
+			gc_set_clip_rect_null_srv(&srvgc, &call);
+			break;
 		case GC_SET_RGB_COLOR:
 			gc_set_rgb_color_srv(&srvgc, &call);
Index: uspace/lib/ipcgfx/test/ipcgfx.c
===================================================================
--- uspace/lib/ipcgfx/test/ipcgfx.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/ipcgfx/test/ipcgfx.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -50,4 +50,5 @@
 static void test_ipcgc_conn(ipc_call_t *, void *);
 
+static errno_t test_gc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t test_gc_set_color(void *, gfx_color_t *);
 static errno_t test_gc_fill_rect(void *, gfx_rect_t *);
@@ -60,4 +61,5 @@
 
 static gfx_context_ops_t test_gc_ops = {
+	.set_clip_rect = test_gc_set_clip_rect,
 	.set_color = test_gc_set_color,
 	.fill_rect = test_gc_fill_rect,
@@ -75,4 +77,8 @@
 	errno_t rc;
 
+	bool set_clip_rect_called;
+	bool do_clip;
+	gfx_rect_t set_clip_rect_rect;
+
 	bool set_color_called;
 	uint16_t set_color_r;
@@ -103,4 +109,148 @@
 	gfx_bitmap_alloc_t alloc;
 } test_bitmap_t;
+
+/** gfx_set_clip_rect with server returning failure */
+PCUT_TEST(set_clip_rect_failure)
+{
+	errno_t rc;
+	service_id_t sid;
+	test_response_t resp;
+	gfx_context_t *gc;
+	gfx_rect_t rect;
+	async_sess_t *sess;
+	ipc_gc_t *ipcgc;
+
+	async_set_fallback_port_handler(test_ipcgc_conn, &resp);
+
+	// FIXME This causes this test to be non-reentrant!
+	rc = loc_server_register(test_ipcgfx_server);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = loc_service_register(test_ipcgfx_svc, &sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	sess = loc_service_connect(sid, INTERFACE_GC, 0);
+	PCUT_ASSERT_NOT_NULL(sess);
+
+	rc = ipc_gc_create(sess, &ipcgc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	gc = ipc_gc_get_ctx(ipcgc);
+	PCUT_ASSERT_NOT_NULL(gc);
+
+	resp.rc = ENOMEM;
+	resp.set_clip_rect_called = false;
+	rect.p0.x = 1;
+	rect.p0.y = 2;
+	rect.p1.x = 3;
+	rect.p1.y = 4;
+	rc = gfx_set_clip_rect(gc, &rect);
+	PCUT_ASSERT_ERRNO_VAL(resp.rc, rc);
+	PCUT_ASSERT_TRUE(resp.set_clip_rect_called);
+	PCUT_ASSERT_EQUALS(rect.p0.x, resp.set_clip_rect_rect.p0.x);
+	PCUT_ASSERT_EQUALS(rect.p0.y, resp.set_clip_rect_rect.p0.y);
+	PCUT_ASSERT_EQUALS(rect.p1.x, resp.set_clip_rect_rect.p1.x);
+	PCUT_ASSERT_EQUALS(rect.p1.y, resp.set_clip_rect_rect.p1.y);
+
+	ipc_gc_delete(ipcgc);
+	async_hangup(sess);
+
+	rc = loc_service_unregister(sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+/** gfx_set_clip_rect with server returning success */
+PCUT_TEST(set_clip_rect_success)
+{
+	errno_t rc;
+	service_id_t sid;
+	test_response_t resp;
+	gfx_context_t *gc;
+	gfx_rect_t rect;
+	async_sess_t *sess;
+	ipc_gc_t *ipcgc;
+
+	async_set_fallback_port_handler(test_ipcgc_conn, &resp);
+
+	// FIXME This causes this test to be non-reentrant!
+	rc = loc_server_register(test_ipcgfx_server);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = loc_service_register(test_ipcgfx_svc, &sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	sess = loc_service_connect(sid, INTERFACE_GC, 0);
+	PCUT_ASSERT_NOT_NULL(sess);
+
+	rc = ipc_gc_create(sess, &ipcgc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	gc = ipc_gc_get_ctx(ipcgc);
+	PCUT_ASSERT_NOT_NULL(gc);
+
+	resp.rc = EOK;
+	resp.set_clip_rect_called = false;
+	rect.p0.x = 1;
+	rect.p0.y = 2;
+	rect.p1.x = 3;
+	rect.p1.y = 4;
+	rc = gfx_set_clip_rect(gc, &rect);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_TRUE(resp.set_clip_rect_called);
+	PCUT_ASSERT_TRUE(resp.do_clip);
+	PCUT_ASSERT_EQUALS(rect.p0.x, resp.set_clip_rect_rect.p0.x);
+	PCUT_ASSERT_EQUALS(rect.p0.y, resp.set_clip_rect_rect.p0.y);
+	PCUT_ASSERT_EQUALS(rect.p1.x, resp.set_clip_rect_rect.p1.x);
+	PCUT_ASSERT_EQUALS(rect.p1.y, resp.set_clip_rect_rect.p1.y);
+
+	ipc_gc_delete(ipcgc);
+	async_hangup(sess);
+
+	rc = loc_service_unregister(sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+/** gfx_set_clip_rect with null rectangle, server returning success */
+PCUT_TEST(set_clip_rect_null_success)
+{
+	errno_t rc;
+	service_id_t sid;
+	test_response_t resp;
+	gfx_context_t *gc;
+	async_sess_t *sess;
+	ipc_gc_t *ipcgc;
+
+	async_set_fallback_port_handler(test_ipcgc_conn, &resp);
+
+	// FIXME This causes this test to be non-reentrant!
+	rc = loc_server_register(test_ipcgfx_server);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = loc_service_register(test_ipcgfx_svc, &sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	sess = loc_service_connect(sid, INTERFACE_GC, 0);
+	PCUT_ASSERT_NOT_NULL(sess);
+
+	rc = ipc_gc_create(sess, &ipcgc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	gc = ipc_gc_get_ctx(ipcgc);
+	PCUT_ASSERT_NOT_NULL(gc);
+
+	resp.rc = EOK;
+	resp.set_clip_rect_called = false;
+
+	rc = gfx_set_clip_rect(gc, NULL);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_TRUE(resp.set_clip_rect_called);
+	PCUT_ASSERT_FALSE(resp.do_clip);
+
+	ipc_gc_delete(ipcgc);
+	async_hangup(sess);
+
+	rc = loc_service_unregister(sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
 
 /** gfx_set_color with server returning failure */
@@ -234,5 +384,5 @@
 
 	resp.rc = ENOMEM;
-	resp.set_color_called = false;
+	resp.fill_rect_called = false;
 	rect.p0.x = 1;
 	rect.p0.y = 2;
@@ -284,5 +434,5 @@
 
 	resp.rc = EOK;
-	resp.set_color_called = false;
+	resp.fill_rect_called = false;
 	rect.p0.x = 1;
 	rect.p0.y = 2;
@@ -898,4 +1048,26 @@
 }
 
+/** Set clipping rectangle in test GC.
+ *
+ * @param arg Test GC
+ * @param rect Rectangle
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t test_gc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	test_response_t *resp = (test_response_t *) arg;
+
+	resp->set_clip_rect_called = true;
+	if (rect != NULL) {
+		resp->do_clip = true;
+		resp->set_clip_rect_rect = *rect;
+	} else {
+		resp->do_clip = false;
+	}
+
+	return resp->rc;
+}
+
 /** Set color in test GC.
  *
Index: uspace/lib/memgfx/private/memgc.h
===================================================================
--- uspace/lib/memgfx/private/memgc.h	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/memgfx/private/memgc.h	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -49,4 +49,6 @@
 	/** Bounding rectangle */
 	gfx_rect_t rect;
+	/** Clipping rectangle */
+	gfx_rect_t clip_rect;
 	/** Allocation info */
 	gfx_bitmap_alloc_t alloc;
Index: uspace/lib/memgfx/src/memgc.c
===================================================================
--- uspace/lib/memgfx/src/memgc.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/memgfx/src/memgc.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -48,4 +48,5 @@
 #include "../private/memgc.h"
 
+static errno_t mem_gc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t mem_gc_set_color(void *, gfx_color_t *);
 static errno_t mem_gc_fill_rect(void *, gfx_rect_t *);
@@ -59,4 +60,5 @@
 
 gfx_context_ops_t mem_gc_ops = {
+	.set_clip_rect = mem_gc_set_clip_rect,
 	.set_color = mem_gc_set_color,
 	.fill_rect = mem_gc_fill_rect,
@@ -68,4 +70,23 @@
 };
 
+/** Set clipping rectangle on memory GC.
+ *
+ * @param arg Memory GC
+ * @param rect Rectangle
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t mem_gc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	mem_gc_t *mgc = (mem_gc_t *) arg;
+
+	if (rect != NULL)
+		gfx_rect_clip(rect, &mgc->rect, &mgc->clip_rect);
+	else
+		mgc->clip_rect = mgc->rect;
+
+	return EOK;
+}
+
 /** Set color on memory GC.
  *
@@ -102,5 +123,5 @@
 
 	/* Make sure we have a sorted, clipped rectangle */
-	gfx_rect_clip(rect, &mgc->rect, &crect);
+	gfx_rect_clip(rect, &mgc->clip_rect, &crect);
 
 	assert(mgc->rect.p0.x == 0);
@@ -167,4 +188,5 @@
 	mgc->gc = gc;
 	mgc->rect = *rect;
+	mgc->clip_rect = *rect;
 	mgc->alloc = *alloc;
 
@@ -208,4 +230,5 @@
 {
 	mgc->rect = *rect;
+	mgc->clip_rect = *rect;
 	mgc->alloc = *alloc;
 }
@@ -370,4 +393,6 @@
 	gfx_rect_translate(&offs, &srect, &drect);
 
+	/* XXX Clip destination rectangle?! */
+
 	assert(mbm->alloc.pitch == (mbm->rect.p1.x - mbm->rect.p0.x) *
 	    (int)sizeof(uint32_t));
Index: uspace/lib/ui/src/dummygc.c
===================================================================
--- uspace/lib/ui/src/dummygc.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/ui/src/dummygc.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -41,4 +41,5 @@
 #include "../private/dummygc.h"
 
+static errno_t dummygc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t dummygc_set_color(void *, gfx_color_t *);
 static errno_t dummygc_fill_rect(void *, gfx_rect_t *);
@@ -52,4 +53,5 @@
 /** Dummy GC operations */
 gfx_context_ops_t dummygc_ops = {
+	.set_clip_rect = dummygc_set_clip_rect,
 	.set_color = dummygc_set_color,
 	.fill_rect = dummygc_fill_rect,
@@ -105,4 +107,17 @@
 {
 	return dgc->gc;
+}
+
+/** Set clipping rectangle on dummy GC
+ *
+ * @param arg Argument (dummy_gc_t)
+ * @param rect Rectangle
+ * @return EOK on success or an error code
+ */
+static errno_t dummygc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	(void) arg;
+	(void) rect;
+	return EOK;
 }
 
Index: uspace/lib/ui/test/checkbox.c
===================================================================
--- uspace/lib/ui/test/checkbox.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/ui/test/checkbox.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -41,4 +41,5 @@
 PCUT_TEST_SUITE(checkbox);
 
+static errno_t testgc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t testgc_set_color(void *, gfx_color_t *);
 static errno_t testgc_fill_rect(void *, gfx_rect_t *);
@@ -51,4 +52,5 @@
 
 static gfx_context_ops_t ops = {
+	.set_clip_rect = testgc_set_clip_rect,
 	.set_color = testgc_set_color,
 	.fill_rect = testgc_fill_rect,
@@ -481,4 +483,11 @@
 	rc = gfx_context_delete(gc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	(void) arg;
+	(void) rect;
+	return EOK;
 }
 
Index: uspace/lib/ui/test/entry.c
===================================================================
--- uspace/lib/ui/test/entry.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/ui/test/entry.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -41,4 +41,5 @@
 PCUT_TEST_SUITE(entry);
 
+static errno_t testgc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t testgc_set_color(void *, gfx_color_t *);
 static errno_t testgc_fill_rect(void *, gfx_rect_t *);
@@ -51,4 +52,5 @@
 
 static gfx_context_ops_t ops = {
+	.set_clip_rect = testgc_set_clip_rect,
 	.set_color = testgc_set_color,
 	.fill_rect = testgc_fill_rect,
@@ -209,4 +211,11 @@
 	rc = gfx_context_delete(gc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	(void) arg;
+	(void) rect;
+	return EOK;
 }
 
Index: uspace/lib/ui/test/label.c
===================================================================
--- uspace/lib/ui/test/label.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/ui/test/label.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -41,4 +41,5 @@
 PCUT_TEST_SUITE(label);
 
+static errno_t testgc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t testgc_set_color(void *, gfx_color_t *);
 static errno_t testgc_fill_rect(void *, gfx_rect_t *);
@@ -51,4 +52,5 @@
 
 static gfx_context_ops_t ops = {
+	.set_clip_rect = testgc_set_clip_rect,
 	.set_color = testgc_set_color,
 	.fill_rect = testgc_fill_rect,
@@ -209,4 +211,11 @@
 	rc = gfx_context_delete(gc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	(void) arg;
+	(void) rect;
+	return EOK;
 }
 
Index: uspace/lib/ui/test/paint.c
===================================================================
--- uspace/lib/ui/test/paint.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/ui/test/paint.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * All rights reserved.
  *
@@ -39,4 +39,5 @@
 PCUT_TEST_SUITE(paint);
 
+static errno_t testgc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t testgc_set_color(void *, gfx_color_t *);
 static errno_t testgc_fill_rect(void *, gfx_rect_t *);
@@ -48,4 +49,5 @@
 
 static gfx_context_ops_t ops = {
+	.set_clip_rect = testgc_set_clip_rect,
 	.set_color = testgc_set_color,
 	.fill_rect = testgc_fill_rect,
@@ -165,4 +167,11 @@
 	rc = gfx_context_delete(gc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	(void) arg;
+	(void) rect;
+	return EOK;
 }
 
Index: uspace/lib/ui/test/pbutton.c
===================================================================
--- uspace/lib/ui/test/pbutton.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/ui/test/pbutton.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -41,4 +41,5 @@
 PCUT_TEST_SUITE(pbutton);
 
+static errno_t testgc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t testgc_set_color(void *, gfx_color_t *);
 static errno_t testgc_fill_rect(void *, gfx_rect_t *);
@@ -51,4 +52,5 @@
 
 static gfx_context_ops_t ops = {
+	.set_clip_rect = testgc_set_clip_rect,
 	.set_color = testgc_set_color,
 	.fill_rect = testgc_fill_rect,
@@ -488,4 +490,11 @@
 	rc = gfx_context_delete(gc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	(void) arg;
+	(void) rect;
+	return EOK;
 }
 
Index: uspace/lib/ui/test/rbutton.c
===================================================================
--- uspace/lib/ui/test/rbutton.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/ui/test/rbutton.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -41,4 +41,5 @@
 PCUT_TEST_SUITE(rbutton);
 
+static errno_t testgc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t testgc_set_color(void *, gfx_color_t *);
 static errno_t testgc_fill_rect(void *, gfx_rect_t *);
@@ -51,4 +52,5 @@
 
 static gfx_context_ops_t ops = {
+	.set_clip_rect = testgc_set_clip_rect,
 	.set_color = testgc_set_color,
 	.fill_rect = testgc_fill_rect,
@@ -553,4 +555,11 @@
 	rc = gfx_context_delete(gc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	(void) arg;
+	(void) rect;
+	return EOK;
 }
 
Index: uspace/lib/ui/test/slider.c
===================================================================
--- uspace/lib/ui/test/slider.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/ui/test/slider.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -41,4 +41,5 @@
 PCUT_TEST_SUITE(slider);
 
+static errno_t testgc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t testgc_set_color(void *, gfx_color_t *);
 static errno_t testgc_fill_rect(void *, gfx_rect_t *);
@@ -51,4 +52,5 @@
 
 static gfx_context_ops_t ops = {
+	.set_clip_rect = testgc_set_clip_rect,
 	.set_color = testgc_set_color,
 	.fill_rect = testgc_fill_rect,
@@ -428,4 +430,11 @@
 	rc = gfx_context_delete(gc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	(void) arg;
+	(void) rect;
+	return EOK;
 }
 
Index: uspace/lib/ui/test/wdecor.c
===================================================================
--- uspace/lib/ui/test/wdecor.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/lib/ui/test/wdecor.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -41,4 +41,5 @@
 PCUT_TEST_SUITE(wdecor);
 
+static errno_t testgc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t testgc_set_color(void *, gfx_color_t *);
 static errno_t testgc_fill_rect(void *, gfx_rect_t *);
@@ -51,4 +52,5 @@
 
 static gfx_context_ops_t ops = {
+	.set_clip_rect = testgc_set_clip_rect,
 	.set_color = testgc_set_color,
 	.fill_rect = testgc_fill_rect,
@@ -845,4 +847,11 @@
 }
 
+static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	(void) arg;
+	(void) rect;
+	return EOK;
+}
+
 static errno_t testgc_set_color(void *arg, gfx_color_t *color)
 {
Index: uspace/srv/hid/display/clonegc.c
===================================================================
--- uspace/srv/hid/display/clonegc.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/srv/hid/display/clonegc.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * All rights reserved.
  *
@@ -44,4 +44,5 @@
 #include "clonegc.h"
 
+static errno_t ds_clonegc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t ds_clonegc_set_color(void *, gfx_color_t *);
 static errno_t ds_clonegc_fill_rect(void *, gfx_rect_t *);
@@ -65,4 +66,5 @@
 
 gfx_context_ops_t ds_clonegc_ops = {
+	.set_clip_rect = ds_clonegc_set_clip_rect,
 	.set_color = ds_clonegc_set_color,
 	.fill_rect = ds_clonegc_fill_rect,
@@ -73,4 +75,29 @@
 };
 
+/** Set clipping rectangle on clone GC.
+ *
+ * @param arg Clone GC
+ * @param rect Rectangle
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t ds_clonegc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	ds_clonegc_t *cgc = (ds_clonegc_t *)arg;
+	ds_clonegc_output_t *output;
+	errno_t rc;
+
+	output = ds_clonegc_first_output(cgc);
+	while (output != NULL) {
+		rc = gfx_set_clip_rect(output->gc, rect);
+		if (rc != EOK)
+			return rc;
+
+		output = ds_clonegc_next_output(output);
+	}
+
+	return EOK;
+}
+
 /** Set color on clone GC.
  *
Index: uspace/srv/hid/display/test/clonegc.c
===================================================================
--- uspace/srv/hid/display/test/clonegc.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/srv/hid/display/test/clonegc.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * All rights reserved.
  *
@@ -39,4 +39,5 @@
 PCUT_TEST_SUITE(clonegc);
 
+static errno_t testgc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t testgc_set_color(void *, gfx_color_t *);
 static errno_t testgc_fill_rect(void *, gfx_rect_t *);
@@ -48,4 +49,5 @@
 
 static gfx_context_ops_t ops = {
+	.set_clip_rect = testgc_set_clip_rect,
 	.set_color = testgc_set_color,
 	.fill_rect = testgc_fill_rect,
@@ -59,4 +61,7 @@
 	/** Error code to return */
 	errno_t rc;
+
+	bool set_clip_rect_called;
+	gfx_rect_t *set_clip_rect_rect;
 
 	bool set_color_called;
@@ -95,4 +100,74 @@
 	rc = ds_clonegc_create(NULL, &cgc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_clonegc_delete(cgc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+/** Set clipping rectangle with two output GCs */
+PCUT_TEST(set_clip_rect)
+{
+	ds_clonegc_t *cgc;
+	gfx_context_t *gc;
+	test_gc_t tgc1;
+	gfx_context_t *gc1;
+	test_gc_t tgc2;
+	gfx_context_t *gc2;
+	gfx_rect_t rect;
+	errno_t rc;
+
+	/* Create clone GC */
+	rc = ds_clonegc_create(NULL, &cgc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	gc = ds_clonegc_get_ctx(cgc);
+	PCUT_ASSERT_NOT_NULL(gc);
+
+	/* Add two output GCs */
+
+	rc = gfx_context_new(&ops, &tgc1, &gc1);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_clonegc_add_output(cgc, gc1);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = gfx_context_new(&ops, &tgc2, &gc2);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_clonegc_add_output(cgc, gc2);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rect.p0.x = 1;
+	rect.p0.y = 2;
+	rect.p1.x = 3;
+	rect.p1.y = 4;
+
+	/* Set clipping rectangle returning error */
+
+	tgc1.set_clip_rect_called = false;
+	tgc2.set_clip_rect_called = false;
+	tgc1.rc = EINVAL;
+	tgc2.rc = EINVAL;
+
+	rc = gfx_set_clip_rect(gc, &rect);
+	PCUT_ASSERT_ERRNO_VAL(EINVAL, rc);
+
+	PCUT_ASSERT_TRUE(tgc1.set_clip_rect_called);
+	PCUT_ASSERT_EQUALS(&rect, tgc1.set_clip_rect_rect);
+	PCUT_ASSERT_FALSE(tgc2.set_clip_rect_called);
+
+	/* Set clipping rectangle returning success for all outputs */
+	tgc1.set_clip_rect_called = false;
+	tgc2.set_clip_rect_called = false;
+	tgc1.rc = EOK;
+	tgc2.rc = EOK;
+
+	rc = gfx_set_clip_rect(gc, &rect);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	PCUT_ASSERT_TRUE(tgc1.set_clip_rect_called);
+	PCUT_ASSERT_EQUALS(&rect, tgc1.set_clip_rect_rect);
+	PCUT_ASSERT_TRUE(tgc2.set_clip_rect_called);
+	PCUT_ASSERT_EQUALS(&rect, tgc2.set_clip_rect_rect);
 
 	rc = ds_clonegc_delete(cgc);
@@ -628,4 +703,14 @@
 }
 
+static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	test_gc_t *tgc = (test_gc_t *) arg;
+
+	tgc->set_clip_rect_called = true;
+	tgc->set_clip_rect_rect = rect;
+
+	return tgc->rc;
+}
+
 static errno_t testgc_set_color(void *arg, gfx_color_t *color)
 {
Index: uspace/srv/hid/rfb/main.c
===================================================================
--- uspace/srv/hid/rfb/main.c	(revision 252d03cdce4fb131247f5dd8f472481f4b7c3417)
+++ uspace/srv/hid/rfb/main.c	(revision 7470d97aaec04abd08ce2ad450cda9e6ff912bd4)
@@ -1,3 +1,4 @@
 /*
+ * Copyright (c) 2021 Jiri Svoboda
  * Copyright (c) 2013 Martin Sucha
  * All rights reserved.
@@ -50,4 +51,5 @@
 static errno_t rfb_ddev_get_info(void *, ddev_info_t *);
 
+static errno_t rfb_gc_set_clip_rect(void *, gfx_rect_t *);
 static errno_t rfb_gc_set_color(void *, gfx_color_t *);
 static errno_t rfb_gc_fill_rect(void *, gfx_rect_t *);
@@ -66,4 +68,6 @@
 	rfb_t rfb;
 	pixel_t color;
+	gfx_rect_t rect;
+	gfx_rect_t clip_rect;
 } rfb_gc_t;
 
@@ -78,4 +82,5 @@
 
 static gfx_context_ops_t rfb_gc_ops = {
+	.set_clip_rect = rfb_gc_set_clip_rect,
 	.set_color = rfb_gc_set_color,
 	.fill_rect = rfb_gc_fill_rect,
@@ -134,4 +139,49 @@
 }
 
+/** Create RFB GC.
+ *
+ * @param rrgb Place to store pointer to new RFB GC
+ * @return EOK on success, ENOMEM if out of memory
+ */
+static errno_t rgb_gc_create(rfb_gc_t **rrfb)
+{
+	rfb_gc_t *rfb;
+
+	rfb = calloc(1, sizeof(rfb_gc_t));
+	if (rfb == NULL)
+		return ENOMEM;
+
+	*rrfb = rfb;
+	return EOK;
+}
+
+/** Destroy RFB GC.
+ *
+ * @param rfb RFB GC
+ */
+static void rfb_gc_destroy(rfb_gc_t *rfb)
+{
+	free(rfb);
+}
+
+/** Set clipping rectangle on RFB.
+ *
+ * @param arg RFB
+ * @param rect Rectangle or @c NULL
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t rfb_gc_set_clip_rect(void *arg, gfx_rect_t *rect)
+{
+	rfb_gc_t *rfb = (rfb_gc_t *) arg;
+
+	if (rect != NULL)
+		gfx_rect_clip(rect, &rfb->rect, &rfb->clip_rect);
+	else
+		rfb->clip_rect = rfb->rect;
+
+	return EOK;
+}
+
 /** Set color on RFB.
  *
@@ -163,10 +213,11 @@
 {
 	rfb_gc_t *rfb = (rfb_gc_t *) arg;
+	gfx_rect_t crect;
 	gfx_coord_t x, y;
 
-	// XXX We should handle p0.x > p1.x and p0.y > p1.y
-
-	for (y = rect->p0.y; y < rect->p1.y; y++) {
-		for (x = rect->p0.x; x < rect->p1.x; x++) {
+	gfx_rect_clip(rect, &rfb->clip_rect, &crect);
+
+	for (y = crect.p0.y; y < crect.p1.y; y++) {
+		for (x = crect.p0.x; x < crect.p1.x; x++) {
 			pixelmap_put_pixel(&rfb->rfb.framebuffer, x, y,
 			    rfb->color);
@@ -174,5 +225,5 @@
 	}
 
-	rfb_gc_invalidate_rect(rfb, rect);
+	rfb_gc_invalidate_rect(rfb, &crect);
 
 	return EOK;
@@ -258,4 +309,5 @@
 	gfx_rect_t srect;
 	gfx_rect_t drect;
+	gfx_rect_t crect;
 	gfx_coord2_t offs;
 	gfx_coord2_t bmdim;
@@ -279,5 +331,6 @@
 	/* Destination rectangle */
 	gfx_rect_translate(&offs, &srect, &drect);
-	gfx_coord2_subtract(&drect.p1, &drect.p0, &dim);
+	gfx_rect_clip(&drect, &rfbbm->rfb->clip_rect, &crect);
+	gfx_coord2_subtract(&crect.p1, &crect.p0, &dim);
 	gfx_coord2_subtract(&rfbbm->rect.p1, &rfbbm->rect.p0, &bmdim);
 
@@ -320,5 +373,5 @@
 	}
 
-	rfb_gc_invalidate_rect(rfbbm->rfb, &drect);
+	rfb_gc_invalidate_rect(rfbbm->rfb, &crect);
 
 	return EOK;
@@ -346,4 +399,5 @@
 {
 	rfb_t *rfb = (rfb_t *) arg;
+	rfb_gc_t *rfbgc;
 	ddev_srv_t srv;
 	sysarg_t svc_id;
@@ -362,6 +416,19 @@
 		ddev_conn(icall, &srv);
 	} else {
-		rc = gfx_context_new(&rfb_gc_ops, (void *) rfb, &gc);
+		rc = rgb_gc_create(&rfbgc);
 		if (rc != EOK) {
+			async_answer_0(icall, ENOMEM);
+			return;
+		}
+
+		rfbgc->rect.p0.x = 0;
+		rfbgc->rect.p0.y = 0;
+		rfbgc->rect.p1.x = rfb->width;
+		rfbgc->rect.p1.y = rfb->height;
+		rfbgc->clip_rect = rfbgc->rect;
+
+		rc = gfx_context_new(&rfb_gc_ops, (void *) rfbgc, &gc);
+		if (rc != EOK) {
+			rfb_gc_destroy(rfbgc);
 			async_answer_0(icall, ENOMEM);
 			return;
