19 Commits

Author SHA1 Message Date
Arda Atci
e9834a5e35 fix on desktop switch
Some checks failed
coding-style / check (push) Has been cancelled
2023-04-25 03:47:31 +03:00
Arda Atci
fb99c9e472 added support for other wm 2023-04-22 13:46:16 +03:00
Arda Atci
dc9d1fe248 Merge branch 'yshui:next' into next 2023-04-01 23:12:29 +03:00
Yuxuan Shui
05ef18d78f Merge pull request #1044 from yshui/alanpq 2023-04-01 11:32:30 +01:00
Yuxuan Shui
379f67f5c2 tests: add corner-radius-rules to the parsing test
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2023-04-01 11:27:05 +01:00
oofsauce
6d459badbc Add corner-radius-rules configuration option
This option accepts a list of patterns and overrides the corner radii of
matching windows

Authored-by: oofsauce <alanpanayotov@gmail.com>
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2023-04-01 11:26:10 +01:00
Yuxuan Shui
838f1f097c Merge pull request #1023 from absolutelynothelix/xrescheck-xcb-render-pictures-test 2023-03-30 09:06:37 +01:00
Arda Atci
1c7466c07c pos fix 2023-02-15 17:29:55 +03:00
Arda Atci
44cfa0b0ef randr_mon position fix 2023-02-14 23:24:51 +03:00
Maxim Solovyov
ce7758a07b backend: fix leak in default_backend_render_shadow 2023-02-13 03:36:00 +03:00
Arda Atci
bb2b4801f7 randr anim fix 2023-02-06 23:12:45 +03:00
Arda Atci
36e6b73cde randr extension 2023-02-04 23:10:18 +03:00
Arda Atci
90f57e9b1a shadow fix 2023-02-04 15:40:21 +03:00
Arda Atci
157ecd2077 shadow fix 2023-02-04 07:11:23 +03:00
Arda Atci
9f14c43989 Merge pull request #18 from yshui/next
merge yshui/next
2023-02-04 05:49:58 +03:00
Yuxuan Shui
cee1287562 github: update git-clang-format-lint action
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2023-01-29 16:23:26 +00:00
Yuxuan Shui
317275abf6 Merge pull request #995 from absolutelynothelix/begone-xinerama 2023-01-29 15:36:04 +00:00
Maxim Solovyov
986b3c1cb3 core: drop xinerama
there are two x extensions for working with monitors (especially
multiple): xinerama and randr. xinerama is old, feature-poor and in
general isn't used anymore compared to the randr: new, feature-rich and
widely-used. for some reason we were using both of them, so let's drop
xinerama to keep things simple, clean and small. and to be modern.

the drop was done in three steps:
* first step was to replace all the xinerama-based code with the
  randr-based one and to replace or remove all the xinerama mentions;
* second step was to replace the xinerama's terminology with the
  randr's one. xinerama was referring only to the word "screen", while
  randr refers to multiple words and i think the word "monitor" is the
  most suitable for us and, hopefully, clear both to a contributor and
  to an end user;
* third step was to refactor the new randr-based code if needed and to
  address related todo's (mostly about moving related functions
  elsewhere).

all the steps were done well except addressing a leftover todo about
moving the win_update_monitor function to the x.c which wasn't done.

the xinerama-shadow-crop option was renamed to crop-shadow-to-monitor,
but it's previous name is still accepted, has effect and the
deprecation message is printed to preserve backwards-compatibility.
2023-01-29 10:51:12 +03:00
Yuxuan Shui
102a0bc5e0 backend: mask can be null in blur()
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2023-01-29 06:35:28 +00:00
27 changed files with 369 additions and 275 deletions

View File

@@ -36,7 +36,7 @@ jobs:
languages: ${{ matrix.language }}
# Install dependencies
- run: sudo apt update && sudo apt install libxext-dev libxcb1-dev libxcb-dpms0-dev libxcb-damage0-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-render-util0-dev libxcb-render0-dev libxcb-randr0-dev libxcb-composite0-dev libxcb-image0-dev libxcb-present-dev libxcb-xinerama0-dev libxcb-glx0-dev libpixman-1-dev libdbus-1-dev libconfig-dev libgl1-mesa-dev libpcre2-dev libevdev-dev uthash-dev libev-dev libx11-xcb-dev meson ninja-build
- run: sudo apt update && sudo apt install libxext-dev libxcb1-dev libxcb-dpms0-dev libxcb-damage0-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-render-util0-dev libxcb-render0-dev libxcb-randr0-dev libxcb-composite0-dev libxcb-image0-dev libxcb-present-dev libxcb-glx0-dev libpixman-1-dev libdbus-1-dev libconfig-dev libgl1-mesa-dev libpcre2-dev libevdev-dev uthash-dev libev-dev libx11-xcb-dev meson ninja-build
if: ${{ matrix.language == 'cpp' }}
# Autobuild

View File

@@ -8,6 +8,6 @@ jobs:
steps:
- uses: actions/checkout@v2
- run: git fetch --depth=1 origin ${{ github.event.pull_request.base.sha }}
- uses: yshui/git-clang-format-lint@v1.13
- uses: yshui/git-clang-format-lint@v1.14
with:
base: ${{ github.event.pull_request.base.sha }}

View File

@@ -9,6 +9,6 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 2
- uses: yshui/git-clang-format-lint@v1.13
- uses: yshui/git-clang-format-lint@v1.14
with:
base: ${{ github.event.ref }}~1

View File

