summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wu <lekensteyn@gmail.com>2012-09-27 22:29:36 +0200
committerPeter Wu <lekensteyn@gmail.com>2012-09-27 22:29:36 +0200
commit2c04b05d548987c39c8c8ba29cd7dd9ab101f093 (patch)
tree5c2e44771858805542a64c43f3d91343399a20f2
parent25d7e38a339d60aa532ebd4fcfc9e710186e834a (diff)
downloadc-files-2c04b05d548987c39c8c8ba29cd7dd9ab101f093.tar.gz
xcbviewfs,colorlookupgen: implement XPM loading
-rw-r--r--Makefile17
-rw-r--r--colorlookupgen.c51
-rw-r--r--xcbviewfs.c220
3 files changed, 287 insertions, 1 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..ca94baf
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,17 @@
+XCBV_CFLAGS += $(shell pkg-config --cflags xcb-image xpm) -Wall -g
+XCBV_LDFLAGS += $(shell pkg-config --libs xcb-image xpm)
+
+RGB_TXT := /usr/share/vim/vim73/rgb.txt
+
+xcbviewfs: xcbviewfs.c colorlookup.c
+ $(CC) $(XCBV_CFLAGS) -o $@ $< colorlookup.c $(XCBV_LDFLAGS)
+
+colorlookupgen: colorlookupgen.c
+ $(CC) -Wall -Werror -o $@ $<
+
+colorlookup.c: $(RGB_TXT) colorlookupgen
+ ./colorlookupgen $(RGB_TXT) > $@
+
+.PHONY: clean
+clean:
+ rm -vf xcbviewfs colorlookupgen colorlookup.c
diff --git a/colorlookupgen.c b/colorlookupgen.c
new file mode 100644
index 0000000..6770703
--- /dev/null
+++ b/colorlookupgen.c
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <stdint.h>
+
+int main(int argc, char **argv) {
+ FILE *file = stdin;
+ char *funcname = "color_lookup";
+ char line[256];
+ char color[256];
+ unsigned int total_colors = 0;
+
+ if (argc >= 2) {
+ file = fopen(argv[1], "r");
+ if (!file) {
+ perror("Error opening rgb.txt");
+ return 1;
+ }
+ }
+
+ if (argc >= 3) {
+ funcname = argv[1];
+ }
+
+ printf("#include <string.h>\n");
+ printf("int %s(char *name, unsigned char color[3]) {\n", funcname);
+ printf(
+ " static struct {\n"
+ " char *name;\n"
+ " unsigned char color[3];\n"
+ " } colors[] = {\n");
+ while (fgets(line, sizeof(line), file) != NULL) {
+ uint8_t r, g, b;
+ int matches = sscanf(line, "%hhd %hhd %hhd %255[^\n]",
+ &r, &g, &b, color);
+ if (matches == 4) {
+ ++total_colors;
+ printf(" { \"%s\", { %d, %d, %d } },\n", color, r, g, b);
+ }
+ }
+ printf(
+ " };\n"
+ " int i = 0;\n"
+ " for (; i<%d; ++i)\n"
+ " if (!strcasecmp(colors[i].name, name)) {\n"
+ " memcpy(color, colors[i].color, 3);\n"
+ " return 1;\n"
+ " }\n"
+ " return 0;\n"
+ "}\n", total_colors);
+
+ return 0;
+}
diff --git a/xcbviewfs.c b/xcbviewfs.c
index 8c57822..e7ab1d6 100644
--- a/xcbviewfs.c
+++ b/xcbviewfs.c
@@ -7,11 +7,17 @@
*/
#include <xcb/xcb.h>
+#include <xcb/xcb_image.h>
//#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
+#include <stdint.h>
+#include <X11/xpm.h>
+
+/* defined in colorlookup.c which is generated by colorlookupgen.c */
+extern int color_lookup(char *name, uint8_t color[3]);
#define die(msg) do { \
fprintf(stderr, msg); \
@@ -24,6 +30,8 @@
} while (0)
static unsigned char empty_cursor_data[32];
+static int load_xpm_image(char *filename, unsigned char **data,
+ unsigned int *len, unsigned int *width, unsigned int *height);
int main(int argc, char **argv) {
xcb_connection_t *c;
@@ -31,29 +39,44 @@ int main(int argc, char **argv) {
xcb_window_t win;
xcb_cursor_t cursor;
+ char *filename;
+ unsigned char *image_data;
+ unsigned int image_data_len;
+ unsigned int image_width, image_height;
+ xcb_pixmap_t pmap = 0;
+ xcb_gcontext_t gc = 0;
+
/* options */
int grab_pointer = 0;
int hide_cursor = 0;
int grab_kbd = 0;
int fullscreen = 0;
+ int draw_picture = 1;
//grab_kbd = !(fullscreen = grab_pointer = hide_cursor = 0 );
if (argc < 2) {
fprintf(stderr, "Usage: %s filename\n", *argv);
return 1;
}
+ filename = argv[1];
+
c = xcb_connect(NULL, NULL);
if (!c) {
fprintf(stderr, "Cannot open display\n");
return 1;
}
+
+ if (!load_xpm_image(filename, &image_data, &image_data_len,
+ &image_width, &image_height))
+ bail(disconnect, "Failed to load XPM image\n");
+
screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
win = xcb_generate_id(c);
/* For each mask, need to add valwin item in order as defined by the
* enum, see See http://xcb.freedesktop.org/tutorial/events/ */
uint32_t mask = XCB_CW_EVENT_MASK;
uint32_t valwin[] = {
- XCB_EVENT_MASK_KEY_PRESS,
+ XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS,
};
xcb_create_window(c, 0, win, /* conn, depth, WinID */
screen->root, /* parent */
@@ -132,10 +155,49 @@ int main(int argc, char **argv) {
property, XCB_ATOM_ATOM, 32, 1, &data);
xcb_flush(c);
}
+ if (draw_picture) {
+ /**
+ * X-Bitmap, XY-Pixmap or Z-Pixmap? See
+ * http://www.linux.ie/old-list/23540.html
+ */
+ xcb_image_t *img;
+ img = xcb_image_create_native(c, image_width, image_height,
+ XCB_IMAGE_FORMAT_Z_PIXMAP,
+ 24, /* depth */
+ image_data,
+ image_data_len,
+ image_data);
+
+ pmap = xcb_generate_id(c);
+ xcb_create_pixmap(c, 24, pmap, win, image_width, image_height);
+
+ gc = xcb_generate_id(c);
+ uint32_t mask = XCB_GC_BACKGROUND;
+ uint32_t value_list[] = {
+ screen->black_pixel
+ };
+ xcb_create_gc(c, gc, pmap, mask, value_list);
+
+ xcb_image_put(c, pmap, gc, img, 0, 0, 0);
+ xcb_flush(c);
+
+ xcb_image_destroy(img);
+ }
+
xcb_generic_event_t *e;
int running = 1;
while (running && (e = xcb_wait_for_event(c))) {
switch (e->response_type) {
+ case XCB_EXPOSE:
+ if (!draw_picture) break;
+ xcb_expose_event_t *ee = (xcb_expose_event_t *)e;
+ xcb_copy_area(c, pmap, win, gc,
+ ee->x, ee->y,
+ ee->x, ee->y,
+ ee->width,
+ ee->height);
+ xcb_flush(c);
+ break;
case XCB_KEY_PRESS: ;
xcb_button_press_event_t *press = (xcb_button_press_event_t *)e;
xcb_keycode_t key = press->detail;
@@ -145,11 +207,167 @@ int main(int argc, char **argv) {
}
free(e);
}
+ if (pmap) xcb_free_pixmap(c, pmap);
ungrab_kbd:
xcb_ungrab_keyboard(c, XCB_CURRENT_TIME);
ungrab_pointer:
xcb_ungrab_pointer(c, XCB_CURRENT_TIME);
disconnect:
+ if (!draw_picture) free(image_data); /* TODO: check other error paths */
xcb_disconnect(c);
return 0;
}
+
+#define print_once(...) do { \
+ static int printed = 0; \
+ if (!printed) { \
+ fprintf(stderr, __VA_ARGS__); \
+ printed = 1; \
+ } \
+} while(0)
+
+static void xpm_parse_color_line(char *line, uint8_t color[3]) {
+ int search_color = 0;
+ char c = *line;
+ while (c) {
+ char *next_ws;
+ while (c == ' ' || c == '\t')
+ c = *++line;
+
+ next_ws = strchr(line, ' ');
+ if (!next_ws) next_ws = strchr(line, '\t');
+ if (next_ws) *next_ws = 0;
+
+ if (search_color) {
+ if (line[0] == '#') {
+ unsigned int hex = strtol(line, NULL, 16);
+ if (strlen(line) == 4) { /* #RGB */
+ color[0] = ((hex >> 2) & 0xF) * 0x11;
+ color[1] = ((hex >> 1) & 0xF) * 0x11;
+ color[2] = (hex & 0xF) * 0x11;
+ } else { /* assume #RRGGBB */
+ color[0] = (hex >> 8) & 0xFF;
+ color[1] = (hex >> 4) & 0xFF;
+ color[2] = hex & 0xFF;
+ }
+ return;
+ } else if (line[0] == '%') {
+ /* HSV not implemented */
+ print_once("HSV not implemented\n");
+ } else if (strcasecmp("None", line) == 0) {
+ /* transparant wut? */
+ memset(color, 0, 3);
+ return;
+ } else if (color_lookup(line, color)) {
+ /* TODO: handle colors with whitespace */
+ return;
+ } else {
+ print_once("Color %s unimplemented\n", line);
+ }
+ search_color = 0;
+ } else if (strcmp(line, "c") == 0) {
+ search_color = 1;
+ } else {
+ /* not implemented */
+ print_once("Color type not implemented: %s\n", line);
+ }
+ /* continue searching if there are more tokens */
+ if (next_ws) line = next_ws + 1;
+ else break;
+ }
+ color[0] = color[1] = color[2] = 0x42;
+ print_once("No color found\n");
+}
+
+/* better use a RB tree instead of a linked list... */
+typedef struct _ColorList ColorList;
+struct _ColorList {
+ unsigned int key; /* assume that the key has less or equal bytes */
+ uint8_t color[3]; /* RGB */
+ ColorList *next;
+};
+
+static int load_xpm_image(char *filename, unsigned char **data,
+ unsigned int *len, unsigned int *width, unsigned int *height) {
+ unsigned int w, h;
+ char **xpm_data;
+ int error;
+
+ if ((error = XpmReadFileToData(filename, &xpm_data))) {
+ fprintf(stderr, "Cannot load image: %s\n", XpmGetErrorString(error));
+ return 0;
+ }
+
+ /* 1: width height ncolors chars_per_pixel [opt_hotspot_x opt_hotspot_y]
+ * ncolors: char (of len chars_per_pixel) (key color)+
+ * key m(ono), s(ymbolic name), g(rayscale)4(level), g(rayscale w/
+ * more than 4 levels), c(color visual). "s None" is transparant
+ * height: width*chars_per_pixels
+ * (ignore Extensions), array size = 1 + ncolors + height
+ * XCB image: width * height * 4 bytes
+ * See also http://www.net.uom.gr/Books/Manuals/xpm-3-paper.pdf
+ */
+
+ unsigned int ncolors, cpp;
+ unsigned int i;
+ /* assume XPM library is not stupid */
+ sscanf(xpm_data[0], "%u %u %u %u", &w, &h, &ncolors, &cpp);
+ if (cpp > sizeof(unsigned int)) {
+ bail(free_xpm, "CPP does not fit in integer data type\n");
+ }
+ *width = w; *height = h;
+ *len = w * h * 4;
+
+ *data = malloc(w * h * 4);
+ if (!data) {
+ bail(free_xpm, "Cannot allocate memory for image\n");
+ }
+
+ /* horrible performance, but ok... */
+ ColorList dummy_color = {0};
+ ColorList *colors = &dummy_color;
+ for (i=1; i<=ncolors; i++) {
+ char *line = xpm_data[i];
+ ColorList *color = malloc(sizeof(ColorList));
+ color->key = 0;
+ memcpy(&color->key, line, cpp);
+ /* skip color key */
+ xpm_parse_color_line(line + cpp, color->color);
+ colors->next = color;
+ colors = color;
+ }
+ colors->next = NULL;
+ colors = dummy_color.next;
+
+ /* fill data */
+ unsigned int x, y;
+ char **all_pixels = &xpm_data[1 + ncolors];
+ for (y=0; y<h; ++y) {
+ char *pixels = all_pixels[y];
+ unsigned char *data_line = *data + 4 * y * w;
+ for (x=0; x<w; ++x) {
+ unsigned int key = 0;
+ ColorList *color = colors;
+ memcpy(&key, pixels + cpp * x, cpp);
+ while (color && color->key != key)
+ color = color->next;
+ if (color) {
+ memcpy(data_line + 4 * x, color->color, cpp);
+ } else {
+ fprintf(stderr, "No color found\n");
+ }
+ }
+ }
+
+ error = 1; /* success */
+
+ /* clean linked list of colors */
+ while (colors) {
+ ColorList *next = colors->next;
+ free(colors);
+ colors = next;
+ }
+free_xpm:
+ XpmFree(xpm_data);
+ return error;
+}