diff options
author | Ray Strode <rstrode@redhat.com> | 2009-09-28 18:03:11 -0400 |
---|---|---|
committer | Ray Strode <rstrode@redhat.com> | 2009-09-28 18:03:11 -0400 |
commit | 3fe3aabc7b1a5752daf8c99aff236cfbcddc75e7 (patch) | |
tree | 8a584d2672698a971c5f89e28264fd500297a063 | |
parent | a8f0572cb279ae2252cec169522a3e3e5b22f105 (diff) | |
parent | 6ceccc7ce8a0ff0ae6efdd75b23670f77860af9b (diff) |
[branch-merge] Support multi-head renderering
This merges the "seat-rework" branch to master.
Instead of talking to /dev/fb, we now use libdrm
to set up the drawing area. This gives us the
functionality we need for querying the user's
monitor layout.
There are cases where /dev/fb works when the new
interfaces don't. For those cases we fall back
to /dev/fb.
85 files changed, 11782 insertions, 5480 deletions
diff --git a/configure.ac b/configure.ac index af507ffd..c98a65b9 100644 --- a/configure.ac +++ b/configure.ac @@ -56,6 +56,10 @@ PKG_CHECK_MODULES(GTK, [gtk+-2.0 >= 2.12.0 ]) AC_SUBST(GTK_CFLAGS) AC_SUBST(GTK_LIBS) +PKG_CHECK_MODULES(DRM, [libdrm libdrm_intel libdrm_radeon libdrm_nouveau]) +AC_SUBST(DRM_CFLAGS) +AC_SUBST(DRM_LIBS) + AC_ARG_ENABLE(tracing, AS_HELP_STRING([--enable-tracing],[enable verbose tracing code]),enable_tracing=$enableval,enable_tracing=yes) if test x$enable_tracing = xyes; then @@ -209,6 +213,9 @@ AC_OUTPUT([Makefile src/libplybootsplash/Makefile src/plymouth-1.pc src/plugins/Makefile + src/plugins/renderers/Makefile + src/plugins/renderers/frame-buffer/Makefile + src/plugins/renderers/drm/Makefile src/plugins/splash/Makefile src/plugins/splash/throbgress/Makefile src/plugins/splash/fade-throbber/Makefile diff --git a/scripts/plymouth-populate-initrd.in b/scripts/plymouth-populate-initrd.in index dcf2b427..14eb6fc7 100755 --- a/scripts/plymouth-populate-initrd.in +++ b/scripts/plymouth-populate-initrd.in @@ -93,6 +93,9 @@ fi inst ${PLYMOUTH_PLUGIN_PATH}/${PLYMOUTH_MODULE_NAME}.so $INITRDDIR +inst ${PLYMOUTH_PLUGIN_PATH}/renderers/drm.so $INITRDDIR +inst ${PLYMOUTH_PLUGIN_PATH}/renderers/frame-buffer.so $INITRDDIR + if [ -d ${DATADIR}/plymouth/themes/${PLYMOUTH_THEME_NAME} ]; then for x in ${DATADIR}/plymouth/themes/${PLYMOUTH_THEME_NAME}/* ; do [ ! -f "$x" ] && break diff --git a/src/libply/Makefile.am b/src/libply/Makefile.am index e0cb84de..50b4d069 100644 --- a/src/libply/Makefile.am +++ b/src/libply/Makefile.am @@ -14,7 +14,6 @@ libplydir = $(includedir)/plymouth-1/ply libply_HEADERS = \ ply-event-loop.h \ ply-command-parser.h \ - ply-frame-buffer.h \ ply-buffer.h \ ply-array.h \ ply-bitarray.h \ @@ -23,7 +22,8 @@ libply_HEADERS = \ ply-logger.h \ ply-key-file.h \ ply-progress.h \ - ply-terminal.h \ + ply-rectangle.h \ + ply-region.h \ ply-terminal-session.h \ ply-trigger.h \ ply-utils.h @@ -36,7 +36,6 @@ libply_la_LDFLAGS = -export-symbols-regex '^[^_].*' \ libply_la_SOURCES = ply-event-loop.c \ $(libply_HEADERS) \ ply-command-parser.c \ - ply-frame-buffer.c \ ply-buffer.c \ ply-array.c \ ply-bitarray.c \ @@ -45,7 +44,8 @@ libply_la_SOURCES = ply-event-loop.c \ ply-logger.c \ ply-key-file.c \ ply-progress.c \ - ply-terminal.c \ + ply-rectangle.c \ + ply-region.c \ ply-terminal-session.c \ ply-trigger.c \ ply-utils.c diff --git a/src/libply/ply-event-loop.c b/src/libply/ply-event-loop.c index 2c03a528..33bd52c7 100644 --- a/src/libply/ply-event-loop.c +++ b/src/libply/ply-event-loop.c @@ -489,6 +489,17 @@ ply_event_loop_new (void) return loop; } +ply_event_loop_t * +ply_event_loop_get_default (void) +{ + static ply_event_loop_t *loop = NULL; + + if (loop == NULL) + loop = ply_event_loop_new (); + + return loop; +} + static void ply_event_loop_free_exit_closures (ply_event_loop_t *loop) { diff --git a/src/libply/ply-event-loop.h b/src/libply/ply-event-loop.h index 98b9cd17..ae29d285 100644 --- a/src/libply/ply-event-loop.h +++ b/src/libply/ply-event-loop.h @@ -48,6 +48,7 @@ typedef void (* ply_event_loop_timeout_handler_t) (void *user_data, #ifndef PLY_HIDE_FUNCTION_DECLARATIONS ply_event_loop_t *ply_event_loop_new (void); void ply_event_loop_free (ply_event_loop_t *loop); +ply_event_loop_t *ply_event_loop_get_default (void); ply_fd_watch_t *ply_event_loop_watch_fd (ply_event_loop_t *loop, int fd, ply_event_loop_fd_status_t status, diff --git a/src/libply/ply-frame-buffer.c b/src/libply/ply-frame-buffer.c deleted file mode 100644 index a1e4fcda..00000000 --- a/src/libply/ply-frame-buffer.c +++ /dev/null @@ -1,1422 +0,0 @@ -/* ply-frame-buffer.c - framebuffer abstraction - * - * Copyright (C) 2006, 2007, 2008 Red Hat, Inc. - * 2008 Charlie Brej <cbrej@cs.man.ac.uk> - * - * 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: Charlie Brej <cbrej@cs.man.ac.uk> - * Kristian Høgsberg <krh@redhat.com> - * Ray Strode <rstrode@redhat.com> - */ -#include "config.h" -#include "ply-list.h" -#include "ply-frame-buffer.h" -#include "ply-logger.h" - -#include <arpa/inet.h> -#include <assert.h> -#include <errno.h> -#include <fcntl.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 <linux/fb.h> - -#ifndef PLY_FRAME_BUFFER_DEFAULT_FB_DEVICE_NAME -#define PLY_FRAME_BUFFER_DEFAULT_FB_DEVICE_NAME "/dev/fb" -#endif - -struct _ply_frame_buffer -{ - char *device_name; - int device_fd; - - char *map_address; - size_t size; - - uint32_t *shadow_buffer; - - uint32_t red_bit_position; - uint32_t green_bit_position; - uint32_t blue_bit_position; - uint32_t alpha_bit_position; - - uint32_t bits_for_red; - uint32_t bits_for_green; - uint32_t bits_for_blue; - uint32_t bits_for_alpha; - - int32_t dither_red; - int32_t dither_green; - int32_t dither_blue; - - unsigned int bytes_per_pixel; - unsigned int row_stride; - - ply_frame_buffer_area_t area; - ply_list_t *areas_to_flush; - - void (*flush_area) (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area_to_flush); - - int pause_count; -}; - -static bool ply_frame_buffer_open_device (ply_frame_buffer_t *buffer); -static void ply_frame_buffer_close_device (ply_frame_buffer_t *buffer); -static bool ply_frame_buffer_query_device (ply_frame_buffer_t *buffer); -static bool ply_frame_buffer_map_to_device (ply_frame_buffer_t *buffer); -static inline uint_fast32_t ply_frame_buffer_pixel_value_to_device_pixel_value ( - ply_frame_buffer_t *buffer, - uint32_t pixel_value); - -static inline void ply_frame_buffer_blend_value_at_pixel (ply_frame_buffer_t *buffer, - int x, - int y, - uint32_t pixel_value); - -static void ply_frame_buffer_fill_area_with_pixel_value ( - ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area, - uint32_t pixel_value); - -static void ply_frame_buffer_add_area_to_flush_area (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area); - -static bool ply_frame_buffer_flush (ply_frame_buffer_t *buffer); - -static void ply_frame_buffer_area_intersect (ply_frame_buffer_area_t *area1, - ply_frame_buffer_area_t *area2, - ply_frame_buffer_area_t *result); - -static bool -ply_frame_buffer_open_device (ply_frame_buffer_t *buffer) -{ - assert (buffer != NULL); - assert (buffer->device_name != NULL); - - buffer->device_fd = open (buffer->device_name, O_RDWR); - - if (buffer->device_fd < 0) - { - return false; - } - - return true; -} - -static void -ply_frame_buffer_close_device (ply_frame_buffer_t *buffer) -{ - assert (buffer != NULL); - - if (buffer->map_address != MAP_FAILED) - { - munmap (buffer->map_address, buffer->size); - buffer->map_address = MAP_FAILED; - } - - if (buffer->device_fd >= 0) - { - close (buffer->device_fd); - buffer->device_fd = -1; - } -} - -static void -flush_area_to_any_device (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area_to_flush) -{ - unsigned long row, column; - char *row_buffer; - size_t bytes_per_row; - unsigned long x1, y1, x2, y2; - - x1 = area_to_flush->x; - y1 = area_to_flush->y; - x2 = x1 + area_to_flush->width; - y2 = y1 + area_to_flush->height; - - bytes_per_row = area_to_flush->width * buffer->bytes_per_pixel; - row_buffer = malloc (buffer->row_stride * buffer->bytes_per_pixel); - for (row = y1; row < y2; row++) - { - unsigned long offset; - - for (column = x1; column < x2; column++) - { - uint32_t pixel_value; - uint_fast32_t device_pixel_value; - - pixel_value = buffer->shadow_buffer[row * buffer->area.width + column]; - - device_pixel_value = - ply_frame_buffer_pixel_value_to_device_pixel_value (buffer, - pixel_value); - - memcpy (row_buffer + column * buffer->bytes_per_pixel, - &device_pixel_value, buffer->bytes_per_pixel); - } - - offset = row * buffer->row_stride * buffer->bytes_per_pixel + x1 * buffer->bytes_per_pixel; - memcpy (buffer->map_address + offset, row_buffer + x1 * buffer->bytes_per_pixel, - area_to_flush->width * buffer->bytes_per_pixel); - } - free (row_buffer); -} - -static void -flush_area_to_xrgb32_device (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area_to_flush) -{ - unsigned long x1, y1, x2, y2, y; - char *dst, *src; - - x1 = area_to_flush->x; - y1 = area_to_flush->y; - x2 = x1 + area_to_flush->width; - y2 = y1 + area_to_flush->height; - - dst = &buffer->map_address[(y1 * buffer->row_stride + x1) * 4]; - src = (char *) &buffer->shadow_buffer[y1 * buffer->area.width + x1]; - - if (area_to_flush->width == buffer->row_stride) - { - memcpy (dst, src, area_to_flush->width * area_to_flush->height * 4); - return; - } - - for (y = y1; y < y2; y++) - { - memcpy (dst, src, area_to_flush->width * 4); - dst += buffer->row_stride * 4; - src += buffer->area.width * 4; - } -} - -static const char const *p_visual(int visual) -{ - static const char const *visuals[] = - { - [FB_VISUAL_MONO01] = "FB_VISUAL_MONO01", - [FB_VISUAL_MONO10] = "FB_VISUAL_MONO10", - [FB_VISUAL_TRUECOLOR] = "FB_VISUAL_TRUECOLOR", - [FB_VISUAL_PSEUDOCOLOR] = "FB_VISUAL_PSEUDOCOLOR", - [FB_VISUAL_DIRECTCOLOR] = "FB_VISUAL_DIRECTCOLOR", - [FB_VISUAL_STATIC_PSEUDOCOLOR] = "FB_VISUAL_STATIC_PSEUDOCOLOR", - NULL - }; - static char unknown[] = "invalid visual: -4294967295"; - - if (visual < FB_VISUAL_MONO01 || visual > FB_VISUAL_STATIC_PSEUDOCOLOR) - { - sprintf(unknown, "invalid visual: %d", visual); - return unknown; - } - - return visuals[visual]; -} - -static bool -ply_frame_buffer_query_device (ply_frame_buffer_t *buffer) -{ - struct fb_var_screeninfo variable_screen_info; - struct fb_fix_screeninfo fixed_screen_info; - - assert (buffer != NULL); - assert (buffer->device_fd >= 0); - - if (ioctl (buffer->device_fd, FBIOGET_VSCREENINFO, &variable_screen_info) < 0) - return false; - - if (ioctl(buffer->device_fd, FBIOGET_FSCREENINFO, &fixed_screen_info) < 0) - return false; - - /* Normally the pixel is divided into channels between the color components. - * Each channel directly maps to a color channel on the hardware. - * - * There are some odd ball modes that use an indexed palette instead. In - * those cases (pseudocolor, direct color, etc), the pixel value is just an - * index into a lookup table of the real color values. - * - * We don't support that. - */ - if (fixed_screen_info.visual != FB_VISUAL_TRUECOLOR) - { - int rc = -1; - int i; - int depths[] = {32, 24, 16, 0}; - - ply_trace("Visual was %s, trying to find usable mode.\n", - p_visual(fixed_screen_info.visual)); - - for (i = 0; depths[i] != 0; i++) - { - variable_screen_info.bits_per_pixel = depths[i]; - variable_screen_info.activate |= FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; - - rc = ioctl(buffer->device_fd, FBIOPUT_VSCREENINFO, &variable_screen_info); - if (rc >= 0) - { - if (ioctl(buffer->device_fd, FBIOGET_FSCREENINFO, &fixed_screen_info) < 0) - return false; - if (fixed_screen_info.visual == FB_VISUAL_TRUECOLOR) - break; - } - } - - if (ioctl(buffer->device_fd, FBIOGET_VSCREENINFO, &variable_screen_info) < 0) - return false; - - if (ioctl(buffer->device_fd, FBIOGET_FSCREENINFO, &fixed_screen_info) < 0) - return false; - } - - if (fixed_screen_info.visual != FB_VISUAL_TRUECOLOR || - variable_screen_info.bits_per_pixel < 16) - { - ply_trace("Visual is %s; not using graphics\n", - p_visual(fixed_screen_info.visual)); - return false; - } - - buffer->area.x = variable_screen_info.xoffset; - buffer->area.y = variable_screen_info.yoffset; - buffer->area.width = variable_screen_info.xres; - buffer->area.height = variable_screen_info.yres; - - buffer->red_bit_position = variable_screen_info.red.offset; - buffer->bits_for_red = variable_screen_info.red.length; - - buffer->green_bit_position = variable_screen_info.green.offset; - buffer->bits_for_green = variable_screen_info.green.length; - - buffer->blue_bit_position = variable_screen_info.blue.offset; - buffer->bits_for_blue = variable_screen_info.blue.length; - - buffer->alpha_bit_position = variable_screen_info.transp.offset; - buffer->bits_for_alpha = variable_screen_info.transp.length; - - buffer->bytes_per_pixel = variable_screen_info.bits_per_pixel >> 3; - buffer->row_stride = fixed_screen_info.line_length / buffer->bytes_per_pixel; - buffer->size = buffer->area.height * buffer->row_stride * buffer->bytes_per_pixel; - - buffer->dither_red = 0; - buffer->dither_green = 0; - buffer->dither_blue = 0; - - if (buffer->bytes_per_pixel == 4 && - buffer->red_bit_position == 16 && buffer->bits_for_red == 8 && - buffer->green_bit_position == 8 && buffer->bits_for_green == 8 && - buffer->blue_bit_position == 0 && buffer->bits_for_blue == 8) - buffer->flush_area = flush_area_to_xrgb32_device; - else - buffer->flush_area = flush_area_to_any_device; - - return true; -} - -static bool -ply_frame_buffer_map_to_device (ply_frame_buffer_t *buffer) -{ - assert (buffer != NULL); - assert (buffer->device_fd >= 0); - assert (buffer->size > 0); - - buffer->map_address = mmap (NULL, buffer->size, PROT_WRITE, - MAP_SHARED, buffer->device_fd, 0); - - return buffer->map_address != MAP_FAILED; -} - -static inline uint_fast32_t -ply_frame_buffer_pixel_value_to_device_pixel_value (ply_frame_buffer_t *buffer, - uint32_t pixel_value) -{ - uint8_t r, g, b, a; - int orig_r, orig_g, orig_b, orig_a; - int i; - - orig_a = pixel_value >> 24; - a = orig_a >> (8 - buffer->bits_for_alpha); - - orig_r = ((pixel_value >> 16) & 0xff) - buffer->dither_red; - r = CLAMP(orig_r, 0, 255) >> (8 - buffer->bits_for_red); - - orig_g = ((pixel_value >> 8) & 0xff) - buffer->dither_green; - g = CLAMP(orig_g, 0, 255) >> (8 - buffer->bits_for_green); - - orig_b = (pixel_value & 0xff) - buffer->dither_blue; - b = CLAMP(orig_b, 0, 255) >> (8 - buffer->bits_for_blue); - - uint8_t new_r = r << (8 - buffer->bits_for_red); - uint8_t new_g = g << (8 - buffer->bits_for_green); - uint8_t new_b = b << (8 - buffer->bits_for_blue); - for (i=buffer->bits_for_red; i<8; i*=2) new_r |= new_r >> i; - for (i=buffer->bits_for_green; i<8; i*=2) new_g |= new_g >> i; - for (i=buffer->bits_for_blue; i<8; i*=2) new_b |= new_b >> i; - - buffer->dither_red = new_r - orig_r; - buffer->dither_green = new_g - orig_g; - buffer->dither_blue = new_b - orig_b; - - - return ((a << buffer->alpha_bit_position) - | (r << buffer->red_bit_position) - | (g << buffer->green_bit_position) - | (b << buffer->blue_bit_position)); -} - -__attribute__((__pure__)) -static inline uint32_t -blend_two_pixel_values (uint32_t pixel_value_1, - uint32_t pixel_value_2) -{ - uint8_t alpha_1, red_1, green_1, blue_1; - uint8_t red_2, green_2, blue_2; - uint_least16_t red, green, blue; - - assert (((uint8_t) (pixel_value_2 >> 24)) == 0xff); - - alpha_1 = (uint8_t) (pixel_value_1 >> 24); - red_1 = (uint8_t) (pixel_value_1 >> 16); - green_1 = (uint8_t) (pixel_value_1 >> 8); - blue_1 = (uint8_t) pixel_value_1; - - red_2 = (uint8_t) (pixel_value_2 >> 16); - green_2 = (uint8_t) (pixel_value_2 >> 8); - blue_2 = (uint8_t) pixel_value_2; - - red = red_1 * 255 + red_2 * (255 - alpha_1); - green = green_1 * 255 + green_2 * (255 - alpha_1); - blue = blue_1 * 255 + blue_2 * (255 - alpha_1); - - red = (uint8_t) ((red + (red >> 8) + 0x80) >> 8); - green = (uint8_t) ((green + (green >> 8) + 0x80) >> 8); - blue = (uint8_t) ((blue + (blue >> 8) + 0x80) >> 8); - - return 0xff000000 | (red << 16) | (green << 8) | blue; -} - -__attribute__((__pure__)) -static inline uint32_t -make_pixel_value_translucent (uint32_t pixel_value, - uint8_t opacity) -{ - uint_least16_t alpha, red, green, blue; - - if (opacity == 255) - return pixel_value; - - alpha = (uint8_t) (pixel_value >> 24); - red = (uint8_t) (pixel_value >> 16); - green = (uint8_t) (pixel_value >> 8); - blue = (uint8_t) pixel_value; - - red *= opacity; - green *= opacity; - blue *= opacity; - alpha *= opacity; - - red = (uint8_t) ((red + (red >> 8) + 0x80) >> 8); - green = (uint8_t) ((green + (green >> 8) + 0x80) >> 8); - blue = (uint8_t) ((blue + (blue >> 8) + 0x80) >> 8); - alpha = (uint8_t) ((alpha + (alpha >> 8) + 0x80) >> 8); - - return (alpha << 24) | (red << 16) | (green << 8) | blue; -} - -static inline void -ply_frame_buffer_blend_value_at_pixel (ply_frame_buffer_t *buffer, - int x, - int y, - uint32_t pixel_value) -{ - uint32_t old_pixel_value; - - if ((pixel_value >> 24) != 0xff) - { - old_pixel_value = buffer->shadow_buffer[y * buffer->area.width + x]; - - pixel_value = blend_two_pixel_values (pixel_value, old_pixel_value); - } - - buffer->shadow_buffer[y * buffer->area.width + x] = pixel_value; -} - -static void -ply_frame_buffer_fill_area_with_pixel_value (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area, - uint32_t pixel_value) -{ - unsigned long row, column; - ply_frame_buffer_area_t cropped_area; - ply_frame_buffer_area_intersect (area, &buffer->area, &cropped_area); - - 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_frame_buffer_blend_value_at_pixel (buffer, - column, row, - pixel_value); - } - } -} - -static void -integrate_area_with_flush_area (ply_frame_buffer_t *buffer, - ply_list_node_t *node, - ply_frame_buffer_area_t *new_area) -{ - if (new_area->width == 0) return; - if (new_area->height == 0) return; - while (node != NULL) - { - ply_list_node_t *next_node; - ply_frame_buffer_area_t *second_new_area; - ply_frame_buffer_area_t *old_area; - old_area = (ply_frame_buffer_area_t *) ply_list_node_get_data (node); - next_node = ply_list_get_next_node (buffer->areas_to_flush, node); - - /* - Say we have an overlap between rectangle A and rectangle B and C denotes the overlap. - Depending on the type of overlap we can create a non overlapping addition to the set. - - 1:Collision on one side 2:Collision on two sides - Trim one of the rectanges Break into two rectangles - - AAAAA AAAAA AAAAA AAAAA - AAACCBBB AAAAABBB AAAAA AAAAA - AAACCBBB => AAAAABBB AAACCBBB => AAAAAbbb - AAACCBBB AAAAABBB AAACCBBB AAAAAbbb - AAAAA AAAAA BBBBB BBBBB - BBBBB BBBBB - - 3:Collision on opposite sides 4:Fully contained - Break into two rectangles Throw away the rectangle - - AAAAA AAAAA AAAAA AAAAA - BCCCCCB BAAAAAb ACCCA AAAAA - BCCCCCB => BAAAAAb ACCCA => AAAAA - BCCCCCB BAAAAAb ACCCA AAAAA - AAAAA AAAAA AAAAA AAAAA - - */ - enum {H_COLLISION_NONE, H_COLLISION_LEFT, H_COLLISION_RIGHT, H_COLLISION_BOTH, H_COLLISION_CONTAINED} - h_collision = H_COLLISION_NONE; - enum {V_COLLISION_NONE, V_COLLISION_TOP, V_COLLISION_BOTTOM, V_COLLISION_BOTH, V_COLLISION_CONTAINED} - v_collision = V_COLLISION_NONE; - - if (new_area->x >= old_area->x && (new_area->x + new_area->width) <= (old_area->x + old_area->width)) - h_collision = H_COLLISION_CONTAINED; - else - { /* Remember: x+width points to the first pixel outside the rectangle*/ - if (new_area->x < old_area->x && - (new_area->x + (int)new_area->width) > old_area->x) - h_collision = H_COLLISION_LEFT; /* new_area colllided with the left edge of old_area */ - - if (new_area->x < (old_area->x + (int)old_area->width) && - (new_area->x + (int)new_area->width) >= (old_area->x + (int)old_area->width)) - { /* new_area colllided with the right edge of old_area */ - if (h_collision == H_COLLISION_LEFT) - h_collision = H_COLLISION_BOTH; - else - h_collision = H_COLLISION_RIGHT; - } - } - - if (h_collision != H_COLLISION_NONE) - { - if (new_area->y >= old_area->y && (new_area->y + new_area->height) <= (old_area->y + old_area->height)) - v_collision = V_COLLISION_CONTAINED; - else - { - if (new_area->y < old_area->y && - (new_area->y + (int)new_area->height) > old_area->y) - v_collision = V_COLLISION_TOP; - if (new_area->y < (old_area->y + (int)old_area->height) && - (new_area->y + (int)new_area->height) >= (old_area->y + (int)old_area->height)) - { /* new_area colllided with the right edge of old_area */ - if (v_collision == V_COLLISION_TOP) - v_collision = V_COLLISION_BOTH; - else - v_collision = V_COLLISION_BOTTOM; - } - } - } - - switch(v_collision) - { - case V_COLLISION_NONE: - break; - case V_COLLISION_TOP: - { - switch (h_collision) - { - case H_COLLISION_NONE: /* no collision */ - break; - case H_COLLISION_LEFT: /* collision with old top left corner, split new into two */ - { - second_new_area = malloc (sizeof (ply_frame_buffer_area_t)); - second_new_area->x = new_area->x; - second_new_area->y = old_area->y; - second_new_area->width = old_area->x - new_area->x; - second_new_area->height = (new_area->y + new_area->height) - old_area->y; - new_area->height = old_area->y - new_area->y; - - integrate_area_with_flush_area (buffer, node, second_new_area); - integrate_area_with_flush_area (buffer, node, new_area); - return; - } - case H_COLLISION_RIGHT: /* collision with old top right corner, split new into two */ - { - second_new_area = malloc (sizeof (ply_frame_buffer_area_t)); - second_new_area->x = old_area->x + old_area->width; - second_new_area->y = old_area->y; - second_new_area->width = (new_area->x + new_area->width) - (old_area->x + old_area->width); - second_new_area->height = (new_area->y + new_area->height) - old_area->y; - new_area->height = old_area->y - new_area->y; - - integrate_area_with_flush_area (buffer, node, second_new_area); - integrate_area_with_flush_area (buffer, node, new_area); - return; - } - case H_COLLISION_BOTH: /* collision with old top, left and right corners, trim old */ - old_area->height = (old_area->y + old_area->height) - (new_area->y + new_area->height); - old_area->y = new_area->y + new_area->height; - break; - case H_COLLISION_CONTAINED: /* collision with old top edge only, trim new */ - new_area->height = old_area->y - new_area->y; - break; - } - break; - } - case V_COLLISION_BOTTOM: - { - switch (h_collision) - { - case H_COLLISION_NONE: /* no collision */ - break; - case H_COLLISION_LEFT: /* collision with old bottom left corner, split new into two */ - { - second_new_area = malloc (sizeof (ply_frame_buffer_area_t)); - second_new_area->x = new_area->x; - second_new_area->y = new_area->y; - second_new_area->width = old_area->x - new_area->x; - second_new_area->height = (old_area->y + old_area->height) - new_area->y; - - new_area->height = (new_area->y + new_area->height) - (old_area->y + old_area->height); - new_area->y = old_area->y + old_area->height; - - integrate_area_with_flush_area (buffer, node, second_new_area); - integrate_area_with_flush_area (buffer, node, new_area); - return; - } - case H_COLLISION_RIGHT: /* collision with old bottom right corner, split new into two */ - { - second_new_area = malloc (sizeof (ply_frame_buffer_area_t)); - second_new_area->x = old_area->x + old_area->width; - second_new_area->y = new_area->y; - second_new_area->width = (new_area->x + new_area->width) - (old_area->x + old_area->width); - second_new_area->height = (old_area->y + old_area->height) - new_area->y; - - new_area->height = (new_area->y + new_area->height) - (old_area->y + old_area->height); - new_area->y = old_area->y + old_area->height; - - integrate_area_with_flush_area (buffer, node, second_new_area); - integrate_area_with_flush_area (buffer, node, new_area); - return; - } - case H_COLLISION_BOTH: /* collision with old bottom, left and right corners, trim old */ - old_area->height = new_area->y - old_area->y; - break; - case H_COLLISION_CONTAINED: /* collision with old botoom edge only, trim new */ - new_area->height = (new_area->y + new_area->height) - (old_area->y + old_area->height); - new_area->y = old_area->y + old_area->height; - break; - } - break; - } - case V_COLLISION_BOTH: - { - switch (h_collision) - { - case H_COLLISION_NONE: /* no collision */ - break; - case H_COLLISION_LEFT: /* collision with old left, top and bottom corners, trim old */ - old_area->width = (old_area->x + old_area->width) - (new_area->x + new_area->width); - old_area->x = new_area->x + new_area->width; - break; - case H_COLLISION_RIGHT: /* collision with old right, top and bottom corners, trim old */ - old_area->width = new_area->x - old_area->x; - break; - case H_COLLISION_BOTH: /* old fully contained within new, remove old */ - free (old_area); - ply_list_remove_node (buffer->areas_to_flush, node); - break; - case H_COLLISION_CONTAINED: /* collision with old top and bottom edges but not left and right, split new into two */ - { - second_new_area = malloc (sizeof (ply_frame_buffer_area_t)); - second_new_area->x = new_area->x; - second_new_area->y = old_area->y + old_area->height; - second_new_area->width = new_area->width; - second_new_area->height = (new_area->y + new_area->height) - (old_area->y + old_area->height); - new_area->height = old_area->y - new_area->y; - - integrate_area_with_flush_area (buffer, node, second_new_area); - integrate_area_with_flush_area (buffer, node, new_area); - return; - } - } - break; - } - case V_COLLISION_CONTAINED: - { - switch (h_collision) - { - case H_COLLISION_NONE: /* no collision */ - break; - case H_COLLISION_LEFT: /* collision with old left edge only, trim new */ - new_area->width = old_area->x - new_area->x; - break; - case H_COLLISION_RIGHT: /* collision with old right edge only, trim new */ - new_area->width = (new_area->x + new_area->width) - (old_area->x + old_area->width); - new_area->x = old_area->x + old_area->width; - break; - case H_COLLISION_BOTH: - { /* collision with old left and right edges but not top and botton, split new into two */ - second_new_area = malloc (sizeof (ply_frame_buffer_area_t)); - second_new_area->x = old_area->x + old_area->width; - second_new_area->y = new_area->y; - second_new_area->width = (new_area->x + new_area->width) - (old_area->x + old_area->width); - second_new_area->height = new_area->height; - new_area->width = old_area->x - new_area->x; - - integrate_area_with_flush_area (buffer, node, second_new_area); - integrate_area_with_flush_area (buffer, node, new_area); - return; - } - case H_COLLISION_CONTAINED: /* new fully contained within old, remove new */ - free (new_area); - return; - } - break; - } - } - node = next_node; - } - - ply_list_append_data (buffer->areas_to_flush, new_area); -} - -static void -ply_frame_buffer_add_area_to_flush_area (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area) -{ - ply_frame_buffer_area_t *cropped_area; - - assert (buffer != NULL); - assert (area != NULL); - - cropped_area = malloc (sizeof (ply_frame_buffer_area_t)); - ply_frame_buffer_area_intersect (area, &buffer->area, cropped_area); - - if (cropped_area->width == 0 || cropped_area->height == 0) - { - free (cropped_area); - return; - } - - integrate_area_with_flush_area (buffer, - ply_list_get_first_node (buffer->areas_to_flush), - cropped_area); -} - -static bool -ply_frame_buffer_flush (ply_frame_buffer_t *buffer) -{ - ply_list_node_t *node; - assert (buffer != NULL); - - if (buffer->pause_count > 0) - return true; - - node = ply_list_get_first_node (buffer->areas_to_flush); - while (node != NULL) - { - ply_list_node_t *next_node; - ply_frame_buffer_area_t *area_to_flush; - - area_to_flush = (ply_frame_buffer_area_t *) ply_list_node_get_data (node); - - next_node = ply_list_get_next_node (buffer->areas_to_flush, node); - - (*buffer->flush_area) (buffer, area_to_flush); - - free (area_to_flush); - ply_list_remove_node (buffer->areas_to_flush, node); - - node = next_node; - } - - return true; -} - -ply_frame_buffer_t * -ply_frame_buffer_new (const char *device_name) -{ - ply_frame_buffer_t *buffer; - - buffer = calloc (1, sizeof (ply_frame_buffer_t)); - - if (device_name != NULL) - buffer->device_name = strdup (device_name); - else if (getenv ("FRAMEBUFFER") != NULL) - buffer->device_name = strdup (getenv ("FRAMEBUFFER")); - else - buffer->device_name = - strdup (PLY_FRAME_BUFFER_DEFAULT_FB_DEVICE_NAME); - - buffer->map_address = MAP_FAILED; - buffer->shadow_buffer = NULL; - buffer->areas_to_flush = ply_list_new (); - - buffer->pause_count = 0; - - return buffer; -} - -static void -free_flush_areas (ply_frame_buffer_t *buffer) -{ - ply_list_node_t *node; - - node = ply_list_get_first_node (buffer->areas_to_flush); - while (node != NULL) - { - ply_list_node_t *next_node; - ply_frame_buffer_area_t *area_to_flush; - - area_to_flush = (ply_frame_buffer_area_t *) ply_list_node_get_data (node); - - next_node = ply_list_get_next_node (buffer->areas_to_flush, node); - - free (area_to_flush); - ply_list_remove_node (buffer->areas_to_flush, node); - - node = next_node; - } - - ply_list_free (buffer->areas_to_flush); -} - -void -ply_frame_buffer_free (ply_frame_buffer_t *buffer) -{ - assert (buffer != NULL); - - if (ply_frame_buffer_device_is_open (buffer)) - ply_frame_buffer_close (buffer); - - free_flush_areas (buffer); - - free (buffer->device_name); - free (buffer->shadow_buffer); - free (buffer); -} - -bool -ply_frame_buffer_open (ply_frame_buffer_t *buffer) -{ - bool is_open; - - assert (buffer != NULL); - - is_open = false; - - if (!ply_frame_buffer_open_device (buffer)) - { - goto out; - } - - if (!ply_frame_buffer_query_device (buffer)) - { - goto out; - } - - if (!ply_frame_buffer_map_to_device (buffer)) - { - goto out; - } - - buffer->shadow_buffer = - realloc (buffer->shadow_buffer, 4 * buffer->area.width * buffer->area.height); - memset (buffer->shadow_buffer, 0, 4 * buffer->area.width * buffer->area.height); - ply_frame_buffer_fill_with_color (buffer, NULL, 0.0, 0.0, 0.0, 1.0); - - is_open = true; - -out: - - if (!is_open) - { - int saved_errno; - - saved_errno = errno; - ply_frame_buffer_close_device (buffer); - errno = saved_errno; - } - - return is_open; -} - -void -ply_frame_buffer_pause_updates (ply_frame_buffer_t *buffer) -{ - assert (buffer != NULL); - - buffer->pause_count++; -} - -bool -ply_frame_buffer_unpause_updates (ply_frame_buffer_t *buffer) -{ - assert (buffer != NULL); - - buffer->pause_count--; - return ply_frame_buffer_flush (buffer); -} - -bool -ply_frame_buffer_device_is_open (ply_frame_buffer_t *buffer) -{ - assert (buffer != NULL); - return buffer->device_fd >= 0 && buffer->map_address != MAP_FAILED; -} - -char * -ply_frame_buffer_get_device_name (ply_frame_buffer_t *buffer) -{ - assert (buffer != NULL); - assert (ply_frame_buffer_device_is_open (buffer)); - assert (buffer->device_name != NULL); - - return strdup (buffer->device_name); -} - -void -ply_frame_buffer_set_device_name (ply_frame_buffer_t *buffer, - const char *device_name) -{ - assert (buffer != NULL); - assert (!ply_frame_buffer_device_is_open (buffer)); - assert (device_name != NULL); - assert (buffer->device_name != NULL); - - if (strcmp (buffer->device_name, device_name) != 0) - { - free (buffer->device_name); - buffer->device_name = strdup (device_name); - } -} - -void -ply_frame_buffer_close (ply_frame_buffer_t *buffer) -{ - assert (buffer != NULL); - - assert (ply_frame_buffer_device_is_open (buffer)); - ply_frame_buffer_close_device (buffer); - - buffer->bytes_per_pixel = 0; - buffer->area.x = 0; - buffer->area.y = 0; - buffer->area.width = 0; - buffer->area.height = 0; -} - -void -ply_frame_buffer_get_size (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *size) -{ - assert (buffer != NULL); - assert (ply_frame_buffer_device_is_open (buffer)); - assert (size != NULL); - - *size = buffer->area; -} - -static void -ply_frame_buffer_area_intersect (ply_frame_buffer_area_t *area1, - ply_frame_buffer_area_t *area2, - ply_frame_buffer_area_t *result) -{ - long x1, y1, x2, y2; - long width, height; - - if (area1->width == 0) - { - *result = *area1; - return; - } - - if (area2->width == 0) - { - *result = *area2; - return; - } - - x1 = area1->x + area1->width; - y1 = area1->y + area1->height; - x2 = area2->x + area2->width; - y2 = area2->y + area2->height; - - result->x = MAX(area1->x, area2->x); - result->y = MAX(area1->y, area2->y); - - width = MIN(x1, x2) - result->x; - height = MIN(y1, y2) - result->y; - if (width <= 0 || height <= 0) - { - result->width = 0; - result->height = 0; - } - else - { - result->width = width; - result->height = height; - } -} - -bool -ply_frame_buffer_fill_with_gradient (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area, - uint32_t start, - uint32_t end) -{ -/* The gradient produced is a linear interpolation of the two passed - * in color stops: start and end. - * - * In order to prevent banding when the color stops are too close - * together, or are stretched over too large an area, we slightly - * perturb the intermediate colors as we generate them. - * - * Before we do this, we store the interpolated color values in a - * fixed point number with lots of fractional bits. This is so - * we don't add noise after the values have been clamped to 8-bits - * - * We add random noise to all of the fractional bits of each color - * channel and also NOISE_BITS worth of noise to the non-fractional - * part of the color. By default NOISE_BITS is 1. - * - * We incorporate the noise by filling the bottom 24 bits of an - * integer with random bits and then shifting the color channels - * to the left such that the top 8 bits of the channel overlap - * the noise by NOISE_BITS. E.g., if NOISE_BITS is 1, then the top - * 7 bits of each channel won't overlap with the noise, and the 8th - * bit + fractional bits will. When the noise and color channel - * are properly aligned, we add them together, drop the precision - * of the resulting channels back to 8 bits and stuff the results - * into a pixel in the frame buffer. - */ -#define NOISE_BITS 1 -/* In the color stops, red is 8 bits starting at position 24 - * (since they're argb32 pixels). - * We want to move those 8 bits such that the bottom NOISE_BITS - * of them overlap the top of the 24 bits of generated noise. - * Of course, green and blue are 8 bits away from red and each - * other, respectively. - */ -#define RED_SHIFT (32 - (24 + NOISE_BITS)) -#define GREEN_SHIFT (RED_SHIFT + 8) -#define BLUE_SHIFT (GREEN_SHIFT + 8) -#define NOISE_MASK (0x00ffffff) - -/* Once, we've lined up the color channel we're interested in with - * the noise, we need to mask out the other channels. - */ -#define COLOR_MASK (0xff << (24 - NOISE_BITS)) - - uint32_t red, green, blue, red_step, green_step, blue_step, t, pixel; - uint32_t x, y; - /* we use a fixed seed so that the dithering doesn't change on repaints - * of the same area. - */ - uint32_t noise = 0x100001; - ply_frame_buffer_area_t cropped_area; - - if (area == NULL) - area = &buffer->area; - - ply_frame_buffer_area_intersect (area, &buffer->area, &cropped_area); - - red = (start << RED_SHIFT) & COLOR_MASK; - green = (start << GREEN_SHIFT) & COLOR_MASK; - blue = (start << BLUE_SHIFT) & COLOR_MASK; - - t = (end << RED_SHIFT) & COLOR_MASK; - red_step = (int32_t) (t - red) / (int32_t) buffer->area.height; - t = (end << GREEN_SHIFT) & COLOR_MASK; - green_step = (int32_t) (t - green) / (int32_t) buffer->area.height; - t = (end << BLUE_SHIFT) & COLOR_MASK; - blue_step = (int32_t) (t - blue) / (int32_t) buffer->area.height; - - -#define RANDOMIZE(num) (num = (num + (num << 1)) & NOISE_MASK) -#define UNROLLED_PIXEL_COUNT 8 - - for (y = buffer->area.y; y < buffer->area.y + buffer->area.height; y++) - { - if (cropped_area.y <= y && y < cropped_area.y + cropped_area.height) - { - if (cropped_area.width < UNROLLED_PIXEL_COUNT) - { - for (x = cropped_area.x; x < cropped_area.x + cropped_area.width; x++) - { - pixel = 0xff000000; - RANDOMIZE(noise); - pixel |= (((red + noise) & COLOR_MASK) >> RED_SHIFT); - RANDOMIZE(noise); - pixel |= (((green + noise) & COLOR_MASK) >> GREEN_SHIFT); - RANDOMIZE(noise); - pixel |= (((blue + noise) & COLOR_MASK) >> BLUE_SHIFT); - - buffer->shadow_buffer[y * buffer->area.width + x] = pixel; - } - } - else - { - uint32_t shaded_set[UNROLLED_PIXEL_COUNT]; - uint32_t *ptr = &buffer->shadow_buffer[y * buffer->area.width + cropped_area.x]; - for (x = 0; x < UNROLLED_PIXEL_COUNT; x++) - { - shaded_set[x] = 0xff000000; - RANDOMIZE(noise); - shaded_set[x] |= (((red + noise) & COLOR_MASK) >> RED_SHIFT); - RANDOMIZE(noise); - shaded_set[x] |= (((green + noise) & COLOR_MASK) >> GREEN_SHIFT); - RANDOMIZE(noise); - shaded_set[x] |= (((blue + noise) & COLOR_MASK) >> BLUE_SHIFT); - } - for (x = cropped_area.width; x >=UNROLLED_PIXEL_COUNT; x-=UNROLLED_PIXEL_COUNT) - { - memcpy((void*)ptr, (void*)shaded_set, UNROLLED_PIXEL_COUNT * sizeof(uint32_t)); - ptr += UNROLLED_PIXEL_COUNT; - } - memcpy((void*)ptr, (void*)shaded_set, x * sizeof(uint32_t)); - - - } - - } - - red += red_step; - green += green_step; - blue += blue_step; - } - - ply_frame_buffer_add_area_to_flush_area (buffer, &cropped_area); - - return ply_frame_buffer_flush (buffer); -} - -bool -ply_frame_buffer_fill_with_color (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area, - double red, - double green, - double blue, - double alpha) -{ - uint32_t pixel_value; - ply_frame_buffer_area_t cropped_area; - - assert (buffer != NULL); - assert (ply_frame_buffer_device_is_open (buffer)); - - if (area == NULL) - area = &buffer->area; - - ply_frame_buffer_area_intersect (area, &buffer->area, &cropped_area); - - red *= alpha; - green *= alpha; - blue *= alpha; - - pixel_value = PLY_FRAME_BUFFER_COLOR_TO_PIXEL_VALUE (red, green, blue, alpha); - - ply_frame_buffer_fill_area_with_pixel_value (buffer, &cropped_area, pixel_value); - - ply_frame_buffer_add_area_to_flush_area (buffer, &cropped_area); - - return ply_frame_buffer_flush (buffer); -} - -bool -ply_frame_buffer_fill_with_hex_color_at_opacity (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area, - uint32_t hex_color, - double opacity) -{ - ply_frame_buffer_area_t cropped_area; - uint32_t pixel_value; - double red; - double green; - double blue; - double alpha; - - assert (buffer != NULL); - assert (ply_frame_buffer_device_is_open (buffer)); - - if (area == NULL) - area = &buffer->area; - - ply_frame_buffer_area_intersect (area, &buffer->area, &cropped_area); - - /* if they only gave an rgb hex number, assume an alpha of 0xff - */ - if ((hex_color & 0xff000000) == 0) - hex_color = (hex_color << 8) | 0xff; - - red = ((double) (hex_color & 0xff000000) / 0xff000000); - green = ((double) (hex_color & 0x00ff0000) / 0x00ff0000); - blue = ((double) (hex_color & 0x0000ff00) / 0x0000ff00); - alpha = ((double) (hex_color & 0x000000ff) / 0x000000ff); - - alpha *= opacity; - - red *= alpha; - green *= alpha; - blue *= alpha; - - pixel_value = PLY_FRAME_BUFFER_COLOR_TO_PIXEL_VALUE (red, green, blue, alpha); - - ply_frame_buffer_fill_area_with_pixel_value (buffer, &cropped_area, pixel_value); - - ply_frame_buffer_add_area_to_flush_area (buffer, &cropped_area); - - return ply_frame_buffer_flush (buffer); -} - -bool -ply_frame_buffer_fill_with_hex_color (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area, - uint32_t hex_color) -{ - return ply_frame_buffer_fill_with_hex_color_at_opacity (buffer, area, hex_color, 1.0); -} - -bool -ply_frame_buffer_fill_with_argb32_data_at_opacity_with_clip (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area, - ply_frame_buffer_area_t *clip, - unsigned long x, - unsigned long y, - uint32_t *data, - double opacity) -{ - unsigned long row, column; - uint8_t opacity_as_byte; - ply_frame_buffer_area_t cropped_area; - - assert (buffer != NULL); - assert (ply_frame_buffer_device_is_open (buffer)); - - if (area == NULL) - area = &buffer->area; - - ply_frame_buffer_area_intersect (area, &buffer->area, &cropped_area); - - if (clip) - ply_frame_buffer_area_intersect (&cropped_area, clip, &cropped_area); - - if (cropped_area.width == 0 || cropped_area.height == 0) - return true; - - x += cropped_area.x - area->x; - y += cropped_area.y - area->y; - 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; - - pixel_value = data[area->width * row + column]; - if ((pixel_value >> 24) == 0x00) - continue; - - pixel_value = make_pixel_value_translucent (pixel_value, opacity_as_byte); - ply_frame_buffer_blend_value_at_pixel (buffer, - cropped_area.x + (column - x), - cropped_area.y + (row - y), - pixel_value); - - } - } - - ply_frame_buffer_add_area_to_flush_area (buffer, &cropped_area); - - return ply_frame_buffer_flush (buffer); -} - -bool -ply_frame_buffer_fill_with_argb32_data_at_opacity (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area, - unsigned long x, - unsigned long y, - uint32_t *data, - double opacity) -{ - return ply_frame_buffer_fill_with_argb32_data_at_opacity_with_clip (buffer, area, NULL, - x, y, data, opacity); -} - -bool -ply_frame_buffer_fill_with_argb32_data (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area, - unsigned long x, - unsigned long y, - uint32_t *data) -{ - return ply_frame_buffer_fill_with_argb32_data_at_opacity_with_clip (buffer, area, NULL, - x, y, data, 1.0); -} - -bool -ply_frame_buffer_fill_with_argb32_data_with_clip (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area, - ply_frame_buffer_area_t *clip, - unsigned long x, - unsigned long y, - uint32_t *data) -{ - return ply_frame_buffer_fill_with_argb32_data_at_opacity_with_clip (buffer, area, clip, - x, y, data, 1.0); -} - -const char * -ply_frame_buffer_get_bytes (ply_frame_buffer_t *buffer) -{ - return (char *) buffer->shadow_buffer; -} - -#ifdef PLY_FRAME_BUFFER_ENABLE_TEST - -#include <math.h> -#include <stdio.h> -#include <sys/time.h> - -static double -get_current_time (void) -{ - const double microseconds_per_second = 1000000.0; - double timestamp; - struct timeval now = { 0L, /* zero-filled */ }; - - gettimeofday (&now, NULL); - timestamp = ((microseconds_per_second * now.tv_sec) + now.tv_usec) / - microseconds_per_second; - - return timestamp; -} - -static void -animate_at_time (ply_frame_buffer_t *buffer, - double time) -{ - unsigned int x, y; - uint32_t *data; - ply_frame_buffer_area_t area; - - ply_frame_buffer_get_size (buffer, &area); - - data = calloc (area.width * area.height, sizeof (uint32_t)); - - for (y = 0; y < area.height; y++) - { - int blue_bit_position; - uint8_t red, green, blue, alpha; - - blue_bit_position = (int) 64 * (.5 * sin (time) + .5) + (255 - 64); - blue = rand () % blue_bit_position; - for (x = 0; x < area.width; x++) - { - alpha = 0xff; - red = (uint8_t) ((y / (area.height * 1.0)) * 255.0); - green = (uint8_t) ((x / (area.width * 1.0)) * 255.0); - - red = green = (red + green + blue) / 3; - - data[y * area.width + x] = (alpha << 24) | (red << 16) | (green << 8) | blue; - } - } - - ply_frame_buffer_fill_with_argb32_data (buffer, NULL, 0, 0, data); -} - -int -main (int argc, - char **argv) -{ - static unsigned int seed = 0; - ply_frame_buffer_t *buffer; - int exit_code; - - exit_code = 0; - - buffer = ply_frame_buffer_new (NULL); - - if (!ply_frame_buffer_open (buffer)) - { - exit_code = errno; - perror ("could not open frame buffer"); - return exit_code; - } - - if (seed == 0) - { - seed = (int) get_current_time (); - srand (seed); - } - - while ("we want to see ad-hoc animations") - { - animate_at_time (buffer, get_current_time ()); - usleep (1000000/30.); - } - - ply_frame_buffer_close (buffer); - ply_frame_buffer_free (buffer); - - return main (argc, argv); -} - -#endif /* PLY_FRAME_BUFFER_ENABLE_TEST */ - -/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/libply/ply-frame-buffer.h b/src/libply/ply-frame-buffer.h deleted file mode 100644 index d30e4ef4..00000000 --- a/src/libply/ply-frame-buffer.h +++ /dev/null @@ -1,112 +0,0 @@ -/* ply-frame-buffer.h - framebuffer abstraction - * - * Copyright (C) 2007 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_FRAME_BUFFER_H -#define PLY_FRAME_BUFFER_H - -#include <stdbool.h> -#include <stdint.h> - -#include "ply-utils.h" - -typedef struct _ply_frame_buffer ply_frame_buffer_t; -typedef struct _ply_frame_buffer_area ply_frame_buffer_area_t; - -struct _ply_frame_buffer_area -{ - long x; - long y; - unsigned long width; - unsigned long height; -}; - -#define PLY_FRAME_BUFFER_COLOR_TO_PIXEL_VALUE(r,g,b,a) \ - (((uint8_t) (CLAMP (a * 255.0, 0.0, 255.0)) << 24) \ - | ((uint8_t) (CLAMP (r * 255.0, 0.0, 255.0)) << 16) \ - | ((uint8_t) (CLAMP (g * 255.0, 0.0, 255.0)) << 8) \ - | ((uint8_t) (CLAMP (b * 255.0, 0.0, 255.0)))) - -#ifndef PLY_HIDE_FUNCTION_DECLARATIONS -ply_frame_buffer_t *ply_frame_buffer_new (const char *device_name); -void ply_frame_buffer_free (ply_frame_buffer_t *buffer); -bool ply_frame_buffer_open (ply_frame_buffer_t *buffer); -void ply_frame_buffer_pause_updates (ply_frame_buffer_t *buffer); -bool ply_frame_buffer_unpause_updates (ply_frame_buffer_t *buffer); -bool ply_frame_buffer_device_is_open (ply_frame_buffer_t *buffer); -char *ply_frame_buffer_get_device_name (ply_frame_buffer_t *buffer); -void ply_frame_buffer_set_device_name (ply_frame_buffer_t *buffer, - const char *device_name); -void ply_frame_buffer_close (ply_frame_buffer_t *buffer); -void ply_frame_buffer_get_size (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *size); -bool ply_frame_buffer_fill_with_color (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area, - double red, - double green, - double blue, - double alpha); -bool ply_frame_buffer_fill_with_hex_color (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area, - uint32_t hex_color); - -bool ply_frame_buffer_fill_with_hex_color_at_opacity (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area, - uint32_t hex_color, - double opacity); - -bool ply_frame_buffer_fill_with_gradient (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area, - uint32_t start, - uint32_t end); - -bool ply_frame_buffer_fill_with_argb32_data (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area, - unsigned long x, - unsigned long y, - uint32_t *data); -bool ply_frame_buffer_fill_with_argb32_data_at_opacity (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area, - unsigned long x, - unsigned long y, - uint32_t *data, - double opacity); - -bool ply_frame_buffer_fill_with_argb32_data_with_clip (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area, - ply_frame_buffer_area_t *clip, - unsigned long x, - unsigned long y, - uint32_t *data); -bool ply_frame_buffer_fill_with_argb32_data_at_opacity_with_clip (ply_frame_buffer_t *buffer, - ply_frame_buffer_area_t *area, - ply_frame_buffer_area_t *clip, - unsigned long x, - unsigned long y, - uint32_t *data, - double opacity); - -const char *ply_frame_buffer_get_bytes (ply_frame_buffer_t *buffer); - - -#endif - -#endif /* PLY_FRAME_BUFFER_H */ -/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/libply/ply-rectangle.c b/src/libply/ply-rectangle.c new file mode 100644 index 00000000..22093936 --- /dev/null +++ b/src/libply/ply-rectangle.c @@ -0,0 +1,294 @@ +/* ply-rectangle.c + * + * Copyright (C) 2009 Red Hat, Inc. + * + * Based in part on some work by: + * Copyright (C) 2009 Charlie Brej <cbrej@cs.man.ac.uk> + * + * 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: Charlie Brej <cbrej@cs.man.ac.uk> + * Ray Strode <rstrode@redhat.com> + */ +#include "config.h" +#include "ply-list.h" +#include "ply-rectangle.h" + +bool +ply_rectangle_contains_point (ply_rectangle_t *rectangle, + long x, + long y) +{ + long top_edge; + long left_edge; + long right_edge; + long bottom_edge; + + top_edge = rectangle->y; + left_edge = rectangle->x; + right_edge = rectangle->x + rectangle->width - 1; + bottom_edge = rectangle->y + rectangle->height - 1; + + if (x < left_edge) + return false; + + if (y < top_edge) + return false; + + if (x > right_edge) + return false; + + if (y > bottom_edge) + return false; + + return true; +} + +bool +ply_rectangle_is_empty (ply_rectangle_t *rectangle) +{ + return rectangle->width == 0 || rectangle->height == 0; +} + +ply_rectangle_overlap_t +ply_rectangle_find_overlap (ply_rectangle_t *rectangle1, + ply_rectangle_t *rectangle2) +{ + ply_rectangle_overlap_t overlap; + + long rectangle1_top_edge; + long rectangle1_left_edge; + long rectangle1_right_edge; + long rectangle1_bottom_edge; + long rectangle2_top_edge; + long rectangle2_left_edge; + long rectangle2_right_edge; + long rectangle2_bottom_edge; + + rectangle1_top_edge = rectangle1->y; + rectangle1_left_edge = rectangle1->x; + rectangle1_right_edge = rectangle1->x + rectangle1->width - 1; + rectangle1_bottom_edge = rectangle1->y + rectangle1->height - 1; + + rectangle2_top_edge = rectangle2->y; + rectangle2_left_edge = rectangle2->x; + rectangle2_right_edge = rectangle2->x + rectangle2->width - 1; + rectangle2_bottom_edge = rectangle2->y + rectangle2->height - 1; + + overlap = 0; + + /* 1111111 + * 1122211 + * 1122211 + * 1111111 + */ + if (ply_rectangle_contains_point (rectangle1, + rectangle2_left_edge, + rectangle2_top_edge) && + ply_rectangle_contains_point (rectangle1, + rectangle2_right_edge, + rectangle2_bottom_edge)) + return PLY_RECTANGLE_OVERLAP_NO_EDGES; + + /* 2222222 + * 2211122 + * 2211122 + * 2222222 + */ + if (ply_rectangle_contains_point (rectangle2, + rectangle1_left_edge, + rectangle1_top_edge) && + ply_rectangle_contains_point (rectangle2, + rectangle1_right_edge, + rectangle1_bottom_edge)) + return PLY_RECTANGLE_OVERLAP_ALL_EDGES; + + /* 1111111 + * 11112222 + * 11112222 + * 1111111 + */ + if (ply_rectangle_contains_point (rectangle2, + rectangle1_right_edge, + rectangle2_top_edge) && + ply_rectangle_contains_point (rectangle2, + rectangle1_right_edge, + rectangle2_bottom_edge)) + overlap |= PLY_RECTANGLE_OVERLAP_RIGHT_EDGE; + + /* 222222 + * 11112222 + * 11112222 + * 222222 + */ + if (ply_rectangle_contains_point (rectangle1, + rectangle2_left_edge, + rectangle1_top_edge) && + ply_rectangle_contains_point (rectangle1, + rectangle2_left_edge, + rectangle1_bottom_edge)) + overlap |= PLY_RECTANGLE_OVERLAP_RIGHT_EDGE; + + /* 1111111 + * 22221111 + * 22221111 + * 1111111 + */ + if (ply_rectangle_contains_point (rectangle2, + rectangle1_left_edge, + rectangle2_top_edge) && + ply_rectangle_contains_point (rectangle2, + rectangle1_left_edge, + rectangle2_bottom_edge)) + overlap |= PLY_RECTANGLE_OVERLAP_LEFT_EDGE; + + /* 222222 + * 22221111 + * 22221111 + * 222222 + */ + if (ply_rectangle_contains_point (rectangle1, + rectangle2_right_edge, + rectangle1_top_edge) && + ply_rectangle_contains_point (rectangle1, + rectangle2_right_edge, + rectangle1_bottom_edge)) + overlap |= PLY_RECTANGLE_OVERLAP_LEFT_EDGE; + + /* + * 2222 + * 122221 + * 111111 + * 111111 + */ + if (ply_rectangle_contains_point (rectangle2, + rectangle2_left_edge, + rectangle1_top_edge) && + ply_rectangle_contains_point (rectangle2, + rectangle2_right_edge, + rectangle1_top_edge)) + overlap |= PLY_RECTANGLE_OVERLAP_TOP_EDGE; + + /* + * 2222222 + * 2211122 + * 111 + */ + if (ply_rectangle_contains_point (rectangle1, + rectangle1_left_edge, + rectangle2_bottom_edge) && + ply_rectangle_contains_point (rectangle1, + rectangle1_right_edge, + rectangle2_bottom_edge)) + overlap |= PLY_RECTANGLE_OVERLAP_TOP_EDGE; + + /* + * 111111 + * 111111 + * 122221 + * 2222 + */ + if (ply_rectangle_contains_point (rectangle1, + rectangle1_left_edge, + rectangle2_top_edge) && + ply_rectangle_contains_point (rectangle1, + rectangle1_right_edge, + rectangle2_top_edge)) + overlap |= PLY_RECTANGLE_OVERLAP_BOTTOM_EDGE; + + /* + * 111 + * 2211122 + * 2222222 + */ + if (ply_rectangle_contains_point (rectangle2, + rectangle2_left_edge, + rectangle1_bottom_edge) && + ply_rectangle_contains_point (rectangle2, + rectangle2_right_edge, + rectangle1_bottom_edge)) + overlap |= PLY_RECTANGLE_OVERLAP_BOTTOM_EDGE; + + return overlap; +} + +void +ply_rectangle_intersect (ply_rectangle_t *rectangle1, + ply_rectangle_t *rectangle2, + ply_rectangle_t *result) +{ + + long rectangle1_top_edge; + long rectangle1_left_edge; + long rectangle1_right_edge; + long rectangle1_bottom_edge; + long rectangle2_top_edge; + long rectangle2_left_edge; + long rectangle2_right_edge; + long rectangle2_bottom_edge; + long result_top_edge; + long result_left_edge; + long result_right_edge; + long result_bottom_edge; + + if (ply_rectangle_is_empty (rectangle1)) + { + *result = *rectangle1; + return; + } + + if (ply_rectangle_is_empty (rectangle2)) + { + *result = *rectangle2; + return; + } + + rectangle1_top_edge = rectangle1->y; + rectangle1_left_edge = rectangle1->x; + rectangle1_right_edge = rectangle1->x + rectangle1->width - 1; + rectangle1_bottom_edge = rectangle1->y + rectangle1->height - 1; + + rectangle2_top_edge = rectangle2->y; + rectangle2_left_edge = rectangle2->x; + rectangle2_right_edge = rectangle2->x + rectangle2->width - 1; + rectangle2_bottom_edge = rectangle2->y + rectangle2->height - 1; + + result_top_edge = MAX (rectangle1_top_edge, rectangle2_top_edge); + result_left_edge = MAX (rectangle1_left_edge, rectangle2_left_edge); + result_right_edge = MIN (rectangle1_right_edge, rectangle2_right_edge); + result_bottom_edge = MIN (rectangle1_bottom_edge, rectangle2_bottom_edge); + + result->x = result_left_edge; + result->y = result_top_edge; + + if (result_right_edge >= result_left_edge) + result->width = result_right_edge - result_left_edge + 1; + else + result->width = 0; + + if (result_bottom_edge >= result_top_edge) + result->height = result_bottom_edge - result_top_edge + 1; + else + result->height = 0; + + if (ply_rectangle_is_empty (result)) + { + result->width = 0; + result->height = 0; + } +} + +/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/libply/ply-rectangle.h b/src/libply/ply-rectangle.h new file mode 100644 index 00000000..bdbb6f4c --- /dev/null +++ b/src/libply/ply-rectangle.h @@ -0,0 +1,105 @@ +/* ply-rectangle.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_RECTANGLE_H +#define PLY_RECTANGLE_H + +#include <stdbool.h> +#include <stdint.h> + +#include "ply-utils.h" + +typedef struct _ply_rectangle ply_rectangle_t; + +struct _ply_rectangle +{ + long x; + long y; + unsigned long width; + unsigned long height; +}; + +typedef enum +{ + PLY_RECTANGLE_OVERLAP_NONE = 0, + PLY_RECTANGLE_OVERLAP_TOP_EDGE = 1 << 0, + PLY_RECTANGLE_OVERLAP_LEFT_EDGE = 1 << 1, + PLY_RECTANGLE_OVERLAP_RIGHT_EDGE = 1 << 2, + PLY_RECTANGLE_OVERLAP_BOTTOM_EDGE = 1 << 3, + PLY_RECTANGLE_OVERLAP_TOP_AND_LEFT_EDGES = + PLY_RECTANGLE_OVERLAP_TOP_EDGE | + PLY_RECTANGLE_OVERLAP_LEFT_EDGE, + PLY_RECTANGLE_OVERLAP_TOP_AND_RIGHT_EDGES = + PLY_RECTANGLE_OVERLAP_TOP_EDGE | + PLY_RECTANGLE_OVERLAP_RIGHT_EDGE, + PLY_RECTANGLE_OVERLAP_TOP_AND_SIDE_EDGES = + PLY_RECTANGLE_OVERLAP_TOP_EDGE | + PLY_RECTANGLE_OVERLAP_LEFT_EDGE | + PLY_RECTANGLE_OVERLAP_RIGHT_EDGE, + PLY_RECTANGLE_OVERLAP_BOTTOM_AND_LEFT_EDGES = + PLY_RECTANGLE_OVERLAP_BOTTOM_EDGE | + PLY_RECTANGLE_OVERLAP_LEFT_EDGE, + PLY_RECTANGLE_OVERLAP_BOTTOM_AND_RIGHT_EDGES = + PLY_RECTANGLE_OVERLAP_BOTTOM_EDGE | + PLY_RECTANGLE_OVERLAP_RIGHT_EDGE, + PLY_RECTANGLE_OVERLAP_BOTTOM_AND_SIDE_EDGES = + PLY_RECTANGLE_OVERLAP_BOTTOM_EDGE | + PLY_RECTANGLE_OVERLAP_LEFT_EDGE | + PLY_RECTANGLE_OVERLAP_RIGHT_EDGE, + PLY_RECTANGLE_OVERLAP_SIDE_EDGES = + PLY_RECTANGLE_OVERLAP_LEFT_EDGE | + PLY_RECTANGLE_OVERLAP_RIGHT_EDGE, + PLY_RECTANGLE_OVERLAP_TOP_AND_BOTTOM_EDGES = + PLY_RECTANGLE_OVERLAP_TOP_EDGE | + PLY_RECTANGLE_OVERLAP_BOTTOM_EDGE, + PLY_RECTANGLE_OVERLAP_TOP_LEFT_AND_BOTTOM_EDGES = + PLY_RECTANGLE_OVERLAP_TOP_EDGE | + PLY_RECTANGLE_OVERLAP_LEFT_EDGE | + PLY_RECTANGLE_OVERLAP_BOTTOM_EDGE, + PLY_RECTANGLE_OVERLAP_TOP_RIGHT_AND_BOTTOM_EDGES = + PLY_RECTANGLE_OVERLAP_TOP_EDGE | + PLY_RECTANGLE_OVERLAP_RIGHT_EDGE | + PLY_RECTANGLE_OVERLAP_BOTTOM_EDGE, + PLY_RECTANGLE_OVERLAP_ALL_EDGES = + PLY_RECTANGLE_OVERLAP_TOP_EDGE | + PLY_RECTANGLE_OVERLAP_LEFT_EDGE | + PLY_RECTANGLE_OVERLAP_BOTTOM_EDGE | + PLY_RECTANGLE_OVERLAP_RIGHT_EDGE, + PLY_RECTANGLE_OVERLAP_NO_EDGES = 1 << 4, +} ply_rectangle_overlap_t; + +#ifndef PLY_HIDE_FUNCTION_DECLARATIONS +bool ply_rectangle_contains_point (ply_rectangle_t *rectangle, + long x, + long y); + +bool ply_rectangle_is_empty (ply_rectangle_t *rectangle); + +ply_rectangle_overlap_t ply_rectangle_find_overlap (ply_rectangle_t *rectangle1, + ply_rectangle_t *rectangle2); + +void ply_rectangle_intersect (ply_rectangle_t *rectangle1, + ply_rectangle_t *rectangle2, + ply_rectangle_t *result); +#endif + +#endif /* PLY_RECTANGLE_H */ +/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/libply/ply-region.c b/src/libply/ply-region.c new file mode 100644 index 00000000..ec6ca5d7 --- /dev/null +++ b/src/libply/ply-region.c @@ -0,0 +1,390 @@ +/* ply-region.c + * + * Copyright (C) 2009 Red Hat, Inc. + * + * Based in part on some work by: + * Copyright (C) 2009 Charlie Brej <cbrej@cs.man.ac.uk> + * + * 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: Charlie Brej <cbrej@cs.man.ac.uk> + * Ray Strode <rstrode@redhat.com> + */ +#include "config.h" +#include "ply-region.h" + +#include <assert.h> +#include <stdlib.h> + +#include "ply-list.h" +#include "ply-rectangle.h" + +struct _ply_region +{ + ply_list_t *rectangle_list; +}; + +ply_region_t * +ply_region_new (void) +{ + ply_region_t *region; + + region = calloc (1, sizeof (ply_region_t)); + + region->rectangle_list = ply_list_new (); + + return region; +} + +void +ply_region_clear (ply_region_t *region) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (region->rectangle_list); + while (node != NULL) + { + ply_list_node_t *next_node; + ply_rectangle_t *rectangle; + + rectangle = (ply_rectangle_t *) ply_list_node_get_data (node); + + next_node = ply_list_get_next_node (region->rectangle_list, node); + + free (rectangle); + ply_list_remove_node (region->rectangle_list, node); + + node = next_node; + } +} + +void +ply_region_free (ply_region_t *region) +{ + + ply_region_clear (region); + ply_list_free (region->rectangle_list); + free (region); +} + +static ply_rectangle_t * +copy_rectangle (ply_rectangle_t *rectangle) +{ + ply_rectangle_t *new_rectangle; + + new_rectangle = malloc (sizeof (*rectangle)); + *new_rectangle = *rectangle; + + return new_rectangle; +} + +static void +merge_rectangle_with_sub_list (ply_region_t *region, + ply_rectangle_t *new_area, + ply_list_node_t *node) +{ + + if (ply_rectangle_is_empty (new_area)) + return; + + while (node != NULL) + { + ply_list_node_t *next_node; + ply_rectangle_t *old_area; + ply_rectangle_overlap_t overlap; + + old_area = (ply_rectangle_t *) ply_list_node_get_data (node); + + next_node = ply_list_get_next_node (region->rectangle_list, node); + + overlap = ply_rectangle_find_overlap (old_area, new_area); + + switch (overlap) + { + /* NNNN The new rectangle and node rectangle don't touch, + * NNNN OOOO so let's move on to the next one. + * OOOO + */ + case PLY_RECTANGLE_OVERLAP_NONE: + break; + + /* NNNNN We need to split the new rectangle into + * NNOOOOO two rectangles: The top row of Ns and + * NNOOOOO the left side of Ns. + * OOOOO + */ + case PLY_RECTANGLE_OVERLAP_TOP_AND_LEFT_EDGES: + { + ply_rectangle_t *rectangle; + + rectangle = copy_rectangle (new_area); + rectangle->y = old_area->y; + rectangle->width = old_area->x - new_area->x; + rectangle->height = (new_area->y + new_area->height) - old_area->y; + + merge_rectangle_with_sub_list (region, rectangle, node); + + new_area->height = old_area->y - new_area->y; + } + break; + + /* NNNNN We need to split the new rectangle into + * OOOOONN two rectangles: The top row of Ns and + * OOOOONN the right side of Ns. + * OOOOO + */ + case PLY_RECTANGLE_OVERLAP_TOP_AND_RIGHT_EDGES: + { + ply_rectangle_t *rectangle; + + rectangle = copy_rectangle (new_area); + rectangle->x = new_area->x + old_area->width; + rectangle->y = old_area->y; + rectangle->width = (old_area->x + new_area->width) - (old_area->x + old_area->width); + rectangle->height = (new_area->y + new_area->height) - old_area->y; + + merge_rectangle_with_sub_list (region, rectangle, node); + + new_area->height = old_area->y - new_area->y; + } + break; + + /* NNNNNNN We need to trim out the part of + * NOOOOON old rectangle that overlaps the new + * NOOOOON rectangle by shrinking and moving it + * OOOOO and then we need to add the new rectangle. + */ + case PLY_RECTANGLE_OVERLAP_TOP_AND_SIDE_EDGES: + { + old_area->height = (old_area->y + old_area->height) + - (new_area->y + new_area->height); + old_area->y = new_area->y + new_area->height; + } + + /* NNN We only care about the top row of Ns, + * ONNNO everything below that is already handled by + * ONNNO the old rectangle. + * OOOOO + */ + case PLY_RECTANGLE_OVERLAP_TOP_EDGE: + new_area->height = old_area->y - new_area->y; + break; + + /* OOOOO We need to split the new rectangle into + * NNOOOOO two rectangles: The left side of Ns and + * NNOOOOO the bottom row of Ns. + * NNOOOOO + * NNNNN + */ + case PLY_RECTANGLE_OVERLAP_BOTTOM_AND_LEFT_EDGES: + { + ply_rectangle_t *rectangle; + + rectangle = copy_rectangle (new_area); + + rectangle->y = old_area->y; + rectangle->width = old_area->x - new_area->x; + rectangle->height = (old_area->y + old_area->height) - new_area->y; + + merge_rectangle_with_sub_list (region, rectangle, node); + + new_area->height = (new_area->y + new_area->height) - (old_area->y + old_area->height); + new_area->width = new_area->width; + new_area->y = old_area->y + old_area->height; + } + break; + + /* OOOOO We need to split the new rectangle into + * OOOOONN two rectangles: The right side of Ns and + * OOOOONN the bottom row of Ns. + * OOOOONN + * NNNNN + */ + case PLY_RECTANGLE_OVERLAP_BOTTOM_AND_RIGHT_EDGES: + { + ply_rectangle_t *rectangle; + + rectangle = copy_rectangle (new_area); + + rectangle->x = old_area->x + old_area->width; + rectangle->width = (new_area->x + new_area->width) - (old_area->x + old_area->width); + rectangle->height = (old_area->y + old_area->height) - new_area->y; + + merge_rectangle_with_sub_list (region, rectangle, node); + + new_area->height = (new_area->y + new_area->height) - (old_area->y + old_area->height); + new_area->y = old_area->y + old_area->height; + } + break; + + /* OOOOO We need to trim out the part of + * NOOOOON old rectangle that overlaps the new + * NOOOOON rectangle by shrinking it + * NNNNNNN and then we need to add the new rectangle. + */ + case PLY_RECTANGLE_OVERLAP_BOTTOM_AND_SIDE_EDGES: + { + old_area->height = (new_area->y + new_area->height) + - (old_area->y + old_area->height); + } + break; + + /* OOOOO We only care about the bottom row of Ns, + * ONNNO everything above that is already handled by + * ONNNO the old rectangle. + * NNN + */ + case PLY_RECTANGLE_OVERLAP_BOTTOM_EDGE: + { + new_area->height = (new_area->y + new_area->height) - (old_area->y + old_area->height); + new_area->y = old_area->y + old_area->height; + } + break; + + /* NNNN We need to trim out the part of + * NNNNO old rectangle that overlaps the new + * NNNNO rectangle by shrinking it and moving it + * NNNN and then we need to add the new rectangle. + */ + case PLY_RECTANGLE_OVERLAP_TOP_LEFT_AND_BOTTOM_EDGES: + { + old_area->width = (old_area->x + old_area->width) + - (new_area->x + new_area->width); + old_area->x = new_area->x + new_area->width; + } + break; + + /* NNNN We need to trim out the part of + * ONNNN old rectangle that overlaps the new + * ONNNN rectangle by shrinking it and then we + * NNNN need to add the new rectangle. + */ + case PLY_RECTANGLE_OVERLAP_TOP_RIGHT_AND_BOTTOM_EDGES: + old_area->width = new_area->x - old_area->x; + break; + + /* NNNNNNN The old rectangle is completely inside the new rectangle + * NOOOOON so replace the old rectangle with the new rectangle. + * NOOOOON + * NNNNNNN + */ + case PLY_RECTANGLE_OVERLAP_ALL_EDGES: + free (old_area); + ply_list_remove_node (region->rectangle_list, node); + break; + + /* NNN We need to split the new rectangle into + * ONNNO two rectangles: the top and bottom row of Ns + * ONNNO + * NNN + */ + case PLY_RECTANGLE_OVERLAP_TOP_AND_BOTTOM_EDGES: + { + ply_rectangle_t *rectangle; + + rectangle = copy_rectangle (new_area); + rectangle->y = old_area->y + old_area->height; + rectangle->width = new_area->width; + rectangle->height = (new_area->y + new_area->height) - (old_area->y + old_area->height); + merge_rectangle_with_sub_list (region, rectangle, node); + + new_area->height = old_area->y - new_area->y; + } + break; + + /* OOOOO We only care about the side row of Ns, + * NNNNOO everything rigth of that is already handled by + * NNNNOO the old rectangle. + * OOOOO + */ + case PLY_RECTANGLE_OVERLAP_LEFT_EDGE: + new_area->width = old_area->x - new_area->x; + break; + + /* OOOOO We only care about the side row of Ns, + * NNNNNN everything left of that is already handled by + * NNNNNN the old rectangle. + * OOOOO + */ + case PLY_RECTANGLE_OVERLAP_RIGHT_EDGE: + { + new_area->width = (new_area->x + new_area->width) - (old_area->x + old_area->width); + new_area->x = old_area->x + old_area->width; + } + break; + + /* OOOOO We need to split the new rectangle into + * NNNNNNN two rectangles: the side columns of Ns + * NNNNNNN + * OOOOO + */ + case PLY_RECTANGLE_OVERLAP_SIDE_EDGES: + { + ply_rectangle_t *rectangle; + + rectangle = copy_rectangle (new_area); + + rectangle->x = old_area->x + old_area->width; + rectangle->width = (new_area->x + new_area->width) - (old_area->x + old_area->width); + + merge_rectangle_with_sub_list (region, rectangle, node); + + new_area->width = old_area->x - new_area->x; + } + break; + + /* OOOOOOO The new rectangle is completely inside an old rectangle + * ONNNNNO so return early without adding the new rectangle. + * ONNNNNO + * OOOOOOO + */ + case PLY_RECTANGLE_OVERLAP_NO_EDGES: + free (new_area); + return; + + } + + node = next_node; + } + + ply_list_append_data (region->rectangle_list, new_area); +} + +void +ply_region_add_rectangle (ply_region_t *region, + ply_rectangle_t *rectangle) +{ + ply_list_node_t *first_node; + ply_rectangle_t *rectangle_copy; + + assert (region != NULL); + assert (rectangle != NULL); + + first_node = ply_list_get_first_node (region->rectangle_list); + + rectangle_copy = copy_rectangle (rectangle); + merge_rectangle_with_sub_list (region, + rectangle_copy, + first_node); +} + +ply_list_t * +ply_region_get_rectangle_list (ply_region_t *region) +{ + return region->rectangle_list; +} + +/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/libply/ply-terminal.h b/src/libply/ply-region.h index df5af542..ee6e992f 100644 --- a/src/libply/ply-terminal.h +++ b/src/libply/ply-region.h @@ -1,6 +1,6 @@ -/* ply-terminal.h - psuedoterminal abstraction +/* ply-region.h * - * Copyright (C) 2007 Red Hat, Inc. + * 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 @@ -19,25 +19,29 @@ * * Written By: Ray Strode <rstrode@redhat.com> */ -#ifndef PLY_TERMINAL_H -#define PLY_TERMINAL_H +#ifndef PLY_REGION_H +#define PLY_REGION_H #include <stdbool.h> #include <stdint.h> -#include <unistd.h> -typedef struct _ply_terminal ply_terminal_t; +#include "ply-list.h" +#include "ply-rectangle.h" +#include "ply-utils.h" + +typedef struct _ply_region ply_region_t; #ifndef PLY_HIDE_FUNCTION_DECLARATIONS -ply_terminal_t *ply_terminal_new (void); -void ply_terminal_free (ply_terminal_t *terminal); -bool ply_terminal_create_device (ply_terminal_t *terminal); -bool ply_terminal_has_device (ply_terminal_t *terminal); -void ply_terminal_destroy_device (ply_terminal_t *terminal); -int ply_terminal_get_fd (ply_terminal_t *terminal); -void ply_terminal_set_fd (ply_terminal_t *terminal, int fd); -const char *ply_terminal_get_device_name (ply_terminal_t *terminal); +ply_region_t *ply_region_new (void); +void ply_region_free (ply_region_t *region); +void ply_region_add_rectangle (ply_region_t *region, + ply_rectangle_t *rectangle); +void ply_region_clear (ply_region_t *region); +ply_list_t *ply_region_get_rectangle_list (ply_region_t *region); + +bool ply_region_is_empty (ply_region_t *region); + #endif -#endif /* PLY_TERMINAL_H */ +#endif /* PLY_REGION_H */ /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/libply/ply-terminal-session.c b/src/libply/ply-terminal-session.c index 2a4ca8db..68f487fd 100644 --- a/src/libply/ply-terminal-session.c +++ b/src/libply/ply-terminal-session.c @@ -39,12 +39,11 @@ #include "ply-event-loop.h" #include "ply-logger.h" -#include "ply-terminal.h" #include "ply-utils.h" struct _ply_terminal_session { - ply_terminal_t *terminal; + int pseudoterminal_master_fd; ply_logger_t *logger; ply_event_loop_t *loop; char **argv; @@ -71,7 +70,7 @@ ply_terminal_session_open_console (ply_terminal_session_t *session) int fd; const char *terminal_name; - terminal_name = ply_terminal_get_device_name (session->terminal); + terminal_name = ptsname (session->pseudoterminal_master_fd); fd = open (terminal_name, O_RDONLY); @@ -128,8 +127,8 @@ ply_terminal_session_new (const char * const *argv) assert (argv == NULL || argv[0] != NULL); session = calloc (1, sizeof (ply_terminal_session_t)); + session->pseudoterminal_master_fd = -1; session->argv = argv == NULL ? NULL : ply_copy_string_array (argv); - session->terminal = ply_terminal_new (); session->logger = ply_logger_new (); session->is_running = false; session->console_is_redirected = false; @@ -147,7 +146,8 @@ ply_terminal_session_free (ply_terminal_session_t *session) ply_logger_free (session->logger); ply_free_string_array (session->argv); - ply_terminal_free (session->terminal); + + close (session->pseudoterminal_master_fd); free (session); } @@ -181,7 +181,7 @@ ply_terminal_session_redirect_console (ply_terminal_session_t *session) assert (session != NULL); - terminal_name = ply_terminal_get_device_name (session->terminal); + terminal_name = ptsname (session->pseudoterminal_master_fd); assert (terminal_name != NULL); @@ -218,6 +218,49 @@ ply_terminal_session_unredirect_console (ply_terminal_session_t *session) session->console_is_redirected = false; } +static void +close_pseudoterminal (ply_terminal_session_t *session) +{ + close (session->pseudoterminal_master_fd); + session->pseudoterminal_master_fd = -1; +} + +static bool +open_pseudoterminal (ply_terminal_session_t *session) +{ + ply_trace ("opening device '/dev/ptmx'"); + session->pseudoterminal_master_fd = posix_openpt (O_RDWR | O_NOCTTY); + + if (session->pseudoterminal_master_fd < 0) + return false; + + ply_trace (" opened device '/dev/ptmx'"); + + ply_trace ("creating pseudoterminal"); + if (grantpt (session->pseudoterminal_master_fd) < 0) + { + ply_save_errno (); + ply_trace ("could not create psuedoterminal: %m"); + close_pseudoterminal (session); + ply_restore_errno (); + return false; + } + ply_trace ("done creating pseudoterminal"); + + ply_trace ("unlocking pseudoterminal"); + if (unlockpt (session->pseudoterminal_master_fd) < 0) + { + ply_save_errno (); + close_pseudoterminal (session); + ply_restore_errno (); + return false; + } + ply_trace ("unlocked pseudoterminal"); + + return true; +} + + bool ply_terminal_session_run (ply_terminal_session_t *session, ply_terminal_session_flags_t flags, @@ -240,7 +283,7 @@ ply_terminal_session_run (ply_terminal_session_t *session, (flags & PLY_TERMINAL_SESSION_FLAGS_REDIRECT_CONSOLE) != 0; ply_trace ("creating terminal device"); - if (!ply_terminal_create_device (session->terminal)) + if (!open_pseudoterminal (session)) return false; ply_trace ("done creating terminal device"); @@ -250,7 +293,7 @@ ply_terminal_session_run (ply_terminal_session_t *session, !ply_terminal_session_redirect_console (session)) { ply_save_errno (); - ply_terminal_destroy_device (session->terminal); + close_pseudoterminal (session); ply_restore_errno (); return false; } @@ -264,7 +307,7 @@ ply_terminal_session_run (ply_terminal_session_t *session, { ply_save_errno (); ply_terminal_session_unredirect_console (session); - ply_terminal_destroy_device (session->terminal); + close_pseudoterminal (session); ply_restore_errno (); return false; } @@ -316,12 +359,12 @@ ply_terminal_session_attach (ply_terminal_session_t *session, if (ptmx >= 0) { ply_trace ("ptmx passed in, using it"); - ply_terminal_set_fd(session->terminal, ptmx); + session->pseudoterminal_master_fd = ptmx; } else { ply_trace ("ptmx not passed in, creating one"); - if (!ply_terminal_create_device (session->terminal)) + if (!open_pseudoterminal (session)) { ply_trace ("could not create pseudo-terminal: %m"); return false; @@ -336,7 +379,7 @@ ply_terminal_session_attach (ply_terminal_session_t *session, !ply_terminal_session_redirect_console (session)) { ply_save_errno (); - ply_terminal_destroy_device (session->terminal); + close_pseudoterminal (session); ply_restore_errno (); return false; } @@ -370,7 +413,7 @@ ply_terminal_session_detach (ply_terminal_session_t *session) if (session->created_terminal_device) { ply_trace ("ptmx wasn't originally passed in, destroying created one"); - ply_terminal_destroy_device (session->terminal); + close_pseudoterminal (session); session->created_terminal_device = false; } @@ -386,7 +429,7 @@ ply_terminal_session_get_fd (ply_terminal_session_t *session) { assert (session != NULL); - return ply_terminal_get_fd (session->terminal); + return session->pseudoterminal_master_fd; } static void diff --git a/src/libply/ply-terminal.c b/src/libply/ply-terminal.c deleted file mode 100644 index 9ad293f1..00000000 --- a/src/libply/ply-terminal.c +++ /dev/null @@ -1,201 +0,0 @@ -/* ply-terminal.c - psuedoterminal abstraction - * - * Copyright (C) 2006, 2007 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: Kristian Høgsberg <krh@redhat.com> - * Ray Strode <rstrode@redhat.com> - */ -#include "config.h" -#include "ply-terminal.h" - -#include <assert.h> -#include <errno.h> -#include <fcntl.h> -#include <string.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/mount.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include "ply-logger.h" -#include "ply-utils.h" - -struct _ply_terminal -{ - char *name; - int fd; -}; - -ply_terminal_t * -ply_terminal_new (void) -{ - ply_terminal_t *terminal; - - terminal = calloc (1, sizeof (ply_terminal_t)); - terminal->fd = -1; - - return terminal; -} - -void -ply_terminal_free (ply_terminal_t *terminal) -{ - assert (terminal != NULL); - - ply_terminal_destroy_device (terminal); - free (terminal); -} - -bool -ply_terminal_create_device (ply_terminal_t *terminal) -{ - assert (terminal != NULL); - assert (!ply_terminal_has_device (terminal)); - - ply_trace ("opening device '/dev/ptmx'"); - terminal->fd = posix_openpt (O_RDWR | O_NOCTTY); - - if (terminal->fd < 0) - return false; - - ply_trace (" opened device '/dev/ptmx'"); - - ply_trace ("creating pseudoterminal"); - if (grantpt (terminal->fd) < 0) - { - ply_save_errno (); - ply_trace ("could not create psuedoterminal: %m"); - ply_terminal_destroy_device (terminal); - ply_restore_errno (); - return false; - } - ply_trace ("done creating pseudoterminal"); - - ply_trace ("unlocking pseudoterminal"); - if (unlockpt (terminal->fd) < 0) - { - ply_save_errno (); - ply_terminal_destroy_device (terminal); - ply_restore_errno (); - return false; - } - ply_trace ("unlocked pseudoterminal"); - - terminal->name = strdup (ptsname (terminal->fd)); - ply_trace ("pseudoterminal '%s' ready for action", terminal->name); - - return true; -} - -bool -ply_terminal_has_device (ply_terminal_t *terminal) -{ - assert (terminal != NULL); - - return terminal->fd >= 0; -} - -void -ply_terminal_destroy_device (ply_terminal_t *terminal) -{ - assert (terminal != NULL); - - free (terminal->name); - terminal->name = NULL; - - close (terminal->fd); - terminal->fd = -1; -} - -int -ply_terminal_get_fd (ply_terminal_t *terminal) -{ - assert (terminal != NULL); - - return terminal->fd; -} - -void -ply_terminal_set_fd (ply_terminal_t *terminal, int fd) -{ - assert (terminal != NULL); - - terminal->fd = fd; - - if (terminal->name) - { - free(terminal->name); - terminal->name = NULL; - } - - if (terminal->fd >= 0) - terminal->name = strdup (ptsname (terminal->fd)); -} - -const char * -ply_terminal_get_device_name (ply_terminal_t *terminal) -{ - assert (terminal != NULL); - assert (ply_terminal_has_device (terminal)); - - assert (terminal->name != NULL); - return terminal->name; -} - -#ifdef PLY_TERMINAL_ENABLE_TEST - -#include <stdio.h> - -int -main (int argc, - char **argv) -{ - ply_terminal_t *terminal; - const char *name; - uint8_t byte; - int exit_code; - - exit_code = 0; - - terminal = ply_terminal_new (); - - if (!ply_terminal_create_device (terminal)) - { - exit_code = errno; - perror ("could not open new terminal"); - return exit_code; - } - - name = ply_terminal_get_device_name (terminal); - printf ("terminal name is '%s'\n", name); - - while (read (ply_terminal_get_fd (terminal), - &byte, sizeof (byte)) == 1) - printf ("%c", byte); - - ply_terminal_free (terminal); - - return exit_code; -} - -#endif /* PLY_TERMINAL_ENABLE_TEST */ -/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/libply/ply-trigger.c b/src/libply/ply-trigger.c index b1952d71..46ea5477 100644 --- a/src/libply/ply-trigger.c +++ b/src/libply/ply-trigger.c @@ -41,6 +41,7 @@ struct _ply_trigger ply_list_t *closures; ply_trigger_t **free_address; + int ignore_count; }; ply_trigger_t * @@ -51,6 +52,7 @@ ply_trigger_new (ply_trigger_t **free_address) trigger = calloc (1, sizeof (ply_trigger_t)); trigger->free_address = free_address; trigger->closures = ply_list_new (); + trigger->ignore_count = 0; return trigger; } @@ -132,12 +134,25 @@ ply_trigger_remove_handler (ply_trigger_t *trigger, } void +ply_trigger_ignore_next_pull (ply_trigger_t *trigger) +{ + trigger->ignore_count++; +} + +void ply_trigger_pull (ply_trigger_t *trigger, const void *data) { ply_list_node_t *node; assert (trigger != NULL); + assert (trigger->ignore_count >= 0); + + if (trigger->ignore_count > 0) + { + trigger->ignore_count--; + return; + } node = ply_list_get_first_node (trigger->closures); while (node != NULL) diff --git a/src/libply/ply-trigger.h b/src/libply/ply-trigger.h index cf9fbf09..d543f042 100644 --- a/src/libply/ply-trigger.h +++ b/src/libply/ply-trigger.h @@ -44,6 +44,7 @@ void ply_trigger_remove_handler (ply_trigger_t *trigger, void *user_data); void ply_trigger_free (ply_trigger_t *trigger); +void ply_trigger_ignore_next_pull (ply_trigger_t *trigger); void ply_trigger_pull (ply_trigger_t *trigger, const void *data); #endif diff --git a/src/libply/ply-utils.c b/src/libply/ply-utils.c index 37b986be..b26773c5 100644 --- a/src/libply/ply-utils.c +++ b/src/libply/ply-utils.c @@ -894,25 +894,4 @@ ply_utf8_string_get_length (const char *string, return count; } -void -ply_switch_to_vt (int vt_number) -{ - int fd; - - fd = open ("/dev/tty0", O_RDWR | O_NOCTTY); - - if (fd < 0) - return; - - if (ioctl (fd, VT_ACTIVATE, vt_number) < 0) - { - close (fd); - return; - } - - ioctl (fd, VT_WAITACTIVE, vt_number); - close (fd); -} - - /* 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 62149ba3..5e41f841 100644 --- a/src/libply/ply-utils.h +++ b/src/libply/ply-utils.h @@ -46,6 +46,9 @@ typedef void (* ply_module_function_t) (void); typedef intptr_t ply_daemon_handle_t; #ifndef PLY_HIDE_FUNCTION_DECLARATIONS + +#define ply_round_to_multiple(n, m) (((n) + (((m) - 1))) & ~((m) - 1)) + bool ply_open_unidirectional_pipe (int *sender_fd, int *receiver_fd); int ply_connect_to_unix_socket (const char *path, @@ -104,8 +107,6 @@ int ply_utf8_character_get_size (const char *string, int ply_utf8_string_get_length (const char *string, size_t n); -void ply_switch_to_vt (int vt_number); - #endif #endif /* PLY_UTILS_H */ diff --git a/src/libply/tests/Makefile.am b/src/libply/tests/Makefile.am index 9ef83381..5707c251 100644 --- a/src/libply/tests/Makefile.am +++ b/src/libply/tests/Makefile.am @@ -5,8 +5,6 @@ INCLUDES = \ TESTS = if ENABLE_TESTS -include $(srcdir)/ply-frame-buffer-test.am -include $(srcdir)/ply-terminal-test.am include $(srcdir)/ply-terminal-session-test.am include $(srcdir)/ply-logger-test.am include $(srcdir)/ply-array-test.am diff --git a/src/libply/tests/ply-frame-buffer-test.am b/src/libply/tests/ply-frame-buffer-test.am deleted file mode 100644 index 82afe7fd..00000000 --- a/src/libply/tests/ply-frame-buffer-test.am +++ /dev/null @@ -1,14 +0,0 @@ -TESTS += ply-frame-buffer-test - -ply_frame_buffer_test_CFLAGS = $(PLYMOUTH_CFLAGS) -DPLY_FRAME_BUFFER_ENABLE_TEST -ply_frame_buffer_test_LDADD = $(PLYMOUTH_LIBS) -ply_frame_buffer_test_SOURCES = \ - $(srcdir)/../ply-utils.h \ - $(srcdir)/../ply-frame-buffer.h \ - $(srcdir)/../ply-frame-buffer.c \ - $(srcdir)/../ply-list.h \ - $(srcdir)/../ply-list.c \ - $(srcdir)/../ply-logger.h \ - $(srcdir)/../ply-logger.c \ - $(srcdir)/../ply-utils.h \ - $(srcdir)/../ply-utils.c diff --git a/src/libply/tests/ply-terminal-session-test.am b/src/libply/tests/ply-terminal-session-test.am index 8206f39f..decb531b 100644 --- a/src/libply/tests/ply-terminal-session-test.am +++ b/src/libply/tests/ply-terminal-session-test.am @@ -14,7 +14,5 @@ ply_terminal_session_test_SOURCES = $(srcdir)/../ply-list.c \ $(srcdir)/../ply-event-loop.h \ $(srcdir)/../ply-event-loop.c \ - $(srcdir)/../ply-terminal.h \ - $(srcdir)/../ply-terminal.c \ $(srcdir)/../ply-terminal-session.h \ $(srcdir)/../ply-terminal-session.c diff --git a/src/libply/tests/ply-terminal-test.am b/src/libply/tests/ply-terminal-test.am deleted file mode 100644 index 67a25724..00000000 --- a/src/libply/tests/ply-terminal-test.am +++ /dev/null @@ -1,14 +0,0 @@ -TESTS += ply-terminal-test - -ply_terminal_test_CFLAGS = $(PLYMOUTH_CFLAGS) -DPLY_TERMINAL_ENABLE_TEST -ply_terminal_test_LDADD = $(PLYMOUTH_LIBS) - -ply_terminal_test_SOURCES = \ - $(srcdir)/../ply-list.h \ - $(srcdir)/../ply-list.c \ - $(srcdir)/../ply-logger.h \ - $(srcdir)/../ply-logger.c \ - $(srcdir)/../ply-utils.h \ - $(srcdir)/../ply-utils.c \ - $(srcdir)/../ply-terminal.h \ - $(srcdir)/../ply-terminal.c diff --git a/src/libplybootsplash/Makefile.am b/src/libplybootsplash/Makefile.am index 508a212c..d2638055 100644 --- a/src/libplybootsplash/Makefile.am +++ b/src/libplybootsplash/Makefile.am @@ -10,15 +10,22 @@ libplybootsplash_HEADERS = \ ply-animation.h \ ply-boot-splash.h \ ply-boot-splash-plugin.h \ + ply-console.h \ ply-entry.h \ ply-image.h \ + ply-keyboard.h \ ply-label.h \ ply-label-plugin.h \ + ply-pixel-buffer.h \ + ply-pixel-display.h \ ply-progress-animation.h \ ply-progress-bar.h \ + ply-renderer.h \ + ply-renderer-plugin.h \ + ply-terminal.h \ + ply-text-display.h \ ply-text-progress-bar.h \ - ply-throbber.h \ - ply-window.h + ply-throbber.h libplybootsplash_la_CFLAGS = $(PLYMOUTH_CFLAGS) \ $(IMAGE_CFLAGS) \ @@ -32,15 +39,21 @@ libplybootsplash_la_LDFLAGS = -export-symbols-regex '^[^_].*' \ -no-undefined libplybootsplash_la_SOURCES = \ $(libplybootsplash_HEADERS) \ + ply-console.c \ ply-entry.c \ ply-image.c \ + ply-keyboard.c \ ply-label.c \ ply-progress-bar.c \ ply-throbber.c \ ply-animation.c \ + ply-pixel-display.c \ ply-progress-animation.c \ + ply-text-display.c \ ply-text-progress-bar.c \ - ply-window.c \ + ply-terminal.c \ + ply-pixel-buffer.c \ + ply-renderer.c \ ply-boot-splash.c MAINTAINERCLEANFILES = Makefile.in diff --git a/src/libplybootsplash/ply-animation.c b/src/libplybootsplash/ply-animation.c index 7d2c481d..1fee4b9c 100644 --- a/src/libplybootsplash/ply-animation.c +++ b/src/libplybootsplash/ply-animation.c @@ -44,10 +44,9 @@ #include "ply-event-loop.h" #include "ply-array.h" #include "ply-logger.h" -#include "ply-frame-buffer.h" #include "ply-image.h" +#include "ply-pixel-buffer.h" #include "ply-utils.h" -#include "ply-window.h" #include <linux/kd.h> @@ -62,9 +61,8 @@ struct _ply_animation char *image_dir; char *frames_prefix; - ply_window_t *window; - ply_frame_buffer_t *frame_buffer; - ply_frame_buffer_area_t frame_area; + ply_pixel_display_t *display; + ply_rectangle_t frame_area; ply_trigger_t *stop_trigger; int frame_number; @@ -128,26 +126,14 @@ ply_animation_free (ply_animation_t *animation) free (animation); } -static void -draw_background (ply_animation_t *animation) -{ - ply_window_erase_area (animation->window, - animation->x, animation->y, - animation->frame_area.width, - animation->frame_area.height); -} - static bool animate_at_time (ply_animation_t *animation, double time) { int number_of_frames; ply_image_t * const * frames; - uint32_t *frame_data; bool should_continue; - ply_window_set_mode (animation->window, PLY_WINDOW_MODE_GRAPHICS); - number_of_frames = ply_array_get_size (animation->frames); if (number_of_frames == 0) @@ -161,22 +147,17 @@ animate_at_time (ply_animation_t *animation, if (animation->stop_requested) should_continue = false; - ply_frame_buffer_pause_updates (animation->frame_buffer); - if (animation->frame_area.width > 0) - draw_background (animation); - frames = (ply_image_t * const *) ply_array_get_elements (animation->frames); animation->frame_area.x = animation->x; animation->frame_area.y = animation->y; animation->frame_area.width = ply_image_get_width (frames[animation->frame_number]); animation->frame_area.height = ply_image_get_height (frames[animation->frame_number]); - frame_data = ply_image_get_data (frames[animation->frame_number]); - ply_frame_buffer_fill_with_argb32_data (animation->frame_buffer, - &animation->frame_area, 0, 0, - frame_data); - ply_frame_buffer_unpause_updates (animation->frame_buffer); + ply_pixel_display_draw_area (animation->display, + animation->x, animation->y, + animation->frame_area.width, + animation->frame_area.height); animation->frame_number++; @@ -313,19 +294,19 @@ ply_animation_load (ply_animation_t *animation) bool ply_animation_start (ply_animation_t *animation, - ply_event_loop_t *loop, - ply_window_t *window, + ply_pixel_display_t *display, ply_trigger_t *stop_trigger, long x, long y) { assert (animation != NULL); - assert (animation->loop == NULL); - animation->loop = loop; - animation->window = window; + if (!animation->is_stopped) + return true; + + animation->loop = ply_event_loop_get_default (); + animation->display = display; animation->stop_trigger = stop_trigger; - animation->frame_buffer = ply_window_get_frame_buffer (window);; animation->is_stopped = false; animation->stop_requested = false; @@ -345,8 +326,6 @@ ply_animation_start (ply_animation_t *animation, static void ply_animation_stop_now (ply_animation_t *animation) { - animation->frame_buffer = NULL; - animation->window = NULL; animation->is_stopped = true; if (animation->loop != NULL) @@ -356,6 +335,8 @@ ply_animation_stop_now (ply_animation_t *animation) on_timeout, animation); animation->loop = NULL; } + + animation->display = NULL; } void @@ -376,6 +357,28 @@ ply_animation_is_stopped (ply_animation_t *animation) return animation->is_stopped; } +void +ply_animation_draw_area (ply_animation_t *animation, + ply_pixel_buffer_t *buffer, + long x, + long y, + unsigned long width, + unsigned long height) +{ + ply_image_t * const * frames; + uint32_t *frame_data; + + if (animation->is_stopped) + return; + + frames = (ply_image_t * const *) ply_array_get_elements (animation->frames); + frame_data = ply_image_get_data (frames[animation->frame_number]); + + ply_pixel_buffer_fill_with_argb32_data (buffer, + &animation->frame_area, 0, 0, + frame_data); +} + long ply_animation_get_width (ply_animation_t *animation) { diff --git a/src/libplybootsplash/ply-animation.h b/src/libplybootsplash/ply-animation.h index eea68d81..7b905472 100644 --- a/src/libplybootsplash/ply-animation.h +++ b/src/libplybootsplash/ply-animation.h @@ -27,9 +27,8 @@ #include <unistd.h> #include "ply-event-loop.h" -#include "ply-frame-buffer.h" +#include "ply-pixel-display.h" #include "ply-trigger.h" -#include "ply-window.h" typedef struct _ply_animation ply_animation_t; @@ -40,14 +39,20 @@ void ply_animation_free (ply_animation_t *animation); bool ply_animation_load (ply_animation_t *animation); bool ply_animation_start (ply_animation_t *animation, - ply_event_loop_t *loop, - ply_window_t *window, + ply_pixel_display_t *display, ply_trigger_t *stop_trigger, long x, long y); void ply_animation_stop (ply_animation_t *animation); bool ply_animation_is_stopped (ply_animation_t *animation); +void ply_animation_draw_area (ply_animation_t *animation, + ply_pixel_buffer_t *buffer, + long x, + long y, + unsigned long width, + unsigned long height); + long ply_animation_get_width (ply_animation_t *animation); long ply_animation_get_height (ply_animation_t *animation); #endif diff --git a/src/libplybootsplash/ply-boot-splash-plugin.h b/src/libplybootsplash/ply-boot-splash-plugin.h index 4671d0c2..d22eb437 100644 --- a/src/libplybootsplash/ply-boot-splash-plugin.h +++ b/src/libplybootsplash/ply-boot-splash-plugin.h @@ -28,9 +28,11 @@ #include "ply-buffer.h" #include "ply-event-loop.h" +#include "ply-keyboard.h" +#include "ply-pixel-display.h" +#include "ply-text-display.h" #include "ply-trigger.h" #include "ply-key-file.h" -#include "ply-window.h" typedef enum { @@ -47,11 +49,18 @@ typedef struct ply_boot_splash_plugin_t * (* create_plugin) (ply_key_file_t *key_file); void (* destroy_plugin) (ply_boot_splash_plugin_t *plugin); - void (* add_window) (ply_boot_splash_plugin_t *plugin, - ply_window_t *window); - - void (* remove_window) (ply_boot_splash_plugin_t *plugin, - ply_window_t *window); + void (* set_keyboard) (ply_boot_splash_plugin_t *plugin, + ply_keyboard_t *keyboard); + void (* unset_keyboard) (ply_boot_splash_plugin_t *plugin, + ply_keyboard_t *keyboard); + void (* add_pixel_display) (ply_boot_splash_plugin_t *plugin, + ply_pixel_display_t *display); + void (* remove_pixel_display) (ply_boot_splash_plugin_t *plugin, + ply_pixel_display_t *display); + void (* add_text_display) (ply_boot_splash_plugin_t *plugin, + ply_text_display_t *display); + void (* remove_text_display) (ply_boot_splash_plugin_t *plugin, + ply_text_display_t *display); bool (* show_splash_screen) (ply_boot_splash_plugin_t *plugin, ply_event_loop_t *loop, ply_buffer_t *boot_buffer, diff --git a/src/libplybootsplash/ply-boot-splash.c b/src/libplybootsplash/ply-boot-splash.c index 68bbaddc..72ee7f02 100644 --- a/src/libplybootsplash/ply-boot-splash.c +++ b/src/libplybootsplash/ply-boot-splash.c @@ -34,18 +34,23 @@ #include <wchar.h> #include "ply-boot-splash-plugin.h" +#include "ply-console.h" #include "ply-event-loop.h" #include "ply-list.h" #include "ply-logger.h" #include "ply-trigger.h" #include "ply-utils.h" #include "ply-progress.h" +#include "ply-keyboard.h" #include "ply-key-file.h" #ifndef UPDATES_PER_SECOND #define UPDATES_PER_SECOND 30 #endif +#define KEY_CTRL_L ('\100' ^'L') +#define KEY_CTRL_T ('\100' ^'T') +#define KEY_CTRL_V ('\100' ^'V') struct _ply_boot_splash { @@ -53,8 +58,12 @@ struct _ply_boot_splash ply_module_handle_t *module_handle; const ply_boot_splash_plugin_interface_t *plugin_interface; ply_boot_splash_plugin_t *plugin; + ply_console_t *console; + ply_keyboard_t *keyboard; ply_buffer_t *boot_buffer; ply_trigger_t *idle_trigger; + ply_list_t *pixel_displays; + ply_list_t *text_displays; char *theme_path; char *plugin_dir; @@ -66,6 +75,7 @@ struct _ply_boot_splash uint32_t is_loaded : 1; uint32_t is_shown : 1; + uint32_t should_force_text_mode : 1; }; typedef const ply_boot_splash_plugin_interface_t * @@ -77,7 +87,8 @@ static void ply_boot_splash_detach_from_event_loop (ply_boot_splash_t *splash); ply_boot_splash_t * ply_boot_splash_new (const char *theme_path, const char *plugin_dir, - ply_buffer_t *boot_buffer) + ply_buffer_t *boot_buffer, + ply_console_t *console) { ply_boot_splash_t *splash; @@ -91,22 +102,162 @@ ply_boot_splash_new (const char *theme_path, splash->is_shown = false; splash->boot_buffer = boot_buffer; + splash->console = console; + splash->pixel_displays = ply_list_new (); + splash->text_displays = ply_list_new (); return splash; } +static void +refresh_displays (ply_boot_splash_t *splash) +{ + ply_list_node_t *node; + + 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_pixel_display_draw_area (display, 0, 0, width, height); + node = next_node; + } + + node = ply_list_get_first_node (splash->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 (splash->text_displays, node); + + number_of_columns = ply_text_display_get_number_of_columns (display); + number_of_rows = ply_text_display_get_number_of_rows (display); + + ply_text_display_draw_area (display, 0, 0, + number_of_columns, + number_of_rows); + node = next_node; + } +} + +static void +on_keyboard_input (ply_boot_splash_t *splash, + const char *keyboard_input, + size_t character_size) +{ + wchar_t key; + + if ((ssize_t) mbrtowc (&key, keyboard_input, character_size, NULL) > 0) + { + switch (key) + { + case KEY_CTRL_L: + refresh_displays (splash); + return; + + case KEY_CTRL_T: + ply_trace ("toggle text mode!"); + splash->should_force_text_mode = !splash->should_force_text_mode; + ply_console_force_text_mode (splash->console, + splash->should_force_text_mode); + ply_trace ("text mode toggled!"); + return; + + case KEY_CTRL_V: + ply_trace ("toggle verbose mode!"); + ply_toggle_tracing (); + ply_trace ("verbose mode toggled!"); + return; + } + } +} + +void +ply_boot_splash_set_keyboard (ply_boot_splash_t *splash, + ply_keyboard_t *keyboard) +{ + splash->keyboard = keyboard; + + ply_keyboard_add_input_handler (keyboard, + (ply_keyboard_input_handler_t) + on_keyboard_input, splash); + + if (splash->plugin_interface->set_keyboard == NULL) + return; + + splash->plugin_interface->set_keyboard (splash->plugin, keyboard); +} + +void +ply_boot_splash_unset_keyboard (ply_boot_splash_t *splash) +{ + ply_keyboard_remove_input_handler (splash->keyboard, + (ply_keyboard_input_handler_t) + on_keyboard_input); + + if (splash->plugin_interface->set_keyboard == NULL) + return; + + splash->plugin_interface->unset_keyboard (splash->plugin, splash->keyboard); +} + +void +ply_boot_splash_add_pixel_display (ply_boot_splash_t *splash, + ply_pixel_display_t *display) +{ + ply_list_append_data (splash->pixel_displays, display); + + if (splash->plugin_interface->add_pixel_display == NULL) + return; + + splash->plugin_interface->add_pixel_display (splash->plugin, display); +} + +void +ply_boot_splash_remove_pixel_display (ply_boot_splash_t *splash, + ply_pixel_display_t *display) +{ + ply_list_remove_data (splash->pixel_displays, display); + + if (splash->plugin_interface->remove_pixel_display == NULL) + return; + + splash->plugin_interface->remove_pixel_display (splash->plugin, display); +} + void -ply_boot_splash_add_window (ply_boot_splash_t *splash, - ply_window_t *window) +ply_boot_splash_add_text_display (ply_boot_splash_t *splash, + ply_text_display_t *display) { - splash->plugin_interface->add_window (splash->plugin, window); + ply_list_append_data (splash->text_displays, display); + + if (splash->plugin_interface->add_text_display == NULL) + return; + + splash->plugin_interface->add_text_display (splash->plugin, display); } void -ply_boot_splash_remove_window (ply_boot_splash_t *splash, - ply_window_t *window) +ply_boot_splash_remove_text_display (ply_boot_splash_t *splash, + ply_text_display_t *display) { - splash->plugin_interface->remove_window (splash->plugin, window); + ply_list_remove_data (splash->text_displays, display); + + if (splash->plugin_interface->remove_pixel_display == NULL) + return; + + splash->plugin_interface->remove_text_display (splash->plugin, display); } bool @@ -223,6 +374,8 @@ ply_boot_splash_free (ply_boot_splash_t *splash) if (splash->idle_trigger != NULL) ply_trigger_free (splash->idle_trigger); + ply_list_free (splash->pixel_displays); + ply_list_free (splash->text_displays); free (splash->theme_path); free (splash->plugin_dir); free (splash); @@ -354,6 +507,8 @@ ply_boot_splash_hide (ply_boot_splash_t *splash) splash->plugin_interface->hide_splash_screen (splash->plugin, splash->loop); + ply_console_set_mode (splash->console, PLY_CONSOLE_MODE_TEXT); + splash->is_shown = false; if (splash->loop != NULL) @@ -479,7 +634,6 @@ typedef struct test_state test_state_t; struct test_state { ply_event_loop_t *loop; ply_boot_splash_t *splash; - ply_window_t *window; ply_buffer_t *buffer; }; @@ -501,6 +655,33 @@ on_quit (test_state_t *state) ply_event_loop_exit (state->loop, 0); } +static void +add_displays_to_splash_from_renderer (test_state_t *state, + ply_renderer_t *renderer) +{ + ply_list_t *heads; + ply_list_node_t *node; + + heads = ply_renderer_get_heads (renderer); + + node = ply_list_get_first_node (heads); + while (node != NULL) + { + ply_list_node_t *next_node; + ply_renderer_head_t *head; + ply_pixel_display_t *display; + + head = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (heads, node); + + display = ply_pixel_display_new (renderer, head); + + ply_boot_splash_add_pixel_display (state->splash, display); + + node = next_node; + } +} + int main (int argc, char **argv) @@ -509,6 +690,11 @@ main (int argc, test_state_t state; char *tty_name; const char *theme_path; + ply_text_display_t *text_display; + ply_renderer_t *renderer; + ply_console_t *console; + ply_terminal_t *terminal; + ply_keyboard_t *keyboard; exit_code = 0; @@ -524,29 +710,51 @@ main (int argc, else tty_name = strdup("tty0"); - state.window = ply_window_new (tty_name); + console = ply_console_new (); + + if (!ply_console_open (console)) + { + perror ("could not open console"); + return errno; + } + + terminal = ply_terminal_new (tty_name); + + if (!ply_terminal_open (terminal)) + { + perror ("could not open tty"); + return errno; + } + + renderer = ply_renderer_new (NULL, terminal, console); free(tty_name); - ply_window_attach_to_event_loop (state.window, state.loop); - if (!ply_window_open (state.window)) + if (!ply_renderer_open (renderer)) { - perror ("could not open terminal"); + perror ("could not open renderer /dev/fb"); + ply_renderer_free (renderer); return errno; } - ply_window_attach_to_event_loop (state.window, state.loop); - ply_window_add_escape_handler (state.window, - (ply_window_escape_handler_t) on_quit, &state); + keyboard = ply_keyboard_new_for_renderer (renderer); + ply_keyboard_add_escape_handler (keyboard, + (ply_keyboard_escape_handler_t) on_quit, &state); state.buffer = ply_buffer_new (); - state.splash = ply_boot_splash_new (theme_path, PLYMOUTH_PLUGIN_PATH, state.buffer); + state.splash = ply_boot_splash_new (theme_path, PLYMOUTH_PLUGIN_PATH, state.buffer, console); + if (!ply_boot_splash_load (state.splash)) { perror ("could not load splash screen"); return errno; } - ply_boot_splash_add_window (state.splash, state.window); + ply_boot_splash_set_keyboard (state.splash, keyboard); + add_displays_to_splash_from_renderer (&state, renderer); + + text_display = ply_text_display_new (terminal, console); + ply_boot_splash_add_text_display (state.splash, text_display); + ply_boot_splash_attach_to_event_loop (state.splash, state.loop); if (!ply_boot_splash_show (state.splash, PLY_BOOT_SPLASH_MODE_BOOT_UP)) @@ -561,7 +769,6 @@ main (int argc, on_timeout, state.splash); exit_code = ply_event_loop_run (state.loop); - ply_window_free (state.window); ply_boot_splash_free (state.splash); ply_buffer_free (state.buffer); diff --git a/src/libplybootsplash/ply-boot-splash.h b/src/libplybootsplash/ply-boot-splash.h index 90cd5853..4cb61b75 100644 --- a/src/libplybootsplash/ply-boot-splash.h +++ b/src/libplybootsplash/ply-boot-splash.h @@ -27,9 +27,13 @@ #include <unistd.h> #include "ply-event-loop.h" -#include "ply-window.h" #include "ply-buffer.h" +#include "ply-console.h" +#include "ply-keyboard.h" +#include "ply-pixel-display.h" +#include "ply-text-display.h" #include "ply-progress.h" + #include "ply-boot-splash-plugin.h" typedef struct _ply_boot_splash ply_boot_splash_t; @@ -39,13 +43,21 @@ typedef void (* ply_boot_splash_on_idle_handler_t) (void *user_data); #ifndef PLY_HIDE_FUNCTION_DECLARATIONS ply_boot_splash_t *ply_boot_splash_new (const char *theme_path, const char *plugin_dir, - ply_buffer_t *boot_buffer); + ply_buffer_t *boot_buffer, + ply_console_t *console); bool ply_boot_splash_load (ply_boot_splash_t *splash); void ply_boot_splash_unload (ply_boot_splash_t *splash); -void ply_boot_splash_add_window (ply_boot_splash_t *splash, - ply_window_t *window); -void ply_boot_splash_remove_window (ply_boot_splash_t *splash, - ply_window_t *window); +void ply_boot_splash_set_keyboard (ply_boot_splash_t *splash, + ply_keyboard_t *keyboard); +void ply_boot_splash_unset_keyboard (ply_boot_splash_t *splash); +void ply_boot_splash_add_pixel_display (ply_boot_splash_t *splash, + ply_pixel_display_t *display); +void ply_boot_splash_remove_pixel_display (ply_boot_splash_t *splash, + ply_pixel_display_t *display); +void ply_boot_splash_add_text_display (ply_boot_splash_t *splash, + ply_text_display_t *display); +void ply_boot_splash_remove_text_display (ply_boot_splash_t *splash, + ply_text_display_t *display); void ply_boot_splash_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/libplybootsplash/ply-console.c b/src/libplybootsplash/ply-console.c new file mode 100644 index 00000000..7fb92980 --- /dev/null +++ b/src/libplybootsplash/ply-console.c @@ -0,0 +1,406 @@ +/* ply-console.c - console APIs + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: Ray Strode <rstrode@redhat.com> + */ +#include "config.h" +#include "ply-console.h" + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <termios.h> +#include <unistd.h> +#include <wchar.h> + +#include <linux/kd.h> +#include <linux/major.h> +#include <linux/vt.h> + +#include "ply-event-loop.h" +#include "ply-list.h" +#include "ply-logger.h" +#include "ply-utils.h" + +#ifndef TEXT_PALETTE_SIZE +#define TEXT_PALETTE_SIZE 48 +#endif + +typedef struct +{ + ply_console_active_vt_changed_handler_t handler; + void *user_data; +} ply_console_active_vt_changed_closure_t; + +struct _ply_console +{ + ply_event_loop_t *loop; + + int fd; + int active_vt; + int next_active_vt; + + ply_list_t *vt_change_closures; + ply_fd_watch_t *fd_watch; + + uint32_t is_open : 1; + uint32_t is_watching_for_vt_changes : 1; + uint32_t should_force_text_mode : 1; +}; + +static bool ply_console_open_device (ply_console_t *console); + +ply_console_t * +ply_console_new (void) +{ + ply_console_t *console; + + console = calloc (1, sizeof (ply_console_t)); + + console->loop = ply_event_loop_get_default (); + console->vt_change_closures = ply_list_new (); + console->fd = -1; + + return console; +} + +static void +ply_console_look_up_active_vt (ply_console_t *console) +{ + struct vt_stat console_state = { 0 }; + + if (ioctl (console->fd, VT_GETSTATE, &console_state) < 0) + return; + + console->active_vt = console_state.v_active; +} + +void +ply_console_set_mode (ply_console_t *console, + ply_console_mode_t mode) +{ + + assert (console != NULL); + assert (mode == PLY_CONSOLE_MODE_TEXT || mode == PLY_CONSOLE_MODE_GRAPHICS); + + if (console->should_force_text_mode) + mode = PLY_CONSOLE_MODE_TEXT; + + switch (mode) + { + case PLY_CONSOLE_MODE_TEXT: + if (ioctl (console->fd, KDSETMODE, KD_TEXT) < 0) + return; + break; + + case PLY_CONSOLE_MODE_GRAPHICS: + if (ioctl (console->fd, KDSETMODE, KD_GRAPHICS) < 0) + return; + break; + } +} + +void +ply_console_force_text_mode (ply_console_t *console, + bool should_force) +{ + console->should_force_text_mode = should_force; +} + +static void +on_tty_disconnected (ply_console_t *console) +{ + ply_trace ("console tty disconnected (fd %d)", console->fd); + console->fd_watch = NULL; + console->fd = -1; + + ply_trace ("trying to reopen console"); + ply_console_open_device (console); +} + +static void +do_active_vt_changed (ply_console_t *console) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (console->vt_change_closures); + while (node != NULL) + { + ply_console_active_vt_changed_closure_t *closure; + ply_list_node_t *next_node; + + closure = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (console->vt_change_closures, node); + + if (closure->handler != NULL) + closure->handler (closure->user_data, console); + + node = next_node; + } +} + +static void +on_leave_vt (ply_console_t *console) +{ + ioctl (console->fd, VT_RELDISP, 1); + + if (console->next_active_vt > 0) + { + ioctl (console->fd, VT_WAITACTIVE, console->next_active_vt); + console->next_active_vt = 0; + } + + ply_console_look_up_active_vt (console); + do_active_vt_changed (console); +} + +static void +on_enter_vt (ply_console_t *console) +{ + ioctl (console->fd, VT_RELDISP, VT_ACKACQ); + + ply_console_look_up_active_vt (console); + do_active_vt_changed (console); +} + +static void +ply_console_watch_for_vt_changes (ply_console_t *console) +{ + assert (console != NULL); + assert (console->fd >= 0); + + struct vt_mode mode = { 0 }; + + if (console->is_watching_for_vt_changes) + return; + + mode.mode = VT_PROCESS; + mode.relsig = SIGUSR1; + mode.acqsig = SIGUSR2; + + if (!ioctl (console->fd, VT_SETMODE, &mode) < 0) + return; + + ply_event_loop_watch_signal (console->loop, + SIGUSR1, + (ply_event_handler_t) + on_leave_vt, console); + + ply_event_loop_watch_signal (console->loop, + SIGUSR2, + (ply_event_handler_t) + on_enter_vt, console); + + console->is_watching_for_vt_changes = true; +} + +static void +ply_console_stop_watching_for_vt_changes (ply_console_t *console) +{ + struct vt_mode mode = { 0 }; + + if (!console->is_watching_for_vt_changes) + return; + + console->is_watching_for_vt_changes = false; + + ply_event_loop_stop_watching_signal (console->loop, SIGUSR1); + ply_event_loop_stop_watching_signal (console->loop, SIGUSR2); + + mode.mode = VT_AUTO; + ioctl (console->fd, VT_SETMODE, &mode); +} + +static bool +ply_console_open_device (ply_console_t *console) +{ + assert (console != NULL); + assert (console->fd < 0); + assert (console->fd_watch == NULL); + + console->fd = open ("/dev/tty0", O_RDWR | O_NOCTTY); + + if (console->fd < 0) + return false; + + console->fd_watch = ply_event_loop_watch_fd (console->loop, console->fd, + PLY_EVENT_LOOP_FD_STATUS_NONE, + (ply_event_handler_t) NULL, + (ply_event_handler_t) on_tty_disconnected, + console); + + ply_console_look_up_active_vt (console); + + return true; +} + +bool +ply_console_open (ply_console_t *console) +{ + assert (console != NULL); + + if (!ply_console_open_device (console)) + { + ply_trace ("could not open console: %m"); + return false; + } + + ply_console_watch_for_vt_changes (console); + + console->is_open = true; + + return true; +} + + +int +ply_console_get_fd (ply_console_t *console) +{ + return console->fd; +} + +bool +ply_console_is_open (ply_console_t *console) +{ + return console->is_open; +} + +void +ply_console_close (ply_console_t *console) +{ + console->is_open = false; + + ply_console_stop_watching_for_vt_changes (console); + + if (console->fd_watch != NULL) + { + ply_trace ("stop watching tty fd"); + ply_event_loop_stop_watching_fd (console->loop, console->fd_watch); + console->fd_watch = NULL; + } + + close (console->fd); + console->fd = -1; +} + +static void +free_vt_change_closures (ply_console_t *console) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (console->vt_change_closures); + while (node != NULL) + { + ply_console_active_vt_changed_closure_t *closure; + ply_list_node_t *next_node; + + closure = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (console->vt_change_closures, node); + + free (closure); + node = next_node; + } + ply_list_free (console->vt_change_closures); +} + +void +ply_console_free (ply_console_t *console) +{ + if (console == NULL) + return; + + ply_console_close (console); + + free_vt_change_closures (console); + free (console); +} + +int +ply_console_get_active_vt (ply_console_t *console) +{ + return console->active_vt; +} + +bool +ply_console_set_active_vt (ply_console_t *console, + int vt_number) +{ + assert (console != NULL); + assert (vt_number > 0); + + if (vt_number == console->active_vt) + return true; + + if (ioctl (console->fd, VT_ACTIVATE, vt_number) < 0) + return false; + + console->next_active_vt = vt_number; + + return true; +} + +void +ply_console_watch_for_active_vt_change (ply_console_t *console, + ply_console_active_vt_changed_handler_t active_vt_changed_handler, + void *user_data) +{ + ply_console_active_vt_changed_closure_t *closure; + + closure = calloc (1, sizeof (*closure)); + closure->handler = active_vt_changed_handler; + closure->user_data = user_data; + + ply_list_append_data (console->vt_change_closures, closure); +} + +void +ply_console_stop_watching_for_active_vt_change (ply_console_t *console, + ply_console_active_vt_changed_handler_t active_vt_changed_handler, + void *user_data) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (console->vt_change_closures); + while (node != NULL) + { + ply_console_active_vt_changed_closure_t *closure; + ply_list_node_t *next_node; + + closure = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (console->vt_change_closures, node); + + if (closure->handler == active_vt_changed_handler && + closure->user_data == user_data) + { + free (closure); + ply_list_remove_node (console->vt_change_closures, node); + } + + node = next_node; + } +} + +/* 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/libplybootsplash/ply-console.h b/src/libplybootsplash/ply-console.h new file mode 100644 index 00000000..36263bbc --- /dev/null +++ b/src/libplybootsplash/ply-console.h @@ -0,0 +1,70 @@ +/* ply-console.h - APIs for consoleing text + * + * 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_CONSOLE_H +#define PLY_CONSOLE_H + +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <unistd.h> + +typedef struct _ply_console ply_console_t; +typedef void (* ply_console_active_vt_changed_handler_t) (void *user_data, + ply_console_t *console); + +typedef enum +{ + PLY_CONSOLE_MODE_TEXT, + PLY_CONSOLE_MODE_GRAPHICS +} ply_console_mode_t; + +#ifndef PLY_HIDE_FUNCTION_DECLARATIONS +ply_console_t *ply_console_new (void); + +void ply_console_free (ply_console_t *console); + +bool ply_console_open (ply_console_t *console); +bool ply_console_is_open (ply_console_t *console); +void ply_console_close (ply_console_t *console); + +void ply_console_set_mode (ply_console_t *console, + ply_console_mode_t mode); + +void ply_console_force_text_mode (ply_console_t *console, + bool should_force); + +int ply_console_get_fd (ply_console_t *console); +int ply_console_get_active_vt (ply_console_t *console); +bool ply_console_set_active_vt (ply_console_t *console, + int vt_number); + +void ply_console_watch_for_active_vt_change (ply_console_t *console, + ply_console_active_vt_changed_handler_t active_vt_changed_handler, + void *user_data); +void ply_console_stop_watching_for_active_vt_change (ply_console_t *console, + ply_console_active_vt_changed_handler_t active_vt_changed_handler, + void *user_data); + +#endif + +#endif /* PLY_CONSOLE_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/libplybootsplash/ply-entry.c b/src/libplybootsplash/ply-entry.c index d59d9207..1940b368 100644 --- a/src/libplybootsplash/ply-entry.c +++ b/src/libplybootsplash/ply-entry.c @@ -45,10 +45,10 @@ #include "ply-array.h" #include "ply-label.h" #include "ply-logger.h" -#include "ply-frame-buffer.h" #include "ply-image.h" +#include "ply-pixel-buffer.h" +#include "ply-pixel-display.h" #include "ply-utils.h" -#include "ply-window.h" #include <linux/kd.h> @@ -60,9 +60,8 @@ struct _ply_entry { ply_event_loop_t *loop; - ply_window_t *window; - ply_frame_buffer_t *frame_buffer; - ply_frame_buffer_area_t area; + ply_pixel_display_t *display; + ply_rectangle_t area; ply_image_t *text_field_image; ply_image_t *bullet_image; ply_label_t *label; @@ -148,33 +147,36 @@ ply_entry_load (ply_entry_t *entry) } static void -erase_entry_area (ply_entry_t *entry) +ply_entry_draw (ply_entry_t *entry) { - ply_window_erase_area (entry->window, - entry->area.x, entry->area.y, - entry->area.width, entry->area.height); + ply_pixel_display_draw_area (entry->display, + entry->area.x, + entry->area.y, + entry->area.width, + entry->area.height); } void -ply_entry_draw (ply_entry_t *entry) +ply_entry_draw_area (ply_entry_t *entry, + ply_pixel_buffer_t *pixel_buffer, + long x, + long y, + unsigned long width, + unsigned long height) { - ply_frame_buffer_area_t bullet_area; + ply_rectangle_t bullet_area; uint32_t *text_field_data, *bullet_data; int i, number_of_visible_bullets; if (entry->is_hidden) return; - ply_frame_buffer_pause_updates (entry->frame_buffer); - text_field_data = ply_image_get_data (entry->text_field_image); - erase_entry_area (entry); - - ply_frame_buffer_fill_with_argb32_data (entry->frame_buffer, + ply_pixel_buffer_fill_with_argb32_data (pixel_buffer, &entry->area, 0, 0, text_field_data); - + if (entry->is_password) { bullet_data = ply_image_get_data (entry->bullet_image); @@ -193,7 +195,7 @@ ply_entry_draw (ply_entry_t *entry) bullet_area.x = entry->area.x; bullet_area.y = entry->area.y + entry->area.height / 2.0 - bullet_area.height / 2.0; - ply_frame_buffer_fill_with_argb32_data (entry->frame_buffer, + ply_pixel_buffer_fill_with_argb32_data (pixel_buffer, &bullet_area, bullet_area.width / 2.0, 0, bullet_data); } @@ -203,7 +205,7 @@ ply_entry_draw (ply_entry_t *entry) bullet_area.x = entry->area.x + i * bullet_area.width + bullet_area.width / 2.0; bullet_area.y = entry->area.y + entry->area.height / 2.0 - bullet_area.height / 2.0; - ply_frame_buffer_fill_with_argb32_data (entry->frame_buffer, + ply_pixel_buffer_fill_with_argb32_data (pixel_buffer, &bullet_area, 0, 0, bullet_data); } @@ -211,10 +213,10 @@ ply_entry_draw (ply_entry_t *entry) else { ply_label_set_text (entry->label, entry->text); - ply_label_show (entry->label, entry->window, entry->area.x, entry->area.y); - + ply_label_draw_area (entry->label, pixel_buffer, + entry->area.x, entry->area.y, + entry->area.width, entry->area.height); } - ply_frame_buffer_unpause_updates (entry->frame_buffer); } void @@ -266,18 +268,17 @@ ply_entry_set_text (ply_entry_t *entry, const char* text) } void -ply_entry_show (ply_entry_t *entry, - ply_event_loop_t *loop, - ply_window_t *window, - long x, - long y) +ply_entry_show (ply_entry_t *entry, + ply_event_loop_t *loop, + ply_pixel_display_t *display, + long x, + long y) { assert (entry != NULL); assert (entry->loop == NULL); entry->loop = loop; - entry->window = window; - entry->frame_buffer = ply_window_get_frame_buffer (window);; + entry->display = display; entry->area.x = x; entry->area.y = y; @@ -290,13 +291,11 @@ ply_entry_show (ply_entry_t *entry, void ply_entry_hide (ply_entry_t *entry) { - erase_entry_area (entry); + entry->is_hidden = true; + ply_entry_draw (entry); - entry->frame_buffer = NULL; - entry->window = NULL; + entry->display = NULL; entry->loop = NULL; - - entry->is_hidden = true; } bool diff --git a/src/libplybootsplash/ply-entry.h b/src/libplybootsplash/ply-entry.h index 76bf2adb..658e2db2 100644 --- a/src/libplybootsplash/ply-entry.h +++ b/src/libplybootsplash/ply-entry.h @@ -27,8 +27,8 @@ #include <unistd.h> #include "ply-event-loop.h" -#include "ply-frame-buffer.h" -#include "ply-window.h" +#include "ply-pixel-buffer.h" +#include "ply-pixel-display.h" typedef struct _ply_entry ply_entry_t; @@ -39,11 +39,16 @@ bool ply_entry_load (ply_entry_t *entry); void ply_entry_show (ply_entry_t *entry, ply_event_loop_t *loop, - ply_window_t *window, + ply_pixel_display_t *display, long x, long y); void ply_entry_hide (ply_entry_t *entry); -void ply_entry_draw (ply_entry_t *entry); +void ply_entry_draw_area (ply_entry_t *entry, + ply_pixel_buffer_t *buffer, + long x, + long y, + unsigned long width, + unsigned long height); bool ply_entry_is_hidden (ply_entry_t *entry); long ply_entry_get_width (ply_entry_t *entry); diff --git a/src/libplybootsplash/ply-image.c b/src/libplybootsplash/ply-image.c index 812313c5..94bc6afa 100644 --- a/src/libplybootsplash/ply-image.c +++ b/src/libplybootsplash/ply-image.c @@ -400,150 +400,4 @@ ply_image_rotate (ply_image_t *image, return new_image; } -#ifdef PLY_IMAGE_ENABLE_TEST - -#include "ply-frame-buffer.h" - -#include <math.h> -#include <signal.h> -#include <stdio.h> -#include <sys/ioctl.h> -#include <sys/time.h> -#include <values.h> - -#include <linux/kd.h> - -#ifndef FRAMES_PER_SECOND -#define FRAMES_PER_SECOND 50 -#endif - -static int console_fd; - -static bool -hide_cursor (void) -{ - static const char invisible_cursor[] = "\033[?25l\033[?1c"; - - if (write (STDOUT_FILENO, invisible_cursor, - sizeof (invisible_cursor) - 1) != sizeof (invisible_cursor) - 1) - return false; - - return true; -} - -static double -get_current_time (void) -{ - const double microseconds_per_second = 1000000.0; - double timestamp; - struct timeval now = { 0L, /* zero-filled */ }; - - gettimeofday (&now, NULL); - timestamp = ((microseconds_per_second * now.tv_sec) + now.tv_usec) / - microseconds_per_second; - - return timestamp; -} - -double start_time = 0.0; -int num_frames = 0; - -static void -animate_at_time (ply_frame_buffer_t *buffer, - ply_image_t *image, - double time) -{ - ply_frame_buffer_area_t area; - uint32_t *data; - long width, height; - static double last_opacity = 0.0; - double opacity = 0.0; - - data = ply_image_get_data (image); - width = ply_image_get_width (image); - height = ply_image_get_height (image); - - ply_frame_buffer_get_size (buffer, &area); - area.x = (area.width / 2) - (width / 2); - area.y = (area.height / 2) - (height / 2); - area.width = width; - area.height = height; - - opacity = .5 * sin ((time / 4) * (2 * M_PI)) + .8; - opacity = CLAMP (opacity, 0, 1.0); - - num_frames++; - if (fabs (opacity - last_opacity) <= DBL_MIN) - return; - - last_opacity = opacity; - - ply_frame_buffer_pause_updates (buffer); - ply_frame_buffer_fill_with_color (buffer, &area, 0.1, 0.1, .7, 1.0); - ply_frame_buffer_fill_with_argb32_data_at_opacity (buffer, &area, - 0, 0, data, opacity); - ply_frame_buffer_unpause_updates (buffer); - - if (time > 10.0) - ioctl (console_fd, KDSETMODE, KD_TEXT); -} - -int -main (int argc, - char **argv) -{ - ply_image_t *image; - ply_frame_buffer_t *buffer; - int exit_code; - - exit_code = 0; - - hide_cursor (); - - if (argc == 1) - image = ply_image_new ("booting.png"); - else - image = ply_image_new (argv[1]); - - if (!ply_image_load (image)) - { - exit_code = errno; - perror ("could not load image"); - return exit_code; - } - - console_fd = open ("/dev/tty0", O_RDWR); - - buffer = ply_frame_buffer_new (NULL); - - if (!ply_frame_buffer_open (buffer)) - { - exit_code = errno; - perror ("could not open framebuffer"); - return exit_code; - } - - start_time = get_current_time (); - ply_frame_buffer_fill_with_color (buffer, NULL, 0.1, 0.1, .7, 1.0); - while ("we want to see ad-hoc animations") - { - long sleep_time; - double now; - - now = get_current_time (); - animate_at_time (buffer, image, now - start_time); - sleep_time = 1000000 / FRAMES_PER_SECOND; - sleep_time = MAX (sleep_time - ((get_current_time () - now) / 1000000), - 10000); - usleep (sleep_time); - } - ply_frame_buffer_close (buffer); - ply_frame_buffer_free (buffer); - - ply_image_free (image); - - return exit_code; -} - -#endif /* PLY_IMAGE_ENABLE_TEST */ /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/libplybootsplash/ply-keyboard.c b/src/libplybootsplash/ply-keyboard.c new file mode 100644 index 00000000..375ddd54 --- /dev/null +++ b/src/libplybootsplash/ply-keyboard.c @@ -0,0 +1,583 @@ +/* ply-keyboard.h - APIs for putting up a keyboard screen + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: Ray Strode <rstrode@redhat.com> + */ +#include "config.h" +#include "ply-keyboard.h" + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <wchar.h> + +#include "ply-buffer.h" +#include "ply-event-loop.h" +#include "ply-list.h" +#include "ply-logger.h" +#include "ply-renderer.h" +#include "ply-terminal.h" +#include "ply-utils.h" + +#define KEY_CTRL_U ('\100' ^'U') +#define KEY_CTRL_W ('\100' ^'W') +#define KEY_CTRL_V ('\100' ^'V') +#define KEY_ESCAPE ('\100' ^'[') +#define KEY_RETURN '\r' +#define KEY_BACKSPACE '\177' + +typedef void (* ply_keyboard_handler_t) (void *); + +typedef struct +{ + ply_keyboard_handler_t function; + void *user_data; +} ply_keyboard_closure_t; + +typedef enum +{ + PLY_KEYBOARD_PROVIDER_TYPE_TERMINAL, + PLY_KEYBOARD_PROVIDER_TYPE_RENDERER +} ply_keyboard_provider_type_t; + +typedef struct +{ + ply_terminal_t *terminal; + ply_fd_watch_t *input_watch; + ply_buffer_t *key_buffer; +} ply_keyboard_terminal_provider_t; + +typedef struct +{ + ply_renderer_t *renderer; + ply_renderer_input_source_t *input_source; +} ply_keyboard_renderer_provider_t; + +typedef union { + ply_keyboard_renderer_provider_t *if_renderer; + ply_keyboard_terminal_provider_t *if_terminal; +} ply_keyboard_provider_t; + +struct _ply_keyboard +{ + ply_event_loop_t *loop; + + ply_keyboard_provider_type_t provider_type; + ply_keyboard_provider_t provider; + + ply_buffer_t *line_buffer; + + ply_list_t *keyboard_input_handler_list; + ply_list_t *backspace_handler_list; + ply_list_t *escape_handler_list; + ply_list_t *enter_handler_list; +}; + +ply_keyboard_t * +ply_keyboard_new_for_terminal (ply_terminal_t *terminal) +{ + ply_keyboard_t *keyboard; + + keyboard = calloc (1, sizeof (ply_keyboard_t)); + keyboard->line_buffer = ply_buffer_new (); + keyboard->keyboard_input_handler_list = ply_list_new (); + keyboard->backspace_handler_list = ply_list_new (); + keyboard->escape_handler_list = ply_list_new (); + keyboard->enter_handler_list = ply_list_new (); + keyboard->provider_type = PLY_KEYBOARD_PROVIDER_TYPE_TERMINAL; + keyboard->provider.if_terminal = calloc (1, sizeof (ply_keyboard_terminal_provider_t)); + keyboard->provider.if_terminal->terminal = terminal; + keyboard->provider.if_terminal->key_buffer = ply_buffer_new (); + + keyboard->loop = ply_event_loop_get_default (); + + return keyboard; +} + +ply_keyboard_t * +ply_keyboard_new_for_renderer (ply_renderer_t *renderer) +{ + ply_keyboard_t *keyboard; + ply_renderer_input_source_t *input_source; + + keyboard = calloc (1, sizeof (ply_keyboard_t)); + keyboard->line_buffer = ply_buffer_new (); + keyboard->keyboard_input_handler_list = ply_list_new (); + keyboard->backspace_handler_list = ply_list_new (); + keyboard->escape_handler_list = ply_list_new (); + keyboard->enter_handler_list = ply_list_new (); + keyboard->provider_type = PLY_KEYBOARD_PROVIDER_TYPE_RENDERER; + keyboard->provider.if_renderer = calloc (1, sizeof (ply_keyboard_renderer_provider_t)); + keyboard->provider.if_renderer->renderer = renderer; + + input_source = ply_renderer_get_input_source (renderer); + + keyboard->provider.if_renderer->input_source = input_source; + + keyboard->loop = ply_event_loop_get_default (); + + return keyboard; +} + +static void +process_backspace (ply_keyboard_t *keyboard) +{ + size_t bytes_to_remove; + ssize_t previous_character_size; + const char *bytes; + size_t size; + ply_list_node_t *node; + + bytes = ply_buffer_get_bytes (keyboard->line_buffer); + size = ply_buffer_get_size (keyboard->line_buffer); + + bytes_to_remove = MIN (size, PLY_UTF8_CHARACTER_SIZE_MAX); + while ((previous_character_size = ply_utf8_character_get_size (bytes + size - bytes_to_remove, bytes_to_remove)) < (ssize_t) bytes_to_remove) + { + if (previous_character_size > 0) + bytes_to_remove -= previous_character_size; + else + bytes_to_remove--; + } + + if (bytes_to_remove <= size) + ply_buffer_remove_bytes_at_end (keyboard->line_buffer, bytes_to_remove); + + for (node = ply_list_get_first_node(keyboard->backspace_handler_list); + node; node = ply_list_get_next_node(keyboard->backspace_handler_list, node)) + { + ply_keyboard_closure_t *closure = ply_list_node_get_data (node); + ply_keyboard_backspace_handler_t backspace_handler = + (ply_keyboard_backspace_handler_t) closure->function; + backspace_handler (closure->user_data); + } +} + +static void +process_line_erase (ply_keyboard_t *keyboard) +{ + size_t size; + + while ((size = ply_buffer_get_size (keyboard->line_buffer)) > 0) + process_backspace (keyboard); +} + +static void +process_keyboard_input (ply_keyboard_t *keyboard, + const char *keyboard_input, + size_t character_size) +{ + wchar_t key; + ply_list_node_t *node; + + if ((ssize_t) mbrtowc (&key, keyboard_input, character_size, NULL) > 0) + { + switch (key) + { + case KEY_CTRL_U: + case KEY_CTRL_W: + ply_trace ("erase line!"); + process_line_erase (keyboard); + return; + + case KEY_CTRL_V: + ply_trace ("toggle verbose mode!"); + ply_toggle_tracing (); + ply_trace ("verbose mode toggled!"); + return; + + case KEY_ESCAPE: + ply_trace ("escape key!"); + for (node = ply_list_get_first_node(keyboard->escape_handler_list); + node; node = ply_list_get_next_node(keyboard->escape_handler_list, node)) + { + ply_keyboard_closure_t *closure = ply_list_node_get_data (node); + ply_keyboard_escape_handler_t escape_handler = (ply_keyboard_escape_handler_t) closure->function; + escape_handler (closure->user_data); + } + + ply_trace ("end escape key handler"); + return; + + case KEY_BACKSPACE: + ply_trace ("backspace key!"); + process_backspace (keyboard); + return; + + case KEY_RETURN: + ply_trace ("return key!"); + + for (node = ply_list_get_first_node(keyboard->enter_handler_list); + node; node = ply_list_get_next_node(keyboard->enter_handler_list, node)) + { + ply_keyboard_closure_t *closure = ply_list_node_get_data (node); + ply_keyboard_enter_handler_t enter_handler = (ply_keyboard_enter_handler_t) closure->function; + enter_handler (closure->user_data, ply_buffer_get_bytes (keyboard->line_buffer)); + } + ply_buffer_clear (keyboard->line_buffer); + return; + + default: + ply_buffer_append_bytes (keyboard->line_buffer, + keyboard_input, character_size); + break; + } + } + + for (node = ply_list_get_first_node(keyboard->keyboard_input_handler_list); + node; node = ply_list_get_next_node(keyboard->keyboard_input_handler_list, node)) + { + ply_keyboard_closure_t *closure = ply_list_node_get_data (node); + ply_keyboard_input_handler_t keyboard_input_handler = + (ply_keyboard_input_handler_t) closure->function; + + keyboard_input_handler (closure->user_data, + keyboard_input, character_size); + } +} + +static void +on_key_event (ply_keyboard_t *keyboard, + ply_buffer_t *buffer) +{ + const char *bytes; + size_t size, i; + + bytes = ply_buffer_get_bytes (buffer); + size = ply_buffer_get_size (buffer); + + i = 0; + while (i < size) + { + ssize_t character_size; + char *keyboard_input; + + character_size = (ssize_t) ply_utf8_character_get_size (bytes + i, size - i); + + if (character_size < 0) + break; + + /* If we're at a NUL character walk through it + */ + if (character_size == 0) + { + i++; + continue; + } + + keyboard_input = strndup (bytes + i, character_size); + + process_keyboard_input (keyboard, keyboard_input, character_size); + + i += character_size; + + free (keyboard_input); + } + + if (i > 0) + ply_buffer_remove_bytes (buffer, i); +} + +static bool +ply_keyboard_watch_for_renderer_input (ply_keyboard_t *keyboard) +{ + assert (keyboard != NULL); + + if (!ply_renderer_open_input_source (keyboard->provider.if_renderer->renderer, + keyboard->provider.if_renderer->input_source)) + return false; + + ply_renderer_set_handler_for_input_source (keyboard->provider.if_renderer->renderer, + keyboard->provider.if_renderer->input_source, + (ply_renderer_input_source_handler_t) + on_key_event, + keyboard); + return true; +} + +static void +ply_keyboard_stop_watching_for_renderer_input (ply_keyboard_t *keyboard) +{ + ply_renderer_set_handler_for_input_source (keyboard->provider.if_renderer->renderer, + keyboard->provider.if_renderer->input_source, + (ply_renderer_input_source_handler_t) + NULL, NULL); + + ply_renderer_close_input_source (keyboard->provider.if_renderer->renderer, + keyboard->provider.if_renderer->input_source); +} + +static void +on_terminal_data (ply_keyboard_t *keyboard) +{ + int terminal_fd; + + terminal_fd = ply_terminal_get_fd (keyboard->provider.if_terminal->terminal); + ply_buffer_append_from_fd (keyboard->provider.if_terminal->key_buffer, + terminal_fd); + on_key_event (keyboard, keyboard->provider.if_terminal->key_buffer); +} + +static bool +ply_keyboard_watch_for_terminal_input (ply_keyboard_t *keyboard) +{ + int terminal_fd; + + assert (keyboard != NULL); + + terminal_fd = ply_terminal_get_fd (keyboard->provider.if_terminal->terminal); + keyboard->provider.if_terminal->input_watch = ply_event_loop_watch_fd (keyboard->loop, terminal_fd, PLY_EVENT_LOOP_FD_STATUS_HAS_DATA, + (ply_event_handler_t) on_terminal_data, NULL, keyboard); + + return true; +} + +static void +ply_keyboard_stop_watching_for_terminal_input (ply_keyboard_t *keyboard) +{ + ply_event_loop_stop_watching_fd (keyboard->loop, + keyboard->provider.if_terminal->input_watch); + keyboard->provider.if_terminal->input_watch = NULL; +} + +bool +ply_keyboard_watch_for_input (ply_keyboard_t *keyboard) +{ + assert (keyboard != NULL); + + switch (keyboard->provider_type) + { + case PLY_KEYBOARD_PROVIDER_TYPE_RENDERER: + return ply_keyboard_watch_for_renderer_input (keyboard); + + case PLY_KEYBOARD_PROVIDER_TYPE_TERMINAL: + return ply_keyboard_watch_for_terminal_input (keyboard); + } + + return false; +} + +void +ply_keyboard_stop_watching_for_input (ply_keyboard_t *keyboard) +{ + assert (keyboard != NULL); + + switch (keyboard->provider_type) + { + case PLY_KEYBOARD_PROVIDER_TYPE_RENDERER: + ply_keyboard_stop_watching_for_renderer_input (keyboard); + break; + + case PLY_KEYBOARD_PROVIDER_TYPE_TERMINAL: + ply_keyboard_stop_watching_for_terminal_input (keyboard); + break; + } + +} + +void +ply_keyboard_free (ply_keyboard_t *keyboard) +{ + if (keyboard == NULL) + return; + + ply_keyboard_stop_watching_for_input (keyboard); + + ply_buffer_free (keyboard->line_buffer); + + if (keyboard->provider_type == PLY_KEYBOARD_PROVIDER_TYPE_RENDERER) + { + free (keyboard->provider.if_renderer); + } + else + { + ply_buffer_free (keyboard->provider.if_terminal->key_buffer); + free (keyboard->provider.if_terminal); + } + + free (keyboard); +} + +static ply_keyboard_closure_t * +ply_keyboard_closure_new (ply_keyboard_handler_t function, + void *user_data) +{ + ply_keyboard_closure_t *closure = calloc (1, sizeof (ply_keyboard_closure_t)); + closure->function = function; + closure->user_data = user_data; + return closure; +} + + +static void +ply_keyboard_closure_free (ply_keyboard_closure_t *closure) +{ + free (closure); +} + +void +ply_keyboard_add_input_handler (ply_keyboard_t *keyboard, + ply_keyboard_input_handler_t input_handler, + void *user_data) +{ + ply_keyboard_closure_t *closure; + + assert (keyboard != NULL); + + closure = ply_keyboard_closure_new ((ply_keyboard_handler_t) input_handler, + user_data); + ply_list_append_data (keyboard->keyboard_input_handler_list, closure); +} + +void +ply_keyboard_remove_input_handler (ply_keyboard_t *keyboard, + ply_keyboard_input_handler_t input_handler) +{ + ply_list_node_t *node; + + assert (keyboard != NULL); + + for (node = ply_list_get_first_node(keyboard->keyboard_input_handler_list); + node; node = ply_list_get_next_node(keyboard->keyboard_input_handler_list, node)) + { + ply_keyboard_closure_t *closure = ply_list_node_get_data (node); + if ((ply_keyboard_input_handler_t) closure->function == input_handler) + { + ply_keyboard_closure_free (closure); + ply_list_remove_node (keyboard->keyboard_input_handler_list, node); + return; + } + } +} + +void +ply_keyboard_add_backspace_handler (ply_keyboard_t *keyboard, + ply_keyboard_backspace_handler_t backspace_handler, + void *user_data) +{ + ply_keyboard_closure_t *closure; + + assert (keyboard != NULL); + + closure = ply_keyboard_closure_new ((ply_keyboard_handler_t) backspace_handler, + user_data); + ply_list_append_data (keyboard->backspace_handler_list, closure); +} + + +void +ply_keyboard_remove_backspace_handler (ply_keyboard_t *keyboard, + ply_keyboard_backspace_handler_t backspace_handler) +{ + ply_list_node_t *node; + + assert (keyboard != NULL); + + for (node = ply_list_get_first_node(keyboard->backspace_handler_list); + node; node = ply_list_get_next_node(keyboard->backspace_handler_list, node)) + { + ply_keyboard_closure_t *closure = ply_list_node_get_data (node); + if ((ply_keyboard_backspace_handler_t) closure->function == backspace_handler) + { + ply_keyboard_closure_free (closure); + ply_list_remove_node (keyboard->backspace_handler_list, node); + return; + } + } +} + +void +ply_keyboard_add_escape_handler (ply_keyboard_t *keyboard, + ply_keyboard_escape_handler_t escape_handler, + void *user_data) +{ + ply_keyboard_closure_t *closure; + + assert (keyboard != NULL); + + closure = ply_keyboard_closure_new ((ply_keyboard_handler_t) escape_handler, + user_data); + ply_list_append_data (keyboard->escape_handler_list, closure); +} + + +void +ply_keyboard_remove_escape_handler (ply_keyboard_t *keyboard, + ply_keyboard_escape_handler_t escape_handler) +{ + ply_list_node_t *node; + + assert (keyboard != NULL); + + for (node = ply_list_get_first_node(keyboard->escape_handler_list); + node; node = ply_list_get_next_node(keyboard->escape_handler_list, node)) + { + ply_keyboard_closure_t *closure = ply_list_node_get_data (node); + if ((ply_keyboard_escape_handler_t) closure->function == escape_handler) + { + ply_keyboard_closure_free (closure); + ply_list_remove_node (keyboard->escape_handler_list, node); + return; + } + } +} + +void +ply_keyboard_add_enter_handler (ply_keyboard_t *keyboard, + ply_keyboard_enter_handler_t enter_handler, + void *user_data) +{ + ply_keyboard_closure_t *closure; + + assert (keyboard != NULL); + + closure = ply_keyboard_closure_new ((ply_keyboard_handler_t) enter_handler, + user_data); + + ply_list_append_data (keyboard->enter_handler_list, closure); +} + +void +ply_keyboard_remove_enter_handler (ply_keyboard_t *keyboard, + ply_keyboard_enter_handler_t enter_handler) +{ + ply_list_node_t *node; + + assert (keyboard != NULL); + + for (node = ply_list_get_first_node(keyboard->enter_handler_list); + node; node = ply_list_get_next_node(keyboard->enter_handler_list, node)) + { + ply_keyboard_closure_t *closure = ply_list_node_get_data (node); + if ((ply_keyboard_enter_handler_t) closure->function == enter_handler) + { + ply_keyboard_closure_free (closure); + ply_list_remove_node (keyboard->enter_handler_list, node); + return; + } + } +} + +/* 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/libplybootsplash/ply-keyboard.h b/src/libplybootsplash/ply-keyboard.h new file mode 100644 index 00000000..74683cf1 --- /dev/null +++ b/src/libplybootsplash/ply-keyboard.h @@ -0,0 +1,78 @@ +/* ply-keyboard.h - APIs for putting up a splash screen + * + * 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_KEYBOARD_H +#define PLY_KEYBOARD_H + +#include <stdbool.h> +#include <stdint.h> +#include <unistd.h> + +#include "ply-buffer.h" +#include "ply-event-loop.h" +#include "ply-renderer.h" + +typedef struct _ply_keyboard ply_keyboard_t; + +typedef void (* ply_keyboard_input_handler_t) (void *user_data, + const char *keyboard_input, + size_t character_size); + +typedef void (* ply_keyboard_backspace_handler_t) (void *user_data); + +typedef void (* ply_keyboard_escape_handler_t) (void *user_data); + +typedef void (* ply_keyboard_enter_handler_t) (void *user_data, + const char *line); + +#ifndef PLY_HIDE_FUNCTION_DECLARATIONS +ply_keyboard_t *ply_keyboard_new_for_terminal (ply_terminal_t *terminal); +ply_keyboard_t *ply_keyboard_new_for_renderer (ply_renderer_t *renderer); +void ply_keyboard_free (ply_keyboard_t *keyboard); + +void ply_keyboard_add_input_handler (ply_keyboard_t *keyboard, + ply_keyboard_input_handler_t input_handler, + void *user_data); +void ply_keyboard_remove_input_handler (ply_keyboard_t *keyboard, + ply_keyboard_input_handler_t input_handler); +void ply_keyboard_add_backspace_handler (ply_keyboard_t *keyboard, + ply_keyboard_backspace_handler_t backspace_handler, + void *user_data); +void ply_keyboard_remove_backspace_handler (ply_keyboard_t *keyboard, + ply_keyboard_backspace_handler_t backspace_handler); +void ply_keyboard_add_escape_handler (ply_keyboard_t *keyboard, + ply_keyboard_escape_handler_t escape_handler, + void *user_data); +void ply_keyboard_remove_escape_handler (ply_keyboard_t *keyboard, + ply_keyboard_escape_handler_t escape_handler); +void ply_keyboard_add_enter_handler (ply_keyboard_t *keyboard, + ply_keyboard_enter_handler_t enter_handler, + void *user_data); +void ply_keyboard_remove_enter_handler (ply_keyboard_t *keyboard, + ply_keyboard_enter_handler_t enter_handler); + +bool ply_keyboard_watch_for_input (ply_keyboard_t *keyboard); +void ply_keyboard_stop_watching_for_input (ply_keyboard_t *keyboard); + +#endif + +#endif /* PLY_KEYBOARD_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/libplybootsplash/ply-label-plugin.h b/src/libplybootsplash/ply-label-plugin.h index fbb65f6f..8db46263 100644 --- a/src/libplybootsplash/ply-label-plugin.h +++ b/src/libplybootsplash/ply-label-plugin.h @@ -27,7 +27,8 @@ #include <unistd.h> #include "ply-event-loop.h" -#include "ply-window.h" +#include "ply-pixel-buffer.h" +#include "ply-pixel-display.h" typedef struct _ply_label_plugin ply_label_plugin_t; typedef struct _ply_label_plugin_control ply_label_plugin_control_t; @@ -37,11 +38,16 @@ typedef struct ply_label_plugin_control_t * (* create_control) (void); void (* destroy_control) (ply_label_plugin_control_t *label); bool (* show_control) (ply_label_plugin_control_t *label, - ply_window_t *window, - long x, - long y); + ply_pixel_display_t *display, + long x, + long y); void (* hide_control) (ply_label_plugin_control_t *label); - void (* draw_control) (ply_label_plugin_control_t *label); + void (* draw_control) (ply_label_plugin_control_t *label, + ply_pixel_buffer_t *pixel_buffer, + long x, + long y, + unsigned long width, + unsigned long height); bool (* is_control_hidden) (ply_label_plugin_control_t *label); void (* set_text_for_control) (ply_label_plugin_control_t *label, diff --git a/src/libplybootsplash/ply-label.c b/src/libplybootsplash/ply-label.c index 16a8b1fc..ef68081f 100644 --- a/src/libplybootsplash/ply-label.c +++ b/src/libplybootsplash/ply-label.c @@ -136,10 +136,10 @@ ply_label_unload_plugin (ply_label_t *label) } bool -ply_label_show (ply_label_t *label, - ply_window_t *window, - long x, - long y) +ply_label_show (ply_label_t *label, + ply_pixel_display_t *display, + long x, + long y) { if (label->plugin_interface == NULL) { @@ -148,7 +148,7 @@ ply_label_show (ply_label_t *label, } return label->plugin_interface->show_control (label->control, - window, x, y); + display, x, y); } void @@ -156,8 +156,22 @@ ply_label_draw (ply_label_t *label) { if (label->plugin_interface == NULL) return; +} + +void +ply_label_draw_area (ply_label_t *label, + ply_pixel_buffer_t *buffer, + long x, + long y, + unsigned long width, + unsigned long height) +{ + if (label->plugin_interface == NULL) + return; - label->plugin_interface->draw_control (label->control); + label->plugin_interface->draw_control (label->control, + buffer, + x, y, width, height); } void diff --git a/src/libplybootsplash/ply-label.h b/src/libplybootsplash/ply-label.h index c4673a2d..b342e17e 100644 --- a/src/libplybootsplash/ply-label.h +++ b/src/libplybootsplash/ply-label.h @@ -27,7 +27,8 @@ #include <unistd.h> #include "ply-event-loop.h" -#include "ply-window.h" +#include "ply-pixel-buffer.h" +#include "ply-pixel-display.h" typedef struct _ply_label ply_label_t; @@ -35,13 +36,19 @@ typedef struct _ply_label ply_label_t; ply_label_t *ply_label_new (void); void ply_label_free (ply_label_t *label); -bool ply_label_show (ply_label_t *label, - ply_window_t *window, - long x, - long y); +bool ply_label_show (ply_label_t *label, + ply_pixel_display_t *display, + long x, + long y); void ply_label_hide (ply_label_t *label); void ply_label_draw (ply_label_t *label); +void ply_label_draw_area (ply_label_t *label, + ply_pixel_buffer_t *buffer, + long x, + long y, + unsigned long width, + unsigned long height); bool ply_label_is_hidden (ply_label_t *label); void ply_label_set_text (ply_label_t *label, diff --git a/src/libplybootsplash/ply-pixel-buffer.c b/src/libplybootsplash/ply-pixel-buffer.c new file mode 100644 index 00000000..722c5324 --- /dev/null +++ b/src/libplybootsplash/ply-pixel-buffer.c @@ -0,0 +1,602 @@ +/* ply-pixel-buffer.c - pixelbuffer abstraction + * + * Copyright (C) 2006, 2007, 2008, 2009 Red Hat, Inc. + * 2008 Charlie Brej <cbrej@cs.man.ac.uk> + * + * 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: Charlie Brej <cbrej@cs.man.ac.uk> + * Kristian Høgsberg <krh@redhat.com> + * Ray Strode <rstrode@redhat.com> + */ +#include "config.h" +#include "ply-list.h" +#include "ply-pixel-buffer.h" +#include "ply-logger.h" + +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +struct _ply_pixel_buffer +{ + uint32_t *bytes; + + ply_rectangle_t area; + ply_list_t *clip_areas; + + ply_region_t *updated_areas; +}; + +static inline void ply_pixel_buffer_blend_value_at_pixel (ply_pixel_buffer_t *buffer, + int x, + int y, + uint32_t pixel_value); + +static void ply_pixel_buffer_fill_area_with_pixel_value (ply_pixel_buffer_t *buffer, + ply_rectangle_t *fill_area, + uint32_t pixel_value); + +__attribute__((__pure__)) +static inline uint32_t +blend_two_pixel_values (uint32_t pixel_value_1, + uint32_t pixel_value_2) +{ + if ((pixel_value_2 & 0xff000000) == 0xff000000) + { + uint8_t alpha_1, red_1, green_1, blue_1; + uint8_t red_2, green_2, blue_2; + uint_least16_t red, green, blue; + + alpha_1 = (uint8_t) (pixel_value_1 >> 24); + red_1 = (uint8_t) (pixel_value_1 >> 16); + green_1 = (uint8_t) (pixel_value_1 >> 8); + blue_1 = (uint8_t) pixel_value_1; + + red_2 = (uint8_t) (pixel_value_2 >> 16); + green_2 = (uint8_t) (pixel_value_2 >> 8); + blue_2 = (uint8_t) pixel_value_2; + + red = red_1 * 255 + red_2 * (255 - alpha_1); + green = green_1 * 255 + green_2 * (255 - alpha_1); + blue = blue_1 * 255 + blue_2 * (255 - alpha_1); + + red = (uint8_t) ((red + (red >> 8) + 0x80) >> 8); + green = (uint8_t) ((green + (green >> 8) + 0x80) >> 8); + blue = (uint8_t) ((blue + (blue >> 8) + 0x80) >> 8); + + return 0xff000000 | (red << 16) | (green << 8) | blue; + } + else + { + uint8_t alpha_1, red_1, green_1, blue_1; + uint8_t alpha_2, red_2, green_2, blue_2; + uint_least32_t alpha, red, green, blue; + + alpha_1 = (uint8_t) (pixel_value_1 >> 24); + red_1 = (uint8_t) (pixel_value_1 >> 16); + green_1 = (uint8_t) (pixel_value_1 >> 8); + blue_1 = (uint8_t) pixel_value_1; + + alpha_2 = (uint8_t) (pixel_value_2 >> 24); + red_2 = (uint8_t) (pixel_value_2 >> 16); + green_2 = (uint8_t) (pixel_value_2 >> 8); + blue_2 = (uint8_t) pixel_value_2; + + red = red_1 * alpha_1 + red_2 * alpha_2 * (255 - alpha_1); + green = green_1 * alpha_1 + green_2 * alpha_2 * (255 - alpha_1); + blue = blue_1 * alpha_1 + blue_2 * alpha_2 * (255 - alpha_1); + alpha = alpha_1 * 255 + alpha_2 * (255 - alpha_1); + + red = (red + (red >> 8) + 0x80) >> 8; + red = MIN (red, 0xff); + + green = (green + (green >> 8) + 0x80) >> 8; + green = MIN (green, 0xff); + + blue = (blue + (blue >> 8) + 0x80) >> 8; + blue = MIN (blue, 0xff); + + alpha = (alpha + (alpha >> 8) + 0x80) >> 8; + alpha = MIN (alpha, 0xff); + + return (alpha << 24) | (red << 16) | (green << 8) | blue; + } +} + +__attribute__((__pure__)) +static inline uint32_t +make_pixel_value_translucent (uint32_t pixel_value, + uint8_t opacity) +{ + uint_least16_t alpha, red, green, blue; + + if (opacity == 255) + return pixel_value; + + alpha = (uint8_t) (pixel_value >> 24); + red = (uint8_t) (pixel_value >> 16); + green = (uint8_t) (pixel_value >> 8); + blue = (uint8_t) pixel_value; + + red *= opacity; + green *= opacity; + blue *= opacity; + alpha *= opacity; + + red = (uint8_t) ((red + (red >> 8) + 0x80) >> 8); + green = (uint8_t) ((green + (green >> 8) + 0x80) >> 8); + blue = (uint8_t) ((blue + (blue >> 8) + 0x80) >> 8); + alpha = (uint8_t) ((alpha + (alpha >> 8) + 0x80) >> 8); + + return (alpha << 24) | (red << 16) | (green << 8) | blue; +} + +static inline void +ply_pixel_buffer_blend_value_at_pixel (ply_pixel_buffer_t *buffer, + int x, + int y, + uint32_t pixel_value) +{ + uint32_t old_pixel_value; + + if ((pixel_value >> 24) != 0xff) + { + old_pixel_value = buffer->bytes[y * buffer->area.width + x]; + + pixel_value = blend_two_pixel_values (pixel_value, old_pixel_value); + } + + buffer->bytes[y * buffer->area.width + x] = pixel_value; +} + +static void +ply_pixel_buffer_crop_area_to_clip_area (ply_pixel_buffer_t *buffer, + ply_rectangle_t *area, + ply_rectangle_t *cropped_area) +{ + ply_list_node_t *node; + + *cropped_area = *area; + + node = ply_list_get_first_node (buffer->clip_areas); + while (node != NULL) + { + ply_list_node_t *next_node; + ply_rectangle_t *clip_rectangle; + + clip_rectangle = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (buffer->clip_areas, node); + + ply_rectangle_intersect (cropped_area, clip_rectangle, cropped_area); + + node = next_node; + } +} + +static void +ply_pixel_buffer_fill_area_with_pixel_value (ply_pixel_buffer_t *buffer, + ply_rectangle_t *fill_area, + uint32_t pixel_value) +{ + unsigned long row, column; + ply_rectangle_t cropped_area; + + ply_pixel_buffer_crop_area_to_clip_area (buffer, fill_area, &cropped_area); + + 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, + column, row, + pixel_value); + } + } +} + +void +ply_pixel_buffer_push_clip_area (ply_pixel_buffer_t *buffer, + ply_rectangle_t *clip_area) +{ + ply_rectangle_t *new_clip_area; + + new_clip_area = malloc (sizeof (*new_clip_area)); + + *new_clip_area = *clip_area; + ply_list_append_data (buffer->clip_areas, new_clip_area); +} + +void +ply_pixel_buffer_pop_clip_area (ply_pixel_buffer_t *buffer) +{ + ply_list_node_t *last_node; + + last_node = ply_list_get_last_node (buffer->clip_areas); + free (ply_list_node_get_data (last_node)); + ply_list_remove_node (buffer->clip_areas, last_node); +} + +ply_pixel_buffer_t * +ply_pixel_buffer_new (unsigned long width, + unsigned long height) +{ + ply_pixel_buffer_t *buffer; + + buffer = calloc (1, sizeof (ply_pixel_buffer_t)); + + buffer->updated_areas = ply_region_new (); + buffer->bytes = (uint32_t *) calloc (height, width * sizeof (uint32_t)); + buffer->area.width = width; + buffer->area.height = height; + + buffer->clip_areas = ply_list_new (); + ply_pixel_buffer_push_clip_area (buffer, &buffer->area); + + return buffer; +} + +static void +free_clip_areas (ply_pixel_buffer_t *buffer) +{ + while (ply_list_get_length (buffer->clip_areas) > 0) + ply_pixel_buffer_pop_clip_area (buffer); + + ply_list_free (buffer->clip_areas); + buffer->clip_areas = NULL; +} + +void +ply_pixel_buffer_free (ply_pixel_buffer_t *buffer) +{ + if (buffer == NULL) + return; + + free_clip_areas (buffer); + free (buffer->bytes); + ply_region_free (buffer->updated_areas); + free (buffer); +} + +void +ply_pixel_buffer_get_size (ply_pixel_buffer_t *buffer, + ply_rectangle_t *size) +{ + assert (buffer != NULL); + assert (size != NULL); + + *size = buffer->area; +} + +ply_region_t * +ply_pixel_buffer_get_updated_areas (ply_pixel_buffer_t *buffer) +{ + return buffer->updated_areas; +} + +void +ply_pixel_buffer_fill_with_gradient (ply_pixel_buffer_t *buffer, + ply_rectangle_t *fill_area, + uint32_t start, + uint32_t end) +{ +/* The gradient produced is a linear interpolation of the two passed + * in color stops: start and end. + * + * In order to prevent banding when the color stops are too close + * together, or are stretched over too large an area, we slightly + * perturb the intermediate colors as we generate them. + * + * Before we do this, we store the interpolated color values in a + * fixed point number with lots of fractional bits. This is so + * we don't add noise after the values have been clamped to 8-bits + * + * We add random noise to all of the fractional bits of each color + * channel and also NOISE_BITS worth of noise to the non-fractional + * part of the color. By default NOISE_BITS is 1. + * + * We incorporate the noise by filling the bottom 24 bits of an + * integer with random bits and then shifting the color channels + * to the left such that the top 8 bits of the channel overlap + * the noise by NOISE_BITS. E.g., if NOISE_BITS is 1, then the top + * 7 bits of each channel won't overlap with the noise, and the 8th + * bit + fractional bits will. When the noise and color channel + * are properly aligned, we add them together, drop the precision + * of the resulting channels back to 8 bits and stuff the results + * into a pixel in the pixel buffer. + */ +#define NOISE_BITS 1 +/* In the color stops, red is 8 bits starting at position 24 + * (since they're argb32 pixels). + * We want to move those 8 bits such that the bottom NOISE_BITS + * of them overlap the top of the 24 bits of generated noise. + * Of course, green and blue are 8 bits away from red and each + * other, respectively. + */ +#define RED_SHIFT (32 - (24 + NOISE_BITS)) +#define GREEN_SHIFT (RED_SHIFT + 8) +#define BLUE_SHIFT (GREEN_SHIFT + 8) +#define NOISE_MASK (0x00ffffff) + +/* Once, we've lined up the color channel we're interested in with + * the noise, we need to mask out the other channels. + */ +#define COLOR_MASK (0xff << (24 - NOISE_BITS)) + + uint32_t red, green, blue, red_step, green_step, blue_step, t, pixel; + uint32_t x, y; + /* we use a fixed seed so that the dithering doesn't change on repaints + * of the same area. + */ + uint32_t noise = 0x100001; + ply_rectangle_t cropped_area; + + if (fill_area == NULL) + fill_area = &buffer->area; + + ply_pixel_buffer_crop_area_to_clip_area (buffer, fill_area, &cropped_area); + + red = (start << RED_SHIFT) & COLOR_MASK; + green = (start << GREEN_SHIFT) & COLOR_MASK; + blue = (start << BLUE_SHIFT) & COLOR_MASK; + + t = (end << RED_SHIFT) & COLOR_MASK; + red_step = (int32_t) (t - red) / (int32_t) buffer->area.height; + t = (end << GREEN_SHIFT) & COLOR_MASK; + green_step = (int32_t) (t - green) / (int32_t) buffer->area.height; + t = (end << BLUE_SHIFT) & COLOR_MASK; + blue_step = (int32_t) (t - blue) / (int32_t) buffer->area.height; + + +#define RANDOMIZE(num) (num = (num + (num << 1)) & NOISE_MASK) +#define UNROLLED_PIXEL_COUNT 8 + + for (y = buffer->area.y; y < buffer->area.y + buffer->area.height; y++) + { + if (cropped_area.y <= y && y < cropped_area.y + cropped_area.height) + { + if (cropped_area.width < UNROLLED_PIXEL_COUNT) + { + for (x = cropped_area.x; x < cropped_area.x + cropped_area.width; x++) + { + pixel = 0xff000000; + RANDOMIZE(noise); + pixel |= (((red + noise) & COLOR_MASK) >> RED_SHIFT); + RANDOMIZE(noise); + pixel |= (((green + noise) & COLOR_MASK) >> GREEN_SHIFT); + RANDOMIZE(noise); + pixel |= (((blue + noise) & COLOR_MASK) >> BLUE_SHIFT); + + buffer->bytes[y * buffer->area.width + x] = pixel; + } + } + else + { + uint32_t shaded_set[UNROLLED_PIXEL_COUNT]; + uint32_t *ptr = &buffer->bytes[y * buffer->area.width + cropped_area.x]; + for (x = 0; x < UNROLLED_PIXEL_COUNT; x++) + { + shaded_set[x] = 0xff000000; + RANDOMIZE(noise); + shaded_set[x] |= (((red + noise) & COLOR_MASK) >> RED_SHIFT); + RANDOMIZE(noise); + shaded_set[x] |= (((green + noise) & COLOR_MASK) >> GREEN_SHIFT); + RANDOMIZE(noise); + shaded_set[x] |= (((blue + noise) & COLOR_MASK) >> BLUE_SHIFT); + } + for (x = cropped_area.width; x >=UNROLLED_PIXEL_COUNT; x-= UNROLLED_PIXEL_COUNT) + { + memcpy (ptr, (void *) shaded_set, UNROLLED_PIXEL_COUNT * sizeof (uint32_t)); + ptr += UNROLLED_PIXEL_COUNT; + } + + memcpy (ptr, (void *) shaded_set, x * sizeof (uint32_t)); + } + } + + red += red_step; + green += green_step; + blue += blue_step; + } + + ply_region_add_rectangle (buffer->updated_areas, &cropped_area); +} + +void +ply_pixel_buffer_fill_with_color (ply_pixel_buffer_t *buffer, + ply_rectangle_t *fill_area, + double red, + double green, + double blue, + 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); +} + +void +ply_pixel_buffer_fill_with_hex_color_at_opacity (ply_pixel_buffer_t *buffer, + ply_rectangle_t *fill_area, + uint32_t hex_color, + double opacity) +{ + ply_rectangle_t cropped_area; + uint32_t pixel_value; + double red; + double green; + double blue; + double alpha; + + 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) + hex_color = (hex_color << 8) | 0xff; + + red = ((double) (hex_color & 0xff000000) / 0xff000000); + green = ((double) (hex_color & 0x00ff0000) / 0x00ff0000); + blue = ((double) (hex_color & 0x0000ff00) / 0x0000ff00); + alpha = ((double) (hex_color & 0x000000ff) / 0x000000ff); + + alpha *= opacity; + + 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); +} + +void +ply_pixel_buffer_fill_with_hex_color (ply_pixel_buffer_t *buffer, + ply_rectangle_t *fill_area, + uint32_t hex_color) +{ + return ply_pixel_buffer_fill_with_hex_color_at_opacity (buffer, fill_area, + hex_color, 1.0); +} + +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, + unsigned long x, + unsigned long y, + uint32_t *data, + double opacity) +{ + unsigned long row, column; + uint8_t opacity_as_byte; + 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); + + if (clip_area) + ply_rectangle_intersect (&cropped_area, 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); + + 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 ((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), + pixel_value); + + } + } + + ply_region_add_rectangle (buffer->updated_areas, &cropped_area); +} + +void +ply_pixel_buffer_fill_with_argb32_data_at_opacity (ply_pixel_buffer_t *buffer, + ply_rectangle_t *fill_area, + unsigned long x, + unsigned long y, + uint32_t *data, + double opacity) +{ + ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip (buffer, + fill_area, + NULL, x, y, + data, opacity); +} + +void +ply_pixel_buffer_fill_with_argb32_data (ply_pixel_buffer_t *buffer, + ply_rectangle_t *fill_area, + unsigned long x, + unsigned long y, + uint32_t *data) +{ + ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip (buffer, + fill_area, + NULL, x, y, + data, 1.0); +} + +void +ply_pixel_buffer_fill_with_argb32_data_with_clip (ply_pixel_buffer_t *buffer, + ply_rectangle_t *fill_area, + ply_rectangle_t *clip_area, + unsigned long x, + unsigned long y, + uint32_t *data) +{ + ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip (buffer, + fill_area, + clip_area, x, y, + data, 1.0); +} + +uint32_t * +ply_pixel_buffer_get_argb32_data (ply_pixel_buffer_t *buffer) +{ + return buffer->bytes; +} +/* 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/libplybootsplash/ply-pixel-buffer.h b/src/libplybootsplash/ply-pixel-buffer.h new file mode 100644 index 00000000..52a93b55 --- /dev/null +++ b/src/libplybootsplash/ply-pixel-buffer.h @@ -0,0 +1,103 @@ +/* ply-pixel-buffer.h - pixel buffer abstraction + * + * Copyright (C) 2007, 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_PIXEL_BUFFER_H +#define PLY_PIXEL_BUFFER_H + +#include <stdbool.h> +#include <stdint.h> + +#include "ply-rectangle.h" +#include "ply-region.h" +#include "ply-utils.h" + +typedef struct _ply_pixel_buffer ply_pixel_buffer_t; + +#define PLY_PIXEL_BUFFER_COLOR_TO_PIXEL_VALUE(r,g,b,a) \ + (((uint8_t) (CLAMP (a * 255.0, 0.0, 255.0)) << 24) \ + | ((uint8_t) (CLAMP (r * 255.0, 0.0, 255.0)) << 16) \ + | ((uint8_t) (CLAMP (g * 255.0, 0.0, 255.0)) << 8) \ + | ((uint8_t) (CLAMP (b * 255.0, 0.0, 255.0)))) + +#ifndef PLY_HIDE_FUNCTION_DECLARATIONS +ply_pixel_buffer_t *ply_pixel_buffer_new (unsigned long width, + unsigned long height); +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); +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, + ply_rectangle_t *fill_area, + double red, + double green, + double blue, + double alpha); +void ply_pixel_buffer_fill_with_hex_color (ply_pixel_buffer_t *buffer, + ply_rectangle_t *fill_area, + uint32_t hex_color); + +void ply_pixel_buffer_fill_with_hex_color_at_opacity (ply_pixel_buffer_t *buffer, + ply_rectangle_t *fill_area, + uint32_t hex_color, + double opacity); + +void ply_pixel_buffer_fill_with_gradient (ply_pixel_buffer_t *buffer, + ply_rectangle_t *fill_area, + uint32_t start, + uint32_t end); + +void ply_pixel_buffer_fill_with_argb32_data (ply_pixel_buffer_t *buffer, + ply_rectangle_t *fill_area, + unsigned long x, + unsigned long y, + uint32_t *data); +void ply_pixel_buffer_fill_with_argb32_data_at_opacity (ply_pixel_buffer_t *buffer, + ply_rectangle_t *fill_area, + unsigned long x, + unsigned long y, + uint32_t *data, + double opacity); + +void ply_pixel_buffer_fill_with_argb32_data_with_clip (ply_pixel_buffer_t *buffer, + ply_rectangle_t *fill_area, + ply_rectangle_t *clip_area, + unsigned long x, + unsigned long y, + uint32_t *data); +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, + unsigned long x, + unsigned long y, + uint32_t *data, + double opacity); + +void ply_pixel_buffer_push_clip_area (ply_pixel_buffer_t *buffer, + ply_rectangle_t *clip_area); +void ply_pixel_buffer_pop_clip_area (ply_pixel_buffer_t *buffer); + +uint32_t *ply_pixel_buffer_get_argb32_data (ply_pixel_buffer_t *buffer); + +#endif + +#endif /* PLY_PIXEL_BUFFER_H */ +/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/libplybootsplash/ply-pixel-display.c b/src/libplybootsplash/ply-pixel-display.c new file mode 100644 index 00000000..37151203 --- /dev/null +++ b/src/libplybootsplash/ply-pixel-display.c @@ -0,0 +1,175 @@ +/* ply-pixel-display.c - APIs for putting up a pixel + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: Ray Strode <rstrode@redhat.com> + */ +#include "config.h" +#include "ply-pixel-display.h" + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <termios.h> +#include <unistd.h> + +#include "ply-event-loop.h" +#include "ply-list.h" +#include "ply-logger.h" +#include "ply-pixel-buffer.h" +#include "ply-renderer.h" +#include "ply-utils.h" + +struct _ply_pixel_display +{ + ply_event_loop_t *loop; + + ply_renderer_t *renderer; + ply_renderer_head_t *head; + + unsigned long width; + unsigned long height; + + ply_pixel_display_draw_handler_t draw_handler; + void *draw_handler_user_data; + + int pause_count; + +}; + +ply_pixel_display_t * +ply_pixel_display_new (ply_renderer_t *renderer, + ply_renderer_head_t *head) +{ + ply_pixel_display_t *display; + ply_pixel_buffer_t *pixel_buffer; + ply_rectangle_t size; + + display = calloc (1, sizeof (ply_pixel_display_t)); + + display->loop = ply_event_loop_get_default (); + display->renderer = renderer; + display->head = head; + + pixel_buffer = ply_renderer_get_buffer_for_head (renderer, head); + ply_pixel_buffer_get_size (pixel_buffer, &size); + + display->width = size.width; + display->height = size.height; + + return display; +} + +unsigned long +ply_pixel_display_get_width (ply_pixel_display_t *display) +{ + return display->width; +} + +unsigned long +ply_pixel_display_get_height (ply_pixel_display_t *display) +{ + return display->height; +} + +static void +ply_pixel_display_flush (ply_pixel_display_t *display) +{ + if (display->pause_count > 0) + return; + + ply_renderer_flush_head (display->renderer, display->head); +} + +void +ply_pixel_display_pause_updates (ply_pixel_display_t *display) +{ + assert (display != NULL); + + display->pause_count++; +} + +void +ply_pixel_display_unpause_updates (ply_pixel_display_t *display) +{ + assert (display != NULL); + + display->pause_count--; + + ply_pixel_display_flush (display); +} + +void +ply_pixel_display_draw_area (ply_pixel_display_t *display, + int x, + int y, + int width, + int height) +{ + + ply_pixel_buffer_t *pixel_buffer; + + pixel_buffer = ply_renderer_get_buffer_for_head (display->renderer, + display->head); + + if (display->draw_handler != NULL) + { + ply_rectangle_t clip_area; + + clip_area.x = x; + clip_area.y = y; + clip_area.width = width; + clip_area.height = height; + ply_pixel_buffer_push_clip_area (pixel_buffer, &clip_area); + display->draw_handler (display->draw_handler_user_data, + pixel_buffer, + x, y, width, height, display); + ply_pixel_buffer_pop_clip_area (pixel_buffer); + } + + ply_pixel_display_flush (display); +} + +void +ply_pixel_display_free (ply_pixel_display_t *display) +{ + if (display == NULL) + return; + + free (display); +} + +void +ply_pixel_display_set_draw_handler (ply_pixel_display_t *display, + ply_pixel_display_draw_handler_t draw_handler, + void *user_data) +{ + assert (display != NULL); + + display->draw_handler = draw_handler; + display->draw_handler_user_data = user_data; +} + +/* 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/libplybootsplash/ply-pixel-display.h b/src/libplybootsplash/ply-pixel-display.h new file mode 100644 index 00000000..98a6b3c8 --- /dev/null +++ b/src/libplybootsplash/ply-pixel-display.h @@ -0,0 +1,68 @@ +/* ply-pixel-display.h - APIs for displaying pixels + * + * 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_PIXEL_DISPLAY_H +#define PLY_PIXEL_DISPLAY_H + +#include <stdbool.h> +#include <stdint.h> +#include <unistd.h> + +#include "ply-event-loop.h" +#include "ply-pixel-buffer.h" +#include "ply-renderer.h" + +typedef struct _ply_pixel_display ply_pixel_display_t; + +typedef void (* ply_pixel_display_draw_handler_t) (void *user_data, + ply_pixel_buffer_t *pixel_buffer, + int x, + int y, + int width, + int height, + ply_pixel_display_t *pixel_display); + +#ifndef PLY_HIDE_FUNCTION_DECLARATIONS +ply_pixel_display_t *ply_pixel_display_new (ply_renderer_t *renderer, + ply_renderer_head_t *head); + +void ply_pixel_display_free (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); + +void ply_pixel_display_set_draw_handler (ply_pixel_display_t *display, + ply_pixel_display_draw_handler_t draw_handler, + void *user_data); + +void ply_pixel_display_draw_area (ply_pixel_display_t *display, + int x, + int y, + int width, + int height); + +void ply_pixel_display_pause_updates (ply_pixel_display_t *display); +void ply_pixel_display_unpause_updates (ply_pixel_display_t *display); + +#endif + +#endif /* PLY_PIXEL_DISPLAY_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/libplybootsplash/ply-progress-animation.c b/src/libplybootsplash/ply-progress-animation.c index 59bdfa18..9d64e713 100644 --- a/src/libplybootsplash/ply-progress-animation.c +++ b/src/libplybootsplash/ply-progress-animation.c @@ -44,10 +44,8 @@ #include "ply-progress-animation.h" #include "ply-array.h" #include "ply-logger.h" -#include "ply-frame-buffer.h" #include "ply-image.h" #include "ply-utils.h" -#include "ply-window.h" #include <linux/kd.h> @@ -60,16 +58,17 @@ struct _ply_progress_animation ply_progress_animation_transition_t transition; double transition_duration; - ply_window_t *window; - ply_frame_buffer_t *frame_buffer; - ply_frame_buffer_area_t area; - ply_frame_buffer_area_t frame_area; + ply_pixel_display_t *display; + ply_rectangle_t area; + ply_rectangle_t frame_area; double percent_done; int previous_frame_number; double transition_start_time; + ply_pixel_buffer_t *last_rendered_frame; + uint32_t is_hidden : 1; uint32_t is_transitioning : 1; }; @@ -99,6 +98,7 @@ ply_progress_animation_new (const char *image_dir, progress_animation->frame_area.width = 0; progress_animation->frame_area.height = 0; progress_animation->previous_frame_number = 0; + progress_animation->last_rendered_frame = NULL; return progress_animation; } @@ -139,16 +139,12 @@ ply_progress_animation_free (ply_progress_animation_t *progress_animation) } static void -draw_background (ply_progress_animation_t *progress_animation) -{ - ply_window_erase_area (progress_animation->window, - progress_animation->area.x, progress_animation->area.y, - progress_animation->frame_area.width, - progress_animation->frame_area.height); -} - -static uint32_t* -image_fade_merge(ply_image_t* frame0, ply_image_t* frame1, float fade, int width, int height) +image_fade_merge (ply_image_t* frame0, + ply_image_t* frame1, + float fade, + int width, + int height, + uint32_t *reply_data) { int frame0_width = ply_image_get_width (frame0); int frame0_height = ply_image_get_height (frame0); @@ -158,10 +154,8 @@ image_fade_merge(ply_image_t* frame0, ply_image_t* frame1, float fade, int width uint32_t *frame0_data = ply_image_get_data (frame0); uint32_t *frame1_data = ply_image_get_data (frame1); - uint32_t *reply_data = malloc (width * height * sizeof (uint32_t)); int x, y, i; - for (y = 0; y < height; y++) { for (x = 0; x < width; x++) @@ -189,7 +183,26 @@ image_fade_merge(ply_image_t* frame0, ply_image_t* frame1, float fade, int width reply_data[y*width+x] = pixelout; } } - return reply_data; +} + +void +ply_progress_animation_draw_area (ply_progress_animation_t *progress_animation, + ply_pixel_buffer_t *buffer, + long x, + long y, + unsigned long width, + unsigned long height) +{ + uint32_t *frame_data; + + if (progress_animation->is_hidden) + return; + + frame_data = ply_pixel_buffer_get_argb32_data (progress_animation->last_rendered_frame); + + ply_pixel_buffer_fill_with_argb32_data (buffer, + &progress_animation->frame_area, 0, 0, + frame_data); } void @@ -203,8 +216,6 @@ ply_progress_animation_draw (ply_progress_animation_t *progress_animation) if (progress_animation->is_hidden) return; - ply_window_set_mode (progress_animation->window, PLY_WINDOW_MODE_GRAPHICS); - number_of_frames = ply_array_get_size (progress_animation->frames); if (number_of_frames == 0) @@ -212,10 +223,6 @@ ply_progress_animation_draw (ply_progress_animation_t *progress_animation) frame_number = progress_animation->percent_done * (number_of_frames - 1); - ply_frame_buffer_pause_updates (progress_animation->frame_buffer); - if (progress_animation->frame_area.width > 0) - draw_background (progress_animation); - if (progress_animation->previous_frame_number != frame_number && progress_animation->transition != PLY_PROGRESS_ANIMATION_TRANSITION_NONE && progress_animation->transition_duration > 0.0) @@ -245,7 +252,6 @@ ply_progress_animation_draw (ply_progress_animation_t *progress_animation) progress_animation->is_transitioning = false; fade_percentage = CLAMP (fade_percentage, 0.0, 1.0); - previous_frame_data = ply_image_get_data (frames[frame_number - 1]); if (progress_animation->transition == PLY_PROGRESS_ANIMATION_TRANSITION_MERGE_FADE) { width = MAX(ply_image_get_width (frames[frame_number]), ply_image_get_width (frames[frame_number - 1])); @@ -253,30 +259,62 @@ ply_progress_animation_draw (ply_progress_animation_t *progress_animation) progress_animation->frame_area.width = width; progress_animation->frame_area.height = height; - faded_data = image_fade_merge(frames[frame_number - 1], frames[frame_number], fade_percentage, width, height); + ply_pixel_buffer_free (progress_animation->last_rendered_frame); + progress_animation->last_rendered_frame = ply_pixel_buffer_new (width, height); + faded_data = ply_pixel_buffer_get_argb32_data (progress_animation->last_rendered_frame); - ply_frame_buffer_fill_with_argb32_data_at_opacity (progress_animation->frame_buffer, - &progress_animation->frame_area, 0, 0, - faded_data, 1.0); - free(faded_data); + image_fade_merge (frames[frame_number - 1], frames[frame_number], fade_percentage, width, height, faded_data); + + ply_pixel_display_draw_area (progress_animation->display, + progress_animation->frame_area.x, + progress_animation->frame_area.y, + progress_animation->frame_area.width, + progress_animation->frame_area.height); } else { + ply_rectangle_t fill_area; + + previous_frame_data = ply_image_get_data (frames[frame_number - 1]); if (progress_animation->transition == PLY_PROGRESS_ANIMATION_TRANSITION_FADE_OVER) - fade_out_opacity = 1.0; + { + ply_pixel_buffer_free (progress_animation->last_rendered_frame); + progress_animation->frame_area.width = ply_image_get_width (frames[frame_number - 1]); + progress_animation->frame_area.height = ply_image_get_height (frames[frame_number - 1]); + + progress_animation->last_rendered_frame = ply_pixel_buffer_new (progress_animation->frame_area.width, + progress_animation->frame_area.height); + fill_area.x = 0; + fill_area.y = 0; + fill_area.width = progress_animation->frame_area.width; + fill_area.height = progress_animation->frame_area.height; + ply_pixel_buffer_fill_with_argb32_data (progress_animation->last_rendered_frame, + &fill_area, 0, 0, + previous_frame_data); + } else - fade_out_opacity = 1.0 - fade_percentage; - - progress_animation->frame_area.width = ply_image_get_width (frames[frame_number - 1]); - progress_animation->frame_area.height = ply_image_get_height (frames[frame_number - 1]); - ply_frame_buffer_fill_with_argb32_data_at_opacity (progress_animation->frame_buffer, - &progress_animation->frame_area, 0, 0, - previous_frame_data, fade_out_opacity); + { + fade_out_opacity = 1.0 - fade_percentage; + progress_animation->frame_area.width = ply_image_get_width (frames[frame_number - 1]); + progress_animation->frame_area.height = ply_image_get_height (frames[frame_number - 1]); + + fill_area.x = 0; + fill_area.y = 0; + fill_area.width = progress_animation->frame_area.width; + fill_area.height = progress_animation->frame_area.height; + ply_pixel_buffer_fill_with_argb32_data_at_opacity (progress_animation->last_rendered_frame, + &fill_area, 0, 0, + previous_frame_data, fade_out_opacity); + } progress_animation->frame_area.width = ply_image_get_width (frames[frame_number]); progress_animation->frame_area.height = ply_image_get_height (frames[frame_number]); - ply_frame_buffer_fill_with_argb32_data_at_opacity (progress_animation->frame_buffer, - &progress_animation->frame_area, 0, 0, + fill_area.x = 0; + fill_area.y = 0; + fill_area.width = progress_animation->frame_area.width; + fill_area.height = progress_animation->frame_area.height; + ply_pixel_buffer_fill_with_argb32_data_at_opacity (progress_animation->last_rendered_frame, + &fill_area, 0, 0, frame_data, fade_percentage); width = MAX(ply_image_get_width (frames[frame_number]), ply_image_get_width (frames[frame_number - 1])); @@ -284,20 +322,33 @@ ply_progress_animation_draw (ply_progress_animation_t *progress_animation) progress_animation->frame_area.width = width; progress_animation->frame_area.height = height; } - } else { + ply_rectangle_t fill_area; + + ply_pixel_buffer_free (progress_animation->last_rendered_frame); progress_animation->frame_area.width = ply_image_get_width (frames[frame_number]); progress_animation->frame_area.height = ply_image_get_height (frames[frame_number]); - ply_frame_buffer_fill_with_argb32_data (progress_animation->frame_buffer, - &progress_animation->frame_area, 0, 0, + progress_animation->last_rendered_frame = ply_pixel_buffer_new (progress_animation->frame_area.width, + progress_animation->frame_area.height); + + fill_area.x = 0; + fill_area.y = 0; + fill_area.width = progress_animation->frame_area.width; + fill_area.height = progress_animation->frame_area.height; + ply_pixel_buffer_fill_with_argb32_data (progress_animation->last_rendered_frame, + &fill_area, 0, 0, frame_data); } - ply_frame_buffer_unpause_updates (progress_animation->frame_buffer); - progress_animation->previous_frame_number = frame_number; + + ply_pixel_display_draw_area (progress_animation->display, + progress_animation->frame_area.x, + progress_animation->frame_area.y, + progress_animation->frame_area.width, + progress_animation->frame_area.height); } static bool @@ -392,14 +443,13 @@ ply_progress_animation_load (ply_progress_animation_t *progress_animation) void ply_progress_animation_show (ply_progress_animation_t *progress_animation, - ply_window_t *window, + ply_pixel_display_t *display, long x, long y) { assert (progress_animation != NULL); - progress_animation->window = window; - progress_animation->frame_buffer = ply_window_get_frame_buffer (window);; + progress_animation->display = display; progress_animation->area.x = x; progress_animation->area.y = y; @@ -414,13 +464,16 @@ ply_progress_animation_hide (ply_progress_animation_t *progress_animation) if (progress_animation->is_hidden) return; + progress_animation->is_hidden = true; if (progress_animation->frame_area.width > 0) - draw_background (progress_animation); - - progress_animation->frame_buffer = NULL; - progress_animation->window = NULL; + { + ply_pixel_display_draw_area (progress_animation->display, + progress_animation->area.x, progress_animation->area.y, + progress_animation->frame_area.width, + progress_animation->frame_area.height); + } - progress_animation->is_hidden = true; + progress_animation->display = NULL; } bool @@ -443,9 +496,10 @@ ply_progress_animation_get_height (ply_progress_animation_t *progress_animation) void ply_progress_animation_set_percent_done (ply_progress_animation_t *progress_animation, - double percent_done) + double percent_done) { progress_animation->percent_done = percent_done; + ply_progress_animation_draw (progress_animation); } double diff --git a/src/libplybootsplash/ply-progress-animation.h b/src/libplybootsplash/ply-progress-animation.h index 3c51d10f..274bd1c5 100644 --- a/src/libplybootsplash/ply-progress-animation.h +++ b/src/libplybootsplash/ply-progress-animation.h @@ -26,8 +26,7 @@ #include <stdint.h> #include <unistd.h> -#include "ply-frame-buffer.h" -#include "ply-window.h" +#include "ply-pixel-display.h" typedef struct _ply_progress_animation ply_progress_animation_t; @@ -49,11 +48,17 @@ void ply_progress_animation_set_transition (ply_progress_animation_t *progress_a ply_progress_animation_transition_t transition, double duration); void ply_progress_animation_show (ply_progress_animation_t *progress_animation, - ply_window_t *window, + ply_pixel_display_t *display, long x, long y); void ply_progress_animation_hide (ply_progress_animation_t *progress_animation); void ply_progress_animation_draw (ply_progress_animation_t *progress_animation); +void ply_progress_animation_draw_area (ply_progress_animation_t *progress_animation, + ply_pixel_buffer_t *buffer, + long x, + long y, + unsigned long width, + unsigned long height); bool ply_progress_animation_is_hidden (ply_progress_animation_t *progress_animation); long ply_progress_animation_get_width (ply_progress_animation_t *progress_animation); diff --git a/src/libplybootsplash/ply-progress-bar.c b/src/libplybootsplash/ply-progress-bar.c index ba9c13d1..12ca46a9 100644 --- a/src/libplybootsplash/ply-progress-bar.c +++ b/src/libplybootsplash/ply-progress-bar.c @@ -45,12 +45,10 @@ #include "ply-event-loop.h" #include "ply-array.h" #include "ply-logger.h" -#include "ply-frame-buffer.h" +#include "ply-pixel-buffer.h" +#include "ply-pixel-display.h" #include "ply-image.h" #include "ply-utils.h" -#include "ply-window.h" - -#include <linux/kd.h> #ifndef FRAMES_PER_SECOND #define FRAMES_PER_SECOND 30 @@ -62,9 +60,8 @@ struct _ply_progress_bar { - ply_window_t *window; - ply_frame_buffer_t *frame_buffer; - ply_frame_buffer_area_t area; + ply_pixel_display_t *display; + ply_rectangle_t area; double percent_done; @@ -97,54 +94,67 @@ ply_progress_bar_free (ply_progress_bar_t *progress_bar) } static void -erase_progress_bar_area (ply_progress_bar_t *progress_bar) -{ - ply_window_erase_area (progress_bar->window, - progress_bar->area.x, progress_bar->area.y, - progress_bar->area.width, progress_bar->area.height); -} - -static void ply_progress_bar_update_area (ply_progress_bar_t *progress_bar, long x, long y) { - - ply_frame_buffer_get_size (progress_bar->frame_buffer, &progress_bar->area); + unsigned long display_width; progress_bar->area.x = x; progress_bar->area.y = y; progress_bar->area.height = BAR_HEIGHT; - progress_bar->area.width = (long) (progress_bar->area.width * progress_bar->percent_done); + display_width = ply_pixel_display_get_width (progress_bar->display); + progress_bar->area.width = (long) (display_width * progress_bar->percent_done); } void -ply_progress_bar_draw (ply_progress_bar_t *progress_bar) +ply_progress_bar_draw_area (ply_progress_bar_t *progress_bar, + ply_pixel_buffer_t *buffer, + long x, + long y, + unsigned long width, + unsigned long height) { + ply_rectangle_t paint_area; if (progress_bar->is_hidden) return; - ply_frame_buffer_pause_updates (progress_bar->frame_buffer); - erase_progress_bar_area (progress_bar); - ply_progress_bar_update_area (progress_bar, progress_bar->area.x, progress_bar->area.y); - ply_frame_buffer_fill_with_hex_color (progress_bar->frame_buffer, - &progress_bar->area, + paint_area.x = x; + paint_area.y = y; + paint_area.width = width; + paint_area.height = height; + + ply_rectangle_intersect (&progress_bar->area, &paint_area, &paint_area); + ply_pixel_buffer_fill_with_hex_color (buffer, + &paint_area, 0xffffff); /* white */ - ply_frame_buffer_unpause_updates (progress_bar->frame_buffer); } void -ply_progress_bar_show (ply_progress_bar_t *progress_bar, - ply_window_t *window, - long x, - long y) +ply_progress_bar_draw (ply_progress_bar_t *progress_bar) +{ + if (progress_bar->is_hidden) + return; + + ply_progress_bar_update_area (progress_bar, progress_bar->area.x, progress_bar->area.y); + ply_pixel_display_draw_area (progress_bar->display, + progress_bar->area.x, + progress_bar->area.y, + progress_bar->area.width, + progress_bar->area.height); +} + +void +ply_progress_bar_show (ply_progress_bar_t *progress_bar, + ply_pixel_display_t *display, + long x, + long y) { assert (progress_bar != NULL); - progress_bar->window = window; - progress_bar->frame_buffer = ply_window_get_frame_buffer (window);; + progress_bar->display = display; ply_progress_bar_update_area (progress_bar, x, y); @@ -155,12 +165,16 @@ ply_progress_bar_show (ply_progress_bar_t *progress_bar, void ply_progress_bar_hide (ply_progress_bar_t *progress_bar) { - erase_progress_bar_area (progress_bar); - - progress_bar->frame_buffer = NULL; - progress_bar->window = NULL; + if (progress_bar->is_hidden) + return; progress_bar->is_hidden = true; + ply_pixel_display_draw_area (progress_bar->display, + progress_bar->area.x, progress_bar->area.y, + progress_bar->area.width, progress_bar->area.height); + + progress_bar->display = NULL; + } bool diff --git a/src/libplybootsplash/ply-progress-bar.h b/src/libplybootsplash/ply-progress-bar.h index 7e865605..2fd80e0b 100644 --- a/src/libplybootsplash/ply-progress-bar.h +++ b/src/libplybootsplash/ply-progress-bar.h @@ -28,8 +28,8 @@ #include <unistd.h> #include "ply-event-loop.h" -#include "ply-frame-buffer.h" -#include "ply-window.h" +#include "ply-pixel-buffer.h" +#include "ply-pixel-display.h" typedef struct _ply_progress_bar ply_progress_bar_t; @@ -38,11 +38,17 @@ ply_progress_bar_t *ply_progress_bar_new (void); void ply_progress_bar_free (ply_progress_bar_t *bar); void ply_progress_bar_show (ply_progress_bar_t *bar, - ply_window_t *window, + ply_pixel_display_t *display, long x, long y); void ply_progress_bar_hide (ply_progress_bar_t *bar); void ply_progress_bar_draw (ply_progress_bar_t *bar); +void ply_progress_bar_draw_area (ply_progress_bar_t *bar, + ply_pixel_buffer_t *buffer, + long x, + long y, + unsigned long width, + unsigned long height); bool ply_progress_bar_is_hidden (ply_progress_bar_t *bar); long ply_progress_bar_get_width (ply_progress_bar_t *bar); diff --git a/src/libplybootsplash/ply-renderer-plugin.h b/src/libplybootsplash/ply-renderer-plugin.h new file mode 100644 index 00000000..6acb8928 --- /dev/null +++ b/src/libplybootsplash/ply-renderer-plugin.h @@ -0,0 +1,71 @@ +/* ply-renderer-plugin.h - plugin interface for ply_renderer_t + * + * 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_PLUGIN_H +#define PLY_RENDERER_PLUGIN_H + +#include <stdbool.h> +#include <stdint.h> +#include <unistd.h> + +#include "ply-console.h" +#include "ply-event-loop.h" +#include "ply-list.h" +#include "ply-region.h" +#include "ply-renderer.h" + +typedef struct _ply_renderer_plugin ply_renderer_plugin_t; +typedef struct _ply_renderer_backend ply_renderer_backend_t; + +typedef struct +{ + ply_renderer_backend_t * (* create_backend) (const char *device_name, + ply_terminal_t *terminal, + ply_console_t *console); + void (* destroy_backend) (ply_renderer_backend_t *backend); + bool (* open_device) (ply_renderer_backend_t *backend); + void (* close_device) (ply_renderer_backend_t *backend); + bool (* query_device) (ply_renderer_backend_t *backend); + bool (* map_to_device) (ply_renderer_backend_t *backend); + void (* unmap_from_device) (ply_renderer_backend_t *backend); + void (* flush_head) (ply_renderer_backend_t *backend, + ply_renderer_head_t *head); + + ply_list_t * (* get_heads) (ply_renderer_backend_t *backend); + + ply_pixel_buffer_t * (* get_buffer_for_head) (ply_renderer_backend_t *backend, + ply_renderer_head_t *head); + + ply_renderer_input_source_t * (* get_input_source) (ply_renderer_backend_t *backend); + bool (* open_input_source) (ply_renderer_backend_t *backend, + ply_renderer_input_source_t *input_source); + + void (* set_handler_for_input_source) (ply_renderer_backend_t *backend, + ply_renderer_input_source_t *input_source, + ply_renderer_input_source_handler_t handler, + void *user_data); + + void (* close_input_source) (ply_renderer_backend_t *backend, + ply_renderer_input_source_t *input_source); +} ply_renderer_plugin_interface_t; + +#endif /* PLY_RENDERER_PLUGIN_H */ +/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/libplybootsplash/ply-renderer.c b/src/libplybootsplash/ply-renderer.c new file mode 100644 index 00000000..5410feb8 --- /dev/null +++ b/src/libplybootsplash/ply-renderer.c @@ -0,0 +1,355 @@ +/* ply-renderer.c - renderer abstraction + * + * Copyright (C) 2006, 2007, 2008, 2009 Red Hat, Inc. + * 2008 Charlie Brej <cbrej@cs.man.ac.uk> + * + * 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: Charlie Brej <cbrej@cs.man.ac.uk> + * Kristian Høgsberg <krh@redhat.com> + * Ray Strode <rstrode@redhat.com> + */ +#include "config.h" +#include "ply-renderer.h" + +#include <assert.h> +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> + +#include "ply-renderer-plugin.h" +#include "ply-buffer.h" +#include "ply-console.h" +#include "ply-event-loop.h" +#include "ply-list.h" +#include "ply-logger.h" +#include "ply-utils.h" + +struct _ply_renderer +{ + ply_event_loop_t *loop; + ply_module_handle_t *module_handle; + const ply_renderer_plugin_interface_t *plugin_interface; + ply_renderer_backend_t *backend; + + char *device_name; + ply_terminal_t *terminal; + ply_console_t *console; +}; + +typedef const ply_renderer_plugin_interface_t * + (* get_backend_interface_function_t) (void); + +static void ply_renderer_unload_plugin (ply_renderer_t *renderer); + +ply_renderer_t * +ply_renderer_new (const char *device_name, + ply_terminal_t *terminal, + ply_console_t *console) +{ + ply_renderer_t *renderer; + + renderer = calloc (1, sizeof (struct _ply_renderer)); + + if (device_name != NULL) + renderer->device_name = strdup (device_name); + + renderer->terminal = terminal; + renderer->console = console; + + return renderer; +} + +void +ply_renderer_free (ply_renderer_t *renderer) +{ + if (renderer == NULL) + return; + + if (renderer->plugin_interface != NULL) + { + ply_trace ("Unloading renderer backend plugin"); + ply_renderer_unload_plugin (renderer); + } + + free (renderer->device_name); + free (renderer); +} + +static bool +ply_renderer_load_plugin (ply_renderer_t *renderer, + const char *module_path) +{ + assert (renderer != NULL); + + get_backend_interface_function_t get_renderer_backend_interface; + + renderer->module_handle = ply_open_module (module_path); + + if (renderer->module_handle == NULL) + return false; + + get_renderer_backend_interface = (get_backend_interface_function_t) + ply_module_look_up_function (renderer->module_handle, + "ply_renderer_backend_get_interface"); + + if (get_renderer_backend_interface == NULL) + { + ply_save_errno (); + ply_trace ("module '%s' is not a renderer plugin", + module_path); + ply_close_module (renderer->module_handle); + renderer->module_handle = NULL; + ply_restore_errno (); + return false; + } + + renderer->plugin_interface = get_renderer_backend_interface (); + + if (renderer->plugin_interface == NULL) + { + ply_trace ("module '%s' is not a valid renderer plugin", + module_path); + ply_save_errno (); + ply_close_module (renderer->module_handle); + renderer->module_handle = NULL; + ply_restore_errno (); + return false; + } + + renderer->backend = renderer->plugin_interface->create_backend (renderer->device_name, + renderer->terminal, + renderer->console); + + if (renderer->backend == NULL) + { + ply_save_errno (); + ply_trace ("module '%s' renderer backend could not be created", + module_path); + ply_close_module (renderer->module_handle); + renderer->module_handle = NULL; + ply_restore_errno (); + return false; + } + + return true; +} + +static void +ply_renderer_unload_plugin (ply_renderer_t *renderer) +{ + assert (renderer != NULL); + assert (renderer->plugin_interface != NULL); + assert (renderer->module_handle != NULL); + + ply_close_module (renderer->module_handle); + renderer->plugin_interface = NULL; + renderer->module_handle = NULL; +} + +static bool +ply_renderer_open_device (ply_renderer_t *renderer) +{ + assert (renderer != NULL); + assert (renderer->plugin_interface != NULL); + + return renderer->plugin_interface->open_device (renderer->backend); +} + +static void +ply_renderer_close_device (ply_renderer_t *renderer) +{ + assert (renderer != NULL); + assert (renderer->plugin_interface != NULL); + + renderer->plugin_interface->close_device (renderer->backend); +} + +static bool +ply_renderer_query_device (ply_renderer_t *renderer) +{ + assert (renderer != NULL); + assert (renderer->plugin_interface != NULL); + + return renderer->plugin_interface->query_device (renderer->backend); +} + +static bool +ply_renderer_map_to_device (ply_renderer_t *renderer) +{ + assert (renderer != NULL); + assert (renderer->plugin_interface != NULL); + + return renderer->plugin_interface->map_to_device (renderer->backend); +} + +static void +ply_renderer_unmap_from_device (ply_renderer_t *renderer) +{ + assert (renderer != NULL); + assert (renderer->plugin_interface != NULL); + + renderer->plugin_interface->unmap_from_device (renderer->backend); +} + +bool +ply_renderer_open (ply_renderer_t *renderer) +{ + int i; + + /* FIXME: at some point we may want to make this + * part more dynamic (so you don't have to edit this + * list to add a new renderer) + */ + const char *known_plugins[] = + { + PLYMOUTH_PLUGIN_PATH "renderers/drm.so", + PLYMOUTH_PLUGIN_PATH "renderers/frame-buffer.so", + NULL + }; + + for (i = 0; known_plugins[i] != NULL; i++) + { + const char *plugin_path; + + plugin_path = known_plugins[i]; + + if (!ply_renderer_load_plugin (renderer, plugin_path)) + continue; + + if (!ply_renderer_open_device (renderer)) + { + ply_trace ("could not open rendering device for plugin %s", + plugin_path); + ply_renderer_unload_plugin (renderer); + continue; + } + + if (!ply_renderer_query_device (renderer)) + { + ply_trace ("could not query rendering device for plugin %s", + plugin_path); + ply_renderer_unload_plugin (renderer); + continue; + } + + if (!ply_renderer_map_to_device (renderer)) + { + ply_trace ("could not map renderer to device for plugin %s", + plugin_path); + ply_renderer_unload_plugin (renderer); + continue; + } + return true; + } + + ply_trace ("could not find suitable rendering plugin"); + return false; +} + +void +ply_renderer_close (ply_renderer_t *renderer) +{ + ply_renderer_unmap_from_device (renderer); + ply_renderer_close_device (renderer); +} + +ply_list_t * +ply_renderer_get_heads (ply_renderer_t *renderer) +{ + assert (renderer->plugin_interface != NULL); + + return renderer->plugin_interface->get_heads (renderer->backend); +} + +ply_pixel_buffer_t * +ply_renderer_get_buffer_for_head (ply_renderer_t *renderer, + ply_renderer_head_t *head) +{ + assert (renderer != NULL); + assert (renderer->plugin_interface != NULL); + assert (head != NULL); + + return renderer->plugin_interface->get_buffer_for_head (renderer->backend, + head); +} + +void +ply_renderer_flush_head (ply_renderer_t *renderer, + ply_renderer_head_t *head) +{ + assert (renderer != NULL); + assert (renderer->plugin_interface != NULL); + assert (head != NULL); + + if (ply_console_get_active_vt (renderer->console) != + ply_terminal_get_vt_number (renderer->terminal)) + return; + + renderer->plugin_interface->flush_head (renderer->backend, head); +} + +ply_renderer_input_source_t * +ply_renderer_get_input_source (ply_renderer_t *renderer) +{ + assert (renderer != NULL); + assert (renderer->plugin_interface != NULL); + + return renderer->plugin_interface->get_input_source (renderer->backend); +} + +bool +ply_renderer_open_input_source (ply_renderer_t *renderer, + ply_renderer_input_source_t *input_source) +{ + assert (renderer != NULL); + assert (input_source != NULL); + + return renderer->plugin_interface->open_input_source (renderer->backend, + input_source); +} + +void +ply_renderer_set_handler_for_input_source (ply_renderer_t *renderer, + ply_renderer_input_source_t *input_source, + ply_renderer_input_source_handler_t handler, + void *user_data) +{ + assert (renderer != NULL); + assert (input_source != NULL); + + renderer->plugin_interface->set_handler_for_input_source (renderer->backend, + input_source, + handler, + user_data); +} + +void +ply_renderer_close_input_source (ply_renderer_t *renderer, + ply_renderer_input_source_t *input_source) +{ + assert (renderer != NULL); + assert (input_source != NULL); + + renderer->plugin_interface->close_input_source (renderer->backend, + input_source); +} + +/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/libplybootsplash/ply-renderer.h b/src/libplybootsplash/ply-renderer.h new file mode 100644 index 00000000..da03e8d8 --- /dev/null +++ b/src/libplybootsplash/ply-renderer.h @@ -0,0 +1,70 @@ +/* ply-renderer.h - rendering abstraction + * + * 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_H +#define PLY_RENDERER_H + +#include <stdbool.h> +#include <stdint.h> + +#include "ply-buffer.h" +#include "ply-console.h" +#include "ply-list.h" +#include "ply-pixel-buffer.h" +#include "ply-terminal.h" +#include "ply-utils.h" + +typedef struct _ply_renderer ply_renderer_t; +typedef struct _ply_renderer_head ply_renderer_head_t; +typedef struct _ply_renderer_input_source ply_renderer_input_source_t; + +typedef void (* ply_renderer_input_source_handler_t) (void *user_data, + ply_buffer_t *key_buffer, + ply_renderer_input_source_t *input_source); + +#ifndef PLY_HIDE_FUNCTION_DECLARATIONS +ply_renderer_t *ply_renderer_new (const char *device_name, + ply_terminal_t *terminal, + ply_console_t *console); +void ply_renderer_free (ply_renderer_t *renderer); +bool ply_renderer_open (ply_renderer_t *renderer); +void ply_renderer_close (ply_renderer_t *renderer); +ply_list_t *ply_renderer_get_heads (ply_renderer_t *renderer); +ply_pixel_buffer_t *ply_renderer_get_buffer_for_head (ply_renderer_t *renderer, + ply_renderer_head_t *head); + +void ply_renderer_flush_head (ply_renderer_t *renderer, + ply_renderer_head_t *head); + +ply_renderer_input_source_t *ply_renderer_get_input_source (ply_renderer_t *renderer); +bool ply_renderer_open_input_source (ply_renderer_t *renderer, + ply_renderer_input_source_t *input_source); +void ply_renderer_set_handler_for_input_source (ply_renderer_t *renderer, + ply_renderer_input_source_t *input_source, + ply_renderer_input_source_handler_t handler, + void *user_data); + +void ply_renderer_close_input_source (ply_renderer_t *renderer, + ply_renderer_input_source_t *input_source); +#endif + +#endif /* PLY_RENDERER_H */ +/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/libplybootsplash/ply-terminal.c b/src/libplybootsplash/ply-terminal.c new file mode 100644 index 00000000..41eab543 --- /dev/null +++ b/src/libplybootsplash/ply-terminal.c @@ -0,0 +1,513 @@ +/* ply-terminal.c - APIs for terminaling text + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: Ray Strode <rstrode@redhat.com> + */ +#include "config.h" +#include "ply-terminal.h" + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <termios.h> +#include <unistd.h> +#include <wchar.h> + +#include <linux/kd.h> +#include <linux/major.h> +#include <linux/vt.h> + +#include "ply-buffer.h" +#include "ply-event-loop.h" +#include "ply-list.h" +#include "ply-logger.h" +#include "ply-utils.h" + +#ifndef TEXT_PALETTE_SIZE +#define TEXT_PALETTE_SIZE 48 +#endif + +struct _ply_terminal +{ + ply_event_loop_t *loop; + + struct termios original_term_attributes; + + char *name; + int fd; + int vt_number; + + ply_fd_watch_t *fd_watch; + ply_terminal_color_t foreground_color; + ply_terminal_color_t background_color; + + uint8_t original_color_palette[TEXT_PALETTE_SIZE]; + uint8_t color_palette[TEXT_PALETTE_SIZE]; + + int number_of_rows; + int number_of_columns; + + uint32_t original_term_attributes_saved : 1; + uint32_t supports_text_color : 1; + uint32_t is_open : 1; +}; + +static bool ply_terminal_open_device (ply_terminal_t *terminal); + +ply_terminal_t * +ply_terminal_new (const char *device_name) +{ + ply_terminal_t *terminal; + + terminal = calloc (1, sizeof (ply_terminal_t)); + + terminal->loop = ply_event_loop_get_default (); + if (device_name != NULL) + { + if (strncmp (device_name, "/dev/", strlen ("/dev/")) == 0) + terminal->name = strdup (device_name); + else + asprintf (&terminal->name, "/dev/%s", device_name); + } + terminal->fd = -1; + terminal->vt_number = -1; + + return terminal; +} + +static void +ply_terminal_look_up_color_palette (ply_terminal_t *terminal) +{ + if (ioctl (terminal->fd, GIO_CMAP, terminal->color_palette) < 0) + terminal->supports_text_color = false; + else + terminal->supports_text_color = true; +} + +static bool +ply_terminal_change_color_palette (ply_terminal_t *terminal) +{ + if (!terminal->supports_text_color) + return true; + + if (ioctl (terminal->fd, PIO_CMAP, terminal->color_palette) < 0) + return false; + + return true; +} + +static void +ply_terminal_save_color_palette (ply_terminal_t *terminal) +{ + if (!terminal->supports_text_color) + return; + + memcpy (terminal->original_color_palette, terminal->color_palette, + TEXT_PALETTE_SIZE); +} + +static void +ply_terminal_restore_color_palette (ply_terminal_t *terminal) +{ + if (!terminal->supports_text_color) + return; + + memcpy (terminal->color_palette, terminal->original_color_palette, + TEXT_PALETTE_SIZE); + + ply_terminal_change_color_palette (terminal); +} + +void +ply_terminal_reset_colors (ply_terminal_t *terminal) +{ + assert (terminal != NULL); + + ply_terminal_restore_color_palette (terminal); +} + +bool +ply_terminal_set_unbuffered_input (ply_terminal_t *terminal) +{ + struct termios term_attributes; + + tcgetattr (terminal->fd, &term_attributes); + + if (!terminal->original_term_attributes_saved) + { + terminal->original_term_attributes = term_attributes; + terminal->original_term_attributes_saved = true; + } + + cfmakeraw (&term_attributes); + + /* Make \n return go to the beginning of the next line */ + term_attributes.c_oflag |= ONLCR; + + if (tcsetattr (terminal->fd, TCSAFLUSH, &term_attributes) != 0) + return false; + + return true; +} + +bool +ply_terminal_set_buffered_input (ply_terminal_t *terminal) +{ + struct termios term_attributes; + + tcgetattr (terminal->fd, &term_attributes); + + /* If someone already messed with the terminal settings, + * and they seem good enough, bail + */ + if (term_attributes.c_lflag & ICANON) + return true; + + /* If we don't know the original term attributes, or they were originally sucky, + * then invent some that are probably good enough. + */ + if (!terminal->original_term_attributes_saved || !(terminal->original_term_attributes.c_lflag & ICANON)) + { + term_attributes.c_iflag |= IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON; + term_attributes.c_oflag |= OPOST; + term_attributes.c_lflag |= ECHO | ECHONL | ICANON | ISIG | IEXTEN; + + if (tcsetattr (terminal->fd, TCSAFLUSH, &term_attributes) != 0) + return false; + + return true; + } + + if (tcsetattr (terminal->fd, TCSAFLUSH, &terminal->original_term_attributes) != 0) + return false; + + return true; +} + +void +ply_terminal_write (ply_terminal_t *terminal, + const char *format, + ...) +{ + va_list args; + char *string; + + assert (terminal != NULL); + assert (format != NULL); + + string = NULL; + va_start (args, format); + vasprintf (&string, format, args); + va_end (args); + + write (terminal->fd, string, strlen (string)); + free (string); +} + +static void +on_tty_disconnected (ply_terminal_t *terminal) +{ + ply_trace ("tty disconnected (fd %d)", terminal->fd); + terminal->fd_watch = NULL; + terminal->fd = -1; + + if (terminal->name != NULL) + { + ply_trace ("trying to reopen terminal '%s'", terminal->name); + ply_terminal_open_device (terminal); + } +} + +static int +get_active_vt (void) +{ + int console_fd; + struct vt_stat console_state = { 0 }; + + console_fd = open ("/dev/tty0", O_RDONLY | O_NOCTTY); + + if (console_fd < 0) + goto out; + + if (ioctl (console_fd, VT_GETSTATE, &console_state) < 0) + goto out; + +out: + if (console_fd >= 0) + close (console_fd); + + return console_state.v_active; +} + +static bool +ply_terminal_look_up_geometry (ply_terminal_t *terminal) +{ + struct winsize terminal_size; + + ply_trace ("looking up terminal text geometry"); + + if (ioctl (terminal->fd, TIOCGWINSZ, &terminal_size) < 0) + { + ply_trace ("could not read terminal text geometry: %m"); + terminal->number_of_columns = 80; + terminal->number_of_rows = 24; + return false; + } + + terminal->number_of_rows = terminal_size.ws_row; + terminal->number_of_columns = terminal_size.ws_col; + + ply_trace ("terminal is now %dx%d text cells", + terminal->number_of_columns, + terminal->number_of_rows); + + return true; +} + +static void +ply_terminal_check_for_vt (ply_terminal_t *terminal) +{ + int major_number, minor_number; + struct stat file_attributes; + + assert (terminal != NULL); + assert (terminal->fd >= 0); + + if (fstat (terminal->fd, &file_attributes) != 0) + return; + + major_number = major (file_attributes.st_rdev); + minor_number = minor (file_attributes.st_rdev); + + if (major_number == TTY_MAJOR) + terminal->vt_number = minor_number; + else + terminal->vt_number = -1; +} + +static bool +ply_terminal_open_device (ply_terminal_t *terminal) +{ + assert (terminal != NULL); + assert (terminal->name != NULL); + assert (terminal->fd < 0); + assert (terminal->fd_watch == NULL); + + terminal->fd = open (terminal->name, O_RDWR | O_NOCTTY); + + if (terminal->fd < 0) + return false; + + terminal->fd_watch = ply_event_loop_watch_fd (terminal->loop, terminal->fd, + PLY_EVENT_LOOP_FD_STATUS_NONE, + (ply_event_handler_t) NULL, + (ply_event_handler_t) on_tty_disconnected, + terminal); + + ply_terminal_check_for_vt (terminal); + + return true; +} + +bool +ply_terminal_open (ply_terminal_t *terminal) +{ + assert (terminal != NULL); + + if (terminal->name == NULL) + { + char tty_name[512] = ""; + + terminal->vt_number = get_active_vt (); + + if (readlink ("/proc/self/fd/0", tty_name, sizeof (tty_name) - 1) < 0) + { + ply_trace ("could not read tty name of fd 0"); + return false; + } + + terminal->name = strdup (tty_name); + } + + ply_trace ("trying to open terminal '%s'", terminal->name); + + if (!ply_terminal_open_device (terminal)) + { + ply_trace ("could not open %s : %m", terminal->name); + return false; + } + + if (!ply_terminal_set_unbuffered_input (terminal)) + ply_trace ("terminal '%s' will be line buffered", terminal->name); + + ply_terminal_look_up_geometry (terminal); + + ply_terminal_look_up_color_palette (terminal); + ply_terminal_save_color_palette (terminal); + + ply_event_loop_watch_signal (terminal->loop, + SIGWINCH, + (ply_event_handler_t) + ply_terminal_look_up_geometry, + terminal); + + terminal->is_open = true; + + return true; +} + +int +ply_terminal_get_fd (ply_terminal_t *terminal) +{ + return terminal->fd; +} + +bool +ply_terminal_is_open (ply_terminal_t *terminal) +{ + return terminal->is_open; +} + +void +ply_terminal_close (ply_terminal_t *terminal) +{ + terminal->is_open = false; + + ply_trace ("restoring color palette"); + ply_terminal_restore_color_palette (terminal); + + if (terminal->fd_watch != NULL) + { + ply_trace ("stop watching tty fd"); + ply_event_loop_stop_watching_fd (terminal->loop, terminal->fd_watch); + terminal->fd_watch = NULL; + } + + if (terminal->loop != NULL) + { + ply_trace ("stop watching SIGWINCH signal"); + ply_event_loop_stop_watching_signal (terminal->loop, SIGWINCH); + } + + ply_trace ("setting buffered input"); + ply_terminal_set_buffered_input (terminal); + + close (terminal->fd); + terminal->fd = -1; +} + +int +ply_terminal_get_number_of_columns (ply_terminal_t *terminal) +{ + return terminal->number_of_columns; +} + +int +ply_terminal_get_number_of_rows (ply_terminal_t *terminal) +{ + return terminal->number_of_rows; +} + +uint32_t +ply_terminal_get_color_hex_value (ply_terminal_t *terminal, + ply_terminal_color_t color) +{ + uint8_t red, green, blue; + uint32_t hex_value; + + assert (terminal != NULL); + assert (color <= PLY_TERMINAL_COLOR_WHITE); + + red = (uint8_t) *(terminal->color_palette + 3 * color); + green = (uint8_t) *(terminal->color_palette + 3 * color + 1); + blue = (uint8_t) *(terminal->color_palette + 3 * color + 2); + + hex_value = red << 16 | green << 8 | blue; + + return hex_value; +} + +void +ply_terminal_set_color_hex_value (ply_terminal_t *terminal, + ply_terminal_color_t color, + uint32_t hex_value) +{ + uint8_t red, green, blue; + + assert (terminal != NULL); + assert (color <= PLY_TERMINAL_COLOR_WHITE); + + red = (uint8_t) ((hex_value >> 16) & 0xff); + green = (uint8_t) ((hex_value >> 8) & 0xff); + blue = (uint8_t) (hex_value & 0xff); + + *(terminal->color_palette + 3 * color) = red; + *(terminal->color_palette + 3 * color + 1) = green; + *(terminal->color_palette + 3 * color + 2) = blue; + + ply_terminal_change_color_palette (terminal); +} + +bool +ply_terminal_supports_color (ply_terminal_t *terminal) +{ + return terminal->supports_text_color; +} + +static void +ply_terminal_detach_from_event_loop (ply_terminal_t *terminal) +{ + assert (terminal != NULL); + terminal->loop = NULL; + terminal->fd_watch = NULL; +} + +void +ply_terminal_free (ply_terminal_t *terminal) +{ + if (terminal == NULL) + return; + + free (terminal->name); + + if (terminal->loop != NULL) + ply_event_loop_stop_watching_for_exit (terminal->loop, + (ply_event_loop_exit_handler_t) + ply_terminal_detach_from_event_loop, + terminal); + + ply_terminal_close (terminal); + + free (terminal); +} + +int +ply_terminal_get_vt_number (ply_terminal_t *terminal) +{ + return terminal->vt_number; +} + +/* 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/libplybootsplash/ply-terminal.h b/src/libplybootsplash/ply-terminal.h new file mode 100644 index 00000000..21689d19 --- /dev/null +++ b/src/libplybootsplash/ply-terminal.h @@ -0,0 +1,82 @@ +/* ply-terminal.h - APIs for terminaling text + * + * 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_TERMINAL_H +#define PLY_TERMINAL_H + +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <unistd.h> + +#include "ply-buffer.h" +#include "ply-event-loop.h" + +typedef struct _ply_terminal ply_terminal_t; + +typedef enum +{ + PLY_TERMINAL_COLOR_BLACK = 0, + PLY_TERMINAL_COLOR_RED, + PLY_TERMINAL_COLOR_GREEN, + PLY_TERMINAL_COLOR_BROWN, + PLY_TERMINAL_COLOR_BLUE, + PLY_TERMINAL_COLOR_MAGENTA, + PLY_TERMINAL_COLOR_CYAN, + PLY_TERMINAL_COLOR_WHITE, + PLY_TERMINAL_COLOR_DEFAULT = PLY_TERMINAL_COLOR_WHITE + 2 +} ply_terminal_color_t; + +#ifndef PLY_HIDE_FUNCTION_DECLARATIONS +ply_terminal_t *ply_terminal_new (const char *device_name); + +void ply_terminal_free (ply_terminal_t *terminal); + +bool ply_terminal_open (ply_terminal_t *terminal); +int ply_terminal_get_fd (ply_terminal_t *terminal); +bool ply_terminal_is_open (ply_terminal_t *terminal); +void ply_terminal_close (ply_terminal_t *terminal); +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); + +__attribute__((__format__ (__printf__, 2, 3))) +void ply_terminal_write (ply_terminal_t *terminal, + const char *format, + ...); +int ply_terminal_get_number_of_columns (ply_terminal_t *terminal); +int ply_terminal_get_number_of_rows (ply_terminal_t *terminal); + +bool ply_terminal_supports_color (ply_terminal_t *terminal); +uint32_t ply_terminal_get_color_hex_value (ply_terminal_t *terminal, + ply_terminal_color_t color); + +void ply_terminal_set_color_hex_value (ply_terminal_t *terminal, + ply_terminal_color_t color, + uint32_t hex_value); + +int ply_terminal_get_vt_number (ply_terminal_t *terminal); + +#endif + +#endif /* PLY_TERMINAL_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/libplybootsplash/ply-text-display.c b/src/libplybootsplash/ply-text-display.c new file mode 100644 index 00000000..5639f241 --- /dev/null +++ b/src/libplybootsplash/ply-text-display.c @@ -0,0 +1,343 @@ +/* ply-text-display.c - APIs for displaying text + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: Ray Strode <rstrode@redhat.com> + */ +#include "config.h" +#include "ply-text-display.h" + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <wchar.h> + +#include "ply-buffer.h" +#include "ply-console.h" +#include "ply-event-loop.h" +#include "ply-list.h" +#include "ply-logger.h" +#include "ply-terminal.h" +#include "ply-utils.h" + +#ifndef CLEAR_SCREEN_SEQUENCE +#define CLEAR_SCREEN_SEQUENCE "\033[2J" +#endif + +#ifndef CLEAR_LINE_SEQUENCE +#define CLEAR_LINE_SEQUENCE "\033[2K\r\n" +#endif + +#ifndef BACKSPACE +#define BACKSPACE "\b\033[0K" +#endif + +#ifndef MOVE_CURSOR_SEQUENCE +#define MOVE_CURSOR_SEQUENCE "\033[%d;%df" +#endif + +#ifndef HIDE_CURSOR_SEQUENCE +#define HIDE_CURSOR_SEQUENCE "\033[?25l" +#endif + +#ifndef SHOW_CURSOR_SEQUENCE +#define SHOW_CURSOR_SEQUENCE "\033[?25h" +#endif + +#ifndef COLOR_SEQUENCE_FORMAT +#define COLOR_SEQUENCE_FORMAT "\033[%dm" +#endif + +#ifndef PAUSE_SEQUENCE +#define PAUSE_SEQUENCE "\023" +#endif + +#ifndef UNPAUSE_SEQUENCE +#define UNPAUSE_SEQUENCE "\021" +#endif + +#ifndef FOREGROUND_COLOR_BASE +#define FOREGROUND_COLOR_BASE 30 +#endif + +#ifndef BACKGROUND_COLOR_BASE +#define BACKGROUND_COLOR_BASE 40 +#endif + +#ifndef TEXT_PALETTE_SIZE +#define TEXT_PALETTE_SIZE 48 +#endif + +struct _ply_text_display +{ + ply_event_loop_t *loop; + + ply_terminal_t *terminal; + ply_console_t *console; + + ply_terminal_color_t foreground_color; + ply_terminal_color_t background_color; + + ply_text_display_draw_handler_t draw_handler; + void *draw_handler_user_data; +}; + +ply_text_display_t * +ply_text_display_new (ply_terminal_t *terminal, + ply_console_t *console) +{ + ply_text_display_t *display; + + display = calloc (1, sizeof (ply_text_display_t)); + + display->loop = NULL; + display->terminal = terminal; + display->console = console; + + return display; +} + +int +ply_text_display_get_number_of_columns (ply_text_display_t *display) +{ + return ply_terminal_get_number_of_columns (display->terminal); +} + +int +ply_text_display_get_number_of_rows (ply_text_display_t *display) +{ + return ply_terminal_get_number_of_rows (display->terminal); +} + +void +ply_text_display_set_cursor_position (ply_text_display_t *display, + int column, + int row) +{ + int number_of_columns; + int number_of_rows; + + number_of_columns = ply_text_display_get_number_of_columns (display); + number_of_rows = ply_text_display_get_number_of_rows (display); + + column = CLAMP (column, 0, number_of_columns - 1); + row = CLAMP (row, 0, number_of_rows - 1); + + ply_terminal_write (display->terminal, + MOVE_CURSOR_SEQUENCE, + row, column); +} + +void +ply_text_display_clear_screen (ply_text_display_t *display) +{ + if (ply_is_tracing ()) + return; + + ply_terminal_write (display->terminal, + CLEAR_SCREEN_SEQUENCE); + + ply_text_display_set_cursor_position (display, 0, 0); +} + +void +ply_text_display_clear_line (ply_text_display_t *display) +{ + + ply_terminal_write (display->terminal, + CLEAR_LINE_SEQUENCE); +} + +void +ply_text_display_remove_character (ply_text_display_t *display) +{ + ply_terminal_write (display->terminal, + BACKSPACE); +} + +void +ply_text_display_set_background_color (ply_text_display_t *display, + ply_terminal_color_t color) +{ + + ply_terminal_write (display->terminal, + COLOR_SEQUENCE_FORMAT, + BACKGROUND_COLOR_BASE + color); + + display->background_color = color; +} + +void +ply_text_display_set_foreground_color (ply_text_display_t *display, + ply_terminal_color_t color) +{ + ply_terminal_write (display->terminal, + COLOR_SEQUENCE_FORMAT, + FOREGROUND_COLOR_BASE + color); + + display->foreground_color = color; +} + +ply_terminal_color_t +ply_text_display_get_background_color (ply_text_display_t *display) +{ + return display->background_color; +} + +ply_terminal_color_t +ply_text_display_get_foreground_color (ply_text_display_t *display) +{ + return display->foreground_color; +} + +void +ply_text_display_draw_area (ply_text_display_t *display, + int x, + int y, + int width, + int height) +{ + if (display->draw_handler != NULL) + display->draw_handler (display->draw_handler_user_data, + display->terminal, + x, y, width, height); +} + +void +ply_text_display_hide_cursor (ply_text_display_t *display) +{ + ply_terminal_write (display->terminal, + HIDE_CURSOR_SEQUENCE); +} + +void +ply_text_display_write (ply_text_display_t *display, + const char *format, + ...) +{ + int fd; + + va_list args; + char *string; + + assert (display != NULL); + assert (format != NULL); + + fd = ply_terminal_get_fd (display->terminal); + + string = NULL; + va_start (args, format); + vasprintf (&string, format, args); + va_end (args); + + if (ply_terminal_get_vt_number (display->terminal) > 0) + ply_console_set_mode (display->console, PLY_CONSOLE_MODE_TEXT); + write (fd, string, strlen (string)); + free (string); +} + +void +ply_text_display_show_cursor (ply_text_display_t *display) +{ + ply_terminal_write (display->terminal, + SHOW_CURSOR_SEQUENCE); +} + +bool +ply_text_display_supports_color (ply_text_display_t *display) +{ + return ply_terminal_supports_color (display->terminal); +} + +static void +ply_text_display_detach_from_event_loop (ply_text_display_t *display) +{ + assert (display != NULL); + display->loop = NULL; +} + +void +ply_text_display_free (ply_text_display_t *display) +{ + if (display == NULL) + return; + + if (display->loop != NULL) + ply_event_loop_stop_watching_for_exit (display->loop, + (ply_event_loop_exit_handler_t) + ply_text_display_detach_from_event_loop, + display); + + free (display); +} + +void +ply_text_display_set_draw_handler (ply_text_display_t *display, + ply_text_display_draw_handler_t draw_handler, + void *user_data) +{ + assert (display != NULL); + + display->draw_handler = draw_handler; + display->draw_handler_user_data = user_data; +} + +void +ply_text_display_pause_updates (ply_text_display_t *display) +{ + ply_terminal_write (display->terminal, + PAUSE_SEQUENCE); +} + +void +ply_text_display_unpause_updates (ply_text_display_t *display) +{ + ply_terminal_write (display->terminal, + UNPAUSE_SEQUENCE); +} + +void +ply_text_display_attach_to_event_loop (ply_text_display_t *display, + ply_event_loop_t *loop) +{ + assert (display != NULL); + assert (loop != NULL); + assert (display->loop == NULL); + + display->loop = loop; + + ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t) + ply_text_display_detach_from_event_loop, + display); +} + +ply_terminal_t * +ply_text_display_get_terminal (ply_text_display_t *display) +{ + return display->terminal; +} + +/* 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/libplybootsplash/ply-text-display.h b/src/libplybootsplash/ply-text-display.h new file mode 100644 index 00000000..8c6870ad --- /dev/null +++ b/src/libplybootsplash/ply-text-display.h @@ -0,0 +1,91 @@ +/* ply-text-display.h - APIs for displaying text + * + * 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_TEXT_DISPLAY_H +#define PLY_TEXT_DISPLAY_H + +#include <stdbool.h> +#include <stdint.h> +#include <unistd.h> + +#include "ply-buffer.h" +#include "ply-console.h" +#include "ply-event-loop.h" +#include "ply-terminal.h" + +typedef struct _ply_text_display ply_text_display_t; + +typedef void (* ply_text_display_draw_handler_t) (void *user_data, + ply_terminal_t *terminal, + int column, + int row, + int number_of_columns, + int number_of_rows); + +#ifndef PLY_HIDE_FUNCTION_DECLARATIONS +ply_text_display_t *ply_text_display_new (ply_terminal_t *terminal, + ply_console_t *console); + +void ply_text_display_free (ply_text_display_t *display); + +void ply_text_display_attach_to_event_loop (ply_text_display_t *display, + ply_event_loop_t *loop); + +ply_terminal_t *ply_text_display_get_terminal (ply_text_display_t *display); + +int ply_text_display_get_number_of_rows (ply_text_display_t *display); +int ply_text_display_get_number_of_columns (ply_text_display_t *display); +void ply_text_display_set_cursor_position (ply_text_display_t *display, + int column, + int row); +__attribute__((__format__ (__printf__, 2, 3))) +void ply_text_display_write (ply_text_display_t *display, + const char *format, + ...); +void ply_text_display_hide_cursor (ply_text_display_t *display); +void ply_text_display_show_cursor (ply_text_display_t *display); +void ply_text_display_clear_screen (ply_text_display_t *display); +void ply_text_display_clear_line (ply_text_display_t *display); +void ply_text_display_remove_character (ply_text_display_t *display); +bool ply_text_display_supports_color (ply_text_display_t *display); +void ply_text_display_set_background_color (ply_text_display_t *display, + ply_terminal_color_t color); +void ply_text_display_set_foreground_color (ply_text_display_t *display, + ply_terminal_color_t color); +ply_terminal_color_t ply_text_display_get_background_color (ply_text_display_t *display); +ply_terminal_color_t ply_text_display_get_foreground_color (ply_text_display_t *display); + +void ply_text_display_draw_area (ply_text_display_t *display, + int column, + int row, + int number_of_columns, + int number_of_rows); + +void ply_text_display_set_draw_handler (ply_text_display_t *display, + ply_text_display_draw_handler_t draw_handler, + void *user_data); +void ply_text_display_pause_updates (ply_text_display_t *display); +void ply_text_display_unpause_updates (ply_text_display_t *display); + +#endif + +#endif /* PLY_TEXT_DISPLAY_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/libplybootsplash/ply-text-progress-bar.c b/src/libplybootsplash/ply-text-progress-bar.c index 1f972067..b7676c91 100644 --- a/src/libplybootsplash/ply-text-progress-bar.c +++ b/src/libplybootsplash/ply-text-progress-bar.c @@ -43,11 +43,11 @@ #include <unistd.h> #include <wchar.h> +#include "ply-text-display.h" #include "ply-text-progress-bar.h" #include "ply-array.h" #include "ply-logger.h" #include "ply-utils.h" -#include "ply-window.h" #include <linux/kd.h> @@ -61,7 +61,7 @@ static char *os_string; struct _ply_text_progress_bar { - ply_window_t *window; + ply_text_display_t *display; int column, row; int number_of_rows; @@ -124,16 +124,15 @@ out: void ply_text_progress_bar_draw (ply_text_progress_bar_t *progress_bar) { - int i, width = progress_bar->number_of_columns - 2 - strlen(os_string); + int i, width = progress_bar->number_of_columns - 2 - strlen (os_string); double brown_fraction, blue_fraction, white_fraction; if (progress_bar->is_hidden) return; - ply_window_set_mode (progress_bar->window, PLY_WINDOW_MODE_TEXT); - ply_window_set_text_cursor_position(progress_bar->window, - progress_bar->column, - progress_bar->row); + ply_text_display_set_cursor_position (progress_bar->display, + progress_bar->column, + progress_bar->row); brown_fraction = - (progress_bar->percent_done * progress_bar->percent_done) + 2 * progress_bar->percent_done; blue_fraction = progress_bar->percent_done; @@ -144,56 +143,56 @@ ply_text_progress_bar_draw (ply_text_progress_bar_t *progress_bar) f = (double) i / (double) width; if (f < white_fraction) - ply_window_set_background_color (progress_bar->window, - PLY_WINDOW_COLOR_WHITE); + ply_text_display_set_background_color (progress_bar->display, + PLY_TERMINAL_COLOR_WHITE); else if (f < blue_fraction) - ply_window_set_background_color (progress_bar->window, - PLY_WINDOW_COLOR_BLUE); + ply_text_display_set_background_color (progress_bar->display, + PLY_TERMINAL_COLOR_BLUE); else if (f < brown_fraction) - ply_window_set_background_color (progress_bar->window, - PLY_WINDOW_COLOR_BROWN); + ply_text_display_set_background_color (progress_bar->display, + PLY_TERMINAL_COLOR_BROWN); else break; - write (STDOUT_FILENO, " ", strlen (" ")); + ply_text_display_write (progress_bar->display, "%c", ' '); } - ply_window_set_background_color (progress_bar->window, PLY_WINDOW_COLOR_BLACK); + ply_text_display_set_background_color (progress_bar->display, + PLY_TERMINAL_COLOR_BLACK); if (brown_fraction > 0.5) { if (white_fraction > 0.875) - ply_window_set_foreground_color (progress_bar->window, - PLY_WINDOW_COLOR_WHITE); + ply_text_display_set_foreground_color (progress_bar->display, + PLY_TERMINAL_COLOR_WHITE); else if (blue_fraction > 0.66) - ply_window_set_foreground_color (progress_bar->window, - PLY_WINDOW_COLOR_BLUE); + ply_text_display_set_foreground_color (progress_bar->display, + PLY_TERMINAL_COLOR_BLUE); else - ply_window_set_foreground_color (progress_bar->window, - PLY_WINDOW_COLOR_BROWN); + ply_text_display_set_foreground_color (progress_bar->display, + PLY_TERMINAL_COLOR_BROWN); - ply_window_set_text_cursor_position(progress_bar->window, - progress_bar->column + width, - progress_bar->row); + ply_text_display_set_cursor_position (progress_bar->display, + progress_bar->column + width, + progress_bar->row); + ply_text_display_write (progress_bar->display, "%s", os_string); - write (STDOUT_FILENO, os_string, strlen(os_string)); - - ply_window_set_foreground_color (progress_bar->window, - PLY_WINDOW_COLOR_DEFAULT); + ply_text_display_set_foreground_color (progress_bar->display, + PLY_TERMINAL_COLOR_DEFAULT); } } void ply_text_progress_bar_show (ply_text_progress_bar_t *progress_bar, - ply_window_t *window) + ply_text_display_t *display) { assert (progress_bar != NULL); - progress_bar->window = window; + progress_bar->display = display; - progress_bar->number_of_rows = ply_window_get_number_of_text_rows(window); + progress_bar->number_of_rows = ply_text_display_get_number_of_rows (display); progress_bar->row = progress_bar->number_of_rows - 1; - progress_bar->number_of_columns = ply_window_get_number_of_text_columns(window); + progress_bar->number_of_columns = ply_text_display_get_number_of_columns (display); progress_bar->column = 2; get_os_string (); @@ -206,7 +205,7 @@ ply_text_progress_bar_show (ply_text_progress_bar_t *progress_bar, void ply_text_progress_bar_hide (ply_text_progress_bar_t *progress_bar) { - progress_bar->window = NULL; + progress_bar->display = NULL; progress_bar->is_hidden = true; } diff --git a/src/libplybootsplash/ply-text-progress-bar.h b/src/libplybootsplash/ply-text-progress-bar.h index d3a43b66..ebf0644b 100644 --- a/src/libplybootsplash/ply-text-progress-bar.h +++ b/src/libplybootsplash/ply-text-progress-bar.h @@ -29,7 +29,7 @@ #include <unistd.h> #include "ply-event-loop.h" -#include "ply-window.h" +#include "ply-text-display.h" typedef struct _ply_text_progress_bar ply_text_progress_bar_t; @@ -39,7 +39,7 @@ void ply_text_progress_bar_free (ply_text_progress_bar_t *progress_bar); void ply_text_progress_bar_draw (ply_text_progress_bar_t *progress_bar); void ply_text_progress_bar_show (ply_text_progress_bar_t *progress_bar, - ply_window_t *window); + ply_text_display_t *display); void ply_text_progress_bar_hide (ply_text_progress_bar_t *progress_bar); void ply_text_progress_bar_set_percent_done (ply_text_progress_bar_t *progress_bar, diff --git a/src/libplybootsplash/ply-throbber.c b/src/libplybootsplash/ply-throbber.c index 7c2d3327..9131e715 100644 --- a/src/libplybootsplash/ply-throbber.c +++ b/src/libplybootsplash/ply-throbber.c @@ -42,12 +42,12 @@ #include "ply-throbber.h" #include "ply-event-loop.h" +#include "ply-pixel-buffer.h" +#include "ply-pixel-display.h" #include "ply-array.h" #include "ply-logger.h" -#include "ply-frame-buffer.h" #include "ply-image.h" #include "ply-utils.h" -#include "ply-window.h" #include <linux/kd.h> @@ -62,14 +62,15 @@ struct _ply_throbber char *image_dir; char *frames_prefix; - ply_window_t *window; - ply_frame_buffer_t *frame_buffer; - ply_frame_buffer_area_t frame_area; + ply_pixel_display_t *display; + ply_rectangle_t frame_area; ply_trigger_t *stop_trigger; long x, y; long width, height; - double start_time, previous_time, now; + double start_time, now; + + int frame_number; uint32_t is_stopped : 1; }; @@ -94,6 +95,7 @@ ply_throbber_new (const char *image_dir, throbber->frame_area.height = 0; throbber->frame_area.x = 0; throbber->frame_area.y = 0; + throbber->frame_number = 0; return throbber; } @@ -124,27 +126,14 @@ ply_throbber_free (ply_throbber_t *throbber) free (throbber); } -static void -draw_background (ply_throbber_t *throbber) -{ - ply_window_erase_area (throbber->window, - throbber->x, throbber->y, - throbber->frame_area.width, - throbber->frame_area.height); -} - static bool animate_at_time (ply_throbber_t *throbber, double time) { int number_of_frames; - int frame_number; ply_image_t * const * frames; - uint32_t *frame_data; bool should_continue; - ply_window_set_mode (throbber->window, PLY_WINDOW_MODE_GRAPHICS); - number_of_frames = ply_array_get_size (throbber->frames); if (number_of_frames == 0) @@ -152,31 +141,24 @@ animate_at_time (ply_throbber_t *throbber, should_continue = true; - frame_number = (.5 * sin (time) + .5) * number_of_frames; + throbber->frame_number = (.5 * sin (time) + .5) * number_of_frames; if (throbber->stop_trigger != NULL) { - if ((time - throbber->previous_time) >= 2 * M_PI) - frame_number = number_of_frames - 1; - should_continue = false; + if (throbber->frame_number == number_of_frames - 1) + should_continue = false; } - ply_frame_buffer_pause_updates (throbber->frame_buffer); - if (throbber->frame_area.width > 0) - draw_background (throbber); - frames = (ply_image_t * const *) ply_array_get_elements (throbber->frames); throbber->frame_area.x = throbber->x; throbber->frame_area.y = throbber->y; - throbber->frame_area.width = ply_image_get_width (frames[frame_number]); - throbber->frame_area.height = ply_image_get_height (frames[frame_number]); - frame_data = ply_image_get_data (frames[frame_number]); - - ply_frame_buffer_fill_with_argb32_data (throbber->frame_buffer, - &throbber->frame_area, 0, 0, - frame_data); - ply_frame_buffer_unpause_updates (throbber->frame_buffer); + throbber->frame_area.width = ply_image_get_width (frames[throbber->frame_number]); + throbber->frame_area.height = ply_image_get_height (frames[throbber->frame_number]); + ply_pixel_display_draw_area (throbber->display, + throbber->x, throbber->y, + throbber->frame_area.width, + throbber->frame_area.height); return should_continue; } @@ -186,7 +168,6 @@ on_timeout (ply_throbber_t *throbber) { double sleep_time; bool should_continue; - throbber->previous_time = throbber->now; throbber->now = ply_get_timestamp (); #ifdef REAL_TIME_ANIMATION @@ -204,9 +185,6 @@ on_timeout (ply_throbber_t *throbber) if (!should_continue) { - - draw_background (throbber); - if (throbber->stop_trigger != NULL) { ply_trigger_pull (throbber->stop_trigger, NULL); @@ -313,18 +291,17 @@ ply_throbber_load (ply_throbber_t *throbber) } bool -ply_throbber_start (ply_throbber_t *throbber, - ply_event_loop_t *loop, - ply_window_t *window, - long x, - long y) +ply_throbber_start (ply_throbber_t *throbber, + ply_event_loop_t *loop, + ply_pixel_display_t *display, + long x, + long y) { assert (throbber != NULL); assert (throbber->loop == NULL); throbber->loop = loop; - throbber->window = window; - throbber->frame_buffer = ply_window_get_frame_buffer (window);; + throbber->display = display; throbber->is_stopped = false; throbber->x = x; @@ -343,13 +320,13 @@ ply_throbber_start (ply_throbber_t *throbber, static void ply_throbber_stop_now (ply_throbber_t *throbber) { - if (throbber->frame_area.width > 0) - draw_background (throbber); - - throbber->frame_buffer = NULL; - throbber->window = NULL; throbber->is_stopped = true; + ply_pixel_display_draw_area (throbber->display, + throbber->x, + throbber->y, + throbber->frame_area.width, + throbber->frame_area.height); if (throbber->loop != NULL) { ply_event_loop_stop_watching_for_timeout (throbber->loop, @@ -357,6 +334,7 @@ ply_throbber_stop_now (ply_throbber_t *throbber) on_timeout, throbber); throbber->loop = NULL; } + throbber->display = NULL; } void @@ -379,6 +357,28 @@ ply_throbber_is_stopped (ply_throbber_t *throbber) return throbber->is_stopped; } +void +ply_throbber_draw_area (ply_throbber_t *throbber, + ply_pixel_buffer_t *buffer, + long x, + long y, + unsigned long width, + unsigned long height) +{ + ply_image_t * const * frames; + uint32_t *frame_data; + + if (throbber->is_stopped) + return; + + frames = (ply_image_t * const *) ply_array_get_elements (throbber->frames); + frame_data = ply_image_get_data (frames[throbber->frame_number]); + + ply_pixel_buffer_fill_with_argb32_data (buffer, + &throbber->frame_area, 0, 0, + frame_data); +} + long ply_throbber_get_width (ply_throbber_t *throbber) { diff --git a/src/libplybootsplash/ply-throbber.h b/src/libplybootsplash/ply-throbber.h index 647f409c..272a7d92 100644 --- a/src/libplybootsplash/ply-throbber.h +++ b/src/libplybootsplash/ply-throbber.h @@ -27,9 +27,9 @@ #include <unistd.h> #include "ply-event-loop.h" -#include "ply-frame-buffer.h" +#include "ply-pixel-buffer.h" +#include "ply-pixel-display.h" #include "ply-trigger.h" -#include "ply-window.h" typedef struct _ply_throbber ply_throbber_t; @@ -40,14 +40,21 @@ void ply_throbber_free (ply_throbber_t *throbber); bool ply_throbber_load (ply_throbber_t *throbber); bool ply_throbber_start (ply_throbber_t *throbber, - ply_event_loop_t *loop, - ply_window_t *window, - long x, - long y); + ply_event_loop_t *loop, + ply_pixel_display_t *display, + long x, + long y); void ply_throbber_stop (ply_throbber_t *throbber, ply_trigger_t *stop_trigger); bool ply_throbber_is_stopped (ply_throbber_t *throbber); +void ply_throbber_draw_area (ply_throbber_t *throbber, + ply_pixel_buffer_t *buffer, + long x, + long y, + unsigned long width, + unsigned long height); + long ply_throbber_get_width (ply_throbber_t *throbber); long ply_throbber_get_height (ply_throbber_t *throbber); #endif diff --git a/src/libplybootsplash/ply-window.c b/src/libplybootsplash/ply-window.c deleted file mode 100644 index 27328930..00000000 --- a/src/libplybootsplash/ply-window.c +++ /dev/null @@ -1,1156 +0,0 @@ -/* ply-window.h - APIs for putting up a window screen - * - * Copyright (C) 2007 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-window.h" - -#include <assert.h> -#include <errno.h> -#include <fcntl.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <termios.h> -#include <unistd.h> -#include <wchar.h> - -#include <linux/kd.h> -#include <linux/vt.h> - -#include "ply-buffer.h" -#include "ply-event-loop.h" -#include "ply-frame-buffer.h" -#include "ply-list.h" -#include "ply-logger.h" -#include "ply-utils.h" - -#define KEY_CTRL_L ('\100' ^'L') -#define KEY_CTRL_P ('\100' ^'P') -#define KEY_CTRL_T ('\100' ^'T') -#define KEY_CTRL_U ('\100' ^'U') -#define KEY_CTRL_W ('\100' ^'W') -#define KEY_CTRL_V ('\100' ^'V') -#define KEY_ESCAPE ('\100' ^'[') -#define KEY_RETURN '\r' -#define KEY_BACKSPACE '\177' - -#ifndef CLEAR_SCREEN_SEQUENCE -#define CLEAR_SCREEN_SEQUENCE "\033[2J" -#endif - -#ifndef CLEAR_LINE_SEQUENCE -#define CLEAR_LINE_SEQUENCE "\033[2K\r\n" -#endif - -#ifndef BACKSPACE -#define BACKSPACE "\b\033[0K" -#endif - -#ifndef MOVE_CURSOR_SEQUENCE -#define MOVE_CURSOR_SEQUENCE "\033[%d;%df" -#endif - -#ifndef HIDE_CURSOR_SEQUENCE -#define HIDE_CURSOR_SEQUENCE "\033[?25l" -#endif - -#ifndef SHOW_CURSOR_SEQUENCE -#define SHOW_CURSOR_SEQUENCE "\033[?25h" -#endif - -#ifndef COLOR_SEQUENCE_FORMAT -#define COLOR_SEQUENCE_FORMAT "\033[%dm" -#endif - -#ifndef FOREGROUND_COLOR_BASE -#define FOREGROUND_COLOR_BASE 30 -#endif - -#ifndef BACKGROUND_COLOR_BASE -#define BACKGROUND_COLOR_BASE 40 -#endif - -#ifndef TEXT_PALETTE_SIZE -#define TEXT_PALETTE_SIZE 48 -#endif - -typedef void (* ply_window_handler_t) (void *); - -typedef struct -{ - ply_window_handler_t *function; - void *user_data; -} ply_window_closure_t; - -struct _ply_window -{ - ply_event_loop_t *loop; - ply_buffer_t *keyboard_input_buffer; - ply_buffer_t *line_buffer; - - struct termios original_term_attributes; - - ply_frame_buffer_t *frame_buffer; - - char *tty_name; - int tty_fd; - int vt_number; - - ply_fd_watch_t *tty_fd_watch; - ply_window_mode_t mode; - ply_window_color_t foreground_color; - ply_window_color_t background_color; - - uint8_t original_color_palette[TEXT_PALETTE_SIZE]; - uint8_t color_palette[TEXT_PALETTE_SIZE]; - - int number_of_text_rows; - int number_of_text_columns; - - uint32_t should_force_text_mode : 1; - uint32_t original_term_attributes_saved : 1; - uint32_t supports_text_color : 1; - uint32_t is_open : 1; - - ply_list_t *keyboard_input_handler_list; - ply_list_t *backspace_handler_list; - ply_list_t *escape_handler_list; - ply_list_t *enter_handler_list; - - ply_window_draw_handler_t draw_handler; - void *draw_handler_user_data; - - ply_window_erase_handler_t erase_handler; - void *erase_handler_user_data; -}; - -static bool ply_window_open_tty (ply_window_t *window); - -ply_window_t * -ply_window_new (const char *tty_name) -{ - ply_window_t *window; - - window = calloc (1, sizeof (ply_window_t)); - window->keyboard_input_buffer = ply_buffer_new (); - window->line_buffer = ply_buffer_new (); - window->frame_buffer = ply_frame_buffer_new (NULL); - window->keyboard_input_handler_list = ply_list_new(); - window->backspace_handler_list = ply_list_new(); - window->escape_handler_list = ply_list_new(); - window->enter_handler_list = ply_list_new(); - - window->loop = NULL; - if (tty_name != NULL) - { - if (strncmp (tty_name, "/dev/", strlen ("/dev/")) == 0) - window->tty_name = strdup (tty_name); - else - asprintf (&window->tty_name, "/dev/%s", tty_name); - } - window->tty_fd = -1; - - return window; -} - -static void -ply_window_look_up_color_palette (ply_window_t *window) -{ - if (ioctl (window->tty_fd, GIO_CMAP, window->color_palette) < 0) - window->supports_text_color = false; - else - window->supports_text_color = true; -} - -static bool -ply_window_change_color_palette (ply_window_t *window) -{ - if (!window->supports_text_color) - return true; - - if (ioctl (window->tty_fd, PIO_CMAP, window->color_palette) < 0) - return false; - - return true; -} - -static void -ply_window_save_color_palette (ply_window_t *window) -{ - if (!window->supports_text_color) - return; - - memcpy (window->original_color_palette, window->color_palette, - TEXT_PALETTE_SIZE); -} - -static void -ply_window_restore_color_palette (ply_window_t *window) -{ - if (!window->supports_text_color) - return; - - memcpy (window->color_palette, window->original_color_palette, - TEXT_PALETTE_SIZE); - - ply_window_change_color_palette (window); -} - -void -ply_window_reset_colors (ply_window_t *window) -{ - assert (window != NULL); - - ply_window_restore_color_palette (window); -} - -static void -process_backspace (ply_window_t *window) -{ - size_t bytes_to_remove; - ssize_t previous_character_size; - const char *bytes; - size_t size; - ply_list_node_t *node; - - bytes = ply_buffer_get_bytes (window->line_buffer); - size = ply_buffer_get_size (window->line_buffer); - - bytes_to_remove = MIN(size, PLY_UTF8_CHARACTER_SIZE_MAX); - while ((previous_character_size = ply_utf8_character_get_size (bytes + size - bytes_to_remove, bytes_to_remove)) < (ssize_t) bytes_to_remove) - { - if (previous_character_size > 0) - bytes_to_remove -= previous_character_size; - else - bytes_to_remove--; - } - - if (bytes_to_remove <= size) - { - ply_buffer_remove_bytes_at_end (window->line_buffer, bytes_to_remove); - } - - for (node = ply_list_get_first_node(window->backspace_handler_list); - node; node = ply_list_get_next_node(window->backspace_handler_list, node)) - { - ply_window_closure_t *closure = ply_list_node_get_data (node); - ply_window_backspace_handler_t backspace_handler = - (ply_window_backspace_handler_t) closure->function; - backspace_handler (closure->user_data); - } -} - -static void -process_line_erase (ply_window_t *window) -{ - size_t size; - - while ((size = ply_buffer_get_size (window->line_buffer)) > 0) - process_backspace (window); -} - -static void -process_keyboard_input (ply_window_t *window, - const char *keyboard_input, - size_t character_size) -{ - wchar_t key; - ply_list_node_t *node; - - if ((ssize_t) mbrtowc (&key, keyboard_input, character_size, NULL) > 0) - { - switch (key) - { - - case KEY_CTRL_L: - if (ply_frame_buffer_device_is_open (window->frame_buffer)) - { - ply_frame_buffer_area_t area; - - ply_trace ("redrawing screen"); - - ply_frame_buffer_get_size (window->frame_buffer, &area); - ply_window_draw_area (window, area.x, area.y, - area.width, area.height); - } - return; - - case KEY_CTRL_P: - ply_trace ("restore text palette to original value!"); - ply_window_restore_color_palette (window); - return; - - case KEY_CTRL_T: - ply_trace ("toggle text mode!"); - window->should_force_text_mode = !window->should_force_text_mode; - ply_window_set_mode (window, window->mode); - ply_trace ("text mode toggled!"); - return; - - case KEY_CTRL_U: - case KEY_CTRL_W: - ply_trace ("erase line!"); - process_line_erase (window); - return; - - case KEY_CTRL_V: - ply_trace ("toggle verbose mode!"); - ply_toggle_tracing (); - ply_trace ("verbose mode toggled!"); - return; - - case KEY_ESCAPE: - ply_trace ("escape key!"); - for (node = ply_list_get_first_node(window->escape_handler_list); - node; node = ply_list_get_next_node(window->escape_handler_list, node)) - { - ply_window_closure_t *closure = ply_list_node_get_data (node); - ply_window_escape_handler_t escape_handler = (ply_window_escape_handler_t) closure->function; - escape_handler (closure->user_data); - } - - ply_trace ("end escape key handler"); - return; - - case KEY_BACKSPACE: - ply_trace ("backspace key!"); - process_backspace (window); - return; - - case KEY_RETURN: - ply_trace ("return key!"); - - for (node = ply_list_get_first_node(window->enter_handler_list); - node; node = ply_list_get_next_node(window->enter_handler_list, node)) - { - ply_window_closure_t *closure = ply_list_node_get_data (node); - ply_window_enter_handler_t enter_handler = (ply_window_enter_handler_t) closure->function; - enter_handler (closure->user_data, ply_buffer_get_bytes (window->line_buffer)); - } - ply_buffer_clear (window->line_buffer); - return; - - default: - ply_buffer_append_bytes (window->line_buffer, - keyboard_input, character_size); - break; - } - } - for (node = ply_list_get_first_node(window->keyboard_input_handler_list); - node; node = ply_list_get_next_node(window->keyboard_input_handler_list, node)) - { - ply_window_closure_t *closure = ply_list_node_get_data (node); - ply_window_keyboard_input_handler_t keyboard_input_handler = - (ply_window_keyboard_input_handler_t) closure->function; - - keyboard_input_handler (closure->user_data, - keyboard_input, character_size); - } -} - -static void -check_buffer_for_key_events (ply_window_t *window) -{ - const char *bytes; - size_t size, i; - - bytes = ply_buffer_get_bytes (window->keyboard_input_buffer); - size = ply_buffer_get_size (window->keyboard_input_buffer); - - i = 0; - while (i < size) - { - ssize_t character_size; - char *keyboard_input; - - character_size = (ssize_t) ply_utf8_character_get_size (bytes + i, size - i); - - if (character_size < 0) - break; - - /* If we're at a NUL character walk through it - */ - if (character_size == 0) - { - i++; - continue; - } - - keyboard_input = strndup (bytes + i, character_size); - - process_keyboard_input (window, keyboard_input, character_size); - - free (keyboard_input); - - i += character_size; - } - - if (i > 0) - ply_buffer_remove_bytes (window->keyboard_input_buffer, i); -} - -static void -on_key_event (ply_window_t *window) -{ - ply_buffer_append_from_fd (window->keyboard_input_buffer, window->tty_fd); - - check_buffer_for_key_events (window); -} - -static void -on_tty_disconnected (ply_window_t *window) -{ - ply_trace ("tty disconnected (fd %d)", window->tty_fd); - window->tty_fd_watch = NULL; - window->tty_fd = -1; - - if (window->tty_name != NULL) - { - ply_trace ("trying to reopen window '%s'", window->tty_name); - ply_window_open_tty (window); - } -} - -static bool -ply_window_set_unbuffered_input (ply_window_t *window) -{ - struct termios term_attributes; - - tcgetattr (window->tty_fd, &term_attributes); - - if (!window->original_term_attributes_saved) - { - window->original_term_attributes = term_attributes; - window->original_term_attributes_saved = true; - } - - cfmakeraw (&term_attributes); - - /* Make \n return go to the beginning of the next line */ - term_attributes.c_oflag |= ONLCR; - - if (tcsetattr (window->tty_fd, TCSAFLUSH, &term_attributes) != 0) - return false; - - return true; -} - -static bool -ply_window_set_buffered_input (ply_window_t *window) -{ - struct termios term_attributes; - - tcgetattr (window->tty_fd, &term_attributes); - - /* If someone already messed with the terminal settings, - * and they seem good enough, bail - */ - if (term_attributes.c_lflag & ICANON) - return true; - - /* If we don't know the original term attributes, or they were originally sucky, - * then invent some that are probably good enough. - */ - if (!window->original_term_attributes_saved || !(window->original_term_attributes.c_lflag & ICANON)) - { - term_attributes.c_iflag |= IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON; - term_attributes.c_oflag |= OPOST; - term_attributes.c_lflag |= ECHO | ECHONL | ICANON | ISIG | IEXTEN; - - if (tcsetattr (window->tty_fd, TCSAFLUSH, &term_attributes) != 0) - return false; - - return true; - } - - if (tcsetattr (window->tty_fd, TCSAFLUSH, &window->original_term_attributes) != 0) - return false; - - return true; -} - -static int -get_active_vt (void) -{ - int console_fd; - struct vt_stat console_state = { 0 }; - - console_fd = open ("/dev/tty0", O_RDONLY | O_NOCTTY); - - if (console_fd < 0) - goto out; - - if (ioctl (console_fd, VT_GETSTATE, &console_state) < 0) - goto out; - -out: - if (console_fd >= 0) - close (console_fd); - - return console_state.v_active; -} - -static bool -ply_window_look_up_geometry (ply_window_t *window) -{ - struct winsize window_size; - - ply_trace ("looking up window text geometry"); - - if (ioctl (window->tty_fd, TIOCGWINSZ, &window_size) < 0) - { - ply_trace ("could not read window text geometry: %m"); - window->number_of_text_columns = 80; - window->number_of_text_rows = 24; - return false; - } - - window->number_of_text_rows = window_size.ws_row; - window->number_of_text_columns = window_size.ws_col; - - ply_trace ("window is now %dx%d text cells", - window->number_of_text_columns, - window->number_of_text_rows); - - return true; -} - -static bool -ply_window_open_tty (ply_window_t *window) -{ - assert (window != NULL); - assert (window->tty_name != NULL); - assert (window->tty_fd < 0); - assert (window->tty_fd_watch == NULL); - - window->tty_fd = open (window->tty_name, O_RDWR | O_NOCTTY); - - if (window->tty_fd < 0) - return false; - - if (window->loop != NULL) - window->tty_fd_watch = ply_event_loop_watch_fd (window->loop, window->tty_fd, - PLY_EVENT_LOOP_FD_STATUS_HAS_DATA, - (ply_event_handler_t) on_key_event, - (ply_event_handler_t) on_tty_disconnected, - window); - - return true; -} - -bool -ply_window_open (ply_window_t *window) -{ - assert (window != NULL); - - if (window->tty_name == NULL) - { - char tty_name[512] = ""; - - window->vt_number = get_active_vt (); - - if (readlink ("/proc/self/fd/0", tty_name, sizeof (tty_name) - 1) < 0) - { - ply_trace ("could not read tty name of fd 0"); - return false; - } - - window->tty_name = strdup (tty_name); - } - - ply_trace ("trying to open window '%s'", window->tty_name); - - if (!ply_window_open_tty (window)) - { - ply_trace ("could not open %s : %m", window->tty_name); - return false; - } - - if (!ply_window_set_unbuffered_input (window)) - ply_trace ("window '%s' will be line buffered", window->tty_name); - - ply_window_set_mode (window, PLY_WINDOW_MODE_TEXT); - - ply_window_look_up_geometry (window); - - ply_window_look_up_color_palette (window); - ply_window_save_color_palette (window); - - ply_event_loop_watch_signal (window->loop, - SIGWINCH, - (ply_event_handler_t) - ply_window_look_up_geometry, - window); - - /* We try to open the frame buffer, but it may fail. splash plugins can check - * to see if it's open and react accordingly - */ - ply_frame_buffer_open (window->frame_buffer); - - window->is_open = true; - - return true; -} - -bool -ply_window_is_open (ply_window_t *window) -{ - return window->is_open; -} - -void -ply_window_close (ply_window_t *window) -{ - window->is_open = false; - - ply_trace ("restoring color palette"); - ply_window_restore_color_palette (window); - - if (ply_frame_buffer_device_is_open (window->frame_buffer)) - { - ply_trace ("closing frame buffer"); - ply_frame_buffer_close (window->frame_buffer); - } - - if (window->tty_fd_watch != NULL) - { - ply_trace ("stop watching tty fd"); - ply_event_loop_stop_watching_fd (window->loop, window->tty_fd_watch); - window->tty_fd_watch = NULL; - } - - if (window->loop != NULL) - { - ply_trace ("stop watching SIGWINCH signal"); - ply_event_loop_stop_watching_signal (window->loop, SIGWINCH); - } - - ply_trace ("setting buffered input"); - ply_window_set_buffered_input (window); - - close (window->tty_fd); - window->tty_fd = -1; -} - -bool -ply_window_set_mode (ply_window_t *window, - ply_window_mode_t mode) -{ - assert (window != NULL); - assert (mode == PLY_WINDOW_MODE_TEXT || mode == PLY_WINDOW_MODE_GRAPHICS); - - switch (mode) - { - case PLY_WINDOW_MODE_TEXT: - if (ioctl (window->tty_fd, KDSETMODE, KD_TEXT) < 0) - return false; - break; - - case PLY_WINDOW_MODE_GRAPHICS: - if (!ply_frame_buffer_device_is_open (window->frame_buffer) - && !ply_frame_buffer_open (window->frame_buffer)) - return false; - - if (ioctl (window->tty_fd, KDSETMODE, - window->should_force_text_mode? KD_TEXT : KD_GRAPHICS) < 0) - return false; - break; - } - ply_window_set_unbuffered_input (window); - - window->mode = mode; - return true; -} - -int -ply_window_get_tty_fd (ply_window_t *window) -{ - return window->tty_fd; -} - -int -ply_window_get_number_of_text_rows (ply_window_t *window) -{ - return window->number_of_text_rows; -} - -int -ply_window_get_number_of_text_columns (ply_window_t *window) -{ - return window->number_of_text_columns; -} - -void -ply_window_set_text_cursor_position (ply_window_t *window, - int column, - int row) -{ - char *sequence; - column = MAX(column, 0); - row = MAX(row, 0); - sequence = NULL; - asprintf (&sequence, MOVE_CURSOR_SEQUENCE, row, column); - write (window->tty_fd, sequence, strlen (sequence)); - free (sequence); -} - -void -ply_window_clear_screen (ply_window_t *window) -{ - if (ply_is_tracing ()) - return; - - if (ply_frame_buffer_device_is_open (window->frame_buffer)) - ply_frame_buffer_fill_with_color (window->frame_buffer, NULL, 0.0, 0.0, 0.0, 1.0); - - write (window->tty_fd, CLEAR_SCREEN_SEQUENCE, strlen (CLEAR_SCREEN_SEQUENCE)); - - ply_window_set_text_cursor_position (window, 0, 0); -} - -void -ply_window_clear_text_line (ply_window_t *window) -{ - write (window->tty_fd, CLEAR_LINE_SEQUENCE, strlen (CLEAR_LINE_SEQUENCE)); -} - -void -ply_window_clear_text_character (ply_window_t *window) -{ - write (window->tty_fd, BACKSPACE, strlen (BACKSPACE)); -} - -void -ply_window_set_background_color (ply_window_t *window, - ply_window_color_t color) -{ - char *sequence; - - sequence = NULL; - asprintf (&sequence, COLOR_SEQUENCE_FORMAT, - BACKGROUND_COLOR_BASE + color); - write (window->tty_fd, sequence, strlen (sequence)); - free (sequence); - - window->background_color = color; -} - -void -ply_window_set_foreground_color (ply_window_t *window, - ply_window_color_t color) -{ - char *sequence; - - sequence = NULL; - asprintf (&sequence, COLOR_SEQUENCE_FORMAT, - FOREGROUND_COLOR_BASE + color); - write (window->tty_fd, sequence, strlen (sequence)); - free (sequence); - - window->foreground_color = color; -} - -ply_window_color_t -ply_window_get_background_color (ply_window_t *window) -{ - return window->background_color; -} - -ply_window_color_t -ply_window_get_foreground_color (ply_window_t *window) -{ - return window->foreground_color; -} - -void -ply_window_draw_area (ply_window_t *window, - int x, - int y, - int width, - int height) -{ - if (window->draw_handler != NULL) - window->draw_handler (window->draw_handler_user_data, - x, y, width, height); -} - -void -ply_window_erase_area (ply_window_t *window, - int x, - int y, - int width, - int height) -{ - if (window->erase_handler != NULL) - window->erase_handler (window->erase_handler_user_data, - x, y, width, height); -} - -uint32_t -ply_window_get_color_hex_value (ply_window_t *window, - ply_window_color_t color) -{ - uint8_t red, green, blue; - uint32_t hex_value; - - assert (window != NULL); - assert (color <= PLY_WINDOW_COLOR_WHITE); - - red = (uint8_t) *(window->color_palette + 3 * color); - green = (uint8_t) *(window->color_palette + 3 * color + 1); - blue = (uint8_t) *(window->color_palette + 3 * color + 2); - - hex_value = red << 16 | green << 8 | blue; - - return hex_value; -} - -void -ply_window_set_color_hex_value (ply_window_t *window, - ply_window_color_t color, - uint32_t hex_value) -{ - uint8_t red, green, blue; - - assert (window != NULL); - assert (color <= PLY_WINDOW_COLOR_WHITE); - - red = (uint8_t) ((hex_value >> 16) & 0xff); - green = (uint8_t) ((hex_value >> 8) & 0xff); - blue = (uint8_t) (hex_value & 0xff); - - *(window->color_palette + 3 * color) = red; - *(window->color_palette + 3 * color + 1) = green; - *(window->color_palette + 3 * color + 2) = blue; - - ply_window_change_color_palette (window); -} - -void -ply_window_hide_text_cursor (ply_window_t *window) -{ - write (window->tty_fd, HIDE_CURSOR_SEQUENCE, strlen (HIDE_CURSOR_SEQUENCE)); -} - -void -ply_window_show_text_cursor (ply_window_t *window) -{ - write (window->tty_fd, SHOW_CURSOR_SEQUENCE, strlen (SHOW_CURSOR_SEQUENCE)); -} - -bool -ply_window_supports_text_color (ply_window_t *window) -{ - return window->supports_text_color; -} - -static void -ply_window_detach_from_event_loop (ply_window_t *window) -{ - assert (window != NULL); - window->loop = NULL; - window->tty_fd_watch = NULL; -} - -void -ply_window_free (ply_window_t *window) -{ - if (window == NULL) - return; - free(window->tty_name); - - if (window->loop != NULL) - ply_event_loop_stop_watching_for_exit (window->loop, - (ply_event_loop_exit_handler_t) - ply_window_detach_from_event_loop, - window); - - ply_window_close (window); - - ply_buffer_free (window->keyboard_input_buffer); - ply_buffer_free (window->line_buffer); - - ply_frame_buffer_free (window->frame_buffer); - - free (window); -} - -static ply_window_closure_t * -ply_window_closure_new(void* function, void* user_data) -{ - ply_window_closure_t *closure = calloc (1, sizeof (ply_window_closure_t)); - closure->function = function; - closure->user_data = user_data; - return closure; -} - - -static void -ply_window_closure_free(ply_window_closure_t* closure) -{ - free(closure); -} - -void -ply_window_add_keyboard_input_handler (ply_window_t *window, - ply_window_keyboard_input_handler_t input_handler, - void *user_data) -{ - assert (window != NULL); - ply_window_closure_t *closure = ply_window_closure_new(input_handler, user_data); - ply_list_append_data (window->keyboard_input_handler_list, closure); -} - - -void -ply_window_remove_keyboard_input_handler (ply_window_t *window, - ply_window_keyboard_input_handler_t input_handler) -{ - ply_list_node_t *node; - assert (window != NULL); - for (node = ply_list_get_first_node(window->keyboard_input_handler_list); - node; node = ply_list_get_next_node(window->keyboard_input_handler_list, node)) - { - ply_window_closure_t *closure = ply_list_node_get_data (node); - if ((ply_window_keyboard_input_handler_t) closure->function == input_handler) - { - ply_window_closure_free(closure); - ply_list_remove_node (window->keyboard_input_handler_list, node); - return; - } - } -} - -void -ply_window_add_backspace_handler (ply_window_t *window, - ply_window_backspace_handler_t backspace_handler, - void *user_data) -{ - assert (window != NULL); - ply_window_closure_t *closure = ply_window_closure_new(backspace_handler, user_data); - ply_list_append_data (window->backspace_handler_list, closure); -} - - -void -ply_window_remove_backspace_handler (ply_window_t *window, - ply_window_backspace_handler_t backspace_handler) -{ - ply_list_node_t *node; - assert (window != NULL); - for (node = ply_list_get_first_node(window->backspace_handler_list); - node; node = ply_list_get_next_node(window->backspace_handler_list, node)) - { - ply_window_closure_t *closure = ply_list_node_get_data (node); - if ((ply_window_backspace_handler_t) closure->function == backspace_handler) - { - ply_window_closure_free(closure); - ply_list_remove_node (window->backspace_handler_list, node); - return; - } - } -} - -void -ply_window_add_escape_handler (ply_window_t *window, - ply_window_escape_handler_t escape_handler, - void *user_data) -{ - assert (window != NULL); - ply_window_closure_t *closure = ply_window_closure_new(escape_handler, user_data); - ply_list_append_data (window->escape_handler_list, closure); -} - - -void -ply_window_remove_escape_handler (ply_window_t *window, - ply_window_escape_handler_t escape_handler) -{ - assert (window != NULL); - ply_list_node_t *node; - assert (window != NULL); - for (node = ply_list_get_first_node(window->escape_handler_list); - node; node = ply_list_get_next_node(window->escape_handler_list, node)) - { - ply_window_closure_t *closure = ply_list_node_get_data (node); - if ((ply_window_escape_handler_t) closure->function == escape_handler) - { - ply_window_closure_free(closure); - ply_list_remove_node (window->escape_handler_list, node); - return; - } - } -} - -void -ply_window_add_enter_handler (ply_window_t *window, - ply_window_enter_handler_t enter_handler, - void *user_data) -{ - assert (window != NULL); - ply_window_closure_t *closure = ply_window_closure_new(enter_handler, user_data); - ply_list_append_data (window->enter_handler_list, closure); -} - - -void -ply_window_remove_enter_handler (ply_window_t *window, - ply_window_enter_handler_t enter_handler) -{ - assert (window != NULL); - ply_list_node_t *node; - assert (window != NULL); - for (node = ply_list_get_first_node(window->enter_handler_list); - node; node = ply_list_get_next_node(window->enter_handler_list, node)) - { - ply_window_closure_t *closure = ply_list_node_get_data (node); - if ((ply_window_enter_handler_t) closure->function == enter_handler) - { - ply_window_closure_free(closure); - ply_list_remove_node (window->enter_handler_list, node); - return; - } - } -} - -void -ply_window_set_draw_handler (ply_window_t *window, - ply_window_draw_handler_t draw_handler, - void *user_data) -{ - assert (window != NULL); - - window->draw_handler = draw_handler; - window->draw_handler_user_data = user_data; -} - -void -ply_window_set_erase_handler (ply_window_t *window, - ply_window_erase_handler_t erase_handler, - void *user_data) -{ - assert (window != NULL); - - window->erase_handler = erase_handler; - window->erase_handler_user_data = user_data; -} - -void -ply_window_attach_to_event_loop (ply_window_t *window, - ply_event_loop_t *loop) -{ - assert (window != NULL); - assert (loop != NULL); - assert (window->loop == NULL); - - window->loop = loop; - - ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t) - ply_window_detach_from_event_loop, - window); -} - -ply_frame_buffer_t * -ply_window_get_frame_buffer (ply_window_t *window) -{ - return window->frame_buffer; -} - -#ifdef PLY_WINDOW_ENABLE_TEST - -#include <stdio.h> - -#include "ply-event-loop.h" -#include "ply-window.h" - -static void -on_timeout (ply_window_t *window, - ply_event_loop_t *loop) -{ - ply_event_loop_exit (loop, 0); -} - -static void -on_keypress (ply_window_t *window, - const char *keyboard_input) -{ - printf ("key '%c' (0x%x) was pressed\n", - keyboard_input[0], (unsigned int) keyboard_input[0]); -} - -int -main (int argc, - char **argv) -{ - ply_event_loop_t *loop; - ply_window_t *window; - int exit_code; - const char *tty_name; - - exit_code = 0; - - loop = ply_event_loop_new (); - - if (argc > 1) - tty_name = argv[1]; - else - tty_name = "/dev/tty1"; - - window = ply_window_new (tty_name); - ply_window_attach_to_event_loop (window, loop); - ply_window_add_keyboard_input_handler (window, - (ply_window_keyboard_input_handler_t) - on_keypress, window); - - if (!ply_window_open (window)) - { - ply_save_errno (); - perror ("could not open window"); - ply_restore_errno (); - return errno; - } - - if (!ply_window_set_mode (window, PLY_WINDOW_MODE_TEXT)) - { - ply_save_errno (); - perror ("could not set window for graphics mode"); - ply_restore_errno (); - } - - ply_event_loop_watch_for_timeout (loop, - 15.0, - (ply_event_loop_timeout_handler_t) - on_timeout, - window); - exit_code = ply_event_loop_run (loop); - - ply_window_close (window); - ply_window_free (window); - - return exit_code; -} - -#endif /* PLY_WINDOW_ENABLE_TEST */ -/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/libplybootsplash/ply-window.h b/src/libplybootsplash/ply-window.h deleted file mode 100644 index 9b8fee79..00000000 --- a/src/libplybootsplash/ply-window.h +++ /dev/null @@ -1,165 +0,0 @@ -/* ply-window.h - APIs for putting up a splash screen - * - * Copyright (C) 2008 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Written By: Ray Strode <rstrode@redhat.com> - */ -#ifndef PLY_WINDOW_H -#define PLY_WINDOW_H - -#include <stdbool.h> -#include <stdint.h> -#include <unistd.h> - -#include "ply-buffer.h" -#include "ply-event-loop.h" -#include "ply-frame-buffer.h" - -typedef struct _ply_window ply_window_t; - -typedef void (* ply_window_keyboard_input_handler_t) (void *user_data, - const char *keyboard_input, - size_t character_size); - -typedef void (* ply_window_backspace_handler_t) (void *user_data); -typedef void (* ply_window_escape_handler_t) (void *user_data); -typedef void (* ply_window_enter_handler_t) (void *user_data, - const char *line); - -typedef void (* ply_window_draw_handler_t) (void *user_data, - int x, - int y, - int width, - int height); -typedef void (* ply_window_erase_handler_t) (void *user_data, - int x, - int y, - int width, - int height); - -typedef enum -{ - PLY_WINDOW_MODE_TEXT, - PLY_WINDOW_MODE_GRAPHICS -} ply_window_mode_t; - -typedef enum -{ - PLY_WINDOW_COLOR_BLACK = 0, - PLY_WINDOW_COLOR_RED, - PLY_WINDOW_COLOR_GREEN, - PLY_WINDOW_COLOR_BROWN, - PLY_WINDOW_COLOR_BLUE, - PLY_WINDOW_COLOR_MAGENTA, - PLY_WINDOW_COLOR_CYAN, - PLY_WINDOW_COLOR_WHITE, - PLY_WINDOW_COLOR_DEFAULT = PLY_WINDOW_COLOR_WHITE + 2 -} ply_window_color_t; - -#ifndef PLY_HIDE_FUNCTION_DECLARATIONS -ply_window_t *ply_window_new (const char *name); -void ply_window_free (ply_window_t *window); - -void ply_window_add_keyboard_input_handler (ply_window_t *window, - ply_window_keyboard_input_handler_t input_handler, - void *user_data); -void ply_window_remove_keyboard_input_handler (ply_window_t *window, - ply_window_keyboard_input_handler_t input_handler); -void ply_window_add_backspace_handler (ply_window_t *window, - ply_window_backspace_handler_t backspace_handler, - void *user_data); -void ply_window_remove_backspace_handler (ply_window_t *window, - ply_window_backspace_handler_t backspace_handler); -void ply_window_add_escape_handler (ply_window_t *window, - ply_window_escape_handler_t escape_handler, - void *user_data); -void ply_window_remove_escape_handler (ply_window_t *window, - ply_window_escape_handler_t escape_handler); -void ply_window_add_enter_handler (ply_window_t *window, - ply_window_enter_handler_t enter_handler, - void *user_data); -void ply_window_remove_enter_handler (ply_window_t *window, - ply_window_enter_handler_t enter_handler); -void ply_window_add_draw_handler (ply_window_t *window, - ply_window_draw_handler_t draw_handler, - void *user_data); -void ply_window_remove_draw_handler (ply_window_t *window, - ply_window_draw_handler_t draw_handler); -void ply_window_add_erase_handler (ply_window_t *window, - ply_window_erase_handler_t erase_handler, - void *user_data); -void ply_window_remove_erase_handler (ply_window_t *window, - ply_window_erase_handler_t erase_handler); - -bool ply_window_open (ply_window_t *window); -bool ply_window_is_open (ply_window_t *window); -void ply_window_close (ply_window_t *window); -bool ply_window_set_mode (ply_window_t *window, - ply_window_mode_t mode); -int ply_window_get_tty_fd (ply_window_t *window); -int ply_window_get_number_of_text_rows (ply_window_t *window); -int ply_window_get_number_of_text_columns (ply_window_t *window); -void ply_window_set_text_cursor_position (ply_window_t *window, - int column, - int row); -void ply_window_hide_text_cursor (ply_window_t *window); -void ply_window_show_text_cursor (ply_window_t *window); -void ply_window_clear_screen (ply_window_t *window); -void ply_window_clear_text_line (ply_window_t *window); -void ply_window_clear_text_character (ply_window_t *window); -bool ply_window_supports_text_color (ply_window_t *window); -void ply_window_set_background_color (ply_window_t *window, - ply_window_color_t color); -void ply_window_set_foreground_color (ply_window_t *window, - ply_window_color_t color); -ply_window_color_t ply_window_get_background_color (ply_window_t *window); -ply_window_color_t ply_window_get_foreground_color (ply_window_t *window); - -void ply_window_draw_area (ply_window_t *window, - int x, - int y, - int width, - int height); - -void ply_window_erase_area (ply_window_t *window, - int x, - int y, - int width, - int height); - -uint32_t ply_window_get_color_hex_value (ply_window_t *window, - ply_window_color_t color); -void ply_window_set_color_hex_value (ply_window_t *window, - ply_window_color_t color, - uint32_t hex_value); -void ply_window_reset_colors (ply_window_t *window); - -void ply_window_set_draw_handler (ply_window_t *window, - ply_window_draw_handler_t draw_handler, - void *user_data); -void ply_window_set_erase_handler (ply_window_t *window, - ply_window_erase_handler_t erase_handler, - void *user_data); -void ply_window_attach_to_event_loop (ply_window_t *window, - ply_event_loop_t *loop); -ply_frame_buffer_t *ply_window_get_frame_buffer (ply_window_t *window); - -#endif - -#endif /* PLY_WINDOW_H */ -/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ @@ -79,8 +79,11 @@ typedef struct typedef struct { ply_event_loop_t *loop; + ply_console_t *console; ply_boot_server_t *boot_server; - ply_list_t *windows; + ply_list_t *pixel_displays; + ply_list_t *text_displays; + ply_keyboard_t *keyboard; ply_boot_splash_t *boot_splash; ply_terminal_session_t *session; ply_buffer_t *boot_buffer; @@ -90,6 +93,7 @@ typedef struct ply_buffer_t *entry_buffer; ply_command_parser_t *command_parser; ply_mode_t mode; + ply_renderer_t *renderer; ply_trigger_t *quit_trigger; @@ -104,6 +108,7 @@ typedef struct char *kernel_console_tty; char *override_splash_path; + const char *default_tty; int number_of_errors; } state_t; @@ -111,8 +116,10 @@ typedef struct static ply_boot_splash_t *start_boot_splash (state_t *state, const char *theme_path); -static ply_window_t *create_window (state_t *state, - const char *tty_name); +static void add_display_and_keyboard_for_terminal (state_t *state, + const char *tty_name); + +static void add_default_displays_and_keyboard (state_t *state); static bool attach_to_running_session (state_t *state); static void on_escape_pressed (state_t *state); @@ -461,47 +468,6 @@ on_error (state_t *state) } static bool -has_open_window (state_t *state) -{ - ply_list_node_t *node; - - ply_trace ("checking for open windows"); - - node = ply_list_get_first_node (state->windows); - while (node != NULL) - { - ply_list_node_t *next_node; - ply_window_t *window; - - next_node = ply_list_get_next_node (state->windows, node); - - window = ply_list_node_get_data (node); - - if (ply_window_is_open (window)) - { - int fd; - const char *name; - - fd = ply_window_get_tty_fd (window); - - if (fd >= 0) - name = ttyname (fd); - else - name = NULL; - - ply_trace ("window %s%sis open", - name != NULL? name : "", - name != NULL? " " : ""); - return true; - } - - node = next_node; - } - - return false; -} - -static bool plymouth_should_ignore_show_splash_calls (state_t *state) { ply_trace ("checking if plymouth should be running"); @@ -526,9 +492,6 @@ plymouth_should_show_default_splash (state_t *state) if (state->kernel_console_tty != NULL) return false; - if (!has_open_window (state)) - return false; - for (i = 0; strings[i] != NULL; i++) { int cmp; @@ -549,53 +512,47 @@ plymouth_should_show_default_splash (state_t *state) } static void -open_windows (state_t *state) +remove_displays_and_keyboard (state_t *state) { ply_list_node_t *node; - node = ply_list_get_first_node (state->windows); + node = ply_list_get_first_node (state->pixel_displays); while (node != NULL) { ply_list_node_t *next_node; - ply_window_t *window; - - next_node = ply_list_get_next_node (state->windows, node); + ply_pixel_display_t *display; - window = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (state->pixel_displays, node); + display = ply_list_node_get_data (node); + ply_pixel_display_free (display); - if (!ply_window_is_open (window)) - ply_window_open (window); + ply_list_remove_node (state->pixel_displays, node); node = next_node; } -} -static void -close_windows (state_t *state) -{ - ply_list_node_t *node; - - node = ply_list_get_first_node (state->windows); + node = ply_list_get_first_node (state->text_displays); while (node != NULL) { ply_list_node_t *next_node; - ply_window_t *window; + ply_text_display_t *display; - next_node = ply_list_get_next_node (state->windows, node); + next_node = ply_list_get_next_node (state->text_displays, node); + display = ply_list_node_get_data (node); + ply_text_display_free (display); - window = ply_list_node_get_data (node); - - if (ply_window_is_open (window)) - ply_window_close (window); + ply_list_remove_node (state->text_displays, node); node = next_node; } + + state->keyboard = NULL; } static void on_show_splash (state_t *state) { - bool has_window; + bool has_display; if (plymouth_should_ignore_show_splash_calls (state)) { @@ -603,16 +560,15 @@ on_show_splash (state_t *state) return; } - open_windows (state); - - has_window = has_open_window (state); + has_display = ply_list_get_length (state->pixel_displays) > 0 || + ply_list_get_length (state->text_displays) > 0; - if (!state->is_attached && state->should_be_attached && has_window) + if (!state->is_attached && state->should_be_attached && has_display) attach_to_running_session (state); - if (!has_window && state->is_attached) + if (!has_display && state->is_attached) { - ply_trace ("no open windows, detaching session"); + ply_trace ("no open seats, detaching session"); ply_terminal_session_detach (state->session); state->is_redirected = false; state->is_attached = false; @@ -641,8 +597,15 @@ quit_splash (state_t *state) state->boot_splash = NULL; } - ply_trace ("closing windows"); - close_windows (state); + ply_trace ("removing displays and keyboard"); + remove_displays_and_keyboard (state); + + if (state->renderer != NULL) + { + ply_renderer_close (state->renderer); + ply_renderer_free (state->renderer); + state->renderer = NULL; + } if (state->session != NULL) { @@ -927,43 +890,166 @@ on_enter (state_t *state, } } -static ply_window_t * -create_window (state_t *state, - const char *tty_name) +static void +set_keyboard (state_t *state, + ply_keyboard_t *keyboard) +{ + state->keyboard = keyboard; + + ply_keyboard_add_escape_handler (keyboard, (ply_keyboard_escape_handler_t) + on_escape_pressed, state); + ply_trace ("listening for keystrokes"); + ply_keyboard_add_input_handler (keyboard, + (ply_keyboard_input_handler_t) + on_keyboard_input, state); + ply_trace ("listening for backspace"); + ply_keyboard_add_backspace_handler (keyboard, + (ply_keyboard_backspace_handler_t) + on_backspace, state); + ply_trace ("listening for enter"); + ply_keyboard_add_enter_handler (keyboard, + (ply_keyboard_enter_handler_t) + on_enter, state); + ply_keyboard_watch_for_input (keyboard); +} +static void +add_display_and_keyboard_for_terminal (state_t *state, + const char *tty_name) { - ply_window_t *window; + ply_terminal_t *terminal; + ply_text_display_t *display; + ply_keyboard_t *keyboard; - ply_trace ("creating window on %s", tty_name != NULL? tty_name : "active vt"); - window = ply_window_new (tty_name); + ply_trace ("adding display and keyboard for %s", tty_name); - ply_window_attach_to_event_loop (window, state->loop); + terminal = ply_terminal_new (tty_name); - return window; + if (!ply_terminal_open (terminal)) + { + ply_trace ("could not open terminal '%s': %m", tty_name); + ply_terminal_free (terminal); + return; + } + + ply_console_set_active_vt (state->console, + ply_terminal_get_vt_number (terminal)); + + keyboard = ply_keyboard_new_for_terminal (terminal); + display = ply_text_display_new (terminal, state->console); + + ply_list_append_data (state->text_displays, display); + state->keyboard = keyboard; + set_keyboard (state, keyboard); } static void -add_windows_to_boot_splash (state_t *state, - ply_boot_splash_t *splash) +add_pixel_displays_from_renderer (state_t *state, + ply_renderer_t *renderer) { + ply_list_t *heads; ply_list_node_t *node; - ply_trace ("There are %d windows in list", - ply_list_get_length (state->windows)); - node = ply_list_get_first_node (state->windows); + heads = ply_renderer_get_heads (renderer); + + node = ply_list_get_first_node (heads); while (node != NULL) { ply_list_node_t *next_node; - ply_window_t *window; + ply_renderer_head_t *head; + ply_pixel_display_t *display; - next_node = ply_list_get_next_node (state->windows, node); + head = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (heads, node); - window = ply_list_node_get_data (node); + display = ply_pixel_display_new (renderer, head); + + ply_list_append_data (state->pixel_displays, display); + + node = next_node; + } + +} + +static void +add_default_displays_and_keyboard (state_t *state) +{ + ply_renderer_t *renderer; + ply_keyboard_t *keyboard; + ply_terminal_t *terminal; + ply_text_display_t *text_display; + + ply_trace ("adding default displays and keyboard"); + + terminal = ply_terminal_new (state->default_tty); + + if (!ply_terminal_open (terminal)) + { + ply_trace ("could not open terminal '%s': %m", state->default_tty); + ply_terminal_free (terminal); + return; + } + + ply_console_set_active_vt (state->console, + ply_terminal_get_vt_number (terminal)); + + renderer = ply_renderer_new (NULL, terminal, state->console); + + if (!ply_renderer_open (renderer)) + { + ply_trace ("could not open renderer /dev/fb"); + ply_renderer_free (renderer); + ply_terminal_free (terminal); + + add_display_and_keyboard_for_terminal (state, state->default_tty); + return; + } + + keyboard = ply_keyboard_new_for_renderer (renderer); + set_keyboard (state, keyboard); + + add_pixel_displays_from_renderer (state, renderer); + + text_display = ply_text_display_new (terminal, state->console); + ply_list_append_data (state->text_displays, text_display); + + state->renderer = renderer; +} + +static void +add_displays_and_keyboard_to_boot_splash (state_t *state, + ply_boot_splash_t *splash) +{ + ply_list_node_t *node; + + ply_trace ("setting keyboard on boot splash"); + ply_boot_splash_set_keyboard (splash, state->keyboard); + + node = ply_list_get_first_node (state->pixel_displays); + while (node != NULL) + { + ply_pixel_display_t *display; + ply_list_node_t *next_node; + + display = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (state->pixel_displays, node); + ply_trace ("adding pixel display on boot splash"); + ply_boot_splash_add_pixel_display (splash, display); + + node = next_node; + } + + node = ply_list_get_first_node (state->text_displays); + while (node != NULL) + { + ply_text_display_t *display; + ply_list_node_t *next_node; + + display = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (state->text_displays, node); + + ply_trace ("adding text display on boot splash"); + ply_boot_splash_add_text_display (splash, display); - if (ply_window_is_open (window)) - { - ply_trace ("adding window to boot splash"); - ply_boot_splash_add_window (splash, window); - } node = next_node; } } @@ -978,7 +1064,10 @@ start_boot_splash (state_t *state, ply_trace ("Loading boot splash theme '%s'", theme_path); - splash = ply_boot_splash_new (theme_path, PLYMOUTH_PLUGIN_PATH, state->boot_buffer); + splash = ply_boot_splash_new (theme_path, + PLYMOUTH_PLUGIN_PATH, + state->boot_buffer, + state->console); if (!ply_boot_splash_load (splash)) { @@ -994,8 +1083,8 @@ start_boot_splash (state_t *state, ply_trace ("attaching progress to plugin"); ply_boot_splash_attach_progress (splash, state->progress); - ply_trace ("adding windows to boot splash"); - add_windows_to_boot_splash (state, splash); + add_displays_and_keyboard_to_boot_splash (state, splash); + ply_trace ("showing plugin"); if (state->mode == PLY_MODE_SHUTDOWN) splash_mode = PLY_BOOT_SPLASH_MODE_SHUTDOWN; @@ -1179,6 +1268,16 @@ check_for_consoles (state_t *state, ply_trace ("checking if splash screen should be disabled"); + state->console = ply_console_new (); + + if (!ply_console_open (state->console)) + { + ply_trace ("could not open /dev/tty0"); + ply_console_free (state->console); + state->console = NULL; + return; + } + remaining_command_line = state->kernel_command_line; while ((console_key = strstr (remaining_command_line, " console=")) != NULL) { @@ -1204,11 +1303,11 @@ check_for_consoles (state_t *state, state->kernel_console_tty = strdup (default_tty); } - ply_list_append_data (state->windows, create_window (state, state->kernel_console_tty)); + add_display_and_keyboard_for_terminal (state, state->kernel_console_tty); } - if (ply_list_get_length (state->windows) == 0) - ply_list_append_data (state->windows, create_window (state, default_tty)); + if (ply_list_get_length (state->text_displays) == 0) + add_default_displays_and_keyboard (state); } static bool @@ -1241,10 +1340,7 @@ redirect_standard_io_to_device (const char *device) static bool initialize_environment (state_t *state) { - const char *default_tty; - ply_trace ("initializing minimal work environment"); - ply_list_node_t *node; if (!get_kernel_command_line (state)) return false; @@ -1252,46 +1348,27 @@ initialize_environment (state_t *state) check_verbosity (state); check_logging (state); - state->windows = ply_list_new (); state->keystroke_triggers = ply_list_new (); state->entry_triggers = ply_list_new (); state->entry_buffer = ply_buffer_new(); + state->pixel_displays = ply_list_new (); + state->text_displays = ply_list_new (); + state->keyboard = NULL; if (state->mode == PLY_MODE_SHUTDOWN) { - default_tty = "tty63"; - ply_switch_to_vt (63); + state->default_tty = "tty63"; } else - default_tty = "tty1"; + state->default_tty = "tty1"; - check_for_consoles (state, default_tty); + check_for_consoles (state, state->default_tty); if (state->kernel_console_tty != NULL) redirect_standard_io_to_device (state->kernel_console_tty); else - redirect_standard_io_to_device (default_tty); + redirect_standard_io_to_device (state->default_tty); - for (node = ply_list_get_first_node (state->windows); node; - node = ply_list_get_next_node (state->windows, node)) - { - ply_window_t *window = ply_list_node_get_data (node); - - ply_trace ("listening for escape key"); - ply_window_add_escape_handler (window, (ply_window_escape_handler_t) - on_escape_pressed, state); - ply_trace ("listening for keystrokes"); - ply_window_add_keyboard_input_handler (window, - (ply_window_keyboard_input_handler_t) on_keyboard_input, state); - ply_trace ("listening for backspace"); - ply_window_add_backspace_handler (window, - (ply_window_backspace_handler_t) on_backspace, state); - ply_trace ("listening for enter"); - ply_window_add_enter_handler (window, - (ply_window_enter_handler_t) on_enter, state); - } - - ply_trace ("initialized minimal work environment"); return true; } @@ -1359,7 +1436,7 @@ main (int argc, state.command_parser = ply_command_parser_new ("plymouthd", "Boot splash control server"); - state.loop = ply_event_loop_new (); + state.loop = ply_event_loop_get_default (); ply_command_parser_add_options (state.command_parser, "help", "This help message", PLY_COMMAND_OPTION_TYPE_FLAG, @@ -1515,7 +1592,6 @@ main (int argc, state.boot_splash = NULL; ply_command_parser_free (state.command_parser); - ply_list_free (state.windows); ply_boot_server_free (state.boot_server); state.boot_server = NULL; @@ -1526,9 +1602,6 @@ main (int argc, ply_buffer_free (state.boot_buffer); ply_progress_free (state.progress); - ply_trace ("freeing event loop"); - ply_event_loop_free (state.loop); - ply_trace ("exiting with code %d", exit_code); if (debug_buffer != NULL) diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index b4fd30b9..12531fbd 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -1,3 +1,3 @@ -SUBDIRS = controls splash +SUBDIRS = controls splash renderers MAINTAINERCLEANFILES = Makefile.in diff --git a/src/plugins/controls/label/plugin.c b/src/plugins/controls/label/plugin.c index 24bdf945..54917b18 100644 --- a/src/plugins/controls/label/plugin.c +++ b/src/plugins/controls/label/plugin.c @@ -43,22 +43,18 @@ #include <cairo.h> #include <pango/pangocairo.h> -#include "ply-frame-buffer.h" +#include "ply-pixel-buffer.h" +#include "ply-pixel-display.h" #include "ply-utils.h" -#include "ply-window.h" #include "ply-label-plugin.h" struct _ply_label_plugin_control { ply_event_loop_t *loop; - ply_window_t *window; - ply_frame_buffer_t *frame_buffer; - ply_frame_buffer_area_t area; + ply_pixel_display_t *display; + ply_rectangle_t area; - PangoLayout *pango_layout; - cairo_t *cairo_context; - cairo_surface_t *cairo_surface; char *text; uint32_t is_hidden : 1; @@ -82,64 +78,135 @@ destroy_control (ply_label_plugin_control_t *label) if (label == NULL) return; - cairo_destroy (label->cairo_context); - cairo_surface_destroy (label->cairo_surface); - g_object_unref (label->pango_layout); - free (label); } long get_width_of_control (ply_label_plugin_control_t *label) { - int width; - - pango_layout_get_size (label->pango_layout, &width, NULL); - - return (long) ((double) width / PANGO_SCALE)+1; + return label->area.width; } long get_height_of_control (ply_label_plugin_control_t *label) { - int height; + return label->area.height; +} - pango_layout_get_size (label->pango_layout, NULL, &height); +static cairo_t * +get_cairo_context_for_pixel_buffer (ply_label_plugin_control_t *label, + ply_pixel_buffer_t *pixel_buffer) +{ + cairo_surface_t *cairo_surface; + cairo_t *cairo_context; + unsigned char *data; + ply_rectangle_t size; + + data = (unsigned char *) ply_pixel_buffer_get_argb32_data (pixel_buffer); + ply_pixel_buffer_get_size (pixel_buffer, &size); + + cairo_surface = cairo_image_surface_create_for_data (data, + CAIRO_FORMAT_ARGB32, + size.width, + size.height, + size.width * 4); + cairo_context = cairo_create (cairo_surface); + cairo_surface_destroy (cairo_surface); + + return cairo_context; +} - return (long) ((double) height / PANGO_SCALE)+1; +static cairo_t * +get_cairo_context_for_sizing (ply_label_plugin_control_t *label) +{ + cairo_surface_t *cairo_surface; + cairo_t *cairo_context; + + cairo_surface = cairo_image_surface_create_for_data (NULL, CAIRO_FORMAT_ARGB32, 0, 0, 0); + cairo_context = cairo_create (cairo_surface); + cairo_surface_destroy (cairo_surface); + + return cairo_context; } static void -erase_label_area (ply_label_plugin_control_t *label) +size_control (ply_label_plugin_control_t *label) { - ply_window_erase_area (label->window, - label->area.x, label->area.y, - label->area.width, label->area.height); + cairo_t *cairo_context; + PangoLayout *pango_layout; + PangoFontDescription *description; + int text_width; + int text_height; + + if (label->is_hidden) + return; + + cairo_context = get_cairo_context_for_sizing (label); + + pango_layout = pango_cairo_create_layout (cairo_context); + + description = pango_font_description_from_string ("Sans 12"); + pango_layout_set_font_description (pango_layout, description); + pango_font_description_free (description); + + pango_layout_set_text (pango_layout, label->text, -1); + pango_cairo_update_layout (cairo_context, pango_layout); + pango_layout_get_size (pango_layout, &text_width, &text_height); + label->area.width = (long) ((double) text_width / PANGO_SCALE) + 1; + label->area.height = (long) ((double) text_height / PANGO_SCALE) + 1; + + g_object_unref (pango_layout); + cairo_destroy (cairo_context); } void -draw_control (ply_label_plugin_control_t *label) +draw_control (ply_label_plugin_control_t *label, + ply_pixel_buffer_t *pixel_buffer, + long x, + long y, + unsigned long width, + unsigned long height) { + cairo_t *cairo_context; + PangoLayout *pango_layout; + PangoFontDescription *description; + int text_width; + int text_height; if (label->is_hidden) return; - ply_frame_buffer_pause_updates (label->frame_buffer); - erase_label_area (label); - cairo_move_to (label->cairo_context, + cairo_context = get_cairo_context_for_pixel_buffer (label, pixel_buffer); + + pango_layout = pango_cairo_create_layout (cairo_context); + + description = pango_font_description_from_string ("Sans 12"); + pango_layout_set_font_description (pango_layout, description); + pango_font_description_free (description); + + pango_layout_set_text (pango_layout, label->text, -1); + pango_cairo_update_layout (cairo_context, pango_layout); + pango_layout_get_size (pango_layout, &text_width, &text_height); + label->area.width = (long) ((double) text_width / PANGO_SCALE) + 1; + label->area.height = (long) ((double) text_height / PANGO_SCALE) + 1; + + cairo_rectangle (cairo_context, x, y, width, height); + cairo_clip (cairo_context); + cairo_move_to (cairo_context, label->area.x + 1, label->area.y + 1); - cairo_set_source_rgba (label->cairo_context, 0.0, 0.0, 0.0, 0.7); - pango_cairo_show_layout (label->cairo_context, - label->pango_layout); - cairo_move_to (label->cairo_context, + cairo_set_source_rgba (cairo_context, 0.0, 0.0, 0.0, 0.7); + pango_cairo_show_layout (cairo_context, + pango_layout); + cairo_move_to (cairo_context, label->area.x, label->area.y); - cairo_set_source_rgb (label->cairo_context, 1.0, 1.0, 1.0); - pango_cairo_show_layout (label->cairo_context, - label->pango_layout); - cairo_surface_flush (label->cairo_surface); - ply_frame_buffer_unpause_updates (label->frame_buffer); + cairo_set_source_rgb (cairo_context, 1.0, 1.0, 1.0); + pango_cairo_show_layout (cairo_context, + pango_layout); + + g_object_unref (pango_layout); + cairo_destroy (cairo_context); } void @@ -151,56 +218,21 @@ set_text_for_control (ply_label_plugin_control_t *label, free (label->text); label->text = strdup (text); } - - if (label->pango_layout != NULL) - { - pango_layout_set_text (label->pango_layout, text, -1); - pango_cairo_update_layout (label->cairo_context, label->pango_layout); - - label->area.width = get_width_of_control (label); - label->area.height = get_height_of_control (label); - - } } bool show_control (ply_label_plugin_control_t *label, - ply_window_t *window, + ply_pixel_display_t *display, long x, long y) { - PangoFontDescription *description; - ply_frame_buffer_area_t size; - unsigned char *data; - - label->window = window; - label->frame_buffer = ply_window_get_frame_buffer (window); - data = (unsigned char *) ply_frame_buffer_get_bytes (label->frame_buffer); - + label->display = display; label->area.x = x; label->area.y = y; - ply_frame_buffer_get_size (label->frame_buffer, &size); - - label->cairo_surface = cairo_image_surface_create_for_data (data, - CAIRO_FORMAT_ARGB32, - size.width, - size.height, - size.width * 4); - - label->cairo_context = cairo_create (label->cairo_surface); - label->pango_layout = pango_cairo_create_layout (label->cairo_context); - - if (label->text != NULL) - set_text_for_control (label, label->text); - - description = pango_font_description_from_string ("Sans 12"); - pango_layout_set_font_description (label->pango_layout, description); - pango_font_description_free (description); - label->is_hidden = false; - draw_control (label); + size_control (label); return true; } @@ -208,22 +240,13 @@ show_control (ply_label_plugin_control_t *label, void hide_control (ply_label_plugin_control_t *label) { - erase_label_area (label); - - g_object_unref (label->pango_layout); - label->pango_layout = NULL; - - cairo_destroy (label->cairo_context); - label->cairo_context = NULL; - - cairo_surface_destroy (label->cairo_surface); - label->cairo_surface = NULL; + label->is_hidden = true; + ply_pixel_display_draw_area (label->display, + label->area.x, label->area.y, + label->area.width, label->area.height); - label->frame_buffer = NULL; - label->window = NULL; + label->display = NULL; label->loop = NULL; - - label->is_hidden = true; } bool diff --git a/src/plugins/renderers/Makefile.am b/src/plugins/renderers/Makefile.am new file mode 100644 index 00000000..2fadbf40 --- /dev/null +++ b/src/plugins/renderers/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = frame-buffer drm +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/plugins/renderers/drm/Makefile.am b/src/plugins/renderers/drm/Makefile.am new file mode 100644 index 00000000..da757c59 --- /dev/null +++ b/src/plugins/renderers/drm/Makefile.am @@ -0,0 +1,27 @@ +INCLUDES = -I$(top_srcdir) \ + -I$(srcdir)/../../../libply \ + -I$(srcdir)/../../../libplybootsplash \ + -I$(srcdir)/../../.. \ + -I$(srcdir)/../.. \ + -I$(srcdir)/.. \ + -I$(srcdir) + +plugindir = $(libdir)/plymouth/renderers +plugin_LTLIBRARIES = drm.la + +drm_la_CFLAGS = $(PLYMOUTH_CFLAGS) $(DRM_CFLAGS) + +drm_la_LDFLAGS = -module -avoid-version -export-dynamic +drm_la_LIBADD = $(PLYMOUTH_LIBS) $(DRM_LIBS) \ + ../../../libply/libply.la \ + ../../../libplybootsplash/libplybootsplash.la +drm_la_SOURCES = $(srcdir)/plugin.c \ + $(srcdir)/ply-renderer-driver.h \ + $(srcdir)/ply-renderer-i915-driver.h \ + $(srcdir)/ply-renderer-i915-driver.c \ + $(srcdir)/ply-renderer-radeon-driver.h \ + $(srcdir)/ply-renderer-radeon-driver.c \ + $(srcdir)/ply-renderer-nouveau-driver.h \ + $(srcdir)/ply-renderer-nouveau-driver.c + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/plugins/renderers/drm/plugin.c b/src/plugins/renderers/drm/plugin.c new file mode 100644 index 00000000..9047d79e --- /dev/null +++ b/src/plugins/renderers/drm/plugin.c @@ -0,0 +1,1075 @@ +/* plugin.c - drm backend renderer plugin + * + * Copyright (C) 2006-2009 Red Hat, Inc. + * 2008 Charlie Brej <cbrej@cs.man.ac.uk> + * + * 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: Charlie Brej <cbrej@cs.man.ac.uk> + * Kristian Høgsberg <krh@redhat.com> + * Peter Jones <pjones@redhat.com> + * Ray Strode <rstrode@redhat.com> + */ +#include "config.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/drm.h> +#include <xf86drm.h> +#include <xf86drmMode.h> + +#include "ply-buffer.h" +#include "ply-event-loop.h" +#include "ply-list.h" +#include "ply-logger.h" +#include "ply-rectangle.h" +#include "ply-region.h" +#include "ply-terminal.h" + +#include "ply-renderer.h" +#include "ply-renderer-plugin.h" +#include "ply-renderer-driver.h" +#include "ply-renderer-i915-driver.h" +#include "ply-renderer-radeon-driver.h" +#include "ply-renderer-nouveau-driver.h" + +#define BYTES_PER_PIXEL (4) + +struct _ply_renderer_head +{ + ply_renderer_backend_t *backend; + ply_pixel_buffer_t *pixel_buffer; + ply_rectangle_t area; + + unsigned long row_stride; + + drmModeConnector *connector; + drmModeModeInfo *mode; + + uint32_t controller_id; + uint32_t encoder_id; + uint32_t console_buffer_id; + uint32_t scan_out_buffer_id; +}; + +struct _ply_renderer_input_source +{ + ply_fd_watch_t *terminal_input_watch; + + ply_buffer_t *key_buffer; + + ply_renderer_input_source_handler_t handler; + void *user_data; +}; + +struct _ply_renderer_backend +{ + ply_event_loop_t *loop; + ply_console_t *console; + 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; + + ply_renderer_input_source_t input_source; + ply_list_t *heads; + + int32_t dither_red; + int32_t dither_green; + int32_t dither_blue; +}; + +ply_renderer_plugin_interface_t *ply_renderer_backend_get_interface (void); +static void ply_renderer_head_redraw (ply_renderer_backend_t *backend, + ply_renderer_head_t *head); + +static ply_renderer_head_t * +ply_renderer_head_new (ply_renderer_backend_t *backend, + drmModeConnector *connector, + uint32_t encoder_id, + uint32_t controller_id, + uint32_t console_buffer_id, + drmModeModeInfo *mode) +{ + ply_renderer_head_t *head; + + head = calloc (1, sizeof (ply_renderer_head_t)); + + head->backend = backend; + head->connector = connector; + head->encoder_id = encoder_id; + head->controller_id = controller_id; + head->console_buffer_id = console_buffer_id; + head->mode = mode; + + head->area.x = 0; + head->area.y = 0; + head->area.width = mode->hdisplay; + head->area.height = mode->vdisplay; + + head->pixel_buffer = ply_pixel_buffer_new (head->area.width, head->area.height); + + ply_pixel_buffer_fill_with_color (head->pixel_buffer, NULL, + 0.0, 0.0, 0.0, 1.0); + + return head; +} + +static void +ply_renderer_head_free (ply_renderer_head_t *head) +{ + ply_pixel_buffer_free (head->pixel_buffer); + drmModeFreeConnector (head->connector); + free (head); +} + +static bool +ply_renderer_head_set_scan_out_buffer (ply_renderer_backend_t *backend, + ply_renderer_head_t *head, + uint32_t buffer_id) +{ + + /* Tell the controller to use the allocated scan out buffer + */ + if (drmModeSetCrtc (backend->device_fd, head->controller_id, buffer_id, + 0, 0, &head->connector->connector_id, 1, head->mode) < 0) + return false; + + return true; +} + +static bool +ply_renderer_head_map (ply_renderer_backend_t *backend, + ply_renderer_head_t *head) +{ + assert (backend != NULL); + assert (backend->device_fd >= 0); + assert (backend->driver_interface != NULL); + assert (backend->driver != NULL); + + assert (head != NULL); + + head->scan_out_buffer_id = + backend->driver_interface->create_buffer (backend->driver, + head->area.width, head->area.height, + &head->row_stride); + + if (head->scan_out_buffer_id == 0) + return false; + + 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); + head->scan_out_buffer_id = 0; + return false; + } + + /* FIXME: Maybe we should blit the fbcon contents instead of the (blank) + * shadow buffer? + */ + ply_renderer_head_redraw (backend, head); + + if (!ply_renderer_head_set_scan_out_buffer (backend, head, + head->scan_out_buffer_id)) + { + backend->driver_interface->destroy_buffer (backend->driver, + head->scan_out_buffer_id); + head->scan_out_buffer_id = 0; + return false; + } + + return true; +} + +static void +ply_renderer_head_unmap (ply_renderer_backend_t *backend, + ply_renderer_head_t *head) +{ + backend->driver_interface->unmap_buffer (backend->driver, + head->scan_out_buffer_id); + + backend->driver_interface->destroy_buffer (backend->driver, + head->scan_out_buffer_id); + head->scan_out_buffer_id = 0; +} + +static void +flush_area (const char *src, + unsigned long src_row_stride, + char *dst, + unsigned long dst_row_stride, + ply_rectangle_t *area_to_flush) +{ + unsigned long x1, y1, x2, y2, y; + + x1 = area_to_flush->x; + y1 = area_to_flush->y; + x2 = x1 + area_to_flush->width; + y2 = y1 + area_to_flush->height; + + if (area_to_flush->width * 4 == src_row_stride && + area_to_flush->width * 4 == dst_row_stride) + { + memcpy (dst, src, area_to_flush->width * area_to_flush->height * 4); + return; + } + + for (y = y1; y < y2; y++) + { + memcpy (dst, src, area_to_flush->width * 4); + dst += dst_row_stride; + src += src_row_stride; + } +} + +static void +ply_renderer_head_flush_area (ply_renderer_head_t *head, + ply_rectangle_t *area_to_flush, + char *map_address) +{ + uint32_t *shadow_buffer; + char *dst, *src; + + shadow_buffer = ply_pixel_buffer_get_argb32_data (head->pixel_buffer); + + dst = &map_address[area_to_flush->y * head->row_stride + area_to_flush->x * BYTES_PER_PIXEL]; + src = (char *) &shadow_buffer[area_to_flush->y * head->area.width + area_to_flush->x]; + + flush_area (src, head->area.width * 4, dst, head->row_stride, area_to_flush); +} + +static void +free_heads (ply_renderer_backend_t *backend) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (backend->heads); + while (node != NULL) + { + ply_list_node_t *next_node; + ply_renderer_head_t *head; + + head = (ply_renderer_head_t *) ply_list_node_get_data (node); + next_node = ply_list_get_next_node (backend->heads, node); + + ply_renderer_head_free (head); + ply_list_remove_node (backend->heads, node); + + node = next_node; + } +} + +static ply_renderer_backend_t * +create_backend (const char *device_name, + ply_terminal_t *terminal, + ply_console_t *console) +{ + ply_renderer_backend_t *backend; + + backend = calloc (1, sizeof (ply_renderer_backend_t)); + + if (device_name != NULL) + backend->device_name = strdup (device_name); + else + backend->device_name = strdup ("/dev/dri/card0"); + + backend->device_fd = -1; + + backend->loop = ply_event_loop_get_default (); + backend->heads = ply_list_new (); + backend->input_source.key_buffer = ply_buffer_new (); + backend->console = console; + backend->terminal = terminal; + + return backend; +} + +static void +destroy_backend (ply_renderer_backend_t *backend) +{ + free_heads (backend); + ply_list_free (backend->heads); + + free (backend->device_name); + + free (backend); +} + +static char * +find_driver_for_device (const char *device_name) +{ + char *driver; + int major_number, minor_number; + struct stat file_attributes; + char *device_path; + char device_link_path[PATH_MAX + 1] = ""; + + if (stat (device_name, &file_attributes) < 0) + return NULL; + + if (!S_ISCHR (file_attributes.st_mode)) + return NULL; + + major_number = major (file_attributes.st_rdev); + minor_number = minor (file_attributes.st_rdev); + + asprintf (&device_path, "/sys/dev/char/%d:%d/device/driver", + major_number, minor_number); + + if (readlink (device_path, device_link_path, sizeof (device_link_path) - 1) < 0) + { + free (device_path); + return NULL; + } + free (device_path); + + driver = strrchr (device_link_path, '/'); + + if (driver == NULL) + return NULL; + + return strdup (driver + strlen ("/")); +} + +static void +on_active_vt_changed (ply_renderer_backend_t *backend) +{ + ply_list_node_t *node; + + if (ply_console_get_active_vt (backend->console) != + ply_terminal_get_vt_number (backend->terminal)) + return; + + node = ply_list_get_first_node (backend->heads); + while (node != NULL) + { + ply_list_node_t *next_node; + ply_renderer_head_t *head; + + head = (ply_renderer_head_t *) ply_list_node_get_data (node); + next_node = ply_list_get_next_node (backend->heads, node); + + if (head->scan_out_buffer_id != 0) + ply_renderer_head_set_scan_out_buffer (backend, head, + head->scan_out_buffer_id); + + node = next_node; + } +} + +static bool +load_driver (ply_renderer_backend_t *backend) +{ + char *driver_name; + int device_fd; + + driver_name = find_driver_for_device (backend->device_name); + device_fd = drmOpen (driver_name, NULL); + + if (device_fd < 0) + { + free (driver_name); + return false; + } + + if (strcmp (driver_name, "i915") == 0) + { + backend->driver_interface = ply_renderer_i915_driver_get_interface (); + backend->driver_supports_mapping_console = true; + } + else if (strcmp (driver_name, "radeon") == 0) + { + backend->driver_interface = ply_renderer_radeon_driver_get_interface (); + backend->driver_supports_mapping_console = false; + } + else if (strcmp (driver_name, "nouveau") == 0) + { + backend->driver_interface = ply_renderer_nouveau_driver_get_interface (); + backend->driver_supports_mapping_console = false; + } + free (driver_name); + + 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; + + return true; +} + +static void +unload_driver (ply_renderer_backend_t *backend) +{ + if (backend->driver == NULL) + return; + + assert (backend->driver_interface != NULL); + + backend->driver_interface->destroy_driver (backend->driver); + backend->driver = NULL; + + backend->driver_interface = NULL; + + if (backend->device_fd >= 0) + { + drmClose (backend->device_fd); + backend->device_fd = -1; + } +} + +static bool +open_device (ply_renderer_backend_t *backend) +{ + assert (backend != NULL); + assert (backend->device_name != NULL); + + if (!load_driver (backend)) + return false; + + ply_console_watch_for_active_vt_change (backend->console, + (ply_console_active_vt_changed_handler_t) + on_active_vt_changed, + backend); + + return true; +} + +static void +close_device (ply_renderer_backend_t *backend) +{ + ply_terminal_close (backend->terminal); + free_heads (backend); + + ply_console_stop_watching_for_active_vt_change (backend->console, + (ply_console_active_vt_changed_handler_t) + on_active_vt_changed, + backend); + + unload_driver (backend); +} + +static drmModeModeInfo * +get_active_mode_for_connector (ply_renderer_backend_t *backend, + drmModeConnector *connector) +{ + return &connector->modes[0]; +} + +static bool +controller_is_available (ply_renderer_backend_t *backend, + uint32_t controller_id) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (backend->heads); + while (node != NULL) + { + ply_list_node_t *next_node; + ply_renderer_head_t *head; + + head = (ply_renderer_head_t *) ply_list_node_get_data (node); + next_node = ply_list_get_next_node (backend->heads, node); + + if (head->controller_id == controller_id) + return false; + + node = next_node; + } + + return true; +} + +static uint32_t +find_controller_for_encoder (ply_renderer_backend_t *backend, + drmModeEncoder *encoder) +{ + int i; + uint32_t possible_crtcs; + + /* Monitor is already lit. We'll use the same controller. + */ + if (encoder->crtc_id != 0) + return encoder->crtc_id; + + /* Monitor cable is plugged in, but the monitor isn't lit + * yet. Let's pick an available controller and light it up + * ourselves. + */ + for (i = 0, + possible_crtcs = encoder->possible_crtcs; + possible_crtcs != 0x0; + i++, possible_crtcs >>= 1) + { + /* controller isn't compatible with encoder + */ + if ((possible_crtcs & 0x1) == 0) + continue; + + /* controller is already being used + */ + if (!controller_is_available (backend, backend->resources->crtcs[i])) + continue; + + assert (i < backend->resources->count_crtcs); + return backend->resources->crtcs[i]; + } + + return 0; +} + +static bool +encoder_is_available (ply_renderer_backend_t *backend, + uint32_t encoder_id) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (backend->heads); + while (node != NULL) + { + ply_list_node_t *next_node; + ply_renderer_head_t *head; + + head = (ply_renderer_head_t *) ply_list_node_get_data (node); + next_node = ply_list_get_next_node (backend->heads, node); + + if (head->encoder_id == encoder_id) + return false; + + node = next_node; + } + + return true; +} + +static drmModeEncoder * +find_unused_encoder_for_connector (ply_renderer_backend_t *backend, + drmModeConnector *connector) +{ + int i; + drmModeEncoder *encoder; + + for (i = 0; i < connector->count_encoders; i++) + { + encoder = drmModeGetEncoder (backend->device_fd, + connector->encoders[i]); + + if (encoder == NULL) + continue; + + if (encoder_is_available (backend, encoder->encoder_id)) + return encoder; + + drmModeFreeEncoder (encoder); + } + + return NULL; +} + +static drmModeEncoder * +find_encoder_for_connector (ply_renderer_backend_t *backend, + drmModeConnector *connector) +{ + int i; + drmModeEncoder *encoder; + + assert (backend != NULL); + + for (i = 0; i < connector->count_encoders; i++) + { + encoder = drmModeGetEncoder (backend->device_fd, + connector->encoders[i]); + + if (encoder == NULL) + continue; + + if (encoder->encoder_id == connector->encoder_id) + return encoder; + + drmModeFreeEncoder (encoder); + } + + /* No encoder yet, pick one + */ + return find_unused_encoder_for_connector (backend, connector); +} + +static uint32_t +get_console_buffer_id (ply_renderer_backend_t *backend, + uint32_t controller_id) +{ + drmModeCrtc *controller; + uint32_t console_buffer_id; + + console_buffer_id = 0; + controller = drmModeGetCrtc (backend->device_fd, controller_id); + + if (controller == NULL) + return 0; + + console_buffer_id = controller->buffer_id; + + drmModeFreeCrtc (controller); + + return console_buffer_id; +} + +static bool +create_heads_for_active_connectors (ply_renderer_backend_t *backend) +{ + int i; + drmModeConnector *connector; + + for (i = 0; i < backend->resources->count_connectors; i++) + { + ply_renderer_head_t *head; + drmModeEncoder *encoder; + uint32_t controller_id; + uint32_t encoder_id; + uint32_t console_buffer_id; + drmModeModeInfo *mode; + + connector = drmModeGetConnector (backend->device_fd, + backend->resources->connectors[i]); + + if (connector == NULL) + continue; + + if (connector->connection != DRM_MODE_CONNECTED) + { + drmModeFreeConnector (connector); + continue; + } + + if (connector->count_modes <= 0) + { + drmModeFreeConnector (connector); + continue; + } + + encoder = find_encoder_for_connector (backend, connector); + + if (encoder == NULL) + { + drmModeFreeConnector (connector); + continue; + } + + encoder_id = encoder->encoder_id; + controller_id = find_controller_for_encoder (backend, encoder); + drmModeFreeEncoder (encoder); + + if (controller_id == 0) + { + drmModeFreeConnector (connector); + continue; + } + + mode = get_active_mode_for_connector (backend, connector); + + console_buffer_id = get_console_buffer_id (backend, controller_id); + + head = ply_renderer_head_new (backend, connector, encoder_id, + controller_id, console_buffer_id, + mode); + + ply_list_append_data (backend->heads, head); + } + + /* 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. + * + * 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) + { + free_heads (backend); + return false; + } + + return ply_list_get_length (backend->heads) > 0; +} + +static bool +query_device (ply_renderer_backend_t *backend) +{ + assert (backend != NULL); + assert (backend->device_fd >= 0); + + backend->resources = drmModeGetResources (backend->device_fd); + + if (backend->resources == NULL) + { + ply_trace ("Could not get card resources"); + return false; + } + + if (!create_heads_for_active_connectors (backend)) + { + ply_trace ("Could not initialize heads"); + return false; + } + + return true; +} + +static bool +map_to_device (ply_renderer_backend_t *backend) +{ + ply_list_node_t *node; + bool head_mapped; + + head_mapped = false; + node = ply_list_get_first_node (backend->heads); + while (node != NULL) + { + ply_list_node_t *next_node; + ply_renderer_head_t *head; + + head = (ply_renderer_head_t *) ply_list_node_get_data (node); + next_node = ply_list_get_next_node (backend->heads, node); + + if (ply_renderer_head_map (backend, head)) + head_mapped = true; + + node = next_node; + } + + 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)) + 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; + } + 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); + } + + 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_renderer_head_set_scan_out_buffer (backend, + head, 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) + { + ply_list_node_t *next_node; + ply_renderer_head_t *head; + + head = (ply_renderer_head_t *) ply_list_node_get_data (node); + next_node = ply_list_get_next_node (backend->heads, node); + + ply_renderer_head_set_scan_out_buffer_to_console (backend, head, + should_set_to_black); + + ply_renderer_head_unmap (backend, head); + + node = next_node; + } +} + +static void +reset_scan_out_buffer_if_needed (ply_renderer_backend_t *backend, + ply_renderer_head_t *head) +{ + drmModeCrtc *controller; + + if (ply_console_get_active_vt (backend->console) != + ply_terminal_get_vt_number (backend->terminal)) + return; + + controller = drmModeGetCrtc (backend->device_fd, head->controller_id); + + if (controller == NULL) + return; + + if (controller->buffer_id != head->scan_out_buffer_id) + { + ply_trace ("Something stole the monitor"); + ply_renderer_head_set_scan_out_buffer (backend, head, + head->scan_out_buffer_id); + } + + drmModeFreeCrtc (controller); +} + +static void +flush_head (ply_renderer_backend_t *backend, + ply_renderer_head_t *head) +{ + ply_region_t *updated_region; + ply_list_t *areas_to_flush; + ply_list_node_t *node; + ply_pixel_buffer_t *pixel_buffer; + char *map_address; + + assert (backend != NULL); + + ply_console_set_mode (backend->console, PLY_CONSOLE_MODE_GRAPHICS); + pixel_buffer = head->pixel_buffer; + updated_region = ply_pixel_buffer_get_updated_areas (pixel_buffer); + areas_to_flush = ply_region_get_rectangle_list (updated_region); + + map_address = + backend->driver_interface->begin_flush (backend->driver, + head->scan_out_buffer_id); + + node = ply_list_get_first_node (areas_to_flush); + while (node != NULL) + { + ply_list_node_t *next_node; + ply_rectangle_t *area_to_flush; + + area_to_flush = (ply_rectangle_t *) ply_list_node_get_data (node); + + next_node = ply_list_get_next_node (areas_to_flush, node); + + reset_scan_out_buffer_if_needed (backend, head); + ply_renderer_head_flush_area (head, area_to_flush, map_address); + + node = next_node; + } + + backend->driver_interface->end_flush (backend->driver, + head->scan_out_buffer_id); + + ply_region_clear (updated_region); +} + +static void +ply_renderer_head_redraw (ply_renderer_backend_t *backend, + ply_renderer_head_t *head) +{ + ply_region_t *region; + + region = ply_pixel_buffer_get_updated_areas (head->pixel_buffer); + + ply_region_add_rectangle (region, &head->area); + + flush_head (backend, head); +} + +static ply_list_t * +get_heads (ply_renderer_backend_t *backend) +{ + return backend->heads; +} + +static ply_pixel_buffer_t * +get_buffer_for_head (ply_renderer_backend_t *backend, + ply_renderer_head_t *head) +{ + + if (head->backend != backend) + return NULL; + + return head->pixel_buffer; +} + +static bool +has_input_source (ply_renderer_backend_t *backend, + ply_renderer_input_source_t *input_source) +{ + return input_source == &backend->input_source; +} + +static ply_renderer_input_source_t * +get_input_source (ply_renderer_backend_t *backend) +{ + return &backend->input_source; +} + +static void +on_key_event (ply_renderer_input_source_t *input_source, + int terminal_fd) +{ + ply_buffer_append_from_fd (input_source->key_buffer, + terminal_fd); + + if (input_source->handler != NULL) + input_source->handler (input_source->user_data, input_source->key_buffer, input_source); + +} + +static bool +open_input_source (ply_renderer_backend_t *backend, + ply_renderer_input_source_t *input_source) +{ + int terminal_fd; + + assert (backend != NULL); + assert (has_input_source (backend, input_source)); + + terminal_fd = ply_terminal_get_fd (backend->terminal); + + input_source->terminal_input_watch = ply_event_loop_watch_fd (backend->loop, terminal_fd, PLY_EVENT_LOOP_FD_STATUS_HAS_DATA, + (ply_event_handler_t) on_key_event, + NULL, input_source); + return true; +} + +static void +set_handler_for_input_source (ply_renderer_backend_t *backend, + ply_renderer_input_source_t *input_source, + ply_renderer_input_source_handler_t handler, + void *user_data) +{ + assert (backend != NULL); + assert (has_input_source (backend, input_source)); + + input_source->handler = handler; + input_source->user_data = user_data; +} + +static void +close_input_source (ply_renderer_backend_t *backend, + ply_renderer_input_source_t *input_source) +{ + assert (backend != NULL); + assert (has_input_source (backend, input_source)); + + ply_event_loop_stop_watching_fd (backend->loop, input_source->terminal_input_watch); + input_source->terminal_input_watch = NULL; +} + +ply_renderer_plugin_interface_t * +ply_renderer_backend_get_interface (void) +{ + static ply_renderer_plugin_interface_t plugin_interface = + { + .create_backend = create_backend, + .destroy_backend = destroy_backend, + .open_device = open_device, + .close_device = close_device, + .query_device = query_device, + .map_to_device = map_to_device, + .unmap_from_device = unmap_from_device, + .flush_head = flush_head, + .get_heads = get_heads, + .get_buffer_for_head = get_buffer_for_head, + .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 + }; + + return &plugin_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-driver.h b/src/plugins/renderers/drm/ply-renderer-driver.h new file mode 100644 index 00000000..a0d6044a --- /dev/null +++ b/src/plugins/renderers/drm/ply-renderer-driver.h @@ -0,0 +1,67 @@ +/* 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-i915-driver.c b/src/plugins/renderers/drm/ply-renderer-i915-driver.c new file mode 100644 index 00000000..b32e21ec --- /dev/null +++ b/src/plugins/renderers/drm/ply-renderer-i915-driver.c @@ -0,0 +1,360 @@ +/* ply-renderer-i915-driver.c - interface to i915 drm driver + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: Ray Strode <rstrode@redhat.com> + */ +#include "config.h" + +#include "ply-renderer-i915-driver.h" + +#include <arpa/inet.h> +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <string.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <values.h> +#include <unistd.h> + +#include <drm/drm.h> +#include <drm/i915_drm.h> +#include <intel_bufmgr.h> +#include <xf86drm.h> +#include <xf86drmMode.h> + +#include "ply-hashtable.h" +#include "ply-logger.h" +#include "ply-renderer-driver.h" + +typedef struct _ply_renderer_buffer ply_renderer_buffer_t; + +struct _ply_renderer_buffer +{ + drm_intel_bo *object; + uint32_t id; + unsigned long width; + unsigned long height; + unsigned long row_stride; +}; + +struct _ply_renderer_driver +{ + int device_fd; + drm_intel_bufmgr *manager; + + ply_hashtable_t *buffers; +}; + +static ply_renderer_driver_t * +create_driver (int device_fd) +{ + ply_renderer_driver_t *driver; + int page_size; + + driver = calloc (1, sizeof (ply_renderer_driver_t)); + driver->device_fd = device_fd; + + page_size = (int) sysconf (_SC_PAGE_SIZE); + + driver->manager = drm_intel_bufmgr_gem_init (driver->device_fd, page_size); + if (driver->manager == NULL) + { + free (driver); + return NULL; + } + + driver->buffers = ply_hashtable_new (ply_hashtable_direct_hash, + ply_hashtable_direct_compare); + + return driver; +} + +static void +destroy_driver (ply_renderer_driver_t *driver) +{ + ply_hashtable_free (driver->buffers); + + drm_intel_bufmgr_destroy (driver->manager); + free (driver); +} + +static ply_renderer_buffer_t * +ply_renderer_buffer_new (ply_renderer_driver_t *driver, + drm_intel_bo *buffer_object, + uint32_t id, + unsigned long width, + unsigned long height, + unsigned long row_stride) +{ + ply_renderer_buffer_t *buffer; + + buffer = calloc (1, sizeof (ply_renderer_buffer_t)); + buffer->object = buffer_object; + buffer->id = id; + buffer->width = width; + buffer->height = height; + buffer->row_stride = row_stride; + + return buffer; +} + +static drm_intel_bo * +create_intel_bo_from_handle (ply_renderer_driver_t *driver, + uint32_t handle) +{ + struct drm_gem_flink flink_request; + char *name; + drm_intel_bo *buffer_object; + + /* FIXME: This can't be the right way to do this. + * + * 1) It requires skirting around the API and using ioctls + * 2) It requires taking a local handle, turning it into a + * a global handle ("name"), just so we can use an api that + * will open the global name and grab the local handle from it. + */ + + memset (&flink_request, 0, sizeof (struct drm_gem_flink)); + flink_request.handle = handle; + + if (ioctl (driver->device_fd, DRM_IOCTL_GEM_FLINK, &flink_request) < 0) + return NULL; + + asprintf (&name, "buffer %u", handle); + + buffer_object = drm_intel_bo_gem_create_from_name (driver->manager, + name, flink_request.name); + free (name); + + return buffer_object; +} + +static ply_renderer_buffer_t * +ply_renderer_buffer_new_from_id (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + ply_renderer_buffer_t *buffer; + drmModeFB *fb; + drm_intel_bo *buffer_object; + + fb = drmModeGetFB (driver->device_fd, buffer_id); + + if (fb == NULL) + return NULL; + + buffer_object = create_intel_bo_from_handle (driver, fb->handle); + + if (buffer_object == NULL) + { + drmModeFreeFB (fb); + return NULL; + } + + buffer = ply_renderer_buffer_new (driver, buffer_object, buffer_id, + fb->width, fb->height, fb->pitch); + drmModeFreeFB (fb); + + return buffer; +} + +static ply_renderer_buffer_t * +get_buffer_from_id (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + static ply_renderer_buffer_t *buffer; + + buffer = ply_hashtable_lookup (driver->buffers, + (void *) (uintptr_t) buffer_id); + + return buffer; +} + +static bool +fetch_buffer (ply_renderer_driver_t *driver, + uint32_t buffer_id, + unsigned long *width, + unsigned long *height, + unsigned long *row_stride) +{ + ply_renderer_buffer_t *buffer; + + buffer = get_buffer_from_id (driver, buffer_id); + + if (buffer == NULL) + { + buffer = ply_renderer_buffer_new_from_id (driver, buffer_id); + + if (buffer == NULL) + return false; + + ply_hashtable_insert (driver->buffers, + (void *) (uintptr_t) buffer_id, + buffer); + } + + if (width != NULL) + *width = buffer->width; + + if (height != NULL) + *height = buffer->height; + + if (row_stride != NULL) + *row_stride = buffer->row_stride; + + return true; +} + +static uint32_t +create_buffer (ply_renderer_driver_t *driver, + unsigned long width, + unsigned long height, + unsigned long *row_stride) +{ + drm_intel_bo *buffer_object; + ply_renderer_buffer_t *buffer; + uint32_t buffer_id; + + *row_stride = ply_round_to_multiple (width * 4, 256); + + buffer_object = drm_intel_bo_alloc (driver->manager, + "frame buffer", + height * *row_stride, 0); + + if (buffer_object == NULL) + { + ply_trace ("Could not allocate GEM object for frame buffer: %m"); + return 0; + } + + if (drmModeAddFB (driver->device_fd, width, height, + 24, 32, *row_stride, buffer_object->handle, + &buffer_id) != 0) + { + ply_trace ("Could not set up GEM object as frame buffer: %m"); + drm_intel_bo_unreference (buffer_object); + return 0; + } + + buffer = ply_renderer_buffer_new (driver, + buffer_object, buffer_id, + width, height, *row_stride); + ply_hashtable_insert (driver->buffers, + (void *) (uintptr_t) buffer_id, + buffer); + + return buffer_id; +} + +static bool +map_buffer (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + ply_renderer_buffer_t *buffer; + + buffer = get_buffer_from_id (driver, buffer_id); + + assert (buffer != NULL); + drm_intel_gem_bo_map_gtt (buffer->object); + + return true; +} + +static void +unmap_buffer (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + ply_renderer_buffer_t *buffer; + + buffer = get_buffer_from_id (driver, buffer_id); + + assert (buffer != NULL); + drm_intel_gem_bo_unmap_gtt (buffer->object); +} + +static char * +begin_flush (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + ply_renderer_buffer_t *buffer; + + buffer = get_buffer_from_id (driver, buffer_id); + + assert (buffer != NULL); + + return buffer->object->virtual; +} + +static void +end_flush (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + ply_renderer_buffer_t *buffer; + + buffer = get_buffer_from_id (driver, buffer_id); + + assert (buffer != NULL); +} + +static void +destroy_buffer (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + ply_renderer_buffer_t *buffer; + + buffer = get_buffer_from_id (driver, buffer_id); + + assert (buffer != NULL); + + drmModeRmFB (driver->device_fd, buffer->id); + + drm_intel_bo_unreference (buffer->object); + + ply_hashtable_remove (driver->buffers, + (void *) (uintptr_t) buffer_id); + free (buffer); +} + +ply_renderer_driver_interface_t * +ply_renderer_i915_driver_get_interface (void) +{ + static ply_renderer_driver_interface_t driver_interface = + { + .create_driver = create_driver, + .destroy_driver = destroy_driver, + .create_buffer = create_buffer, + .fetch_buffer = fetch_buffer, + .map_buffer = map_buffer, + .unmap_buffer = unmap_buffer, + .begin_flush = begin_flush, + .end_flush = end_flush, + .destroy_buffer = destroy_buffer, + }; + + return &driver_interface; +} + +/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */ diff --git a/src/plugins/renderers/drm/ply-renderer-i915-driver.h b/src/plugins/renderers/drm/ply-renderer-i915-driver.h new file mode 100644 index 00000000..dcc983ce --- /dev/null +++ b/src/plugins/renderers/drm/ply-renderer-i915-driver.h @@ -0,0 +1,32 @@ +/* ply-renderer-i915-driver.h + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written By: Ray Strode <rstrode@redhat.com> + */ +#ifndef PLY_RENDERER_I915_DRIVER_H +#define PLY_RENDERER_I915_DRIVER_H + +#include "ply-renderer-driver.h" + +#ifndef PLY_HIDE_FUNCTION_DECLARATIONS +ply_renderer_driver_interface_t *ply_renderer_i915_driver_get_interface (void); +#endif + +#endif /* PLY_RENDERER_I915_DRIVER_H */ +/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */ diff --git a/src/plugins/renderers/drm/ply-renderer-nouveau-driver.c b/src/plugins/renderers/drm/ply-renderer-nouveau-driver.c new file mode 100644 index 00000000..a94b0f4b --- /dev/null +++ b/src/plugins/renderers/drm/ply-renderer-nouveau-driver.c @@ -0,0 +1,332 @@ +/* ply-renderer-nouveau-driver.c - interface to nouveau drm driver + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: Ray Strode <rstrode@redhat.com> + */ +#include "config.h" + +#include "ply-renderer-nouveau-driver.h" + +#include <arpa/inet.h> +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <string.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <values.h> +#include <unistd.h> + +#include <drm/drm.h> +#include <drm/nouveau_drm.h> +#include <drm/nouveau_drmif.h> +#include <nouveau/nouveau_bo.h> +#include <xf86drm.h> +#include <xf86drmMode.h> + +#include "ply-hashtable.h" +#include "ply-logger.h" +#include "ply-renderer-driver.h" + +typedef struct _ply_renderer_buffer ply_renderer_buffer_t; + +struct _ply_renderer_buffer +{ + struct nouveau_bo *object; + uint32_t id; + unsigned long width; + unsigned long height; + unsigned long row_stride; +}; + +struct _ply_renderer_driver +{ + int device_fd; + struct nouveau_device *device; + + ply_hashtable_t *buffers; +}; + +static ply_renderer_driver_t * +create_driver (int device_fd) +{ + ply_renderer_driver_t *driver; + + driver = calloc (1, sizeof (ply_renderer_driver_t)); + driver->device_fd = device_fd; + + if (nouveau_device_open_existing (&driver->device, true, + driver->device_fd, 0) < 0) + { + free (driver); + return NULL; + } + + driver->buffers = ply_hashtable_new (ply_hashtable_direct_hash, + ply_hashtable_direct_compare); + + return driver; +} + +static void +destroy_driver (ply_renderer_driver_t *driver) +{ + ply_hashtable_free (driver->buffers); + + nouveau_device_close (&driver->device); + free (driver); +} + +static ply_renderer_buffer_t * +ply_renderer_buffer_new (ply_renderer_driver_t *driver, + struct nouveau_bo *buffer_object, + uint32_t id, + unsigned long width, + unsigned long height, + unsigned long row_stride) +{ + ply_renderer_buffer_t *buffer; + + buffer = calloc (1, sizeof (ply_renderer_buffer_t)); + buffer->object = buffer_object; + buffer->id = id; + buffer->width = width; + buffer->height = height; + buffer->row_stride = row_stride; + + return buffer; +} + +static ply_renderer_buffer_t * +ply_renderer_buffer_new_from_id (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + ply_renderer_buffer_t *buffer; + drmModeFB *fb; + struct nouveau_bo *buffer_object; + + fb = drmModeGetFB (driver->device_fd, buffer_id); + + if (fb == NULL) + return NULL; + + if (nouveau_bo_wrap (driver->device, + fb->handle, &buffer_object) < 0) + { + drmModeFreeFB (fb); + return NULL; + } + + buffer = ply_renderer_buffer_new (driver, buffer_object, buffer_id, + fb->width, fb->height, fb->pitch); + drmModeFreeFB (fb); + + return buffer; +} + +static ply_renderer_buffer_t * +get_buffer_from_id (ply_renderer_driver_t *driver, + uint32_t id) +{ + static ply_renderer_buffer_t *buffer; + + buffer = ply_hashtable_lookup (driver->buffers, (void *) (uintptr_t) id); + + return buffer; +} + +static bool +fetch_buffer (ply_renderer_driver_t *driver, + uint32_t buffer_id, + unsigned long *width, + unsigned long *height, + unsigned long *row_stride) +{ + ply_renderer_buffer_t *buffer; + + buffer = get_buffer_from_id (driver, buffer_id); + + if (buffer == NULL) + { + buffer = ply_renderer_buffer_new_from_id (driver, buffer_id); + + if (buffer == NULL) + return false; + + ply_hashtable_insert (driver->buffers, + (void *) (uintptr_t) buffer_id, + buffer); + } + + if (width != NULL) + *width = buffer->width; + + if (height != NULL) + *height = buffer->height; + + if (row_stride != NULL) + *row_stride = buffer->row_stride; + + return true; +} + + +static uint32_t +create_buffer (ply_renderer_driver_t *driver, + unsigned long width, + unsigned long height, + unsigned long *row_stride) +{ + struct nouveau_bo *buffer_object; + ply_renderer_buffer_t *buffer; + uint32_t buffer_id; + + *row_stride = ply_round_to_multiple (width * 4, 256); + + buffer_object = NULL; + if (nouveau_bo_new (driver->device, + NOUVEAU_BO_VRAM | NOUVEAU_BO_MAP, 0, + height * *row_stride, &buffer_object) < 0) + { + ply_trace ("Could not allocate GEM object for frame buffer: %m"); + return 0; + } + + /* The map here forces the buffer object to be instantiated + * immediately (it's normally instantiated lazily when needed + * by other nouveau_bo api) + */ + nouveau_bo_map (buffer_object, NOUVEAU_BO_WR); + if (drmModeAddFB (driver->device_fd, width, height, + 24, 32, *row_stride, buffer_object->handle, + &buffer_id) != 0) + { + nouveau_bo_unmap (buffer_object); + ply_trace ("Could not set up GEM object as frame buffer: %m"); + nouveau_bo_ref (NULL, &buffer_object); + return 0; + } + nouveau_bo_unmap (buffer_object); + + buffer = ply_renderer_buffer_new (driver, + buffer_object, buffer_id, + width, height, *row_stride); + ply_hashtable_insert (driver->buffers, + (void *) (uintptr_t) buffer_id, + buffer); + + return buffer_id; +} + +static bool +map_buffer (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + ply_renderer_buffer_t *buffer; + + buffer = get_buffer_from_id (driver, buffer_id); + + assert (buffer != NULL); + + return nouveau_bo_map (buffer->object, NOUVEAU_BO_WR) == 0; +} + +static void +unmap_buffer (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + ply_renderer_buffer_t *buffer; + + buffer = get_buffer_from_id (driver, buffer_id); + + assert (buffer != NULL); + + nouveau_bo_unmap (buffer->object); +} + +static char * +begin_flush (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + ply_renderer_buffer_t *buffer; + + buffer = get_buffer_from_id (driver, buffer_id); + + assert (buffer != NULL); + + return buffer->object->map; +} + +static void +end_flush (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + ply_renderer_buffer_t *buffer; + + buffer = get_buffer_from_id (driver, buffer_id); + + assert (buffer != NULL); +} + +static void +destroy_buffer (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + ply_renderer_buffer_t *buffer; + + buffer = get_buffer_from_id (driver, buffer_id); + + assert (buffer != NULL); + + drmModeRmFB (driver->device_fd, buffer->id); + + nouveau_bo_ref (NULL, &buffer->object); + + ply_hashtable_remove (driver->buffers, + (void *) (uintptr_t) buffer_id); + free (buffer); +} + +ply_renderer_driver_interface_t * +ply_renderer_nouveau_driver_get_interface (void) +{ + static ply_renderer_driver_interface_t driver_interface = + { + .create_driver = create_driver, + .destroy_driver = destroy_driver, + .create_buffer = create_buffer, + .fetch_buffer = fetch_buffer, + .map_buffer = map_buffer, + .unmap_buffer = unmap_buffer, + .begin_flush = begin_flush, + .end_flush = end_flush, + .destroy_buffer = destroy_buffer, + }; + + return &driver_interface; +} + +/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */ diff --git a/src/plugins/renderers/drm/ply-renderer-nouveau-driver.h b/src/plugins/renderers/drm/ply-renderer-nouveau-driver.h new file mode 100644 index 00000000..1baed4a8 --- /dev/null +++ b/src/plugins/renderers/drm/ply-renderer-nouveau-driver.h @@ -0,0 +1,32 @@ +/* ply-renderer-nouveau-driver.h + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written By: Ray Strode <rstrode@redhat.com> + */ +#ifndef PLY_RENDERER_NOUVEAU_DRIVER_H +#define PLY_RENDERER_NOUVEAU_DRIVER_H + +#include "ply-renderer-driver.h" + +#ifndef PLY_HIDE_FUNCTION_DECLARATIONS +ply_renderer_driver_interface_t *ply_renderer_nouveau_driver_get_interface (void); +#endif + +#endif /* PLY_RENDERER_NOUVEAU_DRIVER_H */ +/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */ diff --git a/src/plugins/renderers/drm/ply-renderer-radeon-driver.c b/src/plugins/renderers/drm/ply-renderer-radeon-driver.c new file mode 100644 index 00000000..be11dbf8 --- /dev/null +++ b/src/plugins/renderers/drm/ply-renderer-radeon-driver.c @@ -0,0 +1,354 @@ +/* ply-renderer-radeon-driver.c - interface to radeon drm driver + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: Ray Strode <rstrode@redhat.com> + */ +#include "config.h" + +#include "ply-renderer-radeon-driver.h" + +#include <arpa/inet.h> +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <string.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <values.h> +#include <unistd.h> + +#include <drm/drm.h> +#include <drm/radeon_drm.h> +#include <drm/radeon_bo.h> +#include <drm/radeon_bo_gem.h> +#include <xf86drm.h> +#include <xf86drmMode.h> + +#include "ply-hashtable.h" +#include "ply-logger.h" +#include "ply-renderer-driver.h" + +typedef struct _ply_renderer_buffer ply_renderer_buffer_t; + +struct _ply_renderer_buffer +{ + struct radeon_bo *object; + uint32_t id; + unsigned long width; + unsigned long height; + unsigned long row_stride; +}; + +struct _ply_renderer_driver +{ + int device_fd; + struct radeon_bo_manager *manager; + + ply_hashtable_t *buffers; +}; + +static ply_renderer_driver_t * +create_driver (int device_fd) +{ + ply_renderer_driver_t *driver; + + driver = calloc (1, sizeof (ply_renderer_driver_t)); + driver->device_fd = device_fd; + + driver->manager = radeon_bo_manager_gem_ctor (driver->device_fd); + if (driver->manager == NULL) + { + free (driver); + return NULL; + } + + driver->buffers = ply_hashtable_new (ply_hashtable_direct_hash, + ply_hashtable_direct_compare); + + return driver; +} + +static void +destroy_driver (ply_renderer_driver_t *driver) +{ + ply_hashtable_free (driver->buffers); + + radeon_bo_manager_gem_dtor (driver->manager); + free (driver); +} + +static ply_renderer_buffer_t * +ply_renderer_buffer_new (ply_renderer_driver_t *driver, + struct radeon_bo *buffer_object, + uint32_t id, + unsigned long width, + unsigned long height, + unsigned long row_stride) +{ + ply_renderer_buffer_t *buffer; + + buffer = calloc (1, sizeof (ply_renderer_buffer_t)); + buffer->object = buffer_object; + buffer->id = id; + buffer->width = width; + buffer->height = height; + buffer->row_stride = row_stride; + + return buffer; +} + +static ply_renderer_buffer_t * +get_buffer_from_id (ply_renderer_driver_t *driver, + uint32_t id) +{ + static ply_renderer_buffer_t *buffer; + + buffer = ply_hashtable_lookup (driver->buffers, (void *) (uintptr_t) id); + + return buffer; +} + +static struct radeon_bo * +create_radeon_bo_from_handle (ply_renderer_driver_t *driver, + uint32_t handle) +{ + struct drm_gem_flink flink_request; + struct radeon_bo *buffer_object; + + /* FIXME: This can't be the right way to do this. + * + * 1) It requires skirting around the API and using ioctls + * 2) It requires taking a local handle, turning it into a + * a global handle ("name"), just so we can use an api that + * will open the global name and grab the local handle from it. + */ + + memset (&flink_request, 0, sizeof (struct drm_gem_flink)); + flink_request.handle = handle; + + if (ioctl (driver->device_fd, DRM_IOCTL_GEM_FLINK, &flink_request) < 0) + return NULL; + + buffer_object = radeon_bo_open (driver->manager, flink_request.name, + 0, 0, RADEON_GEM_DOMAIN_GTT, 0); + + return buffer_object; +} + +static ply_renderer_buffer_t * +ply_renderer_buffer_new_from_id (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + ply_renderer_buffer_t *buffer; + drmModeFB *fb; + struct radeon_bo *buffer_object; + + fb = drmModeGetFB (driver->device_fd, buffer_id); + + if (fb == NULL) + return NULL; + + buffer_object = create_radeon_bo_from_handle (driver, fb->handle); + + if (buffer_object == NULL) + { + drmModeFreeFB (fb); + return NULL; + } + + buffer = ply_renderer_buffer_new (driver, buffer_object, buffer_id, + fb->width, fb->height, fb->pitch); + drmModeFreeFB (fb); + + return buffer; +} + + +static bool +fetch_buffer (ply_renderer_driver_t *driver, + uint32_t buffer_id, + unsigned long *width, + unsigned long *height, + unsigned long *row_stride) +{ + ply_renderer_buffer_t *buffer; + + buffer = get_buffer_from_id (driver, buffer_id); + + if (buffer == NULL) + { + buffer = ply_renderer_buffer_new_from_id (driver, buffer_id); + + if (buffer == NULL) + return false; + + ply_hashtable_insert (driver->buffers, + (void *) (uintptr_t) buffer_id, + buffer); + } + + if (width != NULL) + *width = buffer->width; + + if (height != NULL) + *height = buffer->height; + + if (row_stride != NULL) + *row_stride = buffer->row_stride; + + return true; +} + +static uint32_t +create_buffer (ply_renderer_driver_t *driver, + unsigned long width, + unsigned long height, + unsigned long *row_stride) +{ + struct radeon_bo *buffer_object; + ply_renderer_buffer_t *buffer; + uint32_t buffer_id; + + *row_stride = ply_round_to_multiple (width * 4, 256); + + buffer_object = radeon_bo_open (driver->manager, 0, + height * *row_stride, + 0, RADEON_GEM_DOMAIN_GTT, 0); + + if (buffer_object == NULL) + { + ply_trace ("Could not allocate GEM object for frame buffer: %m"); + return 0; + } + + if (drmModeAddFB (driver->device_fd, width, height, + 24, 32, *row_stride, buffer_object->handle, + &buffer_id) != 0) + { + ply_trace ("Could not set up GEM object as frame buffer: %m"); + radeon_bo_unref (buffer_object); + return 0; + } + + buffer = ply_renderer_buffer_new (driver, + buffer_object, buffer_id, + width, height, *row_stride); + ply_hashtable_insert (driver->buffers, + (void *) (uintptr_t) buffer_id, + buffer); + + return buffer_id; +} + +static bool +map_buffer (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + ply_renderer_buffer_t *buffer; + + buffer = get_buffer_from_id (driver, buffer_id); + + assert (buffer != NULL); + + return radeon_bo_map (buffer->object, true) == 0; +} + +static void +unmap_buffer (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + ply_renderer_buffer_t *buffer; + + buffer = get_buffer_from_id (driver, buffer_id); + + assert (buffer != NULL); + + radeon_bo_unmap (buffer->object); +} + +static char * +begin_flush (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + ply_renderer_buffer_t *buffer; + + buffer = get_buffer_from_id (driver, buffer_id); + + assert (buffer != NULL); + + return buffer->object->ptr; +} + +static void +end_flush (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + ply_renderer_buffer_t *buffer; + + buffer = get_buffer_from_id (driver, buffer_id); + + assert (buffer != NULL); +} + +static void +destroy_buffer (ply_renderer_driver_t *driver, + uint32_t buffer_id) +{ + ply_renderer_buffer_t *buffer; + + buffer = get_buffer_from_id (driver, buffer_id); + + assert (buffer != NULL); + + drmModeRmFB (driver->device_fd, buffer->id); + + radeon_bo_unref (buffer->object); + + ply_hashtable_remove (driver->buffers, + (void *) (uintptr_t) buffer_id); + free (buffer); +} + +ply_renderer_driver_interface_t * +ply_renderer_radeon_driver_get_interface (void) +{ + static ply_renderer_driver_interface_t driver_interface = + { + .create_driver = create_driver, + .destroy_driver = destroy_driver, + .create_buffer = create_buffer, + .fetch_buffer = fetch_buffer, + .map_buffer = map_buffer, + .unmap_buffer = unmap_buffer, + .begin_flush = begin_flush, + .end_flush = end_flush, + .destroy_buffer = destroy_buffer, + }; + + return &driver_interface; +} + +/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */ diff --git a/src/plugins/renderers/drm/ply-renderer-radeon-driver.h b/src/plugins/renderers/drm/ply-renderer-radeon-driver.h new file mode 100644 index 00000000..dcec1b1b --- /dev/null +++ b/src/plugins/renderers/drm/ply-renderer-radeon-driver.h @@ -0,0 +1,32 @@ +/* ply-renderer-radeon-driver.h + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written By: Ray Strode <rstrode@redhat.com> + */ +#ifndef PLY_RENDERER_RADEON_DRIVER_H +#define PLY_RENDERER_RADEON_DRIVER_H + +#include "ply-renderer-driver.h" + +#ifndef PLY_HIDE_FUNCTION_DECLARATIONS +ply_renderer_driver_interface_t *ply_renderer_radeon_driver_get_interface (void); +#endif + +#endif /* PLY_RENDERER_RADEON_DRIVER_H */ +/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */ diff --git a/src/plugins/renderers/frame-buffer/Makefile.am b/src/plugins/renderers/frame-buffer/Makefile.am new file mode 100644 index 00000000..6811e01d --- /dev/null +++ b/src/plugins/renderers/frame-buffer/Makefile.am @@ -0,0 +1,20 @@ +INCLUDES = -I$(top_srcdir) \ + -I$(srcdir)/../../../libply \ + -I$(srcdir)/../../../libplybootsplash \ + -I$(srcdir)/../../.. \ + -I$(srcdir)/../.. \ + -I$(srcdir)/.. \ + -I$(srcdir) + +plugindir = $(libdir)/plymouth/renderers +plugin_LTLIBRARIES = frame-buffer.la + +frame_buffer_la_CFLAGS = $(PLYMOUTH_CFLAGS) + +frame_buffer_la_LDFLAGS = -module -avoid-version -export-dynamic +frame_buffer_la_LIBADD = $(PLYMOUTH_LIBS) \ + ../../../libply/libply.la \ + ../../../libplybootsplash/libplybootsplash.la +frame_buffer_la_SOURCES = $(srcdir)/plugin.c + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/plugins/renderers/frame-buffer/plugin.c b/src/plugins/renderers/frame-buffer/plugin.c new file mode 100644 index 00000000..85d9e7dd --- /dev/null +++ b/src/plugins/renderers/frame-buffer/plugin.c @@ -0,0 +1,667 @@ +/* plugin.c - frame-backend renderer plugin + * + * Copyright (C) 2006-2009 Red Hat, Inc. + * 2008 Charlie Brej <cbrej@cs.man.ac.uk> + * + * 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: Charlie Brej <cbrej@cs.man.ac.uk> + * Kristian Høgsberg <krh@redhat.com> + * Peter Jones <pjones@redhat.com> + * Ray Strode <rstrode@redhat.com> + */ +#include "config.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 <linux/fb.h> + +#include "ply-buffer.h" +#include "ply-event-loop.h" +#include "ply-list.h" +#include "ply-logger.h" +#include "ply-rectangle.h" +#include "ply-region.h" +#include "ply-terminal.h" + +#include "ply-renderer.h" +#include "ply-renderer-plugin.h" + +#ifndef PLY_FRAME_BUFFER_DEFAULT_FB_DEVICE_NAME +#define PLY_FRAME_BUFFER_DEFAULT_FB_DEVICE_NAME "/dev/fb" +#endif + +struct _ply_renderer_head +{ + ply_pixel_buffer_t *pixel_buffer; + ply_rectangle_t area; + char *map_address; + size_t size; + +}; + +struct _ply_renderer_input_source +{ + ply_fd_watch_t *terminal_input_watch; + + ply_buffer_t *key_buffer; + + ply_renderer_input_source_handler_t handler; + void *user_data; +}; + +struct _ply_renderer_backend +{ + ply_event_loop_t *loop; + ply_console_t *console; + ply_terminal_t *terminal; + + char *device_name; + int device_fd; + + ply_renderer_input_source_t input_source; + ply_renderer_head_t head; + ply_list_t *heads; + + uint32_t red_bit_position; + uint32_t green_bit_position; + uint32_t blue_bit_position; + uint32_t alpha_bit_position; + + uint32_t bits_for_red; + uint32_t bits_for_green; + uint32_t bits_for_blue; + uint32_t bits_for_alpha; + + int32_t dither_red; + int32_t dither_green; + int32_t dither_blue; + + unsigned int bytes_per_pixel; + unsigned int row_stride; + + void (* flush_area) (ply_renderer_backend_t *backend, + ply_renderer_head_t *head, + ply_rectangle_t *area_to_flush); +}; + +ply_renderer_plugin_interface_t *ply_renderer_backend_get_interface (void); +static void ply_renderer_head_redraw (ply_renderer_backend_t *backend, + ply_renderer_head_t *head); + +static inline uint_fast32_t +argb32_pixel_value_to_device_pixel_value (ply_renderer_backend_t *backend, + uint32_t pixel_value) +{ + uint8_t r, g, b, a; + int orig_r, orig_g, orig_b, orig_a; + uint8_t new_r, new_g, new_b; + int i; + + orig_a = pixel_value >> 24; + a = orig_a >> (8 - backend->bits_for_alpha); + + orig_r = ((pixel_value >> 16) & 0xff) - backend->dither_red; + r = CLAMP (orig_r, 0, 255) >> (8 - backend->bits_for_red); + + orig_g = ((pixel_value >> 8) & 0xff) - backend->dither_green; + g = CLAMP (orig_g, 0, 255) >> (8 - backend->bits_for_green); + + orig_b = (pixel_value & 0xff) - backend->dither_blue; + b = CLAMP (orig_b, 0, 255) >> (8 - backend->bits_for_blue); + + new_r = r << (8 - backend->bits_for_red); + new_g = g << (8 - backend->bits_for_green); + new_b = b << (8 - backend->bits_for_blue); + + for (i = backend->bits_for_red; i < 8; i <<= 1) + new_r |= new_r >> i; + + for (i = backend->bits_for_green; i < 8; i <<= 1) + new_g |= new_g >> i; + + for (i = backend->bits_for_blue; i < 8; i <<= 1) + new_b |= new_b >> i; + + backend->dither_red = new_r - orig_r; + backend->dither_green = new_g - orig_g; + backend->dither_blue = new_b - orig_b; + + return ((a << backend->alpha_bit_position) + | (r << backend->red_bit_position) + | (g << backend->green_bit_position) + | (b << backend->blue_bit_position)); +} + +static void +flush_area_to_any_device (ply_renderer_backend_t *backend, + ply_renderer_head_t *head, + ply_rectangle_t *area_to_flush) +{ + unsigned long row, column; + uint32_t *shadow_buffer; + char *row_backend; + size_t bytes_per_row; + unsigned long x1, y1, x2, y2; + + x1 = area_to_flush->x; + y1 = area_to_flush->y; + x2 = x1 + area_to_flush->width; + y2 = y1 + area_to_flush->height; + + bytes_per_row = area_to_flush->width * backend->bytes_per_pixel; + row_backend = malloc (backend->row_stride); + shadow_buffer = ply_pixel_buffer_get_argb32_data (backend->head.pixel_buffer); + for (row = y1; row < y2; row++) + { + unsigned long offset; + + for (column = x1; column < x2; column++) + { + uint32_t pixel_value; + uint_fast32_t device_pixel_value; + + pixel_value = shadow_buffer[row * head->area.width + column]; + + device_pixel_value = argb32_pixel_value_to_device_pixel_value (backend, + pixel_value); + + memcpy (row_backend + column * backend->bytes_per_pixel, + &device_pixel_value, backend->bytes_per_pixel); + } + + offset = row * backend->row_stride + x1 * backend->bytes_per_pixel; + memcpy (head->map_address + offset, row_backend + x1 * backend->bytes_per_pixel, + area_to_flush->width * backend->bytes_per_pixel); + } + free (row_backend); +} + +static void +flush_area_to_xrgb32_device (ply_renderer_backend_t *backend, + ply_renderer_head_t *head, + ply_rectangle_t *area_to_flush) +{ + unsigned long x1, y1, x2, y2, y; + uint32_t *shadow_buffer; + char *dst, *src; + + x1 = area_to_flush->x; + y1 = area_to_flush->y; + x2 = x1 + area_to_flush->width; + y2 = y1 + area_to_flush->height; + + shadow_buffer = ply_pixel_buffer_get_argb32_data (backend->head.pixel_buffer); + + dst = &head->map_address[y1 * backend->row_stride + x1 * backend->bytes_per_pixel]; + src = (char *) &shadow_buffer[y1 * head->area.width + x1]; + + if (area_to_flush->width == backend->row_stride) + { + memcpy (dst, src, area_to_flush->width * area_to_flush->height * 4); + return; + } + + for (y = y1; y < y2; y++) + { + memcpy (dst, src, area_to_flush->width * 4); + dst += backend->row_stride; + src += head->area.width * 4; + } +} + +static ply_renderer_backend_t * +create_backend (const char *device_name, + ply_terminal_t *terminal, + ply_console_t *console) +{ + ply_renderer_backend_t *backend; + + backend = calloc (1, sizeof (ply_renderer_backend_t)); + + if (device_name != NULL) + backend->device_name = strdup (device_name); + else if (getenv ("FRAMEBUFFER") != NULL) + backend->device_name = strdup (getenv ("FRAMEBUFFER")); + else + backend->device_name = + strdup (PLY_FRAME_BUFFER_DEFAULT_FB_DEVICE_NAME); + + backend->loop = ply_event_loop_get_default (); + backend->heads = ply_list_new (); + backend->input_source.key_buffer = ply_buffer_new (); + backend->console = console; + backend->terminal = terminal; + + return backend; +} + +static void +initialize_head (ply_renderer_backend_t *backend, + ply_renderer_head_t *head) +{ + head->pixel_buffer = ply_pixel_buffer_new (head->area.width, + head->area.height); + ply_pixel_buffer_fill_with_color (backend->head.pixel_buffer, NULL, + 0.0, 0.0, 0.0, 1.0); + ply_list_append_data (backend->heads, head); +} + +static void +uninitialize_head (ply_renderer_backend_t *backend, + ply_renderer_head_t *head) +{ + if (head->pixel_buffer != NULL) + { + ply_pixel_buffer_free (head->pixel_buffer); + head->pixel_buffer = NULL; + + ply_list_remove_data (backend->heads, head); + } +} + +static void +destroy_backend (ply_renderer_backend_t *backend) +{ + + free (backend->device_name); + uninitialize_head (backend, &backend->head); + + ply_list_free (backend->heads); + + free (backend); +} + +static void +on_active_vt_changed (ply_renderer_backend_t *backend) +{ + if (ply_console_get_active_vt (backend->console) != + ply_terminal_get_vt_number (backend->terminal)) + return; + + if (backend->head.map_address != MAP_FAILED) + ply_renderer_head_redraw (backend, &backend->head); +} + +static bool +open_device (ply_renderer_backend_t *backend) +{ + backend->device_fd = open (backend->device_name, O_RDWR); + + if (backend->device_fd < 0) + { + ply_trace ("could not open '%s': %m", backend->device_name); + return false; + } + + ply_console_watch_for_active_vt_change (backend->console, + (ply_console_active_vt_changed_handler_t) + on_active_vt_changed, + backend); + + return true; +} + +static void +close_device (ply_renderer_backend_t *backend) +{ + + ply_console_stop_watching_for_active_vt_change (backend->console, + (ply_console_active_vt_changed_handler_t) + on_active_vt_changed, + backend); + close (backend->device_fd); + backend->device_fd = -1; + + backend->bytes_per_pixel = 0; + backend->head.area.x = 0; + backend->head.area.y = 0; + backend->head.area.width = 0; + backend->head.area.height = 0; +} + +static const char const *get_visual_name (int visual) +{ + static const char const *visuals[] = + { + [FB_VISUAL_MONO01] = "FB_VISUAL_MONO01", + [FB_VISUAL_MONO10] = "FB_VISUAL_MONO10", + [FB_VISUAL_TRUECOLOR] = "FB_VISUAL_TRUECOLOR", + [FB_VISUAL_PSEUDOCOLOR] = "FB_VISUAL_PSEUDOCOLOR", + [FB_VISUAL_DIRECTCOLOR] = "FB_VISUAL_DIRECTCOLOR", + [FB_VISUAL_STATIC_PSEUDOCOLOR] = "FB_VISUAL_STATIC_PSEUDOCOLOR", + NULL + }; + static char unknown[] = "invalid visual: -4294967295"; + + if (visual < FB_VISUAL_MONO01 || visual > FB_VISUAL_STATIC_PSEUDOCOLOR) + { + sprintf (unknown, "invalid visual: %d", visual); + return unknown; + } + + return visuals[visual]; +} + +static bool +query_device (ply_renderer_backend_t *backend) +{ + struct fb_var_screeninfo variable_screen_info; + struct fb_fix_screeninfo fixed_screen_info; + + assert (backend != NULL); + assert (backend->device_fd >= 0); + + if (ioctl (backend->device_fd, FBIOGET_VSCREENINFO, &variable_screen_info) < 0) + return false; + + if (ioctl (backend->device_fd, FBIOGET_FSCREENINFO, &fixed_screen_info) < 0) + return false; + + /* Normally the pixel is divided into channels between the color components. + * Each channel directly maps to a color channel on the hardware. + * + * There are some odd ball modes that use an indexed palette instead. In + * those cases (pseudocolor, direct color, etc), the pixel value is just an + * index into a lookup table of the real color values. + * + * We don't support that. + */ + if (fixed_screen_info.visual != FB_VISUAL_TRUECOLOR) + { + int rc = -1; + int i; + static const int depths[] = {32, 24, 16, 0}; + + ply_trace ("Visual was %s, trying to find usable mode.\n", + get_visual_name (fixed_screen_info.visual)); + + for (i = 0; depths[i] != 0; i++) + { + variable_screen_info.bits_per_pixel = depths[i]; + variable_screen_info.activate |= FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; + + rc = ioctl (backend->device_fd, FBIOPUT_VSCREENINFO, &variable_screen_info); + if (rc >= 0) + { + if (ioctl (backend->device_fd, FBIOGET_FSCREENINFO, &fixed_screen_info) < 0) + return false; + + if (fixed_screen_info.visual == FB_VISUAL_TRUECOLOR) + break; + } + } + + if (ioctl (backend->device_fd, FBIOGET_VSCREENINFO, &variable_screen_info) < 0) + return false; + + if (ioctl (backend->device_fd, FBIOGET_FSCREENINFO, &fixed_screen_info) < 0) + return false; + } + + if (fixed_screen_info.visual != FB_VISUAL_TRUECOLOR || + variable_screen_info.bits_per_pixel < 16) + { + ply_trace ("Visual is %s; not using graphics\n", + get_visual_name (fixed_screen_info.visual)); + return false; + } + + backend->head.area.x = variable_screen_info.xoffset; + backend->head.area.y = variable_screen_info.yoffset; + backend->head.area.width = variable_screen_info.xres; + backend->head.area.height = variable_screen_info.yres; + + backend->red_bit_position = variable_screen_info.red.offset; + backend->bits_for_red = variable_screen_info.red.length; + + backend->green_bit_position = variable_screen_info.green.offset; + backend->bits_for_green = variable_screen_info.green.length; + + backend->blue_bit_position = variable_screen_info.blue.offset; + backend->bits_for_blue = variable_screen_info.blue.length; + + backend->alpha_bit_position = variable_screen_info.transp.offset; + backend->bits_for_alpha = variable_screen_info.transp.length; + + backend->bytes_per_pixel = variable_screen_info.bits_per_pixel >> 3; + backend->row_stride = fixed_screen_info.line_length; + backend->dither_red = 0; + backend->dither_green = 0; + backend->dither_blue = 0; + + backend->head.size = backend->head.area.height * backend->row_stride; + + if (backend->bytes_per_pixel == 4 && + backend->red_bit_position == 16 && backend->bits_for_red == 8 && + backend->green_bit_position == 8 && backend->bits_for_green == 8 && + backend->blue_bit_position == 0 && backend->bits_for_blue == 8) + backend->flush_area = flush_area_to_xrgb32_device; + else + backend->flush_area = flush_area_to_any_device; + + return true; + +} + +static bool +map_to_device (ply_renderer_backend_t *backend) +{ + ply_renderer_head_t *head; + + assert (backend != NULL); + assert (backend->device_fd >= 0); + + head = &backend->head; + assert (head->size > 0); + + head->map_address = mmap (NULL, head->size, PROT_WRITE, + MAP_SHARED, backend->device_fd, 0); + + if (head->map_address == MAP_FAILED) + return false; + + initialize_head (backend, head); + + return true; +} + +static void +unmap_from_device (ply_renderer_backend_t *backend) +{ + ply_renderer_head_t *head; + + head = &backend->head; + + uninitialize_head (backend, head); + + if (head->map_address != MAP_FAILED) + { + munmap (head->map_address, head->size); + head->map_address = MAP_FAILED; + } +} + +static void +flush_head (ply_renderer_backend_t *backend, + ply_renderer_head_t *head) +{ + ply_region_t *updated_region; + ply_list_t *areas_to_flush; + ply_list_node_t *node; + ply_pixel_buffer_t *pixel_buffer; + + assert (backend != NULL); + assert (&backend->head == head); + + ply_console_set_mode (backend->console, PLY_CONSOLE_MODE_GRAPHICS); + pixel_buffer = head->pixel_buffer; + updated_region = ply_pixel_buffer_get_updated_areas (pixel_buffer); + areas_to_flush = ply_region_get_rectangle_list (updated_region); + + node = ply_list_get_first_node (areas_to_flush); + while (node != NULL) + { + ply_list_node_t *next_node; + ply_rectangle_t *area_to_flush; + + area_to_flush = (ply_rectangle_t *) ply_list_node_get_data (node); + + next_node = ply_list_get_next_node (areas_to_flush, node); + + backend->flush_area (backend, head, area_to_flush); + + node = next_node; + } + + ply_region_clear (updated_region); +} + +static void +ply_renderer_head_redraw (ply_renderer_backend_t *backend, + ply_renderer_head_t *head) +{ + ply_region_t *region; + + region = ply_pixel_buffer_get_updated_areas (head->pixel_buffer); + + ply_region_add_rectangle (region, &head->area); + + flush_head (backend, head); +} + +static ply_list_t * +get_heads (ply_renderer_backend_t *backend) +{ + return backend->heads; +} + +static ply_pixel_buffer_t * +get_buffer_for_head (ply_renderer_backend_t *backend, + ply_renderer_head_t *head) +{ + + if (head != &backend->head) + return NULL; + + return backend->head.pixel_buffer; +} + +static bool +has_input_source (ply_renderer_backend_t *backend, + ply_renderer_input_source_t *input_source) +{ + return input_source == &backend->input_source; +} + +static ply_renderer_input_source_t * +get_input_source (ply_renderer_backend_t *backend) +{ + return &backend->input_source; +} + +static void +on_key_event (ply_renderer_input_source_t *input_source, + int terminal_fd) +{ + ply_buffer_append_from_fd (input_source->key_buffer, + terminal_fd); + + if (input_source->handler != NULL) + input_source->handler (input_source->user_data, input_source->key_buffer, input_source); + +} + +static bool +open_input_source (ply_renderer_backend_t *backend, + ply_renderer_input_source_t *input_source) +{ + int terminal_fd; + + assert (backend != NULL); + assert (has_input_source (backend, input_source)); + + terminal_fd = ply_terminal_get_fd (backend->terminal); + + input_source->terminal_input_watch = ply_event_loop_watch_fd (backend->loop, terminal_fd, PLY_EVENT_LOOP_FD_STATUS_HAS_DATA, + (ply_event_handler_t) on_key_event, + NULL, input_source); + return true; +} + +static void +set_handler_for_input_source (ply_renderer_backend_t *backend, + ply_renderer_input_source_t *input_source, + ply_renderer_input_source_handler_t handler, + void *user_data) +{ + assert (backend != NULL); + assert (has_input_source (backend, input_source)); + + input_source->handler = handler; + input_source->user_data = user_data; +} + +static void +close_input_source (ply_renderer_backend_t *backend, + ply_renderer_input_source_t *input_source) +{ + assert (backend != NULL); + assert (has_input_source (backend, input_source)); + + ply_event_loop_stop_watching_fd (backend->loop, input_source->terminal_input_watch); + input_source->terminal_input_watch = NULL; +} + +ply_renderer_plugin_interface_t * +ply_renderer_backend_get_interface (void) +{ + static ply_renderer_plugin_interface_t plugin_interface = + { + .create_backend = create_backend, + .destroy_backend = destroy_backend, + .open_device = open_device, + .close_device = close_device, + .query_device = query_device, + .map_to_device = map_to_device, + .unmap_from_device = unmap_from_device, + .flush_head = flush_head, + .get_heads = get_heads, + .get_buffer_for_head = get_buffer_for_head, + .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 + }; + + return &plugin_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/splash/details/plugin.c b/src/plugins/splash/details/plugin.c index 5d37eaaf..25a3aa23 100644 --- a/src/plugins/splash/details/plugin.c +++ b/src/plugins/splash/details/plugin.c @@ -46,11 +46,10 @@ #include "ply-key-file.h" #include "ply-list.h" #include "ply-logger.h" -#include "ply-frame-buffer.h" #include "ply-image.h" +#include "ply-text-display.h" #include "ply-trigger.h" #include "ply-utils.h" -#include "ply-window.h" #include <linux/kd.h> @@ -62,27 +61,66 @@ typedef enum { PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY } ply_boot_splash_display_type_t; - -typedef void (* ply_boot_splash_plugin_window_handler_t) (ply_window_t *window, ply_boot_splash_plugin_t *, void *user_data, void *other_user_data); - -static void uninitialize_window (ply_window_t *window, - ply_boot_splash_plugin_t *plugin); - -static void for_each_window (ply_boot_splash_plugin_t *plugin, - ply_boot_splash_plugin_window_handler_t handler, - void *user_data, - void *other_user_data); +typedef struct +{ + ply_boot_splash_plugin_t *plugin; + ply_text_display_t *display; +} view_t; ply_boot_splash_plugin_interface_t *ply_boot_splash_plugin_get_interface (void); struct _ply_boot_splash_plugin { ply_event_loop_t *loop; ply_boot_splash_mode_t mode; - ply_list_t *windows; + ply_list_t *views; ply_boot_splash_display_type_t state; }; +static view_t * +view_new (ply_boot_splash_plugin_t *plugin, + ply_text_display_t *display) +{ + view_t *view; + + view = calloc (1, sizeof (view_t)); + view->plugin = plugin; + view->display = display; + + return view; +} + +static void +view_free (view_t *view) +{ + free (view); +} + +static void +free_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_free (view); + ply_list_remove_node (plugin->views, node); + + node = next_node; + } + + ply_list_free (plugin->views); + plugin->views = NULL; +} + static ply_boot_splash_plugin_t * create_plugin (ply_key_file_t *key_file) { @@ -91,7 +129,7 @@ create_plugin (ply_key_file_t *key_file) ply_trace ("creating plugin"); plugin = calloc (1, sizeof (ply_boot_splash_plugin_t)); - plugin->windows = ply_list_new (); + plugin->views = ply_list_new (); plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL; return plugin; } @@ -104,11 +142,7 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin) if (plugin == NULL) return; - for_each_window (plugin, - (ply_boot_splash_plugin_window_handler_t) - uninitialize_window, NULL, NULL); - - ply_list_free (plugin->windows); + free_views (plugin); free (plugin); } @@ -122,103 +156,77 @@ detach_from_event_loop (ply_boot_splash_plugin_t *plugin) } static void -for_each_window (ply_boot_splash_plugin_t *plugin, - ply_boot_splash_plugin_window_handler_t handler, - void *user_data, - void *other_user_data) +view_write (view_t *view, + const char *text, + size_t number_of_bytes) +{ + ply_terminal_t *terminal; + + terminal = ply_text_display_get_terminal (view->display); + ply_terminal_write (terminal, "%.*s", (int) number_of_bytes, text); +} + +static void +write_on_views (ply_boot_splash_plugin_t *plugin, + const char *text, + size_t number_of_bytes) { ply_list_node_t *node; - node = ply_list_get_first_node (plugin->windows); + if (number_of_bytes == 0) + return; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) { ply_list_node_t *next_node; - ply_window_t *window; + view_t *view; - next_node = ply_list_get_next_node (plugin->windows, node); + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - window = ply_list_node_get_data (node); - - handler (window, plugin, user_data, other_user_data); + view_write (view, text, number_of_bytes); node = next_node; } -} -static void -write_text_on_window (ply_window_t *window, - ply_boot_splash_plugin_t *plugin, - const char *text, - void *user_data) -{ - int fd; - size_t size; - - ply_window_set_mode (window, PLY_WINDOW_MODE_TEXT); - - size = (size_t) user_data; - - fd = ply_window_get_tty_fd (window); - - write (fd, text, size); } -void -on_keyboard_input (ply_boot_splash_plugin_t *plugin, - const char *keyboard_input, - size_t character_size) +static void +add_text_display (ply_boot_splash_plugin_t *plugin, + ply_text_display_t *display) { -} + view_t *view; -void -on_backspace (ply_boot_splash_plugin_t *plugin) -{ -} + view = view_new (plugin, display); -void -on_enter (ply_boot_splash_plugin_t *plugin, - const char *line) -{ + ply_list_append_data (plugin->views, view); } static void -add_window (ply_boot_splash_plugin_t *plugin, - ply_window_t *window) +remove_text_display (ply_boot_splash_plugin_t *plugin, + ply_text_display_t *display) { - ply_list_append_data (plugin->windows, window); -} + ply_list_node_t *node; -static void -remove_window (ply_boot_splash_plugin_t *plugin, - ply_window_t *window) -{ - ply_list_remove_data (plugin->windows, window); -} + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + view_t *view; + ply_list_node_t *next_node; -static void -initialize_window (ply_window_t *window, - ply_boot_splash_plugin_t *plugin) -{ - ply_window_set_mode (window, PLY_WINDOW_MODE_TEXT); - - ply_window_add_keyboard_input_handler (window, - (ply_window_keyboard_input_handler_t) - on_keyboard_input, plugin); - ply_window_add_backspace_handler (window, - (ply_window_backspace_handler_t) - on_backspace, plugin); - ply_window_add_enter_handler (window, - (ply_window_enter_handler_t) - on_enter, plugin); -} + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); -static void -uninitialize_window (ply_window_t *window, - ply_boot_splash_plugin_t *plugin) -{ - ply_window_remove_keyboard_input_handler (window, (ply_window_keyboard_input_handler_t) on_keyboard_input); - ply_window_remove_backspace_handler (window, (ply_window_backspace_handler_t) on_backspace); - ply_window_remove_enter_handler (window, (ply_window_enter_handler_t) on_enter); + if (view->display == display) + { + ply_list_remove_node (plugin->views, node); + return; + } + + node = next_node; + } } static bool @@ -231,9 +239,6 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, assert (plugin != NULL); - for_each_window (plugin, - (ply_boot_splash_plugin_window_handler_t) - initialize_window, NULL, NULL); plugin->loop = loop; plugin->mode = mode; @@ -243,10 +248,7 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, size = ply_buffer_get_size (boot_buffer); - if (size > 0) - write (STDOUT_FILENO, - ply_buffer_get_bytes (boot_buffer), - size); + write_on_views (plugin, ply_buffer_get_bytes (boot_buffer), size); return true; } @@ -265,13 +267,9 @@ on_boot_output (ply_boot_splash_plugin_t *plugin, const char *output, size_t size) { - ply_trace ("writing '%s' to all windows (%d bytes)", + ply_trace ("writing '%s' to all views (%d bytes)", output, (int) size); - if (size > 0) - for_each_window (plugin, - (ply_boot_splash_plugin_window_handler_t) - write_text_on_window, - (void *) output, (void *) size); + write_on_views (plugin, output, size); } static void @@ -282,10 +280,6 @@ hide_splash_screen (ply_boot_splash_plugin_t *plugin, ply_trace ("hiding splash screen"); - for_each_window (plugin, - (ply_boot_splash_plugin_window_handler_t) - uninitialize_window, NULL, NULL); - ply_event_loop_stop_watching_for_exit (plugin->loop, (ply_event_loop_exit_handler_t) detach_from_event_loop, @@ -297,16 +291,11 @@ static void display_normal (ply_boot_splash_plugin_t *plugin) { if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_NORMAL) - { - for_each_window (plugin, - (ply_boot_splash_plugin_window_handler_t) - write_text_on_window, - (void *) "\r\n", (void *) strlen ("\r\n")); - } + write_on_views (plugin, "\r\n", strlen ("\r\n")); + plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL; } - static void display_password (ply_boot_splash_plugin_t *plugin, const char *prompt, @@ -314,46 +303,26 @@ display_password (ply_boot_splash_plugin_t *plugin, { int i; if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY) - { - for_each_window (plugin, - (ply_boot_splash_plugin_window_handler_t) - write_text_on_window, - (void *) "\r\n", (void *) strlen ("\r\n")); - } + write_on_views (plugin, "\r\n", strlen ("\r\n")); else - { - for_each_window (plugin, - (ply_boot_splash_plugin_window_handler_t) - write_text_on_window, - (void *) CLEAR_LINE_SEQUENCE, - (void *) strlen (CLEAR_LINE_SEQUENCE)); - } + write_on_views (plugin, + CLEAR_LINE_SEQUENCE, + strlen (CLEAR_LINE_SEQUENCE)); plugin->state = PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY; - + if (prompt) - for_each_window (plugin, - (ply_boot_splash_plugin_window_handler_t) - write_text_on_window, - (void *) prompt, - (void *) strlen (prompt)); + write_on_views (plugin, + prompt, + strlen (prompt)); else - for_each_window (plugin, - (ply_boot_splash_plugin_window_handler_t) - write_text_on_window, - (void *) "Password", - (void *) strlen ("Password")); - - for_each_window (plugin, - (ply_boot_splash_plugin_window_handler_t) - write_text_on_window, - (void *) ":", - (void *) strlen (":")); - for (i=0; i<bullets; i++) - for_each_window (plugin, - (ply_boot_splash_plugin_window_handler_t) - write_text_on_window, - (void *) "*", - (void *) strlen ("*")); + write_on_views (plugin, + "Password", + strlen ("Password")); + + write_on_views (plugin, ":", strlen (":")); + + for (i = 0; i < bullets; i++) + write_on_views (plugin, "*", strlen ("*")); } static void @@ -362,37 +331,18 @@ display_question (ply_boot_splash_plugin_t *plugin, const char *entry_text) { if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY) - { - for_each_window (plugin, - (ply_boot_splash_plugin_window_handler_t) - write_text_on_window, - (void *) "\r\n", (void *) strlen ("\r\n")); - } + write_on_views (plugin, "\r\n", strlen ("\r\n")); else - { - for_each_window (plugin, - (ply_boot_splash_plugin_window_handler_t) - write_text_on_window, - (void *) CLEAR_LINE_SEQUENCE, - (void *) strlen (CLEAR_LINE_SEQUENCE)); - } + write_on_views (plugin, + CLEAR_LINE_SEQUENCE, + strlen (CLEAR_LINE_SEQUENCE)); + plugin->state = PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY; if (prompt) - for_each_window (plugin, - (ply_boot_splash_plugin_window_handler_t) - write_text_on_window, - (void *) prompt, - (void *) strlen (prompt)); - for_each_window (plugin, - (ply_boot_splash_plugin_window_handler_t) - write_text_on_window, - (void *) ":", - (void *) strlen (":")); - for_each_window (plugin, - (ply_boot_splash_plugin_window_handler_t) - write_text_on_window, - (void *) entry_text, - (void *) strlen (entry_text)); + write_on_views (plugin, prompt, strlen (prompt)); + + write_on_views (plugin, ":", strlen (":")); + write_on_views (plugin, entry_text, strlen (entry_text)); } ply_boot_splash_plugin_interface_t * @@ -402,8 +352,8 @@ ply_boot_splash_plugin_get_interface (void) { .create_plugin = create_plugin, .destroy_plugin = destroy_plugin, - .add_window = add_window, - .remove_window = remove_window, + .add_text_display = add_text_display, + .remove_text_display = remove_text_display, .show_splash_screen = show_splash_screen, .update_status = update_status, .on_boot_output = on_boot_output, diff --git a/src/plugins/splash/fade-throbber/plugin.c b/src/plugins/splash/fade-throbber/plugin.c index 64403a4b..d89a562f 100644 --- a/src/plugins/splash/fade-throbber/plugin.c +++ b/src/plugins/splash/fade-throbber/plugin.c @@ -1,6 +1,6 @@ /* fade-throbber.c - boot splash plugin * - * Copyright (C) 2007, 2008 Red Hat, Inc. + * Copyright (C) 2007, 2008, 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 @@ -43,14 +43,15 @@ #include "ply-buffer.h" #include "ply-entry.h" #include "ply-event-loop.h" +#include "ply-label.h" #include "ply-list.h" #include "ply-logger.h" -#include "ply-frame-buffer.h" #include "ply-image.h" #include "ply-key-file.h" +#include "ply-pixel-buffer.h" +#include "ply-pixel-display.h" #include "ply-trigger.h" #include "ply-utils.h" -#include "ply-window.h" #include <linux/kd.h> @@ -58,6 +59,7 @@ #define FRAMES_PER_SECOND 30 #endif + typedef enum { PLY_BOOT_SPLASH_DISPLAY_NORMAL, PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY, @@ -70,20 +72,30 @@ typedef struct unsigned int y; double start_time; double speed; + double opacity; } star_t; +typedef struct +{ + ply_boot_splash_plugin_t *plugin; + ply_pixel_display_t *display; + ply_list_t *stars; + ply_entry_t *entry; + ply_label_t *label; + ply_rectangle_t lock_area; +} view_t; + struct _ply_boot_splash_plugin { ply_event_loop_t *loop; ply_boot_splash_mode_t mode; - ply_frame_buffer_t *frame_buffer; ply_image_t *logo_image; ply_image_t *star_image; ply_image_t *lock_image; - ply_list_t *stars; - ply_window_t *window; + char *image_dir; + ply_list_t *views; + double logo_opacity; - ply_entry_t *entry; ply_boot_splash_display_type_t state; double start_time; @@ -92,6 +104,65 @@ struct _ply_boot_splash_plugin uint32_t is_animating : 1; }; +static void +view_show_prompt (view_t *view, + const char *prompt) +{ + ply_boot_splash_plugin_t *plugin; + int x, y; + int entry_width, entry_height; + + assert (view != NULL); + + plugin = view->plugin; + + if (ply_entry_is_hidden (view->entry)) + { + unsigned long screen_width, screen_height; + + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); + + view->lock_area.width = ply_image_get_width (plugin->lock_image); + view->lock_area.height = ply_image_get_height (plugin->lock_image); + + entry_width = ply_entry_get_width (view->entry); + entry_height = ply_entry_get_height (view->entry); + + x = screen_width / 2.0 - (view->lock_area.width + entry_width) / 2.0 + view->lock_area.width; + y = screen_height / 2.0 - entry_height / 2.0; + + view->lock_area.x = screen_width / 2.0 - (view->lock_area.width + entry_width) / 2.0; + view->lock_area.y = screen_height / 2.0 - view->lock_area.height / 2.0; + + ply_entry_show (view->entry, plugin->loop, view->display, x, y); + } + + if (prompt != NULL) + { + int label_width, label_height; + + ply_label_set_text (view->label, prompt); + label_width = ply_label_get_width (view->label); + label_height = ply_label_get_height (view->label); + + x = view->lock_area.x; + y = view->lock_area.y + view->lock_area.height; + + ply_label_show (view->label, view->display, x, y); + } +} + +static void +view_hide_prompt (view_t *view) +{ + assert (view != NULL); + + ply_entry_hide (view->entry); + ply_label_hide (view->label); +} + + static ply_boot_splash_plugin_t * create_plugin (ply_key_file_t *key_file) { @@ -113,16 +184,15 @@ create_plugin (ply_key_file_t *key_file) plugin->lock_image = ply_image_new (image_path); free (image_path); - plugin->entry = ply_entry_new (image_dir); - free (image_dir); + plugin->image_dir = image_dir; plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL; - plugin->stars = ply_list_new (); + plugin->views = ply_list_new (); return plugin; } -star_t * +static star_t * star_new (int x, int y, double speed) @@ -145,13 +215,13 @@ star_free (star_t *star) } static void -free_stars (ply_boot_splash_plugin_t *plugin) +free_stars (view_t *view) { ply_list_node_t *node; - assert (plugin != NULL); + assert (view != NULL); - node = ply_list_get_first_node (plugin->stars); + node = ply_list_get_first_node (view->stars); while (node != NULL) { ply_list_node_t *next_node; @@ -159,29 +229,184 @@ free_stars (ply_boot_splash_plugin_t *plugin) star = (star_t *) ply_list_node_get_data (node); - next_node = ply_list_get_next_node (plugin->stars, node); + next_node = ply_list_get_next_node (view->stars, node); star_free (star); node = next_node; } - ply_list_free (plugin->stars); - plugin->stars = NULL; + ply_list_free (view->stars); + view->stars = NULL; } -static void add_handlers (ply_boot_splash_plugin_t *plugin); -static void remove_handlers (ply_boot_splash_plugin_t *plugin); - static void detach_from_event_loop (ply_boot_splash_plugin_t *plugin); +static view_t * +view_new (ply_boot_splash_plugin_t *plugin, + ply_pixel_display_t *display) +{ + view_t *view; + + view = calloc (1, sizeof (view_t)); + view->plugin = plugin; + view->display = display; + + view->entry = ply_entry_new (plugin->image_dir); + view->stars = ply_list_new (); + view->label = ply_label_new (); + + return view; +} + +static void +view_free (view_t *view) +{ + + ply_entry_free (view->entry); + free_stars (view); + + free (view); +} + +static bool +view_load (view_t *view) +{ + ply_trace ("loading entry"); + if (!ply_entry_load (view->entry)) + return false; + + return true; +} + +static bool +load_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + bool view_loaded; + + view_loaded = false; + node = ply_list_get_first_node (plugin->views); + + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + if (view_load (view)) + view_loaded = true; + + node = next_node; + } + + return view_loaded; +} + +static void +view_redraw (view_t *view) +{ + unsigned long screen_width, screen_height; + + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); + + ply_pixel_display_draw_area (view->display, 0, 0, + screen_width, screen_height); +} + +static void +redraw_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_redraw (view); + + node = next_node; + } +} + +static void +pause_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + ply_pixel_display_pause_updates (view->display); + + node = next_node; + } +} + +static void +unpause_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + ply_pixel_display_unpause_updates (view->display); + + node = next_node; + } +} + +static void +free_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_free (view); + ply_list_remove_node (plugin->views, node); + + node = next_node; + } + + ply_list_free (plugin->views); + plugin->views = NULL; +} + static void destroy_plugin (ply_boot_splash_plugin_t *plugin) { if (plugin == NULL) return; - remove_handlers (plugin); - if (plugin->loop != NULL) { ply_event_loop_stop_watching_for_exit (plugin->loop, (ply_event_loop_exit_handler_t) @@ -190,100 +415,95 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin) detach_from_event_loop (plugin); } - free_stars (plugin); + free_views (plugin); ply_image_free (plugin->logo_image); ply_image_free (plugin->star_image); ply_image_free (plugin->lock_image); - ply_entry_free (plugin->entry); free (plugin); } static void -draw_background (ply_boot_splash_plugin_t *plugin, - ply_frame_buffer_area_t *area) -{ - ply_frame_buffer_area_t screen_area; - - if (area == NULL) - { - ply_frame_buffer_get_size (plugin->frame_buffer, &screen_area); - area = &screen_area; - } - - ply_window_erase_area (plugin->window, area->x, area->y, - area->width, area->height); -} - -static void -animate_at_time (ply_boot_splash_plugin_t *plugin, - double time) +view_animate_at_time (view_t *view, + double time) { + ply_boot_splash_plugin_t *plugin; ply_list_node_t *node; - ply_frame_buffer_area_t logo_area, star_area; + double logo_opacity; uint32_t *logo_data, *star_data; - long width, height; - static double last_opacity = 0.0; - double opacity = 0.0; + long logo_x, logo_y; + long logo_width, logo_height; + unsigned long screen_width, screen_height; + unsigned long star_width, star_height; - ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_GRAPHICS); + plugin = view->plugin; - ply_frame_buffer_pause_updates (plugin->frame_buffer); - - width = ply_image_get_width (plugin->logo_image); - height = ply_image_get_height (plugin->logo_image); + logo_width = ply_image_get_width (plugin->logo_image); + logo_height = ply_image_get_height (plugin->logo_image); logo_data = ply_image_get_data (plugin->logo_image); - ply_frame_buffer_get_size (plugin->frame_buffer, &logo_area); - logo_area.x = (logo_area.width / 2) - (width / 2); - logo_area.y = (logo_area.height / 2) - (height / 2); - logo_area.width = width; - logo_area.height = height; + + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); + + logo_x = (screen_width / 2) - (logo_width / 2); + logo_y = (screen_height / 2) - (logo_height / 2); star_data = ply_image_get_data (plugin->star_image); - star_area.width = ply_image_get_width (plugin->star_image); - star_area.height = ply_image_get_height (plugin->star_image); + star_width = ply_image_get_width (plugin->star_image); + star_height = ply_image_get_height (plugin->star_image); - node = ply_list_get_first_node (plugin->stars); + node = ply_list_get_first_node (view->stars); while (node != NULL) { ply_list_node_t *next_node; star_t *star; star = (star_t *) ply_list_node_get_data (node); - next_node = ply_list_get_next_node (plugin->stars, node); - - star_area.x = star->x; - star_area.y = star->y; - - opacity = .5 * sin (((plugin->now - star->start_time) / star->speed) * (2 * M_PI)) + .5; - opacity = CLAMP (opacity, 0, 1.0); + next_node = ply_list_get_next_node (view->stars, node); - draw_background (plugin, &star_area); - ply_frame_buffer_fill_with_argb32_data_at_opacity (plugin->frame_buffer, - &star_area, 0, 0, - star_data, opacity); + star->opacity = .5 * sin (((plugin->now - star->start_time) / star->speed) * (2 * M_PI)) + .5; + star->opacity = CLAMP (star->opacity, 0, 1.0); + ply_pixel_display_draw_area (view->display, + star->x, star->y, + star_width, star_height); node = next_node; } - opacity = .5 * sin ((time / 5) * (2 * M_PI)) + .8; - opacity = CLAMP (opacity, 0, 1.0); + logo_opacity = .5 * sin ((time / 5) * (2 * M_PI)) + .8; + logo_opacity = CLAMP (logo_opacity, 0, 1.0); if (plugin->mode == PLY_BOOT_SPLASH_MODE_SHUTDOWN) - opacity = 1.0; + logo_opacity = 1.0; + + if (fabs (logo_opacity - plugin->logo_opacity) <= DBL_MIN) + return; + + plugin->logo_opacity = logo_opacity; + + ply_pixel_display_draw_area (view->display, + logo_x, logo_y, + logo_width, logo_height); +} - if (fabs (opacity - last_opacity) <= DBL_MIN) +static void +animate_at_time (ply_boot_splash_plugin_t *plugin, + double time) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) { - ply_frame_buffer_unpause_updates (plugin->frame_buffer); - return; - } + ply_list_node_t *next_node; + view_t *view; - last_opacity = opacity; + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - draw_background (plugin, &logo_area); - ply_frame_buffer_fill_with_argb32_data_at_opacity (plugin->frame_buffer, - &logo_area, 0, 0, - logo_data, opacity); - ply_frame_buffer_unpause_updates (plugin->frame_buffer); + view_animate_at_time (view, time); + + node = next_node; + } } static void @@ -291,7 +511,6 @@ on_timeout (ply_boot_splash_plugin_t *plugin) { double sleep_time; - ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_GRAPHICS); plugin->now = ply_get_timestamp (); /* The choice below is between @@ -326,15 +545,25 @@ on_timeout (ply_boot_splash_plugin_t *plugin) } static void -start_animation (ply_boot_splash_plugin_t *plugin) +view_start_animation (view_t *view) { - assert (plugin != NULL); + ply_boot_splash_plugin_t *plugin; + unsigned long screen_width, screen_height; + + assert (view != NULL); + + plugin = view->plugin; + assert (plugin->loop != NULL); - + if (plugin->is_animating) return; - draw_background (plugin, NULL); + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); + + ply_pixel_display_draw_area (view->display, 0, 0, + screen_width, screen_height); plugin->start_time = ply_get_timestamp (); animate_at_time (plugin, plugin->start_time); @@ -351,37 +580,40 @@ start_animation (ply_boot_splash_plugin_t *plugin) } static void -stop_animation (ply_boot_splash_plugin_t *plugin) +start_animation (ply_boot_splash_plugin_t *plugin) { - int i; - - assert (plugin != NULL); - assert (plugin->loop != NULL); + ply_list_node_t *node; - if (!plugin->is_animating) + if (plugin->is_animating) return; - plugin->is_animating = false; - - for (i = 0; i < 10; i++) + node = ply_list_get_first_node (plugin->views); + while (node != NULL) { - ply_frame_buffer_fill_with_hex_color_at_opacity (plugin->frame_buffer, - NULL, - PLYMOUTH_BACKGROUND_COLOR, - .1 + .1 * i); - } + ply_list_node_t *next_node; + view_t *view; - ply_frame_buffer_fill_with_hex_color (plugin->frame_buffer, NULL, - PLYMOUTH_BACKGROUND_COLOR); + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - for (i = 0; i < 20; i++) - { - ply_frame_buffer_fill_with_color (plugin->frame_buffer, NULL, - 0.0, 0.0, 0.0, .05 + .05 * i); + view_start_animation (view); + + node = next_node; } - ply_frame_buffer_fill_with_color (plugin->frame_buffer, NULL, - 0.0, 0.0, 0.0, 1.0); + plugin->is_animating = true; +} + +static void +stop_animation (ply_boot_splash_plugin_t *plugin) +{ + assert (plugin != NULL); + assert (plugin->loop != NULL); + + if (!plugin->is_animating) + return; + + plugin->is_animating = false; if (plugin->loop != NULL) { @@ -389,6 +621,7 @@ stop_animation (ply_boot_splash_plugin_t *plugin) (ply_event_loop_timeout_handler_t) on_timeout, plugin); } + redraw_views (plugin); } static void @@ -396,121 +629,188 @@ on_interrupt (ply_boot_splash_plugin_t *plugin) { ply_event_loop_exit (plugin->loop, 1); stop_animation (plugin); - ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_TEXT); } static void detach_from_event_loop (ply_boot_splash_plugin_t *plugin) { plugin->loop = NULL; - - ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_TEXT); } -void -on_keyboard_input (ply_boot_splash_plugin_t *plugin, - const char *keyboard_input, - size_t character_size) +static void +draw_background (view_t *view, + ply_pixel_buffer_t *pixel_buffer, + int x, + int y, + int width, + int height) { + ply_boot_splash_plugin_t *plugin; + ply_rectangle_t area; + + plugin = view->plugin; + + area.x = x; + area.y = y; + area.width = width; + area.height = height; + + ply_pixel_buffer_fill_with_gradient (pixel_buffer, &area, + PLYMOUTH_BACKGROUND_START_COLOR, + PLYMOUTH_BACKGROUND_END_COLOR); } -void -on_backspace (ply_boot_splash_plugin_t *plugin) +static void +draw_normal_view (view_t *view, + ply_pixel_buffer_t *pixel_buffer, + int x, + int y, + int width, + int height) { + ply_boot_splash_plugin_t *plugin; + ply_list_node_t *node; + ply_rectangle_t logo_area; + ply_rectangle_t star_area; + uint32_t *logo_data, *star_data; + unsigned long screen_width, screen_height; + + plugin = view->plugin; + + logo_area.width = ply_image_get_width (plugin->logo_image); + logo_area.height = ply_image_get_height (plugin->logo_image); + logo_data = ply_image_get_data (plugin->logo_image); + + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); + + logo_area.x = (screen_width / 2) - (logo_area.width / 2); + logo_area.y = (screen_height / 2) - (logo_area.height / 2); + + star_data = ply_image_get_data (plugin->star_image); + star_area.width = ply_image_get_width (plugin->star_image); + star_area.height = ply_image_get_height (plugin->star_image); + + node = ply_list_get_first_node (view->stars); + while (node != NULL) + { + ply_list_node_t *next_node; + star_t *star; + + star = (star_t *) ply_list_node_get_data (node); + next_node = ply_list_get_next_node (view->stars, node); + + star_area.x = star->x; + star_area.y = star->y; + ply_pixel_buffer_fill_with_argb32_data_at_opacity (pixel_buffer, + &star_area, 0, 0, + star_data, + star->opacity); + node = next_node; + } + + ply_pixel_buffer_fill_with_argb32_data_at_opacity (pixel_buffer, + &logo_area, 0, 0, + logo_data, + plugin->logo_opacity); } -void -on_enter (ply_boot_splash_plugin_t *plugin, - const char *text) +static void +draw_prompt_view (view_t *view, + ply_pixel_buffer_t *pixel_buffer, + int x, + int y, + int width, + int height) { + ply_boot_splash_plugin_t *plugin; + uint32_t *lock_data; + + plugin = view->plugin; + + ply_entry_draw_area (view->entry, + pixel_buffer, + x, y, width, height); + ply_label_draw_area (view->label, + pixel_buffer, + x, y, width, height); + + lock_data = ply_image_get_data (plugin->lock_image); + ply_pixel_buffer_fill_with_argb32_data (pixel_buffer, + &view->lock_area, 0, 0, + lock_data); } -void -on_draw (ply_boot_splash_plugin_t *plugin, +static void +on_draw (view_t *view, + ply_pixel_buffer_t *pixel_buffer, int x, int y, int width, int height) { - ply_frame_buffer_area_t area; + ply_boot_splash_plugin_t *plugin; + ply_rectangle_t area; + + plugin = view->plugin; area.x = x; area.y = y; area.width = width; area.height = height; - draw_background (plugin, &area); + draw_background (view, pixel_buffer, x, y, width, height); + + if (!plugin->is_animating) + return; if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL) - animate_at_time (plugin, plugin->now); + draw_normal_view (view, pixel_buffer, x, y, width, height); else - ply_entry_draw (plugin->entry); + draw_prompt_view (view, pixel_buffer, x, y, width, height); } -void -on_erase (ply_boot_splash_plugin_t *plugin, - int x, - int y, - int width, - int height) +static void +add_pixel_display (ply_boot_splash_plugin_t *plugin, + ply_pixel_display_t *display) { - ply_frame_buffer_area_t area; + view_t *view; - area.x = x; - area.y = y; - area.width = width; - area.height = height; + view = view_new (plugin, display); - ply_frame_buffer_fill_with_gradient (plugin->frame_buffer, &area, - PLYMOUTH_BACKGROUND_START_COLOR, - PLYMOUTH_BACKGROUND_END_COLOR); + ply_pixel_display_set_draw_handler (view->display, + (ply_pixel_display_draw_handler_t) + on_draw, view); + + ply_list_append_data (plugin->views, view); } static void -add_handlers (ply_boot_splash_plugin_t *plugin) +remove_pixel_display (ply_boot_splash_plugin_t *plugin, + ply_pixel_display_t *display) { - ply_window_add_keyboard_input_handler (plugin->window, - (ply_window_keyboard_input_handler_t) - on_keyboard_input, plugin); - ply_window_add_backspace_handler (plugin->window, - (ply_window_backspace_handler_t) - on_backspace, plugin); - ply_window_add_enter_handler (plugin->window, - (ply_window_enter_handler_t) - on_enter, plugin); - - ply_window_set_draw_handler (plugin->window, - (ply_window_draw_handler_t) - on_draw, plugin); + ply_list_node_t *node; - ply_window_set_erase_handler (plugin->window, - (ply_window_erase_handler_t) - on_erase, plugin); -} + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + view_t *view; + ply_list_node_t *next_node; -static void -remove_handlers (ply_boot_splash_plugin_t *plugin) -{ + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - ply_window_remove_keyboard_input_handler (plugin->window, (ply_window_keyboard_input_handler_t) on_keyboard_input); - ply_window_remove_backspace_handler (plugin->window, (ply_window_backspace_handler_t) on_backspace); - ply_window_remove_enter_handler (plugin->window, (ply_window_enter_handler_t) on_enter); - ply_window_set_draw_handler (plugin->window, NULL, NULL); - ply_window_set_erase_handler (plugin->window, NULL, NULL); -} + if (view->display == display) + { -static void -add_window (ply_boot_splash_plugin_t *plugin, - ply_window_t *window) -{ - plugin->window = window; -} + ply_pixel_display_set_draw_handler (view->display, NULL, NULL); + view_free (view); + ply_list_remove_node (plugin->views, node); + return; + } -static void -remove_window (ply_boot_splash_plugin_t *plugin, - ply_window_t *window) -{ - plugin->window = NULL; + node = next_node; + } } static bool @@ -522,8 +822,6 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, assert (plugin != NULL); assert (plugin->logo_image != NULL); - add_handlers (plugin); - plugin->loop = loop; plugin->mode = mode; @@ -539,16 +837,6 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, if (!ply_image_load (plugin->lock_image)) return false; - ply_trace ("loading entry"); - if (!ply_entry_load (plugin->entry)) - return false; - - ply_trace ("setting graphics mode"); - if (!ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_GRAPHICS)) - return false; - - plugin->frame_buffer = ply_window_get_frame_buffer (plugin->window); - ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t) detach_from_event_loop, plugin); @@ -557,8 +845,11 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, (ply_event_handler_t) on_interrupt, plugin); - ply_window_clear_screen (plugin->window); - ply_window_hide_text_cursor (plugin->window); + if (!load_views (plugin)) + { + ply_trace ("couldn't load views"); + return false; + } ply_trace ("starting boot animation"); start_animation (plugin); @@ -567,21 +858,26 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, } static void -add_star (ply_boot_splash_plugin_t *plugin) +view_add_star (view_t *view) { - ply_frame_buffer_area_t area, logo_area; + ply_boot_splash_plugin_t *plugin; + ply_rectangle_t logo_area; star_t *star; unsigned int x, y; unsigned int width, height; + unsigned long screen_width, screen_height; ply_list_node_t *node; - assert (plugin != NULL); + assert (view != NULL); + + plugin = view->plugin; - ply_frame_buffer_get_size (plugin->frame_buffer, &area); + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); width = ply_image_get_width (plugin->logo_image); height = ply_image_get_height (plugin->logo_image); - logo_area.x = (area.width / 2) - (width / 2); - logo_area.y = (area.height / 2) - (height / 2); + logo_area.x = (screen_width / 2) - (width / 2); + logo_area.y = (screen_height / 2) - (height / 2); logo_area.width = width; logo_area.height = height; @@ -591,8 +887,8 @@ add_star (ply_boot_splash_plugin_t *plugin) node = NULL; do { - x = rand () % area.width; - y = rand () % area.height; + x = rand () % screen_width; + y = rand () % screen_height; if ((x <= logo_area.x + logo_area.width) && (x >= logo_area.x) @@ -606,13 +902,13 @@ add_star (ply_boot_splash_plugin_t *plugin) && (y + height <= logo_area.y + logo_area.height)) continue; - node = ply_list_get_first_node (plugin->stars); + node = ply_list_get_first_node (view->stars); while (node != NULL) { ply_list_node_t *next_node; star = (star_t *) ply_list_node_get_data (node); - next_node = ply_list_get_next_node (plugin->stars, node); + next_node = ply_list_get_next_node (view->stars, node); if ((x <= star->x + width) && (x >= star->x) @@ -632,7 +928,27 @@ add_star (ply_boot_splash_plugin_t *plugin) } while (node != NULL); star = star_new (x, y, (double) ((rand () % 50) + 1)); - ply_list_append_data (plugin->stars, star); + ply_list_append_data (view->stars, star); +} + +static void +add_stars (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_add_star (view); + + node = next_node; + } } static void @@ -641,7 +957,7 @@ update_status (ply_boot_splash_plugin_t *plugin, { assert (plugin != NULL); - add_star (plugin); + add_stars (plugin); } static void @@ -650,8 +966,6 @@ hide_splash_screen (ply_boot_splash_plugin_t *plugin, { assert (plugin != NULL); - remove_handlers (plugin); - if (plugin->loop != NULL) { stop_animation (plugin); @@ -661,63 +975,87 @@ hide_splash_screen (ply_boot_splash_plugin_t *plugin, plugin); detach_from_event_loop (plugin); } +} + +static void +show_password_prompt (ply_boot_splash_plugin_t *plugin, + const char *text, + int number_of_bullets) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; - plugin->frame_buffer = NULL; + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_TEXT); + view_show_prompt (view, text); + ply_entry_set_bullet_count (view->entry, number_of_bullets); + + node = next_node; + } } static void -show_password_entry (ply_boot_splash_plugin_t *plugin) +show_prompt (ply_boot_splash_plugin_t *plugin, + const char *prompt, + const char *entry_text) { - ply_frame_buffer_area_t area; - ply_frame_buffer_area_t lock_area; - int x, y; - int entry_width, entry_height; - uint32_t *lock_data; - - assert (plugin != NULL); + ply_list_node_t *node; - if (ply_entry_is_hidden (plugin->entry)) + node = ply_list_get_first_node (plugin->views); + while (node != NULL) { - draw_background (plugin, NULL); + ply_list_node_t *next_node; + view_t *view; - ply_frame_buffer_get_size (plugin->frame_buffer, &area); + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - entry_width = ply_entry_get_width (plugin->entry); - entry_height = ply_entry_get_height (plugin->entry); + view_show_prompt (view, prompt); + ply_entry_set_text (view->entry, entry_text); - lock_area.width = ply_image_get_width (plugin->lock_image); - lock_area.height = ply_image_get_height (plugin->lock_image); - lock_area.x = area.width / 2.0 - (lock_area.width + entry_width) / 2.0; - lock_area.y = area.height / 2.0 - lock_area.height / 2.0; + node = next_node; + } +} - x = area.width / 2.0 - (lock_area.width + entry_width) / 2.0 + lock_area.width; - y = area.height / 2.0 - entry_height / 2.0; +static void +hide_prompt (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; - ply_entry_show (plugin->entry, plugin->loop, plugin->window, x, y); - - lock_data = ply_image_get_data (plugin->lock_image); - ply_frame_buffer_fill_with_argb32_data (plugin->frame_buffer, - &lock_area, 0, 0, - lock_data); - } - else + node = ply_list_get_first_node (plugin->views); + while (node != NULL) { - ply_entry_draw (plugin->entry); + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_hide_prompt (view); + + node = next_node; } } static void display_normal (ply_boot_splash_plugin_t *plugin) { + pause_views (plugin); if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY || plugin->state == PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY) { plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL; - ply_entry_hide (plugin->entry); - start_animation(plugin); + hide_prompt (plugin); + start_animation (plugin); + redraw_views (plugin); } + unpause_views (plugin); } static void @@ -725,13 +1063,14 @@ display_password (ply_boot_splash_plugin_t *plugin, const char *prompt, int bullets) { + pause_views (plugin); if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL) - { - stop_animation (plugin); - } + stop_animation (plugin); + plugin->state = PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY; - show_password_entry (plugin); - ply_entry_set_bullet_count (plugin->entry, bullets); + show_password_prompt (plugin, prompt, bullets); + redraw_views (plugin); + unpause_views (plugin); } static void @@ -739,16 +1078,17 @@ display_question (ply_boot_splash_plugin_t *plugin, const char *prompt, const char *entry_text) { + pause_views (plugin); if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL) - { - stop_animation (plugin); - } + stop_animation (plugin); plugin->state = PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY; - show_password_entry (plugin); - ply_entry_set_text (plugin->entry, entry_text); + show_prompt (plugin, prompt, entry_text); + redraw_views (plugin); + unpause_views (plugin); } + ply_boot_splash_plugin_interface_t * ply_boot_splash_plugin_get_interface (void) { @@ -756,8 +1096,8 @@ ply_boot_splash_plugin_get_interface (void) { .create_plugin = create_plugin, .destroy_plugin = destroy_plugin, - .add_window = add_window, - .remove_window = remove_window, + .add_pixel_display = add_pixel_display, + .remove_pixel_display = remove_pixel_display, .show_splash_screen = show_splash_screen, .update_status = update_status, .hide_splash_screen = hide_splash_screen, diff --git a/src/plugins/splash/script/plugin.c b/src/plugins/splash/script/plugin.c index 1a34efab..84915e74 100644 --- a/src/plugins/splash/script/plugin.c +++ b/src/plugins/splash/script/plugin.c @@ -49,11 +49,10 @@ #include "ply-label.h" #include "ply-list.h" #include "ply-logger.h" -#include "ply-frame-buffer.h" #include "ply-image.h" +#include "ply-pixel-display.h" #include "ply-trigger.h" #include "ply-utils.h" -#include "ply-window.h" #include "script.h" #include "script-parse.h" @@ -70,32 +69,120 @@ #define FRAMES_PER_SECOND 50 #endif +typedef struct +{ + ply_boot_splash_plugin_t *plugin; + ply_pixel_display_t *display; + + script_state_t *script_state; + script_lib_sprite_data_t *script_sprite_lib; + script_lib_image_data_t *script_image_lib; + script_lib_plymouth_data_t *script_plymouth_lib; + script_lib_math_data_t *script_math_lib; +} view_t; + struct _ply_boot_splash_plugin { ply_event_loop_t *loop; ply_boot_splash_mode_t mode; - ply_frame_buffer_t *frame_buffer; - ply_window_t *window; + ply_list_t *views; char *script_filename; char *image_dir; - script_state_t *script_state; script_op_t *script_main_op; - script_lib_sprite_data_t *script_sprite_lib; - script_lib_image_data_t *script_image_lib; - script_lib_plymouth_data_t *script_plymouth_lib; - script_lib_math_data_t *script_math_lib; uint32_t is_animating : 1; }; -static void add_handlers (ply_boot_splash_plugin_t *plugin); -static void remove_handlers (ply_boot_splash_plugin_t *plugin); static void detach_from_event_loop (ply_boot_splash_plugin_t *plugin); static void stop_animation (ply_boot_splash_plugin_t *plugin); ply_boot_splash_plugin_interface_t *ply_boot_splash_plugin_get_interface (void); +static view_t * +view_new (ply_boot_splash_plugin_t *plugin, + ply_pixel_display_t *display) +{ + view_t *view; + + view = calloc (1, sizeof (view_t)); + view->plugin = plugin; + view->display = display; + + return view; +} + +static void +view_free (view_t *view) +{ + free (view); +} + +static void +pause_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + ply_pixel_display_pause_updates (view->display); + + node = next_node; + } +} + +static void +unpause_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + ply_pixel_display_unpause_updates (view->display); + + node = next_node; + } +} + +static void +free_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_free (view); + ply_list_remove_node (plugin->views, node); + + node = next_node; + } + + ply_list_free (plugin->views); + plugin->views = NULL; +} + static ply_boot_splash_plugin_t * create_plugin (ply_key_file_t *key_file) { @@ -105,6 +192,7 @@ create_plugin (ply_key_file_t *key_file) plugin->script_filename = ply_key_file_get_value (key_file, "script", "ScriptFile"); + plugin->views = ply_list_new (); return plugin; } @@ -113,7 +201,6 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin) { if (plugin == NULL) return; - remove_handlers (plugin); if (plugin->loop != NULL) { @@ -124,27 +211,30 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin) plugin); detach_from_event_loop (plugin); } + + free_views (plugin); free (plugin->script_filename); free (plugin->image_dir); free (plugin); } static void -on_timeout (ply_boot_splash_plugin_t *plugin) +on_timeout (view_t *view) { + ply_boot_splash_plugin_t *plugin; double sleep_time; - ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_GRAPHICS); + plugin = view->plugin; - script_lib_plymouth_on_refresh (plugin->script_state, - plugin->script_plymouth_lib); - script_lib_sprite_refresh (plugin->script_sprite_lib); + script_lib_plymouth_on_refresh (view->script_state, + view->script_plymouth_lib); + script_lib_sprite_refresh (view->script_sprite_lib); sleep_time = 1.0 / FRAMES_PER_SECOND; ply_event_loop_watch_for_timeout (plugin->loop, sleep_time, (ply_event_loop_timeout_handler_t) - on_timeout, plugin); + on_timeout, view); } static void @@ -152,63 +242,128 @@ on_boot_progress (ply_boot_splash_plugin_t *plugin, double duration, double percent_done) { - script_lib_plymouth_on_boot_progress (plugin->script_state, - plugin->script_plymouth_lib, - duration, - percent_done); + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + script_lib_plymouth_on_boot_progress (view->script_state, + view->script_plymouth_lib, + duration, + percent_done); + node = next_node; + } +} + +static bool +view_start_animation (view_t *view) +{ + ply_boot_splash_plugin_t *plugin; + + assert (view != NULL); + + plugin = view->plugin; + + view->script_state = script_state_new (view); + view->script_image_lib = script_lib_image_setup (view->script_state, + plugin->image_dir); + view->script_sprite_lib = script_lib_sprite_setup (view->script_state, + view->display); + view->script_plymouth_lib = script_lib_plymouth_setup (view->script_state, + plugin->mode); + view->script_math_lib = script_lib_math_setup (view->script_state); + + ply_trace ("executing script file"); + script_return_t ret = script_execute (view->script_state, + plugin->script_main_op); + script_obj_unref (ret.object); + on_timeout (view); + + return true; } static bool start_animation (ply_boot_splash_plugin_t *plugin) { - ply_frame_buffer_area_t area; + ply_list_node_t *node; assert (plugin != NULL); assert (plugin->loop != NULL); if (plugin->is_animating) return true; - ply_frame_buffer_get_size (plugin->frame_buffer, &area); ply_trace ("parsing script file"); plugin->script_main_op = script_parse_file (plugin->script_filename); - plugin->script_state = script_state_new (plugin); - plugin->script_image_lib = script_lib_image_setup (plugin->script_state, - plugin->image_dir); - plugin->script_sprite_lib = script_lib_sprite_setup (plugin->script_state, - plugin->window); - plugin->script_plymouth_lib = script_lib_plymouth_setup (plugin->script_state, - plugin->mode); - plugin->script_math_lib = script_lib_math_setup (plugin->script_state); + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; - ply_trace ("executing script file"); - script_return_t ret = script_execute (plugin->script_state, - plugin->script_main_op); - script_obj_unref (ret.object); - on_timeout (plugin); + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_start_animation (view); + + node = next_node; + } plugin->is_animating = true; return true; } static void +view_stop_animation (view_t *view) +{ + ply_boot_splash_plugin_t *plugin; + + plugin = view->plugin; + + if (plugin->loop != NULL) + ply_event_loop_stop_watching_for_timeout (plugin->loop, + (ply_event_loop_timeout_handler_t) + on_timeout, view); + + script_state_destroy (view->script_state); + script_lib_sprite_destroy (view->script_sprite_lib); + script_lib_image_destroy (view->script_image_lib); + script_lib_plymouth_destroy (view->script_plymouth_lib); + script_lib_math_destroy (view->script_math_lib); +} + +static void stop_animation (ply_boot_splash_plugin_t *plugin) { + ply_list_node_t *node; + assert (plugin != NULL); assert (plugin->loop != NULL); if (!plugin->is_animating) return; plugin->is_animating = false; - if (plugin->loop != NULL) - ply_event_loop_stop_watching_for_timeout (plugin->loop, - (ply_event_loop_timeout_handler_t) - on_timeout, plugin); - script_state_destroy (plugin->script_state); - script_lib_sprite_destroy (plugin->script_sprite_lib); - script_lib_image_destroy (plugin->script_image_lib); - script_lib_plymouth_destroy (plugin->script_plymouth_lib); - script_lib_math_destroy (plugin->script_math_lib); + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_stop_animation (view); + + node = next_node; + } + script_parse_op_free (plugin->script_main_op); } @@ -217,7 +372,6 @@ on_interrupt (ply_boot_splash_plugin_t *plugin) { ply_event_loop_exit (plugin->loop, 1); stop_animation (plugin); - ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_TEXT); } static void @@ -232,80 +386,105 @@ on_keyboard_input (ply_boot_splash_plugin_t *plugin, size_t character_size) { char keyboard_string[character_size + 1]; + ply_list_node_t *node; memcpy (keyboard_string, keyboard_input, character_size); keyboard_string[character_size] = '\0'; - script_lib_plymouth_on_keyboard_input (plugin->script_state, - plugin->script_plymouth_lib, - keyboard_string); -} - -static void -on_backspace (ply_boot_splash_plugin_t *plugin) -{} + /* FIXME: Not sure what to do here. We don't want to feed + * the input once per monitor, I don't think, so we just call + * it on the first available monitor. + * + * I'm not even sure it's useful for scripts to be able to access + * this, but if it is we probably need to encode view awareness + * into the script api somehow. + */ + node = ply_list_get_first_node (plugin->views); + + if (node != NULL) + { + view_t *view; + view = (view_t *) ply_list_node_get_data (node); -static void -on_enter (ply_boot_splash_plugin_t *plugin, - const char *text) -{} + script_lib_plymouth_on_keyboard_input (view->script_state, + view->script_plymouth_lib, + keyboard_string); + } +} static void -on_draw (ply_boot_splash_plugin_t *plugin, +on_draw (view_t *view, + ply_pixel_buffer_t *pixel_buffer, int x, int y, int width, int height) -{} +{ + script_lib_sprite_draw_area (view->script_sprite_lib, + pixel_buffer, + x, y, width, height); +} static void -on_erase (ply_boot_splash_plugin_t *plugin, - int x, - int y, - int width, - int height) -{} +set_keyboard (ply_boot_splash_plugin_t *plugin, + ply_keyboard_t *keyboard) +{ -static void -add_handlers (ply_boot_splash_plugin_t *plugin) -{ - ply_window_add_keyboard_input_handler (plugin->window, - (ply_window_keyboard_input_handler_t) - on_keyboard_input, plugin); - ply_window_add_backspace_handler (plugin->window, - (ply_window_backspace_handler_t) - on_backspace, plugin); - ply_window_add_enter_handler (plugin->window, - (ply_window_enter_handler_t) - on_enter, plugin); - ply_window_set_draw_handler (plugin->window, - (ply_window_draw_handler_t) - on_draw, plugin); - ply_window_set_erase_handler (plugin->window, - (ply_window_erase_handler_t) - on_erase, plugin); + ply_keyboard_add_input_handler (keyboard, + (ply_keyboard_input_handler_t) + on_keyboard_input, plugin); } static void -remove_handlers (ply_boot_splash_plugin_t *plugin) +unset_keyboard (ply_boot_splash_plugin_t *plugin, + ply_keyboard_t *keyboard) { - ply_window_remove_keyboard_input_handler (plugin->window, (ply_window_keyboard_input_handler_t) on_keyboard_input); - ply_window_remove_backspace_handler (plugin->window, (ply_window_backspace_handler_t) on_backspace); - ply_window_remove_enter_handler (plugin->window, (ply_window_enter_handler_t) on_enter); + ply_keyboard_remove_input_handler (keyboard, + (ply_keyboard_input_handler_t) + on_keyboard_input); } static void -add_window (ply_boot_splash_plugin_t *plugin, - ply_window_t *window) +add_pixel_display (ply_boot_splash_plugin_t *plugin, + ply_pixel_display_t *display) { - plugin->window = window; + view_t *view; + + view = view_new (plugin, display); + + ply_pixel_display_set_draw_handler (view->display, + (ply_pixel_display_draw_handler_t) + on_draw, view); + + ply_list_append_data (plugin->views, view); } static void -remove_window (ply_boot_splash_plugin_t *plugin, - ply_window_t *window) +remove_pixel_display (ply_boot_splash_plugin_t *plugin, + ply_pixel_display_t *display) { - plugin->window = NULL; + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + view_t *view; + ply_list_node_t *next_node; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + if (view->display == display) + { + + ply_pixel_display_set_draw_handler (view->display, NULL, NULL); + view_free (view); + ply_list_remove_node (plugin->views, node); + return; + } + + node = next_node; + } } static bool @@ -316,13 +495,9 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, { assert (plugin != NULL); - add_handlers (plugin); - plugin->loop = loop; plugin->mode = mode; - plugin->frame_buffer = ply_window_get_frame_buffer (plugin->window); - ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t) detach_from_event_loop, plugin); @@ -332,12 +507,6 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, (ply_event_handler_t) on_interrupt, plugin); - ply_trace ("setting graphics mode"); - if (!ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_GRAPHICS)) - return false; - ply_window_clear_screen (plugin->window); - ply_window_hide_text_cursor (plugin->window); - ply_trace ("starting boot animation"); return start_animation (plugin); } @@ -347,9 +516,23 @@ update_status (ply_boot_splash_plugin_t *plugin, const char *status) { assert (plugin != NULL); - script_lib_plymouth_on_update_status (plugin->script_state, - plugin->script_plymouth_lib, - status); + + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + script_lib_plymouth_on_update_status (view->script_state, + view->script_plymouth_lib, + status); + node = next_node; + } } static void @@ -358,8 +541,6 @@ hide_splash_screen (ply_boot_splash_plugin_t *plugin, { assert (plugin != NULL); - remove_handlers (plugin); - if (plugin->loop != NULL) { stop_animation (plugin); @@ -370,16 +551,27 @@ hide_splash_screen (ply_boot_splash_plugin_t *plugin, plugin); detach_from_event_loop (plugin); } - plugin->frame_buffer = NULL; - - ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_TEXT); } static void on_root_mounted (ply_boot_splash_plugin_t *plugin) { - script_lib_plymouth_on_root_mounted (plugin->script_state, - plugin->script_plymouth_lib); + + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + script_lib_plymouth_on_root_mounted (view->script_state, + view->script_plymouth_lib); + node = next_node; + } } static void @@ -392,8 +584,25 @@ become_idle (ply_boot_splash_plugin_t *plugin, static void display_normal (ply_boot_splash_plugin_t *plugin) { - script_lib_plymouth_on_display_normal (plugin->script_state, - plugin->script_plymouth_lib); + ply_list_node_t *node; + + pause_views (plugin); + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + script_lib_plymouth_on_display_normal (view->script_state, + view->script_plymouth_lib); + + + node = next_node; + } + unpause_views (plugin); } static void @@ -401,10 +610,27 @@ display_password (ply_boot_splash_plugin_t *plugin, const char *prompt, int bullets) { - script_lib_plymouth_on_display_password (plugin->script_state, - plugin->script_plymouth_lib, - prompt, - bullets); + ply_list_node_t *node; + + pause_views (plugin); + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + script_lib_plymouth_on_display_password (view->script_state, + view->script_plymouth_lib, + prompt, + bullets); + + node = next_node; + } + unpause_views (plugin); + } static void @@ -412,19 +638,51 @@ display_question (ply_boot_splash_plugin_t *plugin, const char *prompt, const char *entry_text) { - script_lib_plymouth_on_display_question (plugin->script_state, - plugin->script_plymouth_lib, - prompt, - entry_text); + ply_list_node_t *node; + + pause_views (plugin); + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + script_lib_plymouth_on_display_question (view->script_state, + view->script_plymouth_lib, + prompt, + entry_text); + + node = next_node; + } + unpause_views (plugin); } static void display_message (ply_boot_splash_plugin_t *plugin, const char *message) { - script_lib_plymouth_on_message (plugin->script_state, - plugin->script_plymouth_lib, - message); + ply_list_node_t *node; + + pause_views (plugin); + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + script_lib_plymouth_on_message (view->script_state, + view->script_plymouth_lib, + message); + + node = next_node; + } + unpause_views (plugin); } ply_boot_splash_plugin_interface_t * @@ -434,8 +692,10 @@ ply_boot_splash_plugin_get_interface (void) { .create_plugin = create_plugin, .destroy_plugin = destroy_plugin, - .add_window = add_window, - .remove_window = remove_window, + .set_keyboard = set_keyboard, + .unset_keyboard = unset_keyboard, + .add_pixel_display = add_pixel_display, + .remove_pixel_display = remove_pixel_display, .show_splash_screen = show_splash_screen, .update_status = update_status, .on_boot_progress = on_boot_progress, diff --git a/src/plugins/splash/script/script-lib-sprite.c b/src/plugins/splash/script/script-lib-sprite.c index 3beded22..22ad7e21 100644 --- a/src/plugins/splash/script/script-lib-sprite.c +++ b/src/plugins/splash/script/script-lib-sprite.c @@ -21,10 +21,10 @@ */ #include "ply-image.h" #include "ply-utils.h" -#include "ply-window.h" -#include "ply-frame-buffer.h" #include "ply-logger.h" #include "ply-key-file.h" +#include "ply-pixel-buffer.h" +#include "ply-pixel-display.h" #include "script.h" #include "script-parse.h" #include "script-execute.h" @@ -141,22 +141,16 @@ static script_return_t sprite_window_get_width (script_state_t *state, void *user_data) { script_lib_sprite_data_t *data = user_data; - ply_frame_buffer_t *frame_buffer = ply_window_get_frame_buffer (data->window); - ply_frame_buffer_area_t area; - ply_frame_buffer_get_size (frame_buffer, &area); - return script_return_obj (script_obj_new_number (area.width)); + return script_return_obj (script_obj_new_number (ply_pixel_display_get_width (data->display))); } static script_return_t sprite_window_get_height (script_state_t *state, void *user_data) { script_lib_sprite_data_t *data = user_data; - ply_frame_buffer_t *frame_buffer = ply_window_get_frame_buffer (data->window); - ply_frame_buffer_area_t area; - ply_frame_buffer_get_size (frame_buffer, &area); - return script_return_obj (script_obj_new_number (area.height)); + return script_return_obj (script_obj_new_number (ply_pixel_display_get_height (data->display))); } static uint32_t extract_rgb_color (script_state_t *state) @@ -188,29 +182,26 @@ static script_return_t sprite_window_set_background_bottom_color (script_state_t return script_return_obj_null (); } -static void -draw_area (script_lib_sprite_data_t *data, - int x, - int y, - int width, - int height) +void script_lib_sprite_draw_area (script_lib_sprite_data_t *data, + ply_pixel_buffer_t *pixel_buffer, + int x, + int y, + int width, + int height) { - ply_frame_buffer_area_t clip_area; + ply_rectangle_t clip_area; clip_area.x = x; clip_area.y = y; clip_area.width = width; clip_area.height = height; - ply_frame_buffer_t *frame_buffer = ply_window_get_frame_buffer (data->window); - - ply_frame_buffer_pause_updates (frame_buffer); if (data->background_color_start == data->background_color_end) - ply_frame_buffer_fill_with_hex_color (frame_buffer, + ply_pixel_buffer_fill_with_hex_color (pixel_buffer, &clip_area, data->background_color_start); else - ply_frame_buffer_fill_with_gradient (frame_buffer, + ply_pixel_buffer_fill_with_gradient (pixel_buffer, &clip_area, data->background_color_start, data->background_color_end); @@ -220,7 +211,7 @@ draw_area (script_lib_sprite_data_t *data, node = ply_list_get_next_node (data->sprite_list, node)) { sprite_t *sprite = ply_list_node_get_data (node); - ply_frame_buffer_area_t sprite_area; + ply_rectangle_t sprite_area; if (!sprite->image) continue; if (sprite->remove_me) continue; if (sprite->opacity < 0.011) continue; @@ -234,24 +225,32 @@ draw_area (script_lib_sprite_data_t *data, if ((sprite_area.x + (int) sprite_area.width) <= x) continue; if ((sprite_area.y + (int) sprite_area.height) <= y) continue; - ply_frame_buffer_fill_with_argb32_data_at_opacity_with_clip (frame_buffer, + ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip (pixel_buffer, &sprite_area, &clip_area, 0, 0, ply_image_get_data (sprite->image), sprite->opacity); } - ply_frame_buffer_unpause_updates (frame_buffer); } -script_lib_sprite_data_t *script_lib_sprite_setup (script_state_t *state, - ply_window_t *window) +void draw_area (script_lib_sprite_data_t *data, + int x, + int y, + int width, + int height) +{ + ply_pixel_display_draw_area (data->display, x, y, width, height); +} + +script_lib_sprite_data_t *script_lib_sprite_setup (script_state_t *state, + ply_pixel_display_t *display) { script_lib_sprite_data_t *data = malloc (sizeof (script_lib_sprite_data_t)); data->class = script_obj_native_class_new (sprite_free, "sprite", data); data->sprite_list = ply_list_new (); - data->window = window; + data->display = display; script_obj_t *sprite_hash = script_obj_hash_get_element (state->global, "Sprite"); script_add_native_function (sprite_hash, @@ -348,14 +347,9 @@ void script_lib_sprite_refresh (script_lib_sprite_data_t *data) if (data->full_refresh) { - ply_frame_buffer_area_t screen_area; - ply_frame_buffer_t *frame_buffer = ply_window_get_frame_buffer (data->window); - ply_frame_buffer_get_size (frame_buffer, &screen_area); - draw_area (data, - screen_area.x, - screen_area.y, - screen_area.width, - screen_area.height); + draw_area (data, 0, 0, + ply_pixel_display_get_width (data->display), + ply_pixel_display_get_height (data->display)); data->full_refresh = false; return; } diff --git a/src/plugins/splash/script/script-lib-sprite.h b/src/plugins/splash/script/script-lib-sprite.h index 60a33908..4d1de5e0 100644 --- a/src/plugins/splash/script/script-lib-sprite.h +++ b/src/plugins/splash/script/script-lib-sprite.h @@ -23,10 +23,11 @@ #define SCRIPT_LIB_SPRITE_H #include "script.h" +#include "ply-pixel-display.h" typedef struct { - ply_window_t *window; + ply_pixel_display_t *display; ply_list_t *sprite_list; script_obj_native_class_t *class; script_op_t *script_main_op; @@ -53,9 +54,15 @@ typedef struct script_obj_t *image_obj; } sprite_t; -script_lib_sprite_data_t *script_lib_sprite_setup (script_state_t *state, - ply_window_t *window); +script_lib_sprite_data_t *script_lib_sprite_setup (script_state_t *state, + ply_pixel_display_t *display); void script_lib_sprite_refresh (script_lib_sprite_data_t *data); void script_lib_sprite_destroy (script_lib_sprite_data_t *data); +void script_lib_sprite_draw_area (script_lib_sprite_data_t *data, + ply_pixel_buffer_t *pixel_buffer, + int x, + int y, + int width, + int height); #endif /* SCRIPT_LIB_SPRITE_H */ diff --git a/src/plugins/splash/space-flares/plugin.c b/src/plugins/splash/space-flares/plugin.c index a2cb7349..3a87161e 100644 --- a/src/plugins/splash/space-flares/plugin.c +++ b/src/plugins/splash/space-flares/plugin.c @@ -49,13 +49,11 @@ #include "ply-label.h" #include "ply-list.h" #include "ply-logger.h" -#include "ply-frame-buffer.h" #include "ply-image.h" +#include "ply-pixel-buffer.h" +#include "ply-pixel-display.h" #include "ply-trigger.h" #include "ply-utils.h" -#include "ply-window.h" - -#include <linux/kd.h> #ifndef FRAMES_PER_SECOND #define FRAMES_PER_SECOND 40 @@ -159,12 +157,21 @@ typedef struct int frame_count; } star_bg_t; +typedef struct +{ + ply_boot_splash_plugin_t *plugin; + ply_pixel_display_t *display; + ply_entry_t *entry; + ply_label_t *label; + ply_list_t *sprites; + ply_rectangle_t box_area, lock_area, logo_area; + ply_image_t *scaled_background_image; +} view_t; + struct _ply_boot_splash_plugin { ply_event_loop_t *loop; ply_boot_splash_mode_t mode; - ply_frame_buffer_t *frame_buffer; - ply_frame_buffer_area_t box_area, lock_area, logo_area; ply_image_t *logo_image; ply_image_t *lock_image; ply_image_t *box_image; @@ -177,18 +184,13 @@ struct _ply_boot_splash_plugin ply_image_t *progress_barimage; #endif - ply_image_t *scaled_background_image; #ifdef SHOW_LOGO_HALO ply_image_t *highlight_logo_image; #endif - ply_window_t *window; - - ply_entry_t *entry; - ply_label_t *label; + char *image_dir; ply_boot_splash_display_type_t state; - - ply_list_t *sprites; + ply_list_t *views; double now; @@ -200,12 +202,298 @@ struct _ply_boot_splash_plugin uint32_t is_animating : 1; }; -static void add_handlers (ply_boot_splash_plugin_t *plugin); -static void remove_handlers (ply_boot_splash_plugin_t *plugin); static void detach_from_event_loop (ply_boot_splash_plugin_t *plugin); +static view_t * +view_new (ply_boot_splash_plugin_t *plugin, + ply_pixel_display_t *display) +{ + view_t *view; + + view = calloc (1, sizeof (view_t)); + view->plugin = plugin; + view->display = display; + + view->entry = ply_entry_new (plugin->image_dir); + view->label = ply_label_new (); + view->sprites = ply_list_new (); + + return view; +} + +static void view_free_sprites (view_t *view); + +static void +view_free (view_t *view) +{ + + ply_entry_free (view->entry); + ply_label_free (view->label); + view_free_sprites (view); + ply_list_free (view->sprites); + + ply_image_free (view->scaled_background_image); + + free (view); +} + +static void +free_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_free (view); + + node = next_node; + } + + ply_list_free (plugin->views); + plugin->views = NULL; +} + +static bool +view_load (view_t *view) +{ + ply_trace ("loading entry"); + if (!ply_entry_load (view->entry)) + return false; + + return true; +} + +static bool +load_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + bool view_loaded; + + view_loaded = false; + node = ply_list_get_first_node (plugin->views); + + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + if (view_load (view)) + view_loaded = true; + node = next_node; + } + + return view_loaded; +} + +static void +view_redraw (view_t *view) +{ + unsigned long screen_width, screen_height; + + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); + + ply_pixel_display_draw_area (view->display, 0, 0, + screen_width, screen_height); +} + +static void +redraw_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_redraw (view); + + node = next_node; + } +} + +static void +pause_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + ply_pixel_display_pause_updates (view->display); + + node = next_node; + } +} + +static void +unpause_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + ply_pixel_display_unpause_updates (view->display); + + node = next_node; + } +} + +static sprite_t* +add_sprite (view_t *view, + ply_image_t *image, + int type, + void *data) +{ + sprite_t *new_sprite = calloc (1, sizeof (sprite_t)); + + new_sprite->x = 0; + new_sprite->y = 0; + new_sprite->z = 0; + new_sprite->oldx = 0; + new_sprite->oldy = 0; + new_sprite->oldz = 0; + new_sprite->opacity = 1; + new_sprite->refresh_me = 0; + new_sprite->image = image; + new_sprite->type = type; + new_sprite->data = data; + + ply_list_append_data (view->sprites, new_sprite); + + return new_sprite; +} + +static void view_setup_scene (view_t *view); + +static void +view_start_animation (view_t *view) +{ + unsigned long screen_width, screen_height; + + assert (view != NULL); + + view_setup_scene (view); + + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); + + ply_pixel_display_draw_area (view->display, 0, 0, + screen_width, screen_height); +} + +static void +view_show_prompt (view_t *view, + const char *prompt) +{ + ply_boot_splash_plugin_t *plugin; + int x, y; + int entry_width, entry_height; + + assert (view != NULL); + + plugin = view->plugin; + + if (ply_entry_is_hidden (view->entry)) + { + unsigned long screen_width, screen_height; + + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); + + view->box_area.width = ply_image_get_width (plugin->box_image); + view->box_area.height = ply_image_get_height (plugin->box_image); + view->box_area.x = screen_width / 2.0 - view->box_area.width / 2.0; + view->box_area.y = screen_height / 2.0 - view->box_area.height / 2.0; + + view->lock_area.width = ply_image_get_width (plugin->lock_image); + view->lock_area.height = ply_image_get_height (plugin->lock_image); + + entry_width = ply_entry_get_width (view->entry); + entry_height = ply_entry_get_height (view->entry); + + x = screen_width / 2.0 - (view->lock_area.width + entry_width) / 2.0 + view->lock_area.width; + y = screen_height / 2.0 - entry_height / 2.0; + + view->lock_area.x = screen_width / 2.0 - (view->lock_area.width + entry_width) / 2.0; + view->lock_area.y = screen_height / 2.0 - view->lock_area.height / 2.0; + + ply_entry_show (view->entry, plugin->loop, view->display, x, y); + } + + if (prompt != NULL) + { + int label_width, label_height; + + ply_label_set_text (view->label, prompt); + label_width = ply_label_get_width (view->label); + label_height = ply_label_get_height (view->label); + + x = view->box_area.x + view->lock_area.width / 2; + y = view->box_area.y + view->box_area.height; + + ply_label_show (view->label, view->display, x, y); + } +} + +static void +view_hide_prompt (view_t *view) +{ + assert (view != NULL); + + ply_entry_hide (view->entry); + ply_label_hide (view->label); +} + +static void +hide_prompt (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_hide_prompt (view); + + node = next_node; + } +} static ply_boot_splash_plugin_t * create_plugin (ply_key_file_t *key_file) @@ -228,8 +516,6 @@ create_plugin (ply_key_file_t *key_file) plugin->box_image = ply_image_new (image_path); free (image_path); - plugin->scaled_background_image = NULL; - asprintf (&image_path, "%s/star.png", image_dir); plugin->star_image = ply_image_new (image_path); free (image_path); @@ -263,13 +549,14 @@ create_plugin (ply_key_file_t *key_file) plugin->progress_barimage = ply_image_new (image_path); free (image_path); #endif - plugin->entry = ply_entry_new (image_dir); - plugin->label = ply_label_new (); plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL; - plugin->sprites = ply_list_new(); plugin->progress = 0; plugin->progress_target = -1; - free(image_dir); + + plugin->image_dir = image_dir; + + plugin->views = ply_list_new (); + return plugin; } @@ -279,7 +566,7 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin) if (plugin == NULL) return; - remove_handlers (plugin); + free (plugin->image_dir); if (plugin->loop != NULL) { @@ -293,7 +580,6 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin) ply_image_free (plugin->lock_image); ply_image_free (plugin->box_image); - ply_image_free (plugin->scaled_background_image); ply_image_free (plugin->star_image); #ifdef SHOW_PLANETS ply_image_free (plugin->planet_image[0]); @@ -306,14 +592,11 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin) ply_image_free (plugin->progress_barimage); #endif - ply_entry_free (plugin->entry); - ply_label_free (plugin->label); - ply_list_free (plugin->sprites); + free_views (plugin); free (plugin); } - static void free_sprite (sprite_t* sprite) { @@ -359,44 +642,6 @@ free_sprite (sprite_t* sprite) return; } - - -static sprite_t* -add_sprite (ply_boot_splash_plugin_t *plugin, ply_image_t *image, int type, void* data) -{ - sprite_t* new_sprite = calloc (1, sizeof (sprite_t)); - new_sprite->x = 0; - new_sprite->y = 0; - new_sprite->z = 0; - new_sprite->oldx = 0; - new_sprite->oldy = 0; - new_sprite->oldz = 0; - new_sprite->opacity = 1; - new_sprite->refresh_me = 0; - new_sprite->image = image; - new_sprite->type = type; - new_sprite->data = data; - ply_list_append_data (plugin->sprites, new_sprite); - return new_sprite; -} - - -static void -draw_background (ply_boot_splash_plugin_t *plugin, - ply_frame_buffer_area_t *area) -{ - ply_frame_buffer_area_t screen_area; - - if (area == NULL) - { - ply_frame_buffer_get_size (plugin->frame_buffer, &screen_area); - area = &screen_area; - } - - ply_window_erase_area (plugin->window, area->x, area->y, - area->width, area->height); -} - int sprite_compare_z(void *data_a, void *data_b) { sprite_t *sprite_a = data_a; @@ -444,10 +689,12 @@ stretch_image(ply_image_t *scaled_image, ply_image_t *orig_image, int width) } static void -progress_update (ply_boot_splash_plugin_t *plugin, sprite_t* sprite, double time) +progress_update (view_t *view, sprite_t* sprite, double time) { progress_t *progress = sprite->data; - int newwidth = plugin->progress*(progress->end_width-progress->start_width)+progress->start_width; + ply_boot_splash_plugin_t *plugin = view->plugin; + int newwidth = plugin->progress * (progress->end_width - progress->start_width) + progress->start_width; + if (progress->current_width >newwidth) return; progress->current_width = newwidth; stretch_image(progress->image_altered, progress->image, newwidth); @@ -511,7 +758,7 @@ star_bg_gradient_colour (int x, int y, int width, int height, bool star, float t static void -star_bg_update (ply_boot_splash_plugin_t *plugin, sprite_t* sprite, double time) +star_bg_update (view_t *view, sprite_t* sprite, double time) { star_bg_t *star_bg = sprite->data; int width = ply_image_get_width (sprite->image); @@ -536,15 +783,14 @@ star_bg_update (ply_boot_splash_plugin_t *plugin, sprite_t* sprite, double time) } static void -satellite_move (ply_boot_splash_plugin_t *plugin, sprite_t* sprite, double time) +satellite_move (view_t *view, sprite_t* sprite, double time) { + ply_boot_splash_plugin_t *plugin = view->plugin; satellite_t *satellite = sprite->data; - ply_frame_buffer_area_t screen_area; - - ply_frame_buffer_get_size (plugin->frame_buffer, &screen_area); int width = ply_image_get_width (sprite->image); int height = ply_image_get_height (sprite->image); + unsigned long screen_width, screen_height; sprite->x=cos(satellite->theta+(1-plugin->progress)*2000/(satellite->distance))*satellite->distance; sprite->y=sin(satellite->theta+(1-plugin->progress)*2000/(satellite->distance))*satellite->distance; @@ -557,12 +803,14 @@ satellite_move (ply_boot_splash_plugin_t *plugin, sprite_t* sprite, double time) float angle_offset = atan2 (sprite->x, sprite->y); float cresent_angle = atan2 (sqrt(sprite->x*sprite->x+sprite->y*sprite->y), sprite->z); - + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); + sprite->x+=(float)satellite->end_x*plugin->progress+(float)satellite->start_x*(1-plugin->progress)-width/2; sprite->y+=(float)satellite->end_y*plugin->progress+(float)satellite->start_y*(1-plugin->progress)-height/2; - if (sprite->x > (signed int)screen_area.width) return; - if (sprite->y > (signed int)screen_area.height) return; + if (sprite->x > (signed int) screen_width) return; + if (sprite->y > (signed int) screen_height) return; if (satellite->type == SATELLITE_TYPE_PLANET) { @@ -660,9 +908,9 @@ satellite_move (ply_boot_splash_plugin_t *plugin, sprite_t* sprite, double time) static void -sprite_list_sort (ply_boot_splash_plugin_t *plugin) +sprite_list_sort (view_t *view) { - ply_list_sort (plugin->sprites, &sprite_compare_z); + ply_list_sort (view->sprites, &sprite_compare_z); } static void @@ -803,11 +1051,8 @@ flare_update (sprite_t* sprite, double time) return; } - - - static void -sprite_move (ply_boot_splash_plugin_t *plugin, sprite_t* sprite, double time) +sprite_move (view_t *view, sprite_t* sprite, double time) { sprite->oldx = sprite->x; sprite->oldy = sprite->y; @@ -816,48 +1061,42 @@ sprite_move (ply_boot_splash_plugin_t *plugin, sprite_t* sprite, double time) case SPRITE_TYPE_STATIC: break; case SPRITE_TYPE_PROGRESS: - progress_update (plugin, sprite, time); + progress_update (view, sprite, time); break; case SPRITE_TYPE_FLARE: flare_update (sprite, time); break; case SPRITE_TYPE_SATELLITE: - satellite_move (plugin, sprite, time); + satellite_move (view, sprite, time); break; case SPRITE_TYPE_STAR_BG: - star_bg_update (plugin, sprite, time); + star_bg_update (view, sprite, time); break; } } -void -on_draw (ply_boot_splash_plugin_t *plugin, - int x, - int y, - int width, - int height); - static void -animate_attime (ply_boot_splash_plugin_t *plugin, double time) +view_animate_attime (view_t *view, double time) { ply_list_node_t *node; - - ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_GRAPHICS); + ply_boot_splash_plugin_t *plugin; + + plugin = view->plugin; if (plugin->progress_target>=0) plugin->progress = (plugin->progress*10 + plugin->progress_target) /11; - node = ply_list_get_first_node (plugin->sprites); + node = ply_list_get_first_node (view->sprites); while(node) { sprite_t* sprite = ply_list_node_get_data (node); - sprite_move (plugin, sprite, time); - node = ply_list_get_next_node (plugin->sprites, node); + sprite_move (view, sprite, time); + node = ply_list_get_next_node (view->sprites, node); } - sprite_list_sort (plugin); + sprite_list_sort (view); - for(node = ply_list_get_first_node (plugin->sprites); node; node = ply_list_get_next_node (plugin->sprites, node)) + for(node = ply_list_get_first_node (view->sprites); node; node = ply_list_get_next_node (view->sprites, node)) { sprite_t* sprite = ply_list_node_get_data (node); if (sprite->x != sprite->oldx || @@ -875,7 +1114,8 @@ animate_attime (ply_boot_splash_plugin_t *plugin, double time) int i; for (i=0; i<star_bg->star_count; i++){ if (star_bg->star_refresh[i]){ - ply_window_draw_area (plugin->window, sprite->x+star_bg->star_x[i], sprite->y+star_bg->star_y[i], 1, 1); + ply_pixel_display_draw_area (view->display, + sprite->x+star_bg->star_x[i], sprite->y+star_bg->star_y[i], 1, 1); star_bg->star_refresh[i]=0; } } @@ -893,12 +1133,15 @@ animate_attime (ply_boot_splash_plugin_t *plugin, double time) y=MIN(sprite->y, sprite->oldy); width =(MAX(sprite->x, sprite->oldx)-x)+ply_image_get_width (sprite->image); height=(MAX(sprite->y, sprite->oldy)-y)+ply_image_get_height (sprite->image); - ply_window_draw_area (plugin->window, x, y, width, height); + ply_pixel_display_draw_area (view->display, + x, y, width, height); } else { - ply_window_draw_area (plugin->window, sprite->x, sprite->y, width, height); - ply_window_draw_area (plugin->window, sprite->oldx, sprite->oldy, width, height); + ply_pixel_display_draw_area (view->display, + sprite->x, sprite->y, width, height); + ply_pixel_display_draw_area (view->display, + sprite->oldx, sprite->oldy, width, height); } } } @@ -907,12 +1150,26 @@ animate_attime (ply_boot_splash_plugin_t *plugin, double time) static void on_timeout (ply_boot_splash_plugin_t *plugin) { + ply_list_node_t *node; double sleep_time; double now; now = ply_get_timestamp (); - animate_attime (plugin, now); + node = ply_list_get_first_node (plugin->views); + + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_animate_attime (view, now); + + node = next_node; + } plugin->now = now; sleep_time = 1.0 / FRAMES_PER_SECOND; @@ -933,28 +1190,27 @@ on_boot_progress (ply_boot_splash_plugin_t *plugin, plugin->progress_target = percent_done; } -void -setup_scene (ply_boot_splash_plugin_t *plugin); - static void start_animation (ply_boot_splash_plugin_t *plugin) { - - ply_frame_buffer_area_t area; - assert (plugin != NULL); - assert (plugin->loop != NULL); + ply_list_node_t *node; if (plugin->is_animating) return; - ply_frame_buffer_get_size (plugin->frame_buffer, &area); + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; - plugin->now = ply_get_timestamp (); - setup_scene (plugin); - ply_window_draw_area (plugin->window, area.x, area.y, area.width, area.height); + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - if (plugin->mode == PLY_BOOT_SPLASH_MODE_SHUTDOWN) - return; + view_start_animation (view); + + node = next_node; + } on_timeout (plugin); @@ -962,6 +1218,21 @@ start_animation (ply_boot_splash_plugin_t *plugin) } static void +view_free_sprites (view_t *view) +{ + ply_list_node_t *node; + + for (node = ply_list_get_first_node (view->sprites); + node != NULL; + node = ply_list_get_next_node (view->sprites, node)) + { + sprite_t* sprite = ply_list_node_get_data (node); + free_sprite (sprite); + } + ply_list_remove_all_nodes (view->sprites); +} + +static void stop_animation (ply_boot_splash_plugin_t *plugin) { ply_list_node_t *node; @@ -985,12 +1256,11 @@ stop_animation (ply_boot_splash_plugin_t *plugin) ply_image_free(plugin->highlight_logo_image); #endif - for(node = ply_list_get_first_node (plugin->sprites); node; node = ply_list_get_next_node (plugin->sprites, node)) + for(node = ply_list_get_first_node (plugin->views); node; node = ply_list_get_next_node (plugin->views, node)) { - sprite_t* sprite = ply_list_node_get_data (node); - free_sprite (sprite); + view_t *view = ply_list_node_get_data (node); + view_free_sprites (view); } - ply_list_remove_all_nodes (plugin->sprites); } static void @@ -998,7 +1268,6 @@ on_interrupt (ply_boot_splash_plugin_t *plugin) { ply_event_loop_exit (plugin->loop, 1); stop_animation (plugin); - ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_TEXT); } static void @@ -1007,33 +1276,23 @@ detach_from_event_loop (ply_boot_splash_plugin_t *plugin) plugin->loop = NULL; } +static void +draw_background (view_t *view, + ply_pixel_buffer_t *pixel_buffer, + int x, + int y, + int width, + int height); void -on_keyboard_input (ply_boot_splash_plugin_t *plugin, - const char *keyboard_input, - size_t character_size) -{ -} - -void -on_backspace (ply_boot_splash_plugin_t *plugin) -{ -} - -void -on_enter (ply_boot_splash_plugin_t *plugin, - const char *text) -{ -} - - -void -on_draw (ply_boot_splash_plugin_t *plugin, +on_draw (view_t *view, + ply_pixel_buffer_t *pixel_buffer, int x, int y, int width, int height) { - ply_frame_buffer_area_t clip_area; + ply_boot_splash_plugin_t *plugin; + ply_rectangle_t clip_area; clip_area.x = x; clip_area.y = y; clip_area.width = width; @@ -1043,25 +1302,40 @@ on_draw (ply_boot_splash_plugin_t *plugin, float pixel_r=0; float pixel_g=0; float pixel_b=0; + + plugin = view->plugin; + if (width==1 && height==1) single_pixel = true; - else - ply_frame_buffer_pause_updates (plugin->frame_buffer); if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY || plugin->state == PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY ) { - draw_background (plugin, &clip_area); - ply_entry_draw (plugin->entry); - ply_label_draw (plugin->label); + uint32_t *box_data, *lock_data; + + draw_background (view, pixel_buffer, x, y, width, height); + + box_data = ply_image_get_data (plugin->box_image); + ply_pixel_buffer_fill_with_argb32_data (pixel_buffer, + &view->box_area, 0, 0, + box_data); + ply_entry_draw_area (view->entry, pixel_buffer, x, y, width, height); + ply_label_draw_area (view->label, pixel_buffer, x, y, width, height); + lock_data = ply_image_get_data (plugin->lock_image); + ply_pixel_buffer_fill_with_argb32_data (pixel_buffer, + &view->lock_area, 0, 0, + lock_data); } else { ply_list_node_t *node; - for(node = ply_list_get_first_node (plugin->sprites); node; node = ply_list_get_next_node (plugin->sprites, node)) + + draw_background (view, pixel_buffer, x, y, width, height); + + for(node = ply_list_get_first_node (view->sprites); node; node = ply_list_get_next_node (view->sprites, node)) { sprite_t* sprite = ply_list_node_get_data (node); - ply_frame_buffer_area_t sprite_area; + ply_rectangle_t sprite_area; sprite_area.x = sprite->x; @@ -1090,29 +1364,30 @@ on_draw (ply_boot_splash_plugin_t *plugin, } else { - ply_frame_buffer_fill_with_argb32_data_at_opacity_with_clip (plugin->frame_buffer, - &sprite_area, &clip_area, 0, 0, - ply_image_get_data (sprite->image), sprite->opacity); + ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip (pixel_buffer, + &sprite_area, &clip_area, 0, 0, + ply_image_get_data (sprite->image), sprite->opacity); } } } if (single_pixel){ - ply_frame_buffer_fill_with_color (plugin->frame_buffer, &clip_area, pixel_r, pixel_g, pixel_b, 1.0); - } - else { - ply_frame_buffer_unpause_updates (plugin->frame_buffer); + ply_pixel_buffer_fill_with_color (pixel_buffer, &clip_area, pixel_r, pixel_g, pixel_b, 1.0); } } -void -on_erase (ply_boot_splash_plugin_t *plugin, - int x, - int y, - int width, - int height) +static void +draw_background (view_t *view, + ply_pixel_buffer_t *pixel_buffer, + int x, + int y, + int width, + int height) { - ply_frame_buffer_area_t area; - ply_frame_buffer_area_t image_area; + ply_boot_splash_plugin_t *plugin; + ply_rectangle_t area; + ply_rectangle_t image_area; + + plugin = view->plugin; area.x = x; area.y = y; @@ -1121,12 +1396,12 @@ on_erase (ply_boot_splash_plugin_t *plugin, image_area.x = 0; image_area.y = 0; - image_area.width = ply_image_get_width(plugin->scaled_background_image); - image_area.height = ply_image_get_height(plugin->scaled_background_image); + image_area.width = ply_image_get_width (view->scaled_background_image); + image_area.height = ply_image_get_height (view->scaled_background_image); - ply_frame_buffer_fill_with_argb32_data_with_clip (plugin->frame_buffer, - &image_area, &area, 0, 0, - ply_image_get_data (plugin->scaled_background_image)); + ply_pixel_buffer_fill_with_argb32_data_with_clip (pixel_buffer, + &image_area, &area, 0, 0, + ply_image_get_data (view->scaled_background_image)); image_area.x = image_area.width-ply_image_get_width(plugin->star_image); image_area.y = image_area.height-ply_image_get_height(plugin->star_image); @@ -1134,7 +1409,7 @@ on_erase (ply_boot_splash_plugin_t *plugin, image_area.height = ply_image_get_height(plugin->star_image); - ply_frame_buffer_fill_with_argb32_data_with_clip (plugin->frame_buffer, + ply_pixel_buffer_fill_with_argb32_data_with_clip (pixel_buffer, &image_area, &area, 0, 0, ply_image_get_data (plugin->star_image)); @@ -1144,58 +1419,55 @@ on_erase (ply_boot_splash_plugin_t *plugin, image_area.height = ply_image_get_height(plugin->logo_image); - ply_frame_buffer_fill_with_argb32_data_with_clip (plugin->frame_buffer, + ply_pixel_buffer_fill_with_argb32_data_with_clip (pixel_buffer, &image_area, &area, 0, 0, ply_image_get_data (plugin->logo_image)); } static void -add_handlers (ply_boot_splash_plugin_t *plugin) +add_pixel_display (ply_boot_splash_plugin_t *plugin, + ply_pixel_display_t *display) { - ply_window_add_keyboard_input_handler (plugin->window, - (ply_window_keyboard_input_handler_t) - on_keyboard_input, plugin); - ply_window_add_backspace_handler (plugin->window, - (ply_window_backspace_handler_t) - on_backspace, plugin); - ply_window_add_enter_handler (plugin->window, - (ply_window_enter_handler_t) - on_enter, plugin); - - ply_window_set_draw_handler (plugin->window, - (ply_window_draw_handler_t) - on_draw, plugin); - - ply_window_set_erase_handler (plugin->window, - (ply_window_erase_handler_t) - on_erase, plugin); -} + view_t *view; -static void -remove_handlers (ply_boot_splash_plugin_t *plugin) -{ + view = view_new (plugin, display); - ply_window_remove_keyboard_input_handler (plugin->window, (ply_window_keyboard_input_handler_t) on_keyboard_input); - ply_window_remove_backspace_handler (plugin->window, (ply_window_backspace_handler_t) on_backspace); - ply_window_remove_enter_handler (plugin->window, (ply_window_enter_handler_t) on_enter); - ply_window_set_draw_handler (plugin->window, NULL, NULL); - ply_window_set_erase_handler (plugin->window, NULL, NULL); -} + ply_pixel_display_set_draw_handler (view->display, + (ply_pixel_display_draw_handler_t) + on_draw, view); -static void -add_window (ply_boot_splash_plugin_t *plugin, - ply_window_t *window) -{ - plugin->window = window; + ply_list_append_data (plugin->views, view); } static void -remove_window (ply_boot_splash_plugin_t *plugin, - ply_window_t *window) +remove_pixel_display (ply_boot_splash_plugin_t *plugin, + ply_pixel_display_t *display) { - plugin->window = NULL; + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + view_t *view; + ply_list_node_t *next_node; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + if (view->display == display) + { + + ply_pixel_display_set_draw_handler (view->display, NULL, NULL); + view_free (view); + ply_list_remove_node (plugin->views, node); + return; + } + + node = next_node; + } } + void highlight_image (ply_image_t *highlighted_image, ply_image_t *orig_image, int distance) { int x, y; @@ -1232,93 +1504,97 @@ void highlight_image (ply_image_t *highlighted_image, ply_image_t *orig_image, i } -void -setup_scene (ply_boot_splash_plugin_t *plugin) + +static void +view_setup_scene (view_t *view) { - ply_frame_buffer_area_t screen_area; + ply_boot_splash_plugin_t *plugin; sprite_t *sprite; int i; int x, y; int width = 360; int height = 460; + unsigned long screen_width, screen_height; + + plugin = view->plugin; + + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); - ply_frame_buffer_get_size (plugin->frame_buffer, &screen_area); - { star_bg_t* star_bg; - if (plugin->scaled_background_image) - ply_image_free(plugin->scaled_background_image); - - plugin->scaled_background_image = ply_image_resize (plugin->logo_image, screen_area.width, screen_area.height); + if (view->scaled_background_image) + ply_image_free (view->scaled_background_image); + view->scaled_background_image = ply_image_resize (plugin->logo_image, screen_width, screen_height); star_bg = malloc(sizeof(star_bg_t)); - star_bg->star_count = (screen_area.width * screen_area.height)/400; + star_bg->star_count = (screen_width * screen_height)/400; star_bg->star_x = malloc(sizeof(int)*star_bg->star_count); star_bg->star_y = malloc(sizeof(int)*star_bg->star_count); star_bg->star_refresh = malloc(sizeof(int)*star_bg->star_count); star_bg->frame_count=0; - sprite = add_sprite (plugin, plugin->scaled_background_image, SPRITE_TYPE_STAR_BG, star_bg); + sprite = add_sprite (view, view->scaled_background_image, SPRITE_TYPE_STAR_BG, star_bg); sprite->z = -10000; - uint32_t* image_data = ply_image_get_data (plugin->scaled_background_image); - for (y=0; y< (int) screen_area.height; y++) for (x=0; x< (int) screen_area.width; x++){ - image_data[x + y * screen_area.width] = star_bg_gradient_colour(x, y, screen_area.width, screen_area.height, false, 0); + uint32_t* image_data = ply_image_get_data (view->scaled_background_image); + for (y=0; y< (int) screen_height; y++) for (x=0; x< (int) screen_width; x++){ + image_data[x + y * screen_width] = star_bg_gradient_colour(x, y, screen_width, screen_height, false, 0); } for (i=0; i<star_bg->star_count; i++){ do { - x = rand()%screen_area.width; - y = rand()%screen_area.height; + x = rand()%screen_width; + y = rand()%screen_height; } - while (image_data[x + y * screen_area.width] == 0xFFFFFFFF); + while (image_data[x + y * screen_width] == 0xFFFFFFFF); star_bg->star_refresh[i] = 0; star_bg->star_x[i] = x; star_bg->star_y[i] = y; - image_data[x + y * screen_area.width] = 0xFFFFFFFF; + image_data[x + y * screen_width] = 0xFFFFFFFF; } - for (i=0; i<(int) (screen_area.width * screen_area.height)/400; i++){ - x = rand()%screen_area.width; - y = rand()%screen_area.height; - image_data[x + y * screen_area.width] = star_bg_gradient_colour(x, y, screen_area.width, screen_area.height, true, ((float)x*y*13/10000)); + for (i=0; i<(int) (screen_width * screen_height)/400; i++){ + x = rand()%screen_width; + y = rand()%screen_height; + image_data[x + y * screen_width] = star_bg_gradient_colour(x, y, screen_width, screen_height, true, ((float)x*y*13/10000)); } for (i=0; i<star_bg->star_count; i++){ - image_data[star_bg->star_x[i] + star_bg->star_y[i] * screen_area.width] = - star_bg_gradient_colour(star_bg->star_x[i], star_bg->star_y[i], screen_area.width, screen_area.height, true, 0.0); + image_data[star_bg->star_x[i] + star_bg->star_y[i] * screen_width] = + star_bg_gradient_colour(star_bg->star_x[i], star_bg->star_y[i], screen_width, screen_height, true, 0.0); } } - sprite = add_sprite (plugin, plugin->logo_image, SPRITE_TYPE_STATIC, NULL); - sprite->x=screen_area.width/2-ply_image_get_width(plugin->logo_image)/2; - sprite->y=screen_area.height/2-ply_image_get_height(plugin->logo_image)/2; + sprite = add_sprite (view, plugin->logo_image, SPRITE_TYPE_STATIC, NULL); + sprite->x=screen_width/2-ply_image_get_width(plugin->logo_image)/2; + sprite->y=screen_height/2-ply_image_get_height(plugin->logo_image)/2; sprite->z=1000; #ifdef SHOW_LOGO_HALO plugin->highlight_logo_image = ply_image_resize (plugin->logo_image, ply_image_get_width(plugin->logo_image)+HALO_BLUR*2, ply_image_get_height(plugin->logo_image)+HALO_BLUR*2); highlight_image (plugin->highlight_logo_image, plugin->logo_image, HALO_BLUR); - sprite = add_sprite (plugin, plugin->highlight_logo_image, SPRITE_TYPE_STATIC, NULL); + sprite = add_sprite (view, plugin->highlight_logo_image, SPRITE_TYPE_STATIC, NULL); sprite->x=10-HALO_BLUR; sprite->y=10-HALO_BLUR; sprite->z=-910; #endif - sprite = add_sprite (plugin, plugin->star_image, SPRITE_TYPE_STATIC, NULL); - sprite->x=screen_area.width-ply_image_get_width(plugin->star_image); - sprite->y=screen_area.height-ply_image_get_height(plugin->star_image); + sprite = add_sprite (view, plugin->star_image, SPRITE_TYPE_STATIC, NULL); + sprite->x=screen_width-ply_image_get_width(plugin->star_image); + sprite->y=screen_height-ply_image_get_height(plugin->star_image); sprite->z=0; #ifdef SHOW_PLANETS for (i=0; i<5; i++) { satellite_t* satellite = malloc(sizeof(satellite_t)); satellite->type=SATELLITE_TYPE_PLANET; - satellite->end_x=satellite->start_x=720-800+screen_area.width; - satellite->end_y=satellite->start_y=300-480+screen_area.height; + satellite->end_x=satellite->start_x=720-800+screen_width; + satellite->end_y=satellite->start_y=300-480+screen_height; satellite->distance=i*100+280; satellite->theta=M_PI*0.8; satellite->image=plugin->planet_image[i]; satellite->image_altered=ply_image_resize (satellite->image, ply_image_get_width(satellite->image), ply_image_get_height(satellite->image)); - sprite = add_sprite (plugin, satellite->image_altered, SPRITE_TYPE_SATELLITE, satellite); + sprite = add_sprite (view, satellite->image_altered, SPRITE_TYPE_SATELLITE, satellite); satellite_move (plugin, sprite, 0); } @@ -1328,8 +1604,8 @@ setup_scene (ply_boot_splash_plugin_t *plugin) { satellite_t* satellite = malloc(sizeof(satellite_t)); satellite->type=SATELLITE_TYPE_COMET; - satellite->end_x=satellite->start_x=720-800+screen_area.width; - satellite->end_y=satellite->start_y=300-480+screen_area.height; + satellite->end_x=satellite->start_x=720-800+screen_width; + satellite->end_y=satellite->start_y=300-480+screen_height; satellite->distance=550+i*50; satellite->theta=M_PI*0.8; #define COMET_SIZE 64 @@ -1344,7 +1620,7 @@ setup_scene (ply_boot_splash_plugin_t *plugin) image_altered_data[x + y * COMET_SIZE] = 0x0; } - sprite = add_sprite (plugin, satellite->image_altered, SPRITE_TYPE_SATELLITE, satellite); + sprite = add_sprite (view, satellite->image_altered, SPRITE_TYPE_SATELLITE, satellite); for (x=0; x<COMET_SIZE; x++) satellite_move (plugin, sprite, 0); } #endif @@ -1354,18 +1630,18 @@ setup_scene (ply_boot_splash_plugin_t *plugin) progress->image = plugin->progress_barimage; - x = screen_area.width/2-ply_image_get_width(plugin->logo_image)/2;; - y = screen_area.height/2+ply_image_get_height(plugin->logo_image)/2+20; + x = screen_width/2-ply_image_get_width(plugin->logo_image)/2;; + y = screen_height/2+ply_image_get_height(plugin->logo_image)/2+20; progress->image_altered = ply_image_resize (plugin->progress_barimage, ply_image_get_width(plugin->logo_image), ply_image_get_height(plugin->progress_barimage)); progress->start_width = 1; progress->end_width = ply_image_get_width(plugin->logo_image); progress->current_width = 0; - sprite = add_sprite (plugin, progress->image_altered, SPRITE_TYPE_PROGRESS, progress); + sprite = add_sprite (view, progress->image_altered, SPRITE_TYPE_PROGRESS, progress); sprite->x=x; sprite->y=y; sprite->z=10011; - progress_update (plugin, sprite, 0); + progress_update (view, sprite, 0); @@ -1376,12 +1652,12 @@ setup_scene (ply_boot_splash_plugin_t *plugin) flare->image_a = ply_image_resize (plugin->star_image, width, height); flare->image_b = ply_image_resize (plugin->star_image, width, height); - sprite = add_sprite (plugin, flare->image_a, SPRITE_TYPE_FLARE, flare); - sprite->x=screen_area.width-width; - sprite->y=screen_area.height-height; + sprite = add_sprite (view, flare->image_a, SPRITE_TYPE_FLARE, flare); + sprite->x=screen_width-width; + sprite->y=screen_height-height; sprite->z=1; - sprite_list_sort (plugin); + sprite_list_sort (view); uint32_t * old_image_data = ply_image_get_data (flare->image_a); uint32_t * new_image_data = ply_image_get_data (flare->image_b); @@ -1413,8 +1689,6 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, assert (plugin != NULL); assert (plugin->logo_image != NULL); - add_handlers (plugin); - plugin->loop = loop; plugin->mode = mode; @@ -1452,15 +1726,11 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, if (!ply_image_load (plugin->box_image)) return false; - ply_trace ("loading entry"); - if (!ply_entry_load (plugin->entry)) - return false; - - ply_trace ("setting graphics mode"); - if (!ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_GRAPHICS)) - return false; - - plugin->frame_buffer = ply_window_get_frame_buffer (plugin->window); + if (!load_views (plugin)) + { + ply_trace ("couldn't load views"); + return false; + } ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t) detach_from_event_loop, @@ -1471,9 +1741,6 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, (ply_event_handler_t) on_interrupt, plugin); - ply_window_clear_screen (plugin->window); - ply_window_hide_text_cursor (plugin->window); - ply_trace ("starting boot animation"); start_animation (plugin); @@ -1496,8 +1763,6 @@ hide_splash_screen (ply_boot_splash_plugin_t *plugin, { assert (plugin != NULL); - remove_handlers (plugin); - if (plugin->loop != NULL) { stop_animation (plugin); @@ -1508,76 +1773,53 @@ hide_splash_screen (ply_boot_splash_plugin_t *plugin, detach_from_event_loop (plugin); } - plugin->frame_buffer = NULL; plugin->is_visible = false; - - ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_TEXT); } static void show_password_prompt (ply_boot_splash_plugin_t *plugin, - const char *prompt) + const char *text, + int number_of_bullets) { - ply_frame_buffer_area_t area; - int x, y; - int entry_width, entry_height; - - uint32_t *box_data, *lock_data; - - assert (plugin != NULL); + ply_list_node_t *node; - if (ply_entry_is_hidden (plugin->entry)) + node = ply_list_get_first_node (plugin->views); + while (node != NULL) { - draw_background (plugin, NULL); + ply_list_node_t *next_node; + view_t *view; - ply_frame_buffer_get_size (plugin->frame_buffer, &area); - plugin->box_area.width = ply_image_get_width (plugin->box_image); - plugin->box_area.height = ply_image_get_height (plugin->box_image); - plugin->box_area.x = area.width / 2.0 - plugin->box_area.width / 2.0; - plugin->box_area.y = area.height / 2.0 - plugin->box_area.height / 2.0; + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - plugin->lock_area.width = ply_image_get_width (plugin->lock_image); - plugin->lock_area.height = ply_image_get_height (plugin->lock_image); + view_show_prompt (view, text); + ply_entry_set_bullet_count (view->entry, number_of_bullets); - entry_width = ply_entry_get_width (plugin->entry); - entry_height = ply_entry_get_height (plugin->entry); - - x = area.width / 2.0 - (plugin->lock_area.width + entry_width) / 2.0 + plugin->lock_area.width; - y = area.height / 2.0 - entry_height / 2.0; - - plugin->lock_area.x = area.width / 2.0 - (plugin->lock_area.width + entry_width) / 2.0; - plugin->lock_area.y = area.height / 2.0 - plugin->lock_area.height / 2.0; - - box_data = ply_image_get_data (plugin->box_image); - ply_frame_buffer_fill_with_argb32_data (plugin->frame_buffer, - &plugin->box_area, 0, 0, - box_data); + node = next_node; + } +} - ply_entry_show (plugin->entry, plugin->loop, plugin->window, x, y); +static void +show_prompt (ply_boot_splash_plugin_t *plugin, + const char *prompt, + const char *entry_text) +{ + ply_list_node_t *node; - lock_data = ply_image_get_data (plugin->lock_image); - ply_frame_buffer_fill_with_argb32_data (plugin->frame_buffer, - &plugin->lock_area, 0, 0, - lock_data); - } - else + node = ply_list_get_first_node (plugin->views); + while (node != NULL) { - ply_entry_draw (plugin->entry); - } - if (prompt != NULL) - { - int label_width, label_height; + ply_list_node_t *next_node; + view_t *view; - ply_label_set_text (plugin->label, prompt); - label_width = ply_label_get_width (plugin->label); - label_height = ply_label_get_height (plugin->label); + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - x = plugin->box_area.x + plugin->lock_area.width / 2; - y = plugin->box_area.y + plugin->box_area.height; + view_show_prompt (view, prompt); + ply_entry_set_text (view->entry, entry_text); - ply_label_show (plugin->label, plugin->window, x, y); + node = next_node; } - } static void @@ -1597,12 +1839,15 @@ become_idle (ply_boot_splash_plugin_t *plugin, static void display_normal (ply_boot_splash_plugin_t *plugin) { + pause_views (plugin); if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_NORMAL) { plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL; - ply_entry_hide (plugin->entry); - start_animation(plugin); + hide_prompt (plugin); + start_animation (plugin); + redraw_views (plugin); } + unpause_views (plugin); } static void @@ -1610,13 +1855,14 @@ display_password (ply_boot_splash_plugin_t *plugin, const char *prompt, int bullets) { + pause_views (plugin); if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL) - { - stop_animation (plugin); - } + stop_animation (plugin); + plugin->state = PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY; - show_password_prompt (plugin, prompt); - ply_entry_set_bullet_count (plugin->entry, bullets); + show_password_prompt (plugin, prompt, bullets); + redraw_views (plugin); + unpause_views (plugin); } static void @@ -1624,14 +1870,14 @@ display_question (ply_boot_splash_plugin_t *plugin, const char *prompt, const char *entry_text) { + pause_views (plugin); if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL) - { - stop_animation (plugin); - } + stop_animation (plugin); plugin->state = PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY; - show_password_prompt (plugin, prompt); - ply_entry_set_text (plugin->entry, entry_text); + show_prompt (plugin, prompt, entry_text); + redraw_views (plugin); + unpause_views (plugin); } ply_boot_splash_plugin_interface_t * @@ -1641,8 +1887,8 @@ ply_boot_splash_plugin_get_interface (void) { .create_plugin = create_plugin, .destroy_plugin = destroy_plugin, - .add_window = add_window, - .remove_window = remove_window, + .add_pixel_display = add_pixel_display, + .remove_pixel_display = remove_pixel_display, .show_splash_screen = show_splash_screen, .update_status = update_status, .on_boot_progress = on_boot_progress, diff --git a/src/plugins/splash/text/plugin.c b/src/plugins/splash/text/plugin.c index 60edf491..6ca7ee1b 100644 --- a/src/plugins/splash/text/plugin.c +++ b/src/plugins/splash/text/plugin.c @@ -48,36 +48,270 @@ #include "ply-key-file.h" #include "ply-list.h" #include "ply-logger.h" -#include "ply-frame-buffer.h" -#include "ply-image.h" +#include "ply-text-display.h" #include "ply-text-progress-bar.h" #include "ply-utils.h" -#include "ply-window.h" #include <linux/kd.h> #define CLEAR_LINE_SEQUENCE "\033[2K\r\n" #define BACKSPACE "\b\033[0K" +typedef enum { + PLY_BOOT_SPLASH_DISPLAY_NORMAL, + PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY, + PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY +} ply_boot_splash_display_type_t; struct _ply_boot_splash_plugin { ply_event_loop_t *loop; ply_boot_splash_mode_t mode; - ply_window_t *window; + ply_list_t *views; - ply_text_progress_bar_t *progress_bar; + ply_boot_splash_display_type_t state; char *message; uint32_t is_animating : 1; }; +typedef struct +{ + ply_boot_splash_plugin_t *plugin; + ply_text_display_t *display; + ply_text_progress_bar_t *progress_bar; + +} view_t; + static void hide_splash_screen (ply_boot_splash_plugin_t *plugin, ply_event_loop_t *loop); -static void add_handlers (ply_boot_splash_plugin_t *plugin); -static void remove_handlers (ply_boot_splash_plugin_t *plugin); + +static view_t * +view_new (ply_boot_splash_plugin_t *plugin, + ply_text_display_t *display) +{ + view_t *view; + + view = calloc (1, sizeof (view_t)); + view->plugin = plugin; + view->display = display; + + view->progress_bar = ply_text_progress_bar_new (); + + return view; +} + +static void +view_free (view_t *view) +{ + ply_text_progress_bar_free (view->progress_bar); + + free (view); +} + +static void +view_show_message (view_t *view) +{ + ply_boot_splash_plugin_t *plugin; + int display_width, display_height; + + plugin = view->plugin; + + display_width = ply_text_display_get_number_of_columns (view->display); + display_height = ply_text_display_get_number_of_rows (view->display); + + ply_text_display_set_cursor_position (view->display, 0, + display_height / 2); + ply_text_display_clear_line (view->display); + ply_text_display_set_cursor_position (view->display, + (display_width - + strlen (plugin->message)) / 2, + display_height / 2); + + ply_text_display_write (view->display, "%s", plugin->message); +} + +static void +view_show_prompt (view_t *view, + const char *prompt, + const char *entered_text) +{ + + ply_boot_splash_plugin_t *plugin; + int display_width, display_height; + int i; + + plugin = view->plugin; + + display_width = ply_text_display_get_number_of_columns (view->display); + display_height = ply_text_display_get_number_of_rows (view->display); + ply_text_display_set_background_color (view->display, PLY_TERMINAL_COLOR_DEFAULT); + ply_text_display_clear_screen (view->display); + + ply_text_display_set_cursor_position (view->display, 0, display_height / 2); + + for (i=0; i < display_width; i++) + ply_text_display_write (view->display, "%c", ' '); + + ply_text_display_set_cursor_position (view->display, + display_width / 2 - (strlen (prompt)), + display_height / 2); + + ply_text_display_write (view->display, "%s:%s", prompt, entered_text); + + ply_text_display_show_cursor (view->display); +} + +static void +view_start_animation (view_t *view) +{ + ply_boot_splash_plugin_t *plugin; + ply_terminal_t *terminal; + + assert (view != NULL); + + plugin = view->plugin; + + terminal = ply_text_display_get_terminal (view->display); + + ply_terminal_set_color_hex_value (terminal, + PLY_TERMINAL_COLOR_BLACK, + 0x000000); + ply_terminal_set_color_hex_value (terminal, + PLY_TERMINAL_COLOR_WHITE, + 0xffffff); + ply_terminal_set_color_hex_value (terminal, + PLY_TERMINAL_COLOR_BLUE, + 0x0073B3); + ply_terminal_set_color_hex_value (terminal, + PLY_TERMINAL_COLOR_BROWN, + 0x00457E); + + ply_text_display_set_background_color (view->display, + PLY_TERMINAL_COLOR_BLACK); + ply_text_display_clear_screen (view->display); + ply_text_display_hide_cursor (view->display); + + if (plugin->mode == PLY_BOOT_SPLASH_MODE_SHUTDOWN) + { + ply_text_progress_bar_hide (view->progress_bar); + return; + } + + ply_text_progress_bar_show (view->progress_bar, + view->display); +} + +static void +view_redraw (view_t *view) +{ + unsigned long screen_width, screen_height; + + screen_width = ply_text_display_get_number_of_columns (view->display); + screen_height = ply_text_display_get_number_of_rows (view->display); + + ply_text_display_draw_area (view->display, 0, 0, + screen_width, screen_height); +} + +static void +redraw_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_redraw (view); + + node = next_node; + } +} + +static void +view_hide (view_t *view) +{ + if (view->display != NULL) + { + ply_terminal_t *terminal; + + terminal = ply_text_display_get_terminal (view->display); + + ply_text_display_set_background_color (view->display, PLY_TERMINAL_COLOR_DEFAULT); + ply_text_display_clear_screen (view->display); + ply_text_display_show_cursor (view->display); + + ply_terminal_reset_colors (terminal); + } +} + +static void +hide_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_hide (view); + + node = next_node; + } +} + +static void +pause_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + ply_text_display_pause_updates (view->display); + + node = next_node; + } +} + +static void +unpause_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + ply_text_display_unpause_updates (view->display); + + node = next_node; + } +} static ply_boot_splash_plugin_t * create_plugin (ply_key_file_t *key_file) @@ -87,9 +321,10 @@ create_plugin (ply_key_file_t *key_file) ply_trace ("creating plugin"); plugin = calloc (1, sizeof (ply_boot_splash_plugin_t)); - plugin->progress_bar = ply_text_progress_bar_new (); plugin->message = NULL; + plugin->views = ply_list_new (); + return plugin; } @@ -102,6 +337,31 @@ detach_from_event_loop (ply_boot_splash_plugin_t *plugin) } static void +free_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_free (view); + ply_list_remove_node (plugin->views, node); + + node = next_node; + } + + ply_list_free (plugin->views); + plugin->views = NULL; +} + +static void destroy_plugin (ply_boot_splash_plugin_t *plugin) { ply_trace ("destroying plugin"); @@ -109,14 +369,12 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin) if (plugin == NULL) return; - remove_handlers (plugin); - /* It doesn't ever make sense to keep this plugin on screen * after exit */ hide_splash_screen (plugin, plugin->loop); - ply_text_progress_bar_free (plugin->progress_bar); + free_views (plugin); if (plugin->message != NULL) free (plugin->message); @@ -126,67 +384,52 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin) static void show_message (ply_boot_splash_plugin_t *plugin) { - int window_width, window_height; + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; - window_width = ply_window_get_number_of_text_columns (plugin->window); - window_height = ply_window_get_number_of_text_rows (plugin->window); + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - ply_window_set_text_cursor_position (plugin->window, - 0, window_height / 2); - ply_window_clear_text_line (plugin->window); - ply_window_set_text_cursor_position (plugin->window, - (window_width - strlen (plugin->message)) / 2, - window_height / 2); + view_show_message (view); - write (STDOUT_FILENO, plugin->message, strlen (plugin->message)); + node = next_node; + } } static void start_animation (ply_boot_splash_plugin_t *plugin) { + ply_list_node_t *node; assert (plugin != NULL); assert (plugin->loop != NULL); + redraw_views (plugin); + if (plugin->message != NULL) show_message (plugin); if (plugin->is_animating) return; - ply_window_set_color_hex_value (plugin->window, - PLY_WINDOW_COLOR_BLACK, - 0x000000); - ply_window_set_color_hex_value (plugin->window, - PLY_WINDOW_COLOR_WHITE, - 0xffffff); - ply_window_set_color_hex_value (plugin->window, - PLY_WINDOW_COLOR_BLUE, - 0x0073B3); - ply_window_set_color_hex_value (plugin->window, - PLY_WINDOW_COLOR_BROWN, - 0x00457E); -#if 0 - ply_window_set_color_hex_value (plugin->window, - PLY_WINDOW_COLOR_BLUE, - PLYMOUTH_BACKGROUND_START_COLOR); - ply_window_set_color_hex_value (plugin->window, - PLY_WINDOW_COLOR_GREEN, - PLYMOUTH_BACKGROUND_COLOR); -#endif - - ply_window_set_background_color (plugin->window, PLY_WINDOW_COLOR_BLACK); - ply_window_clear_screen (plugin->window); - ply_window_hide_text_cursor (plugin->window); - - if (plugin->mode == PLY_BOOT_SPLASH_MODE_SHUTDOWN) + node = ply_list_get_first_node (plugin->views); + while (node != NULL) { - ply_text_progress_bar_hide (plugin->progress_bar); - return; - } + ply_list_node_t *next_node; + view_t *view; - ply_text_progress_bar_show (plugin->progress_bar, - plugin->window); + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_start_animation (view); + + node = next_node; + } plugin->is_animating = true; } @@ -194,6 +437,8 @@ start_animation (ply_boot_splash_plugin_t *plugin) static void stop_animation (ply_boot_splash_plugin_t *plugin) { + ply_list_node_t *node; + assert (plugin != NULL); assert (plugin->loop != NULL); @@ -202,64 +447,97 @@ stop_animation (ply_boot_splash_plugin_t *plugin) plugin->is_animating = false; + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + ply_text_progress_bar_hide (view->progress_bar); - ply_text_progress_bar_hide (plugin->progress_bar); + node = next_node; + } + redraw_views (plugin); +} + +static void +clear_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + assert (plugin != NULL); + assert (plugin->loop != NULL); + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + ply_text_display_clear_screen (view->display); + + node = next_node; + } } static void on_draw (ply_boot_splash_plugin_t *plugin, + ply_terminal_t *terminal, int x, int y, int width, int height) { - ply_window_set_background_color (plugin->window, PLY_WINDOW_COLOR_BLUE); - ply_window_clear_screen (plugin->window); + clear_views (plugin); } static void -on_erase (ply_boot_splash_plugin_t *plugin, - int x, - int y, - int width, - int height) +add_text_display (ply_boot_splash_plugin_t *plugin, + ply_text_display_t *display) { - ply_window_set_background_color (plugin->window, PLY_WINDOW_COLOR_BLUE); - ply_window_clear_screen (plugin->window); -} + view_t *view; -static void -add_handlers (ply_boot_splash_plugin_t *plugin) -{ - ply_window_set_draw_handler (plugin->window, - (ply_window_draw_handler_t) - on_draw, plugin); - ply_window_set_erase_handler (plugin->window, - (ply_window_erase_handler_t) - on_erase, plugin); + view = view_new (plugin, display); + + ply_text_display_set_draw_handler (view->display, + (ply_text_display_draw_handler_t) + on_draw, view); + + ply_list_append_data (plugin->views, view); } static void -remove_handlers (ply_boot_splash_plugin_t *plugin) +remove_text_display (ply_boot_splash_plugin_t *plugin, + ply_text_display_t *display) { + ply_list_node_t *node; - ply_window_set_draw_handler (plugin->window, NULL, NULL); - ply_window_set_erase_handler (plugin->window, NULL, NULL); + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + view_t *view; + ply_list_node_t *next_node; -} + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); -static void -add_window (ply_boot_splash_plugin_t *plugin, - ply_window_t *window) -{ - plugin->window = window; -} + if (view->display == display) + { + ply_text_display_set_draw_handler (view->display, + NULL, NULL); + view_free (view); + ply_list_remove_node (plugin->views, node); + return; + } -static void -remove_window (ply_boot_splash_plugin_t *plugin, - ply_window_t *window) -{ - plugin->window = NULL; + node = next_node; + } } static bool @@ -270,11 +548,6 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, { assert (plugin != NULL); - add_handlers (plugin); - - ply_window_hide_text_cursor (plugin->window); - ply_window_set_text_cursor_position (plugin->window, 0, 0); - plugin->loop = loop; plugin->mode = mode; ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t) @@ -301,15 +574,30 @@ on_boot_progress (ply_boot_splash_plugin_t *plugin, double duration, double percent_done) { + ply_list_node_t *node; double total_duration; total_duration = duration / percent_done; - /* Hi Will! */ + /* Fun made-up smoothing function to make the growth asymptotic: + * fraction(time,estimate)=1-2^(-(time^1.45)/estimate) */ percent_done = 1.0 - pow (2.0, -pow (duration, 1.45) / total_duration) * (1.0 - percent_done); - ply_text_progress_bar_set_percent_done (plugin->progress_bar, percent_done); - ply_text_progress_bar_draw (plugin->progress_bar); + node = ply_list_get_first_node (plugin->views); + + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + ply_text_progress_bar_set_percent_done (view->progress_bar, percent_done); + ply_text_progress_bar_draw (view->progress_bar); + + node = next_node; + } } static void @@ -331,23 +619,21 @@ hide_splash_screen (ply_boot_splash_plugin_t *plugin, detach_from_event_loop (plugin); } - if (plugin->window != NULL) - { - remove_handlers (plugin); - - ply_window_set_background_color (plugin->window, PLY_WINDOW_COLOR_DEFAULT); - ply_window_clear_screen (plugin->window); - ply_window_show_text_cursor (plugin->window); - ply_window_reset_colors (plugin->window); - } - + hide_views (plugin); ply_show_new_kernel_messages (true); } static void display_normal (ply_boot_splash_plugin_t *plugin) { - start_animation(plugin); + pause_views (plugin); + if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_NORMAL) + { + plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL; + start_animation (plugin); + redraw_views (plugin); + } + unpause_views (plugin); } static void @@ -362,39 +648,75 @@ display_message (ply_boot_splash_plugin_t *plugin, } static void +show_password_prompt (ply_boot_splash_plugin_t *plugin, + const char *prompt, + int bullets) +{ + ply_list_node_t *node; + int i; + char *entered_text; + + entered_text = calloc (bullets + 1, sizeof (char)); + + for (i = 0; i < bullets; i++) + entered_text[i] = '*'; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_show_prompt (view, prompt, entered_text); + + node = next_node; + } + free (entered_text); +} + +static void +show_prompt (ply_boot_splash_plugin_t *plugin, + const char *prompt, + const char *text) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_show_prompt (view, prompt, text); + + node = next_node; + } +} + +static void display_password (ply_boot_splash_plugin_t *plugin, const char *prompt, int bullets) { - int window_width, window_height; - int i; - stop_animation (plugin); - ply_window_set_background_color (plugin->window, PLY_WINDOW_COLOR_DEFAULT); - ply_window_clear_screen (plugin->window); - - window_width = ply_window_get_number_of_text_columns (plugin->window); - window_height = ply_window_get_number_of_text_rows (plugin->window); - - if (!prompt) - prompt = "Password"; - - ply_window_set_text_cursor_position (plugin->window, 0, window_height / 2); - - for (i=0; i < window_width; i++) - { - write (STDOUT_FILENO, " ", strlen (" ")); - } - ply_window_set_text_cursor_position (plugin->window, - window_width / 2 - (strlen (prompt)), - window_height / 2); - write (STDOUT_FILENO, prompt, strlen (prompt)); - write (STDOUT_FILENO, ":", strlen (":")); - - for (i=0; i < bullets; i++) - { - write (STDOUT_FILENO, "*", strlen ("*")); - } - ply_window_show_text_cursor (plugin->window); + pause_views (plugin); + if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL) + stop_animation (plugin); + + plugin->state = PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY; + + if (!prompt) + prompt = "Password"; + + show_password_prompt (plugin, prompt, bullets); + + redraw_views (plugin); + unpause_views (plugin); } static void @@ -402,35 +724,20 @@ display_question (ply_boot_splash_plugin_t *plugin, const char *prompt, const char *entry_text) { - int window_width, window_height; - int i; - stop_animation (plugin); - ply_window_set_background_color (plugin->window, PLY_WINDOW_COLOR_DEFAULT); - ply_window_clear_screen (plugin->window); - - window_width = ply_window_get_number_of_text_columns (plugin->window); - window_height = ply_window_get_number_of_text_rows (plugin->window); - - if (!prompt) - prompt = ""; - - ply_window_set_text_cursor_position (plugin->window, - 0, window_height / 2); - - for (i=0; i < window_width; i++) - { - write (STDOUT_FILENO, " ", strlen (" ")); - } - ply_window_set_text_cursor_position (plugin->window, - window_width / 2 - (strlen (prompt)), - window_height / 2); - write (STDOUT_FILENO, prompt, strlen (prompt)); - write (STDOUT_FILENO, ":", strlen (":")); - - write (STDOUT_FILENO, entry_text, strlen (entry_text)); - ply_window_show_text_cursor (plugin->window); -} + pause_views (plugin); + if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL) + stop_animation (plugin); + + plugin->state = PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY; + if (!prompt) + prompt = "Password"; + + show_prompt (plugin, prompt, entry_text); + + redraw_views (plugin); + unpause_views (plugin); +} ply_boot_splash_plugin_interface_t * ply_boot_splash_plugin_get_interface (void) @@ -439,8 +746,8 @@ ply_boot_splash_plugin_get_interface (void) { .create_plugin = create_plugin, .destroy_plugin = destroy_plugin, - .add_window = add_window, - .remove_window = remove_window, + .add_text_display = add_text_display, + .remove_text_display = remove_text_display, .show_splash_screen = show_splash_screen, .update_status = update_status, .on_boot_progress = on_boot_progress, diff --git a/src/plugins/splash/throbgress/plugin.c b/src/plugins/splash/throbgress/plugin.c index 89986274..02b334df 100644 --- a/src/plugins/splash/throbgress/plugin.c +++ b/src/plugins/splash/throbgress/plugin.c @@ -49,16 +49,14 @@ #include "ply-list.h" #include "ply-progress-bar.h" #include "ply-logger.h" -#include "ply-frame-buffer.h" #include "ply-image.h" #include "ply-trigger.h" +#include "ply-pixel-buffer.h" +#include "ply-pixel-display.h" #include "ply-utils.h" -#include "ply-window.h" #include "ply-throbber.h" -#include <linux/kd.h> - #ifndef FRAMES_PER_SECOND #define FRAMES_PER_SECOND 30 #endif @@ -73,21 +71,27 @@ typedef enum { PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY } ply_boot_splash_display_type_t; +typedef struct +{ + ply_boot_splash_plugin_t *plugin; + ply_pixel_display_t *display; + ply_entry_t *entry; + ply_throbber_t *throbber; + ply_progress_bar_t *progress_bar; + ply_label_t *label; + ply_rectangle_t box_area, lock_area, logo_area, bar_area; +} view_t; + struct _ply_boot_splash_plugin { ply_event_loop_t *loop; ply_boot_splash_mode_t mode; - ply_frame_buffer_t *frame_buffer; - ply_frame_buffer_area_t box_area, lock_area, logo_area, bar_area; ply_image_t *logo_image; ply_image_t *lock_image; ply_image_t *box_image; - ply_window_t *window; + ply_list_t *views; - ply_entry_t *entry; - ply_throbber_t *throbber; - ply_label_t *label; - ply_progress_bar_t *progress_bar; + char *image_dir; ply_boot_splash_display_type_t state; ply_trigger_t *idle_trigger; @@ -97,11 +101,276 @@ struct _ply_boot_splash_plugin uint32_t is_animating : 1; }; -static void add_handlers (ply_boot_splash_plugin_t *plugin); -static void remove_handlers (ply_boot_splash_plugin_t *plugin); - static void detach_from_event_loop (ply_boot_splash_plugin_t *plugin); +static view_t * +view_new (ply_boot_splash_plugin_t *plugin, + ply_pixel_display_t *display) +{ + view_t *view; + + view = calloc (1, sizeof (view_t)); + view->plugin = plugin; + view->display = display; + + view->entry = ply_entry_new (plugin->image_dir); + view->throbber = ply_throbber_new (plugin->image_dir, + "throbber-"); + view->progress_bar = ply_progress_bar_new (); + view->label = ply_label_new (); + + return view; +} + +static void +view_free (view_t *view) +{ + + ply_entry_free (view->entry); + ply_throbber_free (view->throbber); + ply_progress_bar_free (view->progress_bar); + ply_label_free (view->label); + + free (view); +} + +static void +free_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_free (view); + ply_list_remove_node (plugin->views, node); + + node = next_node; + } + + ply_list_free (plugin->views); + plugin->views = NULL; +} + +static bool +view_load (view_t *view) +{ + ply_trace ("loading entry"); + if (!ply_entry_load (view->entry)) + return false; + + ply_trace ("loading throbber"); + if (!ply_throbber_load (view->throbber)) + return false; + + return true; +} + +static bool +load_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + bool view_loaded; + + view_loaded = false; + node = ply_list_get_first_node (plugin->views); + + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + if (view_load (view)) + view_loaded = true; + + node = next_node; + } + + return view_loaded; +} + +static void +view_redraw (view_t *view) +{ + unsigned long screen_width, screen_height; + + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); + + ply_pixel_display_draw_area (view->display, 0, 0, + screen_width, screen_height); +} + +static void +redraw_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_redraw (view); + + node = next_node; + } +} + +static void +pause_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + ply_pixel_display_pause_updates (view->display); + + node = next_node; + } +} + +static void +unpause_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + ply_pixel_display_unpause_updates (view->display); + + node = next_node; + } +} + +static void +view_start_animation (view_t *view) +{ + ply_boot_splash_plugin_t *plugin; + + unsigned long screen_width, screen_height; + long width, height; + + assert (view != NULL); + + plugin = view->plugin; + + assert (plugin != NULL); + assert (plugin->loop != NULL); + + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); + + ply_pixel_display_draw_area (view->display, 0, 0, + screen_width, screen_height); + + if (plugin->mode == PLY_BOOT_SPLASH_MODE_SHUTDOWN) + return; + + width = ply_throbber_get_width (view->throbber); + height = ply_throbber_get_height (view->throbber); + ply_throbber_start (view->throbber, + plugin->loop, + view->display, + screen_width / 2.0 - width / 2.0, + view->logo_area.y + view->logo_area.height + height / 2); + ply_progress_bar_show (view->progress_bar, + view->display, + 0, screen_height - ply_progress_bar_get_height (view->progress_bar)); + view_redraw (view); +} + +static void +view_show_prompt (view_t *view, + const char *prompt) +{ + ply_boot_splash_plugin_t *plugin; + int x, y; + int entry_width, entry_height; + + assert (view != NULL); + + plugin = view->plugin; + + if (ply_entry_is_hidden (view->entry)) + { + unsigned long screen_width, screen_height; + + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); + + view->box_area.width = ply_image_get_width (plugin->box_image); + view->box_area.height = ply_image_get_height (plugin->box_image); + view->box_area.x = screen_width / 2.0 - view->box_area.width / 2.0; + view->box_area.y = screen_height / 2.0 - view->box_area.height / 2.0; + + view->lock_area.width = ply_image_get_width (plugin->lock_image); + view->lock_area.height = ply_image_get_height (plugin->lock_image); + + entry_width = ply_entry_get_width (view->entry); + entry_height = ply_entry_get_height (view->entry); + + x = screen_width / 2.0 - (view->lock_area.width + entry_width) / 2.0 + view->lock_area.width; + y = screen_height / 2.0 - entry_height / 2.0; + + view->lock_area.x = screen_width / 2.0 - (view->lock_area.width + entry_width) / 2.0; + view->lock_area.y = screen_height / 2.0 - view->lock_area.height / 2.0; + + ply_entry_show (view->entry, plugin->loop, view->display, x, y); + } + + if (prompt != NULL) + { + int label_width, label_height; + + ply_label_set_text (view->label, prompt); + label_width = ply_label_get_width (view->label); + label_height = ply_label_get_height (view->label); + + x = view->box_area.x + view->lock_area.width / 2; + y = view->box_area.y + view->box_area.height; + + ply_label_show (view->label, view->display, x, y); + } +} + +static void +view_hide_prompt (view_t *view) +{ + assert (view != NULL); + + ply_entry_hide (view->entry); + ply_label_hide (view->label); +} + static ply_boot_splash_plugin_t * create_plugin (ply_key_file_t *key_file) { @@ -122,11 +391,8 @@ create_plugin (ply_key_file_t *key_file) plugin->box_image = ply_image_new (image_path); free (image_path); - plugin->entry = ply_entry_new (image_dir); - plugin->throbber = ply_throbber_new (image_dir, "throbber-"); - plugin->label = ply_label_new (); - plugin->progress_bar = ply_progress_bar_new (); - free(image_dir); + plugin->image_dir = image_dir; + plugin->views = ply_list_new (); return plugin; } @@ -137,8 +403,6 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin) if (plugin == NULL) return; - remove_handlers (plugin); - if (plugin->loop != NULL) { ply_event_loop_stop_watching_for_exit (plugin->loop, (ply_event_loop_exit_handler_t) @@ -150,83 +414,83 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin) ply_image_free (plugin->logo_image); ply_image_free (plugin->box_image); ply_image_free (plugin->lock_image); - ply_entry_free (plugin->entry); - ply_throbber_free (plugin->throbber); - ply_label_free (plugin->label); - ply_progress_bar_free (plugin->progress_bar); + + free_views (plugin); free (plugin); } static void -draw_background (ply_boot_splash_plugin_t *plugin, - ply_frame_buffer_area_t *area) +draw_background (view_t *view, + ply_pixel_buffer_t *pixel_buffer, + int x, + int y, + int width, + int height) { - ply_frame_buffer_area_t screen_area; + ply_boot_splash_plugin_t *plugin; + ply_rectangle_t area; - if (area == NULL) - { - ply_frame_buffer_get_size (plugin->frame_buffer, &screen_area); - area = &screen_area; - } + plugin = view->plugin; + + area.x = x; + area.y = y; + area.width = width; + area.height = height; - ply_window_erase_area (plugin->window, area->x, area->y, - area->width, area->height); + ply_pixel_buffer_fill_with_gradient (pixel_buffer, &area, + PLYMOUTH_BACKGROUND_START_COLOR, + PLYMOUTH_BACKGROUND_END_COLOR); } static void -draw_logo (ply_boot_splash_plugin_t *plugin) +draw_logo (view_t *view, + ply_pixel_buffer_t *pixel_buffer) { + ply_boot_splash_plugin_t *plugin; uint32_t *logo_data; + unsigned long screen_width, screen_height; long width, height; + plugin = view->plugin; + + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); + width = ply_image_get_width (plugin->logo_image); height = ply_image_get_height (plugin->logo_image); logo_data = ply_image_get_data (plugin->logo_image); - ply_frame_buffer_get_size (plugin->frame_buffer, &plugin->logo_area); - plugin->logo_area.x = (plugin->logo_area.width / 2) - (width / 2); - plugin->logo_area.y = (plugin->logo_area.height / 2) - (height / 2); - plugin->logo_area.width = width; - plugin->logo_area.height = height; - - ply_frame_buffer_pause_updates (plugin->frame_buffer); - draw_background (plugin, &plugin->logo_area); - ply_frame_buffer_fill_with_argb32_data (plugin->frame_buffer, - &plugin->logo_area, 0, 0, + view->logo_area.x = (screen_width / 2) - (width / 2); + view->logo_area.y = (screen_height / 2) - (height / 2); + view->logo_area.width = width; + view->logo_area.height = height; + + ply_pixel_buffer_fill_with_argb32_data (pixel_buffer, + &view->logo_area, 0, 0, logo_data); - ply_frame_buffer_unpause_updates (plugin->frame_buffer); } static void start_animation (ply_boot_splash_plugin_t *plugin) { - - long width, height; - ply_frame_buffer_area_t area; - assert (plugin != NULL); - assert (plugin->loop != NULL); + ply_list_node_t *node; if (plugin->is_animating) return; - draw_background (plugin, NULL); - draw_logo (plugin); + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; - if (plugin->mode == PLY_BOOT_SPLASH_MODE_SHUTDOWN) - return; + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - ply_frame_buffer_get_size (plugin->frame_buffer, &area); + view_start_animation (view); - width = ply_throbber_get_width (plugin->throbber); - height = ply_throbber_get_height (plugin->throbber); - ply_throbber_start (plugin->throbber, - plugin->loop, - plugin->window, - area.width / 2.0 - width / 2.0, - plugin->logo_area.y + plugin->logo_area.height + height / 2); - ply_progress_bar_show (plugin->progress_bar, - plugin->window, - 0, area.height - ply_progress_bar_get_height (plugin->progress_bar)); + node = next_node; + } plugin->is_animating = true; } @@ -235,6 +499,8 @@ static void stop_animation (ply_boot_splash_plugin_t *plugin, ply_trigger_t *trigger) { + ply_list_node_t *node; + assert (plugin != NULL); assert (plugin->loop != NULL); @@ -243,30 +509,25 @@ stop_animation (ply_boot_splash_plugin_t *plugin, plugin->is_animating = false; - ply_progress_bar_hide (plugin->progress_bar); - ply_throbber_stop (plugin->throbber, trigger); - -#ifdef ENABLE_FADE_OUT - int i; - for (i = 0; i < 10; i++) + node = ply_list_get_first_node (plugin->views); + while (node != NULL) { - ply_frame_buffer_fill_with_hex_color_at_opacity (plugin->frame_buffer, NULL, - PLYMOUTH_BACKGROUND_COLOR, - .1 + .1 * i); - } + ply_list_node_t *next_node; + view_t *view; - ply_frame_buffer_fill_with_hex_color (plugin->frame_buffer, NULL, - PLYMOUTH_BACKGROUND_COLOR); + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - for (i = 0; i < 20; i++) - { - ply_frame_buffer_fill_with_color (plugin->frame_buffer, NULL, - 0.0, 0.0, 0.0, .05 + .05 * i); + ply_progress_bar_hide (view->progress_bar); + if (trigger != NULL) + ply_trigger_ignore_next_pull (trigger); + ply_throbber_stop (view->throbber, trigger); + + node = next_node; } - ply_frame_buffer_fill_with_color (plugin->frame_buffer, NULL, - 0.0, 0.0, 0.0, 1.0); -#endif + if (trigger != NULL) + ply_trigger_pull (trigger, NULL); } static void @@ -274,7 +535,6 @@ on_interrupt (ply_boot_splash_plugin_t *plugin) { ply_event_loop_exit (plugin->loop, 1); stop_animation (plugin, NULL); - ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_TEXT); } static void @@ -283,119 +543,93 @@ detach_from_event_loop (ply_boot_splash_plugin_t *plugin) plugin->loop = NULL; } -void -on_keyboard_input (ply_boot_splash_plugin_t *plugin, - const char *keyboard_input, - size_t character_size) -{ -} - -void -on_backspace (ply_boot_splash_plugin_t *plugin) -{ -} - -void -on_enter (ply_boot_splash_plugin_t *plugin, - const char *text) -{ -} - -void -on_draw (ply_boot_splash_plugin_t *plugin, +static void +on_draw (view_t *view, + ply_pixel_buffer_t *pixel_buffer, int x, int y, int width, int height) { - ply_frame_buffer_area_t area; + ply_boot_splash_plugin_t *plugin; + ply_rectangle_t area; area.x = x; area.y = y; area.width = width; area.height = height; - ply_frame_buffer_pause_updates (plugin->frame_buffer); - draw_background (plugin, &area); + plugin = view->plugin; + + draw_background (view, pixel_buffer, x, y, width, height); - if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY || + if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY || plugin->state == PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY ) { - ply_entry_draw (plugin->entry); - ply_label_draw (plugin->label); + uint32_t *box_data, *lock_data; + + box_data = ply_image_get_data (plugin->box_image); + ply_pixel_buffer_fill_with_argb32_data (pixel_buffer, + &view->box_area, 0, 0, + box_data); + ply_entry_draw_area (view->entry, pixel_buffer, x, y, width, height); + ply_label_draw_area (view->label, pixel_buffer, x, y, width, height); + lock_data = ply_image_get_data (plugin->lock_image); + ply_pixel_buffer_fill_with_argb32_data (pixel_buffer, + &view->lock_area, 0, 0, + lock_data); } else { - draw_logo (plugin); - ply_progress_bar_draw (plugin->progress_bar); + draw_logo (view, pixel_buffer); + ply_throbber_draw_area (view->throbber, + pixel_buffer, x, y, width, height); + ply_progress_bar_draw_area (view->progress_bar, + pixel_buffer, x, y, width, height); } - ply_frame_buffer_unpause_updates (plugin->frame_buffer); } -void -on_erase (ply_boot_splash_plugin_t *plugin, - int x, - int y, - int width, - int height) +static void +add_pixel_display (ply_boot_splash_plugin_t *plugin, + ply_pixel_display_t *display) { - ply_frame_buffer_area_t area; + view_t *view; - area.x = x; - area.y = y; - area.width = width; - area.height = height; + view = view_new (plugin, display); - ply_frame_buffer_fill_with_gradient (plugin->frame_buffer, &area, - PLYMOUTH_BACKGROUND_START_COLOR, - PLYMOUTH_BACKGROUND_END_COLOR); + ply_pixel_display_set_draw_handler (view->display, + (ply_pixel_display_draw_handler_t) + on_draw, view); + + ply_list_append_data (plugin->views, view); } static void -add_handlers (ply_boot_splash_plugin_t *plugin) +remove_pixel_display (ply_boot_splash_plugin_t *plugin, + ply_pixel_display_t *display) { - ply_window_add_keyboard_input_handler (plugin->window, - (ply_window_keyboard_input_handler_t) - on_keyboard_input, plugin); - ply_window_add_backspace_handler (plugin->window, - (ply_window_backspace_handler_t) - on_backspace, plugin); - ply_window_add_enter_handler (plugin->window, - (ply_window_enter_handler_t) - on_enter, plugin); + ply_list_node_t *node; - ply_window_set_draw_handler (plugin->window, - (ply_window_draw_handler_t) - on_draw, plugin); - - ply_window_set_erase_handler (plugin->window, - (ply_window_erase_handler_t) - on_erase, plugin); -} + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + view_t *view; + ply_list_node_t *next_node; -static void -remove_handlers (ply_boot_splash_plugin_t *plugin) -{ + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - ply_window_remove_keyboard_input_handler (plugin->window, (ply_window_keyboard_input_handler_t) on_keyboard_input); - ply_window_remove_backspace_handler (plugin->window, (ply_window_backspace_handler_t) on_backspace); - ply_window_remove_enter_handler (plugin->window, (ply_window_enter_handler_t) on_enter); - ply_window_set_draw_handler (plugin->window, NULL, NULL); - ply_window_set_erase_handler (plugin->window, NULL, NULL); -} + if (view->display == display) + { -static void -add_window (ply_boot_splash_plugin_t *plugin, - ply_window_t *window) -{ - plugin->window = window; -} + ply_pixel_display_set_draw_handler (view->display, NULL, NULL); + view_free (view); + ply_list_remove_node (plugin->views, node); + return; + } -static void -remove_window (ply_boot_splash_plugin_t *plugin, - ply_window_t *window) -{ - plugin->window = NULL; + node = next_node; + } } static bool @@ -407,8 +641,6 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, assert (plugin != NULL); assert (plugin->logo_image != NULL); - add_handlers (plugin); - plugin->loop = loop; plugin->mode = mode; @@ -424,19 +656,11 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, if (!ply_image_load (plugin->box_image)) return false; - ply_trace ("loading entry"); - if (!ply_entry_load (plugin->entry)) - return false; - - ply_trace ("loading throbber"); - if (!ply_throbber_load (plugin->throbber)) - return false; - - ply_trace ("setting graphics mode"); - if (!ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_GRAPHICS)) - return false; - - plugin->frame_buffer = ply_window_get_frame_buffer (plugin->window); + if (!load_views (plugin)) + { + ply_trace ("couldn't load views"); + return false; + } ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t) detach_from_event_loop, @@ -447,9 +671,6 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, (ply_event_handler_t) on_interrupt, plugin); - ply_window_clear_screen (plugin->window); - ply_window_hide_text_cursor (plugin->window); - ply_trace ("starting boot animation"); start_animation (plugin); @@ -470,6 +691,7 @@ on_boot_progress (ply_boot_splash_plugin_t *plugin, double duration, double percent_done) { + ply_list_node_t *node; double total_duration; total_duration = duration / percent_done; @@ -478,8 +700,21 @@ on_boot_progress (ply_boot_splash_plugin_t *plugin, * fraction(time,estimate)=1-2^(-(time^1.45)/estimate) */ percent_done = 1.0 - pow (2.0, -pow (duration, 1.45) / total_duration) * (1.0 - percent_done); - ply_progress_bar_set_percent_done (plugin->progress_bar, percent_done); - ply_progress_bar_draw (plugin->progress_bar); + node = ply_list_get_first_node (plugin->views); + + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + ply_progress_bar_set_percent_done (view->progress_bar, percent_done); + ply_progress_bar_draw (view->progress_bar); + + node = next_node; + } } static void @@ -488,8 +723,6 @@ hide_splash_screen (ply_boot_splash_plugin_t *plugin, { assert (plugin != NULL); - remove_handlers (plugin); - if (plugin->loop != NULL) { stop_animation (plugin, NULL); @@ -500,76 +733,53 @@ hide_splash_screen (ply_boot_splash_plugin_t *plugin, detach_from_event_loop (plugin); } - plugin->frame_buffer = NULL; plugin->is_visible = false; - - ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_TEXT); } static void show_password_prompt (ply_boot_splash_plugin_t *plugin, - const char *prompt) + const char *text, + int number_of_bullets) { - ply_frame_buffer_area_t area; - int x, y; - int entry_width, entry_height; + ply_list_node_t *node; - uint32_t *box_data, *lock_data; - - assert (plugin != NULL); - - if (ply_entry_is_hidden (plugin->entry)) + node = ply_list_get_first_node (plugin->views); + while (node != NULL) { - draw_background (plugin, NULL); - - ply_frame_buffer_get_size (plugin->frame_buffer, &area); - plugin->box_area.width = ply_image_get_width (plugin->box_image); - plugin->box_area.height = ply_image_get_height (plugin->box_image); - plugin->box_area.x = area.width / 2.0 - plugin->box_area.width / 2.0; - plugin->box_area.y = area.height / 2.0 - plugin->box_area.height / 2.0; + ply_list_node_t *next_node; + view_t *view; - plugin->lock_area.width = ply_image_get_width (plugin->lock_image); - plugin->lock_area.height = ply_image_get_height (plugin->lock_image); + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - entry_width = ply_entry_get_width (plugin->entry); - entry_height = ply_entry_get_height (plugin->entry); + view_show_prompt (view, text); + ply_entry_set_bullet_count (view->entry, number_of_bullets); - x = area.width / 2.0 - (plugin->lock_area.width + entry_width) / 2.0 + plugin->lock_area.width; - y = area.height / 2.0 - entry_height / 2.0; - - plugin->lock_area.x = area.width / 2.0 - (plugin->lock_area.width + entry_width) / 2.0; - plugin->lock_area.y = area.height / 2.0 - plugin->lock_area.height / 2.0; - - box_data = ply_image_get_data (plugin->box_image); - ply_frame_buffer_fill_with_argb32_data (plugin->frame_buffer, - &plugin->box_area, 0, 0, - box_data); + node = next_node; + } +} - ply_entry_show (plugin->entry, plugin->loop, plugin->window, x, y); +static void +show_prompt (ply_boot_splash_plugin_t *plugin, + const char *prompt, + const char *entry_text) +{ + ply_list_node_t *node; - lock_data = ply_image_get_data (plugin->lock_image); - ply_frame_buffer_fill_with_argb32_data (plugin->frame_buffer, - &plugin->lock_area, 0, 0, - lock_data); - } - else - { - ply_entry_draw (plugin->entry); - } - if (prompt != NULL) + node = ply_list_get_first_node (plugin->views); + while (node != NULL) { - int label_width, label_height; + ply_list_node_t *next_node; + view_t *view; - ply_label_set_text (plugin->label, prompt); - label_width = ply_label_get_width (plugin->label); - label_height = ply_label_get_height (plugin->label); + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - x = plugin->box_area.x + plugin->lock_area.width / 2; - y = plugin->box_area.y + plugin->box_area.height; + view_show_prompt (view, prompt); + ply_entry_set_text (view->entry, entry_text); - ply_label_show (plugin->label, plugin->window, x, y); + node = next_node; } - } static void @@ -586,14 +796,37 @@ become_idle (ply_boot_splash_plugin_t *plugin, } static void +hide_prompt (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_hide_prompt (view); + + node = next_node; + } +} + +static void display_normal (ply_boot_splash_plugin_t *plugin) { + pause_views (plugin); if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_NORMAL) { plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL; - ply_entry_hide (plugin->entry); - start_animation(plugin); + hide_prompt (plugin); + start_animation (plugin); + redraw_views (plugin); } + unpause_views (plugin); } static void @@ -601,13 +834,14 @@ display_password (ply_boot_splash_plugin_t *plugin, const char *prompt, int bullets) { + pause_views (plugin); if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL) - { - stop_animation (plugin, NULL); - } + stop_animation (plugin, NULL); + plugin->state = PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY; - show_password_prompt (plugin, prompt); - ply_entry_set_bullet_count (plugin->entry, bullets); + show_password_prompt (plugin, prompt, bullets); + redraw_views (plugin); + unpause_views (plugin); } static void @@ -615,14 +849,14 @@ display_question (ply_boot_splash_plugin_t *plugin, const char *prompt, const char *entry_text) { + pause_views (plugin); if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL) - { - stop_animation (plugin, NULL); - } + stop_animation (plugin, NULL); plugin->state = PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY; - show_password_prompt (plugin, prompt); - ply_entry_set_text (plugin->entry, entry_text); + show_prompt (plugin, prompt, entry_text); + redraw_views (plugin); + unpause_views (plugin); } ply_boot_splash_plugin_interface_t * @@ -632,8 +866,8 @@ ply_boot_splash_plugin_get_interface (void) { .create_plugin = create_plugin, .destroy_plugin = destroy_plugin, - .add_window = add_window, - .remove_window = remove_window, + .add_pixel_display = add_pixel_display, + .remove_pixel_display = remove_pixel_display, .show_splash_screen = show_splash_screen, .update_status = update_status, .on_boot_progress = on_boot_progress, diff --git a/src/plugins/splash/two-step/plugin.c b/src/plugins/splash/two-step/plugin.c index 7b70202b..435031e2 100644 --- a/src/plugins/splash/two-step/plugin.c +++ b/src/plugins/splash/two-step/plugin.c @@ -47,12 +47,12 @@ #include "ply-label.h" #include "ply-list.h" #include "ply-logger.h" -#include "ply-frame-buffer.h" #include "ply-image.h" #include "ply-key-file.h" #include "ply-trigger.h" +#include "ply-pixel-buffer.h" +#include "ply-pixel-display.h" #include "ply-utils.h" -#include "ply-window.h" #include "ply-animation.h" #include "ply-progress-animation.h" @@ -73,21 +73,26 @@ typedef enum { PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY } ply_boot_splash_display_type_t; +typedef struct +{ + ply_boot_splash_plugin_t *plugin; + ply_pixel_display_t *display; + ply_entry_t *entry; + ply_animation_t *end_animation; + ply_progress_animation_t *progress_animation; + ply_label_t *label; + ply_rectangle_t box_area, lock_area; +} view_t; + struct _ply_boot_splash_plugin { ply_event_loop_t *loop; ply_boot_splash_mode_t mode; - ply_frame_buffer_t *frame_buffer; - ply_frame_buffer_area_t box_area, lock_area; ply_image_t *lock_image; ply_image_t *box_image; ply_image_t *corner_image; - ply_window_t *window; + ply_list_t *views; - ply_entry_t *entry; - ply_animation_t *animation; - ply_progress_animation_t *progress_animation; - ply_label_t *label; ply_boot_splash_display_type_t state; double animation_horizontal_alignment; @@ -109,12 +114,286 @@ struct _ply_boot_splash_plugin uint32_t is_idle : 1; }; -static void add_handlers (ply_boot_splash_plugin_t *plugin); -static void remove_handlers (ply_boot_splash_plugin_t *plugin); static void stop_animation (ply_boot_splash_plugin_t *plugin); static void detach_from_event_loop (ply_boot_splash_plugin_t *plugin); +static view_t * +view_new (ply_boot_splash_plugin_t *plugin, + ply_pixel_display_t *display) +{ + view_t *view; + + view = calloc (1, sizeof (view_t)); + view->plugin = plugin; + view->display = display; + + view->entry = ply_entry_new (plugin->animation_dir); + view->end_animation = ply_animation_new (plugin->animation_dir, + "throbber-"); + view->progress_animation = ply_progress_animation_new (plugin->animation_dir, + "progress-"); + ply_progress_animation_set_transition (view->progress_animation, + plugin->transition, + plugin->transition_duration); + + view->label = ply_label_new (); + + return view; +} + +static void +view_free (view_t *view) +{ + + ply_entry_free (view->entry); + ply_animation_free (view->end_animation); + ply_progress_animation_free (view->progress_animation); + ply_label_free (view->label); + + free (view); +} + +static bool +view_load (view_t *view) +{ + ply_trace ("loading entry"); + if (!ply_entry_load (view->entry)) + return false; + + ply_trace ("loading animation"); + if (!ply_animation_load (view->end_animation)) + return false; + + ply_trace ("loading progress animation"); + if (!ply_progress_animation_load (view->progress_animation)) + return false; + + return true; +} + +static bool +load_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + bool view_loaded; + + view_loaded = false; + node = ply_list_get_first_node (plugin->views); + + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + if (view_load (view)) + view_loaded = true; + + node = next_node; + } + + return view_loaded; +} + +static void +view_redraw (view_t *view) +{ + unsigned long screen_width, screen_height; + + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); + + ply_pixel_display_draw_area (view->display, 0, 0, + screen_width, screen_height); +} + +static void +redraw_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_redraw (view); + + node = next_node; + } +} + +static void +pause_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + ply_pixel_display_pause_updates (view->display); + + node = next_node; + } +} + +static void +unpause_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + ply_pixel_display_unpause_updates (view->display); + + node = next_node; + } +} + +static void +view_start_end_animation (view_t *view, + ply_trigger_t *trigger) +{ + ply_boot_splash_plugin_t *plugin; + + long x, y; + long width, height; + unsigned long screen_width, screen_height; + + plugin = view->plugin; + + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); + width = ply_animation_get_width (view->end_animation); + height = ply_animation_get_height (view->end_animation); + x = plugin->animation_horizontal_alignment * screen_width - width / 2.0; + y = plugin->animation_vertical_alignment * screen_height - height / 2.0; + + ply_animation_start (view->end_animation, + view->display, + trigger, x, y); +} + +static void +view_start_progress_animation (view_t *view) +{ + ply_boot_splash_plugin_t *plugin; + + long x, y; + long width, height; + unsigned long screen_width, screen_height; + + assert (view != NULL); + + plugin = view->plugin; + + plugin->is_idle = false; + + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); + + ply_pixel_display_draw_area (view->display, 0, 0, + screen_width, screen_height); + + if (plugin->mode == PLY_BOOT_SPLASH_MODE_SHUTDOWN) + { + view_start_end_animation (view, NULL); + return; + } + + width = ply_progress_animation_get_width (view->progress_animation); + height = ply_progress_animation_get_height (view->progress_animation); + x = plugin->animation_horizontal_alignment * screen_width - width / 2.0; + y = plugin->animation_vertical_alignment * screen_height - height / 2.0; + ply_progress_animation_show (view->progress_animation, + view->display, x, y); + + ply_pixel_display_draw_area (view->display, x, y, width, height); +} + +static void +view_show_prompt (view_t *view, + const char *prompt) +{ + ply_boot_splash_plugin_t *plugin; + int x, y; + int entry_width, entry_height; + + assert (view != NULL); + + plugin = view->plugin; + + if (ply_entry_is_hidden (view->entry)) + { + unsigned long screen_width, screen_height; + + screen_width = ply_pixel_display_get_width (view->display); + screen_height = ply_pixel_display_get_height (view->display); + + view->box_area.width = ply_image_get_width (plugin->box_image); + view->box_area.height = ply_image_get_height (plugin->box_image); + view->box_area.x = screen_width / 2.0 - view->box_area.width / 2.0; + view->box_area.y = screen_height / 2.0 - view->box_area.height / 2.0; + + view->lock_area.width = ply_image_get_width (plugin->lock_image); + view->lock_area.height = ply_image_get_height (plugin->lock_image); + + entry_width = ply_entry_get_width (view->entry); + entry_height = ply_entry_get_height (view->entry); + + x = screen_width / 2.0 - (view->lock_area.width + entry_width) / 2.0 + view->lock_area.width; + y = screen_height / 2.0 - entry_height / 2.0; + + view->lock_area.x = screen_width / 2.0 - (view->lock_area.width + entry_width) / 2.0; + view->lock_area.y = screen_height / 2.0 - view->lock_area.height / 2.0; + + ply_entry_show (view->entry, plugin->loop, view->display, x, y); + } + + if (prompt != NULL) + { + int label_width, label_height; + + ply_label_set_text (view->label, prompt); + label_width = ply_label_get_width (view->label); + label_height = ply_label_get_height (view->label); + + x = view->box_area.x + view->lock_area.width / 2; + y = view->box_area.y + view->box_area.height; + + ply_label_show (view->label, view->display, x, y); + } +} + +static void +view_hide_prompt (view_t *view) +{ + assert (view != NULL); + + ply_entry_hide (view->entry); + ply_label_hide (view->label); +} + static ply_boot_splash_plugin_t * create_plugin (ply_key_file_t *key_file) { @@ -142,8 +421,6 @@ create_plugin (ply_key_file_t *key_file) plugin->corner_image = ply_image_new (image_path); free (image_path); - plugin->entry = ply_entry_new (image_dir); - plugin->label = ply_label_new (); plugin->animation_dir = image_dir; alignment = ply_key_file_get_value (key_file, "two-step", "HorizontalAlignment"); @@ -160,7 +437,6 @@ create_plugin (ply_key_file_t *key_file) plugin->animation_vertical_alignment = .5; free (alignment); - plugin->transition = PLY_PROGRESS_ANIMATION_TRANSITION_NONE; transition = ply_key_file_get_value (key_file, "two-step", "Transition"); if (transition != NULL) @@ -199,17 +475,42 @@ create_plugin (ply_key_file_t *key_file) free (color); + plugin->views = ply_list_new (); + return plugin; } static void +free_views (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_free (view); + ply_list_remove_node (plugin->views, node); + + node = next_node; + } + + ply_list_free (plugin->views); + plugin->views = NULL; +} + +static void destroy_plugin (ply_boot_splash_plugin_t *plugin) { if (plugin == NULL) return; - remove_handlers (plugin); - if (plugin->loop != NULL) { stop_animation (plugin); @@ -226,86 +527,66 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin) if (plugin->corner_image != NULL) ply_image_free (plugin->corner_image); - ply_entry_free (plugin->entry); - ply_animation_free (plugin->animation); - ply_progress_animation_free (plugin->progress_animation); - ply_label_free (plugin->label); + free_views (plugin); free (plugin); } static void -draw_background (ply_boot_splash_plugin_t *plugin, - ply_frame_buffer_area_t *area) +start_end_animation (ply_boot_splash_plugin_t *plugin, + ply_trigger_t *trigger) { - ply_frame_buffer_area_t screen_area; - if (area == NULL) + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) { - ply_frame_buffer_get_size (plugin->frame_buffer, &screen_area); - area = &screen_area; - } + ply_list_node_t *next_node; + view_t *view; - ply_window_erase_area (plugin->window, area->x, area->y, - area->width, area->height); -} + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); -static void -begin_animation (ply_boot_splash_plugin_t *plugin, - ply_trigger_t *trigger) -{ - long width, height; - ply_frame_buffer_area_t area; - ply_frame_buffer_get_size (plugin->frame_buffer, &area); - width = ply_animation_get_width (plugin->animation); - height = ply_animation_get_height (plugin->animation); - ply_animation_start (plugin->animation, - plugin->loop, - plugin->window, - trigger, - plugin->animation_horizontal_alignment * area.width - width / 2.0, - plugin->animation_vertical_alignment * area.height - height / 2.0); + ply_progress_animation_hide (view->progress_animation); + ply_trigger_ignore_next_pull (trigger); + view_start_end_animation (view, trigger); + + node = next_node; + } + ply_trigger_pull (trigger, NULL); } static void -start_animation (ply_boot_splash_plugin_t *plugin) +start_progress_animation (ply_boot_splash_plugin_t *plugin) { - - long width, height; - ply_frame_buffer_area_t area; - assert (plugin != NULL); - assert (plugin->loop != NULL); + ply_list_node_t *node; if (plugin->is_animating) return; - plugin->is_idle = false; - - draw_background (plugin, NULL); - - if (plugin->mode == PLY_BOOT_SPLASH_MODE_SHUTDOWN) + node = ply_list_get_first_node (plugin->views); + while (node != NULL) { - begin_animation (plugin, NULL); - return; - } + ply_list_node_t *next_node; + view_t *view; - ply_frame_buffer_get_size (plugin->frame_buffer, &area); + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - width = ply_progress_animation_get_width (plugin->progress_animation); - height = ply_progress_animation_get_height (plugin->progress_animation); - ply_progress_animation_show (plugin->progress_animation, - plugin->window, - plugin->animation_horizontal_alignment * area.width - width / 2.0, - plugin->animation_vertical_alignment * area.height - height / 2.0); + view_start_progress_animation (view); - plugin->is_animating = true; + node = next_node; + } - ply_window_draw_area (plugin->window, 0, 0, area.width, area.height); + plugin->is_animating = true; } static void stop_animation (ply_boot_splash_plugin_t *plugin) { + ply_list_node_t *node; + assert (plugin != NULL); assert (plugin->loop != NULL); @@ -314,29 +595,20 @@ stop_animation (ply_boot_splash_plugin_t *plugin) plugin->is_animating = false; - ply_progress_animation_hide (plugin->progress_animation); - ply_animation_stop (plugin->animation); - -#ifdef ENABLE_FADE_OUT - for (i = 0; i < 10; i++) + node = ply_list_get_first_node (plugin->views); + while (node != NULL) { - ply_frame_buffer_fill_with_hex_color_at_opacity (plugin->frame_buffer, NULL, - PLYMOUTH_BACKGROUND_COLOR, - .1 + .1 * i); - } + ply_list_node_t *next_node; + view_t *view; - ply_frame_buffer_fill_with_hex_color (plugin->frame_buffer, NULL, - PLYMOUTH_BACKGROUND_COLOR); + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - for (i = 0; i < 20; i++) - { - ply_frame_buffer_fill_with_color (plugin->frame_buffer, NULL, - 0.0, 0.0, 0.0, .05 + .05 * i); - } + ply_progress_animation_hide (view->progress_animation); + ply_animation_stop (view->end_animation); - ply_frame_buffer_fill_with_color (plugin->frame_buffer, NULL, - 0.0, 0.0, 0.0, 1.0); -#endif + node = next_node; + } } static void @@ -344,7 +616,6 @@ on_interrupt (ply_boot_splash_plugin_t *plugin) { ply_event_loop_exit (plugin->loop, 1); stop_animation (plugin); - ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_TEXT); } static void @@ -353,138 +624,144 @@ detach_from_event_loop (ply_boot_splash_plugin_t *plugin) plugin->loop = NULL; } -void -on_keyboard_input (ply_boot_splash_plugin_t *plugin, - const char *keyboard_input, - size_t character_size) +static void +draw_background (view_t *view, + ply_pixel_buffer_t *pixel_buffer, + int x, + int y, + int width, + int height) { -} + ply_boot_splash_plugin_t *plugin; + ply_rectangle_t area; -void -on_backspace (ply_boot_splash_plugin_t *plugin) -{ -} + plugin = view->plugin; -void -on_enter (ply_boot_splash_plugin_t *plugin, - const char *text) -{ + area.x = x; + area.y = y; + area.width = width; + area.height = height; + + if (plugin->background_start_color != plugin->background_end_color) + ply_pixel_buffer_fill_with_gradient (pixel_buffer, &area, + plugin->background_start_color, + plugin->background_end_color); + else + ply_pixel_buffer_fill_with_hex_color (pixel_buffer, &area, + plugin->background_start_color); } -void -on_draw (ply_boot_splash_plugin_t *plugin, +static void +on_draw (view_t *view, + ply_pixel_buffer_t *pixel_buffer, int x, int y, int width, int height) { - ply_frame_buffer_area_t area; + ply_boot_splash_plugin_t *plugin; + ply_rectangle_t area; area.x = x; area.y = y; area.width = width; area.height = height; - ply_frame_buffer_pause_updates (plugin->frame_buffer); - draw_background (plugin, &area); + plugin = view->plugin; + + draw_background (view, pixel_buffer, x, y, width, height); if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY || plugin->state == PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY ) { - ply_entry_draw (plugin->entry); - ply_label_draw (plugin->label); + uint32_t *box_data, *lock_data; + + box_data = ply_image_get_data (plugin->box_image); + ply_pixel_buffer_fill_with_argb32_data (pixel_buffer, + &view->box_area, 0, 0, + box_data); + + ply_entry_draw_area (view->entry, + pixel_buffer, + x, y, width, height); + ply_label_draw_area (view->label, + pixel_buffer, + x, y, width, height); + + lock_data = ply_image_get_data (plugin->lock_image); + ply_pixel_buffer_fill_with_argb32_data (pixel_buffer, + &view->lock_area, 0, 0, + lock_data); } else { - ply_progress_animation_draw (plugin->progress_animation); + if (!ply_progress_animation_is_hidden (view->progress_animation)) + ply_progress_animation_draw_area (view->progress_animation, + pixel_buffer, + x, y, width, height); + else if (!ply_animation_is_stopped (view->end_animation)) + ply_animation_draw_area (view->end_animation, + pixel_buffer, + x, y, width, height); if (plugin->corner_image != NULL) { - ply_frame_buffer_area_t screen_area; - ply_frame_buffer_area_t image_area; + ply_rectangle_t screen_area; + ply_rectangle_t image_area; - ply_frame_buffer_get_size (plugin->frame_buffer, &screen_area); + ply_pixel_buffer_get_size (pixel_buffer, &screen_area); image_area.width = ply_image_get_width (plugin->corner_image); image_area.height = ply_image_get_height (plugin->corner_image); image_area.x = screen_area.width - image_area.width - 20; image_area.y = screen_area.height - image_area.height - 20; - ply_frame_buffer_fill_with_argb32_data (plugin->frame_buffer, &image_area, 0, 0, ply_image_get_data (plugin->corner_image)); + ply_pixel_buffer_fill_with_argb32_data (pixel_buffer, &image_area, 0, 0, ply_image_get_data (plugin->corner_image)); } } - ply_frame_buffer_unpause_updates (plugin->frame_buffer); } -void -on_erase (ply_boot_splash_plugin_t *plugin, - int x, - int y, - int width, - int height) +static void +add_pixel_display (ply_boot_splash_plugin_t *plugin, + ply_pixel_display_t *display) { - ply_frame_buffer_area_t area; + view_t *view; - area.x = x; - area.y = y; - area.width = width; - area.height = height; + view = view_new (plugin, display); - if (plugin->background_start_color != plugin->background_end_color) - ply_frame_buffer_fill_with_gradient (plugin->frame_buffer, &area, - plugin->background_start_color, - plugin->background_end_color); - else - ply_frame_buffer_fill_with_hex_color (plugin->frame_buffer, &area, - plugin->background_start_color); + ply_pixel_display_set_draw_handler (view->display, + (ply_pixel_display_draw_handler_t) + on_draw, view); + ply_list_append_data (plugin->views, view); } static void -add_handlers (ply_boot_splash_plugin_t *plugin) +remove_pixel_display (ply_boot_splash_plugin_t *plugin, + ply_pixel_display_t *display) { - ply_window_add_keyboard_input_handler (plugin->window, - (ply_window_keyboard_input_handler_t) - on_keyboard_input, plugin); - ply_window_add_backspace_handler (plugin->window, - (ply_window_backspace_handler_t) - on_backspace, plugin); - ply_window_add_enter_handler (plugin->window, - (ply_window_enter_handler_t) - on_enter, plugin); + ply_list_node_t *node; - ply_window_set_draw_handler (plugin->window, - (ply_window_draw_handler_t) - on_draw, plugin); - - ply_window_set_erase_handler (plugin->window, - (ply_window_erase_handler_t) - on_erase, plugin); -} + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + view_t *view; + ply_list_node_t *next_node; -static void -remove_handlers (ply_boot_splash_plugin_t *plugin) -{ + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - ply_window_remove_keyboard_input_handler (plugin->window, (ply_window_keyboard_input_handler_t) on_keyboard_input); - ply_window_remove_backspace_handler (plugin->window, (ply_window_backspace_handler_t) on_backspace); - ply_window_remove_enter_handler (plugin->window, (ply_window_enter_handler_t) on_enter); - ply_window_set_draw_handler (plugin->window, NULL, NULL); - ply_window_set_erase_handler (plugin->window, NULL, NULL); -} + if (view->display == display) + { -static void -add_window (ply_boot_splash_plugin_t *plugin, - ply_window_t *window) -{ - plugin->window = window; -} + ply_pixel_display_set_draw_handler (view->display, NULL, NULL); + view_free (view); + ply_list_remove_node (plugin->views, node); + return; + } -static void -remove_window (ply_boot_splash_plugin_t *plugin, - ply_window_t *window) -{ - plugin->window = NULL; + node = next_node; + } } static bool @@ -495,19 +772,9 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, { assert (plugin != NULL); - add_handlers (plugin); - plugin->loop = loop; plugin->mode = mode; - plugin->animation = ply_animation_new (plugin->animation_dir, - "throbber-"); - plugin->progress_animation = ply_progress_animation_new (plugin->animation_dir, - "progress-"); - ply_progress_animation_set_transition (plugin->progress_animation, - plugin->transition, - plugin->transition_duration); - ply_trace ("loading lock image"); if (!ply_image_load (plugin->lock_image)) return false; @@ -527,23 +794,11 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, } } - ply_trace ("loading entry"); - if (!ply_entry_load (plugin->entry)) - return false; - - ply_trace ("loading animation"); - if (!ply_animation_load (plugin->animation)) - return false; - - ply_trace ("loading progress animation"); - if (!ply_progress_animation_load (plugin->progress_animation)) - return false; - - ply_trace ("setting graphics mode"); - if (!ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_GRAPHICS)) - return false; - - plugin->frame_buffer = ply_window_get_frame_buffer (plugin->window); + if (!load_views (plugin)) + { + ply_trace ("couldn't load views"); + return false; + } ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t) detach_from_event_loop, @@ -554,11 +809,8 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, (ply_event_handler_t) on_interrupt, plugin); - ply_window_clear_screen (plugin->window); - ply_window_hide_text_cursor (plugin->window); - ply_trace ("starting boot animation"); - start_animation (plugin); + start_progress_animation (plugin); plugin->is_visible = true; @@ -584,6 +836,28 @@ on_animation_stopped (ply_boot_splash_plugin_t *plugin) } static void +update_progress_animation (ply_boot_splash_plugin_t *plugin, + double percent_done) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + ply_progress_animation_set_percent_done (view->progress_animation, + percent_done); + + node = next_node; + } +} + +static void on_boot_progress (ply_boot_splash_plugin_t *plugin, double duration, double percent_done) @@ -592,15 +866,14 @@ on_boot_progress (ply_boot_splash_plugin_t *plugin, if (percent_done >= SHOW_ANIMATION_PERCENT) { - if (ply_animation_is_stopped (plugin->animation)) + if (plugin->stop_trigger == NULL) { plugin->stop_trigger = ply_trigger_new (&plugin->stop_trigger); ply_trigger_add_handler (plugin->stop_trigger, (ply_trigger_handler_t) on_animation_stopped, plugin); - ply_progress_animation_hide (plugin->progress_animation); - begin_animation (plugin, plugin->stop_trigger); + start_end_animation (plugin, plugin->stop_trigger); } } else @@ -614,11 +887,8 @@ on_boot_progress (ply_boot_splash_plugin_t *plugin, * fraction(time,estimate)=1-2^(-(time^1.45)/estimate) */ percent_done = 1.0 - pow (2.0, -pow (duration, 1.45) / total_duration) * (1.0 - percent_done); - ply_progress_animation_set_percent_done (plugin->progress_animation, - percent_done); + update_progress_animation (plugin, percent_done); } - - ply_progress_animation_draw (plugin->progress_animation); } static void @@ -627,8 +897,6 @@ hide_splash_screen (ply_boot_splash_plugin_t *plugin, { assert (plugin != NULL); - remove_handlers (plugin); - if (plugin->loop != NULL) { stop_animation (plugin); @@ -639,74 +907,52 @@ hide_splash_screen (ply_boot_splash_plugin_t *plugin, detach_from_event_loop (plugin); } - plugin->frame_buffer = NULL; plugin->is_visible = false; - - ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_TEXT); } static void show_password_prompt (ply_boot_splash_plugin_t *plugin, - const char *prompt) + const char *text, + int number_of_bullets) { - ply_frame_buffer_area_t area; - int x, y; - int entry_width, entry_height; - - uint32_t *box_data, *lock_data; + ply_list_node_t *node; - assert (plugin != NULL); - - if (ply_entry_is_hidden (plugin->entry)) + node = ply_list_get_first_node (plugin->views); + while (node != NULL) { - draw_background (plugin, NULL); - - ply_frame_buffer_get_size (plugin->frame_buffer, &area); - plugin->box_area.width = ply_image_get_width (plugin->box_image); - plugin->box_area.height = ply_image_get_height (plugin->box_image); - plugin->box_area.x = area.width / 2.0 - plugin->box_area.width / 2.0; - plugin->box_area.y = area.height / 2.0 - plugin->box_area.height / 2.0; + ply_list_node_t *next_node; + view_t *view; - plugin->lock_area.width = ply_image_get_width (plugin->lock_image); - plugin->lock_area.height = ply_image_get_height (plugin->lock_image); + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - entry_width = ply_entry_get_width (plugin->entry); - entry_height = ply_entry_get_height (plugin->entry); + view_show_prompt (view, text); + ply_entry_set_bullet_count (view->entry, number_of_bullets); - x = area.width / 2.0 - (plugin->lock_area.width + entry_width) / 2.0 + plugin->lock_area.width; - y = area.height / 2.0 - entry_height / 2.0; - - plugin->lock_area.x = area.width / 2.0 - (plugin->lock_area.width + entry_width) / 2.0; - plugin->lock_area.y = area.height / 2.0 - plugin->lock_area.height / 2.0; - - box_data = ply_image_get_data (plugin->box_image); - ply_frame_buffer_fill_with_argb32_data (plugin->frame_buffer, - &plugin->box_area, 0, 0, - box_data); + node = next_node; + } +} - ply_entry_show (plugin->entry, plugin->loop, plugin->window, x, y); +static void +show_prompt (ply_boot_splash_plugin_t *plugin, + const char *prompt, + const char *entry_text) +{ + ply_list_node_t *node; - lock_data = ply_image_get_data (plugin->lock_image); - ply_frame_buffer_fill_with_argb32_data (plugin->frame_buffer, - &plugin->lock_area, 0, 0, - lock_data); - } - else - { - ply_entry_draw (plugin->entry); - } - if (prompt != NULL) + node = ply_list_get_first_node (plugin->views); + while (node != NULL) { - int label_width, label_height; + ply_list_node_t *next_node; + view_t *view; - ply_label_set_text (plugin->label, prompt); - label_width = ply_label_get_width (plugin->label); - label_height = ply_label_get_height (plugin->label); + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); - x = plugin->box_area.x + plugin->lock_area.width / 2; - y = plugin->box_area.y + plugin->box_area.height; + view_show_prompt (view, prompt); + ply_entry_set_text (view->entry, entry_text); - ply_label_show (plugin->label, plugin->window, x, y); + node = next_node; } } @@ -728,27 +974,50 @@ become_idle (ply_boot_splash_plugin_t *plugin, plugin->idle_trigger = idle_trigger; - if (ply_animation_is_stopped (plugin->animation)) + if (plugin->stop_trigger == NULL) { plugin->stop_trigger = ply_trigger_new (&plugin->stop_trigger); ply_trigger_add_handler (plugin->stop_trigger, (ply_trigger_handler_t) on_animation_stopped, plugin); - ply_progress_animation_hide (plugin->progress_animation); - begin_animation (plugin, plugin->stop_trigger); + start_end_animation (plugin, plugin->stop_trigger); + } +} + +static void +hide_prompt (ply_boot_splash_plugin_t *plugin) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (plugin->views); + while (node != NULL) + { + ply_list_node_t *next_node; + view_t *view; + + view = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (plugin->views, node); + + view_hide_prompt (view); + + node = next_node; } } static void display_normal (ply_boot_splash_plugin_t *plugin) { + pause_views (plugin); if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_NORMAL) { plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL; - ply_entry_hide (plugin->entry); - start_animation (plugin); + hide_prompt (plugin); + start_progress_animation (plugin); + + redraw_views (plugin); } + unpause_views (plugin); } static void @@ -756,13 +1025,14 @@ display_password (ply_boot_splash_plugin_t *plugin, const char *prompt, int bullets) { + pause_views (plugin); if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL) - { - stop_animation (plugin); - } + stop_animation (plugin); + plugin->state = PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY; - show_password_prompt (plugin, prompt); - ply_entry_set_bullet_count (plugin->entry, bullets); + show_password_prompt (plugin, prompt, bullets); + redraw_views (plugin); + unpause_views (plugin); } static void @@ -770,14 +1040,14 @@ display_question (ply_boot_splash_plugin_t *plugin, const char *prompt, const char *entry_text) { + pause_views (plugin); if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL) - { - stop_animation (plugin); - } + stop_animation (plugin); plugin->state = PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY; - show_password_prompt (plugin, prompt); - ply_entry_set_text (plugin->entry, entry_text); + show_prompt (plugin, prompt, entry_text); + redraw_views (plugin); + unpause_views (plugin); } ply_boot_splash_plugin_interface_t * @@ -787,8 +1057,8 @@ ply_boot_splash_plugin_get_interface (void) { .create_plugin = create_plugin, .destroy_plugin = destroy_plugin, - .add_window = add_window, - .remove_window = remove_window, + .add_pixel_display = add_pixel_display, + .remove_pixel_display = remove_pixel_display, .show_splash_screen = show_splash_screen, .update_status = update_status, .on_boot_progress = on_boot_progress, @@ -803,4 +1073,4 @@ ply_boot_splash_plugin_get_interface (void) return &plugin_interface; } -/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ +/* 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/tests/Makefile.am b/src/tests/Makefile.am index e0c4242d..bd4e4760 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -9,7 +9,6 @@ TESTS = if ENABLE_TESTS include $(srcdir)/ply-boot-server-test.am include $(srcdir)/ply-boot-splash-test.am -include $(srcdir)/ply-window-test.am endif noinst_PROGRAMS = $(TESTS) diff --git a/src/tests/ply-boot-splash-test.am b/src/tests/ply-boot-splash-test.am index ef79719c..3af7bd54 100644 --- a/src/tests/ply-boot-splash-test.am +++ b/src/tests/ply-boot-splash-test.am @@ -9,7 +9,19 @@ ply_boot_splash_test_LDADD = $(PLYMOUTH_LIBS) ../libply/libply.la ply_boot_splash_test_SOURCES = \ $(srcdir)/../libplybootsplash/ply-boot-splash-plugin.h \ - $(srcdir)/../libplybootsplash/ply-window.h \ - $(srcdir)/../libplybootsplash/ply-window.c \ + $(srcdir)/../libplybootsplash/ply-console.h \ + $(srcdir)/../libplybootsplash/ply-console.c \ + $(srcdir)/../libplybootsplash/ply-keyboard.h \ + $(srcdir)/../libplybootsplash/ply-keyboard.c \ + $(srcdir)/../libplybootsplash/ply-pixel-buffer.h \ + $(srcdir)/../libplybootsplash/ply-pixel-buffer.c \ + $(srcdir)/../libplybootsplash/ply-pixel-display.h \ + $(srcdir)/../libplybootsplash/ply-pixel-display.c \ + $(srcdir)/../libplybootsplash/ply-renderer.h \ + $(srcdir)/../libplybootsplash/ply-renderer.c \ + $(srcdir)/../libplybootsplash/ply-terminal.h \ + $(srcdir)/../libplybootsplash/ply-terminal.c \ + $(srcdir)/../libplybootsplash/ply-text-display.h \ + $(srcdir)/../libplybootsplash/ply-text-display.c \ $(srcdir)/../libplybootsplash/ply-boot-splash.h \ $(srcdir)/../libplybootsplash/ply-boot-splash.c diff --git a/src/tests/ply-window-test.am b/src/tests/ply-window-test.am deleted file mode 100644 index 2a4090f5..00000000 --- a/src/tests/ply-window-test.am +++ /dev/null @@ -1,8 +0,0 @@ -TESTS += ply-window-test - -ply_window_test_CFLAGS = $(PLYMOUTH_CFLAGS) -DPLY_WINDOW_ENABLE_TEST -ply_window_test_LDADD = $(PLYMOUTH_LIBS) ../libply/libply.la - -ply_window_test_SOURCES = \ - $(srcdir)/../libplybootsplash/ply-window.h \ - $(srcdir)/../libplybootsplash/ply-window.c |