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

Archive Download this file

Revision: 2006