1 // SPDX-License-Identifier: MPL-2.0
2 // Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
3 
4 #include <getopt.h>
5 #include <locale.h>
6 #include <stdbool.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <xcb/render.h>        // for xcb_render_fixed_t, XXX
12 
13 #include "backend/backend.h"
14 #include "common.h"
15 #include "config.h"
16 #include "log.h"
17 #include "options.h"
18 #include "utils.h"
19 #include "win.h"
20 
21 #pragma GCC diagnostic error "-Wunused-parameter"
22 
23 /**
24  * Print usage text.
25  */
usage(const char * argv0,int ret)26 static void usage(const char *argv0, int ret) {
27 #define WARNING_DISABLED " (DISABLED AT COMPILE TIME)"
28 	static const char *usage_text =
29 	    "picom (" COMPTON_VERSION ")\n"
30 	    "Please report bugs to https://github.com/yshui/picom\n\n"
31 	    "usage: %s [options]\n"
32 	    "Options:\n"
33 	    "\n"
34 	    "-r radius\n"
35 	    "  The blur radius for shadows. (default 12)\n"
36 	    "\n"
37 	    "-o opacity\n"
38 	    "  The translucency for shadows. (default .75)\n"
39 	    "\n"
40 	    "-l left-offset\n"
41 	    "  The left offset for shadows. (default -15)\n"
42 	    "\n"
43 	    "-t top-offset\n"
44 	    "  The top offset for shadows. (default -15)\n"
45 	    "\n"
46 	    "-I fade-in-step\n"
47 	    "  Opacity change between steps while fading in. (default 0.028)\n"
48 	    "\n"
49 	    "-O fade-out-step\n"
50 	    "  Opacity change between steps while fading out. (default 0.03)\n"
51 	    "\n"
52 	    "-D fade-delta-time\n"
53 	    "  The time between steps in a fade in milliseconds. (default 10)\n"
54 	    "\n"
55 	    "-m opacity\n"
56 	    "  The opacity for menus. (default 1.0)\n"
57 	    "\n"
58 	    "-c\n"
59 	    "  Enabled client-side shadows on windows.\n"
60 	    "\n"
61 	    "-C\n"
62 	    "  Avoid drawing shadows on dock/panel windows.\n"
63 	    "\n"
64 	    "-z\n"
65 	    "  Zero the part of the shadow's mask behind the window.\n"
66 	    "\n"
67 	    "-f\n"
68 	    "  Fade windows in/out when opening/closing and when opacity\n"
69 	    "  changes, unless --no-fading-openclose is used.\n"
70 	    "\n"
71 	    "-F\n"
72 	    "  Equals to -f. Deprecated.\n"
73 	    "\n"
74 	    "-i opacity\n"
75 	    "  Opacity of inactive windows. (0.1 - 1.0)\n"
76 	    "\n"
77 	    "-e opacity\n"
78 	    "  Opacity of window titlebars and borders. (0.1 - 1.0)\n"
79 	    "\n"
80 	    "-G\n"
81 	    "  Don't draw shadows on DND windows\n"
82 	    "\n"
83 	    "-b\n"
84 	    "  Daemonize process.\n"
85 	    "\n"
86 	    "--show-all-xerrors\n"
87 	    "  Show all X errors (for debugging).\n"
88 	    "\n"
89 	    "--config path\n"
90 	    "  Look for configuration file at the path. Use /dev/null to avoid\n"
91 	    "  loading configuration file."
92 #ifndef CONFIG_LIBCONFIG
93 	    WARNING_DISABLED
94 #endif
95 	    "\n\n"
96 	    "--write-pid-path path\n"
97 	    "  Write process ID to a file.\n"
98 	    "\n"
99 	    "--shadow-red value\n"
100 	    "  Red color value of shadow (0.0 - 1.0, defaults to 0).\n"
101 	    "\n"
102 	    "--shadow-green value\n"
103 	    "  Green color value of shadow (0.0 - 1.0, defaults to 0).\n"
104 	    "\n"
105 	    "--shadow-blue value\n"
106 	    "  Blue color value of shadow (0.0 - 1.0, defaults to 0).\n"
107 	    "\n"
108 	    "--inactive-opacity-override\n"
109 	    "  Inactive opacity set by -i overrides value of _NET_WM_OPACITY.\n"
110 	    "\n"
111 	    "--inactive-dim value\n"
112 	    "  Dim inactive windows. (0.0 - 1.0, defaults to 0)\n"
113 	    "\n"
114 	    "--active-opacity opacity\n"
115 	    "  Default opacity for active windows. (0.0 - 1.0)\n"
116 	    "\n"
117 	    "--mark-wmwin-focused\n"
118 	    "  Try to detect WM windows and mark them as active.\n"
119 	    "\n"
120 	    "--shadow-exclude condition\n"
121 	    "  Exclude conditions for shadows.\n"
122 	    "\n"
123 	    "--fade-exclude condition\n"
124 	    "  Exclude conditions for fading.\n"
125 	    "\n"
126 	    "--mark-ovredir-focused\n"
127 	    "  Mark windows that have no WM frame as active.\n"
128 	    "\n"
129 	    "--no-fading-openclose\n"
130 	    "  Do not fade on window open/close.\n"
131 	    "\n"
132 	    "--no-fading-destroyed-argb\n"
133 	    "  Do not fade destroyed ARGB windows with WM frame. Workaround of bugs\n"
134 	    "  in Openbox, Fluxbox, etc.\n"
135 	    "\n"
136 	    "--shadow-ignore-shaped\n"
137 	    "  Do not paint shadows on shaped windows. (Deprecated, use\n"
138 	    "  --shadow-exclude \'bounding_shaped\' or\n"
139 	    "  --shadow-exclude \'bounding_shaped && !rounded_corners\' instead.)\n"
140 	    "\n"
141 	    "--detect-rounded-corners\n"
142 	    "  Try to detect windows with rounded corners and don't consider\n"
143 	    "  them shaped windows. Affects --shadow-ignore-shaped,\n"
144 	    "  --unredir-if-possible, and possibly others. You need to turn this\n"
145 	    "  on manually if you want to match against rounded_corners in\n"
146 	    "  conditions.\n"
147 	    "\n"
148 	    "--detect-client-opacity\n"
149 	    "  Detect _NET_WM_OPACITY on client windows, useful for window\n"
150 	    "  managers not passing _NET_WM_OPACITY of client windows to frame\n"
151 	    "  windows.\n"
152 	    "\n"
153 	    "--refresh-rate val\n"
154 	    "  Specify refresh rate of the screen. If not specified or 0, we\n"
155 	    "  will try detecting this with X RandR extension.\n"
156 	    "\n"
157 	    "--vsync\n"
158 	    "  Enable VSync\n"
159 	    "\n"
160 	    "--paint-on-overlay\n"
161 	    "  Painting on X Composite overlay window.\n"
162 	    "\n"
163 	    "--sw-opti\n"
164 	    "  Limit repaint to at most once every 1 / refresh_rate second.\n"
165 	    "\n"
166 	    "--use-ewmh-active-win\n"
167 	    "  Use _NET_WM_ACTIVE_WINDOW on the root window to determine which\n"
168 	    "  window is focused instead of using FocusIn/Out events.\n"
169 	    "\n"
170 	    "--unredir-if-possible\n"
171 	    "  Unredirect all windows if a full-screen opaque window is\n"
172 	    "  detected, to maximize performance for full-screen windows.\n"
173 	    "\n"
174 	    "--unredir-if-possible-delay ms\n"
175 	    "  Delay before unredirecting the window, in milliseconds.\n"
176 	    "  Defaults to 0.\n"
177 	    "\n"
178 	    "--unredir-if-possible-exclude condition\n"
179 	    "  Conditions of windows that shouldn't be considered full-screen\n"
180 	    "  for unredirecting screen.\n"
181 	    "\n"
182 	    "--focus-exclude condition\n"
183 	    "  Specify a list of conditions of windows that should always be\n"
184 	    "  considered focused.\n"
185 	    "\n"
186 	    "--inactive-dim-fixed\n"
187 	    "  Use fixed inactive dim value.\n"
188 	    "\n"
189 	    "--max-brightness\n"
190 	    "  Dims windows which average brightness is above this threshold.\n"
191 	    "  Requires --no-use-damage.\n"
192 	    "  Default: 1.0 or no dimming.\n"
193 	    "\n"
194 	    "--detect-transient\n"
195 	    "  Use WM_TRANSIENT_FOR to group windows, and consider windows in\n"
196 	    "  the same group focused at the same time.\n"
197 	    "\n"
198 	    "--detect-client-leader\n"
199 	    "  Use WM_CLIENT_LEADER to group windows, and consider windows in\n"
200 	    "  the same group focused at the same time. WM_TRANSIENT_FOR has\n"
201 	    "  higher priority if --detect-transient is enabled, too.\n"
202 	    "\n"
203 	    "--blur-method\n"
204 	    "  The algorithm used for background bluring. Available choices are:\n"
205 	    "  'none' to disable, 'gaussian', 'box' or 'kernel' for custom\n"
206 	    "  convolution blur with --blur-kern.\n"
207 	    "  Note: 'gaussian' and 'box' require --experimental-backends.\n"
208 	    "\n"
209 	    "--blur-size\n"
210 	    "  The radius of the blur kernel for 'box' and 'gaussian' blur method.\n"
211 	    "\n"
212 	    "--blur-deviation\n"
213 	    "  The standard deviation for the 'gaussian' blur method.\n"
214 	    "\n"
215 	    "--blur-background\n"
216 	    "  Blur background of semi-transparent / ARGB windows. Bad in\n"
217 	    "  performance. The switch name may change without prior\n"
218 	    "  notifications.\n"
219 	    "\n"
220 	    "--blur-background-frame\n"
221 	    "  Blur background of windows when the window frame is not opaque.\n"
222 	    "  Implies --blur-background. Bad in performance. The switch name\n"
223 	    "  may change.\n"
224 	    "\n"
225 	    "--blur-background-fixed\n"
226 	    "  Use fixed blur strength instead of adjusting according to window\n"
227 	    "  opacity.\n"
228 	    "\n"
229 	    "--blur-kern matrix\n"
230 	    "  Specify the blur convolution kernel, with the following format:\n"
231 	    "    WIDTH,HEIGHT,ELE1,ELE2,ELE3,ELE4,ELE5...\n"
232 	    "  The element in the center must not be included, it will be forever\n"
233 	    "  1.0 or changing based on opacity, depending on whether you have\n"
234 	    "  --blur-background-fixed.\n"
235 	    "  A 7x7 Gaussian blur kernel looks like:\n"
236 	    "    --blur-kern "
237 	    "'7,7,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0."
238 	    "000102,0.003494,0.029143,0.059106,0.029143,0.003494,0.000102,0.000849,0."
239 	    "029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.001723,0.059106,0."
240 	    "493069,0.493069,0.059106,0.001723,0.000849,0.029143,0.243117,0.493069,0."
241 	    "243117,0.029143,0.000849,0.000102,0.003494,0.029143,0.059106,0.029143,0."
242 	    "003494,0.000102,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0."
243 	    "000003'\n"
244 	    "  Up to 4 blur kernels may be specified, separated with semicolon, for\n"
245 	    "  multi-pass blur.\n"
246 	    "  May also be one the predefined kernels: 3x3box (default), 5x5box,\n"
247 	    "  7x7box, 3x3gaussian, 5x5gaussian, 7x7gaussian, 9x9gaussian,\n"
248 	    "  11x11gaussian.\n"
249 	    "\n"
250 	    "--blur-background-exclude condition\n"
251 	    "  Exclude conditions for background blur.\n"
252 	    "\n"
253 	    "--resize-damage integer\n"
254 	    "  Resize damaged region by a specific number of pixels. A positive\n"
255 	    "  value enlarges it while a negative one shrinks it. Useful for\n"
256 	    "  fixing the line corruption issues of blur. May or may not\n"
257 	    "  work with --glx-no-stencil. Shrinking doesn't function correctly.\n"
258 	    "\n"
259 	    "--invert-color-include condition\n"
260 	    "  Specify a list of conditions of windows that should be painted with\n"
261 	    "  inverted color. Resource-hogging, and is not well tested.\n"
262 	    "\n"
263 	    "--opacity-rule opacity:condition\n"
264 	    "  Specify a list of opacity rules, in the format \"PERCENT:PATTERN\",\n"
265 	    "  like \'50:name *= \"Firefox\"'. picom-trans is recommended over\n"
266 	    "  this. Note we do not distinguish 100%% and unset, and we don't make\n"
267 	    "  any guarantee about possible conflicts with other programs that set\n"
268 	    "  _NET_WM_WINDOW_OPACITY on frame or client windows.\n"
269 	    "\n"
270 	    "--shadow-exclude-reg geometry\n"
271 	    "  Specify a X geometry that describes the region in which shadow\n"
272 	    "  should not be painted in, such as a dock window region.\n"
273 	    "  Use --shadow-exclude-reg \'x10+0-0\', for example, if the 10 pixels\n"
274 	    "  on the bottom of the screen should not have shadows painted on.\n"
275 	    "\n"
276 	    "--xinerama-shadow-crop\n"
277 	    "  Crop shadow of a window fully on a particular Xinerama screen to the\n"
278 	    "  screen.\n"
279 	    "\n"
280 	    "--backend backend\n"
281 	    "  Choose backend. Possible choices are xrender, glx, and\n"
282 	    "  xr_glx_hybrid."
283 #ifndef CONFIG_OPENGL
284 	    " (GLX BACKENDS DISABLED AT COMPILE TIME)"
285 #endif
286 	    "\n\n"
287 	    "--glx-no-stencil\n"
288 	    "  GLX backend: Avoid using stencil buffer. Might cause issues\n"
289 	    "  when rendering transparent content. My tests show a 15%% performance\n"
290 	    "  boost.\n"
291 	    "\n"
292 	    "--glx-no-rebind-pixmap\n"
293 	    "  GLX backend: Avoid rebinding pixmap on window damage. Probably\n"
294 	    "  could improve performance on rapid window content changes, but is\n"
295 	    "  known to break things on some drivers (LLVMpipe, xf86-video-intel,\n"
296 	    "  etc.).\n"
297 	    "\n"
298 	    "--no-use-damage\n"
299 	    "  Disable the use of damage information. This cause the whole screen to\n"
300 	    "  be redrawn everytime, instead of the part of the screen that has\n"
301 	    "  actually changed. Potentially degrades the performance, but might fix\n"
302 	    "  some artifacts.\n"
303 	    "\n"
304 	    "--xrender-sync-fence\n"
305 	    "  Additionally use X Sync fence to sync clients' draw calls. Needed\n"
306 	    "  on nvidia-drivers with GLX backend for some users.\n"
307 	    "\n"
308 	    "--force-win-blend\n"
309 	    "  Force all windows to be painted with blending. Useful if you have a\n"
310 	    "  --glx-fshader-win that could turn opaque pixels transparent.\n"
311 	    "\n"
312 	    "--dbus\n"
313 	    "  Enable remote control via D-Bus. See the D-BUS API section in the\n"
314 	    "  man page for more details."
315 #ifndef CONFIG_DBUS
316 	    WARNING_DISABLED
317 #endif
318 	    "\n\n"
319 	    "--benchmark cycles\n"
320 	    "  Benchmark mode. Repeatedly paint until reaching the specified cycles.\n"
321 	    "\n"
322 	    "--benchmark-wid window-id\n"
323 	    "  Specify window ID to repaint in benchmark mode. If omitted or is 0,\n"
324 	    "  the whole screen is repainted.\n"
325 	    "\n"
326 	    "--monitor-repaint\n"
327 	    "  Highlight the updated area of the screen. For debugging the xrender\n"
328 	    "  backend only.\n"
329 	    "\n"
330 	    "--debug-mode\n"
331 	    "  Render into a separate window, and don't take over the screen. Useful\n"
332 	    "  when you want to attach a debugger to picom\n"
333 	    "\n"
334 	    "--no-ewmh-fullscreen\n"
335 	    "  Do not use EWMH to detect fullscreen windows. Reverts to checking\n"
336 	    "  if a window is fullscreen based only on its size and coordinates.\n"
337 	    "\n"
338 	    "--transparent-clipping\n"
339 	    "  Make transparent windows clip other windows like non-transparent windows\n"
340 	    "  do, instead of blending on top of them\n";
341 	FILE *f = (ret ? stderr : stdout);
342 	fprintf(f, usage_text, argv0);
343 #undef WARNING_DISABLED
344 }
345 
346 static const char *shortopts = "D:I:O:d:r:o:m:l:t:i:e:hscnfFCaSzGb";
347 static const struct option longopts[] = {
348     {"help", no_argument, NULL, 'h'},
349     {"config", required_argument, NULL, 256},
350     {"shadow-radius", required_argument, NULL, 'r'},
351     {"shadow-opacity", required_argument, NULL, 'o'},
352     {"shadow-offset-x", required_argument, NULL, 'l'},
353     {"shadow-offset-y", required_argument, NULL, 't'},
354     {"fade-in-step", required_argument, NULL, 'I'},
355     {"fade-out-step", required_argument, NULL, 'O'},
356     {"fade-delta", required_argument, NULL, 'D'},
357     {"menu-opacity", required_argument, NULL, 'm'},
358     {"shadow", no_argument, NULL, 'c'},
359     {"no-dock-shadow", no_argument, NULL, 'C'},
360     {"clear-shadow", no_argument, NULL, 'z'},
361     {"fading", no_argument, NULL, 'f'},
362     {"inactive-opacity", required_argument, NULL, 'i'},
363     {"frame-opacity", required_argument, NULL, 'e'},
364     {"daemon", no_argument, NULL, 'b'},
365     {"no-dnd-shadow", no_argument, NULL, 'G'},
366     {"shadow-red", required_argument, NULL, 257},
367     {"shadow-green", required_argument, NULL, 258},
368     {"shadow-blue", required_argument, NULL, 259},
369     {"inactive-opacity-override", no_argument, NULL, 260},
370     {"inactive-dim", required_argument, NULL, 261},
371     {"mark-wmwin-focused", no_argument, NULL, 262},
372     {"shadow-exclude", required_argument, NULL, 263},
373     {"mark-ovredir-focused", no_argument, NULL, 264},
374     {"no-fading-openclose", no_argument, NULL, 265},
375     {"shadow-ignore-shaped", no_argument, NULL, 266},
376     {"detect-rounded-corners", no_argument, NULL, 267},
377     {"detect-client-opacity", no_argument, NULL, 268},
378     {"refresh-rate", required_argument, NULL, 269},
379     {"vsync", optional_argument, NULL, 270},
380     {"alpha-step", required_argument, NULL, 271},
381     {"dbe", no_argument, NULL, 272},
382     {"paint-on-overlay", no_argument, NULL, 273},
383     {"sw-opti", no_argument, NULL, 274},
384     {"vsync-aggressive", no_argument, NULL, 275},
385     {"use-ewmh-active-win", no_argument, NULL, 276},
386     {"respect-prop-shadow", no_argument, NULL, 277},
387     {"unredir-if-possible", no_argument, NULL, 278},
388     {"focus-exclude", required_argument, NULL, 279},
389     {"inactive-dim-fixed", no_argument, NULL, 280},
390     {"detect-transient", no_argument, NULL, 281},
391     {"detect-client-leader", no_argument, NULL, 282},
392     {"blur-background", no_argument, NULL, 283},
393     {"blur-background-frame", no_argument, NULL, 284},
394     {"blur-background-fixed", no_argument, NULL, 285},
395     {"dbus", no_argument, NULL, 286},
396     {"logpath", required_argument, NULL, 287},
397     {"invert-color-include", required_argument, NULL, 288},
398     {"opengl", no_argument, NULL, 289},
399     {"backend", required_argument, NULL, 290},
400     {"glx-no-stencil", no_argument, NULL, 291},
401     {"benchmark", required_argument, NULL, 293},
402     {"benchmark-wid", required_argument, NULL, 294},
403     {"blur-background-exclude", required_argument, NULL, 296},
404     {"active-opacity", required_argument, NULL, 297},
405     {"glx-no-rebind-pixmap", no_argument, NULL, 298},
406     {"glx-swap-method", required_argument, NULL, 299},
407     {"fade-exclude", required_argument, NULL, 300},
408     {"blur-kern", required_argument, NULL, 301},
409     {"resize-damage", required_argument, NULL, 302},
410     {"glx-use-gpushader4", no_argument, NULL, 303},
411     {"opacity-rule", required_argument, NULL, 304},
412     {"shadow-exclude-reg", required_argument, NULL, 305},
413     {"paint-exclude", required_argument, NULL, 306},
414     {"xinerama-shadow-crop", no_argument, NULL, 307},
415     {"unredir-if-possible-exclude", required_argument, NULL, 308},
416     {"unredir-if-possible-delay", required_argument, NULL, 309},
417     {"write-pid-path", required_argument, NULL, 310},
418     {"vsync-use-glfinish", no_argument, NULL, 311},
419     {"xrender-sync", no_argument, NULL, 312},
420     {"xrender-sync-fence", no_argument, NULL, 313},
421     {"show-all-xerrors", no_argument, NULL, 314},
422     {"no-fading-destroyed-argb", no_argument, NULL, 315},
423     {"force-win-blend", no_argument, NULL, 316},
424     {"glx-fshader-win", required_argument, NULL, 317},
425     {"version", no_argument, NULL, 318},
426     {"no-x-selection", no_argument, NULL, 319},
427     {"no-name-pixmap", no_argument, NULL, 320},
428     {"log-level", required_argument, NULL, 321},
429     {"log-file", required_argument, NULL, 322},
430     {"use-damage", no_argument, NULL, 323},
431     {"no-use-damage", no_argument, NULL, 324},
432     {"no-vsync", no_argument, NULL, 325},
433     {"max-brightness", required_argument, NULL, 326},
434     {"transparent-clipping", no_argument, NULL, 327},
435     {"blur-method", required_argument, NULL, 328},
436     {"blur-size", required_argument, NULL, 329},
437     {"blur-deviation", required_argument, NULL, 330},
438     {"experimental-backends", no_argument, NULL, 733},
439     {"monitor-repaint", no_argument, NULL, 800},
440     {"diagnostics", no_argument, NULL, 801},
441     {"debug-mode", no_argument, NULL, 802},
442     {"no-ewmh-fullscreen", no_argument, NULL, 803},
443     // Must terminate with a NULL entry
444     {NULL, 0, NULL, 0},
445 };
446 
447 /// Get config options that are needed to parse the rest of the options
448 /// Return true if we should quit
get_early_config(int argc,char * const * argv,char ** config_file,bool * all_xerrors,bool * fork,int * exit_code)449 bool get_early_config(int argc, char *const *argv, char **config_file, bool *all_xerrors,
450                       bool *fork, int *exit_code) {
451 	int o = 0, longopt_idx = -1;
452 
453 	// Pre-parse the commandline arguments to check for --config and invalid
454 	// switches
455 	// Must reset optind to 0 here in case we reread the commandline
456 	// arguments
457 	optind = 1;
458 	*config_file = NULL;
459 	*exit_code = 0;
460 	while (-1 != (o = getopt_long(argc, argv, shortopts, longopts, &longopt_idx))) {
461 		if (o == 256) {
462 			*config_file = strdup(optarg);
463 		} else if (o == 'h') {
464 			usage(argv[0], 0);
465 			return true;
466 
467 		} else if (o == 'b') {
468 			*fork = true;
469 		} else if (o == 'd') {
470 			log_error("-d is removed, please use the DISPLAY "
471 			          "environment variable");
472 			goto err;
473 		} else if (o == 314) {
474 			*all_xerrors = true;
475 		} else if (o == 318) {
476 			printf("%s\n", COMPTON_VERSION);
477 			return true;
478 		} else if (o == 'S') {
479 			log_error("-S is no longer available");
480 			goto err;
481 		} else if (o == 320) {
482 			log_error("--no-name-pixmap is no longer available");
483 			goto err;
484 		} else if (o == '?' || o == ':') {
485 			usage(argv[0], 1);
486 			goto err;
487 		}
488 	}
489 
490 	// Check for abundant positional arguments
491 	if (optind < argc) {
492 		// log is not initialized here yet
493 		fprintf(stderr, "picom doesn't accept positional arguments.\n");
494 		goto err;
495 	}
496 
497 	return false;
498 err:
499 	*exit_code = 1;
500 	return true;
501 }
502 
503 /**
504  * Process arguments and configuration files.
505  */
get_cfg(options_t * opt,int argc,char * const * argv,bool shadow_enable,bool fading_enable,bool conv_kern_hasneg,win_option_mask_t * winopt_mask)506 bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
507              bool fading_enable, bool conv_kern_hasneg, win_option_mask_t *winopt_mask) {
508 
509 	int o = 0, longopt_idx = -1;
510 
511 	char *lc_numeric_old = strdup(setlocale(LC_NUMERIC, NULL));
512 
513 	// Enforce LC_NUMERIC locale "C" here to make sure dots are recognized
514 	// instead of commas in atof().
515 	setlocale(LC_NUMERIC, "C");
516 
517 	// Parse commandline arguments. Range checking will be done later.
518 
519 	const char *deprecation_message attr_unused =
520 	    "has been removed. If you encounter problems "
521 	    "without this feature, please feel free to "
522 	    "open a bug report.";
523 	optind = 1;
524 	while (-1 != (o = getopt_long(argc, argv, shortopts, longopts, &longopt_idx))) {
525 		switch (o) {
526 #define P_CASEBOOL(idx, option)                                                          \
527 	case idx:                                                                        \
528 		opt->option = true;                                                      \
529 		break
530 #define P_CASELONG(idx, option)                                                          \
531 	case idx:                                                                        \
532 		if (!parse_long(optarg, &opt->option)) {                                 \
533 			exit(1);                                                         \
534 		}                                                                        \
535 		break
536 #define P_CASEINT(idx, option)                                                           \
537 	case idx:                                                                        \
538 		if (!parse_int(optarg, &opt->option)) {                                  \
539 			exit(1);                                                         \
540 		}                                                                        \
541 		break
542 
543 		// clang-format off
544 		// Short options
545 		case 318:
546 		case 'h':
547 			// These options should cause us to exit early,
548 			// so assert(false) here
549 			assert(false);
550 			break;
551 		case 'd':
552 		case 'b':
553 		case 'S':
554 		case 314:
555 		case 320:
556 			// These options are handled by get_early_config()
557 			break;
558 		P_CASEINT('D', fade_delta);
559 		case 'I': opt->fade_in_step = normalize_d(atof(optarg)); break;
560 		case 'O': opt->fade_out_step = normalize_d(atof(optarg)); break;
561 		case 'c': shadow_enable = true; break;
562 		case 'C':
563 			winopt_mask[WINTYPE_DOCK].shadow = true;
564 			opt->wintype_option[WINTYPE_DOCK].shadow = false;
565 			break;
566 		case 'G':
567 			winopt_mask[WINTYPE_DND].shadow = true;
568 			opt->wintype_option[WINTYPE_DND].shadow = false;
569 			break;
570 		case 'm':;
571 			double tmp;
572 			tmp = normalize_d(atof(optarg));
573 			winopt_mask[WINTYPE_DROPDOWN_MENU].opacity = true;
574 			winopt_mask[WINTYPE_POPUP_MENU].opacity = true;
575 			opt->wintype_option[WINTYPE_POPUP_MENU].opacity = tmp;
576 			opt->wintype_option[WINTYPE_DROPDOWN_MENU].opacity = tmp;
577 			break;
578 		case 'f':
579 		case 'F':
580 			fading_enable = true;
581 			break;
582 		P_CASEINT('r', shadow_radius);
583 		case 'o':
584 			opt->shadow_opacity = atof(optarg);
585 			break;
586 		P_CASEINT('l', shadow_offset_x);
587 		P_CASEINT('t', shadow_offset_y);
588 		case 'i':
589 			opt->inactive_opacity = normalize_d(atof(optarg));
590 			break;
591 		case 'e': opt->frame_opacity = atof(optarg); break;
592 		case 'z':
593 			log_warn("clear-shadow is removed, shadows are automatically "
594 			         "cleared now. If you want to prevent shadow from been "
595 			         "cleared under certain types of windows, you can use "
596 			         "the \"full-shadow\" per window type option.");
597 			break;
598 		case 'n':
599 		case 'a':
600 		case 's':
601 			log_error("-n, -a, and -s have been removed.");
602 			break;
603 		// Long options
604 		case 256:
605 			// --config
606 			break;
607 		case 257:
608 			// --shadow-red
609 			opt->shadow_red = atof(optarg);
610 			break;
611 		case 258:
612 			// --shadow-green
613 			opt->shadow_green = atof(optarg);
614 			break;
615 		case 259:
616 			// --shadow-blue
617 			opt->shadow_blue = atof(optarg);
618 			break;
619 		P_CASEBOOL(260, inactive_opacity_override);
620 		case 261:
621 			// --inactive-dim
622 			opt->inactive_dim = atof(optarg);
623 			break;
624 		P_CASEBOOL(262, mark_wmwin_focused);
625 		case 263:
626 			// --shadow-exclude
627 			condlst_add(&opt->shadow_blacklist, optarg);
628 			break;
629 		P_CASEBOOL(264, mark_ovredir_focused);
630 		P_CASEBOOL(265, no_fading_openclose);
631 		P_CASEBOOL(266, shadow_ignore_shaped);
632 		P_CASEBOOL(267, detect_rounded_corners);
633 		P_CASEBOOL(268, detect_client_opacity);
634 		P_CASEINT(269, refresh_rate);
635 		case 270:
636 			if (optarg) {
637 				opt->vsync = parse_vsync(optarg);
638 				log_warn("--vsync doesn't take argument anymore. \"%s\" "
639 					 "is interpreted as \"%s\" for compatibility, but "
640 					 "this will stop working soon",
641 					 optarg, opt->vsync ? "true" : "false");
642 			} else {
643 				opt->vsync = true;
644 			}
645 			break;
646 		case 271:
647 			// --alpha-step
648 			log_error("--alpha-step has been removed, we now tries to "
649 			         "make use of all alpha values");
650 			return false;
651 		case 272: log_error("use of --dbe is deprecated"); return false;
652 		case 273:
653 			log_error("--paint-on-overlay has been removed, the feature is enabled "
654 			         "whenever possible");
655 			return false;
656 		P_CASEBOOL(274, sw_opti);
657 		case 275:
658 			// --vsync-aggressive
659 			log_warn("--vsync-aggressive has been deprecated, please remove it"
660 			         " from the command line options");
661 			break;
662 		P_CASEBOOL(276, use_ewmh_active_win);
663 		case 277:
664 			// --respect-prop-shadow
665 			log_warn("--respect-prop-shadow option has been deprecated, its "
666 			         "functionality will always be enabled. Please remove it "
667 			         "from the command line options");
668 			break;
669 		P_CASEBOOL(278, unredir_if_possible);
670 		case 279:
671 			// --focus-exclude
672 			condlst_add(&opt->focus_blacklist, optarg);
673 			break;
674 		P_CASEBOOL(280, inactive_dim_fixed);
675 		P_CASEBOOL(281, detect_transient);
676 		P_CASEBOOL(282, detect_client_leader);
677 		case 283:
678 			// --blur_background
679 			opt->blur_method = BLUR_METHOD_KERNEL;
680 			break;
681 		P_CASEBOOL(284, blur_background_frame);
682 		P_CASEBOOL(285, blur_background_fixed);
683 		P_CASEBOOL(286, dbus);
684 		case 287:
685 			log_warn("Please use --log-file instead of --logpath");
686 			// fallthrough
687 		case 322:
688 			// --logpath, --log-file
689 			free(opt->logpath);
690 			opt->logpath = strdup(optarg);
691 			break;
692 		case 288:
693 			// --invert-color-include
694 			condlst_add(&opt->invert_color_list, optarg);
695 			break;
696 		case 289:
697 			// --opengl
698 			opt->backend = BKEND_GLX;
699 			break;
700 		case 290:
701 			// --backend
702 			opt->backend = parse_backend(optarg);
703 			if (opt->backend >= NUM_BKEND)
704 				exit(1);
705 			break;
706 		P_CASEBOOL(291, glx_no_stencil);
707 		P_CASEINT(293, benchmark);
708 		case 294:
709 			// --benchmark-wid
710 			opt->benchmark_wid = (xcb_window_t)strtol(optarg, NULL, 0);
711 			break;
712 		case 296:
713 			// --blur-background-exclude
714 			condlst_add(&opt->blur_background_blacklist, optarg);
715 			break;
716 		case 297:
717 			// --active-opacity
718 			opt->active_opacity = normalize_d(atof(optarg));
719 			break;
720 		P_CASEBOOL(298, glx_no_rebind_pixmap);
721 		case 299: {
722 			// --glx-swap-method
723 			char *endptr;
724 			long tmpval = strtol(optarg, &endptr, 10);
725 			bool should_remove = true;
726 			if (*endptr || !(*optarg)) {
727 				// optarg is not a number, or an empty string
728 				tmpval = -1;
729 			}
730 			if (strcmp(optarg, "undefined") != 0 && tmpval != 0) {
731 				// If not undefined, we will use damage and buffer-age to
732 				// limit the rendering area.
733 				opt->use_damage = true;
734 				should_remove = false;
735 			}
736 			log_warn("--glx-swap-method has been deprecated, your setting "
737 			         "\"%s\" should be %s.",
738 			         optarg,
739 			         !should_remove ? "replaced by `--use-damage`" :
740 			                         "removed");
741 			break;
742 		}
743 		case 300:
744 			// --fade-exclude
745 			condlst_add(&opt->fade_blacklist, optarg);
746 			break;
747 		case 301:
748 			// --blur-kern
749 			opt->blur_kerns = parse_blur_kern_lst(optarg, &conv_kern_hasneg,
750 			                                      &opt->blur_kernel_count);
751 			if (!opt->blur_kerns) {
752 				exit(1);
753 			}
754 			break;
755 		P_CASEINT(302, resize_damage);
756 		case 303:
757 			// --glx-use-gpushader4
758 			log_warn("--glx-use-gpushader4 is deprecated since v6."
759 			         " Please remove it from command line options.");
760 			break;
761 		case 304:
762 			// --opacity-rule
763 			if (!parse_rule_opacity(&opt->opacity_rules, optarg))
764 				exit(1);
765 			break;
766 		case 305:
767 			// --shadow-exclude-reg
768 			free(opt->shadow_exclude_reg_str);
769 			opt->shadow_exclude_reg_str = strdup(optarg);
770 			log_warn("--shadow-exclude-reg is deprecated. You are likely "
771 			         "better off using --shadow-exclude anyway");
772 			break;
773 		case 306:
774 			// --paint-exclude
775 			condlst_add(&opt->paint_blacklist, optarg);
776 			break;
777 		P_CASEBOOL(307, xinerama_shadow_crop);
778 		case 308:
779 			// --unredir-if-possible-exclude
780 			condlst_add(&opt->unredir_if_possible_blacklist, optarg);
781 			break;
782 		P_CASELONG(309, unredir_if_possible_delay);
783 		case 310:
784 			// --write-pid-path
785 			free(opt->write_pid_path);
786 			opt->write_pid_path = strdup(optarg);
787 			if (*opt->write_pid_path != '/') {
788 				log_warn("--write-pid-path is not an absolute path");
789 			}
790 			break;
791 		P_CASEBOOL(311, vsync_use_glfinish);
792 		case 312:
793 			// --xrender-sync
794 			log_error("Please use --xrender-sync-fence instead of --xrender-sync");
795 			return false;
796 		P_CASEBOOL(313, xrender_sync_fence);
797 		P_CASEBOOL(315, no_fading_destroyed_argb);
798 		P_CASEBOOL(316, force_win_blend);
799 		case 317:
800 			opt->glx_fshader_win_str = strdup(optarg);
801 			break;
802 		case 321: {
803 			enum log_level tmp_level = string_to_log_level(optarg);
804 			if (tmp_level == LOG_LEVEL_INVALID) {
805 				log_warn("Invalid log level, defaults to WARN");
806 			} else {
807 				log_set_level_tls(tmp_level);
808 			}
809 			break;
810 		}
811 		P_CASEBOOL(319, no_x_selection);
812 		P_CASEBOOL(323, use_damage);
813 		case 324:
814 			opt->use_damage = false;
815 			break;
816 		case 325:
817 			opt->vsync = false;
818 			break;
819 
820 		case 326:
821 			opt->max_brightness = atof(optarg);
822 			break;
823 		P_CASEBOOL(327, transparent_clipping);
824 		case 328: {
825 			// --blur-method
826 			enum blur_method method = parse_blur_method(optarg);
827 			if (method >= BLUR_METHOD_INVALID) {
828 				log_warn("Invalid blur method %s, ignoring.", optarg);
829 			} else {
830 				opt->blur_method = method;
831 			}
832 			break;
833 		}
834 		case 329:
835 			// --blur-size
836 			opt->blur_radius = atoi(optarg);
837 			break;
838 		case 330:
839 			// --blur-deviation
840 			opt->blur_deviation = atof(optarg);
841 			break;
842 
843 		P_CASEBOOL(733, experimental_backends);
844 		P_CASEBOOL(800, monitor_repaint);
845 		case 801: opt->print_diagnostics = true; break;
846 		P_CASEBOOL(802, debug_mode);
847 		P_CASEBOOL(803, no_ewmh_fullscreen);
848 		default: usage(argv[0], 1); break;
849 #undef P_CASEBOOL
850 		}
851 		// clang-format on
852 	}
853 
854 	// Restore LC_NUMERIC
855 	setlocale(LC_NUMERIC, lc_numeric_old);
856 	free(lc_numeric_old);
857 
858 	if (opt->monitor_repaint && opt->backend != BKEND_XRENDER &&
859 	    !opt->experimental_backends) {
860 		log_warn("--monitor-repaint has no effect when backend is not xrender");
861 	}
862 
863 	if (opt->experimental_backends && !backend_list[opt->backend]) {
864 		log_error("Backend \"%s\" is not available as part of the experimental "
865 		          "backends.",
866 		          BACKEND_STRS[opt->backend]);
867 		return false;
868 	}
869 
870 	if (opt->debug_mode && !opt->experimental_backends) {
871 		log_error("Debug mode only works with the experimental backends.");
872 		return false;
873 	}
874 
875 	if (opt->transparent_clipping && !opt->experimental_backends) {
876 		log_error("Transparent clipping only works with the experimental "
877 		          "backends");
878 		return false;
879 	}
880 
881 	// Range checking and option assignments
882 	opt->fade_delta = max2(opt->fade_delta, 1);
883 	opt->shadow_radius = max2(opt->shadow_radius, 0);
884 	opt->shadow_red = normalize_d(opt->shadow_red);
885 	opt->shadow_green = normalize_d(opt->shadow_green);
886 	opt->shadow_blue = normalize_d(opt->shadow_blue);
887 	opt->inactive_dim = normalize_d(opt->inactive_dim);
888 	opt->frame_opacity = normalize_d(opt->frame_opacity);
889 	opt->shadow_opacity = normalize_d(opt->shadow_opacity);
890 	opt->refresh_rate = normalize_i_range(opt->refresh_rate, 0, 300);
891 
892 	opt->max_brightness = normalize_d(opt->max_brightness);
893 	if (opt->max_brightness < 1.0) {
894 		if (opt->use_damage) {
895 			log_warn("--max-brightness requires --no-use-damage. Falling "
896 			         "back to 1.0");
897 			opt->max_brightness = 1.0;
898 		}
899 
900 		if (!opt->experimental_backends || opt->backend != BKEND_GLX) {
901 			log_warn("--max-brightness requires the experimental glx "
902 			         "backend. Falling back to 1.0");
903 			opt->max_brightness = 1.0;
904 		}
905 	}
906 
907 	// Apply default wintype options that are dependent on global options
908 	set_default_winopts(opt, winopt_mask, shadow_enable, fading_enable);
909 
910 	// --blur-background-frame implies --blur-background
911 	if (opt->blur_background_frame && opt->blur_method == BLUR_METHOD_NONE) {
912 		opt->blur_method = BLUR_METHOD_KERNEL;
913 	}
914 
915 	// Other variables determined by options
916 
917 	// Determine whether we track window grouping
918 	if (opt->detect_transient || opt->detect_client_leader) {
919 		opt->track_leader = true;
920 	}
921 
922 	// Fill default blur kernel
923 	if (opt->blur_method == BLUR_METHOD_KERNEL &&
924 	    (!opt->blur_kerns || !opt->blur_kerns[0])) {
925 		opt->blur_kerns = parse_blur_kern_lst("3x3box", &conv_kern_hasneg,
926 		                                      &opt->blur_kernel_count);
927 		CHECK(opt->blur_kerns);
928 		CHECK(opt->blur_kernel_count);
929 	}
930 
931 	if (opt->resize_damage < 0) {
932 		log_warn("Negative --resize-damage will not work correctly.");
933 	}
934 
935 	if (opt->backend == BKEND_XRENDER && conv_kern_hasneg) {
936 		log_warn("A convolution kernel with negative values may not work "
937 		         "properly under X Render backend.");
938 	}
939 
940 	return true;
941 }
942 
943 // vim: set noet sw=8 ts=8 :
944