Index: console/console.c
===================================================================
--- console/console.c	(revision dc5a0fe1f6cd378525f19e69830be5e2cec0d779)
+++ console/console.c	(revision 429acb9556734369795e31b2cdc6cf1d1080c35d)
@@ -70,6 +70,8 @@
 } connection_t;
 
-connection_t connections[CONSOLE_COUNT];	/**< Array of data for virtual consoles */
-keyfield_t *interbuffer = NULL;			/**< Pointer to memory shared with framebufer used for faster virt. console switching */
+static connection_t connections[CONSOLE_COUNT];	/**< Array of data for virtual consoles */
+static keyfield_t *interbuffer = NULL;			/**< Pointer to memory shared with framebufer used for faster virt. console switching */
+
+static int kernel_pixmap = -1;      /**< Number of fb pixmap, where kernel console is stored */
 
 
@@ -104,4 +106,36 @@
 }
 
+static void clrscr(void)
+{
+	nsend_call(fb_info.phone, FB_CLEAR, 0);
+}
+
+static void curs_visibility(int v)
+{
+	send_call(fb_info.phone, FB_CURSOR_VISIBILITY, v); 
+}
+
+static void curs_goto(int row, int col)
+{
+	nsend_call_2(fb_info.phone, FB_CURSOR_GOTO, row, col); 
+	
+}
+
+static void set_style(style_t *style)
+{
+	nsend_call_2(fb_info.phone, FB_SET_STYLE, style->fg_color, style->bg_color); 
+}
+
+static void set_style_col(int fgcolor, int bgcolor)
+{
+	nsend_call_2(fb_info.phone, FB_SET_STYLE, fgcolor, bgcolor); 
+}
+
+static void prtchr(char c, int row, int col)
+{
+	nsend_call_3(fb_info.phone, FB_PUTCHAR, c, row, col);
+	
+}
+
 /** Check key and process special keys. 
  *
@@ -128,7 +162,6 @@
 			scr->position_x--;
 
-			if (console == active_console) {
-				nsend_call_3(fb_info.phone, FB_PUTCHAR, ' ', scr->position_y, scr->position_x);
-			}
+			if (console == active_console)
+				prtchr(' ', scr->position_y, scr->position_x);
 	
 			screenbuffer_putchar(scr, ' ');
@@ -136,7 +169,6 @@
 			break;
 		default:	
-			if (console == active_console) {
-				nsend_call_3(fb_info.phone, FB_PUTCHAR, key, scr->position_y, scr->position_x);
-			}
+			if (console == active_console)
+				prtchr(key, scr->position_y, scr->position_x);
 	
 			screenbuffer_putchar(scr, key);
@@ -155,9 +187,95 @@
 	scr->position_x = scr->position_x % scr->size_x;
 	
-	if (console == active_console)	
-		send_call_2(fb_info.phone, FB_CURSOR_GOTO, scr->position_y, scr->position_x);
-	
-}
-
+	if (console == active_console)
+		curs_goto(scr->position_y, scr->position_x);
+	
+}
+
+/** Save current screen to pixmap, draw old pixmap
+ *
+ * @param oldpixmap Old pixmap
+ * @return ID of pixmap of current screen
+ */
+static int switch_screens(int oldpixmap)
+{
+	int newpmap;
+       
+	/* Save screen */
+	newpmap = sync_send(fb_info.phone, FB_VP2PIXMAP, 0, NULL);
+	if (newpmap < 0)
+		return -1;
+
+	if (oldpixmap != -1) {
+		/* Show old screen */
+		nsend_call_2(fb_info.phone, FB_VP_DRAW_PIXMAP, 0, oldpixmap);
+		/* Drop old pixmap */
+		nsend_call(fb_info.phone, FB_DROP_PIXMAP, oldpixmap);
+	}
+	
+	return newpmap;
+}
+
+/** Switch to new console */
+static void change_console(int newcons)
+{
+	connection_t *conn;
+	static int console_pixmap = -1;
+	int i, j;
+	char c;
+
+	if (newcons == active_console)
+		return;
+
+	if (newcons == -1) {
+		if (active_console == -1)
+			return;
+		active_console = -1;
+		curs_visibility(0);
+
+		if (kernel_pixmap == -1) { 
+			/* store/restore unsupported */
+			set_style_col(DEFAULT_FOREGROUND, DEFAULT_BACKGROUND);
+			clrscr();
+		} else {
+			gcons_in_kernel();
+			console_pixmap = switch_screens(kernel_pixmap);
+			kernel_pixmap = -1;
+		}
+
+		__SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE);
+		return;
+	} 
+	
+	if (console_pixmap != -1) {
+		kernel_pixmap = switch_screens(console_pixmap);
+		console_pixmap = -1;
+	}
+	
+	active_console = newcons;
+	gcons_change_console(newcons);
+	conn = &connections[active_console];
+
+	curs_visibility(0);
+	if (interbuffer) {
+		for (i = 0; i < conn->screenbuffer.size_x; i++)
+			for (j = 0; j < conn->screenbuffer.size_y; j++) 
+				interbuffer[i + j*conn->screenbuffer.size_x] = *get_field_at(&(conn->screenbuffer),i, j);
+		
+		sync_send_2(fb_info.phone, FB_DRAW_TEXT_DATA, 0, 0, NULL, NULL);		
+	} else {
+		clrscr();
+		
+		for (i = 0; i < conn->screenbuffer.size_x; i++)
+			for (j = 0; j < conn->screenbuffer.size_y; j++) {
+				c = get_field_at(&(conn->screenbuffer),i, j)->character;
+				if (c && c != ' ')
+					prtchr(c, j, i);
+			}
+		
+	}
+	curs_goto(conn->screenbuffer.position_y, conn->screenbuffer.position_x);
+	set_style(&conn->screenbuffer.style);
+	curs_visibility(1);
+}
 
 /** Handler for keyboard */
