12 #include <sys/ioctl.h>
14 #include <linux/input.h>
18 #include <libtwin/twin.h>
19 #include <libtwin/twin_linux_mouse.h>
20 #include <libtwin/twin_linux_js.h>
21 #include <libtwin/twin_png.h>
22 #include <libtwin/twin_jpeg.h>
24 #include "petitboot.h"
25 #include "petitboot-paths.h"
28 #include <libtwin/twin_x11.h>
29 static twin_x11_t *pboot_x11;
31 #include <libtwin/twin_fbdev.h>
32 static twin_fbdev_t *pboot_fbdev;
35 static twin_screen_t *pboot_screen;
37 #define PBOOT_INITIAL_MESSAGE \
38 "keys: 0=safe 1=720p 2=1080i 3=1080p del=GameOS"
40 #define PBOOT_LEFT_PANE_SIZE 160
41 #define PBOOT_LEFT_PANE_COLOR 0x80000000
42 #define PBOOT_LEFT_LINE_COLOR 0xff000000
44 #define PBOOT_LEFT_FOCUS_WIDTH 80
45 #define PBOOT_LEFT_FOCUS_HEIGHT 80
46 #define PBOOT_LEFT_FOCUS_XOFF 40
47 #define PBOOT_LEFT_FOCUS_YOFF 40
48 #define PBOOT_LEFT_FOCUS_XRAD (6 * TWIN_FIXED_ONE)
49 #define PBOOT_LEFT_FOCUS_YRAD (6 * TWIN_FIXED_ONE)
51 #define PBOOT_RIGHT_FOCUS_XOFF 20
52 #define PBOOT_RIGHT_FOCUS_YOFF 60
53 #define PBOOT_RIGHT_FOCUS_HEIGHT 80
54 #define PBOOT_RIGHT_FOCUS_XRAD (6 * TWIN_FIXED_ONE)
55 #define PBOOT_RIGHT_FOCUS_YRAD (6 * TWIN_FIXED_ONE)
57 #define PBOOT_LEFT_ICON_WIDTH 64
58 #define PBOOT_LEFT_ICON_HEIGHT 64
59 #define PBOOT_LEFT_ICON_XOFF 50
60 #define PBOOT_LEFT_ICON_YOFF 50
61 #define PBOOT_LEFT_ICON_STRIDE 100
63 #define PBOOT_RIGHT_OPTION_LMARGIN 30
64 #define PBOOT_RIGHT_OPTION_RMARGIN 30
65 #define PBOOT_RIGHT_OPTION_TMARGIN 70
66 #define PBOOT_RIGHT_OPTION_HEIGHT 64
67 #define PBOOT_RIGHT_OPTION_STRIDE 100
68 #define PBOOT_RIGHT_TITLE_TEXT_SIZE (30 * TWIN_FIXED_ONE)
69 #define PBOOT_RIGHT_SUBTITLE_TEXT_SIZE (18 * TWIN_FIXED_ONE)
70 #define PBOOT_RIGHT_TITLE_XOFFSET 80
71 #define PBOOT_RIGHT_TITLE_YOFFSET 30
72 #define PBOOT_RIGHT_SUBTITLE_XOFFSET 100
73 #define PBOOT_RIGHT_SUBTITLE_YOFFSET 50
74 #define PBOOT_RIGHT_BADGE_XOFFSET 2
75 #define PBOOT_RIGHT_BADGE_YOFFSET 0
78 #define PBOOT_RIGHT_TITLE_COLOR 0xff000000
79 #define PBOOT_RIGHT_SUBTITLE_COLOR 0xff400000
81 #define PBOOT_FOCUS_COLOR 0x10404040
83 #define PBOOT_STATUS_PANE_COLOR 0x60606060
84 #define PBOOT_STATUS_PANE_HEIGHT 20
85 #define PBOOT_STATUS_PANE_XYMARGIN 20
86 #define PBOOT_STATUS_TEXT_MARGIN 10
87 #define PBOOT_STATUS_TEXT_SIZE (16 * TWIN_FIXED_ONE)
88 #define PBOOT_STATUS_TEXT_COLOR 0xff000000
90 typedef struct _pboot_option pboot_option_t;
91 typedef struct _pboot_device pboot_device_t;
106 twin_pixmap_t *badge;
109 pboot_option_t options[PBOOT_MAX_OPTION];
112 static twin_pixmap_t *pboot_cursor;
113 static int pboot_cursor_hx;
114 static int pboot_cursor_hy;
116 static pboot_device_t *pboot_devices[PBOOT_MAX_DEV];
117 static int pboot_dev_count;
118 static int pboot_dev_sel = -1;
119 static int pboot_focus_lpane = 1;
121 typedef struct _pboot_lpane {
122 twin_window_t *window;
123 twin_rect_t focus_box;
130 typedef struct _pboot_rpane {
131 twin_window_t *window;
132 twin_rect_t focus_box;
139 typedef struct _pboot_spane {
140 twin_window_t *window;
144 static pboot_lpane_t *pboot_lpane;
145 static pboot_rpane_t *pboot_rpane;
146 static pboot_spane_t *pboot_spane;
148 /* control to keyboard mappings for the sixaxis controller */
149 uint8_t sixaxis_map[] = {
154 KEY_UP, /* 4 Dpad Up */
155 KEY_RIGHT, /* 5 Dpad Right */
156 KEY_DOWN, /* 6 Dpad Down */
157 KEY_LEFT, /* 7 Dpad Left */
163 KEY_ENTER, /* 13 Circle */
165 KEY_DELETE, /* 15 Square */
166 0, /* 16 PS Button */
172 static int pboot_vmode_change = -1;
174 /* XXX move to twin */
175 static inline twin_bool_t twin_rect_intersect(twin_rect_t r1,
178 return !(r1.left > r2.right ||
179 r1.right < r2.left ||
180 r1.top > r2.bottom ||
184 static void pboot_draw_option_cache(pboot_device_t *dev, pboot_option_t *opt,
192 px = twin_pixmap_create(TWIN_ARGB32, opt->box.right - opt->box.left,
193 opt->box.bottom - opt->box.top);
197 /* Fill background */
198 twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
200 /* Allocate a path for drawing */
201 path = twin_path_create();
205 /* TEST - Bounding rectangle */
206 twin_path_rectangle(path, 0, 0,
207 twin_int_to_fixed(px->width),
208 twin_int_to_fixed(px->height));
209 twin_paint_path(px, PBOOT_RIGHT_TITLE_COLOR, path);
210 twin_path_empty(path);
211 twin_fill(px, 0x00000000, TWIN_SOURCE, 2, 2,
212 px->width - 3, px->height - 3);
216 twin_path_set_font_size(path, PBOOT_RIGHT_TITLE_TEXT_SIZE);
217 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
218 tx = twin_int_to_fixed(PBOOT_RIGHT_TITLE_XOFFSET);
219 ty = twin_int_to_fixed(PBOOT_RIGHT_TITLE_YOFFSET);
220 twin_path_move (path, tx, ty);
221 twin_path_utf8 (path, opt->title);
222 twin_paint_path (px, PBOOT_RIGHT_TITLE_COLOR, path);
223 twin_path_empty (path);
226 twin_path_set_font_size(path, PBOOT_RIGHT_SUBTITLE_TEXT_SIZE);
227 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
228 tx = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_XOFFSET);
229 ty = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_YOFFSET);
230 twin_path_move (path, tx, ty);
231 twin_path_utf8 (path, opt->subtitle);
232 twin_paint_path (px, PBOOT_RIGHT_SUBTITLE_COLOR, path);
233 twin_path_empty (path);
239 src.source_kind = TWIN_PIXMAP;
240 src.u.pixmap = opt->badge;
242 twin_composite(px, PBOOT_RIGHT_BADGE_XOFFSET,
243 PBOOT_RIGHT_BADGE_YOFFSET,
244 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
245 opt->badge->width, opt->badge->height);
250 twin_path_destroy(path);
253 static void pboot_rpane_draw(twin_window_t *window)
255 twin_pixmap_t *px = window->pixmap;
256 pboot_rpane_t *rpane = window->client_data;
259 twin_fixed_t x, y, w, h;
262 /* Fill background */
263 twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
265 /* Nothing to draw, return */
266 if (pboot_dev_sel < 0)
269 /* Create a path for use later */
270 path = twin_path_create();
274 if (rpane->focus_curindex >= 0 &&
275 twin_rect_intersect(rpane->focus_box, px->clip)) {
276 x = twin_int_to_fixed(rpane->focus_box.left + 2);
277 y = twin_int_to_fixed(rpane->focus_box.top + 2);
278 w = twin_int_to_fixed(rpane->focus_box.right -
279 rpane->focus_box.left - 4);
280 h = twin_int_to_fixed(rpane->focus_box.bottom -
281 rpane->focus_box.top - 4);
282 twin_path_rounded_rectangle(path, x, y, w, h,
283 PBOOT_RIGHT_FOCUS_XRAD,
284 PBOOT_RIGHT_FOCUS_YRAD);
285 if (!pboot_focus_lpane)
286 twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
288 twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
292 /* Get device and iterate through options */
293 dev = pboot_devices[pboot_dev_sel];
294 for (i = 0; i < dev->option_count; i++) {
295 pboot_option_t *opt = &dev->options[i];
298 if (opt->title == NULL)
300 if (!twin_rect_intersect(opt->box, px->clip))
302 if (opt->cache == NULL)
303 pboot_draw_option_cache(dev, opt, i);
305 src.source_kind = TWIN_PIXMAP;
306 src.u.pixmap = opt->cache;
308 twin_composite(px, opt->box.left, opt->box.top,
309 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
310 opt->box.right - opt->box.left,
311 opt->box.bottom - opt->box.top);
315 twin_path_destroy(path);
318 static twin_time_t pboot_rfocus_timeout (twin_time_t now, void *closure)
320 int dir = 1, dist, pos;
321 const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 1, 2, 2, 3 };
323 dist = abs(pboot_rpane->focus_target - pboot_rpane->focus_start);
324 dir = dist > 5 ? 5 : dist;
325 pos = pboot_rpane->focus_target - (int)pboot_rpane->focus_box.top;
333 twin_window_damage(pboot_rpane->window,
334 pboot_rpane->focus_box.left,
335 pboot_rpane->focus_box.top,
336 pboot_rpane->focus_box.right,
337 pboot_rpane->focus_box.bottom);
339 pboot_rpane->focus_box.top += dir;
340 pboot_rpane->focus_box.bottom += dir;
342 twin_window_damage(pboot_rpane->window,
343 pboot_rpane->focus_box.left,
344 pboot_rpane->focus_box.top,
345 pboot_rpane->focus_box.right,
346 pboot_rpane->focus_box.bottom);
348 twin_window_queue_paint(pboot_rpane->window);
350 return accel[(pos * 10) / dist];
353 static void pboot_set_rfocus(int index)
357 if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
359 dev = pboot_devices[pboot_dev_sel];
360 if (index < 0 || index >= dev->option_count)
363 pboot_rpane->focus_start = pboot_rpane->focus_box.top;
364 pboot_rpane->focus_target = PBOOT_RIGHT_FOCUS_YOFF +
365 PBOOT_RIGHT_OPTION_STRIDE * index;
366 pboot_rpane->focus_curindex = index;
368 twin_set_timeout(pboot_rfocus_timeout, 0, NULL);
371 static void pboot_select_rpane(void)
373 if (pboot_focus_lpane == 0)
375 pboot_focus_lpane = 0;
377 twin_screen_set_active(pboot_screen, pboot_rpane->window->pixmap);
379 twin_window_damage(pboot_lpane->window,
380 pboot_lpane->focus_box.left,
381 pboot_lpane->focus_box.top,
382 pboot_lpane->focus_box.right,
383 pboot_lpane->focus_box.bottom);
385 twin_window_damage(pboot_rpane->window,
386 pboot_rpane->focus_box.left,
387 pboot_rpane->focus_box.top,
388 pboot_rpane->focus_box.right,
389 pboot_rpane->focus_box.bottom);
391 twin_window_queue_paint(pboot_lpane->window);
392 twin_window_queue_paint(pboot_rpane->window);
397 static void pboot_select_lpane(void)
399 if (pboot_focus_lpane == 1)
401 pboot_focus_lpane = 1;
403 twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
405 twin_window_damage(pboot_lpane->window,
406 pboot_lpane->focus_box.left,
407 pboot_lpane->focus_box.top,
408 pboot_lpane->focus_box.right,
409 pboot_lpane->focus_box.bottom);
411 twin_window_damage(pboot_rpane->window,
412 pboot_rpane->focus_box.left,
413 pboot_rpane->focus_box.top,
414 pboot_rpane->focus_box.right,
415 pboot_rpane->focus_box.bottom);
417 twin_window_queue_paint(pboot_lpane->window);
418 twin_window_queue_paint(pboot_rpane->window);
421 static void pboot_rpane_mousetrack(twin_coord_t x, twin_coord_t y)
427 if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
429 dev = pboot_devices[pboot_dev_sel];
431 if (y < PBOOT_RIGHT_OPTION_TMARGIN)
433 candidate = (y - PBOOT_RIGHT_OPTION_TMARGIN) /
434 PBOOT_RIGHT_OPTION_STRIDE;
435 if (candidate >= dev->option_count) {
439 if (candidate == pboot_rpane->mouse_target)
441 opt = &dev->options[candidate];
442 if (x < opt->box.left || x > opt->box.right ||
443 y < opt->box.top || y > opt->box.bottom) {
448 /* Ok, so now, we know the mouse hit an icon that wasn't the same
449 * as the previous one, we trigger a focus change
451 pboot_set_rfocus(candidate);
454 pboot_rpane->mouse_target = candidate;
457 static void pboot_choose_option(void)
459 pboot_device_t *dev = pboot_devices[pboot_dev_sel];
460 pboot_option_t *opt = &dev->options[pboot_rpane->focus_curindex];
462 LOG("Selected device %s\n", opt->title);
463 pboot_message("booting %s...", opt->title);
465 /* Give user feedback, make sure errors and panics will be seen */
466 pboot_exec_option(opt->data);
469 static twin_bool_t pboot_rpane_event (twin_window_t *window,
472 /* filter out all mouse events */
473 switch(event->kind) {
475 case TwinEventMotion:
477 pboot_select_rpane();
478 pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
480 case TwinEventButtonDown:
481 pboot_select_rpane();
482 pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
483 pboot_choose_option();
484 case TwinEventButtonUp:
486 case TwinEventKeyDown:
487 switch(event->u.key.key) {
489 pboot_set_rfocus(pboot_rpane->focus_curindex - 1);
492 pboot_set_rfocus(pboot_rpane->focus_curindex + 1);
495 pboot_select_lpane();
498 pboot_choose_option();
510 int pboot_add_option(int devindex, const char *title,
511 const char *subtitle, twin_pixmap_t *badge, void *data)
518 if (devindex < 0 || devindex >= pboot_dev_count)
520 dev = pboot_devices[devindex];
522 if (dev->option_count >= PBOOT_MAX_OPTION)
524 index = dev->option_count++;
525 opt = &dev->options[index];
527 opt->title = malloc(strlen(title) + 1);
528 strcpy(opt->title, title);
531 opt->subtitle = malloc(strlen(subtitle) + 1);
532 strcpy(opt->subtitle, subtitle);
534 opt->subtitle = NULL;
539 width = pboot_rpane->window->pixmap->width -
540 (PBOOT_RIGHT_OPTION_LMARGIN + PBOOT_RIGHT_OPTION_RMARGIN);
542 opt->box.left = PBOOT_RIGHT_OPTION_LMARGIN;
543 opt->box.right = opt->box.left + width;
544 opt->box.top = PBOOT_RIGHT_OPTION_TMARGIN +
545 index * PBOOT_RIGHT_OPTION_STRIDE;
546 opt->box.bottom = opt->box.top + PBOOT_RIGHT_OPTION_HEIGHT;
553 static void pboot_set_device_select(int sel, int force)
555 LOG("%s: %d -> %d\n", __FUNCTION__, pboot_dev_sel, sel);
556 if (!force && sel == pboot_dev_sel)
558 if (sel >= pboot_dev_count)
562 pboot_lpane->focus_curindex = sel;
564 pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
566 pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF +
567 PBOOT_LEFT_ICON_STRIDE * sel;
568 pboot_rpane->focus_box.bottom = pboot_lpane->focus_target;
569 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
570 PBOOT_RIGHT_FOCUS_HEIGHT;
571 twin_window_damage(pboot_lpane->window,
573 pboot_lpane->window->pixmap->width,
574 pboot_lpane->window->pixmap->height);
575 twin_window_queue_paint(pboot_lpane->window);
577 pboot_rpane->focus_curindex = -1;
578 pboot_rpane->mouse_target = -1;
579 pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
580 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
581 PBOOT_RIGHT_FOCUS_HEIGHT;
582 twin_window_damage(pboot_rpane->window, 0, 0,
583 pboot_rpane->window->pixmap->width,
584 pboot_rpane->window->pixmap->height);
585 twin_window_queue_paint(pboot_rpane->window);
588 static void pboot_create_rpane(void)
590 pboot_rpane = calloc(1, sizeof(pboot_rpane_t));
593 pboot_rpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
595 PBOOT_LEFT_PANE_SIZE, 0,
596 pboot_screen->width -
597 PBOOT_LEFT_PANE_SIZE,
598 pboot_screen->height);
599 assert(pboot_rpane->window);
601 pboot_rpane->window->draw = pboot_rpane_draw;
602 pboot_rpane->window->event = pboot_rpane_event;
603 pboot_rpane->window->client_data = pboot_rpane;
605 pboot_rpane->focus_curindex = -1;
606 pboot_rpane->focus_box.left = PBOOT_RIGHT_FOCUS_XOFF;
607 pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
608 pboot_rpane->focus_box.right = pboot_rpane->window->pixmap->width -
609 2 * PBOOT_RIGHT_FOCUS_XOFF;
610 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
611 PBOOT_RIGHT_FOCUS_HEIGHT;
612 pboot_rpane->mouse_target = -1;
613 twin_window_show(pboot_rpane->window);
614 twin_window_queue_paint(pboot_rpane->window);
618 static twin_time_t pboot_lfocus_timeout (twin_time_t now, void *closure)
620 int dir = 1, dist, pos;
621 const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 1, 2, 2, 3 };
623 dist = abs(pboot_lpane->focus_target - pboot_lpane->focus_start);
624 dir = dist > 2 ? 2 : dist;
625 pos = pboot_lpane->focus_target - (int)pboot_lpane->focus_box.top;
627 pboot_set_device_select(pboot_lpane->focus_curindex, 0);
634 twin_window_damage(pboot_lpane->window,
635 pboot_lpane->focus_box.left,
636 pboot_lpane->focus_box.top,
637 pboot_lpane->focus_box.right,
638 pboot_lpane->focus_box.bottom);
640 pboot_lpane->focus_box.top += dir;
641 pboot_lpane->focus_box.bottom += dir;
643 twin_window_damage(pboot_lpane->window,
644 pboot_lpane->focus_box.left,
645 pboot_lpane->focus_box.top,
646 pboot_lpane->focus_box.right,
647 pboot_lpane->focus_box.bottom);
649 twin_window_queue_paint(pboot_lpane->window);
651 return accel[(pos * 10) / dist];
654 static void pboot_set_lfocus(int index)
656 if (index >= pboot_dev_count)
659 pboot_lpane->focus_start = pboot_lpane->focus_box.top;
662 pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
664 pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF +
665 PBOOT_LEFT_ICON_STRIDE * index;
667 pboot_lpane->focus_curindex = index;
669 twin_set_timeout(pboot_lfocus_timeout, 0, NULL);
672 static void pboot_lpane_mousetrack(twin_coord_t x, twin_coord_t y)
675 twin_coord_t icon_top;
677 if (x < PBOOT_LEFT_ICON_XOFF ||
678 x > (PBOOT_LEFT_ICON_XOFF + PBOOT_LEFT_ICON_WIDTH))
680 if (y < PBOOT_LEFT_ICON_YOFF)
682 candidate = (y - PBOOT_LEFT_ICON_YOFF) / PBOOT_LEFT_ICON_STRIDE;
683 if (candidate >= pboot_dev_count) {
687 if (candidate == pboot_lpane->mouse_target)
689 icon_top = PBOOT_LEFT_ICON_YOFF +
690 candidate * PBOOT_LEFT_ICON_STRIDE;
691 if (y > (icon_top + PBOOT_LEFT_ICON_HEIGHT)) {
696 /* Ok, so now, we know the mouse hit an icon that wasn't the same
697 * as the previous one, we trigger a focus change
699 pboot_set_lfocus(candidate);
702 pboot_lpane->mouse_target = candidate;
705 static twin_bool_t pboot_lpane_event (twin_window_t *window,
708 /* filter out all mouse events */
709 switch(event->kind) {
711 case TwinEventMotion:
713 pboot_select_lpane();
714 pboot_lpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
716 case TwinEventButtonDown:
717 case TwinEventButtonUp:
719 case TwinEventKeyDown:
720 switch(event->u.key.key) {
722 if (pboot_lpane->focus_curindex > 0)
724 pboot_lpane->focus_curindex - 1);
727 pboot_set_lfocus(pboot_lpane->focus_curindex + 1);
730 pboot_select_rpane();
742 static void pboot_quit(void)
747 twin_bool_t pboot_event_filter(twin_screen_t *screen,
750 switch(event->kind) {
752 case TwinEventMotion:
754 case TwinEventButtonDown:
755 case TwinEventButtonUp:
756 if (pboot_cursor != NULL)
757 twin_screen_set_cursor(pboot_screen, pboot_cursor,
761 case TwinEventJoyButton:
762 /* map joystick events into key events */
763 if (event->u.js.control >= sizeof(sixaxis_map))
766 event->u.key.key = sixaxis_map[event->u.js.control];
767 if (event->u.js.value == 0) {
768 event->kind = TwinEventKeyUp;
771 event->kind = TwinEventKeyDown;
775 case TwinEventKeyDown:
776 switch(event->u.key.key) {
777 /* Gross hack for video modes, need something better ! */
779 pboot_vmode_change = 0; /* auto */
783 pboot_vmode_change = 3; /* 720p */
787 pboot_vmode_change = 4; /* 1080i */
791 pboot_vmode_change = 5; /* 1080p */
795 /* Another gross hack for booting back to gameos */
798 pboot_message("booting to GameOS");
799 system(BOOT_GAMEOS_BIN);
803 twin_screen_set_cursor(pboot_screen, NULL, 0, 0);
811 static void pboot_lpane_draw(twin_window_t *window)
813 twin_pixmap_t *px = window->pixmap;
814 pboot_lpane_t *lpane = window->client_data;
816 twin_fixed_t x, y, w, h;
819 /* Fill background */
820 twin_fill(px, PBOOT_LEFT_PANE_COLOR, TWIN_SOURCE,
821 0, 0, px->width, px->height);
823 /* Create a path for use later */
824 path = twin_path_create();
827 /* Draw right line if needed */
828 if (px->clip.right > (PBOOT_LEFT_PANE_SIZE - 4)) {
829 x = twin_int_to_fixed(PBOOT_LEFT_PANE_SIZE - 4);
830 y = twin_int_to_fixed(px->height);
831 twin_path_rectangle(path, x, 0, 0x40000, y);
832 twin_paint_path(px, PBOOT_LEFT_LINE_COLOR, path);
833 twin_path_empty(path);
837 if (lpane->focus_curindex >= 0 &&
838 twin_rect_intersect(lpane->focus_box, px->clip)) {
839 x = twin_int_to_fixed(lpane->focus_box.left + 2);
840 y = twin_int_to_fixed(lpane->focus_box.top + 2);
841 w = twin_int_to_fixed(lpane->focus_box.right -
842 lpane->focus_box.left - 4);
843 h = twin_int_to_fixed(lpane->focus_box.bottom -
844 lpane->focus_box.top - 4);
845 twin_path_rounded_rectangle(path, x, y, w, h,
846 PBOOT_LEFT_FOCUS_XRAD,
847 PBOOT_LEFT_FOCUS_YRAD);
848 if (pboot_focus_lpane)
849 twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
851 twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
856 for (i = 0; i < pboot_dev_count; i++) {
857 pboot_device_t *dev = pboot_devices[i];
860 if (!twin_rect_intersect(dev->box, px->clip))
863 src.source_kind = TWIN_PIXMAP;
864 src.u.pixmap = dev->badge;
866 twin_composite(px, dev->box.left, dev->box.top,
867 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
868 dev->box.right - dev->box.left,
869 dev->box.bottom - dev->box.top);
874 twin_path_destroy(path);
877 static void pboot_create_lpane(void)
879 pboot_lpane = calloc(1, sizeof(pboot_lpane_t));
882 pboot_lpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
884 0, 0, PBOOT_LEFT_PANE_SIZE,
885 pboot_screen->height);
886 assert(pboot_lpane->window);
888 pboot_lpane->window->draw = pboot_lpane_draw;
889 pboot_lpane->window->event = pboot_lpane_event;
890 pboot_lpane->window->client_data = pboot_lpane;
891 pboot_lpane->focus_curindex = -1;
892 pboot_lpane->focus_box.left = PBOOT_LEFT_FOCUS_XOFF;
893 pboot_lpane->focus_box.top = -2*PBOOT_LEFT_FOCUS_HEIGHT;
894 pboot_lpane->focus_box.right = pboot_lpane->focus_box.left +
895 PBOOT_LEFT_FOCUS_WIDTH;
896 pboot_lpane->focus_box.bottom = pboot_lpane->focus_box.top +
897 PBOOT_LEFT_FOCUS_HEIGHT;
898 pboot_lpane->mouse_target = -1;
899 twin_window_show(pboot_lpane->window);
900 twin_window_queue_paint(pboot_lpane->window);
903 static void pboot_spane_draw(twin_window_t *window)
905 twin_pixmap_t *px = window->pixmap;
906 pboot_spane_t *spane = window->client_data;
910 /* Fill background */
911 twin_fill(px, PBOOT_STATUS_PANE_COLOR, TWIN_SOURCE,
912 0, 0, px->width, px->height);
914 path = twin_path_create();
917 twin_path_set_font_size(path, PBOOT_STATUS_TEXT_SIZE);
918 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
919 tx = twin_int_to_fixed(PBOOT_STATUS_TEXT_MARGIN);
920 ty = twin_int_to_fixed(PBOOT_STATUS_PANE_HEIGHT - 2);
921 twin_path_move (path, tx, ty);
922 twin_path_utf8 (path, spane->text);
923 twin_paint_path (px, PBOOT_STATUS_TEXT_COLOR, path);
925 twin_path_destroy(path);
928 void pboot_message(const char *fmt, ...)
933 if (pboot_spane->text)
934 free(pboot_spane->text);
937 vasprintf(&msg, fmt, ap);
940 pboot_spane->text = msg;
941 twin_window_damage(pboot_spane->window,
943 pboot_spane->window->pixmap->width,
944 pboot_spane->window->pixmap->height);
945 twin_window_queue_paint(pboot_spane->window);
948 static void pboot_create_spane(void)
950 pboot_spane = calloc(1, sizeof(pboot_spane_t));
953 pboot_spane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
955 PBOOT_LEFT_PANE_SIZE +
956 PBOOT_STATUS_PANE_XYMARGIN,
957 pboot_screen->height -
958 PBOOT_STATUS_PANE_HEIGHT,
959 pboot_screen->width -
960 PBOOT_LEFT_PANE_SIZE -
961 2*PBOOT_STATUS_PANE_XYMARGIN,
962 PBOOT_STATUS_PANE_HEIGHT);
963 assert(pboot_spane->window);
965 pboot_spane->window->draw = pboot_spane_draw;
966 pboot_spane->window->client_data = pboot_spane;
967 pboot_spane->text = strdup(PBOOT_INITIAL_MESSAGE);
968 twin_window_show(pboot_spane->window);
969 twin_window_queue_paint(pboot_spane->window);
972 int pboot_add_device(const char *dev_id, const char *name,
973 twin_pixmap_t *pixmap)
978 if (pboot_dev_count >= PBOOT_MAX_DEV)
981 index = pboot_dev_count++;
983 dev = malloc(sizeof(*dev));
984 memset(dev, 0, sizeof(*dev));
985 dev->id = malloc(strlen(dev_id) + 1);
986 strcpy(dev->id, dev_id);
988 dev->box.left = PBOOT_LEFT_ICON_XOFF;
989 dev->box.right = dev->box.left + PBOOT_LEFT_ICON_WIDTH;
990 dev->box.top = PBOOT_LEFT_ICON_YOFF +
991 PBOOT_LEFT_ICON_STRIDE * index;
992 dev->box.bottom = dev->box.top + PBOOT_LEFT_ICON_HEIGHT;
994 pboot_devices[index] = dev;
996 twin_window_damage(pboot_lpane->window,
997 dev->box.left, dev->box.top,
998 dev->box.right, dev->box.bottom);
999 twin_window_queue_paint(pboot_lpane->window);
1004 int pboot_remove_device(const char *dev_id)
1006 pboot_device_t *dev = NULL;
1007 int i, newsel = pboot_dev_sel;
1009 /* find the matching device */
1010 for (i = 0; i < pboot_dev_count; i++) {
1011 if (!strcmp(pboot_devices[i]->id, dev_id)) {
1012 dev = pboot_devices[i];
1020 memmove(pboot_devices + i, pboot_devices + i + 1,
1021 sizeof(*pboot_devices) * (pboot_dev_count + i - 1));
1022 pboot_devices[--pboot_dev_count] = NULL;
1024 /* select the newly-focussed device */
1025 if (pboot_dev_sel > i)
1026 newsel = pboot_dev_sel - 1;
1027 else if (pboot_dev_sel == i && i >= pboot_dev_count)
1028 newsel = pboot_dev_count - 1;
1029 pboot_set_device_select(newsel, 1);
1031 /* todo: free device & options */
1036 static void pboot_make_background(void)
1038 twin_pixmap_t *filepic, *scaledpic;
1039 const char *background_path;
1041 /* Set background pixmap */
1042 LOG("loading background...");
1043 background_path = artwork_pathname("background.jpg");
1044 filepic = twin_jpeg_to_pixmap(background_path, TWIN_ARGB32);
1045 LOG("%s\n", filepic ? "ok" : "failed");
1047 if (filepic == NULL)
1050 if (pboot_screen->height == filepic->height &&
1051 pboot_screen->width == filepic->width)
1052 scaledpic = filepic;
1054 twin_fixed_t sx, sy;
1055 twin_operand_t srcop;
1057 scaledpic = twin_pixmap_create(TWIN_ARGB32,
1058 pboot_screen->width,
1059 pboot_screen->height);
1060 if (scaledpic == NULL) {
1061 twin_pixmap_destroy(filepic);
1064 sx = twin_fixed_div(twin_int_to_fixed(filepic->width),
1065 twin_int_to_fixed(pboot_screen->width));
1066 sy = twin_fixed_div(twin_int_to_fixed(filepic->height),
1067 twin_int_to_fixed(pboot_screen->height));
1069 twin_matrix_scale(&filepic->transform, sx, sy);
1070 srcop.source_kind = TWIN_PIXMAP;
1071 srcop.u.pixmap = filepic;
1072 twin_composite(scaledpic, 0, 0, &srcop, 0, 0,
1073 NULL, 0, 0, TWIN_SOURCE,
1074 pboot_screen->width, pboot_screen->height);
1075 twin_pixmap_destroy(filepic);
1078 twin_screen_set_background(pboot_screen, scaledpic);
1081 #define PS3FB_IOCTL_SETMODE _IOW('r', 1, int)
1082 #define PS3FB_IOCTL_GETMODE _IOR('r', 2, int)
1084 static void exitfunc(void)
1088 twin_fbdev_destroy(pboot_fbdev);
1090 if (pboot_vmode_change != -1) {
1091 int fd = open("/dev/fb0", O_RDWR);
1093 ioctl(fd, PS3FB_IOCTL_SETMODE,
1094 (unsigned long)&pboot_vmode_change);
1100 static void sigint(int sig)
1106 static void usage(const char *progname)
1108 fprintf(stderr, "Usage: %s [-u] [-h]\n", progname);
1111 int main(int argc, char **argv)
1114 int udev_trigger = 0;
1117 c = getopt(argc, argv, "u::h");
1127 return EXIT_SUCCESS;
1129 fprintf(stderr, "Unknown option '%c'\n", c);
1131 return EXIT_FAILURE;
1136 signal(SIGINT, sigint);
1139 pboot_x11 = twin_x11_create(XOpenDisplay(0), 1024, 768);
1140 if (pboot_x11 == NULL) {
1141 perror("failed to create x11 screen !\n");
1144 pboot_screen = pboot_x11->screen;
1146 /* Create screen and mouse drivers */
1147 pboot_fbdev = twin_fbdev_create(-1, SIGUSR1);
1148 if (pboot_fbdev == NULL) {
1149 perror("failed to create fbdev screen !\n");
1152 pboot_screen = pboot_fbdev->screen;
1153 twin_linux_mouse_create(NULL, pboot_screen);
1154 twin_linux_js_create(pboot_screen);
1156 if (pboot_fbdev != NULL) {
1157 char *cursor_path = artwork_pathname("cursor.gz");
1158 pboot_cursor = twin_load_X_cursor(cursor_path, 2,
1161 if (pboot_cursor == NULL)
1163 twin_get_default_cursor(&pboot_cursor_hx,
1168 /* Set background pixmap */
1169 pboot_make_background();
1171 /* Init more stuffs */
1172 pboot_create_lpane();
1173 pboot_create_rpane();
1174 pboot_create_spane();
1176 if (!pboot_start_device_discovery(udev_trigger)) {
1177 LOG("Couldn't start device discovery!\n");
1181 pboot_set_lfocus(0);
1182 twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
1183 pboot_screen->event_filter = pboot_event_filter;
1185 /* Console switch */
1188 twin_fbdev_activate(pboot_fbdev);
1191 /* Process events */