8 #include <linux/input.h>
10 #include <libtwin/twin.h>
11 #include <libtwin/twin_fbdev.h>
12 #include <libtwin/twin_x11.h>
13 #include <libtwin/twin_linux_mouse.h>
14 #include <libtwin/twin_png.h>
16 #include "petitboot.h"
17 #include "petitboot-paths.h"
21 static twin_fbdev_t *pboot_fbdev;
22 static twin_x11_t *pboot_x11;
23 static twin_screen_t *pboot_screen;
25 #define PBOOT_LEFT_PANE_SIZE 200
26 #define PBOOT_LEFT_PANE_COLOR 0x80000000
27 #define PBOOT_LEFT_LINE_COLOR 0xff000000
29 #define PBOOT_LEFT_FOCUS_WIDTH 80
30 #define PBOOT_LEFT_FOCUS_HEIGHT 80
31 #define PBOOT_LEFT_FOCUS_XOFF 60
32 #define PBOOT_LEFT_FOCUS_YOFF 60
33 #define PBOOT_LEFT_FOCUS_XRAD (6 * TWIN_FIXED_ONE)
34 #define PBOOT_LEFT_FOCUS_YRAD (6 * TWIN_FIXED_ONE)
36 #define PBOOT_RIGHT_FOCUS_XOFF 20
37 #define PBOOT_RIGHT_FOCUS_YOFF 60
38 #define PBOOT_RIGHT_FOCUS_HEIGHT 80
39 #define PBOOT_RIGHT_FOCUS_XRAD (6 * TWIN_FIXED_ONE)
40 #define PBOOT_RIGHT_FOCUS_YRAD (6 * TWIN_FIXED_ONE)
42 #define PBOOT_LEFT_ICON_WIDTH 64
43 #define PBOOT_LEFT_ICON_HEIGHT 64
44 #define PBOOT_LEFT_ICON_XOFF 70
45 #define PBOOT_LEFT_ICON_YOFF 70
46 #define PBOOT_LEFT_ICON_STRIDE 100
48 #define PBOOT_RIGHT_OPTION_LMARGIN 30
49 #define PBOOT_RIGHT_OPTION_RMARGIN 30
50 #define PBOOT_RIGHT_OPTION_TMARGIN 70
51 #define PBOOT_RIGHT_OPTION_HEIGHT 64
52 #define PBOOT_RIGHT_OPTION_STRIDE 100
53 #define PBOOT_RIGHT_TITLE_TEXT_SIZE (30 * TWIN_FIXED_ONE)
54 #define PBOOT_RIGHT_SUBTITLE_TEXT_SIZE (18 * TWIN_FIXED_ONE)
55 #define PBOOT_RIGHT_TITLE_XOFFSET 80
56 #define PBOOT_RIGHT_TITLE_YOFFSET 30
57 #define PBOOT_RIGHT_SUBTITLE_XOFFSET 200
58 #define PBOOT_RIGHT_SUBTITLE_YOFFSET 50
59 #define PBOOT_RIGHT_BADGE_XOFFSET 2
60 #define PBOOT_RIGHT_BADGE_YOFFSET 0
63 #define PBOOT_RIGHT_TITLE_COLOR 0xff000000
64 #define PBOOT_RIGHT_SUBTITLE_COLOR 0xff400000
66 #define PBOOT_FOCUS_COLOR 0x10404040
69 typedef struct _pboot_option pboot_option_t;
70 typedef struct _pboot_device pboot_device_t;
88 pboot_option_t options[PBOOT_MAX_OPTION];
91 static twin_pixmap_t *pboot_cursor;
92 static int pboot_cursor_hx;
93 static int pboot_cursor_hy;
95 static pboot_device_t *pboot_devices[PBOOT_MAX_DEV];
96 static int pboot_dev_count;
97 static int pboot_dev_sel = -1;
98 static int pboot_focus_lpane = 1;
100 typedef struct _pboot_lpane {
101 twin_window_t *window;
102 twin_rect_t focus_box;
109 typedef struct _pboot_rpane {
110 twin_window_t *window;
111 twin_rect_t focus_box;
118 static pboot_lpane_t *pboot_lpane;
119 static pboot_rpane_t *pboot_rpane;
121 /* XXX move to twin */
122 static inline twin_bool_t twin_rect_intersect(twin_rect_t r1,
125 return !(r1.left > r2.right ||
126 r1.right < r2.left ||
127 r1.top > r2.bottom ||
131 static void pboot_draw_option_cache(pboot_device_t *dev, pboot_option_t *opt,
139 px = twin_pixmap_create(TWIN_ARGB32, opt->box.right - opt->box.left,
140 opt->box.bottom - opt->box.top);
144 /* Fill background */
145 twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
147 /* Allocate a path for drawing */
148 path = twin_path_create();
152 /* TEST - Bounding rectangle */
153 twin_path_rectangle(path, 0, 0,
154 twin_int_to_fixed(px->width),
155 twin_int_to_fixed(px->height));
156 twin_paint_path(px, PBOOT_RIGHT_TITLE_COLOR, path);
157 twin_path_empty(path);
158 twin_fill(px, 0x00000000, TWIN_SOURCE, 2, 2,
159 px->width - 3, px->height - 3);
163 twin_path_set_font_size(path, PBOOT_RIGHT_TITLE_TEXT_SIZE);
164 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
165 tx = twin_int_to_fixed(PBOOT_RIGHT_TITLE_XOFFSET);
166 ty = twin_int_to_fixed(PBOOT_RIGHT_TITLE_YOFFSET);
167 twin_path_move (path, tx, ty);
168 twin_path_utf8 (path, opt->title);
169 twin_paint_path (px, PBOOT_RIGHT_TITLE_COLOR, path);
170 twin_path_empty (path);
173 twin_path_set_font_size(path, PBOOT_RIGHT_SUBTITLE_TEXT_SIZE);
174 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
175 tx = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_XOFFSET);
176 ty = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_YOFFSET);
177 twin_path_move (path, tx, ty);
178 twin_path_utf8 (path, opt->subtitle);
179 twin_paint_path (px, PBOOT_RIGHT_SUBTITLE_COLOR, path);
180 twin_path_empty (path);
186 src.source_kind = TWIN_PIXMAP;
187 src.u.pixmap = opt->badge;
189 twin_composite(px, PBOOT_RIGHT_BADGE_XOFFSET,
190 PBOOT_RIGHT_BADGE_YOFFSET,
191 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
192 opt->badge->width, opt->badge->height);
197 twin_path_destroy(path);
200 static void pboot_rpane_draw(twin_window_t *window)
202 twin_pixmap_t *px = window->pixmap;
203 pboot_rpane_t *rpane = window->client_data;
206 twin_fixed_t x, y, w, h;
209 /* Fill background */
210 twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
212 /* Nothing to draw, return */
213 if (pboot_dev_sel < 0)
216 /* Create a path for use later */
217 path = twin_path_create();
221 if (rpane->focus_curindex >= 0 &&
222 twin_rect_intersect(rpane->focus_box, px->clip)) {
223 x = twin_int_to_fixed(rpane->focus_box.left + 2);
224 y = twin_int_to_fixed(rpane->focus_box.top + 2);
225 w = twin_int_to_fixed(rpane->focus_box.right -
226 rpane->focus_box.left - 4);
227 h = twin_int_to_fixed(rpane->focus_box.bottom -
228 rpane->focus_box.top - 4);
229 twin_path_rounded_rectangle(path, x, y, w, h,
230 PBOOT_RIGHT_FOCUS_XRAD,
231 PBOOT_RIGHT_FOCUS_YRAD);
232 if (!pboot_focus_lpane)
233 twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
235 twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
239 /* Get device and iterate through options */
240 dev = pboot_devices[pboot_dev_sel];
241 for (i = 0; i < dev->option_count; i++) {
242 pboot_option_t *opt = &dev->options[i];
245 if (opt->title == NULL)
247 if (!twin_rect_intersect(opt->box, px->clip))
249 if (opt->cache == NULL)
250 pboot_draw_option_cache(dev, opt, i);
252 src.source_kind = TWIN_PIXMAP;
253 src.u.pixmap = opt->cache;
255 twin_composite(px, opt->box.left, opt->box.top,
256 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
257 opt->box.right - opt->box.left,
258 opt->box.bottom - opt->box.top);
262 twin_path_destroy(path);
265 static twin_time_t pboot_rfocus_timeout (twin_time_t now, void *closure)
267 int dir = 1, dist, pos;
268 const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 2, 3, 4, 5 };
270 dist = abs(pboot_rpane->focus_target - pboot_rpane->focus_start);
271 dir = dist > 5 ? 5 : dist;
272 pos = pboot_rpane->focus_target - (int)pboot_rpane->focus_box.top;
280 twin_window_damage(pboot_rpane->window,
281 pboot_rpane->focus_box.left,
282 pboot_rpane->focus_box.top,
283 pboot_rpane->focus_box.right,
284 pboot_rpane->focus_box.bottom);
286 pboot_rpane->focus_box.top += dir;
287 pboot_rpane->focus_box.bottom += dir;
289 twin_window_damage(pboot_rpane->window,
290 pboot_rpane->focus_box.left,
291 pboot_rpane->focus_box.top,
292 pboot_rpane->focus_box.right,
293 pboot_rpane->focus_box.bottom);
295 twin_window_queue_paint(pboot_rpane->window);
297 return accel[(pos * 10) / dist];
300 static void pboot_set_rfocus(int index)
304 if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
306 dev = pboot_devices[pboot_dev_sel];
307 if (index < 0 || index >= dev->option_count)
310 pboot_rpane->focus_start = pboot_rpane->focus_box.top;
311 pboot_rpane->focus_target = PBOOT_RIGHT_FOCUS_YOFF +
312 PBOOT_RIGHT_OPTION_STRIDE * index;
313 pboot_rpane->focus_curindex = index;
315 twin_set_timeout(pboot_rfocus_timeout, 0, NULL);
318 static void pboot_select_rpane(void)
320 if (pboot_focus_lpane == 0)
322 pboot_focus_lpane = 0;
324 twin_screen_set_active(pboot_screen, pboot_rpane->window->pixmap);
326 twin_window_damage(pboot_lpane->window,
327 pboot_lpane->focus_box.left,
328 pboot_lpane->focus_box.top,
329 pboot_lpane->focus_box.right,
330 pboot_lpane->focus_box.bottom);
332 twin_window_damage(pboot_rpane->window,
333 pboot_rpane->focus_box.left,
334 pboot_rpane->focus_box.top,
335 pboot_rpane->focus_box.right,
336 pboot_rpane->focus_box.bottom);
338 twin_window_queue_paint(pboot_lpane->window);
339 twin_window_queue_paint(pboot_rpane->window);
344 static void pboot_select_lpane(void)
346 if (pboot_focus_lpane == 1)
348 pboot_focus_lpane = 1;
350 twin_screen_set_active(pboot_screen, pboot_lpane->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);
368 static void pboot_rpane_mousetrack(twin_coord_t x, twin_coord_t y)
374 if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
376 dev = pboot_devices[pboot_dev_sel];
378 if (y < PBOOT_RIGHT_OPTION_TMARGIN)
380 candidate = (y - PBOOT_RIGHT_OPTION_TMARGIN) /
381 PBOOT_RIGHT_OPTION_STRIDE;
382 if (candidate >= dev->option_count) {
386 if (candidate == pboot_rpane->mouse_target)
388 opt = &dev->options[candidate];
389 if (x < opt->box.left || x > opt->box.right ||
390 y < opt->box.top || y > opt->box.bottom) {
395 /* Ok, so now, we know the mouse hit an icon that wasn't the same
396 * as the previous one, we trigger a focus change
398 pboot_set_rfocus(candidate);
401 pboot_rpane->mouse_target = candidate;
404 static void pboot_choose_option(void)
406 pboot_device_t *dev = pboot_devices[pboot_dev_sel];
407 pboot_option_t *opt = &dev->options[pboot_rpane->focus_curindex];
409 LOG("Selected device %s\n", opt->title);
411 /* Give user feedback, make sure errors and panics will be seen */
412 pboot_exec_option(opt->data);
415 static twin_bool_t pboot_rpane_event (twin_window_t *window,
418 /* filter out all mouse events */
419 switch(event->kind) {
421 case TwinEventMotion:
423 pboot_select_rpane();
424 pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
426 case TwinEventButtonDown:
427 pboot_select_rpane();
428 pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
429 pboot_choose_option();
430 case TwinEventButtonUp:
432 case TwinEventKeyDown:
433 switch(event->u.key.key) {
435 pboot_set_rfocus(pboot_rpane->focus_curindex - 1);
438 pboot_set_rfocus(pboot_rpane->focus_curindex + 1);
441 pboot_select_lpane();
444 pboot_choose_option();
456 int pboot_add_option(int devindex, const char *title,
457 const char *subtitle, twin_pixmap_t *badge, void *data)
464 if (devindex < 0 || devindex >= pboot_dev_count)
466 dev = pboot_devices[devindex];
468 if (dev->option_count >= PBOOT_MAX_OPTION)
470 index = dev->option_count++;
471 opt = &dev->options[index];
473 opt->title = malloc(strlen(title) + 1);
474 strcpy(opt->title, title);
477 opt->subtitle = malloc(strlen(subtitle) + 1);
478 strcpy(opt->subtitle, subtitle);
480 opt->subtitle = NULL;
485 width = pboot_rpane->window->pixmap->width -
486 (PBOOT_RIGHT_OPTION_LMARGIN + PBOOT_RIGHT_OPTION_RMARGIN);
488 opt->box.left = PBOOT_RIGHT_OPTION_LMARGIN;
489 opt->box.right = opt->box.left + width;
490 opt->box.top = PBOOT_RIGHT_OPTION_TMARGIN +
491 index * PBOOT_RIGHT_OPTION_STRIDE;
492 opt->box.bottom = opt->box.top + PBOOT_RIGHT_OPTION_HEIGHT;
499 static void pboot_set_device_select(int sel)
501 LOG("%s: %d -> %d\n", __FUNCTION__, pboot_dev_sel, sel);
502 if (sel == pboot_dev_sel || sel >= pboot_dev_count)
505 pboot_rpane->focus_curindex = -1;
506 pboot_rpane->mouse_target = -1;
507 pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
508 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
509 PBOOT_RIGHT_FOCUS_HEIGHT;
510 twin_window_damage(pboot_rpane->window, 0, 0,
511 pboot_rpane->window->pixmap->width,
512 pboot_rpane->window->pixmap->height);
513 twin_window_queue_paint(pboot_rpane->window);
516 static twin_time_t pboot_lfocus_timeout (twin_time_t now, void *closure)
518 int dir = 1, dist, pos;
519 const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 2, 3, 4, 5 };
521 dist = abs(pboot_lpane->focus_target - pboot_lpane->focus_start);
522 pos = pboot_lpane->focus_target - (int)pboot_lpane->focus_box.top;
524 pboot_set_device_select(pboot_lpane->focus_curindex);
531 twin_window_damage(pboot_lpane->window,
532 pboot_lpane->focus_box.left,
533 pboot_lpane->focus_box.top,
534 pboot_lpane->focus_box.right,
535 pboot_lpane->focus_box.bottom);
537 pboot_lpane->focus_box.top += dir;
538 pboot_lpane->focus_box.bottom += dir;
540 twin_window_damage(pboot_lpane->window,
541 pboot_lpane->focus_box.left,
542 pboot_lpane->focus_box.top,
543 pboot_lpane->focus_box.right,
544 pboot_lpane->focus_box.bottom);
546 twin_window_queue_paint(pboot_lpane->window);
548 return accel[(pos * 10) / dist];
551 static void pboot_set_lfocus(int index)
553 if (index >= pboot_dev_count)
556 pboot_lpane->focus_start = pboot_lpane->focus_box.top;
559 pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
561 pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF +
562 PBOOT_LEFT_ICON_STRIDE * index;
564 pboot_lpane->focus_curindex = index;
566 twin_set_timeout(pboot_lfocus_timeout, 0, NULL);
569 static void pboot_lpane_mousetrack(twin_coord_t x, twin_coord_t y)
572 twin_coord_t icon_top;
574 if (x < PBOOT_LEFT_ICON_XOFF ||
575 x > (PBOOT_LEFT_ICON_XOFF + PBOOT_LEFT_ICON_WIDTH))
577 if (y < PBOOT_LEFT_ICON_YOFF)
579 candidate = (y - PBOOT_LEFT_ICON_YOFF) / PBOOT_LEFT_ICON_STRIDE;
580 if (candidate >= pboot_dev_count) {
584 if (candidate == pboot_lpane->mouse_target)
586 icon_top = PBOOT_LEFT_ICON_YOFF +
587 candidate * PBOOT_LEFT_ICON_STRIDE;
588 if (y > (icon_top + PBOOT_LEFT_ICON_HEIGHT)) {
593 /* Ok, so now, we know the mouse hit an icon that wasn't the same
594 * as the previous one, we trigger a focus change
596 pboot_set_lfocus(candidate);
599 pboot_lpane->mouse_target = candidate;
602 static twin_bool_t pboot_lpane_event (twin_window_t *window,
605 /* filter out all mouse events */
606 switch(event->kind) {
608 case TwinEventMotion:
610 pboot_select_lpane();
611 pboot_lpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
613 case TwinEventButtonDown:
614 case TwinEventButtonUp:
616 case TwinEventKeyDown:
617 switch(event->u.key.key) {
619 if (pboot_lpane->focus_curindex > 0)
621 pboot_lpane->focus_curindex - 1);
624 pboot_set_lfocus(pboot_lpane->focus_curindex + 1);
627 pboot_select_rpane();
639 twin_bool_t pboot_event_filter(twin_screen_t *screen,
642 switch(event->kind) {
644 case TwinEventMotion:
646 case TwinEventButtonDown:
647 case TwinEventButtonUp:
648 if (pboot_cursor != NULL)
649 twin_screen_set_cursor(pboot_screen, pboot_cursor,
653 case TwinEventKeyDown:
655 twin_screen_set_cursor(pboot_screen, NULL, 0, 0);
663 static void pboot_lpane_draw(twin_window_t *window)
665 twin_pixmap_t *px = window->pixmap;
666 pboot_lpane_t *lpane = window->client_data;
668 twin_fixed_t x, y, w, h;
671 /* Fill background */
672 twin_fill(px, PBOOT_LEFT_PANE_COLOR, TWIN_SOURCE,
673 0, 0, px->width, px->height);
675 /* Create a path for use later */
676 path = twin_path_create();
679 /* Draw right line if needed */
680 if (px->clip.right > (PBOOT_LEFT_PANE_SIZE - 4)) {
681 x = twin_int_to_fixed(PBOOT_LEFT_PANE_SIZE - 4);
682 y = twin_int_to_fixed(px->height);
683 twin_path_rectangle(path, x, 0, 0x40000, y);
684 twin_paint_path(px, PBOOT_LEFT_LINE_COLOR, path);
685 twin_path_empty(path);
689 if (lpane->focus_curindex >= 0 &&
690 twin_rect_intersect(lpane->focus_box, px->clip)) {
691 x = twin_int_to_fixed(lpane->focus_box.left + 2);
692 y = twin_int_to_fixed(lpane->focus_box.top + 2);
693 w = twin_int_to_fixed(lpane->focus_box.right -
694 lpane->focus_box.left - 4);
695 h = twin_int_to_fixed(lpane->focus_box.bottom -
696 lpane->focus_box.top - 4);
697 twin_path_rounded_rectangle(path, x, y, w, h,
698 PBOOT_LEFT_FOCUS_XRAD,
699 PBOOT_LEFT_FOCUS_YRAD);
700 if (pboot_focus_lpane)
701 twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
703 twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
708 for (i = 0; i < pboot_dev_count; i++) {
709 pboot_device_t *dev = pboot_devices[i];
712 if (!twin_rect_intersect(dev->box, px->clip))
715 src.source_kind = TWIN_PIXMAP;
716 src.u.pixmap = dev->badge;
718 twin_composite(px, dev->box.left, dev->box.top,
719 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
720 dev->box.right - dev->box.left,
721 dev->box.bottom - dev->box.top);
726 twin_path_destroy(path);
729 static void pboot_create_panels(void)
732 pboot_lpane = calloc(1, sizeof(pboot_lpane_t));
735 pboot_lpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
737 0, 0, PBOOT_LEFT_PANE_SIZE,
738 pboot_screen->height);
739 assert(pboot_lpane->window);
741 pboot_lpane->window->draw = pboot_lpane_draw;
742 pboot_lpane->window->event = pboot_lpane_event;
743 pboot_lpane->window->client_data = pboot_lpane;
744 pboot_lpane->focus_curindex = -1;
745 pboot_lpane->focus_box.left = PBOOT_LEFT_FOCUS_XOFF;
746 pboot_lpane->focus_box.top = -2*PBOOT_LEFT_FOCUS_HEIGHT;
747 pboot_lpane->focus_box.right = pboot_lpane->focus_box.left +
748 PBOOT_LEFT_FOCUS_WIDTH;
749 pboot_lpane->focus_box.bottom = pboot_lpane->focus_box.top +
750 PBOOT_LEFT_FOCUS_HEIGHT;
751 pboot_lpane->mouse_target = -1;
752 twin_window_show(pboot_lpane->window);
755 pboot_rpane = calloc(1, sizeof(pboot_rpane_t));
758 pboot_rpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
760 PBOOT_LEFT_PANE_SIZE, 0,
761 pboot_screen->width -
762 PBOOT_LEFT_PANE_SIZE,
763 pboot_screen->height);
764 assert(pboot_rpane->window);
766 pboot_rpane->window->draw = pboot_rpane_draw;
767 pboot_rpane->window->event = pboot_rpane_event;
768 pboot_rpane->window->client_data = pboot_rpane;
770 pboot_rpane->focus_curindex = -1;
771 pboot_rpane->focus_box.left = PBOOT_RIGHT_FOCUS_XOFF;
772 pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
773 pboot_rpane->focus_box.right = pboot_rpane->window->pixmap->width -
774 2 * PBOOT_RIGHT_FOCUS_XOFF;
775 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
776 PBOOT_RIGHT_FOCUS_HEIGHT;
777 pboot_rpane->mouse_target = -1;
778 twin_window_show(pboot_rpane->window);
781 int pboot_add_device(const char *dev_id, const char *name,
782 twin_pixmap_t *pixmap)
787 if (pboot_dev_count >= PBOOT_MAX_DEV)
790 index = pboot_dev_count++;
792 dev = malloc(sizeof(*dev));
793 memset(dev, 0, sizeof(*dev));
794 dev->id = malloc(strlen(dev_id) + 1);
795 strcpy(dev->id, dev_id);
797 dev->box.left = PBOOT_LEFT_ICON_XOFF;
798 dev->box.right = dev->box.left + PBOOT_LEFT_ICON_WIDTH;
799 dev->box.top = PBOOT_LEFT_ICON_YOFF +
800 PBOOT_LEFT_ICON_STRIDE * index;
801 dev->box.bottom = dev->box.top + PBOOT_LEFT_ICON_HEIGHT;
803 pboot_devices[index] = dev;
805 twin_window_damage(pboot_lpane->window,
806 dev->box.left, dev->box.top,
807 dev->box.right, dev->box.bottom);
808 twin_window_queue_paint(pboot_lpane->window);
813 int pboot_remove_device(const char *dev_id)
815 int i, new_dev_index;
816 pboot_device_t *dev = NULL;
818 /* find the matching device */
819 for (i = 0; i < pboot_dev_count; i++) {
820 if (!strcmp(pboot_devices[i]->id, dev_id)) {
821 dev = pboot_devices[i];
829 /* select the newly-focussed device */
830 if (i == pboot_dev_count - 1)
831 new_dev_index = i - 1;
833 new_dev_index = i + 1;
835 memmove(pboot_devices + i, pboot_devices + i + 1,
836 sizeof(*pboot_devices) * (pboot_dev_count + i - 1));
838 pboot_devices[--pboot_dev_count] = NULL;
840 pboot_set_device_select(new_dev_index);
841 twin_window_damage(pboot_lpane->window,
842 dev->box.left, dev->box.top,
843 dev->box.right, dev->box.bottom);
844 twin_window_queue_paint(pboot_lpane->window);
846 /* todo: free device & options */
851 static void exitfunc(void)
854 twin_fbdev_destroy(pboot_fbdev);
858 static void sigint(int sig)
864 int main(int argc, char **argv)
867 const char *background_path;
870 signal(SIGINT, sigint);
873 pboot_x11 = twin_x11_create(XOpenDisplay(0), 1024, 768);
874 if (pboot_x11 == NULL) {
875 perror("failed to create x11 screen !\n");
878 pboot_screen = pboot_x11->screen;
880 /* Create screen and mouse drivers */
881 pboot_fbdev = twin_fbdev_create(-1, SIGUSR1);
882 if (pboot_fbdev == NULL) {
883 perror("failed to create fbdev screen !\n");
886 pboot_screen = pboot_fbdev->screen;
887 twin_linux_mouse_create(NULL, pboot_screen);
890 if (pboot_fbdev != NULL) {
891 char *cursor_path = artwork_pathname("cursor");
892 pboot_cursor = twin_load_X_cursor(cursor_path, 2,
895 if (pboot_cursor == NULL)
897 twin_get_default_cursor(&pboot_cursor_hx,
901 /* Set background pixmap */
902 background_path = artwork_pathname("background.png");
903 LOG("loading background: %s...", background_path);
904 pic = twin_png_to_pixmap(background_path, TWIN_ARGB32);
905 LOG("%s\n", pic ? "ok" : "failed");
907 twin_screen_set_background(pboot_screen, pic);
909 /* Init more stuffs */
910 pboot_create_panels();
911 twin_window_queue_paint(pboot_lpane->window);
912 twin_window_queue_paint(pboot_rpane->window);
914 if (!pboot_start_device_discovery()) {
915 LOG("Couldn't start device discovery!\n");
920 twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
921 pboot_screen->event_filter = pboot_event_filter;
925 twin_fbdev_activate(pboot_fbdev);