@@ -167,6 +285,5 @@
 	ipc_call_t call;
 	int retval;
-	int i, j;
-	char c,d;
+	char c;
 	connection_t *conn;
 	
@@ -189,49 +306,8 @@
 //			if ((c >= KBD_KEY_F1) && (c < KBD_KEY_F1 + CONSOLE_COUNT)) {
 			if ((c >= '0') && (c < '0' + CONSOLE_COUNT)) {
-				if (c == '0') {
-					/* switch to kernel console*/
-					nsend_call(fb_info.phone, FB_CURSOR_VISIBILITY, 0); 
-					nsend_call_2(fb_info.phone, FB_SET_STYLE, DEFAULT_FOREGROUND_COLOR, DEFAULT_BACKGROUND_COLOR); 
-					nsend_call(fb_info.phone, FB_CLEAR, 0); 
-					/* FIXME: restore kernel console */
-					 __SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE);
-					 break;
-					 
-				} else {
-					c = c - '1';
-					if (c == active_console)
-						break;
-					active_console = c;
-					gcons_change_console(c);
-				
-				}
-				
-				conn = &connections[active_console];
-
-				nsend_call(fb_info.phone, FB_CURSOR_VISIBILITY, 0); 
-		
-				if (interbuffer) {
-					for (i = 0; i < conn->screenbuffer.size_x; i++)
-						for (j = 0; j < conn->screenbuffer.size_y; j++) 
-							interbuffer[i + j*conn->screenbuffer.size_x] = *get_field_at(&(conn->screenbuffer),i, j);
-							
-					sync_send_2(fb_info.phone, FB_DRAW_TEXT_DATA, 0, 0, NULL, NULL);		
-				} else {
-					nsend_call(fb_info.phone, FB_CLEAR, 0);
-				
-					
-					for (i = 0; i < conn->screenbuffer.size_x; i++)
-						for (j = 0; j < conn->screenbuffer.size_y; j++) {
-							d = get_field_at(&(conn->screenbuffer),i, j)->character;
-							if (d && d != ' ')
-								nsend_call_3(fb_info.phone, FB_PUTCHAR, d, j, i);
-						}
-
-				}
-				nsend_call_2(fb_info.phone, FB_CURSOR_GOTO, conn->screenbuffer.position_y, conn->screenbuffer.position_x); 
-				nsend_call_2(fb_info.phone, FB_SET_STYLE, conn->screenbuffer.style.fg_color, \
-						conn->screenbuffer.style.bg_color); 
-				send_call(fb_info.phone, FB_CURSOR_VISIBILITY, 1); 
-
+				if (c == '0')
+					change_console(-1);
+				else
+					change_console(c - '1');
 				break;
 			}
