Improvement #74: Use libevent for main loop
- Use libevent for main loop. I will explain the reasons in #56 later. The preferred libevent version is 2.x, yet 1.4.x should work as well. - As a result, compton now should build fine on *BSD. Thanks to DachiChang for the FreeBSD build issue report. - Another consequence is we now use microsecond-level timing all the way. Nanosecond-level code will be dropped soon. Start using long instead of unsigned long to represent time in milliseconds, as both can't hold the full epoch time in ms, anyway, and a signed type requires less care in subtraction. Wrap the epoch time in ms to 15 days. - Fix broken NO_VSYNC_DRM and NO_VSYNC_OPENGL compile-time options. - Use git revision number for versioning in Makefile, and other small improvements. - Reorganize struct _win. Drop unused w->damaged_sequence. w->damaged is turned to bool. - Add type and format to winprop_t, as preparation for the new condition format. - Add w->shadow_force and w->focus_force, to prepare for D-Bus support. - Rename wid_get_prop() to wid_get_prop_adv() with more options. Add wrapper function wid_get_prop(). - Add some extra helper functions, for D-Bus support later. - Make some functions return a bool value to indicate if it's successful. - Modify add_win(), use a static const structure to initialize the new struct _win. - Add some helper macros, like printf_err(f)(q). Make some errors fatal. - Rename some types, constants, and functions. Code clean-up. - Check for time disorder in paint_preprocess() when calculating fading steps. - Rename evpoll() to swopti_handle_timeout(), and partially rewrite it. - Make -h / --help legal. - Known issue: compton segfaults on FreeBSD with nvidia-drivers, unless NO_VSYNC_OPENGL is used. Will look into it later. Thamls to DachiChang for reporting.
This commit is contained in:
parent
75aec17a85
commit
3521f10a97
44
Makefile
44
Makefile
@ -1,3 +1,6 @@
|
|||||||
|
# Use tab to indent recipe lines, spaces to indent other lines, otherwise
|
||||||
|
# GNU make may get unhappy.
|
||||||
|
|
||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
|
|
||||||
PREFIX ?= /usr
|
PREFIX ?= /usr
|
||||||
@ -8,9 +11,26 @@ PACKAGES = x11 xcomposite xfixes xdamage xrender xext xrandr
|
|||||||
LIBS = -lm -lrt
|
LIBS = -lm -lrt
|
||||||
INCS =
|
INCS =
|
||||||
|
|
||||||
# Parse 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 for linking with libevent will result in linking with
|
||||||
|
# libevent.so instead of the smaller libevent_core.so. But FreeBSD keeps
|
||||||
|
# libevent2 .so files at a separate place, and we must learn it from
|
||||||
|
# pkg-config.
|
||||||
|
LIBS += $(shell pkg-config --libs libevent)
|
||||||
|
INCS += $(shell pkg-config --cflags libevent)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# ==== libconfig ====
|
||||||
ifeq "$(NO_LIBCONFIG)" ""
|
ifeq "$(NO_LIBCONFIG)" ""
|
||||||
CFG += -DCONFIG_LIBCONFIG
|
CFG += -DCONFIG_LIBCONFIG
|
||||||
PACKAGES += libconfig
|
PACKAGES += libconfig
|
||||||
@ -20,6 +40,7 @@ ifeq "$(NO_LIBCONFIG)" ""
|
|||||||
CFG += $(shell pkg-config --atleast-version=1.4 libconfig || echo '-DCONFIG_LIBCONFIG_LEGACY')
|
CFG += $(shell pkg-config --atleast-version=1.4 libconfig || echo '-DCONFIG_LIBCONFIG_LEGACY')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# ==== PCRE regular expression ====
|
||||||
ifeq "$(NO_REGEX_PCRE)" ""
|
ifeq "$(NO_REGEX_PCRE)" ""
|
||||||
CFG += -DCONFIG_REGEX_PCRE
|
CFG += -DCONFIG_REGEX_PCRE
|
||||||
LIBS += $(shell pcre-config --libs)
|
LIBS += $(shell pcre-config --libs)
|
||||||
@ -29,23 +50,40 @@ ifeq "$(NO_REGEX_PCRE)" ""
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# ==== DRM VSync ====
|
||||||
ifeq "$(NO_VSYNC_DRM)" ""
|
ifeq "$(NO_VSYNC_DRM)" ""
|
||||||
CFG += -DCONFIG_VSYNC_DRM
|
CFG += -DCONFIG_VSYNC_DRM
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# ==== OpenGL VSync ====
|
||||||
ifeq "$(NO_VSYNC_OPENGL)" ""
|
ifeq "$(NO_VSYNC_OPENGL)" ""
|
||||||
CFG += -DCONFIG_VSYNC_OPENGL
|
CFG += -DCONFIG_VSYNC_OPENGL
|
||||||
LIBS += -lGL
|
LIBS += -lGL
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CFLAGS ?= -DNDEBUG -O2 -D_FORTIFY_SOURCE=2
|
# ==== D-Bus ====
|
||||||
|
# ifeq "$(NO_DBUS)" ""
|
||||||
|
# CFG += -DCONFIG_DBUS
|
||||||
|
# PACKAGES += dbus-1
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# === Version string ===
|
||||||
|
COMPTON_VERSION ?= git-$(shell git describe --always)
|
||||||
|
CFG += -DCOMPTON_VERSION="\"$(COMPTON_VERSION)\""
|
||||||
|
|
||||||
|
LDFLAGS ?= -Wl,-O1 -Wl,--as-needed
|
||||||
|
CFLAGS ?= -DNDEBUG -O2 -D_FORTIFY_SOURCE=2 $(LDFLAGS)
|
||||||
CFLAGS += $(CFG)
|
CFLAGS += $(CFG)
|
||||||
|
|
||||||
LIBS += $(shell pkg-config --libs $(PACKAGES))
|
LIBS += $(shell pkg-config --libs $(PACKAGES))
|
||||||
INCS += $(shell pkg-config --cflags $(PACKAGES))
|
INCS += $(shell pkg-config --cflags $(PACKAGES))
|
||||||
|
|
||||||
CFLAGS += -Wall -std=c99
|
CFLAGS += -Wall -std=c99
|
||||||
OBJS = compton.o
|
OBJS = compton.o
|
||||||
|
|
||||||
|
# === Recipes ===
|
||||||
|
.DEFAULT_GOAL := compton
|
||||||
|
|
||||||
%.o: src/%.c src/%.h
|
%.o: src/%.c src/%.h
|
||||||
$(CC) $(CFLAGS) $(INCS) -c src/$*.c
|
$(CC) $(CFLAGS) $(INCS) -c src/$*.c
|
||||||
|
|
||||||
@ -75,4 +113,4 @@ uninstall:
|
|||||||
clean:
|
clean:
|
||||||
@rm -f $(OBJS) compton
|
@rm -f $(OBJS) compton
|
||||||
|
|
||||||
.PHONY: uninstall clean
|
.PHONY: uninstall clean docs
|
||||||
|
@ -56,6 +56,7 @@ __R__ for runtime
|
|||||||
* 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) (if you wish to run `make docs`)
|
||||||
|
* libevent (B,R)
|
||||||
|
|
||||||
### How to build
|
### How to build
|
||||||
|
|
||||||
|
479
src/compton.c
479
src/compton.c
@ -1196,15 +1196,19 @@ paint_preprocess(session_t *ps, win *list) {
|
|||||||
bool is_highest = true;
|
bool is_highest = true;
|
||||||
|
|
||||||
// Fading step calculation
|
// Fading step calculation
|
||||||
unsigned steps = (sub_unslong(get_time_ms(), ps->fade_time)
|
time_ms_t steps = ((get_time_ms() - ps->fade_time) + FADE_DELTA_TOLERANCE * ps->o.fade_delta) / ps->o.fade_delta;
|
||||||
+ FADE_DELTA_TOLERANCE * ps->o.fade_delta) / ps->o.fade_delta;
|
if (steps < 0L) {
|
||||||
|
// Time disorder
|
||||||
|
ps->fade_time = get_time_ms();
|
||||||
|
steps = 0;
|
||||||
|
}
|
||||||
ps->fade_time += steps * ps->o.fade_delta;
|
ps->fade_time += steps * ps->o.fade_delta;
|
||||||
|
|
||||||
XserverRegion last_reg_ignore = None;
|
XserverRegion last_reg_ignore = None;
|
||||||
|
|
||||||
for (w = list; w; w = next) {
|
for (w = list; w; w = next) {
|
||||||
bool to_paint = true;
|
bool to_paint = true;
|
||||||
const winmode mode_old = w->mode;
|
const winmode_t mode_old = w->mode;
|
||||||
|
|
||||||
// In case calling the fade callback function destroys this window
|
// In case calling the fade callback function destroys this window
|
||||||
next = w->next;
|
next = w->next;
|
||||||
@ -1274,7 +1278,7 @@ paint_preprocess(session_t *ps, win *list) {
|
|||||||
else
|
else
|
||||||
w->frame_opacity = 0.0;
|
w->frame_opacity = 0.0;
|
||||||
|
|
||||||
if (w->to_paint && WINDOW_SOLID == mode_old
|
if (w->to_paint && WMODE_SOLID == mode_old
|
||||||
&& (0.0 == frame_opacity_old) != (0.0 == w->frame_opacity))
|
&& (0.0 == frame_opacity_old) != (0.0 == w->frame_opacity))
|
||||||
ps->reg_ignore_expire = true;
|
ps->reg_ignore_expire = true;
|
||||||
}
|
}
|
||||||
@ -1308,8 +1312,8 @@ paint_preprocess(session_t *ps, win *list) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((to_paint && WINDOW_SOLID == w->mode)
|
if ((to_paint && WMODE_SOLID == w->mode)
|
||||||
!= (w->to_paint && WINDOW_SOLID == mode_old))
|
!= (w->to_paint && WMODE_SOLID == mode_old))
|
||||||
ps->reg_ignore_expire = true;
|
ps->reg_ignore_expire = true;
|
||||||
|
|
||||||
// Add window to damaged area if its painting status changes
|
// Add window to damaged area if its painting status changes
|
||||||
@ -1323,7 +1327,7 @@ paint_preprocess(session_t *ps, win *list) {
|
|||||||
|
|
||||||
// If the window is solid, we add the window region to the
|
// If the window is solid, we add the window region to the
|
||||||
// ignored region
|
// ignored region
|
||||||
if (WINDOW_SOLID == w->mode) {
|
if (WMODE_SOLID == w->mode) {
|
||||||
if (!w->frame_opacity) {
|
if (!w->frame_opacity) {
|
||||||
if (w->border_size)
|
if (w->border_size)
|
||||||
w->reg_ignore = copy_region(ps, w->border_size);
|
w->reg_ignore = copy_region(ps, w->border_size);
|
||||||
@ -1352,7 +1356,7 @@ paint_preprocess(session_t *ps, win *list) {
|
|||||||
|
|
||||||
if (is_highest && to_paint) {
|
if (is_highest && to_paint) {
|
||||||
is_highest = false;
|
is_highest = false;
|
||||||
if (WINDOW_SOLID == w->mode
|
if (WMODE_SOLID == w->mode
|
||||||
&& (!w->frame_opacity || !win_has_frame(w))
|
&& (!w->frame_opacity || !win_has_frame(w))
|
||||||
&& win_is_fullscreen(ps, w))
|
&& win_is_fullscreen(ps, w))
|
||||||
ps->unredir_possible = true;
|
ps->unredir_possible = true;
|
||||||
@ -1473,7 +1477,7 @@ win_blur_background(session_t *ps, win *w, Picture tgt_buffer,
|
|||||||
|
|
||||||
// Minimize the region we try to blur, if the window itself is not
|
// Minimize the region we try to blur, if the window itself is not
|
||||||
// opaque, only the frame is.
|
// opaque, only the frame is.
|
||||||
if (WINDOW_SOLID == w->mode && w->frame_opacity) {
|
if (WMODE_SOLID == w->mode && w->frame_opacity) {
|
||||||
XserverRegion reg_all = border_size(ps, w, false);
|
XserverRegion reg_all = border_size(ps, w, false);
|
||||||
XserverRegion reg_noframe = win_get_region_noframe(ps, w, false);
|
XserverRegion reg_noframe = win_get_region_noframe(ps, w, false);
|
||||||
XFixesSubtractRegion(ps->dpy, reg_noframe, reg_all, reg_noframe);
|
XFixesSubtractRegion(ps->dpy, reg_noframe, reg_all, reg_noframe);
|
||||||
@ -1506,7 +1510,7 @@ win_paint_win(session_t *ps, win *w, Picture tgt_buffer) {
|
|||||||
int hei = w->heightb;
|
int hei = w->heightb;
|
||||||
|
|
||||||
Picture alpha_mask = (OPAQUE == w->opacity ? None: w->alpha_pict);
|
Picture alpha_mask = (OPAQUE == w->opacity ? None: w->alpha_pict);
|
||||||
int op = (w->mode == WINDOW_SOLID ? PictOpSrc: PictOpOver);
|
int op = (w->mode == WMODE_SOLID ? PictOpSrc: PictOpOver);
|
||||||
|
|
||||||
if (!w->frame_opacity) {
|
if (!w->frame_opacity) {
|
||||||
XRenderComposite(ps->dpy, op, w->picture, alpha_mask,
|
XRenderComposite(ps->dpy, op, w->picture, alpha_mask,
|
||||||
@ -1713,7 +1717,7 @@ paint_all(session_t *ps, XserverRegion region, win *t) {
|
|||||||
if (!is_region_empty(ps, reg_paint)) {
|
if (!is_region_empty(ps, reg_paint)) {
|
||||||
XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer, 0, 0, reg_paint);
|
XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer, 0, 0, reg_paint);
|
||||||
// Blur window background
|
// Blur window background
|
||||||
if ((ps->o.blur_background && WINDOW_SOLID != w->mode)
|
if ((ps->o.blur_background && WMODE_SOLID != w->mode)
|
||||||
|| (ps->o.blur_background_frame && w->frame_opacity)) {
|
|| (ps->o.blur_background_frame && w->frame_opacity)) {
|
||||||
win_blur_background(ps, w, ps->tgt_buffer, reg_paint);
|
win_blur_background(ps, w, ps->tgt_buffer, reg_paint);
|
||||||
}
|
}
|
||||||
@ -1815,7 +1819,7 @@ repair_win(session_t *ps, win *w) {
|
|||||||
XFixesSubtractRegion(ps->dpy, parts, parts, w->prev_trans->reg_ignore);
|
XFixesSubtractRegion(ps->dpy, parts, parts, w->prev_trans->reg_ignore);
|
||||||
|
|
||||||
add_damage(ps, parts);
|
add_damage(ps, parts);
|
||||||
w->damaged = 1;
|
w->damaged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static wintype_t
|
static wintype_t
|
||||||
@ -1916,7 +1920,7 @@ map_win(session_t *ps, Window id) {
|
|||||||
|
|
||||||
// Check for _COMPTON_SHADOW
|
// Check for _COMPTON_SHADOW
|
||||||
if (ps->o.respect_prop_shadow)
|
if (ps->o.respect_prop_shadow)
|
||||||
win_update_attr_shadow_raw(ps, w);
|
win_update_prop_shadow_raw(ps, w);
|
||||||
|
|
||||||
// Many things above could affect shadow
|
// Many things above could affect shadow
|
||||||
determine_shadow(ps, w);
|
determine_shadow(ps, w);
|
||||||
@ -1933,7 +1937,7 @@ map_win(session_t *ps, Window id) {
|
|||||||
determine_fade(ps, w);
|
determine_fade(ps, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
w->damaged = 1;
|
w->damaged = true;
|
||||||
|
|
||||||
|
|
||||||
/* if any configure events happened while
|
/* if any configure events happened while
|
||||||
@ -1952,7 +1956,7 @@ finish_map_win(session_t *ps, win *w) {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
finish_unmap_win(session_t *ps, win *w) {
|
finish_unmap_win(session_t *ps, win *w) {
|
||||||
w->damaged = 0;
|
w->damaged = false;
|
||||||
|
|
||||||
update_reg_ignore_expire(ps, w);
|
update_reg_ignore_expire(ps, w);
|
||||||
|
|
||||||
@ -2016,7 +2020,7 @@ get_opacity_percent(win *w) {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
determine_mode(session_t *ps, win *w) {
|
determine_mode(session_t *ps, win *w) {
|
||||||
winmode mode;
|
winmode_t mode = WMODE_SOLID;
|
||||||
XRenderPictFormat *format;
|
XRenderPictFormat *format;
|
||||||
|
|
||||||
/* if trans prop == -1 fall back on previous tests */
|
/* if trans prop == -1 fall back on previous tests */
|
||||||
@ -2029,11 +2033,11 @@ determine_mode(session_t *ps, win *w) {
|
|||||||
|
|
||||||
if (format && format->type == PictTypeDirect
|
if (format && format->type == PictTypeDirect
|
||||||
&& format->direct.alphaMask) {
|
&& format->direct.alphaMask) {
|
||||||
mode = WINDOW_ARGB;
|
mode = WMODE_ARGB;
|
||||||
} else if (w->opacity != OPAQUE) {
|
} else if (w->opacity != OPAQUE) {
|
||||||
mode = WINDOW_TRANS;
|
mode = WMODE_TRANS;
|
||||||
} else {
|
} else {
|
||||||
mode = WINDOW_SOLID;
|
mode = WMODE_SOLID;
|
||||||
}
|
}
|
||||||
|
|
||||||
w->mode = mode;
|
w->mode = mode;
|
||||||
@ -2153,15 +2157,15 @@ win_update_shape(session_t *ps, win *w) {
|
|||||||
* The property must be set on the outermost window, usually the WM frame.
|
* The property must be set on the outermost window, usually the WM frame.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
win_update_attr_shadow_raw(session_t *ps, win *w) {
|
win_update_prop_shadow_raw(session_t *ps, win *w) {
|
||||||
winprop_t prop = wid_get_prop(ps, w->id, ps->atom_compton_shadow, 1,
|
winprop_t prop = wid_get_prop(ps, w->id, ps->atom_compton_shadow, 1,
|
||||||
XA_CARDINAL, 32);
|
XA_CARDINAL, 32);
|
||||||
|
|
||||||
if (!prop.nitems) {
|
if (!prop.nitems) {
|
||||||
w->attr_shadow = -1;
|
w->prop_shadow = -1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
w->attr_shadow = *prop.data.p32;
|
w->prop_shadow = *prop.data.p32;
|
||||||
}
|
}
|
||||||
|
|
||||||
free_winprop(&prop);
|
free_winprop(&prop);
|
||||||
@ -2172,12 +2176,12 @@ win_update_attr_shadow_raw(session_t *ps, win *w) {
|
|||||||
* things.
|
* things.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
win_update_attr_shadow(session_t *ps, win *w) {
|
win_update_prop_shadow(session_t *ps, win *w) {
|
||||||
long attr_shadow_old = w->attr_shadow;
|
long attr_shadow_old = w->prop_shadow;
|
||||||
|
|
||||||
win_update_attr_shadow_raw(ps, w);
|
win_update_prop_shadow_raw(ps, w);
|
||||||
|
|
||||||
if (w->attr_shadow != attr_shadow_old)
|
if (w->prop_shadow != attr_shadow_old)
|
||||||
determine_shadow(ps, w);
|
determine_shadow(ps, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2189,11 +2193,13 @@ static void
|
|||||||
determine_shadow(session_t *ps, win *w) {
|
determine_shadow(session_t *ps, win *w) {
|
||||||
bool shadow_old = w->shadow;
|
bool shadow_old = w->shadow;
|
||||||
|
|
||||||
w->shadow = (ps->o.wintype_shadow[w->window_type]
|
w->shadow = (UNSET == w->shadow_force ?
|
||||||
|
(ps->o.wintype_shadow[w->window_type]
|
||||||
&& !win_match(w, ps->o.shadow_blacklist, &w->cache_sblst)
|
&& !win_match(w, ps->o.shadow_blacklist, &w->cache_sblst)
|
||||||
&& !(ps->o.shadow_ignore_shaped && w->bounding_shaped
|
&& !(ps->o.shadow_ignore_shaped && w->bounding_shaped
|
||||||
&& !w->rounded_corners)
|
&& !w->rounded_corners)
|
||||||
&& !(ps->o.respect_prop_shadow && 0 == w->attr_shadow));
|
&& !(ps->o.respect_prop_shadow && 0 == w->prop_shadow))
|
||||||
|
: w->shadow_force);
|
||||||
|
|
||||||
// Window extents need update on shadow state change
|
// Window extents need update on shadow state change
|
||||||
if (w->shadow != shadow_old) {
|
if (w->shadow != shadow_old) {
|
||||||
@ -2340,18 +2346,98 @@ win_recheck_client(session_t *ps, win *w) {
|
|||||||
win_mark_client(ps, w, cw);
|
win_mark_client(ps, w, cw);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static bool
|
||||||
add_win(session_t *ps, Window id, Window prev) {
|
add_win(session_t *ps, Window id, Window prev) {
|
||||||
|
const static win win_def = {
|
||||||
|
.next = NULL,
|
||||||
|
.prev_trans = NULL,
|
||||||
|
|
||||||
|
.id = None,
|
||||||
|
.a = { },
|
||||||
|
.mode = WMODE_TRANS,
|
||||||
|
.damaged = false,
|
||||||
|
.damage = None,
|
||||||
|
.pixmap = None,
|
||||||
|
.picture = None,
|
||||||
|
.border_size = None,
|
||||||
|
.extents = None,
|
||||||
|
.flags = 0,
|
||||||
|
.need_configure = false,
|
||||||
|
.queue_configure = { },
|
||||||
|
.reg_ignore = None,
|
||||||
|
.destroyed = false,
|
||||||
|
.widthb = 0,
|
||||||
|
.heightb = 0,
|
||||||
|
.bounding_shaped = false,
|
||||||
|
.rounded_corners = false,
|
||||||
|
.to_paint = false,
|
||||||
|
|
||||||
|
.client_win = None,
|
||||||
|
.window_type = WINTYPE_UNKNOWN,
|
||||||
|
.wmwin = false,
|
||||||
|
.leader = None,
|
||||||
|
.cache_leader = None,
|
||||||
|
|
||||||
|
.focused = false,
|
||||||
|
.focused_force = UNSET,
|
||||||
|
.focused_real = false,
|
||||||
|
|
||||||
|
.name = NULL,
|
||||||
|
.class_instance = NULL,
|
||||||
|
.class_general = NULL,
|
||||||
|
.role = NULL,
|
||||||
|
.cache_sblst = NULL,
|
||||||
|
.cache_fblst = NULL,
|
||||||
|
.cache_fcblst = NULL,
|
||||||
|
|
||||||
|
.opacity = 0,
|
||||||
|
.opacity_tgt = 0,
|
||||||
|
.opacity_prop = OPAQUE,
|
||||||
|
.opacity_prop_client = OPAQUE,
|
||||||
|
.alpha_pict = None,
|
||||||
|
|
||||||
|
.fade = false,
|
||||||
|
.fade_callback = NULL,
|
||||||
|
|
||||||
|
.frame_opacity = 0.0,
|
||||||
|
.frame_alpha_pict = None,
|
||||||
|
.left_width = 0,
|
||||||
|
.right_width = 0,
|
||||||
|
.top_width = 0,
|
||||||
|
.bottom_width = 0,
|
||||||
|
|
||||||
|
.shadow = false,
|
||||||
|
.shadow_force = UNSET,
|
||||||
|
.shadow_opacity = 0.0,
|
||||||
|
.shadow_dx = 0,
|
||||||
|
.shadow_dy = 0,
|
||||||
|
.shadow_width = 0,
|
||||||
|
.shadow_height = 0,
|
||||||
|
.shadow_pict = None,
|
||||||
|
.shadow_alpha_pict = None,
|
||||||
|
.prop_shadow = -1,
|
||||||
|
|
||||||
|
.dim = false,
|
||||||
|
.dim_alpha_pict = None,
|
||||||
|
};
|
||||||
|
|
||||||
// Reject overlay window and already added windows
|
// Reject overlay window and already added windows
|
||||||
if (id == ps->overlay || find_win(ps, id)) {
|
if (id == ps->overlay || find_win(ps, id)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allocate and initialize the new win structure
|
||||||
win *new = malloc(sizeof(win));
|
win *new = malloc(sizeof(win));
|
||||||
win **p;
|
|
||||||
|
|
||||||
if (!new) return;
|
if (!new) {
|
||||||
|
printf_errf("(%#010lx): Failed to allocate memory for the new window.", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(new, &win_def, sizeof(win));
|
||||||
|
|
||||||
|
// Find window insertion point
|
||||||
|
win **p = NULL;
|
||||||
if (prev) {
|
if (prev) {
|
||||||
for (p = &ps->list; *p; p = &(*p)->next) {
|
for (p = &ps->list; *p; p = &(*p)->next) {
|
||||||
if ((*p)->id == prev && !(*p)->destroyed)
|
if ((*p)->id == prev && !(*p)->destroyed)
|
||||||
@ -2361,12 +2447,15 @@ add_win(session_t *ps, Window id, Window prev) {
|
|||||||
p = &ps->list;
|
p = &ps->list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fill structure
|
||||||
new->id = id;
|
new->id = id;
|
||||||
set_ignore_next(ps);
|
set_ignore_next(ps);
|
||||||
|
|
||||||
if (!XGetWindowAttributes(ps->dpy, id, &new->a)) {
|
if (!XGetWindowAttributes(ps->dpy, id, &new->a)) {
|
||||||
|
// Failed to get window attributes. Which probably means, the window
|
||||||
|
// is gone already.
|
||||||
free(new);
|
free(new);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delay window mapping
|
// Delay window mapping
|
||||||
@ -2374,76 +2463,12 @@ add_win(session_t *ps, Window id, Window prev) {
|
|||||||
assert(IsViewable == map_state || IsUnmapped == map_state);
|
assert(IsViewable == map_state || IsUnmapped == map_state);
|
||||||
new->a.map_state = IsUnmapped;
|
new->a.map_state = IsUnmapped;
|
||||||
|
|
||||||
new->damaged = 0;
|
// Create Damage for window
|
||||||
new->to_paint = false;
|
if (InputOutput == new->a.class) {
|
||||||
new->pixmap = None;
|
|
||||||
new->picture = None;
|
|
||||||
|
|
||||||
if (new->a.class == InputOnly) {
|
|
||||||
new->damage_sequence = 0;
|
|
||||||
new->damage = None;
|
|
||||||
} else {
|
|
||||||
new->damage_sequence = NextRequest(ps->dpy);
|
|
||||||
set_ignore_next(ps);
|
set_ignore_next(ps);
|
||||||
new->damage = XDamageCreate(ps->dpy, id, XDamageReportNonEmpty);
|
new->damage = XDamageCreate(ps->dpy, id, XDamageReportNonEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
new->name = NULL;
|
|
||||||
new->class_instance = NULL;
|
|
||||||
new->class_general = NULL;
|
|
||||||
new->role = NULL;
|
|
||||||
new->cache_sblst = NULL;
|
|
||||||
new->cache_fblst = NULL;
|
|
||||||
new->cache_fcblst = NULL;
|
|
||||||
new->bounding_shaped = false;
|
|
||||||
new->rounded_corners = false;
|
|
||||||
|
|
||||||
new->border_size = None;
|
|
||||||
new->reg_ignore = None;
|
|
||||||
new->extents = None;
|
|
||||||
new->shadow = false;
|
|
||||||
new->shadow_opacity = 0.0;
|
|
||||||
new->shadow_pict = None;
|
|
||||||
new->shadow_alpha_pict = None;
|
|
||||||
new->shadow_dx = 0;
|
|
||||||
new->shadow_dy = 0;
|
|
||||||
new->shadow_width = 0;
|
|
||||||
new->shadow_height = 0;
|
|
||||||
new->opacity = 0;
|
|
||||||
new->opacity_tgt = 0;
|
|
||||||
new->opacity_prop = OPAQUE;
|
|
||||||
new->opacity_prop_client = OPAQUE;
|
|
||||||
new->fade = false;
|
|
||||||
new->fade_callback = NULL;
|
|
||||||
new->alpha_pict = None;
|
|
||||||
new->frame_opacity = 1.0;
|
|
||||||
new->frame_alpha_pict = None;
|
|
||||||
|
|
||||||
new->dim = false;
|
|
||||||
new->dim_alpha_pict = None;
|
|
||||||
|
|
||||||
new->focused = false;
|
|
||||||
new->focused_real = false;
|
|
||||||
new->leader = None;
|
|
||||||
new->cache_leader = None;
|
|
||||||
new->destroyed = false;
|
|
||||||
new->need_configure = false;
|
|
||||||
new->window_type = WINTYPE_UNKNOWN;
|
|
||||||
new->mode = WINDOW_TRANS;
|
|
||||||
new->attr_shadow = -1;
|
|
||||||
|
|
||||||
new->prev_trans = NULL;
|
|
||||||
|
|
||||||
new->left_width = 0;
|
|
||||||
new->right_width = 0;
|
|
||||||
new->top_width = 0;
|
|
||||||
new->bottom_width = 0;
|
|
||||||
|
|
||||||
new->client_win = 0;
|
|
||||||
new->wmwin = false;
|
|
||||||
|
|
||||||
new->flags = 0;
|
|
||||||
|
|
||||||
calc_win_size(ps, new);
|
calc_win_size(ps, new);
|
||||||
|
|
||||||
new->next = *p;
|
new->next = *p;
|
||||||
@ -2452,6 +2477,8 @@ add_win(session_t *ps, Window id, Window prev) {
|
|||||||
if (map_state == IsViewable) {
|
if (map_state == IsViewable) {
|
||||||
map_win(ps, id);
|
map_win(ps, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -2790,6 +2817,10 @@ static void
|
|||||||
win_update_focused(session_t *ps, win *w) {
|
win_update_focused(session_t *ps, win *w) {
|
||||||
bool focused_old = w->focused;
|
bool focused_old = w->focused;
|
||||||
|
|
||||||
|
if (UNSET != w->focused_force) {
|
||||||
|
w->focused = w->focused_force;
|
||||||
|
}
|
||||||
|
else {
|
||||||
w->focused = w->focused_real;
|
w->focused = w->focused_real;
|
||||||
|
|
||||||
// Use wintype_focus, and treat WM windows and override-redirected
|
// Use wintype_focus, and treat WM windows and override-redirected
|
||||||
@ -2807,6 +2838,7 @@ win_update_focused(session_t *ps, win *w) {
|
|||||||
&& win_get_leader(ps, w) == ps->active_leader) {
|
&& win_get_leader(ps, w) == ps->active_leader) {
|
||||||
w->focused = true;
|
w->focused = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (w->focused != focused_old)
|
if (w->focused != focused_old)
|
||||||
w->flags |= WFLAG_OPCT_CHANGE;
|
w->flags |= WFLAG_OPCT_CHANGE;
|
||||||
@ -3471,7 +3503,7 @@ ev_property_notify(session_t *ps, XPropertyEvent *ev) {
|
|||||||
if (ps->o.respect_prop_shadow && ps->atom_compton_shadow == ev->atom) {
|
if (ps->o.respect_prop_shadow && ps->atom_compton_shadow == ev->atom) {
|
||||||
win *w = find_win(ps, ev->window);
|
win *w = find_win(ps, ev->window);
|
||||||
if (w)
|
if (w)
|
||||||
win_update_attr_shadow(ps, w);
|
win_update_prop_shadow(ps, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a leader property changes
|
// If a leader property changes
|
||||||
@ -3649,7 +3681,7 @@ ev_handle(session_t *ps, XEvent *ev) {
|
|||||||
static void
|
static void
|
||||||
usage(void) {
|
usage(void) {
|
||||||
const static char *usage_text =
|
const static char *usage_text =
|
||||||
"compton (development version)\n"
|
"compton (" COMPTON_VERSION ")\n"
|
||||||
"usage: compton [options]\n"
|
"usage: compton [options]\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -3888,15 +3920,16 @@ register_cm(session_t *ps, bool want_glxct) {
|
|||||||
/**
|
/**
|
||||||
* Fork program to background and disable all I/O streams.
|
* Fork program to background and disable all I/O streams.
|
||||||
*/
|
*/
|
||||||
static void
|
static bool
|
||||||
fork_after(void) {
|
fork_after(void) {
|
||||||
if (getppid() == 1) return;
|
if (getppid() == 1)
|
||||||
|
return true;
|
||||||
|
|
||||||
int pid = fork();
|
int pid = fork();
|
||||||
|
|
||||||
if (pid == -1) {
|
if (-1 == pid) {
|
||||||
fprintf(stderr, "Fork failed\n");
|
printf_errf("(): fork() failed.");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pid > 0) _exit(0);
|
if (pid > 0) _exit(0);
|
||||||
@ -3906,11 +3939,17 @@ 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;
|
success = freopen("/dev/null", "w", stdout) && success;
|
||||||
if (!success)
|
if (!success) {
|
||||||
fprintf(stderr, "fork_after(): freopen() failed.");
|
printf_errf("(): freopen() failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
success = freopen("/dev/null", "w", stderr);
|
success = freopen("/dev/null", "w", stderr);
|
||||||
if (!success)
|
if (!success) {
|
||||||
fprintf(stderr, "fork_after(): freopen() failed.");
|
printf_errf("(): freopen() failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_LIBCONFIG
|
#ifdef CONFIG_LIBCONFIG
|
||||||
@ -4059,7 +4098,7 @@ parse_config(session_t *ps, char *cpath, struct options_tmp *pcfgtmp) {
|
|||||||
f = open_config_file(cpath, &path);
|
f = open_config_file(cpath, &path);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
if (cpath)
|
if (cpath)
|
||||||
printf("Failed to read the specified configuration file.\n");
|
printf_errfq(1, "(): Failed to read the specified configuration file.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4223,8 +4262,9 @@ parse_config(session_t *ps, char *cpath, struct options_tmp *pcfgtmp) {
|
|||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
get_cfg(session_t *ps, int argc, char *const *argv) {
|
get_cfg(session_t *ps, int argc, char *const *argv) {
|
||||||
const static char *shortopts = "D:I:O:d:r:o:m:l:t:i:e:scnfFCaSzGb";
|
const static char *shortopts = "D:I:O:d:r:o:m:l:t:i:e:hscnfFCaSzGb";
|
||||||
const static struct option longopts[] = {
|
const static struct option longopts[] = {
|
||||||
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ "config", required_argument, NULL, 256 },
|
{ "config", required_argument, NULL, 256 },
|
||||||
{ "shadow-red", required_argument, NULL, 257 },
|
{ "shadow-red", required_argument, NULL, 257 },
|
||||||
{ "shadow-green", required_argument, NULL, 258 },
|
{ "shadow-green", required_argument, NULL, 258 },
|
||||||
@ -4255,6 +4295,7 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
|
|||||||
{ "blur-background", no_argument, NULL, 283 },
|
{ "blur-background", no_argument, NULL, 283 },
|
||||||
{ "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 },
|
||||||
// Must terminate with a NULL entry
|
// Must terminate with a NULL entry
|
||||||
{ NULL, 0, NULL, 0 },
|
{ NULL, 0, NULL, 0 },
|
||||||
};
|
};
|
||||||
@ -4303,6 +4344,9 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
|
|||||||
(o = getopt_long(argc, argv, shortopts, longopts, &longopt_idx))) {
|
(o = getopt_long(argc, argv, shortopts, longopts, &longopt_idx))) {
|
||||||
switch (o) {
|
switch (o) {
|
||||||
// Short options
|
// Short options
|
||||||
|
case 'h':
|
||||||
|
usage();
|
||||||
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
ps->o.display = mstrcpy(optarg);
|
ps->o.display = mstrcpy(optarg);
|
||||||
break;
|
break;
|
||||||
@ -4484,6 +4528,10 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
|
|||||||
// --blur-background-fixed
|
// --blur-background-fixed
|
||||||
ps->o.blur_background_fixed = true;
|
ps->o.blur_background_fixed = true;
|
||||||
break;
|
break;
|
||||||
|
case 286:
|
||||||
|
// --dbus
|
||||||
|
ps->o.dbus = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
@ -4609,7 +4657,7 @@ update_refresh_rate(session_t *ps) {
|
|||||||
XRRFreeScreenConfigInfo(randr_info);
|
XRRFreeScreenConfigInfo(randr_info);
|
||||||
|
|
||||||
if (ps->refresh_rate)
|
if (ps->refresh_rate)
|
||||||
ps->refresh_intv = NS_PER_SEC / ps->refresh_rate;
|
ps->refresh_intv = US_PER_SEC / ps->refresh_rate;
|
||||||
else
|
else
|
||||||
ps->refresh_intv = 0;
|
ps->refresh_intv = 0;
|
||||||
}
|
}
|
||||||
@ -4620,12 +4668,12 @@ update_refresh_rate(session_t *ps) {
|
|||||||
* @return true for success, false otherwise
|
* @return true for success, false otherwise
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
sw_opti_init(session_t *ps) {
|
swopti_init(session_t *ps) {
|
||||||
// Prepare refresh rate
|
// Prepare refresh rate
|
||||||
// Check if user provides one
|
// Check if user provides one
|
||||||
ps->refresh_rate = ps->o.refresh_rate;
|
ps->refresh_rate = ps->o.refresh_rate;
|
||||||
if (ps->refresh_rate)
|
if (ps->refresh_rate)
|
||||||
ps->refresh_intv = NS_PER_SEC / ps->refresh_rate;
|
ps->refresh_intv = US_PER_SEC / ps->refresh_rate;
|
||||||
|
|
||||||
// Auto-detect refresh rate otherwise
|
// Auto-detect refresh rate otherwise
|
||||||
if (!ps->refresh_rate && ps->randr_exists) {
|
if (!ps->refresh_rate && ps->randr_exists) {
|
||||||
@ -4661,61 +4709,62 @@ lceil_ntimes(long dividend, long divisor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait for events until next paint.
|
* Modify a struct timeval timeout value to render at a fixed pace.
|
||||||
*
|
*
|
||||||
* Optionally use refresh-rate based optimization to reduce painting.
|
* @param ps current session
|
||||||
*
|
* @param[in,out] ptv pointer to the timeout
|
||||||
* @param fd struct pollfd used for poll()
|
|
||||||
* @param timeout second timeout (fading timeout)
|
|
||||||
* @return > 0 if we get some events, 0 if timeout is reached, < 0 on
|
|
||||||
* problems
|
|
||||||
*/
|
*/
|
||||||
static int
|
static void
|
||||||
evpoll(session_t *ps, int timeout) {
|
swopti_handle_timeout(session_t *ps, struct timeval *ptv) {
|
||||||
struct pollfd ufd = {
|
if (!ptv)
|
||||||
.fd = ConnectionNumber(ps->dpy),
|
return;
|
||||||
.events = POLLIN
|
|
||||||
};
|
|
||||||
|
|
||||||
// Always wait infinitely if asked so, to minimize CPU usage
|
// Get the microsecond offset of the time when the we reach the timeout
|
||||||
if (timeout < 0) {
|
|
||||||
int ret = poll(&ufd, 1, timeout);
|
|
||||||
// Reset ps->fade_time so the fading steps during idling are not counted
|
|
||||||
ps->fade_time = get_time_ms();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just do a poll() if we are not using optimization
|
|
||||||
if (!ps->o.sw_opti)
|
|
||||||
return poll(&ufd, 1, timeout);
|
|
||||||
|
|
||||||
// Convert the old timeout to struct timespec
|
|
||||||
struct timespec next_paint_tmout = {
|
|
||||||
.tv_sec = timeout / MS_PER_SEC,
|
|
||||||
.tv_nsec = timeout % MS_PER_SEC * (NS_PER_SEC / MS_PER_SEC)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get the nanosecond offset of the time when the we reach the timeout
|
|
||||||
// I don't think a 32-bit long could overflow here.
|
// I don't think a 32-bit long could overflow here.
|
||||||
long target_relative_offset = (next_paint_tmout.tv_nsec + get_time_timespec().tv_nsec - ps->paint_tm_offset) % NS_PER_SEC;
|
long offset = (ptv->tv_usec + get_time_timeval().tv_usec - ps->paint_tm_offset) % ps->refresh_intv;
|
||||||
if (target_relative_offset < 0)
|
if (offset < 0)
|
||||||
target_relative_offset += NS_PER_SEC;
|
offset += ps->refresh_intv;
|
||||||
|
|
||||||
assert(target_relative_offset >= 0);
|
assert(offset >= 0 && offset < ps->refresh_intv);
|
||||||
|
|
||||||
// If the target time is sufficiently close to a refresh time, don't add
|
// If the target time is sufficiently close to a refresh time, don't add
|
||||||
// an offset, to avoid certain blocking conditions.
|
// an offset, to avoid certain blocking conditions.
|
||||||
if ((target_relative_offset % NS_PER_SEC) < SW_OPTI_TOLERANCE)
|
if (offset < SWOPTI_TOLERANCE
|
||||||
return poll(&ufd, 1, timeout);
|
|| offset > ps->refresh_intv - SWOPTI_TOLERANCE)
|
||||||
|
return;
|
||||||
|
|
||||||
// Add an offset so we wait until the next refresh after timeout
|
// Add an offset so we wait until the next refresh after timeout
|
||||||
next_paint_tmout.tv_nsec += lceil_ntimes(target_relative_offset, ps->refresh_intv) - target_relative_offset;
|
ptv->tv_usec += ps->refresh_intv - offset;
|
||||||
if (next_paint_tmout.tv_nsec > NS_PER_SEC) {
|
if (ptv->tv_usec > US_PER_SEC) {
|
||||||
next_paint_tmout.tv_nsec -= NS_PER_SEC;
|
ptv->tv_usec -= US_PER_SEC;
|
||||||
++next_paint_tmout.tv_sec;
|
++ptv->tv_sec;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ppoll(&ufd, 1, &next_paint_tmout, NULL);
|
/**
|
||||||
|
* 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) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -4981,6 +5030,45 @@ redir_stop(session_t *ps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main loop.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
mainloop(session_t *ps) {
|
||||||
|
bool infinite_wait = false;
|
||||||
|
|
||||||
|
// Process existing events
|
||||||
|
if (XEventsQueued(ps->dpy, QueuedAfterReading)) {
|
||||||
|
evcallback_x(ConnectionNumber(ps->dpy), 0, NULL);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add timeout
|
||||||
|
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;
|
||||||
|
evtimer_add(ps->ev_tmout, &tv);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
infinite_wait = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run libevent main loop
|
||||||
|
if (event_base_loop(ps->ev_base, EVLOOP_ONCE))
|
||||||
|
printf_errfq(1, "(): Unexpected error when running event loop.");
|
||||||
|
|
||||||
|
evtimer_del(ps->ev_tmout);
|
||||||
|
|
||||||
|
if (infinite_wait)
|
||||||
|
ps->fade_time = get_time_ms();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize a session.
|
* Initialize a session.
|
||||||
*
|
*
|
||||||
@ -5097,11 +5185,15 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||||||
.refresh_intv = 0UL,
|
.refresh_intv = 0UL,
|
||||||
.paint_tm_offset = 0L,
|
.paint_tm_offset = 0L,
|
||||||
|
|
||||||
|
#ifdef CONFIG_VSYNC_DRM
|
||||||
.drm_fd = 0,
|
.drm_fd = 0,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_VSYNC_OPENGL
|
||||||
.glx_context = None,
|
.glx_context = None,
|
||||||
.glx_get_video_sync = NULL,
|
.glx_get_video_sync = NULL,
|
||||||
.glx_wait_video_sync = NULL,
|
.glx_wait_video_sync = NULL,
|
||||||
|
#endif
|
||||||
|
|
||||||
.xfixes_event = 0,
|
.xfixes_event = 0,
|
||||||
.xfixes_error = 0,
|
.xfixes_error = 0,
|
||||||
@ -5119,9 +5211,11 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||||||
.randr_exists = 0,
|
.randr_exists = 0,
|
||||||
.randr_event = 0,
|
.randr_event = 0,
|
||||||
.randr_error = 0,
|
.randr_error = 0,
|
||||||
|
#ifdef CONFIG_VSYNC_OPENGL
|
||||||
.glx_exists = false,
|
.glx_exists = false,
|
||||||
.glx_event = 0,
|
.glx_event = 0,
|
||||||
.glx_error = 0,
|
.glx_error = 0,
|
||||||
|
#endif
|
||||||
.dbe_exists = false,
|
.dbe_exists = false,
|
||||||
.xrfilter_convolution_exists = false,
|
.xrfilter_convolution_exists = false,
|
||||||
|
|
||||||
@ -5255,7 +5349,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||||||
|
|
||||||
// Initialize software optimization
|
// Initialize software optimization
|
||||||
if (ps->o.sw_opti)
|
if (ps->o.sw_opti)
|
||||||
ps->o.sw_opti = sw_opti_init(ps);
|
ps->o.sw_opti = swopti_init(ps);
|
||||||
|
|
||||||
// Initialize DRM/OpenGL VSync
|
// Initialize DRM/OpenGL VSync
|
||||||
if ((VSYNC_DRM == ps->o.vsync && !vsync_drm_init(ps))
|
if ((VSYNC_DRM == ps->o.vsync && !vsync_drm_init(ps))
|
||||||
@ -5269,8 +5363,6 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||||||
if (ps->o.dbe)
|
if (ps->o.dbe)
|
||||||
init_dbe(ps);
|
init_dbe(ps);
|
||||||
|
|
||||||
if (ps->o.fork_after_register) fork_after();
|
|
||||||
|
|
||||||
init_atoms(ps);
|
init_atoms(ps);
|
||||||
init_alpha_picts(ps);
|
init_alpha_picts(ps);
|
||||||
|
|
||||||
@ -5313,6 +5405,24 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ps->all_damage = None;
|
ps->all_damage = None;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
redir_start(ps);
|
redir_start(ps);
|
||||||
@ -5345,6 +5455,18 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||||||
|
|
||||||
XUngrabServer(ps->dpy);
|
XUngrabServer(ps->dpy);
|
||||||
|
|
||||||
|
// Fork to background, if asked
|
||||||
|
if (ps->o.fork_after_register) {
|
||||||
|
if (!fork_after()) {
|
||||||
|
session_destroy(ps);
|
||||||
|
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
|
||||||
if (ps_old)
|
if (ps_old)
|
||||||
free(ps_old);
|
free(ps_old);
|
||||||
@ -5447,10 +5569,12 @@ session_destroy(session_t *ps) {
|
|||||||
XDestroyWindow(ps->dpy, ps->reg_win);
|
XDestroyWindow(ps->dpy, ps->reg_win);
|
||||||
ps->reg_win = None;
|
ps->reg_win = None;
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_VSYNC_OPENGL
|
||||||
if (ps->glx_context) {
|
if (ps->glx_context) {
|
||||||
glXDestroyContext(ps->dpy, ps->glx_context);
|
glXDestroyContext(ps->dpy, ps->glx_context);
|
||||||
ps->glx_context = None;
|
ps->glx_context = None;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Free double buffer
|
// Free double buffer
|
||||||
if (ps->root_dbe) {
|
if (ps->root_dbe) {
|
||||||
@ -5458,11 +5582,13 @@ session_destroy(session_t *ps) {
|
|||||||
ps->root_dbe = None;
|
ps->root_dbe = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_VSYNC_DRM
|
||||||
// Close file opened for DRM VSync
|
// Close file opened for DRM VSync
|
||||||
if (ps->drm_fd) {
|
if (ps->drm_fd) {
|
||||||
close(ps->drm_fd);
|
close(ps->drm_fd);
|
||||||
ps->drm_fd = 0;
|
ps->drm_fd = 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Release overlay window
|
// Release overlay window
|
||||||
if (ps->overlay) {
|
if (ps->overlay) {
|
||||||
@ -5470,6 +5596,11 @@ 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);
|
||||||
|
|
||||||
@ -5487,7 +5618,7 @@ session_run(session_t *ps) {
|
|||||||
win *t;
|
win *t;
|
||||||
|
|
||||||
if (ps->o.sw_opti)
|
if (ps->o.sw_opti)
|
||||||
ps->paint_tm_offset = get_time_timespec().tv_nsec;
|
ps->paint_tm_offset = get_time_timeval().tv_usec;
|
||||||
|
|
||||||
ps->reg_ignore_expire = true;
|
ps->reg_ignore_expire = true;
|
||||||
|
|
||||||
@ -5503,22 +5634,10 @@ session_run(session_t *ps) {
|
|||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
while (!ps->reset) {
|
while (!ps->reset) {
|
||||||
bool ev_received = false;
|
ps->ev_received = false;
|
||||||
|
|
||||||
while (XEventsQueued(ps->dpy, QueuedAfterReading)
|
while (mainloop(ps))
|
||||||
|| (evpoll(ps,
|
continue;
|
||||||
(ev_received ? 0: (ps->idling ? -1: fade_timeout(ps)))) > 0)) {
|
|
||||||
// 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);
|
|
||||||
ev_received = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// idling will be turned off during paint_preprocess() if needed
|
// idling will be turned off during paint_preprocess() if needed
|
||||||
ps->idling = true;
|
ps->idling = true;
|
||||||
@ -5530,7 +5649,7 @@ session_run(session_t *ps) {
|
|||||||
free_region(ps, &ps->all_damage);
|
free_region(ps, &ps->all_damage);
|
||||||
|
|
||||||
if (ps->all_damage && !is_region_empty(ps, ps->all_damage)) {
|
if (ps->all_damage && !is_region_empty(ps, ps->all_damage)) {
|
||||||
static int paint;
|
static int paint = 0;
|
||||||
paint_all(ps, ps->all_damage, t);
|
paint_all(ps, ps->all_damage, t);
|
||||||
ps->reg_ignore_expire = false;
|
ps->reg_ignore_expire = false;
|
||||||
paint++;
|
paint++;
|
||||||
@ -5577,6 +5696,10 @@ main(int argc, char **argv) {
|
|||||||
session_t *ps_old = ps_g;
|
session_t *ps_old = ps_g;
|
||||||
while (1) {
|
while (1) {
|
||||||
ps_g = session_init(ps_old, argc, argv);
|
ps_g = session_init(ps_old, argc, argv);
|
||||||
|
if (!ps_g) {
|
||||||
|
printf_errf("Failed to create new session.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
session_run(ps_g);
|
session_run(ps_g);
|
||||||
ps_old = ps_g;
|
ps_old = ps_g;
|
||||||
session_destroy(ps_g);
|
session_destroy(ps_g);
|
||||||
|
314
src/compton.h
314
src/compton.h
@ -54,6 +54,21 @@
|
|||||||
#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
|
||||||
#ifdef CONFIG_REGEX_PCRE
|
#ifdef CONFIG_REGEX_PCRE
|
||||||
#include <pcre.h>
|
#include <pcre.h>
|
||||||
|
|
||||||
@ -72,6 +87,10 @@
|
|||||||
#include <libconfig.h>
|
#include <libconfig.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_DBUS
|
||||||
|
#include <dbus/dbus.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
@ -109,9 +128,11 @@
|
|||||||
#define REGISTER_PROP "_NET_WM_CM_S"
|
#define REGISTER_PROP "_NET_WM_CM_S"
|
||||||
|
|
||||||
#define FADE_DELTA_TOLERANCE 0.2
|
#define FADE_DELTA_TOLERANCE 0.2
|
||||||
#define SW_OPTI_TOLERANCE 1000
|
#define SWOPTI_TOLERANCE 1000
|
||||||
#define WIN_GET_LEADER_MAX_RECURSION 20
|
#define WIN_GET_LEADER_MAX_RECURSION 20
|
||||||
|
|
||||||
|
#define SEC_WRAP (15L * 24L * 60L * 60L)
|
||||||
|
|
||||||
#define NS_PER_SEC 1000000000L
|
#define NS_PER_SEC 1000000000L
|
||||||
#define US_PER_SEC 1000000L
|
#define US_PER_SEC 1000000L
|
||||||
#define MS_PER_SEC 1000
|
#define MS_PER_SEC 1000
|
||||||
@ -134,10 +155,27 @@
|
|||||||
// #define MSTR_(s) #s
|
// #define MSTR_(s) #s
|
||||||
// #define MSTR(s) MSTR_(s)
|
// #define MSTR(s) MSTR_(s)
|
||||||
|
|
||||||
|
/// Print out an error message.
|
||||||
|
#define printf_err(format, ...) \
|
||||||
|
fprintf(stderr, format "\n", ## __VA_ARGS__)
|
||||||
|
|
||||||
|
/// Print out an error message with function name.
|
||||||
|
#define printf_errf(format, ...) \
|
||||||
|
printf_err("%s" format, __func__, ## __VA_ARGS__)
|
||||||
|
|
||||||
|
/// Print out an error message with function name, and quit with a
|
||||||
|
/// specific exit code.
|
||||||
|
#define printf_errfq(code, format, ...) { \
|
||||||
|
printf_err("%s" format, __func__, ## __VA_ARGS__); \
|
||||||
|
exit(code); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Print out a debug message.
|
||||||
#define printf_dbg(format, ...) \
|
#define printf_dbg(format, ...) \
|
||||||
printf(format, ## __VA_ARGS__); \
|
printf(format, ## __VA_ARGS__); \
|
||||||
fflush(stdout)
|
fflush(stdout)
|
||||||
|
|
||||||
|
/// Print out a debug message with function name.
|
||||||
#define printf_dbgf(format, ...) \
|
#define printf_dbgf(format, ...) \
|
||||||
printf_dbg("%s" format, __func__, ## __VA_ARGS__)
|
printf_dbg("%s" format, __func__, ## __VA_ARGS__)
|
||||||
|
|
||||||
@ -148,6 +186,7 @@
|
|||||||
// === Types ===
|
// === Types ===
|
||||||
|
|
||||||
typedef uint32_t opacity_t;
|
typedef uint32_t opacity_t;
|
||||||
|
typedef long time_ms_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
WINTYPE_UNKNOWN,
|
WINTYPE_UNKNOWN,
|
||||||
@ -175,12 +214,14 @@ typedef enum {
|
|||||||
UNSET
|
UNSET
|
||||||
} switch_t;
|
} switch_t;
|
||||||
|
|
||||||
|
/// Enumeration type of window painting mode.
|
||||||
typedef enum {
|
typedef enum {
|
||||||
WINDOW_SOLID,
|
WMODE_TRANS,
|
||||||
WINDOW_TRANS,
|
WMODE_SOLID,
|
||||||
WINDOW_ARGB
|
WMODE_ARGB
|
||||||
} winmode;
|
} winmode_t;
|
||||||
|
|
||||||
|
/// Structure representing Window property value.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
// All pointers have the same length, right?
|
// All pointers have the same length, right?
|
||||||
// I wanted to use anonymous union but it's a GNU extension...
|
// I wanted to use anonymous union but it's a GNU extension...
|
||||||
@ -190,6 +231,8 @@ typedef struct {
|
|||||||
long *p32;
|
long *p32;
|
||||||
} data;
|
} data;
|
||||||
unsigned long nitems;
|
unsigned long nitems;
|
||||||
|
Atom type;
|
||||||
|
int format;
|
||||||
} winprop_t;
|
} winprop_t;
|
||||||
|
|
||||||
typedef struct _ignore {
|
typedef struct _ignore {
|
||||||
@ -263,6 +306,8 @@ typedef struct {
|
|||||||
/// Whether to unredirect all windows if a full-screen opaque window
|
/// Whether to unredirect all windows if a full-screen opaque window
|
||||||
/// is detected.
|
/// is detected.
|
||||||
bool unredir_if_possible;
|
bool unredir_if_possible;
|
||||||
|
/// Whether to enable D-Bus support.
|
||||||
|
bool dbus;
|
||||||
/// Whether to work under synchronized mode for debugging.
|
/// Whether to work under synchronized mode for debugging.
|
||||||
bool synchronize;
|
bool synchronize;
|
||||||
|
|
||||||
@ -301,7 +346,8 @@ typedef struct {
|
|||||||
opacity_t fade_in_step;
|
opacity_t fade_in_step;
|
||||||
/// How much to fade out in a single fading step.
|
/// How much to fade out in a single fading step.
|
||||||
opacity_t fade_out_step;
|
opacity_t fade_out_step;
|
||||||
unsigned long fade_delta;
|
/// Fading time delta. In milliseconds.
|
||||||
|
time_ms_t fade_delta;
|
||||||
/// Whether to disable fading on window open/close.
|
/// Whether to disable fading on window open/close.
|
||||||
bool no_fading_openclose;
|
bool no_fading_openclose;
|
||||||
/// Fading blacklist. A linked list of conditions.
|
/// Fading blacklist. A linked list of conditions.
|
||||||
@ -401,6 +447,17 @@ typedef struct {
|
|||||||
// === Operation related ===
|
// === Operation related ===
|
||||||
/// Program options.
|
/// Program options.
|
||||||
options_t o;
|
options_t o;
|
||||||
|
/// Libevent event base.
|
||||||
|
struct event_base *ev_base;
|
||||||
|
/// Libevent event for X connection.
|
||||||
|
struct event *ev_x;
|
||||||
|
/// Libevent event for timeout.
|
||||||
|
struct event *ev_tmout;
|
||||||
|
/// Whether we have received an event in this cycle.
|
||||||
|
bool ev_received;
|
||||||
|
/// Whether the program is idling. I.e. no fading, no potential window
|
||||||
|
/// changes.
|
||||||
|
bool idling;
|
||||||
/// Program start time.
|
/// Program start time.
|
||||||
struct timeval time_start;
|
struct timeval time_start;
|
||||||
/// The region needs to painted on next paint.
|
/// The region needs to painted on next paint.
|
||||||
@ -414,11 +471,8 @@ typedef struct {
|
|||||||
Picture *alpha_picts;
|
Picture *alpha_picts;
|
||||||
/// Whether all reg_ignore of windows should expire in this paint.
|
/// Whether all reg_ignore of windows should expire in this paint.
|
||||||
bool reg_ignore_expire;
|
bool reg_ignore_expire;
|
||||||
/// Whether the program is idling. I.e. no fading, no potential window
|
|
||||||
/// changes.
|
|
||||||
bool idling;
|
|
||||||
/// Time of last fading. In milliseconds.
|
/// Time of last fading. In milliseconds.
|
||||||
unsigned long fade_time;
|
time_ms_t fade_time;
|
||||||
/// Head pointer of the error ignore linked list.
|
/// Head pointer of the error ignore linked list.
|
||||||
ignore_t *ignore_head;
|
ignore_t *ignore_head;
|
||||||
/// Pointer to the <code>next</code> member of tail element of the error
|
/// Pointer to the <code>next</code> member of tail element of the error
|
||||||
@ -566,35 +620,42 @@ typedef struct {
|
|||||||
|
|
||||||
/// Structure representing a top-level window compton manages.
|
/// Structure representing a top-level window compton manages.
|
||||||
typedef struct _win {
|
typedef struct _win {
|
||||||
// Next structure in the linked list.
|
/// Pointer to the next structure in the linked list.
|
||||||
struct _win *next;
|
struct _win *next;
|
||||||
|
/// Pointer to the next higher window to paint.
|
||||||
|
struct _win *prev_trans;
|
||||||
|
|
||||||
// ID of the top-level frame window.
|
// Core members
|
||||||
|
/// ID of the top-level frame window.
|
||||||
Window id;
|
Window id;
|
||||||
/// ID of the top-level client window of the window.
|
/// Window attributes.
|
||||||
Window client_win;
|
|
||||||
/// Whether it looks like a WM window. We consider a window WM window if
|
|
||||||
/// it does not have a decedent with WM_STATE and it is not override-
|
|
||||||
/// redirected itself.
|
|
||||||
bool wmwin;
|
|
||||||
Pixmap pixmap;
|
|
||||||
XWindowAttributes a;
|
XWindowAttributes a;
|
||||||
winmode mode;
|
/// Window painting mode.
|
||||||
int damaged;
|
winmode_t mode;
|
||||||
|
/// Whether the window has been damaged at least once.
|
||||||
|
bool damaged;
|
||||||
|
/// Damage of the window.
|
||||||
Damage damage;
|
Damage damage;
|
||||||
|
/// NameWindowPixmap of the window.
|
||||||
|
Pixmap pixmap;
|
||||||
|
/// Picture of the window.
|
||||||
Picture picture;
|
Picture picture;
|
||||||
|
/// Bounding shape of the window.
|
||||||
XserverRegion border_size;
|
XserverRegion border_size;
|
||||||
|
/// Region of the whole window, shadow region included.
|
||||||
XserverRegion extents;
|
XserverRegion extents;
|
||||||
// Type of the window.
|
/// Window flags. Definitions above.
|
||||||
wintype_t window_type;
|
int_fast16_t flags;
|
||||||
/// Whether the window is to be considered focused.
|
/// Whether there's a pending <code>ConfigureNotify</code> happening
|
||||||
bool focused;
|
/// when the window is unmapped.
|
||||||
/// Whether the window is actually focused.
|
bool need_configure;
|
||||||
bool focused_real;
|
/// Queued <code>ConfigureNotify</code> when the window is unmapped.
|
||||||
/// Leader window ID of the window.
|
XConfigureEvent queue_configure;
|
||||||
Window leader;
|
/// Region to be ignored when painting. Basically the region where
|
||||||
/// Cached topmost window ID of the window.
|
/// higher opaque windows will paint upon. Depends on window frame
|
||||||
Window cache_leader;
|
/// opacity state, window geometry, window mapped/unmapped state,
|
||||||
|
/// window mode, of this and all higher windows.
|
||||||
|
XserverRegion reg_ignore;
|
||||||
/// Whether the window has been destroyed.
|
/// Whether the window has been destroyed.
|
||||||
bool destroyed;
|
bool destroyed;
|
||||||
/// Cached width/height of the window including border.
|
/// Cached width/height of the window including border.
|
||||||
@ -606,6 +667,28 @@ typedef struct _win {
|
|||||||
/// Whether this window is to be painted.
|
/// Whether this window is to be painted.
|
||||||
bool to_paint;
|
bool to_paint;
|
||||||
|
|
||||||
|
// Client window related members
|
||||||
|
/// ID of the top-level client window of the window.
|
||||||
|
Window client_win;
|
||||||
|
/// Type of the window.
|
||||||
|
wintype_t window_type;
|
||||||
|
/// Whether it looks like a WM window. We consider a window WM window if
|
||||||
|
/// it does not have a decedent with WM_STATE and it is not override-
|
||||||
|
/// redirected itself.
|
||||||
|
bool wmwin;
|
||||||
|
/// Leader window ID of the window.
|
||||||
|
Window leader;
|
||||||
|
/// Cached topmost window ID of the window.
|
||||||
|
Window cache_leader;
|
||||||
|
|
||||||
|
// Focus-related members
|
||||||
|
/// Whether the window is to be considered focused.
|
||||||
|
bool focused;
|
||||||
|
/// Override value of window focus state. Set by D-Bus method calls.
|
||||||
|
switch_t focused_force;
|
||||||
|
/// Whether the window is actually focused.
|
||||||
|
bool focused_real;
|
||||||
|
|
||||||
// Blacklist related members
|
// Blacklist related members
|
||||||
/// Name of the window.
|
/// Name of the window.
|
||||||
char *name;
|
char *name;
|
||||||
@ -649,8 +732,10 @@ typedef struct _win {
|
|||||||
unsigned int left_width, right_width, top_width, bottom_width;
|
unsigned int left_width, right_width, top_width, bottom_width;
|
||||||
|
|
||||||
// Shadow-related members
|
// Shadow-related members
|
||||||
/// Whether a window has shadow. Affected by window type.
|
/// Whether a window has shadow. Calculated.
|
||||||
bool shadow;
|
bool shadow;
|
||||||
|
/// Override value of window shadow state. Set by D-Bus method calls.
|
||||||
|
switch_t shadow_force;
|
||||||
/// Opacity of the shadow. Affected by window opacity and frame opacity.
|
/// Opacity of the shadow. Affected by window opacity and frame opacity.
|
||||||
double shadow_opacity;
|
double shadow_opacity;
|
||||||
/// X offset of shadow. Affected by commandline argument.
|
/// X offset of shadow. Affected by commandline argument.
|
||||||
@ -667,7 +752,7 @@ typedef struct _win {
|
|||||||
Picture shadow_alpha_pict;
|
Picture shadow_alpha_pict;
|
||||||
/// The value of _COMPTON_SHADOW attribute of the window. Below 0 for
|
/// The value of _COMPTON_SHADOW attribute of the window. Below 0 for
|
||||||
/// none.
|
/// none.
|
||||||
long attr_shadow;
|
long prop_shadow;
|
||||||
|
|
||||||
// Dim-related members
|
// Dim-related members
|
||||||
/// Whether the window is to be dimmed.
|
/// Whether the window is to be dimmed.
|
||||||
@ -675,24 +760,6 @@ typedef struct _win {
|
|||||||
/// Picture for dimming. Affected by user-specified inactive dim
|
/// Picture for dimming. Affected by user-specified inactive dim
|
||||||
/// opacity and window opacity.
|
/// opacity and window opacity.
|
||||||
Picture dim_alpha_pict;
|
Picture dim_alpha_pict;
|
||||||
|
|
||||||
/// Window flags. Definitions above.
|
|
||||||
int_fast16_t flags;
|
|
||||||
|
|
||||||
unsigned long damage_sequence; /* sequence when damage was created */
|
|
||||||
|
|
||||||
/// Whether there's a pending <code>ConfigureNotify</code> happening
|
|
||||||
/// when the window is unmapped.
|
|
||||||
bool need_configure;
|
|
||||||
/// Queued <code>ConfigureNotify</code> when the window is unmapped.
|
|
||||||
XConfigureEvent queue_configure;
|
|
||||||
/// Region to be ignored when painting. Basically the region where
|
|
||||||
/// higher opaque windows will paint upon. Depends on window frame
|
|
||||||
/// opacity state, window geometry, window mapped/unmapped state,
|
|
||||||
/// window mode, of this and all higher windows.
|
|
||||||
XserverRegion reg_ignore;
|
|
||||||
|
|
||||||
struct _win *prev_trans;
|
|
||||||
} win;
|
} win;
|
||||||
|
|
||||||
/// Temporary structure used for communication between
|
/// Temporary structure used for communication between
|
||||||
@ -773,6 +840,22 @@ 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
|
||||||
|
|
||||||
@ -784,6 +867,9 @@ discard_ignore(session_t *ps, unsigned long sequence);
|
|||||||
static void
|
static void
|
||||||
set_ignore(session_t *ps, unsigned long sequence);
|
set_ignore(session_t *ps, unsigned long sequence);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignore X errors caused by next X request.
|
||||||
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
set_ignore_next(session_t *ps) {
|
set_ignore_next(session_t *ps) {
|
||||||
set_ignore(ps, NextRequest(ps->dpy));
|
set_ignore(ps, NextRequest(ps->dpy));
|
||||||
@ -792,6 +878,14 @@ set_ignore_next(session_t *ps) {
|
|||||||
static int
|
static int
|
||||||
should_ignore(session_t *ps, unsigned long sequence);
|
should_ignore(session_t *ps, unsigned long sequence);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper of XInternAtom() for convience.
|
||||||
|
*/
|
||||||
|
static inline Atom
|
||||||
|
get_atom(session_t *ps, char *atom_name) {
|
||||||
|
return XInternAtom(ps->dpy, atom_name, False);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the painting target window.
|
* Return the painting target window.
|
||||||
*/
|
*/
|
||||||
@ -957,6 +1051,14 @@ array_wid_exists(const Window *arr, int count, Window wid) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether a struct timeval value is empty.
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
timeval_isempty(struct timeval tv) {
|
||||||
|
return tv.tv_sec <= 0 && tv.tv_usec <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Subtracting two struct timeval values.
|
* Subtracting two struct timeval values.
|
||||||
*
|
*
|
||||||
@ -1026,6 +1128,19 @@ timespec_subtract(struct timespec *result,
|
|||||||
return x->tv_sec < y->tv_sec;
|
return x->tv_sec < y->tv_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current time in struct timeval.
|
||||||
|
*/
|
||||||
|
static inline struct timeval __attribute__((const))
|
||||||
|
get_time_timeval(void) {
|
||||||
|
struct timeval tv = { 0, 0 };
|
||||||
|
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
|
||||||
|
// Return a time of all 0 if the call fails
|
||||||
|
return tv;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get current time in struct timespec.
|
* Get current time in struct timespec.
|
||||||
*
|
*
|
||||||
@ -1154,18 +1269,25 @@ free_win_res(session_t *ps, win *w) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get current system clock in milliseconds.
|
* Get current system clock in milliseconds.
|
||||||
*
|
|
||||||
* The return type must be unsigned long because so many milliseconds have
|
|
||||||
* passed since the epoch.
|
|
||||||
*/
|
*/
|
||||||
static unsigned long
|
static inline time_ms_t
|
||||||
get_time_ms(void) {
|
get_time_ms(void) {
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
|
|
||||||
return (unsigned long) tv.tv_sec * 1000
|
return tv.tv_sec % SEC_WRAP * 1000 + tv.tv_usec / 1000;
|
||||||
+ (unsigned long) tv.tv_usec / 1000;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert time from milliseconds to struct timeval.
|
||||||
|
*/
|
||||||
|
static inline struct timeval
|
||||||
|
ms_to_tv(int timeout) {
|
||||||
|
return (struct timeval) {
|
||||||
|
.tv_sec = timeout / MS_PER_SEC,
|
||||||
|
.tv_usec = timeout % MS_PER_SEC * (US_PER_SEC / MS_PER_SEC)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -1255,33 +1377,68 @@ wid_has_prop(const session_t *ps, Window w, Atom atom) {
|
|||||||
* @return a <code>winprop_t</code> structure containing the attribute
|
* @return a <code>winprop_t</code> structure containing the attribute
|
||||||
* and number of items. A blank one on failure.
|
* and number of items. A blank one on failure.
|
||||||
*/
|
*/
|
||||||
|
// TODO: Move to compton.c
|
||||||
static winprop_t
|
static winprop_t
|
||||||
wid_get_prop(const session_t *ps, Window w, Atom atom, long length,
|
wid_get_prop_adv(const session_t *ps, Window w, Atom atom, long offset,
|
||||||
Atom rtype, int rformat) {
|
long length, Atom rtype, int rformat) {
|
||||||
Atom type = None;
|
Atom type = None;
|
||||||
int format = 0;
|
int format = 0;
|
||||||
unsigned long nitems = 0, after = 0;
|
unsigned long nitems = 0, after = 0;
|
||||||
unsigned char *data = NULL;
|
unsigned char *data = NULL;
|
||||||
|
|
||||||
// Use two if statements to deal with the sequence point issue.
|
if (Success == XGetWindowProperty(ps->dpy, w, atom, offset, length,
|
||||||
if (Success == XGetWindowProperty(ps->dpy, w, atom, 0L, length, False,
|
False, rtype, &type, &format, &nitems, &after, &data)
|
||||||
rtype, &type, &format, &nitems, &after, &data)) {
|
&& nitems && (AnyPropertyType == type || type == rtype)
|
||||||
if (type == rtype && format == rformat) {
|
&& (!format || format == rformat)
|
||||||
|
&& (8 == format || 16 == format || 32 == format)) {
|
||||||
return (winprop_t) {
|
return (winprop_t) {
|
||||||
.data.p8 = data,
|
.data.p8 = data,
|
||||||
.nitems = nitems
|
.nitems = nitems,
|
||||||
|
.type = type,
|
||||||
|
.format = format,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
XFree(data);
|
XFree(data);
|
||||||
|
|
||||||
return (winprop_t) {
|
return (winprop_t) {
|
||||||
.data.p8 = NULL,
|
.data.p8 = NULL,
|
||||||
.nitems = 0
|
.nitems = 0,
|
||||||
|
.type = AnyPropertyType,
|
||||||
|
.format = 0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper of wid_get_prop_adv().
|
||||||
|
*/
|
||||||
|
static inline winprop_t
|
||||||
|
wid_get_prop(const session_t *ps, Window wid, Atom atom, long length,
|
||||||
|
Atom rtype, int rformat) {
|
||||||
|
return wid_get_prop_adv(ps, wid, atom, 0L, length, rtype, rformat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the numeric property value from a win_prop_t.
|
||||||
|
*/
|
||||||
|
static inline long
|
||||||
|
winprop_get_int(winprop_t prop) {
|
||||||
|
long tgt = 0;
|
||||||
|
|
||||||
|
if (!prop.nitems)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch (prop.format) {
|
||||||
|
case 8: tgt = *(prop.data.p8); break;
|
||||||
|
case 16: tgt = *(prop.data.p16); break;
|
||||||
|
case 32: tgt = *(prop.data.p32); break;
|
||||||
|
default: assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tgt;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free a <code>winprop_t</code>.
|
* Free a <code>winprop_t</code>.
|
||||||
*
|
*
|
||||||
@ -1364,7 +1521,7 @@ wid_bounding_shaped(const session_t *ps, Window wid) {
|
|||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
update_reg_ignore_expire(session_t *ps, const win *w) {
|
update_reg_ignore_expire(session_t *ps, const win *w) {
|
||||||
if (w->to_paint && WINDOW_SOLID == w->mode)
|
if (w->to_paint && WMODE_SOLID == w->mode)
|
||||||
ps->reg_ignore_expire = true;
|
ps->reg_ignore_expire = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1616,10 +1773,10 @@ static void
|
|||||||
win_update_shape(session_t *ps, win *w);
|
win_update_shape(session_t *ps, win *w);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
win_update_attr_shadow_raw(session_t *ps, win *w);
|
win_update_prop_shadow_raw(session_t *ps, win *w);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
win_update_attr_shadow(session_t *ps, win *w);
|
win_update_prop_shadow(session_t *ps, win *w);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
determine_shadow(session_t *ps, win *w);
|
determine_shadow(session_t *ps, win *w);
|
||||||
@ -1639,7 +1796,7 @@ win_unmark_client(session_t *ps, win *w);
|
|||||||
static void
|
static void
|
||||||
win_recheck_client(session_t *ps, win *w);
|
win_recheck_client(session_t *ps, win *w);
|
||||||
|
|
||||||
static void
|
static bool
|
||||||
add_win(session_t *ps, Window id, Window prev);
|
add_win(session_t *ps, Window id, Window prev);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1855,7 +2012,7 @@ ev_window_name(session_t *ps, Window wid, char **name);
|
|||||||
inline static void
|
inline static void
|
||||||
ev_handle(session_t *ps, XEvent *ev);
|
ev_handle(session_t *ps, XEvent *ev);
|
||||||
|
|
||||||
static void
|
static bool
|
||||||
fork_after(void);
|
fork_after(void);
|
||||||
|
|
||||||
#ifdef CONFIG_LIBCONFIG
|
#ifdef CONFIG_LIBCONFIG
|
||||||
@ -1916,10 +2073,16 @@ static void
|
|||||||
update_refresh_rate(session_t *ps);
|
update_refresh_rate(session_t *ps);
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
sw_opti_init(session_t *ps);
|
swopti_init(session_t *ps);
|
||||||
|
|
||||||
static int
|
static void
|
||||||
evpoll(session_t *ps, int timeout);
|
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);
|
||||||
@ -1955,6 +2118,9 @@ redir_start(session_t *ps);
|
|||||||
static void
|
static void
|
||||||
redir_stop(session_t *ps);
|
redir_stop(session_t *ps);
|
||||||
|
|
||||||
|
static bool
|
||||||
|
mainloop(session_t *ps);
|
||||||
|
|
||||||
static session_t *
|
static session_t *
|
||||||
session_init(session_t *ps_old, int argc, char **argv);
|
session_init(session_t *ps_old, int argc, char **argv);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user