Edit default plymouth theme and add grub-theme

Hi. Please help me change the default plymouth theme. I want to replace the logo shown during password entry with this qubes sphere plymouth-themes/pack_1/cubes at master · adi1090x/plymouth-themes · GitHub.
18

However, I’m unable to get it working - when I replace the logo, the password input field disappears. This is what I’ve managed to do so far. I’d appreciate any assistance :slightly_smiling_face: :pray:

# cycle through all images
for (i = 0; i < 81; i++)
  logo.image[i] = Image("progress-" + i + ".png");
logo.sprite = Sprite();

# set image position
logo.sprite.SetX(Window.GetX() + (Window.GetWidth(0) / 2 - logo.image[0].GetWidth() / 2)); # Place images in the center
logo.sprite.SetY(Window.GetY() + (Window.GetHeight(0) / 2 - logo.image[0].GetHeight() / 2));

progress = 0;

fun refresh_callback ()
  {
    logo.sprite.SetImage(logo.image[Math.Int(progress / 2) % 81]);
    progress++;
  }

Plymouth.SetRefreshFunction (refresh_callback);

#----------------------------------------- Dialogue --------------------------------

status = "normal";
show_dots = 1;
show_plaintext_password = 0;
plaintext_password = "";

fun dialog_setup(text)
{
    local.prompt;
    local.entry;
    local.aemsecret;
    
    prompt.text = text;
    prompt.image = Image.Text(text, 1, 1, 1);

    # Try to load AEM secret image, if the file doesn't exists, plymouth shouldn't display anything
    aemsecret.image = Image("antievilmaid_secret.png");

    if (global.show_dots || global.show_plaintext_password) {
        entry.image = Image("entry.png");
    } else {
        entry.image = Image.Text("Password bullets will be hidden", 0.8, 0.8, 0.8);
    }
    
    prompt.sprite = Sprite(prompt.image);
    prompt.sprite.SetX(logo.sprite.GetX() + (logo.image.GetWidth() - prompt.image.GetWidth()) / 2);
    prompt.sprite.SetY(logo.sprite.GetY() + logo.image.GetHeight() + 30);
    prompt.sprite.SetZ(1);
    prompt.sprite.text = text;

    entry.sprite = Sprite(entry.image);
    entry.sprite.SetX(prompt.sprite.GetX() + (prompt.image.GetWidth() - entry.image.GetWidth()) / 2);
    entry.sprite.SetY(prompt.sprite.GetY() + prompt.image.GetHeight() + 30);
    entry.sprite.SetZ(1);

    help.image = Image.Text("|\n|\n|", 0.1, 0.1, 0.1);
    help.sprite = Sprite(help.image);
    
    aemsecret.sprite = Sprite(aemsecret.image);
    aemsecret.sprite.SetX(entry.sprite.GetX() + (entry.image.GetWidth() - aemsecret.image.GetWidth()) / 2);
    aemsecret.sprite.SetY(entry.sprite.GetY() + entry.image.GetHeight() + 30);
    aemsecret.sprite.SetZ(1);
    
    global.dialog.prompt = prompt;
    global.dialog.entry = entry;
    global.dialog.help = help;
    global.dialog.aemsecret = aemsecret;
    global.dialog.bullet_image = Image("bullet.png");
    dialog_opacity(1);
}
    
fun dialog_opacity(opacity)
{
    dialog.prompt.sprite.SetOpacity(opacity);
    dialog.aemsecret.sprite.SetOpacity(opacity);
    dialog.entry.sprite.SetOpacity(opacity);
    dialog.help.sprite.SetOpacity(opacity);
    if (global.show_dots) {
        for (index = 0; dialog.bullet[index]; index++) {
            dialog.bullet[index].sprite.SetOpacity(opacity);
        }
    }
    if (global.show_plaintext_password) {
        dialog.plaintext_password.sprite.SetOpacity(opacity);
    }
}

fun display_normal_callback()
{
    global.status = "normal";
    if (global.dialog)
        dialog_opacity(0);
}

