diff options
-rw-r--r-- | config.def.h | 12 | ||||
-rw-r--r-- | dmenu.c | 147 | ||||
-rw-r--r-- | drw.c | 241 | ||||
-rw-r--r-- | drw.h | 63 | ||||
-rw-r--r-- | util.h | 4 |
5 files changed, 231 insertions, 236 deletions
diff --git a/config.def.h b/config.def.h index dcffd38..5ac2af8 100644 --- a/config.def.h +++ b/config.def.h | |||
@@ -7,12 +7,12 @@ static const char *fonts[] = { | |||
7 | "monospace:size=10" | 7 | "monospace:size=10" |
8 | }; | 8 | }; |
9 | static const char *prompt = NULL; /* -p option; prompt to the left of input field */ | 9 | static const char *prompt = NULL; /* -p option; prompt to the left of input field */ |
10 | static const char *normbgcolor = "#222222"; /* -nb option; normal background */ | 10 | static const char *colors[][2] = { |
11 | static const char *normfgcolor = "#bbbbbb"; /* -nf option; normal foreground */ | 11 | /* fg bg */ |
12 | static const char *selbgcolor = "#005577"; /* -sb option; selected background */ | 12 | { "#bbbbbb", "#222222" }, /* normal */ |
13 | static const char *selfgcolor = "#eeeeee"; /* -sf option; selected foreground */ | 13 | { "#eeeeee", "#005577" }, /* selected */ |
14 | static const char *outbgcolor = "#00ffff"; | 14 | { "#000000", "#00ffff" }, /* out */ |
15 | static const char *outfgcolor = "#000000"; | 15 | }; |
16 | /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ | 16 | /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ |
17 | static unsigned int lines = 0; | 17 | static unsigned int lines = 0; |
18 | 18 | ||
@@ -22,8 +22,7 @@ | |||
22 | #define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \ | 22 | #define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \ |
23 | * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org))) | 23 | * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org))) |
24 | #define LENGTH(X) (sizeof X / sizeof X[0]) | 24 | #define LENGTH(X) (sizeof X / sizeof X[0]) |
25 | #define TEXTNW(X,N) (drw_font_getexts_width(drw->fonts[0], (X), (N))) | 25 | #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) |
26 | #define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h) | ||
27 | 26 | ||
28 | /* enums */ | 27 | /* enums */ |
29 | enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */ | 28 | enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */ |
@@ -37,7 +36,8 @@ struct item { | |||
37 | static char text[BUFSIZ] = ""; | 36 | static char text[BUFSIZ] = ""; |
38 | static int bh, mw, mh; | 37 | static int bh, mw, mh; |
39 | static int sw, sh; /* X display screen geometry width, height */ | 38 | static int sw, sh; /* X display screen geometry width, height */ |
40 | static int inputw, promptw; | 39 | static int inputw = 0, promptw; |
40 | static int lrpad; /* sum of left and right padding */ | ||
41 | static size_t cursor; | 41 | static size_t cursor; |
42 | static struct item *items = NULL; | 42 | static struct item *items = NULL; |
43 | static struct item *matches, *matchend; | 43 | static struct item *matches, *matchend; |
@@ -49,8 +49,8 @@ static Display *dpy; | |||
49 | static Window root, win; | 49 | static Window root, win; |
50 | static XIC xic; | 50 | static XIC xic; |
51 | 51 | ||
52 | static ClrScheme scheme[SchemeLast]; | ||
53 | static Drw *drw; | 52 | static Drw *drw; |
53 | static Clr *scheme[SchemeLast]; | ||
54 | 54 | ||
55 | #include "config.h" | 55 | #include "config.h" |
56 | 56 | ||
@@ -81,10 +81,10 @@ calcoffsets(void) | |||
81 | n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">")); | 81 | n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">")); |
82 | /* calculate which items will begin the next page and previous page */ | 82 | /* calculate which items will begin the next page and previous page */ |
83 | for (i = 0, next = curr; next; next = next->right) | 83 | for (i = 0, next = curr; next; next = next->right) |
84 | if ((i += (lines > 0) ? bh : MIN(TEXTW(next->text), n)) > n) | 84 | if ((i += (lines > 0) ? bh : TEXTW(next->text)) > n) |
85 | break; | 85 | break; |
86 | for (i = 0, prev = curr; prev && prev->left; prev = prev->left) | 86 | for (i = 0, prev = curr; prev && prev->left; prev = prev->left) |
87 | if ((i += (lines > 0) ? bh : MIN(TEXTW(prev->left->text), n)) > n) | 87 | if ((i += (lines > 0) ? bh : TEXTW(prev->left->text)) > n) |
88 | break; | 88 | break; |
89 | } | 89 | } |
90 | 90 | ||
@@ -94,10 +94,8 @@ cleanup(void) | |||
94 | size_t i; | 94 | size_t i; |
95 | 95 | ||
96 | XUngrabKey(dpy, AnyKey, AnyModifier, root); | 96 | XUngrabKey(dpy, AnyKey, AnyModifier, root); |
97 | for (i = 0; i < SchemeLast; i++) { | 97 | for (i = 0; i < SchemeLast; i++) |
98 | drw_clr_free(scheme[i].bg); | 98 | free(scheme[i]); |
99 | drw_clr_free(scheme[i].fg); | ||
100 | } | ||
101 | drw_free(drw); | 99 | drw_free(drw); |
102 | XSync(dpy, False); | 100 | XSync(dpy, False); |
103 | XCloseDisplay(dpy); | 101 | XCloseDisplay(dpy); |
@@ -114,70 +112,63 @@ cistrstr(const char *s, const char *sub) | |||
114 | return NULL; | 112 | return NULL; |
115 | } | 113 | } |
116 | 114 | ||
115 | static int | ||
116 | drawitem(struct item *item, int x, int y, int w) | ||
117 | { | ||
118 | if (item == sel) | ||
119 | drw_setscheme(drw, scheme[SchemeSel]); | ||
120 | else if (item->out) | ||
121 | drw_setscheme(drw, scheme[SchemeOut]); | ||
122 | else | ||
123 | drw_setscheme(drw, scheme[SchemeNorm]); | ||
124 | |||
125 | return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0); | ||
126 | } | ||
127 | |||
117 | static void | 128 | static void |
118 | drawmenu(void) | 129 | drawmenu(void) |
119 | { | 130 | { |
120 | int curpos; | 131 | unsigned int curpos; |
121 | struct item *item; | 132 | struct item *item; |
122 | int x = 0, y = 0, h = bh, w; | 133 | int x = 0, y = 0, w; |
123 | 134 | ||
124 | drw_setscheme(drw, &scheme[SchemeNorm]); | 135 | drw_setscheme(drw, scheme[SchemeNorm]); |
125 | drw_rect(drw, 0, 0, mw, mh, 1, 1, 1); | 136 | drw_rect(drw, 0, 0, mw, mh, 1, 1); |
126 | 137 | ||
127 | if (prompt && *prompt) { | 138 | if (prompt && *prompt) { |
128 | drw_setscheme(drw, &scheme[SchemeSel]); | 139 | drw_setscheme(drw, scheme[SchemeSel]); |
129 | drw_text(drw, x, 0, promptw, bh, prompt, 0); | 140 | x = drw_text(drw, x, 0, promptw, bh, lrpad / 2, prompt, 0); |
130 | x += promptw; | ||
131 | } | 141 | } |
132 | /* draw input field */ | 142 | /* draw input field */ |
133 | w = (lines > 0 || !matches) ? mw - x : inputw; | 143 | w = (lines > 0 || !matches) ? mw - x : inputw; |
134 | drw_setscheme(drw, &scheme[SchemeNorm]); | 144 | drw_setscheme(drw, scheme[SchemeNorm]); |
135 | drw_text(drw, x, 0, w, bh, text, 0); | 145 | drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0); |
136 | 146 | ||
137 | if ((curpos = TEXTNW(text, cursor) + bh / 2 - 2) < w) { | 147 | drw_font_getexts(drw->fonts, text, cursor, &curpos, NULL); |
138 | drw_setscheme(drw, &scheme[SchemeNorm]); | 148 | if ((curpos += lrpad / 2 - 1) < w) { |
139 | drw_rect(drw, x + curpos + 2, 2, 1, bh - 4, 1, 1, 0); | 149 | drw_setscheme(drw, scheme[SchemeNorm]); |
150 | drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0); | ||
140 | } | 151 | } |
141 | 152 | ||
142 | if (lines > 0) { | 153 | if (lines > 0) { |
143 | /* draw vertical list */ | 154 | /* draw vertical list */ |
144 | w = mw - x; | 155 | for (item = curr; item != next; item = item->right) |
145 | for (item = curr; item != next; item = item->right) { | 156 | drawitem(item, x, y += bh, mw - x); |
146 | y += h; | ||
147 | if (item == sel) | ||
148 | drw_setscheme(drw, &scheme[SchemeSel]); | ||
149 | else if (item->out) | ||
150 | drw_setscheme(drw, &scheme[SchemeOut]); | ||
151 | else | ||
152 | drw_setscheme(drw, &scheme[SchemeNorm]); | ||
153 | |||
154 | drw_text(drw, x, y, w, bh, item->text, 0); | ||
155 | } | ||
156 | } else if (matches) { | 157 | } else if (matches) { |
157 | /* draw horizontal list */ | 158 | /* draw horizontal list */ |
158 | x += inputw; | 159 | x += inputw; |
159 | w = TEXTW("<"); | 160 | w = TEXTW("<"); |
160 | if (curr->left) { | 161 | if (curr->left) { |
161 | drw_setscheme(drw, &scheme[SchemeNorm]); | 162 | drw_setscheme(drw, scheme[SchemeNorm]); |
162 | drw_text(drw, x, 0, w, bh, "<", 0); | 163 | drw_text(drw, x, 0, w, bh, lrpad / 2, "<", 0); |
163 | } | 164 | } |
164 | for (item = curr; item != next; item = item->right) { | 165 | x += w; |
165 | x += w; | 166 | for (item = curr; item != next; item = item->right) |
166 | w = MIN(TEXTW(item->text), mw - x - TEXTW(">")); | 167 | x = drawitem(item, x, 0, MIN(TEXTW(item->text), mw - x - TEXTW(">"))); |
167 | |||
168 | if (item == sel) | ||
169 | drw_setscheme(drw, &scheme[SchemeSel]); | ||
170 | else if (item->out) | ||
171 | drw_setscheme(drw, &scheme[SchemeOut]); | ||
172 | else | ||
173 | drw_setscheme(drw, &scheme[SchemeNorm]); | ||
174 | drw_text(drw, x, 0, w, bh, item->text, 0); | ||
175 | } | ||
176 | w = TEXTW(">"); | ||
177 | x = mw - w; | ||
178 | if (next) { | 168 | if (next) { |
179 | drw_setscheme(drw, &scheme[SchemeNorm]); | 169 | w = TEXTW(">"); |
180 | drw_text(drw, x, 0, w, bh, ">", 0); | 170 | drw_setscheme(drw, scheme[SchemeNorm]); |
171 | drw_text(drw, mw - w, 0, w, bh, lrpad / 2, ">", 0); | ||
181 | } | 172 | } |
182 | } | 173 | } |
183 | drw_map(drw, win, 0, 0, mw, mh); | 174 | drw_map(drw, win, 0, 0, mw, mh); |
@@ -191,8 +182,8 @@ grabkeyboard(void) | |||
191 | 182 | ||
192 | /* try to grab keyboard, we may have to wait for another process to ungrab */ | 183 | /* try to grab keyboard, we may have to wait for another process to ungrab */ |
193 | for (i = 0; i < 1000; i++) { | 184 | for (i = 0; i < 1000; i++) { |
194 | if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, | 185 | if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync, |
195 | GrabModeAsync, GrabModeAsync, CurrentTime) == GrabSuccess) | 186 | GrabModeAsync, CurrentTime) == GrabSuccess) |
196 | return; | 187 | return; |
197 | nanosleep(&ts, NULL); | 188 | nanosleep(&ts, NULL); |
198 | } | 189 | } |
@@ -314,11 +305,9 @@ keypress(XKeyEvent *ev) | |||
314 | insert(NULL, 0 - cursor); | 305 | insert(NULL, 0 - cursor); |
315 | break; | 306 | break; |
316 | case XK_w: /* delete word */ | 307 | case XK_w: /* delete word */ |
317 | while (cursor > 0 && strchr(worddelimiters, | 308 | while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)])) |
318 | text[nextrune(-1)])) | ||
319 | insert(NULL, nextrune(-1) - cursor); | 309 | insert(NULL, nextrune(-1) - cursor); |
320 | while (cursor > 0 && !strchr(worddelimiters, | 310 | while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)])) |
321 | text[nextrune(-1)])) | ||
322 | insert(NULL, nextrune(-1) - cursor); | 311 | insert(NULL, nextrune(-1) - cursor); |
323 | break; | 312 | break; |
324 | case XK_y: /* paste selection */ | 313 | case XK_y: /* paste selection */ |
@@ -469,8 +458,9 @@ paste(void) | |||
469 | static void | 458 | static void |
470 | readstdin(void) | 459 | readstdin(void) |
471 | { | 460 | { |
472 | char buf[sizeof text], *p, *maxstr = NULL; | 461 | char buf[sizeof text], *p; |
473 | size_t i, max = 0, size = 0; | 462 | size_t i, imax = 0, size = 0; |
463 | unsigned int tmpmax = 0; | ||
474 | 464 | ||
475 | /* read each line from stdin and add it to the item list */ | 465 | /* read each line from stdin and add it to the item list */ |
476 | for (i = 0; fgets(buf, sizeof buf, stdin); i++) { | 466 | for (i = 0; fgets(buf, sizeof buf, stdin); i++) { |
@@ -482,12 +472,15 @@ readstdin(void) | |||
482 | if (!(items[i].text = strdup(buf))) | 472 | if (!(items[i].text = strdup(buf))) |
483 | die("cannot strdup %u bytes:", strlen(buf) + 1); | 473 | die("cannot strdup %u bytes:", strlen(buf) + 1); |
484 | items[i].out = 0; | 474 | items[i].out = 0; |
485 | if (strlen(items[i].text) > max) | 475 | drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL); |
486 | max = strlen(maxstr = items[i].text); | 476 | if (tmpmax > inputw) { |
477 | inputw = tmpmax; | ||
478 | imax = i; | ||
479 | } | ||
487 | } | 480 | } |
488 | if (items) | 481 | if (items) |
489 | items[i].text = NULL; | 482 | items[i].text = NULL; |
490 | inputw = maxstr ? TEXTW(maxstr) : 0; | 483 | inputw = TEXTW(items[imax].text); |
491 | lines = MIN(lines, i); | 484 | lines = MIN(lines, i); |
492 | } | 485 | } |
493 | 486 | ||
@@ -534,18 +527,15 @@ setup(void) | |||
534 | #endif | 527 | #endif |
535 | 528 | ||
536 | /* init appearance */ | 529 | /* init appearance */ |
537 | scheme[SchemeNorm].bg = drw_clr_create(drw, normbgcolor); | 530 | scheme[SchemeNorm] = drw_scm_create(drw, colors[SchemeNorm], 2); |
538 | scheme[SchemeNorm].fg = drw_clr_create(drw, normfgcolor); | 531 | scheme[SchemeSel] = drw_scm_create(drw, colors[SchemeSel], 2); |
539 | scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor); | 532 | scheme[SchemeOut] = drw_scm_create(drw, colors[SchemeOut], 2); |
540 | scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor); | ||
541 | scheme[SchemeOut].bg = drw_clr_create(drw, outbgcolor); | ||
542 | scheme[SchemeOut].fg = drw_clr_create(drw, outfgcolor); | ||
543 | 533 | ||
544 | clip = XInternAtom(dpy, "CLIPBOARD", False); | 534 | clip = XInternAtom(dpy, "CLIPBOARD", False); |
545 | utf8 = XInternAtom(dpy, "UTF8_STRING", False); | 535 | utf8 = XInternAtom(dpy, "UTF8_STRING", False); |
546 | 536 | ||
547 | /* calculate menu geometry */ | 537 | /* calculate menu geometry */ |
548 | bh = drw->fonts[0]->h + 2; | 538 | bh = drw->fonts->h + 2; |
549 | lines = MAX(lines, 0); | 539 | lines = MAX(lines, 0); |
550 | mh = (lines + 1) * bh; | 540 | mh = (lines + 1) * bh; |
551 | #ifdef XINERAMA | 541 | #ifdef XINERAMA |
@@ -584,13 +574,13 @@ setup(void) | |||
584 | y = topbar ? 0 : sh - mh; | 574 | y = topbar ? 0 : sh - mh; |
585 | mw = sw; | 575 | mw = sw; |
586 | } | 576 | } |
587 | promptw = (prompt && *prompt) ? TEXTW(prompt) : 0; | 577 | promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; |
588 | inputw = MIN(inputw, mw/3); | 578 | inputw = MIN(inputw, mw/3); |
589 | match(); | 579 | match(); |
590 | 580 | ||
591 | /* create menu window */ | 581 | /* create menu window */ |
592 | swa.override_redirect = True; | 582 | swa.override_redirect = True; |
593 | swa.background_pixel = scheme[SchemeNorm].bg->pix; | 583 | swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; |
594 | swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; | 584 | swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; |
595 | win = XCreateWindow(dpy, root, x, y, mw, mh, 0, | 585 | win = XCreateWindow(dpy, root, x, y, mw, mh, 0, |
596 | DefaultDepth(dpy, screen), CopyFromParent, | 586 | DefaultDepth(dpy, screen), CopyFromParent, |
@@ -644,13 +634,13 @@ main(int argc, char *argv[]) | |||
644 | else if (!strcmp(argv[i], "-fn")) /* font or font set */ | 634 | else if (!strcmp(argv[i], "-fn")) /* font or font set */ |
645 | fonts[0] = argv[++i]; | 635 | fonts[0] = argv[++i]; |
646 | else if (!strcmp(argv[i], "-nb")) /* normal background color */ | 636 | else if (!strcmp(argv[i], "-nb")) /* normal background color */ |
647 | normbgcolor = argv[++i]; | 637 | colors[SchemeNorm][ColBg] = argv[++i]; |
648 | else if (!strcmp(argv[i], "-nf")) /* normal foreground color */ | 638 | else if (!strcmp(argv[i], "-nf")) /* normal foreground color */ |
649 | normfgcolor = argv[++i]; | 639 | colors[SchemeNorm][ColFg] = argv[++i]; |
650 | else if (!strcmp(argv[i], "-sb")) /* selected background color */ | 640 | else if (!strcmp(argv[i], "-sb")) /* selected background color */ |
651 | selbgcolor = argv[++i]; | 641 | colors[SchemeSel][ColBg] = argv[++i]; |
652 | else if (!strcmp(argv[i], "-sf")) /* selected foreground color */ | 642 | else if (!strcmp(argv[i], "-sf")) /* selected foreground color */ |
653 | selfgcolor = argv[++i]; | 643 | colors[SchemeSel][ColFg] = argv[++i]; |
654 | else | 644 | else |
655 | usage(); | 645 | usage(); |
656 | 646 | ||
@@ -663,10 +653,9 @@ main(int argc, char *argv[]) | |||
663 | sw = DisplayWidth(dpy, screen); | 653 | sw = DisplayWidth(dpy, screen); |
664 | sh = DisplayHeight(dpy, screen); | 654 | sh = DisplayHeight(dpy, screen); |
665 | drw = drw_create(dpy, screen, root, sw, sh); | 655 | drw = drw_create(dpy, screen, root, sw, sh); |
666 | drw_load_fonts(drw, fonts, LENGTH(fonts)); | 656 | if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) |
667 | if (!drw->fontcount) | ||
668 | die("no fonts could be loaded.\n"); | 657 | die("no fonts could be loaded.\n"); |
669 | drw_setscheme(drw, &scheme[SchemeNorm]); | 658 | lrpad = drw->fonts->h; |
670 | 659 | ||
671 | if (fast) { | 660 | if (fast) { |
672 | grabkeyboard(); | 661 | grabkeyboard(); |
@@ -63,9 +63,8 @@ utf8decode(const char *c, long *u, size_t clen) | |||
63 | Drw * | 63 | Drw * |
64 | drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) | 64 | drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) |
65 | { | 65 | { |
66 | Drw *drw; | 66 | Drw *drw = ecalloc(1, sizeof(Drw)); |
67 | 67 | ||
68 | drw = ecalloc(1, sizeof(Drw)); | ||
69 | drw->dpy = dpy; | 68 | drw->dpy = dpy; |
70 | drw->screen = screen; | 69 | drw->screen = screen; |
71 | drw->root = root; | 70 | drw->root = root; |
@@ -73,7 +72,6 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h | |||
73 | drw->h = h; | 72 | drw->h = h; |
74 | drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); | 73 | drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); |
75 | drw->gc = XCreateGC(dpy, root, 0, NULL); | 74 | drw->gc = XCreateGC(dpy, root, 0, NULL); |
76 | drw->fontcount = 0; | ||
77 | XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); | 75 | XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); |
78 | 76 | ||
79 | return drw; | 77 | return drw; |
@@ -82,6 +80,9 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h | |||
82 | void | 80 | void |
83 | drw_resize(Drw *drw, unsigned int w, unsigned int h) | 81 | drw_resize(Drw *drw, unsigned int w, unsigned int h) |
84 | { | 82 | { |
83 | if (!drw) | ||
84 | return; | ||
85 | |||
85 | drw->w = w; | 86 | drw->w = w; |
86 | drw->h = h; | 87 | drw->h = h; |
87 | if (drw->drawable) | 88 | if (drw->drawable) |
@@ -92,44 +93,39 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h) | |||
92 | void | 93 | void |
93 | drw_free(Drw *drw) | 94 | drw_free(Drw *drw) |
94 | { | 95 | { |
95 | size_t i; | ||
96 | |||
97 | for (i = 0; i < drw->fontcount; i++) | ||
98 | drw_font_free(drw->fonts[i]); | ||
99 | XFreePixmap(drw->dpy, drw->drawable); | 96 | XFreePixmap(drw->dpy, drw->drawable); |
100 | XFreeGC(drw->dpy, drw->gc); | 97 | XFreeGC(drw->dpy, drw->gc); |
101 | free(drw); | 98 | free(drw); |
102 | } | 99 | } |
103 | 100 | ||
104 | /* This function is an implementation detail. Library users should use | 101 | /* This function is an implementation detail. Library users should use |
105 | * drw_font_create instead. | 102 | * drw_fontset_create instead. |
106 | */ | 103 | */ |
107 | static Fnt * | 104 | static Fnt * |
108 | drw_font_xcreate(Drw *drw, const char *fontname, FcPattern *fontpattern) | 105 | xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) |
109 | { | 106 | { |
110 | Fnt *font; | 107 | Fnt *font; |
111 | XftFont *xfont = NULL; | 108 | XftFont *xfont = NULL; |
112 | FcPattern *pattern = NULL; | 109 | FcPattern *pattern = NULL; |
113 | 110 | ||
114 | if (fontname) { | 111 | if (fontname) { |
115 | /* Using the pattern found at font->xfont->pattern does not yield same | 112 | /* Using the pattern found at font->xfont->pattern does not yield the |
116 | * the same substitution results as using the pattern returned by | 113 | * same substitution results as using the pattern returned by |
117 | * FcNameParse; using the latter results in the desired fallback | 114 | * FcNameParse; using the latter results in the desired fallback |
118 | * behaviour whereas the former just results in | 115 | * behaviour whereas the former just results in missing-character |
119 | * missing-character-rectangles being drawn, at least with some fonts. | 116 | * rectangles being drawn, at least with some fonts. */ |
120 | */ | ||
121 | if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) { | 117 | if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) { |
122 | fprintf(stderr, "error, cannot load font: '%s'\n", fontname); | 118 | fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname); |
123 | return NULL; | 119 | return NULL; |
124 | } | 120 | } |
125 | if (!(pattern = FcNameParse((FcChar8 *) fontname))) { | 121 | if (!(pattern = FcNameParse((FcChar8 *) fontname))) { |
126 | fprintf(stderr, "error, cannot load font: '%s'\n", fontname); | 122 | fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname); |
127 | XftFontClose(drw->dpy, xfont); | 123 | XftFontClose(drw->dpy, xfont); |
128 | return NULL; | 124 | return NULL; |
129 | } | 125 | } |
130 | } else if (fontpattern) { | 126 | } else if (fontpattern) { |
131 | if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) { | 127 | if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) { |
132 | fprintf(stderr, "error, cannot load font pattern.\n"); | 128 | fprintf(stderr, "error, cannot load font from pattern.\n"); |
133 | return NULL; | 129 | return NULL; |
134 | } | 130 | } |
135 | } else { | 131 | } else { |
@@ -139,95 +135,115 @@ drw_font_xcreate(Drw *drw, const char *fontname, FcPattern *fontpattern) | |||
139 | font = ecalloc(1, sizeof(Fnt)); | 135 | font = ecalloc(1, sizeof(Fnt)); |
140 | font->xfont = xfont; | 136 | font->xfont = xfont; |
141 | font->pattern = pattern; | 137 | font->pattern = pattern; |
142 | font->ascent = xfont->ascent; | 138 | font->h = xfont->ascent + xfont->descent; |
143 | font->descent = xfont->descent; | ||
144 | font->h = font->ascent + font->descent; | ||
145 | font->dpy = drw->dpy; | 139 | font->dpy = drw->dpy; |
146 | 140 | ||
147 | return font; | 141 | return font; |
148 | } | 142 | } |
149 | 143 | ||
150 | Fnt* | 144 | static void |
151 | drw_font_create(Drw *drw, const char *fontname) | 145 | xfont_free(Fnt *font) |
152 | { | 146 | { |
153 | return drw_font_xcreate(drw, fontname, NULL); | 147 | if (!font) |
148 | return; | ||
149 | if (font->pattern) | ||
150 | FcPatternDestroy(font->pattern); | ||
151 | XftFontClose(font->dpy, font->xfont); | ||
152 | free(font); | ||
154 | } | 153 | } |
155 | 154 | ||
156 | void | 155 | Fnt* |
157 | drw_load_fonts(Drw* drw, const char *fonts[], size_t fontcount) | 156 | drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount) |
158 | { | 157 | { |
158 | Fnt *cur, *ret = NULL; | ||
159 | size_t i; | 159 | size_t i; |
160 | Fnt *font; | ||
161 | 160 | ||
162 | for (i = 0; i < fontcount; i++) { | 161 | if (!drw || !fonts) |
163 | if (drw->fontcount >= DRW_FONT_CACHE_SIZE) { | 162 | return NULL; |
164 | die("Font cache exhausted.\n"); | 163 | |
165 | } else if ((font = drw_font_xcreate(drw, fonts[i], NULL))) { | 164 | for (i = 1; i <= fontcount; i++) { |
166 | drw->fonts[drw->fontcount++] = font; | 165 | if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) { |
166 | cur->next = ret; | ||
167 | ret = cur; | ||
167 | } | 168 | } |
168 | } | 169 | } |
170 | return (drw->fonts = ret); | ||
169 | } | 171 | } |
170 | 172 | ||
171 | void | 173 | void |
172 | drw_font_free(Fnt *font) | 174 | drw_fontset_free(Fnt *font) |
173 | { | 175 | { |
174 | if (!font) | 176 | if (font) { |
175 | return; | 177 | drw_fontset_free(font->next); |
176 | if (font->pattern) | 178 | xfont_free(font); |
177 | FcPatternDestroy(font->pattern); | 179 | } |
178 | XftFontClose(font->dpy, font->xfont); | ||
179 | free(font); | ||
180 | } | 180 | } |
181 | 181 | ||
182 | Clr * | 182 | void |
183 | drw_clr_create(Drw *drw, const char *clrname) | 183 | drw_clr_create(Drw *drw, Clr *dest, const char *clrname) |
184 | { | 184 | { |
185 | Clr *clr; | 185 | if (!drw || !dest || !clrname) |
186 | return; | ||
186 | 187 | ||
187 | clr = ecalloc(1, sizeof(Clr)); | ||
188 | if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), | 188 | if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), |
189 | DefaultColormap(drw->dpy, drw->screen), | 189 | DefaultColormap(drw->dpy, drw->screen), |
190 | clrname, &clr->rgb)) | 190 | clrname, dest)) |
191 | die("error, cannot allocate color '%s'\n", clrname); | 191 | die("error, cannot allocate color '%s'\n", clrname); |
192 | clr->pix = clr->rgb.pixel; | 192 | } |
193 | |||
194 | /* Wrapper to create color schemes. The caller has to call free(3) on the | ||
195 | * returned color scheme when done using it. */ | ||
196 | Clr * | ||
197 | drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) | ||
198 | { | ||
199 | size_t i; | ||
200 | Clr *ret; | ||
193 | 201 | ||
194 | return clr; | 202 | /* need at least two colors for a scheme */ |
203 | if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor)))) | ||
204 | return NULL; | ||
205 | |||
206 | for (i = 0; i < clrcount; i++) | ||
207 | drw_clr_create(drw, &ret[i], clrnames[i]); | ||
208 | return ret; | ||
195 | } | 209 | } |
196 | 210 | ||
197 | void | 211 | void |
198 | drw_clr_free(Clr *clr) | 212 | drw_setfontset(Drw *drw, Fnt *set) |
199 | { | 213 | { |
200 | free(clr); | 214 | if (drw) |
215 | drw->fonts = set; | ||
201 | } | 216 | } |
202 | 217 | ||
203 | void | 218 | void |
204 | drw_setscheme(Drw *drw, ClrScheme *scheme) | 219 | drw_setscheme(Drw *drw, Clr *scm) |
205 | { | 220 | { |
206 | drw->scheme = scheme; | 221 | if (drw) |
222 | drw->scheme = scm; | ||
207 | } | 223 | } |
208 | 224 | ||
209 | void | 225 | void |
210 | drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert) | 226 | drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert) |
211 | { | 227 | { |
212 | if (!drw->scheme) | 228 | if (!drw || !drw->scheme) |
213 | return; | 229 | return; |
214 | XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->bg->pix : drw->scheme->fg->pix); | 230 | XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel); |
215 | if (filled) | 231 | if (filled) |
216 | XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w + 1, h + 1); | 232 | XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); |
217 | else if (empty) | 233 | else |
218 | XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); | 234 | XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1); |
219 | } | 235 | } |
220 | 236 | ||
221 | int | 237 | int |
222 | drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int invert) | 238 | drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert) |
223 | { | 239 | { |
224 | char buf[1024]; | 240 | char buf[1024]; |
225 | int tx, ty, th; | 241 | int ty; |
226 | Extnts tex; | 242 | unsigned int ew; |
227 | XftDraw *d = NULL; | 243 | XftDraw *d = NULL; |
228 | Fnt *curfont, *nextfont; | 244 | Fnt *usedfont, *curfont, *nextfont; |
229 | size_t i, len; | 245 | size_t i, len; |
230 | int utf8strlen, utf8charlen, render; | 246 | int utf8strlen, utf8charlen, render = x || y || w || h; |
231 | long utf8codepoint = 0; | 247 | long utf8codepoint = 0; |
232 | const char *utf8str; | 248 | const char *utf8str; |
233 | FcCharSet *fccharset; | 249 | FcCharSet *fccharset; |
@@ -236,66 +252,67 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *tex | |||
236 | XftResult result; | 252 | XftResult result; |
237 | int charexists = 0; | 253 | int charexists = 0; |
238 | 254 | ||
239 | if (!drw->scheme || !drw->fontcount) | 255 | if (!drw || (render && !drw->scheme) || !text || !drw->fonts) |
240 | return 0; | 256 | return 0; |
241 | 257 | ||
242 | if (!(render = x || y || w || h)) { | 258 | if (!render) { |
243 | w = ~w; | 259 | w = ~w; |
244 | } else { | 260 | } else { |
245 | XSetForeground(drw->dpy, drw->gc, invert ? | 261 | XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); |
246 | drw->scheme->fg->pix : drw->scheme->bg->pix); | ||
247 | XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); | 262 | XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); |
248 | d = XftDrawCreate(drw->dpy, drw->drawable, | 263 | d = XftDrawCreate(drw->dpy, drw->drawable, |
249 | DefaultVisual(drw->dpy, drw->screen), | 264 | DefaultVisual(drw->dpy, drw->screen), |
250 | DefaultColormap(drw->dpy, drw->screen)); | 265 | DefaultColormap(drw->dpy, drw->screen)); |
266 | x += lpad; | ||
267 | w -= lpad; | ||
251 | } | 268 | } |
252 | 269 | ||
253 | curfont = drw->fonts[0]; | 270 | usedfont = drw->fonts; |
254 | while (1) { | 271 | while (1) { |
255 | utf8strlen = 0; | 272 | utf8strlen = 0; |
256 | utf8str = text; | 273 | utf8str = text; |
257 | nextfont = NULL; | 274 | nextfont = NULL; |
258 | while (*text) { | 275 | while (*text) { |
259 | utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); | 276 | utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); |
260 | for (i = 0; i < drw->fontcount; i++) { | 277 | for (curfont = drw->fonts; curfont; curfont = curfont->next) { |
261 | charexists = charexists || XftCharExists(drw->dpy, drw->fonts[i]->xfont, utf8codepoint); | 278 | charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); |
262 | if (charexists) { | 279 | if (charexists) { |
263 | if (drw->fonts[i] == curfont) { | 280 | if (curfont == usedfont) { |
264 | utf8strlen += utf8charlen; | 281 | utf8strlen += utf8charlen; |
265 | text += utf8charlen; | 282 | text += utf8charlen; |
266 | } else { | 283 | } else { |
267 | nextfont = drw->fonts[i]; | 284 | nextfont = curfont; |
268 | } | 285 | } |
269 | break; | 286 | break; |
270 | } | 287 | } |
271 | } | 288 | } |
272 | 289 | ||
273 | if (!charexists || (nextfont && nextfont != curfont)) | 290 | if (!charexists || nextfont) |
274 | break; | 291 | break; |
275 | else | 292 | else |
276 | charexists = 0; | 293 | charexists = 0; |
277 | } | 294 | } |
278 | 295 | ||
279 | if (utf8strlen) { | 296 | if (utf8strlen) { |
280 | drw_font_getexts(curfont, utf8str, utf8strlen, &tex); | 297 | drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL); |
281 | /* shorten text if necessary */ | 298 | /* shorten text if necessary */ |
282 | for (len = MIN(utf8strlen, (sizeof buf) - 1); len && (tex.w > w - drw->fonts[0]->h || w < drw->fonts[0]->h); len--) | 299 | for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--) |
283 | drw_font_getexts(curfont, utf8str, len, &tex); | 300 | drw_font_getexts(usedfont, utf8str, len, &ew, NULL); |
284 | 301 | ||
285 | if (len) { | 302 | if (len) { |
286 | memcpy(buf, utf8str, len); | 303 | memcpy(buf, utf8str, len); |
287 | buf[len] = '\0'; | 304 | buf[len] = '\0'; |
288 | if (len < utf8strlen) | 305 | if (len < utf8strlen) |
289 | for (i = len; i && i > len - 3; buf[--i] = '.'); | 306 | for (i = len; i && i > len - 3; buf[--i] = '.') |
307 | ; /* NOP */ | ||
290 | 308 | ||
291 | if (render) { | 309 | if (render) { |
292 | th = curfont->ascent + curfont->descent; | 310 | ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; |
293 | ty = y + (h / 2) - (th / 2) + curfont->ascent; | 311 | XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], |
294 | tx = x + (h / 2); | 312 | usedfont->xfont, x, ty, (XftChar8 *)buf, len); |
295 | XftDrawStringUtf8(d, invert ? &drw->scheme->bg->rgb : &drw->scheme->fg->rgb, curfont->xfont, tx, ty, (XftChar8 *)buf, len); | ||
296 | } | 313 | } |
297 | x += tex.w; | 314 | x += ew; |
298 | w -= tex.w; | 315 | w -= ew; |
299 | } | 316 | } |
300 | } | 317 | } |
301 | 318 | ||
@@ -303,26 +320,21 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *tex | |||
303 | break; | 320 | break; |
304 | } else if (nextfont) { | 321 | } else if (nextfont) { |
305 | charexists = 0; | 322 | charexists = 0; |
306 | curfont = nextfont; | 323 | usedfont = nextfont; |
307 | } else { | 324 | } else { |
308 | /* Regardless of whether or not a fallback font is found, the | 325 | /* Regardless of whether or not a fallback font is found, the |
309 | * character must be drawn. | 326 | * character must be drawn. */ |
310 | */ | ||
311 | charexists = 1; | 327 | charexists = 1; |
312 | 328 | ||
313 | if (drw->fontcount >= DRW_FONT_CACHE_SIZE) | ||
314 | continue; | ||
315 | |||
316 | fccharset = FcCharSetCreate(); | 329 | fccharset = FcCharSetCreate(); |
317 | FcCharSetAddChar(fccharset, utf8codepoint); | 330 | FcCharSetAddChar(fccharset, utf8codepoint); |
318 | 331 | ||
319 | if (!drw->fonts[0]->pattern) { | 332 | if (!drw->fonts->pattern) { |
320 | /* Refer to the comment in drw_font_xcreate for more | 333 | /* Refer to the comment in xfont_create for more information. */ |
321 | * information. */ | ||
322 | die("the first font in the cache must be loaded from a font string.\n"); | 334 | die("the first font in the cache must be loaded from a font string.\n"); |
323 | } | 335 | } |
324 | 336 | ||
325 | fcpattern = FcPatternDuplicate(drw->fonts[0]->pattern); | 337 | fcpattern = FcPatternDuplicate(drw->fonts->pattern); |
326 | FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); | 338 | FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); |
327 | FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); | 339 | FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); |
328 | 340 | ||
@@ -334,12 +346,14 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *tex | |||
334 | FcPatternDestroy(fcpattern); | 346 | FcPatternDestroy(fcpattern); |
335 | 347 | ||
336 | if (match) { | 348 | if (match) { |
337 | curfont = drw_font_xcreate(drw, NULL, match); | 349 | usedfont = xfont_create(drw, NULL, match); |
338 | if (curfont && XftCharExists(drw->dpy, curfont->xfont, utf8codepoint)) { | 350 | if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) { |
339 | drw->fonts[drw->fontcount++] = curfont; | 351 | for (curfont = drw->fonts; curfont->next; curfont = curfont->next) |
352 | ; /* NOP */ | ||
353 | curfont->next = usedfont; | ||
340 | } else { | 354 | } else { |
341 | drw_font_free(curfont); | 355 | xfont_free(usedfont); |
342 | curfont = drw->fonts[0]; | 356 | usedfont = drw->fonts; |
343 | } | 357 | } |
344 | } | 358 | } |
345 | } | 359 | } |
@@ -347,34 +361,40 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *tex | |||
347 | if (d) | 361 | if (d) |
348 | XftDrawDestroy(d); | 362 | XftDrawDestroy(d); |
349 | 363 | ||
350 | return x; | 364 | return x + (render ? w : 0); |
351 | } | 365 | } |
352 | 366 | ||
353 | void | 367 | void |
354 | drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) | 368 | drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) |
355 | { | 369 | { |
370 | if (!drw) | ||
371 | return; | ||
372 | |||
356 | XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); | 373 | XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); |
357 | XSync(drw->dpy, False); | 374 | XSync(drw->dpy, False); |
358 | } | 375 | } |
359 | 376 | ||
360 | void | 377 | unsigned int |
361 | drw_font_getexts(Fnt *font, const char *text, unsigned int len, Extnts *tex) | 378 | drw_fontset_getwidth(Drw *drw, const char *text) |
362 | { | 379 | { |
363 | XGlyphInfo ext; | 380 | if (!drw || !drw->fonts || !text) |
364 | 381 | return 0; | |
365 | XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext); | 382 | return drw_text(drw, 0, 0, 0, 0, 0, text, 0); |
366 | tex->h = font->h; | ||
367 | tex->w = ext.xOff; | ||
368 | } | 383 | } |
369 | 384 | ||
370 | unsigned int | 385 | void |
371 | drw_font_getexts_width(Fnt *font, const char *text, unsigned int len) | 386 | drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h) |
372 | { | 387 | { |
373 | Extnts tex; | 388 | XGlyphInfo ext; |
374 | 389 | ||
375 | drw_font_getexts(font, text, len, &tex); | 390 | if (!font || !text) |
391 | return; | ||
376 | 392 | ||
377 | return tex.w; | 393 | XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext); |
394 | if (w) | ||
395 | *w = ext.xOff; | ||
396 | if (h) | ||
397 | *h = font->h; | ||
378 | } | 398 | } |
379 | 399 | ||
380 | Cur * | 400 | Cur * |
@@ -382,7 +402,9 @@ drw_cur_create(Drw *drw, int shape) | |||
382 | { | 402 | { |
383 | Cur *cur; | 403 | Cur *cur; |
384 | 404 | ||
385 | cur = ecalloc(1, sizeof(Cur)); | 405 | if (!drw || !(cur = ecalloc(1, sizeof(Cur)))) |
406 | return NULL; | ||
407 | |||
386 | cur->cursor = XCreateFontCursor(drw->dpy, shape); | 408 | cur->cursor = XCreateFontCursor(drw->dpy, shape); |
387 | 409 | ||
388 | return cur; | 410 | return cur; |
@@ -393,6 +415,7 @@ drw_cur_free(Drw *drw, Cur *cursor) | |||
393 | { | 415 | { |
394 | if (!cursor) | 416 | if (!cursor) |
395 | return; | 417 | return; |
418 | |||
396 | XFreeCursor(drw->dpy, cursor->cursor); | 419 | XFreeCursor(drw->dpy, cursor->cursor); |
397 | free(cursor); | 420 | free(cursor); |
398 | } | 421 | } |
@@ -1,29 +1,19 @@ | |||
1 | /* See LICENSE file for copyright and license details. */ | 1 | /* See LICENSE file for copyright and license details. */ |
2 | #define DRW_FONT_CACHE_SIZE 32 | ||
3 | |||
4 | typedef struct { | ||
5 | unsigned long pix; | ||
6 | XftColor rgb; | ||
7 | } Clr; | ||
8 | 2 | ||
9 | typedef struct { | 3 | typedef struct { |
10 | Cursor cursor; | 4 | Cursor cursor; |
11 | } Cur; | 5 | } Cur; |
12 | 6 | ||
13 | typedef struct { | 7 | typedef struct Fnt { |
14 | Display *dpy; | 8 | Display *dpy; |
15 | int ascent; | ||
16 | int descent; | ||
17 | unsigned int h; | 9 | unsigned int h; |
18 | XftFont *xfont; | 10 | XftFont *xfont; |
19 | FcPattern *pattern; | 11 | FcPattern *pattern; |
12 | struct Fnt *next; | ||
20 | } Fnt; | 13 | } Fnt; |
21 | 14 | ||
22 | typedef struct { | 15 | enum { ColFg, ColBg }; /* Clr scheme index */ |
23 | Clr *fg; | 16 | typedef XftColor Clr; |
24 | Clr *bg; | ||
25 | Clr *border; | ||
26 | } ClrScheme; | ||
27 | 17 | ||
28 | typedef struct { | 18 | typedef struct { |
29 | unsigned int w, h; | 19 | unsigned int w, h; |
@@ -32,43 +22,36 @@ typedef struct { | |||
32 | Window root; | 22 | Window root; |
33 | Drawable drawable; | 23 | Drawable drawable; |
34 | GC gc; | 24 | GC gc; |
35 | ClrScheme *scheme; | 25 | Clr *scheme; |
36 | size_t fontcount; | 26 | Fnt *fonts; |
37 | Fnt *fonts[DRW_FONT_CACHE_SIZE]; | ||
38 | } Drw; | 27 | } Drw; |
39 | 28 | ||
40 | typedef struct { | ||
41 | unsigned int w; | ||
42 | unsigned int h; | ||
43 | } Extnts; | ||
44 | |||
45 | /* Drawable abstraction */ | 29 | /* Drawable abstraction */ |
46 | Drw *drw_create(Display *, int, Window, unsigned int, unsigned int); | 30 | Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h); |
47 | void drw_resize(Drw *, unsigned int, unsigned int); | 31 | void drw_resize(Drw *drw, unsigned int w, unsigned int h); |
48 | void drw_free(Drw *); | 32 | void drw_free(Drw *drw); |
49 | 33 | ||
50 | /* Fnt abstraction */ | 34 | /* Fnt abstraction */ |
51 | Fnt *drw_font_create(Drw *, const char *); | 35 | Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount); |
52 | void drw_load_fonts(Drw *, const char *[], size_t); | 36 | void drw_fontset_free(Fnt* set); |
53 | void drw_font_free(Fnt *); | 37 | unsigned int drw_fontset_getwidth(Drw *drw, const char *text); |
54 | void drw_font_getexts(Fnt *, const char *, unsigned int, Extnts *); | 38 | void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h); |
55 | unsigned int drw_font_getexts_width(Fnt *, const char *, unsigned int); | ||
56 | 39 | ||
57 | /* Colour abstraction */ | 40 | /* Colorscheme abstraction */ |
58 | Clr *drw_clr_create(Drw *, const char *); | 41 | void drw_clr_create(Drw *drw, Clr *dest, const char *clrname); |
59 | void drw_clr_free(Clr *); | 42 | Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount); |
60 | 43 | ||
61 | /* Cursor abstraction */ | 44 | /* Cursor abstraction */ |
62 | Cur *drw_cur_create(Drw *, int); | 45 | Cur *drw_cur_create(Drw *drw, int shape); |
63 | void drw_cur_free(Drw *, Cur *); | 46 | void drw_cur_free(Drw *drw, Cur *cursor); |
64 | 47 | ||
65 | /* Drawing context manipulation */ | 48 | /* Drawing context manipulation */ |
66 | void drw_setfont(Drw *, Fnt *); | 49 | void drw_setfontset(Drw *drw, Fnt *set); |
67 | void drw_setscheme(Drw *, ClrScheme *); | 50 | void drw_setscheme(Drw *drw, Clr *scm); |
68 | 51 | ||
69 | /* Drawing functions */ | 52 | /* Drawing functions */ |
70 | void drw_rect(Drw *, int, int, unsigned int, unsigned int, int, int, int); | 53 | void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert); |
71 | int drw_text(Drw *, int, int, unsigned int, unsigned int, const char *, int); | 54 | int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert); |
72 | 55 | ||
73 | /* Map functions */ | 56 | /* Map functions */ |
74 | void drw_map(Drw *, Window, int, int, unsigned int, unsigned int); | 57 | void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); |
@@ -4,5 +4,5 @@ | |||
4 | #define MIN(A, B) ((A) < (B) ? (A) : (B)) | 4 | #define MIN(A, B) ((A) < (B) ? (A) : (B)) |
5 | #define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B)) | 5 | #define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B)) |
6 | 6 | ||
7 | void die(const char *errstr, ...); | 7 | void die(const char *fmt, ...); |
8 | void *ecalloc(size_t, size_t); | 8 | void *ecalloc(size_t nmemb, size_t size); |