The Pedigree Project 0.1
modules/system/splash/main.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/BootstrapInfo.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/Log.h"
23#include "pedigree/kernel/Service.h"
24#include "pedigree/kernel/ServiceFeatures.h"
25#include "pedigree/kernel/ServiceManager.h"
26#include "pedigree/kernel/core/BootIO.h"
27#include "pedigree/kernel/graphics/Graphics.h"
28#include "pedigree/kernel/graphics/GraphicsService.h"
29#include "pedigree/kernel/machine/Display.h"
30#include "pedigree/kernel/machine/Framebuffer.h"
31#include "pedigree/kernel/machine/InputManager.h"
32#include "pedigree/kernel/process/Mutex.h"
33#include "pedigree/kernel/process/TerminationDeferral.h"
34#include "pedigree/kernel/processor/types.h"
35#include "pedigree/kernel/utilities/Cord.h"
36#include "pedigree/kernel/utilities/StaticString.h"
37#include "pedigree/kernel/utilities/String.h"
38#include "pedigree/kernel/utilities/Vector.h"
39#include "pedigree/kernel/utilities/assert.h"
40#include "pedigree/kernel/utilities/utility.h"
41
42#include "font.h"
43#include "image.h"
44#include "modules/Module.h"
45
46static Framebuffer* g_pFramebuffer = 0;
47
48static uint8_t* g_pBuffer = 0;
49static Graphics::Buffer* g_pFont = 0;
50static size_t g_Width = 0;
51static size_t g_Height = 0;
52static size_t g_DesiredWidth = 1024;
53static size_t g_DesiredHeight = 768;
54static size_t g_DesiredBpp = 32;
55
56static uint32_t g_BackgroundColour = 0x000000;
57static uint32_t g_ForegroundColour = 0xFFFFFF;
58static uint32_t g_ProgressBorderColour = 0x965000;
59static uint32_t g_ProgressColour = 0x966400;
60
61static Graphics::PixelFormat g_ColorFormat = Graphics::Bits24_Rgb;
62
63static size_t g_ProgressX, g_ProgressY;
64static size_t g_ProgressW, g_ProgressH;
65static size_t g_LogBoxX, g_LogBoxY;
66static size_t g_LogX, g_LogY;
67static size_t g_LogW, g_LogH;
68
69static GraphicsService::GraphicsParameters g_GraphicsParams;
70
71static size_t g_Previous = 0;
72static bool g_LogMode = true;
73
74static bool g_NoGraphics = false;
75
76static Mutex g_PrintLock;
77
78static void printChar(char c, size_t x, size_t y) {
79 if (!g_pFramebuffer)
80 return;
81
82 g_pFramebuffer->blit(g_pFont, 0, c * FONT_HEIGHT, x, y, FONT_WIDTH, FONT_HEIGHT);
83}
84
85static bool printChar(char c) {
86 if (!g_pFramebuffer) {
87 return false;
88 }
89
90 if (!c) {
91 return false;
92 }
93
94 if (c == '\t') {
95 g_LogX = (g_LogX + 8) & ~7;
96 } else if (c == '\r') {
97 g_LogX = 0;
98 } else if (c == '\n') {
99 g_LogX = 0;
100 g_LogY++;
101 } else if (c >= ' ') {
102 g_pFramebuffer->blit(g_pFont, 0, c * FONT_HEIGHT, g_LogBoxX + (g_LogX * FONT_WIDTH),
103 g_LogBoxY + (g_LogY * FONT_HEIGHT), FONT_WIDTH, FONT_HEIGHT);
104 g_LogX++;
105 }
106
107 if (g_LogX >= g_LogW / FONT_WIDTH) {
108 g_LogX = 0;
109 g_LogY++;
110 }
111
112 // Overflowed the view?
113 if (g_LogY >= (g_LogH / FONT_HEIGHT)) {
114 // By how much?
115 size_t diff = g_LogY - (g_LogH / FONT_HEIGHT) + 1;
116
117 // Scroll up
118 g_pFramebuffer->copy(g_LogBoxX, g_LogBoxY + (diff * FONT_HEIGHT), g_LogBoxX, g_LogBoxY, g_LogW,
119 ((g_LogH / FONT_HEIGHT) - diff) * FONT_HEIGHT);
120 g_pFramebuffer->rect(g_LogBoxX, g_LogBoxY + ((g_LogH / FONT_HEIGHT) - diff) * FONT_HEIGHT,
121 g_LogW, diff * FONT_HEIGHT, g_BackgroundColour, g_ColorFormat);
122
123 g_LogY -= diff;
124 return true;
125 }
126 return false;
127}
128
129static bool printString(const char* str, size_t len = 0) {
130 if (len == 0) {
131 len = StringLength(str);
132 }
133
134 if (!g_NoGraphics) {
135 bool scrolled = false;
136 for (size_t i = 0; i < len; i++) {
137 if (printChar(str[i])) {
138 scrolled = true;
139 }
140 }
141 return scrolled;
142 } else {
143 static HugeStaticString s;
144 s += str;
145
146 // Truncate the string if we need to.
149 if (s.length() >= 79) {
150 s.truncate(75);
151 s += "...>\n";
152 }
153
154 BootIO::Colour c = BootIO::LightGrey;
155 if (str[1] == 'W')
156 c = BootIO::Orange;
157 else if (str[1] == 'E' || str[1] == 'F')
158 c = BootIO::Red;
159 else if (str[1] == 'D')
160 c = BootIO::DarkGrey;
161
162 bootIO.write(s, c, BootIO::Black);
163 s.clear();
164 }
165 return false;
166}
167
168static void printString(const LogCord& str) {
169 TerminationDeferral lifetime;
170 // Progress rendering can log while holding this lock, and another CPU can
171 // log while holding a driver lock needed by the renderer. The ring retains
172 // messages even when the splash cannot safely display them now.
173 if (!g_PrintLock.tryAcquire()) {
174 return;
175 }
176 Framebuffer* parent = nullptr;
177 size_t firstRow = g_LogY;
178 bool scrolled = false;
179 if (!g_NoGraphics && g_pFramebuffer) {
180 // Scroll the RAM backing buffer, avoiding reads from slow scanout memory.
181 // Publish the completed message once, including any wrapped lines.
182 parent = g_pFramebuffer->getParent();
183 g_pFramebuffer->setParent(nullptr);
184 }
185 for (auto it = str.segbegin(); it != str.segend(); ++it) {
186 if (printString(it.ptr(), it.length())) {
187 scrolled = true;
188 }
189 }
190 if (parent) {
191 g_pFramebuffer->setParent(parent);
192 if (scrolled) {
193 firstRow = 0;
194 }
195 g_pFramebuffer->redraw(g_LogBoxX, g_LogBoxY + firstRow * FONT_HEIGHT, g_LogW,
196 (g_LogY - firstRow + 1) * FONT_HEIGHT, false);
197 }
198 g_PrintLock.release();
199}
200
201static void printStringAt(const char* str, size_t x, size_t y) {
203 for (size_t i = 0; i < StringLength(str); i++) {
204 printChar(str[i], x, y);
205 x += FONT_WIDTH;
206 }
207}
208
209static void centerStringAt(const char* str, size_t midX, size_t midY) {
211 size_t stringWidth = StringLength(str) * FONT_WIDTH;
212 size_t stringHeight = FONT_HEIGHT;
213
214 size_t x = midX - (stringWidth / 2);
215 size_t y = midY - (stringHeight / 2);
216 printStringAt(str, x, y);
217}
218
220 public:
221 virtual ~StreamingScreenLogger();
222
225 void callback(const LogCord& cord, bool = true) {
226 if (g_LogMode) {
227 printString(cord);
228 }
229 }
230};
231
232StreamingScreenLogger::~StreamingScreenLogger() = default;
233
234static StreamingScreenLogger g_StreamLogger;
235
236static void keyCallback(InputManager::InputNotification& note) {
237 if (note.type != InputManager::Key)
238 return;
239
240 uint64_t key = note.data.key.key;
241 if (key == '\033') {
242 // Because we edit the dimensions of the screen, we can't let a print
243 // continue while we run here.
244 LockGuard<Mutex> guard(g_PrintLock);
245
246 if (!g_LogMode) {
247 g_LogMode = true;
248 } else {
249 g_LogY += (g_LogBoxY / FONT_HEIGHT);
250 g_LogX = (g_LogBoxX / FONT_WIDTH);
251 g_LogBoxX = g_LogBoxY = 0;
252 g_LogW = g_Width;
253 g_LogH = g_Height;
254 }
255 }
256}
257
258static void progress(const char* text) {
259 const bool bFinished =
260 g_BootProgressTotal && ((g_BootProgressCurrent + 1) >= g_BootProgressTotal);
261 if (bFinished) {
262 // Callback removal can wait for an invocation which needs
263 // g_PrintLock, so it must happen before this function takes that lock.
264 Log::instance().removeCallback(&g_StreamLogger);
265
266 EMIT_IF(DEBUGGER) {
267 if (!g_NoGraphics) {
269 }
270 }
271 }
272
273 LockGuard<Mutex> guard(g_PrintLock);
274
275 // Calculate percentage.
276 if (g_BootProgressTotal == 0)
277 return;
278
279 if (g_NoGraphics) {
280 // Prepare to center the progress bar (22 characters wide).
282 s = " ";
283 for (size_t i = 0; i < (80 / 2) - 11; ++i) {
284 bootIO.write(s, BootIO::Black, BootIO::Black);
285 }
286
287 // Render progress bar - style: [###---]
288 s = "[";
289 size_t pos = (20 * g_BootProgressCurrent) / g_BootProgressTotal;
290 for (size_t i = 0; i < 20; ++i) {
291 if (i <= pos)
292 s += '#';
293 else
294 s += '-';
295 }
296 s += "]\r";
297 bootIO.write(s, BootIO::White, BootIO::Black);
298 } else if (g_LogMode && g_LogH == g_Height) {
299 if (bFinished) {
300 NOTICE("splash: destroying font pixel buffer");
301 g_pFramebuffer->destroyBuffer(g_pFont);
302 NOTICE("splash: destroying font heap buffer");
303 delete[] g_pBuffer;
304
305 NOTICE("splash: destroying framebuffer");
306 Graphics::destroyFramebuffer(g_pFramebuffer);
307 NOTICE("splash: destroyed framebuffer");
308 g_pFramebuffer = 0;
309
310 g_BootProgressUpdate = 0;
311 }
312 } else if (g_pFramebuffer) {
313 size_t w = (g_ProgressW * g_BootProgressCurrent) / g_BootProgressTotal;
314 if (g_Previous <= g_BootProgressCurrent)
315 g_pFramebuffer->rect(g_ProgressX, g_ProgressY, w, g_ProgressH, g_ProgressColour,
316 g_ColorFormat);
317 else
318 g_pFramebuffer->rect(g_ProgressX + w, g_ProgressY, g_ProgressW - w, g_ProgressH,
319 g_BackgroundColour, g_ColorFormat);
320 g_Previous = g_BootProgressCurrent;
321
322 char buf[80];
323 StringFormat(buf, "%d%%", ((g_BootProgressCurrent * 100) / g_BootProgressTotal));
324 centerStringAt(buf, g_ProgressX + (g_ProgressW / 2), g_ProgressY - FONT_HEIGHT);
325
326 g_pFramebuffer->redraw(g_ProgressX, g_ProgressY - (FONT_HEIGHT * 2), g_ProgressW,
327 g_ProgressH + (FONT_HEIGHT * 2), true);
328
329 if (bFinished) {
330 // Clean up font
331 NOTICE("splash: destroying font pixel buffer");
332 g_pFramebuffer->destroyBuffer(g_pFont);
333 NOTICE("splash: destroying font heap buffer");
334 delete[] g_pBuffer;
335
336 // Destroy the framebuffer now that we're done
337 NOTICE("splash: destroying framebuffer");
338 Graphics::destroyFramebuffer(g_pFramebuffer);
339 NOTICE("splash: destroyed framebuffer");
340 g_pFramebuffer = 0;
341
342 // No longer wanting any progress callback.
343 g_BootProgressUpdate = 0;
344 }
345 }
346}
347
348static bool parseVideoMode(const char* value) {
349 size_t mode[3] = {};
350 for (size_t i = 0; i < 3; ++i) {
351 if (*value < '0' || *value > '9') {
352 return false;
353 }
354 while (*value >= '0' && *value <= '9') {
355 mode[i] = mode[i] * 10 + (*value++ - '0');
356 if (mode[i] > 65535) {
357 return false;
358 }
359 }
360 if (!mode[i] || *value != (i == 2 ? '\0' : 'x')) {
361 return false;
362 }
363 if (i != 2) {
364 ++value;
365 }
366 }
367 if (mode[2] > 64) {
368 return false;
369 }
370
371 g_DesiredWidth = mode[0];
372 g_DesiredHeight = mode[1];
373 g_DesiredBpp = mode[2];
374 return true;
375}
376
377static bool parseColour(const char* value, uint32_t& colour) {
378 if (StringLength(value) != 6) {
379 return false;
380 }
381
382 uint32_t result = 0;
383 for (size_t i = 0; i < 6; ++i) {
384 char c = value[i];
385 uint32_t digit;
386 if (c >= '0' && c <= '9') {
387 digit = c - '0';
388 } else if (c >= 'a' && c <= 'f') {
389 digit = c - 'a' + 10;
390 } else if (c >= 'A' && c <= 'F') {
391 digit = c - 'A' + 10;
392 } else {
393 return false;
394 }
395 result = (result << 4) | digit;
396 }
397 colour = result;
398 return true;
399}
400
401static bool handleNoSplash() {
402 g_NoGraphics = true;
403
404 const String title("Pedigree is Loading...\n");
405
406 // Prepare to render by making some space between the current BootIO output
407 // and the progress bar we're about to add.
409 s = "\n";
410 for (size_t i = 0; i < 2; ++i) {
411 bootIO.write(s, BootIO::Black, BootIO::Black);
412 }
413
414 // Prepare to center text.
415 s = " ";
416 for (size_t i = 0; i < (80 / 2) - (title.length() / 2); ++i) {
417 bootIO.write(s, BootIO::Black, BootIO::Black);
418 }
419
420 // Render the system title.
421 s = title;
422 bootIO.write(s, BootIO::White, BootIO::Black);
423
424 g_BootProgressUpdate = &progress;
425
426 return true;
427}
428
429static bool handleSplash() {
430 g_NoGraphics = false;
431
432 // No text mode for us - we're the splash screen!
433 g_GraphicsParams.wantTextMode = false;
434
435 // Grab the current graphics provider for the system, use it to display the
436 // splash screen to the user.
438 ServiceFeatures* pFeatures = ServiceManager::instance().enumerateOperations(String("graphics"));
439 Service* pService = ServiceManager::instance().getService(String("graphics"));
440 bool bSuccess = false;
441 if (pFeatures && pFeatures->provides(ServiceFeatures::probe))
442 if (pService)
443 bSuccess = pService->serve(ServiceFeatures::probe, reinterpret_cast<void*>(&g_GraphicsParams),
444 sizeof(g_GraphicsParams));
445
446 if (!(bSuccess && g_GraphicsParams.providerFound)) {
447 NOTICE(
448 "splash: this system does not support graphics, using fallback "
449 "log callback");
450 return handleNoSplash();
451 }
452
453 Display* pDisplay = g_GraphicsParams.providerResult.pDisplay;
454
455 size_t nDesiredWidth = g_DesiredWidth;
456 size_t nDesiredHeight = g_DesiredHeight;
457 size_t nDesiredBpp = g_DesiredBpp;
458
459 // Set up the mode we want
460 if (!(nDesiredWidth && nDesiredHeight && nDesiredBpp) ||
461 !pDisplay->setScreenMode(nDesiredWidth, nDesiredHeight, nDesiredBpp)) {
462 // A firmware framebuffer has already selected its fixed mode. Keep using
463 // it when the configured mode is not available.
464 Display::ScreenMode currentMode;
465 if (pDisplay->getCurrentScreenMode(currentMode) && !currentMode.textMode &&
466 pDisplay->setScreenMode(currentMode)) {
467 nDesiredWidth = currentMode.width;
468 nDesiredHeight = currentMode.height;
469 nDesiredBpp = currentMode.pf.nBpp;
470 } else {
471 bool bModeFound = true;
472
473 // 24-bit mode fallbacks
474 NOTICE("splash: Falling back to 1024x768x24");
475 if (!pDisplay->setScreenMode(1024, 768, 24)) {
476 // Attempt to fall back to 800x600
477 NOTICE("splash: Falling back to 800x600x24");
478 if (!pDisplay->setScreenMode(800, 600, 24)) {
479 // Finally try and fall back to 640x480
480 NOTICE("splash: Falling back to 640x480x24");
481 if (!pDisplay->setScreenMode(640, 480, 24)) {
482 bModeFound = false;
483 }
484 }
485 }
486
487 if (!bModeFound) {
488 // 16-bit mode fallbacks
489 NOTICE("splash: Falling back to 1024x768x16");
490 if (!pDisplay->setScreenMode(1024, 768, 16)) {
491 // Attempt to fall back to 800x600
492 NOTICE("splash: Falling back to 800x600x16");
493 if (!pDisplay->setScreenMode(800, 600, 16)) {
494 // Finally try and fall back to 640x480
495 NOTICE("splash: Falling back to 640x480x16");
496 if (!pDisplay->setScreenMode(640, 480, 16)) {
497 ERROR(
498 "splash: Couldn't find a suitable display mode "
499 "for this system (tried: 1024x768, 800x600, "
500 "640x480).");
501 g_NoGraphics = true;
502 }
503 }
504 }
505 }
506 }
507 }
508
509 if (g_NoGraphics) {
510 NOTICE(
511 "splash: this system does not support graphics, using fallback "
512 "log callback");
513 return handleNoSplash();
514 }
515
516 Framebuffer* pParentFramebuffer = g_GraphicsParams.providerResult.pFramebuffer;
517
518 g_Width = pParentFramebuffer->getWidth();
519 g_Height = pParentFramebuffer->getHeight();
520
521 g_pFramebuffer = Graphics::createFramebuffer(pParentFramebuffer, 0, 0, g_Width, g_Height);
522 g_ColorFormat = g_pFramebuffer->getFormat();
523
524 g_pFramebuffer->rect(0, 0, g_Width, g_Height, g_BackgroundColour, g_ColorFormat);
525
526 if (!g_LogMode) {
527 // Create the logo buffer
528 uint8_t* data = header_data;
529 g_pBuffer = new uint8_t[width * height * 3]; // 24-bit, hardcoded...
530 for (size_t i = 0; i < (width * height); i++)
531 HEADER_PIXEL(data, &g_pBuffer[i * 3]); // 24-bit, hardcoded
532
533 size_t origx = (g_Width - width) / 2;
534 size_t origy = (g_Height - height) / 3;
535
536 g_pFramebuffer->draw(g_pBuffer, 0, 0, origx, origy, width, height, Graphics::Bits24_Bgr);
537
538 delete[] g_pBuffer;
539 }
540
541 // Create the font buffer
542 g_pBuffer = new uint8_t[(FONT_WIDTH * FONT_HEIGHT * 3) * 256]; // 24-bit
543 ByteSet(g_pBuffer, 0, (FONT_WIDTH * FONT_HEIGHT * 3) * 256);
544 size_t offset = 0;
545
546 // For each character
547 for (size_t character = 0; character < 255; character++) {
548 // For each character row
549 for (size_t row = 0; row < FONT_HEIGHT; row++) {
550 // For each character row bit
551 for (size_t col = 0; col < FONT_WIDTH; col++) {
552 // Is this bit set?
553 size_t fontRow = (character * FONT_HEIGHT) + row;
554 if (font_data[fontRow] & (1 << (FONT_WIDTH - 1 - col))) {
555 // x: col
556 // y: fontRow
557 size_t bytesPerPixel = 3;
558 size_t bytesPerLine = FONT_WIDTH * bytesPerPixel;
559 size_t pixelOffset = (fontRow * bytesPerLine) + (col * bytesPerPixel);
560 size_t bufferOffset = pixelOffset;
561
562 uint32_t* p = adjust_pointer<uint8_t, uint32_t>(g_pBuffer, bufferOffset);
563 *p = g_ForegroundColour;
564 }
565 }
566 }
567 }
568
569 g_pFont =
570 g_pFramebuffer->createBuffer(g_pBuffer, Graphics::Bits24_Rgb, FONT_WIDTH, FONT_HEIGHT * 256);
571
572 if (!g_LogMode) {
573 g_ProgressX = (g_Width / 2) - 200;
574 g_ProgressW = 400;
575 g_ProgressY = (g_Height / 3) * 2;
576 g_ProgressH = 15;
577
578 g_LogBoxX = 0;
579 g_LogBoxY = (g_Height / 4) * 3;
580 g_LogW = g_Width;
581 g_LogH = g_Height - g_LogBoxY;
582 } else {
583 g_LogBoxX = 0;
584 g_LogBoxY = 0;
585 g_LogW = g_Width;
586 g_LogH = g_Height;
587 }
588 g_LogX = g_LogY = 0;
589
590 if (!g_LogMode) {
591 {
592 LockGuard<Mutex> guard(g_PrintLock);
593 centerStringAt("Please wait, Pedigree is loading...", g_Width / 2,
594 g_ProgressY - (FONT_HEIGHT * 3));
595
596 EMIT_IF(DEBUGGER) {
597 // Draw a border around the log area
598 centerStringAt("< Kernel Log >", g_LogW / 2,
599 g_LogBoxY - 2 - (FONT_HEIGHT / 2) - FONT_HEIGHT);
600 centerStringAt(
601 "(you can push ESCAPE to view the kernel log, and again to make the "
602 "log fill the screen)",
603 g_LogW / 2, g_LogBoxY - 2 - (FONT_HEIGHT / 2));
604 }
605 }
606
607 // Draw empty progress bar. Easiest way to draw a nonfilled rect? Draw two
608 // filled rects.
609 g_pFramebuffer->rect(g_ProgressX - 2, g_ProgressY - 2, g_ProgressW + 4, g_ProgressH + 4,
610 g_ProgressBorderColour, g_ColorFormat);
611 g_pFramebuffer->rect(g_ProgressX - 1, g_ProgressY - 1, g_ProgressW + 2, g_ProgressH + 2,
612 g_BackgroundColour, g_ColorFormat);
613 }
614
615 g_pFramebuffer->redraw(0, 0, g_Width, g_Height, true);
616
617 // Replaying the complete kernel backlog through the software renderer can
618 // delay the handoff indefinitely on slow machines. Log mode shows the
619 // messages emitted after the display is ready instead.
620 Log::instance().installCallback(&g_StreamLogger, true);
621
622 g_BootProgressUpdate = &progress;
623
624 EMIT_IF(DEBUGGER) {
626 }
627
628 return true;
629}
630
631static bool init() {
632 g_NoGraphics = false;
633 g_LogMode = true;
634 char* cmdline = g_pBootstrapInfo->getCommandLine();
635 if (cmdline) {
636 Vector<String> cmds = String(cmdline).tokenise(' ');
637 for (auto it = cmds.begin(); it != cmds.end(); it++) {
638 auto cmd = *it;
639 bool valid = true;
640 if (cmd == String("nosplash")) {
641 g_NoGraphics = true;
642 break;
643 } else if (cmd == String("splash=image")) {
644 g_LogMode = false;
645 } else if (cmd == String("splash=log") || cmd == String("splash=logs")) {
646 g_LogMode = true;
647 } else if (!StringCompareN(cmd.cstr(), "video=", 6)) {
648 valid = parseVideoMode(cmd.cstr() + 6);
649 } else if (!StringCompareN(cmd.cstr(), "splash-background=", 18)) {
650 valid = parseColour(cmd.cstr() + 18, g_BackgroundColour);
651 } else if (!StringCompareN(cmd.cstr(), "splash-foreground=", 18)) {
652 valid = parseColour(cmd.cstr() + 18, g_ForegroundColour);
653 } else if (!StringCompareN(cmd.cstr(), "splash-border=", 14)) {
654 valid = parseColour(cmd.cstr() + 14, g_ProgressBorderColour);
655 } else if (!StringCompareN(cmd.cstr(), "splash-fill=", 12)) {
656 valid = parseColour(cmd.cstr() + 12, g_ProgressColour);
657 }
658 if (!valid) {
659 WARNING("splash: ignoring invalid boot option " << cmd);
660 }
661 }
662 }
663
664 if (g_NoGraphics) {
665 return handleNoSplash();
666 } else {
667 return handleSplash();
668 }
669}
670
671static void destroy() {
672 Log::instance().removeCallback(&g_StreamLogger);
673
674 EMIT_IF(DEBUGGER) {
675 if (!g_NoGraphics) {
677 }
678 }
679
680 LockGuard<Mutex> guard(g_PrintLock);
681
682 g_BootProgressUpdate = 0;
683}
684
685MODULE_INFO("splash", &init, &destroy);
686// If no graphics drivers loaded, we can handle that still. But we still need
687// to run after the gfx-deps metamodule.
688MODULE_OPTIONAL_DEPENDS("gfx-deps");
Colour
Definition BootIO.h:41
EXPORTED_PUBLIC void write(T &str, Colour foreColour, Colour backColour)
virtual bool getCurrentScreenMode(ScreenMode &sm)
Definition Display.cc:82
virtual bool setScreenMode(ScreenMode sm)
Definition Display.cc:90
virtual Graphics::Buffer * createBuffer(const void *srcData, Graphics::PixelFormat srcFormat, size_t width, size_t height, uint32_t *pPalette=0)
virtual void blit(Graphics::Buffer *pBuffer, size_t srcx, size_t srcy, size_t destx, size_t desty, size_t width, size_t height, bool bLowestCall=true)
virtual void copy(size_t srcx, size_t srcy, size_t destx, size_t desty, size_t w, size_t h, bool bLowestCall=true)
virtual void draw(void *pBuffer, size_t srcx, size_t srcy, size_t destx, size_t desty, size_t width, size_t height, Graphics::PixelFormat format=Graphics::Bits32_Argb, bool bLowestCall=true)
virtual void destroyBuffer(Graphics::Buffer *pBuffer)
virtual void rect(size_t x, size_t y, size_t width, size_t height, uint32_t colour, Graphics::PixelFormat format=Graphics::Bits32_Argb, bool bLowestCall=true)
void redraw(size_t x=~0UL, size_t y=~0UL, size_t w=~0UL, size_t h=~0UL, bool bChild=false)
static const int Key
static InputManager & instance()
Singleton design.
void installCallback(CallbackType filter, callback_t callback, void *meta=0)
Installs a callback.
void removeCallback(callback_t callback, void *meta=0)
Removes a callback.
EXPORTED_PUBLIC bool removeCallback(LogCallback *pCallback)
Definition Log.cc:228
static EXPORTED_PUBLIC Log & instance()
Definition Log.cc:117
EXPORTED_PUBLIC bool installCallback(LogCallback *pCallback, bool bSkipBacklog=false)
Definition Log.cc:145
Definition Mutex.h:56
void release(size_t n=1)
Definition Semaphore.cc:549
bool tryAcquire(size_t n=1)
Definition Semaphore.cc:484
virtual bool provides(Type service)
Service * getService(const String &serviceName)
ServiceFeatures * enumerateOperations(const String &serviceName)
virtual bool serve(ServiceFeatures::Type type, void *pData, size_t dataLen)=0
void callback(const LogCord &cord, bool=true)
A vector / dynamic array.
Definition Vector.h:33
uint8_t nBpp
Bits per pixel (total).
Definition Display.h:62
Definition cmd.h:30