diff --git a/modules/lfbvideo.c b/modules/lfbvideo.c
index 652db7f..de77810 100644
--- a/modules/lfbvideo.c
+++ b/modules/lfbvideo.c
@@ -17,6 +17,8 @@
 #include <tokenize.h>
 #include <module.h>
 #include <video.h>
+#include <pipe.h>
+#include <mouse.h>
 
 #include "../userspace/gui/terminal/terminal-font.h"
 
@@ -34,6 +36,9 @@ static void graphics_install_bochs(uint16_t, uint16_t);
 static void bochs_set_y_offset(uint16_t y);
 static uint16_t bochs_current_scroll(void);
 
+static void vbox_check(void);
+static pid_t display_change_recipient = 0;
+
 /*
  * Address of the linear frame buffer.
  * This can move, so it's a pointer instead of
@@ -61,6 +66,10 @@ static int ioctl_vid(fs_node_t * node, int request, void * argp) {
 			validate(argp);
 			*((uintptr_t *)argp) = (uintptr_t)lfb_vid_memory;
 			return 0;
+		case 0xFFFF0001:
+			/* ioctl to register for a signal (vid device change? idk) on display change */
+			display_change_recipient = getpid();
+			return 0;
 		default:
 			return -1; /* TODO EINV... something or other */
 	}
@@ -193,6 +202,8 @@ static void bochs_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra
 static void graphics_install_bochs(uint16_t resolution_x, uint16_t resolution_y) {
 	debug_print(NOTICE, "Setting up BOCHS/QEMU graphics controller...");
 
+	vbox_check();
+
 	outports(0x1CE, 0x00);
 	uint16_t i = inports(0x1CF);
 	if (i < 0xB0C0 || i > 0xB0C6) {
@@ -321,6 +332,295 @@ mem_found:
 	}
 }
 
+#define VBOX_VENDOR_ID 0x80EE
+#define VBOX_DEVICE_ID 0xCAFE
+
+static void vbox_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) {
+	if (v == VBOX_VENDOR_ID && d == VBOX_DEVICE_ID) {
+		*((uint32_t *)extra) = device;
+	}
+}
+
+#define VMMDEV_VERSION 0x00010003
+#define VBOX_REQUEST_HEADER_VERSION 0x10001
+struct vbox_header {
+	uint32_t size;
+	uint32_t version;
+	uint32_t requestType;
+	int32_t  rc;
+	uint32_t reserved1;
+	uint32_t reserved2;
+};
+
+struct vbox_guest_info {
+	struct vbox_header header;
+	uint32_t version;
+	uint32_t ostype;
+};
+
+struct vbox_guest_caps {
+	struct vbox_header header;
+	uint32_t caps;
+};
+
+struct vbox_ack_events {
+	struct vbox_header header;
+	uint32_t events;
+};
+
+struct vbox_display_change {
+	struct vbox_header header;
+	uint32_t xres;
+	uint32_t yres;
+	uint32_t bpp;
+	uint32_t eventack;
+};
+
+struct vbox_mouse {
+	struct vbox_header header;
+	uint32_t features;
+	int32_t x;
+	int32_t y;
+};
+
+
+#define EARLY_LOG_DEVICE 0x504
+static uint32_t _vbox_write(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
+	for (unsigned int i = 0; i < size; ++i) {
+		outportb(EARLY_LOG_DEVICE, buffer[i]);
+	}
+	return size;
+}
+static fs_node_t vb = { .write = &_vbox_write };
+
+static uint32_t vbox_device = 0;
+static uint32_t vbox_port = 0x0;
+static int vbox_irq = 0;
+
+static struct vbox_ack_events * vbox_irq_ack;
+static uint32_t vbox_phys_ack;
+static struct vbox_display_change * vbox_disp;
+static uint32_t vbox_phys_disp;
+static struct vbox_mouse * vbox_m;
+static uint32_t vbox_phys_mouse;
+static uint32_t * vbox_vmmdev = 0;
+
+static fs_node_t * mouse_pipe;
+
+#define PACKETS_IN_PIPE 1024
+#define DISCARD_POINT 32
+
+static int vbox_irq_handler(struct regs *r) {
+	// debug_print(WARNING, "(vbox-toaru) irq received; pending events are 0x%x", vbox_vmmdev[4]);
+	outportl(vbox_port, vbox_phys_disp);
+	outportl(vbox_port, vbox_phys_mouse);
+	outportl(vbox_port, vbox_phys_ack);
+	// debug_print(WARNING, "Display stuff: %d %d %d\n", vbox_disp->xres, vbox_disp->yres, vbox_disp->bpp);
+
+	if (lfb_vid_memory && lfb_resolution_x && lfb_resolution_y && vbox_m->x && vbox_m->y) {
+		// debug_print(WARNING, "Mouse stuff: 0x%x 0x%x 0x%x\n", vbox_m->features, vbox_m->x, vbox_m->y);
+
+		unsigned int x = ((unsigned int)vbox_m->x * lfb_resolution_x) / 0xFFFF;
+		unsigned int y = ((unsigned int)vbox_m->y * lfb_resolution_y) / 0xFFFF;
+
+		mouse_device_packet_t packet;
+		packet.magic = MOUSE_MAGIC;
+		packet.x_difference = x;
+		packet.y_difference = y;
+		packet.buttons = 0;
+
+		mouse_device_packet_t bitbucket;
+		while (pipe_size(mouse_pipe) > (int)(DISCARD_POINT * sizeof(packet))) {
+			read_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&bitbucket);
+		}
+		write_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&packet);
+	}
+
+
+	if (lfb_resolution_x && vbox_disp->xres && (vbox_disp->xres != lfb_resolution_x  || vbox_disp->yres != lfb_resolution_y)) {
+		outports(0x1CE, 0x04);
+		outports(0x1CF, 0x00);
+		/* Uh oh, here we go. */
+		outports(0x1CE, 0x01);
+		outports(0x1CF, vbox_disp->xres);
+		/* Set Y resolution to 768 */
+		outports(0x1CE, 0x02);
+		outports(0x1CF, vbox_disp->yres);
+		/* Turn it back on */
+		outports(0x1CE, 0x04);
+		outports(0x1CF, 0x41);
+		lfb_resolution_x = vbox_disp->xres;
+		lfb_resolution_y = vbox_disp->yres;
+
+		if (display_change_recipient) {
+			send_signal(display_change_recipient, SIGWINEVENT);
+			debug_print(WARNING, "Telling %d to SIGWINEVENT", display_change_recipient);
+		}
+
+	}
+	irq_ack(vbox_irq);
+	return 1;
+}
+
+static void vbox_check(void) {
+	pci_scan(vbox_scan_pci, -1, &vbox_device);
+
+	if (vbox_device) {
+		fprintf(&vb, "VirtualBox host detected, switching log to VirtualBox.\n");
+		debug_file = &vb;
+
+		uintptr_t t = pci_read_field(vbox_device, PCI_BAR0, 4);
+		if (t > 0) {
+			vbox_port = (t & 0xFFFFFFF0);
+		}
+
+		mouse_pipe = make_pipe(sizeof(mouse_device_packet_t) * PACKETS_IN_PIPE);
+		mouse_pipe->flags = FS_CHARDEVICE;
+
+		vfs_mount("/dev/absmouse", mouse_pipe);
+
+		vbox_irq = pci_read_field(vbox_device, PCI_INTERRUPT_LINE, 1);
+		debug_print(WARNING, "(vbox) device IRQ is set to %d\n", vbox_irq);
+		irq_install_handler(vbox_irq, vbox_irq_handler);
+
+		uint32_t vbox_phys = 0;
+		struct vbox_guest_info * packet = (void*)kvmalloc_p(0x1000, &vbox_phys);
+		packet->header.size = sizeof(struct vbox_guest_info);
+		packet->header.version = VBOX_REQUEST_HEADER_VERSION;
+		packet->header.requestType = 50;
+		packet->header.rc = 0;
+		packet->header.reserved1 = 0;
+		packet->header.reserved2 = 0;
+		packet->version = VMMDEV_VERSION;
+		packet->ostype = 0;
+
+		outportl(vbox_port, vbox_phys);
+
+		struct vbox_guest_caps * caps = (void*)kvmalloc_p(0x1000, &vbox_phys);
+		caps->header.size = sizeof(struct vbox_guest_caps);
+		caps->header.version = VBOX_REQUEST_HEADER_VERSION;
+		caps->header.requestType = 55;
+		caps->header.rc = 0;
+		caps->header.reserved1 = 0;
+		caps->header.reserved2 = 0;
+		caps->caps = 1 << 2;
+		outportl(vbox_port, vbox_phys);
+
+		vbox_irq_ack = (void*)kvmalloc_p(0x1000, &vbox_phys_ack);
+		vbox_irq_ack->header.size = sizeof(struct vbox_ack_events);
+		vbox_irq_ack->header.version = VBOX_REQUEST_HEADER_VERSION;
+		vbox_irq_ack->header.requestType = 41;
+		vbox_irq_ack->header.rc = 0;
+		vbox_irq_ack->header.reserved1 = 0;
+		vbox_irq_ack->header.reserved2 = 0;
+		vbox_irq_ack->events = 0;
+
+		vbox_disp = (void*)kvmalloc_p(0x1000, &vbox_phys_disp);
+		vbox_disp->header.size = sizeof(struct vbox_display_change);
+		vbox_disp->header.version = VBOX_REQUEST_HEADER_VERSION;
+		vbox_disp->header.requestType = 51;
+		vbox_disp->header.rc = 0;
+		vbox_disp->header.reserved1 = 0;
+		vbox_disp->header.reserved2 = 0;
+		vbox_disp->xres = 0;
+		vbox_disp->yres = 0;
+		vbox_disp->bpp = 0;
+		vbox_disp->eventack = 1;
+
+		vbox_m = (void*)kvmalloc_p(0x1000, &vbox_phys_mouse);
+		vbox_m->header.size = sizeof(struct vbox_mouse);
+		vbox_m->header.version = VBOX_REQUEST_HEADER_VERSION;
+		vbox_m->header.requestType = 2;
+		vbox_m->header.rc = 0;
+		vbox_m->header.reserved1 = 0;
+		vbox_m->header.reserved2 = 0;
+		vbox_m->features = (1 << 0);
+		vbox_m->x = 0;
+		vbox_m->y = 0;
+		outportl(vbox_port, vbox_phys_mouse);
+
+		vbox_m->header.requestType = 1;
+
+		/* device memory region mapping? */
+		{
+			uintptr_t t = pci_read_field(vbox_device, PCI_BAR1, 4);
+			if (t > 0) {
+				vbox_vmmdev =  (void *)(t & 0xFFFFFFF0);
+			}
+			uintptr_t fb_offset = (uintptr_t)vbox_vmmdev;
+			for (uintptr_t i = fb_offset; i <= fb_offset + 0x2000; i += 0x1000) {
+				dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
+			}
+		}
+
+		vbox_vmmdev[3] = 0xFFFFFFFF; /* Enable all for now */
+	}
+}
+
+#define SVGA_IO_BASE (vmware_io)
+#define SVGA_IO_MUL 1
+#define SVGA_INDEX_PORT 0
+#define SVGA_VALUE_PORT 1
+
+#define SVGA_REG_ID 0
+#define SVGA_REG_ENABLE 1
+#define SVGA_REG_WIDTH 2
+#define SVGA_REG_HEIGHT 3
+#define SVGA_REG_BITS_PER_PIXEL 7
+#define SVGA_REG_FB_START 13
+
+static uint32_t vmware_io = 0;
+
+static void vmware_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) {
+	if ((v == 0x15ad && d == 0x0405)) {
+		uintptr_t t = pci_read_field(device, PCI_BAR0, 4);
+		if (t > 0) {
+			*((uint8_t **)extra) = (uint8_t *)(t & 0xFFFFFFF0);
+		}
+	}
+}
+
+static void vmware_write(int reg, int value) {
+	outportl(SVGA_IO_MUL * SVGA_INDEX_PORT + SVGA_IO_BASE, reg);
+	outportl(SVGA_IO_MUL * SVGA_VALUE_PORT + SVGA_IO_BASE, value);
+}
+
+static uint32_t vmware_read(int reg) {
+	outportl(SVGA_IO_MUL * SVGA_INDEX_PORT + SVGA_IO_BASE, reg);
+	return inportl(SVGA_IO_MUL * SVGA_VALUE_PORT + SVGA_IO_BASE);
+}
+
+static void graphics_install_vmware(uint16_t w, uint16_t h) {
+	debug_print(WARNING, "Please note that the `vmware` display driver is experimental.");
+	pci_scan(vmware_scan_pci, -1, &vmware_io);
+
+	if (!vmware_io) {
+		debug_print(ERROR, "No vmware device found?");
+		return;
+	} else {
+		debug_print(WARNING, "vmware io base: 0x%x", vmware_io);
+	}
+
+	vmware_write(SVGA_REG_ID, 0);
+	vmware_write(SVGA_REG_WIDTH, w);
+	vmware_write(SVGA_REG_HEIGHT, h);
+	vmware_write(SVGA_REG_BITS_PER_PIXEL, 32);
+	vmware_write(SVGA_REG_ENABLE, 1);
+
+	uint32_t fb_addr = vmware_read(SVGA_REG_FB_START);
+	debug_print(WARNING, "vmware fb address: 0x%x", fb_addr);
+
+	lfb_vid_memory = (uint8_t *)fb_addr;
+
+	uintptr_t fb_offset = (uintptr_t)lfb_vid_memory;
+	for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) {
+		dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
+	}
+
+	finalize_graphics(w,h,32);
+}
+
+
 static int init(void) {
 
 	if (mboot_ptr->vbe_mode_info) {
@@ -349,6 +649,8 @@ static int init(void) {
 			graphics_install_bochs(x,y);
 		} else if (!strcmp(argv[0],"preset")) {
 			graphics_install_preset(x,y);
+		} else if (!strcmp(argv[0],"vmware")) {
+			graphics_install_vmware(x,y);
 		} else {
 			debug_print(WARNING, "Unrecognized video adapter: %s", argv[0]);
 		}
diff --git a/userspace/gui/compositor/compositor.c b/userspace/gui/compositor/compositor.c
index 3d25c0e..ed143b8 100644
--- a/userspace/gui/compositor/compositor.c
+++ b/userspace/gui/compositor/compositor.c
@@ -15,11 +15,14 @@
 #include <assert.h>
 #include <getopt.h>
 #include <errno.h>
+#include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 
 #include <cairo.h>
 
+#include "../../../kernel/include/video.h"
+
 #include "lib/graphics.h"
 #include "lib/pthread.h"
 #include "lib/mouse.h"
@@ -527,6 +530,8 @@ void * nested_input(void * _yg) {
  * mouse clicks and movements into event objects
  * to send to the core compositor.
  */
+static uint32_t last_mouse_buttons = 0;
+static int abs_mouse_available = 0;
 void * mouse_input(void * garbage) {
 	int mfd = open("/dev/mouse", O_RDONLY);
 
@@ -536,6 +541,11 @@ void * mouse_input(void * garbage) {
 	while (1) {
 		int r = read(mfd, (char *)&packet, sizeof(mouse_device_packet_t));
 		if (r > 0) {
+			last_mouse_buttons = packet.buttons;
+			if (abs_mouse_available) {
+				packet.x_difference = 0;
+				packet.y_difference = 0;
+			}
 			yutani_msg_t * m = yutani_msg_build_mouse_event(0, &packet, YUTANI_MOUSE_EVENT_TYPE_RELATIVE);
 			int result = yutani_msg_send(y, m);
 			free(m);
@@ -543,6 +553,26 @@ void * mouse_input(void * garbage) {
 	}
 }
 
+void * mouse_input_abs(void * garbage) {
+	int mfd = open("/dev/absmouse", O_RDONLY);
+
+	if (mfd == -1) return 0;
+	abs_mouse_available = 1;
+
+	yutani_t * y = yutani_init();
+	mouse_device_packet_t packet;
+
+	while (1) {
+		int r = read(mfd, (char *)&packet, sizeof(mouse_device_packet_t));
+		if (r > 0) {
+			packet.buttons = last_mouse_buttons;
+			yutani_msg_t * m = yutani_msg_build_mouse_event(0, &packet, YUTANI_MOUSE_EVENT_TYPE_ABSOLUTE);
+			int result = yutani_msg_send(y, m);
+			free(m);
+		}
+	}
+}
+
 /**
  * Keyboard input thread
  *
@@ -1179,6 +1209,44 @@ static void redraw_windows(yutani_globals_t * yg) {
 
 	/* Restore the cairo contexts to reset clip regions */
 	restore_cairo_states(yg);
+
+	if (yg->resize_on_next) {
+		spin_lock(&yg->redraw_lock);
+
+		cairo_destroy(yg->framebuffer_ctx);
+		cairo_destroy(yg->real_ctx);
+		cairo_surface_destroy(yg->framebuffer_surface);
+		cairo_surface_destroy(yg->real_surface);
+
+		int fd = open("/dev/fb0", O_RDONLY);
+		ioctl(fd, IO_VID_WIDTH,  &yg->width);
+		ioctl(fd, IO_VID_HEIGHT, &yg->height);
+		close(fd);
+
+		yg->backend_ctx->width = yg->width;
+		yg->backend_ctx->height = yg->height;
+		yg->backend_ctx->backbuffer = realloc(yg->backend_ctx->backbuffer, sizeof(uint32_t) * yg->width * yg->height);
+		yg->backend_framebuffer = yg->backend_ctx->backbuffer;
+
+		int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, yg->width);
+		yg->framebuffer_surface = cairo_image_surface_create_for_data(
+				yg->backend_framebuffer, CAIRO_FORMAT_ARGB32, yg->width, yg->height, stride);
+		yg->real_surface = cairo_image_surface_create_for_data(
+				yg->backend_ctx->buffer, CAIRO_FORMAT_ARGB32, yg->width, yg->height, stride);
+
+		yg->framebuffer_ctx = cairo_create(yg->framebuffer_surface);
+		yg->real_ctx = cairo_create(yg->real_surface);
+
+		yg->resize_on_next = 0;
+		mark_screen(yg, 0, 0, yg->width, yg->height);
+
+		yutani_msg_t * response = yutani_msg_build_welcome(yg->width, yg->height);
+		pex_broadcast(yg->server, response->size, (char *)response);
+		free(response);
+
+		spin_unlock(&yg->redraw_lock);
+	}
+
 }
 
 /**
@@ -1904,6 +1972,13 @@ static void handle_mouse_event(yutani_globals_t * yg, struct yutani_msg_mouse_ev
 	}
 }
 
+static yutani_globals_t * _static_yg;
+static void yutani_display_resize_handle(int signum) {
+	(void)signum;
+	TRACE("Display change request, one moment.");
+	_static_yg->resize_on_next = 1;
+}
+
 /**
  * main
  */
@@ -1923,6 +1998,10 @@ int main(int argc, char * argv[]) {
 		yg->backend_ctx = init_graphics_yutani_double_buffer(yg->host_window);
 	} else {
 		yg->backend_ctx = init_graphics_fullscreen_double_buffer();
+		_static_yg = yg;
+		int fd = open("/dev/fb0", O_RDONLY);
+		ioctl(fd, 0xFFFF0001, NULL);
+		signal(SIGWINEVENT, yutani_display_resize_handle);
 	}
 
 	if (!yg->backend_ctx) {
@@ -1987,6 +2066,7 @@ int main(int argc, char * argv[]) {
 	yutani_cairo_init(yg);
 
 	pthread_t mouse_thread;
+	pthread_t absmouse_thread;
 	pthread_t keyboard_thread;
 	pthread_t render_thread;
 	pthread_t nested_thread;
@@ -1997,6 +2077,7 @@ int main(int argc, char * argv[]) {
 	} else {
 		/* Toaru mouse+keyboard driver */
 		pthread_create(&mouse_thread, NULL, mouse_input, NULL);
+		pthread_create(&absmouse_thread, NULL, mouse_input_abs, NULL);
 		pthread_create(&keyboard_thread, NULL, keyboard_input, NULL);
 	}
 
diff --git a/userspace/gui/compositor/yutani_int.h b/userspace/gui/compositor/yutani_int.h
index 0bb87f3..3dacf83 100644
--- a/userspace/gui/compositor/yutani_int.h
+++ b/userspace/gui/compositor/yutani_int.h
@@ -163,6 +163,7 @@ typedef struct {
 	sprite_t mouse_sprite_resize_db;
 
 	int current_cursor;
+	int resize_on_next;
 
 } yutani_globals_t;
 
diff --git a/userspace/gui/core/panel.c b/userspace/gui/core/panel.c
index b5ab2d7..fcae60b 100644
--- a/userspace/gui/core/panel.c
+++ b/userspace/gui/core/panel.c
@@ -905,6 +905,28 @@ static void * clock_thread(void * garbage) {
 	}
 }
 
+static void resize_finish(int xwidth, int xheight) {
+	width = xwidth;
+	height = xheight;
+	yutani_window_resize_accept(yctx, panel, width, height);
+
+	reinit_graphics_yutani(ctx, panel);
+	yutani_window_resize_done(yctx, panel);
+
+	/* Draw the background */
+	draw_fill(ctx, rgba(0,0,0,0));
+	for (uint32_t i = 0; i < width; i += sprite_panel->width) {
+		draw_sprite(ctx, sprite_panel, i, 0);
+	}
+
+	/* Copy the prerendered background so we can redraw it quickly */
+	bg_size = panel->width * panel->height * sizeof(uint32_t);
+	bg_blob = realloc(bg_blob, bg_size);
+	memcpy(bg_blob, ctx->backbuffer, bg_size);
+
+	redraw();
+}
+
 int main (int argc, char ** argv) {
 	/* Connect to window server */
 	yctx = yutani_init();
@@ -1041,6 +1063,18 @@ int main (int argc, char ** argv) {
 				case YUTANI_MSG_WINDOW_FOCUS_CHANGE:
 					handle_focus_event((struct yutani_msg_window_focus_change *)m->data);
 					break;
+				case YUTANI_MSG_WELCOME:
+					{
+						struct yutani_msg_welcome * mw = (void*)m->data;
+						yutani_window_resize(yctx, panel, mw->display_width, PANEL_HEIGHT);
+					}
+					break;
+				case YUTANI_MSG_RESIZE_OFFER:
+					{
+						struct yutani_msg_window_resize * wr = (void*)m->data;
+						resize_finish(wr->width, wr->height);
+					}
+					break;
 				default:
 					break;
 			}
diff --git a/userspace/gui/core/wallpaper.c b/userspace/gui/core/wallpaper.c
index cb1015b..53290ea 100644
--- a/userspace/gui/core/wallpaper.c
+++ b/userspace/gui/core/wallpaper.c
@@ -390,6 +390,24 @@ void sig_usr(int sig) {
 	yutani_flip(yctx, wina);
 }
 
+static void resize_finish(int xwidth, int xheight) {
+	width = xwidth;
+	height = xheight;
+	yutani_window_resize_accept(yctx, wina, width, height);
+
+	sprite_t * new_wallpaper = load_wallpaper();
+	free(wallpaper);
+	wallpaper = new_wallpaper;
+
+	reinit_graphics_yutani(ctx, wina);
+	yutani_window_resize_done(yctx, wina);
+
+	draw_sprite(ctx, wallpaper, 0, 0);
+	redraw_apps_x(1);
+	yutani_flip(yctx, wina);
+}
+
+
 int main (int argc, char ** argv) {
 	yctx = yutani_init();
 
@@ -441,6 +459,18 @@ int main (int argc, char ** argv) {
 				case YUTANI_MSG_WINDOW_MOUSE_EVENT:
 					wallpaper_check_click((struct yutani_msg_window_mouse_event *)m->data);
 					break;
+				case YUTANI_MSG_WELCOME:
+					{
+						struct yutani_msg_welcome * mw = (void*)m->data;
+						yutani_window_resize(yctx, wina, mw->display_width, mw->display_height);
+					}
+					break;
+				case YUTANI_MSG_RESIZE_OFFER:
+					{
+						struct yutani_msg_window_resize * wr = (void*)m->data;
+						resize_finish(wr->width, wr->height);
+					}
+					break;
 				case YUTANI_MSG_SESSION_END:
 					_continue = 0;
 					break;
diff --git a/userspace/lib/yutani.c b/userspace/lib/yutani.c
index 72e2a85..2466bd7 100644
--- a/userspace/lib/yutani.c
+++ b/userspace/lib/yutani.c
@@ -56,6 +56,12 @@ yutani_msg_t * yutani_poll(yutani_t * y) {
 		memcpy(out, tmp, size);
 	}
 
+	if (out->type == YUTANI_MSG_WELCOME) {
+		struct yutani_msg_welcome * mw = (void *)out;
+		y->display_width = mw->display_width;
+		y->display_height = mw->display_height;
+	}
+
 	return out;
 }
 
diff --git a/userspace/lib/yutani.h b/userspace/lib/yutani.h
index be437d1..f37eb8c 100644
--- a/userspace/lib/yutani.h
+++ b/userspace/lib/yutani.h
@@ -403,6 +403,7 @@ yutani_msg_t * yutani_msg_build_window_update_shape(yutani_wid_t wid, int set_sh
 yutani_msg_t * yutani_msg_build_window_warp_mouse(yutani_wid_t wid, int32_t x, int32_t y);
 yutani_msg_t * yutani_msg_build_window_show_mouse(yutani_wid_t wid, int32_t show_mouse);
 yutani_msg_t * yutani_msg_build_window_resize_start(yutani_wid_t wid, yutani_scale_direction_t direction);
+yutani_msg_t * yutani_msg_build_display_changed(void);
 
 
 int yutani_msg_send(yutani_t * y, yutani_msg_t * msg);
diff --git a/util/cdrom/boot/grub/grub.cfg b/util/cdrom/boot/grub/grub.cfg
index d7ca553..524093a 100644
--- a/util/cdrom/boot/grub/grub.cfg
+++ b/util/cdrom/boot/grub/grub.cfg
@@ -35,6 +35,7 @@ function load_modules {
     module /mod/zero.ko
     module /mod/random.ko
     module /mod/serial.ko
+    module /mod/debug_shell.ko
     module /mod/procfs.ko
     module /mod/tmpfs.ko
     module /mod/ata.ko
diff --git a/util/cdrom/boot/grub/menus.cfg b/util/cdrom/boot/grub/menus.cfg
index 35e6dc1..9b36855 100644
--- a/util/cdrom/boot/grub/menus.cfg
+++ b/util/cdrom/boot/grub/menus.cfg
@@ -76,6 +76,11 @@ submenu 'Advanced graphics configuration options...' {
         export t_driver
         configfile /boot/grub/menus.cfg
     }
+    menuentry 'Use VMWare driver' {
+        set t_driver=vmware
+        export t_driver
+        configfile /boot/grub/menus.cfg
+    }
     menuentry 'Use Preset LFB Driver (Default)' {
         set t_driver=preset
         export t_driver
