summary refs log tree commit diff
path: root/tui/newt
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2014-07-06 02:16:10 +0200
committerMichael Biebl <biebl@debian.org>2014-07-06 02:16:10 +0200
commit33491bc4279481db8ae47213e34a6d695a0e8830 (patch)
tree097d2b0fdff3fae6885381ae5e57a182cd8cbbba /tui/newt
parent59c3714a494c3b3765657c0551ad82842d98a7d2 (diff)
Imported Upstream version 0.9.10.0 upstream/0.9.10.0
Diffstat (limited to 'tui/newt')
-rw-r--r--tui/newt/Makefile.am54
-rw-r--r--tui/newt/Makefile.in802
-rw-r--r--tui/newt/nmt-newt-button-box.c385
-rw-r--r--tui/newt/nmt-newt-button-box.h65
-rw-r--r--tui/newt/nmt-newt-button.c260
-rw-r--r--tui/newt/nmt-newt-button.h53
-rw-r--r--tui/newt/nmt-newt-checkbox.c235
-rw-r--r--tui/newt/nmt-newt-checkbox.h53
-rw-r--r--tui/newt/nmt-newt-component.c307
-rw-r--r--tui/newt/nmt-newt-component.h57
-rw-r--r--tui/newt/nmt-newt-container.c252
-rw-r--r--tui/newt/nmt-newt-container.h61
-rw-r--r--tui/newt/nmt-newt-entry-numeric.c213
-rw-r--r--tui/newt/nmt-newt-entry-numeric.h51
-rw-r--r--tui/newt/nmt-newt-entry.c536
-rw-r--r--tui/newt/nmt-newt-entry.h74
-rw-r--r--tui/newt/nmt-newt-form.c743
-rw-r--r--tui/newt/nmt-newt-form.h66
-rw-r--r--tui/newt/nmt-newt-grid.c472
-rw-r--r--tui/newt/nmt-newt-grid.h72
-rw-r--r--tui/newt/nmt-newt-hacks.c103
-rw-r--r--tui/newt/nmt-newt-hacks.h42
-rw-r--r--tui/newt/nmt-newt-label.c323
-rw-r--r--tui/newt/nmt-newt-label.h66
-rw-r--r--tui/newt/nmt-newt-listbox.c543
-rw-r--r--tui/newt/nmt-newt-listbox.h71
-rw-r--r--tui/newt/nmt-newt-popup.c343
-rw-r--r--tui/newt/nmt-newt-popup.h62
-rw-r--r--tui/newt/nmt-newt-section.c408
-rw-r--r--tui/newt/nmt-newt-section.h57
-rw-r--r--tui/newt/nmt-newt-separator.c66
-rw-r--r--tui/newt/nmt-newt-separator.h49
-rw-r--r--tui/newt/nmt-newt-stack.c366
-rw-r--r--tui/newt/nmt-newt-stack.h61
-rw-r--r--tui/newt/nmt-newt-textbox.c292
-rw-r--r--tui/newt/nmt-newt-textbox.h59
-rw-r--r--tui/newt/nmt-newt-toggle-button.c234
-rw-r--r--tui/newt/nmt-newt-toggle-button.h54
-rw-r--r--tui/newt/nmt-newt-types.h50
-rw-r--r--tui/newt/nmt-newt-utils.c392
-rw-r--r--tui/newt/nmt-newt-utils.h53
-rw-r--r--tui/newt/nmt-newt-widget.c664
-rw-r--r--tui/newt/nmt-newt-widget.h118
-rw-r--r--tui/newt/nmt-newt.h39
44 files changed, 9326 insertions, 0 deletions
diff --git a/tui/newt/Makefile.am b/tui/newt/Makefile.am
new file mode 100644
index 00000000..0db5525d
--- /dev/null
+++ b/tui/newt/Makefile.am
@@ -0,0 +1,54 @@
+AM_CPPFLAGS= \
+	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
+	-DG_LOG_DOMAIN=\""nmtui"\" \
+	$(GLIB_CFLAGS) \
+	$(NEWT_CFLAGS) \
+	$(NULL)
+
+noinst_LIBRARIES = libnmt-newt.a
+
+libnmt_newt_a_SOURCES = \
+	nmt-newt.h \
+	nmt-newt-types.h \
+	nmt-newt-button.c \
+	nmt-newt-button.h \
+	nmt-newt-button-box.c \
+	nmt-newt-button-box.h \
+	nmt-newt-checkbox.c \
+	nmt-newt-checkbox.h \
+	nmt-newt-component.c \
+	nmt-newt-component.h \
+	nmt-newt-container.c \
+	nmt-newt-container.h \
+	nmt-newt-entry.c \
+	nmt-newt-entry.h \
+	nmt-newt-entry-numeric.c \
+	nmt-newt-entry-numeric.h \
+	nmt-newt-form.c \
+	nmt-newt-form.h \
+	nmt-newt-grid.c \
+	nmt-newt-grid.h \
+	nmt-newt-hacks.c \
+	nmt-newt-hacks.h \
+	nmt-newt-label.c \
+	nmt-newt-label.h \
+	nmt-newt-listbox.c \
+	nmt-newt-listbox.h \
+	nmt-newt-popup.c \
+	nmt-newt-popup.h \
+	nmt-newt-section.c \
+	nmt-newt-section.h \
+	nmt-newt-separator.c \
+	nmt-newt-separator.h \
+	nmt-newt-stack.c \
+	nmt-newt-stack.h \
+	nmt-newt-textbox.c \
+	nmt-newt-textbox.h \
+	nmt-newt-toggle-button.c \
+	nmt-newt-toggle-button.h \
+	nmt-newt-utils.c \
+	nmt-newt-utils.h \
+	nmt-newt-widget.c \
+	nmt-newt-widget.h \
+	$(NULL)
diff --git a/tui/newt/Makefile.in b/tui/newt/Makefile.in
new file mode 100644
index 00000000..043382be
--- /dev/null
+++ b/tui/newt/Makefile.in
@@ -0,0 +1,802 @@
+# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = tui/newt
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+	$(top_srcdir)/build-aux/depcomp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
+	$(top_srcdir)/m4/compiler_warnings.m4 \
+	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gnome-code-coverage.m4 \
+	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
+	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
+	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
+	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo "  AR      " $@;
+am__v_AR_1 = 
+libnmt_newt_a_AR = $(AR) $(ARFLAGS)
+libnmt_newt_a_LIBADD =
+am_libnmt_newt_a_OBJECTS = nmt-newt-button.$(OBJEXT) \
+	nmt-newt-button-box.$(OBJEXT) nmt-newt-checkbox.$(OBJEXT) \
+	nmt-newt-component.$(OBJEXT) nmt-newt-container.$(OBJEXT) \
+	nmt-newt-entry.$(OBJEXT) nmt-newt-entry-numeric.$(OBJEXT) \
+	nmt-newt-form.$(OBJEXT) nmt-newt-grid.$(OBJEXT) \
+	nmt-newt-hacks.$(OBJEXT) nmt-newt-label.$(OBJEXT) \
+	nmt-newt-listbox.$(OBJEXT) nmt-newt-popup.$(OBJEXT) \
+	nmt-newt-section.$(OBJEXT) nmt-newt-separator.$(OBJEXT) \
+	nmt-newt-stack.$(OBJEXT) nmt-newt-textbox.$(OBJEXT) \
+	nmt-newt-toggle-button.$(OBJEXT) nmt-newt-utils.$(OBJEXT) \
+	nmt-newt-widget.$(OBJEXT)
+libnmt_newt_a_OBJECTS = $(am_libnmt_newt_a_OBJECTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libnmt_newt_a_SOURCES)
+DIST_SOURCES = $(libnmt_newt_a_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CKDB_PATH = @CKDB_PATH@
+CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@
+CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
+CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
+DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
+DBUS_LIBS = @DBUS_LIBS@
+DBUS_SYS_DIR = @DBUS_SYS_DIR@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DHCLIENT_PATH = @DHCLIENT_PATH@
+DHCPCD_PATH = @DHCPCD_PATH@
+DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@
+DLLTOOL = @DLLTOOL@
+DNSMASQ_PATH = @DNSMASQ_PATH@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GENHTML = @GENHTML@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
+GNUTLS_LIBS = @GNUTLS_LIBS@
+GREP = @GREP@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
+INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
+INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@
+INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@
+INTROSPECTION_LIBS = @INTROSPECTION_LIBS@
+INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@
+INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
+INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@
+IPTABLES_PATH = @IPTABLES_PATH@
+IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@
+IWMX_SDK_LIBS = @IWMX_SDK_LIBS@
+KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDL = @LIBDL@
+LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
+LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
+LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBNDP_CFLAGS = @LIBNDP_CFLAGS@
+LIBNDP_LIBS = @LIBNDP_LIBS@
+LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_LIBS = @LIBNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
+LIBTEAMDCTL_CFLAGS = @LIBTEAMDCTL_CFLAGS@
+LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MM_GLIB_CFLAGS = @MM_GLIB_CFLAGS@
+MM_GLIB_LIBS = @MM_GLIB_LIBS@
+MOC = @MOC@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NEWT_CFLAGS = @NEWT_CFLAGS@
+NEWT_LIBS = @NEWT_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
+NM_MICRO_VERSION = @NM_MICRO_VERSION@
+NM_MINOR_VERSION = @NM_MINOR_VERSION@
+NM_MODIFY_SYSTEM_POLICY = @NM_MODIFY_SYSTEM_POLICY@
+NM_VERSION = @NM_VERSION@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POLKIT_CFLAGS = @POLKIT_CFLAGS@
+POLKIT_LIBS = @POLKIT_LIBS@
+POSUB = @POSUB@
+PPPD_PATH = @PPPD_PATH@
+PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
+PPPOE_PATH = @PPPOE_PATH@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+RANLIB = @RANLIB@
+READLINE_LIBS = @READLINE_LIBS@
+SED = @SED@
+SELINUX_CFLAGS = @SELINUX_CFLAGS@
+SELINUX_LIBS = @SELINUX_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SYSTEMD_200_CFLAGS = @SYSTEMD_200_CFLAGS@
+SYSTEMD_200_LIBS = @SYSTEMD_200_LIBS@
+SYSTEMD_INHIBIT_CFLAGS = @SYSTEMD_INHIBIT_CFLAGS@
+SYSTEMD_INHIBIT_LIBS = @SYSTEMD_INHIBIT_LIBS@
+SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@
+SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@
+SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
+UDEV_BASE_DIR = @UDEV_BASE_DIR@
+USE_NLS = @USE_NLS@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VALGRIND_RULES = @VALGRIND_RULES@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nmbinary = @nmbinary@
+nmconfdir = @nmconfdir@
+nmdatadir = @nmdatadir@
+nmrundir = @nmrundir@
+nmstatedir = @nmstatedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+systemdsystemunitdir = @systemdsystemunitdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+with_dhclient = @with_dhclient@
+with_dhcpcd = @with_dhcpcd@
+with_netconfig = @with_netconfig@
+with_resolvconf = @with_resolvconf@
+with_valgrind = @with_valgrind@
+AM_CPPFLAGS = \
+	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
+	-DG_LOG_DOMAIN=\""nmtui"\" \
+	$(GLIB_CFLAGS) \
+	$(NEWT_CFLAGS) \
+	$(NULL)
+
+noinst_LIBRARIES = libnmt-newt.a
+libnmt_newt_a_SOURCES = \
+	nmt-newt.h \
+	nmt-newt-types.h \
+	nmt-newt-button.c \
+	nmt-newt-button.h \
+	nmt-newt-button-box.c \
+	nmt-newt-button-box.h \
+	nmt-newt-checkbox.c \
+	nmt-newt-checkbox.h \
+	nmt-newt-component.c \
+	nmt-newt-component.h \
+	nmt-newt-container.c \
+	nmt-newt-container.h \
+	nmt-newt-entry.c \
+	nmt-newt-entry.h \
+	nmt-newt-entry-numeric.c \
+	nmt-newt-entry-numeric.h \
+	nmt-newt-form.c \
+	nmt-newt-form.h \
+	nmt-newt-grid.c \
+	nmt-newt-grid.h \
+	nmt-newt-hacks.c \
+	nmt-newt-hacks.h \
+	nmt-newt-label.c \
+	nmt-newt-label.h \
+	nmt-newt-listbox.c \
+	nmt-newt-listbox.h \
+	nmt-newt-popup.c \
+	nmt-newt-popup.h \
+	nmt-newt-section.c \
+	nmt-newt-section.h \
+	nmt-newt-separator.c \
+	nmt-newt-separator.h \
+	nmt-newt-stack.c \
+	nmt-newt-stack.h \
+	nmt-newt-textbox.c \
+	nmt-newt-textbox.h \
+	nmt-newt-toggle-button.c \
+	nmt-newt-toggle-button.h \
+	nmt-newt-utils.c \
+	nmt-newt-utils.h \
+	nmt-newt-widget.c \
+	nmt-newt-widget.h \
+	$(NULL)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tui/newt/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu tui/newt/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLIBRARIES:
+	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+libnmt-newt.a: $(libnmt_newt_a_OBJECTS) $(libnmt_newt_a_DEPENDENCIES) $(EXTRA_libnmt_newt_a_DEPENDENCIES) 
+	$(AM_V_at)-rm -f libnmt-newt.a
+	$(AM_V_AR)$(libnmt_newt_a_AR) libnmt-newt.a $(libnmt_newt_a_OBJECTS) $(libnmt_newt_a_LIBADD)
+	$(AM_V_at)$(RANLIB) libnmt-newt.a
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-button-box.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-button.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-checkbox.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-component.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-container.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-entry-numeric.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-entry.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-form.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-grid.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-hacks.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-label.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-listbox.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-popup.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-section.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-separator.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-stack.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-textbox.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-toggle-button.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-utils.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-widget.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstLIBRARIES cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tui/newt/nmt-newt-button-box.c b/tui/newt/nmt-newt-button-box.c
new file mode 100644
index 00000000..0199ebe9
--- /dev/null
+++ b/tui/newt/nmt-newt-button-box.c
@@ -0,0 +1,385 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-button-box
+ * @short_description: A container for #NmtNewtButtons
+ *
+ * #NmtNewtButtonBox is a container for creating and holding
+ * #NmtNewtButtons.
+ *
+ * A button box can be either horizontally or vertically laid out, and
+ * has two sections within it: the "start" (left or top) and "end"
+ * (right or bottom). Buttons are added from left to right or top to bottom
+ * within each of the two sections.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "nmt-newt-button-box.h"
+#include "nmt-newt-button.h"
+
+G_DEFINE_TYPE (NmtNewtButtonBox, nmt_newt_button_box, NMT_TYPE_NEWT_CONTAINER)
+
+#define NMT_NEWT_BUTTON_BOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_BUTTON_BOX, NmtNewtButtonBoxPrivate))
+
+typedef struct {
+	NmtNewtButtonBoxOrientation orientation;
+	GPtrArray *start_buttons, *end_buttons;
+} NmtNewtButtonBoxPrivate;
+
+enum {
+	PROP_0,
+
+	PROP_ORIENTATION,
+
+	LAST_PROP
+};
+
+/**
+ * NmtNewtButtonBoxOrientation:
+ * @NMT_NEWT_BUTTON_BOX_HORIZONTAL: horizontal
+ * @NMT_NEWT_BUTTON_BOX_VERTICAL: vertical
+ *
+ * The orientation of an #NmtNewtButtonBox
+ */
+
+/**
+ * nmt_newt_button_box_new:
+ * @orientation: the orientation
+ *
+ * Creates a new #NmtNewtButtonBox
+ *
+ * Returns: a new #NmtNewtButtonBox
+ */
+NmtNewtWidget *
+nmt_newt_button_box_new (NmtNewtButtonBoxOrientation orientation)
+{
+	return g_object_new (NMT_TYPE_NEWT_BUTTON_BOX,
+	                     "orientation", orientation,
+	                     NULL);
+}
+
+static void
+nmt_newt_button_box_init (NmtNewtButtonBox *bbox)
+{
+	NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (bbox);
+
+	priv->start_buttons = g_ptr_array_new ();
+	priv->end_buttons = g_ptr_array_new ();
+}
+
+/**
+ * nmt_newt_button_box_add_start:
+ * @bbox: an #NmtNewtButtonBox
+ * @label: the label for the newt button
+ *
+ * Creates a new #NmtNewtButton with the given @label, adds it
+ * to the "start" section of @bbox, and returns the newly-created
+ * button.
+ *
+ * Returns: the newly-created button, already added to @bbox
+ */
+NmtNewtWidget *
+nmt_newt_button_box_add_start (NmtNewtButtonBox *bbox,
+                               const char       *label)
+{
+	NmtNewtWidget *button;
+
+	button = nmt_newt_button_new (label);
+	nmt_newt_button_box_add_widget_start (bbox, button);
+	return button;
+}
+
+/**
+ * nmt_newt_button_box_add_widget_start:
+ * @bbox: an #NmtNewtButtonBox
+ * @widget: the #NmtNewtWidget to add
+ *
+ * Adds the given widget to the "start" section of @bbox.
+ */
+void
+nmt_newt_button_box_add_widget_start (NmtNewtButtonBox *bbox,
+                                      NmtNewtWidget    *widget)
+{
+	NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (bbox);
+
+	NMT_NEWT_CONTAINER_CLASS (nmt_newt_button_box_parent_class)->
+		add (NMT_NEWT_CONTAINER (bbox), widget);
+	g_ptr_array_add (priv->start_buttons, widget);
+}
+
+/**
+ * nmt_newt_button_box_add_end:
+ * @bbox: an #NmtNewtButtonBox
+ * @label: the label for the newt button
+ *
+ * Creates a new #NmtNewtButton with the given @label, adds it
+ * to the "end" section of @bbox, and returns the newly-created
+ * button.
+ *
+ * Returns: the newly-created button, already added to @bbox
+ */
+NmtNewtWidget *
+nmt_newt_button_box_add_end (NmtNewtButtonBox *bbox,
+                             const char       *label)
+{
+	NmtNewtWidget *button;
+
+	button = nmt_newt_button_new (label);
+	nmt_newt_button_box_add_widget_end (bbox, button);
+	return button;
+}
+
+/**
+ * nmt_newt_button_box_add_widget_end:
+ * @bbox: an #NmtNewtButtonBox
+ * @widget: the #NmtNewtWidget to add
+ *
+ * Adds the given widget to the "end" section of @bbox.
+ */
+void
+nmt_newt_button_box_add_widget_end (NmtNewtButtonBox *bbox,
+                                    NmtNewtWidget    *widget)
+{
+	NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (bbox);
+
+	NMT_NEWT_CONTAINER_CLASS (nmt_newt_button_box_parent_class)->
+		add (NMT_NEWT_CONTAINER (bbox), widget);
+	g_ptr_array_add (priv->end_buttons, widget);
+}
+
+static void
+nmt_newt_button_box_remove (NmtNewtContainer *container,
+                            NmtNewtWidget    *child)
+{
+	NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (container);
+	int i;
+
+	NMT_NEWT_CONTAINER_CLASS (nmt_newt_button_box_parent_class)->
+		remove (container, child);
+
+	for (i = 0; i < priv->start_buttons->len; i++) {
+		if (priv->start_buttons->pdata[i] == (gpointer) child) {
+			g_ptr_array_remove_index (priv->start_buttons, i);
+			return;
+		}
+	}
+	for (i = 0; i < priv->end_buttons->len; i++) {
+		if (priv->end_buttons->pdata[i] == (gpointer) child) {
+			g_ptr_array_remove_index (priv->end_buttons, i);
+			return;
+		}
+	}
+}
+
+static void
+add_buttons (GPtrArray *buttons, GPtrArray *cos)
+{
+	NmtNewtWidget *child;
+	newtComponent *child_cos;
+	int i, c;
+
+	for (i = 0; i < buttons->len; i++) {
+		child = buttons->pdata[i];
+
+		if (!nmt_newt_widget_get_visible (child))
+			continue;
+
+		child_cos = nmt_newt_widget_get_components (child);
+		for (c = 0; child_cos[c]; c++)
+			g_ptr_array_add (cos, child_cos[c]);
+		g_free (child_cos);
+	}
+}
+
+static newtComponent *
+nmt_newt_button_box_get_components (NmtNewtWidget *widget)
+{
+	NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (widget);
+	GPtrArray *cos;
+
+	cos = g_ptr_array_new ();
+	add_buttons (priv->start_buttons, cos);
+	add_buttons (priv->end_buttons, cos);
+	g_ptr_array_add (cos, NULL);
+
+	return (newtComponent *) g_ptr_array_free (cos, FALSE);
+}
+
+static void
+size_request_buttons (NmtNewtButtonBox *bbox,
+                      GPtrArray        *buttons,
+                      int              *width,
+                      int              *height)
+{
+	NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (bbox);
+	int child_width, child_height;
+	int i;
+
+	for (i = 0; i < buttons->len; i++) {
+		NmtNewtWidget *child = buttons->pdata[i];
+
+		nmt_newt_widget_size_request (child, &child_width, &child_height);
+		if (priv->orientation == NMT_NEWT_BUTTON_BOX_HORIZONTAL) {
+			*width += child_width;
+			if (i > 0)
+				*width += 1;
+			*height = MAX (*height, child_height);
+		} else {
+			*height += child_height;
+			if (i > 0)
+				*height += 1;
+			*width = MAX (*width, child_width);
+		}
+	}
+}
+
+static void
+nmt_newt_button_box_size_request (NmtNewtWidget *widget,
+                                  int           *width,
+                                  int           *height)
+{
+	NmtNewtButtonBox *bbox = NMT_NEWT_BUTTON_BOX (widget);
+	NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (widget);
+
+	*width = *height = 0;
+	size_request_buttons (bbox, priv->start_buttons, width, height);
+	size_request_buttons (bbox, priv->end_buttons, width, height);
+
+	if (priv->start_buttons && priv->end_buttons) {
+		if (priv->orientation == NMT_NEWT_BUTTON_BOX_HORIZONTAL)
+			*width += 1;
+		else
+			*height += 1;
+	}
+}
+
+static void
+nmt_newt_button_box_size_allocate (NmtNewtWidget *widget,
+                                   int            x,
+                                   int            y,
+                                   int            width,
+                                   int            height)
+{
+	NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (widget);
+	NmtNewtWidget *child;
+	int child_x, child_y, child_width, child_height;
+	int i;
+
+	child_x = x;
+	child_y = y;
+	for (i = 0; i < priv->start_buttons->len; i++) {
+		child = priv->start_buttons->pdata[i];
+		nmt_newt_widget_size_request (child, &child_width, &child_height);
+
+		if (priv->orientation == NMT_NEWT_BUTTON_BOX_HORIZONTAL) {
+			nmt_newt_widget_size_allocate (child, child_x, child_y, child_width, child_height);
+			child_x += child_width + 1;
+		} else {
+			nmt_newt_widget_size_allocate (child, child_x, child_y, child_width, child_height);
+			child_y += child_height + 1;
+		}
+	}
+
+	if (priv->orientation == NMT_NEWT_BUTTON_BOX_HORIZONTAL)
+		child_x = x + width;
+	else
+		child_y = y + height;
+
+	for (i = priv->end_buttons->len - 1; i >= 0; i--) {
+		child = priv->end_buttons->pdata[i];
+		nmt_newt_widget_size_request (child, &child_width, &child_height);
+
+		if (priv->orientation == NMT_NEWT_BUTTON_BOX_HORIZONTAL) {
+			nmt_newt_widget_size_allocate (child,
+			                               child_x - child_width, child_y,
+			                               child_width, child_height);
+			child_x -= child_width + 1;
+		} else {
+			nmt_newt_widget_size_allocate (child,
+			                               child_x, child_y - child_height,
+			                               child_width, child_height);
+			child_y -= child_height + 1;
+		}
+	}
+}
+
+static void
+nmt_newt_button_box_set_property (GObject      *object,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+{
+	NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_ORIENTATION:
+		priv->orientation = g_value_get_int (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_button_box_get_property (GObject    *object,
+                                  guint       prop_id,
+                                  GValue     *value,
+                                  GParamSpec *pspec)
+{
+	NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_ORIENTATION:
+		g_value_set_int (value, priv->orientation);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_button_box_class_init (NmtNewtButtonBoxClass *bbox_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (bbox_class);
+	NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (bbox_class);
+	NmtNewtContainerClass *container_class = NMT_NEWT_CONTAINER_CLASS (bbox_class);
+
+	g_type_class_add_private (bbox_class, sizeof (NmtNewtButtonBoxPrivate));
+
+	object_class->get_property = nmt_newt_button_box_get_property;
+	object_class->set_property = nmt_newt_button_box_set_property;
+
+	widget_class->get_components = nmt_newt_button_box_get_components;
+	widget_class->size_request   = nmt_newt_button_box_size_request;
+	widget_class->size_allocate  = nmt_newt_button_box_size_allocate;
+
+	container_class->remove = nmt_newt_button_box_remove;
+
+	g_object_class_install_property (object_class, PROP_ORIENTATION,
+	                                 g_param_spec_int ("orientation", "", "",
+	                                                   0, G_MAXINT, 0,
+	                                                   G_PARAM_READWRITE |
+	                                                   G_PARAM_CONSTRUCT_ONLY |
+	                                                   G_PARAM_STATIC_STRINGS));
+}
diff --git a/tui/newt/nmt-newt-button-box.h b/tui/newt/nmt-newt-button-box.h
new file mode 100644
index 00000000..970588a4
--- /dev/null
+++ b/tui/newt/nmt-newt-button-box.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_BUTTON_BOX_H
+#define NMT_NEWT_BUTTON_BOX_H
+
+#include "nmt-newt-grid.h"
+
+G_BEGIN_DECLS
+
+#define NMT_TYPE_NEWT_BUTTON_BOX            (nmt_newt_button_box_get_type ())
+#define NMT_NEWT_BUTTON_BOX(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_BUTTON_BOX, NmtNewtButtonBox))
+#define NMT_NEWT_BUTTON_BOX_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_BUTTON_BOX, NmtNewtButtonBoxClass))
+#define NMT_IS_NEWT_BUTTON_BOX(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_BUTTON_BOX))
+#define NMT_IS_NEWT_BUTTON_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_BUTTON_BOX))
+#define NMT_NEWT_BUTTON_BOX_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_BUTTON_BOX, NmtNewtButtonBoxClass))
+
+struct _NmtNewtButtonBox {
+	NmtNewtContainer parent;
+
+};
+
+typedef struct {
+	NmtNewtContainerClass parent;
+
+} NmtNewtButtonBoxClass;
+
+GType nmt_newt_button_box_get_type (void);
+
+typedef enum {
+	NMT_NEWT_BUTTON_BOX_HORIZONTAL,
+	NMT_NEWT_BUTTON_BOX_VERTICAL
+} NmtNewtButtonBoxOrientation;
+
+NmtNewtWidget *nmt_newt_button_box_new       (NmtNewtButtonBoxOrientation orientation);
+
+NmtNewtWidget *nmt_newt_button_box_add_start (NmtNewtButtonBox *bbox,
+                                              const char       *label);
+NmtNewtWidget *nmt_newt_button_box_add_end   (NmtNewtButtonBox *bbox,
+                                              const char       *label);
+
+void           nmt_newt_button_box_add_widget_start (NmtNewtButtonBox *bbox,
+                                                     NmtNewtWidget    *widget);
+void           nmt_newt_button_box_add_widget_end   (NmtNewtButtonBox *bbox,
+                                                     NmtNewtWidget    *widget);
+
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_BUTTON_BOX_H */
diff --git a/tui/newt/nmt-newt-button.c b/tui/newt/nmt-newt-button.c
new file mode 100644
index 00000000..97ad50ca
--- /dev/null
+++ b/tui/newt/nmt-newt-button.c
@@ -0,0 +1,260 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-button
+ * @short_description: Push buttons
+ *
+ * #NmtNewtButton implements a button widget.
+ */
+
+#include "config.h"
+
+#include "nmt-newt-button.h"
+#include "nmt-newt-utils.h"
+
+G_DEFINE_TYPE (NmtNewtButton, nmt_newt_button, NMT_TYPE_NEWT_COMPONENT)
+
+#define NMT_NEWT_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_BUTTON, NmtNewtButtonPrivate))
+
+typedef struct {
+	char *label;
+} NmtNewtButtonPrivate;
+
+enum {
+	PROP_0,
+	PROP_LABEL,
+
+	LAST_PROP
+};
+
+enum {
+	CLICKED,
+
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/**
+ * nmt_newt_button_new:
+ * @label: the (initial) button label
+ *
+ * Creates a new button.
+ *
+ * Returns: a new #NmtNewtButton
+ */
+NmtNewtWidget *
+nmt_newt_button_new (const char *label)
+{
+	return g_object_new (NMT_TYPE_NEWT_BUTTON,
+	                     "label", label,
+	                     NULL);
+}
+
+/**
+ * nmt_newt_button_set_label:
+ * @button: an #NmtNewtButton
+ * @label: the new label
+ *
+ * Updates @button's label.
+ */
+void
+nmt_newt_button_set_label (NmtNewtButton *button,
+                           const char    *label)
+{
+	NmtNewtButtonPrivate *priv = NMT_NEWT_BUTTON_GET_PRIVATE (button);
+
+	if (!g_strcmp0 (priv->label, label))
+		return;
+
+	g_free (priv->label);
+	priv->label = g_strdup (label);
+	nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (button));
+}
+
+/**
+ * nmt_newt_button_get_label:
+ * @button: an #NmtNewtButton
+ *
+ * Gets @button's label.
+ *
+ * Returns: @button's label.
+ */
+const char *
+nmt_newt_button_get_label (NmtNewtButton *button)
+{
+	NmtNewtButtonPrivate *priv = NMT_NEWT_BUTTON_GET_PRIVATE (button);
+
+	return priv->label;
+}
+
+static void
+nmt_newt_button_init (NmtNewtButton *button)
+{
+}
+
+static void
+nmt_newt_button_finalize (GObject *object)
+{
+	NmtNewtButtonPrivate *priv = NMT_NEWT_BUTTON_GET_PRIVATE (object);
+
+	g_free (priv->label);
+
+	G_OBJECT_CLASS (nmt_newt_button_parent_class)->finalize (object);
+}
+
+static newtComponent
+nmt_newt_button_build_component (NmtNewtComponent *component,
+                                 gboolean          sensitive)
+{
+	NmtNewtButtonPrivate *priv = NMT_NEWT_BUTTON_GET_PRIVATE (component);
+	newtComponent co;
+	char *label = NULL, *label_lc;
+
+	if (sensitive) {
+		label_lc = nmt_newt_locale_from_utf8 (priv->label);
+		co = newtCompactButton (-1, -1, label_lc);
+		g_free (label_lc);
+	} else {
+		label = g_strdup_printf (" <%s>", priv->label);
+		label_lc = nmt_newt_locale_from_utf8 (label);
+		co = newtLabel (-1, -1, label_lc);
+		g_free (label_lc);
+		newtLabelSetColors (co, NMT_NEWT_COLORSET_DISABLED_BUTTON);
+	}
+
+	return co;
+}
+
+static void
+nmt_newt_button_size_request (NmtNewtWidget *widget,
+                              int           *width,
+                              int           *height)
+{
+	NMT_NEWT_WIDGET_CLASS (nmt_newt_button_parent_class)->size_request (widget, width, height);
+
+	/* remove the automatically-added left padding */
+	(*width)--;
+}
+
+static void
+nmt_newt_button_size_allocate (NmtNewtWidget *widget,
+                               int            x,
+                               int            y,
+                               int            width,
+                               int            height)
+{
+	/* account for the automatically-added left padding */
+	x--;
+	width++;
+
+	NMT_NEWT_WIDGET_CLASS (nmt_newt_button_parent_class)->size_allocate (widget, x, y, width, height);
+}
+
+static void
+nmt_newt_button_activated (NmtNewtWidget *widget)
+{
+	g_signal_emit (widget, signals[CLICKED], 0);
+
+	NMT_NEWT_WIDGET_CLASS (nmt_newt_button_parent_class)->activated (widget);
+}
+
+static void
+nmt_newt_button_set_property (GObject      *object,
+                              guint         prop_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+	switch (prop_id) {
+	case PROP_LABEL:
+		nmt_newt_button_set_label (NMT_NEWT_BUTTON (object),
+		                           g_value_get_string (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_button_get_property (GObject    *object,
+                             guint       prop_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+	NmtNewtButtonPrivate *priv = NMT_NEWT_BUTTON_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_LABEL:
+		g_value_set_string (value, priv->label);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_button_class_init (NmtNewtButtonClass *button_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (button_class);
+	NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (button_class);
+	NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (button_class);
+
+	g_type_class_add_private (button_class, sizeof (NmtNewtButtonPrivate));
+
+	/* virtual methods */
+	object_class->set_property = nmt_newt_button_set_property;
+	object_class->get_property = nmt_newt_button_get_property;
+	object_class->finalize     = nmt_newt_button_finalize;
+
+	widget_class->size_request  = nmt_newt_button_size_request;
+	widget_class->size_allocate = nmt_newt_button_size_allocate;
+	widget_class->activated     = nmt_newt_button_activated;
+
+	component_class->build_component = nmt_newt_button_build_component;
+
+	/* signals */
+
+	/**
+	 * NmtNewtButton::clicked:
+	 * @button: the #NmtNewtButton
+	 *
+	 * Emitted when the button is clicked.
+	 */
+	signals[CLICKED] =
+		g_signal_new ("clicked",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              0, NULL, NULL, NULL,
+		              G_TYPE_NONE, 0);
+
+	/* properties */
+
+	/**
+	 * NmtNewtButton:label:
+	 *
+	 * The button's label
+	 */
+	g_object_class_install_property (object_class, PROP_LABEL,
+	                                 g_param_spec_string ("label", "", "",
+	                                                      NULL,
+	                                                      G_PARAM_READWRITE |
+	                                                      G_PARAM_STATIC_STRINGS));
+}
diff --git a/tui/newt/nmt-newt-button.h b/tui/newt/nmt-newt-button.h
new file mode 100644
index 00000000..52e95c5d
--- /dev/null
+++ b/tui/newt/nmt-newt-button.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_BUTTON_H
+#define NMT_NEWT_BUTTON_H
+
+#include "nmt-newt-component.h"
+
+G_BEGIN_DECLS
+
+#define NMT_TYPE_NEWT_BUTTON            (nmt_newt_button_get_type ())
+#define NMT_NEWT_BUTTON(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_BUTTON, NmtNewtButton))
+#define NMT_NEWT_BUTTON_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_BUTTON, NmtNewtButtonClass))
+#define NMT_IS_NEWT_BUTTON(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_BUTTON))
+#define NMT_IS_NEWT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_BUTTON))
+#define NMT_NEWT_BUTTON_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_BUTTON, NmtNewtButtonClass))
+
+struct _NmtNewtButton {
+	NmtNewtComponent parent;
+
+};
+
+typedef struct {
+	NmtNewtComponentClass parent;
+
+} NmtNewtButtonClass;
+
+GType nmt_newt_button_get_type (void);
+
+NmtNewtWidget *nmt_newt_button_new       (const char    *label);
+
+void           nmt_newt_button_set_label (NmtNewtButton *button,
+                                          const char    *label);
+const char    *nmt_newt_button_get_label (NmtNewtButton *button);
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_BUTTON_H */
diff --git a/tui/newt/nmt-newt-checkbox.c b/tui/newt/nmt-newt-checkbox.c
new file mode 100644
index 00000000..168fada2
--- /dev/null
+++ b/tui/newt/nmt-newt-checkbox.c
@@ -0,0 +1,235 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-checkbox
+ * @short_description: Checkboxes
+ *
+ * #NmtNewtCheckbox implements a checkbox widget.
+ */
+
+#include "config.h"
+
+#include "nmt-newt-checkbox.h"
+#include "nmt-newt-utils.h"
+
+G_DEFINE_TYPE (NmtNewtCheckbox, nmt_newt_checkbox, NMT_TYPE_NEWT_COMPONENT)
+
+#define NMT_NEWT_CHECKBOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_CHECKBOX, NmtNewtCheckboxPrivate))
+
+typedef struct {
+	char *label_lc;
+	gboolean active;
+} NmtNewtCheckboxPrivate;
+
+enum {
+	PROP_0,
+	PROP_LABEL,
+	PROP_ACTIVE,
+
+	LAST_PROP
+};
+
+#define CHECKBOX_INACTIVE ' '
+#define CHECKBOX_ACTIVE   'X'
+#define CHECKBOX_STATES   " X"
+
+/**
+ * nmt_newt_checkbox_new:
+ * @label: the (initial) checkbox label
+ *
+ * Creates a new checkbox.
+ *
+ * Returns: a new #NmtNewtCheckbox
+ */
+NmtNewtWidget *
+nmt_newt_checkbox_new (const char *label)
+{
+	return g_object_new (NMT_TYPE_NEWT_CHECKBOX,
+	                     "label", label,
+	                     NULL);
+}
+
+/**
+ * nmt_newt_checkbox_set_active:
+ * @checkbox: an #NmtNewtCheckbox
+ * @active: whether @checkbox should be checked
+ *
+ * Updates @checkbox's checked state
+ */
+void
+nmt_newt_checkbox_set_active (NmtNewtCheckbox *checkbox,
+                              gboolean         active)
+{
+	NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (checkbox);
+	newtComponent co;
+
+	active = !!active;
+	if (active == priv->active)
+		return;
+
+	priv->active = active;
+
+	co = nmt_newt_component_get_component (NMT_NEWT_COMPONENT (checkbox));
+	if (co)
+		newtCheckboxSetValue (co, priv->active ? CHECKBOX_ACTIVE : CHECKBOX_INACTIVE);
+
+	g_object_notify (G_OBJECT (checkbox), "active");
+}
+
+/**
+ * nmt_newt_checkbox_get_active:
+ * @checkbox: an #NmtNewtCheckbox
+ *
+ * Gets @checkbox's checked state
+ *
+ * Returns: @checkbox's checked state
+ */
+gboolean
+nmt_newt_checkbox_get_active (NmtNewtCheckbox *checkbox)
+{
+	NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (checkbox);
+
+	return priv->active;
+}
+
+static void
+nmt_newt_checkbox_init (NmtNewtCheckbox *checkbox)
+{
+}
+
+static void
+nmt_newt_checkbox_finalize (GObject *object)
+{
+	NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (object);
+
+	g_free (priv->label_lc);
+
+	G_OBJECT_CLASS (nmt_newt_checkbox_parent_class)->finalize (object);
+}
+
+static void
+checkbox_toggled_callback (newtComponent  co,
+                           void          *checkbox)
+{
+	NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (checkbox);
+	gboolean active;
+
+	active = (newtCheckboxGetValue (co) == CHECKBOX_ACTIVE);
+	if (active != priv->active) {
+		priv->active = active;
+		g_object_notify (checkbox, "active");
+	}
+}
+
+static newtComponent
+nmt_newt_checkbox_build_component (NmtNewtComponent *component,
+                                   gboolean          sensitive)
+{
+	NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (component);
+	newtComponent co;
+
+	co = newtCheckbox (-1, -1, priv->label_lc,
+	                   priv->active ? CHECKBOX_ACTIVE : CHECKBOX_INACTIVE,
+	                   CHECKBOX_STATES, NULL);
+	if (!sensitive)
+		newtCheckboxSetFlags (co, NEWT_FLAG_DISABLED, NEWT_FLAGS_SET);
+	newtComponentAddCallback (co, checkbox_toggled_callback, component);
+	return co;
+}
+
+static void
+nmt_newt_checkbox_set_property (GObject      *object,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+	NmtNewtCheckbox *checkbox = NMT_NEWT_CHECKBOX (object);
+	NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_LABEL:
+		g_free (priv->label_lc);
+		priv->label_lc = nmt_newt_locale_from_utf8 (g_value_get_string (value));
+		break;
+	case PROP_ACTIVE:
+		nmt_newt_checkbox_set_active (checkbox, g_value_get_boolean (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_checkbox_get_property (GObject    *object,
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+	NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_LABEL:
+		g_value_take_string (value, nmt_newt_locale_to_utf8 (priv->label_lc));
+		break;
+	case PROP_ACTIVE:
+		g_value_set_boolean (value, priv->active);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_checkbox_class_init (NmtNewtCheckboxClass *checkbox_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (checkbox_class);
+	NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (checkbox_class);
+
+	g_type_class_add_private (checkbox_class, sizeof (NmtNewtCheckboxPrivate));
+
+	/* virtual methods */
+	object_class->set_property = nmt_newt_checkbox_set_property;
+	object_class->get_property = nmt_newt_checkbox_get_property;
+	object_class->finalize     = nmt_newt_checkbox_finalize;
+
+	component_class->build_component = nmt_newt_checkbox_build_component;
+
+	/**
+	 * NmtNewtCheckbox:label:
+	 *
+	 * The checkbox's label
+	 */
+	g_object_class_install_property (object_class, PROP_LABEL,
+	                                 g_param_spec_string ("label", "", "",
+	                                                      NULL,
+	                                                      G_PARAM_READWRITE |
+	                                                      G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtCheckbox:active:
+	 *
+	 * The checkbox's checked state
+	 */
+	g_object_class_install_property (object_class, PROP_ACTIVE,
+	                                 g_param_spec_boolean ("active", "", "",
+	                                                       FALSE,
+	                                                       G_PARAM_READWRITE |
+	                                                       G_PARAM_STATIC_STRINGS));
+}
diff --git a/tui/newt/nmt-newt-checkbox.h b/tui/newt/nmt-newt-checkbox.h
new file mode 100644
index 00000000..c277386b
--- /dev/null
+++ b/tui/newt/nmt-newt-checkbox.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_CHECKBOX_H
+#define NMT_NEWT_CHECKBOX_H
+
+#include "nmt-newt-component.h"
+
+G_BEGIN_DECLS
+
+#define NMT_TYPE_NEWT_CHECKBOX            (nmt_newt_checkbox_get_type ())
+#define NMT_NEWT_CHECKBOX(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_CHECKBOX, NmtNewtCheckbox))
+#define NMT_NEWT_CHECKBOX_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_CHECKBOX, NmtNewtCheckboxClass))
+#define NMT_IS_NEWT_CHECKBOX(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_CHECKBOX))
+#define NMT_IS_NEWT_CHECKBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_CHECKBOX))
+#define NMT_NEWT_CHECKBOX_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_CHECKBOX, NmtNewtCheckboxClass))
+
+struct _NmtNewtCheckbox {
+	NmtNewtComponent parent;
+
+};
+
+typedef struct {
+	NmtNewtComponentClass parent;
+
+} NmtNewtCheckboxClass;
+
+GType nmt_newt_checkbox_get_type (void);
+
+NmtNewtWidget *nmt_newt_checkbox_new (const char *label);
+
+void     nmt_newt_checkbox_set_active (NmtNewtCheckbox *checkbox,
+                                       gboolean         active);
+gboolean nmt_newt_checkbox_get_active (NmtNewtCheckbox *checkbox);
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_CHECKBOX_H */
diff --git a/tui/newt/nmt-newt-component.c b/tui/newt/nmt-newt-component.c
new file mode 100644
index 00000000..877b53db
--- /dev/null
+++ b/tui/newt/nmt-newt-component.c
@@ -0,0 +1,307 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-component
+ * @short_description: Base class for widgets that wrap #newtComponents
+ *
+ * #NmtNewtComponent is the abstract class for #NmtNewtWidgets that
+ * wrap a (single) #newtComponent.
+ */
+
+#include "config.h"
+
+#include "nmt-newt-component.h"
+#include "nmt-newt-form.h"
+#include "nmt-newt-hacks.h"
+
+G_DEFINE_ABSTRACT_TYPE (NmtNewtComponent, nmt_newt_component, NMT_TYPE_NEWT_WIDGET)
+
+#define NMT_NEWT_COMPONENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_COMPONENT, NmtNewtComponentPrivate))
+
+typedef struct {
+	newtComponent co;
+	gboolean own_component;
+	gboolean sensitive;
+} NmtNewtComponentPrivate;
+
+enum {
+	PROP_0,
+
+	PROP_COMPONENT,
+	PROP_SENSITIVE,
+
+	LAST_PROP
+};
+
+static void
+nmt_newt_component_init (NmtNewtComponent *component)
+{
+	NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (component);
+
+	priv->sensitive = TRUE;
+}
+
+static void
+nmt_newt_component_unrealize (NmtNewtWidget *widget)
+{
+	NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget);
+
+	if (!priv->co)
+		return;
+
+	newtComponentAddCallback (priv->co, NULL, NULL);
+	newtComponentAddDestroyCallback (priv->co, NULL, NULL);
+
+	if (priv->own_component)
+		newtComponentDestroy (priv->co);
+	priv->co = NULL;
+}
+
+static void
+component_destroy_callback (newtComponent  co,
+                            void          *component)
+{
+	NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (component);
+
+	priv->own_component = FALSE;
+	nmt_newt_widget_unrealize (component);
+	nmt_newt_widget_needs_rebuild (component);
+}
+
+static void
+nmt_newt_component_realize (NmtNewtWidget *widget)
+{
+	NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget);
+
+	nmt_newt_component_unrealize (widget);
+	priv->co = NMT_NEWT_COMPONENT_GET_CLASS (widget)->
+		build_component (NMT_NEWT_COMPONENT (widget), priv->sensitive);
+	priv->own_component = TRUE;
+	if (!priv->sensitive)
+		newtComponentTakesFocus (priv->co, FALSE);
+	newtComponentAddDestroyCallback (priv->co, component_destroy_callback, widget);
+}
+
+static newtComponent *
+nmt_newt_component_get_components (NmtNewtWidget *widget)
+{
+	NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget);
+	newtComponent *cos;
+
+	priv->own_component = FALSE;
+	cos = g_new0 (newtComponent, 2);
+	cos[0] = priv->co;
+	return cos;
+}
+
+static NmtNewtWidget *
+nmt_newt_component_find_component (NmtNewtWidget *widget,
+                                   newtComponent  co)
+{
+	NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget);
+
+	if (co == priv->co)
+		return widget;
+	else
+		return NULL;
+}
+
+static void
+nmt_newt_component_size_request (NmtNewtWidget *widget,
+                                 int           *width,
+                                 int           *height)
+{
+	NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget);
+
+	newtComponentGetSize (priv->co, width, height);
+}
+
+static void
+nmt_newt_component_size_allocate (NmtNewtWidget *widget,
+                                  int            x,
+                                  int            y,
+                                  int            width,
+                                  int            height)
+{
+	NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget);
+	newtGrid grid;
+
+	/* You can't directly place a newtComponent, so we create a newtGrid,
+	 * position the component within that, and then place the grid.
+	 */
+	grid = newtCreateGrid (1, 1);
+	newtGridSetField (grid, 0, 0,
+	                  NEWT_GRID_COMPONENT, priv->co,
+	                  x, y, 0, 0,
+	                  NEWT_ANCHOR_LEFT | NEWT_ANCHOR_TOP, 0);
+	newtGridPlace (grid, 0, 0);
+	newtGridFree (grid, FALSE);
+}
+
+static newtComponent
+nmt_newt_component_get_focus_component (NmtNewtWidget *widget)
+{
+	NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget);
+
+	return priv->co;
+}
+
+/**
+ * nmt_newt_component_get_component:
+ * @component: an #NmtNewtComponent
+ *
+ * A simpler version of nmt_newt_widget_get_components() for the
+ * single-component case. Also, unlike
+ * nmt_newt_widget_get_component(), this does not realize the widget
+ * if it isn't already realized. FIXME: why?
+ *
+ * Returns: @component's #newtComponent
+ */
+newtComponent
+nmt_newt_component_get_component (NmtNewtComponent *component)
+{
+	NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (component);
+
+	return priv->co;
+}
+
+/**
+ * nmt_newt_component_get_sensitive:
+ * @component: an #NmtNewtComponent
+ *
+ * Gets @component's #NmtNewtComponent:sensitive property, indicating
+ * whether the widget is available for manipulation. Insensitive
+ * components will be skipped over in the keyboard tab chain, and may
+ * be displayed differently.
+ *
+ * Returns: @component's #NmtNewtComponent:sensitive property
+ */
+gboolean
+nmt_newt_component_get_sensitive (NmtNewtComponent *component)
+{
+	NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (component);
+
+	return priv->sensitive;
+}
+
+/**
+ * nmt_newt_component_set_sensitive:
+ * @component: an #NmtNewtComponent
+ * @sensitive: whether @component should be sensitive
+ *
+ * Sets @component's #NmtNewtComponent:sensitive property.
+ */
+void
+nmt_newt_component_set_sensitive (NmtNewtComponent *component,
+                                  gboolean          sensitive)
+{
+	NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (component);
+
+	sensitive = !!sensitive;
+	if (priv->sensitive == sensitive)
+		return;
+
+	priv->sensitive = sensitive;
+	g_object_notify (G_OBJECT (component), "sensitive");
+	nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (component));
+}
+
+static void
+nmt_newt_component_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+	NmtNewtComponent *component = NMT_NEWT_COMPONENT (object);
+
+	switch (prop_id) {
+	case PROP_SENSITIVE:
+		nmt_newt_component_set_sensitive (component, g_value_get_boolean (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_component_get_property (GObject    *object,
+                                 guint       prop_id,
+                                 GValue     *value,
+                                 GParamSpec *pspec)
+{
+	NmtNewtComponent *component = NMT_NEWT_COMPONENT (object);
+
+	switch (prop_id) {
+	case PROP_COMPONENT:
+		g_value_set_pointer (value, nmt_newt_component_get_component (component));
+		break;
+	case PROP_SENSITIVE:
+		g_value_set_boolean (value, nmt_newt_component_get_sensitive (component));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_component_class_init (NmtNewtComponentClass *component_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (component_class);
+	NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (component_class);
+
+	g_type_class_add_private (component_class, sizeof (NmtNewtComponentPrivate));
+
+	/* virtual methods */
+	object_class->set_property = nmt_newt_component_set_property;
+	object_class->get_property = nmt_newt_component_get_property;
+
+	widget_class->realize             = nmt_newt_component_realize;
+	widget_class->unrealize           = nmt_newt_component_unrealize;
+	widget_class->get_components      = nmt_newt_component_get_components;
+	widget_class->find_component      = nmt_newt_component_find_component;
+	widget_class->size_request        = nmt_newt_component_size_request;
+	widget_class->size_allocate       = nmt_newt_component_size_allocate;
+	widget_class->get_focus_component = nmt_newt_component_get_focus_component;
+
+	/* properties */
+
+	/**
+	 * NmtNewtComponent:component:
+	 *
+	 * The component's #newtComponent
+	 */
+	g_object_class_install_property (object_class, PROP_COMPONENT,
+	                                 g_param_spec_pointer ("component", "", "",
+	                                                       G_PARAM_READABLE |
+	                                                       G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtComponent:sensitive:
+	 *
+	 * Whether the component is sensitive. Insensitive components will
+	 * be skipped over in the keyboard tab chain, and may be displayed
+	 * differently.
+	 */
+	g_object_class_install_property (object_class, PROP_SENSITIVE,
+	                                 g_param_spec_boolean ("sensitive", "", "",
+	                                                       TRUE,
+	                                                       G_PARAM_READWRITE |
+	                                                       G_PARAM_STATIC_STRINGS));
+}
diff --git a/tui/newt/nmt-newt-component.h b/tui/newt/nmt-newt-component.h
new file mode 100644
index 00000000..2ffa018e
--- /dev/null
+++ b/tui/newt/nmt-newt-component.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_COMPONENT_H
+#define NMT_NEWT_COMPONENT_H
+
+#include "nmt-newt-widget.h"
+
+G_BEGIN_DECLS
+
+#define NMT_TYPE_NEWT_COMPONENT            (nmt_newt_component_get_type ())
+#define NMT_NEWT_COMPONENT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_COMPONENT, NmtNewtComponent))
+#define NMT_NEWT_COMPONENT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_COMPONENT, NmtNewtComponentClass))
+#define NMT_IS_NEWT_COMPONENT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_COMPONENT))
+#define NMT_IS_NEWT_COMPONENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_COMPONENT))
+#define NMT_NEWT_COMPONENT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_COMPONENT, NmtNewtComponentClass))
+
+struct _NmtNewtComponent {
+	NmtNewtWidget parent;
+
+};
+
+typedef struct {
+	NmtNewtWidgetClass parent;
+
+	/* methods */
+	newtComponent (*build_component)    (NmtNewtComponent *component,
+	                                     gboolean          sensitive);
+
+} NmtNewtComponentClass;
+
+GType nmt_newt_component_get_type (void);
+
+newtComponent nmt_newt_component_get_component (NmtNewtComponent *component);
+
+gboolean      nmt_newt_component_get_sensitive (NmtNewtComponent *component);
+void          nmt_newt_component_set_sensitive (NmtNewtComponent *component,
+                                                gboolean          sensitive);
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_COMPONENT_H */
diff --git a/tui/newt/nmt-newt-container.c b/tui/newt/nmt-newt-container.c
new file mode 100644
index 00000000..03f677fb
--- /dev/null
+++ b/tui/newt/nmt-newt-container.c
@@ -0,0 +1,252 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-container
+ * @short_description: Base class for containers
+ *
+ * #NmtNewtContainer is the base class for #NmtNewtWidgets that
+ * contain other widgets.
+ *
+ * #NmtNewtGrid is the most generic container type.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "nmt-newt-container.h"
+#include "nmt-newt-component.h"
+
+G_DEFINE_ABSTRACT_TYPE (NmtNewtContainer, nmt_newt_container, NMT_TYPE_NEWT_WIDGET)
+
+#define NMT_NEWT_CONTAINER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_CONTAINER, NmtNewtContainerPrivate))
+
+typedef struct {
+	GPtrArray *children;
+
+} NmtNewtContainerPrivate;
+
+static void child_needs_rebuild (NmtNewtWidget *widget, gpointer user_data);
+
+static void
+nmt_newt_container_init (NmtNewtContainer *container)
+{
+	NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (container);
+
+	priv->children = g_ptr_array_new ();
+}
+
+static void
+nmt_newt_container_finalize (GObject *object)
+{
+	NmtNewtContainer *container = NMT_NEWT_CONTAINER (object);
+	NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (object);
+
+	while (priv->children->len)
+		nmt_newt_container_remove (container, priv->children->pdata[0]);
+
+	G_OBJECT_CLASS (nmt_newt_container_parent_class)->finalize (object);
+}
+
+static void
+nmt_newt_container_realize (NmtNewtWidget *widget)
+{
+	NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (widget);
+	int i;
+
+	for (i = 0; i < priv->children->len; i++)
+		nmt_newt_widget_realize (priv->children->pdata[i]);
+}
+
+static void
+nmt_newt_container_unrealize (NmtNewtWidget *widget)
+{
+	NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (widget);
+	int i;
+
+	for (i = 0; i < priv->children->len; i++)
+		nmt_newt_widget_unrealize (priv->children->pdata[i]);
+}
+
+static void
+child_needs_rebuild (NmtNewtWidget *widget,
+                     gpointer       user_data)
+{
+	NmtNewtWidget *container = user_data;
+
+	nmt_newt_widget_needs_rebuild (container);
+}
+
+static void
+nmt_newt_container_real_child_validity_changed (NmtNewtContainer *container,
+                                                NmtNewtWidget    *widget)
+{
+	NmtNewtContainerPrivate *priv;
+	int i;
+
+	if (widget) {
+		if (!nmt_newt_widget_get_visible (widget))
+			return;
+		if (!nmt_newt_widget_get_valid (widget)) {
+			nmt_newt_widget_set_valid (NMT_NEWT_WIDGET (container), FALSE);
+			return;
+		}
+	}
+
+	priv = NMT_NEWT_CONTAINER_GET_PRIVATE (container);
+	for (i = 0; i < priv->children->len; i++) {
+		widget = priv->children->pdata[i];
+		if (   nmt_newt_widget_get_visible (widget)
+		       && !nmt_newt_widget_get_valid (widget)) {
+			nmt_newt_widget_set_valid (NMT_NEWT_WIDGET (container), FALSE);
+			return;
+		}
+	}
+
+	nmt_newt_widget_set_valid (NMT_NEWT_WIDGET (container), TRUE);
+}
+
+static void
+nmt_newt_container_child_validity_changed (NmtNewtContainer *container,
+                                           NmtNewtWidget    *widget)
+{
+	NMT_NEWT_CONTAINER_GET_CLASS (container)->child_validity_changed (container, widget);
+}
+
+static void
+child_validity_notify (GObject    *object,
+                       GParamSpec *pspec,
+                       gpointer    container)
+{
+	nmt_newt_container_child_validity_changed (container, NMT_NEWT_WIDGET (object));
+}
+
+static void
+nmt_newt_container_real_add (NmtNewtContainer *container,
+                             NmtNewtWidget    *widget)
+{
+	NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (container);
+
+	g_signal_connect (widget, "needs-rebuild", G_CALLBACK (child_needs_rebuild), container);
+	g_signal_connect (widget, "notify::valid", G_CALLBACK (child_validity_notify), container);
+	g_ptr_array_add (priv->children, g_object_ref_sink (widget));
+	nmt_newt_widget_set_parent (widget, NMT_NEWT_WIDGET (container));
+
+	nmt_newt_container_child_validity_changed (container, widget);
+	nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (container));
+}
+
+static void
+nmt_newt_container_real_remove (NmtNewtContainer *container,
+                                NmtNewtWidget    *widget)
+{
+	NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (container);
+	int i;
+
+	for (i = 0; i < priv->children->len; i++) {
+		if (widget == priv->children->pdata[i]) {
+			g_ptr_array_remove_index (priv->children, i);
+			g_signal_handlers_disconnect_by_func (widget, G_CALLBACK (child_needs_rebuild), container);
+			g_signal_handlers_disconnect_by_func (widget, G_CALLBACK (child_validity_notify), container);
+			nmt_newt_widget_set_parent (widget, NULL);
+			g_object_unref (widget);
+
+			nmt_newt_container_child_validity_changed (container, NULL);
+			nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (container));
+			return;
+		}
+	}
+}
+
+/**
+ * nmt_newt_container_remove:
+ * @container: the #NmtNewtContainer
+ * @widget: the child to remove
+ *
+ * Removes @widget from @container.
+ *
+ * Note that there is not a corresponding
+ * <literal>nmt_newt_container_add ()</literal>; you must use
+ * container-type-specific methods to add widgets to containers.
+ */
+void
+nmt_newt_container_remove (NmtNewtContainer *container,
+                           NmtNewtWidget    *widget)
+{
+	NMT_NEWT_CONTAINER_GET_CLASS (container)->remove (container, widget);
+}
+
+static NmtNewtWidget *
+nmt_newt_container_find_component (NmtNewtWidget *widget,
+                                   newtComponent  co)
+{
+	NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (widget);
+	NmtNewtWidget *found, *child;
+	int i;
+
+	for (i = 0; i < priv->children->len; i++) {
+		child = priv->children->pdata[i];
+
+		found = nmt_newt_widget_find_component (child, co);
+		if (found)
+			return found;
+	}
+
+	return NULL;
+}
+
+/**
+ * nmt_newt_container_get_children:
+ * @container: an #NmtNewtContainer
+ *
+ * Gets a list of @container's children.
+ *
+ * Returns: (transfer full): a list of @container's children.
+ */
+GSList *
+nmt_newt_container_get_children (NmtNewtContainer *container)
+{
+	NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (container);
+	GSList *ret;
+	int i;
+
+	for (i = 0, ret = NULL; i < priv->children->len; i++)
+		ret = g_slist_prepend (ret, g_object_ref (priv->children->pdata[i]));
+	return g_slist_reverse (ret);
+}
+
+static void
+nmt_newt_container_class_init (NmtNewtContainerClass *container_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (container_class);
+	NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (container_class);
+
+	g_type_class_add_private (container_class, sizeof (NmtNewtContainerPrivate));
+
+	/* virtual methods */
+	object_class->finalize = nmt_newt_container_finalize;
+
+	widget_class->realize        = nmt_newt_container_realize;
+	widget_class->unrealize      = nmt_newt_container_unrealize;
+	widget_class->find_component = nmt_newt_container_find_component;
+
+	container_class->add    = nmt_newt_container_real_add;
+	container_class->remove = nmt_newt_container_real_remove;
+	container_class->child_validity_changed = nmt_newt_container_real_child_validity_changed;
+}
diff --git a/tui/newt/nmt-newt-container.h b/tui/newt/nmt-newt-container.h
new file mode 100644
index 00000000..6f182925
--- /dev/null
+++ b/tui/newt/nmt-newt-container.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_CONTAINER_H
+#define NMT_NEWT_CONTAINER_H
+
+#include "nmt-newt-widget.h"
+
+G_BEGIN_DECLS
+
+#define NMT_TYPE_NEWT_CONTAINER            (nmt_newt_container_get_type ())
+#define NMT_NEWT_CONTAINER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_CONTAINER, NmtNewtContainer))
+#define NMT_NEWT_CONTAINER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_CONTAINER, NmtNewtContainerClass))
+#define NMT_IS_NEWT_CONTAINER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_CONTAINER))
+#define NMT_IS_NEWT_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_CONTAINER))
+#define NMT_NEWT_CONTAINER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_CONTAINER, NmtNewtContainerClass))
+
+struct _NmtNewtContainer {
+	NmtNewtWidget parent;
+
+};
+
+typedef struct {
+	NmtNewtWidgetClass parent;
+
+	/* methods */
+	void (*add)                    (NmtNewtContainer *container,
+	                                NmtNewtWidget    *child);
+	void (*remove)                 (NmtNewtContainer *container,
+	                                NmtNewtWidget    *child);
+
+	void (*child_validity_changed) (NmtNewtContainer *container,
+	                                NmtNewtWidget    *child);
+
+} NmtNewtContainerClass;
+
+GType nmt_newt_container_get_type (void);
+
+void           nmt_newt_container_remove       (NmtNewtContainer *container,
+                                                NmtNewtWidget    *widget);
+
+GSList        *nmt_newt_container_get_children (NmtNewtContainer *container);
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_CONTAINER_H */
diff --git a/tui/newt/nmt-newt-entry-numeric.c b/tui/newt/nmt-newt-entry-numeric.c
new file mode 100644
index 00000000..753c209a
--- /dev/null
+++ b/tui/newt/nmt-newt-entry-numeric.c
@@ -0,0 +1,213 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-entry-numeric
+ * @short_description: Numeric text entry
+ *
+ * #NmtNewtEntryNumeric implements a numeric-only #NmtNewtEntry.
+ *
+ * #NmtNewtEntryNumeric provides its own #NmtNewtEntryFilter and
+ * #NmtNewtEntryValidator functions, so you should not set your own.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include "nmt-newt-entry-numeric.h"
+
+G_DEFINE_TYPE (NmtNewtEntryNumeric, nmt_newt_entry_numeric, NMT_TYPE_NEWT_ENTRY)
+
+#define NMT_NEWT_ENTRY_NUMERIC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_ENTRY_NUMERIC, NmtNewtEntryNumericPrivate))
+
+typedef struct {
+	int min, max;
+} NmtNewtEntryNumericPrivate;
+
+enum {
+	PROP_0,
+	PROP_MINIMUM,
+	PROP_MAXIMUM,
+
+	LAST_PROP
+};
+
+/**
+ * nmt_newt_entry_numeric_new:
+ * @width: the entry's width in characters
+ * @min: the minimum valid value
+ * @max: the maximum valid value
+ *
+ * Creates a new #NmtNewtEntryNumeric, accepting values in the
+ * indicated range.
+ *
+ * Returns: a new #NmtNewtEntryNumeric
+ */
+NmtNewtWidget *
+nmt_newt_entry_numeric_new (int width,
+                            int min,
+                            int max)
+{
+	return g_object_new (NMT_TYPE_NEWT_ENTRY_NUMERIC,
+	                     "width", width,
+	                     "minimum", min,
+	                     "maximum", max,
+	                     NULL);
+}
+
+static gboolean
+newt_entry_numeric_filter (NmtNewtEntry *entry,
+                           const char   *text,
+                           int           ch,
+                           int           position,
+                           gpointer      user_data)
+{
+	NmtNewtEntryNumericPrivate *priv = NMT_NEWT_ENTRY_NUMERIC_GET_PRIVATE (entry);
+
+	if (g_ascii_isdigit (ch))
+		return TRUE;
+
+	if (ch == '-' && position == 0 && priv->min < 0)
+		return TRUE;
+
+	return FALSE;
+}
+
+static gboolean
+newt_entry_numeric_validate (NmtNewtEntry *entry,
+                             const char   *text,
+                             gpointer      user_data)
+{
+	NmtNewtEntryNumericPrivate *priv = NMT_NEWT_ENTRY_NUMERIC_GET_PRIVATE (entry);
+	int val;
+	char *end;
+
+	if (!*text)
+		return FALSE;
+
+	val = strtoul (text, &end, 10);
+	if (*end)
+		return FALSE;
+	if (val < priv->min || val > priv->max)
+		return FALSE;
+
+	return TRUE;
+}
+
+static void
+nmt_newt_entry_numeric_init (NmtNewtEntryNumeric *entry)
+{
+	nmt_newt_entry_set_filter (NMT_NEWT_ENTRY (entry), newt_entry_numeric_filter, NULL);
+	nmt_newt_entry_set_validator (NMT_NEWT_ENTRY (entry), newt_entry_numeric_validate, NULL);
+}
+
+static void
+nmt_newt_entry_numeric_constructed (GObject *object)
+{
+	NmtNewtEntryNumericPrivate *priv = NMT_NEWT_ENTRY_NUMERIC_GET_PRIVATE (object);
+
+	if (!*nmt_newt_entry_get_text (NMT_NEWT_ENTRY (object))) {
+		char buf[32];
+
+		g_snprintf (buf, sizeof (buf), "%d", priv->min);
+		nmt_newt_entry_set_text (NMT_NEWT_ENTRY (object), buf);
+	}
+
+	G_OBJECT_CLASS (nmt_newt_entry_numeric_parent_class)->constructed (object);
+}
+
+static void
+nmt_newt_entry_numeric_set_property (GObject      *object,
+                                     guint         prop_id,
+                                     const GValue *value,
+                                     GParamSpec   *pspec)
+{
+	NmtNewtEntryNumericPrivate *priv = NMT_NEWT_ENTRY_NUMERIC_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_MINIMUM:
+		priv->min = g_value_get_int (value);
+		break;
+	case PROP_MAXIMUM:
+		priv->max = g_value_get_int (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_entry_numeric_get_property (GObject    *object,
+                                     guint       prop_id,
+                                     GValue     *value,
+                                     GParamSpec *pspec)
+{
+	NmtNewtEntryNumericPrivate *priv = NMT_NEWT_ENTRY_NUMERIC_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_MINIMUM:
+		g_value_set_int (value, priv->min);
+		break;
+	case PROP_MAXIMUM:
+		g_value_set_int (value, priv->max);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_entry_numeric_class_init (NmtNewtEntryNumericClass *entry_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (entry_class);
+
+	g_type_class_add_private (entry_class, sizeof (NmtNewtEntryNumericPrivate));
+
+	/* virtual methods */
+	object_class->constructed = nmt_newt_entry_numeric_constructed;
+	object_class->set_property = nmt_newt_entry_numeric_set_property;
+	object_class->get_property = nmt_newt_entry_numeric_get_property;
+
+	/**
+	 * NmtNewtEntryNumeric:minimum:
+	 *
+	 * The minimum #NmtNewtWidget:valid value for the entry. If this
+	 * is non-negative, then the entry will not allow negative numbers
+	 * to be entered.
+	 */
+	g_object_class_install_property (object_class, PROP_MINIMUM,
+	                                 g_param_spec_int ("minimum", "", "",
+	                                                   G_MININT, G_MAXINT, 0,
+	                                                   G_PARAM_READWRITE |
+	                                                   G_PARAM_CONSTRUCT_ONLY |
+	                                                   G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtEntryNumeric:maximum:
+	 *
+	 * The maximum #NmtNewtWidget:valid value for the entry.
+	 */
+	g_object_class_install_property (object_class, PROP_MAXIMUM,
+	                                 g_param_spec_int ("maximum", "", "",
+	                                                   G_MININT, G_MAXINT, G_MAXINT,
+	                                                   G_PARAM_READWRITE |
+	                                                   G_PARAM_CONSTRUCT_ONLY |
+	                                                   G_PARAM_STATIC_STRINGS));
+}
diff --git a/tui/newt/nmt-newt-entry-numeric.h b/tui/newt/nmt-newt-entry-numeric.h
new file mode 100644
index 00000000..43ac3449
--- /dev/null
+++ b/tui/newt/nmt-newt-entry-numeric.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_ENTRY_NUMERIC_H
+#define NMT_NEWT_ENTRY_NUMERIC_H
+
+#include "nmt-newt-entry.h"
+
+G_BEGIN_DECLS
+
+#define NMT_TYPE_NEWT_ENTRY_NUMERIC            (nmt_newt_entry_numeric_get_type ())
+#define NMT_NEWT_ENTRY_NUMERIC(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_ENTRY_NUMERIC, NmtNewtEntryNumeric))
+#define NMT_NEWT_ENTRY_NUMERIC_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_ENTRY_NUMERIC, NmtNewtEntryNumericClass))
+#define NMT_IS_NEWT_ENTRY_NUMERIC(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_ENTRY_NUMERIC))
+#define NMT_IS_NEWT_ENTRY_NUMERIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_ENTRY_NUMERIC))
+#define NMT_NEWT_ENTRY_NUMERIC_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_ENTRY_NUMERIC, NmtNewtEntryNumericClass))
+
+struct _NmtNewtEntryNumeric {
+	NmtNewtEntry parent;
+
+};
+
+typedef struct {
+	NmtNewtEntryClass parent;
+
+} NmtNewtEntryNumericClass;
+
+GType nmt_newt_entry_numeric_get_type (void);
+
+NmtNewtWidget *nmt_newt_entry_numeric_new (int width,
+                                           int min,
+                                           int max);
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_ENTRY_NUMERIC_H */
diff --git a/tui/newt/nmt-newt-entry.c b/tui/newt/nmt-newt-entry.c
new file mode 100644
index 00000000..c98fcee8
--- /dev/null
+++ b/tui/newt/nmt-newt-entry.c
@@ -0,0 +1,536 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-entry
+ * @short_description: Text entries
+ *
+ * #NmtNewtEntry implements entry widgets, with optional filtering and
+ * validation.
+ *
+ * See also #NmtNewtEntryNumeric, for numeric-only entries.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "nmt-newt-entry.h"
+#include "nmt-newt-form.h"
+#include "nmt-newt-hacks.h"
+#include "nmt-newt-utils.h"
+
+G_DEFINE_TYPE (NmtNewtEntry, nmt_newt_entry, NMT_TYPE_NEWT_COMPONENT)
+
+#define NMT_NEWT_ENTRY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_ENTRY, NmtNewtEntryPrivate))
+
+typedef struct {
+	int width;
+	NmtNewtEntryFlags flags;
+	char *text;
+	int last_cursor_pos;
+	guint idle_update;
+
+	NmtNewtEntryFilter filter;
+	gpointer filter_data;
+
+	NmtNewtEntryValidator validator;
+	gpointer validator_data;
+} NmtNewtEntryPrivate;
+
+enum {
+	PROP_0,
+	PROP_TEXT,
+	PROP_WIDTH,
+	PROP_FLAGS,
+	PROP_PASSWORD,
+
+	LAST_PROP
+};
+
+/**
+ * NmtNewtEntryFlags:
+ * @NMT_NEWT_ENTRY_NOSCROLL: the entry content should not scroll left
+ *   and right
+ * @NMT_NEWT_ENTRY_PASSWORD: the entry should show '*'s instead of its
+ *   actual contents
+ * @NMT_NEWT_ENTRY_NONEMPTY: the entry should be considered not
+ *   #NmtNewtWidget:valid if it is empty.
+ *
+ * Flags describing an #NmtNewtEntry
+ */
+
+/**
+ * nmt_newt_entry_new:
+ * @width: the width in characters for the entry
+ * @flags: flags describing the entry
+ *
+ * Creates a new #NmtNewtEntry.
+ *
+ * Returns: a new #NmtNewtEntry
+ */
+NmtNewtWidget *
+nmt_newt_entry_new (int               width,
+                    NmtNewtEntryFlags flags)
+{
+	return g_object_new (NMT_TYPE_NEWT_ENTRY,
+	                     "width", width,
+	                     "flags", flags,
+	                     NULL);
+}
+
+/**
+ * NmtNewtEntryFilter:
+ * @entry: the #NmtNewtEntry
+ * @text: the current contents of @entry
+ * @ch: the character just typed
+ * @position: the position of the cursor in @entry
+ * @user_data: the data passed to nmt_newt_entry_set_filter()
+ *
+ * Callback function used to filter the contents of an entry.
+ *
+ * Returns: %TRUE if @ch should be accepted, %FALSE if not
+ */
+
+/**
+ * nmt_newt_entry_set_filter:
+ * @entry: an #NmtNewtEntry
+ * @filter: the function to use to filter the entry
+ * @user_data: data for @filter
+ *
+ * Sets a #NmtNewtEntryFilter on @entry, to allow filtering out
+ * certain characters from the entry.
+ *
+ * Note that @filter will only be called for printable characters (eg,
+ * not for cursor-control characters or the like), and that it will
+ * only be called for user input, not, eg, for
+ * nmt_newt_entry_set_text().
+ */
+void
+nmt_newt_entry_set_filter (NmtNewtEntry       *entry,
+                           NmtNewtEntryFilter  filter,
+                           gpointer            user_data)
+{
+	NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry);
+
+	priv->filter = filter;
+	priv->filter_data = user_data;
+}
+
+static void
+nmt_newt_entry_check_valid (NmtNewtEntry *entry)
+{
+	NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry);
+	gboolean valid;
+
+	if (   (priv->flags & NMT_NEWT_ENTRY_NONEMPTY)
+	    && *priv->text == '\0')
+		valid = FALSE;
+	else if (priv->validator)
+		valid = !!priv->validator (entry, priv->text, priv->validator_data);
+	else
+		valid = TRUE;
+
+	nmt_newt_widget_set_valid (NMT_NEWT_WIDGET (entry), valid);
+}
+
+/**
+ * NmtNewtEntryValidator:
+ * @entry: the #NmtNewtEntry
+ * @text: the current contents of @entry
+ * @user_data: the data passed to nmt_newt_entry_set_validator()
+ *
+ * Callback function used to validate the contents of an entry.
+ *
+ * Returns: whether the entry is #NmtNewtWidget:valid
+ */
+
+/**
+ * nmt_newt_entry_set_validator:
+ * @entry: an #NmtNewtEntry
+ * @validator: the function to use to validate the entry
+ * @user_data: data for @validator
+ *
+ * Sets a #NmtNewtEntryValidator on @entry, to allow validation of
+ * the entry contents. If @validator returns %FALSE, then the entry
+ * will not be considered #NmtNewtWidget:valid.
+ */
+void
+nmt_newt_entry_set_validator (NmtNewtEntry          *entry,
+                              NmtNewtEntryValidator  validator,
+                              gpointer               user_data)
+{
+	NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry);
+
+	priv->validator = validator;
+	priv->validator_data = user_data;
+
+	nmt_newt_entry_check_valid (entry);
+}
+
+static void
+nmt_newt_entry_set_text_internal (NmtNewtEntry  *entry,
+                                  const char    *text,
+                                  newtComponent  co)
+{
+	NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry);
+
+	if (!text)
+		text = "";
+
+	if (!strcmp (priv->text, text))
+		return;
+
+	g_free (priv->text);
+	priv->text = g_strdup (text);
+
+	if (co) {
+		char *text_lc;
+
+		text_lc = priv->text ? nmt_newt_locale_from_utf8 (priv->text) : NULL;
+		newtEntrySet (co, text_lc, TRUE);
+		g_free (text_lc);
+		priv->last_cursor_pos = -1;
+	}
+
+	g_object_freeze_notify (G_OBJECT (entry));
+	nmt_newt_entry_check_valid (entry);
+	g_object_notify (G_OBJECT (entry), "text");
+	g_object_thaw_notify (G_OBJECT (entry));
+}
+
+/**
+ * nmt_newt_entry_set_text:
+ * @entry: an #NmtNewtEntry
+ * @text: the new text
+ *
+ * Updates @entry's text. Note that this skips the entry's
+ * #NmtNewtEntryFilter, but will cause its #NmtNewtEntryValidator to
+ * be re-run.
+ */
+void
+nmt_newt_entry_set_text (NmtNewtEntry *entry,
+                         const char   *text)
+{
+	newtComponent co;
+
+	co = nmt_newt_component_get_component (NMT_NEWT_COMPONENT (entry));
+	nmt_newt_entry_set_text_internal (entry, text, co);
+}
+
+/**
+ * nmt_newt_entry_get_text:
+ * @entry: an #NmtNewtEntry
+ *
+ * Gets @entry's text
+ *
+ * Returns: @entry's text
+ */
+const char *
+nmt_newt_entry_get_text (NmtNewtEntry *entry)
+{
+	NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry);
+
+	return priv->text;
+}
+
+/**
+ * nmt_newt_entry_set_width:
+ * @entry: an #NmtNewtEntpry
+ * @widget: the new width
+ *
+ * Updates @entry's width
+ */
+void
+nmt_newt_entry_set_width (NmtNewtEntry *entry,
+                          int           width)
+{
+	NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry);
+
+	if (priv->width == width)
+		return;
+
+	priv->width = width;
+	nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (entry));
+
+	g_object_notify (G_OBJECT (entry), "width");
+}
+
+/**
+ * nmt_newt_entry_get_width:
+ * @entry: an #NmtNewtEntry
+ *
+ * Gets @entry's width
+ *
+ * Returns: @entry's width
+ */
+int
+nmt_newt_entry_get_width (NmtNewtEntry *entry)
+{
+	NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry);
+
+	return priv->width;
+}
+
+static void
+nmt_newt_entry_init (NmtNewtEntry *entry)
+{
+	NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry);
+
+	priv->text = g_strdup ("");
+	priv->last_cursor_pos = -1;
+}
+
+static void
+nmt_newt_entry_constructed (GObject *object)
+{
+	nmt_newt_entry_check_valid (NMT_NEWT_ENTRY (object));
+
+	G_OBJECT_CLASS (nmt_newt_entry_parent_class)->constructed (object);
+}
+
+static void
+nmt_newt_entry_finalize (GObject *object)
+{
+	NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (object);
+
+	g_free (priv->text);
+	if (priv->idle_update)
+		g_source_remove (priv->idle_update);
+
+	G_OBJECT_CLASS (nmt_newt_entry_parent_class)->finalize (object);
+}
+
+static gboolean
+idle_update_entry (gpointer entry)
+{
+	NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry);
+	newtComponent co = nmt_newt_component_get_component (entry);
+	char *text;
+
+	priv->idle_update = 0;
+	if (!co)
+		return FALSE;
+
+	priv->last_cursor_pos = newtEntryGetCursorPosition (co);
+
+	text = nmt_newt_locale_to_utf8 (newtEntryGetValue (co));
+	nmt_newt_entry_set_text_internal (entry, text, NULL);
+	g_free (text);
+
+	return FALSE;
+}
+
+static int
+entry_filter (newtComponent  entry,
+              void          *self,
+              int            ch,
+              int            cursor)
+{
+	NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (self);
+
+	if (g_ascii_isprint (ch)) {
+		if (priv->filter) {
+			char *text = nmt_newt_locale_to_utf8 (newtEntryGetValue (entry));
+
+			if (!priv->filter (self, text, ch, cursor, priv->filter_data)) {
+				g_free (text);
+				return 0;
+			}
+			g_free (text);
+		}
+	}
+
+	if (!priv->idle_update)
+		priv->idle_update = g_idle_add (idle_update_entry, self);
+	return ch;
+}
+
+static guint
+convert_flags (NmtNewtEntryFlags flags)
+{
+	guint newt_flags = NEWT_FLAG_RETURNEXIT;
+
+	if (!(flags & NMT_NEWT_ENTRY_NOSCROLL))
+		newt_flags |= NEWT_FLAG_SCROLL;
+	if (flags & NMT_NEWT_ENTRY_PASSWORD)
+		newt_flags |= NEWT_FLAG_PASSWORD;
+
+	return newt_flags;
+}
+
+static newtComponent
+nmt_newt_entry_build_component (NmtNewtComponent *component,
+                                gboolean          sensitive)
+{
+	NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (component);
+	newtComponent co;
+	char *text_lc;
+	int flags;
+
+	flags = convert_flags (priv->flags);
+	if (!sensitive)
+		flags |= NEWT_FLAG_DISABLED;
+
+	text_lc = priv->text ? nmt_newt_locale_from_utf8 (priv->text) : NULL;
+	co = newtEntry (-1, -1, text_lc, priv->width, NULL, flags);
+	g_free (text_lc);
+
+	if (priv->last_cursor_pos != -1)
+		newtEntrySetCursorPosition (co, priv->last_cursor_pos);
+
+	newtEntrySetFilter (co, entry_filter, component);
+	return co;
+}
+
+static void
+nmt_newt_entry_activated (NmtNewtWidget *widget)
+{
+	NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (widget);
+
+	if (priv->idle_update) {
+		g_source_remove (priv->idle_update);
+		idle_update_entry (widget);
+	}
+
+	NMT_NEWT_WIDGET_CLASS (nmt_newt_entry_parent_class)->activated (widget);
+}
+
+static void
+nmt_newt_entry_set_property (GObject      *object,
+                             guint         prop_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+	NmtNewtEntry *entry = NMT_NEWT_ENTRY (object);
+	NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry);
+
+	switch (prop_id) {
+	case PROP_TEXT:
+		nmt_newt_entry_set_text (entry, g_value_get_string (value));
+		break;
+	case PROP_WIDTH:
+		nmt_newt_entry_set_width (entry, g_value_get_int (value));
+		break;
+	case PROP_FLAGS:
+		priv->flags = g_value_get_uint (value);
+		nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (entry));
+		break;
+	case PROP_PASSWORD:
+		if (g_value_get_boolean (value))
+			priv->flags |= NMT_NEWT_ENTRY_PASSWORD;
+		else
+			priv->flags &= ~NMT_NEWT_ENTRY_PASSWORD;
+		nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (entry));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_entry_get_property (GObject    *object,
+                             guint       prop_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+	NmtNewtEntry *entry = NMT_NEWT_ENTRY (object);
+	NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry);
+
+	switch (prop_id) {
+	case PROP_TEXT:
+		g_value_set_string (value, nmt_newt_entry_get_text (entry));
+		break;
+	case PROP_WIDTH:
+		g_value_set_int (value, priv->width);
+		break;
+	case PROP_FLAGS:
+		g_value_set_uint (value, priv->flags);
+		break;
+	case PROP_PASSWORD:
+		g_value_set_boolean (value, (priv->flags & NMT_NEWT_ENTRY_PASSWORD) != 0);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_entry_class_init (NmtNewtEntryClass *entry_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (entry_class);
+	NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (entry_class);
+	NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (entry_class);
+
+	g_type_class_add_private (entry_class, sizeof (NmtNewtEntryPrivate));
+
+	/* virtual methods */
+	object_class->constructed  = nmt_newt_entry_constructed;
+	object_class->set_property = nmt_newt_entry_set_property;
+	object_class->get_property = nmt_newt_entry_get_property;
+	object_class->finalize     = nmt_newt_entry_finalize;
+
+	widget_class->activated = nmt_newt_entry_activated;
+
+	component_class->build_component    = nmt_newt_entry_build_component;
+
+	/**
+	 * NmtNewtEntry:text
+	 *
+	 * The entry's text
+	 */
+	g_object_class_install_property (object_class, PROP_TEXT,
+	                                 g_param_spec_string ("text", "", "",
+	                                                      NULL,
+	                                                      G_PARAM_READWRITE |
+	                                                      G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtEntry:width
+	 *
+	 * The entry's width in characters
+	 */
+	g_object_class_install_property (object_class, PROP_WIDTH,
+	                                 g_param_spec_int ("width", "", "",
+	                                                   -1, 80, -1,
+	                                                   G_PARAM_READWRITE |
+	                                                   G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtEntry:flags
+	 *
+	 * The entry's #NmtNewtEntryFlags
+	 */
+	g_object_class_install_property (object_class, PROP_FLAGS,
+	                                 g_param_spec_uint ("flags", "", "",
+	                                                    0, 0xFFFF, 0,
+	                                                    G_PARAM_READWRITE |
+	                                                    G_PARAM_CONSTRUCT_ONLY |
+	                                                    G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtEntry:password
+	 *
+	 * %TRUE if #NmtNewtEntry:flags contains %NMT_NEWT_ENTRY_PASSWORD,
+	 * %FALSE if not.
+	 */
+	g_object_class_install_property (object_class, PROP_PASSWORD,
+	                                 g_param_spec_boolean ("password", "", "",
+	                                                       FALSE,
+	                                                       G_PARAM_READWRITE |
+	                                                       G_PARAM_STATIC_STRINGS));
+}
diff --git a/tui/newt/nmt-newt-entry.h b/tui/newt/nmt-newt-entry.h
new file mode 100644
index 00000000..8df0b137
--- /dev/null
+++ b/tui/newt/nmt-newt-entry.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_ENTRY_H
+#define NMT_NEWT_ENTRY_H
+
+#include "nmt-newt-component.h"
+
+G_BEGIN_DECLS
+
+#define NMT_TYPE_NEWT_ENTRY            (nmt_newt_entry_get_type ())
+#define NMT_NEWT_ENTRY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_ENTRY, NmtNewtEntry))
+#define NMT_NEWT_ENTRY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_ENTRY, NmtNewtEntryClass))
+#define NMT_IS_NEWT_ENTRY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_ENTRY))
+#define NMT_IS_NEWT_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_ENTRY))
+#define NMT_NEWT_ENTRY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_ENTRY, NmtNewtEntryClass))
+
+struct _NmtNewtEntry {
+  NmtNewtComponent parent;
+
+};
+
+typedef struct {
+  NmtNewtComponentClass parent;
+
+} NmtNewtEntryClass;
+
+GType nmt_newt_entry_get_type (void);
+
+typedef gboolean (*NmtNewtEntryFilter) (NmtNewtEntry *, const char *text, int ch, int position, gpointer);
+typedef gboolean (*NmtNewtEntryValidator) (NmtNewtEntry *, const char *text, gpointer);
+
+typedef enum {
+	NMT_NEWT_ENTRY_NOSCROLL = (1 << 0),
+	NMT_NEWT_ENTRY_PASSWORD = (1 << 1),
+	NMT_NEWT_ENTRY_NONEMPTY = (1 << 2)
+} NmtNewtEntryFlags;
+
+NmtNewtWidget *nmt_newt_entry_new           (int                    width,
+                                             NmtNewtEntryFlags      flags);
+
+void           nmt_newt_entry_set_filter    (NmtNewtEntry          *entry,
+                                             NmtNewtEntryFilter     filter,
+                                             gpointer               user_data);
+void           nmt_newt_entry_set_validator (NmtNewtEntry          *entry,
+                                             NmtNewtEntryValidator  validator,
+                                             gpointer               user_data);
+
+void           nmt_newt_entry_set_text      (NmtNewtEntry          *entry,
+                                             const char            *text);
+const char    *nmt_newt_entry_get_text      (NmtNewtEntry          *entry);
+
+void           nmt_newt_entry_set_width     (NmtNewtEntry          *entry,
+                                             int                    width);
+int            nmt_newt_entry_get_width     (NmtNewtEntry          *entry);
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_ENTRY_H */
diff --git a/tui/newt/nmt-newt-form.c b/tui/newt/nmt-newt-form.c
new file mode 100644
index 00000000..0c2063be
--- /dev/null
+++ b/tui/newt/nmt-newt-form.c
@@ -0,0 +1,743 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-form
+ * @short_description: The top-level NmtNewt widget
+ *
+ * #NmtNewtForm is the top-level widget that contains and presents a
+ * "form" (aka dialog) to the user.
+ */
+
+#include "config.h"
+
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <glib/gi18n-lib.h>
+
+#include "nmt-newt-form.h"
+#include "nmt-newt-button.h"
+#include "nmt-newt-grid.h"
+#include "nmt-newt-utils.h"
+
+G_DEFINE_TYPE (NmtNewtForm, nmt_newt_form, NMT_TYPE_NEWT_CONTAINER)
+
+#define NMT_NEWT_FORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_FORM, NmtNewtFormPrivate))
+
+typedef struct {
+	newtComponent form;
+	NmtNewtWidget *content;
+
+	guint x, y, width, height;
+	guint padding;
+	gboolean fixed_x, fixed_y;
+	gboolean fixed_width, fixed_height;
+	char *title_lc;
+
+	gboolean dirty, escape_exits;
+	NmtNewtWidget *focus;
+#ifdef HAVE_NEWTFORMGETSCROLLPOSITION
+	int scroll_position = 0;
+#endif
+} NmtNewtFormPrivate;
+
+enum {
+	PROP_0,
+	PROP_TITLE,
+	PROP_FULLSCREEN,
+	PROP_FULLSCREEN_VERTICAL,
+	PROP_FULLSCREEN_HORIZONTAL,
+	PROP_X,
+	PROP_Y,
+	PROP_WIDTH,
+	PROP_HEIGHT,
+	PROP_PADDING,
+	PROP_ESCAPE_EXITS,
+
+	LAST_PROP
+};
+
+enum {
+	QUIT,
+
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void nmt_newt_form_redraw (NmtNewtForm *form);
+
+/**
+ * nmt_newt_form_new:
+ * @title: (allow-none): the form title
+ *
+ * Creates a new form, which will be shown centered on the screen.
+ * Compare nmt_newt_form_new_fullscreen(). You can also position a
+ * form manually by setting its #NmtNewtForm:x and #NmtNewtForm:y
+ * properties at construct time, and/or by setting
+ * #NmtNewtForm:fullscreen, #NmtNewtform:fullscreen-horizontal, or
+ * #NmtNewtForm:fullscreen-vertical.
+ *
+ * If @title is NULL, the form will have no title.
+ *
+ * Returns: a new #NmtNewtForm
+ */
+NmtNewtForm *
+nmt_newt_form_new (const char *title)
+{
+	return g_object_new (NMT_TYPE_NEWT_FORM,
+	                     "title", title,
+	                     NULL);
+}
+
+/**
+ * nmt_newt_form_new_fullscreen:
+ * @title: (allow-none): the form title
+ *
+ * Creates a new fullscreen form. Compare nmt_newt_form_new().
+ *
+ * If @title is NULL, the form will have no title.
+ *
+ * Returns: a new #NmtNewtForm
+ */
+NmtNewtForm *
+nmt_newt_form_new_fullscreen (const char *title)
+{
+	return g_object_new (NMT_TYPE_NEWT_FORM,
+	                     "title", title,
+	                     "fullscreen", TRUE,
+	                     NULL);
+}
+
+static void
+nmt_newt_form_init (NmtNewtForm *form)
+{
+	g_object_ref_sink (form);
+}
+
+static void
+nmt_newt_form_finalize (GObject *object)
+{
+	NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (object);
+
+	g_free (priv->title_lc);
+	g_clear_object (&priv->focus);
+
+	G_OBJECT_CLASS (nmt_newt_form_parent_class)->finalize (object);
+}
+
+static void
+nmt_newt_form_needs_rebuild (NmtNewtWidget *widget)
+{
+	NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (widget);
+
+	if (!priv->dirty) {
+		priv->dirty = TRUE;
+		nmt_newt_form_redraw (NMT_NEWT_FORM (widget));
+	}
+}
+
+static void
+nmt_newt_form_remove (NmtNewtContainer *container,
+                      NmtNewtWidget    *widget)
+{
+	NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (container);
+	NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_newt_form_parent_class);
+
+	g_return_if_fail (widget == priv->content);
+
+	parent_class->remove (container, widget);
+	priv->content = NULL;
+}
+
+/**
+ * nmt_newt_form_set_content:
+ * @form: the #NmtNewtForm
+ * @content: the form's content
+ *
+ * Sets @form's content to be @content.
+ */
+void
+nmt_newt_form_set_content (NmtNewtForm      *form,
+                           NmtNewtWidget    *content)
+{
+	NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form);
+	NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_newt_form_parent_class);
+
+	if (priv->content)
+		nmt_newt_form_remove (NMT_NEWT_CONTAINER (form), priv->content);
+
+	priv->content = content;
+
+	if (priv->content)
+		parent_class->add (NMT_NEWT_CONTAINER (form), content);
+}
+
+static void
+nmt_newt_form_build (NmtNewtForm *form)
+{
+	NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form);
+	int screen_height, screen_width, form_height, form_width;
+	newtComponent *cos;
+	int i;
+
+	priv->dirty = FALSE;
+	nmt_newt_widget_realize (NMT_NEWT_WIDGET (form));
+
+	nmt_newt_widget_size_request (priv->content, &form_width, &form_height);
+	newtGetScreenSize (&screen_width, &screen_height);
+
+	if (!priv->fixed_width)
+		priv->width = MIN (form_width + 2 * priv->padding, screen_width - 2);
+	if (!priv->fixed_height)
+		priv->height = MIN (form_height + 2 * priv->padding, screen_height - 2);
+
+	if (!priv->fixed_x)
+		priv->x = (screen_width - form_width) / 2;
+	if (!priv->fixed_y)
+		priv->y = (screen_height - form_height) / 2;
+
+	nmt_newt_widget_size_allocate (priv->content,
+	                               priv->padding,
+	                               priv->padding,
+	                               priv->width - 2 * priv->padding,
+	                               priv->height - 2 * priv->padding);
+
+	if (priv->height - 2 * priv->padding < form_height) {
+		newtComponent scroll_bar =
+			newtVerticalScrollbar (priv->width - 1, 0, priv->height,
+			                       NEWT_COLORSET_WINDOW,
+			                       NEWT_COLORSET_ACTCHECKBOX);
+
+		priv->form = newtForm (scroll_bar, NULL, NEWT_FLAG_NOF12);
+		newtFormAddComponent (priv->form, scroll_bar);
+		newtFormSetHeight (priv->form, priv->height - 2);
+	} else
+		priv->form = newtForm (NULL, NULL, NEWT_FLAG_NOF12);
+
+	if (priv->escape_exits)
+		newtFormAddHotKey (priv->form, NEWT_KEY_ESCAPE);
+
+	cos = nmt_newt_widget_get_components (priv->content);
+	for (i = 0; cos[i]; i++)
+		newtFormAddComponent (priv->form, cos[i]);
+	g_free (cos);
+
+	if (priv->focus) {
+		newtComponent fco;
+
+		fco = nmt_newt_widget_get_focus_component (priv->focus);
+		if (fco)
+			newtFormSetCurrent (priv->form, fco);
+	}
+#ifdef HAVE_NEWTFORMGETSCROLLPOSITION
+	if (priv->scroll_position)
+		newtFormSetScrollPosition (priv->form, priv->scroll_position);
+#endif
+
+	newtOpenWindow (priv->x, priv->y, priv->width, priv->height, priv->title_lc);
+}
+
+static void
+nmt_newt_form_destroy (NmtNewtForm *form)
+{
+	NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form);
+
+#ifdef HAVE_NEWTFORMGETSCROLLPOSITION
+	priv->scroll_position = newtFormGetScrollPosition (priv->form);
+#endif
+
+	newtFormDestroy (priv->form);
+	priv->form = NULL;
+	newtPopWindowNoRefresh ();
+
+	nmt_newt_widget_unrealize (NMT_NEWT_WIDGET (form));
+}
+
+/* A "normal" newt program would call newtFormRun() to run newt's main loop
+ * and process events. But we want to let GLib's main loop control the program
+ * (eg, so libnm-glib can process D-Bus notifications). So we call this function
+ * to run a single iteration of newt's main loop (or rather, to run newt's
+ * main loop for 1ms) whenever there are events for newt to process (redrawing
+ * or keypresses).
+ */
+static void
+nmt_newt_form_iterate (NmtNewtForm *form)
+{
+	NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form);
+	NmtNewtWidget *focus;
+	struct newtExitStruct es;
+
+	if (priv->dirty) {
+		nmt_newt_form_destroy (form);
+		nmt_newt_form_build (form);
+	}
+
+	newtFormSetTimer (priv->form, 1);
+	newtFormRun (priv->form, &es);
+
+	if (   es.reason == NEWT_EXIT_HOTKEY
+	    || es.reason == NEWT_EXIT_ERROR) {
+		/* The user hit Esc or there was an error. */
+		g_clear_object (&priv->focus);
+		nmt_newt_form_quit (form);
+		return;
+	}
+
+	if (es.reason == NEWT_EXIT_COMPONENT) {
+		/* The user hit Return/Space on a component; update the form focus
+		 * to point that that component, and activate it.
+		 */
+		focus = nmt_newt_widget_find_component (priv->content, es.u.co);
+		if (focus) {
+			nmt_newt_form_set_focus (form, focus);
+			nmt_newt_widget_activated (focus);
+		}
+	} else {
+		/* The 1ms timer ran out. Update focus but don't do anything else. */
+		focus = nmt_newt_widget_find_component (priv->content,
+		                                        newtFormGetCurrent (priv->form));
+		if (focus)
+			nmt_newt_form_set_focus (form, focus);
+	}
+}
+
+/* @form_stack keeps track of all currently-displayed forms, from top to bottom.
+ * @keypress_source is the global stdin-monitoring GSource. When it triggers,
+ * nmt_newt_form_keypress_callback() iterates the top-most form, so it can
+ * process the keypress.
+ */
+static GSList *form_stack;
+static GSource *keypress_source;
+
+static gboolean
+nmt_newt_form_keypress_callback (int          fd,
+                                 GIOCondition condition,
+                                 gpointer     user_data)
+{
+	g_return_val_if_fail (form_stack != NULL, FALSE);
+
+	nmt_newt_form_iterate (form_stack->data);
+	return TRUE;
+}
+
+static gboolean
+nmt_newt_form_timeout_callback (gpointer user_data)
+{
+	if (form_stack)
+		nmt_newt_form_iterate (form_stack->data);
+	return FALSE;
+}
+
+static void
+nmt_newt_form_redraw (NmtNewtForm *form)
+{
+	g_timeout_add (0, nmt_newt_form_timeout_callback, NULL);
+}
+
+static void
+nmt_newt_form_real_show (NmtNewtForm *form)
+{
+	if (!keypress_source) {
+		GIOChannel *io;
+
+		io = g_io_channel_unix_new (STDIN_FILENO);
+		keypress_source = g_io_create_watch (io, G_IO_IN);
+		g_source_set_can_recurse (keypress_source, TRUE);
+		g_source_set_callback (keypress_source,
+		                       (GSourceFunc) nmt_newt_form_keypress_callback,
+		                       NULL, NULL);
+		g_source_attach (keypress_source, NULL);
+		g_io_channel_unref (io);
+	}
+
+	nmt_newt_form_build (form);
+	form_stack = g_slist_prepend (form_stack, g_object_ref (form));
+	nmt_newt_form_redraw (form);
+}
+
+/**
+ * nmt_newt_form_show:
+ * @form: an #NmtNewtForm
+ *
+ * Displays @form and begins running it asynchronously in the default
+ * #GMainContext. If another form is currently running, it will remain
+ * visible in the background, but will not be able to receive keyboard
+ * input until @form exits.
+ *
+ * Call nmt_newt_form_quit() to quit the form.
+ */
+void
+nmt_newt_form_show (NmtNewtForm *form)
+{
+	NMT_NEWT_FORM_GET_CLASS (form)->show (form);
+}
+
+/**
+ * nmt_newt_form_run_sync:
+ * @form: an #NmtNewtForm
+ *
+ * Displays @form as with nmt_newt_form_show(), but then iterates the
+ * #GMainContext internally until @form exits.
+ *
+ * Returns: the widget whose activation caused @form to exit, or
+ *   %NULL if it was not caused by a widget. FIXME: this exit value is
+ *   sort of weird and may not be 100% accurate anyway.
+ */
+NmtNewtWidget *
+nmt_newt_form_run_sync (NmtNewtForm *form)
+{
+	NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form);
+
+	nmt_newt_form_show (form);
+	while (priv->form)
+		g_main_context_iteration (NULL, TRUE);
+
+	return priv->focus;
+}
+
+/**
+ * nmt_newt_form_quit:
+ * @form: an #NmtNewtForm
+ *
+ * Causes @form to exit.
+ */
+void
+nmt_newt_form_quit (NmtNewtForm *form)
+{
+	NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form);
+
+	g_return_if_fail (priv->form != NULL);
+
+	nmt_newt_form_destroy (form);
+
+	form_stack = g_slist_remove (form_stack, form);
+
+	if (form_stack)
+		nmt_newt_form_iterate (form_stack->data);
+	else if (keypress_source) {
+		g_source_destroy (keypress_source);
+		g_clear_pointer (&keypress_source, g_source_unref);
+	}
+
+	g_signal_emit (form, signals[QUIT], 0);
+	g_object_unref (form);
+}
+
+/**
+ * nmt_newt_form_set_focus:
+ * @form: an #NmtNewtForm
+ * @widget: the widget to focus
+ *
+ * Focuses @widget in @form.
+ */
+void
+nmt_newt_form_set_focus (NmtNewtForm   *form,
+                         NmtNewtWidget *widget)
+{
+	NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form);
+
+	g_return_if_fail (priv->form != NULL);
+
+	if (priv->focus == widget)
+		return;
+
+	if (priv->focus)
+		g_object_unref (priv->focus);
+	priv->focus = widget;
+	if (priv->focus)
+		g_object_ref (priv->focus);
+}
+
+static void
+nmt_newt_form_set_property (GObject      *object,
+                            guint         prop_id,
+                            const GValue *value,
+                            GParamSpec   *pspec)
+{
+	NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (object);
+	int screen_width, screen_height;
+
+	switch (prop_id) {
+	case PROP_TITLE:
+		if (g_value_get_string (value)) {
+			priv->title_lc = nmt_newt_locale_from_utf8 (g_value_get_string (value));
+		} else
+			priv->title_lc = NULL;
+		break;
+	case PROP_FULLSCREEN:
+		if (g_value_get_boolean (value)) {
+			newtGetScreenSize (&screen_width, &screen_height);
+			priv->x = priv->y = 2;
+			priv->fixed_x = priv->fixed_y = TRUE;
+			priv->width = screen_width - 4;
+			priv->height = screen_height - 4;
+			priv->fixed_width = priv->fixed_height = TRUE;
+		}
+		break;
+	case PROP_FULLSCREEN_VERTICAL:
+		if (g_value_get_boolean (value)) {
+			newtGetScreenSize (&screen_width, &screen_height);
+			priv->y = 2;
+			priv->fixed_y = TRUE;
+			priv->height = screen_height - 4;
+			priv->fixed_height = TRUE;
+		}
+		break;
+	case PROP_FULLSCREEN_HORIZONTAL:
+		if (g_value_get_boolean (value)) {
+			newtGetScreenSize (&screen_width, &screen_height);
+			priv->x = 2;
+			priv->fixed_x = TRUE;
+			priv->width = screen_width - 4;
+			priv->fixed_width = TRUE;
+		}
+		break;
+	case PROP_X:
+		if (g_value_get_uint (value)) {
+			priv->x = g_value_get_uint (value);
+			priv->fixed_x = TRUE;
+		}
+		break;
+	case PROP_Y:
+		if (g_value_get_uint (value)) {
+			priv->y = g_value_get_uint (value);
+			priv->fixed_y = TRUE;
+		}
+		break;
+	case PROP_WIDTH:
+		if (g_value_get_uint (value)) {
+			priv->width = g_value_get_uint (value);
+			priv->fixed_width = TRUE;
+		}
+		break;
+	case PROP_HEIGHT:
+		if (g_value_get_uint (value)) {
+			priv->height = g_value_get_uint (value);
+			priv->fixed_height = TRUE;
+		}
+		break;
+	case PROP_PADDING:
+		priv->padding = g_value_get_uint (value);
+		break;
+	case PROP_ESCAPE_EXITS:
+		priv->escape_exits = g_value_get_boolean (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_form_get_property (GObject    *object,
+                            guint       prop_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+	NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_TITLE:
+		if (priv->title_lc) {
+			g_value_take_string (value, nmt_newt_locale_to_utf8 (priv->title_lc));
+		} else
+			g_value_set_string (value, NULL);
+		break;
+	case PROP_X:
+		g_value_set_uint (value, priv->x);
+		break;
+	case PROP_Y:
+		g_value_set_uint (value, priv->y);
+		break;
+	case PROP_WIDTH:
+		g_value_set_uint (value, priv->width);
+		break;
+	case PROP_HEIGHT:
+		g_value_set_uint (value, priv->height);
+		break;
+	case PROP_PADDING:
+		g_value_set_uint (value, priv->padding);
+		break;
+	case PROP_ESCAPE_EXITS:
+		g_value_set_boolean (value, priv->escape_exits);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_form_class_init (NmtNewtFormClass *form_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (form_class);
+	NmtNewtContainerClass *container_class = NMT_NEWT_CONTAINER_CLASS (form_class);
+	NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (form_class);
+
+	g_type_class_add_private (form_class, sizeof (NmtNewtFormPrivate));
+
+	/* virtual methods */
+	object_class->set_property = nmt_newt_form_set_property;
+	object_class->get_property = nmt_newt_form_get_property;
+	object_class->finalize     = nmt_newt_form_finalize;
+
+	widget_class->needs_rebuild = nmt_newt_form_needs_rebuild;
+
+	container_class->remove = nmt_newt_form_remove;
+
+	form_class->show = nmt_newt_form_real_show;
+
+	/* signals */
+
+	/**
+	 * NmtNewtForm::quit:
+	 * @form: the #NmtNewtForm
+	 *
+	 * Emitted when the form quits.
+	 */
+	signals[QUIT] =
+		g_signal_new ("quit",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NmtNewtFormClass, quit),
+		              NULL, NULL, NULL,
+		              G_TYPE_NONE, 0);
+
+	/**
+	 * NmtNewtForm:title:
+	 *
+	 * The form's title. If non-%NULL, this will be displayed above
+	 * the form in its border.
+	 */
+	g_object_class_install_property (object_class, PROP_TITLE,
+	                                 g_param_spec_string ("title", "", "",
+	                                                      NULL,
+	                                                      G_PARAM_READWRITE |
+	                                                      G_PARAM_STATIC_STRINGS |
+	                                                      G_PARAM_CONSTRUCT_ONLY));
+	/**
+	 * NmtNewtForm:fullscreen:
+	 *
+	 * If %TRUE, the form will fill the entire "screen" (ie, terminal
+	 * window).
+	 */
+	g_object_class_install_property (object_class, PROP_FULLSCREEN,
+	                                 g_param_spec_boolean ("fullscreen", "", "",
+	                                                       FALSE,
+	                                                       G_PARAM_WRITABLE |
+	                                                       G_PARAM_STATIC_STRINGS |
+	                                                       G_PARAM_CONSTRUCT_ONLY));
+	/**
+	 * NmtNewtForm:fullscreen-vertical:
+	 *
+	 * If %TRUE, the form will fill the entire "screen" (ie, terminal
+	 * window) vertically, but not necessarily horizontally.
+	 */
+	g_object_class_install_property (object_class, PROP_FULLSCREEN_VERTICAL,
+	                                 g_param_spec_boolean ("fullscreen-vertical", "", "",
+	                                                       FALSE,
+	                                                       G_PARAM_WRITABLE |
+	                                                       G_PARAM_STATIC_STRINGS |
+	                                                       G_PARAM_CONSTRUCT_ONLY));
+	/**
+	 * NmtNewtForm:fullscreen-horizontal:
+	 *
+	 * If %TRUE, the form will fill the entire "screen" (ie, terminal
+	 * window) horizontally, but not necessarily vertically.
+	 */
+	g_object_class_install_property (object_class, PROP_FULLSCREEN_HORIZONTAL,
+	                                 g_param_spec_boolean ("fullscreen-horizontal", "", "",
+	                                                       FALSE,
+	                                                       G_PARAM_WRITABLE |
+	                                                       G_PARAM_STATIC_STRINGS |
+	                                                       G_PARAM_CONSTRUCT_ONLY));
+	/**
+	 * NmtNewtForm:x:
+	 *
+	 * The form's x coordinate. By default, the form will be centered
+	 * on the screen.
+	 */
+	g_object_class_install_property (object_class, PROP_X,
+	                                 g_param_spec_uint ("x", "", "",
+	                                                    0, G_MAXUINT, 0,
+	                                                    G_PARAM_READWRITE |
+	                                                    G_PARAM_STATIC_STRINGS |
+	                                                    G_PARAM_CONSTRUCT_ONLY));
+	/**
+	 * NmtNewtForm:y:
+	 *
+	 * The form's y coordinate. By default, the form will be centered
+	 * on the screen.
+	 */
+	g_object_class_install_property (object_class, PROP_Y,
+	                                 g_param_spec_uint ("y", "", "",
+	                                                    0, G_MAXUINT, 0,
+	                                                    G_PARAM_READWRITE |
+	                                                    G_PARAM_STATIC_STRINGS |
+	                                                    G_PARAM_CONSTRUCT_ONLY));
+	/**
+	 * NmtNewtForm:width:
+	 *
+	 * The form's width. By default, this will be determined by the
+	 * width of the form's content.
+	 */
+	g_object_class_install_property (object_class, PROP_WIDTH,
+	                                 g_param_spec_uint ("width", "", "",
+	                                                    0, G_MAXUINT, 0,
+	                                                    G_PARAM_READWRITE |
+	                                                    G_PARAM_STATIC_STRINGS |
+	                                                    G_PARAM_CONSTRUCT_ONLY));
+	/**
+	 * NmtNewtForm:height:
+	 *
+	 * The form's height. By default, this will be determined by the
+	 * height of the form's content.
+	 */
+	g_object_class_install_property (object_class, PROP_HEIGHT,
+	                                 g_param_spec_uint ("height", "", "",
+	                                                    0, G_MAXUINT, 0,
+	                                                    G_PARAM_READWRITE |
+	                                                    G_PARAM_STATIC_STRINGS |
+	                                                    G_PARAM_CONSTRUCT_ONLY));
+	/**
+	 * NmtNewtForm:padding:
+	 *
+	 * The padding between the form's content and its border.
+	 */
+	g_object_class_install_property (object_class, PROP_PADDING,
+	                                 g_param_spec_uint ("padding", "", "",
+	                                                    0, G_MAXUINT, 1,
+	                                                    G_PARAM_READWRITE |
+	                                                    G_PARAM_STATIC_STRINGS |
+	                                                    G_PARAM_CONSTRUCT_ONLY));
+	/**
+	 * NmtNewtForm:escape-exits:
+	 *
+	 * If %TRUE, then hitting the Escape key will cause the form to
+	 * exit.
+	 */
+	g_object_class_install_property (object_class, PROP_ESCAPE_EXITS,
+	                                 g_param_spec_boolean ("escape-exits", "", "",
+	                                                       FALSE,
+	                                                       G_PARAM_READWRITE |
+	                                                       G_PARAM_STATIC_STRINGS |
+	                                                       G_PARAM_CONSTRUCT_ONLY));
+}
diff --git a/tui/newt/nmt-newt-form.h b/tui/newt/nmt-newt-form.h
new file mode 100644
index 00000000..be95eb68
--- /dev/null
+++ b/tui/newt/nmt-newt-form.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_FORM_H
+#define NMT_NEWT_FORM_H
+
+#include "nmt-newt-container.h"
+
+G_BEGIN_DECLS
+
+#define NMT_TYPE_NEWT_FORM            (nmt_newt_form_get_type ())
+#define NMT_NEWT_FORM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_FORM, NmtNewtForm))
+#define NMT_NEWT_FORM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_FORM, NmtNewtFormClass))
+#define NMT_IS_NEWT_FORM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_FORM))
+#define NMT_IS_NEWT_FORM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_FORM))
+#define NMT_NEWT_FORM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_FORM, NmtNewtFormClass))
+
+struct _NmtNewtForm {
+	NmtNewtContainer parent;
+
+};
+
+typedef struct {
+	NmtNewtContainerClass parent;
+
+	/* signals */
+	void (*quit) (NmtNewtForm *form);
+
+	/* methods */
+	void (*show) (NmtNewtForm *form);
+
+} NmtNewtFormClass;
+
+GType nmt_newt_form_get_type (void);
+
+NmtNewtForm   *nmt_newt_form_new              (const char          *title);
+NmtNewtForm   *nmt_newt_form_new_fullscreen   (const char          *title);
+
+void           nmt_newt_form_set_content      (NmtNewtForm         *form,
+                                               NmtNewtWidget       *content);
+
+void           nmt_newt_form_show             (NmtNewtForm         *form);
+NmtNewtWidget *nmt_newt_form_run_sync         (NmtNewtForm         *form);
+void           nmt_newt_form_quit             (NmtNewtForm         *form);
+
+void           nmt_newt_form_set_focus        (NmtNewtForm         *form,
+                                               NmtNewtWidget       *widget);
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_FORM_H */
diff --git a/tui/newt/nmt-newt-grid.c b/tui/newt/nmt-newt-grid.c
new file mode 100644
index 00000000..ac967334
--- /dev/null
+++ b/tui/newt/nmt-newt-grid.c
@@ -0,0 +1,472 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-grid
+ * @short_description: Grid container
+ *
+ * #NmtNewtGrid is the most general-purpose container widget in NmtNewt.
+ *
+ * An #NmtNewtGrid consists of a number of rows and columns. There is
+ * no pre-established maximum row or columns. Rather, rows and columns
+ * exist if and only if there are widgets in them.
+ *
+ * The width of each column is the width of the widest widget in that
+ * column, and the height of each row is the height of the tallest
+ * widget in that row. Empty rows and empty columns take up no space,
+ * so a grid with a single widget at 0,0 would look exactly the same
+ * if the widget was at 5,10 instead.
+ *
+ * If a widget's cell ends up being larger than the widget's requested
+ * size, then by default the widget will be centered in its cell.
+ * However, this can be modified by changing its #NmtNewtGridFlags.
+ * FIXME: the FILL/ANCHOR flags can be implemented in #NmtNewtWidget
+ * and so should move there. Less clear about the EXPAND flags, which
+ * must be implemented by the container...
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "nmt-newt-grid.h"
+
+G_DEFINE_TYPE (NmtNewtGrid, nmt_newt_grid, NMT_TYPE_NEWT_CONTAINER)
+
+#define NMT_NEWT_GRID_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_GRID, NmtNewtGridPrivate))
+
+typedef struct {
+	NmtNewtWidget *widget;
+	int x, y;
+	NmtNewtGridFlags flags;
+	int req_height, req_width;
+} NmtNewtGridChild;
+
+typedef struct {
+	GArray *children;
+	int max_x, max_y;
+	int *row_heights, *col_widths;
+	gboolean *expand_rows, *expand_cols;
+	int n_expand_rows, n_expand_cols;
+	int req_height, req_width;
+} NmtNewtGridPrivate;
+
+/**
+ * nmt_newt_grid_new:
+ *
+ * Creates a new #NmtNewtGrid
+ *
+ * Returns: a new #NmtNewtGrid
+ */
+NmtNewtWidget *
+nmt_newt_grid_new (void)
+{
+	return g_object_new (NMT_TYPE_NEWT_GRID, NULL);
+}
+
+static void
+nmt_newt_grid_init (NmtNewtGrid *grid)
+{
+	NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid);
+
+	priv->children = g_array_new (FALSE, FALSE, sizeof (NmtNewtGridChild));
+}
+
+static void
+nmt_newt_grid_finalize (GObject *object)
+{
+	NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (object);
+
+	g_array_unref (priv->children);
+	g_clear_pointer (&priv->row_heights, g_free);
+	g_clear_pointer (&priv->col_widths, g_free);
+	g_clear_pointer (&priv->expand_rows, g_free);
+	g_clear_pointer (&priv->expand_cols, g_free);
+
+	G_OBJECT_CLASS (nmt_newt_grid_parent_class)->finalize (object);
+}
+
+static int
+child_sort_func (gconstpointer a,
+                 gconstpointer b)
+{
+	NmtNewtGridChild *child_a = (NmtNewtGridChild *)a;
+	NmtNewtGridChild *child_b = (NmtNewtGridChild *)b;
+
+	if (child_a->y != child_b->y)
+		return child_a->y - child_b->y;
+	else
+		return child_a->x - child_b->x;
+}
+
+static newtComponent *
+nmt_newt_grid_get_components (NmtNewtWidget *widget)
+{
+	NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (widget);
+	NmtNewtGridChild *children;
+	GPtrArray *cos;
+	newtComponent *child_cos;
+	int i, c;
+
+	g_array_sort (priv->children, child_sort_func);
+	children = (NmtNewtGridChild *)priv->children->data;
+
+	cos = g_ptr_array_new ();
+
+	for (i = 0; i < priv->children->len; i++) {
+		if (!nmt_newt_widget_get_visible (children[i].widget))
+			continue;
+
+		child_cos = nmt_newt_widget_get_components (children[i].widget);
+		for (c = 0; child_cos[c]; c++)
+			g_ptr_array_add (cos, child_cos[c]);
+		g_free (child_cos);
+	}
+	g_ptr_array_add (cos, NULL);
+
+	return (newtComponent *) g_ptr_array_free (cos, FALSE);
+}
+
+static void
+nmt_newt_grid_size_request (NmtNewtWidget *widget,
+                            int           *width,
+                            int           *height)
+{
+	NmtNewtGrid *grid = NMT_NEWT_GRID (widget);
+	NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid);
+	NmtNewtGridChild *children = (NmtNewtGridChild *)priv->children->data;
+	int row, col, i;
+
+	g_free (priv->row_heights);
+	g_free (priv->col_widths);
+	g_free (priv->expand_rows);
+	g_free (priv->expand_cols);
+
+	priv->row_heights = g_new0 (int, priv->max_y + 1);
+	priv->col_widths = g_new0 (int, priv->max_x + 1);
+	priv->expand_rows = g_new0 (gboolean, priv->max_y + 1);
+	priv->expand_cols = g_new0 (gboolean, priv->max_x + 1);
+	priv->n_expand_rows = priv->n_expand_cols = 0;
+
+	for (row = 0; row < priv->max_y + 1; row++) {
+		for (col = 0; col < priv->max_x + 1; col++) {
+			for (i = 0; i < priv->children->len; i++) {
+				if (children[i].x != col || children[i].y != row)
+					continue;
+				if (!nmt_newt_widget_get_visible (children[i].widget))
+					continue;
+
+				nmt_newt_widget_size_request (children[i].widget,
+				                              &children[i].req_width,
+				                              &children[i].req_height);
+				if (children[i].req_height > priv->row_heights[row])
+					priv->row_heights[row] = children[i].req_height;
+				if (children[i].req_width > priv->col_widths[col])
+					priv->col_widths[col] = children[i].req_width;
+
+				if (   (children[i].flags & NMT_NEWT_GRID_EXPAND_X)
+				    && !priv->expand_cols[children[i].x]) {
+					priv->expand_cols[children[i].x] = TRUE;
+					priv->n_expand_cols++;
+				}
+				if (   (children[i].flags & NMT_NEWT_GRID_EXPAND_Y)
+				    && !priv->expand_rows[children[i].y]) {
+					priv->expand_rows[children[i].y] = TRUE;
+					priv->n_expand_rows++;
+				}
+			}
+		}
+	}
+
+	priv->req_height = priv->req_width = 0;
+	for (row = 0; row < priv->max_y + 1; row++)
+		priv->req_height += priv->row_heights[row];
+	for (col = 0; col < priv->max_x + 1; col++)
+		priv->req_width += priv->col_widths[col];
+
+	*height = priv->req_height;
+	*width = priv->req_width;
+}
+
+static void
+nmt_newt_grid_size_allocate (NmtNewtWidget *widget,
+                             int            x,
+                             int            y,
+                             int            width,
+                             int            height)
+{
+	NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (widget);
+	NmtNewtGridChild *children = (NmtNewtGridChild *)priv->children->data, *child;
+	int i, row, col;
+	int child_x, child_y, child_width, child_height;
+	int extra, extra_all, extra_some;
+
+	extra = width - priv->req_width;
+	if (extra > 0 && priv->n_expand_cols) {
+		extra_all = extra / priv->n_expand_cols;
+		extra_some = extra % priv->n_expand_cols;
+
+		for (col = 0; col < priv->max_x + 1; col++) {
+			if (!priv->expand_cols[col])
+				continue;
+			priv->col_widths[col] += extra_all;
+			if (extra_some) {
+				priv->col_widths[col]++;
+				extra_some--;
+			}
+		}
+	}
+
+	extra = height - priv->req_height;
+	if (extra > 0 && priv->n_expand_rows) {
+		extra_all = extra / priv->n_expand_rows;
+		extra_some = extra % priv->n_expand_rows;
+
+		for (row = 0; row < priv->max_y + 1; row++) {
+			if (!priv->expand_rows[row])
+				continue;
+			priv->row_heights[row] += extra_all;
+			if (extra_some) {
+				priv->row_heights[row]++;
+				extra_some--;
+			}
+		}
+	}
+
+	for (i = 0; i < priv->children->len; i++) {
+		child = &children[i];
+		if (!nmt_newt_widget_get_visible (child->widget))
+			continue;
+
+		child_x = x;
+		for (col = 0; col < child->x; col++)
+			child_x += priv->col_widths[col];
+
+		if ((child->flags & NMT_NEWT_GRID_FILL_X) == NMT_NEWT_GRID_FILL_X) {
+			child_width = priv->col_widths[child->x];
+		} else {
+			child_width = child->req_width;
+			if (child->flags & NMT_NEWT_GRID_ANCHOR_RIGHT)
+				child_x += priv->col_widths[child->x] - child->req_width;
+			else if (!(child->flags & NMT_NEWT_GRID_ANCHOR_LEFT))
+				child_x += (priv->col_widths[child->x] - child->req_width) / 2;
+		}
+
+		child_y = y;
+		for (row = 0; row < child->y; row++)
+			child_y += priv->row_heights[row];
+
+		if ((child->flags & NMT_NEWT_GRID_FILL_Y) == NMT_NEWT_GRID_FILL_Y) {
+			child_height = priv->row_heights[child->y];
+		} else {
+			child_height = child->req_height;
+			if (child->flags & NMT_NEWT_GRID_ANCHOR_BOTTOM)
+				child_y += priv->row_heights[child->y] - child->req_height;
+			else if (!(child->flags & NMT_NEWT_GRID_ANCHOR_TOP))
+				child_y += (priv->row_heights[child->y] - child->req_height) / 2;
+		}
+
+		nmt_newt_widget_size_allocate (child->widget,
+		                               child_x, child_y,
+		                               child_width, child_height);
+	}
+}
+
+static void
+nmt_newt_grid_find_size (NmtNewtGrid *grid)
+{
+	NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid);
+	NmtNewtGridChild *children = (NmtNewtGridChild *)priv->children->data;
+	int i;
+
+	priv->max_x = priv->max_y = 0;
+	for (i = 0; i < priv->children->len; i++) {
+		if (children[i].x > priv->max_x)
+			priv->max_x = children[i].x;
+		if (children[i].y > priv->max_y)
+			priv->max_y = children[i].y;
+	}
+}
+
+/**
+ * nmt_newt_grid_add:
+ * @grid: an #NmtNewtGrid
+ * @widget: the widget to add
+ * @x: x coordinate
+ * @y: y coordinate
+ *
+ * Adds @widget to @grid at @x, @y. See the discussion above for more
+ * details of exactly how this works.
+ */
+void
+nmt_newt_grid_add (NmtNewtGrid   *grid,
+                   NmtNewtWidget *widget,
+                   int            x,
+                   int            y)
+{
+	NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid);
+	NmtNewtGridChild child;
+
+	NMT_NEWT_CONTAINER_CLASS (nmt_newt_grid_parent_class)->add (NMT_NEWT_CONTAINER (grid), widget);
+
+	memset (&child, 0, sizeof (child));
+	child.widget = widget;
+	child.x = x;
+	child.y = y;
+	child.flags = NMT_NEWT_GRID_FILL_X | NMT_NEWT_GRID_FILL_Y;
+	g_array_append_val (priv->children, child);
+
+	if (x > priv->max_x)
+		priv->max_x = x;
+	if (y > priv->max_y)
+		priv->max_y = y;
+}
+
+static int
+find_child (NmtNewtGrid   *grid,
+            NmtNewtWidget *widget)
+{
+	NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid);
+	NmtNewtGridChild *children = (NmtNewtGridChild *)priv->children->data;
+	int i;
+
+	for (i = 0; i < priv->children->len; i++) {
+		if (children[i].widget == widget)
+			return i;
+	}
+
+	return -1;
+}
+
+static void
+nmt_newt_grid_remove (NmtNewtContainer *container,
+                      NmtNewtWidget    *widget)
+{
+	NmtNewtGrid *grid = NMT_NEWT_GRID (container);
+	NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid);
+	int i;
+
+	i = find_child (grid, widget);
+	if (i != -1) {
+		g_array_remove_index (priv->children, i);
+		nmt_newt_grid_find_size (grid);
+	}
+
+	NMT_NEWT_CONTAINER_CLASS (nmt_newt_grid_parent_class)->remove (container, widget);
+}
+
+/**
+ * nmt_newt_grid_move:
+ * @grid: an #NmtNewtGrid
+ * @widget: a child of @grid
+ * @x: x coordinate
+ * @y: y coordinate
+ *
+ * Moves @widget to the given new coordinates.
+ */
+void
+nmt_newt_grid_move (NmtNewtGrid   *grid,
+                    NmtNewtWidget *widget,
+                    int            x,
+                    int            y)
+{
+	NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid);
+	NmtNewtGridChild *children = (NmtNewtGridChild *)priv->children->data;
+	int i;
+
+	i = find_child (grid, widget);
+	if (i != -1 && (children[i].x != x || children[i].y != y)) {
+		children[i].x = x;
+		children[i].y = y;
+		nmt_newt_grid_find_size (grid);
+		nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (grid));
+	}
+}
+
+/**
+ * NmtNewtGridFlags:
+ * @NMT_NEWT_GRID_EXPAND_X: The widget's cell should expand
+ *   horizontally if the grid as a whole is given more width than
+ *   it requested.
+ * @NMT_NEWT_GRID_EXPAND_Y: The widget's cell should expand
+ *   vertically if the grid as a whole is given more height than
+ *   it requested.
+ * @NMT_NEWT_GRID_ANCHOR_LEFT: If the widget's cell is wider than
+ *   the widget requested, the widget should be anchored to the
+ *   left of its cell rather than being centered.
+ * @NMT_NEWT_GRID_ANCHOR_RIGHT: If the widget's cell is wider than
+ *   the widget requested, the widget should be anchored to the
+ *   right of its cell rather than being centered.
+ * @NMT_NEWT_GRID_FILL_X: If the widget's cell is wider than
+ *   the widget requested, the widget should be allocated the
+ *   full width of the cell; this is equivalent to specifying
+ *   both %NMT_NEWT_GRID_ANCHOR_LEFT and %NMT_NEWT_GRID_ANCHOR_RIGHT.
+ * @NMT_NEWT_GRID_ANCHOR_TOP: If the widget's cell is taller than
+ *   the widget requested, the widget should be anchored to the
+ *   top of its cell rather than being centered.
+ * @NMT_NEWT_GRID_ANCHOR_BOTTOM: If the widget's cell is taller than
+ *   the widget requested, the widget should be anchored to the
+ *   bottom of its cell rather than being centered.
+ * @NMT_NEWT_GRID_FILL_Y: If the widget's cell is taller than
+ *   the widget requested, the widget should be allocated the
+ *   full height of the cell; this is equivalent to specifying
+ *   both %NMT_NEWT_GRID_ANCHOR_TOP and %NMT_NEWT_GRID_ANCHOR_BOTTOM.
+ *
+ * Flags describing how a widget is placed within its grid cell.
+ */
+
+/**
+ * nmt_newt_grid_set_flags:
+ * @grid: an #NmtNewtGrid
+ * @widget: a child of @grid
+ * @flags: #NmtNewtGridFlags for @widget
+ *
+ * Sets the #NmtNewtGridFlags on @widget
+ */
+void
+nmt_newt_grid_set_flags (NmtNewtGrid      *grid,
+                         NmtNewtWidget    *widget,
+                         NmtNewtGridFlags  flags)
+{
+	NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid);
+	NmtNewtGridChild *children = (NmtNewtGridChild *)priv->children->data;
+	int i;
+
+	i = find_child (grid, widget);
+	if (i != -1)
+		children[i].flags = flags;
+}
+
+static void
+nmt_newt_grid_class_init (NmtNewtGridClass *grid_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (grid_class);
+	NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (grid_class);
+	NmtNewtContainerClass *container_class = NMT_NEWT_CONTAINER_CLASS (grid_class);
+
+	g_type_class_add_private (grid_class, sizeof (NmtNewtGridPrivate));
+
+	/* virtual methods */
+	object_class->finalize = nmt_newt_grid_finalize;
+
+	widget_class->get_components = nmt_newt_grid_get_components;
+	widget_class->size_request   = nmt_newt_grid_size_request;
+	widget_class->size_allocate  = nmt_newt_grid_size_allocate;
+
+	container_class->remove = nmt_newt_grid_remove;
+}
diff --git a/tui/newt/nmt-newt-grid.h b/tui/newt/nmt-newt-grid.h
new file mode 100644
index 00000000..f36a38ee
--- /dev/null
+++ b/tui/newt/nmt-newt-grid.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_GRID_H
+#define NMT_NEWT_GRID_H
+
+#include "nmt-newt-container.h"
+
+G_BEGIN_DECLS
+
+#define NMT_TYPE_NEWT_GRID            (nmt_newt_grid_get_type ())
+#define NMT_NEWT_GRID(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_GRID, NmtNewtGrid))
+#define NMT_NEWT_GRID_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_GRID, NmtNewtGridClass))
+#define NMT_IS_NEWT_GRID(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_GRID))
+#define NMT_IS_NEWT_GRID_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_GRID))
+#define NMT_NEWT_GRID_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_GRID, NmtNewtGridClass))
+
+struct _NmtNewtGrid {
+	NmtNewtContainer parent;
+
+};
+
+typedef struct {
+	NmtNewtContainerClass parent;
+
+} NmtNewtGridClass;
+
+GType nmt_newt_grid_get_type (void);
+
+typedef enum {
+	NMT_NEWT_GRID_EXPAND_X      = (1 << 0),
+	NMT_NEWT_GRID_EXPAND_Y      = (1 << 1),
+	NMT_NEWT_GRID_ANCHOR_LEFT   = (1 << 2),
+	NMT_NEWT_GRID_ANCHOR_RIGHT  = (1 << 3),
+	NMT_NEWT_GRID_FILL_X        = NMT_NEWT_GRID_ANCHOR_LEFT | NMT_NEWT_GRID_ANCHOR_RIGHT,
+	NMT_NEWT_GRID_ANCHOR_TOP    = (1 << 4),
+	NMT_NEWT_GRID_ANCHOR_BOTTOM = (1 << 5),
+	NMT_NEWT_GRID_FILL_Y        = NMT_NEWT_GRID_ANCHOR_TOP | NMT_NEWT_GRID_ANCHOR_BOTTOM,
+} NmtNewtGridFlags;
+
+NmtNewtWidget *nmt_newt_grid_new         (void);
+
+void           nmt_newt_grid_add         (NmtNewtGrid      *grid,
+                                          NmtNewtWidget    *widget,
+                                          int               x,
+                                          int               y);
+void           nmt_newt_grid_move        (NmtNewtGrid      *grid,
+                                          NmtNewtWidget    *widget,
+                                          int               x,
+                                          int               y);
+void           nmt_newt_grid_set_flags   (NmtNewtGrid      *grid,
+                                          NmtNewtWidget    *widget,
+                                          NmtNewtGridFlags  flags);
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_GRID_H */
diff --git a/tui/newt/nmt-newt-hacks.c b/tui/newt/nmt-newt-hacks.c
new file mode 100644
index 00000000..2d9b1725
--- /dev/null
+++ b/tui/newt/nmt-newt-hacks.c
@@ -0,0 +1,103 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-hacks
+ * @short_description: Hacks!
+ *
+ * This contains hacky cheating implementations of certain newt
+ * functions that were added after 0.52.15.
+ */
+
+#include "config.h"
+
+#include "nmt-newt-hacks.h"
+
+#if !defined (HAVE_NEWTCOMPONENTGETSIZE) || !defined (HAVE_NEWTENTRYGETCURSORPOSITION)
+struct newtComponent_0_52_15_struct_hack {
+	int height, width;
+	int top, left;
+	int takesFocus;
+	int isMapped;
+
+	struct componentOps *ops;
+
+	newtCallback callback;
+	void *callbackData;
+
+	newtCallback destroyCallback;
+	void *destroyCallbackData;
+
+	void *data;
+};
+#endif
+
+#ifndef HAVE_NEWTCOMPONENTGETSIZE
+void
+newtComponentGetSize (newtComponent  component,
+                      int           *width,
+                      int           *height)
+{
+	struct newtComponent_0_52_15_struct_hack *hack = (void *) component;
+
+	*width = hack->width;
+	*height = hack->height;
+}
+
+void
+newtComponentGetPosition (newtComponent  component,
+                          int           *left,
+                          int           *top)
+{
+	struct newtComponent_0_52_15_struct_hack *hack = (void *) component;
+
+	*left = hack->left;
+	*top = hack->top;
+}
+#endif
+
+#ifndef HAVE_NEWTENTRYGETCURSORPOSITION
+struct newtEntry_0_52_15_struct_hack {
+	int flags;
+	char *buf;
+	const char **resultPtr;
+	int bufAlloced;
+	int bufUsed;
+	int cursorPosition;
+	/* ... */
+};
+
+int
+newtEntryGetCursorPosition (newtComponent component)
+{
+	struct newtComponent_0_52_15_struct_hack *co_hack = (void *) component;
+	struct newtEntry_0_52_15_struct_hack *entry_hack = co_hack->data;
+
+	return entry_hack->cursorPosition;
+}
+
+void
+newtEntrySetCursorPosition (newtComponent component,
+                            int           position)
+{
+	struct newtComponent_0_52_15_struct_hack *co_hack = (void *) component;
+	struct newtEntry_0_52_15_struct_hack *entry_hack = co_hack->data;
+
+	entry_hack->cursorPosition = position;
+}
+#endif
diff --git a/tui/newt/nmt-newt-hacks.h b/tui/newt/nmt-newt-hacks.h
new file mode 100644
index 00000000..ba8464af
--- /dev/null
+++ b/tui/newt/nmt-newt-hacks.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_HACKS_H
+#define NMT_NEWT_HACKS_H
+
+#include "config.h"
+
+#include <newt.h>
+
+#ifndef HAVE_NEWTCOMPONENTGETSIZE
+void newtComponentGetSize     (newtComponent  component,
+                               int           *width,
+                               int           *height);
+
+void newtComponentGetPosition (newtComponent  component,
+                               int           *left,
+                               int           *top);
+#endif
+
+#ifndef HAVE_NEWTENTRYGETCURSORPOSITION
+int  newtEntryGetCursorPosition (newtComponent component);
+void newtEntrySetCursorPosition (newtComponent component,
+                                 int           position);
+#endif
+
+#endif /* NMT_NEWT_HACKS_H */
diff --git a/tui/newt/nmt-newt-label.c b/tui/newt/nmt-newt-label.c
new file mode 100644
index 00000000..a9d44b04
--- /dev/null
+++ b/tui/newt/nmt-newt-label.c
@@ -0,0 +1,323 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-label
+ * @short_description: Labels
+ *
+ * #NmtNewtLabel implements a single-line label.
+ *
+ * See also #NmtNewtTextbox, for multiline.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "nmt-newt-label.h"
+#include "nmt-newt-utils.h"
+
+G_DEFINE_TYPE (NmtNewtLabel, nmt_newt_label, NMT_TYPE_NEWT_COMPONENT)
+
+#define NMT_NEWT_LABEL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_LABEL, NmtNewtLabelPrivate))
+
+typedef struct {
+	char *text;
+	NmtNewtLabelStyle style;
+	gboolean highlight;
+} NmtNewtLabelPrivate;
+
+enum {
+	PROP_0,
+	PROP_TEXT,
+	PROP_STYLE,
+	PROP_HIGHLIGHT,
+
+	LAST_PROP
+};
+
+/**
+ * nmt_newt_label_new:
+ * @text: the initial label text
+ *
+ * Creates a new #NmtNewtLabel
+ *
+ * Returns: a new #NmtNewtLabel
+ */
+NmtNewtWidget *
+nmt_newt_label_new (const char *text)
+{
+	return g_object_new (NMT_TYPE_NEWT_LABEL,
+	                     "text", text,
+	                     NULL);
+}
+
+/**
+ * nmt_newt_label_set_text:
+ * @label: an #NmtNewtLabel
+ * @text: the new text
+ *
+ * Updates @label's text.
+ */
+void
+nmt_newt_label_set_text (NmtNewtLabel *label,
+                         const char   *text)
+{
+	NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (label);
+
+	if (!g_strcmp0 (priv->text, text))
+		return;
+
+	g_free (priv->text);
+	priv->text = g_strdup (text);
+
+	g_object_notify (G_OBJECT (label), "text");
+	nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (label));
+}
+
+/**
+ * nmt_newt_label_get_text:
+ * @label: an #NmtNewtLabel
+ *
+ * Gets @label's text
+ *
+ * Returns: @label's text
+ */
+const char *
+nmt_newt_label_get_text (NmtNewtLabel *label)
+{
+	NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (label);
+
+	return priv->text;
+}
+
+/**
+ * NmtNewtLabelStyle:
+ * @NMT_NEWT_LABEL_NORMAL: a normal label
+ * @NMT_NEWT_LABEL_PLAIN: a "plain-looking" label
+ *
+ * The label style. Normal labels are blue. Plain labels are black,
+ * making them look more like they are text in their own right rather
+ * than just being a label for something else.
+ */
+
+/**
+ * nmt_newt_label_set_style:
+ * @label: an #NmtNewtLabel
+ * @style: the #NmtNewtLabelStyle
+ *
+ * Sets the style of @label
+ */
+void
+nmt_newt_label_set_style (NmtNewtLabel      *label,
+                          NmtNewtLabelStyle  style)
+{
+	NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (label);
+
+	if (priv->style == style)
+		return;
+
+	priv->style = style;
+	g_object_notify (G_OBJECT (label), "style");
+	nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (label));
+}
+
+/**
+ * nmt_newt_label_get_style:
+ * @label: an #NmtNewtLabel
+ *
+ * Gets the style of @label
+ *
+ * Returns: the style of @label
+ */
+NmtNewtLabelStyle
+nmt_newt_label_get_style (NmtNewtLabel *label)
+{
+	NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (label);
+
+	return priv->style;
+}
+
+/**
+ * nmt_newt_label_set_highlight:
+ * @label: an #NmtNewtLabel
+ * @highlight: %TRUE if @label should be highlighted
+ *
+ * Sets whether @label is highlighted. Highlighted labels are red;
+ * this is generally used to highlight invalid widgets.
+ */
+void
+nmt_newt_label_set_highlight (NmtNewtLabel *label,
+                              gboolean      highlight)
+{
+	NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (label);
+
+	highlight = !!highlight;
+	if (priv->highlight == highlight)
+		return;
+
+	priv->highlight = highlight;
+	g_object_notify (G_OBJECT (label), "highlight");
+	nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (label));
+}
+
+/**
+ * nmt_newt_label_get_highlight:
+ * @label: an #NmtNewtLabel
+ *
+ * Gets whether @label is highlighted.
+ *
+ * Returns: whether @label is highlighted.
+ */
+gboolean
+nmt_newt_label_get_highlight (NmtNewtLabel *label)
+{
+	NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (label);
+
+	return priv->highlight;
+}
+
+static void
+nmt_newt_label_init (NmtNewtLabel *label)
+{
+}
+
+static void
+nmt_newt_label_finalize (GObject *object)
+{
+	NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (object);
+
+	g_free (priv->text);
+
+	G_OBJECT_CLASS (nmt_newt_label_parent_class)->finalize (object);
+}
+
+static newtComponent
+nmt_newt_label_build_component (NmtNewtComponent *component,
+                                gboolean          sensitive)
+{
+	NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (component);
+	newtComponent co;
+	char *text_lc;
+
+	text_lc = nmt_newt_locale_from_utf8 (priv->text);
+	co = newtLabel (-1, -1, text_lc);
+	g_free (text_lc);
+
+	if (priv->highlight)
+		newtLabelSetColors (co, NMT_NEWT_COLORSET_BAD_LABEL);
+	else if (priv->style == NMT_NEWT_LABEL_PLAIN)
+		newtLabelSetColors (co, NMT_NEWT_COLORSET_PLAIN_LABEL);
+
+	return co;
+}
+
+static void
+nmt_newt_label_set_property (GObject      *object,
+                             guint         prop_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+	NmtNewtLabel *label = NMT_NEWT_LABEL (object);
+
+	switch (prop_id) {
+	case PROP_TEXT:
+		nmt_newt_label_set_text (label, g_value_get_string (value));
+		break;
+	case PROP_STYLE:
+		nmt_newt_label_set_style (label, g_value_get_int (value));
+		break;
+	case PROP_HIGHLIGHT:
+		nmt_newt_label_set_highlight (label, g_value_get_boolean (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_label_get_property (GObject    *object,
+                             guint       prop_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+	NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_TEXT:
+		g_value_set_string (value, priv->text);
+		break;
+	case PROP_STYLE:
+		g_value_set_int (value, priv->style);
+		break;
+	case PROP_HIGHLIGHT:
+		g_value_set_boolean (value, priv->highlight);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_label_class_init (NmtNewtLabelClass *label_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (label_class);
+	NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (label_class);
+
+	g_type_class_add_private (label_class, sizeof (NmtNewtLabelPrivate));
+
+	/* virtual methods */
+	object_class->set_property = nmt_newt_label_set_property;
+	object_class->get_property = nmt_newt_label_get_property;
+	object_class->finalize     = nmt_newt_label_finalize;
+
+	component_class->build_component = nmt_newt_label_build_component;
+
+	/**
+	 * NmtNewtLabel:text:
+	 *
+	 * The label's text
+	 */
+	g_object_class_install_property (object_class, PROP_TEXT,
+	                                 g_param_spec_string ("text", "", "",
+	                                                      NULL,
+	                                                      G_PARAM_READWRITE |
+	                                                      G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtLabel:style:
+	 *
+	 * The label's #NmtNewtLabelStyle
+	 */
+	g_object_class_install_property (object_class, PROP_STYLE,
+	                                 g_param_spec_int ("style", "", "",
+	                                                   0, G_MAXINT, 0,
+	                                                   G_PARAM_READWRITE |
+	                                                   G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtLabel:highlight:
+	 *
+	 * Whether the label is highlighted.
+	 */
+	g_object_class_install_property (object_class, PROP_HIGHLIGHT,
+	                                 g_param_spec_boolean ("highlight", "", "",
+	                                                       FALSE,
+	                                                       G_PARAM_READWRITE |
+	                                                       G_PARAM_STATIC_STRINGS));
+}
diff --git a/tui/newt/nmt-newt-label.h b/tui/newt/nmt-newt-label.h
new file mode 100644
index 00000000..a4e0dcca
--- /dev/null
+++ b/tui/newt/nmt-newt-label.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_LABEL_H
+#define NMT_NEWT_LABEL_H
+
+#include "nmt-newt-component.h"
+
+G_BEGIN_DECLS
+
+#define NMT_TYPE_NEWT_LABEL            (nmt_newt_label_get_type ())
+#define NMT_NEWT_LABEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_LABEL, NmtNewtLabel))
+#define NMT_NEWT_LABEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_LABEL, NmtNewtLabelClass))
+#define NMT_IS_NEWT_LABEL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_LABEL))
+#define NMT_IS_NEWT_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_LABEL))
+#define NMT_NEWT_LABEL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_LABEL, NmtNewtLabelClass))
+
+struct _NmtNewtLabel {
+	NmtNewtComponent parent;
+
+};
+
+typedef struct {
+	NmtNewtComponentClass parent;
+
+} NmtNewtLabelClass;
+
+GType nmt_newt_label_get_type (void);
+
+typedef enum {
+	NMT_NEWT_LABEL_NORMAL,
+	NMT_NEWT_LABEL_PLAIN
+} NmtNewtLabelStyle;
+
+NmtNewtWidget     *nmt_newt_label_new           (const char        *text);
+
+void               nmt_newt_label_set_text      (NmtNewtLabel      *label,
+                                                 const char        *text);
+const char        *nmt_newt_label_get_text      (NmtNewtLabel      *label);
+
+void               nmt_newt_label_set_style     (NmtNewtLabel      *label,
+                                                 NmtNewtLabelStyle  style);
+NmtNewtLabelStyle  nmt_newt_label_get_style     (NmtNewtLabel      *label);
+
+void               nmt_newt_label_set_highlight (NmtNewtLabel      *label,
+                                                 gboolean           highlight);
+gboolean           nmt_newt_label_get_highlight (NmtNewtLabel      *label);
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_LABEL_H */
diff --git a/tui/newt/nmt-newt-listbox.c b/tui/newt/nmt-newt-listbox.c
new file mode 100644
index 00000000..78c55dbe
--- /dev/null
+++ b/tui/newt/nmt-newt-listbox.c
@@ -0,0 +1,543 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-listbox
+ * @short_description: Single-choice listboxes
+ *
+ * #NmtNewtListbox implements a single-choice listbox.
+ *
+ * A listbox has some number of rows, each associated with an
+ * arbitrary pointer value. The pointer values do not need to be
+ * unique, but some APIs will not be usable if they aren't. You
+ * can also cause rows with %NULL keys to be treated specially.
+ *
+ * The listbox will emit #NmtNewtWidget::activate when the user
+ * presses Return on a selection.
+ */
+
+#include "config.h"
+
+#include "nmt-newt-listbox.h"
+#include "nmt-newt-form.h"
+#include "nmt-newt-utils.h"
+
+G_DEFINE_TYPE (NmtNewtListbox, nmt_newt_listbox, NMT_TYPE_NEWT_COMPONENT)
+
+#define NMT_NEWT_LISTBOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_LISTBOX, NmtNewtListboxPrivate))
+
+typedef struct {
+	int height, alloc_height, width;
+	gboolean fixed_height;
+	NmtNewtListboxFlags flags;
+
+	GPtrArray *entries;
+	GPtrArray *keys;
+
+	int active;
+	gpointer active_key;
+	gboolean skip_null_keys;
+
+} NmtNewtListboxPrivate;
+
+enum {
+	PROP_0,
+	PROP_HEIGHT,
+	PROP_FLAGS,
+	PROP_ACTIVE,
+	PROP_ACTIVE_KEY,
+	PROP_SKIP_NULL_KEYS,
+
+	LAST_PROP
+};
+
+/**
+ * NmtNewtListboxFlags:
+ * @NMT_NEWT_LISTBOX_SCROLL: the listbox should have a scroll bar.
+ * @NMT_NEWT_LISTBOX_BORDER: the listbox should have a border around it.
+ *
+ * Flags describing an #NmtNewtListbox
+ */
+
+/**
+ * nmt_newt_listbox_new:
+ * @height: the height of the listbox, or -1 for no fixed height
+ * @flags: the listbox flags
+ *
+ * Creates a new #NmtNewtListbox
+ *
+ * Returns: a new #NmtNewtListbox
+ */
+NmtNewtWidget *
+nmt_newt_listbox_new (int                 height,
+                      NmtNewtListboxFlags flags)
+{
+	return g_object_new (NMT_TYPE_NEWT_LISTBOX,
+	                     "height", height,
+	                     "flags", flags,
+	                     NULL);
+}
+
+/**
+ * nmt_newt_listbox_append:
+ * @listbox: an #NmtNewtListbox
+ * @entry: the text for the new row
+ * @key: (allow-none): the key associated with @entry
+ *
+ * Adds a row to @listbox.
+ */
+void
+nmt_newt_listbox_append (NmtNewtListbox *listbox,
+                         const char     *entry,
+                         gpointer        key)
+{
+	NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox);
+
+	g_ptr_array_add (priv->entries, nmt_newt_locale_from_utf8 (entry));
+	g_ptr_array_add (priv->keys, key);
+	nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (listbox));
+}
+
+/**
+ * nmt_newt_listbox_clear:
+ * @listbox: an #NmtNewtListbox
+ *
+ * Clears the contents of @listbox.
+ */
+void
+nmt_newt_listbox_clear (NmtNewtListbox *listbox)
+{
+	NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox);
+
+	g_ptr_array_set_size (priv->entries, 0);
+	g_ptr_array_set_size (priv->keys, 0);
+
+	priv->active = -1;
+	priv->active_key = NULL;
+
+	nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (listbox));
+}
+
+/**
+ * nmt_newt_listbox_set_active:
+ * @listbox: an #NmtNewtListbox
+ * @active: the row to make active
+ *
+ * Sets @active to be the currently-selected row in @listbox,
+ * scrolling it into view if needed.
+ */
+void
+nmt_newt_listbox_set_active (NmtNewtListbox *listbox,
+                             int             active)
+{
+	NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox);
+
+	if (active == priv->active)
+		return;
+
+	g_return_if_fail (active >= 0 && active < priv->entries->len);
+	g_return_if_fail (!priv->skip_null_keys || priv->keys->pdata[active]);
+
+	priv->active = active;
+	priv->active_key = priv->keys->pdata[active];
+
+	g_object_notify (G_OBJECT (listbox), "active");
+	g_object_notify (G_OBJECT (listbox), "active-key");
+}
+
+/**
+ * nmt_newt_listbox_set_active_key:
+ * @listbox: an #NmtNewtListbox
+ * @active_key: the key for the row to make active
+ *
+ * Selects the (first) row in @listbox with @active_key as its key,
+ * scrolling it into view if needed.
+ */
+void
+nmt_newt_listbox_set_active_key (NmtNewtListbox *listbox,
+                                 gpointer        active_key)
+{
+	NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox);
+	int i;
+
+	if (active_key == priv->active_key)
+		return;
+
+	g_return_if_fail (!priv->skip_null_keys || active_key);
+
+	for (i = 0; i < priv->keys->len; i++) {
+		if (priv->keys->pdata[i] == active_key) {
+			priv->active = i;
+			priv->active_key = active_key;
+
+			g_object_notify (G_OBJECT (listbox), "active");
+			g_object_notify (G_OBJECT (listbox), "active-key");
+			return;
+		}
+	}
+}
+
+/**
+ * nmt_newt_listbox_get_active:
+ * @listbox: an #NmtNewtListbox
+ *
+ * Gets the currently-selected row in @listbox.
+ *
+ * Returns: the currently-selected row in @listbox.
+ */
+int
+nmt_newt_listbox_get_active (NmtNewtListbox *listbox)
+{
+	NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox);
+
+	return priv->active;
+}
+
+/**
+ * nmt_newt_listbox_get_active_key:
+ * @listbox: an #NmtNewtListbox
+ *
+ * Gets the key of the currently-selected row in @listbox.
+ *
+ * Returns: the key of the currently-selected row in @listbox.
+ */
+gpointer
+nmt_newt_listbox_get_active_key (NmtNewtListbox *listbox)
+{
+	NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox);
+
+	return priv->active_key;
+}
+
+/**
+ * nmt_newt_listbox_set_height:
+ * @listbox: an #NmtNewtListbox
+ * @height: the new height, or -1 for no fixed heigh
+ *
+ * Updates @listbox's height.
+ */
+void
+nmt_newt_listbox_set_height (NmtNewtListbox *listbox,
+                             int             height)
+{
+	NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox);
+
+	priv->height = height;
+	priv->fixed_height = priv->height != 0;
+	g_object_notify (G_OBJECT (listbox), "height");
+}
+
+static void
+nmt_newt_listbox_init (NmtNewtListbox *listbox)
+{
+	NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox);
+
+	priv->entries = g_ptr_array_new_with_free_func (g_free);
+	priv->keys = g_ptr_array_new ();
+
+	priv->active = -1;
+}
+
+static void
+nmt_newt_listbox_finalize (GObject *object)
+{
+	NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (object);
+
+	g_ptr_array_unref (priv->entries);
+	g_ptr_array_unref (priv->keys);
+
+	G_OBJECT_CLASS (nmt_newt_listbox_parent_class)->finalize (object);
+}
+
+static void
+nmt_newt_listbox_size_request (NmtNewtWidget *widget,
+                               int           *width,
+                               int           *height)
+{
+	NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (widget);
+
+	NMT_NEWT_WIDGET_CLASS (nmt_newt_listbox_parent_class)->
+		size_request (widget, width, height);
+
+	priv->alloc_height = -1;
+	if (!priv->fixed_height)
+		*height = 1;
+	priv->width = *width;
+}
+
+static void
+nmt_newt_listbox_size_allocate (NmtNewtWidget *widget,
+                                int            x,
+                                int            y,
+                                int            width,
+                                int            height)
+{
+	NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (widget);
+
+	if (width > priv->width) {
+		newtListboxSetWidth (nmt_newt_component_get_component (NMT_NEWT_COMPONENT (widget)),
+		                     width);
+	}
+
+	NMT_NEWT_WIDGET_CLASS (nmt_newt_listbox_parent_class)->
+		size_allocate (widget, x, y, width, height);
+
+	priv->alloc_height = height;
+
+	if (!priv->fixed_height && height != priv->height) {
+		priv->height = height;
+		nmt_newt_widget_needs_rebuild (widget);
+	}
+}
+
+static void
+update_active_internal (NmtNewtListbox *listbox,
+                        int             new_active)
+{
+	NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox);
+
+	if (priv->active == new_active)
+		return;
+	if (new_active >= priv->keys->len)
+		return;
+
+	if (priv->skip_null_keys && !priv->keys->pdata[new_active]) {
+		if (new_active > priv->active) {
+			while (   new_active < priv->entries->len
+			       && !priv->keys->pdata[new_active])
+				new_active++;
+		} else {
+			while (   new_active >= 0
+			       && !priv->keys->pdata[new_active])
+				new_active--;
+		}
+
+		if (   new_active < 0
+		    || new_active >= priv->entries->len
+		    || !priv->keys->pdata[new_active]) {
+			g_assert (priv->active >= 0 && priv->active < priv->entries->len);
+			return;
+		}
+	}
+
+	nmt_newt_listbox_set_active (listbox, new_active);
+}
+
+static void
+selection_changed_callback (newtComponent  co,
+                            void          *user_data)
+{
+	NmtNewtListbox *listbox = user_data;
+	NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox);
+	int new_active;
+
+	new_active = GPOINTER_TO_UINT (newtListboxGetCurrent (co));
+	update_active_internal (listbox, new_active);
+
+	if (priv->active != new_active)
+		newtListboxSetCurrent (co, priv->active);
+}
+
+static guint
+convert_flags (NmtNewtListboxFlags flags)
+{
+	guint newt_flags = NEWT_FLAG_RETURNEXIT;
+
+	if (flags & NMT_NEWT_LISTBOX_SCROLL)
+		newt_flags |= NEWT_FLAG_SCROLL;
+	if (flags & NMT_NEWT_LISTBOX_BORDER)
+		newt_flags |= NEWT_FLAG_BORDER;
+
+	return newt_flags;
+}
+
+static newtComponent
+nmt_newt_listbox_build_component (NmtNewtComponent *component,
+                                  gboolean          sensitive)
+{
+	NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (component);
+	newtComponent co;
+	int i, active;
+
+	if (priv->active == -1)
+		update_active_internal (NMT_NEWT_LISTBOX (component), 0);
+	active = priv->active;
+
+	co = newtListbox (-1, -1, priv->height, convert_flags (priv->flags));
+	newtComponentAddCallback (co, selection_changed_callback, component);
+
+	for (i = 0; i < priv->entries->len; i++) {
+		newtListboxAppendEntry (co, priv->entries->pdata[i], GUINT_TO_POINTER (i));
+		if (active == -1 && priv->keys->pdata[i] == priv->active_key)
+			active = i;
+	}
+
+	if (active != -1)
+		newtListboxSetCurrent (co, active);
+
+	return co;
+}
+
+static void
+nmt_newt_listbox_activated (NmtNewtWidget *widget)
+{
+	NmtNewtListbox *listbox = NMT_NEWT_LISTBOX (widget);
+	newtComponent co = nmt_newt_component_get_component (NMT_NEWT_COMPONENT (widget));
+
+	nmt_newt_listbox_set_active (listbox, GPOINTER_TO_UINT (newtListboxGetCurrent (co)));
+
+	NMT_NEWT_WIDGET_CLASS (nmt_newt_listbox_parent_class)->activated (widget);
+}
+
+static void
+nmt_newt_listbox_set_property (GObject      *object,
+                               guint         prop_id,
+                               const GValue *value,
+                               GParamSpec   *pspec)
+{
+	NmtNewtListbox *listbox = NMT_NEWT_LISTBOX (object);
+	NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_HEIGHT:
+		priv->height = g_value_get_int (value);
+		priv->fixed_height = (priv->height != 0);
+		break;
+	case PROP_FLAGS:
+		priv->flags = g_value_get_uint (value);
+		break;
+	case PROP_ACTIVE:
+		nmt_newt_listbox_set_active (listbox, g_value_get_int (value));
+		break;
+	case PROP_ACTIVE_KEY:
+		nmt_newt_listbox_set_active_key (listbox, g_value_get_pointer (value));
+		break;
+	case PROP_SKIP_NULL_KEYS:
+		priv->skip_null_keys = g_value_get_boolean (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_listbox_get_property (GObject    *object,
+                             guint       prop_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+	NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_HEIGHT:
+		g_value_set_int (value, priv->height);
+		break;
+	case PROP_FLAGS:
+		g_value_set_uint (value, priv->flags);
+		break;
+	case PROP_ACTIVE:
+		g_value_set_int (value, priv->active);
+		break;
+	case PROP_ACTIVE_KEY:
+		g_value_set_pointer (value, priv->active_key);
+		break;
+	case PROP_SKIP_NULL_KEYS:
+		g_value_set_boolean (value, priv->skip_null_keys);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_listbox_class_init (NmtNewtListboxClass *listbox_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (listbox_class);
+	NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (listbox_class);
+	NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (listbox_class);
+
+	g_type_class_add_private (listbox_class, sizeof (NmtNewtListboxPrivate));
+
+	/* virtual methods */
+	object_class->set_property = nmt_newt_listbox_set_property;
+	object_class->get_property = nmt_newt_listbox_get_property;
+	object_class->finalize     = nmt_newt_listbox_finalize;
+
+	widget_class->size_request  = nmt_newt_listbox_size_request;
+	widget_class->size_allocate = nmt_newt_listbox_size_allocate;
+	widget_class->activated     = nmt_newt_listbox_activated;
+
+	component_class->build_component = nmt_newt_listbox_build_component;
+
+	/* properties */
+
+	/**
+	 * NmtNewtListbox:height:
+	 *
+	 * The listbox's height, or -1 if it has no fixed height.
+	 */
+	g_object_class_install_property (object_class, PROP_HEIGHT,
+	                                 g_param_spec_int ("height", "", "",
+	                                                   -1, 255, -1,
+	                                                   G_PARAM_READWRITE |
+	                                                   G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtListbox:flags:
+	 *
+	 * The listbox's #NmtNewtListboxFlags.
+	 */
+	g_object_class_install_property (object_class, PROP_FLAGS,
+	                                 g_param_spec_uint ("flags", "", "",
+	                                                    0, 0xFFFF, 0,
+	                                                    G_PARAM_READWRITE |
+	                                                    G_PARAM_CONSTRUCT_ONLY |
+	                                                    G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtListbox:active:
+	 *
+	 * The currently-selected row.
+	 */
+	g_object_class_install_property (object_class, PROP_ACTIVE,
+	                                 g_param_spec_int ("active", "", "",
+	                                                   0, G_MAXINT, 0,
+	                                                   G_PARAM_READWRITE |
+	                                                   G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtListbox:active-key:
+	 *
+	 * The key of the currently-selected row.
+	 */
+	g_object_class_install_property (object_class, PROP_ACTIVE_KEY,
+	                                 g_param_spec_pointer ("active-key", "", "",
+	                                                       G_PARAM_READWRITE |
+	                                                       G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtListbox:skip-null-keys:
+	 *
+	 * If %TRUE, rows with %NULL key values will be skipped over when
+	 * navigating the list with the arrow keys.
+	 */
+	g_object_class_install_property (object_class, PROP_SKIP_NULL_KEYS,
+	                                 g_param_spec_boolean ("skip-null-keys", "", "",
+	                                                       FALSE,
+	                                                       G_PARAM_READWRITE |
+	                                                       G_PARAM_CONSTRUCT_ONLY |
+	                                                       G_PARAM_STATIC_STRINGS));
+}
diff --git a/tui/newt/nmt-newt-listbox.h b/tui/newt/nmt-newt-listbox.h
new file mode 100644
index 00000000..c18c9f8e
--- /dev/null
+++ b/tui/newt/nmt-newt-listbox.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_LISTBOX_H
+#define NMT_NEWT_LISTBOX_H
+
+#include "nmt-newt-component.h"
+
+G_BEGIN_DECLS
+
+#define NMT_TYPE_NEWT_LISTBOX            (nmt_newt_listbox_get_type ())
+#define NMT_NEWT_LISTBOX(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_LISTBOX, NmtNewtListbox))
+#define NMT_NEWT_LISTBOX_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_LISTBOX, NmtNewtListboxClass))
+#define NMT_IS_NEWT_LISTBOX(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_LISTBOX))
+#define NMT_IS_NEWT_LISTBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_LISTBOX))
+#define NMT_NEWT_LISTBOX_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_LISTBOX, NmtNewtListboxClass))
+
+struct _NmtNewtListbox {
+	NmtNewtComponent parent;
+
+};
+
+typedef struct {
+	NmtNewtComponentClass parent;
+
+} NmtNewtListboxClass;
+
+GType nmt_newt_listbox_get_type (void);
+
+typedef enum {
+	NMT_NEWT_LISTBOX_SCROLL = (1 << 0),
+	NMT_NEWT_LISTBOX_BORDER = (1 << 1)
+} NmtNewtListboxFlags;
+
+NmtNewtWidget *nmt_newt_listbox_new            (int                  height,
+                                                NmtNewtListboxFlags  flags);
+
+void           nmt_newt_listbox_set_height     (NmtNewtListbox      *listbox,
+                                                int                  height);
+
+void           nmt_newt_listbox_append         (NmtNewtListbox      *listbox,
+                                                const char          *entry,
+                                                gpointer             key);
+void           nmt_newt_listbox_clear          (NmtNewtListbox      *listbox);
+
+void           nmt_newt_listbox_set_active     (NmtNewtListbox      *listbox,
+                                                int                  active);
+void           nmt_newt_listbox_set_active_key (NmtNewtListbox      *listbox,
+                                                gpointer             active_key);
+
+int            nmt_newt_listbox_get_active     (NmtNewtListbox      *listbox);
+gpointer       nmt_newt_listbox_get_active_key (NmtNewtListbox      *listbox);
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_LISTBOX_H */
diff --git a/tui/newt/nmt-newt-popup.c b/tui/newt/nmt-newt-popup.c
new file mode 100644
index 00000000..e9757eac
--- /dev/null
+++ b/tui/newt/nmt-newt-popup.c
@@ -0,0 +1,343 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-popup
+ * @short_description: Pop-up menus
+ *
+ * #NmtNewtPopup implements a pop-up menu. When inactive, they appear
+ * the same as #NmtNewtButtons, displaying the label from the
+ * #NmtNewtPopup:active entry. When activated, they pop up a temporary
+ * #NmtNewtForm containing an #NmtNewtListbox to select from.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+
+#include "nmt-newt-popup.h"
+#include "nmt-newt-form.h"
+#include "nmt-newt-hacks.h"
+#include "nmt-newt-listbox.h"
+#include "nmt-newt-utils.h"
+
+G_DEFINE_TYPE (NmtNewtPopup, nmt_newt_popup, NMT_TYPE_NEWT_BUTTON)
+
+#define NMT_NEWT_POPUP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_POPUP, NmtNewtPopupPrivate))
+
+typedef struct {
+	GArray *entries;
+	int active;
+} NmtNewtPopupPrivate;
+
+enum {
+	PROP_0,
+	PROP_ACTIVE,
+	PROP_ACTIVE_ID,
+
+	LAST_PROP
+};
+
+/**
+ * NmtNewtPopupEntry:
+ * @label: the user-visible label for the entry
+ * @id: the internal ID of the entry
+ *
+ * A single entry in a pop-up menu.
+ */
+
+/**
+ * nmt_newt_popup_new:
+ * @entries: an array of #NmtNewtPopupEntry, terminated by an
+ *   entry with a %NULL label
+ *
+ * Creates a new #NmtNewtPopup with the given entries.
+ *
+ * Returns: a new #NmtNewtPopup
+ */
+NmtNewtWidget *
+nmt_newt_popup_new (NmtNewtPopupEntry *entries)
+{
+	NmtNewtWidget *widget;
+	NmtNewtPopupPrivate *priv;
+	int i;
+
+	widget = g_object_new (NMT_TYPE_NEWT_POPUP, NULL);
+	priv = NMT_NEWT_POPUP_GET_PRIVATE (widget);
+
+	for (i = 0; entries[i].label; i++) {
+		NmtNewtPopupEntry entry;
+
+		entry.label = nmt_newt_locale_from_utf8 (_(entries[i].label));
+		entry.id = g_strdup (entries[i].id);
+		g_array_append_val (priv->entries, entry);
+	}
+
+	return widget;
+}
+
+static void
+popup_entry_clear_func (NmtNewtPopupEntry *entry)
+{
+	g_free (entry->label);
+	g_free (entry->id);
+}
+
+static void
+nmt_newt_popup_init (NmtNewtPopup *popup)
+{
+	NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (popup);
+
+	priv->entries = g_array_sized_new (FALSE, FALSE, sizeof (NmtNewtPopupEntry), 10);
+	g_array_set_clear_func (priv->entries, (GDestroyNotify) popup_entry_clear_func);
+}
+
+static void
+nmt_newt_popup_finalize (GObject *object)
+{
+	NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (object);
+
+	g_array_unref (priv->entries);
+
+	G_OBJECT_CLASS (nmt_newt_popup_parent_class)->finalize (object);
+}
+
+static newtComponent
+nmt_newt_popup_build_component (NmtNewtComponent *component,
+                                gboolean          sensitive)
+{
+	NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (component);
+	NmtNewtPopupEntry *entries = (NmtNewtPopupEntry *)priv->entries->data;
+
+	nmt_newt_button_set_label (NMT_NEWT_BUTTON (component),
+	                           entries[priv->active].label);
+	return NMT_NEWT_COMPONENT_CLASS (nmt_newt_popup_parent_class)->
+		build_component (component, sensitive);
+}
+
+static void
+nmt_newt_popup_activated (NmtNewtWidget *widget)
+{
+	NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (widget);
+	NmtNewtPopupEntry *entries = (NmtNewtPopupEntry *)priv->entries->data;
+	NmtNewtForm *form;
+	NmtNewtWidget *listbox, *ret;
+	int button_x, button_y;
+	int window_x, window_y;
+	int list_w, list_h;
+	int i, active;
+
+	listbox = nmt_newt_listbox_new (priv->entries->len, 0);
+	nmt_newt_widget_set_exit_on_activate (listbox, TRUE);
+	for (i = 0; i < priv->entries->len; i++)
+		nmt_newt_listbox_append (NMT_NEWT_LISTBOX (listbox), entries[i].label, NULL);
+	nmt_newt_listbox_set_active (NMT_NEWT_LISTBOX (listbox), priv->active);
+
+	nmt_newt_widget_size_request (listbox, &list_w, &list_h);
+	newtComponentGetPosition (nmt_newt_component_get_component (NMT_NEWT_COMPONENT (widget)),
+	                          &button_x, &button_y);
+	window_x = button_x + 4;
+	window_y = button_y + 2 - priv->active;
+
+	form = g_object_new (NMT_TYPE_NEWT_FORM,
+	                     "x", window_x,
+	                     "y", window_y,
+	                     "width", list_w,
+	                     "height", list_h,
+	                     "padding", 0,
+	                     "escape-exits", TRUE,
+	                     NULL);
+	nmt_newt_form_set_content (form, listbox);
+
+	ret = nmt_newt_form_run_sync (form);
+	if (ret == listbox)
+		active = nmt_newt_listbox_get_active (NMT_NEWT_LISTBOX (listbox));
+	else
+		active = priv->active;
+
+	g_object_unref (form);
+
+	if (active != priv->active) {
+		priv->active = active;
+		g_object_notify (G_OBJECT (widget), "active");
+		g_object_notify (G_OBJECT (widget), "active-id");
+		nmt_newt_widget_needs_rebuild (widget);
+	}
+
+	NMT_NEWT_WIDGET_CLASS (nmt_newt_popup_parent_class)->activated (widget);
+}
+
+/**
+ * nmt_newt_popup_get_active:
+ * @popup: a #NmtNewtPopup
+ *
+ * Gets the index of the active entry in @popup.
+ *
+ * Returns: the index of the active entry in @popup.
+ */
+int
+nmt_newt_popup_get_active (NmtNewtPopup *popup)
+{
+	NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (popup);
+
+	return priv->active;
+}
+
+/**
+ * nmt_newt_popup_set_active:
+ * @popup: a #NmtNewtPopup
+ * @active: the index of the new active entry
+ *
+ * Sets the active entry in @popup.
+ */
+void
+nmt_newt_popup_set_active (NmtNewtPopup *popup,
+                           int           active)
+{
+	NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (popup);
+
+	active = CLAMP (active, 0, priv->entries->len - 1);
+
+	if (active != priv->active) {
+		priv->active = active;
+		g_object_notify (G_OBJECT (popup), "active");
+		g_object_notify (G_OBJECT (popup), "active-id");
+	}
+}
+
+/**
+ * nmt_newt_popup_get_active_id:
+ * @popup: a #NmtNewtPopup
+ *
+ * Gets the textual ID of the active entry in @popup.
+ *
+ * Returns: the ID of the active entry in @popup.
+ */
+const char *
+nmt_newt_popup_get_active_id (NmtNewtPopup *popup)
+{
+	NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (popup);
+	NmtNewtPopupEntry *entries = (NmtNewtPopupEntry *)priv->entries->data;
+
+	return entries[priv->active].id;
+}
+
+/**
+ * nmt_newt_popup_set_active_id:
+ * @popup: a #NmtNewtPopup
+ * @active_id: the ID of the new active entry
+ *
+ * Sets the active entry in @popup.
+ */
+void
+nmt_newt_popup_set_active_id (NmtNewtPopup *popup,
+                              const char   *active_id)
+{
+	NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (popup);
+	NmtNewtPopupEntry *entries = (NmtNewtPopupEntry *)priv->entries->data;
+	int i;
+
+	for (i = 0; i < priv->entries->len; i++) {
+		if (!g_strcmp0 (active_id, entries[i].id)) {
+			nmt_newt_popup_set_active (popup, i);
+			return;
+		}
+	}
+}
+
+static void
+nmt_newt_popup_set_property (GObject      *object,
+                             guint         prop_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+	NmtNewtPopup *popup = NMT_NEWT_POPUP (object);
+
+	switch (prop_id) {
+	case PROP_ACTIVE:
+		nmt_newt_popup_set_active (popup, g_value_get_uint (value));
+		break;
+	case PROP_ACTIVE_ID:
+		nmt_newt_popup_set_active_id (popup, g_value_get_string (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_popup_get_property (GObject    *object,
+                             guint       prop_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+	NmtNewtPopup *popup = NMT_NEWT_POPUP (object);
+
+	switch (prop_id) {
+	case PROP_ACTIVE:
+		g_value_set_uint (value, nmt_newt_popup_get_active (popup));
+		break;
+	case PROP_ACTIVE_ID:
+		g_value_set_string (value, nmt_newt_popup_get_active_id (popup));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_popup_class_init (NmtNewtPopupClass *popup_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (popup_class);
+	NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (popup_class);
+	NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (popup_class);
+
+	g_type_class_add_private (popup_class, sizeof (NmtNewtPopupPrivate));
+
+	/* virtual methods */
+	object_class->set_property = nmt_newt_popup_set_property;
+	object_class->get_property = nmt_newt_popup_get_property;
+	object_class->finalize     = nmt_newt_popup_finalize;
+
+	widget_class->activated = nmt_newt_popup_activated;
+
+	component_class->build_component = nmt_newt_popup_build_component;
+
+	/**
+	 * NmtNewtPopup:active:
+	 *
+	 * The index of the currently-active entry.
+	 */
+	g_object_class_install_property (object_class, PROP_ACTIVE,
+	                                 g_param_spec_uint ("active", "", "",
+	                                                   0, G_MAXUINT, 0,
+	                                                   G_PARAM_READWRITE |
+	                                                   G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtPopup:active-id:
+	 *
+	 * The textual ID of the currently-active entry.
+	 */
+	g_object_class_install_property (object_class, PROP_ACTIVE_ID,
+	                                 g_param_spec_string ("active-id", "", "",
+	                                                      NULL,
+	                                                      G_PARAM_READWRITE |
+	                                                      G_PARAM_STATIC_STRINGS));
+}
diff --git a/tui/newt/nmt-newt-popup.h b/tui/newt/nmt-newt-popup.h
new file mode 100644
index 00000000..643ea2d8
--- /dev/null
+++ b/tui/newt/nmt-newt-popup.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_POPUP_H
+#define NMT_NEWT_POPUP_H
+
+#include "nmt-newt-button.h"
+
+G_BEGIN_DECLS
+
+#define NMT_TYPE_NEWT_POPUP            (nmt_newt_popup_get_type ())
+#define NMT_NEWT_POPUP(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_POPUP, NmtNewtPopup))
+#define NMT_NEWT_POPUP_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_POPUP, NmtNewtPopupClass))
+#define NMT_IS_NEWT_POPUP(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_POPUP))
+#define NMT_IS_NEWT_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_POPUP))
+#define NMT_NEWT_POPUP_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_POPUP, NmtNewtPopupClass))
+
+struct _NmtNewtPopup {
+	NmtNewtButton parent;
+
+};
+
+typedef struct {
+	NmtNewtButtonClass parent;
+
+} NmtNewtPopupClass;
+
+GType nmt_newt_popup_get_type (void);
+
+typedef struct {
+	char *label;
+	char *id;
+} NmtNewtPopupEntry;
+
+NmtNewtWidget *nmt_newt_popup_new           (NmtNewtPopupEntry *entries);
+
+int            nmt_newt_popup_get_active    (NmtNewtPopup      *popup);
+void           nmt_newt_popup_set_active    (NmtNewtPopup      *popup,
+                                             int                active);
+
+const char    *nmt_newt_popup_get_active_id (NmtNewtPopup      *popup);
+void           nmt_newt_popup_set_active_id (NmtNewtPopup      *popup,
+                                             const char        *active_id);
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_POPUP_H */
diff --git a/tui/newt/nmt-newt-section.c b/tui/newt/nmt-newt-section.c
new file mode 100644
index 00000000..094b41b7
--- /dev/null
+++ b/tui/newt/nmt-newt-section.c
@@ -0,0 +1,408 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-section
+ * @short_description: A collapsible section
+ *
+ * #NmtNewtSection is a container with two children; the header and
+ * the body. The header is always visible, but the body is only
+ * visible when the container is #NmtNewtSection:open.
+ *
+ * Note that there is no default way to open and close an
+ * #NmtNewtSection. You need to implement this yourself. (Eg, by
+ * binding the #NmtToggleButton:active property of an #NmtToggleButton
+ * in the section's header to the section's #NmtNewtSection:open
+ * property.)
+ *
+ * In addition to the header and body, the #NmtNewtSection also draws
+ * a border along the left side, indicating the extent of the section.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "nmt-newt-section.h"
+#include "nmt-newt-grid.h"
+#include "nmt-newt-label.h"
+#include "nmt-newt-utils.h"
+
+G_DEFINE_TYPE (NmtNewtSection, nmt_newt_section, NMT_TYPE_NEWT_CONTAINER)
+
+#define NMT_NEWT_SECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_SECTION, NmtNewtSectionPrivate))
+
+typedef struct {
+	NmtNewtWidget *header;
+	int hheight_req, hwidth_req;
+
+	NmtNewtWidget *body;
+	int bheight_req, bwidth_req;
+
+	NmtNewtWidget *border_grid;
+	NmtNewtWidget *border_open_label;
+	NmtNewtWidget *border_closed_label;
+	NmtNewtWidget *border_end_label;
+	GPtrArray *border_line_labels;
+
+	gboolean open;
+} NmtNewtSectionPrivate;
+
+static char *closed_glyph, *open_glyph, *line_glyph, *end_glyph;
+
+enum {
+	PROP_0,
+
+	PROP_OPEN,
+
+	LAST_PROP
+};
+
+/**
+ * nmt_newt_section_new:
+ *
+ * Creates a new #NmtNewtSection
+ *
+ * Returns: a new #NmtNewtSection
+ */
+NmtNewtWidget *
+nmt_newt_section_new (void)
+{
+	return g_object_new (NMT_TYPE_NEWT_SECTION,
+	                     NULL);
+}
+
+static void
+nmt_newt_section_init (NmtNewtSection *section)
+{
+	NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (section);
+	NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_newt_section_parent_class);
+
+	priv->border_grid = nmt_newt_grid_new ();
+	parent_class->add (NMT_NEWT_CONTAINER (section), priv->border_grid);
+
+	priv->border_open_label = nmt_newt_label_new (open_glyph);
+	nmt_newt_widget_set_visible (priv->border_open_label, FALSE);
+	nmt_newt_grid_add (NMT_NEWT_GRID (priv->border_grid), priv->border_open_label, 0, 0);
+
+	priv->border_closed_label = nmt_newt_label_new (closed_glyph);
+	nmt_newt_grid_add (NMT_NEWT_GRID (priv->border_grid), priv->border_closed_label, 0, 0);
+
+	priv->border_end_label = nmt_newt_label_new (end_glyph);
+	nmt_newt_widget_set_visible (priv->border_open_label, FALSE);
+	nmt_newt_grid_add (NMT_NEWT_GRID (priv->border_grid), priv->border_end_label, 0, 1);
+
+	priv->border_line_labels = g_ptr_array_new ();
+}
+
+static void
+nmt_newt_section_finalize (GObject *object)
+{
+	NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (object);
+
+	g_ptr_array_unref (priv->border_line_labels);
+
+	G_OBJECT_CLASS (nmt_newt_section_parent_class)->finalize (object);
+}
+
+/**
+ * nmt_newt_section_set_header:
+ * @section: an #NmtNewtSection
+ * @header: the header widget
+ *
+ * Sets @section's header widget.
+ */
+void
+nmt_newt_section_set_header (NmtNewtSection *section,
+                             NmtNewtWidget  *header)
+{
+	NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (section);
+	NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_newt_section_parent_class);
+	NmtNewtContainer *container = NMT_NEWT_CONTAINER (section);
+
+	if (priv->header)
+		parent_class->remove (container, priv->header);
+	priv->header = header;
+	parent_class->add (container, header);
+}
+
+/**
+ * nmt_newt_section_get_header:
+ * @section: an #NmtNewtSection
+ *
+ * Gets @section's header widget.
+ *
+ * Returns: @section's header widget.
+ */
+NmtNewtWidget *
+nmt_newt_section_get_header (NmtNewtSection *section)
+{
+	NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (section);
+
+	return priv->header;
+}
+
+/**
+ * nmt_newt_section_set_body:
+ * @section: an #NmtNewtSection
+ * @body: the body widget
+ *
+ * Sets @section's body widget.
+ */
+void
+nmt_newt_section_set_body (NmtNewtSection *section,
+                           NmtNewtWidget  *body)
+{
+	NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (section);
+	NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_newt_section_parent_class);
+	NmtNewtContainer *container = NMT_NEWT_CONTAINER (section);
+
+	if (priv->body)
+		parent_class->remove (container, priv->body);
+	priv->body = body;
+	parent_class->add (container, body);
+}
+
+/**
+ * nmt_newt_section_get_body:
+ * @section: an #NmtNewtSection
+ *
+ * Gets @section's body widget.
+ *
+ * Returns: @section's body widget.
+ */
+NmtNewtWidget *
+nmt_newt_section_get_body (NmtNewtSection *section)
+{
+	NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (section);
+
+	return priv->body;
+}
+
+static void
+nmt_newt_section_remove (NmtNewtContainer *container,
+                         NmtNewtWidget    *widget)
+{
+	NmtNewtSection *section = NMT_NEWT_SECTION (container);
+	NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (section);
+	NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_newt_section_parent_class);
+
+	if (widget == priv->header)
+		priv->header = NULL;
+	else if (widget == priv->body)
+		priv->body = NULL;
+	else if (widget == priv->border_grid)
+		priv->border_grid = NULL;
+
+	parent_class->remove (container, widget);
+}
+
+static newtComponent *
+nmt_newt_section_get_components (NmtNewtWidget *widget)
+{
+	NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (widget);
+	newtComponent *child_cos;
+	GPtrArray *cos;
+	int i;
+
+	g_return_val_if_fail (priv->header != NULL && priv->body != NULL, NULL);
+
+	cos = g_ptr_array_new ();
+
+	child_cos = nmt_newt_widget_get_components (priv->border_grid);
+	for (i = 0; child_cos[i]; i++)
+		g_ptr_array_add (cos, child_cos[i]);
+	g_free (child_cos);
+
+	child_cos = nmt_newt_widget_get_components (priv->header);
+	for (i = 0; child_cos[i]; i++)
+		g_ptr_array_add (cos, child_cos[i]);
+	g_free (child_cos);
+
+	if (priv->open) {
+		child_cos = nmt_newt_widget_get_components (priv->body);
+		for (i = 0; child_cos[i]; i++)
+			g_ptr_array_add (cos, child_cos[i]);
+		g_free (child_cos);
+	}
+
+	g_ptr_array_add (cos, NULL);
+	return (newtComponent *) g_ptr_array_free (cos, FALSE);
+}
+
+static void
+nmt_newt_section_size_request (NmtNewtWidget *widget,
+                               int           *width,
+                               int           *height)
+{
+	NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (widget);
+	int border_width, border_height;
+
+	g_return_if_fail (priv->header != NULL && priv->body != NULL);
+
+	nmt_newt_widget_size_request (priv->border_grid, &border_width, &border_height);
+	nmt_newt_widget_size_request (priv->header, &priv->hwidth_req, &priv->hheight_req);
+	nmt_newt_widget_size_request (priv->body, &priv->bwidth_req, &priv->bheight_req);
+
+	*width = MAX (priv->hwidth_req, priv->bwidth_req) + 2;
+	*height = priv->open ? priv->hheight_req + priv->bheight_req + 1 : priv->hheight_req;
+}
+
+static void
+adjust_border_for_allocation (NmtNewtSectionPrivate *priv,
+                              int                    height)
+{
+	int i;
+
+	/* We have to use a series of one-line labels rather than a multi-line
+	 * textbox, because newt will hide any component that's partially offscreen,
+	 * but we want the on-screen portion of the border to show even if part of
+	 * it is offscreen.
+	 */
+
+	if (height == 1) {
+		nmt_newt_widget_set_visible (priv->border_closed_label, TRUE);
+		nmt_newt_widget_set_visible (priv->border_open_label, FALSE);
+		for (i = 0; i < priv->border_line_labels->len; i++)
+			nmt_newt_widget_set_visible (priv->border_line_labels->pdata[i], FALSE);
+		nmt_newt_widget_set_visible (priv->border_end_label, FALSE);
+	} else {
+		nmt_newt_widget_set_visible (priv->border_closed_label, FALSE);
+		nmt_newt_widget_set_visible (priv->border_open_label, TRUE);
+		for (i = 0; i < height - 2; i++) {
+			if (i >= priv->border_line_labels->len) {
+				NmtNewtWidget *label;
+
+				label = nmt_newt_label_new (line_glyph);
+				g_ptr_array_add (priv->border_line_labels, label);
+				nmt_newt_grid_add (NMT_NEWT_GRID (priv->border_grid), label, 0, i + 1);
+			} else 
+				nmt_newt_widget_set_visible (priv->border_line_labels->pdata[i], TRUE);
+		}
+		nmt_newt_widget_set_visible (priv->border_end_label, TRUE);
+		nmt_newt_grid_move (NMT_NEWT_GRID (priv->border_grid), priv->border_end_label, 0, height - 1);
+	}
+}
+
+static void
+nmt_newt_section_size_allocate (NmtNewtWidget *widget,
+                                int            x,
+                                int            y,
+                                int            width,
+                                int            height)
+{
+	NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (widget);
+
+	adjust_border_for_allocation (priv, height);
+
+	nmt_newt_widget_size_allocate (priv->border_grid, x, y, 1, height);
+	nmt_newt_widget_size_allocate (priv->header, x + 2, y, width, priv->hheight_req);
+	if (priv->open) {
+		nmt_newt_widget_size_allocate (priv->body, x + 2, y + priv->hheight_req,
+		                               width, height - priv->hheight_req);
+	}
+}
+
+static void
+nmt_newt_section_set_property (GObject      *object,
+                               guint         prop_id,
+                               const GValue *value,
+                               GParamSpec   *pspec)
+{
+	NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_OPEN:
+		priv->open = g_value_get_boolean (value);
+		nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (object));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_section_get_property (GObject    *object,
+                               guint       prop_id,
+                               GValue     *value,
+                               GParamSpec *pspec)
+{
+	NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_OPEN:
+		g_value_set_boolean (value, priv->open);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_section_class_init (NmtNewtSectionClass *section_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (section_class);
+	NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (section_class);
+	NmtNewtContainerClass *container_class = NMT_NEWT_CONTAINER_CLASS (section_class);
+
+	g_type_class_add_private (section_class, sizeof (NmtNewtSectionPrivate));
+
+	/* virtual methods */
+	object_class->set_property = nmt_newt_section_set_property;
+	object_class->get_property = nmt_newt_section_get_property;
+	object_class->finalize     = nmt_newt_section_finalize;
+
+	widget_class->get_components = nmt_newt_section_get_components;
+	widget_class->size_request   = nmt_newt_section_size_request;
+	widget_class->size_allocate  = nmt_newt_section_size_allocate;
+
+	container_class->remove = nmt_newt_section_remove;
+
+	/* properties */
+
+	/**
+	 * NmtNewtSection:open:
+	 *
+	 * %TRUE if the section is open (ie, its body is visible), %FALSE
+	 * if not.
+	 */
+	g_object_class_install_property (object_class, PROP_OPEN,
+	                                 g_param_spec_boolean ("open", "", "",
+	                                                       FALSE,
+	                                                       G_PARAM_READWRITE |
+	                                                       G_PARAM_STATIC_STRINGS));
+
+	/* globals */
+	closed_glyph = nmt_newt_locale_from_utf8 ("\342\225\220"); /* ═ */
+	open_glyph   = nmt_newt_locale_from_utf8 ("\342\225\244"); /* ╤ */
+	line_glyph   = nmt_newt_locale_from_utf8 ("\342\224\202"); /* │ */
+	end_glyph    = nmt_newt_locale_from_utf8 ("\342\224\224"); /* └ */
+	if (!closed_glyph || !open_glyph || !line_glyph || !end_glyph) {
+		g_clear_pointer (&closed_glyph, g_free);
+		g_clear_pointer (&open_glyph, g_free);
+		g_clear_pointer (&line_glyph, g_free);
+		g_clear_pointer (&end_glyph, g_free);
+
+		closed_glyph = g_strdup ("-");
+		open_glyph   = g_strdup ("+");
+		line_glyph   = g_strdup ("|");
+		end_glyph    = g_strdup ("\\");
+	}
+}
diff --git a/tui/newt/nmt-newt-section.h b/tui/newt/nmt-newt-section.h
new file mode 100644
index 00000000..a943ba20
--- /dev/null
+++ b/tui/newt/nmt-newt-section.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_SECTION_H
+#define NMT_NEWT_SECTION_H
+
+#include "nmt-newt-container.h"
+
+G_BEGIN_DECLS
+
+#define NMT_TYPE_NEWT_SECTION            (nmt_newt_section_get_type ())
+#define NMT_NEWT_SECTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_SECTION, NmtNewtSection))
+#define NMT_NEWT_SECTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_SECTION, NmtNewtSectionClass))
+#define NMT_IS_NEWT_SECTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_SECTION))
+#define NMT_IS_NEWT_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_SECTION))
+#define NMT_NEWT_SECTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_SECTION, NmtNewtSectionClass))
+
+struct _NmtNewtSection {
+	NmtNewtContainer parent;
+
+};
+
+typedef struct {
+	NmtNewtContainerClass parent;
+
+} NmtNewtSectionClass;
+
+GType nmt_newt_section_get_type (void);
+
+NmtNewtWidget *nmt_newt_section_new (void);
+
+void           nmt_newt_section_set_header (NmtNewtSection *section,
+                                            NmtNewtWidget  *header);
+NmtNewtWidget *nmt_newt_section_get_header (NmtNewtSection *section);
+
+void           nmt_newt_section_set_body   (NmtNewtSection *section,
+                                            NmtNewtWidget  *body);
+NmtNewtWidget *nmt_newt_section_get_body   (NmtNewtSection *section);
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_SECTION_H */
diff --git a/tui/newt/nmt-newt-separator.c b/tui/newt/nmt-newt-separator.c
new file mode 100644
index 00000000..07deb1af
--- /dev/null
+++ b/tui/newt/nmt-newt-separator.c
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-separator
+ * @short_description: Separator
+ *
+ * #NmtNewtSeparator is just a blank label, which is used in a few places
+ * where a widget is needed but none is desired, or to add blank space
+ * between widgets in containers that don't implement padding.
+ */
+
+#include "config.h"
+
+#include "nmt-newt-separator.h"
+
+G_DEFINE_TYPE (NmtNewtSeparator, nmt_newt_separator, NMT_TYPE_NEWT_COMPONENT)
+
+/**
+ * nmt_newt_separator_new:
+ *
+ * Creates a new #NmtNewtSeparator.
+ *
+ * Returns: a new #NmtNewtSeparator
+ */
+NmtNewtWidget *
+nmt_newt_separator_new (void)
+{
+	return g_object_new (NMT_TYPE_NEWT_SEPARATOR, NULL);
+}
+
+static void
+nmt_newt_separator_init (NmtNewtSeparator *separator)
+{
+}
+
+static newtComponent
+nmt_newt_separator_build_component (NmtNewtComponent *component,
+                                    gboolean          sensitive)
+{
+	return newtLabel (-1, -1, " ");
+}
+
+static void
+nmt_newt_separator_class_init (NmtNewtSeparatorClass *separator_class)
+{
+	NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (separator_class);
+
+	/* virtual methods */
+	component_class->build_component = nmt_newt_separator_build_component;
+}
diff --git a/tui/newt/nmt-newt-separator.h b/tui/newt/nmt-newt-separator.h
new file mode 100644
index 00000000..3f4183d5
--- /dev/null
+++ b/tui/newt/nmt-newt-separator.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_SEPARATOR_H
+#define NMT_NEWT_SEPARATOR_H
+
+#include "nmt-newt-component.h"
+
+G_BEGIN_DECLS
+
+#define NMT_TYPE_NEWT_SEPARATOR            (nmt_newt_separator_get_type ())
+#define NMT_NEWT_SEPARATOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_SEPARATOR, NmtNewtSeparator))
+#define NMT_NEWT_SEPARATOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_SEPARATOR, NmtNewtSeparatorClass))
+#define NMT_IS_NEWT_SEPARATOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_SEPARATOR))
+#define NMT_IS_NEWT_SEPARATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_SEPARATOR))
+#define NMT_NEWT_SEPARATOR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_SEPARATOR, NmtNewtSeparatorClass))
+
+struct _NmtNewtSeparator {
+  NmtNewtComponent parent;
+
+};
+
+typedef struct {
+  NmtNewtComponentClass parent;
+
+} NmtNewtSeparatorClass;
+
+GType nmt_newt_separator_get_type (void);
+
+NmtNewtWidget *nmt_newt_separator_new (void);
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_SEPARATOR_H */
diff --git a/tui/newt/nmt-newt-stack.c b/tui/newt/nmt-newt-stack.c
new file mode 100644
index 00000000..1b31d58f
--- /dev/null
+++ b/tui/newt/nmt-newt-stack.c
@@ -0,0 +1,366 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-stack
+ * @short_description: A stack of alternative widgets
+ *
+ * #NmtNewtStack implements a stack of widgets, only one of which is
+ * visible at any time.
+ *
+ * The height and width of the widget is determined only by its
+ * visible child. Likewise, the widget's #NmtNewtWidget:valid is
+ * determined only by the validity of its visible child, not its other
+ * children.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "nmt-newt-stack.h"
+
+G_DEFINE_TYPE (NmtNewtStack, nmt_newt_stack, NMT_TYPE_NEWT_CONTAINER)
+
+#define NMT_NEWT_STACK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_STACK, NmtNewtStackPrivate))
+
+typedef struct {
+	GPtrArray *children;
+	GPtrArray *ids;
+
+	guint active;
+} NmtNewtStackPrivate;
+
+enum {
+	PROP_0,
+	PROP_ACTIVE,
+	PROP_ACTIVE_ID,
+
+	LAST_PROP
+};
+
+/**
+ * nmt_newt_stack_new:
+ *
+ * Creates a new #NmtNewtStack
+ *
+ * Returns: a new #NmtNewtStack
+ */
+NmtNewtWidget *
+nmt_newt_stack_new (void)
+{
+	return g_object_new (NMT_TYPE_NEWT_STACK, NULL);
+}
+
+static void
+nmt_newt_stack_init (NmtNewtStack *stack)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack);
+
+	priv->children = g_ptr_array_new ();
+	priv->ids = g_ptr_array_new_with_free_func (g_free);
+}
+
+static void
+nmt_newt_stack_finalize (GObject *object)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (object);
+
+	g_ptr_array_unref (priv->children);
+	g_ptr_array_unref (priv->ids);
+
+	G_OBJECT_CLASS (nmt_newt_stack_parent_class)->finalize (object);
+}
+
+static newtComponent *
+nmt_newt_stack_get_components (NmtNewtWidget *widget)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (widget);
+
+	if (priv->active > priv->children->len)
+		return NULL;
+
+	return nmt_newt_widget_get_components (priv->children->pdata[priv->active]);
+}
+
+static void
+nmt_newt_stack_size_request (NmtNewtWidget *widget,
+                             int           *width,
+                             int           *height)
+{
+	NmtNewtStack *stack = NMT_NEWT_STACK (widget);
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack);
+	int i, child_width, child_height;
+
+	if (priv->active > priv->children->len) {
+		*width = *height = 0;
+		return;
+	}
+
+	/* We size-request all pages so that embedded NmtPageGrids will
+	 * participate in their size-grouping (so that switching pages
+	 * won't result in the column widths changing).
+	 */
+	for (i = 0; i < priv->children->len; i++) {
+		nmt_newt_widget_size_request (priv->children->pdata[i], &child_width, &child_height);
+		if (i == priv->active) {
+			*width = child_width;
+			*height = child_height;
+		}
+	}
+}
+
+static void
+nmt_newt_stack_size_allocate (NmtNewtWidget *widget,
+                              int            x,
+                              int            y,
+                              int            width,
+                              int            height)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (widget);
+
+	if (priv->active > priv->children->len)
+		return;
+
+	nmt_newt_widget_size_allocate (priv->children->pdata[priv->active], x, y, width, height);
+}
+
+/**
+ * nmt_newt_stack_add:
+ * @stack: an #NmtNewtStack
+ * @id: the ID for the new page
+ * @widget: the widget to add
+ *
+ * Adds @widget to @stack with the given @id.
+ */
+void
+nmt_newt_stack_add (NmtNewtStack  *stack,
+                    const char    *id,
+                    NmtNewtWidget *widget)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack);
+
+	g_ptr_array_add (priv->children, widget);
+	g_ptr_array_add (priv->ids, g_strdup (id));
+
+	NMT_NEWT_CONTAINER_CLASS (nmt_newt_stack_parent_class)->add (NMT_NEWT_CONTAINER (stack), widget);
+}
+
+static void
+nmt_newt_stack_remove (NmtNewtContainer *container,
+                       NmtNewtWidget    *widget)
+{
+	NmtNewtStack *stack = NMT_NEWT_STACK (container);
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack);
+	int i;
+
+	NMT_NEWT_CONTAINER_CLASS (nmt_newt_stack_parent_class)->remove (container, widget);
+
+	for (i = 0; i < priv->children->len; i++) {
+		if (priv->children->pdata[i] == widget) {
+			g_ptr_array_remove_index (priv->children, i);
+			g_ptr_array_remove_index (priv->ids, i);
+			return;
+		}
+	}
+}
+
+static void
+nmt_newt_stack_child_validity_changed (NmtNewtContainer *container,
+                                       NmtNewtWidget    *widget)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (container);
+
+	if (priv->active > priv->children->len)
+		return;
+
+	if (priv->children->pdata[priv->active] == (gpointer) widget) {
+		NMT_NEWT_CONTAINER_CLASS (nmt_newt_stack_parent_class)->
+			child_validity_changed (container, widget);
+	}
+}
+
+/**
+ * nmt_newt_stack_set_active:
+ * @stack: an #NmtNewtStack
+ * @active: the index of the new active page
+ *
+ * Sets the active page on @stack to @active.
+ */
+void
+nmt_newt_stack_set_active (NmtNewtStack *stack,
+                           guint         active)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack);
+
+	if (priv->active == active)
+		return;
+
+	priv->active = active;
+	g_object_notify (G_OBJECT (stack), "active");
+	g_object_notify (G_OBJECT (stack), "active-id");
+	nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (stack));
+}
+
+/**
+ * nmt_newt_stack_get_active:
+ * @stack: an #NmtNewtStack
+ *
+ * Gets the index of the active page on @stack
+ *
+ * Returns: the index of the active page on @stack
+ */
+guint
+nmt_newt_stack_get_active (NmtNewtStack *stack)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack);
+
+	return priv->active;
+}
+
+/**
+ * nmt_newt_stack_set_active_id:
+ * @stack: an #NmtNewtStack
+ * @active_id: the ID of the new active page
+ *
+ * Sets the active page on @stack to @active_id.
+ */
+void
+nmt_newt_stack_set_active_id (NmtNewtStack *stack,
+                              const char   *id)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack);
+	int i;
+
+	if (!g_strcmp0 (priv->ids->pdata[priv->active], id))
+		return;
+
+	for (i = 0; i < priv->ids->len; i++) {
+		if (!g_strcmp0 (priv->ids->pdata[i], id)) {
+			priv->active = i;
+			g_object_notify (G_OBJECT (stack), "active");
+			g_object_notify (G_OBJECT (stack), "active-id");
+			nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (stack));
+			return;
+		}
+	}
+}
+
+/**
+ * nmt_newt_stack_get_active_id:
+ * @stack: an #NmtNewtStack
+ *
+ * Gets the ID of the active page on @stack
+ *
+ * Returns: the ID of the active page on @stack
+ */
+const char *
+nmt_newt_stack_get_active_id (NmtNewtStack *stack)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack);
+
+	if (priv->active > priv->children->len)
+		return NULL;
+
+	return priv->ids->pdata[priv->active];
+}
+
+static void
+nmt_newt_stack_set_property (GObject      *object,
+                             guint         prop_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+	NmtNewtStack *stack = NMT_NEWT_STACK (object);
+
+	switch (prop_id) {
+	case PROP_ACTIVE:
+		nmt_newt_stack_set_active (stack, g_value_get_uint (value));
+		break;
+	case PROP_ACTIVE_ID:
+		nmt_newt_stack_set_active_id (stack, g_value_get_string (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_stack_get_property (GObject    *object,
+                             guint       prop_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+	NmtNewtStack *stack = NMT_NEWT_STACK (object);
+
+	switch (prop_id) {
+	case PROP_ACTIVE:
+		g_value_set_uint (value, nmt_newt_stack_get_active (stack));
+		break;
+	case PROP_ACTIVE_ID:
+		g_value_set_string (value, nmt_newt_stack_get_active_id (stack));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_stack_class_init (NmtNewtStackClass *stack_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (stack_class);
+	NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (stack_class);
+	NmtNewtContainerClass *container_class = NMT_NEWT_CONTAINER_CLASS (stack_class);
+
+	g_type_class_add_private (stack_class, sizeof (NmtNewtStackPrivate));
+
+	/* virtual methods */
+	object_class->set_property = nmt_newt_stack_set_property;
+	object_class->get_property = nmt_newt_stack_get_property;
+	object_class->finalize = nmt_newt_stack_finalize;
+
+	widget_class->get_components = nmt_newt_stack_get_components;
+	widget_class->size_request   = nmt_newt_stack_size_request;
+	widget_class->size_allocate  = nmt_newt_stack_size_allocate;
+
+	container_class->remove = nmt_newt_stack_remove;
+	container_class->child_validity_changed = nmt_newt_stack_child_validity_changed;
+
+	/**
+	 * NmtNewtStack:active:
+	 *
+	 * The index of the active page
+	 */
+	g_object_class_install_property (object_class, PROP_ACTIVE,
+	                                 g_param_spec_uint ("active", "", "",
+	                                                    0, G_MAXUINT, 0,
+	                                                    G_PARAM_READWRITE |
+	                                                    G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtStack:active-id:
+	 *
+	 * The ID of the active page
+	 */
+	g_object_class_install_property (object_class, PROP_ACTIVE_ID,
+	                                 g_param_spec_string ("active-id", "", "",
+	                                                      NULL,
+	                                                      G_PARAM_READWRITE |
+	                                                      G_PARAM_STATIC_STRINGS));
+}
diff --git a/tui/newt/nmt-newt-stack.h b/tui/newt/nmt-newt-stack.h
new file mode 100644
index 00000000..09afe4ba
--- /dev/null
+++ b/tui/newt/nmt-newt-stack.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_STACK_H
+#define NMT_NEWT_STACK_H
+
+#include "nmt-newt-container.h"
+
+G_BEGIN_DECLS
+
+#define NMT_TYPE_NEWT_STACK            (nmt_newt_stack_get_type ())
+#define NMT_NEWT_STACK(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_STACK, NmtNewtStack))
+#define NMT_NEWT_STACK_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_STACK, NmtNewtStackClass))
+#define NMT_IS_NEWT_STACK(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_STACK))
+#define NMT_IS_NEWT_STACK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_STACK))
+#define NMT_NEWT_STACK_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_STACK, NmtNewtStackClass))
+
+struct _NmtNewtStack {
+	NmtNewtContainer parent;
+
+};
+
+typedef struct {
+	NmtNewtContainerClass parent;
+
+} NmtNewtStackClass;
+
+GType nmt_newt_stack_get_type (void);
+
+NmtNewtWidget *nmt_newt_stack_new           (void);
+
+void           nmt_newt_stack_add           (NmtNewtStack  *stack,
+                                             const char    *id,
+                                             NmtNewtWidget *widget);
+
+void           nmt_newt_stack_set_active    (NmtNewtStack  *stack,
+                                             guint          active);
+guint          nmt_newt_stack_get_active    (NmtNewtStack  *stack);
+
+void           nmt_newt_stack_set_active_id (NmtNewtStack  *stack,
+                                             const char    *id);
+const char *   nmt_newt_stack_get_active_id (NmtNewtStack  *stack);
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_STACK_H */
diff --git a/tui/newt/nmt-newt-textbox.c b/tui/newt/nmt-newt-textbox.c
new file mode 100644
index 00000000..67b8b247
--- /dev/null
+++ b/tui/newt/nmt-newt-textbox.c
@@ -0,0 +1,292 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-textbox
+ * @short_description: Multi-line text box
+ *
+ * #NmtNewtTextbox implements a multi-line text, optionally with
+ * word-wrapping.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "nmt-newt-textbox.h"
+#include "nmt-newt-utils.h"
+
+G_DEFINE_TYPE (NmtNewtTextbox, nmt_newt_textbox, NMT_TYPE_NEWT_COMPONENT)
+
+#define NMT_NEWT_TEXTBOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_TEXTBOX, NmtNewtTextboxPrivate))
+
+typedef struct {
+	int wrap_width;
+	NmtNewtTextboxFlags flags;
+
+	char *text;
+	int width, height;
+} NmtNewtTextboxPrivate;
+
+enum {
+	PROP_0,
+	PROP_TEXT,
+	PROP_FLAGS,
+	PROP_WRAP_WIDTH,
+
+	LAST_PROP
+};
+
+/**
+ * NmtNewtTextboxFlags:
+ * @NMT_NEWT_TEXTBOX_SCROLLABLE: the textbox should be scollable.
+ * @NMT_NEWT_TEXTBOX_SET_BACKGROUND: the textbox should have a
+ *   white background
+ *
+ * Flags for an #NmtNewtTextbox
+ */
+
+/**
+ * nmt_newt_textbox_new:
+ * @flags: the textbox's flags
+ * @wrap_width: width in characters at which to word-wrap, or
+ *   0 to not wrap.
+ *
+ * Creates a new #NmtNewtTextbox.
+ *
+ * Returns: a new #NmtNewtTextbox
+ */
+NmtNewtWidget *
+nmt_newt_textbox_new (NmtNewtTextboxFlags flags,
+                      int                 wrap_width)
+{
+	return g_object_new (NMT_TYPE_NEWT_TEXTBOX,
+	                     "flags", flags,
+	                     "wrap-width", wrap_width,
+	                     NULL);
+}
+
+/**
+ * nmt_newt_textbox_get_text:
+ * @textbox: an #NmtNewtTextbox
+ *
+ * Gets @textbox's text
+ *
+ * Returns: @textbox's text
+ */
+void
+nmt_newt_textbox_set_text (NmtNewtTextbox *textbox,
+                           const char     *text)
+{
+	NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (textbox);
+	char **lines;
+	int i, width;
+
+	if (!text)
+		text = "";
+	if (!strcmp (priv->text, text))
+		return;
+
+	g_free (priv->text);
+	priv->text = g_strdup (text);
+
+	priv->width = priv->height = 0;
+	lines = g_strsplit (priv->text, "\n", -1);
+	for (i = 0; lines[i]; i++) {
+		width = nmt_newt_text_width (lines[i]);
+		if (width > priv->width)
+			priv->width = width;
+	}
+	g_free (lines);
+	priv->height = MIN (i, 1);
+
+	g_object_notify (G_OBJECT (textbox), "text");
+	nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (textbox));
+}
+
+/**
+ * nmt_newt_textbox_get_text:
+ * @textbox: an #NmtNewtTextbox
+ *
+ * Gets @textbox's text
+ *
+ * Returns: @textbox's text
+ */
+const char *
+nmt_newt_textbox_get_text (NmtNewtTextbox *textbox)
+{
+	NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (textbox);
+
+	return priv->text;
+}
+
+static void
+nmt_newt_textbox_init (NmtNewtTextbox *textbox)
+{
+	NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (textbox);
+
+	priv->text = g_strdup ("");
+}
+
+static void
+nmt_newt_textbox_finalize (GObject *object)
+{
+	NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (object);
+
+	g_free (priv->text);
+
+	G_OBJECT_CLASS (nmt_newt_textbox_parent_class)->finalize (object);
+}
+
+static guint
+convert_flags (NmtNewtTextboxFlags flags)
+{
+	guint newt_flags = 0;
+
+	if (flags & NMT_NEWT_TEXTBOX_SCROLLABLE)
+		newt_flags |= NEWT_FLAG_SCROLL;
+
+	return newt_flags;
+}
+
+static newtComponent
+nmt_newt_textbox_build_component (NmtNewtComponent *component,
+                                gboolean          sensitive)
+{
+	NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (component);
+	newtComponent co;
+	const char *text;
+	char *text_lc;
+
+	text = priv->text;
+	if (!*text)
+		text = "\n";
+
+	text_lc = nmt_newt_locale_from_utf8 (text);
+	if (priv->wrap_width > 0) {
+		co = newtTextboxReflowed (-1, -1, text_lc, priv->wrap_width, 0, 0, 0);
+	} else {
+		co = newtTextbox (-1, -1, priv->width, priv->height, convert_flags (priv->flags));
+		newtTextboxSetText (co, text_lc);
+	}
+	g_free (text_lc);
+
+	if (priv->flags & NMT_NEWT_TEXTBOX_SET_BACKGROUND)
+		newtTextboxSetColors (co, NMT_NEWT_COLORSET_TEXTBOX_WITH_BACKGROUND, NEWT_COLORSET_ACTTEXTBOX);
+
+	return co;
+}
+
+static void
+nmt_newt_textbox_set_property (GObject      *object,
+                               guint         prop_id,
+                               const GValue *value,
+                               GParamSpec   *pspec)
+{
+	NmtNewtTextbox *textbox = NMT_NEWT_TEXTBOX (object);
+	NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (textbox);
+
+	switch (prop_id) {
+	case PROP_TEXT:
+		nmt_newt_textbox_set_text (textbox, g_value_get_string (value));
+		break;
+	case PROP_FLAGS:
+		priv->flags = g_value_get_uint (value);
+		break;
+	case PROP_WRAP_WIDTH:
+		priv->wrap_width = g_value_get_int (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_textbox_get_property (GObject    *object,
+                               guint       prop_id,
+                               GValue     *value,
+                               GParamSpec *pspec)
+{
+	NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_TEXT:
+		g_value_set_string (value, priv->text);
+		break;
+	case PROP_FLAGS:
+		g_value_set_uint (value, priv->flags);
+		break;
+	case PROP_WRAP_WIDTH:
+		g_value_set_int (value, priv->wrap_width);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_textbox_class_init (NmtNewtTextboxClass *textbox_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (textbox_class);
+	NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (textbox_class);
+
+	g_type_class_add_private (textbox_class, sizeof (NmtNewtTextboxPrivate));
+
+	/* virtual methods */
+	object_class->set_property = nmt_newt_textbox_set_property;
+	object_class->get_property = nmt_newt_textbox_get_property;
+	object_class->finalize     = nmt_newt_textbox_finalize;
+
+	component_class->build_component = nmt_newt_textbox_build_component;
+
+	/**
+	 * NmtNewtTextbox:text:
+	 *
+	 * The textbox's text
+	 */
+	g_object_class_install_property (object_class, PROP_TEXT,
+	                                 g_param_spec_string ("text", "", "",
+	                                                      "",
+	                                                      G_PARAM_READWRITE |
+	                                                      G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtTextbox:flags:
+	 *
+	 * The textbox's flags
+	 */
+	g_object_class_install_property (object_class, PROP_FLAGS,
+	                                 g_param_spec_uint ("flags", "", "",
+	                                                    0, G_MAXUINT, 0,
+	                                                    G_PARAM_READWRITE |
+	                                                    G_PARAM_CONSTRUCT_ONLY |
+	                                                    G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtTextbox:wrap-width:
+	 *
+	 * The width in characters at which the textbox's text
+	 * will wrap, or 0 if it does not wrap.
+	 */
+	g_object_class_install_property (object_class, PROP_WRAP_WIDTH,
+	                                 g_param_spec_int ("wrap-width", "", "",
+	                                                   0, G_MAXINT, 0,
+	                                                   G_PARAM_READWRITE |
+	                                                   G_PARAM_CONSTRUCT_ONLY |
+	                                                   G_PARAM_STATIC_STRINGS));
+}
diff --git a/tui/newt/nmt-newt-textbox.h b/tui/newt/nmt-newt-textbox.h
new file mode 100644
index 00000000..b3743aea
--- /dev/null
+++ b/tui/newt/nmt-newt-textbox.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_TEXTBOX_H
+#define NMT_NEWT_TEXTBOX_H
+
+#include "nmt-newt-component.h"
+
+G_BEGIN_DECLS
+
+#define NMT_TYPE_NEWT_TEXTBOX            (nmt_newt_textbox_get_type ())
+#define NMT_NEWT_TEXTBOX(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_TEXTBOX, NmtNewtTextbox))
+#define NMT_NEWT_TEXTBOX_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_TEXTBOX, NmtNewtTextboxClass))
+#define NMT_IS_NEWT_TEXTBOX(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_TEXTBOX))
+#define NMT_IS_NEWT_TEXTBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_TEXTBOX))
+#define NMT_NEWT_TEXTBOX_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_TEXTBOX, NmtNewtTextboxClass))
+
+struct _NmtNewtTextbox {
+	NmtNewtComponent parent;
+
+};
+
+typedef struct {
+	NmtNewtComponentClass parent;
+
+} NmtNewtTextboxClass;
+
+GType nmt_newt_textbox_get_type (void);
+
+typedef enum {
+	NMT_NEWT_TEXTBOX_SCROLLABLE     = (1 << 0),
+	NMT_NEWT_TEXTBOX_SET_BACKGROUND = (1 << 1)
+} NmtNewtTextboxFlags;
+
+NmtNewtWidget *nmt_newt_textbox_new      (NmtNewtTextboxFlags  flags,
+                                          int                  wrap_width);
+
+void           nmt_newt_textbox_set_text (NmtNewtTextbox      *textbox,
+                                          const char          *text);
+const char    *nmt_newt_textbox_get_text (NmtNewtTextbox      *textbox);
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_TEXTBOX_H */
diff --git a/tui/newt/nmt-newt-toggle-button.c b/tui/newt/nmt-newt-toggle-button.c
new file mode 100644
index 00000000..d435e459
--- /dev/null
+++ b/tui/newt/nmt-newt-toggle-button.c
@@ -0,0 +1,234 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-toggle-button
+ * @short_description: Toggle buttons
+ *
+ * #NmtNewtToggleButton implements a two-state toggle button.
+ */
+
+#include "config.h"
+
+#include "nmt-newt-toggle-button.h"
+
+G_DEFINE_TYPE (NmtNewtToggleButton, nmt_newt_toggle_button, NMT_TYPE_NEWT_BUTTON)
+
+#define NMT_NEWT_TOGGLE_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_TOGGLE_BUTTON, NmtNewtToggleButtonPrivate))
+
+typedef struct {
+	char *on_label, *off_label;
+	gboolean active;
+} NmtNewtToggleButtonPrivate;
+
+enum {
+	PROP_0,
+	PROP_ON_LABEL,
+	PROP_OFF_LABEL,
+	PROP_ACTIVE,
+
+	LAST_PROP
+};
+
+/**
+ * nmt_newt_toggle_button_new:
+ * @on_label: the button's label when it is in the "on" state
+ * @off_label: the button's label when it is in the "off" state
+ *
+ * Creates a new #NmtNewtToggleButton
+ *
+ * Returns: a new #NmtNewtToggleButton
+ */
+NmtNewtWidget *
+nmt_newt_toggle_button_new (const char *on_label,
+                            const char *off_label)
+{
+	return g_object_new (NMT_TYPE_NEWT_TOGGLE_BUTTON,
+	                     "on-label", on_label,
+	                     "off-label", off_label,
+	                     NULL);
+}
+
+/**
+ * nmt_newt_toggle_button_get_active:
+ * @button: an #NmtNewtToggleButton
+ *
+ * Gets whether @button is currently "on" or "off"
+ *
+ * Returns: whether @button is currently "on" (%TRUE) or "off" (%FALSE)
+ */
+gboolean
+nmt_newt_toggle_button_get_active (NmtNewtToggleButton *button)
+{
+	NmtNewtToggleButtonPrivate *priv = NMT_NEWT_TOGGLE_BUTTON_GET_PRIVATE (button);
+
+	return priv->active;
+}
+
+/**
+ * nmt_newt_toggle_button_set_active:
+ * @button: an #NmtNewtToggleButton
+ * @active: whether @button should be "on" or "off"
+ *
+ * Sets whether @button is currently "on" or "off"
+ */
+void
+nmt_newt_toggle_button_set_active (NmtNewtToggleButton *button,
+                                   gboolean             active)
+{
+	NmtNewtToggleButtonPrivate *priv = NMT_NEWT_TOGGLE_BUTTON_GET_PRIVATE (button);
+
+	if (priv->active == active)
+		return;
+
+	priv->active = active;
+	g_object_set (G_OBJECT (button),
+	              "label", active ? priv->on_label : priv->off_label,
+	              NULL);
+	g_object_notify (G_OBJECT (button), "active");
+}
+
+static void
+nmt_newt_toggle_button_init (NmtNewtToggleButton *button)
+{
+}
+
+static void
+nmt_newt_toggle_button_finalize (GObject *object)
+{
+	NmtNewtToggleButtonPrivate *priv = NMT_NEWT_TOGGLE_BUTTON_GET_PRIVATE (object);
+
+	g_free (priv->on_label);
+	g_free (priv->off_label);
+
+	G_OBJECT_CLASS (nmt_newt_toggle_button_parent_class)->finalize (object);
+}
+
+static void
+nmt_newt_toggle_button_activated (NmtNewtWidget *widget)
+{
+	NmtNewtToggleButton *button = NMT_NEWT_TOGGLE_BUTTON (widget);
+
+	nmt_newt_toggle_button_set_active (button, !nmt_newt_toggle_button_get_active (button));
+
+	NMT_NEWT_WIDGET_CLASS (nmt_newt_toggle_button_parent_class)->activated (widget);
+}
+
+static void
+nmt_newt_toggle_button_set_property (GObject      *object,
+                                     guint         prop_id,
+                                     const GValue *value,
+                                     GParamSpec   *pspec)
+{
+	NmtNewtToggleButtonPrivate *priv = NMT_NEWT_TOGGLE_BUTTON_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_ON_LABEL:
+		g_free (priv->on_label);
+		priv->on_label = g_value_dup_string (value);
+		if (priv->active)
+			g_object_set (object, "label", priv->on_label, NULL);
+		break;
+	case PROP_OFF_LABEL:
+		g_free (priv->off_label);
+		priv->off_label = g_value_dup_string (value);
+		if (!priv->active)
+			g_object_set (object, "label", priv->off_label, NULL);
+		break;
+	case PROP_ACTIVE:
+		priv->active = g_value_get_boolean (value);
+		g_object_set (object,
+		              "label", priv->active ? priv->on_label : priv->off_label,
+		              NULL);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_toggle_button_get_property (GObject    *object,
+                                     guint       prop_id,
+                                     GValue     *value,
+                                     GParamSpec *pspec)
+{
+	NmtNewtToggleButtonPrivate *priv = NMT_NEWT_TOGGLE_BUTTON_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_ON_LABEL:
+		g_value_set_string (value, priv->on_label);
+		break;
+	case PROP_OFF_LABEL:
+		g_value_set_string (value, priv->off_label);
+		break;
+	case PROP_ACTIVE:
+		g_value_set_boolean (value, priv->active);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_toggle_button_class_init (NmtNewtToggleButtonClass *button_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (button_class);
+	NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (button_class);
+
+	g_type_class_add_private (button_class, sizeof (NmtNewtToggleButtonPrivate));
+
+	/* virtual methods */
+	object_class->set_property = nmt_newt_toggle_button_set_property;
+	object_class->get_property = nmt_newt_toggle_button_get_property;
+	object_class->finalize     = nmt_newt_toggle_button_finalize;
+
+	widget_class->activated = nmt_newt_toggle_button_activated;
+
+	/**
+	 * NmtNewtToggleButton:on-label:
+	 *
+	 * The label the button displays when it is "on".
+	 */
+	g_object_class_install_property (object_class, PROP_ON_LABEL,
+	                                 g_param_spec_string ("on-label", "", "",
+	                                                      NULL,
+	                                                      G_PARAM_READWRITE |
+	                                                      G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtToggleButton:off-label:
+	 *
+	 * The label the button displays when it is "off".
+	 */
+	g_object_class_install_property (object_class, PROP_OFF_LABEL,
+	                                 g_param_spec_string ("off-label", "", "",
+	                                                      NULL,
+	                                                      G_PARAM_READWRITE |
+	                                                      G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtToggleButton:active:
+	 *
+	 * Whether the button is currently "on" (%TRUE) or "off" (%FALSE)
+	 */
+	g_object_class_install_property (object_class, PROP_ACTIVE,
+	                                 g_param_spec_boolean ("active", "", "",
+	                                                       FALSE,
+	                                                       G_PARAM_READWRITE |
+	                                                       G_PARAM_STATIC_STRINGS));
+}
diff --git a/tui/newt/nmt-newt-toggle-button.h b/tui/newt/nmt-newt-toggle-button.h
new file mode 100644
index 00000000..e54c6d3f
--- /dev/null
+++ b/tui/newt/nmt-newt-toggle-button.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_TOGGLE_BUTTON_H
+#define NMT_NEWT_TOGGLE_BUTTON_H
+
+#include "nmt-newt-button.h"
+
+G_BEGIN_DECLS
+
+#define NMT_TYPE_NEWT_TOGGLE_BUTTON            (nmt_newt_toggle_button_get_type ())
+#define NMT_NEWT_TOGGLE_BUTTON(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_TOGGLE_BUTTON, NmtNewtToggleButton))
+#define NMT_NEWT_TOGGLE_BUTTON_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_TOGGLE_BUTTON, NmtNewtToggleButtonClass))
+#define NMT_IS_NEWT_TOGGLE_BUTTON(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_TOGGLE_BUTTON))
+#define NMT_IS_NEWT_TOGGLE_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_TOGGLE_BUTTON))
+#define NMT_NEWT_TOGGLE_BUTTON_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_TOGGLE_BUTTON, NmtNewtToggleButtonClass))
+
+struct _NmtNewtToggleButton {
+	NmtNewtButton parent;
+
+};
+
+typedef struct {
+	NmtNewtButtonClass parent;
+
+} NmtNewtToggleButtonClass;
+
+GType nmt_newt_toggle_button_get_type (void);
+
+NmtNewtWidget *nmt_newt_toggle_button_new        (const char          *on_label,
+                                                  const char          *off_label);
+
+gboolean       nmt_newt_toggle_button_get_active (NmtNewtToggleButton *button);
+void           nmt_newt_toggle_button_set_active (NmtNewtToggleButton *button,
+                                                  gboolean             active);
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_TOGGLE_BUTTON_H */
diff --git a/tui/newt/nmt-newt-types.h b/tui/newt/nmt-newt-types.h
new file mode 100644
index 00000000..608f7ff6
--- /dev/null
+++ b/tui/newt/nmt-newt-types.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_TYPES_H
+#define NMT_NEWT_TYPES_H
+
+#include <glib-object.h>
+#include <newt.h>
+#include "nm-glib-compat.h"
+
+G_BEGIN_DECLS
+
+typedef struct _NmtNewtButton        NmtNewtButton;
+typedef struct _NmtNewtButtonBox     NmtNewtButtonBox;
+typedef struct _NmtNewtCheckbox      NmtNewtCheckbox;
+typedef struct _NmtNewtComponent     NmtNewtComponent;
+typedef struct _NmtNewtContainer     NmtNewtContainer;
+typedef struct _NmtNewtEntry         NmtNewtEntry;
+typedef struct _NmtNewtEntryNumeric  NmtNewtEntryNumeric;
+typedef struct _NmtNewtForm          NmtNewtForm;
+typedef struct _NmtNewtGrid          NmtNewtGrid;
+typedef struct _NmtNewtLabel         NmtNewtLabel;
+typedef struct _NmtNewtListbox       NmtNewtListbox;
+typedef struct _NmtNewtPopup         NmtNewtPopup;
+typedef struct _NmtNewtSection       NmtNewtSection;
+typedef struct _NmtNewtSectionBorder NmtNewtSectionBorder;
+typedef struct _NmtNewtSeparator     NmtNewtSeparator;
+typedef struct _NmtNewtStack         NmtNewtStack;
+typedef struct _NmtNewtTextbox       NmtNewtTextbox;
+typedef struct _NmtNewtToggleButton  NmtNewtToggleButton;
+typedef struct _NmtNewtWidget        NmtNewtWidget;
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_COMPONENT_H */
diff --git a/tui/newt/nmt-newt-utils.c b/tui/newt/nmt-newt-utils.c
new file mode 100644
index 00000000..68d8c449
--- /dev/null
+++ b/tui/newt/nmt-newt-utils.c
@@ -0,0 +1,392 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-utils
+ * @short_description: Utility functions
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include <glib/gi18n-lib.h>
+
+#include "nmt-newt-utils.h"
+
+static void
+nmt_newt_dialog_g_log_handler (const char     *log_domain,
+                               GLogLevelFlags  log_level,
+                               const char     *message,
+                               gpointer        user_data)
+{
+	const char *level_name;
+	char *full_message;
+	int screen_width, screen_height;
+	newtComponent text, ok, form;
+	newtGrid grid;
+
+	g_assert (!(log_level & G_LOG_FLAG_RECURSION));
+
+	if (log_level & G_LOG_LEVEL_DEBUG)
+		return;
+
+	switch (log_level & G_LOG_LEVEL_MASK) {
+	case G_LOG_LEVEL_ERROR:
+		level_name = "ERROR";
+		break;
+	case G_LOG_LEVEL_CRITICAL:
+		level_name = "CRITICAL";
+		break;
+	case G_LOG_LEVEL_WARNING:
+		level_name = "WARNING";
+		break;
+	case G_LOG_LEVEL_MESSAGE:
+		level_name = "Message";
+		break;
+	default:
+		level_name = NULL;
+	}
+
+	full_message = g_strdup_printf ("%s%s%s%s%s",
+	                                log_domain ? log_domain : "",
+	                                log_domain && level_name ? " " : "",
+	                                level_name ? level_name : "",
+	                                log_domain || level_name ? ": " : "",
+	                                message);
+
+	/* newtWinMessage() wraps the window too narrowly by default, so
+	 * we don't want to use that. But we intentionally avoid using any
+	 * NmtNewt classes, to avoid possible error recursion.
+	 */
+
+	newtGetScreenSize (&screen_width, &screen_height);
+	text = newtTextboxReflowed (-1, -1, full_message, MAX (70, screen_width - 10), 0, 0, 0);
+	g_free (full_message);
+
+	ok = newtButton (-1, -1, "OK");
+
+	grid = newtCreateGrid (1, 2);
+	newtGridSetField (grid, 0, 0, NEWT_GRID_COMPONENT, text, 0, 0, 0, 0, 0, 0);
+	newtGridSetField (grid, 0, 1, NEWT_GRID_COMPONENT, ok, 0, 1, 0, 0,
+	                  NEWT_ANCHOR_RIGHT, 0);
+
+	newtGridWrappedWindow (grid, (char *) (level_name ? level_name : ""));
+	newtGridFree (grid, TRUE);
+
+	form = newtForm (NULL, NULL, 0);
+	newtFormAddComponents (form, text, ok, NULL);
+	newtRunForm (form);
+	newtFormDestroy (form);
+	newtPopWindow ();
+}
+
+static void
+nmt_newt_basic_g_log_handler (const char     *log_domain,
+                              GLogLevelFlags  log_level,
+                              const char     *message,
+                              gpointer        user_data)
+{
+	newtSuspend ();
+	g_log_default_handler (log_domain, log_level, message, NULL);
+	newtResume ();
+}
+
+static void
+nmt_newt_suspend_callback (gpointer user_data)
+{
+	newtSuspend ();
+	kill (getpid (), SIGTSTP);
+	newtResume ();
+}
+
+/**
+ * nmt_newt_init:
+ *
+ * Wrapper for newtInit() that also does some nmt-newt-internal setup.
+ * This should be called once, before any other nmt-newt functions.
+ */
+void
+nmt_newt_init (void)
+{
+	newtInit ();
+	newtCls ();
+
+	newtSetColor (NEWT_COLORSET_CHECKBOX, "black", "lightgray");
+	newtSetColor (NMT_NEWT_COLORSET_BAD_LABEL, "red", "lightgray");
+	newtSetColor (NMT_NEWT_COLORSET_PLAIN_LABEL, "black", "lightgray");
+	newtSetColor (NMT_NEWT_COLORSET_DISABLED_BUTTON, "blue", "lightgray");
+	newtSetColor (NMT_NEWT_COLORSET_TEXTBOX_WITH_BACKGROUND, "black", "white");
+
+	if (g_getenv ("NMTUI_DEBUG"))
+		g_log_set_default_handler (nmt_newt_dialog_g_log_handler, NULL);
+	else
+		g_log_set_default_handler (nmt_newt_basic_g_log_handler, NULL);
+
+	newtSetSuspendCallback (nmt_newt_suspend_callback, NULL);
+}
+
+/**
+ * nmt_newt_finished:
+ *
+ * Wrapper for newtFinished(). Should be called at the end of the program.
+ */
+void
+nmt_newt_finished (void)
+{
+	newtFinished ();
+	g_log_set_default_handler (g_log_default_handler, NULL);
+}
+
+/**
+ * nmt_newt_message_dialog:
+ * @message: a printf()-style message format
+ * @...: arguments
+ *
+ * Displays the given message in a dialog box with a single "OK"
+ * button, and returns after the user clicks "OK".
+ */
+void
+nmt_newt_message_dialog  (const char *message,
+                          ...)
+{
+	va_list ap;
+	char *msg, *msg_lc, *ok_lc;
+
+	va_start (ap, message);
+	msg = g_strdup_vprintf (message, ap);
+	va_end (ap);
+
+	msg_lc = nmt_newt_locale_from_utf8 (msg);
+	ok_lc = nmt_newt_locale_from_utf8 (_("OK"));
+	newtWinMessage (NULL, ok_lc, "%s", msg_lc);
+
+	g_free (ok_lc);
+	g_free (msg_lc);
+	g_free (msg);
+}
+
+/**
+ * nmt_newt_choice_dialog:
+ * @button1: the label for the first button
+ * @button2: the label for the second button
+ * @message: a printf()-style message format
+ * @...: arguments
+ *
+ * Displays the given message in a dialog box with two buttons with
+ * the indicated labels, and waits for the user to click one.
+ *
+ * Returns: which button was clicked: 0 for @button1 or 1 for @button2
+ */
+int
+nmt_newt_choice_dialog (const char *button1,
+                        const char *button2,
+                        const char *message,
+                        ...)
+{
+	va_list ap;
+	char *msg, *msg_lc, *button1_lc, *button2_lc;
+	int choice;
+
+	va_start (ap, message);
+	msg = g_strdup_vprintf (message, ap);
+	va_end (ap);
+
+	msg_lc = nmt_newt_locale_from_utf8 (msg);
+	button1_lc = nmt_newt_locale_from_utf8 (button1);
+	button2_lc = nmt_newt_locale_from_utf8 (button2);
+	choice = newtWinChoice (NULL, button1_lc, button2_lc, "%s", msg_lc);
+
+	g_free (button1_lc);
+	g_free (button2_lc);
+	g_free (msg_lc);
+	g_free (msg);
+
+	return choice;
+}
+
+/**
+ * nmt_newt_locale_to_utf8:
+ * @str_lc: a string in the user's locale encoding
+ *
+ * Convenience wrapper around g_locale_to_utf8().
+ *
+ * Note that libnewt works in terms of the user's locale character
+ * set, NOT UTF-8, so all strings received from libnewt must be
+ * converted back to UTF-8 before being returned to the caller or used
+ * in other APIs.
+ *
+ * Returns: @str_lc, converted to UTF-8.
+ */
+char *
+nmt_newt_locale_to_utf8 (const char *str_lc)
+{
+	char *str_utf8;
+
+	str_utf8 = g_locale_to_utf8 (str_lc, -1, NULL, NULL, NULL);
+	if (!str_utf8)
+		str_utf8 = g_strdup ("");
+	return str_utf8;
+}
+
+/**
+ * nmt_newt_locale_from_utf8:
+ * @str_utf8: a UTF-8 string
+ *
+ * Convenience wrapper around g_locale_from_utf8().
+ *
+ * Note that libnewt works in terms of the user's locale character
+ * set, NOT UTF-8, so all strings from nmt-newt must be converted to
+ * locale encoding before being passed to libnewt.
+ *
+ * Returns: @str_utf8, converted to the user's locale encoding.
+ */
+char *
+nmt_newt_locale_from_utf8 (const char *str_utf8)
+{
+	char *str_lc;
+
+	str_lc = g_locale_from_utf8 (str_utf8, -1, NULL, NULL, NULL);
+	if (!str_lc)
+		str_lc = g_strdup ("");
+	return str_lc;
+}
+
+/**
+ * nmt_newt_text_width
+ * @str: a UTF-8 string
+ *
+ * Computes the width (in terminal columns) of @str.
+ *
+ * Returns: the width of @str
+ */
+int
+nmt_newt_text_width (const char *str)
+{
+	int width;
+	gunichar ch;
+
+	for (width = 0; *str; str = g_utf8_next_char (str)) {
+		ch = g_utf8_get_char (str);
+
+		/* Based on _vte_iso2022_unichar_width */
+		if (G_LIKELY (ch < 0x80))
+			width += 1;
+		else if (G_UNLIKELY (g_unichar_iszerowidth (ch)))
+			width += 0;
+		else if (G_UNLIKELY (g_unichar_iswide (ch)))
+			width += 2;
+		else
+			width += 1;
+	}
+
+	return width;
+}
+
+/**
+ * nmt_newt_edit_string:
+ * @data: data to edit
+ *
+ * libnewt does not have a multi-line editable text component, so
+ * nmt-newt provides this function instead, which will open the user's
+ * editor to edit a file containing the given @data (ensuring that the
+ * current screen state is saved before starting the editor and
+ * restored after it returns).
+ *
+ * Returns: the edited data, or %NULL if an error occurred.
+ */
+char *
+nmt_newt_edit_string (const char *data)
+{
+	gssize len, nwrote;
+	char *filename, *argv[3];
+	GError *error = NULL;
+	int fd, status;
+	char *new_data = NULL;
+
+	fd = g_file_open_tmp ("XXXXXX.json", &filename, &error);
+	if (fd == -1) {
+		nmt_newt_message_dialog (_("Could not create temporary file: %s"), error->message);
+		g_error_free (error);
+		return NULL;
+	}
+
+	len = data ? strlen (data) : 0;
+	while (len) {
+		do
+			nwrote = write (fd, data, len);
+		while (nwrote == -1 && errno == EINTR);
+
+		len -= nwrote;
+		data += nwrote;
+	}
+	close (fd);
+
+	argv[0] = (char *) g_getenv ("VISUAL");
+	if (!argv[0])
+		argv[0] = (char *) g_getenv ("EDITOR");
+	if (!argv[0])
+		argv[0] = (char *) "vi";
+	argv[1] = filename;
+	argv[2] = NULL;
+
+	newtSuspend ();
+	g_spawn_sync (NULL, argv, NULL,
+	              G_SPAWN_SEARCH_PATH | G_SPAWN_CHILD_INHERITS_STDIN,
+	              NULL, NULL, NULL, NULL,
+	              &status, &error);
+	newtResume ();
+
+	if (error) {
+		nmt_newt_message_dialog (_("Could not create temporary file: %s"), error->message);
+		g_error_free (error);
+		goto done;
+	}
+
+#if GLIB_CHECK_VERSION (2, 34, 0)
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+	if (!g_spawn_check_exit_status (status, &error)) {
+		nmt_newt_message_dialog (_("Editor failed: %s"), error->message);
+		g_error_free (error);
+		goto done;
+	}
+	G_GNUC_END_IGNORE_DEPRECATIONS
+#else
+	if (WIFEXITED (status)) {
+		if (WEXITSTATUS (status) != 0)
+			nmt_newt_message_dialog (_("Editor failed with status %d"), WEXITSTATUS (status));
+	} else if (WIFSIGNALED (status))
+		nmt_newt_message_dialog (_("Editor failed with signal %d"), WTERMSIG (status));
+#endif
+
+	if (!g_file_get_contents (filename, &new_data, NULL, &error)) {
+		nmt_newt_message_dialog (_("Could not re-read file: %s"), error->message);
+		g_error_free (error);
+		goto done;
+	}
+
+ done:
+	unlink (filename);
+	g_free (filename);
+
+	return new_data;
+}	
+
diff --git a/tui/newt/nmt-newt-utils.h b/tui/newt/nmt-newt-utils.h
new file mode 100644
index 00000000..3b37868a
--- /dev/null
+++ b/tui/newt/nmt-newt-utils.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_UTILS_H
+#define NMT_NEWT_UTILS_H
+
+#include <newt.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+void nmt_newt_init     (void);
+void nmt_newt_finished (void);
+
+typedef enum {
+	NMT_NEWT_COLORSET_BAD_LABEL = NEWT_COLORSET_CUSTOM (0),
+	NMT_NEWT_COLORSET_PLAIN_LABEL,
+	NMT_NEWT_COLORSET_DISABLED_BUTTON,
+	NMT_NEWT_COLORSET_TEXTBOX_WITH_BACKGROUND
+} NmtNewtColorsets;
+
+char *nmt_newt_locale_to_utf8   (const char *str_lc);
+char *nmt_newt_locale_from_utf8 (const char *str_utf8);
+
+int   nmt_newt_text_width       (const char *str);
+
+void nmt_newt_message_dialog  (const char *message,
+                               ...);
+int  nmt_newt_choice_dialog (const char *button1,
+                             const char *button2,
+                             const char *message,
+                             ...);
+
+char *nmt_newt_edit_string (const char *data);
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_UTILS_H */
diff --git a/tui/newt/nmt-newt-widget.c b/tui/newt/nmt-newt-widget.c
new file mode 100644
index 00000000..24ee8b0a
--- /dev/null
+++ b/tui/newt/nmt-newt-widget.c
@@ -0,0 +1,664 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-widget
+ * @short_description: Base TUI Widget class
+ *
+ * #NmtNewtWidget is the abstract base class for nmt-newt. All widgets
+ * inherit from one of its two subclasses: #NmtNewtComponent, for
+ * widgets that wrap a (single) #newtComponent, and #NmtNewtContainer,
+ * for widgets consisting of multiple components. See those classes
+ * for more details.
+ *
+ * With the exception of #NmtNewtForm, all widgets start out with a
+ * floating reference, which will be sunk by the container they are
+ * added to. #NmtNewtForm is the "top-level" widget type, and so does
+ * not have a floating reference.
+ *
+ * FIXME: need RTL support
+ */
+
+#include "config.h"
+
+#include "nmt-newt-widget.h"
+#include "nmt-newt-form.h"
+
+G_DEFINE_ABSTRACT_TYPE (NmtNewtWidget, nmt_newt_widget, G_TYPE_INITIALLY_UNOWNED)
+
+#define NMT_NEWT_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_WIDGET, NmtNewtWidgetPrivate))
+
+typedef struct {
+	NmtNewtWidget *parent;
+	gboolean visible, realized, valid;
+	gboolean exit_on_activate;
+
+	int pad_left, pad_top, pad_right, pad_bottom;
+} NmtNewtWidgetPrivate;
+
+enum {
+	PROP_0,
+
+	PROP_PARENT,
+	PROP_VISIBLE,
+	PROP_VALID,
+	PROP_EXIT_ON_ACTIVATE,
+
+	LAST_PROP
+};
+
+enum {
+	NEEDS_REBUILD,
+	ACTIVATED,
+
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+nmt_newt_widget_init (NmtNewtWidget *widget)
+{
+	NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget);
+
+	priv->visible = TRUE;
+	priv->valid = TRUE;
+}
+
+static void
+nmt_newt_widget_finalize (GObject *object)
+{
+	NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (object);
+
+	nmt_newt_widget_unrealize (NMT_NEWT_WIDGET (object));
+	g_clear_object (&priv->parent);
+
+	G_OBJECT_CLASS (nmt_newt_widget_parent_class)->finalize (object);
+}
+
+/**
+ * nmt_newt_widget_realize:
+ * @widget: an #NmtNewtWidget
+ *
+ * "Realizes" @widget. That is, creates #newtComponents corresponding
+ * to @widget and its children.
+ *
+ * You should not need to call this yourself; an #NmtNewtForm will
+ * cause its children to be realized and unrealized as needed.
+ */
+void
+nmt_newt_widget_realize (NmtNewtWidget *widget)
+{
+	NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget);
+
+	if (!priv->realized) {
+		NMT_NEWT_WIDGET_GET_CLASS (widget)->realize (widget);
+		priv->realized = TRUE;
+	}
+}
+
+/**
+ * nmt_newt_widget_unrealize:
+ * @widget: an #NmtNewtWidget
+ *
+ * "Unrealizes" @widget, destroying its #newtComponents.
+ *
+ * You should not need to call this yourself; an #NmtNewtForm will
+ * cause its children to be realized and unrealized as needed.
+ */
+void
+nmt_newt_widget_unrealize (NmtNewtWidget *widget)
+{
+	NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget);
+
+	if (priv->realized) {
+		NMT_NEWT_WIDGET_GET_CLASS (widget)->unrealize (widget);
+		priv->realized = FALSE;
+	}
+}
+
+/**
+ * nmt_newt_widget_get_realized:
+ * @widget: an #NmtNewtWidget
+ *
+ * Checks if @widget is realized or not.
+ *
+ * Returns: whether @widget is realized.
+ */
+gboolean
+nmt_newt_widget_get_realized (NmtNewtWidget *widget)
+{
+	NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget);
+
+	return priv->realized;
+}
+
+/**
+ * nmt_newt_widget_get_components:
+ * @widget: an #NmtNewtWidget
+ *
+ * Gets the #newtComponents that make up @widget, if @widget is
+ * visible. If @widget has not yet been realized, it will be realized
+ * first.
+ *
+ * If this function is called on a widget, then the widget will assume
+ * that someone else is now responsible for destroying the components,
+ * and so it will not destroy them itself when the widget is
+ * destroyed. Normally, components will end up being destroyed by the
+ * #NmtNewtForm they are added to.
+ *
+ * Returns: a %NULL-terminated array of components, in focus-chain
+ *   order. You must free the array with g_free() when you are done
+ *   with it.
+ */
+newtComponent *
+nmt_newt_widget_get_components (NmtNewtWidget *widget)
+{
+	if (nmt_newt_widget_get_visible (widget)) {
+		nmt_newt_widget_realize (widget);
+		return NMT_NEWT_WIDGET_GET_CLASS (widget)->get_components (widget);
+	} else
+		return NULL;
+}
+
+/**
+ * nmt_newt_widget_find_component:
+ * @widget: an #NmtNewtWidget
+ * @co: a #newtComponent
+ *
+ * Finds the widget inside @widget that owns @co.
+ *
+ * Return value: @co's owner, or %NULL if it was not found.
+ */
+NmtNewtWidget *
+nmt_newt_widget_find_component (NmtNewtWidget *widget,
+                                newtComponent  co)
+{
+	return NMT_NEWT_WIDGET_GET_CLASS (widget)->find_component (widget, co);
+}
+
+/**
+ * nmt_newt_widget_set_padding:
+ * @widget: an #NmtNewtWidget
+ * @pad_left: padding on the left of @widget
+ * @pad_top: padding on the top of @widget
+ * @pad_right: padding on the right of @widget
+ * @pad_bottom: padding on the bottom of @widget
+ *
+ * Sets the padding on @widget.
+ */
+void
+nmt_newt_widget_set_padding (NmtNewtWidget *widget,
+                             int            pad_left,
+                             int            pad_top,
+                             int            pad_right,
+                             int            pad_bottom)
+{
+	NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget);
+
+	priv->pad_left = pad_left;
+	priv->pad_top = pad_top;
+	priv->pad_right = pad_right;
+	priv->pad_bottom = pad_bottom;
+}
+
+/**
+ * nmt_newt_widget_size_request:
+ * @widget: an #NmtNewtWidget
+ * @width: (out): on output, the widget's requested width
+ * @height: (out): on output, the widget's requested height
+ *
+ * Asks @widget for its requested size. If @widget is not visible,
+ * this will return 0, 0. If @widget has not yet been realized, it
+ * will be realized first.
+ */
+void
+nmt_newt_widget_size_request (NmtNewtWidget *widget,
+                              int           *width,
+                              int           *height)
+{
+	if (nmt_newt_widget_get_visible (widget)) {
+		NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget);
+
+		nmt_newt_widget_realize (widget);
+		NMT_NEWT_WIDGET_GET_CLASS (widget)->size_request (widget, width, height);
+
+		*width += priv->pad_left + priv->pad_right;
+		*height += priv->pad_top + priv->pad_bottom;
+	} else
+		*width = *height = 0;
+}
+
+/**
+ * nmt_newt_widget_size_allocate:
+ * @widget: an #NmtNewtWidget
+ * @x: the widget's (absolute) X coordinate
+ * @y: the widget's (absolute) Y coordinate
+ * @width: the widget's allocated width
+ * @height: the widget's allocated height
+ *
+ * Positions @widget at the given coordinates, with the given size. If
+ * @widget is not visible, this has no effect. If @widget has not yet
+ * been realized, it will be realized first.
+ *
+ * @x and @y are absolute coordinates (ie, relative to the screen /
+ * terminal window, not relative to @widget's parent).
+ *
+ * In general, the results are undefined if @width or @height is less
+ * than the widget's requested size. If @width or @height is larger
+ * than the requested size, most #NmtNewtComponents will ignore the
+ * extra space, but some components and most containers will expand to
+ * fit.
+ */
+void
+nmt_newt_widget_size_allocate (NmtNewtWidget *widget,
+                               int            x,
+                               int            y,
+                               int            width,
+                               int            height)
+{
+	if (nmt_newt_widget_get_visible (widget)) {
+		NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget);
+
+		nmt_newt_widget_realize (widget);
+		x += priv->pad_left;
+		y += priv->pad_top;
+		width -= priv->pad_left + priv->pad_right;
+		height -= priv->pad_top + priv->pad_bottom;
+
+		NMT_NEWT_WIDGET_GET_CLASS (widget)->size_allocate (widget, x, y, width, height);
+	}
+}
+
+/**
+ * nmt_newt_widget_get_focus_component:
+ * @widget: an #NmtNewtWidget
+ *
+ * Gets the #newtComponent that should be given the keyboard focus when
+ * @widget is focused.
+ *
+ * Returns: the #newtComponent to focus, or %NULL if @widget can't
+ *   take the focus.
+ */
+newtComponent
+nmt_newt_widget_get_focus_component (NmtNewtWidget *widget)
+{
+	if (!NMT_NEWT_WIDGET_GET_CLASS (widget)->get_focus_component)
+		return NULL;
+
+	return NMT_NEWT_WIDGET_GET_CLASS (widget)->get_focus_component (widget);
+}
+
+static void
+nmt_newt_widget_real_activated (NmtNewtWidget *widget)
+{
+	NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget);
+
+	if (priv->exit_on_activate)
+		nmt_newt_form_quit (nmt_newt_widget_get_form (widget));
+}	
+
+/**
+ * nmt_newt_widget_activated:
+ * @widget: an #NmtNewtWidget
+ *
+ * Tells @widget that its #newtComponent has been activated (ie, the
+ * user hit "Return" on it) and emits #NmtNewtWidget::activated.
+ *
+ * If #NmtNewtWidget:exit-on-activate is set on @widget, then this
+ * will call nmt_newt_form_quit() on the widget's form.
+ */
+void
+nmt_newt_widget_activated (NmtNewtWidget *widget)
+{
+	g_signal_emit (widget, signals[ACTIVATED], 0);
+}
+
+/**
+ * nmt_newt_widget_get_exit_on_activate:
+ * @widget: an #NmtNewtWidget
+ *
+ * Gets @widget's #NmtNewtWidget:exit-on-activate flag, qv.
+ *
+ * Returns: @widget's #NmtNewtWidget:exit-on-activate flag
+ */
+gboolean
+nmt_newt_widget_get_exit_on_activate (NmtNewtWidget *widget)
+{
+	NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget);
+
+	return priv->exit_on_activate;
+}
+
+/**
+ * nmt_newt_widget_set_exit_on_activate:
+ * @widget: an #NmtNewtWidget
+ * @exit_on_activate: whether @widget should exit on activate.
+ *
+ * Sets @widget's #NmtNewtWidget:exit-on-activate flag, qv.
+ */
+void
+nmt_newt_widget_set_exit_on_activate (NmtNewtWidget *widget,
+                                      gboolean       exit_on_activate)
+{
+	NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget);
+
+	exit_on_activate = !!exit_on_activate;
+	if (priv->exit_on_activate != exit_on_activate) {
+		priv->exit_on_activate = exit_on_activate;
+		g_object_notify (G_OBJECT (widget), "exit-on-activate");
+	}
+} 
+
+/**
+ * nmt_newt_widget_get_visible:
+ * @widget: an #NmtNewtWidget
+ *
+ * Gets @widget's #NmtNewtWidget:visible flag, qv.
+ *
+ * Returns: @widget's #NmtNewtWidget:visible flag
+ */
+gboolean
+nmt_newt_widget_get_visible (NmtNewtWidget *widget)
+{
+	NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget);
+
+	return priv->visible;
+}
+
+/**
+ * nmt_newt_widget_set_visible:
+ * @widget: an #NmtNewtWidget
+ * @visible: whether @widget should be visible
+ *
+ * Sets @widget's #NmtNewtWidget:visible flag, qv.
+ */
+void
+nmt_newt_widget_set_visible (NmtNewtWidget *widget,
+                             gboolean       visible)
+{
+	NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget);
+
+	visible = !!visible;
+	if (priv->visible != visible) {
+		priv->visible = visible;
+		g_object_notify (G_OBJECT (widget), "visible");
+		nmt_newt_widget_needs_rebuild (widget);
+	}
+}
+
+/**
+ * nmt_newt_widget_set_parent:
+ * @widget: an #NmtNewtWidget
+ * @parent: @widget's parent
+ *
+ * Sets @widget's parent to @parent. This is used internally by
+ * #NmtNewtContainer implementations; you must use an appropriate
+ * container-specific method to actually add a widget to a container.
+ */
+void
+nmt_newt_widget_set_parent (NmtNewtWidget *widget,
+                            NmtNewtWidget *parent)
+{
+	NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget);
+
+	g_clear_object (&priv->parent);
+	priv->parent = parent ? g_object_ref (parent) : NULL;
+	g_object_notify (G_OBJECT (widget), "parent");
+}
+
+/**
+ * nmt_newt_widget_get_parent:
+ * @widget: an #NmtNewtWidget
+ *
+ * Gets @widget's parent
+ *
+ * Returns: @widget's parent
+ */
+NmtNewtWidget *
+nmt_newt_widget_get_parent (NmtNewtWidget *widget)
+{
+	NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget);
+
+	return priv->parent;
+}
+
+/**
+ * nmt_newt_widget_get_form:
+ * @widget: an #NmtNewtWidget
+ *
+ * Gets @widget's top-level form.
+ *
+ * Returns: @widget's #NmtNewtForm
+ */
+NmtNewtForm *
+nmt_newt_widget_get_form (NmtNewtWidget *widget)
+{
+	while (widget) {
+		if (NMT_IS_NEWT_FORM (widget))
+			return NMT_NEWT_FORM (widget);
+		widget = nmt_newt_widget_get_parent (widget);
+	}
+
+	return NULL;
+}
+
+/**
+ * nmt_newt_widget_get_valid:
+ * @widget: an #NmtNewtWidget
+ *
+ * Gets @widget's #NmtNewtWidget:valid flag, indicating whether its
+ * content is valid.
+ *
+ * Returns: @widget's #NmtNewtWidget:valid flag
+ */
+gboolean
+nmt_newt_widget_get_valid (NmtNewtWidget *widget)
+{
+	NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget);
+
+	return priv->valid;
+}
+
+/**
+ * nmt_newt_widget_set_valid:
+ * @widget: an #NmtNewtWidget
+ * @valid: whether @widget is valid
+ *
+ * Sets @widget's #NmtNewtWidget:valid flag, indicating whether its
+ * content is valid.
+ *
+ * This method should be considered "protected"; if you change it, the
+ * widget implementation will likely just change it back at some
+ * point.
+ */
+void
+nmt_newt_widget_set_valid (NmtNewtWidget *widget,
+                           gboolean       valid)
+{
+	NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget);
+
+	valid = !!valid;
+	if (priv->valid == valid)
+		return;
+
+	priv->valid = valid;
+	g_object_notify (G_OBJECT (widget), "valid");
+}
+
+/**
+ * nmt_newt_widget_needs_rebuilds:
+ * @widget: an #NmtNewtWidget
+ *
+ * Marks @widget as needing to be "rebuilt" (ie, re-realized). This is
+ * called automatically in some cases (such as when adding a widget to
+ * or removing it from a container). #NmtNewtComponent implementations
+ * should also call this if they need to make some change that can
+ * only be done by destroying their current #newtComponent and
+ * creating a new one.
+ */
+void
+nmt_newt_widget_needs_rebuild (NmtNewtWidget *widget)
+{
+	g_signal_emit (widget, signals[NEEDS_REBUILD], 0);
+}
+
+static void
+nmt_newt_widget_set_property (GObject      *object,
+                              guint         prop_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+	NmtNewtWidget *widget = NMT_NEWT_WIDGET (object);
+
+	switch (prop_id) {
+	case PROP_PARENT:
+		nmt_newt_widget_set_parent (widget, g_value_get_object (value));
+		break;
+	case PROP_VISIBLE:
+		nmt_newt_widget_set_visible (widget, g_value_get_boolean (value));
+		break;
+	case PROP_EXIT_ON_ACTIVATE:
+		nmt_newt_widget_set_exit_on_activate (widget, g_value_get_boolean (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_widget_get_property (GObject    *object,
+                              guint       prop_id,
+                              GValue     *value,
+                              GParamSpec *pspec)
+{
+	NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_PARENT:
+		g_value_set_object (value, priv->parent);
+		break;
+	case PROP_VISIBLE:
+		g_value_set_boolean (value, priv->visible);
+		break;
+	case PROP_VALID:
+		g_value_set_boolean (value, priv->valid);
+		break;
+	case PROP_EXIT_ON_ACTIVATE:
+		g_value_set_boolean (value, priv->exit_on_activate);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_widget_class_init (NmtNewtWidgetClass *widget_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (widget_class);
+
+	g_type_class_add_private (widget_class, sizeof (NmtNewtWidgetPrivate));
+
+	/* virtual methods */
+	object_class->set_property = nmt_newt_widget_set_property;
+	object_class->get_property = nmt_newt_widget_get_property;
+	object_class->finalize     = nmt_newt_widget_finalize;
+
+	widget_class->activated = nmt_newt_widget_real_activated;
+
+	/* signals */
+
+	/**
+	 * NmtNewtWidget::needs-rebuild:
+	 * @widget: the #NmtNewtWidget
+	 *
+	 * Emitted when nmt_newt_widget_need_rebuild() is called on @widget
+	 * or any of its children. This signal propagates up the container
+	 * hierarchy, eventually reaching the top-level #NmtNewtForm.
+	 */
+	signals[NEEDS_REBUILD] =
+		g_signal_new ("needs-rebuild",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NmtNewtWidgetClass, needs_rebuild),
+		              NULL, NULL, NULL,
+		              G_TYPE_NONE, 0);
+
+	/**
+	 * NmtNewtWidget::activated:
+	 * @widget: the #NmtNewtWidget
+	 *
+	 * Emitted when the widget's #newtComponent is activated.
+	 */
+	signals[ACTIVATED] =
+		g_signal_new ("activated",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NmtNewtWidgetClass, activated),
+		              NULL, NULL, NULL,
+		              G_TYPE_NONE, 0);
+
+	/* properties */
+
+	/**
+	 * NmtNewtWidget:parent:
+	 *
+	 * The widget's parent widget, or %NULL if it has no parent.
+	 */
+	g_object_class_install_property (object_class, PROP_PARENT,
+	                                 g_param_spec_object ("parent", "", "",
+	                                                      NMT_TYPE_NEWT_WIDGET,
+	                                                      G_PARAM_READABLE |
+	                                                      G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtWidget:visible:
+	 *
+	 * Whether the widget is visible. Invisible widgets do not get
+	 * realized or sized.
+	 */
+	g_object_class_install_property (object_class, PROP_VISIBLE,
+	                                 g_param_spec_boolean ("visible", "", "",
+	                                                       TRUE,
+	                                                       G_PARAM_READWRITE |
+	                                                       G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtWidget:valid:
+	 *
+	 * Whether the widget's content is considered valid. Components
+	 * determine their own validity. A container, by default, is
+	 * considered valid if all of its children are valid.
+	 */
+	g_object_class_install_property (object_class, PROP_VALID,
+	                                 g_param_spec_boolean ("valid", "", "",
+	                                                       TRUE,
+	                                                       G_PARAM_READABLE |
+	                                                       G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtWidget:exit-on-activate:
+	 *
+	 * If %TRUE, the widget will call nmt_newt_form_quit() on its form
+	 * when it is activated.
+	 */
+	g_object_class_install_property (object_class, PROP_EXIT_ON_ACTIVATE,
+	                                 g_param_spec_boolean ("exit-on-activate", "", "",
+	                                                       FALSE,
+	                                                       G_PARAM_READWRITE |
+	                                                       G_PARAM_STATIC_STRINGS));
+}
diff --git a/tui/newt/nmt-newt-widget.h b/tui/newt/nmt-newt-widget.h
new file mode 100644
index 00000000..a526a674
--- /dev/null
+++ b/tui/newt/nmt-newt-widget.h
@@ -0,0 +1,118 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_WIDGET_H
+#define NMT_NEWT_WIDGET_H
+
+#include "nmt-newt-types.h"
+
+G_BEGIN_DECLS
+
+#define NMT_TYPE_NEWT_WIDGET            (nmt_newt_widget_get_type ())
+#define NMT_NEWT_WIDGET(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_WIDGET, NmtNewtWidget))
+#define NMT_NEWT_WIDGET_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_WIDGET, NmtNewtWidgetClass))
+#define NMT_IS_NEWT_WIDGET(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_WIDGET))
+#define NMT_IS_NEWT_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_WIDGET))
+#define NMT_NEWT_WIDGET_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_WIDGET, NmtNewtWidgetClass))
+
+struct _NmtNewtWidget {
+	GInitiallyUnowned parent;
+
+};
+
+typedef struct {
+	GInitiallyUnownedClass parent;
+
+	/* signals */
+	void            (*needs_rebuild)       (NmtNewtWidget *widget);
+	void            (*activated)           (NmtNewtWidget *widget);
+
+	/* methods */
+	void            (*realize)             (NmtNewtWidget *widget);
+	void            (*unrealize)           (NmtNewtWidget *widget);
+
+	newtComponent * (*get_components)      (NmtNewtWidget *widget);
+	NmtNewtWidget * (*find_component)      (NmtNewtWidget *widget,
+	                                        newtComponent  co);
+
+	void            (*size_request)        (NmtNewtWidget *widget,
+	                                        int           *width,
+	                                        int           *height);
+	void            (*size_allocate)       (NmtNewtWidget *widget,
+	                                        int            x,
+	                                        int            y,
+	                                        int            width,
+	                                        int            height);
+
+	newtComponent   (*get_focus_component) (NmtNewtWidget *widget);
+
+} NmtNewtWidgetClass;
+
+GType nmt_newt_widget_get_type (void);
+
+void           nmt_newt_widget_realize        (NmtNewtWidget *widget);
+void           nmt_newt_widget_unrealize      (NmtNewtWidget *widget);
+gboolean       nmt_newt_widget_get_realized   (NmtNewtWidget *widget);
+
+newtComponent *nmt_newt_widget_get_components (NmtNewtWidget *widget);
+
+void           nmt_newt_widget_set_padding    (NmtNewtWidget *widget,
+                                               int            pad_left,
+                                               int            pad_top,
+                                               int            pad_right,
+                                               int            pad_bottom);
+
+void           nmt_newt_widget_size_request   (NmtNewtWidget *widget,
+                                               int           *width,
+                                               int           *height);
+void           nmt_newt_widget_size_allocate  (NmtNewtWidget *widget,
+                                               int            x,
+                                               int            y,
+                                               int            width,
+                                               int            height);
+
+void           nmt_newt_widget_set_parent     (NmtNewtWidget *widget,
+                                               NmtNewtWidget *parent);
+NmtNewtWidget *nmt_newt_widget_get_parent     (NmtNewtWidget *widget);
+
+NmtNewtForm   *nmt_newt_widget_get_form       (NmtNewtWidget *widget);
+
+gboolean       nmt_newt_widget_get_visible    (NmtNewtWidget *widget);
+void           nmt_newt_widget_set_visible    (NmtNewtWidget *widget,
+                                               gboolean       visible);
+
+newtComponent  nmt_newt_widget_get_focus_component  (NmtNewtWidget *widget);
+
+void           nmt_newt_widget_activated            (NmtNewtWidget *widget);
+gboolean       nmt_newt_widget_get_exit_on_activate (NmtNewtWidget *widget);
+void           nmt_newt_widget_set_exit_on_activate (NmtNewtWidget *widget,
+                                                     gboolean       exit_on_activate);
+
+gboolean       nmt_newt_widget_get_valid      (NmtNewtWidget *widget);
+
+NmtNewtWidget *nmt_newt_widget_find_component (NmtNewtWidget *widget,
+                                               newtComponent  co);
+
+/* protected */
+void           nmt_newt_widget_needs_rebuild  (NmtNewtWidget *widget);
+void           nmt_newt_widget_set_valid      (NmtNewtWidget *widget,
+                                               gboolean       valid);
+
+G_END_DECLS
+
+#endif /* NMT_NEWT_WIDGET_H */
diff --git a/tui/newt/nmt-newt.h b/tui/newt/nmt-newt.h
new file mode 100644
index 00000000..6a9c8d9f
--- /dev/null
+++ b/tui/newt/nmt-newt.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NMT_NEWT_H
+#define NMT_NEWT_H
+
+#include "nmt-newt-button.h"
+#include "nmt-newt-button-box.h"
+#include "nmt-newt-checkbox.h"
+#include "nmt-newt-entry.h"
+#include "nmt-newt-entry-numeric.h"
+#include "nmt-newt-form.h"
+#include "nmt-newt-grid.h"
+#include "nmt-newt-label.h"
+#include "nmt-newt-listbox.h"
+#include "nmt-newt-popup.h"
+#include "nmt-newt-section.h"
+#include "nmt-newt-separator.h"
+#include "nmt-newt-stack.h"
+#include "nmt-newt-textbox.h"
+#include "nmt-newt-toggle-button.h"
+#include "nmt-newt-utils.h"
+
+#endif /* NMT_NEWT_H */