@@ -315,5 +391,5 @@
 			screenbuffer_set_style(&(connections[consnum].screenbuffer),arg1, arg2);
 			if (consnum == active_console)
-				nsend_call_2(fb_info.phone, FB_SET_STYLE, arg1, arg2); 
+				set_style_col(arg1, arg2);
 				
 			break;
@@ -362,4 +438,7 @@
 		usleep(10000);
 	}
+	
+	/* Save old kernel screen */
+	kernel_pixmap = switch_screens(-1);
 
 	/* Initialize gcons */
@@ -370,6 +449,6 @@
 	
 	ipc_call_sync_2(fb_info.phone, FB_GET_CSIZE, 0, 0, &(fb_info.rows), &(fb_info.cols)); 
-	nsend_call_2(fb_info.phone, FB_SET_STYLE, DEFAULT_FOREGROUND_COLOR, DEFAULT_BACKGROUND_COLOR); 
-	nsend_call(fb_info.phone, FB_CLEAR, 0); 
+	set_style_col(DEFAULT_FOREGROUND, DEFAULT_BACKGROUND);
+	clrscr();
 	
 	/* Init virtual consoles */
@@ -395,6 +474,4 @@
 	}
 
-	/* FIXME: save kernel console screen */
-	
 	async_new_connection(phonehash, 0, NULL, keyboard_events);
 	
Index: console/gcons.c
===================================================================
--- console/gcons.c	(revision dc5a0fe1f6cd378525f19e69830be5e2cec0d779)
+++ console/gcons.c	(revision 429acb9556734369795e31b2cdc6cf1d1080c35d)
@@ -126,6 +126,7 @@
 	if (!use_gcons)
 		return;
-	
-	draw_stat(active_console, CONS_IDLE);
+
+	if (active_console != -1)
+		draw_stat(active_console, CONS_IDLE);
 	active_console = consnum;
 	draw_stat(consnum, CONS_ACTIVE);
@@ -135,4 +136,5 @@
 }
 
+/** Notification function that gets called on new output to virtual console */
 void gcons_notify_char(int consnum)
 {
@@ -144,9 +146,29 @@
 
 	console_has_input[consnum] = 1;
+
+	if (active_console == -1)
+		return;
+
 	draw_stat(consnum, CONS_HAS_INPUT);
 	
 	vp_switch(console_vp);
-}
-
+
+}
+
+/** Change to kernel console */
+void gcons_in_kernel(void)
+{
+	draw_stat(active_console, CONS_IDLE);
+	active_console = -1; /* Set to kernel console */
+	vp_switch(0);
+}
+
+/** Draw a PPM pixmap to framebuffer
+ *
+ * @param logo Pointer to PPM data
+ * @param size Size of PPM data
+ * @param x Coordinate of upper left corner
+ * @param y Coordinate of upper left corner
+ */
 static void draw_pixmap(char *logo, size_t size, int x, int y)
 {
Index: console/gcons.h
===================================================================
--- console/gcons.h	(revision dc5a0fe1f6cd378525f19e69830be5e2cec0d779)
+++ console/gcons.h	(revision 429acb9556734369795e31b2cdc6cf1d1080c35d)
@@ -33,4 +33,5 @@
 void gcons_change_console(int consnum);
 void gcons_notify_char(int consnum);
+void gcons_in_kernel(void);
 
 #endif
Index: console/screenbuffer.h
===================================================================
--- console/screenbuffer.h	(revision dc5a0fe1f6cd378525f19e69830be5e2cec0d779)
+++ console/screenbuffer.h	(revision 429acb9556734369795e31b2cdc6cf1d1080c35d)
@@ -31,6 +31,6 @@
 
 
-#define DEFAULT_FOREGROUND_COLOR 0xffffff	/**< default console foreground color */
-#define DEFAULT_BACKGROUND_COLOR 0x00003f	/**< default console background color */
+#define DEFAULT_FOREGROUND 0xffff00	/**< default console foreground color */
+#define DEFAULT_BACKGROUND 0x000080	/**< default console background color */
 
 typedef struct {
Index: fb/fb.c
===================================================================
--- fb/fb.c	(revision dc5a0fe1f6cd378525f19e69830be5e2cec0d779)
+++ fb/fb.c	(revision 429acb9556734369795e31b2cdc6cf1d1080c35d)
@@ -84,4 +84,16 @@
 } viewport_t;
 
+/** Maximum number of saved pixmaps 
+ * Pixmap is a saved rectangle
+ */
+#define MAX_PIXMAPS        256
+typedef struct {
+	unsigned int width;
+	unsigned int height;
+	void *data;
+} pixmap_t;
+static pixmap_t pixmaps[MAX_PIXMAPS];
+
+/* Viewport is a rectangular area on the screen */
 #define MAX_VIEWPORTS 128
 static viewport_t viewports[128];
@@ -287,22 +299,4 @@
 }
 
