Index: uspace/lib/display/include/types/display.h
===================================================================
--- uspace/lib/display/include/types/display.h	(revision e1f2079eea6e0ce553d66ced5b7ca0b64e0b4929)
+++ uspace/lib/display/include/types/display.h	(revision 0a052b087f4f2a5bf35eefa42452c3e975cbc319)
@@ -58,6 +58,12 @@
 /** Display window callbacks */
 typedef struct {
+	/** Focus event */
+	void (*focus_event)(void *);
+	/** Keyboard event callback */
 	void (*kbd_event)(void *, kbd_event_t *);
+	/** Position event callback */
 	void (*pos_event)(void *, pos_event_t *);
+	/** Unfocus event */
+	void (*unfocus_event)(void *);
 } display_wnd_cb_t;
 
Index: uspace/lib/display/include/types/display/event.h
===================================================================
--- uspace/lib/display/include/types/display/event.h	(revision e1f2079eea6e0ce553d66ced5b7ca0b64e0b4929)
+++ uspace/lib/display/include/types/display/event.h	(revision 0a052b087f4f2a5bf35eefa42452c3e975cbc319)
@@ -39,13 +39,24 @@
 #include <io/pos_event.h>
 
+/** Display window event type */
 typedef enum {
+	/** Window gained focus */
+	wev_focus,
+	/** Keyboard event */
 	wev_kbd,
-	wev_pos
+	/** Position event */
+	wev_pos,
+	/** Window lost focus */
+	wev_unfocus
 } display_wnd_ev_type_t;
 
