From patchwork Fri Nov 7 00:21:23 2008 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Geoff Levand X-Patchwork-Id: 7635 X-Patchwork-Delegate: jk@ozlabs.org Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from ozlabs.org (localhost [127.0.0.1]) by ozlabs.org (Postfix) with ESMTP id 9EA40DE18E for ; Fri, 7 Nov 2008 11:23:51 +1100 (EST) X-Original-To: cbe-oss-dev@ozlabs.org Delivered-To: cbe-oss-dev@ozlabs.org Received: from VA3EHSOBE001.bigfish.com (outbound-va3.frontbridge.com [216.32.180.16]) by ozlabs.org (Postfix) with ESMTP id E0E56DDFD7; Fri, 7 Nov 2008 11:22:27 +1100 (EST) Received: from mail141-va3-R.bigfish.com (10.7.14.245) by VA3EHSOBE001.bigfish.com (10.7.40.21) with Microsoft SMTP Server id 8.1.291.1; Fri, 7 Nov 2008 00:22:25 +0000 Received: from mail141-va3 (localhost.localdomain [127.0.0.1]) by mail141-va3-R.bigfish.com (Postfix) with ESMTP id F351B88055F; Fri, 7 Nov 2008 00:22:24 +0000 (UTC) X-BigFish: VPS-11(zz1803O655O853kzzzzz2fh6bh62h) X-Spam-TCS-SCL: 1:0 X-FB-SS: 5, Received: by mail141-va3 (MessageSwitch) id 1226017332655000_29815; Fri, 7 Nov 2008 00:22:12 +0000 (UCT) Received: from mail8.fw-bc.sony.com (mail8.fw-bc.sony.com [160.33.98.75]) by mail141-va3.bigfish.com (Postfix) with ESMTP id 81E031C68075; Fri, 7 Nov 2008 00:22:12 +0000 (UTC) Received: from mail3.sjc.in.sel.sony.com (mail3.sjc.in.sel.sony.com [43.134.1.211]) by mail8.fw-bc.sony.com (8.14.2/8.14.2) with ESMTP id mA70MBkG007996; Fri, 7 Nov 2008 00:22:11 GMT Received: from ussdixhub21.spe.sony.com (ussdixhub21.spe.sony.com [43.130.141.76]) by mail3.sjc.in.sel.sony.com (8.12.11/8.12.11) with ESMTP id mA70MBsB000592; Fri, 7 Nov 2008 00:22:11 GMT Received: from USSDIXRG02.am.sony.com (43.130.140.32) by ussdixhub21.spe.sony.com (43.130.141.76) with Microsoft SMTP Server id 8.1.291.1; Thu, 6 Nov 2008 16:22:11 -0800 Received: from ussdixms03.am.sony.com ([43.130.140.23]) by USSDIXRG02.am.sony.com with Microsoft SMTPSVC(5.0.2195.6713); Thu, 6 Nov 2008 16:22:11 -0800 Received: from [192.168.1.10] ([43.135.148.226]) by ussdixms03.am.sony.com with Microsoft SMTPSVC(5.0.2195.6713); Thu, 6 Nov 2008 16:22:10 -0800 Message-ID: <49138A03.7010606@am.sony.com> Date: Thu, 6 Nov 2008 16:21:23 -0800 From: Geoff Levand User-Agent: Thunderbird 2.0.0.16 (X11/20080723) MIME-Version: 1.0 To: jk@ozlabs.org References: <491385D1.2070704@am.sony.com> In-Reply-To: <491385D1.2070704@am.sony.com> X-Enigmail-Version: 0.95.7 X-OriginalArrivalTime: 07 Nov 2008 00:22:10.0593 (UTC) FILETIME=[E0076110:01C9406E] X-SEL-encryption-scan: scanned Cc: cbe-oss-dev@ozlabs.org Subject: [Cbe-oss-dev] [patch 7/9] petitboot: Rename petitboot to petitboot-gui X-BeenThere: cbe-oss-dev@ozlabs.org X-Mailman-Version: 2.1.11 Precedence: list List-Id: Discussion about Open Source Software for the Cell Broadband Engine List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: cbe-oss-dev-bounces+patchwork-incoming=ozlabs.org@ozlabs.org Errors-To: cbe-oss-dev-bounces+patchwork-incoming=ozlabs.org@ozlabs.org From: Yuji Mano Rename the petitboot to petitboot-gui. This eliminates a name clash with the library header petitboot.h, and distinguishes the GUI binary from petitboot-cui, the command-line binary. Signed-off-by: Yuji Mano Signed-off-by: Geoff Levand --- This change is a step to convert petitboot into a collection of applications linking to a core petitboot library. Makefile.am | 10 devices.c | 2 petitboot-gui.c | 1194 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ petitboot-gui.h | 18 petitboot.c | 1194 -------------------------------------------------------- petitboot.h | 18 6 files changed, 1218 insertions(+), 1218 deletions(-) --- a/Makefile.am +++ b/Makefile.am @@ -32,10 +32,10 @@ AM_CFLAGS = \ AM_LDFLAGS = -L$(libdir) -sbin_PROGRAMS = petitboot-udev-helper petitboot +sbin_PROGRAMS = petitboot-udev-helper petitboot-gui petitboot_headers = \ - petitboot.h \ + petitboot-gui.h \ lib/petitboot-paths.h \ lib/params.h \ lib/yaboot-cfg.h \ @@ -54,11 +54,11 @@ petitboot_udev_helper_SOURCES = \ lib/yaboot-parser.c \ lib/kboot-parser.c -petitboot_SOURCES = \ +petitboot_gui_SOURCES = \ $(petitboot_headers) \ - petitboot.c \ + petitboot-gui.c \ devices.c -petitboot_LDADD = -ltwin -lpng -ljpeg -lz -lm +petitboot_gui_LDADD = -ltwin -lpng -ljpeg -lz -lm EXTRA_DIST = bootstrap --- a/devices.c +++ b/devices.c @@ -9,7 +9,7 @@ #include #include -#include "petitboot.h" +#include "petitboot-gui.h" #include "petitboot-paths.h" #include "message.h" --- /dev/null +++ b/petitboot-gui.c @@ -0,0 +1,1194 @@ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#undef _USE_X11 + +#include +#include +#include +#include +#include + +#include "petitboot-gui.h" +#include "petitboot-paths.h" + +#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_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 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) + +#define PBOOT_RIGHT_FOCUS_XOFF 20 +#define PBOOT_RIGHT_FOCUS_YOFF 60 +#define PBOOT_RIGHT_FOCUS_HEIGHT 80 +#define PBOOT_RIGHT_FOCUS_XRAD (6 * TWIN_FIXED_ONE) +#define PBOOT_RIGHT_FOCUS_YRAD (6 * TWIN_FIXED_ONE) + +#define PBOOT_LEFT_ICON_WIDTH 64 +#define PBOOT_LEFT_ICON_HEIGHT 64 +#define PBOOT_LEFT_ICON_XOFF 50 +#define PBOOT_LEFT_ICON_YOFF 50 +#define PBOOT_LEFT_ICON_STRIDE 100 + +#define PBOOT_RIGHT_OPTION_LMARGIN 30 +#define PBOOT_RIGHT_OPTION_RMARGIN 30 +#define PBOOT_RIGHT_OPTION_TMARGIN 70 +#define PBOOT_RIGHT_OPTION_HEIGHT 64 +#define PBOOT_RIGHT_OPTION_STRIDE 100 +#define PBOOT_RIGHT_TITLE_TEXT_SIZE (30 * TWIN_FIXED_ONE) +#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 100 +#define PBOOT_RIGHT_SUBTITLE_YOFFSET 50 +#define PBOOT_RIGHT_BADGE_XOFFSET 2 +#define PBOOT_RIGHT_BADGE_YOFFSET 0 + + +#define PBOOT_RIGHT_TITLE_COLOR 0xff000000 +#define PBOOT_RIGHT_SUBTITLE_COLOR 0xff400000 + +#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; + +struct _pboot_option +{ + char *title; + char *subtitle; + twin_pixmap_t *badge; + twin_pixmap_t *cache; + twin_rect_t box; + void *data; +}; + +struct _pboot_device +{ + char *id; + twin_pixmap_t *badge; + twin_rect_t box; + int option_count; + pboot_option_t options[PBOOT_MAX_OPTION]; +}; + +static twin_pixmap_t *pboot_cursor; +static int pboot_cursor_hx; +static int pboot_cursor_hy; + +static pboot_device_t *pboot_devices[PBOOT_MAX_DEV]; +static int pboot_dev_count; +static int pboot_dev_sel = -1; +static int pboot_focus_lpane = 1; + +typedef struct _pboot_lpane { + twin_window_t *window; + twin_rect_t focus_box; + int focus_start; + int focus_target; + int focus_curindex; + int mouse_target; +} pboot_lpane_t; + +typedef struct _pboot_rpane { + twin_window_t *window; + twin_rect_t focus_box; + int focus_start; + int focus_target; + int focus_curindex; + 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, + twin_rect_t r2) +{ + return !(r1.left > r2.right || + r1.right < r2.left || + r1.top > r2.bottom || + r1.bottom < r2.top); +} + +static void pboot_draw_option_cache(pboot_device_t *dev, pboot_option_t *opt, + int index) +{ + twin_pixmap_t *px; + twin_path_t *path; + twin_fixed_t tx, ty; + + /* Create pixmap */ + px = twin_pixmap_create(TWIN_ARGB32, opt->box.right - opt->box.left, + opt->box.bottom - opt->box.top); + assert(px); + opt->cache = px; + + /* Fill background */ + twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height); + + /* Allocate a path for drawing */ + path = twin_path_create(); + assert(path); + +#if 0 + /* TEST - Bounding rectangle */ + twin_path_rectangle(path, 0, 0, + twin_int_to_fixed(px->width), + twin_int_to_fixed(px->height)); + twin_paint_path(px, PBOOT_RIGHT_TITLE_COLOR, path); + twin_path_empty(path); + twin_fill(px, 0x00000000, TWIN_SOURCE, 2, 2, + px->width - 3, px->height - 3); +#endif + + /* Draw texts */ + twin_path_set_font_size(path, PBOOT_RIGHT_TITLE_TEXT_SIZE); + twin_path_set_font_style(path, TWIN_TEXT_UNHINTED); + tx = twin_int_to_fixed(PBOOT_RIGHT_TITLE_XOFFSET); + ty = twin_int_to_fixed(PBOOT_RIGHT_TITLE_YOFFSET); + twin_path_move (path, tx, ty); + twin_path_utf8 (path, opt->title); + twin_paint_path (px, PBOOT_RIGHT_TITLE_COLOR, path); + twin_path_empty (path); + + if (opt->subtitle) { + twin_path_set_font_size(path, PBOOT_RIGHT_SUBTITLE_TEXT_SIZE); + twin_path_set_font_style(path, TWIN_TEXT_UNHINTED); + tx = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_XOFFSET); + ty = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_YOFFSET); + twin_path_move (path, tx, ty); + twin_path_utf8 (path, opt->subtitle); + twin_paint_path (px, PBOOT_RIGHT_SUBTITLE_COLOR, path); + twin_path_empty (path); + } + + if (opt->badge) { + twin_operand_t src; + + src.source_kind = TWIN_PIXMAP; + src.u.pixmap = opt->badge; + + twin_composite(px, PBOOT_RIGHT_BADGE_XOFFSET, + PBOOT_RIGHT_BADGE_YOFFSET, + &src, 0, 0, NULL, 0, 0, TWIN_OVER, + opt->badge->width, opt->badge->height); + } + + + /* Destroy path */ + twin_path_destroy(path); +} + +static void pboot_rpane_draw(twin_window_t *window) +{ + twin_pixmap_t *px = window->pixmap; + pboot_rpane_t *rpane = window->client_data; + pboot_device_t *dev; + twin_path_t *path; + twin_fixed_t x, y, w, h; + int i; + + /* Fill background */ + twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height); + + /* Nothing to draw, return */ + if (pboot_dev_sel < 0) + return; + + /* Create a path for use later */ + path = twin_path_create(); + assert(path); + + /* Draw focus box */ + if (rpane->focus_curindex >= 0 && + twin_rect_intersect(rpane->focus_box, px->clip)) { + x = twin_int_to_fixed(rpane->focus_box.left + 2); + y = twin_int_to_fixed(rpane->focus_box.top + 2); + w = twin_int_to_fixed(rpane->focus_box.right - + rpane->focus_box.left - 4); + h = twin_int_to_fixed(rpane->focus_box.bottom - + rpane->focus_box.top - 4); + twin_path_rounded_rectangle(path, x, y, w, h, + PBOOT_RIGHT_FOCUS_XRAD, + PBOOT_RIGHT_FOCUS_YRAD); + if (!pboot_focus_lpane) + twin_paint_path(px, PBOOT_FOCUS_COLOR, path); + else + twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path, + 4 * TWIN_FIXED_ONE); + } + + /* Get device and iterate through options */ + dev = pboot_devices[pboot_dev_sel]; + for (i = 0; i < dev->option_count; i++) { + pboot_option_t *opt = &dev->options[i]; + twin_operand_t src; + + if (opt->title == NULL) + continue; + if (!twin_rect_intersect(opt->box, px->clip)) + continue; + if (opt->cache == NULL) + pboot_draw_option_cache(dev, opt, i); + + src.source_kind = TWIN_PIXMAP; + src.u.pixmap = opt->cache; + + twin_composite(px, opt->box.left, opt->box.top, + &src, 0, 0, NULL, 0, 0, TWIN_OVER, + opt->box.right - opt->box.left, + opt->box.bottom - opt->box.top); + } + + /* Destroy path */ + twin_path_destroy(path); +} + +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, 1, 2, 2, 3 }; + + dist = abs(pboot_rpane->focus_target - pboot_rpane->focus_start); + dir = dist > 5 ? 5 : dist; + pos = pboot_rpane->focus_target - (int)pboot_rpane->focus_box.top; + if (pos == 0) { + return -1; + } + if (pos < 0) { + dir = -dir; + pos = -pos; + } + twin_window_damage(pboot_rpane->window, + pboot_rpane->focus_box.left, + pboot_rpane->focus_box.top, + pboot_rpane->focus_box.right, + pboot_rpane->focus_box.bottom); + + pboot_rpane->focus_box.top += dir; + pboot_rpane->focus_box.bottom += dir; + + twin_window_damage(pboot_rpane->window, + pboot_rpane->focus_box.left, + pboot_rpane->focus_box.top, + pboot_rpane->focus_box.right, + pboot_rpane->focus_box.bottom); + + twin_window_queue_paint(pboot_rpane->window); + + return accel[(pos * 10) / dist]; +} + +static void pboot_set_rfocus(int index) +{ + pboot_device_t *dev; + + if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count) + return; + dev = pboot_devices[pboot_dev_sel]; + if (index < 0 || index >= dev->option_count) + return; + + pboot_rpane->focus_start = pboot_rpane->focus_box.top; + pboot_rpane->focus_target = PBOOT_RIGHT_FOCUS_YOFF + + PBOOT_RIGHT_OPTION_STRIDE * index; + pboot_rpane->focus_curindex = index; + + twin_set_timeout(pboot_rfocus_timeout, 0, NULL); +} + +static void pboot_select_rpane(void) +{ + if (pboot_focus_lpane == 0) + return; + pboot_focus_lpane = 0; + + twin_screen_set_active(pboot_screen, pboot_rpane->window->pixmap); + + twin_window_damage(pboot_lpane->window, + pboot_lpane->focus_box.left, + pboot_lpane->focus_box.top, + pboot_lpane->focus_box.right, + pboot_lpane->focus_box.bottom); + + twin_window_damage(pboot_rpane->window, + pboot_rpane->focus_box.left, + pboot_rpane->focus_box.top, + pboot_rpane->focus_box.right, + pboot_rpane->focus_box.bottom); + + twin_window_queue_paint(pboot_lpane->window); + twin_window_queue_paint(pboot_rpane->window); + + pboot_set_rfocus(0); +} + +static void pboot_select_lpane(void) +{ + if (pboot_focus_lpane == 1) + return; + pboot_focus_lpane = 1; + + twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap); + + twin_window_damage(pboot_lpane->window, + pboot_lpane->focus_box.left, + pboot_lpane->focus_box.top, + pboot_lpane->focus_box.right, + pboot_lpane->focus_box.bottom); + + twin_window_damage(pboot_rpane->window, + pboot_rpane->focus_box.left, + pboot_rpane->focus_box.top, + pboot_rpane->focus_box.right, + pboot_rpane->focus_box.bottom); + + twin_window_queue_paint(pboot_lpane->window); + twin_window_queue_paint(pboot_rpane->window); +} + +static void pboot_rpane_mousetrack(twin_coord_t x, twin_coord_t y) +{ + pboot_device_t *dev; + pboot_option_t *opt; + int candidate = -1; + + if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count) + return; + dev = pboot_devices[pboot_dev_sel]; + + if (y < PBOOT_RIGHT_OPTION_TMARGIN) + goto miss; + candidate = (y - PBOOT_RIGHT_OPTION_TMARGIN) / + PBOOT_RIGHT_OPTION_STRIDE; + if (candidate >= dev->option_count) { + candidate = -1; + goto miss; + } + if (candidate == pboot_rpane->mouse_target) + return; + opt = &dev->options[candidate]; + if (x < opt->box.left || x > opt->box.right || + y < opt->box.top || y > opt->box.bottom) { + candidate = -1; + goto miss; + } + + /* Ok, so now, we know the mouse hit an icon that wasn't the same + * as the previous one, we trigger a focus change + */ + pboot_set_rfocus(candidate); + + miss: + 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) +{ + /* filter out all mouse events */ + switch(event->kind) { + case TwinEventEnter: + case TwinEventMotion: + case TwinEventLeave: + pboot_select_rpane(); + 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: + switch(event->u.key.key) { + case KEY_UP: + pboot_set_rfocus(pboot_rpane->focus_curindex - 1); + return TWIN_TRUE; + case KEY_DOWN: + pboot_set_rfocus(pboot_rpane->focus_curindex + 1); + return TWIN_TRUE; + case KEY_LEFT: + pboot_select_lpane(); + return TWIN_TRUE; + case KEY_ENTER: + pboot_choose_option(); + default: + break; + } + break; + default: + break; + } + return TWIN_FALSE; +} + + +int pboot_add_option(int devindex, const char *title, + const char *subtitle, twin_pixmap_t *badge, void *data) +{ + pboot_device_t *dev; + pboot_option_t *opt; + twin_coord_t width; + int index; + + if (devindex < 0 || devindex >= pboot_dev_count) + return -1; + dev = pboot_devices[devindex]; + + if (dev->option_count >= PBOOT_MAX_OPTION) + return -1; + index = dev->option_count++; + opt = &dev->options[index]; + + opt->title = malloc(strlen(title) + 1); + strcpy(opt->title, title); + + if (subtitle) { + opt->subtitle = malloc(strlen(subtitle) + 1); + strcpy(opt->subtitle, subtitle); + } else + opt->subtitle = NULL; + + opt->badge = badge; + opt->cache = NULL; + + width = pboot_rpane->window->pixmap->width - + (PBOOT_RIGHT_OPTION_LMARGIN + PBOOT_RIGHT_OPTION_RMARGIN); + + opt->box.left = PBOOT_RIGHT_OPTION_LMARGIN; + opt->box.right = opt->box.left + width; + opt->box.top = PBOOT_RIGHT_OPTION_TMARGIN + + 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, int force) +{ + LOG("%s: %d -> %d\n", __FUNCTION__, pboot_dev_sel, sel); + 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; + pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top + + PBOOT_RIGHT_FOCUS_HEIGHT; + twin_window_damage(pboot_rpane->window, 0, 0, + pboot_rpane->window->pixmap->width, + pboot_rpane->window->pixmap->height); + 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, 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, 0); + return -1; + } + if (pos < 0) { + dir = -1; + pos = -pos; + } + twin_window_damage(pboot_lpane->window, + pboot_lpane->focus_box.left, + pboot_lpane->focus_box.top, + pboot_lpane->focus_box.right, + pboot_lpane->focus_box.bottom); + + pboot_lpane->focus_box.top += dir; + pboot_lpane->focus_box.bottom += dir; + + twin_window_damage(pboot_lpane->window, + pboot_lpane->focus_box.left, + pboot_lpane->focus_box.top, + pboot_lpane->focus_box.right, + pboot_lpane->focus_box.bottom); + + twin_window_queue_paint(pboot_lpane->window); + + return accel[(pos * 10) / dist]; +} + +static void pboot_set_lfocus(int index) +{ + if (index >= pboot_dev_count) + return; + + pboot_lpane->focus_start = pboot_lpane->focus_box.top; + + if (index < 0) + pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT; + else + pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF + + PBOOT_LEFT_ICON_STRIDE * index; + + pboot_lpane->focus_curindex = index; + + twin_set_timeout(pboot_lfocus_timeout, 0, NULL); +} + +static void pboot_lpane_mousetrack(twin_coord_t x, twin_coord_t y) +{ + int candidate = -1; + twin_coord_t icon_top; + + if (x < PBOOT_LEFT_ICON_XOFF || + x > (PBOOT_LEFT_ICON_XOFF + PBOOT_LEFT_ICON_WIDTH)) + goto miss; + if (y < PBOOT_LEFT_ICON_YOFF) + goto miss; + candidate = (y - PBOOT_LEFT_ICON_YOFF) / PBOOT_LEFT_ICON_STRIDE; + if (candidate >= pboot_dev_count) { + candidate = -1; + goto miss; + } + if (candidate == pboot_lpane->mouse_target) + return; + icon_top = PBOOT_LEFT_ICON_YOFF + + candidate * PBOOT_LEFT_ICON_STRIDE; + if (y > (icon_top + PBOOT_LEFT_ICON_HEIGHT)) { + candidate = -1; + goto miss; + } + + /* Ok, so now, we know the mouse hit an icon that wasn't the same + * as the previous one, we trigger a focus change + */ + pboot_set_lfocus(candidate); + + miss: + pboot_lpane->mouse_target = candidate; +} + +static twin_bool_t pboot_lpane_event (twin_window_t *window, + twin_event_t *event) +{ + /* filter out all mouse events */ + switch(event->kind) { + case TwinEventEnter: + case TwinEventMotion: + case TwinEventLeave: + pboot_select_lpane(); + pboot_lpane_mousetrack(event->u.pointer.x, event->u.pointer.y); + return TWIN_TRUE; + case TwinEventButtonDown: + case TwinEventButtonUp: + return TWIN_TRUE; + case TwinEventKeyDown: + switch(event->u.key.key) { + case KEY_UP: + if (pboot_lpane->focus_curindex > 0) + pboot_set_lfocus( + pboot_lpane->focus_curindex - 1); + return TWIN_TRUE; + case KEY_DOWN: + pboot_set_lfocus(pboot_lpane->focus_curindex + 1); + return TWIN_TRUE; + case KEY_RIGHT: + pboot_select_rpane(); + return TWIN_TRUE; + default: + break; + } + break; + default: + break; + } + 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) +{ + switch(event->kind) { + case TwinEventEnter: + case TwinEventMotion: + case TwinEventLeave: + case TwinEventButtonDown: + case TwinEventButtonUp: + if (pboot_cursor != NULL) + twin_screen_set_cursor(pboot_screen, pboot_cursor, + 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); + } + case TwinEventKeyUp: + twin_screen_set_cursor(pboot_screen, NULL, 0, 0); + break; + default: + break; + } + return TWIN_FALSE; +} + +static void pboot_lpane_draw(twin_window_t *window) +{ + twin_pixmap_t *px = window->pixmap; + pboot_lpane_t *lpane = window->client_data; + twin_path_t *path; + twin_fixed_t x, y, w, h; + int i; + + /* Fill background */ + twin_fill(px, PBOOT_LEFT_PANE_COLOR, TWIN_SOURCE, + 0, 0, px->width, px->height); + + /* Create a path for use later */ + path = twin_path_create(); + assert(path); + + /* Draw right line if needed */ + if (px->clip.right > (PBOOT_LEFT_PANE_SIZE - 4)) { + x = twin_int_to_fixed(PBOOT_LEFT_PANE_SIZE - 4); + y = twin_int_to_fixed(px->height); + twin_path_rectangle(path, x, 0, 0x40000, y); + twin_paint_path(px, PBOOT_LEFT_LINE_COLOR, path); + twin_path_empty(path); + } + + /* Draw focus box */ + if (lpane->focus_curindex >= 0 && + twin_rect_intersect(lpane->focus_box, px->clip)) { + x = twin_int_to_fixed(lpane->focus_box.left + 2); + y = twin_int_to_fixed(lpane->focus_box.top + 2); + w = twin_int_to_fixed(lpane->focus_box.right - + lpane->focus_box.left - 4); + h = twin_int_to_fixed(lpane->focus_box.bottom - + lpane->focus_box.top - 4); + twin_path_rounded_rectangle(path, x, y, w, h, + PBOOT_LEFT_FOCUS_XRAD, + PBOOT_LEFT_FOCUS_YRAD); + if (pboot_focus_lpane) + twin_paint_path(px, PBOOT_FOCUS_COLOR, path); + else + twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path, + 4 * TWIN_FIXED_ONE); + } + + /* Draw icons */ + for (i = 0; i < pboot_dev_count; i++) { + pboot_device_t *dev = pboot_devices[i]; + twin_operand_t src; + + if (!twin_rect_intersect(dev->box, px->clip)) + continue; + + src.source_kind = TWIN_PIXMAP; + src.u.pixmap = dev->badge; + + twin_composite(px, dev->box.left, dev->box.top, + &src, 0, 0, NULL, 0, 0, TWIN_OVER, + dev->box.right - dev->box.left, + dev->box.bottom - dev->box.top); + + } + + /* Destroy path */ + twin_path_destroy(path); +} + +static void pboot_create_lpane(void) +{ + pboot_lpane = calloc(1, sizeof(pboot_lpane_t)); + assert(pboot_lpane); + + pboot_lpane->window = twin_window_create(pboot_screen, TWIN_ARGB32, + TwinWindowPlain, + 0, 0, PBOOT_LEFT_PANE_SIZE, + pboot_screen->height); + assert(pboot_lpane->window); + + pboot_lpane->window->draw = pboot_lpane_draw; + pboot_lpane->window->event = pboot_lpane_event; + pboot_lpane->window->client_data = pboot_lpane; + pboot_lpane->focus_curindex = -1; + pboot_lpane->focus_box.left = PBOOT_LEFT_FOCUS_XOFF; + pboot_lpane->focus_box.top = -2*PBOOT_LEFT_FOCUS_HEIGHT; + pboot_lpane->focus_box.right = pboot_lpane->focus_box.left + + PBOOT_LEFT_FOCUS_WIDTH; + pboot_lpane->focus_box.bottom = pboot_lpane->focus_box.top + + PBOOT_LEFT_FOCUS_HEIGHT; + pboot_lpane->mouse_target = -1; + twin_window_show(pboot_lpane->window); + twin_window_queue_paint(pboot_lpane->window); +} + +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; + + /* Fill background */ + twin_fill(px, PBOOT_STATUS_PANE_COLOR, TWIN_SOURCE, + 0, 0, px->width, px->height); + + path = twin_path_create(); + assert(path); + + 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_draw(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, + twin_pixmap_t *pixmap) +{ + int index; + pboot_device_t *dev; + + if (pboot_dev_count >= PBOOT_MAX_DEV) + return -1; + + index = pboot_dev_count++; + + dev = malloc(sizeof(*dev)); + memset(dev, 0, sizeof(*dev)); + dev->id = malloc(strlen(dev_id) + 1); + strcpy(dev->id, dev_id); + dev->badge = pixmap; + dev->box.left = PBOOT_LEFT_ICON_XOFF; + dev->box.right = dev->box.left + PBOOT_LEFT_ICON_WIDTH; + dev->box.top = PBOOT_LEFT_ICON_YOFF + + PBOOT_LEFT_ICON_STRIDE * index; + dev->box.bottom = dev->box.top + PBOOT_LEFT_ICON_HEIGHT; + + pboot_devices[index] = dev; + + 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); + + return index; +} + +int pboot_remove_device(const char *dev_id) +{ + pboot_device_t *dev = NULL; + int i, newsel = pboot_dev_sel; + + /* find the matching device */ + for (i = 0; i < pboot_dev_count; i++) { + if (!strcmp(pboot_devices[i]->id, dev_id)) { + dev = pboot_devices[i]; + break; + } + } + + if (!dev) + return TWIN_FALSE; + + memmove(pboot_devices + i, pboot_devices + i + 1, + sizeof(*pboot_devices) * (pboot_dev_count + i - 1)); + pboot_devices[--pboot_dev_count] = NULL; + + /* 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) +{ + exitfunc(); + syscall(__NR_exit); +} + +static void usage(const char *progname) +{ + fprintf(stderr, "Usage: %s [-u] [-h]\n", progname); +} + +int main(int argc, char **argv) +{ + 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); + +#ifdef _USE_X11 + pboot_x11 = twin_x11_create(XOpenDisplay(0), 1024, 768); + if (pboot_x11 == NULL) { + perror("failed to create x11 screen !\n"); + return 1; + } + pboot_screen = pboot_x11->screen; +#else + /* Create screen and mouse drivers */ + pboot_fbdev = twin_fbdev_create(-1, SIGUSR1); + if (pboot_fbdev == NULL) { + perror("failed to create fbdev screen !\n"); + return 1; + } + pboot_screen = pboot_fbdev->screen; + twin_linux_mouse_create(NULL, pboot_screen); + twin_linux_js_create(pboot_screen); + + if (pboot_fbdev != NULL) { + 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) + pboot_cursor = + twin_get_default_cursor(&pboot_cursor_hx, + &pboot_cursor_hy); + } +#endif + + /* Set background pixmap */ + pboot_make_background(); + + /* Init more stuffs */ + pboot_create_lpane(); + pboot_create_rpane(); + pboot_create_spane(); + + if (!pboot_start_device_discovery(udev_trigger)) { + LOG("Couldn't start device discovery!\n"); + return 1; + } + + pboot_set_lfocus(0); + twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap); + 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 (); + + return 0; +} --- /dev/null +++ b/petitboot-gui.h @@ -0,0 +1,18 @@ + +#include +#include + +#define LOG(fmt...) printf(fmt) + +#define PBOOT_MAX_DEV 16 +#define PBOOT_MAX_OPTION 16 + +int pboot_add_device(const char *dev_id, const char *name, + twin_pixmap_t *pixmap); +int pboot_add_option(int devindex, const char *title, + const char *subtitle, twin_pixmap_t *badge, void *data); +int pboot_remove_device(const char *dev_id); + +int pboot_start_device_discovery(int udev_trigger); +void pboot_exec_option(void *data); +void pboot_message(const char *fmt, ...); --- a/petitboot.c +++ /dev/null @@ -1,1194 +0,0 @@ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#undef _USE_X11 - -#include -#include -#include -#include -#include - -#include "petitboot.h" -#include "petitboot-paths.h" - -#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_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 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) - -#define PBOOT_RIGHT_FOCUS_XOFF 20 -#define PBOOT_RIGHT_FOCUS_YOFF 60 -#define PBOOT_RIGHT_FOCUS_HEIGHT 80 -#define PBOOT_RIGHT_FOCUS_XRAD (6 * TWIN_FIXED_ONE) -#define PBOOT_RIGHT_FOCUS_YRAD (6 * TWIN_FIXED_ONE) - -#define PBOOT_LEFT_ICON_WIDTH 64 -#define PBOOT_LEFT_ICON_HEIGHT 64 -#define PBOOT_LEFT_ICON_XOFF 50 -#define PBOOT_LEFT_ICON_YOFF 50 -#define PBOOT_LEFT_ICON_STRIDE 100 - -#define PBOOT_RIGHT_OPTION_LMARGIN 30 -#define PBOOT_RIGHT_OPTION_RMARGIN 30 -#define PBOOT_RIGHT_OPTION_TMARGIN 70 -#define PBOOT_RIGHT_OPTION_HEIGHT 64 -#define PBOOT_RIGHT_OPTION_STRIDE 100 -#define PBOOT_RIGHT_TITLE_TEXT_SIZE (30 * TWIN_FIXED_ONE) -#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 100 -#define PBOOT_RIGHT_SUBTITLE_YOFFSET 50 -#define PBOOT_RIGHT_BADGE_XOFFSET 2 -#define PBOOT_RIGHT_BADGE_YOFFSET 0 - - -#define PBOOT_RIGHT_TITLE_COLOR 0xff000000 -#define PBOOT_RIGHT_SUBTITLE_COLOR 0xff400000 - -#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; - -struct _pboot_option -{ - char *title; - char *subtitle; - twin_pixmap_t *badge; - twin_pixmap_t *cache; - twin_rect_t box; - void *data; -}; - -struct _pboot_device -{ - char *id; - twin_pixmap_t *badge; - twin_rect_t box; - int option_count; - pboot_option_t options[PBOOT_MAX_OPTION]; -}; - -static twin_pixmap_t *pboot_cursor; -static int pboot_cursor_hx; -static int pboot_cursor_hy; - -static pboot_device_t *pboot_devices[PBOOT_MAX_DEV]; -static int pboot_dev_count; -static int pboot_dev_sel = -1; -static int pboot_focus_lpane = 1; - -typedef struct _pboot_lpane { - twin_window_t *window; - twin_rect_t focus_box; - int focus_start; - int focus_target; - int focus_curindex; - int mouse_target; -} pboot_lpane_t; - -typedef struct _pboot_rpane { - twin_window_t *window; - twin_rect_t focus_box; - int focus_start; - int focus_target; - int focus_curindex; - 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, - twin_rect_t r2) -{ - return !(r1.left > r2.right || - r1.right < r2.left || - r1.top > r2.bottom || - r1.bottom < r2.top); -} - -static void pboot_draw_option_cache(pboot_device_t *dev, pboot_option_t *opt, - int index) -{ - twin_pixmap_t *px; - twin_path_t *path; - twin_fixed_t tx, ty; - - /* Create pixmap */ - px = twin_pixmap_create(TWIN_ARGB32, opt->box.right - opt->box.left, - opt->box.bottom - opt->box.top); - assert(px); - opt->cache = px; - - /* Fill background */ - twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height); - - /* Allocate a path for drawing */ - path = twin_path_create(); - assert(path); - -#if 0 - /* TEST - Bounding rectangle */ - twin_path_rectangle(path, 0, 0, - twin_int_to_fixed(px->width), - twin_int_to_fixed(px->height)); - twin_paint_path(px, PBOOT_RIGHT_TITLE_COLOR, path); - twin_path_empty(path); - twin_fill(px, 0x00000000, TWIN_SOURCE, 2, 2, - px->width - 3, px->height - 3); -#endif - - /* Draw texts */ - twin_path_set_font_size(path, PBOOT_RIGHT_TITLE_TEXT_SIZE); - twin_path_set_font_style(path, TWIN_TEXT_UNHINTED); - tx = twin_int_to_fixed(PBOOT_RIGHT_TITLE_XOFFSET); - ty = twin_int_to_fixed(PBOOT_RIGHT_TITLE_YOFFSET); - twin_path_move (path, tx, ty); - twin_path_utf8 (path, opt->title); - twin_paint_path (px, PBOOT_RIGHT_TITLE_COLOR, path); - twin_path_empty (path); - - if (opt->subtitle) { - twin_path_set_font_size(path, PBOOT_RIGHT_SUBTITLE_TEXT_SIZE); - twin_path_set_font_style(path, TWIN_TEXT_UNHINTED); - tx = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_XOFFSET); - ty = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_YOFFSET); - twin_path_move (path, tx, ty); - twin_path_utf8 (path, opt->subtitle); - twin_paint_path (px, PBOOT_RIGHT_SUBTITLE_COLOR, path); - twin_path_empty (path); - } - - if (opt->badge) { - twin_operand_t src; - - src.source_kind = TWIN_PIXMAP; - src.u.pixmap = opt->badge; - - twin_composite(px, PBOOT_RIGHT_BADGE_XOFFSET, - PBOOT_RIGHT_BADGE_YOFFSET, - &src, 0, 0, NULL, 0, 0, TWIN_OVER, - opt->badge->width, opt->badge->height); - } - - - /* Destroy path */ - twin_path_destroy(path); -} - -static void pboot_rpane_draw(twin_window_t *window) -{ - twin_pixmap_t *px = window->pixmap; - pboot_rpane_t *rpane = window->client_data; - pboot_device_t *dev; - twin_path_t *path; - twin_fixed_t x, y, w, h; - int i; - - /* Fill background */ - twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height); - - /* Nothing to draw, return */ - if (pboot_dev_sel < 0) - return; - - /* Create a path for use later */ - path = twin_path_create(); - assert(path); - - /* Draw focus box */ - if (rpane->focus_curindex >= 0 && - twin_rect_intersect(rpane->focus_box, px->clip)) { - x = twin_int_to_fixed(rpane->focus_box.left + 2); - y = twin_int_to_fixed(rpane->focus_box.top + 2); - w = twin_int_to_fixed(rpane->focus_box.right - - rpane->focus_box.left - 4); - h = twin_int_to_fixed(rpane->focus_box.bottom - - rpane->focus_box.top - 4); - twin_path_rounded_rectangle(path, x, y, w, h, - PBOOT_RIGHT_FOCUS_XRAD, - PBOOT_RIGHT_FOCUS_YRAD); - if (!pboot_focus_lpane) - twin_paint_path(px, PBOOT_FOCUS_COLOR, path); - else - twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path, - 4 * TWIN_FIXED_ONE); - } - - /* Get device and iterate through options */ - dev = pboot_devices[pboot_dev_sel]; - for (i = 0; i < dev->option_count; i++) { - pboot_option_t *opt = &dev->options[i]; - twin_operand_t src; - - if (opt->title == NULL) - continue; - if (!twin_rect_intersect(opt->box, px->clip)) - continue; - if (opt->cache == NULL) - pboot_draw_option_cache(dev, opt, i); - - src.source_kind = TWIN_PIXMAP; - src.u.pixmap = opt->cache; - - twin_composite(px, opt->box.left, opt->box.top, - &src, 0, 0, NULL, 0, 0, TWIN_OVER, - opt->box.right - opt->box.left, - opt->box.bottom - opt->box.top); - } - - /* Destroy path */ - twin_path_destroy(path); -} - -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, 1, 2, 2, 3 }; - - dist = abs(pboot_rpane->focus_target - pboot_rpane->focus_start); - dir = dist > 5 ? 5 : dist; - pos = pboot_rpane->focus_target - (int)pboot_rpane->focus_box.top; - if (pos == 0) { - return -1; - } - if (pos < 0) { - dir = -dir; - pos = -pos; - } - twin_window_damage(pboot_rpane->window, - pboot_rpane->focus_box.left, - pboot_rpane->focus_box.top, - pboot_rpane->focus_box.right, - pboot_rpane->focus_box.bottom); - - pboot_rpane->focus_box.top += dir; - pboot_rpane->focus_box.bottom += dir; - - twin_window_damage(pboot_rpane->window, - pboot_rpane->focus_box.left, - pboot_rpane->focus_box.top, - pboot_rpane->focus_box.right, - pboot_rpane->focus_box.bottom); - - twin_window_queue_paint(pboot_rpane->window); - - return accel[(pos * 10) / dist]; -} - -static void pboot_set_rfocus(int index) -{ - pboot_device_t *dev; - - if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count) - return; - dev = pboot_devices[pboot_dev_sel]; - if (index < 0 || index >= dev->option_count) - return; - - pboot_rpane->focus_start = pboot_rpane->focus_box.top; - pboot_rpane->focus_target = PBOOT_RIGHT_FOCUS_YOFF + - PBOOT_RIGHT_OPTION_STRIDE * index; - pboot_rpane->focus_curindex = index; - - twin_set_timeout(pboot_rfocus_timeout, 0, NULL); -} - -static void pboot_select_rpane(void) -{ - if (pboot_focus_lpane == 0) - return; - pboot_focus_lpane = 0; - - twin_screen_set_active(pboot_screen, pboot_rpane->window->pixmap); - - twin_window_damage(pboot_lpane->window, - pboot_lpane->focus_box.left, - pboot_lpane->focus_box.top, - pboot_lpane->focus_box.right, - pboot_lpane->focus_box.bottom); - - twin_window_damage(pboot_rpane->window, - pboot_rpane->focus_box.left, - pboot_rpane->focus_box.top, - pboot_rpane->focus_box.right, - pboot_rpane->focus_box.bottom); - - twin_window_queue_paint(pboot_lpane->window); - twin_window_queue_paint(pboot_rpane->window); - - pboot_set_rfocus(0); -} - -static void pboot_select_lpane(void) -{ - if (pboot_focus_lpane == 1) - return; - pboot_focus_lpane = 1; - - twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap); - - twin_window_damage(pboot_lpane->window, - pboot_lpane->focus_box.left, - pboot_lpane->focus_box.top, - pboot_lpane->focus_box.right, - pboot_lpane->focus_box.bottom); - - twin_window_damage(pboot_rpane->window, - pboot_rpane->focus_box.left, - pboot_rpane->focus_box.top, - pboot_rpane->focus_box.right, - pboot_rpane->focus_box.bottom); - - twin_window_queue_paint(pboot_lpane->window); - twin_window_queue_paint(pboot_rpane->window); -} - -static void pboot_rpane_mousetrack(twin_coord_t x, twin_coord_t y) -{ - pboot_device_t *dev; - pboot_option_t *opt; - int candidate = -1; - - if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count) - return; - dev = pboot_devices[pboot_dev_sel]; - - if (y < PBOOT_RIGHT_OPTION_TMARGIN) - goto miss; - candidate = (y - PBOOT_RIGHT_OPTION_TMARGIN) / - PBOOT_RIGHT_OPTION_STRIDE; - if (candidate >= dev->option_count) { - candidate = -1; - goto miss; - } - if (candidate == pboot_rpane->mouse_target) - return; - opt = &dev->options[candidate]; - if (x < opt->box.left || x > opt->box.right || - y < opt->box.top || y > opt->box.bottom) { - candidate = -1; - goto miss; - } - - /* Ok, so now, we know the mouse hit an icon that wasn't the same - * as the previous one, we trigger a focus change - */ - pboot_set_rfocus(candidate); - - miss: - 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) -{ - /* filter out all mouse events */ - switch(event->kind) { - case TwinEventEnter: - case TwinEventMotion: - case TwinEventLeave: - pboot_select_rpane(); - 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: - switch(event->u.key.key) { - case KEY_UP: - pboot_set_rfocus(pboot_rpane->focus_curindex - 1); - return TWIN_TRUE; - case KEY_DOWN: - pboot_set_rfocus(pboot_rpane->focus_curindex + 1); - return TWIN_TRUE; - case KEY_LEFT: - pboot_select_lpane(); - return TWIN_TRUE; - case KEY_ENTER: - pboot_choose_option(); - default: - break; - } - break; - default: - break; - } - return TWIN_FALSE; -} - - -int pboot_add_option(int devindex, const char *title, - const char *subtitle, twin_pixmap_t *badge, void *data) -{ - pboot_device_t *dev; - pboot_option_t *opt; - twin_coord_t width; - int index; - - if (devindex < 0 || devindex >= pboot_dev_count) - return -1; - dev = pboot_devices[devindex]; - - if (dev->option_count >= PBOOT_MAX_OPTION) - return -1; - index = dev->option_count++; - opt = &dev->options[index]; - - opt->title = malloc(strlen(title) + 1); - strcpy(opt->title, title); - - if (subtitle) { - opt->subtitle = malloc(strlen(subtitle) + 1); - strcpy(opt->subtitle, subtitle); - } else - opt->subtitle = NULL; - - opt->badge = badge; - opt->cache = NULL; - - width = pboot_rpane->window->pixmap->width - - (PBOOT_RIGHT_OPTION_LMARGIN + PBOOT_RIGHT_OPTION_RMARGIN); - - opt->box.left = PBOOT_RIGHT_OPTION_LMARGIN; - opt->box.right = opt->box.left + width; - opt->box.top = PBOOT_RIGHT_OPTION_TMARGIN + - 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, int force) -{ - LOG("%s: %d -> %d\n", __FUNCTION__, pboot_dev_sel, sel); - 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; - pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top + - PBOOT_RIGHT_FOCUS_HEIGHT; - twin_window_damage(pboot_rpane->window, 0, 0, - pboot_rpane->window->pixmap->width, - pboot_rpane->window->pixmap->height); - 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, 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, 0); - return -1; - } - if (pos < 0) { - dir = -1; - pos = -pos; - } - twin_window_damage(pboot_lpane->window, - pboot_lpane->focus_box.left, - pboot_lpane->focus_box.top, - pboot_lpane->focus_box.right, - pboot_lpane->focus_box.bottom); - - pboot_lpane->focus_box.top += dir; - pboot_lpane->focus_box.bottom += dir; - - twin_window_damage(pboot_lpane->window, - pboot_lpane->focus_box.left, - pboot_lpane->focus_box.top, - pboot_lpane->focus_box.right, - pboot_lpane->focus_box.bottom); - - twin_window_queue_paint(pboot_lpane->window); - - return accel[(pos * 10) / dist]; -} - -static void pboot_set_lfocus(int index) -{ - if (index >= pboot_dev_count) - return; - - pboot_lpane->focus_start = pboot_lpane->focus_box.top; - - if (index < 0) - pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT; - else - pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF + - PBOOT_LEFT_ICON_STRIDE * index; - - pboot_lpane->focus_curindex = index; - - twin_set_timeout(pboot_lfocus_timeout, 0, NULL); -} - -static void pboot_lpane_mousetrack(twin_coord_t x, twin_coord_t y) -{ - int candidate = -1; - twin_coord_t icon_top; - - if (x < PBOOT_LEFT_ICON_XOFF || - x > (PBOOT_LEFT_ICON_XOFF + PBOOT_LEFT_ICON_WIDTH)) - goto miss; - if (y < PBOOT_LEFT_ICON_YOFF) - goto miss; - candidate = (y - PBOOT_LEFT_ICON_YOFF) / PBOOT_LEFT_ICON_STRIDE; - if (candidate >= pboot_dev_count) { - candidate = -1; - goto miss; - } - if (candidate == pboot_lpane->mouse_target) - return; - icon_top = PBOOT_LEFT_ICON_YOFF + - candidate * PBOOT_LEFT_ICON_STRIDE; - if (y > (icon_top + PBOOT_LEFT_ICON_HEIGHT)) { - candidate = -1; - goto miss; - } - - /* Ok, so now, we know the mouse hit an icon that wasn't the same - * as the previous one, we trigger a focus change - */ - pboot_set_lfocus(candidate); - - miss: - pboot_lpane->mouse_target = candidate; -} - -static twin_bool_t pboot_lpane_event (twin_window_t *window, - twin_event_t *event) -{ - /* filter out all mouse events */ - switch(event->kind) { - case TwinEventEnter: - case TwinEventMotion: - case TwinEventLeave: - pboot_select_lpane(); - pboot_lpane_mousetrack(event->u.pointer.x, event->u.pointer.y); - return TWIN_TRUE; - case TwinEventButtonDown: - case TwinEventButtonUp: - return TWIN_TRUE; - case TwinEventKeyDown: - switch(event->u.key.key) { - case KEY_UP: - if (pboot_lpane->focus_curindex > 0) - pboot_set_lfocus( - pboot_lpane->focus_curindex - 1); - return TWIN_TRUE; - case KEY_DOWN: - pboot_set_lfocus(pboot_lpane->focus_curindex + 1); - return TWIN_TRUE; - case KEY_RIGHT: - pboot_select_rpane(); - return TWIN_TRUE; - default: - break; - } - break; - default: - break; - } - 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) -{ - switch(event->kind) { - case TwinEventEnter: - case TwinEventMotion: - case TwinEventLeave: - case TwinEventButtonDown: - case TwinEventButtonUp: - if (pboot_cursor != NULL) - twin_screen_set_cursor(pboot_screen, pboot_cursor, - 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); - } - case TwinEventKeyUp: - twin_screen_set_cursor(pboot_screen, NULL, 0, 0); - break; - default: - break; - } - return TWIN_FALSE; -} - -static void pboot_lpane_draw(twin_window_t *window) -{ - twin_pixmap_t *px = window->pixmap; - pboot_lpane_t *lpane = window->client_data; - twin_path_t *path; - twin_fixed_t x, y, w, h; - int i; - - /* Fill background */ - twin_fill(px, PBOOT_LEFT_PANE_COLOR, TWIN_SOURCE, - 0, 0, px->width, px->height); - - /* Create a path for use later */ - path = twin_path_create(); - assert(path); - - /* Draw right line if needed */ - if (px->clip.right > (PBOOT_LEFT_PANE_SIZE - 4)) { - x = twin_int_to_fixed(PBOOT_LEFT_PANE_SIZE - 4); - y = twin_int_to_fixed(px->height); - twin_path_rectangle(path, x, 0, 0x40000, y); - twin_paint_path(px, PBOOT_LEFT_LINE_COLOR, path); - twin_path_empty(path); - } - - /* Draw focus box */ - if (lpane->focus_curindex >= 0 && - twin_rect_intersect(lpane->focus_box, px->clip)) { - x = twin_int_to_fixed(lpane->focus_box.left + 2); - y = twin_int_to_fixed(lpane->focus_box.top + 2); - w = twin_int_to_fixed(lpane->focus_box.right - - lpane->focus_box.left - 4); - h = twin_int_to_fixed(lpane->focus_box.bottom - - lpane->focus_box.top - 4); - twin_path_rounded_rectangle(path, x, y, w, h, - PBOOT_LEFT_FOCUS_XRAD, - PBOOT_LEFT_FOCUS_YRAD); - if (pboot_focus_lpane) - twin_paint_path(px, PBOOT_FOCUS_COLOR, path); - else - twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path, - 4 * TWIN_FIXED_ONE); - } - - /* Draw icons */ - for (i = 0; i < pboot_dev_count; i++) { - pboot_device_t *dev = pboot_devices[i]; - twin_operand_t src; - - if (!twin_rect_intersect(dev->box, px->clip)) - continue; - - src.source_kind = TWIN_PIXMAP; - src.u.pixmap = dev->badge; - - twin_composite(px, dev->box.left, dev->box.top, - &src, 0, 0, NULL, 0, 0, TWIN_OVER, - dev->box.right - dev->box.left, - dev->box.bottom - dev->box.top); - - } - - /* Destroy path */ - twin_path_destroy(path); -} - -static void pboot_create_lpane(void) -{ - pboot_lpane = calloc(1, sizeof(pboot_lpane_t)); - assert(pboot_lpane); - - pboot_lpane->window = twin_window_create(pboot_screen, TWIN_ARGB32, - TwinWindowPlain, - 0, 0, PBOOT_LEFT_PANE_SIZE, - pboot_screen->height); - assert(pboot_lpane->window); - - pboot_lpane->window->draw = pboot_lpane_draw; - pboot_lpane->window->event = pboot_lpane_event; - pboot_lpane->window->client_data = pboot_lpane; - pboot_lpane->focus_curindex = -1; - pboot_lpane->focus_box.left = PBOOT_LEFT_FOCUS_XOFF; - pboot_lpane->focus_box.top = -2*PBOOT_LEFT_FOCUS_HEIGHT; - pboot_lpane->focus_box.right = pboot_lpane->focus_box.left + - PBOOT_LEFT_FOCUS_WIDTH; - pboot_lpane->focus_box.bottom = pboot_lpane->focus_box.top + - PBOOT_LEFT_FOCUS_HEIGHT; - pboot_lpane->mouse_target = -1; - twin_window_show(pboot_lpane->window); - twin_window_queue_paint(pboot_lpane->window); -} - -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; - - /* Fill background */ - twin_fill(px, PBOOT_STATUS_PANE_COLOR, TWIN_SOURCE, - 0, 0, px->width, px->height); - - path = twin_path_create(); - assert(path); - - 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_draw(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, - twin_pixmap_t *pixmap) -{ - int index; - pboot_device_t *dev; - - if (pboot_dev_count >= PBOOT_MAX_DEV) - return -1; - - index = pboot_dev_count++; - - dev = malloc(sizeof(*dev)); - memset(dev, 0, sizeof(*dev)); - dev->id = malloc(strlen(dev_id) + 1); - strcpy(dev->id, dev_id); - dev->badge = pixmap; - dev->box.left = PBOOT_LEFT_ICON_XOFF; - dev->box.right = dev->box.left + PBOOT_LEFT_ICON_WIDTH; - dev->box.top = PBOOT_LEFT_ICON_YOFF + - PBOOT_LEFT_ICON_STRIDE * index; - dev->box.bottom = dev->box.top + PBOOT_LEFT_ICON_HEIGHT; - - pboot_devices[index] = dev; - - 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); - - return index; -} - -int pboot_remove_device(const char *dev_id) -{ - pboot_device_t *dev = NULL; - int i, newsel = pboot_dev_sel; - - /* find the matching device */ - for (i = 0; i < pboot_dev_count; i++) { - if (!strcmp(pboot_devices[i]->id, dev_id)) { - dev = pboot_devices[i]; - break; - } - } - - if (!dev) - return TWIN_FALSE; - - memmove(pboot_devices + i, pboot_devices + i + 1, - sizeof(*pboot_devices) * (pboot_dev_count + i - 1)); - pboot_devices[--pboot_dev_count] = NULL; - - /* 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) -{ - exitfunc(); - syscall(__NR_exit); -} - -static void usage(const char *progname) -{ - fprintf(stderr, "Usage: %s [-u] [-h]\n", progname); -} - -int main(int argc, char **argv) -{ - 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); - -#ifdef _USE_X11 - pboot_x11 = twin_x11_create(XOpenDisplay(0), 1024, 768); - if (pboot_x11 == NULL) { - perror("failed to create x11 screen !\n"); - return 1; - } - pboot_screen = pboot_x11->screen; -#else - /* Create screen and mouse drivers */ - pboot_fbdev = twin_fbdev_create(-1, SIGUSR1); - if (pboot_fbdev == NULL) { - perror("failed to create fbdev screen !\n"); - return 1; - } - pboot_screen = pboot_fbdev->screen; - twin_linux_mouse_create(NULL, pboot_screen); - twin_linux_js_create(pboot_screen); - - if (pboot_fbdev != NULL) { - 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) - pboot_cursor = - twin_get_default_cursor(&pboot_cursor_hx, - &pboot_cursor_hy); - } -#endif - - /* Set background pixmap */ - pboot_make_background(); - - /* Init more stuffs */ - pboot_create_lpane(); - pboot_create_rpane(); - pboot_create_spane(); - - if (!pboot_start_device_discovery(udev_trigger)) { - LOG("Couldn't start device discovery!\n"); - return 1; - } - - pboot_set_lfocus(0); - twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap); - 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 (); - - return 0; -} --- a/petitboot.h +++ /dev/null @@ -1,18 +0,0 @@ - -#include -#include - -#define LOG(fmt...) printf(fmt) - -#define PBOOT_MAX_DEV 16 -#define PBOOT_MAX_OPTION 16 - -int pboot_add_device(const char *dev_id, const char *name, - twin_pixmap_t *pixmap); -int pboot_add_option(int devindex, const char *title, - const char *subtitle, twin_pixmap_t *badge, void *data); -int pboot_remove_device(const char *dev_id); - -int pboot_start_device_discovery(int udev_trigger); -void pboot_exec_option(void *data); -void pboot_message(const char *fmt, ...);