aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorphilw <dscr@duck.com>2024-08-11 22:18:24 +0200
committerphilw <dscr@duck.com>2024-08-11 22:18:24 +0200
commit88e4e232df671f2f268708f09613d3412756cf8c (patch)
tree13595fb4305a6a3ef7a651e50230562114fe23c3
parenta9e2d33b5fbe507406137358196f585b7a54059b (diff)
downloaddwm-88e4e232df671f2f268708f09613d3412756cf8c.tar.gz
dwm-88e4e232df671f2f268708f09613d3412756cf8c.zip
Update xf86 keybindings
-rw-r--r--config.h109
-rw-r--r--drw.c769
2 files changed, 410 insertions, 468 deletions
diff --git a/config.h b/config.h
index db44b6d..b9aa1b7 100644
--- a/config.h
+++ b/config.h
@@ -1,27 +1,21 @@
1static const unsigned int borderpx = 0; /* border pixel of windows */ 1// #include <cstddef>
2static const unsigned int snap = 32; /* snap pixel */ 2static const unsigned int borderpx = 0;
3static const unsigned int systraypinning = 3static const unsigned int snap = 32;
4 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor 4static const unsigned int systraypinning = 0;
5 X */ 5static const unsigned int systrayonleft = 0;
6static const unsigned int systrayonleft = 6static const unsigned int systrayspacing = 2;
7 0; /* 0: systray in the right corner, >0: systray on left of status text */ 7static const unsigned int gappih = 5;
8static const unsigned int systrayspacing = 2; /* systray spacing */ 8static const unsigned int gappiv = 5;
9static const int systraypinningfailfirst = 9static const unsigned int gappoh = 5;
10 1; /* 1: if pinning fails, display systray on the first monitor, False: 10static const unsigned int gappov = 5;
11 display systray on the last monitor*/ 11
12static const int showsystray = 1; /* 0 means no systray */ 12static const int showsystray = 1;
13static const unsigned int gappih = 5; /* horiz inner gap between windows */ 13static const int systraypinningfailfirst = 1;
14static const unsigned int gappiv = 5; /* vert inner gap between windows */ 14static const int smartgaps = 0;
15static const unsigned int gappoh = 15static const int swallowfloating = 1;
16 5; /* horiz outer gap between windows and screen edge */ 16static const int showbar = 0;
17static const unsigned int gappov = 17static const int topbar = 1;
18 5; /* vert outer gap between windows and screen edge */ 18
19static const int smartgaps =
20 0; /* 1 means no outer gap when there is only one window */
21static const int swallowfloating =
22 1; /* 1 means no outer gap when there is only one window */
23static const int showbar = 0; /* 0 means no bar */
24static const int topbar = 1; /* 0 means bottom bar */
25static const char *fonts[] = {"monospace:size=10"}; 19static const char *fonts[] = {"monospace:size=10"};
26static const char dmenufont[] = "monospace:size=10"; 20static const char dmenufont[] = "monospace:size=10";
27static const char col_gray1[] = "#222222"; 21static const char col_gray1[] = "#222222";
@@ -29,20 +23,19 @@ static const char col_gray2[] = "#444444";
29static const char col_gray3[] = "#bbbbbb"; 23static const char col_gray3[] = "#bbbbbb";
30static const char col_gray4[] = "#eeeeee"; 24static const char col_gray4[] = "#eeeeee";
31static const char col_cyan[] = "#005577"; 25static const char col_cyan[] = "#005577";
32static const char norm_fg[] = "#bfbfbf"; 26static const char norm_fg[] = "#ddbb88";
33static const char norm_bg[] = "#000001"; 27static const char norm_bg[] = "#000c18";
34static const char norm_border[] = "#3f3f40"; 28static const char norm_border[] = "#3f3f40";
35 29
36static const char sel_fg[] = "#bfbfbf"; 30static const char sel_fg[] = "#ddbb88";
37static const char sel_bg[] = "#5A4A63"; 31static const char sel_bg[] = "#000c18";
38static const char sel_border[] = "#bfbfbf"; 32static const char sel_border[] = "#225588";
39 33
40static const char urg_fg[] = "#bfbfbf"; 34static const char urg_fg[] = "#225588";
41static const char urg_bg[] = "#501C61"; 35static const char urg_bg[] = "#000c18";
42static const char urg_border[] = "#501C61"; 36static const char urg_border[] = "#000c18";
43 37
44static const char *colors[][3] = { 38static const char *colors[][3] = {
45 /* fg bg border */
46 [SchemeNorm] = {norm_fg, norm_bg, norm_border}, // unfocused wins 39 [SchemeNorm] = {norm_fg, norm_bg, norm_border}, // unfocused wins
47 [SchemeSel] = {sel_fg, sel_bg, sel_border}, // the focused win 40 [SchemeSel] = {sel_fg, sel_bg, sel_border}, // the focused win
48}; 41};
@@ -57,19 +50,16 @@ static const Rule rules[] = {
57 {NULL, NULL, "Event Tester", 0, 0, 0, 1, -1}, /* xev */ 50 {NULL, NULL, "Event Tester", 0, 0, 0, 1, -1}, /* xev */
58}; 51};
59 52
60/* layout(s) */ 53static const float mfact = 0.50;
61static const float mfact = 0.50; /* factor of master area size [0.05..0.95] */ 54static const int nmaster = 1;
62static const int nmaster = 1; /* number of clients in master area */ 55static const int resizehints = 0;
63static const int resizehints = 56static const int lockfullscreen = 1;
64 0; /* 1 means respect size hints in tiled resizals */
65static const int lockfullscreen =
66 1; /* 1 will force focus on the fullscreen window */
67 57
68static const Layout layouts[] = { 58static const Layout layouts[] = {
69 /* symbol arrange function */ 59 /* symbol arrange function */
70 {"[]=", tile}, /* first entry is default */ 60 {"[]=", tile}, /* first entry is default */
71 {"><>", NULL}, /* no layout function means floating behavior */ 61 {"><>", NULL}, /* no layout function means floating behavior */
72 {"[M]", monocle}, 62 // {"[M]", monocle},
73}; 63};
74 64
75/* key definitions */ 65/* key definitions */
@@ -80,19 +70,10 @@ static const Layout layouts[] = {
80 {MODKEY | ShiftMask, KEY, tag, {.ui = 1 << TAG}}, \ 70 {MODKEY | ShiftMask, KEY, tag, {.ui = 1 << TAG}}, \
81 {MODKEY | ControlMask | ShiftMask, KEY, toggletag, {.ui = 1 << TAG}}, 71 {MODKEY | ControlMask | ShiftMask, KEY, toggletag, {.ui = 1 << TAG}},
82 72
83/* helper for spawning shell commands in the pre dwm-5.0 fashion */
84#define SHCMD(cmd) \
85 { \
86 .v = (const char *[]) { "/bin/sh", "-c", cmd, NULL } \
87 }
88
89/* commands */ 73/* commands */
90static char dmenumon[2] = 74static char dmenumon[2] = "0";
91 "0"; /* component of dmenucmd, manipulated in spawn() */ 75
92// static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", 76static const char *dmenucmd[] = {"dmenucmd.sh", NULL};
93// dmenufont, "-nb", norm_bg, "-nf", norm_fg, "-sb", sel_bg, "-sf", sel_fg, NULL
94// };
95static const char *dmenucmd[] = {"dmenu_run", "-m", dmenumon, NULL};
96static const char *termcmd[] = {"st", NULL}; 77static const char *termcmd[] = {"st", NULL};
97static const char *screenshotcmd[] = {"screenshotsel.sh", NULL}; 78static const char *screenshotcmd[] = {"screenshotsel.sh", NULL};
98 79
@@ -110,18 +91,26 @@ static const Key keys[] = {
110 TAGKEYS(XK_5, 4) TAGKEYS(XK_6, 5) TAGKEYS(XK_7, 6) TAGKEYS(XK_8, 7) 91 TAGKEYS(XK_5, 4) TAGKEYS(XK_6, 5) TAGKEYS(XK_7, 6) TAGKEYS(XK_8, 7)
111 TAGKEYS(XK_9, 8){MODKEY | ShiftMask, XK_q, quit, {0}}, 92 TAGKEYS(XK_9, 8){MODKEY | ShiftMask, XK_q, quit, {0}},
112 {0, 93 {0,
113 XF86XK_MonBrightnessUp, 94 XF86XK_AudioMute,
95 spawn,
96 {.v = (const char *[]){"wpctl", "set-mute", "@DEFAULT_AUDIO_SINK@",
97 "toggle"}}},
98 {0,
99 XF86XK_AudioMicMute,
100 spawn,
101 {.v = (const char *[]){"wpctl", "set-mute", "54", "toggle"}}},
102 {0,
103 XF86XK_AudioRaiseVolume,
114 spawn, 104 spawn,
115 {.v = (const char *[]){"xbacklight", "-inc", "15", NULL}}}, 105 {.v = (const char *[]){"wpctl", "set-volume", "@DEFAULT_AUDIO_SINK@",
106 "10%+"}}},
116 {0, 107 {0,
117 XF86XK_MonBrightnessDown, 108 XF86XK_AudioLowerVolume,
118 spawn, 109 spawn,
119 {.v = (const char *[]){"xbacklight", "-dec", "15", NULL}}}, 110 {.v = (const char *[]){"wpctl", "set-volume", "@DEFAULT_AUDIO_SINK@",
111 "10%-"}}},
120}; 112};
121 113
122/* button definitions */
123/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
124 * ClkClientWin, or ClkRootWin */
125static const Button buttons[] = { 114static const Button buttons[] = {
126 /* click event mask button function argument */ 115 /* click event mask button function argument */
127 {ClkLtSymbol, 0, Button1, setlayout, {0}}, 116 {ClkLtSymbol, 0, Button1, setlayout, {0}},
diff --git a/drw.c b/drw.c
index 7d7b41b..8f53beb 100644
--- a/drw.c
+++ b/drw.c
@@ -1,472 +1,425 @@
1/* See LICENSE file for copyright and license details. */ 1/* See LICENSE file for copyright and license details. */
2#include <X11/Xft/Xft.h>
3#include <X11/Xlib.h>
2#include <stdio.h> 4#include <stdio.h>
3#include <stdlib.h> 5#include <stdlib.h>
4#include <string.h> 6#include <string.h>
5#include <X11/Xlib.h>
6#include <X11/Xft/Xft.h>
7 7
8#include "drw.h" 8#include "drw.h"
9#include "util.h" 9#include "util.h"
10 10
11#define UTF_INVALID 0xFFFD 11#define UTF_INVALID 0xFFFD
12#define UTF_SIZ 4 12#define UTF_SIZ 4
13 13
14static const unsigned char utfbyte[UTF_SIZ + 1] = { 0x80, 0, 0xC0, 0xE0, 0xF0 }; 14static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
15static const unsigned char utfmask[UTF_SIZ + 1] = 15static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0,
16 { 0xC0, 0x80, 0xE0, 0xF0, 0xF8 }; 16 0xF8};
17static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000 }; 17static const long utfmin[UTF_SIZ + 1] = {0, 0, 0x80, 0x800, 0x10000};
18static const long utfmax[UTF_SIZ + 1] = 18static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF,
19 { 0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF }; 19 0x10FFFF};
20 20
21static long utf8decodebyte(const char c, size_t *i) 21static long utf8decodebyte(const char c, size_t *i) {
22{ 22 for (*i = 0; *i < (UTF_SIZ + 1); ++(*i))
23 for (*i = 0; *i < (UTF_SIZ + 1); ++(*i)) 23 if (((unsigned char)c & utfmask[*i]) == utfbyte[*i])
24 if (((unsigned char)c & utfmask[*i]) == utfbyte[*i]) 24 return (unsigned char)c & ~utfmask[*i];
25 return (unsigned char)c & ~utfmask[*i]; 25 return 0;
26 return 0;
27} 26}
28 27
29static size_t utf8validate(long *u, size_t i) 28static size_t utf8validate(long *u, size_t i) {
30{ 29 if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
31 if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) 30 *u = UTF_INVALID;
32 *u = UTF_INVALID; 31 for (i = 1; *u > utfmax[i]; ++i)
33 for (i = 1; *u > utfmax[i]; ++i) ; 32 ;
34 return i; 33 return i;
35} 34}
36 35
37static size_t utf8decode(const char *c, long *u, size_t clen) 36static size_t utf8decode(const char *c, long *u, size_t clen) {
38{ 37 size_t i, j, len, type;
39 size_t i, j, len, type; 38 long udecoded;
40 long udecoded; 39
41 40 *u = UTF_INVALID;
42 *u = UTF_INVALID; 41 if (!clen)
43 if (!clen) 42 return 0;
44 return 0; 43 udecoded = utf8decodebyte(c[0], &len);
45 udecoded = utf8decodebyte(c[0], &len); 44 if (!BETWEEN(len, 1, UTF_SIZ))
46 if (!BETWEEN(len, 1, UTF_SIZ)) 45 return 1;
47 return 1; 46 for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
48 for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { 47 udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
49 udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); 48 if (type)
50 if (type) 49 return j;
51 return j; 50 }
52 } 51 if (j < len)
53 if (j < len) 52 return 0;
54 return 0; 53 *u = udecoded;
55 *u = udecoded; 54 utf8validate(u, len);
56 utf8validate(u, len); 55
57 56 return len;
58 return len;
59} 57}
60 58
61Drw *drw_create(Display *dpy, int screen, Window root, unsigned int w, 59Drw *drw_create(Display *dpy, int screen, Window root, unsigned int w,
62 unsigned int h) 60 unsigned int h) {
63{ 61 Drw *drw = ecalloc(1, sizeof(Drw));
64 Drw *drw = ecalloc(1, sizeof(Drw)); 62
65 63 drw->dpy = dpy;
66 drw->dpy = dpy; 64 drw->screen = screen;
67 drw->screen = screen; 65 drw->root = root;
68 drw->root = root; 66 drw->w = w;
69 drw->w = w; 67 drw->h = h;
70 drw->h = h; 68 drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
71 drw->drawable = 69 drw->gc = XCreateGC(dpy, root, 0, NULL);
72 XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); 70 XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
73 drw->gc = XCreateGC(dpy, root, 0, NULL); 71
74 XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); 72 return drw;
75
76 return drw;
77} 73}
78 74
79void drw_resize(Drw *drw, unsigned int w, unsigned int h) 75void drw_resize(Drw *drw, unsigned int w, unsigned int h) {
80{ 76 if (!drw)
81 if (!drw) 77 return;
82 return; 78
83 79 drw->w = w;
84 drw->w = w; 80 drw->h = h;
85 drw->h = h; 81 if (drw->drawable)
86 if (drw->drawable) 82 XFreePixmap(drw->dpy, drw->drawable);
87 XFreePixmap(drw->dpy, drw->drawable); 83 drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h,
88 drw->drawable = 84 DefaultDepth(drw->dpy, drw->screen));
89 XCreatePixmap(drw->dpy, drw->root, w, h,
90 DefaultDepth(drw->dpy, drw->screen));
91} 85}
92 86
93void drw_free(Drw *drw) 87void drw_free(Drw *drw) {
94{ 88 XFreePixmap(drw->dpy, drw->drawable);
95 XFreePixmap(drw->dpy, drw->drawable); 89 XFreeGC(drw->dpy, drw->gc);
96 XFreeGC(drw->dpy, drw->gc); 90 drw_fontset_free(drw->fonts);
97 drw_fontset_free(drw->fonts); 91 free(drw);
98 free(drw);
99} 92}
100 93
101/* This function is an implementation detail. Library users should use 94/* This function is an implementation detail. Library users should use
102 * drw_fontset_create instead. 95 * drw_fontset_create instead.
103 */ 96 */
104static Fnt *xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) 97static Fnt *xfont_create(Drw *drw, const char *fontname,
105{ 98 FcPattern *fontpattern) {
106 Fnt *font; 99 Fnt *font;
107 XftFont *xfont = NULL; 100 XftFont *xfont = NULL;
108 FcPattern *pattern = NULL; 101 FcPattern *pattern = NULL;
109 102
110 if (fontname) { 103 if (fontname) {
111 /* Using the pattern found at font->xfont->pattern does not yield the 104 /* Using the pattern found at font->xfont->pattern does not yield the
112 * same substitution results as using the pattern returned by 105 * same substitution results as using the pattern returned by
113 * FcNameParse; using the latter results in the desired fallback 106 * FcNameParse; using the latter results in the desired fallback
114 * behaviour whereas the former just results in missing-character 107 * behaviour whereas the former just results in missing-character
115 * rectangles being drawn, at least with some fonts. */ 108 * rectangles being drawn, at least with some fonts. */
116 if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) { 109 if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) {
117 fprintf(stderr, 110 fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname);
118 "error, cannot load font from name: '%s'\n", 111 return NULL;
119 fontname); 112 }
120 return NULL; 113 if (!(pattern = FcNameParse((FcChar8 *)fontname))) {
121 } 114 fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n",
122 if (!(pattern = FcNameParse((FcChar8 *) fontname))) { 115 fontname);
123 fprintf(stderr, 116 XftFontClose(drw->dpy, xfont);
124 "error, cannot parse font name to pattern: '%s'\n", 117 return NULL;
125 fontname); 118 }
126 XftFontClose(drw->dpy, xfont); 119 } else if (fontpattern) {
127 return NULL; 120 if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
128 } 121 fprintf(stderr, "error, cannot load font from pattern.\n");
129 } else if (fontpattern) { 122 return NULL;
130 if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) { 123 }
131 fprintf(stderr, 124 } else {
132 "error, cannot load font from pattern.\n"); 125 die("no font specified.");
133 return NULL; 126 }
134 } 127
135 } else { 128 font = ecalloc(1, sizeof(Fnt));
136 die("no font specified."); 129 font->xfont = xfont;
137 } 130 font->pattern = pattern;
138 131 font->h = xfont->ascent + xfont->descent;
139 font = ecalloc(1, sizeof(Fnt)); 132 font->dpy = drw->dpy;
140 font->xfont = xfont; 133
141 font->pattern = pattern; 134 return font;
142 font->h = xfont->ascent + xfont->descent;
143 font->dpy = drw->dpy;
144
145 return font;
146} 135}
147 136
148static void xfont_free(Fnt *font) 137static void xfont_free(Fnt *font) {
149{ 138 if (!font)
150 if (!font) 139 return;
151 return; 140 if (font->pattern)
152 if (font->pattern) 141 FcPatternDestroy(font->pattern);
153 FcPatternDestroy(font->pattern); 142 XftFontClose(font->dpy, font->xfont);
154 XftFontClose(font->dpy, font->xfont); 143 free(font);
155 free(font);
156} 144}
157 145
158Fnt *drw_fontset_create(Drw *drw, const char *fonts[], size_t fontcount) 146Fnt *drw_fontset_create(Drw *drw, const char *fonts[], size_t fontcount) {
159{ 147 Fnt *cur, *ret = NULL;
160 Fnt *cur, *ret = NULL; 148 size_t i;
161 size_t i; 149
162 150 if (!drw || !fonts)
163 if (!drw || !fonts) 151 return NULL;
164 return NULL; 152
165 153 for (i = 1; i <= fontcount; i++) {
166 for (i = 1; i <= fontcount; i++) { 154 if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) {
167 if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) { 155 cur->next = ret;
168 cur->next = ret; 156 ret = cur;
169 ret = cur; 157 }
170 } 158 }
171 } 159 return (drw->fonts = ret);
172 return (drw->fonts = ret);
173} 160}
174 161
175void drw_fontset_free(Fnt *font) 162void drw_fontset_free(Fnt *font) {
176{ 163 if (font) {
177 if (font) { 164 drw_fontset_free(font->next);
178 drw_fontset_free(font->next); 165 xfont_free(font);
179 xfont_free(font); 166 }
180 }
181} 167}
182 168
183void drw_clr_create(Drw *drw, Clr *dest, const char *clrname) 169void drw_clr_create(Drw *drw, Clr *dest, const char *clrname) {
184{ 170 if (!drw || !dest || !clrname)
185 if (!drw || !dest || !clrname) 171 return;
186 return;
187 172
188 if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), 173 if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
189 DefaultColormap(drw->dpy, drw->screen), 174 DefaultColormap(drw->dpy, drw->screen), clrname, dest))
190 clrname, dest)) 175 die("error, cannot allocate color '%s'", clrname);
191 die("error, cannot allocate color '%s'", clrname);
192} 176}
193 177
194/* Wrapper to create color schemes. The caller has to call free(3) on the 178/* Wrapper to create color schemes. The caller has to call free(3) on the
195 * returned color scheme when done using it. */ 179 * returned color scheme when done using it. */
196Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) 180Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) {
197{ 181 size_t i;
198 size_t i; 182 Clr *ret;
199 Clr *ret; 183
200 184 /* need at least two colors for a scheme */
201 /* need at least two colors for a scheme */ 185 if (!drw || !clrnames || clrcount < 2 ||
202 if (!drw || !clrnames || clrcount < 2 186 !(ret = ecalloc(clrcount, sizeof(XftColor))))
203 || !(ret = ecalloc(clrcount, sizeof(XftColor)))) 187 return NULL;
204 return NULL; 188
205 189 for (i = 0; i < clrcount; i++)
206 for (i = 0; i < clrcount; i++) 190 drw_clr_create(drw, &ret[i], clrnames[i]);
207 drw_clr_create(drw, &ret[i], clrnames[i]); 191 return ret;
208 return ret;
209} 192}
210 193
211void drw_setfontset(Drw *drw, Fnt *set) 194void drw_setfontset(Drw *drw, Fnt *set) {
212{ 195 if (drw)
213 if (drw) 196 drw->fonts = set;
214 drw->fonts = set;
215} 197}
216 198
217void drw_setscheme(Drw *drw, Clr *scm) 199void drw_setscheme(Drw *drw, Clr *scm) {
218{ 200 if (drw)
219 if (drw) 201 drw->scheme = scm;
220 drw->scheme = scm;
221} 202}
222 203
223void 204void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h,
224drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, 205 int filled, int invert) {
225 int invert) 206 if (!drw || !drw->scheme)
226{ 207 return;
227 if (!drw || !drw->scheme) 208 XSetForeground(drw->dpy, drw->gc,
228 return; 209 invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
229 XSetForeground(drw->dpy, drw->gc, 210 if (filled)
230 invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg]. 211 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
231 pixel); 212 else
232 if (filled) 213 XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
233 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
234 else
235 XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1,
236 h - 1);
237} 214}
238 215
239int 216int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h,
240drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, 217 unsigned int lpad, const char *text, int invert) {
241 unsigned int lpad, const char *text, int invert) 218 int i, ty, ellipsis_x = 0;
242{ 219 unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len;
243 int i, ty, ellipsis_x = 0; 220 XftDraw *d = NULL;
244 unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len; 221 Fnt *usedfont, *curfont, *nextfont;
245 XftDraw *d = NULL; 222 int utf8strlen, utf8charlen, render = x || y || w || h;
246 Fnt *usedfont, *curfont, *nextfont; 223 long utf8codepoint = 0;
247 int utf8strlen, utf8charlen, render = x || y || w || h; 224 const char *utf8str;
248 long utf8codepoint = 0; 225 FcCharSet *fccharset;
249 const char *utf8str; 226 FcPattern *fcpattern;
250 FcCharSet *fccharset; 227 FcPattern *match;
251 FcPattern *fcpattern; 228 XftResult result;
252 FcPattern *match; 229 int charexists = 0, overflow = 0;
253 XftResult result; 230 /* keep track of a couple codepoints for which we have no match. */
254 int charexists = 0, overflow = 0; 231 enum { nomatches_len = 64 };
255 /* keep track of a couple codepoints for which we have no match. */ 232 static struct {
256 enum { nomatches_len = 64 }; 233 long codepoint[nomatches_len];
257 static struct { 234 unsigned int idx;
258 long codepoint[nomatches_len]; 235 } nomatches;
259 unsigned int idx; 236 static unsigned int ellipsis_width = 0;
260 } nomatches; 237
261 static unsigned int ellipsis_width = 0; 238 if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts)
262 239 return 0;
263 if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts) 240
264 return 0; 241 if (!render) {
265 242 w = invert ? invert : ~invert;
266 if (!render) { 243 } else {
267 w = invert ? invert : ~invert; 244 XSetForeground(drw->dpy, drw->gc,
268 } else { 245 drw->scheme[invert ? ColFg : ColBg].pixel);
269 XSetForeground(drw->dpy, drw->gc, 246 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
270 drw->scheme[invert ? ColFg : ColBg].pixel); 247 d = XftDrawCreate(drw->dpy, drw->drawable,
271 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); 248 DefaultVisual(drw->dpy, drw->screen),
272 d = XftDrawCreate(drw->dpy, drw->drawable, 249 DefaultColormap(drw->dpy, drw->screen));
273 DefaultVisual(drw->dpy, drw->screen), 250 x += lpad;
274 DefaultColormap(drw->dpy, drw->screen)); 251 w -= lpad;
275 x += lpad; 252 }
276 w -= lpad; 253
277 } 254 usedfont = drw->fonts;
278 255 if (!ellipsis_width && render)
279 usedfont = drw->fonts; 256 ellipsis_width = drw_fontset_getwidth(drw, "...");
280 if (!ellipsis_width && render) 257 while (1) {
281 ellipsis_width = drw_fontset_getwidth(drw, "..."); 258 ew = ellipsis_len = utf8strlen = 0;
282 while (1) { 259 utf8str = text;
283 ew = ellipsis_len = utf8strlen = 0; 260 nextfont = NULL;
284 utf8str = text; 261 while (*text) {
285 nextfont = NULL; 262 utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ);
286 while (*text) { 263 for (curfont = drw->fonts; curfont; curfont = curfont->next) {
287 utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); 264 charexists = charexists ||
288 for (curfont = drw->fonts; curfont; 265 XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
289 curfont = curfont->next) { 266 if (charexists) {
290 charexists = charexists 267 drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL);
291 || XftCharExists(drw->dpy, curfont->xfont, 268 if (ew + ellipsis_width <= w) {
292 utf8codepoint); 269 /* keep track where the ellipsis still fits */
293 if (charexists) { 270 ellipsis_x = x + ew;
294 drw_font_getexts(curfont, text, 271 ellipsis_w = w - ew;
295 utf8charlen, &tmpw, 272 ellipsis_len = utf8strlen;
296 NULL); 273 }
297 if (ew + ellipsis_width <= w) { 274
298 /* keep track where the ellipsis still fits */ 275 if (ew + tmpw > w) {
299 ellipsis_x = x + ew; 276 overflow = 1;
300 ellipsis_w = w - ew; 277 /* called from drw_fontset_getwidth_clamp():
301 ellipsis_len = utf8strlen; 278 * it wants the width AFTER the overflow
302 } 279 */
303 280 if (!render)
304 if (ew + tmpw > w) { 281 x += tmpw;
305 overflow = 1; 282 else
306 /* called from drw_fontset_getwidth_clamp(): 283 utf8strlen = ellipsis_len;
307 * it wants the width AFTER the overflow 284 } else if (curfont == usedfont) {
308 */ 285 utf8strlen += utf8charlen;
309 if (!render) 286 text += utf8charlen;
310 x += tmpw; 287 ew += tmpw;
311 else 288 } else {
312 utf8strlen = 289 nextfont = curfont;
313 ellipsis_len; 290 }
314 } else if (curfont == usedfont) { 291 break;
315 utf8strlen += utf8charlen; 292 }
316 text += utf8charlen; 293 }
317 ew += tmpw; 294
318 } else { 295 if (overflow || !charexists || nextfont)
319 nextfont = curfont; 296 break;
320 } 297 else
321 break; 298 charexists = 0;
322 } 299 }
323 } 300
324 301 if (utf8strlen) {
325 if (overflow || !charexists || nextfont) 302 if (render) {
326 break; 303 ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
327 else 304 XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
328 charexists = 0; 305 usedfont->xfont, x, ty, (XftChar8 *)utf8str,
329 } 306 utf8strlen);
330 307 }
331 if (utf8strlen) { 308 x += ew;
332 if (render) { 309 w -= ew;
333 ty = y + (h - usedfont->h) / 2 + 310 }
334 usedfont->xfont->ascent; 311 if (render && overflow)
335 XftDrawStringUtf8(d, 312 drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert);
336 &drw-> 313
337 scheme[invert ? ColBg : 314 if (!*text || overflow) {
338 ColFg], 315 break;
339 usedfont->xfont, x, ty, 316 } else if (nextfont) {
340 (XftChar8 *) utf8str, 317 charexists = 0;
341 utf8strlen); 318 usedfont = nextfont;
342 } 319 } else {
343 x += ew; 320 /* Regardless of whether or not a fallback font is found, the
344 w -= ew; 321 * character must be drawn. */
345 } 322 charexists = 1;
346 if (render && overflow) 323
347 drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", 324 for (i = 0; i < nomatches_len; ++i) {
348 invert); 325 /* avoid calling XftFontMatch if we know we won't find a match */
349 326 if (utf8codepoint == nomatches.codepoint[i])
350 if (!*text || overflow) { 327 goto no_match;
351 break; 328 }
352 } else if (nextfont) { 329
353 charexists = 0; 330 fccharset = FcCharSetCreate();
354 usedfont = nextfont; 331 FcCharSetAddChar(fccharset, utf8codepoint);
355 } else { 332
356 /* Regardless of whether or not a fallback font is found, the 333 if (!drw->fonts->pattern) {
357 * character must be drawn. */ 334 /* Refer to the comment in xfont_create for more information. */
358 charexists = 1; 335 die("the first font in the cache must be loaded from a font string.");
359 336 }
360 for (i = 0; i < nomatches_len; ++i) { 337
361 /* avoid calling XftFontMatch if we know we won't find a match */ 338 fcpattern = FcPatternDuplicate(drw->fonts->pattern);
362 if (utf8codepoint == nomatches.codepoint[i]) 339 FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
363 goto no_match; 340 FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
364 } 341
365 342 FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
366 fccharset = FcCharSetCreate(); 343 FcDefaultSubstitute(fcpattern);
367 FcCharSetAddChar(fccharset, utf8codepoint); 344 match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
368 345
369 if (!drw->fonts->pattern) { 346 FcCharSetDestroy(fccharset);
370 /* Refer to the comment in xfont_create for more information. */ 347 FcPatternDestroy(fcpattern);
371 die("the first font in the cache must be loaded from a font string."); 348
372 } 349 if (match) {
373 350 usedfont = xfont_create(drw, NULL, match);
374 fcpattern = FcPatternDuplicate(drw->fonts->pattern); 351 if (usedfont &&
375 FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); 352 XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) {
376 FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); 353 for (curfont = drw->fonts; curfont->next; curfont = curfont->next)
377 354 ; /* NOP */
378 FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); 355 curfont->next = usedfont;
379 FcDefaultSubstitute(fcpattern); 356 } else {
380 match = 357 xfont_free(usedfont);
381 XftFontMatch(drw->dpy, drw->screen, fcpattern, 358 nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint;
382 &result); 359 no_match:
383 360 usedfont = drw->fonts;
384 FcCharSetDestroy(fccharset); 361 }
385 FcPatternDestroy(fcpattern); 362 }
386 363 }
387 if (match) { 364 }
388 usedfont = xfont_create(drw, NULL, match); 365 if (d)
389 if (usedfont 366 XftDrawDestroy(d);
390 && XftCharExists(drw->dpy, usedfont->xfont, 367
391 utf8codepoint)) { 368 return x + (render ? w : 0);
392 for (curfont = drw->fonts; curfont->next; curfont = curfont->next) ; /* NOP */
393 curfont->next = usedfont;
394 } else {
395 xfont_free(usedfont);
396 nomatches.codepoint[++nomatches.idx %
397 nomatches_len] =
398 utf8codepoint;
399 no_match:
400 usedfont = drw->fonts;
401 }
402 }
403 }
404 }
405 if (d)
406 XftDrawDestroy(d);
407
408 return x + (render ? w : 0);
409} 369}
410 370
411void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) 371void drw_map(Drw *drw, Window win, int x, int y, unsigned int w,
412{ 372 unsigned int h) {
413 if (!drw) 373 if (!drw)
414 return; 374 return;
415 375
416 XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); 376 XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
417 XSync(drw->dpy, False); 377 XSync(drw->dpy, False);
418} 378}
419 379
420unsigned int drw_fontset_getwidth(Drw *drw, const char *text) 380unsigned int drw_fontset_getwidth(Drw *drw, const char *text) {
421{ 381 if (!drw || !drw->fonts || !text)
422 if (!drw || !drw->fonts || !text) 382 return 0;
423 return 0; 383 return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
424 return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
425} 384}
426 385
427unsigned int 386unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text,
428drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n) 387 unsigned int n) {
429{ 388 unsigned int tmp = 0;
430 unsigned int tmp = 0; 389 if (drw && drw->fonts && text && n)
431 if (drw && drw->fonts && text && n) 390 tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n);
432 tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n); 391 return MIN(n, tmp);
433 return MIN(n, tmp);
434} 392}
435 393
436void 394void drw_font_getexts(Fnt *font, const char *text, unsigned int len,
437drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, 395 unsigned int *w, unsigned int *h) {
438 unsigned int *h) 396 XGlyphInfo ext;
439{ 397
440 XGlyphInfo ext; 398 if (!font || !text)
441 399 return;
442 if (!font || !text) 400
443 return; 401 XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
444 402 if (w)
445 XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *) text, len, 403 *w = ext.xOff;
446 &ext); 404 if (h)
447 if (w) 405 *h = font->h;
448 *w = ext.xOff;
449 if (h)
450 *h = font->h;
451} 406}
452 407
453Cur *drw_cur_create(Drw *drw, int shape) 408Cur *drw_cur_create(Drw *drw, int shape) {
454{ 409 Cur *cur;
455 Cur *cur;
456 410
457 if (!drw || !(cur = ecalloc(1, sizeof(Cur)))) 411 if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
458 return NULL; 412 return NULL;
459 413
460 cur->cursor = XCreateFontCursor(drw->dpy, shape); 414 cur->cursor = XCreateFontCursor(drw->dpy, shape);
461 415
462 return cur; 416 return cur;
463} 417}
464 418
465void drw_cur_free(Drw *drw, Cur *cursor) 419void drw_cur_free(Drw *drw, Cur *cursor) {
466{ 420 if (!cursor)
467 if (!cursor) 421 return;
468 return;
469 422
470 XFreeCursor(drw->dpy, cursor->cursor); 423 XFreeCursor(drw->dpy, cursor->cursor);
471 free(cursor); 424 free(cursor);
472} 425}