Add transparency support. Reworked EWMH stuff, fixes #20.

This commit is contained in:
LemonBoy 2013-09-02 13:35:32 +00:00
parent 216162c7eb
commit d87fc1f0c8
3 changed files with 69 additions and 70 deletions

View File

@ -1,10 +1,11 @@
b(ar) a(in't) r(ecursive)
=========================
2012 (C) The Lemon Man
2012-2013 (C) The Lemon Man
A lightweight bar based on XCB (yay). Provides foreground/background color
switching along with text alignment (screw you dzen!), full utf8 support
and reduced memory footprint. Nothing less and nothing more.
and reduced memory footprint. It also supports transparency when using a
compositor such as compton. Nothing less and nothing more.
Options
-------
@ -13,6 +14,7 @@ bar accepts a couple of command line switches.
```
-h Show the help and bail out.
-p Make the bar permanent.
-f Force docking (use this if your WM isn't EWMH compliant)
-b Show the bar at the bottom of the screen.
```

127
bar.c
View File

@ -44,6 +44,7 @@ static xcb_gcontext_t clear_gc;
static xcb_gcontext_t underl_gc;
static int bar_width;
static int bar_bottom = BAR_BOTTOM;
static int force_docking = 0;
static fontset_item_t fontset[FONT_MAX];
static fontset_item_t *sel_font = NULL;
@ -240,72 +241,67 @@ font_load (const char **font_list)
return 0;
}
int
set_ewmh_atoms (xcb_window_t root)
enum {
NET_WM_WINDOW_TYPE,
NET_WM_WINDOW_TYPE_DOCK,
NET_WM_DESKTOP,
NET_WM_STRUT_PARTIAL,
NET_WM_STRUT,
NET_WM_STATE,
NET_WM_WINDOW_OPACITY,
NET_WM_STATE_STICKY,
NET_WM_STATE_ABOVE,
};
void
set_ewmh_atoms ()
{
xcb_intern_atom_cookie_t cookies[5];
xcb_intern_atom_reply_t *reply;
xcb_get_property_reply_t *reply1;
xcb_atom_t atoms[5];
int compliance_lvl;
uint32_t v[12] = {0};
const char *atom_names[] = {
"_NET_WM_WINDOW_TYPE",
"_NET_WM_WINDOW_TYPE_DOCK",
"_NET_WM_DESKTOP",
"_NET_WM_STRUT_PARTIAL",
"_NET_WM_STRUT",
"_NET_WM_STATE",
"_NET_WM_WINDOW_OPACITY",
/* Leave those at the end since are batch-set */
"_NET_WM_STATE_STICKY",
"_NET_WM_STATE_ABOVE",
};
const int atoms = sizeof(atom_names)/sizeof(char *);
xcb_intern_atom_cookie_t atom_cookie[atoms];
xcb_atom_t atom_list[atoms];
xcb_intern_atom_reply_t *atom_reply;
int strut[12] = {0};
cookies[0] = xcb_intern_atom (c, 0, strlen ("_NET_WM_WINDOW_TYPE") , "_NET_WM_WINDOW_TYPE");
cookies[1] = xcb_intern_atom (c, 0, strlen ("_NET_WM_WINDOW_TYPE_DOCK"), "_NET_WM_WINDOW_TYPE_DOCK");
cookies[2] = xcb_intern_atom (c, 0, strlen ("_NET_WM_DESKTOP") , "_NET_WM_DESKTOP");
cookies[3] = xcb_intern_atom (c, 0, strlen ("_NET_WM_STRUT_PARTIAL") , "_NET_WM_STRUT_PARTIAL");
cookies[4] = xcb_intern_atom (c, 0, strlen ("_NET_SUPPORTED") , "_NET_SUPPORTED");
/* As suggested fetch all the cookies first (yum!) and then retrieve the
* atoms to exploit the async'ness */
for (int i = 0; i < atoms; i++)
atom_cookie[i] = xcb_intern_atom(c, 0, strlen(atom_names[i]), atom_names[i]);
reply = xcb_intern_atom_reply (c, cookies[0], NULL);
atoms[0] = reply->atom; free (reply);
reply = xcb_intern_atom_reply (c, cookies[1], NULL);
atoms[1] = reply->atom; free (reply);
reply = xcb_intern_atom_reply (c, cookies[2], NULL);
atoms[2] = reply->atom; free (reply);
reply = xcb_intern_atom_reply (c, cookies[3], NULL);
atoms[3] = reply->atom; free (reply);
reply = xcb_intern_atom_reply (c, cookies[4], NULL);
atoms[4] = reply->atom; free (reply);
compliance_lvl = 0;
reply1 = xcb_get_property_reply (c, xcb_get_property (c, 0, root, atoms[4], XCB_ATOM_ATOM, 0, -1), NULL);
if (!reply)
return compliance_lvl;
for (xcb_atom_t *a = xcb_get_property_value (reply1);
a && a != xcb_get_property_value_end (reply1).data;
a++)
{
/* Set the _NET_WM_WINDOW_TYPE_DOCK state */
if (*a == atoms[0]) {
xcb_change_property (c, XCB_PROP_MODE_REPLACE, win, atoms[0], XCB_ATOM_ATOM, 32, 1, &atoms[1]);
compliance_lvl++;
for (int i = 0; i < atoms; i++) {
atom_reply = xcb_intern_atom_reply(c, atom_cookie[i], NULL);
if (!atom_reply)
return;
atom_list[i] = atom_reply->atom;
free(atom_reply);
}
/* Show on every desktop */
if (*a == atoms[2]) {
xcb_change_property (c, XCB_PROP_MODE_REPLACE, win, atoms[2], XCB_ATOM_CARDINAL, 32, 1,
(const uint32_t []){ 0xffffffff } );
compliance_lvl++;
}
/* Tell the WM that this space is for the bar */
if (*a == atoms[3]) {
/* Prepare the strut array */
if (bar_bottom) {
v[3] = BAR_HEIGHT;
v[11] = bar_width;
strut[3] = BAR_HEIGHT;
strut[11] = bar_width;
} else {
strut[2] = BAR_HEIGHT;
strut[9] = bar_width;
}
else {
v[2] = BAR_HEIGHT;
v[8] = bar_width;
}
xcb_change_property (c, XCB_PROP_MODE_REPLACE, win, atoms[3], XCB_ATOM_CARDINAL, 32, 12, v);
compliance_lvl++;
}
}
free (reply1);
/* If the wm supports at least 2 NET atoms then mark as compliant */
return (compliance_lvl > 1);
xcb_change_property (c, XCB_PROP_MODE_REPLACE, win, atom_list[NET_WM_WINDOW_OPACITY], XCB_ATOM_CARDINAL, 32, 1, (const uint32_t []){ (uint32_t)(BAR_OPACITY * 0xffffffff) } );
xcb_change_property (c, XCB_PROP_MODE_REPLACE, win, 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_APPEND, win, atom_list[NET_WM_STATE], XCB_ATOM_ATOM, 32, 2, &atom_list[NET_WM_STATE_STICKY]);
xcb_change_property (c, XCB_PROP_MODE_REPLACE, win, atom_list[NET_WM_DESKTOP], XCB_ATOM_CARDINAL, 32, 1, (const uint32_t []){ -1 } );
xcb_change_property (c, XCB_PROP_MODE_REPLACE, win, atom_list[NET_WM_STRUT_PARTIAL], XCB_ATOM_CARDINAL, 32, 12, strut);
xcb_change_property (c, XCB_PROP_MODE_REPLACE, win, atom_list[NET_WM_STRUT], XCB_ATOM_CARDINAL, 32, 4, strut);
}
void
@ -340,11 +336,10 @@ init (void)
BAR_HEIGHT, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, scr->root_visual,
XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK, (const uint32_t []){ palette[10], XCB_EVENT_MASK_EXPOSURE });
/* Set EWMH hints */
int ewmh_docking = set_ewmh_atoms (root);
/* For WM that support EWMH atoms */
set_ewmh_atoms();
/* Quirk for wm not supporting the EWMH docking method */
xcb_change_window_attributes (c, win, XCB_CW_OVERRIDE_REDIRECT, (const uint32_t []){ !ewmh_docking });
xcb_change_window_attributes (c, win, XCB_CW_OVERRIDE_REDIRECT, (const uint32_t []){ force_docking });
/* Create a temporary canvas */
canvas = xcb_generate_id (c);
@ -362,8 +357,6 @@ init (void)
/* Make the bar visible */
xcb_map_window (c, win);
/* Send a configure event. Needed to make bar work with Openbox */
xcb_configure_window (c, win, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, (const uint32_t []){ BAR_OFFSET, y });
xcb_flush (c);
}
@ -412,16 +405,18 @@ main (int argc, char **argv)
int permanent = 0;
char ch;
while ((ch = getopt (argc, argv, "phb")) != -1) {
while ((ch = getopt (argc, argv, "phbf")) != -1) {
switch (ch) {
case 'h':
printf ("usage: %s [-p | -h] [-b]\n"
"\t-h Show this help\n"
"\t-b Put bar at the bottom of the screen\n"
"\t-f Force docking (use this if your WM isn't EWMH compliant)\n"
"\t-p Don't close after the data ends\n", argv[0]);
exit (0);
case 'p': permanent = 1; break;
case 'b': bar_bottom = 1; break;
case 'f': force_docking = 1; break;
}
}

View File

@ -14,6 +14,8 @@
#define BAR_FONT "-*-terminus-medium-r-normal-*-12-*-*-*-c-*-*-1","fixed"
/* Some fonts don't set the right width for some chars, pheex it */
#define BAR_FONT_FALLBACK_WIDTH 6
/* Define the opacity of the bar (requires a compositor such as compton) */
#define BAR_OPACITY 1.0 /* 0 is invisible, 1 is opaque */
/* Color palette */
#define BACKGROUND 0x232c31
#define COLOR0 0x2d3c46