+++ /dev/null
- 12 files changed, 96 insertions(+), 40 deletions(-)
-
-diff --git a/discover/kboot-parser.c b/discover/kboot-parser.c
-index 23d48a4..7c7cb5d 100644
---- a/discover/kboot-parser.c
-+++ b/discover/kboot-parser.c
-@@ -133,7 +133,7 @@ static int kboot_parse(struct discover_context *dc)
- conf = talloc_zero(dc, struct conf_context);
-
- if (!conf)
-- return -1;
-+ return 0;
-
- conf->dc = dc;
- conf->global_options = kboot_global_options,
-diff --git a/discover/parser.c b/discover/parser.c
-index 2b4ddd2..8f2735c 100644
---- a/discover/parser.c
-+++ b/discover/parser.c
-@@ -13,16 +13,16 @@ extern struct parser __start_parsers[], __stop_parsers[];
- void iterate_parsers(struct discover_context *ctx)
- {
- struct parser *parser;
-+ unsigned int count = 0;
-
- pb_log("trying parsers for %s\n", ctx->device_path);
-
- for (parser = __start_parsers; parser < __stop_parsers; parser++) {
- pb_log("\ttrying parser '%s'\n", parser->name);
-- /* just use a dummy device path for now */
-- if (parser->parse(ctx))
-- return;
-+ count += parser->parse(ctx);
- }
-- pb_log("\tno boot_options found\n");
-+ if (!count)
-+ pb_log("\tno boot_options found\n");
- }
-
- static int compare_parsers(const void *a, const void *b)
-diff --git a/discover/yaboot-parser.c b/discover/yaboot-parser.c
-index 1000505..6101cd8 100644
---- a/discover/yaboot-parser.c
-+++ b/discover/yaboot-parser.c
-@@ -295,7 +295,7 @@ static int yaboot_parse(struct discover_context *dc)
- conf = talloc_zero(dc, struct conf_context);
-
- if (!conf)
-- return -1;
-+ return 0;
-
- conf->dc = dc;
- conf->global_options = yaboot_global_options,
-diff --git a/lib/log/log.h b/lib/log/log.h
-index 2a5d375..6f44bea 100644
---- a/lib/log/log.h
-+++ b/lib/log/log.h
-@@ -3,7 +3,7 @@
-
- #include <stdio.h>
-
--void pb_log(const char *fmt, ...);
-+void __attribute__ ((format (printf, 1, 2))) pb_log(const char *fmt, ...);
- void pb_log_set_stream(FILE *stream);
- FILE * pb_log_get_stream(void);
- void pb_log_always_flush(int state);
-diff --git a/lib/system/system.c b/lib/system/system.c
-index 65bd6bf..7371445 100644
---- a/lib/system/system.c
-+++ b/lib/system/system.c
-@@ -20,6 +20,7 @@ const struct pb_system_apps pb_system_apps = {
- .cp = "/bin/cp",
- .kexec = "/sbin/kexec",
- .mount = "/bin/mount",
-+ .shutdown = "/sbin/shutdown",
- .sftp = "/usr/bin/sftp",
- .tftp = "/usr/bin/tftp",
- .umount = "/bin/umount",
-diff --git a/lib/system/system.h b/lib/system/system.h
-index 47c7c02..1918309 100644
---- a/lib/system/system.h
-+++ b/lib/system/system.h
-@@ -5,6 +5,7 @@ struct pb_system_apps {
- const char *cp;
- const char *kexec;
- const char *mount;
-+ const char *shutdown;
- const char *sftp;
- const char *tftp;
- const char *umount;
-diff --git a/ui/common/discover-client.c b/ui/common/discover-client.c
-index e8ce4dd..5b42b6c 100644
---- a/ui/common/discover-client.c
-+++ b/ui/common/discover-client.c
-@@ -46,7 +46,7 @@ struct discover_client* discover_client_init(
- client->ops.cb_arg = cb_arg;
-
- client->fd = socket(AF_UNIX, SOCK_STREAM, 0);
-- if (!client->fd < 0) {
-+ if (client->fd < 0) {
- pb_log("%s: socket: %s\n", __func__, strerror(errno));
- goto out_err;
- }
-diff --git a/ui/common/loader.c b/ui/common/loader.c
-index 0fe62a0..5c69533 100644
---- a/ui/common/loader.c
-+++ b/ui/common/loader.c
-@@ -263,16 +263,22 @@ fail:
- /**
- * pb_load_file - Loads a remote file and returns the local file path.
- * @ctx: The talloc context to associate with the returned string.
-+ * @remote: The remote file URL.
-+ * @tempfile: An optional variable pointer to be set when a temporary local
-+ * file is created.
- *
- * Returns the local file path in a talloc'ed character string on success,
- * or NULL on error.
- */
-
--char *pb_load_file(void *ctx, const char *remote)
-+char *pb_load_file(void *ctx, const char *remote, unsigned int *tempfile)
- {
- char *local;
- struct pb_url *url = pb_url_parse(NULL, remote);
-
-+ if (tempfile)
-+ *tempfile = 0;
-+
- if (!url)
- return NULL;
-
-@@ -280,19 +286,28 @@ char *pb_load_file(void *ctx, const char *remote)
- case pb_url_ftp:
- case pb_url_http:
- local = pb_load_wget(ctx, url, 0);
-+ if (tempfile && local)
-+ *tempfile = 1;
- break;
- case pb_url_https:
-- local = pb_load_wget(ctx, url,
-- wget_no_check_certificate);
-+ local = pb_load_wget(ctx, url, wget_no_check_certificate);
-+ if (tempfile && local)
-+ *tempfile = 1;
- break;
- case pb_url_nfs:
- local = pb_load_nfs(ctx, url);
-+ if (tempfile && local)
-+ *tempfile = 1;
- break;
- case pb_url_sftp:
- local = pb_load_sftp(ctx, url);
-+ if (tempfile && local)
-+ *tempfile = 1;
- break;
- case pb_url_tftp:
- local = pb_load_tftp(ctx, url);
-+ if (tempfile && local)
-+ *tempfile = 1;
- break;
- default:
- local = talloc_strdup(ctx, url->full);
-diff --git a/ui/common/loader.h b/ui/common/loader.h
-index b06bb43..42d4d4b 100644
---- a/ui/common/loader.h
-+++ b/ui/common/loader.h
-@@ -19,6 +19,6 @@
- #if !defined(_PB_FILE_LOADER_H)
- #define _PB_FILE_LOADER_H
-
--char *pb_load_file(void *ctx, const char *remote);
-+char *pb_load_file(void *ctx, const char *remote, unsigned int *tempfile);
-
- #endif
-diff --git a/ui/common/ps3.c b/ui/common/ps3.c
-index cb1c8d1..c62a10d 100644
---- a/ui/common/ps3.c
-+++ b/ui/common/ps3.c
-@@ -87,7 +87,7 @@ static int ps3_flash_open(struct ps3_flash_ctx *fc, const char *mode)
- result = os_area_fixed_read(&fc->header, &fc->params, fc->dev);
-
- if (result) {
-- pb_log("%s: os_area_fixed_read failed: %s\n", __func__);
-+ pb_log("%s: os_area_fixed_read failed\n", __func__);
- goto fail;
- }
-
-@@ -114,7 +114,7 @@ int ps3_flash_get_values(struct ps3_flash_values *values)
- result = ps3_flash_open(&fc, "r");
-
- if (result)
-- goto done;
-+ goto fail;
-
- result = os_area_db_read(&fc.db, &fc.header, fc.dev);
-
-@@ -123,7 +123,7 @@ int ps3_flash_get_values(struct ps3_flash_values *values)
- if (result) {
- pb_log("%s: os_area_db_read failed: %s\n", __func__,
- strerror(errno));
-- goto done;
-+ goto fail;
- }
-
- sum = result = os_area_db_get(&fc.db, &id_default_item, &tmp);
-@@ -141,14 +141,13 @@ int ps3_flash_get_values(struct ps3_flash_values *values)
- if (!result)
- values->video_mode = (uint16_t)tmp;
-
--done:
- pb_log("%s: default_item: %x\n", __func__,
- (unsigned int)values->default_item);
- pb_log("%s: timeout: %u\n", __func__,
- (unsigned int)values->timeout);
- pb_log("%s: video_mode: %u\n", __func__,
- (unsigned int)values->video_mode);
--
-+fail:
- return (result || sum) ? -1 : 0;
- }
-
-diff --git a/ui/common/ui-system.c b/ui/common/ui-system.c
-index bd6dd31..0140f0e 100644
---- a/ui/common/ui-system.c
-+++ b/ui/common/ui-system.c
-@@ -33,13 +33,13 @@
- #include "ui-system.h"
-
- /**
-- * run_kexec_local - Final kexec helper.
-+ * kexec_load - kexec load helper.
- * @l_image: The local image file for kexec to execute.
- * @l_initrd: Optional local initrd file for kexec --initrd, can be NULL.
- * @args: Optional command line args for kexec --append, can be NULL.
- */
-
--static int run_kexec_local(const char *l_image, const char *l_initrd,
-+static int kexec_load(const char *l_image, const char *l_initrd,
- const char *args)
- {
- int result;
-@@ -49,34 +49,64 @@ static int run_kexec_local(const char *l_image, const char *l_initrd,
- char *s_args = NULL;
-
- p = argv;
-- *p++ = pb_system_apps.kexec; /* 1 */
-+ *p++ = pb_system_apps.kexec; /* 1 */
-+ *p++ = "-l"; /* 2 */
-
- if (l_initrd) {
- s_initrd = talloc_asprintf(NULL, "--initrd=%s", l_initrd);
- assert(s_initrd);
-- *p++ = s_initrd; /* 2 */
-+ *p++ = s_initrd; /* 3 */
- }
-
- if (args) {
- s_args = talloc_asprintf(NULL, "--append=%s", args);
- assert(s_args);
-- *p++ = s_args; /* 3 */
-+ *p++ = s_args; /* 4 */
- }
-
-- /* First try by telling kexec to run shutdown */
-+ *p++ = l_image; /* 5 */
-+ *p++ = NULL; /* 6 */
-
-- *(p + 0) = l_image;
-- *(p + 1) = NULL;
-+ result = pb_run_cmd(argv);
-+
-+ if (result)
-+ pb_log("%s: failed: (%d)\n", __func__, result);
-+
-+ talloc_free(s_initrd);
-+ talloc_free(s_args);
-+
-+ return result;
-+}
-+
-+/**
-+ * kexec_reboot - Helper to boot the new kernel.
-+ *
-+ * Must only be called after a successful call to kexec_load().
-+ */
-+
-+static int kexec_reboot(void)
-+{
-+ int result;
-+ const char *argv[4];
-+ const char **p;
-+
-+ /* First try running shutdown. Init scripts should run 'exec -e' */
-+
-+ p = argv;
-+ *p++ = pb_system_apps.shutdown; /* 1 */
-+ *p++ = "-r"; /* 2 */
-+ *p++ = "now"; /* 3 */
-+ *p++ = NULL; /* 4 */
-
- result = pb_run_cmd(argv);
-
-- /* kexec will return zero on success */
-- /* On error, force a kexec with the -f option */
-+ /* On error, force a kexec with the -e option */
-
- if (result) {
-- *(p + 0) = "-f"; /* 4 */
-- *(p + 1) = l_image; /* 5 */
-- *(p + 2) = NULL; /* 6 */
-+ p = argv;
-+ *p++ = pb_system_apps.kexec; /* 1 */
-+ *p++ = "-e"; /* 2 */
-+ *p++ = NULL; /* 3 */
-
- result = pb_run_cmd(argv);
- }
-@@ -84,9 +114,6 @@ static int run_kexec_local(const char *l_image, const char *l_initrd,
- if (result)
- pb_log("%s: failed: (%d)\n", __func__, result);
-
-- talloc_free(s_initrd);
-- talloc_free(s_args);
--
- return result;
- }
-
-@@ -99,31 +126,44 @@ int pb_run_kexec(const struct pb_kexec_data *kd)
- int result;
- char *l_image = NULL;
- char *l_initrd = NULL;
-+ unsigned int clean_image = 0;
-+ unsigned int clean_initrd = 0;
-
- pb_log("%s: image: '%s'\n", __func__, kd->image);
- pb_log("%s: initrd: '%s'\n", __func__, kd->initrd);
- pb_log("%s: args: '%s'\n", __func__, kd->args);
-
-+ result = -1;
-+
- if (kd->image) {
-- l_image = pb_load_file(NULL, kd->image);
-+ l_image = pb_load_file(NULL, kd->image, &clean_image);
- if (!l_image)
-- return -1;
-+ goto no_load;
- }
-
- if (kd->initrd) {
-- l_initrd = pb_load_file(NULL, kd->initrd);
-+ l_initrd = pb_load_file(NULL, kd->initrd, &clean_initrd);
- if (!l_initrd)
-- return -1;
-+ goto no_load;
- }
-
- if (!l_image && !l_initrd)
-- return -1;
-+ goto no_load;
-+
-+ result = kexec_load(l_image, l_initrd, kd->args);
-
-- result = run_kexec_local(l_image, l_initrd, kd->args);
-+no_load:
-+ if (clean_image)
-+ unlink(l_image);
-+ if (clean_initrd)
-+ unlink(l_initrd);
-
- talloc_free(l_image);
- talloc_free(l_initrd);
-
-+ if (!result)
-+ result = kexec_reboot();
-+
- return result;
- }
-
-diff --git a/ui/common/url.c b/ui/common/url.c
-index 0de0f58..544eee2 100644
---- a/ui/common/url.c
-+++ b/ui/common/url.c
-@@ -140,7 +140,7 @@ struct pb_url *pb_url_parse(void *ctx, const char *url_str)
- path = strchr(p, '/');
-
- if (!path) {
-- pb_log("%s: parse path failed '%s'\n", p);
-+ pb_log("%s: parse path failed '%s'\n", __func__ , p);
- goto fail;
- }
-
+++ /dev/null
-a work-in-progress
-
-Subject: Update PS3 twin GUI program
-
-Update the PS3 twin GUI program to work with petitboot-multi-ui.
-
-Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
----
- 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
- ui/common/url.o
- ncurses_objs = ui/ncurses/nc-scr.o ui/ncurses/nc-menu.o ui/ncurses/nc-ked.o \
- ui/ncurses/nc-cui.o
--twin_objs = ui/twin/pb-twin.o
-+twin_objs =
-
- # 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,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
-+ */
-+
-+#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>
-+#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.
-+ */
-+
-+int main(int argc, char *argv[])
-+{
-+ static struct sigaction sa;
-+ static struct opts opts;
-+ int result;
-+ int ui_result;
-+ unsigned int mode;
-+ FILE *log;
-+
-+ 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);
-+
-+#if defined(DEBUG)
-+ pb_log_always_flush(1);
-+#endif
-+
-+ pb_log("--- pb-twin ---\n");
-+
-+ 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 ui_result ? EXIT_FAILURE : EXIT_SUCCESS;
-+}