Index: uspace/app/taskbar/wndlist.c
===================================================================
--- uspace/app/taskbar/wndlist.c	(revision fc00f0de04b9593122fa431e3a1c99574d299f16)
+++ uspace/app/taskbar/wndlist.c	(revision f1f433d10ab8dfdc792a9cdc8807b76dbcfac663)
@@ -48,8 +48,10 @@
 static void wndlist_wm_window_added(void *, sysarg_t);
 static void wndlist_wm_window_removed(void *, sysarg_t);
+static void wndlist_wm_window_changed(void *, sysarg_t);
 
 static wndmgt_cb_t wndlist_wndmgt_cb = {
 	.window_added = wndlist_wm_window_added,
-	.window_removed = wndlist_wm_window_removed
+	.window_removed = wndlist_wm_window_removed,
+	.window_changed = wndlist_wm_window_changed
 };
 
@@ -233,4 +235,27 @@
 	if (!paint)
 		return EOK;
+
+	return wndlist_repaint(wndlist);
+}
+
+/** Update window list entry.
+ *
+ * @param wndlist Window list
+ * @param entry Window list entry
+ * @return @c EOK on success or an error code
+ */
+errno_t wndlist_update(wndlist_t *wndlist, wndlist_entry_t *entry,
+    const char *caption)
+{
+	errno_t rc;
+	assert(entry->wndlist == wndlist);
+
+	rc = ui_pbutton_set_caption(entry->button, caption);
+	if (rc != EOK)
+		return rc;
+
+	rc = ui_pbutton_paint(entry->button);
+	if (rc != EOK)
+		return rc;
 
 	return wndlist_repaint(wndlist);
@@ -325,4 +350,31 @@
 }
 
+/** Handle WM window changed event.
+ *
+ * @param arg Argument (wndlist_t *)
+ * @param wnd_id Window ID
+ */
+static void wndlist_wm_window_changed(void *arg, sysarg_t wnd_id)
+{
+	wndlist_t *wndlist = (wndlist_t *)arg;
+	wndmgt_window_info_t *winfo = NULL;
+	wndlist_entry_t *entry;
+	errno_t rc;
+
+	printf("wm_window_changed: wndlist=%p wnd_id=%zu\n",
+	    (void *)wndlist, wnd_id);
+
+	entry = wndlist_entry_by_id(wndlist, wnd_id);
+	if (entry == NULL)
+		return;
+
+	rc = wndmgt_get_window_info(wndlist->wndmgt, wnd_id, &winfo);
+	if (rc != EOK)
+		return;
+
+	(void) wndlist_update(wndlist, entry, winfo->caption);
+	wndmgt_free_window_info(winfo);
+}
+
 /** Find window list entry by ID.
  *
Index: uspace/app/taskbar/wndlist.h
===================================================================
--- uspace/app/taskbar/wndlist.h	(revision fc00f0de04b9593122fa431e3a1c99574d299f16)
+++ uspace/app/taskbar/wndlist.h	(revision f1f433d10ab8dfdc792a9cdc8807b76dbcfac663)
@@ -49,4 +49,5 @@
 extern errno_t wndlist_append(wndlist_t *, sysarg_t, const char *, bool);
 extern errno_t wndlist_remove(wndlist_t *, wndlist_entry_t *, bool);
+extern errno_t wndlist_update(wndlist_t *, wndlist_entry_t *, const char *);
 extern void wndlist_set_entry_rect(wndlist_t *, wndlist_entry_t *);
 extern wndlist_entry_t *wndlist_entry_by_id(wndlist_t *, sysarg_t);
Index: uspace/lib/ui/include/ui/pbutton.h
===================================================================
--- uspace/lib/ui/include/ui/pbutton.h	(revision fc00f0de04b9593122fa431e3a1c99574d299f16)
+++ uspace/lib/ui/include/ui/pbutton.h	(revision f1f433d10ab8dfdc792a9cdc8807b76dbcfac663)
@@ -56,4 +56,5 @@
 extern void ui_pbutton_set_rect(ui_pbutton_t *, gfx_rect_t *);
 extern void ui_pbutton_set_default(ui_pbutton_t *, bool);
+extern errno_t ui_pbutton_set_caption(ui_pbutton_t *, const char *);
 extern errno_t ui_pbutton_paint(ui_pbutton_t *);
 extern void ui_pbutton_press(ui_pbutton_t *);
Index: uspace/lib/ui/private/pbutton.h
===================================================================
--- uspace/lib/ui/private/pbutton.h	(revision fc00f0de04b9593122fa431e3a1c99574d299f16)
+++ uspace/lib/ui/private/pbutton.h	(revision f1f433d10ab8dfdc792a9cdc8807b76dbcfac663)
@@ -62,5 +62,5 @@
 	gfx_rect_t rect;
 	/** Caption */
