2018-10-04 05:14:51 +08:00
|
|
|
// SPDX-License-Identifier: MIT
|
2003-11-10 11:45:17 +08:00
|
|
|
/*
|
2012-02-27 12:00:12 +08:00
|
|
|
* Compton - a compositor for X11
|
2003-11-10 11:45:17 +08:00
|
|
|
*
|
2012-02-27 12:00:12 +08:00
|
|
|
* Based on `xcompmgr` - Copyright (c) 2003, Keith Packard
|
2003-11-10 11:45:17 +08: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 20:20:27 +08:00
|
|
|
* Copyright (c) 2011-2013, Christopher Jeffrey
|
2018-10-04 05:24:12 +08:00
|
|
|
* See LICENSE-mit for more information.
|
2003-11-10 11:45:17 +08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2018-12-30 15:06:47 +08:00
|
|
|
#include <X11/Xlib-xcb.h>
|
2019-03-10 20:34:37 +08:00
|
|
|
#include <X11/Xlib.h>
|
2018-12-30 15:06:47 +08:00
|
|
|
#include <X11/extensions/sync.h>
|
2019-03-10 20:34:37 +08:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <xcb/composite.h>
|
2018-09-23 06:44:44 +08:00
|
|
|
#include <xcb/damage.h>
|
2019-03-10 20:34:37 +08:00
|
|
|
#include <xcb/present.h>
|
|
|
|
#include <xcb/randr.h>
|
2018-09-24 02:10:46 +08:00
|
|
|
#include <xcb/render.h>
|
2019-01-21 05:15:20 +08:00
|
|
|
#include <xcb/sync.h>
|
2019-03-10 20:34:37 +08:00
|
|
|
#include <xcb/xfixes.h>
|
2018-09-07 02:17:26 +08:00
|
|
|
|
2019-03-19 06:34:59 +08:00
|
|
|
#include <test.h>
|
2018-10-03 03:22:26 +08:00
|
|
|
#include <ev.h>
|
|
|
|
|
2019-01-19 07:30:44 +08:00
|
|
|
#include "common.h"
|
2018-12-16 02:47:21 +08:00
|
|
|
#include "compiler.h"
|
2012-02-08 18:31:39 +08:00
|
|
|
#include "compton.h"
|
2019-03-10 20:34:37 +08:00
|
|
|
#include "err.h"
|
|
|
|
#include "kernel.h"
|
2018-09-30 06:30:19 +08:00
|
|
|
#ifdef CONFIG_OPENGL
|
|
|
|
#include "opengl.h"
|
|
|
|
#endif
|
2019-03-10 20:34:37 +08:00
|
|
|
#include "backend/backend.h"
|
|
|
|
#include "c2.h"
|
2018-08-22 19:58:49 +08:00
|
|
|
#include "config.h"
|
2018-11-04 06:15:38 +08:00
|
|
|
#include "diagnostic.h"
|
2019-03-10 20:34:37 +08:00
|
|
|
#include "log.h"
|
2019-01-19 07:30:44 +08:00
|
|
|
#include "region.h"
|
2019-03-10 20:34:37 +08:00
|
|
|
#include "render.h"
|
2019-01-19 07:30:44 +08:00
|
|
|
#include "types.h"
|
2019-03-10 20:34:37 +08:00
|
|
|
#include "utils.h"
|
|
|
|
#include "win.h"
|
|
|
|
#include "x.h"
|
2018-12-21 06:31:34 +08:00
|
|
|
#ifdef CONFIG_DBUS
|
|
|
|
#include "dbus.h"
|
|
|
|
#endif
|
2019-03-17 21:44:26 +08:00
|
|
|
#include "event.h"
|
2019-03-17 23:17:48 +08:00
|
|
|
#include "options.h"
|
2018-11-11 05:52:42 +08:00
|
|
|
|
2018-11-27 08:32:08 +08:00
|
|
|
/// Get session_t pointer from a pointer to a member of session_t
|
2019-03-10 20:34:37 +08: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 08:32:08 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
static bool must_use redir_start(session_t *ps);
|
2018-09-07 02:17:26 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
static void redir_stop(session_t *ps);
|
2018-09-07 02:17:26 +08:00
|
|
|
|
2012-11-19 09:46:07 +08:00
|
|
|
// === Global constants ===
|
2012-02-27 12:00:12 +08:00
|
|
|
|
2012-11-19 09:46:07 +08:00
|
|
|
/// Name strings for window types.
|
2019-03-10 20:34:37 +08:00
|
|
|
const char *const WINTYPES[NUM_WINTYPES] = {
|
|
|
|
"unknown", "desktop", "dock", "toolbar", "menu",
|
|
|
|
"utility", "splash", "dialog", "normal", "dropdown_menu",
|
|
|
|
"popup_menu", "tooltip", "notify", "combo", "dnd",
|
2012-09-25 21:04:10 +08:00
|
|
|
};
|
|
|
|
|
2013-03-16 22:54:43 +08:00
|
|
|
/// Names of backends.
|
2019-03-10 20:34:37 +08:00
|
|
|
const char *const BACKEND_STRS[NUM_BKEND + 1] = {"xrender", // BKEND_XRENDER
|
|
|
|
"glx", // BKEND_GLX
|
|
|
|
"xr_glx_hybrid", // BKEND_XR_GLX_HYBRID
|
|
|
|
NULL};
|
2013-04-21 22:30:22 +08:00
|
|
|
|
2012-11-19 09:46:07 +08: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 11:42:39 +08:00
|
|
|
|
2012-11-19 09:46:07 +08:00
|
|
|
/// Pointer to current session, as a global variable. Only used by
|
2018-11-27 07:56:55 +08: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 09:46:07 +08:00
|
|
|
session_t *ps_g = NULL;
|
2003-11-25 01:11:00 +08:00
|
|
|
|
2019-03-17 23:17:48 +08:00
|
|
|
void set_root_flags(session_t *ps, uint64_t flags) {
|
|
|
|
ps->root_flags |= flags;
|
|
|
|
}
|
|
|
|
|
2018-11-04 06:38:18 +08:00
|
|
|
/**
|
|
|
|
* Free Xinerama screen info.
|
|
|
|
*
|
|
|
|
* XXX consider moving to x.c
|
|
|
|
*/
|
2019-03-10 20:34:37 +08: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);
|
|
|
|
}
|
2019-03-17 23:17:48 +08:00
|
|
|
free(ps->xinerama_scrs);
|
2019-03-10 20:34:37 +08:00
|
|
|
ps->xinerama_scrs = NULL;
|
|
|
|
ps->xinerama_nscrs = 0;
|
2018-11-04 06:38:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get current system clock in milliseconds.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
static inline uint64_t get_time_ms(void) {
|
|
|
|
struct timespec tp;
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &tp);
|
|
|
|
return tp.tv_sec * ((uint64_t)1000ul) + tp.tv_nsec / 1000000;
|
2018-11-04 06:38:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// XXX Move to x.c
|
2019-03-17 21:44:26 +08:00
|
|
|
void cxinerama_upd_scrs(session_t *ps) {
|
2019-03-10 20:34:37 +08: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);
|
|
|
|
|
|
|
|
ps->xinerama_scrs =
|
|
|
|
xcb_xinerama_query_screens_reply(ps->c, xcb_xinerama_query_screens(ps->c), NULL);
|
|
|
|
if (!ps->xinerama_scrs)
|
|
|
|
return;
|
|
|
|
|
|
|
|
xcb_xinerama_screen_info_t *scrs =
|
|
|
|
xcb_xinerama_query_screens_screen_info(ps->xinerama_scrs);
|
|
|
|
ps->xinerama_nscrs = xcb_xinerama_query_screens_screen_info_length(ps->xinerama_scrs);
|
|
|
|
|
|
|
|
ps->xinerama_scr_regs = ccalloc(ps->xinerama_nscrs, region_t);
|
|
|
|
for (int i = 0; i < ps->xinerama_nscrs; ++i) {
|
|
|
|
const xcb_xinerama_screen_info_t *const s = &scrs[i];
|
|
|
|
pixman_region32_init_rect(&ps->xinerama_scr_regs[i], s->x_org, s->y_org,
|
|
|
|
s->width, s->height);
|
|
|
|
}
|
2018-11-04 06:38:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find matched window.
|
|
|
|
*
|
|
|
|
* XXX move to win.c
|
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
static inline win *find_win_all(session_t *ps, const xcb_window_t wid) {
|
|
|
|
if (!wid || PointerRoot == wid || wid == ps->root || wid == ps->overlay)
|
|
|
|
return NULL;
|
2018-11-04 06:38:18 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
win *w = find_win(ps, wid);
|
|
|
|
if (!w)
|
|
|
|
w = find_toplevel(ps, wid);
|
|
|
|
if (!w)
|
|
|
|
w = find_toplevel2(ps, wid);
|
|
|
|
return w;
|
2018-11-04 06:38:18 +08:00
|
|
|
}
|
|
|
|
|
2018-10-03 03:22:26 +08:00
|
|
|
void queue_redraw(session_t *ps) {
|
2019-03-10 20:34:37 +08:00
|
|
|
// If --benchmark is used, redraw is always queued
|
|
|
|
if (!ps->redraw_needed && !ps->o.benchmark)
|
|
|
|
ev_idle_start(ps->loop, &ps->draw_idle);
|
|
|
|
ps->redraw_needed = true;
|
2018-10-03 03:22:26 +08: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 11:56:00 +08:00
|
|
|
/**
|
|
|
|
* Get a region of the screen size.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08: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 11:56:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void add_damage(session_t *ps, const region_t *damage) {
|
2019-03-10 20:34:37 +08:00
|
|
|
// Ignore damage when screen isn't redirected
|
|
|
|
if (!ps->redirected)
|
|
|
|
return;
|
2018-09-09 09:29:45 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
if (!damage)
|
|
|
|
return;
|
|
|
|
pixman_region32_union(ps->damage, ps->damage, (region_t *)damage);
|
2018-09-09 09:29:45 +08:00
|
|
|
}
|
|
|
|
|
2012-11-19 09:46:07 +08:00
|
|
|
// === Fading ===
|
2012-09-26 15:37:11 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
/**
|
|
|
|
* Get the time left before next fading point.
|
|
|
|
*
|
|
|
|
* In milliseconds.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08: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-22 00:25:28 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
int diff = ps->o.fade_delta + ps->fade_time - now;
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
diff = normalize_i_range(diff, 0, ps->o.fade_delta * 2);
|
2004-07-08 15:07:26 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
return diff / 1000.0;
|
2004-07-08 15:07:26 +08:00
|
|
|
}
|
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
/**
|
|
|
|
* Run fading on a window.
|
|
|
|
*
|
|
|
|
* @param steps steps of fading
|
2019-02-12 09:53:50 +08:00
|
|
|
* @return whether we are still in fading mode
|
2012-09-19 20:49:16 +08:00
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
static bool run_fade(session_t *ps, win **_w, unsigned steps) {
|
|
|
|
win *w = *_w;
|
|
|
|
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
|
|
|
|
// We are not fading
|
|
|
|
assert(w->opacity_tgt == w->opacity);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!win_should_fade(ps, w)) {
|
|
|
|
log_debug("Window %#010x %s doesn't need fading", w->id, w->name);
|
|
|
|
w->opacity = w->opacity_tgt;
|
|
|
|
}
|
|
|
|
if (w->opacity == w->opacity_tgt) {
|
|
|
|
// We have reached target opacity, wrapping up.
|
|
|
|
// Note, we reach here after we have rendered the window with the target
|
|
|
|
// opacity at least once. If the window is destroyed because it is faded
|
|
|
|
// out, there is no need to add damage here.
|
|
|
|
log_debug("Fading finished for window %#010x %s", w->id, w->name);
|
|
|
|
win_check_fade_finished(ps, _w);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (steps) {
|
|
|
|
if (w->opacity < w->opacity_tgt) {
|
|
|
|
w->opacity = normalize_d_range(
|
|
|
|
w->opacity + ps->o.fade_in_step * steps, 0.0, w->opacity_tgt);
|
|
|
|
} else {
|
|
|
|
w->opacity = normalize_d_range(
|
|
|
|
w->opacity - ps->o.fade_out_step * steps, w->opacity_tgt, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-17 04:14:54 +08:00
|
|
|
// Note even if opacity == opacity_tgt here, we still want to run preprocess one
|
|
|
|
// last time to finish state transition. So return true in that case too.
|
2019-03-10 20:34:37 +08:00
|
|
|
return true;
|
2004-07-08 15:07:26 +08:00
|
|
|
}
|
|
|
|
|
2012-11-19 09:46:07 +08:00
|
|
|
// === Error handling ===
|
2012-02-09 06:45:08 +08:00
|
|
|
|
2019-03-17 21:44:26 +08:00
|
|
|
void discard_ignore(session_t *ps, unsigned long sequence) {
|
2019-03-10 20:34:37 +08: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 12:48:37 +08:00
|
|
|
}
|
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
static int should_ignore(session_t *ps, unsigned long sequence) {
|
|
|
|
discard_ignore(ps, sequence);
|
|
|
|
return ps->ignore_head && ps->ignore_head->sequence == sequence;
|
2004-06-27 12:48:37 +08:00
|
|
|
}
|
|
|
|
|
2012-11-19 09:46:07 +08:00
|
|
|
// === Windows ===
|
2012-02-09 06:45:08 +08:00
|
|
|
|
2012-11-19 09:46:07 +08:00
|
|
|
/**
|
|
|
|
* Determine the event mask for a window.
|
|
|
|
*/
|
2018-12-28 04:45:38 +08:00
|
|
|
long determine_evmask(session_t *ps, xcb_window_t wid, win_evmode_t mode) {
|
2019-03-10 20:34:37 +08:00
|
|
|
long evmask = 0;
|
|
|
|
win *w = NULL;
|
2012-09-13 23:12:54 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
// Check if it's a mapped frame window
|
|
|
|
if (WIN_EVMODE_FRAME == mode ||
|
|
|
|
((w = find_win(ps, wid)) && w->a.map_state == XCB_MAP_STATE_VIEWABLE)) {
|
|
|
|
evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE;
|
|
|
|
if (ps->o.track_focus && !ps->o.use_ewmh_active_win)
|
|
|
|
evmask |= XCB_EVENT_MASK_FOCUS_CHANGE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if it's a mapped client window
|
|
|
|
if (WIN_EVMODE_CLIENT == mode ||
|
|
|
|
((w = find_toplevel(ps, wid)) && w->a.map_state == XCB_MAP_STATE_VIEWABLE)) {
|
|
|
|
if (ps->o.frame_opacity || ps->o.track_wdata || ps->track_atom_lst ||
|
|
|
|
ps->o.detect_client_opacity)
|
|
|
|
evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE;
|
|
|
|
}
|
2012-09-13 22:30:18 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
return evmask;
|
2012-09-13 22:30:18 +08:00
|
|
|
}
|
|
|
|
|
2012-09-13 21:38:55 +08:00
|
|
|
/**
|
|
|
|
* Find out the WM frame of a client window by querying X.
|
|
|
|
*
|
2012-11-19 09:46:07 +08:00
|
|
|
* @param ps current session
|
2013-01-29 09:57:04 +08:00
|
|
|
* @param wid window ID
|
2012-09-13 21:38:55 +08:00
|
|
|
* @return struct _win object of the found window, NULL if not found
|
|
|
|
*/
|
2018-12-28 04:45:38 +08:00
|
|
|
win *find_toplevel2(session_t *ps, xcb_window_t wid) {
|
2019-03-10 20:34:37 +08:00
|
|
|
// TODO this should probably be an "update tree", then find_toplevel.
|
|
|
|
// current approach is a bit more "racy"
|
|
|
|
win *w = NULL;
|
2012-09-13 21:38:55 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
// We traverse through its ancestors to find out the frame
|
|
|
|
while (wid && wid != ps->root && !(w = find_win(ps, wid))) {
|
|
|
|
xcb_query_tree_reply_t *reply;
|
2012-09-13 21:38:55 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
// xcb_query_tree probably fails if you run compton when X is somehow
|
|
|
|
// initializing (like add it in .xinitrc). In this case
|
|
|
|
// just leave it alone.
|
|
|
|
reply = xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, wid), NULL);
|
|
|
|
if (reply == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
2012-09-13 21:38:55 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
wid = reply->parent;
|
2012-09-13 23:12:54 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
free(reply);
|
|
|
|
}
|
2012-09-13 21:38:55 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
return w;
|
2012-09-13 21:38:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Recheck currently focused window and set its <code>w->focused</code>
|
2012-11-19 09:46:07 +08:00
|
|
|
* to true.
|
2012-09-13 21:38:55 +08:00
|
|
|
*
|
2012-11-19 09:46:07 +08:00
|
|
|
* @param ps current session
|
2012-09-13 21:38:55 +08:00
|
|
|
* @return struct _win of currently focused window, NULL if not found
|
|
|
|
*/
|
2019-03-17 21:44:26 +08:00
|
|
|
win *recheck_focus(session_t *ps) {
|
2019-03-10 20:34:37 +08:00
|
|
|
// Use EWMH _NET_ACTIVE_WINDOW if enabled
|
|
|
|
if (ps->o.use_ewmh_active_win) {
|
|
|
|
update_ewmh_active_win(ps);
|
|
|
|
return ps->active_win;
|
|
|
|
}
|
2012-11-04 18:11:08 +08:00
|
|
|
|
2019-03-10 20:34:37 +08: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 21:38:55 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
if (reply) {
|
|
|
|
wid = reply->focus;
|
|
|
|
free(reply);
|
|
|
|
}
|
2012-09-13 21:38:55 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
win *w = find_win_all(ps, wid);
|
2012-09-13 21:38:55 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
log_trace("%#010" PRIx32 " (%#010lx \"%s\") focused.", wid,
|
|
|
|
(w ? w->id : XCB_NONE), (w ? w->name : NULL));
|
2013-10-21 22:17:01 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
// And we set the focus state here
|
|
|
|
if (w) {
|
|
|
|
win_set_focused(ps, w, true);
|
|
|
|
return w;
|
|
|
|
}
|
2012-09-13 21:38:55 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
return NULL;
|
2012-02-01 06:10:30 +08:00
|
|
|
}
|
|
|
|
|
2012-10-21 20:44:24 +08:00
|
|
|
/**
|
2018-09-07 02:17:26 +08:00
|
|
|
* Look for the client window of a particular window.
|
2012-10-21 20:44:24 +08:00
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
xcb_window_t find_client_win(session_t *ps, xcb_window_t w) {
|
|
|
|
if (wid_has_prop(ps, w, ps->atom_client)) {
|
|
|
|
return w;
|
|
|
|
}
|
|
|
|
|
|
|
|
xcb_query_tree_reply_t *reply =
|
|
|
|
xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, w), NULL);
|
|
|
|
if (!reply)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
xcb_window_t *children = xcb_query_tree_children(reply);
|
|
|
|
int nchildren = xcb_query_tree_children_length(reply);
|
|
|
|
int i;
|
|
|
|
xcb_window_t ret = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < nchildren; ++i) {
|
|
|
|
if ((ret = find_client_win(ps, children[i])))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(reply);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-03-17 23:17:48 +08: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");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ps->root_flags &= ~ROOT_FLAGS_SCREEN_CHANGE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
static win *paint_preprocess(session_t *ps, bool *fade_running) {
|
|
|
|
// XXX need better, more general name for `fade_running`. It really
|
|
|
|
// means if fade is still ongoing after the current frame is rendered
|
|
|
|
win *t = NULL, *next = NULL;
|
|
|
|
*fade_running = false;
|
|
|
|
|
|
|
|
// Fading step calculation
|
|
|
|
unsigned long steps = 0L;
|
|
|
|
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
|
|
|
|
for (win *w = ps->list; w; w = next) {
|
|
|
|
next = w->next;
|
|
|
|
const winmode_t mode_old = w->mode;
|
|
|
|
const bool was_painted = w->to_paint;
|
|
|
|
const opacity_t opacity_old = w->opacity;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!w) {
|
|
|
|
// the window might have been destroyed because fading finished
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Opacity will not change, from now on.
|
|
|
|
rc_region_t *last_reg_ignore = rc_region_new();
|
|
|
|
|
|
|
|
bool unredir_possible = false;
|
|
|
|
// Trace whether it's the highest window to paint
|
|
|
|
bool is_highest = true;
|
|
|
|
bool reg_ignore_valid = true;
|
|
|
|
for (win *w = ps->list; w; w = next) {
|
|
|
|
__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;
|
|
|
|
|
|
|
|
// In case calling the fade callback function destroys this window
|
|
|
|
next = w->next;
|
|
|
|
|
|
|
|
// Destroy reg_ignore if some window above us invalidated it
|
|
|
|
if (!reg_ignore_valid)
|
|
|
|
rc_region_unref(&w->reg_ignore);
|
|
|
|
|
|
|
|
// 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
|
|
|
|
if (!w->ever_damaged || 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 || w->state == WSTATE_UNMAPPED ||
|
2019-03-17 11:04:23 +08:00
|
|
|
(double)w->opacity * MAX_ALPHA < 1 || w->paint_excluded) {
|
2019-03-10 20:34:37 +08:00
|
|
|
to_paint = false;
|
2019-03-17 11:04:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((w->flags & WIN_FLAGS_IMAGE_ERROR) != 0) {
|
|
|
|
to_paint = false;
|
|
|
|
}
|
2019-03-10 20:34:37 +08: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);
|
|
|
|
}
|
|
|
|
|
|
|
|
// to_paint will never change afterward
|
|
|
|
if (!to_paint)
|
|
|
|
goto skip_window;
|
|
|
|
|
|
|
|
// 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
|
|
|
|
if (!w->reg_ignore)
|
|
|
|
w->reg_ignore = rc_region_ref(last_reg_ignore);
|
|
|
|
|
|
|
|
// If the window is solid, we add the window region to the
|
|
|
|
// ignored region
|
|
|
|
// Otherwise last_reg_ignore shouldn't change
|
|
|
|
if (w->mode == WMODE_SOLID && !ps->o.force_win_blend) {
|
|
|
|
region_t *tmp = rc_region_new();
|
|
|
|
if (w->frame_opacity == 1)
|
|
|
|
*tmp = win_get_bounding_shape_global_by_val(w);
|
|
|
|
else {
|
|
|
|
win_get_region_noframe_local(w, tmp);
|
|
|
|
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) {
|
|
|
|
if (win_is_solid(ps, w) &&
|
|
|
|
(w->frame_opacity == 1 || !win_has_frame(w)) &&
|
|
|
|
win_is_fullscreen(ps, w) && !w->unredir_if_possible_excluded)
|
|
|
|
unredir_possible = true;
|
|
|
|
}
|
|
|
|
|
2019-03-17 04:14:54 +08:00
|
|
|
if ((w->flags & WIN_FLAGS_STALE_IMAGE) != 0 &&
|
|
|
|
(w->flags & WIN_FLAGS_IMAGE_ERROR) == 0) {
|
|
|
|
// Image needs to be updated
|
|
|
|
w->flags &= ~WIN_FLAGS_STALE_IMAGE;
|
|
|
|
if (w->state != WSTATE_UNMAPPING && w->state != WSTATE_DESTROYING) {
|
|
|
|
// If this window doesn't have an image available, don't
|
|
|
|
// try to rebind it
|
|
|
|
if (!win_try_rebind_image(ps, w)) {
|
|
|
|
w->flags |= WIN_FLAGS_IMAGE_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-03-10 20:34:37 +08:00
|
|
|
w->prev_trans = t;
|
|
|
|
t = w;
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
win_check_fade_finished(ps, &w);
|
|
|
|
|
|
|
|
// 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
|
|
|
|
if (ps->o.redirected_force != UNSET)
|
|
|
|
unredir_possible = !ps->o.redirected_force;
|
|
|
|
else if (ps->o.unredir_if_possible && is_highest && !ps->redirected)
|
|
|
|
// If there's no window to paint, and the screen isn't redirected,
|
|
|
|
// don't redirect it.
|
|
|
|
unredir_possible = true;
|
|
|
|
if (unredir_possible) {
|
|
|
|
if (ps->redirected) {
|
|
|
|
if (!ps->o.unredir_if_possible_delay || ps->tmout_unredir_hit)
|
|
|
|
redir_stop(ps);
|
|
|
|
else if (!ev_is_active(&ps->unredir_timer)) {
|
|
|
|
ev_timer_set(&ps->unredir_timer,
|
|
|
|
ps->o.unredir_if_possible_delay / 1000.0, 0);
|
|
|
|
ev_timer_start(ps->loop, &ps->unredir_timer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ev_timer_stop(ps->loop, &ps->unredir_timer);
|
|
|
|
if (!redir_start(ps)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return t;
|
2018-12-16 05:11:41 +08:00
|
|
|
}
|
2013-03-25 11:36:39 +08:00
|
|
|
|
2012-11-03 10:30:32 +08:00
|
|
|
/**
|
|
|
|
* Rebuild cached <code>screen_reg</code>.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
static void rebuild_screen_reg(session_t *ps) {
|
|
|
|
get_screen_region(ps, &ps->screen_reg);
|
2012-11-03 10:30:32 +08:00
|
|
|
}
|
|
|
|
|
2013-06-09 17:06:35 +08:00
|
|
|
/**
|
|
|
|
* Rebuild <code>shadow_exclude_reg</code>.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void restack_win(session_t *ps, win *w, xcb_window_t new_above) {
|
|
|
|
xcb_window_t old_above;
|
|
|
|
|
|
|
|
if (w->next) {
|
|
|
|
old_above = w->next->id;
|
|
|
|
} else {
|
|
|
|
old_above = XCB_NONE;
|
|
|
|
}
|
|
|
|
log_debug("Restack %#010x (%s), old_above: %#010x, new_above: %#010x", w->id,
|
|
|
|
w->name, old_above, new_above);
|
|
|
|
|
|
|
|
if (old_above != new_above) {
|
|
|
|
w->reg_ignore_valid = false;
|
|
|
|
rc_region_unref(&w->reg_ignore);
|
|
|
|
if (w->next) {
|
|
|
|
w->next->reg_ignore_valid = false;
|
|
|
|
rc_region_unref(&w->next->reg_ignore);
|
|
|
|
}
|
|
|
|
|
|
|
|
win **prev = NULL, **prev_old = NULL;
|
|
|
|
|
|
|
|
bool found = false;
|
|
|
|
for (prev = &ps->list; *prev; prev = &(*prev)->next) {
|
|
|
|
if ((*prev)->id == new_above && (*prev)->state != WSTATE_DESTROYING) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_above && !found) {
|
|
|
|
log_error("(%#010x, %#010x): Failed to found new above window.",
|
|
|
|
w->id, new_above);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (prev_old = &ps->list; *prev_old; prev_old = &(*prev_old)->next) {
|
|
|
|
if ((*prev_old) == w) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*prev_old = w->next;
|
|
|
|
w->next = *prev;
|
|
|
|
*prev = w;
|
|
|
|
|
|
|
|
// add damage for this window
|
|
|
|
add_damage_from_win(ps, w);
|
2018-10-30 01:13:23 +08:00
|
|
|
|
2018-09-07 02:17:26 +08:00
|
|
|
#ifdef DEBUG_RESTACK
|
2019-03-10 20:34:37 +08:00
|
|
|
log_trace("Window stack modified. Current stack:");
|
|
|
|
for (win *c = ps->list; c; c = c->next) {
|
|
|
|
const char *desc = "";
|
|
|
|
if (c->state == WSTATE_DESTROYING) {
|
|
|
|
desc = "(D) ";
|
|
|
|
}
|
|
|
|
log_trace("%#010x \"%s\" %s", c->id, c->name, desc);
|
|
|
|
}
|
2018-09-07 02:17:26 +08:00
|
|
|
#endif
|
2019-03-10 20:34:37 +08:00
|
|
|
}
|
2012-10-28 17:02:07 +08:00
|
|
|
}
|
|
|
|
|
2019-03-18 00:08:31 +08:00
|
|
|
/// Free up all the images and deinit the backend
|
|
|
|
static void destroy_backend(session_t *ps) {
|
|
|
|
for (win *w = ps->list, *next; w; w = next) {
|
|
|
|
next = w->next;
|
|
|
|
// Wrapping up fading in progress
|
|
|
|
win_skip_fading(ps, &w);
|
|
|
|
|
|
|
|
// `w` might be freed by win_check_fade_finished
|
|
|
|
if (!w) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (ps->o.experimental_backends) {
|
|
|
|
if (w->state == WSTATE_MAPPED) {
|
|
|
|
win_release_image(ps->backend_data, w);
|
|
|
|
} else {
|
|
|
|
assert(!w->win_image);
|
|
|
|
assert(!w->shadow_image);
|
|
|
|
}
|
|
|
|
if (ps->root_image) {
|
|
|
|
ps->backend_data->ops->release_image(ps->backend_data,
|
|
|
|
ps->root_image);
|
|
|
|
ps->root_image = NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
free_paint(ps, &w->paint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ps->o.experimental_backends) {
|
|
|
|
// deinit backend
|
|
|
|
ps->backend_data->ops->deinit(ps->backend_data);
|
|
|
|
ps->backend_data = 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) {
|
|
|
|
// Reinitialize win_data
|
|
|
|
ps->backend_data = backend_list[ps->o.backend]->init(ps);
|
|
|
|
ps->backend_data->ops = backend_list[ps->o.backend];
|
|
|
|
if (!ps->backend_data) {
|
|
|
|
log_fatal("Failed to initialize backend, aborting...");
|
|
|
|
ps->quit = true;
|
|
|
|
ev_break(ps->loop, EVBREAK_ALL);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (win *w = ps->list; w; w = w->next) {
|
|
|
|
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) {
|
|
|
|
if (!win_bind_image(ps, w)) {
|
|
|
|
w->flags |= WIN_FLAGS_IMAGE_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The old backends binds pixmap lazily, nothing to do here
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-02-25 08:25:45 +08:00
|
|
|
/// Handle configure event of a root window
|
|
|
|
void configure_root(session_t *ps, int width, int height) {
|
2019-03-18 00:08:31 +08:00
|
|
|
log_info("Root configuration changed, new geometry: %dx%d", width, height);
|
2019-03-10 20:34:37 +08:00
|
|
|
// On root window changes
|
|
|
|
bool has_root_change = false;
|
|
|
|
if (ps->o.experimental_backends) {
|
|
|
|
has_root_change = ps->backend_data->ops->root_change != NULL;
|
|
|
|
if (!has_root_change) {
|
2019-03-18 00:08:31 +08:00
|
|
|
// deinit/reinit backend and free up resources if the backend
|
|
|
|
// cannot handle root change
|
|
|
|
destroy_backend(ps);
|
2019-03-10 20:34:37 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
free_paint(ps, &ps->tgt_buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
ps->root_width = width;
|
|
|
|
ps->root_height = height;
|
|
|
|
|
|
|
|
rebuild_screen_reg(ps);
|
|
|
|
rebuild_shadow_exclude_reg(ps);
|
|
|
|
for (int i = 0; i < ps->ndamage; i++) {
|
|
|
|
pixman_region32_clear(&ps->damage_ring[i]);
|
|
|
|
}
|
|
|
|
ps->damage = ps->damage_ring + ps->ndamage - 1;
|
|
|
|
|
|
|
|
// Invalidate reg_ignore from the top
|
|
|
|
rc_region_unref(&ps->list->reg_ignore);
|
|
|
|
ps->list->reg_ignore_valid = false;
|
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 11:56:00 +08:00
|
|
|
|
2018-09-07 02:17:26 +08:00
|
|
|
#ifdef CONFIG_OPENGL
|
2019-03-10 20:34:37 +08:00
|
|
|
// GLX root change callback
|
2019-03-11 00:34:07 +08:00
|
|
|
if (BKEND_GLX == ps->o.backend && !ps->o.experimental_backends) {
|
2019-03-10 20:34:37 +08:00
|
|
|
glx_on_root_change(ps);
|
2019-03-11 00:34:07 +08:00
|
|
|
}
|
2018-09-07 02:17:26 +08:00
|
|
|
#endif
|
2019-03-10 20:34:37 +08:00
|
|
|
if (ps->o.experimental_backends) {
|
|
|
|
if (has_root_change) {
|
|
|
|
ps->backend_data->ops->root_change(ps->backend_data, ps);
|
|
|
|
} else {
|
2019-03-18 00:08:31 +08:00
|
|
|
if (!initialize_backend(ps)) {
|
2019-03-10 20:34:37 +08:00
|
|
|
log_fatal("Failed to re-initialize backend after root "
|
|
|
|
"change, aborting...");
|
|
|
|
ps->quit = true;
|
|
|
|
// TODO only event handlers should request ev_break,
|
|
|
|
// otherwise it's too hard to keep track of what can break
|
|
|
|
// the event loop
|
|
|
|
ev_break(ps->loop, EVBREAK_ALL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
force_repaint(ps);
|
|
|
|
return;
|
2019-02-25 08:25:45 +08:00
|
|
|
}
|
2013-01-12 22:21:35 +08:00
|
|
|
|
2019-02-25 08:25:45 +08:00
|
|
|
/// Handle configure event of a regular window
|
2019-03-10 20:34:37 +08:00
|
|
|
void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
|
|
|
|
win *w = find_win(ps, ce->window);
|
|
|
|
region_t damage;
|
|
|
|
pixman_region32_init(&damage);
|
|
|
|
|
|
|
|
if (!w) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (w->state == WSTATE_UNMAPPED || w->state == WSTATE_UNMAPPING ||
|
|
|
|
w->state == WSTATE_DESTROYING) {
|
2019-03-17 07:57:47 +08:00
|
|
|
// Only restack the window to make sure we can handle future restack
|
|
|
|
// notification correctly
|
2019-03-10 20:34:37 +08:00
|
|
|
restack_win(ps, w, ce->above_sibling);
|
|
|
|
} else {
|
2019-03-17 07:57:47 +08:00
|
|
|
restack_win(ps, w, ce->above_sibling);
|
2019-03-10 20:34:37 +08:00
|
|
|
|
|
|
|
bool factor_change = false;
|
|
|
|
win_extents(w, &damage);
|
|
|
|
|
|
|
|
// If window geometry change, free old extents
|
|
|
|
if (w->g.x != ce->x || w->g.y != ce->y || w->g.width != ce->width ||
|
|
|
|
w->g.height != ce->height || w->g.border_width != ce->border_width)
|
|
|
|
factor_change = true;
|
|
|
|
|
|
|
|
w->g.x = ce->x;
|
|
|
|
w->g.y = ce->y;
|
|
|
|
|
|
|
|
if (w->g.width != ce->width || w->g.height != ce->height ||
|
|
|
|
w->g.border_width != ce->border_width) {
|
2019-03-17 07:57:47 +08:00
|
|
|
log_trace("Window size changed, %dx%d -> %dx%d", w->g.width,
|
|
|
|
w->g.height, ce->width, ce->height);
|
2019-03-10 20:34:37 +08:00
|
|
|
w->g.width = ce->width;
|
|
|
|
w->g.height = ce->height;
|
|
|
|
w->g.border_width = ce->border_width;
|
|
|
|
win_on_win_size_change(ps, w);
|
|
|
|
win_update_bounding_shape(ps, w);
|
|
|
|
}
|
|
|
|
|
|
|
|
region_t new_extents;
|
|
|
|
pixman_region32_init(&new_extents);
|
|
|
|
win_extents(w, &new_extents);
|
|
|
|
pixman_region32_union(&damage, &damage, &new_extents);
|
|
|
|
pixman_region32_fini(&new_extents);
|
|
|
|
|
|
|
|
if (factor_change) {
|
|
|
|
win_on_factor_change(ps, w);
|
|
|
|
add_damage(ps, &damage);
|
|
|
|
win_update_screen(ps, w);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pixman_region32_fini(&damage);
|
|
|
|
|
|
|
|
// override_redirect flag cannot be changed after window creation, as far
|
|
|
|
// as I know, so there's no point to re-match windows here.
|
|
|
|
w->a.override_redirect = ce->override_redirect;
|
|
|
|
}
|
|
|
|
|
2019-03-17 21:44:26 +08:00
|
|
|
void circulate_win(session_t *ps, xcb_circulate_notify_event_t *ce) {
|
2019-03-10 20:34:37 +08:00
|
|
|
win *w = find_win(ps, ce->window);
|
|
|
|
xcb_window_t new_above;
|
|
|
|
|
|
|
|
if (!w)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (ce->place == PlaceOnTop) {
|
|
|
|
new_above = ps->list->id;
|
|
|
|
} else {
|
|
|
|
new_above = XCB_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
restack_win(ps, w, new_above);
|
|
|
|
}
|
|
|
|
|
2019-03-17 21:44:26 +08:00
|
|
|
void root_damaged(session_t *ps) {
|
2019-03-10 20:34:37 +08:00
|
|
|
if (ps->root_tile_paint.pixmap) {
|
|
|
|
free_root_tile(ps);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ps->o.experimental_backends) {
|
|
|
|
if (ps->root_image) {
|
|
|
|
ps->backend_data->ops->release_image(ps->backend_data, ps->root_image);
|
|
|
|
}
|
|
|
|
auto pixmap = x_get_root_back_pixmap(ps);
|
|
|
|
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);
|
|
|
|
ps->backend_data->ops->image_op(
|
|
|
|
ps->backend_data, IMAGE_OP_RESIZE_TILE, ps->root_image, NULL,
|
|
|
|
NULL, (int[]){ps->root_width, ps->root_height});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mark screen damaged
|
|
|
|
force_repaint(ps);
|
2012-10-24 10:09:59 +08:00
|
|
|
}
|
|
|
|
|
2018-09-29 17:11:43 +08:00
|
|
|
/**
|
|
|
|
* Xlib error handler function.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
static int xerror(Display attr_unused *dpy, XErrorEvent *ev) {
|
|
|
|
if (!should_ignore(ps_g, ev->serial))
|
|
|
|
x_print_error(ev->serial, ev->request_code, ev->minor_code, ev->error_code);
|
|
|
|
return 0;
|
2003-11-09 15:08:23 +08:00
|
|
|
}
|
|
|
|
|
2018-09-29 17:11:43 +08:00
|
|
|
/**
|
|
|
|
* XCB error handler function.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
void ev_xcb_error(session_t *ps, xcb_generic_error_t *err) {
|
|
|
|
if (!should_ignore(ps, err->sequence))
|
|
|
|
x_print_error(err->sequence, err->major_code, err->minor_code, err->error_code);
|
2018-09-29 17:11:43 +08:00
|
|
|
}
|
|
|
|
|
2013-01-24 13:38:03 +08:00
|
|
|
/**
|
|
|
|
* Force a full-screen repaint.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08: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 13:38:03 +08: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 20:20:27 +08:00
|
|
|
#ifdef CONFIG_DBUS
|
|
|
|
/** @name DBus hooks
|
|
|
|
*/
|
|
|
|
///@{
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set w->shadow_force of a window.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
void win_set_shadow_force(session_t *ps, win *w, switch_t val) {
|
|
|
|
if (val != w->shadow_force) {
|
|
|
|
w->shadow_force = val;
|
|
|
|
win_determine_shadow(ps, w);
|
|
|
|
queue_redraw(ps);
|
|
|
|
}
|
2013-05-20 18:04:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set w->fade_force of a window.
|
2019-02-09 23:50:40 +08:00
|
|
|
*
|
|
|
|
* Doesn't affect fading already in progress
|
2013-05-20 18:04:40 +08:00
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
void win_set_fade_force(session_t *ps, win *w, switch_t val) {
|
|
|
|
w->fade_force = val;
|
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 20:20:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set w->focused_force of a window.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
void win_set_focused_force(session_t *ps, win *w, switch_t val) {
|
|
|
|
if (val != w->focused_force) {
|
|
|
|
w->focused_force = val;
|
|
|
|
win_update_focused(ps, w);
|
|
|
|
queue_redraw(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 20:20:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set w->invert_color_force of a window.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
void win_set_invert_color_force(session_t *ps, win *w, switch_t val) {
|
|
|
|
if (val != w->invert_color_force) {
|
|
|
|
w->invert_color_force = val;
|
|
|
|
win_determine_invert_color(ps, w);
|
|
|
|
queue_redraw(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 20:20:27 +08:00
|
|
|
}
|
2013-03-10 18:45:54 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Enable focus tracking.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
void opts_init_track_focus(session_t *ps) {
|
|
|
|
// Already tracking focus
|
|
|
|
if (ps->o.track_focus)
|
|
|
|
return;
|
2013-03-10 18:45:54 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
ps->o.track_focus = true;
|
|
|
|
|
|
|
|
if (!ps->o.use_ewmh_active_win) {
|
|
|
|
// Start listening to FocusChange events
|
|
|
|
for (win *w = ps->list; w; w = w->next)
|
|
|
|
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE)
|
|
|
|
xcb_change_window_attributes(
|
|
|
|
ps->c, w->id, XCB_CW_EVENT_MASK,
|
|
|
|
(const uint32_t[]){
|
|
|
|
determine_evmask(ps, w->id, WIN_EVMODE_FRAME)});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recheck focus
|
|
|
|
recheck_focus(ps);
|
2013-03-10 18:45:54 +08:00
|
|
|
}
|
2013-05-20 18:04:40 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Set no_fading_openclose option.
|
2019-02-09 23:50:40 +08:00
|
|
|
*
|
|
|
|
* Don't affect fading already in progress
|
2013-05-20 18:04:40 +08:00
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
void opts_set_no_fading_openclose(session_t *ps, bool newval) {
|
|
|
|
ps->o.no_fading_openclose = newval;
|
2013-05-20 18:04:40 +08: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 20:20:27 +08:00
|
|
|
//!@}
|
|
|
|
#endif
|
|
|
|
|
2012-11-19 09:46:07 +08:00
|
|
|
// === Events ===
|
2012-02-09 17:37:46 +08:00
|
|
|
|
2012-11-04 18:11:08 +08: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.
|
|
|
|
*/
|
2019-03-17 21:44:26 +08:00
|
|
|
void update_ewmh_active_win(session_t *ps) {
|
2019-03-10 20:34:37 +08:00
|
|
|
// Search for the window
|
|
|
|
xcb_window_t wid = wid_get_prop_window(ps, ps->root, ps->atom_ewmh_active_win);
|
|
|
|
win *w = find_win_all(ps, wid);
|
2012-11-04 18:11:08 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
// Mark the window focused. No need to unfocus the previous one.
|
|
|
|
if (w)
|
|
|
|
win_set_focused(ps, w, true);
|
2012-11-04 18:11:08 +08:00
|
|
|
}
|
|
|
|
|
2012-11-19 09:46:07 +08:00
|
|
|
// === Main ===
|
2012-02-09 17:37:46 +08: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 10:20:01 +08:00
|
|
|
/**
|
|
|
|
* Register a window as symbol, and initialize GLX context if wanted.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
static bool register_cm(session_t *ps) {
|
|
|
|
assert(!ps->reg_win);
|
|
|
|
|
|
|
|
ps->reg_win =
|
|
|
|
XCreateSimpleWindow(ps->dpy, ps->root, 0, 0, 1, 1, 0, XCB_NONE, XCB_NONE);
|
|
|
|
|
|
|
|
if (!ps->reg_win) {
|
|
|
|
log_fatal("Failed to create window.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unredirect the window if it's redirected, just in case
|
|
|
|
if (ps->redirected)
|
|
|
|
xcb_composite_unredirect_window(ps->c, ps->reg_win,
|
|
|
|
XCB_COMPOSITE_REDIRECT_MANUAL);
|
|
|
|
|
|
|
|
{
|
|
|
|
XClassHint *h = XAllocClassHint();
|
|
|
|
if (h) {
|
|
|
|
h->res_name = "compton";
|
|
|
|
h->res_class = "xcompmgr";
|
|
|
|
}
|
|
|
|
Xutf8SetWMProperties(ps->dpy, ps->reg_win, "xcompmgr", "xcompmgr", NULL,
|
|
|
|
0, NULL, NULL, h);
|
|
|
|
cxfree(h);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set _NET_WM_PID
|
|
|
|
{
|
|
|
|
uint32_t pid = getpid();
|
|
|
|
xcb_change_property(ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win,
|
|
|
|
get_atom(ps, "_NET_WM_PID"), XCB_ATOM_CARDINAL, 32, 1,
|
|
|
|
&pid);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set COMPTON_VERSION
|
|
|
|
if (!wid_set_text_prop(ps, ps->reg_win, get_atom(ps, "COMPTON_VERSION"),
|
|
|
|
COMPTON_VERSION)) {
|
|
|
|
log_error("Failed to set COMPTON_VERSION.");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Acquire X Selection _NET_WM_CM_S?
|
|
|
|
if (!ps->o.no_x_selection) {
|
|
|
|
unsigned len = strlen(REGISTER_PROP) + 2;
|
|
|
|
int s = ps->scr;
|
|
|
|
Atom atom;
|
|
|
|
|
|
|
|
while (s >= 10) {
|
|
|
|
++len;
|
|
|
|
s /= 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto buf = ccalloc(len, char);
|
|
|
|
snprintf(buf, len, REGISTER_PROP "%d", ps->scr);
|
|
|
|
buf[len - 1] = '\0';
|
|
|
|
atom = get_atom(ps, buf);
|
|
|
|
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) {
|
|
|
|
free(reply);
|
|
|
|
log_fatal("Another composite manager is already running");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
free(reply);
|
|
|
|
xcb_set_selection_owner(ps->c, ps->reg_win, atom, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2005-10-07 08:08:02 +08:00
|
|
|
}
|
|
|
|
|
2013-11-09 21:38:31 +08:00
|
|
|
/**
|
|
|
|
* Write PID to a file.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
static inline bool write_pid(session_t *ps) {
|
|
|
|
if (!ps->o.write_pid_path)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
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 21:38:31 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
fprintf(f, "%ld\n", (long)getpid());
|
|
|
|
fclose(f);
|
2013-11-09 21:38:31 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
return true;
|
2013-11-09 21:38:31 +08:00
|
|
|
}
|
|
|
|
|
2012-11-19 09:46:07 +08:00
|
|
|
/**
|
|
|
|
* Fetch all required atoms and save them to a session.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
static void init_atoms(session_t *ps) {
|
|
|
|
ps->atom_opacity = get_atom(ps, "_NET_WM_WINDOW_OPACITY");
|
|
|
|
ps->atom_frame_extents = get_atom(ps, "_NET_FRAME_EXTENTS");
|
|
|
|
ps->atom_client = get_atom(ps, "WM_STATE");
|
|
|
|
ps->atom_name = XCB_ATOM_WM_NAME;
|
|
|
|
ps->atom_name_ewmh = get_atom(ps, "_NET_WM_NAME");
|
|
|
|
ps->atom_class = XCB_ATOM_WM_CLASS;
|
|
|
|
ps->atom_role = get_atom(ps, "WM_WINDOW_ROLE");
|
|
|
|
ps->atom_transient = XCB_ATOM_WM_TRANSIENT_FOR;
|
|
|
|
ps->atom_client_leader = get_atom(ps, "WM_CLIENT_LEADER");
|
|
|
|
ps->atom_ewmh_active_win = get_atom(ps, "_NET_ACTIVE_WINDOW");
|
|
|
|
ps->atom_compton_shadow = get_atom(ps, "_COMPTON_SHADOW");
|
|
|
|
|
|
|
|
ps->atom_win_type = get_atom(ps, "_NET_WM_WINDOW_TYPE");
|
|
|
|
ps->atoms_wintypes[WINTYPE_UNKNOWN] = 0;
|
|
|
|
ps->atoms_wintypes[WINTYPE_DESKTOP] = get_atom(ps, "_NET_WM_WINDOW_TYPE_DESKTOP");
|
|
|
|
ps->atoms_wintypes[WINTYPE_DOCK] = get_atom(ps, "_NET_WM_WINDOW_TYPE_DOCK");
|
|
|
|
ps->atoms_wintypes[WINTYPE_TOOLBAR] = get_atom(ps, "_NET_WM_WINDOW_TYPE_TOOLBAR");
|
|
|
|
ps->atoms_wintypes[WINTYPE_MENU] = get_atom(ps, "_NET_WM_WINDOW_TYPE_MENU");
|
|
|
|
ps->atoms_wintypes[WINTYPE_UTILITY] = get_atom(ps, "_NET_WM_WINDOW_TYPE_UTILITY");
|
|
|
|
ps->atoms_wintypes[WINTYPE_SPLASH] = get_atom(ps, "_NET_WM_WINDOW_TYPE_SPLASH");
|
|
|
|
ps->atoms_wintypes[WINTYPE_DIALOG] = get_atom(ps, "_NET_WM_WINDOW_TYPE_DIALOG");
|
|
|
|
ps->atoms_wintypes[WINTYPE_NORMAL] = get_atom(ps, "_NET_WM_WINDOW_TYPE_NORMAL");
|
|
|
|
ps->atoms_wintypes[WINTYPE_DROPDOWN_MENU] =
|
|
|
|
get_atom(ps, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU");
|
|
|
|
ps->atoms_wintypes[WINTYPE_POPUP_MENU] =
|
|
|
|
get_atom(ps, "_NET_WM_WINDOW_TYPE_POPUP_MENU");
|
|
|
|
ps->atoms_wintypes[WINTYPE_TOOLTIP] = get_atom(ps, "_NET_WM_WINDOW_TYPE_TOOLTIP");
|
|
|
|
ps->atoms_wintypes[WINTYPE_NOTIFY] =
|
|
|
|
get_atom(ps, "_NET_WM_WINDOW_TYPE_NOTIFICATION");
|
|
|
|
ps->atoms_wintypes[WINTYPE_COMBO] = get_atom(ps, "_NET_WM_WINDOW_TYPE_COMBO");
|
|
|
|
ps->atoms_wintypes[WINTYPE_DND] = get_atom(ps, "_NET_WM_WINDOW_TYPE_DND");
|
2012-09-25 10:19:20 +08: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 10:20:01 +08:00
|
|
|
/**
|
|
|
|
* Update refresh rate info with X Randr extension.
|
|
|
|
*/
|
2019-03-17 21:44:26 +08:00
|
|
|
void update_refresh_rate(session_t *ps) {
|
2019-03-10 20:34:37 +08: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 10:20:01 +08:00
|
|
|
|
2019-03-10 20:34:37 +08: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 10:20:01 +08:00
|
|
|
|
2019-03-10 20:34:37 +08: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 10:20:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2012-10-26 11:12:28 +08: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 10:20:01 +08:00
|
|
|
*
|
2012-11-19 09:46:07 +08: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 10:20:01 +08:00
|
|
|
*/
|
2019-03-10 20:34:37 +08: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 10:20:01 +08:00
|
|
|
|
2019-03-10 20:34:37 +08: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 10:20:01 +08:00
|
|
|
|
2019-03-10 20:34:37 +08: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 10:20:01 +08: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 08:50:58 +08:00
|
|
|
* Modify a struct timeval timeout value to render at a fixed pace.
|
2012-10-26 11:12:28 +08: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 08:50:58 +08: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 10:20:01 +08:00
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
static double swopti_handle_timeout(session_t *ps) {
|
|
|
|
if (!ps->refresh_intv)
|
|
|
|
return 0;
|
2018-11-27 00:53:57 +08:00
|
|
|
|
2019-03-10 20:34:37 +08: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 10:20:01 +08:00
|
|
|
|
2019-03-10 20:34:37 +08: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 10:20:01 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
// Add an offset so we wait until the next refresh after timeout
|
|
|
|
return (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 08:50:58 +08:00
|
|
|
}
|
|
|
|
|
2012-10-24 10:09:59 +08:00
|
|
|
/**
|
|
|
|
* Initialize X composite overlay window.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08: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;
|
|
|
|
}
|
|
|
|
if (ps->overlay) {
|
|
|
|
// Set window region of the overlay window, code stolen from
|
|
|
|
// compiz-0.8.8
|
|
|
|
xcb_generic_error_t *e;
|
|
|
|
e = XCB_SYNCED_VOID(xcb_shape_mask, ps->c, XCB_SHAPE_SO_SET,
|
|
|
|
XCB_SHAPE_SK_BOUNDING, ps->overlay, 0, 0, 0);
|
|
|
|
if (e) {
|
|
|
|
log_fatal("Failed to set the bounding shape of overlay, giving "
|
|
|
|
"up.");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
e = XCB_SYNCED_VOID(xcb_shape_rectangles, ps->c, XCB_SHAPE_SO_SET,
|
|
|
|
XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED,
|
|
|
|
ps->overlay, 0, 0, 0, NULL);
|
|
|
|
if (e) {
|
|
|
|
log_fatal("Failed to set the input shape of overlay, giving up.");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
// Unmap overlay, firstly. But this typically does not work because
|
|
|
|
// the window isn't created yet.
|
|
|
|
// xcb_unmap_window(c, ps->overlay);
|
|
|
|
// XFlush(ps->dpy);
|
|
|
|
} else {
|
|
|
|
log_error("Cannot get X Composite overlay window. Falling "
|
|
|
|
"back to painting on root window.");
|
|
|
|
}
|
|
|
|
log_debug("overlay = %#010x", ps->overlay);
|
|
|
|
|
|
|
|
return ps->overlay;
|
2012-10-24 10:09:59 +08:00
|
|
|
}
|
|
|
|
|
2012-11-09 21:44:02 +08:00
|
|
|
/**
|
|
|
|
* Redirect all windows.
|
2019-02-25 08:07:12 +08:00
|
|
|
*
|
|
|
|
* @return whether the operation succeeded or not
|
2012-11-09 21:44:02 +08:00
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
static bool redir_start(session_t *ps) {
|
|
|
|
if (!ps->redirected) {
|
|
|
|
log_debug("Screen redirected.");
|
|
|
|
|
|
|
|
// Map overlay window. Done firstly according to this:
|
|
|
|
// https://bugzilla.gnome.org/show_bug.cgi?id=597014
|
|
|
|
if (ps->overlay) {
|
|
|
|
xcb_map_window(ps->c, ps->overlay);
|
|
|
|
}
|
|
|
|
|
|
|
|
xcb_composite_redirect_subwindows(ps->c, ps->root,
|
|
|
|
XCB_COMPOSITE_REDIRECT_MANUAL);
|
|
|
|
|
|
|
|
x_sync(ps->c);
|
|
|
|
|
2019-03-18 00:08:31 +08:00
|
|
|
if (!initialize_backend(ps)) {
|
|
|
|
return false;
|
2019-03-10 20:34:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ps->o.experimental_backends) {
|
|
|
|
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;
|
|
|
|
|
|
|
|
for (int i = 0; i < ps->ndamage; i++) {
|
|
|
|
pixman_region32_init(&ps->damage_ring[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Must call XSync() here
|
|
|
|
x_sync(ps->c);
|
|
|
|
|
|
|
|
ps->redirected = true;
|
|
|
|
|
|
|
|
root_damaged(ps);
|
|
|
|
|
|
|
|
// Repaint the whole screen
|
|
|
|
force_repaint(ps);
|
|
|
|
}
|
|
|
|
return true;
|
2012-11-09 21:44:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unredirect all windows.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
static void redir_stop(session_t *ps) {
|
|
|
|
if (ps->redirected) {
|
|
|
|
log_debug("Screen unredirected.");
|
2019-03-18 00:08:31 +08:00
|
|
|
|
|
|
|
destroy_backend(ps);
|
2019-03-10 20:34:37 +08:00
|
|
|
|
|
|
|
xcb_composite_unredirect_subwindows(ps->c, ps->root,
|
|
|
|
XCB_COMPOSITE_REDIRECT_MANUAL);
|
|
|
|
// Unmap overlay window
|
|
|
|
if (ps->overlay)
|
|
|
|
xcb_unmap_window(ps->c, ps->overlay);
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
// Must call XSync() here
|
|
|
|
x_sync(ps->c);
|
|
|
|
|
|
|
|
ps->redirected = false;
|
|
|
|
}
|
2012-11-09 21:44:02 +08:00
|
|
|
}
|
|
|
|
|
2018-10-03 03:22:26 +08:00
|
|
|
// Handle queued events before we go to sleep
|
2019-03-10 20:34:37 +08:00
|
|
|
static void handle_queued_x_events(EV_P_ ev_prepare *w, int revents) {
|
|
|
|
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-03 03:22:26 +08:00
|
|
|
}
|
|
|
|
|
2013-09-04 22:00:51 +08:00
|
|
|
/**
|
|
|
|
* Unredirection timeout callback.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
static void tmout_unredir_callback(EV_P_ ev_timer *w, int revents) {
|
|
|
|
session_t *ps = session_ptr(w, unredir_timer);
|
|
|
|
ps->tmout_unredir_hit = true;
|
|
|
|
queue_redraw(ps);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fade_timer_callback(EV_P_ ev_timer *w, int revents) {
|
|
|
|
session_t *ps = session_ptr(w, fade_timer);
|
|
|
|
queue_redraw(ps);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _draw_callback(EV_P_ session_t *ps, int revents) {
|
|
|
|
if (ps->o.benchmark) {
|
|
|
|
if (ps->o.benchmark_wid) {
|
|
|
|
win *wi = find_win(ps, ps->o.benchmark_wid);
|
|
|
|
if (!wi) {
|
|
|
|
log_fatal("Couldn't find specified benchmark window.");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
add_damage_from_win(ps, wi);
|
|
|
|
} else {
|
|
|
|
force_repaint(ps);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-17 23:17:48 +08:00
|
|
|
// TODO xcb_grab_server
|
|
|
|
// TODO clean up event queue
|
|
|
|
|
|
|
|
handle_root_flags(ps);
|
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
bool fade_running = false;
|
|
|
|
win *t = paint_preprocess(ps, &fade_running);
|
|
|
|
ps->tmout_unredir_hit = false;
|
|
|
|
|
|
|
|
// Start/stop fade timer depends on whether window are fading
|
|
|
|
if (!fade_running && ev_is_active(&ps->fade_timer))
|
|
|
|
ev_timer_stop(ps->loop, &ps->fade_timer);
|
|
|
|
else if (fade_running && !ev_is_active(&ps->fade_timer)) {
|
|
|
|
ev_timer_set(&ps->fade_timer, fade_timeout(ps), 0);
|
|
|
|
ev_timer_start(ps->loop, &ps->fade_timer);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the screen is unredirected, free all_damage to stop painting
|
|
|
|
if (ps->redirected && ps->o.stoppaint_force != ON) {
|
|
|
|
static int paint = 0;
|
|
|
|
if (ps->o.experimental_backends) {
|
|
|
|
paint_all_new(ps, t, false);
|
|
|
|
} else {
|
|
|
|
paint_all(ps, t, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
paint++;
|
|
|
|
if (ps->o.benchmark && paint >= ps->o.benchmark)
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!fade_running)
|
|
|
|
ps->fade_time = 0L;
|
|
|
|
|
2019-03-17 23:17:48 +08:00
|
|
|
// TODO xcb_ungrab_server
|
|
|
|
|
2019-03-10 20:34:37 +08: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);
|
|
|
|
|
|
|
|
_draw_callback(EV_A_ ps, revents);
|
|
|
|
|
|
|
|
// Don't do painting non-stop unless we are in benchmark mode
|
|
|
|
if (!ps->o.benchmark)
|
|
|
|
ev_idle_stop(ps->loop, &ps->draw_idle);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void delayed_draw_timer_callback(EV_P_ ev_timer *w, int revents) {
|
|
|
|
session_t *ps = session_ptr(w, delayed_draw_timer);
|
|
|
|
_draw_callback(EV_A_ ps, revents);
|
|
|
|
|
|
|
|
// 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) {
|
|
|
|
ev_idle_stop(ps->loop, &ps->draw_idle);
|
|
|
|
}
|
|
|
|
return _draw_callback(EV_A_ ps, revents);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
ev_idle_stop(ps->loop, &ps->draw_idle);
|
|
|
|
|
|
|
|
ev_timer_set(&ps->delayed_draw_timer, delay, 0);
|
|
|
|
ev_timer_start(ps->loop, &ps->delayed_draw_timer);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x_event_callback(EV_P_ ev_io *w, int revents) {
|
|
|
|
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 08:50:58 +08:00
|
|
|
}
|
|
|
|
|
2018-11-27 07:56:55 +08:00
|
|
|
/**
|
|
|
|
* Turn on the program reset flag.
|
|
|
|
*
|
|
|
|
* This will result in compton resetting itself after next paint.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
static void reset_enable(EV_P_ ev_signal *w, int revents) {
|
|
|
|
session_t *ps = session_ptr(w, usr1_signal);
|
|
|
|
log_info("compton is resetting...");
|
|
|
|
ev_break(ps->loop, EVBREAK_ALL);
|
2019-02-12 07:13:39 +08:00
|
|
|
}
|
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
static void exit_enable(EV_P_ ev_signal *w, int revents) {
|
|
|
|
session_t *ps = session_ptr(w, int_signal);
|
|
|
|
log_info("compton is quitting...");
|
|
|
|
ps->quit = true;
|
|
|
|
ev_break(ps->loop, EVBREAK_ALL);
|
2018-11-27 07:56:55 +08:00
|
|
|
}
|
|
|
|
|
2012-11-19 09:46:07 +08:00
|
|
|
/**
|
|
|
|
* Initialize a session.
|
|
|
|
*
|
|
|
|
* @param argc number of commandline arguments
|
|
|
|
* @param argv commandline arguments
|
2019-02-08 09:27:46 +08: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 09:46:07 +08:00
|
|
|
*/
|
2019-03-10 20:34:37 +08: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-22 00:25:28 +08:00
|
|
|
#ifdef CONFIG_OPENGL
|
2019-03-10 20:34:37 +08:00
|
|
|
.glx_prog_win = GLX_PROG_MAIN_INIT,
|
2018-12-22 00:25:28 +08:00
|
|
|
#endif
|
2019-03-10 20:34:37 +08:00
|
|
|
.o =
|
|
|
|
{
|
|
|
|
.backend = BKEND_XRENDER,
|
|
|
|
.glx_no_stencil = false,
|
|
|
|
.mark_wmwin_focused = false,
|
|
|
|
.mark_ovredir_focused = false,
|
|
|
|
.detect_rounded_corners = false,
|
|
|
|
.resize_damage = 0,
|
|
|
|
.unredir_if_possible = false,
|
|
|
|
.unredir_if_possible_blacklist = NULL,
|
|
|
|
.unredir_if_possible_delay = 0,
|
|
|
|
.redirected_force = UNSET,
|
|
|
|
.stoppaint_force = UNSET,
|
|
|
|
.dbus = false,
|
|
|
|
.benchmark = 0,
|
|
|
|
.benchmark_wid = XCB_NONE,
|
|
|
|
.logpath = NULL,
|
|
|
|
|
|
|
|
.refresh_rate = 0,
|
|
|
|
.sw_opti = false,
|
|
|
|
|
|
|
|
.shadow_red = 0.0,
|
|
|
|
.shadow_green = 0.0,
|
|
|
|
.shadow_blue = 0.0,
|
|
|
|
.shadow_radius = 18,
|
|
|
|
.shadow_offset_x = -15,
|
|
|
|
.shadow_offset_y = -15,
|
|
|
|
.shadow_opacity = .75,
|
|
|
|
.shadow_blacklist = NULL,
|
|
|
|
.shadow_ignore_shaped = false,
|
|
|
|
.respect_prop_shadow = false,
|
|
|
|
.xinerama_shadow_crop = false,
|
|
|
|
|
|
|
|
.fade_in_step = 0.028,
|
|
|
|
.fade_out_step = 0.03,
|
|
|
|
.fade_delta = 10,
|
|
|
|
.no_fading_openclose = false,
|
|
|
|
.no_fading_destroyed_argb = false,
|
|
|
|
.fade_blacklist = NULL,
|
|
|
|
|
|
|
|
.inactive_opacity = 1.0,
|
|
|
|
.inactive_opacity_override = false,
|
|
|
|
.active_opacity = 1.0,
|
|
|
|
.frame_opacity = 1.0,
|
|
|
|
.detect_client_opacity = false,
|
|
|
|
|
|
|
|
.blur_background = false,
|
|
|
|
.blur_background_frame = false,
|
|
|
|
.blur_background_fixed = false,
|
|
|
|
.blur_background_blacklist = NULL,
|
|
|
|
.blur_kerns = {NULL},
|
|
|
|
.inactive_dim = 0.0,
|
|
|
|
.inactive_dim_fixed = false,
|
|
|
|
.invert_color_list = NULL,
|
|
|
|
.opacity_rules = NULL,
|
|
|
|
|
|
|
|
.use_ewmh_active_win = false,
|
|
|
|
.focus_blacklist = NULL,
|
|
|
|
.detect_transient = false,
|
|
|
|
.detect_client_leader = false,
|
|
|
|
|
|
|
|
.track_focus = false,
|
|
|
|
.track_wdata = false,
|
|
|
|
.track_leader = false,
|
|
|
|
},
|
|
|
|
|
|
|
|
.time_start = {0, 0},
|
|
|
|
.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,
|
|
|
|
|
|
|
|
.list = NULL,
|
|
|
|
.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 09:46:07 +08: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 08:50:58 +08:00
|
|
|
#ifdef CONFIG_VSYNC_DRM
|
2019-03-10 20:34:37 +08: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 08:50:58 +08:00
|
|
|
#endif
|
2012-11-19 09:46:07 +08:00
|
|
|
|
2019-03-10 20:34:37 +08: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,
|
2018-08-22 22:12:29 +08:00
|
|
|
#ifdef CONFIG_OPENGL
|
2019-03-10 20:34:37 +08:00
|
|
|
.glx_exists = false,
|
|
|
|
.glx_event = 0,
|
|
|
|
.glx_error = 0,
|
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 08:50:58 +08:00
|
|
|
#endif
|
2019-03-10 20:34:37 +08:00
|
|
|
.xrfilter_convolution_exists = false,
|
|
|
|
|
|
|
|
.atom_opacity = XCB_NONE,
|
|
|
|
.atom_frame_extents = XCB_NONE,
|
|
|
|
.atom_client = XCB_NONE,
|
|
|
|
.atom_name = XCB_NONE,
|
|
|
|
.atom_name_ewmh = XCB_NONE,
|
|
|
|
.atom_class = XCB_NONE,
|
|
|
|
.atom_role = XCB_NONE,
|
|
|
|
.atom_transient = XCB_NONE,
|
|
|
|
.atom_ewmh_active_win = XCB_NONE,
|
|
|
|
.atom_compton_shadow = XCB_NONE,
|
|
|
|
.atom_win_type = XCB_NONE,
|
|
|
|
.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 20:20:27 +08:00
|
|
|
|
|
|
|
#ifdef CONFIG_DBUS
|
2019-03-10 20:34:37 +08: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 20:20:27 +08:00
|
|
|
#endif
|
2019-03-10 20:34:37 +08: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;
|
|
|
|
ps->loop = EV_DEFAULT;
|
|
|
|
pixman_region32_init(&ps->screen_reg);
|
|
|
|
|
|
|
|
ps->ignore_tail = &ps->ignore_head;
|
|
|
|
gettimeofday(&ps->time_start, NULL);
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
XSetErrorHandler(xerror);
|
|
|
|
|
|
|
|
ps->scr = DefaultScreen(ps->dpy);
|
|
|
|
ps->root = RootWindow(ps->dpy, ps->scr);
|
|
|
|
|
|
|
|
ps->vis = XVisualIDFromVisual(DefaultVisual(ps->dpy, ps->scr));
|
|
|
|
ps->depth = DefaultDepth(ps->dpy, ps->scr);
|
|
|
|
|
|
|
|
// 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) {
|
|
|
|
log_error("Failed to setup root window event mask");
|
|
|
|
free(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
ps->root_width = DisplayWidth(ps->dpy, ps->scr);
|
|
|
|
ps->root_height = DisplayHeight(ps->dpy, ps->scr);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
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, "
|
|
|
|
"compton cannot run.");
|
|
|
|
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);
|
|
|
|
|
|
|
|
// 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
|
|
|
|
get_cfg(&ps->o, argc, argv, shadow_enabled, fading_enable, hasneg, winopt_mask);
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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) &&
|
|
|
|
c2_list_postprocess(ps, ps->o.focus_blacklist))) {
|
|
|
|
log_error("Post-processing of conditionals failed, some of your rules "
|
|
|
|
"might not work");
|
|
|
|
}
|
|
|
|
|
|
|
|
ps->gaussian_map = gaussian_kernel(ps->o.shadow_radius);
|
|
|
|
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;
|
|
|
|
if (!ps->xsync_exists && ps->o.xrender_sync_fence) {
|
|
|
|
log_error("XSync extension not found. No XSync fence sync is "
|
|
|
|
"possible. (xrender-sync-fence can't be enabled)");
|
|
|
|
ps->o.xrender_sync_fence = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ps->o.xrender_sync_fence) {
|
|
|
|
ps->sync_fence = xcb_generate_id(ps->c);
|
|
|
|
e = xcb_request_check(
|
|
|
|
ps->c, xcb_sync_create_fence(ps->c, ps->root, ps->sync_fence, 0));
|
|
|
|
if (e) {
|
|
|
|
log_error("Failed to create a XSync fence. xrender-sync-fence "
|
|
|
|
"will be disabled");
|
|
|
|
ps->o.xrender_sync_fence = false;
|
|
|
|
ps->sync_fence = XCB_NONE;
|
|
|
|
free(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
// Overlay must be initialized before double buffer, and before creation
|
|
|
|
// of OpenGL context.
|
|
|
|
init_overlay(ps);
|
|
|
|
|
|
|
|
// 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) {
|
|
|
|
print_diagnostics(ps, config_file);
|
|
|
|
free(config_file_to_free);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
free(config_file_to_free);
|
|
|
|
|
|
|
|
if (bkend_use_glx(ps) && !ps->o.experimental_backends) {
|
|
|
|
auto glx_logger = glx_string_marker_logger_new();
|
|
|
|
if (glx_logger) {
|
|
|
|
log_info("Enabling gl string marker");
|
|
|
|
log_add_target_tls(glx_logger);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
// Create registration window
|
|
|
|
if (!ps->reg_win && !register_cm(ps))
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
init_atoms(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);
|
|
|
|
|
|
|
|
xcb_grab_server(ps->c);
|
|
|
|
|
|
|
|
// Initialize DBus. We need to do this early, because add_win might call dbus
|
|
|
|
// functions
|
|
|
|
if (ps->o.dbus) {
|
2018-12-21 06:31:34 +08:00
|
|
|
#ifdef CONFIG_DBUS
|
2019-03-10 20:34:37 +08:00
|
|
|
cdbus_init(ps, DisplayString(ps->dpy));
|
|
|
|
if (!ps->dbus_data) {
|
|
|
|
ps->o.dbus = false;
|
|
|
|
}
|
2018-12-21 06:31:34 +08:00
|
|
|
#else
|
2019-03-10 20:34:37 +08:00
|
|
|
log_fatal("DBus support not compiled in!");
|
|
|
|
exit(1);
|
2018-12-21 06:31:34 +08:00
|
|
|
#endif
|
2019-03-10 20:34:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
xcb_window_t *children;
|
|
|
|
int nchildren;
|
|
|
|
|
|
|
|
xcb_query_tree_reply_t *reply =
|
|
|
|
xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, ps->root), NULL);
|
|
|
|
|
|
|
|
if (reply) {
|
|
|
|
children = xcb_query_tree_children(reply);
|
|
|
|
nchildren = xcb_query_tree_children_length(reply);
|
|
|
|
} else {
|
|
|
|
children = NULL;
|
|
|
|
nchildren = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < nchildren; i++) {
|
|
|
|
add_win(ps, children[i], i ? children[i - 1] : XCB_NONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (win *i = ps->list; i; i = i->next) {
|
|
|
|
if (i->a.map_state == XCB_MAP_STATE_VIEWABLE) {
|
|
|
|
map_win(ps, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(reply);
|
|
|
|
log_trace("Initial stack:");
|
|
|
|
for (win *c = ps->list; c; c = c->next) {
|
|
|
|
log_trace("%#010x \"%s\"", c->id, c->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ps->o.track_focus) {
|
|
|
|
recheck_focus(ps);
|
|
|
|
}
|
|
|
|
|
|
|
|
e = xcb_request_check(ps->c, xcb_ungrab_server(ps->c));
|
|
|
|
if (e) {
|
|
|
|
log_error("Failed to ungrad server");
|
|
|
|
free(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
write_pid(ps);
|
|
|
|
|
|
|
|
if (fork && stderr_logger) {
|
|
|
|
// Remove the stderr logger if we will fork
|
|
|
|
log_remove_target_tls(stderr_logger);
|
|
|
|
}
|
|
|
|
return ps;
|
2012-11-19 09:46:07 +08: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 20:34:37 +08:00
|
|
|
static void session_destroy(session_t *ps) {
|
|
|
|
redir_stop(ps);
|
2012-11-19 09:46:07 +08:00
|
|
|
|
2019-03-10 20:34:37 +08: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 14:33:23 +08: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 20:20:27 +08:00
|
|
|
#ifdef CONFIG_DBUS
|
2019-03-10 20:34:37 +08: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 20:20:27 +08:00
|
|
|
#endif
|
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
// Free window linked list
|
|
|
|
{
|
|
|
|
win *next = NULL;
|
|
|
|
win *list = ps->list;
|
|
|
|
ps->list = NULL;
|
|
|
|
|
|
|
|
for (win *w = list; w; w = next) {
|
|
|
|
next = w->next;
|
|
|
|
|
|
|
|
if (w->state != WSTATE_DESTROYING) {
|
|
|
|
win_ev_stop(ps, w);
|
|
|
|
}
|
|
|
|
|
|
|
|
free_win_res(ps, w);
|
|
|
|
free(w);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
|
|
|
free(ps->o.blur_kerns[i]);
|
|
|
|
free(ps->blur_kerns_cache[i]);
|
|
|
|
}
|
|
|
|
free(ps->o.glx_fshader_win_str);
|
|
|
|
free_xinerama_info(ps);
|
2012-11-19 09:46:07 +08: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 08:50:58 +08:00
|
|
|
#ifdef CONFIG_VSYNC_DRM
|
2019-03-10 20:34:37 +08: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 08:50:58 +08:00
|
|
|
#endif
|
2012-11-19 09:46:07 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
// Release overlay window
|
|
|
|
if (ps->overlay) {
|
|
|
|
xcb_composite_release_overlay_window(ps->c, ps->overlay);
|
|
|
|
ps->overlay = XCB_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ps->sync_fence) {
|
|
|
|
xcb_sync_destroy_fence(ps->c, ps->sync_fence);
|
|
|
|
ps->sync_fence = XCB_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Free reg_win
|
|
|
|
if (ps->reg_win) {
|
|
|
|
xcb_destroy_window(ps->c, ps->reg_win);
|
|
|
|
ps->reg_win = XCB_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ps->o.experimental_backends) {
|
|
|
|
// backend is deinitialized in redir_stop
|
|
|
|
assert(ps->backend_data == NULL);
|
|
|
|
} else {
|
|
|
|
deinit_render(ps);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Flush all events
|
|
|
|
x_sync(ps->c);
|
|
|
|
ev_io_stop(ps->loop, &ps->xiow);
|
|
|
|
free_conv(ps->gaussian_map);
|
2012-11-19 09:46:07 +08:00
|
|
|
|
2014-08-03 19:40:40 +08:00
|
|
|
#ifdef DEBUG_XRC
|
2019-03-10 20:34:37 +08:00
|
|
|
// Report about resource leakage
|
|
|
|
xrc_report_xid();
|
2014-08-03 19:40:40 +08:00
|
|
|
#endif
|
|
|
|
|
2019-03-10 20:34:37 +08: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);
|
2018-11-27 07:56:55 +08:00
|
|
|
|
2019-03-10 20:34:37 +08:00
|
|
|
log_deinit_tls();
|
2012-11-19 09:46:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Do the actual work.
|
|
|
|
*
|
|
|
|
* @param ps current session
|
|
|
|
*/
|
2019-03-10 20:34:37 +08: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 15:08:23 +08:00
|
|
|
}
|
2012-11-19 09:46:07 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The function that everybody knows.
|
|
|
|
*/
|
2019-03-10 20:34:37 +08:00
|
|
|
int main(int argc, char **argv) {
|
|
|
|
// Set locale so window names with special characters are interpreted
|
|
|
|
// correctly
|
|
|
|
setlocale(LC_ALL, "");
|
2019-03-22 06:37:35 +08:00
|
|
|
log_init_tls();
|
2019-03-10 20:34:37 +08: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;
|
|
|
|
Display *dpy = XOpenDisplay(NULL);
|
|
|
|
if (!dpy) {
|
2019-03-22 06:37:35 +08:00
|
|
|
fprintf(stderr, "Can't open display.");
|
2019-03-10 20:34:37 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
XSetEventQueueOwner(dpy, XCBOwnsEventQueue);
|
|
|
|
|
|
|
|
do {
|
|
|
|
ps_g = session_init(argc, argv, dpy, config_file, all_xerrors, need_fork);
|
|
|
|
if (!ps_g) {
|
|
|
|
log_fatal("Failed to create new compton session.");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (need_fork) {
|
|
|
|
// Finishing up daemonization
|
|
|
|
// Close files
|
|
|
|
if (fclose(stdout) || fclose(stderr) || fclose(stdin)) {
|
|
|
|
log_fatal("Failed to close standard input/output");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
// 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;
|
|
|
|
session_destroy(ps_g);
|
|
|
|
free(ps_g);
|
|
|
|
ps_g = NULL;
|
|
|
|
} while (!quit);
|
|
|
|
|
|
|
|
if (dpy) {
|
|
|
|
XCloseDisplay(dpy);
|
|
|
|
}
|
|
|
|
free(config_file);
|
|
|
|
|
|
|
|
return 0;
|
2012-11-19 09:46:07 +08:00
|
|
|
}
|