Improvement: Use select() for main loop
- Back to using select() for main loop. Thus we are not longer relying on libevent. - Add generic timeout system (untested) to prepare for D-Bus support. - Drop troff man pages. Revise Makefile to improve documentation building, fix double LDFLAGS inclusion, and re-add -lrt. This turns asciidoc into a build time dependency. - Change fading time calculation. - Add --logpath and ostream_reopen() for debugging with -b. - Drop unused lceil_ntimes() and other helper functions. - Only very limited tests are done. Bugs to be expected.
This commit is contained in:
parent
7188054825
commit
57c5854fd0
40
Makefile
40
Makefile
|
@ -8,28 +8,12 @@ BINDIR ?= $(PREFIX)/bin
|
||||||
MANDIR ?= $(PREFIX)/share/man/man1
|
MANDIR ?= $(PREFIX)/share/man/man1
|
||||||
|
|
||||||
PACKAGES = x11 xcomposite xfixes xdamage xrender xext xrandr
|
PACKAGES = x11 xcomposite xfixes xdamage xrender xext xrandr
|
||||||
LIBS = -lm
|
LIBS = -lm -lrt
|
||||||
INCS =
|
INCS =
|
||||||
|
|
||||||
# === Configuration flags ===
|
# === Configuration flags ===
|
||||||
CFG =
|
CFG =
|
||||||
|
|
||||||
# ==== libevent ====
|
|
||||||
# Seemingly, libevent1 has no pkg-config file!
|
|
||||||
# FreeBSD 9.1 probably has issues handling --atleast-version in pkg-config.
|
|
||||||
ifeq "$(shell pkg-config --modversion --print-errors libevent)" ""
|
|
||||||
$(warning libevent-2.0 not found, assuming libevent-1.4.x.)
|
|
||||||
CFG += -DCONFIG_LIBEVENT_LEGACY
|
|
||||||
LIBS += -levent
|
|
||||||
else
|
|
||||||
# Using pkg-config --libs for linking with libevent will result in
|
|
||||||
# linking with libevent.so instead of the smaller libevent_core.so.
|
|
||||||
# FreeBSD keeps libevent2 .so files at a separate place, and we must
|
|
||||||
# learn it from pkg-config.
|
|
||||||
LIBS += $(shell pkg-config --libs-only-L libevent) -levent_core
|
|
||||||
INCS += $(shell pkg-config --cflags libevent)
|
|
||||||
endif
|
|
||||||
|
|
||||||
# ==== libconfig ====
|
# ==== libconfig ====
|
||||||
ifeq "$(NO_LIBCONFIG)" ""
|
ifeq "$(NO_LIBCONFIG)" ""
|
||||||
CFG += -DCONFIG_LIBCONFIG
|
CFG += -DCONFIG_LIBCONFIG
|
||||||
|
@ -72,7 +56,7 @@ COMPTON_VERSION ?= git-$(shell git describe --always --dirty)-$(shell git log -1
|
||||||
CFG += -DCOMPTON_VERSION="\"$(COMPTON_VERSION)\""
|
CFG += -DCOMPTON_VERSION="\"$(COMPTON_VERSION)\""
|
||||||
|
|
||||||
LDFLAGS ?= -Wl,-O1 -Wl,--as-needed
|
LDFLAGS ?= -Wl,-O1 -Wl,--as-needed
|
||||||
CFLAGS ?= -DNDEBUG -O2 -D_FORTIFY_SOURCE=2 $(LDFLAGS)
|
CFLAGS ?= -DNDEBUG -O2 -D_FORTIFY_SOURCE=2
|
||||||
CFLAGS += $(CFG)
|
CFLAGS += $(CFG)
|
||||||
|
|
||||||
LIBS += $(shell pkg-config --libs $(PACKAGES))
|
LIBS += $(shell pkg-config --libs $(PACKAGES))
|
||||||
|
@ -80,6 +64,8 @@ INCS += $(shell pkg-config --cflags $(PACKAGES))
|
||||||
|
|
||||||
CFLAGS += -Wall -std=c99
|
CFLAGS += -Wall -std=c99
|
||||||
OBJS = compton.o
|
OBJS = compton.o
|
||||||
|
MANPAGES = man/compton.1 man/compton-trans.1
|
||||||
|
MANPAGES_HTML = $(addsuffix .html,$(MANPAGES))
|
||||||
|
|
||||||
# === Recipes ===
|
# === Recipes ===
|
||||||
.DEFAULT_GOAL := compton
|
.DEFAULT_GOAL := compton
|
||||||
|
@ -90,15 +76,15 @@ OBJS = compton.o
|
||||||
compton: $(OBJS)
|
compton: $(OBJS)
|
||||||
$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
|
$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||||
|
|
||||||
docs:
|
man/%.1: man/%.1.asciidoc
|
||||||
# HTML documentation
|
a2x --format manpage $<
|
||||||
asciidoc man/compton.1.asciidoc
|
|
||||||
asciidoc man/compton-trans.1.asciidoc
|
|
||||||
# man page
|
|
||||||
a2x --format manpage man/compton.1.asciidoc
|
|
||||||
a2x --format manpage man/compton-trans.1.asciidoc
|
|
||||||
|
|
||||||
install: compton
|
man/%.1.html: man/%.1.asciidoc
|
||||||
|
asciidoc $<
|
||||||
|
|
||||||
|
docs: $(MANPAGES) $(MANPAGES_HTML)
|
||||||
|
|
||||||
|
install: compton docs
|
||||||
@install -Dm755 compton "$(DESTDIR)$(BINDIR)"/compton
|
@install -Dm755 compton "$(DESTDIR)$(BINDIR)"/compton
|
||||||
@install -Dm755 bin/compton-trans "$(DESTDIR)$(BINDIR)"/compton-trans
|
@install -Dm755 bin/compton-trans "$(DESTDIR)$(BINDIR)"/compton-trans
|
||||||
@install -Dm644 man/compton.1 "$(DESTDIR)$(MANDIR)"/compton.1
|
@install -Dm644 man/compton.1 "$(DESTDIR)$(MANDIR)"/compton.1
|
||||||
|
@ -111,6 +97,6 @@ uninstall:
|
||||||
@rm -f "$(DESTDIR)$(MANDIR)/compton-trans.1"
|
@rm -f "$(DESTDIR)$(MANDIR)/compton-trans.1"
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@rm -f $(OBJS) compton
|
@rm -f $(OBJS) compton $(MANPAGES) $(MANPAGES_HTML)
|
||||||
|
|
||||||
.PHONY: uninstall clean docs
|
.PHONY: uninstall clean docs
|
||||||
|
|
|
@ -55,8 +55,7 @@ __R__ for runtime
|
||||||
* libconfig (B,R) (Will probably be made optional soon)
|
* libconfig (B,R) (Will probably be made optional soon)
|
||||||
* libdrm (B) (Will probably be made optional soon)
|
* libdrm (B) (Will probably be made optional soon)
|
||||||
* libGL (B,R) (Will probably be made optional soon)
|
* libGL (B,R) (Will probably be made optional soon)
|
||||||
* asciidoc (B) (if you wish to run `make docs`)
|
* asciidoc (B)
|
||||||
* libevent (B,R)
|
|
||||||
|
|
||||||
### How to build
|
### How to build
|
||||||
|
|
||||||
|
@ -83,8 +82,6 @@ $ make install
|
||||||
|
|
||||||
* Compton may give ugly shadow to windows with ARGB background if `-z` is enabled, because compton cannot determine their real shapes. One may have to disable shadows on those windows with window-type-specific settings in configuration file or `--shadow-exclude`.
|
* Compton may give ugly shadow to windows with ARGB background if `-z` is enabled, because compton cannot determine their real shapes. One may have to disable shadows on those windows with window-type-specific settings in configuration file or `--shadow-exclude`.
|
||||||
|
|
||||||
* There are two sets of man pages in the repository: the man pages in groff format (`man/compton.1` & `man/compton-trans.1`) and the man pages in Asciidoc format (`man/compton.1.asciidoc` & `man/compton-trans.1.asciidoc`). The Asciidoc man pages are much more up-to-date than the groff ones, and it is viewable online. As chjj has not yet expressed his attitude towards switching to Asciidoc man pages, I kept both versions. By default the groff version is installed, unless you run `make docs`.
|
|
||||||
|
|
||||||
* The performance of blurring is terrible, probably because of a problem in the X Render implementation. Its behavior is driver-dependent: With nvidia-drivers it works but there are strange 1px lines remaining when you operate on windows (not sure if it's a bug in compton or in the driver); with nouveau it's utterly broken.
|
* The performance of blurring is terrible, probably because of a problem in the X Render implementation. Its behavior is driver-dependent: With nvidia-drivers it works but there are strange 1px lines remaining when you operate on windows (not sure if it's a bug in compton or in the driver); with nouveau it's utterly broken.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
.ds q \N'34'
|
|
||||||
.TH compton\-trans 1
|
|
||||||
|
|
||||||
.SH NAME
|
|
||||||
compton\-trans \- an opacity setter tool
|
|
||||||
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.nf
|
|
||||||
.B compton-trans [-w WINDOW_ID] [-n WINDOW_NAME] [-c] [-s] OPACITY
|
|
||||||
.fi
|
|
||||||
|
|
||||||
.SH DESCRIPTION
|
|
||||||
.B compton-trans
|
|
||||||
is a bash script that sets _NET_WM_WINDOW_OPACITY only using standard
|
|
||||||
command-line utilities for X11, including xprop(1) and xwininfo(1).
|
|
||||||
It is similar to other utilities like transset(1) or transset-df(1).
|
|
||||||
|
|
||||||
.SH OPTIONS
|
|
||||||
.TP
|
|
||||||
.BI \-w\ window\-id
|
|
||||||
Specify the window id to target.
|
|
||||||
.TP
|
|
||||||
.BI \-n\ window\-name
|
|
||||||
Specify and try to match a window name.
|
|
||||||
.TP
|
|
||||||
.BI \-c
|
|
||||||
Specify the current window as a target.
|
|
||||||
.TP
|
|
||||||
.BI \-s
|
|
||||||
Select target window with mouse cursor.
|
|
||||||
This is the default if no window has been specified.
|
|
||||||
.TP
|
|
||||||
.BI \-o\ opacity
|
|
||||||
Specify the new opacity value for the window. This value
|
|
||||||
can be anywhere from 1-100. If it is prefixed with a plus
|
|
||||||
or minus (+/-), this will increment or decrement from the
|
|
||||||
target window's current opacity instead.
|
|
||||||
|
|
||||||
.SH EXAMPLES
|
|
||||||
.TP
|
|
||||||
Set window id to opacity of 75%.
|
|
||||||
compton-trans -w "$WINDOWID" 75
|
|
||||||
.TP
|
|
||||||
Set window name, "urxvt", to opacity of 75%.
|
|
||||||
compton-trans -n "urxvt" 75
|
|
||||||
.TP
|
|
||||||
Set current window to opacity of 75%.
|
|
||||||
compton-trans -c 75
|
|
||||||
.TP
|
|
||||||
Select target window and set opacity to 75%.
|
|
||||||
compton-trans -s 75
|
|
||||||
.TP
|
|
||||||
Increment current window opacity by 5%.
|
|
||||||
compton-trans -c +5
|
|
||||||
.TP
|
|
||||||
Decrement current window opacity by 5%.
|
|
||||||
compton-trans -c -- -5
|
|
||||||
|
|
||||||
.SH BUGS
|
|
||||||
Please report any you find to https://github.com/chjj/compton.
|
|
||||||
|
|
||||||
.SH AUTHORS
|
|
||||||
Christopher Jeffrey (https://github.com/chjj)
|
|
||||||
|
|
||||||
.SH SEE ALSO
|
|
||||||
.BR compton(1),
|
|
||||||
.BR xprop(1),
|
|
||||||
.BR xwininfo(1)
|
|
177
man/compton.1
177
man/compton.1
|
@ -1,177 +0,0 @@
|
||||||
.ds q \N'34'
|
|
||||||
.TH compton 1
|
|
||||||
|
|
||||||
.SH NAME
|
|
||||||
compton \- a compositor for X11
|
|
||||||
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B compton
|
|
||||||
[\-d display] [\-r radius] [\-o opacity] [\-l left\-offset]
|
|
||||||
[\-t top\-offset] [\-i opacity] [\-e opacity] [\-cCfFSdG]
|
|
||||||
[\-\-config path] [\-\-shadow\-red value]
|
|
||||||
[\-\-shadow\-green value] [\-\-shadow\-blue value]
|
|
||||||
[\-\-inactive\-opacity\-override] [\-\-inactive\-dim value]
|
|
||||||
[\-\-mark\-wmwin\-focused] [\-\-shadow\-exclude condition]
|
|
||||||
[\-\-mark\-ovredir\-focused] [\-\-no\-fading\-openclose]
|
|
||||||
[\-\-shadow\-ignore\-shaped] [\-\-detect\-round\-corners]
|
|
||||||
|
|
||||||
.SH DESCRIPTION
|
|
||||||
.B compton
|
|
||||||
is a compositor based on Dana Jansens' version of xcompmgr (which itself was
|
|
||||||
written by Keith Packard). It includes many improvements over the original
|
|
||||||
xcompmgr, including window frame opacity, inactive window transparency,
|
|
||||||
and shadows on argb windows.
|
|
||||||
|
|
||||||
.SH EXAMPLE
|
|
||||||
|
|
||||||
$ compton -cC -i 0.6 -e 0.6 -f
|
|
||||||
|
|
||||||
$ compton --config ~/compton.conf
|
|
||||||
|
|
||||||
.SH OPTIONS
|
|
||||||
.TP
|
|
||||||
.BI \-d\ display
|
|
||||||
Which display should be managed.
|
|
||||||
.TP
|
|
||||||
.BI \-r\ radius
|
|
||||||
The blur radius for shadows. (default 12)
|
|
||||||
.TP
|
|
||||||
.BI \-o\ opacity
|
|
||||||
The translucency for shadows. (default .75)
|
|
||||||
.TP
|
|
||||||
.BI \-l\ left\-offset
|
|
||||||
The left offset for shadows. (default -15)
|
|
||||||
.TP
|
|
||||||
.BI \-t\ top\-offset
|
|
||||||
The top offset for shadows. (default -15)
|
|
||||||
.TP
|
|
||||||
.BI \-I\ fade\-in\-step
|
|
||||||
Opacity change between steps while fading in. (default 0.028)
|
|
||||||
.TP
|
|
||||||
.BI \-O\ fade\-out\-step
|
|
||||||
Opacity change between steps while fading out. (default 0.03)
|
|
||||||
.TP
|
|
||||||
.BI \-D\ fade\-delta\-time
|
|
||||||
The time between steps in a fade in milliseconds. (default 10)
|
|
||||||
.TP
|
|
||||||
.BI \-m\ opacity
|
|
||||||
The opacity for menus. (default 1.0)
|
|
||||||
.TP
|
|
||||||
.BI \-c
|
|
||||||
Enabled client-side shadows on windows.
|
|
||||||
.TP
|
|
||||||
.BI \-C
|
|
||||||
Avoid drawing shadows on dock/panel windows.
|
|
||||||
.TP
|
|
||||||
.BI \-z
|
|
||||||
Zero the part of the shadow's mask behind the window (experimental).
|
|
||||||
.TP
|
|
||||||
.BI \-f
|
|
||||||
Fade windows in/out when opening/closing and when opacity
|
|
||||||
changes, unless --no-fading-openclose is used.
|
|
||||||
.TP
|
|
||||||
.BI \-F
|
|
||||||
Equals -f. Deprecated.
|
|
||||||
.TP
|
|
||||||
.BI \-i\ opacity
|
|
||||||
Opacity of inactive windows. (0.1 - 1.0)
|
|
||||||
.TP
|
|
||||||
.BI \-e\ opacity
|
|
||||||
Opacity of window titlebars and borders. (0.1 - 1.0)
|
|
||||||
.TP
|
|
||||||
.BI \-G
|
|
||||||
Don't draw shadows on DND windows
|
|
||||||
.TP
|
|
||||||
.BI \-b
|
|
||||||
Daemonize/background process.
|
|
||||||
.TP
|
|
||||||
.BI \-S
|
|
||||||
Enable synchronous operation (for debugging).
|
|
||||||
.TP
|
|
||||||
.BI \-\-config\ path
|
|
||||||
Look for configuration file at the path.
|
|
||||||
.TP
|
|
||||||
.BI \-\-shadow\-red\ value
|
|
||||||
Red color value of shadow (0.0 - 1.0, defaults to 0).
|
|
||||||
.TP
|
|
||||||
.BI \-\-shadow\-green\ value
|
|
||||||
Green color value of shadow (0.0 - 1.0, defaults to 0).
|
|
||||||
.TP
|
|
||||||
.BI \-\-shadow\-blue\ value
|
|
||||||
Blue color value of shadow (0.0 - 1.0, defaults to 0).
|
|
||||||
.TP
|
|
||||||
.BI \-\-inactive\-opacity\-override
|
|
||||||
Inactive opacity set by -i overrides value of _NET_WM_OPACITY.
|
|
||||||
.TP
|
|
||||||
.BI \-\-inactive\-dim\ value
|
|
||||||
Dim inactive windows. (0.0 - 1.0, defaults to 0)
|
|
||||||
.TP
|
|
||||||
.BI \-\-mark\-wmwin\-focused
|
|
||||||
Try to detect WM windows and mark them as active.
|
|
||||||
.TP
|
|
||||||
.BI \-\-shadow\-exclude\ condition
|
|
||||||
Exclude conditions for shadows.
|
|
||||||
.TP
|
|
||||||
.BI \--mark\-ovredir\-focused
|
|
||||||
Mark over-redirect windows as active.
|
|
||||||
.TP
|
|
||||||
.BI \-\-no\-fading\-openclose
|
|
||||||
Do not fade on window open/close.
|
|
||||||
.TP
|
|
||||||
.BI \-\-shadow\-ignore\-shaped
|
|
||||||
Do not paint shadows on shaped windows.
|
|
||||||
.TP
|
|
||||||
.BI \-\-detect\-rounded\-corners
|
|
||||||
Try to detect windows with rounded corners and don't consider
|
|
||||||
them shaped windows.
|
|
||||||
.TP
|
|
||||||
.BI Format\ of\ a\ condition:
|
|
||||||
|
|
||||||
condition = <target>:<type>[<flags>]:<pattern>
|
|
||||||
|
|
||||||
<target> is one of "n" (window name), "i" (window class
|
|
||||||
instance), and "g" (window general class)
|
|
||||||
|
|
||||||
<type> is one of "e" (exact match), "a" (match anywhere),
|
|
||||||
"s" (match from start), "w" (wildcard), and "p" (PCRE
|
|
||||||
regular expressions, if compiled with the support).
|
|
||||||
|
|
||||||
<flags> could be a series of flags. Currently the only defined
|
|
||||||
flag is "i" (ignore case).
|
|
||||||
|
|
||||||
<pattern> is the actual pattern string.
|
|
||||||
|
|
||||||
.SH CONFIGURATION
|
|
||||||
(A more robust sample configuration file exists in the compton
|
|
||||||
repository.)
|
|
||||||
|
|
||||||
.B Example
|
|
||||||
|
|
||||||
.B ~/compton.conf:
|
|
||||||
|
|
||||||
# Shadows
|
|
||||||
shadow = true;
|
|
||||||
|
|
||||||
# Opacity
|
|
||||||
inactive-opacity = 0.8;
|
|
||||||
frame-opacity = 0.7;
|
|
||||||
|
|
||||||
# Fades
|
|
||||||
fading = true;
|
|
||||||
|
|
||||||
.B Run with:
|
|
||||||
|
|
||||||
$ compton --config ~/compton.conf
|
|
||||||
|
|
||||||
.SH BUGS
|
|
||||||
Please report any you find to https://github.com/chjj/compton.
|
|
||||||
|
|
||||||
.SH AUTHORS
|
|
||||||
xcompmgr, originally written by Keith Packard, with contributions from
|
|
||||||
Matthew Allum, Eric Anholt, Dan Doel, Thomas Luebking, Matthew Hawn,
|
|
||||||
Ely Levy, Phil Blundell, and Carl Worth.
|
|
||||||
Compton by Christopher Jeffrey, based on Dana Jansens' original work,
|
|
||||||
with numerous contributions from Richard Grenville.
|
|
||||||
|
|
||||||
.SH SEE ALSO
|
|
||||||
.BR compton-trans(1)
|
|
357
src/compton.c
357
src/compton.c
|
@ -57,8 +57,7 @@ static int
|
||||||
fade_timeout(session_t *ps) {
|
fade_timeout(session_t *ps) {
|
||||||
int diff = ps->o.fade_delta - get_time_ms() + ps->fade_time;
|
int diff = ps->o.fade_delta - get_time_ms() + ps->fade_time;
|
||||||
|
|
||||||
if (diff < 0)
|
diff = normalize_i_range(diff, 0, ps->o.fade_delta * 2);
|
||||||
diff = 0;
|
|
||||||
|
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
@ -1196,11 +1195,14 @@ paint_preprocess(session_t *ps, win *list) {
|
||||||
bool is_highest = true;
|
bool is_highest = true;
|
||||||
|
|
||||||
// Fading step calculation
|
// Fading step calculation
|
||||||
time_ms_t steps = ((get_time_ms() - ps->fade_time) + FADE_DELTA_TOLERANCE * ps->o.fade_delta) / ps->o.fade_delta;
|
time_ms_t steps = 0L;
|
||||||
if (steps < 0L) {
|
if (ps->fade_time) {
|
||||||
// Time disorder
|
steps = ((get_time_ms() - ps->fade_time) + FADE_DELTA_TOLERANCE * ps->o.fade_delta) / ps->o.fade_delta;
|
||||||
|
}
|
||||||
|
// Reset fade_time if unset, or there appears to be a time disorder
|
||||||
|
if (!ps->fade_time || steps < 0L) {
|
||||||
ps->fade_time = get_time_ms();
|
ps->fade_time = get_time_ms();
|
||||||
steps = 0;
|
steps = 0L;
|
||||||
}
|
}
|
||||||
ps->fade_time += steps * ps->o.fade_delta;
|
ps->fade_time += steps * ps->o.fade_delta;
|
||||||
|
|
||||||
|
@ -3920,11 +3922,29 @@ register_cm(session_t *ps, bool want_glxct) {
|
||||||
XSetSelectionOwner(ps->dpy, a, ps->reg_win, 0);
|
XSetSelectionOwner(ps->dpy, a, ps->reg_win, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reopen streams for logging.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
ostream_reopen(session_t *ps, const char *path) {
|
||||||
|
if (!path)
|
||||||
|
path = ps->o.logpath;
|
||||||
|
if (!path)
|
||||||
|
path = "/dev/null";
|
||||||
|
|
||||||
|
bool success = freopen(path, "a", stdout);
|
||||||
|
success = freopen(path, "a", stderr) && success;
|
||||||
|
if (!success)
|
||||||
|
printf_errfq(1, "(%s): freopen() failed.", path);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fork program to background and disable all I/O streams.
|
* Fork program to background and disable all I/O streams.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
fork_after(void) {
|
fork_after(session_t *ps) {
|
||||||
if (getppid() == 1)
|
if (getppid() == 1)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -3941,18 +3961,13 @@ fork_after(void) {
|
||||||
|
|
||||||
// Mainly to suppress the _FORTIFY_SOURCE warning
|
// Mainly to suppress the _FORTIFY_SOURCE warning
|
||||||
bool success = freopen("/dev/null", "r", stdin);
|
bool success = freopen("/dev/null", "r", stdin);
|
||||||
success = freopen("/dev/null", "w", stdout) && success;
|
|
||||||
if (!success) {
|
|
||||||
printf_errf("(): freopen() failed.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
success = freopen("/dev/null", "w", stderr);
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
printf_errf("(): freopen() failed.");
|
printf_errf("(): freopen() failed.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
success = ostream_reopen(ps, NULL);
|
||||||
|
|
||||||
return true;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_LIBCONFIG
|
#ifdef CONFIG_LIBCONFIG
|
||||||
|
@ -4299,6 +4314,7 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
|
||||||
{ "blur-background-frame", no_argument, NULL, 284 },
|
{ "blur-background-frame", no_argument, NULL, 284 },
|
||||||
{ "blur-background-fixed", no_argument, NULL, 285 },
|
{ "blur-background-fixed", no_argument, NULL, 285 },
|
||||||
{ "dbus", no_argument, NULL, 286 },
|
{ "dbus", no_argument, NULL, 286 },
|
||||||
|
{ "logpath", required_argument, NULL, 287 },
|
||||||
// Must terminate with a NULL entry
|
// Must terminate with a NULL entry
|
||||||
{ NULL, 0, NULL, 0 },
|
{ NULL, 0, NULL, 0 },
|
||||||
};
|
};
|
||||||
|
@ -4405,8 +4421,7 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
|
||||||
case 'n':
|
case 'n':
|
||||||
case 'a':
|
case 'a':
|
||||||
case 's':
|
case 's':
|
||||||
fprintf(stderr, "Warning: "
|
printf_errfq(1, "(): -n, -a, and -s have been removed.");
|
||||||
"-n, -a, and -s have been removed.\n");
|
|
||||||
break;
|
break;
|
||||||
case 'b':
|
case 'b':
|
||||||
ps->o.fork_after_register = true;
|
ps->o.fork_after_register = true;
|
||||||
|
@ -4535,8 +4550,13 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
|
||||||
// --dbus
|
// --dbus
|
||||||
ps->o.dbus = true;
|
ps->o.dbus = true;
|
||||||
break;
|
break;
|
||||||
|
case 287:
|
||||||
|
// --logpath
|
||||||
|
ps->o.logpath = mstrcpy(optarg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4694,22 +4714,6 @@ swopti_init(session_t *ps) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the smaller number that is bigger than <code>dividend</code> and is
|
|
||||||
* N times of <code>divisor</code>.
|
|
||||||
*/
|
|
||||||
static inline long
|
|
||||||
lceil_ntimes(long dividend, long divisor) {
|
|
||||||
// It's possible to use the more beautiful expression here:
|
|
||||||
// ret = ((dividend - 1) / divisor + 1) * divisor;
|
|
||||||
// But it does not work well for negative values.
|
|
||||||
long ret = dividend / divisor * divisor;
|
|
||||||
if (ret < dividend)
|
|
||||||
ret += divisor;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modify a struct timeval timeout value to render at a fixed pace.
|
* Modify a struct timeval timeout value to render at a fixed pace.
|
||||||
*
|
*
|
||||||
|
@ -4743,32 +4747,6 @@ swopti_handle_timeout(session_t *ps, struct timeval *ptv) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Libevent callback function to handle X events.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
evcallback_x(evutil_socket_t fd, short what, void *arg) {
|
|
||||||
session_t *ps = ps_g;
|
|
||||||
|
|
||||||
// Sometimes poll() returns 1 but no events are actually read,
|
|
||||||
// causing XNextEvent() to block, I have no idea what's wrong, so we
|
|
||||||
// check for the number of events here
|
|
||||||
if (XEventsQueued(ps->dpy, QueuedAfterReading)) {
|
|
||||||
XEvent ev = { };
|
|
||||||
|
|
||||||
XNextEvent(ps->dpy, &ev);
|
|
||||||
ev_handle(ps, &ev);
|
|
||||||
ps->ev_received = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* NULL libevent callback function.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
evcallback_null(evutil_socket_t fd, short what, void *arg) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize DRM VSync.
|
* Initialize DRM VSync.
|
||||||
*
|
*
|
||||||
|
@ -5003,6 +4981,141 @@ redir_start(session_t *ps) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the poll time.
|
||||||
|
*/
|
||||||
|
static time_ms_t
|
||||||
|
timeout_get_poll_time(session_t *ps) {
|
||||||
|
const time_ms_t now = get_time_ms();
|
||||||
|
time_ms_t wait = TIME_MS_MAX;
|
||||||
|
|
||||||
|
// Traverse throught the timeout linked list
|
||||||
|
for (timeout_t *ptmout = ps->tmout_lst; ptmout; ptmout = ptmout->next) {
|
||||||
|
if (ptmout->enabled) {
|
||||||
|
// Truncate the last run time to the closest interval
|
||||||
|
time_ms_t newrun = ptmout->firstrun + ((ptmout->lastrun - ptmout->firstrun) / ptmout->interval + 1) * ptmout->interval;
|
||||||
|
if (newrun <= now) {
|
||||||
|
wait = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
time_ms_t newwait = newrun - now;
|
||||||
|
if (newwait < wait)
|
||||||
|
wait = newwait;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wait;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a new timeout.
|
||||||
|
*/
|
||||||
|
static timeout_t *
|
||||||
|
timeout_insert(session_t *ps, time_ms_t interval,
|
||||||
|
bool (*callback)(session_t *ps, timeout_t *ptmout), void *data) {
|
||||||
|
const static timeout_t tmout_def = {
|
||||||
|
.enabled = true,
|
||||||
|
.data = NULL,
|
||||||
|
.callback = NULL,
|
||||||
|
.firstrun = 0L,
|
||||||
|
.lastrun = 0L,
|
||||||
|
.interval = 0L,
|
||||||
|
};
|
||||||
|
|
||||||
|
const time_ms_t now = get_time_ms();
|
||||||
|
timeout_t *ptmout = malloc(sizeof(timeout_t));
|
||||||
|
if (!ptmout)
|
||||||
|
printf_errfq(1, "(): Failed to allocate memory for timeout.");
|
||||||
|
memcpy(ptmout, &tmout_def, sizeof(timeout_t));
|
||||||
|
|
||||||
|
ptmout->interval = interval;
|
||||||
|
ptmout->firstrun = now;
|
||||||
|
ptmout->lastrun = now;
|
||||||
|
ptmout->data = data;
|
||||||
|
ptmout->callback = callback;
|
||||||
|
ptmout->next = ps->tmout_lst;
|
||||||
|
ps->tmout_lst = ptmout;
|
||||||
|
|
||||||
|
return ptmout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drop a timeout.
|
||||||
|
*
|
||||||
|
* @return true if we have found the timeout and removed it, false
|
||||||
|
* otherwise
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
timeout_drop(session_t *ps, timeout_t *prm) {
|
||||||
|
timeout_t **pplast = &ps->tmout_lst;
|
||||||
|
|
||||||
|
for (timeout_t *ptmout = ps->tmout_lst; ptmout;
|
||||||
|
pplast = &ptmout->next, ptmout = ptmout->next) {
|
||||||
|
if (prm == ptmout) {
|
||||||
|
*pplast = ptmout->next;
|
||||||
|
free(ptmout);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear all timeouts.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
timeout_clear(session_t *ps) {
|
||||||
|
timeout_t *ptmout = ps->tmout_lst;
|
||||||
|
timeout_t *next = NULL;
|
||||||
|
while (ptmout) {
|
||||||
|
next = ptmout->next;
|
||||||
|
free(ptmout);
|
||||||
|
ptmout = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run timeouts.
|
||||||
|
*
|
||||||
|
* @return true if we have ran a timeout, false otherwise
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
timeout_run(session_t *ps) {
|
||||||
|
const time_ms_t now = get_time_ms();
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
for (timeout_t *ptmout = ps->tmout_lst; ptmout; ptmout = ptmout->next) {
|
||||||
|
if (ptmout->enabled) {
|
||||||
|
const time_ms_t max = now +
|
||||||
|
(time_ms_t) (ptmout->interval * TIMEOUT_RUN_TOLERANCE);
|
||||||
|
time_ms_t newrun = ptmout->firstrun + ((ptmout->lastrun - ptmout->firstrun) / ptmout->interval + 1) * ptmout->interval;
|
||||||
|
if (newrun <= max) {
|
||||||
|
ret = true;
|
||||||
|
timeout_invoke(ps, ptmout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke a timeout.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
timeout_invoke(session_t *ps, timeout_t *ptmout) {
|
||||||
|
const time_ms_t now = get_time_ms();
|
||||||
|
ptmout->lastrun = now;
|
||||||
|
// Avoid modifying the timeout structure after running timeout, to
|
||||||
|
// make it possible to remove timeout in callback
|
||||||
|
if (ptmout->callback)
|
||||||
|
ptmout->callback(ps, ptmout);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unredirect all windows.
|
* Unredirect all windows.
|
||||||
*/
|
*/
|
||||||
|
@ -5037,36 +5150,74 @@ redir_stop(session_t *ps) {
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
mainloop(session_t *ps) {
|
mainloop(session_t *ps) {
|
||||||
bool infinite_wait = false;
|
|
||||||
|
|
||||||
// Process existing events
|
// Process existing events
|
||||||
|
// Sometimes poll() returns 1 but no events are actually read,
|
||||||
|
// causing XNextEvent() to block, I have no idea what's wrong, so we
|
||||||
|
// check for the number of events here.
|
||||||
if (XEventsQueued(ps->dpy, QueuedAfterReading)) {
|
if (XEventsQueued(ps->dpy, QueuedAfterReading)) {
|
||||||
evcallback_x(ConnectionNumber(ps->dpy), 0, NULL);
|
XEvent ev = { };
|
||||||
|
|
||||||
|
XNextEvent(ps->dpy, &ev);
|
||||||
|
ev_handle(ps, &ev);
|
||||||
|
ps->ev_received = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add timeout
|
if (ps->reset)
|
||||||
if (ps->ev_received || !ps->idling) {
|
|
||||||
struct timeval tv = ms_to_tv(ps->ev_received ? 0: fade_timeout(ps));
|
|
||||||
if (ps->o.sw_opti)
|
|
||||||
swopti_handle_timeout(ps, &tv);
|
|
||||||
assert(tv.tv_sec >= 0 && tv.tv_usec >= 0);
|
|
||||||
if (timeval_isempty(tv))
|
|
||||||
return false;
|
return false;
|
||||||
evtimer_add(ps->ev_tmout, &tv);
|
|
||||||
|
// Calculate timeout
|
||||||
|
struct timeval *ptv = NULL;
|
||||||
|
{
|
||||||
|
// Consider ev_received firstly
|
||||||
|
if (ps->ev_received) {
|
||||||
|
ptv = malloc(sizeof(struct timeval));
|
||||||
|
ptv->tv_sec = 0L;
|
||||||
|
ptv->tv_usec = 0L;
|
||||||
}
|
}
|
||||||
else {
|
// Then consider fading timeout
|
||||||
infinite_wait = true;
|
else if (!ps->idling) {
|
||||||
|
ptv = malloc(sizeof(struct timeval));
|
||||||
|
*ptv = ms_to_tv(fade_timeout(ps));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run libevent main loop
|
// Software optimization is to be applied on timeouts that require
|
||||||
if (event_base_loop(ps->ev_base, EVLOOP_ONCE))
|
// immediate painting only
|
||||||
printf_errfq(1, "(): Unexpected error when running event loop.");
|
if (ptv && ps->o.sw_opti)
|
||||||
|
swopti_handle_timeout(ps, ptv);
|
||||||
|
|
||||||
evtimer_del(ps->ev_tmout);
|
// Don't continue looping for 0 timeout
|
||||||
|
if (ptv && timeval_isempty(ptv)) {
|
||||||
|
free(ptv);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (infinite_wait)
|
// Now consider the waiting time of other timeouts
|
||||||
ps->fade_time = get_time_ms();
|
time_ms_t tmout_ms = timeout_get_poll_time(ps);
|
||||||
|
if (tmout_ms < TIME_MS_MAX) {
|
||||||
|
if (!ptv) {
|
||||||
|
ptv = malloc(sizeof(struct timeval));
|
||||||
|
*ptv = ms_to_tv(tmout_ms);
|
||||||
|
}
|
||||||
|
else if (timeval_ms_cmp(ptv, tmout_ms) > 0) {
|
||||||
|
*ptv = ms_to_tv(tmout_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't continue looping for 0 timeout
|
||||||
|
if (ptv && timeval_isempty(ptv)) {
|
||||||
|
free(ptv);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Polling
|
||||||
|
fds_poll(ps, ptv);
|
||||||
|
free(ptv);
|
||||||
|
ptv = NULL;
|
||||||
|
|
||||||
|
timeout_run(ps);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -5106,6 +5257,8 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
||||||
.detect_rounded_corners = false,
|
.detect_rounded_corners = false,
|
||||||
.paint_on_overlay = false,
|
.paint_on_overlay = false,
|
||||||
.unredir_if_possible = false,
|
.unredir_if_possible = false,
|
||||||
|
.dbus = false,
|
||||||
|
.logpath = NULL,
|
||||||
|
|
||||||
.refresh_rate = 0,
|
.refresh_rate = 0,
|
||||||
.sw_opti = false,
|
.sw_opti = false,
|
||||||
|
@ -5156,6 +5309,12 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
||||||
.track_leader = false,
|
.track_leader = false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.pfds_read = NULL,
|
||||||
|
.pfds_write = NULL,
|
||||||
|
.pfds_except = NULL,
|
||||||
|
.nfds_max = 0,
|
||||||
|
.tmout_lst = NULL,
|
||||||
|
|
||||||
.all_damage = None,
|
.all_damage = None,
|
||||||
.time_start = { 0, 0 },
|
.time_start = { 0, 0 },
|
||||||
.redirected = false,
|
.redirected = false,
|
||||||
|
@ -5163,7 +5322,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
||||||
.alpha_picts = NULL,
|
.alpha_picts = NULL,
|
||||||
.reg_ignore_expire = false,
|
.reg_ignore_expire = false,
|
||||||
.idling = false,
|
.idling = false,
|
||||||
.fade_time = 0,
|
.fade_time = 0L,
|
||||||
.ignore_head = NULL,
|
.ignore_head = NULL,
|
||||||
.ignore_tail = NULL,
|
.ignore_tail = NULL,
|
||||||
.reset = false,
|
.reset = false,
|
||||||
|
@ -5406,24 +5565,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
||||||
ps->o.shadow_red, ps->o.shadow_green, ps->o.shadow_blue);
|
ps->o.shadow_red, ps->o.shadow_green, ps->o.shadow_blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
ps->all_damage = None;
|
fds_insert(ps, ConnectionNumber(ps->dpy), POLLIN);
|
||||||
|
|
||||||
// Build event base
|
|
||||||
if (!(ps->ev_base =
|
|
||||||
#ifndef CONFIG_LIBEVENT_LEGACY
|
|
||||||
event_base_new()
|
|
||||||
#else
|
|
||||||
event_init()
|
|
||||||
#endif
|
|
||||||
))
|
|
||||||
printf_errfq(1, "(): Failed to build event base.");
|
|
||||||
if (!(ps->ev_x = EVENT_NEW(ps->ev_base, ConnectionNumber(ps->dpy),
|
|
||||||
EV_READ | EV_PERSIST, evcallback_x, NULL)))
|
|
||||||
printf_errfq(1, "(): Failed to build event.");
|
|
||||||
if (event_add(ps->ev_x, NULL))
|
|
||||||
printf_errfq(1, "(): Failed to add event.");
|
|
||||||
if (!(ps->ev_tmout = evtimer_new(ps->ev_base, evcallback_null, NULL)))
|
|
||||||
printf_errfq(1, "(): Failed to build event.");
|
|
||||||
|
|
||||||
XGrabServer(ps->dpy);
|
XGrabServer(ps->dpy);
|
||||||
|
|
||||||
|
@ -5459,14 +5601,10 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
||||||
|
|
||||||
// Fork to background, if asked
|
// Fork to background, if asked
|
||||||
if (ps->o.fork_after_register) {
|
if (ps->o.fork_after_register) {
|
||||||
if (!fork_after()) {
|
if (!fork_after(ps)) {
|
||||||
session_destroy(ps);
|
session_destroy(ps);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reinitialize event base
|
|
||||||
if (event_reinit(ps->ev_base) < 0)
|
|
||||||
printf_errfq(1, "Failed to reinitialize event base.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free the old session
|
// Free the old session
|
||||||
|
@ -5565,6 +5703,10 @@ session_destroy(session_t *ps) {
|
||||||
free(ps->shadow_top);
|
free(ps->shadow_top);
|
||||||
free(ps->gaussian_map);
|
free(ps->gaussian_map);
|
||||||
free(ps->o.display);
|
free(ps->o.display);
|
||||||
|
free(ps->o.logpath);
|
||||||
|
free(ps->pfds_read);
|
||||||
|
free(ps->pfds_write);
|
||||||
|
free(ps->pfds_except);
|
||||||
|
|
||||||
// Free reg_win and glx_context
|
// Free reg_win and glx_context
|
||||||
if (ps->reg_win) {
|
if (ps->reg_win) {
|
||||||
|
@ -5598,14 +5740,12 @@ session_destroy(session_t *ps) {
|
||||||
ps->overlay = None;
|
ps->overlay = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free libevent things
|
|
||||||
event_free(ps->ev_x);
|
|
||||||
event_free(ps->ev_tmout);
|
|
||||||
event_base_free(ps->ev_base);
|
|
||||||
|
|
||||||
// Flush all events
|
// Flush all events
|
||||||
XSync(ps->dpy, True);
|
XSync(ps->dpy, True);
|
||||||
|
|
||||||
|
// Free timeouts
|
||||||
|
timeout_clear(ps);
|
||||||
|
|
||||||
if (ps == ps_g)
|
if (ps == ps_g)
|
||||||
ps_g = NULL;
|
ps_g = NULL;
|
||||||
}
|
}
|
||||||
|
@ -5624,8 +5764,6 @@ session_run(session_t *ps) {
|
||||||
|
|
||||||
ps->reg_ignore_expire = true;
|
ps->reg_ignore_expire = true;
|
||||||
|
|
||||||
ps->fade_time = get_time_ms();
|
|
||||||
|
|
||||||
t = paint_preprocess(ps, ps->list);
|
t = paint_preprocess(ps, ps->list);
|
||||||
|
|
||||||
if (ps->redirected)
|
if (ps->redirected)
|
||||||
|
@ -5658,6 +5796,9 @@ session_run(session_t *ps) {
|
||||||
XSync(ps->dpy, False);
|
XSync(ps->dpy, False);
|
||||||
ps->all_damage = None;
|
ps->all_damage = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ps->idling)
|
||||||
|
ps->fade_time = 0L;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
225
src/compton.h
225
src/compton.h
|
@ -43,9 +43,11 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <sys/select.h>
|
||||||
#include <sys/poll.h>
|
#include <sys/poll.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -54,20 +56,6 @@
|
||||||
#include <fnmatch.h>
|
#include <fnmatch.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
// libevent
|
|
||||||
#ifndef CONFIG_LIBEVENT_LEGACY
|
|
||||||
#include <event2/event.h>
|
|
||||||
#else
|
|
||||||
#include <event.h>
|
|
||||||
typedef int evutil_socket_t;
|
|
||||||
typedef void(* event_callback_fn)(evutil_socket_t, short, void *);
|
|
||||||
#define event_free(ev) (event_del((ev)), free((ev)))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef evtimer_new
|
|
||||||
#define evtimer_new(b, cb, arg) EVENT_NEW((b), -1, 0, (cb), (arg))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// libpcre
|
// libpcre
|
||||||
#ifdef CONFIG_REGEX_PCRE
|
#ifdef CONFIG_REGEX_PCRE
|
||||||
#include <pcre.h>
|
#include <pcre.h>
|
||||||
|
@ -127,8 +115,10 @@ typedef void(* event_callback_fn)(evutil_socket_t, short, void *);
|
||||||
#define OPAQUE 0xffffffff
|
#define OPAQUE 0xffffffff
|
||||||
#define REGISTER_PROP "_NET_WM_CM_S"
|
#define REGISTER_PROP "_NET_WM_CM_S"
|
||||||
|
|
||||||
|
#define TIME_MS_MAX LONG_MAX
|
||||||
#define FADE_DELTA_TOLERANCE 0.2
|
#define FADE_DELTA_TOLERANCE 0.2
|
||||||
#define SWOPTI_TOLERANCE 3000
|
#define SWOPTI_TOLERANCE 3000
|
||||||
|
#define TIMEOUT_RUN_TOLERANCE 0.2
|
||||||
#define WIN_GET_LEADER_MAX_RECURSION 20
|
#define WIN_GET_LEADER_MAX_RECURSION 20
|
||||||
|
|
||||||
#define SEC_WRAP (15L * 24L * 60L * 60L)
|
#define SEC_WRAP (15L * 24L * 60L * 60L)
|
||||||
|
@ -286,6 +276,8 @@ typedef struct {
|
||||||
double *data;
|
double *data;
|
||||||
} conv;
|
} conv;
|
||||||
|
|
||||||
|
struct _timeout_t;
|
||||||
|
|
||||||
struct _win;
|
struct _win;
|
||||||
|
|
||||||
/// Structure representing all options.
|
/// Structure representing all options.
|
||||||
|
@ -308,6 +300,8 @@ typedef struct {
|
||||||
bool unredir_if_possible;
|
bool unredir_if_possible;
|
||||||
/// Whether to enable D-Bus support.
|
/// Whether to enable D-Bus support.
|
||||||
bool dbus;
|
bool dbus;
|
||||||
|
/// Path to log file.
|
||||||
|
char *logpath;
|
||||||
/// Whether to work under synchronized mode for debugging.
|
/// Whether to work under synchronized mode for debugging.
|
||||||
bool synchronize;
|
bool synchronize;
|
||||||
|
|
||||||
|
@ -447,12 +441,16 @@ typedef struct {
|
||||||
// === Operation related ===
|
// === Operation related ===
|
||||||
/// Program options.
|
/// Program options.
|
||||||
options_t o;
|
options_t o;
|
||||||
/// Libevent event base.
|
/// File descriptors to check for reading.
|
||||||
struct event_base *ev_base;
|
fd_set *pfds_read;
|
||||||
/// Libevent event for X connection.
|
/// File descriptors to check for writing.
|
||||||
struct event *ev_x;
|
fd_set *pfds_write;
|
||||||
/// Libevent event for timeout.
|
/// File descriptors to check for exceptions.
|
||||||
struct event *ev_tmout;
|
fd_set *pfds_except;
|
||||||
|
/// Largest file descriptor in fd_set-s above.
|
||||||
|
int nfds_max;
|
||||||
|
/// Linked list of all timeouts.
|
||||||
|
struct _timeout_t *tmout_lst;
|
||||||
/// Whether we have received an event in this cycle.
|
/// Whether we have received an event in this cycle.
|
||||||
bool ev_received;
|
bool ev_received;
|
||||||
/// Whether the program is idling. I.e. no fading, no potential window
|
/// Whether the program is idling. I.e. no fading, no potential window
|
||||||
|
@ -770,6 +768,18 @@ struct options_tmp {
|
||||||
double menu_opacity;
|
double menu_opacity;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Structure for a recorded timeout.
|
||||||
|
typedef struct _timeout_t {
|
||||||
|
bool enabled;
|
||||||
|
void *data;
|
||||||
|
bool (*callback)(session_t *ps, struct _timeout_t *ptmout);
|
||||||
|
time_ms_t interval;
|
||||||
|
time_ms_t firstrun;
|
||||||
|
time_ms_t lastrun;
|
||||||
|
struct _timeout_t *next;
|
||||||
|
} timeout_t;
|
||||||
|
|
||||||
|
/// Enumeration for window event hints.
|
||||||
typedef enum {
|
typedef enum {
|
||||||
WIN_EVMODE_UNKNOWN,
|
WIN_EVMODE_UNKNOWN,
|
||||||
WIN_EVMODE_FRAME,
|
WIN_EVMODE_FRAME,
|
||||||
|
@ -840,22 +850,6 @@ XFixesDestroyRegion_(Display *dpy, XserverRegion reg,
|
||||||
|
|
||||||
// == Functions ==
|
// == Functions ==
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper of libevent event_new(), for compatibility with libevent-1\.x.
|
|
||||||
*/
|
|
||||||
static inline struct event *
|
|
||||||
EVENT_NEW(struct event_base *base, evutil_socket_t fd,
|
|
||||||
short what, event_callback_fn cb, void *arg) {
|
|
||||||
#ifndef CONFIG_LIBEVENT_LEGACY
|
|
||||||
return event_new(base, fd, what, cb, arg);
|
|
||||||
#else
|
|
||||||
struct event *pev = malloc(sizeof(struct event));
|
|
||||||
if (pev)
|
|
||||||
event_set(pev, fd, what, cb, arg);
|
|
||||||
return pev;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// inline functions must be made static to compile correctly under clang:
|
// inline functions must be made static to compile correctly under clang:
|
||||||
// http://clang.llvm.org/compatibility.html#inline
|
// http://clang.llvm.org/compatibility.html#inline
|
||||||
|
|
||||||
|
@ -1007,6 +1001,14 @@ min_i(int a, int b) {
|
||||||
return (a > b ? b : a);
|
return (a > b ? b : a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select the smaller long integer of two.
|
||||||
|
*/
|
||||||
|
static inline long __attribute__((const))
|
||||||
|
min_l(long a, long b) {
|
||||||
|
return (a > b ? b : a);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize a double value to a specific range.
|
* Normalize a double value to a specific range.
|
||||||
*
|
*
|
||||||
|
@ -1055,8 +1057,41 @@ array_wid_exists(const Window *arr, int count, Window wid) {
|
||||||
* Return whether a struct timeval value is empty.
|
* Return whether a struct timeval value is empty.
|
||||||
*/
|
*/
|
||||||
static inline bool
|
static inline bool
|
||||||
timeval_isempty(struct timeval tv) {
|
timeval_isempty(struct timeval *ptv) {
|
||||||
return tv.tv_sec <= 0 && tv.tv_usec <= 0;
|
if (!ptv)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return ptv->tv_sec <= 0 && ptv->tv_usec <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare a struct timeval with a time in milliseconds.
|
||||||
|
*
|
||||||
|
* @return > 0 if ptv > ms, 0 if ptv == 0, -1 if ptv < ms
|
||||||
|
*/
|
||||||
|
static inline int
|
||||||
|
timeval_ms_cmp(struct timeval *ptv, time_ms_t ms) {
|
||||||
|
assert(ptv);
|
||||||
|
|
||||||
|
// We use those if statement instead of a - expression because of possible
|
||||||
|
// truncation problem from long to int.
|
||||||
|
{
|
||||||
|
long sec = ms / MS_PER_SEC;
|
||||||
|
if (ptv->tv_sec > sec)
|
||||||
|
return 1;
|
||||||
|
if (ptv->tv_sec < sec)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
long usec = ms % MS_PER_SEC * (US_PER_SEC / MS_PER_SEC);
|
||||||
|
if (ptv->tv_usec > usec)
|
||||||
|
return 1;
|
||||||
|
if (ptv->tv_usec < usec)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1290,8 +1325,94 @@ ms_to_tv(int timeout) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
/**
|
||||||
fade_timeout(session_t *ps);
|
* Add a file descriptor to a select() fd_set.
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
fds_insert_select(fd_set **ppfds, int fd) {
|
||||||
|
assert(fd <= FD_SETSIZE);
|
||||||
|
|
||||||
|
if (!*ppfds) {
|
||||||
|
if ((*ppfds = malloc(sizeof(fd_set)))) {
|
||||||
|
FD_ZERO(*ppfds);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "Failed to allocate memory for select() fdset.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FD_SET(fd, *ppfds);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new file descriptor to wait for.
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
fds_insert(session_t *ps, int fd, short events) {
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
ps->nfds_max = max_i(fd + 1, ps->nfds_max);
|
||||||
|
|
||||||
|
if (POLLIN & events)
|
||||||
|
result = fds_insert_select(&ps->pfds_read, fd) && result;
|
||||||
|
if (POLLOUT & events)
|
||||||
|
result = fds_insert_select(&ps->pfds_write, fd) && result;
|
||||||
|
if (POLLPRI & events)
|
||||||
|
result = fds_insert_select(&ps->pfds_except, fd) && result;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a file descriptor to wait for.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
fds_drop(session_t *ps, int fd, short events) {
|
||||||
|
// Drop fd from respective fd_set-s
|
||||||
|
if (POLLIN & events)
|
||||||
|
FD_CLR(fd, ps->pfds_read);
|
||||||
|
if (POLLOUT & events)
|
||||||
|
FD_CLR(fd, ps->pfds_write);
|
||||||
|
if (POLLPRI & events)
|
||||||
|
FD_CLR(fd, ps->pfds_except);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CPY_FDS(key) \
|
||||||
|
fd_set * key = NULL; \
|
||||||
|
if (ps->key) { \
|
||||||
|
key = malloc(sizeof(fd_set)); \
|
||||||
|
memcpy(key, ps->key, sizeof(fd_set)); \
|
||||||
|
if (!key) { \
|
||||||
|
fprintf(stderr, "Failed to allocate memory for copying select() fdset.\n"); \
|
||||||
|
exit(1); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Poll for changes.
|
||||||
|
*
|
||||||
|
* poll() is much better than select(), but ppoll() does not exist on
|
||||||
|
* *BSD.
|
||||||
|
*/
|
||||||
|
static inline int
|
||||||
|
fds_poll(session_t *ps, struct timeval *ptv) {
|
||||||
|
// Copy fds
|
||||||
|
CPY_FDS(pfds_read);
|
||||||
|
CPY_FDS(pfds_write);
|
||||||
|
CPY_FDS(pfds_except);
|
||||||
|
|
||||||
|
int ret = select(ps->nfds_max, pfds_read, pfds_write, pfds_except, ptv);
|
||||||
|
|
||||||
|
free(pfds_read);
|
||||||
|
free(pfds_write);
|
||||||
|
free(pfds_except);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#undef CPY_FDS
|
||||||
|
|
||||||
static void
|
static void
|
||||||
run_fade(session_t *ps, win *w, unsigned steps);
|
run_fade(session_t *ps, win *w, unsigned steps);
|
||||||
|
@ -2030,7 +2151,7 @@ inline static void
|
||||||
ev_handle(session_t *ps, XEvent *ev);
|
ev_handle(session_t *ps, XEvent *ev);
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
fork_after(void);
|
fork_after(session_t *ps);
|
||||||
|
|
||||||
#ifdef CONFIG_LIBCONFIG
|
#ifdef CONFIG_LIBCONFIG
|
||||||
/**
|
/**
|
||||||
|
@ -2095,12 +2216,6 @@ swopti_init(session_t *ps);
|
||||||
static void
|
static void
|
||||||
swopti_handle_timeout(session_t *ps, struct timeval *ptv);
|
swopti_handle_timeout(session_t *ps, struct timeval *ptv);
|
||||||
|
|
||||||
static void
|
|
||||||
evcallback_x(evutil_socket_t fd, short what, void *arg);
|
|
||||||
|
|
||||||
static void
|
|
||||||
evcallback_null(evutil_socket_t fd, short what, void *arg);
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
vsync_drm_init(session_t *ps);
|
vsync_drm_init(session_t *ps);
|
||||||
|
|
||||||
|
@ -2135,6 +2250,22 @@ redir_start(session_t *ps);
|
||||||
static void
|
static void
|
||||||
redir_stop(session_t *ps);
|
redir_stop(session_t *ps);
|
||||||
|
|
||||||
|
static time_ms_t
|
||||||
|
timeout_get_poll_time(session_t *ps);
|
||||||
|
|
||||||
|
static timeout_t *
|
||||||
|
timeout_insert(session_t *ps, time_ms_t interval,
|
||||||
|
bool (*callback)(session_t *ps, timeout_t *ptmout), void *data);
|
||||||
|
|
||||||
|
static void
|
||||||
|
timeout_invoke(session_t *ps, timeout_t *ptmout);
|
||||||
|
|
||||||
|
static bool
|
||||||
|
timeout_drop(session_t *ps, timeout_t *prm);
|
||||||
|
|
||||||
|
static void
|
||||||
|
timeout_clear(session_t *ps);
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
mainloop(session_t *ps);
|
mainloop(session_t *ps);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue