2018-10-03 21:14:51 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
2003-11-10 03:45:17 +00:00
|
|
|
/*
|
2012-02-27 04:00:12 +00:00
|
|
|
* Compton - a compositor for X11
|
2003-11-10 03:45:17 +00:00
|
|
|
*
|
2012-02-27 04:00:12 +00:00
|
|
|
* Based on `xcompmgr` - Copyright (c) 2003, Keith Packard
|
2003-11-10 03:45:17 +00:00
|
|
|
*
|
Feature #80: D-Bus support
- Add D-Bus support. Currently 7 methods are available: "reset" (same as
SIGUSR1), "list_win" (list the windows compton manages), "win_get"
(get a property of the window), "win_set" (set a property of the
window), "find_win" (find window based on client window / focus),
"opts_get" (get the value of a compton option), and "opts_set" (set
the value of a compton option), together with 4 signals: "win_added",
"win_destroyed", "win_mapped", "win_unmapped".
- D-Bus support depends on libdbus.
- As there are many items and my time is tight, no much tests are done.
Bugs to be expected.
- Create a new header file `common.h` that contains shared content.
- Fix some bugs in timeout handling.
- Update file headers in all source files.
- Re-enable --unredir-if-possible on multi-screen set-ups, as the user
could turn if off manually anyway.
- Check if the window is mapped in `repair_win()`.
- Add ps->track_atom_lst and its handlers, to prepare for the new
condition format.
- Known issue 1: "win_get", "win_set", "opts_get", "opts_set" support a
very limited number of targets only. New ones will be added gradually.
- Known issue 2: Accidental drop of D-Bus connection is not handled.
- Known issue 3: Introspection does not reveal all available methods,
because some methods have unpredictable prototypes. Still hesitating
about what to do...
- Known issue 4: Error handling is not finished yet. Compton does not
always reply with the correct error message (but it does print out the
correct error message, usually).
2013-01-19 12:20:27 +00:00
|
|
|
* Copyright (c) 2011-2013, Christopher Jeffrey
|
2018-10-03 21:24:12 +00:00
|
|
|
* See LICENSE-mit for more information.
|
2003-11-10 03:45:17 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2018-12-30 07:06:47 +00:00
|
|
|
#include <X11/Xlib-xcb.h>
|
2019-03-10 12:34:37 +00:00
|
|
|
#include <X11/Xlib.h>
|
2019-08-09 23:56:04 +00:00
|
|
|
#include <X11/Xutil.h>
|
2019-09-16 21:14:34 +00:00
|
|
|
#include <X11/extensions/sync.h>
|
2020-10-22 00:39:51 +00:00
|
|
|
#include <errno.h>
|
2019-03-10 12:34:37 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2020-10-25 03:13:03 +00:00
|
|
|
#include <unistd.h>
|
2019-03-10 12:34:37 +00:00
|
|
|
#include <xcb/composite.h>
|
2018-09-22 22:44:44 +00:00
|
|
|
#include <xcb/damage.h>
|
2020-03-31 05:07:09 +00:00
|
|
|
#include <xcb/glx.h>
|
2019-03-10 12:34:37 +00:00
|
|
|
#include <xcb/present.h>
|
|
|
|
#include <xcb/randr.h>
|
2018-09-23 18:10:46 +00:00
|
|
|
#include <xcb/render.h>
|
2019-01-20 21:15:20 +00:00
|
|
|
#include <xcb/sync.h>
|
2019-03-10 12:34:37 +00:00
|
|
|
#include <xcb/xfixes.h>
|
2019-05-06 01:03:07 +00:00
|
|
|
#include <xcb/xinerama.h>
|
2018-09-06 18:17:26 +00:00
|
|
|
|
2018-10-02 19:22:26 +00:00
|
|
|
#include <ev.h>
|
2019-03-24 04:47:25 +00:00
|
|
|
#include <test.h>
|
2018-10-02 19:22:26 +00:00
|
|
|
|
2019-01-18 23:30:44 +00:00
|
|
|
#include "common.h"
|
2018-12-15 18:47:21 +00:00
|
|
|
#include "compiler.h"
|
2019-06-09 18:25:34 +00:00
|
|
|
#include "config.h"
|
2019-03-10 12:34:37 +00:00
|
|
|
#include "err.h"
|
|
|
|
#include "kernel.h"
|
2019-10-23 18:27:30 +00:00
|
|
|
#include "picom.h"
|
2018-09-29 22:30:19 +00:00
|
|
|
#ifdef CONFIG_OPENGL
|
|
|
|
#include "opengl.h"
|
|
|
|
#endif
|
2019-03-10 12:34:37 +00:00
|
|
|
#include "backend/backend.h"
|
|
|
|
#include "c2.h"
|
2018-08-22 11:58:49 +00:00
|
|
|
#include "config.h"
|
2018-11-03 22:15:38 +00:00
|
|
|
#include "diagnostic.h"
|
2019-03-10 12:34:37 +00:00
|
|
|
#include "log.h"
|
2019-01-18 23:30:44 +00:00
|
|
|
#include "region.h"
|
2019-03-10 12:34:37 +00:00
|
|
|
#include "render.h"
|
2019-01-18 23:30:44 +00:00
|
|
|
#include "types.h"
|
2019-03-10 12:34:37 +00:00
|
|
|
#include "utils.h"
|
|
|
|
#include "win.h"
|
|
|
|
#include "x.h"
|
2018-12-20 22:31:34 +00:00
|
|
|
#ifdef CONFIG_DBUS
|
|
|
|
#include "dbus.h"
|
|
|
|
#endif
|
2019-05-05 23:34:08 +00:00
|
|
|
#include "atom.h"
|
2019-03-17 13:44:26 +00:00
|
|
|
#include "event.h"
|
2019-11-10 18:58:01 +00:00
|
|
|
#include "file_watch.h"
|
2019-04-14 00:01:44 +00:00
|
|
|
#include "list.h"
|
2019-03-17 15:17:48 +00:00
|
|
|
#include "options.h"
|
2019-04-03 07:36:02 +00:00
|
|
|
#include "uthash_extra.h"
|
2018-11-10 21:52:42 +00:00
|
|
|
|
2018-11-27 00:32:08 +00:00
|
|
|
/// Get session_t pointer from a pointer to a member of session_t
|
2019-03-10 12:34:37 +00:00
|
|
|
#define session_ptr(ptr, member) \
|
|
|
|
({ \
|
|
|
|
const __typeof__(((session_t *)0)->member) *__mptr = (ptr); \
|
|
|
|
(session_t *)((char *)__mptr - offsetof(session_t, member)); \
|
|
|
|
})
|
2018-11-27 00:32:08 +00:00
|
|
|
|
2019-05-06 01:03:07 +00:00
|
|
|
static const long SWOPTI_TOLERANCE = 3000;
|
|
|
|
|
2019-09-28 22:43:36 +00:00
|
|
|
static bool must_use redirect_start(session_t *ps);
|
2018-09-06 18:17:26 +00:00
|
|
|
|
2019-09-28 22:43:36 +00:00
|
|
|
static void unredirect(session_t *ps);
|
2018-09-06 18:17:26 +00:00
|
|
|
|
2012-11-19 01:46:07 +00:00
|
|
|
// === Global constants ===
|
2012-02-27 04:00:12 +00:00
|
|
|
|
2012-11-19 01:46:07 +00:00
|
|
|
/// Name strings for window types.
|
2019-03-10 12:34:37 +00:00
|
|
|
const char *const WINTYPES[NUM_WINTYPES] = {
|
2020-03-07 12:11:55 +00:00
|
|
|
"unknown", "desktop", "dock", "toolbar", "menu",
|
|
|
|
"utility", "splash", "dialog", "normal", "dropdown_menu",
|
|
|
|
"popup_menu", "tooltip", "notification", "combo", "dnd",
|
2012-09-25 13:04:10 +00:00
|
|
|
};
|
|
|
|
|
2020-01-18 18:00:35 +00:00
|
|
|
// clang-format off
|
2013-03-16 14:54:43 +00:00
|
|
|
/// Names of backends.
|
2019-08-04 16:52:45 +00:00
|
|
|
const char *const BACKEND_STRS[] = {[BKEND_XRENDER] = "xrender",
|
|
|
|
[BKEND_GLX] = "glx",
|
|
|
|
[BKEND_XR_GLX_HYBRID] = "xr_glx_hybrid",
|
|
|
|
[BKEND_DUMMY] = "dummy",
|
|
|
|
NULL};
|
2020-01-18 18:00:35 +00:00
|
|
|
// clang-format on
|
2013-04-21 14:30:22 +00:00
|
|
|
|
2012-11-19 01:46:07 +00:00
|
|
|
// === Global variables ===
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 03:42:39 +00:00
|
|
|
|
2012-11-19 01:46:07 +00:00
|
|
|
/// Pointer to current session, as a global variable. Only used by
|
2018-11-26 23:56:55 +00:00
|
|
|
/// xerror(), which could not have a pointer to current session passed in.
|
|
|
|
/// XXX Limit what xerror can access by not having this pointer
|
2012-11-19 01:46:07 +00:00
|
|
|
session_t *ps_g = NULL;
|
2003-11-24 17:11:00 +00:00
|
|
|
|
2019-03-17 15:17:48 +00:00
|
|
|
void set_root_flags(session_t *ps, uint64_t flags) {
|
2020-10-28 19:02:57 +00:00
|
|
|
log_debug("Setting root flags: %" PRIu64, flags);
|
2019-03-17 15:17:48 +00:00
|
|
|
ps->root_flags |= flags;
|
2020-03-31 03:55:50 +00:00
|
|
|
ps->pending_updates = true;
|
2019-03-17 15:17:48 +00:00
|
|
|
}
|
|
|
|
|
2019-10-23 18:27:30 +00:00
|
|
|
void quit(session_t *ps) {
|
2019-04-19 19:53:52 +00:00
|
|
|
ps->quit = true;
|
|
|
|
ev_break(ps->loop, EVBREAK_ALL);
|
|
|
|
}
|
|
|
|
|
2018-11-03 22:38:18 +00:00
|
|
|
/**
|
|
|
|
* Free Xinerama screen info.
|
|
|
|
*
|
|
|
|
* XXX consider moving to x.c
|
|
|
|
*/
|
2019-03-10 12:34:37 +00:00
|
|
|
static inline void free_xinerama_info(session_t *ps) {
|
|
|
|
if (ps->xinerama_scr_regs) {
|
|
|
|
for (int i = 0; i < ps->xinerama_nscrs; ++i)
|
|
|
|
pixman_region32_fini(&ps->xinerama_scr_regs[i]);
|
|
|
|
free(ps->xinerama_scr_regs);
|
|
|
|
}
|
|
|
|
ps->xinerama_nscrs = 0;
|
2018-11-03 22:38:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get current system clock in milliseconds.
|
|
|
|
*/
|
2019-03-30 09:07:21 +00:00
|
|
|
static inline int64_t get_time_ms(void) {
|
2019-03-10 12:34:37 +00:00
|
|
|
struct timespec tp;
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &tp);
|
2019-03-30 09:07:21 +00:00
|
|
|
return (int64_t)tp.tv_sec * 1000 + (int64_t)tp.tv_nsec / 1000000;
|
2018-11-03 22:38:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// XXX Move to x.c
|
2019-03-17 13:44:26 +00:00
|
|
|
void cxinerama_upd_scrs(session_t *ps) {
|
2019-03-10 12:34:37 +00:00
|
|
|
// XXX Consider deprecating Xinerama, switch to RandR when necessary
|
|
|
|
free_xinerama_info(ps);
|
|
|
|
|
|
|
|
if (!ps->o.xinerama_shadow_crop || !ps->xinerama_exists)
|
|
|
|
return;
|
|
|
|
|
|
|
|
xcb_xinerama_is_active_reply_t *active =
|
|
|
|
xcb_xinerama_is_active_reply(ps->c, xcb_xinerama_is_active(ps->c), NULL);
|
|
|
|
if (!active || !active->state) {
|
|
|
|
free(active);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
free(active);
|
|
|
|
|
2019-05-06 01:03:07 +00:00
|
|
|
auto xinerama_scrs =
|
2019-03-10 12:34:37 +00:00
|
|
|
xcb_xinerama_query_screens_reply(ps->c, xcb_xinerama_query_screens(ps->c), NULL);
|
2019-05-06 01:03:07 +00:00
|
|
|
if (!xinerama_scrs) {
|
2019-03-10 12:34:37 +00:00
|
|
|
return;
|
2019-05-06 01:03:07 +00:00
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
|
|
|
|
xcb_xinerama_screen_info_t *scrs =
|
2019-05-06 01:03:07 +00:00
|
|
|
xcb_xinerama_query_screens_screen_info(xinerama_scrs);
|
|
|
|
ps->xinerama_nscrs = xcb_xinerama_query_screens_screen_info_length(xinerama_scrs);
|
2019-03-10 12:34:37 +00:00
|
|
|
|
|
|
|
ps->xinerama_scr_regs = ccalloc(ps->xinerama_nscrs, region_t);
|
|
|
|
for (int i = 0; i < ps->xinerama_nscrs; ++i) {
|
|
|
|
const xcb_xinerama_screen_info_t *const s = &scrs[i];
|
|
|
|
pixman_region32_init_rect(&ps->xinerama_scr_regs[i], s->x_org, s->y_org,
|
|
|
|
s->width, s->height);
|
|
|
|
}
|
2019-05-06 01:03:07 +00:00
|
|
|
free(xinerama_scrs);
|
2018-11-03 22:38:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find matched window.
|
|
|
|
*
|
|
|
|
* XXX move to win.c
|
|
|
|
*/
|
2019-04-17 22:14:45 +00:00
|
|
|
static inline struct managed_win *find_win_all(session_t *ps, const xcb_window_t wid) {
|
2019-03-10 12:34:37 +00:00
|
|
|
if (!wid || PointerRoot == wid || wid == ps->root || wid == ps->overlay)
|
|
|
|
return NULL;
|
2018-11-03 22:38:18 +00:00
|
|
|
|
2019-04-17 22:14:45 +00:00
|
|
|
auto w = find_managed_win(ps, wid);
|
2019-03-10 12:34:37 +00:00
|
|
|
if (!w)
|
|
|
|
w = find_toplevel(ps, wid);
|
|
|
|
if (!w)
|
2020-04-05 20:20:58 +00:00
|
|
|
w = find_managed_window_or_parent(ps, wid);
|
2019-03-10 12:34:37 +00:00
|
|
|
return w;
|
2018-11-03 22:38:18 +00:00
|
|
|
}
|
|
|
|
|
2018-10-02 19:22:26 +00:00
|
|
|
void queue_redraw(session_t *ps) {
|
2019-03-10 12:34:37 +00:00
|
|
|
// If --benchmark is used, redraw is always queued
|
2019-07-25 01:27:02 +00:00
|
|
|
if (!ps->redraw_needed && !ps->o.benchmark) {
|
2019-03-10 12:34:37 +00:00
|
|
|
ev_idle_start(ps->loop, &ps->draw_idle);
|
2019-07-25 01:27:02 +00:00
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
ps->redraw_needed = true;
|
2018-10-02 19:22:26 +00:00
|
|
|
}
|
|
|
|
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-30 03:56:00 +00:00
|
|
|
/**
|
|
|
|
* Get a region of the screen size.
|
|
|
|
*/
|
2019-03-10 12:34:37 +00:00
|
|
|
static inline void get_screen_region(session_t *ps, region_t *res) {
|
|
|
|
pixman_box32_t b = {.x1 = 0, .y1 = 0, .x2 = ps->root_width, .y2 = ps->root_height};
|
|
|
|
pixman_region32_fini(res);
|
|
|
|
pixman_region32_init_rects(res, &b, 1);
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-30 03:56:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void add_damage(session_t *ps, const region_t *damage) {
|
2019-03-10 12:34:37 +00:00
|
|
|
// Ignore damage when screen isn't redirected
|
2020-12-04 01:07:14 +00:00
|
|
|
if (!ps->redirected) {
|
2019-03-10 12:34:37 +00:00
|
|
|
return;
|
2020-12-04 01:07:14 +00:00
|
|
|
}
|
2018-09-09 01:29:45 +00:00
|
|
|
|
2020-12-04 01:07:14 +00:00
|
|
|
if (!damage) {
|
2019-03-10 12:34:37 +00:00
|
|
|
return;
|
2020-12-04 01:07:14 +00:00
|
|
|
}
|
|
|
|
log_trace("Adding damage: ");
|
|
|
|
dump_region(damage);
|
2019-03-10 12:34:37 +00:00
|
|
|
pixman_region32_union(ps->damage, ps->damage, (region_t *)damage);
|
2018-09-09 01:29:45 +00:00
|
|
|
}
|
|
|
|
|
2012-11-19 01:46:07 +00:00
|
|
|
// === Fading ===
|
2012-09-26 07:37:11 +00:00
|
|
|
|
2012-09-19 12:49:16 +00:00
|
|
|
/**
|
|
|
|
* Get the time left before next fading point.
|
|
|
|
*
|
|
|
|
* In milliseconds.
|
|
|
|
*/
|
2019-03-10 12:34:37 +00:00
|
|
|
static double fade_timeout(session_t *ps) {
|
|
|
|
auto now = get_time_ms();
|
|
|
|
if (ps->o.fade_delta + ps->fade_time < now)
|
|
|
|
return 0;
|
2018-12-21 16:25:28 +00:00
|
|
|
|
2019-03-30 09:07:21 +00:00
|
|
|
auto diff = ps->o.fade_delta + ps->fade_time - now;
|
2011-11-04 08:41:56 +00:00
|
|
|
|
2019-03-30 09:07:21 +00:00
|
|
|
diff = clamp(diff, 0, ps->o.fade_delta * 2);
|
2004-07-08 07:07:26 +00:00
|
|
|
|
2019-03-30 09:07:21 +00:00
|
|
|
return (double)diff / 1000.0;
|
2004-07-08 07:07:26 +00:00
|
|
|
}
|
|
|
|
|
2012-09-19 12:49:16 +00:00
|
|
|
/**
|
|
|
|
* Run fading on a window.
|
|
|
|
*
|
|
|
|
* @param steps steps of fading
|
2019-02-12 01:53:50 +00:00
|
|
|
* @return whether we are still in fading mode
|
2012-09-19 12:49:16 +00:00
|
|
|
*/
|
2019-04-17 22:14:45 +00:00
|
|
|
static bool run_fade(session_t *ps, struct managed_win **_w, long steps) {
|
|
|
|
auto w = *_w;
|
2019-03-10 12:34:37 +00:00
|
|
|
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
|
|
|
|
// We are not fading
|
2019-07-26 22:40:30 +00:00
|
|
|
assert(w->opacity_target == w->opacity);
|
2019-03-10 12:34:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!win_should_fade(ps, w)) {
|
2019-04-17 22:14:45 +00:00
|
|
|
log_debug("Window %#010x %s doesn't need fading", w->base.id, w->name);
|
2019-07-26 22:40:30 +00:00
|
|
|
w->opacity = w->opacity_target;
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
2019-07-26 22:40:30 +00:00
|
|
|
if (w->opacity == w->opacity_target) {
|
2019-03-27 15:30:37 +00:00
|
|
|
// We have reached target opacity.
|
|
|
|
// We don't call win_check_fade_finished here because that could destroy
|
|
|
|
// the window, but we still need the damage info from this window
|
2019-04-17 22:14:45 +00:00
|
|
|
log_debug("Fading finished for window %#010x %s", w->base.id, w->name);
|
2019-03-10 12:34:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (steps) {
|
2020-12-04 02:53:43 +00:00
|
|
|
log_trace("Window %#010x (%s) opacity was: %lf", w->base.id, w->name,
|
|
|
|
w->opacity);
|
2019-07-26 22:40:30 +00:00
|
|
|
if (w->opacity < w->opacity_target) {
|
2019-03-30 09:07:21 +00:00
|
|
|
w->opacity = clamp(w->opacity + ps->o.fade_in_step * (double)steps,
|
2019-07-26 22:40:30 +00:00
|
|
|
0.0, w->opacity_target);
|
2019-03-10 12:34:37 +00:00
|
|
|
} else {
|
2019-03-30 09:07:21 +00:00
|
|
|
w->opacity = clamp(w->opacity - ps->o.fade_out_step * (double)steps,
|
2019-07-26 22:40:30 +00:00
|
|
|
w->opacity_target, 1);
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
2020-12-04 02:53:43 +00:00
|
|
|
log_trace("... updated to: %lf", w->opacity);
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
|
2019-08-01 20:23:56 +00:00
|
|
|
// Note even if opacity == opacity_target here, we still want to run preprocess
|
|
|
|
// one last time to finish state transition. So return true in that case too.
|
2019-03-10 12:34:37 +00:00
|
|
|
return true;
|
2004-07-08 07:07:26 +00:00
|
|
|
}
|
|
|
|
|
2012-11-19 01:46:07 +00:00
|
|
|
// === Error handling ===
|
2012-02-08 22:45:08 +00:00
|
|
|
|
2019-03-17 13:44:26 +00:00
|
|
|
void discard_ignore(session_t *ps, unsigned long sequence) {
|
2019-03-10 12:34:37 +00:00
|
|
|
while (ps->ignore_head) {
|
|
|
|
if (sequence > ps->ignore_head->sequence) {
|
|
|
|
ignore_t *next = ps->ignore_head->next;
|
|
|
|
free(ps->ignore_head);
|
|
|
|
ps->ignore_head = next;
|
|
|
|
if (!ps->ignore_head) {
|
|
|
|
ps->ignore_tail = &ps->ignore_head;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2004-06-27 04:48:37 +00:00
|
|
|
}
|
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
static int should_ignore(session_t *ps, unsigned long sequence) {
|
2021-04-11 21:52:07 +00:00
|
|
|
if (ps == NULL) {
|
|
|
|
// Do not ignore errors until the session has been initialized
|
|
|
|
return false;
|
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
discard_ignore(ps, sequence);
|
|
|
|
return ps->ignore_head && ps->ignore_head->sequence == sequence;
|
2004-06-27 04:48:37 +00:00
|
|
|
}
|
|
|
|
|
2012-11-19 01:46:07 +00:00
|
|
|
// === Windows ===
|
2012-02-08 22:45:08 +00:00
|
|
|
|
2012-11-19 01:46:07 +00:00
|
|
|
/**
|
|
|
|
* Determine the event mask for a window.
|
|
|
|
*/
|
2019-03-30 09:07:21 +00:00
|
|
|
uint32_t determine_evmask(session_t *ps, xcb_window_t wid, win_evmode_t mode) {
|
|
|
|
uint32_t evmask = 0;
|
2019-04-17 22:14:45 +00:00
|
|
|
struct managed_win *w = NULL;
|
2012-09-13 15:12:54 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
// Check if it's a mapped frame window
|
2020-04-10 02:26:13 +00:00
|
|
|
if (mode == WIN_EVMODE_FRAME ||
|
2019-04-17 22:14:45 +00:00
|
|
|
((w = find_managed_win(ps, wid)) && w->a.map_state == XCB_MAP_STATE_VIEWABLE)) {
|
2020-04-10 02:26:13 +00:00
|
|
|
evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
|
2019-05-24 23:02:16 +00:00
|
|
|
if (!ps->o.use_ewmh_active_win) {
|
2019-03-10 12:34:37 +00:00
|
|
|
evmask |= XCB_EVENT_MASK_FOCUS_CHANGE;
|
2019-05-24 23:02:16 +00:00
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check if it's a mapped client window
|
2020-03-29 18:15:07 +00:00
|
|
|
if (mode == WIN_EVMODE_CLIENT ||
|
2019-03-10 12:34:37 +00:00
|
|
|
((w = find_toplevel(ps, wid)) && w->a.map_state == XCB_MAP_STATE_VIEWABLE)) {
|
2020-03-29 18:15:07 +00:00
|
|
|
evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE;
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
2012-09-13 14:30:18 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
return evmask;
|
2012-09-13 14:30:18 +00:00
|
|
|
}
|
|
|
|
|
2019-05-24 23:06:41 +00:00
|
|
|
/**
|
|
|
|
* Update current active window based on EWMH _NET_ACTIVE_WIN.
|
|
|
|
*
|
|
|
|
* Does not change anything if we fail to get the attribute or the window
|
|
|
|
* returned could not be found.
|
|
|
|
*/
|
|
|
|
void update_ewmh_active_win(session_t *ps) {
|
|
|
|
// Search for the window
|
2020-12-26 07:51:03 +00:00
|
|
|
xcb_window_t wid =
|
|
|
|
wid_get_prop_window(ps->c, ps->root, ps->atoms->a_NET_ACTIVE_WINDOW);
|
2019-05-24 23:06:41 +00:00
|
|
|
auto w = find_win_all(ps, wid);
|
|
|
|
|
|
|
|
// Mark the window focused. No need to unfocus the previous one.
|
|
|
|
if (w) {
|
|
|
|
win_set_focused(ps, w);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-13 13:38:55 +00:00
|
|
|
/**
|
|
|
|
* Recheck currently focused window and set its <code>w->focused</code>
|
2012-11-19 01:46:07 +00:00
|
|
|
* to true.
|
2012-09-13 13:38:55 +00:00
|
|
|
*
|
2012-11-19 01:46:07 +00:00
|
|
|
* @param ps current session
|
2012-09-13 13:38:55 +00:00
|
|
|
* @return struct _win of currently focused window, NULL if not found
|
|
|
|
*/
|
2019-05-24 23:06:41 +00:00
|
|
|
static void recheck_focus(session_t *ps) {
|
2019-03-10 12:34:37 +00:00
|
|
|
// Use EWMH _NET_ACTIVE_WINDOW if enabled
|
|
|
|
if (ps->o.use_ewmh_active_win) {
|
|
|
|
update_ewmh_active_win(ps);
|
2019-05-24 21:40:36 +00:00
|
|
|
return;
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
2012-11-04 10:11:08 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
// Determine the currently focused window so we can apply appropriate
|
|
|
|
// opacity on it
|
|
|
|
xcb_window_t wid = XCB_NONE;
|
|
|
|
xcb_get_input_focus_reply_t *reply =
|
|
|
|
xcb_get_input_focus_reply(ps->c, xcb_get_input_focus(ps->c), NULL);
|
2012-09-13 13:38:55 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
if (reply) {
|
|
|
|
wid = reply->focus;
|
|
|
|
free(reply);
|
|
|
|
}
|
2012-09-13 13:38:55 +00:00
|
|
|
|
2019-04-17 22:14:45 +00:00
|
|
|
auto w = find_win_all(ps, wid);
|
2012-09-13 13:38:55 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
log_trace("%#010" PRIx32 " (%#010lx \"%s\") focused.", wid,
|
2019-04-17 22:14:45 +00:00
|
|
|
(w ? w->base.id : XCB_NONE), (w ? w->name : NULL));
|
2013-10-21 14:17:01 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
// And we set the focus state here
|
|
|
|
if (w) {
|
2019-05-24 22:13:24 +00:00
|
|
|
win_set_focused(ps, w);
|
2019-05-24 21:40:36 +00:00
|
|
|
return;
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
2012-01-31 22:10:30 +00:00
|
|
|
}
|
|
|
|
|
core: delayed handling of root ConfigureNotify
Previously, root ConfigureNotify is handled immediately, by resetting
the backend, which in turn releases all the window images. This puts all
the windows into a state where they don't have images attached, which
they really should be in when the screen is redirected.
(To expand a little, a window without images should only exist if:
* It's an unmanaged window.
* Screen is unredirected.)
Normally, this kind of window could be fine, as the next render phase
will re-acquire images for them. However, if a window in this state is
destroyed with fading enabled, then the render phase won't try to
acquire images for it, causing it to go into the main rendering function
without images attached, and trigger an assertion.
This commit delays the handling of root ConfigureNotify until the render
phase. This way, the images will be immediately re-acquired after they
are released, thus prevent this problem from happening.
Also adds a testcase for this.
Fixes #357
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2020-03-31 04:01:14 +00:00
|
|
|
/**
|
|
|
|
* Rebuild cached <code>screen_reg</code>.
|
|
|
|
*/
|
|
|
|
static void rebuild_screen_reg(session_t *ps) {
|
|
|
|
get_screen_region(ps, &ps->screen_reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Rebuild <code>shadow_exclude_reg</code>.
|
|
|
|
*/
|
|
|
|
static void rebuild_shadow_exclude_reg(session_t *ps) {
|
|
|
|
bool ret = parse_geometry(ps, ps->o.shadow_exclude_reg_str, &ps->shadow_exclude_reg);
|
|
|
|
if (!ret)
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Free up all the images and deinit the backend
|
|
|
|
static void destroy_backend(session_t *ps) {
|
|
|
|
win_stack_foreach_managed_safe(w, &ps->window_stack) {
|
|
|
|
// Wrapping up fading in progress
|
|
|
|
if (win_skip_fading(ps, w)) {
|
|
|
|
// `w` is freed by win_skip_fading
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ps->backend_data) {
|
2020-11-28 19:31:43 +00:00
|
|
|
// Unmapped windows could still have shadow images, but not pixmap
|
|
|
|
// images
|
|
|
|
assert(!w->win_image || w->state != WSTATE_UNMAPPED);
|
2020-11-29 00:12:40 +00:00
|
|
|
if (win_check_flags_any(w, WIN_FLAGS_IMAGES_STALE) &&
|
|
|
|
w->state == WSTATE_MAPPED) {
|
|
|
|
log_warn("Stale flags set for mapped window %#010x "
|
|
|
|
"during backend destruction",
|
|
|
|
w->base.id);
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
// Unmapped windows can still have stale flags set, because their
|
|
|
|
// stale flags aren't handled until they are mapped.
|
2020-11-28 19:31:43 +00:00
|
|
|
win_clear_flags(w, WIN_FLAGS_IMAGES_STALE);
|
|
|
|
win_release_images(ps->backend_data, w);
|
core: delayed handling of root ConfigureNotify
Previously, root ConfigureNotify is handled immediately, by resetting
the backend, which in turn releases all the window images. This puts all
the windows into a state where they don't have images attached, which
they really should be in when the screen is redirected.
(To expand a little, a window without images should only exist if:
* It's an unmanaged window.
* Screen is unredirected.)
Normally, this kind of window could be fine, as the next render phase
will re-acquire images for them. However, if a window in this state is
destroyed with fading enabled, then the render phase won't try to
acquire images for it, causing it to go into the main rendering function
without images attached, and trigger an assertion.
This commit delays the handling of root ConfigureNotify until the render
phase. This way, the images will be immediately re-acquired after they
are released, thus prevent this problem from happening.
Also adds a testcase for this.
Fixes #357
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2020-03-31 04:01:14 +00:00
|
|
|
}
|
|
|
|
free_paint(ps, &w->paint);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ps->backend_data && ps->root_image) {
|
|
|
|
ps->backend_data->ops->release_image(ps->backend_data, ps->root_image);
|
|
|
|
ps->root_image = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ps->backend_data) {
|
|
|
|
// deinit backend
|
|
|
|
if (ps->backend_blur_context) {
|
|
|
|
ps->backend_data->ops->destroy_blur_context(
|
|
|
|
ps->backend_data, ps->backend_blur_context);
|
|
|
|
ps->backend_blur_context = NULL;
|
|
|
|
}
|
|
|
|
ps->backend_data->ops->deinit(ps->backend_data);
|
|
|
|
ps->backend_data = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool initialize_blur(session_t *ps) {
|
|
|
|
struct kernel_blur_args kargs;
|
|
|
|
struct gaussian_blur_args gargs;
|
|
|
|
struct box_blur_args bargs;
|
2019-12-20 19:31:00 +00:00
|
|
|
struct dual_kawase_blur_args dkargs;
|
core: delayed handling of root ConfigureNotify
Previously, root ConfigureNotify is handled immediately, by resetting
the backend, which in turn releases all the window images. This puts all
the windows into a state where they don't have images attached, which
they really should be in when the screen is redirected.
(To expand a little, a window without images should only exist if:
* It's an unmanaged window.
* Screen is unredirected.)
Normally, this kind of window could be fine, as the next render phase
will re-acquire images for them. However, if a window in this state is
destroyed with fading enabled, then the render phase won't try to
acquire images for it, causing it to go into the main rendering function
without images attached, and trigger an assertion.
This commit delays the handling of root ConfigureNotify until the render
phase. This way, the images will be immediately re-acquired after they
are released, thus prevent this problem from happening.
Also adds a testcase for this.
Fixes #357
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2020-03-31 04:01:14 +00:00
|
|
|
|
|
|
|
void *args = NULL;
|
|
|
|
switch (ps->o.blur_method) {
|
|
|
|
case BLUR_METHOD_BOX:
|
|
|
|
bargs.size = ps->o.blur_radius;
|
|
|
|
args = (void *)&bargs;
|
|
|
|
break;
|
|
|
|
case BLUR_METHOD_KERNEL:
|
|
|
|
kargs.kernel_count = ps->o.blur_kernel_count;
|
|
|
|
kargs.kernels = ps->o.blur_kerns;
|
|
|
|
args = (void *)&kargs;
|
|
|
|
break;
|
|
|
|
case BLUR_METHOD_GAUSSIAN:
|
|
|
|
gargs.size = ps->o.blur_radius;
|
|
|
|
gargs.deviation = ps->o.blur_deviation;
|
|
|
|
args = (void *)&gargs;
|
|
|
|
break;
|
2019-12-20 19:31:00 +00:00
|
|
|
case BLUR_METHOD_DUAL_KAWASE:
|
|
|
|
dkargs.size = ps->o.blur_radius;
|
|
|
|
dkargs.strength = ps->o.blur_strength;
|
|
|
|
args = (void *)&dkargs;
|
|
|
|
break;
|
core: delayed handling of root ConfigureNotify
Previously, root ConfigureNotify is handled immediately, by resetting
the backend, which in turn releases all the window images. This puts all
the windows into a state where they don't have images attached, which
they really should be in when the screen is redirected.
(To expand a little, a window without images should only exist if:
* It's an unmanaged window.
* Screen is unredirected.)
Normally, this kind of window could be fine, as the next render phase
will re-acquire images for them. However, if a window in this state is
destroyed with fading enabled, then the render phase won't try to
acquire images for it, causing it to go into the main rendering function
without images attached, and trigger an assertion.
This commit delays the handling of root ConfigureNotify until the render
phase. This way, the images will be immediately re-acquired after they
are released, thus prevent this problem from happening.
Also adds a testcase for this.
Fixes #357
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2020-03-31 04:01:14 +00:00
|
|
|
default: return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ps->backend_blur_context = ps->backend_data->ops->create_blur_context(
|
|
|
|
ps->backend_data, ps->o.blur_method, args);
|
|
|
|
return ps->backend_blur_context != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Init the backend and bind all the window pixmap to backend images
|
|
|
|
static bool initialize_backend(session_t *ps) {
|
|
|
|
if (ps->o.experimental_backends) {
|
|
|
|
assert(!ps->backend_data);
|
|
|
|
// Reinitialize win_data
|
|
|
|
assert(backend_list[ps->o.backend]);
|
|
|
|
ps->backend_data = backend_list[ps->o.backend]->init(ps);
|
|
|
|
if (!ps->backend_data) {
|
|
|
|
log_fatal("Failed to initialize backend, aborting...");
|
|
|
|
quit(ps);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
ps->backend_data->ops = backend_list[ps->o.backend];
|
|
|
|
|
|
|
|
if (!initialize_blur(ps)) {
|
|
|
|
log_fatal("Failed to prepare for background blur, aborting...");
|
|
|
|
ps->backend_data->ops->deinit(ps->backend_data);
|
|
|
|
ps->backend_data = NULL;
|
|
|
|
quit(ps);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// window_stack shouldn't include window that's
|
|
|
|
// not in the hash table at this point. Since
|
|
|
|
// there cannot be any fading windows.
|
|
|
|
HASH_ITER2(ps->windows, _w) {
|
|
|
|
if (!_w->managed) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto w = (struct managed_win *)_w;
|
|
|
|
assert(w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED);
|
2020-11-27 05:34:54 +00:00
|
|
|
// We need to reacquire image
|
|
|
|
log_debug("Marking window %#010x (%s) for update after "
|
|
|
|
"redirection",
|
|
|
|
w->base.id, w->name);
|
|
|
|
win_set_flags(w, WIN_FLAGS_IMAGES_STALE);
|
|
|
|
ps->pending_updates = true;
|
core: delayed handling of root ConfigureNotify
Previously, root ConfigureNotify is handled immediately, by resetting
the backend, which in turn releases all the window images. This puts all
the windows into a state where they don't have images attached, which
they really should be in when the screen is redirected.
(To expand a little, a window without images should only exist if:
* It's an unmanaged window.
* Screen is unredirected.)
Normally, this kind of window could be fine, as the next render phase
will re-acquire images for them. However, if a window in this state is
destroyed with fading enabled, then the render phase won't try to
acquire images for it, causing it to go into the main rendering function
without images attached, and trigger an assertion.
This commit delays the handling of root ConfigureNotify until the render
phase. This way, the images will be immediately re-acquired after they
are released, thus prevent this problem from happening.
Also adds a testcase for this.
Fixes #357
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2020-03-31 04:01:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The old backends binds pixmap lazily, nothing to do here
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Handle configure event of the root window
|
|
|
|
static void configure_root(session_t *ps) {
|
|
|
|
auto r = XCB_AWAIT(xcb_get_geometry, ps->c, ps->root);
|
|
|
|
if (!r) {
|
|
|
|
log_fatal("Failed to fetch root geometry");
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
log_info("Root configuration changed, new geometry: %dx%d", r->width, r->height);
|
|
|
|
bool has_root_change = false;
|
|
|
|
if (ps->redirected) {
|
|
|
|
// On root window changes
|
|
|
|
if (ps->o.experimental_backends) {
|
|
|
|
assert(ps->backend_data);
|
|
|
|
has_root_change = ps->backend_data->ops->root_change != NULL;
|
|
|
|
} else {
|
|
|
|
// Old backend can handle root change
|
|
|
|
has_root_change = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!has_root_change) {
|
|
|
|
// deinit/reinit backend and free up resources if the backend
|
|
|
|
// cannot handle root change
|
|
|
|
destroy_backend(ps);
|
|
|
|
}
|
|
|
|
free_paint(ps, &ps->tgt_buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
ps->root_width = r->width;
|
|
|
|
ps->root_height = r->height;
|
|
|
|
|
|
|
|
rebuild_screen_reg(ps);
|
|
|
|
rebuild_shadow_exclude_reg(ps);
|
|
|
|
|
|
|
|
// Invalidate reg_ignore from the top
|
|
|
|
auto top_w = win_stack_find_next_managed(ps, &ps->window_stack);
|
|
|
|
if (top_w) {
|
|
|
|
rc_region_unref(&top_w->reg_ignore);
|
|
|
|
top_w->reg_ignore_valid = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ps->redirected) {
|
|
|
|
for (int i = 0; i < ps->ndamage; i++) {
|
|
|
|
pixman_region32_clear(&ps->damage_ring[i]);
|
|
|
|
}
|
|
|
|
ps->damage = ps->damage_ring + ps->ndamage - 1;
|
|
|
|
#ifdef CONFIG_OPENGL
|
|
|
|
// GLX root change callback
|
|
|
|
if (BKEND_GLX == ps->o.backend && !ps->o.experimental_backends) {
|
|
|
|
glx_on_root_change(ps);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (has_root_change) {
|
|
|
|
if (ps->backend_data != NULL) {
|
|
|
|
ps->backend_data->ops->root_change(ps->backend_data, ps);
|
|
|
|
}
|
|
|
|
// Old backend's root_change is not a specific function
|
|
|
|
} else {
|
|
|
|
if (!initialize_backend(ps)) {
|
|
|
|
log_fatal("Failed to re-initialize backend after root "
|
|
|
|
"change, aborting...");
|
|
|
|
ps->quit = true;
|
2020-08-30 14:25:58 +00:00
|
|
|
/* TODO(yshui) only event handlers should request
|
|
|
|
* ev_break, otherwise it's too hard to keep track of what
|
|
|
|
* can break the event loop */
|
core: delayed handling of root ConfigureNotify
Previously, root ConfigureNotify is handled immediately, by resetting
the backend, which in turn releases all the window images. This puts all
the windows into a state where they don't have images attached, which
they really should be in when the screen is redirected.
(To expand a little, a window without images should only exist if:
* It's an unmanaged window.
* Screen is unredirected.)
Normally, this kind of window could be fine, as the next render phase
will re-acquire images for them. However, if a window in this state is
destroyed with fading enabled, then the render phase won't try to
acquire images for it, causing it to go into the main rendering function
without images attached, and trigger an assertion.
This commit delays the handling of root ConfigureNotify until the render
phase. This way, the images will be immediately re-acquired after they
are released, thus prevent this problem from happening.
Also adds a testcase for this.
Fixes #357
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2020-03-31 04:01:14 +00:00
|
|
|
ev_break(ps->loop, EVBREAK_ALL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Re-acquire the root pixmap.
|
|
|
|
root_damaged(ps);
|
|
|
|
}
|
|
|
|
force_repaint(ps);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-17 15:17:48 +00:00
|
|
|
static void handle_root_flags(session_t *ps) {
|
|
|
|
if ((ps->root_flags & ROOT_FLAGS_SCREEN_CHANGE) != 0) {
|
|
|
|
if (ps->o.xinerama_shadow_crop) {
|
|
|
|
cxinerama_upd_scrs(ps);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ps->o.sw_opti && !ps->o.refresh_rate) {
|
|
|
|
update_refresh_rate(ps);
|
|
|
|
if (!ps->refresh_rate) {
|
|
|
|
log_warn("Refresh rate detection failed. swopti will be "
|
|
|
|
"temporarily disabled");
|
|
|
|
}
|
|
|
|
}
|
2019-03-30 09:07:21 +00:00
|
|
|
ps->root_flags &= ~(uint64_t)ROOT_FLAGS_SCREEN_CHANGE;
|
2019-03-17 15:17:48 +00:00
|
|
|
}
|
core: delayed handling of root ConfigureNotify
Previously, root ConfigureNotify is handled immediately, by resetting
the backend, which in turn releases all the window images. This puts all
the windows into a state where they don't have images attached, which
they really should be in when the screen is redirected.
(To expand a little, a window without images should only exist if:
* It's an unmanaged window.
* Screen is unredirected.)
Normally, this kind of window could be fine, as the next render phase
will re-acquire images for them. However, if a window in this state is
destroyed with fading enabled, then the render phase won't try to
acquire images for it, causing it to go into the main rendering function
without images attached, and trigger an assertion.
This commit delays the handling of root ConfigureNotify until the render
phase. This way, the images will be immediately re-acquired after they
are released, thus prevent this problem from happening.
Also adds a testcase for this.
Fixes #357
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2020-03-31 04:01:14 +00:00
|
|
|
|
|
|
|
if ((ps->root_flags & ROOT_FLAGS_CONFIGURED) != 0) {
|
|
|
|
configure_root(ps);
|
|
|
|
ps->root_flags &= ~(uint64_t)ROOT_FLAGS_CONFIGURED;
|
|
|
|
}
|
2019-03-17 15:17:48 +00:00
|
|
|
}
|
|
|
|
|
2019-04-17 22:14:45 +00:00
|
|
|
static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
|
2019-03-10 12:34:37 +00:00
|
|
|
// XXX need better, more general name for `fade_running`. It really
|
|
|
|
// means if fade is still ongoing after the current frame is rendered
|
2019-04-17 22:14:45 +00:00
|
|
|
struct managed_win *bottom = NULL;
|
2019-03-10 12:34:37 +00:00
|
|
|
*fade_running = false;
|
|
|
|
|
|
|
|
// Fading step calculation
|
2019-03-30 09:07:21 +00:00
|
|
|
long steps = 0L;
|
2019-03-10 12:34:37 +00:00
|
|
|
auto now = get_time_ms();
|
|
|
|
if (ps->fade_time) {
|
|
|
|
assert(now >= ps->fade_time);
|
|
|
|
steps = (now - ps->fade_time) / ps->o.fade_delta;
|
|
|
|
} else {
|
|
|
|
// Reset fade_time if unset
|
|
|
|
ps->fade_time = get_time_ms();
|
|
|
|
steps = 0L;
|
|
|
|
}
|
|
|
|
ps->fade_time += steps * ps->o.fade_delta;
|
|
|
|
|
|
|
|
// First, let's process fading
|
2019-04-17 22:14:45 +00:00
|
|
|
win_stack_foreach_managed_safe(w, &ps->window_stack) {
|
2019-03-10 12:34:37 +00:00
|
|
|
const winmode_t mode_old = w->mode;
|
|
|
|
const bool was_painted = w->to_paint;
|
2019-03-27 18:50:46 +00:00
|
|
|
const double opacity_old = w->opacity;
|
2019-03-10 12:34:37 +00:00
|
|
|
|
|
|
|
if (win_should_dim(ps, w) != w->dim) {
|
|
|
|
w->dim = win_should_dim(ps, w);
|
|
|
|
add_damage_from_win(ps, w);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run fading
|
|
|
|
if (run_fade(ps, &w, steps)) {
|
|
|
|
*fade_running = true;
|
|
|
|
}
|
|
|
|
|
2019-03-27 15:30:37 +00:00
|
|
|
// Add window to damaged area if its opacity changes
|
|
|
|
// If was_painted == false, and to_paint is also false, we don't care
|
|
|
|
// If was_painted == false, but to_paint is true, damage will be added in
|
|
|
|
// the loop below
|
|
|
|
if (was_painted && w->opacity != opacity_old) {
|
|
|
|
add_damage_from_win(ps, w);
|
|
|
|
}
|
|
|
|
|
2019-09-16 21:14:34 +00:00
|
|
|
if (win_check_fade_finished(ps, w)) {
|
|
|
|
// the window has been destroyed because fading finished
|
2019-03-10 12:34:37 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (win_has_frame(w)) {
|
|
|
|
w->frame_opacity = ps->o.frame_opacity;
|
|
|
|
} else {
|
|
|
|
w->frame_opacity = 1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update window mode
|
|
|
|
w->mode = win_calc_mode(w);
|
|
|
|
|
|
|
|
// Destroy all reg_ignore above when frame opaque state changes on
|
|
|
|
// SOLID mode
|
|
|
|
if (was_painted && w->mode != mode_old) {
|
|
|
|
w->reg_ignore_valid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Opacity will not change, from now on.
|
|
|
|
rc_region_t *last_reg_ignore = rc_region_new();
|
|
|
|
|
|
|
|
bool unredir_possible = false;
|
2019-03-25 00:56:34 +00:00
|
|
|
// Track whether it's the highest window to paint
|
2019-03-10 12:34:37 +00:00
|
|
|
bool is_highest = true;
|
|
|
|
bool reg_ignore_valid = true;
|
2019-04-17 22:14:45 +00:00
|
|
|
win_stack_foreach_managed(w, &ps->window_stack) {
|
2019-03-10 12:34:37 +00:00
|
|
|
__label__ skip_window;
|
|
|
|
bool to_paint = true;
|
|
|
|
// w->to_paint remembers whether this window is painted last time
|
|
|
|
const bool was_painted = w->to_paint;
|
|
|
|
|
|
|
|
// Destroy reg_ignore if some window above us invalidated it
|
2019-03-25 00:56:34 +00:00
|
|
|
if (!reg_ignore_valid) {
|
2019-03-10 12:34:37 +00:00
|
|
|
rc_region_unref(&w->reg_ignore);
|
2019-03-25 00:56:34 +00:00
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
|
|
|
|
// log_trace("%d %d %s", w->a.map_state, w->ever_damaged, w->name);
|
|
|
|
|
|
|
|
// Give up if it's not damaged or invisible, or it's unmapped and its
|
|
|
|
// pixmap is gone (for example due to a ConfigureNotify), or when it's
|
|
|
|
// excluded
|
2020-12-04 02:53:43 +00:00
|
|
|
if (w->state == WSTATE_UNMAPPED ||
|
|
|
|
unlikely(w->base.id == ps->debug_window ||
|
|
|
|
w->client_win == ps->debug_window)) {
|
|
|
|
to_paint = false;
|
win: fix window not being rendered when it's mapped and damged while fading out
Consider these 2 cases:
* A window is mapped while fading out
* A window is mapped and damaged while fading out
From the perspective of map_win_start, these 2 cases look the same. The
window will has ever_damage = true in both cases. However, map_win_start
has to distinguish between these 2 cases, because at the end of
map_win_start, window in the first case cannot have ever_damage = true,
while window in the second case should have ever_damage = true.
Currently, map_win_start always clears ever_damage in both cases
(indirectly through win_skip_fading), which causes windows in the second
case to not be rendered when they should be.
This commit move clearing of ever_damage from unmap_win_finish to
unmap_win_start, so when map_win_start sees ever_damage = true, it's
always to second case. And to make sure windows which are fading out are
still rendered, we relax the ever_damage check in paint_preprocess to
also accept windows that are fading out. (see code comment for
explanation why this is fine)
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2020-12-04 03:06:30 +00:00
|
|
|
} else if (!w->ever_damaged && w->state != WSTATE_UNMAPPING &&
|
|
|
|
w->state != WSTATE_DESTROYING) {
|
|
|
|
// Unmapping clears w->ever_damaged, but the fact that the window
|
|
|
|
// is fading out means it must have been damaged when it was still
|
|
|
|
// mapped (because unmap_win_start will skip fading if it wasn't),
|
|
|
|
// so we still need to paint it.
|
2020-12-04 02:53:43 +00:00
|
|
|
log_trace("Window %#010x (%s) will not be painted because it has "
|
|
|
|
"not received any damages",
|
|
|
|
w->base.id, w->name);
|
|
|
|
to_paint = false;
|
|
|
|
} else if (unlikely(w->g.x + w->g.width < 1 || w->g.y + w->g.height < 1 ||
|
|
|
|
w->g.x >= ps->root_width || w->g.y >= ps->root_height)) {
|
|
|
|
log_trace("Window %#010x (%s) will not be painted because it is "
|
|
|
|
"positioned outside of the screen",
|
|
|
|
w->base.id, w->name);
|
|
|
|
to_paint = false;
|
|
|
|
} else if (unlikely((double)w->opacity * MAX_ALPHA < 1 && !w->blur_background)) {
|
2020-08-30 14:25:58 +00:00
|
|
|
/* TODO(yshui) for consistency, even a window has 0 opacity, we
|
|
|
|
* still probably need to blur its background, so to_paint
|
|
|
|
* shouldn't be false for them. */
|
2020-12-04 02:53:43 +00:00
|
|
|
log_trace("Window %#010x (%s) will not be painted because it has "
|
|
|
|
"0 opacity",
|
|
|
|
w->base.id, w->name);
|
2019-03-10 12:34:37 +00:00
|
|
|
to_paint = false;
|
2020-12-04 02:53:43 +00:00
|
|
|
} else if (w->paint_excluded) {
|
|
|
|
log_trace("Window %#010x (%s) will not be painted because it is "
|
|
|
|
"excluded from painting",
|
|
|
|
w->base.id, w->name);
|
2019-07-07 15:15:26 +00:00
|
|
|
to_paint = false;
|
2020-12-04 02:53:43 +00:00
|
|
|
} else if (unlikely((w->flags & WIN_FLAGS_IMAGE_ERROR) != 0)) {
|
|
|
|
log_trace("Window %#010x (%s) will not be painted because it has "
|
|
|
|
"image errors",
|
|
|
|
w->base.id, w->name);
|
2019-03-17 03:04:23 +00:00
|
|
|
to_paint = false;
|
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
// log_trace("%s %d %d %d", w->name, to_paint, w->opacity,
|
|
|
|
// w->paint_excluded);
|
|
|
|
|
|
|
|
// Add window to damaged area if its painting status changes
|
|
|
|
// or opacity changes
|
|
|
|
if (to_paint != was_painted) {
|
|
|
|
w->reg_ignore_valid = false;
|
|
|
|
add_damage_from_win(ps, w);
|
|
|
|
}
|
|
|
|
|
2019-04-14 00:01:44 +00:00
|
|
|
// to_paint will never change after this point
|
|
|
|
if (!to_paint) {
|
2019-03-10 12:34:37 +00:00
|
|
|
goto skip_window;
|
2019-04-14 00:01:44 +00:00
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2020-12-04 02:53:43 +00:00
|
|
|
log_trace("Window %#010x (%s) will be painted", w->base.id, w->name);
|
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
// Calculate shadow opacity
|
|
|
|
w->shadow_opacity = ps->o.shadow_opacity * w->opacity * ps->o.frame_opacity;
|
|
|
|
|
|
|
|
// Generate ignore region for painting to reduce GPU load
|
2019-04-14 00:01:44 +00:00
|
|
|
if (!w->reg_ignore) {
|
2019-03-10 12:34:37 +00:00
|
|
|
w->reg_ignore = rc_region_ref(last_reg_ignore);
|
2019-04-14 00:01:44 +00:00
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-11-30 21:24:22 +00:00
|
|
|
// If the window is solid, or we enabled clipping for transparent windows,
|
|
|
|
// we add the window region to the ignored region
|
2019-03-10 12:34:37 +00:00
|
|
|
// Otherwise last_reg_ignore shouldn't change
|
2019-11-30 21:24:22 +00:00
|
|
|
if ((w->mode != WMODE_TRANS && !ps->o.force_win_blend) ||
|
|
|
|
ps->o.transparent_clipping) {
|
2019-10-24 18:36:19 +00:00
|
|
|
// w->mode == WMODE_SOLID or WMODE_FRAME_TRANS
|
2019-03-10 12:34:37 +00:00
|
|
|
region_t *tmp = rc_region_new();
|
2019-10-24 18:36:19 +00:00
|
|
|
if (w->mode == WMODE_SOLID) {
|
2020-09-05 14:43:25 +00:00
|
|
|
*tmp =
|
|
|
|
win_get_bounding_shape_global_without_corners_by_val(w);
|
2019-10-24 18:36:19 +00:00
|
|
|
} else {
|
|
|
|
// w->mode == WMODE_FRAME_TRANS
|
2020-09-05 14:43:25 +00:00
|
|
|
win_get_region_noframe_local_without_corners(w, tmp);
|
2019-03-10 12:34:37 +00:00
|
|
|
pixman_region32_intersect(tmp, tmp, &w->bounding_shape);
|
|
|
|
pixman_region32_translate(tmp, w->g.x, w->g.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
pixman_region32_union(tmp, tmp, last_reg_ignore);
|
|
|
|
rc_region_unref(&last_reg_ignore);
|
|
|
|
last_reg_ignore = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
// (Un)redirect screen
|
|
|
|
// We could definitely unredirect the screen when there's no window to
|
|
|
|
// paint, but this is typically unnecessary, may cause flickering when
|
|
|
|
// fading is enabled, and could create inconsistency when the wallpaper
|
|
|
|
// is not correctly set.
|
|
|
|
if (ps->o.unredir_if_possible && is_highest) {
|
2019-07-13 11:29:39 +00:00
|
|
|
if (w->mode == WMODE_SOLID && !ps->o.force_win_blend &&
|
|
|
|
win_is_fullscreen(ps, w) && !w->unredir_if_possible_excluded) {
|
2019-03-10 12:34:37 +00:00
|
|
|
unredir_possible = true;
|
2019-07-13 11:29:39 +00:00
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
|
2020-01-18 18:00:35 +00:00
|
|
|
// Unredirect screen if some window is requesting compositor bypass, even
|
|
|
|
// if that window is not on the top.
|
|
|
|
if (ps->o.unredir_if_possible && win_is_bypassing_compositor(ps, w) &&
|
|
|
|
!w->unredir_if_possible_excluded) {
|
|
|
|
// Here we deviate from EWMH a bit. EWMH says we must not
|
|
|
|
// unredirect the screen if the window requesting bypassing would
|
|
|
|
// look different after unredirecting. Instead we always follow
|
|
|
|
// the request.
|
|
|
|
unredir_possible = true;
|
|
|
|
}
|
|
|
|
|
2019-04-17 22:14:45 +00:00
|
|
|
w->prev_trans = bottom;
|
2019-07-25 23:00:51 +00:00
|
|
|
if (bottom) {
|
|
|
|
w->stacking_rank = bottom->stacking_rank + 1;
|
|
|
|
} else {
|
|
|
|
w->stacking_rank = 0;
|
|
|
|
}
|
2019-04-17 22:14:45 +00:00
|
|
|
bottom = w;
|
2019-03-10 12:34:37 +00:00
|
|
|
|
|
|
|
// If the screen is not redirected and the window has redir_ignore set,
|
|
|
|
// this window should not cause the screen to become redirected
|
|
|
|
if (!(ps->o.wintype_option[w->window_type].redir_ignore && !ps->redirected)) {
|
|
|
|
is_highest = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
skip_window:
|
|
|
|
reg_ignore_valid = reg_ignore_valid && w->reg_ignore_valid;
|
|
|
|
w->reg_ignore_valid = true;
|
|
|
|
|
|
|
|
// Avoid setting w->to_paint if w is freed
|
|
|
|
if (w) {
|
|
|
|
w->to_paint = to_paint;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rc_region_unref(&last_reg_ignore);
|
|
|
|
|
|
|
|
// If possible, unredirect all windows and stop painting
|
2019-03-24 04:47:25 +00:00
|
|
|
if (ps->o.redirected_force != UNSET) {
|
2019-03-10 12:34:37 +00:00
|
|
|
unredir_possible = !ps->o.redirected_force;
|
2019-03-24 04:47:25 +00:00
|
|
|
} else if (ps->o.unredir_if_possible && is_highest && !ps->redirected) {
|
2019-03-10 12:34:37 +00:00
|
|
|
// If there's no window to paint, and the screen isn't redirected,
|
|
|
|
// don't redirect it.
|
|
|
|
unredir_possible = true;
|
2019-03-24 04:47:25 +00:00
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
if (unredir_possible) {
|
|
|
|
if (ps->redirected) {
|
2019-09-28 22:43:36 +00:00
|
|
|
if (!ps->o.unredir_if_possible_delay || ps->tmout_unredir_hit) {
|
|
|
|
unredirect(ps);
|
|
|
|
} else if (!ev_is_active(&ps->unredir_timer)) {
|
2019-03-30 09:07:21 +00:00
|
|
|
ev_timer_set(
|
|
|
|
&ps->unredir_timer,
|
|
|
|
(double)ps->o.unredir_if_possible_delay / 1000.0, 0);
|
2019-03-10 12:34:37 +00:00
|
|
|
ev_timer_start(ps->loop, &ps->unredir_timer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ev_timer_stop(ps->loop, &ps->unredir_timer);
|
2019-03-24 04:47:25 +00:00
|
|
|
if (!ps->redirected) {
|
2019-09-28 22:43:36 +00:00
|
|
|
if (!redirect_start(ps)) {
|
2019-03-24 04:47:25 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-17 22:14:45 +00:00
|
|
|
return bottom;
|
2018-12-15 21:11:41 +00:00
|
|
|
}
|
2013-03-25 03:36:39 +00:00
|
|
|
|
2019-03-17 13:44:26 +00:00
|
|
|
void root_damaged(session_t *ps) {
|
2019-03-10 12:34:37 +00:00
|
|
|
if (ps->root_tile_paint.pixmap) {
|
|
|
|
free_root_tile(ps);
|
|
|
|
}
|
|
|
|
|
2019-03-24 15:40:37 +00:00
|
|
|
if (!ps->redirected) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-04-20 04:26:20 +00:00
|
|
|
if (ps->backend_data) {
|
2019-03-10 12:34:37 +00:00
|
|
|
if (ps->root_image) {
|
|
|
|
ps->backend_data->ops->release_image(ps->backend_data, ps->root_image);
|
|
|
|
}
|
2020-12-26 07:51:03 +00:00
|
|
|
auto pixmap = x_get_root_back_pixmap(ps->c, ps->root, ps->atoms);
|
2019-03-10 12:34:37 +00:00
|
|
|
if (pixmap != XCB_NONE) {
|
|
|
|
ps->root_image = ps->backend_data->ops->bind_pixmap(
|
|
|
|
ps->backend_data, pixmap, x_get_visual_info(ps->c, ps->vis), false);
|
2021-06-14 02:22:13 +00:00
|
|
|
ps->backend_data->ops->set_image_property(
|
|
|
|
ps->backend_data, IMAGE_PROPERTY_EFFECTIVE_SIZE,
|
|
|
|
ps->root_image, (int[]){ps->root_width, ps->root_height});
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mark screen damaged
|
|
|
|
force_repaint(ps);
|
2012-10-24 02:09:59 +00:00
|
|
|
}
|
|
|
|
|
2018-09-29 09:11:43 +00:00
|
|
|
/**
|
|
|
|
* Xlib error handler function.
|
|
|
|
*/
|
2019-03-10 12:34:37 +00:00
|
|
|
static int xerror(Display attr_unused *dpy, XErrorEvent *ev) {
|
2021-04-11 21:52:07 +00:00
|
|
|
if (!should_ignore(ps_g, ev->serial)) {
|
2019-03-10 12:34:37 +00:00
|
|
|
x_print_error(ev->serial, ev->request_code, ev->minor_code, ev->error_code);
|
2021-04-11 21:52:07 +00:00
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
return 0;
|
2003-11-09 07:08:23 +00:00
|
|
|
}
|
|
|
|
|
2018-09-29 09:11:43 +00:00
|
|
|
/**
|
|
|
|
* XCB error handler function.
|
|
|
|
*/
|
2019-03-10 12:34:37 +00:00
|
|
|
void ev_xcb_error(session_t *ps, xcb_generic_error_t *err) {
|
2021-04-11 21:52:07 +00:00
|
|
|
if (!should_ignore(ps, err->sequence)) {
|
2019-03-10 12:34:37 +00:00
|
|
|
x_print_error(err->sequence, err->major_code, err->minor_code, err->error_code);
|
2021-04-11 21:52:07 +00:00
|
|
|
}
|
2018-09-29 09:11:43 +00:00
|
|
|
}
|
|
|
|
|
2013-01-24 05:38:03 +00:00
|
|
|
/**
|
|
|
|
* Force a full-screen repaint.
|
|
|
|
*/
|
2019-03-10 12:34:37 +00:00
|
|
|
void force_repaint(session_t *ps) {
|
|
|
|
assert(pixman_region32_not_empty(&ps->screen_reg));
|
|
|
|
queue_redraw(ps);
|
|
|
|
add_damage(ps, &ps->screen_reg);
|
2013-01-24 05:38:03 +00:00
|
|
|
}
|
|
|
|
|
Feature #80: D-Bus support
- Add D-Bus support. Currently 7 methods are available: "reset" (same as
SIGUSR1), "list_win" (list the windows compton manages), "win_get"
(get a property of the window), "win_set" (set a property of the
window), "find_win" (find window based on client window / focus),
"opts_get" (get the value of a compton option), and "opts_set" (set
the value of a compton option), together with 4 signals: "win_added",
"win_destroyed", "win_mapped", "win_unmapped".
- D-Bus support depends on libdbus.
- As there are many items and my time is tight, no much tests are done.
Bugs to be expected.
- Create a new header file `common.h` that contains shared content.
- Fix some bugs in timeout handling.
- Update file headers in all source files.
- Re-enable --unredir-if-possible on multi-screen set-ups, as the user
could turn if off manually anyway.
- Check if the window is mapped in `repair_win()`.
- Add ps->track_atom_lst and its handlers, to prepare for the new
condition format.
- Known issue 1: "win_get", "win_set", "opts_get", "opts_set" support a
very limited number of targets only. New ones will be added gradually.
- Known issue 2: Accidental drop of D-Bus connection is not handled.
- Known issue 3: Introspection does not reveal all available methods,
because some methods have unpredictable prototypes. Still hesitating
about what to do...
- Known issue 4: Error handling is not finished yet. Compton does not
always reply with the correct error message (but it does print out the
correct error message, usually).
2013-01-19 12:20:27 +00:00
|
|
|
#ifdef CONFIG_DBUS
|
|
|
|
/** @name DBus hooks
|
|
|
|
*/
|
|
|
|
///@{
|
|
|
|
|
2013-05-20 10:04:40 +00:00
|
|
|
/**
|
|
|
|
* Set no_fading_openclose option.
|
2019-02-09 15:50:40 +00:00
|
|
|
*
|
|
|
|
* Don't affect fading already in progress
|
2013-05-20 10:04:40 +00:00
|
|
|
*/
|
2019-03-10 12:34:37 +00:00
|
|
|
void opts_set_no_fading_openclose(session_t *ps, bool newval) {
|
|
|
|
ps->o.no_fading_openclose = newval;
|
2013-05-20 10:04:40 +00:00
|
|
|
}
|
|
|
|
|
Feature #80: D-Bus support
- Add D-Bus support. Currently 7 methods are available: "reset" (same as
SIGUSR1), "list_win" (list the windows compton manages), "win_get"
(get a property of the window), "win_set" (set a property of the
window), "find_win" (find window based on client window / focus),
"opts_get" (get the value of a compton option), and "opts_set" (set
the value of a compton option), together with 4 signals: "win_added",
"win_destroyed", "win_mapped", "win_unmapped".
- D-Bus support depends on libdbus.
- As there are many items and my time is tight, no much tests are done.
Bugs to be expected.
- Create a new header file `common.h` that contains shared content.
- Fix some bugs in timeout handling.
- Update file headers in all source files.
- Re-enable --unredir-if-possible on multi-screen set-ups, as the user
could turn if off manually anyway.
- Check if the window is mapped in `repair_win()`.
- Add ps->track_atom_lst and its handlers, to prepare for the new
condition format.
- Known issue 1: "win_get", "win_set", "opts_get", "opts_set" support a
very limited number of targets only. New ones will be added gradually.
- Known issue 2: Accidental drop of D-Bus connection is not handled.
- Known issue 3: Introspection does not reveal all available methods,
because some methods have unpredictable prototypes. Still hesitating
about what to do...
- Known issue 4: Error handling is not finished yet. Compton does not
always reply with the correct error message (but it does print out the
correct error message, usually).
2013-01-19 12:20:27 +00:00
|
|
|
//!@}
|
|
|
|
#endif
|
|
|
|
|
Feature: #7: VSync
- Add VSync feature. 3 possible VSync methods available: "sw" (software,
not too reliable, but at least you have something to fallback to),
"drm" (using DRM_IOCTL_WAIT_VBLANK, should work only on DRI drivers),
"opengl" (using SGI_swap_control extension OpenGL, might work on more
drivers than the DRM method). "sw" and "opengl" are briefly tested,
"drm" received utterly no test (because I use the nVidia binary blob).
They are enabled with "--vsync sw" / "--vsync drm" / "--vsync opengl".
- Add --refresh-rate to let user specify a refresh rate for software
VSync, in case the automatic refresh rate detection does not work
well.
- Seemingly the automatic refresh rate detection using X RandR in
software VSync detects refresh rate incorrectly. Need further investigation.
- Fix a few bugs in fading timing.
- Add a workaround for client window detection on Fluxbox, as Fluxbox
(incorrectly?) sets the override-redirect flag upon all frame
windows.
- Software VSync adds dependency on librt (a part of glibc) for
nanosecond-level timing functions, and libXrandr for automatic refresh
rate detection; DRM VSync adds dependency on libdrm to use its drm.h,
but does not link to libdrm; OpenGL VSync adds dependency on libGL.
- Print timing information on DEBUG_REPAINT.
2012-10-08 02:20:01 +00:00
|
|
|
/**
|
2020-10-22 00:39:51 +00:00
|
|
|
* Setup window properties, then register us with the compositor selection (_NET_WM_CM_S)
|
2020-03-11 19:15:26 +00:00
|
|
|
*
|
|
|
|
* @return 0 if success, 1 if compositor already running, -1 if error.
|
Feature: #7: VSync
- Add VSync feature. 3 possible VSync methods available: "sw" (software,
not too reliable, but at least you have something to fallback to),
"drm" (using DRM_IOCTL_WAIT_VBLANK, should work only on DRI drivers),
"opengl" (using SGI_swap_control extension OpenGL, might work on more
drivers than the DRM method). "sw" and "opengl" are briefly tested,
"drm" received utterly no test (because I use the nVidia binary blob).
They are enabled with "--vsync sw" / "--vsync drm" / "--vsync opengl".
- Add --refresh-rate to let user specify a refresh rate for software
VSync, in case the automatic refresh rate detection does not work
well.
- Seemingly the automatic refresh rate detection using X RandR in
software VSync detects refresh rate incorrectly. Need further investigation.
- Fix a few bugs in fading timing.
- Add a workaround for client window detection on Fluxbox, as Fluxbox
(incorrectly?) sets the override-redirect flag upon all frame
windows.
- Software VSync adds dependency on librt (a part of glibc) for
nanosecond-level timing functions, and libXrandr for automatic refresh
rate detection; DRM VSync adds dependency on libdrm to use its drm.h,
but does not link to libdrm; OpenGL VSync adds dependency on libGL.
- Print timing information on DEBUG_REPAINT.
2012-10-08 02:20:01 +00:00
|
|
|
*/
|
2020-03-11 19:15:26 +00:00
|
|
|
static int register_cm(session_t *ps) {
|
2019-03-10 12:34:37 +00:00
|
|
|
assert(!ps->reg_win);
|
|
|
|
|
2019-04-08 04:49:39 +00:00
|
|
|
ps->reg_win = x_new_id(ps->c);
|
2019-03-30 09:07:21 +00:00
|
|
|
auto e = xcb_request_check(
|
|
|
|
ps->c, xcb_create_window_checked(ps->c, XCB_COPY_FROM_PARENT, ps->reg_win, ps->root,
|
|
|
|
0, 0, 1, 1, 0, XCB_NONE, ps->vis, 0, NULL));
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-03-30 09:07:21 +00:00
|
|
|
if (e) {
|
2019-03-10 12:34:37 +00:00
|
|
|
log_fatal("Failed to create window.");
|
2019-03-30 09:07:21 +00:00
|
|
|
free(e);
|
2020-03-11 19:15:26 +00:00
|
|
|
return -1;
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
|
2020-10-22 00:39:51 +00:00
|
|
|
const xcb_atom_t prop_atoms[] = {
|
|
|
|
ps->atoms->aWM_NAME,
|
|
|
|
ps->atoms->a_NET_WM_NAME,
|
|
|
|
ps->atoms->aWM_ICON_NAME,
|
|
|
|
};
|
|
|
|
|
|
|
|
const bool prop_is_utf8[] = {false, true, false};
|
|
|
|
|
|
|
|
// Set names and classes
|
|
|
|
for (size_t i = 0; i < ARR_SIZE(prop_atoms); i++) {
|
|
|
|
e = xcb_request_check(
|
|
|
|
ps->c, xcb_change_property_checked(
|
|
|
|
ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win, prop_atoms[i],
|
|
|
|
prop_is_utf8[i] ? ps->atoms->aUTF8_STRING : XCB_ATOM_STRING,
|
|
|
|
8, strlen("picom"), "picom"));
|
|
|
|
if (e) {
|
|
|
|
log_error_x_error(e, "Failed to set window property %d",
|
|
|
|
prop_atoms[i]);
|
|
|
|
free(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char picom_class[] = "picom\0picom";
|
|
|
|
e = xcb_request_check(
|
|
|
|
ps->c, xcb_change_property_checked(ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win,
|
|
|
|
ps->atoms->aWM_CLASS, XCB_ATOM_STRING, 8,
|
|
|
|
ARR_SIZE(picom_class), picom_class));
|
|
|
|
if (e) {
|
|
|
|
log_error_x_error(e, "Failed to set the WM_CLASS property");
|
|
|
|
free(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set WM_CLIENT_MACHINE. As per EWMH, because we set _NET_WM_PID, we must also
|
|
|
|
// set WM_CLIENT_MACHINE.
|
2019-03-10 12:34:37 +00:00
|
|
|
{
|
2020-10-25 03:13:03 +00:00
|
|
|
const auto hostname_max = (unsigned long)sysconf(_SC_HOST_NAME_MAX);
|
|
|
|
char *hostname = malloc(hostname_max);
|
|
|
|
|
|
|
|
if (gethostname(hostname, hostname_max) == 0) {
|
2020-10-22 00:39:51 +00:00
|
|
|
e = xcb_request_check(
|
|
|
|
ps->c, xcb_change_property_checked(
|
|
|
|
ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win,
|
|
|
|
ps->atoms->aWM_CLIENT_MACHINE, XCB_ATOM_STRING, 8,
|
|
|
|
(uint32_t)strlen(hostname), hostname));
|
|
|
|
if (e) {
|
|
|
|
log_error_x_error(e, "Failed to set the WM_CLIENT_MACHINE"
|
|
|
|
" property");
|
|
|
|
free(e);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log_error_errno("Failed to get hostname");
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
2020-10-25 03:13:03 +00:00
|
|
|
|
|
|
|
free(hostname);
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set _NET_WM_PID
|
|
|
|
{
|
2019-03-30 09:07:21 +00:00
|
|
|
auto pid = getpid();
|
2019-03-10 12:34:37 +00:00
|
|
|
xcb_change_property(ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win,
|
2019-06-09 18:25:34 +00:00
|
|
|
ps->atoms->a_NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, &pid);
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set COMPTON_VERSION
|
2020-10-21 02:06:15 +00:00
|
|
|
e = xcb_request_check(
|
|
|
|
ps->c, xcb_change_property_checked(
|
|
|
|
ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win,
|
|
|
|
get_atom(ps->atoms, "COMPTON_VERSION"), XCB_ATOM_STRING, 8,
|
|
|
|
(uint32_t)strlen(COMPTON_VERSION), COMPTON_VERSION));
|
|
|
|
if (e) {
|
|
|
|
log_error_x_error(e, "Failed to set COMPTON_VERSION.");
|
|
|
|
free(e);
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Acquire X Selection _NET_WM_CM_S?
|
|
|
|
if (!ps->o.no_x_selection) {
|
2019-05-06 00:24:38 +00:00
|
|
|
const char register_prop[] = "_NET_WM_CM_S";
|
2019-03-30 09:07:21 +00:00
|
|
|
xcb_atom_t atom;
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-05-06 00:24:38 +00:00
|
|
|
char *buf = NULL;
|
|
|
|
if (asprintf(&buf, "%s%d", register_prop, ps->scr) < 0) {
|
|
|
|
log_fatal("Failed to allocate memory");
|
2020-03-11 19:15:26 +00:00
|
|
|
return -1;
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
2019-05-05 23:34:08 +00:00
|
|
|
atom = get_atom(ps->atoms, buf);
|
2019-03-10 12:34:37 +00:00
|
|
|
free(buf);
|
|
|
|
|
|
|
|
xcb_get_selection_owner_reply_t *reply = xcb_get_selection_owner_reply(
|
|
|
|
ps->c, xcb_get_selection_owner(ps->c, atom), NULL);
|
|
|
|
|
|
|
|
if (reply && reply->owner != XCB_NONE) {
|
2020-03-11 19:15:26 +00:00
|
|
|
// Another compositor already running
|
2019-03-10 12:34:37 +00:00
|
|
|
free(reply);
|
2020-03-11 19:15:26 +00:00
|
|
|
return 1;
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
free(reply);
|
|
|
|
xcb_set_selection_owner(ps->c, ps->reg_win, atom, 0);
|
|
|
|
}
|
|
|
|
|
2020-03-11 19:15:26 +00:00
|
|
|
return 0;
|
2005-10-07 00:08:02 +00:00
|
|
|
}
|
|
|
|
|
2013-11-09 13:38:31 +00:00
|
|
|
/**
|
|
|
|
* Write PID to a file.
|
|
|
|
*/
|
2019-03-10 12:34:37 +00:00
|
|
|
static inline bool write_pid(session_t *ps) {
|
2020-10-22 00:39:51 +00:00
|
|
|
if (!ps->o.write_pid_path) {
|
2019-03-10 12:34:37 +00:00
|
|
|
return true;
|
2020-10-22 00:39:51 +00:00
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
|
|
|
|
FILE *f = fopen(ps->o.write_pid_path, "w");
|
|
|
|
if (unlikely(!f)) {
|
|
|
|
log_error("Failed to write PID to \"%s\".", ps->o.write_pid_path);
|
|
|
|
return false;
|
|
|
|
}
|
2013-11-09 13:38:31 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
fprintf(f, "%ld\n", (long)getpid());
|
|
|
|
fclose(f);
|
2013-11-09 13:38:31 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
return true;
|
2013-11-09 13:38:31 +00:00
|
|
|
}
|
|
|
|
|
Feature: #7: VSync
- Add VSync feature. 3 possible VSync methods available: "sw" (software,
not too reliable, but at least you have something to fallback to),
"drm" (using DRM_IOCTL_WAIT_VBLANK, should work only on DRI drivers),
"opengl" (using SGI_swap_control extension OpenGL, might work on more
drivers than the DRM method). "sw" and "opengl" are briefly tested,
"drm" received utterly no test (because I use the nVidia binary blob).
They are enabled with "--vsync sw" / "--vsync drm" / "--vsync opengl".
- Add --refresh-rate to let user specify a refresh rate for software
VSync, in case the automatic refresh rate detection does not work
well.
- Seemingly the automatic refresh rate detection using X RandR in
software VSync detects refresh rate incorrectly. Need further investigation.
- Fix a few bugs in fading timing.
- Add a workaround for client window detection on Fluxbox, as Fluxbox
(incorrectly?) sets the override-redirect flag upon all frame
windows.
- Software VSync adds dependency on librt (a part of glibc) for
nanosecond-level timing functions, and libXrandr for automatic refresh
rate detection; DRM VSync adds dependency on libdrm to use its drm.h,
but does not link to libdrm; OpenGL VSync adds dependency on libGL.
- Print timing information on DEBUG_REPAINT.
2012-10-08 02:20:01 +00:00
|
|
|
/**
|
|
|
|
* Update refresh rate info with X Randr extension.
|
|
|
|
*/
|
2019-03-17 13:44:26 +00:00
|
|
|
void update_refresh_rate(session_t *ps) {
|
2019-03-10 12:34:37 +00:00
|
|
|
xcb_randr_get_screen_info_reply_t *randr_info = xcb_randr_get_screen_info_reply(
|
|
|
|
ps->c, xcb_randr_get_screen_info(ps->c, ps->root), NULL);
|
Feature: #7: VSync
- Add VSync feature. 3 possible VSync methods available: "sw" (software,
not too reliable, but at least you have something to fallback to),
"drm" (using DRM_IOCTL_WAIT_VBLANK, should work only on DRI drivers),
"opengl" (using SGI_swap_control extension OpenGL, might work on more
drivers than the DRM method). "sw" and "opengl" are briefly tested,
"drm" received utterly no test (because I use the nVidia binary blob).
They are enabled with "--vsync sw" / "--vsync drm" / "--vsync opengl".
- Add --refresh-rate to let user specify a refresh rate for software
VSync, in case the automatic refresh rate detection does not work
well.
- Seemingly the automatic refresh rate detection using X RandR in
software VSync detects refresh rate incorrectly. Need further investigation.
- Fix a few bugs in fading timing.
- Add a workaround for client window detection on Fluxbox, as Fluxbox
(incorrectly?) sets the override-redirect flag upon all frame
windows.
- Software VSync adds dependency on librt (a part of glibc) for
nanosecond-level timing functions, and libXrandr for automatic refresh
rate detection; DRM VSync adds dependency on libdrm to use its drm.h,
but does not link to libdrm; OpenGL VSync adds dependency on libGL.
- Print timing information on DEBUG_REPAINT.
2012-10-08 02:20:01 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
if (!randr_info)
|
|
|
|
return;
|
|
|
|
ps->refresh_rate = randr_info->rate;
|
|
|
|
free(randr_info);
|
Feature: #7: VSync
- Add VSync feature. 3 possible VSync methods available: "sw" (software,
not too reliable, but at least you have something to fallback to),
"drm" (using DRM_IOCTL_WAIT_VBLANK, should work only on DRI drivers),
"opengl" (using SGI_swap_control extension OpenGL, might work on more
drivers than the DRM method). "sw" and "opengl" are briefly tested,
"drm" received utterly no test (because I use the nVidia binary blob).
They are enabled with "--vsync sw" / "--vsync drm" / "--vsync opengl".
- Add --refresh-rate to let user specify a refresh rate for software
VSync, in case the automatic refresh rate detection does not work
well.
- Seemingly the automatic refresh rate detection using X RandR in
software VSync detects refresh rate incorrectly. Need further investigation.
- Fix a few bugs in fading timing.
- Add a workaround for client window detection on Fluxbox, as Fluxbox
(incorrectly?) sets the override-redirect flag upon all frame
windows.
- Software VSync adds dependency on librt (a part of glibc) for
nanosecond-level timing functions, and libXrandr for automatic refresh
rate detection; DRM VSync adds dependency on libdrm to use its drm.h,
but does not link to libdrm; OpenGL VSync adds dependency on libGL.
- Print timing information on DEBUG_REPAINT.
2012-10-08 02:20:01 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
if (ps->refresh_rate)
|
|
|
|
ps->refresh_intv = US_PER_SEC / ps->refresh_rate;
|
|
|
|
else
|
|
|
|
ps->refresh_intv = 0;
|
Feature: #7: VSync
- Add VSync feature. 3 possible VSync methods available: "sw" (software,
not too reliable, but at least you have something to fallback to),
"drm" (using DRM_IOCTL_WAIT_VBLANK, should work only on DRI drivers),
"opengl" (using SGI_swap_control extension OpenGL, might work on more
drivers than the DRM method). "sw" and "opengl" are briefly tested,
"drm" received utterly no test (because I use the nVidia binary blob).
They are enabled with "--vsync sw" / "--vsync drm" / "--vsync opengl".
- Add --refresh-rate to let user specify a refresh rate for software
VSync, in case the automatic refresh rate detection does not work
well.
- Seemingly the automatic refresh rate detection using X RandR in
software VSync detects refresh rate incorrectly. Need further investigation.
- Fix a few bugs in fading timing.
- Add a workaround for client window detection on Fluxbox, as Fluxbox
(incorrectly?) sets the override-redirect flag upon all frame
windows.
- Software VSync adds dependency on librt (a part of glibc) for
nanosecond-level timing functions, and libXrandr for automatic refresh
rate detection; DRM VSync adds dependency on libdrm to use its drm.h,
but does not link to libdrm; OpenGL VSync adds dependency on libGL.
- Print timing information on DEBUG_REPAINT.
2012-10-08 02:20:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2012-10-26 03:12:28 +00:00
|
|
|
* Initialize refresh-rated based software optimization.
|
Feature: #7: VSync
- Add VSync feature. 3 possible VSync methods available: "sw" (software,
not too reliable, but at least you have something to fallback to),
"drm" (using DRM_IOCTL_WAIT_VBLANK, should work only on DRI drivers),
"opengl" (using SGI_swap_control extension OpenGL, might work on more
drivers than the DRM method). "sw" and "opengl" are briefly tested,
"drm" received utterly no test (because I use the nVidia binary blob).
They are enabled with "--vsync sw" / "--vsync drm" / "--vsync opengl".
- Add --refresh-rate to let user specify a refresh rate for software
VSync, in case the automatic refresh rate detection does not work
well.
- Seemingly the automatic refresh rate detection using X RandR in
software VSync detects refresh rate incorrectly. Need further investigation.
- Fix a few bugs in fading timing.
- Add a workaround for client window detection on Fluxbox, as Fluxbox
(incorrectly?) sets the override-redirect flag upon all frame
windows.
- Software VSync adds dependency on librt (a part of glibc) for
nanosecond-level timing functions, and libXrandr for automatic refresh
rate detection; DRM VSync adds dependency on libdrm to use its drm.h,
but does not link to libdrm; OpenGL VSync adds dependency on libGL.
- Print timing information on DEBUG_REPAINT.
2012-10-08 02:20:01 +00:00
|
|
|
*
|
2012-11-19 01:46:07 +00:00
|
|
|
* @return true for success, false otherwise
|
Feature: #7: VSync
- Add VSync feature. 3 possible VSync methods available: "sw" (software,
not too reliable, but at least you have something to fallback to),
"drm" (using DRM_IOCTL_WAIT_VBLANK, should work only on DRI drivers),
"opengl" (using SGI_swap_control extension OpenGL, might work on more
drivers than the DRM method). "sw" and "opengl" are briefly tested,
"drm" received utterly no test (because I use the nVidia binary blob).
They are enabled with "--vsync sw" / "--vsync drm" / "--vsync opengl".
- Add --refresh-rate to let user specify a refresh rate for software
VSync, in case the automatic refresh rate detection does not work
well.
- Seemingly the automatic refresh rate detection using X RandR in
software VSync detects refresh rate incorrectly. Need further investigation.
- Fix a few bugs in fading timing.
- Add a workaround for client window detection on Fluxbox, as Fluxbox
(incorrectly?) sets the override-redirect flag upon all frame
windows.
- Software VSync adds dependency on librt (a part of glibc) for
nanosecond-level timing functions, and libXrandr for automatic refresh
rate detection; DRM VSync adds dependency on libdrm to use its drm.h,
but does not link to libdrm; OpenGL VSync adds dependency on libGL.
- Print timing information on DEBUG_REPAINT.
2012-10-08 02:20:01 +00:00
|
|
|
*/
|
2019-03-10 12:34:37 +00:00
|
|
|
static bool swopti_init(session_t *ps) {
|
|
|
|
log_warn("--sw-opti is going to be deprecated. If you get real benefits from "
|
|
|
|
"using "
|
|
|
|
"this option, please open an issue to let us know.");
|
|
|
|
// Prepare refresh rate
|
|
|
|
// Check if user provides one
|
|
|
|
ps->refresh_rate = ps->o.refresh_rate;
|
|
|
|
if (ps->refresh_rate)
|
|
|
|
ps->refresh_intv = US_PER_SEC / ps->refresh_rate;
|
|
|
|
|
|
|
|
// Auto-detect refresh rate otherwise
|
|
|
|
if (!ps->refresh_rate && ps->randr_exists) {
|
|
|
|
update_refresh_rate(ps);
|
|
|
|
}
|
Feature: #7: VSync
- Add VSync feature. 3 possible VSync methods available: "sw" (software,
not too reliable, but at least you have something to fallback to),
"drm" (using DRM_IOCTL_WAIT_VBLANK, should work only on DRI drivers),
"opengl" (using SGI_swap_control extension OpenGL, might work on more
drivers than the DRM method). "sw" and "opengl" are briefly tested,
"drm" received utterly no test (because I use the nVidia binary blob).
They are enabled with "--vsync sw" / "--vsync drm" / "--vsync opengl".
- Add --refresh-rate to let user specify a refresh rate for software
VSync, in case the automatic refresh rate detection does not work
well.
- Seemingly the automatic refresh rate detection using X RandR in
software VSync detects refresh rate incorrectly. Need further investigation.
- Fix a few bugs in fading timing.
- Add a workaround for client window detection on Fluxbox, as Fluxbox
(incorrectly?) sets the override-redirect flag upon all frame
windows.
- Software VSync adds dependency on librt (a part of glibc) for
nanosecond-level timing functions, and libXrandr for automatic refresh
rate detection; DRM VSync adds dependency on libdrm to use its drm.h,
but does not link to libdrm; OpenGL VSync adds dependency on libGL.
- Print timing information on DEBUG_REPAINT.
2012-10-08 02:20:01 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
// Turn off vsync_sw if we can't get the refresh rate
|
|
|
|
if (!ps->refresh_rate)
|
|
|
|
return false;
|
Feature: #7: VSync
- Add VSync feature. 3 possible VSync methods available: "sw" (software,
not too reliable, but at least you have something to fallback to),
"drm" (using DRM_IOCTL_WAIT_VBLANK, should work only on DRI drivers),
"opengl" (using SGI_swap_control extension OpenGL, might work on more
drivers than the DRM method). "sw" and "opengl" are briefly tested,
"drm" received utterly no test (because I use the nVidia binary blob).
They are enabled with "--vsync sw" / "--vsync drm" / "--vsync opengl".
- Add --refresh-rate to let user specify a refresh rate for software
VSync, in case the automatic refresh rate detection does not work
well.
- Seemingly the automatic refresh rate detection using X RandR in
software VSync detects refresh rate incorrectly. Need further investigation.
- Fix a few bugs in fading timing.
- Add a workaround for client window detection on Fluxbox, as Fluxbox
(incorrectly?) sets the override-redirect flag upon all frame
windows.
- Software VSync adds dependency on librt (a part of glibc) for
nanosecond-level timing functions, and libXrandr for automatic refresh
rate detection; DRM VSync adds dependency on libdrm to use its drm.h,
but does not link to libdrm; OpenGL VSync adds dependency on libGL.
- Print timing information on DEBUG_REPAINT.
2012-10-08 02:20:01 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
return true;
|
Feature: #7: VSync
- Add VSync feature. 3 possible VSync methods available: "sw" (software,
not too reliable, but at least you have something to fallback to),
"drm" (using DRM_IOCTL_WAIT_VBLANK, should work only on DRI drivers),
"opengl" (using SGI_swap_control extension OpenGL, might work on more
drivers than the DRM method). "sw" and "opengl" are briefly tested,
"drm" received utterly no test (because I use the nVidia binary blob).
They are enabled with "--vsync sw" / "--vsync drm" / "--vsync opengl".
- Add --refresh-rate to let user specify a refresh rate for software
VSync, in case the automatic refresh rate detection does not work
well.
- Seemingly the automatic refresh rate detection using X RandR in
software VSync detects refresh rate incorrectly. Need further investigation.
- Fix a few bugs in fading timing.
- Add a workaround for client window detection on Fluxbox, as Fluxbox
(incorrectly?) sets the override-redirect flag upon all frame
windows.
- Software VSync adds dependency on librt (a part of glibc) for
nanosecond-level timing functions, and libXrandr for automatic refresh
rate detection; DRM VSync adds dependency on libdrm to use its drm.h,
but does not link to libdrm; OpenGL VSync adds dependency on libGL.
- Print timing information on DEBUG_REPAINT.
2012-10-08 02:20:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
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.
2013-01-08 00:50:58 +00:00
|
|
|
* Modify a struct timeval timeout value to render at a fixed pace.
|
2012-10-26 03:12:28 +00:00
|
|
|
*
|
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.
2013-01-08 00:50:58 +00:00
|
|
|
* @param ps current session
|
|
|
|
* @param[in,out] ptv pointer to the timeout
|
Feature: #7: VSync
- Add VSync feature. 3 possible VSync methods available: "sw" (software,
not too reliable, but at least you have something to fallback to),
"drm" (using DRM_IOCTL_WAIT_VBLANK, should work only on DRI drivers),
"opengl" (using SGI_swap_control extension OpenGL, might work on more
drivers than the DRM method). "sw" and "opengl" are briefly tested,
"drm" received utterly no test (because I use the nVidia binary blob).
They are enabled with "--vsync sw" / "--vsync drm" / "--vsync opengl".
- Add --refresh-rate to let user specify a refresh rate for software
VSync, in case the automatic refresh rate detection does not work
well.
- Seemingly the automatic refresh rate detection using X RandR in
software VSync detects refresh rate incorrectly. Need further investigation.
- Fix a few bugs in fading timing.
- Add a workaround for client window detection on Fluxbox, as Fluxbox
(incorrectly?) sets the override-redirect flag upon all frame
windows.
- Software VSync adds dependency on librt (a part of glibc) for
nanosecond-level timing functions, and libXrandr for automatic refresh
rate detection; DRM VSync adds dependency on libdrm to use its drm.h,
but does not link to libdrm; OpenGL VSync adds dependency on libGL.
- Print timing information on DEBUG_REPAINT.
2012-10-08 02:20:01 +00:00
|
|
|
*/
|
2019-03-10 12:34:37 +00:00
|
|
|
static double swopti_handle_timeout(session_t *ps) {
|
|
|
|
if (!ps->refresh_intv)
|
|
|
|
return 0;
|
2018-11-26 16:53:57 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
// Get the microsecond offset of the time when the we reach the timeout
|
|
|
|
// I don't think a 32-bit long could overflow here.
|
|
|
|
long offset = (get_time_timeval().tv_usec - ps->paint_tm_offset) % ps->refresh_intv;
|
|
|
|
// XXX this formula dones't work if refresh rate is not a whole number
|
|
|
|
if (offset < 0)
|
|
|
|
offset += ps->refresh_intv;
|
Feature: #7: VSync
- Add VSync feature. 3 possible VSync methods available: "sw" (software,
not too reliable, but at least you have something to fallback to),
"drm" (using DRM_IOCTL_WAIT_VBLANK, should work only on DRI drivers),
"opengl" (using SGI_swap_control extension OpenGL, might work on more
drivers than the DRM method). "sw" and "opengl" are briefly tested,
"drm" received utterly no test (because I use the nVidia binary blob).
They are enabled with "--vsync sw" / "--vsync drm" / "--vsync opengl".
- Add --refresh-rate to let user specify a refresh rate for software
VSync, in case the automatic refresh rate detection does not work
well.
- Seemingly the automatic refresh rate detection using X RandR in
software VSync detects refresh rate incorrectly. Need further investigation.
- Fix a few bugs in fading timing.
- Add a workaround for client window detection on Fluxbox, as Fluxbox
(incorrectly?) sets the override-redirect flag upon all frame
windows.
- Software VSync adds dependency on librt (a part of glibc) for
nanosecond-level timing functions, and libXrandr for automatic refresh
rate detection; DRM VSync adds dependency on libdrm to use its drm.h,
but does not link to libdrm; OpenGL VSync adds dependency on libGL.
- Print timing information on DEBUG_REPAINT.
2012-10-08 02:20:01 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
// If the target time is sufficiently close to a refresh time, don't add
|
|
|
|
// an offset, to avoid certain blocking conditions.
|
|
|
|
if (offset < SWOPTI_TOLERANCE || offset > ps->refresh_intv - SWOPTI_TOLERANCE)
|
|
|
|
return 0;
|
Feature: #7: VSync
- Add VSync feature. 3 possible VSync methods available: "sw" (software,
not too reliable, but at least you have something to fallback to),
"drm" (using DRM_IOCTL_WAIT_VBLANK, should work only on DRI drivers),
"opengl" (using SGI_swap_control extension OpenGL, might work on more
drivers than the DRM method). "sw" and "opengl" are briefly tested,
"drm" received utterly no test (because I use the nVidia binary blob).
They are enabled with "--vsync sw" / "--vsync drm" / "--vsync opengl".
- Add --refresh-rate to let user specify a refresh rate for software
VSync, in case the automatic refresh rate detection does not work
well.
- Seemingly the automatic refresh rate detection using X RandR in
software VSync detects refresh rate incorrectly. Need further investigation.
- Fix a few bugs in fading timing.
- Add a workaround for client window detection on Fluxbox, as Fluxbox
(incorrectly?) sets the override-redirect flag upon all frame
windows.
- Software VSync adds dependency on librt (a part of glibc) for
nanosecond-level timing functions, and libXrandr for automatic refresh
rate detection; DRM VSync adds dependency on libdrm to use its drm.h,
but does not link to libdrm; OpenGL VSync adds dependency on libGL.
- Print timing information on DEBUG_REPAINT.
2012-10-08 02:20:01 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
// Add an offset so we wait until the next refresh after timeout
|
2019-03-30 09:07:21 +00:00
|
|
|
return (double)(ps->refresh_intv - offset) / 1e6;
|
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.
2013-01-08 00:50:58 +00:00
|
|
|
}
|
|
|
|
|
2012-10-24 02:09:59 +00:00
|
|
|
/**
|
|
|
|
* Initialize X composite overlay window.
|
|
|
|
*/
|
2019-03-10 12:34:37 +00:00
|
|
|
static bool init_overlay(session_t *ps) {
|
|
|
|
xcb_composite_get_overlay_window_reply_t *reply =
|
|
|
|
xcb_composite_get_overlay_window_reply(
|
|
|
|
ps->c, xcb_composite_get_overlay_window(ps->c, ps->root), NULL);
|
|
|
|
if (reply) {
|
|
|
|
ps->overlay = reply->overlay_win;
|
|
|
|
free(reply);
|
|
|
|
} else {
|
|
|
|
ps->overlay = XCB_NONE;
|
|
|
|
}
|
2020-08-30 13:10:26 +00:00
|
|
|
if (ps->overlay != XCB_NONE) {
|
2019-03-10 12:34:37 +00:00
|
|
|
// Set window region of the overlay window, code stolen from
|
|
|
|
// compiz-0.8.8
|
2019-04-27 13:15:40 +00:00
|
|
|
if (!XCB_AWAIT_VOID(xcb_shape_mask, ps->c, XCB_SHAPE_SO_SET,
|
|
|
|
XCB_SHAPE_SK_BOUNDING, ps->overlay, 0, 0, 0)) {
|
2019-03-10 12:34:37 +00:00
|
|
|
log_fatal("Failed to set the bounding shape of overlay, giving "
|
|
|
|
"up.");
|
2019-04-27 13:15:40 +00:00
|
|
|
return false;
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
2019-04-27 13:15:40 +00:00
|
|
|
if (!XCB_AWAIT_VOID(xcb_shape_rectangles, ps->c, XCB_SHAPE_SO_SET,
|
2019-03-10 12:34:37 +00:00
|
|
|
XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED,
|
2019-04-27 13:15:40 +00:00
|
|
|
ps->overlay, 0, 0, 0, NULL)) {
|
2019-03-10 12:34:37 +00:00
|
|
|
log_fatal("Failed to set the input shape of overlay, giving up.");
|
2019-04-27 13:15:40 +00:00
|
|
|
return false;
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Listen to Expose events on the overlay
|
|
|
|
xcb_change_window_attributes(ps->c, ps->overlay, XCB_CW_EVENT_MASK,
|
|
|
|
(const uint32_t[]){XCB_EVENT_MASK_EXPOSURE});
|
|
|
|
|
|
|
|
// Retrieve DamageNotify on root window if we are painting on an
|
|
|
|
// overlay
|
|
|
|
// root_damage = XDamageCreate(ps->dpy, root, XDamageReportNonEmpty);
|
|
|
|
|
2019-09-28 22:43:36 +00:00
|
|
|
// Unmap the overlay, we will map it when needed in redirect_start
|
2019-04-27 13:15:40 +00:00
|
|
|
XCB_AWAIT_VOID(xcb_unmap_window, ps->c, ps->overlay);
|
2019-03-10 12:34:37 +00:00
|
|
|
} else {
|
|
|
|
log_error("Cannot get X Composite overlay window. Falling "
|
|
|
|
"back to painting on root window.");
|
|
|
|
}
|
|
|
|
log_debug("overlay = %#010x", ps->overlay);
|
|
|
|
|
2019-04-27 13:15:40 +00:00
|
|
|
return true;
|
2012-10-24 02:09:59 +00:00
|
|
|
}
|
|
|
|
|
2019-07-07 15:12:17 +00:00
|
|
|
static bool init_debug_window(session_t *ps) {
|
|
|
|
xcb_colormap_t colormap = x_new_id(ps->c);
|
|
|
|
ps->debug_window = x_new_id(ps->c);
|
|
|
|
|
|
|
|
auto err = xcb_request_check(
|
|
|
|
ps->c, xcb_create_colormap_checked(ps->c, XCB_COLORMAP_ALLOC_NONE, colormap,
|
|
|
|
ps->root, ps->vis));
|
|
|
|
if (err) {
|
|
|
|
goto err_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = xcb_request_check(
|
|
|
|
ps->c, xcb_create_window_checked(ps->c, (uint8_t)ps->depth, ps->debug_window,
|
|
|
|
ps->root, 0, 0, to_u16_checked(ps->root_width),
|
|
|
|
to_u16_checked(ps->root_height), 0,
|
|
|
|
XCB_WINDOW_CLASS_INPUT_OUTPUT, ps->vis,
|
|
|
|
XCB_CW_COLORMAP, (uint32_t[]){colormap, 0}));
|
|
|
|
if (err) {
|
|
|
|
goto err_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = xcb_request_check(ps->c, xcb_map_window(ps->c, ps->debug_window));
|
|
|
|
if (err) {
|
|
|
|
goto err_out;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
|
|
|
|
err_out:
|
|
|
|
free(err);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
xcb_window_t session_get_target_window(session_t *ps) {
|
|
|
|
if (ps->o.debug_mode) {
|
|
|
|
return ps->debug_window;
|
|
|
|
}
|
|
|
|
return ps->overlay != XCB_NONE ? ps->overlay : ps->root;
|
|
|
|
}
|
|
|
|
|
2020-03-11 19:15:26 +00:00
|
|
|
uint8_t session_redirection_mode(session_t *ps) {
|
2019-11-10 05:07:03 +00:00
|
|
|
if (ps->o.debug_mode) {
|
|
|
|
// If the backend is not rendering to the screen, we don't need to
|
|
|
|
// take over the screen.
|
|
|
|
assert(ps->o.experimental_backends);
|
|
|
|
return XCB_COMPOSITE_REDIRECT_AUTOMATIC;
|
|
|
|
}
|
|
|
|
if (ps->o.experimental_backends && !backend_list[ps->o.backend]->present) {
|
|
|
|
// if the backend doesn't render anything, we don't need to take over the
|
|
|
|
// screen.
|
2019-08-04 15:46:09 +00:00
|
|
|
return XCB_COMPOSITE_REDIRECT_AUTOMATIC;
|
|
|
|
}
|
|
|
|
return XCB_COMPOSITE_REDIRECT_MANUAL;
|
|
|
|
}
|
|
|
|
|
2012-11-09 13:44:02 +00:00
|
|
|
/**
|
|
|
|
* Redirect all windows.
|
2019-02-25 00:07:12 +00:00
|
|
|
*
|
|
|
|
* @return whether the operation succeeded or not
|
2012-11-09 13:44:02 +00:00
|
|
|
*/
|
2019-09-28 22:43:36 +00:00
|
|
|
static bool redirect_start(session_t *ps) {
|
2019-03-24 04:47:25 +00:00
|
|
|
assert(!ps->redirected);
|
|
|
|
log_debug("Redirecting the screen.");
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-03-24 04:47:25 +00:00
|
|
|
// Map overlay window. Done firstly according to this:
|
|
|
|
// https://bugzilla.gnome.org/show_bug.cgi?id=597014
|
2020-08-30 13:10:26 +00:00
|
|
|
if (ps->overlay != XCB_NONE) {
|
2019-03-24 04:47:25 +00:00
|
|
|
xcb_map_window(ps->c, ps->overlay);
|
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2020-03-27 21:02:38 +00:00
|
|
|
bool success = XCB_AWAIT_VOID(xcb_composite_redirect_subwindows, ps->c, ps->root,
|
|
|
|
session_redirection_mode(ps));
|
|
|
|
if (!success) {
|
|
|
|
log_fatal("Another composite manager is already running "
|
|
|
|
"(and does not handle _NET_WM_CM_Sn correctly)");
|
|
|
|
return false;
|
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-03-24 04:47:25 +00:00
|
|
|
x_sync(ps->c);
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-03-24 04:47:25 +00:00
|
|
|
if (!initialize_backend(ps)) {
|
|
|
|
return false;
|
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-03-24 04:47:25 +00:00
|
|
|
if (ps->o.experimental_backends) {
|
2019-04-20 04:26:20 +00:00
|
|
|
assert(ps->backend_data);
|
2019-03-24 04:47:25 +00:00
|
|
|
ps->ndamage = ps->backend_data->ops->max_buffer_age;
|
|
|
|
} else {
|
|
|
|
ps->ndamage = maximum_buffer_age(ps);
|
|
|
|
}
|
|
|
|
ps->damage_ring = ccalloc(ps->ndamage, region_t);
|
|
|
|
ps->damage = ps->damage_ring + ps->ndamage - 1;
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-03-24 04:47:25 +00:00
|
|
|
for (int i = 0; i < ps->ndamage; i++) {
|
|
|
|
pixman_region32_init(&ps->damage_ring[i]);
|
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-03-24 04:47:25 +00:00
|
|
|
// Must call XSync() here
|
|
|
|
x_sync(ps->c);
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-03-24 04:47:25 +00:00
|
|
|
ps->redirected = true;
|
2019-09-28 23:11:32 +00:00
|
|
|
ps->first_frame = true;
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-04-19 23:21:38 +00:00
|
|
|
// Re-detect driver since we now have a backend
|
|
|
|
ps->drivers = detect_driver(ps->c, ps->backend_data, ps->root);
|
2020-04-22 19:13:18 +00:00
|
|
|
apply_driver_workarounds(ps, ps->drivers);
|
2019-04-19 23:21:38 +00:00
|
|
|
|
2019-03-24 04:47:25 +00:00
|
|
|
root_damaged(ps);
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-03-24 04:47:25 +00:00
|
|
|
// Repaint the whole screen
|
|
|
|
force_repaint(ps);
|
|
|
|
log_debug("Screen redirected.");
|
2019-03-10 12:34:37 +00:00
|
|
|
return true;
|
2012-11-09 13:44:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unredirect all windows.
|
|
|
|
*/
|
2019-09-28 22:43:36 +00:00
|
|
|
static void unredirect(session_t *ps) {
|
2019-03-24 04:47:25 +00:00
|
|
|
assert(ps->redirected);
|
|
|
|
log_debug("Unredirecting the screen.");
|
2019-03-17 16:08:31 +00:00
|
|
|
|
2019-03-24 04:47:25 +00:00
|
|
|
destroy_backend(ps);
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-08-04 15:46:09 +00:00
|
|
|
xcb_composite_unredirect_subwindows(ps->c, ps->root, session_redirection_mode(ps));
|
2019-03-24 04:47:25 +00:00
|
|
|
// Unmap overlay window
|
2020-08-30 13:10:26 +00:00
|
|
|
if (ps->overlay != XCB_NONE) {
|
2019-03-24 04:47:25 +00:00
|
|
|
xcb_unmap_window(ps->c, ps->overlay);
|
2020-08-30 13:10:26 +00:00
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-03-24 04:47:25 +00:00
|
|
|
// Free the damage ring
|
|
|
|
for (int i = 0; i < ps->ndamage; ++i) {
|
|
|
|
pixman_region32_fini(&ps->damage_ring[i]);
|
|
|
|
}
|
|
|
|
ps->ndamage = 0;
|
|
|
|
free(ps->damage_ring);
|
|
|
|
ps->damage_ring = ps->damage = NULL;
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-03-24 04:47:25 +00:00
|
|
|
// Must call XSync() here
|
|
|
|
x_sync(ps->c);
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-03-24 04:47:25 +00:00
|
|
|
ps->redirected = false;
|
|
|
|
log_debug("Screen unredirected.");
|
2012-11-09 13:44:02 +00:00
|
|
|
}
|
|
|
|
|
2018-10-02 19:22:26 +00:00
|
|
|
// Handle queued events before we go to sleep
|
2019-07-25 01:27:02 +00:00
|
|
|
static void handle_queued_x_events(EV_P attr_unused, ev_prepare *w, int revents attr_unused) {
|
2019-03-10 12:34:37 +00:00
|
|
|
session_t *ps = session_ptr(w, event_check);
|
|
|
|
xcb_generic_event_t *ev;
|
|
|
|
while ((ev = xcb_poll_for_queued_event(ps->c))) {
|
|
|
|
ev_handle(ps, ev);
|
|
|
|
free(ev);
|
|
|
|
};
|
|
|
|
// Flush because if we go into sleep when there is still
|
|
|
|
// requests in the outgoing buffer, they will not be sent
|
|
|
|
// for an indefinite amount of time.
|
|
|
|
// Use XFlush here too, we might still use some Xlib functions
|
|
|
|
// because OpenGL.
|
|
|
|
XFlush(ps->dpy);
|
|
|
|
xcb_flush(ps->c);
|
|
|
|
int err = xcb_connection_has_error(ps->c);
|
|
|
|
if (err) {
|
|
|
|
log_fatal("X11 server connection broke (error %d)", err);
|
|
|
|
exit(1);
|
|
|
|
}
|
2018-10-02 19:22:26 +00:00
|
|
|
}
|
|
|
|
|
2019-04-19 19:53:52 +00:00
|
|
|
static void handle_new_windows(session_t *ps) {
|
|
|
|
list_foreach_safe(struct win, w, &ps->window_stack, stack_neighbour) {
|
|
|
|
if (w->is_new) {
|
2019-04-19 20:10:38 +00:00
|
|
|
auto new_w = fill_win(ps, w);
|
|
|
|
if (!new_w->managed) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto mw = (struct managed_win *)new_w;
|
|
|
|
if (mw->a.map_state == XCB_MAP_STATE_VIEWABLE) {
|
2020-11-28 22:48:01 +00:00
|
|
|
win_set_flags(mw, WIN_FLAGS_MAPPED);
|
2019-04-19 21:52:32 +00:00
|
|
|
|
|
|
|
// This window might be damaged before we called fill_win
|
2019-09-16 21:14:34 +00:00
|
|
|
// and created the damage handle. And there is no way for
|
2019-04-19 21:52:32 +00:00
|
|
|
// us to find out. So just blindly mark it damaged
|
|
|
|
mw->ever_damaged = true;
|
2019-04-19 20:10:38 +00:00
|
|
|
}
|
2019-04-19 19:53:52 +00:00
|
|
|
}
|
|
|
|
}
|
2019-05-22 21:38:22 +00:00
|
|
|
}
|
|
|
|
|
2019-09-20 00:59:25 +00:00
|
|
|
static void refresh_windows(session_t *ps) {
|
2019-05-22 21:38:22 +00:00
|
|
|
win_stack_foreach_managed(w, &ps->window_stack) {
|
2020-08-27 16:44:58 +00:00
|
|
|
win_process_update_flags(ps, w);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void refresh_images(session_t *ps) {
|
|
|
|
win_stack_foreach_managed(w, &ps->window_stack) {
|
|
|
|
win_process_image_flags(ps, w);
|
2019-05-22 21:38:22 +00:00
|
|
|
}
|
2019-04-19 19:53:52 +00:00
|
|
|
}
|
|
|
|
|
2013-09-04 14:00:51 +00:00
|
|
|
/**
|
|
|
|
* Unredirection timeout callback.
|
|
|
|
*/
|
2019-07-25 01:27:02 +00:00
|
|
|
static void tmout_unredir_callback(EV_P attr_unused, ev_timer *w, int revents attr_unused) {
|
2019-03-10 12:34:37 +00:00
|
|
|
session_t *ps = session_ptr(w, unredir_timer);
|
|
|
|
ps->tmout_unredir_hit = true;
|
|
|
|
queue_redraw(ps);
|
|
|
|
}
|
|
|
|
|
2019-07-25 01:27:02 +00:00
|
|
|
static void fade_timer_callback(EV_P attr_unused, ev_timer *w, int revents attr_unused) {
|
2019-03-10 12:34:37 +00:00
|
|
|
session_t *ps = session_ptr(w, fade_timer);
|
|
|
|
queue_redraw(ps);
|
|
|
|
}
|
|
|
|
|
2019-09-19 16:20:18 +00:00
|
|
|
static void handle_pending_updates(EV_P_ struct session *ps) {
|
2019-05-22 21:38:22 +00:00
|
|
|
if (ps->pending_updates) {
|
|
|
|
log_debug("Delayed handling of events, entering critical section");
|
2019-04-25 03:14:32 +00:00
|
|
|
auto e = xcb_request_check(ps->c, xcb_grab_server_checked(ps->c));
|
|
|
|
if (e) {
|
2020-03-28 00:15:45 +00:00
|
|
|
log_fatal_x_error(e, "failed to grab x server");
|
2019-10-23 18:27:30 +00:00
|
|
|
return quit(ps);
|
2019-04-25 03:14:32 +00:00
|
|
|
}
|
2019-04-19 19:53:52 +00:00
|
|
|
|
2019-08-07 23:46:56 +00:00
|
|
|
ps->server_grabbed = true;
|
|
|
|
|
2019-04-25 03:14:32 +00:00
|
|
|
// Catching up with X server
|
2019-07-25 01:27:02 +00:00
|
|
|
handle_queued_x_events(EV_A_ & ps->event_check, 0);
|
2019-04-19 19:53:52 +00:00
|
|
|
|
2019-04-25 03:14:32 +00:00
|
|
|
// Call fill_win on new windows
|
|
|
|
handle_new_windows(ps);
|
2019-04-19 19:53:52 +00:00
|
|
|
|
2020-04-06 19:52:32 +00:00
|
|
|
// Handle screen changes
|
|
|
|
// This HAS TO be called before refresh_windows, as handle_root_flags
|
|
|
|
// could call configure_root, which will release images and mark them
|
|
|
|
// stale.
|
|
|
|
handle_root_flags(ps);
|
|
|
|
|
2020-08-27 16:44:58 +00:00
|
|
|
// Process window flags (window mapping)
|
2019-09-21 04:11:28 +00:00
|
|
|
refresh_windows(ps);
|
|
|
|
|
2019-09-20 08:10:37 +00:00
|
|
|
{
|
2019-10-23 18:27:30 +00:00
|
|
|
auto r = xcb_get_input_focus_reply(
|
|
|
|
ps->c, xcb_get_input_focus(ps->c), NULL);
|
2019-09-20 08:10:37 +00:00
|
|
|
if (!ps->active_win || (r && r->focus != ps->active_win->base.id)) {
|
|
|
|
recheck_focus(ps);
|
|
|
|
}
|
|
|
|
free(r);
|
2019-05-24 23:06:41 +00:00
|
|
|
}
|
|
|
|
|
2020-08-27 16:44:58 +00:00
|
|
|
// Process window flags (stale images)
|
|
|
|
refresh_images(ps);
|
|
|
|
|
2019-04-25 03:14:32 +00:00
|
|
|
e = xcb_request_check(ps->c, xcb_ungrab_server_checked(ps->c));
|
|
|
|
if (e) {
|
2020-03-28 00:15:45 +00:00
|
|
|
log_fatal_x_error(e, "failed to ungrab x server");
|
2019-10-23 18:27:30 +00:00
|
|
|
return quit(ps);
|
2019-04-25 03:14:32 +00:00
|
|
|
}
|
2019-05-22 21:38:22 +00:00
|
|
|
|
2019-09-19 16:20:18 +00:00
|
|
|
ps->server_grabbed = false;
|
2019-05-22 21:38:22 +00:00
|
|
|
ps->pending_updates = false;
|
2019-09-19 16:20:18 +00:00
|
|
|
log_debug("Exited critical section");
|
2019-04-19 19:53:52 +00:00
|
|
|
}
|
2019-09-19 16:20:18 +00:00
|
|
|
}
|
|
|
|
|
2020-08-30 16:44:21 +00:00
|
|
|
static void draw_callback_impl(EV_P_ session_t *ps, int revents attr_unused) {
|
2019-09-19 16:20:18 +00:00
|
|
|
handle_pending_updates(EV_A_ ps);
|
2019-04-19 19:53:52 +00:00
|
|
|
|
2019-09-28 23:11:32 +00:00
|
|
|
if (ps->first_frame) {
|
|
|
|
// If we are still rendering the first frame, if some of the windows are
|
|
|
|
// unmapped/destroyed during the above handle_pending_updates() call, they
|
|
|
|
// won't have pixmap before we rendered it, causing us to crash.
|
|
|
|
// But we will only render them if they are in fading. So we just skip
|
|
|
|
// fading for all windows here.
|
|
|
|
//
|
|
|
|
// Using foreach_safe here since skipping fading can cause window to be
|
|
|
|
// freed if it's destroyed.
|
|
|
|
win_stack_foreach_managed_safe(w, &ps->window_stack) {
|
|
|
|
auto _ attr_unused = win_skip_fading(ps, w);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
if (ps->o.benchmark) {
|
|
|
|
if (ps->o.benchmark_wid) {
|
2019-04-17 22:14:45 +00:00
|
|
|
auto w = find_managed_win(ps, ps->o.benchmark_wid);
|
|
|
|
if (!w) {
|
2019-03-10 12:34:37 +00:00
|
|
|
log_fatal("Couldn't find specified benchmark window.");
|
|
|
|
exit(1);
|
|
|
|
}
|
2019-04-17 22:14:45 +00:00
|
|
|
add_damage_from_win(ps, w);
|
2019-03-10 12:34:37 +00:00
|
|
|
} else {
|
|
|
|
force_repaint(ps);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-30 14:25:58 +00:00
|
|
|
/* TODO(yshui) Have a stripped down version of paint_preprocess that is used when
|
|
|
|
* screen is not redirected. its sole purpose should be to decide whether the
|
|
|
|
* screen should be redirected. */
|
2019-03-10 12:34:37 +00:00
|
|
|
bool fade_running = false;
|
2019-03-24 04:47:25 +00:00
|
|
|
bool was_redirected = ps->redirected;
|
2019-04-17 22:14:45 +00:00
|
|
|
auto bottom = paint_preprocess(ps, &fade_running);
|
2019-03-10 12:34:37 +00:00
|
|
|
ps->tmout_unredir_hit = false;
|
|
|
|
|
2019-03-24 04:47:25 +00:00
|
|
|
if (!was_redirected && ps->redirected) {
|
|
|
|
// paint_preprocess redirected the screen, which might change the state of
|
2019-09-20 00:59:25 +00:00
|
|
|
// some of the windows (e.g. the window image might become stale).
|
|
|
|
// so we rerun _draw_callback to make sure the rendering decision we make
|
|
|
|
// is up-to-date, and all the new flags got handled.
|
|
|
|
//
|
2020-08-30 14:25:58 +00:00
|
|
|
// TODO(yshui) This is not ideal, we should try to avoid setting window
|
|
|
|
// flags in paint_preprocess.
|
2019-09-20 00:59:25 +00:00
|
|
|
log_debug("Re-run _draw_callback");
|
2020-08-30 16:44:21 +00:00
|
|
|
return draw_callback_impl(EV_A_ ps, revents);
|
2019-03-24 04:47:25 +00:00
|
|
|
}
|
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
// Start/stop fade timer depends on whether window are fading
|
2019-03-24 04:47:25 +00:00
|
|
|
if (!fade_running && ev_is_active(&ps->fade_timer)) {
|
2019-07-25 01:27:02 +00:00
|
|
|
ev_timer_stop(EV_A_ & ps->fade_timer);
|
2019-03-24 04:47:25 +00:00
|
|
|
} else if (fade_running && !ev_is_active(&ps->fade_timer)) {
|
2019-03-10 12:34:37 +00:00
|
|
|
ev_timer_set(&ps->fade_timer, fade_timeout(ps), 0);
|
2019-07-25 01:27:02 +00:00
|
|
|
ev_timer_start(EV_A_ & ps->fade_timer);
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the screen is unredirected, free all_damage to stop painting
|
|
|
|
if (ps->redirected && ps->o.stoppaint_force != ON) {
|
|
|
|
static int paint = 0;
|
2020-03-21 14:59:50 +00:00
|
|
|
|
|
|
|
log_trace("Render start, frame %d", paint);
|
2019-03-10 12:34:37 +00:00
|
|
|
if (ps->o.experimental_backends) {
|
2019-04-17 22:14:45 +00:00
|
|
|
paint_all_new(ps, bottom, false);
|
2019-03-10 12:34:37 +00:00
|
|
|
} else {
|
2019-04-17 22:14:45 +00:00
|
|
|
paint_all(ps, bottom, false);
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
2020-03-21 14:59:50 +00:00
|
|
|
log_trace("Render end");
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-09-28 23:11:32 +00:00
|
|
|
ps->first_frame = false;
|
2019-03-10 12:34:37 +00:00
|
|
|
paint++;
|
2020-10-23 15:41:20 +00:00
|
|
|
if (ps->o.benchmark && paint >= ps->o.benchmark) {
|
2019-03-10 12:34:37 +00:00
|
|
|
exit(0);
|
2020-10-23 15:41:20 +00:00
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
|
2020-10-23 15:41:20 +00:00
|
|
|
if (!fade_running) {
|
2019-03-10 12:34:37 +00:00
|
|
|
ps->fade_time = 0L;
|
2020-10-23 15:41:20 +00:00
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2020-08-30 14:25:58 +00:00
|
|
|
// TODO(yshui) Investigate how big the X critical section needs to be. There are
|
|
|
|
// suggestions that rendering should be in the critical section as well.
|
2019-03-17 15:17:48 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
ps->redraw_needed = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void draw_callback(EV_P_ ev_idle *w, int revents) {
|
|
|
|
// This function is not used if we are using --swopti
|
|
|
|
session_t *ps = session_ptr(w, draw_idle);
|
|
|
|
|
2020-08-30 16:44:21 +00:00
|
|
|
draw_callback_impl(EV_A_ ps, revents);
|
2019-03-10 12:34:37 +00:00
|
|
|
|
|
|
|
// Don't do painting non-stop unless we are in benchmark mode
|
2019-07-25 01:27:02 +00:00
|
|
|
if (!ps->o.benchmark) {
|
|
|
|
ev_idle_stop(EV_A_ & ps->draw_idle);
|
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void delayed_draw_timer_callback(EV_P_ ev_timer *w, int revents) {
|
|
|
|
session_t *ps = session_ptr(w, delayed_draw_timer);
|
2020-08-30 16:44:21 +00:00
|
|
|
draw_callback_impl(EV_A_ ps, revents);
|
2019-03-10 12:34:37 +00:00
|
|
|
|
|
|
|
// We might have stopped the ev_idle in delayed_draw_callback,
|
|
|
|
// so we restart it if we are in benchmark mode
|
|
|
|
if (ps->o.benchmark)
|
|
|
|
ev_idle_start(EV_A_ & ps->draw_idle);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void delayed_draw_callback(EV_P_ ev_idle *w, int revents) {
|
|
|
|
// This function is only used if we are using --swopti
|
|
|
|
session_t *ps = session_ptr(w, draw_idle);
|
|
|
|
assert(ps->redraw_needed);
|
|
|
|
assert(!ev_is_active(&ps->delayed_draw_timer));
|
|
|
|
|
|
|
|
double delay = swopti_handle_timeout(ps);
|
|
|
|
if (delay < 1e-6) {
|
|
|
|
if (!ps->o.benchmark) {
|
2019-07-25 01:27:02 +00:00
|
|
|
ev_idle_stop(EV_A_ & ps->draw_idle);
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
2020-08-30 16:44:21 +00:00
|
|
|
return draw_callback_impl(EV_A_ ps, revents);
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// This is a little bit hacky. When we get to this point in code, we need
|
|
|
|
// to update the screen , but we will only be updating after a delay, So
|
|
|
|
// we want to stop the ev_idle, so this callback doesn't get call repeatedly
|
|
|
|
// during the delay, we also want queue_redraw to not restart the ev_idle.
|
|
|
|
// So we stop ev_idle and leave ps->redraw_needed to be true. (effectively,
|
|
|
|
// ps->redraw_needed means if redraw is needed or if draw is in progress).
|
|
|
|
//
|
|
|
|
// We do this anyway even if we are in benchmark mode. That means we will
|
|
|
|
// have to restart draw_idle after the draw actually happened when we are in
|
|
|
|
// benchmark mode.
|
2019-07-25 01:27:02 +00:00
|
|
|
ev_idle_stop(EV_A_ & ps->draw_idle);
|
2019-03-10 12:34:37 +00:00
|
|
|
|
|
|
|
ev_timer_set(&ps->delayed_draw_timer, delay, 0);
|
2019-07-25 01:27:02 +00:00
|
|
|
ev_timer_start(EV_A_ & ps->delayed_draw_timer);
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
|
2019-07-25 01:27:02 +00:00
|
|
|
static void x_event_callback(EV_P attr_unused, ev_io *w, int revents attr_unused) {
|
2019-03-10 12:34:37 +00:00
|
|
|
session_t *ps = (session_t *)w;
|
|
|
|
xcb_generic_event_t *ev = xcb_poll_for_event(ps->c);
|
|
|
|
if (ev) {
|
|
|
|
ev_handle(ps, ev);
|
|
|
|
free(ev);
|
|
|
|
}
|
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.
2013-01-08 00:50:58 +00:00
|
|
|
}
|
|
|
|
|
2018-11-26 23:56:55 +00:00
|
|
|
/**
|
|
|
|
* Turn on the program reset flag.
|
|
|
|
*
|
2019-10-23 18:27:30 +00:00
|
|
|
* This will result in the compostior resetting itself after next paint.
|
2018-11-26 23:56:55 +00:00
|
|
|
*/
|
2019-07-25 01:27:02 +00:00
|
|
|
static void reset_enable(EV_P_ ev_signal *w attr_unused, int revents attr_unused) {
|
2019-10-23 18:27:30 +00:00
|
|
|
log_info("picom is resetting...");
|
2019-07-25 01:27:02 +00:00
|
|
|
ev_break(EV_A_ EVBREAK_ALL);
|
2019-02-11 23:13:39 +00:00
|
|
|
}
|
|
|
|
|
2019-07-25 01:27:02 +00:00
|
|
|
static void exit_enable(EV_P attr_unused, ev_signal *w, int revents attr_unused) {
|
2019-03-10 12:34:37 +00:00
|
|
|
session_t *ps = session_ptr(w, int_signal);
|
2019-10-23 18:27:30 +00:00
|
|
|
log_info("picom is quitting...");
|
|
|
|
quit(ps);
|
2018-11-26 23:56:55 +00:00
|
|
|
}
|
|
|
|
|
2019-11-10 18:58:01 +00:00
|
|
|
static void config_file_change_cb(void *_ps) {
|
|
|
|
auto ps = (struct session *)_ps;
|
|
|
|
reset_enable(ps->loop, NULL, 0);
|
|
|
|
}
|
|
|
|
|
2012-11-19 01:46:07 +00:00
|
|
|
/**
|
|
|
|
* Initialize a session.
|
|
|
|
*
|
|
|
|
* @param argc number of commandline arguments
|
|
|
|
* @param argv commandline arguments
|
2019-02-08 01:27:46 +00:00
|
|
|
* @param dpy the X Display
|
|
|
|
* @param config_file the path to the config file
|
|
|
|
* @param all_xerros whether we should report all X errors
|
|
|
|
* @param fork whether we will fork after initialization
|
2012-11-19 01:46:07 +00:00
|
|
|
*/
|
2019-03-10 12:34:37 +00:00
|
|
|
static session_t *session_init(int argc, char **argv, Display *dpy,
|
|
|
|
const char *config_file, bool all_xerrors, bool fork) {
|
|
|
|
static const session_t s_def = {
|
|
|
|
.backend_data = NULL,
|
|
|
|
.dpy = NULL,
|
|
|
|
.scr = 0,
|
|
|
|
.c = NULL,
|
|
|
|
.vis = 0,
|
|
|
|
.depth = 0,
|
|
|
|
.root = XCB_NONE,
|
|
|
|
.root_height = 0,
|
|
|
|
.root_width = 0,
|
|
|
|
// .root_damage = XCB_NONE,
|
|
|
|
.overlay = XCB_NONE,
|
|
|
|
.root_tile_fill = false,
|
|
|
|
.root_tile_paint = PAINT_INIT,
|
|
|
|
.tgt_picture = XCB_NONE,
|
|
|
|
.tgt_buffer = PAINT_INIT,
|
|
|
|
.reg_win = XCB_NONE,
|
2018-12-21 16:25:28 +00:00
|
|
|
#ifdef CONFIG_OPENGL
|
2019-03-10 12:34:37 +00:00
|
|
|
.glx_prog_win = GLX_PROG_MAIN_INIT,
|
2018-12-21 16:25:28 +00:00
|
|
|
#endif
|
2019-03-10 12:34:37 +00:00
|
|
|
.redirected = false,
|
|
|
|
.alpha_picts = NULL,
|
|
|
|
.fade_time = 0L,
|
|
|
|
.ignore_head = NULL,
|
|
|
|
.ignore_tail = NULL,
|
|
|
|
.quit = false,
|
|
|
|
|
|
|
|
.expose_rects = NULL,
|
|
|
|
.size_expose = 0,
|
|
|
|
.n_expose = 0,
|
|
|
|
|
2019-04-03 07:36:02 +00:00
|
|
|
.windows = NULL,
|
2019-03-10 12:34:37 +00:00
|
|
|
.active_win = NULL,
|
|
|
|
.active_leader = XCB_NONE,
|
|
|
|
|
|
|
|
.black_picture = XCB_NONE,
|
|
|
|
.cshadow_picture = XCB_NONE,
|
|
|
|
.white_picture = XCB_NONE,
|
|
|
|
.gaussian_map = NULL,
|
|
|
|
|
|
|
|
.refresh_rate = 0,
|
|
|
|
.refresh_intv = 0UL,
|
|
|
|
.paint_tm_offset = 0L,
|
2012-11-19 01:46:07 +00:00
|
|
|
|
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.
2013-01-08 00:50:58 +00:00
|
|
|
#ifdef CONFIG_VSYNC_DRM
|
2019-03-10 12:34:37 +00:00
|
|
|
.drm_fd = -1,
|
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.
2013-01-08 00:50:58 +00:00
|
|
|
#endif
|
2012-11-19 01:46:07 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
.xfixes_event = 0,
|
|
|
|
.xfixes_error = 0,
|
|
|
|
.damage_event = 0,
|
|
|
|
.damage_error = 0,
|
|
|
|
.render_event = 0,
|
|
|
|
.render_error = 0,
|
|
|
|
.composite_event = 0,
|
|
|
|
.composite_error = 0,
|
|
|
|
.composite_opcode = 0,
|
|
|
|
.shape_exists = false,
|
|
|
|
.shape_event = 0,
|
|
|
|
.shape_error = 0,
|
|
|
|
.randr_exists = 0,
|
|
|
|
.randr_event = 0,
|
|
|
|
.randr_error = 0,
|
|
|
|
.glx_exists = false,
|
|
|
|
.glx_event = 0,
|
|
|
|
.glx_error = 0,
|
|
|
|
.xrfilter_convolution_exists = false,
|
|
|
|
|
|
|
|
.atoms_wintypes = {0},
|
|
|
|
.track_atom_lst = NULL,
|
Feature #80: D-Bus support
- Add D-Bus support. Currently 7 methods are available: "reset" (same as
SIGUSR1), "list_win" (list the windows compton manages), "win_get"
(get a property of the window), "win_set" (set a property of the
window), "find_win" (find window based on client window / focus),
"opts_get" (get the value of a compton option), and "opts_set" (set
the value of a compton option), together with 4 signals: "win_added",
"win_destroyed", "win_mapped", "win_unmapped".
- D-Bus support depends on libdbus.
- As there are many items and my time is tight, no much tests are done.
Bugs to be expected.
- Create a new header file `common.h` that contains shared content.
- Fix some bugs in timeout handling.
- Update file headers in all source files.
- Re-enable --unredir-if-possible on multi-screen set-ups, as the user
could turn if off manually anyway.
- Check if the window is mapped in `repair_win()`.
- Add ps->track_atom_lst and its handlers, to prepare for the new
condition format.
- Known issue 1: "win_get", "win_set", "opts_get", "opts_set" support a
very limited number of targets only. New ones will be added gradually.
- Known issue 2: Accidental drop of D-Bus connection is not handled.
- Known issue 3: Introspection does not reveal all available methods,
because some methods have unpredictable prototypes. Still hesitating
about what to do...
- Known issue 4: Error handling is not finished yet. Compton does not
always reply with the correct error message (but it does print out the
correct error message, usually).
2013-01-19 12:20:27 +00:00
|
|
|
|
|
|
|
#ifdef CONFIG_DBUS
|
2019-03-10 12:34:37 +00:00
|
|
|
.dbus_data = NULL,
|
Feature #80: D-Bus support
- Add D-Bus support. Currently 7 methods are available: "reset" (same as
SIGUSR1), "list_win" (list the windows compton manages), "win_get"
(get a property of the window), "win_set" (set a property of the
window), "find_win" (find window based on client window / focus),
"opts_get" (get the value of a compton option), and "opts_set" (set
the value of a compton option), together with 4 signals: "win_added",
"win_destroyed", "win_mapped", "win_unmapped".
- D-Bus support depends on libdbus.
- As there are many items and my time is tight, no much tests are done.
Bugs to be expected.
- Create a new header file `common.h` that contains shared content.
- Fix some bugs in timeout handling.
- Update file headers in all source files.
- Re-enable --unredir-if-possible on multi-screen set-ups, as the user
could turn if off manually anyway.
- Check if the window is mapped in `repair_win()`.
- Add ps->track_atom_lst and its handlers, to prepare for the new
condition format.
- Known issue 1: "win_get", "win_set", "opts_get", "opts_set" support a
very limited number of targets only. New ones will be added gradually.
- Known issue 2: Accidental drop of D-Bus connection is not handled.
- Known issue 3: Introspection does not reveal all available methods,
because some methods have unpredictable prototypes. Still hesitating
about what to do...
- Known issue 4: Error handling is not finished yet. Compton does not
always reply with the correct error message (but it does print out the
correct error message, usually).
2013-01-19 12:20:27 +00:00
|
|
|
#endif
|
2019-03-10 12:34:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
auto stderr_logger = stderr_logger_new();
|
|
|
|
if (stderr_logger) {
|
|
|
|
// stderr logger might fail to create if we are already
|
|
|
|
// daemonized.
|
|
|
|
log_add_target_tls(stderr_logger);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allocate a session and copy default values into it
|
|
|
|
session_t *ps = cmalloc(session_t);
|
|
|
|
*ps = s_def;
|
2019-04-04 08:11:27 +00:00
|
|
|
list_init_head(&ps->window_stack);
|
2019-03-10 12:34:37 +00:00
|
|
|
ps->loop = EV_DEFAULT;
|
|
|
|
pixman_region32_init(&ps->screen_reg);
|
|
|
|
|
|
|
|
ps->ignore_tail = &ps->ignore_head;
|
|
|
|
|
|
|
|
ps->o.show_all_xerrors = all_xerrors;
|
|
|
|
|
|
|
|
// Use the same Display across reset, primarily for resource leak checking
|
|
|
|
ps->dpy = dpy;
|
|
|
|
ps->c = XGetXCBConnection(ps->dpy);
|
|
|
|
|
|
|
|
const xcb_query_extension_reply_t *ext_info;
|
|
|
|
|
2019-07-30 05:40:18 +00:00
|
|
|
ps->previous_xerror_handler = XSetErrorHandler(xerror);
|
2019-03-10 12:34:37 +00:00
|
|
|
|
|
|
|
ps->scr = DefaultScreen(ps->dpy);
|
|
|
|
|
2019-03-30 09:07:21 +00:00
|
|
|
auto screen = x_screen_of_display(ps->c, ps->scr);
|
|
|
|
ps->vis = screen->root_visual;
|
|
|
|
ps->depth = screen->root_depth;
|
|
|
|
ps->root = screen->root;
|
|
|
|
ps->root_width = screen->width_in_pixels;
|
|
|
|
ps->root_height = screen->height_in_pixels;
|
2019-03-10 12:34:37 +00:00
|
|
|
|
|
|
|
// Start listening to events on root earlier to catch all possible
|
|
|
|
// root geometry changes
|
|
|
|
auto e = xcb_request_check(
|
|
|
|
ps->c, xcb_change_window_attributes_checked(
|
|
|
|
ps->c, ps->root, XCB_CW_EVENT_MASK,
|
|
|
|
(const uint32_t[]){XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
|
|
|
|
XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY |
|
|
|
|
XCB_EVENT_MASK_PROPERTY_CHANGE}));
|
|
|
|
if (e) {
|
2020-03-28 00:15:45 +00:00
|
|
|
log_error_x_error(e, "Failed to setup root window event mask");
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
xcb_prefetch_extension_data(ps->c, &xcb_render_id);
|
|
|
|
xcb_prefetch_extension_data(ps->c, &xcb_composite_id);
|
|
|
|
xcb_prefetch_extension_data(ps->c, &xcb_damage_id);
|
|
|
|
xcb_prefetch_extension_data(ps->c, &xcb_shape_id);
|
|
|
|
xcb_prefetch_extension_data(ps->c, &xcb_xfixes_id);
|
|
|
|
xcb_prefetch_extension_data(ps->c, &xcb_randr_id);
|
|
|
|
xcb_prefetch_extension_data(ps->c, &xcb_xinerama_id);
|
|
|
|
xcb_prefetch_extension_data(ps->c, &xcb_present_id);
|
|
|
|
xcb_prefetch_extension_data(ps->c, &xcb_sync_id);
|
2020-03-31 05:07:09 +00:00
|
|
|
xcb_prefetch_extension_data(ps->c, &xcb_glx_id);
|
2019-03-10 12:34:37 +00:00
|
|
|
|
|
|
|
ext_info = xcb_get_extension_data(ps->c, &xcb_render_id);
|
|
|
|
if (!ext_info || !ext_info->present) {
|
|
|
|
log_fatal("No render extension");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
ps->render_event = ext_info->first_event;
|
|
|
|
ps->render_error = ext_info->first_error;
|
|
|
|
|
|
|
|
ext_info = xcb_get_extension_data(ps->c, &xcb_composite_id);
|
|
|
|
if (!ext_info || !ext_info->present) {
|
|
|
|
log_fatal("No composite extension");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
ps->composite_opcode = ext_info->major_opcode;
|
|
|
|
ps->composite_event = ext_info->first_event;
|
|
|
|
ps->composite_error = ext_info->first_error;
|
|
|
|
|
|
|
|
{
|
|
|
|
xcb_composite_query_version_reply_t *reply = xcb_composite_query_version_reply(
|
|
|
|
ps->c,
|
|
|
|
xcb_composite_query_version(ps->c, XCB_COMPOSITE_MAJOR_VERSION,
|
|
|
|
XCB_COMPOSITE_MINOR_VERSION),
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (!reply || (reply->major_version == 0 && reply->minor_version < 2)) {
|
|
|
|
log_fatal("Your X server doesn't have Composite >= 0.2 support, "
|
2019-10-23 18:27:30 +00:00
|
|
|
"we cannot proceed.");
|
2019-03-10 12:34:37 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
free(reply);
|
|
|
|
}
|
|
|
|
|
|
|
|
ext_info = xcb_get_extension_data(ps->c, &xcb_damage_id);
|
|
|
|
if (!ext_info || !ext_info->present) {
|
|
|
|
log_fatal("No damage extension");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
ps->damage_event = ext_info->first_event;
|
|
|
|
ps->damage_error = ext_info->first_error;
|
|
|
|
xcb_discard_reply(ps->c, xcb_damage_query_version(ps->c, XCB_DAMAGE_MAJOR_VERSION,
|
|
|
|
XCB_DAMAGE_MINOR_VERSION)
|
|
|
|
.sequence);
|
|
|
|
|
|
|
|
ext_info = xcb_get_extension_data(ps->c, &xcb_xfixes_id);
|
|
|
|
if (!ext_info || !ext_info->present) {
|
|
|
|
log_fatal("No XFixes extension");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
ps->xfixes_event = ext_info->first_event;
|
|
|
|
ps->xfixes_error = ext_info->first_error;
|
|
|
|
xcb_discard_reply(ps->c, xcb_xfixes_query_version(ps->c, XCB_XFIXES_MAJOR_VERSION,
|
|
|
|
XCB_XFIXES_MINOR_VERSION)
|
|
|
|
.sequence);
|
|
|
|
|
2020-08-30 08:11:45 +00:00
|
|
|
ps->damaged_region = x_new_id(ps->c);
|
|
|
|
if (!XCB_AWAIT_VOID(xcb_xfixes_create_region, ps->c, ps->damaged_region, 0, NULL)) {
|
|
|
|
log_fatal("Failed to create a XFixes region");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2020-03-31 05:07:09 +00:00
|
|
|
ext_info = xcb_get_extension_data(ps->c, &xcb_glx_id);
|
|
|
|
if (ext_info && ext_info->present) {
|
|
|
|
ps->glx_exists = true;
|
|
|
|
ps->glx_error = ext_info->first_error;
|
|
|
|
ps->glx_event = ext_info->first_event;
|
|
|
|
}
|
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
// Parse configuration file
|
|
|
|
win_option_mask_t winopt_mask[NUM_WINTYPES] = {{0}};
|
|
|
|
bool shadow_enabled = false, fading_enable = false, hasneg = false;
|
|
|
|
char *config_file_to_free = NULL;
|
|
|
|
config_file = config_file_to_free = parse_config(
|
|
|
|
&ps->o, config_file, &shadow_enabled, &fading_enable, &hasneg, winopt_mask);
|
|
|
|
|
|
|
|
if (IS_ERR(config_file_to_free)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse all of the rest command line options
|
2019-11-10 04:59:55 +00:00
|
|
|
if (!get_cfg(&ps->o, argc, argv, shadow_enabled, fading_enable, hasneg, winopt_mask)) {
|
|
|
|
log_fatal("Failed to get configuration, usually mean you have specified "
|
|
|
|
"invalid options.");
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
|
|
|
|
if (ps->o.logpath) {
|
|
|
|
auto l = file_logger_new(ps->o.logpath);
|
|
|
|
if (l) {
|
|
|
|
log_info("Switching to log file: %s", ps->o.logpath);
|
|
|
|
if (stderr_logger) {
|
|
|
|
log_remove_target_tls(stderr_logger);
|
|
|
|
stderr_logger = NULL;
|
|
|
|
}
|
|
|
|
log_add_target_tls(l);
|
|
|
|
stderr_logger = NULL;
|
|
|
|
} else {
|
|
|
|
log_error("Failed to setup log file %s, I will keep using stderr",
|
|
|
|
ps->o.logpath);
|
|
|
|
}
|
|
|
|
}
|
2019-07-07 18:55:34 +00:00
|
|
|
|
2019-10-23 18:27:30 +00:00
|
|
|
if (strstr(argv[0], "compton")) {
|
|
|
|
log_warn("This compositor has been renamed to \"picom\", the \"compton\" "
|
|
|
|
"binary will not be installed in the future.");
|
|
|
|
}
|
|
|
|
|
2019-05-05 23:34:08 +00:00
|
|
|
ps->atoms = init_atoms(ps->c);
|
|
|
|
ps->atoms_wintypes[WINTYPE_UNKNOWN] = 0;
|
|
|
|
#define SET_WM_TYPE_ATOM(x) \
|
|
|
|
ps->atoms_wintypes[WINTYPE_##x] = ps->atoms->a_NET_WM_WINDOW_TYPE_##x
|
|
|
|
SET_WM_TYPE_ATOM(DESKTOP);
|
|
|
|
SET_WM_TYPE_ATOM(DOCK);
|
|
|
|
SET_WM_TYPE_ATOM(TOOLBAR);
|
|
|
|
SET_WM_TYPE_ATOM(MENU);
|
|
|
|
SET_WM_TYPE_ATOM(UTILITY);
|
|
|
|
SET_WM_TYPE_ATOM(SPLASH);
|
|
|
|
SET_WM_TYPE_ATOM(DIALOG);
|
|
|
|
SET_WM_TYPE_ATOM(NORMAL);
|
|
|
|
SET_WM_TYPE_ATOM(DROPDOWN_MENU);
|
|
|
|
SET_WM_TYPE_ATOM(POPUP_MENU);
|
|
|
|
SET_WM_TYPE_ATOM(TOOLTIP);
|
|
|
|
SET_WM_TYPE_ATOM(NOTIFICATION);
|
|
|
|
SET_WM_TYPE_ATOM(COMBO);
|
|
|
|
SET_WM_TYPE_ATOM(DND);
|
|
|
|
#undef SET_WM_TYPE_ATOM
|
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
// Get needed atoms for c2 condition lists
|
|
|
|
if (!(c2_list_postprocess(ps, ps->o.unredir_if_possible_blacklist) &&
|
|
|
|
c2_list_postprocess(ps, ps->o.paint_blacklist) &&
|
|
|
|
c2_list_postprocess(ps, ps->o.shadow_blacklist) &&
|
|
|
|
c2_list_postprocess(ps, ps->o.fade_blacklist) &&
|
|
|
|
c2_list_postprocess(ps, ps->o.blur_background_blacklist) &&
|
|
|
|
c2_list_postprocess(ps, ps->o.invert_color_list) &&
|
|
|
|
c2_list_postprocess(ps, ps->o.opacity_rules) &&
|
2020-09-05 14:46:31 +00:00
|
|
|
c2_list_postprocess(ps, ps->o.rounded_corners_blacklist) &&
|
2019-03-10 12:34:37 +00:00
|
|
|
c2_list_postprocess(ps, ps->o.focus_blacklist))) {
|
|
|
|
log_error("Post-processing of conditionals failed, some of your rules "
|
|
|
|
"might not work");
|
|
|
|
}
|
|
|
|
|
2019-04-18 23:11:54 +00:00
|
|
|
ps->gaussian_map = gaussian_kernel_autodetect_deviation(ps->o.shadow_radius);
|
2019-03-10 12:34:37 +00:00
|
|
|
sum_kernel_preprocess(ps->gaussian_map);
|
|
|
|
|
|
|
|
rebuild_shadow_exclude_reg(ps);
|
|
|
|
|
|
|
|
// Query X Shape
|
|
|
|
ext_info = xcb_get_extension_data(ps->c, &xcb_shape_id);
|
|
|
|
if (ext_info && ext_info->present) {
|
|
|
|
ps->shape_event = ext_info->first_event;
|
|
|
|
ps->shape_error = ext_info->first_error;
|
|
|
|
ps->shape_exists = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ext_info = xcb_get_extension_data(ps->c, &xcb_randr_id);
|
|
|
|
if (ext_info && ext_info->present) {
|
|
|
|
ps->randr_exists = true;
|
|
|
|
ps->randr_event = ext_info->first_event;
|
|
|
|
ps->randr_error = ext_info->first_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ext_info = xcb_get_extension_data(ps->c, &xcb_present_id);
|
|
|
|
if (ext_info && ext_info->present) {
|
|
|
|
auto r = xcb_present_query_version_reply(
|
|
|
|
ps->c,
|
|
|
|
xcb_present_query_version(ps->c, XCB_PRESENT_MAJOR_VERSION,
|
|
|
|
XCB_PRESENT_MINOR_VERSION),
|
|
|
|
NULL);
|
|
|
|
if (r) {
|
|
|
|
ps->present_exists = true;
|
|
|
|
free(r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Query X Sync
|
|
|
|
ext_info = xcb_get_extension_data(ps->c, &xcb_sync_id);
|
|
|
|
if (ext_info && ext_info->present) {
|
|
|
|
ps->xsync_error = ext_info->first_error;
|
|
|
|
ps->xsync_event = ext_info->first_event;
|
|
|
|
// Need X Sync 3.1 for fences
|
|
|
|
auto r = xcb_sync_initialize_reply(
|
|
|
|
ps->c,
|
|
|
|
xcb_sync_initialize(ps->c, XCB_SYNC_MAJOR_VERSION, XCB_SYNC_MINOR_VERSION),
|
|
|
|
NULL);
|
|
|
|
if (r && (r->major_version > 3 ||
|
|
|
|
(r->major_version == 3 && r->minor_version >= 1))) {
|
|
|
|
ps->xsync_exists = true;
|
|
|
|
free(r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ps->sync_fence = XCB_NONE;
|
2020-04-22 19:17:31 +00:00
|
|
|
if (ps->xsync_exists) {
|
2019-04-08 04:49:39 +00:00
|
|
|
ps->sync_fence = x_new_id(ps->c);
|
2019-03-10 12:34:37 +00:00
|
|
|
e = xcb_request_check(
|
|
|
|
ps->c, xcb_sync_create_fence(ps->c, ps->root, ps->sync_fence, 0));
|
|
|
|
if (e) {
|
2020-04-22 19:17:31 +00:00
|
|
|
if (ps->o.xrender_sync_fence) {
|
|
|
|
log_error_x_error(e, "Failed to create a XSync fence. "
|
|
|
|
"xrender-sync-fence will be "
|
|
|
|
"disabled");
|
|
|
|
ps->o.xrender_sync_fence = false;
|
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
ps->sync_fence = XCB_NONE;
|
|
|
|
free(e);
|
|
|
|
}
|
2020-04-22 19:17:31 +00:00
|
|
|
} else if (ps->o.xrender_sync_fence) {
|
|
|
|
log_error("XSync extension not found. No XSync fence sync is "
|
|
|
|
"possible. (xrender-sync-fence can't be enabled)");
|
|
|
|
ps->o.xrender_sync_fence = false;
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Query X RandR
|
|
|
|
if ((ps->o.sw_opti && !ps->o.refresh_rate) || ps->o.xinerama_shadow_crop) {
|
|
|
|
if (!ps->randr_exists) {
|
|
|
|
log_fatal("No XRandR extension. sw-opti, refresh-rate or "
|
|
|
|
"xinerama-shadow-crop "
|
|
|
|
"cannot be enabled.");
|
2019-04-27 13:15:40 +00:00
|
|
|
goto err;
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Query X Xinerama extension
|
|
|
|
if (ps->o.xinerama_shadow_crop) {
|
|
|
|
ext_info = xcb_get_extension_data(ps->c, &xcb_xinerama_id);
|
|
|
|
ps->xinerama_exists = ext_info && ext_info->present;
|
|
|
|
}
|
|
|
|
|
|
|
|
rebuild_screen_reg(ps);
|
|
|
|
|
2020-03-11 19:15:26 +00:00
|
|
|
bool compositor_running = false;
|
|
|
|
if (session_redirection_mode(ps) == XCB_COMPOSITE_REDIRECT_MANUAL) {
|
|
|
|
// We are running in the manual redirection mode, meaning we are running
|
|
|
|
// as a proper compositor. So we need to register us as a compositor, etc.
|
2019-05-06 00:20:38 +00:00
|
|
|
|
2020-03-11 19:15:26 +00:00
|
|
|
// We are also here when --diagnostics is set. We want to be here because
|
|
|
|
// that gives us more diagnostic information.
|
|
|
|
|
|
|
|
// Create registration window
|
|
|
|
int ret = register_cm(ps);
|
|
|
|
if (ret == -1) {
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
compositor_running = ret == 1;
|
|
|
|
if (compositor_running) {
|
|
|
|
// Don't take the overlay when there is another compositor
|
|
|
|
// running, so we don't disrupt it.
|
|
|
|
|
|
|
|
// If we are printing diagnostic, we will continue a bit further
|
|
|
|
// to get more diagnostic information, otherwise we will exit.
|
|
|
|
if (!ps->o.print_diagnostics) {
|
|
|
|
log_fatal("Another composite manager is already running");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
} else {
|
2019-08-04 15:46:09 +00:00
|
|
|
if (!init_overlay(ps)) {
|
|
|
|
goto err;
|
|
|
|
}
|
2020-03-11 19:15:26 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// We are here if we don't really function as a compositor, so we are not
|
|
|
|
// taking over the screen, and we don't need to register as a compositor
|
|
|
|
|
|
|
|
// If we are in debug mode, we need to create a window for rendering if
|
|
|
|
// the backend supports presenting.
|
|
|
|
|
|
|
|
// The old backends doesn't have a automatic redirection mode
|
|
|
|
log_info("The compositor is started in automatic redirection mode.");
|
|
|
|
assert(ps->o.experimental_backends);
|
|
|
|
|
|
|
|
if (backend_list[ps->o.backend]->present) {
|
|
|
|
// If the backend has `present`, we couldn't be in automatic
|
|
|
|
// redirection mode unless we are in debug mode.
|
|
|
|
assert(ps->o.debug_mode);
|
2019-08-04 15:46:09 +00:00
|
|
|
if (!init_debug_window(ps)) {
|
|
|
|
goto err;
|
|
|
|
}
|
2019-07-07 15:12:17 +00:00
|
|
|
}
|
2019-04-27 13:15:40 +00:00
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-04-19 23:21:38 +00:00
|
|
|
ps->drivers = detect_driver(ps->c, ps->backend_data, ps->root);
|
2020-04-22 19:13:18 +00:00
|
|
|
apply_driver_workarounds(ps, ps->drivers);
|
2019-04-19 23:21:38 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
// Initialize filters, must be preceded by OpenGL context creation
|
|
|
|
if (!ps->o.experimental_backends && !init_render(ps)) {
|
|
|
|
log_fatal("Failed to initialize the backend");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ps->o.print_diagnostics) {
|
2020-03-11 19:15:26 +00:00
|
|
|
print_diagnostics(ps, config_file, compositor_running);
|
2019-03-10 12:34:37 +00:00
|
|
|
free(config_file_to_free);
|
|
|
|
exit(0);
|
|
|
|
}
|
2019-11-10 18:58:01 +00:00
|
|
|
|
|
|
|
ps->file_watch_handle = file_watch_init(ps->loop);
|
2019-11-10 21:55:38 +00:00
|
|
|
if (ps->file_watch_handle && config_file) {
|
2019-11-10 18:58:01 +00:00
|
|
|
file_watch_add(ps->file_watch_handle, config_file, config_file_change_cb, ps);
|
|
|
|
}
|
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
free(config_file_to_free);
|
|
|
|
|
|
|
|
if (bkend_use_glx(ps) && !ps->o.experimental_backends) {
|
2019-03-27 14:51:20 +00:00
|
|
|
auto gl_logger = gl_string_marker_logger_new();
|
|
|
|
if (gl_logger) {
|
2019-03-10 12:34:37 +00:00
|
|
|
log_info("Enabling gl string marker");
|
2019-03-27 14:51:20 +00:00
|
|
|
log_add_target_tls(gl_logger);
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ps->o.experimental_backends) {
|
|
|
|
if (ps->o.monitor_repaint && !backend_list[ps->o.backend]->fill) {
|
|
|
|
log_warn("--monitor-repaint is not supported by the backend, "
|
|
|
|
"disabling");
|
|
|
|
ps->o.monitor_repaint = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize software optimization
|
|
|
|
if (ps->o.sw_opti)
|
|
|
|
ps->o.sw_opti = swopti_init(ps);
|
|
|
|
|
|
|
|
// Monitor screen changes if vsync_sw is enabled and we are using
|
|
|
|
// an auto-detected refresh rate, or when Xinerama features are enabled
|
|
|
|
if (ps->randr_exists &&
|
|
|
|
((ps->o.sw_opti && !ps->o.refresh_rate) || ps->o.xinerama_shadow_crop))
|
|
|
|
xcb_randr_select_input(ps->c, ps->root, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE);
|
|
|
|
|
|
|
|
cxinerama_upd_scrs(ps);
|
|
|
|
|
|
|
|
{
|
|
|
|
xcb_render_create_picture_value_list_t pa = {
|
|
|
|
.subwindowmode = IncludeInferiors,
|
|
|
|
};
|
|
|
|
|
|
|
|
ps->root_picture = x_create_picture_with_visual_and_pixmap(
|
|
|
|
ps->c, ps->vis, ps->root, XCB_RENDER_CP_SUBWINDOW_MODE, &pa);
|
|
|
|
if (ps->overlay != XCB_NONE) {
|
|
|
|
ps->tgt_picture = x_create_picture_with_visual_and_pixmap(
|
|
|
|
ps->c, ps->vis, ps->overlay, XCB_RENDER_CP_SUBWINDOW_MODE, &pa);
|
|
|
|
} else
|
|
|
|
ps->tgt_picture = ps->root_picture;
|
|
|
|
}
|
|
|
|
|
|
|
|
ev_io_init(&ps->xiow, x_event_callback, ConnectionNumber(ps->dpy), EV_READ);
|
|
|
|
ev_io_start(ps->loop, &ps->xiow);
|
|
|
|
ev_init(&ps->unredir_timer, tmout_unredir_callback);
|
|
|
|
if (ps->o.sw_opti)
|
|
|
|
ev_idle_init(&ps->draw_idle, delayed_draw_callback);
|
|
|
|
else
|
|
|
|
ev_idle_init(&ps->draw_idle, draw_callback);
|
|
|
|
|
|
|
|
ev_init(&ps->fade_timer, fade_timer_callback);
|
|
|
|
ev_init(&ps->delayed_draw_timer, delayed_draw_timer_callback);
|
|
|
|
|
|
|
|
// Set up SIGUSR1 signal handler to reset program
|
|
|
|
ev_signal_init(&ps->usr1_signal, reset_enable, SIGUSR1);
|
|
|
|
ev_signal_init(&ps->int_signal, exit_enable, SIGINT);
|
|
|
|
ev_signal_start(ps->loop, &ps->usr1_signal);
|
|
|
|
ev_signal_start(ps->loop, &ps->int_signal);
|
|
|
|
|
|
|
|
// xcb can read multiple events from the socket when a request with reply is
|
|
|
|
// made.
|
|
|
|
//
|
|
|
|
// Use an ev_prepare to make sure we cannot accidentally forget to handle them
|
|
|
|
// before we go to sleep.
|
|
|
|
//
|
|
|
|
// If we don't drain the queue before goes to sleep (i.e. blocking on socket
|
|
|
|
// input), we will be sleeping with events available in queue. Which might
|
|
|
|
// cause us to block indefinitely because arrival of new events could be
|
|
|
|
// dependent on processing of existing events (e.g. if we don't process damage
|
|
|
|
// event and do damage subtract, new damage event won't be generated).
|
|
|
|
//
|
|
|
|
// So we make use of a ev_prepare handle, which is called right before libev
|
|
|
|
// goes into sleep, to handle all the queued X events.
|
|
|
|
ev_prepare_init(&ps->event_check, handle_queued_x_events);
|
|
|
|
// Make sure nothing can cause xcb to read from the X socket after events are
|
|
|
|
// handled and before we going to sleep.
|
|
|
|
ev_set_priority(&ps->event_check, EV_MINPRI);
|
|
|
|
ev_prepare_start(ps->loop, &ps->event_check);
|
|
|
|
|
|
|
|
// Initialize DBus. We need to do this early, because add_win might call dbus
|
|
|
|
// functions
|
|
|
|
if (ps->o.dbus) {
|
2018-12-20 22:31:34 +00:00
|
|
|
#ifdef CONFIG_DBUS
|
2019-03-10 12:34:37 +00:00
|
|
|
cdbus_init(ps, DisplayString(ps->dpy));
|
|
|
|
if (!ps->dbus_data) {
|
|
|
|
ps->o.dbus = false;
|
|
|
|
}
|
2018-12-20 22:31:34 +00:00
|
|
|
#else
|
2019-03-10 12:34:37 +00:00
|
|
|
log_fatal("DBus support not compiled in!");
|
|
|
|
exit(1);
|
2018-12-20 22:31:34 +00:00
|
|
|
#endif
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
|
2019-08-09 22:34:37 +00:00
|
|
|
e = xcb_request_check(ps->c, xcb_grab_server_checked(ps->c));
|
|
|
|
if (e) {
|
2020-03-28 00:18:07 +00:00
|
|
|
log_fatal_x_error(e, "Failed to grab X server");
|
|
|
|
free(e);
|
2019-08-09 22:34:37 +00:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2019-08-07 23:46:56 +00:00
|
|
|
ps->server_grabbed = true;
|
|
|
|
|
2019-08-09 22:34:37 +00:00
|
|
|
// We are going to pull latest information from X server now, events sent by X
|
|
|
|
// earlier is irrelavant at this point.
|
|
|
|
// A better solution is probably grabbing the server from the very start. But I
|
|
|
|
// think there still could be race condition that mandates discarding the events.
|
|
|
|
x_discard_events(ps->c);
|
|
|
|
|
2019-08-10 00:23:11 +00:00
|
|
|
xcb_query_tree_reply_t *query_tree_reply =
|
|
|
|
xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, ps->root), NULL);
|
|
|
|
|
|
|
|
e = xcb_request_check(ps->c, xcb_ungrab_server(ps->c));
|
|
|
|
if (e) {
|
2020-03-28 00:18:07 +00:00
|
|
|
log_fatal_x_error(e, "Failed to ungrab server");
|
2019-08-10 00:23:11 +00:00
|
|
|
free(e);
|
2020-03-28 00:18:07 +00:00
|
|
|
goto err;
|
2019-08-10 00:23:11 +00:00
|
|
|
}
|
|
|
|
|
2019-08-07 23:46:56 +00:00
|
|
|
ps->server_grabbed = false;
|
|
|
|
|
2019-08-10 00:23:11 +00:00
|
|
|
if (query_tree_reply) {
|
2019-03-10 12:34:37 +00:00
|
|
|
xcb_window_t *children;
|
|
|
|
int nchildren;
|
|
|
|
|
2019-08-10 00:23:11 +00:00
|
|
|
children = xcb_query_tree_children(query_tree_reply);
|
|
|
|
nchildren = xcb_query_tree_children_length(query_tree_reply);
|
2019-03-10 12:34:37 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < nchildren; i++) {
|
2019-04-27 13:25:10 +00:00
|
|
|
add_win_above(ps, children[i], i ? children[i - 1] : XCB_NONE);
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
2019-08-10 00:23:11 +00:00
|
|
|
free(query_tree_reply);
|
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-09-19 16:23:48 +00:00
|
|
|
log_debug("Initial stack:");
|
2019-08-10 00:23:11 +00:00
|
|
|
list_foreach(struct win, w, &ps->window_stack, stack_neighbour) {
|
2019-09-19 16:23:48 +00:00
|
|
|
log_debug("%#010x", w->id);
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
|
2019-05-24 23:06:41 +00:00
|
|
|
ps->pending_updates = true;
|
2019-03-10 12:34:37 +00:00
|
|
|
|
|
|
|
write_pid(ps);
|
|
|
|
|
|
|
|
if (fork && stderr_logger) {
|
|
|
|
// Remove the stderr logger if we will fork
|
|
|
|
log_remove_target_tls(stderr_logger);
|
|
|
|
}
|
|
|
|
return ps;
|
2019-04-19 21:35:52 +00:00
|
|
|
err:
|
|
|
|
free(ps);
|
|
|
|
return NULL;
|
2012-11-19 01:46:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Destroy a session.
|
|
|
|
*
|
|
|
|
* Does not close the X connection or free the <code>session_t</code>
|
|
|
|
* structure, though.
|
|
|
|
*
|
|
|
|
* @param ps session to destroy
|
|
|
|
*/
|
2019-03-10 12:34:37 +00:00
|
|
|
static void session_destroy(session_t *ps) {
|
2019-03-24 04:47:25 +00:00
|
|
|
if (ps->redirected) {
|
2019-09-28 22:43:36 +00:00
|
|
|
unredirect(ps);
|
2019-03-24 04:47:25 +00:00
|
|
|
}
|
2012-11-19 01:46:07 +00:00
|
|
|
|
2020-11-03 19:03:07 +00:00
|
|
|
#ifdef CONFIG_OPENGL
|
2020-11-02 18:43:12 +00:00
|
|
|
free(ps->argb_fbconfig);
|
2020-11-03 19:03:07 +00:00
|
|
|
ps->argb_fbconfig = NULL;
|
|
|
|
#endif
|
2020-11-02 18:43:12 +00:00
|
|
|
|
2019-11-10 18:58:01 +00:00
|
|
|
file_watch_destroy(ps->loop, ps->file_watch_handle);
|
|
|
|
ps->file_watch_handle = NULL;
|
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
// Stop listening to events on root window
|
|
|
|
xcb_change_window_attributes(ps->c, ps->root, XCB_CW_EVENT_MASK,
|
|
|
|
(const uint32_t[]){0});
|
2011-11-04 06:33:23 +00:00
|
|
|
|
Feature #80: D-Bus support
- Add D-Bus support. Currently 7 methods are available: "reset" (same as
SIGUSR1), "list_win" (list the windows compton manages), "win_get"
(get a property of the window), "win_set" (set a property of the
window), "find_win" (find window based on client window / focus),
"opts_get" (get the value of a compton option), and "opts_set" (set
the value of a compton option), together with 4 signals: "win_added",
"win_destroyed", "win_mapped", "win_unmapped".
- D-Bus support depends on libdbus.
- As there are many items and my time is tight, no much tests are done.
Bugs to be expected.
- Create a new header file `common.h` that contains shared content.
- Fix some bugs in timeout handling.
- Update file headers in all source files.
- Re-enable --unredir-if-possible on multi-screen set-ups, as the user
could turn if off manually anyway.
- Check if the window is mapped in `repair_win()`.
- Add ps->track_atom_lst and its handlers, to prepare for the new
condition format.
- Known issue 1: "win_get", "win_set", "opts_get", "opts_set" support a
very limited number of targets only. New ones will be added gradually.
- Known issue 2: Accidental drop of D-Bus connection is not handled.
- Known issue 3: Introspection does not reveal all available methods,
because some methods have unpredictable prototypes. Still hesitating
about what to do...
- Known issue 4: Error handling is not finished yet. Compton does not
always reply with the correct error message (but it does print out the
correct error message, usually).
2013-01-19 12:20:27 +00:00
|
|
|
#ifdef CONFIG_DBUS
|
2019-03-10 12:34:37 +00:00
|
|
|
// Kill DBus connection
|
|
|
|
if (ps->o.dbus) {
|
|
|
|
assert(ps->dbus_data);
|
|
|
|
cdbus_destroy(ps);
|
|
|
|
}
|
Feature #80: D-Bus support
- Add D-Bus support. Currently 7 methods are available: "reset" (same as
SIGUSR1), "list_win" (list the windows compton manages), "win_get"
(get a property of the window), "win_set" (set a property of the
window), "find_win" (find window based on client window / focus),
"opts_get" (get the value of a compton option), and "opts_set" (set
the value of a compton option), together with 4 signals: "win_added",
"win_destroyed", "win_mapped", "win_unmapped".
- D-Bus support depends on libdbus.
- As there are many items and my time is tight, no much tests are done.
Bugs to be expected.
- Create a new header file `common.h` that contains shared content.
- Fix some bugs in timeout handling.
- Update file headers in all source files.
- Re-enable --unredir-if-possible on multi-screen set-ups, as the user
could turn if off manually anyway.
- Check if the window is mapped in `repair_win()`.
- Add ps->track_atom_lst and its handlers, to prepare for the new
condition format.
- Known issue 1: "win_get", "win_set", "opts_get", "opts_set" support a
very limited number of targets only. New ones will be added gradually.
- Known issue 2: Accidental drop of D-Bus connection is not handled.
- Known issue 3: Introspection does not reveal all available methods,
because some methods have unpredictable prototypes. Still hesitating
about what to do...
- Known issue 4: Error handling is not finished yet. Compton does not
always reply with the correct error message (but it does print out the
correct error message, usually).
2013-01-19 12:20:27 +00:00
|
|
|
#endif
|
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
// Free window linked list
|
|
|
|
|
2019-04-17 22:14:45 +00:00
|
|
|
list_foreach_safe(struct win, w, &ps->window_stack, stack_neighbour) {
|
|
|
|
if (!w->destroyed) {
|
2019-04-03 07:36:02 +00:00
|
|
|
win_ev_stop(ps, w);
|
|
|
|
HASH_DEL(ps->windows, w);
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
2019-04-03 07:36:02 +00:00
|
|
|
|
2019-04-17 22:14:45 +00:00
|
|
|
if (w->managed) {
|
|
|
|
auto mw = (struct managed_win *)w;
|
|
|
|
free_win_res(ps, mw);
|
|
|
|
}
|
2019-04-03 07:36:02 +00:00
|
|
|
free(w);
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
2019-04-04 08:11:27 +00:00
|
|
|
list_init_head(&ps->window_stack);
|
2019-03-10 12:34:37 +00:00
|
|
|
|
|
|
|
// Free blacklists
|
|
|
|
free_wincondlst(&ps->o.shadow_blacklist);
|
|
|
|
free_wincondlst(&ps->o.fade_blacklist);
|
|
|
|
free_wincondlst(&ps->o.focus_blacklist);
|
|
|
|
free_wincondlst(&ps->o.invert_color_list);
|
|
|
|
free_wincondlst(&ps->o.blur_background_blacklist);
|
|
|
|
free_wincondlst(&ps->o.opacity_rules);
|
|
|
|
free_wincondlst(&ps->o.paint_blacklist);
|
|
|
|
free_wincondlst(&ps->o.unredir_if_possible_blacklist);
|
2020-09-05 14:46:31 +00:00
|
|
|
free_wincondlst(&ps->o.rounded_corners_blacklist);
|
2019-03-10 12:34:37 +00:00
|
|
|
|
|
|
|
// Free tracked atom list
|
|
|
|
{
|
|
|
|
latom_t *next = NULL;
|
|
|
|
for (latom_t *this = ps->track_atom_lst; this; this = next) {
|
|
|
|
next = this->next;
|
|
|
|
free(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
ps->track_atom_lst = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Free ignore linked list
|
|
|
|
{
|
|
|
|
ignore_t *next = NULL;
|
|
|
|
for (ignore_t *ign = ps->ignore_head; ign; ign = next) {
|
|
|
|
next = ign->next;
|
|
|
|
|
|
|
|
free(ign);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset head and tail
|
|
|
|
ps->ignore_head = NULL;
|
|
|
|
ps->ignore_tail = &ps->ignore_head;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Free tgt_{buffer,picture} and root_picture
|
|
|
|
if (ps->tgt_buffer.pict == ps->tgt_picture)
|
|
|
|
ps->tgt_buffer.pict = XCB_NONE;
|
|
|
|
|
|
|
|
if (ps->tgt_picture == ps->root_picture)
|
|
|
|
ps->tgt_picture = XCB_NONE;
|
|
|
|
else
|
|
|
|
free_picture(ps->c, &ps->tgt_picture);
|
|
|
|
|
|
|
|
free_picture(ps->c, &ps->root_picture);
|
|
|
|
free_paint(ps, &ps->tgt_buffer);
|
|
|
|
|
|
|
|
pixman_region32_fini(&ps->screen_reg);
|
|
|
|
free(ps->expose_rects);
|
|
|
|
|
|
|
|
free(ps->o.write_pid_path);
|
|
|
|
free(ps->o.logpath);
|
2019-06-07 20:53:23 +00:00
|
|
|
for (int i = 0; i < ps->o.blur_kernel_count; ++i) {
|
2019-03-10 12:34:37 +00:00
|
|
|
free(ps->o.blur_kerns[i]);
|
|
|
|
}
|
2019-06-06 06:37:48 +00:00
|
|
|
free(ps->o.blur_kerns);
|
2019-03-10 12:34:37 +00:00
|
|
|
free(ps->o.glx_fshader_win_str);
|
|
|
|
free_xinerama_info(ps);
|
2012-11-19 01:46:07 +00:00
|
|
|
|
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.
2013-01-08 00:50:58 +00:00
|
|
|
#ifdef CONFIG_VSYNC_DRM
|
2019-03-10 12:34:37 +00:00
|
|
|
// Close file opened for DRM VSync
|
|
|
|
if (ps->drm_fd >= 0) {
|
|
|
|
close(ps->drm_fd);
|
|
|
|
ps->drm_fd = -1;
|
|
|
|
}
|
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.
2013-01-08 00:50:58 +00:00
|
|
|
#endif
|
2012-11-19 01:46:07 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
// Release overlay window
|
|
|
|
if (ps->overlay) {
|
|
|
|
xcb_composite_release_overlay_window(ps->c, ps->overlay);
|
|
|
|
ps->overlay = XCB_NONE;
|
|
|
|
}
|
|
|
|
|
2020-08-30 13:10:26 +00:00
|
|
|
if (ps->sync_fence != XCB_NONE) {
|
2019-03-10 12:34:37 +00:00
|
|
|
xcb_sync_destroy_fence(ps->c, ps->sync_fence);
|
|
|
|
ps->sync_fence = XCB_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Free reg_win
|
2020-08-30 13:10:26 +00:00
|
|
|
if (ps->reg_win != XCB_NONE) {
|
2019-03-10 12:34:37 +00:00
|
|
|
xcb_destroy_window(ps->c, ps->reg_win);
|
|
|
|
ps->reg_win = XCB_NONE;
|
|
|
|
}
|
|
|
|
|
2020-08-30 13:10:26 +00:00
|
|
|
if (ps->debug_window != XCB_NONE) {
|
2019-07-25 01:36:35 +00:00
|
|
|
xcb_destroy_window(ps->c, ps->debug_window);
|
|
|
|
ps->debug_window = XCB_NONE;
|
|
|
|
}
|
|
|
|
|
2020-08-30 08:11:45 +00:00
|
|
|
if (ps->damaged_region != XCB_NONE) {
|
|
|
|
xcb_xfixes_destroy_region(ps->c, ps->damaged_region);
|
|
|
|
ps->damaged_region = XCB_NONE;
|
|
|
|
}
|
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
if (ps->o.experimental_backends) {
|
2019-09-28 22:43:36 +00:00
|
|
|
// backend is deinitialized in unredirect()
|
2019-03-10 12:34:37 +00:00
|
|
|
assert(ps->backend_data == NULL);
|
|
|
|
} else {
|
|
|
|
deinit_render(ps);
|
|
|
|
}
|
|
|
|
|
2019-06-06 06:40:32 +00:00
|
|
|
#if CONFIG_OPENGL
|
2019-06-06 06:33:07 +00:00
|
|
|
if (glx_has_context(ps)) {
|
|
|
|
// GLX context created, but not for rendering
|
|
|
|
glx_destroy(ps);
|
|
|
|
}
|
2019-06-06 06:40:32 +00:00
|
|
|
#endif
|
2019-06-06 06:33:07 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
// Flush all events
|
|
|
|
x_sync(ps->c);
|
|
|
|
ev_io_stop(ps->loop, &ps->xiow);
|
|
|
|
free_conv(ps->gaussian_map);
|
2019-05-05 23:34:08 +00:00
|
|
|
destroy_atoms(ps->atoms);
|
2012-11-19 01:46:07 +00:00
|
|
|
|
2014-08-03 11:40:40 +00:00
|
|
|
#ifdef DEBUG_XRC
|
2019-03-10 12:34:37 +00:00
|
|
|
// Report about resource leakage
|
|
|
|
xrc_report_xid();
|
2014-08-03 11:40:40 +00:00
|
|
|
#endif
|
|
|
|
|
2019-07-30 05:40:18 +00:00
|
|
|
XSetErrorHandler(ps->previous_xerror_handler);
|
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
// Stop libev event handlers
|
|
|
|
ev_timer_stop(ps->loop, &ps->unredir_timer);
|
|
|
|
ev_timer_stop(ps->loop, &ps->fade_timer);
|
|
|
|
ev_idle_stop(ps->loop, &ps->draw_idle);
|
|
|
|
ev_prepare_stop(ps->loop, &ps->event_check);
|
|
|
|
ev_signal_stop(ps->loop, &ps->usr1_signal);
|
|
|
|
ev_signal_stop(ps->loop, &ps->int_signal);
|
2012-11-19 01:46:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Do the actual work.
|
|
|
|
*
|
|
|
|
* @param ps current session
|
|
|
|
*/
|
2019-03-10 12:34:37 +00:00
|
|
|
static void session_run(session_t *ps) {
|
|
|
|
if (ps->o.sw_opti)
|
|
|
|
ps->paint_tm_offset = get_time_timeval().tv_usec;
|
|
|
|
|
|
|
|
// In benchmark mode, we want draw_idle handler to always be active
|
|
|
|
if (ps->o.benchmark) {
|
|
|
|
ev_idle_start(ps->loop, &ps->draw_idle);
|
|
|
|
} else {
|
|
|
|
// Let's draw our first frame!
|
|
|
|
queue_redraw(ps);
|
|
|
|
}
|
|
|
|
ev_run(ps->loop, 0);
|
2003-11-09 07:08:23 +00:00
|
|
|
}
|
2012-11-19 01:46:07 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The function that everybody knows.
|
|
|
|
*/
|
2019-03-10 12:34:37 +00:00
|
|
|
int main(int argc, char **argv) {
|
|
|
|
// Set locale so window names with special characters are interpreted
|
|
|
|
// correctly
|
|
|
|
setlocale(LC_ALL, "");
|
2019-11-10 19:12:16 +00:00
|
|
|
|
|
|
|
// Initialize logging system for early logging
|
2019-03-21 22:37:35 +00:00
|
|
|
log_init_tls();
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-11-10 19:12:16 +00:00
|
|
|
{
|
|
|
|
auto stderr_logger = stderr_logger_new();
|
|
|
|
if (stderr_logger) {
|
|
|
|
log_add_target_tls(stderr_logger);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
int exit_code;
|
|
|
|
char *config_file = NULL;
|
|
|
|
bool all_xerrors = false, need_fork = false;
|
|
|
|
if (get_early_config(argc, argv, &config_file, &all_xerrors, &need_fork, &exit_code)) {
|
|
|
|
return exit_code;
|
|
|
|
}
|
|
|
|
|
|
|
|
int pfds[2];
|
|
|
|
if (need_fork) {
|
|
|
|
if (pipe2(pfds, O_CLOEXEC)) {
|
|
|
|
perror("pipe2");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
auto pid = fork();
|
|
|
|
if (pid < 0) {
|
|
|
|
perror("fork");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (pid > 0) {
|
|
|
|
// We are the parent
|
|
|
|
close(pfds[1]);
|
|
|
|
// We wait for the child to tell us it has finished initialization
|
|
|
|
// by sending us something via the pipe.
|
|
|
|
int tmp;
|
|
|
|
if (read(pfds[0], &tmp, sizeof tmp) <= 0) {
|
|
|
|
// Failed to read, the child has most likely died
|
|
|
|
// We can probably waitpid() here.
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
// We are done
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// We are the child
|
|
|
|
close(pfds[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Main loop
|
|
|
|
bool quit = false;
|
2019-11-10 19:10:32 +00:00
|
|
|
int ret_code = 0;
|
2020-09-16 18:25:10 +00:00
|
|
|
char *pid_file = NULL;
|
2019-03-10 12:34:37 +00:00
|
|
|
|
|
|
|
do {
|
2019-07-25 20:15:47 +00:00
|
|
|
Display *dpy = XOpenDisplay(NULL);
|
|
|
|
if (!dpy) {
|
2019-11-10 19:12:16 +00:00
|
|
|
log_fatal("Can't open display.");
|
2019-11-10 19:10:32 +00:00
|
|
|
ret_code = 1;
|
|
|
|
break;
|
2019-07-25 20:15:47 +00:00
|
|
|
}
|
|
|
|
XSetEventQueueOwner(dpy, XCBOwnsEventQueue);
|
2019-11-10 19:10:32 +00:00
|
|
|
|
|
|
|
// Reinit logging system so we don't get leftovers from previous sessions
|
|
|
|
// or early logging.
|
|
|
|
log_deinit_tls();
|
|
|
|
log_init_tls();
|
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
ps_g = session_init(argc, argv, dpy, config_file, all_xerrors, need_fork);
|
|
|
|
if (!ps_g) {
|
2019-10-23 18:27:30 +00:00
|
|
|
log_fatal("Failed to create new session.");
|
2019-11-10 19:10:32 +00:00
|
|
|
ret_code = 1;
|
|
|
|
break;
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
if (need_fork) {
|
|
|
|
// Finishing up daemonization
|
|
|
|
// Close files
|
|
|
|
if (fclose(stdout) || fclose(stderr) || fclose(stdin)) {
|
|
|
|
log_fatal("Failed to close standard input/output");
|
2019-11-10 19:10:32 +00:00
|
|
|
ret_code = 1;
|
|
|
|
break;
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
|
|
|
// Make us the session and process group leader so we don't get
|
|
|
|
// killed when our parent die.
|
|
|
|
setsid();
|
|
|
|
// Notify the parent that we are done. This might cause the parent
|
|
|
|
// to quit, so only do this after setsid()
|
|
|
|
int tmp = 1;
|
|
|
|
write(pfds[1], &tmp, sizeof tmp);
|
|
|
|
close(pfds[1]);
|
|
|
|
// We only do this once
|
|
|
|
need_fork = false;
|
|
|
|
}
|
|
|
|
session_run(ps_g);
|
|
|
|
quit = ps_g->quit;
|
2020-09-16 18:25:10 +00:00
|
|
|
if (quit && ps_g->o.write_pid_path) {
|
|
|
|
pid_file = strdup(ps_g->o.write_pid_path);
|
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
session_destroy(ps_g);
|
|
|
|
free(ps_g);
|
|
|
|
ps_g = NULL;
|
2019-07-25 20:15:47 +00:00
|
|
|
if (dpy) {
|
|
|
|
XCloseDisplay(dpy);
|
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
} while (!quit);
|
|
|
|
|
|
|
|
free(config_file);
|
2020-09-16 18:25:10 +00:00
|
|
|
if (pid_file) {
|
|
|
|
log_trace("remove pid file %s", pid_file);
|
|
|
|
unlink(pid_file);
|
2020-10-22 13:44:10 +00:00
|
|
|
free(pid_file);
|
2020-09-16 18:25:10 +00:00
|
|
|
}
|
2019-03-10 12:34:37 +00:00
|
|
|
|
2019-07-25 01:34:50 +00:00
|
|
|
log_deinit_tls();
|
|
|
|
|
2019-11-10 19:10:32 +00:00
|
|
|
return ret_code;
|
2012-11-19 01:46:07 +00:00
|
|
|
}
|