[download]

local/src/lemonbar/lemonbar.c

   1 // vim:sw=4:ts=4:et:
   2 #define _POSIX_C_SOURCE 200809L
   3 #include <stdbool.h>
   4 #include <stddef.h>
   5 #include <stdio.h>
   6 #include <stdlib.h>
   7 #include <string.h>
   8 #include <ctype.h>
   9 #include <signal.h>
  10 #include <poll.h>
  11 #include <fcntl.h>
  12 #include <getopt.h>
  13 #include <unistd.h>
  14 #include <errno.h>
  15 #include <xcb/xcb.h>
  16 #include <xcb/xcbext.h>
  17 #if WITH_XINERAMA
  18 #include <xcb/xinerama.h>
  19 #endif
  20 #include <xcb/randr.h>
  21 
  22 #include <X11/Xft/Xft.h>
  23 #include <X11/Xlib-xcb.h>
  24 
  25 // Here bet  dragons
  26 
  27 #define max(a,b) ((a) > (b) ? (a) : (b))
  28 #define min(a,b) ((a) < (b) ? (a) : (b))
  29 #define indexof(c,s) (strchr((s),(c))-(s))
  30 
  31 typedef struct font_t {
  32     xcb_font_t ptr;
  33     xcb_charinfo_t *width_lut;
  34 
  35     XftFont *xft_ft;
  36 
  37     int ascent;
  38 
  39     int descent, height, width;
  40     uint16_t char_max;
  41     uint16_t char_min;
  42 } font_t;
  43 
  44 typedef struct monitor_t {
  45     int x, y, width;
  46     xcb_window_t window;
  47     xcb_pixmap_t pixmap;
  48     struct monitor_t *prev, *next;
  49 } monitor_t;
  50 
  51 typedef struct area_t {
  52     unsigned int begin:16;
  53     unsigned int end:16;
  54     bool active:1;
  55     int align:3;
  56     unsigned int button:3;
  57     xcb_window_t window;
  58     char *cmd;
  59 } area_t;
  60 
  61 typedef union rgba_t {
  62     struct {
  63         uint8_t b;
  64         uint8_t g;
  65         uint8_t r;
  66         uint8_t a;
  67     };
  68     uint32_t v;
  69 } rgba_t;
  70 
  71 typedef struct area_stack_t {
  72     int at, max;
  73     area_t *area;
  74 } area_stack_t;
  75 
  76 enum {
  77     ATTR_OVERL = (1<<0),
  78     ATTR_UNDERL = (1<<1),
  79 };
  80 
  81 enum { ALIGN_L = 0,
  82        ALIGN_C,
  83        ALIGN_R
  84      };
  85 
  86 enum {
  87     GC_DRAW = 0,
  88     GC_CLEAR,
  89     GC_ATTR,
  90     GC_MAX
  91 };
  92 
  93 #define MAX_FONT_COUNT 5
  94 
  95 static Display *dpy;
  96 static xcb_connection_t *c;
  97 
  98 static xcb_screen_t *scr;
  99 static int scr_nbr = 0;
 100 
 101 static xcb_gcontext_t gc[GC_MAX];
 102 static xcb_visualid_t visual;
 103 static Visual *visual_ptr;
 104 static xcb_colormap_t colormap;
 105 
 106 
 107 static monitor_t *monhead, *montail;
 108 static font_t *font_list[MAX_FONT_COUNT];
 109 static int font_count = 0;
 110 static int font_index = -1;
 111 static int offsets_y[MAX_FONT_COUNT];
 112 static int offset_y_count = 0;
 113 static int offset_y_index = 0;
 114 
 115 static uint32_t attrs = 0;
 116 static bool dock = false;
 117 static bool topbar = true;
 118 static int bw = -1, bh = -1, bx = 0, by = 0;
 119 static int bu = 1; // Underline height
 120 static rgba_t fgc, bgc, ugc;
 121 static rgba_t dfgc, dbgc, dugc;
 122 static area_stack_t area_stack;
 123 
 124 static XftColor sel_fg;
 125 static XftDraw *xft_draw;
 126 
 127 //char width lookuptable
 128 #define MAX_WIDTHS (1 << 16)
 129 static wchar_t xft_char[MAX_WIDTHS];
 130 static char    xft_width[MAX_WIDTHS];
 131 
 132 void
 133 update_gc (void)
 134 {
 135     xcb_change_gc(c, gc[GC_DRAW], XCB_GC_FOREGROUND, (const uint32_t []){ fgc.v });
 136     xcb_change_gc(c, gc[GC_CLEAR], XCB_GC_FOREGROUND, (const uint32_t []){ bgc.v });
 137     xcb_change_gc(c, gc[GC_ATTR], XCB_GC_FOREGROUND, (const uint32_t []){ ugc.v });
 138     XftColorFree(dpy, visual_ptr, colormap , &sel_fg);
 139     char color[] = "#ffffff";
 140     uint32_t nfgc = fgc.v & 0x00ffffff;
 141     snprintf(color, sizeof(color), "#%06X", nfgc);
 142     if (!XftColorAllocName (dpy, visual_ptr, colormap, color, &sel_fg)) {
 143         fprintf(stderr, "Couldn't allocate xft font color '%s'\n", color);
 144     }
 145 }
 146 
 147 void
 148 fill_gradient (xcb_drawable_t d, int x, int y, int width, int height, rgba_t start, rgba_t stop)
 149 {
 150     float i;
 151     const int K = 25; // The number of steps
 152 
 153     for (i = 0.; i < 1.; i += (1. / K)) {
 154         // Perform the linear interpolation magic
 155         unsigned int rr = i * stop.r + (1. - i) * start.r;
 156         unsigned int gg = i * stop.g + (1. - i) * start.g;
 157         unsigned int bb = i * stop.b + (1. - i) * start.b;
 158 
 159         // The alpha is ignored here
 160         rgba_t step = {
 161             .r = rr,
 162             .g = gg,
 163             .b = bb,
 164             .a = 255,
 165         };
 166 
 167         xcb_change_gc(c, gc[GC_DRAW], XCB_GC_FOREGROUND, (const uint32_t []){ step.v });
 168         xcb_poly_fill_rectangle(c, d, gc[GC_DRAW], 1,
 169                                (const xcb_rectangle_t []){ { x, i * bh, width, bh / K + 1 } });
 170     }
 171 
 172     xcb_change_gc(c, gc[GC_DRAW], XCB_GC_FOREGROUND, (const uint32_t []){ fgc.v });
 173 }
 174 
 175 void
 176 fill_rect (xcb_drawable_t d, xcb_gcontext_t _gc, int x, int y, int width, int height)
 177 {
 178     xcb_poly_fill_rectangle(c, d, _gc, 1, (const xcb_rectangle_t []){ { x, y, width, height } });
 179 }
 180 
 181 // Apparently xcb cannot seem to compose the right request for this call, hence we have to do it by
 182 // ourselves.
 183 // The funcion is taken from 'wmdia' (http://wmdia.sourceforge.net/)
 184 xcb_void_cookie_t xcb_poly_text_16_simple(xcb_connection_t * c,
 185     xcb_drawable_t drawable, xcb_gcontext_t gc, int16_t x, int16_t y,
 186     uint32_t len, const uint16_t *str)
 187 {
 188     static const xcb_protocol_request_t xcb_req = {
 189         5,                // count
 190         0,                // ext
 191         XCB_POLY_TEXT_16, // opcode
 192         1                 // isvoid
 193     };
 194     struct iovec xcb_parts[7];
 195     uint8_t xcb_lendelta[2];
 196     xcb_void_cookie_t xcb_ret;
 197     xcb_poly_text_8_request_t xcb_out;
 198 
 199     xcb_out.pad0 = 0;
 200     xcb_out.drawable = drawable;
 201     xcb_out.gc = gc;
 202     xcb_out.x = x;
 203     xcb_out.y = y;
 204 
 205     xcb_lendelta[0] = len;
 206     xcb_lendelta[1] = 0;
 207 
 208     xcb_parts[2].iov_base = (char *)&xcb_out;
 209     xcb_parts[2].iov_len = sizeof(xcb_out);
 210     xcb_parts[3].iov_base = 0;
 211     xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;
 212 
 213     xcb_parts[4].iov_base = xcb_lendelta;
 214     xcb_parts[4].iov_len = sizeof(xcb_lendelta);
 215     xcb_parts[5].iov_base = (char *)str;
 216     xcb_parts[5].iov_len = len * sizeof(int16_t);
 217 
 218     xcb_parts[6].iov_base = 0;
 219     xcb_parts[6].iov_len = -(xcb_parts[4].iov_len + xcb_parts[5].iov_len) & 3;
 220 
 221     xcb_ret.sequence = xcb_send_request(c, 0, xcb_parts + 2, &xcb_req);
 222 
 223     return xcb_ret;
 224 }
 225 
 226 
 227 int
 228 xft_char_width_slot (uint16_t ch)
 229 {
 230     int slot = ch % MAX_WIDTHS;
 231     while (xft_char[slot] != 0 && xft_char[slot] != ch)
 232     {
 233         slot = (slot + 1) % MAX_WIDTHS;
 234     }
 235     return slot;
 236 }
 237 
 238 int xft_char_width (uint16_t ch, font_t *cur_font)
 239 {
 240     int slot = xft_char_width_slot(ch);
 241     if (!xft_char[slot]) {
 242         XGlyphInfo gi;
 243         FT_UInt glyph = XftCharIndex (dpy, cur_font->xft_ft, (FcChar32) ch);
 244         XftFontLoadGlyphs (dpy, cur_font->xft_ft, FcFalse, &glyph, 1);
 245         XftGlyphExtents (dpy, cur_font->xft_ft, &glyph, 1, &gi);
 246         XftFontUnloadGlyphs (dpy, cur_font->xft_ft, &glyph, 1);
 247         xft_char[slot] = ch;
 248         if (gi.xOff >= gi.width) {
 249             xft_width[slot] = gi.xOff;
 250         } else {
 251             xft_width[slot] = gi.width;
 252         }
 253         return xft_width[slot];
 254     } else if (xft_char[slot] == ch)
 255         return xft_width[slot];
 256     else
 257         return 0;
 258 }
 259 
 260 int
 261 shift (monitor_t *mon, int x, int align, int ch_width)
 262 {
 263     switch (align) {
 264         case ALIGN_C:
 265             xcb_copy_area(c, mon->pixmap, mon->pixmap, gc[GC_DRAW],
 266                     mon->width / 2 - x / 2, 0,
 267                     mon->width / 2 - (x + ch_width) / 2, 0,
 268                     x, bh);
 269             x = mon->width / 2 - (x + ch_width) / 2 + x;
 270             break;
 271         case ALIGN_R:
 272             xcb_copy_area(c, mon->pixmap, mon->pixmap, gc[GC_DRAW],
 273                     mon->width - x, 0,
 274                     mon->width - x - ch_width, 0,
 275                     x, bh);
 276             x = mon->width - ch_width;
 277             break;
 278     }
 279     
 280         /* Draw the background first */
 281     fill_rect(mon->pixmap, gc[GC_CLEAR], x, 0, ch_width, bh);
 282     return x;
 283 }
 284 
 285 void
 286 draw_lines (monitor_t *mon, int x, int w)
 287 {
 288     /* We can render both at the same time */
 289     if (attrs & ATTR_OVERL)
 290         fill_rect(mon->pixmap, gc[GC_ATTR], x, 0, w, bu);
 291     if (attrs & ATTR_UNDERL)
 292         fill_rect(mon->pixmap, gc[GC_ATTR], x, bh - bu, w, bu);
 293 }
 294 
 295 void
 296 draw_shift (monitor_t *mon, int x, int align, int w)
 297 {
 298     x = shift(mon, x, align, w);
 299     draw_lines(mon, x, w);
 300 }
 301 
 302 int
 303 draw_char (monitor_t *mon, font_t *cur_font, int x, int align, uint16_t ch)
 304 {
 305     int ch_width;
 306 
 307     if (cur_font->xft_ft) {
 308         ch_width = xft_char_width(ch, cur_font);
 309     } else {
 310         ch_width = (cur_font->width_lut) ?
 311             cur_font->width_lut[ch - cur_font->char_min].character_width:
 312             cur_font->width;
 313     }
 314 
 315     x = shift(mon, x, align, ch_width);
 316 
 317     int y = bh / 2 + cur_font->height / 2- cur_font->descent + offsets_y[offset_y_index];
 318     if (cur_font->xft_ft) {
 319         XftDrawString16 (xft_draw, &sel_fg, cur_font->xft_ft, x,y, &ch, 1);
 320     } else {
 321         /* xcb accepts string in UCS-2 BE, so swap */
 322         ch = (ch >> 8) | (ch << 8);
 323         
 324         // The coordinates here are those of the baseline
 325         xcb_poly_text_16_simple(c, mon->pixmap, gc[GC_DRAW],
 326                             x, y,
 327                             1, &ch);
 328     }
 329 
 330     draw_lines(mon, x, ch_width);
 331 
 332     return ch_width;
 333 }
 334 
 335 rgba_t
 336 parse_color (const char *str, char **end, const rgba_t def)
 337 {
 338     int string_len;
 339     char *ep;
 340 
 341     if (!str)
 342         return def;
 343 
 344     // Reset
 345     if (str[0] == '-') {
 346         if (end)
 347             *end = (char *)str + 1;
 348 
 349         return def;
 350     }
 351 
 352     // Hex representation
 353     if (str[0] != '#') {
 354         if (end)
 355             *end = (char *)str;
 356 
 357         fprintf(stderr, "Invalid color specified\n");
 358         return def;
 359     }
 360 
 361     errno = 0;
 362     rgba_t tmp = (rgba_t)(uint32_t)strtoul(str + 1, &ep, 16);
 363 
 364     if (end)
 365         *end = ep;
 366 
 367     // Some error checking is definitely good
 368     if (errno) {
 369         fprintf(stderr, "Invalid color specified\n");
 370         return def;
 371     }
 372 
 373     string_len = ep - (str + 1);
 374 
 375     switch (string_len) {
 376         case 3:
 377             // Expand the #rgb format into #rrggbb (aa is set to 0xff)
 378             tmp.v = (tmp.v & 0xf00) * 0x1100
 379                   | (tmp.v & 0x0f0) * 0x0110
 380                   | (tmp.v & 0x00f) * 0x0011;
 381         case 6:
 382             // If the code is in #rrggbb form then assume it's opaque
 383             tmp.a = 255;
 384             break;
 385         case 7:
 386         case 8:
 387             // Colors in #aarrggbb format, those need no adjustments
 388             break;
 389         default:
 390             fprintf(stderr, "Invalid color specified\n");
 391             return def;
 392     }
 393 
 394     // Premultiply the alpha in
 395     if (tmp.a) {
 396         // The components are clamped automagically as the rgba_t is made of uint8_t
 397         return (rgba_t){
 398             .r = (tmp.r * tmp.a) / 255,
 399             .g = (tmp.g * tmp.a) / 255,
 400             .b = (tmp.b * tmp.a) / 255,
 401             .a = tmp.a,
 402         };
 403     }
 404 
 405     return (rgba_t)0U;
 406 }
 407 
 408 void
 409 set_attribute (const char modifier, const char attribute)
 410 {
 411     int pos = indexof(attribute, "ou");
 412 
 413     if (pos < 0) {
 414         fprintf(stderr, "Invalid attribute \"%c\" found\n", attribute);
 415         return;
 416     }
 417 
 418     switch (modifier) {
 419     case '+':
 420         attrs |= (1u<<pos);
 421         break;
 422     case '-':
 423         attrs &=~(1u<<pos);
 424         break;
 425     case '!':
 426         attrs ^= (1u<<pos);
 427         break;
 428     }
 429 }
 430 
 431 
 432 area_t *
 433 area_get (xcb_window_t win, const int btn, const int x)
 434 {
 435     // Looping backwards ensures that we get the innermost area first
 436     for (int i = area_stack.at - 1; i >= 0; i--) {
 437         area_t *a = &area_stack.area[i];
 438         if (a->window == win && a->button == btn && x >= a->begin && x < a->end)
 439             return a;
 440     }
 441     return NULL;
 442 }
 443 
 444 void
 445 area_shift (xcb_window_t win, const int align, int delta)
 446 {
 447     if (align == ALIGN_L)
 448         return;
 449     if (align == ALIGN_C)
 450         delta /= 2;
 451 
 452     for (int i = 0; i < area_stack.at; i++) {
 453         area_t *a = &area_stack.area[i];
 454         if (a->window == win && a->align == align && !a->active) {
 455             a->begin -= delta;
 456             a->end -= delta;
 457         }
 458     }
 459 }
 460 
 461 bool
 462 area_add (char *str, const char *optend, char **end, monitor_t *mon, const int x, const int align, const int button)
 463 {
 464     int i;
 465     char *trail;
 466     area_t *a;
 467 
 468     // A wild close area tag appeared!
 469     if (*str != ':') {
 470         *end = str;
 471 
 472         // Find most recent unclosed area.
 473         for (i = area_stack.at - 1; i >= 0 && !area_stack.area[i].active; i--)
 474             ;
 475         a = &area_stack.area[i];
 476 
 477         // Basic safety checks
 478         if (!a->cmd || a->align != align || a->window != mon->window) {
 479             fprintf(stderr, "Invalid geometry for the clickable area\n");
 480             return false;
 481         }
 482 
 483         const int size = x - a->begin;
 484 
 485         switch (align) {
 486             case ALIGN_L:
 487                 a->end = x;
 488                 break;
 489             case ALIGN_C:
 490                 a->begin = mon->width / 2 - size / 2 + a->begin / 2;
 491                 a->end = a->begin + size;
 492                 break;
 493             case ALIGN_R:
 494                 // The newest is the rightmost one
 495                 a->begin = mon->width - size;
 496                 a->end = mon->width;
 497                 break;
 498         }
 499 
 500         a->active = false;
 501         return true;
 502     }
 503 
 504     if (area_stack.at + 1 > area_stack.max) {
 505         fprintf(stderr, "Cannot add any more clickable areas (used %d/%d)\n", 
 506                 area_stack.at, area_stack.max);
 507         return false;
 508     }
 509     a = &area_stack.area[area_stack.at++];
 510 
 511     // Found the closing : and check if it's just an escaped one
 512     for (trail = strchr(++str, ':'); trail && trail[-1] == '\\'; trail = strchr(trail + 1, ':'))
 513         ;
 514 
 515     // Find the trailing : and make sure it's within the formatting block, also reject empty commands
 516     if (!trail || str == trail || trail > optend) {
 517         *end = str;
 518         return false;
 519     }
 520 
 521     *trail = '\0';
 522 
 523     // Sanitize the user command by unescaping all the :
 524     for (char *needle = str; *needle; needle++) {
 525         int delta = trail - &needle[1];
 526         if (needle[0] == '\\' && needle[1] == ':') {
 527             memmove(&needle[0], &needle[1], delta);
 528             needle[delta] = 0;
 529         }
 530     }
 531 
 532     // This is a pointer to the string buffer allocated in the main
 533     a->cmd = str;
 534     a->active = true;
 535     a->align = align;
 536     a->begin = x;
 537     a->window = mon->window;
 538     a->button = button;
 539 
 540     *end = trail + 1;
 541 
 542     return true;
 543 }
 544 
 545 bool
 546 font_has_glyph (font_t *font, const uint16_t c)
 547 {
 548     if (font->xft_ft) {
 549         if (XftCharExists(dpy, font->xft_ft, (FcChar32) c)) {
 550             return true;
 551         } else {
 552             return false;
 553         }
 554 
 555     }
 556 
 557     if (c < font->char_min || c > font->char_max)
 558         return false;
 559 
 560     if (font->width_lut && font->width_lut[c - font->char_min].character_width == 0)
 561         return false;
 562 
 563     return true;
 564 }
 565 
 566 font_t *
 567 select_drawable_font (const uint16_t c)
 568 {
 569     // If the user has specified a font to use, try that first.
 570     if (font_index != -1 && font_has_glyph(font_list[font_index - 1], c)) {
 571         offset_y_index = font_index - 1;
 572         return font_list[font_index - 1];
 573     }
 574 
 575     // If the end is reached without finding an appropriate font, return NULL.
 576     // If the font can draw the character, return it.
 577     for (int i = 0; i < font_count; i++) {
 578         if (font_has_glyph(font_list[i], c)) {
 579             offset_y_index = i;
 580             return font_list[i];
 581         }
 582     }
 583     return NULL;
 584 }
 585 
 586 
 587 void
 588 parse (char *text)
 589 {
 590     font_t *cur_font;
 591     monitor_t *cur_mon;
 592     int pos_x, align, button;
 593     char *p = text, *block_end, *ep;
 594     rgba_t tmp;
 595 
 596     pos_x = 0;
 597     align = ALIGN_L;
 598     cur_mon = monhead;
 599 
 600     // Reset the stack position
 601     area_stack.at = 0;
 602 
 603     for (monitor_t *m = monhead; m != NULL; m = m->next)
 604         fill_rect(m->pixmap, gc[GC_CLEAR], 0, 0, m->width, bh);
 605 
 606     /* Create xft drawable */
 607     if (!(xft_draw = XftDrawCreate (dpy, cur_mon->pixmap, visual_ptr , colormap))) {
 608         fprintf(stderr, "Couldn't create xft drawable\n");
 609     }
 610 
 611     for (;;) {
 612         if (*p == '\0' || *p == '\n')
 613 			break;
 614 
 615         if (p[0] == '%' && p[1] == '{' && (block_end = strchr(p++, '}'))) {
 616             p++;
 617             while (p < block_end) {
 618                 int w;
 619                 while (isspace(*p))
 620                     p++;
 621 
 622                 switch (*p++) {
 623                     case '+': set_attribute('+', *p++); break;
 624                     case '-': set_attribute('-', *p++); break;
 625                     case '!': set_attribute('!', *p++); break;
 626 
 627                     case 'R':
 628                               tmp = fgc;
 629                               fgc = bgc;
 630                               bgc = tmp;
 631                               update_gc();
 632                               break;
 633 
 634                     case 'l': pos_x = 0; align = ALIGN_L; break;
 635                     case 'c': pos_x = 0; align = ALIGN_C; break;
 636                     case 'r': pos_x = 0; align = ALIGN_R; break;
 637 
 638                     case 'A':
 639                               button = XCB_BUTTON_INDEX_1;
 640                               // The range is 1-5
 641                               if (isdigit(*p) && (*p > '0' && *p < '6'))
 642                                   button = *p++ - '0';
 643                               if (!area_add(p, block_end, &p, cur_mon, pos_x, align, button))
 644                                   return;
 645                               break;
 646 
 647                     case 'B': bgc = parse_color(p, &p, dbgc); update_gc(); break;
 648                     case 'F': fgc = parse_color(p, &p, dfgc); update_gc(); break;
 649                     case 'U': ugc = parse_color(p, &p, dugc); update_gc(); break;
 650 
 651                     case 'S':
 652                               if (*p == '+' && cur_mon->next)
 653                               { cur_mon = cur_mon->next; }
 654                               else if (*p == '-' && cur_mon->prev)
 655                               { cur_mon = cur_mon->prev; }
 656                               else if (*p == 'f')
 657                               { cur_mon = monhead; }
 658                               else if (*p == 'l')
 659                               { cur_mon = montail ? montail : monhead; }
 660                               else if (isdigit(*p))
 661                               { cur_mon = monhead;
 662                                 for (int i = 0; i != *p-'0' && cur_mon->next; i++)
 663                                     cur_mon = cur_mon->next;
 664                               }
 665                               else
 666                               { p++; continue; }
 667 					          XftDrawDestroy (xft_draw);
 668 					          if (!(xft_draw = XftDrawCreate (dpy, cur_mon->pixmap, visual_ptr , colormap ))) {
 669 						        fprintf(stderr, "Couldn't create xft drawable\n");
 670 					          }
 671 
 672                               p++;
 673                               pos_x = 0;
 674                               break;
 675                     case 'O':
 676                               errno = 0;
 677                               w = (int) strtoul(p, &p, 10);
 678                               if (errno)
 679                                   continue;
 680 
 681                               draw_shift(cur_mon, pos_x, align, w);
 682 
 683                               pos_x += w;
 684                               area_shift(cur_mon->window, align, w);
 685                               break;
 686 
 687                     case 'T':
 688                               if (*p == '-') { //Reset to automatic font selection
 689                                   font_index = -1;
 690                                   p++;
 691                                   break;
 692                               } else if (isdigit(*p)) {
 693                                   font_index = (int)strtoul(p, &ep, 10);
 694                                   // User-specified 'font_index' ∊ (0,font_count]
 695                                   // Otherwise just fallback to the automatic font selection
 696                                   if (!font_index || font_index > font_count)
 697                                   font_index = -1;
 698                                   p = ep;
 699                                   break;
 700                               } else {
 701                                   fprintf(stderr, "Invalid font slot \"%c\"\n", *p++); //Swallow the token
 702                                   break;
 703                               }
 704 
 705                     // In case of error keep parsing after the closing }
 706                     default:
 707                         p = block_end;
 708                 }
 709             }
 710             // Eat the trailing }
 711             p++;
 712         } else { // utf-8 -> ucs-2
 713             // Escaped % symbol, eat the first one
 714             if (p[0] == '%' && p[1] == '%')
 715                 p++;
 716 
 717             uint8_t *utf = (uint8_t *)p;
 718             uint16_t ucs;
 719 
 720             // ASCII
 721             if (utf[0] < 0x80) {
 722                 ucs = utf[0];
 723                 p  += 1;
 724             }
 725             // Two byte utf8 sequence
 726             else if ((utf[0] & 0xe0) == 0xc0) {
 727                 ucs = (utf[0] & 0x1f) << 6 | (utf[1] & 0x3f);
 728                 p += 2;
 729             }
 730             // Three byte utf8 sequence
 731             else if ((utf[0] & 0xf0) == 0xe0) {
 732                 ucs = (utf[0] & 0xf) << 12 | (utf[1] & 0x3f) << 6 | (utf[2] & 0x3f);
 733                 p += 3;
 734             }
 735             // Four byte utf8 sequence
 736             else if ((utf[0] & 0xf8) == 0xf0) {
 737                 ucs = 0xfffd;
 738                 p += 4;
 739             }
 740             // Five byte utf8 sequence
 741             else if ((utf[0] & 0xfc) == 0xf8) {
 742                 ucs = 0xfffd;
 743                 p += 5;
 744             }
 745             // Six byte utf8 sequence
 746             else if ((utf[0] & 0xfe) == 0xfc) {
 747                 ucs = 0xfffd;
 748                 p += 6;
 749             }
 750             // Not a valid utf-8 sequence
 751             else {
 752                 ucs = utf[0];
 753                 p += 1;
 754             }
 755 
 756             cur_font = select_drawable_font(ucs);
 757             if (!cur_font)
 758                 continue;
 759 
 760             if(cur_font->ptr)
 761                 xcb_change_gc(c, gc[GC_DRAW] , XCB_GC_FONT, (const uint32_t []) {
 762                 cur_font->ptr
 763             });
 764             int w = draw_char(cur_mon, cur_font, pos_x, align, ucs);
 765 
 766             pos_x += w;
 767             area_shift(cur_mon->window, align, w);
 768         }
 769     }
 770     XftDrawDestroy (xft_draw);
 771 }
 772 
 773 void
 774 font_load (const char *pattern)
 775 {
 776     if (font_count >= MAX_FONT_COUNT) {
 777         fprintf(stderr, "Max font count reached. Could not load font \"%s\"\n", pattern);
 778         return;
 779     }
 780 
 781     xcb_query_font_cookie_t queryreq;
 782     xcb_query_font_reply_t *font_info;
 783     xcb_void_cookie_t cookie;
 784     xcb_font_t font;
 785 
 786     font = xcb_generate_id(c);
 787 
 788     font_t *ret = calloc(1, sizeof(font_t));
 789 
 790     if (!ret)
 791         return;
 792 
 793     cookie = xcb_open_font_checked(c, font, strlen(pattern), pattern);
 794     if (!xcb_request_check (c, cookie)) {
 795         queryreq = xcb_query_font(c, font);
 796         font_info = xcb_query_font_reply(c, queryreq, NULL);
 797 
 798         ret->xft_ft = NULL;
 799         ret->ptr = font;
 800         ret->descent = font_info->font_descent;
 801         ret->height = font_info->font_ascent + font_info->font_descent;
 802         ret->width = font_info->max_bounds.character_width;
 803         ret->char_max = font_info->max_byte1 << 8 | font_info->max_char_or_byte2;
 804         ret->char_min = font_info->min_byte1 << 8 | font_info->min_char_or_byte2;
 805         // Copy over the width lut as it's part of font_info
 806         int lut_size = sizeof(xcb_charinfo_t) * xcb_query_font_char_infos_length(font_info);
 807         if (lut_size) {
 808             ret->width_lut = malloc(lut_size);
 809             memcpy(ret->width_lut, xcb_query_font_char_infos(font_info), lut_size);
 810         }
 811         free(font_info);
 812     } else if ((ret->xft_ft = XftFontOpenName (dpy, scr_nbr, pattern))) {
 813         ret->ptr = 0;
 814         ret->ascent = ret->xft_ft->ascent;
 815         ret->descent = ret->xft_ft->descent;
 816         ret->height = ret->ascent + ret->descent;
 817     } else {
 818         fprintf(stderr, "Could not load font %s\n", pattern);
 819         free(ret);
 820         return;
 821     }
 822 
 823     font_list[font_count++] = ret;
 824 }
 825 
 826 void add_y_offset(int offset) {
 827     if (offset_y_count >= MAX_FONT_COUNT) {
 828         fprintf(stderr, "Max offset count reached. Could not set offset \"%d\"\n", offset);
 829         return;
 830     }
 831 
 832     offsets_y[offset_y_count] = strtol(optarg, NULL, 10);
 833     if (offset_y_count == 0) {
 834         for (int i = 1; i < MAX_FONT_COUNT; ++i) {
 835             offsets_y[i] = offsets_y[0];
 836         }
 837     }
 838     ++offset_y_count;
 839 }
 840 
 841 
 842 enum {
 843     NET_WM_WINDOW_TYPE,
 844     NET_WM_WINDOW_TYPE_DOCK,
 845     NET_WM_DESKTOP,
 846     NET_WM_STRUT_PARTIAL,
 847     NET_WM_STRUT,
 848     NET_WM_STATE,
 849     NET_WM_STATE_STICKY,
 850     NET_WM_STATE_ABOVE,
 851 };
 852 
 853 void
 854 set_ewmh_atoms (void)
 855 {
 856     const char *atom_names[] = {
 857         "_NET_WM_WINDOW_TYPE",
 858         "_NET_WM_WINDOW_TYPE_DOCK",
 859         "_NET_WM_DESKTOP",
 860         "_NET_WM_STRUT_PARTIAL",
 861         "_NET_WM_STRUT",
 862         "_NET_WM_STATE",
 863         // Leave those at the end since are batch-set
 864         "_NET_WM_STATE_STICKY",
 865         "_NET_WM_STATE_ABOVE",
 866     };
 867     const int atoms = sizeof(atom_names)/sizeof(char *);
 868     xcb_intern_atom_cookie_t atom_cookie[atoms];
 869     xcb_atom_t atom_list[atoms];
 870     xcb_intern_atom_reply_t *atom_reply;
 871 
 872     // As suggested fetch all the cookies first (yum!) and then retrieve the
 873     // atoms to exploit the async'ness
 874     for (int i = 0; i < atoms; i++)
 875         atom_cookie[i] = xcb_intern_atom(c, 0, strlen(atom_names[i]), atom_names[i]);
 876 
 877     for (int i = 0; i < atoms; i++) {
 878         atom_reply = xcb_intern_atom_reply(c, atom_cookie[i], NULL);
 879         if (!atom_reply)
 880             return;
 881         atom_list[i] = atom_reply->atom;
 882         free(atom_reply);
 883     }
 884 
 885     // Prepare the strut array
 886     for (monitor_t *mon = monhead; mon; mon = mon->next) {
 887         int strut[12] = {0};
 888         if (topbar) {
 889             strut[2] = bh;
 890             strut[8] = mon->x;
 891             strut[9] = mon->x + mon->width - 1;
 892         } else {
 893             strut[3]  = bh;
 894             strut[10] = mon->x;
 895             strut[11] = mon->x + mon->width - 1;
 896         }
 897 
 898         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]);
 899         xcb_change_property(c, XCB_PROP_MODE_APPEND,  mon->window, atom_list[NET_WM_STATE], XCB_ATOM_ATOM, 32, 2, &atom_list[NET_WM_STATE_STICKY]);
 900         xcb_change_property(c, XCB_PROP_MODE_REPLACE, mon->window, atom_list[NET_WM_DESKTOP], XCB_ATOM_CARDINAL, 32, 1, (const uint32_t []) {
 901             0u - 1u
 902         } );
 903         xcb_change_property(c, XCB_PROP_MODE_REPLACE, mon->window, atom_list[NET_WM_STRUT_PARTIAL], XCB_ATOM_CARDINAL, 32, 12, strut);
 904         xcb_change_property(c, XCB_PROP_MODE_REPLACE, mon->window, atom_list[NET_WM_STRUT], XCB_ATOM_CARDINAL, 32, 4, strut);
 905         xcb_change_property(c, XCB_PROP_MODE_REPLACE, mon->window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, 3, "bar");
 906         xcb_change_property(c, XCB_PROP_MODE_REPLACE, mon->window, XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8, 12, "lemonbar\0Bar");
 907     }
 908 }
 909 
 910 monitor_t *
 911 monitor_new (int x, int y, int width, int height)
 912 {
 913     monitor_t *ret;
 914 
 915     ret = calloc(1, sizeof(monitor_t));
 916     if (!ret) {
 917         fprintf(stderr, "Failed to allocate new monitor\n");
 918         exit(EXIT_FAILURE);
 919     }
 920 
 921     ret->x = x;
 922     ret->y = (topbar ? by : height - bh - by) + y;
 923     ret->width = width;
 924     ret->next = ret->prev = NULL;
 925     ret->window = xcb_generate_id(c);
 926     int depth = (visual == scr->root_visual) ? XCB_COPY_FROM_PARENT : 32;
 927     xcb_create_window(c, depth, ret->window, scr->root,
 928                       ret->x, ret->y, width, bh, 0,
 929                       XCB_WINDOW_CLASS_INPUT_OUTPUT, visual,
 930                       XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP,
 931     (const uint32_t []) {
 932         bgc.v, bgc.v, dock, XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS, colormap
 933     });
 934 
 935     ret->pixmap = xcb_generate_id(c);
 936     xcb_create_pixmap(c, depth, ret->pixmap, ret->window, width, bh);
 937 
 938     return ret;
 939 }
 940 
 941 void
 942 monitor_add (monitor_t *mon)
 943 {
 944     if (!monhead) {
 945         monhead = mon;
 946     } else if (!montail) {
 947         montail = mon;
 948         monhead->next = mon;
 949         mon->prev = monhead;
 950     } else {
 951         mon->prev = montail;
 952         montail->next = mon;
 953         montail = montail->next;
 954     }
 955 }
 956 
 957 int
 958 rect_sort_cb (const void *p1, const void *p2)
 959 {
 960     const xcb_rectangle_t *r1 = (xcb_rectangle_t *)p1;
 961     const xcb_rectangle_t *r2 = (xcb_rectangle_t *)p2;
 962 
 963     if (r1->x < r2->x || r1->y + r1->height <= r2->y)
 964     {
 965         return -1;
 966     }
 967 
 968     if (r1->x > r2->x || r1->y + r1->height > r2->y)
 969     {
 970         return 1;
 971     }
 972 
 973     return 0;
 974 }
 975 
 976 void
 977 monitor_create_chain (xcb_rectangle_t *rects, const int num)
 978 {
 979     int i;
 980     int width = 0, height = 0;
 981     int left = bx;
 982 
 983     // Sort before use
 984     qsort(rects, num, sizeof(xcb_rectangle_t), rect_sort_cb);
 985 
 986     for (i = 0; i < num; i++) {
 987         int h = rects[i].y + rects[i].height;
 988         // Accumulated width of all monitors
 989         width += rects[i].width;
 990         // Get height of screen from y_offset + height of lowest monitor
 991         if (h >= height)
 992             height = h;
 993     }
 994 
 995     if (bw < 0)
 996         bw = width - bx;
 997 
 998     // Use the first font height as all the font heights have been set to the biggest of the set
 999     if (bh < 0 || bh > height)
1000         bh = font_list[0]->height + bu + 2;
1001 
1002     // Check the geometry
1003     if (bx + bw > width || by + bh > height) {
1004         fprintf(stderr, "The geometry specified doesn't fit the screen!\n");
1005         exit(EXIT_FAILURE);
1006     }
1007 
1008     // Left is a positive number or zero therefore monitors with zero width are excluded
1009     width = bw;
1010     for (i = 0; i < num; i++) {
1011         if (rects[i].y + rects[i].height < by)
1012             continue;
1013         if (rects[i].width > left) {
1014             monitor_t *mon = monitor_new(
1015                                  rects[i].x + left,
1016                                  rects[i].y,
1017                                  min(width, rects[i].width - left),
1018                                  rects[i].height);
1019 
1020             if (!mon)
1021                 break;
1022 
1023             monitor_add(mon);
1024 
1025             width -= rects[i].width - left;
1026             // No need to check for other monitors
1027             if (width <= 0)
1028                 break;
1029         }
1030 
1031         left -= rects[i].width;
1032 
1033         if (left < 0)
1034             left = 0;
1035     }
1036 }
1037 
1038 void
1039 get_randr_monitors (void)
1040 {
1041     xcb_randr_get_screen_resources_current_reply_t *rres_reply;
1042     xcb_randr_output_t *outputs;
1043     int i, j, num, valid = 0;
1044 
1045     rres_reply = xcb_randr_get_screen_resources_current_reply(c,
1046                  xcb_randr_get_screen_resources_current(c, scr->root), NULL);
1047 
1048     if (!rres_reply) {
1049         fprintf(stderr, "Failed to get current randr screen resources\n");
1050         return;
1051     }
1052 
1053     num = xcb_randr_get_screen_resources_current_outputs_length(rres_reply);
1054     outputs = xcb_randr_get_screen_resources_current_outputs(rres_reply);
1055 
1056 
1057     // There should be at least one output
1058     if (num < 1) {
1059         free(rres_reply);
1060         return;
1061     }
1062 
1063     xcb_rectangle_t rects[num];
1064 
1065     // Get all outputs
1066     for (i = 0; i < num; i++) {
1067         xcb_randr_get_output_info_reply_t *oi_reply;
1068         xcb_randr_get_crtc_info_reply_t *ci_reply;
1069 
1070         oi_reply = xcb_randr_get_output_info_reply(c, xcb_randr_get_output_info(c, outputs[i], XCB_CURRENT_TIME), NULL);
1071 
1072         // Output disconnected or not attached to any CRTC ?
1073         if (!oi_reply || oi_reply->crtc == XCB_NONE || oi_reply->connection != XCB_RANDR_CONNECTION_CONNECTED) {
1074             free(oi_reply);
1075             rects[i].width = 0;
1076             continue;
1077         }
1078 
1079         ci_reply = xcb_randr_get_crtc_info_reply(c,
1080                    xcb_randr_get_crtc_info(c, oi_reply->crtc, XCB_CURRENT_TIME), NULL);
1081 
1082         free(oi_reply);
1083 
1084         if (!ci_reply) {
1085             fprintf(stderr, "Failed to get RandR ctrc info\n");
1086             free(rres_reply);
1087             return;
1088         }
1089 
1090         // There's no need to handle rotated screens here (see #69)
1091         rects[i] = (xcb_rectangle_t){ ci_reply->x, ci_reply->y, ci_reply->width, ci_reply->height };
1092 
1093         free(ci_reply);
1094 
1095         valid++;
1096     }
1097 
1098     free(rres_reply);
1099 
1100     // Check for clones and inactive outputs
1101     for (i = 0; i < num; i++) {
1102         if (rects[i].width == 0)
1103             continue;
1104 
1105         for (j = 0; j < num; j++) {
1106             // Does I contain J ?
1107 
1108             if (i != j && rects[j].width) {
1109                 if (rects[j].x >= rects[i].x && rects[j].x + rects[j].width <= rects[i].x + rects[i].width &&
1110                         rects[j].y >= rects[i].y && rects[j].y + rects[j].height <= rects[i].y + rects[i].height) {
1111                     rects[j].width = 0;
1112                     valid--;
1113                 }
1114             }
1115         }
1116     }
1117 
1118     if (valid < 1) {
1119         fprintf(stderr, "No usable RandR output found\n");
1120         return;
1121     }
1122 
1123     xcb_rectangle_t r[valid];
1124 
1125     for (i = j = 0; i < num && j < valid; i++)
1126         if (rects[i].width != 0)
1127             r[j++] = rects[i];
1128 
1129     monitor_create_chain(r, valid);
1130 }
1131 
1132 #ifdef WITH_XINERAMA
1133 void
1134 get_xinerama_monitors (void)
1135 {
1136     xcb_xinerama_query_screens_reply_t *xqs_reply;
1137     xcb_xinerama_screen_info_iterator_t iter;
1138     int screens;
1139 
1140     xqs_reply = xcb_xinerama_query_screens_reply(c,
1141                 xcb_xinerama_query_screens_unchecked(c), NULL);
1142 
1143     iter = xcb_xinerama_query_screens_screen_info_iterator(xqs_reply);
1144     screens = iter.rem;
1145 
1146     xcb_rectangle_t rects[screens];
1147 
1148     // Fetch all the screens first
1149     for (int i = 0; iter.rem; i++) {
1150         rects[i].x = iter.data->x_org;
1151         rects[i].y = iter.data->y_org;
1152         rects[i].width = iter.data->width;
1153         rects[i].height = iter.data->height;
1154         xcb_xinerama_screen_info_next(&iter);
1155     }
1156 
1157     free(xqs_reply);
1158 
1159     monitor_create_chain(rects, screens);
1160 }
1161 #endif
1162 
1163 xcb_visualid_t
1164 get_visual (void)
1165 {
1166 
1167     XVisualInfo xv; 
1168     xv.depth = 32;
1169     int result = 0;
1170     XVisualInfo* result_ptr = NULL; 
1171     result_ptr = XGetVisualInfo(dpy, VisualDepthMask, &xv, &result);
1172 
1173     if (result > 0) {
1174         visual_ptr = result_ptr->visual;
1175         return result_ptr->visualid;
1176     }
1177     
1178     //Fallback
1179     visual_ptr = DefaultVisual(dpy, scr_nbr);	
1180 	return scr->root_visual;
1181 }
1182 
1183 // Parse an X-styled geometry string, we don't support signed offsets though.
1184 bool
1185 parse_geometry_string (char *str, int *tmp)
1186 {
1187     char *p = str;
1188     int i = 0, j;
1189 
1190     if (!str || !str[0])
1191         return false;
1192 
1193     // The leading = is optional
1194     if (*p == '=')
1195         p++;
1196 
1197     while (*p) {
1198         // A geometry string has only 4 fields
1199         if (i >= 4) {
1200             fprintf(stderr, "Invalid geometry specified\n");
1201             return false;
1202         }
1203         // Move on if we encounter a 'x' or '+'
1204         if (*p == 'x') {
1205             if (i > 0) // The 'x' must precede '+'
1206                 break;
1207             i++; p++; continue;
1208         }
1209         if (*p == '+') {
1210             if (i < 1) // Stray '+', skip the first two fields
1211                 i = 2;
1212             else
1213                 i++;
1214             p++; continue;
1215         }
1216         // A digit must follow
1217         if (!isdigit(*p)) {
1218             fprintf(stderr, "Invalid geometry specified\n");
1219             return false;
1220         }
1221         // Try to parse the number
1222         errno = 0;
1223         j = strtoul(p, &p, 10);
1224         if (errno) {
1225             fprintf(stderr, "Invalid geometry specified\n");
1226             return false;
1227         }
1228         tmp[i] = j;
1229     }
1230 
1231     return true;
1232 }
1233 
1234 void
1235 xconn (void)
1236 {
1237     if ((dpy = XOpenDisplay(0)) == NULL) {
1238         fprintf (stderr, "Couldnt open display\n");
1239     }
1240 
1241     if ((c = XGetXCBConnection(dpy)) == NULL) {
1242         fprintf (stderr, "Couldnt connect to X\n");
1243         exit (EXIT_FAILURE);
1244     }
1245 
1246 	XSetEventQueueOwner(dpy, XCBOwnsEventQueue);
1247 
1248     if (xcb_connection_has_error(c)) {
1249         fprintf(stderr, "Couldn't connect to X\n");
1250         exit(EXIT_FAILURE);
1251     }
1252 
1253     /* Grab infos from the first screen */
1254     scr = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
1255 
1256     /* Try to get a RGBA visual and build the colormap for that */
1257 	visual = get_visual();
1258     colormap = xcb_generate_id(c);
1259     xcb_create_colormap(c, XCB_COLORMAP_ALLOC_NONE, colormap, scr->root, visual);
1260 }
1261 
1262 void
1263 init (char *wm_name, char *wm_instance)
1264 {
1265     // Try to load a default font
1266     if (!font_count)
1267         font_load("fixed");
1268 
1269     // We tried and failed hard, there's something wrong
1270     if (!font_count)
1271         exit(EXIT_FAILURE);
1272 
1273     // To make the alignment uniform, find maximum height
1274     int maxh = font_list[0]->height;
1275     for (int i = 1; i < font_count; i++)
1276         maxh = max(maxh, font_list[i]->height);
1277 
1278     // Set maximum height to all fonts
1279     for (int i = 0; i < font_count; i++)
1280         font_list[i]->height = maxh;
1281 
1282     // Generate a list of screens
1283     const xcb_query_extension_reply_t *qe_reply;
1284 
1285     // Initialize monitor list head and tail
1286     monhead = montail = NULL;
1287 
1288     // Check if RandR is present
1289     qe_reply = xcb_get_extension_data(c, &xcb_randr_id);
1290 
1291     if (qe_reply && qe_reply->present) {
1292         get_randr_monitors();
1293     }
1294 #if WITH_XINERAMA
1295     else {
1296         qe_reply = xcb_get_extension_data(c, &xcb_xinerama_id);
1297 
1298         // Check if Xinerama extension is present and active
1299         if (qe_reply && qe_reply->present) {
1300             xcb_xinerama_is_active_reply_t *xia_reply;
1301             xia_reply = xcb_xinerama_is_active_reply(c, xcb_xinerama_is_active(c), NULL);
1302 
1303             if (xia_reply && xia_reply->state)
1304                 get_xinerama_monitors();
1305 
1306             free(xia_reply);
1307         }
1308     }
1309 #endif
1310 
1311     if (!monhead) {
1312         // If I fits I sits
1313         if (bw < 0)
1314             bw = scr->width_in_pixels - bx;
1315 
1316         // Adjust the height
1317         if (bh < 0 || bh > scr->height_in_pixels)
1318             bh = maxh + bu + 2;
1319 
1320         // Check the geometry
1321         if (bx + bw > scr->width_in_pixels || by + bh > scr->height_in_pixels) {
1322             fprintf(stderr, "The geometry specified doesn't fit the screen!\n");
1323             exit(EXIT_FAILURE);
1324         }
1325 
1326         // If no RandR outputs or Xinerama screens, fall back to using whole screen
1327         monhead = monitor_new(0, 0, bw, scr->height_in_pixels);
1328     }
1329 
1330     if (!monhead)
1331         exit(EXIT_FAILURE);
1332 
1333     // For WM that support EWMH atoms
1334     set_ewmh_atoms();
1335 
1336     // Create the gc for drawing
1337     gc[GC_DRAW] = xcb_generate_id(c);
1338     xcb_create_gc(c, gc[GC_DRAW], monhead->pixmap, XCB_GC_FOREGROUND, (const uint32_t []){ fgc.v });
1339 
1340     gc[GC_CLEAR] = xcb_generate_id(c);
1341     xcb_create_gc(c, gc[GC_CLEAR], monhead->pixmap, XCB_GC_FOREGROUND, (const uint32_t []){ bgc.v });
1342 
1343     gc[GC_ATTR] = xcb_generate_id(c);
1344     xcb_create_gc(c, gc[GC_ATTR], monhead->pixmap, XCB_GC_FOREGROUND, (const uint32_t []){ ugc.v });
1345 
1346     // Make the bar visible and clear the pixmap
1347     for (monitor_t *mon = monhead; mon; mon = mon->next) {
1348         fill_rect(mon->pixmap, gc[GC_CLEAR], 0, 0, mon->width, bh);
1349         xcb_map_window(c, mon->window);
1350 
1351         // Make sure that the window really gets in the place it's supposed to be
1352         // Some WM such as Openbox need this
1353         xcb_configure_window(c, mon->window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, (const uint32_t []){ mon->x, mon->y });
1354 
1355         // Set the WM_NAME atom to the user specified value
1356         if (wm_name)
1357             xcb_change_property(c, XCB_PROP_MODE_REPLACE, mon->window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8 ,strlen(wm_name), wm_name);
1358 
1359         // set the WM_CLASS atom instance to the executable name
1360         if (wm_instance) {
1361             char *wm_class;
1362             int wm_class_offset, wm_class_len;
1363 
1364             // WM_CLASS is nullbyte seperated: wm_instance + "\0Bar\0"
1365             wm_class_offset = strlen(wm_instance) + 1;
1366             wm_class_len = wm_class_offset + 4;
1367 
1368             wm_class = calloc(1, wm_class_len + 1);
1369             strcpy(wm_class, wm_instance);
1370             strcpy(wm_class+wm_class_offset, "Bar");
1371 
1372             xcb_change_property(c, XCB_PROP_MODE_REPLACE, mon->window, XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8, wm_class_len, wm_class);
1373 
1374             free(wm_class);
1375         }
1376     }
1377 
1378     char color[] = "#ffffff";
1379     uint32_t nfgc = fgc.v & 0x00ffffff;
1380     snprintf(color, sizeof(color), "#%06X", nfgc);
1381 
1382     if (!XftColorAllocName (dpy, visual_ptr, colormap, color, &sel_fg)) {
1383         fprintf(stderr, "Couldn't allocate xft font color '%s'\n", color);
1384     }
1385     xcb_flush(c);
1386 }
1387 
1388 void
1389 cleanup (void)
1390 {
1391     free(area_stack.area);
1392     for (int i = 0; font_list[i]; i++) {
1393         if (font_list[i]->xft_ft) {
1394             XftFontClose (dpy, font_list[i]->xft_ft);
1395         }
1396         else {
1397             xcb_close_font(c, font_list[i]->ptr);
1398             free(font_list[i]->width_lut);
1399         }
1400         free(font_list[i]);
1401     }
1402 
1403     while (monhead) {
1404         monitor_t *next = monhead->next;
1405         xcb_destroy_window(c, monhead->window);
1406         xcb_free_pixmap(c, monhead->pixmap);
1407         free(monhead);
1408         monhead = next;
1409     }
1410 
1411     XftColorFree(dpy, visual_ptr, colormap, &sel_fg);
1412 
1413     if (gc[GC_DRAW])
1414         xcb_free_gc(c, gc[GC_DRAW]);
1415     if (gc[GC_CLEAR])
1416         xcb_free_gc(c, gc[GC_CLEAR]);
1417     if (gc[GC_ATTR])
1418         xcb_free_gc(c, gc[GC_ATTR]);
1419     if (c)
1420         xcb_disconnect(c);
1421 }
1422 
1423 char*
1424 strip_path(char *path)
1425 {
1426     char *slash;
1427 
1428     if (path == NULL || *path == '\0')
1429         return strdup("lemonbar");
1430 
1431     slash = strrchr(path, '/');
1432     if (slash != NULL)
1433         return strndup(slash + 1, 31);
1434 
1435     return strndup(path, 31);
1436 }
1437 
1438 void
1439 sighandle (int signal)
1440 {
1441     if (signal == SIGINT || signal == SIGTERM)
1442         exit(EXIT_SUCCESS);
1443 }
1444 
1445 
1446 int
1447 main (int argc, char **argv)
1448 {
1449     struct pollfd pollin[2] = {
1450         { .fd = STDIN_FILENO, .events = POLLIN },
1451         { .fd = -1          , .events = POLLIN },
1452     };
1453     xcb_generic_event_t *ev;
1454     xcb_expose_event_t *expose_ev;
1455     xcb_button_press_event_t *press_ev;
1456     char input[4096] = {0, };
1457     bool permanent = false;
1458     int geom_v[4] = { -1, -1, 0, 0 };
1459     int ch, areas;
1460     char *wm_name;
1461     char *instance_name;
1462 
1463     // Install the parachute!
1464     atexit(cleanup);
1465     signal(SIGINT, sighandle);
1466     signal(SIGTERM, sighandle);
1467 
1468     // B/W combo
1469     dbgc = bgc = (rgba_t)0x00000000U;
1470     dfgc = fgc = (rgba_t)0xffffffffU;
1471 
1472     dugc = ugc = fgc;
1473 
1474     // A safe default
1475     areas = 10;
1476     wm_name = NULL;
1477 
1478     instance_name = strip_path(argv[0]);
1479 
1480     // Connect to the Xserver and initialize scr
1481     xconn();
1482 
1483     while ((ch = getopt(argc, argv, "hg:bdf:a:pu:B:F:U:n:o:")) != -1) {
1484         switch (ch) {
1485             case 'h':
1486                 printf ("lemonbar version %s patched with XFT support\n", VERSION);
1487                 printf ("usage: %s [-h | -g | -b | -d | -f | -a | -p | -n | -u | -B | -F]\n"
1488                         "\t-h Show this help\n"
1489                         "\t-g Set the bar geometry {width}x{height}+{xoffset}+{yoffset}\n"
1490                         "\t-b Put the bar at the bottom of the screen\n"
1491                         "\t-d Force docking (use this if your WM isn't EWMH compliant)\n"
1492                         "\t-f Set the font name to use\n"
1493                         "\t-a Number of clickable areas available (default is 10)\n"
1494                         "\t-p Don't close after the data ends\n"
1495                         "\t-n Set the WM_NAME atom to the specified value for this bar\n"
1496                         "\t-u Set the underline/overline height in pixels\n"
1497                         "\t-B Set background color in #AARRGGBB\n"
1498                         "\t-F Set foreground color in #AARRGGBB\n"
1499                         "\t-o Add a vertical offset to the text, it can be negative\n", argv[0]);
1500                 exit (EXIT_SUCCESS);
1501             case 'g': (void)parse_geometry_string(optarg, geom_v); break;
1502             case 'p': permanent = true; break;
1503             case 'n': wm_name = strdup(optarg); break;
1504             case 'b': topbar = false; break;
1505             case 'd': dock = true; break;
1506             case 'f': font_load(optarg); break;
1507             case 'u': bu = strtoul(optarg, NULL, 10); break;
1508             case 'o': add_y_offset(strtol(optarg, NULL, 10)); break;
1509             case 'B': dbgc = bgc = parse_color(optarg, NULL, (rgba_t)0x00000000U); break;
1510             case 'F': dfgc = fgc = parse_color(optarg, NULL, (rgba_t)0xffffffffU); break;
1511             case 'U': dugc = ugc = parse_color(optarg, NULL, fgc); break;
1512             case 'a': areas = strtoul(optarg, NULL, 10); break;
1513         }
1514     }
1515 
1516     // Initialize the stack holding the clickable areas
1517     area_stack.at = 0;
1518     area_stack.max = areas;
1519     if (areas) {
1520         area_stack.area = calloc(areas, sizeof(area_t));
1521 
1522         if (!area_stack.area) {
1523             fprintf(stderr, "Could not allocate enough memory for %d clickable areas, try lowering the number\n", areas);
1524             return EXIT_FAILURE;
1525         }
1526     }
1527     else
1528         area_stack.area = NULL;
1529 
1530 
1531     // Copy the geometry values in place
1532     bw = geom_v[0];
1533     bh = geom_v[1];
1534     bx = geom_v[2];
1535     by = geom_v[3];
1536 
1537     // Do the heavy lifting
1538     init(wm_name, instance_name);
1539     // The string is strdup'd when the command line arguments are parsed
1540     free(wm_name);
1541     // The string is strdup'd when stripping argv[0]
1542     free(instance_name);
1543     // Get the fd to Xserver
1544     pollin[1].fd = xcb_get_file_descriptor(c);
1545 
1546     // Prevent fgets to block
1547     fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
1548 	
1549     for (;;) {
1550         bool redraw = false;
1551 
1552         // If connection is in error state, then it has been shut down.
1553         if (xcb_connection_has_error(c))
1554             break;
1555 
1556         if (poll(pollin, 2, -1) > 0) {
1557             if (pollin[0].revents & POLLHUP) {      // No more data...
1558                 if (permanent) pollin[0].fd = -1;   // ...null the fd and continue polling :D
1559                 else break;                         // ...bail out
1560             }
1561             if (pollin[0].revents & POLLIN) { // New input, process it
1562                 input[0] = '\0';
1563                 while (fgets(input, sizeof(input), stdin) != NULL)
1564                     ; // Drain the buffer, the last line is actually used
1565                 parse(input);
1566                 redraw = true;
1567             }
1568             if (pollin[1].revents & POLLIN) { // The event comes from the Xorg server
1569                 while ((ev = xcb_poll_for_event(c))) {
1570                     expose_ev = (xcb_expose_event_t *)ev;
1571 
1572                     switch (ev->response_type & 0x7F) {
1573                         case XCB_EXPOSE:
1574                             if (expose_ev->count == 0)
1575                                 redraw = true;
1576                             break;
1577                         case XCB_BUTTON_PRESS:
1578                             press_ev = (xcb_button_press_event_t *)ev;
1579                             {
1580                                 area_t *area = area_get(press_ev->event, press_ev->detail, press_ev->event_x);
1581                                 // Respond to the click
1582                                 if (area) {
1583                                     (void)write(STDOUT_FILENO, area->cmd, strlen(area->cmd));
1584                                     (void)write(STDOUT_FILENO, "\n", 1);
1585                                 }
1586                             }
1587                         break;
1588                     }
1589 
1590                     free(ev);
1591                 }
1592             }
1593         }
1594 
1595         if (redraw) { // Copy our temporary pixmap onto the window
1596             for (monitor_t *mon = monhead; mon; mon = mon->next) {
1597                 xcb_copy_area(c, mon->pixmap, mon->window, gc[GC_DRAW], 0, 0, 0, 0, mon->width, bh);
1598             }
1599         }
1600 
1601         xcb_flush(c);
1602     }
1603 
1604     return EXIT_SUCCESS;
1605 }