Another copy of my dotfiles. Because I don't completely trust GitHub.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

689 lines
17 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. /* See LICENSE file for copyright and license details. */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <X11/Xlib.h>
  6. #include <X11/Xft/Xft.h>
  7. #include "patches.h"
  8. #include "drw.h"
  9. #include "util.h"
  10. #if !BAR_PANGO_PATCH
  11. #define UTF_INVALID 0xFFFD
  12. #define UTF_SIZ 4
  13. static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
  14. static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
  15. static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
  16. static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
  17. #endif // BAR_PANGO_PATCH
  18. #if BAR_POWERLINE_TAGS_PATCH || BAR_POWERLINE_STATUS_PATCH
  19. Clr transcheme[3];
  20. #endif // BAR_POWERLINE_TAGS_PATCH | BAR_POWERLINE_STATUS_PATCH
  21. #if !BAR_PANGO_PATCH
  22. static long
  23. utf8decodebyte(const char c, size_t *i)
  24. {
  25. for (*i = 0; *i < (UTF_SIZ + 1); ++(*i))
  26. if (((unsigned char)c & utfmask[*i]) == utfbyte[*i])
  27. return (unsigned char)c & ~utfmask[*i];
  28. return 0;
  29. }
  30. static size_t
  31. utf8validate(long *u, size_t i)
  32. {
  33. if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
  34. *u = UTF_INVALID;
  35. for (i = 1; *u > utfmax[i]; ++i)
  36. ;
  37. return i;
  38. }
  39. static size_t
  40. utf8decode(const char *c, long *u, size_t clen)
  41. {
  42. size_t i, j, len, type;
  43. long udecoded;
  44. *u = UTF_INVALID;
  45. if (!clen)
  46. return 0;
  47. udecoded = utf8decodebyte(c[0], &len);
  48. if (!BETWEEN(len, 1, UTF_SIZ))
  49. return 1;
  50. for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
  51. udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
  52. if (type)
  53. return j;
  54. }
  55. if (j < len)
  56. return 0;
  57. *u = udecoded;
  58. utf8validate(u, len);
  59. return len;
  60. }
  61. #endif // BAR_PANGO_PATCH
  62. Drw *
  63. #if BAR_ALPHA_PATCH
  64. drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap)
  65. #else
  66. drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
  67. #endif // BAR_ALPHA_PATCH
  68. {
  69. Drw *drw = ecalloc(1, sizeof(Drw));
  70. drw->dpy = dpy;
  71. drw->screen = screen;
  72. drw->root = root;
  73. drw->w = w;
  74. drw->h = h;
  75. #if BAR_ALPHA_PATCH
  76. drw->visual = visual;
  77. drw->depth = depth;
  78. drw->cmap = cmap;
  79. drw->drawable = XCreatePixmap(dpy, root, w, h, depth);
  80. drw->gc = XCreateGC(dpy, drw->drawable, 0, NULL);
  81. #else
  82. drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
  83. drw->gc = XCreateGC(dpy, root, 0, NULL);
  84. #endif // BAR_ALPHA_PATCH
  85. XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
  86. return drw;
  87. }
  88. void
  89. drw_resize(Drw *drw, unsigned int w, unsigned int h)
  90. {
  91. if (!drw)
  92. return;
  93. drw->w = w;
  94. drw->h = h;
  95. if (drw->drawable)
  96. XFreePixmap(drw->dpy, drw->drawable);
  97. #if BAR_ALPHA_PATCH
  98. drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth);
  99. #else
  100. drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
  101. #endif // BAR_ALPHA_PATCH
  102. }
  103. void
  104. drw_free(Drw *drw)
  105. {
  106. XFreePixmap(drw->dpy, drw->drawable);
  107. XFreeGC(drw->dpy, drw->gc);
  108. drw_fontset_free(drw->fonts);
  109. free(drw);
  110. }
  111. #if BAR_PANGO_PATCH
  112. /* This function is an implementation detail. Library users should use
  113. * drw_font_create instead.
  114. */
  115. static Fnt *
  116. xfont_create(Drw *drw, const char *fontname)
  117. {
  118. Fnt *font;
  119. PangoFontMap *fontmap;
  120. PangoContext *context;
  121. PangoFontDescription *desc;
  122. PangoFontMetrics *metrics;
  123. if (!fontname) {
  124. die("no font specified.");
  125. }
  126. font = ecalloc(1, sizeof(Fnt));
  127. font->dpy = drw->dpy;
  128. fontmap = pango_xft_get_font_map(drw->dpy, drw->screen);
  129. context = pango_font_map_create_context(fontmap);
  130. desc = pango_font_description_from_string(fontname);
  131. font->layout = pango_layout_new(context);
  132. pango_layout_set_font_description(font->layout, desc);
  133. metrics = pango_context_get_metrics(context, desc, pango_language_from_string ("en-us"));
  134. font->h = pango_font_metrics_get_height(metrics) / PANGO_SCALE;
  135. pango_font_metrics_unref(metrics);
  136. g_object_unref(context);
  137. return font;
  138. }
  139. #else
  140. /* This function is an implementation detail. Library users should use
  141. * drw_fontset_create instead.
  142. */
  143. static Fnt *
  144. xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
  145. {
  146. Fnt *font;
  147. XftFont *xfont = NULL;
  148. FcPattern *pattern = NULL;
  149. if (fontname) {
  150. /* Using the pattern found at font->xfont->pattern does not yield the
  151. * same substitution results as using the pattern returned by
  152. * FcNameParse; using the latter results in the desired fallback
  153. * behaviour whereas the former just results in missing-character
  154. * rectangles being drawn, at least with some fonts. */
  155. if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) {
  156. fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname);
  157. return NULL;
  158. }
  159. if (!(pattern = FcNameParse((FcChar8 *) fontname))) {
  160. fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname);
  161. XftFontClose(drw->dpy, xfont);
  162. return NULL;
  163. }
  164. } else if (fontpattern) {
  165. if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
  166. fprintf(stderr, "error, cannot load font from pattern.\n");
  167. return NULL;
  168. }
  169. } else {
  170. die("no font specified.");
  171. }
  172. #if !BAR_COLOR_EMOJI_PATCH
  173. /* Do not allow using color fonts. This is a workaround for a BadLength
  174. * error from Xft with color glyphs. Modelled on the Xterm workaround. See
  175. * https://bugzilla.redhat.com/show_bug.cgi?id=1498269
  176. * https://lists.suckless.org/dev/1701/30932.html
  177. * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916349
  178. * and lots more all over the internet.
  179. */
  180. FcBool iscol;
  181. if (FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) {
  182. XftFontClose(drw->dpy, xfont);
  183. return NULL;
  184. }
  185. #endif // BAR_COLOR_EMOJI_PATCH
  186. font = ecalloc(1, sizeof(Fnt));
  187. font->xfont = xfont;
  188. font->pattern = pattern;
  189. font->h = xfont->ascent + xfont->descent;
  190. font->dpy = drw->dpy;
  191. return font;
  192. }
  193. #endif // BAR_PANGO_PATCH
  194. static void
  195. xfont_free(Fnt *font)
  196. {
  197. if (!font)
  198. return;
  199. #if BAR_PANGO_PATCH
  200. if (font->layout)
  201. g_object_unref(font->layout);
  202. #else
  203. if (font->pattern)
  204. FcPatternDestroy(font->pattern);
  205. XftFontClose(font->dpy, font->xfont);
  206. #endif // BAR_PANGO_PATCH
  207. free(font);
  208. }
  209. #if BAR_PANGO_PATCH
  210. Fnt*
  211. drw_font_create(Drw* drw, const char font[])
  212. {
  213. Fnt *fnt = NULL;
  214. if (!drw || !font)
  215. return NULL;
  216. fnt = xfont_create(drw, font);
  217. return (drw->fonts = fnt);
  218. }
  219. #else
  220. Fnt*
  221. drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
  222. {
  223. Fnt *cur, *ret = NULL;
  224. size_t i;
  225. if (!drw || !fonts)
  226. return NULL;
  227. for (i = 1; i <= fontcount; i++) {
  228. if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) {
  229. cur->next = ret;
  230. ret = cur;
  231. }
  232. }
  233. return (drw->fonts = ret);
  234. }
  235. #endif // BAR_PANGO_PATCH
  236. void
  237. drw_fontset_free(Fnt *font)
  238. {
  239. if (font) {
  240. #if !BAR_PANGO_PATCH
  241. drw_fontset_free(font->next);
  242. #endif // BAR_PANGO_PATCH
  243. xfont_free(font);
  244. }
  245. }
  246. void
  247. drw_clr_create(
  248. Drw *drw,
  249. Clr *dest,
  250. const char *clrname
  251. #if BAR_ALPHA_PATCH
  252. , unsigned int alpha
  253. #endif // BAR_ALPHA_PATCH
  254. ) {
  255. if (!drw || !dest || !clrname)
  256. return;
  257. #if BAR_ALPHA_PATCH
  258. if (!XftColorAllocName(drw->dpy, drw->visual, drw->cmap,
  259. clrname, dest))
  260. die("error, cannot allocate color '%s'", clrname);
  261. dest->pixel = (dest->pixel & 0x00ffffffU) | (alpha << 24);
  262. #else
  263. if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
  264. DefaultColormap(drw->dpy, drw->screen),
  265. clrname, dest))
  266. die("error, cannot allocate color '%s'", clrname);
  267. #if NO_TRANSPARENT_BORDERS_PATCH
  268. dest->pixel |= 0xff << 24;
  269. #endif // NO_TRANSPARENT_BORDERS_PATCH
  270. #endif // BAR_ALPHA_PATCH
  271. }
  272. /* Wrapper to create color schemes. The caller has to call free(3) on the
  273. * returned color scheme when done using it. */
  274. Clr *
  275. drw_scm_create(
  276. Drw *drw,
  277. char *clrnames[],
  278. #if BAR_ALPHA_PATCH
  279. const unsigned int alphas[],
  280. #endif // BAR_ALPHA_PATCH
  281. size_t clrcount
  282. ) {
  283. size_t i;
  284. Clr *ret;
  285. /* need at least two colors for a scheme */
  286. if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor))))
  287. return NULL;
  288. for (i = 0; i < clrcount; i++)
  289. #if BAR_ALPHA_PATCH
  290. drw_clr_create(drw, &ret[i], clrnames[i], alphas[i]);
  291. #else
  292. drw_clr_create(drw, &ret[i], clrnames[i]);
  293. #endif // BAR_ALPHA_PATCH
  294. return ret;
  295. }
  296. #if !BAR_PANGO_PATCH
  297. void
  298. drw_setfontset(Drw *drw, Fnt *set)
  299. {
  300. if (drw)
  301. drw->fonts = set;
  302. }
  303. #endif // BAR_PANGO_PATCH
  304. void
  305. drw_setscheme(Drw *drw, Clr *scm)
  306. {
  307. if (drw)
  308. drw->scheme = scm;
  309. }
  310. #if BAR_POWERLINE_TAGS_PATCH || BAR_POWERLINE_STATUS_PATCH
  311. void
  312. drw_settrans(Drw *drw, Clr *psc, Clr *nsc)
  313. {
  314. if (drw) {
  315. transcheme[0] = psc[ColBg]; transcheme[1] = nsc[ColBg]; transcheme[2] = psc[ColBorder];
  316. drw->scheme = transcheme;
  317. }
  318. }
  319. #endif // BAR_POWERLINE_TAGS_PATCH | BAR_POWERLINE_STATUS_PATCH
  320. void
  321. drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert)
  322. {
  323. if (!drw || !drw->scheme)
  324. return;
  325. XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
  326. if (filled)
  327. XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
  328. else
  329. XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
  330. }
  331. #if BAR_PANGO_PATCH
  332. int
  333. drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool markup)
  334. {
  335. char buf[1024];
  336. int ty;
  337. unsigned int ew;
  338. XftDraw *d = NULL;
  339. size_t i, len;
  340. int render = x || y || w || h;
  341. if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
  342. return 0;
  343. if (!render) {
  344. w = ~w;
  345. } else {
  346. XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
  347. XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
  348. #if BAR_ALPHA_PATCH
  349. d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
  350. #else
  351. d = XftDrawCreate(drw->dpy, drw->drawable,
  352. DefaultVisual(drw->dpy, drw->screen),
  353. DefaultColormap(drw->dpy, drw->screen));
  354. #endif // BAR_ALPHA_PATCH
  355. x += lpad;
  356. w -= lpad;
  357. }
  358. len = strlen(text);
  359. if (len) {
  360. drw_font_getexts(drw->fonts, text, len, &ew, NULL, markup);
  361. /* shorten text if necessary */
  362. for (len = MIN(len, sizeof(buf) - 1); len && ew > w; len--)
  363. drw_font_getexts(drw->fonts, text, len, &ew, NULL, markup);
  364. if (len) {
  365. memcpy(buf, text, len);
  366. buf[len] = '\0';
  367. if (len < strlen(text))
  368. for (i = len; i && i > len - 3; buf[--i] = '.')
  369. ; /* NOP */
  370. if (render) {
  371. ty = y + (h - drw->fonts->h) / 2;
  372. if (markup)
  373. pango_layout_set_markup(drw->fonts->layout, buf, len);
  374. else
  375. pango_layout_set_text(drw->fonts->layout, buf, len);
  376. pango_xft_render_layout(d, &drw->scheme[invert ? ColBg : ColFg],
  377. drw->fonts->layout, x * PANGO_SCALE, ty * PANGO_SCALE);
  378. if (markup) /* clear markup attributes */
  379. pango_layout_set_attributes(drw->fonts->layout, NULL);
  380. }
  381. x += ew;
  382. w -= ew;
  383. }
  384. }
  385. if (d)
  386. XftDrawDestroy(d);
  387. return x + (render ? w : 0);
  388. }
  389. #else
  390. int
  391. drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool ignored)
  392. {
  393. char buf[1024];
  394. int ty;
  395. unsigned int ew;
  396. XftDraw *d = NULL;
  397. Fnt *usedfont, *curfont, *nextfont;
  398. size_t i, len;
  399. int utf8strlen, utf8charlen, render = x || y || w || h;
  400. long utf8codepoint = 0;
  401. const char *utf8str;
  402. FcCharSet *fccharset;
  403. FcPattern *fcpattern;
  404. FcPattern *match;
  405. XftResult result;
  406. int charexists = 0;
  407. if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
  408. return 0;
  409. if (!render) {
  410. w = ~w;
  411. } else {
  412. XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
  413. XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
  414. #if BAR_ALPHA_PATCH
  415. d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
  416. #else
  417. d = XftDrawCreate(drw->dpy, drw->drawable,
  418. DefaultVisual(drw->dpy, drw->screen),
  419. DefaultColormap(drw->dpy, drw->screen));
  420. #endif // BAR_ALPHA_PATCH
  421. x += lpad;
  422. w -= lpad;
  423. }
  424. usedfont = drw->fonts;
  425. while (1) {
  426. utf8strlen = 0;
  427. utf8str = text;
  428. nextfont = NULL;
  429. while (*text) {
  430. utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ);
  431. for (curfont = drw->fonts; curfont; curfont = curfont->next) {
  432. charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
  433. if (charexists) {
  434. if (curfont == usedfont) {
  435. utf8strlen += utf8charlen;
  436. text += utf8charlen;
  437. } else {
  438. nextfont = curfont;
  439. }
  440. break;
  441. }
  442. }
  443. if (!charexists || nextfont)
  444. break;
  445. else
  446. charexists = 0;
  447. }
  448. if (utf8strlen) {
  449. drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
  450. /* shorten text if necessary */
  451. for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--)
  452. drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
  453. if (len) {
  454. memcpy(buf, utf8str, len);
  455. buf[len] = '\0';
  456. if (len < utf8strlen)
  457. for (i = len; i && i > len - 3; buf[--i] = '.')
  458. ; /* NOP */
  459. if (render) {
  460. ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
  461. XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
  462. usedfont->xfont, x, ty, (XftChar8 *)buf, len);
  463. }
  464. x += ew;
  465. w -= ew;
  466. }
  467. }
  468. if (!*text) {
  469. break;
  470. } else if (nextfont) {
  471. charexists = 0;
  472. usedfont = nextfont;
  473. } else {
  474. /* Regardless of whether or not a fallback font is found, the
  475. * character must be drawn. */
  476. charexists = 1;
  477. fccharset = FcCharSetCreate();
  478. FcCharSetAddChar(fccharset, utf8codepoint);
  479. if (!drw->fonts->pattern) {
  480. /* Refer to the comment in xfont_create for more information. */
  481. die("the first font in the cache must be loaded from a font string.");
  482. }
  483. fcpattern = FcPatternDuplicate(drw->fonts->pattern);
  484. FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
  485. FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
  486. FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
  487. FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
  488. FcDefaultSubstitute(fcpattern);
  489. match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
  490. FcCharSetDestroy(fccharset);
  491. FcPatternDestroy(fcpattern);
  492. if (match) {
  493. usedfont = xfont_create(drw, NULL, match);
  494. if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) {
  495. for (curfont = drw->fonts; curfont->next; curfont = curfont->next)
  496. ; /* NOP */
  497. curfont->next = usedfont;
  498. } else {
  499. xfont_free(usedfont);
  500. usedfont = drw->fonts;
  501. }
  502. }
  503. }
  504. }
  505. if (d)
  506. XftDrawDestroy(d);
  507. return x + (render ? w : 0);
  508. }
  509. #endif // BAR_PANGO_PATCH
  510. #if BAR_POWERLINE_TAGS_PATCH || BAR_POWERLINE_STATUS_PATCH
  511. void
  512. drw_arrow(Drw *drw, int x, int y, unsigned int w, unsigned int h, int direction, int slash)
  513. {
  514. if (!drw || !drw->scheme)
  515. return;
  516. /* direction=1 draws right arrow */
  517. x = direction ? x : x + w;
  518. w = direction ? w : -w;
  519. /* slash=1 draws slash instead of arrow */
  520. unsigned int hh = slash ? (direction ? 0 : h) : h/2;
  521. XPoint points[] = {
  522. {x , y },
  523. {x + w, y + hh },
  524. {x , y + h },
  525. };
  526. XPoint bg[] = {
  527. {x , y },
  528. {x + w, y },
  529. {x + w, y + h},
  530. {x , y + h},
  531. };
  532. XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel);
  533. XFillPolygon(drw->dpy, drw->drawable, drw->gc, bg, 4, Convex, CoordModeOrigin);
  534. XSetForeground(drw->dpy, drw->gc, drw->scheme[ColFg].pixel);
  535. XFillPolygon(drw->dpy, drw->drawable, drw->gc, points, 3, Nonconvex, CoordModeOrigin);
  536. }
  537. #endif // BAR_POWERLINE_TAGS_PATCH | BAR_POWERLINE_STATUS_PATCH
  538. void
  539. drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
  540. {
  541. if (!drw)
  542. return;
  543. XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
  544. XSync(drw->dpy, False);
  545. }
  546. unsigned int
  547. drw_fontset_getwidth(Drw *drw, const char *text, Bool markup)
  548. {
  549. if (!drw || !drw->fonts || !text)
  550. return 0;
  551. return drw_text(drw, 0, 0, 0, 0, 0, text, 0, markup);
  552. }
  553. #if BAR_PANGO_PATCH
  554. void
  555. drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h, Bool markup)
  556. {
  557. if (!font || !text)
  558. return;
  559. PangoRectangle r;
  560. if (markup)
  561. pango_layout_set_markup(font->layout, text, len);
  562. else
  563. pango_layout_set_text(font->layout, text, len);
  564. pango_layout_get_extents(font->layout, 0, &r);
  565. if (markup) /* clear markup attributes */
  566. pango_layout_set_attributes(font->layout, NULL);
  567. if (w)
  568. *w = r.width / PANGO_SCALE;
  569. if (h)
  570. *h = font->h;
  571. }
  572. #else
  573. void
  574. drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
  575. {
  576. XGlyphInfo ext;
  577. if (!font || !text)
  578. return;
  579. XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
  580. if (w)
  581. *w = ext.xOff;
  582. if (h)
  583. *h = font->h;
  584. }
  585. #endif // BAR_PANGO_PATCH
  586. Cur *
  587. drw_cur_create(Drw *drw, int shape)
  588. {
  589. Cur *cur;
  590. if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
  591. return NULL;
  592. cur->cursor = XCreateFontCursor(drw->dpy, shape);
  593. return cur;
  594. }
  595. void
  596. drw_cur_free(Drw *drw, Cur *cursor)
  597. {
  598. if (!cursor)
  599. return;
  600. XFreeCursor(drw->dpy, cursor->cursor);
  601. free(cursor);
  602. }