fun display_prompt_callback(prompt, password, is_secret)
{
    bullets = password.Length();
    global.plaintext_password = password;

    if (prompt.SubString(0,32) == "Please enter passphrase for disk") {
        prompt = "Disk password";
    }

    global.status = "password";
    if (!global.dialog) {
        dialog_setup(prompt);
    } else {
        if (global.dialog.prompt.text != prompt) {
            dialog_opacity(0);
            global.dialog = NULL;
            dialog_setup(prompt);
        } else {
            dialog_opacity(1);
        }
    }

    if (global.show_plaintext_password) {
        max_password_width = dialog.entry.image.GetWidth()-5*2;
        dialog.plaintext_password.image = Image.Text(password);
        password_width = dialog.plaintext_password.image.GetWidth();

        if (password_width > max_password_width)
            dialog.plaintext_password.image = dialog.plaintext_password.image.Crop(password_width-max_password_width, 0, max_password_width, dialog.plaintext_password.image.GetHeight());
        dialog.plaintext_password.sprite = Sprite(dialog.plaintext_password.image);
        dialog.plaintext_password.sprite.SetX(dialog.entry.sprite.GetX() + 5);
        dialog.plaintext_password.sprite.SetY(dialog.entry.sprite.GetY() + dialog.entry.image.GetHeight() / 2 - dialog.plaintext_password.image.GetHeight() / 2);
        dialog.plaintext_password.sprite.SetZ(2);
        dialog.plaintext_password.sprite.SetOpacity(1);
    } else {
        dialog.plaintext_password.sprite.SetOpacity(0);
    }

    for (index = 0; dialog.bullet[index] || index < bullets; index++) {
        if (!dialog.bullet[index]) {
            dialog.bullet[index].sprite = Sprite(dialog.bullet_image);
            dialog.bullet[index].sprite.SetZ(dialog.entry.sprite.GetZ() + 1);
        }

        /* Always update position, otherwise bullets added during no echo mode will be at the wrong position */
        dialog.bullet[index].sprite.SetX(dialog.entry.sprite.GetX() + 5 + (index % 21) * (dialog.bullet_image.GetWidth() + 2));
        dialog.bullet[index].sprite.SetY(dialog.entry.sprite.GetY() + dialog.entry.image.GetHeight() / 2 - dialog.bullet_image.GetHeight() / 2);

        if (index < bullets && global.show_dots)
            dialog.bullet[index].sprite.SetOpacity(1);
        else
            dialog.bullet[index].sprite.SetOpacity(0);
      }
}

fun keyboard_input_callback(key){
    if (key == "e[[A") {
        global.show_dots = 0;
        global.show_plaintext_password = 0;
        dialog_setup(global.dialog.prompt.text);
        display_prompt_callback(global.dialog.prompt.text, global.plaintext_password, 1);
    } else if (key == "e[[B") {
        global.show_dots = 1;
        global.show_plaintext_password = 0;
        dialog_setup(global.dialog.prompt.text);
        display_prompt_callback(global.dialog.prompt.text, global.plaintext_password, 1);
    } else if (key == "e[19~") {
        global.show_dots = 0;
        global.show_plaintext_password = 1;
        dialog_setup(global.dialog.prompt.text);
        display_prompt_callback(global.dialog.prompt.text, global.plaintext_password, 1);
    }
}

Plymouth.SetKeyboardInputFunction(keyboard_input_callback);
Plymouth.SetDisplayNormalFunction(display_normal_callback);
Plymouth.SetDisplayPromptFunction(display_prompt_callback);

#----------------------------------------- Progress Bar --------------------------------

progress_box.image = Image("progress_box.png");
progress_box.sprite = Sprite(progress_box.image);
progress_box.sprite.SetX((Window.GetWidth() - progress_box.image.GetWidth()) / 2);
progress_box.sprite.SetY(Window.GetHeight() - 50 - progress_box.image.GetHeight() / 2);

progress_bar.original_image = Image("progress_bar.png");
progress_bar.sprite = Sprite();
progress_bar.sprite.SetX(progress_box.sprite.GetX() + (progress_box.image.GetWidth()  - progress_bar.original_image.GetWidth())  / 2);
progress_bar.sprite.SetY(progress_box.sprite.GetY() + (progress_box.image.GetHeight() - progress_bar.original_image.GetHeight()) / 2);

