diff --git a/src/newifc/genapi.c b/src/newifc/genapi.c
index f7556741b332dd09b974a893dbd5e93ca5d8eb4c..140701fc75be8e2c10f9c48b2ca3bddb88e894ea 100644
--- a/src/newifc/genapi.c
+++ b/src/newifc/genapi.c
@@ -33,6 +33,11 @@ struct attribute_info {
 
 const struct attribute_info
 attributes[] = {
+	{"child_height", "uint16_t", attr_impl_global, 1},
+	{"child_width", "uint16_t", attr_impl_global, 1},
+	{"child_xpos", "uint16_t", attr_impl_global, 1},
+	{"child_ypos", "uint16_t", attr_impl_global, 1},
+	{"dirty", "bool", attr_impl_root, 1},
 	{"height", "uint16_t", attr_impl_global, 0},
 	{"locked", "bool", attr_impl_root, 0},
 	{"locked_by_me", "bool", attr_impl_root, 1},
@@ -41,6 +46,8 @@ attributes[] = {
 	{"title", "const char *", attr_impl_object, 0},
 	{"transparent", "bool", attr_impl_object, 0},
 	{"width", "uint16_t", attr_impl_global, 0},
+	{"xpos", "uint16_t", attr_impl_global, 0},
+	{"ypos", "uint16_t", attr_impl_global, 0},
 };
 
 struct error_info {
@@ -55,6 +62,7 @@ error_inf[] = {
 	{"error_not_implemented"},
 	{"error_lock_failed"},
 	{"error_needs_parent"},
+	{"error_wont_fit"},
 };
 
 int
@@ -100,6 +108,7 @@ main(int argc, char **argv)
 	fputs("NewIfcObj NI_copy(NewIfcObj obj);\n", header);
 	fputs("NewIfcObj NI_create(enum NewIfc_object obj, NewIfcObj parent);\n", header);
 	fputs("enum NewIfc_error NI_error(NewIfcObj obj);\n\n", header);
+	fputs("bool NI_walk_children(NewIfcObj obj, bool (*cb)(NewIfcObj obj, void *cb_data), void *cbdata);\n", header);
 
 	nitems = sizeof(attributes) / sizeof(attributes[0]);
 	for (i = 0; i < nitems; i++) {
@@ -133,10 +142,16 @@ main(int argc, char **argv)
 	      "\tNewIfcObj lowerpeer;\n"
 	      "\tNewIfcObj topchild;\n"
 	      "\tNewIfcObj bottomchild;\n"
-	      "\tuint16_t height;\n"
-	      "\tuint16_t width;\n"
 	      "\tenum NewIfc_object type;\n"
 	      "\tenum NewIfc_error last_error;\n"
+	      "\tuint16_t height;\n"
+	      "\tuint16_t width;\n"
+	      "\tuint16_t xpos;\n"
+	      "\tuint16_t ypos;\n"
+	      "\tuint16_t child_height;\n"
+	      "\tuint16_t child_width;\n"
+	      "\tuint16_t child_xpos;\n"
+	      "\tuint16_t child_ypos;\n"
 	      "};\n\n", internal_header);
 
 	fputs("enum NewIfc_attribute {\n", internal_header);
@@ -214,16 +229,7 @@ main(int argc, char **argv)
 	      "\treturn ret;\n"
 	      "};\n\n", c_code);
 
-	fputs("NewIfcObj\n"
-	      "NI_copy(NewIfcObj obj) {\n"
-	      "\treturn obj->copy(obj);\n"
-	      "}\n\n", c_code);
-
-	fputs("enum NewIfc_error\n"
-	      "NI_error(NewIfcObj obj)\n"
-	      "{\n"
-	      "\treturn obj->last_error;\n"
-	      "}\n\n", c_code);
+	fputs("#include \"newifc_nongen.c\"\n\n", c_code);
 
 	nitems = sizeof(attributes) / sizeof(attributes[0]);
 	for (i = 0; i < nitems; i++) {
@@ -261,38 +267,48 @@ main(int argc, char **argv)
 							"NI_set_%s(NewIfcObj obj, %s value) {\n"
 							"\tbool ret;\n"
 							"\tif (NI_set_locked(obj, true)) {\n"
-							"\t\tobj->%s = value;\n"
+							"\t\tif ((!obj->set(obj, NewIfc_%s, value)) && obj->last_error != NewIfc_error_not_implemented) {\n"
+							"\t\t\tobj->%s = value;\n"
+							"\t\t\tobj->last_error = NewIfc_error_none;\n"
+							"\t\t}\n"
 							"\t\tNI_set_locked(obj, false);\n"
 							"\t}\n"
 							"\telse\n"
 							"\t\tret = false;\n"
 							"\treturn ret;\n"
-							"}\n\n", attributes[i].name, attributes[i].type, attributes[i].name);
+							"}\n\n", attributes[i].name, attributes[i].type, attributes[i].name, attributes[i].name);
 				}
 
 				fprintf(c_code, "bool\n"
-						"NI_get_%s(NewIfcObj obj, %s* value) {\n"
-						"\tbool ret;\n"
-						"\tif (NI_set_locked(obj, true)) {\n"
-						"\t\t*value = obj->%s;\n"
+				                "NI_get_%s(NewIfcObj obj, %s* value) {\n"
+				                "\tbool ret;\n"
+				                "\tif (NI_set_locked(obj, true)) {\n"
+						"\t\tif ((!obj->get(obj, NewIfc_%s, value)) && obj->last_error != NewIfc_error_not_implemented) {\n"
+						"\t\t\t*value = obj->%s;\n"
+						"\t\t\tobj->last_error = NewIfc_error_none;\n"
+						"\t\t}\n"
 						"\t\tNI_set_locked(obj, false);\n"
 						"\t}\n"
 						"\telse\n"
 						"\t\tret = false;\n"
 						"\treturn ret;\n"
-						"}\n\n", attributes[i].name, attributes[i].type, attributes[i].name);
+						"}\n\n", attributes[i].name, attributes[i].type, attributes[i].name, attributes[i].name);
 				break;
 			case attr_impl_root:
 				if (!attributes[i].read_only) {
 					fprintf(c_code, "bool\n"
 							"NI_set_%s(NewIfcObj obj, %s value) {\n"
-							"\treturn obj->root->set(obj, NewIfc_%s, value);\n"
+							"\tbool ret = obj->root->set(obj, NewIfc_%s, value);\n"
+							"\tobj->last_error = obj->root->last_error;\n"
+							"\treturn ret;\n"
 							"}\n\n", attributes[i].name, attributes[i].type, attributes[i].name);
 				}
 
 				fprintf(c_code, "bool\n"
 						"NI_get_%s(NewIfcObj obj, %s* value) {\n"
-						"\treturn obj->root->get(obj, NewIfc_%s, value);\n"
+						"\tbool ret = obj->root->get(obj, NewIfc_%s, value);\n"
+						"\tobj->last_error = obj->root->last_error;\n"
+						"\treturn ret;\n"
 						"}\n\n", attributes[i].name, attributes[i].type, attributes[i].name);
 				break;
 		}
