]> git.ozlabs.org Git - petitboot/blobdiff - petitboot.c
Add a status message bar
[petitboot] / petitboot.c
index 44e1cc87b394755b0cdc745725e07916a6f028be..478b294e7ec0f8d07dd9f643e2a5e299027b1678 100644 (file)
@@ -1,4 +1,5 @@
 #include <stdio.h>
+#include <string.h>
 #include <stdlib.h>
 #include <signal.h>
 #include <unistd.h>
@@ -7,29 +8,36 @@
 
 #include <linux/input.h>
 
+#undef _USE_X11
+
 #include <libtwin/twin.h>
-#include <libtwin/twin_fbdev.h>
-#include <libtwin/twin_x11.h>
 #include <libtwin/twin_linux_mouse.h>
 #include <libtwin/twin_png.h>
+#include <libtwin/twin_jpeg.h>
 
 #include "petitboot.h"
 #include "petitboot-paths.h"
 
-#define _USE_X11
-
-static twin_fbdev_t *pboot_fbdev;
+#ifdef _USE_X11
+#include <libtwin/twin_x11.h>
 static twin_x11_t *pboot_x11;
+#else
+#include <libtwin/twin_fbdev.h>
+static twin_fbdev_t *pboot_fbdev;
+#endif
+
 static twin_screen_t *pboot_screen;
 
-#define PBOOT_LEFT_PANE_SIZE           200
+#define PBOOT_INITIAL_MESSAGE          "Petitboot v0.0.1"
+
+#define PBOOT_LEFT_PANE_SIZE           160
 #define PBOOT_LEFT_PANE_COLOR          0x80000000
 #define PBOOT_LEFT_LINE_COLOR          0xff000000
 
 #define PBOOT_LEFT_FOCUS_WIDTH         80
 #define PBOOT_LEFT_FOCUS_HEIGHT                80
-#define PBOOT_LEFT_FOCUS_XOFF          60
-#define PBOOT_LEFT_FOCUS_YOFF          60
+#define PBOOT_LEFT_FOCUS_XOFF          40
+#define PBOOT_LEFT_FOCUS_YOFF          40
 #define PBOOT_LEFT_FOCUS_XRAD          (6 * TWIN_FIXED_ONE)
 #define PBOOT_LEFT_FOCUS_YRAD          (6 * TWIN_FIXED_ONE)
 
@@ -41,8 +49,8 @@ static twin_screen_t *pboot_screen;
 
 #define PBOOT_LEFT_ICON_WIDTH          64
 #define PBOOT_LEFT_ICON_HEIGHT         64
-#define PBOOT_LEFT_ICON_XOFF           70
-#define PBOOT_LEFT_ICON_YOFF           70
+#define PBOOT_LEFT_ICON_XOFF           50
+#define PBOOT_LEFT_ICON_YOFF           50
 #define PBOOT_LEFT_ICON_STRIDE         100
 
 #define PBOOT_RIGHT_OPTION_LMARGIN     30
@@ -54,7 +62,7 @@ static twin_screen_t *pboot_screen;
 #define PBOOT_RIGHT_SUBTITLE_TEXT_SIZE (18 * TWIN_FIXED_ONE)
 #define PBOOT_RIGHT_TITLE_XOFFSET      80
 #define PBOOT_RIGHT_TITLE_YOFFSET      30
-#define PBOOT_RIGHT_SUBTITLE_XOFFSET   200
+#define PBOOT_RIGHT_SUBTITLE_XOFFSET   100
 #define PBOOT_RIGHT_SUBTITLE_YOFFSET   50
 #define PBOOT_RIGHT_BADGE_XOFFSET      2
 #define PBOOT_RIGHT_BADGE_YOFFSET      0
@@ -65,6 +73,12 @@ static twin_screen_t *pboot_screen;
 
 #define PBOOT_FOCUS_COLOR              0x10404040
 
+#define PBOOT_STATUS_PANE_COLOR                0x60606060
+#define PBOOT_STATUS_PANE_HEIGHT       20
+#define PBOOT_STATUS_PANE_XYMARGIN     20
+#define PBOOT_STATUS_TEXT_MARGIN       10
+#define PBOOT_STATUS_TEXT_SIZE         (16 * TWIN_FIXED_ONE)
+#define PBOOT_STATUS_TEXT_COLOR                0xff000000
 
 typedef struct _pboot_option pboot_option_t;
 typedef struct _pboot_device pboot_device_t;