fun progress_callback(duration, progress)
{
    if (progress_bar.image.GetWidth() != Math.Int (progress_bar.original_image.GetWidth() * progress)) {
      progress_bar.image = progress_bar.original_image.Scale(progress_bar.original_image.GetWidth() * progress, progress_bar.original_image.GetHeight());
      progress_bar.sprite.SetImage(progress_bar.image);
    }
}

Plymouth.SetBootProgressFunction(progress_callback);

#----------------------------------------- Quit --------------------------------

fun quit_callback()
{
    logo.sprite.SetOpacity(1);
}

Plymouth.SetQuitFunction(quit_callback);

#----------------------------------------- Message --------------------------------

message_sprites = [];
message_sprite_count = 0;
message_sprite_y = 10;

fun display_message_callback(text)
{
    my_image = Image.Text(text, 1, 1, 1);
    message_sprites[message_sprite_count] = Sprite(my_image);
    message_sprites[message_sprite_count].SetPosition(10, message_sprite_y, 10000);
    message_sprites[message_sprite_count].text = text;
    message_sprite_count++;
    message_sprite_y += my_image.GetHeight();
}

fun hide_message_callback (text)
{
    for (i = 0; i < message_sprite_count; i++) {
        if (message_sprites[i].text == text)
            message_sprites[i] = NULL;
    }
}

Plymouth.SetDisplayMessageFunction(display_message_callback);
Plymouth.SetHideMessageFunction(hide_message_callback);

# vim: ts=4 sw=4 et

i don’t know a lot for plymouth but @renehoj give some animate plymouth:

It can give you a clue :slight_smile:

2 Likes

It seems this option is the most beautiful :heart_eyes:
qubes58e3e69888169b

#if (Plymouth.GetMode() != "shutdown")
{
    Window.SetBackgroundTopColor(0, 0, 0);
    Window.SetBackgroundBottomColor(0, 0, 0);
    
    // Логотип для обычного режима
    logo.image = Image("qubes-logo-solid.png");
    logo.sprite = Sprite(logo.image);
    logo.opacity_angle = 0;

    // Позиционирование логотипа
    logo.sprite.SetX((Window.GetWidth()  - logo.image.GetWidth())  / 2);
    logo.sprite.SetY((Window.GetHeight() - logo.image.GetHeight()) / 2);
}
#else
{
    Window.SetBackgroundTopColor(0, 0, 0);
    Window.SetBackgroundBottomColor(0, 0, 0);
    
    // Логотип для режима завершения работы
    logo.imageOutline = Image("qubes-logo-outline.png");
    logo.spriteOutline = Sprite(logo.imageOutline);
    logo.opacity_angle_outline = 0;

    // Позиционирование логотипа
    logo.spriteOutline.SetX((Window.GetWidth()  - logo.imageOutline.GetWidth())  / 2);
    logo.spriteOutline.SetY((Window.GetHeight() - logo.imageOutline.GetHeight()) / 2);
}

// Общее для прогресса
for (i = 0; i < 81; i++)
    logo.imageProgress[i] = Image("progress-" + i + ".png");
logo.spriteProgress = Sprite();

logo.spriteProgress.SetX(Window.GetX() + (Window.GetWidth(0) / 2 - logo.imageProgress[0].GetWidth() / 2)); # Place images in the center
logo.spriteProgress.SetY(Window.GetY() + (Window.GetHeight(0) / 4 - logo.imageProgress[0].GetHeight() / 4));

progress = 0;

fun refresh_callback ()
{
    // Здесь можно установить для отображения прогресса
    logo.spriteProgress.SetImage(logo.imageProgress[Math.Int(progress / 2) % 81]);
    progress++;
}

Plymouth.SetRefreshFunction(refresh_callback);

#----------------------------------------- Dialogue --------------------------------

status = "normal";
show_dots = 1;
show_plaintext_password = 0;
plaintext_password = "";

