xrandrfontsize-0.8.4-20211224-2f6e597.diff - sites - public wiki contents of su… | |
git clone git://git.suckless.org/sites | |
Log | |
Files | |
Refs | |
--- | |
xrandrfontsize-0.8.4-20211224-2f6e597.diff (8924B) | |
--- | |
1 diff --git a/config.def.h b/config.def.h | |
2 index f92798a..517abbb 100644 | |
3 --- a/config.def.h | |
4 +++ b/config.def.h | |
5 @@ -9,5 +9,19 @@ | |
6 static int borderpx = 2; | |
7 | |
8 +/* | |
9 + * Override/adjust fontsize of choosen monitors: | |
10 + */ | |
11 +MonitorConfig monitors_config[] = { | |
12 + // skip = fixed relative points size (monitor dpi) | |
13 + // =0 : fixed absolute pixel size (default screen dpi) | |
14 + // >0 : auto absolute pixel size (monitor dpi) | |
15 + // <0 : auto relative points size (monitor dpi) | |
16 + // {"DP-1", 0}, // BUG:(size=0): not restored to default after … | |
17 + {"HDMI-0~1", -20}, // BUG:(ignored DPI=220): = 20 is eqv to 10… | |
18 + {"HDMI-0~2", -14}, | |
19 +}; | |
20 +float winmovethreshold = 0.6; | |
21 + | |
22 /* | |
23 * What program is execed by st depends of these precedence rules: | |
24 * 1: program passed with -e | |
25 @@ -272,6 +272,7 @@ static Shortcut shortcuts[] = { | |
26 { TERMMOD, XK_Prior, zoom, {.f = +… | |
27 { TERMMOD, XK_Next, zoom, {.f = -… | |
28 { TERMMOD, XK_Home, zoomreset, {.f = … | |
29 + { TERMMOD, XK_End, refreshxrandr, {.i = … | |
30 { TERMMOD, XK_C, clipcopy, {.i = … | |
31 { TERMMOD, XK_V, clippaste, {.i = … | |
32 { TERMMOD, XK_Y, selpaste, {.i = … | |
33 diff --git a/config.mk b/config.mk | |
34 index aaa54ff..2d28597 100644 | |
35 --- a/config.mk | |
36 +++ b/config.mk | |
37 @@ -24,5 +24,7 @@ LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrend… | |
38 | |
39 +LIBS += -lXrandr | |
40 + | |
41 # flags | |
42 STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 | |
43 STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) | |
44 STLDFLAGS = $(LIBS) $(LDFLAGS) | |
45 diff --git a/x.c b/x.c | |
46 index 684311c..ce1c418 100644 | |
47 --- a/x.c | |
48 +++ b/x.c | |
49 @@ -14,6 +14,7 @@ | |
50 #include <X11/keysym.h> | |
51 #include <X11/Xft/Xft.h> | |
52 #include <X11/XKBlib.h> | |
53 +#include <X11/extensions/Xrandr.h> | |
54 | |
55 char *argv0; | |
56 #include "arg.h" | |
57 @@ -45,5 +46,18 @@ typedef struct { | |
58 signed char appcursor; /* application cursor */ | |
59 } Key; | |
60 | |
61 +typedef struct { | |
62 + const char *name; | |
63 + float defaultfontsize; | |
64 +} MonitorConfig; | |
65 + | |
66 +typedef struct { | |
67 + Atom name; | |
68 + int x, y, w, h; | |
69 + float defaultfontsize, usedfontsize; | |
70 +} MonitorInfo; | |
71 + | |
72 +static void refreshxrandr(const Arg *dummy); | |
73 + | |
74 /* X modifiers */ | |
75 #define XK_ANY_MOD UINT_MAX | |
76 @@ -233,7 +233,12 @@ static XWindow xw; | |
77 [PropertyNotify] = propnotify, | |
78 [SelectionRequest] = selrequest, | |
79 }; | |
80 | |
81 +static double defaultrelfontsize = 0; | |
82 +static MonitorInfo *monitors_info = NULL; | |
83 +static int monitors_num = 0; | |
84 +static int prev_mindex = -1; | |
85 + | |
86 /* Globals */ | |
87 static DC dc; | |
88 static XWindow xw; | |
89 @@ -2280,6 +2280,144 @@ xseturgency(int add) | |
90 XFree(h); | |
91 } | |
92 | |
93 +static void | |
94 +cachemonitorinfo() | |
95 +{ | |
96 + int prev_num = monitors_num; | |
97 + MonitorInfo *prev_info = monitors_info; | |
98 + XRRMonitorInfo *xmonitors = XRRGetMonitors(xw.dpy, XRootWindow(… | |
99 + if (!monitors_num) | |
100 + die("xrandr found no monitors"); | |
101 + | |
102 + monitors_info = xmalloc(monitors_num * sizeof(MonitorInfo)); | |
103 + | |
104 + for (int i = 0; i < monitors_num; ++i) { | |
105 + XRRMonitorInfo *xm = &xmonitors[i]; | |
106 + MonitorInfo *m = &monitors_info[i]; | |
107 + | |
108 + m->name = xm->name; | |
109 + m->x = xm->x; | |
110 + m->y = xm->y; | |
111 + m->w = xm->width; | |
112 + m->h = xm->height; | |
113 + | |
114 + float px_mm = ((float)m->w / xm->mwidth + (float)m->h /… | |
115 + float px_pt = 25.4 * px_mm / 72; | |
116 + m->defaultfontsize = defaultrelfontsize * px_pt; | |
117 + | |
118 + // Override defaultfontsize (dpi) by user config | |
119 + char *name = XGetAtomName(xw.dpy, xm->name); | |
120 + for (int j = 0; j < LEN(monitors_config); ++j) | |
121 + if (!strcmp(name, monitors_config[j].name)) { | |
122 + m->defaultfontsize = monitors_config[j]… | |
123 + if (m->defaultfontsize < 0) | |
124 + m->defaultfontsize *= -px_pt; | |
125 + break; | |
126 + } | |
127 + // fprintf(stderr, "%s: %fpx, %f\n", name, m->defaultfo… | |
128 + XFree(name); | |
129 + | |
130 + // Restore usedfontsize (zoom) after re-cache for monit… | |
131 + m->usedfontsize = m->defaultfontsize; | |
132 + for (int j = 0; j < prev_num; ++j) | |
133 + if (prev_info[j].name == m->name) { | |
134 + m->usedfontsize = prev_info[j].usedfont… | |
135 + break; | |
136 + } | |
137 + } | |
138 + | |
139 + XRRFreeMonitors(xmonitors); | |
140 + free(prev_info); | |
141 +} | |
142 + | |
143 +static int | |
144 +getmonitorindex_threshold(int w, int h, int x, int y) | |
145 +{ | |
146 + int mindex = -1; | |
147 + float fontsize = 0; | |
148 + int thresholdarea = winmovethreshold * w * h; | |
149 + | |
150 + for (int i = 0; i < monitors_num; ++i) { | |
151 + MonitorInfo *m = &monitors_info[i]; | |
152 + int overlap_w = MAX(0, MIN(x + w, m->x + m->w) - MAX(x,… | |
153 + int overlap_h = MAX(0, MIN(y + h, m->y + m->h) - MAX(y,… | |
154 + int area = overlap_w * overlap_h; | |
155 + // Choose monitor with largest dpi (defaultfontsize) | |
156 + // from all "mirrored"/overlapped (e.g. projector) | |
157 + if (area >= thresholdarea && fontsize < m->defaultfonts… | |
158 + fontsize = m->defaultfontsize; | |
159 + mindex = i; | |
160 + } | |
161 + } | |
162 + return mindex; | |
163 +} | |
164 + | |
165 +static int | |
166 +getmonitorindex_nearest(int w, int h, int x, int y) | |
167 +{ | |
168 + int mindex = -1; | |
169 + float fontsize = 0; | |
170 + int overlaparea = 0; | |
171 + | |
172 + for (int i = 0; i < monitors_num; ++i) { | |
173 + MonitorInfo *m = &monitors_info[i]; | |
174 + int overlap_w = MAX(0, MIN(x + w, m->x + m->w) - MAX(x,… | |
175 + int overlap_h = MAX(0, MIN(y + h, m->y + m->h) - MAX(y,… | |
176 + int area = overlap_w * overlap_h; | |
177 + // Choose monitor with largest overlapping area | |
178 + // e.g. when "st" is initially spawned in-between moni… | |
179 + if (area > overlaparea) { | |
180 + overlaparea = area; | |
181 + mindex = i; | |
182 + } | |
183 + } | |
184 + return mindex; | |
185 +} | |
186 + | |
187 +static void | |
188 +adjustmonitorfontsize(int mindex) | |
189 +{ | |
190 + if (mindex < 0 || prev_mindex == mindex) | |
191 + return; | |
192 + // Save zoom of current monitor before switching | |
193 + if (prev_mindex >= 0) | |
194 + monitors_info[prev_mindex].usedfontsize = usedfontsize; | |
195 + | |
196 + defaultfontsize = monitors_info[mindex].defaultfontsize; | |
197 + // fprintf(stderr, "Crossing: %fpx\n", defaultfontsize); | |
198 + | |
199 + // NOTE: do nothing if font size differs by less than 1% | |
200 + double fontsize = monitors_info[mindex].usedfontsize; | |
201 + double delta = 0.01 * usedfontsize; | |
202 + if (!BETWEEN(fontsize - usedfontsize, -delta, delta)) { | |
203 + // fprintf(stderr, "Adjusted: %fpx\n", fontsize); | |
204 + xunloadfonts(); | |
205 + xloadfonts(usedfont, fontsize); | |
206 + } | |
207 + prev_mindex = mindex; | |
208 +} | |
209 + | |
210 +void | |
211 +refreshxrandr(const Arg *dummy) | |
212 +{ | |
213 + // Reset index to detect change of window association on "xrand… | |
214 + // otherwise: zoom won't be saved on switching and new font si… | |
215 + // CRIT!!! event from xrandr may place another monitor into sam… | |
216 + if (prev_mindex >= 0) | |
217 + monitors_info[prev_mindex].usedfontsize = usedfontsize; | |
218 + prev_mindex = -1; | |
219 + | |
220 + XWindowAttributes xattr = {0}; | |
221 + cachemonitorinfo(); | |
222 + XGetWindowAttributes(xw.dpy, xw.win, &xattr); | |
223 + | |
224 + int mindex = getmonitorindex_threshold(xattr.width, xattr.heigh… | |
225 + if (mindex < 0) | |
226 + mindex = getmonitorindex_nearest(xattr.width, xattr.hei… | |
227 + adjustmonitorfontsize(mindex); | |
228 +} | |
229 + | |
230 + | |
231 void | |
232 xbell(void) | |
233 { | |
234 @@ -2437,6 +2437,14 @@ cmessage(XEvent *e) | |
235 void | |
236 resize(XEvent *e) | |
237 { | |
238 + // BAD: no resize on monitor plug/unplug/reconfigure -- until w… | |
239 + // NOTE: no resize event on zoomabs() | |
240 + // fprintf(stderr, "Resize: %dx%d+%d+%d\n", | |
241 + // e->xconfigure.width, e->xconfigure.height, e->xconfigure… | |
242 + | |
243 + adjustmonitorfontsize(getmonitorindex_threshold( | |
244 + e->xconfigure.width, e->xconfigure.height, e->xconfigure.x,… | |
245 + | |
246 if (e->xconfigure.width == win.w && e->xconfigure.height == win… | |
247 return; | |
248 | |
249 @@ -2469,6 +2469,22 @@ run(void) | |
250 } | |
251 } while (ev.type != MapNotify); | |
252 | |
253 + int rr_event_base, rr_error_base, rr_major, rr_minor; | |
254 + if (!XRRQueryExtension (xw.dpy, &rr_event_base, &rr_error_base)… | |
255 + !XRRQueryVersion (xw.dpy, &rr_major, &rr_minor) || | |
256 + rr_major < 1 || (rr_major == 1 && rr_minor < 5)) | |
257 + { | |
258 + die("RandR 1.5 extension isn't available\n"); | |
259 + } | |
260 + XRRSelectInput(xw.dpy, xw.win, RRCrtcChangeNotifyMask); | |
261 + | |
262 + // WARN: can query actual window size/pos only after window is … | |
263 + // * x/y are WM-dependent and can't be determined beforehand a… | |
264 + // * defaultfontsize isn't available until font is loaded and … | |
265 + // BAD: fonts on startup are always reloaded -- how to specify … | |
266 + FcPatternGetDouble(dc.font.match->pattern, FC_SIZE, 0, &default… | |
267 + refreshxrandr(0); | |
268 + | |
269 ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd); | |
270 cresize(w, h); | |
271 | |
272 @@ -2500,6 +2500,16 @@ run(void) | |
273 XNextEvent(xw.dpy, &ev); | |
274 if (XFilterEvent(&ev, None)) | |
275 continue; | |
276 + if (LASTEvent <= ev.type) { | |
277 + if (rr_event_base + RRNotify == ev.type… | |
278 + RRNotify_CrtcChange == ((XRRNot… | |
279 + { | |
280 + XRRUpdateConfiguration(&ev); | |
281 + // fprintf(stderr, "Monitor cha… | |
282 + refreshxrandr(0); | |
283 + } | |
284 + continue; | |
285 + } | |
286 if (handler[ev.type]) | |
287 (handler[ev.type])(&ev); | |
288 } |