Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
---
- rules.mk | 2 +-
- ui/twin/ps3-twin.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 50 insertions(+), 1 deletion(-)
+ Makefile.in | 1
+ configure.ac | 12
+ rules.mk | 14
+ ui/twin/ps3-twin.c | 1441 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 1463 insertions(+), 5 deletions(-)
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -18,6 +18,7 @@ twin_LDFLAGS = @twin_LIBS@
+
+ # build target
+ ENABLE_PS3 = @ENABLE_PS3@
++ENABLE_X11 = @ENABLE_X11@
+
+ # other programs
+ INSTALL = @INSTALL@
+--- a/configure.ac
++++ b/configure.ac
+@@ -56,7 +56,17 @@ AS_IF([test "x$with_twin" != xno],
+ [if test "x$with_twin" != xcheck; then
+ AC_MSG_FAILURE([--with-twin was given, but test for twin failed])
+ fi],
+- [${twin_LIBS}])])
++ [${twin_LIBS}])
++ AC_CHECK_HEADERS([libtwin/twin_x11.h])])
++
++AC_ARG_ENABLE([x11],
++ [AS_HELP_STRING([--enable-x11],
++ [build for x11])],
++ [],
++ [enable_x11=check])
++
++AS_IF([test "x$enable_x11" != xno], [AC_SUBST([ENABLE_X11], ["y"])], [])
++
+
+ mkdir -p discover lib/list lib/log lib/pb-protocol lib/system lib/talloc \
+ lib/waiter test ui/common ui/ncurses ui/test ui/twin utils
--- a/rules.mk
+++ b/rules.mk
@@ -54,7 +54,7 @@ ui_common_objs = ui/common/discover-clie
# Makefiles
makefiles = Makefile $(top_srcdir)/rules.mk
+@@ -89,11 +89,17 @@ $(pb_test): $(pb_test_objs)
+ $(LINK.o) -o $@ $^
+
+ # twin gui
+-pb_twin_objs = $(client_objs) $(twin_objs) ui/twin/ps3-twin.o
++pb_twin_objs-y$(ENABLE_PS3) += ui/twin/pb-twin.o
++pb_twin_objs-$(ENABLE_PS3) += ui/twin/ps3-twin.o ui/common/ps3.o
++pb_twin_cflags-$(ENABLE_X11) += -DUSE_X11
++pb_twin_ldflags-$(ENABLE_PS3) += -lps3-utils
++
++pb_twin_objs = $(client_objs) $(twin_objs) $(pb_twin_objs-y)
+ $(pb_twin_objs): $(makefiles)
+
+-$(pb_twin): LDFLAGS+=$(twin_LDFLAGS) $(LIBTWIN)
+-$(pb_twin): CFLAGS+=$(twin_CFLAGS)
++$(pb_twin): LDFLAGS += $(pb_twin_ldflags-y) $(twin_LDFLAGS) $(LIBTWIN)
++$(pb_twin): CFLAGS += $(pb_twin_cflags-y) $(twin_CFLAGS) \
++ -DPB_ARTWORK_PATH='"$(pkgdatadir)/artwork/"'
+
+ $(pb_twin): $(pb_twin_objs)
+ $(LINK.o) -o $@ $^
--- /dev/null
+++ b/ui/twin/ps3-twin.c
-@@ -0,0 +1,49 @@
+@@ -0,0 +1,1441 @@
+/*
+ * Petitboot twin bootloader for the PS3 game console
+ *
++ * Copyright (C) 2009 Sony Computer Entertainment Inc.
++ * Copyright 2009 Sony Corp.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
-+#define _GNU_SOURCE
++#if defined(HAVE_CONFIG_H)
++#include "config.h"
++#endif
+
++#define _GNU_SOURCE
+#include <assert.h>
++#include <errno.h>
++#include <getopt.h>
+#include <signal.h>
-+
++#include <stdlib.h>
++#include <string.h>
++#include <sys/time.h>
+#include <libtwin/twin.h>
+#include <libtwin/twin_fbdev.h>
-+static twin_fbdev_t *pboot_fbdev;
++#include <libtwin/twin_jpeg.h>
++#include <libtwin/twin_linux_mouse.h>
++#include <libtwin/twin_linux_js.h>
++#include <libtwin/twin_png.h>
++#if defined(HAVE_LIBTWIN_TWIN_X11_H)
++# include <libtwin/twin_x11.h>
++#endif
++#include <linux/input.h>
+
+#include "log/log.h"
++#include "talloc/talloc.h"
++#include "waiter/waiter.h"
++#include "ui/common/discover-client.h"
++#include "ui/common/ps3.h"
++#include "ui/common/timer.h"
++
++//------------------------------------------------------------------------------
++// twin-ui.c/h
++
++#define DBG(fmt, args...) pb_log("DBG: " fmt, ## args)
++#define DBGS(fmt, args...) \
++ pb_log("DBG:%s:%d: " fmt, __func__, __LINE__, ## args)
++
++/* 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 */
++};
++
++#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
++
++#define PBOOT_MAX_OPTION 100
++#define PBOOT_MAX_DEV 10
++
++struct pbt_option
++{
++ char *title;
++ char *subtitle;
++ twin_pixmap_t *badge;
++ twin_pixmap_t *cache;
++ twin_rect_t box;
++ void *data;
++};
++
++struct pbt_device
++{
++ char *id;
++ twin_pixmap_t *badge;
++ twin_rect_t box;
++ int option_count;
++ struct pbt_option options[PBOOT_MAX_OPTION];
++};
++
++enum pbt_sig {
++ pbt_scr_sig = 111,
++ pbt_menu_sig = 222,
++ pbt_pane_sig = 333,
++ pb_removed_sig = -555,
++};
++
++struct pbt_cursor {
++ twin_pixmap_t *pixmap;
++ int hx;
++ int hy;
++};
++
++struct pbt_scr {
++ enum pbt_sig sig;
++ struct pbt_cursor cursor;
++ twin_screen_t *tscreen;
++#if defined(HAVE_LIBTWIN_TWIN_X11_H)
++ twin_x11_t *x11;
++#endif
++ twin_fbdev_t *fbdev;
++};
++
++struct pbt_frame {
++ twin_label_t *title;
++ twin_label_t *help;
++ twin_label_t *status;
++};
++
++/**
++ * struct pbt_pane - A twin menu pane.
++ */
++
++struct pbt_pane {
++ enum pbt_sig sig;
++ twin_window_t *window;
++ twin_rect_t focus_box;
++ int focus_start;
++ int focus_target;
++ int focus_curindex;
++ int mouse_target;
++ int has_focus;
++};
++
++/**
++ * struct pbt_menu - A twin menu.
++ * @sig: Sanity check signature.
++ * @scr: The screen this menu is associated with.
++ * @dp: The device pane instance.
++ * @op: The option pane instance.
++ */
++
++struct pbt_menu {
++ enum pbt_sig sig;
++ struct pbt_scr *scr;
++ struct pbt_pane *dp;
++ struct pbt_pane *op;
++};
++
++//==============================================================================
++// helper
++//==============================================================================
++
++static struct pbt_scr *pbt_scr_from_tscreen(twin_screen_t *tscreen);
++
++static struct pbt_menu *pbt_menu_from_twindow(twin_window_t *twindow)
++{
++ struct pbt_menu *menu = twindow->client_data;
++
++ assert(menu);
++ assert(menu->sig == pbt_menu_sig);
++ return menu;
++}
++
++/*
++static struct pbt_menu *pbt_menu_from_arg(void *arg)
++{
++ struct pbt_menu *menu = arg;
++
++ assert(menu);
++ assert(menu->sig == pbt_menu_sig);
++ return menu;
++}
++*/
++
++static struct pbt_pane *pbt_pane_from_arg(void *arg)
++{
++ struct pbt_pane *pane = arg;
++
++ assert(pane);
++ assert(pane->sig == pbt_pane_sig);
++ return pane;
++}
++
++static twin_bool_t pbt_rect_intersect(twin_rect_t r1, twin_rect_t r2)
++{
++ // FIXME: move this to twin!!!
++ return !(r1.left > r2.right ||
++ r1.right < r2.left ||
++ r1.top > r2.bottom ||
++ r1.bottom < r2.top);
++}
++
++static twin_pixmap_t * pbt_load_background(twin_screen_t *tscreen)
++{
++ static const char *bgd = PB_ARTWORK_PATH "/background.jpg";
++ twin_pixmap_t *rawpix;
++ twin_pixmap_t *scaledpix;
++
++ rawpix = twin_jpeg_to_pixmap(bgd, TWIN_ARGB32);
++
++ if (!rawpix) {
++ pb_log("%s: loading image %s failed\n", __func__, bgd);
++ return twin_make_pattern();
++ }
++
++ if (tscreen->height == rawpix->height &&
++ tscreen->width == rawpix->width)
++ return rawpix;
++
++ /* Scale as needed. */
++
++ twin_fixed_t sx, sy;
++ twin_operand_t srcop;
++
++ scaledpix = twin_pixmap_create(TWIN_ARGB32,
++ tscreen->width,
++ tscreen->height);
++ if (!scaledpix) {
++ pb_log("%s: scale %s failed\n", __func__, bgd);
++ twin_pixmap_destroy(rawpix);
++ return twin_make_pattern();
++ }
++ sx = twin_fixed_div(twin_int_to_fixed(rawpix->width),
++ twin_int_to_fixed(tscreen->width));
++ sy = twin_fixed_div(twin_int_to_fixed(rawpix->height),
++ twin_int_to_fixed(tscreen->height));
++
++ twin_matrix_scale(&rawpix->transform, sx, sy);
++ srcop.source_kind = TWIN_PIXMAP;
++ srcop.u.pixmap = rawpix;
++ twin_composite(scaledpix, 0, 0, &srcop, 0, 0,
++ NULL, 0, 0, TWIN_SOURCE,
++ tscreen->width, tscreen->height);
++
++ twin_pixmap_destroy(rawpix);
++ return scaledpix;
++}
++
++//==============================================================================
++// option
++//==============================================================================
++
++static void pbt_option_execute(struct pbt_menu *menu)
++{
++#if 0
++ pboot_device_t *dev = pboot_devices[pboot_dev_sel];
++ pboot_option_t *opt = &dev->options[menu->op->focus_curindex];
++
++ pb_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);
++#endif
++}
++
++//==============================================================================
++// device
++//==============================================================================
++
++//==============================================================================
++// scr
++//==============================================================================
++
++static twin_bool_t pbt_scr_event(twin_screen_t *tscreen, twin_event_t *event)
++{
++ struct pbt_scr *scr = pbt_scr_from_tscreen(tscreen);
++
++ switch(event->kind) {
++ case TwinEventEnter:
++ case TwinEventMotion:
++ case TwinEventLeave:
++ case TwinEventButtonDown:
++ case TwinEventButtonUp:
++ if (scr->cursor.pixmap)
++ twin_screen_set_cursor(tscreen, scr->cursor.pixmap,
++ scr->cursor.hx, scr->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) {
++ case KEY_0:
++ return TWIN_TRUE;
++ case KEY_BACKSPACE:
++ case KEY_DELETE:
++ return TWIN_FALSE;
++ }
++ case TwinEventKeyUp:
++ twin_screen_set_cursor(tscreen, NULL, 0, 0);
++ break;
++ default:
++ break;
++ }
++ return TWIN_FALSE;
++}
++
++//==============================================================================
++// pane
++//==============================================================================
++
++static int pbt_pane_has_focus(const struct pbt_pane *pane)
++{
++ return pane->has_focus;
++}
++
++static twin_time_t pbt_pane_timeout(twin_time_t now, void *closure)
++{
++ const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 1, 2, 2, 3 };
++ struct pbt_pane *pane = pbt_pane_from_arg(closure);
++ int dir = 1, dist, pos;
++
++ dist = abs(pane->focus_target - pane->focus_start);
++ dir = dist > 5 ? 5 : dist;
++ pos = pane->focus_target - (int)pane->focus_box.top;
++ if (pos == 0) {
++ return -1;
++ }
++ if (pos < 0) {
++ dir = -dir;
++ pos = -pos;
++ }
++ twin_window_damage(pane->window,
++ pane->focus_box.left,
++ pane->focus_box.top,
++ pane->focus_box.right,
++ pane->focus_box.bottom);
++
++ pane->focus_box.top += dir;
++ pane->focus_box.bottom += dir;
++
++ twin_window_damage(pane->window,
++ pane->focus_box.left,
++ pane->focus_box.top,
++ pane->focus_box.right,
++ pane->focus_box.bottom);
++
++ twin_window_queue_paint(pane->window);
++
++ return accel[(pos * 10) / dist];
++}
++
++//==============================================================================
++// menu
++//==============================================================================
++
++/**
++ * pbt_menu_set_focus - Set the menu's pane of focus.
++ * @menu: The menu to operate on.
++ * @pane: The pane that will have the focus.
++ */
++
++static void pbt_menu_set_focus(struct pbt_menu *menu, struct pbt_pane *pane)
++{
++ assert(!pane->has_focus);
++
++ if (pane == menu->dp) {
++ menu->dp->has_focus = 1;
++ menu->op->has_focus = 0;
++ } else if (pane == menu->op) {
++ menu->dp->has_focus = 0;
++ menu->op->has_focus = 1;
++// pbt_menu_set_option_focus(menu, 0);
++ } else
++ assert(0 && "bad logic");
++}
++
++static void pbt_menu_pane_select(struct pbt_menu *menu, struct pbt_pane *pane)
++{
++ if(pbt_pane_has_focus(pane))
++ return;
++
++ twin_screen_set_active(menu->scr->tscreen, pane->window->pixmap);
++
++ twin_window_damage(menu->dp->window,
++ menu->dp->focus_box.left,
++ menu->dp->focus_box.top,
++ menu->dp->focus_box.right,
++ menu->dp->focus_box.bottom);
++ twin_window_damage(menu->op->window,
++ menu->op->focus_box.left,
++ menu->op->focus_box.top,
++ menu->op->focus_box.right,
++ menu->op->focus_box.bottom);
++
++ twin_window_queue_paint(menu->dp->window);
++ twin_window_queue_paint(menu->op->window);
++
++ pbt_menu_set_focus(menu, pane);
++}
++
++
++static struct pbt_pane *pbt_device_pane_create(struct pbt_menu *menu);
++static struct pbt_pane *pbt_option_pane_create(struct pbt_menu *menu);
++
++static struct pbt_menu *pbt_menu_create(void *ctx, struct pbt_scr *scr)
++{
++ struct pbt_menu *menu = talloc_zero(ctx, struct pbt_menu);
++
++ if (!menu)
++ return NULL;
++
++ assert(scr && scr->sig == pbt_scr_sig);
++
++ menu->sig = pbt_menu_sig;
++ menu->scr = scr;
++
++ menu->dp = pbt_device_pane_create(menu);
++
++ if (!menu->dp)
++ goto fail_dp;
++
++ menu->op = pbt_option_pane_create(menu);
++
++ if (!menu->op)
++ goto fail_op;
++
++ return menu;
++
++fail_op:
++ //clean dp
++fail_dp:
++ talloc_free(menu);
++ return NULL;
++}
++
++//==============================================================================
++// device_pane
++//==============================================================================
++
++static void pbt_device_pane_draw(twin_window_t *window)
++{
++ struct pbt_pane *dp = pbt_menu_from_twindow(window)->dp;
++ twin_pixmap_t *px = window->pixmap;
++ 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 (dp->focus_curindex >= 0 &&
++ pbt_rect_intersect(dp->focus_box, px->clip)) {
++ x = twin_int_to_fixed(dp->focus_box.left + 2);
++ y = twin_int_to_fixed(dp->focus_box.top + 2);
++ w = twin_int_to_fixed(dp->focus_box.right -
++ dp->focus_box.left - 4);
++ h = twin_int_to_fixed(dp->focus_box.bottom -
++ dp->focus_box.top - 4);
++ twin_path_rounded_rectangle(path, x, y, w, h,
++ PBOOT_LEFT_FOCUS_XRAD,
++ PBOOT_LEFT_FOCUS_YRAD);
++ if (pbt_pane_has_focus(dp))
++ twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
++ else
++ twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
++ 4 * TWIN_FIXED_ONE);
++ }
++
++#if 0
++ /* 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);
++ }
++#endif
++
++ /* Destroy path */
++ twin_path_destroy(path);
++}
++
++
++static void pbt_device_pane_set_focus(struct pbt_menu *menu, int index)
++{
++#if 0
++ if (index >= pboot_dev_count)
++ return;
++#endif
++
++ menu->dp->focus_start = menu->dp->focus_box.top;
++
++ if (index < 0)
++ menu->dp->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
++ else
++ menu->dp->focus_target = PBOOT_LEFT_FOCUS_YOFF +
++ PBOOT_LEFT_ICON_STRIDE * index;
++
++ menu->dp->focus_curindex = index;
++
++ twin_set_timeout(pbt_pane_timeout, 0, menu->dp);
++}
++
++static void pbt_device_pane_mousetrack(struct pbt_menu *menu, 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 0
++ if (candidate >= pboot_dev_count) {
++ candidate = -1;
++ goto miss;
++ }
++#endif
++ if (candidate == menu->dp->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;
++ }
++
++ /* The mouse hit an icon that wasn't the same
++ * as the previous one, trigger a focus change.
++ */
++
++ pbt_device_pane_set_focus(menu, candidate);
++
++ miss:
++ menu->dp->mouse_target = candidate;
++}
++
++static twin_bool_t pbt_device_pane_event(twin_window_t *window,
++ twin_event_t *event)
++{
++ struct pbt_menu *menu = pbt_menu_from_twindow(window);
++
++ /* filter out all mouse events */
++ switch(event->kind) {
++ case TwinEventEnter:
++ case TwinEventMotion:
++ case TwinEventLeave:
++ pbt_menu_pane_select(menu, menu->dp);
++ pbt_device_pane_mousetrack(menu, 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 (menu->dp->focus_curindex > 0)
++ pbt_device_pane_set_focus(menu,
++ menu->dp->focus_curindex - 1);
++ return TWIN_TRUE;
++ case KEY_DOWN:
++ pbt_device_pane_set_focus(menu, menu->dp->focus_curindex + 1);
++ return TWIN_TRUE;
++ case KEY_RIGHT:
++ pbt_menu_pane_select(menu, menu->op);
++ return TWIN_TRUE;
++ default:
++ break;
++ }
++ break;
++ default:
++ break;
++ }
++ return TWIN_FALSE;
++}
++
++static struct pbt_pane *pbt_device_pane_create(struct pbt_menu *menu)
++{
++ struct pbt_pane *pane = talloc_zero(menu, struct pbt_pane);
++
++ if (!pane)
++ return NULL;
++
++ pane->sig = pbt_pane_sig;
++ pane->window = twin_window_create(menu->scr->tscreen, TWIN_ARGB32,
++ TwinWindowPlain, 0, 0, PBOOT_LEFT_PANE_SIZE,
++ menu->scr->tscreen->height);
++
++ if (!pane->window)
++ goto fail_window;
++
++ pane->window->draw = pbt_device_pane_draw;
++ pane->window->event = pbt_device_pane_event;
++ pane->window->client_data = menu;
++
++ pane->focus_curindex = -1;
++ pane->focus_box.left = PBOOT_LEFT_FOCUS_XOFF;
++ pane->focus_box.top = -2 * PBOOT_LEFT_FOCUS_HEIGHT;
++ pane->focus_box.right = pane->focus_box.left + PBOOT_LEFT_FOCUS_WIDTH;
++ pane->focus_box.bottom = pane->focus_box.top + PBOOT_LEFT_FOCUS_HEIGHT;
++
++ pane->mouse_target = -1;
++
++ twin_window_show(pane->window);
++ twin_window_queue_paint(pane->window);
++
++ return pane;
++
++fail_window:
++ talloc_free(pane);
++ return NULL;
++}
++
++//==============================================================================
++// option_pane
++//==============================================================================
++
++static void pbt_option_pane_set_focus(struct pbt_menu *menu, int index)
++{
++#if 0
++ 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;
++#endif
++
++ menu->op->focus_start = menu->op->focus_box.top;
++ menu->op->focus_target = PBOOT_RIGHT_FOCUS_YOFF +
++ PBOOT_RIGHT_OPTION_STRIDE * index;
++ menu->op->focus_curindex = index;
++
++ twin_set_timeout(pbt_pane_timeout, 0, menu->op);
++}
++
++static void pbt_option_pane_draw(twin_window_t *window)
++{
++ struct pbt_pane *op = pbt_menu_from_twindow(window)->op;
++ twin_pixmap_t *px = window->pixmap;
++// 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 (op->focus_curindex >= 0 &&
++ pbt_rect_intersect(op->focus_box, px->clip)) {
++ x = twin_int_to_fixed(op->focus_box.left + 2);
++ y = twin_int_to_fixed(op->focus_box.top + 2);
++ w = twin_int_to_fixed(op->focus_box.right -
++ op->focus_box.left - 4);
++ h = twin_int_to_fixed(op->focus_box.bottom -
++ op->focus_box.top - 4);
++ twin_path_rounded_rectangle(path, x, y, w, h,
++ PBOOT_RIGHT_FOCUS_XRAD,
++ PBOOT_RIGHT_FOCUS_YRAD);
++ if (pbt_pane_has_focus(op))
++ 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 (!pbt_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 void pbt_option_pane_mousetrack(struct pbt_menu *menu, twin_coord_t x,
++ twin_coord_t y)
++{
++ int candidate = -1;
++
++ if (y < PBOOT_RIGHT_OPTION_TMARGIN)
++ goto miss;
++
++#if 0
++ pboot_device_t *dev;
++ pboot_option_t *opt;
++
++ if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
++ return;
++
++ dev = pboot_devices[pboot_dev_sel];
++
++ candidate = (y - PBOOT_RIGHT_OPTION_TMARGIN) /
++ PBOOT_RIGHT_OPTION_STRIDE;
++
++ if (candidate >= dev->option_count) {
++ candidate = -1;
++ goto miss;
++ }
++
++ if (candidate == op->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;
++ }
++#endif
++
++ pbt_option_pane_set_focus(menu, candidate);
++
++miss:
++ menu->op->mouse_target = candidate;
++}
++
++static twin_bool_t pbt_option_pane_event(twin_window_t *window,
++ twin_event_t *event)
++{
++ struct pbt_menu *menu = pbt_menu_from_twindow(window);
++
++ /* filter out all mouse events */
++ switch(event->kind) {
++ case TwinEventEnter:
++ case TwinEventMotion:
++ case TwinEventLeave:
++ pbt_menu_pane_select(menu, menu->op);
++ pbt_option_pane_mousetrack(menu, event->u.pointer.x,
++ event->u.pointer.y);
++ return TWIN_TRUE;
++ case TwinEventButtonDown:
++ pbt_menu_pane_select(menu, menu->op);
++ pbt_option_pane_mousetrack(menu, event->u.pointer.x,
++ event->u.pointer.y);
++ pbt_option_execute(menu);
++ return TWIN_TRUE;
++ case TwinEventButtonUp:
++ return TWIN_TRUE;
++ case TwinEventKeyDown:
++ switch(event->u.key.key) {
++ case KEY_UP:
++ //pbt_menu_set_option_focus(menu, menu->op->focus_curindex - 1);
++ return TWIN_TRUE;
++ case KEY_DOWN:
++ //pbt_menu_set_option_focus(menu, menu->op->focus_curindex + 1);
++ return TWIN_TRUE;
++ case KEY_LEFT:
++ pbt_menu_pane_select(menu, menu->dp);
++ return TWIN_TRUE;
++ case KEY_ENTER:
++ pbt_option_execute(menu);
++ default:
++ break;
++ }
++ break;
++ default:
++ break;
++ }
++ return TWIN_FALSE;
++}
++
++static struct pbt_pane *pbt_option_pane_create(struct pbt_menu *menu)
++{
++ struct pbt_pane *pane = talloc_zero(menu, struct pbt_pane);
++
++ if (!pane)
++ return NULL;
++
++ pane->sig = pbt_pane_sig;
++ pane->window = twin_window_create(menu->scr->tscreen, TWIN_ARGB32,
++ TwinWindowPlain, PBOOT_LEFT_PANE_SIZE, 0,
++ menu->scr->tscreen->width - PBOOT_LEFT_PANE_SIZE,
++ menu->scr->tscreen->height);
++
++ if (!pane->window)
++ goto fail_window;
++
++ pane->window->draw = pbt_option_pane_draw;
++ pane->window->event = pbt_option_pane_event;
++ pane->window->client_data = menu;
++
++ pane->focus_curindex = -1;
++ pane->focus_box.left = PBOOT_RIGHT_FOCUS_XOFF;
++ pane->focus_box.top = -2 * PBOOT_RIGHT_FOCUS_HEIGHT;
++ pane->focus_box.right = pane->window->pixmap->width
++ - 2 * PBOOT_RIGHT_FOCUS_XOFF;
++ pane->focus_box.bottom = pane->focus_box.top + PBOOT_RIGHT_FOCUS_HEIGHT;
++
++ pane->mouse_target = -1;
++
++ twin_window_show(pane->window);
++ twin_window_queue_paint(pane->window);
++
++ return pane;
++
++fail_window:
++ talloc_free(pane);
++ return NULL;
++}
++
++//==============================================================================
++// junk
++//==============================================================================
++
++#if 0
++
++static pboot_device_t *pboot_devices[PBOOT_MAX_DEV];
++static int pboot_dev_count;
++static int pboot_dev_sel = -1;
++
++
++
++
++static int pboot_vmode_change = -1;
++
++static void pboot_message(const char *fmt, ...)
++{
++ va_list ap;
++ char *msg;
++
++ va_start(ap, fmt);
++ vasprintf(&msg, fmt, ap);
++ va_end(ap);
++
++ pb_log(msg);
++}
++
++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 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;
++ struct pbt_menu *menu = NULL;
++
++ 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 = menu->op->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(struct pbt_menu *menu, int sel, int force)
++{
++ pb_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) {
++ menu->dp->focus_curindex = sel;
++ if (sel < 0)
++ menu->dp->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
++ else
++ menu->dp->focus_target = PBOOT_LEFT_FOCUS_YOFF +
++ PBOOT_LEFT_ICON_STRIDE * sel;
++ menu->op->focus_box.bottom = menu->dp->focus_target;
++ menu->op->focus_box.bottom = menu->op->focus_box.top +
++ PBOOT_RIGHT_FOCUS_HEIGHT;
++ twin_window_damage(menu->dp->window,
++ 0, 0,
++ menu->dp->window->pixmap->width,
++ menu->dp->window->pixmap->height);
++ twin_window_queue_paint(menu->dp->window);
++ }
++ menu->op->focus_curindex = -1;
++ menu->op->mouse_target = -1;
++ menu->op->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
++ menu->op->focus_box.bottom = menu->op->focus_box.top +
++ PBOOT_RIGHT_FOCUS_HEIGHT;
++ twin_window_damage(menu->op->window, 0, 0,
++ menu->op->window->pixmap->width,
++ menu->op->window->pixmap->height);
++ twin_window_queue_paint(menu->op->window);
++}
++
++static void pboot_quit(void)
++{
++ kill(0, SIGINT);
++}
++
++
++static int pboot_add_device(const char *dev_id, twin_pixmap_t *pixmap)
++{
++ int index;
++ pboot_device_t *dev;
++
++ struct pbt_menu *menu = NULL;
++
++ 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(menu->dp->window,
++ dev->box.left, dev->box.top,
++ dev->box.right, dev->box.bottom);
++ twin_window_queue_paint(menu->dp->window);
++
++ return index;
++}
++
++static int pboot_remove_device(const char *dev_id)
++{
++ pboot_device_t *dev = NULL;
++ int i, newsel = pboot_dev_sel;
++
++ struct pbt_menu *menu = NULL;
++
++ /* 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(menu, newsel, 1);
++
++ /* todo: free device & options */
++
++ return TWIN_TRUE;
++}
++#endif
++
++//------------------------------------------------------------------------------
++
++static void print_version(void)
++{
++ printf("pb-twin (" PACKAGE_NAME ") " PACKAGE_VERSION "\n");
++}
++
++static void print_usage(void)
++{
++ print_version();
++ printf(
++"Usage: pb-twin [-h, --help] [-l, --log log-file] [-r, --reset-defaults]\n"
++" [-t, --timeout] [-V, --version]\n");
++}
++
++/**
++ * enum opt_value - Tri-state options variables.
++ */
++
++enum opt_value {opt_undef = 0, opt_yes, opt_no};
++
++/**
++ * struct opts - Values from command line options.
++ */
++
++struct opts {
++ enum opt_value show_help;
++ const char *log_file;
++ enum opt_value reset_defaults;
++ enum opt_value use_timeout;
++ enum opt_value show_version;
++};
++
++/**
++ * opts_parse - Parse the command line options.
++ */
++
++static int opts_parse(struct opts *opts, int argc, char *argv[])
++{
++ static const struct option long_options[] = {
++ {"help", no_argument, NULL, 'h'},
++ {"log", required_argument, NULL, 'l'},
++ {"reset-defaults", no_argument, NULL, 'r'},
++ {"timeout", no_argument, NULL, 't'},
++ {"version", no_argument, NULL, 'V'},
++ { NULL, 0, NULL, 0},
++ };
++ static const char short_options[] = "hl:trV";
++ static const struct opts default_values = {
++ .log_file = "pb-twin.log",
++ };
++
++ *opts = default_values;
++
++ while (1) {
++ int c = getopt_long(argc, argv, short_options, long_options,
++ NULL);
++
++ if (c == EOF)
++ break;
++
++ switch (c) {
++ case 'h':
++ opts->show_help = opt_yes;
++ break;
++ case 'l':
++ opts->log_file = optarg;
++ break;
++ case 't':
++ opts->use_timeout = opt_yes;
++ break;
++ case 'r':
++ opts->reset_defaults = opt_yes;
++ break;
++ case 'V':
++ opts->show_version = opt_yes;
++ break;
++ default:
++ opts->show_help = opt_yes;
++ return -1;
++ }
++ }
++
++ return optind != argc;
++}
++
++/**
++ * struct ps3_gui - Main gui program instance.
++ */
++
++
++struct ps3_gui {
++ struct ui_timer timer;
++ struct ps3_flash_values values;
++ int dirty_values;
++
++ struct pbt_scr scr;
++ struct pbt_frame frame;
++ struct pbt_menu *menu;
++};
++
++static struct ps3_gui ps3;
++
++static struct pbt_scr *pbt_scr_from_tscreen(twin_screen_t *tscreen)
++{
++ assert(ps3.scr.sig == pbt_scr_sig);
++ assert(ps3.scr.tscreen == tscreen);
++ return &ps3.scr;
++}
++
++static void sig_handler(int signum)
++{
++ DBGS("%d\n", signum);
++
++ switch (signum) {
++ case SIGALRM:
++ ui_timer_sigalrm(&ps3.timer);
++ break;
++ case SIGWINCH:
++// if (ps3.gui)
++// gui_resize(ps3.gui);
++ break;
++ default:
++ assert(0 && "unknown sig");
++ /* fall through */
++ case SIGINT:
++ case SIGHUP:
++ case SIGTERM:
++ exit(EXIT_FAILURE);
++// if (ps3.gui)
++// gui_abort(ps3.gui);
++ break;
++ }
++}
+
+/**
+ * main - twin bootloader main routine.
-+ *
-+ * Returns:
-+ * 0 = Returned as success by ps3-utils programs.
-+ * 1 = Error, expecting a restart.
-+ * 22 = Exit to shell.
+ */
+
-+int main(void)
++int main(int argc, char *argv[])
+{
++ static struct sigaction sa;
++ static struct opts opts;
++ int result;
++ int ui_result;
++ unsigned int mode;
+ FILE *log;
+
-+ log = fopen("pb-twin.log", "a");
++ result = opts_parse(&opts, argc, argv);
++
++ if (result) {
++ print_usage();
++ return EXIT_FAILURE;
++ }
++
++ if (opts.show_help == opt_yes) {
++ print_usage();
++ return EXIT_SUCCESS;
++ }
++
++ if (opts.show_version == opt_yes) {
++ print_version();
++ return EXIT_SUCCESS;
++ }
++
++ log = fopen(opts.log_file, "a");
+ assert(log);
+ pb_log_set_stream(log);
+
+
+ pb_log("--- pb-twin ---\n");
+
-+ pboot_fbdev = twin_fbdev_create(-1, SIGUSR1);
-+ if (pboot_fbdev == NULL) {
-+ perror("failed to create fbdev screen !\n");
-+ return 1;
++ sa.sa_handler = sig_handler;
++ result = sigaction(SIGALRM, &sa, NULL);
++ result += sigaction(SIGHUP, &sa, NULL);
++ result += sigaction(SIGINT, &sa, NULL);
++ result += sigaction(SIGTERM, &sa, NULL);
++ result += sigaction(SIGWINCH, &sa, NULL);
++
++ if (result) {
++ pb_log("%s sigaction failed.\n", __func__);
++ return EXIT_FAILURE;
++ }
++
++ ps3.values = ps3_flash_defaults;
++
++ if (opts.reset_defaults != opt_yes)
++ ps3.dirty_values = ps3_flash_get_values(&ps3.values);
++
++ twin_feature_init(); // need it???
++
++ /* Setup screen. */
++
++ ps3.scr.sig = pbt_scr_sig;
++
++#if defined(HAVE_LIBTWIN_TWIN_X11_H)
++# if defined(USE_X11)
++ if (1) {
++# else
++ if (0) {
++# endif
++ ps3.scr.x11 = twin_x11_create(XOpenDisplay(0), 1024, 768);
++
++ if (!ps3.scr.x11) {
++ perror("failed to create x11 screen !\n");
++ return EXIT_FAILURE;
++ }
++
++ ps3.scr.tscreen = ps3.scr.x11->screen;
++ } else {
++#else
++ if (1) {
++#endif
++ result = ps3_get_video_mode(&mode);
++
++ /* Current becomes default if ps3_flash_get_values() failed. */
++
++ if (ps3.dirty_values && !result)
++ ps3.values.video_mode = mode;
++
++ /* Set mode if not at default. */
++
++ if (!result && (ps3.values.video_mode != (uint16_t)mode))
++ ps3_set_video_mode(ps3.values.video_mode);
++
++ ps3.scr.fbdev = twin_fbdev_create(-1, SIGUSR1);
++
++ if (!ps3.scr.fbdev) {
++ perror("failed to create fbdev screen !\n");
++ return EXIT_FAILURE;
++ }
++
++ ps3.scr.tscreen = ps3.scr.fbdev->screen;
+ }
+
++ ps3.scr.tscreen->event_filter = pbt_scr_event;
++
++ twin_screen_set_background(ps3.scr.tscreen,
++ pbt_load_background(ps3.scr.tscreen));
++
++ /* setup menu */
++
++ ps3.menu = pbt_menu_create(NULL, &ps3.scr);
++
++ pbt_device_pane_set_focus(ps3.menu, 0);
++ twin_screen_set_active(ps3.scr.tscreen, ps3.menu->dp->window->pixmap);
++
++ /* Console switch */
++
++ if (ps3.scr.fbdev)
++ twin_fbdev_activate(ps3.scr.fbdev);
++
++ /* run twin */
++
++// twin_toplevel_show(ps3.toplevel);
++ twin_dispatch();
++
+ pb_log("--- end ---\n");
+
-+ return 22;
++ return ui_result ? EXIT_FAILURE : EXIT_SUCCESS;
+}