fun dialog_setup(text)
{
    local.prompt;
    local.entry;
    local.aemsecret;
    
    prompt.text = text;
    prompt.image = Image.Text(text, 1, 1, 1);

    # Try to load AEM secret image, if the file doesn't exists, plymouth shouldn't display anything
    aemsecret.image = Image("antievilmaid_secret.png");

    if (global.show_dots || global.show_plaintext_password) {
        entry.image = Image("entry.png");
    } else {
        entry.image = Image.Text("Password bullets will be hidden", 0.5, 0.5, 0.5);
    }
    
    prompt.sprite = Sprite(prompt.image);
    prompt.sprite.SetX(logo.sprite.GetX() + (logo.image.GetWidth() - prompt.image.GetWidth()) / 2);
    prompt.sprite.SetY(logo.sprite.GetY() + logo.image.GetHeight() + 10);
    prompt.sprite.SetZ(1);
    prompt.sprite.text = text;

    entry.sprite = Sprite(entry.image);
    entry.sprite.SetX(prompt.sprite.GetX() + (prompt.image.GetWidth() - entry.image.GetWidth()) / 2);
    entry.sprite.SetY(prompt.sprite.GetY() + prompt.image.GetHeight() + 10);
    entry.sprite.SetZ(1);

    help.image = Image.Text(".\n.\n.", 0.1, 0.1, 0.1);
    help.sprite = Sprite(help.image);
    
    aemsecret.sprite = Sprite(aemsecret.image);
    aemsecret.sprite.SetX(entry.sprite.GetX() + (entry.image.GetWidth() - aemsecret.image.GetWidth()) / 2);
    aemsecret.sprite.SetY(entry.sprite.GetY() + entry.image.GetHeight() + 10);
    aemsecret.sprite.SetZ(1);
    
    global.dialog.prompt = prompt;
    global.dialog.entry = entry;
    global.dialog.help = help;
    global.dialog.aemsecret = aemsecret;
    global.dialog.bullet_image = Image("bullet.png");
    dialog_opacity(1);
}
    
fun dialog_opacity(opacity)
{
    dialog.prompt.sprite.SetOpacity(opacity);
    dialog.aemsecret.sprite.SetOpacity(opacity);
    dialog.entry.sprite.SetOpacity(opacity);
    dialog.help.sprite.SetOpacity(opacity);
    if (global.show_dots) {
        for (index = 0; dialog.bullet[index]; index++) {
            dialog.bullet[index].sprite.SetOpacity(opacity);
        }
    }
    if (global.show_plaintext_password) {
        dialog.plaintext_password.sprite.SetOpacity(opacity);
    }
}

fun display_normal_callback()
{
    global.status = "normal";
    if (global.dialog)
        dialog_opacity(0);
}

fun display_prompt_callback(prompt, password, is_secret)
{
    bullets = password.Length();
    global.plaintext_password = password;

    if (prompt.SubString(0,32) == "Please enter passphrase for disk") {
        prompt = "Disk password";
    }

    global.status = "password";
    if (!global.dialog) {
        dialog_setup(prompt);
    } else {
        if (global.dialog.prompt.text != prompt) {
            dialog_opacity(0);
            global.dialog = NULL;
            dialog_setup(prompt);
        } else {
            dialog_opacity(1);
        }
    }

    if (global.show_plaintext_password) {
        max_password_width = dialog.entry.image.GetWidth()-5*2;
        dialog.plaintext_password.image = Image.Text(password);
        password_width = dialog.plaintext_password.image.GetWidth();

        if (password_width > max_password_width)
            dialog.plaintext_password.image = dialog.plaintext_password.image.Crop(password_width-max_password_width, 0, max_password_width, dialog.plaintext_password.image.GetHeight());
        dialog.plaintext_password.sprite = Sprite(dialog.plaintext_password.image);
        dialog.plaintext_password.sprite.SetX(dialog.entry.sprite.GetX() + 5);
        dialog.plaintext_password.sprite.SetY(dialog.entry.sprite.GetY() + dialog.entry.image.GetHeight() / 2 - dialog.plaintext_password.image.GetHeight() / 2);
        dialog.plaintext_password.sprite.SetZ(2);
        dialog.plaintext_password.sprite.SetOpacity(1);
    } else {
        dialog.plaintext_password.sprite.SetOpacity(0);
    }

    for (index = 0; dialog.bullet[index] || index < bullets; index++) {
        if (!dialog.bullet[index]) {
            dialog.bullet[index].sprite = Sprite(dialog.bullet_image);
            dialog.bullet[index].sprite.SetZ(dialog.entry.sprite.GetZ() + 1);
        }

        /* Always update position, otherwise bullets added during no echo mode will be at the wrong position */
        dialog.bullet[index].sprite.SetX(dialog.entry.sprite.GetX() + 5 + (index % 21) * (dialog.bullet_image.GetWidth() + 2));
        dialog.bullet[index].sprite.SetY(dialog.entry.sprite.GetY() + dialog.entry.image.GetHeight() / 2 - dialog.bullet_image.GetHeight() / 2);

        if (index < bullets && global.show_dots)
            dialog.bullet[index].sprite.SetOpacity(1);
        else
            dialog.bullet[index].sprite.SetOpacity(0);
      }
}

