Index: uspace/app/gfxdemo/gfxdemo.c
===================================================================
--- uspace/app/gfxdemo/gfxdemo.c	(revision ae634f4aff29f2307762aa24f62038b3fb4ae12a)
+++ uspace/app/gfxdemo/gfxdemo.c	(revision 8dbd13d0cc7a96fe917780001de3568ece3d7da7)
@@ -69,4 +69,7 @@
 
 static bool quit = false;
+static gfx_typeface_t *tface;
+static gfx_font_t *font;
+static gfx_coord_t vpad;
 
 /** Clear screen.
@@ -107,9 +110,153 @@
 }
 
-/** Run rectangle demo on a graphic context.
+/** Initialize demo font.
  *
  * @param gc Graphic context
  * @param w Width
  * @param h Height
+ * @return EOK on success or an error code
+ */
+static errno_t demo_font_init(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
+{
+	gfx_font_info_t *finfo;
+	errno_t rc;
+
+	if (quit)
+		return EOK;
+
+	/* XXX Crude way of detecting text mode */
+	if (w < 256) {
+		/* Create dummy font for text mode */
+		rc = gfx_typeface_create(gc, &tface);
+		if (rc != EOK) {
+			printf("Error creating typeface\n");
+			goto error;
+		}
+
+		rc = gfx_font_create_textmode(tface, &font);
+		if (rc != EOK) {
+			printf("Error creating font\n");
+			goto error;
+		}
+
+		vpad = 0;
+	} else {
+		/* Load font */
+		rc = gfx_typeface_open(gc, "/data/font/helena.tpf", &tface);
+		if (rc != EOK) {
+			printf("Error opening typeface\n");
+			goto error;
+		}
+
+		finfo = gfx_typeface_first_font(tface);
+		if (finfo == NULL) {
+			printf("Typeface contains no font.\n");
+			rc = ENOENT;
+			goto error;
+		}
+
+		rc = gfx_font_open(finfo, &font);
+		if (rc != EOK) {
+			printf("Error opening font.\n");
+			goto error;
+		}
+
+		vpad = 5;
+	}
+
+	return EOK;
+error:
+	if (tface != NULL)
+		gfx_typeface_destroy(tface);
+	return rc;
+}
+
+/** Finalize demo font. */
+static void demo_font_fini(void)
+{
+	if (font == NULL)
+		return;
+
+	gfx_font_close(font);
+	font = NULL;
+
+	gfx_typeface_destroy(tface);
+	tface = NULL;
+}
+
+/** Start a new demo screen.
+ *
+ * Clear the screen, display a status line and set up clipping.
+ *
+ * @param gc Graphic context
+ * @param w Width
+ * @param h Height
+ * @param text Demo screen description
+ * @return EOK on success or an error code
+ */
+static errno_t demo_begin(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h,
+    const char *text)
+{
+	gfx_text_fmt_t fmt;
+	gfx_font_metrics_t metrics;
+	gfx_coord2_t pos;
+	gfx_color_t *color;
+	gfx_rect_t rect;
+	gfx_coord_t height;
+	errno_t rc;
+
+	rc = gfx_set_clip_rect(gc, NULL);
+	if (rc != EOK)
+		return rc;
+
+	rc = clear_scr(gc, w, h);
+	if (rc != EOK)
+		return rc;
+
+	if (font != NULL) {
+		rc = gfx_color_new_rgb_i16(0xffff, 0xffff, 0xffff, &color);
+		if (rc != EOK)
+			goto error;
+
+		gfx_text_fmt_init(&fmt);
+		fmt.color = color;
+		fmt.halign = gfx_halign_center;
+		fmt.valign = gfx_valign_bottom;
+
+		pos.x = w / 2;
+		pos.y = h - 1;
+		rc = gfx_puttext(font, &pos, &fmt, text);
+		if (rc != EOK) {
+			printf("Error rendering text.\n");
+			gfx_color_delete(color);
+			goto error;
+		}
+
+		gfx_color_delete(color);
+
+		gfx_font_get_metrics(font, &metrics);
+		height = metrics.ascent + metrics.descent + 1;
+	} else {
+		height = 0;
+	}
+
+	rect.p0.x = 0;
+	rect.p0.y = 0;
+	rect.p1.x = w;
+	rect.p1.y = h - height - vpad;
+	rc = gfx_set_clip_rect(gc, &rect);
+	if (rc != EOK)
+		return rc;
+
+	return EOK;
+error:
+	return rc;
+}
+
+/** Run rectangle demo on a graphic context.
+ *
+ * @param gc Graphic context
+ * @param w Width
+ * @param h Height
  */
 static errno_t demo_rects(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
@@ -123,5 +270,5 @@
 		return EOK;
 
-	rc = clear_scr(gc, w, h);
+	rc = demo_begin(gc, w, h, "Rectangle rendering");
 	if (rc != EOK)
 		return rc;
@@ -282,5 +429,5 @@
 		return EOK;
 
-	rc = clear_scr(gc, w, h);
+	rc = demo_begin(gc, w, h, "Bitmap rendering without offset");
 	if (rc != EOK)
 		return rc;
@@ -345,5 +492,5 @@
 		return EOK;
 
-	rc = clear_scr(gc, w, h);
+	rc = demo_begin(gc, w, h, "Bitmap rendering with offset");
 	if (rc != EOK)
 		return rc;
@@ -404,5 +551,5 @@
 		return EOK;
 
-	rc = clear_scr(gc, w, h);
+	rc = demo_begin(gc, w, h, "Bitmap rendering with color key");
 	if (rc != EOK)
 		return rc;
@@ -505,5 +652,5 @@
 	}
 
-	rc = clear_scr(gc, w, h);
+	rc = demo_begin(gc, w, h, "Text rendering");
 	if (rc != EOK)
 		goto error;
@@ -542,7 +689,7 @@
 
 	rect.p0.x = w / 20;
-	rect.p0.y = 2 * h / 15;
+	rect.p0.y = 1 * h / 15;
 	rect.p1.x = w - w / 20;
-	rect.p1.y = 5 * h / 15;
+	rect.p1.y = 4 * h / 15;
 
 	rc = gfx_fill_rect(gc, &rect);
@@ -640,5 +787,5 @@
 
 		pos.x = w / 20;
-		pos.y = (7 + i) * h / 15;
+		pos.y = (6 + i) * h / 15;
 		rc = gfx_puttext(font, &pos, &fmt, "The quick brown fox jumps over the lazy dog.");
 		if (rc != EOK)
@@ -684,5 +831,5 @@
 		return EOK;
 
-	rc = clear_scr(gc, w, h);
+	rc = demo_begin(gc, w, h, "Clipping demonstration");
 	if (rc != EOK)
 		return rc;
@@ -777,31 +924,37 @@
 	errno_t rc;
 
+	(void) demo_font_init(gc, w, h);
+
 	while (!quit) {
 		rc = demo_rects(gc, w, h);
 		if (rc != EOK)
-			return rc;
+			goto error;
 
 		rc = demo_bitmap(gc, w, h);
 		if (rc != EOK)
-			return rc;
+			goto error;
 
 		rc = demo_bitmap2(gc, w, h);
 		if (rc != EOK)
-			return rc;
+			goto error;
 
 		rc = demo_bitmap_kc(gc, w, h);
 		if (rc != EOK)
-			return rc;
+			goto error;
 
 		rc = demo_text(gc, w, h);
 		if (rc != EOK)
-			return rc;
+			goto error;
 
 		rc = demo_clip(gc, w, h);
 		if (rc != EOK)
-			return rc;
-	}
-
-	return EOK;
+			goto error;
+	}
+
+	demo_font_fini();
+	return EOK;
+error:
+	demo_font_fini();
+	return rc;
 }
 