diff --git a/src/newifc/newifc_nongen.c b/src/newifc/newifc_nongen.c
new file mode 100644
index 0000000000000000000000000000000000000000..126c272d8d69871f3997d3fb2ec7a219b5f6dc39
--- /dev/null
+++ b/src/newifc/newifc_nongen.c
@@ -0,0 +1,39 @@
+NewIfcObj
+NI_copy(NewIfcObj obj) {
+	return obj->copy(obj);
+}
+
+enum NewIfc_error
+NI_error(NewIfcObj obj)
+{
+	return obj->last_error;
+}
+
+static bool
+NI_walk_children_recurse(NewIfcObj obj, bool (*cb)(NewIfcObj obj, void *cb_data), void *cbdata)
+{
+	if (!obj)
+		return true;
+	if (!cb(obj, cbdata))
+		return false;
+	if (obj->bottomchild != NULL) {
+		if (!NI_walk_children_recurse(obj->bottomchild, cb, cbdata))
+			return false;
+	}
+	if (!obj->higherpeer)
+		return true;
+	return NI_walk_children_recurse(obj->higherpeer, cb, cbdata);
+}
+
+bool
+NI_walk_children(NewIfcObj obj, bool (*cb)(NewIfcObj obj, void *cb_data), void *cbdata)
+{
+	bool ret;
+	if (NI_set_locked(obj, true)) {
+		NI_walk_children_recurse(obj->bottomchild, cb, cbdata);
+		NI_set_locked(obj, false);
+	}
+	else
+		ret = false;
+	return ret;
+}
diff --git a/src/newifc/root_window.c b/src/newifc/root_window.c
index 8e25098f128179fbbfc2fba02151f5d869b48be6..26cdbf375aa791f0e2dcbd45bd68d2974f59781d 100644
--- a/src/newifc/root_window.c
+++ b/src/newifc/root_window.c
@@ -26,8 +26,53 @@ struct root_window {
 	unsigned transparent:1;
 	unsigned show_title:1;
 	unsigned help:1;
+	unsigned dirty:1;
+};
+
+struct rw_recalc_child_cb_params {
+	uint16_t height;
+	uint16_t width;
 };
 