@@ -76,6 +90,7 @@ struct _pboot_option
        twin_pixmap_t   *badge;
        twin_pixmap_t   *cache;
        twin_rect_t     box;
+       void            *data;
 };
 
 struct _pboot_device
@@ -114,8 +129,14 @@ typedef struct _pboot_rpane {
        int             mouse_target;
 } pboot_rpane_t;
 
+typedef struct _pboot_spane {
+       twin_window_t   *window;
+       char            *text;
+} pboot_spane_t;
+
 static pboot_lpane_t   *pboot_lpane;
 static pboot_rpane_t   *pboot_rpane;
+static pboot_spane_t   *pboot_spane;
 
 /* XXX move to twin */
 static inline twin_bool_t twin_rect_intersect(twin_rect_t r1,
@@ -400,6 +421,17 @@ static void pboot_rpane_mousetrack(twin_coord_t x, twin_coord_t y)
        pboot_rpane->mouse_target = candidate;
 }
 
+static void pboot_choose_option(void)
+{
+       pboot_device_t *dev = pboot_devices[pboot_dev_sel];
+       pboot_option_t *opt = &dev->options[pboot_rpane->focus_curindex];
+
+       LOG("Selected device %s\n", opt->title);
+
+       /* Give user feedback, make sure errors and panics will be seen */
+       pboot_exec_option(opt->data);
+}
+
 static twin_bool_t pboot_rpane_event (twin_window_t        *window,
                                      twin_event_t          *event)
 {
@@ -412,6 +444,9 @@ static twin_bool_t pboot_rpane_event (twin_window_t     *window,
                pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
                return TWIN_TRUE;
        case TwinEventButtonDown:
+               pboot_select_rpane();
+               pboot_rpane_mousetrack(event->u.pointer.x, event->u.pointer.y);
+               pboot_choose_option();
        case TwinEventButtonUp:
                return TWIN_TRUE;
        case TwinEventKeyDown:
@@ -425,6 +460,8 @@ static twin_bool_t pboot_rpane_event (twin_window_t     *window,
                case KEY_LEFT:
                        pboot_select_lpane();
                        return TWIN_TRUE;
+               case KEY_ENTER:
+                       pboot_choose_option();
                default:
                        break;
                }
@@ -437,7 +474,7 @@ static twin_bool_t pboot_rpane_event (twin_window_t     *window,
 
 
 int pboot_add_option(int devindex, const char *title,
-                           const char *subtitle, twin_pixmap_t *badge)
+                    const char *subtitle, twin_pixmap_t *badge, void *data)
 {
        pboot_device_t  *dev;
        pboot_option_t  *opt;
@@ -474,6 +511,7 @@ int pboot_add_option(int devindex, const char *title,
                index * PBOOT_RIGHT_OPTION_STRIDE;
        opt->box.bottom = opt->box.top + PBOOT_RIGHT_OPTION_HEIGHT;
 
+       opt->data = data;
        return index;
 }
 
@@ -495,6 +533,36 @@ static void pboot_set_device_select(int sel)
        twin_window_queue_paint(pboot_rpane->window);
 }
 
+static void pboot_create_rpane(void)
+{
+       pboot_rpane = calloc(1, sizeof(pboot_rpane_t));
+       assert(pboot_rpane);
+
+       pboot_rpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
+                                                TwinWindowPlain,
+                                                PBOOT_LEFT_PANE_SIZE, 0,
+                                                pboot_screen->width -
+                                                  PBOOT_LEFT_PANE_SIZE,
+                                                pboot_screen->height);
+       assert(pboot_rpane->window);
+
+       pboot_rpane->window->draw = pboot_rpane_draw;
+       pboot_rpane->window->event = pboot_rpane_event;
+       pboot_rpane->window->client_data = pboot_rpane;
+
+       pboot_rpane->focus_curindex = -1;
+       pboot_rpane->focus_box.left = PBOOT_RIGHT_FOCUS_XOFF;
+       pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
+       pboot_rpane->focus_box.right = pboot_rpane->window->pixmap->width -
+               2 * PBOOT_RIGHT_FOCUS_XOFF;
+       pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
+               PBOOT_RIGHT_FOCUS_HEIGHT;
+       pboot_rpane->mouse_target = -1;
+       twin_window_show(pboot_rpane->window);
+       twin_window_queue_paint(pboot_rpane->window);
+}
+
+
 static twin_time_t pboot_lfocus_timeout (twin_time_t now, void *closure)
 {
        int dir = 1, dist, pos;
@@ -708,9 +776,8 @@ static void pboot_lpane_draw(twin_window_t *window)
        twin_path_destroy(path);
 }
 
-static void pboot_create_panels(void)
+static void pboot_create_lpane(void)
 {
-       /* left pane */
        pboot_lpane = calloc(1, sizeof(pboot_lpane_t));
        assert(pboot_lpane);
 
@@ -732,32 +799,56 @@ static void pboot_create_panels(void)
                PBOOT_LEFT_FOCUS_HEIGHT;
        pboot_lpane->mouse_target = -1;
        twin_window_show(pboot_lpane->window);
+       twin_window_queue_paint(pboot_lpane->window);
+}
 
-       /* right pane */
-       pboot_rpane = calloc(1, sizeof(pboot_rpane_t));
-       assert(pboot_rpane);
+static void pboot_spane_draw(twin_window_t *window)
+{
+       twin_pixmap_t   *px = window->pixmap;
+       pboot_spane_t   *spane = window->client_data;
+       twin_path_t     *path;
+       twin_fixed_t    tx, ty;
 
-       pboot_rpane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
-                                                TwinWindowPlain,
-                                                PBOOT_LEFT_PANE_SIZE, 0,
-                                                pboot_screen->width -
-                                                  PBOOT_LEFT_PANE_SIZE,
-                                                pboot_screen->height);
-       assert(pboot_rpane->window);
+       /* Fill background */
+       twin_fill(px, PBOOT_STATUS_PANE_COLOR, TWIN_SOURCE,
+                 0, 0, px->width, px->height);
 
-       pboot_rpane->window->draw = pboot_rpane_draw;
-       pboot_rpane->window->event = pboot_rpane_event;
-       pboot_rpane->window->client_data = pboot_rpane;
+       path = twin_path_create();
+       assert(path);
 
-       pboot_rpane->focus_curindex = -1;
-       pboot_rpane->focus_box.left = PBOOT_RIGHT_FOCUS_XOFF;
-       pboot_rpane->focus_box.top = -2*PBOOT_RIGHT_FOCUS_HEIGHT;
-       pboot_rpane->focus_box.right = pboot_rpane->window->pixmap->width -
-               2 * PBOOT_RIGHT_FOCUS_XOFF;
-       pboot_rpane->focus_box.bottom = pboot_rpane->focus_box.top +
-               PBOOT_RIGHT_FOCUS_HEIGHT;
-       pboot_rpane->mouse_target = -1;
-       twin_window_show(pboot_rpane->window);
+       twin_path_set_font_size(path, PBOOT_STATUS_TEXT_SIZE);
+       twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
+       tx = twin_int_to_fixed(PBOOT_STATUS_TEXT_MARGIN);
+       ty = twin_int_to_fixed(PBOOT_STATUS_PANE_HEIGHT - 2);
+       twin_path_move (path, tx, ty);
+       twin_path_utf8 (path, spane->text);
+       twin_paint_path (px, PBOOT_STATUS_TEXT_COLOR, path);
+
+       twin_path_destroy(path);
+}
+
+static void pboot_create_spane(void)
+{
+       pboot_spane = calloc(1, sizeof(pboot_spane_t));
+       assert(pboot_spane);
+
+       pboot_spane->window = twin_window_create(pboot_screen, TWIN_ARGB32,
+                                                TwinWindowPlain,
+                                                PBOOT_LEFT_PANE_SIZE +
+                                                 PBOOT_STATUS_PANE_XYMARGIN,
+                                                pboot_screen->height - 
+                                                 PBOOT_STATUS_PANE_HEIGHT,
+                                                pboot_screen->width -
+                                                 PBOOT_LEFT_PANE_SIZE -
+                                                 2*PBOOT_STATUS_PANE_XYMARGIN,
+                                                PBOOT_STATUS_PANE_HEIGHT);
+       assert(pboot_spane->window);
+
+       pboot_spane->window->draw = pboot_spane_draw;
+       pboot_spane->window->client_data = pboot_spane;
+       pboot_spane->text = PBOOT_INITIAL_MESSAGE;
+       twin_window_show(pboot_spane->window);
+       twin_window_queue_paint(pboot_spane->window);
 }
 
 int pboot_add_device(const char *dev_id, const char *name,
@@ -830,11 +921,58 @@ int pboot_remove_device(const char *dev_id)
        return TWIN_TRUE;
 }
 