-static void draw_logo(int vp,unsigned int startx, unsigned int starty)
-{
-	unsigned int x;
-	unsigned int y;
-	unsigned int byte;
-	unsigned int rowbytes;
-
-	rowbytes = (helenos_width - 1) / 8 + 1;
-
-	for (y = 0; y < helenos_height; y++)
-		for (x = 0; x < helenos_width; x++) {
-			byte = helenos_bits[rowbytes * y + x / 8];
-			byte >>= x % 8;
-			if (byte & 1)
-				putpixel(vp ,startx + x, starty + y, viewports[vp].style.fg_color);
-		}
-}
-
 /***************************************************************/
 /* Stdout specific functions */
@@ -396,4 +390,5 @@
 }
 
+/** Hide cursor if it is shown */
 static void cursor_hide(int vp)
 {
@@ -406,4 +401,5 @@
 }
 
+/** Show cursor if cursor showing is enabled */
 static void cursor_print(int vp)
 {
@@ -417,4 +413,5 @@
 }
 
+/** Invert cursor, if it is enabled */
 static void cursor_blink(int vp)
 {
@@ -458,4 +455,9 @@
 }
 
+/** Draw text data to viewport
+ *
+ * @param vp Viewport id
+ * @param data Text data fitting exactly into viewport
+ */
 static void draw_text_data(int vp, keyfield_t *data)
 {
@@ -476,4 +478,24 @@
 }
 
+/** Handle shared memory communication calls
+ *
+ * Protocol for drawing pixmaps:
+ * - FB_PREPARE_SHM(client shm identification)
+ * - IPC_M_SEND_AS_AREA
+ * - FB_DRAW_PPM(startx,starty)
+ * - FB_DROP_SHM
+ *
+ * Protocol for text drawing
+ * - IPC_M_SEND_AS_AREA
+ * - FB_DRAW_TEXT_DATA
+ *
+ * @param callid Callid of the current call
+ * @param call Current call data
+ * @param vp Active viewport
+ * @return 0 if the call was not handled byt this function, 1 otherwise
+ *
+ * note: this function is not threads safe, you would have
+ * to redefine static variables with __thread
+ */
 static int shm_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
 {
@@ -559,4 +581,122 @@
 }
 
