9 #include <linux/input.h>
13 #include <libtwin/twin.h>
14 #include <libtwin/twin_linux_mouse.h>
15 #include <libtwin/twin_png.h>
17 #include "petitboot.h"
18 #include "petitboot-paths.h"
21 #include <libtwin/twin_x11.h>
22 static twin_x11_t *pboot_x11;
24 #include <libtwin/twin_fbdev.h>
25 static twin_fbdev_t *pboot_fbdev;
28 static twin_screen_t *pboot_screen;
30 #define PBOOT_LEFT_PANE_SIZE 200
31 #define PBOOT_LEFT_PANE_COLOR 0x80000000
32 #define PBOOT_LEFT_LINE_COLOR 0xff000000
34 #define PBOOT_LEFT_FOCUS_WIDTH 80
35 #define PBOOT_LEFT_FOCUS_HEIGHT 80
36 #define PBOOT_LEFT_FOCUS_XOFF 60
37 #define PBOOT_LEFT_FOCUS_YOFF 60
38 #define PBOOT_LEFT_FOCUS_XRAD (6 * TWIN_FIXED_ONE)
39 #define PBOOT_LEFT_FOCUS_YRAD (6 * TWIN_FIXED_ONE)
41 #define PBOOT_RIGHT_FOCUS_XOFF 20
42 #define PBOOT_RIGHT_FOCUS_YOFF 60
43 #define PBOOT_RIGHT_FOCUS_HEIGHT 80
44 #define PBOOT_RIGHT_FOCUS_XRAD (6 * TWIN_FIXED_ONE)
45 #define PBOOT_RIGHT_FOCUS_YRAD (6 * TWIN_FIXED_ONE)
47 #define PBOOT_LEFT_ICON_WIDTH 64
48 #define PBOOT_LEFT_ICON_HEIGHT 64
49 #define PBOOT_LEFT_ICON_XOFF 70
50 #define PBOOT_LEFT_ICON_YOFF 70
51 #define PBOOT_LEFT_ICON_STRIDE 100
53 #define PBOOT_RIGHT_OPTION_LMARGIN 30
54 #define PBOOT_RIGHT_OPTION_RMARGIN 30
55 #define PBOOT_RIGHT_OPTION_TMARGIN 70
56 #define PBOOT_RIGHT_OPTION_HEIGHT 64
57 #define PBOOT_RIGHT_OPTION_STRIDE 100
58 #define PBOOT_RIGHT_TITLE_TEXT_SIZE (30 * TWIN_FIXED_ONE)
59 #define PBOOT_RIGHT_SUBTITLE_TEXT_SIZE (18 * TWIN_FIXED_ONE)
60 #define PBOOT_RIGHT_TITLE_XOFFSET 80
61 #define PBOOT_RIGHT_TITLE_YOFFSET 30
62 #define PBOOT_RIGHT_SUBTITLE_XOFFSET 200
63 #define PBOOT_RIGHT_SUBTITLE_YOFFSET 50
64 #define PBOOT_RIGHT_BADGE_XOFFSET 2
65 #define PBOOT_RIGHT_BADGE_YOFFSET 0
68 #define PBOOT_RIGHT_TITLE_COLOR 0xff000000
69 #define PBOOT_RIGHT_SUBTITLE_COLOR 0xff400000
71 #define PBOOT_FOCUS_COLOR 0x10404040
74 typedef struct _pboot_option pboot_option_t;
75 typedef struct _pboot_device pboot_device_t;
93 pboot_option_t options[PBOOT_MAX_OPTION];
96 static twin_pixmap_t *pboot_cursor;
97 static int pboot_cursor_hx;
98 static int pboot_cursor_hy;
100 static pboot_device_t *pboot_devices[PBOOT_MAX_DEV];
101 static int pboot_dev_count;
102 static int pboot_dev_sel = -1;
103 static int pboot_focus_lpane = 1;
105 typedef struct _pboot_lpane {
106 twin_window_t *window;
107 twin_rect_t focus_box;
114 typedef struct _pboot_rpane {
115 twin_window_t *window;
116 twin_rect_t focus_box;
123 static pboot_lpane_t *pboot_lpane;
124 static pboot_rpane_t *pboot_rpane;
126 /* XXX move to twin */
127 static inline twin_bool_t twin_rect_intersect(twin_rect_t r1,
130 return !(r1.left > r2.right ||
131 r1.right < r2.left ||
132 r1.top > r2.bottom ||
136 static void pboot_draw_option_cache(pboot_device_t *dev, pboot_option_t *opt,
144 px = twin_pixmap_create(TWIN_ARGB32, opt->box.right - opt->box.left,
145 opt->box.bottom - opt->box.top);
149 /* Fill background */
150 twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
152 /* Allocate a path for drawing */
153 path = twin_path_create();
157 /* TEST - Bounding rectangle */
158 twin_path_rectangle(path, 0, 0,
159 twin_int_to_fixed(px->width),
160 twin_int_to_fixed(px->height));
161 twin_paint_path(px, PBOOT_RIGHT_TITLE_COLOR, path);
162 twin_path_empty(path);
163 twin_fill(px, 0x00000000, TWIN_SOURCE, 2, 2,
164 px->width - 3, px->height - 3);
168 twin_path_set_font_size(path, PBOOT_RIGHT_TITLE_TEXT_SIZE);
169 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
170 tx = twin_int_to_fixed(PBOOT_RIGHT_TITLE_XOFFSET);
171 ty = twin_int_to_fixed(PBOOT_RIGHT_TITLE_YOFFSET);
172 twin_path_move (path, tx, ty);
173 twin_path_utf8 (path, opt->title);
174 twin_paint_path (px, PBOOT_RIGHT_TITLE_COLOR, path);
175 twin_path_empty (path);
178 twin_path_set_font_size(path, PBOOT_RIGHT_SUBTITLE_TEXT_SIZE);
179 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
180 tx = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_XOFFSET);
181 ty = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_YOFFSET);
182 twin_path_move (path, tx, ty);
183 twin_path_utf8 (path, opt->subtitle);
184 twin_paint_path (px, PBOOT_RIGHT_SUBTITLE_COLOR, path);
185 twin_path_empty (path);
191 src.source_kind = TWIN_PIXMAP;
192 src.u.pixmap = opt->badge;
194 twin_composite(px, PBOOT_RIGHT_BADGE_XOFFSET,
195 PBOOT_RIGHT_BADGE_YOFFSET,
196 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
197 opt->badge->width, opt->badge->height);
202 twin_path_destroy(path);
205 static void pboot_rpane_draw(twin_window_t *window)
207 twin_pixmap_t *px = window->pixmap;
208 pboot_rpane_t *rpane = window->client_data;
211 twin_fixed_t x, y, w, h;
214 /* Fill background */
215 twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
217 /* Nothing to draw, return */
218 if (pboot_dev_sel < 0)
221 /* Create a path for use later */
222 path = twin_path_create();
226 if (rpane->focus_curindex >= 0 &&
227 twin_rect_intersect(rpane->focus_box, px->clip)) {
228 x = twin_int_to_fixed(rpane->focus_box.left + 2);
229 y = twin_int_to_fixed(rpane->focus_box.top + 2);
230 w = twin_int_to_fixed(rpane->focus_box.right -
231 rpane->focus_box.left - 4);
232 h = twin_int_to_fixed(rpane->focus_box.bottom -
233 rpane->focus_box.top - 4);
234 twin_path_rounded_rectangle(path, x, y, w, h,
235 PBOOT_RIGHT_FOCUS_XRAD,
236 PBOOT_RIGHT_FOCUS_YRAD);
237 if (!pboot_focus_lpane)
238 twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
240 twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
244 /* Get device and iterate through options */
245 dev = pboot_devices[pboot_dev_sel];
246 for (i = 0; i < dev->option_count; i++) {
247 pboot_option_t *opt = &dev->options[i];
250 if (opt->title == NULL)
252 if (!twin_rect_intersect(opt->box, px->clip))
254 if (opt->cache == NULL)
255 pboot_draw_option_cache(dev, opt, i);
257 src.source_kind = TWIN_PIXMAP;
258 src.u.pixmap = opt->cache;
260 twin_composite(px, opt->box.left, opt->box.top,
261 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
262 opt->box.right - opt->box.left,
263 opt->box.bottom - opt->box.top);
267 twin_path_destroy(path);
270 static twin_time_t pboot_rfocus_timeout (twin_time_t now, void *closure)
272 int dir = 1, dist, pos;
273 const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 2, 3, 4, 5 };
275 dist = abs(pboot_rpane->focus_target - pboot_rpane->focus_start);
276 dir = dist > 5 ? 5 : dist;
277 pos = pboot_rpane->focus_target - (int)pboot_rpane->focus_box.top;
285 twin_window_damage(pboot_rpane->window,
286 pboot_rpane->focus_box.left,
287 pboot_rpane->focus_box.top,
288 pboot_rpane->focus_box.right,
289 pboot_rpane->focus_box.bottom);
291 pboot_rpane->focus_box.top += dir;
292 pboot_rpane->focus_box.bottom += dir;
294 twin_window_damage(pboot_rpane->window,
295 pboot_rpane->focus_box.left,
296 pboot_rpane->focus_box.top,
297 pboot_rpane->focus_box.right,
298 pboot_rpane->focus_box.bottom);
300 twin_window_queue_paint(pboot_rpane->window);
302 return accel[(pos * 10) / dist];
305 static void pboot_set_rfocus(int index)
309 if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
311 dev = pboot_devices[pboot_dev_sel];
312 if (index < 0 || index >= dev->option_count)
315 pboot_rpane->focus_start = pboot_rpane->focus_box.top;
316 pboot_rpane->focus_target = PBOOT_RIGHT_FOCUS_YOFF +
317 PBOOT_RIGHT_OPTION_STRIDE * index;
318 pboot_rpane->focus_curindex = index;
320 twin_set_timeout(pboot_rfocus_timeout, 0, NULL);
323 static void pboot_select_rpane(void)
325 if (pboot_focus_lpane == 0)
327 pboot_focus_lpane = 0;
329 twin_screen_set_active(pboot_screen, pboot_rpane->window->pixmap);
331 twin_window_damage(pboot_lpane->window,
332 pboot_lpane->focus_box.left,
333 pboot_lpane->focus_box.top,
334 pboot_lpane->focus_box.right,
335 pboot_lpane->focus_box.bottom);
337 twin_window_damage(pboot_rpane->window,
338 pboot_rpane->focus_box.left,
339 pboot_rpane->focus_box.top,
340 pboot_rpane->focus_box.right,
341 pboot_rpane->focus_box.bottom);
343 twin_window_queue_paint(pboot_lpane->window);
344 twin_window_queue_paint(pboot_rpane->window);
349 static void pboot_select_lpane(void)
351 if (pboot_focus_lpane == 1)
353 pboot_focus_lpane = 1;
355 twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
357 twin_window_damage(pboot_lpane->window,
358 pboot_lpane->focus_box.left,
359 pboot_lpane->focus_box.top,
360 pboot_lpane->focus_box.right,
361 pboot_lpane->focus_box.bottom);
363 twin_window_damage(pboot_rpane->window,
364 pboot_rpane->focus_box.left,
365 pboot_rpane->focus_box.top,
366 pboot_rpane->focus_box.right,
367 pboot_rpane->focus_box.bottom);
369 twin_window_queue_paint(pboot_lpane->window);
370 twin_window_queue_paint(pboot_rpane->window);
373 static void pboot_rpane_mousetrack(twin_coord_t x, twin_coord_t y)
379 if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
381 dev = pboot_devices[pboot_dev_sel];
383 if (y < PBOOT_RIGHT_OPTION_TMARGIN)
385 candidate = (y - PBOOT_RIGHT_OPTION_TMARGIN) /
386 PBOOT_RIGHT_OPTION_STRIDE;
387 if (candidate >= dev->option_count) {
391 if (candidate == pboot_rpane->mouse_target)
393 opt = &dev->options[candidate];
394 if (x < opt->box.left || x > opt->box.right ||
395 y < opt->box.top || y > opt->box.bottom) {
400 /* Ok, so now, we know the mouse hit an icon that wasn't the same
401 * as the previous one, we trigger a focus change
403 pboot_set_rfocus(candidate);
406 pboot_rpane->mouse_target = candidate;
409 static void pboot_choose_option(void)
411 pboot_device_t *dev = pboot_devices[pboot_dev_sel];
412 pboot_option_t *opt = &dev->options[pboot_rpane->focus_curindex];
414 LOG("Selected device %s\n", opt->title);
416 /* Give user feedback, make sure errors and panics will be seen */
417 pboot_exec_option(opt->data);
420 static twin_bool_t pboot_rpane_event (twin_window_t *window,
423 /* filter out all mouse events */
424 switch(event->kind) {
426 case TwinEventMotion:
428 pboot_select_rpane();
429 pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
431 case TwinEventButtonDown:
432 pboot_select_rpane();
433 pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
434 pboot_choose_option();
435 case TwinEventButtonUp:
437 case TwinEventKeyDown:
438 switch(event->u.key.key) {
440 pboot_set_rfocus(pboot_rpane->focus_curindex - 1);
443 pboot_set_rfocus(pboot_rpane->focus_curindex + 1);
446 pboot_select_lpane();
449 pboot_choose_option();
461 int pboot_add_option(int devindex, const char *title,
462 const char *subtitle, twin_pixmap_t *badge, void *data)
469 if (devindex < 0 || devindex >= pboot_dev_count)
471 dev = pboot_devices[devindex];
473 if (dev->option_count >= PBOOT_MAX_OPTION)
475 index = dev->option_count++;
476 opt = &dev->options[index];
478 opt->title = malloc(strlen(title) + 1);
479 strcpy(opt->title, title);
482 opt->subtitle = malloc(strlen(subtitle) + 1);
483 strcpy(opt->subtitle, subtitle);
485 opt->subtitle = NULL;
490 width = pboot_rpane->window->pixmap->width -
491 (PBOOT_RIGHT_OPTION_LMARGIN + PBOOT_RIGHT_OPTION_RMARGIN);
493 opt->box.left = PBOOT_RIGHT_OPTION_LMARGIN;
494 opt->box.right = opt->box.left + width;
495 opt->box.top = PBOOT_RIGHT_OPTION_TMARGIN +
496 index * PBOOT_RIGHT_OPTION_STRIDE;
497 opt->box.bottom = opt->box.top + PBOOT_RIGHT_OPTION_HEIGHT;
504 static void pboot_set_device_select(int sel)
506 LOG("%s: %d -> %d\n", __FUNCTION__, pboot_dev_sel, sel);
507 if (sel == pboot_dev_sel || sel >= pboot_dev_count)
510 pboot_rpane->focus_curindex = -1;
511 pboot_rpane->mouse_target = -1;
512 pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
513 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
514 PBOOT_RIGHT_FOCUS_HEIGHT;
515 twin_window_damage(pboot_rpane->window, 0, 0,
516 pboot_rpane->window->pixmap->width,
517 pboot_rpane->window->pixmap->height);
518 twin_window_queue_paint(pboot_rpane->window);
521 static twin_time_t pboot_lfocus_timeout (twin_time_t now, void *closure)
523 int dir = 1, dist, pos;
524 const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 2, 3, 4, 5 };
526 dist = abs(pboot_lpane->focus_target - pboot_lpane->focus_start);
527 pos = pboot_lpane->focus_target - (int)pboot_lpane->focus_box.top;
529 pboot_set_device_select(pboot_lpane->focus_curindex);
536 twin_window_damage(pboot_lpane->window,
537 pboot_lpane->focus_box.left,
538 pboot_lpane->focus_box.top,
539 pboot_lpane->focus_box.right,
540 pboot_lpane->focus_box.bottom);
542 pboot_lpane->focus_box.top += dir;
543 pboot_lpane->focus_box.bottom += dir;
545 twin_window_damage(pboot_lpane->window,
546 pboot_lpane->focus_box.left,
547 pboot_lpane->focus_box.top,
548 pboot_lpane->focus_box.right,
549 pboot_lpane->focus_box.bottom);
551 twin_window_queue_paint(pboot_lpane->window);
553 return accel[(pos * 10) / dist];
556 static void pboot_set_lfocus(int index)
558 if (index >= pboot_dev_count)
561 pboot_lpane->focus_start = pboot_lpane->focus_box.top;
564 pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
566 pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF +
567 PBOOT_LEFT_ICON_STRIDE * index;
569 pboot_lpane->focus_curindex = index;
571 twin_set_timeout(pboot_lfocus_timeout, 0, NULL);
574 static void pboot_lpane_mousetrack(twin_coord_t x, twin_coord_t y)
577 twin_coord_t icon_top;
579 if (x < PBOOT_LEFT_ICON_XOFF ||
580 x > (PBOOT_LEFT_ICON_XOFF + PBOOT_LEFT_ICON_WIDTH))
582 if (y < PBOOT_LEFT_ICON_YOFF)
584 candidate = (y - PBOOT_LEFT_ICON_YOFF) / PBOOT_LEFT_ICON_STRIDE;
585 if (candidate >= pboot_dev_count) {
589 if (candidate == pboot_lpane->mouse_target)
591 icon_top = PBOOT_LEFT_ICON_YOFF +
592 candidate * PBOOT_LEFT_ICON_STRIDE;
593 if (y > (icon_top + PBOOT_LEFT_ICON_HEIGHT)) {
598 /* Ok, so now, we know the mouse hit an icon that wasn't the same
599 * as the previous one, we trigger a focus change
601 pboot_set_lfocus(candidate);
604 pboot_lpane->mouse_target = candidate;
607 static twin_bool_t pboot_lpane_event (twin_window_t *window,
610 /* filter out all mouse events */
611 switch(event->kind) {
613 case TwinEventMotion:
615 pboot_select_lpane();
616 pboot_lpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
618 case TwinEventButtonDown:
619 case TwinEventButtonUp:
621 case TwinEventKeyDown:
622 switch(event->u.key.key) {
624 if (pboot_lpane->focus_curindex > 0)
626 pboot_lpane->focus_curindex - 1);
629 pboot_set_lfocus(pboot_lpane->focus_curindex + 1);
632 pboot_select_rpane();
644 twin_bool_t pboot_event_filter(twin_screen_t *screen,
647 switch(event->kind) {
649 case TwinEventMotion:
651 case TwinEventButtonDown:
652 case TwinEventButtonUp:
653 if (pboot_cursor != NULL)
654 twin_screen_set_cursor(pboot_screen, pboot_cursor,
658 case TwinEventKeyDown:
660 twin_screen_set_cursor(pboot_screen, NULL, 0, 0);
668 static void pboot_lpane_draw(twin_window_t *window)
670 twin_pixmap_t *px = window->pixmap;
671 pboot_lpane_t *lpane = window->client_data;
673 twin_fixed_t x, y, w, h;
676 /* Fill background */
677 twin_fill(px, PBOOT_LEFT_PANE_COLOR, TWIN_SOURCE,
678 0, 0, px->width, px->height);
680 /* Create a path for use later */
681 path = twin_path_create();
684 /* Draw right line if needed */
685 if (px->clip.right > (PBOOT_LEFT_PANE_SIZE - 4)) {
686 x = twin_int_to_fixed(PBOOT_LEFT_PANE_SIZE - 4);
687 y = twin_int_to_fixed(px->height);
688 twin_path_rectangle(path, x, 0, 0x40000, y);
689 twin_paint_path(px, PBOOT_LEFT_LINE_COLOR, path);
690 twin_path_empty(path);
694 if (lpane->focus_curindex >= 0 &&
695 twin_rect_intersect(lpane->focus_box, px->clip)) {
696 x = twin_int_to_fixed(lpane->focus_box.left + 2);
697 y = twin_int_to_fixed(lpane->focus_box.top + 2);
698 w = twin_int_to_fixed(lpane->focus_box.right -
699 lpane->focus_box.left - 4);
700 h = twin_int_to_fixed(lpane->focus_box.bottom -
701 lpane->focus_box.top - 4);
702 twin_path_rounded_rectangle(path, x, y, w, h,
703 PBOOT_LEFT_FOCUS_XRAD,
704 PBOOT_LEFT_FOCUS_YRAD);
705 if (pboot_focus_lpane)
706 twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
708 twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
713 for (i = 0; i < pboot_dev_count; i++) {
714 pboot_device_t *dev = pboot_devices[i];
717 if (!twin_rect_intersect(dev->box, px->clip))
720 src.source_kind = TWIN_PIXMAP;
721 src.u.pixmap = dev->badge;
723 twin_composite(px, dev->box.left, dev->box.top,
724 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
725 dev->box.right - dev->box.left,
726 dev->box.bottom - dev->box.top);
731 twin_path_destroy(path);
734 static void pboot_create_panels(void)
737 pboot_lpane = calloc(1, sizeof(pboot_lpane_t));
740 pboot_lpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
742 0, 0, PBOOT_LEFT_PANE_SIZE,
743 pboot_screen->height);
744 assert(pboot_lpane->window);
746 pboot_lpane->window->draw = pboot_lpane_draw;
747 pboot_lpane->window->event = pboot_lpane_event;
748 pboot_lpane->window->client_data = pboot_lpane;
749 pboot_lpane->focus_curindex = -1;
750 pboot_lpane->focus_box.left = PBOOT_LEFT_FOCUS_XOFF;
751 pboot_lpane->focus_box.top = -2*PBOOT_LEFT_FOCUS_HEIGHT;
752 pboot_lpane->focus_box.right = pboot_lpane->focus_box.left +
753 PBOOT_LEFT_FOCUS_WIDTH;
754 pboot_lpane->focus_box.bottom = pboot_lpane->focus_box.top +
755 PBOOT_LEFT_FOCUS_HEIGHT;
756 pboot_lpane->mouse_target = -1;
757 twin_window_show(pboot_lpane->window);
760 pboot_rpane = calloc(1, sizeof(pboot_rpane_t));
763 pboot_rpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
765 PBOOT_LEFT_PANE_SIZE, 0,
766 pboot_screen->width -
767 PBOOT_LEFT_PANE_SIZE,
768 pboot_screen->height);
769 assert(pboot_rpane->window);
771 pboot_rpane->window->draw = pboot_rpane_draw;
772 pboot_rpane->window->event = pboot_rpane_event;
773 pboot_rpane->window->client_data = pboot_rpane;
775 pboot_rpane->focus_curindex = -1;
776 pboot_rpane->focus_box.left = PBOOT_RIGHT_FOCUS_XOFF;
777 pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
778 pboot_rpane->focus_box.right = pboot_rpane->window->pixmap->width -
779 2 * PBOOT_RIGHT_FOCUS_XOFF;
780 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
781 PBOOT_RIGHT_FOCUS_HEIGHT;
782 pboot_rpane->mouse_target = -1;
783 twin_window_show(pboot_rpane->window);
786 int pboot_add_device(const char *dev_id, const char *name,
787 twin_pixmap_t *pixmap)
792 if (pboot_dev_count >= PBOOT_MAX_DEV)
795 index = pboot_dev_count++;
797 dev = malloc(sizeof(*dev));
798 memset(dev, 0, sizeof(*dev));
799 dev->id = malloc(strlen(dev_id) + 1);
800 strcpy(dev->id, dev_id);
802 dev->box.left = PBOOT_LEFT_ICON_XOFF;
803 dev->box.right = dev->box.left + PBOOT_LEFT_ICON_WIDTH;
804 dev->box.top = PBOOT_LEFT_ICON_YOFF +
805 PBOOT_LEFT_ICON_STRIDE * index;
806 dev->box.bottom = dev->box.top + PBOOT_LEFT_ICON_HEIGHT;
808 pboot_devices[index] = dev;
810 twin_window_damage(pboot_lpane->window,
811 dev->box.left, dev->box.top,
812 dev->box.right, dev->box.bottom);
813 twin_window_queue_paint(pboot_lpane->window);
818 int pboot_remove_device(const char *dev_id)
820 int i, new_dev_index;
821 pboot_device_t *dev = NULL;
823 /* find the matching device */
824 for (i = 0; i < pboot_dev_count; i++) {
825 if (!strcmp(pboot_devices[i]->id, dev_id)) {
826 dev = pboot_devices[i];
834 /* select the newly-focussed device */
835 if (i == pboot_dev_count - 1)
836 new_dev_index = i - 1;
838 new_dev_index = i + 1;
840 memmove(pboot_devices + i, pboot_devices + i + 1,
841 sizeof(*pboot_devices) * (pboot_dev_count + i - 1));
843 pboot_devices[--pboot_dev_count] = NULL;
845 pboot_set_device_select(new_dev_index);
846 twin_window_damage(pboot_lpane->window,
847 dev->box.left, dev->box.top,
848 dev->box.right, dev->box.bottom);
849 twin_window_queue_paint(pboot_lpane->window);
851 /* todo: free device & options */
856 static void exitfunc(void)
860 twin_fbdev_destroy(pboot_fbdev);
865 static void sigint(int sig)
871 int main(int argc, char **argv)
874 const char *background_path;
877 signal(SIGINT, sigint);
880 pboot_x11 = twin_x11_create(XOpenDisplay(0), 1024, 768);
881 if (pboot_x11 == NULL) {
882 perror("failed to create x11 screen !\n");
885 pboot_screen = pboot_x11->screen;
887 /* Create screen and mouse drivers */
888 pboot_fbdev = twin_fbdev_create(-1, SIGUSR1);
889 if (pboot_fbdev == NULL) {
890 perror("failed to create fbdev screen !\n");
893 pboot_screen = pboot_fbdev->screen;
894 twin_linux_mouse_create(NULL, pboot_screen);
896 if (pboot_fbdev != NULL) {
897 char *cursor_path = artwork_pathname("cursor");
898 pboot_cursor = twin_load_X_cursor(cursor_path, 2,
901 if (pboot_cursor == NULL)
903 twin_get_default_cursor(&pboot_cursor_hx,
908 /* Set background pixmap */
909 background_path = artwork_pathname("background.png");
910 LOG("loading background: %s...", background_path);
911 pic = twin_png_to_pixmap(background_path, TWIN_ARGB32);
912 LOG("%s\n", pic ? "ok" : "failed");
914 twin_screen_set_background(pboot_screen, pic);
916 /* Init more stuffs */
917 pboot_create_panels();
918 twin_window_queue_paint(pboot_lpane->window);
919 twin_window_queue_paint(pboot_rpane->window);
921 if (!pboot_start_device_discovery()) {
922 LOG("Couldn't start device discovery!\n");
927 twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
928 pboot_screen->event_filter = pboot_event_filter;
933 twin_fbdev_activate(pboot_fbdev);