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
51jmp_buf uterror;
52
53// CoreHash Declarations
54__CHNewStrVar(themeList_t)
55CHUnInit(themeList_t)
56
57static void (*showHelp)(void) = NULL;
58static char *(*getMemoryInfoString)(void) = NULL;
59
60
61gui_t gui;// gui structure
62font_t font_small;
63font_t font_console;
64
65
66#define IMG_REQUIRED -1
67#define THEME_NAME_DEFAULT"Default"
68const char* theme_name = THEME_NAME_DEFAULT;
69
70#define MAX_THEMES 255
71
72struct themeList_t *gthemeList = NULL;
73static char tmp_theme[64]; // should be engouth
74
75char dirsrc[22];
76
77#ifdef EMBED_THEME
78#include "art.h"
79#endif
80
81
82static int loadThemeImage(char *src, const char *image, int alt_image);
83static void loadBootGraphics(char *src);
84static void drawInfoMenuItems();
85static void drawProgressBar(pixmap_t *blendInto, uint16_t width, position_t p, uint8_t progress);
86static void animateProgressBar();
87static void makeRoundedCorners(pixmap_t *p);
88static void colorFont(font_t *font, uint32_t color);
89static int initFont(font_t *font, image_t *data);
90static void drawStrCenteredAt(char *text, font_t *font, pixmap_t *blendInto, position_t p);
91static position_t drawChar(unsigned char ch, font_t *font, pixmap_t *blendInto, position_t p);
92static void drawStr(char *ch, font_t *font, pixmap_t *blendInto, position_t p);
93#if DEBUG_GUI
94static int dprintf( window_t * window, const char * fmt, ...);
95#endif
96
97static inline
98void vramwrite (void *data, int width);
99
100static void drawDeviceIcon(BVRef device, pixmap_t *buffer, position_t p, bool isSelected);
101static int startGUI(void);
102static void free_theme_list();
103static void add_theme(const char* theme, uint8_t nb);
104static int randomTheme(char *dirspec, const char **theme);
105static void loadThemeValues(config_file_t *theme);
106static void setupDeviceList(config_file_t *theme);
107static void fillPixmapWithColor(pixmap_t *pm, uint32_t color);
108static int freeWindowBuffer( window_t *window );
109static int createWindowBuffer( window_t *window );
110static int createBackBuffer( window_t *window );
111static int loadGraphics(char *src);
112#ifdef EMBED_THEME
113static int getEmbeddedImageIndexByName(const char *name);
114#endif
115static int getImageIndexByName(const char *name);
116
117static int destroyFont(font_t *font);
118static int unloadGraphics(void);
119static int freeBackBuffer( window_t *window );
120static bool is_image_loaded(int i);
121static bool GUI_getDimensionForKey( const char *key, unsigned int *value, config_file_t *config, unsigned int dimension_max, unsigned int object_size );
122static bool GUI_getColorForKey( const char *key, unsigned int *value, config_file_t *config );
123
124#define LOADPNG(src, img, alt_img) if (loadThemeImage(src, #img, alt_img) != 0) { return 1; }
125
126#ifndef MIN
127#define MIN(x, y) ((x) < (y) ? (x) : (y))
128#endif
129
130#ifndef MAX
131#define MAX(x, y) ((x) > (y) ? (x) : (y))
132#endif
133
134#define VIDEO(x) (((boot_args*)getBootArgs())->Video.v_ ## x)
135
136#define vram VIDEO(baseAddr)
137
138#define TAB_PIXELS_WIDTH (font->chars[0]->width * 4) // tab = 4 spaces
139
140int lasttime = 0; // we need this for animating maybe
141
142/*
143 * ATTENTION: the enum and the following array images[] MUST match !!!
144 */
145enum {
146 iBackground = 0,
147 iLogo,
148
149 iDeviceGeneric,
150 iDeviceGeneric_o,
151 iDeviceHFS,
152 iDeviceHFS_o,
153 iDeviceHFS_ML,
154 iDeviceHFS_ML_o,
155iDeviceHFS_Lion,
156 iDeviceHFS_Lion_o,
157iDeviceHFS_SL,
158 iDeviceHFS_SL_o,
159iDeviceHFS_Leo,
160 iDeviceHFS_Leo_o,
161iDeviceHFS_Tiger,
162 iDeviceHFS_Tiger_o,
163 iDeviceHFSRAID,
164 iDeviceHFSRAID_o,
165 iDeviceHFSRAID_ML,
166 iDeviceHFSRAID_ML_o,
167iDeviceHFSRAID_Lion,
168 iDeviceHFSRAID_Lion_o,
169iDeviceHFSRAID_SL,
170 iDeviceHFSRAID_SL_o,
171iDeviceHFSRAID_Leo,
172 iDeviceHFSRAID_Leo_o,
173iDeviceHFSRAID_Tiger,
174 iDeviceHFSRAID_Tiger_o,
175 iDeviceEXT3,
176 iDeviceEXT3_o,
177iDeviceFreeBSD,
178 iDeviceFreeBSD_o,
179 iDeviceOpenBSD,
180 iDeviceOpenBSD_o,
181iDeviceBEFS, /* Haiku detection and Icon credits to scorpius */
182iDeviceBEFS_o, /* Haiku detection and Icon credits to scorpius */
183 iDeviceFAT,
184 iDeviceFAT_o,
185 iDeviceFAT16,
186 iDeviceFAT16_o,
187 iDeviceFAT32,
188 iDeviceFAT32_o,
189 iDeviceNTFS,
190 iDeviceNTFS_o,
191 iDeviceCDROM,
192 iDeviceCDROM_o,
193
194 iSelection,
195 iDeviceScrollPrev,
196 iDeviceScrollNext,
197
198 iMenuBoot,
199 iMenuVerbose,
200 iMenuIgnoreCaches,
201 iMenuSingleUser,
202 iMenuMemoryInfo,
203 iMenuVideoInfo,
204 iMenuHelp,
205 iMenuVerboseDisabled,
206 iMenuIgnoreCachesDisabled,
207 iMenuSingleUserDisabled,
208 iMenuSelection,
209
210 iProgressBar,
211 iProgressBarBackground,
212
213 iTextScrollPrev,
214 iTextScrollNext,
215
216 iFontConsole,
217 iFontSmall,
218};
219
220image_t images[] = {
221 {.name = "background", .image = NULL},
222 {.name = "logo", .image = NULL},
223
224 {.name = "device_generic", .image = NULL},
225 {.name = "device_generic_o", .image = NULL},
226
227{.name = "device_hfsplus", .image = NULL},
228 {.name = "device_hfsplus_o", .image = NULL},
229{.name = "device_hfsplus_ml", .image = NULL},
230 {.name = "device_hfsplus_ml_o", .image = NULL},
231{.name = "device_hfsplus_lion", .image = NULL},
232 {.name = "device_hfsplus_lion_o", .image = NULL},
233{.name = "device_hfsplus_sl", .image = NULL},
234 {.name = "device_hfsplus_sl_o", .image = NULL},
235{.name = "device_hfsplus_leo", .image = NULL},
236 {.name = "device_hfsplus_leo_o", .image = NULL},
237{.name = "device_hfsplus_tiger", .image = NULL},
238 {.name = "device_hfsplus_tiger_o", .image = NULL},
239
240 {.name = "device_hfsraid", .image = NULL},
241 {.name = "device_hfsraid_o", .image = NULL},
242 {.name = "device_hfsraid_ml", .image = NULL},
243 {.name = "device_hfsraid_ml_o", .image = NULL},
244{.name = "device_hfsraid_lion", .image = NULL},
245 {.name = "device_hfsraid_lion_o", .image = NULL},
246{.name = "device_hfsraid_sl", .image = NULL},
247 {.name = "device_hfsraid_sl_o", .image = NULL},
248{.name = "device_hfsraid_leo", .image = NULL},
249 {.name = "device_hfsraid_leo_o", .image = NULL},
250{.name = "device_hfsraid_tiger", .image = NULL},
251 {.name = "device_hfsraid_tiger_o", .image = NULL},
252
253 {.name = "device_ext3", .image = NULL},
254 {.name = "device_ext3_o", .image = NULL},
255{.name = "device_freebsd", .image = NULL},
256 {.name = "device_freebsd_o", .image = NULL},
257 {.name = "device_openbsd", .image = NULL},
258 {.name = "device_openbsd_o", .image = NULL},
259{.name = "device_befs", .image = NULL}, /* Haiku detection and Icon credits to scorpius */
260{.name = "device_befs_o", .image = NULL}, /* Haiku detection and Icon credits to scorpius */
261 {.name = "device_fat", .image = NULL},
262 {.name = "device_fat_o", .image = NULL},
263 {.name = "device_fat16", .image = NULL},
264 {.name = "device_fat16_o", .image = NULL},
265 {.name = "device_fat32", .image = NULL},
266 {.name = "device_fat32_o", .image = NULL},
267 {.name = "device_ntfs", .image = NULL},
268 {.name = "device_ntfs_o", .image = NULL},
269 {.name = "device_cdrom", .image = NULL},
270 {.name = "device_cdrom_o", .image = NULL},
271
272 {.name = "device_selection", .image = NULL},
273 {.name = "device_scroll_prev", .image = NULL},
274 {.name = "device_scroll_next", .image = NULL},
275
276 {.name = "menu_boot", .image = NULL},
277 {.name = "menu_verbose", .image = NULL},
278 {.name = "menu_ignore_caches", .image = NULL},
279 {.name = "menu_single_user", .image = NULL},
280 {.name = "menu_memory_info", .image = NULL},
281 {.name = "menu_video_info", .image = NULL},
282 {.name = "menu_help", .image = NULL},
283 {.name = "menu_verbose_disabled", .image = NULL},
284 {.name = "menu_ignore_caches_disabled", .image = NULL},
285 {.name = "menu_single_user_disabled", .image = NULL},
286 {.name = "menu_selection", .image = NULL},
287
288 {.name = "progress_bar", .image = NULL},
289 {.name = "progress_bar_background", .image = NULL},
290
291 {.name = "text_scroll_prev", .image = NULL},
292 {.name = "text_scroll_next", .image = NULL},
293
294 {.name = "font_console", .image = NULL},
295 {.name = "font_small", .image = NULL},
296};
297
298//int imageCnt = 0;
299
300char prompt[BOOT_STRING_LEN];
301
302int prompt_pos=0;
303
304char prompt_text[] = "boot: ";
305
306menuitem_t infoMenuItems[] =
307{
308{ .text = "Boot" },
309{ .text = "Boot Verbose" },
310{ .text = "Boot Ignore Caches" },
311{ .text = "Boot Single User" },
312{ .text = "Memory Info" },
313{ .text = "Video Info" },
314{ .text = "Help" }
315};
316
317int infoMenuSelection = 0;
318int infoMenuItemsCount = sizeof(infoMenuItems)/sizeof(infoMenuItems[0]);
319
320bool infoMenuNativeBoot = false;
321
322unsigned long screen_params[4] = {DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT, 32, 0};// here we store the used screen resolution
323
324static void moveCursor( int col, int row )
325{
326 setCursorPosition( col, row, 0 );
327}
328
329/*
330 *
331 */
332
333static bool GUI_getDimensionForKey( const char *key, unsigned int *value, config_file_t *config, unsigned int dimension_max, unsigned int object_size )
334{
335const char *val;
336
337 int size = 0;
338int sum = 0;
339
340bool negative = false;
341bool percentage = false;
342
343 config = resolveConfig(config);
344
345 if (getValueForKey(key, &val, &size, config))
346{
347if ( size )
348{
349if (*val == '-')
350{
351negative = true;
352val++;
353size--;
354}
355
356if (val[size-1] == '%')
357{
358percentage = true;
359size--;
360}
361
362// convert string to integer
363for (sum = 0; size > 0; size--)
364{
365if (*val < '0' || *val > '9')
366return false;
367
368sum = (sum * 10) + (*val++ - '0');
369}
370
371if (percentage)
372sum = ( dimension_max * sum ) / 100;
373
374// calculate offset from opposite origin
375if (negative)
376sum = ( ( dimension_max - object_size ) - sum );
377
378} else {
379
380// null value calculate center
381sum = ( dimension_max - object_size ) / 2;
382
383}
384
385*value = (uint16_t) sum;
386return true;
387}
388
389// key not found
390 return false;
391}
392
393static bool GUI_getColorForKey( const char *key, unsigned int *value, config_file_t *config )
394{
395 const char *val;
396 int size;
397
398 config = resolveConfig(config);
399
400 if (getValueForKey(key, &val, &size, config))
401{
402if (*val == '#')
403{
404 val++;
405*value = strtol(val, NULL, 16);
406return true;
407 }
408 }
409 return false;
410}
411//==========================================================================
412
413/* Flush keyboard buffer; returns TRUE if any of the flushed
414 * characters was F8.
415 */
416
417static bool flushKeyboardBuffer(void)
418{
419 bool status = false;
420
421 while ( readKeyboardStatus() ) {
422 if (bgetc() == 0x4200) status = true;
423 }
424 return status;
425}
426
427static int getImageIndexByName(const char *name)
428{
429 int i;
430for (i = 0; (unsigned)i < sizeof(images) / sizeof(images[0]); i++)
431{
432 if (strncmp(name, images[i].name, sizeof(images[i].name)) == 0)
433 return i; // found the name
434}
435return -1;
436}
437
438#ifdef EMBED_THEME
439static int getEmbeddedImageIndexByName(const char *name)
440{
441int upperLimit = sizeof(embeddedImages) / sizeof(embeddedImages[0]) - 1;
442int lowerLimit = 0;
443int compareIndex = (upperLimit - lowerLimit) >> 1; // Midpoint
444int result;
445
446// NOTE: This algorithm assumes that the embeddedImages is sorted.
447// This is currently done using the make file. If the array is every
448// manualy generated, this *will* fail to work properly.
449while((result = strncmp(name, embeddedImages[compareIndex].name, sizeof(embeddedImages[compareIndex].name))) != 0)
450{
451if(result > 0)// We need to search a HIGHER index
452{
453if(compareIndex != lowerLimit)
454{
455lowerLimit = compareIndex;
456}
457else
458{
459return -1;
460}
461compareIndex = (upperLimit + lowerLimit + 1) >> 1;// Midpoint, round up
462}
463else // We Need to search a LOWER index
464{
465if(compareIndex != upperLimit)
466{
467upperLimit = compareIndex;
468}
469else
470{
471return -1;
472}
473compareIndex = (upperLimit + lowerLimit) >> 1;// Midpoint, round down
474}
475}
476return compareIndex;
477}
478#endif
479
480static int loadThemeImage(char* src, const char *image, int alt_image)
481{
482chardirspec[256];
483int i;
484#ifdef EMBED_THEME
485int e;
486#endif
487uint16_twidth;
488uint16_theight;
489uint8_t*imagedata;
490if ((unsigned)(strlen(image) + strlen(theme_name) + strlen(src) + (6+1) ) > sizeof(dirspec)) {
491
492DBG("Path of %s/%s/%s.png to long\n", src, theme_name, image);
493
494return 1;
495}
496
497 if ((i = getImageIndexByName(image)) >= 0)
498 {
499if (images[i].image == NULL) {
500images[i].image = malloc(sizeof(pixmap_t));
501if (images[i].image == NULL) {
502
503DBG("Unable to allocate memory for %s.png\n", image);
504
505return 1;
506}
507}
508 snprintf(dirspec, sizeof(dirspec),"%s/%s/%s.png", src, theme_name, image);
509
510 width = 0;
511 height = 0;
512 imagedata = NULL;
513 if ((strlen(theme_name) > 0) && (loadPngImage(dirspec, &width, &height, &imagedata) != -1 ))
514 {
515 images[i].image->width = width;
516 images[i].image->height = height;
517 images[i].image->pixels = (pixel_t *)imagedata;
518 flipRB(images[i].image);
519
520DBG("[ %s ] succesfully loaded and registred !!\n", dirspec);
521DBG("width = %d : height = %d !!\n",images[i].image->width,images[i].image->height);
522
523 return 0;
524 }
525#ifdef EMBED_THEME
526 else if ((e = getEmbeddedImageIndexByName(image)) >= 0)
527 {
528 unsigned char *embed_data;
529 unsigned int embed_size;
530 embed_data = embeddedImages[e].pngdata;
531 embed_size = *embeddedImages[e].length;
532
533 if (loadEmbeddedPngImage(embed_data, embed_size, &width, &height, &imagedata) != -1)
534 {
535 images[i].image->width = width;
536 images[i].image->height = height;
537 images[i].image->pixels = (pixel_t *)imagedata;
538 flipRB(images[i].image);
539 return 0;
540 }
541
542 return 0;
543 }
544#endif
545 else if (alt_image != IMG_REQUIRED)
546 {
547if (images[alt_image].image->pixels != NULL) {
548
549// Using the passed alternate image for non-mandatory images.
550// We don't clone the already existing pixmap, but using its properties instead!
551images[i].image->width = images[alt_image].image->width;
552images[i].image->height = images[alt_image].image->height;
553images[i].image->pixels = images[alt_image].image->pixels;
554
555DBG("Passing to alt_image !!\n");
556DBG("width = %d : height = %d !!\n",images[alt_image].image->width,images[alt_image].image->height);
557
558} else {
559
560DBG("Unable to load %s, this image not vital anyway, reseting and returning success !!\n", dirspec);
561
562free(images[i].image);
563images[i].image = NULL;
564}
565
566 return 0;
567 }
568 else
569 {
570#if DEBUG_GUI
571 printf("ERROR: GUI: could not open '%s/%s.png'!\n", theme_name, image);
572sleep(2);
573#else
574#ifndef CONFIG_EMBED_THEME
575 printf("ERROR: GUI: could not open '%s/%s.png'!\n", theme_name, image);
576sleep(2);
577#endif
578#endif
579free(images[i].image);
580images[i].image = NULL;
581return 1;
582
583 }
584
585 }
586
587#if DEBUG_GUI
588printf("[ %s/%s/%s.png ] not used in this version, skipped !!\n",src, theme_name, image);
589sleep(2);
590#endif
591return 0;
592}
593
594static int loadGraphics(char *src)
595{
596DBG("Loading image into memory....\n",theme_name);
597
598LOADPNG(src, background, IMG_REQUIRED);
599
600LOADPNG(src, logo, IMG_REQUIRED);
601
602LOADPNG(src, device_generic, IMG_REQUIRED);
603LOADPNG(src, device_generic_o, iDeviceGeneric);
604
605LOADPNG(src, device_hfsplus, iDeviceGeneric);
606LOADPNG(src, device_hfsplus_o, iDeviceHFS);
607 LOADPNG(src, device_hfsplus_ml, iDeviceHFS_ML);
608 LOADPNG(src, device_hfsplus_ml_o, iDeviceHFS_ML_o);
609LOADPNG(src, device_hfsplus_lion, iDeviceHFS_Lion);
610LOADPNG(src, device_hfsplus_lion_o, iDeviceHFS_Lion_o);
611LOADPNG(src, device_hfsplus_sl, iDeviceHFS_SL);
612LOADPNG(src, device_hfsplus_sl_o, iDeviceHFS_SL_o);
613LOADPNG(src, device_hfsplus_leo, iDeviceHFS_Leo);
614LOADPNG(src, device_hfsplus_leo_o, iDeviceHFS_Leo_o);
615LOADPNG(src, device_hfsplus_tiger, iDeviceHFS_Tiger);
616LOADPNG(src, device_hfsplus_tiger_o, iDeviceHFS_Tiger_o);
617
618LOADPNG(src, device_hfsraid, iDeviceGeneric);
619LOADPNG(src, device_hfsraid_o, iDeviceHFSRAID);
620 LOADPNG(src, device_hfsraid_ml, iDeviceHFSRAID_ML);
621 LOADPNG(src, device_hfsraid_ml_o, iDeviceHFSRAID_ML_o);
622LOADPNG(src, device_hfsraid_lion, iDeviceHFSRAID_Lion);
623LOADPNG(src, device_hfsraid_lion_o, iDeviceHFSRAID_Lion_o);
624LOADPNG(src, device_hfsraid_sl, iDeviceHFSRAID_SL);
625LOADPNG(src, device_hfsraid_sl_o, iDeviceHFSRAID_SL_o);
626LOADPNG(src, device_hfsraid_leo, iDeviceHFSRAID_Leo);
627LOADPNG(src, device_hfsraid_leo_o, iDeviceHFSRAID_Leo_o);
628LOADPNG(src, device_hfsraid_tiger, iDeviceHFSRAID_Tiger);
629LOADPNG(src, device_hfsraid_tiger_o, iDeviceHFSRAID_Tiger_o);
630
631LOADPNG(src, device_ext3, iDeviceGeneric);
632LOADPNG(src, device_ext3_o, iDeviceEXT3);
633LOADPNG(src, device_freebsd, iDeviceGeneric);
634LOADPNG(src, device_freebsd_o, iDeviceFreeBSD);
635LOADPNG(src, device_openbsd, iDeviceGeneric);
636LOADPNG(src, device_openbsd_o, iDeviceOpenBSD);
637LOADPNG(src, device_befs, iDeviceGeneric); /* Haiku detection and Icon credits to scorpius */
638LOADPNG(src, device_befs_o, iDeviceBEFS); /* Haiku detection and Icon credits to scorpius */
639LOADPNG(src, device_fat, iDeviceGeneric);
640LOADPNG(src, device_fat_o, iDeviceFAT);
641LOADPNG(src, device_fat16, iDeviceFAT);
642LOADPNG(src, device_fat16_o, iDeviceFAT_o);
643LOADPNG(src, device_fat32, iDeviceFAT);
644LOADPNG(src, device_fat32_o, iDeviceFAT_o);
645LOADPNG(src, device_ntfs, iDeviceGeneric);
646LOADPNG(src, device_ntfs_o, iDeviceNTFS);
647LOADPNG(src, device_cdrom, iDeviceGeneric);
648LOADPNG(src, device_cdrom_o, iDeviceCDROM);
649
650LOADPNG(src, device_selection, IMG_REQUIRED);
651LOADPNG(src, device_scroll_prev, IMG_REQUIRED);
652LOADPNG(src, device_scroll_next, IMG_REQUIRED);
653
654LOADPNG(src, menu_boot, IMG_REQUIRED);
655LOADPNG(src, menu_verbose, IMG_REQUIRED);
656LOADPNG(src, menu_ignore_caches, IMG_REQUIRED);
657LOADPNG(src, menu_single_user, IMG_REQUIRED);
658LOADPNG(src, menu_memory_info, IMG_REQUIRED);
659LOADPNG(src, menu_video_info, IMG_REQUIRED);
660LOADPNG(src, menu_help, IMG_REQUIRED);
661LOADPNG(src, menu_verbose_disabled, IMG_REQUIRED);
662LOADPNG(src, menu_ignore_caches_disabled, IMG_REQUIRED);
663LOADPNG(src, menu_single_user_disabled, IMG_REQUIRED);
664LOADPNG(src, menu_selection, IMG_REQUIRED);
665
666LOADPNG(src, progress_bar, IMG_REQUIRED);
667LOADPNG(src, progress_bar_background, IMG_REQUIRED);
668
669LOADPNG(src, text_scroll_prev, IMG_REQUIRED);
670LOADPNG(src, text_scroll_next, IMG_REQUIRED);
671
672LOADPNG(src, font_console, IMG_REQUIRED);
673LOADPNG(src, font_small, IMG_REQUIRED);
674
675DBG("Initializing font....\n",theme_name);
676
677initFont( &font_console, &images[iFontConsole]);
678initFont( &font_small, &images[iFontSmall]);
679
680DBG("Graphic objects successfully loaded !!\n",theme_name);
681
682return 0;
683}
684
685static int unloadGraphics(void)
686{
687 int i;
688
689 destroyFont(&font_console);
690 destroyFont(&font_small);
691for (i = 0; i < sizeof(images) / sizeof(images[0]); i++)
692{
693 if (images[i].image)
694 {
695 if (images[i].image->pixels) free(images[i].image->pixels);
696 free (images[i].image);
697 images[i].image = 0;
698 }
699}
700return 0;
701}
702
703static int freeBackBuffer( window_t *window )
704{
705if (gui.backbuffer && gui.backbuffer->pixels)
706 {
707free(gui.backbuffer->pixels);
708free(gui.backbuffer);
709gui.backbuffer = 0;
710return 0;
711}
712
713return 1;
714}
715
716#if UNUSED
717pixmap_t *getCroppedPixmapAtPosition( pixmap_t *from, position_t pos, uint16_t width, uint16_t height )
718{
719
720pixmap_t *cropped = malloc( sizeof( pixmap_t ) );
721if( !cropped )
722return 0;
723cropped->pixels = malloc( width * height * 4 );
724if ( !cropped->pixels )
725return 0;
726
727cropped->width = width;
728cropped->height = height;
729
730int destx = 0, desty = 0;
731int srcx = pos.x, srcy = pos.y;
732
733for( ; desty < height; desty++, srcy++)
734{
735for( destx = 0, srcx = pos.x; destx < width; destx++, srcx++ )
736{
737pixel( cropped, destx, desty ).value = pixel( from, srcx, srcy ).value;
738}
739}
740return cropped;
741}
742#endif
743
744static int createBackBuffer( window_t *window )
745{
746gui.backbuffer = malloc(sizeof(pixmap_t));
747if(!gui.backbuffer)
748{
749DBG("Unable to allocate memory for gui.backbuffer");
750return 1;
751}
752
753gui.backbuffer->pixels = malloc( window->width * window->height * 4 );
754if(!gui.backbuffer->pixels)
755{
756free(gui.backbuffer);
757gui.backbuffer = 0;
758DBG("Unable to allocate memory for gui.backbuffer->pixels");
759return 1;
760}
761
762gui.backbuffer->width = gui.screen.width;
763gui.backbuffer->height = gui.screen.height;
764
765return 0;
766}
767
768static int createWindowBuffer( window_t *window )
769{
770window->pixmap = malloc(sizeof(pixmap_t));
771if(!window->pixmap)
772{
773DBG("Unable to allocate memory for window->pixmap");
774return 1;
775}
776
777window->pixmap->pixels = malloc( window->width * window->height * 4 );
778if(!window->pixmap->pixels)
779{
780free(window->pixmap);
781window->pixmap = 0;
782DBG("Unable to allocate memory for window->pixmap->pixels");
783return 1;
784}
785
786window->pixmap->width = window->width;
787window->pixmap->height = window->height;
788
789return 0;
790}
791
792static int freeWindowBuffer( window_t *window )
793{
794if (window->pixmap && window->pixmap->pixels)
795 {
796free(window->pixmap->pixels);
797free(window->pixmap);
798return 0;
799}
800
801return 1;
802}
803
804static void fillPixmapWithColor(pixmap_t *pm, uint32_t color)
805{
806int x,y;
807
808// fill with given color AARRGGBB
809for( x=0; x < pm->width; x++ )
810for( y=0; y< pm->height; y++)
811pixel(pm,x,y).value = color;
812}
813
814void drawBackground()
815{
816// reset text cursor
817gui.screen.cursor.x = gui.screen.hborder;
818gui.screen.cursor.y = gui.screen.vborder;
819
820fillPixmapWithColor( gui.screen.pixmap, gui.screen.bgcolor);
821
822// draw background.png into background buffer
823blend( images[iBackground].image, gui.screen.pixmap, gui.background.pos );
824
825// draw logo.png into background buffer
826if (gui.logo.draw)
827{
828 blend( images[iLogo].image, gui.screen.pixmap, gui.logo.pos);
829}
830
831memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
832}
833
834static void setupDeviceList(config_file_t *theme)
835{
836unsigned int pixel;
837intalpha;// transparency level 0 (obligue) - 255 (transparent)
838uint32_t color;// color value formatted RRGGBB
839int val, len;
840const char *string;
841 int devcnt = (int)get_env(envgDeviceCount);
842
843if(getIntForKey("devices_max_visible", &val, theme ))
844gui.maxdevices = MIN( val, devcnt );
845
846if(getIntForKey("devices_iconspacing", &val, theme ))
847gui.devicelist.iconspacing = val;
848
849// check layout for horizontal or vertical
850gui.layout = HorizontalLayout;
851if(getValueForKey( "devices_layout", &string, &len, theme)) {
852if (!strncmp (string, "vertical",sizeof("vertical"))) {
853gui.layout = VerticalLayout;
854}
855}
856
857switch (gui.layout) {
858case VerticalLayout:
859gui.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);
860gui.devicelist.width = (images[iSelection].image->width + gui.devicelist.iconspacing);
861
862if(GUI_getDimensionForKey("devices_pos_x", &pixel, theme, gui.screen.width , images[iSelection].image->width ) )
863gui.devicelist.pos.x = pixel;
864
865if(GUI_getDimensionForKey("devices_pos_y", &pixel, theme, gui.screen.height , gui.devicelist.height ) )
866gui.devicelist.pos.y = pixel;
867break;
868
869case HorizontalLayout:
870default:
871gui.devicelist.width = ((images[iSelection].image->width + gui.devicelist.iconspacing) * MIN(gui.maxdevices, devcnt) + (images[iDeviceScrollPrev].image->width + images[iDeviceScrollNext].image->width) + gui.devicelist.iconspacing);
872gui.devicelist.height = (images[iSelection].image->height + font_console.chars[0]->height + gui.devicelist.iconspacing);
873
874if(GUI_getDimensionForKey("devices_pos_x", &pixel, theme, gui.screen.width , gui.devicelist.width ) )
875gui.devicelist.pos.x = pixel;
876else
877gui.devicelist.pos.x = ( gui.screen.width - gui.devicelist.width ) / 2;
878
879if(GUI_getDimensionForKey("devices_pos_y", &pixel, theme, gui.screen.height , images[iSelection].image->height ) )
880gui.devicelist.pos.y = pixel;
881else
882gui.devicelist.pos.y = ( gui.screen.height - gui.devicelist.height ) / 2;
883break;
884}
885
886if(GUI_getColorForKey("devices_bgcolor", &color, theme))
887gui.devicelist.bgcolor = (color & 0x00FFFFFF);
888
889if(getIntForKey("devices_transparency", &alpha, theme))
890gui.devicelist.bgcolor = gui.devicelist.bgcolor | (( 255 - ( alpha & 0xFF) ) << 24);
891
892if (gui.devicelist.pixmap)
893{
894 freeWindowBuffer(&gui.devicelist);
895 createWindowBuffer(&gui.devicelist);
896 }
897}
898
899static void loadThemeValues(config_file_t *theme)
900{
901unsigned int screen_width = gui.screen.width;
902unsigned int screen_height = gui.screen.height;
903unsigned int pixel;
904intalpha;// transparency level 0 (obligue) - 255 (transparent)
905uint32_t color;// color value formatted RRGGBB
906int val;
907
908/*
909 * Parse screen parameters
910 */
911if(GUI_getColorForKey("screen_bgcolor", &color, theme ))
912gui.screen.bgcolor = (color & 0x00FFFFFF);
913
914if(getIntForKey("screen_textmargin_h", &val, theme))
915gui.screen.hborder = MIN( gui.screen.width , val );
916
917if(getIntForKey("screen_textmargin_v", &val, theme))
918gui.screen.vborder = MIN( gui.screen.height , val );
919
920/*
921 * Parse background parameters
922 */
923if(GUI_getDimensionForKey("background_pos_x", &pixel, theme, screen_width , images[iBackground].image->width ) )
924gui.background.pos.x = pixel;
925
926if(GUI_getDimensionForKey("background_pos_y", &pixel, theme, screen_height , images[iBackground].image->height ) )
927gui.background.pos.y = pixel;
928
929/*
930 * Parse logo parameters
931 */
932if(GUI_getDimensionForKey("logo_pos_x", &pixel, theme, screen_width , images[iLogo].image->width ) )
933gui.logo.pos.x = pixel;
934
935if(GUI_getDimensionForKey("logo_pos_y", &pixel, theme, screen_height , images[iLogo].image->height ) )
936gui.logo.pos.y = pixel;
937
938/*
939 * Parse progress bar parameters
940 */
941if(GUI_getDimensionForKey("progressbar_pos_x", &pixel, theme, screen_width , 0 ) )
942gui.progressbar.pos.x = pixel;
943
944if(GUI_getDimensionForKey("progressbar_pos_y", &pixel, theme, screen_height , 0 ) )
945gui.progressbar.pos.y = pixel;
946
947/*
948 * Parse countdown text parameters
949 */
950if(GUI_getDimensionForKey("countdown_pos_x", &pixel, theme, screen_width , 0 ) )
951gui.countdown.pos.x = pixel;
952
953if(GUI_getDimensionForKey("countdown_pos_y", &pixel, theme, screen_height , 0 ) )
954gui.countdown.pos.y = pixel;
955
956 /*
957 * Parse devicelist parameters
958 */
959setupDeviceList(theme);
960
961/*
962 * Parse infobox parameters
963 */
964if(getIntForKey("infobox_width", &val, theme) && val >= 0)
965gui.infobox.width = MIN( screen_width ,(unsigned) val );
966
967if(getIntForKey("infobox_height", &val, theme) && val >= 0)
968gui.infobox.height = MIN( screen_height , (unsigned)val );
969
970if(GUI_getDimensionForKey("infobox_pos_x", &pixel, theme, screen_width , gui.infobox.width ) )
971gui.infobox.pos.x = pixel;
972
973if(GUI_getDimensionForKey("infobox_pos_y", &pixel, theme, screen_height , gui.infobox.height ) )
974gui.infobox.pos.y = pixel;
975
976if(getIntForKey("infobox_textmargin_h", &val, theme))
977gui.infobox.hborder = MIN( gui.infobox.width , val );
978
979if(getIntForKey("infobox_textmargin_v", &val, theme))
980gui.infobox.vborder = MIN( gui.infobox.height , val );
981
982if(GUI_getColorForKey("infobox_bgcolor", &color, theme))
983gui.infobox.bgcolor = (color & 0x00FFFFFF);
984
985if(getIntForKey("infobox_transparency", &alpha, theme))
986gui.infobox.bgcolor = gui.infobox.bgcolor | (( 255 - ( alpha & 0xFF) ) << 24);
987
988/*
989 * Parse menu parameters
990 */
991if(GUI_getDimensionForKey("menu_width", &pixel, theme, gui.screen.width , 0 ) )
992gui.menu.width = pixel;
993else
994gui.menu.width = images[iMenuSelection].image->width;
995
996if(GUI_getDimensionForKey("menu_height", &pixel, theme, gui.screen.height , 0 ) )
997gui.menu.height = pixel;
998else
999gui.menu.height = infoMenuItemsCount * images[iMenuSelection].image->height;
1000
1001if(GUI_getDimensionForKey("menu_pos_x", &pixel, theme, screen_width , gui.menu.width ) )
1002gui.menu.pos.x = pixel;
1003
1004if(GUI_getDimensionForKey("menu_pos_y", &pixel, theme, screen_height , gui.menu.height ) )
1005gui.menu.pos.y = pixel;
1006
1007if(getIntForKey("menu_textmargin_h", &val, theme))
1008gui.menu.hborder = MIN( gui.menu.width , val );
1009
1010if(getIntForKey("menu_textmargin_v", &val, theme))
1011gui.menu.vborder = MIN( gui.menu.height , val );
1012
1013if(GUI_getColorForKey("menu_bgcolor", &color, theme))
1014gui.menu.bgcolor = (color & 0x00FFFFFF);
1015
1016if(getIntForKey("menu_transparency", &alpha, theme))
1017gui.menu.bgcolor = gui.menu.bgcolor | (( 255 - ( alpha & 0xFF) ) << 24);
1018
1019/*
1020 * Parse bootprompt parameters
1021 */
1022if(GUI_getDimensionForKey("bootprompt_width", &pixel, theme, screen_width , 0 ) )
1023gui.bootprompt.width = pixel;
1024
1025if(getIntForKey("bootprompt_height", &val, theme) && val >= 0)
1026gui.bootprompt.height = MIN( screen_height , (unsigned)val );
1027
1028if(GUI_getDimensionForKey("bootprompt_pos_x", &pixel, theme, screen_width , gui.bootprompt.width ) )
1029gui.bootprompt.pos.x = pixel;
1030
1031if(GUI_getDimensionForKey("bootprompt_pos_y", &pixel, theme, screen_height , gui.bootprompt.height ) )
1032gui.bootprompt.pos.y = pixel;
1033
1034if(getIntForKey("bootprompt_textmargin_h", &val, theme) && val >= 0)
1035gui.bootprompt.hborder = MIN( gui.bootprompt.width , (unsigned)val );
1036
1037if(getIntForKey("bootprompt_textmargin_v", &val, theme) && val >= 0)
1038gui.bootprompt.vborder = MIN( gui.bootprompt.height , (unsigned)val );
1039
1040if(GUI_getColorForKey("bootprompt_bgcolor", &color, theme))
1041gui.bootprompt.bgcolor = (color & 0x00FFFFFF);
1042
1043if(getIntForKey("bootprompt_transparency", &alpha, theme))
1044gui.bootprompt.bgcolor = gui.bootprompt.bgcolor | (( 255 - ( alpha & 0xFF) ) << 24);
1045
1046if(GUI_getColorForKey("font_small_color", &color, theme))
1047gui.screen.font_small_color = (color & 0x00FFFFFF);
1048
1049if(GUI_getColorForKey("font_console_color", &color, theme))
1050gui.screen.font_console_color = (color & 0x00FFFFFF);
1051}
1052
1053static void add_theme(const char *theme, uint8_t nb)
1054{
1055 struct themeList_t *new_theme;
1056
1057 new_theme = themeList_t_NewStrVar(theme, &gthemeList);
1058if (!new_theme)
1059{
1060return;
1061}
1062 new_theme->nb = nb;
1063}
1064
1065static char *get_theme_by_index(uint8_t i)
1066{
1067 struct themeList_t *current_theme;
1068 for(current_theme=gthemeList;current_theme;current_theme=(struct themeList_t*)(current_theme->hh.next))
1069 {
1070 if (current_theme->nb == i)
1071 return current_theme->name;
1072 }
1073 return NULL;
1074}
1075
1076static void free_theme_list(void)
1077{
1078 themeList_t_DeleteAll(gthemeList);
1079}
1080
1081static int randomTheme(char *dirspec, const char **theme) {
1082
1083long ret, flags, time;
1084long long index;
1085int sta = 1;
1086const char * name;
1087index = 0;
1088uint8_t i=0;
1089
1090#ifdef EMBED_THEME
1091add_theme("", i);
1092i++;
1093#endif
1094
1095while (i < MAX_THEMES) {
1096ret = GetDirEntry(dirspec, &index, &name, &flags, &time);
1097if (ret == -1) break;
1098
1099// Make sure this is a directory.
1100if ((flags & kFileTypeMask) != kFileTypeDirectory) continue;
1101
1102add_theme(name, i);
1103
1104i++;
1105
1106}
1107
1108#if DEBUG_GUI
1109printf("theme list: \n");
1110printf("\n");
1111struct themeList_t *current_theme;
1112 for(current_theme=gthemeList;current_theme;current_theme=(struct themeList_t*)(current_theme->hh.next))
1113 {
1114printf("* %s (nb = %d)\n", current_theme->name, current_theme->nb);
1115
1116 }
1117
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
1126
1127char *tmp = get_theme_by_index(choosen);
1128
1129if (tmp)
1130{
1131bzero(tmp_theme,sizeof(tmp_theme));
1132strlcpy(tmp_theme, tmp, sizeof(tmp_theme));
1133}
1134
1135free_theme_list();
1136
1137if (tmp_theme[0])
1138{
1139*theme = tmp_theme;
1140
1141sta = startGUI();
1142}
1143}
1144else
1145{
1146#if DEBUG_GUI
1147printf("No theme found !!\n");
1148sleep(1);
1149#endif
1150free_theme_list();
1151
1152}
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)) {
1186snprintf(dirsrc,sizeof(dirsrc), "rd(0,0)/Extra/Themes");
1187
1188} else {
1189ret = GetFileInfo("/Extra/", "Themes", &flags, &time);
1190if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)) {
1191snprintf(dirsrc,sizeof(dirsrc), "/Extra/Themes");
1192
1193} else {
1194ret = GetFileInfo("bt(0,0)/Extra/", "Themes", &flags, &time);
1195if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)) {
1196snprintf(dirsrc,sizeof(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)) {
1210snprintf(dirsrc,sizeof(dirsrc), "rd(0,0)/Extra/Themes");
1211
1212} else {
1213ret = GetFileInfo("/Extra/Themes/", theme_name, &flags, &time);
1214if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)) {
1215snprintf(dirsrc,sizeof(dirsrc), "/Extra/Themes");
1216
1217} else {
1218ret = GetFileInfo("bt(0,0)/Extra/Themes/", theme_name, &flags, &time);
1219if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)) {
1220snprintf(dirsrc,sizeof(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 && (strncmp(theme_name, THEME_NAME_DEFAULT,sizeof(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
1292snprintf(dirspec, sizeof(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}
2587snprintf(dirspec, sizeof(dirspec), "%s/%s/boot.png", src, theme_name);
2588if ((strlen(theme_name) == 0) || (loadPngImage(dirspec, &bootImageWidth, &bootImageHeight, &bootImageData) == -1)) {
2589#ifdef EMBED_THEME
2590if ((loadEmbeddedPngImage(__boot_png, __boot_png_len, &bootImageWidth, &bootImageHeight, &bootImageData)) == -1)
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: HEAD