altos/draw: Rename test app to 'lco-test'
authorKeith Packard <keithp@keithp.com>
Mon, 27 Feb 2023 00:04:17 +0000 (16:04 -0800)
committerKeith Packard <keithp@keithp.com>
Mon, 27 Feb 2023 00:08:08 +0000 (16:08 -0800)
This seems like a good place to do the LCO UX prototyping

Signed-off-by: Keith Packard <keithp@keithp.com>
src/draw/.gitignore
src/draw/Makefile
src/draw/draw-test.c [deleted file]
src/draw/lco-test.c [new file with mode: 0644]

index 85d262530812d12e5133ef964ecd2040c725180b..8e744beafae284f091549f97dc2d80ac0c8c75ce 100644 (file)
@@ -4,4 +4,4 @@ Bitstream*.c
 NotoMono*.c
 ao_font.h
 ao_logo.h
-draw-test
+lco-test
index ccedc6a149caaef72d0b910b657932a93c637186..47336fbef3ca19168b45e90c650cb7570c21e895 100644 (file)
@@ -79,7 +79,7 @@ FONT_SRCS=$(BDFS:.bdf=.c)
 .bdf.c:
        nickle font-convert -o $@ $<
 
-all: ao_font.h ao_logo.h draw-test
+all: ao_font.h ao_logo.h lco-test
 
 $(FONT_SRCS): font-convert
 
@@ -89,8 +89,7 @@ ao_font.h: $(FONT_SRCS)
 ao_logo.h: make-logo
        nickle make-logo ao_logo > $@
 
-SRCS=\
-       draw-test.c \
+LIB_SRCS=\
        ao_blt.c \
        ao_copy.c \
        ao_line.c \
@@ -101,9 +100,10 @@ SRCS=\
        ao_logo.c \
        $(FONT_SRCS)
 
-OBJS=$(SRCS:.c=.o)
+LCO_TEST_SRCS=$(LIB_SRCS) lco-test.c
+LCO_TEST_OBJS=$(LCO_TEST_SRCS:.c=.o)
 
-LIBS=-lXrender -lX11 -lm -Wl,--gc-sections
+TEST_LIBS=-lXrender -lX11 -lm -Wl,--gc-sections
 
 CFLAGS=-O0 -g $(WARN_FLAGS)
 
@@ -113,10 +113,10 @@ HEADERS=\
        ao_font.h \
        ao_logo.h
 
-draw-test: $(OBJS)
-       cc $(CFLAGS) -o $@ $(OBJS) $(LIBS)
+lco-test: $(LCO_TEST_OBJS)
+       cc $(CFLAGS) -o $@ $(LCO_TEST_OBJS) $(TEST_LIBS)
 
-$(OBJS): $(HEADERS)
+$(LCO_TEST_OBJS): $(HEADERS)
 
 clean:
