branch Attitude Adjustment packages
[12.09/packages.git] / utils / petitboot / patches / 020-petitboot-fix-pb-twin.diff
1 a work-in-progress
2
3 Subject: Update PS3 twin GUI program
4
5 Update the PS3 twin GUI program to work with petitboot-multi-ui.
6
7 Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
8 ---
9  Makefile.in        |    1 
10  configure.ac       |   12 
11  rules.mk           |   14 
12  ui/twin/ps3-twin.c | 1441 +++++++++++++++++++++++++++++++++++++++++++++++++++++
13  4 files changed, 1463 insertions(+), 5 deletions(-)
14
15 --- a/Makefile.in
16 +++ b/Makefile.in
17 @@ -18,6 +18,7 @@ twin_LDFLAGS = @twin_LIBS@
18  
19  # build target
20  ENABLE_PS3 = @ENABLE_PS3@
21 +ENABLE_X11 = @ENABLE_X11@
22  
23  # other programs
24  INSTALL = @INSTALL@
25 --- a/configure.ac
26 +++ b/configure.ac
27 @@ -56,7 +56,17 @@ AS_IF([test "x$with_twin" != xno],
28                 [if test "x$with_twin" != xcheck; then
29                         AC_MSG_FAILURE([--with-twin was given, but test for twin failed])
30                 fi],
31 -               [${twin_LIBS}])])
32 +               [${twin_LIBS}])
33 +       AC_CHECK_HEADERS([libtwin/twin_x11.h])])
34 +
35 +AC_ARG_ENABLE([x11],
36 +       [AS_HELP_STRING([--enable-x11],
37 +               [build for x11])],
38 +       [],
39 +       [enable_x11=check])
40 +
41 +AS_IF([test "x$enable_x11" != xno], [AC_SUBST([ENABLE_X11], ["y"])], [])
42 +
43  
44  mkdir -p discover lib/list lib/log lib/pb-protocol lib/system lib/talloc \
45         lib/waiter test ui/common ui/ncurses ui/test ui/twin utils
46 --- a/rules.mk
47 +++ b/rules.mk
48 @@ -54,7 +54,7 @@ ui_common_objs = ui/common/discover-clie
49         ui/common/url.o
50  ncurses_objs = ui/ncurses/nc-scr.o ui/ncurses/nc-menu.o ui/ncurses/nc-ked.o \
51         ui/ncurses/nc-cui.o
52 -twin_objs = ui/twin/pb-twin.o
53 +twin_objs =
54  
55  # Makefiles
56  makefiles = Makefile $(top_srcdir)/rules.mk
57 @@ -89,11 +89,17 @@ $(pb_test): $(pb_test_objs)
58         $(LINK.o) -o $@ $^
59  
60  # twin gui
61 -pb_twin_objs = $(client_objs) $(twin_objs) ui/twin/ps3-twin.o
62 +pb_twin_objs-y$(ENABLE_PS3) += ui/twin/pb-twin.o
63 +pb_twin_objs-$(ENABLE_PS3) += ui/twin/ps3-twin.o ui/common/ps3.o
64 +pb_twin_cflags-$(ENABLE_X11) += -DUSE_X11
65 +pb_twin_ldflags-$(ENABLE_PS3) += -lps3-utils
66 +
67 +pb_twin_objs = $(client_objs) $(twin_objs)  $(pb_twin_objs-y)
68  $(pb_twin_objs): $(makefiles)
69  
70 -$(pb_twin): LDFLAGS+=$(twin_LDFLAGS) $(LIBTWIN)
71 -$(pb_twin): CFLAGS+=$(twin_CFLAGS)
72 +$(pb_twin): LDFLAGS += $(pb_twin_ldflags-y) $(twin_LDFLAGS) $(LIBTWIN)
73 +$(pb_twin): CFLAGS += $(pb_twin_cflags-y) $(twin_CFLAGS) \
74 +       -DPB_ARTWORK_PATH='"$(pkgdatadir)/artwork/"'
75  
76  $(pb_twin): $(pb_twin_objs)
77         $(LINK.o) -o $@ $^
78 --- /dev/null
79 +++ b/ui/twin/ps3-twin.c
80 @@ -0,0 +1,1441 @@
81 +/*
82 + * Petitboot twin bootloader for the PS3 game console
83 + *
84 + *  Copyright (C) 2009 Sony Computer Entertainment Inc.
85 + *  Copyright 2009 Sony Corp.
86 + *
87 + *  This program is free software; you can redistribute it and/or modify
88 + *  it under the terms of the GNU General Public License as published by
89 + *  the Free Software Foundation; version 2 of the License.
90 + *
91 + *  This program is distributed in the hope that it will be useful,
92 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
93 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
94 + *  GNU General Public License for more details.
95 + *
96 + *  You should have received a copy of the GNU General Public License
97 + *  along with this program; if not, write to the Free Software
98 + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
99 + */
100 +
101 +#if defined(HAVE_CONFIG_H)
102 +#include "config.h"
103 +#endif
104 +
105 +#define _GNU_SOURCE
106 +#include <assert.h>
107 +#include <errno.h>
108 +#include <getopt.h>
109 +#include <signal.h>
110 +#include <stdlib.h>
111 +#include <string.h>
112 +#include <sys/time.h>
113 +#include <libtwin/twin.h>
114 +#include <libtwin/twin_fbdev.h>
115 +#include <libtwin/twin_jpeg.h>
116 +#include <libtwin/twin_linux_mouse.h>
117 +#include <libtwin/twin_linux_js.h>
118 +#include <libtwin/twin_png.h>
119 +#if defined(HAVE_LIBTWIN_TWIN_X11_H)
120 +# include <libtwin/twin_x11.h>
121 +#endif
122 +#include <linux/input.h>
123 +
124 +#include "log/log.h"
125 +#include "talloc/talloc.h"
126 +#include "waiter/waiter.h"
127 +#include "ui/common/discover-client.h"
128 +#include "ui/common/ps3.h"
129 +#include "ui/common/timer.h"
130 +
131 +//------------------------------------------------------------------------------
132 +// twin-ui.c/h
133 +
134 +#define DBG(fmt, args...) pb_log("DBG: " fmt, ## args)
135 +#define DBGS(fmt, args...) \
136 +       pb_log("DBG:%s:%d: " fmt, __func__, __LINE__, ## args)
137 +
138 +/* control to keyboard mappings for the sixaxis controller */
139 +uint8_t sixaxis_map[] = {
140 +       0,              /*   0  Select          */
141 +       0,              /*   1  L3              */
142 +       0,              /*   2  R3              */
143 +       0,              /*   3  Start           */
144 +       KEY_UP,         /*   4  Dpad Up         */
145 +       KEY_RIGHT,      /*   5  Dpad Right      */
146 +       KEY_DOWN,       /*   6  Dpad Down       */
147 +       KEY_LEFT,       /*   7  Dpad Left       */
148 +       0,              /*   8  L2              */
149 +       0,              /*   9  R2              */
150 +       0,              /*  10  L1              */
151 +       0,              /*  11  R1              */
152 +       0,              /*  12  Triangle        */
153 +       KEY_ENTER,      /*  13  Circle          */
154 +       0,              /*  14  Cross           */
155 +       KEY_DELETE,     /*  15  Square          */
156 +       0,              /*  16  PS Button       */
157 +       0,              /*  17  nothing      */
158 +       0,              /*  18  nothing      */
159 +};
160 +
161 +#define PBOOT_LEFT_PANE_SIZE           160
162 +#define PBOOT_LEFT_PANE_COLOR          0x80000000
163 +#define PBOOT_LEFT_LINE_COLOR          0xff000000
164 +
165 +#define PBOOT_LEFT_FOCUS_WIDTH         80
166 +#define PBOOT_LEFT_FOCUS_HEIGHT                80
167 +#define PBOOT_LEFT_FOCUS_XOFF          40
168 +#define PBOOT_LEFT_FOCUS_YOFF          40
169 +#define PBOOT_LEFT_FOCUS_XRAD          (6 * TWIN_FIXED_ONE)
170 +#define PBOOT_LEFT_FOCUS_YRAD          (6 * TWIN_FIXED_ONE)
171 +
172 +#define PBOOT_RIGHT_FOCUS_XOFF         20
173 +#define PBOOT_RIGHT_FOCUS_YOFF         60
174 +#define PBOOT_RIGHT_FOCUS_HEIGHT       80
175 +#define PBOOT_RIGHT_FOCUS_XRAD         (6 * TWIN_FIXED_ONE)
176 +#define PBOOT_RIGHT_FOCUS_YRAD         (6 * TWIN_FIXED_ONE)
177 +
178 +#define PBOOT_LEFT_ICON_WIDTH          64
179 +#define PBOOT_LEFT_ICON_HEIGHT         64
180 +#define PBOOT_LEFT_ICON_XOFF           50
181 +#define PBOOT_LEFT_ICON_YOFF           50
182 +#define PBOOT_LEFT_ICON_STRIDE         100
183 +
184 +#define PBOOT_RIGHT_OPTION_LMARGIN     30
185 +#define PBOOT_RIGHT_OPTION_RMARGIN     30
186 +#define PBOOT_RIGHT_OPTION_TMARGIN     70
187 +#define PBOOT_RIGHT_OPTION_HEIGHT      64
188 +#define PBOOT_RIGHT_OPTION_STRIDE      100
189 +#define PBOOT_RIGHT_TITLE_TEXT_SIZE    (30 * TWIN_FIXED_ONE)
190 +#define PBOOT_RIGHT_SUBTITLE_TEXT_SIZE (18 * TWIN_FIXED_ONE)
191 +#define PBOOT_RIGHT_TITLE_XOFFSET      80
192 +#define PBOOT_RIGHT_TITLE_YOFFSET      30
193 +#define PBOOT_RIGHT_SUBTITLE_XOFFSET   100
194 +#define PBOOT_RIGHT_SUBTITLE_YOFFSET   50
195 +#define PBOOT_RIGHT_BADGE_XOFFSET      2
196 +#define PBOOT_RIGHT_BADGE_YOFFSET      0
197 +
198 +
199 +#define PBOOT_RIGHT_TITLE_COLOR                0xff000000
200 +#define PBOOT_RIGHT_SUBTITLE_COLOR     0xff400000
201 +
202 +#define PBOOT_FOCUS_COLOR              0x10404040
203 +
204 +#define PBOOT_STATUS_PANE_COLOR                0x60606060
205 +#define PBOOT_STATUS_PANE_HEIGHT       20
206 +#define PBOOT_STATUS_PANE_XYMARGIN     20
207 +#define PBOOT_STATUS_TEXT_MARGIN       10
208 +#define PBOOT_STATUS_TEXT_SIZE         (16 * TWIN_FIXED_ONE)
209 +#define PBOOT_STATUS_TEXT_COLOR                0xff000000
210 +
211 +#define PBOOT_MAX_OPTION 100
212 +#define PBOOT_MAX_DEV 10
213 +
214 +struct pbt_option
215 +{
216 +       char            *title;
217 +       char            *subtitle;
218 +       twin_pixmap_t   *badge;
219 +       twin_pixmap_t   *cache;
220 +       twin_rect_t     box;
221 +       void            *data;
222 +};
223 +
224 +struct pbt_device
225 +{
226 +       char                    *id;
227 +       twin_pixmap_t           *badge;
228 +       twin_rect_t             box;
229 +       int                     option_count;
230 +       struct pbt_option               options[PBOOT_MAX_OPTION];
231 +};
232 +
233 +enum pbt_sig {
234 +       pbt_scr_sig = 111,
235 +       pbt_menu_sig = 222,
236 +       pbt_pane_sig = 333,
237 +       pb_removed_sig = -555,
238 +};
239 +
240 +struct pbt_cursor {
241 +       twin_pixmap_t *pixmap;
242 +       int hx;
243 +       int hy;
244 +};
245 +
246 +struct pbt_scr {
247 +       enum pbt_sig sig;
248 +       struct pbt_cursor cursor;
249 +       twin_screen_t *tscreen;
250 +#if defined(HAVE_LIBTWIN_TWIN_X11_H)
251 +       twin_x11_t *x11;
252 +#endif
253 +       twin_fbdev_t *fbdev;
254 +};
255 +
256 +struct pbt_frame {
257 +       twin_label_t *title;
258 +       twin_label_t *help;
259 +       twin_label_t *status;
260 +};
261 +
262 +/**
263 + * struct pbt_pane - A twin menu pane.
264 + */
265 +
266 +struct pbt_pane {
267 +       enum pbt_sig sig;
268 +       twin_window_t *window;
269 +       twin_rect_t focus_box;
270 +       int focus_start;
271 +       int focus_target;
272 +       int focus_curindex;
273 +       int mouse_target;
274 +       int has_focus;
275 +};
276 +
277 +/**
278 + * struct pbt_menu - A twin menu.
279 + * @sig: Sanity check signature.
280 + * @scr: The screen this menu is associated with.
281 + * @dp: The device pane instance.
282 + * @op: The option pane instance.
283 + */
284 +
285 +struct pbt_menu {
286 +       enum pbt_sig sig;
287 +       struct pbt_scr *scr;
288 +       struct pbt_pane *dp;
289 +       struct pbt_pane *op;
290 +};
291 +
292 +//==============================================================================
293 +// helper
294 +//==============================================================================
295 +
296 +static struct pbt_scr *pbt_scr_from_tscreen(twin_screen_t *tscreen);
297 +
298 +static struct pbt_menu *pbt_menu_from_twindow(twin_window_t *twindow)
299 +{
300 +       struct pbt_menu *menu = twindow->client_data;
301 +
302 +       assert(menu);
303 +       assert(menu->sig == pbt_menu_sig);
304 +       return menu;
305 +}
306 +
307 +/*
308 +static struct pbt_menu *pbt_menu_from_arg(void *arg)
309 +{
310 +       struct pbt_menu *menu = arg;
311 +
312 +       assert(menu);
313 +       assert(menu->sig == pbt_menu_sig);
314 +       return menu;
315 +}
316 +*/
317 +
318 +static struct pbt_pane *pbt_pane_from_arg(void *arg)
319 +{
320 +       struct pbt_pane *pane = arg;
321 +
322 +       assert(pane);
323 +       assert(pane->sig == pbt_pane_sig);
324 +       return pane;
325 +}
326 +
327 +static twin_bool_t pbt_rect_intersect(twin_rect_t r1, twin_rect_t r2)
328 +{
329 +       // FIXME: move this to twin!!!
330 +       return !(r1.left > r2.right ||
331 +                r1.right < r2.left ||
332 +                r1.top > r2.bottom ||
333 +                r1.bottom < r2.top);
334 +}
335 +
336 +static twin_pixmap_t * pbt_load_background(twin_screen_t *tscreen)
337 +{
338 +       static const char *bgd = PB_ARTWORK_PATH "/background.jpg";
339 +       twin_pixmap_t *rawpix;
340 +       twin_pixmap_t *scaledpix;
341 +
342 +       rawpix = twin_jpeg_to_pixmap(bgd, TWIN_ARGB32);
343 +
344 +       if (!rawpix) {
345 +               pb_log("%s: loading image %s failed\n", __func__, bgd);
346 +               return twin_make_pattern();
347 +       }
348 +
349 +       if (tscreen->height == rawpix->height &&
350 +               tscreen->width == rawpix->width)
351 +               return rawpix;
352 +
353 +       /* Scale as needed. */
354 +
355 +       twin_fixed_t sx, sy;
356 +       twin_operand_t srcop;
357 +
358 +       scaledpix = twin_pixmap_create(TWIN_ARGB32,
359 +                               tscreen->width,
360 +                               tscreen->height);
361 +       if (!scaledpix) {
362 +               pb_log("%s: scale %s failed\n", __func__, bgd);
363 +               twin_pixmap_destroy(rawpix);
364 +               return twin_make_pattern();
365 +       }
366 +       sx = twin_fixed_div(twin_int_to_fixed(rawpix->width),
367 +                       twin_int_to_fixed(tscreen->width));
368 +       sy = twin_fixed_div(twin_int_to_fixed(rawpix->height),
369 +                       twin_int_to_fixed(tscreen->height));
370 +
371 +       twin_matrix_scale(&rawpix->transform, sx, sy);
372 +       srcop.source_kind = TWIN_PIXMAP;
373 +       srcop.u.pixmap = rawpix;
374 +       twin_composite(scaledpix, 0, 0, &srcop, 0, 0,
375 +               NULL, 0, 0, TWIN_SOURCE,
376 +               tscreen->width, tscreen->height);
377 +
378 +       twin_pixmap_destroy(rawpix);
379 +       return scaledpix;
380 +}
381 +
382 +//==============================================================================
383 +// option
384 +//==============================================================================
385 +
386 +static void pbt_option_execute(struct pbt_menu *menu)
387 +{
388 +#if 0
389 +       pboot_device_t *dev = pboot_devices[pboot_dev_sel];
390 +       pboot_option_t *opt = &dev->options[menu->op->focus_curindex];
391 +
392 +       pb_log("Selected device %s\n", opt->title);
393 +       pboot_message("booting %s...", opt->title);
394 +
395 +       /* Give user feedback, make sure errors and panics will be seen */
396 +       pboot_exec_option(opt->data);
397 +#endif
398 +}
399 +
400 +//==============================================================================
401 +// device
402 +//==============================================================================
403 +
404 +//==============================================================================
405 +// scr
406 +//==============================================================================
407 +
408 +static twin_bool_t pbt_scr_event(twin_screen_t *tscreen, twin_event_t *event)
409 +{
410 +       struct pbt_scr *scr = pbt_scr_from_tscreen(tscreen);
411 +
412 +       switch(event->kind) {
413 +       case TwinEventEnter:
414 +       case TwinEventMotion:
415 +       case TwinEventLeave:
416 +       case TwinEventButtonDown:
417 +       case TwinEventButtonUp:
418 +               if (scr->cursor.pixmap)
419 +                       twin_screen_set_cursor(tscreen, scr->cursor.pixmap,
420 +                               scr->cursor.hx, scr->cursor.hy);
421 +               break;
422 +       case TwinEventJoyButton:
423 +               /* map joystick events into key events */
424 +               if (event->u.js.control >= sizeof(sixaxis_map))
425 +                       break;
426 +
427 +               event->u.key.key = sixaxis_map[event->u.js.control];
428 +               if (event->u.js.value == 0) {
429 +                       event->kind = TwinEventKeyUp;
430 +                       break;
431 +               } else {
432 +                       event->kind = TwinEventKeyDown;
433 +               }
434 +               /* fall through.. */
435 +       case TwinEventKeyDown:
436 +               switch(event->u.key.key) {
437 +               case KEY_0:
438 +                       return TWIN_TRUE;
439 +               case KEY_BACKSPACE:
440 +               case KEY_DELETE:
441 +                       return TWIN_FALSE;
442 +               }
443 +       case TwinEventKeyUp:
444 +               twin_screen_set_cursor(tscreen, NULL, 0, 0);
445 +               break;
446 +       default:
447 +               break;
448 +       }
449 +       return TWIN_FALSE;
450 +}
451 +
452 +//==============================================================================
453 +// pane
454 +//==============================================================================
455 +
456 +static int pbt_pane_has_focus(const struct pbt_pane *pane)
457 +{
458 +       return pane->has_focus;
459 +}
460 +
461 +static twin_time_t pbt_pane_timeout(twin_time_t now, void *closure)
462 +{
463 +       const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 1, 2, 2, 3 };
464 +       struct pbt_pane *pane = pbt_pane_from_arg(closure);
465 +       int dir = 1, dist, pos;
466 +
467 +       dist = abs(pane->focus_target - pane->focus_start);
468 +       dir = dist > 5 ? 5 : dist;
469 +       pos = pane->focus_target - (int)pane->focus_box.top;
470 +       if (pos == 0) {
471 +               return -1;
472 +       }
473 +       if (pos < 0) {
474 +               dir = -dir;
475 +               pos = -pos;
476 +       }
477 +       twin_window_damage(pane->window,
478 +                          pane->focus_box.left,
479 +                          pane->focus_box.top,
480 +                          pane->focus_box.right,
481 +                          pane->focus_box.bottom);
482 +
483 +       pane->focus_box.top += dir;
484 +       pane->focus_box.bottom += dir;
485 +
486 +       twin_window_damage(pane->window,
487 +                          pane->focus_box.left,
488 +                          pane->focus_box.top,
489 +                          pane->focus_box.right,
490 +                          pane->focus_box.bottom);
491 +
492 +       twin_window_queue_paint(pane->window);
493 +
494 +       return accel[(pos * 10) / dist];
495 +}
496 +
497 +//==============================================================================
498 +// menu
499 +//==============================================================================
500 +
501 +/**
502 + * pbt_menu_set_focus - Set the menu's pane of focus.
503 + * @menu: The menu to operate on.
504 + * @pane: The pane that will have the focus.
505 + */
506 +
507 +static void pbt_menu_set_focus(struct pbt_menu *menu, struct pbt_pane *pane)
508 +{
509 +       assert(!pane->has_focus);
510 +
511 +       if (pane == menu->dp) {
512 +               menu->dp->has_focus = 1;
513 +               menu->op->has_focus = 0;
514 +       } else if (pane == menu->op) {
515 +               menu->dp->has_focus = 0;
516 +               menu->op->has_focus = 1;
517 +//             pbt_menu_set_option_focus(menu, 0);
518 +       } else
519 +               assert(0 && "bad logic");
520 +}
521 +
522 +static void pbt_menu_pane_select(struct pbt_menu *menu, struct pbt_pane *pane)
523 +{
524 +       if(pbt_pane_has_focus(pane))
525 +               return;
526 +
527 +       twin_screen_set_active(menu->scr->tscreen, pane->window->pixmap);
528 +
529 +       twin_window_damage(menu->dp->window,
530 +                          menu->dp->focus_box.left,
531 +                          menu->dp->focus_box.top,
532 +                          menu->dp->focus_box.right,
533 +                          menu->dp->focus_box.bottom);
534 +       twin_window_damage(menu->op->window,
535 +                          menu->op->focus_box.left,
536 +                          menu->op->focus_box.top,
537 +                          menu->op->focus_box.right,
538 +                          menu->op->focus_box.bottom);
539 +
540 +       twin_window_queue_paint(menu->dp->window);
541 +       twin_window_queue_paint(menu->op->window);
542 +
543 +       pbt_menu_set_focus(menu, pane);
544 +}
545 +
546 +
547 +static struct pbt_pane *pbt_device_pane_create(struct pbt_menu *menu);
548 +static struct pbt_pane *pbt_option_pane_create(struct pbt_menu *menu);
549 +
550 +static struct pbt_menu *pbt_menu_create(void *ctx, struct pbt_scr *scr)
551 +{
552 +       struct pbt_menu *menu = talloc_zero(ctx, struct pbt_menu);
553 +
554 +       if (!menu)
555 +               return NULL;
556 +
557 +       assert(scr && scr->sig == pbt_scr_sig);
558 +
559 +       menu->sig = pbt_menu_sig;
560 +       menu->scr = scr;
561 +
562 +       menu->dp = pbt_device_pane_create(menu);
563 +
564 +       if (!menu->dp)
565 +               goto fail_dp;
566 +
567 +       menu->op = pbt_option_pane_create(menu);
568 +
569 +       if (!menu->op)
570 +               goto fail_op;
571 +
572 +       return menu;
573 +
574 +fail_op:
575 +       //clean dp
576 +fail_dp:
577 +       talloc_free(menu);
578 +       return NULL;
579 +}
580 +
581 +//==============================================================================
582 +// device_pane
583 +//==============================================================================
584 +
585 +static void pbt_device_pane_draw(twin_window_t *window)
586 +{
587 +       struct pbt_pane *dp = pbt_menu_from_twindow(window)->dp;
588 +       twin_pixmap_t   *px = window->pixmap;
589 +       twin_path_t     *path;
590 +       twin_fixed_t    x, y, w, h;
591 +       int             i;
592 +
593 +       /* Fill background */
594 +       twin_fill(px, PBOOT_LEFT_PANE_COLOR, TWIN_SOURCE, 0, 0, px->width,
595 +               px->height);
596 +
597 +       /* Create a path for use later */
598 +       path = twin_path_create();
599 +       assert(path);
600 +
601 +       /* Draw right line if needed */
602 +       if (px->clip.right > (PBOOT_LEFT_PANE_SIZE - 4)) {
603 +               x = twin_int_to_fixed(PBOOT_LEFT_PANE_SIZE - 4);
604 +               y = twin_int_to_fixed(px->height);
605 +               twin_path_rectangle(path, x, 0, 0x40000, y);
606 +               twin_paint_path(px, PBOOT_LEFT_LINE_COLOR, path);
607 +               twin_path_empty(path);
608 +       }
609 +
610 +       /* Draw focus box */
611 +       if (dp->focus_curindex >= 0 &&
612 +           pbt_rect_intersect(dp->focus_box, px->clip)) {
613 +               x = twin_int_to_fixed(dp->focus_box.left + 2);
614 +               y = twin_int_to_fixed(dp->focus_box.top + 2);
615 +               w = twin_int_to_fixed(dp->focus_box.right -
616 +                                     dp->focus_box.left - 4);
617 +               h = twin_int_to_fixed(dp->focus_box.bottom -
618 +                                     dp->focus_box.top - 4);
619 +               twin_path_rounded_rectangle(path, x, y, w, h,
620 +                                           PBOOT_LEFT_FOCUS_XRAD,
621 +                                           PBOOT_LEFT_FOCUS_YRAD);
622 +               if (pbt_pane_has_focus(dp))
623 +                       twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
624 +               else
625 +                       twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
626 +                                         4 * TWIN_FIXED_ONE);
627 +       }
628 +
629 +#if 0
630 +       /* Draw icons */
631 +       for (i = 0; i < pboot_dev_count; i++) {
632 +               pboot_device_t  *dev = pboot_devices[i];
633 +               twin_operand_t  src;
634 +
635 +               if (!twin_rect_intersect(dev->box, px->clip))
636 +                       continue;
637 +
638 +               src.source_kind = TWIN_PIXMAP;
639 +               src.u.pixmap = dev->badge;
640 +
641 +               twin_composite(px, dev->box.left, dev->box.top,
642 +                              &src, 0, 0, NULL, 0, 0, TWIN_OVER,
643 +                              dev->box.right - dev->box.left,
644 +                              dev->box.bottom - dev->box.top);
645 +       }
646 +#endif
647 +
648 +       /* Destroy path */
649 +       twin_path_destroy(path);
650 +}
651 +
652 +
653 +static void pbt_device_pane_set_focus(struct pbt_menu *menu, int index)
654 +{
655 +#if 0
656 +       if (index >= pboot_dev_count)
657 +               return;
658 +#endif
659 +
660 +       menu->dp->focus_start = menu->dp->focus_box.top;
661 +
662 +       if (index < 0)
663 +               menu->dp->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
664 +       else
665 +               menu->dp->focus_target = PBOOT_LEFT_FOCUS_YOFF +
666 +                       PBOOT_LEFT_ICON_STRIDE * index;
667 +
668 +       menu->dp->focus_curindex = index;
669 +
670 +       twin_set_timeout(pbt_pane_timeout, 0, menu->dp);
671 +}
672 +
673 +static void pbt_device_pane_mousetrack(struct pbt_menu *menu, twin_coord_t x,
674 +       twin_coord_t y)
675 +{
676 +       int candidate = -1;
677 +       twin_coord_t icon_top;
678 +
679 +       if (x < PBOOT_LEFT_ICON_XOFF ||
680 +           x > (PBOOT_LEFT_ICON_XOFF + PBOOT_LEFT_ICON_WIDTH))
681 +               goto miss;
682 +
683 +       if (y < PBOOT_LEFT_ICON_YOFF)
684 +               goto miss;
685 +
686 +       candidate = (y - PBOOT_LEFT_ICON_YOFF) / PBOOT_LEFT_ICON_STRIDE;
687 +
688 +#if 0
689 +       if (candidate >= pboot_dev_count) {
690 +               candidate = -1;
691 +               goto miss;
692 +       }
693 +#endif
694 +       if (candidate == menu->dp->mouse_target)
695 +               return;
696 +
697 +       icon_top = PBOOT_LEFT_ICON_YOFF + candidate * PBOOT_LEFT_ICON_STRIDE;
698 +
699 +       if (y > (icon_top + PBOOT_LEFT_ICON_HEIGHT)) {
700 +               candidate = -1;
701 +               goto miss;
702 +       }
703 +
704 +       /* The mouse hit an icon that wasn't the same
705 +        * as the previous one, trigger a focus change.
706 +        */
707 +
708 +       pbt_device_pane_set_focus(menu, candidate);
709 +
710 + miss:
711 +       menu->dp->mouse_target = candidate;
712 +}
713 +
714 +static twin_bool_t pbt_device_pane_event(twin_window_t *window,
715 +       twin_event_t *event)
716 +{
717 +       struct pbt_menu *menu = pbt_menu_from_twindow(window);
718 +
719 +       /* filter out all mouse events */
720 +       switch(event->kind) {
721 +       case TwinEventEnter:
722 +       case TwinEventMotion:
723 +       case TwinEventLeave:
724 +               pbt_menu_pane_select(menu, menu->dp);
725 +               pbt_device_pane_mousetrack(menu, event->u.pointer.x,
726 +                       event->u.pointer.y);
727 +               return TWIN_TRUE;
728 +       case TwinEventButtonDown:
729 +       case TwinEventButtonUp:
730 +               return TWIN_TRUE;
731 +       case TwinEventKeyDown:
732 +               switch(event->u.key.key) {
733 +               case KEY_UP:
734 +                       if (menu->dp->focus_curindex > 0)
735 +                               pbt_device_pane_set_focus(menu,
736 +                                       menu->dp->focus_curindex - 1);
737 +                       return TWIN_TRUE;
738 +               case KEY_DOWN:
739 +                       pbt_device_pane_set_focus(menu, menu->dp->focus_curindex + 1);
740 +                       return TWIN_TRUE;
741 +               case KEY_RIGHT:
742 +                       pbt_menu_pane_select(menu, menu->op);
743 +                       return TWIN_TRUE;
744 +               default:
745 +                       break;
746 +               }
747 +               break;
748 +       default:
749 +               break;
750 +       }
751 +       return TWIN_FALSE;
752 +}
753 +
754 +static struct pbt_pane *pbt_device_pane_create(struct pbt_menu *menu)
755 +{
756 +       struct pbt_pane *pane = talloc_zero(menu, struct pbt_pane);
757 +
758 +       if (!pane)
759 +               return NULL;
760 +
761 +       pane->sig = pbt_pane_sig;
762 +       pane->window = twin_window_create(menu->scr->tscreen, TWIN_ARGB32,
763 +               TwinWindowPlain, 0, 0, PBOOT_LEFT_PANE_SIZE,
764 +               menu->scr->tscreen->height);
765 +
766 +       if (!pane->window)
767 +               goto fail_window;
768 +
769 +       pane->window->draw = pbt_device_pane_draw;
770 +       pane->window->event = pbt_device_pane_event;
771 +       pane->window->client_data = menu;
772 +
773 +       pane->focus_curindex = -1;
774 +       pane->focus_box.left = PBOOT_LEFT_FOCUS_XOFF;
775 +       pane->focus_box.top = -2 * PBOOT_LEFT_FOCUS_HEIGHT;
776 +       pane->focus_box.right = pane->focus_box.left + PBOOT_LEFT_FOCUS_WIDTH;
777 +       pane->focus_box.bottom = pane->focus_box.top + PBOOT_LEFT_FOCUS_HEIGHT;
778 +
779 +       pane->mouse_target = -1;
780 +
781 +       twin_window_show(pane->window);
782 +       twin_window_queue_paint(pane->window);
783 +
784 +       return pane;
785 +
786 +fail_window:
787 +       talloc_free(pane);
788 +       return NULL;
789 +}
790 +
791 +//==============================================================================
792 +// option_pane
793 +//==============================================================================
794 +
795 +static void pbt_option_pane_set_focus(struct pbt_menu *menu, int index)
796 +{
797 +#if 0
798 +       pboot_device_t  *dev;
799 +
800 +       if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
801 +               return;
802 +       dev = pboot_devices[pboot_dev_sel];
803 +       if (index < 0 || index >= dev->option_count)
804 +               return;
805 +#endif
806 +
807 +       menu->op->focus_start = menu->op->focus_box.top;
808 +       menu->op->focus_target = PBOOT_RIGHT_FOCUS_YOFF +
809 +               PBOOT_RIGHT_OPTION_STRIDE * index;
810 +       menu->op->focus_curindex = index;
811 +
812 +       twin_set_timeout(pbt_pane_timeout, 0, menu->op);
813 +}
814 +
815 +static void pbt_option_pane_draw(twin_window_t *window)
816 +{
817 +       struct pbt_pane *op = pbt_menu_from_twindow(window)->op;
818 +       twin_pixmap_t   *px = window->pixmap;
819 +//     pboot_device_t  *dev;
820 +       twin_path_t     *path;
821 +       twin_fixed_t    x, y, w, h;
822 +       int             i;
823 +
824 +       /* Fill background */
825 +       twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
826 +
827 +       /* Nothing to draw, return */
828 +//     if (pboot_dev_sel < 0)
829 +//             return;
830 +
831 +       /* Create a path for use later */
832 +       path = twin_path_create();
833 +       assert(path);
834 +
835 +       /* Draw focus box */
836 +       if (op->focus_curindex >= 0 &&
837 +           pbt_rect_intersect(op->focus_box, px->clip)) {
838 +               x = twin_int_to_fixed(op->focus_box.left + 2);
839 +               y = twin_int_to_fixed(op->focus_box.top + 2);
840 +               w = twin_int_to_fixed(op->focus_box.right -
841 +                                     op->focus_box.left - 4);
842 +               h = twin_int_to_fixed(op->focus_box.bottom -
843 +                                     op->focus_box.top - 4);
844 +               twin_path_rounded_rectangle(path, x, y, w, h,
845 +                                           PBOOT_RIGHT_FOCUS_XRAD,
846 +                                           PBOOT_RIGHT_FOCUS_YRAD);
847 +               if (pbt_pane_has_focus(op))
848 +                       twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
849 +               else
850 +                       twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
851 +                                         4 * TWIN_FIXED_ONE);
852 +       }
853 +
854 +       /* Get device and iterate through options */
855 +/*
856 +       dev = pboot_devices[pboot_dev_sel];
857 +       for (i = 0; i < dev->option_count; i++) {
858 +               pboot_option_t  *opt = &dev->options[i];
859 +               twin_operand_t  src;
860 +
861 +               if (opt->title == NULL)
862 +                       continue;
863 +               if (!pbt_rect_intersect(opt->box, px->clip))
864 +                       continue;
865 +               if (opt->cache == NULL)
866 +                       pboot_draw_option_cache(dev, opt, i);
867 +
868 +               src.source_kind = TWIN_PIXMAP;
869 +               src.u.pixmap = opt->cache;
870 +
871 +               twin_composite(px, opt->box.left, opt->box.top,
872 +                              &src, 0, 0, NULL, 0, 0, TWIN_OVER,
873 +                              opt->box.right - opt->box.left,
874 +                              opt->box.bottom - opt->box.top);
875 +       }
876 +*/
877 +       /* Destroy path */
878 +       twin_path_destroy(path);
879 +}
880 +
881 +static void pbt_option_pane_mousetrack(struct pbt_menu *menu, twin_coord_t x,
882 +       twin_coord_t y)
883 +{
884 +       int candidate = -1;
885 +
886 +       if (y < PBOOT_RIGHT_OPTION_TMARGIN)
887 +               goto miss;
888 +
889 +#if 0
890 +       pboot_device_t  *dev;
891 +       pboot_option_t  *opt;
892 +
893 +       if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
894 +               return;
895 +
896 +       dev = pboot_devices[pboot_dev_sel];
897 +
898 +       candidate = (y - PBOOT_RIGHT_OPTION_TMARGIN) /
899 +               PBOOT_RIGHT_OPTION_STRIDE;
900 +
901 +       if (candidate >= dev->option_count) {
902 +               candidate = -1;
903 +               goto miss;
904 +       }
905 +
906 +       if (candidate == op->mouse_target)
907 +               return;
908 +
909 +       opt = &dev->options[candidate];
910 +
911 +       if (x < opt->box.left || x > opt->box.right ||
912 +           y < opt->box.top || y > opt->box.bottom) {
913 +               candidate = -1;
914 +               goto miss;
915 +       }
916 +#endif
917 +
918 +       pbt_option_pane_set_focus(menu, candidate);
919 +
920 +miss:
921 +       menu->op->mouse_target = candidate;
922 +}
923 +
924 +static twin_bool_t pbt_option_pane_event(twin_window_t *window,
925 +       twin_event_t *event)
926 +{
927 +       struct pbt_menu *menu = pbt_menu_from_twindow(window);
928 +
929 +       /* filter out all mouse events */
930 +       switch(event->kind) {
931 +       case TwinEventEnter:
932 +       case TwinEventMotion:
933 +       case TwinEventLeave:
934 +               pbt_menu_pane_select(menu, menu->op);
935 +               pbt_option_pane_mousetrack(menu, event->u.pointer.x,
936 +                       event->u.pointer.y);
937 +               return TWIN_TRUE;
938 +       case TwinEventButtonDown:
939 +               pbt_menu_pane_select(menu, menu->op);
940 +               pbt_option_pane_mousetrack(menu, event->u.pointer.x,
941 +                       event->u.pointer.y);
942 +               pbt_option_execute(menu);
943 +               return TWIN_TRUE;
944 +       case TwinEventButtonUp:
945 +               return TWIN_TRUE;
946 +       case TwinEventKeyDown:
947 +               switch(event->u.key.key) {
948 +               case KEY_UP:
949 +                       //pbt_menu_set_option_focus(menu, menu->op->focus_curindex - 1);
950 +                       return TWIN_TRUE;
951 +               case KEY_DOWN:
952 +                       //pbt_menu_set_option_focus(menu, menu->op->focus_curindex + 1);
953 +                       return TWIN_TRUE;
954 +               case KEY_LEFT:
955 +                       pbt_menu_pane_select(menu, menu->dp);
956 +                       return TWIN_TRUE;
957 +               case KEY_ENTER:
958 +                       pbt_option_execute(menu);
959 +               default:
960 +                       break;
961 +               }
962 +               break;
963 +       default:
964 +               break;
965 +       }
966 +       return TWIN_FALSE;
967 +}
968 +
969 +static struct pbt_pane *pbt_option_pane_create(struct pbt_menu *menu)
970 +{
971 +       struct pbt_pane *pane = talloc_zero(menu, struct pbt_pane);
972 +
973 +       if (!pane)
974 +               return NULL;
975 +
976 +       pane->sig = pbt_pane_sig;
977 +       pane->window = twin_window_create(menu->scr->tscreen, TWIN_ARGB32,
978 +               TwinWindowPlain, PBOOT_LEFT_PANE_SIZE, 0,
979 +               menu->scr->tscreen->width - PBOOT_LEFT_PANE_SIZE,
980 +               menu->scr->tscreen->height);
981 +
982 +       if (!pane->window)
983 +               goto fail_window;
984 +
985 +       pane->window->draw = pbt_option_pane_draw;
986 +       pane->window->event = pbt_option_pane_event;
987 +       pane->window->client_data = menu;
988 +
989 +       pane->focus_curindex = -1;
990 +       pane->focus_box.left = PBOOT_RIGHT_FOCUS_XOFF;
991 +       pane->focus_box.top = -2 * PBOOT_RIGHT_FOCUS_HEIGHT;
992 +       pane->focus_box.right = pane->window->pixmap->width
993 +               - 2 * PBOOT_RIGHT_FOCUS_XOFF;
994 +       pane->focus_box.bottom = pane->focus_box.top + PBOOT_RIGHT_FOCUS_HEIGHT;
995 +
996 +       pane->mouse_target = -1;
997 +
998 +       twin_window_show(pane->window);
999 +       twin_window_queue_paint(pane->window);
1000 +
1001 +       return pane;
1002 +
1003 +fail_window:
1004 +       talloc_free(pane);
1005 +       return NULL;
1006 +}
1007 +
1008 +//==============================================================================
1009 +// junk
1010 +//==============================================================================
1011 +
1012 +#if 0
1013 +
1014 +static pboot_device_t  *pboot_devices[PBOOT_MAX_DEV];
1015 +static int             pboot_dev_count;
1016 +static int             pboot_dev_sel = -1;
1017 +
1018 +
1019 +
1020 +
1021 +static int pboot_vmode_change = -1;
1022 +
1023 +static void pboot_message(const char *fmt, ...)
1024 +{
1025 +       va_list ap;
1026 +       char *msg;
1027 +
1028 +       va_start(ap, fmt);
1029 +       vasprintf(&msg, fmt, ap);
1030 +       va_end(ap);
1031 +
1032 +       pb_log(msg);
1033 +}
1034 +
1035 +static void pboot_draw_option_cache(pboot_device_t *dev, pboot_option_t *opt,
1036 +                                   int index)
1037 +{
1038 +       twin_pixmap_t   *px;
1039 +       twin_path_t     *path;
1040 +       twin_fixed_t    tx, ty;
1041 +
1042 +       /* Create pixmap */
1043 +       px = twin_pixmap_create(TWIN_ARGB32, opt->box.right - opt->box.left,
1044 +                                opt->box.bottom - opt->box.top);
1045 +       assert(px);
1046 +       opt->cache = px;
1047 +
1048 +       /* Fill background */
1049 +       twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
1050 +
1051 +       /* Allocate a path for drawing */
1052 +       path = twin_path_create();
1053 +       assert(path);
1054 +
1055 +#if 0
1056 +       /* TEST - Bounding rectangle */
1057 +       twin_path_rectangle(path, 0, 0,
1058 +                           twin_int_to_fixed(px->width),
1059 +                           twin_int_to_fixed(px->height));
1060 +       twin_paint_path(px, PBOOT_RIGHT_TITLE_COLOR, path);
1061 +       twin_path_empty(path);
1062 +       twin_fill(px, 0x00000000, TWIN_SOURCE, 2, 2,
1063 +                 px->width - 3, px->height - 3);
1064 +#endif
1065 +
1066 +       /* Draw texts */
1067 +       twin_path_set_font_size(path, PBOOT_RIGHT_TITLE_TEXT_SIZE);
1068 +       twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
1069 +       tx = twin_int_to_fixed(PBOOT_RIGHT_TITLE_XOFFSET);
1070 +       ty = twin_int_to_fixed(PBOOT_RIGHT_TITLE_YOFFSET);
1071 +       twin_path_move (path, tx, ty);
1072 +       twin_path_utf8 (path, opt->title);
1073 +       twin_paint_path (px, PBOOT_RIGHT_TITLE_COLOR, path);
1074 +       twin_path_empty (path);
1075 +
1076 +       if (opt->subtitle) {
1077 +               twin_path_set_font_size(path, PBOOT_RIGHT_SUBTITLE_TEXT_SIZE);
1078 +               twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
1079 +               tx = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_XOFFSET);
1080 +               ty = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_YOFFSET);
1081 +               twin_path_move (path, tx, ty);
1082 +               twin_path_utf8 (path, opt->subtitle);
1083 +               twin_paint_path (px, PBOOT_RIGHT_SUBTITLE_COLOR, path);
1084 +               twin_path_empty (path);
1085 +       }
1086 +
1087 +       if (opt->badge) {
1088 +               twin_operand_t  src;
1089 +
1090 +               src.source_kind = TWIN_PIXMAP;
1091 +               src.u.pixmap = opt->badge;
1092 +
1093 +               twin_composite(px, PBOOT_RIGHT_BADGE_XOFFSET,
1094 +                              PBOOT_RIGHT_BADGE_YOFFSET,
1095 +                              &src, 0, 0, NULL, 0, 0, TWIN_OVER,
1096 +                              opt->badge->width, opt->badge->height);
1097 +       }
1098 +
1099 +
1100 +       /* Destroy path */
1101 +       twin_path_destroy(path);
1102 +}
1103 +
1104 +
1105 +
1106 +static int pboot_add_option(int devindex, const char *title,
1107 +                    const char *subtitle, twin_pixmap_t *badge, void *data)
1108 +{
1109 +       pboot_device_t  *dev;
1110 +       pboot_option_t  *opt;
1111 +       twin_coord_t    width;
1112 +       int             index;
1113 +       struct pbt_menu *menu = NULL;
1114 +
1115 +       if (devindex < 0 || devindex >= pboot_dev_count)
1116 +               return -1;
1117 +       dev = pboot_devices[devindex];
1118 +
1119 +       if (dev->option_count >= PBOOT_MAX_OPTION)
1120 +               return -1;
1121 +       index = dev->option_count++;
1122 +       opt = &dev->options[index];
1123 +
1124 +       opt->title = malloc(strlen(title) + 1);
1125 +       strcpy(opt->title, title);
1126 +
1127 +       if (subtitle) {
1128 +               opt->subtitle = malloc(strlen(subtitle) + 1);
1129 +               strcpy(opt->subtitle, subtitle);
1130 +       } else
1131 +               opt->subtitle = NULL;
1132 +
1133 +       opt->badge = badge;
1134 +       opt->cache = NULL;
1135 +
1136 +       width = menu->op->window->pixmap->width -
1137 +               (PBOOT_RIGHT_OPTION_LMARGIN + PBOOT_RIGHT_OPTION_RMARGIN);
1138 +
1139 +       opt->box.left = PBOOT_RIGHT_OPTION_LMARGIN;
1140 +       opt->box.right = opt->box.left + width;
1141 +       opt->box.top = PBOOT_RIGHT_OPTION_TMARGIN +
1142 +               index * PBOOT_RIGHT_OPTION_STRIDE;
1143 +       opt->box.bottom = opt->box.top + PBOOT_RIGHT_OPTION_HEIGHT;
1144 +
1145 +       opt->data = data;
1146 +       return index;
1147 +}
1148 +
1149 +static void pboot_set_device_select(struct pbt_menu *menu, int sel, int force)
1150 +{
1151 +       pb_log("%s: %d -> %d\n", __FUNCTION__, pboot_dev_sel, sel);
1152 +       if (!force && sel == pboot_dev_sel)
1153 +               return;
1154 +       if (sel >= pboot_dev_count)
1155 +               return;
1156 +       pboot_dev_sel = sel;
1157 +       if (force) {
1158 +               menu->dp->focus_curindex = sel;
1159 +               if (sel < 0)
1160 +                       menu->dp->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
1161 +               else
1162 +                       menu->dp->focus_target = PBOOT_LEFT_FOCUS_YOFF +
1163 +                               PBOOT_LEFT_ICON_STRIDE * sel;
1164 +               menu->op->focus_box.bottom = menu->dp->focus_target;
1165 +               menu->op->focus_box.bottom = menu->op->focus_box.top +
1166 +                       PBOOT_RIGHT_FOCUS_HEIGHT;
1167 +               twin_window_damage(menu->dp->window,
1168 +                                  0, 0,
1169 +                                  menu->dp->window->pixmap->width,
1170 +                                  menu->dp->window->pixmap->height);
1171 +               twin_window_queue_paint(menu->dp->window);
1172 +       }
1173 +       menu->op->focus_curindex = -1;
1174 +       menu->op->mouse_target = -1;
1175 +       menu->op->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
1176 +       menu->op->focus_box.bottom = menu->op->focus_box.top +
1177 +               PBOOT_RIGHT_FOCUS_HEIGHT;
1178 +       twin_window_damage(menu->op->window, 0, 0,
1179 +                          menu->op->window->pixmap->width,
1180 +                          menu->op->window->pixmap->height);
1181 +       twin_window_queue_paint(menu->op->window);
1182 +}
1183 +
1184 +static void pboot_quit(void)
1185 +{
1186 +       kill(0, SIGINT);
1187 +}
1188 +
1189 +
1190 +static int pboot_add_device(const char *dev_id, twin_pixmap_t *pixmap)
1191 +{
1192 +       int             index;
1193 +       pboot_device_t  *dev;
1194 +
1195 +       struct pbt_menu *menu = NULL;
1196 +
1197 +       if (pboot_dev_count >= PBOOT_MAX_DEV)
1198 +               return -1;
1199 +
1200 +       index = pboot_dev_count++;
1201 +
1202 +       dev = malloc(sizeof(*dev));
1203 +       memset(dev, 0, sizeof(*dev));
1204 +       dev->id = malloc(strlen(dev_id) + 1);
1205 +       strcpy(dev->id, dev_id);
1206 +       dev->badge = pixmap;
1207 +       dev->box.left = PBOOT_LEFT_ICON_XOFF;
1208 +       dev->box.right = dev->box.left + PBOOT_LEFT_ICON_WIDTH;
1209 +       dev->box.top = PBOOT_LEFT_ICON_YOFF +
1210 +               PBOOT_LEFT_ICON_STRIDE * index;
1211 +       dev->box.bottom = dev->box.top + PBOOT_LEFT_ICON_HEIGHT;
1212 +
1213 +       pboot_devices[index] = dev;
1214 +
1215 +       twin_window_damage(menu->dp->window,
1216 +                          dev->box.left, dev->box.top,
1217 +                          dev->box.right, dev->box.bottom);
1218 +       twin_window_queue_paint(menu->dp->window);
1219 +
1220 +       return index;
1221 +}
1222 +
1223 +static int pboot_remove_device(const char *dev_id)
1224 +{
1225 +       pboot_device_t  *dev = NULL;
1226 +       int             i, newsel = pboot_dev_sel;
1227 +
1228 +       struct pbt_menu *menu = NULL;
1229 +
1230 +       /* find the matching device */
1231 +       for (i = 0; i < pboot_dev_count; i++) {
1232 +               if (!strcmp(pboot_devices[i]->id, dev_id)) {
1233 +                       dev = pboot_devices[i];
1234 +                       break;
1235 +               }
1236 +       }
1237 +
1238 +       if (!dev)
1239 +               return TWIN_FALSE;
1240 +
1241 +       memmove(pboot_devices + i, pboot_devices + i + 1,
1242 +                       sizeof(*pboot_devices) * (pboot_dev_count + i - 1));
1243 +       pboot_devices[--pboot_dev_count] = NULL;
1244 +
1245 +       /* select the newly-focussed device */
1246 +       if (pboot_dev_sel > i)
1247 +               newsel = pboot_dev_sel - 1;
1248 +       else if (pboot_dev_sel == i && i >= pboot_dev_count)
1249 +                       newsel = pboot_dev_count - 1;
1250 +       pboot_set_device_select(menu, newsel, 1);
1251 +
1252 +       /* todo: free device & options */
1253 +
1254 +       return TWIN_TRUE;
1255 +}
1256 +#endif
1257 +
1258 +//------------------------------------------------------------------------------
1259 +
1260 +static void print_version(void)
1261 +{
1262 +       printf("pb-twin (" PACKAGE_NAME ") " PACKAGE_VERSION "\n");
1263 +}
1264 +
1265 +static void print_usage(void)
1266 +{
1267 +       print_version();
1268 +       printf(
1269 +"Usage: pb-twin [-h, --help] [-l, --log log-file] [-r, --reset-defaults]\n"
1270 +"               [-t, --timeout] [-V, --version]\n");
1271 +}
1272 +
1273 +/**
1274 + * enum opt_value - Tri-state options variables.
1275 + */
1276 +
1277 +enum opt_value {opt_undef = 0, opt_yes, opt_no};
1278 +
1279 +/**
1280 + * struct opts - Values from command line options.
1281 + */
1282 +
1283 +struct opts {
1284 +       enum opt_value show_help;
1285 +       const char *log_file;
1286 +       enum opt_value reset_defaults;
1287 +       enum opt_value use_timeout;
1288 +       enum opt_value show_version;
1289 +};
1290 +
1291 +/**
1292 + * opts_parse - Parse the command line options.
1293 + */
1294 +
1295 +static int opts_parse(struct opts *opts, int argc, char *argv[])
1296 +{
1297 +       static const struct option long_options[] = {
1298 +               {"help",           no_argument,       NULL, 'h'},
1299 +               {"log",            required_argument, NULL, 'l'},
1300 +               {"reset-defaults", no_argument,       NULL, 'r'},
1301 +               {"timeout",        no_argument,       NULL, 't'},
1302 +               {"version",        no_argument,       NULL, 'V'},
1303 +               { NULL, 0, NULL, 0},
1304 +       };
1305 +       static const char short_options[] = "hl:trV";
1306 +       static const struct opts default_values = {
1307 +               .log_file = "pb-twin.log",
1308 +       };
1309 +
1310 +       *opts = default_values;
1311 +
1312 +       while (1) {
1313 +               int c = getopt_long(argc, argv, short_options, long_options,
1314 +                       NULL);
1315 +
1316 +               if (c == EOF)
1317 +                       break;
1318 +
1319 +               switch (c) {
1320 +               case 'h':
1321 +                       opts->show_help = opt_yes;
1322 +                       break;
1323 +               case 'l':
1324 +                       opts->log_file = optarg;
1325 +                       break;
1326 +               case 't':
1327 +                       opts->use_timeout = opt_yes;
1328 +                       break;
1329 +               case 'r':
1330 +                       opts->reset_defaults = opt_yes;
1331 +                       break;
1332 +               case 'V':
1333 +                       opts->show_version = opt_yes;
1334 +                       break;
1335 +               default:
1336 +                       opts->show_help = opt_yes;
1337 +                       return -1;
1338 +               }
1339 +       }
1340 +
1341 +       return optind != argc;
1342 +}
1343 +
1344 +/**
1345 + * struct ps3_gui - Main gui program instance.
1346 + */
1347 +
1348 +
1349 +struct ps3_gui {
1350 +       struct ui_timer timer;
1351 +       struct ps3_flash_values values;
1352 +       int dirty_values;
1353 +
1354 +       struct pbt_scr scr;
1355 +       struct pbt_frame frame;
1356 +       struct pbt_menu *menu;
1357 +};
1358 +
1359 +static struct ps3_gui ps3;
1360 +
1361 +static struct pbt_scr *pbt_scr_from_tscreen(twin_screen_t *tscreen)
1362 +{
1363 +       assert(ps3.scr.sig == pbt_scr_sig);
1364 +       assert(ps3.scr.tscreen == tscreen);
1365 +       return &ps3.scr;
1366 +}
1367 +
1368 +static void sig_handler(int signum)
1369 +{
1370 +       DBGS("%d\n", signum);
1371 +
1372 +       switch (signum) {
1373 +       case SIGALRM:
1374 +               ui_timer_sigalrm(&ps3.timer);
1375 +               break;
1376 +       case SIGWINCH:
1377 +//             if (ps3.gui)
1378 +//                     gui_resize(ps3.gui);
1379 +               break;
1380 +       default:
1381 +               assert(0 && "unknown sig");
1382 +               /* fall through */
1383 +       case SIGINT:
1384 +       case SIGHUP:
1385 +       case SIGTERM:
1386 +               exit(EXIT_FAILURE);
1387 +//             if (ps3.gui)
1388 +//                     gui_abort(ps3.gui);
1389 +               break;
1390 +       }
1391 +}
1392 +
1393 +/**
1394 + * main - twin bootloader main routine.
1395 + */
1396 +
1397 +int main(int argc, char *argv[])
1398 +{
1399 +       static struct sigaction sa;
1400 +       static struct opts opts;
1401 +       int result;
1402 +       int ui_result;
1403 +       unsigned int mode;
1404 +       FILE *log;
1405 +
1406 +       result = opts_parse(&opts, argc, argv);
1407 +
1408 +       if (result) {
1409 +               print_usage();
1410 +               return EXIT_FAILURE;
1411 +       }
1412 +
1413 +       if (opts.show_help == opt_yes) {
1414 +               print_usage();
1415 +               return EXIT_SUCCESS;
1416 +       }
1417 +
1418 +       if (opts.show_version == opt_yes) {
1419 +               print_version();
1420 +               return EXIT_SUCCESS;
1421 +       }
1422 +
1423 +       log = fopen(opts.log_file, "a");
1424 +       assert(log);
1425 +       pb_log_set_stream(log);
1426 +
1427 +#if defined(DEBUG)
1428 +       pb_log_always_flush(1);
1429 +#endif
1430 +
1431 +       pb_log("--- pb-twin ---\n");
1432 +
1433 +       sa.sa_handler = sig_handler;
1434 +       result = sigaction(SIGALRM, &sa, NULL);
1435 +       result += sigaction(SIGHUP, &sa, NULL);
1436 +       result += sigaction(SIGINT, &sa, NULL);
1437 +       result += sigaction(SIGTERM, &sa, NULL);
1438 +       result += sigaction(SIGWINCH, &sa, NULL);
1439 +
1440 +       if (result) {
1441 +               pb_log("%s sigaction failed.\n", __func__);
1442 +               return EXIT_FAILURE;
1443 +       }
1444 +
1445 +       ps3.values = ps3_flash_defaults;
1446 +
1447 +       if (opts.reset_defaults != opt_yes)
1448 +               ps3.dirty_values = ps3_flash_get_values(&ps3.values);
1449 +
1450 +       twin_feature_init(); // need it???
1451 +
1452 +       /* Setup screen. */
1453 +
1454 +       ps3.scr.sig = pbt_scr_sig;
1455 +
1456 +#if defined(HAVE_LIBTWIN_TWIN_X11_H)
1457 +# if defined(USE_X11)
1458 +       if (1) {
1459 +# else
1460 +       if (0) {
1461 +# endif
1462 +               ps3.scr.x11 = twin_x11_create(XOpenDisplay(0), 1024, 768);
1463 +
1464 +               if (!ps3.scr.x11) {
1465 +                       perror("failed to create x11 screen !\n");
1466 +                       return EXIT_FAILURE;
1467 +               }
1468 +
1469 +               ps3.scr.tscreen = ps3.scr.x11->screen;
1470 +       } else {
1471 +#else
1472 +       if (1) {
1473 +#endif
1474 +               result = ps3_get_video_mode(&mode);
1475 +
1476 +               /* Current becomes default if ps3_flash_get_values() failed. */
1477 +
1478 +               if (ps3.dirty_values && !result)
1479 +                       ps3.values.video_mode = mode;
1480 +
1481 +               /* Set mode if not at default. */
1482 +
1483 +               if (!result && (ps3.values.video_mode != (uint16_t)mode))
1484 +                       ps3_set_video_mode(ps3.values.video_mode);
1485 +
1486 +               ps3.scr.fbdev = twin_fbdev_create(-1, SIGUSR1);
1487 +
1488 +               if (!ps3.scr.fbdev) {
1489 +                       perror("failed to create fbdev screen !\n");
1490 +                       return EXIT_FAILURE;
1491 +               }
1492 +
1493 +               ps3.scr.tscreen = ps3.scr.fbdev->screen;
1494 +       }
1495 +
1496 +       ps3.scr.tscreen->event_filter = pbt_scr_event;
1497 +
1498 +       twin_screen_set_background(ps3.scr.tscreen,
1499 +               pbt_load_background(ps3.scr.tscreen));
1500 +
1501 +       /* setup menu */
1502 +
1503 +       ps3.menu = pbt_menu_create(NULL, &ps3.scr);
1504 +
1505 +       pbt_device_pane_set_focus(ps3.menu, 0);
1506 +       twin_screen_set_active(ps3.scr.tscreen, ps3.menu->dp->window->pixmap);
1507 +
1508 +       /* Console switch */
1509 +
1510 +       if (ps3.scr.fbdev)
1511 +               twin_fbdev_activate(ps3.scr.fbdev);
1512 +
1513 +       /* run twin */
1514 +
1515 +//     twin_toplevel_show(ps3.toplevel);
1516 +       twin_dispatch();
1517 +
1518 +       pb_log("--- end ---\n");
1519 +
1520 +       return ui_result ? EXIT_FAILURE : EXIT_SUCCESS;
1521 +}