[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.
This commit is contained in:
Ray Strode 2009-09-28 18:03:11 -04:00
commit 3fe3aabc7b
85 changed files with 11846 additions and 5544 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)
{

View file

@ -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,

File diff suppressed because it is too large Load diff

View file

@ -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: */

294
src/libply/ply-rectangle.c Normal file
View file

@ -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: */

105
src/libply/ply-rectangle.h Normal file
View file

@ -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: */

390
src/libply/ply-region.c Normal file
View file

@ -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: */

View file

@ -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: */

View file

@ -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

View file

@ -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: */

View file

@ -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;
}
@ -131,6 +133,12 @@ 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)
@ -138,6 +146,13 @@ ply_trigger_pull (ply_trigger_t *trigger,
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)

View file

@ -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

View file

@ -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: */

View file

@ -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 */

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)
{

View file

@ -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

View file

@ -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,

View file

@ -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;
}
void
ply_boot_splash_add_window (ply_boot_splash_t *splash,
ply_window_t *window)
static void
refresh_displays (ply_boot_splash_t *splash)
{
splash->plugin_interface->add_window (splash->plugin, window);
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_remove_window (ply_boot_splash_t *splash,
ply_window_t *window)
ply_boot_splash_set_keyboard (ply_boot_splash_t *splash,
ply_keyboard_t *keyboard)
{
splash->plugin_interface->remove_window (splash->plugin, window);
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_text_display (ply_boot_splash_t *splash,
ply_text_display_t *display)
{
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_text_display (ply_boot_splash_t *splash,
ply_text_display_t *display)
{
ply_list_remove_data (splash->text_displays, display);
if (splash->plugin_interface->remove_pixel_display == NULL)
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);
free(tty_name);
ply_window_attach_to_event_loop (state.window, state.loop);
console = ply_console_new ();
if (!ply_window_open (state.window))
if (!ply_console_open (console))
{
perror ("could not open terminal");
perror ("could not open console");
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);
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);
if (!ply_renderer_open (renderer))
{
perror ("could not open renderer /dev/fb");
ply_renderer_free (renderer);
return errno;
}
keyboard = ply_keyboard_new_for_renderer (renderer);
ply_keyboard_add_escape_handler (keyboard,
(ply_keyboard_escape_handler_t) on_quit, &state);
state.buffer = ply_buffer_new ();
state.splash = ply_boot_splash_new (theme_path, PLYMOUTH_PLUGIN_PATH, state.buffer);
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);

View file

@ -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);

View file

@ -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 */

View file

@ -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 */

View file

@ -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->frame_buffer = NULL;
entry->window = NULL;
entry->loop = NULL;
entry->is_hidden = true;
ply_entry_draw (entry);
entry->display = NULL;
entry->loop = NULL;
}
bool

View file

@ -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);

View file

@ -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: */

View file

@ -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 */

View file

@ -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 */

View file

@ -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,

View file

@ -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;
}
label->plugin_interface->draw_control (label->control);
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,
buffer,
x, y, width, height);
}
void

View file

@ -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,

View file

@ -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 */

View file

@ -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: */

View file

@ -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 */

View file

@ -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 */

View file

@ -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
{
if (progress_animation->transition == PLY_PROGRESS_ANIMATION_TRANSITION_FADE_OVER)
fade_out_opacity = 1.0;
else
fade_out_opacity = 1.0 - fade_percentage;
ply_rectangle_t fill_area;
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);
previous_frame_data = ply_image_get_data (frames[frame_number - 1]);
if (progress_animation->transition == PLY_PROGRESS_ANIMATION_TRANSITION_FADE_OVER)
{
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]);
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;
if (progress_animation->frame_area.width > 0)
draw_background (progress_animation);
progress_animation->frame_buffer = NULL;
progress_animation->window = NULL;
progress_animation->is_hidden = true;
if (progress_animation->frame_area.width > 0)
{
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->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

View file

@ -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);

View file

@ -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;
@ -96,55 +93,68 @@ ply_progress_bar_free (ply_progress_bar_t *progress_bar)
free (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_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;
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 */
}
void
ply_progress_bar_draw (ply_progress_bar_t *progress_bar)
{
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,
0xffffff); /* white */
ply_frame_buffer_unpause_updates (progress_bar->frame_buffer);
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_window_t *window,
long x,
long y)
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

