diff options
author | Timo Teräs <timo.teras@iki.fi> | 2017-01-25 21:25:55 +0200 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2017-01-25 19:28:33 +0000 |
commit | e6008f2c4d8a820d9238fbd14236e7f239848041 (patch) | |
tree | d18389e385e13ee8dd8d86568d7516ef80d7bfda | |
parent | d66adb97be094fb7d54436775b65640599fd5176 (diff) | |
download | aports-e6008f2c4d8a820d9238fbd14236e7f239848041.tar.bz2 aports-e6008f2c4d8a820d9238fbd14236e7f239848041.tar.xz |
testing/plymouth: upgrade to git snapshot 20170123
-rw-r--r-- | testing/plymouth/APKBUILD | 22 | ||||
-rw-r--r-- | testing/plymouth/plymouth-git-master-20170123.patch | 5399 |
2 files changed, 5415 insertions, 6 deletions
diff --git a/testing/plymouth/APKBUILD b/testing/plymouth/APKBUILD index 3a797ec59a..0b646bcdc9 100644 --- a/testing/plymouth/APKBUILD +++ b/testing/plymouth/APKBUILD @@ -2,7 +2,7 @@ # Maintainer: Timo Teräs <timo.teras@iki.fi> pkgname=plymouth pkgver=0.9.2 -pkgrel=0 +pkgrel=1 pkgdesc="graphical bootsplash on linux" url="http://www.freedesktop.org/wiki/Software/Plymouth" arch="all" @@ -12,14 +12,21 @@ depends_dev="pango-dev gtk+3.0-dev libpng-dev libdrm-dev" -makedepends="$depends_dev docbook-xsl" +makedepends="$depends_dev docbook-xsl autoconf automake" install="" subpackages="$pkgname-dev $pkgname-doc $pkgname-themes $pkgname-x11:_render $pkgname-drm:_render" source="http://www.freedesktop.org/software/plymouth/releases/plymouth-$pkgver.tar.bz2 - plymouth-rpmatch.patch" + plymouth-rpmatch.patch + plymouth-git-master-20170123.patch + " builddir="$srcdir"/plymouth-$pkgver +prepare() { + default_prepare || return 1 + autoreconf -f -i -s +} + build() { cd "$builddir" ./configure --prefix=/usr \ @@ -51,8 +58,11 @@ _render() { } md5sums="ff420994deb7ea203df678df92e7ab7d plymouth-0.9.2.tar.bz2 -7d342aa2f011833647f1c696007b190c plymouth-rpmatch.patch" +7d342aa2f011833647f1c696007b190c plymouth-rpmatch.patch +d3451ffd12270bdbdaf563c64580addc plymouth-git-master-20170123.patch" sha256sums="2f0ce82042cf9c7eadd2517a1f74c8a85fa8699781d9f294a06eade29fbed57f plymouth-0.9.2.tar.bz2 -2281bffcd64de8c2e675656d21b26b0a74fa997af52e941fe6f356d8d4362e37 plymouth-rpmatch.patch" +2281bffcd64de8c2e675656d21b26b0a74fa997af52e941fe6f356d8d4362e37 plymouth-rpmatch.patch +cdbaa71a099bbb75d669db0c581770611ebd82dc5506ae7934cb4b64afdbd7bb plymouth-git-master-20170123.patch" sha512sums="89356eb8326504fbf3155de262ce15de0847f0a0e6d157d873cf1dea9af464a6cb9e11d7143ee9a595b217a2487060b5835eba5ac142c3cd6d66689deb272e60 plymouth-0.9.2.tar.bz2 -ec1c32ddf7ee418ef1b5d173040db464193d9bca3fd85d5c3a8d2ee13ba1218947f7c9f39c403d3ccced70be28b2c7328e82dc8f967e9bdeea1651dee4be2dc7 plymouth-rpmatch.patch" +ec1c32ddf7ee418ef1b5d173040db464193d9bca3fd85d5c3a8d2ee13ba1218947f7c9f39c403d3ccced70be28b2c7328e82dc8f967e9bdeea1651dee4be2dc7 plymouth-rpmatch.patch +6545c29190b9cf04df0284a73c26ec7d14fddf2c4d7a8f3dff5242b49fafda24ee2aeab54b44b19deb9228707816b6b3779ea8bec7b742020cb1f7e2ca64b509 plymouth-git-master-20170123.patch" diff --git a/testing/plymouth/plymouth-git-master-20170123.patch b/testing/plymouth/plymouth-git-master-20170123.patch new file mode 100644 index 0000000000..6ab412fa5d --- /dev/null +++ b/testing/plymouth/plymouth-git-master-20170123.patch @@ -0,0 +1,5399 @@ +diff --git a/Makefile.am b/Makefile.am +index 395c91b..cb6eedb 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -4,7 +4,7 @@ if BUILD_DOCUMENTATION + SUBDIRS += docs + endif + +-DISTCHECK_CONFIGURE_FLAGS = --disable-tests --without-system-root-install ++DISTCHECK_CONFIGURE_FLAGS = --disable-tests --disable-systemd-integration + + EXTRA_DIST = ChangeLog \ + README +diff --git a/configure.ac b/configure.ac +index aad673e..d145c69 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1,4 +1,4 @@ +-AC_INIT([plymouth],[0.9.2],[https://bugs.freedesktop.org/enter_bug.cgi?product=plymouth]) ++AC_INIT([plymouth],[0.9.3],[https://bugs.freedesktop.org/enter_bug.cgi?product=plymouth]) + AC_CONFIG_SRCDIR(src/main.c) + AC_CONFIG_HEADER(config.h) + AC_CONFIG_AUX_DIR(build-tools) +@@ -11,7 +11,7 @@ AM_PROG_CC_C_O + AC_HEADER_STDC + AC_C_CONST + +-AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip]) ++AM_INIT_AUTOMAKE([dist-xz no-dist-gzip]) + m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + AM_MAINTAINER_MODE([enable]) + +@@ -38,9 +38,18 @@ 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) ++AC_ARG_WITH(udev, AS_HELP_STRING([--with-udev], [Add udev support]),, with_udev=yes) ++ ++if test "x$with_udev" != "xno" ; then ++ PKG_CHECK_MODULES(UDEV, [libudev], have_udev=yes, have_udev=no) ++ AC_SUBST(UDEV_CFLAGS) ++ AC_SUBST(UDEV_LIBS) ++ if test "x$have_udev" = "xyes"; then ++ AC_DEFINE(HAVE_UDEV, 1, [Define if have udev support]) ++ else ++ AC_MSG_ERROR([libudev is required unless --without-udev is passed]) ++ fi ++fi + + PLYMOUTH_CFLAGS="" + PLYMOUTH_LIBS="-lm -lrt -ldl" +@@ -117,16 +126,21 @@ if test x$enable_upstart_monitoring = xyes; then + fi + AM_CONDITIONAL(ENABLE_UPSTART_MONITORING, [test "$enable_upstart_monitoring" = yes]) + +-AC_ARG_ENABLE(systemd-integration, AS_HELP_STRING([--enable-systemd-integration],[coordinate boot up with systemd]),enable_systemd_integration=$enableval,enable_systemd_integration=no) ++AC_ARG_ENABLE(systemd-integration, AS_HELP_STRING([--enable-systemd-integration],[coordinate boot up with systemd]),enable_systemd_integration=$enableval,enable_systemd_integration=yes) + AM_CONDITIONAL(ENABLE_SYSTEMD_INTEGRATION, [test "$enable_systemd_integration" = yes]) + + if test x$enable_systemd_integration = xyes; then + AC_DEFINE(PLY_ENABLE_SYSTEMD_INTEGRATION, 1, [Coordinate boot up with systemd]) +- SYSTEMD_UNIT_DIR=$($PKG_CONFIG --variable=systemdsystemunitdir systemd) ++ AC_ARG_WITH([systemdunitdir], AC_HELP_STRING([--with-systemdunitdir=DIR], ++ [path to systemd service directory]), [path_systemdunit=${withval}], ++ [path_systemdunit="`$PKG_CONFIG --variable=systemdsystemunitdir systemd`"]) ++ if (test -n "${path_systemdunit}"); then ++ SYSTEMD_UNIT_DIR="${path_systemdunit}" ++ fi + AC_SUBST(SYSTEMD_UNIT_DIR) + fi + +-AC_ARG_WITH(system-root-install, AS_HELP_STRING([--with-system-root-install],[Install client in /bin and daemon in /sbin]),with_system_root_install=${withval},with_system_root_install=yes) ++AC_ARG_WITH(system-root-install, AS_HELP_STRING([--with-system-root-install],[Install client in /bin and daemon in /sbin]),with_system_root_install=${withval},with_system_root_install=no) + AM_CONDITIONAL(WITH_SYSTEM_ROOT_INSTALL, [test "$with_system_root_install" = yes]) + + if test x$with_system_root_install = xyes; then +diff --git a/scripts/plymouth-populate-initrd.in b/scripts/plymouth-populate-initrd.in +index 43c7f22..e3326e9 100755 +--- a/scripts/plymouth-populate-initrd.in ++++ b/scripts/plymouth-populate-initrd.in +@@ -392,6 +392,9 @@ fi + if [ $THEME_OVERRIDE ]; then + conf=$INITRDDIR/${PLYMOUTH_CONFDIR}/plymouthd.conf + echo "modifying plymouthd.conf: Theme=$PLYMOUTH_THEME_NAME" > /dev/stderr ++ # make sure the section and key exist so we can modify them ++ grep -q "^ *\[Daemon\]" $conf || echo "[Daemon]" >> $conf ++ grep -q "^ *Theme *=" $conf || echo "Theme=fade-in" >> $conf + sed -i "s/^ *Theme *=.*/# theme modified by plymouth-populate-initrd\nTheme=$PLYMOUTH_THEME_NAME/" $conf + fi + +diff --git a/src/libply-splash-core/Makefile.am b/src/libply-splash-core/Makefile.am +index d07d7f1..7036569 100644 +--- a/src/libply-splash-core/Makefile.am ++++ b/src/libply-splash-core/Makefile.am +@@ -21,7 +21,6 @@ libply_splash_core_HEADERS = \ + 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 \ +@@ -47,7 +46,6 @@ libply_splash_core_la_SOURCES = \ + 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 310d4d5..87a7a0c 100644 +--- a/src/libply-splash-core/ply-boot-splash.c ++++ b/src/libply-splash-core/ply-boot-splash.c +@@ -57,7 +57,10 @@ struct _ply_boot_splash + ply_boot_splash_mode_t mode; + ply_buffer_t *boot_buffer; + ply_trigger_t *idle_trigger; +- ply_list_t *seats; ++ ++ ply_keyboard_t *keyboard; ++ ply_list_t *pixel_displays; ++ ply_list_t *text_displays; + + char *theme_path; + char *plugin_dir; +@@ -94,160 +97,102 @@ ply_boot_splash_new (const char *theme_path, + splash->mode = PLY_BOOT_SPLASH_MODE_INVALID; + + splash->boot_buffer = boot_buffer; +- splash->seats = ply_list_new (); ++ splash->pixel_displays = ply_list_new (); ++ splash->text_displays = ply_list_new (); + + return splash; + } + +-static void +-detach_from_seat (ply_boot_splash_t *splash, +- ply_seat_t *seat) ++void ++ply_boot_splash_set_keyboard (ply_boot_splash_t *splash, ++ ply_keyboard_t *keyboard) + { +- ply_keyboard_t *keyboard; +- ply_list_t *displays; +- ply_list_node_t *node, *next_node; +- +- 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; +- ply_list_node_t *next_node; +- unsigned long width, height; +- +- display = ply_list_node_get_data (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_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; +- } +- +- 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; +- int number_of_columns, number_of_rows; +- +- display = ply_list_node_get_data (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_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); ++ if (splash->plugin_interface->set_keyboard == NULL) ++ return; + +- node = next_node; +- } ++ splash->plugin_interface->set_keyboard (splash->plugin, keyboard); ++ splash->keyboard = keyboard; + } + +-static void +-attach_to_seat (ply_boot_splash_t *splash, +- ply_seat_t *seat) ++void ++ply_boot_splash_unset_keyboard (ply_boot_splash_t *splash) + { +- ply_keyboard_t *keyboard; +- ply_list_t *displays; +- ply_list_node_t *node, *next_node; +- +- if (splash->plugin_interface->set_keyboard != NULL) { +- keyboard = ply_seat_get_keyboard (seat); +- splash->plugin_interface->set_keyboard (splash->plugin, keyboard); +- } +- +- if (splash->plugin_interface->add_pixel_display != NULL) { +- displays = ply_seat_get_pixel_displays (seat); +- +- 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; +- +- display = ply_list_node_get_data (node); +- next_node = ply_list_get_next_node (displays, node); ++ if (splash->plugin_interface->unset_keyboard == NULL) ++ return; + +- width = ply_pixel_display_get_width (display); +- height = ply_pixel_display_get_height (display); ++ splash->plugin_interface->unset_keyboard (splash->plugin, splash->keyboard); ++} + +- ply_trace ("Adding %lux%lu pixel display", width, height); ++void ++ply_boot_splash_add_pixel_display (ply_boot_splash_t *splash, ++ ply_pixel_display_t *display) ++{ ++ unsigned long width, height; + +- splash->plugin_interface->add_pixel_display (splash->plugin, display); ++ if (splash->plugin_interface->add_pixel_display == NULL) ++ return; + +- node = next_node; +- } +- } ++ width = ply_pixel_display_get_width (display); ++ height = ply_pixel_display_get_height (display); + +- if (splash->plugin_interface->add_text_display != NULL) { +- displays = ply_seat_get_text_displays (seat); ++ ply_trace ("adding %lux%lu pixel display", width, height); + +- 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; ++ splash->plugin_interface->add_pixel_display (splash->plugin, display); ++ ply_list_append_data (splash->pixel_displays, display); ++} + +- display = ply_list_node_get_data (node); +- next_node = ply_list_get_next_node (displays, node); ++void ++ply_boot_splash_remove_pixel_display (ply_boot_splash_t *splash, ++ ply_pixel_display_t *display) ++{ ++ unsigned long width, height; + +- number_of_columns = ply_text_display_get_number_of_columns (display); +- number_of_rows = ply_text_display_get_number_of_rows (display); ++ if (splash->plugin_interface->remove_pixel_display == NULL) ++ return; + +- ply_trace ("Adding %dx%d text display", number_of_columns, number_of_rows); ++ width = ply_pixel_display_get_width (display); ++ height = ply_pixel_display_get_height (display); + +- splash->plugin_interface->add_text_display (splash->plugin, display); ++ ply_trace ("removing %lux%lu pixel display", width, height); + +- node = next_node; +- } +- } ++ splash->plugin_interface->remove_pixel_display (splash->plugin, display); ++ ply_list_remove_data (splash->pixel_displays, display); + } + + void +-ply_boot_splash_attach_to_seat (ply_boot_splash_t *splash, +- ply_seat_t *seat) ++ply_boot_splash_add_text_display (ply_boot_splash_t *splash, ++ ply_text_display_t *display) + { +- ply_list_node_t *node; ++ int number_of_columns, number_of_rows; + +- node = ply_list_find_node (splash->seats, seat); +- +- if (node != NULL) ++ if (splash->plugin_interface->add_text_display == NULL) + return; + +- ply_list_append_data (splash->seats, seat); +- attach_to_seat (splash, seat); ++ number_of_columns = ply_text_display_get_number_of_columns (display); ++ number_of_rows = ply_text_display_get_number_of_rows (display); ++ ++ ply_trace ("adding %dx%d text display", number_of_columns, number_of_rows); ++ ++ splash->plugin_interface->add_text_display (splash->plugin, display); ++ ply_list_append_data (splash->text_displays, display); + } + + void +-ply_boot_splash_detach_from_seat (ply_boot_splash_t *splash, +- ply_seat_t *seat) ++ply_boot_splash_remove_text_display (ply_boot_splash_t *splash, ++ ply_text_display_t *display) + { +- ply_list_node_t *node; +- +- node = ply_list_find_node (splash->seats, seat); ++ int number_of_columns, number_of_rows; + +- if (node == NULL) ++ if (splash->plugin_interface->remove_text_display == NULL) + return; + +- ply_list_remove_data (splash->seats, seat); +- detach_from_seat (splash, seat); ++ 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); ++ ++ splash->plugin_interface->remove_text_display (splash->plugin, display); ++ ply_list_remove_data (splash->text_displays, display); + } + + bool +@@ -378,23 +323,60 @@ ply_boot_splash_unload (ply_boot_splash_t *splash) + } + + static void +-detach_from_seats (ply_boot_splash_t *splash) ++remove_pixel_displays (ply_boot_splash_t *splash) ++{ ++ ply_list_node_t *node; ++ ++ if (splash->plugin_interface->remove_pixel_display == NULL) ++ return; ++ ++ ply_trace ("removing pixel displays"); ++ ++ node = ply_list_get_first_node (splash->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 (splash->pixel_displays, node); ++ ++ width = ply_pixel_display_get_width (display); ++ height = ply_pixel_display_get_height (display); ++ ++ ply_trace ("Removing %lux%lu pixel display", width, height); ++ ++ splash->plugin_interface->remove_pixel_display (splash->plugin, display); ++ ++ node = next_node; ++ } ++} ++ ++static void ++remove_text_displays (ply_boot_splash_t *splash) + { + ply_list_node_t *node; + +- ply_trace ("detaching from seats"); ++ if (splash->plugin_interface->remove_text_display == NULL) ++ return; ++ ++ ply_trace ("removing text displays"); + +- node = ply_list_get_first_node (splash->seats); ++ node = ply_list_get_first_node (splash->text_displays); + while (node != NULL) { +- ply_seat_t *seat; ++ ply_text_display_t *display; + ply_list_node_t *next_node; ++ int number_of_columns, number_of_rows; + +- seat = ply_list_node_get_data (node); +- next_node = ply_list_get_next_node (splash->seats, node); ++ display = ply_list_node_get_data (node); ++ next_node = ply_list_get_next_node (splash->text_displays, node); + +- detach_from_seat (splash, seat); ++ 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); + +- ply_list_remove_node (splash->seats, node); ++ splash->plugin_interface->remove_text_display (splash->plugin, display); + + node = next_node; + } +@@ -419,11 +401,17 @@ ply_boot_splash_free (ply_boot_splash_t *splash) + splash); + } + +- detach_from_seats (splash); +- ply_list_free (splash->seats); ++ if (splash->module_handle != NULL) { ++ ply_boot_splash_unset_keyboard (splash); ++ ++ remove_pixel_displays (splash); ++ ply_list_free (splash->pixel_displays); ++ ++ remove_text_displays (splash); ++ ply_list_free (splash->text_displays); + +- if (splash->module_handle != NULL) + ply_boot_splash_unload (splash); ++ } + + if (splash->idle_trigger != NULL) + ply_trigger_free (splash->idle_trigger); +diff --git a/src/libply-splash-core/ply-boot-splash.h b/src/libply-splash-core/ply-boot-splash.h +index 0ad6f22..b66ca47 100644 +--- a/src/libply-splash-core/ply-boot-splash.h ++++ b/src/libply-splash-core/ply-boot-splash.h +@@ -33,12 +33,10 @@ + #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); + +@@ -50,10 +48,17 @@ 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_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_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 *pixel_display); ++void ply_boot_splash_remove_pixel_display (ply_boot_splash_t *splash, ++ ply_pixel_display_t *pixel_display); ++void ply_boot_splash_add_text_display (ply_boot_splash_t *splash, ++ ply_text_display_t *text_display); ++void ply_boot_splash_remove_text_display (ply_boot_splash_t *splash, ++ ply_text_display_t *text_display); + 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 +index 67eba32..b4c33d4 100644 +--- a/src/libply-splash-core/ply-device-manager.c ++++ b/src/libply-splash-core/ply-device-manager.c +@@ -30,7 +30,9 @@ + #include <sys/stat.h> + #include <sys/types.h> + ++#ifdef HAVE_UDEV + #include <libudev.h> ++#endif + + #include "ply-logger.h" + #include "ply-event-loop.h" +@@ -41,27 +43,40 @@ + #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); ++#ifdef HAVE_UDEV ++static void create_devices_from_udev (ply_device_manager_t *manager); ++#endif ++ ++static void create_devices_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_hashtable_t *renderers; + ply_terminal_t *local_console_terminal; +- ply_seat_t *local_console_seat; +- ply_list_t *seats; ++ ply_list_t *keyboards; ++ ply_list_t *text_displays; ++ ply_list_t *pixel_displays; + 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; ++ ply_keyboard_added_handler_t keyboard_added_handler; ++ ply_keyboard_removed_handler_t keyboard_removed_handler; ++ ply_pixel_display_added_handler_t pixel_display_added_handler; ++ ply_pixel_display_removed_handler_t pixel_display_removed_handler; ++ ply_text_display_added_handler_t text_display_added_handler; ++ ply_text_display_removed_handler_t text_display_removed_handler; ++ void *event_handler_data; ++ ++ uint32_t local_console_managed : 1; ++ uint32_t local_console_is_text : 1; ++ uint32_t serial_consoles_detected : 1; ++ uint32_t renderers_activated : 1; ++ uint32_t keyboards_activated : 1; + }; + + static void +@@ -87,64 +102,66 @@ attach_to_event_loop (ply_device_manager_t *manager, + 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 +-drm_device_in_use (ply_device_manager_t *manager, +- const char *device_path) ++static void ++free_displays_for_renderer (ply_device_manager_t *manager, ++ ply_renderer_t *renderer) + { + ply_list_node_t *node; + +- node = ply_list_get_first_node (manager->seats); ++ node = ply_list_get_first_node (manager->pixel_displays); + while (node != NULL) { +- ply_seat_t *seat; +- ply_renderer_t *renderer; + ply_list_node_t *next_node; +- const char *renderer_device_path; ++ ply_pixel_display_t *display; ++ ply_renderer_t *display_renderer; + +- seat = ply_list_node_get_data (node); +- next_node = ply_list_get_next_node (manager->seats, node); +- renderer = ply_seat_get_renderer (seat); ++ display = ply_list_node_get_data (node); ++ next_node = ply_list_get_next_node (manager->pixel_displays, node); ++ display_renderer = ply_pixel_display_get_renderer (display); + +- if (renderer != NULL) { +- renderer_device_path = ply_renderer_get_device_name (renderer); ++ if (display_renderer == renderer) { ++ if (manager->pixel_display_removed_handler != NULL) ++ manager->pixel_display_removed_handler (manager->event_handler_data, display); ++ ply_pixel_display_free (display); ++ ply_list_remove_node (manager->pixel_displays, node); + +- if (renderer_device_path != NULL) { +- if (strcmp (device_path, renderer_device_path) == 0) { +- return true; +- } +- } + } + + node = next_node; + } ++} + +- return false; ++static void ++free_devices_from_device_path (ply_device_manager_t *manager, ++ const char *device_path) ++{ ++ char *key = NULL; ++ ply_renderer_t *renderer = NULL; ++ ++ ply_hashtable_lookup_full (manager->renderers, ++ (void *) device_path, ++ (void **) &key, ++ (void **) &renderer); ++ ++ if (renderer == NULL) ++ return; ++ ++ free_displays_for_renderer (manager, renderer); ++ ++ ply_hashtable_remove (manager->renderers, (void *) device_path); ++ free (key); ++ ply_renderer_free (renderer); ++} ++ ++#ifdef HAVE_UDEV ++static bool ++drm_device_in_use (ply_device_manager_t *manager, ++ const char *device_path) ++{ ++ ply_renderer_t *renderer; ++ ++ renderer = ply_hashtable_lookup (manager->renderers, (void *) device_path); ++ ++ return renderer != NULL; + } + + static bool +@@ -196,19 +213,10 @@ fb_device_has_drm_device (ply_device_manager_t *manager, + } + + static void +-create_seat_for_udev_device (ply_device_manager_t *manager, +- struct udev_device *device) ++create_devices_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); + +@@ -231,7 +239,13 @@ create_seat_for_udev_device (ply_device_manager_t *manager, + } + + if (renderer_type != PLY_RENDERER_TYPE_NONE) { +- create_seat_for_terminal_and_renderer_type (manager, ++ ply_terminal_t *terminal = NULL; ++ ++ if (!manager->local_console_managed) { ++ terminal = manager->local_console_terminal; ++ } ++ ++ create_devices_for_terminal_and_renderer_type (manager, + device_path, + terminal, + renderer_type); +@@ -240,64 +254,26 @@ create_seat_for_udev_device (ply_device_manager_t *manager, + } + + 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) ++free_devices_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); ++ free_devices_from_device_path (manager, device_path); + } + + static bool +-create_seats_for_subsystem (ply_device_manager_t *manager, +- const char *subsystem) ++create_devices_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", ++ ply_trace ("creating objects for %s devices", + strcmp (subsystem, SUBSYSTEM_FRAME_BUFFER) == 0 ? + "frame buffer" : + subsystem); +@@ -326,7 +302,7 @@ create_seats_for_subsystem (ply_device_manager_t *manager, + if (udev_device_get_is_initialized (device)) { + ply_trace ("device is initialized"); + +- /* We only care about devices assigned to a (any) seat. Floating ++ /* We only care about devices assigned to a (any) devices. Floating + * devices should be ignored. + */ + if (udev_device_has_tag (device, "seat")) { +@@ -335,10 +311,10 @@ create_seats_for_subsystem (ply_device_manager_t *manager, + if (node != NULL) { + ply_trace ("found node %s", node); + found_device = true; +- create_seat_for_udev_device (manager, device); ++ create_devices_for_udev_device (manager, device); + } + } else { +- ply_trace ("device doesn't have a seat tag"); ++ ply_trace ("device doesn't have a devices tag"); + } + } else { + ply_trace ("it's not initialized"); +@@ -371,17 +347,19 @@ on_udev_event (ply_device_manager_t *manager) + + 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); ++ if (strcmp (subsystem, SUBSYSTEM_DRM) == 0) { ++ if (manager->local_console_managed && manager->local_console_is_text) ++ ply_trace ("ignoring since we're already using text splash for local console"); ++ else ++ create_devices_for_udev_device (manager, device); ++ } else { ++ ply_trace ("ignoring since we only handle subsystem %s devices after timeout", subsystem); ++ } + } else if (strcmp (action, "remove") == 0) { +- free_seat_for_udev_device (manager, device); ++ free_devices_for_udev_device (manager, device); + } + + udev_device_unref (device); +@@ -413,30 +391,7 @@ watch_for_udev_events (ply_device_manager_t *manager) + 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; +- } +-} ++#endif + + static void + free_terminal (char *device, +@@ -473,6 +428,10 @@ get_terminal (ply_device_manager_t *manager, + strcmp (full_name, "/dev/tty") == 0 || + strcmp (full_name, ply_terminal_get_name (manager->local_console_terminal)) == 0) { + terminal = manager->local_console_terminal; ++ ++ ply_hashtable_insert (manager->terminals, ++ (void *) ply_terminal_get_name (terminal), ++ terminal); + goto done; + } + +@@ -491,6 +450,23 @@ done: + return terminal; + } + ++static void ++free_renderer (char *device_path, ++ ply_renderer_t *renderer, ++ ply_device_manager_t *manager) ++{ ++ free_devices_from_device_path (manager, device_path); ++} ++ ++static void ++free_renderers (ply_device_manager_t *manager) ++{ ++ ply_hashtable_foreach (manager->renderers, ++ (ply_hashtable_foreach_func_t *) ++ free_renderer, ++ manager); ++} ++ + ply_device_manager_t * + ply_device_manager_new (const char *default_tty, + ply_device_manager_flags_t flags) +@@ -500,15 +476,19 @@ ply_device_manager_new (const char *default_tty, + 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->renderers = 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->keyboards = ply_list_new (); ++ manager->text_displays = ply_list_new (); ++ manager->pixel_displays = ply_list_new (); + manager->flags = flags; + ++#ifdef HAVE_UDEV + if (!(flags & PLY_DEVICE_MANAGER_FLAGS_IGNORE_UDEV)) + manager->udev_context = udev_new (); ++#else ++ manager->flags |= PLY_DEVICE_MANAGER_FLAGS_IGNORE_UDEV; ++#endif + + attach_to_event_loop (manager, ply_event_loop_get_default ()); + +@@ -527,17 +507,24 @@ ply_device_manager_free (ply_device_manager_t *manager) + (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); + ++ free_renderers (manager); ++ ply_hashtable_free (manager->renderers); ++ ++#ifdef HAVE_UDEV ++ ply_event_loop_stop_watching_for_timeout (manager->loop, ++ (ply_event_loop_timeout_handler_t) ++ create_devices_from_udev, manager); ++ + if (manager->udev_monitor != NULL) + udev_monitor_unref (manager->udev_monitor); + + if (manager->udev_context != NULL) + udev_unref (manager->udev_context); ++#endif + + free (manager); + } +@@ -615,53 +602,161 @@ add_consoles_from_file (ply_device_manager_t *manager, + } + + 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) ++create_pixel_displays_for_renderer (ply_device_manager_t *manager, ++ ply_renderer_t *renderer) + { +- ply_seat_t *seat; +- bool is_local_terminal = false; ++ ply_list_t *heads; ++ ply_list_node_t *node; ++ ++ heads = ply_renderer_get_heads (renderer); + +- if (terminal != NULL && manager->local_console_terminal == terminal) +- is_local_terminal = true; ++ 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 (manager->pixel_displays, display); ++ ++ if (manager->pixel_display_added_handler != NULL) ++ manager->pixel_display_added_handler (manager->event_handler_data, display); ++ node = next_node; ++ } ++} ++ ++static void ++create_text_displays_for_terminal (ply_device_manager_t *manager, ++ ply_terminal_t *terminal) ++{ ++ ply_text_display_t *display; + +- if (is_local_terminal && manager->local_console_seat != NULL) { +- ply_trace ("trying to create seat for local console when one already exists"); ++ if (!ply_terminal_is_open (terminal)) { ++ if (!ply_terminal_open (terminal)) { ++ ply_trace ("could not add terminal %s: %m", ++ ply_terminal_get_name (terminal)); ++ return; ++ } ++ } ++ ++ ply_trace ("adding text display for terminal %s", ++ ply_terminal_get_name (terminal)); ++ ++ display = ply_text_display_new (terminal); ++ ply_list_append_data (manager->text_displays, display); ++ ++ if (manager->text_display_added_handler != NULL) ++ manager->text_display_added_handler (manager->event_handler_data, display); ++} ++ ++static void ++create_devices_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_renderer_t *renderer = NULL; ++ ply_keyboard_t *keyboard = NULL; ++ ++ if (device_path != NULL) ++ renderer = ply_hashtable_lookup (manager->renderers, (void *) device_path); ++ ++ if (renderer != NULL) { ++ ply_trace ("ignoring device %s since it's already managed", device_path); + return; + } + +- ply_trace ("creating seat for %s (renderer type: %u) (terminal: %s)", ++ ply_trace ("creating devices 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; ++ if (renderer_type != PLY_RENDERER_TYPE_NONE) { ++ ply_renderer_t *old_renderer = NULL; ++ renderer = ply_renderer_new (renderer_type, device_path, terminal); ++ ++ if (renderer != NULL && !ply_renderer_open (renderer)) { ++ ply_trace ("could not open renderer for %s", device_path); ++ ply_renderer_free (renderer); ++ renderer = NULL; ++ ++ if (renderer_type != PLY_RENDERER_TYPE_AUTO) ++ return; ++ } ++ ++ if (renderer != NULL) { ++ old_renderer = ply_hashtable_lookup (manager->renderers, ++ (void *) ply_renderer_get_device_name (renderer)); ++ ++ if (old_renderer != NULL) { ++ ply_trace ("ignoring device %s since it's alerady managed", ++ ply_renderer_get_device_name (renderer)); ++ ply_renderer_free (renderer); ++ ++ renderer = NULL; ++ return; ++ } ++ } ++ } ++ ++ if (renderer != NULL) { ++ keyboard = ply_keyboard_new_for_renderer (renderer); ++ ply_list_append_data (manager->keyboards, keyboard); ++ ++ if (manager->keyboard_added_handler != NULL) ++ manager->keyboard_added_handler (manager->event_handler_data, keyboard); ++ ++ create_pixel_displays_for_renderer (manager, renderer); ++ ply_hashtable_insert (manager->renderers, strdup (ply_renderer_get_device_name (renderer)), renderer); ++ create_pixel_displays_for_renderer (manager, renderer); ++ ++ if (manager->renderers_activated) { ++ ply_trace ("activating renderer"); ++ ply_renderer_activate (renderer); ++ } ++ ++ if (terminal != NULL) ++ ply_terminal_refresh_geometry (terminal); ++ } else if (terminal != NULL) { ++ keyboard = ply_keyboard_new_for_terminal (terminal); ++ ply_list_append_data (manager->keyboards, keyboard); ++ ++ if (manager->keyboard_added_handler != NULL) ++ manager->keyboard_added_handler (manager->event_handler_data, keyboard); + } + +- ply_list_append_data (manager->seats, seat); ++ if (terminal != NULL) { ++ create_text_displays_for_terminal (manager, terminal); + +- if (is_local_terminal) +- manager->local_console_seat = seat; ++ if (terminal == manager->local_console_terminal) { ++ manager->local_console_is_text = renderer == NULL; ++ manager->local_console_managed = true; ++ } ++ } + +- if (manager->seat_added_handler != NULL) +- manager->seat_added_handler (manager->seat_event_handler_data, seat); ++ if (keyboard != NULL && manager->keyboards_activated) { ++ ply_trace ("activating keyboards"); ++ ply_keyboard_watch_for_input (keyboard); ++ } + } + + static void +-create_seat_for_terminal (const char *device_path, +- ply_terminal_t *terminal, +- ply_device_manager_t *manager) ++create_devices_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); ++ create_devices_for_terminal_and_renderer_type (manager, ++ NULL, ++ terminal, ++ PLY_RENDERER_TYPE_NONE); + } + static bool +-create_seats_from_terminals (ply_device_manager_t *manager) ++create_devices_from_terminals (ply_device_manager_t *manager) + { + bool has_serial_consoles; + +@@ -676,9 +771,11 @@ create_seats_from_terminals (ply_device_manager_t *manager) + + if (has_serial_consoles) { + ply_trace ("serial consoles detected, managing them with details forced"); ++ manager->serial_consoles_detected = true; ++ + ply_hashtable_foreach (manager->terminals, + (ply_hashtable_foreach_func_t *) +- create_seat_for_terminal, ++ create_devices_for_terminal, + manager); + return true; + } +@@ -686,145 +783,104 @@ create_seats_from_terminals (ply_device_manager_t *manager) + return false; + } + ++#ifdef HAVE_UDEV + static void +-create_seats_from_udev (ply_device_manager_t *manager) ++create_devices_from_udev (ply_device_manager_t *manager) + { + bool found_drm_device, found_fb_device; + +- ply_trace ("Looking for devices from udev"); ++ ply_trace ("Timeout elapsed, 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); ++ found_drm_device = create_devices_for_subsystem (manager, SUBSYSTEM_DRM); ++ found_fb_device = create_devices_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); ++ ply_trace ("Creating non-graphical devices, since there's no suitable graphics hardware"); ++ create_devices_for_terminal_and_renderer_type (manager, ++ NULL, ++ manager->local_console_terminal, ++ PLY_RENDERER_TYPE_NONE); + } ++#endif + + static void +-on_udev_queue_changed (ply_device_manager_t *manager) ++create_fallback_devices (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| IN_DELETE); +- +- 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); ++ create_devices_for_terminal_and_renderer_type (manager, ++ NULL, ++ manager->local_console_terminal, ++ PLY_RENDERER_TYPE_AUTO); + } + + 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 ++ply_device_manager_watch_devices (ply_device_manager_t *manager, ++ double device_timeout, ++ ply_keyboard_added_handler_t keyboard_added_handler, ++ ply_keyboard_removed_handler_t keyboard_removed_handler, ++ ply_pixel_display_added_handler_t pixel_display_added_handler, ++ ply_pixel_display_removed_handler_t pixel_display_removed_handler, ++ ply_text_display_added_handler_t text_display_added_handler, ++ ply_text_display_removed_handler_t text_display_removed_handler, ++ void *data) ++{ ++ bool done_with_initial_devices_setup; ++ ++ manager->keyboard_added_handler = keyboard_added_handler; ++ manager->keyboard_removed_handler = keyboard_removed_handler; ++ manager->pixel_display_added_handler = pixel_display_added_handler; ++ manager->pixel_display_removed_handler = pixel_display_removed_handler; ++ manager->text_display_added_handler = text_display_added_handler; ++ manager->text_display_removed_handler = text_display_removed_handler; ++ manager->event_handler_data = data; ++ ++ /* Try to create devices for each serial device right away, if possible + */ +- done_with_initial_seat_setup = create_seats_from_terminals (manager); ++ done_with_initial_devices_setup = create_devices_from_terminals (manager); + +- if (done_with_initial_seat_setup) ++ if (done_with_initial_devices_setup) + return; + + if ((manager->flags & PLY_DEVICE_MANAGER_FLAGS_IGNORE_UDEV)) { +- ply_trace ("udev support disabled, creating fallback seat"); +- create_fallback_seat (manager); ++ ply_trace ("udev support disabled, creating fallback devices"); ++ create_fallback_devices (manager); + return; + } + ++#ifdef HAVE_UDEV + watch_for_udev_events (manager); +- watch_for_coldplug_completion (manager); ++ create_devices_for_subsystem (manager, SUBSYSTEM_DRM); ++ ply_event_loop_watch_for_timeout (manager->loop, ++ device_timeout, ++ (ply_event_loop_timeout_handler_t) ++ create_devices_from_udev, manager); ++#endif + } + + bool +-ply_device_manager_has_open_seats (ply_device_manager_t *manager) ++ply_device_manager_has_displays (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; ++ return ply_list_get_length (manager->pixel_displays) > 0 || ++ ply_list_get_length (manager->text_displays) > 0; ++} + +- node = next_node; +- } ++ply_list_t * ++ply_device_manager_get_keyboards (ply_device_manager_t *manager) ++{ ++ return manager->keyboards; ++} + +- return false; ++ply_list_t * ++ply_device_manager_get_pixel_displays (ply_device_manager_t *manager) ++{ ++ return manager->pixel_displays; + } + + ply_list_t * +-ply_device_manager_get_seats (ply_device_manager_t *manager) ++ply_device_manager_get_text_displays (ply_device_manager_t *manager) + { +- return manager->seats; ++ return manager->text_displays; + } + + ply_terminal_t * +@@ -833,44 +889,49 @@ ply_device_manager_get_default_terminal (ply_device_manager_t *manager) + return manager->local_console_terminal; + } + ++bool ++ply_device_manager_has_serial_consoles (ply_device_manager_t *manager) ++{ ++ return manager->serial_consoles_detected; ++} ++ ++static void ++activate_renderer (char *device_path, ++ ply_renderer_t *renderer, ++ ply_device_manager_t *manager) ++{ ++ ply_renderer_activate (renderer); ++} ++ + 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_hashtable_foreach (manager->renderers, ++ (ply_hashtable_foreach_func_t *) ++ activate_renderer, ++ manager); + +- ply_seat_activate_renderer (seat); ++ manager->renderers_activated = true; ++} + +- node = next_node; +- } ++static void ++deactivate_renderer (char *device_path, ++ ply_renderer_t *renderer, ++ ply_device_manager_t *manager) ++{ ++ ply_renderer_deactivate (renderer); + } + + 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); ++ ply_hashtable_foreach (manager->renderers, ++ (ply_hashtable_foreach_func_t *) ++ deactivate_renderer, ++ manager); + +- node = next_node; +- } ++ manager->renderers_activated = false; + } + + void +@@ -879,18 +940,20 @@ 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); ++ node = ply_list_get_first_node (manager->keyboards); + while (node != NULL) { +- ply_seat_t *seat; ++ ply_keyboard_t *keyboard; + ply_list_node_t *next_node; + +- seat = ply_list_node_get_data (node); +- next_node = ply_list_get_next_node (manager->seats, node); ++ keyboard = ply_list_node_get_data (node); ++ next_node = ply_list_get_next_node (manager->keyboards, node); + +- ply_seat_activate_keyboard (seat); ++ ply_keyboard_watch_for_input (keyboard); + + node = next_node; + } ++ ++ manager->keyboards_activated = true; + } + + void +@@ -899,16 +962,18 @@ 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); ++ node = ply_list_get_first_node (manager->keyboards); + while (node != NULL) { +- ply_seat_t *seat; ++ ply_keyboard_t *keyboard; + ply_list_node_t *next_node; + +- seat = ply_list_node_get_data (node); +- next_node = ply_list_get_next_node (manager->seats, node); ++ keyboard = ply_list_node_get_data (node); ++ next_node = ply_list_get_next_node (manager->keyboards, node); + +- ply_seat_deactivate_keyboard (seat); ++ ply_keyboard_stop_watching_for_input (keyboard); + + node = next_node; + } ++ ++ manager->keyboards_activated = false; + } +diff --git a/src/libply-splash-core/ply-device-manager.h b/src/libply-splash-core/ply-device-manager.h +index c3e6487..058f6e8 100644 +--- a/src/libply-splash-core/ply-device-manager.h ++++ b/src/libply-splash-core/ply-device-manager.h +@@ -21,7 +21,11 @@ + #define PLY_DEVICE_MANAGER_H + + #include <stdbool.h> +-#include "ply-seat.h" ++ ++#include "ply-keyboard.h" ++#include "ply-pixel-display.h" ++#include "ply-renderer.h" ++#include "ply-text-display.h" + + typedef enum + { +@@ -31,20 +35,30 @@ typedef enum + } 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 *); ++typedef void (* ply_keyboard_added_handler_t) (void *, ply_keyboard_t *); ++typedef void (* ply_keyboard_removed_handler_t) (void *, ply_keyboard_t *); ++typedef void (* ply_pixel_display_added_handler_t) (void *, ply_pixel_display_t *); ++typedef void (* ply_pixel_display_removed_handler_t) (void *, ply_pixel_display_t *); ++typedef void (* ply_text_display_added_handler_t) (void *, ply_text_display_t *); ++typedef void (* ply_text_display_removed_handler_t) (void *, ply_text_display_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_watch_devices (ply_device_manager_t *manager, ++ double device_timeout, ++ ply_keyboard_added_handler_t keyboard_added_handler, ++ ply_keyboard_removed_handler_t keyboard_removed_handler, ++ ply_pixel_display_added_handler_t pixel_display_added_handler, ++ ply_pixel_display_removed_handler_t pixel_display_removed_handler, ++ ply_text_display_added_handler_t text_display_added_handler, ++ ply_text_display_removed_handler_t text_display_removed_handler, ++ void *data); ++bool ply_device_manager_has_serial_consoles (ply_device_manager_t *manager); ++bool ply_device_manager_has_displays (ply_device_manager_t *manager); ++ply_list_t *ply_device_manager_get_keyboards (ply_device_manager_t *manager); ++ply_list_t *ply_device_manager_get_pixel_displays (ply_device_manager_t *manager); ++ply_list_t *ply_device_manager_get_text_displays (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); +diff --git a/src/libply-splash-core/ply-keyboard.c b/src/libply-splash-core/ply-keyboard.c +index ccf08e8..80f7694 100644 +--- a/src/libply-splash-core/ply-keyboard.c ++++ b/src/libply-splash-core/ply-keyboard.c +@@ -93,6 +93,8 @@ struct _ply_keyboard + ply_list_t *backspace_handler_list; + ply_list_t *escape_handler_list; + ply_list_t *enter_handler_list; ++ ++ uint32_t is_active : 1; + }; + + static bool ply_keyboard_watch_for_terminal_input (ply_keyboard_t *keyboard); +@@ -323,6 +325,12 @@ ply_keyboard_stop_watching_for_renderer_input (ply_keyboard_t *keyboard) + keyboard->provider.if_renderer->input_source); + } + ++bool ++ply_keyboard_is_active (ply_keyboard_t *keyboard) ++{ ++ return keyboard->is_active; ++} ++ + static void + on_terminal_data (ply_keyboard_t *keyboard) + { +@@ -369,15 +377,20 @@ ply_keyboard_watch_for_input (ply_keyboard_t *keyboard) + { + assert (keyboard != NULL); + ++ if (keyboard->is_active) ++ return true; ++ + switch (keyboard->provider_type) { + case PLY_KEYBOARD_PROVIDER_TYPE_RENDERER: +- return ply_keyboard_watch_for_renderer_input (keyboard); ++ keyboard->is_active = ply_keyboard_watch_for_renderer_input (keyboard); ++ break; + + case PLY_KEYBOARD_PROVIDER_TYPE_TERMINAL: +- return ply_keyboard_watch_for_terminal_input (keyboard); ++ keyboard->is_active = ply_keyboard_watch_for_terminal_input (keyboard); ++ break; + } + +- return false; ++ return keyboard->is_active; + } + + void +@@ -385,6 +398,9 @@ ply_keyboard_stop_watching_for_input (ply_keyboard_t *keyboard) + { + assert (keyboard != NULL); + ++ if (!keyboard->is_active) ++ return; ++ + switch (keyboard->provider_type) { + case PLY_KEYBOARD_PROVIDER_TYPE_RENDERER: + ply_keyboard_stop_watching_for_renderer_input (keyboard); +@@ -394,6 +410,8 @@ ply_keyboard_stop_watching_for_input (ply_keyboard_t *keyboard) + ply_keyboard_stop_watching_for_terminal_input (keyboard); + break; + } ++ ++ keyboard->is_active = false; + } + + void +diff --git a/src/libply-splash-core/ply-keyboard.h b/src/libply-splash-core/ply-keyboard.h +index 23497d9..6147cc7 100644 +--- a/src/libply-splash-core/ply-keyboard.h ++++ b/src/libply-splash-core/ply-keyboard.h +@@ -71,6 +71,7 @@ void ply_keyboard_remove_enter_handler (ply_keyboard_t *keyboard, + + bool ply_keyboard_watch_for_input (ply_keyboard_t *keyboard); + void ply_keyboard_stop_watching_for_input (ply_keyboard_t *keyboard); ++bool ply_keyboard_is_active (ply_keyboard_t *keyboard); + + #endif + +diff --git a/src/libply-splash-core/ply-pixel-buffer.c b/src/libply-splash-core/ply-pixel-buffer.c +index c1825cc..52a3f86 100644 +--- a/src/libply-splash-core/ply-pixel-buffer.c ++++ b/src/libply-splash-core/ply-pixel-buffer.c +@@ -37,14 +37,19 @@ + #include <stdlib.h> + #include <unistd.h> + ++#define ALPHA_MASK 0xff000000 ++ + struct _ply_pixel_buffer + { + uint32_t *bytes; + +- ply_rectangle_t area; +- ply_list_t *clip_areas; ++ ply_rectangle_t area; /* in device pixels */ ++ ply_rectangle_t logical_area; /* in logical pixels */ ++ ply_list_t *clip_areas; /* in device pixels */ + +- ply_region_t *updated_areas; ++ ply_region_t *updated_areas; /* in device pixels */ ++ uint32_t is_opaque : 1; ++ int device_scale; + }; + + static inline void ply_pixel_buffer_blend_value_at_pixel (ply_pixel_buffer_t *buffer, +@@ -166,6 +171,34 @@ ply_pixel_buffer_blend_value_at_pixel (ply_pixel_buffer_t *buffer, + } + + static void ++ply_rectangle_upscale (ply_rectangle_t *area, ++ int scale) ++{ ++ area->x *= scale; ++ area->y *= scale; ++ area->width *= scale; ++ area->height *= scale; ++} ++ ++static void ++ply_rectangle_downscale (ply_rectangle_t *area, ++ int scale) ++{ ++ area->x /= scale; ++ area->y /= scale; ++ area->width /= scale; ++ area->height /= scale; ++} ++ ++static void ++ply_pixel_buffer_adjust_area_for_device_scale (ply_pixel_buffer_t *buffer, ++ ply_rectangle_t *area) ++{ ++ ply_rectangle_upscale (area, buffer->device_scale); ++} ++ ++/* this function will also convert logical pixels to device pixels */ ++static void + ply_pixel_buffer_crop_area_to_clip_area (ply_pixel_buffer_t *buffer, + ply_rectangle_t *area, + ply_rectangle_t *cropped_area) +@@ -173,6 +206,7 @@ ply_pixel_buffer_crop_area_to_clip_area (ply_pixel_buffer_t *buffer, + ply_list_node_t *node; + + *cropped_area = *area; ++ ply_pixel_buffer_adjust_area_for_device_scale (buffer, cropped_area); + + node = ply_list_get_first_node (buffer->clip_areas); + while (node != NULL) { +@@ -196,8 +230,19 @@ ply_pixel_buffer_fill_area_with_pixel_value (ply_pixel_buffer_t *buffer, + unsigned long row, column; + ply_rectangle_t cropped_area; + ++ if (fill_area == NULL) ++ fill_area = &buffer->logical_area; ++ + ply_pixel_buffer_crop_area_to_clip_area (buffer, fill_area, &cropped_area); + ++ /* If we're filling the entire buffer with a fully opaque color, ++ * then make note of it ++ */ ++ if (fill_area == &buffer->area && ++ (pixel_value >> 24) == 0xff) { ++ buffer->is_opaque = true; ++ } ++ + for (row = cropped_area.y; row < cropped_area.y + cropped_area.height; row++) { + for (column = cropped_area.x; column < cropped_area.x + cropped_area.width; column++) { + ply_pixel_buffer_blend_value_at_pixel (buffer, +@@ -205,6 +250,8 @@ ply_pixel_buffer_fill_area_with_pixel_value (ply_pixel_buffer_t *buffer, + pixel_value); + } + } ++ ++ ply_region_add_rectangle (buffer->updated_areas, &cropped_area); + } + + void +@@ -216,6 +263,8 @@ ply_pixel_buffer_push_clip_area (ply_pixel_buffer_t *buffer, + new_clip_area = malloc (sizeof(*new_clip_area)); + + *new_clip_area = *clip_area; ++ ply_pixel_buffer_adjust_area_for_device_scale (buffer, new_clip_area); ++ + ply_list_append_data (buffer->clip_areas, new_clip_area); + } + +@@ -241,9 +290,12 @@ ply_pixel_buffer_new (unsigned long width, + buffer->bytes = (uint32_t *) calloc (height, width * sizeof(uint32_t)); + buffer->area.width = width; + buffer->area.height = height; ++ buffer->logical_area = buffer->area; ++ buffer->device_scale = 1; + + buffer->clip_areas = ply_list_new (); + ply_pixel_buffer_push_clip_area (buffer, &buffer->area); ++ buffer->is_opaque = false; + + return buffer; + } +@@ -278,21 +330,36 @@ ply_pixel_buffer_get_size (ply_pixel_buffer_t *buffer, + assert (buffer != NULL); + assert (size != NULL); + +- *size = buffer->area; ++ *size = buffer->logical_area; + } + + unsigned long + ply_pixel_buffer_get_width (ply_pixel_buffer_t *buffer) + { + assert (buffer != NULL); +- return buffer->area.width; ++ return buffer->logical_area.width; + } + + unsigned long + ply_pixel_buffer_get_height (ply_pixel_buffer_t *buffer) + { + assert (buffer != NULL); +- return buffer->area.height; ++ return buffer->logical_area.height; ++} ++ ++bool ++ply_pixel_buffer_is_opaque (ply_pixel_buffer_t *buffer) ++{ ++ assert (buffer != NULL); ++ return buffer->is_opaque; ++} ++ ++void ++ply_pixel_buffer_set_opaque (ply_pixel_buffer_t *buffer, ++ bool is_opaque) ++{ ++ assert (buffer != NULL); ++ buffer->is_opaque = is_opaque; + } + + ply_region_t * +@@ -359,7 +426,7 @@ ply_pixel_buffer_fill_with_gradient (ply_pixel_buffer_t *buffer, + ply_rectangle_t cropped_area; + + if (fill_area == NULL) +- fill_area = &buffer->area; ++ fill_area = &buffer->logical_area; + + ply_pixel_buffer_crop_area_to_clip_area (buffer, fill_area, &cropped_area); + +@@ -430,24 +497,16 @@ ply_pixel_buffer_fill_with_color (ply_pixel_buffer_t *buffer, + double alpha) + { + uint32_t pixel_value; +- ply_rectangle_t cropped_area; + + assert (buffer != NULL); + +- if (fill_area == NULL) +- fill_area = &buffer->area; +- +- ply_pixel_buffer_crop_area_to_clip_area (buffer, fill_area, &cropped_area); +- + red *= alpha; + green *= alpha; + blue *= alpha; + + pixel_value = PLY_PIXEL_BUFFER_COLOR_TO_PIXEL_VALUE (red, green, blue, alpha); + +- ply_pixel_buffer_fill_area_with_pixel_value (buffer, &cropped_area, pixel_value); +- +- ply_region_add_rectangle (buffer->updated_areas, &cropped_area); ++ ply_pixel_buffer_fill_area_with_pixel_value (buffer, fill_area, pixel_value); + } + + void +@@ -456,7 +515,6 @@ ply_pixel_buffer_fill_with_hex_color_at_opacity (ply_pixel_buffer_t *buffer, + uint32_t hex_color, + double opacity) + { +- ply_rectangle_t cropped_area; + uint32_t pixel_value; + double red; + double green; +@@ -465,11 +523,6 @@ ply_pixel_buffer_fill_with_hex_color_at_opacity (ply_pixel_buffer_t *buffer, + + assert (buffer != NULL); + +- if (fill_area == NULL) +- fill_area = &buffer->area; +- +- ply_pixel_buffer_crop_area_to_clip_area (buffer, fill_area, &cropped_area); +- + /* if they only gave an rgb hex number, assume an alpha of 0xff + */ + if ((hex_color & 0xff000000) == 0) +@@ -488,9 +541,7 @@ ply_pixel_buffer_fill_with_hex_color_at_opacity (ply_pixel_buffer_t *buffer, + + pixel_value = PLY_PIXEL_BUFFER_COLOR_TO_PIXEL_VALUE (red, green, blue, alpha); + +- ply_pixel_buffer_fill_area_with_pixel_value (buffer, &cropped_area, pixel_value); +- +- ply_region_add_rectangle (buffer->updated_areas, &cropped_area); ++ ply_pixel_buffer_fill_area_with_pixel_value (buffer, fill_area, pixel_value); + } + + void +@@ -502,48 +553,120 @@ ply_pixel_buffer_fill_with_hex_color (ply_pixel_buffer_t *buffer, + hex_color, 1.0); + } + ++static inline uint32_t ++ply_pixels_interpolate (uint32_t *bytes, ++ int width, ++ int height, ++ double x, ++ double y) ++{ ++ int ix; ++ int iy; ++ int i; ++ int offset_x; ++ int offset_y; ++ uint32_t pixels[2][2]; ++ uint32_t reply = 0; ++ ++ for (offset_y = 0; offset_y < 2; offset_y++) { ++ for (offset_x = 0; offset_x < 2; offset_x++) { ++ ix = x + offset_x; ++ iy = y + offset_y; ++ ++ if (ix < 0 || ix >= width || iy < 0 || iy >= height) ++ pixels[offset_y][offset_x] = 0x00000000; ++ else ++ pixels[offset_y][offset_x] = bytes[ix + iy * width]; ++ } ++ } ++ if (!pixels[0][0] && !pixels[0][1] && !pixels[1][0] && !pixels[1][1]) return 0; ++ ++ ix = x; ++ iy = y; ++ x -= ix; ++ y -= iy; ++ for (i = 0; i < 4; i++) { ++ uint32_t value = 0; ++ uint32_t mask = 0xFF << (i * 8); ++ value += ((pixels[0][0]) & mask) * (1 - x) * (1 - y); ++ value += ((pixels[0][1]) & mask) * x * (1 - y); ++ value += ((pixels[1][0]) & mask) * (1 - x) * y; ++ value += ((pixels[1][1]) & mask) * x * y; ++ reply |= value & mask; ++ } ++ return reply; ++} ++ + void +-ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip (ply_pixel_buffer_t *buffer, +- ply_rectangle_t *fill_area, +- ply_rectangle_t *clip_area, +- uint32_t *data, +- double opacity) ++ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip_and_scale (ply_pixel_buffer_t *buffer, ++ ply_rectangle_t *fill_area, ++ ply_rectangle_t *clip_area, ++ uint32_t *data, ++ double opacity, ++ int scale) + { + unsigned long row, column; + uint8_t opacity_as_byte; ++ ply_rectangle_t logical_fill_area; + ply_rectangle_t cropped_area; + unsigned long x; + unsigned long y; ++ double scale_factor; + + assert (buffer != NULL); + +- if (fill_area == NULL) +- fill_area = &buffer->area; ++ if (fill_area == NULL) { ++ fill_area = &buffer->logical_area; ++ logical_fill_area = buffer->logical_area; ++ } else { ++ logical_fill_area = *fill_area; ++ ply_rectangle_downscale (&logical_fill_area, scale); ++ } + +- ply_pixel_buffer_crop_area_to_clip_area (buffer, fill_area, &cropped_area); ++ ply_pixel_buffer_crop_area_to_clip_area (buffer, &logical_fill_area, &cropped_area); ++ ++ if (clip_area) { ++ ply_rectangle_t device_clip_area; + +- if (clip_area) +- ply_rectangle_intersect (&cropped_area, clip_area, &cropped_area); ++ device_clip_area = *clip_area; ++ ply_rectangle_downscale (&device_clip_area, scale); ++ ply_pixel_buffer_adjust_area_for_device_scale (buffer, &device_clip_area); ++ ply_rectangle_intersect (&cropped_area, &device_clip_area, &cropped_area); ++ } + + if (cropped_area.width == 0 || cropped_area.height == 0) + return; + +- x = cropped_area.x - fill_area->x; +- y = cropped_area.y - fill_area->y; + opacity_as_byte = (uint8_t) (opacity * 255.0); ++ scale_factor = (double)scale / buffer->device_scale; ++ x = cropped_area.x; ++ y = cropped_area.y; + ++ /* column, row are the point we want to write into, in ++ pixel_buffer coordinate space (device pixels) ++ ++ scale_factor * (column - fill_area->x), scale_factor * (row - fill_area->y) ++ is the point we want to source from, in the data coordinate ++ space */ + for (row = y; row < y + cropped_area.height; row++) { + for (column = x; column < x + cropped_area.width; column++) { + uint32_t pixel_value; + +- pixel_value = data[fill_area->width * row + column]; ++ if (buffer->device_scale == scale) ++ pixel_value = data[fill_area->width * (row - fill_area->y) + ++ column - fill_area->x]; ++ else ++ pixel_value = ply_pixels_interpolate (data, ++ fill_area->width, ++ fill_area->height, ++ scale_factor * column - fill_area->x, ++ scale_factor * row - fill_area->y); + if ((pixel_value >> 24) == 0x00) + continue; + + pixel_value = make_pixel_value_translucent (pixel_value, opacity_as_byte); + ply_pixel_buffer_blend_value_at_pixel (buffer, +- cropped_area.x + (column - x), +- cropped_area.y + (row - y), ++ column, row, + pixel_value); + } + } +@@ -552,15 +675,30 @@ ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip (ply_pixel_buffer_t + } + + void ++ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip (ply_pixel_buffer_t *buffer, ++ ply_rectangle_t *fill_area, ++ ply_rectangle_t *clip_area, ++ uint32_t *data, ++ double opacity) ++{ ++ ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip_and_scale (buffer, ++ fill_area, ++ clip_area, ++ data, ++ opacity, ++ 1); ++} ++ ++void + ply_pixel_buffer_fill_with_argb32_data_at_opacity (ply_pixel_buffer_t *buffer, + ply_rectangle_t *fill_area, + uint32_t *data, + double opacity) + { +- ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip (buffer, +- fill_area, +- NULL, +- data, opacity); ++ ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip_and_scale (buffer, ++ fill_area, ++ NULL, ++ data, opacity, 1); + } + + void +@@ -568,10 +706,10 @@ ply_pixel_buffer_fill_with_argb32_data (ply_pixel_buffer_t *buffer, + ply_rectangle_t *fill_area, + uint32_t *data) + { +- ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip (buffer, +- fill_area, +- NULL, +- data, 1.0); ++ ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip_and_scale (buffer, ++ fill_area, ++ NULL, ++ data, 1.0, 1); + } + + void +@@ -580,10 +718,25 @@ ply_pixel_buffer_fill_with_argb32_data_with_clip (ply_pixel_buffer_t *buffer, + ply_rectangle_t *clip_area, + uint32_t *data) + { +- ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip (buffer, +- fill_area, +- clip_area, +- data, 1.0); ++ ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip_and_scale (buffer, ++ fill_area, ++ clip_area, ++ data, 1.0, 1); ++} ++ ++static void ++ply_pixel_buffer_copy_area (ply_pixel_buffer_t *canvas, ++ ply_pixel_buffer_t *source, ++ int x, int y, ++ ply_rectangle_t *cropped_area) ++{ ++ unsigned long row; ++ ++ for (row = y; row < y + cropped_area->height; row++) { ++ memcpy (canvas->bytes + (cropped_area->y + row - y) * canvas->area.width + cropped_area->x, ++ source->bytes + (row * source->area.width) + x, ++ cropped_area->width * 4); ++ } + } + + void +@@ -594,51 +747,51 @@ ply_pixel_buffer_fill_with_buffer_at_opacity_with_clip (ply_pixel_buffer_t *canv + ply_rectangle_t *clip_area, + float opacity) + { +- unsigned long row, column; +- uint8_t opacity_as_byte; +- ply_rectangle_t cropped_area; ++ ply_rectangle_t fill_area; + unsigned long x; + unsigned long y; + + assert (canvas != NULL); + assert (source != NULL); + +- cropped_area.x = x_offset; +- cropped_area.y = y_offset; +- cropped_area.width = source->area.width; +- cropped_area.height = source->area.height; ++ /* Fast path to memcpy if we need no blending or scaling */ ++ if (opacity == 1.0 && ply_pixel_buffer_is_opaque (source) && ++ canvas->device_scale == source->device_scale) { ++ ply_rectangle_t cropped_area; + +- ply_pixel_buffer_crop_area_to_clip_area (canvas, &cropped_area, &cropped_area); ++ cropped_area.x = x_offset; ++ cropped_area.y = y_offset; ++ cropped_area.width = source->logical_area.width; ++ cropped_area.height = source->logical_area.height; + +- if (clip_area) +- ply_rectangle_intersect (&cropped_area, clip_area, &cropped_area); ++ ply_pixel_buffer_crop_area_to_clip_area (canvas, &cropped_area, &cropped_area); + +- if (cropped_area.width == 0 || cropped_area.height == 0) +- return; +- +- x = cropped_area.x - x_offset; +- y = cropped_area.y - y_offset; +- opacity_as_byte = (uint8_t) (opacity * 255.0); +- +- for (row = y; row < y + cropped_area.height; row++) { +- for (column = x; column < x + cropped_area.width; column++) { +- uint32_t pixel_value; ++ /* clip_area is in source device pixels, which are also canvas device pixels */ ++ if (clip_area) ++ ply_rectangle_intersect (&cropped_area, clip_area, &cropped_area); + +- pixel_value = source->bytes[row * source->area.width + column]; ++ if (cropped_area.width == 0 || cropped_area.height == 0) ++ return; + +- pixel_value = make_pixel_value_translucent (pixel_value, opacity_as_byte); ++ x = cropped_area.x - x_offset; ++ y = cropped_area.y - y_offset; + +- if ((pixel_value >> 24) == 0x00) +- continue; ++ ply_pixel_buffer_copy_area (canvas, source, x, y, &cropped_area); + +- ply_pixel_buffer_blend_value_at_pixel (canvas, +- cropped_area.x + (column - x), +- cropped_area.y + (row - y), +- pixel_value); +- } ++ ply_region_add_rectangle (canvas->updated_areas, &cropped_area); ++ } else { ++ fill_area.x = x_offset * source->device_scale; ++ fill_area.y = y_offset * source->device_scale; ++ fill_area.width = source->area.width; ++ fill_area.height = source->area.height; ++ ++ ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip_and_scale (canvas, ++ &fill_area, ++ clip_area, ++ source->bytes, ++ opacity, ++ source->device_scale); + } +- +- ply_region_add_rectangle (canvas->updated_areas, &cropped_area); + } + + void +@@ -696,52 +849,15 @@ ply_pixel_buffer_interpolate (ply_pixel_buffer_t *buffer, + double x, + double y) + { +- int ix; +- int iy; + int width; + int height; +- +- int i; +- +- int offset_x; +- int offset_y; +- uint32_t pixels[2][2]; +- uint32_t reply = 0; + uint32_t *bytes; + + width = buffer->area.width; + height = buffer->area.height; +- +- + bytes = ply_pixel_buffer_get_argb32_data (buffer); + +- for (offset_y = 0; offset_y < 2; offset_y++) { +- for (offset_x = 0; offset_x < 2; offset_x++) { +- ix = x + offset_x; +- iy = y + offset_y; +- +- if (ix < 0 || ix >= width || iy < 0 || iy >= height) +- pixels[offset_y][offset_x] = 0x00000000; +- else +- pixels[offset_y][offset_x] = bytes[ix + iy * width]; +- } +- } +- if (!pixels[0][0] && !pixels[0][1] && !pixels[1][0] && !pixels[1][1]) return 0; +- +- ix = x; +- iy = y; +- x -= ix; +- y -= iy; +- for (i = 0; i < 4; i++) { +- uint32_t value = 0; +- uint32_t mask = 0xFF << (i * 8); +- value += ((pixels[0][0]) & mask) * (1 - x) * (1 - y); +- value += ((pixels[0][1]) & mask) * x * (1 - y); +- value += ((pixels[1][0]) & mask) * (1 - x) * y; +- value += ((pixels[1][1]) & mask) * x * y; +- reply |= value & mask; +- } +- return reply; ++ return ply_pixels_interpolate (bytes, width, height, x, y); + } + + ply_pixel_buffer_t * +@@ -753,7 +869,7 @@ ply_pixel_buffer_resize (ply_pixel_buffer_t *old_buffer, + int x, y; + double old_x, old_y; + int old_width, old_height; +- float scale_x, scale_y; ++ double scale_x, scale_y; + uint32_t *bytes; + + buffer = ply_pixel_buffer_new (width, height); +@@ -852,4 +968,20 @@ ply_pixel_buffer_tile (ply_pixel_buffer_t *old_buffer, + return buffer; + } + ++int ++ply_pixel_buffer_get_device_scale (ply_pixel_buffer_t *buffer) ++{ ++ return buffer->device_scale; ++} ++ ++void ++ply_pixel_buffer_set_device_scale (ply_pixel_buffer_t *buffer, ++ int scale) ++{ ++ buffer->device_scale = scale; ++ ++ buffer->logical_area.width = buffer->area.width / scale; ++ buffer->logical_area.height = buffer->area.height / scale; ++} ++ + /* 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 7848a98..595e9bd 100644 +--- a/src/libply-splash-core/ply-pixel-buffer.h ++++ b/src/libply-splash-core/ply-pixel-buffer.h +@@ -43,10 +43,17 @@ ply_pixel_buffer_t *ply_pixel_buffer_new (unsigned long width, + void ply_pixel_buffer_free (ply_pixel_buffer_t *buffer); + void ply_pixel_buffer_get_size (ply_pixel_buffer_t *buffer, + ply_rectangle_t *size); ++int ply_pixel_buffer_get_device_scale (ply_pixel_buffer_t *buffer); ++void ply_pixel_buffer_set_device_scale (ply_pixel_buffer_t *buffer, ++ int scale); + + unsigned long ply_pixel_buffer_get_width (ply_pixel_buffer_t *buffer); + unsigned long ply_pixel_buffer_get_height (ply_pixel_buffer_t *buffer); + ++bool ply_pixel_buffer_is_opaque (ply_pixel_buffer_t *buffer); ++void ply_pixel_buffer_set_opaque (ply_pixel_buffer_t *buffer, ++ bool is_opaque); ++ + ply_region_t *ply_pixel_buffer_get_updated_areas (ply_pixel_buffer_t *buffer); + + void ply_pixel_buffer_fill_with_color (ply_pixel_buffer_t *buffer, +@@ -86,6 +93,12 @@ void ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip (ply_pixel_buff + ply_rectangle_t *clip_area, + uint32_t *data, + double opacity); ++void ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip_and_scale (ply_pixel_buffer_t *buffer, ++ ply_rectangle_t *fill_area, ++ ply_rectangle_t *clip_area, ++ uint32_t *data, ++ double opacity, ++ int scale); + + void ply_pixel_buffer_fill_with_buffer_at_opacity_with_clip (ply_pixel_buffer_t *canvas, + ply_pixel_buffer_t *source, +diff --git a/src/libply-splash-core/ply-pixel-display.c b/src/libply-splash-core/ply-pixel-display.c +index b061bfc..cb01a2c 100644 +--- a/src/libply-splash-core/ply-pixel-display.c ++++ b/src/libply-splash-core/ply-pixel-display.c +@@ -81,6 +81,18 @@ ply_pixel_display_new (ply_renderer_t *renderer, + return display; + } + ++ply_renderer_t * ++ply_pixel_display_get_renderer (ply_pixel_display_t *display) ++{ ++ return display->renderer; ++} ++ ++ply_renderer_head_t * ++ply_pixel_display_get_renderer_head (ply_pixel_display_t *display) ++{ ++ return display->head; ++} ++ + unsigned long + ply_pixel_display_get_width (ply_pixel_display_t *display) + { +diff --git a/src/libply-splash-core/ply-pixel-display.h b/src/libply-splash-core/ply-pixel-display.h +index 62a36da..675c181 100644 +--- a/src/libply-splash-core/ply-pixel-display.h ++++ b/src/libply-splash-core/ply-pixel-display.h +@@ -46,6 +46,9 @@ ply_pixel_display_t *ply_pixel_display_new (ply_renderer_t *renderer, + + void ply_pixel_display_free (ply_pixel_display_t *display); + ++ply_renderer_t *ply_pixel_display_get_renderer (ply_pixel_display_t *display); ++ply_renderer_head_t *ply_pixel_display_get_renderer_head (ply_pixel_display_t *display); ++ + unsigned long ply_pixel_display_get_width (ply_pixel_display_t *display); + unsigned long ply_pixel_display_get_height (ply_pixel_display_t *display); + +diff --git a/src/libply-splash-core/ply-renderer-plugin.h b/src/libply-splash-core/ply-renderer-plugin.h +index 82ef913..f1455d3 100644 +--- a/src/libply-splash-core/ply-renderer-plugin.h ++++ b/src/libply-splash-core/ply-renderer-plugin.h +@@ -66,6 +66,8 @@ typedef struct + + void (*close_input_source)(ply_renderer_backend_t *backend, + ply_renderer_input_source_t *input_source); ++ ++ const char * (*get_device_name)(ply_renderer_backend_t *backend); + } ply_renderer_plugin_interface_t; + + #endif /* PLY_RENDERER_PLUGIN_H */ +diff --git a/src/libply-splash-core/ply-renderer.c b/src/libply-splash-core/ply-renderer.c +index f64eac5..b9059ef 100644 +--- a/src/libply-splash-core/ply-renderer.c ++++ b/src/libply-splash-core/ply-renderer.c +@@ -55,6 +55,7 @@ struct _ply_renderer + + uint32_t input_source_is_open : 1; + uint32_t is_mapped : 1; ++ uint32_t is_active : 1; + }; + + typedef const ply_renderer_plugin_interface_t * +@@ -154,6 +155,11 @@ ply_renderer_load_plugin (ply_renderer_t *renderer, + return false; + } + ++ if (renderer->plugin_interface->get_device_name != NULL) { ++ free (renderer->device_name); ++ renderer->device_name = strdup (renderer->plugin_interface->get_device_name (renderer->backend)); ++ } ++ + return true; + } + +@@ -268,15 +274,19 @@ ply_renderer_open (ply_renderer_t *renderer) + { PLY_RENDERER_TYPE_NONE, NULL } + }; + ++ renderer->is_active = false; + for (i = 0; known_plugins[i].type != PLY_RENDERER_TYPE_NONE; i++) { + 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; ++ if (ply_renderer_open_plugin (renderer, known_plugins[i].path)) { ++ renderer->is_active = true; ++ goto out; ++ } + } + + ply_trace ("could not find suitable rendering plugin"); +- return false; ++out: ++ return renderer->is_active; + } + + void +@@ -284,6 +294,7 @@ ply_renderer_close (ply_renderer_t *renderer) + { + ply_renderer_unmap_from_device (renderer); + ply_renderer_close_device (renderer); ++ renderer->is_active = false; + } + + void +@@ -291,7 +302,11 @@ ply_renderer_activate (ply_renderer_t *renderer) + { + assert (renderer->plugin_interface != NULL); + +- return renderer->plugin_interface->activate (renderer->backend); ++ if (renderer->is_active) ++ return; ++ ++ renderer->plugin_interface->activate (renderer->backend); ++ renderer->is_active = true; + } + + void +@@ -302,6 +317,12 @@ ply_renderer_deactivate (ply_renderer_t *renderer) + return renderer->plugin_interface->deactivate (renderer->backend); + } + ++bool ++ply_renderer_is_active (ply_renderer_t *renderer) ++{ ++ return renderer->is_active; ++} ++ + ply_list_t * + ply_renderer_get_heads (ply_renderer_t *renderer) + { +diff --git a/src/libply-splash-core/ply-renderer.h b/src/libply-splash-core/ply-renderer.h +index a019a4d..59391e1 100644 +--- a/src/libply-splash-core/ply-renderer.h ++++ b/src/libply-splash-core/ply-renderer.h +@@ -57,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); ++bool ply_renderer_is_active (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, +diff --git a/src/libply-splash-core/ply-seat.c b/src/libply-splash-core/ply-seat.c +deleted file mode 100644 +index 700332f..0000000 +--- a/src/libply-splash-core/ply-seat.c ++++ /dev/null +@@ -1,381 +0,0 @@ +-/* 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 if (seat->terminal != NULL) { +- seat->keyboard = ply_keyboard_new_for_terminal (seat->terminal); +- } +- +- if (seat->terminal != NULL) { +- add_text_displays (seat); +- } else { +- ply_trace ("not adding text display for seat, since seat has no associated terminal"); +- } +- +- if (seat->keyboard != NULL) { +- ply_keyboard_watch_for_input (seat->keyboard); +- seat->keyboard_active = true; +- } else { +- ply_trace ("not watching seat for input"); +- } +- +- 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 keyboard"); +- 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 +deleted file mode 100644 +index f9ed15d..0000000 +--- a/src/libply-splash-core/ply-seat.h ++++ /dev/null +@@ -1,66 +0,0 @@ +-/* 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 1bbeb42..a0954f2 100644 +--- a/src/libply-splash-core/ply-terminal.c ++++ b/src/libply-splash-core/ply-terminal.c +@@ -387,8 +387,8 @@ on_tty_disconnected (ply_terminal_t *terminal) + ply_terminal_reopen_device (terminal); + } + +-static bool +-ply_terminal_look_up_geometry (ply_terminal_t *terminal) ++bool ++ply_terminal_refresh_geometry (ply_terminal_t *terminal) + { + struct winsize terminal_size; + +@@ -551,7 +551,7 @@ ply_terminal_open_device (ply_terminal_t *terminal) + assert (terminal->fd < 0); + assert (terminal->fd_watch == NULL); + +- terminal->fd = open (terminal->name, O_RDWR | O_NOCTTY); ++ terminal->fd = open (terminal->name, O_RDWR | O_NOCTTY | O_NONBLOCK); + + if (terminal->fd < 0) { + ply_trace ("Unable to open terminal device '%s': %m", terminal->name); +@@ -570,6 +570,8 @@ ply_terminal_open_device (ply_terminal_t *terminal) + return PLY_TERMINAL_OPEN_RESULT_FAILURE; + } + ++ ply_set_fd_as_blocking (terminal->fd); ++ + terminal->fd_watch = ply_event_loop_watch_fd (terminal->loop, terminal->fd, + PLY_EVENT_LOOP_FD_STATUS_HAS_DATA, + (ply_event_handler_t) on_tty_input, +@@ -605,7 +607,7 @@ ply_terminal_open (ply_terminal_t *terminal) + return false; + } + +- ply_terminal_look_up_geometry (terminal); ++ ply_terminal_refresh_geometry (terminal); + + ply_terminal_look_up_color_palette (terminal); + ply_terminal_save_color_palette (terminal); +@@ -613,7 +615,7 @@ ply_terminal_open (ply_terminal_t *terminal) + ply_event_loop_watch_signal (terminal->loop, + SIGWINCH, + (ply_event_handler_t) +- ply_terminal_look_up_geometry, ++ ply_terminal_refresh_geometry, + terminal); + + if (ply_terminal_is_vt (terminal)) { +diff --git a/src/libply-splash-core/ply-terminal.h b/src/libply-splash-core/ply-terminal.h +index dc83ec3..7cfcc59 100644 +--- a/src/libply-splash-core/ply-terminal.h ++++ b/src/libply-splash-core/ply-terminal.h +@@ -69,6 +69,7 @@ void ply_terminal_reset_colors (ply_terminal_t *terminal); + + bool ply_terminal_set_unbuffered_input (ply_terminal_t *terminal); + bool ply_terminal_set_buffered_input (ply_terminal_t *terminal); ++bool ply_terminal_refresh_geometry (ply_terminal_t *terminal); + + __attribute__((__format__ (__printf__, 2, 3))) + void ply_terminal_write (ply_terminal_t *terminal, +diff --git a/src/libply-splash-graphics/ply-animation.c b/src/libply-splash-graphics/ply-animation.c +index 81348f9..323d9ed 100644 +--- a/src/libply-splash-graphics/ply-animation.c ++++ b/src/libply-splash-graphics/ply-animation.c +@@ -353,6 +353,11 @@ ply_animation_stop_now (ply_animation_t *animation) + void + ply_animation_stop (ply_animation_t *animation) + { ++ if (animation->is_stopped) { ++ ply_trace ("animation already stopped, ignoring stop request"); ++ return; ++ } ++ + if (animation->stop_trigger == NULL) { + ply_animation_stop_now (animation); + return; +diff --git a/src/libply-splash-graphics/ply-image.c b/src/libply-splash-graphics/ply-image.c +index f838601..8b46978 100644 +--- a/src/libply-splash-graphics/ply-image.c ++++ b/src/libply-splash-graphics/ply-image.c +@@ -99,10 +99,13 @@ transform_to_argb32 (png_struct *png, + blue = data[i + 2]; + alpha = data[i + 3]; + +- red = (uint8_t) CLAMP (((red / 255.0) * (alpha / 255.0)) * 255.0, 0, 255.0); +- green = (uint8_t) CLAMP (((green / 255.0) * (alpha / 255.0)) * 255.0, +- 0, 255.0); +- blue = (uint8_t) CLAMP (((blue / 255.0) * (alpha / 255.0)) * 255.0, 0, 255.0); ++ /* pre-multiply the alpha if there's translucency */ ++ if (alpha != 0xff) { ++ red = (uint8_t) CLAMP (((red / 255.0) * (alpha / 255.0)) * 255.0, 0, 255.0); ++ green = (uint8_t) CLAMP (((green / 255.0) * (alpha / 255.0)) * 255.0, ++ 0, 255.0); ++ blue = (uint8_t) CLAMP (((blue / 255.0) * (alpha / 255.0)) * 255.0, 0, 255.0); ++ } + + pixel_value = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0); + memcpy (data + i, &pixel_value, sizeof(uint32_t)); +diff --git a/src/libply-splash-graphics/ply-throbber.c b/src/libply-splash-graphics/ply-throbber.c +index c9c5bbd..f18feb6 100644 +--- a/src/libply-splash-graphics/ply-throbber.c ++++ b/src/libply-splash-graphics/ply-throbber.c +@@ -337,6 +337,15 @@ void + ply_throbber_stop (ply_throbber_t *throbber, + ply_trigger_t *stop_trigger) + { ++ if (throbber->is_stopped) { ++ ply_trace ("throbber already stopped"); ++ if (stop_trigger != NULL) { ++ ply_trace ("pulling stop trigger right away"); ++ ply_trigger_pull (stop_trigger, NULL); ++ } ++ return; ++ } ++ + if (stop_trigger == NULL) { + ply_throbber_stop_now (throbber); + return; +diff --git a/src/libply/ply-logger.h b/src/libply/ply-logger.h +index de23181..545e64c 100644 +--- a/src/libply/ply-logger.h ++++ b/src/libply/ply-logger.h +@@ -92,7 +92,7 @@ bool ply_logger_is_tracing_enabled (ply_logger_t *logger); + ply_logger_flush (logger); \ + errno = _old_errno; \ + ply_logger_inject (logger, \ +- "[%s:%d] %45.45s:" format "\r\n", \ ++ "[%s:%d] %45.45s:" format "\n", \ + __FILE__, __LINE__, __func__, ## args); \ + ply_logger_flush (logger); \ + errno = _old_errno; \ +diff --git a/src/libply/ply-utils.c b/src/libply/ply-utils.c +index 5c8510c..89e37e9 100644 +--- a/src/libply/ply-utils.c ++++ b/src/libply/ply-utils.c +@@ -78,6 +78,8 @@ + static int errno_stack[PLY_ERRNO_STACK_SIZE]; + static int errno_stack_position = 0; + ++static int overridden_device_scale = 0; ++ + bool + ply_open_unidirectional_pipe (int *sender_fd, + int *receiver_fd) +@@ -421,6 +423,29 @@ ply_fd_may_block (int fd) + return (flags & O_NONBLOCK) != 0; + } + ++bool ++ply_set_fd_as_blocking (int fd) ++{ ++ int flags; ++ int ret = 0; ++ ++ assert (fd >= 0); ++ ++ flags = fcntl (fd, F_GETFL); ++ ++ if (flags == -1) { ++ return false; ++ } ++ ++ if (flags & O_NONBLOCK) { ++ flags &= ~O_NONBLOCK; ++ ++ ret = fcntl (fd, F_SETFL, flags); ++ } ++ ++ return ret == 0; ++} ++ + char ** + ply_copy_string_array (const char *const *array) + { +@@ -936,4 +961,58 @@ out: + + return (pid_t) ppid; + } ++ ++void ++ply_set_device_scale (int device_scale) ++{ ++ overridden_device_scale = device_scale; ++ ply_trace ("Device scale is set to %d", device_scale); ++} ++ ++/* The minimum resolution at which we turn on a device-scale of 2 */ ++#define HIDPI_LIMIT 192 ++#define HIDPI_MIN_HEIGHT 1200 ++ ++int ++ply_get_device_scale (uint32_t width, ++ uint32_t height, ++ uint32_t width_mm, ++ uint32_t height_mm) ++{ ++ int device_scale; ++ double dpi_x, dpi_y; ++ const char *force_device_scale; ++ ++ device_scale = 1; ++ ++ if ((force_device_scale = getenv ("PLYMOUTH_FORCE_SCALE"))) ++ return strtoul (force_device_scale, NULL, 0); ++ ++ if (overridden_device_scale != 0) ++ return overridden_device_scale; ++ ++ if (height < HIDPI_MIN_HEIGHT) ++ return 1; ++ ++ /* Somebody encoded the aspect ratio (16/9 or 16/10) ++ * instead of the physical size */ ++ if ((width_mm == 160 && height_mm == 90) || ++ (width_mm == 160 && height_mm == 100) || ++ (width_mm == 16 && height_mm == 9) || ++ (width_mm == 16 && height_mm == 10)) ++ return 1; ++ ++ if (width_mm > 0 && height_mm > 0) { ++ dpi_x = (double)width / (width_mm / 25.4); ++ dpi_y = (double)height / (height_mm / 25.4); ++ /* We don't completely trust these values so both ++ must be high, and never pick higher ratio than ++ 2 automatically */ ++ if (dpi_x > HIDPI_LIMIT && dpi_y > HIDPI_LIMIT) ++ device_scale = 2; ++ } ++ ++ return device_scale; ++} ++ + /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ +diff --git a/src/libply/ply-utils.h b/src/libply/ply-utils.h +index b9a28d0..c46603e 100644 +--- a/src/libply/ply-utils.h ++++ b/src/libply/ply-utils.h +@@ -82,6 +82,7 @@ bool ply_read_uint32 (int fd, + bool ply_fd_has_data (int fd); + bool ply_fd_can_take_data (int fd); + bool ply_fd_may_block (int fd); ++bool ply_set_fd_as_blocking (int fd); + char **ply_copy_string_array (const char *const *array); + void ply_free_string_array (char **array); + bool ply_string_has_prefix (const char *string, +@@ -120,6 +121,13 @@ int ply_utf8_string_get_length (const char *string, + char *ply_get_process_command_line (pid_t pid); + pid_t ply_get_process_parent_pid (pid_t pid); + ++void ply_set_device_scale (int device_scale); ++ ++int ply_get_device_scale (uint32_t width, ++ uint32_t height, ++ uint32_t width_mm, ++ uint32_t height_mm); ++ + #endif + + #endif /* PLY_UTILS_H */ +diff --git a/src/main.c b/src/main.c +index da6e95d..0864e5e 100644 +--- a/src/main.c ++++ b/src/main.c +@@ -107,6 +107,7 @@ typedef struct + + double start_time; + double splash_delay; ++ double device_timeout; + + char kernel_command_line[PLY_MAX_COMMAND_LINE_SIZE]; + uint32_t kernel_command_line_is_set : 1; +@@ -136,8 +137,8 @@ static ply_boot_splash_t *load_theme (state_t *state, + 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 void attach_splash_to_devices (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); +@@ -293,8 +294,8 @@ load_settings (state_t *state, + char **theme_path) + { + ply_key_file_t *key_file = NULL; +- const char *delay_string; + bool settings_loaded = false; ++ const char *scale_string; + const char *splash_string; + + ply_trace ("Trying to load %s", path); +@@ -313,6 +314,8 @@ load_settings (state_t *state, + splash_string, splash_string); + + if (isnan (state->splash_delay)) { ++ const char *delay_string; ++ + delay_string = ply_key_file_get_value (key_file, "Daemon", "ShowDelay"); + + if (delay_string != NULL) { +@@ -321,6 +324,23 @@ load_settings (state_t *state, + } + } + ++ if (isnan (state->device_timeout)) { ++ const char *timeout_string; ++ ++ timeout_string = ply_key_file_get_value (key_file, "Daemon", "DeviceTimeout"); ++ ++ if (timeout_string != NULL) { ++ state->device_timeout = atof (timeout_string); ++ ply_trace ("Device timeout is set to %lf", state->device_timeout); ++ } ++ } ++ ++ scale_string = ply_key_file_get_value (key_file, "Daemon", "DeviceScale"); ++ ++ if (scale_string != NULL) { ++ ply_set_device_scale (strtoul (scale_string, NULL, 0)); ++ } ++ + settings_loaded = true; + out: + ply_key_file_free (key_file); +@@ -345,6 +365,8 @@ show_detailed_splash (state_t *state) + } + + state->boot_splash = splash; ++ ++ show_messages (state); + update_display (state); + } + +@@ -419,6 +441,17 @@ find_override_splash (state_t *state) + } + + static void ++find_force_scale (state_t *state) ++{ ++ const char *scale_string; ++ ++ scale_string = command_line_get_string_after_prefix (state->kernel_command_line, "plymouth.force-scale="); ++ ++ if (scale_string != NULL) ++ ply_set_device_scale (strtoul (scale_string, NULL, 0)); ++} ++ ++static void + find_system_default_splash (state_t *state) + { + if (state->system_default_splash_path != NULL) +@@ -492,6 +525,7 @@ show_default_splash (state_t *state) + return; + } + ++ show_messages (state); + update_display (state); + } + +@@ -520,14 +554,14 @@ on_ask_for_password (state_t *state, + * arrive shortly so just sit tight + */ + if (state->is_shown) { +- bool has_open_seats; ++ bool has_displays; + + cancel_pending_delayed_show (state); + +- has_open_seats = ply_device_manager_has_open_seats (state->device_manager); ++ has_displays = ply_device_manager_has_displays (state->device_manager); + +- if (has_open_seats) { +- ply_trace ("seats open now, showing splash immediately"); ++ if (has_displays) { ++ ply_trace ("displays available now, showing splash immediately"); + show_splash (state); + } else { + ply_trace ("splash still coming up, waiting a bit"); +@@ -891,7 +925,7 @@ plymouth_should_show_default_splash (state_t *state) + static void + on_show_splash (state_t *state) + { +- bool has_open_seats; ++ bool has_displays; + + if (state->is_shown) { + ply_trace ("show splash called while already shown"); +@@ -910,49 +944,20 @@ on_show_splash (state_t *state) + } + + state->is_shown = true; +- has_open_seats = ply_device_manager_has_open_seats (state->device_manager); ++ has_displays = ply_device_manager_has_displays (state->device_manager); + +- if (!state->is_attached && state->should_be_attached && has_open_seats) ++ if (!state->is_attached && state->should_be_attached && has_displays) + attach_to_running_session (state); + +- if (has_open_seats) { +- ply_trace ("at least one seat already open, so loading splash"); ++ if (has_displays) { ++ ply_trace ("at least one display already available, so loading splash"); + show_splash (state); + } else { +- ply_trace ("no seats available to show splash on, waiting..."); ++ ply_trace ("no displays 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) +@@ -991,23 +996,9 @@ show_splash (state_t *state) + } + + static void +-on_seat_added (state_t *state, +- ply_seat_t *seat) ++on_keyboard_added (state_t *state, ++ ply_keyboard_t *keyboard) + { +- ply_keyboard_t *keyboard; +- +- if (state->is_shown && !state->is_inactive) { +- 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); +- } +- } +- +- keyboard = ply_seat_get_keyboard (seat); +- + ply_trace ("listening for keystrokes"); + ply_keyboard_add_input_handler (keyboard, + (ply_keyboard_input_handler_t) +@@ -1024,6 +1015,90 @@ on_seat_added (state_t *state, + ply_keyboard_add_enter_handler (keyboard, + (ply_keyboard_enter_handler_t) + on_enter, state); ++ ++ if (state->boot_splash != NULL) { ++ ply_trace ("keyboard set after splash loaded, so attaching to splash"); ++ ply_boot_splash_set_keyboard (state->boot_splash, keyboard); ++ } ++} ++ ++static void ++on_keyboard_removed (state_t *state, ++ ply_keyboard_t *keyboard) ++{ ++ 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_unset_keyboard (state->boot_splash); ++} ++ ++static void ++on_pixel_display_added (state_t *state, ++ ply_pixel_display_t *display) ++{ ++ if (state->is_shown) { ++ if (state->boot_splash == NULL) { ++ ply_trace ("pixel display added before splash loaded, so loading splash now"); ++ show_splash (state); ++ } else { ++ ply_trace ("pixel display added after splash loaded, so attaching to splash"); ++ ply_boot_splash_add_pixel_display (state->boot_splash, display); ++ ++ update_display (state); ++ } ++ } ++} ++ ++static void ++on_pixel_display_removed (state_t *state, ++ ply_pixel_display_t *display) ++{ ++ if (state->boot_splash == NULL) ++ return; ++ ++ ply_boot_splash_remove_pixel_display (state->boot_splash, display); ++} ++ ++static void ++on_text_display_added (state_t *state, ++ ply_text_display_t *display) ++{ ++ if (state->is_shown) { ++ if (state->boot_splash == NULL) { ++ ply_trace ("text display added before splash loaded, so loading splash now"); ++ show_splash (state); ++ } else { ++ ply_trace ("text display added after splash loaded, so attaching to splash"); ++ ply_boot_splash_add_text_display (state->boot_splash, display); ++ ++ update_display (state); ++ } ++ } ++} ++ ++static void ++on_text_display_removed (state_t *state, ++ ply_text_display_t *display) ++{ ++ if (state->boot_splash == NULL) ++ return; ++ ++ ply_boot_splash_remove_text_display (state->boot_splash, display); + } + + static void +@@ -1033,12 +1108,25 @@ load_devices (state_t *state, + state->device_manager = ply_device_manager_new (state->default_tty, flags); + state->local_console_terminal = ply_device_manager_get_default_terminal (state->device_manager); + +- 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); ++ ply_device_manager_watch_devices (state->device_manager, ++ state->device_timeout, ++ (ply_keyboard_added_handler_t) ++ on_keyboard_added, ++ (ply_keyboard_removed_handler_t) ++ on_keyboard_removed, ++ (ply_pixel_display_added_handler_t) ++ on_pixel_display_added, ++ (ply_pixel_display_removed_handler_t) ++ on_pixel_display_removed, ++ (ply_text_display_added_handler_t) ++ on_text_display_added, ++ (ply_text_display_removed_handler_t) ++ on_text_display_removed, ++ state); ++ ++ if (ply_device_manager_has_serial_consoles (state->device_manager)) { ++ state->should_force_details = true; ++ } + } + + static void +@@ -1507,22 +1595,52 @@ on_enter (state_t *state, + } + + static void +-attach_splash_to_seats (state_t *state, +- ply_boot_splash_t *splash) ++attach_splash_to_devices (state_t *state, ++ ply_boot_splash_t *splash) + { +- ply_list_t *seats; ++ ply_list_t *keyboards; ++ ply_list_t *pixel_displays; ++ ply_list_t *text_displays; + ply_list_node_t *node; + +- seats = ply_device_manager_get_seats (state->device_manager); +- node = ply_list_get_first_node (seats); ++ keyboards = ply_device_manager_get_keyboards (state->device_manager); ++ node = ply_list_get_first_node (keyboards); ++ while (node != NULL) { ++ ply_keyboard_t *keyboard; ++ ply_list_node_t *next_node; ++ ++ keyboard = ply_list_node_get_data (node); ++ next_node = ply_list_get_next_node (keyboards, node); ++ ++ ply_boot_splash_set_keyboard (splash, keyboard); ++ ++ node = next_node; ++ } ++ ++ pixel_displays = ply_device_manager_get_pixel_displays (state->device_manager); ++ node = ply_list_get_first_node (pixel_displays); + while (node != NULL) { +- ply_seat_t *seat; ++ ply_pixel_display_t *pixel_display; + ply_list_node_t *next_node; + +- seat = ply_list_node_get_data (node); +- next_node = ply_list_get_next_node (seats, node); ++ pixel_display = ply_list_node_get_data (node); ++ next_node = ply_list_get_next_node (pixel_displays, node); + +- ply_boot_splash_attach_to_seat (splash, seat); ++ ply_boot_splash_add_pixel_display (splash, pixel_display); ++ ++ node = next_node; ++ } ++ ++ text_displays = ply_device_manager_get_text_displays (state->device_manager); ++ node = ply_list_get_first_node (text_displays); ++ while (node != NULL) { ++ ply_text_display_t *text_display; ++ ply_list_node_t *next_node; ++ ++ text_display = ply_list_node_get_data (node); ++ next_node = ply_list_get_next_node (text_displays, node); ++ ++ ply_boot_splash_add_text_display (splash, text_display); + + node = next_node; + } +@@ -1623,7 +1741,7 @@ show_theme (state_t *state, + if (splash == NULL) + return NULL; + +- attach_splash_to_seats (state, splash); ++ attach_splash_to_devices (state, splash); + ply_device_manager_activate_renderers (state->device_manager); + + splash_mode = get_splash_mode_from_mode (state->mode); +@@ -1641,7 +1759,6 @@ show_theme (state_t *state, + #endif + + ply_device_manager_activate_keyboards (state->device_manager); +- show_messages (state); + + return splash; + } +@@ -1978,12 +2095,15 @@ on_crash (int signum) + { + struct termios term_attributes; + int fd; ++ static const char *show_cursor_sequence = "\033[?25h"; + + fd = open ("/dev/tty1", O_RDWR | O_NOCTTY); + if (fd < 0) fd = open ("/dev/hvc0", O_RDWR | O_NOCTTY); + + ioctl (fd, KDSETMODE, KD_TEXT); + ++ write (fd, show_cursor_sequence, sizeof (show_cursor_sequence) - 1); ++ + tcgetattr (fd, &term_attributes); + + term_attributes.c_iflag |= BRKINT | IGNPAR | ICRNL | IXON; +@@ -2191,6 +2311,7 @@ main (int argc, + + state.progress = ply_progress_new (); + state.splash_delay = NAN; ++ state.device_timeout = NAN; + + ply_progress_load_cache (state.progress, + get_cache_file_for_mode (state.mode)); +@@ -2223,6 +2344,8 @@ main (int argc, + state.splash_delay = NAN; + } + ++ find_force_scale (&state); ++ + load_devices (&state, device_manager_flags); + + ply_trace ("entering event loop"); +diff --git a/src/plugins/controls/label/plugin.c b/src/plugins/controls/label/plugin.c +index 5edce3b..acba52b 100644 +--- a/src/plugins/controls/label/plugin.c ++++ b/src/plugins/controls/label/plugin.c +@@ -113,15 +113,18 @@ get_cairo_context_for_pixel_buffer (ply_label_plugin_control_t *label, + cairo_t *cairo_context; + unsigned char *data; + ply_rectangle_t size; ++ uint32_t scale; + + data = (unsigned char *) ply_pixel_buffer_get_argb32_data (pixel_buffer); + ply_pixel_buffer_get_size (pixel_buffer, &size); ++ scale = ply_pixel_buffer_get_device_scale (pixel_buffer); + + cairo_surface = cairo_image_surface_create_for_data (data, + CAIRO_FORMAT_ARGB32, +- size.width, +- size.height, +- size.width * 4); ++ size.width * scale, ++ size.height * scale, ++ size.width * scale * 4); ++ cairo_surface_set_device_scale (cairo_surface, scale, scale); + cairo_context = cairo_create (cairo_surface); + cairo_surface_destroy (cairo_surface); + +diff --git a/src/plugins/renderers/drm/Makefile.am b/src/plugins/renderers/drm/Makefile.am +index 747f202..271b17f 100644 +--- a/src/plugins/renderers/drm/Makefile.am ++++ b/src/plugins/renderers/drm/Makefile.am +@@ -16,12 +16,7 @@ drm_la_LDFLAGS = -module -avoid-version -export-dynamic + drm_la_LIBADD = $(PLYMOUTH_LIBS) $(DRM_LIBS) \ + ../../../libply/libply.la \ + ../../../libply-splash-core/libply-splash-core.la +-drm_la_SOURCES = $(srcdir)/plugin.c \ +- $(srcdir)/ply-renderer-driver.h +-drm_la_SOURCES += $(srcdir)/ply-renderer-generic-driver.h \ +- $(srcdir)/ply-renderer-generic-driver.c +- +- ++drm_la_SOURCES = $(srcdir)/plugin.c + + endif + +diff --git a/src/plugins/renderers/drm/plugin.c b/src/plugins/renderers/drm/plugin.c +index 45aab7d..b93e8e4 100644 +--- a/src/plugins/renderers/drm/plugin.c ++++ b/src/plugins/renderers/drm/plugin.c +@@ -54,12 +54,11 @@ + #include "ply-hashtable.h" + #include "ply-rectangle.h" + #include "ply-region.h" ++#include "ply-utils.h" + #include "ply-terminal.h" + + #include "ply-renderer.h" + #include "ply-renderer-plugin.h" +-#include "ply-renderer-driver.h" +-#include "ply-renderer-generic-driver.h" + + #define BYTES_PER_PIXEL (4) + +@@ -92,15 +91,27 @@ struct _ply_renderer_input_source + void *user_data; + }; + ++typedef struct ++{ ++ uint32_t id; ++ ++ uint32_t handle; ++ uint32_t width; ++ uint32_t height; ++ uint32_t row_stride; ++ ++ void *map_address; ++ uint32_t map_size; ++ int map_count; ++ ++ uint32_t added_fb : 1; ++} ply_renderer_buffer_t; ++ + struct _ply_renderer_backend + { + ply_event_loop_t *loop; + ply_terminal_t *terminal; + +- ply_renderer_driver_interface_t *driver_interface; +- ply_renderer_driver_t *driver; +- uint32_t driver_supports_mapping_console; +- + int device_fd; + char *device_name; + drmModeRes *resources; +@@ -109,11 +120,14 @@ struct _ply_renderer_backend + ply_list_t *heads; + ply_hashtable_t *heads_by_connector_id; + ++ ply_hashtable_t *output_buffers; ++ + int32_t dither_red; + int32_t dither_green; + int32_t dither_blue; + + uint32_t is_active : 1; ++ uint32_t requires_explicit_flushing : 1; + }; + + ply_renderer_plugin_interface_t *ply_renderer_backend_get_interface (void); +@@ -127,6 +141,233 @@ static void flush_head (ply_renderer_backend_t *backend, + ply_renderer_head_t *head); + + static bool ++ply_renderer_buffer_map (ply_renderer_backend_t *backend, ++ ply_renderer_buffer_t *buffer) ++{ ++ struct drm_mode_map_dumb map_dumb_buffer_request; ++ void *map_address; ++ ++ if (buffer->map_address != MAP_FAILED) { ++ buffer->map_count++; ++ return true; ++ } ++ ++ memset (&map_dumb_buffer_request, 0, sizeof(struct drm_mode_map_dumb)); ++ map_dumb_buffer_request.handle = buffer->handle; ++ if (drmIoctl (backend->device_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb_buffer_request) < 0) { ++ ply_trace ("Could not map GEM object %u: %m", buffer->handle); ++ return false; ++ } ++ ++ map_address = mmap (0, buffer->map_size, ++ PROT_READ | PROT_WRITE, MAP_SHARED, ++ backend->device_fd, map_dumb_buffer_request.offset); ++ ++ if (map_address == MAP_FAILED) ++ return false; ++ ++ buffer->map_address = map_address; ++ buffer->map_count++; ++ ++ return true; ++} ++ ++static void ++ply_renderer_buffer_unmap (ply_renderer_backend_t *backend, ++ ply_renderer_buffer_t *buffer) ++{ ++ buffer->map_count--; ++ ++ assert (buffer->map_count >= 0); ++} ++ ++static ply_renderer_buffer_t * ++ply_renderer_buffer_new (ply_renderer_backend_t *backend, ++ uint32_t width, ++ uint32_t height) ++{ ++ ply_renderer_buffer_t *buffer; ++ struct drm_mode_create_dumb create_dumb_buffer_request; ++ ++ buffer = calloc (1, sizeof(ply_renderer_buffer_t)); ++ buffer->width = width; ++ buffer->height = height; ++ buffer->map_address = MAP_FAILED; ++ ++ memset (&create_dumb_buffer_request, 0, sizeof(struct drm_mode_create_dumb)); ++ ++ create_dumb_buffer_request.width = width; ++ create_dumb_buffer_request.height = height; ++ create_dumb_buffer_request.bpp = 32; ++ create_dumb_buffer_request.flags = 0; ++ ++ if (drmIoctl (backend->device_fd, ++ DRM_IOCTL_MODE_CREATE_DUMB, ++ &create_dumb_buffer_request) < 0) { ++ free (buffer); ++ ply_trace ("Could not allocate GEM object for frame buffer: %m"); ++ return NULL; ++ } ++ ++ buffer->handle = create_dumb_buffer_request.handle; ++ buffer->row_stride = create_dumb_buffer_request.pitch; ++ buffer->map_size = create_dumb_buffer_request.size; ++ ++ ply_trace ("returning %ux%u buffer with stride %u", ++ width, height, buffer->row_stride); ++ ++ return buffer; ++} ++ ++static void ++ply_renderer_buffer_free (ply_renderer_backend_t *backend, ++ ply_renderer_buffer_t *buffer) ++{ ++ struct drm_mode_destroy_dumb destroy_dumb_buffer_request; ++ ++ if (buffer->added_fb) ++ drmModeRmFB (backend->device_fd, buffer->id); ++ ++ if (buffer->map_address != MAP_FAILED) { ++ munmap (buffer->map_address, buffer->map_size); ++ buffer->map_address = MAP_FAILED; ++ } ++ ++ memset (&destroy_dumb_buffer_request, 0, sizeof(struct drm_mode_destroy_dumb)); ++ destroy_dumb_buffer_request.handle = buffer->handle; ++ ++ if (drmIoctl (backend->device_fd, ++ DRM_IOCTL_MODE_DESTROY_DUMB, ++ &destroy_dumb_buffer_request) < 0) ++ ply_trace ("Could not deallocate GEM object %u: %m", buffer->handle); ++ ++ free (buffer); ++} ++ ++static ply_renderer_buffer_t * ++get_buffer_from_id (ply_renderer_backend_t *backend, ++ uint32_t id) ++{ ++ static ply_renderer_buffer_t *buffer; ++ ++ buffer = ply_hashtable_lookup (backend->output_buffers, (void *) (uintptr_t) id); ++ ++ return buffer; ++} ++ ++static uint32_t ++create_output_buffer (ply_renderer_backend_t *backend, ++ unsigned long width, ++ unsigned long height, ++ unsigned long *row_stride) ++{ ++ ply_renderer_buffer_t *buffer; ++ ++ buffer = ply_renderer_buffer_new (backend, width, height); ++ ++ if (buffer == NULL) { ++ ply_trace ("Could not allocate GEM object for frame buffer: %m"); ++ return 0; ++ } ++ ++ if (drmModeAddFB (backend->device_fd, width, height, ++ 24, 32, buffer->row_stride, buffer->handle, ++ &buffer->id) != 0) { ++ ply_trace ("Could not set up GEM object as frame buffer: %m"); ++ ply_renderer_buffer_free (backend, buffer); ++ return 0; ++ } ++ ++ *row_stride = buffer->row_stride; ++ ++ buffer->added_fb = true; ++ ply_hashtable_insert (backend->output_buffers, ++ (void *) (uintptr_t) buffer->id, ++ buffer); ++ ++ return buffer->id; ++} ++ ++static bool ++map_buffer (ply_renderer_backend_t *backend, ++ uint32_t buffer_id) ++{ ++ ply_renderer_buffer_t *buffer; ++ ++ buffer = get_buffer_from_id (backend, buffer_id); ++ ++ assert (buffer != NULL); ++ ++ return ply_renderer_buffer_map (backend, buffer); ++} ++ ++static void ++unmap_buffer (ply_renderer_backend_t *backend, ++ uint32_t buffer_id) ++{ ++ ply_renderer_buffer_t *buffer; ++ ++ buffer = get_buffer_from_id (backend, buffer_id); ++ ++ assert (buffer != NULL); ++ ++ ply_renderer_buffer_unmap (backend, buffer); ++} ++ ++static char * ++begin_flush (ply_renderer_backend_t *backend, ++ uint32_t buffer_id) ++{ ++ ply_renderer_buffer_t *buffer; ++ ++ buffer = get_buffer_from_id (backend, buffer_id); ++ ++ assert (buffer != NULL); ++ ++ return buffer->map_address; ++} ++ ++static void ++end_flush (ply_renderer_backend_t *backend, ++ uint32_t buffer_id) ++{ ++ ply_renderer_buffer_t *buffer; ++ ++ buffer = get_buffer_from_id (backend, buffer_id); ++ ++ assert (buffer != NULL); ++ ++ if (backend->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 (backend->device_fd, buffer->id, &flush_area, 1); ++ ++ if (ret == -ENOSYS) ++ backend->requires_explicit_flushing = false; ++ } ++} ++ ++static void ++destroy_output_buffer (ply_renderer_backend_t *backend, ++ uint32_t buffer_id) ++{ ++ ply_renderer_buffer_t *buffer; ++ ++ buffer = ply_hashtable_remove (backend->output_buffers, ++ (void *) (uintptr_t) buffer_id); ++ ++ assert (buffer != NULL); ++ ++ ply_renderer_buffer_free (backend, buffer); ++} ++ ++static bool + ply_renderer_head_add_connector (ply_renderer_head_t *head, + drmModeConnector *connector, + int connector_mode_index) +@@ -185,6 +426,11 @@ ply_renderer_head_new (ply_renderer_backend_t *backend, + assert (ply_array_get_size (head->connector_ids) > 0); + + head->pixel_buffer = ply_pixel_buffer_new (head->area.width, head->area.height); ++ ply_pixel_buffer_set_device_scale (head->pixel_buffer, ++ ply_get_device_scale (head->area.width, ++ head->area.height, ++ connector->mmWidth, ++ connector->mmHeight)); + + ply_trace ("Creating %ldx%ld renderer head", head->area.width, head->area.height); + ply_pixel_buffer_fill_with_color (head->pixel_buffer, NULL, +@@ -241,25 +487,21 @@ ply_renderer_head_map (ply_renderer_backend_t *backend, + + assert (backend != NULL); + assert (backend->device_fd >= 0); +- assert (backend->driver_interface != NULL); +- assert (backend->driver != NULL); ++ assert (backend != NULL); + + assert (head != NULL); + + ply_trace ("Creating buffer for %ldx%ld renderer head", head->area.width, head->area.height); +- head->scan_out_buffer_id = +- backend->driver_interface->create_buffer (backend->driver, +- head->area.width, head->area.height, +- &head->row_stride); ++ head->scan_out_buffer_id = create_output_buffer (backend, ++ head->area.width, head->area.height, ++ &head->row_stride); + + if (head->scan_out_buffer_id == 0) + return false; + + ply_trace ("Mapping buffer for %ldx%ld renderer head", head->area.width, head->area.height); +- if (!backend->driver_interface->map_buffer (backend->driver, +- head->scan_out_buffer_id)) { +- backend->driver_interface->destroy_buffer (backend->driver, +- head->scan_out_buffer_id); ++ if (!map_buffer (backend, head->scan_out_buffer_id)) { ++ destroy_output_buffer (backend, head->scan_out_buffer_id); + head->scan_out_buffer_id = 0; + return false; + } +@@ -271,8 +513,7 @@ ply_renderer_head_map (ply_renderer_backend_t *backend, + + scan_out_set = reset_scan_out_buffer_if_needed (backend, head); + if (!scan_out_set && backend->is_active) { +- backend->driver_interface->destroy_buffer (backend->driver, +- head->scan_out_buffer_id); ++ destroy_output_buffer (backend, head->scan_out_buffer_id); + head->scan_out_buffer_id = 0; + return false; + } +@@ -285,11 +526,9 @@ ply_renderer_head_unmap (ply_renderer_backend_t *backend, + ply_renderer_head_t *head) + { + ply_trace ("unmapping %ldx%ld renderer head", head->area.width, head->area.height); +- backend->driver_interface->unmap_buffer (backend->driver, +- head->scan_out_buffer_id); ++ unmap_buffer (backend, head->scan_out_buffer_id); + +- backend->driver_interface->destroy_buffer (backend->driver, +- head->scan_out_buffer_id); ++ destroy_output_buffer (backend, head->scan_out_buffer_id); + head->scan_out_buffer_id = 0; + } + +@@ -375,10 +614,19 @@ create_backend (const char *device_name, + backend->heads = ply_list_new (); + backend->input_source.key_buffer = ply_buffer_new (); + backend->terminal = terminal; ++ backend->requires_explicit_flushing = true; ++ backend->output_buffers = ply_hashtable_new (ply_hashtable_direct_hash, ++ ply_hashtable_direct_compare); + + return backend; + } + ++static const char * ++get_device_name (ply_renderer_backend_t *backend) ++{ ++ return backend->device_name; ++} ++ + static void + destroy_backend (ply_renderer_backend_t *backend) + { +@@ -386,6 +634,9 @@ destroy_backend (ply_renderer_backend_t *backend) + free_heads (backend); + + free (backend->device_name); ++ ply_hashtable_free (backend->output_buffers); ++ ++ drmModeFreeResources (backend->resources); + + free (backend); + } +@@ -455,44 +706,29 @@ load_driver (ply_renderer_backend_t *backend) + return false; + } + +- backend->driver_interface = ply_renderer_generic_driver_get_interface (device_fd); +- backend->driver_supports_mapping_console = false; +- +- if (backend->driver_interface == NULL) { +- close (device_fd); +- return false; +- } +- +- backend->driver = backend->driver_interface->create_driver (device_fd); +- +- if (backend->driver == NULL) { +- close (device_fd); +- return false; +- } +- + backend->device_fd = device_fd; + ++ drmDropMaster (device_fd); ++ + return true; + } + + static void +-unload_driver (ply_renderer_backend_t *backend) ++unload_backend (ply_renderer_backend_t *backend) + { +- if (backend->driver == NULL) ++ if (backend == NULL) + return; + +- ply_trace ("unloading driver"); +- assert (backend->driver_interface != NULL); +- +- backend->driver_interface->destroy_driver (backend->driver); +- backend->driver = NULL; +- +- backend->driver_interface = NULL; ++ ply_trace ("unloading backend"); + + if (backend->device_fd >= 0) { + drmClose (backend->device_fd); + backend->device_fd = -1; + } ++ ++ destroy_backend (backend); ++ backend = NULL; ++ + } + + static bool +@@ -540,7 +776,7 @@ close_device (ply_renderer_backend_t *backend) + backend); + } + +- unload_driver (backend); ++ unload_backend (backend); + } + + static drmModeCrtc * +@@ -732,34 +968,6 @@ create_heads_for_active_connectors (ply_renderer_backend_t *backend) + + ply_hashtable_free (heads_by_controller_id); + +-#ifdef PLY_ENABLE_DEPRECATED_GDM_TRANSITION +- /* If the driver doesn't support mapping the fb console +- * then we can't get a smooth crossfade transition to +- * the display manager unless we use the /dev/fb interface +- * or the plymouth deactivate interface. +- * +- * In multihead configurations, we'd rather have working +- * multihead, but otherwise bail now. +- */ +- if (!backend->driver_supports_mapping_console && +- ply_list_get_length (backend->heads) == 1) { +- ply_list_node_t *node; +- ply_renderer_head_t *head; +- +- node = ply_list_get_first_node (backend->heads); +- head = (ply_renderer_head_t *) ply_list_node_get_data (node); +- +- if (ply_array_get_size (head->connector_ids) == 1) { +- ply_trace ("Only one monitor configured, and driver doesn't " +- "support mapping console, so letting frame-buffer " +- "take over"); +- +- free_heads (backend); +- return false; +- } +- } +-#endif +- + return ply_list_get_length (backend->heads) > 0; + } + +@@ -774,7 +982,7 @@ has_32bpp_support (ply_renderer_backend_t *backend) + min_width = backend->resources->min_width; + min_height = backend->resources->min_height; + +- /* Some drivers set min_width/min_height to 0, ++ /* Some backends set min_width/min_height to 0, + * but 0x0 sized buffers don't work. + */ + if (min_width == 0) +@@ -783,10 +991,7 @@ has_32bpp_support (ply_renderer_backend_t *backend) + if (min_height == 0) + min_height = 1; + +- buffer_id = backend->driver_interface->create_buffer (backend->driver, +- min_width, +- min_height, +- &row_stride); ++ buffer_id = create_output_buffer (backend, min_width, min_height, &row_stride); + + if (buffer_id == 0) { + ply_trace ("Could not create minimal (%ux%u) 32bpp dummy buffer", +@@ -795,8 +1000,7 @@ has_32bpp_support (ply_renderer_backend_t *backend) + return false; + } + +- backend->driver_interface->destroy_buffer (backend->driver, +- buffer_id); ++ destroy_output_buffer (backend, buffer_id); + + return true; + } +@@ -860,93 +1064,10 @@ map_to_device (ply_renderer_backend_t *backend) + return head_mapped; + } + +-static bool +-ply_renderer_head_set_scan_out_buffer_to_console (ply_renderer_backend_t *backend, +- ply_renderer_head_t *head, +- bool should_set_to_black) +-{ +- unsigned long width; +- unsigned long height; +- unsigned long row_stride; +- uint32_t *shadow_buffer; +- ply_pixel_buffer_t *pixel_buffer; +- char *map_address; +- ply_rectangle_t area; +- +- if (!backend->driver_interface->fetch_buffer (backend->driver, +- head->console_buffer_id, +- &width, &height, &row_stride)) +- return false; +- +- if (!backend->driver_interface->map_buffer (backend->driver, +- head->console_buffer_id)) { +- backend->driver_interface->destroy_buffer (backend->driver, +- head->console_buffer_id); +- return false; +- } +- +- if (head->area.width != width || head->area.height != height) { +- /* Force black if the fb console resolution doesn't match our resolution +- */ +- area.x = 0; +- area.y = 0; +- area.width = width; +- area.height = height; +- +- should_set_to_black = true; +- ply_trace ("Console fb is %ldx%ld and screen contents are %ldx%ld. " +- "They aren't the same dimensions; forcing black", +- width, height, head->area.width, head->area.height); +- } else { +- area = head->area; +- } +- +- if (should_set_to_black) { +- pixel_buffer = ply_pixel_buffer_new (width, height); +- shadow_buffer = ply_pixel_buffer_get_argb32_data (pixel_buffer); +- } else { +- pixel_buffer = NULL; +- shadow_buffer = ply_pixel_buffer_get_argb32_data (head->pixel_buffer); +- } +- +- ply_trace ("Drawing %s to console fb", should_set_to_black ? "black" : "screen contents"); +- map_address = +- backend->driver_interface->begin_flush (backend->driver, +- head->console_buffer_id); +- +- flush_area ((char *) shadow_buffer, area.width * 4, +- map_address, row_stride, &area); +- +- backend->driver_interface->end_flush (backend->driver, +- head->console_buffer_id); +- +- backend->driver_interface->unmap_buffer (backend->driver, +- head->console_buffer_id); +- +- ply_trace ("Setting scan out hardware to console fb"); +- ply_renderer_head_set_scan_out_buffer (backend, +- head, head->console_buffer_id); +- +- backend->driver_interface->destroy_buffer (backend->driver, +- head->console_buffer_id); +- +- if (pixel_buffer != NULL) +- ply_pixel_buffer_free (pixel_buffer); +- +- return true; +-} +- + static void + unmap_from_device (ply_renderer_backend_t *backend) + { + ply_list_node_t *node; +- bool should_set_to_black; +- +- /* We only copy what's on screen back to the fb console +- * if there's one head (since in multihead set ups the fb console +- * is cloned). +- */ +- should_set_to_black = ply_list_get_length (backend->heads) > 1; + + node = ply_list_get_first_node (backend->heads); + while (node != NULL) { +@@ -956,13 +1077,6 @@ unmap_from_device (ply_renderer_backend_t *backend) + head = (ply_renderer_head_t *) ply_list_node_get_data (node); + next_node = ply_list_get_next_node (backend->heads, node); + +- if (backend->is_active) { +- ply_trace ("scanning out %s directly to console", +- should_set_to_black ? "black" : "splash"); +- ply_renderer_head_set_scan_out_buffer_to_console (backend, head, +- should_set_to_black); +- } +- + ply_renderer_head_unmap (backend, head); + + node = next_node; +@@ -1019,9 +1133,7 @@ flush_head (ply_renderer_backend_t *backend, + updated_region = ply_pixel_buffer_get_updated_areas (pixel_buffer); + areas_to_flush = ply_region_get_sorted_rectangle_list (updated_region); + +- map_address = +- backend->driver_interface->begin_flush (backend->driver, +- head->scan_out_buffer_id); ++ map_address = begin_flush (backend, head->scan_out_buffer_id); + + node = ply_list_get_first_node (areas_to_flush); + while (node != NULL) { +@@ -1041,8 +1153,7 @@ flush_head (ply_renderer_backend_t *backend, + node = next_node; + } + +- backend->driver_interface->end_flush (backend->driver, +- head->scan_out_buffer_id); ++ end_flush (backend, head->scan_out_buffer_id); + + ply_region_clear (updated_region); + } +@@ -1180,7 +1291,8 @@ ply_renderer_backend_get_interface (void) + .get_input_source = get_input_source, + .open_input_source = open_input_source, + .set_handler_for_input_source = set_handler_for_input_source, +- .close_input_source = close_input_source ++ .close_input_source = close_input_source, ++ .get_device_name = get_device_name + }; + + return &plugin_interface; +diff --git a/src/plugins/renderers/drm/ply-renderer-driver.h b/src/plugins/renderers/drm/ply-renderer-driver.h +deleted file mode 100644 +index f3febcf..0000000 +--- a/src/plugins/renderers/drm/ply-renderer-driver.h ++++ /dev/null +@@ -1,66 +0,0 @@ +-/* ply-renderer-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_DRIVER_H +-#define PLY_RENDERER_DRIVER_H +- +-#include <stdbool.h> +-#include <stdint.h> +- +-#include "ply-list.h" +-#include "ply-rectangle.h" +-#include "ply-utils.h" +- +-typedef struct _ply_renderer_driver ply_renderer_driver_t; +- +-typedef struct +-{ +- ply_renderer_driver_t * (*create_driver)(int device_fd); +- +- void (*destroy_driver)(ply_renderer_driver_t *driver); +- +- uint32_t (*create_buffer)(ply_renderer_driver_t *driver, +- unsigned long width, +- unsigned long height, +- unsigned long *row_stride); +- bool (*fetch_buffer)(ply_renderer_driver_t *driver, +- uint32_t buffer_id, +- unsigned long *width, +- unsigned long *height, +- unsigned long *row_stride); +- +- bool (*map_buffer)(ply_renderer_driver_t *driver, +- uint32_t buffer_id); +- +- void (*unmap_buffer)(ply_renderer_driver_t *driver, +- uint32_t buffer_id); +- +- char * (*begin_flush)(ply_renderer_driver_t * driver, +- uint32_t buffer_id); +- void (*end_flush)(ply_renderer_driver_t *driver, +- uint32_t buffer_id); +- +- void (*destroy_buffer)(ply_renderer_driver_t *driver, +- uint32_t buffer_id); +-} ply_renderer_driver_interface_t; +- +-#endif /* PLY_RENDERER_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-generic-driver.c b/src/plugins/renderers/drm/ply-renderer-generic-driver.c +deleted file mode 100644 +index b1be714..0000000 +--- a/src/plugins/renderers/drm/ply-renderer-generic-driver.c ++++ /dev/null +@@ -1,385 +0,0 @@ +-/* ply-renderer-generic-driver.c - interface to generic drm kms api +- * +- * Copyright (C) 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. +- * +- * Written by: Dave Airlie +- * Based on other renderer drivers written by Ray Strode +- */ +-#include "config.h" +- +-#include "ply-renderer-generic-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 <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 +-{ +- uint32_t id; +- +- uint32_t handle; +- uint32_t width; +- uint32_t height; +- uint32_t row_stride; +- +- void *map_address; +- uint32_t map_size; +- int map_count; +- +- uint32_t added_fb : 1; +-}; +- +-struct _ply_renderer_driver +-{ +- int device_fd; +- ply_hashtable_t *buffers; +- +- uint32_t requires_explicit_flushing : 1; +-}; +- +-static bool +-ply_renderer_buffer_map (ply_renderer_driver_t *driver, +- ply_renderer_buffer_t *buffer) +-{ +- struct drm_mode_map_dumb map_dumb_buffer_request; +- void *map_address; +- +- if (buffer->map_address != MAP_FAILED) { +- buffer->map_count++; +- return true; +- } +- +- memset (&map_dumb_buffer_request, 0, sizeof(struct drm_mode_map_dumb)); +- map_dumb_buffer_request.handle = buffer->handle; +- if (drmIoctl (driver->device_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb_buffer_request) < 0) { +- ply_trace ("Could not map GEM object %u: %m", buffer->handle); +- return false; +- } +- +- map_address = mmap (0, buffer->map_size, +- PROT_READ | PROT_WRITE, MAP_SHARED, +- driver->device_fd, map_dumb_buffer_request.offset); +- +- if (map_address == MAP_FAILED) +- return false; +- +- buffer->map_address = map_address; +- buffer->map_count++; +- +- return true; +-} +- +-static void +-ply_renderer_buffer_unmap (ply_renderer_driver_t *driver, +- ply_renderer_buffer_t *buffer) +-{ +- buffer->map_count--; +- +- assert (buffer->map_count >= 0); +-} +- +-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->requires_explicit_flushing = true; +- 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); +- +- free (driver); +-} +- +-static ply_renderer_buffer_t * +-ply_renderer_buffer_new (ply_renderer_driver_t *driver, +- uint32_t width, +- uint32_t height) +-{ +- ply_renderer_buffer_t *buffer; +- struct drm_mode_create_dumb create_dumb_buffer_request; +- +- buffer = calloc (1, sizeof(ply_renderer_buffer_t)); +- buffer->width = width; +- buffer->height = height; +- buffer->map_address = MAP_FAILED; +- +- memset (&create_dumb_buffer_request, 0, sizeof(struct drm_mode_create_dumb)); +- +- create_dumb_buffer_request.width = width; +- create_dumb_buffer_request.height = height; +- create_dumb_buffer_request.bpp = 32; +- create_dumb_buffer_request.flags = 0; +- +- if (drmIoctl (driver->device_fd, +- DRM_IOCTL_MODE_CREATE_DUMB, +- &create_dumb_buffer_request) < 0) { +- free (buffer); +- ply_trace ("Could not allocate GEM object for frame buffer: %m"); +- return NULL; +- } +- +- buffer->handle = create_dumb_buffer_request.handle; +- buffer->row_stride = create_dumb_buffer_request.pitch; +- buffer->map_size = create_dumb_buffer_request.size; +- +- ply_trace ("returning %ux%u buffer with stride %u", +- width, height, buffer->row_stride); +- +- return buffer; +-} +- +-static void +-ply_renderer_buffer_free (ply_renderer_driver_t *driver, +- ply_renderer_buffer_t *buffer) +-{ +- struct drm_mode_destroy_dumb destroy_dumb_buffer_request; +- +- if (buffer->added_fb) +- drmModeRmFB (driver->device_fd, buffer->id); +- +- if (buffer->map_address != MAP_FAILED) { +- munmap (buffer->map_address, buffer->map_size); +- buffer->map_address = MAP_FAILED; +- } +- +- memset (&destroy_dumb_buffer_request, 0, sizeof(struct drm_mode_destroy_dumb)); +- destroy_dumb_buffer_request.handle = buffer->handle; +- +- if (drmIoctl (driver->device_fd, +- DRM_IOCTL_MODE_DESTROY_DUMB, +- &destroy_dumb_buffer_request) < 0) +- ply_trace ("Could not deallocate GEM object %u: %m", buffer->handle); +- +- free (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", buffer_id); +- return false; +- } +- +- if (width != NULL) +- *width = buffer->width; +- +- if (height != NULL) +- *height = buffer->height; +- +- if (row_stride != NULL) +- *row_stride = buffer->row_stride; +- +- ply_trace ("fetched %ux%u buffer with stride %u", +- 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) +-{ +- ply_renderer_buffer_t *buffer; +- +- buffer = ply_renderer_buffer_new (driver, width, height); +- +- if (buffer == NULL) { +- ply_trace ("Could not allocate GEM object for frame buffer: %m"); +- return 0; +- } +- +- if (drmModeAddFB (driver->device_fd, width, height, +- 24, 32, buffer->row_stride, buffer->handle, +- &buffer->id) != 0) { +- ply_trace ("Could not set up GEM object as frame buffer: %m"); +- ply_renderer_buffer_free (driver, buffer); +- return 0; +- } +- +- *row_stride = buffer->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 ply_renderer_buffer_map (driver, buffer); +-} +- +-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); +- +- ply_renderer_buffer_unmap (driver, buffer); +-} +- +-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->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); +- +- 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 +-destroy_buffer (ply_renderer_driver_t *driver, +- uint32_t buffer_id) +-{ +- ply_renderer_buffer_t *buffer; +- +- buffer = ply_hashtable_remove (driver->buffers, +- (void *) (uintptr_t) buffer_id); +- +- assert (buffer != NULL); +- +- ply_renderer_buffer_free (driver, buffer); +-} +- +-ply_renderer_driver_interface_t * +-ply_renderer_generic_driver_get_interface (int device_fd) +-{ +- uint64_t supports_dumb_buffers; +- +- 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, +- }; +- +- +- if (drmGetCap (device_fd, DRM_CAP_DUMB_BUFFER, &supports_dumb_buffers) < 0) +- return NULL; +- +- if (!supports_dumb_buffers) +- return NULL; +- +- 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-generic-driver.h b/src/plugins/renderers/drm/ply-renderer-generic-driver.h +deleted file mode 100644 +index 053587a..0000000 +--- a/src/plugins/renderers/drm/ply-renderer-generic-driver.h ++++ /dev/null +@@ -1,33 +0,0 @@ +-/* ply-renderer-generic-driver.h +- * +- * Copyright (C) 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. +- * +- * Written by: Dave Airlie +- * Based on other renderer drivers written by Ray Strode +- */ +-#ifndef PLY_RENDERER_DUMB_DRIVER_H +-#define PLY_RENDERER_DUMB_DRIVER_H +- +-#include "ply-renderer-driver.h" +- +-#ifndef PLY_HIDE_FUNCTION_DECLARATIONS +-ply_renderer_driver_interface_t *ply_renderer_generic_driver_get_interface (int device_fd); +-#endif +- +-#endif /* PLY_RENDERER_GENERIC_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/plugin.c b/src/plugins/renderers/frame-buffer/plugin.c +index 418855a..41ad6cd 100644 +--- a/src/plugins/renderers/frame-buffer/plugin.c ++++ b/src/plugins/renderers/frame-buffer/plugin.c +@@ -365,6 +365,12 @@ open_device (ply_renderer_backend_t *backend) + return true; + } + ++static const char * ++get_device_name (ply_renderer_backend_t *backend) ++{ ++ return backend->device_name; ++} ++ + static void + close_device (ply_renderer_backend_t *backend) + { +@@ -732,7 +738,8 @@ ply_renderer_backend_get_interface (void) + .get_input_source = get_input_source, + .open_input_source = open_input_source, + .set_handler_for_input_source = set_handler_for_input_source, +- .close_input_source = close_input_source ++ .close_input_source = close_input_source, ++ .get_device_name = get_device_name + }; + + return &plugin_interface; +diff --git a/src/plugins/renderers/x11/plugin.c b/src/plugins/renderers/x11/plugin.c +index 1e1fe31..8948f69 100644 +--- a/src/plugins/renderers/x11/plugin.c ++++ b/src/plugins/renderers/x11/plugin.c +@@ -56,6 +56,7 @@ + #include "ply-logger.h" + #include "ply-rectangle.h" + #include "ply-region.h" ++#include "ply-utils.h" + + #include "ply-renderer.h" + #include "ply-renderer-plugin.h" +@@ -64,9 +65,10 @@ struct _ply_renderer_head + { + ply_renderer_backend_t *backend; + ply_pixel_buffer_t *pixel_buffer; +- ply_rectangle_t area; ++ ply_rectangle_t area; /* in device pixels */ + GtkWidget *window; + cairo_surface_t *image; ++ uint32_t scale; + uint32_t is_fullscreen : 1; + }; + +@@ -148,9 +150,14 @@ open_device (ply_renderer_backend_t *backend) + Display *display; + int display_fd; + ++ gdk_set_allowed_backends ("x11"); ++ + if (!gtk_init_check (0, NULL)) + return false; + ++ /* Force gtk+ to deal in device pixels */ ++ gdk_x11_display_set_window_scale (gdk_display_get_default (), 1); ++ + display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); + display_fd = ConnectionNumber (display); + backend->display_watch = ply_event_loop_watch_fd (backend->loop, +@@ -163,6 +170,12 @@ open_device (ply_renderer_backend_t *backend) + return true; + } + ++static const char * ++get_device_name (ply_renderer_backend_t *backend) ++{ ++ return gdk_display_get_name (gdk_display_get_default ()); ++} ++ + static void + close_device (ply_renderer_backend_t *backend) + { +@@ -183,7 +196,9 @@ create_fake_multi_head_setup (ply_renderer_backend_t *backend) + head->area.y = 0; + head->area.width = 800; /* FIXME hardcoded */ + head->area.height = 600; ++ head->scale = 1; + head->pixel_buffer = ply_pixel_buffer_new (head->area.width, head->area.height); ++ ply_pixel_buffer_set_device_scale (head->pixel_buffer, head->scale); + + ply_list_append_data (backend->heads, head); + +@@ -194,7 +209,9 @@ create_fake_multi_head_setup (ply_renderer_backend_t *backend) + head->area.y = 0; + head->area.width = 640; /* FIXME hardcoded */ + head->area.height = 480; ++ head->scale = 1; + head->pixel_buffer = ply_pixel_buffer_new (head->area.width, head->area.height); ++ ply_pixel_buffer_set_device_scale (head->pixel_buffer, head->scale); + + ply_list_append_data (backend->heads, head); + } +@@ -204,8 +221,11 @@ create_fullscreen_single_head_setup (ply_renderer_backend_t *backend) + { + ply_renderer_head_t *head; + GdkRectangle monitor_geometry; ++ int width_mm, height_mm; + + gdk_screen_get_monitor_geometry (gdk_screen_get_default (), 0, &monitor_geometry); ++ width_mm = gdk_screen_get_monitor_width_mm (gdk_screen_get_default (), 0); ++ height_mm = gdk_screen_get_monitor_height_mm (gdk_screen_get_default (), 0); + + head = calloc (1, sizeof(ply_renderer_head_t)); + +@@ -215,7 +235,11 @@ create_fullscreen_single_head_setup (ply_renderer_backend_t *backend) + head->area.width = monitor_geometry.width; + head->area.height = monitor_geometry.height; + head->is_fullscreen = true; ++ head->scale = ply_get_device_scale (monitor_geometry.width, ++ monitor_geometry.height, ++ width_mm, height_mm); + head->pixel_buffer = ply_pixel_buffer_new (head->area.width, head->area.height); ++ ply_pixel_buffer_set_device_scale (head->pixel_buffer, head->scale); + + ply_list_append_data (backend->heads, head); + } +@@ -380,6 +404,12 @@ flush_head (ply_renderer_backend_t *backend, + area_to_flush = (ply_rectangle_t *) ply_list_node_get_data (node); + next_node = ply_list_get_next_node (areas_to_flush, node); + ++ cairo_surface_mark_dirty_rectangle (head->image, ++ area_to_flush->x, ++ area_to_flush->y, ++ area_to_flush->width, ++ area_to_flush->height); ++ + gtk_widget_queue_draw_area (head->window, + area_to_flush->x, + area_to_flush->y, +@@ -515,7 +545,8 @@ ply_renderer_backend_get_interface (void) + .get_input_source = get_input_source, + .open_input_source = open_input_source, + .set_handler_for_input_source = set_handler_for_input_source, +- .close_input_source = close_input_source ++ .close_input_source = close_input_source, ++ .get_device_name = get_device_name + }; + + return &plugin_interface; +diff --git a/src/plugins/splash/details/plugin.c b/src/plugins/splash/details/plugin.c +index 8e55d05..f534450 100644 +--- a/src/plugins/splash/details/plugin.c ++++ b/src/plugins/splash/details/plugin.c +@@ -77,6 +77,8 @@ struct _ply_boot_splash_plugin + ply_list_t *views; + ply_boot_splash_display_type_t state; + ply_list_t *messages; ++ ++ ply_buffer_t *boot_buffer; + }; + + static view_t * +@@ -239,6 +241,15 @@ add_text_display (ply_boot_splash_plugin_t *plugin, + ply_terminal_activate_vt (terminal); + + ply_list_append_data (plugin->views, view); ++ ++ if (plugin->boot_buffer != NULL) { ++ size_t size; ++ const char *bytes; ++ ++ size = ply_buffer_get_size (plugin->boot_buffer); ++ bytes = ply_buffer_get_bytes (plugin->boot_buffer); ++ view_write (view, bytes, size); ++ } + } + + static void +@@ -282,8 +293,9 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, + plugin); + + if (boot_buffer) { +- size = ply_buffer_get_size (boot_buffer); ++ plugin->boot_buffer = boot_buffer; + ++ size = ply_buffer_get_size (boot_buffer); + write_on_views (plugin, ply_buffer_get_bytes (boot_buffer), size); + } + +@@ -330,7 +342,7 @@ display_normal (ply_boot_splash_plugin_t *plugin) + ply_list_node_t *node; + + if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_NORMAL) +- write_on_views (plugin, "\r\n", strlen ("\r\n")); ++ write_on_views (plugin, "\n", strlen ("\n")); + + plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL; + +@@ -343,7 +355,7 @@ display_normal (ply_boot_splash_plugin_t *plugin) + next_node = ply_list_get_next_node (plugin->messages, node); + + write_on_views (plugin, message, strlen (message)); +- write_on_views (plugin, "\r\n", strlen ("\r\n")); ++ write_on_views (plugin, "\n", strlen ("\n")); + + ply_list_remove_node (plugin->messages, node); + node = next_node; +@@ -358,7 +370,7 @@ display_password (ply_boot_splash_plugin_t *plugin, + int i; + + if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY) +- write_on_views (plugin, "\r\n", strlen ("\r\n")); ++ write_on_views (plugin, "\n", strlen ("\n")); + else + write_on_views (plugin, + CLEAR_LINE_SEQUENCE, +@@ -387,7 +399,7 @@ display_question (ply_boot_splash_plugin_t *plugin, + const char *entry_text) + { + if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY) +- write_on_views (plugin, "\r\n", strlen ("\r\n")); ++ write_on_views (plugin, "\n", strlen ("\n")); + else + write_on_views (plugin, + CLEAR_LINE_SEQUENCE, +@@ -407,7 +419,7 @@ display_message (ply_boot_splash_plugin_t *plugin, + { + if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL) { + write_on_views (plugin, message, strlen (message)); +- write_on_views (plugin, "\r\n", strlen ("\r\n")); ++ write_on_views (plugin, "\n", strlen ("\n")); + } else { + ply_list_append_data (plugin->messages, strdup (message)); + } +diff --git a/src/plugins/splash/fade-throbber/plugin.c b/src/plugins/splash/fade-throbber/plugin.c +index 1643b87..a7ab4ef 100644 +--- a/src/plugins/splash/fade-throbber/plugin.c ++++ b/src/plugins/splash/fade-throbber/plugin.c +@@ -104,6 +104,7 @@ struct _ply_boot_splash_plugin + double now; + + uint32_t is_animating : 1; ++ uint32_t is_visible : 1; + }; + + ply_boot_splash_plugin_interface_t *ply_boot_splash_plugin_get_interface (void); +@@ -264,6 +265,8 @@ view_free (view_t *view) + ply_label_free (view->message_label); + free_stars (view); + ++ ply_pixel_display_set_draw_handler (view->display, NULL, NULL); ++ + free (view); + } + +@@ -293,8 +296,12 @@ load_views (ply_boot_splash_plugin_t *plugin) + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + +- if (view_load (view)) ++ if (view_load (view)) { + view_loaded = true; ++ } else { ++ ply_list_remove_node (plugin->views, node); ++ view_free (view); ++ } + + node = next_node; + } +@@ -745,7 +752,14 @@ add_pixel_display (ply_boot_splash_plugin_t *plugin, + (ply_pixel_display_draw_handler_t) + on_draw, view); + +- ply_list_append_data (plugin->views, view); ++ if (plugin->is_visible) { ++ if (view_load (view)) ++ ply_list_append_data (plugin->views, view); ++ else ++ view_free (view); ++ } else { ++ ply_list_append_data (plugin->views, view); ++ } + } + + static void +@@ -763,7 +777,6 @@ remove_pixel_display (ply_boot_splash_plugin_t *plugin, + next_node = ply_list_get_next_node (plugin->views, node); + + if (view->display == display) { +- ply_pixel_display_set_draw_handler (view->display, NULL, NULL); + view_free (view); + ply_list_remove_node (plugin->views, node); + return; +@@ -806,6 +819,8 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, + return false; + } + ++ plugin->is_visible = true; ++ + ply_trace ("starting boot animation"); + start_animation (plugin); + +@@ -940,6 +955,8 @@ hide_splash_screen (ply_boot_splash_plugin_t *plugin, + { + assert (plugin != NULL); + ++ plugin->is_visible = false; ++ + if (plugin->loop != NULL) { + stop_animation (plugin); + +diff --git a/src/plugins/splash/script/script-lib-sprite.c b/src/plugins/splash/script/script-lib-sprite.c +index f292d90..c49297d 100644 +--- a/src/plugins/splash/script/script-lib-sprite.c ++++ b/src/plugins/splash/script/script-lib-sprite.c +@@ -416,6 +416,22 @@ static script_return_t sprite_window_set_background_bottom_color (script_state_t + return script_return_obj_null (); + } + ++static void script_lib_draw_brackground (ply_pixel_buffer_t *pixel_buffer, ++ ply_rectangle_t *clip_area, ++ script_lib_sprite_data_t *data) ++{ ++ if (data->background_color_start == data->background_color_end) { ++ ply_pixel_buffer_fill_with_hex_color (pixel_buffer, ++ clip_area, ++ data->background_color_start); ++ } else { ++ ply_pixel_buffer_fill_with_gradient (pixel_buffer, ++ clip_area, ++ data->background_color_start, ++ data->background_color_end); ++ } ++} ++ + static void script_lib_sprite_draw_area (script_lib_display_t *display, + ply_pixel_buffer_t *pixel_buffer, + int x, +@@ -425,6 +441,7 @@ static void script_lib_sprite_draw_area (script_lib_display_t *display, + { + ply_rectangle_t clip_area; + ply_list_node_t *node; ++ sprite_t *sprite; + script_lib_sprite_data_t *data = display->data; + + clip_area.x = x; +@@ -432,22 +449,33 @@ static void script_lib_sprite_draw_area (script_lib_display_t *display, + clip_area.width = width; + clip_area.height = height; + +- if (data->background_color_start == data->background_color_end) { +- ply_pixel_buffer_fill_with_hex_color (pixel_buffer, +- &clip_area, +- data->background_color_start); ++ ++ node = ply_list_get_first_node (data->sprite_list); ++ sprite = ply_list_node_get_data (node); ++ ++ /* Check If the first sprite should be rendered opaque */ ++ if (sprite->image && !sprite->remove_me && ++ ply_pixel_buffer_is_opaque (sprite->image) && sprite->opacity == 1.0) { ++ int position_x = sprite->x - display->x; ++ int position_y = sprite->y - display->y; ++ ++ /* In that case only draw the background if the sprite doesn't ++ * cover the complete area */ ++ if (position_x > x || position_y > y || ++ (ply_pixel_buffer_get_width (sprite->image) + position_x) < (x + width) || ++ (ply_pixel_buffer_get_height (sprite->image) + position_y) < (y + height)) ++ script_lib_draw_brackground (pixel_buffer, &clip_area, data); + } else { +- ply_pixel_buffer_fill_with_gradient (pixel_buffer, +- &clip_area, +- data->background_color_start, +- data->background_color_end); ++ script_lib_draw_brackground (pixel_buffer, &clip_area, data); + } ++ + for (node = ply_list_get_first_node (data->sprite_list); + node; + node = ply_list_get_next_node (data->sprite_list, node)) { +- sprite_t *sprite = ply_list_node_get_data (node); + int position_x, position_y; + ++ sprite = ply_list_node_get_data (node); ++ + if (!sprite->image) continue; + if (sprite->remove_me) continue; + if (sprite->opacity < 0.011) continue; +diff --git a/src/plugins/splash/space-flares/plugin.c b/src/plugins/splash/space-flares/plugin.c +index 5212c38..5af99c1 100644 +--- a/src/plugins/splash/space-flares/plugin.c ++++ b/src/plugins/splash/space-flares/plugin.c +@@ -1387,7 +1387,14 @@ add_pixel_display (ply_boot_splash_plugin_t *plugin, + (ply_pixel_display_draw_handler_t) + on_draw, view); + +- ply_list_append_data (plugin->views, view); ++ if (plugin->is_visible) { ++ if (view_load (view)) ++ ply_list_append_data (plugin->views, view); ++ else ++ view_free (view); ++ } else { ++ ply_list_append_data (plugin->views, view); ++ } + } + + static void +diff --git a/src/plugins/splash/text/plugin.c b/src/plugins/splash/text/plugin.c +index 468bb89..8260daa 100644 +--- a/src/plugins/splash/text/plugin.c ++++ b/src/plugins/splash/text/plugin.c +@@ -472,6 +472,9 @@ add_text_display (ply_boot_splash_plugin_t *plugin, + on_draw, view); + + ply_list_append_data (plugin->views, view); ++ ++ if (plugin->is_animating) ++ view_start_animation (view); + } + + static void +@@ -553,7 +556,9 @@ on_boot_progress (ply_boot_splash_plugin_t *plugin, + next_node = ply_list_get_next_node (plugin->views, node); + + ply_text_step_bar_set_percent_done (view->step_bar, percent_done); +- ply_text_step_bar_draw (view->step_bar); ++ ++ if (plugin->is_animating) ++ ply_text_step_bar_draw (view->step_bar); + + node = next_node; + } +diff --git a/src/plugins/splash/throbgress/plugin.c b/src/plugins/splash/throbgress/plugin.c +index c105e02..a1c8a90 100644 +--- a/src/plugins/splash/throbgress/plugin.c ++++ b/src/plugins/splash/throbgress/plugin.c +@@ -625,7 +625,14 @@ add_pixel_display (ply_boot_splash_plugin_t *plugin, + (ply_pixel_display_draw_handler_t) + on_draw, view); + +- ply_list_append_data (plugin->views, view); ++ if (plugin->is_visible) { ++ if (view_load (view)) ++ ply_list_append_data (plugin->views, view); ++ else ++ view_free (view); ++ } else { ++ ply_list_append_data (plugin->views, view); ++ } + } + + static void +diff --git a/src/plugins/splash/tribar/plugin.c b/src/plugins/splash/tribar/plugin.c +index 0dcd7f8..ecc17ea 100644 +--- a/src/plugins/splash/tribar/plugin.c ++++ b/src/plugins/splash/tribar/plugin.c +@@ -478,6 +478,9 @@ add_text_display (ply_boot_splash_plugin_t *plugin, + on_draw, view); + + ply_list_append_data (plugin->views, view); ++ ++ if (plugin->is_animating) ++ view_start_animation (view); + } + + static void +@@ -559,7 +562,9 @@ on_boot_progress (ply_boot_splash_plugin_t *plugin, + 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); ++ ++ if (plugin->is_animating) ++ ply_text_progress_bar_draw (view->progress_bar); + + node = next_node; + } +diff --git a/src/plugins/splash/two-step/plugin.c b/src/plugins/splash/two-step/plugin.c +index 0899ace..070741d 100644 +--- a/src/plugins/splash/two-step/plugin.c ++++ b/src/plugins/splash/two-step/plugin.c +@@ -267,11 +267,15 @@ view_load (view_t *view) + + view_load_end_animation (view); + +- ply_trace ("loading progress animation"); +- if (!ply_progress_animation_load (view->progress_animation)) { +- ply_trace ("optional progress animation wouldn't load"); +- ply_progress_animation_free (view->progress_animation); +- view->progress_animation = NULL; ++ if (view->progress_animation != NULL) { ++ ply_trace ("loading progress animation"); ++ if (!ply_progress_animation_load (view->progress_animation)) { ++ ply_trace ("optional progress animation wouldn't load"); ++ ply_progress_animation_free (view->progress_animation); ++ view->progress_animation = NULL; ++ } ++ } else { ++ ply_trace ("this theme has no progress animation"); + } + + if (view->throbber != NULL) { +@@ -875,7 +879,12 @@ draw_background (view_t *view, + 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); ++ ++ /* We must pass NULL as fill area, because the fill area ++ must be sized as the image we're sourcing from, otherwise ++ sampling does not work ++ */ ++ ply_pixel_buffer_fill_with_argb32_data_with_clip (pixel_buffer, NULL, NULL, data); + } + + if (plugin->watermark_image != NULL) { +@@ -986,7 +995,14 @@ add_pixel_display (ply_boot_splash_plugin_t *plugin, + ply_pixel_display_set_draw_handler (view->display, + (ply_pixel_display_draw_handler_t) + on_draw, view); +- ply_list_append_data (plugin->views, view); ++ if (plugin->is_visible) { ++ if (view_load (view)) ++ ply_list_append_data (plugin->views, view); ++ else ++ view_free (view); ++ } else { ++ ply_list_append_data (plugin->views, view); ++ } + } + + static void +@@ -1329,8 +1345,8 @@ system_update (ply_boot_splash_plugin_t *plugin, + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); +- ply_progress_animation_set_percent_done (view->progress_animation, +- (double) progress / 100.f); ++ if (view->progress_animation != NULL) ++ ply_progress_animation_set_percent_done (view->progress_animation, (double) progress / 100.f); + node = next_node; + } + } +diff --git a/src/plymouthd.defaults b/src/plymouthd.defaults +index fc48b15..4d3b6d4 100644 +--- a/src/plymouthd.defaults ++++ b/src/plymouthd.defaults +@@ -3,3 +3,4 @@ + [Daemon] + Theme=spinner + ShowDelay=5 ++DeviceTimeout=5 +diff --git a/systemd-units/Makefile.am b/systemd-units/Makefile.am +index 89355ac..b1d843b 100644 +--- a/systemd-units/Makefile.am ++++ b/systemd-units/Makefile.am +@@ -50,21 +50,20 @@ install-data-hook: + $(LN_S) ../plymouth-halt.service) + + uninstall-hook: +- rm -f \ + (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/initrd-switch-root.target.wants && \ +- rm -f plymouth-start.service 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) \ ++ rm -f plymouth-start.service plymouth-read-write.service) + (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/multi-user.target.wants && \ +- rm -f plymouth-quit.service plymouth-quit-wait.service) \ ++ rm -f plymouth-quit.service plymouth-quit-wait.service) + (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/reboot.target.wants && \ +- rm -f plymouth-reboot.service) \ ++ rm -f plymouth-reboot.service) + (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/kexec.target.wants && \ +- rm -f plymouth-kexec.service) \ ++ rm -f plymouth-kexec.service) + (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/poweroff.target.wants && \ +- rm -f plymouth-poweroff.service) \ ++ rm -f plymouth-poweroff.service) + (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/halt.target.wants && \ +- rm -f plymouth-halt.service) \ ++ rm -f plymouth-halt.service) + rmdir --ignore-fail-on-non-empty \ + $(DESTDIR)$(SYSTEMD_UNIT_DIR)/sysinit.target.wants \ + $(DESTDIR)$(SYSTEMD_UNIT_DIR)/multi-user.target.wants \ +diff --git a/themes/script/script.script b/themes/script/script.script +index 7ea9d5e..25a2f2b 100644 +--- a/themes/script/script.script ++++ b/themes/script/script.script +@@ -152,27 +152,19 @@ Plymouth.SetQuitFunction(quit_callback); + + #----------------------------------------- Message -------------------------------- + +-message_sprites = []; +-message_sprite_count = 0; +-message_sprite_y = 10; ++message_sprite = Sprite(); ++message_sprite.SetPosition(10, 10, 10000); + + fun display_message_callback (text) + { + my_image = Image.Text(text, 1, 1, 1); +- message_sprites[message_sprite_count] = Sprite(my_image); +- message_sprites[message_sprite_count].SetPosition(10, message_sprite_y, 10000); +- message_sprites[message_sprite_count].text = text; +- message_sprite_count++; +- message_sprite_y += my_image.GetHeight(); ++ message_sprite.SetImage(my_image); + } + + fun hide_message_callback (text) + { +- for (i = 0; i < message_sprite_count; i++) +- { +- if (message_sprites[i].text == text) +- message_sprites[i] = NULL; +- } ++ message_sprite = Sprite(); ++ message_sprite.SetPosition(10, 10, 10000); + } + + Plymouth.SetDisplayMessageFunction (display_message_callback); |