Configuration file for DWM on MacBook Air
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.

411 lines
9.8 KiB

  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 "drw.h"
  8. #include "util.h"
  9. #define UTF_INVALID 0xFFFD
  10. #define UTF_SIZ 4
  11. static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
  12. static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
  13. static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
  14. static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
  15. static long
  16. utf8decodebyte(const char c, size_t *i) {
  17. for(*i = 0; *i < (UTF_SIZ + 1); ++(*i))
  18. if(((unsigned char)c & utfmask[*i]) == utfbyte[*i])
  19. return (unsigned char)c & ~utfmask[*i];
  20. return 0;
  21. }
  22. static size_t
  23. utf8validate(long *u, size_t i) {
  24. if(!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
  25. *u = UTF_INVALID;
  26. for(i = 1; *u > utfmax[i]; ++i)
  27. ;
  28. return i;
  29. }
  30. static size_t
  31. utf8decode(const char *c, long *u, size_t clen) {
  32. size_t i, j, len, type;
  33. long udecoded;
  34. *u = UTF_INVALID;
  35. if(!clen)
  36. return 0;
  37. udecoded = utf8decodebyte(c[0], &len);
  38. if(!BETWEEN(len, 1, UTF_SIZ))
  39. return 1;
  40. for(i = 1, j = 1; i < clen && j < len; ++i, ++j) {
  41. udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
  42. if(type != 0)
  43. return j;
  44. }
  45. if(j < len)
  46. return 0;
  47. *u = udecoded;
  48. utf8validate(u, len);
  49. return len;
  50. }
  51. Drw *
  52. drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) {
  53. Drw *drw = (Drw *)calloc(1, sizeof(Drw));
  54. if(!drw)
  55. return NULL;
  56. drw->dpy = dpy;
  57. drw->screen = screen;
  58. drw->root = root;
  59. drw->w = w;
  60. drw->h = h;
  61. drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
  62. drw->gc = XCreateGC(dpy, root, 0, NULL);
  63. drw->fontcount = 0;
  64. XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
  65. return drw;
  66. }
  67. void
  68. drw_resize(Drw *drw, unsigned int w, unsigned int h) {
  69. if(!drw)
  70. return;
  71. drw->w = w;
  72. drw->h = h;
  73. if(drw->drawable != 0)
  74. XFreePixmap(drw->dpy, drw->drawable);
  75. drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
  76. }
  77. void
  78. drw_free(Drw *drw) {
  79. size_t i;
  80. for (i = 0; i < drw->fontcount; i++) {
  81. drw_font_free(drw->fonts[i]);
  82. }
  83. XFreePixmap(drw->dpy, drw->drawable);
  84. XFreeGC(drw->dpy, drw->gc);
  85. free(drw);
  86. }
  87. /* This function is an implementation detail. Library users should use
  88. * drw_font_create instead.
  89. */
  90. static Fnt *
  91. drw_font_xcreate(Drw *drw, const char *fontname, FcPattern *fontpattern) {
  92. Fnt *font;
  93. if (!(fontname || fontpattern))
  94. die("No font specified.\n");
  95. if (!(font = (Fnt *)calloc(1, sizeof(Fnt))))
  96. return NULL;
  97. if (fontname) {
  98. /* Using the pattern found at font->xfont->pattern does not yield same
  99. * the same substitution results as using the pattern returned by
  100. * FcNameParse; using the latter results in the desired fallback
  101. * behaviour whereas the former just results in
  102. * missing-character-rectangles being drawn, at least with some fonts.
  103. */
  104. if (!(font->xfont = XftFontOpenName(drw->dpy, drw->screen, fontname)) ||
  105. !(font->pattern = FcNameParse((FcChar8 *) fontname))) {
  106. if (font->xfont) {
  107. XftFontClose(drw->dpy, font->xfont);
  108. font->xfont = NULL;
  109. }
  110. fprintf(stderr, "error, cannot load font: '%s'\n", fontname);
  111. }
  112. } else if (fontpattern) {
  113. if (!(font->xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
  114. fprintf(stderr, "error, cannot load font pattern.\n");
  115. } else {
  116. font->pattern = NULL;
  117. }
  118. }
  119. if (!font->xfont) {
  120. free(font);
  121. return NULL;
  122. }
  123. font->ascent = font->xfont->ascent;
  124. font->descent = font->xfont->descent;
  125. font->h = font->ascent + font->descent;
  126. font->dpy = drw->dpy;
  127. return font;
  128. }
  129. Fnt*
  130. drw_font_create(Drw *drw, const char *fontname) {
  131. return drw_font_xcreate(drw, fontname, NULL);
  132. }
  133. void
  134. drw_load_fonts(Drw* drw, const char *fonts[], size_t fontcount) {
  135. size_t i;
  136. Fnt *font;
  137. for (i = 0; i < fontcount; i++) {
  138. if (drw->fontcount >= DRW_FONT_CACHE_SIZE) {
  139. die("Font cache exhausted.\n");
  140. } else if ((font = drw_font_xcreate(drw, fonts[i], NULL))) {
  141. drw->fonts[drw->fontcount++] = font;
  142. }
  143. }
  144. }
  145. void
  146. drw_font_free(Fnt *font) {
  147. if(!font)
  148. return;
  149. if(font->pattern)
  150. FcPatternDestroy(font->pattern);
  151. XftFontClose(font->dpy, font->xfont);
  152. free(font);
  153. }
  154. Clr *
  155. drw_clr_create(Drw *drw, const char *clrname) {
  156. Clr *clr;
  157. Colormap cmap;
  158. Visual *vis;
  159. if(!drw)
  160. return NULL;
  161. clr = (Clr *)calloc(1, sizeof(Clr));
  162. if(!clr)
  163. return NULL;
  164. cmap = DefaultColormap(drw->dpy, drw->screen);
  165. vis = DefaultVisual(drw->dpy, drw->screen);
  166. if(!XftColorAllocName(drw->dpy, vis, cmap, clrname, &clr->rgb))
  167. die("error, cannot allocate color '%s'\n", clrname);
  168. clr->pix = clr->rgb.pixel;
  169. return clr;
  170. }
  171. void
  172. drw_clr_free(Clr *clr) {
  173. if(clr)
  174. free(clr);
  175. }
  176. void
  177. drw_setscheme(Drw *drw, ClrScheme *scheme) {
  178. if(drw && scheme)
  179. drw->scheme = scheme;
  180. }
  181. void
  182. drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert) {
  183. int dx;
  184. if(!drw || !drw->fontcount || !drw->scheme)
  185. return;
  186. XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->bg->pix : drw->scheme->fg->pix);
  187. dx = (drw->fonts[0]->ascent + drw->fonts[0]->descent + 2) / 4;
  188. if(filled)
  189. XFillRectangle(drw->dpy, drw->drawable, drw->gc, x+1, y+1, dx+1, dx+1);
  190. else if(empty)
  191. XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x+1, y+1, dx, dx);
  192. }
  193. int
  194. drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int invert) {
  195. char buf[1024];
  196. int tx, ty, th;
  197. Extnts tex;
  198. Colormap cmap;
  199. Visual *vis;
  200. XftDraw *d;
  201. Fnt *curfont, *nextfont;
  202. size_t i, len;
  203. int utf8strlen, utf8charlen, render;
  204. long utf8codepoint = 0;
  205. const char *utf8str;
  206. FcCharSet *fccharset;
  207. FcPattern *fcpattern;
  208. FcPattern *match;
  209. XftResult result;
  210. int charexists = 0;
  211. if (!(render = x || y || w || h)) {
  212. w = ~w;
  213. }
  214. if (!drw || !drw->scheme) {
  215. return 0;
  216. } else if (render) {
  217. XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->fg->pix : drw->scheme->bg->pix);
  218. XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
  219. }
  220. if (!text || !drw->fontcount) {
  221. return 0;
  222. } else if (render) {
  223. cmap = DefaultColormap(drw->dpy, drw->screen);
  224. vis = DefaultVisual(drw->dpy, drw->screen);
  225. d = XftDrawCreate(drw->dpy, drw->drawable, vis, cmap);
  226. }
  227. curfont = drw->fonts[0];
  228. while (1) {
  229. utf8strlen = 0;
  230. utf8str = text;
  231. nextfont = NULL;
  232. while (*text) {
  233. utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ);
  234. for (i = 0; i < drw->fontcount; i++) {
  235. charexists = charexists || XftCharExists(drw->dpy, drw->fonts[i]->xfont, utf8codepoint);
  236. if (charexists) {
  237. if (drw->fonts[i] == curfont) {
  238. utf8strlen += utf8charlen;
  239. text += utf8charlen;
  240. } else {
  241. nextfont = drw->fonts[i];
  242. }
  243. break;
  244. }
  245. }
  246. if (!charexists || (nextfont && nextfont != curfont)) {
  247. break;
  248. } else {
  249. charexists = 0;
  250. }
  251. }
  252. if (utf8strlen) {
  253. drw_font_getexts(curfont, utf8str, utf8strlen, &tex);
  254. /* shorten text if necessary */
  255. for(len = MIN(utf8strlen, (sizeof buf) - 1); len && (tex.w > w - drw->fonts[0]->h || w < drw->fonts[0]->h); len--)
  256. drw_font_getexts(curfont, utf8str, len, &tex);
  257. if (len) {
  258. memcpy(buf, utf8str, len);
  259. buf[len] = '\0';
  260. if(len < utf8strlen)
  261. for(i = len; i && i > len - 3; buf[--i] = '.');
  262. if (render) {
  263. th = curfont->ascent + curfont->descent;
  264. ty = y + (h / 2) - (th / 2) + curfont->ascent;
  265. tx = x + (h / 2);
  266. XftDrawStringUtf8(d, invert ? &drw->scheme->bg->rgb : &drw->scheme->fg->rgb, curfont->xfont, tx, ty, (XftChar8 *)buf, len);
  267. }
  268. x += tex.w;
  269. w -= tex.w;
  270. }
  271. }
  272. if (!*text) {
  273. break;
  274. } else if (nextfont) {
  275. charexists = 0;
  276. curfont = nextfont;
  277. } else {
  278. /* Regardless of whether or not a fallback font is found, the
  279. * character must be drawn.
  280. */
  281. charexists = 1;
  282. if (drw->fontcount >= DRW_FONT_CACHE_SIZE) {
  283. continue;
  284. }
  285. fccharset = FcCharSetCreate();
  286. FcCharSetAddChar(fccharset, utf8codepoint);
  287. if (!drw->fonts[0]->pattern) {
  288. /* Refer to the comment in drw_font_xcreate for more
  289. * information.
  290. */
  291. die("The first font in the cache must be loaded from a font string.\n");
  292. }
  293. fcpattern = FcPatternDuplicate(drw->fonts[0]->pattern);
  294. FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
  295. FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
  296. FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
  297. FcDefaultSubstitute(fcpattern);
  298. match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
  299. FcCharSetDestroy(fccharset);
  300. FcPatternDestroy(fcpattern);
  301. if (match) {
  302. curfont = drw_font_xcreate(drw, NULL, match);
  303. if (curfont && XftCharExists(drw->dpy, curfont->xfont, utf8codepoint)) {
  304. drw->fonts[drw->fontcount++] = curfont;
  305. } else {
  306. if (curfont) {
  307. drw_font_free(curfont);
  308. }
  309. curfont = drw->fonts[0];
  310. }
  311. }
  312. }
  313. }
  314. if (render) {
  315. XftDrawDestroy(d);
  316. }
  317. return x;
  318. }
  319. void
  320. drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) {
  321. if(!drw)
  322. return;
  323. XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
  324. XSync(drw->dpy, False);
  325. }
  326. void
  327. drw_font_getexts(Fnt *font, const char *text, unsigned int len, Extnts *tex) {
  328. XGlyphInfo ext;
  329. if(!font || !text)
  330. return;
  331. XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
  332. tex->h = font->h;
  333. tex->w = ext.xOff;
  334. }
  335. unsigned int
  336. drw_font_getexts_width(Fnt *font, const char *text, unsigned int len) {
  337. Extnts tex;
  338. if(!font)
  339. return -1;
  340. drw_font_getexts(font, text, len, &tex);
  341. return tex.w;
  342. }
  343. Cur *
  344. drw_cur_create(Drw *drw, int shape) {
  345. Cur *cur = (Cur *)calloc(1, sizeof(Cur));
  346. if(!drw || !cur)
  347. return NULL;
  348. cur->cursor = XCreateFontCursor(drw->dpy, shape);
  349. return cur;
  350. }
  351. void
  352. drw_cur_free(Drw *drw, Cur *cursor) {
  353. if(!drw || !cursor)
  354. return;
  355. XFreeCursor(drw->dpy, cursor->cursor);
  356. free(cursor);
  357. }