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

Archive Download this file

Revision: 2066