+static void pboot_make_background(void)
+{
+       twin_pixmap_t   *filepic, *scaledpic;
+       const char      *background_path;
+
+       /* Set background pixmap */
+       LOG("loading background...");
+       background_path = artwork_pathname("background.jpg");
+       filepic = twin_jpeg_to_pixmap(background_path, TWIN_ARGB32);
+       LOG("%s\n", filepic ? "ok" : "failed");
+
+       if (filepic == NULL)
+               return;
+
+       if (pboot_screen->height == filepic->height &&
+           pboot_screen->width == filepic->width)
+               scaledpic = filepic;
+       else {
+               twin_fixed_t    sx, sy;
+               twin_operand_t  srcop;
+
+               scaledpic = twin_pixmap_create(TWIN_ARGB32,
+                                              pboot_screen->width,
+                                              pboot_screen->height);
+               if (scaledpic == NULL) {
+                       twin_pixmap_destroy(filepic);
+                       return;
+               }
+               sx = twin_fixed_div(twin_int_to_fixed(filepic->width),
+                                   twin_int_to_fixed(pboot_screen->width));
+               sy = twin_fixed_div(twin_int_to_fixed(filepic->height),
+                                   twin_int_to_fixed(pboot_screen->height));
+               
+               twin_matrix_scale(&filepic->transform, sx, sy);
+               srcop.source_kind = TWIN_PIXMAP;
+               srcop.u.pixmap = filepic;
+               twin_composite(scaledpic, 0, 0, &srcop, 0, 0,
+                              NULL, 0, 0, TWIN_SOURCE,
+                              pboot_screen->width, pboot_screen->height);
+               twin_pixmap_destroy(filepic);
+                              
+       }
+       twin_screen_set_background(pboot_screen, scaledpic);
+}
+
 static void exitfunc(void)
 {
+#ifndef _USE_X11
        if (pboot_fbdev)
                twin_fbdev_destroy(pboot_fbdev);
        pboot_fbdev = NULL;
+#endif
 }
 
 static void sigint(int sig)