-	const char *caption;
+	char *caption;
 	/** Button is selected as default */
 	bool isdefault;
Index: uspace/lib/ui/src/pbutton.c
===================================================================
--- uspace/lib/ui/src/pbutton.c	(revision fc00f0de04b9593122fa431e3a1c99574d299f16)
+++ uspace/lib/ui/src/pbutton.c	(revision f1f433d10ab8dfdc792a9cdc8807b76dbcfac663)
@@ -114,4 +114,5 @@
 
 	ui_control_delete(pbutton->control);
+	free(pbutton->caption);
 	free(pbutton);
 }
@@ -183,4 +184,23 @@
 {
 	pbutton->isdefault = isdefault;
+}
+
+/** Set push button caption.
+ *
+ * @param pbutton Button
+ * @param caption New caption
+ * @return EOK on success, ENOMEM if out of memory
+ */
+errno_t ui_pbutton_set_caption(ui_pbutton_t *pbutton, const char *caption)
+{
+	char *dcaption;
+
+	dcaption = str_dup(caption);
+	if (dcaption == NULL)
+		return ENOMEM;
+
+	free(pbutton->caption);
+	pbutton->caption = dcaption;
+	return EOK;
 }
 
Index: uspace/lib/ui/test/pbutton.c
===================================================================
--- uspace/lib/ui/test/pbutton.c	(revision fc00f0de04b9593122fa431e3a1c99574d299f16)
+++ uspace/lib/ui/test/pbutton.c	(revision f1f433d10ab8dfdc792a9cdc8807b76dbcfac663)
@@ -190,4 +190,23 @@
 }
 
+/** Set caption sets internal field */
+PCUT_TEST(set_caption)
+{
+	ui_pbutton_t *pbutton;
+	errno_t rc;
+
+	rc = ui_pbutton_create(NULL, "Hello", &pbutton);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	PCUT_ASSERT_STR_EQUALS("Hello", pbutton->caption);
+
+	rc = ui_pbutton_set_caption(pbutton, "World");
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	PCUT_ASSERT_STR_EQUALS("World", pbutton->caption);
+
+	ui_pbutton_destroy(pbutton);
+}
+
 /** Paint button */
 PCUT_TEST(paint)
Index: uspace/lib/wndmgt/include/types/wndmgt.h
===================================================================
--- uspace/lib/wndmgt/include/types/wndmgt.h	(revision fc00f0de04b9593122fa431e3a1c99574d299f16)
+++ uspace/lib/wndmgt/include/types/wndmgt.h	(revision f1f433d10ab8dfdc792a9cdc8807b76dbcfac663)
@@ -53,4 +53,6 @@
 	/** Window removed */
 	void (*window_removed)(void *, sysarg_t);
+	/** Window changed */
+	void (*window_changed)(void *, sysarg_t);
 } wndmgt_cb_t;
 
@@ -60,5 +62,7 @@
 	wmev_window_added,
 	/** Window removed */
-	wmev_window_removed
+	wmev_window_removed,
+	/** Window changed */
+	wmev_window_changed
 } wndmgt_ev_type_t;
 
Index: uspace/lib/wndmgt/src/wndmgt.c
===================================================================
--- uspace/lib/wndmgt/src/wndmgt.c	(revision fc00f0de04b9593122fa431e3a1c99574d299f16)
+++ uspace/lib/wndmgt/src/wndmgt.c	(revision f1f433d10ab8dfdc792a9cdc8807b76dbcfac663)
@@ -387,4 +387,11 @@
 			}
 			break;
+		case wmev_window_changed:
+			if (wndmgt->cb != NULL &&
+			    wndmgt->cb->window_changed != NULL) {
+				wndmgt->cb->window_changed(wndmgt->cb_arg,
+				    event.wnd_id);
+			}
+			break;
 		}
 	}
Index: uspace/lib/wndmgt/test/wndmgt.c
===================================================================
--- uspace/lib/wndmgt/test/wndmgt.c	(revision fc00f0de04b9593122fa431e3a1c99574d299f16)
+++ uspace/lib/wndmgt/test/wndmgt.c	(revision f1f433d10ab8dfdc792a9cdc8807b76dbcfac663)
@@ -54,4 +54,5 @@
 static void test_window_added(void *, sysarg_t);
 static void test_window_removed(void *, sysarg_t);