View file

@ -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);

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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;
}

View file

@ -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,

View file

@ -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)
{

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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: */

View file

@ -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);
@ -460,47 +467,6 @@ on_error (state_t *state)
state->number_of_errors++;
}
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)
{
@ -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;
ply_pixel_display_t *display;
next_node = ply_list_get_next_node (state->windows, node);
next_node = ply_list_get_next_node (state->pixel_displays, node);
display = ply_list_node_get_data (node);
ply_pixel_display_free (display);
window = ply_list_node_get_data (node);
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_display = ply_list_get_length (state->pixel_displays) > 0 ||
ply_list_get_length (state->text_displays) > 0;
has_window = has_open_window (state);
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)
{
ply_window_t *window;
state->keyboard = keyboard;
ply_trace ("creating window on %s", tty_name != NULL? tty_name : "active vt");
window = ply_window_new (tty_name);
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_terminal_t *terminal;
ply_text_display_t *display;
ply_keyboard_t *keyboard;
ply_window_attach_to_event_loop (window, state->loop);
ply_trace ("adding display and keyboard for %s", tty_name);
return window;
terminal = ply_terminal_new (tty_name);
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)

View file

@ -1,3 +1,3 @@
SUBDIRS = controls splash
SUBDIRS = controls splash renderers
MAINTAINERCLEANFILES = Makefile.in

View file

@ -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;
return (long) ((double) height / PANGO_SCALE)+1;
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;
}
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)
{
ply_window_erase_area (label->window,
label->area.x, label->area.y,
label->area.width, label->area.height);
}
void
draw_control (ply_label_plugin_control_t *label)
size_control (ply_label_plugin_control_t *label)
{
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_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,
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;
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->frame_buffer = NULL;
label->window = NULL;
label->loop = 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->display = NULL;
label->loop = NULL;
}
bool

View file

@ -0,0 +1,2 @@
SUBDIRS = frame-buffer drm
MAINTAINERCLEANFILES = Makefile.in

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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

View file

@ -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 */

View file

@ -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)
add_text_display (ply_boot_splash_plugin_t *plugin,
ply_text_display_t *display)
{
int fd;
size_t size;
view_t *view;
ply_window_set_mode (window, PLY_WINDOW_MODE_TEXT);
view = view_new (plugin, display);
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)
{
}
void
on_backspace (ply_boot_splash_plugin_t *plugin)
{
}
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);
view = ply_list_node_get_data (node);
next_node = ply_list_get_next_node (plugin->views, node);
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);
}
if (view->display == display)
{
ply_list_remove_node (plugin->views, node);
return;
}
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);
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));
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 ("*"));
if (prompt)
write_on_views (plugin,
prompt,
strlen (prompt));
else
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,

File diff suppressed because it is too large Load diff

View file

@ -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
struct _ply_boot_splash_plugin
typedef struct
{
ply_event_loop_t *loop;
ply_boot_splash_mode_t mode;
ply_frame_buffer_t *frame_buffer;
ply_window_t *window;
char *script_filename;
char *image_dir;
ply_boot_splash_plugin_t *plugin;
ply_pixel_display_t *display;
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;
} view_t;
struct _ply_boot_splash_plugin
{
ply_event_loop_t *loop;
ply_boot_splash_mode_t mode;
ply_list_t *views;
char *script_filename;
char *image_dir;
script_op_t *script_main_op;
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);
/* 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);
script_lib_plymouth_on_keyboard_input (view->script_state,
view->script_plymouth_lib,
keyboard_string);
}
}
static void
on_backspace (ply_boot_splash_plugin_t *plugin)
{}
static void
on_enter (ply_boot_splash_plugin_t *plugin,
const char *text)
{}
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)
{}
static void
on_erase (ply_boot_splash_plugin_t *plugin,
int x,
int y,
int width,
int height)
{}
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);
script_lib_sprite_draw_area (view->script_sprite_lib,
pixel_buffer,
x, y, width, height);
}
static void
remove_handlers (ply_boot_splash_plugin_t *plugin)
set_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_add_input_handler (keyboard,
(ply_keyboard_input_handler_t)
on_keyboard_input, plugin);
}
static void
add_window (ply_boot_splash_plugin_t *plugin,
ply_window_t *window)
unset_keyboard (ply_boot_splash_plugin_t *plugin,
ply_keyboard_t *keyboard)
{
plugin->window = window;
ply_keyboard_remove_input_handler (keyboard,
(ply_keyboard_input_handler_t)
on_keyboard_input);
}
static void
remove_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 = NULL;
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_pixel_display (ply_boot_splash_plugin_t *plugin,
ply_pixel_display_t *display)
{
ply_list_node_t *node;
node = ply_list_get_first_node (plugin->views);
while (node != NULL)
{
view_t *view;
ply_list_node_t *next_node;
view = ply_list_node_get_data (node);
next_node = ply_list_get_next_node (plugin->views, node);
if (view->display == display)
{
ply_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,

View file

@ -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;
}

View file

@ -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 */

