Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for XBM icons. #178

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 4 additions & 0 deletions README.pod
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,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.
Expand Down
155 changes: 154 additions & 1 deletion lemonbar.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <xcb/xcbext.h>
#include <xcb/xinerama.h>
#include <xcb/randr.h>
#include <xcb/xcb_image.h>

// Here be dragons

Expand Down Expand Up @@ -60,6 +61,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),
Expand Down Expand Up @@ -98,10 +105,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 });
}
Expand Down Expand Up @@ -231,6 +244,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)
{
Expand Down Expand Up @@ -509,6 +650,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
Expand Down Expand Up @@ -1151,7 +1304,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 });
Expand Down