From 184e955b4760a4bd9f641bcf0c76ecc82709616e Mon Sep 17 00:00:00 2001 From: Paolo Asperti Date: Wed, 30 Sep 2015 15:15:43 +0200 Subject: [PATCH] Merged package plymouth-theme-edubuntu-bglug --- debian/control | 9 + debian/plymouth-theme-edubuntu-bglug.install | 3 + debian/plymouth-theme-edubuntu-bglug.postinst | 26 + debian/plymouth-theme-edubuntu-bglug.postrm | 29 + plymouth-theme/edubuntu-logo-bglug.plymouth | 8 + plymouth-theme/edubuntu-logo-bglug.script | 1058 +++++++++++++++++ plymouth-theme/edubuntu_logo.png | Bin 0 -> 36573 bytes plymouth-theme/edubuntu_logo16.png | Bin 0 -> 980 bytes plymouth-theme/password_field.png | Bin 0 -> 788 bytes plymouth-theme/password_field16.png | Bin 0 -> 177 bytes plymouth-theme/progress_dot_off.png | Bin 0 -> 387 bytes plymouth-theme/progress_dot_off16.png | Bin 0 -> 133 bytes plymouth-theme/progress_dot_on.png | Bin 0 -> 379 bytes plymouth-theme/progress_dot_on16.png | Bin 0 -> 122 bytes 14 files changed, 1133 insertions(+) create mode 100644 debian/plymouth-theme-edubuntu-bglug.install create mode 100644 debian/plymouth-theme-edubuntu-bglug.postinst create mode 100644 debian/plymouth-theme-edubuntu-bglug.postrm create mode 100644 plymouth-theme/edubuntu-logo-bglug.plymouth create mode 100644 plymouth-theme/edubuntu-logo-bglug.script create mode 100644 plymouth-theme/edubuntu_logo.png create mode 100644 plymouth-theme/edubuntu_logo16.png create mode 100644 plymouth-theme/password_field.png create mode 100644 plymouth-theme/password_field16.png create mode 100644 plymouth-theme/progress_dot_off.png create mode 100644 plymouth-theme/progress_dot_off16.png create mode 100644 plymouth-theme/progress_dot_on.png create mode 100644 plymouth-theme/progress_dot_on16.png diff --git a/debian/control b/debian/control index 66b6036..2ac6641 100644 --- a/debian/control +++ b/debian/control @@ -2,6 +2,7 @@ Source: bglug-artwork Section: x11 Priority: optional Maintainer: BGLug +SBuild-Depends: debhelper (>= 7), intltool, libplymouth-dev, pkg-config Standards-Version: 3.9.1 Homepage: http://www.bglug.it @@ -9,3 +10,11 @@ Package: bglug-artwork Architecture: all Description: Default BGLug artwork At the moment, this package contains only the default background. + +Package: plymouth-theme-edubuntu-bglug +Architecture: all +Depends: plymouth (>= 0.8.1-1), plymouth-label, ${misc:Depends} +Provides: plymouth-theme +Description: plymouth theme for Edubuntu - BGLug edition + This package contains a clone of base Edubuntu theme for plymouth, + customized with the BGLug logo. diff --git a/debian/plymouth-theme-edubuntu-bglug.install b/debian/plymouth-theme-edubuntu-bglug.install new file mode 100644 index 0000000..9b45ec9 --- /dev/null +++ b/debian/plymouth-theme-edubuntu-bglug.install @@ -0,0 +1,3 @@ +plymouth-theme/*.png lib/plymouth/themes/edubuntu-logo-bglug/ +plymouth-theme/edubuntu-logo-bglug.plymouth lib/plymouth/themes/edubuntu-logo-bglug/ +plymouth-theme/*.script lib/plymouth/themes/edubuntu-logo-bglug/ diff --git a/debian/plymouth-theme-edubuntu-bglug.postinst b/debian/plymouth-theme-edubuntu-bglug.postinst new file mode 100644 index 0000000..241d436 --- /dev/null +++ b/debian/plymouth-theme-edubuntu-bglug.postinst @@ -0,0 +1,26 @@ +#!/bin/sh +set -e + +case "$1" in + configure) + update-alternatives \ + --install /lib/plymouth/themes/default.plymouth default.plymouth \ + /lib/plymouth/themes/edubuntu-logo-bglug/edubuntu-logo-bglug.plymouth 250 + + if which update-initramfs >/dev/null 2>&1 + then + update-initramfs -u + fi + ;; + + abort-upgrade|abort-deconfigure|abort-remove) + ;; + + *) + echo "$0 called with unknown argument \`$1'" 1>&2 + exit 1 + ;; +esac + +#DEBHELPER# +exit 0 diff --git a/debian/plymouth-theme-edubuntu-bglug.postrm b/debian/plymouth-theme-edubuntu-bglug.postrm new file mode 100644 index 0000000..69b37df --- /dev/null +++ b/debian/plymouth-theme-edubuntu-bglug.postrm @@ -0,0 +1,29 @@ +#!/bin/sh +set -e + +case "$1" in + purge|remove) + update-alternatives \ + --remove default.plymouth /lib/plymouth/themes/edubuntu-logo-bglug/edubuntu-logo-bglug.plymouth + + rmdir /lib/plymouth/themes || : + rmdir /lib/plymouth || : + + if which update-initramfs >/dev/null 2>&1 + then + update-initramfs -u + fi + ;; + + upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + ;; + + *) + echo "$0 called with unknown argument \`$1'" 1>&2 + exit 1 + ;; +esac + +#DEBHELPER# + +exit 0 diff --git a/plymouth-theme/edubuntu-logo-bglug.plymouth b/plymouth-theme/edubuntu-logo-bglug.plymouth new file mode 100644 index 0000000..11385ae --- /dev/null +++ b/plymouth-theme/edubuntu-logo-bglug.plymouth @@ -0,0 +1,8 @@ +[Plymouth Theme] +Name=Edubuntu Logo - BGLug edition +Description=A theme that features a blank background with a logo. +ModuleName=script + +[script] +ImageDir=/lib/plymouth/themes/edubuntu-logo-bglug +ScriptFile=/lib/plymouth/themes/edubuntu-logo-bglug/edubuntu-logo-bglug.script diff --git a/plymouth-theme/edubuntu-logo-bglug.script b/plymouth-theme/edubuntu-logo-bglug.script new file mode 100644 index 0000000..7dca442 --- /dev/null +++ b/plymouth-theme/edubuntu-logo-bglug.script @@ -0,0 +1,1058 @@ +# ubuntu-logo.script - boot splash plugin +# +# Copyright (C) 2009 Canonical Ltd. +# +# 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: Alberto Milone +# +# Based on the example provided with the "script plugin" written by: +# Charlie Brej +# + +# Set the text colour in (rgb / 256) +text_colour.red = 0.0; +text_colour.green = 0.0; +text_colour.blue = 0.0; + +# Tinted text #988592 +tinted_text_colour.red = 0.0; +tinted_text_colour.green = 0.0; +tinted_text_colour.blue = 0.0; + +# Action Text - #ffffff - RGB 255 255 255 +action_text_colour.red = 0.0; +action_text_colour.green = 0.0; +action_text_colour.blue = 0.0; + +# Orange - #ff4012 - RGB 255 64 18 +debugsprite = Sprite(); +debugsprite_bottom = Sprite(); +debugsprite_medium = Sprite(); + +# are we currently prompting for a password? +prompt_active = 0; + +# General purpose function to create text +fun WriteText (text, colour) { + image = Image.Text (text, colour.red, colour.green, colour.blue); + return image; +} + +fun ImageToText (text) { + image = WriteText (text, text_colour); + return image; +} + +fun ImageToTintedText (text) { + image = WriteText (text, tinted_text_colour); + return image; +} + +fun ImageToActionText (text) { + image = WriteText (text, action_text_colour); + return image; +} + +fun Debug(text) { + debugsprite.SetImage(ImageToText (text)); +} + +fun DebugBottom(text) { + debugsprite_bottom.SetImage(ImageToText (text)); + debugsprite_bottom.SetPosition(0, (Window.GetHeight (0) - 20), 1); +} + +fun DebugMedium(text) { + debugsprite_medium.SetImage(ImageToText (text)); + debugsprite_medium.SetPosition(0, (Window.GetHeight (0) - 60), 1); +} + +fun TextYOffset() { + local.y; + local.text_height; + local.min_height; + + # Put the 1st line below the logo + some spacing + y = logo.y + logo.height + (progress_indicator.bullet_height * 7 ); # + logo_spacing; + + text_height = first_line_height * 7.5; + + min_height = Window.GetHeight(); + if (y + text_height > min_height) + y = min_height - text_height; + + if (y < progress_indicator.y + progress_indicator.height) + return progress_indicator.y + progress_indicator.height; + return y; +} + +#------------------------------String functions------------------------------- + +# This is the equivalent for strstr() +fun StringString(string, substring) { + start = 0; + while (String(string).CharAt (start)) { + walk = 0; + while (String(substring).CharAt (walk) == String(string).CharAt (start + walk) ) { + walk++; + if (!String(substring).CharAt (walk)) return start; + } + start++; + } + + return NULL; +} + +fun StringLength (string) { + index = 0; + while (String(string).CharAt(index)) index++; + return index; +} + +fun StringCopy (source, beginning, end) { + local.destination = ""; + for (index = beginning; ( ( (end == NULL) || (index <= end) ) && (String(source).CharAt(index)) ); index++) { + local.destination += String(source).CharAt(index); + } + + return local.destination; +} + +fun StringReplace (source, pattern, replacement) { + local.found = StringString(source, pattern); + if (local.found == NULL) + return source; + + local.new_string = StringCopy (source, 0, local.found - 1) + + replacement + + StringCopy (source, local.found + StringLength(pattern), NULL); + + return local.new_string; +} + +# it makes sense to use it only for +# numbers up to 100 +fun StringToInteger (str) { + int = -1; + for (i=0; i<=100; i++) { + if (i+"" == str) { + int = i; + break; + } + } + return int; +} + +#----------------------------------------------------------------------------- +# Previous background colour +# #300a24 --> 0.19, 0.04, 0.14 +# New background colour +# #2c001e --> 0.16, 0.00, 0.12 +# +Window.SetBackgroundTopColor (0.86, 0.84, 0.83); # Nice colour on top of the screen fading to +Window.SetBackgroundBottomColor (0.93, 0.93, 0.92); # an equally nice colour on the bottom + +bits_per_pixel = Window.GetBitsPerPixel (); +if (bits_per_pixel == 4) { + logo_filename = "edubuntu_logo16.png"; + progress_dot_off_filename = "progress_dot_off16.png"; + progress_dot_on_filename = "progress_dot_on16.png"; + password_field_filename = "password_field16.png"; +} else { + logo_filename = "edubuntu_logo.png"; + progress_dot_off_filename = "progress_dot_off.png"; + progress_dot_on_filename = "progress_dot_on.png"; + password_field_filename = "password_field.png"; +} + +logo.image = Image (logo_filename); +logo.sprite = Sprite (); +logo.sprite.SetImage (logo.image); +logo.width = logo.image.GetWidth (); +logo.height = logo.image.GetHeight (); +logo.x = Window.GetX () + Window.GetWidth () / 2 - logo.width / 2; +logo.y = Window.GetY () + Window.GetHeight () / 2 - logo.height; +logo.z = 1000; +logo.sprite.SetX (logo.x); +logo.sprite.SetY (logo.y); +logo.sprite.SetZ (logo.z); +logo.sprite.SetOpacity (1); + +# Spacing below the logo - in pixels +logo_spacing = logo.height * 4; + +message_notification[0].image = ImageToTintedText (""); +message_notification[1].image = ImageToTintedText (""); +fsck_notification.image = ImageToActionText (""); + +status = "normal"; + +progress_indicator.bullet_off = Image (progress_dot_off_filename); +progress_indicator.bullet_on = Image (progress_dot_on_filename); +progress_indicator.bullet_width = progress_indicator.bullet_off.GetWidth (); +progress_indicator.bullet_height = progress_indicator.bullet_off.GetHeight (); +progress_indicator.bullet_hspacing = progress_indicator.bullet_width * 1.1; +progress_indicator.width = progress_indicator.bullet_width * 5; +progress_indicator.height = progress_indicator.bullet_height; +progress_indicator.y = logo.y + logo.height + (logo.height / 4); +progress_indicator.x = Window.GetX () + Window.GetWidth () / 2 - progress_indicator.width / 2; # logo.x + 26; + +# use a fixed string with ascending and descending stems to calibrate the +# bounding box for the first message, so the messages below don't move up +# and down according to *their* height. +first_line_height = ImageToTintedText ("AfpqtM").GetHeight(); + +# if the user has a 640x480 or 800x600 display, we can't quite fit everything +# (including passphrase prompts) with the target spacing, so scoot the text up +# a bit if needed. +top_of_the_text = TextYOffset(); + +#-----------------------------------------Logo functions------------------------------ + +# Call this when updating the screen +fun draw_logo () { + logo.sprite.SetX (logo.x); + logo.sprite.SetY (logo.y); + logo.sprite.SetZ (logo.z); + logo.sprite.SetOpacity (1); +} + + +#-----------------------------------------Progress Indicator-------------------------- +fun set_progress_indicator () { + + + # Here we assume that we can store half bullets on each half of the screen + # together with some spacing + local.x = progress_indicator.x; + + for (index = 0; index <= 4; index++) { + # Set the "off" bullets + progress_indicator.bullets_off[index].sprite = Sprite (progress_indicator.bullet_off); + progress_indicator.bullets_off[index].sprite.SetPosition (local.x, progress_indicator.y, 1000); + progress_indicator.bullets_off[index].x = local.x; + progress_indicator.bullets_off[index].y = progress_indicator.y; + progress_indicator.bullets_off[index].sprite.SetOpacity (1); + + #local.debug_medium_string = "Progress indicator " + index + ": x = " + progress_indicator.bullets_off[index].x + + # ", y = " + progress_indicator.bullets_off[index].y + ", logo width = " + logo.width + + # ", logo height = " + logo.height + " " + screen_width + " " + screen_height; + # + #(index % 2) && DebugMedium (local.debug_medium_string) || DebugBottom (local.debug_medium_string); + + # Set the "on" bullets on top of the "off" bullets and make them transparent + progress_indicator.bullets_on[index].sprite = Sprite (progress_indicator.bullet_on); + progress_indicator.bullets_on[index].x = progress_indicator.bullets_off[index].x; + progress_indicator.bullets_on[index].y = progress_indicator.bullets_off[index].y; + progress_indicator.bullets_on[index].sprite.SetPosition (progress_indicator.bullets_on[index].x, progress_indicator.bullets_on[index].y, 10000); + + progress_indicator.bullets_on[index].sprite.SetOpacity (0); + + local.x += progress_indicator.bullet_hspacing; + } + #local.debug_string = "Progress indicator: x1 = " + progress_indicator.x + ", x2 = " + local.x + ", y = " + progress_indicator.y + + # ", x logo = " + logo.x + ", y logo = " + logo.y + ", indicator width = " + progress_indicator.width; + #Debug(progress_indicator.bullets_off[0].x); +} + + +# We have 2 bullets, one on top of the other: +# The white one is on top of the red one and the former should +# slowly fade so as to get a nice transition effect. +fun switch_on_bullet (bullets_off, bullets_on, bullet_number, opacity) { + local.x = bullets_on[bullet_number].x; + local.y = bullets_on[bullet_number].y; + local.z = bullets_on[bullet_number].z; + + # Hide the bullets which are off + bullets_off[bullet_number].sprite.SetOpacity (0); + + # Show the bullets which are on + bullets_on[bullet_number].sprite.SetPosition (local.x, local.y, local.z); + bullets_on[bullet_number].sprite.SetOpacity (opacity); + + # Bump the number of times we have switched on bullets + global.times_bullets_switched++; +} + +fun switch_off_bullets () { + # Debug("Switching off progress indicator"); + + set_progress_indicator (); + global.times_bullets_switched = 0; + global.on_off = 1; +} + +# This is something that we can call when we exit +fun switch_on_bullets () { + # Debug("Switching off progress indicator"); + if (!global.progress_indicator.bullets_on) set_progress_indicator (); + local = global.progress_indicator; + + for (index = 0; bullets_on[index]; index++) { + switch_on_bullet (bullets_off, bullets_on, index, 1.0); + } +} + + +# Implement in boot progress callback +fun animate_progress_indicator (progress, time) { + if (global.progress_time == NULL) { + global.progress_time = progress; #time; + switch_off_bullets (); + } + +# Debug ("progress = " + progress + ", time = " + time + " times switched = " + global.times_bullets_switched + " on_off " + global.on_off); + +# if (global.times_bullets_switched == NULL) +# global.times_bullets_switched = 5; + +# if (global.on_off == NULL) +# global.on_off = 0; + + if ((progress - global.progress_time) >= 1.0) { + global.progress_time = progress; + + if (global.times_bullets_switched == 5) { + # Change which bullets are switched on + # and which ones are switched off + global.on_off = !global.on_off; + global.times_bullets_switched = 0; + } + + if (global.on_off) { + switch_on_bullet (progress_indicator.bullets_off, progress_indicator.bullets_on, + global.times_bullets_switched, 1.0); + } + else { + switch_on_bullet (progress_indicator.bullets_on, progress_indicator.bullets_off, + global.times_bullets_switched, 1.0); + } + } + + + # Start setting bullets to "on" with translucency +# for (index = 0; index <= 5; index++) { +# opacity = 0.0; +# while (opacity <= 1.0) { +# switch_on_bullet (progress_indicator.bullets_off, progress_indicator.bullets_on, +# index, opacity); +# opacity += 0.1; +# } +# } +} + + +#-----------------------------------------Label utility functions--------------------- + +# label should be either a string or NULL +# Images for n lines will be created and returned as items of the +# message_label array +# +fun get_message_label (label, is_fake, is_action_line) { + # Debug("Get Label position"); + local.message_label; + + if (is_fake) + # Create a fake label so as to get the y coordinate of + # a standard-length label. + local.message_image = ImageToTintedText ("This is a fake message"); + else + local.message_image = (is_action_line) && ImageToActionText (label) || ImageToTintedText (label); + + message_label.width = message_image.GetWidth (); + message_label.height = message_image.GetHeight (); + + # Center the line horizontally + message_label.x = Window.GetX () + Window.GetWidth () / 2 - message_label.width / 2; + + message_label.y = top_of_the_text; + + # Put the 2nd line below the fsck line + if (is_action_line) { + local.fsck_label.y = message_label.y + (first_line_height + first_line_height / 2); + message_label.y = local.fsck_label.y + (first_line_height * 2); + } + + # Debug("action label x = " + message_label.x + " y = " + message_label.y ); + +# message_debug = "msg_x = " + message_label.x + " msg_y = " + message_label.y + +# "msg_width = " + message_label.width + " msg_height = " + +# message_label.height + " message = " + label; +# Debug(message_debug); + + return message_label; + +} + +# Create an fsck label and/or get its position +fun get_fsck_label (label, is_fake) { + # Debug("Get Label position"); + local.fsck_label = global.progress_label; + + if (is_fake) + fsck_label.image = ImageToTintedText ("This is a fake message"); + else + fsck_label.image = ImageToTintedText (label); + + fsck_label.width = fsck_label.image.GetWidth (); + fsck_label.height = fsck_label.image.GetHeight (); + + # Centre the label horizontally + fsck_label.x = Window.GetX () + Window.GetWidth () / 2 - fsck_label.width / 2; + + local.first_label = get_message_label (label, 1, 0); + + # Place the label below the 1st message line + fsck_label.y = local.first_label.y + local.first_label.height + (local.first_label.height / 2); + +# message_debug = "msg_x = " + fsck_label.x + " msg_y = " + fsck_label.y + +# "msg_width = " + fsck_label.width + " msg_height = " + +# fsck_label.height + " message = " + label; +# Debug(message_debug); + + return fsck_label; +} + +#-----------------------------------------Message stuff -------------------------------- +# + +# Set up a message label +# +# NOTE: this is called when doing something like 'plymouth message "hello world"' +# +fun setup_message (message_text, x, y, z, index) { + # Debug("Message setup"); + global.message_notification[index].image = (index) && ImageToActionText (message_text) || ImageToTintedText (message_text); + + # Set up the text message, if any + message_notification[index].x = x; + message_notification[index].y = y; + message_notification[index].z = z; + + message_notification[index].sprite = Sprite (); + message_notification[index].sprite.SetImage (message_notification[index].image); + message_notification[index].sprite.SetX (message_notification[index].x); + message_notification[index].sprite.SetY (message_notification[index].y); + message_notification[index].sprite.SetZ (message_notification[index].z); + +} + +fun show_message (index) { + if (global.message_notification[index].sprite) global.message_notification[index].sprite.SetOpacity(1); +} + +fun hide_message (index) { + if (global.message_notification[index].sprite) global.message_notification[index].sprite.SetOpacity(0); +} + + + + +# the callback function is called when new message should be displayed. +# First arg is message to display. +fun message_callback (message) +{ + # Debug("Message callback"); + is_fake = 0; + if (!message || (message == "")) is_fake = 1; + + local.substring = "keys:"; + + # Look for the "keys:" prefix + local.keys = StringString(message, local.substring); + + local.is_action_line = (keys != NULL); + #Debug("keys " + local.keys + " substring length = " + StringLength(local.substring)); + + # Get the message without the "keys:" prefix + if (keys != NULL) + message = StringCopy (message, keys + StringLength(local.substring), NULL); + + local.label.is_fake = is_fake; + label = get_message_label(message, is_fake, is_action_line); + label.z = 10000; + + setup_message (message, label.x, label.y, label.z, is_action_line); + if (prompt_active && local.is_action_line) + hide_message (is_action_line); + else + show_message (is_action_line); + +} + + +#-----------------------------------------Display Password stuff ----------------------- +# + +fun password_dialogue_setup (message_label) { + # Debug("Password dialog setup"); + + local.entry; + local.bullet_image; + + bullet_image = Image (progress_dot_off_filename); + entry.image = Image (password_field_filename); + + # Hide the normal labels + prompt_active = 1; + if (message_notification[1].sprite) hide_message (1); + + # Set the prompt label + label = get_message_label(message_label, 0, 1); + label.z = 10000; + + setup_message (message_label, label.x, label.y, label.z, 2); + show_message (2); + + # Set up the text entry which contains the bullets + entry.sprite = Sprite (); + entry.sprite.SetImage (entry.image); + + # Centre the box horizontally + entry.x = Window.GetX () + Window.GetWidth () / 2 - entry.image.GetWidth () / 2; + + # Put the entry below the second label. + entry.y = message_notification[2].y + label.height; + + #Debug ("entry x = " + entry.x + ", y = " + entry.y); + entry.z = 10000; + entry.sprite.SetX (entry.x); + entry.sprite.SetY (entry.y); + entry.sprite.SetZ (entry.z); + + global.password_dialogue = local; +} + +fun password_dialogue_opacity (opacity) { + # Debug("Password dialog opacity"); + global.password_dialogue.opacity = opacity; + local = global.password_dialogue; + + # You can make the box translucent with a float + # entry.sprite.SetOpacity (0.3); + entry.sprite.SetOpacity (opacity); + label.sprite.SetOpacity (opacity); + + if (bullets) { + for (index = 0; bullets[index]; index++) { + bullets[index].sprite.SetOpacity (opacity); + } + } +} + + +# The callback function is called when the display should display a password dialogue. +# First arg is prompt string, the second is the number of bullets. +fun display_password_callback (prompt, bullets) { + # Debug("Password dialog setup"); + + global.status = "password"; + if (!global.password_dialogue) password_dialogue_setup(prompt); + password_dialogue_opacity (1); + bullet_width = password_dialogue.bullet_image.GetWidth(); + bullet_y = password_dialogue.entry.y + + password_dialogue.entry.image.GetHeight () / 2 - + password_dialogue.bullet_image.GetHeight () / 2; + margin = bullet_width; + spaces = Math.Int( (password_dialogue.entry.image.GetWidth () - (margin * 2)) / (bullet_width / 2 ) ); + #Debug ("spaces = " + spaces + ", bullets = " + bullets); + bullets_area.width = margin + spaces * (bullet_width / 2); + bullets_area.x = Window.GetX () + Window.GetWidth () / 2 - bullets_area.width / 2; + #DebugBottom ("pwd_entry x = " + password_dialogue.entry.x + ", bullets_area.x = " + bullets_area.x + ", bullets_area.width = " + bullets_area.width); + if (bullets > spaces) + bullets = spaces; + for (index = 0; password_dialogue.bullets[index] || index < bullets; index++){ + if (!password_dialogue.bullets[index]) { + password_dialogue.bullets[index].sprite = Sprite (); + password_dialogue.bullets[index].sprite.SetImage (password_dialogue.bullet_image); + password_dialogue.bullets[index].x = bullets_area.x + # password_dialogue.entry.x + margin + + index * bullet_width / 2; + password_dialogue.bullets[index].sprite.SetX (password_dialogue.bullets[index].x); + password_dialogue.bullets[index].y = bullet_y; + password_dialogue.bullets[index].sprite.SetY (password_dialogue.bullets[index].y); + password_dialogue.bullets[index].z = password_dialogue.entry.z + 1; + password_dialogue.bullets[index].sprite.SetZ (password_dialogue.bullets[index].z); + } + + password_dialogue.bullets[index].sprite.SetOpacity (0); + + if (index < bullets) { + password_dialogue.bullets[index].sprite.SetOpacity (1); + } + } +} + +Plymouth.SetDisplayPasswordFunction (display_password_callback); + +Plymouth.SetMessageFunction (message_callback); + +Plymouth.SetBootProgressFunction (animate_progress_indicator); + +# Plymouth.SetBootProgressFunction: the callback function is called with two numbers, the progress (between 0 and 1) and the time spent booting so far +# Plymouth.SetRootMountedFunction: the callback function is called when a new root is mounted +# Plymouth.SetKeyboardInputFunction: the callback function is called with a string containing a new character entered on the keyboard + +#----------------------------------------- FSCK Counter -------------------------------- + +# Initialise the counter +fun init_fsck_count () { + # The number of fsck checks in this cycle + global.counter.total = 0; + # The number of fsck checks already performed + the current one + global.counter.current = 1; + # The previous fsck + global.counter.last = 0; +} + +# Increase the total counter +fun increase_fsck_count () { + global.counter.total++; +} + +fun increase_current_fsck_count () { + global.counter.last = global.counter.current++; +} + +# Clear the counter +fun clear_fsck_count () { + global.counter = NULL; + init_fsck_count (); +} + +#----------------------------------------- Progress Label ------------------------------ + + +# Change the opacity level of a progress label +# +# opacity = 1 -> show +# opacity = 0 -> hide +# opacity = 0.3 (or any other float) -> translucent +# +fun set_progress_label_opacity (opacity) { + # the label + progress_label.sprite.SetOpacity (opacity); + + # Make the slot available again when hiding the bar + # So that another bar can take its place + if (opacity == 0) { + progress_label.is_available = 1; + progress_label.device = ""; + } +} + +# Set up a new Progress Bar +# +# TODO: Make it possible to reuse (rather than recreate) a bar +# if .is_available = 1. Ideally this would just reset the +# label, the associated +# device and the image size of the sprite. + +fun init_progress_label (device, status_string) { + # Make the slot unavailable + global.progress_label.is_available = 0; + progress_label.progress = 0; + progress_label.device = device; + progress_label.status_string = status_string; +} + +# See if the progress label is keeping track of the fsck +# of "device" +# +fun device_has_progress_label (device) { + #DebugBottom ("label device = " + progress_label.device + " checking device " + device); + return (progress_label.device == device); +} + +# Update the Progress bar which corresponds to index +# +fun update_progress_label (progress) { + # If progress is NULL then we just refresh the label. + # This happens when only counter.total has changed. + if (progress != NULL) { + progress_label.progress = progress; + + #Debug("device " + progress_label.device + " progress " + progress); + + # If progress >= 100% hide the label and make it available again + if (progress >= 100) { + set_progress_label_opacity (0); + + # See if we any other fsck check is complete + # and, if so, hide the progress bars and the labels + on_fsck_completed (); + + return 0; + } + } + # Update progress label here + # + # FIXME: the queue logic from this theme should really be moved into mountall + # instead of using string replacement to deal with localised strings. + label = StringReplace (progress_label.status_string[0], "%1$d", global.counter.current); + label = StringReplace (label, "%2$d", global.counter.total); + label = StringReplace (label, "%3$d", progress_label.progress); + label = StringReplace (label, "%%", "%"); + + progress_label = get_fsck_label (label, 0); + #progress_label.progress = progress; + + progress_label.sprite = Sprite (progress_label.image); + + # Set up the bar + progress_label.sprite.SetPosition(progress_label.x, progress_label.y, 1); + + set_progress_label_opacity (1); + +} + +# Refresh the label so as to update counters +fun refresh_progress_label () { + update_progress_label (NULL); +} + +#----------------------------------------- FSCK Queue ---------------------------------- + +# Initialise the fsck queue +fun init_queue () { + global.fsck_queue[0].device; + global.fsck_queue[0].progress; + global.fsck_queue.counter = 0; + global.fsck_queue.biggest_item = 0; +} + +fun clear_queue () { + global.fsck_queue = NULL; + init_queue (); +} + +# Return either the device index in the queue or -1 +fun queue_look_up_by_device (device) { + for (i=0; i <= fsck_queue.biggest_item; i++) { + if ((fsck_queue[i]) && (fsck_queue[i].device == device)) + return i; + } + return -1; +} + +# Keep track of an fsck process in the queue +fun add_fsck_to_queue (device, progress) { + # Look for an empty slot in the queue + for (i=0; global.fsck_queue[i].device; i++) { + continue; + } + local.index = i; + + # Set device and progress + global.fsck_queue[local.index].device = device; + global.fsck_queue[local.index].progress = progress; + + # Increase the queue counter + global.fsck_queue.counter++; + + # Update the max index of the array for iterations + if (local.index > global.fsck_queue.biggest_item) + global.fsck_queue.biggest_item = local.index; + + #DebugMedium ("Adding " + device + " at " + local.index); +} + +fun is_queue_empty () { + return (fsck_queue.counter == 0); +} + +fun is_progress_label_available () { + return (progress_label.is_available == 1); +} + + +# This should cover the case in which the fsck checks in +# the queue are completed before the ones showed in the +# progress label +fun on_queued_fsck_completed () { + if (!is_queue_empty ()) + return; + + # Hide the extra label, if any + #if (progress_bar.extra_label.sprite) + # progress_bar.extra_label.sprite.SetOpacity(0); +} + +fun remove_fsck_from_queue (index) { + # Free memory which was previously allocated for + # device and progress + global.fsck_queue[index].device = NULL; + global.fsck_queue[index].progress = NULL; + + # Decrease the queue counter + global.fsck_queue.counter--; + + # See if there are other processes in the queue + # if not, clear the extra_label + on_queued_fsck_completed (); +} + +fun on_fsck_completed () { + # We have moved on to tracking the next fsck + increase_current_fsck_count (); + + if (!is_progress_label_available ()) + return; + + if (!is_queue_empty ()) + return; + + # Hide the progress label + if (progress_label.sprite) + progress_label.sprite.SetOpacity (0); + + # Clear the queue + clear_queue (); + + # Clear the fsck counter + clear_fsck_count (); +} + +# Update an fsck process that we keep track of in the queue +fun update_progress_in_queue (index, device, progress) { + # If the fsck is complete, remove it from the queue + if (progress >= 100) { + remove_fsck_from_queue (index); + on_queued_fsck_completed (); + return; + } + + global.fsck_queue[index].device = device; + global.fsck_queue[index].progress = progress; + +} + +# TODO: Move it to some function +# Create an empty queue +#init_queue (); + + +#----------------------------------------- FSCK Functions ------------------------------ + + +# Either add a new bar for fsck checks or update an existing bar +# +# NOTE: no more than "progress_bar.max_number" bars are allowed +# +fun fsck_check (device, progress, status_string) { + + # The 1st time this will take place + if (!global.progress_label) { + # Increase the fsck counter + increase_fsck_count (); + + # Set up a new label for the check + init_progress_label (device, status_string); + update_progress_label (progress); + + return; + } + + + if (device_has_progress_label (device)) { + # Update the progress of the existing label + update_progress_label (progress); + } + else { + # See if there's already a slot in the queue for the device + local.queue_device_index = queue_look_up_by_device(device); + + # See if the progress_label is available + if (progress_label.is_available) { + +# local.my_string = "available index " + local.available_index + " progress_bar counter is " + progress_bar.counter; +# Debug(local.my_string); + + + # If the fsck check for the device was in the queue, then + # remove it from the queue + if (local.queue_device_index >= 0) { + remove_fsck_from_queue (index); + } + else { + # Increase the fsck counter + increase_fsck_count (); + } + +# local.my_string += local.message; + #Debug("setting new label for device " + device + " progress " + progress); + + # Set up a new label for the check + init_progress_label (device, status_string); + update_progress_label (progress); + + } + # If the progress_label is not available + else { + + # If the fsck check for the device is already in the queue + # just update its progress in the queue + if (local.queue_device_index >= 0) { + #DebugMedium("Updating queue at " + local.queue_device_index + " for device " + device); + update_progress_in_queue (local.queue_device_index, device, progress); + } + # Otherwise add the check to the queue + else { + #DebugMedium("Adding device " + device + " to queue at " + local.queue_device_index); + add_fsck_to_queue (device, progress); + + # Increase the fsck counter + increase_fsck_count (); + + refresh_progress_label (); + } + + } + } + +# if (!is_queue_empty ()) { +# DebugBottom("Extra label for "+ device); + #} +# else { +# DebugBottom("No extra label for " + device + ". 1st Device in the queue "+ fsck_queue[0].device + " counter = " + global.fsck_queue.counter); +# } +} + + +#-----------------------------------------Update Status stuff -------------------------- +# +# The update_status_callback is what we can use to pass plymouth whatever we want so +# as to make use of features which are available only in this program (as opposed to +# being available for any theme for the script plugin). +# +# Example: +# +# Thanks to the current implementation, some scripts can call "plymouth --update=fsck:sda1:40" +# and this program will know that 1) we're performing and fsck check, 2) we're checking sda1, +# 3) the program should set the label progress to 40% +# +# Other features can be easily added by parsing the string that we pass plymouth with "--update" +# +fun update_status_callback (status) { +# Debug(status); + if (!status) return; + + string_it = 0; + update_strings[string_it] = ""; + + for (i=0; (String(status).CharAt(i) != ""); i++) { + local.temp_char = String(status).CharAt(i); + if (temp_char != ":") + update_strings[string_it] += temp_char; + else + update_strings[++string_it] = ""; + } + +# my_string = update_strings[0] + " " + update_strings[1] + " " + update_strings[2]; +# Debug(my_string); + # Let's assume that we're dealing with these strings fsck:sda1:40 + if ((string_it >= 2) && (update_strings[0] == "fsck")) { + + device = update_strings[1]; + progress = update_strings[2]; + status_string[0] = update_strings[3]; # "Checking disk %1$d of %2$d (%3$d %% complete)" + if (!status_string[0]) + status_string[0] = "Checking disk %1$d of %2$d (%3$d %% complete)"; + + if ((device != "") && (progress != "")) { + progress = StringToInteger (progress); + + # Make sure that the fsck_queue is initialised + if (!global.fsck_queue) + init_queue (); + + # Make sure that the fsck counter is initialised + if (!global.counter) + init_fsck_count (); + +# if (!global.progress_bar.extra_label.sprite) +# create_extra_fsck_label (); + + # Keep track of the fsck check + fsck_check (device, progress, status_string); + } + + } + +} +Plymouth.SetUpdateStatusFunction (update_status_callback); + +#-----------------------------------------Display Question stuff ----------------------- +# +# TODO: Implement this if needed +# +# The callback function is called when the display should display a question dialogue. +# First arg is prompt string, the second is the entry contents. +#fun display_question_callback (prompt_string, entry_contents) +#{ +# time++; +#} +# +#Plymouth.SetDisplayQuestionFunction (display_question_callback); + +#-----------------------------------------Refresh stuff -------------------------------- +# +# Calling Plymouth.SetRefreshFunction with a function will set that function to be +# called up to 50 times every second, e.g. +# +# NOTE: if a refresh function is not set, Plymouth doesn't seem to be able to update +# the screen correctly +# +fun refresh_callback () +{ + draw_logo (); +} +Plymouth.SetRefreshFunction (refresh_callback); + + +#-----------------------------------------Display Normal stuff ----------------------- +# +# The callback function is called when the display should return to normal +fun display_normal_callback () +{ + global.status = "normal"; + if (global.password_dialogue) { + password_dialogue_opacity (0); + global.password_dialogue = NULL; + if (message_notification[2].sprite) hide_message(2); + prompt_active = 0; + } + + if (message_notification[1].sprite) show_message (1); + + +} + +Plymouth.SetDisplayNormalFunction (display_normal_callback); + + +#----------------------------------------- Quit -------------------------------- + +# TODO: Maybe we should also hide any other dialog +# Show the logo and make the progress indicator look full when on exit +fun quit_callback () +{ + logo.sprite.SetOpacity (1); + switch_on_bullets (); +} + +Plymouth.SetQuitFunction(quit_callback); diff --git a/plymouth-theme/edubuntu_logo.png b/plymouth-theme/edubuntu_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6612a839a6339e2383cf7ab5c9195898878fdd15 GIT binary patch literal 36573 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 z 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 iR(^ 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 literal 0 HcmV?d00001 diff --git a/plymouth-theme/edubuntu_logo16.png b/plymouth-theme/edubuntu_logo16.png new file mode 100644 index 0000000000000000000000000000000000000000..34d80d69b3b6b1bfec12bf1e635826791df2e251 GIT binary patch literal 980 zcmV;_11tQAP)d3|O+t~K%>i+om{{Q?9QC2$u z0004WQchCh90 zlCgr3{e)qxu^d7OA%q_NatI-W5JCtcgb+dqA#{(99I}WW!Pv$Yz@LB{1Aq;6C#+yQ zU782%5N5bEq>jveeNOS5@5&pt6v^7xzomH2_g%ax5QUzXFnHCv+;Z}ETS^l>0&g?j zm{RI!PUkQ1Hs>7<*MZh_)YBvI>U6pBa9#7yJ^XZDf7Fh5=!j@aM`M__r6cYq^7>pe z-Em)tXijHSAd28^#LJs5P3y9rJHxi`5xmWK<9?uSfzIN%r=x{9@alN;p1THmtINIv zczqk)aC$y%2Yp_?;BCPh`bcwLt=ycs!Rr+9PB4Zof6%=y-yXbr-X$;8DQ)yr7>=-d z8}M#l^XjeV4pD#G#AbxTUj^ z|0w9*4!rzOq2|3Gs^jH{l`|=L<906BIpy|woMtNJEd=LkdF7e3yv~}J;yP0QN4E=o zSD|}9CR_|Cc-=K6FK57e^$mg6lpFY)Vwv~l!Mll`S3i~Tk7~=y#c9urH%Q+U%gYJ8 z?E6&L4}H9TQ(Spb{uf?n$m^86oC&X^d;CqYlGlG4um2*vk}qE;OS<4K;&t>Y2VNzw ztI*{;8=kUIniJ?7*ww6@Z-sub!8CXA52hul3iF^}HUu)x0@VUJqXI z)(77I&Ff^6oSyeK%9_`k^Oi4PLtYPF??v8R39od5Z^x_mwdcJZu;b-Z*z@K}$H*wv zyxyAEt9kXlzHE%l>*cpwI=9#I%J+0x@k;j|6pYE043c))it~N&K0kga+^J!}tGWxS zWRN^UzV}YSdrdw?+qCaj9#lLFr{m=mytcp%7kT+4oQ{`Myckp8hW~_$IXE3JSG}7# zi$3y>E62zKRHS5;C1s=qMMb#y1=xA{*?546 zkCmI3g^P!o^NMYx6;MM|NswPK10xeN3o9Et2PYRd4=*3TfS{1Dh^Uyjq>QY*f})bL zimIB1mbQ+rp0TlsnYp>8rKOd%jg5`1ot=ZDqmz@9i;JtPo4dP*ho`5Pw@-3v-~1&z zuRVYH=JVf^RXj|rIf96i-J-$;@Y0{fD9R?QZj|-hWte@#=PF1m3D%4%5o;CB2_~A`= zuXyDxela;_<%ILguKwwHkj&#=`S07wv%wBUbK6g+na+>v;IrJZ;cC^|+AYzFyFWR; zzH$D@(t|S;W7n7cyY&A;%J;w5?po?DlQ}pubNQdLpRt$ky^c#hJ9SRyjjY=J>sP-2 zxoFB9(-}{noip2S^0jpRs+X3{CtV({TXb@Ld2D={k6P$PX5PEIb1MuDFMMFmcyX`x zayP%pqze*RHgahT8F@1tn58Z>u$e5tU|uo(px`6Vvd8;jIp_K0AC*V6W$Ts(>a=vT zUeS3tD>cZfR%qLdDSnf=@>V;Q*Ne(TCc2 literal 0 HcmV?d00001 diff --git a/plymouth-theme/password_field16.png b/plymouth-theme/password_field16.png new file mode 100644 index 0000000000000000000000000000000000000000..ff7f6b5b8693dedd36bde19506826d1bd4696907 GIT binary patch literal 177 zcmeAS@N?(olHy`uVBq!ia0y~yVB`g|^*ES;Bx~~?F(Abm;1lAyghPOziAzOV=7q=6 zWS}5pNswPKgTu2MX+Tbxr;B4q#jUru778*bFfbdw_~)FQ9Z(?gN!jK91eMr~y4Zx0 z#)}tUI5o5JN||I_Sm210Q88)u(L0+DPf(e=onf!5O5?MyZ|s0JFnGH9xvX!+#frlZ1C911~Dem@}n*YaRKAu?=U2iJC}-N&bRb=f6EKx6bNqeUNJ;C7V>gTe~DWM4fxNf{! literal 0 HcmV?d00001 diff --git a/plymouth-theme/progress_dot_off16.png b/plymouth-theme/progress_dot_off16.png new file mode 100644 index 0000000000000000000000000000000000000000..abbbab6801746d59a1364b35457c7ddb15d6d2df GIT binary patch literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^q9Dw{3?%2B3|#`GcmjMvT!Hih7xza2LI3{$+37Ve z6Ub*Q3GxeOaCmkj4aiaVba4!+xOMf+MqUO64kpLOzvb7?F$rhy+asW5Ccy4h^i1Rb c+keZhY0PHOIUFOl2dIU?)78&qol`;+09ey0(*OVf literal 0 HcmV?d00001 diff --git a/plymouth-theme/progress_dot_on.png b/plymouth-theme/progress_dot_on.png new file mode 100644 index 0000000000000000000000000000000000000000..6dd07b76166fae7652d0b0c9f0f098649be60254 GIT binary patch literal 379 zcmeAS@N?(olHy`uVBq!ia0vp^q9Dw{3?%2B3|#`GVgr0aT>m==S@f)+1^WO0|EUc? zYZw@0OM?7@85o(ESy?LTz<%dcHr(yl;-8$4YcLn>~S zUVO{ftiZ#1fl-&$Met+x>^=Xp*SRc?obs=6&V*%m_MH=Qn(~;xMJH5mx#v;_0YL}N zN(ydovTZ zNvW)6Day6?Ilaxt`M#BwmP(LtQq}W0_L^;N0bPrZwOiChZZ~AhkC=adUhQ+!^`9?p tw>n&V@6`QQmUoO-KdWB*DC*efdv!P7@^Gq(uZ;%z($m$?Wt~$(6954{nmhmi literal 0 HcmV?d00001 diff --git a/plymouth-theme/progress_dot_on16.png b/plymouth-theme/progress_dot_on16.png new file mode 100644 index 0000000000000000000000000000000000000000..7d5826315714d094000154de9763af618286edd8 GIT binary patch literal 122 zcmeAS@N?(olHy`uVBq!ia0vp^q9Dw{3?%2B3|#`G*aCb)Tp1Re@oDh5d_QOvP=v80 z$S;_|;n|HeAV