File diff suppressed because it is too large Load diff

View file

@ -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;
}
@ -101,6 +336,31 @@ detach_from_event_loop (ply_boot_splash_plugin_t *plugin)
ply_trace ("detaching from event loop");
}
static void
free_views (ply_boot_splash_plugin_t *plugin)
{
ply_list_node_t *node;
node = ply_list_get_first_node (plugin->views);
while (node != NULL)
{
ply_list_node_t *next_node;
view_t *view;
view = ply_list_node_get_data (node);
next_node = ply_list_get_next_node (plugin->views, node);
view_free (view);
ply_list_remove_node (plugin->views, node);
node = next_node;
}
ply_list_free (plugin->views);
plugin->views = NULL;
}
static void
destroy_plugin (ply_boot_splash_plugin_t *plugin)
{
@ -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;
window_width = ply_window_get_number_of_text_columns (plugin->window);
window_height = ply_window_get_number_of_text_rows (plugin->window);
node = ply_list_get_first_node (plugin->views);
while (node != NULL)
{
ply_list_node_t *next_node;
view_t *view;
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 = ply_list_node_get_data (node);
next_node = ply_list_get_next_node (plugin->views, node);
write (STDOUT_FILENO, plugin->message, strlen (plugin->message));
view_show_message (view);
node = next_node;
}
}
static void
start_animation (ply_boot_splash_plugin_t *plugin)
{
ply_list_node_t *node;
assert (plugin != NULL);
assert (plugin->loop != NULL);
redraw_views (plugin);
if (plugin->message != NULL)
show_message (plugin);
if (plugin->is_animating)
return;
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;
ply_text_progress_bar_hide (plugin->progress_bar);
view = ply_list_node_get_data (node);
next_node = ply_list_get_next_node (plugin->views, node);
ply_text_progress_bar_hide (view->progress_bar);
node = next_node;
}
redraw_views (plugin);
}
static void
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;
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
add_handlers (ply_boot_splash_plugin_t *plugin)
remove_text_display (ply_boot_splash_plugin_t *plugin,
ply_text_display_t *display)
{
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_list_node_t *node;
static void
remove_handlers (ply_boot_splash_plugin_t *plugin)
{
node = ply_list_get_first_node (plugin->views);
while (node != NULL)
{
view_t *view;
ply_list_node_t *next_node;
ply_window_set_draw_handler (plugin->window, NULL, NULL);
ply_window_set_erase_handler (plugin->window, NULL, NULL);
view = ply_list_node_get_data (node);
next_node = ply_list_get_next_node (plugin->views, node);
}
if (view->display == display)
{
ply_text_display_set_draw_handler (view->display,
NULL, NULL);
view_free (view);
ply_list_remove_node (plugin->views, node);
return;
}
static void
add_window (ply_boot_splash_plugin_t *plugin,
ply_window_t *window)
{
plugin->window = window;
}
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
@ -361,40 +647,76 @@ display_message (ply_boot_splash_plugin_t *plugin,
start_animation (plugin);
}
static void
show_password_prompt (ply_boot_splash_plugin_t *plugin,
const char *prompt,
int bullets)
{
ply_list_node_t *node;
int i;
char *entered_text;
entered_text = calloc (bullets + 1, sizeof (char));
for (i = 0; i < bullets; i++)
entered_text[i] = '*';
node = ply_list_get_first_node (plugin->views);
while (node != NULL)
{
ply_list_node_t *next_node;
view_t *view;
view = ply_list_node_get_data (node);
next_node = ply_list_get_next_node (plugin->views, node);
view_show_prompt (view, prompt, entered_text);
node = next_node;
}
free (entered_text);
}
static void
show_prompt (ply_boot_splash_plugin_t *plugin,
const char *prompt,
const char *text)
{
ply_list_node_t *node;
node = ply_list_get_first_node (plugin->views);
while (node != NULL)
{
ply_list_node_t *next_node;
view_t *view;
view = ply_list_node_get_data (node);
next_node = ply_list_get_next_node (plugin->views, node);
view_show_prompt (view, prompt, text);
node = next_node;
}
}
static void
display_password (ply_boot_splash_plugin_t *plugin,
const char *prompt,
int bullets)
{
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);
pause_views (plugin);
if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL)
stop_animation (plugin);
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);
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,36 +724,21 @@ 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);
pause_views (plugin);
if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL)
stop_animation (plugin);
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);
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,

