X-Git-Url: https://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=petitboot.c;h=6f2a386fe90cbc021fc4317b3d618eccb027add7;hp=e69353e6b4dbc0bd70300d6d70507a5fd87749f0;hb=ba15ae87098f62df9f7c81a71c3882d05e8c8d80;hpb=f60d0b2e7dbd9d85980866c68d0f87b6bc823663 diff --git a/petitboot.c b/petitboot.c index e69353e..6f2a386 100644 --- a/petitboot.c +++ b/petitboot.c @@ -1,34 +1,50 @@ + +#define _GNU_SOURCE + #include +#include #include #include #include #include #include +#include +#include #include +#undef _USE_X11 + #include -#include -#include #include +#include #include +#include #include "petitboot.h" +#include "petitboot-paths.h" -#define _USE_X11 - -static twin_fbdev_t *pboot_fbdev; +#ifdef _USE_X11 +#include static twin_x11_t *pboot_x11; +#else +#include +static twin_fbdev_t *pboot_fbdev; +#endif + static twin_screen_t *pboot_screen; -#define PBOOT_LEFT_PANE_SIZE 200 +#define PBOOT_INITIAL_MESSAGE \ + "keys: 0=safe 1=720p 2=1080i 3=1080p del=GameOS" + +#define PBOOT_LEFT_PANE_SIZE 160 #define PBOOT_LEFT_PANE_COLOR 0x80000000 #define PBOOT_LEFT_LINE_COLOR 0xff000000 #define PBOOT_LEFT_FOCUS_WIDTH 80 #define PBOOT_LEFT_FOCUS_HEIGHT 80 -#define PBOOT_LEFT_FOCUS_XOFF 60 -#define PBOOT_LEFT_FOCUS_YOFF 60 +#define PBOOT_LEFT_FOCUS_XOFF 40 +#define PBOOT_LEFT_FOCUS_YOFF 40 #define PBOOT_LEFT_FOCUS_XRAD (6 * TWIN_FIXED_ONE) #define PBOOT_LEFT_FOCUS_YRAD (6 * TWIN_FIXED_ONE) @@ -40,8 +56,8 @@ static twin_screen_t *pboot_screen; #define PBOOT_LEFT_ICON_WIDTH 64 #define PBOOT_LEFT_ICON_HEIGHT 64 -#define PBOOT_LEFT_ICON_XOFF 70 -#define PBOOT_LEFT_ICON_YOFF 70 +#define PBOOT_LEFT_ICON_XOFF 50 +#define PBOOT_LEFT_ICON_YOFF 50 #define PBOOT_LEFT_ICON_STRIDE 100 #define PBOOT_RIGHT_OPTION_LMARGIN 30 @@ -53,7 +69,7 @@ static twin_screen_t *pboot_screen; #define PBOOT_RIGHT_SUBTITLE_TEXT_SIZE (18 * TWIN_FIXED_ONE) #define PBOOT_RIGHT_TITLE_XOFFSET 80 #define PBOOT_RIGHT_TITLE_YOFFSET 30 -#define PBOOT_RIGHT_SUBTITLE_XOFFSET 200 +#define PBOOT_RIGHT_SUBTITLE_XOFFSET 100 #define PBOOT_RIGHT_SUBTITLE_YOFFSET 50 #define PBOOT_RIGHT_BADGE_XOFFSET 2 #define PBOOT_RIGHT_BADGE_YOFFSET 0 @@ -64,6 +80,12 @@ static twin_screen_t *pboot_screen; #define PBOOT_FOCUS_COLOR 0x10404040 +#define PBOOT_STATUS_PANE_COLOR 0x60606060 +#define PBOOT_STATUS_PANE_HEIGHT 20 +#define PBOOT_STATUS_PANE_XYMARGIN 20 +#define PBOOT_STATUS_TEXT_MARGIN 10 +#define PBOOT_STATUS_TEXT_SIZE (16 * TWIN_FIXED_ONE) +#define PBOOT_STATUS_TEXT_COLOR 0xff000000 typedef struct _pboot_option pboot_option_t; typedef struct _pboot_device pboot_device_t; @@ -75,6 +97,7 @@ struct _pboot_option twin_pixmap_t *badge; twin_pixmap_t *cache; twin_rect_t box; + void *data; }; struct _pboot_device @@ -113,8 +136,40 @@ typedef struct _pboot_rpane { int mouse_target; } pboot_rpane_t; +typedef struct _pboot_spane { + twin_window_t *window; + char *text; +} pboot_spane_t; + static pboot_lpane_t *pboot_lpane; static pboot_rpane_t *pboot_rpane; +static pboot_spane_t *pboot_spane; + +/* control to keyboard mappings for the sixaxis controller */ +uint8_t sixaxis_map[] = { + 0, /* 0 Select */ + 0, /* 1 L3 */ + 0, /* 2 R3 */ + 0, /* 3 Start */ + KEY_UP, /* 4 Dpad Up */ + KEY_RIGHT, /* 5 Dpad Right */ + KEY_DOWN, /* 6 Dpad Down */ + KEY_LEFT, /* 7 Dpad Left */ + 0, /* 8 L2 */ + 0, /* 9 R2 */ + 0, /* 10 L1 */ + 0, /* 11 R1 */ + 0, /* 12 Triangle */ + KEY_ENTER, /* 13 Circle */ + 0, /* 14 Cross */ + KEY_DELETE, /* 15 Square */ + 0, /* 16 PS Button */ + 0, /* 17 nothing */ + 0, /* 18 nothing */ +}; + + +static int pboot_vmode_change = -1; /* XXX move to twin */ static inline twin_bool_t twin_rect_intersect(twin_rect_t r1, @@ -263,7 +318,7 @@ static void pboot_rpane_draw(twin_window_t *window) static twin_time_t pboot_rfocus_timeout (twin_time_t now, void *closure) { int dir = 1, dist, pos; - const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 2, 3, 4, 5 }; + const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 1, 2, 2, 3 }; dist = abs(pboot_rpane->focus_target - pboot_rpane->focus_start); dir = dist > 5 ? 5 : dist; @@ -399,6 +454,18 @@ static void pboot_rpane_mousetrack(twin_coord_t x, twin_coord_t y) pboot_rpane->mouse_target = candidate; } +static void pboot_choose_option(void) +{ + pboot_device_t *dev = pboot_devices[pboot_dev_sel]; + pboot_option_t *opt = &dev->options[pboot_rpane->focus_curindex]; + + LOG("Selected device %s\n", opt->title); + pboot_message("booting %s...", opt->title); + + /* Give user feedback, make sure errors and panics will be seen */ + pboot_exec_option(opt->data); +} + static twin_bool_t pboot_rpane_event (twin_window_t *window, twin_event_t *event) { @@ -411,6 +478,9 @@ static twin_bool_t pboot_rpane_event (twin_window_t *window, pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y); return TWIN_TRUE; case TwinEventButtonDown: + pboot_select_rpane(); + pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y); + pboot_choose_option(); case TwinEventButtonUp: return TWIN_TRUE; case TwinEventKeyDown: @@ -424,6 +494,8 @@ static twin_bool_t pboot_rpane_event (twin_window_t *window, case KEY_LEFT: pboot_select_lpane(); return TWIN_TRUE; + case KEY_ENTER: + pboot_choose_option(); default: break; } @@ -436,7 +508,7 @@ static twin_bool_t pboot_rpane_event (twin_window_t *window, int pboot_add_option(int devindex, const char *title, - const char *subtitle, twin_pixmap_t *badge) + const char *subtitle, twin_pixmap_t *badge, void *data) { pboot_device_t *dev; pboot_option_t *opt; @@ -473,16 +545,35 @@ int pboot_add_option(int devindex, const char *title, index * PBOOT_RIGHT_OPTION_STRIDE; opt->box.bottom = opt->box.top + PBOOT_RIGHT_OPTION_HEIGHT; + opt->data = data; return index; } -static void pboot_set_device_select(int sel) +static void pboot_set_device_select(int sel, int force) { LOG("%s: %d -> %d\n", __FUNCTION__, pboot_dev_sel, sel); - if (sel == pboot_dev_sel || sel >= pboot_dev_count) + if (!force && sel == pboot_dev_sel) + return; + if (sel >= pboot_dev_count) return; pboot_dev_sel = sel; + if (force) { + pboot_lpane->focus_curindex = sel; + if (sel < 0) + pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT; + else + pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF + + PBOOT_LEFT_ICON_STRIDE * sel; + pboot_rpane->focus_box.bottom = pboot_lpane->focus_target; + pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top + + PBOOT_RIGHT_FOCUS_HEIGHT; + twin_window_damage(pboot_lpane->window, + 0, 0, + pboot_lpane->window->pixmap->width, + pboot_lpane->window->pixmap->height); + twin_window_queue_paint(pboot_lpane->window); + } pboot_rpane->focus_curindex = -1; pboot_rpane->mouse_target = -1; pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT; @@ -494,15 +585,46 @@ static void pboot_set_device_select(int sel) twin_window_queue_paint(pboot_rpane->window); } +static void pboot_create_rpane(void) +{ + pboot_rpane = calloc(1, sizeof(pboot_rpane_t)); + assert(pboot_rpane); + + pboot_rpane->window = twin_window_create(pboot_screen, TWIN_ARGB32, + TwinWindowPlain, + PBOOT_LEFT_PANE_SIZE, 0, + pboot_screen->width - + PBOOT_LEFT_PANE_SIZE, + pboot_screen->height); + assert(pboot_rpane->window); + + pboot_rpane->window->draw = pboot_rpane_draw; + pboot_rpane->window->event = pboot_rpane_event; + pboot_rpane->window->client_data = pboot_rpane; + + pboot_rpane->focus_curindex = -1; + pboot_rpane->focus_box.left = PBOOT_RIGHT_FOCUS_XOFF; + pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT; + pboot_rpane->focus_box.right = pboot_rpane->window->pixmap->width - + 2 * PBOOT_RIGHT_FOCUS_XOFF; + pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top + + PBOOT_RIGHT_FOCUS_HEIGHT; + pboot_rpane->mouse_target = -1; + twin_window_show(pboot_rpane->window); + twin_window_queue_paint(pboot_rpane->window); +} + + static twin_time_t pboot_lfocus_timeout (twin_time_t now, void *closure) { int dir = 1, dist, pos; - const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 2, 3, 4, 5 }; + const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 1, 2, 2, 3 }; dist = abs(pboot_lpane->focus_target - pboot_lpane->focus_start); + dir = dist > 2 ? 2 : dist; pos = pboot_lpane->focus_target - (int)pboot_lpane->focus_box.top; if (pos == 0) { - pboot_set_device_select(pboot_lpane->focus_curindex); + pboot_set_device_select(pboot_lpane->focus_curindex, 0); return -1; } if (pos < 0) { @@ -617,6 +739,11 @@ static twin_bool_t pboot_lpane_event (twin_window_t *window, return TWIN_FALSE; } +static void pboot_quit(void) +{ + kill(0, SIGINT); +} + twin_bool_t pboot_event_filter(twin_screen_t *screen, twin_event_t *event) { @@ -631,7 +758,47 @@ twin_bool_t pboot_event_filter(twin_screen_t *screen, pboot_cursor_hx, pboot_cursor_hy); break; + case TwinEventJoyButton: + /* map joystick events into key events */ + if (event->u.js.control >= sizeof(sixaxis_map)) + break; + + event->u.key.key = sixaxis_map[event->u.js.control]; + if (event->u.js.value == 0) { + event->kind = TwinEventKeyUp; + break; + } else { + event->kind = TwinEventKeyDown; + } + + /* fall through.. */ case TwinEventKeyDown: + switch(event->u.key.key) { + /* Gross hack for video modes, need something better ! */ + case KEY_0: + pboot_vmode_change = 0; /* auto */ + pboot_quit(); + return TWIN_TRUE; + case KEY_1: + pboot_vmode_change = 3; /* 720p */ + pboot_quit(); + return TWIN_TRUE; + case KEY_2: + pboot_vmode_change = 4; /* 1080i */ + pboot_quit(); + return TWIN_TRUE; + case KEY_3: + pboot_vmode_change = 5; /* 1080p */ + pboot_quit(); + return TWIN_TRUE; + + /* Another gross hack for booting back to gameos */ + case KEY_BACKSPACE: + case KEY_DELETE: + pboot_message("booting to GameOS"); + system(BOOT_GAMEOS_BIN); + pboot_quit(); + } case TwinEventKeyUp: twin_screen_set_cursor(pboot_screen, NULL, 0, 0); break; @@ -707,9 +874,8 @@ static void pboot_lpane_draw(twin_window_t *window) twin_path_destroy(path); } -static void pboot_create_panels(void) +static void pboot_create_lpane(void) { - /* left pane */ pboot_lpane = calloc(1, sizeof(pboot_lpane_t)); assert(pboot_lpane); @@ -731,32 +897,76 @@ static void pboot_create_panels(void) PBOOT_LEFT_FOCUS_HEIGHT; pboot_lpane->mouse_target = -1; twin_window_show(pboot_lpane->window); + twin_window_queue_paint(pboot_lpane->window); +} - /* right pane */ - pboot_rpane = calloc(1, sizeof(pboot_rpane_t)); - assert(pboot_rpane); +static void pboot_spane_draw(twin_window_t *window) +{ + twin_pixmap_t *px = window->pixmap; + pboot_spane_t *spane = window->client_data; + twin_path_t *path; + twin_fixed_t tx, ty; - pboot_rpane->window = twin_window_create(pboot_screen, TWIN_ARGB32, - TwinWindowPlain, - PBOOT_LEFT_PANE_SIZE, 0, - pboot_screen->width - - PBOOT_LEFT_PANE_SIZE, - pboot_screen->height); - assert(pboot_rpane->window); + /* Fill background */ + twin_fill(px, PBOOT_STATUS_PANE_COLOR, TWIN_SOURCE, + 0, 0, px->width, px->height); - pboot_rpane->window->draw = pboot_rpane_draw; - pboot_rpane->window->event = pboot_rpane_event; - pboot_rpane->window->client_data = pboot_rpane; + path = twin_path_create(); + assert(path); - pboot_rpane->focus_curindex = -1; - pboot_rpane->focus_box.left = PBOOT_RIGHT_FOCUS_XOFF; - pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT; - pboot_rpane->focus_box.right = pboot_rpane->window->pixmap->width - - 2 * PBOOT_RIGHT_FOCUS_XOFF; - pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top + - PBOOT_RIGHT_FOCUS_HEIGHT; - pboot_rpane->mouse_target = -1; - twin_window_show(pboot_rpane->window); + twin_path_set_font_size(path, PBOOT_STATUS_TEXT_SIZE); + twin_path_set_font_style(path, TWIN_TEXT_UNHINTED); + tx = twin_int_to_fixed(PBOOT_STATUS_TEXT_MARGIN); + ty = twin_int_to_fixed(PBOOT_STATUS_PANE_HEIGHT - 2); + twin_path_move (path, tx, ty); + twin_path_utf8 (path, spane->text); + twin_paint_path (px, PBOOT_STATUS_TEXT_COLOR, path); + + twin_path_destroy(path); +} + +void pboot_message(const char *fmt, ...) +{ + va_list ap; + char *msg; + + if (pboot_spane->text) + free(pboot_spane->text); + + va_start(ap, fmt); + vasprintf(&msg, fmt, ap); + va_end(ap); + + pboot_spane->text = msg; + twin_window_damage(pboot_spane->window, + 0, 0, + pboot_spane->window->pixmap->width, + pboot_spane->window->pixmap->height); + twin_window_queue_paint(pboot_spane->window); +} + +static void pboot_create_spane(void) +{ + pboot_spane = calloc(1, sizeof(pboot_spane_t)); + assert(pboot_spane); + + pboot_spane->window = twin_window_create(pboot_screen, TWIN_ARGB32, + TwinWindowPlain, + PBOOT_LEFT_PANE_SIZE + + PBOOT_STATUS_PANE_XYMARGIN, + pboot_screen->height - + PBOOT_STATUS_PANE_HEIGHT, + pboot_screen->width - + PBOOT_LEFT_PANE_SIZE - + 2*PBOOT_STATUS_PANE_XYMARGIN, + PBOOT_STATUS_PANE_HEIGHT); + assert(pboot_spane->window); + + pboot_spane->window->draw = pboot_spane_draw; + pboot_spane->window->client_data = pboot_spane; + pboot_spane->text = strdup(PBOOT_INITIAL_MESSAGE); + twin_window_show(pboot_spane->window); + twin_window_queue_paint(pboot_spane->window); } int pboot_add_device(const char *dev_id, const char *name, @@ -793,8 +1003,8 @@ int pboot_add_device(const char *dev_id, const char *name, int pboot_remove_device(const char *dev_id) { - int i, new_dev_index; pboot_device_t *dev = NULL; + int i, newsel = pboot_dev_sel; /* find the matching device */ for (i = 0; i < pboot_dev_count; i++) { @@ -807,33 +1017,84 @@ int pboot_remove_device(const char *dev_id) if (!dev) return TWIN_FALSE; - /* select the newly-focussed device */ - if (i == pboot_dev_count - 1) - new_dev_index = i - 1; - else - new_dev_index = i + 1; - memmove(pboot_devices + i, pboot_devices + i + 1, sizeof(*pboot_devices) * (pboot_dev_count + i - 1)); - pboot_devices[--pboot_dev_count] = NULL; - pboot_set_device_select(new_dev_index); - twin_window_damage(pboot_lpane->window, - dev->box.left, dev->box.top, - dev->box.right, dev->box.bottom); - twin_window_queue_paint(pboot_lpane->window); + /* select the newly-focussed device */ + if (pboot_dev_sel > i) + newsel = pboot_dev_sel - 1; + else if (pboot_dev_sel == i && i >= pboot_dev_count) + newsel = pboot_dev_count - 1; + pboot_set_device_select(newsel, 1); /* todo: free device & options */ return TWIN_TRUE; } +static void pboot_make_background(void) +{ + twin_pixmap_t *filepic, *scaledpic; + const char *background_path; + + /* Set background pixmap */ + LOG("loading background..."); + background_path = artwork_pathname("background.jpg"); + filepic = twin_jpeg_to_pixmap(background_path, TWIN_ARGB32); + LOG("%s\n", filepic ? "ok" : "failed"); + + if (filepic == NULL) + return; + + if (pboot_screen->height == filepic->height && + pboot_screen->width == filepic->width) + scaledpic = filepic; + else { + twin_fixed_t sx, sy; + twin_operand_t srcop; + + scaledpic = twin_pixmap_create(TWIN_ARGB32, + pboot_screen->width, + pboot_screen->height); + if (scaledpic == NULL) { + twin_pixmap_destroy(filepic); + return; + } + sx = twin_fixed_div(twin_int_to_fixed(filepic->width), + twin_int_to_fixed(pboot_screen->width)); + sy = twin_fixed_div(twin_int_to_fixed(filepic->height), + twin_int_to_fixed(pboot_screen->height)); + + twin_matrix_scale(&filepic->transform, sx, sy); + srcop.source_kind = TWIN_PIXMAP; + srcop.u.pixmap = filepic; + twin_composite(scaledpic, 0, 0, &srcop, 0, 0, + NULL, 0, 0, TWIN_SOURCE, + pboot_screen->width, pboot_screen->height); + twin_pixmap_destroy(filepic); + + } + twin_screen_set_background(pboot_screen, scaledpic); +} + +#define PS3FB_IOCTL_SETMODE _IOW('r', 1, int) +#define PS3FB_IOCTL_GETMODE _IOR('r', 2, int) + static void exitfunc(void) { +#ifndef _USE_X11 if (pboot_fbdev) twin_fbdev_destroy(pboot_fbdev); pboot_fbdev = NULL; + if (pboot_vmode_change != -1) { + int fd = open("/dev/fb0", O_RDWR); + if (fd >= 0) + ioctl(fd, PS3FB_IOCTL_SETMODE, + (unsigned long)&pboot_vmode_change); + close(fd); + } +#endif } static void sigint(int sig) @@ -842,9 +1103,34 @@ static void sigint(int sig) syscall(__NR_exit); } +static void usage(const char *progname) +{ + fprintf(stderr, "Usage: %s [-u] [-h]\n", progname); +} + int main(int argc, char **argv) { - twin_pixmap_t *pic; + int c; + int udev_trigger = 0; + + for (;;) { + c = getopt(argc, argv, "u::h"); + if (c == -1) + break; + + switch (c) { + case 'u': + udev_trigger = 1; + break; + case 'h': + usage(argv[0]); + return EXIT_SUCCESS; + default: + fprintf(stderr, "Unknown option '%c'\n", c); + usage(argv[0]); + return EXIT_FAILURE; + } + } atexit(exitfunc); signal(SIGINT, sigint); @@ -865,10 +1151,11 @@ int main(int argc, char **argv) } pboot_screen = pboot_fbdev->screen; twin_linux_mouse_create(NULL, pboot_screen); -#endif + twin_linux_js_create(pboot_screen); if (pboot_fbdev != NULL) { - pboot_cursor = twin_load_X_cursor("artwork/cursor", 2, + char *cursor_path = artwork_pathname("cursor.gz"); + pboot_cursor = twin_load_X_cursor(cursor_path, 2, &pboot_cursor_hx, &pboot_cursor_hy); if (pboot_cursor == NULL) @@ -876,20 +1163,17 @@ int main(int argc, char **argv) twin_get_default_cursor(&pboot_cursor_hx, &pboot_cursor_hy); } +#endif /* Set background pixmap */ - LOG("loading background..."); - pic = twin_png_to_pixmap("artwork/background.png", TWIN_ARGB32); - LOG("%s\n", pic ? "ok" : "failed"); - if (pic) - twin_screen_set_background(pboot_screen, pic); + pboot_make_background(); /* Init more stuffs */ - pboot_create_panels(); - twin_window_queue_paint(pboot_lpane->window); - twin_window_queue_paint(pboot_rpane->window); + pboot_create_lpane(); + pboot_create_rpane(); + pboot_create_spane(); - if (!pboot_start_device_discovery()) { + if (!pboot_start_device_discovery(udev_trigger)) { LOG("Couldn't start device discovery!\n"); return 1; } @@ -899,8 +1183,10 @@ int main(int argc, char **argv) pboot_screen->event_filter = pboot_event_filter; /* Console switch */ +#ifndef _USE_X11 if (pboot_fbdev) twin_fbdev_activate(pboot_fbdev); +#endif /* Process events */ twin_dispatch ();