-       rm -f $(OBJS) ao_font.h ao_logo.h $(FONT_SRCS)
+       rm -f $(LCO_TEST_OBJS) ao_font.h ao_logo.h $(FONT_SRCS)
diff --git a/src/draw/draw-test.c b/src/draw/draw-test.c
deleted file mode 100644 (file)
index 0221fbb..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Copyright © 2023 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#define IMAGE_SCALE    8
-#define WIDTH  128
-#define HEIGHT 64
-
-#define IMAGE_WIDTH    (WIDTH * IMAGE_SCALE)
-#define IMAGE_HEIGHT   (HEIGHT * IMAGE_SCALE)
-
-#define DEFAULT_WIDTH  IMAGE_WIDTH
-#define DEFAULT_HEIGHT IMAGE_HEIGHT
-
-#define TIMEOUT        50
-
-#define PASS_KEYS
-#include "frame.c"
-#include "ao_draw.h"
-
-#define STRIDE ((WIDTH + 31) / 32)
-
-static uint32_t bits[STRIDE * HEIGHT];
-
-static struct ao_bitmap fb = {
-       .base = bits,
-       .stride = STRIDE,
-       .width = WIDTH,
-       .height = HEIGHT
-};
-
-#define BIG_FONT FrutigerLT_Roman_64_font
-#define VOLT_FONT FrutigerLT_Roman_64_font
-#define SMALL_FONT NotoMono_12_font
-#define TINY_FONT NotoMono_10_font
-#define LOGO_FONT BenguiatGothicStd_Bold_26_font
-
-#define LABEL_Y                (int16_t) (SMALL_FONT.ascent)
-#define VALUE_Y                (int16_t) (LABEL_Y + BIG_FONT.ascent)
-#define BOX_X          2
-#define PAD_X          90
-#define BOX_LABEL_X    30
-#define VOLT_LABEL_X   25
-#define RSSI_LABEL_X   15
-#define PAD_LABEL_X    95
-#define SEP_X          (PAD_X - 10)
-
-static int     box_number = 1;
-static int     pad_number = 1;
-static int     do_polys = 1;
-static int     scan_number = 0;
-
-static const struct ao_coord trek[] = {
-       { .x = 90, .y = 0 },
-       { .x = 60, .y = 40 },
-       { .x = 90, .y = 20 },
-       { .x = 120, .y = 40 },
-};
-
-#define NCOORD_TREK (sizeof(trek)/sizeof(trek[0]))
-
-static const struct ao_coord donut[] = {
-       { .x = 30, .y = 0 },
-       { .x = 0, .y = 30 },
-       { .x = 30, .y = 60 },
-       { .x = 60, .y = 30 },
-       { .x = 30, .y = 0 },
-       { .x = 30, .y = 10 },
-       { .x = 50, .y = 30 },
-       { .x = 30, .y = 50 },
-       { .x = 10, .y = 30 },
-       { .x = 30, .y = 10 },
-};
-
-#define NCOORD_DONUT (sizeof(donut)/sizeof(donut[0]))
-
-static const struct ao_coord bowtie[] = {
-       { .x = 0, .y = 0 },
-       { .x = 32, .y = 32 },
-       { .x = 0, .y = 32 },
-       { .x = 32, .y = 0 },
-};
-
-#define NCOORD_BOWTIE (sizeof(bowtie)/sizeof(bowtie[0]))
-
-static const struct ao_transform logo_transform = {
-       .x_scale = 48, .x_off = 0,
-       .y_scale = 48, .y_off = 0,
-};
-
-#define SCAN_X         (WIDTH - 100) / 2
-#define SCAN_Y         51
-#define SCAN_HEIGHT    4
-#define FOUND_Y                64
-#define FOUND_WIDTH    14
-#define MAX_VALID      (WIDTH / FOUND_WIDTH)
-
-static const struct ao_transform bowtie_transform = {
-       .x_scale = 1, .x_off = 50,
-       .y_scale = 1, .y_off = 20,
-};
-
-static const float pad_volts = 12.3f;
-static const float lco_volts = 4.1f;
-static const int rssi = -30;
-
-#define IMAGE_STRIDE   ((IMAGE_WIDTH + 31) / 32)
-
-static uint32_t image_bits[IMAGE_STRIDE * IMAGE_HEIGHT];
-
-static int     boxes[] = { 1, 2, 3, 5, 8, 11, 13, 17, 19, 23, 29, 31, 37, 62, 97 };
-
-static int     max_box = 97;
-
-#define ARRAYSIZE(a)   (sizeof(a) / sizeof((a)[0]))
-
-static bool
-valid_box(int box)
-{
-       size_t i;
-       if (box == 0)
-               return true;
-       for (i = 0; i < ARRAYSIZE(boxes); i++)
-               if (boxes[i] == box)
-                       return true;
-       return false;
-}
-
-static void
-next_box(void)
-{
-       for (int n = box_number + 1; n <= max_box; n++)
-               if (valid_box(n)) {
-                       box_number = n;
-                       return;
-               }
-       box_number = 0;
-}
-
-static void
-prev_box(void)
-{
-       for (int n = box_number - 1; n >= 0; n--)
-               if (valid_box(n)) {
-                       box_number = n;
-                       return;
-               }
-       box_number = max_box;
-}
-
-void HandleExpose(Display *dpy, Window win, GC gc)
-{
-       char    str[64];
-       int     i;
-       int     v;
-       int16_t b;
-
-       ao_rect(&fb, 0, 0, WIDTH, HEIGHT, 0xffffffff, AO_COPY);
-
-       if (do_polys == 1)
-               current_timeout = TIMEOUT;
-       else
-               current_timeout = 0;
-       switch (do_polys) {
-       case 1:
-               ao_logo(&fb, &logo_transform, &LOGO_FONT, 0x00000000, AO_COPY);
-               if (scan_number) {
-                       ao_rect(&fb, SCAN_X, SCAN_Y, (int16_t) scan_number, SCAN_HEIGHT, 0x00000000, AO_COPY);
-                       b = 0;
-                       v = 0;
-                       for (i = scan_number; i > 1; i--) {
-                               if (valid_box(i)) {
-                                       v++;
-                                       if (v == MAX_VALID)
-                                               break;
-                               }
-                       }
-                       for (; i <= scan_number; i++) {
-                               if (valid_box(i)) {
-                                       sprintf(str, "%02d", i);
-                                       ao_text(&fb, &TINY_FONT, 0 + FOUND_WIDTH * b, FOUND_Y, str, 0x00000000, AO_COPY);
-                                       b++;
-                               }
-                       }
-               }
-               break;
-       case 2:
-               ao_poly(&fb, trek, NCOORD_TREK, NULL, 0x00000000, AO_COPY);
-               ao_poly(&fb, donut, NCOORD_DONUT, NULL, 0x00000000, AO_COPY);
-               break;
-       case 3:
-               ao_poly(&fb, bowtie, NCOORD_BOWTIE, &bowtie_transform, 0x00000000, AO_COPY);
-               break;
-       default:
-       case 0:
-               switch (box_number) {
-               case 0:
-                       sprintf(str, "%4.1f", lco_volts);
-                       ao_text(&fb, &VOLT_FONT, BOX_X, VALUE_Y, str, 0x00000000, AO_COPY);
-                       ao_text(&fb, &SMALL_FONT, VOLT_LABEL_X, LABEL_Y, "LCO Battery", 0x00000000, AO_COPY);
-                       break;
-               default:
-                       switch (pad_number) {
-                       case -1:
-                               sprintf(str, "%4.1f", pad_volts);
-                               ao_text(&fb, &VOLT_FONT, BOX_X, VALUE_Y, str, 0x00000000, AO_COPY);
-                               ao_text(&fb, &SMALL_FONT, VOLT_LABEL_X, LABEL_Y, "Pad Battery", 0x00000000, AO_COPY);
-                               break;
-                       case 0:
-                               sprintf(str, "%4d", rssi);
-                               ao_text(&fb, &VOLT_FONT, BOX_X, VALUE_Y, str, 0x00000000, AO_COPY);
-                               ao_text(&fb, &SMALL_FONT, RSSI_LABEL_X, LABEL_Y, "Signal Strength", 0x00000000, AO_COPY);
-                               break;
-                       default:
-                               sprintf(str, "%02d", box_number);
-                               ao_text(&fb, &BIG_FONT, BOX_X, VALUE_Y, str, 0x00000000, AO_COPY);
-                               ao_text(&fb, &SMALL_FONT, BOX_LABEL_X, LABEL_Y, "Box", 0x00000000, AO_COPY);
-
-                               sprintf(str, "%d", pad_number);
-                               ao_text(&fb, &BIG_FONT, PAD_X, VALUE_Y, str, 0x00000000, AO_COPY);
-                               ao_text(&fb, &SMALL_FONT, PAD_LABEL_X, LABEL_Y, "Pad", 0x00000000, AO_COPY);
-
-                               ao_rect(&fb, SEP_X, 0, 2, HEIGHT, 0x00000000, AO_COPY);
-                       }
-                       break;
-               }
-               break;
-       }
-
-       XImage *source_image = XCreateImage(dpy, visual, 1, XYBitmap, 0, (char *) bits, WIDTH, HEIGHT, 32, STRIDE*4);
-       XImage *image = XCreateImage(dpy, visual, 1, XYBitmap, 0, (char *) image_bits, IMAGE_WIDTH, IMAGE_HEIGHT, 32, IMAGE_STRIDE * 4);
-       int ix, iy;
-       int dx, dy;
-
-       for (iy = 0; iy < HEIGHT; iy++) {
-               for (ix = 0; ix < WIDTH; ix++) {
-                       unsigned long bit = XGetPixel(source_image, ix, iy);
-                       for (dy = 0; dy < IMAGE_SCALE; dy++) {
-
-                               for (dx = 0; dx < IMAGE_SCALE; dx++) {
-                                       XPutPixel(image, ix * IMAGE_SCALE + dx, iy * IMAGE_SCALE + dy, bit);
-                               }
-                       }
-               }
-       }
-       XSetForeground(dpy, gc, WhitePixel(dpy, screen));
-       XSetBackground(dpy, gc, BlackPixel(dpy, screen));
-       XPutImage(dpy, win, gc, image, 0, 0, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
-       free(image);
-}
-
-void
-HandleKeyPress(Display *dpy, Window win, GC gc, XEvent *ev)
-{
-       char    string[10];
-       if (XLookupString ((XKeyEvent *) ev, string, sizeof (string), 0, 0) >= 1) {
-               switch (string[0]) {
-               case 'q':
-                       exit (0);
-               case 'p':
-                       if (box_number != 0) {
-                               pad_number++;
-                               if (pad_number > 8)
-                                       pad_number = -1;
-                       }
-                       break;
-               case 'P':
-                       if (box_number != 0) {
-                               pad_number--;
-                               if (pad_number < -1)
-                                       pad_number = 8;
-                       }
-                       break;
-               case 'b':
-                       next_box();
-                       break;
-               case 'B':
-                       prev_box();
-                       break;
-               case 'i':
-                       do_polys++;
-                       if (do_polys == 4)
-                               do_polys = 0;
-                       if (do_polys == 1)
-                               scan_number = 0;
-                       break;
-               case 'I':
-                       do_polys--;
-                       if (do_polys < 0)
-                               do_polys = 4;
-                       if (do_polys == 1)
-                               scan_number = 0;
-                       break;
-               case 's':
-                       if (scan_number < 99)
-                               scan_number++;
-                       break;
-               case 'S':
-                       if (scan_number > 0)
-                               scan_number--;
-                       break;
-               case 'c':
-                       break;
-               }
-               HandleExpose(dpy, win, gc);
-       }
-}
-
-void
-HandleKeyRelease(Display *dpy, Window win, GC gc, XEvent *ev)
-{
-       (void) dpy;
-       (void) win;
-       (void) gc;
-       (void) ev;
-}
-
-void
-HandleTimeout(Display *dpy, Window win, GC gc)
-{
-       if (do_polys == 1) {
-               if (scan_number < 99)
-                       scan_number++;
-               else {
-                       box_number = boxes[0];
-                       pad_number = 1;
-                       do_polys = 0;
-               }
-               HandleExpose(dpy, win, gc);
-       }
-}
diff --git a/src/draw/lco-test.c b/src/draw/lco-test.c
new file mode 100644 (file)
index 0000000..0221fbb
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * Copyright © 2023 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#define IMAGE_SCALE    8
+#define WIDTH  128
+#define HEIGHT 64
+
+#define IMAGE_WIDTH    (WIDTH * IMAGE_SCALE)
+#define IMAGE_HEIGHT   (HEIGHT * IMAGE_SCALE)
+
+#define DEFAULT_WIDTH  IMAGE_WIDTH
+#define DEFAULT_HEIGHT IMAGE_HEIGHT
+
+#define TIMEOUT        50
+
+#define PASS_KEYS
+#include "frame.c"
+#include "ao_draw.h"
+
+#define STRIDE ((WIDTH + 31) / 32)
+
+static uint32_t bits[STRIDE * HEIGHT];
+
+static struct ao_bitmap fb = {
+       .base = bits,
+       .stride = STRIDE,
+       .width = WIDTH,
+       .height = HEIGHT
+};
+
+#define BIG_FONT FrutigerLT_Roman_64_font
+#define VOLT_FONT FrutigerLT_Roman_64_font
+#define SMALL_FONT NotoMono_12_font
+#define TINY_FONT NotoMono_10_font
+#define LOGO_FONT BenguiatGothicStd_Bold_26_font
+
+#define LABEL_Y                (int16_t) (SMALL_FONT.ascent)
+#define VALUE_Y                (int16_t) (LABEL_Y + BIG_FONT.ascent)
+#define BOX_X          2
+#define PAD_X          90
+#define BOX_LABEL_X    30
+#define VOLT_LABEL_X   25
+#define RSSI_LABEL_X   15
+#define PAD_LABEL_X    95
+#define SEP_X          (PAD_X - 10)
+
+static int     box_number = 1;
+static int     pad_number = 1;
+static int     do_polys = 1;
+static int     scan_number = 0;
+
+static const struct ao_coord trek[] = {
+       { .x = 90, .y = 0 },
+       { .x = 60, .y = 40 },
+       { .x = 90, .y = 20 },
+       { .x = 120, .y = 40 },
+};
+
+#define NCOORD_TREK (sizeof(trek)/sizeof(trek[0]))
+
+static const struct ao_coord donut[] = {
+       { .x = 30, .y = 0 },
+       { .x = 0, .y = 30 },
+       { .x = 30, .y = 60 },
+       { .x = 60, .y = 30 },
+       { .x = 30, .y = 0 },
+       { .x = 30, .y = 10 },
+       { .x = 50, .y = 30 },
+       { .x = 30, .y = 50 },
+       { .x = 10, .y = 30 },
+       { .x = 30, .y = 10 },
+};
+
+#define NCOORD_DONUT (sizeof(donut)/sizeof(donut[0]))
+
+static const struct ao_coord bowtie[] = {
+       { .x = 0, .y = 0 },
+       { .x = 32, .y = 32 },
+       { .x = 0, .y = 32 },
+       { .x = 32, .y = 0 },
+};
+
+#define NCOORD_BOWTIE (sizeof(bowtie)/sizeof(bowtie[0]))
+
+static const struct ao_transform logo_transform = {
+       .x_scale = 48, .x_off = 0,
+       .y_scale = 48, .y_off = 0,
+};
+
+#define SCAN_X         (WIDTH - 100) / 2
+#define SCAN_Y         51
+#define SCAN_HEIGHT    4
+#define FOUND_Y                64
+#define FOUND_WIDTH    14
+#define MAX_VALID      (WIDTH / FOUND_WIDTH)
+
+static const struct ao_transform bowtie_transform = {
+       .x_scale = 1, .x_off = 50,
+       .y_scale = 1, .y_off = 20,
+};
+
+static const float pad_volts = 12.3f;
+static const float lco_volts = 4.1f;
+static const int rssi = -30;
+
+#define IMAGE_STRIDE   ((IMAGE_WIDTH + 31) / 32)
+
+static uint32_t image_bits[IMAGE_STRIDE * IMAGE_HEIGHT];
+
+static int     boxes[] = { 1, 2, 3, 5, 8, 11, 13, 17, 19, 23, 29, 31, 37, 62, 97 };
+
+static int     max_box = 97;
+
+#define ARRAYSIZE(a)   (sizeof(a) / sizeof((a)[0]))
+
+static bool
+valid_box(int box)
+{
+       size_t i;
+       if (box == 0)
+               return true;
+       for (i = 0; i < ARRAYSIZE(boxes); i++)
+               if (boxes[i] == box)
+                       return true;
+       return false;
+}
+
+static void
+next_box(void)
+{
+       for (int n = box_number + 1; n <= max_box; n++)
+               if (valid_box(n)) {
+                       box_number = n;
+                       return;
+               }
+       box_number = 0;
+}
+
+static void
+prev_box(void)
+{
+       for (int n = box_number - 1; n >= 0; n--)
+               if (valid_box(n)) {
+                       box_number = n;
+                       return;
+               }
+       box_number = max_box;
+}
+
+void HandleExpose(Display *dpy, Window win, GC gc)
+{
+       char    str[64];
+       int     i;
+       int     v;
+       int16_t b;
+
+       ao_rect(&fb, 0, 0, WIDTH, HEIGHT, 0xffffffff, AO_COPY);
+
+       if (do_polys == 1)
+               current_timeout = TIMEOUT;
+       else
+               current_timeout = 0;
+       switch (do_polys) {
+       case 1:
+               ao_logo(&fb, &logo_transform, &LOGO_FONT, 0x00000000, AO_COPY);
+               if (scan_number) {
+                       ao_rect(&fb, SCAN_X, SCAN_Y, (int16_t) scan_number, SCAN_HEIGHT, 0x00000000, AO_COPY);
+                       b = 0;
+                       v = 0;
+                       for (i = scan_number; i > 1; i--) {
+                               if (valid_box(i)) {
+                                       v++;
+                                       if (v == MAX_VALID)
+                                               break;
+                               }
+                       }
+                       for (; i <= scan_number; i++) {
+                               if (valid_box(i)) {
+                                       sprintf(str, "%02d", i);
+                                       ao_text(&fb, &TINY_FONT, 0 + FOUND_WIDTH * b, FOUND_Y, str, 0x00000000, AO_COPY);
+                                       b++;
+                               }
+                       }
+               }
+               break;
+       case 2:
+               ao_poly(&fb, trek, NCOORD_TREK, NULL, 0x00000000, AO_COPY);
+               ao_poly(&fb, donut, NCOORD_DONUT, NULL, 0x00000000, AO_COPY);
+               break;
+       case 3:
+               ao_poly(&fb, bowtie, NCOORD_BOWTIE, &bowtie_transform, 0x00000000, AO_COPY);
+               break;
+       default:
+       case 0:
+               switch (box_number) {
+               case 0:
+                       sprintf(str, "%4.1f", lco_volts);
+                       ao_text(&fb, &VOLT_FONT, BOX_X, VALUE_Y, str, 0x00000000, AO_COPY);
+                       ao_text(&fb, &SMALL_FONT, VOLT_LABEL_X, LABEL_Y, "LCO Battery", 0x00000000, AO_COPY);
+                       break;
+               default:
+                       switch (pad_number) {
+                       case -1:
+                               sprintf(str, "%4.1f", pad_volts);
+                               ao_text(&fb, &VOLT_FONT, BOX_X, VALUE_Y, str, 0x00000000, AO_COPY);
+                               ao_text(&fb, &SMALL_FONT, VOLT_LABEL_X, LABEL_Y, "Pad Battery", 0x00000000, AO_COPY);
+                               break;
+                       case 0:
+                               sprintf(str, "%4d", rssi);
+                               ao_text(&fb, &VOLT_FONT, BOX_X, VALUE_Y, str, 0x00000000, AO_COPY);
+                               ao_text(&fb, &SMALL_FONT, RSSI_LABEL_X, LABEL_Y, "Signal Strength", 0x00000000, AO_COPY);
+                               break;
+                       default:
+                               sprintf(str, "%02d", box_number);
+                               ao_text(&fb, &BIG_FONT, BOX_X, VALUE_Y, str, 0x00000000, AO_COPY);
+                               ao_text(&fb, &SMALL_FONT, BOX_LABEL_X, LABEL_Y, "Box", 0x00000000, AO_COPY);
+
+                               sprintf(str, "%d", pad_number);
+                               ao_text(&fb, &BIG_FONT, PAD_X, VALUE_Y, str, 0x00000000, AO_COPY);
+                               ao_text(&fb, &SMALL_FONT, PAD_LABEL_X, LABEL_Y, "Pad", 0x00000000, AO_COPY);
+
+                               ao_rect(&fb, SEP_X, 0, 2, HEIGHT, 0x00000000, AO_COPY);
+                       }
+                       break;
+               }
+               break;
+       }
+
+       XImage *source_image = XCreateImage(dpy, visual, 1, XYBitmap, 0, (char *) bits, WIDTH, HEIGHT, 32, STRIDE*4);
+       XImage *image = XCreateImage(dpy, visual, 1, XYBitmap, 0, (char *) image_bits, IMAGE_WIDTH, IMAGE_HEIGHT, 32, IMAGE_STRIDE * 4);
+       int ix, iy;
+       int dx, dy;
+
+       for (iy = 0; iy < HEIGHT; iy++) {
+               for (ix = 0; ix < WIDTH; ix++) {
+                       unsigned long bit = XGetPixel(source_image, ix, iy);
+                       for (dy = 0; dy < IMAGE_SCALE; dy++) {
+
+                               for (dx = 0; dx < IMAGE_SCALE; dx++) {
+                                       XPutPixel(image, ix * IMAGE_SCALE + dx, iy * IMAGE_SCALE + dy, bit);
+                               }
+                       }
+               }
+       }
+       XSetForeground(dpy, gc, WhitePixel(dpy, screen));
+       XSetBackground(dpy, gc, BlackPixel(dpy, screen));
+       XPutImage(dpy, win, gc, image, 0, 0, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
+       free(image);
+}
+
+void
+HandleKeyPress(Display *dpy, Window win, GC gc, XEvent *ev)
+{
+       char    string[10];
+       if (XLookupString ((XKeyEvent *) ev, string, sizeof (string), 0, 0) >= 1) {
+               switch (string[0]) {
+               case 'q':
+                       exit (0);
+               case 'p':
+                       if (box_number != 0) {
+                               pad_number++;
+                               if (pad_number > 8)
+                                       pad_number = -1;
+                       }
+                       break;
+               case 'P':
+                       if (box_number != 0) {
+                               pad_number--;
+                               if (pad_number < -1)
+                                       pad_number = 8;
+                       }
+                       break;
+               case 'b':
+                       next_box();
+                       break;
+               case 'B':
+                       prev_box();
+                       break;
+               case 'i':
+                       do_polys++;
+                       if (do_polys == 4)
+                               do_polys = 0;
+                       if (do_polys == 1)
+                               scan_number = 0;
+                       break;
+               case 'I':
+                       do_polys--;
+                       if (do_polys < 0)
+                               do_polys = 4;
+                       if (do_polys == 1)
+                               scan_number = 0;
+                       break;
+               case 's':
+                       if (scan_number < 99)
+                               scan_number++;
+                       break;
+               case 'S':
+                       if (scan_number > 0)
+                               scan_number--;
+                       break;
+               case 'c':
+                       break;
+               }
+               HandleExpose(dpy, win, gc);
+       }
+}
+
+void
+HandleKeyRelease(Display *dpy, Window win, GC gc, XEvent *ev)
+{
+       (void) dpy;
+       (void) win;
+       (void) gc;
+       (void) ev;
+}
+
+void
+HandleTimeout(Display *dpy, Window win, GC gc)
+{
+       if (do_polys == 1) {
+               if (scan_number < 99)
+                       scan_number++;
+               else {
+                       box_number = boxes[0];
+                       pad_number = 1;
+                       do_polys = 0;
+               }
+               HandleExpose(dpy, win, gc);
+       }
+}