2018-12-20 21:57:32 +00:00
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
# include <getopt.h>
# include <locale.h>
# include <stdbool.h>
2019-01-20 21:15:20 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2022-08-21 14:07:44 +00:00
# include <sys/ioctl.h>
# include <termios.h>
2018-12-20 21:57:32 +00:00
# include <unistd.h>
2019-01-29 23:36:34 +00:00
# include <xcb/render.h> // for xcb_render_fixed_t, XXX
2018-12-20 21:57:32 +00:00
2019-11-10 04:59:55 +00:00
# include "backend/backend.h"
2018-12-20 21:57:32 +00:00
# include "common.h"
2019-01-20 21:15:20 +00:00
# include "config.h"
2019-01-20 16:53:39 +00:00
# include "log.h"
2019-01-20 21:15:20 +00:00
# include "options.h"
2024-05-12 14:12:47 +00:00
# include "string_utils.h"
2019-01-20 16:53:39 +00:00
# include "utils.h"
# include "win.h"
2024-02-19 23:30:53 +00:00
# include "x.h"
2018-12-21 16:25:28 +00:00
# pragma GCC diagnostic error "-Wunused-parameter"
2018-12-20 21:57:32 +00:00
2024-05-12 14:12:47 +00:00
struct picom_option ;
struct picom_arg {
const char * name ;
ptrdiff_t offset ;
const void * user_data ;
bool ( * handler ) ( const struct picom_option * , const struct picom_arg * ,
const char * optarg , void * output ) ;
} ;
struct picom_arg_parser {
int ( * parse ) ( const char * ) ;
int invalid_value ;
} ;
struct picom_rules_parser {
void * ( * parse_prefix ) ( const char * , const char * * end , void * data ) ;
void ( * free_value ) ( void * ) ;
void * user_data ;
} ;
struct picom_deprecated_arg {
const char * message ;
struct picom_arg inner ;
bool error ;
} ;
2022-08-21 14:07:44 +00:00
struct picom_option {
const char * long_name ;
int has_arg ;
2024-05-12 14:12:47 +00:00
struct picom_arg arg ;
2022-08-21 14:07:44 +00:00
const char * help ;
} ;
2024-05-12 14:12:47 +00:00
static bool set_flag ( const struct picom_option * /*opt*/ , const struct picom_arg * arg ,
const char * /*arg_str*/ , void * output ) {
* ( bool * ) ( output + arg - > offset ) = true ;
return true ;
}
static bool unset_flag ( const struct picom_option * /*opt*/ , const struct picom_arg * arg ,
const char * /*arg_str*/ , void * output ) {
* ( bool * ) ( output + arg - > offset ) = false ;
return true ;
}
static bool parse_with ( const struct picom_option * opt , const struct picom_arg * arg ,
const char * arg_str , void * output ) {
const struct picom_arg_parser * parser = arg - > user_data ;
int * dst = ( int * ) ( output + arg - > offset ) ;
* dst = parser - > parse ( arg_str ) ;
if ( * dst = = parser - > invalid_value ) {
log_error ( " Invalid argument for option `--%s`: %s " , opt - > long_name , arg_str ) ;
return false ;
}
return true ;
}
static bool store_float ( const struct picom_option * opt , const struct picom_arg * arg ,
const char * arg_str , void * output ) {
double * dst = ( double * ) ( output + arg - > offset ) ;
const double * minmax = ( const double * ) arg - > user_data ;
const char * endptr = NULL ;
* dst = strtod_simple ( arg_str , & endptr ) ;
if ( ! endptr | | * endptr ! = ' \0 ' ) {
log_error ( " Argument for option `--%s` is not a valid float number: %s " ,
opt - > long_name , arg_str ) ;
return false ;
}
* dst = max2 ( minmax [ 0 ] , min2 ( * dst , minmax [ 1 ] ) ) ;
return true ;
}
static bool store_int ( const struct picom_option * opt , const struct picom_arg * arg ,
const char * arg_str , void * output ) {
const int * minmax = ( const int * ) arg - > user_data ;
int * dst = ( int * ) ( output + arg - > offset ) ;
if ( ! parse_int ( arg_str , dst ) ) {
log_error ( " Argument for option `--%s` is not a valid integer: %s " ,
opt - > long_name , arg_str ) ;
return false ;
}
* dst = max2 ( minmax [ 0 ] , min2 ( * dst , minmax [ 1 ] ) ) ;
return true ;
}
static bool store_string ( const struct picom_option * /*opt*/ , const struct picom_arg * arg ,
const char * arg_str , void * output ) {
char * * dst = ( char * * ) ( output + arg - > offset ) ;
free ( * dst ) ;
* dst = strdup ( arg_str ) ;
return true ;
}
static bool store_rules ( const struct picom_option * /*opt*/ , const struct picom_arg * arg ,
const char * arg_str , void * output ) {
const struct picom_rules_parser * parser = arg - > user_data ;
auto rules = ( c2_lptr_t * * ) ( output + arg - > offset ) ;
if ( ! parser - > parse_prefix ) {
return c2_parse ( rules , arg_str , NULL ) ! = NULL ;
}
return c2_parse_with_prefix ( rules , arg_str , parser - > parse_prefix ,
parser - > free_value , parser - > user_data ) ;
}
static bool store_fixed_enum ( const struct picom_option * /*opt*/ , const struct picom_arg * arg ,
const char * /*arg_str*/ , void * output ) {
const int * value = ( const int * ) arg - > user_data ;
* ( int * ) ( output + arg - > offset ) = * value ;
return true ;
}
static bool noop ( const struct picom_option * /*opt*/ , const struct picom_arg * /*arg*/ ,
const char * /*arg_str*/ , void * /*output*/ ) {
return true ;
}
static bool reject ( const struct picom_option * /*opt*/ , const struct picom_arg * /*arg*/ ,
const char * /*arg_str*/ , void * /*output*/ ) {
return false ;
}
static bool say_deprecated ( const struct picom_option * opt , const struct picom_arg * arg ,
const char * arg_str , void * output ) {
const struct picom_deprecated_arg * deprecation = arg - > user_data ;
enum log_level level = deprecation - > error ? LOG_LEVEL_ERROR : LOG_LEVEL_WARN ;
log_printf ( tls_logger , level , __func__ ,
" Option `--%s` has been deprecated. Please remove it. %s " ,
opt - > long_name , deprecation - > message ) ;
return deprecation - > inner . handler ( opt , & deprecation - > inner , arg_str , output ) ;
}
# define OFFSET(member) offsetof(struct options, member)
# define ENABLE(member) \
no_argument , { \
. offset = OFFSET ( member ) , . handler = set_flag , \
}
# define DISABLE(member) \
no_argument , { \
. offset = OFFSET ( member ) , . handler = unset_flag , \
}
# define IGNORE(has_arg) \
has_arg , { \
. handler = noop , \
}
# define REJECT(has_arg) \
has_arg , { \
. handler = reject , \
}
# define DO(fn) \
required_argument , { \
. handler = ( fn ) , \
}
# define PARSE_WITH(fn, invalid, member) \
required_argument , { \
. offset = OFFSET ( member ) , . handler = parse_with , \
. user_data = ( struct picom_arg_parser [ ] ) { { \
. invalid_value = ( invalid ) , \
. parse = ( fn ) , \
} } , \
}
# define FLOAT(member, min, max) \
required_argument , { \
. offset = OFFSET ( member ) , . handler = store_float , \
. user_data = ( double [ ] ) { min , max } , \
}
# define INTEGER(member, min, max) \
required_argument , { \
. offset = OFFSET ( member ) , . handler = store_int , \
. user_data = ( int [ ] ) { min , max } , \
}
# define NAMED_STRING(member, name_) \
required_argument , { \
. offset = OFFSET ( member ) , . handler = store_string , . name = ( name_ ) \
}
# define STRING(member) NAMED_STRING(member, NULL)
# define NAMED_RULES(member, name_, ...) \
required_argument , { \
. offset = OFFSET ( member ) , . handler = store_rules , . name = ( name_ ) , \
. user_data = ( struct picom_rules_parser [ ] ) { \
__VA_ARGS__ \
} \
}
# define NUMERIC_RULES(member, value, min, max) \
NAMED_RULES ( member , value " :COND " , \
{ . parse_prefix = parse_numeric_prefix , . user_data = ( int [ ] ) { min , max } } )
# define RULES(member) NAMED_RULES(member, "COND", {})
# define FIXED(member, value) \
no_argument , { \
. offset = OFFSET ( member ) , . handler = store_fixed_enum , \
. user_data = ( int [ ] ) { value } , \
}
# define SAY_DEPRECATED_(error_, msg, has_arg, ...) \
has_arg , { \
. handler = say_deprecated , . user_data = ( struct picom_deprecated_arg [ ] ) { \
{ . message = ( msg ) , . inner = __VA_ARGS__ , . error = error_ } , \
} \
}
# define SAY_DEPRECATED(error_, msg, ...) SAY_DEPRECATED_(error_, msg, __VA_ARGS__)
# define WARN_DEPRECATED(...) \
SAY_DEPRECATED_ ( false , \
" If you encounter problems without this feature, please " \
" feel free to open a bug report. " , \
__VA_ARGS__ )
# define WARN_DEPRECATED_ENABLED(...) \
SAY_DEPRECATED_ ( false , " Its functionality will always be enabled. " , __VA_ARGS__ )
# define ERROR_DEPRECATED(has_arg) SAY_DEPRECATED(true, "", REJECT(has_arg))
static bool
store_shadow_color ( const struct picom_option * /*opt*/ , const struct picom_arg * /*arg*/ ,
const char * arg_str , void * output ) {
struct options * opt = ( struct options * ) output ;
struct color rgb ;
rgb = hex_to_rgb ( arg_str ) ;
opt - > shadow_red = rgb . red ;
opt - > shadow_green = rgb . green ;
opt - > shadow_blue = rgb . blue ;
return true ;
}
static bool
handle_menu_opacity ( const struct picom_option * /*opt*/ , const struct picom_arg * /*arg*/ ,
const char * arg_str , void * output ) {
struct options * opt = ( struct options * ) output ;
const char * endptr = NULL ;
double tmp = max2 ( 0.0 , min2 ( 1.0 , strtod_simple ( arg_str , & endptr ) ) ) ;
if ( ! endptr | | * endptr ! = ' \0 ' ) {
return false ;
}
opt - > wintype_option_mask [ WINTYPE_DROPDOWN_MENU ] . opacity = true ;
opt - > wintype_option_mask [ WINTYPE_POPUP_MENU ] . opacity = true ;
opt - > wintype_option [ WINTYPE_POPUP_MENU ] . opacity = tmp ;
opt - > wintype_option [ WINTYPE_DROPDOWN_MENU ] . opacity = tmp ;
return true ;
}
static bool
store_blur_kern ( const struct picom_option * /*opt*/ , const struct picom_arg * /*arg*/ ,
const char * arg_str , void * output ) {
struct options * opt = ( struct options * ) output ;
opt - > blur_kerns = parse_blur_kern_lst ( arg_str , & opt - > blur_kernel_count ) ;
return opt - > blur_kerns ! = NULL ;
}
static bool
store_benchmark_wid ( const struct picom_option * /*opt*/ , const struct picom_arg * /*arg*/ ,
const char * arg_str , void * output ) {
struct options * opt = ( struct options * ) output ;
const char * endptr = NULL ;
opt - > benchmark_wid = ( xcb_window_t ) strtoul ( arg_str , ( char * * ) & endptr , 0 ) ;
if ( ! endptr | | * endptr ! = ' \0 ' ) {
log_error ( " Invalid window ID for `--benchmark-wid`: %s " , arg_str ) ;
return false ;
}
return true ;
}
# define WINDOW_SHADER_RULE \
{ . parse_prefix = parse_window_shader_prefix_with_cwd , . free_value = free , }
# ifdef CONFIG_OPENGL
# define BACKENDS "xrender, glx"
# else
# define BACKENDS "xrender"
# endif
2022-08-21 14:07:44 +00:00
// clang-format off
static const struct option * longopts = NULL ;
static const struct picom_option picom_options [ ] = {
2024-05-12 14:12:47 +00:00
// As you can see, aligning this table is difficult...
// Rejected options, we shouldn't be able to reach `get_cfg` when these are set
[ ' h ' ] = { " help " , REJECT ( no_argument ) , " Print this help message and exit. " } ,
[ 318 ] = { " version " , REJECT ( no_argument ) , " Print version number and exit. " } ,
// Ignored options, these are already handled by `get_early_cfg`
[ 314 ] = { " show-all-xerrors " , IGNORE ( no_argument ) } ,
[ ' b ' ] = { " daemon " , IGNORE ( no_argument ) , " Daemonize process. " } ,
[ 256 ] = { " config " , IGNORE ( required_argument ) , " Path to the configuration file. " } ,
// Simple flags
[ ' c ' ] = { " shadow " , ENABLE ( shadow_enable ) , " Enabled client-side shadows on windows. " } ,
[ ' f ' ] = { " fading " , ENABLE ( fading_enable ) , " Fade windows in/out when opening/closing and when opacity changes, "
2022-08-21 14:07:44 +00:00
" unless --no-fading-openclose is used. " } ,
2024-05-12 14:12:47 +00:00
[ 262 ] = { " mark-wmwin-focused " , ENABLE ( mark_wmwin_focused ) , " Try to detect WM windows and mark them as active. " } ,
[ 264 ] = { " mark-ovredir-focused " , ENABLE ( mark_ovredir_focused ) , " Mark windows that have no WM frame as active. " } ,
[ 265 ] = { " no-fading-openclose " , ENABLE ( no_fading_openclose ) , " Do not fade on window open/close. " } ,
[ 266 ] = { " shadow-ignore-shaped " , ENABLE ( shadow_ignore_shaped ) , " Do not paint shadows on shaped windows. (Deprecated, use --shadow-exclude "
2022-08-21 14:07:44 +00:00
" \' bounding_shaped \' or --shadow-exclude \' bounding_shaped && "
" !rounded_corners \' instead.) " } ,
2024-05-12 14:12:47 +00:00
[ 268 ] = { " detect-client-opacity " , ENABLE ( detect_client_opacity ) , " Detect _NET_WM_WINDOW_OPACITY on client windows, useful for window "
2022-08-21 14:07:44 +00:00
" managers not passing _NET_WM_WINDOW_OPACITY of client windows to frame " } ,
2024-05-12 14:12:47 +00:00
[ 270 ] = { " vsync " , ENABLE ( vsync ) , " Enable VSync " } ,
[ 271 ] = { " crop-shadow-to-monitor " , ENABLE ( crop_shadow_to_monitor ) , " Crop shadow of a window fully on a particular monitor to that monitor. "
2023-01-13 11:27:45 +00:00
" This is currently implemented using the X RandR extension " } ,
2024-05-12 14:12:47 +00:00
[ 276 ] = { " use-ewmh-active-win " , ENABLE ( use_ewmh_active_win ) , " Use _NET_WM_ACTIVE_WINDOW on the root window to determine which window is "
2022-08-21 14:07:44 +00:00
" focused instead of using FocusIn/Out events " } ,
2024-05-12 14:12:47 +00:00
[ 278 ] = { " unredir-if-possible " , ENABLE ( unredir_if_possible ) , " Unredirect all windows if a full-screen opaque window is detected, to "
2022-08-21 14:07:44 +00:00
" maximize performance for full-screen applications. " } ,
2024-05-12 14:12:47 +00:00
[ 280 ] = { " inactive-dim-fixed " , ENABLE ( inactive_dim_fixed ) , " Use fixed inactive dim value. " } ,
[ 281 ] = { " detect-transient " , ENABLE ( detect_transient ) , " Use WM_TRANSIENT_FOR to group windows, and consider windows in the same "
2022-08-21 14:07:44 +00:00
" group focused at the same time. " } ,
2024-05-12 14:12:47 +00:00
[ 282 ] = { " detect-client-leader " , ENABLE ( detect_client_leader ) , " Use WM_CLIENT_LEADER to group windows, and consider windows in the same group "
2022-08-21 14:07:44 +00:00
" focused at the same time. This usually means windows from the same application "
" will be considered focused or unfocused at the same time. WM_TRANSIENT_FOR has "
" higher priority if --detect-transient is enabled, too. " } ,
2024-05-12 14:12:47 +00:00
[ 284 ] = { " blur-background-frame " , ENABLE ( blur_background_frame ) , " Blur background of windows when the window frame is not opaque. Implies "
2022-08-21 14:07:44 +00:00
" --blur-background. " } ,
2024-05-12 14:12:47 +00:00
[ 285 ] = { " blur-background-fixed " , ENABLE ( blur_background_fixed ) , " Use fixed blur strength instead of adjusting according to window opacity. " } ,
2022-08-21 14:07:44 +00:00
# ifdef CONFIG_DBUS
2024-05-12 14:12:47 +00:00
[ 286 ] = { " dbus " , ENABLE ( dbus ) , " Enable remote control via D-Bus. See the D-BUS API section in the man page "
2022-08-21 14:07:44 +00:00
" for more details. " } ,
# endif
2024-05-12 14:12:47 +00:00
[ 311 ] = { " vsync-use-glfinish " , ENABLE ( vsync_use_glfinish ) } ,
[ 313 ] = { " xrender-sync-fence " , ENABLE ( xrender_sync_fence ) , " Additionally use X Sync fence to sync clients' draw calls. Needed on "
2022-08-21 14:07:44 +00:00
" nvidia-drivers with GLX backend for some users. " } ,
2024-05-12 14:12:47 +00:00
[ 315 ] = { " no-fading-destroyed-argb " , ENABLE ( no_fading_destroyed_argb ) , " Do not fade destroyed ARGB windows with WM frame. Workaround bugs in Openbox, "
2022-08-21 14:07:44 +00:00
" Fluxbox, etc. " } ,
2024-05-12 14:12:47 +00:00
[ 316 ] = { " force-win-blend " , ENABLE ( force_win_blend ) , " Force all windows to be painted with blending. Useful if you have a custom "
2022-08-21 14:07:44 +00:00
" shader that could turn opaque pixels transparent. " } ,
2024-05-12 14:12:47 +00:00
[ 319 ] = { " no-x-selection " , ENABLE ( no_x_selection ) } ,
[ 323 ] = { " use-damage " , ENABLE ( use_damage ) , " Render only the damaged (changed) part of the screen " } ,
[ 324 ] = { " no-use-damage " , DISABLE ( use_damage ) , " Disable the use of damage information. This cause the whole screen to be "
2022-11-16 15:39:17 +00:00
" redrawn every time, instead of the part of the screen that has actually "
2022-08-21 14:07:44 +00:00
" changed. Potentially degrades the performance, but might fix some artifacts. " } ,
2024-05-12 14:12:47 +00:00
[ 260 ] = { " inactive-opacity-override " , ENABLE ( inactive_opacity_override ) , " Inactive opacity set by -i overrides value of _NET_WM_WINDOW_OPACITY. " } ,
[ 267 ] = { " detect-rounded-corners " , ENABLE ( detect_rounded_corners ) , " Try to detect windows with rounded corners and don't consider them shaped "
" windows. Affects --shadow-ignore-shaped, --unredir-if-possible, and "
" possibly others. You need to turn this on manually if you want to match "
" against rounded_corners in conditions. " } ,
[ 298 ] = { " glx-no-rebind-pixmap " , ENABLE ( glx_no_rebind_pixmap ) } ,
[ 291 ] = { " glx-no-stencil " , ENABLE ( glx_no_stencil ) } ,
[ 325 ] = { " no-vsync " , DISABLE ( vsync ) , " Disable VSync " } ,
[ 327 ] = { " transparent-clipping " , ENABLE ( transparent_clipping ) , " Make transparent windows clip other windows like non-transparent windows do, "
2022-08-21 14:07:44 +00:00
" instead of blending on top of them " } ,
2024-05-12 14:12:47 +00:00
[ 339 ] = { " dithered-present " , ENABLE ( dithered_present ) , " Use higher precision during rendering, and apply dither when presenting the "
2022-11-30 05:28:57 +00:00
" rendered screen. Reduces banding artifacts, but might cause performance "
" degradation. Only works with OpenGL. " } ,
2024-05-12 14:12:47 +00:00
[ 341 ] = { " no-frame-pacing " , DISABLE ( frame_pacing ) , " Disable frame pacing. This might increase the latency. " } ,
[ 733 ] = { " legacy-backends " , ENABLE ( legacy_backends ) , " Use deprecated version of the backends. " } ,
[ 800 ] = { " monitor-repaint " , ENABLE ( monitor_repaint ) , " Highlight the updated area of the screen. For debugging. " } ,
[ 801 ] = { " diagnostics " , ENABLE ( print_diagnostics ) , " Print diagnostic information " } ,
[ 802 ] = { " debug-mode " , ENABLE ( debug_mode ) , " Render into a separate window, and don't take over the screen. Useful when "
2022-08-21 14:07:44 +00:00
" you want to attach a debugger to picom " } ,
2024-05-12 14:12:47 +00:00
[ 803 ] = { " no-ewmh-fullscreen " , ENABLE ( no_ewmh_fullscreen ) , " Do not use EWMH to detect fullscreen windows. Reverts to checking if a "
2022-08-21 14:07:44 +00:00
" window is fullscreen based only on its size and coordinates. " } ,
2024-05-12 14:12:47 +00:00
[ 804 ] = { " realtime " , ENABLE ( use_realtime_scheduling ) , " Enable realtime scheduling. This might reduce latency, but might also cause "
2024-03-03 01:24:26 +00:00
" other issues. Disable this if you see the compositor being killed. " } ,
2024-05-12 14:12:47 +00:00
// Flags that takes an argument
[ ' r ' ] = { " shadow-radius " , INTEGER ( shadow_radius , 0 , INT_MAX ) , " The blur radius for shadows. (default 12) " } ,
[ ' o ' ] = { " shadow-opacity " , FLOAT ( shadow_opacity , 0 , 1 ) , " The translucency for shadows. (default .75) " } ,
[ ' l ' ] = { " shadow-offset-x " , INTEGER ( shadow_offset_x , INT_MIN , INT_MAX ) , " The left offset for shadows. (default -15) " } ,
[ ' t ' ] = { " shadow-offset-y " , INTEGER ( shadow_offset_y , INT_MIN , INT_MAX ) , " The top offset for shadows. (default -15) " } ,
[ ' I ' ] = { " fade-in-step " , FLOAT ( fade_in_step , 0 , 1 ) , " Opacity change between steps while fading in. (default 0.028) " } ,
[ ' O ' ] = { " fade-out-step " , FLOAT ( fade_out_step , 0 , 1 ) , " Opacity change between steps while fading out. (default 0.03) " } ,
[ ' D ' ] = { " fade-delta " , INTEGER ( fade_delta , 1 , INT_MAX ) , " The time between steps in a fade in milliseconds. (default 10) " } ,
[ ' i ' ] = { " inactive-opacity " , FLOAT ( inactive_opacity , 0 , 1 ) , " Opacity of inactive windows. (0.0 - 1.0) " } ,
[ ' e ' ] = { " frame-opacity " , FLOAT ( frame_opacity , 0 , 1 ) , " Opacity of window titlebars and borders. (0.0 - 1.0) " } ,
[ 257 ] = { " shadow-red " , FLOAT ( shadow_red , 0 , 1 ) , " Red color value of shadow (0.0 - 1.0, defaults to 0). " } ,
[ 258 ] = { " shadow-green " , FLOAT ( shadow_green , 0 , 1 ) , " Green color value of shadow (0.0 - 1.0, defaults to 0). " } ,
[ 259 ] = { " shadow-blue " , FLOAT ( shadow_blue , 0 , 1 ) , " Blue color value of shadow (0.0 - 1.0, defaults to 0). " } ,
[ 261 ] = { " inactive-dim " , FLOAT ( inactive_dim , 0 , 1 ) , " Dim inactive windows. (0.0 - 1.0, defaults to 0) " } ,
[ 283 ] = { " blur-background " , FIXED ( blur_method , BLUR_METHOD_KERNEL ) , " Blur background of semi-transparent / ARGB windows. May impact performance " } ,
[ 290 ] = { " backend " , PARSE_WITH ( parse_backend , NUM_BKEND , backend ) , " Backend. Possible values are: " BACKENDS } ,
[ 293 ] = { " benchmark " , INTEGER ( benchmark , 0 , INT_MAX ) , " Benchmark mode. Repeatedly paint until reaching the specified cycles. " } ,
[ 297 ] = { " active-opacity " , FLOAT ( active_opacity , 0 , 1 ) , " Default opacity for active windows. (0.0 - 1.0) " } ,
[ 302 ] = { " resize-damage " , INTEGER ( resize_damage , INT_MIN , INT_MAX ) } , // only used by legacy backends
[ 309 ] = { " unredir-if-possible-delay " , INTEGER ( unredir_if_possible_delay , 0 , INT_MAX ) , " Delay before unredirecting the window, in milliseconds. Defaults to 0. " } ,
[ 310 ] = { " write-pid-path " , NAMED_STRING ( write_pid_path , " PATH " ) , " Write process ID to a file. " } ,
[ 317 ] = { " glx-fshader-win " , STRING ( glx_fshader_win_str ) } ,
[ 322 ] = { " log-file " , STRING ( logpath ) , " Path to the log file. " } ,
[ 326 ] = { " max-brightness " , FLOAT ( max_brightness , 0 , 1 ) , " Dims windows which average brightness is above this threshold. Requires "
" --no-use-damage. (default: 1.0, meaning no dimming) " } ,
[ 329 ] = { " blur-size " , INTEGER ( blur_radius , 0 , INT_MAX ) , " The radius of the blur kernel for 'box' and 'gaussian' blur method. " } ,
[ 330 ] = { " blur-deviation " , FLOAT ( blur_deviation , 0 , INFINITY ) , " The standard deviation for the 'gaussian' blur method. " } ,
[ 331 ] = { " blur-strength " , INTEGER ( blur_strength , 0 , INT_MAX ) , " The strength level of the 'dual_kawase' blur method. " } ,
[ 333 ] = { " corner-radius " , INTEGER ( corner_radius , 0 , INT_MAX ) , " Sets the radius of rounded window corners. When > 0, the compositor will "
" round the corners of windows. (defaults to 0). " } ,
[ 336 ] = { " window-shader-fg " , NAMED_STRING ( window_shader_fg , " PATH " ) , " Specify GLSL fragment shader path for rendering window contents. Does not "
" work when `--legacy-backends` is enabled. See man page for more details. " } ,
[ 294 ] = { " benchmark-wid " , DO ( store_benchmark_wid ) , " Specify window ID to repaint in benchmark mode. If omitted or is 0, the whole "
" screen is repainted. " } ,
[ 301 ] = { " blur-kern " , DO ( store_blur_kern ) , " Specify the blur convolution kernel, see man page for more details " } ,
[ 332 ] = { " shadow-color " , DO ( store_shadow_color ) , " Color of shadow, as a hex RGB string (defaults to #000000) " } ,
// Rules
[ 263 ] = { " shadow-exclude " , RULES ( shadow_blacklist ) , " Exclude conditions for shadows. " } ,
[ 279 ] = { " focus-exclude " , RULES ( focus_blacklist ) , " Specify a list of conditions of windows that should always be considered focused. " } ,
[ 288 ] = { " invert-color-include " , RULES ( invert_color_list ) , " Specify a list of conditions of windows that should be painted with "
" inverted color. " } ,
[ 296 ] = { " blur-background-exclude " , RULES ( blur_background_blacklist ) , " Exclude conditions for background blur. " } ,
[ 300 ] = { " fade-exclude " , RULES ( fade_blacklist ) , " Exclude conditions for fading. " } ,
[ 306 ] = { " paint-exclude " , RULES ( paint_blacklist ) , NULL } ,
[ 308 ] = { " unredir-if-possible-exclude " , RULES ( unredir_if_possible_blacklist ) , " Conditions of windows that shouldn't be considered full-screen for "
" unredirecting screen. " } ,
[ 334 ] = { " rounded-corners-exclude " , RULES ( rounded_corners_blacklist ) , " Exclude conditions for rounded corners. " } ,
[ 335 ] = { " clip-shadow-above " , RULES ( shadow_clip_list ) , " Specify a list of conditions of windows to not paint a shadow over, such "
" as a dock window. " } ,
[ 338 ] = { " transparent-clipping-exclude " , RULES ( transparent_clipping_blacklist ) , " Specify a list of conditions of windows that should never have "
" transparent clipping applied. Useful for screenshot tools, where you "
" need to be able to see through transparent parts of the window. " } ,
// Rules that are too long to fit in one line
[ 304 ] = { " opacity-rule " , NUMERIC_RULES ( opacity_rules , " OPACITY " , 0 , 100 ) ,
" Specify a list of opacity rules, see man page for more details " } ,
[ 337 ] = { " window-shader-fg-rule " , NAMED_RULES ( window_shader_fg_rules , " PATH " , WINDOW_SHADER_RULE ) ,
" Specify GLSL fragment shader path for rendering window contents using patterns. Pattern should be "
" in the format of SHADER_PATH:PATTERN, similar to --opacity-rule. SHADER_PATH can be \" default \" , "
" in which case the default shader will be used. Does not work when --legacy-backends is enabled. See "
" man page for more details " } ,
[ 340 ] = { " corner-radius-rules " , NUMERIC_RULES ( corner_radius_rules , " RADIUS " , 0 , INT_MAX ) ,
" Window rules for specific rounded corner radii. " } ,
// Options that are too long to fit in one line
[ 321 ] = { " log-level " , PARSE_WITH ( string_to_log_level , LOG_LEVEL_INVALID , log_level ) ,
" Log level, possible values are: trace, debug, info, warn, error " } ,
[ 328 ] = { " blur-method " , PARSE_WITH ( parse_blur_method , BLUR_METHOD_INVALID , blur_method ) ,
" The algorithm used for background bluring. Available choices are: 'none' to disable, 'gaussian', "
" 'box' or 'kernel' for custom convolution blur with --blur-kern. Note: 'gaussian' and 'box' is not "
" supported by --legacy-backends. " } ,
// Deprecated options
[ 274 ] = { " sw-opti " , ERROR_DEPRECATED ( no_argument ) } ,
[ 275 ] = { " vsync-aggressive " , ERROR_DEPRECATED ( no_argument ) } ,
[ 277 ] = { " respect-prop-shadow " , ERROR_DEPRECATED ( no_argument ) } ,
[ 303 ] = { " glx-use-gpushader4 " , ERROR_DEPRECATED ( no_argument ) } ,
[ 269 ] = { " refresh-rate " , WARN_DEPRECATED ( IGNORE ( required_argument ) ) } ,
// Deprecated options with messages
# define CLEAR_SHADOW_DEPRECATION \
" Shadows are automatically cleared now. If you want to prevent shadow from " \
" being cleared under certain types of windows, you can use the \" full-shadow \" " \
" window type option. "
# define MENU_OPACITY_DEPRECATION \
" Use the wintype option `opacity` of `popup_menu` and `dropdown_menu` instead. "
[ ' m ' ] = { " menu-opacity " , SAY_DEPRECATED ( false , MENU_OPACITY_DEPRECATION , DO ( handle_menu_opacity ) ) } ,
[ ' z ' ] = { " clear-shadow " , SAY_DEPRECATED ( false , CLEAR_SHADOW_DEPRECATION , IGNORE ( no_argument ) ) } ,
[ 272 ] = { " xinerama-shadow-crop " , SAY_DEPRECATED ( false , " Use --crop-shadow-to-monitor instead. " , ENABLE ( crop_shadow_to_monitor ) ) } ,
[ 287 ] = { " logpath " , SAY_DEPRECATED ( false , " Use --log-file instead. " , STRING ( logpath ) ) } ,
[ 289 ] = { " opengl " , SAY_DEPRECATED ( false , " Use --backend=glx instead. " , FIXED ( backend , BKEND_GLX ) ) } ,
[ 305 ] = { " shadow-exclude-reg " , SAY_DEPRECATED ( true , " Use --clip-shadow-above instead. " , REJECT ( required_argument ) ) } ,
# undef CLEAR_SHADOW_DEPRECATION
# undef MENU_OPACITY_DEPRECATION
2022-08-21 14:07:44 +00:00
} ;
// clang-format on
static void setup_longopts ( void ) {
auto opts = ccalloc ( ARR_SIZE ( picom_options ) + 1 , struct option ) ;
2024-05-12 14:12:47 +00:00
int option_count = 0 ;
2022-08-21 14:07:44 +00:00
for ( size_t i = 0 ; i < ARR_SIZE ( picom_options ) ; i + + ) {
2024-05-12 14:12:47 +00:00
if ( picom_options [ i ] . arg . handler = = NULL ) {
continue ;
}
opts [ option_count ] . name = picom_options [ i ] . long_name ;
opts [ option_count ] . has_arg = picom_options [ i ] . has_arg ;
opts [ option_count ] . flag = NULL ;
opts [ option_count ] . val = ( int ) i ;
option_count + + ;
2022-08-21 14:07:44 +00:00
}
longopts = opts ;
}
void print_help ( const char * help , size_t indent , size_t curr_indent , size_t line_wrap ,
FILE * f ) {
if ( curr_indent > indent ) {
fputs ( " \n " , f ) ;
curr_indent = 0 ;
}
if ( line_wrap - indent < = 1 ) {
line_wrap = indent + 2 ;
}
size_t pos = 0 ;
size_t len = strlen ( help ) ;
while ( pos < len ) {
fprintf ( f , " %*s " , ( int ) ( indent - curr_indent ) , " " ) ;
curr_indent = 0 ;
size_t towrite = line_wrap - indent ;
while ( help [ pos ] = = ' ' ) {
pos + + ;
}
if ( pos + towrite > len ) {
towrite = len - pos ;
fwrite ( help + pos , 1 , towrite , f ) ;
} else {
auto space_break = towrite ;
while ( space_break > 0 & & help [ pos + space_break - 1 ] ! = ' ' ) {
space_break - - ;
}
bool print_hyphen = false ;
if ( space_break = = 0 ) {
print_hyphen = true ;
towrite - - ;
} else {
towrite = space_break ;
}
fwrite ( help + pos , 1 , towrite , f ) ;
if ( print_hyphen ) {
fputs ( " - " , f ) ;
}
}
fputs ( " \n " , f ) ;
pos + = towrite ;
}
}
2018-12-20 21:57:32 +00:00
/**
2019-01-29 23:36:34 +00:00
* Print usage text .
2018-12-20 21:57:32 +00:00
*/
2019-10-23 18:27:30 +00:00
static void usage ( const char * argv0 , int ret ) {
2018-12-20 21:57:32 +00:00
FILE * f = ( ret ? stderr : stdout ) ;
2022-08-21 14:07:44 +00:00
fprintf ( f , " picom (%s) \n " , PICOM_VERSION ) ;
fprintf ( f , " Standalone X11 compositor \n " ) ;
fprintf ( f , " Please report bugs to https://github.com/yshui/picom \n \n " ) ;
fprintf ( f , " Usage: %s [OPTION]... \n \n " , argv0 ) ;
fprintf ( f , " OPTIONS: \n " ) ;
int line_wrap = 80 ;
struct winsize window_size = { 0 } ;
if ( ioctl ( fileno ( f ) , TIOCGWINSZ , & window_size ) ! = - 1 ) {
line_wrap = window_size . ws_col ;
}
size_t help_indent = 0 ;
for ( size_t i = 0 ; i < ARR_SIZE ( picom_options ) ; i + + ) {
if ( picom_options [ i ] . help = = NULL ) {
// Hide options with no help message.
continue ;
}
auto option_len = strlen ( picom_options [ i ] . long_name ) + 2 + 4 ;
2024-05-12 14:12:47 +00:00
if ( picom_options [ i ] . arg . name ) {
option_len + = strlen ( picom_options [ i ] . arg . name ) + 1 ;
2022-08-21 14:07:44 +00:00
}
if ( option_len > help_indent & & option_len < 30 ) {
help_indent = option_len ;
}
}
help_indent + = 6 ;
for ( size_t i = 0 ; i < ARR_SIZE ( picom_options ) ; i + + ) {
if ( picom_options [ i ] . help = = NULL ) {
continue ;
}
size_t option_len = 8 ;
fprintf ( f , " " ) ;
2024-05-12 14:12:47 +00:00
if ( ( i > ' a ' & & i < ' z ' ) | | ( i > ' A ' & & i < ' Z ' ) ) {
fprintf ( f , " -%c, " , ( char ) i ) ;
2022-08-21 14:07:44 +00:00
} else {
fprintf ( f , " " ) ;
}
fprintf ( f , " --%s " , picom_options [ i ] . long_name ) ;
option_len + = strlen ( picom_options [ i ] . long_name ) + 2 ;
2024-05-12 14:12:47 +00:00
if ( picom_options [ i ] . arg . name ) {
fprintf ( f , " =%s " , picom_options [ i ] . arg . name ) ;
option_len + = strlen ( picom_options [ i ] . arg . name ) + 1 ;
2022-08-21 14:07:44 +00:00
}
fprintf ( f , " " ) ;
option_len + = 2 ;
print_help ( picom_options [ i ] . help , help_indent , option_len ,
( size_t ) line_wrap , f ) ;
}
2018-12-20 21:57:32 +00:00
}
2024-05-12 14:12:47 +00:00
static void set_default_winopts ( options_t * opt ) {
auto mask = opt - > wintype_option_mask ;
// Apply default wintype options.
if ( ! mask [ WINTYPE_DESKTOP ] . shadow ) {
// Desktop windows are always drawn without shadow by default.
mask [ WINTYPE_DESKTOP ] . shadow = true ;
opt - > wintype_option [ WINTYPE_DESKTOP ] . shadow = false ;
}
// Focused/unfocused state only apply to a few window types, all other windows
// are always considered focused.
const wintype_t nofocus_type [ ] = { WINTYPE_UNKNOWN , WINTYPE_NORMAL , WINTYPE_UTILITY } ;
for ( unsigned long i = 0 ; i < ARR_SIZE ( nofocus_type ) ; i + + ) {
if ( ! mask [ nofocus_type [ i ] ] . focus ) {
mask [ nofocus_type [ i ] ] . focus = true ;
opt - > wintype_option [ nofocus_type [ i ] ] . focus = false ;
}
}
for ( unsigned long i = 0 ; i < NUM_WINTYPES ; i + + ) {
if ( ! mask [ i ] . shadow ) {
mask [ i ] . shadow = true ;
opt - > wintype_option [ i ] . shadow = opt - > shadow_enable ;
}
if ( ! mask [ i ] . fade ) {
mask [ i ] . fade = true ;
opt - > wintype_option [ i ] . fade = opt - > fading_enable ;
}
if ( ! mask [ i ] . focus ) {
mask [ i ] . focus = true ;
opt - > wintype_option [ i ] . focus = true ;
}
if ( ! mask [ i ] . blur_background ) {
mask [ i ] . blur_background = true ;
opt - > wintype_option [ i ] . blur_background =
opt - > blur_method ! = BLUR_METHOD_NONE ;
}
if ( ! mask [ i ] . full_shadow ) {
mask [ i ] . full_shadow = true ;
opt - > wintype_option [ i ] . full_shadow = false ;
}
if ( ! mask [ i ] . redir_ignore ) {
mask [ i ] . redir_ignore = true ;
opt - > wintype_option [ i ] . redir_ignore = false ;
}
if ( ! mask [ i ] . opacity ) {
mask [ i ] . opacity = true ;
// Opacity is not set to a concrete number here because the
// opacity logic is complicated, and needs an "unset" state
opt - > wintype_option [ i ] . opacity = NAN ;
}
if ( ! mask [ i ] . clip_shadow_above ) {
mask [ i ] . clip_shadow_above = true ;
opt - > wintype_option [ i ] . clip_shadow_above = false ;
}
}
}
2024-05-12 12:53:39 +00:00
static const char * shortopts = " D:I:O:r:o:m:l:t:i:e:hcfCzGb " ;
2018-12-20 21:57:32 +00:00
2018-12-20 23:58:47 +00:00
/// Get config options that are needed to parse the rest of the options
/// Return true if we should quit
2019-02-08 01:27:46 +00:00
bool get_early_config ( int argc , char * const * argv , char * * config_file , bool * all_xerrors ,
bool * fork , int * exit_code ) {
2022-08-21 14:07:44 +00:00
setup_longopts ( ) ;
2018-12-20 21:57:32 +00:00
int o = 0 , longopt_idx = - 1 ;
2024-01-31 03:09:28 +00:00
// Pre-parse the command line arguments to check for --config and invalid
2018-12-20 23:58:47 +00:00
// switches
2024-01-31 03:09:28 +00:00
// Must reset optind to 0 here in case we reread the command line
2018-12-20 23:58:47 +00:00
// arguments
optind = 1 ;
2018-12-21 22:49:42 +00:00
* config_file = NULL ;
2019-01-29 23:36:34 +00:00
* exit_code = 0 ;
2018-12-20 23:58:47 +00:00
while ( - 1 ! = ( o = getopt_long ( argc , argv , shortopts , longopts , & longopt_idx ) ) ) {
2018-12-21 22:49:42 +00:00
if ( o = = 256 ) {
2018-12-20 23:58:47 +00:00
* config_file = strdup ( optarg ) ;
2019-01-29 23:36:34 +00:00
} else if ( o = = ' h ' ) {
2019-10-23 18:27:30 +00:00
usage ( argv [ 0 ] , 0 ) ;
2019-01-29 23:36:34 +00:00
return true ;
2019-02-08 01:27:46 +00:00
} else if ( o = = ' b ' ) {
* fork = true ;
2018-12-20 23:58:47 +00:00
} else if ( o = = 314 ) {
* all_xerrors = true ;
} else if ( o = = 318 ) {
2022-08-21 13:57:39 +00:00
printf ( " %s \n " , PICOM_VERSION ) ;
2018-12-20 23:58:47 +00:00
return true ;
} else if ( o = = ' ? ' | | o = = ' : ' ) {
2019-10-23 18:27:30 +00:00
usage ( argv [ 0 ] , 1 ) ;
2020-04-11 15:04:31 +00:00
goto err ;
2018-12-20 21:57:32 +00:00
}
2018-12-20 23:58:47 +00:00
}
2018-12-20 21:57:32 +00:00
2018-12-20 23:58:47 +00:00
// Check for abundant positional arguments
2019-02-08 22:46:24 +00:00
if ( optind < argc ) {
// log is not initialized here yet
2019-10-23 18:27:30 +00:00
fprintf ( stderr , " picom doesn't accept positional arguments. \n " ) ;
2020-04-11 15:04:31 +00:00
goto err ;
2019-02-08 22:46:24 +00:00
}
2018-12-20 21:57:32 +00:00
2018-12-20 23:58:47 +00:00
return false ;
2020-04-11 15:04:31 +00:00
err :
* exit_code = 1 ;
return true ;
2018-12-20 23:58:47 +00:00
}
/**
* Process arguments and configuration files .
*/
2024-05-12 14:12:47 +00:00
bool get_cfg ( options_t * opt , int argc , char * const * argv ) {
2018-12-20 23:58:47 +00:00
int o = 0 , longopt_idx = - 1 ;
2020-10-22 13:44:10 +00:00
bool failed = false ;
2018-12-20 21:57:32 +00:00
optind = 1 ;
while ( - 1 ! = ( o = getopt_long ( argc , argv , shortopts , longopts , & longopt_idx ) ) ) {
2024-05-12 14:12:47 +00:00
if ( o = = ' ? ' | | o = = ' : ' | | picom_options [ o ] . arg . handler = = NULL ) {
usage ( argv [ 0 ] , 1 ) ;
2022-01-24 18:04:57 +00:00
failed = true ;
2024-05-12 14:12:47 +00:00
} else if ( ! picom_options [ o ] . arg . handler (
& picom_options [ o ] , & picom_options [ o ] . arg , optarg , opt ) ) {
2024-05-12 11:24:32 +00:00
failed = true ;
2018-12-20 21:57:32 +00:00
}
2020-10-22 13:44:10 +00:00
if ( failed ) {
// Parsing this option has failed, break the loop
break ;
}
2018-12-20 21:57:32 +00:00
}
2020-10-22 13:44:10 +00:00
if ( failed ) {
return false ;
}
2024-05-12 14:12:47 +00:00
log_set_level_tls ( opt - > log_level ) ;
2022-08-21 05:00:43 +00:00
if ( opt - > monitor_repaint & & opt - > backend ! = BKEND_XRENDER & & opt - > legacy_backends ) {
2018-12-20 21:57:32 +00:00
log_warn ( " --monitor-repaint has no effect when backend is not xrender " ) ;
}
2024-05-12 14:12:47 +00:00
if ( opt - > window_shader_fg ) {
scoped_charp cwd = getcwd ( NULL , 0 ) ;
scoped_charp tmp = opt - > window_shader_fg ;
opt - > window_shader_fg = locate_auxiliary_file ( " shaders " , tmp , cwd ) ;
if ( ! opt - > window_shader_fg ) {
log_error ( " Couldn't find the specified window shader file \" %s \" " , tmp ) ;
return false ;
}
}
if ( opt - > write_pid_path & & * opt - > write_pid_path ! = ' / ' ) {
log_warn ( " --write-pid-path is not an absolute path " ) ;
}
2022-09-29 06:59:25 +00:00
if ( opt - > backend = = BKEND_EGL ) {
if ( opt - > legacy_backends ) {
log_error ( " The egl backend is not supported with "
" --legacy-backends " ) ;
return false ;
}
log_warn ( " The egl backend is still experimental, use with care. " ) ;
}
2022-08-21 05:00:43 +00:00
if ( ! opt - > legacy_backends & & ! backend_list [ opt - > backend ] ) {
log_error ( " Backend \" %s \" is only available as part of the legacy "
2019-11-10 04:59:55 +00:00
" backends. " ,
BACKEND_STRS [ opt - > backend ] ) ;
return false ;
}
2022-08-21 05:00:43 +00:00
if ( opt - > debug_mode & & opt - > legacy_backends ) {
log_error ( " Debug mode does not work with the legacy backends. " ) ;
2019-11-10 05:04:10 +00:00
return false ;
}
2022-08-21 05:00:43 +00:00
if ( opt - > transparent_clipping & & opt - > legacy_backends ) {
log_error ( " Transparent clipping does not work with the legacy "
2019-11-30 21:24:22 +00:00
" backends " ) ;
return false ;
}
2022-08-21 05:00:43 +00:00
if ( opt - > glx_fshader_win_str & & ! opt - > legacy_backends ) {
2022-07-17 16:49:35 +00:00
log_warn ( " --glx-fshader-win has been replaced by "
2022-08-21 05:00:43 +00:00
" \" --window-shader-fg \" for the new backends. " ) ;
2022-07-17 16:49:35 +00:00
}
if ( opt - > window_shader_fg | | opt - > window_shader_fg_rules ) {
2023-01-21 15:16:52 +00:00
if ( opt - > backend = = BKEND_XRENDER | | opt - > legacy_backends ) {
log_warn ( opt - > backend = = BKEND_XRENDER
2023-06-16 15:21:34 +00:00
? " Shader interface is not supported by the xrender "
" backend. "
: " The new shader interface is not supported by the "
" legacy glx backend. You may want to use "
2023-01-21 15:16:52 +00:00
" --glx-fshader-win instead. " ) ;
2022-07-17 16:49:35 +00:00
opt - > window_shader_fg = NULL ;
c2_list_free ( & opt - > window_shader_fg_rules , free ) ;
}
}
2018-12-20 21:57:32 +00:00
// Range checking and option assignments
2019-11-10 03:00:17 +00:00
if ( opt - > max_brightness < 1.0 ) {
2023-06-16 14:57:59 +00:00
if ( opt - > backend = = BKEND_XRENDER | | opt - > legacy_backends ) {
log_warn ( " --max-brightness is not supported by the %s backend. "
" Falling back to 1.0. " ,
opt - > backend = = BKEND_XRENDER ? " xrender " : " legacy glx " ) ;
2019-11-10 03:00:17 +00:00
opt - > max_brightness = 1.0 ;
2023-06-16 14:57:59 +00:00
} else if ( opt - > use_damage ) {
log_warn ( " --max-brightness requires --no-use-damage. Falling "
" back to 1.0. " ) ;
2019-11-10 03:00:17 +00:00
opt - > max_brightness = 1.0 ;
}
2019-11-07 00:19:20 +00:00
}
2018-12-20 21:57:32 +00:00
// --blur-background-frame implies --blur-background
2019-12-20 18:07:35 +00:00
if ( opt - > blur_background_frame & & opt - > blur_method = = BLUR_METHOD_NONE ) {
2019-05-31 23:39:00 +00:00
opt - > blur_method = BLUR_METHOD_KERNEL ;
}
2018-12-20 21:57:32 +00:00
2020-10-01 20:51:15 +00:00
// Apply default wintype options that are dependent on global options
2024-05-12 14:12:47 +00:00
set_default_winopts ( opt ) ;
2018-12-20 21:57:32 +00:00
// Determine whether we track window grouping
2018-12-21 16:25:28 +00:00
if ( opt - > detect_transient | | opt - > detect_client_leader ) {
opt - > track_leader = true ;
2018-12-20 21:57:32 +00:00
}
// Fill default blur kernel
2019-06-06 06:37:48 +00:00
if ( opt - > blur_method = = BLUR_METHOD_KERNEL & &
( ! opt - > blur_kerns | | ! opt - > blur_kerns [ 0 ] ) ) {
2024-05-12 14:12:47 +00:00
opt - > blur_kerns = parse_blur_kern_lst ( " 3x3box " , & opt - > blur_kernel_count ) ;
2019-06-06 06:37:48 +00:00
CHECK ( opt - > blur_kerns ) ;
2019-06-07 20:53:23 +00:00
CHECK ( opt - > blur_kernel_count ) ;
2018-12-20 21:57:32 +00:00
}
2019-12-20 19:31:00 +00:00
// Sanitize parameters for dual-filter kawase blur
if ( opt - > blur_method = = BLUR_METHOD_DUAL_KAWASE ) {
if ( opt - > blur_strength < = 0 & & opt - > blur_radius > 500 ) {
log_warn ( " Blur radius >500 not supported by dual_kawase method, "
" capping to 500. " ) ;
opt - > blur_radius = 500 ;
}
if ( opt - > blur_strength > 20 ) {
log_warn ( " Blur strength >20 not supported by dual_kawase method, "
" capping to 20. " ) ;
opt - > blur_strength = 20 ;
}
2022-08-21 05:00:43 +00:00
if ( opt - > legacy_backends ) {
2020-09-08 06:04:06 +00:00
log_warn ( " Dual-kawase blur is not implemented by the legacy "
2022-08-21 05:00:43 +00:00
" backends. " ) ;
2020-09-08 06:04:06 +00:00
}
2019-12-20 19:31:00 +00:00
}
2019-02-17 23:47:46 +00:00
if ( opt - > resize_damage < 0 ) {
2018-12-20 21:57:32 +00:00
log_warn ( " Negative --resize-damage will not work correctly. " ) ;
2019-02-17 23:47:46 +00:00
}
2018-12-21 16:25:28 +00:00
2024-05-12 14:12:47 +00:00
if ( opt - > backend = = BKEND_XRENDER ) {
for ( int i = 0 ; i < opt - > blur_kernel_count ; i + + ) {
auto kernel = opt - > blur_kerns [ i ] ;
for ( int j = 0 ; j < kernel - > h * kernel - > w ; j + + ) {
if ( kernel - > data [ j ] < 0 ) {
log_warn ( " A convolution kernel with negative "
" values may not work properly under X "
" Render backend. " ) ;
goto check_end ;
}
}
}
check_end : ;
2019-02-17 23:47:46 +00:00
}
2019-11-10 04:59:55 +00:00
2024-05-11 16:54:15 +00:00
if ( opt - > legacy_backends & & opt - > number_of_scripts > 0 ) {
log_warn ( " Custom animations are not supported by the legacy "
" backends. Disabling animations. " ) ;
for ( size_t i = 0 ; i < ARR_SIZE ( opt - > animations ) ; i + + ) {
opt - > animations [ i ] . script = NULL ;
}
for ( int i = 0 ; i < opt - > number_of_scripts ; i + + ) {
script_free ( opt - > all_scripts [ i ] ) ;
}
free ( opt - > all_scripts ) ;
opt - > all_scripts = NULL ;
opt - > number_of_scripts = 0 ;
}
2024-04-20 15:19:21 +00:00
generate_fading_config ( opt ) ;
2019-11-10 04:59:55 +00:00
return true ;
2018-12-20 21:57:32 +00:00
}
2024-02-19 23:30:53 +00:00
void options_postprocess_c2_lists ( struct c2_state * state , struct x_connection * c ,
struct options * option ) {
if ( ! ( c2_list_postprocess ( state , c - > c , option - > unredir_if_possible_blacklist ) & &
c2_list_postprocess ( state , c - > c , option - > paint_blacklist ) & &
c2_list_postprocess ( state , c - > c , option - > shadow_blacklist ) & &
c2_list_postprocess ( state , c - > c , option - > shadow_clip_list ) & &
c2_list_postprocess ( state , c - > c , option - > fade_blacklist ) & &
c2_list_postprocess ( state , c - > c , option - > blur_background_blacklist ) & &
c2_list_postprocess ( state , c - > c , option - > invert_color_list ) & &
c2_list_postprocess ( state , c - > c , option - > window_shader_fg_rules ) & &
c2_list_postprocess ( state , c - > c , option - > opacity_rules ) & &
c2_list_postprocess ( state , c - > c , option - > rounded_corners_blacklist ) & &
c2_list_postprocess ( state , c - > c , option - > corner_radius_rules ) & &
2024-04-12 13:26:30 +00:00
c2_list_postprocess ( state , c - > c , option - > focus_blacklist ) & &
c2_list_postprocess ( state , c - > c , option - > transparent_clipping_blacklist ) ) ) {
2024-02-19 23:30:53 +00:00
log_error ( " Post-processing of conditionals failed, some of your rules "
" might not work " ) ;
}
}
2024-02-20 00:18:39 +00:00
void options_destroy ( struct options * options ) {
// Free blacklists
c2_list_free ( & options - > shadow_blacklist , NULL ) ;
c2_list_free ( & options - > shadow_clip_list , NULL ) ;
c2_list_free ( & options - > fade_blacklist , NULL ) ;
c2_list_free ( & options - > focus_blacklist , NULL ) ;
c2_list_free ( & options - > invert_color_list , NULL ) ;
c2_list_free ( & options - > blur_background_blacklist , NULL ) ;
c2_list_free ( & options - > opacity_rules , NULL ) ;
c2_list_free ( & options - > paint_blacklist , NULL ) ;
c2_list_free ( & options - > unredir_if_possible_blacklist , NULL ) ;
c2_list_free ( & options - > rounded_corners_blacklist , NULL ) ;
c2_list_free ( & options - > corner_radius_rules , NULL ) ;
c2_list_free ( & options - > window_shader_fg_rules , free ) ;
2024-04-12 13:26:30 +00:00
c2_list_free ( & options - > transparent_clipping_blacklist , NULL ) ;
2024-02-20 00:18:39 +00:00
free ( options - > write_pid_path ) ;
free ( options - > logpath ) ;
for ( int i = 0 ; i < options - > blur_kernel_count ; + + i ) {
free ( options - > blur_kerns [ i ] ) ;
}
free ( options - > blur_kerns ) ;
free ( options - > glx_fshader_win_str ) ;
2024-04-20 12:51:59 +00:00
for ( int i = 0 ; i < options - > number_of_scripts ; i + + ) {
script_free ( options - > all_scripts [ i ] ) ;
options - > all_scripts [ i ] = NULL ;
}
free ( options - > all_scripts ) ;
memset ( options - > animations , 0 , sizeof ( options - > animations ) ) ;
2024-02-20 00:18:39 +00:00
}
2018-12-20 21:57:32 +00:00
// vim: set noet sw=8 ts=8 :