Index: fb/fb.c
===================================================================
--- fb/fb.c	(revision a2ae4f41971fbd500371cd3a751906ff798ad764)
+++ fb/fb.c	(revision 88c315148b0d6fc3b1a63c2a832ea0190a3367cc)
@@ -78,5 +78,5 @@
 	int bgcolor, fgcolor;
 	/* Auto-cursor position */
-	int cursor_active, cur_x, cur_y;
+	int cursor_active, cur_col, cur_row;
 } viewport_t;
 
@@ -197,10 +197,4 @@
 	}	
 }
-
-/** Optimized scroll for windows that cover whole lines */
-//static void scroll_optim(int vp, int rows)
-//{
-	/* TODO */
-//}
 
 /** Scroll port up/down 
@@ -323,5 +317,10 @@
 		return ELIMIT;
 
-	viewports[i].initialized = 1;
+	if (width ==0 || height == 0 ||
+	    x+width > screen.xres || y+height > screen.yres)
+		return EINVAL;
+	if (width < FONT_SCANLINES || height < COL_WIDTH)
+		return EINVAL;
+
 	viewports[i].x = x;
 	viewports[i].y = y;
@@ -335,4 +334,6 @@
 	viewports[i].fgcolor = DEFAULT_FGCOLOR;
 	
+	viewports[i].initialized = 1;
+
 	return i;
 }
@@ -415,4 +416,25 @@
 }
 
+static void draw_char(int vp, char c, unsigned int col, unsigned int row)
+{
+	viewport_t *vport = &viewports[vp];
+
+	if (vport->cursor_active && (vport->cur_col != col || vport->cur_row != row))
+		invert_char(vp, vport->cur_col,vport->cur_row);
+	
+	draw_glyph(vp, c, col, row);
+	
+	if (vport->cursor_active) {
+		vport->cur_col++;
+		if (vport->cur_col>= vport->cols) {
+			vport->cur_col = 0;
+			vport->cur_row++;
+			if (vport->cur_row >= vport->rows)
+				vport->cur_row--;
+		}
+		invert_char(vp, vport->cur_col,vport->cur_row);
+	}
+}
+
 void client_connection(ipc_callid_t iid, ipc_call_t *icall)
 {
@@ -423,5 +445,7 @@
 	unsigned int row,col;
 	char c;
+
 	int vp = 0;
+	viewport_t *vport = &viewports[0];
 
 	if (client_connected) {
@@ -429,4 +453,5 @@
 		return;
 	}
+	client_connected = 1;
 	ipc_answer_fast(iid, 0, 0, 0); /* Accept connection */
 
@@ -438,5 +463,5 @@
 			/* cleanup other viewports */
 			for (i=1; i < MAX_VIEWPORTS; i++)
-				viewports[i].initialized = 0;
+				vport->initialized = 0;
 			ipc_answer_fast(callid,0,0,0);
 			return; /* Exit thread */
@@ -445,28 +470,102 @@
 			row = IPC_GET_ARG2(call);
 			col = IPC_GET_ARG3(call);
-			if (row >= viewports[vp].rows || col >= viewports[vp].cols) {
+			if (row >= vport->rows || col >= vport->cols) {
 				retval = EINVAL;
 				break;
 			}
 			ipc_answer_fast(callid,0,0,0);
-			draw_glyph(vp,c, row, col);
+
+			draw_char(vp, c, row, col);
 			continue; /* msg already answered */
 		case FB_CLEAR:
 			clear_port(vp);
+			if (vport->cursor_active)
+				invert_char(vp, vport->cur_col,vport->cur_row);
 			retval = 0;
 			break;
-/* 		case FB_CURSOR_GOTO: */
-/* 			retval = 0; */
-/* 			break; */
-/* 		case FB_CURSOR_VISIBILITY: */
-/* 			retval = 0; */
-/* 			break; */
+ 		case FB_CURSOR_GOTO:
+			row = IPC_GET_ARG1(call);
+			col = IPC_GET_ARG2(call);
+			if (row >= vport->rows || col >= vport->cols) {
+				retval = EINVAL;
+				break;
+			}
+ 			retval = 0;
+			if (viewports[vp].cursor_active) {
+				invert_char(vp, vport->cur_col,vport->cur_row);
+				invert_char(vp, col, row);
+			}
+			vport->cur_col = col;
+			vport->cur_row = row;
+ 			break;
+		case FB_CURSOR_VISIBILITY:
+			i = IPC_GET_ARG1(call);
+			retval = 0;
+			if ((i && vport->cursor_active) || (!i && !vport->cursor_active))
+				break;
+
+			vport->cursor_active = i;
+			invert_char(vp, vport->cur_col,vport->cur_row);
+			break;
 		case FB_GET_CSIZE:
-			ipc_answer_fast(callid, 0, viewports[vp].rows, viewports[vp].cols);
+			ipc_answer_fast(callid, 0, vport->rows, vport->cols);
+			continue;
+		case FB_SCROLL:
+			i = IPC_GET_ARG1(call);
+			if (i > vport->rows || i < (- (int)vport->rows)) {
+				retval = EINVAL;
+				break;
+			}
+			if (vport->cursor_active)
+				invert_char(vp, vport->cur_col,vport->cur_row);
+			scroll_port(vp, i);
+			if (vport->cursor_active)
+				invert_char(vp, vport->cur_col,vport->cur_row);
+			retval = 0;
+			break;
+		case FB_VIEWPORT_SWITCH:
+			i = IPC_GET_ARG1(call);
+			if (i < 0 || i >= MAX_VIEWPORTS) {
+				retval = EINVAL;
+				break;
+			}
+			if (! viewports[i].initialized ) {
+				retval = EADDRNOTAVAIL;
+				break;
+			}
+			vp = i;
+			vport = &viewports[vp];
+			retval = 0;
+			break;
+		case FB_VIEWPORT_CREATE:
+			retval = viewport_create(IPC_GET_ARG1(call) >> 16,
+						 IPC_GET_ARG1(call) & 0xffff,
+						 IPC_GET_ARG2(call) >> 16,
+						 IPC_GET_ARG2(call) & 0xffff);
+			break;
+		case FB_VIEWPORT_DELETE:
+			i = IPC_GET_ARG1(call);
+			if (i < 0 || i >= MAX_VIEWPORTS) {
+				retval = EINVAL;
+				break;
+			}
+			if (! viewports[i].initialized ) {
+				retval = EADDRNOTAVAIL;
+				break;
+			}
+			viewports[i].initialized = 0;
+			retval = 0;
+			break;
+		case FB_SET_STYLE:
+			vport->fgcolor = IPC_GET_ARG1(call);
+			vport->bgcolor = IPC_GET_ARG2(call);
+			retval = 0;
+			break;
+		case FB_GET_RESOLUTION:
+			ipc_answer_fast(callid, 0, screen.xres,screen.yres);
 			continue;
 		default:
 			retval = ENOENT;
 		}
