11 #include <linux/input.h>
15 #include <libtwin/twin.h>
16 #include <libtwin/twin_linux_mouse.h>
17 #include <libtwin/twin_linux_js.h>
18 #include <libtwin/twin_png.h>
19 #include <libtwin/twin_jpeg.h>
21 #include "petitboot.h"
22 #include "petitboot-paths.h"
25 #include <libtwin/twin_x11.h>
26 static twin_x11_t *pboot_x11;
28 #include <libtwin/twin_fbdev.h>
29 static twin_fbdev_t *pboot_fbdev;
32 static twin_screen_t *pboot_screen;
34 #define PBOOT_INITIAL_MESSAGE \
35 "keys: 0=safe 1=720p 2=1080i 3=1080p del=GameOS"
37 #define PBOOT_LEFT_PANE_SIZE 160
38 #define PBOOT_LEFT_PANE_COLOR 0x80000000
39 #define PBOOT_LEFT_LINE_COLOR 0xff000000
41 #define PBOOT_LEFT_FOCUS_WIDTH 80
42 #define PBOOT_LEFT_FOCUS_HEIGHT 80
43 #define PBOOT_LEFT_FOCUS_XOFF 40
44 #define PBOOT_LEFT_FOCUS_YOFF 40
45 #define PBOOT_LEFT_FOCUS_XRAD (6 * TWIN_FIXED_ONE)
46 #define PBOOT_LEFT_FOCUS_YRAD (6 * TWIN_FIXED_ONE)
48 #define PBOOT_RIGHT_FOCUS_XOFF 20
49 #define PBOOT_RIGHT_FOCUS_YOFF 60
50 #define PBOOT_RIGHT_FOCUS_HEIGHT 80
51 #define PBOOT_RIGHT_FOCUS_XRAD (6 * TWIN_FIXED_ONE)
52 #define PBOOT_RIGHT_FOCUS_YRAD (6 * TWIN_FIXED_ONE)
54 #define PBOOT_LEFT_ICON_WIDTH 64
55 #define PBOOT_LEFT_ICON_HEIGHT 64
56 #define PBOOT_LEFT_ICON_XOFF 50
57 #define PBOOT_LEFT_ICON_YOFF 50
58 #define PBOOT_LEFT_ICON_STRIDE 100
60 #define PBOOT_RIGHT_OPTION_LMARGIN 30
61 #define PBOOT_RIGHT_OPTION_RMARGIN 30
62 #define PBOOT_RIGHT_OPTION_TMARGIN 70
63 #define PBOOT_RIGHT_OPTION_HEIGHT 64
64 #define PBOOT_RIGHT_OPTION_STRIDE 100
65 #define PBOOT_RIGHT_TITLE_TEXT_SIZE (30 * TWIN_FIXED_ONE)
66 #define PBOOT_RIGHT_SUBTITLE_TEXT_SIZE (18 * TWIN_FIXED_ONE)
67 #define PBOOT_RIGHT_TITLE_XOFFSET 80
68 #define PBOOT_RIGHT_TITLE_YOFFSET 30
69 #define PBOOT_RIGHT_SUBTITLE_XOFFSET 100
70 #define PBOOT_RIGHT_SUBTITLE_YOFFSET 50
71 #define PBOOT_RIGHT_BADGE_XOFFSET 2
72 #define PBOOT_RIGHT_BADGE_YOFFSET 0
75 #define PBOOT_RIGHT_TITLE_COLOR 0xff000000
76 #define PBOOT_RIGHT_SUBTITLE_COLOR 0xff400000
78 #define PBOOT_FOCUS_COLOR 0x10404040
80 #define PBOOT_STATUS_PANE_COLOR 0x60606060
81 #define PBOOT_STATUS_PANE_HEIGHT 20
82 #define PBOOT_STATUS_PANE_XYMARGIN 20
83 #define PBOOT_STATUS_TEXT_MARGIN 10
84 #define PBOOT_STATUS_TEXT_SIZE (16 * TWIN_FIXED_ONE)
85 #define PBOOT_STATUS_TEXT_COLOR 0xff000000
87 typedef struct _pboot_option pboot_option_t;
88 typedef struct _pboot_device pboot_device_t;
103 twin_pixmap_t *badge;
106 pboot_option_t options[PBOOT_MAX_OPTION];
109 static twin_pixmap_t *pboot_cursor;
110 static int pboot_cursor_hx;
111 static int pboot_cursor_hy;
113 static pboot_device_t *pboot_devices[PBOOT_MAX_DEV];
114 static int pboot_dev_count;
115 static int pboot_dev_sel = -1;
116 static int pboot_focus_lpane = 1;
118 typedef struct _pboot_lpane {
119 twin_window_t *window;
120 twin_rect_t focus_box;
127 typedef struct _pboot_rpane {
128 twin_window_t *window;
129 twin_rect_t focus_box;
136 typedef struct _pboot_spane {
137 twin_window_t *window;
141 static pboot_lpane_t *pboot_lpane;
142 static pboot_rpane_t *pboot_rpane;
143 static pboot_spane_t *pboot_spane;
145 /* control to keyboard mappings for the sixaxis controller */
146 uint8_t sixaxis_map[] = {
151 KEY_UP, /* 4 Dpad Up */
152 KEY_RIGHT, /* 5 Dpad Right */
153 KEY_DOWN, /* 6 Dpad Down */
154 KEY_LEFT, /* 7 Dpad Left */
160 KEY_ENTER, /* 13 Circle */
162 KEY_DELETE, /* 15 Square */
163 0, /* 16 PS Button */
169 static int pboot_vmode_change = -1;
171 /* XXX move to twin */
172 static inline twin_bool_t twin_rect_intersect(twin_rect_t r1,
175 return !(r1.left > r2.right ||
176 r1.right < r2.left ||
177 r1.top > r2.bottom ||
181 static void pboot_draw_option_cache(pboot_device_t *dev, pboot_option_t *opt,
189 px = twin_pixmap_create(TWIN_ARGB32, opt->box.right - opt->box.left,
190 opt->box.bottom - opt->box.top);
194 /* Fill background */
195 twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
197 /* Allocate a path for drawing */
198 path = twin_path_create();
202 /* TEST - Bounding rectangle */
203 twin_path_rectangle(path, 0, 0,
204 twin_int_to_fixed(px->width),
205 twin_int_to_fixed(px->height));
206 twin_paint_path(px, PBOOT_RIGHT_TITLE_COLOR, path);
207 twin_path_empty(path);
208 twin_fill(px, 0x00000000, TWIN_SOURCE, 2, 2,
209 px->width - 3, px->height - 3);
213 twin_path_set_font_size(path, PBOOT_RIGHT_TITLE_TEXT_SIZE);
214 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
215 tx = twin_int_to_fixed(PBOOT_RIGHT_TITLE_XOFFSET);
216 ty = twin_int_to_fixed(PBOOT_RIGHT_TITLE_YOFFSET);
217 twin_path_move (path, tx, ty);
218 twin_path_utf8 (path, opt->title);
219 twin_paint_path (px, PBOOT_RIGHT_TITLE_COLOR, path);
220 twin_path_empty (path);
223 twin_path_set_font_size(path, PBOOT_RIGHT_SUBTITLE_TEXT_SIZE);
224 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
225 tx = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_XOFFSET);
226 ty = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_YOFFSET);
227 twin_path_move (path, tx, ty);
228 twin_path_utf8 (path, opt->subtitle);
229 twin_paint_path (px, PBOOT_RIGHT_SUBTITLE_COLOR, path);
230 twin_path_empty (path);
236 src.source_kind = TWIN_PIXMAP;
237 src.u.pixmap = opt->badge;
239 twin_composite(px, PBOOT_RIGHT_BADGE_XOFFSET,
240 PBOOT_RIGHT_BADGE_YOFFSET,
241 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
242 opt->badge->width, opt->badge->height);
247 twin_path_destroy(path);
250 static void pboot_rpane_draw(twin_window_t *window)
252 twin_pixmap_t *px = window->pixmap;
253 pboot_rpane_t *rpane = window->client_data;
256 twin_fixed_t x, y, w, h;
259 /* Fill background */
260 twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
262 /* Nothing to draw, return */
263 if (pboot_dev_sel < 0)
266 /* Create a path for use later */
267 path = twin_path_create();
271 if (rpane->focus_curindex >= 0 &&
272 twin_rect_intersect(rpane->focus_box, px->clip)) {
273 x = twin_int_to_fixed(rpane->focus_box.left + 2);
274 y = twin_int_to_fixed(rpane->focus_box.top + 2);
275 w = twin_int_to_fixed(rpane->focus_box.right -
276 rpane->focus_box.left - 4);
277 h = twin_int_to_fixed(rpane->focus_box.bottom -
278 rpane->focus_box.top - 4);
279 twin_path_rounded_rectangle(path, x, y, w, h,
280 PBOOT_RIGHT_FOCUS_XRAD,
281 PBOOT_RIGHT_FOCUS_YRAD);
282 if (!pboot_focus_lpane)
283 twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
285 twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
289 /* Get device and iterate through options */
290 dev = pboot_devices[pboot_dev_sel];
291 for (i = 0; i < dev->option_count; i++) {
292 pboot_option_t *opt = &dev->options[i];
295 if (opt->title == NULL)
297 if (!twin_rect_intersect(opt->box, px->clip))
299 if (opt->cache == NULL)
300 pboot_draw_option_cache(dev, opt, i);
302 src.source_kind = TWIN_PIXMAP;
303 src.u.pixmap = opt->cache;
305 twin_composite(px, opt->box.left, opt->box.top,
306 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
307 opt->box.right - opt->box.left,
308 opt->box.bottom - opt->box.top);
312 twin_path_destroy(path);
315 static twin_time_t pboot_rfocus_timeout (twin_time_t now, void *closure)
317 int dir = 1, dist, pos;
318 const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 1, 2, 2, 3 };
320 dist = abs(pboot_rpane->focus_target - pboot_rpane->focus_start);
321 dir = dist > 5 ? 5 : dist;
322 pos = pboot_rpane->focus_target - (int)pboot_rpane->focus_box.top;
330 twin_window_damage(pboot_rpane->window,
331 pboot_rpane->focus_box.left,
332 pboot_rpane->focus_box.top,
333 pboot_rpane->focus_box.right,
334 pboot_rpane->focus_box.bottom);
336 pboot_rpane->focus_box.top += dir;
337 pboot_rpane->focus_box.bottom += dir;
339 twin_window_damage(pboot_rpane->window,
340 pboot_rpane->focus_box.left,
341 pboot_rpane->focus_box.top,
342 pboot_rpane->focus_box.right,
343 pboot_rpane->focus_box.bottom);
345 twin_window_queue_paint(pboot_rpane->window);
347 return accel[(pos * 10) / dist];
350 static void pboot_set_rfocus(int index)
354 if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
356 dev = pboot_devices[pboot_dev_sel];
357 if (index < 0 || index >= dev->option_count)
360 pboot_rpane->focus_start = pboot_rpane->focus_box.top;
361 pboot_rpane->focus_target = PBOOT_RIGHT_FOCUS_YOFF +
362 PBOOT_RIGHT_OPTION_STRIDE * index;
363 pboot_rpane->focus_curindex = index;
365 twin_set_timeout(pboot_rfocus_timeout, 0, NULL);
368 static void pboot_select_rpane(void)
370 if (pboot_focus_lpane == 0)
372 pboot_focus_lpane = 0;
374 twin_screen_set_active(pboot_screen, pboot_rpane->window->pixmap);
376 twin_window_damage(pboot_lpane->window,
377 pboot_lpane->focus_box.left,
378 pboot_lpane->focus_box.top,
379 pboot_lpane->focus_box.right,
380 pboot_lpane->focus_box.bottom);
382 twin_window_damage(pboot_rpane->window,
383 pboot_rpane->focus_box.left,
384 pboot_rpane->focus_box.top,
385 pboot_rpane->focus_box.right,
386 pboot_rpane->focus_box.bottom);
388 twin_window_queue_paint(pboot_lpane->window);
389 twin_window_queue_paint(pboot_rpane->window);
394 static void pboot_select_lpane(void)
396 if (pboot_focus_lpane == 1)
398 pboot_focus_lpane = 1;
400 twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
402 twin_window_damage(pboot_lpane->window,
403 pboot_lpane->focus_box.left,
404 pboot_lpane->focus_box.top,
405 pboot_lpane->focus_box.right,
406 pboot_lpane->focus_box.bottom);
408 twin_window_damage(pboot_rpane->window,
409 pboot_rpane->focus_box.left,
410 pboot_rpane->focus_box.top,
411 pboot_rpane->focus_box.right,
412 pboot_rpane->focus_box.bottom);
414 twin_window_queue_paint(pboot_lpane->window);
415 twin_window_queue_paint(pboot_rpane->window);
418 static void pboot_rpane_mousetrack(twin_coord_t x, twin_coord_t y)
424 if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
426 dev = pboot_devices[pboot_dev_sel];
428 if (y < PBOOT_RIGHT_OPTION_TMARGIN)
430 candidate = (y - PBOOT_RIGHT_OPTION_TMARGIN) /
431 PBOOT_RIGHT_OPTION_STRIDE;
432 if (candidate >= dev->option_count) {
436 if (candidate == pboot_rpane->mouse_target)
438 opt = &dev->options[candidate];
439 if (x < opt->box.left || x > opt->box.right ||
440 y < opt->box.top || y > opt->box.bottom) {
445 /* Ok, so now, we know the mouse hit an icon that wasn't the same
446 * as the previous one, we trigger a focus change
448 pboot_set_rfocus(candidate);
451 pboot_rpane->mouse_target = candidate;
454 static void pboot_choose_option(void)
456 pboot_device_t *dev = pboot_devices[pboot_dev_sel];
457 pboot_option_t *opt = &dev->options[pboot_rpane->focus_curindex];
459 LOG("Selected device %s\n", opt->title);
461 /* Give user feedback, make sure errors and panics will be seen */
462 pboot_exec_option(opt->data);
465 static twin_bool_t pboot_rpane_event (twin_window_t *window,
468 /* filter out all mouse events */
469 switch(event->kind) {
471 case TwinEventMotion:
473 pboot_select_rpane();
474 pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
476 case TwinEventButtonDown:
477 pboot_select_rpane();
478 pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
479 pboot_choose_option();
480 case TwinEventButtonUp:
482 case TwinEventKeyDown:
483 switch(event->u.key.key) {
485 pboot_set_rfocus(pboot_rpane->focus_curindex - 1);
488 pboot_set_rfocus(pboot_rpane->focus_curindex + 1);
491 pboot_select_lpane();
494 pboot_choose_option();
506 int pboot_add_option(int devindex, const char *title,
507 const char *subtitle, twin_pixmap_t *badge, void *data)
514 if (devindex < 0 || devindex >= pboot_dev_count)
516 dev = pboot_devices[devindex];
518 if (dev->option_count >= PBOOT_MAX_OPTION)
520 index = dev->option_count++;
521 opt = &dev->options[index];
523 opt->title = malloc(strlen(title) + 1);
524 strcpy(opt->title, title);
527 opt->subtitle = malloc(strlen(subtitle) + 1);
528 strcpy(opt->subtitle, subtitle);
530 opt->subtitle = NULL;
535 width = pboot_rpane->window->pixmap->width -
536 (PBOOT_RIGHT_OPTION_LMARGIN + PBOOT_RIGHT_OPTION_RMARGIN);
538 opt->box.left = PBOOT_RIGHT_OPTION_LMARGIN;
539 opt->box.right = opt->box.left + width;
540 opt->box.top = PBOOT_RIGHT_OPTION_TMARGIN +
541 index * PBOOT_RIGHT_OPTION_STRIDE;
542 opt->box.bottom = opt->box.top + PBOOT_RIGHT_OPTION_HEIGHT;
549 static void pboot_set_device_select(int sel, int force)
551 LOG("%s: %d -> %d\n", __FUNCTION__, pboot_dev_sel, sel);
552 if (!force && sel == pboot_dev_sel)
554 if (sel >= pboot_dev_count)
558 pboot_lpane->focus_curindex = sel;
560 pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
562 pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF +
563 PBOOT_LEFT_ICON_STRIDE * sel;
564 pboot_rpane->focus_box.bottom = pboot_lpane->focus_target;
565 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
566 PBOOT_RIGHT_FOCUS_HEIGHT;
567 twin_window_damage(pboot_lpane->window,
569 pboot_lpane->window->pixmap->width,
570 pboot_lpane->window->pixmap->height);
571 twin_window_queue_paint(pboot_lpane->window);
573 pboot_rpane->focus_curindex = -1;
574 pboot_rpane->mouse_target = -1;
575 pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
576 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
577 PBOOT_RIGHT_FOCUS_HEIGHT;
578 twin_window_damage(pboot_rpane->window, 0, 0,
579 pboot_rpane->window->pixmap->width,
580 pboot_rpane->window->pixmap->height);
581 twin_window_queue_paint(pboot_rpane->window);
584 static void pboot_create_rpane(void)
586 pboot_rpane = calloc(1, sizeof(pboot_rpane_t));
589 pboot_rpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
591 PBOOT_LEFT_PANE_SIZE, 0,
592 pboot_screen->width -
593 PBOOT_LEFT_PANE_SIZE,
594 pboot_screen->height);
595 assert(pboot_rpane->window);
597 pboot_rpane->window->draw = pboot_rpane_draw;
598 pboot_rpane->window->event = pboot_rpane_event;
599 pboot_rpane->window->client_data = pboot_rpane;
601 pboot_rpane->focus_curindex = -1;
602 pboot_rpane->focus_box.left = PBOOT_RIGHT_FOCUS_XOFF;
603 pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
604 pboot_rpane->focus_box.right = pboot_rpane->window->pixmap->width -
605 2 * PBOOT_RIGHT_FOCUS_XOFF;
606 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
607 PBOOT_RIGHT_FOCUS_HEIGHT;
608 pboot_rpane->mouse_target = -1;
609 twin_window_show(pboot_rpane->window);
610 twin_window_queue_paint(pboot_rpane->window);
614 static twin_time_t pboot_lfocus_timeout (twin_time_t now, void *closure)
616 int dir = 1, dist, pos;
617 const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 1, 2, 2, 3 };
619 dist = abs(pboot_lpane->focus_target - pboot_lpane->focus_start);
620 dir = dist > 2 ? 2 : dist;
621 pos = pboot_lpane->focus_target - (int)pboot_lpane->focus_box.top;
623 pboot_set_device_select(pboot_lpane->focus_curindex, 0);
630 twin_window_damage(pboot_lpane->window,
631 pboot_lpane->focus_box.left,
632 pboot_lpane->focus_box.top,
633 pboot_lpane->focus_box.right,
634 pboot_lpane->focus_box.bottom);
636 pboot_lpane->focus_box.top += dir;
637 pboot_lpane->focus_box.bottom += dir;
639 twin_window_damage(pboot_lpane->window,
640 pboot_lpane->focus_box.left,
641 pboot_lpane->focus_box.top,
642 pboot_lpane->focus_box.right,
643 pboot_lpane->focus_box.bottom);
645 twin_window_queue_paint(pboot_lpane->window);
647 return accel[(pos * 10) / dist];
650 static void pboot_set_lfocus(int index)
652 if (index >= pboot_dev_count)
655 pboot_lpane->focus_start = pboot_lpane->focus_box.top;
658 pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
660 pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF +
661 PBOOT_LEFT_ICON_STRIDE * index;
663 pboot_lpane->focus_curindex = index;
665 twin_set_timeout(pboot_lfocus_timeout, 0, NULL);
668 static void pboot_lpane_mousetrack(twin_coord_t x, twin_coord_t y)
671 twin_coord_t icon_top;
673 if (x < PBOOT_LEFT_ICON_XOFF ||
674 x > (PBOOT_LEFT_ICON_XOFF + PBOOT_LEFT_ICON_WIDTH))
676 if (y < PBOOT_LEFT_ICON_YOFF)
678 candidate = (y - PBOOT_LEFT_ICON_YOFF) / PBOOT_LEFT_ICON_STRIDE;
679 if (candidate >= pboot_dev_count) {
683 if (candidate == pboot_lpane->mouse_target)
685 icon_top = PBOOT_LEFT_ICON_YOFF +
686 candidate * PBOOT_LEFT_ICON_STRIDE;
687 if (y > (icon_top + PBOOT_LEFT_ICON_HEIGHT)) {
692 /* Ok, so now, we know the mouse hit an icon that wasn't the same
693 * as the previous one, we trigger a focus change
695 pboot_set_lfocus(candidate);
698 pboot_lpane->mouse_target = candidate;
701 static twin_bool_t pboot_lpane_event (twin_window_t *window,
704 /* filter out all mouse events */
705 switch(event->kind) {
707 case TwinEventMotion:
709 pboot_select_lpane();
710 pboot_lpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
712 case TwinEventButtonDown:
713 case TwinEventButtonUp:
715 case TwinEventKeyDown:
716 switch(event->u.key.key) {
718 if (pboot_lpane->focus_curindex > 0)
720 pboot_lpane->focus_curindex - 1);
723 pboot_set_lfocus(pboot_lpane->focus_curindex + 1);
726 pboot_select_rpane();
738 static void pboot_quit(void)
743 twin_bool_t pboot_event_filter(twin_screen_t *screen,
746 switch(event->kind) {
748 case TwinEventMotion:
750 case TwinEventButtonDown:
751 case TwinEventButtonUp:
752 if (pboot_cursor != NULL)
753 twin_screen_set_cursor(pboot_screen, pboot_cursor,
757 case TwinEventJoyButton:
758 /* map joystick events into key events */
759 if (event->u.js.control >= sizeof(sixaxis_map))
762 event->u.key.key = sixaxis_map[event->u.js.control];
763 if (event->u.js.value == 0) {
764 event->kind = TwinEventKeyUp;
767 event->kind = TwinEventKeyDown;
771 case TwinEventKeyDown:
772 switch(event->u.key.key) {
773 /* Gross hack for video modes, need something better ! */
775 pboot_vmode_change = 0; /* auto */
779 pboot_vmode_change = 3; /* 720p */
783 pboot_vmode_change = 4; /* 1080i */
787 pboot_vmode_change = 5; /* 1080p */
791 /* Another gross hack for booting back to gameos */
794 system("boot-game-os");
798 twin_screen_set_cursor(pboot_screen, NULL, 0, 0);
806 static void pboot_lpane_draw(twin_window_t *window)
808 twin_pixmap_t *px = window->pixmap;
809 pboot_lpane_t *lpane = window->client_data;
811 twin_fixed_t x, y, w, h;
814 /* Fill background */
815 twin_fill(px, PBOOT_LEFT_PANE_COLOR, TWIN_SOURCE,
816 0, 0, px->width, px->height);
818 /* Create a path for use later */
819 path = twin_path_create();
822 /* Draw right line if needed */
823 if (px->clip.right > (PBOOT_LEFT_PANE_SIZE - 4)) {
824 x = twin_int_to_fixed(PBOOT_LEFT_PANE_SIZE - 4);
825 y = twin_int_to_fixed(px->height);
826 twin_path_rectangle(path, x, 0, 0x40000, y);
827 twin_paint_path(px, PBOOT_LEFT_LINE_COLOR, path);
828 twin_path_empty(path);
832 if (lpane->focus_curindex >= 0 &&
833 twin_rect_intersect(lpane->focus_box, px->clip)) {
834 x = twin_int_to_fixed(lpane->focus_box.left + 2);
835 y = twin_int_to_fixed(lpane->focus_box.top + 2);
836 w = twin_int_to_fixed(lpane->focus_box.right -
837 lpane->focus_box.left - 4);
838 h = twin_int_to_fixed(lpane->focus_box.bottom -
839 lpane->focus_box.top - 4);
840 twin_path_rounded_rectangle(path, x, y, w, h,
841 PBOOT_LEFT_FOCUS_XRAD,
842 PBOOT_LEFT_FOCUS_YRAD);
843 if (pboot_focus_lpane)
844 twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
846 twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
851 for (i = 0; i < pboot_dev_count; i++) {
852 pboot_device_t *dev = pboot_devices[i];
855 if (!twin_rect_intersect(dev->box, px->clip))
858 src.source_kind = TWIN_PIXMAP;
859 src.u.pixmap = dev->badge;
861 twin_composite(px, dev->box.left, dev->box.top,
862 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
863 dev->box.right - dev->box.left,
864 dev->box.bottom - dev->box.top);
869 twin_path_destroy(path);
872 static void pboot_create_lpane(void)
874 pboot_lpane = calloc(1, sizeof(pboot_lpane_t));
877 pboot_lpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
879 0, 0, PBOOT_LEFT_PANE_SIZE,
880 pboot_screen->height);
881 assert(pboot_lpane->window);
883 pboot_lpane->window->draw = pboot_lpane_draw;
884 pboot_lpane->window->event = pboot_lpane_event;
885 pboot_lpane->window->client_data = pboot_lpane;
886 pboot_lpane->focus_curindex = -1;
887 pboot_lpane->focus_box.left = PBOOT_LEFT_FOCUS_XOFF;
888 pboot_lpane->focus_box.top = -2*PBOOT_LEFT_FOCUS_HEIGHT;
889 pboot_lpane->focus_box.right = pboot_lpane->focus_box.left +
890 PBOOT_LEFT_FOCUS_WIDTH;
891 pboot_lpane->focus_box.bottom = pboot_lpane->focus_box.top +
892 PBOOT_LEFT_FOCUS_HEIGHT;
893 pboot_lpane->mouse_target = -1;
894 twin_window_show(pboot_lpane->window);
895 twin_window_queue_paint(pboot_lpane->window);
898 static void pboot_spane_draw(twin_window_t *window)
900 twin_pixmap_t *px = window->pixmap;
901 pboot_spane_t *spane = window->client_data;
905 /* Fill background */
906 twin_fill(px, PBOOT_STATUS_PANE_COLOR, TWIN_SOURCE,
907 0, 0, px->width, px->height);
909 path = twin_path_create();
912 twin_path_set_font_size(path, PBOOT_STATUS_TEXT_SIZE);
913 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
914 tx = twin_int_to_fixed(PBOOT_STATUS_TEXT_MARGIN);
915 ty = twin_int_to_fixed(PBOOT_STATUS_PANE_HEIGHT - 2);
916 twin_path_move (path, tx, ty);
917 twin_path_utf8 (path, spane->text);
918 twin_paint_path (px, PBOOT_STATUS_TEXT_COLOR, path);
920 twin_path_destroy(path);
923 void pboot_message(const char *message)
925 if (pboot_spane->text)
926 free(pboot_spane->text);
927 pboot_spane->text = strdup(message);
928 twin_window_damage(pboot_spane->window,
930 pboot_spane->window->pixmap->width,
931 pboot_spane->window->pixmap->height);
932 twin_window_queue_paint(pboot_spane->window);
935 static void pboot_create_spane(void)
937 pboot_spane = calloc(1, sizeof(pboot_spane_t));
940 pboot_spane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
942 PBOOT_LEFT_PANE_SIZE +
943 PBOOT_STATUS_PANE_XYMARGIN,
944 pboot_screen->height -
945 PBOOT_STATUS_PANE_HEIGHT,
946 pboot_screen->width -
947 PBOOT_LEFT_PANE_SIZE -
948 2*PBOOT_STATUS_PANE_XYMARGIN,
949 PBOOT_STATUS_PANE_HEIGHT);
950 assert(pboot_spane->window);
952 pboot_spane->window->draw = pboot_spane_draw;
953 pboot_spane->window->client_data = pboot_spane;
954 pboot_spane->text = strdup(PBOOT_INITIAL_MESSAGE);
955 twin_window_show(pboot_spane->window);
956 twin_window_queue_paint(pboot_spane->window);
959 int pboot_add_device(const char *dev_id, const char *name,
960 twin_pixmap_t *pixmap)
965 if (pboot_dev_count >= PBOOT_MAX_DEV)
968 index = pboot_dev_count++;
970 dev = malloc(sizeof(*dev));
971 memset(dev, 0, sizeof(*dev));
972 dev->id = malloc(strlen(dev_id) + 1);
973 strcpy(dev->id, dev_id);
975 dev->box.left = PBOOT_LEFT_ICON_XOFF;
976 dev->box.right = dev->box.left + PBOOT_LEFT_ICON_WIDTH;
977 dev->box.top = PBOOT_LEFT_ICON_YOFF +
978 PBOOT_LEFT_ICON_STRIDE * index;
979 dev->box.bottom = dev->box.top + PBOOT_LEFT_ICON_HEIGHT;
981 pboot_devices[index] = dev;
983 twin_window_damage(pboot_lpane->window,
984 dev->box.left, dev->box.top,
985 dev->box.right, dev->box.bottom);
986 twin_window_queue_paint(pboot_lpane->window);
991 int pboot_remove_device(const char *dev_id)
993 pboot_device_t *dev = NULL;
994 int i, newsel = pboot_dev_sel;
996 /* find the matching device */
997 for (i = 0; i < pboot_dev_count; i++) {
998 if (!strcmp(pboot_devices[i]->id, dev_id)) {
999 dev = pboot_devices[i];
1007 memmove(pboot_devices + i, pboot_devices + i + 1,
1008 sizeof(*pboot_devices) * (pboot_dev_count + i - 1));
1009 pboot_devices[--pboot_dev_count] = NULL;
1011 /* select the newly-focussed device */
1012 if (pboot_dev_sel > i)
1013 newsel = pboot_dev_sel - 1;
1014 else if (pboot_dev_sel == i && i >= pboot_dev_count)
1015 newsel = pboot_dev_count - 1;
1016 pboot_set_device_select(newsel, 1);
1018 /* todo: free device & options */
1023 static void pboot_make_background(void)
1025 twin_pixmap_t *filepic, *scaledpic;
1026 const char *background_path;
1028 /* Set background pixmap */
1029 LOG("loading background...");
1030 background_path = artwork_pathname("background.jpg");
1031 filepic = twin_jpeg_to_pixmap(background_path, TWIN_ARGB32);
1032 LOG("%s\n", filepic ? "ok" : "failed");
1034 if (filepic == NULL)
1037 if (pboot_screen->height == filepic->height &&
1038 pboot_screen->width == filepic->width)
1039 scaledpic = filepic;
1041 twin_fixed_t sx, sy;
1042 twin_operand_t srcop;
1044 scaledpic = twin_pixmap_create(TWIN_ARGB32,
1045 pboot_screen->width,
1046 pboot_screen->height);
1047 if (scaledpic == NULL) {
1048 twin_pixmap_destroy(filepic);
1051 sx = twin_fixed_div(twin_int_to_fixed(filepic->width),
1052 twin_int_to_fixed(pboot_screen->width));
1053 sy = twin_fixed_div(twin_int_to_fixed(filepic->height),
1054 twin_int_to_fixed(pboot_screen->height));
1056 twin_matrix_scale(&filepic->transform, sx, sy);
1057 srcop.source_kind = TWIN_PIXMAP;
1058 srcop.u.pixmap = filepic;
1059 twin_composite(scaledpic, 0, 0, &srcop, 0, 0,
1060 NULL, 0, 0, TWIN_SOURCE,
1061 pboot_screen->width, pboot_screen->height);
1062 twin_pixmap_destroy(filepic);
1065 twin_screen_set_background(pboot_screen, scaledpic);
1068 #define PS3FB_IOCTL_SETMODE _IOW('r', 1, int)
1069 #define PS3FB_IOCTL_GETMODE _IOR('r', 2, int)
1071 static void exitfunc(void)
1075 twin_fbdev_destroy(pboot_fbdev);
1077 if (pboot_vmode_change != -1) {
1078 int fd = open("/dev/fb0", O_RDWR);
1080 ioctl(fd, PS3FB_IOCTL_SETMODE,
1081 (unsigned long)&pboot_vmode_change);
1087 static void sigint(int sig)
1093 static void usage(const char *progname)
1095 fprintf(stderr, "Usage: %s [-u] [-h]\n", progname);
1098 int main(int argc, char **argv)
1101 int udev_trigger = 0;
1104 c = getopt(argc, argv, "u::h");
1114 return EXIT_SUCCESS;
1116 fprintf(stderr, "Unknown option '%c'\n", c);
1118 return EXIT_FAILURE;
1123 signal(SIGINT, sigint);
1126 pboot_x11 = twin_x11_create(XOpenDisplay(0), 1024, 768);
1127 if (pboot_x11 == NULL) {
1128 perror("failed to create x11 screen !\n");
1131 pboot_screen = pboot_x11->screen;
1133 /* Create screen and mouse drivers */
1134 pboot_fbdev = twin_fbdev_create(-1, SIGUSR1);
1135 if (pboot_fbdev == NULL) {
1136 perror("failed to create fbdev screen !\n");
1139 pboot_screen = pboot_fbdev->screen;
1140 twin_linux_mouse_create(NULL, pboot_screen);
1141 twin_linux_js_create(pboot_screen);
1143 if (pboot_fbdev != NULL) {
1144 char *cursor_path = artwork_pathname("cursor.gz");
1145 pboot_cursor = twin_load_X_cursor(cursor_path, 2,
1148 if (pboot_cursor == NULL)
1150 twin_get_default_cursor(&pboot_cursor_hx,
1155 /* Set background pixmap */
1156 pboot_make_background();
1158 /* Init more stuffs */
1159 pboot_create_lpane();
1160 pboot_create_rpane();
1161 pboot_create_spane();
1163 if (!pboot_start_device_discovery(udev_trigger)) {
1164 LOG("Couldn't start device discovery!\n");
1168 pboot_set_lfocus(0);
1169 twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
1170 pboot_screen->event_filter = pboot_event_filter;
1172 /* Console switch */
1175 twin_fbdev_activate(pboot_fbdev);
1178 /* Process events */