--- /dev/null
+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