[packages] flashrom: update source url, use PKG_INSTALL & MAKE_FLAGS, refresh patches
[openwrt/svn-archive/archive.git] / utils / petitboot / patches / 020-petitboot-fix-pb-twin.diff
index e8589c5c1cc866c89792a5977bb6c9b09bfe454a..aa24f56598e362e90ef264898222c3dcf14b9590 100644 (file)
@@ -6,10 +6,43 @@ Update the PS3 twin GUI program to work with petitboot-multi-ui.
 
 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
@@ -21,39 +54,1373 @@ Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
  
  # 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);
 +
@@ -63,13 +1430,92 @@ Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
 +
 +      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;
 +}