Lines added in edit (added_lines) | [
0 => 'This is [[Article description::a guide on how to create themes for plymouth: a bootsplash for system boot/shutdown]]',
1 => '',
2 => '== Defining a theme ==',
3 => '',
4 => 'Each theme should have its own directory within the root plymouth themes directory which can be typically found at <code>/usr/share/plymouth/themes</code>, however this is dependent on the <code>data</code> directory passed to meson whilst building plymouth<ref>https://gitlab.freedesktop.org/plymouth/plymouth/-/blob/main/meson.build</ref>. This tutorial will assume that the user is using the default theme location.',
5 => '',
6 => 'For a theme to be recognised by plymouth, a <code>theme_name.plymouth</code> file specimen is required to be present within the directory of the theme in order to define:',
7 => '* Theme name',
8 => '* Theme module/plugin (and the selected module's options)',
9 => '* Theme description',
10 => '',
11 => 'The rest of this tutorial will assume that the user is creating a theme called <code>example</code>, and all files will be assumed to be placed within it's relevant theme directory e.g. <code>/usr/share/plymouth/themes/example/</code>',
12 => '',
13 => '{{',
14 => 'CodeBox |',
15 => 'title=example.plymouth (general layout)|',
16 => 'lang=toml |',
17 => '1=[Plymouth-Theme]',
18 => 'Name=Example',
19 => 'Description=This will be an example plugin',
20 => 'ModuleName=selected-module-name',
21 => '',
22 => '[selected-module-name]',
23 => '...module options',
24 => '}}',
25 => '',
26 => '=== Theme Modules ===',
27 => '',
28 => 'Currently there are 7 different theme modules available which can also referred to as splash plugins, however this guide will only go into details about the '''''script''''' module since it is the most customisable, the rest of the modules offer limited capabilities/customisation with most being created specifically for default themes that already exist:',
29 => '',
30 => '{| class="table table-condensed table-striped" style="width: auto;"',
31 => '|-',
32 => '! Module Name',
33 => '! Customisability',
34 => '! Description',
35 => '! Implementation',
36 => '|-',
37 => '| script || most customisable || This allows for a script to be ran which has access to various functions to display sprites and text across the screen, it is the most customisable as a user can implement their own logic for the theme including complex animations. This will be the main focus of this guide. || [https://gitlab.freedesktop.org/plymouth/plymouth/-/tree/main/src/plugins/splash Source Code]',
38 => '|-',
39 => '| two-step || basic customisation || This displays a two-step animation based on the loading of a two phased boot process, it includes a progress animation synced to the boot time, and finishes with a fast one-shot animation. || [https://gitlab.freedesktop.org/plymouth/plymouth/-/tree/main/src/plugins/splash/two-step Source Code]',
40 => '|-',
41 => '| space-flares || slighty (can swap images & font) || Used for the solar theme: "Space theme with violent flaring blue star" || [https://gitlab.freedesktop.org/plymouth/plymouth/-/tree/main/src/plugins/splash/space-flares Source Code]',
42 => '|-',
43 => '| fade-throbber || none || Used for the fade-in theme: "Simple theme that fades in and out with shimmering stars" || [https://gitlab.freedesktop.org/plymouth/plymouth/-/tree/main/src/plugins/splash/fade-throbber Source Code]',
44 => '|-',
45 => '| tribar || none || Used for the tribar theme: "text mode theme with tricolor progress bar" || [https://gitlab.freedesktop.org/plymouth/plymouth/-/tree/main/src/plugins/splash/tribar Source Code]',
46 => '|-',
47 => '| text || none || This is used for the text theme: "text-only boot splash" || [https://gitlab.freedesktop.org/plymouth/plymouth/-/tree/main/src/plugins/splash/text Source Code]',
48 => '|-',
49 => '| details || none || This is used for the details theme which is the verbose text fallback theme || [https://gitlab.freedesktop.org/plymouth/plymouth/-/tree/main/src/plugins/splash/details Source Code]',
50 => '|-',
51 => '|}',
52 => '',
53 => '== Writing a script theme ==',
54 => 'Plymouth uses its own language implementation for scripts, it is a '''''C'''''-style language, it is recommended to read the [https://www.freedesktop.org/wiki/Software/Plymouth/Scripts/ plymouth documentation] on it's language which can help the user get a general understanding of how to write a script.',
55 => '',
56 => '=== Specimen ===',
57 => 'To define a '''script''' theme, you use <code>script</code> as the module name in the <code>example.plymouth</code> file.',
58 => '',
59 => 'The script module has four options that can be defined:',
60 => '* <code>ScriptFile</code>: An absolute path to the script file.',
61 => '* <code>ImageDir</code>: An absolute path to a directory.',
62 => '* <code>MonospaceFont</code>: The font to use in text sprites (the font needs to be available in the initramfs). (optional)',
63 => '* <code>ConsoleLogTextColor</code>: The color to use for console logs (in hex: 0x''ffffff'') (optional)',
64 => '',
65 => '{{CodeBox|title=example.plymouth|lang=toml|1=',
66 => '[Plymouth-Theme]',
67 => 'Name=Example',
68 => 'Description=This will be an example plugin',
69 => 'ModuleName=script',
70 => '',
71 => '[script]',
72 => 'ScriptFile=/usr/share/plymouth/themes/example/example.script',
73 => 'ImageDir=/usr/share/plymouth/themes/example/',
74 => '}}',
75 => '',
76 => 'It is '''''recommended''''' to keep scripts and files in their respectives theme folders (so that they are populated in the initramfs).',
77 => '',
78 => '=== Terminology ===',
79 => '',
80 => '* Image: An image is a resource that has been loaded.',
81 => '* Sprite: A sprite is an image that has been placed.',
82 => '',
83 => '',
84 => '=== Hookable event callbacks ===',
85 => 'There are lots of different callbacks you can use in a script to track events/boot progress, each of these take a function as a parameter, which is called with the appropriate data when the relevant event is fired.',
86 => '',
87 => '{{CodeBox|lang=C|1=',
88 => '# The refresh function is called `x` amount of times per second, where `x` is the refresh rate set with `Plymouth.SetRefreshRate` or the default value (50).',
89 => 'fun on_refresh() {}',
90 => '',
91 => 'Plymouth.SetRefreshFunction(on_refresh);',
92 => '}}',
93 => '',
94 => '{{CodeBox|lang=C|1=',
95 => '# The boot progress function is called whenever progress is made during the boot process.',
96 => 'fun on_boot_progress(duration, progress) {}',
97 => '# duration and progress are both `numbers`',
98 => '',
99 => 'Plymouth.SetBootProgressFunction(on_boot_progress);',
100 => '}}',
101 => '',
102 => '{{CodeBox|lang=C|1=',
103 => '# The root mounted function is called when the root partition is mounted (needs verification).',
104 => 'fun on_root_mounted() {}',
105 => '',
106 => 'Plymouth.SetRootMountedFunction(on_root_mounted);',
107 => '}}',
108 => '',
109 => '{{CodeBox|lang=C|1=',
110 => '# The keyboard input function is called whenever input is made on a keyboard, this does not trigger on non-text characters such as return (needs verification).',
111 => 'fun on_keyboard_input(char) {}',
112 => '# char is a string containing the character pressed.',
113 => '',
114 => 'Plymouth.SetKeyboardInputFunction(on_keyboard_input);',
115 => '}}',
116 => '',
117 => '{{CodeBox|lang=C|1=',
118 => '# This is called whenever the status is changed.',
119 => 'fun on_status_update(new_status) {}',
120 => '# new_status is a string containing the new status.',
121 => '',
122 => 'Plymouth.SetUpdateStatusFunction(on_status_update);',
123 => '}}',
124 => '',
125 => '{{CodeBox|lang=C|1=',
126 => '# This is called whenever the display should return to normal.',
127 => 'fun on_mode_normal() {}',
128 => '',
129 => 'Plymouth.SetDisplayNormalFunction(on_mode_normal);',
130 => '}}',
131 => '',
132 => '{{CodeBox|lang=C|1=',
133 => '# This is called whenever the display should show a password prompt.',
134 => 'fun on_mode_password(prompt, bullets) {}',
135 => '# prompt is a string and bullets is a number indicating how many characters have been entered. ',
136 => '',
137 => 'Plymouth.SetDisplayPasswordFunction(on_mode_password);',
138 => '}}',
139 => '',
140 => '{{CodeBox|lang=C|1=',
141 => '# This is called whenever a question is asked.',
142 => 'fun on_mode_question(prompt, entry_text) {}',
143 => '# prompt and entry_text are strings.',
144 => '',
145 => 'Plymouth.SetDisplayQuestionFunction(on_mode_question);',
146 => '}}',
147 => '',
148 => '{{CodeBox|lang=C|1=',
149 => '# This is called whenever a prompt needs displaying.',
150 => 'fun on_mode_prompt(prompt, entry_text, is_secret) {}',
151 => '# prompt and entry_text are strings and is_secret is a bool.',
152 => '',
153 => 'Plymouth.SetDisplayPromptFunction(on_mode_prompt);',
154 => '}}',
155 => '',
156 => '{{CodeBox|lang=C|1=',
157 => '# This is called whenever a device is hotplugged into the machine.',
158 => 'fun on_hotplug() {}',
159 => '',
160 => 'Plymouth.SetDisplayHotplugFunction();',
161 => '}}',
162 => '',
163 => '{{CodeBox|lang=C|1=',
164 => '# This is called whenever an input needs validation.',
165 => 'fun on_validate_input(entry_text, additional_text) { return some_bool; }',
166 => '# entry_text and additional_text are both strings, the function expects a boolean return value.',
167 => '',
168 => 'Plymouth.SetValidateInputFunction(on_validate_input);',
169 => '}}',
170 => '',
171 => '{{CodeBox|lang=C|1=',
172 => '# This is called when a new message needs to be displayed.',
173 => 'fun on_message(message) {}',
174 => '# message is a string.',
175 => '',
176 => 'Plymouth.SetDisplayMessageFunction(on_message);',
177 => '}}',
178 => '',
179 => '{{CodeBox|lang=C|1=',
180 => '# This is called to hide a previously shown message.',
181 => 'fun on_hide_message(message) {}',
182 => '# message is a string.',
183 => '',
184 => 'Plymouth.SetHideMessageFunction(on_hide_message);',
185 => '}}',
186 => '',
187 => '{{CodeBox|lang=C|1=',
188 => '# This is called when plymouth is quitting.',
189 => 'fun on_quit() {}',
190 => '',
191 => 'Plymouth.SetQuitFunction(on_quit);',
192 => '}}',
193 => '',
194 => '{{CodeBox|lang=C|1=',
195 => '# This is called when there is a system update.',
196 => 'fun on_system_update(status) {}',
197 => '# status is a string of the new status of the system.',
198 => '',
199 => 'Plymouth.SetSystemUpdateFunction();',
200 => '}}',
201 => '',
202 => '=== Other Builtin Functions ===',
203 => 'There are also other builtin functions which are listed below:',
204 => '{{CodeBox|lang=C|1=',
205 => '# returns a boolean depicting the current capslock state (true=on, false=off)',
206 => 'Plymouth.GetCapslockState(): returns bool',
207 => '',
208 => '# returns the current mode that plymouth is in (normal, password, question, ...)',
209 => 'Plymouth.GetMode(): returns string;',
210 => '',
211 => '# sets the amount of times the refresh function is called per second.',
212 => 'Plymouth.SetRefreshRate(number): returns null;',
213 => '}}',
214 => '',
215 => 'In addition to this, there are also some mathematics functions under a different namespace:',
216 => '{{CodeBox|lang=C|1=',
217 => '# Returns absolute (positive) of a number.',
218 => 'Math.Abs(number);',
219 => '',
220 => '# Returns the smallest number from two numbers.',
221 => 'Math.Min(number1, number2);',
222 => '',
223 => '# Returns the largest number from two numbers.',
224 => 'Math.Max(number1, number2);',
225 => '',
226 => '# Forces the value to be between min and max, otherwise either min or max are returned.',
227 => 'Math.Clamp(value, min, max);',
228 => '',
229 => '# The value of Pi (3.14159...) to 21 d.p.',
230 => 'Math.Pi();',
231 => '',
232 => '# Cosine function',
233 => 'Math.Cos(radians);',
234 => '',
235 => '# Sine function',
236 => 'Math.Sin(radians);',
237 => '',
238 => '# Tangent function',
239 => 'Math.Tan(radians);',
240 => '',
241 => '# Arc tangent function taking 2 values (see "man atan2")',
242 => 'Math.ATan2(x, y);',
243 => '',
244 => '# Square root of a number',
245 => 'Math.Sqrt(number);',
246 => '',
247 => '# Returns the rounded down integer.',
248 => 'Math.Int(number);',
249 => '',
250 => '# Returns a pseudo random number between 0 and 1. ',
251 => 'Math.Random();',
252 => '}}',
253 => '',
254 => 'Strings, images and sprites that each have their own associated functions:',
255 => '{{CodeBox|lang=C|1=',
256 => '',
257 => '# Create a string object',
258 => 'string_example = String("some string"); # or alternatively just "some string".',
259 => '',
260 => '# Associated methods for strings:',
261 => '# Returns the character at the given index',
262 => 'string_example.CharAt(number);',
263 => '# Returns a substring starting at index `start` and ending at index `end`.',
264 => 'string_example.SubString(start, end);',
265 => '# Returns the length of the string',
266 => 'string_example.Length();',
267 => '',
268 => '',
269 => '# Creates an image object from the image at the given location.',
270 => 'image_example = Image(filename);',
271 => '# Creates an image from text. All parameters apart from text are optional.',
272 => 'Image.Text = fun (text, red, green, blue, alpha, font, align)',
273 => '',
274 => '# Associated methods for images:',
275 => '# Rotates the image by the given angle',
276 => 'image_example.Rotate(angle);',
277 => '# Crops the given image starting at x, y and ending at x+width, y+height.',
278 => 'image_example.Crop(x, y, width, height);',
279 => '# Scales the given image to a given width and height.',
280 => 'image_example.Scale(width, height);',
281 => '# Tiles the given image to a given width and height.',
282 => 'image_example.Tile(width, height);',
283 => '',
284 => '',
285 => '# Creates a sprite, image is *optional*, if not provided then a sprite with no image is made, you can change the image later.',
286 => 'sprite_example = Sprite(image);',
287 => '',
288 => '# Sprites also have methods associated with them:',
289 => '# This sets the X coordinate of the sprite to number',
290 => 'sprite_example.SetX(number);',
291 => '# This sets the Y coordinate of the sprite to number',
292 => 'sprite_example.SetY(number);',
293 => '# This sets the Z coordinate of the sprite to number',
294 => 'sprite_example.SetZ(number);',
295 => '# You can also get and set the sprite opacity:',
296 => 'sprite_example.SetOpacity(number);',
297 => 'sprite_example.GetOpacity();',
298 => '# You can also get the width and height of the sprite:',
299 => 'sprite_example.GetWidth();',
300 => 'sprite_example.GetHeight();',
301 => '# Finally you can also get and set the image of the sprite',
302 => 'sprite_example.SetImage(image);',
303 => 'sprite_example.GetImage();',
304 => '',
305 => '# These can also all be set together using (WARNING: this is deprecated).',
306 => 'SetPosition(sprite_example, x,y,z)',
307 => '}}',
308 => '',
309 => 'You can also get and set attributes for the window',
310 => '{{CodeBox|lang=C|1=',
311 => '# Get the display width and height',
312 => 'Window.GetWidth();',
313 => 'Window.GetHeight();',
314 => '',
315 => '# Get and set the position of the background window sprite',
316 => 'Window.GetX(number);',
317 => 'Window.GetY(number);',
318 => '',
319 => 'Window.SetX(number);',
320 => 'Window.SetY(number);',
321 => '',
322 => '# And you can also change the background sprite color:',
323 => 'Window.SetBackgroundTopColor(r, g, b);',
324 => 'Window.SetBackgroundBottomColor(r, g, b);',
325 => '}}',
326 => '',
327 => '',
328 => '',
329 => '=== Creating animations ===',
330 => 'One common way to create animations is to load all images for the animation and store them within a hashmap, then on each refresh we change the image that a sprite is displaying onto the next frame (and then loop to the start when the end of the animation is reached).',
331 => '{{CodeBox|lang=C|1=',
332 => '',
333 => ' animation_first_frame = 0;',
334 => 'animation_last_frame = 250;',
335 => 'animation_current_frame = 0;',
336 => '',
337 => 'for (frame = animation_first_frame; frame <= animation_last_frame; frame++) {',
338 => ' animation_images[frame] = Image("animation/frame-" + frame + ".png");',
339 => '}',
340 => '',
341 => '# Create a sprite for the password box, we will assign a image later to it later.',
342 => 'animation_sprite = Sprite();',
343 => '# Align the animation in the centre of the screen (optional)',
344 => 'animation_width = animation_images[animation_first_frame].GetWidth();',
345 => 'animation_height = animation_images[animation_first_frame].GetHeight();',
346 => 'animation_sprite.SetX((Window.GetWidth() / 2) - (animation_width / 2));',
347 => 'animation_sprite.SetY((Window.GetHeight() / 2) - (animation_height / 2));',
348 => 'animation_sprite.SetZ(-1);',
349 => '',
350 => '# Now to animate we can change the image used in the sprite each frame,',
351 => 'fun on_refresh() {',
352 => ' animation_current_frame += 1;',
353 => ' if (animation_current_frame > animation_last_frame) {',
354 => ' # loop back to the start when the last frame is reached.',
355 => ' animation_current_frame = animation_first_frame;',
356 => ' }',
357 => ' animation_sprite.SetImage(animation_images[animation_current_frame]);',
358 => '}',
359 => 'Plymouth.SetRefreshFunction(on_refresh);',
360 => '}}',
361 => '',
362 => '== Writing a two-step theme ==',
363 => '{{Stub}}',
364 => '',
365 => '== Writing a space-flares theme ==',
366 => '=== Specimen ===',
367 => 'To define a '''space-flares''' theme, you use <code>space-flares</code> as the module name in the <code>example.plymouth</code> file.',
368 => '',
369 => 'The space-flares module has three options that can be defined:',
370 => '* <code>ImageDir</code>: An absolute path to a directory that contains images.',
371 => '* <code>MonospaceFont</code>: The font to use in text sprites (the font needs to be available in the initramfs). (optional)',
372 => '* <code>ConsoleLogTextColor</code>: The color to use for console logs (in hex: 0x''ffffff'') (optional)',
373 => '',
374 => '{{CodeBox|title=example.plymouth|lang=toml|1=',
375 => '[Plymouth-Theme]',
376 => 'Name=Example',
377 => 'Description=This will be an example plugin',
378 => 'ModuleName=space-flares',
379 => '',
380 => '[space-flares]',
381 => 'ImageDir=/usr/share/plymouth/themes/example/',
382 => '}}',
383 => '',
384 => '=== Customising',
385 => 'There are limited options for customising a solar-flares theme, you are limited to changing the following images (note: all of the images must be present):',
386 => '* lock.png',
387 => '* box.png',
388 => '* star.png',
389 => '* plant1.png (used if <code>SHOW_PLANETS</code> is defined in source)',
390 => '* plant2.png (used if <code>SHOW_PLANETS</code> is defined in source)',
391 => '* plant3.png (used if <code>SHOW_PLANETS</code> is defined in source)',
392 => '* plant4.png (used if <code>SHOW_PLANETS</code> is defined in source)',
393 => '* plant5.png (used if <code>SHOW_PLANETS</code> is defined in source)',
394 => '* progress_bar.png (used if <code>SHOW_PROGRESS_BAR</code> is defined in source)',
395 => '',
396 => '',
397 => 'The amount of images actually displayed depends on how plymouth is compiled<ref>https://gitlab.freedesktop.org/plymouth/plymouth/-/blob/main/src/plugins/splash/space-flares/plugin.c#L69</ref>, however it defaults to showing a progress bar, with no planets, no comets, and, no logo halo.',
398 => 'You can also change more options by editing the source code at <code>/src/plugins/splash/space-flares/plugin.c</code> where you can define fps, blur, flare count, flare lines, and star Hz.',
399 => '',
400 => '== Activating a theme ==',
401 => 'To set a theme you may refer to: https://wiki.gentoo.org/wiki/Plymouth#Themes',
402 => '',
403 => '== Troubleshooting ==',
404 => '',
405 => 'To temporarily disable plymouth , you can add the following kernel parameters:',
406 => '{{CodeBox|1=plymouth.enable=0 disablehooks=plymouth}}',
407 => '',
408 => 'To write debug output into /var/log/plymouth-debug.log, you can add the following kernel parameter:',
409 => '{{CodeBox|1=plymouth.debug}}',
410 => '',
411 => 'If themes are not loading properly it may be a good idea to check the user's initramfs to ensure that it has been populated with the plymouth binaries and themes<ref>https://wiki.gentoo.org/wiki/Plymouth#Manual_initramfs_creation</ref>',
412 => '',
413 => '',
414 => '== See also ==',
415 => '',
416 => '* {{See also|Plymouth}}',
417 => '',
418 => '== External resources ==',
419 => '',
420 => '',
421 => '* [https://gitlab.freedesktop.org/plymouth/plymouth/-/tree/main/src/plugins/splash script module source code]',
422 => '* [https://www.freedesktop.org/wiki/Software/Plymouth/Scripts/ Freedesktop Plymouth Script Wiki]',
423 => '* [https://github.com/adi1090x/plymouth-themes Large theme repository]',
424 => '* [https://wiki.archlinux.org/title/Plymouth Arch wiki on plymouth]',
425 => '* [https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/desktop_migration_and_administration_guide/plymouth Redhat guide for plymouth theme creation]',
426 => '',
427 => '== References ==',
428 => '',
429 => '{{reflist}}',
430 => '',
431 => '[[Category:Software:Plymouth]]'
] |