11 #include <linux/input.h>
15 #include <libtwin/twin.h>
16 #include <libtwin/twin_linux_mouse.h>
17 #include <libtwin/twin_png.h>
18 #include <libtwin/twin_jpeg.h>
20 #include "petitboot.h"
21 #include "petitboot-paths.h"
24 #include <libtwin/twin_x11.h>
25 static twin_x11_t *pboot_x11;
27 #include <libtwin/twin_fbdev.h>
28 static twin_fbdev_t *pboot_fbdev;
31 static twin_screen_t *pboot_screen;
33 #define PBOOT_INITIAL_MESSAGE \
34 "keys: 0=safe 1=720p 2=1080i 3=1080p del=GameOS"
36 #define PBOOT_LEFT_PANE_SIZE 160
37 #define PBOOT_LEFT_PANE_COLOR 0x80000000
38 #define PBOOT_LEFT_LINE_COLOR 0xff000000
40 #define PBOOT_LEFT_FOCUS_WIDTH 80
41 #define PBOOT_LEFT_FOCUS_HEIGHT 80
42 #define PBOOT_LEFT_FOCUS_XOFF 40
43 #define PBOOT_LEFT_FOCUS_YOFF 40
44 #define PBOOT_LEFT_FOCUS_XRAD (6 * TWIN_FIXED_ONE)
45 #define PBOOT_LEFT_FOCUS_YRAD (6 * TWIN_FIXED_ONE)
47 #define PBOOT_RIGHT_FOCUS_XOFF 20
48 #define PBOOT_RIGHT_FOCUS_YOFF 60
49 #define PBOOT_RIGHT_FOCUS_HEIGHT 80
50 #define PBOOT_RIGHT_FOCUS_XRAD (6 * TWIN_FIXED_ONE)
51 #define PBOOT_RIGHT_FOCUS_YRAD (6 * TWIN_FIXED_ONE)
53 #define PBOOT_LEFT_ICON_WIDTH 64
54 #define PBOOT_LEFT_ICON_HEIGHT 64
55 #define PBOOT_LEFT_ICON_XOFF 50
56 #define PBOOT_LEFT_ICON_YOFF 50
57 #define PBOOT_LEFT_ICON_STRIDE 100
59 #define PBOOT_RIGHT_OPTION_LMARGIN 30
60 #define PBOOT_RIGHT_OPTION_RMARGIN 30
61 #define PBOOT_RIGHT_OPTION_TMARGIN 70
62 #define PBOOT_RIGHT_OPTION_HEIGHT 64
63 #define PBOOT_RIGHT_OPTION_STRIDE 100
64 #define PBOOT_RIGHT_TITLE_TEXT_SIZE (30 * TWIN_FIXED_ONE)
65 #define PBOOT_RIGHT_SUBTITLE_TEXT_SIZE (18 * TWIN_FIXED_ONE)
66 #define PBOOT_RIGHT_TITLE_XOFFSET 80
67 #define PBOOT_RIGHT_TITLE_YOFFSET 30
68 #define PBOOT_RIGHT_SUBTITLE_XOFFSET 100
69 #define PBOOT_RIGHT_SUBTITLE_YOFFSET 50
70 #define PBOOT_RIGHT_BADGE_XOFFSET 2
71 #define PBOOT_RIGHT_BADGE_YOFFSET 0
74 #define PBOOT_RIGHT_TITLE_COLOR 0xff000000
75 #define PBOOT_RIGHT_SUBTITLE_COLOR 0xff400000
77 #define PBOOT_FOCUS_COLOR 0x10404040
79 #define PBOOT_STATUS_PANE_COLOR 0x60606060
80 #define PBOOT_STATUS_PANE_HEIGHT 20
81 #define PBOOT_STATUS_PANE_XYMARGIN 20
82 #define PBOOT_STATUS_TEXT_MARGIN 10
83 #define PBOOT_STATUS_TEXT_SIZE (16 * TWIN_FIXED_ONE)
84 #define PBOOT_STATUS_TEXT_COLOR 0xff000000
86 typedef struct _pboot_option pboot_option_t;
87 typedef struct _pboot_device pboot_device_t;
102 twin_pixmap_t *badge;
105 pboot_option_t options[PBOOT_MAX_OPTION];
108 static twin_pixmap_t *pboot_cursor;
109 static int pboot_cursor_hx;
110 static int pboot_cursor_hy;
112 static pboot_device_t *pboot_devices[PBOOT_MAX_DEV];
113 static int pboot_dev_count;
114 static int pboot_dev_sel = -1;
115 static int pboot_focus_lpane = 1;
117 typedef struct _pboot_lpane {
118 twin_window_t *window;
119 twin_rect_t focus_box;
126 typedef struct _pboot_rpane {
127 twin_window_t *window;
128 twin_rect_t focus_box;
135 typedef struct _pboot_spane {
136 twin_window_t *window;
140 static pboot_lpane_t *pboot_lpane;
141 static pboot_rpane_t *pboot_rpane;
142 static pboot_spane_t *pboot_spane;
144 static int pboot_vmode_change = -1;
146 /* XXX move to twin */
147 static inline twin_bool_t twin_rect_intersect(twin_rect_t r1,
150 return !(r1.left > r2.right ||
151 r1.right < r2.left ||
152 r1.top > r2.bottom ||
156 static void pboot_draw_option_cache(pboot_device_t *dev, pboot_option_t *opt,
164 px = twin_pixmap_create(TWIN_ARGB32, opt->box.right - opt->box.left,
165 opt->box.bottom - opt->box.top);
169 /* Fill background */
170 twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
172 /* Allocate a path for drawing */
173 path = twin_path_create();
177 /* TEST - Bounding rectangle */
178 twin_path_rectangle(path, 0, 0,
179 twin_int_to_fixed(px->width),
180 twin_int_to_fixed(px->height));
181 twin_paint_path(px, PBOOT_RIGHT_TITLE_COLOR, path);
182 twin_path_empty(path);
183 twin_fill(px, 0x00000000, TWIN_SOURCE, 2, 2,
184 px->width - 3, px->height - 3);
188 twin_path_set_font_size(path, PBOOT_RIGHT_TITLE_TEXT_SIZE);
189 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
190 tx = twin_int_to_fixed(PBOOT_RIGHT_TITLE_XOFFSET);
191 ty = twin_int_to_fixed(PBOOT_RIGHT_TITLE_YOFFSET);
192 twin_path_move (path, tx, ty);
193 twin_path_utf8 (path, opt->title);
194 twin_paint_path (px, PBOOT_RIGHT_TITLE_COLOR, path);
195 twin_path_empty (path);
198 twin_path_set_font_size(path, PBOOT_RIGHT_SUBTITLE_TEXT_SIZE);
199 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
200 tx = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_XOFFSET);
201 ty = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_YOFFSET);
202 twin_path_move (path, tx, ty);
203 twin_path_utf8 (path, opt->subtitle);
204 twin_paint_path (px, PBOOT_RIGHT_SUBTITLE_COLOR, path);
205 twin_path_empty (path);
211 src.source_kind = TWIN_PIXMAP;
212 src.u.pixmap = opt->badge;
214 twin_composite(px, PBOOT_RIGHT_BADGE_XOFFSET,
215 PBOOT_RIGHT_BADGE_YOFFSET,
216 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
217 opt->badge->width, opt->badge->height);
222 twin_path_destroy(path);
225 static void pboot_rpane_draw(twin_window_t *window)
227 twin_pixmap_t *px = window->pixmap;
228 pboot_rpane_t *rpane = window->client_data;
231 twin_fixed_t x, y, w, h;
234 /* Fill background */
235 twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
237 /* Nothing to draw, return */
238 if (pboot_dev_sel < 0)
241 /* Create a path for use later */
242 path = twin_path_create();
246 if (rpane->focus_curindex >= 0 &&
247 twin_rect_intersect(rpane->focus_box, px->clip)) {
248 x = twin_int_to_fixed(rpane->focus_box.left + 2);
249 y = twin_int_to_fixed(rpane->focus_box.top + 2);
250 w = twin_int_to_fixed(rpane->focus_box.right -
251 rpane->focus_box.left - 4);
252 h = twin_int_to_fixed(rpane->focus_box.bottom -
253 rpane->focus_box.top - 4);
254 twin_path_rounded_rectangle(path, x, y, w, h,
255 PBOOT_RIGHT_FOCUS_XRAD,
256 PBOOT_RIGHT_FOCUS_YRAD);
257 if (!pboot_focus_lpane)
258 twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
260 twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
264 /* Get device and iterate through options */
265 dev = pboot_devices[pboot_dev_sel];
266 for (i = 0; i < dev->option_count; i++) {
267 pboot_option_t *opt = &dev->options[i];
270 if (opt->title == NULL)
272 if (!twin_rect_intersect(opt->box, px->clip))
274 if (opt->cache == NULL)
275 pboot_draw_option_cache(dev, opt, i);
277 src.source_kind = TWIN_PIXMAP;
278 src.u.pixmap = opt->cache;
280 twin_composite(px, opt->box.left, opt->box.top,
281 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
282 opt->box.right - opt->box.left,
283 opt->box.bottom - opt->box.top);
287 twin_path_destroy(path);
290 static twin_time_t pboot_rfocus_timeout (twin_time_t now, void *closure)
292 int dir = 1, dist, pos;
293 const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 1, 2, 2, 3 };
295 dist = abs(pboot_rpane->focus_target - pboot_rpane->focus_start);
296 dir = dist > 5 ? 5 : dist;
297 pos = pboot_rpane->focus_target - (int)pboot_rpane->focus_box.top;
305 twin_window_damage(pboot_rpane->window,
306 pboot_rpane->focus_box.left,
307 pboot_rpane->focus_box.top,
308 pboot_rpane->focus_box.right,
309 pboot_rpane->focus_box.bottom);
311 pboot_rpane->focus_box.top += dir;
312 pboot_rpane->focus_box.bottom += dir;
314 twin_window_damage(pboot_rpane->window,
315 pboot_rpane->focus_box.left,
316 pboot_rpane->focus_box.top,
317 pboot_rpane->focus_box.right,
318 pboot_rpane->focus_box.bottom);
320 twin_window_queue_paint(pboot_rpane->window);
322 return accel[(pos * 10) / dist];
325 static void pboot_set_rfocus(int index)
329 if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
331 dev = pboot_devices[pboot_dev_sel];
332 if (index < 0 || index >= dev->option_count)
335 pboot_rpane->focus_start = pboot_rpane->focus_box.top;
336 pboot_rpane->focus_target = PBOOT_RIGHT_FOCUS_YOFF +
337 PBOOT_RIGHT_OPTION_STRIDE * index;
338 pboot_rpane->focus_curindex = index;
340 twin_set_timeout(pboot_rfocus_timeout, 0, NULL);
343 static void pboot_select_rpane(void)
345 if (pboot_focus_lpane == 0)
347 pboot_focus_lpane = 0;
349 twin_screen_set_active(pboot_screen, pboot_rpane->window->pixmap);
351 twin_window_damage(pboot_lpane->window,
352 pboot_lpane->focus_box.left,
353 pboot_lpane->focus_box.top,
354 pboot_lpane->focus_box.right,
355 pboot_lpane->focus_box.bottom);
357 twin_window_damage(pboot_rpane->window,
358 pboot_rpane->focus_box.left,
359 pboot_rpane->focus_box.top,
360 pboot_rpane->focus_box.right,
361 pboot_rpane->focus_box.bottom);
363 twin_window_queue_paint(pboot_lpane->window);
364 twin_window_queue_paint(pboot_rpane->window);
369 static void pboot_select_lpane(void)
371 if (pboot_focus_lpane == 1)
373 pboot_focus_lpane = 1;
375 twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
377 twin_window_damage(pboot_lpane->window,
378 pboot_lpane->focus_box.left,
379 pboot_lpane->focus_box.top,
380 pboot_lpane->focus_box.right,
381 pboot_lpane->focus_box.bottom);
383 twin_window_damage(pboot_rpane->window,
384 pboot_rpane->focus_box.left,
385 pboot_rpane->focus_box.top,
386 pboot_rpane->focus_box.right,
387 pboot_rpane->focus_box.bottom);
389 twin_window_queue_paint(pboot_lpane->window);
390 twin_window_queue_paint(pboot_rpane->window);
393 static void pboot_rpane_mousetrack(twin_coord_t x, twin_coord_t y)
399 if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
401 dev = pboot_devices[pboot_dev_sel];
403 if (y < PBOOT_RIGHT_OPTION_TMARGIN)
405 candidate = (y - PBOOT_RIGHT_OPTION_TMARGIN) /
406 PBOOT_RIGHT_OPTION_STRIDE;
407 if (candidate >= dev->option_count) {
411 if (candidate == pboot_rpane->mouse_target)
413 opt = &dev->options[candidate];
414 if (x < opt->box.left || x > opt->box.right ||
415 y < opt->box.top || y > opt->box.bottom) {
420 /* Ok, so now, we know the mouse hit an icon that wasn't the same
421 * as the previous one, we trigger a focus change
423 pboot_set_rfocus(candidate);
426 pboot_rpane->mouse_target = candidate;
429 static void pboot_choose_option(void)
431 pboot_device_t *dev = pboot_devices[pboot_dev_sel];
432 pboot_option_t *opt = &dev->options[pboot_rpane->focus_curindex];
434 LOG("Selected device %s\n", opt->title);
436 /* Give user feedback, make sure errors and panics will be seen */
437 pboot_exec_option(opt->data);
440 static twin_bool_t pboot_rpane_event (twin_window_t *window,
443 /* filter out all mouse events */
444 switch(event->kind) {
446 case TwinEventMotion:
448 pboot_select_rpane();
449 pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
451 case TwinEventButtonDown:
452 pboot_select_rpane();
453 pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
454 pboot_choose_option();
455 case TwinEventButtonUp:
457 case TwinEventKeyDown:
458 switch(event->u.key.key) {
460 pboot_set_rfocus(pboot_rpane->focus_curindex - 1);
463 pboot_set_rfocus(pboot_rpane->focus_curindex + 1);
466 pboot_select_lpane();
469 pboot_choose_option();
481 int pboot_add_option(int devindex, const char *title,
482 const char *subtitle, twin_pixmap_t *badge, void *data)
489 if (devindex < 0 || devindex >= pboot_dev_count)
491 dev = pboot_devices[devindex];
493 if (dev->option_count >= PBOOT_MAX_OPTION)
495 index = dev->option_count++;
496 opt = &dev->options[index];
498 opt->title = malloc(strlen(title) + 1);
499 strcpy(opt->title, title);
502 opt->subtitle = malloc(strlen(subtitle) + 1);
503 strcpy(opt->subtitle, subtitle);
505 opt->subtitle = NULL;
510 width = pboot_rpane->window->pixmap->width -
511 (PBOOT_RIGHT_OPTION_LMARGIN + PBOOT_RIGHT_OPTION_RMARGIN);
513 opt->box.left = PBOOT_RIGHT_OPTION_LMARGIN;
514 opt->box.right = opt->box.left + width;
515 opt->box.top = PBOOT_RIGHT_OPTION_TMARGIN +
516 index * PBOOT_RIGHT_OPTION_STRIDE;
517 opt->box.bottom = opt->box.top + PBOOT_RIGHT_OPTION_HEIGHT;
524 static void pboot_set_device_select(int sel, int force)
526 LOG("%s: %d -> %d\n", __FUNCTION__, pboot_dev_sel, sel);
527 if (!force && sel == pboot_dev_sel)
529 if (sel >= pboot_dev_count)
533 pboot_lpane->focus_curindex = sel;
535 pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
537 pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF +
538 PBOOT_LEFT_ICON_STRIDE * sel;
539 pboot_rpane->focus_box.bottom = pboot_lpane->focus_target;
540 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
541 PBOOT_RIGHT_FOCUS_HEIGHT;
542 twin_window_damage(pboot_lpane->window,
544 pboot_lpane->window->pixmap->width,
545 pboot_lpane->window->pixmap->height);
546 twin_window_queue_paint(pboot_lpane->window);
548 pboot_rpane->focus_curindex = -1;
549 pboot_rpane->mouse_target = -1;
550 pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
551 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
552 PBOOT_RIGHT_FOCUS_HEIGHT;
553 twin_window_damage(pboot_rpane->window, 0, 0,
554 pboot_rpane->window->pixmap->width,
555 pboot_rpane->window->pixmap->height);
556 twin_window_queue_paint(pboot_rpane->window);
559 static void pboot_create_rpane(void)
561 pboot_rpane = calloc(1, sizeof(pboot_rpane_t));
564 pboot_rpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
566 PBOOT_LEFT_PANE_SIZE, 0,
567 pboot_screen->width -
568 PBOOT_LEFT_PANE_SIZE,
569 pboot_screen->height);
570 assert(pboot_rpane->window);
572 pboot_rpane->window->draw = pboot_rpane_draw;
573 pboot_rpane->window->event = pboot_rpane_event;
574 pboot_rpane->window->client_data = pboot_rpane;
576 pboot_rpane->focus_curindex = -1;
577 pboot_rpane->focus_box.left = PBOOT_RIGHT_FOCUS_XOFF;
578 pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
579 pboot_rpane->focus_box.right = pboot_rpane->window->pixmap->width -
580 2 * PBOOT_RIGHT_FOCUS_XOFF;
581 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
582 PBOOT_RIGHT_FOCUS_HEIGHT;
583 pboot_rpane->mouse_target = -1;
584 twin_window_show(pboot_rpane->window);
585 twin_window_queue_paint(pboot_rpane->window);
589 static twin_time_t pboot_lfocus_timeout (twin_time_t now, void *closure)
591 int dir = 1, dist, pos;
592 const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 1, 2, 2, 3 };
594 dist = abs(pboot_lpane->focus_target - pboot_lpane->focus_start);
595 dir = dist > 2 ? 2 : dist;
596 pos = pboot_lpane->focus_target - (int)pboot_lpane->focus_box.top;
598 pboot_set_device_select(pboot_lpane->focus_curindex, 0);
605 twin_window_damage(pboot_lpane->window,
606 pboot_lpane->focus_box.left,
607 pboot_lpane->focus_box.top,
608 pboot_lpane->focus_box.right,
609 pboot_lpane->focus_box.bottom);
611 pboot_lpane->focus_box.top += dir;
612 pboot_lpane->focus_box.bottom += dir;
614 twin_window_damage(pboot_lpane->window,
615 pboot_lpane->focus_box.left,
616 pboot_lpane->focus_box.top,
617 pboot_lpane->focus_box.right,
618 pboot_lpane->focus_box.bottom);
620 twin_window_queue_paint(pboot_lpane->window);
622 return accel[(pos * 10) / dist];
625 static void pboot_set_lfocus(int index)
627 if (index >= pboot_dev_count)
630 pboot_lpane->focus_start = pboot_lpane->focus_box.top;
633 pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
635 pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF +
636 PBOOT_LEFT_ICON_STRIDE * index;
638 pboot_lpane->focus_curindex = index;
640 twin_set_timeout(pboot_lfocus_timeout, 0, NULL);
643 static void pboot_lpane_mousetrack(twin_coord_t x, twin_coord_t y)
646 twin_coord_t icon_top;
648 if (x < PBOOT_LEFT_ICON_XOFF ||
649 x > (PBOOT_LEFT_ICON_XOFF + PBOOT_LEFT_ICON_WIDTH))
651 if (y < PBOOT_LEFT_ICON_YOFF)
653 candidate = (y - PBOOT_LEFT_ICON_YOFF) / PBOOT_LEFT_ICON_STRIDE;
654 if (candidate >= pboot_dev_count) {
658 if (candidate == pboot_lpane->mouse_target)
660 icon_top = PBOOT_LEFT_ICON_YOFF +
661 candidate * PBOOT_LEFT_ICON_STRIDE;
662 if (y > (icon_top + PBOOT_LEFT_ICON_HEIGHT)) {
667 /* Ok, so now, we know the mouse hit an icon that wasn't the same
668 * as the previous one, we trigger a focus change
670 pboot_set_lfocus(candidate);
673 pboot_lpane->mouse_target = candidate;
676 static twin_bool_t pboot_lpane_event (twin_window_t *window,
679 /* filter out all mouse events */
680 switch(event->kind) {
682 case TwinEventMotion:
684 pboot_select_lpane();
685 pboot_lpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
687 case TwinEventButtonDown:
688 case TwinEventButtonUp:
690 case TwinEventKeyDown:
691 switch(event->u.key.key) {
693 if (pboot_lpane->focus_curindex > 0)
695 pboot_lpane->focus_curindex - 1);
698 pboot_set_lfocus(pboot_lpane->focus_curindex + 1);
701 pboot_select_rpane();
713 static void pboot_quit(void)
718 twin_bool_t pboot_event_filter(twin_screen_t *screen,
721 switch(event->kind) {
723 case TwinEventMotion:
725 case TwinEventButtonDown:
726 case TwinEventButtonUp:
727 if (pboot_cursor != NULL)
728 twin_screen_set_cursor(pboot_screen, pboot_cursor,
732 case TwinEventKeyDown:
733 switch(event->u.key.key) {
734 /* Gross hack for video modes, need something better ! */
736 pboot_vmode_change = 0; /* auto */
740 pboot_vmode_change = 3; /* 720p */
744 pboot_vmode_change = 4; /* 1080i */
748 pboot_vmode_change = 5; /* 1080p */
752 /* Another gross hack for booting back to gameos */
755 system("boot-game-os");
759 twin_screen_set_cursor(pboot_screen, NULL, 0, 0);
767 static void pboot_lpane_draw(twin_window_t *window)
769 twin_pixmap_t *px = window->pixmap;
770 pboot_lpane_t *lpane = window->client_data;
772 twin_fixed_t x, y, w, h;
775 /* Fill background */
776 twin_fill(px, PBOOT_LEFT_PANE_COLOR, TWIN_SOURCE,
777 0, 0, px->width, px->height);
779 /* Create a path for use later */
780 path = twin_path_create();
783 /* Draw right line if needed */
784 if (px->clip.right > (PBOOT_LEFT_PANE_SIZE - 4)) {
785 x = twin_int_to_fixed(PBOOT_LEFT_PANE_SIZE - 4);
786 y = twin_int_to_fixed(px->height);
787 twin_path_rectangle(path, x, 0, 0x40000, y);
788 twin_paint_path(px, PBOOT_LEFT_LINE_COLOR, path);
789 twin_path_empty(path);
793 if (lpane->focus_curindex >= 0 &&
794 twin_rect_intersect(lpane->focus_box, px->clip)) {
795 x = twin_int_to_fixed(lpane->focus_box.left + 2);
796 y = twin_int_to_fixed(lpane->focus_box.top + 2);
797 w = twin_int_to_fixed(lpane->focus_box.right -
798 lpane->focus_box.left - 4);
799 h = twin_int_to_fixed(lpane->focus_box.bottom -
800 lpane->focus_box.top - 4);
801 twin_path_rounded_rectangle(path, x, y, w, h,
802 PBOOT_LEFT_FOCUS_XRAD,
803 PBOOT_LEFT_FOCUS_YRAD);
804 if (pboot_focus_lpane)
805 twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
807 twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
812 for (i = 0; i < pboot_dev_count; i++) {
813 pboot_device_t *dev = pboot_devices[i];
816 if (!twin_rect_intersect(dev->box, px->clip))
819 src.source_kind = TWIN_PIXMAP;
820 src.u.pixmap = dev->badge;
822 twin_composite(px, dev->box.left, dev->box.top,
823 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
824 dev->box.right - dev->box.left,
825 dev->box.bottom - dev->box.top);
830 twin_path_destroy(path);
833 static void pboot_create_lpane(void)
835 pboot_lpane = calloc(1, sizeof(pboot_lpane_t));
838 pboot_lpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
840 0, 0, PBOOT_LEFT_PANE_SIZE,
841 pboot_screen->height);
842 assert(pboot_lpane->window);
844 pboot_lpane->window->draw = pboot_lpane_draw;
845 pboot_lpane->window->event = pboot_lpane_event;
846 pboot_lpane->window->client_data = pboot_lpane;
847 pboot_lpane->focus_curindex = -1;
848 pboot_lpane->focus_box.left = PBOOT_LEFT_FOCUS_XOFF;
849 pboot_lpane->focus_box.top = -2*PBOOT_LEFT_FOCUS_HEIGHT;
850 pboot_lpane->focus_box.right = pboot_lpane->focus_box.left +
851 PBOOT_LEFT_FOCUS_WIDTH;
852 pboot_lpane->focus_box.bottom = pboot_lpane->focus_box.top +
853 PBOOT_LEFT_FOCUS_HEIGHT;
854 pboot_lpane->mouse_target = -1;
855 twin_window_show(pboot_lpane->window);
856 twin_window_queue_paint(pboot_lpane->window);
859 static void pboot_spane_draw(twin_window_t *window)
861 twin_pixmap_t *px = window->pixmap;
862 pboot_spane_t *spane = window->client_data;
866 /* Fill background */
867 twin_fill(px, PBOOT_STATUS_PANE_COLOR, TWIN_SOURCE,
868 0, 0, px->width, px->height);
870 path = twin_path_create();
873 twin_path_set_font_size(path, PBOOT_STATUS_TEXT_SIZE);
874 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
875 tx = twin_int_to_fixed(PBOOT_STATUS_TEXT_MARGIN);
876 ty = twin_int_to_fixed(PBOOT_STATUS_PANE_HEIGHT - 2);
877 twin_path_move (path, tx, ty);
878 twin_path_utf8 (path, spane->text);
879 twin_paint_path (px, PBOOT_STATUS_TEXT_COLOR, path);
881 twin_path_destroy(path);
884 void pboot_message(const char *message)
886 if (pboot_spane->text)
887 free(pboot_spane->text);
888 pboot_spane->text = strdup(message);
889 twin_window_damage(pboot_spane->window,
891 pboot_spane->window->pixmap->width,
892 pboot_spane->window->pixmap->height);
893 twin_window_queue_paint(pboot_spane->window);
896 static void pboot_create_spane(void)
898 pboot_spane = calloc(1, sizeof(pboot_spane_t));
901 pboot_spane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
903 PBOOT_LEFT_PANE_SIZE +
904 PBOOT_STATUS_PANE_XYMARGIN,
905 pboot_screen->height -
906 PBOOT_STATUS_PANE_HEIGHT,
907 pboot_screen->width -
908 PBOOT_LEFT_PANE_SIZE -
909 2*PBOOT_STATUS_PANE_XYMARGIN,
910 PBOOT_STATUS_PANE_HEIGHT);
911 assert(pboot_spane->window);
913 pboot_spane->window->draw = pboot_spane_draw;
914 pboot_spane->window->client_data = pboot_spane;
915 pboot_spane->text = strdup(PBOOT_INITIAL_MESSAGE);
916 twin_window_show(pboot_spane->window);
917 twin_window_queue_paint(pboot_spane->window);
920 int pboot_add_device(const char *dev_id, const char *name,
921 twin_pixmap_t *pixmap)
926 if (pboot_dev_count >= PBOOT_MAX_DEV)
929 index = pboot_dev_count++;
931 dev = malloc(sizeof(*dev));
932 memset(dev, 0, sizeof(*dev));
933 dev->id = malloc(strlen(dev_id) + 1);
934 strcpy(dev->id, dev_id);
936 dev->box.left = PBOOT_LEFT_ICON_XOFF;
937 dev->box.right = dev->box.left + PBOOT_LEFT_ICON_WIDTH;
938 dev->box.top = PBOOT_LEFT_ICON_YOFF +
939 PBOOT_LEFT_ICON_STRIDE * index;
940 dev->box.bottom = dev->box.top + PBOOT_LEFT_ICON_HEIGHT;
942 pboot_devices[index] = dev;
944 twin_window_damage(pboot_lpane->window,
945 dev->box.left, dev->box.top,
946 dev->box.right, dev->box.bottom);
947 twin_window_queue_paint(pboot_lpane->window);
952 int pboot_remove_device(const char *dev_id)
954 pboot_device_t *dev = NULL;
955 int i, newsel = pboot_dev_sel;
957 /* find the matching device */
958 for (i = 0; i < pboot_dev_count; i++) {
959 if (!strcmp(pboot_devices[i]->id, dev_id)) {
960 dev = pboot_devices[i];
968 memmove(pboot_devices + i, pboot_devices + i + 1,
969 sizeof(*pboot_devices) * (pboot_dev_count + i - 1));
970 pboot_devices[--pboot_dev_count] = NULL;
972 /* select the newly-focussed device */
973 if (pboot_dev_sel > i)
974 newsel = pboot_dev_sel - 1;
975 else if (pboot_dev_sel == i && i >= pboot_dev_count)
976 newsel = pboot_dev_count - 1;
977 pboot_set_device_select(newsel, 1);
979 /* todo: free device & options */
984 static void pboot_make_background(void)
986 twin_pixmap_t *filepic, *scaledpic;
987 const char *background_path;
989 /* Set background pixmap */
990 LOG("loading background...");
991 background_path = artwork_pathname("background.jpg");
992 filepic = twin_jpeg_to_pixmap(background_path, TWIN_ARGB32);
993 LOG("%s\n", filepic ? "ok" : "failed");
998 if (pboot_screen->height == filepic->height &&
999 pboot_screen->width == filepic->width)
1000 scaledpic = filepic;
1002 twin_fixed_t sx, sy;
1003 twin_operand_t srcop;
1005 scaledpic = twin_pixmap_create(TWIN_ARGB32,
1006 pboot_screen->width,
1007 pboot_screen->height);
1008 if (scaledpic == NULL) {
1009 twin_pixmap_destroy(filepic);
1012 sx = twin_fixed_div(twin_int_to_fixed(filepic->width),
1013 twin_int_to_fixed(pboot_screen->width));
1014 sy = twin_fixed_div(twin_int_to_fixed(filepic->height),
1015 twin_int_to_fixed(pboot_screen->height));
1017 twin_matrix_scale(&filepic->transform, sx, sy);
1018 srcop.source_kind = TWIN_PIXMAP;
1019 srcop.u.pixmap = filepic;
1020 twin_composite(scaledpic, 0, 0, &srcop, 0, 0,
1021 NULL, 0, 0, TWIN_SOURCE,
1022 pboot_screen->width, pboot_screen->height);
1023 twin_pixmap_destroy(filepic);
1026 twin_screen_set_background(pboot_screen, scaledpic);
1029 #define PS3FB_IOCTL_SETMODE _IOW('r', 1, int)
1030 #define PS3FB_IOCTL_GETMODE _IOR('r', 2, int)
1032 static void exitfunc(void)
1036 twin_fbdev_destroy(pboot_fbdev);
1038 if (pboot_vmode_change != -1) {
1039 int fd = open("/dev/fb0", O_RDWR);
1041 ioctl(fd, PS3FB_IOCTL_SETMODE,
1042 (unsigned long)&pboot_vmode_change);
1048 static void sigint(int sig)
1054 static void usage(const char *progname)
1056 fprintf(stderr, "Usage: %s [-u] [-h]\n", progname);
1059 int main(int argc, char **argv)
1062 int udev_trigger = 0;
1065 c = getopt(argc, argv, "u::h");
1075 return EXIT_SUCCESS;
1077 fprintf(stderr, "Unknown option '%c'\n", c);
1079 return EXIT_FAILURE;
1084 signal(SIGINT, sigint);
1087 pboot_x11 = twin_x11_create(XOpenDisplay(0), 1024, 768);
1088 if (pboot_x11 == NULL) {
1089 perror("failed to create x11 screen !\n");
1092 pboot_screen = pboot_x11->screen;
1094 /* Create screen and mouse drivers */
1095 pboot_fbdev = twin_fbdev_create(-1, SIGUSR1);
1096 if (pboot_fbdev == NULL) {
1097 perror("failed to create fbdev screen !\n");
1100 pboot_screen = pboot_fbdev->screen;
1101 twin_linux_mouse_create(NULL, pboot_screen);
1103 if (pboot_fbdev != NULL) {
1104 char *cursor_path = artwork_pathname("cursor.gz");
1105 pboot_cursor = twin_load_X_cursor(cursor_path, 2,
1108 if (pboot_cursor == NULL)
1110 twin_get_default_cursor(&pboot_cursor_hx,
1115 /* Set background pixmap */
1116 pboot_make_background();
1118 /* Init more stuffs */
1119 pboot_create_lpane();
1120 pboot_create_rpane();
1121 pboot_create_spane();
1123 if (!pboot_start_device_discovery(udev_trigger)) {
1124 LOG("Couldn't start device discovery!\n");
1128 pboot_set_lfocus(0);
1129 twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
1130 pboot_screen->event_filter = pboot_event_filter;
1132 /* Console switch */
1135 twin_fbdev_activate(pboot_fbdev);
1138 /* Process events */