Added New Backend Dual Kawase Blur + Rounded Corners - merged with Ibhagwan

This commit is contained in:
jon 2020-07-14 18:04:45 +02:00
parent d6bc68146b
commit 0375dad5d1
54 changed files with 4696 additions and 1620 deletions

View File

@ -1,13 +0,0 @@
name: coding-style
on: pull_request
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: git fetch --depth=1 origin ${{ github.event.pull_request.base.sha }}
- uses: yshui/git-clang-format-lint@v1.10
with:
base: ${{ github.event.pull_request.base.sha }}

View File

@ -1,14 +0,0 @@
name: coding-style
on: push
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 2
- uses: yshui/git-clang-format-lint@v1.10
with:
base: ${{ github.event.ref }}~1

2
.gitignore vendored
View File

@ -52,5 +52,3 @@ doxygen/
/src/backtrace-symbols.[ch]
/compton*.trace
*.orig
/tests/log
/tests/testcases/__pycache__/

22
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,22 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"/usr/include",
"/usr/include/pixman-1",
"${workspaceFolder}/**"
],
"defines": [
"CONFIG_OPENGL",
"_POSIX_C_SOURCE 199309L"
],
"compilerPath": "/bin/gcc",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "clang-x64",
"compileCommands": "${workspaceFolder}/build/compile_commands.json"
}
],
"version": 4
}

26
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,26 @@
{
"configurations": [
{
"targetArchitecture": "x64",
"name": "Debug with Meson",
"type": "cppdbg",
"request": "launch",
"cwd": "${workspaceRoot}",
"program": "${workspaceRoot}/build/src/picom",
"preLaunchTask": "build debug meson",
"stopAtEntry": false,
"launchCompleteCommand": "exec-run",
"linux": {
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb"
},
"osx": {
"MIMode": "lldb"
},
"windows": {
"MIMode": "gdb",
"miDebuggerPath": "C:\\MinGw\\bin\\gdb.exe"
}
}
]
}

25
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,25 @@
{
"tasks": [
{
"label": "build debug meson",
"type": "shell",
"command": "meson build --buildtype=debug && ninja -C build",
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "build release meson",
"type": "shell",
"command": "meson build --buildtype=release && ninja -C build",
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": true
}
}
],
"version": "2.0.0"
}

View File

@ -4,10 +4,7 @@ Open an issue or pull request if you don't want your name listed here.
Adam Jackson <ajax@nwnk.net>
Alexander Kapshuna <kapsh@kap.sh>
Antonin Décimo <antonin.decimo@gmail.com>
Antonio Vivace <dev@avivace.com>
Avi-D-coder <avi.the.coder@gmail.com>
Ben Friesen <bfriesen95@gmail.com>
Bernd Busse <bernd@busse-net.de>
Brottweiler <tibell.christoffer@gmail.com>
Carl Worth <cworth@cworth.org>
Christopher Jeffrey <chjjeffrey@gmail.com>
@ -15,46 +12,36 @@ Corax26 <cor.ax26@gmail.com>
Dan Elkouby <streetwalkermc@gmail.com>
Dana Jansens <danakj@orodu.net>
Dave Airlie <airlied@linux.ie>
David Schlachter
dolio
Duncan <duncan.britton@outlook.com>
Dylan Araps <dylan.araps@gmail.com>
Einar Lielmanis <einars@gmail.com>
Eric Anholt <anholt@freebsd.org> <eric@anholt.net>
Greg Flynn
hasufell <julian.ospald@googlemail.com>
James Cloos <cloos@jhcloos.com>
Jamey Sharp <jamey@minilop.net>
Jan Beich <jbeich@FreeBSD.org>
Jarrad <jarrad.whitaker@gmail.com>
Javeed Shaikh <syscrash2k@gmail.com>
Jerónimo Navarro <jnavarro@ancasrl.com.ar>
Keith Packard <keithp@keithp.com>
Kevin Kelley <kelleyk@kelleyk.net>
mæp <m.aep@live.com>
Mark Tiefenbruck <mark@fluxbox.org>
Matthew Allum <breakfast@10.am>
Maxim Solovyov <visleaf@protonmail.com>
Michael Reed <supertron421@gmail.com>
Michele Lambertucci <michele.lambertucci@mail.polimi.it>
Namkhai Bourquin <namkhai.n3@protonmail.com>
Nate Hart <nejthan@gmail.com>
notfoss <static.vortex@gmx.com>
@Paradigm0001
Patrick Collins <Patricol@users.noreply.github.com>
Peter Mattern <matternp@arcor.de>
Phil Blundell <pb@reciva.com>
Que Quotion <quequotion@bugmenot.com>
Richard Grenville <pyxlcy@gmail.com>
Rytis Karpuska <rytis.karpuska@gmail.com>
Scott Leggett <scott@sl.id.au>
Tasos Sahanidis <tasos@tasossah.com>
The Gitter Badger <badger@gitter.im>
Tilman Sauerbeck <tilman@code-monkey.de>
Tim van Dalen <Tim@timvdalen.nl>
Tomas Janousek <tomi@nomi.cz>
Uli Schlachter <psychon@znc.in>
Walter Lapchynski <wxl@ubuntu.com>
Will Dietz <w@wdtz.org>
XeCycle <XeCycle@Gmail.com>
Yuxuan Shui <yshuiv7@gmail.com>
ಠ_ಠ <easteregg@verfriemelt.org>

View File