+static bool
+rw_recalc_child_cb(NewIfcObj obj, void *cbdata)
+{
+	struct rw_recalc_child_cb_params *nsz = cbdata;
+
+	if (obj->height > nsz->height)
+		return false;
+	if (obj->width > nsz->width)
+		return false;
+	return true;
+}
+
+static void
+rw_recalc_child(struct root_window *rw, uint16_t height, uint16_t width)
+{
+	uint16_t losty = 0;
+	struct rw_recalc_child_cb_params nsz = {height, width};
+
+	if (rw->show_title) {
+		nsz.height--;
+		losty++;
+	}
+	if (rw->help) {
+		nsz.height--;
+		losty++;
+	}
+	if (losty > height) {
+		rw->api.last_error = NewIfc_error_wont_fit;
+		return;
+	}
+	if (!NI_walk_children((NewIfcObj)rw, rw_recalc_child_cb, &nsz)) {
+		rw->api.last_error = NewIfc_error_wont_fit;
+		return;
+	}
+	rw->api.child_height = nsz.height;
+	rw->api.child_ypos = rw->show_title ? 1 : 0;
+	return;
+}
+
 static bool
 rw_set(NewIfcObj obj, int attr, ...)
 {
@@ -45,9 +90,17 @@ rw_set(NewIfcObj obj, int attr, ...)
 			break;
 		case NewIfc_show_help:
 			SET_BOOL(rw, help);
+			rw_recalc_child(rw, rw->api.height, rw->api.width);
 			break;
 		case NewIfc_title:
 			SET_STRING(rw, title, title_sz);
+			rw_recalc_child(rw, rw->api.height, rw->api.width);
+			break;
+		case NewIfc_height:
+			rw_recalc_child(rw, va_arg(ap, int), rw->api.width);
+			break;
+		case NewIfc_width:
+			rw_recalc_child(rw, rw->api.height, va_arg(ap, int));
 			break;
 		case NewIfc_locked:
 			if (va_arg(ap, int)) {
@@ -176,6 +229,12 @@ NewIFC_root_window(void)
 		ret->api.last_error = NewIfc_error_none;
 		ret->api.width = 80;
 		ret->api.height = 25;
+		ret->api.xpos = 0;
+		ret->api.ypos = 0;
+		ret->api.child_xpos = 0;
+		ret->api.child_ypos = 1;
+		ret->api.child_width = 80;
+		ret->api.child_height = 23;
 		ret->transparent = false;
 		ret->show_title = true;
 		ret->help = true;