Index: uspace/lib/display/include/disp_srv.h
===================================================================
--- uspace/lib/display/include/disp_srv.h	(revision 2a515dcdbf45d99dae90d9f82bc03f8416d806b7)
+++ uspace/lib/display/include/disp_srv.h	(revision 0e6e77f09b348a14b2b1fa8165b25000755a93f1)
@@ -38,4 +38,5 @@
 #include <async.h>
 #include <errno.h>
+#include <gfx/coord.h>
 #include "display/wndparams.h"
 #include "types/display/event.h"
@@ -53,4 +54,5 @@
 	errno_t (*window_create)(void *, display_wnd_params_t *, sysarg_t *);
 	errno_t (*window_destroy)(void *, sysarg_t);
+	errno_t (*window_resize)(void *, sysarg_t, gfx_coord2_t *, gfx_rect_t *);
 	errno_t (*get_event)(void *, sysarg_t *, display_wnd_ev_t *);
 };
Index: uspace/lib/display/include/display.h
===================================================================
--- uspace/lib/display/include/display.h	(revision 2a515dcdbf45d99dae90d9f82bc03f8416d806b7)
+++ uspace/lib/display/include/display.h	(revision 0e6e77f09b348a14b2b1fa8165b25000755a93f1)
@@ -38,4 +38,5 @@
 #include <errno.h>
 #include <gfx/context.h>
+#include <gfx/coord.h>
 #include <stdbool.h>
 #include "display/wndparams.h"
@@ -48,4 +49,6 @@
 extern errno_t display_window_destroy(display_window_t *);
 extern errno_t display_window_get_gc(display_window_t *, gfx_context_t **);
+extern errno_t display_window_resize(display_window_t *,
+    gfx_coord2_t *, gfx_rect_t *);
 
 #endif
Index: uspace/lib/display/include/ipc/display.h
===================================================================
--- uspace/lib/display/include/ipc/display.h	(revision 2a515dcdbf45d99dae90d9f82bc03f8416d806b7)
+++ uspace/lib/display/include/ipc/display.h	(revision 0e6e77f09b348a14b2b1fa8165b25000755a93f1)
@@ -42,4 +42,5 @@
 	DISPLAY_WINDOW_CREATE,
 	DISPLAY_WINDOW_DESTROY,
+	DISPLAY_WINDOW_RESIZE,
 	DISPLAY_GET_EVENT
 } display_request_t;
Index: uspace/lib/display/src/disp_srv.c
===================================================================
--- uspace/lib/display/src/disp_srv.c	(revision 2a515dcdbf45d99dae90d9f82bc03f8416d806b7)
+++ uspace/lib/display/src/disp_srv.c	(revision 0e6e77f09b348a14b2b1fa8165b25000755a93f1)
@@ -43,4 +43,5 @@
 #include <stdlib.h>
 #include <stddef.h>
+#include "../private/params.h"
 
 static void display_callback_create_srv(display_srv_t *srv, ipc_call_t *call)
@@ -108,4 +109,43 @@
 }
 
+static void display_window_resize_srv(display_srv_t *srv, ipc_call_t *icall)
+{
+	sysarg_t wnd_id;
+	ipc_call_t call;
+	display_wnd_move_t wmove;
+	size_t size;
+	errno_t rc;
+
+	wnd_id = ipc_get_arg1(icall);
+
+	if (!async_data_write_receive(&call, &size)) {
+		async_answer_0(&call, EREFUSED);
+		async_answer_0(icall, EREFUSED);
+		return;
+	}
+
+	if (size != sizeof(display_wnd_move_t)) {
+		async_answer_0(&call, EINVAL);
+		async_answer_0(icall, EINVAL);
+		return;
+	}
+
+	rc = async_data_write_finalize(&call, &wmove, size);
+	if (rc != EOK) {
+		async_answer_0(&call, rc);
+		async_answer_0(icall, rc);
+		return;
+	}
+
+	if (srv->ops->window_resize == NULL) {
+		async_answer_0(icall, ENOTSUP);
+		return;
+	}
+
+	rc = srv->ops->window_resize(srv->arg, wnd_id, &wmove.offs,
+	    &wmove.nrect);
+	async_answer_0(icall, rc);
+}
+
 static void display_get_event_srv(display_srv_t *srv, ipc_call_t *icall)
 {
@@ -175,4 +215,7 @@
 		case DISPLAY_WINDOW_DESTROY:
 			display_window_destroy_srv(srv, &call);
+			break;
+		case DISPLAY_WINDOW_RESIZE:
+			display_window_resize_srv(srv, &call);
 			break;
 		case DISPLAY_GET_EVENT:
Index: uspace/lib/display/src/display.c
===================================================================
--- uspace/lib/display/src/display.c	(revision 2a515dcdbf45d99dae90d9f82bc03f8416d806b7)
+++ uspace/lib/display/src/display.c	(revision 0e6e77f09b348a14b2b1fa8165b25000755a93f1)
@@ -38,4 +38,5 @@
 #include <mem.h>
 #include <stdlib.h>
+#include "../private/params.h"
 
 static errno_t display_callback_create(display_t *);
@@ -237,4 +238,74 @@
 
 	*rgc = ipc_gc_get_ctx(gc);
+	return EOK;
+}
+
+/** Resize display window.
+ *
+ * It seems resizing windows should be easy with bounding rectangles.
+ * You have an old bounding rectangle and a new bounding rectangle (@a nrect).
+ * Change .p0 and top-left corner moves. Change .p1 and bottom-right corner
+ * moves. Piece of cake!
+ *
+ * There's always a catch, though. By series of resizes and moves .p0 could
+ * drift outside of the range of @c gfx_coord_t. Now what? @a offs to the
+ * rescue! @a offs moves the @em boundaries of the window with respect
+ * to the display, while keeping the @em contents of the window in the
+ * same place (with respect to the display). In other words, @a offs shifts
+ * the window's internal coordinate system.
+ *
+ * A few examples follow:
+ *
+ * Enlarge window by moving bottom-right corner 1 right, 1 down:
+ *
+ *   bound = (0, 0, 10, 10)
+ *   offs  = (0, 0)
+ *   nrect = (0, 0, 11, 11)
+ *
+ * Enlarge window by moving top-left corner, 1 up, 1 left, allowing the
+ * window-relative coordinate of the top-left corner to drift (undesirable)
+ *
+ *   bound = (0, 0, 10, 10)
+ *   offs  = (0, 0)
+ *   nrect = (-1, -1, 10, 10) <- this is the new bounding rectangle
+ *
+ * Enlarge window by moving top-left corner 1 up, 1 left, keeping top-left
+ * corner locked to (0,0) window-relative coordinates (desirable):
+ *
+ *   bound = (0, 0, 10, 10)
+ *   off   = (-1,-1)        <- top-left corner goes 1 up, 1 left
+ *   nrect = (0, 0, 11, 11) <- window still starts at 0,0 window-relative
+ *
+ * @param window Window
+ * @param nrect New bounding rectangle
+ * @param offs
+ * @return EOK on success or an error code. In both cases @a window must
+ *         not be accessed anymore
+ */
+errno_t display_window_resize(display_window_t *window, gfx_coord2_t *offs,
+    gfx_rect_t *nrect)
+{
+	async_exch_t *exch;
+	aid_t req;
+	ipc_call_t answer;
+	display_wnd_move_t wmove;
+	errno_t rc;
+
+	wmove.offs = *offs;
+	wmove.nrect = *nrect;
+
+	exch = async_exchange_begin(window->display->sess);
+	req = async_send_1(exch, DISPLAY_WINDOW_RESIZE, window->id, &answer);
+	rc = async_data_write_start(exch, &wmove, sizeof (display_wnd_move_t));
+	async_exchange_end(exch);
+	if (rc != EOK) {
+		async_forget(req);
+		return rc;
+	}
+
+	async_wait_for(req, &rc);
+	if (rc != EOK)
+		return rc;
+
 	return EOK;
 }
Index: uspace/lib/display/test/display.c
===================================================================
--- uspace/lib/display/test/display.c	(revision 2a515dcdbf45d99dae90d9f82bc03f8416d806b7)
+++ uspace/lib/display/test/display.c	(revision 0e6e77f09b348a14b2b1fa8165b25000755a93f1)
@@ -55,4 +55,6 @@
 static errno_t test_window_create(void *, display_wnd_params_t *, sysarg_t *);
 static errno_t test_window_destroy(void *, sysarg_t);
+static errno_t test_window_resize(void *, sysarg_t, gfx_coord2_t *,
+    gfx_rect_t *);
 static errno_t test_get_event(void *, sysarg_t *, display_wnd_ev_t *);
 
@@ -62,4 +64,5 @@
 	.window_create = test_window_create,
 	.window_destroy = test_window_destroy,
+	.window_resize = test_window_resize,
 	.get_event = test_get_event
 };
@@ -88,4 +91,11 @@
 	gfx_rect_t create_rect;
 	bool window_destroy_called;
+	sysarg_t destroy_wnd_id;
+
+	bool window_resize_called;
+	gfx_coord2_t resize_offs;
+	gfx_rect_t resize_nbound;
+	sysarg_t resize_wnd_id;
+
 	bool get_event_called;
 	bool set_color_called;
@@ -220,4 +230,5 @@
 	rc = display_window_destroy(wnd);
 	PCUT_ASSERT_TRUE(resp.window_destroy_called);
+	PCUT_ASSERT_INT_EQUALS(wnd->id, resp.destroy_wnd_id);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -272,6 +283,132 @@
 	rc = display_window_destroy(wnd);
 	PCUT_ASSERT_TRUE(resp.window_destroy_called);
+	PCUT_ASSERT_INT_EQUALS(wnd->id, resp.destroy_wnd_id);
 	PCUT_ASSERT_ERRNO_VAL(resp.rc, rc);
 
+	display_close(disp);
+	rc = loc_service_unregister(sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+/** display_window_resize() with server returning error response works. */
+PCUT_TEST(window_resize_failure)
+{
+	errno_t rc;
+	service_id_t sid;
+	display_t *disp = NULL;
+	display_wnd_params_t params;
+	display_window_t *wnd;
+	gfx_coord2_t offs;
+	gfx_rect_t nrect;
+	test_response_t resp;
+
+	async_set_fallback_port_handler(test_display_conn, &resp);
+
+	// FIXME This causes this test to be non-reentrant!
+	rc = loc_server_register(test_display_server);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = loc_service_register(test_display_svc, &sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = display_open(test_display_svc, &disp);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(disp);
+
+	resp.rc = EOK;
+	display_wnd_params_init(&params);
+	params.rect.p0.x = 0;
+	params.rect.p0.y = 0;
+	params.rect.p0.x = 100;
+	params.rect.p0.y = 100;
+
+	rc = display_window_create(disp, &params, &test_display_wnd_cb,
+	    (void *) &resp, &wnd);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(wnd);
+
+	resp.rc = EIO;
+	resp.window_resize_called = false;
+	offs.x = 11;
+	offs.y = 12;
+	nrect.p0.x = 13;
+	nrect.p0.y = 14;
+	nrect.p1.x = 15;
+	nrect.p1.y = 16;
+
+	rc = display_window_resize(wnd, &offs, &nrect);
+	PCUT_ASSERT_TRUE(resp.window_resize_called);
+	PCUT_ASSERT_ERRNO_VAL(resp.rc, rc);
+	PCUT_ASSERT_INT_EQUALS(wnd->id, resp.resize_wnd_id);
+	PCUT_ASSERT_INT_EQUALS(offs.x, resp.resize_offs.x);
+	PCUT_ASSERT_INT_EQUALS(offs.y, resp.resize_offs.y);
+	PCUT_ASSERT_INT_EQUALS(nrect.p0.x, resp.resize_nbound.p0.x);
+	PCUT_ASSERT_INT_EQUALS(nrect.p0.y, resp.resize_nbound.p0.y);
+	PCUT_ASSERT_INT_EQUALS(nrect.p1.x, resp.resize_nbound.p1.x);
+	PCUT_ASSERT_INT_EQUALS(nrect.p1.y, resp.resize_nbound.p1.y);
+
+	display_window_destroy(wnd);
+	display_close(disp);
+	rc = loc_service_unregister(sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+/** display_window_resize() with server returning success response works. */
+PCUT_TEST(window_resize_success)
+{
+	errno_t rc;
+	service_id_t sid;
+	display_t *disp = NULL;
+	display_wnd_params_t params;
+	display_window_t *wnd;
+	gfx_coord2_t offs;
+	gfx_rect_t nrect;
+	test_response_t resp;
+
+	async_set_fallback_port_handler(test_display_conn, &resp);
+
+	// FIXME This causes this test to be non-reentrant!
+	rc = loc_server_register(test_display_server);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = loc_service_register(test_display_svc, &sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = display_open(test_display_svc, &disp);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(disp);
+
+	resp.rc = EOK;
+	display_wnd_params_init(&params);
+	params.rect.p0.x = 0;
+	params.rect.p0.y = 0;
+	params.rect.p0.x = 100;
+	params.rect.p0.y = 100;
+
+	rc = display_window_create(disp, &params, &test_display_wnd_cb,
+	    (void *) &resp, &wnd);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(wnd);
+
+	resp.rc = EOK;
+	resp.window_resize_called = false;
+	offs.x = 11;
+	offs.y = 12;
+	nrect.p0.x = 13;
+	nrect.p0.y = 14;
+	nrect.p1.x = 15;
+	nrect.p1.y = 16;
+
+	rc = display_window_resize(wnd, &offs, &nrect);
+	PCUT_ASSERT_TRUE(resp.window_resize_called);
+	PCUT_ASSERT_ERRNO_VAL(resp.rc, rc);
+	PCUT_ASSERT_INT_EQUALS(offs.x, resp.resize_offs.x);
+	PCUT_ASSERT_INT_EQUALS(offs.y, resp.resize_offs.y);
+	PCUT_ASSERT_INT_EQUALS(nrect.p0.x, resp.resize_nbound.p0.x);
+	PCUT_ASSERT_INT_EQUALS(nrect.p0.y, resp.resize_nbound.p0.y);
+	PCUT_ASSERT_INT_EQUALS(nrect.p1.x, resp.resize_nbound.p1.x);
+	PCUT_ASSERT_INT_EQUALS(nrect.p1.y, resp.resize_nbound.p1.y);
+
+	display_window_destroy(wnd);
 	display_close(disp);
 	rc = loc_service_unregister(sid);
@@ -792,4 +929,17 @@
 
 	resp->window_destroy_called = true;
+	resp->destroy_wnd_id = wnd_id;
+	return resp->rc;
+}
+
+static errno_t test_window_resize(void *arg, sysarg_t wnd_id,
+    gfx_coord2_t *offs, gfx_rect_t *nrect)
+{
+	test_response_t *resp = (test_response_t *) arg;
+
+	resp->window_resize_called = true;
+	resp->resize_wnd_id = wnd_id;
+	resp->resize_offs = *offs;
+	resp->resize_nbound = *nrect;
 	return resp->rc;
 }
Index: uspace/lib/gfx/include/gfx/coord.h
===================================================================
--- uspace/lib/gfx/include/gfx/coord.h	(revision 2a515dcdbf45d99dae90d9f82bc03f8416d806b7)
+++ uspace/lib/gfx/include/gfx/coord.h	(revision 0e6e77f09b348a14b2b1fa8165b25000755a93f1)
@@ -52,4 +52,5 @@
 extern void gfx_rect_clip(gfx_rect_t *, gfx_rect_t *, gfx_rect_t *);
 extern void gfx_rect_points_sort(gfx_rect_t *, gfx_rect_t *);
+extern void gfx_rect_dims(gfx_rect_t *, gfx_coord2_t *);
 extern bool gfx_rect_is_empty(gfx_rect_t *);
 extern bool gfx_pix_inside_rect(gfx_coord2_t *, gfx_rect_t *);
Index: uspace/lib/gfx/src/coord.c
===================================================================
--- uspace/lib/gfx/src/coord.c	(revision 2a515dcdbf45d99dae90d9f82bc03f8416d806b7)
+++ uspace/lib/gfx/src/coord.c	(revision 0e6e77f09b348a14b2b1fa8165b25000755a93f1)
@@ -235,4 +235,20 @@
 }
 
+/** Get rectangle dimensions.
+ *
+ * Get a vector containing the x, y dimensions of a rectangle. These are
+ * always nonnegative.
+ *
+ * @param rect Rectangle
+ * @param dims Place to store dimensions
+ */
+void gfx_rect_dims(gfx_rect_t *rect, gfx_coord2_t *dims)
+{
+	gfx_rect_t srect;
+
+	gfx_rect_points_sort(rect, &srect);
+	gfx_coord2_subtract(&srect.p1, &srect.p0, dims);
+}
+
 /** Return true if pixel at coordinate @a coord lies within rectangle @a rect. */
 bool gfx_pix_inside_rect(gfx_coord2_t *coord, gfx_rect_t *rect)
Index: uspace/lib/gfx/test/coord.c
===================================================================
--- uspace/lib/gfx/test/coord.c	(revision 2a515dcdbf45d99dae90d9f82bc03f8416d806b7)
+++ uspace/lib/gfx/test/coord.c	(revision 0e6e77f09b348a14b2b1fa8165b25000755a93f1)
@@ -239,5 +239,5 @@
 
 /** Sorting span with hight start and lower end point results in transposed span. */
-PCUT_TEST(span_points_sort_decs)
+PCUT_TEST(span_points_sort_desc)
 {
 	gfx_coord_t a, b;
@@ -580,4 +580,38 @@
 }
 
+/** Rectangle dimensions for straight rectangle are computed correctly */
+PCUT_TEST(rect_dims_straight)
+{
+	gfx_rect_t rect;
+	gfx_coord2_t dims;
+
+	rect.p0.x = 1;
+	rect.p0.y = 10;
+	rect.p1.x = 100;
+	rect.p1.y = 1000;
+
+	gfx_rect_dims(&rect, &dims);
+
+	PCUT_ASSERT_INT_EQUALS(99, dims.x);
+	PCUT_ASSERT_INT_EQUALS(990, dims.y);
+}
+
+/** Rectangle dimensions for reversed rectangle are computed correctly */
+PCUT_TEST(rect_dims_straight)
+{
+	gfx_rect_t rect;
+	gfx_coord2_t dims;
+
+	rect.p0.x = 1000;
+	rect.p0.y = 100;
+	rect.p1.x = 10;
+	rect.p1.y = 1;
+
+	gfx_rect_dims(&rect, &dims);
+
+	PCUT_ASSERT_INT_EQUALS(990, dims.x);
+	PCUT_ASSERT_INT_EQUALS(99, dims.y);
+}
+
 /** gfx_rect_is_empty for straight rectangle with zero columns returns true */
 PCUT_TEST(rect_is_empty_pos_x)
Index: uspace/lib/gui/window.c
===================================================================
--- uspace/lib/gui/window.c	(revision 2a515dcdbf45d99dae90d9f82bc03f8416d806b7)
+++ uspace/lib/gui/window.c	(revision 0e6e77f09b348a14b2b1fa8165b25000755a93f1)
@@ -382,10 +382,9 @@
     sysarg_t width, sysarg_t height, window_placement_flags_t placement_flags)
 {
-	display_wnd_params_t wparams;
-	display_window_t *new_window = NULL;
 	gfx_bitmap_params_t params;
 	gfx_bitmap_alloc_t alloc;
 	gfx_bitmap_t *new_bitmap = NULL;
-	gfx_context_t *new_gc = NULL;
+	gfx_coord2_t offs;
+	gfx_rect_t nrect;
 	errno_t rc;
 
@@ -406,24 +405,4 @@
 		return;
 
-	display_wnd_params_init(&wparams);
-	wparams.rect.p0.x = 0;
-	wparams.rect.p0.y = 0;
-	wparams.rect.p1.x = width;
-	wparams.rect.p1.y = height;
-
-	rc = display_window_create(win->display, &wparams, &window_cb,
-	    (void *) win, &new_window);
-	if (rc != EOK) {
-		surface_destroy(new_surface);
-		return;
-	}
-
-	rc = display_window_get_gc(new_window, &new_gc);
-	if (rc != EOK) {
-		display_window_destroy(new_window);
-		surface_destroy(new_surface);
-		return;
-	}
-
 	params.rect.p0.x = 0;
 	params.rect.p0.y = 0;
@@ -435,8 +414,6 @@
 	alloc.pixels = surface_direct_access(new_surface);
 
-	rc = gfx_bitmap_create(new_gc, &params, &alloc, &new_bitmap);
+	rc = gfx_bitmap_create(win->gc, &params, &alloc, &new_bitmap);
 	if (rc != EOK) {
-		gfx_context_delete(new_gc);
-		display_window_destroy(new_window);
 		surface_destroy(new_surface);
 		return;
@@ -447,10 +424,6 @@
 	surface_t *old_surface = win->surface;
 	gfx_bitmap_t *old_bitmap = win->bitmap;
-	display_window_t *old_window = win->dwindow;
-	gfx_context_t *old_gc = win->gc;
 	win->surface = new_surface;
 	win->bitmap = new_bitmap;
-	win->dwindow = new_window;
-	win->gc = new_gc;
 	fibril_mutex_unlock(&win->guard);
 
@@ -465,11 +438,13 @@
 	fibril_mutex_unlock(&win->guard);
 
-	/* Inform compositor about new surface. */
-#if 0
-	errno_t rc = win_resize(win->osess, offset_x, offset_y, width, height,
-	    placement_flags, surface_direct_access(new_surface));
-#endif
-	rc = EOK;
-
+	/* Resize the display window. */
+	offs.x = offset_x;
+	offs.y = offset_y;
+	nrect.p0.x = 0;
+	nrect.p0.y = 0;
+	nrect.p1.x = width;
+	nrect.p1.y = height;
+
+	rc = display_window_resize(win->dwindow, &offs, &nrect);
 	if (rc != EOK) {
 		/* Rollback to old surface. Reverse all changes. */
@@ -484,6 +459,4 @@
 		win->surface = old_surface;
 		win->bitmap = old_bitmap;
-		win->dwindow = old_window;
-		win->gc = old_gc;
 		fibril_mutex_unlock(&win->guard);
 
@@ -498,8 +471,4 @@
 		surface_destroy(new_surface);
 	} else {
-		if (old_window != NULL)
-			display_window_destroy(old_window);
-		if (old_gc != NULL)
-			gfx_context_delete(old_gc);
 		if (old_bitmap != NULL)
 			gfx_bitmap_destroy(old_bitmap);
@@ -643,4 +612,6 @@
     window_flags_t flags, const char *caption)
 {
+	display_wnd_params_t wparams;
+
 	window_t *win = (window_t *) calloc(1, sizeof(window_t));
 	if (!win)
@@ -663,8 +634,40 @@
 	win->grab = NULL;
 	win->focus = NULL;
-	win->surface = NULL;
+
+	/* Allocate resources for new surface. */
+	win->surface = surface_create(100, 100, NULL, SURFACE_FLAG_SHARED);
+	if (win->surface == NULL) {
+		free(win);
+		return NULL;
+	}
 
 	errno_t rc = display_open(winreg, &win->display);
 	if (rc != EOK) {
+		surface_destroy(win->surface);
+		free(win);
+		return NULL;
+	}
+
+	/* Window dimensions are not know at this time */
+	display_wnd_params_init(&wparams);
+	wparams.rect.p0.x = 0;
+	wparams.rect.p0.y = 0;
+	wparams.rect.p1.x = 100;
+	wparams.rect.p1.y = 100;
+
+	rc = display_window_create(win->display, &wparams, &window_cb,
+	    (void *) win, &win->dwindow);
+	if (rc != EOK) {
+		display_close(win->display);
+		surface_destroy(win->surface);
+		free(win);
+		return NULL;
+	}
+
+	rc = display_window_get_gc(win->dwindow, &win->gc);
+	if (rc != EOK) {
+		display_window_destroy(win->dwindow);
+		display_close(win->display);
+		surface_destroy(win->surface);
 		free(win);
 		return NULL;
Index: uspace/srv/hid/display/dsops.c
===================================================================
--- uspace/srv/hid/display/dsops.c	(revision 2a515dcdbf45d99dae90d9f82bc03f8416d806b7)
+++ uspace/srv/hid/display/dsops.c	(revision 0e6e77f09b348a14b2b1fa8165b25000755a93f1)
@@ -36,4 +36,5 @@
 #include <disp_srv.h>
 #include <errno.h>
+#include <gfx/coord.h>
 #include <io/log.h>
 #include "client.h"
@@ -45,4 +46,6 @@
 static errno_t disp_window_create(void *, display_wnd_params_t *, sysarg_t *);
 static errno_t disp_window_destroy(void *, sysarg_t);
+static errno_t disp_window_resize(void *, sysarg_t, gfx_coord2_t *,
+    gfx_rect_t *);
 static errno_t disp_get_event(void *, sysarg_t *, display_wnd_ev_t *);
 
@@ -50,4 +53,5 @@
 	.window_create = disp_window_create,
 	.window_destroy = disp_window_destroy,
+	.window_resize = disp_window_resize,
 	.get_event = disp_get_event
 };
@@ -98,4 +102,18 @@
 }
 
+static errno_t disp_window_resize(void *arg, sysarg_t wnd_id,
+    gfx_coord2_t *offs, gfx_rect_t *nbound)
+{
+	ds_client_t *client = (ds_client_t *) arg;
+	ds_window_t *wnd;
+
+	wnd = ds_client_find_window(client, wnd_id);
+	if (wnd == NULL)
+		return ENOENT;
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "disp_window_resize()");
+	return ds_window_resize(wnd, offs, nbound);
+}
+
 static errno_t disp_get_event(void *arg, sysarg_t *wnd_id,
     display_wnd_ev_t *event)
Index: uspace/srv/hid/display/test/display.c
===================================================================
--- uspace/srv/hid/display/test/display.c	(revision 2a515dcdbf45d99dae90d9f82bc03f8416d806b7)
+++ uspace/srv/hid/display/test/display.c	(revision 0e6e77f09b348a14b2b1fa8165b25000755a93f1)
@@ -53,5 +53,4 @@
 	printf("test_ds_ev_pending\n");
 	*called_cb = true;
-
 }
 
@@ -265,5 +264,5 @@
 	event.c = L'\0';
 
-	PCUT_ASSERT_FALSE(called_cb);
+	called_cb = false;
 
 	rc = ds_display_post_kbd_event(disp, &event);
@@ -316,16 +315,22 @@
 	event.c = L'\0';
 
-	PCUT_ASSERT_FALSE(called_cb);
+	called_cb = false;
 
 	rc = ds_display_post_kbd_event(disp, &event);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-	PCUT_ASSERT_FALSE(called_cb);
+
+	/* Got gocus/unfocus events */
+	PCUT_ASSERT_TRUE(called_cb);
 
 	/* Next window should be focused */
 	PCUT_ASSERT_EQUALS(w1, seat->focus);
 
+	called_cb = false;
+
 	rc = ds_display_post_kbd_event(disp, &event);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-	PCUT_ASSERT_FALSE(called_cb);
+
+	/* Got gocus/unfocus events */
+	PCUT_ASSERT_TRUE(called_cb);
 
 	/* Focus should be back to the first window */
@@ -361,4 +366,14 @@
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
+	/*
+	 * For PTD_MOVE to work we need to set display dimensions (as pointer
+	 * move is clipped to the display rectangle. Here we do it directly
+	 * instead of adding a display device.
+	 */
+	disp->rect.p0.x = 0;
+	disp->rect.p0.y = 0;
+	disp->rect.p1.x = 500;
+	disp->rect.p1.y = 500;
+
 	display_wnd_params_init(&params);
 	params.rect.p0.x = params.rect.p0.y = 0;
Index: uspace/srv/hid/display/test/window.c
===================================================================
--- uspace/srv/hid/display/test/window.c	(revision 2a515dcdbf45d99dae90d9f82bc03f8416d806b7)
+++ uspace/srv/hid/display/test/window.c	(revision 0e6e77f09b348a14b2b1fa8165b25000755a93f1)
@@ -49,4 +49,47 @@
 	.fill_rect = dummy_fill_rect
 };
+
+/** Test ds_window_resize(). */
+PCUT_TEST(window_resize)
+{
+	ds_display_t *disp;
+	ds_client_t *client;
+	ds_window_t *wnd;
+	display_wnd_params_t params;
+	gfx_coord2_t offs;
+	gfx_rect_t nrect;
+	errno_t rc;
+
+	rc = ds_display_create(NULL, &disp);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_client_create(disp, NULL, NULL, &client);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	display_wnd_params_init(&params);
+	params.rect.p0.x = params.rect.p0.y = 0;
+	params.rect.p1.x = params.rect.p1.y = 10;
+
+	rc = ds_window_create(client, &params, &wnd);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	wnd->dpos.x = 100;
+	wnd->dpos.y = 100;
+
+	offs.x = -2;
+	offs.y = -3;
+	params.rect.p0.x = params.rect.p0.y = 0;
+	params.rect.p1.x = 12;
+	params.rect.p1.y = 13;
+	rc = ds_window_resize(wnd, &offs, &nrect);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	PCUT_ASSERT_INT_EQUALS(98, wnd->dpos.x);
+	PCUT_ASSERT_INT_EQUALS(97, wnd->dpos.y);
+
+	ds_window_destroy(wnd);
+	ds_client_destroy(client);
+	ds_display_destroy(disp);
+}
 
 /** Test ds_window_get_ctx(). */
Index: uspace/srv/hid/display/window.c
===================================================================
--- uspace/srv/hid/display/window.c	(revision 2a515dcdbf45d99dae90d9f82bc03f8416d806b7)
+++ uspace/srv/hid/display/window.c	(revision 0e6e77f09b348a14b2b1fa8165b25000755a93f1)
@@ -264,5 +264,4 @@
 	gfx_context_t *gc = NULL;
 	gfx_context_t *dgc;
-	gfx_rect_t rect;
 	gfx_coord2_t dims;
 	gfx_bitmap_params_t bparams;
@@ -282,7 +281,4 @@
 	ds_client_add_window(client, wnd);
 	ds_display_add_window(client->display, wnd);
-
-	gfx_rect_points_sort(&params->rect, &rect);
-	gfx_coord2_subtract(&rect.p1, &rect.p0, &dims);
 
 	bparams.rect = params->rect;
@@ -298,12 +294,8 @@
 			goto error;
 
+		gfx_rect_dims(&params->rect, &dims);
 		wnd->pixelmap.width = dims.x;
 		wnd->pixelmap.height = dims.y;
 		wnd->pixelmap.data = alloc.pixels;
-
-		if (wnd->pixelmap.data == NULL) {
-			rc = ENOMEM;
-			goto error;
-		}
 	}
 
@@ -323,7 +315,7 @@
 }
 
-/** Delete window GC.
- *
- * @param wnd Window GC
+/** Destroy window.
+ *
+ * @param wnd Window
  */
 void ds_window_destroy(ds_window_t *wnd)
@@ -343,4 +335,57 @@
 
 	(void) ds_display_paint(disp, NULL);
+}
+
+/** Resize window.
+ *
+ * @param wnd Window
+ */
+errno_t ds_window_resize(ds_window_t *wnd, gfx_coord2_t *offs,
+    gfx_rect_t *nrect)
+{
+	gfx_context_t *dgc;
+	gfx_bitmap_params_t bparams;
+	gfx_bitmap_t *nbitmap;
+	pixelmap_t npixelmap;
+	gfx_coord2_t dims;
+	gfx_bitmap_alloc_t alloc;
+	gfx_coord2_t ndpos;
+	errno_t rc;
+
+	dgc = ds_display_get_gc(wnd->display); // XXX
+	if (dgc != NULL) {
+		bparams.rect = *nrect;
+
+		rc = gfx_bitmap_create(dgc, &bparams, NULL, &nbitmap);
+		if (rc != EOK)
+			return ENOMEM;
+
+		rc = gfx_bitmap_get_alloc(nbitmap, &alloc);
+		if (rc != EOK) {
+			gfx_bitmap_destroy(nbitmap);
+			return ENOMEM;
+		}
+
+		gfx_rect_dims(nrect, &dims);
+		npixelmap.width = dims.x;
+		npixelmap.height = dims.y;
+		npixelmap.data = alloc.pixels;
+
+		/* TODO: Transfer contents within overlap */
+
+		if (wnd->bitmap != NULL)
+			gfx_bitmap_destroy(wnd->bitmap);
+
+		wnd->bitmap = nbitmap;
+		wnd->pixelmap = npixelmap;
+	}
+
+	gfx_coord2_add(&wnd->dpos, offs, &ndpos);
+
+	wnd->dpos = ndpos;
+	wnd->rect = *nrect;
+
+	(void) ds_display_paint(wnd->display, NULL);
+	return EOK;
 }
 
Index: uspace/srv/hid/display/window.h
===================================================================
--- uspace/srv/hid/display/window.h	(revision 2a515dcdbf45d99dae90d9f82bc03f8416d806b7)
+++ uspace/srv/hid/display/window.h	(revision 0e6e77f09b348a14b2b1fa8165b25000755a93f1)
@@ -51,4 +51,5 @@
     ds_window_t **);
 extern void ds_window_destroy(ds_window_t *);
+extern errno_t ds_window_resize(ds_window_t *, gfx_coord2_t *, gfx_rect_t *);
 extern gfx_context_t *ds_window_get_ctx(ds_window_t *);
 extern errno_t ds_window_paint(ds_window_t *, gfx_rect_t *);
