11 #include <linux/input.h>
15 #include <libtwin/twin.h>
16 #include <libtwin/twin_linux_mouse.h>
17 #include <libtwin/twin_png.h>
18 #include <libtwin/twin_jpeg.h>
20 #include "petitboot.h"
21 #include "petitboot-paths.h"
24 #include <libtwin/twin_x11.h>
25 static twin_x11_t *pboot_x11;
27 #include <libtwin/twin_fbdev.h>
28 static twin_fbdev_t *pboot_fbdev;
31 static twin_screen_t *pboot_screen;
33 #define PBOOT_INITIAL_MESSAGE \
34 "video hack: 0=default 1=720p 2=1080i 3=1080p " \
35 "BACKSPACE=return to 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 static int pboot_vmode_change = -1;
147 /* XXX move to twin */
148 static inline twin_bool_t twin_rect_intersect(twin_rect_t r1,
151 return !(r1.left > r2.right ||
152 r1.right < r2.left ||
153 r1.top > r2.bottom ||
157 static void pboot_draw_option_cache(pboot_device_t *dev, pboot_option_t *opt,
165 px = twin_pixmap_create(TWIN_ARGB32, opt->box.right - opt->box.left,
166 opt->box.bottom - opt->box.top);
170 /* Fill background */
171 twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
173 /* Allocate a path for drawing */
174 path = twin_path_create();
178 /* TEST - Bounding rectangle */
179 twin_path_rectangle(path, 0, 0,
180 twin_int_to_fixed(px->width),
181 twin_int_to_fixed(px->height));
182 twin_paint_path(px, PBOOT_RIGHT_TITLE_COLOR, path);
183 twin_path_empty(path);
184 twin_fill(px, 0x00000000, TWIN_SOURCE, 2, 2,
185 px->width - 3, px->height - 3);
189 twin_path_set_font_size(path, PBOOT_RIGHT_TITLE_TEXT_SIZE);
190 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
191 tx = twin_int_to_fixed(PBOOT_RIGHT_TITLE_XOFFSET);
192 ty = twin_int_to_fixed(PBOOT_RIGHT_TITLE_YOFFSET);
193 twin_path_move (path, tx, ty);
194 twin_path_utf8 (path, opt->title);
195 twin_paint_path (px, PBOOT_RIGHT_TITLE_COLOR, path);
196 twin_path_empty (path);
199 twin_path_set_font_size(path, PBOOT_RIGHT_SUBTITLE_TEXT_SIZE);
200 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
201 tx = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_XOFFSET);
202 ty = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_YOFFSET);
203 twin_path_move (path, tx, ty);
204 twin_path_utf8 (path, opt->subtitle);
205 twin_paint_path (px, PBOOT_RIGHT_SUBTITLE_COLOR, path);
206 twin_path_empty (path);
212 src.source_kind = TWIN_PIXMAP;
213 src.u.pixmap = opt->badge;
215 twin_composite(px, PBOOT_RIGHT_BADGE_XOFFSET,
216 PBOOT_RIGHT_BADGE_YOFFSET,
217 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
218 opt->badge->width, opt->badge->height);
223 twin_path_destroy(path);
226 static void pboot_rpane_draw(twin_window_t *window)
228 twin_pixmap_t *px = window->pixmap;
229 pboot_rpane_t *rpane = window->client_data;
232 twin_fixed_t x, y, w, h;
235 /* Fill background */
236 twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
238 /* Nothing to draw, return */
239 if (pboot_dev_sel < 0)
242 /* Create a path for use later */
243 path = twin_path_create();
247 if (rpane->focus_curindex >= 0 &&
248 twin_rect_intersect(rpane->focus_box, px->clip)) {
249 x = twin_int_to_fixed(rpane->focus_box.left + 2);
250 y = twin_int_to_fixed(rpane->focus_box.top + 2);
251 w = twin_int_to_fixed(rpane->focus_box.right -
252 rpane->focus_box.left - 4);
253 h = twin_int_to_fixed(rpane->focus_box.bottom -
254 rpane->focus_box.top - 4);
255 twin_path_rounded_rectangle(path, x, y, w, h,
256 PBOOT_RIGHT_FOCUS_XRAD,
257 PBOOT_RIGHT_FOCUS_YRAD);
258 if (!pboot_focus_lpane)
259 twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
261 twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
265 /* Get device and iterate through options */
266 dev = pboot_devices[pboot_dev_sel];
267 for (i = 0; i < dev->option_count; i++) {
268 pboot_option_t *opt = &dev->options[i];
271 if (opt->title == NULL)
273 if (!twin_rect_intersect(opt->box, px->clip))
275 if (opt->cache == NULL)
276 pboot_draw_option_cache(dev, opt, i);
278 src.source_kind = TWIN_PIXMAP;
279 src.u.pixmap = opt->cache;
281 twin_composite(px, opt->box.left, opt->box.top,
282 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
283 opt->box.right - opt->box.left,
284 opt->box.bottom - opt->box.top);
288 twin_path_destroy(path);
291 static twin_time_t pboot_rfocus_timeout (twin_time_t now, void *closure)
293 int dir = 1, dist, pos;
294 const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 1, 2, 2, 3 };
296 dist = abs(pboot_rpane->focus_target - pboot_rpane->focus_start);
297 dir = dist > 5 ? 5 : dist;
298 pos = pboot_rpane->focus_target - (int)pboot_rpane->focus_box.top;
306 twin_window_damage(pboot_rpane->window,
307 pboot_rpane->focus_box.left,
308 pboot_rpane->focus_box.top,
309 pboot_rpane->focus_box.right,
310 pboot_rpane->focus_box.bottom);
312 pboot_rpane->focus_box.top += dir;
313 pboot_rpane->focus_box.bottom += dir;
315 twin_window_damage(pboot_rpane->window,
316 pboot_rpane->focus_box.left,
317 pboot_rpane->focus_box.top,
318 pboot_rpane->focus_box.right,
319 pboot_rpane->focus_box.bottom);
321 twin_window_queue_paint(pboot_rpane->window);
323 return accel[(pos * 10) / dist];
326 static void pboot_set_rfocus(int index)
330 if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
332 dev = pboot_devices[pboot_dev_sel];
333 if (index < 0 || index >= dev->option_count)
336 pboot_rpane->focus_start = pboot_rpane->focus_box.top;
337 pboot_rpane->focus_target = PBOOT_RIGHT_FOCUS_YOFF +
338 PBOOT_RIGHT_OPTION_STRIDE * index;
339 pboot_rpane->focus_curindex = index;
341 twin_set_timeout(pboot_rfocus_timeout, 0, NULL);
344 static void pboot_select_rpane(void)
346 if (pboot_focus_lpane == 0)
348 pboot_focus_lpane = 0;
350 twin_screen_set_active(pboot_screen, pboot_rpane->window->pixmap);
352 twin_window_damage(pboot_lpane->window,
353 pboot_lpane->focus_box.left,
354 pboot_lpane->focus_box.top,
355 pboot_lpane->focus_box.right,
356 pboot_lpane->focus_box.bottom);
358 twin_window_damage(pboot_rpane->window,
359 pboot_rpane->focus_box.left,
360 pboot_rpane->focus_box.top,
361 pboot_rpane->focus_box.right,
362 pboot_rpane->focus_box.bottom);
364 twin_window_queue_paint(pboot_lpane->window);
365 twin_window_queue_paint(pboot_rpane->window);
370 static void pboot_select_lpane(void)
372 if (pboot_focus_lpane == 1)
374 pboot_focus_lpane = 1;
376 twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
378 twin_window_damage(pboot_lpane->window,
379 pboot_lpane->focus_box.left,
380 pboot_lpane->focus_box.top,
381 pboot_lpane->focus_box.right,
382 pboot_lpane->focus_box.bottom);
384 twin_window_damage(pboot_rpane->window,
385 pboot_rpane->focus_box.left,
386 pboot_rpane->focus_box.top,
387 pboot_rpane->focus_box.right,
388 pboot_rpane->focus_box.bottom);
390 twin_window_queue_paint(pboot_lpane->window);
391 twin_window_queue_paint(pboot_rpane->window);
394 static void pboot_rpane_mousetrack(twin_coord_t x, twin_coord_t y)
400 if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
402 dev = pboot_devices[pboot_dev_sel];
404 if (y < PBOOT_RIGHT_OPTION_TMARGIN)
406 candidate = (y - PBOOT_RIGHT_OPTION_TMARGIN) /
407 PBOOT_RIGHT_OPTION_STRIDE;
408 if (candidate >= dev->option_count) {
412 if (candidate == pboot_rpane->mouse_target)
414 opt = &dev->options[candidate];
415 if (x < opt->box.left || x > opt->box.right ||
416 y < opt->box.top || y > opt->box.bottom) {
421 /* Ok, so now, we know the mouse hit an icon that wasn't the same
422 * as the previous one, we trigger a focus change
424 pboot_set_rfocus(candidate);
427 pboot_rpane->mouse_target = candidate;
430 static void pboot_choose_option(void)
432 pboot_device_t *dev = pboot_devices[pboot_dev_sel];
433 pboot_option_t *opt = &dev->options[pboot_rpane->focus_curindex];
435 LOG("Selected device %s\n", opt->title);
437 /* Give user feedback, make sure errors and panics will be seen */
438 pboot_exec_option(opt->data);
441 static twin_bool_t pboot_rpane_event (twin_window_t *window,
444 /* filter out all mouse events */
445 switch(event->kind) {
447 case TwinEventMotion:
449 pboot_select_rpane();
450 pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
452 case TwinEventButtonDown:
453 pboot_select_rpane();
454 pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
455 pboot_choose_option();
456 case TwinEventButtonUp:
458 case TwinEventKeyDown:
459 switch(event->u.key.key) {
461 pboot_set_rfocus(pboot_rpane->focus_curindex - 1);
464 pboot_set_rfocus(pboot_rpane->focus_curindex + 1);
467 pboot_select_lpane();
470 pboot_choose_option();
482 int pboot_add_option(int devindex, const char *title,
483 const char *subtitle, twin_pixmap_t *badge, void *data)
490 if (devindex < 0 || devindex >= pboot_dev_count)
492 dev = pboot_devices[devindex];
494 if (dev->option_count >= PBOOT_MAX_OPTION)
496 index = dev->option_count++;
497 opt = &dev->options[index];
499 opt->title = malloc(strlen(title) + 1);
500 strcpy(opt->title, title);
503 opt->subtitle = malloc(strlen(subtitle) + 1);
504 strcpy(opt->subtitle, subtitle);
506 opt->subtitle = NULL;
511 width = pboot_rpane->window->pixmap->width -
512 (PBOOT_RIGHT_OPTION_LMARGIN + PBOOT_RIGHT_OPTION_RMARGIN);
514 opt->box.left = PBOOT_RIGHT_OPTION_LMARGIN;
515 opt->box.right = opt->box.left + width;
516 opt->box.top = PBOOT_RIGHT_OPTION_TMARGIN +
517 index * PBOOT_RIGHT_OPTION_STRIDE;
518 opt->box.bottom = opt->box.top + PBOOT_RIGHT_OPTION_HEIGHT;
525 static void pboot_set_device_select(int sel, int force)
527 LOG("%s: %d -> %d\n", __FUNCTION__, pboot_dev_sel, sel);
528 if (!force && sel == pboot_dev_sel)
530 if (sel >= pboot_dev_count)
534 pboot_lpane->focus_curindex = sel;
536 pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
538 pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF +
539 PBOOT_LEFT_ICON_STRIDE * sel;
540 pboot_rpane->focus_box.bottom = pboot_lpane->focus_target;
541 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
542 PBOOT_RIGHT_FOCUS_HEIGHT;
543 twin_window_damage(pboot_lpane->window,
545 pboot_lpane->window->pixmap->width,
546 pboot_lpane->window->pixmap->height);
547 twin_window_queue_paint(pboot_lpane->window);
549 pboot_rpane->focus_curindex = -1;
550 pboot_rpane->mouse_target = -1;
551 pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
552 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
553 PBOOT_RIGHT_FOCUS_HEIGHT;
554 twin_window_damage(pboot_rpane->window, 0, 0,
555 pboot_rpane->window->pixmap->width,
556 pboot_rpane->window->pixmap->height);
557 twin_window_queue_paint(pboot_rpane->window);
560 static void pboot_create_rpane(void)
562 pboot_rpane = calloc(1, sizeof(pboot_rpane_t));
565 pboot_rpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
567 PBOOT_LEFT_PANE_SIZE, 0,
568 pboot_screen->width -
569 PBOOT_LEFT_PANE_SIZE,
570 pboot_screen->height);
571 assert(pboot_rpane->window);
573 pboot_rpane->window->draw = pboot_rpane_draw;
574 pboot_rpane->window->event = pboot_rpane_event;
575 pboot_rpane->window->client_data = pboot_rpane;
577 pboot_rpane->focus_curindex = -1;
578 pboot_rpane->focus_box.left = PBOOT_RIGHT_FOCUS_XOFF;
579 pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
580 pboot_rpane->focus_box.right = pboot_rpane->window->pixmap->width -
581 2 * PBOOT_RIGHT_FOCUS_XOFF;
582 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
583 PBOOT_RIGHT_FOCUS_HEIGHT;
584 pboot_rpane->mouse_target = -1;
585 twin_window_show(pboot_rpane->window);
586 twin_window_queue_paint(pboot_rpane->window);
590 static twin_time_t pboot_lfocus_timeout (twin_time_t now, void *closure)
592 int dir = 1, dist, pos;
593 const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 1, 2, 2, 3 };
595 dist = abs(pboot_lpane->focus_target - pboot_lpane->focus_start);
596 dir = dist > 2 ? 2 : dist;
597 pos = pboot_lpane->focus_target - (int)pboot_lpane->focus_box.top;
599 pboot_set_device_select(pboot_lpane->focus_curindex, 0);
606 twin_window_damage(pboot_lpane->window,
607 pboot_lpane->focus_box.left,
608 pboot_lpane->focus_box.top,
609 pboot_lpane->focus_box.right,
610 pboot_lpane->focus_box.bottom);
612 pboot_lpane->focus_box.top += dir;
613 pboot_lpane->focus_box.bottom += dir;
615 twin_window_damage(pboot_lpane->window,
616 pboot_lpane->focus_box.left,
617 pboot_lpane->focus_box.top,
618 pboot_lpane->focus_box.right,
619 pboot_lpane->focus_box.bottom);
621 twin_window_queue_paint(pboot_lpane->window);
623 return accel[(pos * 10) / dist];
626 static void pboot_set_lfocus(int index)
628 if (index >= pboot_dev_count)
631 pboot_lpane->focus_start = pboot_lpane->focus_box.top;
634 pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
636 pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF +
637 PBOOT_LEFT_ICON_STRIDE * index;
639 pboot_lpane->focus_curindex = index;
641 twin_set_timeout(pboot_lfocus_timeout, 0, NULL);
644 static void pboot_lpane_mousetrack(twin_coord_t x, twin_coord_t y)
647 twin_coord_t icon_top;
649 if (x < PBOOT_LEFT_ICON_XOFF ||
650 x > (PBOOT_LEFT_ICON_XOFF + PBOOT_LEFT_ICON_WIDTH))
652 if (y < PBOOT_LEFT_ICON_YOFF)
654 candidate = (y - PBOOT_LEFT_ICON_YOFF) / PBOOT_LEFT_ICON_STRIDE;
655 if (candidate >= pboot_dev_count) {
659 if (candidate == pboot_lpane->mouse_target)
661 icon_top = PBOOT_LEFT_ICON_YOFF +
662 candidate * PBOOT_LEFT_ICON_STRIDE;
663 if (y > (icon_top + PBOOT_LEFT_ICON_HEIGHT)) {
668 /* Ok, so now, we know the mouse hit an icon that wasn't the same
669 * as the previous one, we trigger a focus change
671 pboot_set_lfocus(candidate);
674 pboot_lpane->mouse_target = candidate;
677 static twin_bool_t pboot_lpane_event (twin_window_t *window,
680 /* filter out all mouse events */
681 switch(event->kind) {
683 case TwinEventMotion:
685 pboot_select_lpane();
686 pboot_lpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
688 case TwinEventButtonDown:
689 case TwinEventButtonUp:
691 case TwinEventKeyDown:
692 switch(event->u.key.key) {
694 if (pboot_lpane->focus_curindex > 0)
696 pboot_lpane->focus_curindex - 1);
699 pboot_set_lfocus(pboot_lpane->focus_curindex + 1);
702 pboot_select_rpane();
714 static void pboot_quit(void)
719 twin_bool_t pboot_event_filter(twin_screen_t *screen,
722 switch(event->kind) {
724 case TwinEventMotion:
726 case TwinEventButtonDown:
727 case TwinEventButtonUp:
728 if (pboot_cursor != NULL)
729 twin_screen_set_cursor(pboot_screen, pboot_cursor,
733 case TwinEventKeyDown:
734 switch(event->u.key.key) {
735 /* Gross hack for video modes, need something better ! */
737 pboot_vmode_change = 0; /* auto */
741 pboot_vmode_change = 3; /* 720p */
745 pboot_vmode_change = 4; /* 1080i */
749 pboot_vmode_change = 5; /* 1080p */
753 /* Another gross hack for booting back to gameos */
756 system("boot-game-os");
760 twin_screen_set_cursor(pboot_screen, NULL, 0, 0);
768 static void pboot_lpane_draw(twin_window_t *window)
770 twin_pixmap_t *px = window->pixmap;
771 pboot_lpane_t *lpane = window->client_data;
773 twin_fixed_t x, y, w, h;
776 /* Fill background */
777 twin_fill(px, PBOOT_LEFT_PANE_COLOR, TWIN_SOURCE,
778 0, 0, px->width, px->height);
780 /* Create a path for use later */
781 path = twin_path_create();
784 /* Draw right line if needed */
785 if (px->clip.right > (PBOOT_LEFT_PANE_SIZE - 4)) {
786 x = twin_int_to_fixed(PBOOT_LEFT_PANE_SIZE - 4);
787 y = twin_int_to_fixed(px->height);
788 twin_path_rectangle(path, x, 0, 0x40000, y);
789 twin_paint_path(px, PBOOT_LEFT_LINE_COLOR, path);
790 twin_path_empty(path);
794 if (lpane->focus_curindex >= 0 &&
795 twin_rect_intersect(lpane->focus_box, px->clip)) {
796 x = twin_int_to_fixed(lpane->focus_box.left + 2);
797 y = twin_int_to_fixed(lpane->focus_box.top + 2);
798 w = twin_int_to_fixed(lpane->focus_box.right -
799 lpane->focus_box.left - 4);
800 h = twin_int_to_fixed(lpane->focus_box.bottom -
801 lpane->focus_box.top - 4);
802 twin_path_rounded_rectangle(path, x, y, w, h,
803 PBOOT_LEFT_FOCUS_XRAD,
804 PBOOT_LEFT_FOCUS_YRAD);
805 if (pboot_focus_lpane)
806 twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
808 twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
813 for (i = 0; i < pboot_dev_count; i++) {
814 pboot_device_t *dev = pboot_devices[i];
817 if (!twin_rect_intersect(dev->box, px->clip))
820 src.source_kind = TWIN_PIXMAP;
821 src.u.pixmap = dev->badge;
823 twin_composite(px, dev->box.left, dev->box.top,
824 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
825 dev->box.right - dev->box.left,
826 dev->box.bottom - dev->box.top);
831 twin_path_destroy(path);
834 static void pboot_create_lpane(void)
836 pboot_lpane = calloc(1, sizeof(pboot_lpane_t));
839 pboot_lpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
841 0, 0, PBOOT_LEFT_PANE_SIZE,
842 pboot_screen->height);
843 assert(pboot_lpane->window);
845 pboot_lpane->window->draw = pboot_lpane_draw;
846 pboot_lpane->window->event = pboot_lpane_event;
847 pboot_lpane->window->client_data = pboot_lpane;
848 pboot_lpane->focus_curindex = -1;
849 pboot_lpane->focus_box.left = PBOOT_LEFT_FOCUS_XOFF;
850 pboot_lpane->focus_box.top = -2*PBOOT_LEFT_FOCUS_HEIGHT;
851 pboot_lpane->focus_box.right = pboot_lpane->focus_box.left +
852 PBOOT_LEFT_FOCUS_WIDTH;
853 pboot_lpane->focus_box.bottom = pboot_lpane->focus_box.top +
854 PBOOT_LEFT_FOCUS_HEIGHT;
855 pboot_lpane->mouse_target = -1;
856 twin_window_show(pboot_lpane->window);
857 twin_window_queue_paint(pboot_lpane->window);
860 static void pboot_spane_draw(twin_window_t *window)
862 twin_pixmap_t *px = window->pixmap;
863 pboot_spane_t *spane = window->client_data;
867 /* Fill background */
868 twin_fill(px, PBOOT_STATUS_PANE_COLOR, TWIN_SOURCE,
869 0, 0, px->width, px->height);
871 path = twin_path_create();
874 twin_path_set_font_size(path, PBOOT_STATUS_TEXT_SIZE);
875 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
876 tx = twin_int_to_fixed(PBOOT_STATUS_TEXT_MARGIN);
877 ty = twin_int_to_fixed(PBOOT_STATUS_PANE_HEIGHT - 2);
878 twin_path_move (path, tx, ty);
879 twin_path_utf8 (path, spane->text);
880 twin_paint_path (px, PBOOT_STATUS_TEXT_COLOR, path);
882 twin_path_destroy(path);
885 void pboot_message(const char *message)
887 if (pboot_spane->text)
888 free(pboot_spane->text);
889 pboot_spane->text = strdup(message);
890 twin_window_damage(pboot_spane->window,
892 pboot_spane->window->pixmap->width,
893 pboot_spane->window->pixmap->height);
894 twin_window_queue_paint(pboot_spane->window);
897 static void pboot_create_spane(void)
899 pboot_spane = calloc(1, sizeof(pboot_spane_t));
902 pboot_spane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
904 PBOOT_LEFT_PANE_SIZE +
905 PBOOT_STATUS_PANE_XYMARGIN,
906 pboot_screen->height -
907 PBOOT_STATUS_PANE_HEIGHT,
908 pboot_screen->width -
909 PBOOT_LEFT_PANE_SIZE -
910 2*PBOOT_STATUS_PANE_XYMARGIN,
911 PBOOT_STATUS_PANE_HEIGHT);
912 assert(pboot_spane->window);
914 pboot_spane->window->draw = pboot_spane_draw;
915 pboot_spane->window->client_data = pboot_spane;
916 pboot_spane->text = strdup(PBOOT_INITIAL_MESSAGE);
917 twin_window_show(pboot_spane->window);
918 twin_window_queue_paint(pboot_spane->window);
921 int pboot_add_device(const char *dev_id, const char *name,
922 twin_pixmap_t *pixmap)
927 if (pboot_dev_count >= PBOOT_MAX_DEV)
930 index = pboot_dev_count++;
932 dev = malloc(sizeof(*dev));
933 memset(dev, 0, sizeof(*dev));
934 dev->id = malloc(strlen(dev_id) + 1);
935 strcpy(dev->id, dev_id);
937 dev->box.left = PBOOT_LEFT_ICON_XOFF;
938 dev->box.right = dev->box.left + PBOOT_LEFT_ICON_WIDTH;
939 dev->box.top = PBOOT_LEFT_ICON_YOFF +
940 PBOOT_LEFT_ICON_STRIDE * index;
941 dev->box.bottom = dev->box.top + PBOOT_LEFT_ICON_HEIGHT;
943 pboot_devices[index] = dev;
945 twin_window_damage(pboot_lpane->window,
946 dev->box.left, dev->box.top,
947 dev->box.right, dev->box.bottom);
948 twin_window_queue_paint(pboot_lpane->window);
953 int pboot_remove_device(const char *dev_id)
955 pboot_device_t *dev = NULL;
956 int i, newsel = pboot_dev_sel;
958 /* find the matching device */
959 for (i = 0; i < pboot_dev_count; i++) {
960 if (!strcmp(pboot_devices[i]->id, dev_id)) {
961 dev = pboot_devices[i];
969 memmove(pboot_devices + i, pboot_devices + i + 1,
970 sizeof(*pboot_devices) * (pboot_dev_count + i - 1));
971 pboot_devices[--pboot_dev_count] = NULL;
973 /* select the newly-focussed device */
974 if (pboot_dev_sel > i)
975 newsel = pboot_dev_sel - 1;
976 else if (pboot_dev_sel == i && i >= pboot_dev_count)
977 newsel = pboot_dev_count - 1;
978 pboot_set_device_select(newsel, 1);
980 /* todo: free device & options */
985 static void pboot_make_background(void)
987 twin_pixmap_t *filepic, *scaledpic;
988 const char *background_path;
990 /* Set background pixmap */
991 LOG("loading background...");
992 background_path = artwork_pathname("background.jpg");
993 filepic = twin_jpeg_to_pixmap(background_path, TWIN_ARGB32);
994 LOG("%s\n", filepic ? "ok" : "failed");
999 if (pboot_screen->height == filepic->height &&
1000 pboot_screen->width == filepic->width)
1001 scaledpic = filepic;
1003 twin_fixed_t sx, sy;
1004 twin_operand_t srcop;
1006 scaledpic = twin_pixmap_create(TWIN_ARGB32,
1007 pboot_screen->width,
1008 pboot_screen->height);
1009 if (scaledpic == NULL) {
1010 twin_pixmap_destroy(filepic);
1013 sx = twin_fixed_div(twin_int_to_fixed(filepic->width),
1014 twin_int_to_fixed(pboot_screen->width));
1015 sy = twin_fixed_div(twin_int_to_fixed(filepic->height),
1016 twin_int_to_fixed(pboot_screen->height));
1018 twin_matrix_scale(&filepic->transform, sx, sy);
1019 srcop.source_kind = TWIN_PIXMAP;
1020 srcop.u.pixmap = filepic;
1021 twin_composite(scaledpic, 0, 0, &srcop, 0, 0,
1022 NULL, 0, 0, TWIN_SOURCE,
1023 pboot_screen->width, pboot_screen->height);
1024 twin_pixmap_destroy(filepic);
1027 twin_screen_set_background(pboot_screen, scaledpic);
1030 #define PS3FB_IOCTL_SETMODE _IOW('r', 1, int)
1031 #define PS3FB_IOCTL_GETMODE _IOR('r', 2, int)
1033 static void exitfunc(void)
1037 twin_fbdev_destroy(pboot_fbdev);
1039 if (pboot_vmode_change != -1) {
1040 int fd = open("/dev/fb0", O_RDWR);
1042 ioctl(fd, PS3FB_IOCTL_SETMODE,
1043 (unsigned long)&pboot_vmode_change);
1049 static void sigint(int sig)
1055 static void usage(const char *progname)
1057 fprintf(stderr, "Usage: %s [-u] [-h]\n", progname);
1060 int main(int argc, char **argv)
1063 int udev_trigger = 0;
1066 c = getopt(argc, argv, "u::h");
1076 return EXIT_SUCCESS;
1078 fprintf(stderr, "Unknown option '%c'\n", c);
1080 return EXIT_FAILURE;
1085 signal(SIGINT, sigint);
1088 pboot_x11 = twin_x11_create(XOpenDisplay(0), 1024, 768);
1089 if (pboot_x11 == NULL) {
1090 perror("failed to create x11 screen !\n");
1093 pboot_screen = pboot_x11->screen;
1095 /* Create screen and mouse drivers */
1096 pboot_fbdev = twin_fbdev_create(-1, SIGUSR1);
1097 if (pboot_fbdev == NULL) {
1098 perror("failed to create fbdev screen !\n");
1101 pboot_screen = pboot_fbdev->screen;
1102 twin_linux_mouse_create(NULL, pboot_screen);
1104 if (pboot_fbdev != NULL) {
1105 char *cursor_path = artwork_pathname("cursor.gz");
1106 pboot_cursor = twin_load_X_cursor(cursor_path, 2,
1109 if (pboot_cursor == NULL)
1111 twin_get_default_cursor(&pboot_cursor_hx,
1116 /* Set background pixmap */
1117 pboot_make_background();
1119 /* Init more stuffs */
1120 pboot_create_lpane();
1121 pboot_create_rpane();
1122 pboot_create_spane();
1124 if (!pboot_start_device_discovery(udev_trigger)) {
1125 LOG("Couldn't start device discovery!\n");
1129 pboot_set_lfocus(0);
1130 twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
1131 pboot_screen->event_filter = pboot_event_filter;
1133 /* Console switch */
1136 twin_fbdev_activate(pboot_fbdev);
1139 /* Process events */