Skip to content

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
From 87760af9cdb2ec7d54aa4b48f5964b52bfa24f61 Mon Sep 17 00:00:00 2001
From: Sudaraka Wijesinghe <sudaraka.wijesinghe@gmail.com>
Date: Mon, 16 Jun 2014 20:34:40 +0530
Subject: [PATCH] i3bar XBM icon support
Ported the patch from 4.5 to 4.8
Original source:
https://github.com/ashinkarov/i3-extras/blob/master/i3bar-xbm-icons.patch
---
common.mk | 2 +
i3bar/include/common.h | 4 +
i3bar/include/xbm_image.h | 14 +++
i3bar/src/child.c | 11 ++
i3bar/src/xbm_image.c | 278 ++++++++++++++++++++++++++++++++++++++++++++++
i3bar/src/xcb.c | 44 +++++++-
6 files changed, 350 insertions(+), 3 deletions(-)
create mode 100644 i3bar/include/xbm_image.h
create mode 100644 i3bar/src/xbm_image.c
diff --git a/common.mk b/common.mk
index b086bc8..8929447 100644
--- a/common.mk
+++ b/common.mk
@@ -80,8 +80,10 @@ ldflags_for_lib = $(shell pkg-config --exists 2>/dev/null $(1) && pkg-config --l
# XCB common stuff
XCB_CFLAGS := $(call cflags_for_lib, xcb)
XCB_CFLAGS += $(call cflags_for_lib, xcb-event)
+XCB_CFLAGS += $(call cflags_for_lib, xcb-image)
XCB_LIBS := $(call ldflags_for_lib, xcb,xcb)
XCB_LIBS += $(call ldflags_for_lib, xcb-event,xcb-event)
+XCB_LIBS += $(call ldflags_for_lib, xcb-image,xcb-image)
ifeq ($(shell pkg-config --exists xcb-util 2>/dev/null || echo 1),1)
XCB_CFLAGS += $(call cflags_for_lib, xcb-atom)
XCB_CFLAGS += $(call cflags_for_lib, xcb-aux)
diff --git a/i3bar/include/common.h b/i3bar/include/common.h
index d63780d..ec4b84c 100644
--- a/i3bar/include/common.h
+++ b/i3bar/include/common.h
@@ -12,6 +12,7 @@
#include <xcb/xproto.h>
#include "libi3.h"
#include "queue.h"
+#include "xbm_image.h"
typedef struct rect_t rect;
@@ -41,6 +42,9 @@ struct status_block {
uint32_t min_width;
blockalign_t align;
+ struct xbm_image *icon;
+ char *icon_color;
+
bool urgent;
bool no_separator;
diff --git a/i3bar/include/xbm_image.h b/i3bar/include/xbm_image.h
new file mode 100644
index 0000000..3c01c84
--- /dev/null
+++ b/i3bar/include/xbm_image.h
@@ -0,0 +1,14 @@
+#ifndef __XBM_IMAGE_H__
+#define __XBM_IMAGE_H__
+
+struct xbm_image {
+ int width, height;
+ char * id;
+ char * data;
+};
+
+
+struct xbm_image * xbm_from_file (char *);
+void xbm_free (struct xbm_image *);
+
+#endif /* __XBM_IMAGE_H__ */
diff --git a/i3bar/src/child.c b/i3bar/src/child.c
index 5867ce4..a8f2622 100644
--- a/i3bar/src/child.c
+++ b/i3bar/src/child.c
@@ -141,6 +141,8 @@ static int stdin_start_array(void *context) {
FREE(first->color);
FREE(first->name);
FREE(first->instance);
+ FREE(first->icon_color);
+ xbm_free (first->icon);
TAILQ_REMOVE(&statusline_head, first, blocks);
free(first);
}
@@ -187,6 +189,15 @@ static int stdin_string(void *context, const unsigned char *val, size_t len) {
if (strcasecmp(ctx->last_map_key, "color") == 0) {
sasprintf(&(ctx->block.color), "%.*s", len, val);
}
+ if (strcasecmp(ctx->last_map_key, "icon") == 0) {
+ char * s;
+ sasprintf(&s, "%.*s", len, val);
+ ctx->block.icon = xbm_from_file(s);
+ FREE(s);
+ }
+ if (strcasecmp(ctx->last_map_key, "icon_color") == 0) {
+ sasprintf(&(ctx->block.icon_color), "%.*s", len, val);
+ }
if (strcasecmp(ctx->last_map_key, "align") == 0) {
if (len == strlen("left") && !strncmp((const char *)val, "left", strlen("left"))) {
ctx->block.align = ALIGN_LEFT;
diff --git a/i3bar/src/xbm_image.c b/i3bar/src/xbm_image.c
new file mode 100644
index 0000000..ea99ffa
--- /dev/null
+++ b/i3bar/src/xbm_image.c
@@ -0,0 +1,278 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdbool.h>
+
+#include "xbm_image.h"
+
+#if FILENAME_CHECKING
+/* Assume that file is called xxx.xbm, get xxx out of the filename
+ for furhter validation during parsing. */
+static char *
+validate_fname (char * fname)
+{
+ char * dot = strrchr (fname, '.');
+ char * slash = strrchr (fname, '/');
+ char * ret = NULL;
+ unsigned sz = 0;
+
+ if (NULL == dot)
+ return NULL;
+
+ if (0 != strncmp (dot, ".xbm", 4))
+ return NULL;
+
+ if (slash)
+ fname = slash + 1;
+
+ sz = dot - fname;
+ ret = malloc (sz + 1);
+ strncpy (ret, fname, sz);
+ ret[sz] = 0;
+ return ret;
+}
+#endif
+
+static char *
+read_id (FILE * f)
+{
+ unsigned sz = 2, ptr = 0;
+ char * data = malloc (sz);
+ int c;
+
+ c = fgetc (f);
+ if (isalpha (c) || c == '_')
+ data[ptr++] = c;
+ else
+ goto out;
+
+ while (true) {
+ c = fgetc (f);
+ if (ptr == sz - 1)
+ data = realloc (data, sz *= 2);
+
+ if (isalnum (c) || c == '_')
+ data[ptr++] = c;
+ else {
+ ungetc (c, f);
+ break;
+ }
+ }
+
+ data[ptr] = '\0';
+ return data;
+
+out:
+ if (data)
+ free (data);
+
+ return NULL;
+}
+
+
+static bool
+read_string (FILE * f, const char * s)
+{
+ while (*s != '\0') {
+ int c = fgetc (f);
+ if (c == EOF || c != *s) {
+ ungetc (c, f);
+ return false;
+ }
+ s++;
+ }
+
+ return true;
+}
+
+static bool
+skip_spaces (FILE * f)
+{
+ int c;
+ while (isspace (c = fgetc (f)) && c != EOF)
+ ;
+
+ ungetc (c, f);
+ return true;
+}
+
+static inline bool
+string_ends_with (const char * s, const char * postfix)
+{
+ return strlen (s) > strlen (postfix)
+ && strncmp (s + strlen (s) - strlen (postfix),
+ postfix, strlen (postfix)) == 0;
+}
+
+#define READ_WORD_EAT_SPACES(file, word) \
+do { \
+ if (!read_string (file, word)) \
+ return false; \
+ skip_spaces (file); \
+} while (0)
+
+
+static bool
+read_define (FILE * f, struct xbm_image * img)
+{
+ unsigned sz;
+ char * wh;
+
+ READ_WORD_EAT_SPACES (f, "define");
+
+ /* read the <id>_width variable, and save <id> for
+ later validation in the img. */
+ if (NULL == (wh = read_id (f)))
+ return false;
+
+ if (string_ends_with (wh, "_width")) {
+ if (!img->id) {
+ unsigned idsz = strlen (wh) - strlen ("_width");
+ img->id = malloc (idsz+1);
+ strncpy (img->id, wh, idsz);
+ img->id[idsz] = '\0';
+ } else if (0 != strncmp (img->id, wh, strlen (img->id))) {
+ free (wh);
+ return false;
+ }
+
+ free (wh);
+ skip_spaces (f);
+ if (fscanf (f, "%u", &sz) < 1)
+ return false;
+
+ img->width = sz;
+ } else if (string_ends_with (wh, "_height")) {
+ if (!img->id) {
+ unsigned idsz = strlen (wh) - strlen ("_height");
+ img->id = malloc (idsz+1);
+ strncpy (img->id, wh, idsz);
+ img->id[idsz] = '\0';
+ } else if (0 != strncmp (img->id, wh, strlen (img->id))) {
+ free (wh);
+ return false;
+ }
+
+ free (wh);
+ skip_spaces (f);
+ if (fscanf (f, "%u", &sz) < 1)
+ return false;
+
+ img->height = sz;
+ } else
+ return false;
+
+ return true;
+}
+
+static bool
+read_data (FILE * f, struct xbm_image * img)
+{
+ int sz, i;
+ char * data;
+
+ /* size in bytes */
+ sz = (img->width / 8 + !!(img->width % 8)) * img->height;
+
+ data = malloc (sz);
+
+ READ_WORD_EAT_SPACES (f, "tatic");
+ READ_WORD_EAT_SPACES (f, "unsigned");
+ READ_WORD_EAT_SPACES (f, "char");
+ READ_WORD_EAT_SPACES (f, img->id);
+ READ_WORD_EAT_SPACES (f, "_bits[]");
+ READ_WORD_EAT_SPACES (f, "=");
+ READ_WORD_EAT_SPACES (f, "{");
+
+ for (i = 0; i < sz; i++) {
+ unsigned value;
+ if (fscanf (f, "%x", &value) < 1 || value > 255)
+ return false;
+
+ data[i] = (char)value;
+ skip_spaces (f);
+ if (i != sz - 1)
+ READ_WORD_EAT_SPACES (f, ",");
+ }
+
+ READ_WORD_EAT_SPACES (f, "}");
+ READ_WORD_EAT_SPACES (f, ";");
+ img->data = data;
+ return true;
+}
+
+
+struct xbm_image *
+xbm_from_file (char * fname)
+{
+ struct xbm_image * img = NULL;
+ FILE * f = NULL;
+ int c;
+
+ if (!(f = fopen (fname, "r")))
+ goto out;
+
+ img = malloc (sizeof (struct xbm_image));
+ img->id = NULL;
+ img->width = -1;
+ img->height = -1;
+
+ do {
+ c = fgetc (f);
+ if (c == '#') {
+ if (!read_define (f, img))
+ goto out;
+ } else if (c == 's') {
+ if (img->width == -1 || img->height == -1 || !img->id
+ || !read_data (f, img))
+ goto out;
+ } else if (isspace (c) || c == EOF)
+ ;
+ else
+ goto out;
+ } while (c != EOF);
+
+ fclose (f);
+ return img;
+
+out:
+ if (f)
+ fclose (f);
+
+ return NULL;
+}
+
+void
+xbm_free (struct xbm_image * img)
+{
+ if (!img)
+ return;
+
+ if (img->id)
+ free (img->id);
+ if (img->data)
+ free (img->data);
+
+ free (img);
+}
+
+#ifdef TESTING
+int
+main (int argc, char *argv[])
+{
+ struct xbm_image * img;
+ int i;
+
+ img = xbm_from_file (argv[1]);
+
+ if (img != NULL) {
+ for (i = 0; i < (img->width /8 + !!(img->width % 8)) * img->height; i++)
+ printf ("%x, ", (unsigned char)img->data[i]);
+
+ xbm_free (img);
+ }
+
+ return EXIT_SUCCESS;
+}
+#endif
diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c
index a29f909..ab63e66 100644
--- a/i3bar/src/xcb.c
+++ b/i3bar/src/xcb.c
@@ -10,6 +10,7 @@
#include <xcb/xcb.h>
#include <xcb/xproto.h>
#include <xcb/xcb_aux.h>
+#include <xcb/xcb_image.h>
#ifdef XCB_COMPAT
#include "xcb_compat.h"
@@ -129,7 +130,7 @@ void refresh_statusline(void) {
/* Predict the text width of all blocks (in pixels). */
TAILQ_FOREACH (block, &statusline_head, blocks) {
- if (i3string_get_num_bytes(block->full_text) == 0)
+ if (i3string_get_num_bytes(block->full_text) == 0 && block->icon == NULL)
continue;
block->width = predict_text_width(block->full_text);
@@ -159,6 +160,10 @@ void refresh_statusline(void) {
block->width += block->sep_block_width;
statusline_width += block->width + block->x_offset + block->x_append;
+
+ /* Add some space between the text and the icon. */
+ if (block->icon)
+ statusline_width += block->icon->width + 5;
}
/* If the statusline is bigger than our screen we need to make sure that
@@ -174,12 +179,45 @@ void refresh_statusline(void) {
/* Draw the text of each block. */
uint32_t x = 0;
TAILQ_FOREACH (block, &statusline_head, blocks) {
- if (i3string_get_num_bytes(block->full_text) == 0)
+ if (i3string_get_num_bytes(block->full_text) == 0 && block->icon == NULL)
continue;
+ if (block->icon != NULL) {
+ xcb_image_t * img;
+
+ img = xcb_image_create_native (conn, block->icon->width,
+ block->icon->height,
+ XCB_IMAGE_FORMAT_XY_BITMAP,
+ 1, NULL, ~0, NULL);
+
+ img->data = malloc (img->size);
+ memset (img->data, 0, img->size);
+
+ for (int i = 0; i < block->icon->height; i++)
+ for (int j = 0; j < block->icon->width; j++) {
+ unsigned pos = (img->width /8 + !!(img->width % 8))*i + j/8;
+ bool p = !!(block->icon->data[pos] & (1 << (j%8)));
+ xcb_image_put_pixel (img, j, i, p);
+ }
+
+ uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
+ if (block->icon_color) {
+ uint32_t values[] = { get_colorpixel(block->icon_color), colors.bar_bg };
+ xcb_change_gc(xcb_connection, statusline_ctx, mask, values);
+ } else {
+ uint32_t values[] = { colors.bar_fg, colors.bar_bg };
+ xcb_change_gc(xcb_connection, statusline_ctx, mask, values);
+ }
+
+ xcb_image_put (conn, statusline_pm, statusline_ctx,
+ img, x, (font.height - block->icon->height)/2, 0);
+ xcb_image_destroy(img);
+ x += block->icon->width + 5;
+ }
+
uint32_t colorpixel = (block->color ? get_colorpixel(block->color) : colors.bar_fg);
set_font_colors(statusline_ctx, colorpixel, colors.bar_bg);
- draw_text(block->full_text, statusline_pm, statusline_ctx, x + block->x_offset, 1, block->width);
+ draw_text(block->full_text, statusline_pm, statusline_ctx, x + block->x_offset, 0, block->width);
x += block->width + block->x_offset + block->x_append;
if (TAILQ_NEXT(block, blocks) != NULL && !block->no_separator && block->sep_block_width > 0) {
--
2.0.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.