Chameleon

Chameleon Svn Source Tree

Root/branches/cparm/i386/modules/GUI/gui.c

1/*
2 * gui.c
3 *
4 *
5 * Created by Jasmin Fazlic on 18.12.08.
6 * Copyright 2008/09 Jasmin Fazlic All rights reserved.
7 * Copyright 2008/09 iNDi All rights reserved.
8 *
9 */
10
11/*
12 * cparm : cleaned
13 */
14
15/*
16 * cparm : add volume version detection
17 */
18#include "platform.h"
19#include "gui.h"
20#include "GUI_appleboot.h"
21#include "vers.h"
22#include "modules.h"
23#include "sl.h"
24
25#ifndef DEBUG_GUI
26#define DEBUG_GUI 0
27#endif
28
29#if DEBUG_GUI==2
30#define DBG(x...)printf(x);sleep(2)
31#elif DEBUG_GUI==1
32#define DBG(x...)printf(x)
33#else
34#define DBG(x...)
35#endif
36
37enum {
38kBackspaceKey= 0x08,
39kTabKey= 0x09,
40kReturnKey= 0x0d,
41kEscapeKey= 0x1b,
42kUpArrowkey= 0x4800,
43kDownArrowkey= 0x5000,
44kASCIIKeyMask= 0x7f,
45kF5Key= 0x3f00,
46kF10Key= 0x4400
47};
48
49static config_file_t themeConfig; // theme.plist
50
51themeList_t* themeList = NULL;
52
53static void (*showHelp)(void) = NULL;
54static char *(*getMemoryInfoString)(void) = NULL;
55
56
57gui_t gui;// gui structure
58font_t font_small;
59font_t font_console;
60
61
62#define IMG_REQUIRED -1
63#define THEME_NAME_DEFAULT"Default"
64const char* theme_name = THEME_NAME_DEFAULT;
65
66char dirsrc[22];
67
68#ifdef EMBED_THEME
69#include "art.h"
70#endif
71
72struct putc_info {
73 char * str;
74 char * last_str;
75};
76
77static int loadThemeImage(char *src, const char *image, int alt_image);
78static void loadBootGraphics(char *src);
79static void drawInfoMenuItems();
80static void drawProgressBar(pixmap_t *blendInto, uint16_t width, position_t p, uint8_t progress);
81static void animateProgressBar();
82static void makeRoundedCorners(pixmap_t *p);
83static void colorFont(font_t *font, uint32_t color);
84static int initFont(font_t *font, image_t *data);
85static void drawStrCenteredAt(char *text, font_t *font, pixmap_t *blendInto, position_t p);
86static position_t drawChar(unsigned char ch, font_t *font, pixmap_t *blendInto, position_t p);
87static void drawStr(char *ch, font_t *font, pixmap_t *blendInto, position_t p);
88#if DEBUG_GUI
89static int dprintf( window_t * window, const char * fmt, ...);
90#endif
91static void sputc(int c, struct putc_info * pi);
92
93static inline
94void vramwrite (void *data, int width);
95
96static void drawDeviceIcon(BVRef device, pixmap_t *buffer, position_t p, bool isSelected);
97static int startGUI(void);
98static void free_theme_list();
99static void add_theme(const char* theme, uint8_t nb);
100static int randomTheme(char *dirspec, const char **theme);
101static void loadThemeValues(config_file_t *theme);
102static void setupDeviceList(config_file_t *theme);
103static void fillPixmapWithColor(pixmap_t *pm, uint32_t color);
104static int freeWindowBuffer( window_t *window );
105static int createWindowBuffer( window_t *window );
106static int createBackBuffer( window_t *window );
107static int loadGraphics(char *src);
108#ifdef EMBED_THEME
109static int getEmbeddedImageIndexByName(const char *name);
110#endif
111static int getImageIndexByName(const char *name);
112
113static int destroyFont(font_t *font);
114static int unloadGraphics(void);
115static int freeBackBuffer( window_t *window );
116static bool is_image_loaded(int i);
117static bool GUI_getDimensionForKey( const char *key, unsigned int *value, config_file_t *config, unsigned int dimension_max, unsigned int object_size );
118static bool GUI_getColorForKey( const char *key, unsigned int *value, config_file_t *config );
119
120#define LOADPNG(src, img, alt_img) if (loadThemeImage(src, #img, alt_img) != 0) { return 1; }
121
122#ifndef MIN
123#define MIN(x, y) ((x) < (y) ? (x) : (y))
124#endif
125
126#ifndef MAX
127#define MAX(x, y) ((x) > (y) ? (x) : (y))
128#endif
129
130#define VIDEO(x) (((boot_args_common*)getBootArgs())->Video.v_ ## x)
131
132#define vram VIDEO(baseAddr)
133
134#define TAB_PIXELS_WIDTH (font->chars[0]->width * 4) // tab = 4 spaces
135
136int lasttime = 0; // we need this for animating maybe
137
138/*
139 * ATTENTION: the enum and the following array images[] MUST match !!!
140 */
141enum {
142 iBackground = 0,
143 iLogo,
144
145 iDeviceGeneric,
146 iDeviceGeneric_o,
147 iDeviceHFS,
148 iDeviceHFS_o,
149 iDeviceHFS_ML,
150 iDeviceHFS_ML_o,
151iDeviceHFS_Lion,
152 iDeviceHFS_Lion_o,
153iDeviceHFS_SL,
154 iDeviceHFS_SL_o,
155iDeviceHFS_Leo,
156 iDeviceHFS_Leo_o,
157iDeviceHFS_Tiger,
158 iDeviceHFS_Tiger_o,
159 iDeviceHFSRAID,
160 iDeviceHFSRAID_o,
161 iDeviceHFSRAID_ML,
162 iDeviceHFSRAID_ML_o,
163iDeviceHFSRAID_Lion,
164 iDeviceHFSRAID_Lion_o,
165iDeviceHFSRAID_SL,
166 iDeviceHFSRAID_SL_o,
167iDeviceHFSRAID_Leo,
168 iDeviceHFSRAID_Leo_o,
169iDeviceHFSRAID_Tiger,
170 iDeviceHFSRAID_Tiger_o,
171 iDeviceEXT3,
172 iDeviceEXT3_o,
173iDeviceFreeBSD,
174 iDeviceFreeBSD_o,
175 iDeviceOpenBSD,
176 iDeviceOpenBSD_o,
177iDeviceBEFS, /* Haiku detection and Icon credits to scorpius */
178iDeviceBEFS_o, /* Haiku detection and Icon credits to scorpius */
179 iDeviceFAT,
180 iDeviceFAT_o,
181 iDeviceFAT16,
182 iDeviceFAT16_o,
183 iDeviceFAT32,
184 iDeviceFAT32_o,
185 iDeviceNTFS,
186 iDeviceNTFS_o,
187 iDeviceCDROM,
188 iDeviceCDROM_o,
189
190 iSelection,
191 iDeviceScrollPrev,
192 iDeviceScrollNext,
193
194 iMenuBoot,
195 iMenuVerbose,
196 iMenuIgnoreCaches,
197 iMenuSingleUser,
198 iMenuMemoryInfo,
199 iMenuVideoInfo,
200 iMenuHelp,
201 iMenuVerboseDisabled,
202 iMenuIgnoreCachesDisabled,
203 iMenuSingleUserDisabled,
204 iMenuSelection,
205
206 iProgressBar,
207 iProgressBarBackground,
208
209 iTextScrollPrev,
210 iTextScrollNext,
211
212 iFontConsole,
213 iFontSmall,
214};
215
216image_t images[] = {
217 {.name = "background", .image = NULL},
218 {.name = "logo", .image = NULL},
219
220 {.name = "device_generic", .image = NULL},
221 {.name = "device_generic_o", .image = NULL},
222
223{.name = "device_hfsplus", .image = NULL},
224 {.name = "device_hfsplus_o", .image = NULL},
225{.name = "device_hfsplus_ml", .image = NULL},
226 {.name = "device_hfsplus_ml_o", .image = NULL},
227{.name = "device_hfsplus_lion", .image = NULL},
228 {.name = "device_hfsplus_lion_o", .image = NULL},
229{.name = "device_hfsplus_sl", .image = NULL},
230 {.name = "device_hfsplus_sl_o", .image = NULL},
231{.name = "device_hfsplus_leo", .image = NULL},
232 {.name = "device_hfsplus_leo_o", .image = NULL},
233{.name = "device_hfsplus_tiger", .image = NULL},
234 {.name = "device_hfsplus_tiger_o", .image = NULL},
235
236 {.name = "device_hfsraid", .image = NULL},
237 {.name = "device_hfsraid_o", .image = NULL},
238 {.name = "device_hfsraid_ml", .image = NULL},
239 {.name = "device_hfsraid_ml_o", .image = NULL},
240{.name = "device_hfsraid_lion", .image = NULL},
241 {.name = "device_hfsraid_lion_o", .image = NULL},
242{.name = "device_hfsraid_sl", .image = NULL},
243 {.name = "device_hfsraid_sl_o", .image = NULL},
244{.name = "device_hfsraid_leo", .image = NULL},
245 {.name = "device_hfsraid_leo_o", .image = NULL},
246{.name = "device_hfsraid_tiger", .image = NULL},
247 {.name = "device_hfsraid_tiger_o", .image = NULL},
248
249 {.name = "device_ext3", .image = NULL},
250 {.name = "device_ext3_o", .image = NULL},
251{.name = "device_freebsd", .image = NULL},
252 {.name = "device_freebsd_o", .image = NULL},
253 {.name = "device_openbsd", .image = NULL},
254 {.name = "device_openbsd_o", .image = NULL},
255{.name = "device_befs", .image = NULL}, /* Haiku detection and Icon credits to scorpius */
256{.name = "device_befs_o", .image = NULL}, /* Haiku detection and Icon credits to scorpius */
257 {.name = "device_fat", .image = NULL},
258 {.name = "device_fat_o", .image = NULL},
259 {.name = "device_fat16", .image = NULL},
260 {.name = "device_fat16_o", .image = NULL},
261 {.name = "device_fat32", .image = NULL},
262 {.name = "device_fat32_o", .image = NULL},
263 {.name = "device_ntfs", .image = NULL},
264 {.name = "device_ntfs_o", .image = NULL},
265 {.name = "device_cdrom", .image = NULL},
266 {.name = "device_cdrom_o", .image = NULL},
267
268 {.name = "device_selection", .image = NULL},
269 {.name = "device_scroll_prev", .image = NULL},
270 {.name = "device_scroll_next", .image = NULL},
271
272 {.name = "menu_boot", .image = NULL},
273 {.name = "menu_verbose", .image = NULL},
274 {.name = "menu_ignore_caches", .image = NULL},
275 {.name = "menu_single_user", .image = NULL},
276 {.name = "menu_memory_info", .image = NULL},
277 {.name = "menu_video_info", .image = NULL},
278 {.name = "menu_help", .image = NULL},
279 {.name = "menu_verbose_disabled", .image = NULL},
280 {.name = "menu_ignore_caches_disabled", .image = NULL},
281 {.name = "menu_single_user_disabled", .image = NULL},
282 {.name = "menu_selection", .image = NULL},
283
284 {.name = "progress_bar", .image = NULL},
285 {.name = "progress_bar_background", .image = NULL},
286
287 {.name = "text_scroll_prev", .image = NULL},
288 {.name = "text_scroll_next", .image = NULL},
289
290 {.name = "font_console", .image = NULL},
291 {.name = "font_small", .image = NULL},
292};
293
294//int imageCnt = 0;
295
296char prompt[BOOT_STRING_LEN];
297
298int prompt_pos=0;
299
300char prompt_text[] = "boot: ";
301
302menuitem_t infoMenuItems[] =
303{
304{ .text = "Boot" },
305{ .text = "Boot Verbose" },
306{ .text = "Boot Ignore Caches" },
307{ .text = "Boot Single User" },
308{ .text = "Memory Info" },
309{ .text = "Video Info" },
310{ .text = "Help" }
311};
312
313int infoMenuSelection = 0;
314int infoMenuItemsCount = sizeof(infoMenuItems)/sizeof(infoMenuItems[0]);
315
316bool infoMenuNativeBoot = false;
317
318unsigned long screen_params[4] = {DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT, 32, 0};// here we store the used screen resolution
319
320static void moveCursor( int col, int row )
321{
322 setCursorPosition( col, row, 0 );
323}
324
325/*
326 *
327 */
328
329static bool GUI_getDimensionForKey( const char *key, unsigned int *value, config_file_t *config, unsigned int dimension_max, unsigned int object_size )
330{
331const char *val;
332
333 int size = 0;
334int sum = 0;
335
336bool negative = false;
337bool percentage = false;
338
339 config = resolveConfig(config);
340
341 if (getValueForKey(key, &val, &size, config))
342{
343if ( size )
344{
345if (*val == '-')
346{
347negative = true;
348val++;
349size--;
350}
351
352if (val[size-1] == '%')
353{
354percentage = true;
355size--;
356}
357
358// convert string to integer
359for (sum = 0; size > 0; size--)
360{
361if (*val < '0' || *val > '9')
362return false;
363
364sum = (sum * 10) + (*val++ - '0');
365}
366
367if (percentage)
368sum = ( dimension_max * sum ) / 100;
369
370// calculate offset from opposite origin
371if (negative)
372sum = ( ( dimension_max - object_size ) - sum );
373
374} else {
375
376// null value calculate center
377sum = ( dimension_max - object_size ) / 2;
378
379}
380
381*value = (uint16_t) sum;
382return true;
383}
384
385// key not found
386 return false;
387}
388
389static bool GUI_getColorForKey( const char *key, unsigned int *value, config_file_t *config )
390{
391 const char *val;
392 int size;
393
394 config = resolveConfig(config);
395
396 if (getValueForKey(key, &val, &size, config))
397{
398if (*val == '#')
399{
400 val++;
401*value = strtol(val, NULL, 16);
402return true;
403 }
404 }
405 return false;
406}
407//==========================================================================
408
409/* Flush keyboard buffer; returns TRUE if any of the flushed
410 * characters was F8.
411 */
412
413static bool flushKeyboardBuffer(void)
414{
415 bool status = false;
416
417 while ( readKeyboardStatus() ) {
418 if (bgetc() == 0x4200) status = true;
419 }
420 return status;
421}
422
423static int getImageIndexByName(const char *name)
424{
425 int i;
426for (i = 0; (unsigned)i < sizeof(images) / sizeof(images[0]); i++)
427{
428 if (strcmp(name, images[i].name) == 0)
429 return i; // found the name
430}
431return -1;
432}
433
434#ifdef EMBED_THEME
435static int getEmbeddedImageIndexByName(const char *name)
436{
437int upperLimit = sizeof(embeddedImages) / sizeof(embeddedImages[0]) - 1;
438int lowerLimit = 0;
439int compareIndex = (upperLimit - lowerLimit) >> 1; // Midpoint
440int result;
441
442// NOTE: This algorithm assumes that the embeddedImages is sorted.
443// This is currently done using the make file. If the array is every
444// manualy generated, this *will* fail to work properly.
445while((result = strcmp(name, embeddedImages[compareIndex].name)) != 0)
446{
447if(result > 0)// We need to search a HIGHER index
448{
449if(compareIndex != lowerLimit)
450{
451lowerLimit = compareIndex;
452}
453else
454{
455return -1;
456}
457compareIndex = (upperLimit + lowerLimit + 1) >> 1;// Midpoint, round up
458}
459else // We Need to search a LOWER index
460{
461if(compareIndex != upperLimit)
462{
463upperLimit = compareIndex;
464}
465else
466{
467return -1;
468}
469compareIndex = (upperLimit + lowerLimit) >> 1;// Midpoint, round down
470}
471}
472return compareIndex;
473}
474#endif
475
476static int loadThemeImage(char* src, const char *image, int alt_image)
477{
478chardirspec[256];
479int i;
480#ifdef EMBED_THEME
481int e;
482#endif
483uint16_twidth;
484uint16_theight;
485uint8_t*imagedata;
486if ((unsigned)(strlen(image) + strlen(theme_name) + strlen(src) + (6+1) ) > sizeof(dirspec)) {
487
488DBG("Path of %s/%s/%s.png to long\n", src, theme_name, image);
489
490return 1;
491}
492
493 if ((i = getImageIndexByName(image)) >= 0)
494 {
495if (images[i].image == NULL) {
496images[i].image = malloc(sizeof(pixmap_t));
497if (images[i].image == NULL) {
498
499DBG("Unable to allocate memory for %s.png\n", image);
500
501return 1;
502}
503}
504 sprintf(dirspec, "%s/%s/%s.png", src, theme_name, image);
505
506 width = 0;
507 height = 0;
508 imagedata = NULL;
509 if ( strlen(theme_name) > 0 && (loadPngImage(dirspec, &width, &height, &imagedata)) == 0)
510 {
511 images[i].image->width = width;
512 images[i].image->height = height;
513 images[i].image->pixels = (pixel_t *)imagedata;
514 flipRB(images[i].image);
515
516DBG("[ %s ] succesfully loaded and registred !!\n", dirspec);
517
518 return 0;
519 }
520#ifdef EMBED_THEME
521 else if ((e = getEmbeddedImageIndexByName(image)) >= 0)
522 {
523 unsigned char *embed_data;
524 unsigned int embed_size;
525 embed_data = embeddedImages[e].pngdata;
526 embed_size = *embeddedImages[e].length;
527
528 if (loadEmbeddedPngImage(embed_data, embed_size, &width, &height, &imagedata) == 0)
529 {
530 images[i].image->width = width;
531 images[i].image->height = height;
532 images[i].image->pixels = (pixel_t *)imagedata;
533 flipRB(images[i].image);
534 return 0;
535 }
536
537 return 0;
538 }
539#endif
540 else if (alt_image != IMG_REQUIRED)
541 {
542if (images[alt_image].image->pixels != NULL) {
543
544// Using the passed alternate image for non-mandatory images.
545// We don't clone the already existing pixmap, but using its properties instead!
546images[i].image->width = images[alt_image].image->width;
547images[i].image->height = images[alt_image].image->height;
548images[i].image->pixels = images[alt_image].image->pixels;
549
550} else {
551
552DBG("Unable to load %s, this image not vital anyway, reseting and returning success !!\n", dirspec);
553
554free(images[i].image);
555images[i].image = NULL;
556}
557
558 return 0;
559 }
560 else
561 {
562#if DEBUG_GUI
563 printf("ERROR: GUI: could not open '%s/%s.png'!\n", theme_name, image);
564sleep(2);
565#else
566#ifndef CONFIG_EMBED_THEME
567 printf("ERROR: GUI: could not open '%s/%s.png'!\n", theme_name, image);
568sleep(2);
569#endif
570#endif
571free(images[i].image);
572images[i].image = NULL;
573return 1;
574
575 }
576
577 }
578
579#if DEBUG_GUI
580printf("[ %s/%s/%s.png ] not used in this version, skipped !!\n",src, theme_name, image);
581sleep(2);
582#endif
583return 1;
584}
585
586static int loadGraphics(char *src)
587{
588DBG("Loading image into memory....\n",theme_name);
589
590LOADPNG(src, background, IMG_REQUIRED);
591
592LOADPNG(src, logo, IMG_REQUIRED);
593
594LOADPNG(src, device_generic, IMG_REQUIRED);
595LOADPNG(src, device_generic_o, iDeviceGeneric);
596
597LOADPNG(src, device_hfsplus, iDeviceGeneric);
598LOADPNG(src, device_hfsplus_o, iDeviceHFS);
599 LOADPNG(src, device_hfsplus_ml, iDeviceHFS_ML);
600 LOADPNG(src, device_hfsplus_ml_o, iDeviceHFS_ML_o);
601LOADPNG(src, device_hfsplus_lion, iDeviceHFS_Lion);
602LOADPNG(src, device_hfsplus_lion_o, iDeviceHFS_Lion_o);
603LOADPNG(src, device_hfsplus_sl, iDeviceHFS_SL);
604LOADPNG(src, device_hfsplus_sl_o, iDeviceHFS_SL_o);
605LOADPNG(src, device_hfsplus_leo, iDeviceHFS_Leo);
606LOADPNG(src, device_hfsplus_leo_o, iDeviceHFS_Leo_o);
607LOADPNG(src, device_hfsplus_tiger, iDeviceHFS_Tiger);
608LOADPNG(src, device_hfsplus_tiger_o, iDeviceHFS_Tiger_o);
609
610LOADPNG(src, device_hfsraid, iDeviceGeneric);
611LOADPNG(src, device_hfsraid_o, iDeviceHFSRAID);
612 LOADPNG(src, device_hfsraid_ml, iDeviceHFSRAID_ML);
613 LOADPNG(src, device_hfsraid_ml_o, iDeviceHFSRAID_ML_o);
614LOADPNG(src, device_hfsraid_lion, iDeviceHFSRAID_Lion);
615LOADPNG(src, device_hfsraid_lion_o, iDeviceHFSRAID_Lion_o);
616LOADPNG(src, device_hfsraid_sl, iDeviceHFSRAID_SL);
617LOADPNG(src, device_hfsraid_sl_o, iDeviceHFSRAID_SL_o);
618LOADPNG(src, device_hfsraid_leo, iDeviceHFSRAID_Leo);
619LOADPNG(src, device_hfsraid_leo_o, iDeviceHFSRAID_Leo_o);
620LOADPNG(src, device_hfsraid_tiger, iDeviceHFSRAID_Tiger);
621LOADPNG(src, device_hfsraid_tiger_o, iDeviceHFSRAID_Tiger_o);
622
623LOADPNG(src, device_ext3, iDeviceGeneric);
624LOADPNG(src, device_ext3_o, iDeviceEXT3);
625LOADPNG(src, device_freebsd, iDeviceGeneric);
626LOADPNG(src, device_freebsd_o, iDeviceFreeBSD);
627LOADPNG(src, device_openbsd, iDeviceGeneric);
628LOADPNG(src, device_openbsd_o, iDeviceOpenBSD);
629LOADPNG(src, device_befs, iDeviceGeneric); /* Haiku detection and Icon credits to scorpius */
630LOADPNG(src, device_befs_o, iDeviceBEFS); /* Haiku detection and Icon credits to scorpius */
631LOADPNG(src, device_fat, iDeviceGeneric);
632LOADPNG(src, device_fat_o, iDeviceFAT);
633LOADPNG(src, device_fat16, iDeviceFAT);
634LOADPNG(src, device_fat16_o, iDeviceFAT_o);
635LOADPNG(src, device_fat32, iDeviceFAT);
636LOADPNG(src, device_fat32_o, iDeviceFAT_o);
637LOADPNG(src, device_ntfs, iDeviceGeneric);
638LOADPNG(src, device_ntfs_o, iDeviceNTFS);
639LOADPNG(src, device_cdrom, iDeviceGeneric);
640LOADPNG(src, device_cdrom_o, iDeviceCDROM);
641
642LOADPNG(src, device_selection, IMG_REQUIRED);
643LOADPNG(src, device_scroll_prev, IMG_REQUIRED);
644LOADPNG(src, device_scroll_next, IMG_REQUIRED);
645
646LOADPNG(src, menu_boot, IMG_REQUIRED);
647LOADPNG(src, menu_verbose, IMG_REQUIRED);
648LOADPNG(src, menu_ignore_caches, IMG_REQUIRED);
649LOADPNG(src, menu_single_user, IMG_REQUIRED);
650LOADPNG(src, menu_memory_info, IMG_REQUIRED);
651LOADPNG(src, menu_video_info, IMG_REQUIRED);
652LOADPNG(src, menu_help, IMG_REQUIRED);
653LOADPNG(src, menu_verbose_disabled, IMG_REQUIRED);
654LOADPNG(src, menu_ignore_caches_disabled, IMG_REQUIRED);
655LOADPNG(src, menu_single_user_disabled, IMG_REQUIRED);
656LOADPNG(src, menu_selection, IMG_REQUIRED);
657
658LOADPNG(src, progress_bar, IMG_REQUIRED);
659LOADPNG(src, progress_bar_background, IMG_REQUIRED);
660
661LOADPNG(src, text_scroll_prev, IMG_REQUIRED);
662LOADPNG(src, text_scroll_next, IMG_REQUIRED);
663
664LOADPNG(src, font_console, IMG_REQUIRED);
665LOADPNG(src, font_small, IMG_REQUIRED);
666
667DBG("Initializing font....\n",theme_name);
668
669initFont( &font_console, &images[iFontConsole]);
670initFont( &font_small, &images[iFontSmall]);
671
672DBG("Graphic objects successfully loaded !!\n",theme_name);
673
674return 0;
675}
676
677static int unloadGraphics(void)
678{
679 int i;
680
681 destroyFont(&font_console);
682 destroyFont(&font_small);
683for (i = 0; i < sizeof(images) / sizeof(images[0]); i++)
684{
685 if (images[i].image)
686 {
687 if (images[i].image->pixels) free(images[i].image->pixels);
688 free (images[i].image);
689 images[i].image = 0;
690 }
691}
692return 0;
693}
694
695static int freeBackBuffer( window_t *window )
696{
697if (gui.backbuffer && gui.backbuffer->pixels)
698 {
699free(gui.backbuffer->pixels);
700free(gui.backbuffer);
701gui.backbuffer = 0;
702return 0;
703}
704
705return 1;
706}
707
708#if UNUSED
709pixmap_t *getCroppedPixmapAtPosition( pixmap_t *from, position_t pos, uint16_t width, uint16_t height )
710{
711
712pixmap_t *cropped = malloc( sizeof( pixmap_t ) );
713if( !cropped )
714return 0;
715cropped->pixels = malloc( width * height * 4 );
716if ( !cropped->pixels )
717return 0;
718
719cropped->width = width;
720cropped->height = height;
721
722int destx = 0, desty = 0;
723int srcx = pos.x, srcy = pos.y;
724
725for( ; desty < height; desty++, srcy++)
726{
727for( destx = 0, srcx = pos.x; destx < width; destx++, srcx++ )
728{
729pixel( cropped, destx, desty ).value = pixel( from, srcx, srcy ).value;
730}
731}
732return cropped;
733}
734#endif
735
736static int createBackBuffer( window_t *window )
737{
738gui.backbuffer = malloc(sizeof(pixmap_t));
739if(!gui.backbuffer)
740{
741DBG("Unable to allocate memory for gui.backbuffer");
742return 1;
743}
744
745gui.backbuffer->pixels = malloc( window->width * window->height * 4 );
746if(!gui.backbuffer->pixels)
747{
748free(gui.backbuffer);
749gui.backbuffer = 0;
750DBG("Unable to allocate memory for gui.backbuffer->pixels");
751return 1;
752}
753
754gui.backbuffer->width = gui.screen.width;
755gui.backbuffer->height = gui.screen.height;
756
757return 0;
758}
759
760static int createWindowBuffer( window_t *window )
761{
762window->pixmap = malloc(sizeof(pixmap_t));
763if(!window->pixmap)
764{
765DBG("Unable to allocate memory for window->pixmap");
766return 1;
767}
768
769window->pixmap->pixels = malloc( window->width * window->height * 4 );
770if(!window->pixmap->pixels)
771{
772free(window->pixmap);
773window->pixmap = 0;
774DBG("Unable to allocate memory for window->pixmap->pixels");
775return 1;
776}
777
778window->pixmap->width = window->width;
779window->pixmap->height = window->height;
780
781return 0;
782}
783
784static int freeWindowBuffer( window_t *window )
785{
786if (window->pixmap && window->pixmap->pixels)
787 {
788free(window->pixmap->pixels);
789free(window->pixmap);
790return 0;
791}
792
793return 1;
794}
795
796static void fillPixmapWithColor(pixmap_t *pm, uint32_t color)
797{
798int x,y;
799
800// fill with given color AARRGGBB
801for( x=0; x < pm->width; x++ )
802for( y=0; y< pm->height; y++)
803pixel(pm,x,y).value = color;
804}
805
806void drawBackground()
807{
808// reset text cursor
809gui.screen.cursor.x = gui.screen.hborder;
810gui.screen.cursor.y = gui.screen.vborder;
811
812fillPixmapWithColor( gui.screen.pixmap, gui.screen.bgcolor);
813
814// draw background.png into background buffer
815blend( images[iBackground].image, gui.screen.pixmap, gui.background.pos );
816
817// draw logo.png into background buffer
818if (gui.logo.draw)
819{
820 blend( images[iLogo].image, gui.screen.pixmap, gui.logo.pos);
821}
822
823memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
824}
825
826static void setupDeviceList(config_file_t *theme)
827{
828unsigned int pixel;
829intalpha;// transparency level 0 (obligue) - 255 (transparent)
830uint32_t color;// color value formatted RRGGBB
831int val, len;
832const char *string;
833 int devcnt = (int)get_env(envgDeviceCount);
834
835if(getIntForKey("devices_max_visible", &val, theme ))
836gui.maxdevices = MIN( val, devcnt );
837
838if(getIntForKey("devices_iconspacing", &val, theme ))
839gui.devicelist.iconspacing = val;
840
841// check layout for horizontal or vertical
842gui.layout = HorizontalLayout;
843if(getValueForKey( "devices_layout", &string, &len, theme)) {
844if (!strcmp (string, "vertical")) {
845gui.layout = VerticalLayout;
846}
847}
848
849switch (gui.layout) {
850case VerticalLayout:
851gui.devicelist.height = ((images[iSelection].image->height + font_console.chars[0]->height + gui.devicelist.iconspacing) * MIN(gui.maxdevices, devcnt) + (images[iDeviceScrollPrev].image->height + images[iDeviceScrollNext].image->height) + gui.devicelist.iconspacing);
852gui.devicelist.width = (images[iSelection].image->width + gui.devicelist.iconspacing);
853
854if(GUI_getDimensionForKey("devices_pos_x", &pixel, theme, gui.screen.width , images[iSelection].image->width ) )
855gui.devicelist.pos.x = pixel;
856
857if(GUI_getDimensionForKey("devices_pos_y", &pixel, theme, gui.screen.height , gui.devicelist.height ) )
858gui.devicelist.pos.y = pixel;
859break;
860
861case HorizontalLayout:
862default:
863gui.devicelist.width = ((images[iSelection].image->width + gui.devicelist.iconspacing) * MIN(gui.maxdevices, devcnt) + (images[iDeviceScrollPrev].image->width + images[iDeviceScrollNext].image->width) + gui.devicelist.iconspacing);
864gui.devicelist.height = (images[iSelection].image->height + font_console.chars[0]->height + gui.devicelist.iconspacing);
865
866if(GUI_getDimensionForKey("devices_pos_x", &pixel, theme, gui.screen.width , gui.devicelist.width ) )
867gui.devicelist.pos.x = pixel;
868else
869gui.devicelist.pos.x = ( gui.screen.width - gui.devicelist.width ) / 2;
870
871if(GUI_getDimensionForKey("devices_pos_y", &pixel, theme, gui.screen.height , images[iSelection].image->height ) )
872gui.devicelist.pos.y = pixel;
873else
874gui.devicelist.pos.y = ( gui.screen.height - gui.devicelist.height ) / 2;
875break;
876}
877
878if(GUI_getColorForKey("devices_bgcolor", &color, theme))
879gui.devicelist.bgcolor = (color & 0x00FFFFFF);
880
881if(getIntForKey("devices_transparency", &alpha, theme))
882gui.devicelist.bgcolor = gui.devicelist.bgcolor | (( 255 - ( alpha & 0xFF) ) << 24);
883
884if (gui.devicelist.pixmap)
885{
886 freeWindowBuffer(&gui.devicelist);
887 createWindowBuffer(&gui.devicelist);
888 }
889}
890
891static void loadThemeValues(config_file_t *theme)
892{
893unsigned int screen_width = gui.screen.width;
894unsigned int screen_height = gui.screen.height;
895unsigned int pixel;
896intalpha;// transparency level 0 (obligue) - 255 (transparent)
897uint32_t color;// color value formatted RRGGBB
898int val;
899
900/*
901 * Parse screen parameters
902 */
903if(GUI_getColorForKey("screen_bgcolor", &color, theme ))
904gui.screen.bgcolor = (color & 0x00FFFFFF);
905
906if(getIntForKey("screen_textmargin_h", &val, theme))
907gui.screen.hborder = MIN( gui.screen.width , val );
908
909if(getIntForKey("screen_textmargin_v", &val, theme))
910gui.screen.vborder = MIN( gui.screen.height , val );
911
912/*
913 * Parse background parameters
914 */
915if(GUI_getDimensionForKey("background_pos_x", &pixel, theme, screen_width , images[iBackground].image->width ) )
916gui.background.pos.x = pixel;
917
918if(GUI_getDimensionForKey("background_pos_y", &pixel, theme, screen_height , images[iBackground].image->height ) )
919gui.background.pos.y = pixel;
920
921/*
922 * Parse logo parameters
923 */
924if(GUI_getDimensionForKey("logo_pos_x", &pixel, theme, screen_width , images[iLogo].image->width ) )
925gui.logo.pos.x = pixel;
926
927if(GUI_getDimensionForKey("logo_pos_y", &pixel, theme, screen_height , images[iLogo].image->height ) )
928gui.logo.pos.y = pixel;
929
930/*
931 * Parse progress bar parameters
932 */
933if(GUI_getDimensionForKey("progressbar_pos_x", &pixel, theme, screen_width , 0 ) )
934gui.progressbar.pos.x = pixel;
935
936if(GUI_getDimensionForKey("progressbar_pos_y", &pixel, theme, screen_height , 0 ) )
937gui.progressbar.pos.y = pixel;
938
939/*
940 * Parse countdown text parameters
941 */
942if(GUI_getDimensionForKey("countdown_pos_x", &pixel, theme, screen_width , 0 ) )
943gui.countdown.pos.x = pixel;
944
945if(GUI_getDimensionForKey("countdown_pos_y", &pixel, theme, screen_height , 0 ) )
946gui.countdown.pos.y = pixel;
947
948 /*
949 * Parse devicelist parameters
950 */
951setupDeviceList(theme);
952
953/*
954 * Parse infobox parameters
955 */
956if(getIntForKey("infobox_width", &val, theme) && val >= 0)
957gui.infobox.width = MIN( screen_width ,(unsigned) val );
958
959if(getIntForKey("infobox_height", &val, theme) && val >= 0)
960gui.infobox.height = MIN( screen_height , (unsigned)val );
961
962if(GUI_getDimensionForKey("infobox_pos_x", &pixel, theme, screen_width , gui.infobox.width ) )
963gui.infobox.pos.x = pixel;
964
965if(GUI_getDimensionForKey("infobox_pos_y", &pixel, theme, screen_height , gui.infobox.height ) )
966gui.infobox.pos.y = pixel;
967
968if(getIntForKey("infobox_textmargin_h", &val, theme))
969gui.infobox.hborder = MIN( gui.infobox.width , val );
970
971if(getIntForKey("infobox_textmargin_v", &val, theme))
972gui.infobox.vborder = MIN( gui.infobox.height , val );
973
974if(GUI_getColorForKey("infobox_bgcolor", &color, theme))
975gui.infobox.bgcolor = (color & 0x00FFFFFF);
976
977if(getIntForKey("infobox_transparency", &alpha, theme))
978gui.infobox.bgcolor = gui.infobox.bgcolor | (( 255 - ( alpha & 0xFF) ) << 24);
979
980/*
981 * Parse menu parameters
982 */
983if(GUI_getDimensionForKey("menu_width", &pixel, theme, gui.screen.width , 0 ) )
984gui.menu.width = pixel;
985else
986gui.menu.width = images[iMenuSelection].image->width;
987
988if(GUI_getDimensionForKey("menu_height", &pixel, theme, gui.screen.height , 0 ) )
989gui.menu.height = pixel;
990else
991gui.menu.height = (infoMenuItemsCount) * images[iMenuSelection].image->height;
992
993if(GUI_getDimensionForKey("menu_pos_x", &pixel, theme, screen_width , gui.menu.width ) )
994gui.menu.pos.x = pixel;
995
996if(GUI_getDimensionForKey("menu_pos_y", &pixel, theme, screen_height , gui.menu.height ) )
997gui.menu.pos.y = pixel;
998
999if(getIntForKey("menu_textmargin_h", &val, theme))
1000gui.menu.hborder = MIN( gui.menu.width , val );
1001
1002if(getIntForKey("menu_textmargin_v", &val, theme))
1003gui.menu.vborder = MIN( gui.menu.height , val );
1004
1005if(GUI_getColorForKey("menu_bgcolor", &color, theme))
1006gui.menu.bgcolor = (color & 0x00FFFFFF);
1007
1008if(getIntForKey("menu_transparency", &alpha, theme))
1009gui.menu.bgcolor = gui.menu.bgcolor | (( 255 - ( alpha & 0xFF) ) << 24);
1010
1011/*
1012 * Parse bootprompt parameters
1013 */
1014if(GUI_getDimensionForKey("bootprompt_width", &pixel, theme, screen_width , 0 ) )
1015gui.bootprompt.width = pixel;
1016
1017if(getIntForKey("bootprompt_height", &val, theme) && val >= 0)
1018gui.bootprompt.height = MIN( screen_height , (unsigned)val );
1019
1020if(GUI_getDimensionForKey("bootprompt_pos_x", &pixel, theme, screen_width , gui.bootprompt.width ) )
1021gui.bootprompt.pos.x = pixel;
1022
1023if(GUI_getDimensionForKey("bootprompt_pos_y", &pixel, theme, screen_height , gui.bootprompt.height ) )
1024gui.bootprompt.pos.y = pixel;
1025
1026if(getIntForKey("bootprompt_textmargin_h", &val, theme) && val >= 0)
1027gui.bootprompt.hborder = MIN( gui.bootprompt.width , (unsigned)val );
1028
1029if(getIntForKey("bootprompt_textmargin_v", &val, theme) && val >= 0)
1030gui.bootprompt.vborder = MIN( gui.bootprompt.height , (unsigned)val );
1031
1032if(GUI_getColorForKey("bootprompt_bgcolor", &color, theme))
1033gui.bootprompt.bgcolor = (color & 0x00FFFFFF);
1034
1035if(getIntForKey("bootprompt_transparency", &alpha, theme))
1036gui.bootprompt.bgcolor = gui.bootprompt.bgcolor | (( 255 - ( alpha & 0xFF) ) << 24);
1037
1038if(GUI_getColorForKey("font_small_color", &color, theme))
1039gui.screen.font_small_color = (color & 0x00FFFFFF);
1040
1041if(GUI_getColorForKey("font_console_color", &color, theme))
1042gui.screen.font_console_color = (color & 0x00FFFFFF);
1043}
1044
1045#define MAX_THEMES 255
1046
1047static void add_theme(const char* theme, uint8_t nb)
1048{
1049
1050themeList_t* new_theme = malloc(sizeof(themeList_t));
1051if (new_theme)
1052{
1053new_theme->next = themeList;
1054
1055themeList = new_theme;
1056
1057new_theme->nb = nb;
1058new_theme->theme = newString(theme);
1059}
1060}
1061
1062static void free_theme_list()
1063{
1064themeList_t* entry = themeList;
1065while(entry)
1066{
1067#if DEBUG_GUI
1068printf("freeing %s (nb = %d)\n", entry->theme, entry->nb);
1069#endif
1070
1071char *theme = entry->theme;
1072themeList_t* tmp = NULL;
1073
1074tmp = entry;
1075entry = entry->next;
1076
1077free(theme);
1078free(tmp);
1079
1080}
1081}
1082
1083
1084static int randomTheme(char *dirspec, const char **theme) {
1085
1086long ret, flags, time;
1087long long index;
1088int sta = 1;
1089const char * name;
1090index = 0;
1091uint8_t i=0;
1092
1093#ifdef EMBED_THEME
1094add_theme("", i);
1095i++;
1096#endif
1097
1098while (i < MAX_THEMES) {
1099ret = GetDirEntry(dirspec, &index, &name, &flags, &time);
1100if (ret == -1) break;
1101
1102// Make sure this is a directory.
1103if ((flags & kFileTypeMask) != kFileTypeDirectory) continue;
1104
1105add_theme(name, i);
1106
1107i++;
1108
1109}
1110#if DEBUG_GUI
1111themeList_t* debugentry = themeList;
1112printf("theme list: \n");
1113while(debugentry)
1114{
1115printf("* %s (nb = %d)\n", debugentry->theme, debugentry->nb);
1116debugentry = debugentry->next;
1117}
1118printf("\n");
1119#endif
1120
1121if (i) {
1122
1123uint8_t choosen = arc4random_uniform(i);
1124#if DEBUG_GUI
1125printf("choosen number (nb = %d), i = %d \n", choosen, i);
1126#endif
1127themeList_t* entry = themeList;
1128
1129while(entry)
1130{
1131
1132if (entry->nb == choosen) {
1133#if DEBUG_GUI
1134
1135printf("choosen theme %s (nb = %d)\n", entry->theme, entry->nb);
1136sleep(1);
1137#endif
1138*theme = entry->theme;
1139
1140sta = startGUI();
1141
1142break;
1143}
1144
1145entry = entry->next;
1146}
1147
1148free_theme_list();
1149
1150}
1151#if DEBUG_GUI
1152else {
1153printf("No theme found !!\n");
1154
1155sleep(1);
1156}
1157#endif
1158return sta;
1159}
1160
1161int initGUI(void)
1162{
1163bool dummybool = true;
1164int ret = 1;
1165bool theme_ran= false;
1166bool theme_name_set= false;
1167
1168getBoolForKey(kGUIKey, &dummybool, DEFAULT_BOOT_CONFIG);
1169if (!dummybool) {
1170return 1;
1171}
1172 getMemoryInfoString = (void*)lookup_all_symbols(SYMBOLS_BUNDLE,"_getMemoryInfoString");
1173 showHelp = (void*)lookup_all_symbols(SYMBOLS_BUNDLE,"_showHelp");
1174
1175
1176getBoolForKey("RandomTheme", &theme_ran, DEFAULT_BOOT_CONFIG);
1177
1178{
1179long flags;
1180long time;
1181long ret = -1;
1182int len;
1183
1184theme_name_set = getValueForKey( "Theme", &theme_name, &len, DEFAULT_BOOT_CONFIG );
1185
1186if (theme_ran)
1187{
1188retry:
1189ret = GetFileInfo("rd(0,0)/Extra/", "Themes", &flags, &time);
1190if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)) {
1191sprintf(dirsrc, "rd(0,0)/Extra/Themes");
1192
1193} else {
1194ret = GetFileInfo("/Extra/", "Themes", &flags, &time);
1195if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)) {
1196sprintf(dirsrc, "/Extra/Themes");
1197
1198} else {
1199ret = GetFileInfo("bt(0,0)/Extra/", "Themes", &flags, &time);
1200if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)) {
1201sprintf(dirsrc, "bt(0,0)/Extra/Themes");
1202
1203} else {
1204printf("Failed to find the /extra/Themes folder\n");
1205return 1;
1206}
1207}
1208
1209}
1210}
1211else if (theme_name_set)
1212{
1213ret = GetFileInfo("rd(0,0)/Extra/Themes/", theme_name, &flags, &time);
1214if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)) {
1215sprintf(dirsrc, "rd(0,0)/Extra/Themes");
1216
1217} else {
1218ret = GetFileInfo("/Extra/Themes/", theme_name, &flags, &time);
1219if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)) {
1220sprintf(dirsrc, "/Extra/Themes");
1221
1222} else {
1223ret = GetFileInfo("bt(0,0)/Extra/Themes/", theme_name, &flags, &time);
1224if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)) {
1225sprintf(dirsrc, "bt(0,0)/Extra/Themes");
1226
1227} else {
1228printf("Failed to find the /extra/Themes/%s folder\n",theme_name);
1229theme_name_set = false;
1230goto retry;
1231}
1232}
1233
1234}
1235}
1236}
1237
1238if (theme_ran)
1239{
1240
1241ret = randomTheme(dirsrc, &theme_name);
1242
1243if (ret) {
1244printf("randomTheme Failed !! \n");
1245//#if DEBUG_GUI
1246getc();
1247//#endif
1248}
1249#if DEBUG_GUI
1250else
1251 {
1252 DBG("Theme successfuly Choosen randomly !! \n");
1253 }
1254#endif
1255}
1256
1257if (ret)
1258{
1259if (theme_name_set == true)
1260{
1261ret = startGUI();
1262
1263if (ret) printf("Failed to load Theme : %s !! \n", theme_name);
1264
1265}
1266#ifdef EMBED_THEME
1267if (ret) {
1268theme_name = "";
1269ret = startGUI();
1270
1271if (ret) printf("Failed to load Embed Theme !! \n");
1272
1273}
1274#endif
1275if (ret && (strcmp(theme_name, THEME_NAME_DEFAULT) != 0)) {
1276theme_name = THEME_NAME_DEFAULT;
1277ret = startGUI();
1278
1279if (ret) printf("Failed to load Default Theme : %s !! \n", THEME_NAME_DEFAULT);
1280}
1281}
1282return ret;
1283}
1284
1285static int startGUI(void)
1286{
1287int val;
1288char dirspec[256];
1289
1290
1291if ((unsigned)(strlen(theme_name) + strlen(dirsrc) + strlen("theme.plist") + 2 ) > sizeof(dirspec)) {
1292
1293DBG("Path of %s/%s/theme.plist to long\n", dirsrc, theme_name);
1294return 1;
1295}
1296
1297sprintf(dirspec, "%s/%s/theme.plist", dirsrc ,theme_name);
1298
1299if (loadConfigFile(dirspec, &themeConfig) != 0) {
1300
1301#ifdef EMBED_THEME
1302if (strlen(theme_name) == 0) {
1303config_file_t *config;
1304
1305config = &themeConfig;
1306if (ParseXMLFile((char *)__theme_plist, &config->dictionary) != 0) {
1307
1308DBG("Unable to load embed theme plist datas.\n");
1309
1310return 1;
1311}
1312}
1313#else
1314
1315DBG("Unable to load %s theme plist.\n",theme_name);
1316
1317return 1;
1318
1319#endif
1320 }
1321
1322if (execute_hook("getResolution_hook", &screen_params[0], &screen_params[1], &screen_params[2], NULL, NULL, NULL) != EFI_SUCCESS)
1323{
1324// parse display size parameters
1325if (getIntForKey("screen_width", &val, &themeConfig) && val > 0) {
1326screen_params[0] = val;
1327}
1328if (getIntForKey("screen_height", &val, &themeConfig) && val > 0) {
1329screen_params[1] = val;
1330}
1331}
1332#if DEBUG_GUI
1333else
1334{
1335printf("No getResolution function hook installed, using default resolution.\n",theme_name);
1336
1337}
1338#endif
1339
1340
1341// Initalizing GUI strucutre.
1342bzero(&gui, sizeof(gui_t));
1343
1344// find best matching vesa mode for our requested width & height
1345getGraphicModeParams(screen_params);
1346
1347// set our screen structure with the mode width & height
1348gui.screen.width = screen_params[0];
1349gui.screen.height = screen_params[1];
1350
1351// load graphics otherwise fail and return
1352if (loadGraphics(dirsrc) == 0) {
1353loadThemeValues(&themeConfig);
1354colorFont(&font_small, gui.screen.font_small_color);
1355colorFont(&font_console, gui.screen.font_console_color);
1356
1357// create the screen & window buffers
1358if (createBackBuffer(&gui.screen) == 0)
1359{
1360if (createWindowBuffer(&gui.screen) == 0)
1361{
1362if (createWindowBuffer(&gui.devicelist) == 0)
1363{
1364if (createWindowBuffer(&gui.bootprompt) == 0)
1365{
1366if (createWindowBuffer(&gui.infobox) == 0)
1367{
1368if (createWindowBuffer(&gui.menu) == 0)
1369{
1370 gui.logo.draw = true;
1371drawBackground();
1372// lets copy the screen into the back buffer
1373 memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
1374
1375setVideoMode( GRAPHICS_MODE );
1376
1377gui.initialised = true;
1378return 0;
1379}
1380}
1381}
1382}
1383}
1384}
1385}
1386
1387DBG("Loading error occurred, reseting...\n",theme_name);
1388
1389// Loading error occurred, freeing resources
1390 freeWindowBuffer(&gui.menu);
1391 freeWindowBuffer(&gui.infobox);
1392 freeWindowBuffer(&gui.bootprompt);
1393 freeWindowBuffer(&gui.devicelist);
1394 freeWindowBuffer(&gui.screen);
1395 freeBackBuffer(&gui.screen);
1396 unloadGraphics();
1397
1398return 1;
1399}
1400
1401static bool is_image_loaded(int i)
1402{
1403return (images[i].image != NULL) ? true : false;
1404}
1405
1406static void drawDeviceIcon(BVRef device, pixmap_t *buffer, position_t p, bool isSelected)
1407{
1408int devicetype;
1409
1410if( diskIsCDROM(device) )
1411devicetype = iDeviceCDROM;// Use CDROM icon
1412else
1413{
1414switch (device->part_type)
1415{
1416case kPartitionTypeHFS:
1417{
1418#ifdef BOOT_HELPER_SUPPORT
1419// Use HFS or HFSRAID icon depending on bvr flags.
1420if (device->flags & kBVFlagBooter) {
1421
1422switch (device->OSVersion[3]) {
1423 case '8':
1424 devicetype = is_image_loaded(iDeviceHFSRAID_ML) ? iDeviceHFSRAID_ML : is_image_loaded(iDeviceHFSRAID) ? iDeviceHFSRAID : iDeviceGeneric;
1425 break;
1426case '7':
1427devicetype = is_image_loaded(iDeviceHFSRAID_Lion) ? iDeviceHFSRAID_Lion : is_image_loaded(iDeviceHFSRAID) ? iDeviceHFSRAID : iDeviceGeneric;
1428break;
1429case '6':
1430devicetype = is_image_loaded(iDeviceHFSRAID_SL) ? iDeviceHFSRAID_SL : is_image_loaded(iDeviceHFSRAID) ? iDeviceHFSRAID : iDeviceGeneric;
1431break;
1432case '5':
1433devicetype = is_image_loaded(iDeviceHFSRAID_Leo) ? iDeviceHFSRAID_Leo : is_image_loaded(iDeviceHFSRAID) ? iDeviceHFSRAID : iDeviceGeneric;
1434break;
1435case '4':
1436devicetype = is_image_loaded(iDeviceHFSRAID_Tiger) ? iDeviceHFSRAID_Tiger : is_image_loaded(iDeviceHFSRAID) ? iDeviceHFSRAID : iDeviceGeneric;
1437break;
1438default:
1439devicetype = is_image_loaded(iDeviceHFSRAID) ? iDeviceHFSRAID : iDeviceGeneric;
1440break;
1441}
1442
1443} else
1444#endif
1445{
1446
1447switch (device->OSVersion[3]) {
1448 case '8':
1449 devicetype = is_image_loaded(iDeviceHFS_ML) ? iDeviceHFS_ML : is_image_loaded(iDeviceHFS) ? iDeviceHFS : iDeviceGeneric;
1450 break;
1451case '7':
1452devicetype = is_image_loaded(iDeviceHFS_Lion) ? iDeviceHFS_Lion : is_image_loaded(iDeviceHFS) ? iDeviceHFS : iDeviceGeneric;
1453break;
1454case '6':
1455devicetype = is_image_loaded(iDeviceHFS_SL) ? iDeviceHFS_SL : is_image_loaded(iDeviceHFS) ? iDeviceHFS : iDeviceGeneric;
1456break;
1457case '5':
1458devicetype = is_image_loaded(iDeviceHFS_Leo) ? iDeviceHFS_Leo : is_image_loaded(iDeviceHFS) ? iDeviceHFS : iDeviceGeneric;
1459break;
1460case '4':
1461devicetype = is_image_loaded(iDeviceHFS_Tiger) ? iDeviceHFS_Tiger : is_image_loaded(iDeviceHFS) ? iDeviceHFS : iDeviceGeneric;
1462break;
1463default:
1464devicetype = is_image_loaded(iDeviceHFS) ? iDeviceHFS : iDeviceGeneric;
1465break;
1466}
1467
1468}
1469
1470break;
1471
1472}
1473case kPartitionTypeHPFS:
1474devicetype = is_image_loaded(iDeviceNTFS) ? iDeviceNTFS : iDeviceGeneric;// Use HPFS / NTFS icon
1475break;
1476
1477case kPartitionTypeFAT16:
1478devicetype = is_image_loaded(iDeviceFAT16) ? iDeviceFAT16 : iDeviceGeneric;// Use FAT16 icon
1479break;
1480
1481case kPartitionTypeFAT32:
1482devicetype = is_image_loaded(iDeviceFAT32) ? iDeviceFAT32 : iDeviceGeneric;// Use FAT32 icon
1483break;
1484
1485case kPartitionTypeEXT3:
1486devicetype = is_image_loaded(iDeviceEXT3) ? iDeviceEXT3 : iDeviceGeneric;// Use EXT2/3 icon
1487break;
1488
1489case kPartitionTypeFreeBSD:
1490devicetype = is_image_loaded(iDeviceFreeBSD) ? iDeviceFreeBSD : iDeviceGeneric;// Use FreeBSD icon
1491break;
1492
1493case kPartitionTypeOpenBSD:
1494devicetype = is_image_loaded(iDeviceOpenBSD) ? iDeviceOpenBSD : iDeviceGeneric;// Use OpenBSD icon
1495break;
1496
1497case kPartitionTypeBEFS: /* Haiku detection and Icon credits to scorpius */
1498devicetype = is_image_loaded(iDeviceBEFS) ? iDeviceBEFS : iDeviceGeneric;// Use BEFS / Haiku icon
1499break;
1500
1501default:
1502devicetype = iDeviceGeneric;// Use Generic icon
1503break;
1504}
1505}
1506
1507// Draw the selection image and use the next (device_*_o) image for the selected item.
1508 if (isSelected)
1509{
1510blend(images[iSelection].image, buffer, centeredAt(images[iSelection].image, p));
1511devicetype++; // selec override image
1512}
1513
1514// draw icon
1515blend( images[devicetype].image, buffer, centeredAt( images[devicetype].image, p ));
1516
1517p.y += (images[iSelection].image->height / 2) + font_console.chars[0]->height;
1518
1519// draw volume label
1520drawStrCenteredAt( device->label, &font_small, buffer, p);
1521
1522}
1523
1524void drawDeviceList (int start, int end, int selection, MenuItem * menuItems)
1525{
1526int i;
1527position_t p, p_prev, p_next;
1528
1529//uint8_tmaxDevices = MIN( gui.maxdevices, menucount );
1530
1531fillPixmapWithColor( gui.devicelist.pixmap, gui.devicelist.bgcolor);
1532
1533makeRoundedCorners( gui.devicelist.pixmap);
1534
1535 int devcnt = (int)get_env(envgDeviceCount);
1536
1537switch (gui.layout)
1538{
1539
1540case VerticalLayout:
1541p.x = (gui.devicelist.width /2);
1542p.y = ( ( images[iSelection].image->height / 2 ) + images[iDeviceScrollPrev].image->height + gui.devicelist.iconspacing );
1543
1544// place scroll indicators at top & bottom edges
1545p_prev = pos ( gui.devicelist.width / 2 , gui.devicelist.iconspacing );
1546p_next = pos ( p_prev.x, gui.devicelist.height - gui.devicelist.iconspacing );
1547
1548break;
1549
1550default:// use Horizontal layout as the default
1551
1552case HorizontalLayout:
1553p.x = (gui.devicelist.width - ( gui.devicelist.width / gui.maxdevices ) * gui.maxdevices ) / 2 + ( images[iSelection].image->width / 2) + images[iDeviceScrollPrev].image->width + gui.devicelist.iconspacing;
1554p.y = ((gui.devicelist.height - font_console.chars[0]->height ) - images[iSelection].image->height) / 2 + ( images[iSelection].image->height / 2 );
1555
1556// place scroll indicators at left & right edges
1557p_prev = pos ( images[iDeviceScrollPrev].image->width / 2 + gui.devicelist.iconspacing / 2, gui.devicelist.height / 2 );
1558p_next = pos ( gui.devicelist.width - ( images[iDeviceScrollNext].image->width / 2 + gui.devicelist.iconspacing / 2), gui.devicelist.height / 2 );
1559
1560break;
1561
1562}
1563
1564// draw visible device icons
1565for (i = 0; i < gui.maxdevices; i++)
1566{
1567BVRef param = menuItems[start + i].param;
1568
1569 bool isSelected = ((start + i) == selection) ? true : false;
1570if (isSelected)
1571{
1572 if (param->flags & kBVFlagNativeBoot)
1573 {
1574 infoMenuNativeBoot = true;
1575 }
1576 else
1577 {
1578 infoMenuNativeBoot = false;
1579 if(infoMenuSelection >= INFOMENU_NATIVEBOOT_START && infoMenuSelection <= INFOMENU_NATIVEBOOT_END)
1580infoMenuSelection = 0;
1581 }
1582
1583if(gui.menu.draw)
1584drawInfoMenuItems();
1585
1586#if DEBUG_GUI
1587 gui.debug.cursor = pos( 10, 100);
1588 dprintf( &gui.screen, "label %s\n", param->label );
1589 dprintf( &gui.screen, "biosdev 0x%x\n", param->biosdev );
1590 dprintf( &gui.screen, "width %d\n", gui.screen.width);
1591 dprintf( &gui.screen, "height %d\n", gui.screen.height);
1592 dprintf( &gui.screen, "type 0x%x\n", param->type );
1593 dprintf( &gui.screen, "flags 0x%x\n", param->flags );
1594 dprintf( &gui.screen, "part_no %d\n", param->part_no );
1595 dprintf( &gui.screen, "part_boff 0x%x\n", param->part_boff );
1596 dprintf( &gui.screen, "part_type 0x%x\n", param->part_type );
1597 dprintf( &gui.screen, "bps 0x%x\n", param->bps );
1598 dprintf( &gui.screen, "name %s\n", param->name );
1599 dprintf( &gui.screen, "type_name %s\n", param->type_name );
1600 dprintf( &gui.screen, "modtime %d\n", param->modTime );
1601#endif
1602}
1603
1604drawDeviceIcon( param, gui.devicelist.pixmap, p, isSelected);
1605
1606if (gui.layout == HorizontalLayout)
1607{
1608p.x += images[iSelection].image->width + gui.devicelist.iconspacing;
1609}
1610if (gui.layout == VerticalLayout)
1611{
1612p.y += ( images[iSelection].image->height + font_console.chars[0]->height + gui.devicelist.iconspacing );
1613}
1614}
1615
1616// draw prev indicator
1617if(start)
1618blend( images[iDeviceScrollPrev].image, gui.devicelist.pixmap, centeredAt( images[iDeviceScrollPrev].image, p_prev ) );
1619
1620// draw next indicator
1621if( end < devcnt - 1 )
1622blend( images[iDeviceScrollNext].image, gui.devicelist.pixmap, centeredAt( images[iDeviceScrollNext].image, p_next ) );
1623
1624gui.redraw = true;
1625
1626updateVRAM();
1627
1628}
1629
1630void clearGraphicBootPrompt()
1631{
1632// clear text buffer
1633prompt[0] = '\0';
1634prompt_pos=0;
1635
1636
1637if(gui.bootprompt.draw == true )
1638{
1639gui.bootprompt.draw = false;
1640gui.redraw = true;
1641// this causes extra frames to be drawn
1642//updateVRAM();
1643}
1644
1645return;
1646}
1647
1648void updateGraphicBootPrompt(int key)
1649{
1650if ( key == kBackspaceKey )
1651prompt[--prompt_pos] = '\0';
1652else
1653{
1654prompt[prompt_pos] = key;
1655prompt_pos++;
1656prompt[prompt_pos] = '\0';
1657}
1658
1659fillPixmapWithColor( gui.bootprompt.pixmap, gui.bootprompt.bgcolor);
1660
1661makeRoundedCorners( gui.bootprompt.pixmap);
1662
1663position_t p_text = pos( gui.bootprompt.hborder , ( ( gui.bootprompt.height - font_console.chars[0]->height) ) / 2 );
1664
1665// print the boot prompt text
1666drawStr(prompt_text, &font_console, gui.bootprompt.pixmap, p_text);
1667
1668// get the position of the end of the boot prompt text to display user input
1669position_t p_prompt = pos( p_text.x + ( ( strlen(prompt_text) ) * font_console.chars[0]->width ), p_text.y );
1670
1671// calculate the position of the cursor
1672intoffset = ( prompt_pos - ( ( gui.bootprompt.width / font_console.chars[0]->width ) - strlen(prompt_text) - 2 ) );
1673
1674if ( offset < 0)
1675offset = 0;
1676
1677drawStr( prompt+offset, &font_console, gui.bootprompt.pixmap, p_prompt);
1678
1679gui.menu.draw = false;
1680gui.bootprompt.draw = true;
1681gui.redraw = true;
1682
1683updateVRAM();
1684
1685return;
1686}
1687
1688
1689static inline
1690void vramwrite (void *data, int width)
1691{
1692if (VIDEO (depth) == 0x20 /*32*/ && VIDEO (rowBytes) == (unsigned long)gui.backbuffer->width * 4)
1693memcpy((uint8_t *)vram, gui.backbuffer->pixels, VIDEO (rowBytes)*VIDEO (height));
1694else
1695{
1696uint32_t r, g, b;
1697uint32_t i, j;
1698for (i = 0; i < VIDEO (height); i++)
1699for (j = 0; j < VIDEO (width); j++)
1700{
1701b = ((uint8_t *) data)[4*i*width + 4*j];
1702g = ((uint8_t *) data)[4*i*width + 4*j + 1];
1703r = ((uint8_t *) data)[4*i*width + 4*j + 2];
1704switch (VIDEO (depth))
1705{
1706case 32:
1707*(uint32_t *)(((uint8_t *)vram)+i*VIDEO (rowBytes) + j*4) = (b&0xff) | ((g&0xff)<<8) | ((r&0xff)<<16);
1708break;
1709case 24:
1710*(uint32_t *)(((uint8_t *)vram)+i*VIDEO (rowBytes) + j*3) = ((*(uint32_t *)(((uint8_t *)vram)+i*VIDEO (rowBytes) + j*3))&0xff000000)
1711| (b&0xff) | ((g&0xff)<<8) | ((r&0xff)<<16);
1712break;
1713case 16:
1714// Somehow 16-bit is always 15-bits really
1715//*(uint16_t *)(((uint8_t *)vram)+i*VIDEO (rowBytes) + j*2) = ((b&0xf8)>>3) | ((g&0xfc)<<3) | ((r&0xf8)<<8);
1716//break;
1717case 15:
1718*(uint16_t *)(((uint8_t *)vram)+i*VIDEO (rowBytes) + j*2) = ((b&0xf8)>>3) | ((g&0xf8)<<2) | ((r&0xf8)<<7);
1719break;
1720default:
1721break;
1722}
1723}
1724}
1725}
1726
1727void updateVRAM()
1728{
1729if (gui.redraw)
1730{
1731if (gui.devicelist.draw)
1732blend( gui.devicelist.pixmap, gui.backbuffer, gui.devicelist.pos );
1733
1734if (gui.bootprompt.draw)
1735blend( gui.bootprompt.pixmap, gui.backbuffer, gui.bootprompt.pos );
1736
1737if (gui.menu.draw)
1738blend( gui.menu.pixmap, gui.backbuffer, gui.menu.pos );
1739
1740if (gui.infobox.draw)
1741blend( gui.infobox.pixmap, gui.backbuffer, gui.infobox.pos );
1742}
1743
1744vramwrite ( gui.backbuffer->pixels, gui.backbuffer->width );
1745
1746if (gui.redraw)
1747{
1748memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
1749gui.redraw = false;
1750}
1751}
1752
1753static void
1754sputc(int c, struct putc_info * pi)
1755{
1756 if (pi->last_str)
1757 if (pi->str == pi->last_str) {
1758 *(pi->str) = '\0';
1759 return;
1760 }
1761 *(pi->str)++ = c;
1762}
1763
1764int gprintf( window_t * window, const char * fmt, ...)
1765{
1766char *formattedtext;
1767
1768va_list ap;
1769
1770struct putc_info pi;
1771
1772if ((formattedtext = malloc(1024)) != NULL) {
1773// format the text
1774va_start(ap, fmt);
1775pi.str = formattedtext;
1776pi.last_str = 0;
1777prf(fmt, ap, sputc, &pi);
1778*pi.str = '\0';
1779va_end(ap);
1780
1781position_torigin, cursor, bounds;
1782
1783int i;
1784int character;
1785
1786origin.x = MAX( window->cursor.x, window->hborder );
1787origin.y = MAX( window->cursor.y, window->vborder );
1788
1789bounds.x = ( window->width - window->hborder );
1790bounds.y = ( window->height - window->vborder );
1791
1792cursor = origin;
1793
1794font_t *font = &font_console;
1795
1796for( i=0; i< strlen(formattedtext); i++ )
1797{
1798character = formattedtext[i];
1799
1800character -= 32;
1801
1802// newline ?
1803if( formattedtext[i] == '\n' )
1804{
1805cursor.x = window->hborder;
1806cursor.y += font->height;
1807
1808if ( cursor.y > bounds.y )
1809cursor.y = origin.y;
1810
1811continue;
1812}
1813
1814// tab ?
1815if( formattedtext[i] == '\t' )
1816cursor.x += ( font->chars[0]->width * 5 );
1817
1818// draw the character
1819if( font->chars[character])
1820blend(font->chars[character], window->pixmap, cursor);
1821
1822cursor.x += font->chars[character]->width;
1823
1824// check x pos and do newline
1825if ( cursor.x > bounds.x )
1826{
1827cursor.x = origin.x;
1828cursor.y += font->height;
1829}
1830
1831// check y pos and reset to origin.y
1832if ( cursor.y > bounds.y )
1833cursor.y = origin.y;
1834}
1835
1836// update cursor postition
1837window->cursor = cursor;
1838
1839free(formattedtext);
1840
1841return 0;
1842
1843}
1844return 1;
1845}
1846#if DEBUG_GUI
1847static int dprintf( window_t * window, const char * fmt, ...)
1848{
1849char *formattedtext;
1850
1851va_list ap;
1852
1853//window = &gui.debug;
1854
1855struct putc_info pi;
1856
1857if ((formattedtext = malloc(1024)) != NULL) {
1858// format the text
1859va_start(ap, fmt);
1860pi.str = formattedtext;
1861pi.last_str = 0;
1862prf(fmt, ap, sputc, &pi);
1863*pi.str = '\0';
1864va_end(ap);
1865
1866position_torigin, cursor, bounds;
1867
1868int i;
1869int character;
1870
1871origin.x = MAX( gui.debug.cursor.x, window->hborder );
1872origin.y = MAX( gui.debug.cursor.y, window->vborder );
1873
1874bounds.x = ( window->width - window->hborder );
1875bounds.y = ( window->height - window->vborder );
1876
1877cursor = origin;
1878
1879font_t *font = &font_console;
1880
1881for( i=0; i< strlen(formattedtext); i++ )
1882{
1883character = formattedtext[i];
1884
1885character -= 32;
1886
1887// newline ?
1888if( formattedtext[i] == '\n' )
1889{
1890cursor.x = window->hborder;
1891cursor.y += font->height;
1892
1893if ( cursor.y > bounds.y )
1894cursor.y = origin.y;
1895
1896continue;
1897}
1898
1899// tab ?
1900if( formattedtext[i] == '\t' )
1901cursor.x += ( font->chars[0]->width * 5 );
1902
1903// draw the character
1904if( font->chars[character])
1905blend(font->chars[character], gui.backbuffer, cursor);
1906
1907cursor.x += font->chars[character]->width;
1908
1909// check x pos and do newline
1910if ( cursor.x > bounds.x )
1911{
1912cursor.x = origin.x;
1913cursor.y += font->height;
1914}
1915
1916// check y pos and reset to origin.y
1917if ( cursor.y > bounds.y )
1918cursor.y = origin.y;
1919}
1920
1921// update cursor postition
1922gui.debug.cursor = cursor;
1923
1924free(formattedtext);
1925
1926return 0;
1927
1928}
1929return 1;
1930}
1931#endif
1932int vprf(const char * fmt, va_list ap)
1933{
1934int i;
1935int character;
1936
1937char *formattedtext;
1938window_t *window = &gui.screen;
1939struct putc_info pi;
1940
1941position_torigin, cursor, bounds;
1942font_t *font = &font_console;
1943
1944if ((formattedtext = malloc(1024)) != NULL) {
1945// format the text
1946pi.str = formattedtext;
1947pi.last_str = 0;
1948prf(fmt, ap, sputc, &pi);
1949*pi.str = '\0';
1950
1951origin.x = MAX( window->cursor.x, window->hborder );
1952origin.y = MAX( window->cursor.y, window->vborder );
1953bounds.x = ( window->width - ( window->hborder * 2 ) );
1954bounds.y = ( window->height - ( window->vborder * 2 ) );
1955cursor = origin;
1956
1957for( i=0; i< strlen(formattedtext); i++ )
1958{
1959character = formattedtext[i];
1960character -= 32;
1961
1962// newline ?
1963if( formattedtext[i] == '\n' )
1964{
1965cursor.x = window->hborder;
1966cursor.y += font->height;
1967if ( cursor.y > bounds.y )
1968{
1969gui.redraw = true;
1970updateVRAM();
1971cursor.y = window->vborder;
1972}
1973window->cursor.y = cursor.y;
1974continue;
1975}
1976
1977// tab ?
1978if( formattedtext[i] == '\t' )
1979{
1980cursor.x = ( cursor.x / ( font->chars[0]->width * 8 ) + 1 ) * ( font->chars[0]->width * 8 );
1981continue;
1982}
1983cursor.x += font->chars[character]->width;
1984
1985// check x pos and do newline
1986if ( cursor.x > bounds.x )
1987{
1988cursor.x = origin.x;
1989cursor.y += font->height;
1990}
1991
1992// check y pos and reset to origin.y
1993if ( cursor.y > ( bounds.y + font->chars[0]->height) )
1994{
1995gui.redraw = true;
1996updateVRAM();
1997cursor.y = window->vborder;
1998}
1999// draw the character
2000if( font->chars[character])
2001blend(font->chars[character], gui.backbuffer, cursor);
2002}
2003// save cursor postition
2004window->cursor.x = cursor.x;
2005updateVRAM();
2006free(formattedtext);
2007return 0;
2008}
2009return 1;
2010}
2011
2012pixmap_t* charToPixmap(unsigned char ch, font_t *font) {
2013unsigned int cha = (unsigned int)ch - 32;
2014if (cha >= font->count)
2015// return ? if the font for the char doesn't exists
2016cha = '?' - 32;
2017return font->chars[cha] ? font->chars[cha] : NULL;
2018}
2019
2020static position_t drawChar(unsigned char ch, font_t *font, pixmap_t *blendInto, position_t p) {
2021pixmap_t* pm = charToPixmap(ch, font);
2022if (pm && ((p.x + pm->width) < blendInto->width))
2023{
2024blend(pm, blendInto, p);
2025return pos(p.x + pm->width, p.y);
2026}
2027else
2028return p;
2029}
2030
2031static void drawStr(char *ch, font_t *font, pixmap_t *blendInto, position_t p)
2032{
2033int i=0;
2034position_t current_pos = pos(p.x, p.y);
2035
2036for (i=0; i < strlen(ch); i++)
2037{
2038// newline ?
2039if ( ch[i] == '\n' )
2040{
2041current_pos.x = p.x;
2042current_pos.y += font->height;
2043continue;
2044}
2045
2046// tab ?
2047if ( ch[i] == '\t' )
2048{
2049current_pos.x += TAB_PIXELS_WIDTH;
2050continue;
2051}
2052
2053current_pos = drawChar(ch[i], font, blendInto, current_pos);
2054}
2055}
2056
2057static void drawStrCenteredAt(char *text, font_t *font, pixmap_t *blendInto, position_t p)
2058{
2059int i = 0;
2060int width = 0;
2061int max_width = 0;
2062int height = font->height;
2063
2064// calculate the width in pixels
2065for (i=0; i < strlen(text); i++) {
2066if (text[i] == '\n')
2067{
2068width = 0;
2069height += font->height;
2070}
2071else if (text[i] == '\t')
2072width += TAB_PIXELS_WIDTH;
2073else
2074{
2075pixmap_t* pm = charToPixmap(text[i], font);
2076if (pm)
2077width += pm->width;
2078}
2079if (width > max_width)
2080max_width = width;
2081}
2082
2083p.x = ( p.x - ( max_width / 2 ) );
2084p.y = ( p.y - ( height / 2 ) );
2085
2086drawStr(text, font, blendInto, p);
2087}
2088
2089static int destroyFont(font_t *font)
2090{
2091int i;
2092 for (i = 0; i < CHARACTERS_COUNT; i++)
2093 {
2094if (font->chars[i])
2095{
2096if (font->chars[i]->pixels) free (font->chars[i]->pixels);
2097free (font->chars[i]);
2098font->chars[i] = 0;
2099}
2100 }
2101 return 0;
2102}
2103
2104static int initFont(font_t *font, image_t *data)
2105{
2106unsigned int x = 0, y = 0, x2 = 0, x3 = 0;
2107
2108int start = 0, end = 0, count = 0, space = 0;
2109
2110bool monospaced = false;
2111
2112font->height = data->image->height;
2113
2114for( x = 0; x < data->image->width && count < CHARACTERS_COUNT; x++)
2115{
2116start = end;
2117
2118// if the pixel is red we've reached the end of the char
2119if( pixel( data->image, x, 0 ).value == 0xFFFF0000)
2120{
2121end = x + 1;
2122
2123if( (font->chars[count] = malloc(sizeof(pixmap_t)) ) )
2124{
2125font->chars[count]->width = ( end - start) - 1;
2126font->chars[count]->height = font->height;
2127{
2128 int pixels_size = (font->chars[count]->width * data->image->height * 4);
2129
2130 if (!(pixels_size > 0))
2131 {
2132 continue;
2133 }
2134
2135 if ( !( font->chars[count]->pixels = malloc( pixels_size ) ) )
2136 {
2137 continue;
2138 }
2139
2140space += pixels_size;
2141 }
2142// we skip the first line because there are just the red pixels for the char width
2143 for( y = 1; y< (font->height); y++)
2144 {
2145 for( x2 = (unsigned)start, x3 = 0; x2 < (unsigned)end; x2++, x3++)
2146 {
2147 pixel( font->chars[count], x3, y ) = pixel( data->image, x2, y );
2148 }
2149 }
2150
2151 // check if font is monospaced
2152 if( ( count > 0 ) && ( font->width != font->chars[count]->width ) )
2153 monospaced = true;
2154
2155 font->width = font->chars[count]->width;
2156
2157 count++;
2158
2159}
2160}
2161}
2162
2163for (x = count; x < CHARACTERS_COUNT; x++)
2164font->chars[x] = NULL;
2165
2166if(monospaced)
2167font->width = 0;
2168
2169font->count = count;
2170
2171return 0;
2172}
2173
2174static void colorFont(font_t *font, uint32_t color)
2175{
2176if( !color )
2177return;
2178
2179int x, y, width, height;
2180int count = 0;
2181pixel_t *buff;
2182
2183while( font->chars[count++] )
2184{
2185width = font->chars[count-1]->width;
2186height = font->chars[count-1]->height;
2187for( y = 0; y < height; y++ )
2188{
2189for( x = 0; x < width; x++ )
2190{
2191buff = &(pixel( font->chars[count-1], x, y ));
2192if( buff->ch.a )
2193{
2194buff->ch.r = (color & 0xFFFF0000) >> 16;
2195buff->ch.g = (color & 0xFF00FF00) >> 8;
2196buff->ch.b = (color & 0xFF0000FF);
2197}
2198}
2199}
2200}
2201}
2202
2203static void makeRoundedCorners(pixmap_t *p)
2204{
2205int x,y;
2206int width=p->width-1;
2207int height=p->height-1;
2208
2209// 10px rounded corner alpha values
2210uint8_t roundedCorner[10][10] =
2211{
2212{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0xC0, 0xFF},
2213{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF},
2214{ 0x00, 0x00, 0x00, 0x40, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
2215{ 0x00, 0x00, 0x40, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
2216{ 0x00, 0x40, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
2217{ 0x00, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
2218{ 0x40, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
2219{ 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
2220{ 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
2221{ 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
2222};
2223
2224uint8_t alpha=0;
2225
2226for( y=0; y<10; y++)
2227{
2228for( x=0; x<10; x++)
2229{
2230// skip if the pixel should be visible
2231if(roundedCorner[y][x] != 0xFF)
2232{
2233alpha = ( roundedCorner[y][x] ? (uint8_t) (roundedCorner[y][x] * pixel(p, x, y).ch.a) / 255 : 0 );
2234// Upper left corner
2235pixel(p, x, y).ch.a = alpha;
2236
2237// upper right corner
2238pixel(p, width-x,y).ch.a = alpha;
2239
2240// lower left corner
2241pixel(p, x, height-y).ch.a = alpha;
2242
2243// lower right corner
2244pixel(p, width-x, height-y).ch.a = alpha;
2245}
2246}
2247}
2248}
2249
2250void showInfoBox(char *title, char *text)
2251{
2252int i, key, lines, visiblelines;
2253
2254int currentline=0;
2255int cnt=0;
2256int offset=0;
2257
2258if( !title || !text )
2259return;
2260
2261position_t pos_title = pos ( gui.infobox.vborder, gui.infobox.vborder );
2262
2263// calculate number of lines in the title
2264for ( i = 0, lines = 1; i<strlen(title); i++ )
2265if( title[i] == '\n')
2266lines++;
2267
2268// y position of text is lines in title * height of font
2269position_t pos_text = pos( pos_title.x , pos_title.y + ( font_console.height * lines ));
2270
2271// calculate number of lines in the text
2272for ( i=0, lines = 1; i<strlen(text); i++ )
2273if( text[i] == '\n')
2274lines++;
2275
2276// if text ends with \n strip off
2277if( text[i] == '\n' || text[i] == '\0')
2278lines--;
2279
2280visiblelines = ( ( gui.infobox.height - ( gui.infobox.vborder * 2 ) ) / font_console.height ) - 1;
2281
2282// lets display the text and allow scroll thru using up down / arrows
2283while(1)
2284{
2285// move to current line in text
2286for( offset = 0, i = 0; offset < strlen(text); offset++ )
2287{
2288if( currentline == i)
2289break;
2290if( text[offset] =='\n')
2291i++;
2292}
2293
2294// find last visible line in text and place \0
2295for( i = offset, cnt = 0; i < strlen(text); i++)
2296{
2297if(text[i]=='\n')
2298cnt++;
2299if ( cnt == visiblelines )
2300{
2301text[i]='\0';
2302break;
2303}
2304}
2305
2306fillPixmapWithColor( gui.infobox.pixmap, gui.infobox.bgcolor);
2307
2308makeRoundedCorners( gui.infobox.pixmap);
2309
2310// print the title if present
2311if( title )
2312drawStr(title, &font_console, gui.infobox.pixmap, pos_title);
2313
2314// print the text
2315drawStr( text + offset, &font_console, gui.infobox.pixmap, pos_text);
2316
2317// restore \n in text
2318if ( cnt == visiblelines )
2319text[i] = '\n';
2320
2321position_t pos_indicator = pos( gui.infobox.width - ( images[iTextScrollPrev].image->width - ( gui.infobox.vborder / 2) ), pos_text.y );
2322
2323// draw prev indicator
2324if(offset)
2325{
2326blend( images[iTextScrollPrev].image, gui.infobox.pixmap, centeredAt( images[iTextScrollPrev].image, pos_indicator ));
2327}
2328
2329// draw next indicator
2330if( lines > ( currentline + visiblelines ) )
2331{
2332pos_indicator.y = ( gui.infobox.height - ( ( images[iTextScrollNext].image->width + gui.infobox.vborder ) / 2 ) );
2333blend( images[iTextScrollNext].image, gui.infobox.pixmap, centeredAt( images[iTextScrollNext].image, pos_indicator ) );
2334}
2335
2336gui.bootprompt.draw = false;
2337gui.infobox.draw = true;
2338gui.redraw = true;
2339
2340updateVRAM();
2341
2342key = getc();
2343
2344if( key == kUpArrowkey )
2345if( currentline > 0 )
2346currentline--;
2347
2348if( key == kDownArrowkey )
2349if( lines > ( currentline + visiblelines ) )
2350currentline++;
2351
2352if( key == kEscapeKey || key == 'q' || key == 'Q')
2353{
2354gui.infobox.draw = false;
2355gui.redraw = true;
2356updateVRAM();
2357break;
2358}
2359}
2360}
2361
2362static void animateProgressBar()
2363{
2364int y;
2365
2366if( time18() > (unsigned) lasttime)
2367{
2368lasttime = time18();
2369
2370pixmap_t *buffBar = images[iProgressBar].image;
2371
2372uint32_t buff = buffBar->pixels[0].value;
2373
2374memcpy( buffBar->pixels, buffBar->pixels + 1, ( (buffBar->width*buffBar->height) - 1 ) * 4 );
2375
2376for( y = buffBar->height - 1; y > 0; y--)
2377pixel(buffBar, buffBar->width - 1, y) = pixel(buffBar, buffBar->width - 1, y - 1);
2378
2379pixel(buffBar, buffBar->width-1, 0).value = buff;
2380}
2381}
2382
2383static void drawProgressBar(pixmap_t *blendInto, uint16_t width, position_t p, uint8_t progress)
2384{
2385if(progress>100)
2386return;
2387
2388p.x = ( p.x - ( width / 2 ) );
2389
2390int todraw = (width * progress) / 100;
2391
2392pixmap_t *buff = images[iProgressBar].image;
2393pixmap_t *buffBG = images[iProgressBarBackground].image;
2394if(!buff || !buffBG)
2395return;
2396
2397pixmap_t progressbar;
2398progressbar.pixels=malloc(width * 4 * buff->height);
2399if(!progressbar.pixels)
2400return;
2401
2402progressbar.width = width;
2403progressbar.height = buff->height;
2404
2405int x,x2,y;
2406
2407for(y=0; y<buff->height; y++)
2408{
2409for(x=0,x2=0; x<todraw; x++, x2++)
2410{
2411if(x2 == (buff->width-1)) x2=0;
2412pixel(&progressbar, x,y).value = pixel(buff, x2,y).value;
2413}
2414}
2415
2416for(y=0; y<buff->height; y++)
2417{
2418for(x=todraw, x2 = 0; x < width - 1; x++, x2++)
2419{
2420if(x2 == (buffBG->width -2 )) x2 = 0;
2421pixel(&progressbar, x,y).value = pixel(buffBG, x2,y).value;
2422}
2423if(progress < 100)
2424pixel(&progressbar, width - 1, y).value = pixel(buffBG, buffBG->width - 1, y).value;
2425if(progress == 0)
2426pixel(&progressbar, 0, y).value = pixel(buffBG, buffBG->width - 1, y).value;
2427}
2428
2429blend(&progressbar, blendInto, p);
2430animateProgressBar();
2431free(progressbar.pixels);
2432}
2433
2434static void drawInfoMenuItems()
2435{
2436int i,n;
2437
2438position_t position;
2439
2440pixmap_t *selection = images[iMenuSelection].image;
2441
2442pixmap_t *pbuff;
2443
2444fillPixmapWithColor(gui.menu.pixmap, gui.menu.bgcolor);
2445
2446makeRoundedCorners(gui.menu.pixmap);
2447
2448uint8_t offset = infoMenuNativeBoot ? 0 : infoMenuItemsCount - 1;
2449
2450position = pos(0,0);
2451
2452for ( i = 0, n = iMenuBoot; i < infoMenuItemsCount; i++, n++)
2453{
2454if (i == infoMenuSelection)
2455{
2456blend(selection, gui.menu.pixmap, position);
2457}
2458
2459pbuff = images[n].image;
2460if (offset && i >= INFOMENU_NATIVEBOOT_START && i <= INFOMENU_NATIVEBOOT_END)
2461{
2462blend( images[n + (iMenuHelp - iMenuBoot)].image , gui.menu.pixmap,
2463 pos((position.x + (gui.menu.hborder / 2)), position.y + ((selection->height - pbuff->height) / 2)));
2464}
2465else
2466{
2467blend( pbuff, gui.menu.pixmap,
2468 pos((position.x + (gui.menu.hborder / 2)), position.y + ((selection->height - pbuff->height) / 2)));
2469}
2470
2471drawStr(infoMenuItems[i].text, &font_console, gui.menu.pixmap,
2472pos(position.x + (pbuff->width + gui.menu.hborder),
2473position.y + ((selection->height - font_console.height) / 2)));
2474position.y += images[iMenuSelection].image->height;
2475
2476}
2477
2478gui.redraw = true;
2479}
2480
2481int drawInfoMenu()
2482{
2483drawInfoMenuItems();
2484
2485gui.menu.draw = true;
2486
2487updateVRAM();
2488
2489return 1;
2490}
2491
2492int updateInfoMenu(int key)
2493{
2494switch (key)
2495{
2496
2497case kUpArrowkey:// up arrow
2498if (infoMenuSelection > 0)
2499{
2500if(!infoMenuNativeBoot && infoMenuSelection == INFOMENU_NATIVEBOOT_END + 1)
2501{
2502infoMenuSelection -= 4;
2503}
2504else
2505{
2506infoMenuSelection--;
2507}
2508drawInfoMenuItems();
2509updateVRAM();
2510
2511}
2512else
2513{
2514
2515gui.menu.draw = false;
2516gui.redraw = true;
2517
2518updateVRAM();
2519
2520return CLOSE_INFO_MENU;
2521}
2522break;
2523
2524case kDownArrowkey:// down arrow
2525if (infoMenuSelection < infoMenuItemsCount - 1)
2526{
2527if(!infoMenuNativeBoot && infoMenuSelection == INFOMENU_NATIVEBOOT_START - 1)
2528infoMenuSelection += 4;
2529else
2530infoMenuSelection++;
2531drawInfoMenuItems();
2532updateVRAM();
2533}
2534break;
2535
2536case kReturnKey:
2537if( infoMenuSelection == MENU_SHOW_MEMORY_INFO )
2538showInfoBox( "Memory Info. Press q to quit.\n", getMemoryInfoString());
2539
2540else if( infoMenuSelection == MENU_SHOW_VIDEO_INFO )
2541showInfoBox( getVBEInfoString(), getVBEModeInfoString() );
2542
2543else if( infoMenuSelection == MENU_SHOW_HELP )
2544showHelp();
2545
2546else
2547{
2548int buff = infoMenuSelection;
2549infoMenuSelection = 0;
2550return buff;
2551}
2552break;
2553default:
2554break;
2555}
2556return DO_NOT_BOOT;
2557}
2558
2559uint16_t bootImageWidth = 0;
2560uint16_t bootImageHeight = 0;
2561uint8_t *bootImageData = NULL;
2562static bool usePngImage = false;
2563
2564//==========================================================================
2565// loadBootGraphics
2566static void loadBootGraphics(char *src)
2567{
2568if (bootImageData != NULL) {
2569return;
2570}
2571
2572char dirspec[256];
2573
2574if ((unsigned)(strlen(theme_name) + 34) > sizeof(dirspec)) {
2575usePngImage = false;
2576return;
2577}
2578sprintf(dirspec, "%s/%s/boot.png", src, theme_name);
2579if (strlen(theme_name) == 0 || loadPngImage(dirspec, &bootImageWidth, &bootImageHeight, &bootImageData) != 0) {
2580#ifdef EMBED_THEME
2581if ((loadEmbeddedPngImage(__boot_png, __boot_png_len, &bootImageWidth, &bootImageHeight, &bootImageData)) != 0)
2582#endif
2583usePngImage = false;
2584}
2585}
2586
2587//==========================================================================
2588// drawBootGraphics
2589void drawBootGraphics(void)
2590{
2591int pos;
2592int length;
2593const char *dummyVal;
2594int oldScreenWidth, oldScreenHeight;
2595uint16_t x, y;
2596bool legacy_logo = false;
2597getBoolForKey("Legacy Logo", &legacy_logo, DEFAULT_BOOT_CONFIG);
2598if (legacy_logo == false) {
2599usePngImage = true;
2600
2601if (bootImageData == NULL)
2602loadBootGraphics(dirsrc);
2603
2604}
2605
2606
2607if (execute_hook("getResolution_hook", &screen_params[0], &screen_params[1], &screen_params[2], NULL, NULL, NULL) != EFI_SUCCESS)
2608{
2609// parse screen size parameters
2610if (getIntForKey("boot_width", &pos, &themeConfig) && pos > 0) {
2611screen_params[0] = pos;
2612} else {
2613screen_params[0] = DEFAULT_SCREEN_WIDTH;
2614}
2615if (getIntForKey("boot_height", &pos, &themeConfig) && pos > 0) {
2616screen_params[1] = pos;
2617} else {
2618screen_params[1] = DEFAULT_SCREEN_HEIGHT;
2619}
2620}
2621
2622 // Save current screen resolution.
2623oldScreenWidth = gui.screen.width;
2624oldScreenHeight = gui.screen.height;
2625
2626gui.screen.width = screen_params[0];
2627gui.screen.height = screen_params[1];
2628
2629// find best matching vesa mode for our requested width & height
2630getGraphicModeParams(screen_params);
2631
2632 // Set graphics mode if the booter was in text mode or the screen resolution has changed.
2633if (getVideoMode() == VGA_TEXT_MODE
2634|| (screen_params[0] != (uint32_t)oldScreenWidth && screen_params[1] != (uint32_t)oldScreenHeight) )
2635{
2636
2637setVideoMode(GRAPHICS_MODE);
2638
2639}
2640
2641if (getValueForKey("-checkers", &dummyVal, &length, DEFAULT_BOOT_CONFIG)) {
2642drawCheckerBoard();
2643} else {
2644// Fill the background to 75% grey (same as BootX).
2645drawColorRectangle(0, 0, screen_params[0], screen_params[1], 0x01);
2646}
2647if ((bootImageData) && (usePngImage)) {
2648x = (screen_params[0] - MIN(bootImageWidth, screen_params[0])) / 2;
2649y = (screen_params[1] - MIN(bootImageHeight, screen_params[1])) / 2;
2650
2651// Draw the image in the center of the display.
2652blendImage(x, y, bootImageWidth, bootImageHeight, bootImageData);
2653} else {
2654uint8_t *appleBootPict;
2655bootImageData = NULL;
2656bootImageWidth = kAppleBootWidth;
2657bootImageHeight = kAppleBootHeight;
2658
2659// Prepare the data for the default Apple boot image.
2660appleBootPict = (uint8_t *) decodeRLE(gAppleBootPictRLE, kAppleBootRLEBlocks, bootImageWidth * bootImageHeight);
2661if (appleBootPict) {
2662if (convertImage(bootImageWidth, bootImageHeight, appleBootPict, &bootImageData) == 0)
2663 {
2664 if (bootImageData) {
2665 x = (screen_params[0] - MIN(kAppleBootWidth, screen_params[0])) / 2;
2666 y = (screen_params[1] - MIN(kAppleBootHeight, screen_params[1])) / 2;
2667 drawDataRectangle(x, y, kAppleBootWidth, kAppleBootHeight, bootImageData);
2668 free(bootImageData);
2669 }
2670 }
2671free(appleBootPict);
2672}
2673}
2674}
2675
2676int GUI_initGraphicsMode (void)
2677{
2678unsigned long params[4];
2679int count;
2680
2681params[3] = 0;
2682count = getNumberArrayFromProperty( kGraphicsModeKey, params, 4 );
2683
2684// Try to find a resolution if "Graphics Mode" setting is not available.
2685if ( count < 3 )
2686{
2687// Use the default resolution if we don't have an initialized GUI.
2688if (gui.screen.width == 0 || gui.screen.height == 0)
2689{
2690gui.screen.width = DEFAULT_SCREEN_WIDTH;
2691gui.screen.height = DEFAULT_SCREEN_HEIGHT;
2692}
2693
2694params[0] = gui.screen.width;
2695params[1] = gui.screen.height;
2696params[2] = 32;
2697}
2698
2699// Map from pixel format to bits per pixel.
2700
2701if ( params[2] == 256 ) params[2] = 8;
2702if ( params[2] == 555 ) params[2] = 16;
2703if ( params[2] == 888 ) params[2] = 32;
2704
2705return setVESAGraphicsMode( params[0], params[1], params[2] );
2706
2707}
2708
2709
2710int GUI_countdown( const char * msg, register int row, register int timeout , int *optionKey)
2711{
2712 register unsigned long time;
2713 int ch = 0;
2714 register int col = strlen(msg) + 1;
2715
2716 flushKeyboardBuffer();
2717
2718if( getVideoMode() == VGA_TEXT_MODE )
2719{
2720moveCursor( 0, row );
2721printf(msg);
2722
2723} else {
2724
2725position_t p = pos( gui.screen.width / 2 + 1 , ( gui.devicelist.pos.y + 3 ) + ( ( gui.devicelist.height - gui.devicelist.iconspacing ) / 2 ) );
2726
2727char dummy[80];
2728getBootVolumeDescription( ((BVRef)(uint32_t)get_env(envgBootVolume)), dummy, sizeof(dummy) - 1, true );
2729drawDeviceIcon( ((BVRef)(uint32_t)get_env(envgBootVolume)), gui.screen.pixmap, p, true );
2730drawStrCenteredAt( (char *) msg, &font_small, gui.screen.pixmap, gui.countdown.pos );
2731
2732// make this screen the new background
2733memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
2734
2735}
2736
2737int multi_buff = 18 * (timeout);
2738 int multi = ++multi_buff;
2739
2740 int lasttime=0;
2741
2742 for ( time = time18(), timeout++; timeout > 0; )
2743 {
2744
2745if( time18() > (unsigned)lasttime)
2746{
2747multi--;
2748lasttime=time18();
2749}
2750
2751 if ((ch = readKeyboardStatus())){
2752 *optionKey = ch;
2753 break;
2754}
2755
2756 // Count can be interrupted by holding down shift,
2757 // control or alt key
2758 if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 )
2759{
2760 ch = 1;
2761 break;
2762 }
2763
2764 if ( time18() >= time )
2765 {
2766 time += 18;
2767 timeout--;
2768
2769if( getVideoMode() == VGA_TEXT_MODE )
2770{
2771moveCursor( col, row );
2772printf("(%d) ", timeout);
2773}
2774 }
2775
2776if( getVideoMode() == GRAPHICS_MODE )
2777{
2778drawProgressBar( gui.screen.pixmap, 100, gui.progressbar.pos , ( multi * 100 / multi_buff ) );
2779gui.redraw = true;
2780updateVRAM();
2781}
2782
2783 }
2784
2785 flushKeyboardBuffer();
2786
2787 return ch;
2788}
2789

Archive Download this file

Revision: 1977