@ -1,24 +1,21 @@
picom
=======
This is a forked version from Sandmark's picom branch, including Blackcapcoder's animation code inside. The animations here are further smoothed and time deltas reduced from 1ms to 40us for high refresh rates and buttery smooth transitions.
## Why another picom fork?
You'll need to run it with the experimental backend with:
TL;DR: rounded corners and dual_kawase blur on all backends.
`picom --experimental-backend`
This fork contains:
- Dual kawase blur method from [tryone144](https://github.com/tryone144/compton) as well as his new [feature/dual_kawase branch](https://github.com/tryone144/compton/tree/feature/dual_kawase) which implements the dual kawase blur method on the experimental glx backend.
- Rounded corners code from [sdhand](https://github.com/sdhand/picom) which is also ported to the experimetnal XRender backend.
- New code for rounded corners on the glx backend using GLSL frangment shader
For more information read [my reddit post](https://www.reddit.com/r/unixporn/comments/fs8trg/oc_comptonpicom_fork_with_both_tryone144s_dual/)
Your picom config can also now take advantage of some of the options that were previously implemented in blackcapcoder's compton version:
- [x] * `transition-length` length of animation in milliseconds (default: 300)
- [x] * `transition-pow-x` animation easing on the x-axis (default: 0.1)
- [x] * `transition-pow-y` animation easing on the y-axis (default: 0.1)
- [x] * `transition-pow-w` animation easing on the window width (default: 0.1)
- [x] * `transition-pow-h` animation easing on the window height (default: 0.1)
- [x] * `size-transition` whether to animate window size changes (default: true)
- [ ] * `spawn-center-screen` whether to animate new windows from the center of the screen (default: false)
- [ ] * `spawn-center` whether to animate new windows from their own center (default: true)
- [ ] * `no-scale-down` Whether to animate down scaling (some programs handle this poorly) (default: false)
----
**This is a development branch, bugs to be expected**
This is forked from the original Compton because it seems to have become unmaintained.
@ -98,7 +95,6 @@ Assuming you already have all the usual building tools installed (e.g. gcc, pyth
* xcb-image
* xcb-present
* xcb-xinerama
* xcb-glx
* pixman
* libdbus (optional, disable with the `-Ddbus=false` meson configure flag)
* libconfig (optional, disable with the `-Dconfig_file=false` meson configure flag)
@ -110,7 +106,7 @@ Assuming you already have all the usual building tools installed (e.g. gcc, pyth
On Debian based distributions (e.g. Ubuntu), the list of needed packages are
```
libxext-dev libxcb1-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
libxext-dev libxcb1-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 libpixman-1-dev libdbus-1-dev libconfig-dev libgl1-mesa-dev libpcre2-dev libevdev-dev uthash-dev libev-dev libx11-xcb-dev
```
To build the documents, you need `asciidoc`

View File

@ -1,41 +1,38 @@
#!/bin/sh
# == Declare stderr function ===
# === Verify `compton --dbus` status ===
stderr() {
printf "\033[1;31m%s\n\033[0m" "$@" >&2
}
# === Verify `picom --dbus` status ===
if [ -z "$(dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply /org/freedesktop/DBus org.freedesktop.DBus.ListNames | grep compton)" ]; then
stderr "picom DBus interface unavailable"
if [ -n "$(pgrep picom)" ]; then
stderr "picom running without dbus interface"
#killall picom & # Causes all windows to flicker away and come back ugly.
#picom --dbus & # Causes all windows to flicker away and come back beautiful
if [ -z "`dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply /org/freedesktop/DBus org.freedesktop.DBus.ListNames | grep compton`" ]; then
echo "compton DBus interface unavailable"
if [ -n "`pgrep picom`" ]; then
echo "compton running without dbus interface"
#killall compton & # Causes all windows to flicker away and come back ugly.
#compton --dbus & # Causes all windows to flicker away and come back beautiful
else
stderr "picom not running"
echo "compton not running"
fi
exit 1
exit 1;
fi
# === Setup sed ===
SED="${SED:-$(command -v gsed || printf 'sed')}"
if [ -z "$SED" ]; then
SED="sed"
command -v gsed > /dev/null && SED="gsed"
fi
# === Get connection parameters ===
dpy=$(printf "$DISPLAY" | tr -c '[:alnum:]' _)
dpy=$(echo -n "$DISPLAY" | tr -c '[:alnum:]' _)
if [ -z "$dpy" ]; then
stderr "Cannot find display."
exit 1
echo "Cannot find display."
exit 1;
fi
service="com.github.chjj.compton.${dpy}"
interface="com.github.chjj.compton"
picom_dbus="dbus-send --print-reply --dest="${service}" / "${interface}"."
compton_dbus="dbus-send --print-reply --dest="${service}" / "${interface}"."
type_win='uint32'
type_enum='uint32'
@ -46,7 +43,7 @@ if [ -z "$1" -o "$1" = "selected" ]; then
window=$(xwininfo -frame | sed -n 's/^xwininfo: Window id: \(0x[[:xdigit:]][[:xdigit:]]*\).*/\1/p') # Select window by mouse
elif [ "$1" = "focused" ]; then
# Ensure we are tracking focus
window=$(${picom_dbus}find_win string:focused | $SED -n 's/^[[:space:]]*'${type_win}'[[:space:]]*\([[:digit:]]*\).*/\1/p') # Query picom for the active window
window=$(${compton_dbus}find_win string:focused | $SED -n 's/^[[:space:]]*'${type_win}'[[:space:]]*\([[:digit:]]*\).*/\1/p') # Query compton for the active window
elif echo "$1" | grep -Eiq '^([[:digit:]][[:digit:]]*|0x[[:xdigit:]][[:xdigit:]]*)$'; then
window="$1" # Accept user-specified window-id if the format is correct
else
@ -55,15 +52,15 @@ fi
# Color invert the selected or focused window
if [ -n "$window" ]; then
invert_status="$(${picom_dbus}win_get "${type_win}:${window}" string:invert_color | $SED -n 's/^[[:space:]]*boolean[[:space:]]*\([[:alpha:]]*\).*/\1/p')"
invert_status="$(${compton_dbus}win_get "${type_win}:${window}" string:invert_color | $SED -n 's/^[[:space:]]*boolean[[:space:]]*\([[:alpha:]]*\).*/\1/p')"
if [ "$invert_status" = true ]; then
invert=0 # Set the window to have normal color
else
invert=1 # Set the window to have inverted color
fi
${picom_dbus}win_set "${type_win}:${window}" string:invert_color_force "${type_enum}:${invert}" &
${compton_dbus}win_set "${type_win}:${window}" string:invert_color_force "${type_enum}:${invert}" &
else
stderr "Cannot find $1 window."
exit 1
echo "Cannot find $1 window."
exit 1;
fi
exit 0
exit 0;

View File

@ -7,7 +7,6 @@ if get_option('with_docs')
'picom-version='+version,
'--format', 'manpage', '@INPUT@', '-D',
meson.current_build_dir()],
install: true,
install_dir: join_paths(get_option('mandir'), 'man1'))
install: true, install_dir: 'share/man/man1/')
endforeach
endif

View File

@ -106,6 +106,18 @@ OPTIONS
*--inactive-dim* 'VALUE'::
Dim inactive windows. (0.0 - 1.0, defaults to 0.0)
*--corner-radius* 'VALUE'::
Round the corners of windows. (defaults to 0).
*--rounded-corners-exclude* 'CONDITION'::
Exclude conditions for rounded corners.
*--round-borders* 'VALUE'::
When rounding corners, Round the borders of windows. (defaults to 1).
*--round-borders-exclude* 'CONDITION'::
Exclude conditions for rounding borders.
*--mark-wmwin-focused*::
Try to detect WM windows (a non-override-redirect window with no child that has 'WM_STATE') and mark them as active.
@ -140,7 +152,7 @@ OPTIONS
Use EWMH '_NET_ACTIVE_WINDOW' to determine currently focused window, rather than listening to 'FocusIn'/'FocusOut' event. Might have more accuracy, provided that the WM supports it.
*--unredir-if-possible*::
Unredirect all windows if a full-screen opaque window is detected, to maximize performance for full-screen windows. Known to cause flickering when redirecting/unredirecting windows.
Unredirect all windows if a full-screen opaque window is detected, to maximize performance for full-screen windows. Known to cause flickering when redirecting/unredirecting windows. *--paint-on-overlay* may make the flickering less obvious.
*--unredir-if-possible-delay* 'MILLISECONDS'::
Delay before unredirecting the window, in milliseconds. Defaults to 0.
@ -166,7 +178,7 @@ OPTIONS
*--detect-client-leader*::
Use 'WM_CLIENT_LEADER' to group windows, and consider windows in the same group focused at the same time. 'WM_TRANSIENT_FOR' has higher priority if *--detect-transient* is enabled, too.
*--blur-method*, *--blur-size*, *--blur-deviation*::
*--blur-method*, *--blur-size*, *--blur-deviation, *--blur-strength*::
Parameters for background blurring, see the *BLUR* section for more information.
*--blur-background*::
@ -407,6 +419,9 @@ Available options of the 'blur' section are: ::
*deviation*:::
A floating point number. The standard deviation for the 'gaussian' blur method. Corresponds to the *--blur-deviation* command line option (default: 0.84089642).
*strength*:::
An integer in the range 1-20. The strength of the 'dual_kawase' blur method. Corresponds to the *--blur-strength* command line option. If not specified, the value requested by *--blur-size* is approximated.
*kernel*:::
A string. The kernel to use for the 'kernel' blur method, specified in the same format as the *--blur-kerns* option. Corresponds to the *--blur-kerns* command line option.

View File

@ -1,4 +1,4 @@
project('picom', 'c', version: '8',
project('picom', 'c', version: '7',
default_options: ['c_std=c11'])
cc = meson.get_compiler('c')
@ -70,14 +70,11 @@ subdir('src')
subdir('man')
install_data('bin/picom-trans', install_dir: get_option('bindir'))
install_data('compton.desktop', install_dir: 'share/applications')
install_data('picom.desktop', install_dir: 'share/applications')
install_data('media/icons/48x48/compton.png',
install_dir: 'share/icons/hicolor/48x48/apps')
install_data('media/compton.svg',
install_dir: 'share/icons/hicolor/scalable/apps')
if get_option('compton')
install_data('compton.desktop', install_dir: 'share/applications')
install_data('media/icons/48x48/compton.png',
install_dir: 'share/icons/hicolor/48x48/apps')
install_data('media/compton.svg',
install_dir: 'share/icons/hicolor/scalable/apps')
meson.add_install_script('meson/install.sh')
endif
meson.add_install_script('meson/install.sh')

View File

@ -9,8 +9,6 @@ option('dbus', type: 'boolean', value: true, description: 'Enable support for D-
option('xrescheck', type: 'boolean', value: false, description: 'Enable X resource leak checker (for debug only)')
option('compton', type: 'boolean', value: true, description: 'Install backwards compat with compton')
option('with_docs', type: 'boolean', value: false, description: 'Build documentation and man pages')
option('modularize', type: 'boolean', value: false, description: 'Build with clang\'s module system')

View File

@ -1,3 +1,26 @@
#################################
# Corners #
#################################
# requires: https://github.com/sdhand/compton
corner-radius = 25.0;
rounded-corners-exclude = [
#"window_type = 'normal'",
"class_g = 'awesome'",
"class_g = 'URxvt'",
"class_g = 'XTerm'",
"class_g = 'kitty'",
"class_g = 'Alacritty'",
"class_g = 'Polybar'",
"class_g = 'code-oss'",
#"class_g = 'TelegramDesktop'",
"class_g = 'firefox'",
"class_g = 'Thunderbird'"
];
round-borders = 1;
round-borders-exclude = [
#"class_g = 'TelegramDesktop'",
];
#################################
# Shadows #
#################################
@ -8,7 +31,7 @@
# unless explicitly requested using the wintypes option.
#
# shadow = false
shadow = true;
shadow = false;
# The blur radius for shadows, in pixels. (defaults to 12)
# shadow-radius = 12
@ -66,6 +89,8 @@ shadow-exclude = [
"class_g = 'Conky'",
"class_g ?= 'Notify-osd'",
"class_g = 'Cairo-clock'",
"class_g = 'slop'",
"class_g = 'Polybar'",
"_GTK_FRAME_EXTENTS@:c"
];
@ -88,7 +113,7 @@ shadow-exclude = [
# Fade windows in/out when opening/closing and when opacity changes,
# unless no-fading-openclose is used.
# fading = false
fading = true
fading = true;
# Opacity change between steps while fading in. (0.01 - 1.0, defaults to 0.028)
# fade-in-step = 0.028
@ -102,7 +127,10 @@ fade-out-step = 0.03;
# fade-delta = 10
# Specify a list of conditions of windows that should not be faded.
# fade-exclude = []
# don't need this, we disable fading for all normal windows with wintypes: {}
fade-exclude = [
"class_g = 'slop'" # maim
]
# Do not fade on window open/close.
# no-fading-openclose = false
@ -132,14 +160,18 @@ frame-opacity = 0.7;
inactive-opacity-override = false;
# Default opacity for active windows. (0.0 - 1.0, defaults to 1.0)
# active-opacity = 1.0
active-opacity = 1.0;
# Dim inactive windows. (0.0 - 1.0, defaults to 0.0)
# inactive-dim = 0.0
# Specify a list of conditions of windows that should always be considered focused.
# focus-exclude = []
focus-exclude = [ "class_g = 'Cairo-clock'" ];
focus-exclude = [
"class_g = 'Cairo-clock'",
"class_g = 'Bar'", # lemonbar
"class_g = 'slop'" # maim
];
# Use fixed inactive dim value, instead of adjusting according to window opacity.
# inactive-dim-fixed = 1.0
@ -152,6 +184,21 @@ focus-exclude = [ "class_g = 'Cairo-clock'" ];
# opacity-rule = [ "80:class_g = 'URxvt'" ];
#
# opacity-rule = []
opacity-rule = [
"80:class_g = 'Bar'", # lemonbar
"100:class_g = 'slop'", # maim
"100:class_g = 'XTerm'",
"100:class_g = 'URxvt'",
"100:class_g = 'kitty'",
"100:class_g = 'Alacritty'",
"80:class_g = 'Polybar'",
"100:class_g = 'code-oss'",
"100:class_g = 'Meld'",
"70:class_g = 'TelegramDesktop'",
"90:class_g = 'Joplin'",
"100:class_g = 'firefox'",
"100:class_g = 'Thunderbird'"
];
#################################
@ -169,18 +216,18 @@ focus-exclude = [ "class_g = 'Cairo-clock'" ];
# Bad in performance, with driver-dependent behavior.
# The name of the switch may change without prior notifications.
#
# blur-background = false
# blur-background = true;
# Blur background of windows when the window frame is not opaque.
# Implies:
# blur-background
# Bad in performance, with driver-dependent behavior. The name may change.
#
# blur-background-frame = false
# blur-background-frame = false;
# Use fixed blur strength rather than adjusting according to window opacity.
# blur-background-fixed = false
# blur-background-fixed = false;
# Specify the blur convolution kernel, with the following format:
@ -188,17 +235,35 @@ focus-exclude = [ "class_g = 'Cairo-clock'" ];
# blur-kern = "5,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1";
#
# blur-kern = ''
blur-kern = "3x3box";
# blur-kern = "3x3box";
blur: {
# requires: https://github.com/ibhagwan/picom
method = "kawase";
#method = "kernel";
strength = 7;
# deviation = 1.0;
# kernel = "11x11gaussian";
background = false;
background-frame = false;
background-fixed = false;
kern = "3x3box";
}
# Exclude conditions for background blur.
# blur-background-exclude = []
blur-background-exclude = [
"window_type = 'dock'",
"window_type = 'desktop'",
#"window_type = 'dock'",
#"window_type = 'desktop'",
#"class_g = 'URxvt'",
#
# prevents picom from blurring the background
# when taking selection screenshot with `main`
# https://github.com/naelstrof/maim/issues/130
"class_g = 'slop'",
"_GTK_FRAME_EXTENTS@:c"
];
#################################
# General Settings #
#################################
@ -209,8 +274,10 @@ blur-background-exclude = [
# Specify the backend to use: `xrender`, `glx`, or `xr_glx_hybrid`.
# `xrender` is the default one.
#
# backend = 'glx'
backend = "xrender";
experimental-backends = true;
backend = "glx";
#backend = "xrender";
# Enable/disable VSync.
# vsync = false
@ -263,7 +330,7 @@ refresh-rate = 0
# Unredirect all windows if a full-screen opaque window is detected,
# to maximize performance for full-screen windows. Known to cause flickering
# when redirecting/unredirecting windows.
# when redirecting/unredirecting windows. paint-on-overlay may make the flickering less obvious.
#
# unredir-if-possible = false
@ -367,7 +434,7 @@ use-damage = true
# using *--log-file*, since it can generate a huge stream of logs.
#
# log-level = "debug"
log-level = "warn";
log-level = "info";
# Set the log file.
# If *--log-file* is never specified, logs will be written to stderr.
@ -415,6 +482,7 @@ log-level = "warn";
#
wintypes:
{
normal = { fade = false; shadow = false; }
tooltip = { fade = true; shadow = true; opacity = 0.75; focus = true; full-shadow = false; };
dock = { shadow = false; }
dnd = { shadow = false; }

View File

@ -55,7 +55,7 @@ region_t get_damage(session_t *ps, bool all_damage) {
/// paint all windows
void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
if (ps->o.xrender_sync_fence) {
if (ps->o.xrender_sync_fence || (ps->drivers & DRIVER_NVIDIA)) {
if (ps->xsync_exists && !x_fence_sync(ps->c, ps->sync_fence)) {
log_error("x_fence_sync failed, xrender-sync-fence will be "
"disabled from now on.");
@ -151,11 +151,8 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
}
if (ps->root_image) {
ps->backend_data->ops->compose(ps->backend_data, ps->root_image, 0, 0,
ps->backend_data->ops->compose(ps->backend_data, t, ps->root_image, 0, 0,
&reg_paint, &reg_visible);
} else {
ps->backend_data->ops->fill(ps->backend_data, (struct color){0, 0, 0, 1},
&reg_paint);
}
// Windows are sorted from bottom to top
@ -171,7 +168,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
// The bounding shape of the window, in global/target coordinates
// reminder: bounding shape contains the WM frame
auto reg_bound = win_get_bounding_shape_global_by_val(w);
auto reg_bound = win_get_bounding_shape_global_by_val(w, true);
// The clip region for the current window, in global/target coordinates
// reg_paint_in_bound \in reg_paint
@ -190,6 +187,17 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
&reg_paint_in_bound, &reg_visible);
}
// Store the window background for rounded corners
// If rounded corners backup the region first
if (w->corner_radius > 0) {
const int16_t x = w->g.x;
const int16_t y = w->g.y;
const auto wid = to_u16_checked(w->widthb);
const auto hei = to_u16_checked(w->heightb);
ps->backend_data->ops->store_back_texture(ps->backend_data, w,
ps->backend_round_context, &reg_bound, x, y, wid, hei);
}
// Blur window background
// TODO since the background might change the content of the window (e.g.
// with shaders), we should consult the background whether the window
@ -204,36 +212,20 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
// itself is not opaque, only the frame is.
double blur_opacity = 1;
if (w->opacity < (1.0 / MAX_ALPHA)) {
// Hide blur for fully transparent windows.
blur_opacity = 0;
} else if (w->state == WSTATE_MAPPING) {
if (w->state == WSTATE_MAPPING) {
// Gradually increase the blur intensity during
// fading in.
assert(w->opacity <= w->opacity_target);
blur_opacity = w->opacity / w->opacity_target;
} else if (w->state == WSTATE_UNMAPPING ||
w->state == WSTATE_DESTROYING) {
// Gradually decrease the blur intensity during
// fading out.
assert(w->opacity <= w->opacity_target_old);
blur_opacity = w->opacity / w->opacity_target_old;
} else if (w->state == WSTATE_FADING) {
if (w->opacity < w->opacity_target &&
w->opacity_target_old < (1.0 / MAX_ALPHA)) {
// Gradually increase the blur intensity during
// fading in.
assert(w->opacity <= w->opacity_target);
blur_opacity = w->opacity / w->opacity_target;
} else if (w->opacity > w->opacity_target &&
w->opacity_target < (1.0 / MAX_ALPHA)) {
// Gradually decrease the blur intensity during
// fading out.
assert(w->opacity <= w->opacity_target_old);
blur_opacity = w->opacity / w->opacity_target_old;
}
blur_opacity =
w->opacity / win_calc_opacity_target(ps, w, true);
} else if (!ps->o.blur_background_fixed) {
// Apply blur intensity depending on the window opacity.
blur_opacity = w->opacity;
}
assert(blur_opacity >= 0 && blur_opacity <= 1);
if (real_win_mode == WMODE_TRANS || ps->o.force_win_blend) {
// We need to blur the bounding shape of the window
@ -249,7 +241,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
assert(ps->o.blur_background_frame);
assert(real_win_mode == WMODE_FRAME_TRANS);
auto reg_blur = win_get_region_frame_local_by_val(w);
auto reg_blur = win_get_region_frame_local_by_val(w, true);
pixman_region32_translate(&reg_blur, w->g.x, w->g.y);
// make sure reg_blur \in reg_paint
pixman_region32_intersect(&reg_blur, &reg_blur, &reg_paint);
@ -305,7 +297,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
assert(w->shadow_image);
if (w->opacity == 1) {
ps->backend_data->ops->compose(
ps->backend_data, w->shadow_image, w->g.x + w->shadow_dx,
ps->backend_data, w, w->shadow_image, w->g.x + w->shadow_dx,
w->g.y + w->shadow_dy, &reg_shadow, &reg_visible);
} else {
auto new_img = ps->backend_data->ops->copy(
@ -314,7 +306,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
ps->backend_data, IMAGE_OP_APPLY_ALPHA_ALL, new_img,
NULL, &reg_visible, (double[]){w->opacity});
ps->backend_data->ops->compose(
ps->backend_data, new_img, w->g.x + w->shadow_dx,
ps->backend_data, w, new_img, w->g.x + w->shadow_dx,
w->g.y + w->shadow_dy, &reg_shadow, &reg_visible);
ps->backend_data->ops->release_image(ps->backend_data, new_img);
}
@ -330,7 +322,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
// Draw window on target
if (!w->invert_color && !w->dim && w->frame_opacity == 1 && w->opacity == 1) {
ps->backend_data->ops->compose(ps->backend_data, w->win_image,
ps->backend_data->ops->compose(ps->backend_data, w, w->win_image,
w->g.x, w->g.y,
&reg_paint_in_bound, &reg_visible);
} else if (w->opacity * MAX_ALPHA >= 1) {
@ -379,7 +371,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
&reg_visible_local, (double[]){dim_opacity});
}
if (w->frame_opacity != 1) {
auto reg_frame = win_get_region_frame_local_by_val(w);
auto reg_frame = win_get_region_frame_local_by_val(w, true);
ps->backend_data->ops->image_op(
ps->backend_data, IMAGE_OP_APPLY_ALPHA, new_img, &reg_frame,
&reg_visible_local, (double[]){w->frame_opacity});
@ -390,13 +382,21 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
ps->backend_data, IMAGE_OP_APPLY_ALPHA_ALL, new_img,
NULL, &reg_visible_local, (double[]){w->opacity});
}
ps->backend_data->ops->compose(ps->backend_data, new_img, w->g.x,
ps->backend_data->ops->compose(ps->backend_data, w, new_img, w->g.x,
w->g.y, &reg_paint_in_bound,
&reg_visible);
ps->backend_data->ops->release_image(ps->backend_data, new_img);
pixman_region32_fini(&reg_visible_local);
pixman_region32_fini(&reg_bound_local);
}
// Round the corners as last step after blur/shadow/dim/etc
if (w->corner_radius > 0.0) {
ps->backend_data->ops->round(ps->backend_data, w,
ps->backend_round_context, w->win_image,
&reg_bound, &reg_visible);
}
pixman_region32_fini(&reg_bound);
pixman_region32_fini(&reg_paint_in_bound);
}

View File

@ -28,6 +28,9 @@ typedef struct backend_base {
/// Whether the backend can accept new render request at the moment
bool busy;
// ...
// Session data
session_t *ps;
} backend_t;
typedef void (*backend_ready_callback_t)(void *);
@ -56,6 +59,11 @@ struct gaussian_blur_args {
double deviation;
};
struct dual_kawase_blur_args {
int size;
blur_strength_t strength;
};
struct box_blur_args {
int size;
};
@ -65,6 +73,11 @@ struct kernel_blur_args {
int kernel_count;
};
struct round_corners_args {
int corner_radius;
bool round_borders;
};
struct backend_operations {
// =========== Initialization ===========
@ -126,7 +139,7 @@ struct backend_operations {
* @param reg_paint the clip region, in target coordinates
* @param reg_visible the visible region, in target coordinates
*/
void (*compose)(backend_t *backend_data, void *image_data, int dst_x, int dst_y,
void (*compose)(backend_t *backend_data, struct managed_win *const w, void *image_data, int dst_x, int dst_y,
const region_t *reg_paint, const region_t *reg_visible);
/// Fill rectangle of the rendering buffer, mostly for debug purposes, optional.
@ -137,6 +150,11 @@ struct backend_operations {
const region_t *reg_blur, const region_t *reg_visible)
attr_nonnull(1, 3, 4, 5);
/// Round a given region of the rendering buffer.
bool (*round)(backend_t *backend_data, struct managed_win *w, void *round_ctx,
void *image_data, const region_t *reg_round, const region_t *reg_visible)
attr_nonnull(1, 2, 3, 5, 6);
/// 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
/// target window directly).
@ -218,6 +236,15 @@ struct backend_operations {
/// Get how many pixels outside of the blur area is needed for blur
void (*get_blur_size)(void *blur_context, int *width, int *height);
/// Backup our current window background so we can use it for "erasing" corners
bool (*store_back_texture)(backend_t *base, struct managed_win *w, void *ctx_,
const region_t *reg_tgt, int x, int y, int width, int height);
/// Create a rounded corners context
void *(*create_round_context)(backend_t *base, void *args);
/// Destroy a rounded corners context
void (*destroy_round_context)(backend_t *base, void *ctx);
// =========== Hooks ============
/// Let the backend hook into the event handling queue
/// Not implemented yet

View File

@ -362,10 +362,106 @@ struct conv **generate_blur_kernel(enum blur_method method, void *args, int *ker
return NULL;
}
/// Generate kernel parameters for dual-kawase blur method. Falls back on approximating
/// standard gauss radius if strength is not supplied
struct dual_kawase_params *generate_dual_kawase_params(void *args) {
struct dual_kawase_blur_args *blur_args = args;
static const struct {
int iterations;
float offset;
} strength_levels[20] = {
{.iterations = 1, .offset = 1.25f}, // LVL 1 => radius 4
{.iterations = 1, .offset = 2.25f}, // LVL 2 => radius 7
{.iterations = 2, .offset = 2.00f}, // LVL 3 => radius 14
{.iterations = 2, .offset = 3.00f}, // LVL 4 => radius 20
{.iterations = 2, .offset = 4.25f}, // LVL 5 => radius 28
{.iterations = 3, .offset = 2.50f}, // LVL 6 => radius 35
{.iterations = 3, .offset = 3.25f}, // LVL 7 => radius 45
{.iterations = 3, .offset = 4.25f}, // LVL 8 => radius 57
{.iterations = 3, .offset = 5.50f}, // LVL 9 => radius 74
{.iterations = 4, .offset = 3.25f}, // LVL 10 => radius 91
{.iterations = 4, .offset = 4.00f}, // LVL 11 => radius 110
{.iterations = 4, .offset = 5.00f}, // LVL 12 => radius 135
{.iterations = 4, .offset = 6.00f}, // LVL 13 => radius 161
{.iterations = 4, .offset = 7.25f}, // LVL 14 => radius 195
{.iterations = 4, .offset = 8.25f}, // LVL 15 => radius 221
{.iterations = 5, .offset = 4.50f}, // LVL 16 => radius 250
{.iterations = 5, .offset = 5.25f}, // LVL 17 => radius 287
{.iterations = 5, .offset = 6.25f}, // LVL 18 => radius 330
{.iterations = 5, .offset = 7.25f}, // LVL 19 => radius 383
{.iterations = 5, .offset = 8.50f}, // LVL 20 => radius >450
};
auto params = ccalloc(1, struct dual_kawase_params);
params->iterations = 0;
params->offset = 1.0f;
if (blur_args->strength.strength <= 0 && blur_args->size) {
// approximate blur_strength with gaussian blur_radius
if (blur_args->size < 6) {
blur_args->strength.strength = 1;
} else if (blur_args->size < 11) {
blur_args->strength.strength = 2;
} else if (blur_args->size < 17) {
blur_args->strength.strength = 3;
} else if (blur_args->size < 24) {
blur_args->strength.strength = 4;
} else if (blur_args->size < 32) {
blur_args->strength.strength = 5;
} else if (blur_args->size < 40) {
blur_args->strength.strength = 6;
} else if (blur_args->size < 51) {
blur_args->strength.strength = 7;
} else if (blur_args->size < 67) {
blur_args->strength.strength = 8;
} else if (blur_args->size < 83) {
blur_args->strength.strength = 9;
} else if (blur_args->size < 101) {
blur_args->strength.strength = 10;
} else if (blur_args->size < 123) {
blur_args->strength.strength = 11;
} else if (blur_args->size < 148) {
blur_args->strength.strength = 12;
} else if (blur_args->size < 177) {
blur_args->strength.strength = 13;
} else if (blur_args->size < 208) {
blur_args->strength.strength = 14;
} else if (blur_args->size < 236) {
blur_args->strength.strength = 15;
} else if (blur_args->size < 269) {
blur_args->strength.strength = 16;
} else if (blur_args->size < 309) {
blur_args->strength.strength = 17;
} else if (blur_args->size < 357) {
blur_args->strength.strength = 18;
} else if (blur_args->size < 417) {
blur_args->strength.strength = 19;
} else {
blur_args->strength.strength = 20;
}
}
if (blur_args->strength.strength > 0) {
assert(blur_args->strength.strength <= 20);
params->iterations = strength_levels[blur_args->strength.strength - 1].iterations;
params->offset = strength_levels[blur_args->strength.strength - 1].offset;
}
params->expand = 2 * (int)exp2f((float)params->iterations) *
(256 - (int)(256.0f - params->offset)) +
1;
log_info("blur-strength: %d [.iter = %d, .offset = %f]",
blur_args->strength.strength, params->iterations, params->offset);
return params;
}
void init_backend_base(struct backend_base *base, session_t *ps) {
base->c = ps->c;
base->loop = ps->loop;
base->root = ps->root;
base->busy = false;
base->ops = NULL;
base->ps = ps;
}

View File

@ -16,6 +16,15 @@ typedef struct conv conv;
typedef struct backend_base backend_t;
struct backend_operations;
typedef struct dual_kawase_params {
/// Number of downsample passes
int iterations;
/// Pixel offset for down- and upsample
float offset;
/// Save area around blur target (@ref resize_width, @ref resize_height)
int expand;
} dual_kawase_params_t;
bool build_shadow(xcb_connection_t *, xcb_drawable_t, double opacity, int width,
int height, const conv *kernel, xcb_render_picture_t shadow_pixel,
xcb_pixmap_t *pixmap, xcb_render_picture_t *pict);
@ -41,3 +50,5 @@ default_backend_render_shadow(backend_t *backend_data, int width, int height,
void init_backend_base(struct backend_base *base, session_t *ps);
struct conv **generate_blur_kernel(enum blur_method method, void *args, int *kernel_count);
struct dual_kawase_params *generate_dual_kawase_params(void *args);

View File

@ -12,14 +12,6 @@
#include "compiler.h"
#include "log.h"
/// Apply driver specified global workarounds. It's safe to call this multiple times.
void apply_driver_workarounds(struct session *ps, enum driver driver) {
if (driver & DRIVER_NVIDIA) {
setenv("__GL_YIELD", "usleep", true);
ps->o.xrender_sync_fence = true;
}
}
enum driver detect_driver(xcb_connection_t *c, backend_t *backend_data, xcb_window_t window) {
enum driver ret = 0;
// First we try doing backend agnostic detection using RANDR

View File

@ -32,9 +32,6 @@ enum driver {
/// Note, this is a best-effort test, so no guarantee all drivers will be detected.
enum driver detect_driver(xcb_connection_t *, struct backend_base *, xcb_window_t);
/// Apply driver specified global workarounds. It's safe to call this multiple times.
void apply_driver_workarounds(struct session *ps, enum driver);
// Print driver names to stdout, for diagnostics
static inline void print_drivers(enum driver drivers) {
if (drivers & DRIVER_AMDGPU) {

View File

@ -56,7 +56,7 @@ static void dummy_check_image(struct backend_base *base, const struct dummy_imag
assert(*tmp->refcount > 0);
}
void dummy_compose(struct backend_base *base, void *image, int dst_x attr_unused,
void dummy_compose(struct backend_base *base, struct managed_win *w attr_unused, void *image, int dst_x attr_unused,
int dst_y attr_unused, const region_t *reg_paint attr_unused,
const region_t *reg_visible attr_unused) {
dummy_check_image(base, image);
@ -72,6 +72,12 @@ bool dummy_blur(struct backend_base *backend_data attr_unused, double opacity at
return true;
}
bool dummy_round(struct backend_base *backend_data attr_unused, struct managed_win *w attr_unused,
void *ctx_ attr_unused, void *image_data attr_unused, const region_t *reg_round attr_unused,
const region_t *reg_visible attr_unused) {
return true;
}
void *dummy_bind_pixmap(struct backend_base *base, xcb_pixmap_t pixmap,
struct xvisual_info fmt, bool owned attr_unused) {
auto dummy = (struct dummy_data *)base;
@ -138,6 +144,14 @@ void *dummy_create_blur_context(struct backend_base *base attr_unused,
void dummy_destroy_blur_context(struct backend_base *base attr_unused, void *ctx attr_unused) {
}
void *dummy_create_round_context(struct backend_base *base attr_unused, void *args attr_unused) {
static int dummy_context;
return &dummy_context;
}
void dummy_destroy_round_context(struct backend_base *base attr_unused, void *ctx attr_unused) {
}
void dummy_get_blur_size(void *ctx attr_unused, int *width, int *height) {
// These numbers are arbitrary, to make sure the reisze_region code path is
// covered.
@ -145,12 +159,18 @@ void dummy_get_blur_size(void *ctx attr_unused, int *width, int *height) {
*height = 5;
}
bool dummy_store_back_texture(backend_t *backend_data attr_unused, struct managed_win *w attr_unused, void *ctx_ attr_unused,
const region_t *reg_tgt attr_unused, int x attr_unused, int y attr_unused, int width attr_unused, int height attr_unused) {
return true;
}
struct backend_operations dummy_ops = {
.init = dummy_init,
.deinit = dummy_deinit,
.compose = dummy_compose,
.fill = dummy_fill,
.blur = dummy_blur,
.round = dummy_round,
.bind_pixmap = dummy_bind_pixmap,
.render_shadow = default_backend_render_shadow,
.release_image = dummy_release_image,
@ -162,6 +182,9 @@ struct backend_operations dummy_ops = {
.copy = dummy_image_copy,
.create_blur_context = dummy_create_blur_context,
.destroy_blur_context = dummy_destroy_blur_context,
.create_round_context = dummy_create_round_context,
.destroy_round_context = dummy_destroy_round_context,
.get_blur_size = dummy_get_blur_size,
.store_back_texture = dummy_store_back_texture
};

File diff suppressed because it is too large Load Diff

View File

@ -33,10 +33,25 @@ typedef struct {
typedef struct {
GLuint prog;
GLint unifm_opacity;
GLint unifm_texture_size;
GLint unifm_halfpixel;
GLint orig_loc;
GLint texorig_loc;
GLint projection_loc;
} gl_blur_shader_t;
typedef struct {
GLuint prog;
GLint projection_loc;
GLint unifm_radius;
GLint unifm_texcoord;
GLint unifm_texsize;
GLint unifm_borderw;
GLint unifm_resolution;
GLint unifm_tex_bg;
GLint unifm_tex_wnd;
} gl_round_shader_t;
typedef struct {
GLuint prog;
GLint color_loc;
@ -68,7 +83,7 @@ struct gl_data {
backend_t base;
// If we are using proprietary NVIDIA driver
bool is_nvidia;
// Height and width of the root window
// Height and width of the viewport
int height, width;
gl_win_shader_t win_shader;
gl_brightness_shader_t brightness_shader;
@ -98,7 +113,7 @@ GLuint gl_create_program_from_str(const char *vert_shader_str, const char *frag_
/**
* @brief Render a region with texture data.
*/
void gl_compose(backend_t *, void *ptex, int dst_x, int dst_y, const region_t *reg_tgt,
void gl_compose(backend_t *, struct managed_win *, void *ptex, int dst_x, int dst_y, const region_t *reg_tgt,
const region_t *reg_visible);
void gl_resize(struct gl_data *, int width, int height);
@ -121,6 +136,14 @@ void *gl_create_blur_context(backend_t *base, enum blur_method, void *args);
void gl_destroy_blur_context(backend_t *base, void *ctx);
void gl_get_blur_size(void *blur_context, int *width, int *height);
bool gl_round(backend_t *backend_data, struct managed_win *w, void *ctx_,
void *image_data, const region_t *reg_round, const region_t *reg_visible);
void *gl_create_round_context(backend_t *base, void *args);
void gl_destroy_round_context(backend_t *base, void *ctx);
bool gl_store_back_texture(backend_t *backend_data, struct managed_win *w,
void *ctx_, const region_t *reg_tgt, int x, int y, int width, int height);
bool gl_is_image_transparent(backend_t *base, void *image_data);
void gl_fill(backend_t *base, struct color, const region_t *clip);

View File

@ -45,6 +45,8 @@ struct _glx_data {
Display *display;
int screen;
xcb_window_t target_win;
int glx_event;
int glx_error;
GLXContext ctx;
};
@ -244,7 +246,7 @@ static backend_t *glx_init(session_t *ps) {
XVisualInfo *pvis = NULL;
// Check for GLX extension
if (!ps->glx_exists) {
if (!glXQueryExtension(ps->dpy, &gd->glx_event, &gd->glx_error)) {
log_error("No GLX extension.");
goto end;
}
@ -466,7 +468,10 @@ static void glx_present(backend_t *base, const region_t *region attr_unused) {
struct _glx_data *gd = (void *)base;
gl_present(base, region);
glXSwapBuffers(gd->display, gd->target_win);
glFinish();
// XXX there should be no need to block, the core should wait for render to finish
if (!gd->gl.is_nvidia) {
glFinish();
}
}
static int glx_buffer_age(backend_t *base) {
@ -489,6 +494,7 @@ struct backend_operations glx_ops = {
.image_op = gl_image_op,
.copy = gl_copy,
.blur = gl_blur,
.round = gl_round,
.is_image_transparent = gl_is_image_transparent,
.present = glx_present,
.buffer_age = glx_buffer_age,
@ -496,7 +502,10 @@ struct backend_operations glx_ops = {
.fill = gl_fill,
.create_blur_context = gl_create_blur_context,
.destroy_blur_context = gl_destroy_blur_context,
.create_round_context = gl_create_round_context,
.destroy_round_context = gl_destroy_round_context,
.get_blur_size = gl_get_blur_size,
.store_back_texture = gl_store_back_texture,
.max_buffer_age = 5, // Why?
};

View File

@ -90,7 +90,9 @@ struct _xrender_image_data {
bool owned;
};
static void compose(backend_t *base, void *img_data, int dst_x, int dst_y,
uint32_t make_rounded_window_shape(xcb_render_trapezoid_t traps[], uint32_t max_ntraps, int cr, int wid, int hei);
static void compose(backend_t *base, struct managed_win *w, void *img_data, int dst_x, int dst_y,
const region_t *reg_paint, const region_t *reg_visible) {
struct _xrender_data *xd = (void *)base;
struct _xrender_image_data *img = img_data;
@ -104,10 +106,52 @@ static void compose(backend_t *base, void *img_data, int dst_x, int dst_y,
// sure we get everything into the buffer
x_clear_picture_clip_region(base->c, img->pict);
x_set_picture_clip_region(base->c, xd->back[2], 0, 0, &reg);
xcb_render_composite(base->c, op, img->pict, alpha_pict, xd->back[2], 0, 0, 0, 0,
to_i16_checked(dst_x), to_i16_checked(dst_y),
to_u16_checked(img->ewidth), to_u16_checked(img->eheight));
// Are we rounding corners?
session_t *ps = base->ps;
int cr = (w ? w->corner_radius : 0);
if (cr == 0) {
x_set_picture_clip_region(base->c, xd->back[2], 0, 0, &reg);
xcb_render_composite(base->c, op, img->pict, alpha_pict, xd->back[2], 0, 0, 0, 0,
to_i16_checked(dst_x), to_i16_checked(dst_y),
to_u16_checked(img->ewidth), to_u16_checked(img->eheight));
} else {
// Rounded corners
const int fullwid = w ? w->widthb : 0;
const int fullhei = w ? w-> heightb : 0;
//const int fullwid = img->width;
//const int fullhei = img->height;
//log_warn("f(%d, %d) imge(%d %d) imgf(%d %d) sdw(%d %d) dst(%d %d) s:%d b:%d", fullwid, fullhei, img->ewidth, img->eheight, img->width, img->height, w->shadow_width, w->shadow_height, dst_x, dst_y, w->shadow, w->g.border_width);
xcb_render_picture_t p_tmp = x_create_picture_with_standard(
ps->c, ps->root, fullwid, fullhei, XCB_PICT_STANDARD_ARGB_32, 0, 0);
xcb_render_color_t trans = {
.red = 0, .blue = 0, .green = 0, .alpha = 0};
const xcb_rectangle_t rect = {.x = 0,
.y = 0,
.width = to_u16_checked(fullwid),
.height = to_u16_checked(fullhei)};
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC,
p_tmp, trans, 1, &rect);
uint32_t max_ntraps = to_u32_checked(cr);
xcb_render_trapezoid_t traps[4 * max_ntraps + 5];
uint32_t n = make_rounded_window_shape(traps, max_ntraps, cr, fullwid, fullhei);
xcb_render_trapezoids(
ps->c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp,
x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8),
0, 0, n, traps);
x_set_picture_clip_region(base->c, xd->back[2], 0, 0, &reg);
xcb_render_composite(base->c, XCB_RENDER_PICT_OP_OVER, img->pict, p_tmp, xd->back[2],
0, 0, 0, 0,
//0, 0, to_i16_checked(x), to_i16_checked(y),
to_i16_checked(dst_x), to_i16_checked(dst_y),
to_u16_checked(img->ewidth), to_u16_checked(img->eheight));
xcb_render_free_picture(ps->c, p_tmp);
}
pixman_region32_fini(&reg);
}
@ -245,6 +289,15 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_,
return true;
}
static bool x_round(struct backend_base *backend_data attr_unused, struct managed_win *w attr_unused,
void *ctx_ attr_unused, void *image_data attr_unused, const region_t *reg_blur attr_unused,
const region_t *reg_visible attr_unused) {
// dummy implementation, we already perform the rounding in compose
// TODO: should move the compose code here and call it from here
return true;
}
static void *
bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool owned) {
xcb_generic_error_t *e;
@ -506,6 +559,13 @@ void *create_blur_context(backend_t *base attr_unused, enum blur_method method,
return ret;
}
if (method == BLUR_METHOD_DUAL_KAWASE || method == BLUR_METHOD_ALT_KAWASE) {
log_warn("Blur method 'kawase' is not compatible with the 'xrender' "
"backend.");
ret->method = BLUR_METHOD_NONE;
return ret;
}
ret->method = BLUR_METHOD_KERNEL;
struct conv **kernels;
int kernel_count;
@ -551,6 +611,19 @@ void get_blur_size(void *blur_context, int *width, int *height) {
*height = ctx->resize_height;
}
bool store_back_texture(backend_t *backend_data attr_unused, struct managed_win *w attr_unused, void *ctx_ attr_unused,
const region_t *reg_tgt attr_unused, int x attr_unused, int y attr_unused, int width attr_unused, int height attr_unused) {
return true;
}
void *create_round_context(struct backend_base *base attr_unused, void *args attr_unused) {
static int dummy_context;
return &dummy_context;
}
void destroy_round_context(struct backend_base *base attr_unused, void *ctx attr_unused) {
}
backend_t *backend_xrender_init(session_t *ps) {
auto xd = ccalloc(1, struct _xrender_data);
init_backend_base(&xd->base, ps);
@ -638,6 +711,7 @@ struct backend_operations xrender_ops = {
.init = backend_xrender_init,
.deinit = deinit,
.blur = blur,
.round = x_round,
.present = present,
.compose = compose,
.fill = fill,
@ -654,7 +728,11 @@ struct backend_operations xrender_ops = {
.copy = copy,
.create_blur_context = create_blur_context,
.destroy_blur_context = destroy_blur_context,
.create_round_context = create_round_context,
.destroy_round_context = destroy_round_context,
.get_blur_size = get_blur_size,
.store_back_texture = store_back_texture
};
// vim: set noet sw=8 ts=8:

View File

@ -75,6 +75,9 @@
/// @brief Maximum OpenGL buffer age.
#define CGLX_MAX_BUFFER_AGE 5
/// @brief Maximum passes for blur.
#define MAX_BLUR_PASS 6
// Window flags
// === Types ===
@ -157,6 +160,8 @@ typedef struct session {
backend_t *backend_data;
/// backend blur context
void *backend_blur_context;
/// round corners context
void *backend_round_context;
/// graphic drivers used
enum driver drivers;
/// file watch handle
@ -214,7 +219,6 @@ typedef struct session {
/// Custom GLX program used for painting window.
// XXX should be in struct glx_session
glx_prog_main_t glx_prog_win;
struct glx_fbconfig_info *argb_fbconfig;
#endif
/// Sync fence to sync draw operations
xcb_sync_fence_t sync_fence;
@ -340,12 +344,14 @@ typedef struct session {
int randr_error;
/// Whether X Present extension exists.
bool present_exists;
#ifdef CONFIG_OPENGL
/// Whether X GLX extension exists.
bool glx_exists;
/// Event base number for X GLX extension.
int glx_event;
/// Error base number for X GLX extension.
int glx_error;
#endif
/// Whether X Xinerama extension exists.
bool xinerama_exists;
/// Xinerama screen regions.
@ -528,7 +534,8 @@ static inline void wintype_arr_enable(bool arr[]) {
}
}
/**
* Get current system clock in 40 microseconds.
* Get current system clock in milliseconds.
*/
int64_t get_time_ms(void);

View File

@ -88,6 +88,11 @@ enum blur_method parse_blur_method(const char *src) {
return BLUR_METHOD_BOX;
} else if (strcmp(src, "gaussian") == 0) {
return BLUR_METHOD_GAUSSIAN;
} else if (strcmp(src, "kawase") == 0 || strcmp(src, "dual_kawase") == 0) {
return BLUR_METHOD_DUAL_KAWASE;
} else if (strcmp(src, "kawase_alt") == 0 || strcmp(src, "alt_kawase") == 0) {
// new code from tryone144's `improved_dbo` branch
return BLUR_METHOD_ALT_KAWASE;
} else if (strcmp(src, "none") == 0) {
return BLUR_METHOD_NONE;
}
@ -489,6 +494,12 @@ void set_default_winopts(options_t *opt, win_option_mask_t *mask, bool shadow_en
// opacity logic is complicated, and needs an "unset" state
opt->wintype_option[i].opacity = NAN;
}
if (!mask[i].corner_radius) {
opt->wintype_option[i].corner_radius = -1;
}
if (!mask[i].round_borders) {
opt->wintype_option[i].round_borders = -1;
}
}
}
@ -497,15 +508,6 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
*opt = (struct options){
.backend = BKEND_XRENDER,
.glx_no_stencil = false,
.transition_length = 300,
.transition_pow_x = 0.1,
.transition_pow_y = 0.1,
.transition_pow_w = 0.1,
.transition_pow_h = 0.1,
.size_transition = true,
.no_scale_down = false,
.spawn_center_screen = false,
.spawn_center = true,
.mark_wmwin_focused = false,
.mark_ovredir_focused = false,
.detect_rounded_corners = false,
@ -519,6 +521,15 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
.benchmark = 0,
.benchmark_wid = XCB_NONE,
.logpath = NULL,
.transition_length = 300,
.transition_pow_x = 0.1,
.transition_pow_y = 0.1,
.transition_pow_w = 0.1,
.transition_pow_h = 0.1,
.size_transition = true,
.no_scale_down = false,
.spawn_center_screen = false,
.spawn_center = true,
.refresh_rate = 0,
.sw_opti = false,
@ -551,6 +562,7 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
.blur_method = BLUR_METHOD_NONE,
.blur_radius = 3,
.blur_deviation = 0.84089642,
.blur_strength = {.strength = -1, .iterations = 3, .offset = 2.75, .expand = 50},
.blur_background_frame = false,
.blur_background_fixed = false,
.blur_background_blacklist = NULL,
@ -569,7 +581,9 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
.no_ewmh_fullscreen = false,
.track_leader = false,
};
.rounded_corners_blacklist = NULL,
.round_borders_blacklist = NULL};
char *ret = NULL;
#ifdef CONFIG_LIBCONFIG

View File

@ -44,6 +44,8 @@ typedef struct win_option_mask {
bool full_shadow : 1;
bool redir_ignore : 1;
bool opacity : 1;
bool corner_radius : 1;
bool round_borders : 1;
} win_option_mask_t;
typedef struct win_option {
@ -53,6 +55,8 @@ typedef struct win_option {
bool full_shadow;
bool redir_ignore;
double opacity;
int corner_radius;
int round_borders;
} win_option_t;
enum blur_method {
@ -60,9 +64,18 @@ enum blur_method {
BLUR_METHOD_KERNEL,
BLUR_METHOD_BOX,
BLUR_METHOD_GAUSSIAN,
BLUR_METHOD_DUAL_KAWASE,
BLUR_METHOD_ALT_KAWASE,
BLUR_METHOD_INVALID,
};
typedef struct blur_strength {
int expand;
int strength;
int iterations;
float offset;
} blur_strength_t;
typedef struct _c2_lptr c2_lptr_t;
/// Structure representing all options.
@ -87,7 +100,7 @@ typedef struct options {
bool glx_no_stencil;
/// Whether to avoid rebinding pixmap on window damage.
bool glx_no_rebind_pixmap;
/// Length of window transitions
/// Length of window transitions
int transition_length;
/// For smoothing on the x-coordinate of window animations
float transition_pow_x;
@ -207,6 +220,8 @@ typedef struct options {
int blur_radius;
// Standard deviation for the gaussian blur
double blur_deviation;
/// Blur strength (for kawase blur)
blur_strength_t blur_strength;
/// Whether to blur background when the window frame is not opaque.
/// Implies blur_background.
bool blur_background_frame;
@ -255,6 +270,15 @@ typedef struct options {
// Make transparent windows clip other windows, instead of blending on top of
// them
bool transparent_clipping;
// === Rounded corners related ===
int corner_radius;
/// Rounded corners blacklist. A linked list of conditions.
c2_lptr_t *rounded_corners_blacklist;
/// Do we round the borders of rounded windows?
int round_borders;
/// Rounded borders blacklist. A linked list of conditions.
c2_lptr_t *round_borders_blacklist;
} options_t;
extern const char *const BACKEND_STRS[NUM_BKEND + 1];
@ -331,3 +355,42 @@ static inline bool parse_vsync(const char *str) {
}
// vim: set noet sw=8 ts=8 :
/**
* Parse a blur_strength option argument.
*/
static inline attr_pure blur_strength_t
parse_kawase_blur_strength(const int level) {
static const blur_strength_t values[20] = {
{ .expand = 10, .strength =1, .iterations = 1, .offset = 1.5 }, // 1
{ .expand = 10, .strength =2, .iterations = 1, .offset = 2.0 }, // 2
{ .expand = 20, .strength =3, .iterations = 2, .offset = 2.5 }, // 3
{ .expand = 20, .strength =4, .iterations = 2, .offset = 3.0 }, // 4
{ .expand = 50, .strength =5, .iterations = 3, .offset = 2.75 }, // 5
{ .expand = 50, .strength =6, .iterations = 3, .offset = 3.5 }, // 6
{ .expand = 50, .strength =7, .iterations = 3, .offset = 4.25 }, // 7
{ .expand = 50, .strength =8, .iterations = 3, .offset = 5.0 }, // 8
{ .expand = 150, .strength =9, .iterations = 4, .offset = 3.71429f }, // 9
{ .expand = 150, .strength =10, .iterations = 4, .offset = 4.42857f }, // 10
{ .expand = 150, .strength =11, .iterations = 4, .offset = 5.14286f }, // 11
{ .expand = 150, .strength =12, .iterations = 4, .offset = 5.85714f }, // 12
{ .expand = 150, .strength =13, .iterations = 4, .offset = 6.57143f }, // 13
{ .expand = 150, .strength =14, .iterations = 4, .offset = 7.28571f }, // 14
{ .expand = 150, .strength =15, .iterations = 4, .offset = 8.0 }, // 15
{ .expand = 400, .strength =16, .iterations = 5, .offset = 6.0 }, // 16
{ .expand = 400, .strength =17, .iterations = 5, .offset = 7.0 }, // 17
{ .expand = 400, .strength =18, .iterations = 5, .offset = 8.0 }, // 18
{ .expand = 400, .strength =19, .iterations = 5, .offset = 9.0 }, // 19
{ .expand = 400, .strength =20, .iterations = 5, .offset = 10.0 }, // 20
};
if (level < 1 || level > 20) {
log_error("(\"%d\"): Invalid blur_strength argument. Needs to be a number between 1 and 20. Will default to 5", level);
return values[5];
}
log_info("blur-strength: %d [.iter = %d, .offset = %f, .expand = %d]",
level, values[level - 1].iterations, values[level - 1].offset, values[level - 1].expand);
return values[level - 1];;
}

View File

@ -284,6 +284,17 @@ static inline void parse_wintype_config(const config_t *cfg, const char *member_
o->opacity = normalize_d(fval);
mask->opacity = true;
}
if (config_setting_lookup_int(setting, "corner-radius", &ival)) {
o->corner_radius = ival;
mask->corner_radius = true;
// log_warn("%s: corner-radius: %d", member_name, ival);
}
if (config_setting_lookup_int(setting, "round-borders", &ival)) {
o->round_borders = ival;
mask->round_borders = true;
// log_warn("%s: round_borders: %d", member_name, ival);
}
}
}
@ -353,29 +364,31 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
// -O (fade_out_step)
if (config_lookup_float(&cfg, "fade-out-step", &dval))
opt->fade_out_step = normalize_d(dval);
// --transition-length
if (config_lookup_int(&cfg, "transition-length", &ival))
opt->transition_length = ival;
// --transition-pow-x
if (config_lookup_float(&cfg, "transition-pow-x", &dval))
opt->transition_pow_x = dval;
// --transition-pow-y
if (config_lookup_float(&cfg, "transition-pow-y", &dval))
opt->transition_pow_y = dval;
// --transition-pow-w
if (config_lookup_float(&cfg, "transition-pow-w", &dval))
opt->transition_pow_w = dval;
// --transition-pow-h
if (config_lookup_float(&cfg, "transition-pow-h", &dval))
opt->transition_pow_h = dval;
// --size-transition
lcfg_lookup_bool(&cfg, "size-transition", &opt->size_transition);
// --spawn-center-screen
lcfg_lookup_bool(&cfg, "spawn-center-screen", &opt->spawn_center_screen);
// --spawn-center
lcfg_lookup_bool(&cfg, "spawn-center", &opt->spawn_center);
// --no-scale-down
lcfg_lookup_bool(&cfg, "no-scale-down", &opt->no_scale_down);
// --transition-length
if (config_lookup_int(&cfg, "transition-length", &ival))
opt->transition_length = ival;
// --transition-pow-x
if (config_lookup_float(&cfg, "transition-pow-x", &dval))
opt->transition_pow_x = dval;
// --transition-pow-y
if (config_lookup_float(&cfg, "transition-pow-y", &dval))
opt->transition_pow_y = dval;
// --transition-pow-w
if (config_lookup_float(&cfg, "transition-pow-w", &dval))
opt->transition_pow_w = dval;
// --transition-pow-h
if (config_lookup_float(&cfg, "transition-pow-h", &dval))
opt->transition_pow_h = dval;
// --size-transition
lcfg_lookup_bool(&cfg, "size-transition", &opt->size_transition);
// --spawn-center-screen
lcfg_lookup_bool(&cfg, "spawn-center-screen", &opt->spawn_center_screen);
// --spawn-center
lcfg_lookup_bool(&cfg, "spawn-center", &opt->spawn_center);
// --no-scale-down
lcfg_lookup_bool(&cfg, "no-scale-down", &opt->no_scale_down);
// -r (shadow_radius)
config_lookup_int(&cfg, "shadow-radius", &opt->shadow_radius);
// -o (shadow_opacity)
@ -390,6 +403,14 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
// --active_opacity
if (config_lookup_float(&cfg, "active-opacity", &dval))
opt->active_opacity = normalize_d(dval);
// --corner-radius
config_lookup_int(&cfg, "corner-radius", &opt->corner_radius);
// --rounded-corners-exclude
parse_cfg_condlst(&cfg, &opt->rounded_corners_blacklist, "rounded-corners-exclude");
// --round-borders
config_lookup_int(&cfg, "round-borders", &opt->round_borders);
// --round-borders-exclude
parse_cfg_condlst(&cfg, &opt->round_borders_blacklist, "round-borders-exclude");
// -e (frame_opacity)
config_lookup_float(&cfg, "frame-opacity", &opt->frame_opacity);
// -c (shadow_enable)
@ -469,6 +490,7 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
}
lcfg_lookup_bool(&cfg, "vsync", &opt->vsync);
// --backend
lcfg_lookup_bool(&cfg, "experimental-backends", &opt->experimental_backends);
if (config_lookup_string(&cfg, "backend", &sval)) {
opt->backend = parse_backend(sval);
if (opt->backend >= NUM_BKEND) {
@ -545,6 +567,10 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
config_lookup_int(&cfg, "blur-size", &opt->blur_radius);
// --blur-deviation
config_lookup_float(&cfg, "blur-deviation", &opt->blur_deviation);
// --blur-strength
if (config_lookup_int(&cfg, "blur-strength", &ival) && ival) {
opt->blur_strength = parse_kawase_blur_strength(ival);
}
// --blur-background
if (config_lookup_bool(&cfg, "blur-background", &ival) && ival) {
if (opt->blur_method == BLUR_METHOD_NONE) {
@ -570,7 +596,6 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
lcfg_lookup_bool(&cfg, "glx-no-stencil", &opt->glx_no_stencil);
// --glx-no-rebind-pixmap
lcfg_lookup_bool(&cfg, "glx-no-rebind-pixmap", &opt->glx_no_rebind_pixmap);
lcfg_lookup_bool(&cfg, "force-win-blend", &opt->force_win_blend);
// --glx-swap-method
if (config_lookup_string(&cfg, "glx-swap-method", &sval)) {
char *endptr;
@ -608,8 +633,8 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
}
// --xrender-sync
if (config_lookup_bool(&cfg, "xrender-sync", &ival) && ival) {
log_error("Please use xrender-sync-fence instead of xrender-sync.");
goto err;
log_warn("Please use xrender-sync-fence instead of xrender-sync.");
opt->xrender_sync_fence = true;
}
// --xrender-sync-fence
lcfg_lookup_bool(&cfg, "xrender-sync-fence", &opt->xrender_sync_fence);
@ -617,21 +642,25 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
if (lcfg_lookup_bool(&cfg, "clear-shadow", &bval))
log_warn("\"clear-shadow\" is removed as an option, and is always"
" enabled now. Consider removing it from your config file");
if (lcfg_lookup_bool(&cfg, "paint-on-overlay", &bval)) {
log_error("\"paint-on-overlay\" has been removed as an option, and "
"the feature is enabled whenever possible");
goto err;
}
if (lcfg_lookup_bool(&cfg, "paint-on-overlay", &bval))
log_warn("\"paint-on-overlay\" has been removed as an option, and "
"is enabled whenever possible");
if (config_lookup_float(&cfg, "alpha-step", &dval)) {
log_error("\"alpha-step\" has been removed, compton now tries to make use"
" of all alpha values");
goto err;
}
if (config_lookup_float(&cfg, "alpha-step", &dval))
log_warn("\"alpha-step\" has been removed, compton now tries to make use"
" of all alpha values");
const char *deprecation_message attr_unused =
const char *deprecation_message =
"has been removed. If you encounter problems "
"without this feature, please feel free to open a bug report";
if (lcfg_lookup_bool(&cfg, "glx-use-copysubbuffermesa", &bval) && bval) {
log_error("\"glx-use-copysubbuffermesa\" %s", deprecation_message);
return ERR_PTR(-1);
}
if (lcfg_lookup_bool(&cfg, "glx-copy-from-front", &bval) && bval) {
log_error("\"glx-copy-from-front\" %s", deprecation_message);
return ERR_PTR(-1);
}
config_setting_t *blur_cfg = config_lookup(&cfg, "blur");
if (blur_cfg) {
@ -655,6 +684,10 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
}
config_setting_lookup_float(blur_cfg, "deviation", &opt->blur_deviation);
if (config_setting_lookup_int(blur_cfg, "strength", &ival) && ival) {
opt->blur_strength = parse_kawase_blur_strength(ival);
}
}
// Wintype settings

View File

@ -100,9 +100,6 @@ static inline xcb_window_t attr_pure ev_window(session_t *ps, xcb_generic_event_
}
}
#define CASESTRRET(s) \
case s: return #s;
static inline const char *ev_name(session_t *ps, xcb_generic_event_t *ev) {
static char buf[128];
switch (ev->response_type & 0x7f) {
@ -165,8 +162,6 @@ static inline const char *attr_pure ev_focus_detail_name(xcb_focus_in_event_t *e
return "Unknown";
}
#undef CASESTRRET
static inline void ev_focus_in(session_t *ps, xcb_focus_in_event_t *ev) {
log_debug("{ mode: %s, detail: %s }\n", ev_focus_mode_name(ev),
ev_focus_detail_name(ev));
@ -180,9 +175,8 @@ static inline void ev_focus_out(session_t *ps, xcb_focus_out_event_t *ev) {
}
static inline void ev_create_notify(session_t *ps, xcb_create_notify_event_t *ev) {
if (ev->parent == ps->root) {
add_win_top(ps, ev->window);
}
assert(ev->parent == ps->root);
add_win_top(ps, ev->window);
}
/// Handle configure event of a regular window
@ -202,105 +196,122 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
auto mw = (struct managed_win *)w;
float t = get_time_ms();
if (mw->oldX == -500 && mw->oldY == -500 && mw->oldW == 0 && mw->oldH == 0) {
if (!mw->isOld) {
/* mw->isOld = true; */
float t = get_time_ms();
if (mw->oldX == -10000 && mw->oldY == -10000 && mw->oldW == 0 && mw->oldH == 0) {
if (!mw->isOld) {
/* mw->isOld = true; */
if (ps->o.spawn_center_screen) {
mw->oldX = ps->root_width/2;
mw->oldY = ps->root_height/2;
mw->oldW = 1;
mw->oldH = 1;
} else if (ps->o.spawn_center) {
mw->oldX = ce->x + ce->width/2;
mw->oldY = ce->y + ce->height/2;
mw->oldW = 1;
mw->oldH = 1;
} else {
mw->oldX = ce->x;
mw->oldY = ce->y;
mw->oldW = ce->width;
mw->oldH = ce->height;
}
} else {
mw->oldX = ce->x;
mw->oldY = ce->y;
mw->oldW = ce->width;
mw->oldH = ce->height;
}
if (ps->o.spawn_center_screen) {
mw->oldX = ps->root_width / 2;
mw->oldY = ps->root_height / 2;
mw->oldW = 1;
mw->oldH = 1;
} else if (ps->o.spawn_center) {
mw->oldX = ce->x + ce->width / 2;
mw->oldY = ce->y + ce->height / 2;
mw->oldW = 1;
mw->oldH = 1;
} else {
mw->oldX = ce->x;
mw->oldY = ce->y;
mw->oldW = ce->width;
mw->oldH = ce->height;
}
} else {
mw->oldX = ce->x;
mw->oldY = ce->y;
mw->oldW = ce->width;
mw->oldH = ce->height;
}
mw->newX = ce->x;
mw->newY = ce->y;
mw->newW = ce->width;
mw->newH = ce->height;
mw->moveTimeX = t;
mw->moveTimeY = t;
mw->moveTimeW = t;
mw->moveTimeH = t;
} else {
if (mw->newX == mw->g.x && mw->newY == mw->g.y) {
mw->oldX = mw->g.x;
mw->oldY = mw->g.y;
mw->oldW = mw->g.width;
mw->oldH = mw->g.height;
mw->moveTimeX = t;
mw->moveTimeY = t;
mw->moveTimeW = t;
mw->moveTimeH = t;
}
if (mw->newX != ce->x || mw->newY != ce->y || mw->newW != ce->width || mw->newH != ce->height) {
float moveDx = ((float) t - mw->moveTimeX) / ps->o.transition_length;
float moveDy = ((float) t - mw->moveTimeY) / ps->o.transition_length;
float moveDw = ((float) t - mw->moveTimeW) / ps->o.transition_length;
float moveDh = ((float) t - mw->moveTimeH) / ps->o.transition_length;
mw->newX = ce->x;
mw->newY = ce->y;
mw->newW = ce->width;
mw->newH = ce->height;
mw->moveTimeX = t;
mw->moveTimeY = t;
mw->moveTimeW = t;
mw->moveTimeH = t;
} else {
if (mw->newX == mw->g.x && mw->newY == mw->g.y) {
mw->oldX = mw->g.x;
mw->oldY = mw->g.y;
mw->oldW = mw->g.width;
mw->oldH = mw->g.height;
mw->moveTimeX = t;
mw->moveTimeY = t;
mw->moveTimeW = t;
mw->moveTimeH = t;
}
if (mw->newX != ce->x || mw->newY != ce->y || mw->newW != ce->width ||
mw->newH != ce->height) {
float moveDx = ((float)t - mw->moveTimeX) / ps->o.transition_length;
float moveDy = ((float)t - mw->moveTimeY) / ps->o.transition_length;
float moveDw = ((float)t - mw->moveTimeW) / ps->o.transition_length;
float moveDh = ((float)t - mw->moveTimeH) / ps->o.transition_length;
if (mw->moveTimeX != 0.0 && moveDx < 1.0 && mw->oldX != mw->newX) {
float oldMoveDx = pow((float) (mw->newX - mw->g.x) / (float) (mw->newX - ce->x), 1 / ps->o.transition_pow_x);
float fakeT = (t - oldMoveDx * (float) ps->o.transition_length);
/* printf("X: %f,%f\n", fakeT, t); */
mw->moveTimeX = isnanf(fakeT)? t : fakeT;
} else {
mw->moveTimeX = t;
}
if (mw->moveTimeY != 0.0 && moveDy < 1.0 && mw->oldY != mw->newY) {
float oldMoveDy = pow((float) (mw->newY - mw->g.y) / (float) (mw->newY - ce->y), 1 / ps->o.transition_pow_y);
float fakeT = (t - oldMoveDy * (float) ps->o.transition_length);
/* printf("Y: %f,%f\n", fakeT, t); */
mw->moveTimeY = isnanf(fakeT)? t : fakeT;
} else {
mw->moveTimeY = t;
}
if (mw->moveTimeW != 0.0 && moveDw < 1.0 && mw->oldW != mw->newW) {
float oldMoveDw = pow((float) (mw->newW - mw->g.width) / (float) (mw->newW - ce->width), 1 / ps->o.transition_pow_w);
float fakeT = (t - oldMoveDw * (float) ps->o.transition_length);
/* printf("Y: %f,%f\n", fakeT, t); */
mw->moveTimeW = isnanf(fakeT)? t : fakeT;
} else {
mw->moveTimeW = t;
}
if (mw->moveTimeH != 0.0 && moveDh < 1.0 && mw->oldH != mw->newH) {
float oldMoveDh = pow((float) (mw->newH - mw->g.height) / (float) (mw->newH - ce->height), 1 / ps->o.transition_pow_h);
float fakeT = (t - oldMoveDh * (float) ps->o.transition_length);
/* printf("Y: %f,%f\n", fakeT, t); */
mw->moveTimeH = isnanf(fakeT)? t : fakeT;
} else {
mw->moveTimeH = t;
}
if (mw->moveTimeX != 0.0 && moveDx < 1.0 && mw->oldX != mw->newX) {
float oldMoveDx = pow(
(float)(mw->newX - mw->g.x) / (float)(mw->newX - ce->x),
1 / ps->o.transition_pow_x);
float fakeT =
(t - oldMoveDx * (float)ps->o.transition_length);
/* printf("X: %f,%f\n", fakeT, t); */
mw->moveTimeX = isnanf(fakeT) ? t : fakeT;
} else {
mw->moveTimeX = t;
}
if (mw->moveTimeY != 0.0 && moveDy < 1.0 && mw->oldY != mw->newY) {
float oldMoveDy = pow(
(float)(mw->newY - mw->g.y) / (float)(mw->newY - ce->y),
1 / ps->o.transition_pow_y);
float fakeT =
(t - oldMoveDy * (float)ps->o.transition_length);
/* printf("Y: %f,%f\n", fakeT, t); */
mw->moveTimeY = isnanf(fakeT) ? t : fakeT;
} else {
mw->moveTimeY = t;
}
if (mw->moveTimeW != 0.0 && moveDw < 1.0 && mw->oldW != mw->newW) {
float oldMoveDw = pow((float)(mw->newW - mw->g.width) /
(float)(mw->newW - ce->width),
1 / ps->o.transition_pow_w);
float fakeT =
(t - oldMoveDw * (float)ps->o.transition_length);
/* printf("Y: %f,%f\n", fakeT, t); */
mw->moveTimeW = isnanf(fakeT) ? t : fakeT;
} else {
mw->moveTimeW = t;
}
if (mw->moveTimeH != 0.0 && moveDh < 1.0 && mw->oldH != mw->newH) {
float oldMoveDh = pow((float)(mw->newH - mw->g.height) /
(float)(mw->newH - ce->height),
1 / ps->o.transition_pow_h);
float fakeT =
(t - oldMoveDh * (float)ps->o.transition_length);
/* printf("Y: %f,%f\n", fakeT, t); */
mw->moveTimeH = isnanf(fakeT) ? t : fakeT;
} else {
mw->moveTimeH = t;
}
mw->oldX = mw->newX;
mw->oldY = mw->newY;
mw->oldW = mw->newW;
mw->oldH = mw->newH;
mw->newX = ce->x;
mw->newY = ce->y;
mw->newW = ce->width;
mw->newH = ce->height;
mw->oldX = mw->newX;
mw->oldY = mw->newY;
mw->oldW = mw->newW;
mw->oldH = mw->newH;
mw->newX = ce->x;
mw->newY = ce->y;
mw->newW = ce->width;
mw->newH = ce->height;
if (ps->o.no_scale_down && mw->newW < mw->oldW) { mw->oldW = mw->newW; }
if (ps->o.no_scale_down && mw->newH < mw->oldH) { mw->oldH = mw->newH; }
}
}
if (ps->o.no_scale_down && mw->newW < mw->oldW) {
mw->oldW = mw->newW;
}
if (ps->o.no_scale_down && mw->newH < mw->oldH) {
mw->oldH = mw->newH;
}
}
}
if (mw->state == WSTATE_UNMAPPED || mw->state == WSTATE_UNMAPPING ||
mw->state == WSTATE_DESTROYING) {
@ -353,7 +364,7 @@ static inline void ev_configure_notify(session_t *ps, xcb_configure_notify_event
log_debug("{ send_event: %d, id: %#010x, above: %#010x, override_redirect: %d }",
ev->event, ev->window, ev->above_sibling, ev->override_redirect);
if (ev->window == ps->root) {
set_root_flags(ps, ROOT_FLAGS_CONFIGURED);
configure_root(ps, ev->width, ev->height);
} else {
configure_win(ps, ev);
}
@ -361,23 +372,8 @@ static inline void ev_configure_notify(session_t *ps, xcb_configure_notify_event
static inline void ev_destroy_notify(session_t *ps, xcb_destroy_notify_event_t *ev) {
auto w = find_win(ps, ev->window);
auto mw = find_toplevel(ps, ev->window);
if (mw && mw->client_win == mw->base.id) {
// We only want _real_ frame window
assert(&mw->base == w);
mw = NULL;
}
assert(w == NULL || mw == NULL);
if (w != NULL) {
if (w) {
auto _ attr_unused = destroy_win_start(ps, w);
} else if (mw != NULL) {
win_unmark_client(ps, mw);
win_set_flags(mw, WIN_FLAGS_CLIENT_STALE);
ps->pending_updates = true;
} else {
log_debug("Received a destroy notify from an unknown window, %#010x",
ev->window);
}
}
@ -400,7 +396,7 @@ static inline void ev_map_notify(session_t *ps, xcb_map_notify_event_t *ev) {
return;
}
win_set_flags(w, WIN_FLAGS_MAPPED);
win_queue_update(w, WIN_UPDATE_MAP);
// FocusIn/Out may be ignored when the window is unmapped, so we must
// recheck focus here
@ -415,14 +411,8 @@ static inline void ev_unmap_notify(session_t *ps, xcb_unmap_notify_event_t *ev)
}
static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t *ev) {
log_debug("Window %#010x has new parent: %#010x, override_redirect: %d",
ev->window, ev->parent, ev->override_redirect);
auto w_top = find_toplevel(ps, ev->window);
if (w_top) {
win_unmark_client(ps, w_top);
win_set_flags(w_top, WIN_FLAGS_CLIENT_STALE);
ps->pending_updates = true;
}
log_debug("{ new_parent: %#010x, override_redirect: %d }", ev->parent,
ev->override_redirect);
if (ev->parent == ps->root) {
// X will generate reparent notifiy even if the parent didn't actually
@ -442,11 +432,7 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t
{
auto w = find_win(ps, ev->window);
if (w) {
auto ret = destroy_win_start(ps, w);
if (!ret && w->managed) {
auto mw = (struct managed_win *)w;
CHECK(win_skip_fading(ps, mw));
}
auto _ attr_unused = destroy_win_start(ps, w);
}
}
@ -455,35 +441,28 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t
ps->c, ev->window, XCB_CW_EVENT_MASK,
(const uint32_t[]){determine_evmask(ps, ev->window, WIN_EVMODE_UNKNOWN)});
if (!wid_has_prop(ps, ev->window, ps->atoms->aWM_STATE)) {
log_debug("Window %#010x doesn't have WM_STATE property, it is "
"probably not a client window. But we will listen for "
"property change in case it gains one.",
ev->window);
xcb_change_window_attributes(
ps->c, ev->window, XCB_CW_EVENT_MASK,
(const uint32_t[]){determine_evmask(ps, ev->window, WIN_EVMODE_UNKNOWN) |
XCB_EVENT_MASK_PROPERTY_CHANGE});
} else {
auto w_real_top = find_managed_window_or_parent(ps, ev->parent);
if (w_real_top && w_real_top->state != WSTATE_UNMAPPED &&
w_real_top->state != WSTATE_UNMAPPING) {
log_debug("Mark window %#010x (%s) as having a stale "
"client",
w_real_top->base.id, w_real_top->name);
win_set_flags(w_real_top, WIN_FLAGS_CLIENT_STALE);
ps->pending_updates = true;
} else {
if (!w_real_top)
log_debug("parent %#010x not found", ev->parent);
// Check if the window is an undetected client window
// Firstly, check if it's a known client window
if (!find_toplevel(ps, ev->window)) {
// If not, look for its frame window
auto w_top = find_toplevel2(ps, ev->parent);
// If found, and the client window has not been determined, or its
// frame may not have a correct client, continue
if (w_top &&
(!w_top->client_win || w_top->client_win == w_top->base.id)) {
// If it has WM_STATE, mark it the client window
if (wid_has_prop(ps, ev->window, ps->atoms->aWM_STATE)) {
w_top->wmwin = false;
win_unmark_client(ps, w_top);
win_mark_client(ps, w_top, ev->window);
}
// Otherwise, watch for WM_STATE on it
else {
// Window is not currently mapped, unmark its
// client to trigger a client recheck when it is
// mapped later.
win_unmark_client(ps, w_real_top);
log_debug("parent %#010x (%s) is in state %d",
w_real_top->base.id, w_real_top->name,
w_real_top->state);
xcb_change_window_attributes(
ps->c, ev->window, XCB_CW_EVENT_MASK,
(const uint32_t[]){
determine_evmask(ps, ev->window, WIN_EVMODE_UNKNOWN) |
XCB_EVENT_MASK_PROPERTY_CHANGE});
}
}
}
@ -576,12 +555,14 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
(const uint32_t[]){determine_evmask(
ps, ev->window, WIN_EVMODE_UNKNOWN)});
auto w_top = find_managed_window_or_parent(ps, ev->window);
// ev->window might have not been managed yet, in that case w_top
// would be NULL.
if (w_top) {
win_set_flags(w_top, WIN_FLAGS_CLIENT_STALE);
ps->pending_updates = true;
auto w_top = find_toplevel2(ps, ev->window);
// Initialize client_win as early as possible
if (w_top &&
(!w_top->client_win || w_top->client_win == w_top->base.id) &&
wid_has_prop(ps, ev->window, ps->atoms->aWM_STATE)) {
w_top->wmwin = false;
win_unmark_client(ps, w_top);
win_mark_client(ps, w_top, ev->window);
}
}
}
@ -606,7 +587,14 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
win_update_opacity_prop(ps, w);
// we cannot receive OPACITY change when window is destroyed
assert(w->state != WSTATE_DESTROYING);
win_update_opacity_target(ps, w);
w->opacity_target = win_calc_opacity_target(ps, w, false);
if (w->state == WSTATE_MAPPED) {
// See the winstate_t transition table
w->state = WSTATE_FADING;
}
if (!ps->redirected) {
CHECK(!win_skip_fading(ps, w));
}
}
}
@ -743,14 +731,14 @@ static inline void ev_shape_notify(session_t *ps, xcb_shape_notify_event_t *ev)
* if we attempt to rebuild border_size
*/
// Mark the old border_size as damaged
region_t tmp = win_get_bounding_shape_global_by_val(w);
region_t tmp = win_get_bounding_shape_global_by_val(w, true);
add_damage(ps, &tmp);
pixman_region32_fini(&tmp);
win_update_bounding_shape(ps, w);
// Mark the new border_size as damaged
tmp = win_get_bounding_shape_global_by_val(w);
tmp = win_get_bounding_shape_global_by_val(w, true);
add_damage(ps, &tmp);
pixman_region32_fini(&tmp);

View File

@ -16,7 +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'
'xcb-shape', 'xcb-xinerama', 'xcb-xfixes', 'xcb-present', 'xcb'
]
required_packages = [
@ -81,8 +81,8 @@ endif
host_system = host_machine.system()
if host_system == 'linux'
cflags += ['-DHAS_INOTIFY']
elif (host_system == 'freebsd' or host_system == 'netbsd' or
host_system == 'dragonfly' or host_system == 'openbsd')
elif host_system == 'freebsd' or host_system == 'netbsd' or
host_system == 'dragonfly' or host_system == 'openbsd'
cflags += ['-DHAS_KQUEUE']
endif

File diff suppressed because it is too large Load Diff

View File

@ -36,10 +36,40 @@ typedef struct {
GLint unifm_offset_x;
/// Location of uniform "offset_y" in blur GLSL program.
GLint unifm_offset_y;
/// Location of uniform "factor_center" in blur GLSL program.
GLint unifm_factor_center;
/// Location of uniform "opacity" in conv-blur and (dual filter) kawase-blur GLSL program.
GLint unifm_opacity;
/// Location of uniform "offset" in kawase-blur GLSL program.
GLint unifm_offset;
/// Location of uniform "halfpixel" in kawase-blur GLSL program.
GLint unifm_halfpixel;
/// Location of uniform "fulltex" in kawase-blur GLSL program.
GLint unifm_fulltex;
} glx_blur_pass_t;
typedef struct {
/// Fragment shader for rounded corners.
GLuint frag_shader;
/// GLSL program for rounded corners.
GLuint prog;
/// Location of uniform "radius" in rounded-corners GLSL program.
GLint unifm_radius;
/// Location of uniform "texcoord" in rounded-corners GLSL program.
GLint unifm_texcoord;
/// Location of uniform "texsize" in rounded-corners GLSL program.
GLint unifm_texsize;
/// Location of uniform "borderw" in rounded-corners GLSL program.
GLint unifm_borderw;
/// Location of uniform "borderc" in rounded-corners GLSL program.
GLint unifm_borderc;
/// Location of uniform "resolution" in rounded-corners GLSL program.
GLint unifm_resolution;
/// Location of uniform "texture_scr" in rounded-corners GLSL program.
GLint unifm_tex_scr;
/// Location of uniform "texture_wnd" in rounded-corners GLSL program.
GLint unifm_tex_wnd;
} glx_round_pass_t;
/// Structure containing GLX-dependent data for a session.
typedef struct glx_session {
// === OpenGL related ===
@ -49,7 +79,10 @@ typedef struct glx_session {
bool has_texture_non_power_of_two;
/// Current GLX Z value.
int z;
/// Cached blur textures for every pass
glx_blur_cache_t blur_cache;
glx_blur_pass_t *blur_passes;
glx_round_pass_t *round_passes;
} glx_session_t;
/// @brief Wrapper of a binded GLX texture.
@ -69,8 +102,8 @@ typedef struct _glx_texture {
bool glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, int z,
GLfloat factor, const region_t *reg_tgt);
bool glx_render(session_t *ps, const glx_texture_t *ptex, int x, int y, int dx, int dy,
int width, int height, int z, double opacity, bool argb, bool neg,
bool glx_render(session_t *ps, struct managed_win *w, const glx_texture_t *ptex, int x, int y, int dx, int dy,
int width, int height, int z, double opacity, bool argb, bool neg, int cr,
const region_t *reg_tgt, const glx_prog_main_t *pprogram);
bool glx_init(session_t *ps, bool need_render);
@ -81,6 +114,8 @@ void glx_on_root_change(session_t *ps);
bool glx_init_blur(session_t *ps);
bool glx_init_rounded_corners(session_t *ps);
#ifdef CONFIG_OPENGL
bool glx_load_prog_main(const char *vshader_str, const char *fshader_str,
glx_prog_main_t *pprogram);
@ -91,6 +126,11 @@ bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
void glx_release_pixmap(session_t *ps, glx_texture_t *ptex);
bool glx_bind_texture(session_t *ps, glx_texture_t **pptex,
int x, int y, int width, int height, bool repeat);
void glx_release_texture(session_t *ps, glx_texture_t **ptex);
void glx_paint_pre(session_t *ps, region_t *preg) attr_nonnull(1, 2);
/**
@ -103,7 +143,15 @@ static inline bool glx_tex_binded(const glx_texture_t *ptex, xcb_pixmap_t pixmap
void glx_set_clip(session_t *ps, const region_t *reg);
bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc);
double opacity, const region_t *reg_tgt, glx_blur_cache_t *pbc);
bool glx_round_corners_dst0(session_t *ps, struct managed_win *w, const glx_texture_t *ptex, int shader_idx,
int dx, int dy, int width, int height, float z, float cr,
const region_t *reg_tgt, glx_blur_cache_t *pbc);
bool glx_round_corners_dst1(session_t *ps, struct managed_win *w, const glx_texture_t *ptex, int shader_idx,
int dx, int dy, int width, int height, float z, float cr,
const region_t *reg_tgt, glx_blur_cache_t *pbc);
GLuint glx_create_shader(GLenum shader_type, const char *shader_str);
@ -157,17 +205,19 @@ static inline void free_glx_fbo(GLuint *pfbo) {
* Free data in glx_blur_cache_t on resize.
*/
static inline void free_glx_bc_resize(session_t *ps, glx_blur_cache_t *pbc) {
free_texture_r(ps, &pbc->textures[0]);
free_texture_r(ps, &pbc->textures[1]);
pbc->width = 0;
pbc->height = 0;
for (int i = 0; i < MAX_BLUR_PASS; i++) {
free_texture_r(ps, &pbc->textures[i]);
pbc->width[i] = 0;
pbc->height[i] = 0;
}
}
/**
* Free a glx_blur_cache_t
*/
static inline void free_glx_bc(session_t *ps, glx_blur_cache_t *pbc) {
free_glx_fbo(&pbc->fbo);
for (int i = 0; i < MAX_BLUR_PASS; i++)
free_glx_fbo(&pbc->fbos[i]);
free_glx_bc_resize(ps, pbc);
}
@ -196,7 +246,6 @@ static inline void free_texture(session_t *ps, glx_texture_t **pptex) {
*/
static inline void free_paint_glx(session_t *ps, paint_t *ppaint) {
free_texture(ps, &ppaint->ptex);
ppaint->fbcfg = NULL;
}
/**
@ -207,6 +256,8 @@ static inline void free_win_res_glx(session_t *ps, struct managed_win *w) {
free_paint_glx(ps, &w->shadow_paint);
#ifdef CONFIG_OPENGL
free_glx_bc(ps, &w->glx_blur_cache);
free_glx_bc(ps, &w->glx_round_cache);
free_texture(ps, &w->glx_texture_bg);
free(w->paint.fbcfg);
#endif
}

View File

@ -114,6 +114,18 @@ static void usage(const char *argv0, int ret) {
"--active-opacity opacity\n"
" Default opacity for active windows. (0.0 - 1.0)\n"
"\n"
"--corner-radius value\n"
" Round the corners of windows. (defaults to 0)\n"
"\n"
"--rounded-corners-exclude condition\n"
" Exclude conditions for rounded corners.\n"
"\n"
"--round-borders value\n"
" When rounding corners, round the borders of windows. (defaults to 1)\n"
"\n"
"--round-borders-exclude condition\n"
" Exclude conditions for rounding borders.\n"
"\n"
"--mark-wmwin-focused\n"
" Try to detect WM windows and mark them as active.\n"
"\n"
@ -202,8 +214,8 @@ static void usage(const char *argv0, int ret) {
"\n"
"--blur-method\n"
" The algorithm used for background bluring. Available choices are:\n"
" 'none' to disable, 'gaussian', 'box' or 'kernel' for custom\n"
" convolution blur with --blur-kern.\n"
" 'none' to disable, 'dual_kawase', 'gaussian', 'box' or 'kernel'\n"
" for custom convolution blur with --blur-kern.\n"
" Note: 'gaussian' and 'box' require --experimental-backends.\n"
"\n"
"--blur-size\n"
@ -211,6 +223,10 @@ static void usage(const char *argv0, int ret) {
"\n"
"--blur-deviation\n"
" The standard deviation for the 'gaussian' blur method.\n"
"\n"
"--blur-strength\n"
" Only valid for '--blur-method dual_kawase'!\n"
" The strength of the kawase blur as an integer between 1 and 20. Defaults to 5.\n"
"\n"
"--blur-background\n"
" Blur background of semi-transparent / ARGB windows. Bad in\n"
@ -227,6 +243,7 @@ static void usage(const char *argv0, int ret) {
" opacity.\n"
"\n"
"--blur-kern matrix\n"
" Only valid for '--blur-method convolution'!\n"
" Specify the blur convolution kernel, with the following format:\n"
" WIDTH,HEIGHT,ELE1,ELE2,ELE3,ELE4,ELE5...\n"
" The element in the center must not be included, it will be forever\n"
@ -398,8 +415,10 @@ static const struct option longopts[] = {
{"opengl", no_argument, NULL, 289},
{"backend", required_argument, NULL, 290},
{"glx-no-stencil", no_argument, NULL, 291},
{"glx-copy-from-front", no_argument, NULL, 292},
{"benchmark", required_argument, NULL, 293},
{"benchmark-wid", required_argument, NULL, 294},
{"glx-use-copysubbuffermesa", no_argument, NULL, 295},
{"blur-background-exclude", required_argument, NULL, 296},
{"active-opacity", required_argument, NULL, 297},
{"glx-no-rebind-pixmap", no_argument, NULL, 298},
@ -435,6 +454,11 @@ static const struct option longopts[] = {
{"blur-method", required_argument, NULL, 328},
{"blur-size", required_argument, NULL, 329},
{"blur-deviation", required_argument, NULL, 330},
{"blur-strength", required_argument, NULL, 331},
{"corner-radius", required_argument, NULL, 332},
{"rounded-corners-exclude", required_argument, NULL, 333},
{"round-borders", required_argument, NULL, 334},
{"round-borders-exclude", required_argument, NULL, 335},
{"experimental-backends", no_argument, NULL, 733},
{"monitor-repaint", no_argument, NULL, 800},
{"diagnostics", no_argument, NULL, 801},
@ -467,23 +491,21 @@ bool get_early_config(int argc, char *const *argv, char **config_file, bool *all
} else if (o == 'b') {
*fork = true;
} else if (o == 'd') {
log_error("-d is removed, please use the DISPLAY "
"environment variable");
goto err;
log_warn("-d will be ignored, please use the DISPLAY "
"environment variable");
} else if (o == 314) {
*all_xerrors = true;
} else if (o == 318) {
printf("%s\n", COMPTON_VERSION);
return true;
} else if (o == 'S') {
log_error("-S is no longer available");
goto err;
log_warn("-S will be ignored");
} else if (o == 320) {
log_error("--no-name-pixmap is no longer available");
goto err;
log_warn("--no-name-pixmap will be ignored");
} else if (o == '?' || o == ':') {
usage(argv[0], 1);
goto err;
*exit_code = 1;
return true;
}
}
@ -491,13 +513,11 @@ bool get_early_config(int argc, char *const *argv, char **config_file, bool *all
if (optind < argc) {
// log is not initialized here yet
fprintf(stderr, "picom doesn't accept positional arguments.\n");
goto err;
*exit_code = 1;
return true;
}
return false;
err:
*exit_code = 1;
return true;
}
/**
@ -516,10 +536,9 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
// Parse commandline arguments. Range checking will be done later.
const char *deprecation_message attr_unused =
"has been removed. If you encounter problems "
"without this feature, please feel free to "
"open a bug report.";
const char *deprecation_message = "has been removed. If you encounter problems "
"without this feature, please feel free to "
"open a bug report.";
optind = 1;
while (-1 != (o = getopt_long(argc, argv, shortopts, longopts, &longopt_idx))) {
switch (o) {
@ -645,14 +664,14 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
break;
case 271:
// --alpha-step
log_error("--alpha-step has been removed, we now tries to "
log_warn("--alpha-step has been removed, we now tries to "
"make use of all alpha values");
return false;
case 272: log_error("use of --dbe is deprecated"); return false;
break;
case 272: log_warn("use of --dbe is deprecated"); break;
case 273:
log_error("--paint-on-overlay has been removed, the feature is enabled "
"whenever possible");
return false;
log_warn("--paint-on-overlay has been removed, and is enabled "
"when possible");
break;
P_CASEBOOL(274, sw_opti);
case 275:
// --vsync-aggressive
@ -704,11 +723,19 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
exit(1);
break;
P_CASEBOOL(291, glx_no_stencil);
case 292:
log_error("--glx-copy-from-front %s", deprecation_message);
exit(1);
break;
P_CASEINT(293, benchmark);
case 294:
// --benchmark-wid
opt->benchmark_wid = (xcb_window_t)strtol(optarg, NULL, 0);
break;
case 295:
log_error("--glx-use-copysubbuffermesa %s", deprecation_message);
exit(1);
break;
case 296:
// --blur-background-exclude
condlst_add(&opt->blur_background_blacklist, optarg);
@ -787,8 +814,9 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
P_CASEBOOL(311, vsync_use_glfinish);
case 312:
// --xrender-sync
log_error("Please use --xrender-sync-fence instead of --xrender-sync");
return false;
log_warn("Please use --xrender-sync-fence instead of --xrender-sync");
opt->xrender_sync_fence = true;
break;
P_CASEBOOL(313, xrender_sync_fence);
P_CASEBOOL(315, no_fading_destroyed_argb);
P_CASEBOOL(316, force_win_blend);
@ -835,7 +863,15 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
// --blur-deviation
opt->blur_deviation = atof(optarg);
break;
case 331:
// --blur-strength
opt->blur_strength = parse_kawase_blur_strength(atoi(optarg));
break;
case 332: opt->corner_radius = atoi(optarg); break;
case 333: condlst_add(&opt->rounded_corners_blacklist, optarg); break;
case 334: opt->round_borders = atoi(optarg); break;
case 335: condlst_add(&opt->round_borders_blacklist, optarg); break;
P_CASEBOOL(733, experimental_backends);
P_CASEBOOL(800, monitor_repaint);
case 801: opt->print_diagnostics = true; break;
@ -915,6 +951,13 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
opt->track_leader = true;
}
// Blur method kawase is not compatible with the xrender backend
if (opt->backend != BKEND_GLX && (opt->blur_method == BLUR_METHOD_DUAL_KAWASE
|| opt->blur_method == BLUR_METHOD_ALT_KAWASE)) {
log_warn("Blur method 'kawase' is incompatible with the XRender backend. Fall back to default.\n");
opt->blur_method = BLUR_METHOD_KERNEL;
}
// Fill default blur kernel
if (opt->blur_method == BLUR_METHOD_KERNEL &&
(!opt->blur_kerns || !opt->blur_kerns[0])) {
@ -924,6 +967,15 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
CHECK(opt->blur_kernel_count);
}
// override blur_kernel_count for kawase
if (opt->blur_method == BLUR_METHOD_DUAL_KAWASE ||
opt->blur_method == BLUR_METHOD_ALT_KAWASE) {
opt->blur_kernel_count = MAX_BLUR_PASS;
opt->blur_kerns = ccalloc(opt->blur_kernel_count, struct conv *);
CHECK(opt->blur_kerns);
CHECK(opt->blur_kernel_count);
}
if (opt->resize_damage < 0) {
log_warn("Negative --resize-damage will not work correctly.");
}

View File

@ -19,7 +19,6 @@
#include <string.h>
#include <xcb/composite.h>
#include <xcb/damage.h>
#include <xcb/glx.h>
#include <xcb/present.h>
#include <xcb/randr.h>
#include <xcb/render.h>
@ -99,9 +98,7 @@ const char *const BACKEND_STRS[] = {[BKEND_XRENDER] = "xrender",
session_t *ps_g = NULL;
void set_root_flags(session_t *ps, uint64_t flags) {
log_debug("Setting root flags: %lu", flags);
ps->root_flags |= flags;
ps->pending_updates = true;
}
void quit(session_t *ps) {
@ -124,16 +121,15 @@ static inline void free_xinerama_info(session_t *ps) {
}
/**
* Get current system clock in 40micro second accuracy.
* Get current system clock in milliseconds.
*/
int64_t get_time_ms(void) {
struct timespec tp;
clock_gettime(CLOCK_MONOTONIC, &tp);
/* return (int64_t)tp.tv_sec * 1000 + (int64_t)tp.tv_nsec / 1000000; //ultra high refresh */
return (int64_t)tp.tv_sec * 100 + (int64_t)tp.tv_nsec / 250000; //ultra high refresh
// return (int64_t)tp.tv_sec * 1000 + (int64_t)tp.tv_nsec / 1000000;
return (int64_t)tp.tv_sec * 100 + (int64_t)tp.tv_nsec / 250000;
}
// XXX Move to x.c
void cxinerama_upd_scrs(session_t *ps) {
// XXX Consider deprecating Xinerama, switch to RandR when necessary
@ -182,7 +178,7 @@ static inline struct managed_win *find_win_all(session_t *ps, const xcb_window_t
if (!w)
w = find_toplevel(ps, wid);
if (!w)
w = find_managed_window_or_parent(ps, wid);
w = find_toplevel2(ps, wid);
return w;
}
@ -305,9 +301,9 @@ uint32_t determine_evmask(session_t *ps, xcb_window_t wid, win_evmode_t mode) {
struct managed_win *w = NULL;
// Check if it's a mapped frame window
if (mode == WIN_EVMODE_FRAME ||
if (WIN_EVMODE_FRAME == mode ||
((w = find_managed_win(ps, wid)) && w->a.map_state == XCB_MAP_STATE_VIEWABLE)) {
evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE;
if (!ps->o.use_ewmh_active_win) {
evmask |= XCB_EVENT_MASK_FOCUS_CHANGE;
}
@ -377,219 +373,31 @@ static void recheck_focus(session_t *ps) {
}
/**
* Rebuild cached <code>screen_reg</code>.
* Look for the client window of a particular window.
*/
static void rebuild_screen_reg(session_t *ps) {
get_screen_region(ps, &ps->screen_reg);
}
/**
* Rebuild <code>shadow_exclude_reg</code>.
*/
static void rebuild_shadow_exclude_reg(session_t *ps) {
bool ret = parse_geometry(ps, ps->o.shadow_exclude_reg_str, &ps->shadow_exclude_reg);
if (!ret)
exit(1);
}
/// Free up all the images and deinit the backend
static void destroy_backend(session_t *ps) {
win_stack_foreach_managed_safe(w, &ps->window_stack) {
// Wrapping up fading in progress
if (win_skip_fading(ps, w)) {
// `w` is freed by win_skip_fading
continue;
}
if (ps->backend_data) {
if (w->state == WSTATE_MAPPED) {
win_release_images(ps->backend_data, w);
} else {
assert(!w->win_image);
assert(!w->shadow_image);
}
}
free_paint(ps, &w->paint);
xcb_window_t find_client_win(session_t *ps, xcb_window_t w) {
if (wid_has_prop(ps, w, ps->atoms->aWM_STATE)) {
return w;
}
if (ps->backend_data && ps->root_image) {
ps->backend_data->ops->release_image(ps->backend_data, ps->root_image);
ps->root_image = NULL;
xcb_query_tree_reply_t *reply =
xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, w), NULL);
if (!reply)
return 0;
xcb_window_t *children = xcb_query_tree_children(reply);
int nchildren = xcb_query_tree_children_length(reply);
int i;
xcb_window_t ret = 0;
for (i = 0; i < nchildren; ++i) {
if ((ret = find_client_win(ps, children[i])))
break;
}
if (ps->backend_data) {
// deinit backend
if (ps->backend_blur_context) {
ps->backend_data->ops->destroy_blur_context(
ps->backend_data, ps->backend_blur_context);
ps->backend_blur_context = NULL;
}
ps->backend_data->ops->deinit(ps->backend_data);
ps->backend_data = NULL;
}
}
free(reply);
static bool initialize_blur(session_t *ps) {
struct kernel_blur_args kargs;
struct gaussian_blur_args gargs;
struct box_blur_args bargs;
void *args = NULL;
switch (ps->o.blur_method) {
case BLUR_METHOD_BOX:
bargs.size = ps->o.blur_radius;
args = (void *)&bargs;
break;
case BLUR_METHOD_KERNEL:
kargs.kernel_count = ps->o.blur_kernel_count;
kargs.kernels = ps->o.blur_kerns;
args = (void *)&kargs;
break;
case BLUR_METHOD_GAUSSIAN:
gargs.size = ps->o.blur_radius;
gargs.deviation = ps->o.blur_deviation;
args = (void *)&gargs;
break;
default: return true;
}
ps->backend_blur_context = ps->backend_data->ops->create_blur_context(
ps->backend_data, ps->o.blur_method, args);
return ps->backend_blur_context != NULL;
}
/// Init the backend and bind all the window pixmap to backend images
static bool initialize_backend(session_t *ps) {
if (ps->o.experimental_backends) {
assert(!ps->backend_data);
// Reinitialize win_data
assert(backend_list[ps->o.backend]);
ps->backend_data = backend_list[ps->o.backend]->init(ps);
if (!ps->backend_data) {
log_fatal("Failed to initialize backend, aborting...");
quit(ps);
return false;
}
ps->backend_data->ops = backend_list[ps->o.backend];
if (!initialize_blur(ps)) {
log_fatal("Failed to prepare for background blur, aborting...");
ps->backend_data->ops->deinit(ps->backend_data);
ps->backend_data = NULL;
quit(ps);
return false;
}
// window_stack shouldn't include window that's
// not in the hash table at this point. Since
// there cannot be any fading windows.
HASH_ITER2(ps->windows, _w) {
if (!_w->managed) {
continue;
}
auto w = (struct managed_win *)_w;
assert(w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED);
if (w->state == WSTATE_MAPPED) {
// We need to reacquire image
log_debug("Marking window %#010x (%s) for update after "
"redirection",
w->base.id, w->name);
if (w->shadow) {
struct color c = {
.red = ps->o.shadow_red,
.green = ps->o.shadow_green,
.blue = ps->o.shadow_blue,
.alpha = ps->o.shadow_opacity,
};
win_bind_shadow(ps->backend_data, w, c,
ps->gaussian_map);
}
w->flags |= WIN_FLAGS_PIXMAP_STALE;
ps->pending_updates = true;
}
}
}
// The old backends binds pixmap lazily, nothing to do here
return true;
}
/// Handle configure event of the root window
static void configure_root(session_t *ps) {
auto r = XCB_AWAIT(xcb_get_geometry, ps->c, ps->root);
if (!r) {
log_fatal("Failed to fetch root geometry");
abort();
}
log_info("Root configuration changed, new geometry: %dx%d", r->width, r->height);
bool has_root_change = false;
if (ps->redirected) {
// On root window changes
if (ps->o.experimental_backends) {
assert(ps->backend_data);
has_root_change = ps->backend_data->ops->root_change != NULL;
} else {
// Old backend can handle root change
has_root_change = true;
}
if (!has_root_change) {
// deinit/reinit backend and free up resources if the backend
// cannot handle root change
destroy_backend(ps);
}
free_paint(ps, &ps->tgt_buffer);
}
ps->root_width = r->width;
ps->root_height = r->height;
rebuild_screen_reg(ps);
rebuild_shadow_exclude_reg(ps);
// Invalidate reg_ignore from the top
auto top_w = win_stack_find_next_managed(ps, &ps->window_stack);
if (top_w) {
rc_region_unref(&top_w->reg_ignore);
top_w->reg_ignore_valid = false;
}
if (ps->redirected) {
for (int i = 0; i < ps->ndamage; i++) {
pixman_region32_clear(&ps->damage_ring[i]);
}
ps->damage = ps->damage_ring + ps->ndamage - 1;
#ifdef CONFIG_OPENGL
// GLX root change callback
if (BKEND_GLX == ps->o.backend && !ps->o.experimental_backends) {
glx_on_root_change(ps);
}
#endif
if (has_root_change) {
if (ps->backend_data != NULL) {
ps->backend_data->ops->root_change(ps->backend_data, ps);
}
// Old backend's root_change is not a specific function
} else {
if (!initialize_backend(ps)) {
log_fatal("Failed to re-initialize backend after root "
"change, aborting...");
ps->quit = true;
// TODO only event handlers should request ev_break,
// otherwise it's too hard to keep track of what can break
// the event loop
ev_break(ps->loop, EVBREAK_ALL);
return;
}
// Re-acquire the root pixmap.
root_damaged(ps);
}
force_repaint(ps);
}
return;
return ret;
}
static void handle_root_flags(session_t *ps) {
@ -607,11 +415,6 @@ static void handle_root_flags(session_t *ps) {
}
ps->root_flags &= ~(uint64_t)ROOT_FLAGS_SCREEN_CHANGE;
}
if ((ps->root_flags & ROOT_FLAGS_CONFIGURED) != 0) {
configure_root(ps);
ps->root_flags &= ~(uint64_t)ROOT_FLAGS_CONFIGURED;
}
}
static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
@ -668,8 +471,20 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
w->frame_opacity = 1.0;
}
// The below moved to it's own function:
// `win_determine_rounded_corners` (win.c)
/*
// 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)) {
w->corner_radius = 0;
} else {
w->corner_radius = ps->o.corner_radius;
}
*/
// Update window mode
w->mode = win_calc_mode(w);
w->mode = win_calc_mode(ps, w);
// Destroy all reg_ignore above when frame opaque state changes on
// SOLID mode
@ -678,56 +493,63 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
}
}
win_stack_foreach_managed(w, &ps->window_stack) {
bool posChanged = (w->oldX != -30000 && w->oldY != -30000 && w->oldW != 0 && w->oldH != 0)
&& (w->g.x != w->newX || w->g.y != w->newY || w->g.width != w->newW || w->g.height != w->newH);
win_stack_foreach_managed(w, &ps->window_stack) {
bool posChanged =
(w->oldX != -10000 && w->oldY != -10000 && w->oldW != 0 && w->oldH != 0) &&
(w->g.x != w->newX || w->g.y != w->newY || w->g.width != w->newW ||
w->g.height != w->newH);
if (posChanged) {
float t = get_time_ms();
float moveDx = (t - w->moveTimeX) / ps->o.transition_length;
float moveDy = (t - w->moveTimeY) / ps->o.transition_length;
float moveDw = (t - w->moveTimeW) / ps->o.transition_length;
float moveDh = (t - w->moveTimeH) / ps->o.transition_length;
if (moveDx >= 1.0) moveDx = 1.0;
if (moveDy >= 1.0) moveDy = 1.0;
if (moveDw >= 1.0) moveDw = 1.0;
if (moveDh >= 1.0) moveDh = 1.0;
if (posChanged) {
float t = get_time_ms();
float moveDx = (t - w->moveTimeX) / ps->o.transition_length;
float moveDy = (t - w->moveTimeY) / ps->o.transition_length;
float moveDw = (t - w->moveTimeW) / ps->o.transition_length;
float moveDh = (t - w->moveTimeH) / ps->o.transition_length;
if (moveDx >= 1.0)
moveDx = 1.0;
if (moveDy >= 1.0)
moveDy = 1.0;
if (moveDw >= 1.0)
moveDw = 1.0;
if (moveDh >= 1.0)
moveDh = 1.0;
float q = pow (moveDx, ps->o.transition_pow_x);
float k = pow (moveDy, ps->o.transition_pow_y);
float g = pow (moveDw, ps->o.transition_pow_w);
float z = pow (moveDh, ps->o.transition_pow_h);
float q = pow(moveDx, ps->o.transition_pow_x);
float k = pow(moveDy, ps->o.transition_pow_y);
float g = pow(moveDw, ps->o.transition_pow_w);
float z = pow(moveDh, ps->o.transition_pow_h);
float x = (float) w->oldX * (1-q) + (float) w->newX * q;
float y = (float) w->oldY * (1-k) + (float) w->newY * k;
float W = (float) w->oldW * (1-g) + (float) w->newW * g;
float h = (float) w->oldH * (1-z) + (float) w->newH * z;
float x = (float)w->oldX * (1 - q) + (float)w->newX * q;
float y = (float)w->oldY * (1 - k) + (float)w->newY * k;
float W = (float)w->oldW * (1 - g) + (float)w->newW * g;
float h = (float)w->oldH * (1 - z) + (float)w->newH * z;
add_damage_from_win(ps, w);
w->g.x = (int) x;
w->g.y = (int) y;
if (ps->o.size_transition) {
w->g.width = (int) W;
w->g.height = (int) h;
}
add_damage_from_win(ps, w);
w->g.x = (int)x;
w->g.y = (int)y;
if (ps->o.size_transition) {
w->g.width = (int)W;
w->g.height = (int)h;
}
/* w->to_paint = true; */
w->mode = WMODE_TRANS;
*fade_running = true;
}
// TODO
//if ((w->shadow && posChanged) || (ps->o.size_transition && w->pixmap_damaged)) {
// rc_region_unref(&w->extents);
// rc_region_unref(&w->border_size);
// w->extents = win_extents(ps, w);
// calc_win_size(ps, w);
/* w->to_paint = true; */
w->mode = WMODE_TRANS;
*fade_running = true;
}
// TODO
// if ((w->shadow && posChanged) || (ps->o.size_transition &&
// w->pixmap_damaged)) {
// rc_region_unref(&w->extents);
// rc_region_unref(&w->border_size);
// w->extents = win_extents(ps, w);
// calc_win_size(ps, w);
// if (ps->shape_exists && ps->o.shadow_ignore_shaped
// && ps->o.detect_rounded_corners && w->bounding_shaped)
// win_update_shape(ps, w);
//}
/* add_damage_win(ps, w); */
}
// if (ps->shape_exists && ps->o.shadow_ignore_shaped
// && ps->o.detect_rounded_corners && w->bounding_shaped)
// win_update_shape(ps, w);
//}
/* add_damage_win(ps, w); */
}
// Opacity will not change, from now on.
rc_region_t *last_reg_ignore = rc_region_new();
@ -747,6 +569,11 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
rc_region_unref(&w->reg_ignore);
}
// Clear flags if we are not using experimental backends
if (!ps->o.experimental_backends) {
w->flags = 0;
}
// log_trace("%d %d %s", w->a.map_state, w->ever_damaged, w->name);
// Give up if it's not damaged or invisible, or it's unmapped and its
@ -801,10 +628,10 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
// w->mode == WMODE_SOLID or WMODE_FRAME_TRANS
region_t *tmp = rc_region_new();
if (w->mode == WMODE_SOLID) {
*tmp = win_get_bounding_shape_global_by_val(w);
*tmp = win_get_bounding_shape_global_by_val(w, false);
} else {
// w->mode == WMODE_FRAME_TRANS
win_get_region_noframe_local(w, tmp);
win_get_region_noframe_local(w, tmp, false);
pixman_region32_intersect(tmp, tmp, &w->bounding_shape);
pixman_region32_translate(tmp, w->g.x, w->g.y);
}
@ -894,6 +721,243 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
return bottom;
}
/**
* Rebuild cached <code>screen_reg</code>.
*/
static void rebuild_screen_reg(session_t *ps) {
get_screen_region(ps, &ps->screen_reg);
}
/**
* Rebuild <code>shadow_exclude_reg</code>.
*/
static void rebuild_shadow_exclude_reg(session_t *ps) {
bool ret = parse_geometry(ps, ps->o.shadow_exclude_reg_str, &ps->shadow_exclude_reg);
if (!ret)
exit(1);
}
/// Free up all the images and deinit the backend
static void destroy_backend(session_t *ps) {
win_stack_foreach_managed_safe(w, &ps->window_stack) {
// Wrapping up fading in progress
if (win_skip_fading(ps, w)) {
// `w` is freed by win_skip_fading
continue;
}
if (ps->backend_data) {
if (w->state == WSTATE_MAPPED) {
win_release_images(ps->backend_data, w);
} else {
assert(!w->win_image);
assert(!w->shadow_image);
}
}
free_paint(ps, &w->paint);
}
if (ps->backend_data && ps->root_image) {
ps->backend_data->ops->release_image(ps->backend_data, ps->root_image);
ps->root_image = NULL;
}
if (ps->backend_data) {
// deinit backend
if (ps->backend_blur_context) {
ps->backend_data->ops->destroy_blur_context(
ps->backend_data, ps->backend_blur_context);
ps->backend_blur_context = NULL;
}
if (ps->backend_round_context) {
ps->backend_data->ops->destroy_round_context(
ps->backend_data, ps->backend_round_context);
ps->backend_round_context = NULL;
}
ps->backend_data->ops->deinit(ps->backend_data);
ps->backend_data = NULL;
}
}
static bool initialize_blur(session_t *ps) {
struct kernel_blur_args kargs;
struct gaussian_blur_args gargs;
struct dual_kawase_blur_args dkargs;
struct box_blur_args bargs;
void *args = NULL;
switch (ps->o.blur_method) {
case BLUR_METHOD_BOX:
bargs.size = ps->o.blur_radius;
args = (void *)&bargs;
break;
case BLUR_METHOD_KERNEL:
kargs.kernel_count = ps->o.blur_kernel_count;
kargs.kernels = ps->o.blur_kerns;
args = (void *)&kargs;
break;
case BLUR_METHOD_GAUSSIAN:
gargs.size = ps->o.blur_radius;
gargs.deviation = ps->o.blur_deviation;
args = (void *)&gargs;
break;
case BLUR_METHOD_ALT_KAWASE:
case BLUR_METHOD_DUAL_KAWASE:
dkargs.size = ps->o.blur_radius;
dkargs.strength = ps->o.blur_strength;
args = (void *)&dkargs;
break;
default: return true;
}
ps->backend_blur_context = ps->backend_data->ops->create_blur_context(
ps->backend_data, ps->o.blur_method, args);
return ps->backend_blur_context != NULL;
}
static bool initialize_round_corners(session_t *ps) {
struct round_corners_args cargs;
cargs.corner_radius = ps->o.corner_radius;
cargs.round_borders = ps->o.round_borders;
ps->backend_round_context =
ps->backend_data->ops->create_round_context(ps->backend_data, &cargs);
return ps->backend_round_context != NULL;
}
/// Init the backend and bind all the window pixmap to backend images
static bool initialize_backend(session_t *ps) {
if (ps->o.experimental_backends) {
assert(!ps->backend_data);
// Reinitialize win_data
assert(backend_list[ps->o.backend]);
ps->backend_data = backend_list[ps->o.backend]->init(ps);
if (!ps->backend_data) {
log_fatal("Failed to initialize backend, aborting...");
quit(ps);
return false;
}
ps->backend_data->ops = backend_list[ps->o.backend];
if (!initialize_blur(ps)) {
log_fatal("Failed to prepare for background blur, aborting...");
ps->backend_data->ops->deinit(ps->backend_data);
ps->backend_data = NULL;
quit(ps);
return false;
}
if (!initialize_round_corners(ps)) {
log_fatal("Failed to prepare for rounded corners, will "
"ignore...");
ps->o.corner_radius = 0;
}
// window_stack shouldn't include window that's
// not in the hash table at this point. Since
// there cannot be any fading windows.
HASH_ITER2(ps->windows, _w) {
if (!_w->managed) {
continue;
}
auto w = (struct managed_win *)_w;
assert(w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED);
if (w->state == WSTATE_MAPPED) {
// We need to reacquire image
log_debug("Marking window %#010x (%s) for update after "
"redirection",
w->base.id, w->name);
if (w->shadow) {
struct color c = {
.red = ps->o.shadow_red,
.green = ps->o.shadow_green,
.blue = ps->o.shadow_blue,
.alpha = ps->o.shadow_opacity,
};
win_bind_shadow(ps->backend_data, w, c,
ps->gaussian_map);
}
w->flags |= WIN_FLAGS_PIXMAP_STALE;
ps->pending_updates = true;
}
}
}
// The old backends binds pixmap lazily, nothing to do here
return true;
}
/// Handle configure event of a root window
void configure_root(session_t *ps, int width, int height) {
log_info("Root configuration changed, new geometry: %dx%d", width, height);
bool has_root_change = false;
if (ps->redirected) {
// On root window changes
if (ps->o.experimental_backends) {
assert(ps->backend_data);
has_root_change = ps->backend_data->ops->root_change != NULL;
} else {
// Old backend can handle root change
has_root_change = true;
}
if (!has_root_change) {
// deinit/reinit backend and free up resources if the backend
// cannot handle root change
destroy_backend(ps);
}
free_paint(ps, &ps->tgt_buffer);
}
ps->root_width = width;
ps->root_height = height;
rebuild_screen_reg(ps);
rebuild_shadow_exclude_reg(ps);
// Invalidate reg_ignore from the top
auto top_w = win_stack_find_next_managed(ps, &ps->window_stack);
if (top_w) {
rc_region_unref(&top_w->reg_ignore);
top_w->reg_ignore_valid = false;
}
if (ps->redirected) {
for (int i = 0; i < ps->ndamage; i++) {
pixman_region32_clear(&ps->damage_ring[i]);
}
ps->damage = ps->damage_ring + ps->ndamage - 1;
#ifdef CONFIG_OPENGL
// GLX root change callback
if (BKEND_GLX == ps->o.backend && !ps->o.experimental_backends) {
glx_on_root_change(ps);
}
#endif
if (has_root_change) {
if (ps->backend_data != NULL) {
ps->backend_data->ops->root_change(ps->backend_data, ps);
}
// Old backend's root_change is not a specific function
} else {
if (!initialize_backend(ps)) {
log_fatal("Failed to re-initialize backend after root "
"change, aborting...");
ps->quit = true;
// TODO only event handlers should request ev_break,
// otherwise it's too hard to keep track of what can break
// the event loop
ev_break(ps->loop, EVBREAK_ALL);
return;
}
// Re-acquire the root pixmap.
root_damaged(ps);
}
force_repaint(ps);
}
return;
}
void root_damaged(session_t *ps) {
if (ps->root_tile_paint.pixmap) {
free_root_tile(ps);
@ -1277,7 +1341,6 @@ static bool redirect_start(session_t *ps) {
// Re-detect driver since we now have a backend
ps->drivers = detect_driver(ps->c, ps->backend_data, ps->root);
apply_driver_workarounds(ps, ps->drivers);
root_damaged(ps);
@ -1363,6 +1426,12 @@ static void handle_new_windows(session_t *ps) {
}
static void refresh_windows(session_t *ps) {
win_stack_foreach_managed_safe(w, &ps->window_stack) {
win_process_updates(ps, w);
}
}
static void refresh_stale_images(session_t *ps) {
win_stack_foreach_managed(w, &ps->window_stack) {
win_process_flags(ps, w);
}
@ -1399,13 +1468,7 @@ static void handle_pending_updates(EV_P_ struct session *ps) {
// Call fill_win on new windows
handle_new_windows(ps);
// Handle screen changes
// This HAS TO be called before refresh_windows, as handle_root_flags
// could call configure_root, which will release images and mark them
// stale.
handle_root_flags(ps);
// Process window flags
// Process window updates
refresh_windows(ps);
{
@ -1417,6 +1480,12 @@ static void handle_pending_updates(EV_P_ struct session *ps) {
free(r);
}
// Refresh pixmaps and shadows
refresh_stale_images(ps);
// Handle screen changes
handle_root_flags(ps);
e = xcb_request_check(ps->c, xcb_ungrab_server_checked(ps->c));
if (e) {
log_fatal_x_error(e, "failed to ungrab x server");
@ -1670,9 +1739,11 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
.randr_exists = 0,
.randr_event = 0,
.randr_error = 0,
#ifdef CONFIG_OPENGL
.glx_exists = false,
.glx_event = 0,
.glx_error = 0,
#endif
.xrfilter_convolution_exists = false,
.atoms_wintypes = {0},
@ -1739,7 +1810,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
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);
ext_info = xcb_get_extension_data(ps->c, &xcb_render_id);
if (!ext_info || !ext_info->present) {
@ -1795,13 +1865,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
XCB_XFIXES_MINOR_VERSION)
.sequence);
ext_info = xcb_get_extension_data(ps->c, &xcb_glx_id);
if (ext_info && ext_info->present) {
ps->glx_exists = true;
ps->glx_error = ext_info->first_error;
ps->glx_event = ext_info->first_event;
}
// Parse configuration file
win_option_mask_t winopt_mask[NUM_WINTYPES] = {{0}};
bool shadow_enabled = false, fading_enable = false, hasneg = false;
@ -1869,6 +1932,8 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
c2_list_postprocess(ps, ps->o.blur_background_blacklist) &&
c2_list_postprocess(ps, ps->o.invert_color_list) &&
c2_list_postprocess(ps, ps->o.opacity_rules) &&
c2_list_postprocess(ps, ps->o.rounded_corners_blacklist) &&
c2_list_postprocess(ps, ps->o.round_borders_blacklist) &&
c2_list_postprocess(ps, ps->o.focus_blacklist))) {
log_error("Post-processing of conditionals failed, some of your rules "
"might not work");
@ -1925,24 +1990,23 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
}
ps->sync_fence = XCB_NONE;
if (ps->xsync_exists) {
if (!ps->xsync_exists && ps->o.xrender_sync_fence) {
log_error("XSync extension not found. No XSync fence sync is "
"possible. (xrender-sync-fence can't be enabled)");
ps->o.xrender_sync_fence = false;
}
if (ps->o.xrender_sync_fence) {
ps->sync_fence = x_new_id(ps->c);
e = xcb_request_check(
ps->c, xcb_sync_create_fence(ps->c, ps->root, ps->sync_fence, 0));
if (e) {
if (ps->o.xrender_sync_fence) {
log_error_x_error(e, "Failed to create a XSync fence. "
"xrender-sync-fence will be "
"disabled");
ps->o.xrender_sync_fence = false;
}
log_error_x_error(e, "Failed to create a XSync fence. "
"xrender-sync-fence will be disabled");
ps->o.xrender_sync_fence = false;
ps->sync_fence = XCB_NONE;
free(e);
}
} else if (ps->o.xrender_sync_fence) {
log_error("XSync extension not found. No XSync fence sync is "
"possible. (xrender-sync-fence can't be enabled)");
ps->o.xrender_sync_fence = false;
}
// Query X RandR
@ -2014,8 +2078,12 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
}
}
// Target window must be initialized before the backend
//
// backend_operations::present == NULL means this backend doesn't need a target
// window; non experimental backends always need a target window
ps->drivers = detect_driver(ps->c, ps->backend_data, ps->root);
apply_driver_workarounds(ps, ps->drivers);
// Initialize filters, must be preceded by OpenGL context creation
if (!ps->o.experimental_backends && !init_render(ps)) {
@ -2132,7 +2200,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
e = xcb_request_check(ps->c, xcb_grab_server_checked(ps->c));
if (e) {
log_fatal_x_error(e, "Failed to grab X server");
free(e);
goto err;
}
@ -2151,7 +2218,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
if (e) {
log_fatal_x_error(e, "Failed to ungrab server");
free(e);
goto err;
}
ps->server_grabbed = false;
@ -2241,6 +2307,8 @@ static void session_destroy(session_t *ps) {
free_wincondlst(&ps->o.opacity_rules);
free_wincondlst(&ps->o.paint_blacklist);
free_wincondlst(&ps->o.unredir_if_possible_blacklist);
free_wincondlst(&ps->o.rounded_corners_blacklist);
free_wincondlst(&ps->o.round_borders_blacklist);
// Free tracked atom list
{

View File

@ -25,11 +25,7 @@
#include "win.h"
#include "x.h"
enum root_flags {
ROOT_FLAGS_SCREEN_CHANGE = 1, // Received RandR screen change notify, we
// use this to track refresh rate changes
ROOT_FLAGS_CONFIGURED = 2 // Received configure notify on the root window
};
enum root_flags { ROOT_FLAGS_SCREEN_CHANGE = 1 };
// == Functions ==
// TODO move static inline functions that are only used in picom.c, into
@ -42,6 +38,11 @@ void add_damage(session_t *ps, const region_t *damage);
uint32_t determine_evmask(session_t *ps, xcb_window_t wid, win_evmode_t mode);
xcb_window_t find_client_win(session_t *ps, xcb_window_t w);
/// Handle configure event of a root window
void configure_root(session_t *ps, int width, int height);
void circulate_win(session_t *ps, xcb_circulate_notify_event_t *ce);
void update_refresh_rate(session_t *ps);

View File

@ -48,14 +48,15 @@ static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, int wid, int h
bool repeat, int depth, xcb_visualid_t visual, bool force) {
#ifdef CONFIG_OPENGL
// XXX This is a mess. But this will go away after the backend refactor.
static thread_local struct glx_fbconfig_info *argb_fbconfig = NULL;
if (!ppaint->pixmap)
return false;
struct glx_fbconfig_info *fbcfg;
if (!visual) {
assert(depth == 32);
if (!ps->argb_fbconfig) {
ps->argb_fbconfig =
if (!argb_fbconfig) {
argb_fbconfig =
glx_find_fbconfig(ps->dpy, ps->scr,
(struct xvisual_info){.red_size = 8,
.green_size = 8,
@ -63,11 +64,11 @@ static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, int wid, int h
.alpha_size = 8,
.visual_depth = 32});
}
if (!ps->argb_fbconfig) {
if (!argb_fbconfig) {
log_error("Failed to find appropriate FBConfig for 32 bit depth");
return false;
}
fbcfg = ps->argb_fbconfig;
fbcfg = argb_fbconfig;
} else {
auto m = x_get_visual_info(ps->c, visual);
if (m.visual_depth < 0) {
@ -185,28 +186,139 @@ void free_paint(session_t *ps, paint_t *ppaint) {
ppaint->pixmap = XCB_NONE;
}
void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, double opacity,
bool argb, bool neg, xcb_render_picture_t pict, glx_texture_t *ptex,
const region_t *reg_paint, const glx_prog_main_t *pprogram) {
uint32_t
make_circle(int cx, int cy, int radius, uint32_t max_ntraps, xcb_render_trapezoid_t traps[]) {
uint32_t n = 0, k = 0;
int y1, y2;
double w;
while (k < max_ntraps) {
y1 = (int)(-radius * cos(M_PI * k / max_ntraps));
traps[n].top = (cy + y1) << 16;
traps[n].left.p1.y = (cy + y1) << 16;
traps[n].right.p1.y = (cy + y1) << 16;
w = sqrt(radius * radius - y1 * y1) * 65536;
traps[n].left.p1.x = (int)((cx << 16) - w);
traps[n].right.p1.x = (int)((cx << 16) + w);
do {
k++;
y2 = (int)(-radius * cos(M_PI * k / max_ntraps));
} while (y1 == y2);
traps[n].bottom = (cy + y2) << 16;
traps[n].left.p2.y = (cy + y2) << 16;
traps[n].right.p2.y = (cy + y2) << 16;
w = sqrt(radius * radius - y2 * y2) * 65536;
traps[n].left.p2.x = (int)((cx << 16) - w);
traps[n].right.p2.x = (int)((cx << 16) + w);
n++;
}
return n;
}
uint32_t make_rectangle(int x, int y, int wid, int hei, xcb_render_trapezoid_t traps[]) {
traps[0].top = y << 16;
traps[0].left.p1.y = y << 16;
traps[0].left.p1.x = x << 16;
traps[0].left.p2.y = (y + hei) << 16;
traps[0].left.p2.x = x << 16;
traps[0].bottom = (y + hei) << 16;
traps[0].right.p1.x = (x + wid) << 16;
traps[0].right.p1.y = y << 16;
traps[0].right.p2.x = (x + wid) << 16;
traps[0].right.p2.y = (y + hei) << 16;
return 1;
}
uint32_t make_rounded_window_shape(xcb_render_trapezoid_t traps[], uint32_t max_ntraps, int cr, int wid, int hei)
{
uint32_t n = make_circle(cr, cr, cr, max_ntraps, traps);
n += make_circle(wid - cr, cr, cr, max_ntraps, traps + n);
n += make_circle(wid - cr, hei - cr, cr, max_ntraps, traps + n);
n += make_circle(cr, hei - cr, cr, max_ntraps, traps + n);
n += make_rectangle(0, cr, cr, hei - 2 * cr, traps + n);
n += make_rectangle(cr, 0, wid - 2 * cr, cr, traps + n);
n += make_rectangle(wid - cr, cr, cr, hei - 2 * cr, traps + n);
n += make_rectangle(cr, hei - cr, wid - 2 * cr, cr, traps + n);
n += make_rectangle(cr, cr, wid - 2 * cr, hei - 2 * cr,
traps + n);
return n;
}
void render(session_t *ps, struct managed_win *w attr_unused, int x, int y,
int dx, int dy, int wid, int hei, int fullwid, int fullhei, double opacity,
bool argb, bool neg, int cr, xcb_render_picture_t pict, glx_texture_t *ptex,
const region_t *reg_paint, const glx_prog_main_t *pprogram, clip_t *clip) {
switch (ps->o.backend) {
case BKEND_XRENDER:
case BKEND_XR_GLX_HYBRID: {
auto alpha_step = (int)(opacity * MAX_ALPHA);
xcb_render_picture_t alpha_pict = ps->alpha_picts[alpha_step];
if (alpha_step != 0) {
uint8_t op = ((!argb && !alpha_pict) ? XCB_RENDER_PICT_OP_SRC
if (cr) {
//log_warn("f(%d, %d) wh(%d %d) xy(%d %d) dxy(%d %d)", fullwid, fullhei, wid, hei, x, y, dx, dy);
xcb_render_picture_t p_tmp = x_create_picture_with_standard(
ps->c, ps->root, fullwid, fullhei, XCB_PICT_STANDARD_ARGB_32, 0, 0);
xcb_render_color_t trans = {
.red = 0, .blue = 0, .green = 0, .alpha = 0};
const xcb_rectangle_t rect = {.x = 0,
.y = 0,
.width = to_u16_checked(fullwid),
.height = to_u16_checked(fullhei)};
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC,
p_tmp, trans, 1, &rect);
uint32_t max_ntraps = to_u32_checked(cr);
xcb_render_trapezoid_t traps[4 * max_ntraps + 5];
uint32_t n = make_rounded_window_shape(traps, max_ntraps, cr, fullwid, fullhei);
xcb_render_trapezoids(
ps->c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp,
x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8),
0, 0, n, traps);
xcb_render_composite(
ps->c, XCB_RENDER_PICT_OP_OVER, pict, p_tmp,
ps->tgt_buffer.pict, to_i16_checked(x), to_i16_checked(y),
to_i16_checked(x), to_i16_checked(y), to_i16_checked(dx), to_i16_checked(dy),
to_u16_checked(wid), to_u16_checked(hei));
xcb_render_free_picture(ps->c, p_tmp);
} else {
xcb_render_picture_t p_tmp = alpha_pict;
if(clip){
p_tmp = x_create_picture_with_standard(ps->c, ps->root, wid, hei, XCB_PICT_STANDARD_ARGB_32, 0, 0);
xcb_render_color_t black = {.red = 255, .blue = 255, .green = 255, .alpha = 255};
const xcb_rectangle_t rect = {.x = 0, .y = 0, .width = to_u16_checked(wid), .height = to_u16_checked(hei)};
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, p_tmp, black, 1, &rect);
if(alpha_pict) {
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, alpha_pict, XCB_NONE, p_tmp, 0, 0, 0, 0, 0, 0, to_u16_checked(wid), to_u16_checked(hei));
}
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_OUT_REVERSE, clip->pict, XCB_NONE, p_tmp, 0, 0, 0, 0, to_i16_checked(clip->x), to_i16_checked(clip->y), to_u16_checked(wid), to_u16_checked(hei));
}
uint8_t op = ((!argb && !alpha_pict && !clip) ? XCB_RENDER_PICT_OP_SRC
: XCB_RENDER_PICT_OP_OVER);
xcb_render_composite(
ps->c, op, pict, alpha_pict, ps->tgt_buffer.pict,
to_i16_checked(x), to_i16_checked(y), 0, 0, to_i16_checked(dx),
to_i16_checked(dy), to_u16_checked(wid), to_u16_checked(hei));
xcb_render_composite(
ps->c, op, pict, p_tmp/*alpha_pict*/, ps->tgt_buffer.pict,
to_i16_checked(x), to_i16_checked(y), 0, 0, to_i16_checked(dx),
to_i16_checked(dy), to_u16_checked(wid), to_u16_checked(hei));
if(clip){
xcb_render_free_picture(ps->c, p_tmp);
}
}
}
break;
}
#ifdef CONFIG_OPENGL
case BKEND_GLX:
glx_render(ps, ptex, x, y, dx, dy, wid, hei, ps->psglx->z, opacity, argb,
neg, reg_paint, pprogram);
glx_render(ps, w, ptex, x, y, dx, dy, wid, hei, ps->psglx->z, opacity, argb,
neg, cr, reg_paint, pprogram);
ps->psglx->z += 1;
break;
#endif
@ -221,21 +333,24 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, doubl
}
static inline void
paint_region(session_t *ps, const struct managed_win *w, int x, int y, int wid, int hei,
paint_region(session_t *ps, struct managed_win *w, int x, int y, int wid, int hei,
double opacity, const region_t *reg_paint, xcb_render_picture_t pict) {
const int dx = (w ? w->g.x : 0) + x;
const int dy = (w ? w->g.y : 0) + y;
const int fullwid = w ? w->widthb : 0;
const int fullhei = w ? w-> heightb : 0;
const bool argb = (w && (win_has_alpha(w) || ps->o.force_win_blend));
const bool neg = (w && w->invert_color);
render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, pict,
(w ? w->paint.ptex : ps->root_tile_paint.ptex), reg_paint,
render(ps, w, x, y, dx, dy, wid, hei, fullwid, fullhei, opacity, argb, neg,
(w ? w->corner_radius : 0),
pict, (w ? w->paint.ptex : ps->root_tile_paint.ptex), reg_paint,
#ifdef CONFIG_OPENGL
w ? &ps->glx_prog_win : NULL
#else
NULL
#endif
);
, XCB_NONE);
}
/**
@ -258,6 +373,46 @@ static inline bool paint_isvalid(session_t *ps, const paint_t *ppaint) {
return true;
}
/**
* Rounde the corners of a window.
* Applies a fragment shader to discard corners
*
*/
static inline void
win_round_corners(session_t *ps, struct managed_win *w attr_unused, int shader_idx attr_unused, float cr attr_unused,
xcb_render_picture_t tgt_buffer attr_unused, const region_t *reg_paint) {
#ifdef CONFIG_OPENGL
const int16_t x = w->g.x;
const int16_t y = w->g.y;
const auto wid = to_u16_checked(w->widthb);
const auto hei = to_u16_checked(w->heightb);
#endif
//log_debug("x:%d y:%d w:%d h:%d", x, y, wid, hei);
switch (ps->o.backend) {
case BKEND_XRENDER:
case BKEND_XR_GLX_HYBRID: {
// XRender method is implemented inside render()
} break;
#ifdef CONFIG_OPENGL
case BKEND_GLX:
if (shader_idx == 1) {
glx_round_corners_dst1(ps, w, w->glx_texture_bg, shader_idx, x, y, wid, hei,
(float)ps->psglx->z - 0.5f, cr, reg_paint, &w->glx_round_cache);
} else {
glx_round_corners_dst0(ps, w, w->glx_texture_bg, shader_idx, x, y, wid, hei,
(float)ps->psglx->z - 0.5f, cr, reg_paint, &w->glx_round_cache);
}
break;
#endif
default: assert(0);
}
#ifndef CONFIG_OPENGL
(void)reg_paint;
#endif
}
/**
* Paint a window itself and dim it if asked.
*/
@ -529,8 +684,8 @@ static void paint_root(session_t *ps, const region_t *reg_paint) {
* Generate shadow <code>Picture</code> for a window.
*/
static bool win_build_shadow(session_t *ps, struct managed_win *w, double opacity) {
/* const int width = w->widthb; */
/* const int height = w->heightb; */
//const int width = w->widthb;
//const int height = w->heightb;
const int width = w->newW; // TODO!
const int height = w->newH;
// log_trace("(): building shadow for %s %d %d", w->name, width, height);
@ -613,9 +768,29 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) {
return;
}
render(ps, 0, 0, w->g.x + w->shadow_dx, w->g.y + w->shadow_dy, w->shadow_width,
w->shadow_height, w->shadow_opacity, true, false, w->shadow_paint.pict,
w->shadow_paint.ptex, reg_paint, NULL);
xcb_render_picture_t td = XCB_NONE;
if (w->corner_radius) {
uint32_t max_ntraps = to_u32_checked(w->corner_radius);
xcb_render_trapezoid_t traps[4 * max_ntraps + 5];
uint32_t n = make_rounded_window_shape(traps, max_ntraps, w->corner_radius, w->widthb, w->heightb);
td = x_create_picture_with_standard(ps->c, ps->root, w->widthb, w->heightb, XCB_PICT_STANDARD_ARGB_32, 0, 0);
xcb_render_color_t trans = {.red = 0, .blue = 0, .green = 0, .alpha = 0};
const xcb_rectangle_t rect = {.x = 0, .y = 0, .width = to_u16_checked(w->widthb), .height = to_u16_checked(w->heightb)};
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, td, trans, 1, &rect);
xcb_render_trapezoids(ps->c, XCB_RENDER_PICT_OP_OVER, solid_picture(ps->c, ps->root, false, 1, 0, 0, 0), td, x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), 0, 0, n, traps);
}
clip_t clip = { .pict = td, -(w->shadow_dx), .y = -(w->shadow_dy) };
render(ps, w, 0, 0, w->g.x + w->shadow_dx, w->g.y + w->shadow_dy, w->shadow_width,
w->shadow_height, w->widthb, w->heightb, w->shadow_opacity, true, false, 0, w->shadow_paint.pict,
w->shadow_paint.ptex, reg_paint, NULL, w->corner_radius ? &clip : NULL);
if(td){
xcb_render_free_picture(ps->c, td);
}
}
/**
@ -635,7 +810,7 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) {
*/
static bool xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t x, int16_t y,
uint16_t wid, uint16_t hei, struct x_convolution_kernel **blur_kerns,
int nkernels, const region_t *reg_clip) {
int nkernels, const region_t *reg_clip, xcb_render_picture_t rounded) {
assert(blur_kerns);
assert(blur_kerns[0]);
@ -680,7 +855,8 @@ static bool xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t
}
if (src_pict != tgt_buffer)
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE,
//xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, src_pict, rounded,
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_OVER, src_pict, rounded,
tgt_buffer, 0, 0, 0, 0, x, y, wid, hei);
free_picture(ps->c, &tmp_picture);
@ -698,6 +874,7 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t
const int16_t y = w->g.y;
const auto wid = to_u16_checked(w->widthb);
const auto hei = to_u16_checked(w->heightb);
const int cr = (w ? w->corner_radius : 0);
double factor_center = 1.0;
// Adjust blur strength according to window opacity, to make it appear
@ -729,13 +906,27 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t
&ps->blur_kerns_cache[i]);
}
xcb_render_picture_t td = XCB_NONE;
if (cr) {
uint32_t max_ntraps = to_u32_checked(cr);
xcb_render_trapezoid_t traps[4 * max_ntraps + 5];
uint32_t n = make_rounded_window_shape(traps, max_ntraps, cr, wid, hei);
td = x_create_picture_with_standard(ps->c, ps->root, wid, hei, XCB_PICT_STANDARD_ARGB_32, 0, 0);
xcb_render_color_t trans = {.red = 0, .blue = 0, .green = 0, .alpha = 0};
const xcb_rectangle_t rect = {.x = 0, .y = 0, .width = to_u16_checked(wid), .height = to_u16_checked(hei)};
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, td, trans, 1, &rect);
xcb_render_trapezoids(ps->c, XCB_RENDER_PICT_OP_OVER, solid_picture(ps->c, ps->root, false, 1, 0, 0, 0), td, x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), 0, 0, n, traps);
}
// Minimize the region we try to blur, if the window itself is not
// opaque, only the frame is.
region_t reg_blur = win_get_bounding_shape_global_by_val(w);
region_t reg_blur = win_get_bounding_shape_global_by_val(w, true);
if (w->mode == WMODE_FRAME_TRANS && !ps->o.force_win_blend) {
region_t reg_noframe;
pixman_region32_init(&reg_noframe);
win_get_region_noframe_local(w, &reg_noframe);
win_get_region_noframe_local(w, &reg_noframe, true);
pixman_region32_translate(&reg_noframe, w->g.x, w->g.y);
pixman_region32_subtract(&reg_blur, &reg_blur, &reg_noframe);
pixman_region32_fini(&reg_noframe);
@ -743,14 +934,14 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t
// Translate global coordinates to local ones
pixman_region32_translate(&reg_blur, -x, -y);
xr_blur_dst(ps, tgt_buffer, x, y, wid, hei, ps->blur_kerns_cache,
ps->o.blur_kernel_count, &reg_blur);
ps->o.blur_kernel_count, &reg_blur, td);
pixman_region32_clear(&reg_blur);
} break;
#ifdef CONFIG_OPENGL
case BKEND_GLX:
// TODO: Handle frame opacity
glx_blur_dst(ps, x, y, wid, hei, (float)ps->psglx->z - 0.5f,
(float)factor_center, reg_paint, &w->glx_blur_cache);
(float)w->opacity, reg_paint, &w->glx_blur_cache);
break;
#endif
default: assert(0);
@ -852,7 +1043,9 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
//
// Whether this is beneficial is to be determined XXX
for (auto w = t; w; w = w->prev_trans) {
region_t bshape = win_get_bounding_shape_global_by_val(w);
region_t bshape_no_corners = win_get_bounding_shape_global_by_val(w, false);
region_t bshape_corners = win_get_bounding_shape_global_by_val(w, true);
// Painting shadow
if (w->shadow) {
// Lazy shadow building
@ -881,7 +1074,7 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
// saving GPU power and handling shaped windows (XXX
// unconfirmed)
if (!ps->o.wintype_option[w->window_type].full_shadow)
pixman_region32_subtract(&reg_tmp, &reg_tmp, &bshape);
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)
@ -908,12 +1101,25 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
// Remember, reg_ignore is the union of all windows above the current
// window.
pixman_region32_subtract(&reg_tmp, &region, w->reg_ignore);
pixman_region32_intersect(&reg_tmp, &reg_tmp, &bshape);
pixman_region32_fini(&bshape);
pixman_region32_intersect(&reg_tmp, &reg_tmp, &bshape_corners);
pixman_region32_fini(&bshape_corners);
pixman_region32_fini(&bshape_no_corners);
reg_tmp = region;
if (pixman_region32_not_empty(&reg_tmp) || true) {
set_tgt_clip(ps, &reg_tmp);
// If rounded corners backup the region first
#ifdef CONFIG_OPENGL
if (w->corner_radius > 0) {
const int16_t x = w->g.x;
const int16_t y = w->g.y;
const auto wid = to_u16_checked(w->widthb);
const auto hei = to_u16_checked(w->heightb);
glx_bind_texture(ps, &w->glx_texture_bg, x, y, wid, hei, false);
}
#endif
// Blur window background
if (w->blur_background &&
(w->mode == WMODE_TRANS ||
@ -923,6 +1129,12 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
// Painting the window
paint_one(ps, w, &reg_tmp);
// Round window corners
if (w->corner_radius > 0) {
win_round_corners(ps, w, 1, (float)w->corner_radius,
ps->tgt_buffer.pict, &reg_tmp);
}
}
}
@ -1011,8 +1223,8 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
else
glFlush();
glXWaitX();
glx_render(ps, ps->tgt_buffer.ptex, 0, 0, 0, 0, ps->root_width,
ps->root_height, 0, 1.0, false, false, &region, NULL);
glx_render(ps, t, ps->tgt_buffer.ptex, 0, 0, 0, 0, ps->root_width,
ps->root_height, 0, 1.0, false, false, 0, &region, NULL);
// falls through
case BKEND_GLX: glXSwapBuffers(ps->dpy, get_tgt_window(ps)); break;
#endif
@ -1131,13 +1343,15 @@ bool init_render(session_t *ps) {
}
// Blur filter
if (ps->o.blur_method && ps->o.blur_method != BLUR_METHOD_KERNEL) {
log_warn("Old backends only support blur method \"kernel\". Your blur "
if (ps->o.blur_method && ps->o.blur_method != BLUR_METHOD_KERNEL &&
ps->o.blur_method != BLUR_METHOD_DUAL_KAWASE && ps->o.blur_method != BLUR_METHOD_ALT_KAWASE) {
log_warn("Old backends only support blur methods \"kernel|kawase\". Your blur "
"setting will not be applied");
ps->o.blur_method = BLUR_METHOD_NONE;
}
if (ps->o.blur_method == BLUR_METHOD_KERNEL) {
if (ps->o.blur_method == BLUR_METHOD_KERNEL || ps->o.blur_method == BLUR_METHOD_DUAL_KAWASE
|| ps->o.blur_method == BLUR_METHOD_ALT_KAWASE) {
ps->blur_kerns_cache =
ccalloc(ps->o.blur_kernel_count, struct x_convolution_kernel *);
@ -1176,6 +1390,18 @@ bool init_render(session_t *ps) {
return false;
}
}
// Initialize our rounded corners fragment shader
if (ps->o.corner_radius > 0 && ps->o.backend == BKEND_GLX) {
#ifdef CONFIG_OPENGL
if (!glx_init_rounded_corners(ps)) {
log_error("Failed to init rounded corners shader.");
return false;
}
#else
assert(false);
#endif
}
return true;
}

View File

@ -25,9 +25,15 @@ typedef struct paint {
#endif
} paint_t;
void render(session_t *ps, int x, int y, int dx, int dy, int w, int h, double opacity,
bool argb, bool neg, xcb_render_picture_t pict, glx_texture_t *ptex,
const region_t *reg_paint, const glx_prog_main_t *pprogram);
typedef struct clip {
xcb_render_picture_t pict;
int x;
int y;
} clip_t;
void render(session_t *ps, struct managed_win *, int x, int y, int dx, int dy, int w, int h, int fullw, int fullh, double opacity,
bool argb, bool neg, int cr, xcb_render_picture_t pict, glx_texture_t *ptex,
const region_t *reg_paint, const glx_prog_main_t *pprogram, clip_t *clip);
void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint);
void paint_all(session_t *ps, struct managed_win *const t, bool ignore_damage);

View File

@ -33,6 +33,9 @@ safe_isnan(double a) {
return __builtin_isnan(a);
}
#define CASESTRRET(s) \
case s: return #s
/// Same as assert(false), but make sure we abort _even in release builds_.
/// Silence compiler warning caused by release builds making some code paths reachable.
#define BUG() \

364
src/win.c
View File

@ -46,6 +46,9 @@
// TODO Make more window states internal
struct managed_win_internal {
struct managed_win base;
/// A bit mask of unhandled window updates
uint_fast32_t pending_updates;
};
#define OPAQUE (0xffffffff)
@ -53,6 +56,17 @@ static const int WIN_GET_LEADER_MAX_RECURSION = 20;
static const int ROUNDED_PIXELS = 1;
static const double ROUNDED_PERCENT = 0.05;
/// Generate a "return by value" function, from a function that returns the
/// region via a region_t pointer argument.
/// Function signature has to be (win *, region_t *, bool)
#define gen_by_val_corners(fun) \
region_t fun##_by_val(const struct managed_win *w, bool include_corners) { \
region_t ret; \
pixman_region32_init(&ret); \
fun(w, &ret, include_corners); \
return ret; \
}
/// Generate a "return by value" function, from a function that returns the
/// region via a region_t pointer argument.
/// Function signature has to be (win *, region_t *)
@ -109,6 +123,19 @@ static void win_update_focused(session_t *ps, struct managed_win *w) {
w->focused = true;
}
}
// Always recalculate the window target opacity, since some opacity-related
// options depend on the output value of win_is_focused_real() instead of
// w->focused
auto opacity_target_old = w->opacity_target;
w->opacity_target = win_calc_opacity_target(ps, w, false);
if (opacity_target_old != w->opacity_target && w->state == WSTATE_MAPPED) {
// Only MAPPED can transition to FADING
w->state = WSTATE_FADING;
if (!ps->redirected) {
CHECK(!win_skip_fading(ps, w));
}
}
}
/**
@ -170,16 +197,18 @@ static inline bool group_is_focused(session_t *ps, xcb_window_t leader) {
/**
* Get a rectangular region a window occupies, excluding shadow.
*/
static void win_get_region_local(const struct managed_win *w, region_t *res) {
static void win_get_region_local(const struct managed_win *w, region_t *res, bool include_corners) {
assert(w->widthb >= 0 && w->heightb >= 0);
pixman_region32_fini(res);
pixman_region32_init_rect(res, 0, 0, (uint)w->widthb, (uint)w->heightb);
if(!include_corners) win_region_remove_corners(w, res);
}
/**
* Get a rectangular region a window occupies, excluding frame and shadow.
*/
void win_get_region_noframe_local(const struct managed_win *w, region_t *res) {
void win_get_region_noframe_local(const struct managed_win *w, region_t *res, bool include_corners) {
const margin_t extents = win_calc_frame_extents(w);
int x = extents.left;
@ -190,10 +219,11 @@ void win_get_region_noframe_local(const struct managed_win *w, region_t *res) {
pixman_region32_fini(res);
if (width > 0 && height > 0) {
pixman_region32_init_rect(res, x, y, (uint)width, (uint)height);
if(!include_corners) win_region_remove_corners(w, res);
}
}
void win_get_region_frame_local(const struct managed_win *w, region_t *res) {
void win_get_region_frame_local(const struct managed_win *w, region_t *res, bool include_corners) {
const margin_t extents = win_calc_frame_extents(w);
auto outer_width = extents.left + extents.right + w->g.width;
auto outer_height = extents.top + extents.bottom + w->g.height;
@ -216,10 +246,11 @@ void win_get_region_frame_local(const struct managed_win *w, region_t *res) {
region_t reg_win;
pixman_region32_init_rects(&reg_win, (rect_t[]){0, 0, outer_width, outer_height}, 1);
pixman_region32_intersect(res, &reg_win, res);
if(!include_corners) win_region_remove_corners(w, res);
pixman_region32_fini(&reg_win);
}
gen_by_val(win_get_region_frame_local);
gen_by_val_corners(win_get_region_frame_local);
/**
* Add a window to damaged area.
@ -244,7 +275,6 @@ static inline void win_release_pixmap(backend_t *base, struct managed_win *w) {
if (w->win_image) {
base->ops->release_image(base, w->win_image);
w->win_image = NULL;
// Bypassing win_set_flags, because `w` might have been destroyed
w->flags |= WIN_FLAGS_PIXMAP_NONE;
}
}
@ -254,7 +284,6 @@ static inline void win_release_shadow(backend_t *base, struct managed_win *w) {
if (w->shadow_image) {
base->ops->release_image(base, w->shadow_image);
w->shadow_image = NULL;
// Bypassing win_set_flags, because `w` might have been destroyed
w->flags |= WIN_FLAGS_SHADOW_NONE;
}
}
@ -275,11 +304,11 @@ static inline bool win_bind_pixmap(struct backend_base *b, struct managed_win *w
b->ops->bind_pixmap(b, pixmap, x_get_visual_info(b->c, w->a.visual), true);
if (!w->win_image) {
log_error("Failed to bind pixmap");
win_set_flags(w, WIN_FLAGS_IMAGE_ERROR);
w->flags |= WIN_FLAGS_IMAGE_ERROR;
return false;
}
win_clear_flags(w, WIN_FLAGS_PIXMAP_NONE);
w->flags &= ~WIN_FLAGS_PIXMAP_NONE;
return true;
}
@ -293,13 +322,13 @@ bool win_bind_shadow(struct backend_base *b, struct managed_win *w, struct color
log_error("Failed to bind shadow image, shadow will be disabled for "
"%#010x (%s)",
w->base.id, w->name);
win_set_flags(w, WIN_FLAGS_SHADOW_NONE);
w->flags |= WIN_FLAGS_SHADOW_NONE;
w->shadow = false;
return false;
}
log_debug("New shadow for %#010x (%s)", w->base.id, w->name);
win_clear_flags(w, WIN_FLAGS_SHADOW_NONE);
w->flags &= ~WIN_FLAGS_SHADOW_NONE;
return true;
}
@ -309,38 +338,40 @@ void win_release_images(struct backend_base *backend, struct managed_win *w) {
// But if we are not releasing any images anyway, we don't care about the stale
// flags.
if (!win_check_flags_all(w, WIN_FLAGS_PIXMAP_NONE)) {
assert(!win_check_flags_all(w, WIN_FLAGS_PIXMAP_STALE));
if ((w->flags & WIN_FLAGS_PIXMAP_NONE) == 0) {
assert((w->flags & WIN_FLAGS_PIXMAP_STALE) == 0);
win_release_pixmap(backend, w);
}
if (!win_check_flags_all(w, WIN_FLAGS_SHADOW_NONE)) {
assert(!win_check_flags_all(w, WIN_FLAGS_SHADOW_STALE));
if ((w->flags & WIN_FLAGS_SHADOW_NONE) == 0) {
assert((w->flags & WIN_FLAGS_SHADOW_STALE) == 0);
win_release_shadow(backend, w);
}
}
void win_process_flags(session_t *ps, struct managed_win *w) {
if (win_check_flags_all(w, WIN_FLAGS_MAPPED)) {
map_win_start(ps, w);
win_clear_flags(w, WIN_FLAGS_MAPPED);
// Make sure all pending window updates are processed before this. Making this
// assumption simplifies some checks (e.g. whether window is mapped)
assert(((struct managed_win_internal *)w)->pending_updates == 0);
if (!w->flags || (w->flags & WIN_FLAGS_IMAGE_ERROR) != 0) {
return;
}
// Not a loop
while (win_check_flags_any(w, WIN_FLAGS_IMAGES_STALE) &&
!win_check_flags_all(w, WIN_FLAGS_IMAGE_ERROR)) {
while ((w->flags & WIN_FLAGS_IMAGES_STALE) != 0) {
// Image needs to be updated, update it.
if (!ps->backend_data) {
// We are using legacy backend, nothing to do here.
break;
}
if (win_check_flags_all(w, WIN_FLAGS_PIXMAP_STALE)) {
if ((w->flags & WIN_FLAGS_PIXMAP_STALE) != 0) {
// Check to make sure the window is still mapped, otherwise we
// won't be able to rebind pixmap after releasing it, yet we might
// still need the pixmap for rendering.
assert(w->state != WSTATE_UNMAPPING && w->state != WSTATE_DESTROYING);
if (!win_check_flags_all(w, WIN_FLAGS_PIXMAP_NONE)) {
if ((w->flags & WIN_FLAGS_PIXMAP_NONE) == 0) {
// Must release images first, otherwise breaks
// NVIDIA driver
win_release_pixmap(ps->backend_data, w);
@ -348,8 +379,8 @@ void win_process_flags(session_t *ps, struct managed_win *w) {
win_bind_pixmap(ps->backend_data, w);
}
if (win_check_flags_all(w, WIN_FLAGS_SHADOW_STALE)) {
if (!win_check_flags_all(w, WIN_FLAGS_SHADOW_NONE)) {
if ((w->flags & WIN_FLAGS_SHADOW_STALE) != 0) {
if ((w->flags & WIN_FLAGS_SHADOW_NONE) == 0) {
win_release_shadow(ps->backend_data, w);
}
if (w->shadow) {
@ -367,14 +398,7 @@ void win_process_flags(session_t *ps, struct managed_win *w) {
}
// Clear stale image flags
if (win_check_flags_any(w, WIN_FLAGS_IMAGES_STALE)) {
win_clear_flags(w, WIN_FLAGS_IMAGES_STALE);
}
if (win_check_flags_all(w, WIN_FLAGS_CLIENT_STALE)) {
win_recheck_client(ps, w);
win_clear_flags(w, WIN_FLAGS_CLIENT_STALE);
}
w->flags &= ~WIN_FLAGS_IMAGES_STALE;
}
/**
@ -542,11 +566,15 @@ bool win_client_has_alpha(const struct managed_win *w) {
w->client_pictfmt->direct.alpha_mask;
}
winmode_t win_calc_mode(const struct managed_win *w) {
winmode_t win_calc_mode(session_t *ps, const struct managed_win *w) {
if (w->opacity < 1.0) {
return WMODE_TRANS;
}
if (ps->o.backend == BKEND_GLX && w->corner_radius > 0) {
return WMODE_TRANS;
}
if (win_has_alpha(w)) {
if (w->client_win == XCB_NONE) {
// This is a window not managed by the WM, and it has alpha,
@ -586,17 +614,18 @@ winmode_t win_calc_mode(const struct managed_win *w) {
*
* @param ps current session
* @param w struct _win object representing the window
* @param ignore_state whether window state should be ignored in opacity calculation
*
* @return target opacity
*/
double win_calc_opacity_target(session_t *ps, const struct managed_win *w) {
double win_calc_opacity_target(session_t *ps, const struct managed_win *w, bool ignore_state) {
double opacity = 1;
if (w->state == WSTATE_UNMAPPED) {
if (w->state == WSTATE_UNMAPPED && !ignore_state) {
// be consistent
return 0;
}
if (w->state == WSTATE_UNMAPPING || w->state == WSTATE_DESTROYING) {
if ((w->state == WSTATE_UNMAPPING || w->state == WSTATE_DESTROYING) && !ignore_state) {
return 0;
}
// Try obeying opacity property and window type opacity firstly
@ -697,7 +726,7 @@ static void win_set_shadow(session_t *ps, struct managed_win *w, bool shadow_new
w->shadow = shadow_new;
assert(!w->shadow_image);
assert(!w->win_image);
assert(win_check_flags_all(w, WIN_FLAGS_IMAGES_NONE));
//assert(w->flags & WIN_FLAGS_IMAGES_NONE);
return;
}
@ -723,14 +752,14 @@ static void win_set_shadow(session_t *ps, struct managed_win *w, bool shadow_new
// asserting the existence of the shadow image.
if (w->shadow) {
// Mark the new extents as damaged if the shadow is added
assert(!w->shadow_image || win_check_flags_all(w, WIN_FLAGS_SHADOW_STALE) ||
assert(!w->shadow_image || (w->flags & WIN_FLAGS_SHADOW_STALE) ||
!ps->o.experimental_backends);
pixman_region32_clear(&extents);
win_extents(w, &extents);
add_damage_from_win(ps, w);
} else {
// Mark the old extents as damaged if the shadow is removed
assert(w->shadow_image || win_check_flags_all(w, WIN_FLAGS_SHADOW_STALE) ||
assert(w->shadow_image || (w->flags & WIN_FLAGS_SHADOW_STALE) ||
!ps->o.experimental_backends);
add_damage(ps, &extents);
}
@ -740,7 +769,7 @@ static void win_set_shadow(session_t *ps, struct managed_win *w, bool shadow_new
// Delayed update of shadow image
// By setting WIN_FLAGS_SHADOW_STALE, we ask win_process_flags to re-create or
// release the shaodw in based on whether w->shadow is set.
win_set_flags(w, WIN_FLAGS_SHADOW_STALE);
w->flags |= WIN_FLAGS_SHADOW_STALE;
ps->pending_updates = true;
}
@ -878,6 +907,48 @@ static void win_determine_blur_background(session_t *ps, struct managed_win *w)
win_set_blur_background(ps, w, blur_background_new);
}
/**
* Determine if a window should have rounded corners.
*/
static void win_determine_rounded_corners(session_t *ps, struct managed_win *w) {
if (w->a.map_state != XCB_MAP_STATE_VIEWABLE /*|| ps->o.corner_radius == 0*/)
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)) {
w->corner_radius = 0;
//log_warn("xy(%d %d) wh(%d %d) will NOT round corners", w->g.x, w->g.y, w->widthb, w->heightb);
} else {
w->corner_radius = ps->o.corner_radius;
//log_warn("xy(%d %d) wh(%d %d) will round corners", w->g.x, w->g.y, w->widthb, w->heightb);
// HACK: we reset this so we can query the color once
// we query the color in glx_round_corners_dst0 using glReadPixels
//w->border_col = { -1., -1, -1, -1 };
w->border_col[0] = w->border_col[1] = w->border_col[2] = w->border_col[3] = -1.0;
// wintypes config section override
if (!safe_isnan(ps->o.wintype_option[w->window_type].corner_radius) &&
ps->o.wintype_option[w->window_type].corner_radius >= 0) {
w->corner_radius = ps->o.wintype_option[w->window_type].corner_radius;
//log_warn("xy(%d %d) wh(%d %d) wintypes:corner_radius: %d", w->g.x, w->g.y, w->widthb, w->heightb, w->corner_radius);
}
if (w && c2_match(ps, w, ps->o.round_borders_blacklist, NULL)) {
w->round_borders = 0;
} else {
w->round_borders = ps->o.round_borders;
// wintypes config section override
if (!safe_isnan(ps->o.wintype_option[w->window_type].round_borders) &&
ps->o.wintype_option[w->window_type].round_borders >= 0) {
w->round_borders = ps->o.wintype_option[w->window_type].round_borders;
//log_warn("wintypes:round_borders: %d", w->round_borders);
}
}
}
}
/**
* Update window opacity according to opacity rules.
*/
@ -904,7 +975,6 @@ void win_update_opacity_rule(session_t *ps, struct managed_win *w) {
* TODO need better name
*/
void win_on_factor_change(session_t *ps, struct managed_win *w) {
log_debug("Window %#010x (%s) factor change", w->base.id, w->name);
// Focus needs to be updated first, as other rules might depend on the focused
// state of the window
win_update_focused(ps, w);
@ -912,8 +982,7 @@ void win_on_factor_change(session_t *ps, struct managed_win *w) {
win_determine_shadow(ps, w);
win_determine_invert_color(ps, w);
win_determine_blur_background(ps, w);
w->mode = win_calc_mode(w);
log_debug("Window mode changed to %d", w->mode);
win_determine_rounded_corners(ps, w);
win_update_opacity_rule(ps, w);
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE)
w->paint_excluded = c2_match(ps, w, ps->o.paint_blacklist, NULL);
@ -921,7 +990,15 @@ void win_on_factor_change(session_t *ps, struct managed_win *w) {
w->unredir_if_possible_excluded =
c2_match(ps, w, ps->o.unredir_if_possible_blacklist, NULL);
win_update_opacity_target(ps, w);
auto opacity_target_old = w->opacity_target;
w->opacity_target = win_calc_opacity_target(ps, w, false);
if (opacity_target_old != w->opacity_target && w->state == WSTATE_MAPPED) {
// Only MAPPED can transition to FADING
w->state = WSTATE_FADING;
if (!ps->redirected) {
CHECK(!win_skip_fading(ps, w));
}
}
w->reg_ignore_valid = false;
}
@ -940,7 +1017,7 @@ void win_on_win_size_change(session_t *ps, struct managed_win *w) {
// Invalidate the shadow we built
if (w->state == WSTATE_MAPPED || w->state == WSTATE_MAPPING ||
w->state == WSTATE_FADING) {
win_set_flags(w, WIN_FLAGS_IMAGES_STALE);
w->flags |= WIN_FLAGS_IMAGES_STALE;
ps->pending_updates = true;
} else {
assert(w->state == WSTATE_UNMAPPED);
@ -1014,9 +1091,9 @@ void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client)
win_on_factor_change(ps, w);
auto r = xcb_get_window_attributes_reply(
ps->c, xcb_get_window_attributes(ps->c, w->client_win), &e);
ps->c, xcb_get_window_attributes(ps->c, w->client_win), NULL);
if (!r) {
log_error_x_error(e, "Failed to get client window attributes");
log_error("Failed to get client window attributes");
return;
}
@ -1032,8 +1109,6 @@ void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client)
*/
void win_unmark_client(session_t *ps, struct managed_win *w) {
xcb_window_t client = w->client_win;
log_debug("Detaching client window %#010x from frame %#010x (%s)", client,
w->base.id, w->name);
w->client_win = XCB_NONE;
@ -1043,42 +1118,13 @@ void win_unmark_client(session_t *ps, struct managed_win *w) {
(const uint32_t[]){determine_evmask(ps, client, WIN_EVMODE_UNKNOWN)});
}
/**
* Look for the client window of a particular window.
*/
static xcb_window_t find_client_win(session_t *ps, xcb_window_t w) {
if (wid_has_prop(ps, w, ps->atoms->aWM_STATE)) {
return w;
}
xcb_query_tree_reply_t *reply =
xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, w), NULL);
if (!reply)
return 0;
xcb_window_t *children = xcb_query_tree_children(reply);
int nchildren = xcb_query_tree_children_length(reply);
int i;
xcb_window_t ret = 0;
for (i = 0; i < nchildren; ++i) {
if ((ret = find_client_win(ps, children[i])))
break;
}
free(reply);
return ret;
}
/**
* Recheck client window of a window.
*
* @param ps current session
* @param w struct _win of the parent window
*/
void win_recheck_client(session_t *ps, struct managed_win *w) {
assert(ps->server_grabbed);
static void win_recheck_client(session_t *ps, struct managed_win *w) {
// Initialize wmwin to false
w->wmwin = false;
@ -1088,14 +1134,14 @@ void win_recheck_client(session_t *ps, struct managed_win *w) {
// sets override-redirect flags on all frame windows.
xcb_window_t cw = find_client_win(ps, w->base.id);
if (cw) {
log_debug("(%#010x): client %#010x", w->base.id, cw);
log_trace("(%#010x): client %#010x", w->base.id, cw);
}
// Set a window's client window to itself if we couldn't find a
// client window
if (!cw) {
cw = w->base.id;
w->wmwin = !w->a.override_redirect;
log_debug("(%#010x): client self (%s)", w->base.id,
log_trace("(%#010x): client self (%s)", w->base.id,
(w->wmwin ? "wmwin" : "override-redirected"));
}
@ -1191,10 +1237,10 @@ struct win *fill_win(session_t *ps, struct win *w) {
.invert_color = false,
.blur_background = false,
.oldX = -10000,
.oldY = -10000,
.oldW = 0,
.oldH = 0,
.oldX = -10000,
.oldY = -10000,
.oldW = 0,
.oldH = 0,
.reg_ignore = NULL,
// The following ones are updated for other reasons
@ -1262,6 +1308,8 @@ struct win *fill_win(session_t *ps, struct win *w) {
// Initialized during paint
.paint = PAINT_INIT,
.shadow_paint = PAINT_INIT,
.corner_radius = 0,
};
assert(!w->destroyed);
@ -1305,6 +1353,7 @@ struct win *fill_win(session_t *ps, struct win *w) {
// Allocate and initialize the new win structure
auto new_internal = cmalloc(struct managed_win_internal);
auto new = (struct managed_win *)new_internal;
new_internal->pending_updates = 0;
// Fill structure
// We only need to initialize the part that are not initialized
@ -1550,7 +1599,7 @@ void win_update_bounding_shape(session_t *ps, struct managed_win *w) {
pixman_region32_clear(&w->bounding_shape);
// Start with the window rectangular region
win_get_region_local(w, &w->bounding_shape);
win_get_region_local(w, &w->bounding_shape, true);
// Only request for a bounding region if the window is shaped
// (while loop is used to avoid goto, not an actual loop)
@ -1602,7 +1651,7 @@ void win_update_bounding_shape(session_t *ps, struct managed_win *w) {
// Note we only do this when screen is redirected, because
// otherwise win_data is not valid
assert(w->state != WSTATE_UNMAPPING && w->state != WSTATE_DESTROYING);
win_set_flags(w, WIN_FLAGS_IMAGES_STALE);
w->flags |= WIN_FLAGS_IMAGES_STALE;
ps->pending_updates = true;
}
free_paint(ps, &w->paint);
@ -1716,7 +1765,7 @@ static void unmap_win_finish(session_t *ps, struct managed_win *w) {
free_paint(ps, &w->shadow_paint);
// Try again at binding images when the window is mapped next time
win_clear_flags(w, WIN_FLAGS_IMAGE_ERROR);
w->flags &= ~WIN_FLAGS_IMAGE_ERROR;
}
/// Finish the destruction of a window (e.g. after fading has finished).
@ -1778,7 +1827,7 @@ static void destroy_win_finish(session_t *ps, struct win *w) {
static void map_win_finish(struct managed_win *w) {
w->in_openclose = false;
w->isOld = true;
w->isOld = true;
w->state = WSTATE_MAPPED;
}
@ -1890,15 +1939,14 @@ bool destroy_win_start(session_t *ps, struct win *w) {
}
if (w->managed) {
// Clear PIXMAP_STALE flag, since the window is destroyed there is no
// pixmap available so STALE doesn't make sense.
// Do this before changing the window state to destroying
win_clear_flags(mw, WIN_FLAGS_PIXMAP_STALE);
// Update state flags of a managed window
mw->state = WSTATE_DESTROYING;
mw->a.map_state = XCB_MAP_STATE_UNMAPPED;
mw->in_openclose = true;
// Clear PIXMAP_STALE flag, since the window is destroyed there is no
// pixmap available so STALE doesn't make sense.
mw->flags &= ~WIN_FLAGS_PIXMAP_STALE;
}
// don't need win_ev_stop because the window is gone anyway
@ -1918,6 +1966,7 @@ bool destroy_win_start(session_t *ps, struct win *w) {
}
void unmap_win_start(session_t *ps, struct managed_win *w) {
auto internal_w = (struct managed_win_internal *)w;
assert(w);
assert(w->base.managed);
assert(w->a._class != XCB_WINDOW_CLASS_INPUT_ONLY);
@ -1930,9 +1979,8 @@ void unmap_win_start(session_t *ps, struct managed_win *w) {
}
if (unlikely(w->state == WSTATE_UNMAPPING || w->state == WSTATE_UNMAPPED)) {
if (win_check_flags_all(w, WIN_FLAGS_MAPPED)) {
// Clear the pending map as this window is now unmapped
win_clear_flags(w, WIN_FLAGS_MAPPED);
if (internal_w->pending_updates & WIN_UPDATE_MAP) {
internal_w->pending_updates &= ~(unsigned long)WIN_UPDATE_MAP;
} else {
log_warn("Trying to unmapping an already unmapped window %#010x "
"\"%s\"",
@ -1947,12 +1995,11 @@ void unmap_win_start(session_t *ps, struct managed_win *w) {
w->a.map_state = XCB_MAP_STATE_UNMAPPED;
w->state = WSTATE_UNMAPPING;
w->opacity_target_old = fmax(w->opacity_target, w->opacity_target_old);
w->opacity_target = win_calc_opacity_target(ps, w);
w->opacity_target = win_calc_opacity_target(ps, w, false);
// Clear PIXMAP_STALE flag, since the window is unmapped there is no pixmap
// available so STALE doesn't make sense.
win_clear_flags(w, WIN_FLAGS_PIXMAP_STALE);
w->flags &= ~WIN_FLAGS_PIXMAP_STALE;
// don't care about properties anymore
win_ev_stop(ps, &w->base);
@ -2059,7 +2106,8 @@ void map_win_start(session_t *ps, struct managed_win *w) {
}
assert(w->state == WSTATE_UNMAPPED);
assert(win_check_flags_all(w, WIN_FLAGS_IMAGES_NONE) || !ps->o.experimental_backends);
assert((w->flags & WIN_FLAGS_IMAGES_NONE) == WIN_FLAGS_IMAGES_NONE ||
!ps->o.experimental_backends);
// We stopped processing window size change when we were unmapped, refresh the
// size of the window
@ -2087,13 +2135,14 @@ void map_win_start(session_t *ps, struct managed_win *w) {
// XXX Can we assume map_state is always viewable?
w->a.map_state = XCB_MAP_STATE_VIEWABLE;
if (!w->isOld) {
w->oldX = -1000;
w->oldY = -1000;
if (!w->isOld) {
w->oldX = -10000;
w->oldY = -10000;
w->oldW = 0;
w->oldH = 0;
}
win_update_screen(ps, w);
// Set window event mask before reading properties so that no property
@ -2108,7 +2157,7 @@ void map_win_start(session_t *ps, struct managed_win *w) {
}
// Update window mode here to check for ARGB windows
w->mode = win_calc_mode(w);
w->mode = win_calc_mode(ps, w);
// Detect client window here instead of in add_win() as the client
// window should have been prepared at this point
@ -2139,13 +2188,13 @@ void map_win_start(session_t *ps, struct managed_win *w) {
// XXX We need to make sure that win_data is available
// iff `state` is MAPPED
w->state = WSTATE_MAPPING;
w->opacity_target_old = 0;
w->opacity_target = win_calc_opacity_target(ps, w);
w->opacity_target = win_calc_opacity_target(ps, w, false);
log_debug("Window %#010x has opacity %f, opacity target is %f", w->base.id,
w->opacity, w->opacity_target);
win_determine_blur_background(ps, w);
win_determine_rounded_corners(ps, w);
// Cannot set w->ever_damaged = false here, since window mapping could be
// delayed, so a damage event might have already arrived before this function
@ -2161,7 +2210,7 @@ void map_win_start(session_t *ps, struct managed_win *w) {
// the window's image will be bound
win_update_bounding_shape(ps, w);
assert(win_check_flags_all(w, WIN_FLAGS_IMAGES_STALE));
assert((w->flags & WIN_FLAGS_IMAGES_STALE) == WIN_FLAGS_IMAGES_STALE);
#ifdef CONFIG_DBUS
// Send D-Bus signal
@ -2175,60 +2224,6 @@ void map_win_start(session_t *ps, struct managed_win *w) {
}
}
/**
* Update target window opacity depending on the current state.
*/
void win_update_opacity_target(session_t *ps, struct managed_win *w) {
auto opacity_target_old = w->opacity_target;
w->opacity_target = win_calc_opacity_target(ps, w);
if (opacity_target_old == w->opacity_target) {
return;
}
if (w->state == WSTATE_MAPPED) {
// Opacity target changed while MAPPED. Transition to FADING.
assert(w->opacity == opacity_target_old);
w->opacity_target_old = opacity_target_old;
w->state = WSTATE_FADING;
log_debug("Window %#010x (%s) opacity %f, opacity target %f, set "
"old target %f",
w->base.id, w->name, w->opacity, w->opacity_target,
w->opacity_target_old);
} else if (w->state == WSTATE_MAPPING) {
// Opacity target changed while fading in.
if (w->opacity >= w->opacity_target) {
// Already reached new target opacity. Transition to
// FADING.
map_win_finish(w);
w->opacity_target_old = fmax(opacity_target_old, w->opacity);
w->state = WSTATE_FADING;
log_debug("Window %#010x (%s) opacity %f already reached "
"new opacity target %f while mapping, set old "
"target %f",
w->base.id, w->name, w->opacity, w->opacity_target,
w->opacity_target_old);
}
} else if (w->state == WSTATE_FADING) {
// Opacity target changed while FADING.
if ((w->opacity < opacity_target_old && w->opacity > w->opacity_target) ||
(w->opacity > opacity_target_old && w->opacity < w->opacity_target)) {
// Changed while fading in and will fade out or while
// fading out and will fade in.
w->opacity_target_old = opacity_target_old;
log_debug("Window %#010x (%s) opacity %f already reached "
"new opacity target %f while fading, set "
"old target %f",
w->base.id, w->name, w->opacity, w->opacity_target,
w->opacity_target_old);
}
}
if (!ps->redirected) {
CHECK(!win_skip_fading(ps, w));
}
}
/**
* Find a managed window from window id in window linked list of the session.
*/
@ -2284,13 +2279,13 @@ struct managed_win *find_toplevel(session_t *ps, xcb_window_t id) {
}
/**
* Find a managed window that is, or is a parent of `wid`.
* Find out the WM frame of a client window by querying X.
*
* @param ps current session
* @param wid window ID
* @return struct _win object of the found window, NULL if not found
*/
struct managed_win *find_managed_window_or_parent(session_t *ps, xcb_window_t wid) {
struct managed_win *find_toplevel2(session_t *ps, xcb_window_t wid) {
// TODO this should probably be an "update tree", then find_toplevel.
// current approach is a bit more "racy"
struct win *w = NULL;
@ -2351,35 +2346,31 @@ win_is_fullscreen_xcb(xcb_connection_t *c, const struct atom *a, const xcb_windo
return false;
}
/// Set flags on a window. Some sanity checks are performed
void win_set_flags(struct managed_win *w, uint64_t flags) {
log_debug("Set flags %lu to window %#010x (%s)", flags, w->base.id, w->name);
if (unlikely(w->state == WSTATE_DESTROYING)) {
log_error("Flags set on a destroyed window %#010x (%s)", w->base.id, w->name);
/// Queue an update on a window. A series of sanity checks are performed
void win_queue_update(struct managed_win *_w, enum win_update update) {
auto w = (struct managed_win_internal *)_w;
assert(popcount(update) == 1);
assert(update == WIN_UPDATE_MAP); // Currently the only supported update
if (unlikely(_w->state == WSTATE_DESTROYING)) {
log_error("Updates queued on a destroyed window %#010x (%s)", _w->base.id,
_w->name);
return;
}
w->flags |= flags;
w->pending_updates |= update;
}
/// Clear flags on a window. Some sanity checks are performed
void win_clear_flags(struct managed_win *w, uint64_t flags) {
log_debug("Clear flags %lu from window %#010x (%s)", flags, w->base.id, w->name);
if (unlikely(w->state == WSTATE_DESTROYING)) {
log_warn("Flags cleared on a destroyed window %#010x (%s)", w->base.id,
w->name);
return;
/// Process pending updates on a window. Has to be called in X critical section
void win_process_updates(struct session *ps, struct managed_win *_w) {
assert(ps->server_grabbed);
auto w = (struct managed_win_internal *)_w;
if (w->pending_updates & WIN_UPDATE_MAP) {
map_win_start(ps, _w);
}
w->flags = w->flags & (~flags);
}
bool win_check_flags_any(struct managed_win *w, uint64_t flags) {
return (w->flags & flags) != 0;
}
bool win_check_flags_all(struct managed_win *w, uint64_t flags) {
return (w->flags & flags) == flags;
w->pending_updates = 0;
}
/**
@ -2435,6 +2426,7 @@ win_stack_find_next_managed(const session_t *ps, const struct list_node *i) {
/// Return whether this window is mapped on the X server side
bool win_is_mapped_in_x(const struct managed_win *w) {
auto iw = (const struct managed_win_internal *)w;
return w->state == WSTATE_MAPPING || w->state == WSTATE_FADING ||
w->state == WSTATE_MAPPED || (w->flags & WIN_FLAGS_MAPPED);
w->state == WSTATE_MAPPED || (iw->pending_updates & WIN_UPDATE_MAP);
}

View File

@ -40,13 +40,13 @@ typedef struct _glx_texture glx_texture_t;
// it is very unideal for it to be here
typedef struct {
/// Framebuffer used for blurring.
GLuint fbo;
GLuint fbos[MAX_BLUR_PASS];
/// Textures used for blurring.
GLuint textures[2];
GLuint textures[MAX_BLUR_PASS];
/// Width of the textures.
int width;
int width[MAX_BLUR_PASS];
/// Height of the textures.
int height;
int height[MAX_BLUR_PASS];
} glx_blur_cache_t;
#endif
@ -131,7 +131,7 @@ struct managed_win {
/// See above about coordinate systems.
region_t bounding_shape;
/// Window flags. Definitions above.
uint64_t flags;
int_fast16_t flags;
/// The region of screen that will be obscured when windows above is painted,
/// in global coordinates.
/// We use this to reduce the pixels that needed to be paint when painting
@ -192,8 +192,6 @@ struct managed_win {
double opacity;
/// Target window opacity.
double opacity_target;
/// Previous window opacity.
double opacity_target_old;
/// true if window (or client window, for broken window managers
/// not transferring client window's _NET_WM_OPACITY value) has opacity prop
bool has_opacity_prop;
@ -204,6 +202,11 @@ struct managed_win {
/// Last window opacity value set by the rules.
double opacity_set;
/// Corner radius
int corner_radius;
bool round_borders;
float border_col[4];
// Fading-related members
/// Override value of window fade state. Set by D-Bus method calls.
switch_t fade_force;
@ -248,21 +251,29 @@ struct managed_win {
/// Whether to blur window background.
bool blur_background;
/// Animation state
int oldX; int oldY; int oldW; int oldH;
int newX; int newY; int newW; int newH;
float moveTimeX; float moveTimeY;
float moveTimeW; float moveTimeH;
bool isOld;
/// Animation state
int oldX; int oldY; int oldW; int oldH;
int newX; int newY; int newW; int newH;
float moveTimeX; float moveTimeY;
float moveTimeW; float moveTimeH;
bool isOld;
#ifdef CONFIG_OPENGL
/// Textures and FBO background blur use.
glx_blur_cache_t glx_blur_cache;
glx_blur_cache_t glx_round_cache;
/// Background texture of the window
glx_texture_t *glx_texture_bg;
#endif
};
/// Process pending updates on a window. Has to be called in X critical section
void win_process_updates(struct session *ps, struct managed_win *_w);
/// Process pending images flags on a window. Has to be called in X critical section
void win_process_flags(session_t *ps, struct managed_win *w);
/// Queue an update on a window. A series of sanity checks are performed
void win_queue_update(struct managed_win *_w, enum win_update update);
/// Bind a shadow to the window, with color `c` and shadow kernel `kernel`
bool win_bind_shadow(struct backend_base *b, struct managed_win *w, struct color c,
struct conv *kernel);
@ -284,7 +295,7 @@ bool must_use destroy_win_start(session_t *ps, struct win *w);
void win_release_images(struct backend_base *base, struct managed_win *w);
int win_update_name(session_t *ps, struct managed_win *w);
int win_get_role(session_t *ps, struct managed_win *w);
winmode_t attr_pure win_calc_mode(const struct managed_win *w);
winmode_t attr_pure win_calc_mode(session_t *ps, const struct managed_win *w);
void win_set_shadow_force(session_t *ps, struct managed_win *w, switch_t val);
void win_set_fade_force(struct managed_win *w, switch_t val);
void win_set_focused_force(session_t *ps, struct managed_win *w, switch_t val);
@ -296,7 +307,6 @@ void win_set_focused(session_t *ps, struct managed_win *w);
bool attr_pure win_should_fade(session_t *ps, const struct managed_win *w);
void win_update_prop_shadow_raw(session_t *ps, struct managed_win *w);
void win_update_prop_shadow(session_t *ps, struct managed_win *w);
void win_update_opacity_target(session_t *ps, struct managed_win *w);
void win_on_factor_change(session_t *ps, struct managed_win *w);
/**
* Update cache data in struct _win that depends on window size.
@ -305,7 +315,6 @@ void win_on_win_size_change(session_t *ps, struct managed_win *w);
void win_update_wintype(session_t *ps, struct managed_win *w);
void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client);
void win_unmark_client(session_t *ps, struct managed_win *w);
void win_recheck_client(session_t *ps, struct managed_win *w);
bool win_get_class(session_t *ps, struct managed_win *w);
/**
@ -318,10 +327,12 @@ bool win_get_class(session_t *ps, struct managed_win *w);
*
* @param ps current session
* @param w struct _win object representing the window
* @param ignore_state whether window state should be ignored in opacity calculation
*
* @return target opacity
*/
double attr_pure win_calc_opacity_target(session_t *ps, const struct managed_win *w);
double attr_pure win_calc_opacity_target(session_t *ps, const struct managed_win *w,
bool ignore_state);
bool attr_pure win_should_dim(session_t *ps, const struct managed_win *w);
void win_update_screen(session_t *, struct managed_win *);
/**
@ -362,12 +373,12 @@ void add_damage_from_win(session_t *ps, const struct managed_win *w);
*
* Return region in global coordinates.
*/
void win_get_region_noframe_local(const struct managed_win *w, region_t *);
void win_get_region_noframe_local(const struct managed_win *w, region_t *, bool include_corners);
/// Get the region for the frame of the window
void win_get_region_frame_local(const struct managed_win *w, region_t *res);
void win_get_region_frame_local(const struct managed_win *w, region_t *res, bool include_corners);
/// Get the region for the frame of the window, by value
region_t win_get_region_frame_local_by_val(const struct managed_win *w);
region_t win_get_region_frame_local_by_val(const struct managed_win *w, bool include_corners);
/**
* Retrieve frame extents from a window.
*/
@ -407,13 +418,13 @@ struct managed_win *find_managed_win(session_t *ps, xcb_window_t id);
struct win *find_win(session_t *ps, xcb_window_t id);
struct managed_win *find_toplevel(session_t *ps, xcb_window_t id);
/**
* Find a managed window that is, or is a parent of `wid`.
* Find out the WM frame of a client window by querying X.
*
* @param ps current session
* @param wid window ID
* @return struct _win object of the found window, NULL if not found
*/
struct managed_win *find_managed_window_or_parent(session_t *ps, xcb_window_t wid);
struct managed_win *find_toplevel2(session_t *ps, xcb_window_t wid);
/**
* Check if a window is a fullscreen window.
@ -439,22 +450,29 @@ bool win_is_mapped_in_x(const struct managed_win *w);
// Find the managed window immediately below `w` in the window stack
struct managed_win *attr_pure win_stack_find_next_managed(const session_t *ps,
const struct list_node *w);
/// Set flags on a window. Some sanity checks are performed
void win_set_flags(struct managed_win *w, uint64_t flags);
/// Clear flags on a window. Some sanity checks are performed
void win_clear_flags(struct managed_win *w, uint64_t flags);
/// Returns true if any of the flags in `flags` is set
bool win_check_flags_any(struct managed_win *w, uint64_t flags);
/// Returns true if all of the flags in `flags` are set
bool win_check_flags_all(struct managed_win *w, uint64_t flags);
/// Free all resources in a struct win
void free_win_res(session_t *ps, struct managed_win *w);
static inline region_t win_get_bounding_shape_global_by_val(struct managed_win *w) {
static inline void win_region_remove_corners(const struct managed_win *w, region_t *res) {
region_t corners;
pixman_region32_init_rects(
&corners,
(rect_t[]){
{.x1 = 0, .y1 = 0, .x2 = w->corner_radius, .y2 = w->corner_radius},
{.x1 = 0, .y1 = w->heightb-w->corner_radius, .x2 = w->corner_radius, .y2 = w->heightb},
{.x1 = w->widthb-w->corner_radius, .y1 = 0, .x2 = w->widthb, .y2 = w->corner_radius},
{.x1 = w->widthb-w->corner_radius, .y1 = w->heightb-w->corner_radius, .x2 = w->widthb, .y2 = w->heightb},
},
4);
pixman_region32_subtract(res, res, &corners);
}
static inline region_t win_get_bounding_shape_global_by_val(struct managed_win *w, bool include_corners) {
region_t ret;
pixman_region32_init(&ret);
pixman_region32_copy(&ret, &w->bounding_shape);
if(!include_corners) win_region_remove_corners(w, &ret);
pixman_region32_translate(&ret, w->g.x, w->g.y);
return ret;
}

View File

@ -27,6 +27,11 @@ typedef enum {
WMODE_SOLID, // The window is opaque including the frame
} winmode_t;
/// Pending window updates
enum win_update {
WIN_UPDATE_MAP = 1,
};
/// Transition table:
/// (DESTROYED is when the win struct is destroyed and freed)
/// ('o' means in all other cases)
@ -40,8 +45,8 @@ typedef enum {
/// | DESTROYING | - | o | - | - | - | - | Fading |
/// | | | | | | | |finished |
/// +-------------+---------+----------+-------+-------+--------+--------+---------+
/// | MAPPING | Window | Window | o |Opacity| - | Fading | - |
/// | |unmapped |destroyed | |change | |finished| |
/// | MAPPING | Window | Window | o | - | - | Fading | - |
/// | |unmapped |destroyed | | | |finished| |
/// +-------------+---------+----------+-------+-------+--------+--------+---------+
/// | FADING | Window | Window | - | o | - | Fading | - |
/// | |unmapped |destroyed | | | |finished| |
@ -81,13 +86,9 @@ enum win_flags {
WIN_FLAGS_SHADOW_STALE = 8,
/// shadow has not been generated
WIN_FLAGS_SHADOW_NONE = 16,
/// the client window needs to be updated
WIN_FLAGS_CLIENT_STALE = 32,
/// the window is mapped by X, we need to call map_win_start for it
WIN_FLAGS_MAPPED = 64,
};
static const uint64_t WIN_FLAGS_IMAGES_STALE =
static const int_fast16_t WIN_FLAGS_IMAGES_STALE =
WIN_FLAGS_PIXMAP_STALE | WIN_FLAGS_SHADOW_STALE;
#define WIN_FLAGS_IMAGES_NONE (WIN_FLAGS_PIXMAP_NONE | WIN_FLAGS_SHADOW_NONE)

107
src/x.c
View File

@ -7,7 +7,6 @@
#include <pixman.h>
#include <xcb/composite.h>
#include <xcb/damage.h>
#include <xcb/glx.h>
#include <xcb/render.h>
#include <xcb/sync.h>
#include <xcb/xcb.h>
@ -168,6 +167,15 @@ xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_
return x_get_visual_for_pictfmt(g_pictfmts, pictfmt->id);
}
xcb_render_pictformat_t
x_get_pictfmt_for_standard(xcb_connection_t *c, xcb_pict_standard_t std) {
x_get_server_pictfmts(c);
auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, std);
return pictfmt->id;
}
int x_get_visual_depth(xcb_connection_t *c, xcb_visualid_t visual) {
auto setup = xcb_get_setup(c);
for (auto screen = xcb_setup_roots_iterator(setup); screen.rem;
@ -231,6 +239,17 @@ x_create_picture_with_standard_and_pixmap(xcb_connection_t *c, xcb_pict_standard
return x_create_picture_with_pictfmt_and_pixmap(c, pictfmt, pixmap, valuemask, attr);
}
xcb_render_picture_t
x_create_picture_with_standard(xcb_connection_t *c, xcb_drawable_t d, int w, int h,
xcb_pict_standard_t standard, uint32_t valuemask,
const xcb_render_create_picture_value_list_t *attr) {
x_get_server_pictfmts(c);
auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, standard);
assert(pictfmt);
return x_create_picture_with_pictfmt(c, d, w, h, pictfmt, valuemask, attr);
}
/**
* Create an picture.
*/
@ -338,80 +357,69 @@ _x_strerror(unsigned long serial, uint8_t major, uint16_t minor, uint8_t error_c
int o = 0;
const char *name = "Unknown";
#define CASESTRRET(s) \
case s: \
name = #s; \
break
#define CASESTRRET2(s) \
case XCB_##s: name = #s; break
case s: name = #s; break
// TODO separate error code out from session_t
o = error_code - ps->xfixes_error;
switch (o) { CASESTRRET2(XFIXES_BAD_REGION); }
switch (o) { CASESTRRET2(XCB_XFIXES_BAD_REGION); }
o = error_code - ps->damage_error;
switch (o) { CASESTRRET2(DAMAGE_BAD_DAMAGE); }
switch (o) { CASESTRRET2(XCB_DAMAGE_BAD_DAMAGE); }
o = error_code - ps->render_error;
switch (o) {
CASESTRRET2(RENDER_PICT_FORMAT);
CASESTRRET2(RENDER_PICTURE);
CASESTRRET2(RENDER_PICT_OP);
CASESTRRET2(RENDER_GLYPH_SET);
CASESTRRET2(RENDER_GLYPH);
CASESTRRET2(XCB_RENDER_PICT_FORMAT);
CASESTRRET2(XCB_RENDER_PICTURE);
CASESTRRET2(XCB_RENDER_PICT_OP);
CASESTRRET2(XCB_RENDER_GLYPH_SET);
CASESTRRET2(XCB_RENDER_GLYPH);
}
#ifdef CONFIG_OPENGL
if (ps->glx_exists) {
o = error_code - ps->glx_error;
switch (o) {
CASESTRRET2(GLX_BAD_SCREEN);
CASESTRRET2(GLX_BAD_ATTRIBUTE);
CASESTRRET2(GLX_NO_EXTENSION);
CASESTRRET2(GLX_BAD_VISUAL);
CASESTRRET2(GLX_BAD_CONTEXT);
CASESTRRET2(GLX_BAD_CONTEXT_STATE);
CASESTRRET2(GLX_BAD_DRAWABLE);
CASESTRRET2(GLX_BAD_PIXMAP);
CASESTRRET2(GLX_BAD_CONTEXT_TAG);
CASESTRRET2(GLX_BAD_CURRENT_WINDOW);
CASESTRRET2(GLX_BAD_RENDER_REQUEST);
CASESTRRET2(GLX_BAD_LARGE_REQUEST);
CASESTRRET2(GLX_UNSUPPORTED_PRIVATE_REQUEST);
CASESTRRET2(GLX_BAD_FB_CONFIG);
CASESTRRET2(GLX_BAD_PBUFFER);
CASESTRRET2(GLX_BAD_CURRENT_DRAWABLE);
CASESTRRET2(GLX_BAD_WINDOW);
CASESTRRET2(GLX_GLX_BAD_PROFILE_ARB);
CASESTRRET2(GLX_BAD_VALUE);
CASESTRRET2(GLX_BAD_ENUM);
}
}
#endif
if (ps->xsync_exists) {
o = error_code - ps->xsync_error;
switch (o) {
CASESTRRET(XSyncBadCounter);
CASESTRRET(XSyncBadAlarm);
CASESTRRET(XSyncBadFence);
CASESTRRET2(XSyncBadCounter);
CASESTRRET2(XSyncBadAlarm);
CASESTRRET2(XSyncBadFence);
}
}
switch (error_code) {
CASESTRRET2(ACCESS);
CASESTRRET2(ALLOC);
CASESTRRET2(ATOM);
CASESTRRET2(COLORMAP);
CASESTRRET2(CURSOR);
CASESTRRET2(DRAWABLE);
CASESTRRET2(FONT);
CASESTRRET2(G_CONTEXT);
CASESTRRET2(ID_CHOICE);
CASESTRRET2(IMPLEMENTATION);
CASESTRRET2(LENGTH);
CASESTRRET2(MATCH);
CASESTRRET2(NAME);
CASESTRRET2(PIXMAP);
CASESTRRET2(REQUEST);
CASESTRRET2(VALUE);
CASESTRRET2(WINDOW);
CASESTRRET2(BadAccess);
CASESTRRET2(BadAlloc);
CASESTRRET2(BadAtom);
CASESTRRET2(BadColor);
CASESTRRET2(BadCursor);
CASESTRRET2(BadDrawable);
CASESTRRET2(BadFont);
CASESTRRET2(BadGC);
CASESTRRET2(BadIDChoice);
CASESTRRET2(BadImplementation);
CASESTRRET2(BadLength);
CASESTRRET2(BadMatch);
CASESTRRET2(BadName);
CASESTRRET2(BadPixmap);
CASESTRRET2(BadRequest);
CASESTRRET2(BadValue);
CASESTRRET2(BadWindow);
}
#undef CASESTRRET
#undef CASESTRRET2
thread_local static char buffer[256];
@ -434,9 +442,6 @@ void x_print_error(unsigned long serial, uint8_t major, uint16_t minor, uint8_t
* for multiple calls to this function,
*/
const char *x_strerror(xcb_generic_error_t *e) {
if (!e) {
return "No error";
}
return _x_strerror(e->full_sequence, e->major_code, e->minor_code, e->error_code);
}

View File

@ -172,6 +172,12 @@ x_create_picture_with_standard_and_pixmap(xcb_connection_t *, xcb_pict_standard_
const xcb_render_create_picture_value_list_t *attr)
attr_nonnull(1);
xcb_render_picture_t
x_create_picture_with_standard(xcb_connection_t *c, xcb_drawable_t d, int w, int h,
xcb_pict_standard_t standard, uint32_t valuemask,
const xcb_render_create_picture_value_list_t *attr)
attr_nonnull(1);
/**
* Create an picture.
*/
@ -261,6 +267,8 @@ struct xvisual_info x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual
xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_t std);
xcb_render_pictformat_t 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);
uint32_t attr_deprecated xcb_generate_id(xcb_connection_t *c);

View File

@ -1,6 +0,0 @@
fading = true
fade-in-step = 0.01
fade-out-step = 0.01
inactive-opacity = 0
blur-background = true
force-win-blend = true

View File

@ -1,3 +0,0 @@
fading = true;
fade-in-step = 1;
fade-out-step = 0.01;

View File

@ -7,7 +7,7 @@ fi
echo "Running test $2"
# TODO keep the log file, and parse it to see if test is successful
($1 --dbus --experimental-backends --backend dummy --log-level=debug --log-file=$PWD/log --config=$2) &
($1 --experimental-backends --backend dummy --log-level=debug --log-file=$PWD/log --config=$2) &
main_pid=$!
$3

View File

@ -3,15 +3,8 @@ set -e
exe=$(realpath $1)
cd $(dirname $0)
eval `dbus-launch --sh-syntax`
./run_one_test.sh $exe configs/empty.conf testcases/basic.py
./run_one_test.sh $exe configs/issue357.conf testcases/issue357.py
./run_one_test.sh $exe configs/issue239.conf testcases/issue239.py
./run_one_test.sh $exe configs/issue239_2.conf testcases/issue239_2.py
./run_one_test.sh $exe configs/issue239_3.conf testcases/issue239_3.py
./run_one_test.sh $exe configs/issue239_3.conf testcases/issue239_3_norefresh.py
./run_one_test.sh $exe configs/issue314.conf testcases/issue314.py
./run_one_test.sh $exe configs/issue314.conf testcases/issue314_2.py
./run_one_test.sh $exe configs/issue314.conf testcases/issue314_3.py
./run_one_test.sh $exe /dev/null testcases/issue299.py

View File

@ -1,35 +1,18 @@
import xcffib.xproto as xproto
import xcffib.randr as randr
import xcffib
import time
import random
import string
def to_atom(conn, string):
return conn.core.InternAtom(False, len(string), string).reply().atom
def set_window_name(conn, wid, name):
prop_name = to_atom(conn, "_NET_WM_NAME")
str_type = to_atom(conn, "UTF8_STRING")
conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid, prop_name, str_type, 8, len(name), name).check()
prop_name = to_atom(conn, "WM_NAME")
str_type = to_atom(conn, "STRING")
conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid, prop_name, str_type, 8, len(name), name).check()
def set_window_state(conn, wid, state):
prop_name = to_atom(conn, "WM_STATE")
conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid, prop_name, prop_name, 32, 2, [state, 0]).check()
def set_window_class(conn, wid, name):
if not isinstance(name, bytearray):
name = name.encode()
name = name+b"\0"+name+b"\0"
prop_name = to_atom(conn, "WM_CLASS")
str_type = to_atom(conn, "STRING")
prop_name = "_NET_WM_NAME"
prop_name = conn.core.InternAtom(True, len(prop_name), prop_name).reply().atom
str_type = "STRING"
str_type = conn.core.InternAtom(True, len(str_type), str_type).reply().atom
conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid, prop_name, str_type, 8, len(name), name).check()
def find_picom_window(conn):
prop_name = to_atom(conn, "WM_NAME")
prop_name = "WM_NAME"
prop_name = conn.core.InternAtom(True, len(prop_name), prop_name).reply().atom
setup = conn.get_setup()
root = setup.roots[0].root
windows = conn.core.QueryTree(root).reply()
@ -58,19 +41,3 @@ def trigger_root_configure(conn):
rr.AddOutputModeChecked(output, mode).check()
rr.SetCrtcConfig(reply.crtcs[0], reply.timestamp, reply.config_timestamp, 0, 0, mode, randr.Rotation.Rotate_0, 1, [output]).reply()
def find_32bit_visual(conn):
setup = conn.get_setup()
render = conn(xcffib.render.key)
r = render.QueryPictFormats().reply()
pictfmt_ids = set()
for pictform in r.formats:
if (pictform.depth == 32 and
pictform.type == xcffib.render.PictType.Direct and
pictform.direct.alpha_mask != 0):
pictfmt_ids.add(pictform.id)
print(pictfmt_ids)
for screen in r.screens:
for depth in screen.depths:
for pv in depth.visuals:
if pv.format in pictfmt_ids:
return pv.visual

View File

@ -1,112 +0,0 @@
#!/usr/bin/env python3
import xcffib.xproto as xproto
import xcffib
import time
import os
import subprocess
import asyncio
from dbus_next.aio import MessageBus
from dbus_next.message import Message, MessageType
from common import *
display = os.environ["DISPLAY"].replace(":", "_")
conn = xcffib.connect()
setup = conn.get_setup()
root = setup.roots[0].root
visual = setup.roots[0].root_visual
depth = setup.roots[0].root_depth
x = xproto.xprotoExtension(conn)
visual32 = find_32bit_visual(conn)
async def get_client_win_async(wid):
message = await bus.call(Message(destination='com.github.chjj.compton.'+display,
path='/',
interface='com.github.chjj.compton',
member='win_get',
signature='us',
body=[wid, 'client_win']))
return message.body[0]
def get_client_win(wid):
return loop.run_until_complete(get_client_win_async(wid))
def wait():
time.sleep(0.5)
def create_client_window(name):
client_win = conn.generate_id()
print("Window : ", hex(client_win))
conn.core.CreateWindowChecked(depth, client_win, root, 0, 0, 100, 100, 0,
xproto.WindowClass.InputOutput, visual, 0, []).check()
set_window_name(conn, client_win, "Test window "+name)
set_window_class(conn, client_win, "Test windows")
set_window_state(conn, client_win, 1)
conn.core.MapWindowChecked(client_win).check()
return client_win
loop = asyncio.get_event_loop()
bus = loop.run_until_complete(MessageBus().connect())
cmid = conn.generate_id()
colormap = conn.core.CreateColormapChecked(xproto.ColormapAlloc._None, cmid, root, visual32).check()
# Create window
client_wins = []
for i in range(0,2):
client_wins.append(create_client_window(str(i)))
# Create frame window
frame_win = conn.generate_id()
print("Window : ", hex(frame_win))
conn.core.CreateWindowChecked(depth, frame_win, root, 0, 0, 200, 200, 0,
xproto.WindowClass.InputOutput, visual, 0, []).check()
set_window_name(conn, frame_win, "Frame")
conn.core.MapWindowChecked(frame_win).check()
# Scenario 1.1
# 1. reparent placeholder to frame
conn.core.ReparentWindowChecked(client_wins[0], frame_win, 0, 0).check()
wait()
# 2. reparent real client to frame
conn.core.ReparentWindowChecked(client_wins[1], frame_win, 0, 0).check()
wait()
# 3. detach the placeholder
conn.core.ReparentWindowChecked(client_wins[0], root, 0, 0).check()
wait()
assert get_client_win(frame_win) == client_wins[1]
# Scenario 1.2
# 1. reparent placeholder to frame
conn.core.ReparentWindowChecked(client_wins[0], frame_win, 0, 0).check()
wait()
# 2. reparent real client to frame
conn.core.ReparentWindowChecked(client_wins[1], frame_win, 0, 0).check()
wait()
# 3. destroy the placeholder
conn.core.DestroyWindowChecked(client_wins[0]).check()
wait()
assert get_client_win(frame_win) == client_wins[1]
client_wins[0] = create_client_window("0")
# Scenario 2
# 1. frame is unmapped
conn.core.UnmapWindowChecked(frame_win).check()
wait()
# 2. reparent placeholder to frame
conn.core.ReparentWindowChecked(client_wins[0], frame_win, 0, 0).check()
wait()
# 3. destroy placeholder, map frame and reparent real client to frame
conn.core.DestroyWindowChecked(client_wins[0]).check()
conn.core.MapWindowChecked(frame_win).check()
conn.core.ReparentWindowChecked(client_wins[1], frame_win, 0, 0).check()
wait()
assert get_client_win(frame_win) == client_wins[1]
client_wins[0] = create_client_window("0")
# Destroy the windows
for wid in client_wins:
conn.core.DestroyWindowChecked(wid).check()
conn.core.DestroyWindowChecked(frame_win).check()

View File

@ -1,44 +0,0 @@
#!/usr/bin/env python
import xcffib.xproto as xproto
import xcffib
import time
from common import set_window_name, trigger_root_configure
conn = xcffib.connect()
setup = conn.get_setup()
root = setup.roots[0].root
visual = setup.roots[0].root_visual
depth = setup.roots[0].root_depth
x = xproto.xprotoExtension(conn)
# issue 314 is caused by changing a windows target opacity during its fade-in/-out transition
wid1 = conn.generate_id()
print("Window 1: ", hex(wid1))
wid2 = conn.generate_id()
print("Window 2: ", hex(wid2))
# Create windows
conn.core.CreateWindowChecked(depth, wid1, root, 0, 0, 100, 100, 0, xproto.WindowClass.InputOutput, visual, 0, []).check()
conn.core.CreateWindowChecked(depth, wid2, root, 0, 0, 100, 100, 0, xproto.WindowClass.InputOutput, visual, 0, []).check()
# Set Window names
set_window_name(conn, wid1, "Test window 1")
set_window_name(conn, wid2, "Test window 2")
# Check updating opacity while UNMAPPING/DESTROYING windows
print("Mapping 1")
conn.core.MapWindowChecked(wid1).check()
print("Mapping 2")
conn.core.MapWindowChecked(wid2).check()
time.sleep(0.5)
x.SetInputFocusChecked(0, wid1, xproto.Time.CurrentTime).check()
time.sleep(0.5)
# Destroy the windows
print("Destroy 1 while fading out")
conn.core.DestroyWindowChecked(wid1).check()
x.SetInputFocusChecked(0, wid2, xproto.Time.CurrentTime).check()
time.sleep(1)
conn.core.DestroyWindowChecked(wid2).check()

View File

@ -1,46 +0,0 @@
#!/usr/bin/env python
import xcffib.xproto as xproto
import xcffib
import time
from common import set_window_name, trigger_root_configure
conn = xcffib.connect()
setup = conn.get_setup()
root = setup.roots[0].root
visual = setup.roots[0].root_visual
depth = setup.roots[0].root_depth
x = xproto.xprotoExtension(conn)
opacity_80 = [int(0xffffffff * 0.8), ]
opacity_single = [int(0xffffffff * 0.002), ]
# issue 314 is caused by changing a windows target opacity during its fade-in/-out transition
wid1 = conn.generate_id()
print("Window 1: ", hex(wid1))
atom = "_NET_WM_WINDOW_OPACITY"
opacity_atom = conn.core.InternAtom(False, len(atom), atom).reply().atom
# Create windows
conn.core.CreateWindowChecked(depth, wid1, root, 0, 0, 100, 100, 0, xproto.WindowClass.InputOutput, visual, 0, []).check()
# Set Window names
set_window_name(conn, wid1, "Test window 1")
# Check updating opacity while MAPPING windows
print("Mapping window")
conn.core.MapWindowChecked(wid1).check()
time.sleep(0.5)
print("Update opacity while fading in")
conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid1, opacity_atom, xproto.Atom.CARDINAL, 32, 1, opacity_80).check()
time.sleep(0.2)
conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid1, opacity_atom, xproto.Atom.CARDINAL, 32, 1, opacity_single).check()
time.sleep(1)
conn.core.DeletePropertyChecked(wid1, opacity_atom).check()
time.sleep(0.5)
# Destroy the windows
conn.core.DestroyWindowChecked(wid1).check()

View File

@ -1,63 +0,0 @@
#!/usr/bin/env python
import xcffib.xproto as xproto
import xcffib
import time
from common import set_window_name, trigger_root_configure
conn = xcffib.connect()
setup = conn.get_setup()
root = setup.roots[0].root
visual = setup.roots[0].root_visual
depth = setup.roots[0].root_depth
x = xproto.xprotoExtension(conn)
opacity_100 = [0xffffffff, ]
opacity_80 = [int(0xffffffff * 0.8), ]
opacity_single = [int(0xffffffff * 0.002), ]
opacity_0 = [0, ]
# issue 314 is caused by changing a windows target opacity during its fade-in/-out transition
wid1 = conn.generate_id()
print("Window 1: ", hex(wid1))
atom = "_NET_WM_WINDOW_OPACITY"
opacity_atom = conn.core.InternAtom(False, len(atom), atom).reply().atom
# Create windows
conn.core.CreateWindowChecked(depth, wid1, root, 0, 0, 100, 100, 0, xproto.WindowClass.InputOutput, visual, 0, []).check()
# Set Window names
set_window_name(conn, wid1, "Test window 1")
# Check updating opacity while FADING windows
print("Mapping window")
conn.core.MapWindowChecked(wid1).check()
time.sleep(1.2)
print("Update opacity while fading out")
conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid1, opacity_atom, xproto.Atom.CARDINAL, 32, 1, opacity_single).check()
time.sleep(0.2)
conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid1, opacity_atom, xproto.Atom.CARDINAL, 32, 1, opacity_0).check()
time.sleep(1)
print("Change from fading in to fading out")
conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid1, opacity_atom, xproto.Atom.CARDINAL, 32, 1, opacity_80).check()
time.sleep(0.5)
conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid1, opacity_atom, xproto.Atom.CARDINAL, 32, 1, opacity_0).check()
time.sleep(1)
print("Update opacity while fading in")
conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid1, opacity_atom, xproto.Atom.CARDINAL, 32, 1, opacity_80).check()
time.sleep(0.2)
conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid1, opacity_atom, xproto.Atom.CARDINAL, 32, 1, opacity_100).check()
time.sleep(1)
print("Change from fading out to fading in")
conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid1, opacity_atom, xproto.Atom.CARDINAL, 32, 1, opacity_0).check()
time.sleep(0.5)
conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid1, opacity_atom, xproto.Atom.CARDINAL, 32, 1, opacity_80).check()
time.sleep(1)
# Destroy the windows
conn.core.DestroyWindowChecked(wid1).check()

View File

@ -1,33 +0,0 @@
#!/usr/bin/env python
import xcffib.xproto as xproto
import xcffib
import time
from common import set_window_name, trigger_root_configure
conn = xcffib.connect()
setup = conn.get_setup()
root = setup.roots[0].root
visual = setup.roots[0].root_visual
depth = setup.roots[0].root_depth
# issue 357 is triggered when a window is destroyed right after configure_root
wid = conn.generate_id()
print("Window 1: ", hex(wid))
# Create a window
conn.core.CreateWindowChecked(depth, wid, root, 0, 0, 100, 100, 0, xproto.WindowClass.InputOutput, visual, 0, []).check()
# Set Window name
set_window_name(conn, wid, "Test window 1")
print("mapping 1")
conn.core.MapWindowChecked(wid).check()
time.sleep(0.5)
trigger_root_configure(conn)
# Destroy the windows
conn.core.DestroyWindowChecked(wid).check()
time.sleep(1)