8 #include <linux/input.h>
12 #include <libtwin/twin.h>
13 #include <libtwin/twin_linux_mouse.h>
14 #include <libtwin/twin_png.h>
16 #include "petitboot.h"
17 #include "petitboot-paths.h"
20 #include <libtwin/twin_x11.h>
21 static twin_x11_t *pboot_x11;
23 #include <libtwin/twin_fbdev.h>
24 static twin_fbdev_t *pboot_fbdev;
27 static twin_screen_t *pboot_screen;
29 #define PBOOT_LEFT_PANE_SIZE 200
30 #define PBOOT_LEFT_PANE_COLOR 0x80000000
31 #define PBOOT_LEFT_LINE_COLOR 0xff000000
33 #define PBOOT_LEFT_FOCUS_WIDTH 80
34 #define PBOOT_LEFT_FOCUS_HEIGHT 80
35 #define PBOOT_LEFT_FOCUS_XOFF 60
36 #define PBOOT_LEFT_FOCUS_YOFF 60
37 #define PBOOT_LEFT_FOCUS_XRAD (6 * TWIN_FIXED_ONE)
38 #define PBOOT_LEFT_FOCUS_YRAD (6 * TWIN_FIXED_ONE)
40 #define PBOOT_RIGHT_FOCUS_XOFF 20
41 #define PBOOT_RIGHT_FOCUS_YOFF 60
42 #define PBOOT_RIGHT_FOCUS_HEIGHT 80
43 #define PBOOT_RIGHT_FOCUS_XRAD (6 * TWIN_FIXED_ONE)
44 #define PBOOT_RIGHT_FOCUS_YRAD (6 * TWIN_FIXED_ONE)
46 #define PBOOT_LEFT_ICON_WIDTH 64
47 #define PBOOT_LEFT_ICON_HEIGHT 64
48 #define PBOOT_LEFT_ICON_XOFF 70
49 #define PBOOT_LEFT_ICON_YOFF 70
50 #define PBOOT_LEFT_ICON_STRIDE 100
52 #define PBOOT_RIGHT_OPTION_LMARGIN 30
53 #define PBOOT_RIGHT_OPTION_RMARGIN 30
54 #define PBOOT_RIGHT_OPTION_TMARGIN 70
55 #define PBOOT_RIGHT_OPTION_HEIGHT 64
56 #define PBOOT_RIGHT_OPTION_STRIDE 100
57 #define PBOOT_RIGHT_TITLE_TEXT_SIZE (30 * TWIN_FIXED_ONE)
58 #define PBOOT_RIGHT_SUBTITLE_TEXT_SIZE (18 * TWIN_FIXED_ONE)
59 #define PBOOT_RIGHT_TITLE_XOFFSET 80
60 #define PBOOT_RIGHT_TITLE_YOFFSET 30
61 #define PBOOT_RIGHT_SUBTITLE_XOFFSET 200
62 #define PBOOT_RIGHT_SUBTITLE_YOFFSET 50
63 #define PBOOT_RIGHT_BADGE_XOFFSET 2
64 #define PBOOT_RIGHT_BADGE_YOFFSET 0
67 #define PBOOT_RIGHT_TITLE_COLOR 0xff000000
68 #define PBOOT_RIGHT_SUBTITLE_COLOR 0xff400000
70 #define PBOOT_FOCUS_COLOR 0x10404040
73 typedef struct _pboot_option pboot_option_t;
74 typedef struct _pboot_device pboot_device_t;
92 pboot_option_t options[PBOOT_MAX_OPTION];
95 static twin_pixmap_t *pboot_cursor;
96 static int pboot_cursor_hx;
97 static int pboot_cursor_hy;
99 static pboot_device_t *pboot_devices[PBOOT_MAX_DEV];
100 static int pboot_dev_count;
101 static int pboot_dev_sel = -1;
102 static int pboot_focus_lpane = 1;
104 typedef struct _pboot_lpane {
105 twin_window_t *window;
106 twin_rect_t focus_box;
113 typedef struct _pboot_rpane {
114 twin_window_t *window;
115 twin_rect_t focus_box;
122 static pboot_lpane_t *pboot_lpane;
123 static pboot_rpane_t *pboot_rpane;
125 /* XXX move to twin */
126 static inline twin_bool_t twin_rect_intersect(twin_rect_t r1,
129 return !(r1.left > r2.right ||
130 r1.right < r2.left ||
131 r1.top > r2.bottom ||
135 static void pboot_draw_option_cache(pboot_device_t *dev, pboot_option_t *opt,
143 px = twin_pixmap_create(TWIN_ARGB32, opt->box.right - opt->box.left,
144 opt->box.bottom - opt->box.top);
148 /* Fill background */
149 twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
151 /* Allocate a path for drawing */
152 path = twin_path_create();
156 /* TEST - Bounding rectangle */
157 twin_path_rectangle(path, 0, 0,
158 twin_int_to_fixed(px->width),
159 twin_int_to_fixed(px->height));
160 twin_paint_path(px, PBOOT_RIGHT_TITLE_COLOR, path);
161 twin_path_empty(path);
162 twin_fill(px, 0x00000000, TWIN_SOURCE, 2, 2,
163 px->width - 3, px->height - 3);
167 twin_path_set_font_size(path, PBOOT_RIGHT_TITLE_TEXT_SIZE);
168 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
169 tx = twin_int_to_fixed(PBOOT_RIGHT_TITLE_XOFFSET);
170 ty = twin_int_to_fixed(PBOOT_RIGHT_TITLE_YOFFSET);
171 twin_path_move (path, tx, ty);
172 twin_path_utf8 (path, opt->title);
173 twin_paint_path (px, PBOOT_RIGHT_TITLE_COLOR, path);
174 twin_path_empty (path);
177 twin_path_set_font_size(path, PBOOT_RIGHT_SUBTITLE_TEXT_SIZE);
178 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
179 tx = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_XOFFSET);
180 ty = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_YOFFSET);
181 twin_path_move (path, tx, ty);
182 twin_path_utf8 (path, opt->subtitle);
183 twin_paint_path (px, PBOOT_RIGHT_SUBTITLE_COLOR, path);
184 twin_path_empty (path);
190 src.source_kind = TWIN_PIXMAP;
191 src.u.pixmap = opt->badge;
193 twin_composite(px, PBOOT_RIGHT_BADGE_XOFFSET,
194 PBOOT_RIGHT_BADGE_YOFFSET,
195 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
196 opt->badge->width, opt->badge->height);
201 twin_path_destroy(path);
204 static void pboot_rpane_draw(twin_window_t *window)
206 twin_pixmap_t *px = window->pixmap;
207 pboot_rpane_t *rpane = window->client_data;
210 twin_fixed_t x, y, w, h;
213 /* Fill background */
214 twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
216 /* Nothing to draw, return */
217 if (pboot_dev_sel < 0)
220 /* Create a path for use later */
221 path = twin_path_create();
225 if (rpane->focus_curindex >= 0 &&
226 twin_rect_intersect(rpane->focus_box, px->clip)) {
227 x = twin_int_to_fixed(rpane->focus_box.left + 2);
228 y = twin_int_to_fixed(rpane->focus_box.top + 2);
229 w = twin_int_to_fixed(rpane->focus_box.right -
230 rpane->focus_box.left - 4);
231 h = twin_int_to_fixed(rpane->focus_box.bottom -
232 rpane->focus_box.top - 4);
233 twin_path_rounded_rectangle(path, x, y, w, h,
234 PBOOT_RIGHT_FOCUS_XRAD,
235 PBOOT_RIGHT_FOCUS_YRAD);
236 if (!pboot_focus_lpane)
237 twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
239 twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
243 /* Get device and iterate through options */
244 dev = pboot_devices[pboot_dev_sel];
245 for (i = 0; i < dev->option_count; i++) {
246 pboot_option_t *opt = &dev->options[i];
249 if (opt->title == NULL)
251 if (!twin_rect_intersect(opt->box, px->clip))
253 if (opt->cache == NULL)
254 pboot_draw_option_cache(dev, opt, i);
256 src.source_kind = TWIN_PIXMAP;
257 src.u.pixmap = opt->cache;
259 twin_composite(px, opt->box.left, opt->box.top,
260 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
261 opt->box.right - opt->box.left,
262 opt->box.bottom - opt->box.top);
266 twin_path_destroy(path);
269 static twin_time_t pboot_rfocus_timeout (twin_time_t now, void *closure)
271 int dir = 1, dist, pos;
272 const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 2, 3, 4, 5 };
274 dist = abs(pboot_rpane->focus_target - pboot_rpane->focus_start);
275 dir = dist > 5 ? 5 : dist;
276 pos = pboot_rpane->focus_target - (int)pboot_rpane->focus_box.top;
284 twin_window_damage(pboot_rpane->window,
285 pboot_rpane->focus_box.left,
286 pboot_rpane->focus_box.top,
287 pboot_rpane->focus_box.right,
288 pboot_rpane->focus_box.bottom);
290 pboot_rpane->focus_box.top += dir;
291 pboot_rpane->focus_box.bottom += dir;
293 twin_window_damage(pboot_rpane->window,
294 pboot_rpane->focus_box.left,
295 pboot_rpane->focus_box.top,
296 pboot_rpane->focus_box.right,
297 pboot_rpane->focus_box.bottom);
299 twin_window_queue_paint(pboot_rpane->window);
301 return accel[(pos * 10) / dist];
304 static void pboot_set_rfocus(int index)
308 if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
310 dev = pboot_devices[pboot_dev_sel];
311 if (index < 0 || index >= dev->option_count)
314 pboot_rpane->focus_start = pboot_rpane->focus_box.top;
315 pboot_rpane->focus_target = PBOOT_RIGHT_FOCUS_YOFF +
316 PBOOT_RIGHT_OPTION_STRIDE * index;
317 pboot_rpane->focus_curindex = index;
319 twin_set_timeout(pboot_rfocus_timeout, 0, NULL);
322 static void pboot_select_rpane(void)
324 if (pboot_focus_lpane == 0)
326 pboot_focus_lpane = 0;
328 twin_screen_set_active(pboot_screen, pboot_rpane->window->pixmap);
330 twin_window_damage(pboot_lpane->window,
331 pboot_lpane->focus_box.left,
332 pboot_lpane->focus_box.top,
333 pboot_lpane->focus_box.right,
334 pboot_lpane->focus_box.bottom);
336 twin_window_damage(pboot_rpane->window,
337 pboot_rpane->focus_box.left,
338 pboot_rpane->focus_box.top,
339 pboot_rpane->focus_box.right,
340 pboot_rpane->focus_box.bottom);
342 twin_window_queue_paint(pboot_lpane->window);
343 twin_window_queue_paint(pboot_rpane->window);
348 static void pboot_select_lpane(void)
350 if (pboot_focus_lpane == 1)
352 pboot_focus_lpane = 1;
354 twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
356 twin_window_damage(pboot_lpane->window,
357 pboot_lpane->focus_box.left,
358 pboot_lpane->focus_box.top,
359 pboot_lpane->focus_box.right,
360 pboot_lpane->focus_box.bottom);
362 twin_window_damage(pboot_rpane->window,
363 pboot_rpane->focus_box.left,
364 pboot_rpane->focus_box.top,
365 pboot_rpane->focus_box.right,
366 pboot_rpane->focus_box.bottom);
368 twin_window_queue_paint(pboot_lpane->window);
369 twin_window_queue_paint(pboot_rpane->window);
372 static void pboot_rpane_mousetrack(twin_coord_t x, twin_coord_t y)
378 if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
380 dev = pboot_devices[pboot_dev_sel];
382 if (y < PBOOT_RIGHT_OPTION_TMARGIN)
384 candidate = (y - PBOOT_RIGHT_OPTION_TMARGIN) /
385 PBOOT_RIGHT_OPTION_STRIDE;
386 if (candidate >= dev->option_count) {
390 if (candidate == pboot_rpane->mouse_target)
392 opt = &dev->options[candidate];
393 if (x < opt->box.left || x > opt->box.right ||
394 y < opt->box.top || y > opt->box.bottom) {
399 /* Ok, so now, we know the mouse hit an icon that wasn't the same
400 * as the previous one, we trigger a focus change
402 pboot_set_rfocus(candidate);
405 pboot_rpane->mouse_target = candidate;
408 static void pboot_choose_option(void)
410 pboot_device_t *dev = pboot_devices[pboot_dev_sel];
411 pboot_option_t *opt = &dev->options[pboot_rpane->focus_curindex];
413 LOG("Selected device %s\n", opt->title);
415 /* Give user feedback, make sure errors and panics will be seen */
416 pboot_exec_option(opt->data);
419 static twin_bool_t pboot_rpane_event (twin_window_t *window,
422 /* filter out all mouse events */
423 switch(event->kind) {
425 case TwinEventMotion:
427 pboot_select_rpane();
428 pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
430 case TwinEventButtonDown:
431 pboot_select_rpane();
432 pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
433 pboot_choose_option();
434 case TwinEventButtonUp:
436 case TwinEventKeyDown:
437 switch(event->u.key.key) {
439 pboot_set_rfocus(pboot_rpane->focus_curindex - 1);
442 pboot_set_rfocus(pboot_rpane->focus_curindex + 1);
445 pboot_select_lpane();
448 pboot_choose_option();
460 int pboot_add_option(int devindex, const char *title,
461 const char *subtitle, twin_pixmap_t *badge, void *data)
468 if (devindex < 0 || devindex >= pboot_dev_count)
470 dev = pboot_devices[devindex];
472 if (dev->option_count >= PBOOT_MAX_OPTION)
474 index = dev->option_count++;
475 opt = &dev->options[index];
477 opt->title = malloc(strlen(title) + 1);
478 strcpy(opt->title, title);
481 opt->subtitle = malloc(strlen(subtitle) + 1);
482 strcpy(opt->subtitle, subtitle);
484 opt->subtitle = NULL;
489 width = pboot_rpane->window->pixmap->width -
490 (PBOOT_RIGHT_OPTION_LMARGIN + PBOOT_RIGHT_OPTION_RMARGIN);
492 opt->box.left = PBOOT_RIGHT_OPTION_LMARGIN;
493 opt->box.right = opt->box.left + width;
494 opt->box.top = PBOOT_RIGHT_OPTION_TMARGIN +
495 index * PBOOT_RIGHT_OPTION_STRIDE;
496 opt->box.bottom = opt->box.top + PBOOT_RIGHT_OPTION_HEIGHT;
503 static void pboot_set_device_select(int sel)
505 LOG("%s: %d -> %d\n", __FUNCTION__, pboot_dev_sel, sel);
506 if (sel == pboot_dev_sel || sel >= pboot_dev_count)
509 pboot_rpane->focus_curindex = -1;
510 pboot_rpane->mouse_target = -1;
511 pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
512 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
513 PBOOT_RIGHT_FOCUS_HEIGHT;
514 twin_window_damage(pboot_rpane->window, 0, 0,
515 pboot_rpane->window->pixmap->width,
516 pboot_rpane->window->pixmap->height);
517 twin_window_queue_paint(pboot_rpane->window);
520 static twin_time_t pboot_lfocus_timeout (twin_time_t now, void *closure)
522 int dir = 1, dist, pos;
523 const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 2, 3, 4, 5 };
525 dist = abs(pboot_lpane->focus_target - pboot_lpane->focus_start);
526 pos = pboot_lpane->focus_target - (int)pboot_lpane->focus_box.top;
528 pboot_set_device_select(pboot_lpane->focus_curindex);
535 twin_window_damage(pboot_lpane->window,
536 pboot_lpane->focus_box.left,
537 pboot_lpane->focus_box.top,
538 pboot_lpane->focus_box.right,
539 pboot_lpane->focus_box.bottom);
541 pboot_lpane->focus_box.top += dir;
542 pboot_lpane->focus_box.bottom += dir;
544 twin_window_damage(pboot_lpane->window,
545 pboot_lpane->focus_box.left,
546 pboot_lpane->focus_box.top,
547 pboot_lpane->focus_box.right,
548 pboot_lpane->focus_box.bottom);
550 twin_window_queue_paint(pboot_lpane->window);
552 return accel[(pos * 10) / dist];
555 static void pboot_set_lfocus(int index)
557 if (index >= pboot_dev_count)
560 pboot_lpane->focus_start = pboot_lpane->focus_box.top;
563 pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
565 pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF +
566 PBOOT_LEFT_ICON_STRIDE * index;
568 pboot_lpane->focus_curindex = index;
570 twin_set_timeout(pboot_lfocus_timeout, 0, NULL);
573 static void pboot_lpane_mousetrack(twin_coord_t x, twin_coord_t y)
576 twin_coord_t icon_top;
578 if (x < PBOOT_LEFT_ICON_XOFF ||
579 x > (PBOOT_LEFT_ICON_XOFF + PBOOT_LEFT_ICON_WIDTH))
581 if (y < PBOOT_LEFT_ICON_YOFF)
583 candidate = (y - PBOOT_LEFT_ICON_YOFF) / PBOOT_LEFT_ICON_STRIDE;
584 if (candidate >= pboot_dev_count) {
588 if (candidate == pboot_lpane->mouse_target)
590 icon_top = PBOOT_LEFT_ICON_YOFF +
591 candidate * PBOOT_LEFT_ICON_STRIDE;
592 if (y > (icon_top + PBOOT_LEFT_ICON_HEIGHT)) {
597 /* Ok, so now, we know the mouse hit an icon that wasn't the same
598 * as the previous one, we trigger a focus change
600 pboot_set_lfocus(candidate);
603 pboot_lpane->mouse_target = candidate;
606 static twin_bool_t pboot_lpane_event (twin_window_t *window,
609 /* filter out all mouse events */
610 switch(event->kind) {
612 case TwinEventMotion:
614 pboot_select_lpane();
615 pboot_lpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
617 case TwinEventButtonDown:
618 case TwinEventButtonUp:
620 case TwinEventKeyDown:
621 switch(event->u.key.key) {
623 if (pboot_lpane->focus_curindex > 0)
625 pboot_lpane->focus_curindex - 1);
628 pboot_set_lfocus(pboot_lpane->focus_curindex + 1);
631 pboot_select_rpane();
643 twin_bool_t pboot_event_filter(twin_screen_t *screen,
646 switch(event->kind) {
648 case TwinEventMotion:
650 case TwinEventButtonDown:
651 case TwinEventButtonUp:
652 if (pboot_cursor != NULL)
653 twin_screen_set_cursor(pboot_screen, pboot_cursor,
657 case TwinEventKeyDown:
659 twin_screen_set_cursor(pboot_screen, NULL, 0, 0);
667 static void pboot_lpane_draw(twin_window_t *window)
669 twin_pixmap_t *px = window->pixmap;
670 pboot_lpane_t *lpane = window->client_data;
672 twin_fixed_t x, y, w, h;
675 /* Fill background */
676 twin_fill(px, PBOOT_LEFT_PANE_COLOR, TWIN_SOURCE,
677 0, 0, px->width, px->height);
679 /* Create a path for use later */
680 path = twin_path_create();
683 /* Draw right line if needed */
684 if (px->clip.right > (PBOOT_LEFT_PANE_SIZE - 4)) {
685 x = twin_int_to_fixed(PBOOT_LEFT_PANE_SIZE - 4);
686 y = twin_int_to_fixed(px->height);
687 twin_path_rectangle(path, x, 0, 0x40000, y);
688 twin_paint_path(px, PBOOT_LEFT_LINE_COLOR, path);
689 twin_path_empty(path);
693 if (lpane->focus_curindex >= 0 &&
694 twin_rect_intersect(lpane->focus_box, px->clip)) {
695 x = twin_int_to_fixed(lpane->focus_box.left + 2);
696 y = twin_int_to_fixed(lpane->focus_box.top + 2);
697 w = twin_int_to_fixed(lpane->focus_box.right -
698 lpane->focus_box.left - 4);
699 h = twin_int_to_fixed(lpane->focus_box.bottom -
700 lpane->focus_box.top - 4);
701 twin_path_rounded_rectangle(path, x, y, w, h,
702 PBOOT_LEFT_FOCUS_XRAD,
703 PBOOT_LEFT_FOCUS_YRAD);
704 if (pboot_focus_lpane)
705 twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
707 twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
712 for (i = 0; i < pboot_dev_count; i++) {
713 pboot_device_t *dev = pboot_devices[i];
716 if (!twin_rect_intersect(dev->box, px->clip))
719 src.source_kind = TWIN_PIXMAP;
720 src.u.pixmap = dev->badge;
722 twin_composite(px, dev->box.left, dev->box.top,
723 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
724 dev->box.right - dev->box.left,
725 dev->box.bottom - dev->box.top);
730 twin_path_destroy(path);
733 static void pboot_create_panels(void)
736 pboot_lpane = calloc(1, sizeof(pboot_lpane_t));
739 pboot_lpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
741 0, 0, PBOOT_LEFT_PANE_SIZE,
742 pboot_screen->height);
743 assert(pboot_lpane->window);
745 pboot_lpane->window->draw = pboot_lpane_draw;
746 pboot_lpane->window->event = pboot_lpane_event;
747 pboot_lpane->window->client_data = pboot_lpane;
748 pboot_lpane->focus_curindex = -1;
749 pboot_lpane->focus_box.left = PBOOT_LEFT_FOCUS_XOFF;
750 pboot_lpane->focus_box.top = -2*PBOOT_LEFT_FOCUS_HEIGHT;
751 pboot_lpane->focus_box.right = pboot_lpane->focus_box.left +
752 PBOOT_LEFT_FOCUS_WIDTH;
753 pboot_lpane->focus_box.bottom = pboot_lpane->focus_box.top +
754 PBOOT_LEFT_FOCUS_HEIGHT;
755 pboot_lpane->mouse_target = -1;
756 twin_window_show(pboot_lpane->window);
759 pboot_rpane = calloc(1, sizeof(pboot_rpane_t));
762 pboot_rpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
764 PBOOT_LEFT_PANE_SIZE, 0,
765 pboot_screen->width -
766 PBOOT_LEFT_PANE_SIZE,
767 pboot_screen->height);
768 assert(pboot_rpane->window);
770 pboot_rpane->window->draw = pboot_rpane_draw;
771 pboot_rpane->window->event = pboot_rpane_event;
772 pboot_rpane->window->client_data = pboot_rpane;
774 pboot_rpane->focus_curindex = -1;
775 pboot_rpane->focus_box.left = PBOOT_RIGHT_FOCUS_XOFF;
776 pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
777 pboot_rpane->focus_box.right = pboot_rpane->window->pixmap->width -
778 2 * PBOOT_RIGHT_FOCUS_XOFF;
779 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
780 PBOOT_RIGHT_FOCUS_HEIGHT;
781 pboot_rpane->mouse_target = -1;
782 twin_window_show(pboot_rpane->window);
785 int pboot_add_device(const char *dev_id, const char *name,
786 twin_pixmap_t *pixmap)
791 if (pboot_dev_count >= PBOOT_MAX_DEV)
794 index = pboot_dev_count++;
796 dev = malloc(sizeof(*dev));
797 memset(dev, 0, sizeof(*dev));
798 dev->id = malloc(strlen(dev_id) + 1);
799 strcpy(dev->id, dev_id);
801 dev->box.left = PBOOT_LEFT_ICON_XOFF;
802 dev->box.right = dev->box.left + PBOOT_LEFT_ICON_WIDTH;
803 dev->box.top = PBOOT_LEFT_ICON_YOFF +
804 PBOOT_LEFT_ICON_STRIDE * index;
805 dev->box.bottom = dev->box.top + PBOOT_LEFT_ICON_HEIGHT;
807 pboot_devices[index] = dev;
809 twin_window_damage(pboot_lpane->window,
810 dev->box.left, dev->box.top,
811 dev->box.right, dev->box.bottom);
812 twin_window_queue_paint(pboot_lpane->window);
817 int pboot_remove_device(const char *dev_id)
819 int i, new_dev_index;
820 pboot_device_t *dev = NULL;
822 /* find the matching device */
823 for (i = 0; i < pboot_dev_count; i++) {
824 if (!strcmp(pboot_devices[i]->id, dev_id)) {
825 dev = pboot_devices[i];
833 /* select the newly-focussed device */
834 if (i == pboot_dev_count - 1)
835 new_dev_index = i - 1;
837 new_dev_index = i + 1;
839 memmove(pboot_devices + i, pboot_devices + i + 1,
840 sizeof(*pboot_devices) * (pboot_dev_count + i - 1));
842 pboot_devices[--pboot_dev_count] = NULL;
844 pboot_set_device_select(new_dev_index);
845 twin_window_damage(pboot_lpane->window,
846 dev->box.left, dev->box.top,
847 dev->box.right, dev->box.bottom);
848 twin_window_queue_paint(pboot_lpane->window);
850 /* todo: free device & options */
855 static void exitfunc(void)
859 twin_fbdev_destroy(pboot_fbdev);
864 static void sigint(int sig)
870 int main(int argc, char **argv)
873 const char *background_path;
876 signal(SIGINT, sigint);
879 pboot_x11 = twin_x11_create(XOpenDisplay(0), 1024, 768);
880 if (pboot_x11 == NULL) {
881 perror("failed to create x11 screen !\n");
884 pboot_screen = pboot_x11->screen;
886 /* Create screen and mouse drivers */
887 pboot_fbdev = twin_fbdev_create(-1, SIGUSR1);
888 if (pboot_fbdev == NULL) {
889 perror("failed to create fbdev screen !\n");
892 pboot_screen = pboot_fbdev->screen;
893 twin_linux_mouse_create(NULL, pboot_screen);
895 if (pboot_fbdev != NULL) {
896 char *cursor_path = artwork_pathname("cursor");
897 pboot_cursor = twin_load_X_cursor(cursor_path, 2,
900 if (pboot_cursor == NULL)
902 twin_get_default_cursor(&pboot_cursor_hx,
907 /* Set background pixmap */
908 background_path = artwork_pathname("background.png");
909 LOG("loading background: %s...", background_path);
910 pic = twin_png_to_pixmap(background_path, TWIN_ARGB32);
911 LOG("%s\n", pic ? "ok" : "failed");
913 twin_screen_set_background(pboot_screen, pic);
915 /* Init more stuffs */
916 pboot_create_panels();
917 twin_window_queue_paint(pboot_lpane->window);
918 twin_window_queue_paint(pboot_rpane->window);
920 if (!pboot_start_device_discovery()) {
921 LOG("Couldn't start device discovery!\n");
926 twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
927 pboot_screen->event_filter = pboot_event_filter;
932 twin_fbdev_activate(pboot_fbdev);