Merge branch 'parsekmsg' into 'main'

Support for displaying logs from /dev/kmsg and the console on the screen, instead of relying on the text on the VT

See merge request plymouth/plymouth!224
This commit is contained in:
Ray Strode 2023-12-02 23:33:26 +00:00
commit 44a2c8e452
23 changed files with 3924 additions and 123 deletions

View file

@ -29,7 +29,7 @@ find -name '*.[ch]' -exec git diff -- {} \; >> before
interdiff -B --no-revert-omitted before after > diff
if [ -n "$(cat diff)" ]; then
if [ -n "$(cat diff | grep -vE '^only in patch[12]:')" ]; then
echo "Uncrustify found style abnormalities" 2>&1
cat diff
exit 1

View file

@ -545,6 +545,35 @@ fi
PLYMOUTH_MODULE_NAME=$(grep "ModuleName *= *" ${PLYMOUTH_SYSROOT}${PLYMOUTH_THEME_DIR}/${PLYMOUTH_THEME_NAME}.plymouth | sed 's/ModuleName *= *//')
PLYMOUTH_IMAGE_DIR=$(grep "ImageDir *= *" ${PLYMOUTH_SYSROOT}${PLYMOUTH_THEME_DIR}/${PLYMOUTH_THEME_NAME}.plymouth | sed 's/ImageDir *= *//')
PLYMOUTH_FONT_PATH=""
PLYMOUTH_FONT=$(grep "\bFont *= *" ${PLYMOUTH_SYSROOT}${PLYMOUTH_THEME_DIR}/${PLYMOUTH_THEME_NAME}.plymouth | sed 's/Font *= *//' | head -1)
if [ ! -z "$PLYMOUTH_FONT" ]; then
PLYMOUTH_FONT_PATH=$(fc-match -f %{file} "$PLYMOUTH_FONT")
if [ ! -z "$PLYMOUTH_FONT_PATH" ]; then
inst "$PLYMOUTH_FONT_PATH" $INITRDDIR
fi
fi
PLYMOUTH_TITLE_FONT_PATH=""
PLYMOUTH_TITLE_FONT=$(grep "\bTitleFont *= *" ${PLYMOUTH_SYSROOT}${PLYMOUTH_THEME_DIR}/${PLYMOUTH_THEME_NAME}.plymouth | sed 's/TitleFont *= *//' | head -1)
if [ ! -z "$PLYMOUTH_TITLE_FONT" ]; then
PLYMOUTH_TITLE_FONT_PATH=$(fc-match -f %{file} "$PLYMOUTH_TITLE_FONT")
if [ ! -z "$PLYMOUTH_TITLE_FONT_PATH" ]; then
inst "$PLYMOUTH_TITLE_FONT_PATH" $INITRDDIR
fi
fi
PLYMOUTH_MONOSPACE_FONT_PATH=""
PLYMOUTH_MONOSPACE_FONT=$(grep "\bMonospaceFont *= *" ${PLYMOUTH_SYSROOT}${PLYMOUTH_THEME_DIR}/${PLYMOUTH_THEME_NAME}.plymouth | sed 's/MonospaceFont *= *//' | head -1)
if [ ! -z "$PLYMOUTH_MONOSPACE_FONT" ]; then
PLYMOUTH_MONOSPACE_FONT_PATH=$(fc-match -f %{file} "$PLYMOUTH_MONOSPACE_FONT")
if [ ! -z "$PLYMOUTH_MONOSPACE_FONT_PATH" ]; then
inst "$PLYMOUTH_MONOSPACE_FONT_PATH" $INITRDDIR
fi
fi
if [ ! -f ${PLYMOUTH_SYSROOT}${PLYMOUTH_PLUGIN_PATH}/${PLYMOUTH_MODULE_NAME}.so ]; then
echo "The default plymouth plugin (${PLYMOUTH_MODULE_NAME}) doesn't exist" >&2
exit 1
@ -563,13 +592,17 @@ if [ "${PLYMOUTH_IMAGE_DIR}" != "${PLYMOUTH_THEME_DIR}" -a -d "${PLYMOUTH_SYSROO
inst_recur "${PLYMOUTH_IMAGE_DIR}"
fi
DefaultFont=$(fc-match -f %{file})
inst "$DefaultFont" $INITRDDIR
DefaultMonospaceFont=$(fc-match -f %{file} monospace)
inst "$DefaultMonospaceFont" $INITRDDIR
if [ -f "${PLYMOUTH_PLUGIN_PATH}/label-freetype.so" ]; then
inst ${PLYMOUTH_PLUGIN_PATH}/label-freetype.so $INITRDDIR
font=$(fc-match -f %{file})
inst "$font" $INITRDDIR
# The label-freetype plugin expects it at this location
mkdir -p $INITRDDIR/usr/share/fonts
ln -s "$font" $INITRDDIR/usr/share/fonts/Plymouth.ttf
ln -s "$DefaultFont" $INITRDDIR/usr/share/fonts/Plymouth.ttf
ln -s "$DefaultMonospaceFont" $INITRDDIR/usr/share/fonts/Plymouth-monospace.ttf
fi
if [ -L ${PLYMOUTH_SYSROOT}${PLYMOUTH_DATADIR}/plymouth/themes/default.plymouth ]; then

View file

@ -2,11 +2,14 @@ libply_splash_core_sources = files(
'ply-boot-splash.c',
'ply-device-manager.c',
'ply-input-device.c',
'ply-kmsg-reader.c',
'ply-keyboard.c',
'ply-pixel-buffer.c',
'ply-pixel-display.c',
'ply-renderer.c',
'ply-rich-text.c',
'ply-terminal.c',
'ply-terminal-emulator.c',
'ply-text-display.c',
'ply-text-progress-bar.c',
'ply-text-step-bar.c',
@ -54,12 +57,15 @@ libply_splash_core_headers = files(
'ply-boot-splash.h',
'ply-device-manager.h',
'ply-input-device.h',
'ply-kmsg-reader.h',
'ply-keyboard.h',
'ply-pixel-buffer.h',
'ply-pixel-display.h',
'ply-renderer-plugin.h',
'ply-renderer.h',
'ply-rich-text.h',
'ply-terminal.h',
'ply-terminal-emulator.h',
'ply-text-display.h',
'ply-text-progress-bar.h',
'ply-text-step-bar.h',

View file

@ -0,0 +1,236 @@
/* ply-kmsg-reader.c - kernel log message reader
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
*/
#include "ply-list.h"
#include "ply-kmsg-reader.h"
#include "ply-terminal-emulator.h"
#include "ply-event-loop.h"
#include "ply-logger.h"
#include "ply-utils.h"
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#ifndef LOG_LINE_MAX
#define LOG_LINE_MAX 8192
#endif
#define from_hex(c) (isdigit (c) ? c - '0' : tolower (c) - 'a' + 10)
size_t
unhexmangle_to_buffer (const char *s,
char *buf,
size_t len)
{
size_t sz = 0;
const char *buf0 = buf;
if (!s)
return 0;
while (*s && sz < len - 1) {
if (*s == '\\' && sz + 3 < len - 1 && s[1] == 'x' &&
isxdigit (s[2]) && isxdigit (s[3])) {
*buf++ = from_hex (s[2]) << 4 | from_hex (s[3]);
s += 4;
sz += 4;
} else {
*buf++ = *s++;
sz++;
}
}
*buf = '\0';
return buf - buf0 + 1;
}
int
handle_kmsg_message (ply_kmsg_reader_t *kmsg_reader,
int fd)
{
ssize_t bytes_read;
char read_buffer[LOG_LINE_MAX] = "";
int current_log_level = LOG_ERR, default_log_level = LOG_WARNING;
ply_get_kmsg_log_levels (&current_log_level,
&default_log_level);
bytes_read = read (fd, read_buffer, sizeof(read_buffer) - 1);
if (bytes_read > 0) {
ply_terminal_style_attributes_t bold_enabled = PLY_TERMINAL_ATTRIBUTE_NO_BOLD;
ply_terminal_color_t color = PLY_TERMINAL_ATTRIBUTE_FOREGROUND_COLOR_OFFSET + PLY_TERMINAL_COLOR_DEFAULT;
char *fields, *field_prefix, *field_sequence, *field_timestamp, *message, *message_substr, *msgptr, *saveptr, *format_begin, *new_message;
int prefix, priority, facility;
uint64_t sequence;
unsigned long long timestamp;
kmsg_message_t *kmsg_message;
fields = strtok_r (read_buffer, ";", &message);
/* Messages end in \n, any following lines are machine readable. Actual multiline messages are expanded with unhexmangle_to_buffer */
msgptr = strchr (message, '\n');
if (*msgptr && *msgptr != '\n')
msgptr--;
unhexmangle_to_buffer (message, (char *) message, msgptr - message + 1);
field_prefix = strtok_r (fields, ",", &fields);
field_sequence = strtok_r (fields, ",", &fields);
field_timestamp = strtok_r (fields, ",", &fields);
prefix = atoi (field_prefix);
sequence = strtoull (field_sequence, NULL, 0);
timestamp = strtoull (field_timestamp, NULL, 0);
if (prefix > 0) {
priority = LOG_PRI (prefix);
facility = LOG_FAC (prefix);
} else {
priority = default_log_level;
facility = LOG_USER;
}
if (priority > current_log_level)
return 0;
if (priority < LOG_ALERT)
bold_enabled = PLY_TERMINAL_ATTRIBUTE_BOLD;
switch (priority) {
case LOG_EMERG:
case LOG_ALERT:
case LOG_CRIT:
case LOG_ERR:
color = PLY_TERMINAL_ATTRIBUTE_FOREGROUND_COLOR_OFFSET + PLY_TERMINAL_COLOR_RED;
break;
case LOG_WARNING:
color = PLY_TERMINAL_ATTRIBUTE_FOREGROUND_COLOR_OFFSET + PLY_TERMINAL_COLOR_BROWN;
break;
case LOG_NOTICE:
color = PLY_TERMINAL_ATTRIBUTE_FOREGROUND_COLOR_OFFSET + PLY_TERMINAL_COLOR_GREEN;
break;
}
asprintf (&format_begin, "\033[0;%i;%im", bold_enabled, color);
message_substr = strtok_r (message, "\n", &saveptr);
while (message_substr != NULL) {
kmsg_message = calloc (1, sizeof(kmsg_message_t));
kmsg_message->priority = priority;
kmsg_message->facility = facility;
kmsg_message->sequence = sequence;
kmsg_message->timestamp = timestamp;
asprintf (&new_message, "%s%s%s", format_begin, message_substr, "\033[0m");
kmsg_message->message = strndup (new_message, strlen (new_message));
ply_trigger_pull (kmsg_reader->kmsg_trigger, kmsg_message);
ply_list_append_data (kmsg_reader->kmsg_messages, kmsg_message);
free (new_message);
message_substr = strtok_r (NULL, "\n", &saveptr);
}
free (format_begin);
return 0;
} else {
ply_event_loop_stop_watching_fd (ply_event_loop_get_default (), kmsg_reader->fd_watch);
close (kmsg_reader->kmsg_fd);
return -1;
}
}
ply_kmsg_reader_t *
ply_kmsg_reader_new (void)
{
ply_kmsg_reader_t *kmsg_reader = calloc (1, sizeof(ply_kmsg_reader_t));
kmsg_reader->kmsg_trigger = ply_trigger_new (NULL);
kmsg_reader->kmsg_messages = ply_list_new ();
return kmsg_reader;
}
void
ply_kmsg_message_free (kmsg_message_t *kmsg_message)
{
if (kmsg_message == NULL)
return;
free (kmsg_message->message);
free (kmsg_message);
}
void
ply_kmsg_reader_free (ply_kmsg_reader_t *kmsg_reader)
{
ply_list_node_t *node;
kmsg_message_t *kmsg_message;
if (kmsg_reader == NULL)
return;
ply_list_foreach (kmsg_reader->kmsg_messages, node) {
kmsg_message = ply_list_node_get_data (node);
ply_kmsg_message_free (kmsg_message);
}
ply_trigger_free (kmsg_reader->kmsg_trigger);
free (kmsg_reader);
}
void
ply_kmsg_reader_start (ply_kmsg_reader_t *kmsg_reader)
{
kmsg_reader->kmsg_fd = open ("/dev/kmsg", O_RDWR | O_NONBLOCK);
if (kmsg_reader->kmsg_fd < 0)
return;
kmsg_reader->fd_watch = ply_event_loop_watch_fd (ply_event_loop_get_default (), kmsg_reader->kmsg_fd, PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
(ply_event_handler_t) handle_kmsg_message,
NULL,
kmsg_reader);
}
void
ply_kmsg_reader_stop (ply_kmsg_reader_t *kmsg_reader)
{
if (kmsg_reader->kmsg_fd < 0)
return;
ply_event_loop_stop_watching_fd (ply_event_loop_get_default (),
kmsg_reader->fd_watch);
kmsg_reader->fd_watch = NULL;
close (kmsg_reader->kmsg_fd);
kmsg_reader->kmsg_fd = -1;
}
void
ply_kmsg_reader_watch_for_messages (ply_kmsg_reader_t *kmsg_reader,
ply_kmsg_reader_message_handler_t message_handler,
void *user_data)
{
ply_trigger_add_handler (kmsg_reader->kmsg_trigger,
(ply_trigger_handler_t)
message_handler,
user_data);
}

View file

@ -0,0 +1,64 @@
/* ply-kmsg-reader.h - kernel log message reader
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
*/
#ifndef PLY_KMSG_READER_H
#define PLY_KMSG_READER_H
#include "ply-list.h"
#include "ply-boot-splash.h"
#include <sys/syslog.h>
typedef struct _ply_kmsg_reader ply_kmsg_reader_t;
struct dmesg_name
{
const char *name;
};
typedef struct
{
int priority;
int facility;
unsigned long sequence;
unsigned long long timestamp;
char *message;
} kmsg_message_t;
struct _ply_kmsg_reader
{
int kmsg_fd;
ply_fd_watch_t *fd_watch;
ply_trigger_t *kmsg_trigger;
ply_list_t *kmsg_messages;
};
typedef void (* ply_kmsg_reader_message_handler_t) (void *,
kmsg_message_t *);
#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
ply_kmsg_reader_t *ply_kmsg_reader_new (void);
void ply_kmsg_reader_free (ply_kmsg_reader_t *kmsg_reader);
void ply_kmsg_reader_start (ply_kmsg_reader_t *kmsg_reader);
void ply_kmsg_reader_stop (ply_kmsg_reader_t *kmsg_reader);
void ply_kmsg_reader_watch_for_messages (ply_kmsg_reader_t *kmsg_reader,
ply_kmsg_reader_message_handler_t message_handler,
void *user_data);
#endif //PLY_HIDE_FUNCTION_DECLARATIONS
#endif //PLY_KMSG_READER_H

View file

@ -0,0 +1,254 @@
/* ply-rich-text.c - Text with colors and styles
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
*/
#include "ply-array.h"
#include "ply-rich-text.h"
#include "ply-logger.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <stdio.h>
struct _ply_rich_text_t
{
ply_array_t *characters;
size_t reference_count;
};
ply_rich_text_t *
ply_rich_text_new (void)
{
ply_rich_text_t *rich_text;
rich_text = calloc (1, sizeof(ply_rich_text_t));
rich_text->characters = ply_array_new (PLY_ARRAY_ELEMENT_TYPE_POINTER);
rich_text->reference_count = 1;
return rich_text;
}
void
ply_rich_text_take_reference (ply_rich_text_t *rich_text)
{
rich_text->reference_count++;
}
void
ply_rich_text_drop_reference (ply_rich_text_t *rich_text)
{
rich_text->reference_count--;
if (rich_text->reference_count == 0)
ply_rich_text_free (rich_text);
}
void
ply_rich_text_free (ply_rich_text_t *rich_text)
{
ply_rich_text_character_t **characters;
if (rich_text == NULL)
return;
characters = ply_rich_text_get_characters (rich_text);
characters = (ply_rich_text_character_t **) ply_array_get_pointer_elements (rich_text->characters);
for (size_t i = 0; characters[i] != NULL; i++) {
ply_rich_text_character_free (characters[i]);
}
ply_array_free (rich_text->characters);
free (rich_text);
}
char *
ply_rich_text_get_string (ply_rich_text_t *rich_text,
ply_rich_text_span_t *span)
{
char *string = NULL;
ply_buffer_t *buffer;
ply_rich_text_character_t **characters;
characters = ply_rich_text_get_characters (rich_text);
buffer = ply_buffer_new ();
for (size_t i = span->offset; characters[i] != NULL; i++) {
if (span->range >= 0) {
if (i >= span->offset + span->range)
break;
}
ply_buffer_append_bytes (buffer,
characters[i]->bytes,
characters[i]->length);
}
string = ply_buffer_steal_bytes (buffer);
ply_buffer_free (buffer);
return string;
}
void
ply_rich_text_remove_characters (ply_rich_text_t *rich_text)
{
ply_rich_text_character_t **characters;
if (rich_text == NULL)
return;
characters = ply_rich_text_get_characters (rich_text);
characters = (ply_rich_text_character_t **) ply_array_get_pointer_elements (rich_text->characters);
for (size_t i = 0; characters[i] != NULL; i++) {
ply_rich_text_character_free (characters[i]);
}
ply_array_free (rich_text->characters);
rich_text->characters = ply_array_new (PLY_ARRAY_ELEMENT_TYPE_POINTER);
}
size_t
ply_rich_text_get_length (ply_rich_text_t *rich_text)
{
ply_rich_text_character_t **characters;
size_t length = 0;
characters = ply_rich_text_get_characters (rich_text);
for (length = 0; characters[length] != NULL; length++) {
}
return length;
}
ply_rich_text_character_t *
ply_rich_text_character_new (void)
{
ply_rich_text_character_t *character = calloc (1, sizeof(ply_rich_text_character_t));
character->bytes = NULL;
character->length = 0;
return character;
}
void
ply_rich_text_character_free (ply_rich_text_character_t *character)
{
free (character->bytes);
free (character);
}
ply_rich_text_character_t **
ply_rich_text_get_characters (ply_rich_text_t *rich_text)
{
ply_rich_text_character_t **characters;
characters = (ply_rich_text_character_t **) ply_array_get_pointer_elements (rich_text->characters);
return characters;
}
void
ply_rich_text_remove_character (ply_rich_text_t *rich_text,
size_t character_index)
{
ply_rich_text_character_t **characters;
characters = ply_rich_text_get_characters (rich_text);
if (characters[character_index] == NULL)
return;
ply_rich_text_character_free (characters[character_index]);
characters[character_index] = NULL;
}
void
ply_rich_text_move_character (ply_rich_text_t *rich_text,
size_t old_index,
size_t new_index)
{
ply_rich_text_character_t **characters = ply_rich_text_get_characters (rich_text);
characters[new_index] = characters[old_index];
characters[old_index] = NULL;
}
void
ply_rich_text_set_character (ply_rich_text_t *rich_text,
ply_rich_text_character_style_t style,
size_t character_index,
const char *character_string,
size_t length)
{
ply_rich_text_character_t **characters;
ply_rich_text_character_t *character;
characters = ply_rich_text_get_characters (rich_text);
if (characters[character_index] == NULL) {
character = ply_rich_text_character_new ();
ply_array_add_pointer_element (rich_text->characters, character);
characters = (ply_rich_text_character_t **) ply_array_get_pointer_elements (rich_text->characters);
} else {
character = characters[character_index];
if (character->bytes) {
free (character->bytes);
character->bytes = NULL;
}
}
characters[character_index] = character;
character->bytes = strdup (character_string);
character->length = length;
character->style = style;
}
void
ply_rich_text_iterator_init (ply_rich_text_iterator_t *iterator,
ply_rich_text_t *rich_text,
ply_rich_text_span_t *span)
{
iterator->rich_text = rich_text;
iterator->span = *span;
iterator->current_offset = span->offset;
}
bool
ply_rich_text_iterator_next (ply_rich_text_iterator_t *iterator,
ply_rich_text_character_t **character)
{
ply_rich_text_t *rich_text = iterator->rich_text;
ply_rich_text_span_t *span = &iterator->span;
ply_rich_text_character_t **characters = ply_rich_text_get_characters (rich_text);
if (iterator->current_offset >= span->offset + span->range) {
return false;
}
if (characters[iterator->current_offset] == NULL) {
return false;
}
*character = characters[iterator->current_offset];
iterator->current_offset++;
return true;
}

View file

@ -0,0 +1,94 @@
/* ply-rich-text.h - Text with colors and styles
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
*/
#ifndef PLY_RICH_TEXT_H
#define PLY_RICH_TEXT_H
#include "ply-array.h"
#include "ply-terminal.h"
#include <stddef.h>
#define PLY_UTF8_CHARACTER_MAX_SIZE 5
typedef struct _ply_rich_text_t ply_rich_text_t;
typedef struct
{
ply_terminal_color_t foreground_color;
ply_terminal_color_t background_color;
uint32_t bold_enabled : 1;
uint32_t dim_enabled : 1;
uint32_t italic_enabled : 1;
uint32_t underline_enabled : 1;
uint32_t reverse_enabled : 1;
} ply_rich_text_character_style_t;
typedef struct
{
char *bytes;
size_t length;
ply_rich_text_character_style_t style;
} ply_rich_text_character_t;
typedef struct
{
ssize_t offset;
ssize_t range;
} ply_rich_text_span_t;
typedef struct
{
ply_rich_text_t *rich_text;
ply_rich_text_span_t span;
ssize_t current_offset;
} ply_rich_text_iterator_t;
#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
ply_rich_text_t *ply_rich_text_new (void);
void ply_rich_text_take_reference (ply_rich_text_t *rich_text);
void ply_rich_text_drop_reference (ply_rich_text_t *rich_text);
char *ply_rich_text_get_string (ply_rich_text_t *rich_text,
ply_rich_text_span_t *span);
size_t ply_rich_text_get_length (ply_rich_text_t *rich_text);
void ply_rich_text_set_character (ply_rich_text_t *rich_text,
ply_rich_text_character_style_t style,
size_t index,
const char *bytes,
size_t length);
void ply_rich_text_move_character (ply_rich_text_t *rich_text,
size_t old_index,
size_t new_index);
void ply_rich_text_remove_character (ply_rich_text_t *rich_text,
size_t character_index);
void ply_rich_text_remove_characters (ply_rich_text_t *rich_text);
ply_rich_text_character_t **ply_rich_text_get_characters (ply_rich_text_t *rich_text);
void ply_rich_text_free (ply_rich_text_t *rich_text);
ply_rich_text_character_t *ply_rich_text_character_new (void);
void ply_rich_text_character_free (ply_rich_text_character_t *character);
void ply_rich_text_iterator_init (ply_rich_text_iterator_t *iterator,
ply_rich_text_t *rich_text,
ply_rich_text_span_t *span);
bool ply_rich_text_iterator_next (ply_rich_text_iterator_t *iterator,
ply_rich_text_character_t **character);
#endif //PLY_HIDE_FUNCTION_DECLARATIONS
#endif //PLY_RICH_TEXT_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,70 @@
/* ply-terminal-emulator.h - Minimal Terminal Emulator
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
*/
#ifndef PLY_TERMINAL_EMULATOR_H
#define PLY_TERMINAL_EMULATOR_H
#include "ply-boot-splash.h"
#include "ply-rich-text.h"
#include <sys/syslog.h>
/* Terminal attribute values are determined from the "ECMA-48 Select Graphic Rendition" section from
* https://man7.org/linux/man-pages/man4/console_codes.4.html
*/
#define PLY_TERMINAL_ATTRIBUTE_FOREGROUND_COLOR_OFFSET 30
#define PLY_TERMINAL_ATTRIBUTE_BACKGROUND_COLOR_OFFSET 40
#define PLY_TERMINAL_ATTRIBUTE_FOREGROUND_BRIGHT_OFFSET 90
#define PLY_TERMINAL_ATTRIBUTE_BACKGROUND_BRIGHT_OFFSET 100
typedef struct _ply_terminal_emulator ply_terminal_emulator_t;
typedef enum
{
PLY_TERMINAL_ATTRIBUTE_RESET,
PLY_TERMINAL_ATTRIBUTE_BOLD,
PLY_TERMINAL_ATTRIBUTE_DIM,
PLY_TERMINAL_ATTRIBUTE_ITALIC,
PLY_TERMINAL_ATTRIBUTE_UNDERLINE,
PLY_TERMINAL_ATTRIBUTE_REVERSE = 7,
PLY_TERMINAL_ATTRIBUTE_NO_BOLD = 21,
PLY_TERMINAL_ATTRIBUTE_NO_DIM,
PLY_TERMINAL_ATTRIBUTE_NO_ITALIC,
PLY_TERMINAL_ATTRIBUTE_NO_UNDERLINE,
PLY_TERMINAL_ATTRIBUTE_NO_REVERSE = 27
} ply_terminal_style_attributes_t;
typedef void (*ply_terminal_emulator_output_handler_t) (void *user_data,
const char *output);
#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
ply_terminal_emulator_t *ply_terminal_emulator_new (size_t maximum_line_count);
void ply_terminal_emulator_free (ply_terminal_emulator_t *terminal_emulator);
void ply_terminal_emulator_parse_lines (ply_terminal_emulator_t *terminal_emulator,
const char *text,
size_t size);
ply_rich_text_t *ply_terminal_emulator_get_nth_line (ply_terminal_emulator_t *terminal_emulator,
int line_number);
int ply_terminal_emulator_get_line_count (ply_terminal_emulator_t *terminal_emulator);
void ply_terminal_emulator_convert_boot_buffer (ply_terminal_emulator_t *terminal_emulator,
ply_buffer_t *boot_buffer);
void ply_terminal_emulator_watch_for_output (ply_terminal_emulator_t *terminal_emulator,
ply_terminal_emulator_output_handler_t handler,
void *user_data);
#endif //PLY_HIDE_FUNCTION_DECLARATIONS
#endif //PLY_TERMINAL_EMULATOR_H

View file

@ -1,6 +1,7 @@
libply_splash_graphics_sources = files(
'ply-animation.c',
'ply-capslock-icon.c',
'ply-console-viewer.c',
'ply-entry.c',
'ply-image.c',
'ply-keymap-icon.c',
@ -40,6 +41,7 @@ libply_splash_graphics_dep = declare_dependency(
libply_splash_graphics_headers = files(
'ply-animation.h',
'ply-capslock-icon.h',
'ply-console-viewer.h',
'ply-entry.h',
'ply-image.h',
'ply-keymap-icon.h',

View file

@ -0,0 +1,324 @@
/* ply-console-view.c - console message viewer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
*/
#include <stdlib.h>
#include <assert.h>
#include "ply-label.h"
#include "ply-array.h"
#include "ply-pixel-display.h"
#include "ply-image.h"
#include "ply-kmsg-reader.h"
#include "ply-console-viewer.h"
#include "ply-rich-text.h"
#define TERMINAL_OUTPUT_UPDATE_INTERVAL (1.0 / 60)
struct _ply_console_viewer
{
ply_event_loop_t *loop;
ply_terminal_emulator_t *terminal_emulator;
ply_pixel_display_t *display;
ply_rectangle_t area;
ply_list_t *message_labels;
uint32_t is_hidden : 1;
uint32_t output_queued : 1;
uint32_t needs_redraw : 1;
char *font;
long font_height;
long font_width;
int line_max_chars;
uint32_t text_color;
};
static void update_console_messages (ply_console_viewer_t *console_viewer);
static void on_terminal_emulator_output (ply_console_viewer_t *console_viewer);
bool ply_console_viewer_preferred (void)
{
return !ply_kernel_command_line_has_argument ("plymouth.prefer-fbcon");
}
ply_console_viewer_t *
ply_console_viewer_new (ply_pixel_display_t *display,
const char *font)
{
ply_console_viewer_t *console_viewer;
ply_label_t *console_message_label, *measure_label;
size_t line_count;
console_viewer = calloc (1, sizeof(struct _ply_console_viewer));
console_viewer->message_labels = ply_list_new ();
console_viewer->is_hidden = true;
console_viewer->font = strdup (font);
measure_label = ply_label_new ();
ply_label_set_text (measure_label, " ");
ply_label_set_font (measure_label, console_viewer->font);
console_viewer->text_color = PLY_CONSOLE_VIEWER_LOG_TEXT_COLOR;
console_viewer->font_height = ply_label_get_height (measure_label);
console_viewer->font_width = ply_label_get_width (measure_label);
/* Allow the label to be the size of how many characters can fit in the width of the screeen, minus one for larger fonts that have some size overhead */
console_viewer->line_max_chars = ply_pixel_display_get_width (display) / console_viewer->font_width - 1;
line_count = ply_pixel_display_get_height (display) / console_viewer->font_height;
/* Display at least one line */
if (line_count < 0)
line_count = 1;
ply_label_free (measure_label);
for (size_t label_index = 0; label_index < line_count; label_index++) {
console_message_label = ply_label_new ();
ply_label_set_font (console_message_label, console_viewer->font);
ply_list_append_data (console_viewer->message_labels, console_message_label);
}
console_viewer->terminal_emulator = ply_terminal_emulator_new (line_count);
ply_terminal_emulator_watch_for_output (console_viewer->terminal_emulator,
(ply_terminal_emulator_output_handler_t)
on_terminal_emulator_output,
console_viewer);
return console_viewer;
}
void
ply_console_viewer_free (ply_console_viewer_t *console_viewer)
{
ply_list_node_t *node;
ply_label_t *console_message_label;
ply_list_foreach (console_viewer->message_labels, node) {
console_message_label = ply_list_node_get_data (node);
ply_label_free (console_message_label);
}
ply_list_free (console_viewer->message_labels);
ply_terminal_emulator_free (console_viewer->terminal_emulator);
free (console_viewer->font);
free (console_viewer);
}
static void
update_console_messages (ply_console_viewer_t *console_viewer)
{
ply_list_node_t *node;
ply_label_t *console_message_label;
size_t message_number;
ssize_t characters_left;
ply_rich_text_span_t span;
console_viewer->output_queued = false;
if (console_viewer->terminal_emulator == NULL)
return;
if (console_viewer->display == NULL)
return;
message_number = ply_terminal_emulator_get_line_count (console_viewer->terminal_emulator) - 1;
if (message_number < 0)
return;
ply_pixel_display_pause_updates (console_viewer->display);
node = ply_list_get_first_node (console_viewer->message_labels);
while (node != NULL) {
ply_rich_text_t *line = NULL;
characters_left = 0;
if (message_number >= 0) {
line = ply_terminal_emulator_get_nth_line (console_viewer->terminal_emulator, message_number);
if (line != NULL) {
ply_rich_text_take_reference (line);
characters_left = ply_rich_text_get_length (line);
}
}
span.offset = characters_left;
while (characters_left >= 0) {
console_message_label = ply_list_node_get_data (node);
span.range = span.offset % console_viewer->line_max_chars;
if (span.range == 0)
span.range = console_viewer->line_max_chars;
characters_left = span.offset - span.range - 1;
if (span.offset - span.range >= 0)
span.offset -= span.range;
else
span.offset = 0;
if (line != NULL) {
ply_label_set_rich_text (console_message_label, line, &span);
} else {
ply_label_set_text (console_message_label, "");
}
node = ply_list_get_next_node (console_viewer->message_labels, node);
if (node == NULL)
break;
}
if (line != NULL)
ply_rich_text_drop_reference (line);
if (message_number <= 0)
break;
message_number--;
}
console_viewer->needs_redraw = true;
ply_pixel_display_draw_area (console_viewer->display, 0, 0,
ply_pixel_display_get_width (console_viewer->display),
ply_pixel_display_get_height (console_viewer->display));
ply_pixel_display_unpause_updates (console_viewer->display);
}
void
ply_console_viewer_show (ply_console_viewer_t *console_viewer,
ply_pixel_display_t *display)
{
uint32_t label_color;
size_t label_index;
ply_list_node_t *node;
assert (console_viewer != NULL);
console_viewer->display = display;
console_viewer->is_hidden = false;
label_color = console_viewer->text_color;
label_index = 0;
ply_list_foreach (console_viewer->message_labels, node) {
ply_label_t *console_message_label;
console_message_label = ply_list_node_get_data (node);
ply_label_show (console_message_label, console_viewer->display,
console_viewer->font_width / 2,
(ply_pixel_display_get_height (console_viewer->display) - (console_viewer->font_height * label_index) - console_viewer->font_height));
ply_label_set_hex_color (console_message_label, label_color);
label_index++;
}
update_console_messages (console_viewer);
}
void
ply_console_viewer_draw_area (ply_console_viewer_t *console_viewer,
ply_pixel_buffer_t *buffer,
long x,
long y,
unsigned long width,
unsigned long height)
{
ply_list_node_t *node;
size_t label_index;
ply_label_t *console_message_label;
if (!console_viewer->needs_redraw)
return;
if (console_viewer->is_hidden)
return;
label_index = 0;
ply_list_foreach (console_viewer->message_labels, node) {
console_message_label = ply_list_node_get_data (node);
ply_label_draw_area (console_message_label, buffer,
MAX (x, console_viewer->font_width / 2),
MAX (y, (ply_pixel_display_get_height (console_viewer->display) - (console_viewer->font_height * label_index) - console_viewer->font_height)),
MIN (ply_label_get_width (console_message_label), width),
MIN (height, console_viewer->font_height));
label_index++;
}
console_viewer->needs_redraw = false;
}
void
ply_console_viewer_hide (ply_console_viewer_t *console_viewer)
{
ply_list_node_t *node;
ply_label_t *console_message_label;
if (console_viewer->is_hidden)
return;
console_viewer->is_hidden = true;
ply_list_foreach (console_viewer->message_labels, node) {
console_message_label = ply_list_node_get_data (node);
ply_label_hide (console_message_label);
}
console_viewer->display = NULL;
}
static void
on_terminal_emulator_output (ply_console_viewer_t *console_viewer)
{
if (console_viewer->output_queued)
return;
if (console_viewer->is_hidden)
return;
ply_event_loop_watch_for_timeout (ply_event_loop_get_default (),
TERMINAL_OUTPUT_UPDATE_INTERVAL,
(ply_event_loop_timeout_handler_t)
update_console_messages, console_viewer);
console_viewer->output_queued = true;
}
void
ply_console_viewer_set_text_color (ply_console_viewer_t *console_viewer,
uint32_t hex_color)
{
console_viewer->text_color = hex_color;
}
void
ply_console_viewer_convert_boot_buffer (ply_console_viewer_t *console_viewer,
ply_buffer_t *boot_buffer)
{
ply_terminal_emulator_convert_boot_buffer (console_viewer->terminal_emulator, boot_buffer);
}
void
ply_console_viewer_parse_lines (ply_console_viewer_t *console_viewer,
const char *text,
size_t size)
{
ply_terminal_emulator_parse_lines (console_viewer->terminal_emulator, text, size);
}

View file

@ -0,0 +1,55 @@
/* ply-console-viewer.h - console message viewer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
*/
#ifndef PLY_CONSOLE_VIEWER_H
#define PLY_CONSOLE_VIEWER_H
#include "ply-key-file.h"
#include "ply-list.h"
#include "ply-event-loop.h"
#include "ply-pixel-display.h"
#include "ply-terminal-emulator.h"
typedef struct _ply_console_viewer ply_console_viewer_t;
#define PLY_CONSOLE_VIEWER_LOG_TEXT_COLOR 0xffffffff /* white */
#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
bool ply_console_viewer_preferred (void);
ply_console_viewer_t *ply_console_viewer_new (ply_pixel_display_t *display,
const char *fontdesc);
void ply_console_viewer_free (ply_console_viewer_t *console_viewer);
void ply_console_viewer_show (ply_console_viewer_t *console_viewer,
ply_pixel_display_t *display);
void ply_console_viewer_draw_area (ply_console_viewer_t *console_viewer,
ply_pixel_buffer_t *buffer,
long x,
long y,
unsigned long width,
unsigned long height);
void ply_console_viewer_hide (ply_console_viewer_t *console_viewer);
void ply_console_viewer_set_text_color (ply_console_viewer_t *console_viewer,
uint32_t hex_color);
void ply_console_viewer_convert_boot_buffer (ply_console_viewer_t *console_viewer,
ply_buffer_t *boot_buffer);
void ply_console_viewer_parse_lines (ply_console_viewer_t *console_viewer,
const char *text,
size_t size);
#endif //PLY_HIDE_FUNCTION_DECLARATIONS
#endif //PLY_CONSOLE_VIEWER_H

View file

@ -36,7 +36,7 @@ typedef struct _ply_label_plugin_control ply_label_plugin_control_t;
typedef struct
{
ply_label_plugin_control_t * (*create_control)(void);
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_pixel_display_t *display,
@ -53,6 +53,9 @@ typedef struct
void (*set_text_for_control)(ply_label_plugin_control_t *label,
const char *text);
void (*set_rich_text_for_control)(ply_label_plugin_control_t *label,
ply_rich_text_t *rich_text,
ply_rich_text_span_t *span);
void (*set_font_for_control)(ply_label_plugin_control_t *label,
const char *fontdesc);
void (*set_color_for_control)(ply_label_plugin_control_t *label,

View file

@ -37,6 +37,7 @@
#include "ply-list.h"
#include "ply-logger.h"
#include "ply-utils.h"
#include "ply-array.h"
struct _ply_label
{
@ -46,9 +47,13 @@ struct _ply_label
ply_label_plugin_control_t *control;
char *text;
ply_rich_text_t *rich_text;
ply_rich_text_span_t span;
ply_label_alignment_t alignment;
long width;
char *fontdesc;
char *font;
float red;
float green;
float blue;
@ -86,6 +91,14 @@ ply_label_free (ply_label_t *label)
ply_label_unload_plugin (label);
}
free (label->text);
free (label->font);
if (label->rich_text) {
ply_rich_text_drop_reference (label->rich_text);
label->rich_text = NULL;
}
free (label);
}
@ -98,7 +111,7 @@ ply_label_load_plugin (ply_label_t *label)
label->module_handle = ply_open_module (PLYMOUTH_PLUGIN_PATH "label-pango.so");
/* ...and the FreeType based one after that, it is not a complete substitute (yet). */
/* and the FreeType based one after that, it is not a complete substitute (yet). */
if (label->module_handle == NULL)
label->module_handle = ply_open_module (PLYMOUTH_PLUGIN_PATH "label-freetype.so");
@ -138,17 +151,24 @@ ply_label_load_plugin (ply_label_t *label)
return false;
}
if (label->text != NULL)
label->plugin_interface->set_text_for_control (label->control,
label->text);
if (label->font != NULL)
label->plugin_interface->set_font_for_control (label->control,
label->font);
if (label->text != NULL) {
if (label->rich_text == NULL) {
label->plugin_interface->set_text_for_control (label->control,
label->text);
} else {
label->plugin_interface->set_rich_text_for_control (label->control,
label->rich_text,
&label->span);
}
}
label->plugin_interface->set_alignment_for_control (label->control,
label->alignment);
label->plugin_interface->set_width_for_control (label->control,
label->width);
if (label->fontdesc != NULL)
label->plugin_interface->set_font_for_control (label->control,
label->fontdesc);
label->plugin_interface->set_color_for_control (label->control,
label->red,
label->green,
@ -231,6 +251,11 @@ ply_label_set_text (ply_label_t *label,
free (label->text);
label->text = strdup (text);
if (label->rich_text) {
ply_rich_text_drop_reference (label->rich_text);
label->rich_text = NULL;
}
if (label->plugin_interface == NULL)
return;
@ -238,6 +263,29 @@ ply_label_set_text (ply_label_t *label,
text);
}
void
ply_label_set_rich_text (ply_label_t *label,
ply_rich_text_t *rich_text,
ply_rich_text_span_t *span)
{
free (label->text);
label->text = ply_rich_text_get_string (rich_text, span);
if (label->rich_text)
ply_rich_text_drop_reference (label->rich_text);
label->rich_text = rich_text;
ply_rich_text_take_reference (rich_text);
label->span = *span;
if (label->plugin_interface == NULL)
return;
label->plugin_interface->set_rich_text_for_control (label->control,
label->rich_text,
&label->span);
}
void
ply_label_set_alignment (ply_label_t *label,
ply_label_alignment_t alignment)
@ -265,25 +313,49 @@ ply_label_set_width (ply_label_t *label,
}
/*
* Please see pango documentation, for fontdesc format:
* Please see pango documentation, for font format:
* http://library.gnome.org/devel/pango/stable/pango-Fonts.html#pango-font-description-from-string
* If you pass NULL, it will use default font.
*/
void
ply_label_set_font (ply_label_t *label,
const char *fontdesc)
const char *font)
{
free (label->fontdesc);
if (fontdesc)
label->fontdesc = strdup (fontdesc);
free (label->font);
if (font)
label->font = strdup (font);
else
label->fontdesc = NULL;
label->font = NULL;
if (label->plugin_interface == NULL)
return;
label->plugin_interface->set_font_for_control (label->control,
fontdesc);
font);
}
void
ply_label_set_hex_color (ply_label_t *label,
uint32_t hex_color)
{
double red;
double green;
double blue;
double alpha;
red = ((double) (hex_color & 0xff000000) / 0xff000000);
green = ((double) (hex_color & 0x00ff0000) / 0x00ff0000);
blue = ((double) (hex_color & 0x0000ff00) / 0x0000ff00);
alpha = ((double) (hex_color & 0x000000ff) / 0x000000ff);
if (label->plugin_interface == NULL)
return;
label->plugin_interface->set_color_for_control (label->control,
red,
green,
blue,
alpha);
}
void

View file

@ -29,6 +29,7 @@
#include "ply-event-loop.h"
#include "ply-pixel-buffer.h"
#include "ply-pixel-display.h"
#include "ply-rich-text.h"
typedef struct _ply_label ply_label_t;
@ -60,12 +61,19 @@ bool ply_label_is_hidden (ply_label_t *label);
void ply_label_set_text (ply_label_t *label,
const char *text);
void ply_label_set_rich_text (ply_label_t *label,
ply_rich_text_t *rich_text,
ply_rich_text_span_t *span);
void ply_label_set_alignment (ply_label_t *label,
ply_label_alignment_t alignment);
void ply_label_set_width (ply_label_t *label,
long width);
void ply_label_set_font (ply_label_t *label,
const char *fontdesc);
void ply_label_set_hex_color (ply_label_t *label,
uint32_t hex_color);
void ply_label_set_color (ply_label_t *label,
float red,
float green,

View file

@ -776,6 +776,64 @@ ply_utf8_string_get_length (const char *string,
return count;
}
size_t
ply_utf8_string_get_byte_offset_from_character_offset (const char *string,
size_t character_offset)
{
size_t byte_offset = 0;
size_t i;
for (i = 0; i < character_offset && string[byte_offset] != '\0'; i++) {
byte_offset += ply_utf8_character_get_size (string + byte_offset, PLY_UTF8_CHARACTER_SIZE_MAX);
}
return byte_offset;
}
void
ply_utf8_string_iterator_init (ply_utf8_string_iterator_t *iterator,
const char *string,
ssize_t starting_offset,
ssize_t range)
{
size_t byte_offset;
iterator->character_range = range;
iterator->string = string;
byte_offset = ply_utf8_string_get_byte_offset_from_character_offset (string, starting_offset);
iterator->current_byte_offset = byte_offset;
iterator->number_characters_iterated = 0;
}
bool
ply_utf8_string_iterator_next (ply_utf8_string_iterator_t *iterator,
const char **character,
size_t *size)
{
size_t size_of_current_character;
if (iterator->number_characters_iterated >= iterator->character_range)
return false;
if (iterator->string[iterator->current_byte_offset] == '\0')
return false;
size_of_current_character = ply_utf8_character_get_size (iterator->string + iterator->current_byte_offset,
PLY_UTF8_CHARACTER_SIZE_MAX);
if (size_of_current_character == 0)
return false;
*character = &iterator->string[iterator->current_byte_offset];
*size = size_of_current_character;
iterator->current_byte_offset += size_of_current_character;
iterator->number_characters_iterated++;
return true;
}
char *
ply_get_process_command_line (pid_t pid)
{
@ -939,6 +997,66 @@ int ply_guess_device_scale (uint32_t width,
return get_device_scale (width, height, 0, 0, true);
}
void
ply_get_kmsg_log_levels (int *current_log_level,
int *default_log_level)
{
static double last_update_time = 0;
static int cached_current_log_level = 0;
static int cached_default_log_level = 0;
char log_levels[4096] = "";
double current_time;
char *field, *fields;
int fd;
current_time = ply_get_timestamp ();
if ((current_time - last_update_time) < 1.0) {
*current_log_level = cached_current_log_level;
*default_log_level = cached_default_log_level;
return;
}
ply_trace ("opening /proc/sys/kernel/printk");
fd = open ("/proc/sys/kernel/printk", O_RDONLY);
if (fd < 0) {
ply_trace ("couldn't open it: %m");
return;
}
ply_trace ("reading kmsg log levels");
if (read (fd, log_levels, sizeof(log_levels) - 1) < 0) {
ply_trace ("couldn't read it: %m");
close (fd);
return;
}
close (fd);
field = strtok_r (log_levels, " \t", &fields);
if (field == NULL) {
ply_trace ("Couldn't parse current log level: %m");
return;
}
*current_log_level = atoi (field);
field = strtok_r (NULL, " \t", &fields);
if (field == NULL) {
ply_trace ("Couldn't parse default log level: %m");
return;
}
*default_log_level = atoi (field);
cached_current_log_level = *current_log_level;
cached_default_log_level = *default_log_level;
last_update_time = current_time;
}
static const char *
ply_get_kernel_command_line (void)
{

View file

@ -55,6 +55,14 @@ typedef enum
PLY_UNIX_SOCKET_TYPE_TRIMMED_ABSTRACT
} ply_unix_socket_type_t;
typedef struct
{
const char *string;
ssize_t character_range;
ssize_t current_byte_offset;
ssize_t number_characters_iterated;
} ply_utf8_string_iterator_t;
#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
#define ply_round_to_multiple(n, m) (((n) + (((m) - 1))) & ~((m) - 1))
@ -117,6 +125,16 @@ int ply_utf8_character_get_size (const char *string,
int ply_utf8_string_get_length (const char *string,
size_t n);
size_t ply_utf8_string_get_byte_offset_from_character_offset (const char *string,
size_t character_offset);
void ply_utf8_string_iterator_init (ply_utf8_string_iterator_t *iterator,
const char *string,
ssize_t starting_offset,
ssize_t range);
bool ply_utf8_string_iterator_next (ply_utf8_string_iterator_t *iterator,
const char **character,
size_t *size);
char *ply_get_process_command_line (pid_t pid);
pid_t ply_get_process_parent_pid (pid_t pid);
@ -130,6 +148,9 @@ int ply_get_device_scale (uint32_t width,
int ply_guess_device_scale (uint32_t width,
uint32_t height);
void ply_get_kmsg_log_levels (int *current_log_level,
int *default_log_level);
const char *ply_kernel_command_line_get_string_after_prefix (const char *prefix);
bool ply_kernel_command_line_has_argument (const char *argument);
void ply_kernel_command_line_override (const char *command_line);

View file

@ -55,6 +55,7 @@
#include "ply-trigger.h"
#include "ply-utils.h"
#include "ply-progress.h"
#include "ply-kmsg-reader.h"
#define BOOT_DURATION_FILE PLYMOUTH_TIME_DIRECTORY "/boot-duration"
#define SHUTDOWN_DURATION_FILE PLYMOUTH_TIME_DIRECTORY "/shutdown-duration"
@ -79,6 +80,7 @@ typedef struct
ply_event_loop_t *loop;
ply_boot_server_t *boot_server;
ply_boot_splash_t *boot_splash;
ply_kmsg_reader_t *kmsg_reader;
ply_terminal_session_t *session;
ply_buffer_t *boot_buffer;
ply_progress_t *progress;
@ -93,6 +95,7 @@ typedef struct
ply_trigger_t *deactivate_trigger;
ply_trigger_t *quit_trigger;
ply_trigger_t *kmsg_trigger;
double start_time;
double splash_delay;
@ -157,6 +160,8 @@ static void on_backspace (state_t *state);
static void on_quit (state_t *state,
bool retain_splash,
ply_trigger_t *quit_trigger);
static void on_new_kmsg_message (state_t *state,
kmsg_message_t *kmsg_message);
static bool sh_is_init (state_t *state);
static void cancel_pending_delayed_show (state_t *state);
static void prepare_logging (state_t *state);
@ -1455,6 +1460,22 @@ on_quit (state_t *state,
}
}
void
on_new_kmsg_message (state_t *state,
kmsg_message_t *kmsg_message)
{
long size = strlen (kmsg_message->message) + 1;
char output[size];
strcpy (output, kmsg_message->message);
strcat (output, "\n");
ply_buffer_append_bytes (state->boot_buffer, output, size);
if (state->boot_splash != NULL)
ply_boot_splash_update_output (state->boot_splash, output, size);
}
static bool
on_has_active_vt (state_t *state)
{
@ -1578,15 +1599,16 @@ static void
on_escape_pressed (state_t *state)
{
ply_trace ("escape key pressed");
bool has_vt_consoles = true;
if (state->local_console_terminal != NULL) {
if (!ply_terminal_is_vt (state->local_console_terminal))
return;
has_vt_consoles = false;
} else {
return;
has_vt_consoles = false;
}
if (validate_input (state, "", "\e"))
if (validate_input (state, "", "\e") && has_vt_consoles == true)
toggle_between_splash_and_details (state);
}
@ -1891,6 +1913,18 @@ attach_to_running_session (state_t *state)
return false;
}
if (state->kmsg_reader == NULL) {
ply_trace ("Creating new kmsg reader");
state->kmsg_reader = ply_kmsg_reader_new ();
ply_kmsg_reader_watch_for_messages (state->kmsg_reader,
(ply_kmsg_reader_message_handler_t)
on_new_kmsg_message,
state);
}
ply_kmsg_reader_start (state->kmsg_reader);
#ifdef PLY_ENABLE_SYSTEMD_INTEGRATION
tell_systemd_to_print_details (state);
#endif
@ -1915,6 +1949,9 @@ detach_from_running_session (state_t *state)
tell_systemd_to_stop_printing_details (state);
#endif
ply_trace ("stopping kmsg reader");
ply_kmsg_reader_stop (state->kmsg_reader);
ply_trace ("detaching from terminal session");
ply_terminal_session_detach (state->session);
state->is_redirected = false;

View file

@ -27,6 +27,7 @@
#include <stdint.h>
#include <string.h>
#include <limits.h>
#include <wchar.h>
#include <ft2build.h>
#include FT_FREETYPE_H
@ -39,6 +40,7 @@
/* This is used if fontconfig (fc-match) is not available, like in the initrd. */
#define FONT_FALLBACK "/usr/share/fonts/Plymouth.ttf"
#define MONOSPACE_FONT_FALLBACK "/usr/share/fonts/Plymouth-monospace.ttf"
struct _ply_label_plugin_control
{
@ -52,12 +54,15 @@ struct _ply_label_plugin_control
FT_Face face;
char *text;
ply_rich_text_t *rich_text;
ply_rich_text_span_t span;
float red;
float green;
float blue;
float alpha;
uint32_t is_hidden : 1;
uint32_t is_monospaced : 1;
};
ply_label_plugin_interface_t *ply_label_plugin_get_interface (void);
@ -80,10 +85,45 @@ query_fc_match ()
return fc_match_out;
}
/* Query fontconfig, if available, for the default monospace font. */
static const char *
query_fc_match_monospace ()
{
FILE *fp;
static char fc_match_out[PATH_MAX];
fp = popen ("/usr/bin/fc-match -f %{file} monospace", "r");
if (!fp)
return NULL;
fgets (fc_match_out, sizeof(fc_match_out), fp);
pclose (fp);
return fc_match_out;
}
static FT_Error
set_font_with_fallback (ply_label_plugin_control_t *label,
const char *primary_font_path,
const char *fallback_font_path)
{
FT_Error error;
if (primary_font_path)
error = FT_New_Face (label->library, primary_font_path, 0, &label->face);
if (!fallback_font_path || error) {
printf ("label-ft: trying font fallback\n");
error = FT_New_Face (label->library, fallback_font_path, 0, &label->face);
}
return error;
}
static ply_label_plugin_control_t *
create_control (void)
{
FT_Error error;
int error;
ply_label_plugin_control_t *label;
const char *font_path;
@ -100,19 +140,11 @@ create_control (void)
}
font_path = query_fc_match ();
if (font_path)
error = FT_New_Face (label->library, font_path, 0, &label->face);
if (!font_path || error) {
printf ("label-ft: trying font fallback\n");
font_path = FONT_FALLBACK;
error = FT_New_Face (label->library, font_path, 0, &label->face);
if (error) {
FT_Done_FreeType (label->library);
free (label);
return NULL;
}
error = set_font_with_fallback (label, font_path, FONT_FALLBACK);
if (error) {
FT_Done_FreeType (label->library);
free (label);
return NULL;
}
/* 12pt/96dpi as default */
@ -152,26 +184,44 @@ get_height_of_control (ply_label_plugin_control_t *label)
return label->area.height;
}
static FT_Int
width_of_line (ply_label_plugin_control_t *label,
const char *text)
static bool
load_character (ply_label_plugin_control_t *label,
const char **text)
{
FT_Error error;
size_t character_size;
wchar_t character;
const char *input_text = *text;
character_size = mbrtowc (&character, input_text, PLY_UTF8_CHARACTER_SIZE_MAX, NULL);
if (character_size <= 0) {
character = (wchar_t) *input_text;
character_size = 1;
}
error = FT_Load_Char (label->face, (FT_ULong) character, FT_LOAD_RENDER | FT_LOAD_TARGET_LIGHT);
*text = input_text + character_size;
return !error;
}
static FT_Int
width_of_string (ply_label_plugin_control_t *label,
const char *text)
{
FT_Int width = 0;
FT_Int left_bearing = 0;
while (*text != '\0' && *text != '\n') {
error = FT_Load_Char (label->face, *text, FT_LOAD_RENDER | FT_LOAD_TARGET_LIGHT);
if (!error) {
if (load_character (label, &text)) {
width += label->face->glyph->advance.x >> 6;
left_bearing = label->face->glyph->bitmap_left;
/* We don't "go back" when drawing, so when left bearing is
* negative (like for 'j'), we simply add to the width. */
if (left_bearing < 0)
width += -left_bearing;
++text;
}
}
@ -181,29 +231,65 @@ width_of_line (ply_label_plugin_control_t *label,
static void
size_control (ply_label_plugin_control_t *label)
{
FT_Int width;
const char *text = label->text;
FT_Int character_width, line_width;
ply_rich_text_iterator_t rich_text_iterator;
ply_utf8_string_iterator_t utf8_string_iterator;
bool should_stop = false;
if (label->is_hidden)
if (label->rich_text == NULL && label->text == NULL) {
label->area.width = 0;
label->area.height = 0;
return;
}
if (label->rich_text != NULL) {
ply_rich_text_iterator_init (&rich_text_iterator,
label->rich_text,
&label->span);
} else {
ply_utf8_string_iterator_init (&utf8_string_iterator,
label->text,
0,
ply_utf8_string_get_length (label->text, strlen (label->text)));
}
label->area.width = 0;
label->area.height = 0;
line_width = 0;
/* Go through each line */
while (text && *text) {
width = width_of_line (label, text);
if ((uint32_t) width > label->area.width)
label->area.width = width;
do {
const char *current_character;
label->area.height += (label->face->size->metrics.ascender
- label->face->size->metrics.descender) >> 6;
if (label->rich_text != NULL) {
ply_rich_text_character_t *rich_text_character;
should_stop = !ply_rich_text_iterator_next (&rich_text_iterator,
&rich_text_character);
if (!should_stop)
current_character = rich_text_character->bytes;
} else {
size_t character_size;
text = strchr (text, '\n');
/* skip newline character */
if (text)
++text;
}
should_stop = !ply_utf8_string_iterator_next (&utf8_string_iterator,
&current_character,
&character_size);
}
if (!should_stop) {
character_width = width_of_string (label, current_character);
line_width += character_width;
}
if (should_stop || character_width == 0) {
if ((uint32_t) line_width > label->area.width)
label->area.width = line_width;
line_width = 0;
label->area.height += (label->face->size->metrics.ascender
- label->face->size->metrics.descender) >> 6;
}
} while (!should_stop);
/* If centered, area.x is not the origin anymore */
if ((long) label->area.width < label->width)
@ -216,12 +302,12 @@ trigger_redraw (ply_label_plugin_control_t *label,
{
ply_rectangle_t dirty_area = label->area;
if (label->is_hidden || label->display == NULL)
return;
if (adjust_size)
size_control (label);
if (label->is_hidden || label->display == NULL)
return;
ply_pixel_display_draw_area (label->display,
dirty_area.x, dirty_area.y,
dirty_area.width, dirty_area.height);
@ -233,7 +319,10 @@ draw_bitmap (ply_label_plugin_control_t *label,
ply_rectangle_t target_size,
FT_Bitmap *source,
FT_Int x_start,
FT_Int y_start)
FT_Int y_start,
uint8_t rs,
uint8_t gs,
uint8_t bs)
{
FT_Int x, y, xs, ys;
FT_Int x_end = MIN (x_start + source->width, target_size.width);
@ -243,10 +332,7 @@ draw_bitmap (ply_label_plugin_control_t *label,
(uint32_t) y_start >= target_size.height)
return;
uint8_t rs, gs, bs, rd, gd, bd, ad;
rs = 255 * label->red;
gs = 255 * label->green;
bs = 255 * label->blue;
uint8_t rd, gd, bd, ad;
for (y = y_start, ys = 0; y < y_end; ++y, ++ys) {
for (x = x_start, xs = 0; x < x_end; ++x, ++xs) {
@ -273,6 +359,67 @@ draw_bitmap (ply_label_plugin_control_t *label,
}
}
static void
look_up_rgb_color_from_terminal_color (ply_label_plugin_control_t *label,
ply_terminal_color_t color,
uint8_t *red,
uint8_t *green,
uint8_t *blue)
{
switch (color) {
case PLY_TERMINAL_COLOR_BLACK:
*red = 0x00;
*green = 0x00;
*blue = 0x00;
break;
/* Linux VT Color: 0xaa0000 */
case PLY_TERMINAL_COLOR_RED:
*red = 0xaa;
*green = 0x00;
*blue = 0x00;
break;
/* Linux VT Color: 0x00aa00 */
case PLY_TERMINAL_COLOR_GREEN:
*red = 0x00;
*green = 0xaa;
*blue = 0x00;
break;
/* Linux VT Color: 0xaa5500 */
case PLY_TERMINAL_COLOR_BROWN:
*red = 0xaa;
*green = 0x55;
*blue = 0x00;
break;
/* Linux VT Color: 0x0000aa */
case PLY_TERMINAL_COLOR_BLUE:
*red = 0x00;
*green = 0x00;
*blue = 0xaa;
break;
/* Linux VT Color: 0xaa00aa */
case PLY_TERMINAL_COLOR_MAGENTA:
*red = 0xaa;
*green = 0x00;
*blue = 0xaa;
break;
/* Linux VT Color: 0x00aaaa */
case PLY_TERMINAL_COLOR_CYAN:
*red = 0x00;
*green = 0xaa;
*blue = 0xaa;
break;
/* Linux VT Color: 0xaaaaaa */
case PLY_TERMINAL_COLOR_WHITE:
break;
default:
*red = 255 * label->red;
*green = 255 * label->green;
*blue = 255 * label->blue;
break;
}
}
static void
draw_control (ply_label_plugin_control_t *label,
ply_pixel_buffer_t *pixel_buffer,
@ -281,16 +428,19 @@ draw_control (ply_label_plugin_control_t *label,
unsigned long width,
unsigned long height)
{
FT_Error error;
FT_Vector pen;
FT_GlyphSlot slot;
const char *cur_c;
ply_rich_text_iterator_t rich_text_iterator;
ply_utf8_string_iterator_t utf8_string_iterator;
uint32_t *target;
ply_rectangle_t target_size;
if (label->is_hidden)
return;
if (label->rich_text == NULL &&
label->text == NULL)
return;
/* Check for overlap.
* TODO: Don't redraw everything if only a part should be drawn! */
if (label->area.x > x + (long) width || label->area.y > y + (long) height
@ -300,7 +450,16 @@ draw_control (ply_label_plugin_control_t *label,
slot = label->face->glyph;
cur_c = label->text;
if (label->rich_text != NULL) {
ply_rich_text_iterator_init (&rich_text_iterator,
label->rich_text,
&label->span);
} else {
ply_utf8_string_iterator_init (&utf8_string_iterator,
label->text,
0,
ply_utf8_string_get_length (label->text, strlen (label->text)));
}
target = ply_pixel_buffer_get_argb32_data (pixel_buffer);
ply_pixel_buffer_get_size (pixel_buffer, &target_size);
@ -315,50 +474,77 @@ draw_control (ply_label_plugin_control_t *label,
pen.y += label->face->size->metrics.ascender;
/* Go through each line */
while (*cur_c) {
do {
bool should_stop;
const char *current_character;
uint8_t red, green, blue;
FT_Int extraAdvance = 0, positiveBearingX = 0;
ply_rich_text_character_t *rich_text_character;
red = 255 * label->red;
green = 255 * label->green;
blue = 255 * label->blue;
if (label->rich_text != NULL) {
should_stop = !ply_rich_text_iterator_next (&rich_text_iterator,
&rich_text_character);
if (should_stop)
break;
current_character = rich_text_character->bytes;
look_up_rgb_color_from_terminal_color (label,
rich_text_character->style.foreground_color,
&red,
&green,
&blue);
} else {
size_t character_size;
should_stop = !ply_utf8_string_iterator_next (&utf8_string_iterator,
&current_character,
&character_size);
}
if (*current_character == '\n')
continue;
pen.x = label->area.x << 6;
/* Start at start position (alignment) */
if (label->alignment == PLY_LABEL_ALIGN_CENTER)
pen.x += (label->area.width - width_of_line (label, cur_c)) << 5;
pen.x += (label->area.width - width_of_string (label, current_character)) << 5;
else if (label->alignment == PLY_LABEL_ALIGN_RIGHT)
pen.x += (label->area.width - width_of_line (label, cur_c)) << 6;
pen.x += (label->area.width - width_of_string (label, current_character)) << 6;
while (*cur_c && *cur_c != '\n') {
FT_Int extraAdvance = 0, positiveBearingX = 0;
/* TODO: Unicode support. */
error = FT_Load_Char (label->face, *cur_c,
FT_LOAD_RENDER | FT_LOAD_TARGET_LIGHT);
if (error)
continue;
if (!load_character (label, &current_character))
continue;
/* We consider negative left bearing an increment in size,
* as we draw full character boxes and don't "go back" in
* this plugin. Positive left bearing is treated as usual.
* For definitions see
* https://freetype.org/freetype2/docs/glyphs/glyphs-3.html
*/
if (slot->bitmap_left < 0) {
extraAdvance = -slot->bitmap_left;
} else {
positiveBearingX = slot->bitmap_left;
}
draw_bitmap (label, target, target_size, &slot->bitmap,
(pen.x >> 6) + positiveBearingX,
(pen.y >> 6) - slot->bitmap_top);
/* We consider negative left bearing an increment in size,
* as we draw full character boxes and don't "go back" in
* this plugin. Positive left bearing is treated as usual.
* For definitions see
* https://freetype.org/freetype2/docs/glyphs/glyphs-3.html
*/
if (slot->bitmap_left < 0)
extraAdvance = -slot->bitmap_left;
else
positiveBearingX = slot->bitmap_left;
pen.x += slot->advance.x + extraAdvance;
pen.y += slot->advance.y;
draw_bitmap (label, target, target_size, &slot->bitmap,
(pen.x >> 6) + positiveBearingX,
(pen.y >> 6) - slot->bitmap_top,
red,
green,
blue);
++cur_c;
}
/* skip newline character */
if (*cur_c)
++cur_c;
pen.x += slot->advance.x + extraAdvance;
pen.y += slot->advance.y;
/* Next line */
pen.y += label->face->size->metrics.height;
}
} while (true);
}
static void
@ -381,28 +567,73 @@ set_width_for_control (ply_label_plugin_control_t *label,
}
}
static void
clear_text (ply_label_plugin_control_t *label)
{
free (label->text);
label->text = NULL;
if (label->rich_text != NULL) {
ply_rich_text_drop_reference (label->rich_text);
label->rich_text = NULL;
label->span.offset = 0;
label->span.range = 0;
}
}
static void
set_text_for_control (ply_label_plugin_control_t *label,
const char *text)
{
if (label->text != text) {
free (label->text);
clear_text (label);
label->text = strdup (text);
trigger_redraw (label, true);
}
}
static void
set_rich_text_for_control (ply_label_plugin_control_t *label,
ply_rich_text_t *rich_text,
ply_rich_text_span_t *span)
{
clear_text (label);
label->rich_text = rich_text;
ply_rich_text_take_reference (rich_text);
label->span = *span;
trigger_redraw (label, true);
}
static void
set_font_for_control (ply_label_plugin_control_t *label,
const char *fontdesc)
{
/* Only able to set size */
/* Only able to set size and monospaced/nonmonospaced */
int error = 0;
char *size_str_after;
const char *size_str;
const char *size_str, *font_path;
unsigned long size;
bool size_in_pixels;
if (strstr (fontdesc, "Mono") || strstr (fontdesc, "mono")) {
if (label->is_monospaced == false) {
FT_Done_Face (label->face);
font_path = query_fc_match_monospace ();
error = set_font_with_fallback (label, font_path, MONOSPACE_FONT_FALLBACK);
}
} else {
if (label->is_monospaced == true) {
FT_Done_Face (label->face);
font_path = query_fc_match ();
error = set_font_with_fallback (label, font_path, FONT_FALLBACK);
}
}
if (error)
FT_Done_Face (label->face);
size = 25; /* Default, if not set. */
size_in_pixels = false;
@ -500,6 +731,7 @@ ply_label_plugin_get_interface (void)
.draw_control = draw_control,
.is_control_hidden = is_control_hidden,
.set_text_for_control = set_text_for_control,
.set_rich_text_for_control = set_rich_text_for_control,
.set_alignment_for_control = set_alignment_for_control,
.set_width_for_control = set_width_for_control,
.set_font_for_control = set_font_for_control,

View file

@ -43,6 +43,7 @@
#include <cairo.h>
#include <pango/pangocairo.h>
#include "ply-terminal.h"
#include "ply-pixel-buffer.h"
#include "ply-pixel-display.h"
#include "ply-utils.h"
@ -56,9 +57,10 @@ struct _ply_label_plugin_control
ply_rectangle_t area;
char *text;
char *fontdesc;
char *font;
PangoAlignment alignment;
PangoAttrList *attribute_list;
long width;
float red;
float green;
@ -81,6 +83,7 @@ create_control (void)
label->is_hidden = true;
label->alignment = PANGO_ALIGN_LEFT;
label->width = -1;
label->attribute_list = pango_attr_list_new ();
return label;
}
@ -88,9 +91,19 @@ create_control (void)
static void
destroy_control (ply_label_plugin_control_t *label)
{
GSList *attributes, *attribute;
if (label == NULL)
return;
if (label->attribute_list) {
attributes = pango_attr_list_get_attributes (label->attribute_list);
for (attribute = attributes; attribute; attribute = attribute->next) {
pango_attribute_destroy (attribute->data);
}
pango_attr_list_unref (label->attribute_list);
g_slist_free (attributes);
}
free (label);
}
@ -164,11 +177,114 @@ get_cairo_context_for_sizing (ply_label_plugin_control_t *label)
return cairo_context;
}
void
remove_hexboxes_from_pango_layout (PangoLayout *pango_layout)
{
PangoLayoutIter *iter;
bool hexbox_removed = false;
ply_buffer_t *buffer = ply_buffer_new ();
const char *old_string = pango_layout_get_text (pango_layout);
iter = pango_layout_get_iter (pango_layout);
do {
PangoLayoutRun *run;
PangoGlyphItem *glyph_items;
PangoGlyphString *glyph_string;
run = pango_layout_iter_get_run_readonly (iter);
if (!run)
continue;
glyph_items = (PangoGlyphItem *) run;
glyph_string = glyph_items->glyphs;
if (glyph_string->num_glyphs == 0)
continue;
for (size_t i = 0; i < glyph_string->num_glyphs; i++) {
if (glyph_string->glyphs[i].glyph & PANGO_GLYPH_UNKNOWN_FLAG) {
hexbox_removed = true;
ply_buffer_append (buffer, "%c", '?');
} else {
ply_buffer_append_bytes (buffer, old_string + glyph_items->item->offset, glyph_items->item->length);
}
}
} while (pango_layout_iter_next_run (iter));
pango_layout_iter_free (iter);
if (hexbox_removed) {
const char *new_string = ply_buffer_get_bytes (buffer);
pango_layout_set_text (pango_layout, new_string, -1);
}
ply_buffer_free (buffer);
}
void
look_up_rgb_color_from_terminal_color (ply_terminal_color_t color,
uint16_t *red,
uint16_t *green,
uint16_t *blue)
{
switch (color) {
case PLY_TERMINAL_COLOR_BLACK:
*red = 0x0000;
*green = 0x0000;
*blue = 0x0000;
break;
/* Linux VT Color: 0xaa0000 */
case PLY_TERMINAL_COLOR_RED:
*red = 0xaa00;
*green = 0x0000;
*blue = 0x0000;
break;
/* Linux VT Color: 0x00aa00 */
case PLY_TERMINAL_COLOR_GREEN:
*red = 0x0000;
*green = 0xaa00;
*blue = 0x0000;
break;
/* Linux VT Color: 0xaa5500 */
case PLY_TERMINAL_COLOR_BROWN:
*red = 0xaa00;
*green = 0x5500;
*blue = 0x0000;
break;
/* Linux VT Color: 0x0000aa */
case PLY_TERMINAL_COLOR_BLUE:
*red = 0x0000;
*green = 0x0000;
*blue = 0xaa00;
break;
/* Linux VT Color: 0xaa00aa */
case PLY_TERMINAL_COLOR_MAGENTA:
*red = 0xaa00;
*green = 0x0000;
*blue = 0xaa00;
break;
/* Linux VT Color: 0x00aaaa */
case PLY_TERMINAL_COLOR_CYAN:
*red = 0x0000;
*green = 0xaa00;
*blue = 0xaa00;
break;
/* Linux VT Color: 0xaaaaaa */
case PLY_TERMINAL_COLOR_WHITE:
default:
*red = 0xaa00;
*green = 0xaa00;
*blue = 0xaa00;
break;
}
}
static PangoLayout *
init_pango_text_layout (cairo_t *cairo_context,
char *text,
char *font_description,
PangoAlignment alignment,
PangoAttrList *attribute_list,
long width)
{
PangoLayout *pango_layout;
@ -189,6 +305,7 @@ init_pango_text_layout (cairo_t *cairo_context,
pango_layout_set_width (pango_layout, width * PANGO_SCALE);
pango_layout_set_text (pango_layout, text ?: "", -1);
pango_layout_set_attributes (pango_layout, attribute_list);
pango_cairo_update_layout (cairo_context, pango_layout);
return pango_layout;
@ -213,7 +330,7 @@ size_control (ply_label_plugin_control_t *label,
cairo_context = get_cairo_context_for_sizing (label);
pango_layout = init_pango_text_layout (cairo_context, label->text, label->fontdesc, label->alignment, label->width);
pango_layout = init_pango_text_layout (cairo_context, label->text, label->font, label->alignment, label->attribute_list, label->width);
pango_layout_get_size (pango_layout, &text_width, &text_height);
label->area.width = (long) ((double) text_width / PANGO_SCALE);
@ -244,7 +361,8 @@ draw_control (ply_label_plugin_control_t *label,
cairo_context = get_cairo_context_for_pixel_buffer (label, pixel_buffer, &center_x, &center_y);
pango_layout = init_pango_text_layout (cairo_context, label->text, label->fontdesc, label->alignment, label->width);
pango_layout = init_pango_text_layout (cairo_context, label->text, label->font, label->alignment, label->attribute_list, label->width);
remove_hexboxes_from_pango_layout (pango_layout);
pango_layout_get_size (pango_layout, &text_width, &text_height);
label->area.width = (long) ((double) text_width / PANGO_SCALE);
@ -316,8 +434,24 @@ set_width_for_control (ply_label_plugin_control_t *label,
}
static void
set_text_for_control (ply_label_plugin_control_t *label,
const char *text)
clear_text (ply_label_plugin_control_t *label)
{
GSList *attributes, *attribute;
if (label->attribute_list) {
attributes = pango_attr_list_get_attributes (label->attribute_list);
for (attribute = attributes; attribute; attribute = attribute->next) {
pango_attribute_destroy (attribute->data);
}
pango_attr_list_unref (label->attribute_list);
g_slist_free (attributes);
label->attribute_list = pango_attr_list_new ();
}
}
static void
set_text (ply_label_plugin_control_t *label,
const char *text)
{
ply_rectangle_t dirty_area;
@ -333,19 +467,241 @@ set_text_for_control (ply_label_plugin_control_t *label,
}
}
static void
set_text_for_control (ply_label_plugin_control_t *label,
const char *text)
{
clear_text (label);
set_text (label, text);
}
static void
stage_pango_attribute_for_list (PangoAttrList *attribute_list,
PangoAttribute **staged_attributes,
PangoAttribute *new_attribute)
{
PangoAttrType attribute_type = new_attribute->klass->type;
if (staged_attributes[attribute_type] != NULL) {
if (!pango_attribute_equal (staged_attributes[attribute_type], new_attribute)) {
pango_attr_list_insert (attribute_list, staged_attributes[attribute_type]);
staged_attributes[attribute_type] = new_attribute;
} else {
staged_attributes[attribute_type]->end_index = new_attribute->end_index;
pango_attribute_destroy (new_attribute);
}
} else {
staged_attributes[attribute_type] = new_attribute;
}
}
static void
flush_pango_attributes_to_list (PangoAttrList *attribute_list,
PangoAttribute **staged_attributes)
{
for (size_t i = 0; i <= PANGO_ATTR_FONT_SCALE; i++) {
if (staged_attributes[i] == NULL)
continue;
pango_attr_list_insert (attribute_list, staged_attributes[i]);
staged_attributes[i] = NULL;
}
}
static void
set_rich_text_for_control (ply_label_plugin_control_t *label,
ply_rich_text_t *rich_text,
ply_rich_text_span_t *span)
{
int i;
size_t start_index = 0;
size_t length;
char *string;
PangoAttribute *staged_attributes[PANGO_ATTR_FONT_SCALE + 1] = { NULL };
ply_rich_text_character_t **characters;
clear_text (label);
if (label->attribute_list) {
pango_attr_list_unref (label->attribute_list);
label->attribute_list = pango_attr_list_new ();
}
characters = ply_rich_text_get_characters (rich_text);
for (i = span->offset; characters[i] != NULL; i++) {
PangoAttribute *pango_attribute = NULL;
uint16_t foreground_red, background_red;
uint16_t foreground_green, background_green;
uint16_t foreground_blue, background_blue;
length = characters[i]->length;
PangoWeight bold_style = PANGO_WEIGHT_NORMAL;
PangoStyle italic_style = PANGO_STYLE_NORMAL;
PangoUnderline underline_style = PANGO_UNDERLINE_NONE;
ply_terminal_color_t foreground_color = PLY_TERMINAL_COLOR_DEFAULT;
ply_terminal_color_t background_color = PLY_TERMINAL_COLOR_DEFAULT;
if (!characters[i]->style.reverse_enabled) {
foreground_color = characters[i]->style.foreground_color;
background_color = characters[i]->style.background_color;
} else {
foreground_color = characters[i]->style.background_color;
background_color = characters[i]->style.foreground_color;
/* if no background color is specified, the label is transparent.
* When reversed, and the background color is default
*/
if (background_color == PLY_TERMINAL_COLOR_DEFAULT) {
background_color = PLY_TERMINAL_COLOR_WHITE;
if (foreground_color == PLY_TERMINAL_COLOR_DEFAULT)
foreground_color = PLY_TERMINAL_COLOR_BLACK;
}
}
/* Default to a black background when none is set so bright text is readable on bright backgrounds */
if (background_color == PLY_TERMINAL_COLOR_DEFAULT)
background_color = PLY_TERMINAL_COLOR_BLACK;
look_up_rgb_color_from_terminal_color (foreground_color,
&foreground_red,
&foreground_green,
&foreground_blue);
look_up_rgb_color_from_terminal_color (background_color,
&background_red,
&background_green,
&background_blue);
if (characters[i]->style.bold_enabled && characters[i]->style.dim_enabled) {
/* xterm subtracts 0x44 when bold and dim*/
if (foreground_red > 0x4400) {
foreground_red -= 0x4400;
} else {
foreground_red = 0;
}
if (foreground_green > 0x4400) {
foreground_green -= 0x4400;
} else {
foreground_green = 0;
}
if (foreground_blue > 0x4400) {
foreground_blue -= 0x4400;
} else {
foreground_blue = 0;
}
bold_style = PANGO_WEIGHT_SEMIBOLD;
} else {
if (characters[i]->style.bold_enabled) {
/* Linux VT adds 0x55 when bold */
if (foreground_red + 0x55ff < 0xffff) {
foreground_red += 0x55ff;
} else {
foreground_red = 0xffff;
}
if (foreground_green + 0x55ff < 0xffff) {
foreground_green += 0x55ff;
} else {
foreground_green = 0xffff;
}
if (foreground_blue + 0x55ff < 0xffff) {
foreground_blue += 0x55ff;
} else {
foreground_blue = 0xffff;
}
bold_style = PANGO_WEIGHT_BOLD;
}
if (characters[i]->style.dim_enabled) {
/* xterm subtracts 0x23 when dim */
if (foreground_red > 0x2300) {
foreground_red -= 0x2300;
} else {
foreground_red = 0;
}
if (foreground_green > 0x2300) {
foreground_green -= 0x2300;
} else {
foreground_green = 0;
}
if (foreground_blue > 0x2300) {
foreground_blue -= 0x2300;
} else {
foreground_blue = 0;
}
bold_style = PANGO_WEIGHT_LIGHT;
}
}
if (foreground_color != PLY_TERMINAL_COLOR_DEFAULT) {
pango_attribute = pango_attr_foreground_new (foreground_red, foreground_green, foreground_blue);
pango_attribute->start_index = start_index;
pango_attribute->end_index = start_index + length;
stage_pango_attribute_for_list (label->attribute_list, staged_attributes, pango_attribute);
}
if (background_color != PLY_TERMINAL_COLOR_DEFAULT) {
pango_attribute = pango_attr_background_new (background_red, background_green, background_blue);
pango_attribute->start_index = start_index;
pango_attribute->end_index = start_index + length;
stage_pango_attribute_for_list (label->attribute_list, staged_attributes, pango_attribute);
}
pango_attribute = pango_attr_weight_new (bold_style);
pango_attribute->start_index = start_index;
pango_attribute->end_index = start_index + length;
stage_pango_attribute_for_list (label->attribute_list, staged_attributes, pango_attribute);
if (characters[i]->style.italic_enabled == true)
italic_style = PANGO_STYLE_ITALIC;
pango_attribute = pango_attr_style_new (italic_style);
pango_attribute->start_index = start_index;
pango_attribute->end_index = start_index + length;
stage_pango_attribute_for_list (label->attribute_list, staged_attributes, pango_attribute);
if (characters[i]->style.underline_enabled == true)
underline_style = PANGO_UNDERLINE_SINGLE;
pango_attribute = pango_attr_underline_new (underline_style);
pango_attribute->start_index = start_index;
pango_attribute->end_index = start_index + length;
stage_pango_attribute_for_list (label->attribute_list, staged_attributes, pango_attribute);
start_index += length;
if (i >= span->offset + span->range)
break;
}
flush_pango_attributes_to_list (label->attribute_list, staged_attributes);
string = ply_rich_text_get_string (rich_text, span);
set_text (label, string);
free (string);
}
static void
set_font_for_control (ply_label_plugin_control_t *label,
const char *fontdesc)
const char *font)
{
ply_rectangle_t dirty_area;
if (label->fontdesc != fontdesc) {
if (label->font != font) {
dirty_area = label->area;
free (label->fontdesc);
if (fontdesc)
label->fontdesc = strdup (fontdesc);
free (label->font);
if (font)
label->font = strdup (font);
else
label->fontdesc = NULL;
label->font = NULL;
size_control (label, false);
if (!label->is_hidden && label->display != NULL)
ply_pixel_display_draw_area (label->display,
@ -444,6 +800,7 @@ ply_label_plugin_get_interface (void)
.draw_control = draw_control,
.is_control_hidden = is_control_hidden,
.set_text_for_control = set_text_for_control,
.set_rich_text_for_control = set_rich_text_for_control,
.set_alignment_for_control = set_alignment_for_control,
.set_width_for_control = set_width_for_control,
.set_font_for_control = set_font_for_control,
@ -454,4 +811,3 @@ ply_label_plugin_get_interface (void)
return &plugin_interface;
}

View file

@ -52,6 +52,7 @@
#include "ply-pixel-display.h"
#include "ply-trigger.h"
#include "ply-utils.h"
#include "ply-console-viewer.h"
#include <linux/kd.h>
@ -59,7 +60,6 @@
#define FRAMES_PER_SECOND 30
#endif
typedef enum
{
PLY_BOOT_SPLASH_DISPLAY_NORMAL,
@ -86,6 +86,8 @@ typedef struct
ply_label_t *message_label;
ply_rectangle_t lock_area;
double logo_opacity;
ply_console_viewer_t *console_viewer;
} view_t;
struct _ply_boot_splash_plugin
@ -105,9 +107,25 @@ struct _ply_boot_splash_plugin
uint32_t is_animating : 1;
uint32_t is_visible : 1;
char *monospace_font;
uint32_t plugin_console_messages_updating : 1;
uint32_t should_show_console_messages : 1;
ply_buffer_t *boot_buffer;
uint32_t console_text_color;
};
ply_boot_splash_plugin_interface_t *ply_boot_splash_plugin_get_interface (void);
static bool validate_input (ply_boot_splash_plugin_t *plugin,
const char *entry_text,
const char *add_text);
static void on_boot_output (ply_boot_splash_plugin_t *plugin,
const char *output,
size_t size);
static void toggle_console_messages (ply_boot_splash_plugin_t *plugin);
static void display_console_messages (ply_boot_splash_plugin_t *plugin);
static void hide_console_messages (ply_boot_splash_plugin_t *plugin);
static void unhide_console_messages (ply_boot_splash_plugin_t *plugin);
static void
view_show_prompt (view_t *view,
@ -183,6 +201,20 @@ create_plugin (ply_key_file_t *key_file)
plugin->lock_image = ply_image_new (image_path);
free (image_path);
plugin->plugin_console_messages_updating = false;
plugin->should_show_console_messages = false;
/* Likely only able to set the font if the font is in the initrd */
plugin->monospace_font = ply_key_file_get_value (key_file, "two-step", "MonospaceFont");
if (plugin->monospace_font == NULL)
plugin->monospace_font = strdup ("monospace 10");
plugin->console_text_color =
ply_key_file_get_long (key_file, "two-step",
"ConsoleLogTextColor",
PLY_CONSOLE_VIEWER_LOG_TEXT_COLOR);
plugin->image_dir = image_dir;
plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL;
@ -255,6 +287,16 @@ view_new (ply_boot_splash_plugin_t *plugin,
view->message_label = ply_label_new ();
if (ply_console_viewer_preferred ()) {
view->console_viewer = ply_console_viewer_new (view->display, plugin->monospace_font);
ply_console_viewer_set_text_color (view->console_viewer, plugin->console_text_color);
if (plugin->boot_buffer)
ply_console_viewer_convert_boot_buffer (view->console_viewer, plugin->boot_buffer);
} else {
view->console_viewer = NULL;
}
return view;
}
@ -265,6 +307,9 @@ view_free (view_t *view)
ply_label_free (view->message_label);
free_stars (view);
if (view->console_viewer)
ply_console_viewer_free (view->console_viewer);
ply_pixel_display_set_draw_handler (view->display, NULL, NULL);
free (view);
@ -419,6 +464,7 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin)
ply_image_free (plugin->logo_image);
ply_image_free (plugin->star_image);
ply_image_free (plugin->lock_image);
free (plugin->monospace_font);
free (plugin);
}
@ -740,6 +786,10 @@ on_draw (view_t *view,
ply_label_draw_area (view->message_label,
pixel_buffer,
x, y, width, height);
if (plugin->plugin_console_messages_updating == false && view->console_viewer) {
ply_console_viewer_draw_area (view->console_viewer, pixel_buffer, x, y, width, height);
}
}
static void
@ -794,12 +844,31 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin,
ply_buffer_t *boot_buffer,
ply_boot_splash_mode_t mode)
{
ply_list_node_t *node;
assert (plugin != NULL);
assert (plugin->logo_image != NULL);
plugin->loop = loop;
plugin->mode = mode;
if (boot_buffer && ply_console_viewer_preferred ()) {
plugin->boot_buffer = boot_buffer;
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);
ply_console_viewer_convert_boot_buffer (view->console_viewer, plugin->boot_buffer);
node = next_node;
}
}
ply_trace ("loading logo image");
if (!ply_image_load (plugin->logo_image))
return false;
@ -965,6 +1034,7 @@ hide_splash_screen (ply_boot_splash_plugin_t *plugin,
ply_event_loop_stop_watching_for_exit (plugin->loop, (ply_event_loop_exit_handler_t)
detach_from_event_loop,
plugin);
detach_from_event_loop (plugin);
}
}
@ -1040,7 +1110,12 @@ display_normal (ply_boot_splash_plugin_t *plugin)
hide_prompt (plugin);
plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL;
start_animation (plugin);
if (!plugin->should_show_console_messages) {
start_animation (plugin);
} else {
unhide_console_messages (plugin);
}
redraw_views (plugin);
unpause_views (plugin);
}
@ -1083,6 +1158,101 @@ display_message (ply_boot_splash_plugin_t *plugin,
show_message (plugin, message);
}
static bool
validate_input (ply_boot_splash_plugin_t *plugin,
const char *entry_text,
const char *add_text)
{
if (!ply_console_viewer_preferred ())
return true;
if (strcmp (add_text, "\e") == 0) {
toggle_console_messages (plugin);
return false;
}
return true;
}
static void
toggle_console_messages (ply_boot_splash_plugin_t *plugin)
{
if (plugin->should_show_console_messages) {
plugin->should_show_console_messages = false;
hide_console_messages (plugin);
} else {
unhide_console_messages (plugin);
}
}
static void
display_console_messages (ply_boot_splash_plugin_t *plugin)
{
ply_list_node_t *node;
view_t *view;
pause_views (plugin);
plugin->plugin_console_messages_updating = true;
node = ply_list_get_first_node (plugin->views);
while (node != NULL) {
view = ply_list_node_get_data (node);
ply_console_viewer_show (view->console_viewer, view->display);
node = ply_list_get_next_node (plugin->views, node);
}
plugin->plugin_console_messages_updating = false;
redraw_views (plugin);
unpause_views (plugin);
}
static void
unhide_console_messages (ply_boot_splash_plugin_t *plugin)
{
plugin->should_show_console_messages = true;
stop_animation (plugin);
display_console_messages (plugin);
}
static void
hide_console_messages (ply_boot_splash_plugin_t *plugin)
{
ply_list_node_t *node;
view_t *view;
plugin->should_show_console_messages = false;
plugin->plugin_console_messages_updating = true;
node = ply_list_get_first_node (plugin->views);
while (node != NULL) {
view = ply_list_node_get_data (node);
ply_console_viewer_hide (view->console_viewer);
node = ply_list_get_next_node (plugin->views, node);
}
plugin->plugin_console_messages_updating = false;
if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL)
start_animation (plugin);
}
static void
on_boot_output (ply_boot_splash_plugin_t *plugin,
const char *output,
size_t size)
{
ply_list_node_t *node;
view_t *view;
if (!ply_console_viewer_preferred ())
return;
node = ply_list_get_first_node (plugin->views);
while (node != NULL) {
view = ply_list_node_get_data (node);
ply_console_viewer_parse_lines (view->console_viewer, output, size);
node = ply_list_get_next_node (plugin->views, node);
}
}
ply_boot_splash_plugin_interface_t *
ply_boot_splash_plugin_get_interface (void)
{
@ -1099,6 +1269,8 @@ ply_boot_splash_plugin_get_interface (void)
.display_password = display_password,
.display_question = display_question,
.display_message = display_message,
.on_boot_output = on_boot_output,
.validate_input = validate_input,
};
return &plugin_interface;

View file

@ -54,6 +54,7 @@
#include "ply-pixel-display.h"
#include "ply-trigger.h"
#include "ply-utils.h"
#include "ply-console-viewer.h"
#ifndef FRAMES_PER_SECOND
#define FRAMES_PER_SECOND 40
@ -168,6 +169,8 @@ typedef struct
ply_list_t *sprites;
ply_rectangle_t box_area, lock_area, logo_area;
ply_image_t *scaled_background_image;
ply_console_viewer_t *console_viewer;
} view_t;
struct _ply_boot_splash_plugin
@ -202,10 +205,26 @@ struct _ply_boot_splash_plugin
uint32_t root_is_mounted : 1;
uint32_t is_visible : 1;
uint32_t is_animating : 1;
char *monospace_font;
uint32_t plugin_console_messages_updating : 1;
uint32_t should_show_console_messages : 1;
ply_buffer_t *boot_buffer;
uint32_t console_text_color;
};
ply_boot_splash_plugin_interface_t *ply_boot_splash_plugin_get_interface (void);
static void detach_from_event_loop (ply_boot_splash_plugin_t *plugin);
static bool validate_input (ply_boot_splash_plugin_t *plugin,
const char *entry_text,
const char *add_text);
static void on_boot_output (ply_boot_splash_plugin_t *plugin,
const char *output,
size_t size);
static void toggle_console_messages (ply_boot_splash_plugin_t *plugin);
static void display_console_messages (ply_boot_splash_plugin_t *plugin);
static void hide_console_messages (ply_boot_splash_plugin_t *plugin);
static void unhide_console_messages (ply_boot_splash_plugin_t *plugin);
static view_t *
view_new (ply_boot_splash_plugin_t *plugin,
@ -223,6 +242,16 @@ view_new (ply_boot_splash_plugin_t *plugin,
view->sprites = ply_list_new ();
if (ply_console_viewer_preferred ()) {
view->console_viewer = ply_console_viewer_new (view->display, plugin->monospace_font);
ply_console_viewer_set_text_color (view->console_viewer, plugin->console_text_color);
if (plugin->boot_buffer)
ply_console_viewer_convert_boot_buffer (view->console_viewer, plugin->boot_buffer);
} else {
view->console_viewer = NULL;
}
return view;
}
@ -237,6 +266,9 @@ view_free (view_t *view)
view_free_sprites (view);
ply_list_free (view->sprites);
if (view->console_viewer)
ply_console_viewer_free (view->console_viewer);
ply_image_free (view->scaled_background_image);
free (view);
@ -541,6 +573,21 @@ create_plugin (ply_key_file_t *key_file)
plugin->progress_barimage = ply_image_new (image_path);
free (image_path);
#endif
plugin->plugin_console_messages_updating = false;
plugin->should_show_console_messages = false;
/* Likely only able to set the font if the font is in the initrd */
plugin->monospace_font = ply_key_file_get_value (key_file, "two-step", "MonospaceFont");
if (plugin->monospace_font == NULL)
plugin->monospace_font = strdup ("monospace 10");
plugin->console_text_color =
ply_key_file_get_long (key_file, "two-step",
"ConsoleLogTextColor",
PLY_CONSOLE_VIEWER_LOG_TEXT_COLOR);
plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL;
plugin->progress = 0;
plugin->progress_target = -1;
@ -564,6 +611,7 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin)
ply_event_loop_stop_watching_for_exit (plugin->loop, (ply_event_loop_exit_handler_t)
detach_from_event_loop,
plugin);
detach_from_event_loop (plugin);
}
@ -583,6 +631,8 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin)
ply_image_free (plugin->progress_barimage);
#endif
free (plugin->monospace_font);
free_views (plugin);
free (plugin);
@ -1346,6 +1396,10 @@ on_draw (view_t *view,
ply_label_draw_area (view->message_label,
pixel_buffer,
x, y, width, height);
if (plugin->plugin_console_messages_updating == false && view->console_viewer) {
ply_console_viewer_draw_area (view->console_viewer, pixel_buffer, x, y, width, height);
}
}
static void
@ -1623,12 +1677,31 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin,
ply_buffer_t *boot_buffer,
ply_boot_splash_mode_t mode)
{
ply_list_node_t *node;
assert (plugin != NULL);
assert (plugin->logo_image != NULL);
plugin->loop = loop;
plugin->mode = mode;
if (boot_buffer && ply_console_viewer_preferred ()) {
plugin->boot_buffer = boot_buffer;
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);
ply_console_viewer_convert_boot_buffer (view->console_viewer, plugin->boot_buffer);
node = next_node;
}
}
ply_trace ("loading logo image");
if (!ply_image_load (plugin->logo_image))
return false;
@ -1795,7 +1868,12 @@ display_normal (ply_boot_splash_plugin_t *plugin)
hide_prompt (plugin);
plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL;
start_animation (plugin);
if (!plugin->should_show_console_messages) {
start_animation (plugin);
} else {
unhide_console_messages (plugin);
}
redraw_views (plugin);
unpause_views (plugin);
}
@ -1837,6 +1915,101 @@ display_message (ply_boot_splash_plugin_t *plugin,
show_message (plugin, message);
}
static bool
validate_input (ply_boot_splash_plugin_t *plugin,
const char *entry_text,
const char *add_text)
{
if (!ply_console_viewer_preferred ())
return true;
if (strcmp (add_text, "\e") == 0) {
toggle_console_messages (plugin);
return false;
}
return true;
}
static void
toggle_console_messages (ply_boot_splash_plugin_t *plugin)
{
if (plugin->should_show_console_messages) {
plugin->should_show_console_messages = false;
hide_console_messages (plugin);
} else {
unhide_console_messages (plugin);
}
}
static void
display_console_messages (ply_boot_splash_plugin_t *plugin)
{
ply_list_node_t *node;
view_t *view;
pause_views (plugin);
plugin->plugin_console_messages_updating = true;
node = ply_list_get_first_node (plugin->views);
while (node != NULL) {
view = ply_list_node_get_data (node);
ply_console_viewer_show (view->console_viewer, view->display);
node = ply_list_get_next_node (plugin->views, node);
}
plugin->plugin_console_messages_updating = false;
redraw_views (plugin);
unpause_views (plugin);
}
static void
unhide_console_messages (ply_boot_splash_plugin_t *plugin)
{
plugin->should_show_console_messages = true;
stop_animation (plugin);
display_console_messages (plugin);
}
static void
hide_console_messages (ply_boot_splash_plugin_t *plugin)
{
ply_list_node_t *node;
view_t *view;
plugin->should_show_console_messages = false;
plugin->plugin_console_messages_updating = true;
node = ply_list_get_first_node (plugin->views);
while (node != NULL) {
view = ply_list_node_get_data (node);
ply_console_viewer_hide (view->console_viewer);
node = ply_list_get_next_node (plugin->views, node);
}
plugin->plugin_console_messages_updating = false;
if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL)
start_animation (plugin);
}
static void
on_boot_output (ply_boot_splash_plugin_t *plugin,
const char *output,
size_t size)
{
ply_list_node_t *node;
view_t *view;
if (!ply_console_viewer_preferred ())
return;
node = ply_list_get_first_node (plugin->views);
while (node != NULL) {
view = ply_list_node_get_data (node);
ply_console_viewer_parse_lines (view->console_viewer, output, size);
node = ply_list_get_next_node (plugin->views, node);
}
}
ply_boot_splash_plugin_interface_t *
ply_boot_splash_plugin_get_interface (void)
{
@ -1856,6 +2029,8 @@ ply_boot_splash_plugin_get_interface (void)
.display_password = display_password,
.display_question = display_question,
.display_message = display_message,
.on_boot_output = on_boot_output,
.validate_input = validate_input,
};
return &plugin_interface;

View file

@ -61,6 +61,7 @@
#include "ply-progress-animation.h"
#include "ply-throbber.h"
#include "ply-progress-bar.h"
#include "ply-console-viewer.h"
#include <linux/kd.h>
@ -113,6 +114,8 @@ typedef struct
ply_trigger_t *end_trigger;
ply_pixel_buffer_t *background_buffer;
int animation_bottom;
ply_console_viewer_t *console_viewer;
} view_t;
typedef struct
@ -192,6 +195,12 @@ struct _ply_boot_splash_plugin
uint32_t background_image_is_scaled : 1;
uint32_t dialog_clears_firmware_background : 1;
uint32_t message_below_animation : 1;
char *monospace_font;
uint32_t plugin_console_messages_updating : 1;
uint32_t should_show_console_messages : 1;
ply_buffer_t *boot_buffer;
uint32_t console_text_color;
};
ply_boot_splash_plugin_interface_t *ply_boot_splash_plugin_get_interface (void);
@ -204,6 +213,16 @@ static void become_idle (ply_boot_splash_plugin_t *plugin,
ply_trigger_t *idle_trigger);
static void view_show_message (view_t *view,
const char *message);
static bool validate_input (ply_boot_splash_plugin_t *plugin,
const char *entry_text,
const char *add_text);
static void on_boot_output (ply_boot_splash_plugin_t *plugin,
const char *output,
size_t size);
static void toggle_console_messages (ply_boot_splash_plugin_t *plugin);
static void display_console_messages (ply_boot_splash_plugin_t *plugin);
static void hide_console_messages (ply_boot_splash_plugin_t *plugin);
static void unhide_console_messages (ply_boot_splash_plugin_t *plugin);
static view_t *
view_new (ply_boot_splash_plugin_t *plugin,
@ -244,6 +263,16 @@ view_new (ply_boot_splash_plugin_t *plugin,
view->subtitle_label = ply_label_new ();
ply_label_set_font (view->subtitle_label, plugin->font);
if (ply_console_viewer_preferred ()) {
view->console_viewer = ply_console_viewer_new (view->display, plugin->monospace_font);
ply_console_viewer_set_text_color (view->console_viewer, plugin->console_text_color);
if (plugin->boot_buffer)
ply_console_viewer_convert_boot_buffer (view->console_viewer, plugin->boot_buffer);
} else {
view->console_viewer = NULL;
}
return view;
}
@ -262,6 +291,9 @@ view_free (view_t *view)
ply_label_free (view->title_label);
ply_label_free (view->subtitle_label);
if (view->console_viewer)
ply_console_viewer_free (view->console_viewer);
if (view->background_buffer != NULL)
ply_pixel_buffer_free (view->background_buffer);
@ -1191,6 +1223,21 @@ create_plugin (ply_key_file_t *key_file)
}
free (transition);
plugin->plugin_console_messages_updating = false;
plugin->should_show_console_messages = false;
/* Likely only able to set the font if the font is in the initrd */
plugin->monospace_font = ply_key_file_get_value (key_file, "two-step", "MonospaceFont");
if (plugin->monospace_font == NULL)
plugin->monospace_font = strdup ("monospace 10");
plugin->console_text_color =
ply_key_file_get_long (key_file, "two-step",
"ConsoleLogTextColor",
PLY_CONSOLE_VIEWER_LOG_TEXT_COLOR);
plugin->transition_duration =
ply_key_file_get_double (key_file, "two-step",
"TransitionDuration", 0.0);
@ -1314,6 +1361,7 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin)
ply_event_loop_stop_watching_for_exit (plugin->loop, (ply_event_loop_exit_handler_t)
detach_from_event_loop,
plugin);
detach_from_event_loop (plugin);
}
@ -1347,6 +1395,7 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin)
free (plugin->font);
free (plugin->title_font);
free (plugin->monospace_font);
free (plugin->animation_dir);
free_views (plugin);
free (plugin);
@ -1514,6 +1563,9 @@ draw_background (view_t *view,
using_fw_background && plugin->dialog_clears_firmware_background)
use_black_background = true;
if (plugin->should_show_console_messages)
use_black_background = true;
if (use_black_background)
ply_pixel_buffer_fill_with_hex_color (pixel_buffer, &area, 0);
else if (view->background_buffer != NULL)
@ -1526,6 +1578,9 @@ draw_background (view_t *view,
ply_pixel_buffer_fill_with_hex_color (pixel_buffer, &area,
plugin->background_start_color);
if (plugin->should_show_console_messages)
return;
if (plugin->watermark_image != NULL) {
uint32_t *data;
@ -1648,6 +1703,10 @@ on_draw (view_t *view,
ply_label_draw_area (view->message_label,
pixel_buffer,
x, y, width, height);
if (!plugin->plugin_console_messages_updating && view->console_viewer) {
ply_console_viewer_draw_area (view->console_viewer, pixel_buffer, x, y, width, height);
}
}
static void
@ -1707,11 +1766,30 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin,
ply_buffer_t *boot_buffer,
ply_boot_splash_mode_t mode)
{
ply_list_node_t *node;
assert (plugin != NULL);
plugin->loop = loop;
plugin->mode = mode;
if (boot_buffer && ply_console_viewer_preferred ()) {
plugin->boot_buffer = boot_buffer;
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);
ply_console_viewer_convert_boot_buffer (view->console_viewer, plugin->boot_buffer);
node = next_node;
}
}
ply_trace ("loading lock image");
if (!ply_image_load (plugin->lock_image))
return false;
@ -2053,7 +2131,13 @@ display_normal (ply_boot_splash_plugin_t *plugin)
hide_prompt (plugin);
plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL;
start_progress_animation (plugin);
if (!plugin->should_show_console_messages) {
start_progress_animation (plugin);
} else {
unhide_console_messages (plugin);
}
redraw_views (plugin);
unpause_views (plugin);
}
@ -2095,6 +2179,101 @@ display_message (ply_boot_splash_plugin_t *plugin,
show_message (plugin, message);
}
static bool
validate_input (ply_boot_splash_plugin_t *plugin,
const char *entry_text,
const char *add_text)
{
if (!ply_console_viewer_preferred ())
return true;
if (strcmp (add_text, "\e") == 0) {
toggle_console_messages (plugin);
return false;
}
return true;
}
static void
toggle_console_messages (ply_boot_splash_plugin_t *plugin)
{
if (plugin->should_show_console_messages) {
plugin->should_show_console_messages = false;
hide_console_messages (plugin);
} else {
unhide_console_messages (plugin);
}
}
static void
display_console_messages (ply_boot_splash_plugin_t *plugin)
{
ply_list_node_t *node;
view_t *view;
pause_views (plugin);
plugin->plugin_console_messages_updating = true;
node = ply_list_get_first_node (plugin->views);
while (node != NULL) {
view = ply_list_node_get_data (node);
ply_console_viewer_show (view->console_viewer, view->display);
node = ply_list_get_next_node (plugin->views, node);
}
plugin->plugin_console_messages_updating = false;
redraw_views (plugin);
unpause_views (plugin);
}
static void
unhide_console_messages (ply_boot_splash_plugin_t *plugin)
{
plugin->should_show_console_messages = true;
stop_animation (plugin);
display_console_messages (plugin);
}
static void
hide_console_messages (ply_boot_splash_plugin_t *plugin)
{
ply_list_node_t *node;
view_t *view;
plugin->should_show_console_messages = false;
plugin->plugin_console_messages_updating = true;
node = ply_list_get_first_node (plugin->views);
while (node != NULL) {
view = ply_list_node_get_data (node);
ply_console_viewer_hide (view->console_viewer);
node = ply_list_get_next_node (plugin->views, node);
}
plugin->plugin_console_messages_updating = false;
if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL)
start_progress_animation (plugin);
}
static void
on_boot_output (ply_boot_splash_plugin_t *plugin,
const char *output,
size_t size)
{
ply_list_node_t *node;
view_t *view;
if (!ply_console_viewer_preferred ())
return;
node = ply_list_get_first_node (plugin->views);
while (node != NULL) {
view = ply_list_node_get_data (node);
ply_console_viewer_parse_lines (view->console_viewer, output, size);
node = ply_list_get_next_node (plugin->views, node);
}
}
ply_boot_splash_plugin_interface_t *
ply_boot_splash_plugin_get_interface (void)
{
@ -2115,6 +2294,8 @@ ply_boot_splash_plugin_get_interface (void)
.display_question = display_question,
.display_message = display_message,
.system_update = system_update,
.on_boot_output = on_boot_output,
.validate_input = validate_input,
};
return &plugin_interface;