* Written by: Charlie Brej <cbrej@cs.man.ac.uk>
* Ray Strode <rstrode@redhat.com>
*/
+#include "config.h"
#include <assert.h>
#include <errno.h>
#define FRAMES_PER_SECOND 50
#endif
+typedef enum
+{
+ PLY_BOOT_SPLASH_DISPLAY_NORMAL,
+ PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY,
+ PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY
+} ply_boot_splash_display_type_t;
+
struct _ply_boot_splash_plugin
{
- ply_event_loop_t *loop;
- ply_boot_splash_mode_t mode;
- ply_list_t *displays;
- ply_keyboard_t *keyboard;
+ ply_event_loop_t *loop;
+ ply_boot_splash_mode_t mode;
+ ply_list_t *displays;
+ ply_keyboard_t *keyboard;
+
+ ply_boot_splash_display_type_t state;
+ char *script_filename;
+ char *image_dir;
- char *script_filename;
- char *image_dir;
+ ply_list_t *script_env_vars;
+ script_op_t *script_main_op;
- ply_list_t *script_env_vars;
- script_op_t *script_main_op;
+ script_state_t *script_state;
+ script_lib_sprite_data_t *script_sprite_lib;
+ script_lib_image_data_t *script_image_lib;
+ script_lib_plymouth_data_t *script_plymouth_lib;
+ script_lib_math_data_t *script_math_lib;
+ script_lib_string_data_t *script_string_lib;
- script_state_t *script_state;
- script_lib_sprite_data_t *script_sprite_lib;
- script_lib_image_data_t *script_image_lib;
- script_lib_plymouth_data_t *script_plymouth_lib;
- script_lib_math_data_t *script_math_lib;
- script_lib_string_data_t *script_string_lib;
+ uint32_t is_animating : 1;
- uint32_t is_animating : 1;
+ char *monospace_font;
+ uint32_t should_show_console_messages : 1;
+ ply_buffer_t *boot_buffer;
+ uint32_t console_text_color;
};
typedef struct
static void on_keyboard_input (ply_boot_splash_plugin_t *plugin,
const char *keyboard_input,
size_t character_size);
+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
+show_prompt_on_console_viewer (ply_boot_splash_plugin_t *plugin,
+ const char *prompt,
+ const char *entry_text,
+ int number_of_bullets)
+{
+ if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL)
+ script_lib_sprite_console_viewer_print (plugin->script_sprite_lib, "\n");
+
+ script_lib_sprite_console_viewer_clear_line (plugin->script_sprite_lib);
+
+ script_lib_sprite_console_viewer_print (plugin->script_sprite_lib, prompt);
+
+ script_lib_sprite_console_viewer_print (plugin->script_sprite_lib, ": ");
+ if (entry_text)
+ script_lib_sprite_console_viewer_print (plugin->script_sprite_lib, "%s", entry_text);
+
+ for (int i = 0; i < number_of_bullets; i++) {
+ script_lib_sprite_console_viewer_print (plugin->script_sprite_lib, " ");
+ }
+
+ script_lib_sprite_console_viewer_print (plugin->script_sprite_lib, "_");
+}
static void
pause_displays (ply_boot_splash_plugin_t *plugin)
"script",
"ScriptFile");
+ plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL;
+
plugin->script_env_vars = ply_list_new ();
ply_key_file_foreach_entry (key_file, add_script_env_var, plugin->script_env_vars);
+ /* Likely only able to set the font if the font is in the initrd */
+ plugin->monospace_font = ply_key_file_get_value (key_file, "script", "MonospaceFont");
+
+ if (plugin->monospace_font == NULL)
+ plugin->monospace_font = strdup ("monospace 10");
+
+ plugin->console_text_color =
+ ply_key_file_get_long (key_file, "script",
+ "ConsoleLogTextColor",
+ PLY_CONSOLE_VIEWER_LOG_TEXT_COLOR);
+
plugin->displays = ply_list_new ();
+
return plugin;
}
if (plugin->loop != NULL) {
stop_animation (plugin);
+
ply_event_loop_stop_watching_for_exit (plugin->loop,
(ply_event_loop_exit_handler_t)
detach_from_event_loop,
ply_list_free (plugin->script_env_vars);
free (plugin->script_filename);
free (plugin->image_dir);
+ free (plugin->monospace_font);
free (plugin);
}
plugin->script_plymouth_lib);
pause_displays (plugin);
+ script_lib_sprite_set_needs_redraw (plugin->script_sprite_lib);
script_lib_sprite_refresh (plugin->script_sprite_lib);
unpause_displays (plugin);
}
static bool
start_script_animation (ply_boot_splash_plugin_t *plugin)
{
+ ply_list_t *displays;
ply_list_node_t *node;
script_obj_t *target_obj;
script_obj_t *value_obj;
plugin->script_math_lib = script_lib_math_setup (plugin->script_state);
plugin->script_string_lib = script_lib_string_setup (plugin->script_state);
+
+ displays = script_lib_get_displays (plugin->script_sprite_lib);
+ node = ply_list_get_first_node (displays);
+ while (node != NULL) {
+ script_lib_display_t *display;
+ ply_list_node_t *next_node;
+
+ display = ply_list_node_get_data (node);
+ next_node = ply_list_get_next_node (displays, node);
+
+ if (ply_console_viewer_preferred ()) {
+ display->console_viewer = ply_console_viewer_new (display->pixel_display, plugin->monospace_font);
+ ply_console_viewer_set_text_color (display->console_viewer, plugin->console_text_color);
+
+ if (plugin->boot_buffer)
+ ply_console_viewer_convert_boot_buffer (display->console_viewer, plugin->boot_buffer);
+ } else {
+ display->console_viewer = NULL;
+ }
+
+ node = next_node;
+ }
+
+ plugin->script_sprite_lib->monospace_font = plugin->monospace_font;
+ plugin->script_sprite_lib->boot_buffer = plugin->boot_buffer;
+
ply_trace ("executing script file");
script_return_t ret = script_execute (plugin->script_state,
plugin->script_main_op);
ply_buffer_t *boot_buffer,
ply_boot_splash_mode_t mode)
{
+ ply_list_node_t *node;
+
assert (plugin != NULL);
if (ply_list_get_length (plugin->displays) == 0) {
plugin->loop = loop;
plugin->mode = mode;
+ if (boot_buffer && ply_console_viewer_preferred ())
+ plugin->boot_buffer = boot_buffer;
+
ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t)
detach_from_event_loop,
plugin);
+ plugin->should_show_console_messages = false;
+
ply_trace ("starting boot animation");
return start_animation (plugin);
}
display_normal (ply_boot_splash_plugin_t *plugin)
{
pause_displays (plugin);
+
+ if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_NORMAL) {
+ if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY)
+ script_lib_sprite_console_viewer_clear_line (plugin->script_sprite_lib);
+
+ script_lib_sprite_console_viewer_print (plugin->script_sprite_lib, "\n");
+ }
+
script_lib_plymouth_on_display_normal (plugin->script_state,
plugin->script_plymouth_lib);
+
+ script_lib_sprite_refresh (plugin->script_sprite_lib);
+ plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL;
unpause_displays (plugin);
}
const char *prompt,
int bullets)
{
+ plugin->state = PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY;
pause_displays (plugin);
+ show_prompt_on_console_viewer (plugin, prompt, NULL, bullets);
script_lib_plymouth_on_display_password (plugin->script_state,
plugin->script_plymouth_lib,
prompt,
bullets);
+ script_lib_sprite_refresh (plugin->script_sprite_lib);
unpause_displays (plugin);
}
const char *prompt,
const char *entry_text)
{
+ plugin->state = PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY;
pause_displays (plugin);
+ show_prompt_on_console_viewer (plugin, prompt, entry_text, -1);
script_lib_plymouth_on_display_question (plugin->script_state,
plugin->script_plymouth_lib,
prompt,
entry_text);
+ script_lib_sprite_refresh (plugin->script_sprite_lib);
unpause_displays (plugin);
}
const char *entry_text,
const char *add_text)
{
- return script_lib_plymouth_on_validate_input (plugin->script_state,
- plugin->script_plymouth_lib,
- entry_text,
- add_text);
+ bool ret = script_lib_plymouth_on_validate_input (plugin->script_state,
+ plugin->script_plymouth_lib,
+ entry_text,
+ add_text);
+ if (!ply_console_viewer_preferred ())
+ return true;
+
+ if (strcmp (add_text, "\e") == 0) {
+ toggle_console_messages (plugin);
+ return false;
+ }
+
+ return ret;
}
static void
prompt,
entry_text,
is_secret);
+ script_lib_sprite_refresh (plugin->script_sprite_lib);
unpause_displays (plugin);
}
script_lib_plymouth_on_display_message (plugin->script_state,
plugin->script_plymouth_lib,
message);
+ script_lib_sprite_console_viewer_print (plugin->script_sprite_lib,
+ message);
+ script_lib_sprite_refresh (plugin->script_sprite_lib);
unpause_displays (plugin);
}
script_lib_plymouth_on_hide_message (plugin->script_state,
plugin->script_plymouth_lib,
message);
+ script_lib_sprite_refresh (plugin->script_sprite_lib);
+ unpause_displays (plugin);
+}
+
+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)
+{
+ pause_displays (plugin);
+ script_lib_sprite_console_viewer_show (plugin->script_sprite_lib);
unpause_displays (plugin);
}
+static void
+unhide_console_messages (ply_boot_splash_plugin_t *plugin)
+{
+ plugin->should_show_console_messages = true;
+ display_console_messages (plugin);
+}
+
+static void
+hide_console_messages (ply_boot_splash_plugin_t *plugin)
+{
+ plugin->should_show_console_messages = false;
+ script_lib_sprite_console_viewer_hide (plugin->script_sprite_lib);
+}
+
+static void
+on_boot_output (ply_boot_splash_plugin_t *plugin,
+ const char *output,
+ size_t size)
+{
+ ply_list_t *displays;
+ ply_list_node_t *node;
+
+ if (!ply_console_viewer_preferred ())
+ return;
+
+ displays = script_lib_get_displays (plugin->script_sprite_lib);
+ node = ply_list_get_first_node (displays);
+ while (node != NULL) {
+ script_lib_display_t *display;
+ ply_list_node_t *next_node;
+
+ display = ply_list_node_get_data (node);
+ next_node = ply_list_get_next_node (displays, node);
+
+ ply_console_viewer_write (display->console_viewer, output, size);
+
+ node = next_node;
+ }
+}
+
ply_boot_splash_plugin_interface_t *
ply_boot_splash_plugin_get_interface (void)
{
.display_prompt = display_prompt,
.display_message = display_message,
.hide_message = hide_message,
+ .on_boot_output = on_boot_output,
.validate_input = validate_input,
};
*
* Written by: Charlie Brej <cbrej@cs.man.ac.uk>
*/
+#include "config.h"
#include "ply-image.h"
#include "ply-utils.h"
#include "ply-logger.h"
#include "ply-key-file.h"
#include "ply-pixel-buffer.h"
#include "ply-pixel-display.h"
+#include "ply-console-viewer.h"
#include "script.h"
#include "script-parse.h"
#include "script-execute.h"
sprite->remove_me = false;
sprite->image = NULL;
sprite->image_obj = NULL;
+ sprite->state = state;
+ sprite->monospace_font = data->monospace_font;
+ sprite->draw_func = NULL;
ply_list_append_data (data->sprite_list, sprite);
reply = script_obj_new_native (sprite, data->class);
return script_return_obj (reply);
}
+static script_return_t consoleviewer_new (script_state_t *state,
+ void *user_data)
+{
+ sprite_t *sprite;
+ script_lib_sprite_data_t *data = user_data;
+ script_obj_t *reply;
+ ply_list_node_t *node;
+ int index;
+ script_obj_t *index_obj;
+ script_lib_display_t *display;
+ ply_console_viewer_t *console_viewer;
+
+ script_return_t ret = sprite_new (state, user_data);
+ sprite = ret.object->data.native.object_data;
+
+ index_obj = script_obj_hash_peek_element (state->local, "window");
+
+ if (index_obj) {
+ index = script_obj_as_number (index_obj);
+ script_obj_unref (index_obj);
+ if (index < 0)
+ return script_return_obj_null ();
+ node = ply_list_get_nth_node (data->displays, index);
+ if (node == NULL)
+ return script_return_obj_null ();
+ display = ply_list_node_get_data (node);
+ console_viewer = ply_console_viewer_new (display->pixel_display, sprite->monospace_font);
+
+ reply = script_obj_new_native (console_viewer, data->class);
+ return script_return_obj (reply);
+ }
+
+ return script_return_obj_null ();
+}
+
static script_return_t sprite_get_image (script_state_t *state,
void *user_data)
{
ply_rectangle_t *clip_area,
script_lib_sprite_data_t *data)
{
+ if (data->should_show_console_messages) {
+ ply_pixel_buffer_fill_with_hex_color (pixel_buffer, clip_area, 0);
+ return;
+ }
+
if (data->background_color_start == data->background_color_end) {
ply_pixel_buffer_fill_with_hex_color (pixel_buffer,
clip_area,
clip_area.width = width;
clip_area.height = height;
+ if (data->plugin_console_messages_updating == false && display->console_viewer != NULL && data->should_show_console_messages == true) {
+ script_lib_draw_brackground (pixel_buffer, &clip_area, data);
+ ply_console_viewer_draw_area (display->console_viewer, pixel_buffer, x, y, width, height);
+ return;
+ }
node = ply_list_get_first_node (data->sprite_list);
if (node == NULL)
if ((position_x + (int) ply_pixel_buffer_get_width (sprite->image)) <= x) continue;
if ((position_y + (int) ply_pixel_buffer_get_height (sprite->image)) <= y) continue;
+
+ if (sprite->draw_func != NULL) {
+ script_return_t ret = script_execute_object (sprite->state,
+ sprite->draw_func,
+ NULL,
+ NULL);
+
+ script_obj_unref (ret.object);
+
+ continue;
+ }
+
ply_pixel_buffer_fill_with_buffer_at_opacity_with_clip (pixel_buffer,
sprite->image,
position_x,
{
ply_list_node_t *node;
script_lib_sprite_data_t *data = malloc (sizeof(script_lib_sprite_data_t));
+ script_return_t ret;
data->class = script_obj_native_class_new (sprite_free, "sprite", data);
data->sprite_list = ply_list_new ();
NULL);
script_obj_unref (window_hash);
+
+ data->script_consoleviewer_op = script_parse_string (script_lib_sprite_string, "script-lib-consoleviewer.script");
+ ret = script_execute (state, data->script_consoleviewer_op);
+ script_obj_unref (ret.object);
+
+ script_obj_t *consoleviewer_hash = script_obj_hash_get_element (state->global, "ConsoleViewer");
+
+ script_add_native_function (consoleviewer_hash,
+ "New",
+ consoleviewer_new,
+ data,
+ "window",
+ NULL);
+
+ script_obj_unref (consoleviewer_hash);
+
data->script_main_op = script_parse_string (script_lib_sprite_string, "script-lib-sprite.script");
data->background_color_start = 0x000000;
data->background_color_end = 0x000000;
data->full_refresh = true;
- script_return_t ret = script_execute (state, data->script_main_op);
+ data->needs_redraw = true;
+ ret = script_execute (state, data->script_main_op);
+
+ data->should_show_console_messages = false;
+ data->plugin_console_messages_updating = false;
script_obj_unref (ret.object);
return data;
update_displays (data);
}
+void
+script_lib_sprite_set_needs_redraw (script_lib_sprite_data_t *data)
+{
+ data->needs_redraw = true;
+}
+
void
script_lib_sprite_refresh (script_lib_sprite_data_t *data)
{
if (!data)
return;
+ if (!data->needs_redraw)
+ return;
+
region = ply_region_new ();
ply_list_sort_stable (data->sprite_list, &sprite_compare_z);
}
ply_list_remove_node (data->sprite_list, node);
script_obj_unref (sprite->image_obj);
+ if (sprite->draw_func != NULL)
+ script_obj_unref (sprite->draw_func);
free (sprite);
}
node = next_node;
for (node = ply_list_get_first_node (data->sprite_list);
node;
node = ply_list_get_next_node (data->sprite_list, node)) {
+ if (data->should_show_console_messages)
+ break;
+
sprite_t *sprite = ply_list_node_get_data (node);
if (!sprite->image) continue;
if ((sprite->x != sprite->old_x)
}
ply_region_free (region);
+
+ data->needs_redraw = false;
}
void script_lib_sprite_destroy (script_lib_sprite_data_t *data)
node;
node = ply_list_get_next_node (data->displays, node)) {
script_lib_display_t *display = ply_list_node_get_data (node);
+
+ if (display->console_viewer)
+ ply_console_viewer_free (display->console_viewer);
+
ply_pixel_display_set_draw_handler (display->pixel_display, NULL, NULL);
}
node);
ply_list_remove_node (data->sprite_list, node);
script_obj_unref (sprite->image_obj);
+ script_obj_unref (sprite->draw_func);
free (sprite);
node = next_node;
}
free (data);
data = NULL;
}
+
+ply_list_t *
+script_lib_get_displays (script_lib_sprite_data_t *data)
+{
+ return data->displays;
+}
+
+void
+script_lib_sprite_console_viewer_print (script_lib_sprite_data_t *data,
+ const char *format,
+ ...)
+{
+ va_list arguments;
+ char *buffer = NULL;
+ int length;
+ ply_list_node_t *node;
+
+ if (format == NULL)
+ return;
+
+ va_start (arguments, format);
+ length = vsnprintf (NULL, 0, format, arguments);
+ if (length > 0)
+ buffer = calloc (1, length + 1);
+ va_end (arguments);
+
+ if (buffer == NULL)
+ return;
+
+ va_start (arguments, format);
+ vsnprintf (buffer, length + 1, format, arguments);
+
+ node = ply_list_get_first_node (data->displays);
+ while (node != NULL) {
+ script_lib_display_t *display;
+ ply_list_node_t *next_node;
+
+ display = ply_list_node_get_data (node);
+ next_node = ply_list_get_next_node (data->displays, node);
+
+ if (display->console_viewer != NULL)
+ ply_console_viewer_print (display->console_viewer, buffer);
+
+ node = next_node;
+ }
+
+ va_end (arguments);
+ free (buffer);
+}
+
+void
+script_lib_sprite_console_viewer_clear_line (script_lib_sprite_data_t *data)
+{
+ ply_list_node_t *node;
+
+ node = ply_list_get_first_node (data->displays);
+ while (node != NULL) {
+ script_lib_display_t *display;
+ ply_list_node_t *next_node;
+
+ display = ply_list_node_get_data (node);
+ next_node = ply_list_get_next_node (data->displays, node);
+
+ if (display->console_viewer != NULL)
+ ply_console_viewer_clear_line (display->console_viewer);
+
+ node = next_node;
+ }
+}
+
+void
+script_lib_sprite_console_viewer_show (script_lib_sprite_data_t *data)
+{
+ ply_list_node_t *node;
+
+ data->should_show_console_messages = true;
+
+ data->plugin_console_messages_updating = true;
+
+ data->full_refresh = true;
+
+ node = ply_list_get_first_node (data->displays);
+ while (node != NULL) {
+ script_lib_display_t *display;
+ ply_list_node_t *next_node;
+
+ display = ply_list_node_get_data (node);
+ next_node = ply_list_get_next_node (data->displays, node);
+
+ ply_console_viewer_show (display->console_viewer, display->pixel_display);
+
+ node = next_node;
+ }
+
+ script_lib_sprite_set_needs_redraw (data);
+ data->plugin_console_messages_updating = false;
+ script_lib_sprite_refresh (data);
+}
+
+void
+script_lib_sprite_console_viewer_hide (script_lib_sprite_data_t *data)
+{
+ ply_list_node_t *node;
+
+ data->should_show_console_messages = false;
+
+ data->plugin_console_messages_updating = true;
+
+ data->full_refresh = true;
+
+ node = ply_list_get_first_node (data->displays);
+ while (node != NULL) {
+ script_lib_display_t *display;
+ ply_list_node_t *next_node;
+
+ display = ply_list_node_get_data (node);
+ next_node = ply_list_get_next_node (data->displays, node);
+
+ ply_console_viewer_hide (display->console_viewer);
+
+ node = next_node;
+ }
+
+ script_lib_sprite_set_needs_redraw (data);
+ data->plugin_console_messages_updating = false;
+ script_lib_sprite_refresh (data);
+}