Compare commits
61 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
35183ab81d | ||
|
09b5a9b8ba | ||
|
2f255b1756 | ||
|
8cd84e8edf | ||
|
b721a37ab0 | ||
|
1411d260a4 | ||
|
50fe7d2083 | ||
|
84be3d8dbf | ||
|
d680ea4256 | ||
|
44a708b7a4 | ||
|
40f08d5245 | ||
|
3dbdf9d078 | ||
|
a3fb967ad9 | ||
|
ae5a3a477a | ||
|
f2662d75c8 | ||
|
3020df1923 | ||
|
13dcc66cae | ||
|
c788534107 | ||
|
0f2cfbab28 | ||
|
61985278f2 | ||
|
d3d7a87b66 | ||
|
7c8eb7495b | ||
|
f26b88272e | ||
|
214ad63925 | ||
|
495ac4e546 | ||
|
e4ea4071ab | ||
|
63ed303553 | ||
|
e0aee14533 | ||
|
da26209013 | ||
|
2c0f57c584 | ||
|
3b5baa93b1 | ||
|
531c575575 | ||
|
6580e2d4f7 | ||
|
255c93dc7a | ||
|
38422c5014 | ||
|
1585d7257d | ||
|
7f8a79131b | ||
|
177deb0860 | ||
|
b331ee3927 | ||
|
71ed0d3375 | ||
|
63a55dd06c | ||
|
a390ef6a5c | ||
|
04d22b4ae5 | ||
|
73d8c58286 | ||
|
49fdc25f37 | ||
|
a8fa2766fb | ||
|
a9f285fd28 | ||
|
7880eac8c9 | ||
|
25c3441925 | ||
|
b82d96a68e | ||
|
ebb625b529 | ||
|
72106b17b1 | ||
|
19167c2e55 | ||
|
fe4ff881dd | ||
|
75dbf3397e | ||
|
eeb88f8ae0 | ||
|
d32cd8bce9 | ||
|
5186f68658 | ||
|
4ee19586a3 | ||
|
1ef64eab99 | ||
|
ab3a49962f |
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,5 +1,4 @@
|
||||||
config.h
|
lemonbar
|
||||||
bar
|
|
||||||
*.o
|
*.o
|
||||||
*.swp
|
*.swp
|
||||||
*~
|
*~
|
||||||
|
|
|
@ -3,5 +3,8 @@ compiler:
|
||||||
- clang
|
- clang
|
||||||
- gcc
|
- gcc
|
||||||
before_install:
|
before_install:
|
||||||
- sudo apt-get install -qq libx11-xcb-dev libxcb-randr0-dev libxcb-xinerama0-dev
|
- sudo apt-get update -qq
|
||||||
|
- sudo apt-get install -y libx11-xcb-dev libxcb-randr0-dev libxcb-xinerama0-dev
|
||||||
|
env:
|
||||||
|
- CFLAGS='-DWITH_XINERAMA=1'
|
||||||
script: make
|
script: make
|
||||||
|
|
28
Makefile
28
Makefile
|
@ -1,11 +1,19 @@
|
||||||
|
# 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
|
CC ?= gcc
|
||||||
CFLAGS = -g -Wall -std=c99 -Os
|
CFLAGS += -Wall -std=c99 -Os -DVERSION="\"$(VERSION)\""
|
||||||
LDFLAGS = -lxcb -lxcb-xinerama -lxcb-randr
|
LDFLAGS += -lxcb -lxcb-xinerama -lxcb-randr
|
||||||
CFDEBUG = -g3 -pedantic -Wall -Wunused-parameter -Wlong-long \
|
CFDEBUG = -g3 -pedantic -Wall -Wunused-parameter -Wlong-long \
|
||||||
-Wsign-conversion -Wconversion -Wimplicit-function-declaration
|
-Wsign-conversion -Wconversion -Wimplicit-function-declaration
|
||||||
|
|
||||||
EXEC = bar
|
EXEC = lemonbar
|
||||||
SRCS = bar.c
|
SRCS = lemonbar.c
|
||||||
OBJS = ${SRCS:.c=.o}
|
OBJS = ${SRCS:.c=.o}
|
||||||
|
|
||||||
PREFIX?=/usr
|
PREFIX?=/usr
|
||||||
|
@ -14,7 +22,7 @@ BINDIR=${PREFIX}/bin
|
||||||
all: ${EXEC}
|
all: ${EXEC}
|
||||||
|
|
||||||
doc: README.pod
|
doc: README.pod
|
||||||
pod2man --section=1 --center="bar Manual" --name "bar" --release="bar $(shell git describe --always)" README.pod > bar.1
|
pod2man --section=1 --center="lemonbar Manual" --name "lemonbar" --release="lemonbar $(VERSION)" README.pod > lemonbar.1
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
${CC} ${CFLAGS} -o $@ -c $<
|
${CC} ${CFLAGS} -o $@ -c $<
|
||||||
|
@ -29,12 +37,12 @@ clean:
|
||||||
rm -f ./*.o ./*.1
|
rm -f ./*.o ./*.1
|
||||||
rm -f ./${EXEC}
|
rm -f ./${EXEC}
|
||||||
|
|
||||||
install: bar doc
|
install: lemonbar doc
|
||||||
install -D -m 755 bar ${DESTDIR}${BINDIR}/bar
|
install -D -m 755 lemonbar ${DESTDIR}${BINDIR}/lemonbar
|
||||||
install -D -m 644 bar.1 ${DESTDIR}${PREFIX}/share/man/man1/bar.1
|
install -D -m 644 lemonbar.1 ${DESTDIR}${PREFIX}/share/man/man1/lemonbar.1
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f ${DESTDIR}${BINDIR}/bar
|
rm -f ${DESTDIR}${BINDIR}/lemonbar
|
||||||
rm -f $(DESTDIR)$(PREFIX)/share/man/man1/bar.1
|
rm -f $(DESTDIR)$(PREFIX)/share/man/man1/lemonbar.1
|
||||||
|
|
||||||
.PHONY: all debug clean install
|
.PHONY: all debug clean install
|
||||||
|
|
45
README.pod
45
README.pod
|
@ -1,16 +1,16 @@
|
||||||
=head1 NAME
|
=head1 NAME
|
||||||
|
|
||||||
bar - bar ain't recursive
|
lemonbar - Featherweight lemon-scented bar
|
||||||
|
|
||||||
=for HTML <a href="https://travis-ci.org/LemonBoy/bar"><img src="https://travis-ci.org/LemonBoy/bar.svg?branch=master"></a>
|
=for HTML <a href="https://travis-ci.org/LemonBoy/bar"><img src="https://travis-ci.org/LemonBoy/bar.svg?branch=master"></a>
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
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>]
|
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>]
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
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<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.
|
||||||
|
|
||||||
=head1 OPTIONS
|
=head1 OPTIONS
|
||||||
|
|
||||||
|
@ -34,11 +34,20 @@ Force docking without asking the window manager. This is needed if the window ma
|
||||||
|
|
||||||
=item B<-f> I<font>
|
=item B<-f> I<font>
|
||||||
|
|
||||||
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).
|
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)
|
||||||
|
|
||||||
=item B<-p>
|
=item B<-p>
|
||||||
|
|
||||||
Make bar permanent, don't exit after the standard input is closed.
|
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.
|
||||||
|
|
||||||
=item B<-u> I<pixel>
|
=item B<-u> I<pixel>
|
||||||
|
|
||||||
|
@ -46,17 +55,21 @@ Sets the underline width in pixels. The default is 1.
|
||||||
|
|
||||||
=item B<-B> I<color>
|
=item B<-B> I<color>
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
=item B<-F> I<color>
|
=item B<-F> I<color>
|
||||||
|
|
||||||
Set the foreground color of the bar. Accepts the same color formats as B<-B>.
|
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
|
=back
|
||||||
|
|
||||||
=head1 FORMATTING
|
=head1 FORMATTING
|
||||||
|
|
||||||
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.
|
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<%>).
|
||||||
|
|
||||||
=over
|
=over
|
||||||
|
|
||||||
|
@ -76,6 +89,10 @@ Aligns the following text to the center of the screen.
|
||||||
|
|
||||||
Aligns the following text to the right side 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>
|
=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.
|
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.
|
||||||
|
@ -86,7 +103,7 @@ Set the text foreground color. The parameter I<color> can be I<-> or a color in
|
||||||
|
|
||||||
=item B<T>I<index>
|
=item B<T>I<index>
|
||||||
|
|
||||||
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.
|
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
|
||||||
|
|
||||||
=item B<U>I<color>
|
=item B<U>I<color>
|
||||||
|
|
||||||
|
@ -94,15 +111,19 @@ Set the text underline color. The parameter I<color> can be I<-> or a color in o
|
||||||
|
|
||||||
=item B<A>I<button>:I<command>:
|
=item B<A>I<button>:I<command>:
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
Eg. I<%{A:reboot:} Click here to reboot %{A}>
|
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.
|
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>
|
=item B<S>I<dir>
|
||||||
|
|
||||||
Change the monitor bar is rendering to. I<dir> can be either
|
Change the monitor the bar is rendered to. I<dir> can be either
|
||||||
|
|
||||||
=over
|
=over
|
||||||
|
|
||||||
|
@ -156,7 +177,7 @@ Draw a line under the text.
|
||||||
|
|
||||||
=head1 OUTPUT
|
=head1 OUTPUT
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
=head1 WWW
|
=head1 WWW
|
||||||
|
|
||||||
|
@ -164,7 +185,7 @@ L<git repository|https://github.com/LemonBoy/bar>
|
||||||
|
|
||||||
=head1 AUTHOR
|
=head1 AUTHOR
|
||||||
|
|
||||||
2012-2014 (C) The Lemon Man
|
2012-2017 (C) The Lemon Man
|
||||||
|
|
||||||
Xinerama support was kindly contributed by Stebalien
|
Xinerama support was kindly contributed by Stebalien
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// vim:sw=4:ts=4:et:
|
// vim:sw=4:ts=4:et:
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -11,7 +12,9 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xcbext.h>
|
#include <xcb/xcbext.h>
|
||||||
|
#if WITH_XINERAMA
|
||||||
#include <xcb/xinerama.h>
|
#include <xcb/xinerama.h>
|
||||||
|
#endif
|
||||||
#include <xcb/randr.h>
|
#include <xcb/randr.h>
|
||||||
|
|
||||||
// Here be dragons
|
// Here be dragons
|
||||||
|
@ -22,7 +25,7 @@
|
||||||
|
|
||||||
typedef struct font_t {
|
typedef struct font_t {
|
||||||
xcb_font_t ptr;
|
xcb_font_t ptr;
|
||||||
int descent, height;
|
int descent, height, width;
|
||||||
uint16_t char_max;
|
uint16_t char_max;
|
||||||
uint16_t char_min;
|
uint16_t char_min;
|
||||||
xcb_charinfo_t *width_lut;
|
xcb_charinfo_t *width_lut;
|
||||||
|
@ -36,27 +39,28 @@ typedef struct monitor_t {
|
||||||
} monitor_t;
|
} monitor_t;
|
||||||
|
|
||||||
typedef struct area_t {
|
typedef struct area_t {
|
||||||
bool active;
|
unsigned int begin:16;
|
||||||
int begin, end, align, button;
|
unsigned int end:16;
|
||||||
|
bool active:1;
|
||||||
|
int align:3;
|
||||||
|
unsigned int button:3;
|
||||||
xcb_window_t window;
|
xcb_window_t window;
|
||||||
char *cmd;
|
char *cmd;
|
||||||
} area_t;
|
} area_t;
|
||||||
|
|
||||||
typedef union rgba_t {
|
typedef union rgba_t {
|
||||||
struct {
|
struct {
|
||||||
uint8_t r;
|
|
||||||
uint8_t g;
|
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t r;
|
||||||
uint8_t a;
|
uint8_t a;
|
||||||
};
|
};
|
||||||
uint32_t v;
|
uint32_t v;
|
||||||
} rgba_t;
|
} rgba_t;
|
||||||
|
|
||||||
#define N 20
|
|
||||||
|
|
||||||
typedef struct area_stack_t {
|
typedef struct area_stack_t {
|
||||||
int pos;
|
int at, max;
|
||||||
area_t slot[N];
|
area_t *area;
|
||||||
} area_stack_t;
|
} area_stack_t;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -94,8 +98,8 @@ static bool topbar = true;
|
||||||
static int bw = -1, bh = -1, bx = 0, by = 0;
|
static int bw = -1, bh = -1, bx = 0, by = 0;
|
||||||
static int bu = 1; // Underline height
|
static int bu = 1; // Underline height
|
||||||
static rgba_t fgc, bgc, ugc;
|
static rgba_t fgc, bgc, ugc;
|
||||||
static rgba_t dfgc, dbgc;
|
static rgba_t dfgc, dbgc, dugc;
|
||||||
static area_stack_t astack;
|
static area_stack_t area_stack;
|
||||||
|
|
||||||
void
|
void
|
||||||
update_gc (void)
|
update_gc (void)
|
||||||
|
@ -180,144 +184,60 @@ 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_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);
|
xcb_ret.sequence = xcb_send_request(c, 0, xcb_parts + 2, &xcb_req);
|
||||||
|
|
||||||
return xcb_ret;
|
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
|
int
|
||||||
xbm_parse (char *path)
|
shift (monitor_t *mon, int x, int align, int ch_width)
|
||||||
{
|
|
||||||
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) {
|
switch (align) {
|
||||||
case ALIGN_L:
|
|
||||||
return x;
|
|
||||||
|
|
||||||
case ALIGN_C:
|
case ALIGN_C:
|
||||||
xcb_copy_area(c, mon->pixmap, mon->pixmap, gc[GC_DRAW],
|
xcb_copy_area(c, mon->pixmap, mon->pixmap, gc[GC_DRAW],
|
||||||
mon->width / 2 - x / 2, 0,
|
mon->width / 2 - x / 2, 0,
|
||||||
mon->width / 2 - (x + w) / 2, 0,
|
mon->width / 2 - (x + ch_width) / 2, 0,
|
||||||
x, bh);
|
x, bh);
|
||||||
return mon->width / 2 - (x + w) / 2 + x;
|
x = mon->width / 2 - (x + ch_width) / 2 + x;
|
||||||
|
break;
|
||||||
case ALIGN_R:
|
case ALIGN_R:
|
||||||
xcb_copy_area(c, mon->pixmap, mon->pixmap, gc[GC_DRAW],
|
xcb_copy_area(c, mon->pixmap, mon->pixmap, gc[GC_DRAW],
|
||||||
mon->width - x, 0,
|
mon->width - x, 0,
|
||||||
mon->width - x - w, 0,
|
mon->width - x - ch_width, 0,
|
||||||
x, bh);
|
x, bh);
|
||||||
return mon->width - w;
|
x = mon->width - ch_width;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
// Draw the background first
|
||||||
|
fill_rect(mon->pixmap, gc[GC_CLEAR], x, 0, ch_width, bh);
|
||||||
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
draw_icon (monitor_t *mon, int x, xbm_t *icon, int align)
|
draw_lines (monitor_t *mon, int x, int w)
|
||||||
{
|
{
|
||||||
xcb_gcontext_t tmp_gc;
|
/* We can render both at the same time */
|
||||||
xcb_pixmap_t mask;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
x = pixmap_shift(mon, x, align, icon->width);
|
void
|
||||||
|
draw_shift (monitor_t *mon, int x, int align, int w)
|
||||||
mask = xcb_generate_id(c);
|
{
|
||||||
xcb_create_pixmap(c, 1, mask, mon->pixmap, icon->width, icon->height);
|
x = shift(mon, x, align, w);
|
||||||
|
draw_lines(mon, x, w);
|
||||||
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
|
int
|
||||||
draw_char (monitor_t *mon, font_t *cur_font, int x, int align, uint16_t ch)
|
draw_char (monitor_t *mon, font_t *cur_font, int x, int align, uint16_t ch)
|
||||||
{
|
{
|
||||||
int ch_width = cur_font->width_lut[ch - cur_font->char_min].character_width;
|
int ch_width = (cur_font->width_lut) ?
|
||||||
|
cur_font->width_lut[ch - cur_font->char_min].character_width:
|
||||||
|
cur_font->width;
|
||||||
|
|
||||||
x = pixmap_shift(mon, x, align, ch_width);
|
x = 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
|
// xcb accepts string in UCS-2 BE, so swap
|
||||||
ch = (ch >> 8) | (ch << 8);
|
ch = (ch >> 8) | (ch << 8);
|
||||||
|
@ -327,29 +247,15 @@ 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,
|
x, bh / 2 + cur_font->height / 2 - cur_font->descent,
|
||||||
1, &ch);
|
1, &ch);
|
||||||
|
|
||||||
// We can render both at the same time
|
draw_lines(mon, x, ch_width);
|
||||||
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;
|
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
|
rgba_t
|
||||||
parse_color (const char *str, char **end, const rgba_t def)
|
parse_color (const char *str, char **end, const rgba_t def)
|
||||||
{
|
{
|
||||||
xcb_alloc_named_color_reply_t *nc_reply;
|
|
||||||
int string_len;
|
int string_len;
|
||||||
rgba_t ret;
|
|
||||||
char *ep;
|
char *ep;
|
||||||
|
|
||||||
if (!str)
|
if (!str)
|
||||||
|
@ -364,7 +270,14 @@ parse_color (const char *str, char **end, const rgba_t def)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hex representation
|
// Hex representation
|
||||||
if (str[0] == '#') {
|
if (str[0] != '#') {
|
||||||
|
if (end)
|
||||||
|
*end = (char *)str;
|
||||||
|
|
||||||
|
fprintf(stderr, "Invalid color specified\n");
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
rgba_t tmp = (rgba_t)(uint32_t)strtoul(str + 1, &ep, 16);
|
rgba_t tmp = (rgba_t)(uint32_t)strtoul(str + 1, &ep, 16);
|
||||||
|
|
||||||
|
@ -379,9 +292,24 @@ parse_color (const char *str, char **end, const rgba_t def)
|
||||||
|
|
||||||
string_len = ep - (str + 1);
|
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
|
// If the code is in #rrggbb form then assume it's opaque
|
||||||
if (string_len <= 6)
|
|
||||||
tmp.a = 255;
|
tmp.a = 255;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
// Colors in #aarrggbb format, those need no adjustments
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Invalid color specified\n");
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
// Premultiply the alpha in
|
// Premultiply the alpha in
|
||||||
if (tmp.a) {
|
if (tmp.a) {
|
||||||
|
@ -397,28 +325,6 @@ parse_color (const char *str, char **end, const rgba_t def)
|
||||||
return (rgba_t)0U;
|
return (rgba_t)0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actual color name, resolve it
|
|
||||||
for (string_len = 0; isalpha(str[string_len]); string_len++)
|
|
||||||
;
|
|
||||||
|
|
||||||
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
|
void
|
||||||
set_attribute (const char modifier, const char attribute)
|
set_attribute (const char modifier, const char attribute)
|
||||||
{
|
{
|
||||||
|
@ -441,10 +347,9 @@ area_t *
|
||||||
area_get (xcb_window_t win, const int btn, const int x)
|
area_get (xcb_window_t win, const int btn, const int x)
|
||||||
{
|
{
|
||||||
// Looping backwards ensures that we get the innermost area first
|
// Looping backwards ensures that we get the innermost area first
|
||||||
for (int i = astack.pos; i >= 0; i--) {
|
for (int i = area_stack.at - 1; i >= 0; i--) {
|
||||||
area_t *a = &astack.slot[i];
|
area_t *a = &area_stack.area[i];
|
||||||
if (a->window == win && a->button == btn
|
if (a->window == win && a->button == btn && x >= a->begin && x < a->end)
|
||||||
&& x >= a->begin && x < a->end)
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -458,10 +363,11 @@ area_shift (xcb_window_t win, const int align, int delta)
|
||||||
if (align == ALIGN_C)
|
if (align == ALIGN_C)
|
||||||
delta /= 2;
|
delta /= 2;
|
||||||
|
|
||||||
for (int i = 0; i < astack.pos; i++) {
|
for (int i = 0; i < area_stack.at; i++) {
|
||||||
if (astack.slot[i].window == win && astack.slot[i].align == align) {
|
area_t *a = &area_stack.area[i];
|
||||||
astack.slot[i].begin -= delta;
|
if (a->window == win && a->align == align && !a->active) {
|
||||||
astack.slot[i].end -= delta;
|
a->begin -= delta;
|
||||||
|
a->end -= delta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -478,13 +384,15 @@ area_add (char *str, const char *optend, char **end, monitor_t *mon, const int x
|
||||||
*end = str;
|
*end = str;
|
||||||
|
|
||||||
// Find most recent unclosed area.
|
// Find most recent unclosed area.
|
||||||
for (i = astack.pos - 1; i >= 0 && !astack.slot[i].active; i--)
|
for (i = area_stack.at - 1; i >= 0 && !area_stack.area[i].active; i--)
|
||||||
;
|
;
|
||||||
a = &astack.slot[i];
|
a = &area_stack.area[i];
|
||||||
|
|
||||||
// Basic safety checks
|
// Basic safety checks
|
||||||
if (!a->cmd || a->align != align || a->window != mon->window)
|
if (!a->cmd || a->align != align || a->window != mon->window) {
|
||||||
|
fprintf(stderr, "Invalid geometry for the clickable area\n");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const int size = x - a->begin;
|
const int size = x - a->begin;
|
||||||
|
|
||||||
|
@ -507,11 +415,12 @@ area_add (char *str, const char *optend, char **end, monitor_t *mon, const int x
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (astack.pos >= N) {
|
if (area_stack.at + 1 > area_stack.max) {
|
||||||
fprintf(stderr, "astack overflow!\n");
|
fprintf(stderr, "Cannot add any more clickable areas (used %d/%d)\n",
|
||||||
|
area_stack.at, area_stack.max);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
a = &astack.slot[astack.pos++];
|
a = &area_stack.area[area_stack.at++];
|
||||||
|
|
||||||
// Found the closing : and check if it's just an escaped one
|
// Found the closing : and check if it's just an escaped one
|
||||||
for (trail = strchr(++str, ':'); trail && trail[-1] == '\\'; trail = strchr(trail + 1, ':'))
|
for (trail = strchr(++str, ':'); trail && trail[-1] == '\\'; trail = strchr(trail + 1, ':'))
|
||||||
|
@ -550,10 +459,13 @@ area_add (char *str, const char *optend, char **end, monitor_t *mon, const int x
|
||||||
bool
|
bool
|
||||||
font_has_glyph (font_t *font, const uint16_t c)
|
font_has_glyph (font_t *font, const uint16_t c)
|
||||||
{
|
{
|
||||||
return (c >= font->char_min &&
|
if (c < font->char_min || c > font->char_max)
|
||||||
c <= font->char_max &&
|
return false;
|
||||||
font->width_lut &&
|
|
||||||
font->width_lut[c - font->char_min].character_width);
|
if (font->width_lut && font->width_lut[c - font->char_min].character_width == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns NULL if character cannot be printed
|
// returns NULL if character cannot be printed
|
||||||
|
@ -564,7 +476,7 @@ select_drawable_font (const uint16_t c)
|
||||||
if (font_index != -1 && font_has_glyph(font_list[font_index - 1], c))
|
if (font_index != -1 && font_has_glyph(font_list[font_index - 1], c))
|
||||||
return font_list[font_index - 1];
|
return font_list[font_index - 1];
|
||||||
|
|
||||||
// If the end is reached without finding an apropriate font, return NULL.
|
// If the end is reached without finding an appropriate font, return NULL.
|
||||||
// If the font can draw the character, return it.
|
// If the font can draw the character, return it.
|
||||||
for (int i = 0; i < font_count; i++) {
|
for (int i = 0; i < font_count; i++) {
|
||||||
if (font_has_glyph(font_list[i], c))
|
if (font_has_glyph(font_list[i], c))
|
||||||
|
@ -579,14 +491,15 @@ parse (char *text)
|
||||||
font_t *cur_font;
|
font_t *cur_font;
|
||||||
monitor_t *cur_mon;
|
monitor_t *cur_mon;
|
||||||
int pos_x, align, button;
|
int pos_x, align, button;
|
||||||
char *p = text, *end;
|
char *p = text, *block_end, *ep;
|
||||||
rgba_t tmp;
|
rgba_t tmp;
|
||||||
|
|
||||||
pos_x = 0;
|
pos_x = 0;
|
||||||
align = ALIGN_L;
|
align = ALIGN_L;
|
||||||
cur_mon = monhead;
|
cur_mon = monhead;
|
||||||
|
|
||||||
memset(&astack, 0, sizeof(area_stack_t));
|
// Reset the stack position
|
||||||
|
area_stack.at = 0;
|
||||||
|
|
||||||
for (monitor_t *m = monhead; m != NULL; m = m->next)
|
for (monitor_t *m = monhead; m != NULL; m = m->next)
|
||||||
fill_rect(m->pixmap, gc[GC_CLEAR], 0, 0, m->width, bh);
|
fill_rect(m->pixmap, gc[GC_CLEAR], 0, 0, m->width, bh);
|
||||||
|
@ -595,8 +508,10 @@ parse (char *text)
|
||||||
if (*p == '\0' || *p == '\n')
|
if (*p == '\0' || *p == '\n')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (*p == '%' && p++ && *p == '{' && (end = strchr(p++, '}'))) {
|
if (p[0] == '%' && p[1] == '{' && (block_end = strchr(p++, '}'))) {
|
||||||
while (p < end) {
|
p++;
|
||||||
|
while (p < block_end) {
|
||||||
|
int w;
|
||||||
while (isspace(*p))
|
while (isspace(*p))
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
|
@ -621,12 +536,13 @@ parse (char *text)
|
||||||
// The range is 1-5
|
// The range is 1-5
|
||||||
if (isdigit(*p) && (*p > '0' && *p < '6'))
|
if (isdigit(*p) && (*p > '0' && *p < '6'))
|
||||||
button = *p++ - '0';
|
button = *p++ - '0';
|
||||||
area_add(p, end, &p, cur_mon, pos_x, align, button);
|
if (!area_add(p, block_end, &p, cur_mon, pos_x, align, button))
|
||||||
|
return;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'B': bgc = parse_color(p, &p, dbgc); update_gc(); break;
|
case 'B': bgc = parse_color(p, &p, dbgc); update_gc(); break;
|
||||||
case 'F': fgc = parse_color(p, &p, dfgc); update_gc(); break;
|
case 'F': fgc = parse_color(p, &p, dfgc); update_gc(); break;
|
||||||
case 'U': ugc = parse_color(p, &p, dbgc); update_gc(); break;
|
case 'U': ugc = parse_color(p, &p, dugc); update_gc(); break;
|
||||||
|
|
||||||
case 'S':
|
case 'S':
|
||||||
if (*p == '+' && cur_mon->next)
|
if (*p == '+' && cur_mon->next)
|
||||||
|
@ -648,35 +564,48 @@ parse (char *text)
|
||||||
p++;
|
p++;
|
||||||
pos_x = 0;
|
pos_x = 0;
|
||||||
break;
|
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':
|
case 'T':
|
||||||
font_index = (int)strtoul(p, NULL, 10);
|
if (*p == '-') { //Reset to automatic font selection
|
||||||
|
font_index = -1;
|
||||||
|
p++;
|
||||||
|
break;
|
||||||
|
} else if (isdigit(*p)) {
|
||||||
|
font_index = (int)strtoul(p, &ep, 10);
|
||||||
// User-specified 'font_index' ∊ (0,font_count]
|
// User-specified 'font_index' ∊ (0,font_count]
|
||||||
// Otherwise just fallback to the automatic font selection
|
// Otherwise just fallback to the automatic font selection
|
||||||
if (!font_index || font_index > font_count)
|
if (!font_index || font_index > font_count)
|
||||||
font_index = -1;
|
font_index = -1;
|
||||||
p = end;
|
p = ep;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Invalid font slot \"%c\"\n", *p++); //Swallow the token
|
||||||
break;
|
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 }
|
// In case of error keep parsing after the closing }
|
||||||
default:
|
default:
|
||||||
p = end;
|
p = block_end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Eat the trailing }
|
// Eat the trailing }
|
||||||
p++;
|
p++;
|
||||||
} else { // utf-8 -> ucs-2
|
} else { // utf-8 -> ucs-2
|
||||||
|
// Escaped % symbol, eat the first one
|
||||||
|
if (p[0] == '%' && p[1] == '%')
|
||||||
|
p++;
|
||||||
|
|
||||||
uint8_t *utf = (uint8_t *)p;
|
uint8_t *utf = (uint8_t *)p;
|
||||||
uint16_t ucs;
|
uint16_t ucs;
|
||||||
|
|
||||||
|
@ -705,7 +634,7 @@ parse (char *text)
|
||||||
ucs = 0xfffd;
|
ucs = 0xfffd;
|
||||||
p += 5;
|
p += 5;
|
||||||
}
|
}
|
||||||
// Siz byte utf8 sequence
|
// Six byte utf8 sequence
|
||||||
else if ((utf[0] & 0xfe) == 0xfc) {
|
else if ((utf[0] & 0xfe) == 0xfc) {
|
||||||
ucs = 0xfffd;
|
ucs = 0xfffd;
|
||||||
p += 6;
|
p += 6;
|
||||||
|
@ -723,16 +652,21 @@ parse (char *text)
|
||||||
xcb_change_gc(c, gc[GC_DRAW] , XCB_GC_FONT, (const uint32_t []){ cur_font->ptr });
|
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);
|
int w = draw_char(cur_mon, cur_font, pos_x, align, ucs);
|
||||||
pos_x += w;
|
|
||||||
|
|
||||||
|
pos_x += w;
|
||||||
area_shift(cur_mon->window, align, w);
|
area_shift(cur_mon->window, align, w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
font_t *
|
void
|
||||||
font_load (const char *str)
|
font_load (const char *pattern)
|
||||||
{
|
{
|
||||||
|
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_cookie_t queryreq;
|
||||||
xcb_query_font_reply_t *font_info;
|
xcb_query_font_reply_t *font_info;
|
||||||
xcb_void_cookie_t cookie;
|
xcb_void_cookie_t cookie;
|
||||||
|
@ -740,16 +674,16 @@ font_load (const char *str)
|
||||||
|
|
||||||
font = xcb_generate_id(c);
|
font = xcb_generate_id(c);
|
||||||
|
|
||||||
cookie = xcb_open_font_checked(c, font, strlen(str), str);
|
cookie = xcb_open_font_checked(c, font, strlen(pattern), pattern);
|
||||||
if (xcb_request_check (c, cookie)) {
|
if (xcb_request_check (c, cookie)) {
|
||||||
fprintf(stderr, "Could not load font \"%s\"\n", str);
|
fprintf(stderr, "Could not load font \"%s\"\n", pattern);
|
||||||
return NULL;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
font_t *ret = calloc(1, sizeof(font_t));
|
font_t *ret = calloc(1, sizeof(font_t));
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return NULL;
|
return;
|
||||||
|
|
||||||
queryreq = xcb_query_font(c, font);
|
queryreq = xcb_query_font(c, font);
|
||||||
font_info = xcb_query_font_reply(c, queryreq, NULL);
|
font_info = xcb_query_font_reply(c, queryreq, NULL);
|
||||||
|
@ -757,6 +691,7 @@ font_load (const char *str)
|
||||||
ret->ptr = font;
|
ret->ptr = font;
|
||||||
ret->descent = font_info->font_descent;
|
ret->descent = font_info->font_descent;
|
||||||
ret->height = font_info->font_ascent + 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_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;
|
ret->char_min = font_info->min_byte1 << 8 | font_info->min_char_or_byte2;
|
||||||
|
|
||||||
|
@ -769,7 +704,7 @@ font_load (const char *str)
|
||||||
|
|
||||||
free(font_info);
|
free(font_info);
|
||||||
|
|
||||||
return ret;
|
font_list[font_count++] = ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -821,11 +756,11 @@ set_ewmh_atoms (void)
|
||||||
if (topbar) {
|
if (topbar) {
|
||||||
strut[2] = bh;
|
strut[2] = bh;
|
||||||
strut[8] = mon->x;
|
strut[8] = mon->x;
|
||||||
strut[9] = mon->x + mon->width;
|
strut[9] = mon->x + mon->width - 1;
|
||||||
} else {
|
} else {
|
||||||
strut[3] = bh;
|
strut[3] = bh;
|
||||||
strut[10] = mon->x;
|
strut[10] = mon->x;
|
||||||
strut[11] = mon->x + mon->width;
|
strut[11] = mon->x + mon->width - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
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]);
|
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]);
|
||||||
|
@ -889,10 +824,15 @@ rect_sort_cb (const void *p1, const void *p2)
|
||||||
const xcb_rectangle_t *r1 = (xcb_rectangle_t *)p1;
|
const xcb_rectangle_t *r1 = (xcb_rectangle_t *)p1;
|
||||||
const xcb_rectangle_t *r2 = (xcb_rectangle_t *)p2;
|
const xcb_rectangle_t *r2 = (xcb_rectangle_t *)p2;
|
||||||
|
|
||||||
if (r1->x < r2->x || r1->y < r2->y)
|
if (r1->x < r2->x || r1->y + r1->height <= r2->y)
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
if (r1->x > r2->x || r1->y > r2->y)
|
}
|
||||||
|
|
||||||
|
if (r1->x > r2->x || r1->y + r1->height > r2->y)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -941,6 +881,9 @@ monitor_create_chain (xcb_rectangle_t *rects, const int num)
|
||||||
min(width, rects[i].width - left),
|
min(width, rects[i].width - left),
|
||||||
rects[i].height);
|
rects[i].height);
|
||||||
|
|
||||||
|
if (!mon)
|
||||||
|
break;
|
||||||
|
|
||||||
monitor_add(mon);
|
monitor_add(mon);
|
||||||
|
|
||||||
width -= rects[i].width - left;
|
width -= rects[i].width - left;
|
||||||
|
@ -1025,7 +968,7 @@ get_randr_monitors (void)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (j = 0; j < num; j++) {
|
for (j = 0; j < num; j++) {
|
||||||
// Does I countain J ?
|
// Does I contain J ?
|
||||||
|
|
||||||
if (i != j && rects[j].width) {
|
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 &&
|
if (rects[j].x >= rects[i].x && rects[j].x + rects[j].width <= rects[i].x + rects[i].width &&
|
||||||
|
@ -1051,6 +994,7 @@ get_randr_monitors (void)
|
||||||
monitor_create_chain(r, valid);
|
monitor_create_chain(r, valid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_XINERAMA
|
||||||
void
|
void
|
||||||
get_xinerama_monitors (void)
|
get_xinerama_monitors (void)
|
||||||
{
|
{
|
||||||
|
@ -1079,6 +1023,7 @@ get_xinerama_monitors (void)
|
||||||
|
|
||||||
monitor_create_chain(rects, screens);
|
monitor_create_chain(rects, screens);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
xcb_visualid_t
|
xcb_visualid_t
|
||||||
get_visual (void)
|
get_visual (void)
|
||||||
|
@ -1101,7 +1046,7 @@ get_visual (void)
|
||||||
return scr->root_visual;
|
return scr->root_visual;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse an X-styled geometry string, we don't support signed offsets tho.
|
// Parse an X-styled geometry string, we don't support signed offsets though.
|
||||||
bool
|
bool
|
||||||
parse_geometry_string (char *str, int *tmp)
|
parse_geometry_string (char *str, int *tmp)
|
||||||
{
|
{
|
||||||
|
@ -1152,46 +1097,6 @@ parse_geometry_string (char *str, int *tmp)
|
||||||
return true;
|
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
|
void
|
||||||
xconn (void)
|
xconn (void)
|
||||||
{
|
{
|
||||||
|
@ -1213,15 +1118,11 @@ xconn (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
init (void)
|
init (char *wm_name)
|
||||||
{
|
{
|
||||||
// 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
|
// Try to load a default font
|
||||||
if (!font_count)
|
if (!font_count)
|
||||||
parse_font_list(fallback_font);
|
font_load("fixed");
|
||||||
|
|
||||||
// We tried and failed hard, there's something wrong
|
// We tried and failed hard, there's something wrong
|
||||||
if (!font_count)
|
if (!font_count)
|
||||||
|
@ -1239,7 +1140,7 @@ init (void)
|
||||||
// Generate a list of screens
|
// Generate a list of screens
|
||||||
const xcb_query_extension_reply_t *qe_reply;
|
const xcb_query_extension_reply_t *qe_reply;
|
||||||
|
|
||||||
// Initialiaze monitor list head and tail
|
// Initialize monitor list head and tail
|
||||||
monhead = montail = NULL;
|
monhead = montail = NULL;
|
||||||
|
|
||||||
// Check if RandR is present
|
// Check if RandR is present
|
||||||
|
@ -1247,7 +1148,9 @@ init (void)
|
||||||
|
|
||||||
if (qe_reply && qe_reply->present) {
|
if (qe_reply && qe_reply->present) {
|
||||||
get_randr_monitors();
|
get_randr_monitors();
|
||||||
} else {
|
}
|
||||||
|
#if WITH_XINERAMA
|
||||||
|
else {
|
||||||
qe_reply = xcb_get_extension_data(c, &xcb_xinerama_id);
|
qe_reply = xcb_get_extension_data(c, &xcb_xinerama_id);
|
||||||
|
|
||||||
// Check if Xinerama extension is present and active
|
// Check if Xinerama extension is present and active
|
||||||
|
@ -1261,6 +1164,7 @@ init (void)
|
||||||
free(xia_reply);
|
free(xia_reply);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!monhead) {
|
if (!monhead) {
|
||||||
// If I fits I sits
|
// If I fits I sits
|
||||||
|
@ -1305,6 +1209,10 @@ init (void)
|
||||||
// Make sure that the window really gets in the place it's supposed to be
|
// Make sure that the window really gets in the place it's supposed to be
|
||||||
// Some WM such as Openbox need this
|
// 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 });
|
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);
|
xcb_flush(c);
|
||||||
|
@ -1313,6 +1221,8 @@ init (void)
|
||||||
void
|
void
|
||||||
cleanup (void)
|
cleanup (void)
|
||||||
{
|
{
|
||||||
|
free(area_stack.area);
|
||||||
|
|
||||||
for (int i = 0; i < font_count; i++) {
|
for (int i = 0; i < font_count; i++) {
|
||||||
xcb_close_font(c, font_list[i]->ptr);
|
xcb_close_font(c, font_list[i]->ptr);
|
||||||
free(font_list[i]->width_lut);
|
free(font_list[i]->width_lut);
|
||||||
|
@ -1359,47 +1269,72 @@ main (int argc, char **argv)
|
||||||
char input[4096] = {0, };
|
char input[4096] = {0, };
|
||||||
bool permanent = false;
|
bool permanent = false;
|
||||||
int geom_v[4] = { -1, -1, 0, 0 };
|
int geom_v[4] = { -1, -1, 0, 0 };
|
||||||
int ch;
|
int ch, areas;
|
||||||
|
char *wm_name;
|
||||||
|
|
||||||
// Install the parachute!
|
// Install the parachute!
|
||||||
atexit(cleanup);
|
atexit(cleanup);
|
||||||
signal(SIGINT, sighandle);
|
signal(SIGINT, sighandle);
|
||||||
signal(SIGTERM, 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
|
// Connect to the Xserver and initialize scr
|
||||||
xconn();
|
xconn();
|
||||||
|
|
||||||
// B/W combo
|
while ((ch = getopt(argc, argv, "hg:bdf:a:pu:B:F:U:n:")) != -1) {
|
||||||
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) {
|
switch (ch) {
|
||||||
case 'h':
|
case 'h':
|
||||||
printf ("usage: %s [-h | -g | -b | -d | -f | -a | -p | -u | -B | -F]\n"
|
printf ("lemonbar version %s\n", VERSION);
|
||||||
|
printf ("usage: %s [-h | -g | -b | -d | -f | -a | -p | -n | -u | -B | -F]\n"
|
||||||
"\t-h Show this help\n"
|
"\t-h Show this help\n"
|
||||||
"\t-g Set the bar geometry {width}x{height}+{xoffset}+{yoffset}\n"
|
"\t-g Set the bar geometry {width}x{height}+{xoffset}+{yoffset}\n"
|
||||||
"\t-b Put bar at the bottom of the screen\n"
|
"\t-b Put the bar at the bottom of the screen\n"
|
||||||
"\t-d Force docking (use this if your WM isn't EWMH compliant)\n"
|
"\t-d Force docking (use this if your WM isn't EWMH compliant)\n"
|
||||||
"\t-f Bar font list, comma separated\n"
|
"\t-f Set the font name to use\n"
|
||||||
|
"\t-a Number of clickable areas available (default is 10)\n"
|
||||||
"\t-p Don't close after the data ends\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-u Set the underline/overline height in pixels\n"
|
||||||
"\t-B Set background color in #AARRGGBB\n"
|
"\t-B Set background color in #AARRGGBB\n"
|
||||||
"\t-F Set foreground color in #AARRGGBB\n", argv[0]);
|
"\t-F Set foreground color in #AARRGGBB\n", argv[0]);
|
||||||
exit (EXIT_SUCCESS);
|
exit (EXIT_SUCCESS);
|
||||||
case 'g': (void)parse_geometry_string(optarg, geom_v); break;
|
case 'g': (void)parse_geometry_string(optarg, geom_v); break;
|
||||||
case 'p': permanent = true; break;
|
case 'p': permanent = true; break;
|
||||||
|
case 'n': wm_name = strdup(optarg); break;
|
||||||
case 'b': topbar = false; break;
|
case 'b': topbar = false; break;
|
||||||
case 'd': dock = true; break;
|
case 'd': dock = true; break;
|
||||||
case 'f': parse_font_list(optarg); break;
|
case 'f': font_load(optarg); break;
|
||||||
case 'u': bu = strtoul(optarg, NULL, 10); break;
|
case 'u': bu = strtoul(optarg, NULL, 10); break;
|
||||||
case 'B': dbgc = bgc = parse_color(optarg, NULL, (rgba_t)scr->black_pixel); break;
|
case 'B': dbgc = bgc = parse_color(optarg, NULL, (rgba_t)0x00000000U); break;
|
||||||
case 'F': dfgc = fgc = parse_color(optarg, NULL, (rgba_t)scr->white_pixel); 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
// Copy the geometry values in place
|
||||||
bw = geom_v[0];
|
bw = geom_v[0];
|
||||||
bh = geom_v[1];
|
bh = geom_v[1];
|
||||||
|
@ -1407,12 +1342,12 @@ main (int argc, char **argv)
|
||||||
by = geom_v[3];
|
by = geom_v[3];
|
||||||
|
|
||||||
// Do the heavy lifting
|
// Do the heavy lifting
|
||||||
init();
|
init(wm_name);
|
||||||
|
// The string is strdup'd when the command line arguments are parsed
|
||||||
|
free(wm_name);
|
||||||
// Get the fd to Xserver
|
// Get the fd to Xserver
|
||||||
pollin[1].fd = xcb_get_file_descriptor(c);
|
pollin[1].fd = xcb_get_file_descriptor(c);
|
||||||
|
|
||||||
xbm_load (fox_bits, xbm_w, xbm_h);
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
bool redraw = false;
|
bool redraw = false;
|
||||||
|
|
||||||
|
@ -1432,7 +1367,7 @@ main (int argc, char **argv)
|
||||||
parse(input);
|
parse(input);
|
||||||
redraw = true;
|
redraw = true;
|
||||||
}
|
}
|
||||||
if (pollin[1].revents & POLLIN) { // Xserver broadcasted an event
|
if (pollin[1].revents & POLLIN) { // The event comes from the Xorg server
|
||||||
while ((ev = xcb_poll_for_event(c))) {
|
while ((ev = xcb_poll_for_event(c))) {
|
||||||
expose_ev = (xcb_expose_event_t *)ev;
|
expose_ev = (xcb_expose_event_t *)ev;
|
||||||
|
|
||||||
|
@ -1447,8 +1382,8 @@ main (int argc, char **argv)
|
||||||
area_t *area = area_get(press_ev->event, press_ev->detail, press_ev->event_x);
|
area_t *area = area_get(press_ev->event, press_ev->detail, press_ev->event_x);
|
||||||
// Respond to the click
|
// Respond to the click
|
||||||
if (area) {
|
if (area) {
|
||||||
write(STDOUT_FILENO, area->cmd, strlen(area->cmd));
|
(void)write(STDOUT_FILENO, area->cmd, strlen(area->cmd));
|
||||||
write(STDOUT_FILENO, "\n", 1);
|
(void)write(STDOUT_FILENO, "\n", 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
36
palette.pl
36
palette.pl
|
@ -1,36 +0,0 @@
|
||||||
#!/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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user