]> git.pld-linux.org Git - packages/plymouth.git/commitdiff
- added git patch to update the package to current state
authorJan Rękorajski <baggins@pld-linux.org>
Tue, 29 Apr 2014 17:39:57 +0000 (19:39 +0200)
committerJan Rękorajski <baggins@pld-linux.org>
Tue, 29 Apr 2014 17:39:57 +0000 (19:39 +0200)
- removed Fedora junk
- removed duplicate services provided upstream
- static libs no longer provided by upstream
- updated patches
- rel 9

charge.plymouth [deleted file]
path-udevadm.patch [deleted file]
plymouth-git.patch [new file with mode: 0644]
plymouth.spec
systemd-ask-password-plymouth.path [deleted file]
systemd-ask-password-plymouth.service [deleted file]
text-colors.patch

diff --git a/charge.plymouth b/charge.plymouth
deleted file mode 100644 (file)
index f499c0f..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-[Plymouth Theme]
-Name=Charge
-Description=A theme that features the shadowy hull of a Fedora logo charge up and and finally burst into into full form.
-ModuleName=two-step
-
-[two-step]
-ImageDir=/usr/share/plymouth/themes/charge
-HorizontalAlignment=.5
-VerticalAlignment=.5
-Transition=none
-TransitionDuration=0.0
-BackgroundStartColor=0x202020
-BackgroundEndColor=0x202020
diff --git a/path-udevadm.patch b/path-udevadm.patch
deleted file mode 100644 (file)
index 42970b6..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
---- plymouth-0.8.8/systemd-units/plymouth-start.service.in.orig        2012-10-31 20:43:34.695979769 +0100
-+++ plymouth-0.8.8/systemd-units/plymouth-start.service.in     2012-10-31 20:44:47.219310059 +0100
-@@ -8,7 +8,7 @@
- [Service]
- ExecStart=@PLYMOUTH_DAEMON_DIR@/plymouthd --mode=boot --pid-file=@plymouthruntimedir@/pid --attach-to-session
--ExecStartPost=-/bin/udevadm settle --timeout=30 --exit-if-exists=/sys/class/drm/card0/dev ; /bin/udevadm settle --timeout=30 --exit-if-exists=/sys/class/graphics/fb0/dev ; @PLYMOUTH_CLIENT_DIR@/plymouth show-splash
-+ExecStartPost=-/sbin/udevadm settle --timeout=30 --exit-if-exists=/sys/class/drm/card0/dev ; /sbin/udevadm settle --timeout=30 --exit-if-exists=/sys/class/graphics/fb0/dev ; @PLYMOUTH_CLIENT_DIR@/plymouth show-splash
- Type=forking
- KillMode=none
- SendSIGKILL=no
diff --git a/plymouth-git.patch b/plymouth-git.patch
new file mode 100644 (file)
index 0000000..a5c8b3c
--- /dev/null
@@ -0,0 +1,11238 @@
+diff --git a/Makefile.am b/Makefile.am
+index b322463..395c91b 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1,4 +1,8 @@
+-SUBDIRS = src themes images scripts docs systemd-units
++SUBDIRS = src themes images scripts systemd-units
++
++if BUILD_DOCUMENTATION
++SUBDIRS += docs
++endif
+ DISTCHECK_CONFIGURE_FLAGS = --disable-tests --without-system-root-install
+diff --git a/configure.ac b/configure.ac
+index 2ab0893..9c8f863 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -6,7 +6,7 @@ AC_CONFIG_AUX_DIR(build-tools)
+ AC_USE_SYSTEM_EXTENSIONS
+ AC_SYS_LARGEFILE
+ AC_PROG_AWK
+-AC_PROG_CC
++AC_PROG_CC_STDC
+ AM_PROG_CC_C_O
+ AC_HEADER_STDC
+ AC_C_CONST
+@@ -16,7 +16,7 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+ AM_MAINTAINER_MODE([enable])
+ PKG_PROG_PKG_CONFIG
+-LT_INIT
++LT_INIT([dlopen disable-static pic-only])
+ ## increment if the interface has additions, changes, removals.
+ LT_CURRENT=3
+@@ -38,12 +38,19 @@ PKG_CHECK_MODULES(IMAGE, [libpng >= 1.2.16 ])
+ AC_SUBST(IMAGE_CFLAGS)
+ AC_SUBST(IMAGE_LIBS)
++PKG_CHECK_MODULES(UDEV, [libudev]);
++AC_SUBST(UDEV_CFLAGS)
++AC_SUBST(UDEV_LIBS)
++
+ PLYMOUTH_CFLAGS=""
+ PLYMOUTH_LIBS="-lm -lrt -ldl"
+ AC_SUBST(PLYMOUTH_CFLAGS)
+ AC_SUBST(PLYMOUTH_LIBS)
++AC_PATH_PROG([SYSTEMD_ASK_PASSWORD_AGENT], [systemd-tty-ask-password-agent])
++AC_PATH_PROG([UDEVADM], [udevadm])
++
+ AC_ARG_ENABLE(pango, AS_HELP_STRING([--enable-pango],[enable building with pango, disabled there is no encryption prompts]),enable_pango=$enableval,enable_pango=yes)
+ AM_CONDITIONAL(ENABLE_PANGO,  [test "$enable_pango" = yes])
+@@ -62,148 +69,6 @@ if test x$enable_gtk = xyes; then
+   AC_SUBST(GTK_LIBS)
+ fi
+-AC_ARG_ENABLE(libdrm_intel, AS_HELP_STRING([--enable-libdrm_intel],[enable building with libdrm_intel support]),enable_libdrm_intel=$enableval,enable_libdrm_intel=no)
+-AM_CONDITIONAL(ENABLE_LIBDRM_INTEL,  [test "$enable_libdrm_intel" = yes])
+-
+-if test x$enable_libdrm_intel = xyes; then
+-  PKG_CHECK_MODULES(DRM_INTEL, [libdrm libdrm_intel])
+-  OLD_CFLAGS="$CFLAGS"
+-  CFLAGS="$CFLAGS $DRM_INTEL_CFLAGS"
+-  AC_MSG_CHECKING([if i915_drm.h is in include path])
+-  AC_COMPILE_IFELSE(AC_LANG_PROGRAM(
+-  [[
+-    #include <stdint.h>
+-    #include <stdlib.h>
+-    #include "i915_drm.h"
+-  ]],[[]]),[found_drm_intel_kernel_headers=yes],[found_drm_intel_kernel_headers=no])
+-
+-  if test "$found_drm_intel_kernel_headers" = "yes"; then
+-    AC_MSG_RESULT([yes])
+-  else
+-    AC_MSG_RESULT([no])
+-    AC_MSG_CHECKING([if we can find them anyway])
+-
+-    MORE_DRM_CFLAGS="-I`$PKG_CONFIG --variable includedir libdrm`/drm"
+-    CFLAGS="$CFLAGS $MORE_DRM_CFLAGS"
+-    AC_COMPILE_IFELSE(AC_LANG_PROGRAM(
+-    [[
+-      #include <stdint.h>
+-      #include <stdlib.h>
+-      #include "i915_drm.h"
+-    ]],[[]]),[found_drm_intel_kernel_headers=yes],[found_drm_intel_kernel_headers=no])
+-
+-    if test "$found_drm_intel_kernel_headers" = "yes"; then
+-      AC_MSG_RESULT([yes])
+-      DRM_INTEL_CFLAGS="$DRM_INTEL_CFLAGS $MORE_DRM_CFLAGS"
+-    else
+-      AC_MSG_RESULT([no])
+-      AC_MSG_ERROR([Could not find i915_drm.h])
+-    fi
+-  fi
+-
+-  AC_SUBST(DRM_INTEL_CFLAGS)
+-  AC_SUBST(DRM_INTEL_LIBS)
+-  AC_DEFINE(PLY_ENABLE_LIBDRM_INTEL, 1, [Enable support for libdrm_intel driver])
+-fi
+-
+-AC_ARG_ENABLE(libdrm_radeon, AS_HELP_STRING([--enable-libdrm_radeon],[enable building with libdrm_radeon support]),enable_libdrm_radeon=$enableval,enable_libdrm_radeon=no)
+-AM_CONDITIONAL(ENABLE_LIBDRM_RADEON,  [test "$enable_libdrm_radeon" = yes])
+-
+-if test x$enable_libdrm_radeon = xyes; then
+-  PKG_CHECK_MODULES(DRM_RADEON, [libdrm libdrm_radeon])
+-  OLD_CFLAGS="$CFLAGS"
+-  CFLAGS="$CFLAGS $DRM_RADEON_CFLAGS"
+-  AC_MSG_CHECKING([if radeon_drm.h is in include path])
+-  AC_COMPILE_IFELSE(AC_LANG_PROGRAM(
+-  [[
+-    #include <stdint.h>
+-    #include <stdlib.h>
+-    #include "radeon_drm.h"
+-  ]],[[]]),[found_drm_radeon_kernel_headers=yes],[found_drm_radeon_kernel_headers=no])
+-
+-  if test "$found_drm_radeon_kernel_headers" = "yes"; then
+-    AC_MSG_RESULT([yes])
+-  else
+-    AC_MSG_RESULT([no])
+-    AC_MSG_CHECKING([if we can find them anyway])
+-
+-    MORE_DRM_CFLAGS="-I`$PKG_CONFIG --variable includedir libdrm`/drm"
+-    CFLAGS="$CFLAGS $MORE_DRM_RADEON_CFLAGS"
+-    AC_COMPILE_IFELSE(AC_LANG_PROGRAM(
+-    [[
+-      #include <stdint.h>
+-      #include <stdlib.h>
+-      #include "radeon_drm.h"
+-    ]],[[]]),[found_drm_radeon_kernel_headers=yes],[found_drm_radeon_kernel_headers=no])
+-
+-    if test "$found_drm_radeon_kernel_headers" = "yes"; then
+-      AC_MSG_RESULT([yes])
+-      DRM_RADEON_CFLAGS="$DRM_RADEON_CFLAGS $MORE_DRM_CFLAGS"
+-    else
+-      AC_MSG_RESULT([no])
+-      AC_MSG_ERROR([Could not find radeon_drm.h])
+-    fi
+-  fi
+-
+-  AC_SUBST(DRM_RADEON_CFLAGS)
+-  AC_SUBST(DRM_RADEON_LIBS)
+-  AC_DEFINE(PLY_ENABLE_LIBDRM_RADEON, 1, [Enable support for libdrm_radeon driver])
+-fi
+-
+-AC_ARG_ENABLE(libdrm_nouveau, AS_HELP_STRING([--enable-libdrm_nouveau],[enable building with libdrm_nouveau support]),enable_libdrm_nouveau=$enableval,enable_libdrm_nouveau=no)
+-AM_CONDITIONAL(ENABLE_LIBDRM_NOUVEAU,  [test "$enable_libdrm_nouveau" = yes])
+-
+-if test x$enable_libdrm_nouveau = xyes; then
+-  PKG_CHECK_MODULES(DRM_NOUVEAU, [libdrm libdrm_nouveau])
+-  OLD_CFLAGS="$CFLAGS"
+-  CFLAGS="$CFLAGS $DRM_NOUVEAU_CFLAGS"
+-  AC_MSG_CHECKING([if nouveau_drm.h is in include path])
+-  AC_COMPILE_IFELSE(AC_LANG_PROGRAM(
+-  [[
+-    #include <stdint.h>
+-    #include <stdlib.h>
+-    #include "nouveau_drm.h"
+-  ]],[[]]),[found_drm_nouveau_kernel_headers=yes],[found_drm_nouveau_kernel_headers=no])
+-
+-  if test "$found_drm_nouveau_kernel_headers" = "yes"; then
+-    AC_MSG_RESULT([yes])
+-  else
+-    AC_MSG_RESULT([no])
+-    AC_MSG_CHECKING([if we can find them anyway])
+-
+-    MORE_DRM_CFLAGS="-I`$PKG_CONFIG --variable includedir libdrm`/drm"
+-    CFLAGS="$CFLAGS $MORE_DRM_CFLAGS"
+-    AC_COMPILE_IFELSE(AC_LANG_PROGRAM(
+-    [[
+-      #include <stdint.h>
+-      #include <stdlib.h>
+-      #include "nouveau_drm.h"
+-    ]],[[]]),[found_drm_nouveau_kernel_headers=yes],[found_drm_nouveau_kernel_headers=no])
+-
+-    if test "$found_drm_nouveau_kernel_headers" = "yes"; then
+-      AC_MSG_RESULT([yes])
+-      DRM_NOUVEAU_CFLAGS="$DRM_NOUVEAU_CFLAGS $MORE_DRM_CFLAGS"
+-    else
+-      AC_MSG_RESULT([no])
+-      AC_MSG_ERROR([Could not find nouveau_drm.h])
+-    fi
+-  fi
+-
+-  AC_SUBST(DRM_NOUVEAU_CFLAGS)
+-  AC_SUBST(DRM_NOUVEAU_LIBS)
+-  AC_DEFINE(PLY_ENABLE_LIBDRM_NOUVEAU, 1, [Enable support for libdrm_nouveau driver])
+-fi
+-
+-AC_ARG_ENABLE(libkms, AS_HELP_STRING([--enable-libkms],[enable building with libkms support]),enable_libkms=$enableval,enable_libkms=no)
+-AM_CONDITIONAL(ENABLE_LIBKMS,  [test "$enable_libkms" = yes])
+-
+-if test x$enable_libkms = xyes; then
+-  PKG_CHECK_MODULES(LIBKMS, [libdrm libkms])
+-  AC_SUBST(LIBKMS_CFLAGS)
+-  AC_SUBST(LIBKMS_LIBS)
+-  AC_DEFINE(PLY_ENABLE_LIBKMS, 1, [Enable support for libkms abstraction over drm drivers])
+-fi
+-
+ AC_ARG_ENABLE(drm, AS_HELP_STRING([--enable-drm-renderer],[enable building drm kms support]),enable_drm_renderer=$enableval,enable_drm_renderer=yes)
+ AM_CONDITIONAL(ENABLE_DRM_RENDERER,  [test "$enable_drm_renderer" = yes])
+@@ -211,10 +76,17 @@ if test x$enable_drm_renderer = xyes; then
+   PKG_CHECK_MODULES(DRM, [libdrm])
+ fi
+-DRM_CFLAGS="$DRM_CFLAGS $DRM_INTEL_CFLAGS $DRM_RADEON_CFLAGS $DRM_NOUVEAU_CFLAGS $LIBKMS_CFLAG"
+-DRM_LIBS="$DRM_LIBS $DRM_INTEL_LIBS $DRM_RADEON_LIBS $DRM_NOUVEAU_LIBS $LIBKMS_LIBS"
+-AC_SUBST(DRM_CFLAGS)
+-AC_SUBST(DRM_LIBS)
++AC_ARG_ENABLE(documentation,
++              AS_HELP_STRING([--enable-documentation],
++                             [build documentation]),,
++              enable_documentation=yes)
++if test x$enable_documentation = xyes; then
++   AC_PATH_PROG([XSLTPROC], [xsltproc])
++   if test x$XSLTPROC = x; then
++      AC_MSG_ERROR([xsltproc is required to build documentation])
++   fi
++fi
++AM_CONDITIONAL(BUILD_DOCUMENTATION, test x$enable_documentation = xyes)
+ AC_ARG_ENABLE(tracing, AS_HELP_STRING([--enable-tracing],[enable verbose tracing code]),enable_tracing=$enableval,enable_tracing=yes)
+@@ -222,10 +94,6 @@ if test x$enable_tracing = xyes; then
+   AC_DEFINE(PLY_ENABLE_TRACING, 1, [Build in verbose debug tracing spew])
+ fi
+-AC_ARG_ENABLE(tests, AS_HELP_STRING([--enable-tests],[build tests]),enable_tests=$enableval,enable_tests=yes)
+-
+-AM_CONDITIONAL(ENABLE_TESTS,  [test "$enable_tests" = yes])
+-
+ AC_ARG_ENABLE(gdm-transition, AS_HELP_STRING([--enable-gdm-transition],[enable smooth transition to gdm]),enable_gdm_transition=$enableval,enable_gdm_transition=no)
+ if test x$enable_gdm_transition = xyes; then
+@@ -254,7 +122,7 @@ AM_CONDITIONAL(ENABLE_SYSTEMD_INTEGRATION, [test "$enable_systemd_integration" =
+ if test x$enable_systemd_integration = xyes; then
+   AC_DEFINE(PLY_ENABLE_SYSTEMD_INTEGRATION, 1, [Coordinate boot up with systemd])
+-  SYSTEMD_UNIT_DIR=/lib/systemd/system
++  SYSTEMD_UNIT_DIR=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)
+   AC_SUBST(SYSTEMD_UNIT_DIR)
+ fi
+@@ -278,7 +146,7 @@ AS_AC_EXPAND(PLYMOUTH_CLIENT_DIR, $plymouthclientdir)
+ AS_AC_EXPAND(PLYMOUTH_DAEMON_DIR, $plymouthdaemondir)
+ AS_AC_EXPAND(PLYMOUTH_RUNTIME_DIR, $plymouthruntimedir)
+-AC_ARG_WITH(rhgb-compat-link, AS_HELP_STRING([--with-rhgb-compat-link],[Install /usr/bin/rhgb-client compatability symlink]),with_rhgb_compat_link=${withval},with_rhgb_compat_link=yes)
++AC_ARG_WITH(rhgb-compat-link, AS_HELP_STRING([--with-rhgb-compat-link],[Install /usr/bin/rhgb-client compatability symlink]),with_rhgb_compat_link=${withval},with_rhgb_compat_link=no)
+ AM_CONDITIONAL(WITH_RHGB_COMPAT_LINK,  [test "$with_rhgb_compat_link" = yes])
+ AC_ARG_WITH(log-viewer, AS_HELP_STRING([--with-log-viewer],[Install plymouth log viewer]),with_log_viewer=${withval},with_log_viewer=no)
+@@ -328,7 +196,7 @@ AC_DEFUN([PLYMOUTH_CC_TRY_FLAG], [
+   plymouth_save_CFLAGS="$CFLAGS"
+   CFLAGS="$CFLAGS $1"
+-  AC_COMPILE_IFELSE([ ], [plymouth_cc_flag=yes], [plymouth_cc_flag=no])
++  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]], [[ ]])], [plymouth_cc_flag=yes], [plymouth_cc_flag=no])
+   CFLAGS="$plymouth_save_CFLAGS"
+   if test "x$plymouth_cc_flag" = "xyes"; then
+@@ -357,7 +225,7 @@ if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then
+    -Wchar-subscripts -Wmissing-declarations -Wmissing-prototypes \
+    -Wwrite-strings -Wnested-externs -Wpointer-arith \
+    -Wswitch-enum -Wstrict-aliasing=2 -Winit-self -Wunsafe-loop-optimizations \
+-   -Wno-missing-field-initializers -Wno-unused-parameter \
++   -Wno-missing-field-initializers -Wno-unused-parameter -Wno-unused-result \
+    -Wcast-align -Wsign-compare -Wp,-D_FORTIFY_SOURCE=2"
+ elif test "$GCC" = "yes"; then
+   AC_MSG_RESULT(no)
+@@ -427,6 +295,7 @@ AC_CONFIG_FILES([Makefile
+            src/plugins/splash/Makefile
+            src/plugins/splash/throbgress/Makefile
+            src/plugins/splash/fade-throbber/Makefile
++           src/plugins/splash/tribar/Makefile
+            src/plugins/splash/text/Makefile
+            src/plugins/splash/details/Makefile
+            src/plugins/splash/space-flares/Makefile
+@@ -439,12 +308,10 @@ AC_CONFIG_FILES([Makefile
+            src/client/Makefile
+            src/viewer/Makefile
+            src/upstart-bridge/Makefile
+-           src/tests/Makefile
+-           src/libply/tests/Makefile
+-           src/client/tests/Makefile
+            themes/Makefile
+            themes/spinfinity/Makefile
+            themes/fade-in/Makefile
++           themes/tribar/Makefile
+            themes/text/Makefile
+            themes/details/Makefile
+            themes/solar/Makefile
+diff --git a/docs/Makefile.am b/docs/Makefile.am
+index dedda55..1a9f7ea 100644
+--- a/docs/Makefile.am
++++ b/docs/Makefile.am
+@@ -1,4 +1,31 @@
+-dist_man_MANS = plymouth.8
++XSLTPROC_FLAGS = \
++        --nonet \
++        --stringparam man.output.quietly 1 \
++        --stringparam funcsynopsis.style ansi \
++        --stringparam man.th.extra1.suppress 1 \
++        --stringparam man.authors.section.enabled 0 \
++        --stringparam man.copyright.section.enabled 0
+-%.html: %.txt
+-      asciidoc $(ASCIIDOC_OPTS) -a toc $*.txt
++
++plymouth.1: plymouth1.xml
++      $(AM_V_GEN) $(XSLTPROC) $(XSLTPROC_FLAGS) http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
++
++%.8: %.xml
++      $(AM_V_GEN) $(XSLTPROC) $(XSLTPROC_FLAGS) http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
++      
++%.1: %.xml
++      $(AM_V_GEN) $(XSLTPROC) $(XSLTPROC_FLAGS) http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
++      
++man_MANS = \
++      plymouth.1 \
++      plymouth.8 \
++      plymouthd.8 \
++      plymouth-set-default-theme.1
++
++EXTRA_DIST = \
++      plymouth.xml \
++      plymouth1.xml \
++      plymouth-set-default-theme.xml \
++      plymouthd.xml
++
++CLEANFILES = $(man_MANS)
+diff --git a/docs/plymouth-set-default-theme.xml b/docs/plymouth-set-default-theme.xml
+new file mode 100644
+index 0000000..efb051e
+--- /dev/null
++++ b/docs/plymouth-set-default-theme.xml
+@@ -0,0 +1,103 @@
++<?xml version='1.0'?>
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
++        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
++
++<refentry id="plymouth-set-default-theme">
++
++        <refentryinfo>
++                <title>plymouth-set-default-theme</title>
++                <productname>plymouth</productname>
++
++                <authorgroup>
++                        <author>
++                                <contrib>Developer</contrib>
++                                <firstname>Kristian</firstname>
++                                <surname>Høgsberg</surname>
++                        </author>
++                        <author>
++                                <contrib>Developer</contrib>
++                                <firstname>Ray</firstname>
++                                <surname>Strode</surname>
++                        </author>
++                </authorgroup>
++
++        </refentryinfo>
++
++        <refmeta>
++                <refentrytitle>plymouth-set-default-theme</refentrytitle>
++                <manvolnum>1</manvolnum>
++                <refmiscinfo class="manual">User Commands</refmiscinfo>
++        </refmeta>
++
++        <refnamediv>
++                <refname>plymouth-set-default-theme</refname>
++                <refpurpose>Set the plymouth theme</refpurpose>
++        </refnamediv>
++
++        <refsynopsisdiv>
++                <cmdsynopsis>
++                        <command>plymouth-set-default-theme <arg choice="opt" rep="repeat">OPTION</arg> <arg choice="opt" rep="norepeat">THEME</arg></command>
++                </cmdsynopsis>
++        </refsynopsisdiv>
++
++        <refsect1>
++                <title>Description</title>
++
++<para>
++When called with a <option>THEME</option> argument,
++the <command>plymouth-set-default-theme</command> command
++changes the preferred boot theme and also performs the necessary
++regeneration of the initial ramdisk (initrd) since plymouth is loaded
++from the boot loader from the initrd prior to the mounting of the root
++filesystem.
++</para>
++
++<para>
++If <command>plymouth-set-default-theme</command> is invoked with no options
++or parameters, it shows the currently selected theme by default. This output
++is used by the helper scripts plymouth-generate-initrd and
++plymouth-update-initrd to set the proper theme in the initial ramdisk.
++</para>
++
++        </refsect1>
++
++        <refsect1>
++                <title>Options</title>
++
++                <para>The following options are understood:</para>
++
++                <variablelist>
++                        <varlistentry>
++                                <term><option>-h</option>, <option>--help</option></term>
++                                <listitem><para>Show summary of options.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>-l</option>, <option>--list</option></term>
++                                <listitem><para>List available themes.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>-r</option>, <option>--reset</option></term>
++                                <listitem><para>Reset to default theme.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>-R</option>, <option>--rebuild-initrd</option></term>
++                                <listitem><para>Rebuild initrd (necessary after changing theme).</para></listitem>
++                        </varlistentry>
++                </variablelist>
++        </refsect1>
++
++        <refsect1>
++                <title>See Also</title>
++                <para>
++                        <citerefentry><refentrytitle>grub</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++                        <citerefentry><refentrytitle>plymouth</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++                        <citerefentry><refentrytitle>plymouthd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++                        <citerefentry><refentrytitle>plymouth</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
++                        <ulink url="http://www.freedesktop.org/wiki/Software/Plymouth">http://www.freedesktop.org/wiki/Software/Plymouth</ulink>
++                </para>
++        </refsect1>
++
++</refentry>
+diff --git a/docs/plymouth.8 b/docs/plymouth.8
+deleted file mode 100644
+index 7f4766b..0000000
+--- a/docs/plymouth.8
++++ /dev/null
+@@ -1,62 +0,0 @@
+-\"                                      Hey, EMACS: -*- nroff -*-
+-.TH PLYMOUTH 8 "December 15, 2009"
+-.SH NAME
+-plymouth \- A graphical boot system and logger
+-.SH SYNOPSIS
+-.B plymouth-set-default-theme
+-.RI [ options ] " \<theme\>"
+-.SH DESCRIPTION
+-\fBplymouth\fP is a graphical boot system for Linux which takes advantage of the kernel-based
+-mode setting (KMS) available for modern graphic cards to provide a seamless, flickerfree
+-and attractive boot screen. It allows to choose between various, static or
+-animated graphical themes to spruce up the startup and avoid the noise
+-generated by the vast amount of kernel messages while the machine boots into X.
+-On systems where kernel-based mode setting is not available, plymouth falls
+-back to a text mode boot screen which provides a simple progress bar to provide
+-feedback during boot.
+-.PP
+-To configure plymouth, that is to choose and install the preferred boot theme, the
+-user has to invoke \fBplymouth-set-default-theme\fP. It changes the configuration
+-to the new theme and also performs the necessary regeneration of the initial ramdisk
+-(initrd) since plymouth is loaded from the boot loader from the initrd
+-prior to the mounting of the root filesystem. The options available to this
+-script are explained in the \fBOPTIONS\fP paragraph.
+-.PP
+-In order for the configured default plymouth theme to be loaded during boot,
+-the option `splash' (or `rhgb' for backward compatibility with the RHGB boot
+-splash) must be provided at the kernel command line.  With this command line
+-option, plymouth will default to showing detailed boot output.
+-.SH OPTIONS
+-plymouth-set-default-theme follows the usual GNU command line syntax, with long
+-options starting with two dashes (`-') and short variants of each of them.
+-.TP
+-.B \-h, \-\-help
+-Show summary of options.
+-.TP
+-.B \-l, \-\-list
+-List available themes.
+-.TP
+-.B \-r, \-\-reset
+-Reset to default theme.
+-.TP
+-.B \-R, \-\-rebuild\-initrd
+-Rebuild initrd (necessary after changing theme).
+-.TP
+-.B \<theme-name\>
+-Name of new theme to use. If you want to see which themes are available, invoke the script with just \-\-list.
+-.PP
+-If plymouth-set-default-theme is invoked with no options or parameters, it shows the currently selected theme
+-by default. This output is used by the helper scripts `plymouth-generate-initrd' and `plymouth-update-initrd'
+-to set the proper theme in the initial ramdisk.
+-.SH SEE ALSO
+-.BR grub (8)
+-.br
+-.SH AUTHOR
+-plymouth was originally prototyped and named by Kristian Høgsberg <krh@bitplanet.net>,
+-originally written by Ray Strode <halfline@gmail.com> and has had significant contributions
+-from Charlie Brej <cbrej@cs.man.ac.uk>.  It has also had contributions from
+-Peter Jones <pjones@redhat.com>, Adam Jackson <ajax@nwnk.net>,
+-Frederic Crozat <fcrozat@mandriva.com> and others.
+-It can be downloaded here: <http://www.freedesktop.org/wiki/Software/Plymouth>.
+-.PP
+-This manual page was written by Adrian Glaubitz <glaubitz@physik.fu-berlin.de>.
+diff --git a/docs/plymouth.xml b/docs/plymouth.xml
+new file mode 100644
+index 0000000..0f196c6
+--- /dev/null
++++ b/docs/plymouth.xml
+@@ -0,0 +1,86 @@
++<?xml version='1.0'?>
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
++        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
++
++<refentry id="plymouth">
++
++        <refentryinfo>
++                <title>plymouth</title>
++                <productname>plymouth</productname>
++
++                <authorgroup>
++                        <author>
++                                <contrib>Developer</contrib>
++                                <firstname>Kristian</firstname>
++                                <surname>Høgsberg</surname>
++                        </author>
++                        <author>
++                                <contrib>Developer</contrib>
++                                <firstname>Ray</firstname>
++                                <surname>Strode</surname>
++                        </author>
++                </authorgroup>
++
++        </refentryinfo>
++
++        <refmeta>
++                <refentrytitle>plymouth</refentrytitle>
++                <manvolnum>8</manvolnum>
++                <refmiscinfo class="manual">System Administration</refmiscinfo>
++        </refmeta>
++
++        <refnamediv>
++                <refname>plymouth</refname>
++                <refpurpose>A graphical boot system and logger</refpurpose>
++        </refnamediv>
++
++        <refsect1>
++                <title>Description</title>
++
++<para>
++<command>plymouth</command> is a graphical boot system for Linux which takes advantage of
++the kernel-based mode setting (KMS) available for modern graphic  cards
++to  provide  a  seamless,  flickerfree  and  attractive boot screen. It
++allows to choose between various, static or animated  graphical  themes
++to  spruce  up  the  startup  and avoid the noise generated by the vast
++amount of kernel messages while the machine boots into X.   On  systems
++where  kernel-based  mode setting is not available, plymouth falls back
++to a text mode boot screen which provides a simple progress bar to pro‐
++vide feedback during boot.
++</para>
++<para>
++In order for the configured default plymouth theme to be loaded during
++boot, the option `splash' (or `rhgb' for  backward  compatibility  with
++the RHGB  boot  splash) must be provided at the kernel command line.
++Without this command line option, plymouth will default to showing
++detailed boot output.
++</para>
++
++<para>
++During the boot process, the user can switch between the graphical theme
++and the detailed boot output using the Escape key.
++</para>
++
++        </refsect1>
++
++        <refsect1>
++                <title>See Also</title>
++                <para>
++                        <citerefentry><refentrytitle>grub</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++                        <citerefentry><refentrytitle>plymouth-set-theme</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
++                        <citerefentry><refentrytitle>plymouthd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++                        <citerefentry><refentrytitle>plymouth</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
++                        <ulink url="http://www.freedesktop.org/wiki/Software/Plymouth">http://www.freedesktop.org/wiki/Software/Plymouth</ulink>
++                </para>
++        </refsect1>
++
++        <refsect1>
++                <title>Authors</title>
++                <para>
++plymouth  was  originally  prototyped  and  named  by Kristian Høgsberg,
++originally written by Ray Strode and has had significant contributions from
++Charlie Brej. It has also had contributions from Peter Jones, Adam Jackson,
++Frederic Crozat and others.
++                </para>
++        </refsect1>
++</refentry>
+diff --git a/docs/plymouth1.xml b/docs/plymouth1.xml
+new file mode 100644
+index 0000000..b484599
+--- /dev/null
++++ b/docs/plymouth1.xml
+@@ -0,0 +1,351 @@
++<?xml version='1.0'?>
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
++        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
++
++<refentry id="plymouth-set-default-theme">
++
++        <refentryinfo>
++                <title>plymouth</title>
++                <productname>plymouth</productname>
++
++                <authorgroup>
++                        <author>
++                                <contrib>Developer</contrib>
++                                <firstname>Kristian</firstname>
++                                <surname>Høgsberg</surname>
++                        </author>
++                        <author>
++                                <contrib>Developer</contrib>
++                                <firstname>Ray</firstname>
++                                <surname>Strode</surname>
++                        </author>
++                </authorgroup>
++
++        </refentryinfo>
++
++        <refmeta>
++                <refentrytitle>plymouth</refentrytitle>
++                <manvolnum>1</manvolnum>
++                <refmiscinfo class="manual">User Commands</refmiscinfo>
++        </refmeta>
++
++        <refnamediv>
++                <refname>plymouth</refname>
++                <refpurpose>Send commands to plymouthd</refpurpose>
++        </refnamediv>
++
++        <refsynopsisdiv>
++                <cmdsynopsis>
++                        <command>plymouth <arg choice="opt" rep="repeat">OPTION</arg></command>
++                </cmdsynopsis>
++                <cmdsynopsis>
++                        <command>plymouth <arg choice="plain">COMMAND <arg choice="opt" rep="repeat">OPTION</arg></arg></command>
++                </cmdsynopsis>
++        </refsynopsisdiv>
++
++        <refsect1>
++                <title>Description</title>
++
++<para>
++The <command>plymouth</command> sends commands to a running
++<command>plymouthd</command>. This is used during the boot
++process to control the display of the graphical boot splash.
++</para>
++
++        </refsect1>
++
++        <refsect1>
++                <title>Options</title>
++
++                <para>
++The following options are understood. These options are supported
++for compatibility with the old <command>rhgb-client</command> interface,
++and have been replaced by the commands that are described in the
++next section.
++</para>
++
++                <variablelist>
++                        <varlistentry>
++                                <term><option>--help</option></term>
++                                <listitem><para>Show summary of options.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--debug</option></term>
++                                <listitem><para>Enable verbose debug logging.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--get-splash-plugin-path</option></term>
++                                <listitem><para>Get directory where splash plugins are installed.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--newroot=<arg>STRING</arg></option></term>
++                                <listitem><para>Tell plymouthd that the new root filesystem is mounted.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--quit</option></term>
++                                <listitem><para>Tell plymouthd to quit.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--ping</option></term>
++                                <listitem><para>Check if plymouthd is running.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--has-active-vt</option></term>
++                                <listitem><para>Check if plymouthd has an active vt.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--sysinit</option></term>
++                                <listitem><para>Tell plymouthd root filesystem is mounted read-write.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--show-splash</option></term>
++                                <listitem><para>Show the splash screen.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--hide-splash</option></term>
++                                <listitem><para>Hide the splash screen.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--ask-for-password</option></term>
++                                <listitem><para>Ask the user for a password.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--ignore-keystroke=<arg>STRING</arg></option></term>
++                                <listitem><para>Remove sensitivity to a keystroke.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--update=<arg>STRING</arg></option></term>
++                                <listitem><para>Tell plymouthd an update about boot progress.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--details</option></term>
++                                <listitem><para>Tell plymouthd there were errors during boot.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--wait</option></term>
++                                <listitem><para>Wait for plymouthd to quit.</para></listitem>
++                        </varlistentry>
++                </variablelist>
++        </refsect1>
++
++        <refsect1>
++              <title>Commands</title>
++
++<para>
++The following commands are understood:
++</para>
++                <variablelist>
++                        <varlistentry>
++                                <term><command>change-mode <arg choice="plain">OPTION</arg></command></term>
++                                <listitem><para>Change the operation mode.</para>
++<variablelist>
++<varlistentry>
++  <term><option>--boot-up</option></term>
++  <listitem><para>Start the system up</para></listitem>
++</varlistentry>
++<varlistentry>
++  <term><option>--shutdown</option></term>
++  <listitem><para>Shutting the system up</para></listitem>
++</varlistentry>
++<varlistentry>
++  <term><option>--updates</option></term>
++  <listitem><para>Applying updates</para></listitem>
++</varlistentry>
++</variablelist>
++</listitem>
++                        </varlistentry>
++                        <varlistentry>
++                                <term><command>system-update <arg choice="plain">OPTION</arg></command></term>
++                                <listitem><para>Tell plymouthd about boot progress.</para>
++<variablelist>
++<varlistentry>
++  <term><option>--progress=INTEGER</option></term>
++  <listitem><para>The percentage progress of the updates</para></listitem>
++</varlistentry>
++</variablelist>
++</listitem>
++                        </varlistentry>
++                        <varlistentry>
++                                <term><command>update <arg choice="plain">OPTION</arg></command></term>
++                                <listitem><para>Tell plymouthd about boot status changes.</para>
++<variablelist>
++<varlistentry>
++  <term><option>--status=STRING</option></term>
++  <listitem><para>Tell plymouthd the current boot status</para></listitem>
++</varlistentry>
++</variablelist>
++</listitem>
++                        </varlistentry>
++                        <varlistentry>
++                                <term><command>update-root-fs <arg choice="plain">OPTION</arg></command></term>
++                                <listitem><para>Tell plymouthd about root filesystem changes.</para>
++<variablelist>
++<varlistentry>
++  <term><option>--new-root-dir=STRING</option></term>
++  <listitem><para>Root filesystem is about to change</para></listitem>
++</varlistentry>
++<varlistentry>
++  <term><option>--read-write</option></term>
++  <listitem><para>Root filesystem is no longer read-only</para></listitem>
++</varlistentry>
++</variablelist>
++</listitem>
++                        </varlistentry>
++                        <varlistentry>
++                                <term><command>show-splash</command></term>
++                                <listitem><para>Tell plymouthd to show splash screen.</para></listitem>
++                        </varlistentry>
++                        <varlistentry>
++                                <term><command>hide-splash</command></term>
++                                <listitem><para>Tell plymouthd to hide splash screen.</para></listitem>
++                        </varlistentry>
++                        <varlistentry>
++                                <term><command>ask-for-password <arg choice="plain">OPTION</arg></command></term>
++                                <listitem><para>Ask the user for a password.</para>
++<variablelist>
++<varlistentry>
++  <term><option>--command=STRING</option></term>
++  <listitem><para>Command to send password to via standard input</para></listitem>
++</varlistentry>
++<varlistentry>
++  <term><option>--prompt=STRING</option></term>
++  <listitem><para>Message to display when asking for password</para></listitem>
++</varlistentry>
++<varlistentry>
++  <term><option>--number-of-tries=INTEGER</option></term>
++  <listitem><para>Number of times to ask before giving up (requires <option>--command</option>)</para></listitem>
++</varlistentry>
++<varlistentry>
++  <term><option>--dont-pause-progress</option></term>
++  <listitem><para>Don't pause boot progress bar while asking</para></listitem>
++</varlistentry>
++</variablelist>
++</listitem>
++                        </varlistentry>
++                        <varlistentry>
++                                <term><command>ask-question</command></term>
++                                <listitem><para>Ask the user a question.</para>
++<variablelist>
++<varlistentry>
++  <term><option>--command=STRING</option></term>
++  <listitem><para>Command to send the answer to via standard input</para></listitem>
++</varlistentry>
++<varlistentry>
++  <term><option>--prompt=STRING</option></term>
++  <listitem><para>Message to display when asking the question</para></listitem>
++</varlistentry>
++<varlistentry>
++  <term><option>--dont-pause-progress</option></term>
++  <listitem><para>Don't pause boot progress bar while asking</para></listitem>
++</varlistentry>
++</variablelist>
++</listitem>
++                        </varlistentry>
++                        <varlistentry>
++                                <term><command>display-message <arg choice="plain">OPTION</arg></command></term>
++                                <listitem><para>Display a message.</para>
++<variablelist>
++<varlistentry>
++  <term><option>--text=STRING</option></term>
++  <listitem><para>The message text</para></listitem>
++</varlistentry>
++</variablelist>
++</listitem>
++                        </varlistentry>
++                        <varlistentry>
++                                <term><command>hide-message <arg choice="plain">OPTION</arg></command></term>
++                                <listitem><para>Hide a message.</para>
++<variablelist>
++<varlistentry>
++  <term><option>--text=STRING</option></term>
++  <listitem><para>The message text</para></listitem>
++</varlistentry>
++</variablelist>
++</listitem>
++                        </varlistentry>
++                        <varlistentry>
++                                <term><command>watch-keystroke <arg choice="plain">OPTION</arg></command></term>
++                                <listitem><para>Become sensitive to a keystroke.</para>
++<variablelist>
++<varlistentry>
++  <term><option>--command=STRING</option></term>
++  <listitem><para>Command to send keystroke to via standard input</para></listitem>
++</varlistentry>
++<varlistentry>
++  <term><option>--keys=STRING</option></term>
++  <listitem><para>Keys to become sensitive to</para></listitem>
++</varlistentry>
++</variablelist>
++</listitem>
++                        </varlistentry>
++                        <varlistentry>
++                                <term><command>ignore-keystroke <arg choice="plain">OPTION</arg></command></term>
++                                <listitem><para>Remove sensitivity to a keystroke.</para>
++<variablelist>
++<varlistentry>
++  <term><option>--keys=STRING</option></term>
++  <listitem><para>Keys to remove sensitivitiy from</para></listitem>
++</varlistentry>
++</variablelist>
++</listitem>
++                        </varlistentry>
++                        <varlistentry>
++                                <term><command>pause-progress</command></term>
++                                <listitem><para>Pause boot progress bar.</para></listitem>
++                        </varlistentry>
++                        <varlistentry>
++                                <term><command>unpause-progress</command></term>
++                                <listitem><para>Unpause boot progress bar.</para></listitem>
++                        </varlistentry>
++                        <varlistentry>
++                                <term><command>report-error</command></term>
++                                <listitem><para>Tell plymouthd there were errors during boot.</para></listitem>
++                        </varlistentry>
++                        <varlistentry>
++                                <term><command>deactivate</command></term>
++                                <listitem><para>Tell plymouthd to deactivate.</para></listitem>
++                        </varlistentry>
++                        <varlistentry>
++                                <term><command>reactivate</command></term>
++                                <listitem><para>Tell plymouthd to reactivate.</para></listitem>
++                        </varlistentry>
++                        <varlistentry>
++                                <term><command>quit <arg choice="plain">OPTION</arg></command></term>
++                                <listitem><para>Tell plymouthd to quit.</para>
++<variablelist>
++<varlistentry>
++  <term><option>--retain-splash</option></term>
++  <listitem><para>Don't explicitly hide boot splash on exit</para></listitem>
++</varlistentry>
++</variablelist>
++</listitem>
++                        </varlistentry>
++                </variablelist>
++
++        </refsect1>
++
++        <refsect1>
++                <title>See Also</title>
++                <para>
++                        <citerefentry><refentrytitle>grub</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++                        <citerefentry><refentrytitle>plymouth</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++                        <citerefentry><refentrytitle>plymouthd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++                        <ulink url="http://www.freedesktop.org/wiki/Software/Plymouth">http://www.freedesktop.org/wiki/Software/Plymouth</ulink>
++                </para>
++        </refsect1>
++
++</refentry>
+diff --git a/docs/plymouthd.xml b/docs/plymouthd.xml
+new file mode 100644
+index 0000000..4e7e499
+--- /dev/null
++++ b/docs/plymouthd.xml
+@@ -0,0 +1,121 @@
++<?xml version='1.0'?>
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
++        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
++
++<refentry id="plymouthd">
++
++        <refentryinfo>
++                <title>plymouthd</title>
++                <productname>plymouth</productname>
++
++                <authorgroup>
++                        <author>
++                                <contrib>Developer</contrib>
++                                <firstname>Kristian</firstname>
++                                <surname>Høgsberg</surname>
++                        </author>
++                        <author>
++                                <contrib>Developer</contrib>
++                                <firstname>Ray</firstname>
++                                <surname>Strode</surname>
++                        </author>
++                </authorgroup>
++
++        </refentryinfo>
++
++        <refmeta>
++                <refentrytitle>plymouthd</refentrytitle>
++                <manvolnum>8</manvolnum>
++                <refmiscinfo class="manual">System Administration</refmiscinfo>
++        </refmeta>
++
++        <refnamediv>
++                <refname>plymouthd</refname>
++                <refpurpose>The plymouth daemon</refpurpose>
++        </refnamediv>
++
++        <refsynopsisdiv>
++                <cmdsynopsis>
++                        <command>plymouthd <arg choice="opt" rep="repeat">OPTION</arg></command>
++                </cmdsynopsis>
++        </refsynopsisdiv>
++
++        <refsect1>
++                <title>Description</title>
++
++<para>
++The <command>plymouthd</command> daemon is usually run out of
++the initrd. It does the heavy lifting of the plymouth system, logging
++the session and showing the splash screen.
++</para>
++<para>
++The <command>plymouth</command> is used to send commands to plymouthd
++that control its behaviour.
++</para>
++
++        </refsect1>
++
++        <refsect1>
++                <title>Options</title>
++
++                <para>The following options are understood:</para>
++
++                <variablelist>
++                        <varlistentry>
++                                <term><option>--help</option></term>
++                                <listitem><para>Show summary of options.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--attach-to-session</option></term>
++                                <listitem><para>Redirect console messages from screen to log.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--no-daemon</option></term>
++                                <listitem><para>Do not daemonize.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--debug</option></term>
++                                <listitem><para>Output debugging information.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--debug-file=STRING</option></term>
++                                <listitem><para>File to write debugging information to.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--mode=MODE</option></term>
++                                <listitem><para>Set mode to either boot or shutdown.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--pid-file=STRING</option></term>
++                                <listitem><para>Write the PID of the daemon to a file.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--kernel-command-line=STRING</option></term>
++                                <listitem><para>Fake kernel commandline to use.</para></listitem>
++                        </varlistentry>
++
++                        <varlistentry>
++                                <term><option>--tty=STRING</option></term>
++                                <listitem><para>TTY to ues instead of default.</para></listitem>
++                        </varlistentry>
++                </variablelist>
++        </refsect1>
++
++        <refsect1>
++                <title>See Also</title>
++                <para>
++                        <citerefentry><refentrytitle>grub</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++                        <citerefentry><refentrytitle>plymouth</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++                        <citerefentry><refentrytitle>plymouth</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
++                        <ulink url="http://www.freedesktop.org/wiki/Software/Plymouth">http://www.freedesktop.org/wiki/Software/Plymouth</ulink>
++                </para>
++        </refsect1>
++
++</refentry>
+diff --git a/scripts/plymouth-generate-initrd.in b/scripts/plymouth-generate-initrd.in
+index 35509a1..c44ca4c 100755
+--- a/scripts/plymouth-generate-initrd.in
++++ b/scripts/plymouth-generate-initrd.in
+@@ -13,11 +13,12 @@ PLYMOUTH_INITRD_DIR="$(mktemp --tmpdir -d plymouth-XXXXXXX)"
+ $PLYMOUTH_POPULATE_INITRD -t "$PLYMOUTH_INITRD_DIR"
+ if [ $? -eq 0 ]; then
++    command -v pigz &>/dev/null && gzip=pigz || gzip=gzip
+     (cd $PLYMOUTH_INITRD_DIR;
+         # FIXME: might make sense to add a flag to plymouth-populate-initrd to
+         #        skip these from the start
+         rm -f lib*/{ld*,libc*,libdl*,libm*,libz*,libpthread*}
+-        find | cpio -Hnewc -o | gzip -9 > $PLYMOUTH_IMAGE_FILE
++        find | cpio -Hnewc -o | $gzip -9 > $PLYMOUTH_IMAGE_FILE
+     )
+ fi
+diff --git a/scripts/plymouth-populate-initrd.in b/scripts/plymouth-populate-initrd.in
+index 8d1eec0..43c7f22 100755
+--- a/scripts/plymouth-populate-initrd.in
++++ b/scripts/plymouth-populate-initrd.in
+@@ -8,6 +8,7 @@
+ [ -z "$PLYMOUTH_DATADIR" ] && PLYMOUTH_DATADIR="@PLYMOUTH_DATADIR@"
+ [ -z "$PLYMOUTH_PLUGIN_PATH" ] && PLYMOUTH_PLUGIN_PATH="$(plymouth --get-splash-plugin-path)"
+ [ -z "$PLYMOUTH_LOGO_FILE" ] && PLYMOUTH_LOGO_FILE="@PLYMOUTH_LOGO_FILE@"
++[ -n "$PLYMOUTH_THEME_NAME" ] && THEME_OVERRIDE=1
+ [ -z "$PLYMOUTH_THEME_NAME" ] && PLYMOUTH_THEME_NAME=$(plymouth-set-default-theme)
+ [ -z "$PLYMOUTH_CONFDIR" ] && PLYMOUTH_CONFDIR="@PLYMOUTH_CONF_DIR@"
+ [ -z "$PLYMOUTH_POLICYDIR" ] && PLYMOUTH_POLICYDIR="@PLYMOUTH_POLICY_DIR@"
+@@ -372,8 +373,8 @@ done
+ [ -z "$INITRDDIR" ] && usage error
+ mkdir -p ${INITRDDIR}${PLYMOUTH_DATADIR}/plymouth/themes
+-inst ${PLYMOUTH_DAEMON_PATH} $INITRDDIR /sbin/plymouthd
+-inst ${PLYMOUTH_CLIENT_PATH} $INITRDDIR /bin/plymouth
++inst ${PLYMOUTH_DAEMON_PATH} $INITRDDIR
++inst ${PLYMOUTH_CLIENT_PATH} $INITRDDIR
+ inst ${PLYMOUTH_DATADIR}/plymouth/themes/text/text.plymouth $INITRDDIR
+ inst ${PLYMOUTH_PLUGIN_PATH}/text.so $INITRDDIR
+ inst ${PLYMOUTH_DATADIR}/plymouth/themes/details/details.plymouth $INITRDDIR
+@@ -388,6 +389,12 @@ if [ -z "$PLYMOUTH_THEME_NAME" ]; then
+     exit 1
+ fi
++if [ $THEME_OVERRIDE ]; then
++    conf=$INITRDDIR/${PLYMOUTH_CONFDIR}/plymouthd.conf
++    echo "modifying plymouthd.conf: Theme=$PLYMOUTH_THEME_NAME" > /dev/stderr
++    sed -i "s/^ *Theme *=.*/# theme modified by plymouth-populate-initrd\nTheme=$PLYMOUTH_THEME_NAME/" $conf
++fi
++
+ PLYMOUTH_MODULE_NAME=$(grep "ModuleName *= *" ${PLYMOUTH_DATADIR}/plymouth/themes/${PLYMOUTH_THEME_NAME}/${PLYMOUTH_THEME_NAME}.plymouth | sed 's/ModuleName *= *//')
+ if [ ! -f ${PLYMOUTH_PLUGIN_PATH}/${PLYMOUTH_MODULE_NAME}.so ]; then
+@@ -425,6 +432,7 @@ if [ -n "$SYSTEMD_UNIT_DIR" -a -d "$SYSTEMD_UNIT_DIR" ]; then
+     inst $SYSTEMD_UNIT_DIR/plymouth-halt.service $INITRDDIR
+     inst $SYSTEMD_UNIT_DIR/initrd-switch-root.target.wants/plymouth-switch-root.service $INITRDDIR
++    inst $SYSTEMD_UNIT_DIR/initrd-switch-root.target.wants/plymouth-start.service $INITRDDIR
+     inst $SYSTEMD_UNIT_DIR/sysinit.target.wants/plymouth-start.service $INITRDDIR
+     inst $SYSTEMD_UNIT_DIR/multi-user.target.wants/plymouth-quit.service $INITRDDIR
+     inst $SYSTEMD_UNIT_DIR/multi-user.target.wants/plymouth-quit-wait.service $INITRDDIR
+diff --git a/scripts/plymouth-update-initrd b/scripts/plymouth-update-initrd
+index 1403b8b..4ed5709 100755
+--- a/scripts/plymouth-update-initrd
++++ b/scripts/plymouth-update-initrd
+@@ -1,2 +1,2 @@
+ #!/bin/bash
+-mkinitrd -f /boot/initrd-$(uname -r).img $(uname -r)
++dracut -f
+diff --git a/src/Makefile.am b/src/Makefile.am
+index a9e6eb1..fc2f5da 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -1,8 +1,8 @@
+-SUBDIRS = libply libply-splash-core libply-splash-graphics . plugins client viewer tests
++SUBDIRS = libply libply-splash-core libply-splash-graphics . plugins client viewer
+ if ENABLE_UPSTART_MONITORING
+ SUBDIRS += upstart-bridge
+ endif
+-INCLUDES = -I$(top_srcdir)                                                    \
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
+            -I$(srcdir)/libply                                                 \
+            -I$(srcdir)/libply-splash-core                                     \
+            -I$(srcdir)                                                        \
+@@ -15,6 +15,7 @@ plymouthdbindir = $(plymouthdaemondir)
+ plymouthdbin_PROGRAMS = plymouthd
+ plymouthd_CFLAGS = $(PLYMOUTH_CFLAGS)                                         \
++                 -rdynamic                                                  \
+                  -DPLYMOUTH_PLUGIN_PATH=\"$(PLYMOUTH_PLUGIN_PATH)\"         \
+                  -DPLYMOUTH_THEME_PATH=\"$(PLYMOUTH_THEME_PATH)/\"          \
+                  -DPLYMOUTH_POLICY_DIR=\"$(PLYMOUTH_POLICY_DIR)/\"          \
+diff --git a/src/client/Makefile.am b/src/client/Makefile.am
+index 9487901..83b19cc 100644
+--- a/src/client/Makefile.am
++++ b/src/client/Makefile.am
+@@ -1,6 +1,4 @@
+-SUBDIRS = . tests
+-
+-INCLUDES = -I$(top_srcdir)                                                    \
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
+            -I$(top_srcdir)/src                                                \
+            -I$(top_srcdir)/src/libply                                         \
+            -I$(srcdir)
+diff --git a/src/client/ply-boot-client.c b/src/client/ply-boot-client.c
+index 56458ce..3480676 100644
+--- a/src/client/ply-boot-client.c
++++ b/src/client/ply-boot-client.c
+@@ -869,137 +869,4 @@ ply_boot_client_attach_to_event_loop (ply_boot_client_t *client,
+ }
+-#ifdef PLY_BOOT_CLIENT_ENABLE_TEST
+-
+-#include <stdio.h>
+-
+-#include "ply-event-loop.h"
+-#include "ply-boot-client.h"
+-
+-static void
+-on_pinged (ply_event_loop_t *loop)
+-{
+-  printf ("PING!\n");
+-}
+-
+-static void
+-on_ping_failed (ply_event_loop_t *loop)
+-{
+-  printf ("PING FAILED! %m\n");
+-  ply_event_loop_exit (loop, 1);
+-}
+-
+-static void
+-on_update (ply_event_loop_t *loop)
+-{
+-  printf ("UPDATE!\n");
+-}
+-
+-static void
+-on_update_failed (ply_event_loop_t *loop)
+-{
+-  printf ("UPDATE FAILED! %m\n");
+-  ply_event_loop_exit (loop, 1);
+-}
+-
+-static void
+-on_newroot (ply_event_loop_t *loop)
+-{
+-  printf ("NEWROOT!\n");
+-}
+-
+-static void
+-on_system_initialized (ply_event_loop_t *loop)
+-{
+-  printf ("SYSTEM INITIALIZED!\n");
+-}
+-
+-static void
+-on_system_initialized_failed (ply_event_loop_t *loop)
+-{
+-  printf ("SYSTEM INITIALIZATION REQUEST FAILED!\n");
+-  ply_event_loop_exit (loop, 1);
+-}
+-
+-static void
+-on_quit (ply_event_loop_t *loop)
+-{
+-  printf ("QUIT!\n");
+-  ply_event_loop_exit (loop, 0);
+-}
+-
+-static void
+-on_quit_failed (ply_event_loop_t *loop)
+-{
+-  printf ("QUIT FAILED! %m\n");
+-  ply_event_loop_exit (loop, 2);
+-}
+-
+-static void
+-on_disconnect (ply_event_loop_t *loop)
+-{
+-  printf ("DISCONNECT!\n");
+-  ply_event_loop_exit (loop, 1);
+-}
+-
+-int
+-main (int    argc,
+-      char **argv)
+-{
+-  ply_event_loop_t *loop;
+-  ply_boot_client_t *client;
+-  int exit_code;
+-
+-  exit_code = 0;
+-
+-  loop = ply_event_loop_new ();
+-
+-  client = ply_boot_client_new ();
+-
+-  if (!ply_boot_client_connect (client, 
+-                                (ply_boot_client_disconnect_handler_t) on_disconnect,
+-                                loop))
+-    {
+-      perror ("could not start boot client");
+-      return errno;
+-    }
+-
+-  ply_boot_client_attach_to_event_loop (client, loop);
+-  ply_boot_client_ping_daemon (client, 
+-                               (ply_boot_client_response_handler_t) on_pinged,
+-                               (ply_boot_client_response_handler_t) on_ping_failed,
+-                               loop);
+-
+-  ply_boot_client_update_daemon (client, 
+-                                 "loading",
+-                                 (ply_boot_client_response_handler_t) on_update,
+-                                 (ply_boot_client_response_handler_t) on_update_failed,
+-                                 loop);
+-
+-  ply_boot_client_update_daemon (client, 
+-                                 "loading more",
+-                                 (ply_boot_client_response_handler_t) on_update,
+-                                 (ply_boot_client_response_handler_t) on_update_failed,
+-                                 loop);
+-
+-  ply_boot_client_tell_daemon_system_is_initialized (client, 
+-                                       (ply_boot_client_response_handler_t) 
+-                                       on_system_initialized,
+-                                       (ply_boot_client_response_handler_t) 
+-                                       on_system_initialized_failed,
+-                                       loop);
+-
+-  ply_boot_client_tell_daemon_to_quit (client, 
+-                                       (ply_boot_client_response_handler_t) on_quit,
+-                                       (ply_boot_client_response_handler_t) on_quit_failed,
+-                                       loop);
+-
+-  exit_code = ply_event_loop_run (loop);
+-
+-  ply_boot_client_free (client);
+-
+-  return exit_code;
+-}
+-
+-#endif /* PLY_BOOT_CLIENT_ENABLE_TEST */
+ /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
+diff --git a/src/client/plymouth.c b/src/client/plymouth.c
+index e00208d..b22e90c 100644
+--- a/src/client/plymouth.c
++++ b/src/client/plymouth.c
+@@ -1173,7 +1173,8 @@ main (int    argc,
+   if (get_kernel_command_line (&state))
+     {
+-      if (strstr (state.kernel_command_line, "plymouth:debug") != NULL
++      if ((strstr (state.kernel_command_line, "plymouth.debug") != NULL ||
++           strstr (state.kernel_command_line, "plymouth:debug") != NULL)
+           && !ply_is_tracing ())
+         ply_toggle_tracing ();
+     }
+diff --git a/src/client/tests/Makefile.am b/src/client/tests/Makefile.am
+deleted file mode 100644
+index c6dbfdb..0000000
+--- a/src/client/tests/Makefile.am
++++ /dev/null
+@@ -1,10 +0,0 @@
+-INCLUDES =                                                                    \
+-           -I$(top_srcdir)                                                    \
+-           -I$(srcdir)/..                                                     \
+-           -I$(srcdir)/../..                                                  \
+-           -I$(srcdir)
+-TESTS = 
+-
+-noinst_PROGRAMS = $(TESTS)
+-
+-MAINTAINERCLEANFILES = Makefile.in
+diff --git a/src/libply-splash-core/Makefile.am b/src/libply-splash-core/Makefile.am
+index b289b65..d07d7f1 100644
+--- a/src/libply-splash-core/Makefile.am
++++ b/src/libply-splash-core/Makefile.am
+@@ -1,4 +1,4 @@
+-INCLUDES = -I$(top_srcdir)                                                    \
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
+            -I$(srcdir)                                                        \
+            -I$(srcdir)/../libply                                              \
+            -I$(srcdir)/../plugins/controls
+@@ -15,33 +15,39 @@ libply_splash_coredir = $(includedir)/plymouth-1/ply-splash-core
+ libply_splash_core_HEADERS = \
+                   ply-boot-splash.h                                         \
+                   ply-boot-splash-plugin.h                                  \
++                  ply-device-manager.h                                      \
+                   ply-keyboard.h                                            \
+                   ply-pixel-buffer.h                                        \
+                   ply-pixel-display.h                                       \
+                   ply-renderer.h                                            \
+                   ply-renderer-plugin.h                                     \
++                  ply-seat.h                                                \
+                   ply-terminal.h                                            \
+                   ply-text-display.h                                        \
+-                  ply-text-progress-bar.h
++                  ply-text-progress-bar.h                                   \
++                  ply-text-step-bar.h
+-libply_splash_core_la_CFLAGS = $(PLYMOUTH_CFLAGS)                               \
++libply_splash_core_la_CFLAGS = $(PLYMOUTH_CFLAGS) $(UDEV_CFLAGS)               \
+                              -DPLYMOUTH_BACKGROUND_COLOR=$(background_color)   \
+                        -DPLYMOUTH_BACKGROUND_END_COLOR=$(background_end_color) \
+                        -DPLYMOUTH_BACKGROUND_START_COLOR=$(background_start_color) \
+                        -DPLYMOUTH_PLUGIN_PATH=\"$(PLYMOUTH_PLUGIN_PATH)\"
+-libply_splash_core_la_LIBADD = $(PLYMOUTH_LIBS) ../libply/libply.la
++libply_splash_core_la_LIBADD = $(PLYMOUTH_LIBS) $(UDEV_LIBS) ../libply/libply.la
+ libply_splash_core_la_LDFLAGS = -export-symbols-regex '^[^_].*' \
+                   -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+                   -no-undefined
+ libply_splash_core_la_SOURCES = \
+                   $(libply_splash_core_HEADERS)                              \
++                  ply-device-manager.c                                      \
+                   ply-keyboard.c                                           \
+                   ply-pixel-display.c                                      \
+                   ply-text-display.c                                       \
+                   ply-text-progress-bar.c                                  \
++                  ply-text-step-bar.c                                      \
+                   ply-terminal.c                                           \
+                   ply-pixel-buffer.c                                       \
+                   ply-renderer.c                                           \
++                  ply-seat.c                                               \
+                   ply-boot-splash.c
+ MAINTAINERCLEANFILES = Makefile.in
+diff --git a/src/libply-splash-core/ply-boot-splash.c b/src/libply-splash-core/ply-boot-splash.c
+index 93d9345..160ce45 100644
+--- a/src/libply-splash-core/ply-boot-splash.c
++++ b/src/libply-splash-core/ply-boot-splash.c
+@@ -48,10 +48,6 @@
+ #define UPDATES_PER_SECOND 30
+ #endif
+-#define KEY_CTRL_L ('\100' ^'L')
+-#define KEY_CTRL_T ('\100' ^'T')
+-#define KEY_CTRL_V ('\100' ^'V')
+-
+ struct _ply_boot_splash
+ {
+   ply_event_loop_t *loop;
+@@ -59,11 +55,9 @@ struct _ply_boot_splash
+   const ply_boot_splash_plugin_interface_t *plugin_interface;
+   ply_boot_splash_plugin_t *plugin;
+   ply_boot_splash_mode_t mode;
+-  ply_keyboard_t *keyboard;
+   ply_buffer_t *boot_buffer;
+   ply_trigger_t *idle_trigger;
+-  ply_list_t *pixel_displays;
+-  ply_list_t *text_displays;
++  ply_list_t *seats;
+   char *theme_path;
+   char *plugin_dir;
+@@ -100,18 +94,30 @@ ply_boot_splash_new (const char     *theme_path,
+   splash->mode = PLY_BOOT_SPLASH_MODE_INVALID;
+   splash->boot_buffer = boot_buffer;
+-  splash->pixel_displays = ply_list_new ();
+-  splash->text_displays = ply_list_new ();
++  splash->seats = ply_list_new ();
+   return splash;
+ }
+ static void
+-refresh_displays (ply_boot_splash_t *splash)
++detach_from_seat (ply_boot_splash_t *splash,
++                  ply_seat_t        *seat)
+ {
+-  ply_list_node_t *node;
++  ply_keyboard_t *keyboard;
++  ply_list_t *displays;
++  ply_list_node_t *node, *next_node;
+-  node = ply_list_get_first_node (splash->pixel_displays);
++  ply_trace ("removing keyboard");
++  if (splash->plugin_interface->unset_keyboard != NULL)
++    {
++      keyboard = ply_seat_get_keyboard (seat);
++      splash->plugin_interface->unset_keyboard (splash->plugin, keyboard);
++    }
++
++  ply_trace ("removing pixel displays");
++  displays = ply_seat_get_pixel_displays (seat);
++
++  node = ply_list_get_first_node (displays);
+   while (node != NULL)
+     {
+       ply_pixel_display_t *display;
+@@ -119,184 +125,137 @@ refresh_displays (ply_boot_splash_t *splash)
+       unsigned long width, height;
+       display = ply_list_node_get_data (node);
+-      next_node = ply_list_get_next_node (splash->pixel_displays, node);
++      next_node = ply_list_get_next_node (displays, node);
+       width = ply_pixel_display_get_width (display);
+       height = ply_pixel_display_get_height (display);
+-      ply_pixel_display_draw_area (display, 0, 0, width, height);
++      ply_trace ("Removing %lux%lu pixel display", width, height);
++
++      if (splash->plugin_interface->remove_pixel_display != NULL)
++        splash->plugin_interface->remove_pixel_display (splash->plugin, display);
++
+       node = next_node;
+     }
+-  node = ply_list_get_first_node (splash->text_displays);
++  ply_trace ("removing text displays");
++  displays = ply_seat_get_text_displays (seat);
++
++  node = ply_list_get_first_node (displays);
+   while (node != NULL)
+     {
+       ply_text_display_t *display;
+-      ply_list_node_t *next_node;
+       int number_of_columns, number_of_rows;
+       display = ply_list_node_get_data (node);
+-      next_node = ply_list_get_next_node (splash->text_displays, node);
++      next_node = ply_list_get_next_node (displays, node);
+       number_of_columns = ply_text_display_get_number_of_columns (display);
+       number_of_rows = ply_text_display_get_number_of_rows (display);
+-      ply_text_display_draw_area (display, 0, 0,
+-                                  number_of_columns,
+-                                  number_of_rows);
++      ply_trace ("Removing %dx%d text display", number_of_columns, number_of_rows);
++
++      if (splash->plugin_interface->remove_text_display != NULL)
++        splash->plugin_interface->remove_text_display (splash->plugin, display);
++
+       node = next_node;
+     }
+ }
+-static ply_terminal_t *
+-find_local_console_terminal (ply_boot_splash_t *splash)
++static void
++attach_to_seat (ply_boot_splash_t *splash,
++                ply_seat_t        *seat)
+ {
+-  ply_list_node_t *node;
+-  node = ply_list_get_first_node (splash->text_displays);
++  ply_keyboard_t *keyboard;
++  ply_list_t *displays;
++  ply_list_node_t *node, *next_node;
+-  while (node != NULL)
++  if (splash->plugin_interface->set_keyboard != NULL)
+     {
+-      ply_text_display_t *display;
+-      ply_terminal_t *terminal;
+-      ply_list_node_t *next_node;
++      keyboard = ply_seat_get_keyboard (seat);
++      splash->plugin_interface->set_keyboard (splash->plugin, keyboard);
++    }
+-      display = ply_list_node_get_data (node);
+-      next_node = ply_list_get_next_node (splash->text_displays, node);
++  if (splash->plugin_interface->add_pixel_display != NULL)
++    {
++      displays = ply_seat_get_pixel_displays (seat);
+-      terminal = ply_text_display_get_terminal (display);
++      ply_trace ("adding pixel displays");
++      node = ply_list_get_first_node (displays);
++      while (node != NULL)
++        {
++          ply_pixel_display_t *display;
++          ply_list_node_t *next_node;
++          unsigned long width, height;
+-      if (terminal != NULL && ply_terminal_is_vt (terminal))
+-        return terminal;
++          display = ply_list_node_get_data (node);
++          next_node = ply_list_get_next_node (displays, node);
+-      node = next_node;
+-    }
++          width = ply_pixel_display_get_width (display);
++          height = ply_pixel_display_get_height (display);
+-  return NULL;
+-}
++          ply_trace ("Adding %lux%lu pixel display", width, height);
+-static void
+-on_keyboard_input (ply_boot_splash_t *splash,
+-                   const char        *keyboard_input,
+-                   size_t             character_size)
+-{
+-  wchar_t key;
++          splash->plugin_interface->add_pixel_display (splash->plugin, display);
+-  if ((ssize_t) mbrtowc (&key, keyboard_input, character_size, NULL) > 0)
+-    {
+-      switch (key)
+-        {
+-          case KEY_CTRL_L:
+-            refresh_displays (splash);
+-          return;
+-
+-          case KEY_CTRL_T:
+-            ply_trace ("toggle text mode!");
+-            splash->should_force_text_mode = !splash->should_force_text_mode;
+-
+-            if (ply_list_get_length (splash->pixel_displays) >= 1)
+-              {
+-                ply_terminal_t *terminal;
+-
+-                terminal = find_local_console_terminal (splash);
+-
+-                if (terminal != NULL)
+-                  {
+-                    if (splash->should_force_text_mode)
+-                      {
+-                        ply_terminal_set_mode (terminal, PLY_TERMINAL_MODE_TEXT);
+-                        ply_terminal_ignore_mode_changes (terminal, true);
+-                      }
+-                    else
+-                      ply_terminal_ignore_mode_changes (terminal, false);
+-                  }
+-              }
+-            ply_trace ("text mode toggled!");
+-          return;
+-
+-          case KEY_CTRL_V:
+-            ply_trace ("toggle verbose mode!");
+-            ply_toggle_tracing ();
+-            ply_trace ("verbose mode toggled!");
+-          return;
++          node = next_node;
+         }
+     }
+-}
+-void
+-ply_boot_splash_set_keyboard (ply_boot_splash_t *splash,
+-                              ply_keyboard_t    *keyboard)
+-{
+-  splash->keyboard = keyboard;
++  if (splash->plugin_interface->add_text_display != NULL)
++    {
++      displays = ply_seat_get_text_displays (seat);
+-  ply_keyboard_add_input_handler (keyboard,
+-                                  (ply_keyboard_input_handler_t)
+-                                  on_keyboard_input, splash);
++      ply_trace ("adding text displays");
++      node = ply_list_get_first_node (displays);
++      while (node != NULL)
++        {
++          ply_text_display_t *display;
++          int number_of_columns, number_of_rows;
+-  if (splash->plugin_interface->set_keyboard == NULL)
+-    return;
++          display = ply_list_node_get_data (node);
++          next_node = ply_list_get_next_node (displays, node);
+-  splash->plugin_interface->set_keyboard (splash->plugin, keyboard);
+-}
++          number_of_columns = ply_text_display_get_number_of_columns (display);
++          number_of_rows = ply_text_display_get_number_of_rows (display);
+-void
+-ply_boot_splash_unset_keyboard (ply_boot_splash_t *splash)
+-{
+-  ply_keyboard_remove_input_handler (splash->keyboard,
+-                                     (ply_keyboard_input_handler_t)
+-                                     on_keyboard_input);
++          ply_trace ("Adding %dx%d text display", number_of_columns, number_of_rows);
+-  if (splash->plugin_interface->set_keyboard == NULL)
+-    return;
++          splash->plugin_interface->add_text_display (splash->plugin, display);
+-  splash->plugin_interface->unset_keyboard (splash->plugin, splash->keyboard);
++          node = next_node;
++        }
++    }
+ }
+ void
+-ply_boot_splash_add_pixel_display (ply_boot_splash_t   *splash,
+-                                   ply_pixel_display_t *display)
++ply_boot_splash_attach_to_seat (ply_boot_splash_t *splash,
++                                ply_seat_t        *seat)
+ {
+-  ply_list_append_data (splash->pixel_displays, display);
+-
+-  if (splash->plugin_interface->add_pixel_display == NULL)
+-    return;
+-
+-  splash->plugin_interface->add_pixel_display (splash->plugin, display);
+-}
++  ply_list_node_t *node;
+-void
+-ply_boot_splash_remove_pixel_display (ply_boot_splash_t   *splash,
+-                                      ply_pixel_display_t *display)
+-{
+-  ply_list_remove_data (splash->pixel_displays, display);
++  node = ply_list_find_node (splash->seats, seat);
+-  if (splash->plugin_interface->remove_pixel_display == NULL)
++  if (node != NULL)
+     return;
+-  splash->plugin_interface->remove_pixel_display (splash->plugin, display);
++  ply_list_append_data (splash->seats, seat);
++  attach_to_seat (splash, seat);
+ }
+ void
+-ply_boot_splash_add_text_display (ply_boot_splash_t   *splash,
+-                                  ply_text_display_t *display)
++ply_boot_splash_detach_from_seat (ply_boot_splash_t *splash,
++                                  ply_seat_t        *seat)
+ {
+-  ply_list_append_data (splash->text_displays, display);
++  ply_list_node_t *node;
+-  if (splash->plugin_interface->add_text_display == NULL)
+-    return;
++  node = ply_list_find_node (splash->seats, seat);
+-  splash->plugin_interface->add_text_display (splash->plugin, display);
+-}
+-
+-void
+-ply_boot_splash_remove_text_display (ply_boot_splash_t   *splash,
+-                                     ply_text_display_t *display)
+-{
+-  ply_list_remove_data (splash->text_displays, display);
+-
+-  if (splash->plugin_interface->remove_pixel_display == NULL)
++  if (node == NULL)
+     return;
+-  splash->plugin_interface->remove_text_display (splash->plugin, display);
++  ply_list_remove_data (splash->seats, seat);
++  detach_from_seat (splash, seat);
+ }
+ bool
+@@ -432,56 +391,24 @@ ply_boot_splash_unload (ply_boot_splash_t *splash)
+ }
+ static void
+-remove_displays (ply_boot_splash_t *splash)
++detach_from_seats (ply_boot_splash_t *splash)
+ {
+-  ply_list_node_t *node, *next_node;
++  ply_list_node_t *node;
+-  ply_trace ("removing pixel displays");
++  ply_trace ("detaching from seats");
+-  node = ply_list_get_first_node (splash->pixel_displays);
++  node = ply_list_get_first_node (splash->seats);
+   while (node != NULL)
+     {
+-      ply_pixel_display_t *display;
++      ply_seat_t *seat;
+       ply_list_node_t *next_node;
+-      unsigned long width, height;
+-      display = ply_list_node_get_data (node);
+-      next_node = ply_list_get_next_node (splash->pixel_displays, node);
++      seat = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (splash->seats, node);
+-      width = ply_pixel_display_get_width (display);
+-      height = ply_pixel_display_get_height (display);
++      detach_from_seat (splash, seat);
+-      ply_trace ("Removing %lux%lu pixel display", width, height);
+-
+-      if (splash->plugin_interface->remove_pixel_display != NULL)
+-        splash->plugin_interface->remove_pixel_display (splash->plugin, display);
+-
+-      ply_trace ("Removing node");
+-      ply_list_remove_node (splash->pixel_displays, node);
+-
+-      node = next_node;
+-    }
+-
+-  ply_trace ("removing text displays");
+-  node = ply_list_get_first_node (splash->text_displays);
+-  while (node != NULL)
+-    {
+-      ply_text_display_t *display;
+-      int number_of_columns, number_of_rows;
+-
+-      display = ply_list_node_get_data (node);
+-      next_node = ply_list_get_next_node (splash->text_displays, node);
+-
+-      number_of_columns = ply_text_display_get_number_of_columns (display);
+-      number_of_rows = ply_text_display_get_number_of_rows (display);
+-
+-      ply_trace ("Removing %dx%d text display", number_of_columns, number_of_rows);
+-
+-      if (splash->plugin_interface->remove_text_display != NULL)
+-        splash->plugin_interface->remove_text_display (splash->plugin, display);
+-
+-      ply_trace ("Removing node");
+-      ply_list_remove_node (splash->text_displays, node);
++      ply_list_remove_node (splash->seats, node);
+       node = next_node;
+     }
+@@ -508,9 +435,8 @@ ply_boot_splash_free (ply_boot_splash_t *splash)
+                                              splash);
+     }
+-  remove_displays (splash);
+-  ply_list_free (splash->pixel_displays);
+-  ply_list_free (splash->text_displays);
++  detach_from_seats (splash);
++  ply_list_free (splash->seats);
+   if (splash->module_handle != NULL)
+     ply_boot_splash_unload (splash);
+@@ -676,16 +602,6 @@ ply_boot_splash_hide (ply_boot_splash_t *splash)
+   splash->plugin_interface->hide_splash_screen (splash->plugin,
+                                                 splash->loop);
+-  if (ply_list_get_length (splash->pixel_displays) >= 1)
+-    {
+-      ply_terminal_t *terminal;
+-
+-      terminal = find_local_console_terminal (splash);
+-
+-      if (terminal != NULL)
+-        ply_terminal_set_mode (terminal, PLY_TERMINAL_MODE_TEXT);
+-    }
+-
+   splash->mode = PLY_BOOT_SPLASH_MODE_INVALID;
+   if (splash->loop != NULL)
+@@ -820,148 +736,4 @@ ply_boot_splash_become_idle (ply_boot_splash_t                  *splash,
+   splash->plugin_interface->become_idle (splash->plugin, splash->idle_trigger);
+ }
+-#ifdef PLY_BOOT_SPLASH_ENABLE_TEST
+-
+-#include <stdio.h>
+-
+-#include "ply-event-loop.h"
+-#include "ply-boot-splash.h"
+-
+-typedef struct test_state test_state_t;
+-struct test_state {
+-  ply_event_loop_t *loop;
+-  ply_boot_splash_t *splash;
+-  ply_buffer_t *buffer;
+-};
+-
+-static void
+-on_timeout (ply_boot_splash_t *splash)
+-{
+-  ply_boot_splash_update_status (splash, "foo");
+-  ply_event_loop_watch_for_timeout (splash->loop, 
+-                                    5.0,
+-                                   (ply_event_loop_timeout_handler_t)
+-                                   on_timeout,
+-                                   splash);
+-}
+-
+-static void
+-on_quit (test_state_t *state)
+-{
+-    ply_boot_splash_hide (state->splash);
+-    ply_event_loop_exit (state->loop, 0);
+-}
+-
+-static void
+-add_displays_to_splash_from_renderer (test_state_t   *state,
+-                                      ply_renderer_t *renderer)
+-{
+-  ply_list_t *heads;
+-  ply_list_node_t *node;
+-
+-  heads = ply_renderer_get_heads (renderer);
+-
+-  node = ply_list_get_first_node (heads);
+-  while (node != NULL)
+-    {
+-      ply_list_node_t *next_node;
+-      ply_renderer_head_t *head;
+-      ply_pixel_display_t *display;
+-
+-      head = ply_list_node_get_data (node);
+-      next_node = ply_list_get_next_node (heads, node);
+-
+-      display = ply_pixel_display_new (renderer, head);
+-
+-      ply_boot_splash_add_pixel_display (state->splash, display);
+-
+-      node = next_node;
+-    }
+-}
+-
+-int
+-main (int    argc,
+-      char **argv)
+-{
+-  int exit_code;
+-  test_state_t state;
+-  char *tty_name;
+-  const char *theme_path;
+-  ply_text_display_t *text_display;
+-  ply_renderer_t *renderer;
+-  ply_terminal_t *terminal;
+-  ply_keyboard_t *keyboard;
+-
+-  exit_code = 0;
+-
+-  state.loop = ply_event_loop_new ();
+-
+-  if (argc > 1)
+-    theme_path = argv[1];
+-  else
+-    theme_path = PLYMOUTH_THEME_PATH "/fade-in/fade-in.plymouth";
+-
+-  if (argc > 2)
+-    asprintf(&tty_name, "tty%s", argv[2]);
+-  else
+-    tty_name = strdup("tty0");
+-
+-  terminal = ply_terminal_new (tty_name);
+-
+-  if (!ply_terminal_open (terminal))
+-    {
+-      perror ("could not open tty");
+-      return errno;
+-    }
+-
+-  renderer = ply_renderer_new (NULL, terminal);
+-  free(tty_name);
+-
+-  if (!ply_renderer_open (renderer))
+-    {
+-      perror ("could not open renderer /dev/fb");
+-      ply_renderer_free (renderer);
+-      return errno;
+-    }
+-
+-  keyboard = ply_keyboard_new_for_renderer (renderer);
+-  ply_keyboard_add_escape_handler (keyboard,
+-                                   (ply_keyboard_escape_handler_t) on_quit, &state);
+-
+-  state.buffer = ply_buffer_new ();
+-  state.splash = ply_boot_splash_new (theme_path, PLYMOUTH_PLUGIN_PATH, state.buffer);
+-
+-  if (!ply_boot_splash_load (state.splash))
+-    {
+-      perror ("could not load splash screen");
+-      return errno;
+-    }
+-
+-  ply_boot_splash_set_keyboard (state.splash, keyboard);
+-  add_displays_to_splash_from_renderer (&state, renderer);
+-
+-  text_display = ply_text_display_new (terminal);
+-  ply_boot_splash_add_text_display (state.splash, text_display);
+-
+-  ply_boot_splash_attach_to_event_loop (state.splash, state.loop);
+-
+-  if (!ply_boot_splash_show (state.splash, PLY_BOOT_SPLASH_MODE_BOOT_UP))
+-    {
+-      perror ("could not show splash screen");
+-      return errno;
+-    }
+-
+-  ply_event_loop_watch_for_timeout (state.loop, 
+-                                    1.0,
+-                                   (ply_event_loop_timeout_handler_t)
+-                                   on_timeout,
+-                                   state.splash);
+-  exit_code = ply_event_loop_run (state.loop);
+-  ply_boot_splash_free (state.splash);
+-  ply_buffer_free (state.buffer);
+-
+-  return exit_code;
+-}
+-
+-#endif /* PLY_BOOT_SPLASH_ENABLE_TEST */
+ /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
+diff --git a/src/libply-splash-core/ply-boot-splash.h b/src/libply-splash-core/ply-boot-splash.h
+index a79e939..335039b 100644
+--- a/src/libply-splash-core/ply-boot-splash.h
++++ b/src/libply-splash-core/ply-boot-splash.h
+@@ -33,10 +33,12 @@
+ #include "ply-pixel-display.h"
+ #include "ply-text-display.h"
+ #include "ply-progress.h"
++#include "ply-seat.h"
+ #include "ply-boot-splash-plugin.h"
+ typedef struct _ply_boot_splash ply_boot_splash_t;
++typedef struct _ply_seat ply_seat_t;
+ typedef void (* ply_boot_splash_on_idle_handler_t) (void *user_data);
+@@ -48,17 +50,10 @@ ply_boot_splash_t *ply_boot_splash_new (const char   *  theme_path,
+ bool ply_boot_splash_load (ply_boot_splash_t *splash);
+ bool ply_boot_splash_load_built_in (ply_boot_splash_t *splash);
+ void ply_boot_splash_unload (ply_boot_splash_t *splash);
+-void ply_boot_splash_set_keyboard (ply_boot_splash_t *splash,
+-                                   ply_keyboard_t    *keyboard);
+-void ply_boot_splash_unset_keyboard (ply_boot_splash_t *splash);
+-void ply_boot_splash_add_pixel_display (ply_boot_splash_t   *splash,
+-                                        ply_pixel_display_t *display);
+-void ply_boot_splash_remove_pixel_display (ply_boot_splash_t   *splash,
+-                                           ply_pixel_display_t *display);
+-void ply_boot_splash_add_text_display (ply_boot_splash_t   *splash,
+-                                        ply_text_display_t *display);
+-void ply_boot_splash_remove_text_display (ply_boot_splash_t   *splash,
+-                                           ply_text_display_t *display);
++void ply_boot_splash_attach_to_seat (ply_boot_splash_t *splash,
++                                     ply_seat_t        *seat);
++void ply_boot_splash_detach_from_seat (ply_boot_splash_t *splash,
++                                       ply_seat_t        *seat);
+ void ply_boot_splash_free (ply_boot_splash_t *splash);
+ bool ply_boot_splash_show (ply_boot_splash_t *splash,
+                            ply_boot_splash_mode_t mode);
+diff --git a/src/libply-splash-core/ply-device-manager.c b/src/libply-splash-core/ply-device-manager.c
+new file mode 100644
+index 0000000..dbc203d
+--- /dev/null
++++ b/src/libply-splash-core/ply-device-manager.c
+@@ -0,0 +1,935 @@
++/* ply-device-manager.c - device manager
++ *
++ * Copyright (C) 2013 Red Hat, Inc.
++ *
++ * 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, 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, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
++ * 02111-1307, USA.
++ */
++#include "config.h"
++#include "ply-device-manager.h"
++
++#include <assert.h>
++#include <fcntl.h>
++#include <stdbool.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <sys/inotify.h>
++#include <sys/stat.h>
++#include <sys/types.h>
++
++#include <libudev.h>
++
++#include "ply-logger.h"
++#include "ply-event-loop.h"
++#include "ply-hashtable.h"
++#include "ply-list.h"
++#include "ply-utils.h"
++
++#define SUBSYSTEM_DRM "drm"
++#define SUBSYSTEM_FRAME_BUFFER "graphics"
++
++static void create_seat_for_terminal_and_renderer_type (ply_device_manager_t *manager,
++                                                        const char           *device_path,
++                                                        ply_terminal_t       *terminal,
++                                                        ply_renderer_type_t   renderer_type);
++struct _ply_device_manager
++{
++  ply_device_manager_flags_t  flags;
++  ply_event_loop_t           *loop;
++  ply_hashtable_t            *terminals;
++  ply_terminal_t             *local_console_terminal;
++  ply_seat_t                 *local_console_seat;
++  ply_list_t                 *seats;
++  struct udev                *udev_context;
++  struct udev_queue          *udev_queue;
++  int                         udev_queue_fd;
++  ply_fd_watch_t             *udev_queue_fd_watch;
++  struct udev_monitor        *udev_monitor;
++
++  ply_seat_added_handler_t    seat_added_handler;
++  ply_seat_removed_handler_t  seat_removed_handler;
++  void                       *seat_event_handler_data;
++};
++
++static void
++detach_from_event_loop (ply_device_manager_t *manager)
++{
++  assert (manager != NULL);
++
++  manager->loop = NULL;
++}
++
++static void
++attach_to_event_loop (ply_device_manager_t *manager,
++                      ply_event_loop_t     *loop)
++{
++  assert (manager != NULL);
++  assert (loop != NULL);
++  assert (manager->loop == NULL);
++
++  manager->loop = loop;
++
++  ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t)
++                                 detach_from_event_loop,
++                                 manager);
++}
++
++static bool
++device_is_for_local_console (ply_device_manager_t *manager,
++                             struct udev_device   *device)
++{
++  const char *device_path;
++  struct udev_device *bus_device;
++  char *bus_device_path;
++  const char *boot_vga;
++  bool for_local_console;
++
++  /* Look at the associated bus device to see if this card is the
++   * card the kernel is using for its console. */
++  device_path = udev_device_get_syspath (device);
++  asprintf (&bus_device_path, "%s/device", device_path);
++  bus_device = udev_device_new_from_syspath (manager->udev_context, bus_device_path);
++
++  boot_vga = udev_device_get_sysattr_value (bus_device, "boot_vga");
++  free (bus_device_path);
++
++  if (boot_vga != NULL && strcmp (boot_vga, "1") == 0)
++    for_local_console = true;
++  else
++    for_local_console = false;
++
++  return for_local_console;
++}
++
++static bool
++fb_device_has_drm_device (ply_device_manager_t *manager,
++                          struct udev_device   *fb_device)
++{
++  struct udev_enumerate *card_matches;
++  struct udev_list_entry *card_entry;
++  const char *id_path;
++  bool has_drm_device = false;
++
++  /* We want to see if the framebuffer is associated with a DRM-capable
++   * graphics card, if it is, we'll use the DRM device */
++  card_matches = udev_enumerate_new (manager->udev_context);
++  udev_enumerate_add_match_is_initialized(card_matches);
++  udev_enumerate_add_match_parent (card_matches, udev_device_get_parent (fb_device));
++  udev_enumerate_add_match_subsystem (card_matches, "drm");
++  id_path = udev_device_get_property_value (fb_device, "ID_PATH");
++  udev_enumerate_add_match_property (card_matches, "ID_PATH", id_path);
++
++  ply_trace ("trying to find associated drm node for fb device (path: %s)", id_path);
++
++  udev_enumerate_scan_devices (card_matches);
++
++  /* there should only ever be at most one match so we don't iterate through
++   * the list, but just look at the first entry */
++  card_entry = udev_enumerate_get_list_entry (card_matches);
++
++  if (card_entry != NULL)
++    {
++      struct udev_device *card_device = NULL;
++      const char *card_node;
++      const char *card_path;
++
++      card_path = udev_list_entry_get_name (card_entry);
++      card_device = udev_device_new_from_syspath (manager->udev_context, card_path);
++      card_node = udev_device_get_devnode (card_device);
++      if (card_node != NULL)
++        has_drm_device = true;
++      else
++        ply_trace ("no card node!");
++
++      udev_device_unref (card_device);
++    }
++  else
++    {
++      ply_trace ("no card entry!");
++    }
++
++  udev_enumerate_unref (card_matches);
++  return has_drm_device;
++}
++
++static void
++create_seat_for_udev_device (ply_device_manager_t *manager,
++                             struct udev_device   *device)
++{
++  bool for_local_console;
++  const char *device_path;
++  ply_terminal_t *terminal = NULL;
++
++  for_local_console = device_is_for_local_console (manager, device);
++
++  ply_trace ("device is for local console: %s", for_local_console? "yes" : "no");
++
++  if (for_local_console)
++    terminal = manager->local_console_terminal;
++
++  device_path = udev_device_get_devnode (device);
++
++  if (device_path != NULL)
++    {
++      const char *subsystem;
++      ply_renderer_type_t renderer_type = PLY_RENDERER_TYPE_NONE;
++
++      subsystem = udev_device_get_subsystem (device);
++      ply_trace ("device subsystem is %s", subsystem);
++
++      if (subsystem != NULL && strcmp (subsystem, SUBSYSTEM_DRM) == 0)
++        {
++          ply_trace ("found DRM device %s", device_path);
++          renderer_type = PLY_RENDERER_TYPE_DRM;
++        }
++      else if (strcmp (subsystem, SUBSYSTEM_FRAME_BUFFER) == 0)
++        {
++          ply_trace ("found frame buffer device %s", device_path);
++          if (!fb_device_has_drm_device (manager, device))
++            {
++              renderer_type = PLY_RENDERER_TYPE_FRAME_BUFFER;
++            }
++          else
++            {
++              ply_trace ("ignoring, since there's a DRM device associated with it");
++            }
++        }
++
++      if (renderer_type != PLY_RENDERER_TYPE_NONE)
++        create_seat_for_terminal_and_renderer_type (manager,
++                                                    device_path,
++                                                    terminal,
++                                                    renderer_type);
++    }
++}
++
++static void
++free_seat_from_device_path (ply_device_manager_t *manager,
++                            const char           *device_path)
++{
++  ply_list_node_t *node;
++
++  node = ply_list_get_first_node (manager->seats);
++  while (node != NULL)
++    {
++      ply_seat_t *seat;
++      ply_renderer_t *renderer;
++      ply_list_node_t *next_node;
++      const char *renderer_device_path;
++
++      seat = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (manager->seats, node);
++      renderer = ply_seat_get_renderer (seat);
++
++      if (renderer != NULL)
++        {
++          renderer_device_path = ply_renderer_get_device_name (renderer);
++
++          if (renderer_device_path != NULL)
++            {
++              if (strcmp (device_path, renderer_device_path) == 0)
++                {
++                  ply_trace ("removing seat associated with %s", device_path);
++
++                  if (manager->seat_removed_handler != NULL)
++                    manager->seat_removed_handler (manager->seat_event_handler_data, seat);
++
++                  ply_seat_free (seat);
++                  ply_list_remove_node (manager->seats, node);
++                  break;
++                }
++            }
++        }
++
++      node = next_node;
++    }
++}
++
++static void
++free_seat_for_udev_device (ply_device_manager_t *manager,
++                           struct udev_device   *device)
++{
++  const char *device_path;
++
++  device_path = udev_device_get_devnode (device);
++
++  if (device_path != NULL)
++    free_seat_from_device_path (manager, device_path);
++}
++
++static bool
++create_seats_for_subsystem (ply_device_manager_t *manager,
++                            const char           *subsystem)
++{
++  struct udev_enumerate *matches;
++  struct udev_list_entry *entry;
++  bool found_device = false;
++
++  ply_trace ("creating seats for %s devices",
++             strcmp (subsystem, SUBSYSTEM_FRAME_BUFFER) == 0?
++             "frame buffer":
++             subsystem);
++
++  matches = udev_enumerate_new (manager->udev_context);
++  udev_enumerate_add_match_subsystem (matches, subsystem);
++  udev_enumerate_scan_devices (matches);
++
++  udev_list_entry_foreach (entry, udev_enumerate_get_list_entry (matches))
++    {
++      struct udev_device *device = NULL;
++      const char *path;
++
++      path = udev_list_entry_get_name (entry);
++
++      if (path == NULL)
++        {
++          ply_trace ("path was null!");
++          continue;
++        }
++
++      ply_trace ("found device %s", path);
++
++      device = udev_device_new_from_syspath (manager->udev_context, path);
++
++      /* if device isn't fully initialized, we'll get an add event later
++       */
++      if (udev_device_get_is_initialized (device))
++        {
++          ply_trace ("device is initialized");
++
++          /* We only care about devices assigned to a (any) seat. Floating
++           * devices should be ignored.
++           */
++          if (udev_device_has_tag (device, "seat"))
++            {
++              const char *node;
++              node = udev_device_get_devnode (device);
++              if (node != NULL)
++                {
++                  ply_trace ("found node %s", node);
++                  found_device = true;
++                  create_seat_for_udev_device (manager, device);
++                }
++            }
++          else
++            {
++              ply_trace ("device doesn't have a seat tag");
++            }
++        }
++      else
++        {
++          ply_trace ("it's not initialized");
++        }
++
++      udev_device_unref (device);
++    }
++
++  udev_enumerate_unref (matches);
++
++  return found_device;
++}
++
++static void
++on_udev_event (ply_device_manager_t *manager)
++{
++  struct udev_device *device;
++  const char *action;
++
++  device = udev_monitor_receive_device (manager->udev_monitor);
++  if (device == NULL)
++    return;
++
++  action = udev_device_get_action (device);
++
++  ply_trace ("got %s event for device %s", action, udev_device_get_sysname (device));
++
++  if (action == NULL)
++    return;
++
++  if (strcmp (action, "add") == 0)
++    {
++      const char *subsystem;
++      bool coldplug_complete = manager->udev_queue_fd_watch == NULL;
++
++      subsystem = udev_device_get_subsystem (device);
++
++      if (strcmp (subsystem, SUBSYSTEM_DRM) == 0 ||
++          coldplug_complete)
++        {
++          create_seat_for_udev_device (manager, device);
++        }
++      else
++        {
++          ply_trace ("ignoring since we only handle subsystem %s devices after coldplug completes", subsystem);
++        }
++    }
++  else if (strcmp (action, "remove") == 0)
++    {
++      free_seat_for_udev_device (manager, device);
++    }
++
++  udev_device_unref (device);
++}
++
++static void
++watch_for_udev_events (ply_device_manager_t *manager)
++{
++  int fd;
++  assert (manager != NULL);
++  assert (manager->udev_monitor == NULL);
++
++  ply_trace ("watching for udev graphics device add and remove events");
++
++  manager->udev_monitor = udev_monitor_new_from_netlink (manager->udev_context, "udev");
++
++  udev_monitor_filter_add_match_subsystem_devtype (manager->udev_monitor, SUBSYSTEM_DRM, NULL);
++  udev_monitor_filter_add_match_subsystem_devtype (manager->udev_monitor, SUBSYSTEM_FRAME_BUFFER, NULL);
++  udev_monitor_filter_add_match_tag (manager->udev_monitor, "seat");
++  udev_monitor_enable_receiving (manager->udev_monitor);
++
++  fd = udev_monitor_get_fd (manager->udev_monitor);
++  ply_event_loop_watch_fd (manager->loop,
++                           fd,
++                           PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
++                           (ply_event_handler_t)
++                           on_udev_event,
++                           NULL,
++                           manager);
++}
++
++static void
++free_seats (ply_device_manager_t *manager)
++{
++  ply_list_node_t *node;
++
++  ply_trace ("removing seats");
++  node = ply_list_get_first_node (manager->seats);
++  while (node != NULL)
++    {
++      ply_seat_t *seat;
++      ply_list_node_t *next_node;
++
++      seat = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (manager->seats, node);
++
++      if (manager->seat_removed_handler != NULL)
++        manager->seat_removed_handler (manager->seat_event_handler_data, seat);
++
++      ply_seat_free (seat);
++      ply_list_remove_node (manager->seats, node);
++
++      node = next_node;
++    }
++}
++
++static void
++free_terminal (char                 *device,
++               ply_terminal_t       *terminal,
++               ply_device_manager_t *manager)
++{
++  ply_hashtable_remove (manager->terminals, device);
++
++  ply_terminal_close (terminal);
++  ply_terminal_free (terminal);
++}
++
++static void
++free_terminals (ply_device_manager_t *manager)
++{
++  ply_hashtable_foreach (manager->terminals,
++                         (ply_hashtable_foreach_func_t *)
++                         free_terminal,
++                         manager);
++}
++
++static ply_terminal_t *
++get_terminal (ply_device_manager_t *manager,
++              const char           *device_name)
++{
++  char *full_name = NULL;
++  ply_terminal_t *terminal;
++
++  if (strncmp (device_name, "/dev/", strlen ("/dev/")) == 0)
++    full_name = strdup (device_name);
++  else
++    asprintf (&full_name, "/dev/%s", device_name);
++
++  if (strcmp (full_name, "/dev/tty0") == 0 ||
++      strcmp (full_name, "/dev/tty") == 0 ||
++      strcmp (full_name, ply_terminal_get_name (manager->local_console_terminal)) == 0)
++    {
++      terminal = manager->local_console_terminal;
++      goto done;
++    }
++
++  terminal = ply_hashtable_lookup (manager->terminals, full_name);
++
++  if (terminal == NULL)
++    {
++      terminal = ply_terminal_new (full_name);
++
++      ply_hashtable_insert (manager->terminals,
++                            (void *) ply_terminal_get_name (terminal),
++                            terminal);
++    }
++
++done:
++  free (full_name);
++  return terminal;
++}
++
++ply_device_manager_t *
++ply_device_manager_new (const char                 *default_tty,
++                        ply_device_manager_flags_t  flags)
++{
++  ply_device_manager_t *manager;
++
++  manager = calloc (1, sizeof (ply_device_manager_t));
++  manager->loop = NULL;
++  manager->terminals = ply_hashtable_new (ply_hashtable_string_hash, ply_hashtable_string_compare);
++  manager->local_console_terminal = ply_terminal_new (default_tty);
++  ply_hashtable_insert (manager->terminals,
++                        (void *) ply_terminal_get_name (manager->local_console_terminal),
++                        manager->local_console_terminal);
++  manager->seats = ply_list_new ();
++  manager->flags = flags;
++
++  if (!(flags & PLY_DEVICE_MANAGER_FLAGS_IGNORE_UDEV))
++    manager->udev_context = udev_new ();
++
++  attach_to_event_loop (manager, ply_event_loop_get_default ());
++
++  return manager;
++}
++
++void
++ply_device_manager_free (ply_device_manager_t *manager)
++{
++  ply_trace ("freeing device manager");
++
++  if (manager == NULL)
++    return;
++
++  ply_event_loop_stop_watching_for_exit (manager->loop,
++                                         (ply_event_loop_exit_handler_t)
++                                         detach_from_event_loop,
++                                         manager);
++  free_seats (manager);
++  ply_list_free (manager->seats);
++
++  free_terminals (manager);
++  ply_hashtable_free (manager->terminals);
++
++  if (manager->udev_monitor != NULL)
++    udev_monitor_unref (manager->udev_monitor);
++
++  if (manager->udev_context != NULL)
++    udev_unref (manager->udev_context);
++
++  free (manager);
++}
++
++static bool
++add_consoles_from_file (ply_device_manager_t *manager,
++                        const char           *path)
++{
++  int fd;
++  char contents[512] = "";
++  ssize_t contents_length;
++  bool has_serial_consoles;
++  const char *remaining_file_contents;
++
++  ply_trace ("opening %s", path);
++  fd = open (path, O_RDONLY);
++
++  if (fd < 0)
++    {
++      ply_trace ("couldn't open it: %m");
++      return false;
++    }
++
++  ply_trace ("reading file");
++  contents_length = read (fd, contents, sizeof (contents) - 1);
++
++  if (contents_length <= 0)
++    {
++      ply_trace ("couldn't read it: %m");
++      close (fd);
++      return false;
++    }
++  close (fd);
++
++  remaining_file_contents = contents;
++  has_serial_consoles = false;
++
++  while (remaining_file_contents < contents + contents_length)
++    {
++      char *console;
++      size_t console_length;
++      const char *console_device;
++      ply_terminal_t *terminal;
++
++      /* Advance past any leading whitespace */
++      remaining_file_contents += strspn (remaining_file_contents, " \n\t\v");
++
++      if (*remaining_file_contents == '\0')
++        {
++          /* There's nothing left after the whitespace, we're done */
++          break;
++        }
++
++      /* Find trailing whitespace and NUL terminate.  If strcspn
++       * doesn't find whitespace, it gives us the length of the string
++       * until the next NUL byte, which we'll just overwrite with
++       * another NUL byte anyway. */
++      console_length = strcspn (remaining_file_contents, " \n\t\v");
++      console = strndup (remaining_file_contents, console_length);
++
++      terminal = get_terminal (manager, console);
++      console_device = ply_terminal_get_name (terminal);
++
++      free (console);
++
++      ply_trace ("console %s found!", console_device);
++
++      if (terminal != manager->local_console_terminal)
++        has_serial_consoles = true;
++
++      /* Move past the parsed console string, and the whitespace we
++       * may have found above.  If we found a NUL above and not whitespace,
++       * then we're going to jump past the end of the buffer and the loop
++       * will terminate
++       */
++      remaining_file_contents += console_length + 1;
++    }
++
++  return has_serial_consoles;
++}
++
++static void
++create_seat_for_terminal_and_renderer_type (ply_device_manager_t *manager,
++                                            const char           *device_path,
++                                            ply_terminal_t       *terminal,
++                                            ply_renderer_type_t   renderer_type)
++{
++  ply_seat_t *seat;
++  bool is_local_terminal = false;
++
++  if (terminal != NULL && manager->local_console_terminal == terminal)
++    is_local_terminal = true;
++
++  if (is_local_terminal && manager->local_console_seat != NULL)
++    {
++      ply_trace ("trying to create seat for local console when one already exists");
++      return;
++    }
++
++  ply_trace ("creating seat for %s (renderer type: %u) (terminal: %s)",
++             device_path? : "", renderer_type, terminal? ply_terminal_get_name (terminal): "none");
++  seat = ply_seat_new (terminal);
++
++  if (!ply_seat_open (seat, renderer_type, device_path))
++    {
++      ply_trace ("could not create seat");
++      ply_seat_free (seat);
++      return;
++    }
++
++  ply_list_append_data (manager->seats, seat);
++
++  if (is_local_terminal)
++    manager->local_console_seat = seat;
++
++  if (manager->seat_added_handler != NULL)
++    manager->seat_added_handler (manager->seat_event_handler_data, seat);
++}
++
++static void
++create_seat_for_terminal (const char           *device_path,
++                          ply_terminal_t       *terminal,
++                          ply_device_manager_t *manager)
++{
++  create_seat_for_terminal_and_renderer_type (manager,
++                                              device_path,
++                                              terminal,
++                                              PLY_RENDERER_TYPE_NONE);
++}
++static bool
++create_seats_from_terminals (ply_device_manager_t *manager)
++{
++  bool has_serial_consoles;
++
++  ply_trace ("checking for consoles");
++
++  if (manager->flags & PLY_DEVICE_MANAGER_FLAGS_IGNORE_SERIAL_CONSOLES)
++    {
++      has_serial_consoles = false;
++      ply_trace ("ignoring all consoles but default console because explicitly told to.");
++    }
++  else
++    {
++      has_serial_consoles = add_consoles_from_file (manager, "/sys/class/tty/console/active");
++    }
++
++  if (has_serial_consoles)
++    {
++      ply_trace ("serial consoles detected, managing them with details forced");
++      ply_hashtable_foreach (manager->terminals,
++                             (ply_hashtable_foreach_func_t *)
++                             create_seat_for_terminal,
++                             manager);
++      return true;
++    }
++
++  return false;
++}
++
++static void
++create_seats_from_udev (ply_device_manager_t *manager)
++{
++  bool found_drm_device, found_fb_device;
++
++  ply_trace ("Looking for devices from udev");
++
++  found_drm_device = create_seats_for_subsystem (manager, SUBSYSTEM_DRM);
++  found_fb_device = create_seats_for_subsystem (manager, SUBSYSTEM_FRAME_BUFFER);
++
++  if (found_drm_device || found_fb_device)
++    return;
++
++  ply_trace ("Creating non-graphical seat, since there's no suitable graphics hardware");
++  create_seat_for_terminal_and_renderer_type (manager,
++                                              ply_terminal_get_name (manager->local_console_terminal),
++                                              manager->local_console_terminal,
++                                              PLY_RENDERER_TYPE_NONE);
++}
++
++static void
++create_fallback_seat (ply_device_manager_t *manager)
++{
++  create_seat_for_terminal_and_renderer_type (manager,
++                                              ply_terminal_get_name (manager->local_console_terminal),
++                                              manager->local_console_terminal,
++                                              PLY_RENDERER_TYPE_AUTO);
++}
++
++static void
++on_udev_queue_changed (ply_device_manager_t *manager)
++{
++
++  if (!udev_queue_get_queue_is_empty (manager->udev_queue))
++    return;
++
++  ply_trace ("udev coldplug complete");
++  ply_event_loop_stop_watching_fd (manager->loop, manager->udev_queue_fd_watch);
++  manager->udev_queue_fd_watch = NULL;
++  udev_queue_unref (manager->udev_queue);
++
++  close (manager->udev_queue_fd);
++  manager->udev_queue_fd = -1;
++
++  manager->udev_queue = NULL;
++
++  create_seats_from_udev (manager);
++}
++
++static void
++watch_for_coldplug_completion (ply_device_manager_t *manager)
++{
++  int fd;
++  int result;
++
++  manager->udev_queue = udev_queue_new (manager->udev_context);
++
++  if (udev_queue_get_queue_is_empty (manager->udev_queue))
++    {
++      ply_trace ("udev coldplug completed already ");
++      create_seats_from_udev (manager);
++      return;
++    }
++
++  fd = inotify_init1 (IN_CLOEXEC);
++  result = inotify_add_watch (fd, "/run/udev", IN_MOVED_TO);
++
++  if (result < 0)
++    {
++      ply_trace ("could not watch for udev to show up: %m");
++      close (fd);
++
++      create_fallback_seat (manager);
++      return;
++    }
++
++  manager->udev_queue_fd = fd;
++
++  manager->udev_queue_fd_watch = ply_event_loop_watch_fd (manager->loop,
++                                                          fd,
++                                                          PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
++                                                          (ply_event_handler_t)
++                                                          on_udev_queue_changed,
++                                                          NULL,
++                                                          manager);
++
++}
++
++void
++ply_device_manager_watch_seats (ply_device_manager_t       *manager,
++                                ply_seat_added_handler_t    seat_added_handler,
++                                ply_seat_removed_handler_t  seat_removed_handler,
++                                void                       *data)
++{
++  bool done_with_initial_seat_setup;
++
++  manager->seat_added_handler = seat_added_handler;
++  manager->seat_removed_handler = seat_removed_handler;
++  manager->seat_event_handler_data = data;
++
++  /* Try to create seats for each serial device right away, if possible
++   */
++  done_with_initial_seat_setup = create_seats_from_terminals (manager);
++
++  if (done_with_initial_seat_setup)
++    return;
++
++  if ((manager->flags & PLY_DEVICE_MANAGER_FLAGS_IGNORE_UDEV))
++    {
++      ply_trace ("udev support disabled, creating fallback seat");
++      create_fallback_seat (manager);
++      return;
++    }
++
++  watch_for_udev_events (manager);
++  watch_for_coldplug_completion (manager);
++}
++
++bool
++ply_device_manager_has_open_seats (ply_device_manager_t *manager)
++{
++  ply_list_node_t *node;
++
++  node = ply_list_get_first_node (manager->seats);
++  while (node != NULL)
++    {
++      ply_seat_t *seat;
++      ply_list_node_t *next_node;
++
++      seat = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (manager->seats, node);
++
++      if (ply_seat_is_open (seat))
++        return true;
++
++      node = next_node;
++    }
++
++  return false;
++}
++
++ply_list_t *
++ply_device_manager_get_seats (ply_device_manager_t *manager)
++{
++  return manager->seats;
++}
++
++ply_terminal_t *
++ply_device_manager_get_default_terminal (ply_device_manager_t *manager)
++{
++  return manager->local_console_terminal;
++}
++
++void
++ply_device_manager_activate_renderers (ply_device_manager_t *manager)
++{
++  ply_list_node_t *node;
++
++  ply_trace ("activating renderers");
++  node = ply_list_get_first_node (manager->seats);
++  while (node != NULL)
++    {
++      ply_seat_t *seat;
++      ply_list_node_t *next_node;
++
++      seat = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (manager->seats, node);
++
++      ply_seat_activate_renderer (seat);
++
++      node = next_node;
++    }
++}
++
++void
++ply_device_manager_deactivate_renderers (ply_device_manager_t *manager)
++{
++  ply_list_node_t *node;
++
++  ply_trace ("deactivating renderers");
++  node = ply_list_get_first_node (manager->seats);
++  while (node != NULL)
++    {
++      ply_seat_t *seat;
++      ply_list_node_t *next_node;
++
++      seat = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (manager->seats, node);
++
++      ply_seat_deactivate_renderer (seat);
++
++      node = next_node;
++    }
++}
++
++void
++ply_device_manager_activate_keyboards (ply_device_manager_t *manager)
++{
++  ply_list_node_t *node;
++
++  ply_trace ("activating keyboards");
++  node = ply_list_get_first_node (manager->seats);
++  while (node != NULL)
++    {
++      ply_seat_t *seat;
++      ply_list_node_t *next_node;
++
++      seat = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (manager->seats, node);
++
++      ply_seat_activate_keyboard (seat);
++
++      node = next_node;
++    }
++}
++
++void
++ply_device_manager_deactivate_keyboards (ply_device_manager_t *manager)
++{
++  ply_list_node_t *node;
++
++  ply_trace ("deactivating keyboards");
++  node = ply_list_get_first_node (manager->seats);
++  while (node != NULL)
++    {
++      ply_seat_t *seat;
++      ply_list_node_t *next_node;
++
++      seat = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (manager->seats, node);
++
++      ply_seat_deactivate_keyboard (seat);
++
++      node = next_node;
++    }
++}
+diff --git a/src/libply-splash-core/ply-device-manager.h b/src/libply-splash-core/ply-device-manager.h
+new file mode 100644
+index 0000000..d9c58e8
+--- /dev/null
++++ b/src/libply-splash-core/ply-device-manager.h
+@@ -0,0 +1,56 @@
++/* ply-device-manager.h - udev monitor
++ *
++ * Copyright (C) 2013 Red Hat, Inc.
++ *
++ * 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, 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, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
++ * 02111-1307, USA.
++ */
++#ifndef PLY_DEVICE_MANAGER_H
++#define PLY_DEVICE_MANAGER_H
++
++#include <stdbool.h>
++#include "ply-seat.h"
++
++typedef enum
++{
++  PLY_DEVICE_MANAGER_FLAGS_NONE                   = 0,
++  PLY_DEVICE_MANAGER_FLAGS_IGNORE_SERIAL_CONSOLES = 1 << 0,
++  PLY_DEVICE_MANAGER_FLAGS_IGNORE_UDEV            = 1 << 1
++} ply_device_manager_flags_t;
++
++typedef struct _ply_device_manager ply_device_manager_t;
++typedef void (* ply_seat_added_handler_t) (void *, ply_seat_t *);
++typedef void (* ply_seat_removed_handler_t) (void *, ply_seat_t *);
++
++#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
++ply_device_manager_t *ply_device_manager_new (const char                 *default_tty,
++                                              ply_device_manager_flags_t  flags);
++void ply_device_manager_watch_seats (ply_device_manager_t *manager,
++                                     ply_seat_added_handler_t seat_added_handler,
++                                     ply_seat_removed_handler_t seat_removed_handler,
++                                     void *data);
++bool ply_device_manager_has_open_seats (ply_device_manager_t *manager);
++ply_list_t *ply_device_manager_get_seats (ply_device_manager_t *manager);
++void ply_device_manager_free (ply_device_manager_t *manager);
++void ply_device_manager_activate_keyboards (ply_device_manager_t *manager);
++void ply_device_manager_deactivate_keyboards (ply_device_manager_t *manager);
++void ply_device_manager_activate_renderers (ply_device_manager_t *manager);
++void ply_device_manager_deactivate_renderers (ply_device_manager_t *manager);
++ply_terminal_t *ply_device_manager_get_default_terminal (ply_device_manager_t *manager);
++
++#endif
++
++#endif
++/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
+diff --git a/src/libply-splash-core/ply-pixel-buffer.c b/src/libply-splash-core/ply-pixel-buffer.c
+index a612990..a860b7f 100644
+--- a/src/libply-splash-core/ply-pixel-buffer.c
++++ b/src/libply-splash-core/ply-pixel-buffer.c
+@@ -848,5 +848,35 @@ ply_pixel_buffer_rotate (ply_pixel_buffer_t *old_buffer,
+   return buffer;
+ }
++ply_pixel_buffer_t *
++ply_pixel_buffer_tile (ply_pixel_buffer_t *old_buffer,
++                       long                width,
++                       long                height)
++{
++  long x, y;
++  long old_x, old_y;
++  long old_width, old_height;
++  uint32_t *bytes, *old_bytes;
++  ply_pixel_buffer_t *buffer;
++
++  buffer = ply_pixel_buffer_new (width, height);
++
++  old_bytes = ply_pixel_buffer_get_argb32_data (old_buffer);
++  bytes = ply_pixel_buffer_get_argb32_data (buffer);
++
++  old_width = old_buffer->area.width;
++  old_height = old_buffer->area.height;
++
++  for (y = 0; y < height; y++)
++    {
++      old_y = y % old_height;
++      for (x = 0; x < width; x++)
++        {
++          old_x = x % old_width;
++          bytes[x + y * width] = old_bytes[old_x + old_y * old_width];
++        }
++    }
++  return buffer;
++}
+ /* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */
+diff --git a/src/libply-splash-core/ply-pixel-buffer.h b/src/libply-splash-core/ply-pixel-buffer.h
+index 47cdd52..e0dffda 100644
+--- a/src/libply-splash-core/ply-pixel-buffer.h
++++ b/src/libply-splash-core/ply-pixel-buffer.h
+@@ -124,6 +124,10 @@ ply_pixel_buffer_t *ply_pixel_buffer_rotate (ply_pixel_buffer_t *old_buffer,
+                                              long                center_y,
+                                              double              theta_offset);
++ply_pixel_buffer_t *ply_pixel_buffer_tile (ply_pixel_buffer_t *old_buffer,
++                                           long                width,
++                                           long                height);
++
+ #endif
+ #endif /* PLY_PIXEL_BUFFER_H */
+diff --git a/src/libply-splash-core/ply-renderer.c b/src/libply-splash-core/ply-renderer.c
+index 3559e01..04a99ce 100644
+--- a/src/libply-splash-core/ply-renderer.c
++++ b/src/libply-splash-core/ply-renderer.c
+@@ -49,7 +49,7 @@ struct _ply_renderer
+   const ply_renderer_plugin_interface_t *plugin_interface;
+   ply_renderer_backend_t *backend;
+-  char *plugin_path;
++  ply_renderer_type_t type;
+   char *device_name;
+   ply_terminal_t *terminal;
+@@ -63,16 +63,15 @@ typedef const ply_renderer_plugin_interface_t *
+ static void ply_renderer_unload_plugin (ply_renderer_t *renderer);
+ ply_renderer_t *
+-ply_renderer_new (const char     *plugin_path,
+-                  const char     *device_name,
+-                  ply_terminal_t *terminal)
++ply_renderer_new (ply_renderer_type_t  renderer_type,
++                  const char          *device_name,
++                  ply_terminal_t      *terminal)
+ {
+   ply_renderer_t *renderer;
+   renderer = calloc (1, sizeof (struct _ply_renderer));
+-  if (plugin_path != NULL)
+-    renderer->plugin_path = strdup (plugin_path);
++  renderer->type = renderer_type;
+   if (device_name != NULL)
+     renderer->device_name = strdup (device_name);
+@@ -95,10 +94,15 @@ ply_renderer_free (ply_renderer_t *renderer)
+     }
+   free (renderer->device_name);
+-  free (renderer->plugin_path);
+   free (renderer);
+ }
++const char *
++ply_renderer_get_device_name (ply_renderer_t *renderer)
++{
++  return renderer->device_name;
++}
++
+ static bool
+ ply_renderer_load_plugin (ply_renderer_t *renderer,
+                           const char     *module_path)
+@@ -258,29 +262,28 @@ ply_renderer_open (ply_renderer_t *renderer)
+ {
+   int i;
+-  /* FIXME: at some point we may want to make this
+-   * part more dynamic (so you don't have to edit this
+-   * list to add a new renderer)
+-   */
+-  const char *known_plugins[] =
++  struct
+     {
+-      PLYMOUTH_PLUGIN_PATH "renderers/x11.so",
+-      PLYMOUTH_PLUGIN_PATH "renderers/drm.so",
+-      PLYMOUTH_PLUGIN_PATH "renderers/frame-buffer.so",
+-      NULL
++      ply_renderer_type_t  type;
++      const char          *path;
++    } known_plugins[] =
++    {
++      { PLY_RENDERER_TYPE_X11, PLYMOUTH_PLUGIN_PATH "renderers/x11.so" },
++      { PLY_RENDERER_TYPE_DRM, PLYMOUTH_PLUGIN_PATH "renderers/drm.so" },
++      { PLY_RENDERER_TYPE_FRAME_BUFFER, PLYMOUTH_PLUGIN_PATH "renderers/frame-buffer.so" },
++      { PLY_RENDERER_TYPE_NONE, NULL }
+     };
+-  if (renderer->plugin_path != NULL)
++  for (i = 0; known_plugins[i].type != PLY_RENDERER_TYPE_NONE; i++)
+     {
+-      return ply_renderer_open_plugin (renderer, renderer->plugin_path);
++      if (renderer->type == known_plugins[i].type ||
++          renderer->type == PLY_RENDERER_TYPE_AUTO)
++        {
++          if (ply_renderer_open_plugin (renderer, known_plugins[i].path))
++            return true;
++        }
+     }
+-  for (i = 0; known_plugins[i] != NULL; i++)
+-    {
+-      if (ply_renderer_open_plugin (renderer, known_plugins[i]))
+-        return true;
+-  }
+-
+   ply_trace ("could not find suitable rendering plugin");
+   return false;
+ }
+diff --git a/src/libply-splash-core/ply-renderer.h b/src/libply-splash-core/ply-renderer.h
+index 4b3bd1a..3d48341 100644
+--- a/src/libply-splash-core/ply-renderer.h
++++ b/src/libply-splash-core/ply-renderer.h
+@@ -35,12 +35,21 @@ typedef struct _ply_renderer ply_renderer_t;
+ typedef struct _ply_renderer_head ply_renderer_head_t;
+ typedef struct _ply_renderer_input_source ply_renderer_input_source_t;
++typedef enum
++{
++  PLY_RENDERER_TYPE_NONE = -1,
++  PLY_RENDERER_TYPE_AUTO,
++  PLY_RENDERER_TYPE_DRM,
++  PLY_RENDERER_TYPE_FRAME_BUFFER,
++  PLY_RENDERER_TYPE_X11
++} ply_renderer_type_t;
++
+ typedef void (* ply_renderer_input_source_handler_t) (void                        *user_data,
+                                                       ply_buffer_t                *key_buffer,
+                                                       ply_renderer_input_source_t *input_source);
+ #ifndef PLY_HIDE_FUNCTION_DECLARATIONS
+-ply_renderer_t *ply_renderer_new (const char     *plugin_path,
++ply_renderer_t *ply_renderer_new (ply_renderer_type_t renderer_type,
+                                   const char     *device_name,
+                                   ply_terminal_t *terminal);
+ void ply_renderer_free (ply_renderer_t *renderer);
+@@ -48,6 +57,7 @@ bool ply_renderer_open (ply_renderer_t *renderer);
+ void ply_renderer_close (ply_renderer_t *renderer);
+ void ply_renderer_activate (ply_renderer_t *renderer);
+ void ply_renderer_deactivate (ply_renderer_t *renderer);
++const char *ply_renderer_get_device_name (ply_renderer_t *renderer);
+ ply_list_t *ply_renderer_get_heads (ply_renderer_t *renderer);
+ ply_pixel_buffer_t *ply_renderer_get_buffer_for_head (ply_renderer_t      *renderer,
+                                                       ply_renderer_head_t *head);
+diff --git a/src/libply-splash-core/ply-seat.c b/src/libply-splash-core/ply-seat.c
+new file mode 100644
+index 0000000..2ac8bf7
+--- /dev/null
++++ b/src/libply-splash-core/ply-seat.c
+@@ -0,0 +1,387 @@
++/* ply-seat.c - APIs for encapsulating a keyboard and one or more displays
++ *
++ * Copyright (C) 2013 Red Hat, Inc.
++ *
++ * 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, 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, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
++ * 02111-1307, USA.
++ *
++ * Written by: Ray Strode <rstrode@redhat.com>
++ */
++#include "config.h"
++#include "ply-seat.h"
++
++#include <assert.h>
++#include <errno.h>
++#include <stdint.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++
++#include "ply-boot-splash.h"
++#include "ply-event-loop.h"
++#include "ply-keyboard.h"
++#include "ply-pixel-display.h"
++#include "ply-text-display.h"
++#include "ply-list.h"
++#include "ply-logger.h"
++#include "ply-utils.h"
++
++struct _ply_seat
++{
++  ply_event_loop_t *loop;
++
++  ply_boot_splash_t *splash;
++  ply_terminal_t *terminal;
++  ply_renderer_t *renderer;
++  ply_keyboard_t *keyboard;
++  ply_list_t *text_displays;
++  ply_list_t *pixel_displays;
++
++  uint32_t renderer_active : 1;
++  uint32_t keyboard_active : 1;
++};
++
++ply_seat_t *
++ply_seat_new (ply_terminal_t *terminal)
++{
++  ply_seat_t *seat;
++
++  seat = calloc (1, sizeof (ply_seat_t));
++
++  seat->loop = ply_event_loop_get_default ();
++  seat->terminal = terminal;
++  seat->text_displays = ply_list_new ();
++  seat->pixel_displays = ply_list_new ();
++
++  return seat;
++}
++
++static void
++add_pixel_displays (ply_seat_t *seat)
++{
++  ply_list_t *heads;
++  ply_list_node_t *node;
++
++  heads = ply_renderer_get_heads (seat->renderer);
++
++  ply_trace ("Adding displays for %d heads",
++             ply_list_get_length (heads));
++
++  node = ply_list_get_first_node (heads);
++  while (node != NULL)
++    {
++      ply_list_node_t *next_node;
++      ply_renderer_head_t *head;
++      ply_pixel_display_t *display;
++
++      head = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (heads, node);
++
++      display = ply_pixel_display_new (seat->renderer, head);
++
++      ply_list_append_data (seat->pixel_displays, display);
++
++      node = next_node;
++    }
++}
++
++static void
++add_text_displays (ply_seat_t *seat)
++{
++  ply_text_display_t *display;
++
++  if (!ply_terminal_is_open (seat->terminal))
++    {
++      if (!ply_terminal_open (seat->terminal))
++        {
++          ply_trace ("could not add terminal %s: %m",
++                     ply_terminal_get_name (seat->terminal));
++          return;
++        }
++    }
++
++  ply_trace ("adding text display for terminal %s",
++             ply_terminal_get_name (seat->terminal));
++
++  display = ply_text_display_new (seat->terminal);
++  ply_list_append_data (seat->text_displays, display);
++}
++
++bool
++ply_seat_open (ply_seat_t          *seat,
++               ply_renderer_type_t  renderer_type,
++               const char          *device)
++{
++  if (renderer_type != PLY_RENDERER_TYPE_NONE)
++    {
++      ply_renderer_t *renderer;
++
++      renderer = ply_renderer_new (renderer_type, device, seat->terminal);
++
++      if (!ply_renderer_open (renderer))
++        {
++          ply_trace ("could not open renderer for %s", device);
++          ply_renderer_free (renderer);
++
++          seat->renderer = NULL;
++          seat->renderer_active = false;
++
++          if (renderer_type != PLY_RENDERER_TYPE_AUTO)
++            return false;
++        }
++      else
++        {
++          seat->renderer = renderer;
++          seat->renderer_active = true;
++        }
++    }
++
++  if (seat->renderer != NULL)
++    {
++      seat->keyboard = ply_keyboard_new_for_renderer (seat->renderer);
++      add_pixel_displays (seat);
++
++    }
++  else
++    {
++      seat->keyboard = ply_keyboard_new_for_terminal (seat->terminal);
++    }
++  add_text_displays (seat);
++
++  ply_keyboard_watch_for_input (seat->keyboard);
++  seat->keyboard_active = true;
++
++  return true;
++}
++
++bool
++ply_seat_is_open (ply_seat_t *seat)
++{
++  return ply_list_get_length (seat->pixel_displays) > 0 ||
++         ply_list_get_length (seat->text_displays) > 0;
++}
++
++void
++ply_seat_deactivate_keyboard (ply_seat_t *seat)
++{
++  if (!seat->keyboard_active)
++    return;
++
++  seat->keyboard_active = false;
++
++  if (seat->keyboard == NULL)
++    return;
++
++  ply_trace ("deactivating keybord");
++  ply_keyboard_stop_watching_for_input (seat->keyboard);
++}
++
++void
++ply_seat_deactivate_renderer (ply_seat_t *seat)
++{
++  if (!seat->renderer_active)
++    return;
++
++  seat->renderer_active = false;
++
++  if (seat->renderer == NULL)
++    return;
++
++  ply_trace ("deactivating renderer");
++  ply_renderer_deactivate (seat->renderer);
++}
++
++void
++ply_seat_activate_keyboard (ply_seat_t *seat)
++{
++  if (seat->keyboard_active)
++    return;
++
++  if (seat->keyboard == NULL)
++    return;
++
++  ply_trace ("activating keyboard");
++  ply_keyboard_watch_for_input (seat->keyboard);
++
++  seat->keyboard_active = true;
++}
++
++void
++ply_seat_activate_renderer (ply_seat_t *seat)
++{
++  if (seat->renderer_active)
++    return;
++
++  if (seat->renderer == NULL)
++    return;
++
++  ply_trace ("activating renderer");
++  ply_renderer_activate (seat->renderer);
++
++  seat->renderer_active = true;
++}
++
++void
++ply_seat_refresh_displays (ply_seat_t *seat)
++{
++  ply_list_node_t *node;
++
++  node = ply_list_get_first_node (seat->pixel_displays);
++  while (node != NULL)
++    {
++      ply_pixel_display_t *display;
++      ply_list_node_t *next_node;
++      unsigned long width, height;
++
++      display = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (seat->pixel_displays, node);
++
++      width = ply_pixel_display_get_width (display);
++      height = ply_pixel_display_get_height (display);
++
++      ply_pixel_display_draw_area (display, 0, 0, width, height);
++      node = next_node;
++    }
++
++  node = ply_list_get_first_node (seat->text_displays);
++  while (node != NULL)
++    {
++      ply_text_display_t *display;
++      ply_list_node_t *next_node;
++      int number_of_columns, number_of_rows;
++
++      display = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (seat->text_displays, node);
++
++      number_of_columns = ply_text_display_get_number_of_columns (display);
++      number_of_rows = ply_text_display_get_number_of_rows (display);
++
++      ply_text_display_draw_area (display, 0, 0,
++                                  number_of_columns,
++                                  number_of_rows);
++      node = next_node;
++    }
++}
++
++void
++ply_seat_close (ply_seat_t *seat)
++{
++  if (seat->renderer == NULL)
++    return;
++
++  ply_trace ("destroying renderer");
++  ply_renderer_close (seat->renderer);
++  ply_renderer_free (seat->renderer);
++  seat->renderer = NULL;
++}
++
++void
++ply_seat_set_splash (ply_seat_t        *seat,
++                     ply_boot_splash_t *splash)
++{
++  if (seat->splash == splash)
++    return;
++
++  if (seat->splash != NULL)
++    ply_boot_splash_detach_from_seat (splash, seat);
++
++  if (splash != NULL)
++    ply_boot_splash_attach_to_seat (splash, seat);
++
++  seat->splash = splash;
++}
++
++static void
++free_pixel_displays (ply_seat_t *seat)
++{
++  ply_list_node_t *node;
++
++  ply_trace ("freeing %d pixel displays", ply_list_get_length (seat->pixel_displays));
++  node = ply_list_get_first_node (seat->pixel_displays);
++  while (node != NULL)
++    {
++      ply_list_node_t *next_node;
++      ply_pixel_display_t *display;
++
++      next_node = ply_list_get_next_node (seat->pixel_displays, node);
++      display = ply_list_node_get_data (node);
++      ply_pixel_display_free (display);
++
++      ply_list_remove_node (seat->pixel_displays, node);
++
++      node = next_node;
++    }
++}
++
++static void
++free_text_displays (ply_seat_t *seat)
++{
++  ply_list_node_t *node;
++
++  ply_trace ("freeing %d text displays", ply_list_get_length (seat->text_displays));
++  node = ply_list_get_first_node (seat->text_displays);
++  while (node != NULL)
++    {
++      ply_list_node_t *next_node;
++      ply_text_display_t *display;
++
++      next_node = ply_list_get_next_node (seat->text_displays, node);
++      display = ply_list_node_get_data (node);
++      ply_text_display_free (display);
++
++      ply_list_remove_node (seat->text_displays, node);
++
++      node = next_node;
++    }
++}
++
++void
++ply_seat_free (ply_seat_t *seat)
++{
++  if (seat == NULL)
++    return;
++
++  free_pixel_displays (seat);
++  free_text_displays (seat);
++  ply_keyboard_free (seat->keyboard);
++
++  free (seat);
++}
++
++ply_list_t *
++ply_seat_get_pixel_displays (ply_seat_t *seat)
++{
++  return seat->pixel_displays;
++}
++
++ply_list_t *
++ply_seat_get_text_displays (ply_seat_t *seat)
++{
++  return seat->text_displays;
++}
++
++ply_keyboard_t *
++ply_seat_get_keyboard (ply_seat_t *seat)
++{
++  return seat->keyboard;
++}
++
++ply_renderer_t *
++ply_seat_get_renderer (ply_seat_t *seat)
++{
++  return seat->renderer;
++}
++
++/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */
+diff --git a/src/libply-splash-core/ply-seat.h b/src/libply-splash-core/ply-seat.h
+new file mode 100644
+index 0000000..d5d3397
+--- /dev/null
++++ b/src/libply-splash-core/ply-seat.h
+@@ -0,0 +1,66 @@
++/* ply-seat.h - APIs for encapsulating a keyboard and one or more displays
++ *
++ * Copyright (C) 2013 Red Hat, Inc.
++ *
++ * 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, 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, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
++ * 02111-1307, USA.
++ *
++ * Written By: Ray Strode <rstrode@redhat.com>
++ */
++#ifndef PLY_SEAT_H
++#define PLY_SEAT_H
++
++#include <stdarg.h>
++#include <stdbool.h>
++#include <stdint.h>
++#include <unistd.h>
++
++#include "ply-boot-splash.h"
++#include "ply-buffer.h"
++#include "ply-event-loop.h"
++#include "ply-keyboard.h"
++#include "ply-list.h"
++#include "ply-pixel-display.h"
++#include "ply-terminal.h"
++#include "ply-text-display.h"
++
++typedef struct _ply_boot_splash ply_boot_splash_t;
++typedef struct _ply_seat ply_seat_t;
++
++#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
++ply_seat_t *ply_seat_new (ply_terminal_t *terminal);
++
++void ply_seat_free (ply_seat_t *seat);
++bool ply_seat_open (ply_seat_t          *seat,
++                    ply_renderer_type_t  renderer_type,
++                    const char          *device);
++bool ply_seat_is_open (ply_seat_t *seat);
++void ply_seat_deactivate_keyboard (ply_seat_t *seat);
++void ply_seat_activate_keyboard (ply_seat_t *seat);
++void ply_seat_deactivate_renderer (ply_seat_t *seat);
++void ply_seat_activate_renderer (ply_seat_t *seat);
++void ply_seat_refresh_displays (ply_seat_t *seat);
++void ply_seat_close (ply_seat_t *seat);
++void ply_seat_set_splash (ply_seat_t        *seat,
++                          ply_boot_splash_t *splash);
++
++ply_list_t *ply_seat_get_pixel_displays (ply_seat_t *seat);
++ply_list_t *ply_seat_get_text_displays (ply_seat_t *seat);
++ply_keyboard_t *ply_seat_get_keyboard (ply_seat_t *seat);
++ply_renderer_t *ply_seat_get_renderer (ply_seat_t *seat);
++#endif
++
++#endif /* PLY_SEAT_H */
++/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */
+diff --git a/src/libply-splash-core/ply-terminal.c b/src/libply-splash-core/ply-terminal.c
+index 2e95dc8..992dd3f 100644
+--- a/src/libply-splash-core/ply-terminal.c
++++ b/src/libply-splash-core/ply-terminal.c
+@@ -876,6 +876,12 @@ ply_terminal_free (ply_terminal_t *terminal)
+   free (terminal);
+ }
++const char *
++ply_terminal_get_name (ply_terminal_t *terminal)
++{
++  return terminal->name;
++}
++
+ int
+ ply_terminal_get_vt_number (ply_terminal_t *terminal)
+ {
+diff --git a/src/libply-splash-core/ply-terminal.h b/src/libply-splash-core/ply-terminal.h
+index 8b4b017..48b4f77 100644
+--- a/src/libply-splash-core/ply-terminal.h
++++ b/src/libply-splash-core/ply-terminal.h
+@@ -91,6 +91,7 @@ void ply_terminal_set_mode (ply_terminal_t     *terminal,
+ void ply_terminal_ignore_mode_changes (ply_terminal_t *terminal,
+                                        bool            should_ignore);
++const char *ply_terminal_get_name (ply_terminal_t *terminal);
+ int ply_terminal_get_vt_number (ply_terminal_t *terminal);
+ bool ply_terminal_activate_vt (ply_terminal_t *terminal);
+ bool ply_terminal_deactivate_vt (ply_terminal_t *terminal);
+diff --git a/src/libply-splash-core/ply-text-progress-bar.c b/src/libply-splash-core/ply-text-progress-bar.c
+index bf4b378..8c4e759 100644
+--- a/src/libply-splash-core/ply-text-progress-bar.c
++++ b/src/libply-splash-core/ply-text-progress-bar.c
+@@ -104,7 +104,7 @@ get_os_string (void)
+   buf = NULL;
+-  fd = open (RELEASE_FILE, O_RDONLY);
++  fd = open (RELEASE_FILE, O_RDONLY|O_CLOEXEC);
+   if (fd == -1)
+     goto out;
+@@ -136,6 +136,8 @@ get_os_string (void)
+           if (pos2 != NULL)
+             *pos2 = '\0';
++          else
++            pos2 = pos + strlen(pos) - 1;
+           if ((*pos == '\"' && pos2[-1] == '\"') ||
+               (*pos == '\'' && pos2[-1] == '\''))
+diff --git a/src/libply-splash-core/ply-text-step-bar.c b/src/libply-splash-core/ply-text-step-bar.c
+new file mode 100644
+index 0000000..552a39f
+--- /dev/null
++++ b/src/libply-splash-core/ply-text-step-bar.c
+@@ -0,0 +1,163 @@
++/*
++ * Copyright (C) 2008-2012 Red Hat, Inc.
++ *
++ * 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, 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, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
++ * 02111-1307, USA.
++ *
++ */
++#include "config.h"
++
++#include <assert.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++
++#include "ply-text-display.h"
++#include "ply-text-step-bar.h"
++
++struct _ply_text_step_bar
++{
++  ply_text_display_t *display;
++
++  int column;
++  int row;
++  int number_of_rows;
++  int number_of_columns;
++
++  double percent_done;
++  uint32_t is_hidden : 1;
++};
++
++ply_text_step_bar_t *
++ply_text_step_bar_new (void)
++{
++  ply_text_step_bar_t *step_bar;
++
++  step_bar = calloc (1, sizeof (ply_text_step_bar_t));
++
++  step_bar->row = 0;
++  step_bar->column = 0;
++  step_bar->number_of_columns = 0;
++  step_bar->number_of_rows = 0;
++
++  return step_bar;
++}
++
++void
++ply_text_step_bar_free (ply_text_step_bar_t *step_bar)
++{
++  if (step_bar == NULL)
++    return;
++
++  free (step_bar);
++}
++
++void
++ply_text_step_bar_draw (ply_text_step_bar_t *step_bar)
++{
++  int i;
++  int cur;
++
++  if (step_bar->is_hidden)
++    return;
++
++  ply_text_display_set_background_color (step_bar->display,
++                                         PLY_TERMINAL_COLOR_BLACK);
++
++  ply_text_display_set_cursor_position (step_bar->display,
++                                        step_bar->column,
++                                        step_bar->row);
++
++  cur = step_bar->percent_done * step_bar->number_of_columns;
++  for (i = 0; i < step_bar->number_of_columns; i++)
++    {
++      if (i == cur)
++        {
++          ply_text_display_set_foreground_color (step_bar->display,
++                                                 PLY_TERMINAL_COLOR_WHITE);
++        }
++      else
++        {
++          ply_text_display_set_foreground_color (step_bar->display,
++                                                 PLY_TERMINAL_COLOR_BROWN);
++        }
++
++      ply_text_display_write (step_bar->display, "%c", '■');
++      ply_text_display_write (step_bar->display, "%c", ' ');
++    }
++
++  ply_text_display_set_foreground_color (step_bar->display,
++                                         PLY_TERMINAL_COLOR_DEFAULT);
++}
++
++void
++ply_text_step_bar_show (ply_text_step_bar_t  *step_bar,
++                        ply_text_display_t       *display)
++{
++  int screen_rows;
++  int screen_cols;
++
++  assert (step_bar != NULL);
++
++  step_bar->display = display;
++
++
++  screen_rows = ply_text_display_get_number_of_rows (display);
++  screen_cols = ply_text_display_get_number_of_columns (display);
++
++  step_bar->number_of_rows = 1;
++  step_bar->row = screen_rows * .66;
++  step_bar->number_of_columns = 3;
++  step_bar->column = screen_cols / 2.0 - step_bar->number_of_columns / 2.0;
++
++  step_bar->is_hidden = false;
++
++  ply_text_step_bar_draw (step_bar);
++}
++
++void
++ply_text_step_bar_hide (ply_text_step_bar_t *step_bar)
++{
++  step_bar->display = NULL;
++  step_bar->is_hidden = true;
++}
++
++void
++ply_text_step_bar_set_percent_done (ply_text_step_bar_t  *step_bar,
++                                    double percent_done)
++{
++  step_bar->percent_done = percent_done;
++}
++
++double
++ply_text_step_bar_get_percent_done (ply_text_step_bar_t  *step_bar)
++{
++  return step_bar->percent_done;
++}
++
++int
++ply_text_step_bar_get_number_of_columns (ply_text_step_bar_t *step_bar)
++{
++  return step_bar->number_of_columns;
++}
++
++int
++ply_text_step_bar_get_number_of_rows (ply_text_step_bar_t *step_bar)
++{
++  return step_bar->number_of_rows;
++}
++
++/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
+diff --git a/src/libply-splash-core/ply-text-step-bar.h b/src/libply-splash-core/ply-text-step-bar.h
+new file mode 100644
+index 0000000..0a4733f
+--- /dev/null
++++ b/src/libply-splash-core/ply-text-step-bar.h
+@@ -0,0 +1,49 @@
++/*
++ * Copyright (C) 2008-2012 Red Hat, Inc.
++ *
++ * 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, 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, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
++ * 02111-1307, USA.
++ *
++ */
++#ifndef PLY_TEXT_STEP_BAR_H
++#define PLY_TEXT_STEP_BAR_H
++
++#include <unistd.h>
++
++#include "ply-event-loop.h"
++#include "ply-text-display.h"
++
++typedef struct _ply_text_step_bar ply_text_step_bar_t;
++
++#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
++ply_text_step_bar_t *ply_text_step_bar_new (void);
++void ply_text_step_bar_free (ply_text_step_bar_t *step_bar);
++
++void ply_text_step_bar_draw (ply_text_step_bar_t *step_bar);
++void ply_text_step_bar_show (ply_text_step_bar_t *step_bar,
++                             ply_text_display_t *display);
++void ply_text_step_bar_hide (ply_text_step_bar_t *step_bar);
++
++void ply_text_step_bar_set_percent_done (ply_text_step_bar_t *step_bar,
++                                         double percent_done);
++
++double ply_text_step_bar_get_percent_done (ply_text_step_bar_t *step_bar);
++
++int ply_text_step_bar_get_number_of_rows (ply_text_step_bar_t *step_bar);
++int ply_text_step_bar_get_number_of_columns (ply_text_step_bar_t *step_bar);
++#endif
++
++#endif /* PLY_TEXT_PULSER_H */
++/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
+diff --git a/src/libply-splash-graphics/Makefile.am b/src/libply-splash-graphics/Makefile.am
+index f70d1ed..9013e56 100644
+--- a/src/libply-splash-graphics/Makefile.am
++++ b/src/libply-splash-graphics/Makefile.am
+@@ -1,4 +1,4 @@
+-INCLUDES = -I$(top_srcdir)                                                    \
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
+            -I$(srcdir)                                                        \
+            -I$(srcdir)/../libply                                              \
+            -I$(srcdir)/../libply-splash-core                                  \
+diff --git a/src/libply-splash-graphics/ply-animation.c b/src/libply-splash-graphics/ply-animation.c
+index ed558cf..bba8490 100644
+--- a/src/libply-splash-graphics/ply-animation.c
++++ b/src/libply-splash-graphics/ply-animation.c
+@@ -182,14 +182,8 @@ on_timeout (ply_animation_t *animation)
+   animation->previous_time = animation->now;
+   animation->now = ply_get_timestamp ();
+-#ifdef REAL_TIME_ANIMATION
+   should_continue = animate_at_time (animation,
+                                      animation->now - animation->start_time);
+-#else
+-  static double time = 0.0;
+-  time += 1.0 / FRAMES_PER_SECOND;
+-  should_continue = animate_at_time (animation, time);
+-#endif
+   sleep_time = 1.0 / FRAMES_PER_SECOND;
+   sleep_time = MAX (sleep_time - (ply_get_timestamp () - animation->now),
+diff --git a/src/libply-splash-graphics/ply-image.c b/src/libply-splash-graphics/ply-image.c
+index 3e09f68..7d21946 100644
+--- a/src/libply-splash-graphics/ply-image.c
++++ b/src/libply-splash-graphics/ply-image.c
+@@ -123,7 +123,7 @@ ply_image_load (ply_image_t *image)
+   
+   assert (image != NULL);
+   
+-  fp = fopen (image->filename, "r");
++  fp = fopen (image->filename, "re");
+   if (fp == NULL)
+     return false;
+   
+@@ -254,6 +254,21 @@ ply_image_rotate (ply_image_t *image,
+   return new_image;
+ }
++ply_image_t *
++ply_image_tile (ply_image_t *image,
++                long         width,
++                long         height)
++{
++  ply_image_t *new_image;
++
++  new_image = ply_image_new (image->filename);
++
++  new_image->buffer = ply_pixel_buffer_tile (image->buffer,
++                                             width,
++                                             height);
++  return new_image;
++}
++
+ ply_pixel_buffer_t *
+ ply_image_get_buffer (ply_image_t *image)
+ {
+diff --git a/src/libply-splash-graphics/ply-image.h b/src/libply-splash-graphics/ply-image.h
+index 66fa520..5bda567 100644
+--- a/src/libply-splash-graphics/ply-image.h
++++ b/src/libply-splash-graphics/ply-image.h
+@@ -39,6 +39,7 @@ long ply_image_get_width (ply_image_t *image);
+ long ply_image_get_height (ply_image_t *image);
+ ply_image_t *ply_image_resize (ply_image_t *image, long width, long height);
+ ply_image_t *ply_image_rotate (ply_image_t *oldimage, long center_x, long center_y, double theta_offset);
++ply_image_t *ply_image_tile (ply_image_t *image, long width, long height);
+ ply_pixel_buffer_t *ply_image_get_buffer (ply_image_t *image);
+ ply_pixel_buffer_t *ply_image_convert_to_pixel_buffer (ply_image_t *image);
+diff --git a/src/libply-splash-graphics/ply-throbber.c b/src/libply-splash-graphics/ply-throbber.c
+index 59cf10c..42044ba 100644
+--- a/src/libply-splash-graphics/ply-throbber.c
++++ b/src/libply-splash-graphics/ply-throbber.c
+@@ -178,14 +178,8 @@ on_timeout (ply_throbber_t *throbber)
+   bool should_continue;
+   throbber->now = ply_get_timestamp ();
+-#ifdef REAL_TIME_ANIMATION
+   should_continue = animate_at_time (throbber,
+-                                 throbber->now - throbber->start_time);
+-#else
+-  static double time = 0.0;
+-  time += 1.0 / FRAMES_PER_SECOND;
+-  should_continue = animate_at_time (throbber, time);
+-#endif
++                                     throbber->now - throbber->start_time);
+   sleep_time = 1.0 / FRAMES_PER_SECOND;
+   sleep_time = MAX (sleep_time - (ply_get_timestamp () - throbber->now),
+diff --git a/src/libply/Makefile.am b/src/libply/Makefile.am
+index 302e47d..de15808 100644
+--- a/src/libply/Makefile.am
++++ b/src/libply/Makefile.am
+@@ -1,5 +1,4 @@
+-SUBDIRS = tests
+-INCLUDES = -I$(top_srcdir)                                                    \
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
+            -I$(srcdir)                                                        \
+            -DPLYMOUTH_TIME_DIRECTORY=\"$(localstatedir)/lib/plymouth/\"       
+diff --git a/src/libply/ply-array.c b/src/libply/ply-array.c
+index 41134b8..999c86e 100644
+--- a/src/libply/ply-array.c
++++ b/src/libply/ply-array.c
+@@ -171,34 +171,4 @@ ply_array_steal_uint32_elements (ply_array_t *array)
+   return data;
+ }
+-#ifdef PLY_ARRAY_ENABLE_TEST
+-#include <stdio.h>
+-
+-int
+-main (int    argc,
+-      char **argv)
+-{
+-  ply_array_t *array;
+-  int i;
+-  char **data;
+-
+-  array = ply_array_new (PLY_ARRAY_ELEMENT_TYPE_POINTER);
+-
+-  ply_array_add_pointer_element (array, "foo");
+-  ply_array_add_pointer_element (array, "bar");
+-  ply_array_add_pointer_element (array, "baz");
+-  ply_array_add_pointer_element (array, "qux");
+-
+-  data = (char **) ply_array_get_pointer_elements (array);
+-  for (i = 0; data[i] != NULL; i++)
+-    {
+-      printf ("element '%d' has data '%s'\n", i, data[i]);
+-      i++;
+-    }
+-
+-  ply_array_free (array);
+-  return 0;
+-}
+-
+-#endif
+ /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
+diff --git a/src/libply/ply-bitarray.c b/src/libply/ply-bitarray.c
+index 89e2216..3d0cdd0 100644
+--- a/src/libply/ply-bitarray.c
++++ b/src/libply/ply-bitarray.c
+@@ -42,64 +42,4 @@ ply_bitarray_count (ply_bitarray_t *bitarray,
+   return count;
+ }
+-
+-
+-
+-#ifdef PLY_BITARRAY_ENABLE_TEST
+-#include <stdio.h>
+-
+-int
+-main (int    argc,
+-      char **argv)
+-{
+-  ply_bitarray_t *bitarray;
+-  int i, i2;
+-  printf ("bitarray test start\n");
+-  bitarray = ply_bitarray_new (134);
+-  
+-  for (i=0; i<64; i++)
+-    {
+-      if (ply_bitarray_lookup (bitarray, i))
+-        printf ("1");
+-      else
+-        printf ("0");
+-    }
+-  printf ("\n");
+-  
+-  for (i=0; i<64; i++)
+-    if ((6654654654654654654ll >> i) & 1)
+-      ply_bitarray_set (bitarray, i);
+-  
+-  for (i=0; i<64; i++)
+-    {
+-      if (ply_bitarray_lookup (bitarray, i))
+-        printf ("1");
+-      else
+-        printf ("0");
+-    }
+-  printf ("\n");
+-    
+-  for (i = 63; i > 0; i--)
+-    {
+-      if ((6654654654654654654ll >> i) & 1)
+-        {
+-          ply_bitarray_clear (bitarray, i);
+-          for (i2 = 0; i2 < 64; i2++)
+-            {
+-              if (ply_bitarray_lookup (bitarray, i2))
+-                printf ("1");
+-              else
+-                printf ("0"); 
+-            }
+-          printf ("\n");
+-        }
+-    }
+-    
+-  ply_bitarray_free (bitarray);
+-  
+-  printf ("bitarray test end\n");
+-  return 0;
+-}
+-
+-#endif
+ /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
+diff --git a/src/libply/ply-buffer.c b/src/libply/ply-buffer.c
+index c65634f..0d0406f 100644
+--- a/src/libply/ply-buffer.c
++++ b/src/libply/ply-buffer.c
+@@ -263,22 +263,4 @@ ply_buffer_clear (ply_buffer_t *buffer)
+   buffer->size = 0;
+ }
+-#ifdef PLY_BUFFER_ENABLE_TEST
+-int
+-main (int    argc,
+-      char **argv)
+-{
+-  int exit_code;
+-  ply_buffer_t *buffer;
+-
+-  exit_code = 0;
+-  buffer = ply_buffer_new ();
+-
+-  ply_buffer_append (buffer, "yo yo yo\n");
+-  ply_buffer_free (buffer);
+-
+-  return exit_code;
+-}
+-
+-#endif /* PLY_BUFFER_ENABLE_TEST */
+ /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
+diff --git a/src/libply/ply-command-parser.c b/src/libply/ply-command-parser.c
+index 6ab323b..2768668 100644
+--- a/src/libply/ply-command-parser.c
++++ b/src/libply/ply-command-parser.c
+@@ -968,100 +968,4 @@ ply_command_parser_parse_arguments (ply_command_parser_t *parser,
+   return parsed_arguments;
+ }
+-#ifdef PLY_COMMAND_PARSER_ENABLE_TEST
+-
+-#include <stdio.h>
+-
+-#include "ply-command-parser.h"
+-#include "ply-event-loop.h"
+-#include "ply-logger.h"
+-
+-static void
+-on_ask_for_password (ply_command_parser_t *parser,
+-                     const char *command)
+-{
+-  char *prompt;
+-  char *program;
+-
+-  prompt = NULL;
+-  program = NULL;
+-  ply_command_parser_get_command_options (parser, command, "prompt", &prompt, "command", &program, NULL);
+-
+-  printf ("ask for password with prompt '%s' feed result to '%s'\n", prompt, program);
+-  free (prompt);
+-  free (program);
+-}
+-
+-static void
+-on_show_splash (ply_command_parser_t *parser,
+-                const char *command)
+-{
+-  char *plugin_name;
+-
+-  plugin_name = NULL;
+-  ply_command_parser_get_command_options (parser, command, "plugin-name", &plugin_name, NULL);
+-
+-  printf ("show splash plugin '%s'\n", plugin_name);
+-  free (plugin_name);
+-}
+-
+-int
+-main (int    argc,
+-      char **argv)
+-{
+-  ply_event_loop_t *loop;
+-  ply_command_parser_t *parser;
+-  bool should_help;
+-
+-  loop = ply_event_loop_new ();
+-  parser = ply_command_parser_new (argv[0], "Test Program");
+-
+-  ply_command_parser_add_options (parser,
+-                                  "help", "This help message", PLY_COMMAND_OPTION_TYPE_FLAG,
+-                                  NULL);
+-
+-  ply_command_parser_add_command (parser,
+-                                  "ask-for-password",
+-                                  "Ask user for password",
+-                                  (ply_command_handler_t)
+-                                  on_ask_for_password, parser,
+-                                  "command", "command to pipe result to", PLY_COMMAND_OPTION_TYPE_STRING,
+-                                  "prompt", "string to present to user", PLY_COMMAND_OPTION_TYPE_STRING,
+-                                  "output-result", "print result", PLY_COMMAND_OPTION_TYPE_BOOLEAN,
+-                                  NULL);
+-
+-  ply_command_parser_add_command (parser,
+-                                  "show-splash",
+-                                  "Show splash to user",
+-                                  (ply_command_handler_t)
+-                                  on_show_splash, parser,
+-                                  "plugin-name", "name of the plugin to run", PLY_COMMAND_OPTION_TYPE_STRING,
+-                                  NULL);
+-
+-  if (!ply_command_parser_parse_arguments (parser, loop, argv, argc))
+-    {
+-      ply_error ("couldn't parse arguments");
+-      return 1;
+-    }
+-
+-
+-  ply_command_parser_get_options (parser, "help", &should_help, NULL);
+-
+-  if (should_help)
+-    {
+-      char *usage;
+-      usage = ply_command_parser_get_help_string (parser);
+-      printf ("%s\n", usage);
+-      free (usage);
+-      return 0;
+-    }
+-
+-  ply_event_loop_run (loop);
+-
+-  ply_command_parser_free (parser);
+-
+-  return 0;
+-}
+-
+-#endif
+ /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
+diff --git a/src/libply/ply-event-loop.c b/src/libply/ply-event-loop.c
+index 3cfad76..0c85cb9 100644
+--- a/src/libply/ply-event-loop.c
++++ b/src/libply/ply-event-loop.c
+@@ -491,7 +491,7 @@ ply_event_loop_new (void)
+   loop = calloc (1, sizeof (ply_event_loop_t));
+-  loop->epoll_fd = epoll_create (PLY_EVENT_LOOP_NUM_EVENT_HANDLERS);
++  loop->epoll_fd =  epoll_create1(EPOLL_CLOEXEC);
+   loop->wakeup_time = PLY_EVENT_LOOP_NO_TIMED_WAKEUP;
+   assert (loop->epoll_fd >= 0);
+@@ -1376,88 +1376,4 @@ ply_event_loop_run (ply_event_loop_t *loop)
+   return loop->exit_code;
+ }
+-#ifdef PLY_EVENT_LOOP_ENABLE_TEST
+-
+-static ply_event_loop_t *loop;
+-
+-static void
+-alrm_signal_handler (void)
+-{
+-  write (1, "times up!\n", sizeof ("times up!\n") - 1);
+-  ply_event_loop_exit (loop, 0);
+-}
+-
+-static void
+-usr1_signal_handler (void)
+-{
+-  write (1, "got sigusr1\n", sizeof ("got sigusr1\n") - 1);
+-}
+-
+-static void
+-hangup_signal_handler (void)
+-{
+-  write (1, "got hangup\n", sizeof ("got hangup\n") - 1);
+-}
+-
+-static void
+-terminate_signal_handler (void)
+-{
+-  write (1, "got terminate\n", sizeof ("got terminate\n") - 1);
+-  ply_event_loop_exit (loop, 0);
+-}
+-
+-static void
+-line_received_handler (void)
+-{
+-  char line[512] = { 0 };
+-  printf ("Received line: ");
+-  fflush (stdout);
+-
+-  fgets (line, sizeof (line), stdin);
+-  printf ("%s", line);
+-}
+-
+-static void
+-on_timeout (ply_event_loop_t *loop)
+-{
+-  printf ("timeout elapsed\n");
+-}
+-
+-int
+-main (int    argc,
+-      char **argv)
+-{
+-  int exit_code;
+-
+-  loop = ply_event_loop_new ();
+-
+-  ply_event_loop_watch_signal (loop, SIGHUP,
+-                             (ply_event_handler_t) hangup_signal_handler,
+-                             NULL);
+-  ply_event_loop_watch_signal (loop, SIGTERM,
+-                             (ply_event_handler_t)
+-                             terminate_signal_handler, NULL);
+-  ply_event_loop_watch_signal (loop, SIGUSR1,
+-                             (ply_event_handler_t)
+-                             usr1_signal_handler, NULL);
+-  ply_event_loop_watch_signal (loop, SIGALRM,
+-                             (ply_event_handler_t)
+-                             alrm_signal_handler, NULL);
+-
+-  ply_event_loop_watch_for_timeout (loop, 2.0,
+-                                    (ply_event_loop_timeout_handler_t)
+-                                    on_timeout, loop);
+-  ply_event_loop_watch_fd (loop, 0, PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
+-                          (ply_event_handler_t) line_received_handler,
+-                          (ply_event_handler_t) line_received_handler,
+-                          NULL);
+-
+-  alarm (5);
+-  exit_code = ply_event_loop_run (loop);
+-
+-  ply_event_loop_free (loop);
+-
+-  return exit_code;
+-}
+-#endif /* PLY_EVENT_LOOP_ENABLE_TEST */
+ /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
+diff --git a/src/libply/ply-hashtable.c b/src/libply/ply-hashtable.c
+index 7d8d648..7b03d87 100644
+--- a/src/libply/ply-hashtable.c
++++ b/src/libply/ply-hashtable.c
+@@ -130,14 +130,6 @@ ply_hashtable_insert_internal (ply_hashtable_t *hashtable,
+ {
+   unsigned int hash_index;
+   int step = 0;
+-  
+-#ifdef PLY_HASHTABLE_ENABLE_TEST
+-    /* Make sure the counts are synchronised with bitmap */
+-  assert (ply_bitarray_count (hashtable->dirty_node_bitmap, hashtable->total_node_count) ==
+-          (int) hashtable->dirty_node_count);
+-  assert (ply_bitarray_count (hashtable->live_node_bitmap, hashtable->total_node_count) ==
+-          (int) hashtable->live_node_count);
+-#endif /* PLY_HASHTABLE_ENABLE_TEST */
+   hash_index = hashtable->hash_func (key);
+   hash_index &= hashtable->total_node_count - 1;
+@@ -281,56 +273,10 @@ ply_hashtable_foreach (ply_hashtable_t              *hashtable,
+     }
+ }
+-
+-#ifdef PLY_HASHTABLE_ENABLE_TEST
+-#include <stdio.h>
+-
+-static void
+-foreach_func (void *key,
+-              void *data,
+-              void *user_data)
+-{
+-  printf ("foreach key:%s data:%s\n", (char*) key, (char*) data);
+-}
+-
+-
+ int
+-main (int    argc,
+-      char **argv)
++ply_hashtable_get_size (ply_hashtable_t *hashtable)
+ {
+-  ply_hashtable_t *hashtable;
+-  int i;
+-  const char* key[10] =  {"k1", "k2", "k3", "k4", "k5", "k6", "k7", "k8", "k9", "k10"};
+-  const char* data[10] = {"d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10"};
+-  char* reply_key = NULL;
+-  char* reply_data = NULL;
+-  
+-  printf ("hashtable test start\n");
+-  hashtable = ply_hashtable_new (ply_hashtable_string_hash, ply_hashtable_string_compare);
+-  for (i=0; i<10; i++)
+-    {
+-      ply_hashtable_insert (hashtable, (void *) key[i], (void *) data[9-i]);
+-    }
+-  for (i=0; i<10; i++)
+-    {
+-      reply_data = ply_hashtable_lookup (hashtable, (void *) key[i]);
+-      printf ("got:%s\n", reply_data);
+-    }
+-  for (i=0; i<10; i++)
+-    {
+-      ply_hashtable_remove (hashtable, (void *) key[i]);
+-      ply_hashtable_insert (hashtable, (void *) key[i], (void *) data[i]);
+-    }
+-  for (i=0; i<10; i++)
+-    {
+-      if (ply_hashtable_lookup_full (hashtable, (void *) key[i], (void**) &reply_key, (void**) &reply_data))
+-        printf ("got key:%s data:%s\n", reply_key, reply_data);
+-    }
+-  ply_hashtable_foreach (hashtable, foreach_func, NULL);
+-  ply_hashtable_free(hashtable);
+-  printf ("hashtable test end\n");
+-  return 0;
++  return hashtable->live_node_count;
+ }
+-#endif
+ /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
+diff --git a/src/libply/ply-hashtable.h b/src/libply/ply-hashtable.h
+index 016c781..e7e1a6e 100644
+--- a/src/libply/ply-hashtable.h
++++ b/src/libply/ply-hashtable.h
+@@ -57,6 +57,8 @@ int ply_hashtable_lookup_full (ply_hashtable_t *hashtable,
+ void ply_hashtable_foreach (ply_hashtable_t              *hashtable,
+                                                       ply_hashtable_foreach_func_t  func,
+                                                       void                         *user_data);
++
++int ply_hashtable_get_size (ply_hashtable_t *hashtable);
+ #endif
+ #endif /* PLY_HASHTABLE_H */
+diff --git a/src/libply/ply-key-file.c b/src/libply/ply-key-file.c
+index a3d5a11..c62551e 100644
+--- a/src/libply/ply-key-file.c
++++ b/src/libply/ply-key-file.c
+@@ -25,6 +25,7 @@
+ #include "ply-key-file.h"
+ #include <assert.h>
++#include <ctype.h>
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <string.h>
+@@ -75,7 +76,7 @@ ply_key_file_open_file (ply_key_file_t *key_file)
+ {
+   assert (key_file != NULL);
+-  key_file->fp = fopen (key_file->filename, "r");
++  key_file->fp = fopen (key_file->filename, "re");
+   if (key_file->fp == NULL)
+     {
+@@ -173,13 +174,18 @@ ply_key_file_load_group (ply_key_file_t *key_file,
+       ply_key_file_entry_t *entry;
+       char *key;
+       char *value;
+-      long offset;
++      off_t offset;
+       int first_byte;
+       key = NULL;
+       value = NULL;
+-      first_byte = fgetc (key_file->fp);
++      do
++        {
++          first_byte = fgetc (key_file->fp);
++        }
++      while (isspace (first_byte));
++
+       if (first_byte == '#')
+         {
+           char *line_to_toss;
+@@ -196,13 +202,13 @@ ply_key_file_load_group (ply_key_file_t *key_file,
+         }
+       ungetc (first_byte, key_file->fp);
+-      offset = ftell (key_file->fp);
+-      items_matched = fscanf (key_file->fp, " %a[^= \t\n] = %a[^\n] ", &key, &value);
++      offset = ftello (key_file->fp);
++      items_matched = fscanf (key_file->fp, " %m[^= \t\n] = %m[^\n] ", &key, &value);
+       if (items_matched != 2)
+         {
+           if (items_matched == 1)
+-            fseek (key_file->fp, offset, SEEK_SET);
++            fseeko (key_file->fp, offset, SEEK_SET);
+           free (key);
+           free (value);
+@@ -254,7 +260,7 @@ ply_key_file_load_groups (ply_key_file_t *key_file)
+       ungetc (first_byte, key_file->fp);
+       group_name = NULL;
+-      items_matched = fscanf (key_file->fp, " [ %a[^]] ] ", &group_name);
++      items_matched = fscanf (key_file->fp, " [ %m[^]] ] ", &group_name);
+       if (items_matched <= 0)
+         {
+diff --git a/src/libply/ply-list.c b/src/libply/ply-list.c
+index 85262ab..8c589c2 100644
+--- a/src/libply/ply-list.c
++++ b/src/libply/ply-list.c
+@@ -375,85 +375,4 @@ ply_list_node_get_data (ply_list_node_t *node)
+   return node->data;
+ }
+-#ifdef PLY_LIST_ENABLE_TEST
+-#include <stdio.h>
+-
+-static int
+-compare_int_ptr (void *element_a,
+-                 void *element_b)
+-{
+-  int *int_a = element_a;
+-  int *int_b = element_b;
+-  return *int_a - *int_b;
+-
+-}
+-
+-int
+-main (int    argc,
+-      char **argv)
+-{
+-  ply_list_t *list;
+-  ply_list_node_t *node;
+-  int i, lastval;
+-  int *value;
+-  int errors;
+-
+-  errors = 0;
+-
+-  list = ply_list_new ();
+-
+-  ply_list_append_data (list, (void *) "foo");
+-  ply_list_append_data (list, (void *) "bar");
+-  ply_list_append_data (list, (void *) "baz");
+-  ply_list_prepend_data (list, (void *) "qux");
+-  ply_list_prepend_data (list, (void *) "quux");
+-  ply_list_remove_data (list, (void *) "baz");
+-  ply_list_remove_data (list, (void *) "foo");
+-
+-  node = ply_list_get_first_node (list);
+-  i = 0;
+-  while (node != NULL)
+-    {
+-      printf ("node '%d' has data '%s'\n", i,
+-              (char *) ply_list_node_get_data (node));
+-      node = ply_list_get_next_node (list, node);
+-      i++;
+-    }
+-
+-  printf ("\n");
+-  ply_list_remove_all_nodes (list);
+-  srandom(1);
+-
+-  for (i = 0; i<100; i++)
+-    {
+-      value = malloc (sizeof (int));
+-      *value = random() % 100;
+-      ply_list_append_data (list, (void *) value);
+-    }
+-
+-  ply_list_sort (list, compare_int_ptr);
+-
+-  node = ply_list_get_first_node (list);
+-  i = 0;
+-  lastval = 0;
+-
+-  while (node != NULL)
+-    {
+-      value = (int *) ply_list_node_get_data (node);
+-      if (*value < lastval)
+-        {
+-          printf ("ERROR: incorrect order\n");
+-          errors = 1;
+-        }
+-      lastval = *value;
+-      printf ("node '%d' has data '%d'\n", i, *value);
+-      node = ply_list_get_next_node (list, node);
+-      i++;
+-    }
+-
+-  ply_list_free (list);
+-  return errors;
+-}
+-
+-#endif
+ /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
+diff --git a/src/libply/ply-logger.c b/src/libply/ply-logger.c
+index f51bb84..740c30e 100644
+--- a/src/libply/ply-logger.c
++++ b/src/libply/ply-logger.c
+@@ -40,7 +40,7 @@
+ #include "ply-list.h"
+ #ifndef PLY_LOGGER_OPEN_FLAGS
+-#define PLY_LOGGER_OPEN_FLAGS (O_WRONLY | O_TRUNC | O_CREAT | O_NOFOLLOW)
++#define PLY_LOGGER_OPEN_FLAGS (O_WRONLY | O_TRUNC | O_CREAT | O_NOFOLLOW | O_CLOEXEC)
+ #endif
+ #ifndef PLY_LOGGER_MAX_INJECTION_SIZE
+@@ -357,6 +357,9 @@ ply_logger_close_file (ply_logger_t *logger)
+ {
+   assert (logger != NULL);
++  if (logger->output_fd < 0)
++      return;
++
+   close (logger->output_fd);
+   ply_logger_set_output_fd (logger, -1);
+ }
+@@ -595,26 +598,4 @@ ply_logger_is_tracing_enabled (ply_logger_t *logger)
+ }
+ #endif /* PLY_ENABLE_TRACING */
+-#ifdef PLY_LOGGER_ENABLE_TEST
+-
+-int
+-main (int    argc,
+-      char **argv)
+-{
+-  int exit_code;
+-  ply_logger_t *logger;
+-
+-  exit_code = 0;
+-  logger = ply_logger_new ();
+-
+-  ply_logger_inject (logger, "yo yo yo\n");
+-  ply_logger_set_output_fd (logger, 1);
+-  ply_logger_inject (logger, "yo yo yo yo\n");
+-  ply_logger_flush (logger);
+-  ply_logger_free (logger);
+-
+-  return exit_code;
+-}
+-
+-#endif /* PLY_LOGGER_ENABLE_TEST */
+ /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
+diff --git a/src/libply/ply-logger.h b/src/libply/ply-logger.h
+index 36fe7d1..596bed5 100644
+--- a/src/libply/ply-logger.h
++++ b/src/libply/ply-logger.h
+@@ -91,8 +91,8 @@ do                                                                             \
+         ply_logger_flush (logger);                                             \
+         errno = _old_errno;                                                    \
+         ply_logger_inject (logger,                                             \
+-                           "[%s] %45.45s:" format "\r\n",                      \
+-                           __FILE__, __func__, ##args);                        \
++                           "[%s:%d] %45.45s:" format "\r\n",                   \
++                           __FILE__, __LINE__, __func__, ##args);              \
+         ply_logger_flush (logger);                                             \
+         errno = _old_errno;                                                    \
+       }                                                                        \
+diff --git a/src/libply/ply-progress.c b/src/libply/ply-progress.c
+index 2091a27..4a16556 100644
+--- a/src/libply/ply-progress.c
++++ b/src/libply/ply-progress.c
+@@ -22,6 +22,10 @@
+  *             Charlie Brej <cbrej@cs.man.ac.uk>
+  */
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
+ #include <assert.h>
+ #include <errno.h>
+ #include <math.h>
+@@ -212,9 +216,14 @@ ply_progress_save_cache (ply_progress_t* progress,
+   ply_list_node_t *node;
+   double cur_time = ply_progress_get_time(progress);
++  ply_trace ("saving progress cache to %s", filename);
++
+   fp = fopen (filename,"w");
+   if (fp == NULL)
+-    return;
++    {
++      ply_trace ("failed to save cache: %m");
++      return;
++    }
+   node = ply_list_get_first_node (progress->current_message_list);
+@@ -326,75 +335,5 @@ ply_progress_status_update (ply_progress_t* progress,
+     }
+ }
+-#ifdef PLY_PROGRESS_ENABLE_TEST
+-
+-#include <stdio.h>
+-
+-int
+-main (int    argc,
+-      char **argv)
+-{
+-  double percent;
+-  int slowness;
+-  double time;
+-  int i;
+-  const char* strings[10]={"foobar", "barfoo", "barbar", "foo", "foo", "bar", "foo", "more", "even more", "even even more"};
+-  ply_progress_t* progress = ply_progress_new ();
+-  
+-  progress->scalar = 1.0/5;  /* Original time estimate is 5 sec*/
+-
+-  percent = ply_progress_get_percentage (progress);
+-  time = ply_progress_get_time (progress);
+-  printf("Time:%f   \t Percentage: %f%%\n", time, percent*100);
+-  srand ((int) ply_get_timestamp ());
+-  
+-  slowness = rand () % 500000 + 50000;
+-
+-  for (i=0; i<2; i++)
+-    {
+-      usleep ((rand () % slowness+slowness));
+-      percent = ply_progress_get_percentage (progress);
+-      time = ply_progress_get_time (progress);
+-      printf("Time:%f   \t Percentage: %f%%\n", time, percent*100);
+-    }
+-  printf("Load cache\n");
+-  ply_progress_load_cache (progress, PLYMOUTH_TIME_DIRECTORY "/boot-duration");
+-
+-  for (i=0; i<10; i++)
+-    {
+-      ply_progress_status_update (progress, strings[i]);
+-      usleep ((rand () % slowness+slowness));
+-      percent = ply_progress_get_percentage (progress);
+-      time = ply_progress_get_time (progress);
+-      printf("Time:%f   \t Percentage: %f%% \tScalar:%f\n", time, percent*100, progress->scalar);
+-    }
+-  printf("Save and free cache\n");
+-  ply_progress_save_cache (progress, PLYMOUTH_TIME_DIRECTORY "/boot-duration");
+-  ply_progress_free(progress);
+-
+-  printf("\nManual set percentage run\n\n");
+-
+-  progress = ply_progress_new ();
+-  progress->scalar = 1.0/5;  /* Original time estimate is 5 sec*/
+-
+-  percent = ply_progress_get_percentage (progress);
+-  time = ply_progress_get_time (progress);
+-  printf("Time:%f   \t Percentage: %f%%\n", time, percent*100);
+-  srand ((int) ply_get_timestamp ());
+-
+-  for (i=0; i<12; i++)
+-    {
+-      ply_progress_set_percentage (progress, (double)i/12);
+-      usleep ((rand () % slowness+slowness));
+-      percent = ply_progress_get_percentage (progress);
+-      time = ply_progress_get_time (progress);
+-      printf("Time:%f   \t Percentage: %f%% (%f%%)\tScalar:%f\n", time, percent*100, (double)i/12*100, progress->scalar);
+-    }
+-  ply_progress_free(progress);
+-
+-  return 0;
+-}
+-
+-#endif /* PLY_PROGRESS_ENABLE_TEST */
+ /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
+     
+diff --git a/src/libply/ply-region.c b/src/libply/ply-region.c
+index cbaca40..92d3574 100644
+--- a/src/libply/ply-region.c
++++ b/src/libply/ply-region.c
+@@ -467,141 +467,4 @@ ply_region_get_sorted_rectangle_list (ply_region_t *region)
+   return region->rectangle_list;
+ }
+-#ifdef PLY_REGION_ENABLE_TEST
+-#include <stdio.h>
+-
+-#define COVER_SIZE 100
+-#define RECTANGLE_COUNT 1000
+-
+-static void
+-cover_with_rect(char             cover[COVER_SIZE][COVER_SIZE],
+-                ply_rectangle_t *rectangle,
+-                char             value)
+-{      /* is value is not zero, the entry will be set to the value,
+-          otherwise entry is incremented*/
+-  unsigned long x, y;
+-  for (y=0; y<rectangle->height; y++)
+-    {
+-      for (x=0; x<rectangle->width; x++)
+-        {
+-          if (rectangle->x + x < COVER_SIZE &&
+-              rectangle->y + y < COVER_SIZE)
+-            {
+-              if (value)
+-                cover[rectangle->y + y][rectangle->x + x] = value;
+-              else
+-                cover[rectangle->y + y][rectangle->x + x]++;
+-            }
+-        }
+-    }
+-}
+-
+-static int
+-do_test (void)
+-{
+-  ply_rectangle_t rectangle;
+-  char cover[COVER_SIZE][COVER_SIZE];
+-  int i;
+-  unsigned long x, y;
+-  ply_region_t *region;
+-  ply_list_node_t *node;
+-
+-  region = ply_region_new ();
+-
+-  for (y = 0; y < COVER_SIZE; y++)
+-    {
+-      for (x = 0; x < COVER_SIZE; x++)
+-        {
+-          cover[y][x] = 0;
+-        }
+-    }
+-
+-  for (i = 0; i < RECTANGLE_COUNT; i++)
+-    {
+-      rectangle.x = random() % COVER_SIZE-5;
+-      rectangle.y = random() % COVER_SIZE-5;
+-      rectangle.width = 1 + random() % 20;
+-      rectangle.height = 1 + random() % 20;
+-      printf("Adding X=%ld Y=%ld W=%ld H=%ld\n",
+-              rectangle.x,
+-              rectangle.y,
+-              rectangle.width,
+-              rectangle.height);
+-      cover_with_rect(cover, &rectangle, 100); /* 100 means covered by origial squares */
+-      ply_region_add_rectangle (region, &rectangle);
+-    }
+-
+-  printf("Converted to:\n");
+-  int count = 0;
+-
+-  ply_list_t *rectangle_list = ply_region_get_rectangle_list (region);
+-  for (node = ply_list_get_first_node (rectangle_list);
+-       node;
+-       node = ply_list_get_next_node (rectangle_list, node))
+-    {
+-      ply_rectangle_t *small_rectangle = ply_list_node_get_data (node);
+-      printf("Processed X=%ld Y=%ld W=%ld H=%ld\n",
+-             small_rectangle->x,
+-             small_rectangle->y, 
+-             small_rectangle->width, 
+-             small_rectangle->height);
+-      cover_with_rect(cover, small_rectangle, 0);
+-      count++;
+-    }
+-  printf("Rectangles in:%d out:%d\n", RECTANGLE_COUNT, count);
+-
+-  count=0;
+-
+-  for (y = 0; y < COVER_SIZE; y++)
+-    {
+-      printf("%03ld ", y);
+-      for (x = 0; x < COVER_SIZE; x++)
+-        {
+-          if (cover[y][x] >= 100)
+-            {
+-              if (cover[y][x] == 100)
+-                {
+-                  printf("-");  /* "-" means should have been covered but wasn't */
+-                  count++;
+-                }
+-              else
+-                {
+-                  if (cover[y][x] == 101)
+-                    printf("O");  /* "O" means correctly covered */
+-                  else
+-                    {
+-                      printf("%d", cover[y][x] - 101);
+-                      count++;  /* 1+ means covered multiple times*/
+-                    }
+-                }
+-            }
+-          else
+-            {
+-              if (cover[y][x] == 0)
+-                printf("o");  /* "o" means not involved*/
+-              else
+-                {
+-                  printf("%c", 'A' - 1 + cover[y][x]);
+-                  count++;  /* A+ means covered despite being not involved*/
+-                }
+-            }
+-        }
+-      printf("\n");
+-    }
+-  printf("errors:%d\n", count);
+-  return count;
+-}
+-int
+-main (int    argc,
+-      char **argv)
+-{
+-  int i;
+-  srandom(312);
+-  for (i=0; i<100; i++)
+-    {
+-      if (do_test ()) return 1;
+-    }
+-  return 0;
+-}
+-#endif
+ /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
+diff --git a/src/libply/ply-terminal-session.c b/src/libply/ply-terminal-session.c
+index 3d43709..379035c 100644
+--- a/src/libply/ply-terminal-session.c
++++ b/src/libply/ply-terminal-session.c
+@@ -148,7 +148,8 @@ ply_terminal_session_free (ply_terminal_session_t *session)
+   ply_free_string_array (session->argv);
+-  close (session->pseudoterminal_master_fd);
++  if (session->pseudoterminal_master_fd >= 0)
++    close (session->pseudoterminal_master_fd);
+   free (session);
+ }
+@@ -213,8 +214,12 @@ ply_terminal_session_unredirect_console (ply_terminal_session_t *session)
+   assert (session->console_is_redirected);
+   fd = open ("/dev/console", O_RDWR | O_NOCTTY);
+-  if (fd >= 0)
++  if (fd >= 0) {
+     ioctl (fd, TIOCCONS);
++    close (fd);
++  } else {
++    ply_trace ("couldn't open /dev/console to stop redirecting it: %m");
++  }
+   session->console_is_redirected = false;
+ }
+@@ -582,57 +587,4 @@ ply_terminal_session_close_log (ply_terminal_session_t *session)
+   return ply_logger_close_file (session->logger);
+ }
+-#ifdef PLY_TERMINAL_SESSION_ENABLE_TEST
+-
+-#include <stdio.h>
+-
+-#include "ply-event-loop.h"
+-#include "ply-terminal-session.h"
+-
+-static void
+-on_finished (ply_event_loop_t *loop)
+-{
+-  ply_event_loop_exit (loop, 0);
+-}
+-
+-int
+-main (int    argc,
+-      char **argv)
+-{
+-  ply_event_loop_t *loop;
+-  ply_terminal_session_t *session;
+-  int exit_code;
+-  ply_terminal_session_flags_t flags;
+-
+-  exit_code = 0;
+-
+-  loop = ply_event_loop_new ();
+-
+-  session = ply_terminal_session_new ((const char * const *) (argv + 1));
+-
+-  flags = PLY_TERMINAL_SESSION_FLAGS_RUN_IN_PARENT;
+-  flags |= PLY_TERMINAL_SESSION_FLAGS_LOOK_IN_PATH;
+-
+-  ply_terminal_session_attach_to_event_loop (session, loop);
+-
+-  if (!ply_terminal_session_run (session, flags, 
+-                                 (ply_terminal_session_begin_handler_t) NULL,
+-                                 (ply_terminal_session_output_handler_t) NULL,
+-                                 (ply_terminal_session_hangup_handler_t) 
+-                                 on_finished, loop))
+-    {
+-      perror ("could not start terminal session");
+-      return errno;
+-    }
+-
+-  ply_terminal_session_open_log (session, "foo.log");
+-
+-  exit_code = ply_event_loop_run (loop);
+-
+-  ply_terminal_session_free (session);
+-
+-  return exit_code;
+-}
+-
+-#endif /* PLY_TERMINAL_SESSION_ENABLE_TEST */
+ /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
+diff --git a/src/libply/ply-utils.c b/src/libply/ply-utils.c
+index 60d59d1..8333485 100644
+--- a/src/libply/ply-utils.c
++++ b/src/libply/ply-utils.c
+@@ -87,27 +87,9 @@ ply_open_unidirectional_pipe (int *sender_fd,
+   assert (sender_fd != NULL);
+   assert (receiver_fd != NULL);
+-  if (pipe (pipe_fds) < 0)
++  if (pipe2 (pipe_fds, O_CLOEXEC) < 0)
+     return false;
+-  if (fcntl (pipe_fds[0], F_SETFD, O_NONBLOCK | FD_CLOEXEC) < 0)
+-    {
+-      ply_save_errno ();
+-      close (pipe_fds[0]);
+-      close (pipe_fds[1]);
+-      ply_restore_errno ();
+-      return false;
+-    }
+-
+-  if (fcntl (pipe_fds[1], F_SETFD, O_NONBLOCK | FD_CLOEXEC) < 0)
+-    {
+-      ply_save_errno ();
+-      close (pipe_fds[0]);
+-      close (pipe_fds[1]);
+-      ply_restore_errno ();
+-      return false;
+-    }
+-
+   *sender_fd = pipe_fds[1];
+   *receiver_fd = pipe_fds[0];
+@@ -120,20 +102,11 @@ ply_open_unix_socket (void)
+   int fd;
+   const int should_pass_credentials = true;
+-  fd = socket (PF_UNIX, SOCK_STREAM, 0);
++  fd = socket (PF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+   if (fd < 0)
+     return -1;
+-  if (fcntl (fd, F_SETFD, O_NONBLOCK | FD_CLOEXEC) < 0)
+-    {
+-      ply_save_errno ();
+-      close (fd);
+-      ply_restore_errno ();
+-
+-      return -1;
+-    }
+-
+   if (setsockopt (fd, SOL_SOCKET, SO_PASSCRED,
+                   &should_pass_credentials, sizeof (should_pass_credentials)) < 0)
+     {
+@@ -822,11 +795,12 @@ ply_create_daemon (void)
+       if (!ply_read (receiver_fd, &byte, sizeof (uint8_t)))
+         {
++          int read_error = errno;
+           int status;
+           if (waitpid (pid, &status, WNOHANG) <= 0)
+             {
+-              ply_error ("failed to read status from child immediately after starting to daemonize");
++              ply_error ("failed to read status from child immediately after starting to daemonize: %s", strerror (read_error));
+             }
+           else if (WIFEXITED (status))
+             {
+@@ -971,7 +945,7 @@ ply_get_process_parent_pid (pid_t pid)
+   asprintf (&path, "/proc/%ld/stat", (long) pid);
+   ppid = 0;
+-  fp = fopen (path, "r");
++  fp = fopen (path, "re");
+   if (fp == NULL)
+     {
+diff --git a/src/libply/tests/Makefile.am b/src/libply/tests/Makefile.am
+deleted file mode 100644
+index bc4da58..0000000
+--- a/src/libply/tests/Makefile.am
++++ /dev/null
+@@ -1,25 +0,0 @@
+-INCLUDES =                                                                    \
+-           -I$(top_srcdir)                                                    \
+-           -I$(srcdir)/..                                                     \
+-           -I$(srcdir)
+-TESTS = 
+-
+-if ENABLE_TESTS
+-include $(srcdir)/ply-terminal-session-test.am
+-include $(srcdir)/ply-logger-test.am
+-include $(srcdir)/ply-array-test.am
+-include $(srcdir)/ply-bitarray-test.am
+-include $(srcdir)/ply-list-test.am
+-include $(srcdir)/ply-hashtable-test.am
+-include $(srcdir)/ply-event-loop-test.am
+-include $(srcdir)/ply-command-parser-test.am
+-include $(srcdir)/ply-progress-test.am
+-include $(srcdir)/ply-region.am
+-endif
+-
+-noinst_PROGRAMS = $(TESTS)
+-
+-# Our tests aren't unit tests so clear for now
+-TESTS =
+-
+-MAINTAINERCLEANFILES = Makefile.in
+diff --git a/src/libply/tests/ply-array-test.am b/src/libply/tests/ply-array-test.am
+deleted file mode 100644
+index 4f8ecc4..0000000
+--- a/src/libply/tests/ply-array-test.am
++++ /dev/null
+@@ -1,16 +0,0 @@
+-TESTS += ply-array-test
+-
+-ply_array_test_CFLAGS = $(PLYMOUTH_CFLAGS) -DPLY_ARRAY_ENABLE_TEST
+-ply_array_test_LDADD = $(PLYMOUTH_LIBS)
+-
+-ply_array_test_SOURCES =                                                     \
+-                          $(srcdir)/../ply-buffer.h                          \
+-                          $(srcdir)/../ply-buffer.c                          \
+-                          $(srcdir)/../ply-list.h                            \
+-                          $(srcdir)/../ply-list.c                            \
+-                          $(srcdir)/../ply-logger.h                          \
+-                          $(srcdir)/../ply-logger.c                          \
+-                          $(srcdir)/../ply-utils.h                           \
+-                          $(srcdir)/../ply-utils.c                           \
+-                          $(srcdir)/../ply-array.h                           \
+-                          $(srcdir)/../ply-array.c
+diff --git a/src/libply/tests/ply-bitarray-test.am b/src/libply/tests/ply-bitarray-test.am
+deleted file mode 100644
+index 85c3608..0000000
+--- a/src/libply/tests/ply-bitarray-test.am
++++ /dev/null
+@@ -1,8 +0,0 @@
+-TESTS += ply-bitarray-test
+-
+-ply_bitarray_test_CFLAGS = $(PLYMOUTH_CFLAGS) -DPLY_BITARRAY_ENABLE_TEST
+-ply_bitarray_test_LDADD = $(PLYMOUTH_LIBS)
+-
+-ply_bitarray_test_SOURCES =                                                     \
+-                          $(srcdir)/../ply-bitarray.h                           \
+-                          $(srcdir)/../ply-bitarray.c
+diff --git a/src/libply/tests/ply-command-parser-test.am b/src/libply/tests/ply-command-parser-test.am
+deleted file mode 100644
+index 91649d5..0000000
+--- a/src/libply/tests/ply-command-parser-test.am
++++ /dev/null
+@@ -1,18 +0,0 @@
+-TESTS += ply-command-parser-test
+-
+-ply_command_parser_test_CFLAGS = $(PLYMOUTH_CFLAGS) -DPLY_COMMAND_PARSER_ENABLE_TEST
+-ply_command_parser_test_LDADD = $(PLYMOUTH_LIBS)
+-
+-ply_command_parser_test_SOURCES =                                            \
+-                          $(srcdir)/../ply-buffer.h                          \
+-                          $(srcdir)/../ply-buffer.c                          \
+-                          $(srcdir)/../ply-event-loop.h                      \
+-                          $(srcdir)/../ply-event-loop.c                      \
+-                          $(srcdir)/../ply-list.h                            \
+-                          $(srcdir)/../ply-list.c                            \
+-                          $(srcdir)/../ply-logger.h                          \
+-                          $(srcdir)/../ply-logger.c                          \
+-                          $(srcdir)/../ply-utils.h                           \
+-                          $(srcdir)/../ply-utils.c                           \
+-                          $(srcdir)/../ply-command-parser.h                  \
+-                          $(srcdir)/../ply-command-parser.c
+diff --git a/src/libply/tests/ply-event-loop-test.am b/src/libply/tests/ply-event-loop-test.am
+deleted file mode 100644
+index c666ea6..0000000
+--- a/src/libply/tests/ply-event-loop-test.am
++++ /dev/null
+@@ -1,14 +0,0 @@
+-TESTS += ply-event-loop-test
+-
+-ply_event_loop_test_CFLAGS = $(PLYMOUTH_CFLAGS) -DPLY_EVENT_LOOP_ENABLE_TEST
+-ply_event_loop_test_LDADD = $(PLYMOUTH_LIBS)
+-
+-ply_event_loop_test_SOURCES =                                               \
+-                          $(srcdir)/../ply-utils.h                          \
+-                          $(srcdir)/../ply-utils.c                          \
+-                          $(srcdir)/../ply-list.h                           \
+-                          $(srcdir)/../ply-list.c                           \
+-                          $(srcdir)/../ply-logger.h                         \
+-                          $(srcdir)/../ply-logger.c                         \
+-                          $(srcdir)/../ply-event-loop.h                     \
+-                          $(srcdir)/../ply-event-loop.c
+diff --git a/src/libply/tests/ply-hashtable-test.am b/src/libply/tests/ply-hashtable-test.am
+deleted file mode 100644
+index d3410fc..0000000
+--- a/src/libply/tests/ply-hashtable-test.am
++++ /dev/null
+@@ -1,10 +0,0 @@
+-TESTS += ply-hashtable-test
+-
+-ply_hashtable_test_CFLAGS = $(PLYMOUTH_CFLAGS) -DPLY_HASHTABLE_ENABLE_TEST
+-ply_hashtable_test_LDADD = $(PLYMOUTH_LIBS)
+-
+-ply_hashtable_test_SOURCES =                                                     \
+-                          $(srcdir)/../ply-hashtable.h                           \
+-                          $(srcdir)/../ply-hashtable.c                           \
+-                          $(srcdir)/../ply-bitarray.h                            \
+-                          $(srcdir)/../ply-bitarray.c
+diff --git a/src/libply/tests/ply-list-test.am b/src/libply/tests/ply-list-test.am
+deleted file mode 100644
+index 8beb578..0000000
+--- a/src/libply/tests/ply-list-test.am
++++ /dev/null
+@@ -1,8 +0,0 @@
+-TESTS += ply-list-test
+-
+-ply_list_test_CFLAGS = $(PLYMOUTH_CFLAGS) -DPLY_LIST_ENABLE_TEST
+-ply_list_test_LDADD = $(PLYMOUTH_LIBS)
+-
+-ply_list_test_SOURCES =                                                     \
+-                          $(srcdir)/../ply-list.h                           \
+-                          $(srcdir)/../ply-list.c
+diff --git a/src/libply/tests/ply-logger-test.am b/src/libply/tests/ply-logger-test.am
+deleted file mode 100644
+index a589fb9..0000000
+--- a/src/libply/tests/ply-logger-test.am
++++ /dev/null
+@@ -1,12 +0,0 @@
+-TESTS += ply-logger-test
+-
+-ply_logger_test_CFLAGS = $(PLYMOUTH_CFLAGS) -DPLY_LOGGER_ENABLE_TEST
+-ply_logger_test_LDADD = $(PLYMOUTH_LIBS)
+-
+-ply_logger_test_SOURCES =                                                     \
+-                          $(srcdir)/../ply-list.h                             \
+-                          $(srcdir)/../ply-list.c                             \
+-                          $(srcdir)/../ply-utils.h                            \
+-                          $(srcdir)/../ply-utils.c                            \
+-                          $(srcdir)/../ply-logger.h                           \
+-                          $(srcdir)/../ply-logger.c
+diff --git a/src/libply/tests/ply-progress-test.am b/src/libply/tests/ply-progress-test.am
+deleted file mode 100644
+index 6279fac..0000000
+--- a/src/libply/tests/ply-progress-test.am
++++ /dev/null
+@@ -1,15 +0,0 @@
+-TESTS += ply-progress-test
+-
+-ply_progress_test_CFLAGS = $(PLYMOUTH_CFLAGS) -DPLY_PROGRESS_ENABLE_TEST      \
+-           -DPLYMOUTH_TIME_DIRECTORY=\"$(localstatedir)/lib/plymouth/\"
+-ply_progress_test_LDADD = $(PLYMOUTH_LIBS)
+-
+-ply_progress_test_SOURCES =                                     \
+-                          $(srcdir)/../ply-progress.h           \
+-                          $(srcdir)/../ply-progress.c           \
+-                          $(srcdir)/../ply-list.h               \
+-                          $(srcdir)/../ply-list.c               \
+-                          $(srcdir)/../ply-logger.h             \
+-                          $(srcdir)/../ply-logger.c             \
+-                          $(srcdir)/../ply-utils.h              \
+-                          $(srcdir)/../ply-utils.c
+diff --git a/src/libply/tests/ply-region.am b/src/libply/tests/ply-region.am
+deleted file mode 100644
+index 1883833..0000000
+--- a/src/libply/tests/ply-region.am
++++ /dev/null
+@@ -1,12 +0,0 @@
+-TESTS += ply-region-test
+-
+-ply_region_test_CFLAGS = $(PLYMOUTH_CFLAGS) -DPLY_REGION_ENABLE_TEST
+-ply_region_test_LDADD = $(PLYMOUTH_LIBS)
+-
+-ply_region_test_SOURCES =                                                   \
+-                          $(srcdir)/../ply-region.h                         \
+-                          $(srcdir)/../ply-region.c                         \
+-                          $(srcdir)/../ply-rectangle.h                      \
+-                          $(srcdir)/../ply-rectangle.c                      \
+-                          $(srcdir)/../ply-list.h                           \
+-                          $(srcdir)/../ply-list.c                           
+diff --git a/src/libply/tests/ply-terminal-session-test.am b/src/libply/tests/ply-terminal-session-test.am
+deleted file mode 100644
+index decb531..0000000
+--- a/src/libply/tests/ply-terminal-session-test.am
++++ /dev/null
+@@ -1,18 +0,0 @@
+-TESTS += ply-terminal-session-test
+-
+-ply_terminal_session_test_CFLAGS = $(PLYMOUTH_CFLAGS) -DPLY_TERMINAL_SESSION_ENABLE_TEST
+-ply_terminal_session_test_LDADD = $(PLYMOUTH_LIBS)
+-
+-ply_terminal_session_test_SOURCES =                                                   \
+-                          $(srcdir)/../ply-utils.h                                    \
+-                          $(srcdir)/../ply-utils.c                                    \
+-                          $(srcdir)/../ply-buffer.h                                   \
+-                          $(srcdir)/../ply-buffer.c                                   \
+-                          $(srcdir)/../ply-logger.h                                   \
+-                          $(srcdir)/../ply-logger.c                                   \
+-                          $(srcdir)/../ply-list.h                                     \
+-                          $(srcdir)/../ply-list.c                                     \
+-                          $(srcdir)/../ply-event-loop.h                               \
+-                          $(srcdir)/../ply-event-loop.c                               \
+-                          $(srcdir)/../ply-terminal-session.h                         \
+-                          $(srcdir)/../ply-terminal-session.c
+diff --git a/src/main.c b/src/main.c
+index 88e5002..c3daac0 100644
+--- a/src/main.c
++++ b/src/main.c
+@@ -23,6 +23,7 @@
+ #include <sys/stat.h>
+ #include <sys/types.h>
++#include <math.h>
+ #include <ctype.h>
+ #include <limits.h>
+ #include <dirent.h>
+@@ -35,6 +36,7 @@
+ #include <wchar.h>
+ #include <paths.h>
+ #include <assert.h>
++#include <values.h>
+ #include <linux/kd.h>
+ #include <linux/vt.h>
+@@ -43,10 +45,12 @@
+ #include "ply-command-parser.h"
+ #include "ply-boot-server.h"
+ #include "ply-boot-splash.h"
++#include "ply-device-manager.h"
+ #include "ply-event-loop.h"
+ #include "ply-hashtable.h"
+ #include "ply-list.h"
+ #include "ply-logger.h"
++#include "ply-renderer.h"
+ #include "ply-terminal-session.h"
+ #include "ply-trigger.h"
+ #include "ply-utils.h"
+@@ -84,9 +88,6 @@ typedef struct
+ {
+   ply_event_loop_t *loop;
+   ply_boot_server_t *boot_server;
+-  ply_list_t *pixel_displays;
+-  ply_list_t *text_displays;
+-  ply_keyboard_t *keyboard;
+   ply_boot_splash_t *boot_splash;
+   ply_terminal_session_t *session;
+   ply_buffer_t *boot_buffer;
+@@ -97,12 +98,15 @@ typedef struct
+   ply_list_t *messages;
+   ply_command_parser_t *command_parser;
+   ply_mode_t mode;
+-  ply_renderer_t *renderer;
+   ply_terminal_t *local_console_terminal;
++  ply_device_manager_t *device_manager;
+   ply_trigger_t *deactivate_trigger;
+   ply_trigger_t *quit_trigger;
++  double start_time;
++  double splash_delay;
++
+   char kernel_command_line[PLY_MAX_COMMAND_LINE_SIZE];
+   uint32_t kernel_command_line_is_set : 1;
+   uint32_t no_boot_log : 1;
+@@ -113,9 +117,9 @@ typedef struct
+   uint32_t should_be_attached : 1;
+   uint32_t should_retain_splash : 1;
+   uint32_t is_inactive : 1;
++  uint32_t is_shown : 1;
+   uint32_t should_force_details : 1;
+-  char *kernel_console_tty;
+   char *override_splash_path;
+   char *system_default_splash_path;
+   char *distribution_default_splash_path;
+@@ -124,15 +128,15 @@ typedef struct
+   int number_of_errors;
+ } state_t;
+-static ply_boot_splash_t *start_boot_splash (state_t    *state,
+-                                             const char *theme_path,
+-                                             bool        fall_back_if_neccessary);
+-
+-static void add_display_and_keyboard_for_terminal (state_t        *state,
+-                                                   ply_terminal_t *terminal);
+-
+-static void add_default_displays_and_keyboard (state_t *state);
++static void show_splash (state_t *state);
++static ply_boot_splash_t *load_built_in_theme (state_t *state);
++static ply_boot_splash_t *load_theme (state_t    *state,
++                                      const char *theme_path);
++static ply_boot_splash_t *show_theme (state_t    *state,
++                                      const char *theme_path);
++static void attach_splash_to_seats (state_t           *state,
++                                    ply_boot_splash_t *splash);
+ static bool attach_to_running_session (state_t *state);
+ static void detach_from_running_session (state_t *state);
+ static void on_escape_pressed (state_t *state);
+@@ -145,12 +149,19 @@ static void on_error_message (ply_buffer_t *debug_buffer,
+ static ply_buffer_t *debug_buffer;
+ static char *debug_buffer_path = NULL;
+ static char *pid_file = NULL;
+-static void check_for_consoles (state_t    *state,
+-                                const char *default_tty,
+-                                bool        should_add_displays);
+ static void toggle_between_splash_and_details (state_t *state);
++#ifdef PLY_ENABLE_SYSTEMD_INTEGRATION
+ static void tell_systemd_to_print_details (state_t *state);
+ static void tell_systemd_to_stop_printing_details (state_t *state);
++#endif
++static const char * get_cache_file_for_mode (ply_mode_t mode);
++static void on_escape_pressed (state_t *state);
++static void on_enter (state_t    *state,
++                      const char *line);
++static void on_keyboard_input (state_t    *state,
++                               const char *keyboard_input,
++                               size_t      character_size);
++static void on_backspace (state_t *state);
+ static void
+ on_session_output (state_t    *state,
+@@ -249,21 +260,68 @@ show_messages (state_t *state)
+     }
+ }
++static bool
++load_settings (state_t     *state,
++               const char  *path,
++               char       **theme_path)
++{
++  ply_key_file_t *key_file = NULL;
++  const char *delay_string;
++  bool settings_loaded = false;
++  const char *splash_string;
++
++  ply_trace ("Trying to load %s", path);
++  key_file = ply_key_file_new (path);
++
++  if (!ply_key_file_load (key_file))
++    goto out;
++
++  splash_string = ply_key_file_get_value (key_file, "Daemon", "Theme");
++
++  if (splash_string == NULL)
++    goto out;
++
++  asprintf (theme_path,
++            PLYMOUTH_THEME_PATH "%s/%s.plymouth",
++            splash_string, splash_string);
++
++  if (isnan (state->splash_delay))
++    {
++      delay_string = ply_key_file_get_value (key_file, "Daemon", "ShowDelay");
++
++      if (delay_string != NULL)
++        {
++          state->splash_delay = atof (delay_string);
++          ply_trace ("Splash delay is set to %lf", state->splash_delay);
++        }
++    }
++
++  settings_loaded = true;
++out:
++  ply_key_file_free (key_file);
++
++  return settings_loaded;
++}
++
+ static void
+ show_detailed_splash (state_t *state)
+ {
++  ply_boot_splash_t *splash;
++
+   if (state->boot_splash != NULL)
+     return;
+   ply_trace ("Showing detailed splash screen");
+-  state->boot_splash = start_boot_splash (state,
+-                                          PLYMOUTH_THEME_PATH "details/details.plymouth",
+-                                          true);
++  splash = show_theme (state, NULL);
+-  if (state->boot_splash == NULL)
++  if (splash == NULL)
+     {
+       ply_trace ("Could not start detailed splash screen, this could be a problem.");
++      return;
+     }
++
++  state->boot_splash = splash;
++  update_display (state);
+ }
+ static const char *
+@@ -326,64 +384,46 @@ find_override_splash (state_t *state)
+                 PLYMOUTH_THEME_PATH "%*.*s/%*.*s.plymouth",
+                 length, length, splash_string, length, length, splash_string);
+     }
++
++  if (isnan (state->splash_delay))
++    {
++      const char *delay_string;
++
++      delay_string = command_line_get_string_after_prefix (state->kernel_command_line, "plymouth.splash-delay=");
++
++      if (delay_string != NULL)
++        state->splash_delay = atof (delay_string);
++    }
+ }
+ static void
+ find_system_default_splash (state_t *state)
+ {
+-  ply_key_file_t *key_file;
+-  char *splash_string;
+-
+   if (state->system_default_splash_path != NULL)
+       return;
+-  ply_trace ("Trying to load " PLYMOUTH_CONF_DIR "plymouthd.conf");
+-  key_file = ply_key_file_new (PLYMOUTH_CONF_DIR "plymouthd.conf");
+-
+-  if (!ply_key_file_load (key_file))
++  if (!load_settings (state, PLYMOUTH_CONF_DIR "plymouthd.conf", &state->system_default_splash_path))
+     {
+       ply_trace ("failed to load " PLYMOUTH_CONF_DIR "plymouthd.conf");
+-      ply_key_file_free (key_file);
+       return;
+     }
+-  splash_string = ply_key_file_get_value (key_file, "Daemon", "Theme");
+-
+-  ply_trace ("System default splash is configured to be '%s'", splash_string);
+-
+-  asprintf (&state->system_default_splash_path,
+-            PLYMOUTH_THEME_PATH "%s/%s.plymouth",
+-            splash_string, splash_string);
+-  free (splash_string);
++  ply_trace ("System configured theme file is '%s'", state->system_default_splash_path);
+ }
+ static void
+ find_distribution_default_splash (state_t *state)
+ {
+-  ply_key_file_t *key_file;
+-  char *splash_string;
+-
+   if (state->distribution_default_splash_path != NULL)
+       return;
+-  ply_trace ("Trying to load " PLYMOUTH_POLICY_DIR "plymouthd.defaults");
+-  key_file = ply_key_file_new (PLYMOUTH_POLICY_DIR "plymouthd.defaults");
+-
+-  if (!ply_key_file_load (key_file))
++  if (!load_settings (state, PLYMOUTH_POLICY_DIR "plymouthd.defaults", &state->distribution_default_splash_path))
+     {
+       ply_trace ("failed to load " PLYMOUTH_POLICY_DIR "plymouthd.defaults");
+-      ply_key_file_free (key_file);
+       return;
+     }
+-  splash_string = ply_key_file_get_value (key_file, "Daemon", "Theme");
+-
+-  ply_trace ("Distribution default splash is configured to be '%s'", splash_string);
+-
+-  asprintf (&state->distribution_default_splash_path,
+-            PLYMOUTH_THEME_PATH "%s/%s.plymouth",
+-            splash_string, splash_string);
+-  free (splash_string);
++  ply_trace ("Distribution default theme file is '%s'", state->distribution_default_splash_path);
+ }
+ static void
+@@ -393,63 +433,66 @@ show_default_splash (state_t *state)
+     return;
+   ply_trace ("Showing splash screen");
+-  find_override_splash (state);
+   if (state->override_splash_path != NULL)
+     {
+       ply_trace ("Trying override splash at '%s'", state->override_splash_path);
+-      state->boot_splash = start_boot_splash (state,
+-                                              state->override_splash_path,
+-                                              false);
++      state->boot_splash = show_theme (state, state->override_splash_path);
+     }
+-  find_system_default_splash (state);
+   if (state->boot_splash == NULL &&
+       state->system_default_splash_path != NULL)
+     {
+       ply_trace ("Trying system default splash");
+-      state->boot_splash = start_boot_splash (state,
+-                                              state->system_default_splash_path,
+-                                              false);
++      state->boot_splash = show_theme (state, state->system_default_splash_path);
+     }
+-  find_distribution_default_splash (state);
+   if (state->boot_splash == NULL &&
+       state->distribution_default_splash_path != NULL)
+     {
+       ply_trace ("Trying distribution default splash");
+-      state->boot_splash = start_boot_splash (state,
+-                                              state->distribution_default_splash_path,
+-                                              false);
++      state->boot_splash = show_theme (state, state->distribution_default_splash_path);
+     }
+   if (state->boot_splash == NULL)
+     {
+       ply_trace ("Trying old scheme for default splash");
+-      state->boot_splash = start_boot_splash (state,
+-                                              PLYMOUTH_THEME_PATH "default.plymouth",
+-                                              false);
++      state->boot_splash = show_theme (state, PLYMOUTH_THEME_PATH "default.plymouth");
+     }
+   if (state->boot_splash == NULL)
+     {
+       ply_trace ("Could not start default splash screen,"
+                  "showing text splash screen");
+-      state->boot_splash = start_boot_splash (state,
+-                                              PLYMOUTH_THEME_PATH "text/text.plymouth",
+-                                              false);
++      state->boot_splash = show_theme (state, PLYMOUTH_THEME_PATH "text/text.plymouth");
+     }
+   if (state->boot_splash == NULL)
+     {
+       ply_trace ("Could not start text splash screen,"
+-                 "showing built-in fallback");
+-      state->boot_splash = start_boot_splash (state,
+-                                              PLYMOUTH_THEME_PATH "text/text.plymouth",
+-                                              true);
++                 "showing built-in splash screen");
++      state->boot_splash = show_theme (state, NULL);
+     }
+   if (state->boot_splash == NULL)
+-    ply_error ("plymouthd: could not start boot splash: %m");
++    {
++      ply_error ("plymouthd: could not start boot splash: %m");
++      return;
++    }
++
++  update_display (state);
++}
++
++static void
++cancel_pending_delayed_show (state_t *state)
++{
++  if (isnan (state->splash_delay))
++    return;
++
++  ply_event_loop_stop_watching_for_timeout (state->loop,
++                                            (ply_event_loop_timeout_handler_t)
++                                            show_splash,
++                                            state);
++  state->splash_delay = NAN;
+ }
+ static void
+@@ -459,13 +502,36 @@ on_ask_for_password (state_t      *state,
+ {
+   ply_entry_trigger_t *entry_trigger;
+-  /* No splash, client will have to get password
+-   */
+   if (state->boot_splash == NULL)
+     {
+-      ply_trace ("no splash loaded, replying immediately with no password");
+-      ply_trigger_pull (answer, NULL);
+-      return;
++      /* Waiting to be shown, boot splash will
++       * arrive shortly so just sit tight
++       */
++      if (state->is_shown)
++        {
++          bool has_open_seats;
++
++          cancel_pending_delayed_show (state);
++
++          has_open_seats = ply_device_manager_has_open_seats (state->device_manager);
++
++          if (has_open_seats)
++            {
++              ply_trace ("seats open now, showing splash immediately");
++              show_splash (state);
++            }
++          else
++            {
++              ply_trace ("splash still coming up, waiting a bit");
++            }
++        }
++      else
++        {
++          /* No splash, client will have to get password */
++          ply_trace ("no splash loaded, replying immediately with no password");
++          ply_trigger_pull (answer, NULL);
++          return;
++        }
+     }
+   entry_trigger = calloc (1, sizeof (ply_entry_trigger_t));
+@@ -587,17 +653,11 @@ static void
+ on_newroot (state_t    *state,
+             const char *root_dir)
+ {
+-  if (state->mode != PLY_MODE_BOOT)
+-    {
+-      ply_trace ("new root is only supported in boot mode ");
+-      return;
+-    }
+-
+   ply_trace ("new root mounted at \"%s\", switching to it", root_dir);
+   chdir(root_dir);
+   chroot(".");
+   chdir("/");
+-  ply_progress_load_cache (state->progress, BOOT_DURATION_FILE);
++  ply_progress_load_cache (state->progress, get_cache_file_for_mode (state->mode));
+   if (state->boot_splash != NULL)
+     ply_boot_splash_root_mounted (state->boot_splash);
+ }
+@@ -619,7 +679,7 @@ get_cache_file_for_mode (ply_mode_t mode)
+       filename = NULL;
+       break;
+     default:
+-      fprintf (stderr, "Unhandled case in %s line %d\n", __FILE__, __LINE__);
++      ply_error ("Unhandled case in %s line %d\n", __FILE__, __LINE__);
+       abort ();
+       break;
+     }
+@@ -629,21 +689,24 @@ get_cache_file_for_mode (ply_mode_t mode)
+ }
+ static const char *
+-get_log_file_for_mode (ply_mode_t mode)
++get_log_file_for_state (state_t *state)
+ {
+   const char *filename;
+-  switch ((int)mode)
++  switch ((int)state->mode)
+     {
+     case PLY_MODE_BOOT:
+-      filename = PLYMOUTH_LOG_DIRECTORY "/boot.log";
++      if (state->no_boot_log)
++      filename = NULL;
++      else
++      filename = PLYMOUTH_LOG_DIRECTORY "/boot.log";
+       break;
+     case PLY_MODE_SHUTDOWN:
+     case PLY_MODE_UPDATES:
+       filename = _PATH_DEVNULL;
+       break;
+     default:
+-      fprintf (stderr, "Unhandled case in %s line %d\n", __FILE__, __LINE__);
++      ply_error ("Unhandled case in %s line %d\n", __FILE__, __LINE__);
+       abort ();
+       break;
+     }
+@@ -667,7 +730,7 @@ get_log_spool_file_for_mode (ply_mode_t mode)
+       filename = NULL;
+       break;
+     default:
+-      fprintf (stderr, "Unhandled case in %s line %d\n", __FILE__, __LINE__);
++      ply_error ("Unhandled case in %s line %d\n", __FILE__, __LINE__);
+       abort ();
+       break;
+     }
+@@ -684,7 +747,7 @@ spool_error (state_t *state)
+   ply_trace ("spooling error for viewer");
+-  logfile = get_log_file_for_mode (state->mode);
++  logfile = get_log_file_for_state (state);
+   logspool = get_log_spool_file_for_mode (state->mode);
+   if (logfile != NULL && logspool != NULL)
+@@ -712,11 +775,16 @@ prepare_logging (state_t *state)
+       return;
+     }
+-  logfile = get_log_file_for_mode (state->mode);
++  logfile = get_log_file_for_state (state);
+   if (logfile != NULL)
+     {
++      bool log_opened;
+       ply_trace ("opening log '%s'", logfile);
+-      ply_terminal_session_open_log (state->session, logfile);
++
++      log_opened = ply_terminal_session_open_log (state->session, logfile);
++
++      if (!log_opened)
++        ply_trace ("failed to open log: %m");
+       if (state->number_of_errors > 0)
+         spool_error (state);
+@@ -821,55 +889,15 @@ plymouth_should_show_default_splash (state_t *state)
+ }
+ static void
+-remove_displays_and_keyboard (state_t *state)
++on_show_splash (state_t *state)
+ {
+-  ply_list_node_t *node;
+-  ply_trace ("removing displays and keyboard");
+-
+-  node = ply_list_get_first_node (state->pixel_displays);
+-  while (node != NULL)
+-    {
+-      ply_list_node_t *next_node;
+-      ply_pixel_display_t *display;
+-
+-      ply_trace ("removing pixel display");
+-      next_node = ply_list_get_next_node (state->pixel_displays, node);
+-      display = ply_list_node_get_data (node);
+-      ply_pixel_display_free (display);
+-
+-      ply_list_remove_node (state->pixel_displays, node);
+-
+-      node = next_node;
+-    }
+-
+-  node = ply_list_get_first_node (state->text_displays);
+-  while (node != NULL)
+-    {
+-      ply_list_node_t *next_node;
+-      ply_text_display_t *display;
++  bool has_open_seats;
+-      ply_trace ("removing text display");
+-      next_node = ply_list_get_next_node (state->text_displays, node);
+-      display = ply_list_node_get_data (node);
+-      ply_text_display_free (display);
+-
+-      ply_list_remove_node (state->text_displays, node);
+-
+-      node = next_node;
+-    }
+-
+-  if (state->keyboard != NULL)
++  if (state->is_shown)
+     {
+-      ply_trace ("removing keyboard");
+-      ply_keyboard_free (state->keyboard);
+-      state->keyboard = NULL;
++      ply_trace ("show splash called while already shown");
++      return;
+     }
+-}
+-
+-static void
+-on_show_splash (state_t *state)
+-{
+-  bool has_display;
+   if (state->is_inactive)
+     {
+@@ -884,18 +912,81 @@ on_show_splash (state_t *state)
+       return;
+     }
+-  check_for_consoles (state, state->default_tty, true);
+-
+-  has_display = ply_list_get_length (state->pixel_displays) > 0 ||
+-                ply_list_get_length (state->text_displays) > 0;
++  state->is_shown = true;
++  has_open_seats = ply_device_manager_has_open_seats (state->device_manager);
+-  if (!state->is_attached && state->should_be_attached && has_display)
++  if (!state->is_attached && state->should_be_attached && has_open_seats)
+     attach_to_running_session (state);
+-  if (!has_display)
++  if (has_open_seats)
++    {
++      ply_trace ("at least one seat already open, so loading splash");
++      show_splash (state);
++    }
++  else
+     {
+-      ply_trace ("no open seats");
+-      detach_from_running_session (state);
++      ply_trace ("no seats available to show splash on, waiting...");
++    }
++}
++
++static void
++on_seat_removed (state_t    *state,
++                 ply_seat_t *seat)
++{
++  ply_keyboard_t *keyboard;
++
++  keyboard = ply_seat_get_keyboard (seat);
++
++  ply_trace ("no longer listening for keystrokes");
++  ply_keyboard_remove_input_handler (keyboard,
++                                     (ply_keyboard_input_handler_t)
++                                     on_keyboard_input);
++  ply_trace ("no longer listening for escape");
++  ply_keyboard_remove_escape_handler (keyboard,
++                                      (ply_keyboard_escape_handler_t)
++                                      on_escape_pressed);
++  ply_trace ("no longer listening for backspace");
++  ply_keyboard_remove_backspace_handler (keyboard,
++                                         (ply_keyboard_backspace_handler_t)
++                                         on_backspace);
++  ply_trace ("no longer listening for enter");
++  ply_keyboard_remove_enter_handler (keyboard,
++                                     (ply_keyboard_enter_handler_t)
++                                     on_enter);
++
++  if (state->boot_splash != NULL)
++   ply_boot_splash_detach_from_seat (state->boot_splash, seat);
++}
++
++static void
++show_splash (state_t *state)
++{
++  if (state->boot_splash != NULL)
++    return;
++
++  if (!isnan (state->splash_delay))
++    {
++      double now, running_time;
++
++      now = ply_get_timestamp ();
++      running_time = now - state->start_time;
++      if (state->splash_delay > running_time)
++        {
++          double time_left = state->splash_delay - running_time;
++
++          ply_trace ("delaying show splash for %lf seconds",
++                     time_left);
++          ply_event_loop_stop_watching_for_timeout (state->loop,
++                                                    (ply_event_loop_timeout_handler_t)
++                                                    show_splash,
++                                                    state);
++          ply_event_loop_watch_for_timeout (state->loop,
++                                            time_left,
++                                            (ply_event_loop_timeout_handler_t)
++                                            show_splash,
++                                            state);
++          return;
++        }
+     }
+   if (plymouth_should_show_default_splash (state))
+@@ -908,65 +999,67 @@ on_show_splash (state_t *state)
+       show_detailed_splash (state);
+       state->showing_details = true;
+     }
+-  show_messages (state);
+ }
+-static ply_list_t *
+-get_tracked_terminals (state_t *state)
++static void
++on_seat_added (state_t    *state,
++               ply_seat_t *seat)
+ {
+-  ply_list_t *terminals;
+-  ply_list_node_t *node;
+-
+-  terminals = ply_list_new ();
++  ply_keyboard_t *keyboard;
+-  node = ply_list_get_first_node (state->text_displays);
+-  while (node != NULL)
++  if (state->is_shown)
+     {
+-      ply_list_node_t *next_node;
+-      ply_text_display_t *display;
+-      ply_terminal_t *terminal;
+-
+-      next_node = ply_list_get_next_node (state->text_displays, node);
+-      display = ply_list_node_get_data (node);
+-      terminal = ply_text_display_get_terminal (display);
++      if (state->boot_splash == NULL)
++        {
++          ply_trace ("seat added before splash loaded, so loading splash now");
++          show_splash (state);
++        }
++      else
++        {
++          ply_trace ("seat added after splash loaded, so attaching to splash");
++          ply_boot_splash_attach_to_seat (state->boot_splash, seat);
++        }
++    }
+-      ply_list_append_data (terminals, terminal);
++  keyboard = ply_seat_get_keyboard (seat);
+-      node = next_node;
+-    }
++  ply_trace ("listening for keystrokes");
++  ply_keyboard_add_input_handler (keyboard,
++                                  (ply_keyboard_input_handler_t)
++                                  on_keyboard_input, state);
++  ply_trace ("listening for escape");
++  ply_keyboard_add_escape_handler (keyboard,
++                                   (ply_keyboard_escape_handler_t)
++                                   on_escape_pressed, state);
++  ply_trace ("listening for backspace");
++  ply_keyboard_add_backspace_handler (keyboard,
++                                      (ply_keyboard_backspace_handler_t)
++                                      on_backspace, state);
++  ply_trace ("listening for enter");
++  ply_keyboard_add_enter_handler (keyboard,
++                                  (ply_keyboard_enter_handler_t)
++                                  on_enter, state);
+-  return terminals;
+ }
+ static void
+-free_terminals (state_t    *state,
+-                ply_list_t *terminals)
++load_devices (state_t                    *state,
++              ply_device_manager_flags_t  flags)
+ {
+-  ply_list_node_t *node;
+-  node = ply_list_get_first_node (terminals);
+-  while (node != NULL)
+-    {
+-      ply_list_node_t *next_node;
+-      ply_terminal_t *terminal;
++  state->device_manager = ply_device_manager_new (state->default_tty, flags);
++  state->local_console_terminal = ply_device_manager_get_default_terminal (state->device_manager);
+-      next_node = ply_list_get_next_node (state->text_displays, node);
+-      terminal = ply_list_node_get_data (node);
+-
+-      ply_terminal_close (terminal);
+-      ply_terminal_free (terminal);
+-      ply_list_remove_node (terminals, node);
+-
+-      node = next_node;
+-    }
+-
+-  ply_list_free (terminals);
++  ply_device_manager_watch_seats (state->device_manager,
++                                  (ply_seat_added_handler_t)
++                                  on_seat_added,
++                                  (ply_seat_removed_handler_t)
++                                  on_seat_removed,
++                                  state);
+ }
+ static void
+ quit_splash (state_t *state)
+ {
+-  ply_list_t *terminals;
+-
+   ply_trace ("quiting splash");
+   if (state->boot_splash != NULL)
+     {
+@@ -975,17 +1068,7 @@ quit_splash (state_t *state)
+       state->boot_splash = NULL;
+     }
+-  terminals = get_tracked_terminals (state);
+-
+-  ply_trace ("removing displays and keyboard");
+-  remove_displays_and_keyboard (state);
+-
+-  if (state->renderer != NULL)
+-    {
+-      ply_renderer_close (state->renderer);
+-      ply_renderer_free (state->renderer);
+-      state->renderer = NULL;
+-    }
++  ply_device_manager_deactivate_keyboards (state->device_manager);
+   if (state->local_console_terminal != NULL)
+     {
+@@ -993,25 +1076,37 @@ quit_splash (state_t *state)
+         {
+           ply_trace ("Not retaining splash, so deallocating VT");
+           ply_terminal_deactivate_vt (state->local_console_terminal);
++          ply_terminal_close (state->local_console_terminal);
+         }
+-      state->local_console_terminal = NULL;
+     }
+-  free_terminals (state, terminals);
+   detach_from_running_session (state);
+ }
+ static void
++hide_splash (state_t *state)
++{
++  state->is_shown = false;
++
++  cancel_pending_delayed_show (state);
++
++  if (state->boot_splash == NULL)
++    return;
++
++  ply_boot_splash_hide (state->boot_splash);
++
++  if (state->local_console_terminal != NULL)
++    ply_terminal_set_mode (state->local_console_terminal, PLY_TERMINAL_MODE_TEXT);
++}
++
++static void
+ dump_details_and_quit_splash (state_t *state)
+ {
+   state->showing_details = false;
+   toggle_between_splash_and_details (state);
+-  if (state->renderer != NULL)
+-    ply_renderer_deactivate (state->renderer);
+-  if (state->boot_splash != NULL)
+-    ply_boot_splash_hide (state->boot_splash);
+-
++  ply_device_manager_deactivate_renderers (state->device_manager);
++  hide_splash (state);
+   quit_splash (state);
+ }
+@@ -1042,6 +1137,9 @@ tell_gdm_to_transition (void)
+ static void
+ quit_program (state_t *state)
+ {
++  ply_trace ("cleaning up devices");
++  ply_device_manager_free (state->device_manager);
++
+   ply_trace ("exiting event loop");
+   ply_event_loop_exit (state->loop, 0);
+@@ -1077,11 +1175,7 @@ deactivate_splash (state_t *state)
+ {
+   assert (!state->is_inactive);
+-  if (state->renderer != NULL)
+-    {
+-      ply_trace ("deactivating renderer");
+-      ply_renderer_deactivate (state->renderer);
+-    }
++  ply_device_manager_deactivate_renderers (state->device_manager);
+   detach_from_running_session (state);
+@@ -1090,7 +1184,13 @@ deactivate_splash (state_t *state)
+       ply_trace ("deactivating terminal");
+       ply_terminal_stop_watching_for_vt_changes (state->local_console_terminal);
+       ply_terminal_set_buffered_input (state->local_console_terminal);
+-      ply_terminal_ignore_mode_changes (state->local_console_terminal, true);
++      ply_terminal_close (state->local_console_terminal);
++    }
++
++  /* do not let any tty opened where we could write after deactivate */
++  if (command_line_has_argument (state->kernel_command_line, "plymouth.debug"))
++    {
++      ply_logger_close_file (ply_logger_get_error_default ());
+     }
+   state->is_inactive = true;
+@@ -1112,10 +1212,8 @@ on_boot_splash_idle (state_t *state)
+       if (!state->should_retain_splash)
+         {
+           ply_trace ("hiding splash");
+-          if (state->renderer != NULL)
+-            ply_renderer_deactivate (state->renderer);
+-          if (state->boot_splash != NULL)
+-            ply_boot_splash_hide (state->boot_splash);
++          ply_device_manager_deactivate_renderers (state->device_manager);
++          hide_splash (state);
+         }
+       ply_trace ("quitting splash");
+@@ -1130,12 +1228,17 @@ on_boot_splash_idle (state_t *state)
+     }
+ }
+-
+ static void
+ on_deactivate (state_t       *state,
+                ply_trigger_t *deactivate_trigger)
+ {
+-  if ((state->deactivate_trigger != NULL) || state->is_inactive)
++  if (state->is_inactive)
++    {
++      ply_trigger_pull (deactivate_trigger, NULL);
++      return;
++    }
++
++  if (state->deactivate_trigger != NULL)
+     {
+       ply_trigger_add_handler (state->deactivate_trigger,
+                                (ply_trigger_handler_t)
+@@ -1147,12 +1250,9 @@ on_deactivate (state_t       *state,
+   state->deactivate_trigger = deactivate_trigger;
+   ply_trace ("deactivating");
++  cancel_pending_delayed_show (state);
+-  if (state->keyboard != NULL)
+-    {
+-      ply_trace ("deactivating keyboard");
+-      ply_keyboard_stop_watching_for_input (state->keyboard);
+-    }
++  ply_device_manager_deactivate_keyboards (state->device_manager);
+   if (state->boot_splash != NULL)
+     {
+@@ -1176,6 +1276,7 @@ on_reactivate (state_t *state)
+   if (state->local_console_terminal != NULL)
+     {
++      ply_terminal_open (state->local_console_terminal);
+       ply_terminal_watch_for_vt_changes (state->local_console_terminal);
+       ply_terminal_set_unbuffered_input (state->local_console_terminal);
+       ply_terminal_ignore_mode_changes (state->local_console_terminal, false);
+@@ -1187,17 +1288,8 @@ on_reactivate (state_t *state)
+       attach_to_running_session (state);
+     }
+-  if (state->keyboard != NULL)
+-    {
+-      ply_trace ("activating keyboard");
+-      ply_keyboard_watch_for_input (state->keyboard);
+-    }
+-
+-  if (state->renderer != NULL)
+-    {
+-      ply_trace ("activating renderer");
+-      ply_renderer_activate (state->renderer);
+-    }
++  ply_device_manager_activate_keyboards (state->device_manager);
++  ply_device_manager_activate_renderers (state->device_manager);
+   state->is_inactive = false;
+@@ -1209,8 +1301,11 @@ on_quit (state_t       *state,
+          bool           retain_splash,
+          ply_trigger_t *quit_trigger)
+ {
++  ply_trace ("quitting (retain splash: %s)", retain_splash? "true" : "false");
++
+   if (state->quit_trigger != NULL)
+     {
++      ply_trace ("quit trigger already pending, so chaining to it");
+       ply_trigger_add_handler (state->quit_trigger,
+                                (ply_trigger_handler_t)
+                                ply_trigger_pull,
+@@ -1219,9 +1314,16 @@ on_quit (state_t       *state,
+     }
+   if (state->system_initialized)
+-    ply_progress_save_cache (state->progress,
+-                             get_cache_file_for_mode (state->mode));
+-
++    {
++      ply_trace ("system initialized so saving boot-duration file");
++      ply_create_directory (PLYMOUTH_TIME_DIRECTORY);
++      ply_progress_save_cache (state->progress,
++                               get_cache_file_for_mode (state->mode));
++    }
++  else
++    {
++      ply_trace ("system not initialized so skipping saving boot-duration file");
++    }
+   state->quit_trigger = quit_trigger;
+   state->should_retain_splash = retain_splash;
+@@ -1229,15 +1331,11 @@ on_quit (state_t       *state,
+   tell_systemd_to_stop_printing_details (state);
+ #endif
+-  ply_trace ("time to quit, closing log");
++  ply_trace ("closing log");
+   if (state->session != NULL)
+     ply_terminal_session_close_log (state->session);
+-  if (state->keyboard != NULL)
+-    {
+-      ply_trace ("deactivating keyboard");
+-      ply_keyboard_stop_watching_for_input (state->keyboard);
+-    }
++  ply_device_manager_deactivate_keyboards (state->device_manager);
+   ply_trace ("unloading splash");
+   if (state->is_inactive && !retain_splash)
+@@ -1351,7 +1449,7 @@ toggle_between_splash_and_details (state_t *state)
+   if (state->boot_splash != NULL)
+     {
+       ply_trace ("hiding and freeing current splash");
+-      ply_boot_splash_hide (state->boot_splash);
++      hide_splash (state);
+       ply_boot_splash_free (state->boot_splash);
+       state->boot_splash = NULL;
+     }
+@@ -1366,8 +1464,6 @@ toggle_between_splash_and_details (state_t *state)
+       show_default_splash (state);
+       state->showing_details = false;
+     }
+-  update_display (state);
+-  show_messages (state);
+ }
+ static void
+@@ -1479,140 +1575,24 @@ on_enter (state_t                  *state,
+ }
+ static void
+-set_keyboard (state_t        *state,
+-              ply_keyboard_t *keyboard)
+-{
+-  state->keyboard = keyboard;
+-
+-  ply_keyboard_add_escape_handler (keyboard, (ply_keyboard_escape_handler_t)
+-                                   on_escape_pressed, state);
+-  ply_trace ("listening for keystrokes");
+-  ply_keyboard_add_input_handler (keyboard,
+-                                  (ply_keyboard_input_handler_t)
+-                                  on_keyboard_input, state);
+-  ply_trace ("listening for backspace");
+-  ply_keyboard_add_backspace_handler (keyboard,
+-                                      (ply_keyboard_backspace_handler_t)
+-                                      on_backspace, state);
+-  ply_trace ("listening for enter");
+-  ply_keyboard_add_enter_handler (keyboard,
+-                                  (ply_keyboard_enter_handler_t)
+-                                  on_enter, state);
+-}
+-static void
+-add_display_and_keyboard_for_terminal (state_t        *state,
+-                                       ply_terminal_t *terminal)
+-{
+-  ply_text_display_t *display;
+-  ply_keyboard_t *keyboard;
+-
+-  keyboard = ply_keyboard_new_for_terminal (terminal);
+-  display = ply_text_display_new (terminal);
+-
+-  ply_list_append_data (state->text_displays, display);
+-  set_keyboard (state, keyboard);
+-}
+-
+-static void
+-add_pixel_displays_from_renderer (state_t        *state,
+-                                  ply_renderer_t *renderer)
+-{
+-  ply_list_t *heads;
+-  ply_list_node_t *node;
+-
+-  heads = ply_renderer_get_heads (renderer);
+-
+-  ply_trace ("Adding displays for %d heads",
+-             ply_list_get_length (heads));
+-
+-  node = ply_list_get_first_node (heads);
+-  while (node != NULL)
+-    {
+-      ply_list_node_t *next_node;
+-      ply_renderer_head_t *head;
+-      ply_pixel_display_t *display;
+-
+-      head = ply_list_node_get_data (node);
+-      next_node = ply_list_get_next_node (heads, node);
+-
+-      display = ply_pixel_display_new (renderer, head);
+-
+-      ply_list_append_data (state->pixel_displays, display);
+-
+-      node = next_node;
+-    }
+-
+-}
+-
+-static void
+-add_default_displays_and_keyboard (state_t *state)
++attach_splash_to_seats (state_t           *state,
++                        ply_boot_splash_t *splash)
+ {
+-  ply_renderer_t *renderer;
+-  ply_keyboard_t *keyboard;
+-  ply_text_display_t *text_display;
+-
+-  ply_trace ("adding default displays and keyboard");
+-  state->local_console_terminal = ply_terminal_new (state->default_tty);
+-
+-  renderer = ply_renderer_new (NULL, NULL, state->local_console_terminal);
+-
+-  if (!ply_renderer_open (renderer))
+-    {
+-      ply_trace ("could not open renderer /dev/fb");
+-      ply_renderer_free (renderer);
+-
+-      ply_trace ("adding text display and keyboard for %s", state->default_tty);
+-      add_display_and_keyboard_for_terminal (state, state->local_console_terminal);
+-      return;
+-    }
+-
+-  keyboard = ply_keyboard_new_for_renderer (renderer);
+-  set_keyboard (state, keyboard);
+-
+-  add_pixel_displays_from_renderer (state, renderer);
+-
+-  text_display = ply_text_display_new (state->local_console_terminal);
+-  ply_list_append_data (state->text_displays, text_display);
+-
+-  state->renderer = renderer;
+-}
+-
+-static void
+-add_displays_and_keyboard_to_boot_splash (state_t           *state,
+-                                          ply_boot_splash_t *splash)
+-{
++  ply_list_t *seats;
+   ply_list_node_t *node;
+-  ply_trace ("setting keyboard on boot splash");
+-  if (state->keyboard != NULL)
+-    ply_boot_splash_set_keyboard (splash, state->keyboard);
+-
+-  node = ply_list_get_first_node (state->pixel_displays);
++  seats = ply_device_manager_get_seats (state->device_manager);
++  node = ply_list_get_first_node (seats);
+   while (node != NULL)
+     {
+-      ply_pixel_display_t *display;
++      ply_seat_t *seat;
+       ply_list_node_t *next_node;
+-      display = ply_list_node_get_data (node);
+-      next_node = ply_list_get_next_node (state->pixel_displays, node);
+-      ply_trace ("adding pixel display on boot splash");
+-      ply_boot_splash_add_pixel_display (splash, display);
++      seat = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (seats, node);
+-      node = next_node;
+-    }
+-
+-  node = ply_list_get_first_node (state->text_displays);
+-  while (node != NULL)
+-    {
+-      ply_text_display_t *display;
+-      ply_list_node_t *next_node;
+-
+-      display = ply_list_node_get_data (node);
+-      next_node = ply_list_get_next_node (state->text_displays, node);
+-
+-      ply_trace ("adding text display on boot splash");
+-      ply_boot_splash_add_text_display (splash, display);
++      ply_boot_splash_attach_to_seat (splash, seat);
+       node = next_node;
+     }
+@@ -1637,12 +1617,41 @@ tell_systemd_to_stop_printing_details (state_t *state)
+ #endif
+ static ply_boot_splash_t *
+-start_boot_splash (state_t    *state,
+-                   const char *theme_path,
+-                   bool        fall_back_if_neccessary)
++load_built_in_theme (state_t *state)
++{
++  ply_boot_splash_t *splash;
++  bool is_loaded;
++
++  ply_trace ("Loading built-in theme");
++
++  splash = ply_boot_splash_new ("",
++                                PLYMOUTH_PLUGIN_PATH,
++                                state->boot_buffer);
++
++  is_loaded = ply_boot_splash_load_built_in (splash);
++
++  if (!is_loaded)
++    {
++      ply_save_errno ();
++      ply_boot_splash_free (splash);
++      ply_restore_errno ();
++      return NULL;
++    }
++
++  ply_trace ("attaching plugin to event loop");
++  ply_boot_splash_attach_to_event_loop (splash, state->loop);
++
++  ply_trace ("attaching progress to plugin");
++  ply_boot_splash_attach_progress (splash, state->progress);
++
++  return splash;
++}
++
++static ply_boot_splash_t *
++load_theme (state_t    *state,
++            const char *theme_path)
+ {
+   ply_boot_splash_t *splash;
+-  ply_boot_splash_mode_t splash_mode;
+   bool is_loaded;
+   ply_trace ("Loading boot splash theme '%s'",
+@@ -1653,13 +1662,6 @@ start_boot_splash (state_t    *state,
+                                 state->boot_buffer);
+   is_loaded = ply_boot_splash_load (splash);
+-  if (!is_loaded && fall_back_if_neccessary)
+-    {
+-      ply_trace ("Splash couldn't be loaded: %m");
+-
+-      ply_trace ("Loading built in splash");
+-      is_loaded = ply_boot_splash_load_built_in (splash);
+-    }
+   if (!is_loaded)
+     {
+@@ -1675,9 +1677,27 @@ start_boot_splash (state_t    *state,
+   ply_trace ("attaching progress to plugin");
+   ply_boot_splash_attach_progress (splash, state->progress);
+-  add_displays_and_keyboard_to_boot_splash (state, splash);
++  return splash;
++}
++
++static ply_boot_splash_t *
++show_theme (state_t           *state,
++            const char        *theme_path)
++{
++  ply_boot_splash_mode_t splash_mode;
++  ply_boot_splash_t *splash;
++
++  if (theme_path != NULL)
++    splash = load_theme (state, theme_path);
++  else
++    splash = load_built_in_theme (state);
++
++  if (splash == NULL)
++    return NULL;
++
++  attach_splash_to_seats (state, splash);
++  ply_device_manager_activate_renderers (state->device_manager);
+-  ply_trace ("showing plugin");
+   if (state->mode == PLY_MODE_SHUTDOWN)
+     splash_mode = PLY_BOOT_SPLASH_MODE_SHUTDOWN;
+   else
+@@ -1686,7 +1706,6 @@ start_boot_splash (state_t    *state,
+   if (!ply_boot_splash_show (splash, splash_mode))
+     {
+       ply_save_errno ();
+-      ply_boot_splash_unset_keyboard (splash);
+       ply_boot_splash_free (splash);
+       ply_restore_errno ();
+       return NULL;
+@@ -1697,10 +1716,9 @@ start_boot_splash (state_t    *state,
+     tell_systemd_to_print_details (state);
+ #endif
+-  if (state->keyboard != NULL)
+-    ply_keyboard_watch_for_input (state->keyboard);
++  ply_device_manager_activate_keyboards (state->device_manager);
++  show_messages (state);
+-  update_display (state);
+   return splash;
+ }
+@@ -1875,6 +1893,30 @@ check_verbosity (state_t *state)
+               ply_logger_set_output_fd (ply_logger_get_error_default (), fd);
+             }
+           free (stream_copy);
++        } else {
++            const char* device;
++            char *file;
++
++            device = state->default_tty;
++
++            ply_trace ("redirecting debug output to %s", device);
++
++            if (strncmp (device, "/dev/", strlen ("/dev/")) == 0)
++                file = strdup (device);
++              else
++                asprintf (&file, "/dev/%s", device);
++
++            fd = open (file, O_RDWR | O_APPEND);
++
++            if (fd < 0)
++              {
++                 ply_trace ("could not redirected debug output to %s: %m", device);
++              }
++            else {
++                ply_logger_set_output_fd (ply_logger_get_error_default (), fd);
++            }
++
++            free (file);
+         }
+     }
+   else
+@@ -1896,267 +1938,26 @@ check_verbosity (state_t *state)
+ static void
+ check_logging (state_t *state)
+ {
+-  ply_trace ("checking if console messages should be redirected and logged");
+-
+-  if (command_line_has_argument (state->kernel_command_line, "plymouth.nolog"))
+-    {
+-      ply_trace ("logging won't be enabled!");
+-      state->no_boot_log = true;
+-    }
+-  else
+-    {
+-      ply_trace ("logging will be enabled!");
+-      state->no_boot_log = false;
+-    }
+-}
+-
+-static void
+-add_display_and_keyboard_for_console (const char *console,
+-                                      const char *null,
+-                                      state_t    *state)
+-{
+-  ply_terminal_t *terminal;
+-
+-  terminal = ply_terminal_new (console);
+-
+-  if (strcmp (console, state->default_tty) == 0)
+-    state->local_console_terminal = terminal;
++  bool kernel_no_log;
+-  ply_trace ("adding display and keyboard for console %s", console);
+-  add_display_and_keyboard_for_terminal (state, terminal);
+-}
+-
+-static int
+-add_consoles_from_file (state_t         *state,
+-                        ply_hashtable_t *consoles,
+-                        const char      *path)
+-{
+-  int fd;
+-  char contents[512] = "";
+-  ssize_t contents_length;
+-  int num_consoles;
+-  const char *remaining_file_contents;
+-
+-  ply_trace ("opening %s", path);
+-  fd = open (path, O_RDONLY);
+-
+-  if (fd < 0)
+-    {
+-      ply_trace ("couldn't open it: %m");
+-      return 0;
+-    }
+-
+-  ply_trace ("reading file");
+-  contents_length = read (fd, contents, sizeof (contents));
+-
+-  if (contents_length <= 0)
+-    {
+-      ply_trace ("couldn't read it: %m");
+-      close (fd);
+-      return 0;
+-    }
+-  close (fd);
+-
+-  remaining_file_contents = contents;
+-  num_consoles = 0;
+-
+-  while (remaining_file_contents < contents + contents_length)
+-    {
+-      char *console;
+-      size_t console_length;
+-      char *console_device;
+-
+-      /* Advance past any leading whitespace */
+-      remaining_file_contents += strspn (remaining_file_contents, " \n\t\v");
+-
+-      if (*remaining_file_contents == '\0')
+-        {
+-          /* There's nothing left after the whitespace, we're done */
+-          break;
+-        }
+-
+-      /* Find trailing whitespace and NUL terminate.  If strcspn
+-       * doesn't find whitespace, it gives us the length of the string
+-       * until the next NUL byte, which we'll just overwrite with
+-       * another NUL byte anyway. */
+-      console_length = strcspn (remaining_file_contents, " \n\t\v");
+-      console = strndup (remaining_file_contents, console_length);
+-
+-      /* If this console is anything besides tty0, then the user is sort
+-       * of a weird case (uses a serial console or whatever) and they
+-       * most likely don't want a graphical splash, so force details.
+-       */
+-      if (strcmp (console, "tty0") != 0)
+-        state->should_force_details = true;
+-
+-      asprintf (&console_device, "/dev/%s", console);
+-
+-      free (console);
+-
+-      ply_trace ("console %s found!", console_device);
+-      ply_hashtable_insert (consoles, console_device, console_device);
+-      num_consoles++;
+-
+-      /* Move past the parsed console string, and the whitespace we
+-       * may have found above.  If we found a NUL above and not whitespace,
+-       * then we're going to jump past the end of the buffer and the loop
+-       * will terminate
+-       */
+-      remaining_file_contents += console_length + 1;
+-    }
+-
+-  return num_consoles;
+-}
+-
+-static int
+-add_consoles_from_kernel_command_line (state_t         *state,
+-                                       ply_hashtable_t *consoles)
+-{
+-  const char *console_string;
+-  const char *remaining_command_line;
+-  char *console;
+-  int num_consoles;
+-
+-  remaining_command_line = state->kernel_command_line;
+-
+-  num_consoles = 0;
+-  console = NULL;
+-  while ((console_string = command_line_get_string_after_prefix (remaining_command_line,
+-                                                                 "console=")) != NULL)
+-    {
+-      char *end;
+-      size_t console_length;
+-      char *console_device;
+-
+-      remaining_command_line = console_string;
+-
+-      state->should_force_details = true;
+-
+-      console = strdup (console_string);
+-
+-      end = strpbrk (console, " \n\t\v,");
+-
+-      if (end != NULL)
+-        *end = '\0';
+-
+-      console_length = strlen (console);
+-
+-      if (strncmp (console, "/dev/", strlen ("/dev/")) == 0)
+-        {
+-          console_device = console;
+-          console = NULL;
+-        }
+-      else
+-        {
+-          asprintf (&console_device, "/dev/%s", console);
+-          free (console);
+-          console = NULL;
+-        }
+-
+-      ply_trace ("console %s found!", console_device);
+-      ply_hashtable_insert (consoles, console_device, console_device);
+-      num_consoles++;
+-      remaining_command_line += console_length;
+-    }
+-
+-  return num_consoles;
+-}
+-
+-static void
+-check_for_consoles (state_t    *state,
+-                    const char *default_tty,
+-                    bool        should_add_displays)
+-{
+-  char *console;
+-  ply_hashtable_t *consoles;
+-  int num_consoles;
+-  bool ignore_serial_consoles;
+-
+-  ply_trace ("checking for consoles%s",
+-             should_add_displays? " and adding displays": "");
+-
+-  consoles = ply_hashtable_new (ply_hashtable_string_hash,
+-                                ply_hashtable_string_compare);
+-  ignore_serial_consoles = command_line_has_argument (state->kernel_command_line, "plymouth.ignore-serial-consoles");
+-
+-  num_consoles = 0;
++  ply_trace ("checking if console messages should be redirected and logged");
+-  if (!ignore_serial_consoles)
+-    {
+-      num_consoles = add_consoles_from_file (state, consoles, "/sys/class/tty/console/active");
++  kernel_no_log = command_line_has_argument (state->kernel_command_line, "plymouth.nolog");
++  if (kernel_no_log)
++    state->no_boot_log = true;
+-      if (num_consoles == 0)
+-        {
+-          ply_trace ("falling back to kernel command line");
+-          num_consoles = add_consoles_from_kernel_command_line (state, consoles);
+-        }
+-    }
++  if (state->no_boot_log)
++    ply_trace ("logging won't be enabled!");
+   else
+-    {
+-      ply_trace ("ignoring all consoles but default console because of plymouth.ignore-serial-consoles");
+-    }
+-
+-  console = ply_hashtable_remove (consoles, (void *) "/dev/tty0");
+-  if (console != NULL)
+-    {
+-      free (console);
+-      console = strdup (default_tty);
+-      ply_hashtable_insert (consoles, console, console);
+-    }
+-
+-  console = ply_hashtable_remove (consoles, (void *) "/dev/tty");
+-  if (console != NULL)
+-    {
+-      free (console);
+-      console = strdup (default_tty);
+-      ply_hashtable_insert (consoles, console, console);
+-    }
+-
+-  free (state->kernel_console_tty);
+-  state->kernel_console_tty = NULL;
+-
+-  if (console != NULL)
+-    state->kernel_console_tty = strdup (console);
+-
+-  if (should_add_displays)
+-    {
+-      /* Do a full graphical splash if there's no weird serial console
+-       * stuff going on, otherwise just prepare text splashes
+-       */
+-      if ((num_consoles == 0) ||
+-          ((num_consoles == 1) &&
+-           (ply_hashtable_lookup (consoles, (void *) default_tty) != NULL)))
+-        add_default_displays_and_keyboard (state);
+-      else
+-        ply_hashtable_foreach (consoles,
+-                               (ply_hashtable_foreach_func_t *)
+-                               add_display_and_keyboard_for_console,
+-                               state);
+-    }
+-
+-  ply_hashtable_foreach (consoles, (ply_hashtable_foreach_func_t *) free, NULL);
+-  ply_hashtable_free (consoles);
+-
+-  ply_trace ("After processing serial consoles there are now %d text displays",
+-             ply_list_get_length (state->text_displays));
++    ply_trace ("logging will be enabled!");
+ }
+ static bool
+-redirect_standard_io_to_device (const char *device)
++redirect_standard_io_to_dev_null (void)
+ {
+   int fd;
+-  char *file;
+-
+-  ply_trace ("redirecting stdio to %s", device);
+-
+-  if (strncmp (device, "/dev/", strlen ("/dev/")) == 0)
+-    file = strdup (device);
+-  else
+-    asprintf (&file, "/dev/%s", device);
+-  fd = open (file, O_RDWR | O_APPEND);
+-
+-  free (file);
++  fd = open ("/dev/null", O_RDWR | O_APPEND);
+   if (fd < 0)
+     return false;
+@@ -2199,19 +2000,11 @@ initialize_environment (state_t *state)
+   if (!get_kernel_command_line (state))
+     return false;
+-  check_verbosity (state);
+-  check_logging (state);
+-
+-  ply_trace ("source built on %s", __DATE__);
+-
+-  state->keystroke_triggers = ply_list_new ();
+-  state->entry_triggers = ply_list_new ();
+-  state->entry_buffer = ply_buffer_new();
+-  state->pixel_displays = ply_list_new ();
+-  state->text_displays = ply_list_new ();
+-  state->messages = ply_list_new ();
+-  state->keyboard = NULL;
+-
++  if (!state->default_tty)
++    {
++      if (getenv ("DISPLAY") != NULL && access (PLYMOUTH_PLUGIN_PATH "renderers/x11.so", F_OK) == 0)
++          state->default_tty = "/dev/tty";
++    }
+   if (!state->default_tty)
+     {
+       if (state->mode == PLY_MODE_SHUTDOWN)
+@@ -2232,12 +2025,17 @@ initialize_environment (state_t *state)
+         }
+     }
+-  check_for_consoles (state, state->default_tty, false);
++  check_verbosity (state);
++  check_logging (state);
+-  if (state->kernel_console_tty != NULL)
+-    redirect_standard_io_to_device (state->kernel_console_tty);
+-  else
+-    redirect_standard_io_to_device (state->default_tty);
++  ply_trace ("source built on %s", __DATE__);
++
++  state->keystroke_triggers = ply_list_new ();
++  state->entry_triggers = ply_list_new ();
++  state->entry_buffer = ply_buffer_new();
++  state->messages = ply_list_new ();
++
++  redirect_standard_io_to_dev_null ();
+   ply_trace ("Making sure " PLYMOUTH_RUNTIME_DIR " exists");
+   if (!ply_create_directory (PLYMOUTH_RUNTIME_DIR))
+@@ -2338,6 +2136,7 @@ main (int    argc,
+   state_t state = { 0 };
+   int exit_code;
+   bool should_help = false;
++  bool no_boot_log = false;
+   bool no_daemon = false;
+   bool debug = false;
+   bool attach_to_session;
+@@ -2345,7 +2144,9 @@ main (int    argc,
+   char *mode_string = NULL;
+   char *kernel_command_line = NULL;
+   char *tty = NULL;
++  ply_device_manager_flags_t device_manager_flags = PLY_DEVICE_MANAGER_FLAGS_NONE;
++  state.start_time = ply_get_timestamp ();
+   state.command_parser = ply_command_parser_new ("plymouthd", "Splash server");
+   state.loop = ply_event_loop_get_default ();
+@@ -2360,6 +2161,7 @@ main (int    argc,
+                                   "pid-file", "Write the pid of the daemon to a file", PLY_COMMAND_OPTION_TYPE_STRING,
+                                   "kernel-command-line", "Fake kernel command line to use", PLY_COMMAND_OPTION_TYPE_STRING,
+                                   "tty", "TTY to use instead of default", PLY_COMMAND_OPTION_TYPE_STRING,
++                                  "no-boot-log", "Do not write boot log file", PLY_COMMAND_OPTION_TYPE_FLAG,
+                                   NULL);
+   if (!ply_command_parser_parse_arguments (state.command_parser, state.loop, argv, argc))
+@@ -2378,6 +2180,7 @@ main (int    argc,
+                                   "help", &should_help,
+                                   "attach-to-session", &attach_to_session,
+                                   "mode", &mode_string,
++                                  "no-boot-log", &no_boot_log,
+                                   "no-daemon", &no_daemon,
+                                   "debug", &debug,
+                                   "debug-file", &debug_buffer_path,
+@@ -2434,6 +2237,8 @@ main (int    argc,
+       return EX_OSERR;
+     }
++  state.no_boot_log = no_boot_log;
++
+   chdir ("/");
+   signal (SIGPIPE, SIG_IGN);
+@@ -2505,6 +2310,7 @@ main (int    argc,
+     }
+   state.progress = ply_progress_new ();
++  state.splash_delay = NAN;
+   ply_progress_load_cache (state.progress,
+                            get_cache_file_for_mode (state.mode));
+@@ -2519,6 +2325,28 @@ main (int    argc,
+       return EX_UNAVAILABLE;
+     }
++  find_override_splash (&state);
++  find_system_default_splash (&state);
++  find_distribution_default_splash (&state);
++
++  if (command_line_has_argument (state.kernel_command_line, "plymouth.ignore-serial-consoles"))
++    device_manager_flags |= PLY_DEVICE_MANAGER_FLAGS_IGNORE_SERIAL_CONSOLES;
++
++  if (command_line_has_argument (state.kernel_command_line, "plymouth.ignore-udev") ||
++      (getenv ("DISPLAY") != NULL))
++    device_manager_flags |= PLY_DEVICE_MANAGER_FLAGS_IGNORE_UDEV;
++
++  if (!plymouth_should_show_default_splash (&state))
++    {
++      /* don't bother listening for udev events if we're forcing details */
++      device_manager_flags |= PLY_DEVICE_MANAGER_FLAGS_IGNORE_UDEV;
++
++      /* don't ever delay showing the detailed splash */
++      state.splash_delay = NAN;
++    }
++
++  load_devices (&state, device_manager_flags);
++
+   ply_trace ("entering event loop");
+   exit_code = ply_event_loop_run (state.loop);
+   ply_trace ("exited event loop");
+diff --git a/src/plugins/controls/label/Makefile.am b/src/plugins/controls/label/Makefile.am
+index 296203b..219930a 100644
+--- a/src/plugins/controls/label/Makefile.am
++++ b/src/plugins/controls/label/Makefile.am
+@@ -1,4 +1,4 @@
+-INCLUDES = -I$(top_srcdir)                                                    \
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
+            -I$(srcdir)/../../../libply                                        \
+            -I$(srcdir)/../../../libply-splash-core                            \
+            -I$(srcdir)/../../../libply-splash-graphics                        \
+diff --git a/src/plugins/renderers/drm/Makefile.am b/src/plugins/renderers/drm/Makefile.am
+index 2209b30..747f202 100644
+--- a/src/plugins/renderers/drm/Makefile.am
++++ b/src/plugins/renderers/drm/Makefile.am
+@@ -1,5 +1,5 @@
+ if ENABLE_DRM_RENDERER
+-INCLUDES = -I$(top_srcdir)                                                    \
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
+            -I$(srcdir)/../../../libply                                        \
+            -I$(srcdir)/../../../libply-splash-core                            \
+            -I$(srcdir)/../../..                                               \
+@@ -21,27 +21,7 @@ drm_la_SOURCES = $(srcdir)/plugin.c                                           \
+ drm_la_SOURCES += $(srcdir)/ply-renderer-generic-driver.h                     \
+                   $(srcdir)/ply-renderer-generic-driver.c
+-if ENABLE_LIBDRM_INTEL
+-drm_la_SOURCES += $(srcdir)/ply-renderer-i915-driver.h                        \
+-                  $(srcdir)/ply-renderer-i915-driver.c
+-endif
+-
+-if ENABLE_LIBDRM_RADEON
+-drm_la_SOURCES += $(srcdir)/ply-renderer-radeon-driver.h                      \
+-                  $(srcdir)/ply-renderer-radeon-driver.c
+-endif
+-if ENABLE_LIBDRM_NOUVEAU
+-drm_la_SOURCES += $(srcdir)/ply-renderer-nouveau-driver.h                     \
+-                  $(srcdir)/ply-renderer-nouveau-driver.c
+-endif
+-
+-if ENABLE_LIBKMS
+-drm_la_LIBADD += $(LIBKMS_LIBS)
+-drm_la_CFLAGS += $(LIBKMS_CFLAGS)
+-drm_la_SOURCES += $(srcdir)/ply-renderer-libkms-driver.h                      \
+-                  $(srcdir)/ply-renderer-libkms-driver.c
+-endif
+ endif
+diff --git a/src/plugins/renderers/drm/plugin.c b/src/plugins/renderers/drm/plugin.c
+index db953e6..6677279 100644
+--- a/src/plugins/renderers/drm/plugin.c
++++ b/src/plugins/renderers/drm/plugin.c
+@@ -60,19 +60,6 @@
+ #include "ply-renderer-plugin.h"
+ #include "ply-renderer-driver.h"
+ #include "ply-renderer-generic-driver.h"
+-#ifdef PLY_ENABLE_LIBDRM_INTEL
+-#include "ply-renderer-i915-driver.h"
+-#endif
+-#ifdef PLY_ENABLE_LIBDRM_RADEON
+-#include "ply-renderer-radeon-driver.h"
+-#endif
+-#ifdef PLY_ENABLE_LIBDRM_NOUVEAU
+-#include "ply-renderer-nouveau-driver.h"
+-#endif
+-
+-#ifdef PLY_ENABLE_LIBKMS
+-#include "ply-renderer-libkms-driver.h"
+-#endif
+ #define BYTES_PER_PIXEL (4)
+@@ -412,42 +399,6 @@ destroy_backend (ply_renderer_backend_t *backend)
+   free (backend);
+ }
+-static char *
+-find_driver_for_device (const char *device_name)
+-{
+-  char *driver;
+-  int major_number, minor_number;
+-  struct stat file_attributes;
+-  char *device_path;
+-  char device_link_path[PATH_MAX + 1] = "";
+-
+-  if (stat (device_name, &file_attributes) < 0)
+-    return NULL;
+-
+-  if (!S_ISCHR (file_attributes.st_mode))
+-    return NULL;
+-
+-  major_number = major (file_attributes.st_rdev);
+-  minor_number = minor (file_attributes.st_rdev);
+-
+-  asprintf (&device_path, "/sys/dev/char/%d:%d/device/driver",
+-            major_number, minor_number);
+-
+-  if (readlink (device_path, device_link_path, sizeof (device_link_path) - 1) < 0)
+-    {
+-      free (device_path);
+-      return NULL;
+-    }
+-  free (device_path);
+-
+-  driver = strrchr (device_link_path, '/');
+-
+-  if (driver == NULL)
+-    return NULL;
+-
+-  return strdup (driver + strlen ("/"));
+-}
+-
+ static void
+ activate (ply_renderer_backend_t *backend)
+ {
+@@ -508,72 +459,24 @@ on_active_vt_changed (ply_renderer_backend_t *backend)
+ static bool
+ load_driver (ply_renderer_backend_t *backend)
+ {
+-  char *driver_name;
+   int device_fd;
+-  driver_name = find_driver_for_device (backend->device_name);
+-  ply_trace ("Attempting to load driver '%s'", driver_name);
+-  device_fd = drmOpen (driver_name, NULL);
++  ply_trace ("Opening '%s'", backend->device_name);
++  device_fd = open (backend->device_name, O_RDWR);
+   if (device_fd < 0)
+     {
+-      ply_trace ("drmOpen failed");
+-      free (driver_name);
++      ply_trace ("open failed: %m");
+       return false;
+     }
+-  backend->driver_interface = NULL;
+-/* Try intel driver first if we're supporting the legacy GDM transition
+- * since it can map the kernel console, which gives us the ability to do
+- * a more seamless transition when plymouth quits before X starts
+- */
+-#if defined(PLY_ENABLE_DEPRECATED_GDM_TRANSITION) && defined(PLY_ENABLE_LIBDRM_INTEL)
+-  if (backend->driver_interface == NULL && strcmp (driver_name, "i915") == 0)
+-    {
+-      backend->driver_interface = ply_renderer_i915_driver_get_interface ();
+-      backend->driver_supports_mapping_console = true;
+-    }
+-#endif
++  backend->driver_interface = ply_renderer_generic_driver_get_interface (device_fd);
++  backend->driver_supports_mapping_console = false;
+   if (backend->driver_interface == NULL)
+     {
+-      backend->driver_interface = ply_renderer_generic_driver_get_interface (device_fd);
+-      backend->driver_supports_mapping_console = false;
+-    }
+-
+-#ifdef PLY_ENABLE_LIBDRM_INTEL
+-  if (backend->driver_interface == NULL && strcmp (driver_name, "i915") == 0)
+-    {
+-      backend->driver_interface = ply_renderer_i915_driver_get_interface ();
+-      backend->driver_supports_mapping_console = true;
+-    }
+-#endif
+-#ifdef PLY_ENABLE_LIBDRM_RADEON
+-  if (backend->driver_interface == NULL && strcmp (driver_name, "radeon") == 0)
+-    {
+-      backend->driver_interface = ply_renderer_radeon_driver_get_interface ();
+-      backend->driver_supports_mapping_console = false;
+-    }
+-#endif
+-#ifdef PLY_ENABLE_LIBDRM_NOUVEAU
+-  if (backend->driver_interface == NULL && strcmp (driver_name, "nouveau") == 0)
+-    {
+-      backend->driver_interface = ply_renderer_nouveau_driver_get_interface ();
+-      backend->driver_supports_mapping_console = false;
+-    }
+-#endif
+-
+-  free (driver_name);
+-
+-  if (backend->driver_interface == NULL)
+-    {
+-#ifdef PLY_ENABLE_LIBKMS
+-      backend->driver_interface = ply_renderer_libkms_driver_get_interface ();
+-      backend->driver_supports_mapping_console = false;
+-#else
+       close (device_fd);
+       return false;
+-#endif
+     }
+   backend->driver = backend->driver_interface->create_driver (device_fd);
+@@ -619,6 +522,9 @@ open_device (ply_renderer_backend_t *backend)
+   if (!load_driver (backend))
+     return false;
++  if (backend->terminal == NULL)
++    return true;
++
+   if (!ply_terminal_open (backend->terminal))
+     {
+       ply_trace ("could not open terminal: %m");
+@@ -647,10 +553,11 @@ close_device (ply_renderer_backend_t *backend)
+   free_heads (backend);
+-  ply_terminal_stop_watching_for_active_vt_change (backend->terminal,
+-                                                   (ply_terminal_active_vt_changed_handler_t)
+-                                                   on_active_vt_changed,
+-                                                   backend);
++  if (backend->terminal != NULL)
++    ply_terminal_stop_watching_for_active_vt_change (backend->terminal,
++                                                     (ply_terminal_active_vt_changed_handler_t)
++                                                     on_active_vt_changed,
++                                                     backend);
+   unload_driver (backend);
+ }
+@@ -985,10 +892,17 @@ map_to_device (ply_renderer_backend_t *backend)
+       node = next_node;
+     }
+-  if (ply_terminal_is_active (backend->terminal))
+-    activate (backend);
++  if (backend->terminal != NULL)
++    {
++      if (ply_terminal_is_active (backend->terminal))
++        activate (backend);
++      else
++        ply_terminal_activate_vt (backend->terminal);
++    }
+   else
+-    ply_terminal_activate_vt (backend->terminal);
++    {
++      activate (backend);
++    }
+   return head_mapped;
+ }
+@@ -1116,8 +1030,11 @@ reset_scan_out_buffer_if_needed (ply_renderer_backend_t *backend,
+   drmModeCrtc *controller;
+   bool did_reset = false;
+-  if (!ply_terminal_is_active (backend->terminal))
+-    return false;
++  if (backend->terminal != NULL)
++    {
++      if (!ply_terminal_is_active (backend->terminal))
++        return false;
++    }
+   controller = drmModeGetCrtc (backend->device_fd, head->controller_id);
+@@ -1151,8 +1068,11 @@ flush_head (ply_renderer_backend_t *backend,
+   if (!backend->is_active)
+     return;
+-  ply_terminal_set_mode (backend->terminal, PLY_TERMINAL_MODE_GRAPHICS);
+-  ply_terminal_set_unbuffered_input (backend->terminal);
++  if (backend->terminal != NULL)
++    {
++      ply_terminal_set_mode (backend->terminal, PLY_TERMINAL_MODE_GRAPHICS);
++      ply_terminal_set_unbuffered_input (backend->terminal);
++    }
+   pixel_buffer = head->pixel_buffer;
+   updated_region = ply_pixel_buffer_get_updated_areas (pixel_buffer);
+   areas_to_flush = ply_region_get_sorted_rectangle_list (updated_region);
+@@ -1260,6 +1180,9 @@ open_input_source (ply_renderer_backend_t      *backend,
+   assert (backend != NULL);
+   assert (has_input_source (backend, input_source));
++  if (backend->terminal == NULL)
++    return false;
++
+   terminal_fd = ply_terminal_get_fd (backend->terminal);
+   input_source->backend = backend;
+@@ -1290,6 +1213,9 @@ close_input_source (ply_renderer_backend_t      *backend,
+   assert (backend != NULL);
+   assert (has_input_source (backend, input_source));
++  if (backend->terminal == NULL)
++    return;
++
+   ply_event_loop_stop_watching_fd (backend->loop, input_source->terminal_input_watch);
+   input_source->terminal_input_watch = NULL;
+   input_source->backend = NULL;
+diff --git a/src/plugins/renderers/drm/ply-renderer-generic-driver.c b/src/plugins/renderers/drm/ply-renderer-generic-driver.c
+index 50fde64..45a8faa 100644
+--- a/src/plugins/renderers/drm/ply-renderer-generic-driver.c
++++ b/src/plugins/renderers/drm/ply-renderer-generic-driver.c
+@@ -71,6 +71,8 @@ struct _ply_renderer_driver
+ {
+   int device_fd;
+   ply_hashtable_t *buffers;
++
++  uint32_t requires_explicit_flushing : 1;
+ };
+ static bool
+@@ -123,7 +125,7 @@ create_driver (int device_fd)
+   driver = calloc (1, sizeof (ply_renderer_driver_t));
+   driver->device_fd = device_fd;
+-
++  driver->requires_explicit_flushing = true;
+   driver->buffers = ply_hashtable_new (ply_hashtable_direct_hash,
+                                        ply_hashtable_direct_compare);
+@@ -330,6 +332,22 @@ end_flush (ply_renderer_driver_t *driver,
+   buffer = get_buffer_from_id (driver, buffer_id);
+   assert (buffer != NULL);
++
++  if (driver->requires_explicit_flushing)
++    {
++      struct drm_clip_rect flush_area;
++      int ret;
++
++      flush_area.x1 = 0;
++      flush_area.y1 = 0;
++      flush_area.x2 = buffer->width;
++      flush_area.y2 = buffer->height;
++
++      ret = drmModeDirtyFB (driver->device_fd, buffer->id, &flush_area, 1);
++
++      if (ret == -ENOSYS)
++        driver->requires_explicit_flushing = false;
++    }
+ }
+ static void
+diff --git a/src/plugins/renderers/drm/ply-renderer-i915-driver.c b/src/plugins/renderers/drm/ply-renderer-i915-driver.c
+deleted file mode 100644
+index 907a061..0000000
+--- a/src/plugins/renderers/drm/ply-renderer-i915-driver.c
++++ /dev/null
+@@ -1,383 +0,0 @@
+-/* ply-renderer-i915-driver.c - interface to i915 drm driver
+- *
+- * Copyright (C) 2009 Red Hat, Inc.
+- *
+- * 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, 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, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+- * 02111-1307, USA.
+- *
+- * Written by: Ray Strode <rstrode@redhat.com>
+- */
+-#include "config.h"
+-
+-#include "ply-renderer-i915-driver.h"
+-
+-#include <arpa/inet.h>
+-#include <assert.h>
+-#include <errno.h>
+-#include <fcntl.h>
+-#include <signal.h>
+-#include <string.h>
+-#include <stdbool.h>
+-#include <stdint.h>
+-#include <stdio.h>
+-#include <stdlib.h>
+-#include <sys/ioctl.h>
+-#include <sys/mman.h>
+-#include <sys/stat.h>
+-#include <sys/types.h>
+-#include <values.h>
+-#include <unistd.h>
+-
+-#include <drm.h>
+-#include <i915_drm.h>
+-#include <intel_bufmgr.h>
+-#include <xf86drm.h>
+-#include <xf86drmMode.h>
+-
+-#include "ply-hashtable.h"
+-#include "ply-logger.h"
+-#include "ply-renderer-driver.h"
+-
+-typedef struct _ply_renderer_buffer ply_renderer_buffer_t;
+-
+-struct _ply_renderer_buffer
+-{
+-  drm_intel_bo *object;
+-  uint32_t id;
+-  unsigned long width;
+-  unsigned long height;
+-  unsigned long row_stride;
+-
+-  uint32_t added_fb : 1;
+-};
+-
+-struct _ply_renderer_driver
+-{
+-  int device_fd;
+-  drm_intel_bufmgr *manager;
+-
+-  ply_hashtable_t *buffers;
+-};
+-
+-static ply_renderer_driver_t *
+-create_driver (int device_fd)
+-{
+-  ply_renderer_driver_t *driver;
+-  int page_size;
+-
+-  driver = calloc (1, sizeof (ply_renderer_driver_t));
+-  driver->device_fd = device_fd;
+-
+-  page_size = (int) sysconf (_SC_PAGE_SIZE);
+-
+-  driver->manager = drm_intel_bufmgr_gem_init (driver->device_fd, page_size);
+-  if (driver->manager == NULL)
+-    {
+-      ply_trace ("intel buffer manager could not be initialized");
+-      free (driver);
+-      return NULL;
+-    }
+-
+-  driver->buffers = ply_hashtable_new (ply_hashtable_direct_hash,
+-                                       ply_hashtable_direct_compare);
+-
+-  return driver;
+-}
+-
+-static void
+-destroy_driver (ply_renderer_driver_t *driver)
+-{
+-  ply_hashtable_free (driver->buffers);
+-
+-  ply_trace ("uninitializing intel buffer manager");
+-  drm_intel_bufmgr_destroy (driver->manager);
+-  free (driver);
+-}
+-
+-static ply_renderer_buffer_t *
+-ply_renderer_buffer_new (ply_renderer_driver_t *driver,
+-                         drm_intel_bo *buffer_object,
+-                         uint32_t id,
+-                         unsigned long width,
+-                         unsigned long height,
+-                         unsigned long row_stride)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = calloc (1, sizeof (ply_renderer_buffer_t));
+-  buffer->object = buffer_object;
+-  buffer->id = id;
+-  buffer->width = width;
+-  buffer->height = height;
+-  buffer->row_stride = row_stride;
+-
+-  ply_trace ("returning %lux%lu buffer with stride %lu",
+-             width, height, row_stride);
+-
+-  return buffer;
+-}
+-
+-static drm_intel_bo *
+-create_intel_bo_from_handle (ply_renderer_driver_t *driver,
+-                             uint32_t               handle)
+-{
+-  struct drm_gem_flink flink_request;
+-  char *name;
+-  drm_intel_bo *buffer_object;
+-
+-  /* FIXME: This can't be the right way to do this.
+-   *
+-   * 1) It requires skirting around the API and using ioctls
+-   * 2) It requires taking a local handle, turning it into a
+-   * a global handle ("name"), just so we can use an api that
+-   * will open the global name and grab the local handle from it.
+-   */
+-
+-  memset (&flink_request, 0, sizeof (struct drm_gem_flink));
+-  flink_request.handle = handle;
+-
+-  if (ioctl (driver->device_fd, DRM_IOCTL_GEM_FLINK, &flink_request) < 0)
+-    {
+-      ply_trace ("Could not export global name for handle %u", handle);
+-      return NULL;
+-    }
+-
+-  asprintf (&name, "buffer %u", handle);
+-
+-  buffer_object = drm_intel_bo_gem_create_from_name (driver->manager,
+-                                                     name, flink_request.name);
+-  free (name);
+-
+-  return buffer_object;
+-}
+-
+-static ply_renderer_buffer_t *
+-ply_renderer_buffer_new_from_id (ply_renderer_driver_t *driver,
+-                                 uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-  drmModeFB *fb;
+-  drm_intel_bo *buffer_object;
+-
+-  fb = drmModeGetFB (driver->device_fd, buffer_id);
+-
+-  if (fb == NULL)
+-    {
+-      ply_trace ("could not get FB with buffer id %u", buffer_id);
+-      return NULL;
+-    }
+-
+-  buffer_object = create_intel_bo_from_handle (driver, fb->handle);
+-
+-  if (buffer_object == NULL)
+-    {
+-      ply_trace ("could not create buffer object from handle %lu",
+-                 (unsigned long) fb->handle);
+-      drmModeFreeFB (fb);
+-      return NULL;
+-    }
+-
+-  buffer = ply_renderer_buffer_new (driver, buffer_object, buffer_id,
+-                                    fb->width, fb->height, fb->pitch);
+-  drmModeFreeFB (fb);
+-
+-  return buffer;
+-}
+-
+-static ply_renderer_buffer_t *
+-get_buffer_from_id (ply_renderer_driver_t *driver,
+-                    uint32_t               buffer_id)
+-{
+-  static ply_renderer_buffer_t *buffer;
+-
+-  buffer = ply_hashtable_lookup (driver->buffers,
+-                                 (void *) (uintptr_t) buffer_id);
+-
+-  return buffer;
+-}
+-
+-static bool
+-fetch_buffer (ply_renderer_driver_t *driver,
+-              uint32_t               buffer_id,
+-              unsigned long         *width,
+-              unsigned long         *height,
+-              unsigned long         *row_stride)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  if (buffer == NULL)
+-    {
+-      ply_trace ("could not fetch buffer %u, creating one", buffer_id);
+-      buffer = ply_renderer_buffer_new_from_id (driver, buffer_id);
+-
+-      if (buffer == NULL)
+-        {
+-          ply_trace ("could not create buffer either %u", buffer_id);
+-          return false;
+-        }
+-
+-      ply_hashtable_insert (driver->buffers,
+-                            (void *) (uintptr_t) buffer_id,
+-                            buffer);
+-    }
+-
+-  if (width != NULL)
+-    *width = buffer->width;
+-
+-  if (height != NULL)
+-    *height = buffer->height;
+-
+-  if (row_stride != NULL)
+-    *row_stride = buffer->row_stride;
+-
+-  ply_trace ("fetched %lux%lu buffer with stride %lu",
+-             buffer->width, buffer->height, buffer->row_stride);
+-  return true;
+-}
+-
+-static uint32_t
+-create_buffer (ply_renderer_driver_t *driver,
+-               unsigned long          width,
+-               unsigned long          height,
+-               unsigned long         *row_stride)
+-{
+-  drm_intel_bo *buffer_object;
+-  ply_renderer_buffer_t *buffer;
+-  uint32_t buffer_id;
+-
+-  *row_stride = ply_round_to_multiple (width * 4, 256);
+-
+-  buffer_object = drm_intel_bo_alloc (driver->manager,
+-                                      "frame buffer",
+-                                      height * *row_stride, 0);
+-
+-  if (buffer_object == NULL)
+-    {
+-      ply_trace ("Could not allocate GEM object for frame buffer: %m");
+-      return 0;
+-    }
+-
+-  if (drmModeAddFB (driver->device_fd, width, height,
+-                    24, 32, *row_stride, buffer_object->handle,
+-                    &buffer_id) != 0)
+-    {
+-      ply_trace ("Could not set up GEM object as frame buffer: %m");
+-      drm_intel_bo_unreference (buffer_object);
+-      return 0;
+-    }
+-
+-  buffer = ply_renderer_buffer_new (driver,
+-                                    buffer_object, buffer_id,
+-                                    width, height, *row_stride);
+-  buffer->added_fb = true;
+-  ply_hashtable_insert (driver->buffers,
+-                        (void *) (uintptr_t) buffer_id,
+-                        buffer);
+-
+-  return buffer_id;
+-}
+-
+-static bool
+-map_buffer (ply_renderer_driver_t *driver,
+-            uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-  drm_intel_gem_bo_map_gtt (buffer->object);
+-
+-  return true;
+-}
+-
+-static void
+-unmap_buffer (ply_renderer_driver_t *driver,
+-              uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-  drm_intel_gem_bo_unmap_gtt (buffer->object);
+-}
+-
+-static char *
+-begin_flush (ply_renderer_driver_t *driver,
+-             uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-
+-  return buffer->object->virtual;
+-}
+-
+-static void
+-end_flush (ply_renderer_driver_t *driver,
+-           uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-}
+-
+-static void
+-destroy_buffer (ply_renderer_driver_t *driver,
+-                uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-
+-  if (buffer->added_fb)
+-    drmModeRmFB (driver->device_fd, buffer->id);
+-
+-  drm_intel_bo_unreference (buffer->object);
+-
+-  ply_hashtable_remove (driver->buffers,
+-                        (void *) (uintptr_t) buffer_id);
+-  free (buffer);
+-}
+-
+-ply_renderer_driver_interface_t *
+-ply_renderer_i915_driver_get_interface (void)
+-{
+-  static ply_renderer_driver_interface_t driver_interface =
+-    {
+-      .create_driver = create_driver,
+-      .destroy_driver = destroy_driver,
+-      .create_buffer = create_buffer,
+-      .fetch_buffer = fetch_buffer,
+-      .map_buffer = map_buffer,
+-      .unmap_buffer = unmap_buffer,
+-      .begin_flush = begin_flush,
+-      .end_flush = end_flush,
+-      .destroy_buffer = destroy_buffer,
+-    };
+-
+-  return &driver_interface;
+-}
+-
+-/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */
+diff --git a/src/plugins/renderers/drm/ply-renderer-i915-driver.h b/src/plugins/renderers/drm/ply-renderer-i915-driver.h
+deleted file mode 100644
+index dcc983c..0000000
+--- a/src/plugins/renderers/drm/ply-renderer-i915-driver.h
++++ /dev/null
+@@ -1,32 +0,0 @@
+-/* ply-renderer-i915-driver.h
+- *
+- * Copyright (C) 2009 Red Hat, Inc.
+- *
+- * 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, 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, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+- * 02111-1307, USA.
+- *
+- * Written By: Ray Strode <rstrode@redhat.com>
+- */
+-#ifndef PLY_RENDERER_I915_DRIVER_H
+-#define PLY_RENDERER_I915_DRIVER_H
+-
+-#include "ply-renderer-driver.h"
+-
+-#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
+-ply_renderer_driver_interface_t *ply_renderer_i915_driver_get_interface (void);
+-#endif
+-
+-#endif /* PLY_RENDERER_I915_DRIVER_H */
+-/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */
+diff --git a/src/plugins/renderers/drm/ply-renderer-libkms-driver.c b/src/plugins/renderers/drm/ply-renderer-libkms-driver.c
+deleted file mode 100644
+index 18c7ccf..0000000
+--- a/src/plugins/renderers/drm/ply-renderer-libkms-driver.c
++++ /dev/null
+@@ -1,430 +0,0 @@
+-/* ply-renderer-libkms-driver.c - interface to libkms abstraction over drm drivers
+- *
+- * Copyright (C) 2010 Red Hat, Inc.
+- *
+- * 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, 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, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+- * 02111-1307, USA.
+- *
+- * Written by: Ray Strode <rstrode@redhat.com>
+- */
+-#include "config.h"
+-
+-#include "ply-renderer-libkms-driver.h"
+-
+-#include <arpa/inet.h>
+-#include <assert.h>
+-#include <errno.h>
+-#include <fcntl.h>
+-#include <signal.h>
+-#include <string.h>
+-#include <stdbool.h>
+-#include <stdint.h>
+-#include <stdio.h>
+-#include <stdlib.h>
+-#include <sys/ioctl.h>
+-#include <sys/mman.h>
+-#include <sys/stat.h>
+-#include <sys/types.h>
+-#include <values.h>
+-#include <unistd.h>
+-
+-#include <drm.h>
+-#include <libkms.h>
+-#include <xf86drm.h>
+-#include <xf86drmMode.h>
+-
+-#include "ply-array.h"
+-#include "ply-hashtable.h"
+-#include "ply-logger.h"
+-#include "ply-renderer-driver.h"
+-
+-typedef struct _ply_renderer_buffer ply_renderer_buffer_t;
+-
+-struct _ply_renderer_buffer
+-{
+-  struct kms_bo *object;
+-  uint32_t id;
+-  unsigned long width;
+-  unsigned long height;
+-  unsigned long row_stride;
+-
+-  void *map_address;
+-
+-  uint32_t added_fb : 1;
+-};
+-
+-struct _ply_renderer_driver
+-{
+-  int device_fd;
+-  struct kms_driver *driver;
+-
+-  ply_hashtable_t *buffers;
+-};
+-
+-static ply_renderer_driver_t *
+-create_driver (int device_fd)
+-{
+-  ply_renderer_driver_t *driver;
+-  int result;
+-
+-  driver = calloc (1, sizeof (ply_renderer_driver_t));
+-  driver->device_fd = device_fd;
+-
+-  result = kms_create (driver->device_fd, &driver->driver);
+-  if (result != 0)
+-    {
+-      ply_trace ("kms buffer driver could not be initialized: %d", result);
+-      free (driver);
+-      return NULL;
+-    }
+-
+-  driver->buffers = ply_hashtable_new (ply_hashtable_direct_hash,
+-                                       ply_hashtable_direct_compare);
+-
+-  return driver;
+-}
+-
+-static void
+-destroy_driver (ply_renderer_driver_t *driver)
+-{
+-  ply_hashtable_free (driver->buffers);
+-
+-  ply_trace ("uninitializing kms buffer driver");
+-  kms_destroy (&driver->driver);
+-  free (driver);
+-}
+-
+-static ply_renderer_buffer_t *
+-ply_renderer_buffer_new (ply_renderer_driver_t *driver,
+-                         struct kms_bo *buffer_object,
+-                         uint32_t id,
+-                         unsigned long width,
+-                         unsigned long height,
+-                         unsigned long row_stride)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = calloc (1, sizeof (ply_renderer_buffer_t));
+-  buffer->object = buffer_object;
+-  buffer->id = id;
+-  buffer->width = width;
+-  buffer->height = height;
+-  buffer->row_stride = row_stride;
+-
+-  ply_trace ("returning %lux%lu buffer with stride %lu",
+-             width, height, row_stride);
+-
+-  return buffer;
+-}
+-
+-static ply_renderer_buffer_t *
+-get_buffer_from_id (ply_renderer_driver_t *driver,
+-                    uint32_t               id)
+-{
+-  static ply_renderer_buffer_t *buffer;
+-
+-  buffer = ply_hashtable_lookup (driver->buffers, (void *) (uintptr_t) id);
+-
+-  return buffer;
+-}
+-
+-static struct kms_bo *
+-create_kms_bo_from_handle (ply_renderer_driver_t *driver,
+-                           uint32_t               handle)
+-{
+-  struct drm_gem_flink flink_request;
+-  struct kms_bo *buffer_object;
+-  ply_array_t *attributes;
+-  int result;
+-
+-  /* FIXME: This can't be the right way to do this.
+-   *
+-   * 1) It requires skirting around the API and using ioctls
+-   * 2) It requires taking a local handle, turning it into a
+-   * a global handle ("name"), just so we can use an api that
+-   * will open the global name and grab the local handle from it.
+-   */
+-
+-  memset (&flink_request, 0, sizeof (struct drm_gem_flink));
+-  flink_request.handle = handle;
+-
+-  if (ioctl (driver->device_fd, DRM_IOCTL_GEM_FLINK, &flink_request) < 0)
+-    {
+-      ply_trace ("Could not export global name for handle %u", handle);
+-      return NULL;
+-    }
+-
+-  attributes = ply_array_new (PLY_ARRAY_ELEMENT_TYPE_UINT32);
+-  ply_array_add_uint32_element (attributes, KMS_HANDLE);
+-  ply_array_add_uint32_element (attributes, flink_request.name);
+-  ply_array_add_uint32_element (attributes, KMS_TERMINATE_PROP_LIST);
+-  result = kms_bo_create (driver->driver,
+-                          (const unsigned *)
+-                          ply_array_get_uint32_elements (attributes),
+-                          &buffer_object);
+-  ply_array_free (attributes);
+-
+-  if (result != 0)
+-    {
+-      ply_trace ("could not create buffer object from global name %u: %d",
+-                 flink_request.name, result);
+-      return NULL;
+-    }
+-
+-  return buffer_object;
+-}
+-
+-static ply_renderer_buffer_t *
+-ply_renderer_buffer_new_from_id (ply_renderer_driver_t *driver,
+-                                 uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-  drmModeFB *fb;
+-  struct kms_bo *buffer_object;
+-
+-  fb = drmModeGetFB (driver->device_fd, buffer_id);
+-
+-  if (fb == NULL)
+-    {
+-      ply_trace ("could not get FB with buffer id %u", buffer_id);
+-      return NULL;
+-    }
+-
+-  buffer_object = create_kms_bo_from_handle (driver, fb->handle);
+-
+-  if (buffer_object == NULL)
+-    {
+-      ply_trace ("could not create buffer object from handle %lu",
+-                 (unsigned long) fb->handle);
+-      drmModeFreeFB (fb);
+-      return NULL;
+-    }
+-
+-  buffer = ply_renderer_buffer_new (driver, buffer_object, buffer_id,
+-                                    fb->width, fb->height, fb->pitch);
+-  drmModeFreeFB (fb);
+-
+-  return buffer;
+-}
+-
+-static bool
+-fetch_buffer (ply_renderer_driver_t *driver,
+-              uint32_t               buffer_id,
+-              unsigned long         *width,
+-              unsigned long         *height,
+-              unsigned long         *row_stride)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  if (buffer == NULL)
+-    {
+-      ply_trace ("could not fetch buffer %u, creating one", buffer_id);
+-      buffer = ply_renderer_buffer_new_from_id (driver, buffer_id);
+-
+-      if (buffer == NULL)
+-        {
+-          ply_trace ("could not create buffer either %u", buffer_id);
+-          return false;
+-        }
+-
+-      ply_hashtable_insert (driver->buffers,
+-                            (void *) (uintptr_t) buffer_id,
+-                            buffer);
+-    }
+-
+-  if (width != NULL)
+-    *width = buffer->width;
+-
+-  if (height != NULL)
+-    *height = buffer->height;
+-
+-  if (row_stride != NULL)
+-    *row_stride = buffer->row_stride;
+-
+-  ply_trace ("fetched %lux%lu buffer with stride %lu",
+-             buffer->width, buffer->height, buffer->row_stride);
+-  return true;
+-}
+-
+-static uint32_t
+-create_buffer (ply_renderer_driver_t *driver,
+-               unsigned long          width,
+-               unsigned long          height,
+-               unsigned long         *row_stride)
+-{
+-  struct kms_bo *buffer_object;
+-  ply_renderer_buffer_t *buffer;
+-  uint32_t buffer_id;
+-  int result;
+-  unsigned int handle;
+-  ply_array_t *attributes;
+-
+-  *row_stride = ply_round_to_multiple (width * 4, 256);
+-
+-  attributes = ply_array_new (PLY_ARRAY_ELEMENT_TYPE_UINT32);
+-  ply_array_add_uint32_element (attributes, KMS_BO_TYPE);
+-  ply_array_add_uint32_element (attributes, KMS_BO_TYPE_SCANOUT_X8R8G8B8);
+-  ply_array_add_uint32_element (attributes, KMS_WIDTH);
+-  ply_array_add_uint32_element (attributes, (uint32_t) width);
+-  ply_array_add_uint32_element (attributes, KMS_HEIGHT);
+-  ply_array_add_uint32_element (attributes, (uint32_t) height);
+-  ply_array_add_uint32_element (attributes, KMS_PITCH);
+-  ply_array_add_uint32_element (attributes, (uint32_t) *row_stride);
+-  ply_array_add_uint32_element (attributes, KMS_TERMINATE_PROP_LIST);
+-  result = kms_bo_create (driver->driver,
+-                          (const unsigned *)
+-                          ply_array_get_uint32_elements (attributes),
+-                          &buffer_object);
+-  ply_array_free (attributes);
+-
+-  if (result != 0)
+-    {
+-      ply_trace ("Could not allocate GEM object for frame buffer: %d", result);
+-      return 0;
+-    }
+-
+-  result = kms_bo_get_prop (buffer_object, KMS_HANDLE, &handle);
+-
+-  if (result != 0)
+-    {
+-      ply_trace ("Could not retrieve handle from GEM object: %d", result);
+-
+-      kms_bo_destroy (&buffer_object);
+-      return 0;
+-    }
+-
+-  if (drmModeAddFB (driver->device_fd, width, height,
+-                    24, 32, *row_stride, handle,
+-                    &buffer_id) != 0)
+-    {
+-      ply_trace ("Could not set up GEM object as frame buffer: %m");
+-      kms_bo_destroy (&buffer_object);
+-      return 0;
+-    }
+-
+-  buffer = ply_renderer_buffer_new (driver,
+-                                    buffer_object, buffer_id,
+-                                    width, height, *row_stride);
+-  buffer->added_fb = true;
+-  ply_hashtable_insert (driver->buffers,
+-                        (void *) (uintptr_t) buffer_id,
+-                        buffer);
+-
+-  return buffer_id;
+-}
+-
+-static bool
+-map_buffer (ply_renderer_driver_t *driver,
+-            uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-  int result;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-
+-  result = kms_bo_map (buffer->object, &buffer->map_address);
+-
+-  if (result != 0)
+-    {
+-      ply_trace ("could not map buffer %u: %d", buffer_id, result);
+-      buffer->map_address = MAP_FAILED;
+-      return false;
+-    }
+-
+-  return true;
+-}
+-
+-static void
+-unmap_buffer (ply_renderer_driver_t *driver,
+-              uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-
+-  kms_bo_unmap (buffer->object);
+-  buffer->map_address = MAP_FAILED;
+-}
+-
+-static char *
+-begin_flush (ply_renderer_driver_t *driver,
+-             uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-
+-  return (char *) buffer->map_address;
+-}
+-
+-static void
+-end_flush (ply_renderer_driver_t *driver,
+-           uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-}
+-
+-static void
+-destroy_buffer (ply_renderer_driver_t *driver,
+-                uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-
+-  if (buffer->added_fb)
+-    drmModeRmFB (driver->device_fd, buffer->id);
+-
+-  kms_bo_destroy (&buffer->object);
+-
+-  ply_hashtable_remove (driver->buffers,
+-                        (void *) (uintptr_t) buffer_id);
+-  free (buffer);
+-}
+-
+-ply_renderer_driver_interface_t *
+-ply_renderer_libkms_driver_get_interface (void)
+-{
+-  static ply_renderer_driver_interface_t driver_interface =
+-    {
+-      .create_driver = create_driver,
+-      .destroy_driver = destroy_driver,
+-      .create_buffer = create_buffer,
+-      .fetch_buffer = fetch_buffer,
+-      .map_buffer = map_buffer,
+-      .unmap_buffer = unmap_buffer,
+-      .begin_flush = begin_flush,
+-      .end_flush = end_flush,
+-      .destroy_buffer = destroy_buffer,
+-    };
+-
+-  return &driver_interface;
+-}
+-
+-/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */
+diff --git a/src/plugins/renderers/drm/ply-renderer-libkms-driver.h b/src/plugins/renderers/drm/ply-renderer-libkms-driver.h
+deleted file mode 100644
+index b419a94..0000000
+--- a/src/plugins/renderers/drm/ply-renderer-libkms-driver.h
++++ /dev/null
+@@ -1,32 +0,0 @@
+-/* ply-renderer-kms-driver.h
+- *
+- * Copyright (C) 2009 Red Hat, Inc.
+- *
+- * 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, 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, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+- * 02111-1307, USA.
+- *
+- * Written By: Ray Strode <rstrode@redhat.com>
+- */
+-#ifndef PLY_RENDERER_LIBKMS_DRIVER_H
+-#define PLY_RENDERER_LIBKMS_DRIVER_H
+-
+-#include "ply-renderer-driver.h"
+-
+-#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
+-ply_renderer_driver_interface_t *ply_renderer_libkms_driver_get_interface (void);
+-#endif
+-
+-#endif /* PLY_RENDERER_LIBKMS_DRIVER_H */
+-/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */
+diff --git a/src/plugins/renderers/drm/ply-renderer-nouveau-driver.c b/src/plugins/renderers/drm/ply-renderer-nouveau-driver.c
+deleted file mode 100644
+index 2cef56e..0000000
+--- a/src/plugins/renderers/drm/ply-renderer-nouveau-driver.c
++++ /dev/null
+@@ -1,352 +0,0 @@
+-/* ply-renderer-nouveau-driver.c - interface to nouveau drm driver
+- *
+- * Copyright (C) 2009 Red Hat, Inc.
+- *
+- * 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, 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, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+- * 02111-1307, USA.
+- *
+- * Written by: Ray Strode <rstrode@redhat.com>
+- */
+-#include "config.h"
+-
+-#include "ply-renderer-nouveau-driver.h"
+-
+-#include <arpa/inet.h>
+-#include <assert.h>
+-#include <errno.h>
+-#include <fcntl.h>
+-#include <signal.h>
+-#include <string.h>
+-#include <stdbool.h>
+-#include <stdint.h>
+-#include <stdio.h>
+-#include <stdlib.h>
+-#include <sys/ioctl.h>
+-#include <sys/mman.h>
+-#include <sys/stat.h>
+-#include <sys/types.h>
+-#include <values.h>
+-#include <unistd.h>
+-
+-#include <drm.h>
+-#include <nouveau_drm.h>
+-#include <nouveau_drmif.h>
+-#include <nouveau_bo.h>
+-#include <xf86drm.h>
+-#include <xf86drmMode.h>
+-
+-#include "ply-hashtable.h"
+-#include "ply-logger.h"
+-#include "ply-renderer-driver.h"
+-
+-typedef struct _ply_renderer_buffer ply_renderer_buffer_t;
+-
+-struct _ply_renderer_buffer
+-{
+-  struct nouveau_bo *object;
+-  uint32_t id;
+-  unsigned long width;
+-  unsigned long height;
+-  unsigned long row_stride;
+-
+-  uint32_t added_fb : 1;
+-};
+-
+-struct _ply_renderer_driver
+-{
+-  int device_fd;
+-  struct nouveau_device *device;
+-
+-  ply_hashtable_t *buffers;
+-};
+-
+-static ply_renderer_driver_t *
+-create_driver (int device_fd)
+-{
+-  ply_renderer_driver_t *driver;
+-
+-  driver = calloc (1, sizeof (ply_renderer_driver_t));
+-  driver->device_fd = device_fd;
+-
+-  if (nouveau_device_open_existing (&driver->device, true,
+-                                    driver->device_fd, 0) < 0)
+-    {
+-      ply_trace ("could not open nouveau device");
+-      free (driver);
+-      return NULL;
+-    }
+-
+-  driver->buffers = ply_hashtable_new (ply_hashtable_direct_hash,
+-                                       ply_hashtable_direct_compare);
+-
+-  return driver;
+-}
+-
+-static void
+-destroy_driver (ply_renderer_driver_t *driver)
+-{
+-  ply_hashtable_free (driver->buffers);
+-
+-  ply_trace ("closing nouveau device");
+-  nouveau_device_close (&driver->device);
+-  free (driver);
+-}
+-
+-static ply_renderer_buffer_t *
+-ply_renderer_buffer_new (ply_renderer_driver_t *driver,
+-                         struct nouveau_bo *buffer_object,
+-                         uint32_t id,
+-                         unsigned long width,
+-                         unsigned long height,
+-                         unsigned long row_stride)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = calloc (1, sizeof (ply_renderer_buffer_t));
+-  buffer->object = buffer_object;
+-  buffer->id = id;
+-  buffer->width = width;
+-  buffer->height = height;
+-  buffer->row_stride = row_stride;
+-
+-  ply_trace ("returning %lux%lu buffer with stride %lu",
+-             width, height, row_stride);
+-
+-  return buffer;
+-}
+-
+-static ply_renderer_buffer_t *
+-ply_renderer_buffer_new_from_id (ply_renderer_driver_t *driver,
+-                                 uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-  drmModeFB *fb;
+-  struct nouveau_bo *buffer_object;
+-
+-  fb = drmModeGetFB (driver->device_fd, buffer_id);
+-
+-  if (fb == NULL)
+-    {
+-      ply_trace ("could not get FB with buffer id %u", buffer_id);
+-      return NULL;
+-    }
+-
+-  if (nouveau_bo_wrap (driver->device,
+-                       fb->handle, &buffer_object) < 0)
+-    {
+-      ply_trace ("could not create buffer object from handle %lu",
+-                 (unsigned long) fb->handle);
+-      drmModeFreeFB (fb);
+-      return NULL;
+-    }
+-
+-  buffer = ply_renderer_buffer_new (driver, buffer_object, buffer_id,
+-                                    fb->width, fb->height, fb->pitch);
+-  drmModeFreeFB (fb);
+-
+-  return buffer;
+-}
+-
+-static ply_renderer_buffer_t *
+-get_buffer_from_id (ply_renderer_driver_t *driver,
+-                    uint32_t               id)
+-{
+-  static ply_renderer_buffer_t *buffer;
+-
+-  buffer = ply_hashtable_lookup (driver->buffers, (void *) (uintptr_t) id);
+-
+-  return buffer;
+-}
+-
+-static bool
+-fetch_buffer (ply_renderer_driver_t *driver,
+-              uint32_t               buffer_id,
+-              unsigned long         *width,
+-              unsigned long         *height,
+-              unsigned long         *row_stride)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  if (buffer == NULL)
+-    {
+-      ply_trace ("could not fetch buffer %u, creating one", buffer_id);
+-      buffer = ply_renderer_buffer_new_from_id (driver, buffer_id);
+-
+-      if (buffer == NULL)
+-        {
+-          ply_trace ("could not create buffer either %u", buffer_id);
+-          return false;
+-        }
+-
+-      ply_hashtable_insert (driver->buffers,
+-                            (void *) (uintptr_t) buffer_id,
+-                            buffer);
+-    }
+-
+-  if (width != NULL)
+-    *width = buffer->width;
+-
+-  if (height != NULL)
+-    *height = buffer->height;
+-
+-  if (row_stride != NULL)
+-    *row_stride = buffer->row_stride;
+-
+-  ply_trace ("fetched %lux%lu buffer with stride %lu",
+-             buffer->width, buffer->height, buffer->row_stride);
+-  return true;
+-}
+-
+-
+-static uint32_t
+-create_buffer (ply_renderer_driver_t *driver,
+-               unsigned long          width,
+-               unsigned long          height,
+-               unsigned long         *row_stride)
+-{
+-  struct nouveau_bo *buffer_object;
+-  ply_renderer_buffer_t *buffer;
+-  uint32_t buffer_id;
+-
+-  *row_stride = ply_round_to_multiple (width * 4, 256);
+-
+-  buffer_object = NULL;
+-  if (nouveau_bo_new (driver->device,
+-                      NOUVEAU_BO_VRAM | NOUVEAU_BO_MAP, 0,
+-                      height * *row_stride, &buffer_object) < 0)
+-    {
+-      ply_trace ("Could not allocate GEM object for frame buffer: %m");
+-      return 0;
+-    }
+-
+-  /* The map here forces the buffer object to be instantiated
+-   * immediately (it's normally instantiated lazily when needed
+-   * by other nouveau_bo api)
+-   */
+-  nouveau_bo_map (buffer_object, NOUVEAU_BO_WR);
+-  if (drmModeAddFB (driver->device_fd, width, height,
+-                    24, 32, *row_stride, buffer_object->handle,
+-                    &buffer_id) != 0)
+-    {
+-      nouveau_bo_unmap (buffer_object);
+-      ply_trace ("Could not set up GEM object as frame buffer: %m");
+-      nouveau_bo_ref (NULL, &buffer_object);
+-      return 0;
+-    }
+-  nouveau_bo_unmap (buffer_object);
+-
+-  buffer = ply_renderer_buffer_new (driver,
+-                                    buffer_object, buffer_id,
+-                                    width, height, *row_stride);
+-  buffer->added_fb = true;
+-  ply_hashtable_insert (driver->buffers,
+-                        (void *) (uintptr_t) buffer_id,
+-                        buffer);
+-
+-  return buffer_id;
+-}
+-
+-static bool
+-map_buffer (ply_renderer_driver_t *driver,
+-            uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-
+-  return nouveau_bo_map (buffer->object, NOUVEAU_BO_WR) == 0;
+-}
+-
+-static void
+-unmap_buffer (ply_renderer_driver_t *driver,
+-              uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-
+-  nouveau_bo_unmap (buffer->object);
+-}
+-
+-static char *
+-begin_flush (ply_renderer_driver_t *driver,
+-             uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-
+-  return buffer->object->map;
+-}
+-
+-static void
+-end_flush (ply_renderer_driver_t *driver,
+-           uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-}
+-
+-static void
+-destroy_buffer (ply_renderer_driver_t *driver,
+-                uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-
+-  if (buffer->added_fb)
+-    drmModeRmFB (driver->device_fd, buffer->id);
+-
+-  nouveau_bo_ref (NULL, &buffer->object);
+-
+-  ply_hashtable_remove (driver->buffers,
+-                        (void *) (uintptr_t) buffer_id);
+-  free (buffer);
+-}
+-
+-ply_renderer_driver_interface_t *
+-ply_renderer_nouveau_driver_get_interface (void)
+-{
+-  static ply_renderer_driver_interface_t driver_interface =
+-    {
+-      .create_driver = create_driver,
+-      .destroy_driver = destroy_driver,
+-      .create_buffer = create_buffer,
+-      .fetch_buffer = fetch_buffer,
+-      .map_buffer = map_buffer,
+-      .unmap_buffer = unmap_buffer,
+-      .begin_flush = begin_flush,
+-      .end_flush = end_flush,
+-      .destroy_buffer = destroy_buffer,
+-    };
+-
+-  return &driver_interface;
+-}
+-
+-/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */
+diff --git a/src/plugins/renderers/drm/ply-renderer-nouveau-driver.h b/src/plugins/renderers/drm/ply-renderer-nouveau-driver.h
+deleted file mode 100644
+index 1baed4a..0000000
+--- a/src/plugins/renderers/drm/ply-renderer-nouveau-driver.h
++++ /dev/null
+@@ -1,32 +0,0 @@
+-/* ply-renderer-nouveau-driver.h
+- *
+- * Copyright (C) 2009 Red Hat, Inc.
+- *
+- * 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, 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, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+- * 02111-1307, USA.
+- *
+- * Written By: Ray Strode <rstrode@redhat.com>
+- */
+-#ifndef PLY_RENDERER_NOUVEAU_DRIVER_H
+-#define PLY_RENDERER_NOUVEAU_DRIVER_H
+-
+-#include "ply-renderer-driver.h"
+-
+-#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
+-ply_renderer_driver_interface_t *ply_renderer_nouveau_driver_get_interface (void);
+-#endif
+-
+-#endif /* PLY_RENDERER_NOUVEAU_DRIVER_H */
+-/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */
+diff --git a/src/plugins/renderers/drm/ply-renderer-radeon-driver.c b/src/plugins/renderers/drm/ply-renderer-radeon-driver.c
+deleted file mode 100644
+index 36cee47..0000000
+--- a/src/plugins/renderers/drm/ply-renderer-radeon-driver.c
++++ /dev/null
+@@ -1,377 +0,0 @@
+-/* ply-renderer-radeon-driver.c - interface to radeon drm driver
+- *
+- * Copyright (C) 2009 Red Hat, Inc.
+- *
+- * 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, 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, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+- * 02111-1307, USA.
+- *
+- * Written by: Ray Strode <rstrode@redhat.com>
+- */
+-#include "config.h"
+-
+-#include "ply-renderer-radeon-driver.h"
+-
+-#include <arpa/inet.h>
+-#include <assert.h>
+-#include <errno.h>
+-#include <fcntl.h>
+-#include <signal.h>
+-#include <string.h>
+-#include <stdbool.h>
+-#include <stdint.h>
+-#include <stdio.h>
+-#include <stdlib.h>
+-#include <sys/ioctl.h>
+-#include <sys/mman.h>
+-#include <sys/stat.h>
+-#include <sys/types.h>
+-#include <values.h>
+-#include <unistd.h>
+-
+-#include <drm.h>
+-#include <radeon_drm.h>
+-#include <radeon_bo.h>
+-#include <radeon_bo_gem.h>
+-#include <xf86drm.h>
+-#include <xf86drmMode.h>
+-
+-#include "ply-hashtable.h"
+-#include "ply-logger.h"
+-#include "ply-renderer-driver.h"
+-
+-typedef struct _ply_renderer_buffer ply_renderer_buffer_t;
+-
+-struct _ply_renderer_buffer
+-{
+-  struct radeon_bo *object;
+-  uint32_t id;
+-  unsigned long width;
+-  unsigned long height;
+-  unsigned long row_stride;
+-
+-  uint32_t added_fb : 1;
+-};
+-
+-struct _ply_renderer_driver
+-{
+-  int device_fd;
+-  struct radeon_bo_manager *manager;
+-
+-  ply_hashtable_t *buffers;
+-};
+-
+-static ply_renderer_driver_t *
+-create_driver (int device_fd)
+-{
+-  ply_renderer_driver_t *driver;
+-
+-  driver = calloc (1, sizeof (ply_renderer_driver_t));
+-  driver->device_fd = device_fd;
+-
+-  driver->manager = radeon_bo_manager_gem_ctor (driver->device_fd);
+-  if (driver->manager == NULL)
+-    {
+-      ply_trace ("radeon buffer manager could not be initialized");
+-      free (driver);
+-      return NULL;
+-    }
+-
+-  driver->buffers = ply_hashtable_new (ply_hashtable_direct_hash,
+-                                       ply_hashtable_direct_compare);
+-
+-  return driver;
+-}
+-
+-static void
+-destroy_driver (ply_renderer_driver_t *driver)
+-{
+-  ply_hashtable_free (driver->buffers);
+-
+-  ply_trace ("uninitializing radeon buffer manager");
+-  radeon_bo_manager_gem_dtor (driver->manager);
+-  free (driver);
+-}
+-
+-static ply_renderer_buffer_t *
+-ply_renderer_buffer_new (ply_renderer_driver_t *driver,
+-                         struct radeon_bo *buffer_object,
+-                         uint32_t id,
+-                         unsigned long width,
+-                         unsigned long height,
+-                         unsigned long row_stride)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = calloc (1, sizeof (ply_renderer_buffer_t));
+-  buffer->object = buffer_object;
+-  buffer->id = id;
+-  buffer->width = width;
+-  buffer->height = height;
+-  buffer->row_stride = row_stride;
+-
+-  ply_trace ("returning %lux%lu buffer with stride %lu",
+-             width, height, row_stride);
+-
+-  return buffer;
+-}
+-
+-static ply_renderer_buffer_t *
+-get_buffer_from_id (ply_renderer_driver_t *driver,
+-                    uint32_t               id)
+-{
+-  static ply_renderer_buffer_t *buffer;
+-
+-  buffer = ply_hashtable_lookup (driver->buffers, (void *) (uintptr_t) id);
+-
+-  return buffer;
+-}
+-
+-static struct radeon_bo *
+-create_radeon_bo_from_handle (ply_renderer_driver_t *driver,
+-                              uint32_t               handle)
+-{
+-  struct drm_gem_flink flink_request;
+-  struct radeon_bo *buffer_object;
+-
+-  /* FIXME: This can't be the right way to do this.
+-   *
+-   * 1) It requires skirting around the API and using ioctls
+-   * 2) It requires taking a local handle, turning it into a
+-   * a global handle ("name"), just so we can use an api that
+-   * will open the global name and grab the local handle from it.
+-   */
+-
+-  memset (&flink_request, 0, sizeof (struct drm_gem_flink));
+-  flink_request.handle = handle;
+-
+-  if (ioctl (driver->device_fd, DRM_IOCTL_GEM_FLINK, &flink_request) < 0)
+-    {
+-      ply_trace ("Could not export global name for handle %u", handle);
+-      return NULL;
+-    }
+-
+-  buffer_object = radeon_bo_open (driver->manager, flink_request.name,
+-                                  0, 0, RADEON_GEM_DOMAIN_GTT, 0);
+-
+-  return buffer_object;
+-}
+-
+-static ply_renderer_buffer_t *
+-ply_renderer_buffer_new_from_id (ply_renderer_driver_t *driver,
+-                                 uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-  drmModeFB *fb;
+-  struct radeon_bo *buffer_object;
+-
+-  fb = drmModeGetFB (driver->device_fd, buffer_id);
+-
+-  if (fb == NULL)
+-    {
+-      ply_trace ("could not get FB with buffer id %u", buffer_id);
+-      return NULL;
+-    }
+-
+-  buffer_object = create_radeon_bo_from_handle (driver, fb->handle);
+-
+-  if (buffer_object == NULL)
+-    {
+-      ply_trace ("could not create buffer object from handle %lu",
+-                 (unsigned long) fb->handle);
+-      drmModeFreeFB (fb);
+-      return NULL;
+-    }
+-
+-  buffer = ply_renderer_buffer_new (driver, buffer_object, buffer_id,
+-                                    fb->width, fb->height, fb->pitch);
+-  drmModeFreeFB (fb);
+-
+-  return buffer;
+-}
+-
+-
+-static bool
+-fetch_buffer (ply_renderer_driver_t *driver,
+-              uint32_t               buffer_id,
+-              unsigned long         *width,
+-              unsigned long         *height,
+-              unsigned long         *row_stride)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  if (buffer == NULL)
+-    {
+-      ply_trace ("could not fetch buffer %u, creating one", buffer_id);
+-      buffer = ply_renderer_buffer_new_from_id (driver, buffer_id);
+-
+-      if (buffer == NULL)
+-        {
+-          ply_trace ("could not create buffer either %u", buffer_id);
+-          return false;
+-        }
+-
+-      ply_hashtable_insert (driver->buffers,
+-                            (void *) (uintptr_t) buffer_id,
+-                            buffer);
+-    }
+-
+-  if (width != NULL)
+-    *width = buffer->width;
+-
+-  if (height != NULL)
+-    *height = buffer->height;
+-
+-  if (row_stride != NULL)
+-    *row_stride = buffer->row_stride;
+-
+-  ply_trace ("fetched %lux%lu buffer with stride %lu",
+-             buffer->width, buffer->height, buffer->row_stride);
+-  return true;
+-}
+-
+-static uint32_t
+-create_buffer (ply_renderer_driver_t *driver,
+-               unsigned long          width,
+-               unsigned long          height,
+-               unsigned long         *row_stride)
+-{
+-  struct radeon_bo *buffer_object;
+-  ply_renderer_buffer_t *buffer;
+-  uint32_t buffer_id;
+-
+-  *row_stride = ply_round_to_multiple (width * 4, 256);
+-
+-  buffer_object = radeon_bo_open (driver->manager, 0,
+-                                  height * *row_stride,
+-                                  0, RADEON_GEM_DOMAIN_GTT, 0);
+-
+-  if (buffer_object == NULL)
+-    {
+-      ply_trace ("Could not allocate GEM object for frame buffer: %m");
+-      return 0;
+-    }
+-
+-  if (drmModeAddFB (driver->device_fd, width, height,
+-                    24, 32, *row_stride, buffer_object->handle,
+-                    &buffer_id) != 0)
+-    {
+-      ply_trace ("Could not set up GEM object as frame buffer: %m");
+-      radeon_bo_unref (buffer_object);
+-      return 0;
+-    }
+-
+-  buffer = ply_renderer_buffer_new (driver,
+-                                    buffer_object, buffer_id,
+-                                    width, height, *row_stride);
+-  buffer->added_fb = true;
+-  ply_hashtable_insert (driver->buffers,
+-                        (void *) (uintptr_t) buffer_id,
+-                        buffer);
+-
+-  return buffer_id;
+-}
+-
+-static bool
+-map_buffer (ply_renderer_driver_t *driver,
+-            uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-
+-  return radeon_bo_map (buffer->object, true) == 0;
+-}
+-
+-static void
+-unmap_buffer (ply_renderer_driver_t *driver,
+-              uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-
+-  radeon_bo_unmap (buffer->object);
+-}
+-
+-static char *
+-begin_flush (ply_renderer_driver_t *driver,
+-             uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-
+-  return buffer->object->ptr;
+-}
+-
+-static void
+-end_flush (ply_renderer_driver_t *driver,
+-           uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-}
+-
+-static void
+-destroy_buffer (ply_renderer_driver_t *driver,
+-                uint32_t               buffer_id)
+-{
+-  ply_renderer_buffer_t *buffer;
+-
+-  buffer = get_buffer_from_id (driver, buffer_id);
+-
+-  assert (buffer != NULL);
+-
+-  if (buffer->added_fb)
+-    drmModeRmFB (driver->device_fd, buffer->id);
+-
+-  radeon_bo_unref (buffer->object);
+-
+-  ply_hashtable_remove (driver->buffers,
+-                        (void *) (uintptr_t) buffer_id);
+-  free (buffer);
+-}
+-
+-ply_renderer_driver_interface_t *
+-ply_renderer_radeon_driver_get_interface (void)
+-{
+-  static ply_renderer_driver_interface_t driver_interface =
+-    {
+-      .create_driver = create_driver,
+-      .destroy_driver = destroy_driver,
+-      .create_buffer = create_buffer,
+-      .fetch_buffer = fetch_buffer,
+-      .map_buffer = map_buffer,
+-      .unmap_buffer = unmap_buffer,
+-      .begin_flush = begin_flush,
+-      .end_flush = end_flush,
+-      .destroy_buffer = destroy_buffer,
+-    };
+-
+-  return &driver_interface;
+-}
+-
+-/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */
+diff --git a/src/plugins/renderers/drm/ply-renderer-radeon-driver.h b/src/plugins/renderers/drm/ply-renderer-radeon-driver.h
+deleted file mode 100644
+index dcec1b1..0000000
+--- a/src/plugins/renderers/drm/ply-renderer-radeon-driver.h
++++ /dev/null
+@@ -1,32 +0,0 @@
+-/* ply-renderer-radeon-driver.h
+- *
+- * Copyright (C) 2009 Red Hat, Inc.
+- *
+- * 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, 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, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+- * 02111-1307, USA.
+- *
+- * Written By: Ray Strode <rstrode@redhat.com>
+- */
+-#ifndef PLY_RENDERER_RADEON_DRIVER_H
+-#define PLY_RENDERER_RADEON_DRIVER_H
+-
+-#include "ply-renderer-driver.h"
+-
+-#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
+-ply_renderer_driver_interface_t *ply_renderer_radeon_driver_get_interface (void);
+-#endif
+-
+-#endif /* PLY_RENDERER_RADEON_DRIVER_H */
+-/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */
+diff --git a/src/plugins/renderers/frame-buffer/Makefile.am b/src/plugins/renderers/frame-buffer/Makefile.am
+index 44f9d6a..12e1470 100644
+--- a/src/plugins/renderers/frame-buffer/Makefile.am
++++ b/src/plugins/renderers/frame-buffer/Makefile.am
+@@ -1,4 +1,4 @@
+-INCLUDES = -I$(top_srcdir)                                                    \
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
+            -I$(srcdir)/../../../libply                                        \
+            -I$(srcdir)/../../../libply-splash-core                            \
+            -I$(srcdir)/../../..                                               \
+diff --git a/src/plugins/renderers/frame-buffer/plugin.c b/src/plugins/renderers/frame-buffer/plugin.c
+index 0e07943..dd73a0f 100644
+--- a/src/plugins/renderers/frame-buffer/plugin.c
++++ b/src/plugins/renderers/frame-buffer/plugin.c
+@@ -351,6 +351,9 @@ open_device (ply_renderer_backend_t *backend)
+       return false;
+     }
++  if (backend->terminal == NULL)
++    return true;
++
+   if (!ply_terminal_open (backend->terminal))
+     {
+       ply_trace ("could not open terminal: %m");
+@@ -376,10 +379,11 @@ static void
+ close_device (ply_renderer_backend_t *backend)
+ {
+-  ply_terminal_stop_watching_for_active_vt_change (backend->terminal,
+-                                                   (ply_terminal_active_vt_changed_handler_t)
+-                                                   on_active_vt_changed,
+-                                                   backend);
++  if (backend->terminal != NULL)
++    ply_terminal_stop_watching_for_active_vt_change (backend->terminal,
++                                                     (ply_terminal_active_vt_changed_handler_t)
++                                                     on_active_vt_changed,
++                                                     backend);
+   uninitialize_head (backend, &backend->head);
+   close (backend->device_fd);
+@@ -546,15 +550,22 @@ map_to_device (ply_renderer_backend_t *backend)
+       return false;
+     }
+-  if (ply_terminal_is_active (backend->terminal))
++  if (backend->terminal != NULL)
+     {
+-      ply_trace ("already on right vt, activating");
+-      activate (backend);
++      if (ply_terminal_is_active (backend->terminal))
++        {
++          ply_trace ("already on right vt, activating");
++          activate (backend);
++        }
++      else
++        {
++          ply_trace ("on wrong vt, changing vts");
++          ply_terminal_activate_vt (backend->terminal);
++        }
+     }
+   else
+     {
+-      ply_trace ("on wrong vt, changing vts");
+-      ply_terminal_activate_vt (backend->terminal);
++      activate (backend);
+     }
+   return true;
+@@ -590,8 +601,11 @@ flush_head (ply_renderer_backend_t *backend,
+   if (!backend->is_active)
+     return;
+-  ply_terminal_set_mode (backend->terminal, PLY_TERMINAL_MODE_GRAPHICS);
+-  ply_terminal_set_unbuffered_input (backend->terminal);
++  if (backend->terminal != NULL)
++    {
++      ply_terminal_set_mode (backend->terminal, PLY_TERMINAL_MODE_GRAPHICS);
++      ply_terminal_set_unbuffered_input (backend->terminal);
++    }
+   pixel_buffer = head->pixel_buffer;
+   updated_region = ply_pixel_buffer_get_updated_areas (pixel_buffer);
+   areas_to_flush = ply_region_get_sorted_rectangle_list (updated_region);
+@@ -685,6 +699,9 @@ open_input_source (ply_renderer_backend_t      *backend,
+   assert (backend != NULL);
+   assert (has_input_source (backend, input_source));
++  if (backend->terminal == NULL)
++    return false;
++
+   terminal_fd = ply_terminal_get_fd (backend->terminal);
+   input_source->backend = backend;
+@@ -715,6 +732,9 @@ close_input_source (ply_renderer_backend_t      *backend,
+   assert (backend != NULL);
+   assert (has_input_source (backend, input_source));
++  if (backend->terminal == NULL)
++    return;
++
+   ply_event_loop_stop_watching_fd (backend->loop, input_source->terminal_input_watch);
+   input_source->terminal_input_watch = NULL;
+   input_source->backend = NULL;
+diff --git a/src/plugins/renderers/x11/Makefile.am b/src/plugins/renderers/x11/Makefile.am
+index fd142c0..33513ac 100644
+--- a/src/plugins/renderers/x11/Makefile.am
++++ b/src/plugins/renderers/x11/Makefile.am
+@@ -1,4 +1,4 @@
+-INCLUDES = -I$(top_srcdir)                                                    \
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
+            -I$(srcdir)/../../../libply                                        \
+            -I$(srcdir)/../../../libply-splash-core                            \
+            -I$(srcdir)/../../..                                               \
+diff --git a/src/plugins/splash/Makefile.am b/src/plugins/splash/Makefile.am
+index 02f94fa..a19197b 100644
+--- a/src/plugins/splash/Makefile.am
++++ b/src/plugins/splash/Makefile.am
+@@ -1,2 +1,2 @@
+-SUBDIRS = throbgress fade-throbber text details space-flares two-step script
++SUBDIRS = throbgress fade-throbber text details space-flares two-step script tribar
+ MAINTAINERCLEANFILES = Makefile.in
+diff --git a/src/plugins/splash/details/Makefile.am b/src/plugins/splash/details/Makefile.am
+index a656129..3be4755 100644
+--- a/src/plugins/splash/details/Makefile.am
++++ b/src/plugins/splash/details/Makefile.am
+@@ -1,4 +1,4 @@
+-INCLUDES = -I$(top_srcdir)                                                    \
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
+            -I$(srcdir)/../../../libply                                        \
+            -I$(srcdir)/../../../libply-splash-core                            \
+            -I$(srcdir)/../../..                                               \
+diff --git a/src/plugins/splash/fade-throbber/Makefile.am b/src/plugins/splash/fade-throbber/Makefile.am
+index f7b559b..6bbb490 100644
+--- a/src/plugins/splash/fade-throbber/Makefile.am
++++ b/src/plugins/splash/fade-throbber/Makefile.am
+@@ -1,4 +1,4 @@
+-INCLUDES = -I$(top_srcdir)                                                    \
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
+            -I$(srcdir)/../../../libply                                        \
+            -I$(srcdir)/../../../libply-splash-core                            \
+            -I$(srcdir)/../../../libply-splash-graphics                        \
+diff --git a/src/plugins/splash/script/Makefile.am b/src/plugins/splash/script/Makefile.am
+index 0f2b0f7..ce46df6 100644
+--- a/src/plugins/splash/script/Makefile.am
++++ b/src/plugins/splash/script/Makefile.am
+@@ -1,4 +1,4 @@
+-INCLUDES = -I$(top_srcdir)                                                    \
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
+            -I$(srcdir)/../../../libply                                        \
+            -I$(srcdir)/../../../libply-splash-core                            \
+            -I$(srcdir)/../../../libply-splash-graphics                        \
+diff --git a/src/plugins/splash/script/script-debug.c b/src/plugins/splash/script/script-debug.c
+index 355c2b2..118574b 100644
+--- a/src/plugins/splash/script/script-debug.c
++++ b/src/plugins/splash/script/script-debug.c
+@@ -19,6 +19,10 @@
+  *
+  * Written by: Charlie Brej <cbrej@cs.man.ac.uk>
+  */
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
+ #include "ply-hashtable.h"
+ #include <stdlib.h>
+ #include <string.h>
+diff --git a/src/plugins/splash/script/script-execute.c b/src/plugins/splash/script/script-execute.c
+index 6abd3a6..c06959b 100644
+--- a/src/plugins/splash/script/script-execute.c
++++ b/src/plugins/splash/script/script-execute.c
+@@ -19,7 +19,11 @@
+  *
+  * Written by: Charlie Brej <cbrej@cs.man.ac.uk>
+  */
+-#define _GNU_SOURCE
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
+ #include "ply-hashtable.h"
+ #include "ply-list.h"
+ #include "ply-logger.h"
+diff --git a/src/plugins/splash/script/script-lib-image.c b/src/plugins/splash/script/script-lib-image.c
+index 5be27fb..f08be31 100644
+--- a/src/plugins/splash/script/script-lib-image.c
++++ b/src/plugins/splash/script/script-lib-image.c
+@@ -19,7 +19,9 @@
+  *
+  * Written by: Charlie Brej <cbrej@cs.man.ac.uk>
+  */
+-#define _GNU_SOURCE
++
++#include "config.h"
++
+ #include "ply-image.h"
+ #include "ply-label.h"
+ #include "ply-pixel-buffer.h"
+@@ -36,8 +38,6 @@
+ #include <stdlib.h>
+ #include <string.h>
+-#include "config.h"
+-
+ #include "script-lib-image.script.h"
+ static void image_free (script_obj_t *obj)
+diff --git a/src/plugins/splash/script/script-lib-math.c b/src/plugins/splash/script/script-lib-math.c
+index a1afc04..3f2dc79 100644
+--- a/src/plugins/splash/script/script-lib-math.c
++++ b/src/plugins/splash/script/script-lib-math.c
+@@ -19,7 +19,10 @@
+  *
+  * Written by: Charlie Brej <cbrej@cs.man.ac.uk>
+  */
+-#define _GNU_SOURCE
++
++#include "config.h"
++
++#include "ply-utils.h"
+ #include "script.h"
+ #include "script-parse.h"
+ #include "script-execute.h"
+@@ -31,7 +34,6 @@
+ #include <string.h>
+ #include <math.h>
+-#include "config.h"
+ #include "script-lib-math.script.h"
+diff --git a/src/plugins/splash/script/script-lib-plymouth.c b/src/plugins/splash/script/script-lib-plymouth.c
+index 5c648a6..ab2ec44 100644
+--- a/src/plugins/splash/script/script-lib-plymouth.c
++++ b/src/plugins/splash/script/script-lib-plymouth.c
+@@ -19,7 +19,9 @@
+  *
+  * Written by: Charlie Brej <cbrej@cs.man.ac.uk>
+  */
+-#define _GNU_SOURCE
++
++#include "config.h"
++
+ #include "ply-boot-splash-plugin.h"
+ #include "ply-utils.h"
+ #include "script.h"
+@@ -32,8 +34,6 @@
+ #include <stdlib.h>
+ #include <string.h>
+-#include "config.h"
+-
+ #include "script-lib-plymouth.script.h"
+ static script_return_t plymouth_set_function (script_state_t *state,
+@@ -64,6 +64,7 @@ static script_return_t plymouth_get_mode (script_state_t *state,
+       case PLY_BOOT_SPLASH_MODE_UPDATES:
+         obj = script_obj_new_string ("updates");
+         break;
++      case PLY_BOOT_SPLASH_MODE_INVALID:
+       default:
+         obj = script_obj_new_string ("unknown");
+         break;
+diff --git a/src/plugins/splash/script/script-lib-string.c b/src/plugins/splash/script/script-lib-string.c
+index dbd63fe..0b836eb 100644
+--- a/src/plugins/splash/script/script-lib-string.c
++++ b/src/plugins/splash/script/script-lib-string.c
+@@ -19,7 +19,9 @@
+  *
+  * Written by: Charlie Brej <cbrej@cs.man.ac.uk>
+  */
+-#define _GNU_SOURCE
++
++#include "config.h"
++
+ #include "script.h"
+ #include "script-parse.h"
+ #include "script-execute.h"
+@@ -31,8 +33,6 @@
+ #include <stdlib.h>
+ #include <string.h>
+-#include "config.h"
+-
+ #include "script-lib-string.script.h"
+diff --git a/src/plugins/splash/script/script-object.c b/src/plugins/splash/script/script-object.c
+index 465fef6..7c16c94 100644
+--- a/src/plugins/splash/script/script-object.c
++++ b/src/plugins/splash/script/script-object.c
+@@ -19,7 +19,11 @@
+  *
+  * Written by: Charlie Brej <cbrej@cs.man.ac.uk>
+  */
+-#define _GNU_SOURCE
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
+ #include "ply-hashtable.h"
+ #include "ply-list.h"
+ #include "ply-bitarray.h"
+diff --git a/src/plugins/splash/script/script-parse.c b/src/plugins/splash/script/script-parse.c
+index 10eb667..4adf273 100644
+--- a/src/plugins/splash/script/script-parse.c
++++ b/src/plugins/splash/script/script-parse.c
+@@ -19,7 +19,11 @@
+  *
+  * Written by: Charlie Brej <cbrej@cs.man.ac.uk>
+  */
+-#define _GNU_SOURCE
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
+ #include "ply-hashtable.h"
+ #include "ply-list.h"
+ #include "ply-bitarray.h"
+diff --git a/src/plugins/splash/script/script-scan.c b/src/plugins/splash/script/script-scan.c
+index ead752f..5d1aa64 100644
+--- a/src/plugins/splash/script/script-scan.c
++++ b/src/plugins/splash/script/script-scan.c
+@@ -19,6 +19,10 @@
+  *
+  * Written by: Charlie Brej <cbrej@cs.man.ac.uk>
+  */
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <fcntl.h>
+@@ -26,6 +30,7 @@
+ #include <stdbool.h>
+ #include <unistd.h>
+ #include <string.h>
++#include <limits.h>
+ #include "ply-bitarray.h"
+ #include "script-scan.h"
+@@ -61,7 +66,7 @@ static script_scan_t *script_scan_new (void)
+ script_scan_t *script_scan_file (const char *filename)
+ {
+-  int fd = open (filename, O_RDONLY);
++  int fd = open (filename, O_RDONLY|O_CLOEXEC);
+   if (fd < 0) return NULL;
+   script_scan_t *scan = script_scan_new ();
+   scan->name = strdup (filename);
+@@ -367,11 +372,13 @@ static script_scan_token_t *script_scan_peek_token (script_scan_t *scan,
+ {
+   int i;
+-  if (scan->tokencount <= n)
++  /* we're screwed long before we ever actually hit INT_MAX; but at least
++   * we shouldn't get ourselves stuck in an infinite loop. */
++  if (scan->tokencount <= n && n < INT_MAX)
+     {
+       scan->tokens =
+         realloc (scan->tokens, (n + 1) * sizeof (script_scan_token_t *));
+-      for (i = scan->tokencount; i <= n; i++)                                   /* FIXME warning about possibely inifnite loop */
++      for (i = scan->tokencount; i <= n; i++)
+         {
+           scan->tokens[i] = malloc (sizeof (script_scan_token_t));
+           scan->tokens[i]->type = SCRIPT_SCAN_TOKEN_TYPE_EMPTY;
+diff --git a/src/plugins/splash/script/script.c b/src/plugins/splash/script/script.c
+index 635a8b4..3290825 100644
+--- a/src/plugins/splash/script/script.c
++++ b/src/plugins/splash/script/script.c
+@@ -19,7 +19,11 @@
+  *
+  * Written by: Charlie Brej <cbrej@cs.man.ac.uk>
+  */
+-#define _GNU_SOURCE
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
+ #include "ply-hashtable.h"
+ #include "ply-list.h"
+ #include "ply-bitarray.h"
+diff --git a/src/plugins/splash/space-flares/Makefile.am b/src/plugins/splash/space-flares/Makefile.am
+index 0d22a2e..24fdb39 100644
+--- a/src/plugins/splash/space-flares/Makefile.am
++++ b/src/plugins/splash/space-flares/Makefile.am
+@@ -1,4 +1,4 @@
+-INCLUDES = -I$(top_srcdir)                                                    \
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
+            -I$(srcdir)/../../../libply                                        \
+            -I$(srcdir)/../../../libply-splash-core                            \
+            -I$(srcdir)/../../../libply-splash-graphics                        \
+diff --git a/src/plugins/splash/text/Makefile.am b/src/plugins/splash/text/Makefile.am
+index f4c21a8..7ccefb2 100644
+--- a/src/plugins/splash/text/Makefile.am
++++ b/src/plugins/splash/text/Makefile.am
+@@ -1,4 +1,4 @@
+-INCLUDES = -I$(top_srcdir)                                                    \
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
+            -I$(srcdir)/../../../libply                                        \
+            -I$(srcdir)/../../../libply-splash-core                            \
+            -I$(srcdir)/../../..                                               \
+diff --git a/src/plugins/splash/text/plugin.c b/src/plugins/splash/text/plugin.c
+index af81635..fb97c14 100644
+--- a/src/plugins/splash/text/plugin.c
++++ b/src/plugins/splash/text/plugin.c
+@@ -1,6 +1,5 @@
+-/* text.c - boot splash plugin
+- *
+- * Copyright (C) 2008 Red Hat, Inc.
++/*
++ * Copyright (C) 2008-2012 Red Hat, Inc.
+  *
+  * 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
+@@ -17,8 +16,6 @@
+  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+  * 02111-1307, USA.
+  *
+- * Written by: Adam Jackson <ajax@redhat.com>
+- *             Ray Strode <rstrode@redhat.com>
+  */
+ #include "config.h"
+@@ -49,7 +46,7 @@
+ #include "ply-list.h"
+ #include "ply-logger.h"
+ #include "ply-text-display.h"
+-#include "ply-text-progress-bar.h"
++#include "ply-text-step-bar.h"
+ #include "ply-utils.h"
+ #include <linux/kd.h>
+@@ -78,7 +75,7 @@ typedef struct
+ {
+   ply_boot_splash_plugin_t *plugin;
+   ply_text_display_t *display;
+-  ply_text_progress_bar_t *progress_bar;
++  ply_text_step_bar_t *step_bar;
+ } view_t;
+@@ -97,7 +94,7 @@ view_new (ply_boot_splash_plugin_t *plugin,
+   view->plugin = plugin;
+   view->display = display;
+-  view->progress_bar = ply_text_progress_bar_new ();
++  view->step_bar = ply_text_step_bar_new ();
+   return view;
+ }
+@@ -105,7 +102,7 @@ view_new (ply_boot_splash_plugin_t *plugin,
+ static void
+ view_free (view_t *view)
+ {
+-  ply_text_progress_bar_free (view->progress_bar);
++  ply_text_step_bar_free (view->step_bar);
+   free (view);
+ }
+@@ -180,10 +177,10 @@ view_start_animation (view_t *view)
+                                     0xffffff);
+   ply_terminal_set_color_hex_value (terminal,
+                                     PLY_TERMINAL_COLOR_BLUE,
+-                                    0x0073B3);
++                                    0x3465a4);
+   ply_terminal_set_color_hex_value (terminal,
+                                     PLY_TERMINAL_COLOR_BROWN,
+-                                    0x00457E);
++                                    0x979a9b);
+   ply_text_display_set_background_color (view->display,
+                                          PLY_TERMINAL_COLOR_BLACK);
+@@ -192,11 +189,11 @@ view_start_animation (view_t *view)
+   if (plugin->mode == PLY_BOOT_SPLASH_MODE_SHUTDOWN)
+     {
+-      ply_text_progress_bar_hide (view->progress_bar);
++      ply_text_step_bar_hide (view->step_bar);
+       return;
+     }
+-  ply_text_progress_bar_show (view->progress_bar,
++  ply_text_step_bar_show (view->step_bar,
+                               view->display);
+ }
+@@ -452,7 +449,7 @@ stop_animation (ply_boot_splash_plugin_t *plugin)
+       view = ply_list_node_get_data (node);
+       next_node = ply_list_get_next_node (plugin->views, node);
+-      ply_text_progress_bar_hide (view->progress_bar);
++      ply_text_step_bar_hide (view->step_bar);
+       node = next_node;
+     }
+@@ -571,8 +568,8 @@ on_boot_progress (ply_boot_splash_plugin_t *plugin,
+       view = ply_list_node_get_data (node);
+       next_node = ply_list_get_next_node (plugin->views, node);
+-      ply_text_progress_bar_set_percent_done (view->progress_bar, percent_done);
+-      ply_text_progress_bar_draw (view->progress_bar);
++      ply_text_step_bar_set_percent_done (view->step_bar, percent_done);
++      ply_text_step_bar_draw (view->step_bar);
+       node = next_node;
+     }
+diff --git a/src/plugins/splash/throbgress/Makefile.am b/src/plugins/splash/throbgress/Makefile.am
+index 8f93fd2..2ac1b0c 100644
+--- a/src/plugins/splash/throbgress/Makefile.am
++++ b/src/plugins/splash/throbgress/Makefile.am
+@@ -1,4 +1,4 @@
+-INCLUDES = -I$(top_srcdir)                                                    \
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
+            -I$(srcdir)/../../../libply                                        \
+            -I$(srcdir)/../../../libply-splash-core                            \
+            -I$(srcdir)/../../../libply-splash-graphics                        \
+diff --git a/src/plugins/splash/throbgress/plugin.c b/src/plugins/splash/throbgress/plugin.c
+index 5ed6c06..fba809b 100644
+--- a/src/plugins/splash/throbgress/plugin.c
++++ b/src/plugins/splash/throbgress/plugin.c
+@@ -247,6 +247,8 @@ pause_views (ply_boot_splash_plugin_t *plugin)
+ {
+   ply_list_node_t *node;
++  ply_trace ("pausing views");
++
+   node = ply_list_get_first_node (plugin->views);
+   while (node != NULL)
+     {
+@@ -267,6 +269,8 @@ unpause_views (ply_boot_splash_plugin_t *plugin)
+ {
+   ply_list_node_t *node;
++  ply_trace ("unpausing views");
++
+   node = ply_list_get_first_node (plugin->views);
+   while (node != NULL)
+     {
+@@ -431,6 +435,8 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin)
+   if (plugin == NULL)
+     return;
++  ply_trace ("destroying plugin");
++
+   if (plugin->loop != NULL)
+     {
+       ply_event_loop_stop_watching_for_exit (plugin->loop, (ply_event_loop_exit_handler_t)
+@@ -510,6 +516,8 @@ start_animation (ply_boot_splash_plugin_t *plugin)
+   if (plugin->is_animating)
+      return;
++  ply_trace ("starting animation");
++
+   node = ply_list_get_first_node (plugin->views);
+   while (node != NULL)
+     {
+@@ -542,6 +550,9 @@ stop_animation (ply_boot_splash_plugin_t *plugin,
+   if (!plugin->is_animating)
+      return;
++  ply_trace ("stopping animation%s",
++             trigger != NULL? " with trigger" : "");
++
+   plugin->is_animating = false;
+   node = ply_list_get_first_node (plugin->views);
+@@ -619,6 +630,7 @@ add_pixel_display (ply_boot_splash_plugin_t *plugin,
+ {
+   view_t *view;
++  ply_trace ("adding pixel display to plugin");
+   view = view_new (plugin, display);
+   ply_pixel_display_set_draw_handler (view->display,
+@@ -634,6 +646,7 @@ remove_pixel_display (ply_boot_splash_plugin_t *plugin,
+ {
+   ply_list_node_t *node;
++  ply_trace ("removing pixel display from plugin");
+   node = ply_list_get_first_node (plugin->views);
+   while (node != NULL)
+     {
+@@ -745,6 +758,7 @@ hide_splash_screen (ply_boot_splash_plugin_t *plugin,
+ {
+   assert (plugin != NULL);
++  ply_trace ("hiding splash");
+   if (plugin->loop != NULL)
+     {
+       stop_animation (plugin, NULL);
+@@ -765,6 +779,7 @@ show_password_prompt (ply_boot_splash_plugin_t *plugin,
+ {
+   ply_list_node_t *node;
++  ply_trace ("showing password prompt");
+   node = ply_list_get_first_node (plugin->views);
+   while (node != NULL)
+     {
+@@ -788,6 +803,7 @@ show_prompt (ply_boot_splash_plugin_t *plugin,
+ {
+   ply_list_node_t *node;
++  ply_trace ("showing prompt");
+   node = ply_list_get_first_node (plugin->views);
+   while (node != NULL)
+     {
+@@ -807,6 +823,7 @@ show_prompt (ply_boot_splash_plugin_t *plugin,
+ static void
+ on_root_mounted (ply_boot_splash_plugin_t *plugin)
+ {
++  ply_trace ("root filesystem mounted");
+   plugin->root_is_mounted = true;
+ }
+@@ -814,8 +831,10 @@ static void
+ become_idle (ply_boot_splash_plugin_t *plugin,
+              ply_trigger_t            *idle_trigger)
+ {
++  ply_trace ("deactivation requested");
+   if (plugin->is_idle)
+     {
++      ply_trace ("plugin is already idle");
+       ply_trigger_pull (idle_trigger, NULL);
+       return;
+     }
+@@ -829,6 +848,7 @@ hide_prompt (ply_boot_splash_plugin_t *plugin)
+ {
+   ply_list_node_t *node;
++  ply_trace ("hiding prompt");
+   node = ply_list_get_first_node (plugin->views);
+   while (node != NULL)
+     {
+@@ -844,6 +864,7 @@ hide_prompt (ply_boot_splash_plugin_t *plugin)
+     }
+ }
++
+ static void
+ show_message (ply_boot_splash_plugin_t *plugin,
+               const char               *message)
+diff --git a/src/plugins/splash/tribar/Makefile.am b/src/plugins/splash/tribar/Makefile.am
+new file mode 100644
+index 0000000..9b11502
+--- /dev/null
++++ b/src/plugins/splash/tribar/Makefile.am
+@@ -0,0 +1,23 @@
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
++           -I$(srcdir)/../../../libply                                        \
++           -I$(srcdir)/../../../libply-splash-core                            \
++           -I$(srcdir)/../../..                                               \
++           -I$(srcdir)/../..                                                  \
++           -I$(srcdir)/..                                                     \
++           -I$(srcdir)
++
++plugindir = $(libdir)/plymouth
++plugin_LTLIBRARIES = tribar.la
++
++tribar_la_CFLAGS = $(PLYMOUTH_CFLAGS)                                           \
++                 -DPLYMOUTH_BACKGROUND_COLOR=$(background_color)              \
++                 -DPLYMOUTH_BACKGROUND_END_COLOR=$(background_end_color)      \
++                 -DPLYMOUTH_BACKGROUND_START_COLOR=$(background_start_color)
++
++tribar_la_LDFLAGS = -module -avoid-version -export-dynamic
++tribar_la_LIBADD = $(PLYMOUTH_LIBS)                                            \
++                 ../../../libply/libply.la                                   \
++                 ../../../libply-splash-core/libply-splash-core.la
++tribar_la_SOURCES = $(srcdir)/plugin.c
++
++MAINTAINERCLEANFILES = Makefile.in
+diff --git a/src/plugins/splash/tribar/plugin.c b/src/plugins/splash/tribar/plugin.c
+new file mode 100644
+index 0000000..4458bad
+--- /dev/null
++++ b/src/plugins/splash/tribar/plugin.c
+@@ -0,0 +1,740 @@
++/*
++ *
++ * Copyright (C) 2008 Red Hat, Inc.
++ *
++ * 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, 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, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
++ * 02111-1307, USA.
++ *
++ * Written by: Adam Jackson <ajax@redhat.com>
++ *             Ray Strode <rstrode@redhat.com>
++ */
++#include "config.h"
++
++#include <assert.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <math.h>
++#include <signal.h>
++#include <stdbool.h>
++#include <stdio.h>
++#include <stdint.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/ioctl.h>
++#include <sys/stat.h>
++#include <sys/time.h>
++#include <sys/types.h>
++#include <termios.h>
++#include <unistd.h>
++#include <values.h>
++#include <wchar.h>
++
++#include "ply-trigger.h"
++#include "ply-boot-splash-plugin.h"
++#include "ply-buffer.h"
++#include "ply-event-loop.h"
++#include "ply-key-file.h"
++#include "ply-list.h"
++#include "ply-logger.h"
++#include "ply-text-display.h"
++#include "ply-text-progress-bar.h"
++#include "ply-utils.h"
++
++#include <linux/kd.h>
++
++typedef enum {
++   PLY_BOOT_SPLASH_DISPLAY_NORMAL,
++   PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY,
++   PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY
++} ply_boot_splash_display_type_t;
++
++struct _ply_boot_splash_plugin
++{
++  ply_event_loop_t *loop;
++  ply_boot_splash_mode_t mode;
++
++  ply_list_t *views;
++
++  ply_boot_splash_display_type_t state;
++
++  char *message;
++
++  uint32_t is_animating : 1;
++};
++
++typedef struct
++{
++  ply_boot_splash_plugin_t *plugin;
++  ply_text_display_t *display;
++  ply_text_progress_bar_t *progress_bar;
++
++} view_t;
++
++ply_boot_splash_plugin_interface_t *ply_boot_splash_plugin_get_interface (void);
++
++static void hide_splash_screen (ply_boot_splash_plugin_t *plugin,
++                                ply_event_loop_t         *loop);
++
++static view_t *
++view_new (ply_boot_splash_plugin_t *plugin,
++          ply_text_display_t       *display)
++{
++  view_t *view;
++
++  view = calloc (1, sizeof (view_t));
++  view->plugin = plugin;
++  view->display = display;
++
++  view->progress_bar = ply_text_progress_bar_new ();
++
++  return view;
++}
++
++static void
++view_free (view_t *view)
++{
++  ply_text_progress_bar_free (view->progress_bar);
++
++  free (view);
++}
++
++static void
++view_show_message (view_t *view)
++{
++  ply_boot_splash_plugin_t *plugin;
++  int display_width, display_height;
++
++  plugin = view->plugin;
++
++  display_width = ply_text_display_get_number_of_columns (view->display);
++  display_height = ply_text_display_get_number_of_rows (view->display);
++
++  ply_text_display_set_cursor_position (view->display, 0,
++                                        display_height / 2);
++  ply_text_display_clear_line (view->display);
++  ply_text_display_set_cursor_position (view->display,
++                                        (display_width -
++                                        strlen (plugin->message)) / 2,
++                                        display_height / 2);
++
++  ply_text_display_write (view->display, "%s", plugin->message);
++}
++
++static void
++view_show_prompt (view_t     *view,
++                  const char *prompt,
++                  const char *entered_text)
++{
++
++  int display_width, display_height;
++  int i;
++
++  display_width = ply_text_display_get_number_of_columns (view->display);
++  display_height = ply_text_display_get_number_of_rows (view->display);
++  ply_text_display_set_background_color (view->display, PLY_TERMINAL_COLOR_DEFAULT);
++  ply_text_display_clear_screen (view->display);
++
++  ply_text_display_set_cursor_position (view->display, 0, display_height / 2);
++
++  for (i=0; i < display_width; i++)
++    ply_text_display_write (view->display, "%c", ' ');
++
++  ply_text_display_set_cursor_position (view->display,
++                                        display_width / 2 - (strlen (prompt)),
++                                        display_height / 2);
++
++  ply_text_display_write (view->display, "%s:%s", prompt, entered_text);
++
++  ply_text_display_show_cursor (view->display);
++}
++
++static void
++view_start_animation (view_t *view)
++{
++  ply_boot_splash_plugin_t *plugin;
++  ply_terminal_t *terminal;
++
++  assert (view != NULL);
++
++  plugin = view->plugin;
++
++  terminal = ply_text_display_get_terminal (view->display);
++
++  ply_terminal_set_color_hex_value (terminal,
++                                    PLY_TERMINAL_COLOR_BLACK,
++                                    0x000000);
++  ply_terminal_set_color_hex_value (terminal,
++                                    PLY_TERMINAL_COLOR_WHITE,
++                                    0xffffff);
++  ply_terminal_set_color_hex_value (terminal,
++                                    PLY_TERMINAL_COLOR_BLUE,
++                                    0x0073B3);
++  ply_terminal_set_color_hex_value (terminal,
++                                    PLY_TERMINAL_COLOR_BROWN,
++                                    0x00457E);
++
++  ply_text_display_set_background_color (view->display,
++                                         PLY_TERMINAL_COLOR_BLACK);
++  ply_text_display_clear_screen (view->display);
++  ply_text_display_hide_cursor (view->display);
++
++  if (plugin->mode == PLY_BOOT_SPLASH_MODE_SHUTDOWN)
++    {
++      ply_text_progress_bar_hide (view->progress_bar);
++      return;
++    }
++
++  ply_text_progress_bar_show (view->progress_bar,
++                              view->display);
++}
++
++static void
++view_redraw (view_t *view)
++{
++  unsigned long screen_width, screen_height;
++
++  screen_width = ply_text_display_get_number_of_columns (view->display);
++  screen_height = ply_text_display_get_number_of_rows (view->display);
++
++  ply_text_display_draw_area (view->display, 0, 0,
++                              screen_width, screen_height);
++}
++
++static void
++redraw_views (ply_boot_splash_plugin_t *plugin)
++{
++  ply_list_node_t *node;
++
++  node = ply_list_get_first_node (plugin->views);
++  while (node != NULL)
++    {
++      ply_list_node_t *next_node;
++      view_t *view;
++
++      view = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (plugin->views, node);
++
++      view_redraw (view);
++
++      node = next_node;
++    }
++}
++
++static void
++view_hide (view_t *view)
++{
++  if (view->display != NULL)
++    {
++      ply_terminal_t *terminal;
++
++      terminal = ply_text_display_get_terminal (view->display);
++
++      ply_text_display_set_background_color (view->display, PLY_TERMINAL_COLOR_DEFAULT);
++      ply_text_display_clear_screen (view->display);
++      ply_text_display_show_cursor (view->display);
++
++      ply_terminal_reset_colors (terminal);
++    }
++}
++
++static void
++hide_views (ply_boot_splash_plugin_t *plugin)
++{
++  ply_list_node_t *node;
++
++  node = ply_list_get_first_node (plugin->views);
++  while (node != NULL)
++    {
++      ply_list_node_t *next_node;
++      view_t *view;
++
++      view = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (plugin->views, node);
++
++      view_hide (view);
++
++      node = next_node;
++    }
++}
++
++static void
++pause_views (ply_boot_splash_plugin_t *plugin)
++{
++  ply_list_node_t *node;
++
++  node = ply_list_get_first_node (plugin->views);
++  while (node != NULL)
++    {
++      ply_list_node_t *next_node;
++      view_t *view;
++
++      view = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (plugin->views, node);
++
++      ply_text_display_pause_updates (view->display);
++
++      node = next_node;
++    }
++}
++
++static void
++unpause_views (ply_boot_splash_plugin_t *plugin)
++{
++  ply_list_node_t *node;
++
++  node = ply_list_get_first_node (plugin->views);
++  while (node != NULL)
++    {
++      ply_list_node_t *next_node;
++      view_t *view;
++
++      view = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (plugin->views, node);
++
++      ply_text_display_unpause_updates (view->display);
++
++      node = next_node;
++    }
++}
++
++static ply_boot_splash_plugin_t *
++create_plugin (ply_key_file_t *key_file)
++{
++  ply_boot_splash_plugin_t *plugin;
++
++  ply_trace ("creating plugin");
++
++  plugin = calloc (1, sizeof (ply_boot_splash_plugin_t));
++  plugin->message = NULL;
++
++  plugin->views = ply_list_new ();
++
++  return plugin;
++}
++
++static void
++detach_from_event_loop (ply_boot_splash_plugin_t *plugin)
++{
++  plugin->loop = NULL;
++
++  ply_trace ("detaching from event loop");
++}
++
++static void
++free_views (ply_boot_splash_plugin_t *plugin)
++{
++  ply_list_node_t *node;
++
++  node = ply_list_get_first_node (plugin->views);
++
++  while (node != NULL)
++    {
++      ply_list_node_t *next_node;
++      view_t *view;
++
++      view = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (plugin->views, node);
++
++      view_free (view);
++      ply_list_remove_node (plugin->views, node);
++
++      node = next_node;
++    }
++
++  ply_list_free (plugin->views);
++  plugin->views = NULL;
++}
++
++static void
++destroy_plugin (ply_boot_splash_plugin_t *plugin)
++{
++  ply_trace ("destroying plugin");
++
++  if (plugin == NULL)
++    return;
++
++  /* It doesn't ever make sense to keep this plugin on screen
++   * after exit
++   */
++  hide_splash_screen (plugin, plugin->loop);
++
++  free_views (plugin);
++  if (plugin->message != NULL)
++    free (plugin->message);
++
++  free (plugin);
++}
++
++static void
++show_message (ply_boot_splash_plugin_t *plugin)
++{
++  ply_list_node_t *node;
++
++  node = ply_list_get_first_node (plugin->views);
++  while (node != NULL)
++    {
++      ply_list_node_t *next_node;
++      view_t *view;
++
++      view = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (plugin->views, node);
++
++      view_show_message (view);
++
++      node = next_node;
++    }
++}
++
++static void
++start_animation (ply_boot_splash_plugin_t *plugin)
++{
++  ply_list_node_t *node;
++
++  assert (plugin != NULL);
++  assert (plugin->loop != NULL);
++
++  redraw_views (plugin);
++
++  if (plugin->message != NULL)
++    show_message (plugin);
++
++  if (plugin->is_animating)
++     return;
++
++  node = ply_list_get_first_node (plugin->views);
++  while (node != NULL)
++    {
++      ply_list_node_t *next_node;
++      view_t *view;
++
++      view = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (plugin->views, node);
++
++      view_start_animation (view);
++
++      node = next_node;
++    }
++
++  plugin->is_animating = true;
++}
++
++static void
++stop_animation (ply_boot_splash_plugin_t *plugin)
++{
++  ply_list_node_t *node;
++
++  assert (plugin != NULL);
++  assert (plugin->loop != NULL);
++
++  if (!plugin->is_animating)
++     return;
++
++  plugin->is_animating = false;
++
++  node = ply_list_get_first_node (plugin->views);
++  while (node != NULL)
++    {
++      ply_list_node_t *next_node;
++      view_t *view;
++
++      view = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (plugin->views, node);
++
++      ply_text_progress_bar_hide (view->progress_bar);
++
++      node = next_node;
++    }
++  redraw_views (plugin);
++}
++
++static void
++on_draw (view_t                   *view,
++         ply_terminal_t           *terminal,
++         int                       x,
++         int                       y,
++         int                       width,
++         int                       height)
++{
++  ply_text_display_clear_screen (view->display);
++}
++
++static void
++add_text_display (ply_boot_splash_plugin_t *plugin,
++                  ply_text_display_t       *display)
++{
++  view_t *view;
++  ply_terminal_t *terminal;
++
++  view = view_new (plugin, display);
++
++  terminal = ply_text_display_get_terminal (view->display);
++  if (ply_terminal_open (terminal))
++    ply_terminal_activate_vt (terminal);
++
++  ply_text_display_set_draw_handler (view->display,
++                                     (ply_text_display_draw_handler_t)
++                                     on_draw, view);
++
++  ply_list_append_data (plugin->views, view);
++}
++
++static void
++remove_text_display (ply_boot_splash_plugin_t *plugin,
++                     ply_text_display_t       *display)
++{
++  ply_list_node_t *node;
++
++  node = ply_list_get_first_node (plugin->views);
++  while (node != NULL)
++    {
++      view_t *view;
++      ply_list_node_t *next_node;
++
++      view = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (plugin->views, node);
++
++      if (view->display == display)
++        {
++          ply_text_display_set_draw_handler (view->display,
++                                             NULL, NULL);
++          view_free (view);
++          ply_list_remove_node (plugin->views, node);
++          return;
++        }
++
++      node = next_node;
++    }
++}
++
++static bool
++show_splash_screen (ply_boot_splash_plugin_t *plugin,
++                    ply_event_loop_t         *loop,
++                    ply_buffer_t             *boot_buffer,
++                    ply_boot_splash_mode_t    mode)
++{
++  assert (plugin != NULL);
++
++  plugin->loop = loop;
++  plugin->mode = mode;
++  ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t)
++                                 detach_from_event_loop,
++                                 plugin);
++
++  ply_show_new_kernel_messages (false);
++  start_animation (plugin);
++
++  return true;
++}
++
++static void
++update_status (ply_boot_splash_plugin_t *plugin,
++               const char               *status)
++{
++  assert (plugin != NULL);
++
++  ply_trace ("status update");
++}
++
++static void
++on_boot_progress (ply_boot_splash_plugin_t *plugin,
++                  double                    duration,
++                  double                    percent_done)
++{
++  ply_list_node_t *node;
++  double total_duration;
++
++  total_duration = duration / percent_done;
++
++  /* Fun made-up smoothing function to make the growth asymptotic:
++   * fraction(time,estimate)=1-2^(-(time^1.45)/estimate) */
++  percent_done = 1.0 - pow (2.0, -pow (duration, 1.45) / total_duration) * (1.0 - percent_done);
++
++  node = ply_list_get_first_node (plugin->views);
++
++  while (node != NULL)
++    {
++      ply_list_node_t *next_node;
++      view_t *view;
++
++      view = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (plugin->views, node);
++
++      ply_text_progress_bar_set_percent_done (view->progress_bar, percent_done);
++      ply_text_progress_bar_draw (view->progress_bar);
++
++      node = next_node;
++    }
++}
++
++static void
++hide_splash_screen (ply_boot_splash_plugin_t *plugin,
++                    ply_event_loop_t         *loop)
++{
++  assert (plugin != NULL);
++
++  ply_trace ("hiding splash screen");
++
++  if (plugin->loop != NULL)
++    {
++      stop_animation (plugin);
++
++      ply_event_loop_stop_watching_for_exit (plugin->loop,
++                                             (ply_event_loop_exit_handler_t)
++                                             detach_from_event_loop,
++                                             plugin);
++      detach_from_event_loop (plugin);
++    }
++
++  hide_views (plugin);
++  ply_show_new_kernel_messages (true);
++}
++
++static void
++display_normal (ply_boot_splash_plugin_t *plugin)
++{
++  pause_views (plugin);
++  if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_NORMAL)
++    {
++      plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL;
++      start_animation (plugin);
++      redraw_views (plugin);
++    }
++  unpause_views (plugin);
++}
++
++static void
++display_message (ply_boot_splash_plugin_t *plugin,
++                 const char               *message)
++{
++  if (plugin->message != NULL)
++    free (plugin->message);
++
++  plugin->message = strdup (message);
++  start_animation (plugin);
++}
++
++static void
++show_password_prompt (ply_boot_splash_plugin_t *plugin,
++                      const char               *prompt,
++                      int                       bullets)
++{
++  ply_list_node_t *node;
++  int i;
++  char *entered_text;
++
++  entered_text = calloc (bullets + 1, sizeof (char));
++
++  for (i = 0; i < bullets; i++)
++    entered_text[i] = '*';
++
++  node = ply_list_get_first_node (plugin->views);
++  while (node != NULL)
++    {
++      ply_list_node_t *next_node;
++      view_t *view;
++
++      view = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (plugin->views, node);
++
++      view_show_prompt (view, prompt, entered_text);
++
++      node = next_node;
++    }
++  free (entered_text);
++}
++
++static void
++show_prompt (ply_boot_splash_plugin_t *plugin,
++             const char               *prompt,
++             const char               *text)
++{
++  ply_list_node_t *node;
++
++  node = ply_list_get_first_node (plugin->views);
++  while (node != NULL)
++    {
++      ply_list_node_t *next_node;
++      view_t *view;
++
++      view = ply_list_node_get_data (node);
++      next_node = ply_list_get_next_node (plugin->views, node);
++
++      view_show_prompt (view, prompt, text);
++
++      node = next_node;
++    }
++}
++
++static void
++display_password (ply_boot_splash_plugin_t *plugin,
++                  const char               *prompt,
++                  int                       bullets)
++{
++  pause_views (plugin);
++  if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL)
++    stop_animation (plugin);
++
++  plugin->state = PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY;
++
++  if (!prompt)
++    prompt = "Password";
++
++  show_password_prompt (plugin, prompt, bullets);
++
++  unpause_views (plugin);
++}
++
++static void
++display_question (ply_boot_splash_plugin_t *plugin,
++                  const char               *prompt,
++                  const char               *entry_text)
++{
++  pause_views (plugin);
++  if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL)
++    stop_animation (plugin);
++
++  plugin->state = PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY;
++
++  if (!prompt)
++    prompt = "Password";
++
++  show_prompt (plugin, prompt, entry_text);
++
++  unpause_views (plugin);
++}
++
++ply_boot_splash_plugin_interface_t *
++ply_boot_splash_plugin_get_interface (void)
++{
++  static ply_boot_splash_plugin_interface_t plugin_interface =
++    {
++      .create_plugin = create_plugin,
++      .destroy_plugin = destroy_plugin,
++      .add_text_display = add_text_display,
++      .remove_text_display = remove_text_display,
++      .show_splash_screen = show_splash_screen,
++      .update_status = update_status,
++      .on_boot_progress = on_boot_progress,
++      .hide_splash_screen = hide_splash_screen,
++      .display_normal = display_normal,
++      .display_message = display_message,
++      .display_password = display_password,
++      .display_question = display_question,
++    };
++
++  return &plugin_interface;
++}
++
++/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
+diff --git a/src/plugins/splash/two-step/Makefile.am b/src/plugins/splash/two-step/Makefile.am
+index 7310d6c..f3a6aaa 100644
+--- a/src/plugins/splash/two-step/Makefile.am
++++ b/src/plugins/splash/two-step/Makefile.am
+@@ -1,4 +1,4 @@
+-INCLUDES = -I$(top_srcdir)                                                    \
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
+            -I$(srcdir)/../../../libply                                        \
+            -I$(srcdir)/../../../libply-splash-core                            \
+            -I$(srcdir)/../../../libply-splash-graphics                        \
+diff --git a/src/plugins/splash/two-step/plugin.c b/src/plugins/splash/two-step/plugin.c
+index 2998beb..f48b41e 100644
+--- a/src/plugins/splash/two-step/plugin.c
++++ b/src/plugins/splash/two-step/plugin.c
+@@ -89,8 +89,9 @@ typedef struct
+   ply_throbber_t *throbber;
+   ply_label_t *label;
+   ply_label_t *message_label;
+-  ply_rectangle_t box_area, lock_area;
++  ply_rectangle_t box_area, lock_area, watermark_area;
+   ply_trigger_t *end_trigger;
++  ply_image_t *background_image;
+ } view_t;
+ struct _ply_boot_splash_plugin
+@@ -101,10 +102,15 @@ struct _ply_boot_splash_plugin
+   ply_image_t *box_image;
+   ply_image_t *corner_image;
+   ply_image_t *header_image;
++  ply_image_t *background_tile_image;
++  ply_image_t *watermark_image;
+   ply_list_t *views;
+   ply_boot_splash_display_type_t state;
++  double watermark_horizontal_alignment;
++  double watermark_vertical_alignment;
++
+   double animation_horizontal_alignment;
+   double animation_vertical_alignment;
+   char *animation_dir;
+@@ -176,12 +182,37 @@ view_free (view_t *view)
+   ply_label_free (view->label);
+   ply_label_free (view->message_label);
++  if (view->background_image != NULL)
++    ply_image_free (view->background_image);
++
+   free (view);
+ }
+ static bool
+ view_load (view_t *view)
+ {
++  unsigned long screen_width, screen_height;
++  ply_boot_splash_plugin_t *plugin;
++
++  plugin = view->plugin;
++
++  screen_width = ply_pixel_display_get_width (view->display);
++  screen_height = ply_pixel_display_get_height (view->display);
++
++  if (plugin->background_tile_image != NULL)
++    {
++      ply_trace ("tiling background to %lux%lu", screen_width, screen_height);
++      view->background_image = ply_image_tile (plugin->background_tile_image, screen_width, screen_height);
++    }
++
++  if (plugin->watermark_image != NULL)
++    {
++      view->watermark_area.width = ply_image_get_width (plugin->watermark_image);
++      view->watermark_area.height = ply_image_get_height (plugin->watermark_image);
++      view->watermark_area.x = screen_width * plugin->watermark_horizontal_alignment - ply_image_get_width (plugin->watermark_image) * plugin->watermark_horizontal_alignment;
++      view->watermark_area.y = screen_height * plugin->watermark_vertical_alignment - ply_image_get_height (plugin->watermark_image) * plugin->watermark_vertical_alignment;
++    }
++
+   ply_trace ("loading entry");
+   if (!ply_entry_load (view->entry))
+     return false;
+@@ -519,6 +550,14 @@ create_plugin (ply_key_file_t *key_file)
+   plugin->header_image = ply_image_new (image_path);
+   free (image_path);
++  asprintf (&image_path, "%s/background-tile.png", image_dir);
++  plugin->background_tile_image = ply_image_new (image_path);
++  free (image_path);
++
++  asprintf (&image_path, "%s/watermark.png", image_dir);
++  plugin->watermark_image = ply_image_new (image_path);
++  free (image_path);
++
+   plugin->animation_dir = image_dir;
+   alignment = ply_key_file_get_value (key_file, "two-step", "HorizontalAlignment");
+@@ -535,6 +574,20 @@ create_plugin (ply_key_file_t *key_file)
+     plugin->animation_vertical_alignment = .5;
+   free (alignment);
++  alignment = ply_key_file_get_value (key_file, "two-step", "WatermarkHorizontalAlignment");
++  if (alignment != NULL)
++    plugin->watermark_horizontal_alignment = strtod (alignment, NULL);
++  else
++    plugin->watermark_horizontal_alignment = 1.0;
++  free (alignment);
++
++  alignment = ply_key_file_get_value (key_file, "two-step", "WatermarkVerticalAlignment");
++  if (alignment != NULL)
++    plugin->watermark_vertical_alignment = strtod (alignment, NULL);
++  else
++    plugin->watermark_vertical_alignment = .5;
++  free (alignment);
++
+   plugin->transition = PLY_PROGRESS_ANIMATION_TRANSITION_NONE;
+   transition = ply_key_file_get_value (key_file, "two-step", "Transition");
+   if (transition != NULL)
+@@ -653,6 +706,12 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin)
+   if (plugin->header_image != NULL)
+     ply_image_free (plugin->header_image);
++  if (plugin->background_tile_image != NULL)
++    ply_image_free (plugin->background_tile_image);
++
++  if (plugin->watermark_image != NULL)
++    ply_image_free (plugin->watermark_image);
++
+   free (plugin->animation_dir);
+   free_views (plugin);
+   free (plugin);
+@@ -813,6 +872,21 @@ draw_background (view_t             *view,
+   else
+     ply_pixel_buffer_fill_with_hex_color (pixel_buffer, &area,
+                                           plugin->background_start_color);
++
++  if (view->background_image != NULL)
++    {
++      uint32_t *data;
++      data = ply_image_get_data (view->background_image);
++      ply_pixel_buffer_fill_with_argb32_data (pixel_buffer, &area, data);
++    }
++
++  if (plugin->watermark_image != NULL)
++    {
++      uint32_t *data;
++
++      data = ply_image_get_data (plugin->watermark_image);
++      ply_pixel_buffer_fill_with_argb32_data (pixel_buffer, &view->watermark_area, data);
++    }
+ }
+ static void
+@@ -997,6 +1071,26 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin,
+         }
+     }
++  if (plugin->background_tile_image != NULL)
++    {
++      ply_trace ("loading background tile image");
++      if (!ply_image_load (plugin->background_tile_image))
++        {
++          ply_image_free (plugin->background_tile_image);
++          plugin->background_tile_image = NULL;
++        }
++    }
++
++  if (plugin->watermark_image != NULL)
++    {
++      ply_trace ("loading watermark image");
++      if (!ply_image_load (plugin->watermark_image))
++        {
++          ply_image_free (plugin->watermark_image);
++          plugin->watermark_image = NULL;
++        }
++    }
++
+   if (!load_views (plugin))
+     {
+       ply_trace ("couldn't load views");
+@@ -1067,6 +1161,9 @@ on_boot_progress (ply_boot_splash_plugin_t *plugin,
+   if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_NORMAL)
+     return;
++  if (plugin->is_idle)
++    return;
++
+   if (percent_done >= SHOW_ANIMATION_PERCENT)
+     {
+       if (plugin->stop_trigger == NULL)
+diff --git a/src/ply-boot-server.c b/src/ply-boot-server.c
+index f15ade7..3e67bfb 100644
+--- a/src/ply-boot-server.c
++++ b/src/ply-boot-server.c
+@@ -776,7 +776,7 @@ ply_boot_server_on_new_connection (ply_boot_server_t *server)
+   assert (server != NULL);
+-  fd = accept (server->socket_fd, NULL, NULL);
++  fd = accept4 (server->socket_fd, NULL, NULL, SOCK_CLOEXEC);
+   if (fd < 0)
+     return;
+@@ -831,183 +831,4 @@ ply_boot_server_attach_to_event_loop (ply_boot_server_t *server,
+                                  server); 
+ }
+-#ifdef PLY_BOOT_SERVER_ENABLE_TEST
+-
+-#include <stdio.h>
+-
+-#include "ply-event-loop.h"
+-#include "ply-boot-server.h"
+-
+-static void 
+-on_update (ply_event_loop_t  *loop,
+-           const char        *status)
+-{
+-  printf ("new status is '%s'\n", status);
+-}
+-
+-static void
+-on_newroot (ply_event_loop_t *loop)
+-{
+-  printf ("got newroot request\n");
+-}
+-
+-static void
+-on_system_initialized (ply_event_loop_t *loop)
+-{
+-  printf ("got sysinit done request\n");
+-}
+-
+-static void
+-on_show_splash (ply_event_loop_t *loop)
+-{
+-  printf ("got show splash request\n");
+-}
+-
+-static void
+-on_hide_splash (ply_event_loop_t *loop)
+-{
+-  printf ("got hide splash request\n");
+-}
+-
+-static void
+-on_deactivate (ply_event_loop_t *loop)
+-{
+-  printf ("got deactivate request\n");
+-}
+-
+-static void
+-on_reactivate (ply_event_loop_t *loop)
+-{
+-  printf ("got reactivate request\n");
+-}
+-
+-static void
+-on_quit (ply_event_loop_t *loop)
+-{
+-  printf ("got quit request, quiting...\n");
+-  ply_event_loop_exit (loop, 0);
+-}
+-
+-static void
+-on_error (ply_event_loop_t *loop)
+-{
+-  printf ("got error starting service\n");
+-}
+-
+-static char *
+-on_ask_for_password (ply_event_loop_t *loop)
+-{
+-  printf ("got password request, returning 'password'...\n");
+-
+-  return strdup ("password");
+-}
+-
+-static void
+-on_ask_question (ply_event_loop_t *loop)
+-{
+-  printf ("got question request\n");
+-  return;
+-}
+-
+-static void
+-on_display_message (ply_event_loop_t *loop)
+-{
+-  printf ("got display message request\n");
+-  return;
+-}
+-
+-static void
+-on_hide_message (ply_event_loop_t *loop)
+-{
+-  printf ("got hide message request\n");
+-  return;
+-}
+-
+-static void
+-on_watch_for_keystroke (ply_event_loop_t *loop)
+-{
+-  printf ("got keystroke request\n");
+-
+-  return;
+-}
+-
+-static void
+-on_progress_pause (ply_event_loop_t *loop)
+-{
+-  printf ("got progress pause request\n");
+-
+-  return;
+-}
+-
+-static void
+-on_progress_unpause (ply_event_loop_t *loop)
+-{
+-  printf ("got progress unpause request\n");
+-
+-  return;
+-}
+-
+-static void
+-on_ignore_keystroke (ply_event_loop_t *loop)
+-{
+-  printf ("got keystroke ignore request\n");
+-
+-  return;
+-}
+-
+-static bool
+-on_has_active_vt (ply_event_loop_t *loop)
+-{
+-  printf ("got has_active vt? request\n");
+-  return true;
+-}
+-
+-int
+-main (int    argc,
+-      char **argv)
+-{
+-  ply_event_loop_t *loop;
+-  ply_boot_server_t *server;
+-  int exit_code;
+-
+-  exit_code = 0;
+-
+-  loop = ply_event_loop_new ();
+-
+-  server = ply_boot_server_new ((ply_boot_server_update_handler_t) on_update,
+-                                (ply_boot_server_change_mode_handler_t) on_change_mode,
+-                                (ply_boot_server_system_update_handler_t) on_system_update,
+-                                (ply_boot_server_ask_for_password_handler_t) on_ask_for_password,
+-                                (ply_boot_server_ask_question_handler_t) on_ask_question,
+-                                (ply_boot_server_display_message_handler_t) on_display_message,
+-                                (ply_boot_server_hide_message_handler_t) on_hide_message,
+-                                (ply_boot_server_watch_for_keystroke_handler_t) on_watch_for_keystroke,
+-                                (ply_boot_server_ignore_keystroke_handler_t) on_ignore_keystroke,
+-                                (ply_boot_server_progress_pause_handler_t) on_progress_pause,
+-                                (ply_boot_server_progress_unpause_handler_t) on_progress_unpause,
+-                                (ply_boot_server_show_splash_handler_t) on_show_splash,
+-                                (ply_boot_server_hide_splash_handler_t) on_hide_splash,
+-                                (ply_boot_server_newroot_handler_t) on_newroot,
+-                                (ply_boot_server_system_initialized_handler_t) on_system_initialized,
+-                                (ply_boot_server_error_handler_t) on_error,
+-                                (ply_boot_server_deactivate_handler_t) on_deactivate,
+-                                (ply_boot_server_reactivate_handler_t) on_reactivate,
+-                                (ply_boot_server_quit_handler_t) on_quit,
+-                                (ply_boot_server_has_active_vt_handler_t) on_has_active_vt,
+-                                loop);
+-
+-  if (!ply_boot_server_listen (server))
+-    {
+-      perror ("could not start boot status daemon");
+-      return errno;
+-    }
+-
+-  ply_boot_server_attach_to_event_loop (server, loop);
+-  exit_code = ply_event_loop_run (loop);
+-  ply_boot_server_free (server);
+-
+-  return exit_code;
+-}
+-
+-#endif /* PLY_BOOT_SERVER_ENABLE_TEST */
+ /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
+diff --git a/src/plymouthd.defaults b/src/plymouthd.defaults
+index 46417d6..fc48b15 100644
+--- a/src/plymouthd.defaults
++++ b/src/plymouthd.defaults
+@@ -2,3 +2,4 @@
+ # upgrades.
+ [Daemon]
+ Theme=spinner
++ShowDelay=5
+diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
+deleted file mode 100644
+index 86a8ea6..0000000
+--- a/src/tests/Makefile.am
++++ /dev/null
+@@ -1,18 +0,0 @@
+-INCLUDES =                                                                    \
+-           -I$(top_srcdir)                                                    \
+-           -I$(srcdir)/..                                                     \
+-           -I$(srcdir)/../libply                                              \
+-           -I$(srcdir)/../libply-splash-core                                  \
+-           -I$(srcdir)
+-TESTS =
+-
+-if ENABLE_TESTS
+-include $(srcdir)/ply-boot-server-test.am
+-include $(srcdir)/ply-boot-splash-test.am
+-endif
+-
+-noinst_PROGRAMS = $(TESTS)
+-
+-# our tests aren't unit tests, so clear for now
+-TESTS =
+-MAINTAINERCLEANFILES = Makefile.in
+diff --git a/src/tests/ply-boot-server-test.am b/src/tests/ply-boot-server-test.am
+deleted file mode 100644
+index cc28348..0000000
+--- a/src/tests/ply-boot-server-test.am
++++ /dev/null
+@@ -1,8 +0,0 @@
+-TESTS += ply-boot-server-test
+-
+-ply_boot_server_test_CFLAGS = $(PLYMOUTH_CFLAGS) -DPLY_BOOT_SERVER_ENABLE_TEST
+-ply_boot_server_test_LDADD = $(PLYMOUTH_LIBS) ../libply/libply.la
+-
+-ply_boot_server_test_SOURCES =                                                \
+-                          $(srcdir)/../ply-boot-server.h                      \
+-                          $(srcdir)/../ply-boot-server.c
+diff --git a/src/tests/ply-boot-splash-test.am b/src/tests/ply-boot-splash-test.am
+deleted file mode 100644
+index 9dd1598..0000000
+--- a/src/tests/ply-boot-splash-test.am
++++ /dev/null
+@@ -1,25 +0,0 @@
+-TESTS += ply-boot-splash-test
+-
+-ply_boot_splash_test_CFLAGS = $(PLYMOUTH_CFLAGS) -DPLY_BOOT_SPLASH_ENABLE_TEST  \
+-                        -DPLYMOUTH_TIME_DIRECTORY=\"/var/lib/plymouth\"         \
+-                        -DPLYMOUTH_PLUGIN_PATH=\"$(PLYMOUTH_PLUGIN_PATH)\"      \
+-                        -DPLYMOUTH_THEME_PATH=\"$(PLYMOUTH_THEME_PATH)/\"
+-
+-ply_boot_splash_test_LDADD = $(PLYMOUTH_LIBS) ../libply/libply.la
+-
+-ply_boot_splash_test_SOURCES =                                                   \
+-                          $(srcdir)/../libply-splash-core/ply-boot-splash-plugin.h \
+-                          $(srcdir)/../libply-splash-core/ply-keyboard.h           \
+-                          $(srcdir)/../libply-splash-core/ply-keyboard.c           \
+-                          $(srcdir)/../libply-splash-core/ply-pixel-buffer.h       \
+-                          $(srcdir)/../libply-splash-core/ply-pixel-buffer.c       \
+-                          $(srcdir)/../libply-splash-core/ply-pixel-display.h      \
+-                          $(srcdir)/../libply-splash-core/ply-pixel-display.c      \
+-                          $(srcdir)/../libply-splash-core/ply-renderer.h           \
+-                          $(srcdir)/../libply-splash-core/ply-renderer.c           \
+-                          $(srcdir)/../libply-splash-core/ply-terminal.h           \
+-                          $(srcdir)/../libply-splash-core/ply-terminal.c           \
+-                          $(srcdir)/../libply-splash-core/ply-text-display.h       \
+-                          $(srcdir)/../libply-splash-core/ply-text-display.c       \
+-                          $(srcdir)/../libply-splash-core/ply-boot-splash.h        \
+-                          $(srcdir)/../libply-splash-core/ply-boot-splash.c
+diff --git a/src/upstart-bridge/Makefile.am b/src/upstart-bridge/Makefile.am
+index 628ef20..a16cd11 100644
+--- a/src/upstart-bridge/Makefile.am
++++ b/src/upstart-bridge/Makefile.am
+@@ -1,4 +1,4 @@
+-INCLUDES = -I$(top_srcdir)                                                    \
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
+            -I$(top_srcdir)/src                                                \
+            -I$(top_srcdir)/src/libply                                         \
+            -I$(top_srcdir)/src/client                                         \
+diff --git a/src/viewer/Makefile.am b/src/viewer/Makefile.am
+index 6ade690..0c5c3ec 100644
+--- a/src/viewer/Makefile.am
++++ b/src/viewer/Makefile.am
+@@ -1,7 +1,7 @@
+ SUBDIRS = .
+ EXTRA_DIST=
+-INCLUDES = -I$(top_srcdir)                                                    \
++AM_CPPFLAGS = -I$(top_srcdir)                                                 \
+            -I$(srcdir)
+ if WITH_LOG_VIEWER
+ plymouth_log_viewerdir = $(bindir)
+diff --git a/src/viewer/plymouth-log-viewer.c b/src/viewer/plymouth-log-viewer.c
+index c20e391..ca54e0f 100644
+--- a/src/viewer/plymouth-log-viewer.c
++++ b/src/viewer/plymouth-log-viewer.c
+@@ -20,6 +20,10 @@
+  *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+  */
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sys/types.h>
+diff --git a/systemd-units/Makefile.am b/systemd-units/Makefile.am
+index 3aa44df..89355ac 100644
+--- a/systemd-units/Makefile.am
++++ b/systemd-units/Makefile.am
+@@ -25,7 +25,8 @@ install-data-hook:
+               $(DESTDIR)$(SYSTEMD_UNIT_DIR)/poweroff.target.wants          \
+               $(DESTDIR)$(SYSTEMD_UNIT_DIR)/halt.target.wants
+       (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/initrd-switch-root.target.wants && \
+-              rm -f plymouth-switch-root.service &&                        \
++              rm -f plymouth-start.service plymouth-switch-root.service && \
++              $(LN_S) ../plymouth-start.service &&                         \
+               $(LN_S) ../plymouth-switch-root.service)
+       (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/sysinit.target.wants &&            \
+               rm -f plymouth-start.service plymouth-read-write.service &&  \
+@@ -51,7 +52,7 @@ install-data-hook:
+ uninstall-hook:
+       rm -f \
+       (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/initrd-switch-root.target.wants && \
+-              rm -f plymouth-switch-root.service)                          \
++              rm -f plymouth-start.service plymouth-switch-root.service)   \
+       (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/sysinit.target.wants &&            \
+               rm -f plymouth-start.service plymouth-read-write.service)    \
+       (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/multi-user.target.wants &&         \
+diff --git a/systemd-units/plymouth-halt.service.in b/systemd-units/plymouth-halt.service.in
+index 8fd6c48..fd27e10 100644
+--- a/systemd-units/plymouth-halt.service.in
++++ b/systemd-units/plymouth-halt.service.in
+@@ -1,7 +1,7 @@
+ [Unit]
+ Description=Show Plymouth Halt Screen
+-After=getty@tty1.service prefdm.service plymouth-start.service
+-Before=halt.service
++After=getty@tty1.service display-manager.service plymouth-start.service
++Before=systemd-halt.service
+ DefaultDependencies=no
+ ConditionKernelCommandLine=!plymouth.enable=0
+@@ -9,3 +9,6 @@ ConditionKernelCommandLine=!plymouth.enable=0
+ ExecStart=@PLYMOUTH_DAEMON_DIR@/plymouthd --mode=shutdown --attach-to-session
+ ExecStartPost=-@PLYMOUTH_CLIENT_DIR@/plymouth show-splash
+ Type=forking
++
++[Install]
++WantedBy=halt.target
+diff --git a/systemd-units/plymouth-kexec.service.in b/systemd-units/plymouth-kexec.service.in
+index 6ee0461..8aa661d 100644
+--- a/systemd-units/plymouth-kexec.service.in
++++ b/systemd-units/plymouth-kexec.service.in
+@@ -1,7 +1,7 @@
+ [Unit]
+ Description=Show Plymouth Reboot with kexec Screen
+-After=getty@tty1.service prefdm.service plymouth-start.service
+-Before=kexec.service
++After=getty@tty1.service display-manager.service plymouth-start.service
++Before=systemd-kexec.service
+ DefaultDependencies=no
+ ConditionKernelCommandLine=!plymouth.enable=0
+@@ -9,3 +9,6 @@ ConditionKernelCommandLine=!plymouth.enable=0
+ ExecStart=@PLYMOUTH_DAEMON_DIR@/plymouthd --mode=shutdown --attach-to-session
+ ExecStartPost=-@PLYMOUTH_CLIENT_DIR@/plymouth show-splash
+ Type=forking
++
++[Install]
++WantedBy=kexec.target
+diff --git a/systemd-units/plymouth-poweroff.service.in b/systemd-units/plymouth-poweroff.service.in
+index 3e2a83c..305ece6 100644
+--- a/systemd-units/plymouth-poweroff.service.in
++++ b/systemd-units/plymouth-poweroff.service.in
+@@ -1,7 +1,7 @@
+ [Unit]
+ Description=Show Plymouth Power Off Screen
+-After=getty@tty1.service prefdm.service plymouth-start.service
+-Before=poweroff.service
++After=getty@tty1.service display-manager.service plymouth-start.service
++Before=systemd-poweroff.service
+ DefaultDependencies=no
+ ConditionKernelCommandLine=!plymouth.enable=0
+@@ -9,3 +9,5 @@ ConditionKernelCommandLine=!plymouth.enable=0
+ ExecStart=@PLYMOUTH_DAEMON_DIR@/plymouthd --mode=shutdown --attach-to-session
+ ExecStartPost=-@PLYMOUTH_CLIENT_DIR@/plymouth show-splash
+ Type=forking
++[Install]
++WantedBy=poweroff.target
+diff --git a/systemd-units/plymouth-quit-wait.service.in b/systemd-units/plymouth-quit-wait.service.in
+index 9fc20e7..1c431b6 100644
+--- a/systemd-units/plymouth-quit-wait.service.in
++++ b/systemd-units/plymouth-quit-wait.service.in
+@@ -5,4 +5,6 @@ After=rc-local.service plymouth-start.service systemd-user-sessions.service
+ [Service]
+ ExecStart=-@PLYMOUTH_CLIENT_DIR@/plymouth --wait
+ Type=oneshot
+-TimeoutSec=20
++TimeoutSec=0
++[Install]
++WantedBy=multi-user.target
+diff --git a/systemd-units/plymouth-quit.service.in b/systemd-units/plymouth-quit.service.in
+index cf9901e..24c11bb 100644
+--- a/systemd-units/plymouth-quit.service.in
++++ b/systemd-units/plymouth-quit.service.in
+@@ -6,3 +6,5 @@ After=rc-local.service plymouth-start.service systemd-user-sessions.service
+ ExecStart=-@PLYMOUTH_CLIENT_DIR@/plymouth quit
+ Type=oneshot
+ TimeoutSec=20
++[Install]
++WantedBy=multi-user.target
+diff --git a/systemd-units/plymouth-read-write.service.in b/systemd-units/plymouth-read-write.service.in
+index 55b975e..5abfc49 100644
+--- a/systemd-units/plymouth-read-write.service.in
++++ b/systemd-units/plymouth-read-write.service.in
+@@ -8,3 +8,5 @@ ConditionPathExists=!/etc/initrd-release
+ [Service]
+ ExecStart=-@PLYMOUTH_CLIENT_DIR@/plymouth update-root-fs --read-write
+ Type=oneshot
++[Install]
++WantedBy=sysinit.target
+diff --git a/systemd-units/plymouth-reboot.service.in b/systemd-units/plymouth-reboot.service.in
+index a6e86e4..ce56855 100644
+--- a/systemd-units/plymouth-reboot.service.in
++++ b/systemd-units/plymouth-reboot.service.in
+@@ -1,7 +1,7 @@
+ [Unit]
+ Description=Show Plymouth Reboot Screen
+-After=getty@tty1.service prefdm.service plymouth-start.service
+-Before=reboot.service
++After=getty@tty1.service display-manager.service plymouth-start.service
++Before=systemd-reboot.service
+ DefaultDependencies=no
+ ConditionKernelCommandLine=!plymouth.enable=0
+@@ -9,3 +9,5 @@ ConditionKernelCommandLine=!plymouth.enable=0
+ ExecStart=@PLYMOUTH_DAEMON_DIR@/plymouthd --mode=shutdown --attach-to-session
+ ExecStartPost=-@PLYMOUTH_CLIENT_DIR@/plymouth show-splash
+ Type=forking
++[Install]
++WantedBy=reboot.target
+diff --git a/systemd-units/plymouth-start.service.in b/systemd-units/plymouth-start.service.in
+index bbff9f5..0d5ff2a 100644
+--- a/systemd-units/plymouth-start.service.in
++++ b/systemd-units/plymouth-start.service.in
+@@ -1,14 +1,16 @@
+ [Unit]
+ Description=Show Plymouth Boot Screen
+ DefaultDependencies=no
+-Wants=systemd-ask-password-plymouth.path
+-After=systemd-vconsole-setup.service systemd-udev-trigger.service
++Wants=systemd-ask-password-plymouth.path systemd-vconsole-setup.service
++After=systemd-vconsole-setup.service systemd-udev-trigger.service systemd-udevd.service
+ Before=systemd-ask-password-plymouth.service
+ ConditionKernelCommandLine=!plymouth.enable=0
+ [Service]
+ ExecStart=@PLYMOUTH_DAEMON_DIR@/plymouthd --mode=boot --pid-file=@plymouthruntimedir@/pid --attach-to-session
+-ExecStartPost=-/bin/udevadm settle --timeout=30 --exit-if-exists=/sys/class/drm/card0/dev ; /bin/udevadm settle --timeout=30 --exit-if-exists=/sys/class/graphics/fb0/dev ; @PLYMOUTH_CLIENT_DIR@/plymouth show-splash
++ExecStartPost=-@PLYMOUTH_CLIENT_DIR@/plymouth show-splash
+ Type=forking
+ KillMode=none
+ SendSIGKILL=no
++[Install]
++WantedBy=sysinit.target
+diff --git a/systemd-units/systemd-ask-password-plymouth.service.in b/systemd-units/systemd-ask-password-plymouth.service.in
+index aa9ffc2..0c3acde 100644
+--- a/systemd-units/systemd-ask-password-plymouth.service.in
++++ b/systemd-units/systemd-ask-password-plymouth.service.in
+@@ -9,4 +9,4 @@ ConditionKernelCommandLine=!plymouth.enable=0
+ ConditionPathExists=/run/plymouth/pid
+ [Service]
+-ExecStart=/bin/systemd-tty-ask-password-agent --watch --plymouth
++ExecStart=@SYSTEMD_ASK_PASSWORD_AGENT@ --watch --plymouth
+diff --git a/themes/Makefile.am b/themes/Makefile.am
+index cfd149e..72e642b 100644
+--- a/themes/Makefile.am
++++ b/themes/Makefile.am
+@@ -1,2 +1,2 @@
+-SUBDIRS = spinfinity fade-in text details solar glow script spinner
++SUBDIRS = spinfinity fade-in text details solar glow script spinner tribar
+ MAINTAINERCLEANFILES = Makefile.in
+diff --git a/themes/text/text.plymouth b/themes/text/text.plymouth
+index a2db9e6..126eb09 100644
+--- a/themes/text/text.plymouth
++++ b/themes/text/text.plymouth
+@@ -1,4 +1,4 @@
+ [Plymouth Theme]
+ Name=Text
+-Description=Text mode theme with tricolor progress bar
++Description=Text mode theme with a 3 box countdown
+ ModuleName=text
+diff --git a/themes/tribar/Makefile.am b/themes/tribar/Makefile.am
+new file mode 100644
+index 0000000..3066d2f
+--- /dev/null
++++ b/themes/tribar/Makefile.am
+@@ -0,0 +1,4 @@
++themedir = $(datadir)/plymouth/themes/tribar
++dist_theme_DATA = tribar.plymouth
++
++MAINTAINERCLEANFILES = Makefile.in
+diff --git a/themes/tribar/tribar.plymouth b/themes/tribar/tribar.plymouth
+new file mode 100644
+index 0000000..6db7b4e
+--- /dev/null
++++ b/themes/tribar/tribar.plymouth
+@@ -0,0 +1,4 @@
++[Plymouth Theme]
++Name=Tribar
++Description=Text mode theme with tricolor progress bar
++ModuleName=tribar
index 3297aebfc20d9286991e44e4109c6d18aab428b9..894f4f4943308e6efd9c8fdab11ad9bda3ef1b8b 100644 (file)
@@ -1,20 +1,15 @@
 # TODO
 # - integrate with geninitrd
 # - pldize recent update (r1.18)
-# - verify if systemd services have to be installed for targets,
-#      and remove the symlinks if not
 #
 # Conditional build:
-%bcond_without drm_intel       # disable building with libdrm_intel support
-%bcond_without drm_radeon      # disable building with libdrm_radeon support
-%bcond_with    drm_nouveau     # enable building with libdrm_nouveau support
-%bcond_without kms             # disable building with libkms support
+%bcond_without drm             # disable building with DRM renderer support
 
 Summary:       Graphical Boot Animation and Logger
 Summary(pl.UTF-8):     Graficzna animacja i logowanie startu systemu
 Name:          plymouth
 Version:       0.8.8
-Release:       8
+Release:       9
 License:       GPL v2+
 Group:         Base
 Source0:       http://www.freedesktop.org/software/plymouth/releases/%{name}-%{version}.tar.bz2
@@ -22,25 +17,20 @@ Source0:    http://www.freedesktop.org/software/plymouth/releases/%{name}-%{version
 Source1:       %{name}-logo.png
 # Source1-md5: 6b38a868585adfd3a96a4ad16973c1f8
 Source2:       %{name}.tmpfiles
-Source3:       charge.%{name}
 Source4:       boot-duration
-Source5:       %{name}-set-default-plugin
 Source6:       %{name}-update-initrd
-Source7:       systemd-ask-password-plymouth.path
-Source8:       systemd-ask-password-plymouth.service
 Patch0:                text-colors.patch
-Patch1:                path-udevadm.patch
-Patch2:                %{name}-restore-suspend.patch
+Patch1:                %{name}-restore-suspend.patch
+Patch100:      %{name}-git.patch
 URL:           http://www.freedesktop.org/wiki/Software/Plymouth
 BuildRequires: cairo-devel
 BuildRequires: gtk+2-devel >= 2:2.12.0
-%if %{with drm_intel} ||  %{with drm_radeon} ||  %{with drm_nouveau} ||  %{with kms}
-BuildRequires: libdrm-devel
-%endif
 BuildRequires: xorg-lib-libpciaccess-devel
+%{?with_drm:BuildRequires:     libdrm-devel}
 BuildRequires: libpng-devel >= 2:1.2.16
 BuildRequires: pango-devel >= 1:1.21.0
 BuildRequires: pkgconfig
+BuildRequires: udev-devel
 Requires:      %{name}-graphics-libs = %{version}-%{release}
 Requires(post):        %{name}-scripts = %{version}-%{release}
 Requires:      /etc/os-release
@@ -253,23 +243,22 @@ This metapackage tracks the current distribution default theme.
 %description system-theme -l pl.UTF-8
 Ten metapakiet śledzi domyślny motyw dystrybucji.
 
-%package theme-charge
-Summary:       Plymouth "Charge" theme
-Summary(pl.UTF-8):     Motyw Plymouth "Charge"
+%package theme-glow
+Summary:       Plymouth "Glow" theme
+Summary(pl.UTF-8):     Motyw Plymouth "Glow"
 Group:         Base
 Requires:      %{name}-plugin-two-step = %{version}-%{release}
 Requires(post):        %{name}-scripts = %{version}-%{release}
 Provides:      %{name}(system-theme) = %{version}-%{release}
+Obsoletes:     plymouth-theme-charge
 
-%description theme-charge
-This package contains the "charge" boot splash theme for Plymouth. It
-features the shadowy hull of a Fedora logo charge up and and finally
-burst into full form.
+%description theme-glow
+This package contains the "Glow" boot splash theme for Plymouth.
+Corporate theme with pie chart boot progress followed by a glowing
+emerging logo.
 
-%description theme-charge -l pl.UTF-8
-Ten pakiet zawiera motyw ekranu startowego Plymouth "Charge". Odznacza
-się on cieniowaną łupiną loga Fedory, która rośnie, a ostatecznie
-wybucha do pełnej postaci.
+%description theme-glow -l pl.UTF-8
+Ten pakiet zawiera motyw ekranu startowego Plymouth "Glow".
 
 %package theme-fade-in
 Summary:       Plymouth "Fade-In" theme
@@ -357,21 +346,21 @@ Odznacza się on małym kółkiem kręcącym się na ciemnym tle.
 
 %prep
 %setup -q
+%patch100 -p1
 %patch0 -p1
 %patch1 -p1
-%patch2 -p1
-
-# Change the default theme
-sed -i -e 's/fade-in/charge/g' src/plymouthd.defaults
 
 %build
+%{__aclocal}
+%{__autoconf}
+%{__autoheader}
+%{__automake}
 %configure \
-       %{__enable_disable drm_intel libdrm_intel} \
-       %{__enable_disable drm_radeon libdrm_radeon} \
-       %{__enable_disable drm_nouveau libdrm_nouveau} \
-       %{__enable_disable kms libkms} \
+       UDEVADM=/sbin/udevadm \
+       SYSTEMD_ASK_PASSWORD_AGENT=/bin/systemd-tty-ask-password-agent \
+       %{__enable_disable drm drm} \
        --disable-silent-rules \
-       --disable-tests \
+       --enable-documentation \
        --disable-gdm-transition \
        --enable-systemd-integration \
        --enable-tracing \
@@ -392,7 +381,6 @@ install -d $RPM_BUILD_ROOT{%{_bindir},%{_libdir},%{_pixmapsdir},%{systemdtmpfile
 %{__make} install \
        DESTDIR=$RPM_BUILD_ROOT
 
-%{__mv} $RPM_BUILD_ROOT/%{_lib}/lib*.a $RPM_BUILD_ROOT%{_libdir}
 ln -sf /%{_lib}/$(basename $RPM_BUILD_ROOT/%{_lib}/libply.so.*.*.*) $RPM_BUILD_ROOT%{_libdir}/libply.so
 ln -sf /%{_lib}/$(basename $RPM_BUILD_ROOT/%{_lib}/libply-splash-core.so.*.*.*) $RPM_BUILD_ROOT%{_libdir}/libply-splash-core.so
 %{__rm} $RPM_BUILD_ROOT/%{_lib}/libply{,-splash-core}.so
@@ -401,47 +389,18 @@ install -d $RPM_BUILD_ROOT%{_localstatedir}/lib/plymouth
 cp -p %{SOURCE4} $RPM_BUILD_ROOT%{_datadir}/plymouth/default-boot-duration
 > $RPM_BUILD_ROOT%{_localstatedir}/lib/plymouth/boot-duration
 
-# FC: Add charge, our new default
-install -d $RPM_BUILD_ROOT%{_datadir}/plymouth/themes/charge
-cp %{SOURCE3} $RPM_BUILD_ROOT%{_datadir}/plymouth/themes/charge
-cp $RPM_BUILD_ROOT%{_datadir}/plymouth/themes/glow/{box,bullet,entry,lock}.png $RPM_BUILD_ROOT%{_datadir}/plymouth/themes/charge
-
-# FC: Drop glow, it's not very Fedora-y
-%{__rm} -r $RPM_BUILD_ROOT%{_datadir}/plymouth/themes/glow
-
-# FC: Override plymouth-update-initrd to work dracut or mkinitrd
+# Override plymouth-update-initrd to work with dracut or mkinitrd
 cp -p %{SOURCE6} $RPM_BUILD_ROOT%{_libdir}/plymouth/plymouth-update-initrd
 
-# FC: Add compat script for upgrades
-install -p %{SOURCE5} $RPM_BUILD_ROOT%{_sbindir}
-
 %{__rm} $RPM_BUILD_ROOT{/%{_lib},%{_libdir}}/*.la \
-       $RPM_BUILD_ROOT%{_libdir}/plymouth/*.{a,la} \
-       $RPM_BUILD_ROOT%{_libdir}/plymouth/renderers/*.{a,la}
-
-# Temporary symlink until rc.sysinit is fixed
-ln -sf /bin/plymouth $RPM_BUILD_ROOT%{_bindir}/plymouth
+       $RPM_BUILD_ROOT%{_libdir}/plymouth/*.la \
+       $RPM_BUILD_ROOT%{_libdir}/plymouth/renderers/*.la
 
 install -d $RPM_BUILD_ROOT%{_localstatedir}/lib/plymouth
 
 cp -p %{SOURCE1} $RPM_BUILD_ROOT%{_pixmapsdir}/plymouth-logo.png
 cp -p %{SOURCE2} $RPM_BUILD_ROOT%{systemdtmpfilesdir}/%{name}.conf
 
-cp -p %{SOURCE7} $RPM_BUILD_ROOT%{systemdunitdir}/systemd-ask-password-plymouth.path
-cp -p %{SOURCE8} $RPM_BUILD_ROOT%{systemdunitdir}/systemd-ask-password-plymouth.service
-
-# install plymouth services for targets
-# http://cgit.freedesktop.org/systemd/systemd/commit/?id=26cbf29c52a36b6ad9d1ccc16d8f7adccefeddca
-install -d $RPM_BUILD_ROOT%{systemdunitdir}/{halt,kexec,poweroff,reboot,sysinit,multi-user}.target.wants
-ln -sf ../plymouth-start.service $RPM_BUILD_ROOT%{systemdunitdir}/sysinit.target.wants/plymouth-start.service
-ln -sf ../plymouth-read-write.service $RPM_BUILD_ROOT%{systemdunitdir}/sysinit.target.wants/plymouth-read-write.service
-ln -sf ../plymouth-quit.service $RPM_BUILD_ROOT%{systemdunitdir}/multi-user.target.wants/plymouth-quit.service
-ln -sf ../plymouth-quit-wait.service $RPM_BUILD_ROOT%{systemdunitdir}/multi-user.target.wants/plymouth-quit-wait.service
-ln -sf ../plymouth-reboot.service $RPM_BUILD_ROOT%{systemdunitdir}/reboot.target.wants/plymouth-reboot.service
-ln -sf ../plymouth-kexec.service $RPM_BUILD_ROOT%{systemdunitdir}/kexec.target.wants/plymouth-kexec.service
-ln -sf ../plymouth-poweroff.service $RPM_BUILD_ROOT%{systemdunitdir}/poweroff.target.wants/plymouth-poweroff.service
-ln -sf ../plymouth-halt.service $RPM_BUILD_ROOT%{systemdunitdir}/halt.target.wants/plymouth-halt.service
-
 %clean
 rm -rf $RPM_BUILD_ROOT
 
@@ -462,7 +421,6 @@ fi
 %files
 %defattr(644,root,root,755)
 %doc AUTHORS README TODO
-%attr(755,root,root) %{_bindir}/plymouth
 %dir %{_sysconfdir}/plymouth
 %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/plymouth/plymouthd.conf
 %{_mandir}/man8/plymouth.8*
@@ -470,22 +428,27 @@ fi
 %attr(755,root,root) /sbin/plymouthd
 %attr(755,root,root) %{_libdir}/plymouth/details.so
 %attr(755,root,root) %{_libdir}/plymouth/text.so
+%attr(755,root,root) %{_libdir}/plymouth/tribar.so
 %attr(755,root,root) %{_libdir}/plymouth/renderers/drm.so
 %attr(755,root,root) %{_libdir}/plymouth/renderers/frame-buffer.so
 %dir %{_datadir}/plymouth
 %dir %{_datadir}/plymouth/themes
 %dir %{_datadir}/plymouth/themes/details
 %dir %{_datadir}/plymouth/themes/text
+%dir %{_datadir}/plymouth/themes/tribar
 %{_datadir}/plymouth/plymouthd.defaults
 %{_datadir}/plymouth/default-boot-duration
 %{_datadir}/plymouth/themes/details/details.plymouth
 %{_datadir}/plymouth/themes/text/text.plymouth
+%{_datadir}/plymouth/themes/tribar/tribar.plymouth
 %{_pixmapsdir}/plymouth-logo.png
 %{systemdtmpfilesdir}/%{name}.conf
 %dir %{_localstatedir}/lib/plymouth
 %ghost %{_localstatedir}/lib/plymouth/boot-duration
 %{_localstatedir}/run/plymouth
 %{_localstatedir}/spool/plymouth
+%{_mandir}/man1/plymouth.1*
+%{_mandir}/man8/plymouthd.8*
 
 %{systemdunitdir}/plymouth-halt.service
 %{systemdunitdir}/plymouth-kexec.service
@@ -501,6 +464,7 @@ fi
 %{systemdunitdir}/halt.target.wants/plymouth-halt.service
 %dir %{systemdunitdir}/initrd-switch-root.target.wants
 %{systemdunitdir}/initrd-switch-root.target.wants/plymouth-switch-root.service
+%{systemdunitdir}/initrd-switch-root.target.wants/plymouth-start.service
 %{systemdunitdir}/kexec.target.wants/plymouth-kexec.service
 %{systemdunitdir}/multi-user.target.wants/plymouth-quit.service
 %{systemdunitdir}/multi-user.target.wants/plymouth-quit-wait.service
@@ -537,20 +501,13 @@ fi
 %{_pkgconfigdir}/ply-splash-core.pc
 %{_pkgconfigdir}/ply-splash-graphics.pc
 
-%files static
-%defattr(644,root,root,755)
-%attr(755,root,root) %{_libdir}/libply.a
-%attr(755,root,root) %{_libdir}/libply-boot-client.a
-%attr(755,root,root) %{_libdir}/libply-splash-core.a
-%attr(755,root,root) %{_libdir}/libply-splash-graphics.a
-
 %files scripts
 %defattr(644,root,root,755)
-%attr(755,root,root) %{_sbindir}/plymouth-set-default-plugin
 %attr(755,root,root) %{_sbindir}/plymouth-set-default-theme
 %attr(755,root,root) %{_libdir}/plymouth/plymouth-generate-initrd
 %attr(755,root,root) %{_libdir}/plymouth/plymouth-populate-initrd
 %attr(755,root,root) %{_libdir}/plymouth/plymouth-update-initrd
+%{_mandir}/man1/plymouth-set-default-theme.1*
 
 %files plugin-fade-throbber
 %defattr(644,root,root,755)
@@ -579,11 +536,11 @@ fi
 %files system-theme
 %defattr(644,root,root,755)
 
-%files theme-charge
+%files theme-glow
 %defattr(644,root,root,755)
-%dir %{_datadir}/plymouth/themes/charge
-%{_datadir}/plymouth/themes/charge/*.png
-%{_datadir}/plymouth/themes/charge/charge.plymouth
+%dir %{_datadir}/plymouth/themes/glow
+%{_datadir}/plymouth/themes/glow/*.png
+%{_datadir}/plymouth/themes/glow/glow.plymouth
 
 %files theme-fade-in
 %defattr(644,root,root,755)
diff --git a/systemd-ask-password-plymouth.path b/systemd-ask-password-plymouth.path
deleted file mode 100644 (file)
index 9320b4a..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#  This file is part of systemd.
-#
-#  systemd is free software; you can redistribute it and/or modify it
-#  under the terms of the GNU Lesser General Public License as published by
-#  the Free Software Foundation; either version 2.1 of the License, or
-#  (at your option) any later version.
-
-[Unit]
-Description=Forward Password Requests to Plymouth Directory Watch
-Documentation=http://www.freedesktop.org/wiki/Software/systemd/PasswordAgents
-DefaultDependencies=no
-Conflicts=shutdown.target
-After=plymouth-start.service
-Before=basic.target shutdown.target
-ConditionKernelCommandLine=!plymouth.enable=0
-ConditionPathExists=/run/plymouth/pid
-
-[Path]
-DirectoryNotEmpty=/run/systemd/ask-password
-MakeDirectory=yes
diff --git a/systemd-ask-password-plymouth.service b/systemd-ask-password-plymouth.service
deleted file mode 100644 (file)
index 7a9eb07..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#  This file is part of systemd.
-#
-#  systemd is free software; you can redistribute it and/or modify it
-#  under the terms of the GNU Lesser General Public License as published by
-#  the Free Software Foundation; either version 2.1 of the License, or
-#  (at your option) any later version.
-
-[Unit]
-Description=Forward Password Requests to Plymouth
-Documentation=http://www.freedesktop.org/wiki/Software/systemd/PasswordAgents
-DefaultDependencies=no
-Conflicts=shutdown.target
-After=plymouth-start.service
-Before=shutdown.target
-ConditionKernelCommandLine=!plymouth.enable=0
-ConditionPathExists=/run/plymouth/pid
-
-[Service]
-ExecStart=/bin/systemd-tty-ask-password-agent --watch --plymouth
index d4e85980bcdabd1af91acbe82ccdd52fe8e018dd..a14c8f3c8273de8d12874eecad7b5df42844d159 100644 (file)
@@ -1,5 +1,5 @@
---- plymouth-0.8.4/src/plugins/splash/text/plugin.c~   2011-02-09 21:07:14.000000000 +0100
-+++ plymouth-0.8.4/src/plugins/splash/text/plugin.c    2012-04-27 12:56:30.461837997 +0200
+--- plymouth-0.8.4/src/plugins/splash/tribar/plugin.c~ 2011-02-09 21:07:14.000000000 +0100
++++ plymouth-0.8.4/src/plugins/splash/tribar/plugin.c  2012-04-27 12:56:30.461837997 +0200
 @@ -183,10 +183,10 @@
                                      0xffffff);
    ply_terminal_set_color_hex_value (terminal,
  
    ply_text_display_set_background_color (view->display,
                                           PLY_TERMINAL_COLOR_BLACK);
+--- plymouth-0.8.8/src/plugins/splash/text/plugin.c~   2014-04-29 18:42:57.000000000 +0200
++++ plymouth-0.8.8/src/plugins/splash/text/plugin.c    2014-04-29 18:55:53.714017941 +0200
+@@ -177,10 +177,10 @@
+                                     0xffffff);
+   ply_terminal_set_color_hex_value (terminal,
+                                     PLY_TERMINAL_COLOR_BLUE,
+-                                    0x3465a4);
++                                    PLYMOUTH_BACKGROUND_START_COLOR);
+   ply_terminal_set_color_hex_value (terminal,
+                                     PLY_TERMINAL_COLOR_BROWN,
+-                                    0x979a9b);
++                                    PLYMOUTH_BACKGROUND_END_COLOR);
+   ply_text_display_set_background_color (view->display,
+                                          PLY_TERMINAL_COLOR_BLACK);
This page took 1.093662 seconds and 4 git commands to generate.