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

Archive Download this file

Revision: 2112