diff options
| author | Filip Wandzio <contact@philw.dev> | 2025-09-08 19:09:10 +0200 |
|---|---|---|
| committer | Filip Wandzio <contact@philw.dev> | 2025-09-08 19:09:10 +0200 |
| commit | f33c70176cd078c6e1c189b9c2a61089422129c9 (patch) | |
| tree | eaf3d27a81566d5118b0736ba32f5189963e4d1c /src/drw | |
| parent | bd019ee25b380d32ccf900f5afa0dab9f9d541b8 (diff) | |
| download | dwm-f33c70176cd078c6e1c189b9c2a61089422129c9.tar.gz dwm-f33c70176cd078c6e1c189b9c2a61089422129c9.zip | |
Enforce code style, reformat project
Signed-off-by: Filip Wandzio <contact@philw.dev>
Diffstat (limited to '')
| -rw-r--r-- | src/drw/drw.c | 744 | ||||
| -rw-r--r-- | src/drw/drw.h | 28 |
2 files changed, 412 insertions, 360 deletions
diff --git a/src/drw/drw.c b/src/drw/drw.c index 8f53beb..05420c0 100644 --- a/src/drw/drw.c +++ b/src/drw/drw.c | |||
| @@ -18,408 +18,460 @@ static const long utfmin[UTF_SIZ + 1] = {0, 0, 0x80, 0x800, 0x10000}; | |||
| 18 | static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, | 18 | static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, |
| 19 | 0x10FFFF}; | 19 | 0x10FFFF}; |
| 20 | 20 | ||
| 21 | static long utf8decodebyte(const char c, size_t *i) { | 21 | static long utf8decodebyte(const char c, size_t *i) |
| 22 | for (*i = 0; *i < (UTF_SIZ + 1); ++(*i)) | 22 | { |
| 23 | if (((unsigned char)c & utfmask[*i]) == utfbyte[*i]) | 23 | for (*i = 0; *i < (UTF_SIZ + 1); ++(*i)) |
| 24 | return (unsigned char)c & ~utfmask[*i]; | 24 | if (((unsigned char)c & utfmask[*i]) == utfbyte[*i]) |
| 25 | return 0; | 25 | return (unsigned char)c & ~utfmask[*i]; |
| 26 | return 0; | ||
| 26 | } | 27 | } |
| 27 | 28 | ||
| 28 | static size_t utf8validate(long *u, size_t i) { | 29 | static size_t utf8validate(long *u, size_t i) |
| 29 | if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) | 30 | { |
| 30 | *u = UTF_INVALID; | 31 | if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) |
| 31 | for (i = 1; *u > utfmax[i]; ++i) | 32 | *u = UTF_INVALID; |
| 32 | ; | 33 | for (i = 1; *u > utfmax[i]; ++i) |
| 33 | return i; | 34 | ; |
| 35 | return i; | ||
| 34 | } | 36 | } |
| 35 | 37 | ||
| 36 | static size_t utf8decode(const char *c, long *u, size_t clen) { | 38 | static size_t utf8decode(const char *c, long *u, size_t clen) |
| 37 | size_t i, j, len, type; | 39 | { |
| 38 | long udecoded; | 40 | size_t i, j, len, type; |
| 39 | 41 | long udecoded; | |
| 40 | *u = UTF_INVALID; | 42 | |
| 41 | if (!clen) | 43 | *u = UTF_INVALID; |
| 42 | return 0; | 44 | if (!clen) |
| 43 | udecoded = utf8decodebyte(c[0], &len); | 45 | return 0; |
| 44 | if (!BETWEEN(len, 1, UTF_SIZ)) | 46 | udecoded = utf8decodebyte(c[0], &len); |
| 45 | return 1; | 47 | if (!BETWEEN(len, 1, UTF_SIZ)) |
| 46 | for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { | 48 | return 1; |
| 47 | udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); | 49 | for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { |
| 48 | if (type) | 50 | udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); |
| 49 | return j; | 51 | if (type) |
| 50 | } | 52 | return j; |
| 51 | if (j < len) | 53 | } |
| 52 | return 0; | 54 | if (j < len) |
| 53 | *u = udecoded; | 55 | return 0; |
| 54 | utf8validate(u, len); | 56 | *u = udecoded; |
| 55 | 57 | utf8validate(u, len); | |
| 56 | return len; | 58 | |
| 59 | return len; | ||
| 57 | } | 60 | } |
| 58 | 61 | ||
| 59 | Drw *drw_create(Display *dpy, int screen, Window root, unsigned int w, | 62 | Drw *drw_create(Display *dpy, int screen, Window root, unsigned int w, |
| 60 | unsigned int h) { | 63 | unsigned int h) |
| 61 | Drw *drw = ecalloc(1, sizeof(Drw)); | 64 | { |
| 62 | 65 | Drw *drw = ecalloc(1, sizeof(Drw)); | |
| 63 | drw->dpy = dpy; | 66 | |
| 64 | drw->screen = screen; | 67 | drw->dpy = dpy; |
| 65 | drw->root = root; | 68 | drw->screen = screen; |
| 66 | drw->w = w; | 69 | drw->root = root; |
| 67 | drw->h = h; | 70 | drw->w = w; |
| 68 | drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); | 71 | drw->h = h; |
| 69 | drw->gc = XCreateGC(dpy, root, 0, NULL); | 72 | drw->drawable = |
| 70 | XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); | 73 | XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); |
| 71 | 74 | drw->gc = XCreateGC(dpy, root, 0, NULL); | |
| 72 | return drw; | 75 | XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); |
| 76 | |||
| 77 | return drw; | ||
| 73 | } | 78 | } |
| 74 | 79 | ||
| 75 | void drw_resize(Drw *drw, unsigned int w, unsigned int h) { | 80 | void drw_resize(Drw *drw, unsigned int w, unsigned int h) |
| 76 | if (!drw) | 81 | { |
| 77 | return; | 82 | if (!drw) |
| 78 | 83 | return; | |
| 79 | drw->w = w; | 84 | |
| 80 | drw->h = h; | 85 | drw->w = w; |
| 81 | if (drw->drawable) | 86 | drw->h = h; |
| 82 | XFreePixmap(drw->dpy, drw->drawable); | 87 | if (drw->drawable) |
| 83 | drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, | 88 | XFreePixmap(drw->dpy, drw->drawable); |
| 84 | DefaultDepth(drw->dpy, drw->screen)); | 89 | drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, |
| 90 | DefaultDepth(drw->dpy, drw->screen)); | ||
| 85 | } | 91 | } |
| 86 | 92 | ||
| 87 | void drw_free(Drw *drw) { | 93 | void drw_free(Drw *drw) |
| 88 | XFreePixmap(drw->dpy, drw->drawable); | 94 | { |
| 89 | XFreeGC(drw->dpy, drw->gc); | 95 | XFreePixmap(drw->dpy, drw->drawable); |
| 90 | drw_fontset_free(drw->fonts); | 96 | XFreeGC(drw->dpy, drw->gc); |
| 91 | free(drw); | 97 | drw_fontset_free(drw->fonts); |
| 98 | free(drw); | ||
| 92 | } | 99 | } |
| 93 | 100 | ||
| 94 | /* This function is an implementation detail. Library users should use | 101 | /* This function is an implementation detail. Library users should use |
| 95 | * drw_fontset_create instead. | 102 | * drw_fontset_create instead. |
| 96 | */ | 103 | */ |
| 97 | static Fnt *xfont_create(Drw *drw, const char *fontname, | 104 | static Fnt *xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) |
| 98 | FcPattern *fontpattern) { | 105 | { |
| 99 | Fnt *font; | 106 | Fnt *font; |
| 100 | XftFont *xfont = NULL; | 107 | XftFont *xfont = NULL; |
| 101 | FcPattern *pattern = NULL; | 108 | FcPattern *pattern = NULL; |
| 102 | 109 | ||
| 103 | if (fontname) { | 110 | if (fontname) { |
| 104 | /* Using the pattern found at font->xfont->pattern does not yield the | 111 | /* Using the pattern found at font->xfont->pattern does not |
| 105 | * same substitution results as using the pattern returned by | 112 | * yield the same substitution results as using the pattern |
| 106 | * FcNameParse; using the latter results in the desired fallback | 113 | * returned by FcNameParse; using the latter results in the |
| 107 | * behaviour whereas the former just results in missing-character | 114 | * desired fallback behaviour whereas the former just results in |
| 108 | * rectangles being drawn, at least with some fonts. */ | 115 | * missing-character rectangles being drawn, at least with some |
| 109 | if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) { | 116 | * fonts. */ |
| 110 | fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname); | 117 | if (!(xfont = |
| 111 | return NULL; | 118 | XftFontOpenName(drw->dpy, drw->screen, fontname))) { |
| 112 | } | 119 | fprintf(stderr, |
| 113 | if (!(pattern = FcNameParse((FcChar8 *)fontname))) { | 120 | "error, cannot load font from name: '%s'\n", |
| 114 | fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", | 121 | fontname); |
| 115 | fontname); | 122 | return NULL; |
| 116 | XftFontClose(drw->dpy, xfont); | 123 | } |
| 117 | return NULL; | 124 | if (!(pattern = FcNameParse((FcChar8 *)fontname))) { |
| 118 | } | 125 | fprintf( |
| 119 | } else if (fontpattern) { | 126 | stderr, |
| 120 | if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) { | 127 | "error, cannot parse font name to pattern: '%s'\n", |
| 121 | fprintf(stderr, "error, cannot load font from pattern.\n"); | 128 | fontname); |
| 122 | return NULL; | 129 | XftFontClose(drw->dpy, xfont); |
| 123 | } | 130 | return NULL; |
| 124 | } else { | 131 | } |
| 125 | die("no font specified."); | 132 | } else if (fontpattern) { |
| 126 | } | 133 | if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) { |
| 127 | 134 | fprintf(stderr, | |
| 128 | font = ecalloc(1, sizeof(Fnt)); | 135 | "error, cannot load font from pattern.\n"); |
| 129 | font->xfont = xfont; | 136 | return NULL; |
| 130 | font->pattern = pattern; | 137 | } |
| 131 | font->h = xfont->ascent + xfont->descent; | 138 | } else { |
| 132 | font->dpy = drw->dpy; | 139 | die("no font specified."); |
| 133 | 140 | } | |
| 134 | return font; | 141 | |
| 142 | font = ecalloc(1, sizeof(Fnt)); | ||
| 143 | font->xfont = xfont; | ||
| 144 | font->pattern = pattern; | ||
| 145 | font->h = xfont->ascent + xfont->descent; | ||
| 146 | font->dpy = drw->dpy; | ||
| 147 | |||
| 148 | return font; | ||
| 135 | } | 149 | } |
| 136 | 150 | ||
| 137 | static void xfont_free(Fnt *font) { | 151 | static void xfont_free(Fnt *font) |
| 138 | if (!font) | 152 | { |
| 139 | return; | 153 | if (!font) |
| 140 | if (font->pattern) | 154 | return; |
| 141 | FcPatternDestroy(font->pattern); | 155 | if (font->pattern) |
| 142 | XftFontClose(font->dpy, font->xfont); | 156 | FcPatternDestroy(font->pattern); |
| 143 | free(font); | 157 | XftFontClose(font->dpy, font->xfont); |
| 158 | free(font); | ||
| 144 | } | 159 | } |
| 145 | 160 | ||
| 146 | Fnt *drw_fontset_create(Drw *drw, const char *fonts[], size_t fontcount) { | 161 | Fnt *drw_fontset_create(Drw *drw, const char *fonts[], size_t fontcount) |
| 147 | Fnt *cur, *ret = NULL; | 162 | { |
| 148 | size_t i; | 163 | Fnt *cur, *ret = NULL; |
| 149 | 164 | size_t i; | |
| 150 | if (!drw || !fonts) | 165 | |
| 151 | return NULL; | 166 | if (!drw || !fonts) |
| 152 | 167 | return NULL; | |
| 153 | for (i = 1; i <= fontcount; i++) { | 168 | |
| 154 | if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) { | 169 | for (i = 1; i <= fontcount; i++) { |
| 155 | cur->next = ret; | 170 | if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) { |
| 156 | ret = cur; | 171 | cur->next = ret; |
| 157 | } | 172 | ret = cur; |
| 158 | } | 173 | } |
| 159 | return (drw->fonts = ret); | 174 | } |
| 175 | return (drw->fonts = ret); | ||
| 160 | } | 176 | } |
| 161 | 177 | ||
| 162 | void drw_fontset_free(Fnt *font) { | 178 | void drw_fontset_free(Fnt *font) |
| 163 | if (font) { | 179 | { |
| 164 | drw_fontset_free(font->next); | 180 | if (font) { |
| 165 | xfont_free(font); | 181 | drw_fontset_free(font->next); |
| 166 | } | 182 | xfont_free(font); |
| 183 | } | ||
| 167 | } | 184 | } |
| 168 | 185 | ||
| 169 | void drw_clr_create(Drw *drw, Clr *dest, const char *clrname) { | 186 | void drw_clr_create(Drw *drw, Clr *dest, const char *clrname) |
| 170 | if (!drw || !dest || !clrname) | 187 | { |
| 171 | return; | 188 | if (!drw || !dest || !clrname) |
| 189 | return; | ||
| 172 | 190 | ||
| 173 | if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), | 191 | if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), |
| 174 | DefaultColormap(drw->dpy, drw->screen), clrname, dest)) | 192 | DefaultColormap(drw->dpy, drw->screen), clrname, |
| 175 | die("error, cannot allocate color '%s'", clrname); | 193 | dest)) |
| 194 | die("error, cannot allocate color '%s'", clrname); | ||
| 176 | } | 195 | } |
| 177 | 196 | ||
| 178 | /* Wrapper to create color schemes. The caller has to call free(3) on the | 197 | /* Wrapper to create color schemes. The caller has to call free(3) on the |
| 179 | * returned color scheme when done using it. */ | 198 | * returned color scheme when done using it. */ |
| 180 | Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) { | 199 | Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) |
| 181 | size_t i; | 200 | { |
| 182 | Clr *ret; | 201 | size_t i; |
| 183 | 202 | Clr *ret; | |
| 184 | /* need at least two colors for a scheme */ | 203 | |
| 185 | if (!drw || !clrnames || clrcount < 2 || | 204 | /* need at least two colors for a scheme */ |
| 186 | !(ret = ecalloc(clrcount, sizeof(XftColor)))) | 205 | if (!drw || !clrnames || clrcount < 2 || |
| 187 | return NULL; | 206 | !(ret = ecalloc(clrcount, sizeof(XftColor)))) |
| 188 | 207 | return NULL; | |
| 189 | for (i = 0; i < clrcount; i++) | 208 | |
| 190 | drw_clr_create(drw, &ret[i], clrnames[i]); | 209 | for (i = 0; i < clrcount; i++) |
| 191 | return ret; | 210 | drw_clr_create(drw, &ret[i], clrnames[i]); |
| 211 | return ret; | ||
| 192 | } | 212 | } |
| 193 | 213 | ||
| 194 | void drw_setfontset(Drw *drw, Fnt *set) { | 214 | void drw_setfontset(Drw *drw, Fnt *set) |
| 195 | if (drw) | 215 | { |
| 196 | drw->fonts = set; | 216 | if (drw) |
| 217 | drw->fonts = set; | ||
| 197 | } | 218 | } |
| 198 | 219 | ||
| 199 | void drw_setscheme(Drw *drw, Clr *scm) { | 220 | void drw_setscheme(Drw *drw, Clr *scm) |
| 200 | if (drw) | 221 | { |
| 201 | drw->scheme = scm; | 222 | if (drw) |
| 223 | drw->scheme = scm; | ||
| 202 | } | 224 | } |
| 203 | 225 | ||
| 204 | void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, | 226 | void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, |
| 205 | int filled, int invert) { | 227 | int filled, int invert) |
| 206 | if (!drw || !drw->scheme) | 228 | { |
| 207 | return; | 229 | if (!drw || !drw->scheme) |
| 208 | XSetForeground(drw->dpy, drw->gc, | 230 | return; |
| 209 | invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel); | 231 | XSetForeground(drw->dpy, drw->gc, |
| 210 | if (filled) | 232 | invert ? drw->scheme[ColBg].pixel |
| 211 | XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); | 233 | : drw->scheme[ColFg].pixel); |
| 212 | else | 234 | if (filled) |
| 213 | XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1); | 235 | XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); |
| 236 | else | ||
| 237 | XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, | ||
| 238 | h - 1); | ||
| 214 | } | 239 | } |
| 215 | 240 | ||
| 216 | int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, | 241 | int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, |
| 217 | unsigned int lpad, const char *text, int invert) { | 242 | unsigned int lpad, const char *text, int invert) |
| 218 | int i, ty, ellipsis_x = 0; | 243 | { |
| 219 | unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len; | 244 | int i, ty, ellipsis_x = 0; |
| 220 | XftDraw *d = NULL; | 245 | unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len; |
| 221 | Fnt *usedfont, *curfont, *nextfont; | 246 | XftDraw *d = NULL; |
| 222 | int utf8strlen, utf8charlen, render = x || y || w || h; | 247 | Fnt *usedfont, *curfont, *nextfont; |
| 223 | long utf8codepoint = 0; | 248 | int utf8strlen, utf8charlen, render = x || y || w || h; |
| 224 | const char *utf8str; | 249 | long utf8codepoint = 0; |
| 225 | FcCharSet *fccharset; | 250 | const char *utf8str; |
| 226 | FcPattern *fcpattern; | 251 | FcCharSet *fccharset; |
| 227 | FcPattern *match; | 252 | FcPattern *fcpattern; |
| 228 | XftResult result; | 253 | FcPattern *match; |
| 229 | int charexists = 0, overflow = 0; | 254 | XftResult result; |
| 230 | /* keep track of a couple codepoints for which we have no match. */ | 255 | int charexists = 0, overflow = 0; |
| 231 | enum { nomatches_len = 64 }; | 256 | /* keep track of a couple codepoints for which we have no match. */ |
| 232 | static struct { | 257 | enum { nomatches_len = 64 }; |
| 233 | long codepoint[nomatches_len]; | 258 | static struct { |
| 234 | unsigned int idx; | 259 | long codepoint[nomatches_len]; |
| 235 | } nomatches; | 260 | unsigned int idx; |
| 236 | static unsigned int ellipsis_width = 0; | 261 | } nomatches; |
| 237 | 262 | static unsigned int ellipsis_width = 0; | |
| 238 | if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts) | 263 | |
| 239 | return 0; | 264 | if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts) |
| 240 | 265 | return 0; | |
| 241 | if (!render) { | 266 | |
| 242 | w = invert ? invert : ~invert; | 267 | if (!render) { |
| 243 | } else { | 268 | w = invert ? invert : ~invert; |
| 244 | XSetForeground(drw->dpy, drw->gc, | 269 | } else { |
| 245 | drw->scheme[invert ? ColFg : ColBg].pixel); | 270 | XSetForeground(drw->dpy, drw->gc, |
| 246 | XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); | 271 | drw->scheme[invert ? ColFg : ColBg].pixel); |
| 247 | d = XftDrawCreate(drw->dpy, drw->drawable, | 272 | XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); |
| 248 | DefaultVisual(drw->dpy, drw->screen), | 273 | d = XftDrawCreate(drw->dpy, drw->drawable, |
| 249 | DefaultColormap(drw->dpy, drw->screen)); | 274 | DefaultVisual(drw->dpy, drw->screen), |
| 250 | x += lpad; | 275 | DefaultColormap(drw->dpy, drw->screen)); |
| 251 | w -= lpad; | 276 | x += lpad; |
| 252 | } | 277 | w -= lpad; |
| 253 | 278 | } | |
| 254 | usedfont = drw->fonts; | 279 | |
| 255 | if (!ellipsis_width && render) | 280 | usedfont = drw->fonts; |
| 256 | ellipsis_width = drw_fontset_getwidth(drw, "..."); | 281 | if (!ellipsis_width && render) |
| 257 | while (1) { | 282 | ellipsis_width = drw_fontset_getwidth(drw, "..."); |
| 258 | ew = ellipsis_len = utf8strlen = 0; | 283 | while (1) { |
| 259 | utf8str = text; | 284 | ew = ellipsis_len = utf8strlen = 0; |
| 260 | nextfont = NULL; | 285 | utf8str = text; |
| 261 | while (*text) { | 286 | nextfont = NULL; |
| 262 | utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); | 287 | while (*text) { |
| 263 | for (curfont = drw->fonts; curfont; curfont = curfont->next) { | 288 | utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); |
| 264 | charexists = charexists || | 289 | for (curfont = drw->fonts; curfont; |
| 265 | XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); | 290 | curfont = curfont->next) { |
| 266 | if (charexists) { | 291 | charexists = |
| 267 | drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL); | 292 | charexists || |
| 268 | if (ew + ellipsis_width <= w) { | 293 | XftCharExists(drw->dpy, curfont->xfont, |
| 269 | /* keep track where the ellipsis still fits */ | 294 | utf8codepoint); |
| 270 | ellipsis_x = x + ew; | 295 | if (charexists) { |
| 271 | ellipsis_w = w - ew; | 296 | drw_font_getexts(curfont, text, |
| 272 | ellipsis_len = utf8strlen; | 297 | utf8charlen, &tmpw, |
| 273 | } | 298 | NULL); |
| 274 | 299 | if (ew + ellipsis_width <= w) { | |
| 275 | if (ew + tmpw > w) { | 300 | /* keep track where the ellipsis |
| 276 | overflow = 1; | 301 | * still fits */ |
| 277 | /* called from drw_fontset_getwidth_clamp(): | 302 | ellipsis_x = x + ew; |
| 278 | * it wants the width AFTER the overflow | 303 | ellipsis_w = w - ew; |
| 279 | */ | 304 | ellipsis_len = utf8strlen; |
| 280 | if (!render) | 305 | } |
| 281 | x += tmpw; | 306 | |
| 282 | else | 307 | if (ew + tmpw > w) { |
| 283 | utf8strlen = ellipsis_len; | 308 | overflow = 1; |
| 284 | } else if (curfont == usedfont) { | 309 | /* called from |
| 285 | utf8strlen += utf8charlen; | 310 | * drw_fontset_getwidth_clamp(): |
| 286 | text += utf8charlen; | 311 | * it wants the width AFTER the |
| 287 | ew += tmpw; | 312 | * overflow |
| 288 | } else { | 313 | */ |
| 289 | nextfont = curfont; | 314 | if (!render) |
| 290 | } | 315 | x += tmpw; |
| 291 | break; | 316 | else |
| 292 | } | 317 | utf8strlen = |
| 293 | } | 318 | ellipsis_len; |
| 294 | 319 | } else if (curfont == usedfont) { | |
| 295 | if (overflow || !charexists || nextfont) | 320 | utf8strlen += utf8charlen; |
| 296 | break; | 321 | text += utf8charlen; |
| 297 | else | 322 | ew += tmpw; |
| 298 | charexists = 0; | 323 | } else { |
| 299 | } | 324 | nextfont = curfont; |
| 300 | 325 | } | |
| 301 | if (utf8strlen) { | 326 | break; |
| 302 | if (render) { | 327 | } |
| 303 | ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; | 328 | } |
| 304 | XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], | 329 | |
| 305 | usedfont->xfont, x, ty, (XftChar8 *)utf8str, | 330 | if (overflow || !charexists || nextfont) |
| 306 | utf8strlen); | 331 | break; |
| 307 | } | 332 | else |
| 308 | x += ew; | 333 | charexists = 0; |
| 309 | w -= ew; | 334 | } |
| 310 | } | 335 | |
| 311 | if (render && overflow) | 336 | if (utf8strlen) { |
| 312 | drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert); | 337 | if (render) { |
| 313 | 338 | ty = y + (h - usedfont->h) / 2 + | |
| 314 | if (!*text || overflow) { | 339 | usedfont->xfont->ascent; |
| 315 | break; | 340 | XftDrawStringUtf8( |
| 316 | } else if (nextfont) { | 341 | d, &drw->scheme[invert ? ColBg : ColFg], |
| 317 | charexists = 0; | 342 | usedfont->xfont, x, ty, (XftChar8 *)utf8str, |
| 318 | usedfont = nextfont; | 343 | utf8strlen); |
| 319 | } else { | 344 | } |
| 320 | /* Regardless of whether or not a fallback font is found, the | 345 | x += ew; |
| 321 | * character must be drawn. */ | 346 | w -= ew; |
| 322 | charexists = 1; | 347 | } |
| 323 | 348 | if (render && overflow) | |
| 324 | for (i = 0; i < nomatches_len; ++i) { | 349 | drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", |
| 325 | /* avoid calling XftFontMatch if we know we won't find a match */ | 350 | invert); |
| 326 | if (utf8codepoint == nomatches.codepoint[i]) | 351 | |
| 327 | goto no_match; | 352 | if (!*text || overflow) { |
| 328 | } | 353 | break; |
| 329 | 354 | } else if (nextfont) { | |
| 330 | fccharset = FcCharSetCreate(); | 355 | charexists = 0; |
| 331 | FcCharSetAddChar(fccharset, utf8codepoint); | 356 | usedfont = nextfont; |
| 332 | 357 | } else { | |
| 333 | if (!drw->fonts->pattern) { | 358 | /* Regardless of whether or not a fallback font is |
| 334 | /* Refer to the comment in xfont_create for more information. */ | 359 | * found, the character must be drawn. */ |
| 335 | die("the first font in the cache must be loaded from a font string."); | 360 | charexists = 1; |
| 336 | } | 361 | |
| 337 | 362 | for (i = 0; i < nomatches_len; ++i) { | |
| 338 | fcpattern = FcPatternDuplicate(drw->fonts->pattern); | 363 | /* avoid calling XftFontMatch if we know we |
| 339 | FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); | 364 | * won't find a match */ |
| 340 | FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); | 365 | if (utf8codepoint == nomatches.codepoint[i]) |
| 341 | 366 | goto no_match; | |
| 342 | FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); | 367 | } |
| 343 | FcDefaultSubstitute(fcpattern); | 368 | |
| 344 | match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result); | 369 | fccharset = FcCharSetCreate(); |
| 345 | 370 | FcCharSetAddChar(fccharset, utf8codepoint); | |
| 346 | FcCharSetDestroy(fccharset); | 371 | |
| 347 | FcPatternDestroy(fcpattern); | 372 | if (!drw->fonts->pattern) { |
| 348 | 373 | /* Refer to the comment in xfont_create for more | |
| 349 | if (match) { | 374 | * information. */ |
| 350 | usedfont = xfont_create(drw, NULL, match); | 375 | die("the first font in the cache must be " |
| 351 | if (usedfont && | 376 | "loaded from a font string."); |
| 352 | XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) { | 377 | } |
| 353 | for (curfont = drw->fonts; curfont->next; curfont = curfont->next) | 378 | |
| 354 | ; /* NOP */ | 379 | fcpattern = FcPatternDuplicate(drw->fonts->pattern); |
| 355 | curfont->next = usedfont; | 380 | FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); |
| 356 | } else { | 381 | FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); |
| 357 | xfont_free(usedfont); | 382 | |
| 358 | nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint; | 383 | FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); |
| 359 | no_match: | 384 | FcDefaultSubstitute(fcpattern); |
| 360 | usedfont = drw->fonts; | 385 | match = XftFontMatch(drw->dpy, drw->screen, fcpattern, |
| 361 | } | 386 | &result); |
| 362 | } | 387 | |
| 363 | } | 388 | FcCharSetDestroy(fccharset); |
| 364 | } | 389 | FcPatternDestroy(fcpattern); |
| 365 | if (d) | 390 | |
| 366 | XftDrawDestroy(d); | 391 | if (match) { |
| 367 | 392 | usedfont = xfont_create(drw, NULL, match); | |
| 368 | return x + (render ? w : 0); | 393 | if (usedfont && |
| 394 | XftCharExists(drw->dpy, usedfont->xfont, | ||
| 395 | utf8codepoint)) { | ||
| 396 | for (curfont = drw->fonts; | ||
| 397 | curfont->next; | ||
| 398 | curfont = curfont->next) | ||
| 399 | ; /* NOP */ | ||
| 400 | curfont->next = usedfont; | ||
| 401 | } else { | ||
| 402 | xfont_free(usedfont); | ||
| 403 | nomatches.codepoint[++nomatches.idx % | ||
| 404 | nomatches_len] = | ||
| 405 | utf8codepoint; | ||
| 406 | no_match: | ||
| 407 | usedfont = drw->fonts; | ||
| 408 | } | ||
| 409 | } | ||
| 410 | } | ||
| 411 | } | ||
| 412 | if (d) | ||
| 413 | XftDrawDestroy(d); | ||
| 414 | |||
| 415 | return x + (render ? w : 0); | ||
| 369 | } | 416 | } |
| 370 | 417 | ||
| 371 | void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, | 418 | void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) |
| 372 | unsigned int h) { | 419 | { |
| 373 | if (!drw) | 420 | if (!drw) |
| 374 | return; | 421 | return; |
| 375 | 422 | ||
| 376 | XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); | 423 | XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); |
| 377 | XSync(drw->dpy, False); | 424 | XSync(drw->dpy, False); |
| 378 | } | 425 | } |
| 379 | 426 | ||
| 380 | unsigned int drw_fontset_getwidth(Drw *drw, const char *text) { | 427 | unsigned int drw_fontset_getwidth(Drw *drw, const char *text) |
| 381 | if (!drw || !drw->fonts || !text) | 428 | { |
| 382 | return 0; | 429 | if (!drw || !drw->fonts || !text) |
| 383 | return drw_text(drw, 0, 0, 0, 0, 0, text, 0); | 430 | return 0; |
| 431 | return drw_text(drw, 0, 0, 0, 0, 0, text, 0); | ||
| 384 | } | 432 | } |
| 385 | 433 | ||
| 386 | unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, | 434 | unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, |
| 387 | unsigned int n) { | 435 | unsigned int n) |
| 388 | unsigned int tmp = 0; | 436 | { |
| 389 | if (drw && drw->fonts && text && n) | 437 | unsigned int tmp = 0; |
| 390 | tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n); | 438 | if (drw && drw->fonts && text && n) |
| 391 | return MIN(n, tmp); | 439 | tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n); |
| 440 | return MIN(n, tmp); | ||
| 392 | } | 441 | } |
| 393 | 442 | ||
| 394 | void drw_font_getexts(Fnt *font, const char *text, unsigned int len, | 443 | void drw_font_getexts(Fnt *font, const char *text, unsigned int len, |
| 395 | unsigned int *w, unsigned int *h) { | 444 | unsigned int *w, unsigned int *h) |
| 396 | XGlyphInfo ext; | 445 | { |
| 397 | 446 | XGlyphInfo ext; | |
| 398 | if (!font || !text) | 447 | |
| 399 | return; | 448 | if (!font || !text) |
| 400 | 449 | return; | |
| 401 | XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext); | 450 | |
| 402 | if (w) | 451 | XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext); |
| 403 | *w = ext.xOff; | 452 | if (w) |
| 404 | if (h) | 453 | *w = ext.xOff; |
| 405 | *h = font->h; | 454 | if (h) |
| 455 | *h = font->h; | ||
| 406 | } | 456 | } |
| 407 | 457 | ||
| 408 | Cur *drw_cur_create(Drw *drw, int shape) { | 458 | Cur *drw_cur_create(Drw *drw, int shape) |
| 409 | Cur *cur; | 459 | { |
| 460 | Cur *cur; | ||
| 410 | 461 | ||
| 411 | if (!drw || !(cur = ecalloc(1, sizeof(Cur)))) | 462 | if (!drw || !(cur = ecalloc(1, sizeof(Cur)))) |
| 412 | return NULL; | 463 | return NULL; |
| 413 | 464 | ||
| 414 | cur->cursor = XCreateFontCursor(drw->dpy, shape); | 465 | cur->cursor = XCreateFontCursor(drw->dpy, shape); |
| 415 | 466 | ||
| 416 | return cur; | 467 | return cur; |
| 417 | } | 468 | } |
| 418 | 469 | ||
| 419 | void drw_cur_free(Drw *drw, Cur *cursor) { | 470 | void drw_cur_free(Drw *drw, Cur *cursor) |
| 420 | if (!cursor) | 471 | { |
| 421 | return; | 472 | if (!cursor) |
| 473 | return; | ||
| 422 | 474 | ||
| 423 | XFreeCursor(drw->dpy, cursor->cursor); | 475 | XFreeCursor(drw->dpy, cursor->cursor); |
| 424 | free(cursor); | 476 | free(cursor); |
| 425 | } | 477 | } |
diff --git a/src/drw/drw.h b/src/drw/drw.h index e645d43..88308ab 100644 --- a/src/drw/drw.h +++ b/src/drw/drw.h | |||
| @@ -1,29 +1,29 @@ | |||
| 1 | /* See LICENSE file for copyright and license details. */ | 1 | /* See LICENSE file for copyright and license details. */ |
| 2 | 2 | ||
| 3 | typedef struct { | 3 | typedef struct { |
| 4 | Cursor cursor; | 4 | Cursor cursor; |
| 5 | } Cur; | 5 | } Cur; |
| 6 | 6 | ||
| 7 | typedef struct Fnt { | 7 | typedef struct Fnt { |
| 8 | Display *dpy; | 8 | Display *dpy; |
| 9 | unsigned int h; | 9 | unsigned int h; |
| 10 | XftFont *xfont; | 10 | XftFont *xfont; |
| 11 | FcPattern *pattern; | 11 | FcPattern *pattern; |
| 12 | struct Fnt *next; | 12 | struct Fnt *next; |
| 13 | } Fnt; | 13 | } Fnt; |
| 14 | 14 | ||
| 15 | enum { ColFg, ColBg, ColBorder }; /* Clr scheme index */ | 15 | enum { ColFg, ColBg, ColBorder }; /* Clr scheme index */ |
| 16 | typedef XftColor Clr; | 16 | typedef XftColor Clr; |
| 17 | 17 | ||
| 18 | typedef struct { | 18 | typedef struct { |
| 19 | unsigned int w, h; | 19 | unsigned int w, h; |
| 20 | Display *dpy; | 20 | Display *dpy; |
| 21 | int screen; | 21 | int screen; |
| 22 | Window root; | 22 | Window root; |
| 23 | Drawable drawable; | 23 | Drawable drawable; |
| 24 | GC gc; | 24 | GC gc; |
| 25 | Clr *scheme; | 25 | Clr *scheme; |
| 26 | Fnt *fonts; | 26 | Fnt *fonts; |
| 27 | } Drw; | 27 | } Drw; |
| 28 | 28 | ||
| 29 | /* Drawable abstraction */ | 29 | /* Drawable abstraction */ |