-		retval = ENOENT;
 		ipc_answer_fast(callid,retval,0,0);
 	}
Index: init/init.c
===================================================================
--- init/init.c	(revision a2ae4f41971fbd500371cd3a751906ff798ad764)
+++ init/init.c	(revision 88c315148b0d6fc3b1a63c2a832ea0190a3367cc)
@@ -381,8 +381,7 @@
 	ipcarg_t result;
 	int phoneid;
+	int vp;
 
 //	printf("Test: Starting connect...\n");
-
-	phoneid = ipc_connect_me_to(PHONE_NS, SERVICE_VIDEO, 0);
 
 	while ((phoneid = ipc_connect_me_to(PHONE_NS, SERVICE_VIDEO, 0)) < 0) {
@@ -391,13 +390,12 @@
 	};
 	
-//	printf("Test: Connected: %d\n", res);
-//	printf("Test: pinging.\n");
-	while (1) {
-		res = ipc_call_sync(phoneid, FB_GET_VFB, 0xbeef,&result);
-//		printf("Test: Retval: %d - received: %c\n", res, result);
-//		printf("%c", result);
-	}
-	
-//	printf("Test: Hangin up\n");
+	usleep(100000);
+	vp = ipc_call_sync_3(phoneid, FB_VIEWPORT_CREATE, (200 << 16) | 300, (200 << 16) | 150,0,NULL,NULL,NULL);
+	if (! ipc_call_sync(phoneid, FB_VIEWPORT_SWITCH, vp, NULL)) {
+		ipc_call_sync_2(phoneid, FB_SET_STYLE, 0, 0xffffff, NULL, NULL);
+		ipc_call_sync(phoneid, FB_CLEAR, 0, NULL);
+		ipc_call_sync_3(phoneid, FB_PUTCHAR, 'X', 0,0, NULL, NULL, NULL);
+	}
+
 	ipc_hangup(phoneid);
 }
@@ -448,5 +446,5 @@
 //	test_async_kbd();
 //	test_fb();
-	test_console();
+//	test_console();
 
 	printf("\nBye.\n");
Index: libc/include/ipc/fb.h
===================================================================
--- libc/include/ipc/fb.h	(revision a2ae4f41971fbd500371cd3a751906ff798ad764)
+++ libc/include/ipc/fb.h	(revision 88c315148b0d6fc3b1a63c2a832ea0190a3367cc)
@@ -7,8 +7,15 @@
 #define __libc__FB_H__
 
-#define FB_PUTCHAR     1025
-#define FB_CLEAR       1026
-#define FB_GET_CSIZE   1027
-
+#define FB_PUTCHAR           1025
+#define FB_CLEAR             1026
+#define FB_GET_CSIZE         1027
+#define FB_CURSOR_VISIBILITY 1028
+#define FB_CURSOR_GOTO       1029
+#define FB_SCROLL            1030
+#define FB_VIEWPORT_SWITCH   1031
+#define FB_VIEWPORT_CREATE   1032
+#define FB_VIEWPORT_DELETE   1033
+#define FB_SET_STYLE         1034
+#define FB_GET_RESOLUTION    1035
 
 #endif