View file

@ -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;
ply_window_erase_area (plugin->window, area->x, area->y,
area->width, area->height);
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);
}
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;
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_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,
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;
view = ply_list_node_get_data (node);
next_node = ply_list_get_next_node (plugin->views, node);
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_hex_color (plugin->frame_buffer, NULL,
PLYMOUTH_BACKGROUND_COLOR);
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_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;
if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY ||
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
{
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)
{
ply_frame_buffer_area_t area;
area.x = x;
area.y = y;
area.width = width;
area.height = height;
ply_frame_buffer_fill_with_gradient (plugin->frame_buffer, &area,
PLYMOUTH_BACKGROUND_START_COLOR,
PLYMOUTH_BACKGROUND_END_COLOR);
}
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);
view_t *view;
ply_window_set_draw_handler (plugin->window,
(ply_window_draw_handler_t)
on_draw, plugin);
view = view_new (plugin, display);
ply_window_set_erase_handler (plugin->window,
(ply_window_erase_handler_t)
on_erase, plugin);
ply_pixel_display_set_draw_handler (view->display,
(ply_pixel_display_draw_handler_t)
on_draw, view);
ply_list_append_data (plugin->views, view);
}
static void
remove_handlers (ply_boot_splash_plugin_t *plugin)
remove_pixel_display (ply_boot_splash_plugin_t *plugin,
ply_pixel_display_t *display)
{
ply_list_node_t *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);
}
node = ply_list_get_first_node (plugin->views);
while (node != NULL)
{
view_t *view;
ply_list_node_t *next_node;
static void
add_window (ply_boot_splash_plugin_t *plugin,
ply_window_t *window)
{
plugin->window = window;
}
view = ply_list_node_get_data (node);
next_node = ply_list_get_next_node (plugin->views, node);
static void
remove_window (ply_boot_splash_plugin_t *plugin,
ply_window_t *window)
{
plugin->window = NULL;
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
@ -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_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);
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,
&plugin->lock_area, 0, 0,
lock_data);
node = next_node;
}
else
}
static void
show_prompt (ply_boot_splash_plugin_t *plugin,
const char *prompt,
const char *entry_text)
{
ply_list_node_t *node;
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_show_prompt (view, prompt);
ply_entry_set_text (view->entry, entry_text);
node = next_node;
}
if (prompt != NULL)
{
int label_width, label_height;
ply_label_set_text (plugin->label, prompt);
label_width = ply_label_get_width (plugin->label);
label_height = ply_label_get_height (plugin->label);
x = plugin->box_area.x + plugin->lock_area.width / 2;
y = plugin->box_area.y + plugin->box_area.height;
ply_label_show (plugin->label, plugin->window, x, y);
}
}
static void
@ -585,15 +795,38 @@ become_idle (ply_boot_splash_plugin_t *plugin,
stop_animation (plugin, idle_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_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,

File diff suppressed because it is too large Load diff

View file

@ -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)

View file

@ -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

View file

@ -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