You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2224 lines
89 KiB
2224 lines
89 KiB
4 years ago
|
/*
|
||
|
*
|
||
|
* Copyright (C) 2009-2019 Red Hat, Inc.
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||
|
* any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, write to the Free Software
|
||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||
|
* 02111-1307, USA.
|
||
|
*
|
||
|
* Written by: William Jon McCann, Hans de Goede <hdegoede@redhat.com>
|
||
|
*
|
||
|
*/
|
||
|
#include "config.h"
|
||
|
|
||
|
#include <assert.h>
|
||
|
#include <errno.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <math.h>
|
||
|
#include <signal.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdint.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <sys/ioctl.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <sys/time.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <values.h>
|
||
|
#include <unistd.h>
|
||
|
#include <wchar.h>
|
||
|
#include <dirent.h>
|
||
|
|
||
|
#include "ply-boot-splash-plugin.h"
|
||
|
#include "ply-buffer.h"
|
||
|
#include "ply-capslock-icon.h"
|
||
|
#include "ply-entry.h"
|
||
|
#include "ply-event-loop.h"
|
||
|
#include "ply-label.h"
|
||
|
#include "ply-list.h"
|
||
|
#include "ply-logger.h"
|
||
|
#include "ply-image.h"
|
||
|
#include "ply-key-file.h"
|
||
|
#include "ply-keymap-icon.h"
|
||
|
#include "ply-trigger.h"
|
||
|
#include "ply-pixel-buffer.h"
|
||
|
#include "ply-pixel-display.h"
|
||
|
#include "ply-utils.h"
|
||
|
#include "ply-i18n.h"
|
||
|
|
||
|
#include "ply-animation.h"
|
||
|
#include "ply-progress-animation.h"
|
||
|
#include "ply-throbber.h"
|
||
|
#include "ply-progress-bar.h"
|
||
|
|
||
|
#include <linux/kd.h>
|
||
|
|
||
|
#ifndef FRAMES_PER_SECOND
|
||
|
#define FRAMES_PER_SECOND 30
|
||
|
#endif
|
||
|
|
||
|
#ifndef SHOW_ANIMATION_FRACTION
|
||
|
#define SHOW_ANIMATION_FRACTION 0.9
|
||
|
#endif
|
||
|
|
||
|
#define PROGRESS_BAR_WIDTH 400
|
||
|
#define PROGRESS_BAR_HEIGHT 5
|
||
|
|
||
|
#define BGRT_STATUS_ORIENTATION_OFFSET_0 (0 << 1)
|
||
|
#define BGRT_STATUS_ORIENTATION_OFFSET_90 (1 << 1)
|
||
|
#define BGRT_STATUS_ORIENTATION_OFFSET_180 (2 << 1)
|
||
|
#define BGRT_STATUS_ORIENTATION_OFFSET_270 (3 << 1)
|
||
|
#define BGRT_STATUS_ORIENTATION_OFFSET_MASK (3 << 1)
|
||
|
|
||
|
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;
|
||
|
|
||
|
typedef enum
|
||
|
{
|
||
|
PROGRESS_FUNCTION_TYPE_WWOODS,
|
||
|
PROGRESS_FUNCTION_TYPE_LINEAR,
|
||
|
} progress_function_t;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
ply_boot_splash_plugin_t *plugin;
|
||
|
ply_pixel_display_t *display;
|
||
|
ply_entry_t *entry;
|
||
|
ply_keymap_icon_t *keymap_icon;
|
||
|
ply_capslock_icon_t *capslock_icon;
|
||
|
ply_animation_t *end_animation;
|
||
|
ply_progress_animation_t *progress_animation;
|
||
|
ply_progress_bar_t *progress_bar;
|
||
|
ply_throbber_t *throbber;
|
||
|
ply_label_t *label;
|
||
|
ply_label_t *message_label;
|
||
|
ply_label_t *title_label;
|
||
|
ply_label_t *subtitle_label;
|
||
|
ply_rectangle_t box_area, lock_area, watermark_area, title_area, dialog_area;
|
||
|
ply_trigger_t *end_trigger;
|
||
|
ply_pixel_buffer_t *background_buffer;
|
||
|
ply_image_t *watermark_image;
|
||
|
int animation_bottom;
|
||
|
} view_t;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
bool suppress_messages;
|
||
|
bool progress_bar_show_percent_complete;
|
||
|
bool use_progress_bar;
|
||
|
bool use_animation;
|
||
|
bool use_end_animation;
|
||
|
bool use_firmware_background;
|
||
|
char *title;
|
||
|
char *subtitle;
|
||
|
uint32_t background_start_color;
|
||
|
uint32_t background_end_color;
|
||
|
uint32_t title_color;
|
||
|
char *watermark_imagename;
|
||
|
double animation_horizontal_alignment;
|
||
|
double animation_vertical_alignment;
|
||
|
char *animation_vertical_alignment_type;
|
||
|
} mode_settings_t;
|
||
|
|
||
|
struct _ply_boot_splash_plugin
|
||
|
{
|
||
|
ply_event_loop_t *loop;
|
||
|
ply_boot_splash_mode_t mode;
|
||
|
mode_settings_t mode_settings[PLY_BOOT_SPLASH_MODE_COUNT];
|
||
|
char *font;
|
||
|
ply_image_t *lock_image;
|
||
|
ply_image_t *box_image;
|
||
|
ply_image_t *corner_image;
|
||
|
ply_image_t *header_image;
|
||
|
ply_image_t *background_tile_image;
|
||
|
ply_image_t *background_bgrt_image;
|
||
|
ply_list_t *views;
|
||
|
|
||
|
ply_boot_splash_display_type_t state;
|
||
|
|
||
|
double dialog_horizontal_alignment;
|
||
|
double dialog_vertical_alignment;
|
||
|
|
||
|
double title_horizontal_alignment;
|
||
|
double title_vertical_alignment;
|
||
|
char *title_font;
|
||
|
|
||
|
double watermark_horizontal_alignment;
|
||
|
double watermark_vertical_alignment;
|
||
|
char *watermark_imagename;
|
||
|
|
||
|
double animation_horizontal_alignment;
|
||
|
double animation_vertical_alignment;
|
||
|
char *animation_vertical_alignment_type;
|
||
|
char *animation_dir;
|
||
|
|
||
|
ply_progress_animation_transition_t transition;
|
||
|
double transition_duration;
|
||
|
|
||
|
uint32_t background_start_color;
|
||
|
uint32_t background_end_color;
|
||
|
uint32_t title_color;
|
||
|
int background_bgrt_raw_width;
|
||
|
int background_bgrt_raw_height;
|
||
|
|
||
|
double progress_bar_horizontal_alignment;
|
||
|
double progress_bar_vertical_alignment;
|
||
|
long progress_bar_width;
|
||
|
long progress_bar_height;
|
||
|
uint32_t progress_bar_bg_color;
|
||
|
uint32_t progress_bar_fg_color;
|
||
|
|
||
|
progress_function_t progress_function;
|
||
|
|
||
|
ply_trigger_t *idle_trigger;
|
||
|
ply_trigger_t *stop_trigger;
|
||
|
|
||
|
uint32_t root_is_mounted : 1;
|
||
|
uint32_t is_visible : 1;
|
||
|
uint32_t is_animating : 1;
|
||
|
uint32_t is_idle : 1;
|
||
|
uint32_t use_firmware_background : 1;
|
||
|
uint32_t dialog_clears_firmware_background : 1;
|
||
|
uint32_t message_below_animation : 1;
|
||
|
};
|
||
|
|
||
|
ply_boot_splash_plugin_interface_t *ply_boot_splash_plugin_get_interface (void);
|
||
|
|
||
|
static void stop_animation (ply_boot_splash_plugin_t *plugin);
|
||
|
static void detach_from_event_loop (ply_boot_splash_plugin_t *plugin);
|
||
|
static void display_message (ply_boot_splash_plugin_t *plugin,
|
||
|
const char *message);
|
||
|
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);
|
||
|
|
||
|
bool is_dir(const char* path) {
|
||
|
struct stat path_stat;
|
||
|
stat(path, &path_stat);
|
||
|
return S_ISDIR(path_stat.st_mode);
|
||
|
}
|
||
|
|
||
|
void image_get_res(const char *basedir, int *xres, int *yres)
|
||
|
{
|
||
|
FILE *fp;
|
||
|
char buf[512];
|
||
|
int oxres, oyres;
|
||
|
|
||
|
oxres = *xres;
|
||
|
oyres = *yres;
|
||
|
snprintf(buf, 512, "%s/%dx%d.png", basedir, oxres, oyres);
|
||
|
|
||
|
fp = fopen(buf, "r");
|
||
|
if (!fp) {
|
||
|
*xres = 1024;
|
||
|
*yres = 768;
|
||
|
unsigned int t, tx, ty, mdist = 0xffffffff;
|
||
|
struct dirent *dent;
|
||
|
DIR *tdir;
|
||
|
|
||
|
snprintf(buf, 512, "%s", basedir);
|
||
|
tdir = opendir(buf);
|
||
|
if (!tdir) {
|
||
|
*xres = 0;
|
||
|
*yres = 0;
|
||
|
return;
|
||
|
}
|
||
|
while ((dent = readdir(tdir))) {
|
||
|
if (sscanf(dent->d_name, "%dx%d.png", &tx, &ty) != 2)
|
||
|
continue;
|
||
|
|
||
|
/* We only want configs for resolutions smaller than the current one,
|
||
|
* so that we can actually fit the image on the screen. */
|
||
|
if (tx >= oxres || ty >= oyres)
|
||
|
continue;
|
||
|
|
||
|
t = (tx - oxres) * (tx - oxres) + (ty - oyres) * (ty - oyres);
|
||
|
|
||
|
/* Penalize configs for resolutions with different aspect ratios. */
|
||
|
if (oxres / oyres != tx / ty)
|
||
|
t *= 10;
|
||
|
|
||
|
if (t < mdist) {
|
||
|
*xres = tx;
|
||
|
*yres = ty;
|
||
|
mdist = t;
|
||
|
}
|
||
|
}
|
||
|
closedir(tdir);
|
||
|
} else {
|
||
|
fclose(fp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
char *detect_image(const char *logo_image, int xres, int yres) {
|
||
|
char *buf;
|
||
|
if(logo_image != NULL) {
|
||
|
if(is_dir(logo_image)) {
|
||
|
image_get_res(logo_image, &xres, &yres);
|
||
|
if(asprintf(&buf, "%s/%dx%d.png", logo_image, xres, yres) != -1)
|
||
|
return buf;
|
||
|
} else {
|
||
|
return strdup (logo_image);
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
long
|
||
|
calculate_animation_y(view_t *view, double animation_vertical_alignment,
|
||
|
char *animation_vertical_alignment_type, unsigned long screen_height, long height)
|
||
|
{
|
||
|
ply_boot_splash_plugin_t *plugin;
|
||
|
plugin = view->plugin;
|
||
|
long y;
|
||
|
if (animation_vertical_alignment_type == NULL) {
|
||
|
y = animation_vertical_alignment * screen_height - height / 2.0;
|
||
|
} else if (strcmp(animation_vertical_alignment_type,
|
||
|
"below_title") == 0) {
|
||
|
y = view->title_area.y + view->title_area.height;
|
||
|
if( y + height >= screen_height) {
|
||
|
y = animation_vertical_alignment * screen_height - height / 2.0;
|
||
|
} else {
|
||
|
y += animation_vertical_alignment * (screen_height - y);
|
||
|
if( animation_vertical_alignment != 0.0) {
|
||
|
y -= height / 2;
|
||
|
}
|
||
|
}
|
||
|
} else if (strcmp(animation_vertical_alignment_type,
|
||
|
"below_watermark") == 0 && view->watermark_image != NULL) {
|
||
|
y = view->watermark_area.y + view->watermark_area.height;
|
||
|
if( y + height >= screen_height) {
|
||
|
y = animation_vertical_alignment * screen_height - height / 2.0;
|
||
|
} else {
|
||
|
y += animation_vertical_alignment * (screen_height - y);
|
||
|
if( animation_vertical_alignment != 0.0) {
|
||
|
y -= height / 2;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
y = animation_vertical_alignment * screen_height - height / 2.0;
|
||
|
}
|
||
|
return y;
|
||
|
}
|
||
|
|
||
|
static view_t *
|
||
|
view_new (ply_boot_splash_plugin_t *plugin,
|
||
|
ply_pixel_display_t *display)
|
||
|
{
|
||
|
view_t *view;
|
||
|
|
||
|
view = calloc (1, sizeof(view_t));
|
||
|
view->plugin = plugin;
|
||
|
view->display = display;
|
||
|
view->watermark_image = NULL;
|
||
|
|
||
|
view->entry = ply_entry_new (plugin->animation_dir);
|
||
|
view->keymap_icon = ply_keymap_icon_new (display, plugin->animation_dir);
|
||
|
view->capslock_icon = ply_capslock_icon_new (plugin->animation_dir);
|
||
|
view->progress_animation = ply_progress_animation_new (plugin->animation_dir,
|
||
|
"progress-");
|
||
|
ply_progress_animation_set_transition (view->progress_animation,
|
||
|
plugin->transition,
|
||
|
plugin->transition_duration);
|
||
|
|
||
|
view->progress_bar = ply_progress_bar_new ();
|
||
|
ply_progress_bar_set_colors (view->progress_bar,
|
||
|
plugin->progress_bar_fg_color,
|
||
|
plugin->progress_bar_bg_color);
|
||
|
|
||
|
view->throbber = ply_throbber_new (plugin->animation_dir,
|
||
|
"throbber-");
|
||
|
|
||
|
view->label = ply_label_new ();
|
||
|
ply_label_set_font (view->label, plugin->font);
|
||
|
|
||
|
view->message_label = ply_label_new ();
|
||
|
ply_label_set_font (view->message_label, plugin->font);
|
||
|
|
||
|
view->title_label = ply_label_new ();
|
||
|
ply_label_set_font (view->title_label, plugin->title_font);
|
||
|
|
||
|
view->subtitle_label = ply_label_new ();
|
||
|
ply_label_set_font (view->subtitle_label, plugin->font);
|
||
|
|
||
|
return view;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
view_free (view_t *view)
|
||
|
{
|
||
|
ply_entry_free (view->entry);
|
||
|
ply_keymap_icon_free (view->keymap_icon);
|
||
|
ply_capslock_icon_free (view->capslock_icon);
|
||
|
ply_animation_free (view->end_animation);
|
||
|
ply_progress_animation_free (view->progress_animation);
|
||
|
ply_progress_bar_free (view->progress_bar);
|
||
|
ply_throbber_free (view->throbber);
|
||
|
ply_label_free (view->label);
|
||
|
ply_label_free (view->message_label);
|
||
|
ply_label_free (view->title_label);
|
||
|
ply_label_free (view->subtitle_label);
|
||
|
|
||
|
if (view->watermark_image != NULL)
|
||
|
ply_image_free (view->watermark_image);
|
||
|
|
||
|
if (view->background_buffer != NULL)
|
||
|
ply_pixel_buffer_free (view->background_buffer);
|
||
|
|
||
|
free (view);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
view_load_end_animation (view_t *view)
|
||
|
{
|
||
|
ply_boot_splash_plugin_t *plugin = view->plugin;
|
||
|
const char *animation_prefix;
|
||
|
|
||
|
if (!plugin->mode_settings[plugin->mode].use_end_animation)
|
||
|
return;
|
||
|
|
||
|
ply_trace ("loading animation");
|
||
|
|
||
|
switch (plugin->mode) {
|
||
|
case PLY_BOOT_SPLASH_MODE_BOOT_UP:
|
||
|
case PLY_BOOT_SPLASH_MODE_UPDATES:
|
||
|
case PLY_BOOT_SPLASH_MODE_SYSTEM_UPGRADE:
|
||
|
case PLY_BOOT_SPLASH_MODE_FIRMWARE_UPGRADE:
|
||
|
animation_prefix = "startup-animation-";
|
||
|
break;
|
||
|
case PLY_BOOT_SPLASH_MODE_SHUTDOWN:
|
||
|
case PLY_BOOT_SPLASH_MODE_REBOOT:
|
||
|
animation_prefix = "shutdown-animation-";
|
||
|
break;
|
||
|
case PLY_BOOT_SPLASH_MODE_INVALID:
|
||
|
default:
|
||
|
ply_trace ("unexpected splash mode 0x%x\n", plugin->mode);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ply_trace ("trying prefix: %s", animation_prefix);
|
||
|
view->end_animation = ply_animation_new (plugin->animation_dir,
|
||
|
animation_prefix);
|
||
|
|
||
|
if (ply_animation_load (view->end_animation))
|
||
|
return;
|
||
|
ply_animation_free (view->end_animation);
|
||
|
|
||
|
ply_trace ("now trying more general prefix: animation-");
|
||
|
view->end_animation = ply_animation_new (plugin->animation_dir,
|
||
|
"animation-");
|
||
|
if (ply_animation_load (view->end_animation))
|
||
|
return;
|
||
|
ply_animation_free (view->end_animation);
|
||
|
|
||
|
ply_trace ("now trying old compat prefix: throbber-");
|
||
|
view->end_animation = ply_animation_new (plugin->animation_dir,
|
||
|
"throbber-");
|
||
|
if (ply_animation_load (view->end_animation)) {
|
||
|
/* files named throbber- are for end animation, so
|
||
|
* there's no throbber */
|
||
|
ply_throbber_free (view->throbber);
|
||
|
view->throbber = NULL;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ply_trace ("optional animation didn't load");
|
||
|
ply_animation_free (view->end_animation);
|
||
|
view->end_animation = NULL;
|
||
|
plugin->mode_settings[plugin->mode].use_end_animation = false;
|
||
|
}
|
||
|
|
||
|
static bool
|
||
|
get_bgrt_sysfs_info(int *x_offset, int *y_offset,
|
||
|
ply_pixel_buffer_rotation_t *rotation)
|
||
|
{
|
||
|
bool ret = false;
|
||
|
char buf[64];
|
||
|
int status;
|
||
|
FILE *f;
|
||
|
|
||
|
f = fopen("/sys/firmware/acpi/bgrt/status", "r");
|
||
|
if (!f)
|
||
|
return false;
|
||
|
|
||
|
if (!fgets(buf, sizeof(buf), f))
|
||
|
goto out;
|
||
|
|
||
|
if (sscanf(buf, "%d", &status) != 1)
|
||
|
goto out;
|
||
|
|
||
|
fclose(f);
|
||
|
|
||
|
switch (status & BGRT_STATUS_ORIENTATION_OFFSET_MASK) {
|
||
|
case BGRT_STATUS_ORIENTATION_OFFSET_0:
|
||
|
*rotation = PLY_PIXEL_BUFFER_ROTATE_UPRIGHT;
|
||
|
break;
|
||
|
case BGRT_STATUS_ORIENTATION_OFFSET_90:
|
||
|
*rotation = PLY_PIXEL_BUFFER_ROTATE_COUNTER_CLOCKWISE;
|
||
|
break;
|
||
|
case BGRT_STATUS_ORIENTATION_OFFSET_180:
|
||
|
*rotation = PLY_PIXEL_BUFFER_ROTATE_UPSIDE_DOWN;
|
||
|
break;
|
||
|
case BGRT_STATUS_ORIENTATION_OFFSET_270:
|
||
|
*rotation = PLY_PIXEL_BUFFER_ROTATE_CLOCKWISE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
f = fopen("/sys/firmware/acpi/bgrt/xoffset", "r");
|
||
|
if (!f)
|
||
|
return false;
|
||
|
|
||
|
if (!fgets(buf, sizeof(buf), f))
|
||
|
goto out;
|
||
|
|
||
|
if (sscanf(buf, "%d", x_offset) != 1)
|
||
|
goto out;
|
||
|
|
||
|
fclose(f);
|
||
|
|
||
|
f = fopen("/sys/firmware/acpi/bgrt/yoffset", "r");
|
||
|
if (!f)
|
||
|
return false;
|
||
|
|
||
|
if (!fgets(buf, sizeof(buf), f))
|
||
|
goto out;
|
||
|
|
||
|
if (sscanf(buf, "%d", y_offset) != 1)
|
||
|
goto out;
|
||
|
|
||
|
ret = true;
|
||
|
out:
|
||
|
fclose(f);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/* The Microsoft boot logo spec says that the logo must use a black background
|
||
|
* and have its center at 38.2% from the screen's top (golden ratio).
|
||
|
* We reproduce this exactly here so that we get a background which is an exact
|
||
|
* match of the firmware's boot splash.
|
||
|
* At the time of writing this comment this is documented in a document called
|
||
|
* "Boot screen components" which is available here:
|
||
|
* https://docs.microsoft.com/en-us/windows-hardware/drivers/bringup/boot-screen-components
|
||
|
* Note that we normally do not use the firmware reported x and y-offset as
|
||
|
* that is based on the EFI fb resolution which may not be the native
|
||
|
* resolution of the screen (esp. when using multiple heads).
|
||
|
*/
|
||
|
static void
|
||
|
view_set_bgrt_background (view_t *view)
|
||
|
{
|
||
|
ply_pixel_buffer_rotation_t panel_rotation = PLY_PIXEL_BUFFER_ROTATE_UPRIGHT;
|
||
|
ply_pixel_buffer_rotation_t bgrt_rotation = PLY_PIXEL_BUFFER_ROTATE_UPRIGHT;
|
||
|
int x_offset, y_offset, sysfs_x_offset, sysfs_y_offset, width, height;
|
||
|
int panel_width = 0, panel_height = 0, panel_scale = 1;
|
||
|
int screen_width, screen_height, screen_scale;
|
||
|
ply_pixel_buffer_t *bgrt_buffer;
|
||
|
bool have_panel_props;
|
||
|
|
||
|
if (!view->plugin->background_bgrt_image)
|
||
|
return;
|
||
|
|
||
|
if (!get_bgrt_sysfs_info(&sysfs_x_offset, &sysfs_y_offset,
|
||
|
&bgrt_rotation)) {
|
||
|
ply_trace ("get bgrt sysfs info failed");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
screen_width = ply_pixel_display_get_width (view->display);
|
||
|
screen_height = ply_pixel_display_get_height (view->display);
|
||
|
screen_scale = ply_pixel_display_get_device_scale (view->display);
|
||
|
|
||
|
bgrt_buffer = ply_image_get_buffer (view->plugin->background_bgrt_image);
|
||
|
|
||
|
have_panel_props = ply_renderer_get_panel_properties (ply_pixel_display_get_renderer (view->display),
|
||
|
&panel_width, &panel_height,
|
||
|
&panel_rotation, &panel_scale);
|
||
|
|
||
|
/*
|
||
|
* Some buggy Lenovo 2-in-1s with a 90 degree rotated panel, behave as
|
||
|
* if the panel is mounted up-right / not rotated at all. These devices
|
||
|
* have a buggy efifb size (landscape resolution instead of the actual
|
||
|
* portrait resolution of the panel), this gets fixed-up by the kernel.
|
||
|
* These buggy devices also do not pre-rotate the bgrt_image nor do
|
||
|
* they set the ACPI-6.2 rotation status-bits. We can detect this by
|
||
|
* checking that the bgrt_image is perfectly centered horizontally
|
||
|
* when we use the panel's height as the width.
|
||
|
*/
|
||
|
if (have_panel_props &&
|
||
|
(panel_rotation == PLY_PIXEL_BUFFER_ROTATE_CLOCKWISE ||
|
||
|
panel_rotation == PLY_PIXEL_BUFFER_ROTATE_COUNTER_CLOCKWISE) &&
|
||
|
(panel_width - view->plugin->background_bgrt_raw_width) / 2 != sysfs_x_offset &&
|
||
|
(panel_height - view->plugin->background_bgrt_raw_width) / 2 == sysfs_x_offset)
|
||
|
bgrt_rotation = panel_rotation;
|
||
|
|
||
|
/*
|
||
|
* Before the ACPI 6.2 specification, the BGRT table did not contain
|
||
|
* any rotation information, so to make sure that the firmware-splash
|
||
|
* showed the right way up the firmware would contain a pre-rotated
|
||
|
* image. Starting with ACPI 6.2 the bgrt status fields has 2 bits
|
||
|
* to tell the firmware the image needs to be rotated before being
|
||
|
* displayed.
|
||
|
* If these bits are set then the firmwares-splash is not pre-rotated,
|
||
|
* in this case we must not rotate it when rendering and when doing
|
||
|
* comparisons with the panel-size we must use the post rotation
|
||
|
* panel-size.
|
||
|
*/
|
||
|
if (bgrt_rotation != PLY_PIXEL_BUFFER_ROTATE_UPRIGHT) {
|
||
|
if (bgrt_rotation != panel_rotation) {
|
||
|
ply_trace ("bgrt orientation mismatch, bgrt_rot %d panel_rot %d", (int)bgrt_rotation, (int)panel_rotation);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Set panel properties to their post-rotations values */
|
||
|
if (panel_rotation == PLY_PIXEL_BUFFER_ROTATE_CLOCKWISE ||
|
||
|
panel_rotation == PLY_PIXEL_BUFFER_ROTATE_COUNTER_CLOCKWISE) {
|
||
|
int temp = panel_width;
|
||
|
panel_width = panel_height;
|
||
|
panel_height = temp;
|
||
|
}
|
||
|
panel_rotation = PLY_PIXEL_BUFFER_ROTATE_UPRIGHT;
|
||
|
}
|
||
|
|
||
|
if (have_panel_props) {
|
||
|
ply_pixel_buffer_set_device_rotation (bgrt_buffer, panel_rotation);
|
||
|
ply_pixel_buffer_set_device_scale (bgrt_buffer, panel_scale);
|
||
|
}
|
||
|
|
||
|
width = ply_pixel_buffer_get_width (bgrt_buffer);
|
||
|
height = ply_pixel_buffer_get_height (bgrt_buffer);
|
||
|
|
||
|
x_offset = (screen_width - width) / 2;
|
||
|
y_offset = screen_height * 382 / 1000 - height / 2;
|
||
|
|
||
|
/*
|
||
|
* On laptops / tablets the LCD panel is typically brought up in
|
||
|
* its native resolution, so we can trust the x- and y-offset values
|
||
|
* provided by the firmware to be correct for a screen with the panels
|
||
|
* resolution.
|
||
|
*
|
||
|
* Moreover some laptop / tablet firmwares to do all kind of hacks wrt
|
||
|
* the y offset. This happens especially on devices where the panel is
|
||
|
* mounted 90 degrees rotated, but also on other devices.
|
||
|
*
|
||
|
* So on devices with an internal LCD panel, we prefer to use the
|
||
|
* firmware provided offsets, to make sure we match its quirky behavior.
|
||
|
*
|
||
|
* We check that the x-offset matches what we expect for the panel's
|
||
|
* native resolution to make sure that the values are indeed for the
|
||
|
* panel's native resolution and then we correct for any difference
|
||
|
* between the (external) screen's and the panel's resolution.
|
||
|
*/
|
||
|
if (have_panel_props &&
|
||
|
(panel_width - view->plugin->background_bgrt_raw_width) / 2 == sysfs_x_offset) {
|
||
|
if (panel_rotation == PLY_PIXEL_BUFFER_ROTATE_CLOCKWISE ||
|
||
|
panel_rotation == PLY_PIXEL_BUFFER_ROTATE_COUNTER_CLOCKWISE) {
|
||
|
/*
|
||
|
* For left side up panels the y_offset is from the
|
||
|
* right side of the image once rotated upright (the
|
||
|
* top of the physicial LCD panel is on the right side).
|
||
|
* Our coordinates have the left side as 0, so we need
|
||
|
* to "flip" the y_offset in this case.
|
||
|
*/
|
||
|
if (panel_rotation == PLY_PIXEL_BUFFER_ROTATE_COUNTER_CLOCKWISE)
|
||
|
sysfs_y_offset = panel_height - view->plugin->background_bgrt_raw_height - sysfs_y_offset;
|
||
|
|
||
|
/* 90 degrees rotated, swap x and y */
|
||
|
x_offset = sysfs_y_offset / panel_scale;
|
||
|
y_offset = sysfs_x_offset / panel_scale;
|
||
|
|
||
|
x_offset += (screen_width - panel_height / panel_scale) / 2;
|
||
|
y_offset += (screen_height - panel_width / panel_scale) * 382 / 1000;
|
||
|
} else {
|
||
|
/* Normal orientation */
|
||
|
x_offset = sysfs_x_offset / panel_scale;
|
||
|
y_offset = sysfs_y_offset / panel_scale;
|
||
|
|
||
|
x_offset += (screen_width - panel_width / panel_scale) / 2;
|
||
|
y_offset += (screen_height - panel_height / panel_scale) * 382 / 1000;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* On desktops (no panel) we normally do not use the BGRT provided
|
||
|
* xoffset and yoffset because the resolution they are intended for
|
||
|
* may be differtent then the resolution of the current display.
|
||
|
*
|
||
|
* On some desktops (no panel) the image gets centered not only
|
||
|
* horizontally, but also vertically. In this case our default of using
|
||
|
* the golden ratio for the vertical position causes the BGRT image
|
||
|
* to jump. To avoid this we check here if the provided xoffset and
|
||
|
* yoffset perfectly center the image and in that case we use them.
|
||
|
*/
|
||
|
if (!have_panel_props && screen_scale == 1 &&
|
||
|
(screen_width - width ) / 2 == sysfs_x_offset &&
|
||
|
(screen_height - height) / 2 == sysfs_y_offset) {
|
||
|
x_offset = sysfs_x_offset;
|
||
|
y_offset = sysfs_y_offset;
|
||
|
}
|
||
|
|
||
|
ply_trace ("using %dx%d bgrt image centered at %dx%d for %dx%d screen",
|
||
|
width, height, x_offset, y_offset, screen_width, screen_height);
|
||
|
|
||
|
view->background_buffer = ply_pixel_buffer_new (screen_width * screen_scale, screen_height * screen_scale);
|
||
|
ply_pixel_buffer_set_device_scale (view->background_buffer, screen_scale);
|
||
|
ply_pixel_buffer_fill_with_hex_color (view->background_buffer, NULL, 0x000000);
|
||
|
if (x_offset >= 0 && y_offset >= 0) {
|
||
|
bgrt_buffer = ply_pixel_buffer_rotate_upright (bgrt_buffer);
|
||
|
ply_pixel_buffer_fill_with_buffer (view->background_buffer, bgrt_buffer, x_offset, y_offset);
|
||
|
ply_pixel_buffer_free (bgrt_buffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool
|
||
|
view_load (view_t *view)
|
||
|
{
|
||
|
unsigned long x, y, width, title_height = 0, subtitle_height = 0;
|
||
|
unsigned long screen_width, screen_height, screen_scale;
|
||
|
char *image_dir, *image_path;
|
||
|
ply_boot_splash_plugin_t *plugin;
|
||
|
ply_pixel_buffer_t *buffer;
|
||
|
|
||
|
plugin = view->plugin;
|
||
|
|
||
|
screen_width = ply_pixel_display_get_width (view->display);
|
||
|
screen_height = ply_pixel_display_get_height (view->display);
|
||
|
|
||
|
buffer = ply_renderer_get_buffer_for_head(
|
||
|
ply_pixel_display_get_renderer (view->display),
|
||
|
ply_pixel_display_get_renderer_head (view->display));
|
||
|
screen_scale = ply_pixel_buffer_get_device_scale (buffer);
|
||
|
|
||
|
view_set_bgrt_background (view);
|
||
|
|
||
|
if (!view->background_buffer && plugin->background_tile_image != NULL) {
|
||
|
ply_trace ("tiling background to %lux%lu", screen_width, screen_height);
|
||
|
|
||
|
/* Create a buffer at screen scale so that we only do the slow interpolating scale once */
|
||
|
view->background_buffer = ply_pixel_buffer_new (screen_width * screen_scale, screen_height * screen_scale);
|
||
|
ply_pixel_buffer_set_device_scale (view->background_buffer, screen_scale);
|
||
|
|
||
|
if (plugin->background_start_color != plugin->background_end_color)
|
||
|
ply_pixel_buffer_fill_with_gradient (view->background_buffer, NULL,
|
||
|
plugin->background_start_color,
|
||
|
plugin->background_end_color);
|
||
|
else
|
||
|
ply_pixel_buffer_fill_with_hex_color (view->background_buffer, NULL,
|
||
|
plugin->background_start_color);
|
||
|
|
||
|
buffer = ply_pixel_buffer_tile (ply_image_get_buffer (plugin->background_tile_image), screen_width, screen_height);
|
||
|
ply_pixel_buffer_fill_with_buffer (view->background_buffer, buffer, 0, 0);
|
||
|
ply_pixel_buffer_free (buffer);
|
||
|
}
|
||
|
|
||
|
if (view->watermark_image == NULL && plugin->mode_settings[plugin->mode].watermark_imagename) {
|
||
|
image_path = detect_image(plugin->mode_settings[plugin->mode].watermark_imagename,
|
||
|
screen_width, screen_height);
|
||
|
ply_trace ("assing watermark %s", image_path);
|
||
|
view->watermark_image = ply_image_new (image_path);
|
||
|
free (image_path);
|
||
|
}
|
||
|
if (view->watermark_image != NULL) {
|
||
|
ply_trace ("loading watermark image");
|
||
|
if (!ply_image_load (view->watermark_image)) {
|
||
|
ply_image_free (view->watermark_image);
|
||
|
view->watermark_image = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (view->watermark_image != NULL) {
|
||
|
view->watermark_area.width = ply_image_get_width (view->watermark_image);
|
||
|
view->watermark_area.height = ply_image_get_height (view->watermark_image);
|
||
|
view->watermark_area.x = screen_width * plugin->watermark_horizontal_alignment - ply_image_get_width (view->watermark_image) * plugin->watermark_horizontal_alignment;
|
||
|
view->watermark_area.y = screen_height * plugin->watermark_vertical_alignment - ply_image_get_height (view->watermark_image) * plugin->watermark_vertical_alignment;
|
||
|
ply_trace ("using %ldx%ld watermark centered at %ldx%ld for %ldx%ld screen",
|
||
|
view->watermark_area.width, view->watermark_area.height,
|
||
|
view->watermark_area.x, view->watermark_area.y,
|
||
|
screen_width, screen_height);
|
||
|
}
|
||
|
|
||
|
ply_trace ("loading entry");
|
||
|
if (!ply_entry_load (view->entry))
|
||
|
return false;
|
||
|
|
||
|
ply_keymap_icon_load (view->keymap_icon);
|
||
|
ply_capslock_icon_load (view->capslock_icon);
|
||
|
|
||
|
view_load_end_animation (view);
|
||
|
|
||
|
if (view->progress_animation != NULL) {
|
||
|
ply_trace ("loading progress animation");
|
||
|
if (!ply_progress_animation_load (view->progress_animation)) {
|
||
|
ply_trace ("optional progress animation wouldn't load");
|
||
|
ply_progress_animation_free (view->progress_animation);
|
||
|
view->progress_animation = NULL;
|
||
|
}
|
||
|
} else {
|
||
|
ply_trace ("this theme has no progress animation");
|
||
|
}
|
||
|
|
||
|
if (view->throbber != NULL) {
|
||
|
ply_trace ("loading throbber");
|
||
|
if (!ply_throbber_load (view->throbber)) {
|
||
|
ply_trace ("optional throbber was not loaded");
|
||
|
ply_throbber_free (view->throbber);
|
||
|
view->throbber = NULL;
|
||
|
}
|
||
|
} else {
|
||
|
ply_trace ("this theme has no throbber\n");
|
||
|
}
|
||
|
|
||
|
if (plugin->mode_settings[plugin->mode].title) {
|
||
|
ply_label_set_text (view->title_label,
|
||
|
_(plugin->mode_settings[plugin->mode].title));
|
||
|
title_height = ply_label_get_height (view->title_label);
|
||
|
} else {
|
||
|
ply_label_hide (view->title_label);
|
||
|
}
|
||
|
|
||
|
if (plugin->mode_settings[plugin->mode].subtitle) {
|
||
|
ply_label_set_text (view->subtitle_label,
|
||
|
_(plugin->mode_settings[plugin->mode].subtitle));
|
||
|
subtitle_height = ply_label_get_height (view->subtitle_label);
|
||
|
} else {
|
||
|
ply_label_hide (view->subtitle_label);
|
||
|
}
|
||
|
|
||
|
y = (screen_height - title_height - 2 * subtitle_height) * plugin->title_vertical_alignment;
|
||
|
|
||
|
view->title_area.width = 0;
|
||
|
view->title_area.height = 0;
|
||
|
view->title_area.x = -1;
|
||
|
view->title_area.y = 0;
|
||
|
if (plugin->mode_settings[plugin->mode].title) {
|
||
|
width = ply_label_get_width (view->title_label);
|
||
|
x = (screen_width - width) * plugin->title_horizontal_alignment;
|
||
|
ply_trace ("using %ldx%ld title centered at %ldx%ld for %ldx%ld screen",
|
||
|
width, title_height, x, y, screen_width, screen_height);
|
||
|
ply_label_show (view->title_label, view->display, x, y);
|
||
|
view->title_area.width = width;
|
||
|
view->title_area.height = 2 * title_height;
|
||
|
view->title_area.x = x;
|
||
|
view->title_area.y = y;
|
||
|
|
||
|
/* Use subtitle_height pixels seperation between title and subtitle */
|
||
|
y += title_height + subtitle_height;
|
||
|
}
|
||
|
|
||
|
if (plugin->mode_settings[plugin->mode].subtitle) {
|
||
|
width = ply_label_get_width (view->subtitle_label);
|
||
|
x = (screen_width - width) * plugin->title_horizontal_alignment;
|
||
|
ply_trace ("using %ldx%ld subtitle centered at %ldx%ld for %ldx%ld screen",
|
||
|
width, subtitle_height, x, y, screen_width, screen_height);
|
||
|
ply_label_show (view->subtitle_label, view->display, x, y);
|
||
|
if( x == -1 || x < view->title_area.x ) {
|
||
|
view->title_area.x = x;
|
||
|
}
|
||
|
if( width > view->title_area.width ) {
|
||
|
view->title_area.width = width;
|
||
|
}
|
||
|
if (view->title_area.height != 0) {
|
||
|
view->title_area.height = title_height + subtitle_height + subtitle_height * 2;
|
||
|
} else {
|
||
|
view->title_area.height = subtitle_height * 2;
|
||
|
}
|
||
|
}
|
||
|
uint32_t title_color = 0xff00ff;
|
||
|
title_color = plugin->mode_settings[plugin->mode].title_color;
|
||
|
|
||
|
if(view->title_label) {
|
||
|
ply_label_set_color(view->title_label,
|
||
|
((title_color >> 16) & 0xff) / 255.0f,
|
||
|
((title_color >> 8) & 0xff) / 255.0f,
|
||
|
(title_color & 0xff) / 255.0f,
|
||
|
1.0f);
|
||
|
ply_label_set_color(view->subtitle_label,
|
||
|
((title_color >> 16) & 0xff) / 255.0f,
|
||
|
((title_color >> 8) & 0xff) / 255.0f,
|
||
|
(title_color & 0xff) / 255.0f,
|
||
|
1.0f);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static bool
|
||
|
load_views (ply_boot_splash_plugin_t *plugin)
|
||
|
{
|
||
|
ply_list_node_t *node;
|
||
|
bool view_loaded;
|
||
|
view_t *view;
|
||
|
|
||
|
view_loaded = false;
|
||
|
node = ply_list_get_first_node (plugin->views);
|
||
|
|
||
|
while (node != NULL) {
|
||
|
view = ply_list_node_get_data (node);
|
||
|
|
||
|
if (view_load (view))
|
||
|
view_loaded = true;
|
||
|
|
||
|
node = ply_list_get_next_node (plugin->views, node);
|
||
|
}
|
||
|
|
||
|
return view_loaded;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
view_redraw (view_t *view)
|
||
|
{
|
||
|
unsigned long screen_width, screen_height;
|
||
|
|
||
|
screen_width = ply_pixel_display_get_width (view->display);
|
||
|
screen_height = ply_pixel_display_get_height (view->display);
|
||
|
|
||
|
ply_pixel_display_draw_area (view->display, 0, 0,
|
||
|
screen_width, screen_height);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
redraw_views (ply_boot_splash_plugin_t *plugin)
|
||
|
{
|
||
|
ply_list_node_t *node;
|
||
|
view_t *view;
|
||
|
|
||
|
node = ply_list_get_first_node (plugin->views);
|
||
|
while (node != NULL) {
|
||
|
view = ply_list_node_get_data (node);
|
||
|
view_redraw (view);
|
||
|
node = ply_list_get_next_node (plugin->views, node);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pause_views (ply_boot_splash_plugin_t *plugin)
|
||
|
{
|
||
|
ply_list_node_t *node;
|
||
|
view_t *view;
|
||
|
|
||
|
ply_trace ("pausing views");
|
||
|
|
||
|
node = ply_list_get_first_node (plugin->views);
|
||
|
while (node != NULL) {
|
||
|
view = ply_list_node_get_data (node);
|
||
|
ply_pixel_display_pause_updates (view->display);
|
||
|
node = ply_list_get_next_node (plugin->views, node);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
unpause_views (ply_boot_splash_plugin_t *plugin)
|
||
|
{
|
||
|
ply_list_node_t *node;
|
||
|
view_t *view;
|
||
|
|
||
|
ply_trace ("unpausing views");
|
||
|
|
||
|
node = ply_list_get_first_node (plugin->views);
|
||
|
while (node != NULL) {
|
||
|
view = ply_list_node_get_data (node);
|
||
|
ply_pixel_display_unpause_updates (view->display);
|
||
|
node = ply_list_get_next_node (plugin->views, node);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
view_start_end_animation (view_t *view,
|
||
|
ply_trigger_t *trigger)
|
||
|
{
|
||
|
ply_boot_splash_plugin_t *plugin = view->plugin;
|
||
|
unsigned long screen_width, screen_height;
|
||
|
long x, y, width, height;
|
||
|
|
||
|
ply_progress_bar_hide (view->progress_bar);
|
||
|
if (view->progress_animation != NULL)
|
||
|
ply_progress_animation_hide (view->progress_animation);
|
||
|
|
||
|
screen_width = ply_pixel_display_get_width (view->display);
|
||
|
screen_height = ply_pixel_display_get_height (view->display);
|
||
|
width = ply_animation_get_width (view->end_animation);
|
||
|
height = ply_animation_get_height (view->end_animation);
|
||
|
x = plugin->mode_settings[plugin->mode].animation_horizontal_alignment * screen_width - width / 2.0;
|
||
|
y = calculate_animation_y(view,
|
||
|
plugin->mode_settings[plugin->mode].animation_vertical_alignment,
|
||
|
plugin->mode_settings[plugin->mode].animation_vertical_alignment_type,
|
||
|
screen_height, height);
|
||
|
|
||
|
ply_trace ("starting end sequence animation for %ldx%ld view", width, height);
|
||
|
ply_animation_start (view->end_animation,
|
||
|
view->display,
|
||
|
trigger, x, y);
|
||
|
view->animation_bottom = y + height;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
on_view_throbber_stopped (view_t *view)
|
||
|
{
|
||
|
view_start_end_animation (view, view->end_trigger);
|
||
|
view->end_trigger = NULL;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
view_start_progress_animation (view_t *view)
|
||
|
{
|
||
|
ply_boot_splash_plugin_t *plugin;
|
||
|
|
||
|
long x, y;
|
||
|
long width, height;
|
||
|
unsigned long screen_width, screen_height;
|
||
|
|
||
|
assert (view != NULL);
|
||
|
|
||
|
plugin = view->plugin;
|
||
|
|
||
|
plugin->is_idle = false;
|
||
|
|
||
|
screen_width = ply_pixel_display_get_width (view->display);
|
||
|
screen_height = ply_pixel_display_get_height (view->display);
|
||
|
|
||
|
ply_pixel_display_draw_area (view->display, 0, 0,
|
||
|
screen_width, screen_height);
|
||
|
|
||
|
if (plugin->mode_settings[plugin->mode].use_progress_bar) {
|
||
|
if (plugin->progress_bar_width != -1)
|
||
|
width = plugin->progress_bar_width;
|
||
|
else
|
||
|
width = screen_width;
|
||
|
height = plugin->progress_bar_height;
|
||
|
x = plugin->progress_bar_horizontal_alignment * (screen_width - width);
|
||
|
//y = plugin->progress_bar_vertical_alignment * (screen_height - height);
|
||
|
y = calculate_animation_y(view,
|
||
|
plugin->progress_bar_vertical_alignment,
|
||
|
plugin->mode_settings[plugin->mode].animation_vertical_alignment_type,
|
||
|
screen_height, height);
|
||
|
ply_progress_bar_show (view->progress_bar, view->display,
|
||
|
x, y, width, height);
|
||
|
ply_pixel_display_draw_area (view->display, x, y, width, height);
|
||
|
view->animation_bottom = y + height;
|
||
|
}
|
||
|
|
||
|
if (plugin->mode_settings[plugin->mode].use_animation &&
|
||
|
view->throbber != NULL) {
|
||
|
width = ply_throbber_get_width (view->throbber);
|
||
|
height = ply_throbber_get_height (view->throbber);
|
||
|
x = plugin->mode_settings[plugin->mode].animation_horizontal_alignment * screen_width - width / 2.0;
|
||
|
|
||
|
y = calculate_animation_y(view,
|
||
|
plugin->mode_settings[plugin->mode].animation_vertical_alignment,
|
||
|
plugin->mode_settings[plugin->mode].animation_vertical_alignment_type,
|
||
|
screen_height, height);
|
||
|
ply_throbber_start (view->throbber,
|
||
|
plugin->loop,
|
||
|
view->display, x, y);
|
||
|
ply_pixel_display_draw_area (view->display, x, y, width, height);
|
||
|
view->animation_bottom = y + height;
|
||
|
}
|
||
|
|
||
|
/* We don't really know how long shutdown will so
|
||
|
* don't show the progress animation
|
||
|
*/
|
||
|
if (plugin->mode == PLY_BOOT_SPLASH_MODE_SHUTDOWN ||
|
||
|
plugin->mode == PLY_BOOT_SPLASH_MODE_REBOOT)
|
||
|
return;
|
||
|
|
||
|
if (plugin->mode_settings[plugin->mode].use_animation &&
|
||
|
view->progress_animation != NULL) {
|
||
|
width = ply_progress_animation_get_width (view->progress_animation);
|
||
|
height = ply_progress_animation_get_height (view->progress_animation);
|
||
|
x = plugin->mode_settings[plugin->mode].animation_horizontal_alignment * screen_width - width / 2.0;
|
||
|
y = calculate_animation_y(view,
|
||
|
plugin->mode_settings[plugin->mode].animation_vertical_alignment,
|
||
|
plugin->mode_settings[plugin->mode].animation_vertical_alignment_type,
|
||
|
screen_height, height);
|
||
|
ply_progress_animation_show (view->progress_animation,
|
||
|
view->display, x, y);
|
||
|
|
||
|
ply_pixel_display_draw_area (view->display, x, y, width, height);
|
||
|
view->animation_bottom = y + height;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
view_show_prompt (view_t *view,
|
||
|
const char *prompt,
|
||
|
const char *entry_text,
|
||
|
int number_of_bullets)
|
||
|
{
|
||
|
ply_boot_splash_plugin_t *plugin;
|
||
|
unsigned long screen_width, screen_height, entry_width, entry_height;
|
||
|
unsigned long keyboard_indicator_width, keyboard_indicator_height;
|
||
|
bool show_keyboard_indicators = false;
|
||
|
long dialog_bottom;
|
||
|
int x, y;
|
||
|
|
||
|
assert (view != NULL);
|
||
|
|
||
|
plugin = view->plugin;
|
||
|
|
||
|
screen_width = ply_pixel_display_get_width (view->display);
|
||
|
screen_height = ply_pixel_display_get_height (view->display);
|
||
|
|
||
|
if (ply_entry_is_hidden (view->entry)) {
|
||
|
view->lock_area.width = ply_image_get_width (plugin->lock_image);
|
||
|
view->lock_area.height = ply_image_get_height (plugin->lock_image);
|
||
|
|
||
|
entry_width = ply_entry_get_width (view->entry);
|
||
|
entry_height = ply_entry_get_height (view->entry);
|
||
|
|
||
|
if (plugin->box_image) {
|
||
|
view->box_area.width = ply_image_get_width (plugin->box_image);
|
||
|
view->box_area.height = ply_image_get_height (plugin->box_image);
|
||
|
view->box_area.x = (screen_width - view->box_area.width) * plugin->dialog_horizontal_alignment;
|
||
|
view->box_area.y = (screen_height - view->box_area.height) * plugin->dialog_vertical_alignment;
|
||
|
view->dialog_area = view->box_area;
|
||
|
} else {
|
||
|
view->dialog_area.width = view->lock_area.width + entry_width;
|
||
|
view->dialog_area.height = MAX(view->lock_area.height, entry_height);
|
||
|
view->dialog_area.x = (screen_width - view->dialog_area.width) * plugin->dialog_horizontal_alignment;
|
||
|
view->dialog_area.y = (screen_height - view->dialog_area.height) * plugin->dialog_vertical_alignment;
|
||
|
}
|
||
|
|
||
|
view->lock_area.x =
|
||
|
view->dialog_area.x +
|
||
|
(view->dialog_area.width -
|
||
|
(view->lock_area.width + entry_width)) / 2.0;
|
||
|
view->lock_area.y =
|
||
|
view->dialog_area.y +
|
||
|
(view->dialog_area.height - view->lock_area.height) / 2.0;
|
||
|
|
||
|
x = view->lock_area.x + view->lock_area.width;
|
||
|
y = view->dialog_area.y +
|
||
|
(view->dialog_area.height - entry_height) / 2.0;
|
||
|
|
||
|
ply_entry_show (view->entry, plugin->loop, view->display, x, y);
|
||
|
|
||
|
show_keyboard_indicators = true;
|
||
|
}
|
||
|
|
||
|
if (entry_text != NULL)
|
||
|
ply_entry_set_text (view->entry, entry_text);
|
||
|
|
||
|
if (number_of_bullets != -1)
|
||
|
ply_entry_set_bullet_count (view->entry, number_of_bullets);
|
||
|
|
||
|
dialog_bottom = view->dialog_area.y + view->dialog_area.height;
|
||
|
|
||
|
if (prompt != NULL) {
|
||
|
ply_label_set_text (view->label, prompt);
|
||
|
|
||
|
/* We center the prompt in the middle and use 80% of the horizontal space */
|
||
|
int label_width = screen_width * 100 / 80;
|
||
|
ply_label_set_alignment (view->label, PLY_LABEL_ALIGN_CENTER);
|
||
|
ply_label_set_width (view->label, label_width);
|
||
|
|
||
|
x = (screen_width - label_width) / 2;
|
||
|
y = dialog_bottom;
|
||
|
|
||
|
ply_label_show (view->label, view->display, x, y);
|
||
|
|
||
|
dialog_bottom += ply_label_get_height (view->label);
|
||
|
}
|
||
|
|
||
|
if (show_keyboard_indicators) {
|
||
|
keyboard_indicator_width =
|
||
|
ply_keymap_icon_get_width (view->keymap_icon);
|
||
|
keyboard_indicator_height = MAX(
|
||
|
ply_capslock_icon_get_height (view->capslock_icon),
|
||
|
ply_keymap_icon_get_height (view->keymap_icon));
|
||
|
|
||
|
x = (screen_width - keyboard_indicator_width) * plugin->dialog_horizontal_alignment;
|
||
|
y = dialog_bottom + keyboard_indicator_height / 2 +
|
||
|
(keyboard_indicator_height - ply_keymap_icon_get_height (view->keymap_icon)) / 2.0;
|
||
|
ply_keymap_icon_show (view->keymap_icon, x, y);
|
||
|
|
||
|
x += ply_keymap_icon_get_width (view->keymap_icon);
|
||
|
y = dialog_bottom + keyboard_indicator_height / 2 +
|
||
|
(keyboard_indicator_height - ply_capslock_icon_get_height (view->capslock_icon)) / 2.0;
|
||
|
ply_capslock_icon_show (view->capslock_icon, plugin->loop, view->display, x, y);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
view_hide_prompt (view_t *view)
|
||
|
{
|
||
|
assert (view != NULL);
|
||
|
|
||
|
ply_entry_hide (view->entry);
|
||
|
ply_capslock_icon_hide (view->capslock_icon);
|
||
|
ply_keymap_icon_hide (view->keymap_icon);
|
||
|
ply_label_hide (view->label);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
load_mode_settings (ply_boot_splash_plugin_t *plugin,
|
||
|
ply_key_file_t *key_file,
|
||
|
const char *group_name,
|
||
|
ply_boot_splash_mode_t mode)
|
||
|
{
|
||
|
mode_settings_t *settings = &plugin->mode_settings[mode];
|
||
|
|
||
|
settings->suppress_messages =
|
||
|
ply_key_file_get_bool (key_file, group_name, "SuppressMessages");
|
||
|
settings->progress_bar_show_percent_complete =
|
||
|
ply_key_file_get_bool (key_file, group_name, "ProgressBarShowPercentComplete");
|
||
|
settings->use_progress_bar =
|
||
|
ply_key_file_get_bool (key_file, group_name, "UseProgressBar");
|
||
|
settings->use_firmware_background =
|
||
|
ply_key_file_get_bool (key_file, group_name, "UseFirmwareBackground");
|
||
|
|
||
|
/* This defaults to !use_progress_bar for compat. with older themes */
|
||
|
if (ply_key_file_has_key (key_file, group_name, "UseAnimation"))
|
||
|
settings->use_animation =
|
||
|
ply_key_file_get_bool (key_file, group_name, "UseAnimation");
|
||
|
else
|
||
|
settings->use_animation = !settings->use_progress_bar;
|
||
|
|
||
|
/* This defaults to true for compat. with older themes */
|
||
|
if (ply_key_file_has_key (key_file, group_name, "UseEndAnimation"))
|
||
|
settings->use_end_animation =
|
||
|
ply_key_file_get_bool (key_file, group_name, "UseEndAnimation");
|
||
|
else
|
||
|
settings->use_end_animation = true;
|
||
|
|
||
|
/* If any mode uses the firmware background, then we need to load it */
|
||
|
if (settings->use_firmware_background)
|
||
|
plugin->use_firmware_background = true;
|
||
|
|
||
|
settings->watermark_imagename = ply_key_file_get_value (key_file, group_name, "WatermarkImage");
|
||
|
if( settings->watermark_imagename == NULL &&
|
||
|
plugin->watermark_imagename != NULL )
|
||
|
settings->watermark_imagename = strdup(plugin->watermark_imagename);
|
||
|
|
||
|
settings->title = ply_key_file_get_value (key_file, group_name, "Title");
|
||
|
settings->subtitle = ply_key_file_get_value (key_file, group_name, "SubTitle");
|
||
|
|
||
|
settings->title_color = ply_key_file_get_long (key_file, group_name, "TitleColor",
|
||
|
plugin->title_color);
|
||
|
|
||
|
settings->background_start_color =
|
||
|
ply_key_file_get_long (key_file, group_name,
|
||
|
"BackgroundStartColor",
|
||
|
plugin->background_start_color);
|
||
|
settings->background_end_color =
|
||
|
ply_key_file_get_long (key_file, group_name,
|
||
|
"BackgroundEndColor",
|
||
|
plugin->background_end_color);
|
||
|
|
||
|
/* Throbber, progress- and end-animation alignment */
|
||
|
settings->animation_horizontal_alignment =
|
||
|
ply_key_file_get_double (key_file, group_name,
|
||
|
"HorizontalAlignment", plugin->animation_horizontal_alignment);
|
||
|
settings->animation_vertical_alignment =
|
||
|
ply_key_file_get_double (key_file, group_name,
|
||
|
"VerticalAlignment", plugin->animation_vertical_alignment);
|
||
|
settings->animation_vertical_alignment_type =
|
||
|
ply_key_file_get_value (key_file, group_name,
|
||
|
"VerticalAlignmentType");
|
||
|
if( settings->animation_vertical_alignment_type == NULL &&
|
||
|
plugin->animation_vertical_alignment_type != NULL )
|
||
|
settings->animation_vertical_alignment_type = strdup(plugin->animation_vertical_alignment_type);
|
||
|
}
|
||
|
|
||
|
static ply_boot_splash_plugin_t *
|
||
|
create_plugin (ply_key_file_t *key_file)
|
||
|
{
|
||
|
ply_boot_splash_plugin_t *plugin;
|
||
|
char *image_dir, *image_path;
|
||
|
char *transition;
|
||
|
char *progress_function;
|
||
|
|
||
|
srand ((int) ply_get_timestamp ());
|
||
|
plugin = calloc (1, sizeof(ply_boot_splash_plugin_t));
|
||
|
|
||
|
image_dir = ply_key_file_get_value (key_file, "calculate", "ImageDir");
|
||
|
|
||
|
ply_trace ("Using '%s' as working directory", image_dir);
|
||
|
|
||
|
asprintf (&image_path, "%s/lock.png", image_dir);
|
||
|
plugin->lock_image = ply_image_new (image_path);
|
||
|
free (image_path);
|
||
|
|
||
|
asprintf (&image_path, "%s/box.png", image_dir);
|
||
|
plugin->box_image = ply_image_new (image_path);
|
||
|
free (image_path);
|
||
|
|
||
|
asprintf (&image_path, "%s/corner-image.png", image_dir);
|
||
|
plugin->corner_image = ply_image_new (image_path);
|
||
|
free (image_path);
|
||
|
|
||
|
asprintf (&image_path, "%s/header-image.png", image_dir);
|
||
|
plugin->header_image = ply_image_new (image_path);
|
||
|
free (image_path);
|
||
|
|
||
|
asprintf (&image_path, "%s/background-tile.png", image_dir);
|
||
|
plugin->background_tile_image = ply_image_new (image_path);
|
||
|
free (image_path);
|
||
|
|
||
|
plugin->animation_dir = image_dir;
|
||
|
|
||
|
plugin->font = ply_key_file_get_value (key_file, "calculate", "Font");
|
||
|
plugin->title_font = ply_key_file_get_value (key_file, "calculate", "TitleFont");
|
||
|
|
||
|
/* Throbber, progress- and end-animation alignment */
|
||
|
plugin->animation_horizontal_alignment =
|
||
|
ply_key_file_get_double (key_file, "calculate",
|
||
|
"HorizontalAlignment", 0.5);
|
||
|
plugin->animation_vertical_alignment =
|
||
|
ply_key_file_get_double (key_file, "calculate",
|
||
|
"VerticalAlignment", 0.5);
|
||
|
plugin->animation_vertical_alignment_type =
|
||
|
ply_key_file_get_value (key_file, "calculate",
|
||
|
"VerticalAlignmentType");
|
||
|
|
||
|
/* Progressbar alignment, this defaults to the animation alignment
|
||
|
* for compatibility with older themes.
|
||
|
*/
|
||
|
plugin->progress_bar_horizontal_alignment =
|
||
|
ply_key_file_get_double (key_file, "calculate",
|
||
|
"ProgressBarHorizontalAlignment",
|
||
|
plugin->animation_horizontal_alignment);
|
||
|
plugin->progress_bar_vertical_alignment =
|
||
|
ply_key_file_get_double (key_file, "calculate",
|
||
|
"ProgressBarVerticalAlignment",
|
||
|
plugin->animation_vertical_alignment);
|
||
|
|
||
|
/* Watermark alignment */
|
||
|
plugin->watermark_horizontal_alignment =
|
||
|
ply_key_file_get_double (key_file, "calculate",
|
||
|
"WatermarkHorizontalAlignment", 1.0);
|
||
|
plugin->watermark_vertical_alignment =
|
||
|
ply_key_file_get_double (key_file, "calculate",
|
||
|
"WatermarkVerticalAlignment", 0.5);
|
||
|
|
||
|
/* Password (or other) dialog alignment */
|
||
|
plugin->dialog_horizontal_alignment =
|
||
|
ply_key_file_get_double (key_file, "calculate",
|
||
|
"DialogHorizontalAlignment", 0.5);
|
||
|
plugin->dialog_vertical_alignment =
|
||
|
ply_key_file_get_double (key_file, "calculate",
|
||
|
"DialogVerticalAlignment", 0.5);
|
||
|
|
||
|
/* Title alignment */
|
||
|
plugin->title_horizontal_alignment =
|
||
|
ply_key_file_get_double (key_file, "calculate",
|
||
|
"TitleHorizontalAlignment", 0.5);
|
||
|
plugin->title_vertical_alignment =
|
||
|
ply_key_file_get_double (key_file, "calculate",
|
||
|
"TitleVerticalAlignment", 0.5);
|
||
|
|
||
|
plugin->transition = PLY_PROGRESS_ANIMATION_TRANSITION_NONE;
|
||
|
transition = ply_key_file_get_value (key_file, "calculate", "Transition");
|
||
|
if (transition != NULL) {
|
||
|
if (strcmp (transition, "fade-over") == 0)
|
||
|
plugin->transition = PLY_PROGRESS_ANIMATION_TRANSITION_FADE_OVER;
|
||
|
else if (strcmp (transition, "cross-fade") == 0)
|
||
|
plugin->transition = PLY_PROGRESS_ANIMATION_TRANSITION_CROSS_FADE;
|
||
|
else if (strcmp (transition, "merge-fade") == 0)
|
||
|
plugin->transition = PLY_PROGRESS_ANIMATION_TRANSITION_MERGE_FADE;
|
||
|
}
|
||
|
free (transition);
|
||
|
|
||
|
plugin->transition_duration =
|
||
|
ply_key_file_get_double (key_file, "calculate",
|
||
|
"TransitionDuration", 0.0);
|
||
|
|
||
|
plugin->background_start_color =
|
||
|
ply_key_file_get_long (key_file, "calculate",
|
||
|
"BackgroundStartColor",
|
||
|
PLYMOUTH_BACKGROUND_START_COLOR);
|
||
|
plugin->background_end_color =
|
||
|
ply_key_file_get_long (key_file, "calculate",
|
||
|
"BackgroundEndColor",
|
||
|
PLYMOUTH_BACKGROUND_END_COLOR);
|
||
|
plugin->title_color = ply_key_file_get_long (
|
||
|
key_file, "calculate", "TitleColor", 0xffffff);
|
||
|
|
||
|
plugin->progress_bar_bg_color =
|
||
|
ply_key_file_get_long (key_file, "calculate",
|
||
|
"ProgressBarBackgroundColor",
|
||
|
0xffffff /* white */);
|
||
|
plugin->progress_bar_fg_color =
|
||
|
ply_key_file_get_long (key_file, "calculate",
|
||
|
"ProgressBarForegroundColor",
|
||
|
0x000000 /* black */);
|
||
|
plugin->progress_bar_width =
|
||
|
ply_key_file_get_long (key_file, "calculate",
|
||
|
"ProgressBarWidth",
|
||
|
PROGRESS_BAR_WIDTH);
|
||
|
plugin->progress_bar_height =
|
||
|
ply_key_file_get_long (key_file, "calculate",
|
||
|
"ProgressBarHeight",
|
||
|
PROGRESS_BAR_HEIGHT);
|
||
|
|
||
|
plugin->watermark_imagename = ply_key_file_get_value (key_file, "calculate", "WatermarkImage");
|
||
|
|
||
|
load_mode_settings (plugin, key_file, "boot-up", PLY_BOOT_SPLASH_MODE_BOOT_UP);
|
||
|
load_mode_settings (plugin, key_file, "shutdown", PLY_BOOT_SPLASH_MODE_SHUTDOWN);
|
||
|
load_mode_settings (plugin, key_file, "reboot", PLY_BOOT_SPLASH_MODE_REBOOT);
|
||
|
load_mode_settings (plugin, key_file, "updates", PLY_BOOT_SPLASH_MODE_UPDATES);
|
||
|
load_mode_settings (plugin, key_file, "system-upgrade", PLY_BOOT_SPLASH_MODE_SYSTEM_UPGRADE);
|
||
|
load_mode_settings (plugin, key_file, "firmware-upgrade", PLY_BOOT_SPLASH_MODE_FIRMWARE_UPGRADE);
|
||
|
|
||
|
if (plugin->use_firmware_background)
|
||
|
plugin->background_bgrt_image = ply_image_new ("/sys/firmware/acpi/bgrt/image");
|
||
|
|
||
|
plugin->dialog_clears_firmware_background =
|
||
|
ply_key_file_get_bool (key_file, "calculate", "DialogClearsFirmwareBackground");
|
||
|
|
||
|
plugin->message_below_animation =
|
||
|
ply_key_file_get_bool (key_file, "calculate", "MessageBelowAnimation");
|
||
|
|
||
|
progress_function = ply_key_file_get_value (key_file, "calculate", "ProgressFunction");
|
||
|
|
||
|
if (progress_function != NULL) {
|
||
|
if (strcmp (progress_function, "wwoods") == 0) {
|
||
|
ply_trace ("Using wwoods progress function");
|
||
|
plugin->progress_function = PROGRESS_FUNCTION_TYPE_WWOODS;
|
||
|
} else if (strcmp (progress_function, "linear") == 0) {
|
||
|
ply_trace ("Using linear progress function");
|
||
|
plugin->progress_function = PROGRESS_FUNCTION_TYPE_LINEAR;
|
||
|
} else {
|
||
|
ply_trace ("unknown progress function %s, defaulting to linear", progress_function);
|
||
|
plugin->progress_function = PROGRESS_FUNCTION_TYPE_LINEAR;
|
||
|
}
|
||
|
|
||
|
free (progress_function);
|
||
|
}
|
||
|
|
||
|
plugin->views = ply_list_new ();
|
||
|
|
||
|
return plugin;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
free_views (ply_boot_splash_plugin_t *plugin)
|
||
|
{
|
||
|
ply_list_node_t *node;
|
||
|
|
||
|
ply_trace ("freeing views");
|
||
|
|
||
|
node = ply_list_get_first_node (plugin->views);
|
||
|
|
||
|
while (node != NULL) {
|
||
|
ply_list_node_t *next_node;
|
||
|
view_t *view;
|
||
|
|
||
|
view = ply_list_node_get_data (node);
|
||
|
next_node = ply_list_get_next_node (plugin->views, node);
|
||
|
|
||
|
view_free (view);
|
||
|
ply_list_remove_node (plugin->views, node);
|
||
|
|
||
|
node = next_node;
|
||
|
}
|
||
|
|
||
|
ply_list_free (plugin->views);
|
||
|
plugin->views = NULL;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
destroy_plugin (ply_boot_splash_plugin_t *plugin)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if (plugin == NULL)
|
||
|
return;
|
||
|
|
||
|
ply_trace ("destroying 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,
|
||
|
plugin);
|
||
|
detach_from_event_loop (plugin);
|
||
|
}
|
||
|
|
||
|
ply_image_free (plugin->lock_image);
|
||
|
|
||
|
if (plugin->box_image != NULL)
|
||
|
ply_image_free (plugin->box_image);
|
||
|
|
||
|
if (plugin->corner_image != NULL)
|
||
|
ply_image_free (plugin->corner_image);
|
||
|
|
||
|
if (plugin->header_image != NULL)
|
||
|
ply_image_free (plugin->header_image);
|
||
|
|
||
|
if (plugin->background_tile_image != NULL)
|
||
|
ply_image_free (plugin->background_tile_image);
|
||
|
|
||
|
if (plugin->background_bgrt_image != NULL)
|
||
|
ply_image_free (plugin->background_bgrt_image);
|
||
|
|
||
|
for (i = 0; i < PLY_BOOT_SPLASH_MODE_COUNT; i++) {
|
||
|
free (plugin->mode_settings[i].title);
|
||
|
free (plugin->mode_settings[i].watermark_imagename);
|
||
|
free (plugin->mode_settings[i].subtitle);
|
||
|
free (plugin->mode_settings[i].animation_vertical_alignment_type);
|
||
|
}
|
||
|
|
||
|
free (plugin->font);
|
||
|
free (plugin->title_font);
|
||
|
free (plugin->animation_vertical_alignment_type);
|
||
|
free (plugin->animation_dir);
|
||
|
free (plugin->watermark_imagename);
|
||
|
free_views (plugin);
|
||
|
free (plugin);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
start_end_animation (ply_boot_splash_plugin_t *plugin,
|
||
|
ply_trigger_t *trigger)
|
||
|
{
|
||
|
ply_list_node_t *node;
|
||
|
view_t *view;
|
||
|
|
||
|
if (!plugin->mode_settings[plugin->mode].use_animation) {
|
||
|
ply_trigger_pull (trigger, NULL);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!plugin->mode_settings[plugin->mode].use_end_animation) {
|
||
|
node = ply_list_get_first_node (plugin->views);
|
||
|
while (node != NULL) {
|
||
|
view = ply_list_node_get_data (node);
|
||
|
|
||
|
ply_progress_bar_hide (view->progress_bar);
|
||
|
|
||
|
if (view->throbber != NULL)
|
||
|
ply_throbber_stop (view->throbber, NULL);
|
||
|
|
||
|
if (view->progress_animation != NULL)
|
||
|
ply_progress_animation_hide (view->progress_animation);
|
||
|
|
||
|
node = ply_list_get_next_node (plugin->views, node);
|
||
|
}
|
||
|
ply_trigger_pull (trigger, NULL);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ply_trace ("starting end animation");
|
||
|
|
||
|
node = ply_list_get_first_node (plugin->views);
|
||
|
while (node != NULL) {
|
||
|
view = ply_list_node_get_data (node);
|
||
|
|
||
|
ply_trigger_ignore_next_pull (trigger);
|
||
|
|
||
|
if (view->throbber != NULL) {
|
||
|
ply_trigger_t *throbber_trigger;
|
||
|
ply_trace ("stopping throbber");
|
||
|
view->end_trigger = trigger;
|
||
|
throbber_trigger = ply_trigger_new (NULL);
|
||
|
ply_trigger_add_handler (throbber_trigger,
|
||
|
(ply_trigger_handler_t)
|
||
|
on_view_throbber_stopped,
|
||
|
view);
|
||
|
ply_throbber_stop (view->throbber, throbber_trigger);
|
||
|
} else {
|
||
|
view_start_end_animation (view, trigger);
|
||
|
}
|
||
|
|
||
|
node = ply_list_get_next_node (plugin->views, node);
|
||
|
}
|
||
|
ply_trigger_pull (trigger, NULL);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
start_progress_animation (ply_boot_splash_plugin_t *plugin)
|
||
|
{
|
||
|
ply_list_node_t *node;
|
||
|
view_t *view;
|
||
|
|
||
|
if (plugin->is_animating)
|
||
|
return;
|
||
|
|
||
|
ply_trace ("starting animation");
|
||
|
|
||
|
node = ply_list_get_first_node (plugin->views);
|
||
|
while (node != NULL) {
|
||
|
view = ply_list_node_get_data (node);
|
||
|
view_start_progress_animation (view);
|
||
|
node = ply_list_get_next_node (plugin->views, node);
|
||
|
}
|
||
|
|
||
|
plugin->is_animating = true;
|
||
|
|
||
|
/* We don't really know how long shutdown will, take
|
||
|
* but it's normally really fast, so just jump to
|
||
|
* the end animation
|
||
|
*/
|
||
|
if (plugin->mode_settings[plugin->mode].use_end_animation &&
|
||
|
(plugin->mode == PLY_BOOT_SPLASH_MODE_SHUTDOWN ||
|
||
|
plugin->mode == PLY_BOOT_SPLASH_MODE_REBOOT))
|
||
|
become_idle (plugin, NULL);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
stop_animation (ply_boot_splash_plugin_t *plugin)
|
||
|
{
|
||
|
ply_list_node_t *node;
|
||
|
view_t *view;
|
||
|
|
||
|
assert (plugin != NULL);
|
||
|
assert (plugin->loop != NULL);
|
||
|
|
||
|
if (!plugin->is_animating)
|
||
|
return;
|
||
|
|
||
|
ply_trace ("stopping animation");
|
||
|
plugin->is_animating = false;
|
||
|
|
||
|
node = ply_list_get_first_node (plugin->views);
|
||
|
while (node != NULL) {
|
||
|
view = ply_list_node_get_data (node);
|
||
|
|
||
|
ply_progress_bar_hide (view->progress_bar);
|
||
|
if (view->progress_animation != NULL)
|
||
|
ply_progress_animation_hide (view->progress_animation);
|
||
|
if (view->throbber != NULL)
|
||
|
ply_throbber_stop (view->throbber, NULL);
|
||
|
if (view->end_animation != NULL)
|
||
|
ply_animation_stop (view->end_animation);
|
||
|
|
||
|
node = ply_list_get_next_node (plugin->views, node);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
detach_from_event_loop (ply_boot_splash_plugin_t *plugin)
|
||
|
{
|
||
|
plugin->loop = NULL;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
draw_background (view_t *view,
|
||
|
ply_pixel_buffer_t *pixel_buffer,
|
||
|
int x,
|
||
|
int y,
|
||
|
int width,
|
||
|
int height)
|
||
|
{
|
||
|
ply_boot_splash_plugin_t *plugin;
|
||
|
ply_rectangle_t area;
|
||
|
bool use_black_background = false;
|
||
|
|
||
|
plugin = view->plugin;
|
||
|
|
||
|
area.x = x;
|
||
|
area.y = y;
|
||
|
area.width = width;
|
||
|
area.height = height;
|
||
|
|
||
|
/* When using the firmware logo as background and we should not use
|
||
|
* it for this mode, use solid black as background.
|
||
|
*/
|
||
|
if (plugin->background_bgrt_image &&
|
||
|
!plugin->mode_settings[plugin->mode].use_firmware_background)
|
||
|
use_black_background = true;
|
||
|
|
||
|
/* When using the firmware logo as background, use solid black as
|
||
|
* background for dialogs.
|
||
|
*/
|
||
|
if ((plugin->state == PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY ||
|
||
|
plugin->state == PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY) &&
|
||
|
plugin->background_bgrt_image && plugin->dialog_clears_firmware_background)
|
||
|
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)
|
||
|
ply_pixel_buffer_fill_with_buffer (pixel_buffer, view->background_buffer, 0, 0);
|
||
|
else if (plugin->mode_settings[plugin->mode].background_start_color != plugin->mode_settings[plugin->mode].background_end_color)
|
||
|
ply_pixel_buffer_fill_with_gradient (pixel_buffer, &area,
|
||
|
plugin->mode_settings[plugin->mode].background_start_color,
|
||
|
plugin->mode_settings[plugin->mode].background_end_color);
|
||
|
else
|
||
|
ply_pixel_buffer_fill_with_hex_color (pixel_buffer, &area,
|
||
|
plugin->mode_settings[plugin->mode].background_start_color);
|
||
|
|
||
|
if (view->watermark_image != NULL) {
|
||
|
uint32_t *data;
|
||
|
|
||
|
data = ply_image_get_data (view->watermark_image);
|
||
|
ply_pixel_buffer_fill_with_argb32_data (pixel_buffer, &view->watermark_area, data);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
on_draw (view_t *view,
|
||
|
ply_pixel_buffer_t *pixel_buffer,
|
||
|
int x,
|
||
|
int y,
|
||
|
int width,
|
||
|
int height)
|
||
|
{
|
||
|
ply_boot_splash_plugin_t *plugin;
|
||
|
ply_rectangle_t screen_area;
|
||
|
ply_rectangle_t image_area;
|
||
|
|
||
|
plugin = view->plugin;
|
||
|
|
||
|
draw_background (view, pixel_buffer, x, y, width, height);
|
||
|
|
||
|
ply_pixel_buffer_get_size (pixel_buffer, &screen_area);
|
||
|
|
||
|
if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY ||
|
||
|
plugin->state == PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY) {
|
||
|
uint32_t *box_data, *lock_data;
|
||
|
|
||
|
if (plugin->box_image) {
|
||
|
box_data = ply_image_get_data (plugin->box_image);
|
||
|
ply_pixel_buffer_fill_with_argb32_data (pixel_buffer,
|
||
|
&view->box_area,
|
||
|
box_data);
|
||
|
}
|
||
|
|
||
|
ply_entry_draw_area (view->entry,
|
||
|
pixel_buffer,
|
||
|
x, y, width, height);
|
||
|
ply_keymap_icon_draw_area (view->keymap_icon,
|
||
|
pixel_buffer,
|
||
|
x, y, width, height);
|
||
|
ply_capslock_icon_draw_area (view->capslock_icon,
|
||
|
pixel_buffer,
|
||
|
x, y, width, height);
|
||
|
ply_label_draw_area (view->label,
|
||
|
pixel_buffer,
|
||
|
x, y, width, height);
|
||
|
|
||
|
lock_data = ply_image_get_data (plugin->lock_image);
|
||
|
ply_pixel_buffer_fill_with_argb32_data (pixel_buffer,
|
||
|
&view->lock_area,
|
||
|
lock_data);
|
||
|
} else {
|
||
|
if (plugin->mode_settings[plugin->mode].use_progress_bar)
|
||
|
ply_progress_bar_draw_area (view->progress_bar, pixel_buffer,
|
||
|
x, y, width, height);
|
||
|
|
||
|
if (plugin->mode_settings[plugin->mode].use_animation &&
|
||
|
view->throbber != NULL)
|
||
|
ply_throbber_draw_area (view->throbber, pixel_buffer,
|
||
|
x, y, width, height);
|
||
|
|
||
|
if (plugin->mode_settings[plugin->mode].use_animation &&
|
||
|
view->progress_animation != NULL)
|
||
|
ply_progress_animation_draw_area (view->progress_animation,
|
||
|
pixel_buffer,
|
||
|
x, y, width, height);
|
||
|
|
||
|
if (plugin->mode_settings[plugin->mode].use_animation &&
|
||
|
view->end_animation != NULL)
|
||
|
ply_animation_draw_area (view->end_animation,
|
||
|
pixel_buffer,
|
||
|
x, y, width, height);
|
||
|
|
||
|
if (plugin->corner_image != NULL) {
|
||
|
image_area.width = ply_image_get_width (plugin->corner_image);
|
||
|
image_area.height = ply_image_get_height (plugin->corner_image);
|
||
|
image_area.x = screen_area.width - image_area.width - 20;
|
||
|
image_area.y = screen_area.height - image_area.height - 20;
|
||
|
|
||
|
ply_pixel_buffer_fill_with_argb32_data (pixel_buffer, &image_area, ply_image_get_data (plugin->corner_image));
|
||
|
}
|
||
|
|
||
|
if (plugin->header_image != NULL) {
|
||
|
long sprite_height;
|
||
|
|
||
|
|
||
|
if (view->progress_animation != NULL)
|
||
|
sprite_height = ply_progress_animation_get_height (view->progress_animation);
|
||
|
else
|
||
|
sprite_height = 0;
|
||
|
|
||
|
if (view->throbber != NULL)
|
||
|
sprite_height = MAX (ply_throbber_get_height (view->throbber),
|
||
|
sprite_height);
|
||
|
|
||
|
image_area.width = ply_image_get_width (plugin->header_image);
|
||
|
image_area.height = ply_image_get_height (plugin->header_image);
|
||
|
image_area.x = screen_area.width / 2.0 - image_area.width / 2.0;
|
||
|
image_area.y = plugin->mode_settings[plugin->mode].animation_vertical_alignment * screen_area.height - sprite_height / 2.0 - image_area.height;
|
||
|
|
||
|
|
||
|
ply_pixel_buffer_fill_with_argb32_data (pixel_buffer, &image_area, ply_image_get_data (plugin->header_image));
|
||
|
}
|
||
|
ply_label_draw_area (view->title_label,
|
||
|
pixel_buffer,
|
||
|
x, y, width, height);
|
||
|
ply_label_draw_area (view->subtitle_label,
|
||
|
pixel_buffer,
|
||
|
x, y, width, height);
|
||
|
}
|
||
|
ply_label_draw_area (view->message_label,
|
||
|
pixel_buffer,
|
||
|
x, y, width, height);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
add_pixel_display (ply_boot_splash_plugin_t *plugin,
|
||
|
ply_pixel_display_t *display)
|
||
|
{
|
||
|
view_t *view;
|
||
|
|
||
|
ply_trace ("adding pixel display to plugin");
|
||
|
view = view_new (plugin, display);
|
||
|
|
||
|
ply_pixel_display_set_draw_handler (view->display,
|
||
|
(ply_pixel_display_draw_handler_t)
|
||
|
on_draw, view);
|
||
|
if (plugin->is_visible) {
|
||
|
if (view_load (view)) {
|
||
|
ply_list_append_data (plugin->views, view);
|
||
|
if (plugin->is_animating)
|
||
|
view_start_progress_animation (view);
|
||
|
} else {
|
||
|
view_free (view);
|
||
|
}
|
||
|
} else {
|
||
|
ply_list_append_data (plugin->views, view);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
remove_pixel_display (ply_boot_splash_plugin_t *plugin,
|
||
|
ply_pixel_display_t *display)
|
||
|
{
|
||
|
ply_list_node_t *node;
|
||
|
|
||
|
ply_trace ("removing pixel display from plugin");
|
||
|
node = ply_list_get_first_node (plugin->views);
|
||
|
while (node != NULL) {
|
||
|
view_t *view;
|
||
|
ply_list_node_t *next_node;
|
||
|
|
||
|
view = ply_list_node_get_data (node);
|
||
|
next_node = ply_list_get_next_node (plugin->views, node);
|
||
|
|
||
|
if (view->display == display) {
|
||
|
ply_pixel_display_set_draw_handler (view->display, NULL, NULL);
|
||
|
view_free (view);
|
||
|
ply_list_remove_node (plugin->views, node);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
node = next_node;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool
|
||
|
show_splash_screen (ply_boot_splash_plugin_t *plugin,
|
||
|
ply_event_loop_t *loop,
|
||
|
ply_buffer_t *boot_buffer,
|
||
|
ply_boot_splash_mode_t mode)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
assert (plugin != NULL);
|
||
|
|
||
|
plugin->loop = loop;
|
||
|
plugin->mode = mode;
|
||
|
|
||
|
ply_trace ("loading lock image");
|
||
|
if (!ply_image_load (plugin->lock_image))
|
||
|
return false;
|
||
|
|
||
|
if (plugin->box_image != NULL) {
|
||
|
ply_trace ("loading box image");
|
||
|
|
||
|
if (!ply_image_load (plugin->box_image)) {
|
||
|
ply_image_free (plugin->box_image);
|
||
|
plugin->box_image = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (plugin->corner_image != NULL) {
|
||
|
ply_trace ("loading corner image");
|
||
|
|
||
|
if (!ply_image_load (plugin->corner_image)) {
|
||
|
ply_image_free (plugin->corner_image);
|
||
|
plugin->corner_image = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (plugin->header_image != NULL) {
|
||
|
ply_trace ("loading header image");
|
||
|
|
||
|
if (!ply_image_load (plugin->header_image)) {
|
||
|
ply_image_free (plugin->header_image);
|
||
|
plugin->header_image = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (plugin->background_tile_image != NULL) {
|
||
|
ply_trace ("loading background tile image");
|
||
|
if (!ply_image_load (plugin->background_tile_image)) {
|
||
|
ply_image_free (plugin->background_tile_image);
|
||
|
plugin->background_tile_image = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (plugin->background_bgrt_image != NULL) {
|
||
|
ply_trace ("loading background bgrt image");
|
||
|
if (ply_image_load (plugin->background_bgrt_image)) {
|
||
|
plugin->background_bgrt_raw_width = ply_image_get_width (plugin->background_bgrt_image);
|
||
|
plugin->background_bgrt_raw_height = ply_image_get_height (plugin->background_bgrt_image);
|
||
|
} else {
|
||
|
ply_image_free (plugin->background_bgrt_image);
|
||
|
plugin->background_bgrt_image = NULL;
|
||
|
for (i = 0; i < PLY_BOOT_SPLASH_MODE_COUNT; i++)
|
||
|
plugin->mode_settings[i].use_firmware_background = false;
|
||
|
plugin->use_firmware_background = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!load_views (plugin)) {
|
||
|
ply_trace ("couldn't load views");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t)
|
||
|
detach_from_event_loop,
|
||
|
plugin);
|
||
|
|
||
|
ply_trace ("starting boot animations");
|
||
|
start_progress_animation (plugin);
|
||
|
|
||
|
plugin->is_visible = true;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
update_status (ply_boot_splash_plugin_t *plugin,
|
||
|
const char *status)
|
||
|
{
|
||
|
assert (plugin != NULL);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
on_animation_stopped (ply_boot_splash_plugin_t *plugin)
|
||
|
{
|
||
|
if (plugin->idle_trigger != NULL) {
|
||
|
ply_trigger_pull (plugin->idle_trigger, NULL);
|
||
|
plugin->idle_trigger = NULL;
|
||
|
}
|
||
|
plugin->is_idle = true;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
update_progress_animation (ply_boot_splash_plugin_t *plugin,
|
||
|
double fraction_done)
|
||
|
{
|
||
|
ply_list_node_t *node;
|
||
|
view_t *view;
|
||
|
char buf[64];
|
||
|
|
||
|
node = ply_list_get_first_node (plugin->views);
|
||
|
while (node != NULL) {
|
||
|
view = ply_list_node_get_data (node);
|
||
|
|
||
|
if (view->progress_animation != NULL)
|
||
|
ply_progress_animation_set_fraction_done (view->progress_animation,
|
||
|
fraction_done);
|
||
|
|
||
|
ply_progress_bar_set_fraction_done (view->progress_bar, fraction_done);
|
||
|
if (!ply_progress_bar_is_hidden (view->progress_bar) &&
|
||
|
plugin->mode_settings[plugin->mode].progress_bar_show_percent_complete) {
|
||
|
snprintf (buf, sizeof(buf), _("%d%% complete"), (int)(fraction_done * 100));
|
||
|
view_show_message (view, buf);
|
||
|
}
|
||
|
|
||
|
node = ply_list_get_next_node (plugin->views, node);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
on_boot_progress (ply_boot_splash_plugin_t *plugin,
|
||
|
double duration,
|
||
|
double fraction_done)
|
||
|
{
|
||
|
if (plugin->mode == PLY_BOOT_SPLASH_MODE_UPDATES ||
|
||
|
plugin->mode == PLY_BOOT_SPLASH_MODE_SYSTEM_UPGRADE ||
|
||
|
plugin->mode == PLY_BOOT_SPLASH_MODE_FIRMWARE_UPGRADE)
|
||
|
return;
|
||
|
|
||
|
if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_NORMAL)
|
||
|
return;
|
||
|
|
||
|
if (plugin->is_idle)
|
||
|
return;
|
||
|
|
||
|
/*
|
||
|
* If we do not have an end animation, we keep showing progress until
|
||
|
* become_idle gets called.
|
||
|
*/
|
||
|
if (plugin->mode_settings[plugin->mode].use_end_animation &&
|
||
|
fraction_done >= SHOW_ANIMATION_FRACTION) {
|
||
|
if (plugin->stop_trigger == NULL) {
|
||
|
ply_trace ("boot progressed to end");
|
||
|
|
||
|
plugin->stop_trigger = ply_trigger_new (&plugin->stop_trigger);
|
||
|
ply_trigger_add_handler (plugin->stop_trigger,
|
||
|
(ply_trigger_handler_t)
|
||
|
on_animation_stopped,
|
||
|
plugin);
|
||
|
start_end_animation (plugin, plugin->stop_trigger);
|
||
|
}
|
||
|
} else {
|
||
|
double total_duration;
|
||
|
|
||
|
fraction_done *= (1 / SHOW_ANIMATION_FRACTION);
|
||
|
|
||
|
switch (plugin->progress_function) {
|
||
|
/* Fun made-up smoothing function to make the growth asymptotic:
|
||
|
* fraction(time,estimate)=1-2^(-(time^1.45)/estimate) */
|
||
|
case PROGRESS_FUNCTION_TYPE_WWOODS:
|
||
|
total_duration = duration / fraction_done;
|
||
|
fraction_done = 1.0 - pow (2.0, -pow (duration, 1.45) / total_duration) * (1.0 - fraction_done);
|
||
|
break;
|
||
|
|
||
|
case PROGRESS_FUNCTION_TYPE_LINEAR:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
update_progress_animation (plugin, fraction_done);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
hide_splash_screen (ply_boot_splash_plugin_t *plugin,
|
||
|
ply_event_loop_t *loop)
|
||
|
{
|
||
|
assert (plugin != NULL);
|
||
|
|
||
|
ply_trace ("hiding splash");
|
||
|
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,
|
||
|
plugin);
|
||
|
detach_from_event_loop (plugin);
|
||
|
}
|
||
|
|
||
|
plugin->is_visible = false;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
show_prompt (ply_boot_splash_plugin_t *plugin,
|
||
|
const char *prompt,
|
||
|
const char *entry_text,
|
||
|
int number_of_bullets)
|
||
|
{
|
||
|
ply_list_node_t *node;
|
||
|
view_t *view;
|
||
|
|
||
|
ply_trace ("showing prompt");
|
||
|
node = ply_list_get_first_node (plugin->views);
|
||
|
while (node != NULL) {
|
||
|
view = ply_list_node_get_data (node);
|
||
|
view_show_prompt (view, prompt, entry_text, number_of_bullets);
|
||
|
node = ply_list_get_next_node (plugin->views, node);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
on_root_mounted (ply_boot_splash_plugin_t *plugin)
|
||
|
{
|
||
|
ply_trace ("root filesystem mounted");
|
||
|
plugin->root_is_mounted = true;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
become_idle (ply_boot_splash_plugin_t *plugin,
|
||
|
ply_trigger_t *idle_trigger)
|
||
|
{
|
||
|
ply_trace ("deactivation requested");
|
||
|
if (plugin->is_idle) {
|
||
|
ply_trace ("plugin is already idle");
|
||
|
ply_trigger_pull (idle_trigger, NULL);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
plugin->idle_trigger = idle_trigger;
|
||
|
|
||
|
if (plugin->stop_trigger == NULL) {
|
||
|
ply_trace ("waiting for plugin to stop");
|
||
|
plugin->stop_trigger = ply_trigger_new (&plugin->stop_trigger);
|
||
|
ply_trigger_add_handler (plugin->stop_trigger,
|
||
|
(ply_trigger_handler_t)
|
||
|
on_animation_stopped,
|
||
|
plugin);
|
||
|
start_end_animation (plugin, plugin->stop_trigger);
|
||
|
} else {
|
||
|
ply_trace ("already waiting for plugin to stop");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
hide_prompt (ply_boot_splash_plugin_t *plugin)
|
||
|
{
|
||
|
ply_list_node_t *node;
|
||
|
view_t *view;
|
||
|
|
||
|
ply_trace ("hiding prompt");
|
||
|
node = ply_list_get_first_node (plugin->views);
|
||
|
while (node != NULL) {
|
||
|
view = ply_list_node_get_data (node);
|
||
|
view_hide_prompt (view);
|
||
|
node = ply_list_get_next_node (plugin->views, node);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
view_show_message (view_t *view,
|
||
|
const char *message)
|
||
|
{
|
||
|
ply_boot_splash_plugin_t *plugin = view->plugin;
|
||
|
int x, y, width, height;
|
||
|
|
||
|
if (plugin->message_below_animation)
|
||
|
ply_label_set_alignment (view->message_label, PLY_LABEL_ALIGN_CENTER);
|
||
|
|
||
|
ply_label_set_text (view->message_label, message);
|
||
|
width = ply_label_get_width (view->message_label);
|
||
|
height = ply_label_get_height (view->message_label);
|
||
|
|
||
|
if (plugin->message_below_animation) {
|
||
|
x = (ply_pixel_display_get_width (view->display) - width) * 0.5;
|
||
|
y = view->animation_bottom + 10;
|
||
|
} else {
|
||
|
x = 10;
|
||
|
y = 10;
|
||
|
}
|
||
|
|
||
|
ply_label_show (view->message_label, view->display, x, y);
|
||
|
ply_pixel_display_draw_area (view->display, x, y, width, height);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
show_message (ply_boot_splash_plugin_t *plugin,
|
||
|
const char *message)
|
||
|
{
|
||
|
ply_list_node_t *node;
|
||
|
view_t *view;
|
||
|
|
||
|
if (plugin->mode_settings[plugin->mode].suppress_messages) {
|
||
|
ply_trace ("Suppressing message '%s'", message);
|
||
|
return;
|
||
|
}
|
||
|
ply_trace ("Showing message '%s'", message);
|
||
|
node = ply_list_get_first_node (plugin->views);
|
||
|
while (node != NULL) {
|
||
|
view = ply_list_node_get_data (node);
|
||
|
view_show_message (view, message);
|
||
|
node = ply_list_get_next_node (plugin->views, node);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
system_update (ply_boot_splash_plugin_t *plugin,
|
||
|
int progress)
|
||
|
{
|
||
|
if (plugin->mode != PLY_BOOT_SPLASH_MODE_UPDATES &&
|
||
|
plugin->mode != PLY_BOOT_SPLASH_MODE_SYSTEM_UPGRADE &&
|
||
|
plugin->mode != PLY_BOOT_SPLASH_MODE_FIRMWARE_UPGRADE)
|
||
|
return;
|
||
|
|
||
|
update_progress_animation (plugin, progress / 100.0);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
display_normal (ply_boot_splash_plugin_t *plugin)
|
||
|
{
|
||
|
pause_views (plugin);
|
||
|
if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_NORMAL)
|
||
|
hide_prompt (plugin);
|
||
|
|
||
|
plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL;
|
||
|
start_progress_animation (plugin);
|
||
|
redraw_views (plugin);
|
||
|
unpause_views (plugin);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
display_password (ply_boot_splash_plugin_t *plugin,
|
||
|
const char *prompt,
|
||
|
int bullets)
|
||
|
{
|
||
|
pause_views (plugin);
|
||
|
if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL)
|
||
|
stop_animation (plugin);
|
||
|
|
||
|
plugin->state = PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY;
|
||
|
show_prompt (plugin, prompt, NULL, bullets);
|
||
|
redraw_views (plugin);
|
||
|
unpause_views (plugin);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
display_question (ply_boot_splash_plugin_t *plugin,
|
||
|
const char *prompt,
|
||
|
const char *entry_text)
|
||
|
{
|
||
|
pause_views (plugin);
|
||
|
if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL)
|
||
|
stop_animation (plugin);
|
||
|
|
||
|
plugin->state = PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY;
|
||
|
show_prompt (plugin, prompt, entry_text, -1);
|
||
|
redraw_views (plugin);
|
||
|
unpause_views (plugin);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
display_message (ply_boot_splash_plugin_t *plugin,
|
||
|
const char *message)
|
||
|
{
|
||
|
show_message (plugin, message);
|
||
|
}
|
||
|
|
||
|
ply_boot_splash_plugin_interface_t *
|
||
|
ply_boot_splash_plugin_get_interface (void)
|
||
|
{
|
||
|
static ply_boot_splash_plugin_interface_t plugin_interface =
|
||
|
{
|
||
|
.create_plugin = create_plugin,
|
||
|
.destroy_plugin = destroy_plugin,
|
||
|
.add_pixel_display = add_pixel_display,
|
||
|
.remove_pixel_display = remove_pixel_display,
|
||
|
.show_splash_screen = show_splash_screen,
|
||
|
.update_status = update_status,
|
||
|
.on_boot_progress = on_boot_progress,
|
||
|
.hide_splash_screen = hide_splash_screen,
|
||
|
.on_root_mounted = on_root_mounted,
|
||
|
.become_idle = become_idle,
|
||
|
.display_normal = display_normal,
|
||
|
.display_password = display_password,
|
||
|
.display_question = display_question,
|
||
|
.display_message = display_message,
|
||
|
.system_update = system_update,
|
||
|
};
|
||
|
|
||
|
return &plugin_interface;
|
||
|
}
|
||
|
|
||
|
/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
|