Use libev for inputs and timeouts
Bugs: * There seems to be a noticeable frame loss when window is being opened/closed. But the same problem also exists in master/next, so this is not a regression. * Using --sw-opti and --benchmark at the same time causing compton to draw more frequently than permitted by the arguments. That is because the sleep interval calculation is flawed. Not really a regression either. Verified still working: * Usual painting * Fade * Benchmark mode * --sw-opti (with or without benchmark mode) * DBus * Unredir delay Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
e58de49d7a
commit
2a4fed50f4
2
Makefile
2
Makefile
|
@ -10,7 +10,7 @@ APPDIR ?= $(PREFIX)/share/applications
|
||||||
ICODIR ?= $(PREFIX)/share/icons/hicolor/
|
ICODIR ?= $(PREFIX)/share/icons/hicolor/
|
||||||
|
|
||||||
PACKAGES = x11 x11-xcb xcb-renderutil xcb-render xcb-damage xcb-randr xcb-composite xcb-shape xcb-image xcb-xfixes xext pixman-1
|
PACKAGES = x11 x11-xcb xcb-renderutil xcb-render xcb-damage xcb-randr xcb-composite xcb-shape xcb-image xcb-xfixes xext pixman-1
|
||||||
LIBS = -lm -lrt
|
LIBS = -lm -lrt -lev
|
||||||
INCS =
|
INCS =
|
||||||
|
|
||||||
OBJS = compton.o config.o win.o x.o
|
OBJS = compton.o config.o win.o x.o
|
||||||
|
|
118
src/common.h
118
src/common.h
|
@ -94,6 +94,7 @@
|
||||||
#ifdef CONFIG_XINERAMA
|
#ifdef CONFIG_XINERAMA
|
||||||
#include <xcb/xinerama.h>
|
#include <xcb/xinerama.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <ev.h>
|
||||||
#include <pixman.h>
|
#include <pixman.h>
|
||||||
|
|
||||||
// libdbus
|
// libdbus
|
||||||
|
@ -180,7 +181,6 @@
|
||||||
#define TIME_MS_MAX LONG_MAX
|
#define TIME_MS_MAX LONG_MAX
|
||||||
#define FADE_DELTA_TOLERANCE 0.2
|
#define FADE_DELTA_TOLERANCE 0.2
|
||||||
#define SWOPTI_TOLERANCE 3000
|
#define SWOPTI_TOLERANCE 3000
|
||||||
#define TIMEOUT_RUN_TOLERANCE 0.05
|
|
||||||
#define WIN_GET_LEADER_MAX_RECURSION 20
|
#define WIN_GET_LEADER_MAX_RECURSION 20
|
||||||
|
|
||||||
#define SEC_WRAP (15L * 24L * 60L * 60L)
|
#define SEC_WRAP (15L * 24L * 60L * 60L)
|
||||||
|
@ -504,9 +504,10 @@ typedef struct _latom {
|
||||||
|
|
||||||
#define REG_DATA_INIT { NULL, 0 }
|
#define REG_DATA_INIT { NULL, 0 }
|
||||||
|
|
||||||
struct _timeout_t;
|
|
||||||
|
|
||||||
typedef struct win win;
|
typedef struct win win;
|
||||||
|
typedef struct ev_session_timer ev_session_timer;
|
||||||
|
typedef struct ev_session_idle ev_session_idle;
|
||||||
|
typedef struct ev_session_prepare ev_session_prepare;
|
||||||
|
|
||||||
/// Structure representing all options.
|
/// Structure representing all options.
|
||||||
typedef struct options_t {
|
typedef struct options_t {
|
||||||
|
@ -764,6 +765,10 @@ typedef struct {
|
||||||
|
|
||||||
/// Structure containing all necessary data for a compton session.
|
/// Structure containing all necessary data for a compton session.
|
||||||
typedef struct session {
|
typedef struct session {
|
||||||
|
/// ev_io for X connection
|
||||||
|
ev_io xiow;
|
||||||
|
/// libev mainloop
|
||||||
|
struct ev_loop *loop;
|
||||||
// === Display related ===
|
// === Display related ===
|
||||||
/// Display in use.
|
/// Display in use.
|
||||||
Display *dpy;
|
Display *dpy;
|
||||||
|
@ -813,25 +818,27 @@ typedef struct session {
|
||||||
// === Operation related ===
|
// === Operation related ===
|
||||||
/// Program options.
|
/// Program options.
|
||||||
options_t o;
|
options_t o;
|
||||||
/// File descriptors to check for reading.
|
|
||||||
fd_set *pfds_read;
|
|
||||||
/// File descriptors to check for writing.
|
|
||||||
fd_set *pfds_write;
|
|
||||||
/// File descriptors to check for exceptions.
|
|
||||||
fd_set *pfds_except;
|
|
||||||
/// Largest file descriptor in fd_set-s above.
|
|
||||||
int nfds_max;
|
|
||||||
/// Linked list of all timeouts.
|
|
||||||
struct _timeout_t *tmout_lst;
|
|
||||||
/// Timeout for delayed unredirection.
|
/// Timeout for delayed unredirection.
|
||||||
struct _timeout_t *tmout_unredir;
|
ev_session_timer *unredir_timer;
|
||||||
|
/// Timer for fading
|
||||||
|
ev_session_timer *fade_timer;
|
||||||
|
/// Timer for delayed drawing, right now only used by
|
||||||
|
/// swopti
|
||||||
|
ev_session_timer *delayed_draw_timer;
|
||||||
|
/// Use an ev_idle callback for drawing
|
||||||
|
/// So we only start drawing when events are processed
|
||||||
|
ev_session_idle *draw_idle;
|
||||||
|
/// Called everytime we have timeouts or new data on socket,
|
||||||
|
/// so we can be sure if xcb read from X socket at anytime during event
|
||||||
|
/// handling, we will not left any event unhandled in the queue
|
||||||
|
ev_session_prepare *event_check;
|
||||||
/// Whether we have hit unredirection timeout.
|
/// Whether we have hit unredirection timeout.
|
||||||
bool tmout_unredir_hit;
|
bool tmout_unredir_hit;
|
||||||
/// Whether we have received an event in this cycle.
|
/// Whether we need to redraw the screen
|
||||||
bool ev_received;
|
bool redraw_needed;
|
||||||
/// Whether the program is idling. I.e. no fading, no potential window
|
/// Whether the program is idling. I.e. no fading, no potential window
|
||||||
/// changes.
|
/// changes.
|
||||||
bool idling;
|
bool fade_running;
|
||||||
/// Program start time.
|
/// Program start time.
|
||||||
struct timeval time_start;
|
struct timeval time_start;
|
||||||
/// The region needs to painted on next paint.
|
/// The region needs to painted on next paint.
|
||||||
|
@ -853,6 +860,8 @@ typedef struct session {
|
||||||
xcb_render_fixed_t *blur_kerns_cache[MAX_BLUR_PASS];
|
xcb_render_fixed_t *blur_kerns_cache[MAX_BLUR_PASS];
|
||||||
/// Reset program after next paint.
|
/// Reset program after next paint.
|
||||||
bool reset;
|
bool reset;
|
||||||
|
/// If compton should quit
|
||||||
|
bool quit;
|
||||||
|
|
||||||
// === Expose event related ===
|
// === Expose event related ===
|
||||||
/// Pointer to an array of <code>XRectangle</code>-s of exposed region.
|
/// Pointer to an array of <code>XRectangle</code>-s of exposed region.
|
||||||
|
@ -1206,17 +1215,6 @@ struct options_tmp {
|
||||||
double menu_opacity;
|
double menu_opacity;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Structure for a recorded timeout.
|
|
||||||
typedef struct _timeout_t {
|
|
||||||
bool enabled;
|
|
||||||
void *data;
|
|
||||||
bool (*callback)(session_t *ps, struct _timeout_t *ptmout);
|
|
||||||
time_ms_t interval;
|
|
||||||
time_ms_t firstrun;
|
|
||||||
time_ms_t lastrun;
|
|
||||||
struct _timeout_t *next;
|
|
||||||
} timeout_t;
|
|
||||||
|
|
||||||
/// Enumeration for window event hints.
|
/// Enumeration for window event hints.
|
||||||
typedef enum {
|
typedef enum {
|
||||||
WIN_EVMODE_UNKNOWN,
|
WIN_EVMODE_UNKNOWN,
|
||||||
|
@ -1453,7 +1451,7 @@ print_timestamp(session_t *ps) {
|
||||||
if (gettimeofday(&tm, NULL)) return;
|
if (gettimeofday(&tm, NULL)) return;
|
||||||
|
|
||||||
timeval_subtract(&diff, &tm, &ps->time_start);
|
timeval_subtract(&diff, &tm, &ps->time_start);
|
||||||
fprintf(stderr, "[ %5ld.%02ld ] ", diff.tv_sec, diff.tv_usec / 10000);
|
fprintf(stderr, "[ %5ld.%06ld ] ", diff.tv_sec, diff.tv_usec);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1684,68 +1682,6 @@ parse_glx_swap_method(session_t *ps, const char *str) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout_t *
|
|
||||||
timeout_insert(session_t *ps, time_ms_t interval,
|
|
||||||
bool (*callback)(session_t *ps, timeout_t *ptmout), void *data);
|
|
||||||
|
|
||||||
void
|
|
||||||
timeout_invoke(session_t *ps, timeout_t *ptmout);
|
|
||||||
|
|
||||||
bool
|
|
||||||
timeout_drop(session_t *ps, timeout_t *prm);
|
|
||||||
|
|
||||||
void
|
|
||||||
timeout_reset(session_t *ps, timeout_t *ptmout);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a file descriptor to a select() fd_set.
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
fds_insert_select(fd_set **ppfds, int fd) {
|
|
||||||
assert(fd <= FD_SETSIZE);
|
|
||||||
|
|
||||||
if (!*ppfds) {
|
|
||||||
if ((*ppfds = malloc(sizeof(fd_set)))) {
|
|
||||||
FD_ZERO(*ppfds);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "Failed to allocate memory for select() fdset.\n");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FD_SET(fd, *ppfds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a new file descriptor to wait for.
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
fds_insert(session_t *ps, int fd, short events) {
|
|
||||||
ps->nfds_max = max_i(fd + 1, ps->nfds_max);
|
|
||||||
|
|
||||||
if (POLLIN & events)
|
|
||||||
fds_insert_select(&ps->pfds_read, fd);
|
|
||||||
if (POLLOUT & events)
|
|
||||||
fds_insert_select(&ps->pfds_write, fd);
|
|
||||||
if (POLLPRI & events)
|
|
||||||
fds_insert_select(&ps->pfds_except, fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a file descriptor to wait for.
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
fds_drop(session_t *ps, int fd, short events) {
|
|
||||||
// Drop fd from respective fd_set-s
|
|
||||||
if (POLLIN & events && ps->pfds_read)
|
|
||||||
FD_CLR(fd, ps->pfds_read);
|
|
||||||
if (POLLOUT & events && ps->pfds_write)
|
|
||||||
FD_CLR(fd, ps->pfds_write);
|
|
||||||
if (POLLPRI & events && ps->pfds_except)
|
|
||||||
FD_CLR(fd, ps->pfds_except);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper of XFree() for convenience.
|
* Wrapper of XFree() for convenience.
|
||||||
*
|
*
|
||||||
|
|
632
src/compton.c
632
src/compton.c
|
@ -15,6 +15,8 @@
|
||||||
#include <xcb/render.h>
|
#include <xcb/render.h>
|
||||||
#include <xcb/xcb_image.h>
|
#include <xcb/xcb_image.h>
|
||||||
|
|
||||||
|
#include <ev.h>
|
||||||
|
|
||||||
#include "compton.h"
|
#include "compton.h"
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
#include "opengl.h"
|
#include "opengl.h"
|
||||||
|
@ -38,9 +40,6 @@ update_refresh_rate(session_t *ps);
|
||||||
static bool
|
static bool
|
||||||
swopti_init(session_t *ps);
|
swopti_init(session_t *ps);
|
||||||
|
|
||||||
static void
|
|
||||||
swopti_handle_timeout(session_t *ps, struct timeval *ptv);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cxinerama_upd_scrs(session_t *ps);
|
cxinerama_upd_scrs(session_t *ps);
|
||||||
|
|
||||||
|
@ -113,6 +112,24 @@ restack_win(session_t *ps, win *w, Window new_above);
|
||||||
static void
|
static void
|
||||||
update_ewmh_active_win(session_t *ps);
|
update_ewmh_active_win(session_t *ps);
|
||||||
|
|
||||||
|
static void
|
||||||
|
draw_callback(EV_P_ ev_idle *w, int revents);
|
||||||
|
|
||||||
|
typedef struct ev_session_timer {
|
||||||
|
ev_timer w;
|
||||||
|
session_t *ps;
|
||||||
|
} ev_session_timer;
|
||||||
|
|
||||||
|
typedef struct ev_session_idle {
|
||||||
|
ev_idle w;
|
||||||
|
session_t *ps;
|
||||||
|
} ev_session_idle;
|
||||||
|
|
||||||
|
typedef struct ev_session_prepare {
|
||||||
|
ev_prepare w;
|
||||||
|
session_t *ps;
|
||||||
|
} ev_session_prepare;
|
||||||
|
|
||||||
// === Global constants ===
|
// === Global constants ===
|
||||||
|
|
||||||
/// Name strings for window types.
|
/// Name strings for window types.
|
||||||
|
@ -214,6 +231,13 @@ set_tgt_clip(session_t *ps, region_t *reg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void queue_redraw(session_t *ps) {
|
||||||
|
// If --benchmark is used, redraw is always queued
|
||||||
|
if (!ps->redraw_needed && !ps->o.benchmark)
|
||||||
|
ev_idle_start(ps->loop, &ps->draw_idle->w);
|
||||||
|
ps->redraw_needed = true;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
paint_region(session_t *ps, win *w, int x, int y, int wid, int hei,
|
paint_region(session_t *ps, win *w, int x, int y, int wid, int hei,
|
||||||
double opacity, const region_t *reg_paint, xcb_render_picture_t pict) {
|
double opacity, const region_t *reg_paint, xcb_render_picture_t pict) {
|
||||||
|
@ -281,40 +305,6 @@ void add_damage(session_t *ps, const region_t *damage) {
|
||||||
pixman_region32_union(&ps->all_damage, &ps->all_damage, (region_t *)damage);
|
pixman_region32_union(&ps->all_damage, &ps->all_damage, (region_t *)damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CPY_FDS(key) \
|
|
||||||
fd_set * key = NULL; \
|
|
||||||
if (ps->key) { \
|
|
||||||
key = malloc(sizeof(fd_set)); \
|
|
||||||
memcpy(key, ps->key, sizeof(fd_set)); \
|
|
||||||
if (!key) { \
|
|
||||||
fprintf(stderr, "Failed to allocate memory for copying select() fdset.\n"); \
|
|
||||||
exit(1); \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Poll for changes.
|
|
||||||
*
|
|
||||||
* poll() is much better than select(), but ppoll() does not exist on
|
|
||||||
* *BSD.
|
|
||||||
*/
|
|
||||||
static inline int
|
|
||||||
fds_poll(session_t *ps, struct timeval *ptv) {
|
|
||||||
// Copy fds
|
|
||||||
CPY_FDS(pfds_read);
|
|
||||||
CPY_FDS(pfds_write);
|
|
||||||
CPY_FDS(pfds_except);
|
|
||||||
|
|
||||||
int ret = select(ps->nfds_max, pfds_read, pfds_write, pfds_except, ptv);
|
|
||||||
|
|
||||||
free(pfds_read);
|
|
||||||
free(pfds_write);
|
|
||||||
free(pfds_except);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#undef CPY_FDS
|
|
||||||
|
|
||||||
// === Fading ===
|
// === Fading ===
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -322,13 +312,13 @@ fds_poll(session_t *ps, struct timeval *ptv) {
|
||||||
*
|
*
|
||||||
* In milliseconds.
|
* In milliseconds.
|
||||||
*/
|
*/
|
||||||
static int
|
static double
|
||||||
fade_timeout(session_t *ps) {
|
fade_timeout(session_t *ps) {
|
||||||
int diff = ps->o.fade_delta - get_time_ms() + ps->fade_time;
|
int diff = ps->o.fade_delta - get_time_ms() + ps->fade_time;
|
||||||
|
|
||||||
diff = normalize_i_range(diff, 0, ps->o.fade_delta * 2);
|
diff = normalize_i_range(diff, 0, ps->o.fade_delta * 2);
|
||||||
|
|
||||||
return diff;
|
return diff / 1000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -359,7 +349,7 @@ run_fade(session_t *ps, win *w, unsigned steps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (w->opacity != w->opacity_tgt) {
|
if (w->opacity != w->opacity_tgt) {
|
||||||
ps->idling = false;
|
ps->fade_running = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,6 +357,9 @@ run_fade(session_t *ps, win *w, unsigned steps) {
|
||||||
* Set fade callback of a window, and possibly execute the previous
|
* Set fade callback of a window, and possibly execute the previous
|
||||||
* callback.
|
* callback.
|
||||||
*
|
*
|
||||||
|
* If a callback can cause rendering result to change, it should call
|
||||||
|
* `queue_redraw`.
|
||||||
|
*
|
||||||
* @param exec_callback whether the previous callback is to be executed
|
* @param exec_callback whether the previous callback is to be executed
|
||||||
*/
|
*/
|
||||||
void set_fade_callback(session_t *ps, win **_w,
|
void set_fade_callback(session_t *ps, win **_w,
|
||||||
|
@ -376,12 +369,8 @@ void set_fade_callback(session_t *ps, win **_w,
|
||||||
|
|
||||||
w->fade_callback = callback;
|
w->fade_callback = callback;
|
||||||
// Must be the last line as the callback could destroy w!
|
// Must be the last line as the callback could destroy w!
|
||||||
if (exec_callback && old_callback) {
|
if (exec_callback && old_callback)
|
||||||
old_callback(ps, _w);
|
old_callback(ps, _w);
|
||||||
// Although currently no callback function affects window state on
|
|
||||||
// next paint, it could, in the future
|
|
||||||
ps->idling = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1228,14 +1217,15 @@ paint_preprocess(session_t *ps, win *list) {
|
||||||
if (ps->redirected) {
|
if (ps->redirected) {
|
||||||
if (!ps->o.unredir_if_possible_delay || ps->tmout_unredir_hit)
|
if (!ps->o.unredir_if_possible_delay || ps->tmout_unredir_hit)
|
||||||
redir_stop(ps);
|
redir_stop(ps);
|
||||||
else if (!ps->tmout_unredir->enabled) {
|
else if (!ev_is_active(&ps->unredir_timer->w)) {
|
||||||
timeout_reset(ps, ps->tmout_unredir);
|
ev_timer_set(&ps->unredir_timer->w,
|
||||||
ps->tmout_unredir->enabled = true;
|
ps->o.unredir_if_possible_delay / 1000.0, 0);
|
||||||
|
ev_timer_start(ps->loop, &ps->unredir_timer->w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ps->tmout_unredir->enabled = false;
|
ev_timer_stop(ps->loop, &ps->unredir_timer->w);
|
||||||
redir_start(ps);
|
redir_start(ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2466,7 +2456,7 @@ expose_root(session_t *ps, const rect_t *rects, int nrects) {
|
||||||
void
|
void
|
||||||
force_repaint(session_t *ps) {
|
force_repaint(session_t *ps) {
|
||||||
assert(pixman_region32_not_empty(&ps->screen_reg));
|
assert(pixman_region32_not_empty(&ps->screen_reg));
|
||||||
ps->ev_received = true;
|
queue_redraw(ps);
|
||||||
add_damage(ps, &ps->screen_reg);
|
add_damage(ps, &ps->screen_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2483,7 +2473,7 @@ win_set_shadow_force(session_t *ps, win *w, switch_t val) {
|
||||||
if (val != w->shadow_force) {
|
if (val != w->shadow_force) {
|
||||||
w->shadow_force = val;
|
w->shadow_force = val;
|
||||||
win_determine_shadow(ps, w);
|
win_determine_shadow(ps, w);
|
||||||
ps->ev_received = true;
|
queue_redraw(ps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2495,7 +2485,7 @@ win_set_fade_force(session_t *ps, win *w, switch_t val) {
|
||||||
if (val != w->fade_force) {
|
if (val != w->fade_force) {
|
||||||
w->fade_force = val;
|
w->fade_force = val;
|
||||||
win_determine_fade(ps, w);
|
win_determine_fade(ps, w);
|
||||||
ps->ev_received = true;
|
queue_redraw(ps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2507,7 +2497,7 @@ win_set_focused_force(session_t *ps, win *w, switch_t val) {
|
||||||
if (val != w->focused_force) {
|
if (val != w->focused_force) {
|
||||||
w->focused_force = val;
|
w->focused_force = val;
|
||||||
win_update_focused(ps, w);
|
win_update_focused(ps, w);
|
||||||
ps->ev_received = true;
|
queue_redraw(ps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2519,7 +2509,7 @@ win_set_invert_color_force(session_t *ps, win *w, switch_t val) {
|
||||||
if (val != w->invert_color_force) {
|
if (val != w->invert_color_force) {
|
||||||
w->invert_color_force = val;
|
w->invert_color_force = val;
|
||||||
win_determine_invert_color(ps, w);
|
win_determine_invert_color(ps, w);
|
||||||
ps->ev_received = true;
|
queue_redraw(ps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2555,7 +2545,7 @@ opts_set_no_fading_openclose(session_t *ps, bool newval) {
|
||||||
ps->o.no_fading_openclose = newval;
|
ps->o.no_fading_openclose = newval;
|
||||||
for (win *w = ps->list; w; w = w->next)
|
for (win *w = ps->list; w; w = w->next)
|
||||||
win_determine_fade(ps, w);
|
win_determine_fade(ps, w);
|
||||||
ps->ev_received = true;
|
queue_redraw(ps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3075,6 +3065,9 @@ ev_handle(session_t *ps, xcb_generic_event_t *ev) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// XXX redraw needs to be more fine grained
|
||||||
|
queue_redraw(ps);
|
||||||
|
|
||||||
switch (ev->response_type) {
|
switch (ev->response_type) {
|
||||||
case FocusIn:
|
case FocusIn:
|
||||||
ev_focus_in(ps, (xcb_focus_in_event_t *)ev);
|
ev_focus_in(ps, (xcb_focus_in_event_t *)ev);
|
||||||
|
@ -4215,31 +4208,22 @@ swopti_init(session_t *ps) {
|
||||||
* @param ps current session
|
* @param ps current session
|
||||||
* @param[in,out] ptv pointer to the timeout
|
* @param[in,out] ptv pointer to the timeout
|
||||||
*/
|
*/
|
||||||
static void
|
static double
|
||||||
swopti_handle_timeout(session_t *ps, struct timeval *ptv) {
|
swopti_handle_timeout(session_t *ps) {
|
||||||
if (!ptv)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Get the microsecond offset of the time when the we reach the timeout
|
// Get the microsecond offset of the time when the we reach the timeout
|
||||||
// I don't think a 32-bit long could overflow here.
|
// I don't think a 32-bit long could overflow here.
|
||||||
long offset = (ptv->tv_usec + get_time_timeval().tv_usec - ps->paint_tm_offset) % ps->refresh_intv;
|
long offset = (get_time_timeval().tv_usec - ps->paint_tm_offset) % ps->refresh_intv;
|
||||||
if (offset < 0)
|
if (offset < 0)
|
||||||
offset += ps->refresh_intv;
|
offset += ps->refresh_intv;
|
||||||
|
|
||||||
assert(offset >= 0 && offset < ps->refresh_intv);
|
|
||||||
|
|
||||||
// If the target time is sufficiently close to a refresh time, don't add
|
// If the target time is sufficiently close to a refresh time, don't add
|
||||||
// an offset, to avoid certain blocking conditions.
|
// an offset, to avoid certain blocking conditions.
|
||||||
if (offset < SWOPTI_TOLERANCE
|
if (offset < SWOPTI_TOLERANCE
|
||||||
|| offset > ps->refresh_intv - SWOPTI_TOLERANCE)
|
|| offset > ps->refresh_intv - SWOPTI_TOLERANCE)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
// Add an offset so we wait until the next refresh after timeout
|
// Add an offset so we wait until the next refresh after timeout
|
||||||
ptv->tv_usec += ps->refresh_intv - offset;
|
return (ps->refresh_intv - offset) / 1e6;
|
||||||
if (ptv->tv_usec > US_PER_SEC) {
|
|
||||||
ptv->tv_usec -= US_PER_SEC;
|
|
||||||
++ptv->tv_sec;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4663,150 +4647,6 @@ redir_start(session_t *ps) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the poll time.
|
|
||||||
*/
|
|
||||||
static time_ms_t
|
|
||||||
timeout_get_poll_time(session_t *ps) {
|
|
||||||
const time_ms_t now = get_time_ms();
|
|
||||||
time_ms_t wait = TIME_MS_MAX;
|
|
||||||
|
|
||||||
// Traverse throught the timeout linked list
|
|
||||||
for (timeout_t *ptmout = ps->tmout_lst; ptmout; ptmout = ptmout->next) {
|
|
||||||
if (ptmout->enabled) {
|
|
||||||
time_ms_t newrun = timeout_get_newrun(ptmout);
|
|
||||||
if (newrun <= now) {
|
|
||||||
wait = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
time_ms_t newwait = newrun - now;
|
|
||||||
if (newwait < wait)
|
|
||||||
wait = newwait;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return wait;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert a new timeout.
|
|
||||||
*/
|
|
||||||
timeout_t *
|
|
||||||
timeout_insert(session_t *ps, time_ms_t interval,
|
|
||||||
bool (*callback)(session_t *ps, timeout_t *ptmout), void *data) {
|
|
||||||
static const timeout_t tmout_def = {
|
|
||||||
.enabled = true,
|
|
||||||
.data = NULL,
|
|
||||||
.callback = NULL,
|
|
||||||
.firstrun = 0L,
|
|
||||||
.lastrun = 0L,
|
|
||||||
.interval = 0L,
|
|
||||||
};
|
|
||||||
|
|
||||||
const time_ms_t now = get_time_ms();
|
|
||||||
timeout_t *ptmout = malloc(sizeof(timeout_t));
|
|
||||||
if (!ptmout)
|
|
||||||
printf_errfq(1, "(): Failed to allocate memory for timeout.");
|
|
||||||
memcpy(ptmout, &tmout_def, sizeof(timeout_t));
|
|
||||||
|
|
||||||
ptmout->interval = interval;
|
|
||||||
ptmout->firstrun = now;
|
|
||||||
ptmout->lastrun = now;
|
|
||||||
ptmout->data = data;
|
|
||||||
ptmout->callback = callback;
|
|
||||||
ptmout->next = ps->tmout_lst;
|
|
||||||
ps->tmout_lst = ptmout;
|
|
||||||
|
|
||||||
return ptmout;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Drop a timeout.
|
|
||||||
*
|
|
||||||
* @return true if we have found the timeout and removed it, false
|
|
||||||
* otherwise
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
timeout_drop(session_t *ps, timeout_t *prm) {
|
|
||||||
timeout_t **pplast = &ps->tmout_lst;
|
|
||||||
|
|
||||||
for (timeout_t *ptmout = ps->tmout_lst; ptmout;
|
|
||||||
pplast = &ptmout->next, ptmout = ptmout->next) {
|
|
||||||
if (prm == ptmout) {
|
|
||||||
*pplast = ptmout->next;
|
|
||||||
free(ptmout);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear all timeouts.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
timeout_clear(session_t *ps) {
|
|
||||||
timeout_t *ptmout = ps->tmout_lst;
|
|
||||||
timeout_t *next = NULL;
|
|
||||||
while (ptmout) {
|
|
||||||
next = ptmout->next;
|
|
||||||
free(ptmout);
|
|
||||||
ptmout = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run timeouts.
|
|
||||||
*
|
|
||||||
* @return true if we have ran a timeout, false otherwise
|
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
timeout_run(session_t *ps) {
|
|
||||||
const time_ms_t now = get_time_ms();
|
|
||||||
bool ret = false;
|
|
||||||
timeout_t *pnext = NULL;
|
|
||||||
|
|
||||||
for (timeout_t *ptmout = ps->tmout_lst; ptmout; ptmout = pnext) {
|
|
||||||
pnext = ptmout->next;
|
|
||||||
if (ptmout->enabled) {
|
|
||||||
const time_ms_t max = now +
|
|
||||||
(time_ms_t) (ptmout->interval * TIMEOUT_RUN_TOLERANCE);
|
|
||||||
time_ms_t newrun = timeout_get_newrun(ptmout);
|
|
||||||
if (newrun <= max) {
|
|
||||||
ret = true;
|
|
||||||
timeout_invoke(ps, ptmout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoke a timeout.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
timeout_invoke(session_t *ps, timeout_t *ptmout) {
|
|
||||||
const time_ms_t now = get_time_ms();
|
|
||||||
ptmout->lastrun = now;
|
|
||||||
// Avoid modifying the timeout structure after running timeout, to
|
|
||||||
// make it possible to remove timeout in callback
|
|
||||||
if (ptmout->callback)
|
|
||||||
ptmout->callback(ps, ptmout);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset a timeout to initial state.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
timeout_reset(session_t *ps, timeout_t *ptmout) {
|
|
||||||
ptmout->firstrun = ptmout->lastrun = get_time_ms();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unredirect all windows.
|
* Unredirect all windows.
|
||||||
*/
|
*/
|
||||||
|
@ -4836,99 +4676,156 @@ redir_stop(session_t *ps) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Handle queued events before we go to sleep
|
||||||
* Unredirection timeout callback.
|
static void
|
||||||
*/
|
handle_queued_x_events(EV_P_ ev_prepare *w, int revents) {
|
||||||
static bool
|
ev_session_prepare *sw = (void *)w;
|
||||||
tmout_unredir_callback(session_t *ps, timeout_t *tmout) {
|
session_t *ps = sw->ps;
|
||||||
ps->tmout_unredir_hit = true;
|
xcb_generic_event_t *ev;
|
||||||
tmout->enabled = false;
|
xcb_connection_t *c = XGetXCBConnection(ps->dpy);
|
||||||
|
while ((ev = xcb_poll_for_queued_event(c))) {
|
||||||
return true;
|
ev_handle(ps, ev);
|
||||||
|
free(ev);
|
||||||
|
};
|
||||||
|
XFlush(ps->dpy);
|
||||||
|
xcb_flush(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main loop.
|
* Unredirection timeout callback.
|
||||||
*/
|
*/
|
||||||
static bool
|
static void
|
||||||
mainloop(session_t *ps) {
|
tmout_unredir_callback(EV_P_ ev_timer *w, int revents) {
|
||||||
// Don't miss timeouts even when we have a LOT of other events!
|
ev_session_timer *sw = (void *)w;
|
||||||
timeout_run(ps);
|
sw->ps->tmout_unredir_hit = true;
|
||||||
|
queue_redraw(sw->ps);
|
||||||
|
}
|
||||||
|
|
||||||
// Process existing events
|
static void
|
||||||
// Sometimes poll() returns 1 but no events are actually read,
|
fade_timer_callback(EV_P_ ev_timer *w, int revents) {
|
||||||
// causing XNextEvent() to block, I have no idea what's wrong, so we
|
ev_session_timer *sw = (void *)w;
|
||||||
// check for the number of events here.
|
queue_redraw(sw->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) {
|
||||||
|
printf_errf("(): Couldn't find specified benchmark window.");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
add_damage_from_win(ps, wi);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
force_repaint(ps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ps->fade_running = false;
|
||||||
|
win *t = paint_preprocess(ps, ps->list);
|
||||||
|
ps->tmout_unredir_hit = false;
|
||||||
|
|
||||||
|
// Start/stop fade timer depends on whether window are fading
|
||||||
|
if (!ps->fade_running && ev_is_active(&ps->fade_timer->w))
|
||||||
|
ev_timer_stop(ps->loop, &ps->fade_timer->w);
|
||||||
|
else if (ps->fade_running && !ev_is_active(&ps->fade_timer->w)) {
|
||||||
|
ev_timer_set(&ps->fade_timer->w, fade_timeout(ps), 0);
|
||||||
|
ev_timer_start(ps->loop, &ps->fade_timer->w);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the screen is unredirected, free all_damage to stop painting
|
||||||
|
if (!ps->redirected || ps->o.stoppaint_force == ON)
|
||||||
|
pixman_region32_clear(&ps->all_damage);
|
||||||
|
|
||||||
|
if (pixman_region32_not_empty(&ps->all_damage)) {
|
||||||
|
region_t all_damage_orig, *region_real = NULL;
|
||||||
|
pixman_region32_init(&all_damage_orig);
|
||||||
|
|
||||||
|
// keep a copy of non-resized all_damage for region_real
|
||||||
|
if (ps->o.resize_damage > 0) {
|
||||||
|
copy_region(&all_damage_orig, &ps->all_damage);
|
||||||
|
resize_region(ps, &ps->all_damage, ps->o.resize_damage);
|
||||||
|
region_real = &all_damage_orig;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int paint = 0;
|
||||||
|
paint_all(ps, &ps->all_damage, region_real, t);
|
||||||
|
|
||||||
|
pixman_region32_clear(&ps->all_damage);
|
||||||
|
pixman_region32_fini(&all_damage_orig);
|
||||||
|
|
||||||
|
paint++;
|
||||||
|
if (ps->o.benchmark && paint >= ps->o.benchmark)
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ps->fade_running)
|
||||||
|
ps->fade_time = 0L;
|
||||||
|
|
||||||
|
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
|
||||||
|
ev_session_idle *sw = (void *)w;
|
||||||
|
|
||||||
|
_draw_callback(EV_A_ sw->ps, revents);
|
||||||
|
|
||||||
|
// Don't do painting non-stop unless we are in benchmark mode
|
||||||
|
if (!sw->ps->o.benchmark)
|
||||||
|
ev_idle_stop(sw->ps->loop, &sw->ps->draw_idle->w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delayed_draw_timer_callback(EV_P_ ev_timer *w, int revents) {
|
||||||
|
ev_session_timer *sw = (void *)w;
|
||||||
|
_draw_callback(EV_A_ sw->ps, revents);
|
||||||
|
|
||||||
|
// We might have stopped the ev_idle in delayed_draw_callback,
|
||||||
|
// so we restart it if we are in benchmark mode
|
||||||
|
if (sw->ps->o.benchmark)
|
||||||
|
ev_idle_start(EV_A_ &sw->ps->draw_idle->w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delayed_draw_callback(EV_P_ ev_idle *w, int revents) {
|
||||||
|
// This function is only used if we are using --swopti
|
||||||
|
ev_session_idle *sw = (void *)w;
|
||||||
|
if (ev_is_active(sw->ps->delayed_draw_timer))
|
||||||
|
return;
|
||||||
|
|
||||||
|
double delay = swopti_handle_timeout(sw->ps);
|
||||||
|
printf_errf("(): %lf", delay);
|
||||||
|
if (delay < 1e-6)
|
||||||
|
return _draw_callback(EV_A_ sw->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 updated 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.
|
||||||
|
//
|
||||||
|
// 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(sw->ps->loop, &sw->ps->draw_idle->w);
|
||||||
|
|
||||||
|
ev_timer_set(&sw->ps->delayed_draw_timer->w, delay, 0);
|
||||||
|
ev_timer_start(sw->ps->loop, &sw->ps->delayed_draw_timer->w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
x_event_callback(EV_P_ ev_io *w, int revents) {
|
||||||
|
session_t *ps = (session_t *)w;
|
||||||
xcb_connection_t *c = XGetXCBConnection(ps->dpy);
|
xcb_connection_t *c = XGetXCBConnection(ps->dpy);
|
||||||
xcb_generic_event_t *ev = xcb_poll_for_event(c);
|
xcb_generic_event_t *ev = xcb_poll_for_event(c);
|
||||||
if (ev) {
|
if (ev) {
|
||||||
ev_handle(ps, ev);
|
ev_handle(ps, ev);
|
||||||
ps->ev_received = true;
|
|
||||||
free(ev);
|
free(ev);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_DBUS
|
|
||||||
if (ps->o.dbus) {
|
|
||||||
cdbus_loop(ps);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (ps->reset)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Calculate timeout
|
|
||||||
struct timeval *ptv = NULL;
|
|
||||||
{
|
|
||||||
// Consider ev_received firstly
|
|
||||||
if (ps->ev_received || ps->o.benchmark) {
|
|
||||||
ptv = malloc(sizeof(struct timeval));
|
|
||||||
ptv->tv_sec = 0L;
|
|
||||||
ptv->tv_usec = 0L;
|
|
||||||
}
|
|
||||||
// Then consider fading timeout
|
|
||||||
else if (!ps->idling) {
|
|
||||||
ptv = malloc(sizeof(struct timeval));
|
|
||||||
*ptv = ms_to_tv(fade_timeout(ps));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Software optimization is to be applied on timeouts that require
|
|
||||||
// immediate painting only
|
|
||||||
if (ptv && ps->o.sw_opti)
|
|
||||||
swopti_handle_timeout(ps, ptv);
|
|
||||||
|
|
||||||
// Don't continue looping for 0 timeout
|
|
||||||
if (ptv && timeval_isempty(ptv)) {
|
|
||||||
free(ptv);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now consider the waiting time of other timeouts
|
|
||||||
time_ms_t tmout_ms = timeout_get_poll_time(ps);
|
|
||||||
if (tmout_ms < TIME_MS_MAX) {
|
|
||||||
if (!ptv) {
|
|
||||||
ptv = malloc(sizeof(struct timeval));
|
|
||||||
*ptv = ms_to_tv(tmout_ms);
|
|
||||||
}
|
|
||||||
else if (timeval_ms_cmp(ptv, tmout_ms) > 0) {
|
|
||||||
*ptv = ms_to_tv(tmout_ms);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't continue looping for 0 timeout
|
|
||||||
if (ptv && timeval_isempty(ptv)) {
|
|
||||||
free(ptv);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Polling
|
|
||||||
fds_poll(ps, ptv);
|
|
||||||
free(ptv);
|
|
||||||
ptv = NULL;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -5073,20 +4970,14 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
||||||
.track_leader = false,
|
.track_leader = false,
|
||||||
},
|
},
|
||||||
|
|
||||||
.pfds_read = NULL,
|
|
||||||
.pfds_write = NULL,
|
|
||||||
.pfds_except = NULL,
|
|
||||||
.nfds_max = 0,
|
|
||||||
.tmout_lst = NULL,
|
|
||||||
|
|
||||||
.time_start = { 0, 0 },
|
.time_start = { 0, 0 },
|
||||||
.redirected = false,
|
.redirected = false,
|
||||||
.alpha_picts = NULL,
|
.alpha_picts = NULL,
|
||||||
.idling = false,
|
.fade_running = false,
|
||||||
.fade_time = 0L,
|
.fade_time = 0L,
|
||||||
.ignore_head = NULL,
|
.ignore_head = NULL,
|
||||||
.ignore_tail = NULL,
|
.ignore_tail = NULL,
|
||||||
.reset = false,
|
.quit = false,
|
||||||
|
|
||||||
.expose_rects = NULL,
|
.expose_rects = NULL,
|
||||||
.size_expose = 0,
|
.size_expose = 0,
|
||||||
|
@ -5159,6 +5050,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
||||||
// Allocate a session and copy default values into it
|
// Allocate a session and copy default values into it
|
||||||
session_t *ps = malloc(sizeof(session_t));
|
session_t *ps = malloc(sizeof(session_t));
|
||||||
*ps = s_def;
|
*ps = s_def;
|
||||||
|
ps->loop = EV_DEFAULT;
|
||||||
pixman_region32_init(&ps->screen_reg);
|
pixman_region32_init(&ps->screen_reg);
|
||||||
pixman_region32_init(&ps->all_damage);
|
pixman_region32_init(&ps->all_damage);
|
||||||
for (int i = 0; i < CGLX_MAX_BUFFER_AGE; i ++)
|
for (int i = 0; i < CGLX_MAX_BUFFER_AGE; i ++)
|
||||||
|
@ -5456,10 +5348,44 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
||||||
ps->o.shadow_red, ps->o.shadow_green, ps->o.shadow_blue);
|
ps->o.shadow_red, ps->o.shadow_green, ps->o.shadow_blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
fds_insert(ps, ConnectionNumber(ps->dpy), POLLIN);
|
ev_io_init(&ps->xiow, x_event_callback, ConnectionNumber(ps->dpy), EV_READ);
|
||||||
ps->tmout_unredir = timeout_insert(ps, ps->o.unredir_if_possible_delay,
|
ev_io_start(ps->loop, &ps->xiow);
|
||||||
tmout_unredir_callback, NULL);
|
ps->unredir_timer = calloc(1, sizeof(ev_session_timer));
|
||||||
ps->tmout_unredir->enabled = false;
|
ps->unredir_timer->ps = ps;
|
||||||
|
ev_init(&ps->unredir_timer->w, tmout_unredir_callback);
|
||||||
|
ps->draw_idle = calloc(1, sizeof(ev_session_idle));
|
||||||
|
ps->draw_idle->ps = ps;
|
||||||
|
if (ps->o.sw_opti)
|
||||||
|
ev_idle_init(&ps->draw_idle->w, delayed_draw_callback);
|
||||||
|
else
|
||||||
|
ev_idle_init(&ps->draw_idle->w, draw_callback);
|
||||||
|
|
||||||
|
ps->fade_timer = calloc(1, sizeof(ev_session_timer));
|
||||||
|
ps->fade_timer->ps = ps;
|
||||||
|
ev_init(&ps->fade_timer->w, fade_timer_callback);
|
||||||
|
|
||||||
|
ps->delayed_draw_timer = calloc(1, sizeof(ev_session_timer));
|
||||||
|
ps->delayed_draw_timer->ps = ps;
|
||||||
|
ev_init(&ps->delayed_draw_timer->w, delayed_draw_timer_callback);
|
||||||
|
|
||||||
|
// xcb can read multiple events from the socket anytime a request which requires
|
||||||
|
// 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.
|
||||||
|
ps->event_check = calloc(1, sizeof(ev_session_prepare));
|
||||||
|
ps->event_check->ps = ps;
|
||||||
|
ev_prepare_init(&ps->event_check->w, 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->w, EV_MINPRI);
|
||||||
|
ev_prepare_start(ps->loop, &ps->event_check->w);
|
||||||
|
|
||||||
XGrabServer(ps->dpy);
|
XGrabServer(ps->dpy);
|
||||||
|
|
||||||
|
@ -5647,9 +5573,6 @@ session_destroy(session_t *ps) {
|
||||||
free(ps->o.blur_kerns[i]);
|
free(ps->o.blur_kerns[i]);
|
||||||
free(ps->blur_kerns_cache[i]);
|
free(ps->blur_kerns_cache[i]);
|
||||||
}
|
}
|
||||||
free(ps->pfds_read);
|
|
||||||
free(ps->pfds_write);
|
|
||||||
free(ps->pfds_except);
|
|
||||||
free(ps->o.glx_fshader_win_str);
|
free(ps->o.glx_fshader_win_str);
|
||||||
free_xinerama_info(ps);
|
free_xinerama_info(ps);
|
||||||
free(ps->pictfmts);
|
free(ps->pictfmts);
|
||||||
|
@ -5686,6 +5609,7 @@ session_destroy(session_t *ps) {
|
||||||
|
|
||||||
// Flush all events
|
// Flush all events
|
||||||
XSync(ps->dpy, True);
|
XSync(ps->dpy, True);
|
||||||
|
ev_io_stop(ps->loop, &ps->xiow);
|
||||||
|
|
||||||
#ifdef DEBUG_XRC
|
#ifdef DEBUG_XRC
|
||||||
// Report about resource leakage
|
// Report about resource leakage
|
||||||
|
@ -5693,8 +5617,21 @@ session_destroy(session_t *ps) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Free timeouts
|
// Free timeouts
|
||||||
ps->tmout_unredir = NULL;
|
ev_timer_stop(ps->loop, &ps->unredir_timer->w);
|
||||||
timeout_clear(ps);
|
free(ps->unredir_timer);
|
||||||
|
ps->unredir_timer = NULL;
|
||||||
|
|
||||||
|
ev_timer_stop(ps->loop, &ps->fade_timer->w);
|
||||||
|
free(ps->fade_timer);
|
||||||
|
ps->fade_timer = NULL;
|
||||||
|
|
||||||
|
ev_idle_stop(ps->loop, &ps->draw_idle->w);
|
||||||
|
free(ps->draw_idle);
|
||||||
|
ps->draw_idle = NULL;
|
||||||
|
|
||||||
|
ev_prepare_stop(ps->loop, &ps->event_check->w);
|
||||||
|
free(ps->event_check);
|
||||||
|
ps->event_check = NULL;
|
||||||
|
|
||||||
if (ps == ps_g)
|
if (ps == ps_g)
|
||||||
ps_g = NULL;
|
ps_g = NULL;
|
||||||
|
@ -5727,68 +5664,10 @@ session_run(session_t *ps) {
|
||||||
if (ps->redirected)
|
if (ps->redirected)
|
||||||
paint_all(ps, NULL, NULL, t);
|
paint_all(ps, NULL, NULL, t);
|
||||||
|
|
||||||
// Initialize idling
|
if (ps->o.benchmark)
|
||||||
ps->idling = false;
|
ev_idle_start(ps->loop, &ps->draw_idle->w);
|
||||||
|
|
||||||
// Main loop
|
ev_run(ps->loop, 0);
|
||||||
while (!ps->reset) {
|
|
||||||
ps->ev_received = false;
|
|
||||||
|
|
||||||
while (mainloop(ps))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ps->o.benchmark) {
|
|
||||||
if (ps->o.benchmark_wid) {
|
|
||||||
win *w = find_win(ps, ps->o.benchmark_wid);
|
|
||||||
if (!w) {
|
|
||||||
printf_errf("(): Couldn't find specified benchmark window.");
|
|
||||||
session_destroy(ps);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
add_damage_from_win(ps, w);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
force_repaint(ps);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// idling will be turned off during paint_preprocess() if needed
|
|
||||||
ps->idling = true;
|
|
||||||
|
|
||||||
t = paint_preprocess(ps, ps->list);
|
|
||||||
ps->tmout_unredir_hit = false;
|
|
||||||
|
|
||||||
// If the screen is unredirected, free all_damage to stop painting
|
|
||||||
if (!ps->redirected || ON == ps->o.stoppaint_force)
|
|
||||||
pixman_region32_clear(&ps->all_damage);
|
|
||||||
|
|
||||||
if (pixman_region32_not_empty(&ps->all_damage)) {
|
|
||||||
region_t all_damage_orig, *region_real = NULL;
|
|
||||||
pixman_region32_init(&all_damage_orig);
|
|
||||||
|
|
||||||
// keep a copy of non-resized all_damage for region_real
|
|
||||||
if (ps->o.resize_damage > 0) {
|
|
||||||
copy_region(&all_damage_orig, &ps->all_damage);
|
|
||||||
resize_region(ps, &ps->all_damage, ps->o.resize_damage);
|
|
||||||
region_real = &all_damage_orig;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int paint = 0;
|
|
||||||
paint_all(ps, &ps->all_damage, region_real, t);
|
|
||||||
|
|
||||||
pixman_region32_clear(&ps->all_damage);
|
|
||||||
pixman_region32_fini(&all_damage_orig);
|
|
||||||
|
|
||||||
paint++;
|
|
||||||
if (ps->o.benchmark && paint >= ps->o.benchmark)
|
|
||||||
exit(0);
|
|
||||||
|
|
||||||
XSync(ps->dpy, False);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps->idling)
|
|
||||||
ps->fade_time = 0L;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5799,8 +5678,7 @@ session_run(session_t *ps) {
|
||||||
static void
|
static void
|
||||||
reset_enable(int __attribute__((unused)) signum) {
|
reset_enable(int __attribute__((unused)) signum) {
|
||||||
session_t * const ps = ps_g;
|
session_t * const ps = ps_g;
|
||||||
|
ev_break(ps->loop, EVBREAK_ALL);
|
||||||
ps->reset = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5826,7 +5704,8 @@ main(int argc, char **argv) {
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
session_t *ps_old = ps_g;
|
session_t *ps_old = ps_g;
|
||||||
while (1) {
|
bool quit = false;
|
||||||
|
while (!quit) {
|
||||||
ps_g = session_init(ps_old, argc, argv);
|
ps_g = session_init(ps_old, argc, argv);
|
||||||
if (!ps_g) {
|
if (!ps_g) {
|
||||||
printf_errf("(): Failed to create new session.");
|
printf_errf("(): Failed to create new session.");
|
||||||
|
@ -5834,6 +5713,7 @@ main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
session_run(ps_g);
|
session_run(ps_g);
|
||||||
ps_old = ps_g;
|
ps_old = ps_g;
|
||||||
|
quit = ps_g->quit;
|
||||||
session_destroy(ps_g);
|
session_destroy(ps_g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -491,11 +491,6 @@ ensure_glx_context(session_t *ps) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline time_ms_t
|
|
||||||
timeout_get_newrun(const timeout_t *ptmout) {
|
|
||||||
return ptmout->firstrun + (max_l((ptmout->lastrun + (time_ms_t) (ptmout->interval * TIMEOUT_RUN_TOLERANCE) - ptmout->firstrun) / ptmout->interval, (ptmout->lastrun + (time_ms_t) (ptmout->interval * (1 - TIMEOUT_RUN_TOLERANCE)) - ptmout->firstrun) / ptmout->interval) + 1) * ptmout->interval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Xinerama screen a window is on.
|
* Get the Xinerama screen a window is on.
|
||||||
*
|
*
|
||||||
|
|
353
src/dbus.c
353
src/dbus.c
|
@ -10,6 +10,27 @@
|
||||||
|
|
||||||
#include "dbus.h"
|
#include "dbus.h"
|
||||||
|
|
||||||
|
static DBusHandlerResult
|
||||||
|
cdbus_process(DBusConnection *conn, DBusMessage *m, void *);
|
||||||
|
|
||||||
|
static dbus_bool_t
|
||||||
|
cdbus_callback_add_timeout(DBusTimeout *timeout, void *data);
|
||||||
|
|
||||||
|
static void
|
||||||
|
cdbus_callback_remove_timeout(DBusTimeout *timeout, void *data);
|
||||||
|
|
||||||
|
static void
|
||||||
|
cdbus_callback_timeout_toggled(DBusTimeout *timeout, void *data);
|
||||||
|
|
||||||
|
static dbus_bool_t
|
||||||
|
cdbus_callback_add_watch(DBusWatch *watch, void *data);
|
||||||
|
|
||||||
|
static void
|
||||||
|
cdbus_callback_remove_watch(DBusWatch *watch, void *data);
|
||||||
|
|
||||||
|
static void
|
||||||
|
cdbus_callback_watch_toggled(DBusWatch *watch, void *data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize D-Bus connection.
|
* Initialize D-Bus connection.
|
||||||
*/
|
*/
|
||||||
|
@ -84,7 +105,7 @@ cdbus_init(session_t *ps) {
|
||||||
dbus_error_free(&err);
|
dbus_error_free(&err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
dbus_connection_add_filter(ps->dbus_conn, cdbus_process, ps, NULL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +138,20 @@ cdbus_destroy(session_t *ps) {
|
||||||
*/
|
*/
|
||||||
///@{
|
///@{
|
||||||
|
|
||||||
|
typedef struct ev_dbus_timer {
|
||||||
|
ev_timer w;
|
||||||
|
DBusTimeout *t;
|
||||||
|
} ev_dbus_timer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for handling a D-Bus timeout.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
cdbus_callback_handle_timeout(EV_P_ ev_timer *w, int revents) {
|
||||||
|
ev_dbus_timer *t = (void *)w;
|
||||||
|
dbus_timeout_handle(t->t);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for adding D-Bus timeout.
|
* Callback for adding D-Bus timeout.
|
||||||
*/
|
*/
|
||||||
|
@ -124,12 +159,16 @@ static dbus_bool_t
|
||||||
cdbus_callback_add_timeout(DBusTimeout *timeout, void *data) {
|
cdbus_callback_add_timeout(DBusTimeout *timeout, void *data) {
|
||||||
session_t *ps = data;
|
session_t *ps = data;
|
||||||
|
|
||||||
timeout_t *ptmout = timeout_insert(ps, dbus_timeout_get_interval(timeout),
|
ev_dbus_timer *t = calloc(1, sizeof *t);
|
||||||
cdbus_callback_handle_timeout, timeout);
|
double i = dbus_timeout_get_interval(timeout) / 1000.0;
|
||||||
if (ptmout)
|
ev_timer_init(&t->w, cdbus_callback_handle_timeout, i, i);
|
||||||
dbus_timeout_set_data(timeout, ptmout, NULL);
|
t->t = timeout;
|
||||||
|
dbus_timeout_set_data(timeout, t, NULL);
|
||||||
|
|
||||||
return (bool) ptmout;
|
if (dbus_timeout_get_enabled(timeout))
|
||||||
|
ev_timer_start(ps->loop, &t->w);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -139,10 +178,10 @@ static void
|
||||||
cdbus_callback_remove_timeout(DBusTimeout *timeout, void *data) {
|
cdbus_callback_remove_timeout(DBusTimeout *timeout, void *data) {
|
||||||
session_t *ps = data;
|
session_t *ps = data;
|
||||||
|
|
||||||
timeout_t *ptmout = dbus_timeout_get_data(timeout);
|
ev_dbus_timer *t = dbus_timeout_get_data(timeout);
|
||||||
assert(ptmout);
|
assert(t);
|
||||||
if (ptmout)
|
ev_timer_stop(ps->loop, &t->w);
|
||||||
timeout_drop(ps, ptmout);
|
free(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -150,52 +189,77 @@ cdbus_callback_remove_timeout(DBusTimeout *timeout, void *data) {
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
cdbus_callback_timeout_toggled(DBusTimeout *timeout, void *data) {
|
cdbus_callback_timeout_toggled(DBusTimeout *timeout, void *data) {
|
||||||
timeout_t *ptmout = dbus_timeout_get_data(timeout);
|
session_t *ps = data;
|
||||||
|
ev_dbus_timer *t = dbus_timeout_get_data(timeout);
|
||||||
|
|
||||||
assert(ptmout);
|
assert(t);
|
||||||
if (ptmout) {
|
ev_timer_stop(ps->loop, &t->w);
|
||||||
ptmout->enabled = dbus_timeout_get_enabled(timeout);
|
if (dbus_timeout_get_enabled(timeout)) {
|
||||||
// Refresh interval as libdbus doc says: "Whenever a timeout is toggled,
|
double i = dbus_timeout_get_interval(timeout) / 1000.0;
|
||||||
// its interval may change."
|
ev_timer_set(&t->w, i, i);
|
||||||
ptmout->interval = dbus_timeout_get_interval(timeout);
|
ev_timer_start(ps->loop, &t->w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for handling a D-Bus timeout.
|
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
cdbus_callback_handle_timeout(session_t *ps, timeout_t *ptmout) {
|
|
||||||
assert(ptmout && ptmout->data);
|
|
||||||
if (ptmout && ptmout->data)
|
|
||||||
return dbus_timeout_handle(ptmout->data);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
/** @name DBusWatch handling
|
/** @name DBusWatch handling
|
||||||
*/
|
*/
|
||||||
///@{
|
///@{
|
||||||
|
|
||||||
|
typedef struct ev_dbus_io {
|
||||||
|
ev_io w;
|
||||||
|
session_t *ps;
|
||||||
|
DBusWatch *dw;
|
||||||
|
} ev_dbus_io;
|
||||||
|
|
||||||
|
void cdbus_io_callback(EV_P_ ev_io *w, int revents) {
|
||||||
|
ev_dbus_io *dw = (void *)w;
|
||||||
|
DBusWatchFlags flags = 0;
|
||||||
|
if (revents & EV_READ)
|
||||||
|
flags |= DBUS_WATCH_READABLE;
|
||||||
|
if (revents & EV_WRITE)
|
||||||
|
flags |= DBUS_WATCH_WRITABLE;
|
||||||
|
dbus_watch_handle(dw->dw, flags);
|
||||||
|
while (dbus_connection_dispatch(dw->ps->dbus_conn) != DBUS_DISPATCH_COMPLETE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the poll condition of a DBusWatch.
|
||||||
|
*/
|
||||||
|
static inline int
|
||||||
|
cdbus_get_watch_cond(DBusWatch *watch) {
|
||||||
|
const unsigned flags = dbus_watch_get_flags(watch);
|
||||||
|
int condition = 0;
|
||||||
|
if (flags & DBUS_WATCH_READABLE)
|
||||||
|
condition |= EV_READ;
|
||||||
|
if (flags & DBUS_WATCH_WRITABLE)
|
||||||
|
condition |= EV_WRITE;
|
||||||
|
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for adding D-Bus watch.
|
* Callback for adding D-Bus watch.
|
||||||
*/
|
*/
|
||||||
static dbus_bool_t
|
static dbus_bool_t
|
||||||
cdbus_callback_add_watch(DBusWatch *watch, void *data) {
|
cdbus_callback_add_watch(DBusWatch *watch, void *data) {
|
||||||
// Leave disabled watches alone
|
|
||||||
if (!dbus_watch_get_enabled(watch))
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
session_t *ps = data;
|
session_t *ps = data;
|
||||||
|
|
||||||
// Insert the file descriptor
|
ev_dbus_io *w = calloc(1, sizeof *w);
|
||||||
fds_insert(ps, dbus_watch_get_unix_fd(watch),
|
w->dw = watch;
|
||||||
|
w->ps = ps;
|
||||||
|
ev_io_init(&w->w, cdbus_io_callback, dbus_watch_get_unix_fd(watch),
|
||||||
cdbus_get_watch_cond(watch));
|
cdbus_get_watch_cond(watch));
|
||||||
|
|
||||||
|
// Leave disabled watches alone
|
||||||
|
if (dbus_watch_get_enabled(watch))
|
||||||
|
ev_io_start(ps->loop, &w->w);
|
||||||
|
|
||||||
|
dbus_watch_set_data(watch, w, NULL);
|
||||||
|
|
||||||
// Always return true
|
// Always return true
|
||||||
return TRUE;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -204,9 +268,9 @@ cdbus_callback_add_watch(DBusWatch *watch, void *data) {
|
||||||
static void
|
static void
|
||||||
cdbus_callback_remove_watch(DBusWatch *watch, void *data) {
|
cdbus_callback_remove_watch(DBusWatch *watch, void *data) {
|
||||||
session_t *ps = data;
|
session_t *ps = data;
|
||||||
|
ev_dbus_io *w = dbus_watch_get_data(watch);
|
||||||
fds_drop(ps, dbus_watch_get_unix_fd(watch),
|
ev_io_stop(ps->loop, &w->w);
|
||||||
cdbus_get_watch_cond(watch));
|
free(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -214,12 +278,12 @@ cdbus_callback_remove_watch(DBusWatch *watch, void *data) {
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
cdbus_callback_watch_toggled(DBusWatch *watch, void *data) {
|
cdbus_callback_watch_toggled(DBusWatch *watch, void *data) {
|
||||||
if (dbus_watch_get_enabled(watch)) {
|
session_t *ps = data;
|
||||||
cdbus_callback_add_watch(watch, data);
|
ev_io *w = dbus_watch_get_data(watch);
|
||||||
}
|
if (dbus_watch_get_enabled(watch))
|
||||||
else {
|
ev_io_start(ps->loop, w);
|
||||||
cdbus_callback_remove_watch(watch, data);
|
else
|
||||||
}
|
ev_io_stop(ps->loop, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
///@}
|
///@}
|
||||||
|
@ -534,110 +598,10 @@ cdbus_msg_get_arg(DBusMessage *msg, int count, const int type, void *pdest) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
cdbus_loop(session_t *ps) {
|
|
||||||
dbus_connection_read_write(ps->dbus_conn, 0);
|
|
||||||
DBusMessage *msg = NULL;
|
|
||||||
while ((msg = dbus_connection_pop_message(ps->dbus_conn)))
|
|
||||||
cdbus_process(ps, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @name Message processing
|
/** @name Message processing
|
||||||
*/
|
*/
|
||||||
///@{
|
///@{
|
||||||
|
|
||||||
/**
|
|
||||||
* Process a message from D-Bus.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
cdbus_process(session_t *ps, DBusMessage *msg) {
|
|
||||||
bool success = false;
|
|
||||||
|
|
||||||
#define cdbus_m_ismethod(method) \
|
|
||||||
dbus_message_is_method_call(msg, CDBUS_INTERFACE_NAME, method)
|
|
||||||
|
|
||||||
if (cdbus_m_ismethod("reset")) {
|
|
||||||
ps->reset = true;
|
|
||||||
if (!dbus_message_get_no_reply(msg))
|
|
||||||
cdbus_reply_bool(ps, msg, true);
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
else if (cdbus_m_ismethod("repaint")) {
|
|
||||||
force_repaint(ps);
|
|
||||||
if (!dbus_message_get_no_reply(msg))
|
|
||||||
cdbus_reply_bool(ps, msg, true);
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
else if (cdbus_m_ismethod("list_win")) {
|
|
||||||
success = cdbus_process_list_win(ps, msg);
|
|
||||||
}
|
|
||||||
else if (cdbus_m_ismethod("win_get")) {
|
|
||||||
success = cdbus_process_win_get(ps, msg);
|
|
||||||
}
|
|
||||||
else if (cdbus_m_ismethod("win_set")) {
|
|
||||||
success = cdbus_process_win_set(ps, msg);
|
|
||||||
}
|
|
||||||
else if (cdbus_m_ismethod("find_win")) {
|
|
||||||
success = cdbus_process_find_win(ps, msg);
|
|
||||||
}
|
|
||||||
else if (cdbus_m_ismethod("opts_get")) {
|
|
||||||
success = cdbus_process_opts_get(ps, msg);
|
|
||||||
}
|
|
||||||
else if (cdbus_m_ismethod("opts_set")) {
|
|
||||||
success = cdbus_process_opts_set(ps, msg);
|
|
||||||
}
|
|
||||||
#undef cdbus_m_ismethod
|
|
||||||
else if (dbus_message_is_method_call(msg,
|
|
||||||
"org.freedesktop.DBus.Introspectable", "Introspect")) {
|
|
||||||
success = cdbus_process_introspect(ps, msg);
|
|
||||||
}
|
|
||||||
else if (dbus_message_is_method_call(msg,
|
|
||||||
"org.freedesktop.DBus.Peer", "Ping")) {
|
|
||||||
cdbus_reply(ps, msg, NULL, NULL);
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
else if (dbus_message_is_method_call(msg,
|
|
||||||
"org.freedesktop.DBus.Peer", "GetMachineId")) {
|
|
||||||
char *uuid = dbus_get_local_machine_id();
|
|
||||||
if (uuid) {
|
|
||||||
cdbus_reply_string(ps, msg, uuid);
|
|
||||||
dbus_free(uuid);
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameAcquired")
|
|
||||||
|| dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameLost")) {
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (DBUS_MESSAGE_TYPE_ERROR == dbus_message_get_type(msg)) {
|
|
||||||
printf_errf("(): Error message of path \"%s\" "
|
|
||||||
"interface \"%s\", member \"%s\", error \"%s\"",
|
|
||||||
dbus_message_get_path(msg), dbus_message_get_interface(msg),
|
|
||||||
dbus_message_get_member(msg), dbus_message_get_error_name(msg));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf_errf("(): Illegal message of type \"%s\", path \"%s\" "
|
|
||||||
"interface \"%s\", member \"%s\"",
|
|
||||||
cdbus_repr_msgtype(msg), dbus_message_get_path(msg),
|
|
||||||
dbus_message_get_interface(msg), dbus_message_get_member(msg));
|
|
||||||
}
|
|
||||||
if (DBUS_MESSAGE_TYPE_METHOD_CALL == dbus_message_get_type(msg)
|
|
||||||
&& !dbus_message_get_no_reply(msg))
|
|
||||||
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADMSG, CDBUS_ERROR_BADMSG_S);
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the message could not be processed, and an reply is expected, return
|
|
||||||
// an empty reply.
|
|
||||||
if (!success && DBUS_MESSAGE_TYPE_METHOD_CALL == dbus_message_get_type(msg)
|
|
||||||
&& !dbus_message_get_no_reply(msg))
|
|
||||||
cdbus_reply_err(ps, msg, CDBUS_ERROR_UNKNOWN, CDBUS_ERROR_UNKNOWN_S);
|
|
||||||
|
|
||||||
// Free the message
|
|
||||||
dbus_message_unref(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a list_win D-Bus request.
|
* Process a list_win D-Bus request.
|
||||||
*/
|
*/
|
||||||
|
@ -993,6 +957,9 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX Remove this after header clean up
|
||||||
|
void queue_redraw(session_t *ps);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a opts_set D-Bus request.
|
* Process a opts_set D-Bus request.
|
||||||
*/
|
*/
|
||||||
|
@ -1055,7 +1022,7 @@ cdbus_process_opts_set(session_t *ps, DBusMessage *msg) {
|
||||||
return false;
|
return false;
|
||||||
if (ps->o.unredir_if_possible != val) {
|
if (ps->o.unredir_if_possible != val) {
|
||||||
ps->o.unredir_if_possible = val;
|
ps->o.unredir_if_possible = val;
|
||||||
ps->ev_received = true;
|
queue_redraw(ps);
|
||||||
}
|
}
|
||||||
goto cdbus_process_opts_set_success;
|
goto cdbus_process_opts_set_success;
|
||||||
}
|
}
|
||||||
|
@ -1171,6 +1138,100 @@ cdbus_process_introspect(session_t *ps, DBusMessage *msg) {
|
||||||
}
|
}
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a message from D-Bus.
|
||||||
|
*/
|
||||||
|
static DBusHandlerResult
|
||||||
|
cdbus_process(DBusConnection *c, DBusMessage *msg, void *ud) {
|
||||||
|
session_t *ps = ud;
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
|
#define cdbus_m_ismethod(method) \
|
||||||
|
dbus_message_is_method_call(msg, CDBUS_INTERFACE_NAME, method)
|
||||||
|
|
||||||
|
if (cdbus_m_ismethod("reset")) {
|
||||||
|
ps->reset = true;
|
||||||
|
if (!dbus_message_get_no_reply(msg))
|
||||||
|
cdbus_reply_bool(ps, msg, true);
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
else if (cdbus_m_ismethod("repaint")) {
|
||||||
|
force_repaint(ps);
|
||||||
|
if (!dbus_message_get_no_reply(msg))
|
||||||
|
cdbus_reply_bool(ps, msg, true);
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
else if (cdbus_m_ismethod("list_win")) {
|
||||||
|
handled = cdbus_process_list_win(ps, msg);
|
||||||
|
}
|
||||||
|
else if (cdbus_m_ismethod("win_get")) {
|
||||||
|
handled = cdbus_process_win_get(ps, msg);
|
||||||
|
}
|
||||||
|
else if (cdbus_m_ismethod("win_set")) {
|
||||||
|
handled = cdbus_process_win_set(ps, msg);
|
||||||
|
}
|
||||||
|
else if (cdbus_m_ismethod("find_win")) {
|
||||||
|
handled = cdbus_process_find_win(ps, msg);
|
||||||
|
}
|
||||||
|
else if (cdbus_m_ismethod("opts_get")) {
|
||||||
|
handled = cdbus_process_opts_get(ps, msg);
|
||||||
|
}
|
||||||
|
else if (cdbus_m_ismethod("opts_set")) {
|
||||||
|
handled = cdbus_process_opts_set(ps, msg);
|
||||||
|
}
|
||||||
|
#undef cdbus_m_ismethod
|
||||||
|
else if (dbus_message_is_method_call(msg,
|
||||||
|
"org.freedesktop.DBus.Introspectable", "Introspect")) {
|
||||||
|
handled = cdbus_process_introspect(ps, msg);
|
||||||
|
}
|
||||||
|
else if (dbus_message_is_method_call(msg,
|
||||||
|
"org.freedesktop.DBus.Peer", "Ping")) {
|
||||||
|
cdbus_reply(ps, msg, NULL, NULL);
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
else if (dbus_message_is_method_call(msg,
|
||||||
|
"org.freedesktop.DBus.Peer", "GetMachineId")) {
|
||||||
|
char *uuid = dbus_get_local_machine_id();
|
||||||
|
if (uuid) {
|
||||||
|
cdbus_reply_string(ps, msg, uuid);
|
||||||
|
dbus_free(uuid);
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameAcquired")
|
||||||
|
|| dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameLost")) {
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (DBUS_MESSAGE_TYPE_ERROR == dbus_message_get_type(msg)) {
|
||||||
|
printf_errf("(): Error message of path \"%s\" "
|
||||||
|
"interface \"%s\", member \"%s\", error \"%s\"",
|
||||||
|
dbus_message_get_path(msg), dbus_message_get_interface(msg),
|
||||||
|
dbus_message_get_member(msg), dbus_message_get_error_name(msg));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf_errf("(): Illegal message of type \"%s\", path \"%s\" "
|
||||||
|
"interface \"%s\", member \"%s\"",
|
||||||
|
cdbus_repr_msgtype(msg), dbus_message_get_path(msg),
|
||||||
|
dbus_message_get_interface(msg), dbus_message_get_member(msg));
|
||||||
|
}
|
||||||
|
if (DBUS_MESSAGE_TYPE_METHOD_CALL == dbus_message_get_type(msg)
|
||||||
|
&& !dbus_message_get_no_reply(msg))
|
||||||
|
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADMSG, CDBUS_ERROR_BADMSG_S);
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the message could not be processed, and an reply is expected, return
|
||||||
|
// an empty reply.
|
||||||
|
if (!handled && DBUS_MESSAGE_TYPE_METHOD_CALL == dbus_message_get_type(msg)
|
||||||
|
&& !dbus_message_get_no_reply(msg)) {
|
||||||
|
cdbus_reply_err(ps, msg, CDBUS_ERROR_UNKNOWN, CDBUS_ERROR_UNKNOWN_S);
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
/** @name Core callbacks
|
/** @name Core callbacks
|
||||||
*/
|
*/
|
||||||
///@{
|
///@{
|
||||||
|
|
64
src/dbus.h
64
src/dbus.h
|
@ -42,42 +42,6 @@ typedef uint16_t cdbus_enum_t;
|
||||||
#define CDBUS_TYPE_ENUM DBUS_TYPE_UINT16
|
#define CDBUS_TYPE_ENUM DBUS_TYPE_UINT16
|
||||||
#define CDBUS_TYPE_ENUM_STR DBUS_TYPE_UINT16_AS_STRING
|
#define CDBUS_TYPE_ENUM_STR DBUS_TYPE_UINT16_AS_STRING
|
||||||
|
|
||||||
static dbus_bool_t
|
|
||||||
cdbus_callback_add_timeout(DBusTimeout *timeout, void *data);
|
|
||||||
|
|
||||||
static void
|
|
||||||
cdbus_callback_remove_timeout(DBusTimeout *timeout, void *data);
|
|
||||||
|
|
||||||
static void
|
|
||||||
cdbus_callback_timeout_toggled(DBusTimeout *timeout, void *data);
|
|
||||||
|
|
||||||
static bool
|
|
||||||
cdbus_callback_handle_timeout(session_t *ps, timeout_t *ptmout);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine the poll condition of a DBusWatch.
|
|
||||||
*/
|
|
||||||
static inline short
|
|
||||||
cdbus_get_watch_cond(DBusWatch *watch) {
|
|
||||||
const unsigned flags = dbus_watch_get_flags(watch);
|
|
||||||
short condition = POLLERR | POLLHUP;
|
|
||||||
if (flags & DBUS_WATCH_READABLE)
|
|
||||||
condition |= POLLIN;
|
|
||||||
if (flags & DBUS_WATCH_WRITABLE)
|
|
||||||
condition |= POLLOUT;
|
|
||||||
|
|
||||||
return condition;
|
|
||||||
}
|
|
||||||
|
|
||||||
static dbus_bool_t
|
|
||||||
cdbus_callback_add_watch(DBusWatch *watch, void *data);
|
|
||||||
|
|
||||||
static void
|
|
||||||
cdbus_callback_remove_watch(DBusWatch *watch, void *data);
|
|
||||||
|
|
||||||
static void
|
|
||||||
cdbus_callback_watch_toggled(DBusWatch *watch, void *data);
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
cdbus_apdarg_bool(session_t *ps, DBusMessage *msg, const void *data);
|
cdbus_apdarg_bool(session_t *ps, DBusMessage *msg, const void *data);
|
||||||
|
|
||||||
|
@ -221,32 +185,4 @@ cdbus_repr_msgtype(DBusMessage *msg) {
|
||||||
return dbus_message_type_to_string(dbus_message_get_type(msg));
|
return dbus_message_type_to_string(dbus_message_get_type(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @name Message processing
|
|
||||||
*/
|
|
||||||
///@{
|
|
||||||
|
|
||||||
static void
|
|
||||||
cdbus_process(session_t *ps, DBusMessage *msg);
|
|
||||||
|
|
||||||
static bool
|
|
||||||
cdbus_process_list_win(session_t *ps, DBusMessage *msg);
|
|
||||||
|
|
||||||
static bool
|
|
||||||
cdbus_process_win_get(session_t *ps, DBusMessage *msg);
|
|
||||||
|
|
||||||
static bool
|
|
||||||
cdbus_process_win_set(session_t *ps, DBusMessage *msg);
|
|
||||||
|
|
||||||
static bool
|
|
||||||
cdbus_process_find_win(session_t *ps, DBusMessage *msg);
|
|
||||||
|
|
||||||
static bool
|
|
||||||
cdbus_process_opts_get(session_t *ps, DBusMessage *msg);
|
|
||||||
|
|
||||||
static bool
|
|
||||||
cdbus_process_opts_set(session_t *ps, DBusMessage *msg);
|
|
||||||
|
|
||||||
static bool
|
|
||||||
cdbus_process_introspect(session_t *ps, DBusMessage *msg);
|
|
||||||
|
|
||||||
///@}
|
///@}
|
||||||
|
|
Loading…
Reference in New Issue