fun keyboard_input_callback(key){
    if (key == "e[[A") {
        global.show_dots = 0;
        global.show_plaintext_password = 0;
        dialog_setup(global.dialog.prompt.text);
        display_prompt_callback(global.dialog.prompt.text, global.plaintext_password, 1);
    } else if (key == "e[[B") {
        global.show_dots = 1;
        global.show_plaintext_password = 0;
        dialog_setup(global.dialog.prompt.text);
        display_prompt_callback(global.dialog.prompt.text, global.plaintext_password, 1);
    } else if (key == "e[19~") {
        global.show_dots = 0;
        global.show_plaintext_password = 1;
        dialog_setup(global.dialog.prompt.text);
        display_prompt_callback(global.dialog.prompt.text, global.plaintext_password, 1);
    }
}

Plymouth.SetKeyboardInputFunction(keyboard_input_callback);
Plymouth.SetDisplayNormalFunction(display_normal_callback);
Plymouth.SetDisplayPromptFunction(display_prompt_callback);

#----------------------------------------- Progress Bar --------------------------------

progress_box.image = Image("progress_box.png");
progress_box.sprite = Sprite(progress_box.image);
progress_box.sprite.SetX((Window.GetWidth() - progress_box.image.GetWidth()) / 2);
progress_box.sprite.SetY(Window.GetHeight() - 50 - progress_box.image.GetHeight() / 2);

progress_bar.original_image = Image("progress_bar.png");
progress_bar.sprite = Sprite();
progress_bar.sprite.SetX(progress_box.sprite.GetX() + (progress_box.image.GetWidth()  - progress_bar.original_image.GetWidth())  / 2);
progress_bar.sprite.SetY(progress_box.sprite.GetY() + (progress_box.image.GetHeight() - progress_bar.original_image.GetHeight()) / 2);

fun progress_callback(duration, progress)
{
    if (progress_bar.image.GetWidth() != Math.Int (progress_bar.original_image.GetWidth() * progress)) {
      progress_bar.image = progress_bar.original_image.Scale(progress_bar.original_image.GetWidth() * progress, progress_bar.original_image.GetHeight());
      progress_bar.sprite.SetImage(progress_bar.image);
    }
}

Plymouth.SetBootProgressFunction(progress_callback);

#----------------------------------------- Quit --------------------------------

fun quit_callback()
{
    logo.sprite.SetOpacity(1);
}

Plymouth.SetQuitFunction(quit_callback);

#----------------------------------------- Message --------------------------------

message_sprites = [];
message_sprite_count = 0;
message_sprite_y = 10;

fun display_message_callback(text)
{
    my_image = Image.Text(text, 1, 1, 1);
    message_sprites[message_sprite_count] = Sprite(my_image);
    message_sprites[message_sprite_count].SetPosition(10, message_sprite_y, 10000);
    message_sprites[message_sprite_count].text = text;
    message_sprite_count++;
    message_sprite_y += my_image.GetHeight();
}

fun hide_message_callback (text)
{
    for (i = 0; i < message_sprite_count; i++) {
        if (message_sprites[i].text == text)
            message_sprites[i] = NULL;
    }
}

Plymouth.SetDisplayMessageFunction(display_message_callback);
Plymouth.SetHideMessageFunction(hide_message_callback);

# vim: ts=4 sw=4 et
1 Like

Please share your beautiful GRUB theme with qubes :slightly_smiling_face: