This commit is contained in:
Matteo Signer 2018-01-15 20:36:29 +00:00 committed by GitHub
commit b74db99a1d
3 changed files with 159 additions and 2 deletions

View File

@ -8,7 +8,7 @@ endif
CC ?= gcc
CFLAGS += -Wall -std=c99 -Os -DVERSION="\"$(VERSION)\""
LDFLAGS += -lxcb -lxcb-xinerama -lxcb-randr
LDFLAGS += -lxcb -lxcb-xinerama -lxcb-randr -lxcb-image
CFDEBUG = -g3 -pedantic -Wall -Wunused-parameter -Wlong-long \
-Wsign-conversion -Wconversion -Wimplicit-function-declaration

View File

@ -109,6 +109,10 @@ Set the font used to draw the following text. The parameter I<index> can either
Set the text underline color. The parameter I<color> can be I<-> or a color in one of the formats mentioned before. The special value I<-> resets the color to the default one.
=item B<I>I<filename>
Draw the icon specified by I<filename>. The icon must be in xbm format.
=item B<A>I<button>:I<command>:
Create a clickable area starting from the current position, when the area is clicked I<command> is printed on stdout. The area is closed when a B<A> token, not followed by : is encountered.

View File

@ -16,6 +16,7 @@
#include <xcb/xinerama.h>
#endif
#include <xcb/randr.h>
#include <xcb/xcb_image.h>
// Here be dragons
@ -63,6 +64,12 @@ typedef struct area_stack_t {
area_t *area;
} area_stack_t;
typedef struct xbm_icon_t {
int width, height;
char *filename;
xcb_image_t* image;
} xbm_icon_t;
enum {
ATTR_OVERL = (1<<0),
ATTR_UNDERL = (1<<1),
@ -101,10 +108,16 @@ static rgba_t fgc, bgc, ugc;
static rgba_t dfgc, dbgc, dugc;
static area_stack_t area_stack;
#define ICON_CACHE_SIZE 256
static int icon_count = 0;
static int icon_index = 0;
static xbm_icon_t* icon_cache[ICON_CACHE_SIZE];
void
update_gc (void)
{
xcb_change_gc(c, gc[GC_DRAW], XCB_GC_FOREGROUND, (const uint32_t []){ fgc.v });
xcb_change_gc(c, gc[GC_DRAW], XCB_GC_BACKGROUND, (const uint32_t []){ bgc.v });
xcb_change_gc(c, gc[GC_CLEAR], XCB_GC_FOREGROUND, (const uint32_t []){ bgc.v });
xcb_change_gc(c, gc[GC_ATTR], XCB_GC_FOREGROUND, (const uint32_t []){ ugc.v });
}
@ -252,6 +265,134 @@ draw_char (monitor_t *mon, font_t *cur_font, int x, int align, uint16_t ch)
return ch_width;
}
xbm_icon_t* load_xbm(char* filename) {
for (int i=0; i<icon_count; i++) {
if (strcmp(icon_cache[i]->filename, filename) == 0) {
return icon_cache[i];
}
}
FILE *f = NULL;
f = fopen(filename, "r");
if (!f)
return NULL;
int width = -1;
int height = -1;
char line[256];
char define_name[256];
int value;
while (fgets(line, sizeof(line), f)) {
if (line[0] == '\n') continue;
if (sscanf(line, "#define %s %d", define_name, &value) == 2) {
char *type = strrchr(define_name, '_');
if (type)
type++;
else
type = define_name;
if (strcmp(type, "width") == 0)
width = value;
if (strcmp(type, "height") == 0)
height = value;
continue;
}
if (width <= 0 || height <= 0) {
fclose(f);
return NULL;
}
if (
sscanf(line, "static const unsigned char %s = {", define_name) == 1||
sscanf(line, "static unsigned char %s = {", define_name) == 1||
sscanf(line, "static const char %s = {", define_name) == 1||
sscanf(line, "static char %s = {", define_name) == 1
) {
} else {
fclose(f);
return NULL;
}
//const int n = (width/8 + (width%8) ? 1 : 0) * height;
xbm_icon_t *icon = calloc(1, sizeof(xbm_icon_t));
icon->width = width;
icon->height = height;
icon->filename = calloc(strlen(filename), sizeof(char));
if (icon->filename == NULL) {
exit(1);
}
strcpy(icon->filename, filename);
xcb_image_t *img = xcb_image_create_native(c, width, height, XCB_IMAGE_FORMAT_XY_BITMAP, 1, NULL, ~0, NULL);
img->data = calloc(1, img->size);
if (img->data == NULL) {
exit(1);
}
for (int y = 0; y < height; y ++) {
for (int x = 0; x < width; x+= 8) {
if (x != 0 || y != 0)
fgetc(f);
int val;
if (fscanf(f, "%x", &val)) {
} else {
xcb_image_destroy(img);
free(icon);
fclose(f);
return NULL;
}
for (int x2 = x; x2 < width && x2 < x + 8; x2++) {
bool pix = (val >> (x2%8)) & 1;
xcb_image_put_pixel(img, x2, y, pix);
}
}
}
icon->image = img;
if (icon_count < ICON_CACHE_SIZE)
icon_count++;
icon_cache[icon_index] = icon;
icon_index++;
icon_index %= ICON_CACHE_SIZE;
fclose(f);
return icon;
}
// Instruction pointer modifiecd by cosmic rays
return NULL;
}
int
draw_icon (monitor_t *mon, int x, int align, char *filename)
{
xbm_icon_t *icon = load_xbm(filename);
if (icon == NULL)
return 0;
int icon_width = icon->width;
switch (align) {
case ALIGN_C:
xcb_copy_area(c, mon->pixmap, mon->pixmap, gc[GC_DRAW],
mon->width / 2 - x / 2, 0,
mon->width / 2 - (x + icon_width) / 2, 0,
x, bh);
x = mon->width / 2 - (x + icon_width) / 2 + x;
break;
case ALIGN_R:
xcb_copy_area(c, mon->pixmap, mon->pixmap, gc[GC_DRAW],
mon->width - x, 0,
mon->width - x - icon_width, 0,
x, bh);
x = mon->width - icon_width;
break;
}
fill_rect(mon->pixmap, gc[GC_CLEAR], x, by, icon->width, bh);
xcb_image_put(c, mon->pixmap, gc[GC_DRAW], icon->image, x, (bh-icon->height) / 2, 0);
return icon_width;
}
rgba_t
parse_color (const char *str, char **end, const rgba_t def)
{
@ -531,6 +672,18 @@ parse (char *text)
case 'c': pos_x = 0; align = ALIGN_C; break;
case 'r': pos_x = 0; align = ALIGN_R; break;
case 'I':
if (block_end-p > 255)
break;
char filename[256];
strncpy(filename, p, block_end-p);
filename[block_end-p] = '\0';
int icon_width = draw_icon(cur_mon, pos_x, align, filename);
pos_x += icon_width;
area_shift(cur_mon->window, align, icon_width);
break;
case 'A':
button = XCB_BUTTON_INDEX_1;
// The range is 1-5
@ -1193,7 +1346,7 @@ init (char *wm_name)
// Create the gc for drawing
gc[GC_DRAW] = xcb_generate_id(c);
xcb_create_gc(c, gc[GC_DRAW], monhead->pixmap, XCB_GC_FOREGROUND, (const uint32_t []){ fgc.v });
xcb_create_gc(c, gc[GC_DRAW], monhead->pixmap, XCB_GC_FOREGROUND | XCB_GC_BACKGROUND, (const uint32_t []){ fgc.v, bgc.v });
gc[GC_CLEAR] = xcb_generate_id(c);
xcb_create_gc(c, gc[GC_CLEAR], monhead->pixmap, XCB_GC_FOREGROUND, (const uint32_t []){ bgc.v });