@@ -32,7 +32,6 @@ Assuming you already have all the usual building tools installed (e.g. gcc, pyth
* xcb-composite
* xcb-image
* xcb-present
* xcb-xinerama
* xcb-glx
* pixman
* libdbus (optional, disable with the `-Ddbus=false` meson configure flag)
@@ -45,7 +44,7 @@ Assuming you already have all the usual building tools installed (e.g. gcc, pyth
On Debian based distributions (e.g. Ubuntu), the needed packages are
```
libxext-dev libxcb1-dev libxcb-damage0-dev libxcb-dpms0-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-render-util0-dev libxcb-render0-dev libxcb-randr0-dev libxcb-composite0-dev libxcb-image0-dev libxcb-present-dev libxcb-xinerama0-dev libxcb-glx0-dev libpixman-1-dev libdbus-1-dev libconfig-dev libgl-dev libegl-dev libpcre2-dev libevdev-dev uthash-dev libev-dev libx11-xcb-dev meson
libxext-dev libxcb1-dev libxcb-damage0-dev libxcb-dpms0-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-render-util0-dev libxcb-render0-dev libxcb-randr0-dev libxcb-composite0-dev libxcb-image0-dev libxcb-present-dev libxcb-glx0-dev libpixman-1-dev libdbus-1-dev libconfig-dev libgl-dev libegl-dev libpcre2-dev libevdev-dev uthash-dev libev-dev libx11-xcb-dev meson
```
On Fedora, the needed packages are

View File

@@ -103,6 +103,9 @@ OPTIONS
*--corner-radius* 'VALUE'::
Sets the radius of rounded window corners. When > 0, the compositor will round the corners of windows. Does not interact well with *--transparent-clipping*. (defaults to 0).
*--corner-radius-rules* 'RADIUS':'CONDITION'::
Specify a list of corner radius rules. Overrides the corner radii of matching windows. This option takes precedence over the *--rounded-corners-exclude* option, and also overrides the default exclusion of fullscreen windows. The condition has the same format as *--opacity-rule*.
*--rounded-corners-exclude* 'CONDITION'::
Exclude conditions for rounded corners.
@@ -217,8 +220,8 @@ May also be one of the predefined kernels: `3x3box` (default), `5x5box`, `7x7box
*--shadow-exclude-reg* 'GEOMETRY'::
Specify a X geometry that describes the region in which shadow should not be painted in, such as a dock window region. Use `--shadow-exclude-reg x10+0-0`, for example, if the 10 pixels on the bottom of the screen should not have shadows painted on.
*--xinerama-shadow-crop*::
Crop shadow of a window fully on a particular Xinerama screen to the screen.
*--crop-shadow-to-monitor*::
Crop shadow of a window fully on a particular monitor to that monitor. This is currently implemented using the X RandR extension.
*--backend* 'BACKEND'::
Specify the backend to use: `xrender`, `glx`, or `xr_glx_hybrid`. `xrender` is the default one.

View File

@@ -111,8 +111,9 @@ shadow-exclude = [
#
# shadow-exclude-reg = ""
# Crop shadow of a window fully on a particular Xinerama screen to the screen.
# xinerama-shadow-crop = false
# Crop shadow of a window fully on a particular monitor to that monitor. This is
# currently implemented using the X RandR extension.
# crop-shadow-to-monitor = false
#################################

View File

@@ -23,8 +23,8 @@
WM_CLIENT_MACHINE, \
_NET_ACTIVE_WINDOW, \
_COMPTON_SHADOW, \
_NET_WM_WINDOW_TYPE, \
_NET_CURRENT_MON_CENTER
_NET_WM_DESKTOP, \
_NET_CURRENT_DESKTOP
#define ATOM_LIST2 \
_NET_WM_WINDOW_TYPE_DESKTOP, \
@@ -44,6 +44,7 @@
_NET_WM_STATE, \
_NET_WM_STATE_FULLSCREEN, \
_NET_WM_BYPASS_COMPOSITOR, \
_NET_WM_WINDOW_TYPE, \
UTF8_STRING, \
C_STRING
// clang-format on

View File

@@ -380,18 +380,18 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
&reg_shadow_clip);
}
if (ps->o.xinerama_shadow_crop && w->xinerama_scr >= 0 &&
w->xinerama_scr < ps->xinerama_nscrs) {
// There can be a window where number of screens is
// updated, but the screen number attached to the windows
if (ps->o.crop_shadow_to_monitor && w->randr_monitor >= 0 &&
w->randr_monitor < ps->randr_nmonitors) {
// There can be a window where number of monitors is
// updated, but the monitor number attached to the window
// have not.
//
// Window screen number will be updated eventually, so
// Window monitor number will be updated eventually, so
// here we just check to make sure we don't access out of
// bounds.
pixman_region32_intersect(
&reg_shadow, &reg_shadow,
&ps->xinerama_scr_regs[w->xinerama_scr]);
&ps->randr_monitor_regs[w->randr_monitor]);
}
if (ps->o.transparent_clipping) {

View File

@@ -197,7 +197,7 @@ struct backend_operations {
/// mask is.
bool (*blur)(backend_t *backend_data, double opacity, void *blur_ctx, void *mask,
coord_t mask_dst, const region_t *reg_blur,
const region_t *reg_visible) attr_nonnull(1, 3, 4, 6, 7);
const region_t *reg_visible) attr_nonnull(1, 3, 6, 7);
/// Update part of the back buffer with the rendering buffer, then present the
/// back buffer onto the target window (if not back buffered, update part of the

View File

@@ -294,13 +294,14 @@ shadow_picture_err:
void *default_backend_render_shadow(backend_t *backend_data, int width, int height,
struct backend_shadow_context *sctx, struct color color) {
const conv *kernel = (void *)sctx;
xcb_pixmap_t shadow_pixel = solid_picture(backend_data->c, backend_data->root, true,
1, color.red, color.green, color.blue),
shadow = XCB_NONE;
xcb_render_picture_t shadow_pixel = solid_picture(
backend_data->c, backend_data->root, true, 1, color.red, color.green, color.blue);
xcb_pixmap_t shadow = XCB_NONE;
xcb_render_picture_t pict = XCB_NONE;
if (!build_shadow(backend_data->c, backend_data->root, color.alpha, width, height,
kernel, shadow_pixel, &shadow, &pict)) {
xcb_render_free_picture(backend_data->c, shadow_pixel);
return NULL;
}
@@ -308,6 +309,7 @@ void *default_backend_render_shadow(backend_t *backend_data, int width, int heig
void *ret = backend_data->ops->bind_pixmap(
backend_data, shadow, x_get_visual_info(backend_data->c, visual), true);
xcb_render_free_picture(backend_data->c, pict);
xcb_render_free_picture(backend_data->c, shadow_pixel);
return ret;
}

View File

@@ -206,9 +206,6 @@ typedef struct session {
/// Width of root window.
int root_width;
// Damage of root window.
// Damage root_damage;
int selmon_center_x;
int selmon_center_y;
/// X Composite overlay window.
xcb_window_t overlay;
/// The target window for debug mode
@@ -294,6 +291,8 @@ typedef struct session {
int size_expose;
/// Index of the next free slot in <code>expose_rects</code>.
int n_expose;
/// Current desktop of display
uint32_t cur_desktop;
// === Window related ===
/// A hash table of all windows.
@@ -374,12 +373,10 @@ typedef struct session {
int glx_event;
/// Error base number for X GLX extension.
int glx_error;
/// Whether X Xinerama extension exists.
bool xinerama_exists;
/// Xinerama screen regions.
region_t *xinerama_scr_regs;
/// Number of Xinerama screens.
int xinerama_nscrs;
/// Number of X RandR monitors.
int randr_nmonitors;
/// X RandR monitor regions.
region_t *randr_monitor_regs;
/// Whether X Sync extension exists.
bool xsync_exists;
/// Event base number for X Sync extension.

View File

@@ -509,32 +509,37 @@ parse_geometry_end:
}
/**
* Parse a list of opacity rules.
* Parse a list of window rules, prefixed with a number, separated by a ':'
*/
bool parse_rule_opacity(c2_lptr_t **res, const char *src) {
// Find opacity value
bool parse_numeric_window_rule(c2_lptr_t **res, const char *src, long min, long max) {
if (!src) {
return false;
}
// Find numeric value
char *endptr = NULL;
long val = strtol(src, &endptr, 0);
if (!endptr || endptr == src) {
log_error("No opacity specified: %s", src);
log_error("No number specified: %s", src);
return false;
}
if (val > 100 || val < 0) {
log_error("Opacity %ld invalid: %s", val, src);
if (val < min || val > max) {
log_error("Number not in range (%ld <= n <= %ld): %s", min, max, src);
return false;
}
// Skip over spaces
while (*endptr && isspace((unsigned char)*endptr))
while (*endptr && isspace((unsigned char)*endptr)) {
++endptr;
}
if (':' != *endptr) {
log_error("Opacity terminator not found: %s", src);
log_error("Number separator (':') not found: %s", src);
return false;
}
++endptr;
// Parse pattern
// I hope 1-100 is acceptable for (void *)
return c2_parse(res, endptr, (void *)val);
}
@@ -785,7 +790,7 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
.shadow_opacity = .75,
.shadow_blacklist = NULL,
.shadow_ignore_shaped = false,
.xinerama_shadow_crop = false,
.crop_shadow_to_monitor = false,
.shadow_clip_list = NULL,
.corner_radius = 0,

View File

@@ -173,8 +173,8 @@ typedef struct options {
c2_lptr_t *shadow_blacklist;
/// Whether bounding-shaped window should be ignored.
bool shadow_ignore_shaped;
/// Whether to crop shadow to the very Xinerama screen.
bool xinerama_shadow_crop;
/// Whether to crop shadow to the very X RandR monitor.
bool crop_shadow_to_monitor;
/// Don't draw shadow over these windows. A linked list of conditions.
c2_lptr_t *shadow_clip_list;
@@ -275,6 +275,8 @@ typedef struct options {
int corner_radius;
/// Rounded corners blacklist. A linked list of conditions.
c2_lptr_t *rounded_corners_blacklist;
/// Rounded corner rules. A linked list of conditions.
c2_lptr_t *corner_radius_rules;
// === Focus related ===
/// Whether to try to detect WM windows and mark them as focused.
@@ -320,7 +322,7 @@ bool must_use parse_long(const char *, long *);
bool must_use parse_int(const char *, int *);
struct conv **must_use parse_blur_kern_lst(const char *, bool *hasneg, int *count);
bool must_use parse_geometry(session_t *, const char *, region_t *);
bool must_use parse_rule_opacity(c2_lptr_t **, const char *);
bool must_use parse_numeric_window_rule(c2_lptr_t **, const char *, long, long);
bool must_use parse_rule_window_shader(c2_lptr_t **, const char *, const char *);
char *must_use locate_auxiliary_file(const char *scope, const char *path,
const char *include_dir);

View File

@@ -135,6 +135,32 @@ void parse_cfg_condlst(const config_t *pcfg, c2_lptr_t **pcondlst, const char *n
}
}
/**
* Parse a window corner radius rule list in configuration file.
*/
static inline void
parse_cfg_condlst_corner(options_t *opt, const config_t *pcfg, const char *name) {
config_setting_t *setting = config_lookup(pcfg, name);
if (setting) {
// Parse an array of options
if (config_setting_is_array(setting)) {
int i = config_setting_length(setting);
while (i--)
if (!parse_numeric_window_rule(
&opt->corner_radius_rules,
config_setting_get_string_elem(setting, i), 0, INT_MAX))
exit(1);
}
// Treat it as a single pattern if it's a string
else if (config_setting_type(setting) == CONFIG_TYPE_STRING) {
if (!parse_numeric_window_rule(&opt->corner_radius_rules,
config_setting_get_string(setting),
0, INT_MAX))
exit(1);
}
}
}
/**
* Parse an opacity rule list in configuration file.
*/
@@ -146,15 +172,15 @@ parse_cfg_condlst_opct(options_t *opt, const config_t *pcfg, const char *name) {
if (config_setting_is_array(setting)) {
int i = config_setting_length(setting);
while (i--)
if (!parse_rule_opacity(
if (!parse_numeric_window_rule(
&opt->opacity_rules,
config_setting_get_string_elem(setting, i)))
config_setting_get_string_elem(setting, i), 0, 100))
exit(1);
}
// Treat it as a single pattern if it's a string
else if (config_setting_type(setting) == CONFIG_TYPE_STRING) {
if (!parse_rule_opacity(&opt->opacity_rules,
config_setting_get_string(setting)))
if (!parse_numeric_window_rule(
&opt->opacity_rules, config_setting_get_string(setting), 0, 100))
exit(1);
}
}
@@ -343,6 +369,9 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
config_lookup_int(&cfg, "corner-radius", &opt->corner_radius);
// --rounded-corners-exclude
parse_cfg_condlst(&cfg, &opt->rounded_corners_blacklist, "rounded-corners-exclude");
// --corner-radius-rules
parse_cfg_condlst_corner(opt, &cfg, "corner-radius-rules");
// -e (frame_opacity)
config_lookup_float(&cfg, "frame-opacity", &opt->frame_opacity);
// -c (shadow_enable)
@@ -393,8 +422,12 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
lcfg_lookup_bool(&cfg, "shadow-ignore-shaped", &opt->shadow_ignore_shaped);
// --detect-rounded-corners
lcfg_lookup_bool(&cfg, "detect-rounded-corners", &opt->detect_rounded_corners);
// --xinerama-shadow-crop
lcfg_lookup_bool(&cfg, "xinerama-shadow-crop", &opt->xinerama_shadow_crop);
// --crop-shadow-to-monitor
if (lcfg_lookup_bool(&cfg, "xinerama-shadow-crop", &opt->crop_shadow_to_monitor)) {
log_warn("xinerama-shadow-crop is deprecated. Use crop-shadow-to-monitor "
"instead.");
}
lcfg_lookup_bool(&cfg, "crop-shadow-to-monitor", &opt->crop_shadow_to_monitor);
// --detect-client-opacity
lcfg_lookup_bool(&cfg, "detect-client-opacity", &opt->detect_client_opacity);
// --refresh-rate

View File

@@ -1202,7 +1202,7 @@ static bool cdbus_process_opts_get(session_t *ps, DBusMessage *msg) {
cdbus_m_opts_get_do(shadow_offset_x, cdbus_reply_int32);
cdbus_m_opts_get_do(shadow_offset_y, cdbus_reply_int32);
cdbus_m_opts_get_do(shadow_opacity, cdbus_reply_double);
cdbus_m_opts_get_do(xinerama_shadow_crop, cdbus_reply_bool);
cdbus_m_opts_get_do(crop_shadow_to_monitor, cdbus_reply_bool);
cdbus_m_opts_get_do(fade_delta, cdbus_reply_int32);
cdbus_m_opts_get_do(fade_in_step, cdbus_reply_double);

View File

@@ -2,21 +2,21 @@
// Copyright (c) 2018 Yuxuan Shui <yshuiv7@gmail.com>
#include <stdio.h>
#include <xcb/xcb.h>
#include <xcb/composite.h>
#include <xcb/xcb.h>
#include "backend/driver.h"
#include "diagnostic.h"
#include "config.h"
#include "picom.h"
#include "common.h"
#include "config.h"
#include "diagnostic.h"
#include "picom.h"
void print_diagnostics(session_t *ps, const char *config_file, bool compositor_running) {
printf("**Version:** " PICOM_VERSION "\n");
//printf("**CFLAGS:** %s\n", "??");
// printf("**CFLAGS:** %s\n", "??");
printf("\n### Extensions:\n\n");
printf("* Shape: %s\n", ps->shape_exists ? "Yes" : "No");
printf("* XRandR: %s\n", ps->randr_exists ? "Yes" : "No");
printf("* RandR: %s\n", ps->randr_exists ? "Yes" : "No");
printf("* Present: %s\n", ps->present_exists ? "Present" : "Not Present");
printf("\n### Misc:\n\n");
printf("* Use Overlay: %s\n", ps->overlay != XCB_NONE ? "Yes" : "No");

View File

@@ -237,8 +237,8 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
win_set_flags(mw, WIN_FLAGS_SIZE_STALE);
}
// Recalculate which screen this window is on
win_update_screen(ps->xinerama_nscrs, ps->xinerama_scr_regs, mw);
// Recalculate which monitor this window is on
win_update_monitor(ps->randr_nmonitors, ps->randr_monitor_regs, mw);
}
// override_redirect flag cannot be changed after window creation, as far
@@ -452,14 +452,27 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
}
if (ps->root == ev->window) {
if (ev->atom == ps->atoms->a_NET_CURRENT_MON_CENTER) {
winprop_t prop = x_get_prop(ps->c, ps->root, ps->atoms->a_NET_CURRENT_MON_CENTER, 2L, XCB_ATOM_CARDINAL, 32);
if (prop.nitems == 2) {
ps->selmon_center_x = prop.p32[0];
ps->selmon_center_y = prop.p32[1];
}
free_winprop(&prop);
}
if (ev->atom == ps->atoms->a_NET_CURRENT_DESKTOP) {
auto prop = x_get_prop(ps->c, ps->root, ps->atoms->a_NET_CURRENT_DESKTOP,
1L, XCB_ATOM_CARDINAL, 32);
if (prop.nitems) {
if (ps->cur_desktop != *prop.c32) {
win_stack_foreach_managed_safe(w, &ps->window_stack) {
if (w->a.override_redirect) {
continue;
}
if (w->cur_desktop & *prop.c32) {
w->dwm_mask = ANIM_NEXT_TAG;
} else if (w->cur_desktop & ps->cur_desktop) {
w->dwm_mask = ANIM_PREV_TAG;
}
}
ps->cur_desktop = *prop.c32;
}
}
}
if (ps->o.use_ewmh_active_win && ps->atoms->a_NET_ACTIVE_WINDOW == ev->atom) {
// to update focus

View File

@@ -16,8 +16,7 @@ cflags = []
required_xcb_packages = [
'xcb-render', 'xcb-damage', 'xcb-randr', 'xcb-sync', 'xcb-composite',
'xcb-shape', 'xcb-xinerama', 'xcb-xfixes', 'xcb-present', 'xcb-glx',
'xcb-dpms', 'xcb'
'xcb-shape', 'xcb-xfixes', 'xcb-present', 'xcb-glx', 'xcb-dpms', 'xcb'
]
required_packages = [

View File

@@ -72,6 +72,9 @@ static const struct picom_option picom_options[] = {
"managers not passing _NET_WM_WINDOW_OPACITY of client windows to frame"},
{"refresh-rate" , required_argument, 269, NULL , NULL},
{"vsync" , optional_argument, 270, NULL , "Enable VSync"},
{"crop-shadow-to-monitor" , no_argument , 271, NULL , "Crop shadow of a window fully on a particular monitor to that monitor. "
"This is currently implemented using the X RandR extension"},
{"xinerama-shadow-crop" , no_argument , 272, NULL , NULL},
{"sw-opti" , no_argument , 274, NULL , NULL},
{"vsync-aggressive" , no_argument , 275, NULL , NULL},
{"use-ewmh-active-win" , no_argument , 276, NULL , "Use _NET_WM_ACTIVE_WINDOW on the root window to determine which window is "
@@ -119,7 +122,6 @@ static const struct picom_option picom_options[] = {
{"opacity-rule" , required_argument, 304, "OPACITY:COND", "Specify a list of opacity rules, see man page for more details"},
{"shadow-exclude-reg" , required_argument, 305, NULL , NULL},
{"paint-exclude" , required_argument, 306, NULL , NULL},
{"xinerama-shadow-crop" , no_argument , 307, NULL , "Crop shadow of a window fully on a particular Xinerama screen to the screen."},
{"unredir-if-possible-exclude" , required_argument, 308, "COND" , "Conditions of windows that shouldn't be considered full-screen for "
"unredirecting screen."},
{"unredir-if-possible-delay" , required_argument, 309, NULL, "Delay before unredirecting the window, in milliseconds. Defaults to 0."},
@@ -159,6 +161,7 @@ static const struct picom_option picom_options[] = {
{"corner-radius" , required_argument, 333, NULL , "Sets the radius of rounded window corners. When > 0, the compositor will "
"round the corners of windows. (defaults to 0)."},
{"rounded-corners-exclude" , required_argument, 334, "COND" , "Exclude conditions for rounded corners."},
{"corner-radius-rules" , required_argument, 340, "RADIUS:COND" , "Window rules for specific rounded corner radii."},
{"clip-shadow-above" , required_argument, 335, NULL , "Specify a list of conditions of windows to not paint a shadow over, such "
"as a dock window."},
{"window-shader-fg" , required_argument, 336, "PATH" , "Specify GLSL fragment shader path for rendering window contents. Does not"
@@ -172,6 +175,7 @@ static const struct picom_option picom_options[] = {
{"dithered-present" , no_argument , 339, NULL , "Use higher precision during rendering, and apply dither when presenting the "
"rendered screen. Reduces banding artifacts, but might cause performance "
"degradation. Only works with OpenGL."},
// 340 is corner-radius-rules
{"legacy-backends" , no_argument , 733, NULL , "Use deprecated version of the backends."},
{"monitor-repaint" , no_argument , 800, NULL , "Highlight the updated area of the screen. For debugging."},
{"diagnostics" , no_argument , 801, NULL , "Print diagnostic information"},
@@ -494,8 +498,8 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
P_CASEBOOL(267, detect_rounded_corners);
P_CASEBOOL(268, detect_client_opacity);
case 269:
log_warn("--refresh-rate has been deprecated, please remove it from"
"your command line options");
log_warn("--refresh-rate has been deprecated, please remove it "
"from your command line options");
break;
case 270:
if (optarg) {
@@ -508,6 +512,12 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
opt->vsync = true;
}
break;
P_CASEBOOL(271, crop_shadow_to_monitor);
case 272:
opt->crop_shadow_to_monitor = true;
log_warn("--xinerama-shadow-crop is deprecated. Use "
"--crop-shadow-to-monitor instead.");
break;
case 274:
log_warn("--sw-opti has been deprecated, please remove it from the "
"command line options");
@@ -515,7 +525,7 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
case 275:
// --vsync-aggressive
log_error("--vsync-aggressive has been removed, please remove it"
" from the command line options");
" from the command line options");
failed = true;
break;
P_CASEBOOL(276, use_ewmh_active_win);
@@ -620,7 +630,7 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
break;
case 304:
// --opacity-rule
if (!parse_rule_opacity(&opt->opacity_rules, optarg))
if (!parse_numeric_window_rule(&opt->opacity_rules, optarg, 0, 100))
exit(1);
break;
case 305:
@@ -634,7 +644,6 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
// --paint-exclude
condlst_add(&opt->paint_blacklist, optarg);
break;
P_CASEBOOL(307, xinerama_shadow_crop);
case 308:
// --unredir-if-possible-exclude
condlst_add(&opt->unredir_if_possible_blacklist, optarg);
@@ -725,6 +734,11 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
// --rounded-corners-exclude
condlst_add(&opt->rounded_corners_blacklist, optarg);
break;
case 340:
// --corner-radius-rules
if (!parse_numeric_window_rule(&opt->corner_radius_rules, optarg, 0, INT_MAX))
exit(1);
break;
case 335:
// --clip-shadow-above
condlst_add(&opt->shadow_clip_list, optarg);

View File

@@ -28,7 +28,6 @@
#include <xcb/render.h>
#include <xcb/sync.h>
#include <xcb/xfixes.h>
#include <xcb/xinerama.h>
#include <ev.h>
#include <test.h>
@@ -111,21 +110,6 @@ void quit(session_t *ps) {
ev_break(ps->loop, EVBREAK_ALL);
}
/**
* Free Xinerama screen info.
*
* XXX consider moving to x.c
*/
static inline void free_xinerama_info(session_t *ps) {
if (ps->xinerama_scr_regs) {
for (int i = 0; i < ps->xinerama_nscrs; ++i)
pixman_region32_fini(&ps->xinerama_scr_regs[i]);
free(ps->xinerama_scr_regs);
ps->xinerama_scr_regs = NULL;
}
ps->xinerama_nscrs = 0;
}
/**
* Get current system clock in milliseconds.
*/
@@ -135,41 +119,6 @@ static inline int64_t get_time_ms(void) {
return (int64_t)tp.tv_sec * 1000 + (int64_t)tp.tv_nsec / 1000000;
}
// XXX Move to x.c
void cxinerama_upd_scrs(session_t *ps) {
// XXX Consider deprecating Xinerama, switch to RandR when necessary
free_xinerama_info(ps);
if (!ps->o.xinerama_shadow_crop || !ps->xinerama_exists)
return;
xcb_xinerama_is_active_reply_t *active =
xcb_xinerama_is_active_reply(ps->c, xcb_xinerama_is_active(ps->c), NULL);
if (!active || !active->state) {
free(active);
return;
}
free(active);
auto xinerama_scrs =
xcb_xinerama_query_screens_reply(ps->c, xcb_xinerama_query_screens(ps->c), NULL);
if (!xinerama_scrs) {
return;
}
xcb_xinerama_screen_info_t *scrs =
xcb_xinerama_query_screens_screen_info(xinerama_scrs);
ps->xinerama_nscrs = xcb_xinerama_query_screens_screen_info_length(xinerama_scrs);
ps->xinerama_scr_regs = ccalloc(ps->xinerama_nscrs, region_t);
for (int i = 0; i < ps->xinerama_nscrs; ++i) {
const xcb_xinerama_screen_info_t *const s = &scrs[i];
pixman_region32_init_rect(&ps->xinerama_scr_regs[i], s->x_org, s->y_org,
s->width, s->height);
}
free(xinerama_scrs);
}
static inline bool dpms_screen_is_off(xcb_dpms_info_reply_t *info) {
// state is a bool indicating whether dpms is enabled
return info->state && (info->power_level != XCB_DPMS_DPMS_MODE_ON);
@@ -691,8 +640,8 @@ static void configure_root(session_t *ps) {
static void handle_root_flags(session_t *ps) {
if ((ps->root_flags & ROOT_FLAGS_SCREEN_CHANGE) != 0) {
if (ps->o.xinerama_shadow_crop) {
cxinerama_upd_scrs(ps);
if (ps->o.crop_shadow_to_monitor) {
x_update_randr_monitors(ps);
}
ps->root_flags &= ~(uint64_t)ROOT_FLAGS_SCREEN_CHANGE;
}
@@ -749,13 +698,13 @@ paint_preprocess(session_t *ps, bool *fade_running, bool *animation_running) {
w->animation_dest_center_y - w->animation_center_y;
double neg_displacement_w = w->animation_dest_w - w->animation_w;
double neg_displacement_h = w->animation_dest_h - w->animation_h;
double animation_stiffness = ps->o.animation_stiffness;
if (!(w->animation_is_tag & ANIM_IN_TAG)) {
if (w->animation_is_tag & ANIM_SLOW)
animation_stiffness = ps->o.animation_stiffness_tag_change;
else if (w->animation_is_tag & ANIM_FAST)
animation_stiffness = ps->o.animation_stiffness_tag_change * 1.5;
}
double animation_stiffness = ps->o.animation_stiffness;
if (!(w->animation_is_tag & ANIM_IN_TAG)) {
if (w->animation_is_tag & ANIM_SLOW)
animation_stiffness = ps->o.animation_stiffness_tag_change;
else if (w->animation_is_tag & ANIM_FAST)
animation_stiffness = ps->o.animation_stiffness_tag_change * 1.5;
}
if (w->state == WSTATE_FADING && !(w->animation_is_tag & ANIM_FADE))
w->opacity_target = win_calc_opacity_target(ps, w);
double acceleration_x =
@@ -893,7 +842,6 @@ paint_preprocess(session_t *ps, bool *fade_running, bool *animation_running) {
// We can't check for 1 here as sometimes 1 = 0.999999999999999
// in case of floating numbers
if (w->animation_progress >= 0.999999999) {
win_process_update_flags(ps, w);
w->animation_progress = 1;
w->animation_velocity_x = 0.0;
w->animation_velocity_y = 0.0;
@@ -1934,6 +1882,8 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
.white_picture = XCB_NONE,
.shadow_context = NULL,
.cur_desktop = 0,
#ifdef CONFIG_VSYNC_DRM
.drm_fd = -1,
#endif
@@ -2020,7 +1970,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
xcb_prefetch_extension_data(ps->c, &xcb_shape_id);
xcb_prefetch_extension_data(ps->c, &xcb_xfixes_id);
xcb_prefetch_extension_data(ps->c, &xcb_randr_id);
xcb_prefetch_extension_data(ps->c, &xcb_xinerama_id);
xcb_prefetch_extension_data(ps->c, &xcb_present_id);
xcb_prefetch_extension_data(ps->c, &xcb_sync_id);
xcb_prefetch_extension_data(ps->c, &xcb_glx_id);
@@ -2279,18 +2228,10 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
}
// Query X RandR
if (ps->o.xinerama_shadow_crop) {
if (!ps->randr_exists) {
log_fatal("No XRandR extension. xinerama-shadow-crop cannot be "
"enabled.");
goto err;
}
}
// Query X Xinerama extension
if (ps->o.xinerama_shadow_crop) {
ext_info = xcb_get_extension_data(ps->c, &xcb_xinerama_id);
ps->xinerama_exists = ext_info && ext_info->present;
if (ps->o.crop_shadow_to_monitor && !ps->randr_exists) {
log_fatal("No X RandR extension. crop-shadow-to-monitor cannot be "
"enabled.");
goto err;
}
rebuild_screen_reg(ps);
@@ -2385,12 +2326,12 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
}
// Monitor screen changes if vsync_sw is enabled and we are using
// an auto-detected refresh rate, or when Xinerama features are enabled
if (ps->randr_exists && ps->o.xinerama_shadow_crop) {
// an auto-detected refresh rate, or when X RandR features are enabled
if (ps->randr_exists && ps->o.crop_shadow_to_monitor) {
xcb_randr_select_input(ps->c, ps->root, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE);
}
cxinerama_upd_scrs(ps);
x_update_randr_monitors(ps);
{
xcb_render_create_picture_value_list_t pa = {
@@ -2502,15 +2443,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
write_pid(ps);
// When picom starts, fetch monitor positions first. Because it won't fetch the data unless property changes.
if (!ps->selmon_center_x && !ps->selmon_center_y) {
winprop_t prop = x_get_prop(ps->c, ps->root, ps->atoms->a_NET_CURRENT_MON_CENTER, 2L, XCB_ATOM_CARDINAL, 32);
if (prop.nitems == 2) {
ps->selmon_center_x = prop.p32[0];
ps->selmon_center_y = prop.p32[1];
}
free_winprop(&prop);
}
ev_init(&ps->animation_timer, animation_timer_callback);
if (fork && stderr_logger) {
@@ -2634,7 +2566,7 @@ static void session_destroy(session_t *ps) {
}
free(ps->o.blur_kerns);
free(ps->o.glx_fshader_win_str);
free_xinerama_info(ps);
x_free_randr_info(ps);
// Release custom window shaders
free(ps->o.window_shader_fg);

View File

@@ -42,8 +42,6 @@ void circulate_win(session_t *ps, xcb_circulate_notify_event_t *ce);
void root_damaged(session_t *ps);
void cxinerama_upd_scrs(session_t *ps);
void queue_redraw(session_t *ps);
void discard_pending(session_t *ps, uint32_t sequence);

View File

@@ -1098,18 +1098,19 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
if (!ps->o.wintype_option[w->window_type].full_shadow)
pixman_region32_subtract(&reg_tmp, &reg_tmp, &bshape_no_corners);
if (ps->o.xinerama_shadow_crop && w->xinerama_scr >= 0 &&
w->xinerama_scr < ps->xinerama_nscrs)
// There can be a window where number of screens
// is updated, but the screen number attached to
// the windows have not.
if (ps->o.crop_shadow_to_monitor && w->randr_monitor >= 0 &&
w->randr_monitor < ps->randr_nmonitors) {
// There can be a window where number of monitors is
// updated, but the monitor number attached to the window
// have not.
//
// Window screen number will be updated
// eventually, so here we just check to make sure
// we don't access out of bounds.
// Window monitor number will be updated eventually, so
// here we just check to make sure we don't access out of
// bounds.
pixman_region32_intersect(
&reg_tmp, &reg_tmp,
&ps->xinerama_scr_regs[w->xinerama_scr]);
&ps->randr_monitor_regs[w->randr_monitor]);
}
// Detect if the region is empty before painting
if (pixman_region32_not_empty(&reg_tmp)) {

215
src/win.c
View File

@@ -14,7 +14,6 @@
#include <xcb/render.h>
#include <xcb/xcb.h>
#include <xcb/xcb_renderutil.h>
#include <xcb/xinerama.h>
#include "atom.h"
#include "backend/backend.h"
@@ -446,6 +445,10 @@ static void win_update_properties(session_t *ps, struct managed_win *w) {
}
}
if (win_fetch_and_unset_property_stale(w, ps->atoms->a_NET_WM_DESKTOP)) {
win_update_prop_desktop(ps, w);
}
if (win_fetch_and_unset_property_stale(w, ps->atoms->aWM_CLASS)) {
if (win_update_class(ps, w)) {
win_set_flags(w, WIN_FLAGS_FACTOR_CHANGED);
@@ -472,6 +475,19 @@ static void win_update_properties(session_t *ps, struct managed_win *w) {
static void init_animation(session_t *ps, struct managed_win *w) {
CLEAR_MASK(w->animation_is_tag)
static int32_t randr_mon_center_x, randr_mon_center_y;
if (w->randr_monitor == -1) {
win_update_monitor(ps->randr_nmonitors, ps->randr_monitor_regs, w);
if (w->randr_monitor != -1) {
auto e = pixman_region32_extents(&ps->randr_monitor_regs[w->randr_monitor]);
randr_mon_center_x = (e->x2 + e->x1) / 2, randr_mon_center_y = (e->y2 + e->y1) / 2;
} else {
randr_mon_center_x = ps->root_width / 2, randr_mon_center_y = ps->root_height / 2;
}
} else {
auto e = pixman_region32_extents(&ps->randr_monitor_regs[w->randr_monitor]);
randr_mon_center_x = (e->x2 + e->x1) / 2, randr_mon_center_y = (e->y2 + e->y1) / 2;
}
static double *anim_x, *anim_y, *anim_w, *anim_h;
enum open_window_animation animation;
if (ps->o.wintype_option[w->window_type].animation != OPEN_WINDOW_ANIMATION_INVALID
@@ -486,6 +502,7 @@ static void init_animation(session_t *ps, struct managed_win *w) {
animation = ps->o.animation_for_transient_window;
}
anim_x = &w->animation_center_x, anim_y = &w->animation_center_y;
anim_w = &w->animation_w, anim_h = &w->animation_h;
@@ -532,9 +549,9 @@ static void init_animation(session_t *ps, struct managed_win *w) {
sqrt(ps->root_width * ps->root_width + ps->root_height * ps->root_height);
// Set animation
*anim_x = ps->selmon_center_x + radius * cos(angle);
*anim_y = ps->selmon_center_y + radius * sin(angle);
*anim_w = 0;
*anim_x = randr_mon_center_x + radius * cos(angle);
*anim_y = randr_mon_center_y + radius * sin(angle);
*anim_w = 0;
*anim_h = 0;
break;
case OPEN_WINDOW_ANIMATION_SLIDE_UP: // Slide up the image, without changing its location
@@ -568,7 +585,7 @@ static void init_animation(session_t *ps, struct managed_win *w) {
*anim_h = w->pending_g.height;
break;
case OPEN_WINDOW_ANIMATION_SLIDE_IN_CENTER:
*anim_x = ps->selmon_center_x;
*anim_x = randr_mon_center_x;
*anim_y = w->g.y + w->pending_g.height * 0.5;
*anim_w = w->pending_g.width;
*anim_h = w->pending_g.height;
@@ -580,7 +597,7 @@ static void init_animation(session_t *ps, struct managed_win *w) {
w->animation_dest_h = w->pending_g.height;
break;
case OPEN_WINDOW_ANIMATION_SLIDE_OUT_CENTER:
w->animation_dest_center_x = ps->selmon_center_x;
w->animation_dest_center_x = randr_mon_center_x;
w->animation_dest_center_y = w->pending_g.y;
w->animation_dest_w = w->pending_g.width;
w->animation_dest_h = w->pending_g.height;
@@ -597,8 +614,8 @@ static void init_animation(session_t *ps, struct managed_win *w) {
*anim_h = 0;
break;
case OPEN_WINDOW_ANIMATION_MINIMIZE:
*anim_x = ps->selmon_center_x;
*anim_y = ps->selmon_center_y;
*anim_x = randr_mon_center_x;
*anim_y = randr_mon_center_y;
*anim_w = 0;
*anim_h = 0;
break;
@@ -673,10 +690,10 @@ void win_process_update_flags(session_t *ps, struct managed_win *w) {
// Determine if a window should animate
if (win_should_animate(ps, w)) {
win_update_bounding_shape(ps, w);
if (w->pending_g.y < 0 && w->g.y > 0 && abs(w->pending_g.y - w->g.y) >= w->pending_g.height)
w->dwm_mask = ANIM_PREV_TAG;
else if (w->pending_g.y > 0 && w->g.y < 0 && abs(w->pending_g.y - w->g.y) >= w->pending_g.height)
w->dwm_mask = ANIM_NEXT_TAG;
// if (w->pending_g.y < 0 && w->g.y > 0 && abs(w->pending_g.y - w->g.y) >= w->pending_g.height)
// w->dwm_mask = ANIM_PREV_TAG;
// else if (w->pending_g.y > 0 && w->g.y < 0 && abs(w->pending_g.y - w->g.y) >= w->pending_g.height)
// w->dwm_mask = ANIM_NEXT_TAG;
if (!was_visible || w->dwm_mask) {
@@ -694,7 +711,6 @@ void win_process_update_flags(session_t *ps, struct managed_win *w) {
w->g.width = (uint16_t)round(w->animation_w);
w->g.height = (uint16_t)round(w->animation_h);
}
} else {
w->animation_is_tag = ANIM_IN_TAG;
w->animation_dest_center_x =
@@ -705,37 +721,37 @@ void win_process_update_flags(session_t *ps, struct managed_win *w) {
w->animation_dest_h = w->pending_g.height;
}
CLEAR_MASK(w->dwm_mask)
w->g.border_width = w->pending_g.border_width;
double x_dist = w->animation_dest_center_x - w->animation_center_x;
double y_dist = w->animation_dest_center_y - w->animation_center_y;
double w_dist = w->animation_dest_w - w->animation_w;
double h_dist = w->animation_dest_h - w->animation_h;
w->animation_inv_og_distance =
1.0 / sqrt(x_dist * x_dist + y_dist * y_dist +
w_dist * w_dist + h_dist * h_dist);
CLEAR_MASK(w->dwm_mask)
w->g.border_width = w->pending_g.border_width;
double x_dist = w->animation_dest_center_x - w->animation_center_x;
double y_dist = w->animation_dest_center_y - w->animation_center_y;
double w_dist = w->animation_dest_w - w->animation_w;
double h_dist = w->animation_dest_h - w->animation_h;
w->animation_inv_og_distance =
1.0 / sqrt(x_dist * x_dist + y_dist * y_dist +
w_dist * w_dist + h_dist * h_dist);
if (isinf(w->animation_inv_og_distance))
w->animation_inv_og_distance = 0;
if (isinf(w->animation_inv_og_distance))
w->animation_inv_og_distance = 0;
// We only grab images if w->reg_ignore_valid is true as
// there's an ev_shape_notify() event fired quickly on new windows
// for e.g. in case of Firefox main menu and ev_shape_notify()
// sets the win_set_flags(w, WIN_FLAGS_SIZE_STALE); which
// brakes the new image captured and because this same event
// also sets w->reg_ignore_valid = false; too we check for it
if (w->reg_ignore_valid) {
if (w->old_win_image) {
ps->backend_data->ops->release_image(ps->backend_data,
w->old_win_image);
w->old_win_image = NULL;
}
// We only grab images if w->reg_ignore_valid is true as
// there's an ev_shape_notify() event fired quickly on new windows
// for e.g. in case of Firefox main menu and ev_shape_notify()
// sets the win_set_flags(w, WIN_FLAGS_SIZE_STALE); which
// brakes the new image captured and because this same event
// also sets w->reg_ignore_valid = false; too we check for it
if (w->reg_ignore_valid) {
if (w->old_win_image) {
ps->backend_data->ops->release_image(ps->backend_data,
w->old_win_image);
w->old_win_image = NULL;
}
// We only grab
if (w->win_image) {
w->old_win_image = ps->backend_data->ops->clone_image(
ps->backend_data, w->win_image, &w->bounding_shape);
}
// We only grab
if (w->win_image) {
w->old_win_image = ps->backend_data->ops->clone_image(
ps->backend_data, w->win_image, &w->bounding_shape);
}
}
w->animation_progress = 0.0;
@@ -755,7 +771,7 @@ void win_process_update_flags(session_t *ps, struct managed_win *w) {
win_clear_flags(w, WIN_FLAGS_POSITION_STALE);
}
win_update_screen(ps->xinerama_nscrs, ps->xinerama_scr_regs, w);
win_update_monitor(ps->randr_nmonitors, ps->randr_monitor_regs, w);
}
if (win_check_flags_all(w, WIN_FLAGS_PROPERTY_STALE)) {
@@ -1157,6 +1173,17 @@ void win_update_prop_shadow_raw(session_t *ps, struct managed_win *w) {
free_winprop(&prop);
}
void win_update_prop_desktop(session_t *ps, struct managed_win *w) {
winprop_t prop = x_get_prop(ps->c, w->base.id, ps->atoms->a_NET_WM_DESKTOP, 1,
XCB_ATOM_CARDINAL, 32);
if (!prop.nitems) {
w->cur_desktop = w->cur_desktop;
} else {
w->cur_desktop = *prop.c32;
}
free_winprop(&prop);
}
static void win_set_shadow(session_t *ps, struct managed_win *w, bool shadow_new) {
if (w->shadow == shadow_new) {
return;
@@ -1400,13 +1427,24 @@ static void win_determine_rounded_corners(session_t *ps, struct managed_win *w)
return;
}
// Don't round full screen windows & excluded windows
if ((w && win_is_fullscreen(ps, w)) ||
c2_match(ps, w, ps->o.rounded_corners_blacklist, NULL)) {
void *radius_override = NULL;
if (c2_match(ps, w, ps->o.corner_radius_rules, &radius_override)) {
log_debug("Matched corner rule! %d", w->corner_radius);
}
// Don't round full screen windows & excluded windows,
// unless we find a corner override in corner_radius_rules
if (!radius_override && ((w && win_is_fullscreen(ps, w)) ||
c2_match(ps, w, ps->o.rounded_corners_blacklist, NULL))) {
w->corner_radius = 0;
log_debug("Not rounding corners for window %#010x", w->base.id);
} else {
w->corner_radius = ps->o.corner_radius;
if (radius_override) {
w->corner_radius = (int)(long)radius_override;
} else {
w->corner_radius = ps->o.corner_radius;
}
log_debug("Rounding corners for window %#010x", w->base.id);
// Initialize the border color to an invalid value
w->border_col[0] = w->border_col[1] = w->border_col[2] =
@@ -1467,7 +1505,7 @@ void win_on_factor_change(session_t *ps, struct managed_win *w) {
// focused state of the window
win_update_focused(ps, w);
if (w->animation_progress > 0.9999 || w->animation_progress < 0.0001) {
if (w->animation_progress > 0.99999999 || (w->animation_progress == 0.0 && ps->animation_time != 0L)) {
win_determine_shadow(ps, w);
win_determine_clip_shadow_above(ps, w);
}
@@ -1818,7 +1856,7 @@ struct win *fill_win(session_t *ps, struct win *w) {
.shadow = false,
.clip_shadow_above = false,
.fg_shader = NULL,
.xinerama_scr = -1,
.randr_monitor = -1,
.mode = WMODE_TRANS,
.ever_damaged = false,
.client_win = XCB_NONE,
@@ -1970,6 +2008,7 @@ struct win *fill_win(session_t *ps, struct win *w) {
ps->atoms->a_NET_WM_NAME, ps->atoms->aWM_CLASS,
ps->atoms->aWM_WINDOW_ROLE, ps->atoms->a_COMPTON_SHADOW,
ps->atoms->aWM_CLIENT_LEADER, ps->atoms->aWM_TRANSIENT_FOR,
ps->atoms->a_NET_WM_DESKTOP
};
win_set_properties_stale(new, init_stale_props, ARR_SIZE(init_stale_props));
@@ -2662,29 +2701,31 @@ void unmap_win_start(session_t *ps, struct managed_win *w) {
w->opacity_target_old = fmax(w->opacity_target, w->opacity_target_old);
w->opacity_target = win_calc_opacity_target(ps, w);
if (ps->o.animations && ps->o.animation_for_unmap_window != OPEN_WINDOW_ANIMATION_NONE && ps->o.wintype_option[w->window_type].animation) {
w->dwm_mask = ANIM_UNMAP;
init_animation(ps, w);
if (ps->o.animations &&
ps->o.animation_for_unmap_window != OPEN_WINDOW_ANIMATION_NONE &&
ps->o.wintype_option[w->window_type].animation) {
w->dwm_mask = ANIM_UNMAP;
init_animation(ps, w);
double x_dist = w->animation_dest_center_x - w->animation_center_x;
double y_dist = w->animation_dest_center_y - w->animation_center_y;
double w_dist = w->animation_dest_w - w->animation_w;
double h_dist = w->animation_dest_h - w->animation_h;
w->animation_inv_og_distance =
1.0 / sqrt(x_dist * x_dist + y_dist * y_dist +
w_dist * w_dist + h_dist * h_dist);
double x_dist = w->animation_dest_center_x - w->animation_center_x;
double y_dist = w->animation_dest_center_y - w->animation_center_y;
double w_dist = w->animation_dest_w - w->animation_w;
double h_dist = w->animation_dest_h - w->animation_h;
w->animation_inv_og_distance =
1.0 / sqrt(x_dist * x_dist + y_dist * y_dist +
w_dist * w_dist + h_dist * h_dist);
if (isinf(w->animation_inv_og_distance))
w->animation_inv_og_distance = 0;
if (isinf(w->animation_inv_og_distance))
w->animation_inv_og_distance = 0;
w->animation_progress = 0.0;
w->animation_progress = 0.0;
if (w->old_win_image) {
ps->backend_data->ops->release_image(ps->backend_data,
w->old_win_image);
w->old_win_image = NULL;
}
}
if (w->old_win_image) {
ps->backend_data->ops->release_image(ps->backend_data,
w->old_win_image);
w->old_win_image = NULL;
}
}
#ifdef CONFIG_DBUS
// Send D-Bus signal
@@ -2740,33 +2781,25 @@ bool win_skip_fading(session_t *ps, struct managed_win *w) {
return win_check_fade_finished(ps, w);
}
/**
* Get the Xinerama screen a window is on.
*
* Return an index >= 0, or -1 if not found.
*
* TODO(yshui) move to x.c
* TODO(yshui) use xrandr
*/
void win_update_screen(int nscreens, region_t *screens, struct managed_win *w) {
w->xinerama_scr = -1;
for (int i = 0; i < nscreens; i++) {
auto e = pixman_region32_extents(&screens[i]);
if (e->x1 <= w->g.x && e->y1 <= w->g.y && e->x2 >= w->g.x + w->widthb &&
e->y2 >= w->g.y + w->heightb) {
w->xinerama_scr = i;
log_debug("Window %#010x (%s), %dx%d+%dx%d, is on screen "
"%d "
"(%dx%d+%dx%d)",
w->base.id, w->name, w->g.x, w->g.y, w->widthb, w->heightb,
i, e->x1, e->y1, e->x2 - e->x1, e->y2 - e->y1);
// TODO(absolutelynothelix): rename to x_update_win_(randr_?)monitor and move to
// the x.c.
void win_update_monitor(int nmons, region_t *mons, struct managed_win *mw) {
for (int i = 0; i < nmons; i++) {
auto e = pixman_region32_extents(&mons[i]);
// if (e->x1 <= mw->g.x && e->y1 <= mw->g.y &&
// e->x2 >= mw->g.x + mw->widthb && e->y2 >= mw->g.y + mw->heightb) {
if (e->x1 <= mw->pending_g.x && e->x2 >= mw->pending_g.x + mw->widthb) {
mw->randr_monitor = i;
log_debug("Window %#010x (%s), %dx%d+%dx%d, is entirely on the "
"monitor %d (%dx%d+%dx%d)",
mw->base.id, mw->name, mw->g.x, mw->g.y, mw->widthb,
mw->heightb, i, e->x1, e->y1, e->x2 - e->x1, e->y2 - e->y1);
return;
}
}
log_debug("Window %#010x (%s), %dx%d+%dx%d, is not contained by any "
"screen",
w->base.id, w->name, w->g.x, w->g.y, w->g.width, w->g.height);
mw->randr_monitor = -1;
log_debug("Window %#010x (%s), %dx%d+%dx%d, is not entirely on any monitor",
mw->base.id, mw->name, mw->g.x, mw->g.y, mw->widthb, mw->heightb);
}
/// Map an already registered window

View File

@@ -125,6 +125,7 @@ struct managed_win {
struct managed_win *prev_trans;
/// Number of windows above this window
int stacking_rank;
uint32_t cur_desktop;
// TODO(yshui) rethink reg_ignore
// Core members
@@ -137,8 +138,8 @@ struct managed_win {
struct win_geometry g;
/// Updated geometry received in events
struct win_geometry pending_g;
/// Xinerama screen this window is on.
int xinerama_scr;
/// X RandR monitor this window is on.
int randr_monitor;
/// Window visual pict format
const xcb_render_pictforminfo_t *pictfmt;
/// Client window visual pict format
@@ -170,8 +171,8 @@ struct managed_win {
/// opacity state, window geometry, window mapped/unmapped state,
/// window mode of the windows above. DOES NOT INCLUDE the body of THIS WINDOW.
/// NULL means reg_ignore has not been calculated for this window.
/// 1 = tag prev , 2 = tag next, 4 = unmap
uint32_t dwm_mask;
/// 1 = tag prev , 2 = tag next, 4 = unmap
uint32_t dwm_mask;
rc_region_t *reg_ignore;
/// Whether the reg_ignore of all windows beneath this window are valid
bool reg_ignore_valid;
@@ -202,11 +203,11 @@ struct managed_win {
/// Inverse of the window distance at the start of animation, for
/// tracking animation progress
double animation_inv_og_distance;
/// Animation info if it is a tag change & check if its changing window sizes
/// 0: no tag change
/// 1: normal tag change animation
/// 2: tag change animation that effects window size
uint16_t animation_is_tag;
/// Animation info if it is a tag change & check if its changing window sizes
/// 0: no tag change
/// 1: normal tag change animation
/// 2: tag change animation that effects window size
uint16_t animation_is_tag;
// Client window related members
/// ID of the top-level client window of the window.
@@ -379,7 +380,11 @@ void win_recheck_client(session_t *ps, struct managed_win *w);
*/
double attr_pure win_calc_opacity_target(session_t *ps, const struct managed_win *w);
bool attr_pure win_should_dim(session_t *ps, const struct managed_win *w);
void win_update_screen(int nscreens, region_t *screens, struct managed_win *w);
// TODO(absolutelynothelix): rename to x_update_win_(randr_?)monitor and move to
// the x.h.
void win_update_monitor(int nmons, region_t *mons, struct managed_win *mw);
/**
* Retrieve the bounding shape of a window.
*/
@@ -561,3 +566,5 @@ static inline bool attr_pure attr_unused win_has_frame(const struct managed_win
return w->g.border_width || w->frame_extents.top || w->frame_extents.left ||
w->frame_extents.right || w->frame_extents.bottom;
}
void win_update_prop_desktop(session_t *ps, struct managed_win *w);

38
src/x.c
View File

@@ -9,6 +9,7 @@
#include <xcb/composite.h>
#include <xcb/damage.h>
#include <xcb/glx.h>
#include <xcb/randr.h>
#include <xcb/render.h>
#include <xcb/sync.h>
#include <xcb/xcb.h>
@@ -787,3 +788,40 @@ xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen) {
return NULL;
}
void x_update_randr_monitors(session_t *ps) {
x_free_randr_info(ps);
if (!(ps->o.crop_shadow_to_monitor || ps->o.animations) || !ps->randr_exists) {
return;
}
xcb_randr_get_monitors_reply_t *r = xcb_randr_get_monitors_reply(
ps->c, xcb_randr_get_monitors(ps->c, ps->root, true), NULL);
if (!r) {
return;
}
ps->randr_nmonitors = xcb_randr_get_monitors_monitors_length(r);
ps->randr_monitor_regs = ccalloc(ps->randr_nmonitors, region_t);
xcb_randr_monitor_info_iterator_t monitor_info_it =
xcb_randr_get_monitors_monitors_iterator(r);
for (int i = 0; monitor_info_it.rem; xcb_randr_monitor_info_next(&monitor_info_it)) {
xcb_randr_monitor_info_t *mi = monitor_info_it.data;
pixman_region32_init_rect(&ps->randr_monitor_regs[i++], mi->x, mi->y,
mi->width, mi->height);
}
free(r);
}
void x_free_randr_info(session_t *ps) {
if (ps->randr_monitor_regs) {
for (int i = 0; i < ps->randr_nmonitors; i++) {
pixman_region32_fini(&ps->randr_monitor_regs[i]);
}
free(ps->randr_monitor_regs);
ps->randr_monitor_regs = NULL;
}
ps->randr_nmonitors = 0;
}

10
src/x.h
View File

@@ -302,4 +302,14 @@ x_get_pictfmt_for_standard(xcb_connection_t *c, xcb_pict_standard_t std);
xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen);
/**
* X RandR-related functions.
*
* The x_update_randr_monitors function populates ps->randr_nmonitors and
* ps->randr_monitor_regs with the data X RandR provided and the
* x_free_randr_info function frees them.
*/
void x_update_randr_monitors(session_t *ps);
void x_free_randr_info(session_t *ps);
uint32_t attr_deprecated xcb_generate_id(xcb_connection_t *c);

View File

@@ -64,8 +64,9 @@ shadow-exclude = [
#
# shadow-exclude-reg = ""
# Crop shadow of a window fully on a particular Xinerama screen to the screen.
# xinerama-shadow-crop = false
# Crop shadow of a window fully on a particular monitor to that monitor. This is
# currently implemented using the X RandR extension.
# crop-shadow-to-monitor = false
#################################
@@ -154,6 +155,11 @@ rounded-corners-exclude = [
"window_type = 'desktop'"
];
corner-radius-rules = [
"10:window_type = 'dock'",
"0x32:window_type = 'desktop'"
];
#################################
# Background-Blurring #