Compare commits

..

3 Commits
master ... xbm

Author SHA1 Message Date
LemonBoy a116c04ed9 p 2015-02-28 17:29:37 +01:00
LemonBoy 9dd806b9fc pppp 2015-02-15 23:49:33 +01:00
LemonBoy fa9cfcbbd7 pew 2015-02-14 16:43:45 +01:00
6 changed files with 377 additions and 307 deletions

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
lemonbar
config.h
bar
*.o
*.swp
*~

View File

@ -3,8 +3,5 @@ compiler:
- clang
- gcc
before_install:
- sudo apt-get update -qq
- sudo apt-get install -y libx11-xcb-dev libxcb-randr0-dev libxcb-xinerama0-dev
env:
- CFLAGS='-DWITH_XINERAMA=1'
- sudo apt-get install -qq libx11-xcb-dev libxcb-randr0-dev libxcb-xinerama0-dev
script: make

View File

@ -1,19 +1,11 @@
# This snippet has been shmelessly stol^Hborrowed from thestinger's repose Makefile
VERSION = 1.3
GIT_DESC=$(shell test -d .git && git describe --always 2>/dev/null)
ifneq "$(GIT_DESC)" ""
VERSION=$(GIT_DESC)
endif
CC ?= gcc
CFLAGS += -Wall -std=c99 -Os -DVERSION="\"$(VERSION)\""
LDFLAGS += -lxcb -lxcb-xinerama -lxcb-randr
CFDEBUG = -g3 -pedantic -Wall -Wunused-parameter -Wlong-long \
-Wsign-conversion -Wconversion -Wimplicit-function-declaration
CFLAGS = -g -Wall -std=c99 -Os
LDFLAGS = -lxcb -lxcb-xinerama -lxcb-randr
CFDEBUG = -g3 -pedantic -Wall -Wunused-parameter -Wlong-long\
-Wsign-conversion -Wconversion -Wimplicit-function-declaration
EXEC = lemonbar
SRCS = lemonbar.c
EXEC = bar
SRCS = bar.c
OBJS = ${SRCS:.c=.o}
PREFIX?=/usr
@ -22,7 +14,7 @@ BINDIR=${PREFIX}/bin
all: ${EXEC}
doc: README.pod
pod2man --section=1 --center="lemonbar Manual" --name "lemonbar" --release="lemonbar $(VERSION)" README.pod > lemonbar.1
pod2man --section=1 --center="bar Manual" --name "bar" --release="bar $(shell git describe --always)" README.pod > bar.1
.c.o:
${CC} ${CFLAGS} -o $@ -c $<
@ -37,12 +29,12 @@ clean:
rm -f ./*.o ./*.1
rm -f ./${EXEC}
install: lemonbar doc
install -D -m 755 lemonbar ${DESTDIR}${BINDIR}/lemonbar
install -D -m 644 lemonbar.1 ${DESTDIR}${PREFIX}/share/man/man1/lemonbar.1
install: bar doc
install -D -m 755 bar ${DESTDIR}${BINDIR}/bar
install -D -m 644 bar.1 ${DESTDIR}${PREFIX}/share/man/man1/bar.1
uninstall:
rm -f ${DESTDIR}${BINDIR}/lemonbar
rm -f $(DESTDIR)$(PREFIX)/share/man/man1/lemonbar.1
rm -f ${DESTDIR}${BINDIR}/bar
rm -f $(DESTDIR)$(PREFIX)/share/man/man1/bar.1
.PHONY: all debug clean install

View File

@ -1,16 +1,16 @@
=head1 NAME
lemonbar - Featherweight lemon-scented bar
bar - bar ain't recursive
=for HTML <a href="https://travis-ci.org/LemonBoy/bar"><img src="https://travis-ci.org/LemonBoy/bar.svg?branch=master"></a>
=head1 SYNOPSIS
I<lemonbar> [-h | -g I<width>B<x>I<height>B<+>I<x>B<+>I<y> | -b | -d | -f I<font> | -p | -n I<name> | -u I<pixel> | -B I<color> | -F I<color> | -U I<color>]
I<bar> [-h | -g I<width>B<x>I<height>B<+>I<x>B<+>I<y> | -b | -d | -f I<font> | -p | -u I<pixel> | -B I<color> | -F I<color>]
=head1 DESCRIPTION
B<lemonbar> (formerly known as B<bar>) is a lightweight bar entirely based on XCB. Provides full UTF-8 support, basic formatting, RandR and Xinerama support and EWMH compliance without wasting your precious memory.
B<bar> is a lightweight bar entirely based on XCB. Provides full UTF-8 support, basic formatting, RandR and Xinerama support and EWMH compliance without wasting your precious memory.
=head1 OPTIONS
@ -34,20 +34,11 @@ Force docking without asking the window manager. This is needed if the window ma
=item B<-f> I<font>
Define the font to load into one of the five slots (the number of slots is hardcoded and can be tweaked by
changing the MAX_FONT_COUNT parameter in the source code).
=item B<-a> I<number>
Set number of clickable areas (default is 10)
Comma separated list of fonts, bar supports a maximum of five fonts (the limit can be tweaked by changing the MAX_FONT_COUNT parameter in the source).
=item B<-p>
Make the bar permanent, don't exit after the standard input is closed.
=item B<-n> I<name>
Set the WM_NAME atom value for the bar.
Make bar permanent, don't exit after the standard input is closed.
=item B<-u> I<pixel>
@ -55,21 +46,17 @@ Sets the underline width in pixels. The default is 1.
=item B<-B> I<color>
Set the background color of the bar. I<color> must be specified in the hex format (#aarrggbb, #rrggbb, #rgb). If no compositor such as compton or xcompmgr is running the alpha channel is silently ignored.
Set the background color of the bar. I<color> might be either in hex format (#aarrggbb) or in the symbolic name format (eg. white, indianred, darkgray). If no compositor such as compton or xcompmgr is running the alpha channel is silently ignored.
=item B<-F> I<color>
Set the foreground color of the bar. Accepts the same color formats as B<-B>.
=item B<-U> I<color>
Set the underline color of the bar. Accepts the same color formats as B<-B>.
=back
=head1 FORMATTING
lemonbar provides a screenrc-inspired formatting syntax to allow full customization at runtime. Every formatting block is opened with C<%{> and closed by C<}> and accepts the following commands, the parser tries its best to handle malformed input. Use C<%%> to get a literal percent sign (C<%>).
bar provides a screenrc-inspired formatting syntax to allow full customization at runtime. Every formatting block is opened with B<%{> and closed by B<}> and accepts the following commands, the parser tries it's best to handle malformed input.
=over
@ -89,10 +76,6 @@ Aligns the following text to the center of the screen.
Aligns the following text to the right side of the screen.
=item B<O>I<width>
Offset the current position by I<width> pixels in the alignment direction.
=item B<B>I<color>
Set the text background 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.
@ -103,7 +86,7 @@ Set the text foreground color. The parameter I<color> can be I<-> or a color in
=item B<T>I<index>
Set the font used to draw the following text. The parameter I<index> can either be I<-> or the 1-based index of the slot which contains the desired font. If the parameter is I<-> lemonbar resets to the normal behavior (matching the first font that can be used for the character). If the selected font can't be used to draw a character, lemonbar will fall back to normal behavior for that character
Set the font used to draw the following text. The parameter I<index> is a 1-based index of the font list supplied to bar. Any other value (for example I<->) resets bar to normal behaviour (matching the first font that can be used for that character). If the selected font can't be used to draw a character, bar will fall back to normal behaviour for that character.
=item B<U>I<color>
@ -111,19 +94,15 @@ Set the text underline color. The parameter I<color> can be I<-> or a color in o
=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.
Create a clickable area starting from the current position, when the area is clicked I<command> is executed. The area is closed when a B<A> token, not followed by : is encountered.
Eg. I<%{A:reboot:} Click here to reboot %{A}>
The I<button> field is optional, it defaults to the left button, and it's a number ranging from 1 to 5 which maps to the left, middle, right, scroll up and scroll down movements. Your mileage may vary.
Nested clickable areas can trigger different commands.
Eg. I<%{A:reboot:}%{A3:halt:} Left click to reboot, right click to shutdown %{A}%{A}>
=item B<S>I<dir>
Change the monitor the bar is rendered to. I<dir> can be either
Change the monitor bar is rendering to. I<dir> can be either
=over
@ -177,7 +156,7 @@ Draw a line under the text.
=head1 OUTPUT
Clicking on an area makes lemonbar output the command to stdout, followed by a newline, allowing the user to pipe it into a script, execute it or simply ignore it. Simple and powerful, that's it.
Clicking on an area makes bar output the command to stdout, followed by a newline, allowing the user to pipe it into a script, execute it or simply ignore it. Simple and powerful, that's it.
=head1 WWW
@ -185,7 +164,7 @@ L<git repository|https://github.com/LemonBoy/bar>
=head1 AUTHOR
2012-2017 (C) The Lemon Man
2012-2014 (C) The Lemon Man
Xinerama support was kindly contributed by Stebalien

View File

@ -1,5 +1,4 @@
// vim:sw=4:ts=4:et:
#define _POSIX_C_SOURCE 200809L
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@ -12,9 +11,7 @@
#include <errno.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
#if WITH_XINERAMA
#include <xcb/xinerama.h>
#endif
#include <xcb/randr.h>
// Here be dragons
@ -25,7 +22,7 @@
typedef struct font_t {
xcb_font_t ptr;
int descent, height, width;
int descent, height;
uint16_t char_max;
uint16_t char_min;
xcb_charinfo_t *width_lut;
@ -39,28 +36,27 @@ typedef struct monitor_t {
} monitor_t;
typedef struct area_t {
unsigned int begin:16;
unsigned int end:16;
bool active:1;
int align:3;
unsigned int button:3;
bool active;
int begin, end, align, button;
xcb_window_t window;
char *cmd;
} area_t;
typedef union rgba_t {
struct {
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
uint32_t v;
} rgba_t;
#define N 20
typedef struct area_stack_t {
int at, max;
area_t *area;
int pos;
area_t slot[N];
} area_stack_t;
enum {
@ -98,8 +94,8 @@ static bool topbar = true;
static int bw = -1, bh = -1, bx = 0, by = 0;
static int bu = 1; // Underline height
static rgba_t fgc, bgc, ugc;
static rgba_t dfgc, dbgc, dugc;
static area_stack_t area_stack;
static rgba_t dfgc, dbgc;
static area_stack_t astack;
void
update_gc (void)
@ -151,10 +147,10 @@ xcb_void_cookie_t xcb_poly_text_16_simple(xcb_connection_t * c,
uint32_t len, const uint16_t *str)
{
static const xcb_protocol_request_t xcb_req = {
5, // count
0, // ext
XCB_POLY_TEXT_16, // opcode
1 // isvoid
5, // count
0, // ext
XCB_POLY_TEXT_16, // opcode
1 // isvoid
};
struct iovec xcb_parts[7];
uint8_t xcb_lendelta[2];
@ -184,60 +180,144 @@ xcb_void_cookie_t xcb_poly_text_16_simple(xcb_connection_t * c,
xcb_parts[6].iov_len = -(xcb_parts[4].iov_len + xcb_parts[5].iov_len) & 3;
xcb_ret.sequence = xcb_send_request(c, 0, xcb_parts + 2, &xcb_req);
return xcb_ret;
}
#define pad_to(x, to) (((x) + (to) - 1) & ~((to) - 1))
typedef struct xbm_t {
int width;
int height;
uint8_t *bits;
size_t bits_size;
} xbm_t;
xbm_t xbm_cache[20];
int xbm_cache_elem = 0;
int
shift (monitor_t *mon, int x, int align, int ch_width)
xbm_parse (char *path)
{
FILE *fp;
char line[4096];
int xbm_height, xcb_width;
fp = fopen(path, "r");
if (!fp)
return 0;
while (fgets(line, sizeof(line), fp)) {
}
}
xbm_t *
xbm_load (uint8_t *bits, int width, int height)
{
const xcb_setup_t *setup = xcb_get_setup(c);
uint8_t *buf;
int width_b, line;
xbm_t *ico = &xbm_cache[xbm_cache_elem];
// XCB_IMAGE_ORDER_LSB_FIRST
// bitmap_format_bit_order
width_b = (width + 7) / 8;
line = pad_to(width_b, setup->bitmap_format_scanline_pad >> 3);
buf = malloc(height * line);
if (!buf)
return NULL;
// Despite the naming, this is actually a stencil
for (int i = 0; i < height * width_b; i++)
bits[i] = ~bits[i];
for (int i = 0; i < height; i++)
memcpy(buf + (i * line),
bits + (i * width_b),
width_b);
ico->width = width;
ico->height = height;
ico->bits = buf;
ico->bits_size = height * line;
xbm_cache_elem++;
return ico;
}
int
pixmap_shift (monitor_t *mon, int x, int align, int w)
{
switch (align) {
case ALIGN_L:
return x;
case ALIGN_C:
xcb_copy_area(c, mon->pixmap, mon->pixmap, gc[GC_DRAW],
mon->width / 2 - x / 2, 0,
mon->width / 2 - (x + ch_width) / 2, 0,
mon->width / 2 - (x + w) / 2, 0,
x, bh);
x = mon->width / 2 - (x + ch_width) / 2 + x;
break;
return mon->width / 2 - (x + w) / 2 + x;
case ALIGN_R:
xcb_copy_area(c, mon->pixmap, mon->pixmap, gc[GC_DRAW],
mon->width - x, 0,
mon->width - x - ch_width, 0,
mon->width - x - w, 0,
x, bh);
x = mon->width - ch_width;
break;
return mon->width - w;
}
// Draw the background first
fill_rect(mon->pixmap, gc[GC_CLEAR], x, 0, ch_width, bh);
return x;
return 0;
}
void
draw_lines (monitor_t *mon, int x, int w)
int
draw_icon (monitor_t *mon, int x, xbm_t *icon, int align)
{
/* We can render both at the same time */
if (attrs & ATTR_OVERL)
fill_rect(mon->pixmap, gc[GC_ATTR], x, 0, w, bu);
if (attrs & ATTR_UNDERL)
fill_rect(mon->pixmap, gc[GC_ATTR], x, bh - bu, w, bu);
}
xcb_gcontext_t tmp_gc;
xcb_pixmap_t mask;
void
draw_shift (monitor_t *mon, int x, int align, int w)
{
x = shift(mon, x, align, w);
draw_lines(mon, x, w);
x = pixmap_shift(mon, x, align, icon->width);
mask = xcb_generate_id(c);
xcb_create_pixmap(c, 1, mask, mon->pixmap, icon->width, icon->height);
tmp_gc = xcb_generate_id(c);
xcb_create_gc(c, tmp_gc, mask, 0, NULL);
xcb_put_image(
c,
XCB_IMAGE_FORMAT_XY_BITMAP,
mask,
tmp_gc,
icon->width, icon->height,
0, 0,
0, 1,
icon->bits_size, icon->bits);
xcb_free_gc(c, tmp_gc);
xcb_change_gc(c, gc[GC_DRAW], XCB_GC_CLIP_MASK, (const uint32_t []){ mask });
xcb_change_gc(c, gc[GC_DRAW], XCB_GC_CLIP_ORIGIN_X | XCB_GC_CLIP_ORIGIN_Y,
(const uint32_t []){ x, bh / 2 - icon->height / 2 });
xcb_poly_fill_rectangle(c, mon->pixmap, gc[GC_DRAW], 1,
(const xcb_rectangle_t []){ { 0, 0, bw, bh } });
xcb_change_gc(c, gc[GC_DRAW], XCB_GC_CLIP_MASK, (const uint32_t []){ XCB_NONE });
xcb_free_pixmap(c, mask);
return icon->width;
}
int
draw_char (monitor_t *mon, font_t *cur_font, int x, int align, uint16_t ch)
{
int ch_width = (cur_font->width_lut) ?
cur_font->width_lut[ch - cur_font->char_min].character_width:
cur_font->width;
int ch_width = cur_font->width_lut[ch - cur_font->char_min].character_width;
x = shift(mon, x, align, ch_width);
x = pixmap_shift(mon, x, align, ch_width);
// Draw the background first
fill_rect(mon->pixmap, gc[GC_CLEAR], x, by, ch_width, bh);
// xcb accepts string in UCS-2 BE, so swap
ch = (ch >> 8) | (ch << 8);
@ -247,15 +327,29 @@ draw_char (monitor_t *mon, font_t *cur_font, int x, int align, uint16_t ch)
x, bh / 2 + cur_font->height / 2 - cur_font->descent,
1, &ch);
draw_lines(mon, x, ch_width);
// We can render both at the same time
if (attrs & ATTR_OVERL)
fill_rect(mon->pixmap, gc[GC_ATTR], x, 0, ch_width, bu);
if (attrs & ATTR_UNDERL)
fill_rect(mon->pixmap, gc[GC_ATTR], x, bh - bu, ch_width, bu);
return ch_width;
}
static unsigned char fox_bits[] = {
0x70, 0x88, 0xC4, 0xE2, 0x7E, 0x32, 0x09, 0x07
0x81, 0xC3, 0xBD, 0xFF, 0x99, 0xDB, 0x7E, 0x18,
};
int xbm_w = 8;
int xbm_h = 8;
rgba_t
parse_color (const char *str, char **end, const rgba_t def)
{
xcb_alloc_named_color_reply_t *nc_reply;
int string_len;
rgba_t ret;
char *ep;
if (!str)
@ -270,61 +364,61 @@ parse_color (const char *str, char **end, const rgba_t def)
}
// Hex representation
if (str[0] != '#') {
if (str[0] == '#') {
errno = 0;
rgba_t tmp = (rgba_t)(uint32_t)strtoul(str + 1, &ep, 16);
if (end)
*end = (char *)str;
*end = ep;
fprintf(stderr, "Invalid color specified\n");
return def;
}
errno = 0;
rgba_t tmp = (rgba_t)(uint32_t)strtoul(str + 1, &ep, 16);
if (end)
*end = ep;
// Some error checking is definitely good
if (errno) {
fprintf(stderr, "Invalid color specified\n");
return def;
}
string_len = ep - (str + 1);
switch (string_len) {
case 3:
// Expand the #rgb format into #rrggbb (aa is set to 0xff)
tmp.v = (tmp.v & 0xf00) * 0x1100
| (tmp.v & 0x0f0) * 0x0110
| (tmp.v & 0x00f) * 0x0011;
case 6:
// If the code is in #rrggbb form then assume it's opaque
tmp.a = 255;
break;
case 7:
case 8:
// Colors in #aarrggbb format, those need no adjustments
break;
default:
// Some error checking is definitely good
if (errno) {
fprintf(stderr, "Invalid color specified\n");
return def;
}
string_len = ep - (str + 1);
// If the code is in #rrggbb form then assume it's opaque
if (string_len <= 6)
tmp.a = 255;
// Premultiply the alpha in
if (tmp.a) {
// The components are clamped automagically as the rgba_t is made of uint8_t
return (rgba_t){
.r = (tmp.r * tmp.a) / 255,
.g = (tmp.g * tmp.a) / 255,
.b = (tmp.b * tmp.a) / 255,
.a = tmp.a,
};
}
return (rgba_t)0U;
}
// Premultiply the alpha in
if (tmp.a) {
// The components are clamped automagically as the rgba_t is made of uint8_t
return (rgba_t){
.r = (tmp.r * tmp.a) / 255,
.g = (tmp.g * tmp.a) / 255,
.b = (tmp.b * tmp.a) / 255,
.a = tmp.a,
};
}
// Actual color name, resolve it
for (string_len = 0; isalpha(str[string_len]); string_len++)
;
return (rgba_t)0U;
nc_reply = xcb_alloc_named_color_reply(c, xcb_alloc_named_color(c, colormap, string_len, str), NULL);
if (!nc_reply)
fprintf(stderr, "Could not alloc color \"%.*s\"\n", string_len, str);
ret = nc_reply?
(rgba_t)nc_reply->pixel:
def;
free(nc_reply);
if (end)
*end = (char *)str + string_len;
return ret;
}
void
set_attribute (const char modifier, const char attribute)
{
@ -347,9 +441,10 @@ area_t *
area_get (xcb_window_t win, const int btn, const int x)
{
// Looping backwards ensures that we get the innermost area first
for (int i = area_stack.at - 1; i >= 0; i--) {
area_t *a = &area_stack.area[i];
if (a->window == win && a->button == btn && x >= a->begin && x < a->end)
for (int i = astack.pos; i >= 0; i--) {
area_t *a = &astack.slot[i];
if (a->window == win && a->button == btn
&& x >= a->begin && x < a->end)
return a;
}
return NULL;
@ -363,11 +458,10 @@ area_shift (xcb_window_t win, const int align, int delta)
if (align == ALIGN_C)
delta /= 2;
for (int i = 0; i < area_stack.at; i++) {
area_t *a = &area_stack.area[i];
if (a->window == win && a->align == align && !a->active) {
a->begin -= delta;
a->end -= delta;
for (int i = 0; i < astack.pos; i++) {
if (astack.slot[i].window == win && astack.slot[i].align == align) {
astack.slot[i].begin -= delta;
astack.slot[i].end -= delta;
}
}
}
@ -384,15 +478,13 @@ area_add (char *str, const char *optend, char **end, monitor_t *mon, const int x
*end = str;
// Find most recent unclosed area.
for (i = area_stack.at - 1; i >= 0 && !area_stack.area[i].active; i--)
for (i = astack.pos - 1; i >= 0 && !astack.slot[i].active; i--)
;
a = &area_stack.area[i];
a = &astack.slot[i];
// Basic safety checks
if (!a->cmd || a->align != align || a->window != mon->window) {
fprintf(stderr, "Invalid geometry for the clickable area\n");
if (!a->cmd || a->align != align || a->window != mon->window)
return false;
}
const int size = x - a->begin;
@ -415,12 +507,11 @@ area_add (char *str, const char *optend, char **end, monitor_t *mon, const int x
return true;
}
if (area_stack.at + 1 > area_stack.max) {
fprintf(stderr, "Cannot add any more clickable areas (used %d/%d)\n",
area_stack.at, area_stack.max);
if (astack.pos >= N) {
fprintf(stderr, "astack overflow!\n");
return false;
}
a = &area_stack.area[area_stack.at++];
a = &astack.slot[astack.pos++];
// Found the closing : and check if it's just an escaped one
for (trail = strchr(++str, ':'); trail && trail[-1] == '\\'; trail = strchr(trail + 1, ':'))
@ -459,13 +550,10 @@ area_add (char *str, const char *optend, char **end, monitor_t *mon, const int x
bool
font_has_glyph (font_t *font, const uint16_t c)
{
if (c < font->char_min || c > font->char_max)
return false;
if (font->width_lut && font->width_lut[c - font->char_min].character_width == 0)
return false;
return true;
return (c >= font->char_min &&
c <= font->char_max &&
font->width_lut &&
font->width_lut[c - font->char_min].character_width);
}
// returns NULL if character cannot be printed
@ -476,7 +564,7 @@ select_drawable_font (const uint16_t c)
if (font_index != -1 && font_has_glyph(font_list[font_index - 1], c))
return font_list[font_index - 1];
// If the end is reached without finding an appropriate font, return NULL.
// If the end is reached without finding an apropriate font, return NULL.
// If the font can draw the character, return it.
for (int i = 0; i < font_count; i++) {
if (font_has_glyph(font_list[i], c))
@ -491,15 +579,14 @@ parse (char *text)
font_t *cur_font;
monitor_t *cur_mon;
int pos_x, align, button;
char *p = text, *block_end, *ep;
char *p = text, *end;
rgba_t tmp;
pos_x = 0;
align = ALIGN_L;
cur_mon = monhead;
// Reset the stack position
area_stack.at = 0;
memset(&astack, 0, sizeof(area_stack_t));
for (monitor_t *m = monhead; m != NULL; m = m->next)
fill_rect(m->pixmap, gc[GC_CLEAR], 0, 0, m->width, bh);
@ -508,10 +595,8 @@ parse (char *text)
if (*p == '\0' || *p == '\n')
return;
if (p[0] == '%' && p[1] == '{' && (block_end = strchr(p++, '}'))) {
p++;
while (p < block_end) {
int w;
if (*p == '%' && p++ && *p == '{' && (end = strchr(p++, '}'))) {
while (p < end) {
while (isspace(*p))
p++;
@ -536,13 +621,12 @@ parse (char *text)
// The range is 1-5
if (isdigit(*p) && (*p > '0' && *p < '6'))
button = *p++ - '0';
if (!area_add(p, block_end, &p, cur_mon, pos_x, align, button))
return;
area_add(p, end, &p, cur_mon, pos_x, align, button);
break;
case 'B': bgc = parse_color(p, &p, dbgc); update_gc(); break;
case 'F': fgc = parse_color(p, &p, dfgc); update_gc(); break;
case 'U': ugc = parse_color(p, &p, dugc); update_gc(); break;
case 'U': ugc = parse_color(p, &p, dbgc); update_gc(); break;
case 'S':
if (*p == '+' && cur_mon->next)
@ -564,48 +648,35 @@ parse (char *text)
p++;
pos_x = 0;
break;
case 'O':
errno = 0;
w = (int) strtoul(p, &p, 10);
if (errno)
continue;
draw_shift(cur_mon, pos_x, align, w);
pos_x += w;
area_shift(cur_mon->window, align, w);
break;
case 'T':
if (*p == '-') { //Reset to automatic font selection
font_index = (int)strtoul(p, NULL, 10);
// User-specified 'font_index' ∊ (0,font_count]
// Otherwise just fallback to the automatic font selection
if (!font_index || font_index > font_count)
font_index = -1;
p++;
break;
} else if (isdigit(*p)) {
font_index = (int)strtoul(p, &ep, 10);
// User-specified 'font_index' ∊ (0,font_count]
// Otherwise just fallback to the automatic font selection
if (!font_index || font_index > font_count)
font_index = -1;
p = ep;
break;
} else {
fprintf(stderr, "Invalid font slot \"%c\"\n", *p++); //Swallow the token
break;
p = end;
break;
case 'i':
;
int icon_index = (int)strtoul(p, NULL, 10);
if (icon_index < xbm_cache_elem) {
int w = draw_icon(cur_mon, pos_x, &xbm_cache[0], align);
pos_x += w;
area_shift(cur_mon->window, align, w);
}
p = end;
break;
// In case of error keep parsing after the closing }
default:
p = block_end;
p = end;
}
}
// Eat the trailing }
p++;
} else { // utf-8 -> ucs-2
// Escaped % symbol, eat the first one
if (p[0] == '%' && p[1] == '%')
p++;
uint8_t *utf = (uint8_t *)p;
uint16_t ucs;
@ -634,7 +705,7 @@ parse (char *text)
ucs = 0xfffd;
p += 5;
}
// Six byte utf8 sequence
// Siz byte utf8 sequence
else if ((utf[0] & 0xfe) == 0xfc) {
ucs = 0xfffd;
p += 6;
@ -652,21 +723,16 @@ parse (char *text)
xcb_change_gc(c, gc[GC_DRAW] , XCB_GC_FONT, (const uint32_t []){ cur_font->ptr });
int w = draw_char(cur_mon, cur_font, pos_x, align, ucs);
pos_x += w;
area_shift(cur_mon->window, align, w);
}
}
}
void
font_load (const char *pattern)
font_t *
font_load (const char *str)
{
if (font_count >= MAX_FONT_COUNT) {
fprintf(stderr, "Max font count reached. Could not load font \"%s\"\n", pattern);
return;
}
xcb_query_font_cookie_t queryreq;
xcb_query_font_reply_t *font_info;
xcb_void_cookie_t cookie;
@ -674,16 +740,16 @@ font_load (const char *pattern)
font = xcb_generate_id(c);
cookie = xcb_open_font_checked(c, font, strlen(pattern), pattern);
cookie = xcb_open_font_checked(c, font, strlen(str), str);
if (xcb_request_check (c, cookie)) {
fprintf(stderr, "Could not load font \"%s\"\n", pattern);
return;
fprintf(stderr, "Could not load font \"%s\"\n", str);
return NULL;
}
font_t *ret = calloc(1, sizeof(font_t));
if (!ret)
return;
return NULL;
queryreq = xcb_query_font(c, font);
font_info = xcb_query_font_reply(c, queryreq, NULL);
@ -691,7 +757,6 @@ font_load (const char *pattern)
ret->ptr = font;
ret->descent = font_info->font_descent;
ret->height = font_info->font_ascent + font_info->font_descent;
ret->width = font_info->max_bounds.character_width;
ret->char_max = font_info->max_byte1 << 8 | font_info->max_char_or_byte2;
ret->char_min = font_info->min_byte1 << 8 | font_info->min_char_or_byte2;
@ -704,7 +769,7 @@ font_load (const char *pattern)
free(font_info);
font_list[font_count++] = ret;
return ret;
}
enum {
@ -756,11 +821,11 @@ set_ewmh_atoms (void)
if (topbar) {
strut[2] = bh;
strut[8] = mon->x;
strut[9] = mon->x + mon->width - 1;
strut[9] = mon->x + mon->width;
} else {
strut[3] = bh;
strut[10] = mon->x;
strut[11] = mon->x + mon->width - 1;
strut[11] = mon->x + mon->width;
}
xcb_change_property(c, XCB_PROP_MODE_REPLACE, mon->window, atom_list[NET_WM_WINDOW_TYPE], XCB_ATOM_ATOM, 32, 1, &atom_list[NET_WM_WINDOW_TYPE_DOCK]);
@ -824,15 +889,10 @@ rect_sort_cb (const void *p1, const void *p2)
const xcb_rectangle_t *r1 = (xcb_rectangle_t *)p1;
const xcb_rectangle_t *r2 = (xcb_rectangle_t *)p2;
if (r1->x < r2->x || r1->y + r1->height <= r2->y)
{
if (r1->x < r2->x || r1->y < r2->y)
return -1;
}
if (r1->x > r2->x || r1->y + r1->height > r2->y)
{
return 1;
}
if (r1->x > r2->x || r1->y > r2->y)
return 1;
return 0;
}
@ -881,9 +941,6 @@ monitor_create_chain (xcb_rectangle_t *rects, const int num)
min(width, rects[i].width - left),
rects[i].height);
if (!mon)
break;
monitor_add(mon);
width -= rects[i].width - left;
@ -968,7 +1025,7 @@ get_randr_monitors (void)
continue;
for (j = 0; j < num; j++) {
// Does I contain J ?
// Does I countain J ?
if (i != j && rects[j].width) {
if (rects[j].x >= rects[i].x && rects[j].x + rects[j].width <= rects[i].x + rects[i].width &&
@ -994,7 +1051,6 @@ get_randr_monitors (void)
monitor_create_chain(r, valid);
}
#ifdef WITH_XINERAMA
void
get_xinerama_monitors (void)
{
@ -1023,7 +1079,6 @@ get_xinerama_monitors (void)
monitor_create_chain(rects, screens);
}
#endif
xcb_visualid_t
get_visual (void)
@ -1046,7 +1101,7 @@ get_visual (void)
return scr->root_visual;
}
// Parse an X-styled geometry string, we don't support signed offsets though.
// Parse an X-styled geometry string, we don't support signed offsets tho.
bool
parse_geometry_string (char *str, int *tmp)
{
@ -1097,6 +1152,46 @@ parse_geometry_string (char *str, int *tmp)
return true;
}
void
parse_font_list (char *str)
{
char *tok, *end;
if (!str)
return;
tok = strtok(str, ",");
while (tok) {
if (font_count > MAX_FONT_COUNT - 1) {
fprintf(stderr, "Too many fonts; maximum %i\n", MAX_FONT_COUNT);
return;
}
// Strip the leading and trailing whitespaces
while (isspace(*tok) || iscntrl(*tok))
tok++;
end = tok + strlen(tok) - 1;
while ((end > tok && isspace(*end)) || iscntrl(*end))
end--;
*(end + 1) = '\0';
if (tok[0]) {
// Load the selected font
font_t *font = font_load(tok);
if (font)
font_list[font_count++] = font;
}
else
fprintf(stderr, "Empty font name, skipping...\n");
tok = strtok(NULL, ",");
}
}
void
xconn (void)
{
@ -1118,11 +1213,15 @@ xconn (void)
}
void
init (char *wm_name)
init (void)
{
// This has to be declared as an array because otherwise the compiler would turn it into a const
// string, making strtok choke very hard on this
char fallback_font[] = "fixed";
// Try to load a default font
if (!font_count)
font_load("fixed");
parse_font_list(fallback_font);
// We tried and failed hard, there's something wrong
if (!font_count)
@ -1140,7 +1239,7 @@ init (char *wm_name)
// Generate a list of screens
const xcb_query_extension_reply_t *qe_reply;
// Initialize monitor list head and tail
// Initialiaze monitor list head and tail
monhead = montail = NULL;
// Check if RandR is present
@ -1148,9 +1247,7 @@ init (char *wm_name)
if (qe_reply && qe_reply->present) {
get_randr_monitors();
}
#if WITH_XINERAMA
else {
} else {
qe_reply = xcb_get_extension_data(c, &xcb_xinerama_id);
// Check if Xinerama extension is present and active
@ -1164,7 +1261,6 @@ init (char *wm_name)
free(xia_reply);
}
}
#endif
if (!monhead) {
// If I fits I sits
@ -1209,10 +1305,6 @@ init (char *wm_name)
// Make sure that the window really gets in the place it's supposed to be
// Some WM such as Openbox need this
xcb_configure_window(c, mon->window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, (const uint32_t []){ mon->x, mon->y });
// Set the WM_NAME atom to the user specified value
if (wm_name)
xcb_change_property(c, XCB_PROP_MODE_REPLACE, mon->window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8 ,strlen(wm_name), wm_name);
}
xcb_flush(c);
@ -1221,8 +1313,6 @@ init (char *wm_name)
void
cleanup (void)
{
free(area_stack.area);
for (int i = 0; i < font_count; i++) {
xcb_close_font(c, font_list[i]->ptr);
free(font_list[i]->width_lut);
@ -1269,72 +1359,47 @@ main (int argc, char **argv)
char input[4096] = {0, };
bool permanent = false;
int geom_v[4] = { -1, -1, 0, 0 };
int ch, areas;
char *wm_name;
int ch;
// Install the parachute!
atexit(cleanup);
signal(SIGINT, sighandle);
signal(SIGTERM, sighandle);
// B/W combo
dbgc = bgc = (rgba_t)0x00000000U;
dfgc = fgc = (rgba_t)0xffffffffU;
dugc = ugc = fgc;
// A safe default
areas = 10;
wm_name = NULL;
// Connect to the Xserver and initialize scr
xconn();
while ((ch = getopt(argc, argv, "hg:bdf:a:pu:B:F:U:n:")) != -1) {
// B/W combo
dbgc = bgc = parse_color("black", NULL, (rgba_t)scr->black_pixel);
dfgc = fgc = parse_color("white", NULL, (rgba_t)scr->white_pixel);
ugc = fgc;
while ((ch = getopt(argc, argv, "hg:bdf:a:pu:B:F:")) != -1) {
switch (ch) {
case 'h':
printf ("lemonbar version %s\n", VERSION);
printf ("usage: %s [-h | -g | -b | -d | -f | -a | -p | -n | -u | -B | -F]\n"
printf ("usage: %s [-h | -g | -b | -d | -f | -a | -p | -u | -B | -F]\n"
"\t-h Show this help\n"
"\t-g Set the bar geometry {width}x{height}+{xoffset}+{yoffset}\n"
"\t-b Put the bar at the bottom of the screen\n"
"\t-b Put bar at the bottom of the screen\n"
"\t-d Force docking (use this if your WM isn't EWMH compliant)\n"
"\t-f Set the font name to use\n"
"\t-a Number of clickable areas available (default is 10)\n"
"\t-f Bar font list, comma separated\n"
"\t-p Don't close after the data ends\n"
"\t-n Set the WM_NAME atom to the specified value for this bar\n"
"\t-u Set the underline/overline height in pixels\n"
"\t-B Set background color in #AARRGGBB\n"
"\t-F Set foreground color in #AARRGGBB\n", argv[0]);
exit (EXIT_SUCCESS);
case 'g': (void)parse_geometry_string(optarg, geom_v); break;
case 'p': permanent = true; break;
case 'n': wm_name = strdup(optarg); break;
case 'b': topbar = false; break;
case 'd': dock = true; break;
case 'f': font_load(optarg); break;
case 'f': parse_font_list(optarg); break;
case 'u': bu = strtoul(optarg, NULL, 10); break;
case 'B': dbgc = bgc = parse_color(optarg, NULL, (rgba_t)0x00000000U); break;
case 'F': dfgc = fgc = parse_color(optarg, NULL, (rgba_t)0xffffffffU); break;
case 'U': dugc = ugc = parse_color(optarg, NULL, fgc); break;
case 'a': areas = strtoul(optarg, NULL, 10); break;
case 'B': dbgc = bgc = parse_color(optarg, NULL, (rgba_t)scr->black_pixel); break;
case 'F': dfgc = fgc = parse_color(optarg, NULL, (rgba_t)scr->white_pixel); break;
}
}
// Initialize the stack holding the clickable areas
area_stack.at = 0;
area_stack.max = areas;
if (areas) {
area_stack.area = calloc(areas, sizeof(area_t));
if (!area_stack.area) {
fprintf(stderr, "Could not allocate enough memory for %d clickable areas, try lowering the number\n", areas);
return EXIT_FAILURE;
}
}
else
area_stack.area = NULL;
// Copy the geometry values in place
bw = geom_v[0];
bh = geom_v[1];
@ -1342,12 +1407,12 @@ main (int argc, char **argv)
by = geom_v[3];
// Do the heavy lifting
init(wm_name);
// The string is strdup'd when the command line arguments are parsed
free(wm_name);
init();
// Get the fd to Xserver
pollin[1].fd = xcb_get_file_descriptor(c);
xbm_load (fox_bits, xbm_w, xbm_h);
for (;;) {
bool redraw = false;
@ -1367,7 +1432,7 @@ main (int argc, char **argv)
parse(input);
redraw = true;
}
if (pollin[1].revents & POLLIN) { // The event comes from the Xorg server
if (pollin[1].revents & POLLIN) { // Xserver broadcasted an event
while ((ev = xcb_poll_for_event(c))) {
expose_ev = (xcb_expose_event_t *)ev;
@ -1382,8 +1447,8 @@ main (int argc, char **argv)
area_t *area = area_get(press_ev->event, press_ev->detail, press_ev->event_x);
// Respond to the click
if (area) {
(void)write(STDOUT_FILENO, area->cmd, strlen(area->cmd));
(void)write(STDOUT_FILENO, "\n", 1);
write(STDOUT_FILENO, area->cmd, strlen(area->cmd));
write(STDOUT_FILENO, "\n", 1);
}
}
break;

36
palette.pl Executable file
View File

@ -0,0 +1,36 @@
#!/usr/bin/env perl
#
# palette.pl
#
# Converts your .Xdefault/.Xresources colors into a ready to paste palette
# for bar. It takes your foreground/background settings into account and if
# it cant find them it leaves COLOR0/COLOR1 undefined.
#
use strict;
use warnings;
open (F, "<".$ARGV[0]) || die "Can't open!";
our %vars = ();
while (<F>) {
# Don't match comments
if ($_ !~ m/^\s*!/) {
# It's a define!
if ($_ =~ m/^\s*#define\s+(\w+)\s+#([0-9A-Fa-f]{1,6})/) {
$vars{"$1"} = hex($2);
}
elsif ($_ =~ m/^\s*\w*\*(background|foreground|color\d)\s*:\s*([\w\d#]+)/) {
my ($name, $value) = (uc $1, $2);
# Check if it's a color
if (substr($value, 0, 1) eq '#') {
$value = hex(substr($value, 1));
} else {
$value = $vars{"$value"};
}
printf "#define $name 0x%06x\n", $value;
}
}
}