9 #include <linux/input.h>
13 #include <libtwin/twin.h>
14 #include <libtwin/twin_linux_mouse.h>
15 #include <libtwin/twin_png.h>
16 #include <libtwin/twin_jpeg.h>
18 #include "petitboot.h"
19 #include "petitboot-paths.h"
22 #include <libtwin/twin_x11.h>
23 static twin_x11_t *pboot_x11;
25 #include <libtwin/twin_fbdev.h>
26 static twin_fbdev_t *pboot_fbdev;
29 static twin_screen_t *pboot_screen;
31 #define PBOOT_LEFT_PANE_SIZE 200
32 #define PBOOT_LEFT_PANE_COLOR 0x80000000
33 #define PBOOT_LEFT_LINE_COLOR 0xff000000
35 #define PBOOT_LEFT_FOCUS_WIDTH 80
36 #define PBOOT_LEFT_FOCUS_HEIGHT 80
37 #define PBOOT_LEFT_FOCUS_XOFF 60
38 #define PBOOT_LEFT_FOCUS_YOFF 60
39 #define PBOOT_LEFT_FOCUS_XRAD (6 * TWIN_FIXED_ONE)
40 #define PBOOT_LEFT_FOCUS_YRAD (6 * TWIN_FIXED_ONE)
42 #define PBOOT_RIGHT_FOCUS_XOFF 20
43 #define PBOOT_RIGHT_FOCUS_YOFF 60
44 #define PBOOT_RIGHT_FOCUS_HEIGHT 80
45 #define PBOOT_RIGHT_FOCUS_XRAD (6 * TWIN_FIXED_ONE)
46 #define PBOOT_RIGHT_FOCUS_YRAD (6 * TWIN_FIXED_ONE)
48 #define PBOOT_LEFT_ICON_WIDTH 64
49 #define PBOOT_LEFT_ICON_HEIGHT 64
50 #define PBOOT_LEFT_ICON_XOFF 70
51 #define PBOOT_LEFT_ICON_YOFF 70
52 #define PBOOT_LEFT_ICON_STRIDE 100
54 #define PBOOT_RIGHT_OPTION_LMARGIN 30
55 #define PBOOT_RIGHT_OPTION_RMARGIN 30
56 #define PBOOT_RIGHT_OPTION_TMARGIN 70
57 #define PBOOT_RIGHT_OPTION_HEIGHT 64
58 #define PBOOT_RIGHT_OPTION_STRIDE 100
59 #define PBOOT_RIGHT_TITLE_TEXT_SIZE (30 * TWIN_FIXED_ONE)
60 #define PBOOT_RIGHT_SUBTITLE_TEXT_SIZE (18 * TWIN_FIXED_ONE)
61 #define PBOOT_RIGHT_TITLE_XOFFSET 80
62 #define PBOOT_RIGHT_TITLE_YOFFSET 30
63 #define PBOOT_RIGHT_SUBTITLE_XOFFSET 200
64 #define PBOOT_RIGHT_SUBTITLE_YOFFSET 50
65 #define PBOOT_RIGHT_BADGE_XOFFSET 2
66 #define PBOOT_RIGHT_BADGE_YOFFSET 0
69 #define PBOOT_RIGHT_TITLE_COLOR 0xff000000
70 #define PBOOT_RIGHT_SUBTITLE_COLOR 0xff400000
72 #define PBOOT_FOCUS_COLOR 0x10404040
75 typedef struct _pboot_option pboot_option_t;
76 typedef struct _pboot_device pboot_device_t;
94 pboot_option_t options[PBOOT_MAX_OPTION];
97 static twin_pixmap_t *pboot_cursor;
98 static int pboot_cursor_hx;
99 static int pboot_cursor_hy;
101 static pboot_device_t *pboot_devices[PBOOT_MAX_DEV];
102 static int pboot_dev_count;
103 static int pboot_dev_sel = -1;
104 static int pboot_focus_lpane = 1;
106 typedef struct _pboot_lpane {
107 twin_window_t *window;
108 twin_rect_t focus_box;
115 typedef struct _pboot_rpane {
116 twin_window_t *window;
117 twin_rect_t focus_box;
124 static pboot_lpane_t *pboot_lpane;
125 static pboot_rpane_t *pboot_rpane;
127 /* XXX move to twin */
128 static inline twin_bool_t twin_rect_intersect(twin_rect_t r1,
131 return !(r1.left > r2.right ||
132 r1.right < r2.left ||
133 r1.top > r2.bottom ||
137 static void pboot_draw_option_cache(pboot_device_t *dev, pboot_option_t *opt,
145 px = twin_pixmap_create(TWIN_ARGB32, opt->box.right - opt->box.left,
146 opt->box.bottom - opt->box.top);
150 /* Fill background */
151 twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
153 /* Allocate a path for drawing */
154 path = twin_path_create();
158 /* TEST - Bounding rectangle */
159 twin_path_rectangle(path, 0, 0,
160 twin_int_to_fixed(px->width),
161 twin_int_to_fixed(px->height));
162 twin_paint_path(px, PBOOT_RIGHT_TITLE_COLOR, path);
163 twin_path_empty(path);
164 twin_fill(px, 0x00000000, TWIN_SOURCE, 2, 2,
165 px->width - 3, px->height - 3);
169 twin_path_set_font_size(path, PBOOT_RIGHT_TITLE_TEXT_SIZE);
170 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
171 tx = twin_int_to_fixed(PBOOT_RIGHT_TITLE_XOFFSET);
172 ty = twin_int_to_fixed(PBOOT_RIGHT_TITLE_YOFFSET);
173 twin_path_move (path, tx, ty);
174 twin_path_utf8 (path, opt->title);
175 twin_paint_path (px, PBOOT_RIGHT_TITLE_COLOR, path);
176 twin_path_empty (path);
179 twin_path_set_font_size(path, PBOOT_RIGHT_SUBTITLE_TEXT_SIZE);
180 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
181 tx = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_XOFFSET);
182 ty = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_YOFFSET);
183 twin_path_move (path, tx, ty);
184 twin_path_utf8 (path, opt->subtitle);
185 twin_paint_path (px, PBOOT_RIGHT_SUBTITLE_COLOR, path);
186 twin_path_empty (path);
192 src.source_kind = TWIN_PIXMAP;
193 src.u.pixmap = opt->badge;
195 twin_composite(px, PBOOT_RIGHT_BADGE_XOFFSET,
196 PBOOT_RIGHT_BADGE_YOFFSET,
197 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
198 opt->badge->width, opt->badge->height);
203 twin_path_destroy(path);
206 static void pboot_rpane_draw(twin_window_t *window)
208 twin_pixmap_t *px = window->pixmap;
209 pboot_rpane_t *rpane = window->client_data;
212 twin_fixed_t x, y, w, h;
215 /* Fill background */
216 twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
218 /* Nothing to draw, return */
219 if (pboot_dev_sel < 0)
222 /* Create a path for use later */
223 path = twin_path_create();
227 if (rpane->focus_curindex >= 0 &&
228 twin_rect_intersect(rpane->focus_box, px->clip)) {
229 x = twin_int_to_fixed(rpane->focus_box.left + 2);
230 y = twin_int_to_fixed(rpane->focus_box.top + 2);
231 w = twin_int_to_fixed(rpane->focus_box.right -
232 rpane->focus_box.left - 4);
233 h = twin_int_to_fixed(rpane->focus_box.bottom -
234 rpane->focus_box.top - 4);
235 twin_path_rounded_rectangle(path, x, y, w, h,
236 PBOOT_RIGHT_FOCUS_XRAD,
237 PBOOT_RIGHT_FOCUS_YRAD);
238 if (!pboot_focus_lpane)
239 twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
241 twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
245 /* Get device and iterate through options */
246 dev = pboot_devices[pboot_dev_sel];
247 for (i = 0; i < dev->option_count; i++) {
248 pboot_option_t *opt = &dev->options[i];
251 if (opt->title == NULL)
253 if (!twin_rect_intersect(opt->box, px->clip))
255 if (opt->cache == NULL)
256 pboot_draw_option_cache(dev, opt, i);
258 src.source_kind = TWIN_PIXMAP;
259 src.u.pixmap = opt->cache;
261 twin_composite(px, opt->box.left, opt->box.top,
262 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
263 opt->box.right - opt->box.left,
264 opt->box.bottom - opt->box.top);
268 twin_path_destroy(path);
271 static twin_time_t pboot_rfocus_timeout (twin_time_t now, void *closure)
273 int dir = 1, dist, pos;
274 const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 2, 3, 4, 5 };
276 dist = abs(pboot_rpane->focus_target - pboot_rpane->focus_start);
277 dir = dist > 5 ? 5 : dist;
278 pos = pboot_rpane->focus_target - (int)pboot_rpane->focus_box.top;
286 twin_window_damage(pboot_rpane->window,
287 pboot_rpane->focus_box.left,
288 pboot_rpane->focus_box.top,
289 pboot_rpane->focus_box.right,
290 pboot_rpane->focus_box.bottom);
292 pboot_rpane->focus_box.top += dir;
293 pboot_rpane->focus_box.bottom += dir;
295 twin_window_damage(pboot_rpane->window,
296 pboot_rpane->focus_box.left,
297 pboot_rpane->focus_box.top,
298 pboot_rpane->focus_box.right,
299 pboot_rpane->focus_box.bottom);
301 twin_window_queue_paint(pboot_rpane->window);
303 return accel[(pos * 10) / dist];
306 static void pboot_set_rfocus(int index)
310 if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
312 dev = pboot_devices[pboot_dev_sel];
313 if (index < 0 || index >= dev->option_count)
316 pboot_rpane->focus_start = pboot_rpane->focus_box.top;
317 pboot_rpane->focus_target = PBOOT_RIGHT_FOCUS_YOFF +
318 PBOOT_RIGHT_OPTION_STRIDE * index;
319 pboot_rpane->focus_curindex = index;
321 twin_set_timeout(pboot_rfocus_timeout, 0, NULL);
324 static void pboot_select_rpane(void)
326 if (pboot_focus_lpane == 0)
328 pboot_focus_lpane = 0;
330 twin_screen_set_active(pboot_screen, pboot_rpane->window->pixmap);
332 twin_window_damage(pboot_lpane->window,
333 pboot_lpane->focus_box.left,
334 pboot_lpane->focus_box.top,
335 pboot_lpane->focus_box.right,
336 pboot_lpane->focus_box.bottom);
338 twin_window_damage(pboot_rpane->window,
339 pboot_rpane->focus_box.left,
340 pboot_rpane->focus_box.top,
341 pboot_rpane->focus_box.right,
342 pboot_rpane->focus_box.bottom);
344 twin_window_queue_paint(pboot_lpane->window);
345 twin_window_queue_paint(pboot_rpane->window);
350 static void pboot_select_lpane(void)
352 if (pboot_focus_lpane == 1)
354 pboot_focus_lpane = 1;
356 twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
358 twin_window_damage(pboot_lpane->window,
359 pboot_lpane->focus_box.left,
360 pboot_lpane->focus_box.top,
361 pboot_lpane->focus_box.right,
362 pboot_lpane->focus_box.bottom);
364 twin_window_damage(pboot_rpane->window,
365 pboot_rpane->focus_box.left,
366 pboot_rpane->focus_box.top,
367 pboot_rpane->focus_box.right,
368 pboot_rpane->focus_box.bottom);
370 twin_window_queue_paint(pboot_lpane->window);
371 twin_window_queue_paint(pboot_rpane->window);
374 static void pboot_rpane_mousetrack(twin_coord_t x, twin_coord_t y)
380 if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
382 dev = pboot_devices[pboot_dev_sel];
384 if (y < PBOOT_RIGHT_OPTION_TMARGIN)
386 candidate = (y - PBOOT_RIGHT_OPTION_TMARGIN) /
387 PBOOT_RIGHT_OPTION_STRIDE;
388 if (candidate >= dev->option_count) {
392 if (candidate == pboot_rpane->mouse_target)
394 opt = &dev->options[candidate];
395 if (x < opt->box.left || x > opt->box.right ||
396 y < opt->box.top || y > opt->box.bottom) {
401 /* Ok, so now, we know the mouse hit an icon that wasn't the same
402 * as the previous one, we trigger a focus change
404 pboot_set_rfocus(candidate);
407 pboot_rpane->mouse_target = candidate;
410 static void pboot_choose_option(void)
412 pboot_device_t *dev = pboot_devices[pboot_dev_sel];
413 pboot_option_t *opt = &dev->options[pboot_rpane->focus_curindex];
415 LOG("Selected device %s\n", opt->title);
417 /* Give user feedback, make sure errors and panics will be seen */
418 pboot_exec_option(opt->data);
421 static twin_bool_t pboot_rpane_event (twin_window_t *window,
424 /* filter out all mouse events */
425 switch(event->kind) {
427 case TwinEventMotion:
429 pboot_select_rpane();
430 pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
432 case TwinEventButtonDown:
433 pboot_select_rpane();
434 pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
435 pboot_choose_option();
436 case TwinEventButtonUp:
438 case TwinEventKeyDown:
439 switch(event->u.key.key) {
441 pboot_set_rfocus(pboot_rpane->focus_curindex - 1);
444 pboot_set_rfocus(pboot_rpane->focus_curindex + 1);
447 pboot_select_lpane();
450 pboot_choose_option();
462 int pboot_add_option(int devindex, const char *title,
463 const char *subtitle, twin_pixmap_t *badge, void *data)
470 if (devindex < 0 || devindex >= pboot_dev_count)
472 dev = pboot_devices[devindex];
474 if (dev->option_count >= PBOOT_MAX_OPTION)
476 index = dev->option_count++;
477 opt = &dev->options[index];
479 opt->title = malloc(strlen(title) + 1);
480 strcpy(opt->title, title);
483 opt->subtitle = malloc(strlen(subtitle) + 1);
484 strcpy(opt->subtitle, subtitle);
486 opt->subtitle = NULL;
491 width = pboot_rpane->window->pixmap->width -
492 (PBOOT_RIGHT_OPTION_LMARGIN + PBOOT_RIGHT_OPTION_RMARGIN);
494 opt->box.left = PBOOT_RIGHT_OPTION_LMARGIN;
495 opt->box.right = opt->box.left + width;
496 opt->box.top = PBOOT_RIGHT_OPTION_TMARGIN +
497 index * PBOOT_RIGHT_OPTION_STRIDE;
498 opt->box.bottom = opt->box.top + PBOOT_RIGHT_OPTION_HEIGHT;
505 static void pboot_set_device_select(int sel)
507 LOG("%s: %d -> %d\n", __FUNCTION__, pboot_dev_sel, sel);
508 if (sel == pboot_dev_sel || sel >= pboot_dev_count)
511 pboot_rpane->focus_curindex = -1;
512 pboot_rpane->mouse_target = -1;
513 pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
514 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
515 PBOOT_RIGHT_FOCUS_HEIGHT;
516 twin_window_damage(pboot_rpane->window, 0, 0,
517 pboot_rpane->window->pixmap->width,
518 pboot_rpane->window->pixmap->height);
519 twin_window_queue_paint(pboot_rpane->window);
522 static twin_time_t pboot_lfocus_timeout (twin_time_t now, void *closure)
524 int dir = 1, dist, pos;
525 const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 2, 3, 4, 5 };
527 dist = abs(pboot_lpane->focus_target - pboot_lpane->focus_start);
528 pos = pboot_lpane->focus_target - (int)pboot_lpane->focus_box.top;
530 pboot_set_device_select(pboot_lpane->focus_curindex);
537 twin_window_damage(pboot_lpane->window,
538 pboot_lpane->focus_box.left,
539 pboot_lpane->focus_box.top,
540 pboot_lpane->focus_box.right,
541 pboot_lpane->focus_box.bottom);
543 pboot_lpane->focus_box.top += dir;
544 pboot_lpane->focus_box.bottom += dir;
546 twin_window_damage(pboot_lpane->window,
547 pboot_lpane->focus_box.left,
548 pboot_lpane->focus_box.top,
549 pboot_lpane->focus_box.right,
550 pboot_lpane->focus_box.bottom);
552 twin_window_queue_paint(pboot_lpane->window);
554 return accel[(pos * 10) / dist];
557 static void pboot_set_lfocus(int index)
559 if (index >= pboot_dev_count)
562 pboot_lpane->focus_start = pboot_lpane->focus_box.top;
565 pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
567 pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF +
568 PBOOT_LEFT_ICON_STRIDE * index;
570 pboot_lpane->focus_curindex = index;
572 twin_set_timeout(pboot_lfocus_timeout, 0, NULL);
575 static void pboot_lpane_mousetrack(twin_coord_t x, twin_coord_t y)
578 twin_coord_t icon_top;
580 if (x < PBOOT_LEFT_ICON_XOFF ||
581 x > (PBOOT_LEFT_ICON_XOFF + PBOOT_LEFT_ICON_WIDTH))
583 if (y < PBOOT_LEFT_ICON_YOFF)
585 candidate = (y - PBOOT_LEFT_ICON_YOFF) / PBOOT_LEFT_ICON_STRIDE;
586 if (candidate >= pboot_dev_count) {
590 if (candidate == pboot_lpane->mouse_target)
592 icon_top = PBOOT_LEFT_ICON_YOFF +
593 candidate * PBOOT_LEFT_ICON_STRIDE;
594 if (y > (icon_top + PBOOT_LEFT_ICON_HEIGHT)) {
599 /* Ok, so now, we know the mouse hit an icon that wasn't the same
600 * as the previous one, we trigger a focus change
602 pboot_set_lfocus(candidate);
605 pboot_lpane->mouse_target = candidate;
608 static twin_bool_t pboot_lpane_event (twin_window_t *window,
611 /* filter out all mouse events */
612 switch(event->kind) {
614 case TwinEventMotion:
616 pboot_select_lpane();
617 pboot_lpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
619 case TwinEventButtonDown:
620 case TwinEventButtonUp:
622 case TwinEventKeyDown:
623 switch(event->u.key.key) {
625 if (pboot_lpane->focus_curindex > 0)
627 pboot_lpane->focus_curindex - 1);
630 pboot_set_lfocus(pboot_lpane->focus_curindex + 1);
633 pboot_select_rpane();
645 twin_bool_t pboot_event_filter(twin_screen_t *screen,
648 switch(event->kind) {
650 case TwinEventMotion:
652 case TwinEventButtonDown:
653 case TwinEventButtonUp:
654 if (pboot_cursor != NULL)
655 twin_screen_set_cursor(pboot_screen, pboot_cursor,
659 case TwinEventKeyDown:
661 twin_screen_set_cursor(pboot_screen, NULL, 0, 0);
669 static void pboot_lpane_draw(twin_window_t *window)
671 twin_pixmap_t *px = window->pixmap;
672 pboot_lpane_t *lpane = window->client_data;
674 twin_fixed_t x, y, w, h;
677 /* Fill background */
678 twin_fill(px, PBOOT_LEFT_PANE_COLOR, TWIN_SOURCE,
679 0, 0, px->width, px->height);
681 /* Create a path for use later */
682 path = twin_path_create();
685 /* Draw right line if needed */
686 if (px->clip.right > (PBOOT_LEFT_PANE_SIZE - 4)) {
687 x = twin_int_to_fixed(PBOOT_LEFT_PANE_SIZE - 4);
688 y = twin_int_to_fixed(px->height);
689 twin_path_rectangle(path, x, 0, 0x40000, y);
690 twin_paint_path(px, PBOOT_LEFT_LINE_COLOR, path);
691 twin_path_empty(path);
695 if (lpane->focus_curindex >= 0 &&
696 twin_rect_intersect(lpane->focus_box, px->clip)) {
697 x = twin_int_to_fixed(lpane->focus_box.left + 2);
698 y = twin_int_to_fixed(lpane->focus_box.top + 2);
699 w = twin_int_to_fixed(lpane->focus_box.right -
700 lpane->focus_box.left - 4);
701 h = twin_int_to_fixed(lpane->focus_box.bottom -
702 lpane->focus_box.top - 4);
703 twin_path_rounded_rectangle(path, x, y, w, h,
704 PBOOT_LEFT_FOCUS_XRAD,
705 PBOOT_LEFT_FOCUS_YRAD);
706 if (pboot_focus_lpane)
707 twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
709 twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
714 for (i = 0; i < pboot_dev_count; i++) {
715 pboot_device_t *dev = pboot_devices[i];
718 if (!twin_rect_intersect(dev->box, px->clip))
721 src.source_kind = TWIN_PIXMAP;
722 src.u.pixmap = dev->badge;
724 twin_composite(px, dev->box.left, dev->box.top,
725 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
726 dev->box.right - dev->box.left,
727 dev->box.bottom - dev->box.top);
732 twin_path_destroy(path);
735 static void pboot_create_panels(void)
738 pboot_lpane = calloc(1, sizeof(pboot_lpane_t));
741 pboot_lpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
743 0, 0, PBOOT_LEFT_PANE_SIZE,
744 pboot_screen->height);
745 assert(pboot_lpane->window);
747 pboot_lpane->window->draw = pboot_lpane_draw;
748 pboot_lpane->window->event = pboot_lpane_event;
749 pboot_lpane->window->client_data = pboot_lpane;
750 pboot_lpane->focus_curindex = -1;
751 pboot_lpane->focus_box.left = PBOOT_LEFT_FOCUS_XOFF;
752 pboot_lpane->focus_box.top = -2*PBOOT_LEFT_FOCUS_HEIGHT;
753 pboot_lpane->focus_box.right = pboot_lpane->focus_box.left +
754 PBOOT_LEFT_FOCUS_WIDTH;
755 pboot_lpane->focus_box.bottom = pboot_lpane->focus_box.top +
756 PBOOT_LEFT_FOCUS_HEIGHT;
757 pboot_lpane->mouse_target = -1;
758 twin_window_show(pboot_lpane->window);
761 pboot_rpane = calloc(1, sizeof(pboot_rpane_t));
764 pboot_rpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
766 PBOOT_LEFT_PANE_SIZE, 0,
767 pboot_screen->width -
768 PBOOT_LEFT_PANE_SIZE,
769 pboot_screen->height);
770 assert(pboot_rpane->window);
772 pboot_rpane->window->draw = pboot_rpane_draw;
773 pboot_rpane->window->event = pboot_rpane_event;
774 pboot_rpane->window->client_data = pboot_rpane;
776 pboot_rpane->focus_curindex = -1;
777 pboot_rpane->focus_box.left = PBOOT_RIGHT_FOCUS_XOFF;
778 pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
779 pboot_rpane->focus_box.right = pboot_rpane->window->pixmap->width -
780 2 * PBOOT_RIGHT_FOCUS_XOFF;
781 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
782 PBOOT_RIGHT_FOCUS_HEIGHT;
783 pboot_rpane->mouse_target = -1;
784 twin_window_show(pboot_rpane->window);
787 int pboot_add_device(const char *dev_id, const char *name,
788 twin_pixmap_t *pixmap)
793 if (pboot_dev_count >= PBOOT_MAX_DEV)
796 index = pboot_dev_count++;
798 dev = malloc(sizeof(*dev));
799 memset(dev, 0, sizeof(*dev));
800 dev->id = malloc(strlen(dev_id) + 1);
801 strcpy(dev->id, dev_id);
803 dev->box.left = PBOOT_LEFT_ICON_XOFF;
804 dev->box.right = dev->box.left + PBOOT_LEFT_ICON_WIDTH;
805 dev->box.top = PBOOT_LEFT_ICON_YOFF +
806 PBOOT_LEFT_ICON_STRIDE * index;
807 dev->box.bottom = dev->box.top + PBOOT_LEFT_ICON_HEIGHT;
809 pboot_devices[index] = dev;
811 twin_window_damage(pboot_lpane->window,
812 dev->box.left, dev->box.top,
813 dev->box.right, dev->box.bottom);
814 twin_window_queue_paint(pboot_lpane->window);
819 int pboot_remove_device(const char *dev_id)
821 int i, new_dev_index;
822 pboot_device_t *dev = NULL;
824 /* find the matching device */
825 for (i = 0; i < pboot_dev_count; i++) {
826 if (!strcmp(pboot_devices[i]->id, dev_id)) {
827 dev = pboot_devices[i];
835 /* select the newly-focussed device */
836 if (i == pboot_dev_count - 1)
837 new_dev_index = i - 1;
839 new_dev_index = i + 1;
841 memmove(pboot_devices + i, pboot_devices + i + 1,
842 sizeof(*pboot_devices) * (pboot_dev_count + i - 1));
844 pboot_devices[--pboot_dev_count] = NULL;
846 pboot_set_device_select(new_dev_index);
847 twin_window_damage(pboot_lpane->window,
848 dev->box.left, dev->box.top,
849 dev->box.right, dev->box.bottom);
850 twin_window_queue_paint(pboot_lpane->window);
852 /* todo: free device & options */
857 static void pboot_make_background(void)
859 twin_pixmap_t *filepic, *scaledpic;
860 const char *background_path;
862 /* Set background pixmap */
863 LOG("loading background...");
864 background_path = artwork_pathname("background.jpg");
865 filepic = twin_jpeg_to_pixmap(background_path, TWIN_ARGB32);
866 LOG("%s\n", filepic ? "ok" : "failed");
871 if (pboot_screen->height == filepic->height &&
872 pboot_screen->width == filepic->width)
876 twin_operand_t srcop;
878 scaledpic = twin_pixmap_create(TWIN_ARGB32,
880 pboot_screen->height);
881 if (scaledpic == NULL) {
882 twin_pixmap_destroy(filepic);
885 sx = twin_fixed_div(twin_int_to_fixed(filepic->width),
886 twin_int_to_fixed(pboot_screen->width));
887 sy = twin_fixed_div(twin_int_to_fixed(filepic->height),
888 twin_int_to_fixed(pboot_screen->height));
890 twin_matrix_scale(&filepic->transform, sx, sy);
891 srcop.source_kind = TWIN_PIXMAP;
892 srcop.u.pixmap = filepic;
893 twin_composite(scaledpic, 0, 0, &srcop, 0, 0,
894 NULL, 0, 0, TWIN_SOURCE,
895 pboot_screen->width, pboot_screen->height);
896 twin_pixmap_destroy(filepic);
899 twin_screen_set_background(pboot_screen, scaledpic);
902 static void exitfunc(void)
906 twin_fbdev_destroy(pboot_fbdev);
911 static void sigint(int sig)
917 static void usage(const char *progname)
919 fprintf(stderr, "Usage: %s [-u] [-h]\n", progname);
922 int main(int argc, char **argv)
925 int udev_trigger = 0;
928 c = getopt(argc, argv, "u::h");
940 fprintf(stderr, "Unknown option '%c'\n", c);
947 signal(SIGINT, sigint);
950 pboot_x11 = twin_x11_create(XOpenDisplay(0), 1024, 768);
951 if (pboot_x11 == NULL) {
952 perror("failed to create x11 screen !\n");
955 pboot_screen = pboot_x11->screen;
957 /* Create screen and mouse drivers */
958 pboot_fbdev = twin_fbdev_create(-1, SIGUSR1);
959 if (pboot_fbdev == NULL) {
960 perror("failed to create fbdev screen !\n");
963 pboot_screen = pboot_fbdev->screen;
964 twin_linux_mouse_create(NULL, pboot_screen);
966 if (pboot_fbdev != NULL) {
967 char *cursor_path = artwork_pathname("cursor");
968 pboot_cursor = twin_load_X_cursor(cursor_path, 2,
971 if (pboot_cursor == NULL)
973 twin_get_default_cursor(&pboot_cursor_hx,
978 /* Set background pixmap */
979 pboot_make_background();
981 /* Init more stuffs */
982 pboot_create_panels();
983 twin_window_queue_paint(pboot_lpane->window);
984 twin_window_queue_paint(pboot_rpane->window);
986 if (!pboot_start_device_discovery(udev_trigger)) {
987 LOG("Couldn't start device discovery!\n");
992 twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
993 pboot_screen->event_filter = pboot_event_filter;
998 twin_fbdev_activate(pboot_fbdev);
1001 /* Process events */