@@ -845,9 +983,6 @@ static void sigint(int sig)
 
 int main(int argc, char **argv)
 {
-       twin_pixmap_t *pic;
-       const char *background_path;
-
        atexit(exitfunc);
        signal(SIGINT, sigint);
 
@@ -867,7 +1002,6 @@ int main(int argc, char **argv)
        }
        pboot_screen = pboot_fbdev->screen;
        twin_linux_mouse_create(NULL, pboot_screen);
-#endif
 
        if (pboot_fbdev != NULL) {
                char *cursor_path = artwork_pathname("cursor");
@@ -879,19 +1013,15 @@ int main(int argc, char **argv)
                                twin_get_default_cursor(&pboot_cursor_hx,
                                                        &pboot_cursor_hy);
        }
+#endif
 
        /* Set background pixmap */
-       background_path = artwork_pathname("background.png");
-       LOG("loading background: %s...", background_path);
-       pic = twin_png_to_pixmap(background_path, TWIN_ARGB32);
-       LOG("%s\n", pic ? "ok" : "failed");
-       if (pic)
-               twin_screen_set_background(pboot_screen, pic);
+       pboot_make_background();
 
        /* Init more stuffs */
-       pboot_create_panels();
-       twin_window_queue_paint(pboot_lpane->window);
-       twin_window_queue_paint(pboot_rpane->window);
+       pboot_create_lpane();
+       pboot_create_rpane();
+       pboot_create_spane();
 
        if (!pboot_start_device_discovery()) {
                LOG("Couldn't start device discovery!\n");
@@ -903,8 +1033,10 @@ int main(int argc, char **argv)
        pboot_screen->event_filter = pboot_event_filter;
 
        /* Console switch */
+#ifndef _USE_X11
        if (pboot_fbdev)
                twin_fbdev_activate(pboot_fbdev);
+#endif
 
        /* Process events */
        twin_dispatch ();