+static void test_window_changed(void *, sysarg_t);
 
 static wndmgt_ops_t test_wndmgt_srv_ops = {
@@ -65,5 +66,6 @@
 static wndmgt_cb_t test_wndmgt_cb = {
 	.window_added = test_window_added,
-	.window_removed = test_window_removed
+	.window_removed = test_window_removed,
+	.window_changed = test_window_changed
 };
 
@@ -98,4 +100,7 @@
 	bool window_removed_called;
 	sysarg_t window_removed_wnd_id;
+
+	bool window_changed_called;
+	sysarg_t window_changed_wnd_id;
 
 	fibril_condvar_t event_cv;
@@ -529,4 +534,51 @@
 }
 
+/** Window changed event can be delivered from server to client callback function */
+PCUT_TEST(window_changed_deliver)
+{
+	errno_t rc;
+	service_id_t sid;
+	wndmgt_t *wndmgt = NULL;
+	test_response_t resp;
+
+	async_set_fallback_port_handler(test_wndmgt_conn, &resp);
+
+	// FIXME This causes this test to be non-reentrant!
+	rc = loc_server_register(test_wndmgt_server);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = loc_service_register(test_wndmgt_svc, &sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = wndmgt_open(test_wndmgt_svc, &test_wndmgt_cb, &resp, &wndmgt);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(wndmgt);
+	PCUT_ASSERT_NOT_NULL(resp.srv);
+
+	resp.event_cnt = 1;
+	resp.event.etype = wmev_window_changed;
+	resp.event.wnd_id = 42;
+	resp.window_changed_called = false;
+	fibril_mutex_initialize(&resp.event_lock);
+	fibril_condvar_initialize(&resp.event_cv);
+	wndmgt_srv_ev_pending(resp.srv);
+
+	/* Wait for the event handler to be called. */
+	fibril_mutex_lock(&resp.event_lock);
+	while (!resp.window_changed_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_INT_EQUALS(resp.event.etype,
+	    resp.revent.etype);
+
+	wndmgt_close(wndmgt);
+
+	rc = loc_service_unregister(sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
 /** Test window management service connection. */
 static void test_wndmgt_conn(ipc_call_t *icall, void *arg)
@@ -569,4 +621,17 @@
 	resp->window_removed_called = true;
 	resp->window_removed_wnd_id = wnd_id;
+	fibril_condvar_broadcast(&resp->event_cv);
+	fibril_mutex_unlock(&resp->event_lock);
+}
+
+static void test_window_changed(void *arg, sysarg_t wnd_id)
+{
+	test_response_t *resp = (test_response_t *) arg;
+
+	resp->revent.etype = wmev_window_changed;
+
+	fibril_mutex_lock(&resp->event_lock);
+	resp->window_changed_called = true;
+	resp->window_changed_wnd_id = wnd_id;
 	fibril_condvar_broadcast(&resp->event_cv);
 	fibril_mutex_unlock(&resp->event_lock);
Index: uspace/srv/hid/display/test/wmclient.c
===================================================================
--- uspace/srv/hid/display/test/wmclient.c	(revision fc00f0de04b9593122fa431e3a1c99574d299f16)
+++ uspace/srv/hid/display/test/wmclient.c	(revision f1f433d10ab8dfdc792a9cdc8807b76dbcfac663)
@@ -107,4 +107,82 @@
 }
 
+/** Test ds_wmclient_get_event(), ds_wmclient_post_wnd_removed_event(). */
+PCUT_TEST(client_get_post_wnd_removed_event)
+{
+	ds_display_t *disp;
+	ds_wmclient_t *wmclient;
+	wndmgt_ev_t revent;
+	bool called_cb = NULL;
+	sysarg_t wnd_id;
+	errno_t rc;
+
+	rc = ds_display_create(NULL, df_none, &disp);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_wmclient_create(disp, &test_ds_wmclient_cb, &called_cb,
+	    &wmclient);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	called_cb = false;
+	wnd_id = 42;
+
+	rc = ds_wmclient_get_event(wmclient, &revent);
+	PCUT_ASSERT_ERRNO_VAL(ENOENT, rc);
+
+	rc = ds_wmclient_post_wnd_removed_event(wmclient, wnd_id);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_TRUE(called_cb);
+
+	rc = ds_wmclient_get_event(wmclient, &revent);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_EQUALS(wnd_id, revent.wnd_id);
+	PCUT_ASSERT_EQUALS(wmev_window_removed, revent.etype);
+
+	rc = ds_wmclient_get_event(wmclient, &revent);
+	PCUT_ASSERT_ERRNO_VAL(ENOENT, rc);
+
+	ds_wmclient_destroy(wmclient);
+	ds_display_destroy(disp);
+}
+
+/** Test ds_wmclient_get_event(), ds_wmclient_post_wnd_changed_event(). */
+PCUT_TEST(client_get_post_wnd_changed_event)
+{
+	ds_display_t *disp;
+	ds_wmclient_t *wmclient;
+	wndmgt_ev_t revent;
+	bool called_cb = NULL;
+	sysarg_t wnd_id;
+	errno_t rc;
+
+	rc = ds_display_create(NULL, df_none, &disp);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_wmclient_create(disp, &test_ds_wmclient_cb, &called_cb,
+	    &wmclient);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	called_cb = false;
+	wnd_id = 42;
+
+	rc = ds_wmclient_get_event(wmclient, &revent);
+	PCUT_ASSERT_ERRNO_VAL(ENOENT, rc);
+
+	rc = ds_wmclient_post_wnd_changed_event(wmclient, wnd_id);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_TRUE(called_cb);
+
+	rc = ds_wmclient_get_event(wmclient, &revent);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_EQUALS(wnd_id, revent.wnd_id);
+	PCUT_ASSERT_EQUALS(wmev_window_changed, revent.etype);
+
+	rc = ds_wmclient_get_event(wmclient, &revent);
+	PCUT_ASSERT_ERRNO_VAL(ENOENT, rc);
+
+	ds_wmclient_destroy(wmclient);
+	ds_display_destroy(disp);
+}
+
 /** Test ds_wmclient_purge_events() */
 PCUT_TEST(purge_events)
Index: uspace/srv/hid/display/window.c
===================================================================
--- uspace/srv/hid/display/window.c	(revision fc00f0de04b9593122fa431e3a1c99574d299f16)
+++ uspace/srv/hid/display/window.c	(revision f1f433d10ab8dfdc792a9cdc8807b76dbcfac663)
@@ -45,8 +45,10 @@
 #include <stdlib.h>
 #include <str.h>
+#include <wndmgt.h>
 #include "client.h"
 #include "display.h"
 #include "seat.h"
 #include "window.h"
+#include "wmclient.h"
 
 static void ds_window_invalidate_cb(void *, gfx_rect_t *);
@@ -933,4 +935,5 @@
 {
 	char *dcaption;
+	ds_wmclient_t *wmclient;
 
 	dcaption = str_dup(caption);
@@ -940,4 +943,11 @@
 	free(wnd->caption);
 	wnd->caption = dcaption;
+
+	/* Notify window managers about window information change */
+	wmclient = ds_display_first_wmclient(wnd->display);
+	while (wmclient != NULL) {
+		ds_wmclient_post_wnd_changed_event(wmclient, wnd->id);
+		wmclient = ds_display_next_wmclient(wmclient);
+	}
 
 	return EOK;
Index: uspace/srv/hid/display/wmclient.c
===================================================================
--- uspace/srv/hid/display/wmclient.c	(revision fc00f0de04b9593122fa431e3a1c99574d299f16)
+++ uspace/srv/hid/display/wmclient.c	(revision f1f433d10ab8dfdc792a9cdc8807b76dbcfac663)
@@ -184,4 +184,33 @@
 }
 
+/** Post window changed event to the WM client's message queue.
+ *
+ * @param wmclient WM client
+ * @param wnd_id Window ID of the added window
+ *
+ * @return EOK on success or an error code
+ */
+errno_t ds_wmclient_post_wnd_changed_event(ds_wmclient_t *wmclient,
+    sysarg_t wnd_id)
+{
+	ds_wmclient_ev_t *wevent;
+
+	wevent = calloc(1, sizeof(ds_wmclient_ev_t));
+	if (wevent == NULL)
+		return ENOMEM;
+
+	wevent->wmclient = wmclient;
+	wevent->event.etype = wmev_window_changed;
+	wevent->event.wnd_id = wnd_id;
+	list_append(&wevent->levents, &wmclient->events);
+
+	/* Notify the client */
+	// TODO Do not send more than once until client drains the queue
+	if (wmclient->cb != NULL && wmclient->cb->ev_pending != NULL)
+		wmclient->cb->ev_pending(wmclient->cb_arg);
+
+	return EOK;
+}
+
 /** @}
  */
Index: uspace/srv/hid/display/wmclient.h
===================================================================
--- uspace/srv/hid/display/wmclient.h	(revision fc00f0de04b9593122fa431e3a1c99574d299f16)
+++ uspace/srv/hid/display/wmclient.h	(revision f1f433d10ab8dfdc792a9cdc8807b76dbcfac663)
@@ -48,4 +48,5 @@
 extern errno_t ds_wmclient_post_wnd_added_event(ds_wmclient_t *, sysarg_t);
 extern errno_t ds_wmclient_post_wnd_removed_event(ds_wmclient_t *, sysarg_t);
+extern errno_t ds_wmclient_post_wnd_changed_event(ds_wmclient_t *, sysarg_t);
 extern void ds_wmclient_purge_events(ds_wmclient_t *);
 