+/** Return first free pixmap */
+static int find_free_pixmap(void)
+{
+	int i;
+	
+	for (i=0;i < MAX_PIXMAPS;i++)
+		if (!pixmaps[i].data)
+			return i;
+	return -1;
+}
+
+/** Save viewport to pixmap */
+static int save_vp_to_pixmap(int vp)
+{
+	int pm;
+	pixmap_t *pmap;
+	viewport_t *vport = &viewports[vp];
+	int x,y;
+	int rowsize;
+	int tmp;
+
+	pm = find_free_pixmap();
+	if (pm == -1)
+		return ELIMIT;
+	
+	pmap = &pixmaps[pm];
+	pmap->data = malloc(screen.pixelbytes * vport->width * vport->height);
+	if (!pmap->data)
+		return ENOMEM;
+
+	pmap->width = vport->width;
+	pmap->height = vport->height;
+	
+	rowsize = vport->width * screen.pixelbytes;
+	for (y=0;y < vport->height; y++) {
+		tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
+		memcpy(pmap->data + rowsize*y, screen.fbaddress + tmp, rowsize); 
+	}
+	return pm;
+}
+
+/** Draw pixmap on screen
+ *
+ * @param vp Viewport to draw on
+ * @param pm Pixmap identifier
+ */
+static int draw_pixmap(int vp, int pm)
+{
+	pixmap_t *pmap = &pixmaps[pm];
+	viewport_t *vport = &viewports[vp];
+	int x,y;
+	int tmp, srcrowsize;
+	int realwidth, realheight, realrowsize;
+
+	if (!pmap->data)
+		return EINVAL;
+
+	realwidth = pmap->width <= vport->width ? pmap->width : vport->width;
+	realheight = pmap->height <= vport->height ? pmap->height : vport->height;
+
+	srcrowsize = vport->width * screen.pixelbytes;
+	realrowsize = realwidth * screen.pixelbytes;
+
+	for (y=0; y < realheight; y++) {
+		tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
+		memcpy(screen.fbaddress + tmp, pmap->data + y * srcrowsize, realrowsize);
+	}
+}
+
+/** Handler for messages concerning pixmap handling */
+static int pixmap_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
+{
+	int handled = 1;
+	int retval = 0;
+	int i,nvp;
+
+	switch (IPC_GET_METHOD(*call)) {
+	case FB_VP_DRAW_PIXMAP:
+		nvp = IPC_GET_ARG1(*call);
+		if (nvp == -1)
+			nvp = vp;
+		if (nvp < 0 || nvp >= MAX_VIEWPORTS || !viewports[nvp].initialized) {
+			retval = EINVAL;
+			break;
+		}
+		i = IPC_GET_ARG2(*call);
+		retval = draw_pixmap(nvp, i);
+		break;
+	case FB_VP2PIXMAP:
+		nvp = IPC_GET_ARG1(*call);
+		if (nvp == -1)
+			nvp = vp;
+		if (nvp < 0 || nvp >= MAX_VIEWPORTS || !viewports[nvp].initialized)
+			retval = EINVAL;
+		else
+			retval = save_vp_to_pixmap(nvp);
+		break;
+	case FB_DROP_PIXMAP:
+		i = IPC_GET_ARG1(*call);
+		if (i >= MAX_PIXMAPS) {
+			retval = EINVAL;
+			break;
+		}
+		if (pixmaps[i].data) {
+			free(pixmaps[i].data);
+			pixmaps[i].data = NULL;
+		}
+		break;
+	default:
+		handled = 0;
+	}
+
+	if (handled)
+		ipc_answer_fast(callid, retval, 0, 0);
+	return handled;
+	
+}
+
 /** Function for handling connections to FB
  *
@@ -588,4 +728,6 @@
 		}
 		if (shm_handle(callid, &call, vp))
+			continue;
+		if (pixmap_handle(callid, &call, vp))
 			continue;
 
Index: libc/include/async.h
===================================================================
--- libc/include/async.h	(revision dc5a0fe1f6cd378525f19e69830be5e2cec0d779)
+++ libc/include/async.h	(revision 429acb9556734369795e31b2cdc6cf1d1080c35d)
@@ -71,4 +71,6 @@
 	return rc;
 }
+#define sync_send(phoneid, method, arg1, r1) sync_send_2(phoneid, method, arg1, 0, r1, 0)
+
 static inline ipcarg_t sync_send_3(int phoneid, ipcarg_t method, ipcarg_t arg1,
 				   ipcarg_t arg2, ipcarg_t arg3, ipcarg_t *r1, 
Index: libc/include/ipc/fb.h
===================================================================
--- libc/include/ipc/fb.h	(revision dc5a0fe1f6cd378525f19e69830be5e2cec0d779)
+++ libc/include/ipc/fb.h	(revision 429acb9556734369795e31b2cdc6cf1d1080c35d)
@@ -24,4 +24,9 @@
 #define FB_PREPARE_SHM       1039
 #define FB_DROP_SHM          1040
+#define FB_SHM2PIXMAP        1041
+
+#define FB_VP_DRAW_PIXMAP    1042
+#define FB_VP2PIXMAP         1043
+#define FB_DROP_PIXMAP       1044
 
 #endif
