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_INITIAL_MESSAGE "Petitboot v0.0.1"
33 #define PBOOT_LEFT_PANE_SIZE 160
34 #define PBOOT_LEFT_PANE_COLOR 0x80000000
35 #define PBOOT_LEFT_LINE_COLOR 0xff000000
37 #define PBOOT_LEFT_FOCUS_WIDTH 80
38 #define PBOOT_LEFT_FOCUS_HEIGHT 80
39 #define PBOOT_LEFT_FOCUS_XOFF 40
40 #define PBOOT_LEFT_FOCUS_YOFF 40
41 #define PBOOT_LEFT_FOCUS_XRAD (6 * TWIN_FIXED_ONE)
42 #define PBOOT_LEFT_FOCUS_YRAD (6 * TWIN_FIXED_ONE)
44 #define PBOOT_RIGHT_FOCUS_XOFF 20
45 #define PBOOT_RIGHT_FOCUS_YOFF 60
46 #define PBOOT_RIGHT_FOCUS_HEIGHT 80
47 #define PBOOT_RIGHT_FOCUS_XRAD (6 * TWIN_FIXED_ONE)
48 #define PBOOT_RIGHT_FOCUS_YRAD (6 * TWIN_FIXED_ONE)
50 #define PBOOT_LEFT_ICON_WIDTH 64
51 #define PBOOT_LEFT_ICON_HEIGHT 64
52 #define PBOOT_LEFT_ICON_XOFF 50
53 #define PBOOT_LEFT_ICON_YOFF 50
54 #define PBOOT_LEFT_ICON_STRIDE 100
56 #define PBOOT_RIGHT_OPTION_LMARGIN 30
57 #define PBOOT_RIGHT_OPTION_RMARGIN 30
58 #define PBOOT_RIGHT_OPTION_TMARGIN 70
59 #define PBOOT_RIGHT_OPTION_HEIGHT 64
60 #define PBOOT_RIGHT_OPTION_STRIDE 100
61 #define PBOOT_RIGHT_TITLE_TEXT_SIZE (30 * TWIN_FIXED_ONE)
62 #define PBOOT_RIGHT_SUBTITLE_TEXT_SIZE (18 * TWIN_FIXED_ONE)
63 #define PBOOT_RIGHT_TITLE_XOFFSET 80
64 #define PBOOT_RIGHT_TITLE_YOFFSET 30
65 #define PBOOT_RIGHT_SUBTITLE_XOFFSET 100
66 #define PBOOT_RIGHT_SUBTITLE_YOFFSET 50
67 #define PBOOT_RIGHT_BADGE_XOFFSET 2
68 #define PBOOT_RIGHT_BADGE_YOFFSET 0
71 #define PBOOT_RIGHT_TITLE_COLOR 0xff000000
72 #define PBOOT_RIGHT_SUBTITLE_COLOR 0xff400000
74 #define PBOOT_FOCUS_COLOR 0x10404040
76 #define PBOOT_STATUS_PANE_COLOR 0x60606060
77 #define PBOOT_STATUS_PANE_HEIGHT 20
78 #define PBOOT_STATUS_PANE_XYMARGIN 20
79 #define PBOOT_STATUS_TEXT_MARGIN 10
80 #define PBOOT_STATUS_TEXT_SIZE (16 * TWIN_FIXED_ONE)
81 #define PBOOT_STATUS_TEXT_COLOR 0xff000000
83 typedef struct _pboot_option pboot_option_t;
84 typedef struct _pboot_device pboot_device_t;
102 pboot_option_t options[PBOOT_MAX_OPTION];
105 static twin_pixmap_t *pboot_cursor;
106 static int pboot_cursor_hx;
107 static int pboot_cursor_hy;
109 static pboot_device_t *pboot_devices[PBOOT_MAX_DEV];
110 static int pboot_dev_count;
111 static int pboot_dev_sel = -1;
112 static int pboot_focus_lpane = 1;
114 typedef struct _pboot_lpane {
115 twin_window_t *window;
116 twin_rect_t focus_box;
123 typedef struct _pboot_rpane {
124 twin_window_t *window;
125 twin_rect_t focus_box;
132 typedef struct _pboot_spane {
133 twin_window_t *window;
137 static pboot_lpane_t *pboot_lpane;
138 static pboot_rpane_t *pboot_rpane;
139 static pboot_spane_t *pboot_spane;
141 /* XXX move to twin */
142 static inline twin_bool_t twin_rect_intersect(twin_rect_t r1,
145 return !(r1.left > r2.right ||
146 r1.right < r2.left ||
147 r1.top > r2.bottom ||
151 static void pboot_draw_option_cache(pboot_device_t *dev, pboot_option_t *opt,
159 px = twin_pixmap_create(TWIN_ARGB32, opt->box.right - opt->box.left,
160 opt->box.bottom - opt->box.top);
164 /* Fill background */
165 twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
167 /* Allocate a path for drawing */
168 path = twin_path_create();
172 /* TEST - Bounding rectangle */
173 twin_path_rectangle(path, 0, 0,
174 twin_int_to_fixed(px->width),
175 twin_int_to_fixed(px->height));
176 twin_paint_path(px, PBOOT_RIGHT_TITLE_COLOR, path);
177 twin_path_empty(path);
178 twin_fill(px, 0x00000000, TWIN_SOURCE, 2, 2,
179 px->width - 3, px->height - 3);
183 twin_path_set_font_size(path, PBOOT_RIGHT_TITLE_TEXT_SIZE);
184 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
185 tx = twin_int_to_fixed(PBOOT_RIGHT_TITLE_XOFFSET);
186 ty = twin_int_to_fixed(PBOOT_RIGHT_TITLE_YOFFSET);
187 twin_path_move (path, tx, ty);
188 twin_path_utf8 (path, opt->title);
189 twin_paint_path (px, PBOOT_RIGHT_TITLE_COLOR, path);
190 twin_path_empty (path);
193 twin_path_set_font_size(path, PBOOT_RIGHT_SUBTITLE_TEXT_SIZE);
194 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
195 tx = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_XOFFSET);
196 ty = twin_int_to_fixed(PBOOT_RIGHT_SUBTITLE_YOFFSET);
197 twin_path_move (path, tx, ty);
198 twin_path_utf8 (path, opt->subtitle);
199 twin_paint_path (px, PBOOT_RIGHT_SUBTITLE_COLOR, path);
200 twin_path_empty (path);
206 src.source_kind = TWIN_PIXMAP;
207 src.u.pixmap = opt->badge;
209 twin_composite(px, PBOOT_RIGHT_BADGE_XOFFSET,
210 PBOOT_RIGHT_BADGE_YOFFSET,
211 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
212 opt->badge->width, opt->badge->height);
217 twin_path_destroy(path);
220 static void pboot_rpane_draw(twin_window_t *window)
222 twin_pixmap_t *px = window->pixmap;
223 pboot_rpane_t *rpane = window->client_data;
226 twin_fixed_t x, y, w, h;
229 /* Fill background */
230 twin_fill(px, 0x00000000, TWIN_SOURCE, 0, 0, px->width, px->height);
232 /* Nothing to draw, return */
233 if (pboot_dev_sel < 0)
236 /* Create a path for use later */
237 path = twin_path_create();
241 if (rpane->focus_curindex >= 0 &&
242 twin_rect_intersect(rpane->focus_box, px->clip)) {
243 x = twin_int_to_fixed(rpane->focus_box.left + 2);
244 y = twin_int_to_fixed(rpane->focus_box.top + 2);
245 w = twin_int_to_fixed(rpane->focus_box.right -
246 rpane->focus_box.left - 4);
247 h = twin_int_to_fixed(rpane->focus_box.bottom -
248 rpane->focus_box.top - 4);
249 twin_path_rounded_rectangle(path, x, y, w, h,
250 PBOOT_RIGHT_FOCUS_XRAD,
251 PBOOT_RIGHT_FOCUS_YRAD);
252 if (!pboot_focus_lpane)
253 twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
255 twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
259 /* Get device and iterate through options */
260 dev = pboot_devices[pboot_dev_sel];
261 for (i = 0; i < dev->option_count; i++) {
262 pboot_option_t *opt = &dev->options[i];
265 if (opt->title == NULL)
267 if (!twin_rect_intersect(opt->box, px->clip))
269 if (opt->cache == NULL)
270 pboot_draw_option_cache(dev, opt, i);
272 src.source_kind = TWIN_PIXMAP;
273 src.u.pixmap = opt->cache;
275 twin_composite(px, opt->box.left, opt->box.top,
276 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
277 opt->box.right - opt->box.left,
278 opt->box.bottom - opt->box.top);
282 twin_path_destroy(path);
285 static twin_time_t pboot_rfocus_timeout (twin_time_t now, void *closure)
287 int dir = 1, dist, pos;
288 const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 2, 3, 4, 5 };
290 dist = abs(pboot_rpane->focus_target - pboot_rpane->focus_start);
291 dir = dist > 5 ? 5 : dist;
292 pos = pboot_rpane->focus_target - (int)pboot_rpane->focus_box.top;
300 twin_window_damage(pboot_rpane->window,
301 pboot_rpane->focus_box.left,
302 pboot_rpane->focus_box.top,
303 pboot_rpane->focus_box.right,
304 pboot_rpane->focus_box.bottom);
306 pboot_rpane->focus_box.top += dir;
307 pboot_rpane->focus_box.bottom += dir;
309 twin_window_damage(pboot_rpane->window,
310 pboot_rpane->focus_box.left,
311 pboot_rpane->focus_box.top,
312 pboot_rpane->focus_box.right,
313 pboot_rpane->focus_box.bottom);
315 twin_window_queue_paint(pboot_rpane->window);
317 return accel[(pos * 10) / dist];
320 static void pboot_set_rfocus(int index)
324 if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
326 dev = pboot_devices[pboot_dev_sel];
327 if (index < 0 || index >= dev->option_count)
330 pboot_rpane->focus_start = pboot_rpane->focus_box.top;
331 pboot_rpane->focus_target = PBOOT_RIGHT_FOCUS_YOFF +
332 PBOOT_RIGHT_OPTION_STRIDE * index;
333 pboot_rpane->focus_curindex = index;
335 twin_set_timeout(pboot_rfocus_timeout, 0, NULL);
338 static void pboot_select_rpane(void)
340 if (pboot_focus_lpane == 0)
342 pboot_focus_lpane = 0;
344 twin_screen_set_active(pboot_screen, pboot_rpane->window->pixmap);
346 twin_window_damage(pboot_lpane->window,
347 pboot_lpane->focus_box.left,
348 pboot_lpane->focus_box.top,
349 pboot_lpane->focus_box.right,
350 pboot_lpane->focus_box.bottom);
352 twin_window_damage(pboot_rpane->window,
353 pboot_rpane->focus_box.left,
354 pboot_rpane->focus_box.top,
355 pboot_rpane->focus_box.right,
356 pboot_rpane->focus_box.bottom);
358 twin_window_queue_paint(pboot_lpane->window);
359 twin_window_queue_paint(pboot_rpane->window);
364 static void pboot_select_lpane(void)
366 if (pboot_focus_lpane == 1)
368 pboot_focus_lpane = 1;
370 twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
372 twin_window_damage(pboot_lpane->window,
373 pboot_lpane->focus_box.left,
374 pboot_lpane->focus_box.top,
375 pboot_lpane->focus_box.right,
376 pboot_lpane->focus_box.bottom);
378 twin_window_damage(pboot_rpane->window,
379 pboot_rpane->focus_box.left,
380 pboot_rpane->focus_box.top,
381 pboot_rpane->focus_box.right,
382 pboot_rpane->focus_box.bottom);
384 twin_window_queue_paint(pboot_lpane->window);
385 twin_window_queue_paint(pboot_rpane->window);
388 static void pboot_rpane_mousetrack(twin_coord_t x, twin_coord_t y)
394 if (pboot_dev_sel < 0 || pboot_dev_sel >= pboot_dev_count)
396 dev = pboot_devices[pboot_dev_sel];
398 if (y < PBOOT_RIGHT_OPTION_TMARGIN)
400 candidate = (y - PBOOT_RIGHT_OPTION_TMARGIN) /
401 PBOOT_RIGHT_OPTION_STRIDE;
402 if (candidate >= dev->option_count) {
406 if (candidate == pboot_rpane->mouse_target)
408 opt = &dev->options[candidate];
409 if (x < opt->box.left || x > opt->box.right ||
410 y < opt->box.top || y > opt->box.bottom) {
415 /* Ok, so now, we know the mouse hit an icon that wasn't the same
416 * as the previous one, we trigger a focus change
418 pboot_set_rfocus(candidate);
421 pboot_rpane->mouse_target = candidate;
424 static void pboot_choose_option(void)
426 pboot_device_t *dev = pboot_devices[pboot_dev_sel];
427 pboot_option_t *opt = &dev->options[pboot_rpane->focus_curindex];
429 LOG("Selected device %s\n", opt->title);
431 /* Give user feedback, make sure errors and panics will be seen */
432 pboot_exec_option(opt->data);
435 static twin_bool_t pboot_rpane_event (twin_window_t *window,
438 /* filter out all mouse events */
439 switch(event->kind) {
441 case TwinEventMotion:
443 pboot_select_rpane();
444 pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
446 case TwinEventButtonDown:
447 pboot_select_rpane();
448 pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
449 pboot_choose_option();
450 case TwinEventButtonUp:
452 case TwinEventKeyDown:
453 switch(event->u.key.key) {
455 pboot_set_rfocus(pboot_rpane->focus_curindex - 1);
458 pboot_set_rfocus(pboot_rpane->focus_curindex + 1);
461 pboot_select_lpane();
464 pboot_choose_option();
476 int pboot_add_option(int devindex, const char *title,
477 const char *subtitle, twin_pixmap_t *badge, void *data)
484 if (devindex < 0 || devindex >= pboot_dev_count)
486 dev = pboot_devices[devindex];
488 if (dev->option_count >= PBOOT_MAX_OPTION)
490 index = dev->option_count++;
491 opt = &dev->options[index];
493 opt->title = malloc(strlen(title) + 1);
494 strcpy(opt->title, title);
497 opt->subtitle = malloc(strlen(subtitle) + 1);
498 strcpy(opt->subtitle, subtitle);
500 opt->subtitle = NULL;
505 width = pboot_rpane->window->pixmap->width -
506 (PBOOT_RIGHT_OPTION_LMARGIN + PBOOT_RIGHT_OPTION_RMARGIN);
508 opt->box.left = PBOOT_RIGHT_OPTION_LMARGIN;
509 opt->box.right = opt->box.left + width;
510 opt->box.top = PBOOT_RIGHT_OPTION_TMARGIN +
511 index * PBOOT_RIGHT_OPTION_STRIDE;
512 opt->box.bottom = opt->box.top + PBOOT_RIGHT_OPTION_HEIGHT;
519 static void pboot_set_device_select(int sel)
521 LOG("%s: %d -> %d\n", __FUNCTION__, pboot_dev_sel, sel);
522 if (sel == pboot_dev_sel || sel >= pboot_dev_count)
525 pboot_rpane->focus_curindex = -1;
526 pboot_rpane->mouse_target = -1;
527 pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
528 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
529 PBOOT_RIGHT_FOCUS_HEIGHT;
530 twin_window_damage(pboot_rpane->window, 0, 0,
531 pboot_rpane->window->pixmap->width,
532 pboot_rpane->window->pixmap->height);
533 twin_window_queue_paint(pboot_rpane->window);
536 static void pboot_create_rpane(void)
538 pboot_rpane = calloc(1, sizeof(pboot_rpane_t));
541 pboot_rpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
543 PBOOT_LEFT_PANE_SIZE, 0,
544 pboot_screen->width -
545 PBOOT_LEFT_PANE_SIZE,
546 pboot_screen->height);
547 assert(pboot_rpane->window);
549 pboot_rpane->window->draw = pboot_rpane_draw;
550 pboot_rpane->window->event = pboot_rpane_event;
551 pboot_rpane->window->client_data = pboot_rpane;
553 pboot_rpane->focus_curindex = -1;
554 pboot_rpane->focus_box.left = PBOOT_RIGHT_FOCUS_XOFF;
555 pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
556 pboot_rpane->focus_box.right = pboot_rpane->window->pixmap->width -
557 2 * PBOOT_RIGHT_FOCUS_XOFF;
558 pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
559 PBOOT_RIGHT_FOCUS_HEIGHT;
560 pboot_rpane->mouse_target = -1;
561 twin_window_show(pboot_rpane->window);
562 twin_window_queue_paint(pboot_rpane->window);
566 static twin_time_t pboot_lfocus_timeout (twin_time_t now, void *closure)
568 int dir = 1, dist, pos;
569 const int accel[11] = { 7, 4, 2, 1, 1, 1, 1, 2, 3, 4, 5 };
571 dist = abs(pboot_lpane->focus_target - pboot_lpane->focus_start);
572 pos = pboot_lpane->focus_target - (int)pboot_lpane->focus_box.top;
574 pboot_set_device_select(pboot_lpane->focus_curindex);
581 twin_window_damage(pboot_lpane->window,
582 pboot_lpane->focus_box.left,
583 pboot_lpane->focus_box.top,
584 pboot_lpane->focus_box.right,
585 pboot_lpane->focus_box.bottom);
587 pboot_lpane->focus_box.top += dir;
588 pboot_lpane->focus_box.bottom += dir;
590 twin_window_damage(pboot_lpane->window,
591 pboot_lpane->focus_box.left,
592 pboot_lpane->focus_box.top,
593 pboot_lpane->focus_box.right,
594 pboot_lpane->focus_box.bottom);
596 twin_window_queue_paint(pboot_lpane->window);
598 return accel[(pos * 10) / dist];
601 static void pboot_set_lfocus(int index)
603 if (index >= pboot_dev_count)
606 pboot_lpane->focus_start = pboot_lpane->focus_box.top;
609 pboot_lpane->focus_target = 0 - PBOOT_LEFT_FOCUS_HEIGHT;
611 pboot_lpane->focus_target = PBOOT_LEFT_FOCUS_YOFF +
612 PBOOT_LEFT_ICON_STRIDE * index;
614 pboot_lpane->focus_curindex = index;
616 twin_set_timeout(pboot_lfocus_timeout, 0, NULL);
619 static void pboot_lpane_mousetrack(twin_coord_t x, twin_coord_t y)
622 twin_coord_t icon_top;
624 if (x < PBOOT_LEFT_ICON_XOFF ||
625 x > (PBOOT_LEFT_ICON_XOFF + PBOOT_LEFT_ICON_WIDTH))
627 if (y < PBOOT_LEFT_ICON_YOFF)
629 candidate = (y - PBOOT_LEFT_ICON_YOFF) / PBOOT_LEFT_ICON_STRIDE;
630 if (candidate >= pboot_dev_count) {
634 if (candidate == pboot_lpane->mouse_target)
636 icon_top = PBOOT_LEFT_ICON_YOFF +
637 candidate * PBOOT_LEFT_ICON_STRIDE;
638 if (y > (icon_top + PBOOT_LEFT_ICON_HEIGHT)) {
643 /* Ok, so now, we know the mouse hit an icon that wasn't the same
644 * as the previous one, we trigger a focus change
646 pboot_set_lfocus(candidate);
649 pboot_lpane->mouse_target = candidate;
652 static twin_bool_t pboot_lpane_event (twin_window_t *window,
655 /* filter out all mouse events */
656 switch(event->kind) {
658 case TwinEventMotion:
660 pboot_select_lpane();
661 pboot_lpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
663 case TwinEventButtonDown:
664 case TwinEventButtonUp:
666 case TwinEventKeyDown:
667 switch(event->u.key.key) {
669 if (pboot_lpane->focus_curindex > 0)
671 pboot_lpane->focus_curindex - 1);
674 pboot_set_lfocus(pboot_lpane->focus_curindex + 1);
677 pboot_select_rpane();
689 twin_bool_t pboot_event_filter(twin_screen_t *screen,
692 switch(event->kind) {
694 case TwinEventMotion:
696 case TwinEventButtonDown:
697 case TwinEventButtonUp:
698 if (pboot_cursor != NULL)
699 twin_screen_set_cursor(pboot_screen, pboot_cursor,
703 case TwinEventKeyDown:
705 twin_screen_set_cursor(pboot_screen, NULL, 0, 0);
713 static void pboot_lpane_draw(twin_window_t *window)
715 twin_pixmap_t *px = window->pixmap;
716 pboot_lpane_t *lpane = window->client_data;
718 twin_fixed_t x, y, w, h;
721 /* Fill background */
722 twin_fill(px, PBOOT_LEFT_PANE_COLOR, TWIN_SOURCE,
723 0, 0, px->width, px->height);
725 /* Create a path for use later */
726 path = twin_path_create();
729 /* Draw right line if needed */
730 if (px->clip.right > (PBOOT_LEFT_PANE_SIZE - 4)) {
731 x = twin_int_to_fixed(PBOOT_LEFT_PANE_SIZE - 4);
732 y = twin_int_to_fixed(px->height);
733 twin_path_rectangle(path, x, 0, 0x40000, y);
734 twin_paint_path(px, PBOOT_LEFT_LINE_COLOR, path);
735 twin_path_empty(path);
739 if (lpane->focus_curindex >= 0 &&
740 twin_rect_intersect(lpane->focus_box, px->clip)) {
741 x = twin_int_to_fixed(lpane->focus_box.left + 2);
742 y = twin_int_to_fixed(lpane->focus_box.top + 2);
743 w = twin_int_to_fixed(lpane->focus_box.right -
744 lpane->focus_box.left - 4);
745 h = twin_int_to_fixed(lpane->focus_box.bottom -
746 lpane->focus_box.top - 4);
747 twin_path_rounded_rectangle(path, x, y, w, h,
748 PBOOT_LEFT_FOCUS_XRAD,
749 PBOOT_LEFT_FOCUS_YRAD);
750 if (pboot_focus_lpane)
751 twin_paint_path(px, PBOOT_FOCUS_COLOR, path);
753 twin_paint_stroke(px, PBOOT_FOCUS_COLOR, path,
758 for (i = 0; i < pboot_dev_count; i++) {
759 pboot_device_t *dev = pboot_devices[i];
762 if (!twin_rect_intersect(dev->box, px->clip))
765 src.source_kind = TWIN_PIXMAP;
766 src.u.pixmap = dev->badge;
768 twin_composite(px, dev->box.left, dev->box.top,
769 &src, 0, 0, NULL, 0, 0, TWIN_OVER,
770 dev->box.right - dev->box.left,
771 dev->box.bottom - dev->box.top);
776 twin_path_destroy(path);
779 static void pboot_create_lpane(void)
781 pboot_lpane = calloc(1, sizeof(pboot_lpane_t));
784 pboot_lpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
786 0, 0, PBOOT_LEFT_PANE_SIZE,
787 pboot_screen->height);
788 assert(pboot_lpane->window);
790 pboot_lpane->window->draw = pboot_lpane_draw;
791 pboot_lpane->window->event = pboot_lpane_event;
792 pboot_lpane->window->client_data = pboot_lpane;
793 pboot_lpane->focus_curindex = -1;
794 pboot_lpane->focus_box.left = PBOOT_LEFT_FOCUS_XOFF;
795 pboot_lpane->focus_box.top = -2*PBOOT_LEFT_FOCUS_HEIGHT;
796 pboot_lpane->focus_box.right = pboot_lpane->focus_box.left +
797 PBOOT_LEFT_FOCUS_WIDTH;
798 pboot_lpane->focus_box.bottom = pboot_lpane->focus_box.top +
799 PBOOT_LEFT_FOCUS_HEIGHT;
800 pboot_lpane->mouse_target = -1;
801 twin_window_show(pboot_lpane->window);
802 twin_window_queue_paint(pboot_lpane->window);
805 static void pboot_spane_draw(twin_window_t *window)
807 twin_pixmap_t *px = window->pixmap;
808 pboot_spane_t *spane = window->client_data;
812 /* Fill background */
813 twin_fill(px, PBOOT_STATUS_PANE_COLOR, TWIN_SOURCE,
814 0, 0, px->width, px->height);
816 path = twin_path_create();
819 twin_path_set_font_size(path, PBOOT_STATUS_TEXT_SIZE);
820 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
821 tx = twin_int_to_fixed(PBOOT_STATUS_TEXT_MARGIN);
822 ty = twin_int_to_fixed(PBOOT_STATUS_PANE_HEIGHT - 2);
823 twin_path_move (path, tx, ty);
824 twin_path_utf8 (path, spane->text);
825 twin_paint_path (px, PBOOT_STATUS_TEXT_COLOR, path);
827 twin_path_destroy(path);
830 static void pboot_create_spane(void)
832 pboot_spane = calloc(1, sizeof(pboot_spane_t));
835 pboot_spane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
837 PBOOT_LEFT_PANE_SIZE +
838 PBOOT_STATUS_PANE_XYMARGIN,
839 pboot_screen->height -
840 PBOOT_STATUS_PANE_HEIGHT,
841 pboot_screen->width -
842 PBOOT_LEFT_PANE_SIZE -
843 2*PBOOT_STATUS_PANE_XYMARGIN,
844 PBOOT_STATUS_PANE_HEIGHT);
845 assert(pboot_spane->window);
847 pboot_spane->window->draw = pboot_spane_draw;
848 pboot_spane->window->client_data = pboot_spane;
849 pboot_spane->text = PBOOT_INITIAL_MESSAGE;
850 twin_window_show(pboot_spane->window);
851 twin_window_queue_paint(pboot_spane->window);
854 int pboot_add_device(const char *dev_id, const char *name,
855 twin_pixmap_t *pixmap)
860 if (pboot_dev_count >= PBOOT_MAX_DEV)
863 index = pboot_dev_count++;
865 dev = malloc(sizeof(*dev));
866 memset(dev, 0, sizeof(*dev));
867 dev->id = malloc(strlen(dev_id) + 1);
868 strcpy(dev->id, dev_id);
870 dev->box.left = PBOOT_LEFT_ICON_XOFF;
871 dev->box.right = dev->box.left + PBOOT_LEFT_ICON_WIDTH;
872 dev->box.top = PBOOT_LEFT_ICON_YOFF +
873 PBOOT_LEFT_ICON_STRIDE * index;
874 dev->box.bottom = dev->box.top + PBOOT_LEFT_ICON_HEIGHT;
876 pboot_devices[index] = dev;
878 twin_window_damage(pboot_lpane->window,
879 dev->box.left, dev->box.top,
880 dev->box.right, dev->box.bottom);
881 twin_window_queue_paint(pboot_lpane->window);
886 int pboot_remove_device(const char *dev_id)
888 int i, new_dev_index;
889 pboot_device_t *dev = NULL;
891 /* find the matching device */
892 for (i = 0; i < pboot_dev_count; i++) {
893 if (!strcmp(pboot_devices[i]->id, dev_id)) {
894 dev = pboot_devices[i];
902 /* select the newly-focussed device */
903 if (i == pboot_dev_count - 1)
904 new_dev_index = i - 1;
906 new_dev_index = i + 1;
908 memmove(pboot_devices + i, pboot_devices + i + 1,
909 sizeof(*pboot_devices) * (pboot_dev_count + i - 1));
911 pboot_devices[--pboot_dev_count] = NULL;
913 pboot_set_device_select(new_dev_index);
914 twin_window_damage(pboot_lpane->window,
915 dev->box.left, dev->box.top,
916 dev->box.right, dev->box.bottom);
917 twin_window_queue_paint(pboot_lpane->window);
919 /* todo: free device & options */
924 static void pboot_make_background(void)
926 twin_pixmap_t *filepic, *scaledpic;
927 const char *background_path;
929 /* Set background pixmap */
930 LOG("loading background...");
931 background_path = artwork_pathname("background.jpg");
932 filepic = twin_jpeg_to_pixmap(background_path, TWIN_ARGB32);
933 LOG("%s\n", filepic ? "ok" : "failed");
938 if (pboot_screen->height == filepic->height &&
939 pboot_screen->width == filepic->width)
943 twin_operand_t srcop;
945 scaledpic = twin_pixmap_create(TWIN_ARGB32,
947 pboot_screen->height);
948 if (scaledpic == NULL) {
949 twin_pixmap_destroy(filepic);
952 sx = twin_fixed_div(twin_int_to_fixed(filepic->width),
953 twin_int_to_fixed(pboot_screen->width));
954 sy = twin_fixed_div(twin_int_to_fixed(filepic->height),
955 twin_int_to_fixed(pboot_screen->height));
957 twin_matrix_scale(&filepic->transform, sx, sy);
958 srcop.source_kind = TWIN_PIXMAP;
959 srcop.u.pixmap = filepic;
960 twin_composite(scaledpic, 0, 0, &srcop, 0, 0,
961 NULL, 0, 0, TWIN_SOURCE,
962 pboot_screen->width, pboot_screen->height);
963 twin_pixmap_destroy(filepic);
966 twin_screen_set_background(pboot_screen, scaledpic);
969 static void exitfunc(void)
973 twin_fbdev_destroy(pboot_fbdev);
978 static void sigint(int sig)
984 int main(int argc, char **argv)
987 signal(SIGINT, sigint);
990 pboot_x11 = twin_x11_create(XOpenDisplay(0), 1024, 768);
991 if (pboot_x11 == NULL) {
992 perror("failed to create x11 screen !\n");
995 pboot_screen = pboot_x11->screen;
997 /* Create screen and mouse drivers */
998 pboot_fbdev = twin_fbdev_create(-1, SIGUSR1);
999 if (pboot_fbdev == NULL) {
1000 perror("failed to create fbdev screen !\n");
1003 pboot_screen = pboot_fbdev->screen;
1004 twin_linux_mouse_create(NULL, pboot_screen);
1006 if (pboot_fbdev != NULL) {
1007 char *cursor_path = artwork_pathname("cursor");
1008 pboot_cursor = twin_load_X_cursor(cursor_path, 2,
1011 if (pboot_cursor == NULL)
1013 twin_get_default_cursor(&pboot_cursor_hx,
1018 /* Set background pixmap */
1019 pboot_make_background();
1021 /* Init more stuffs */
1022 pboot_create_lpane();
1023 pboot_create_rpane();
1024 pboot_create_spane();
1026 if (!pboot_start_device_discovery()) {
1027 LOG("Couldn't start device discovery!\n");
1031 pboot_set_lfocus(0);
1032 twin_screen_set_active(pboot_screen, pboot_lpane->window->pixmap);
1033 pboot_screen->event_filter = pboot_event_filter;
1035 /* Console switch */
1038 twin_fbdev_activate(pboot_fbdev);
1041 /* Process events */