Archive for December 16th, 2009

Plymouth theming guide (part 4)

This the final part of the theming guide. As I mentioned in the last post, you already know everything you need to write your themes. In this post I will show a couple themes I wrote to explore the system and some fancy high level aspects of the scripting language. You don’t need to know these, they are just a cute method to solve a problem that others may find useful.


To install these themes, extract them to /usr/share/plymouth/themes and run the appropriate plymouth-set-default-theme line.


A very simple theme matching what the Vista theme does. It has just 30 lines of custom code.



This theme has the target of stressing the system. A couple months ago it was running at about 3 fps, now my machine hits 30 fps and spends some time idle.



When I first proposed doing a scripting system Ray said “If you do this, I guess I’d recommend you keep it very simple”. I agreed, so what I aimed to do was to implement all the features with the minimum space. The solution I came up was to kill several birds with one stone. The stone being an inheritance system.

The important operation for inheritance is the single bar (“|“), inherit operator. Think of it as a very lazy OR function. As an example take the statement:

A = B | C;

This creates a new object (A) which is an inheritance of B and C. A now gains all the properties of B and, as a fall-back, C. There are three ways of using inheritance objects.


Consider the following statement:

A = "Seven" | 7;
B = String(A).CharAt(2);
C = 80 + A;

So A is an inheritance of the string “Seven” and the number 7. This means when in situations where a string is preferred, it will act as a string, and when the a number is preferred, it will act as a number. The value in B will be the third character in the string (“v”), and the value in C will be the number 87.

This kind of inheritance is used to allow native C objects (images, sprites etc.) to be able to be used as hashes to find appropriate functions to call. An object is created which inherits from the native object and the object template hash (which holds all the functions). The constructor function is also connected to the template using an inheritance. Thus you can treat it as a function, or as a hash of functions and it will adopt the appropriate behaviour.

text_image = Image.Text("string"); # Treat Image as a hash
png_image = Image("filename.png"); # Treat Image as a function


Hashes are the main containers in the system. When an object inherits from two hashes, accessing the inner elements will trigger a crawl through all hashes for that element.

A.a = "a";
A.b = "b";   # A: a="a", b="b"
B.b = "B";
B.c = "C";   # B: b="B", c="c"
C = A | B;   # C: a="a", b="b", c="c"

When accessing the elements within C, the system looks within A, then B (also within any object they inherit from). Thus, elements within B can be overridden by A. This is very much like the __proto__ in Mozilla JavaScript.


Just like hashes, when functions are inherited, the system goes through them in the inheritance sequence, executing each one and moving onto the next if it has failed.

Fib = fun (v) {if (v <= 2) return 1; else fail;}
    | fun (v) {if (FibCache[v]) return FibCache[v]; else fail;}
    | fun (v) {return FibCache[v] = Fib(v-1) + Fib(v-2);};

If you have ever programmed the ML languages, you will already be somewhat familiar with this. In those, you can put constants in the function variable decelerations and functions which do not match these to the passed parameters, fail. Here, at any point in the function, you can choose to fail. The system then tries to execute the next function in the inheritance.