+/** Display window event */
 typedef struct {
+	/** Event type */
 	display_wnd_ev_type_t etype;
 	union {
+		/** Keyboard event data */
 		kbd_event_t kbd;
+		/** Position event data */
 		pos_event_t pos;
 	} ev;
Index: uspace/lib/display/src/display.c
===================================================================
--- uspace/lib/display/src/display.c	(revision e1f2079eea6e0ce553d66ced5b7ca0b64e0b4929)
+++ uspace/lib/display/src/display.c	(revision 0a052b087f4f2a5bf35eefa42452c3e975cbc319)
@@ -296,4 +296,9 @@
 
 		switch (event.etype) {
+		case wev_focus:
+			if (window->cb != NULL && window->cb->focus_event != NULL) {
+				window->cb->focus_event(window->cb_arg);
+			}
+			break;
 		case wev_kbd:
 			if (window->cb != NULL && window->cb->kbd_event != NULL) {
@@ -306,4 +311,9 @@
 				window->cb->pos_event(window->cb_arg,
 				    &event.ev.pos);
+			}
+			break;
+		case wev_unfocus:
+			if (window->cb != NULL && window->cb->unfocus_event != NULL) {
+				window->cb->unfocus_event(window->cb_arg);
 			}
 			break;
Index: uspace/lib/display/test/display.c
===================================================================
--- uspace/lib/display/test/display.c	(revision e1f2079eea6e0ce553d66ced5b7ca0b64e0b4929)
+++ uspace/lib/display/test/display.c	(revision 0a052b087f4f2a5bf35eefa42452c3e975cbc319)
@@ -47,6 +47,9 @@
 
 static void test_display_conn(ipc_call_t *, void *);
+
+static void test_focus_event(void *);
 static void test_kbd_event(void *, kbd_event_t *);
 static void test_pos_event(void *, pos_event_t *);
+static void test_unfocus_event(void *);
 
 static errno_t test_window_create(void *, display_wnd_params_t *, sysarg_t *);
@@ -63,6 +66,8 @@
 
 static display_wnd_cb_t test_display_wnd_cb = {
+	.focus_event = test_focus_event,
 	.kbd_event = test_kbd_event,
-	.pos_event = test_pos_event
+	.pos_event = test_pos_event,
+	.unfocus_event = test_unfocus_event
 };
 
@@ -85,6 +90,8 @@
 	bool get_event_called;
 	bool set_color_called;
+	bool focus_event_called;
 	bool kbd_event_called;
 	bool pos_event_called;
+	bool unfocus_event_called;
 	fibril_condvar_t event_cv;
 	fibril_mutex_t event_lock;
@@ -382,4 +389,69 @@
 
 	display_close(disp);
+	rc = loc_service_unregister(sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+/** Focus event can be delivered from server to client callback function */
+PCUT_TEST(focus_event_deliver)
+{
+	errno_t rc;
+	service_id_t sid;
+	display_t *disp = NULL;
+	display_wnd_params_t params;
+	display_window_t *wnd;
+	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);
+	PCUT_ASSERT_NOT_NULL(resp.srv);
+
+	wnd = NULL;
+	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.event_cnt = 1;
+	resp.event.etype = wev_focus;
+	resp.wnd_id = wnd->id;
+	resp.focus_event_called = false;
+	fibril_mutex_initialize(&resp.event_lock);
+	fibril_condvar_initialize(&resp.event_cv);
+	display_srv_ev_pending(resp.srv);
+
+	/* Wait for the event handler to be called. */
+	fibril_mutex_lock(&resp.event_lock);
+	while (!resp.focus_event_called) {
+		fibril_condvar_wait(&resp.event_cv, &resp.event_lock);
+	}
+	fibril_mutex_unlock(&resp.event_lock);
+
+	/* Verify that the event was delivered correctly */
+	PCUT_ASSERT_EQUALS(resp.event.etype,
+	    resp.revent.etype);
+
+	rc = display_window_destroy(wnd);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	display_close(disp);
+
 	rc = loc_service_unregister(sid);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
@@ -540,4 +612,69 @@
 }
 
+/** Unfocus event can be delivered from server to client callback function */
+PCUT_TEST(unfocus_event_deliver)
+{
+	errno_t rc;
+	service_id_t sid;
+	display_t *disp = NULL;
+	display_wnd_params_t params;
+	display_window_t *wnd;
+	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);
+	PCUT_ASSERT_NOT_NULL(resp.srv);
+
+	wnd = NULL;
+	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.event_cnt = 1;
+	resp.event.etype = wev_unfocus;
+	resp.wnd_id = wnd->id;
+	resp.focus_event_called = false;
+	fibril_mutex_initialize(&resp.event_lock);
+	fibril_condvar_initialize(&resp.event_cv);
+	display_srv_ev_pending(resp.srv);
+
+	/* Wait for the event handler to be called. */
+	fibril_mutex_lock(&resp.event_lock);
+	while (!resp.unfocus_event_called) {
+		fibril_condvar_wait(&resp.event_cv, &resp.event_lock);
+	}
+	fibril_mutex_unlock(&resp.event_lock);
+
+	/* Verify that the event was delivered correctly */
+	PCUT_ASSERT_EQUALS(resp.event.etype,
+	    resp.revent.etype);
+
+	rc = display_window_destroy(wnd);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	display_close(disp);
+
+	rc = loc_service_unregister(sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
 /** Test display service connection.
  *
@@ -587,4 +724,16 @@
 }
 
+static void test_focus_event(void *arg)
+{
+	test_response_t *resp = (test_response_t *) arg;
+
+	resp->revent.etype = wev_focus;
+
+	fibril_mutex_lock(&resp->event_lock);
+	resp->focus_event_called = true;
+	fibril_condvar_broadcast(&resp->event_cv);
+	fibril_mutex_unlock(&resp->event_lock);
+}
+
 static void test_kbd_event(void *arg, kbd_event_t *event)
 {
@@ -609,4 +758,16 @@
 	fibril_mutex_lock(&resp->event_lock);
 	resp->pos_event_called = true;
+	fibril_condvar_broadcast(&resp->event_cv);
+	fibril_mutex_unlock(&resp->event_lock);
+}
+
+static void test_unfocus_event(void *arg)
+{
+	test_response_t *resp = (test_response_t *) arg;
+
+	resp->revent.etype = wev_unfocus;
+
+	fibril_mutex_lock(&resp->event_lock);
+	resp->unfocus_event_called = true;
 	fibril_condvar_broadcast(&resp->event_cv);
 	fibril_mutex_unlock(&resp->event_lock);
Index: uspace/lib/gui/window.c
===================================================================
--- uspace/lib/gui/window.c	(revision e1f2079eea6e0ce553d66ced5b7ca0b64e0b4929)
+++ uspace/lib/gui/window.c	(revision 0a052b087f4f2a5bf35eefa42452c3e975cbc319)
@@ -83,10 +83,14 @@
 static pixel_t color_caption_unfocus = PIXEL(255, 207, 207, 207);
 
+static void window_focus_event(void *);
 static void window_kbd_event(void *, kbd_event_t *);
 static void window_pos_event(void *, pos_event_t *);
+static void window_unfocus_event(void *);
 
 static display_wnd_cb_t window_cb = {
+	.focus_event = window_focus_event,
 	.kbd_event = window_kbd_event,
-	.pos_event = window_pos_event
+	.pos_event = window_pos_event,
+	.unfocus_event = window_unfocus_event
 };
 
@@ -587,8 +591,4 @@
 			break;
 		case ET_POSITION_EVENT:
-			if (!win->is_focused) {
-				win->is_focused = true;
-				handle_refresh(win);
-			}
 			deliver_position_event(win, event->data.pos);
 			break;
@@ -766,4 +766,18 @@
 }
 
+static void window_focus_event(void *arg)
+{
+	window_t *win = (window_t *) arg;
+	window_event_t *event;
+
+	event = (window_event_t *) calloc(1, sizeof(window_event_t));
+	if (event == NULL)
+		return;
+
+	link_initialize(&event->link);
+	event->type = ET_WINDOW_FOCUS;
+	prodcons_produce(&win->events, &event->link);
+}
+
 static void window_kbd_event(void *arg, kbd_event_t *kevent)
 {
@@ -796,4 +810,18 @@
 }
 
+static void window_unfocus_event(void *arg)
+{
+	window_t *win = (window_t *) arg;
+	window_event_t *event;
+
+	event = (window_event_t *) calloc(1, sizeof(window_event_t));
+	if (event == NULL)
+		return;
+
+	link_initialize(&event->link);
+	event->type = ET_WINDOW_UNFOCUS;
+	prodcons_produce(&win->events, &event->link);
+}
+
 /** @}
  */
