Merge pull request #111 from yshui/winstate-refactor
Window state tracking refactor
This commit is contained in:
commit
ecb3050eaa
|
@ -3,11 +3,11 @@
|
|||
#include <xcb/xcb.h>
|
||||
|
||||
#include "backend.h"
|
||||
#include "config.h"
|
||||
#include "win.h"
|
||||
#include "region.h"
|
||||
#include "common.h"
|
||||
#include "compiler.h"
|
||||
#include "config.h"
|
||||
#include "region.h"
|
||||
#include "win.h"
|
||||
|
||||
backend_info_t *backend_list[NUM_BKEND] = {
|
||||
[BKEND_XRENDER] = &xrender_backend,
|
||||
|
@ -107,8 +107,7 @@ void paint_all_new(session_t *ps, win *const t, bool ignore_damage) {
|
|||
®_noframe);
|
||||
pixman_region32_fini(®_noframe);
|
||||
}
|
||||
bi->blur(ps->backend_data, ps,
|
||||
(double)w->opacity / OPAQUE, ®_blur);
|
||||
bi->blur(ps->backend_data, ps, w->opacity, ®_blur);
|
||||
pixman_region32_fini(®_blur);
|
||||
}
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ static void compose(void *backend_data, session_t *ps, win *w, void *win_data, i
|
|||
bool blend = default_is_frame_transparent(NULL, w, win_data) ||
|
||||
default_is_win_transparent(NULL, w, win_data);
|
||||
int op = (blend ? XCB_RENDER_PICT_OP_OVER : XCB_RENDER_PICT_OP_SRC);
|
||||
auto alpha_pict = xd->alpha_pict[(int)(((double)w->opacity / OPAQUE) * 255.0)];
|
||||
auto alpha_pict = xd->alpha_pict[(int)(w->opacity * 255.0)];
|
||||
|
||||
// XXX Move shadow drawing into a separate function,
|
||||
// also do shadow excluding outside of backend
|
||||
|
@ -290,7 +290,6 @@ render_win(void *backend_data, session_t *ps, win *w, void *win_data, const regi
|
|||
0, 0, 0, 0, w->widthb, w->heightb);
|
||||
}
|
||||
|
||||
const double dopacity = get_opacity_percent(w);
|
||||
if (w->frame_opacity != 1) {
|
||||
// Handle transparent frame
|
||||
// Step 1: clip paint area to frame
|
||||
|
@ -303,7 +302,7 @@ render_win(void *backend_data, session_t *ps, win *w, void *win_data, const regi
|
|||
|
||||
// Draw the frame with frame opacity
|
||||
xcb_render_picture_t alpha_pict =
|
||||
xd->alpha_pict[(int)(w->frame_opacity * dopacity * 255)];
|
||||
xd->alpha_pict[(int)(w->frame_opacity * w->opacity * 255)];
|
||||
x_set_picture_clip_region(ps->c, wd->rendered_pict, 0, 0, &frame_reg);
|
||||
|
||||
// Step 2: multiply alpha value
|
||||
|
@ -317,7 +316,7 @@ render_win(void *backend_data, session_t *ps, win *w, void *win_data, const regi
|
|||
|
||||
double dim_opacity = ps->o.inactive_dim;
|
||||
if (!ps->o.inactive_dim_fixed)
|
||||
dim_opacity *= get_opacity_percent(w);
|
||||
dim_opacity *= w->opacity;
|
||||
|
||||
xcb_render_color_t color = {
|
||||
.red = 0, .green = 0, .blue = 0, .alpha = 0xffff * dim_opacity};
|
||||
|
|
20
src/c2.c
20
src/c2.c
|
@ -353,7 +353,7 @@ static xcb_atom_t
|
|||
c2_get_atom_type(const c2_l_t *pleaf);
|
||||
|
||||
static bool
|
||||
c2_match_once(session_t *ps, win *w, const c2_ptr_t cond);
|
||||
c2_match_once(session_t *ps, const win *w, const c2_ptr_t cond);
|
||||
|
||||
/**
|
||||
* Parse a condition string.
|
||||
|
@ -1365,7 +1365,7 @@ c2_get_atom_type(const c2_l_t *pleaf) {
|
|||
* For internal use.
|
||||
*/
|
||||
static inline void
|
||||
c2_match_once_leaf(session_t *ps, win *w, const c2_l_t *pleaf,
|
||||
c2_match_once_leaf(session_t *ps, const win *w, const c2_l_t *pleaf,
|
||||
bool *pres, bool *perr) {
|
||||
assert(pleaf);
|
||||
|
||||
|
@ -1567,7 +1567,7 @@ c2_match_once_leaf(session_t *ps, win *w, const c2_l_t *pleaf,
|
|||
* @return true if matched, false otherwise.
|
||||
*/
|
||||
static bool
|
||||
c2_match_once(session_t *ps, win *w, const c2_ptr_t cond) {
|
||||
c2_match_once(session_t *ps, const win *w, const c2_ptr_t cond) {
|
||||
bool result = false;
|
||||
bool error = true;
|
||||
|
||||
|
@ -1644,22 +1644,10 @@ c2_match_once(session_t *ps, win *w, const c2_ptr_t cond) {
|
|||
* @return true if matched, false otherwise.
|
||||
*/
|
||||
bool
|
||||
c2_match(session_t *ps, win *w, const c2_lptr_t *condlst,
|
||||
const c2_lptr_t **cache, void **pdata) {
|
||||
assert(w->a.map_state == XCB_MAP_STATE_VIEWABLE);
|
||||
|
||||
// Check if the cached entry matches firstly
|
||||
if (cache && *cache && c2_match_once(ps, w, (*cache)->ptr)) {
|
||||
if (pdata)
|
||||
*pdata = (*cache)->data;
|
||||
return true;
|
||||
}
|
||||
|
||||
c2_match(session_t *ps, const win *w, const c2_lptr_t *condlst, void **pdata) {
|
||||
// Then go through the whole linked list
|
||||
for (; condlst; condlst = condlst->next) {
|
||||
if (c2_match_once(ps, w, condlst->ptr)) {
|
||||
if (cache)
|
||||
*cache = condlst;
|
||||
if (pdata)
|
||||
*pdata = condlst->data;
|
||||
return true;
|
||||
|
|
3
src/c2.h
3
src/c2.h
|
@ -21,7 +21,6 @@ c2_lptr_t *c2_parse(c2_lptr_t **pcondlst, const char *pattern, void *data);
|
|||
|
||||
c2_lptr_t *c2_free_lptr(c2_lptr_t *lp);
|
||||
|
||||
bool c2_match(session_t *ps, win *w, const c2_lptr_t *condlst, const c2_lptr_t **cache,
|
||||
void **pdata);
|
||||
bool c2_match(session_t *ps, const win *w, const c2_lptr_t *condlst, void **pdata);
|
||||
|
||||
bool c2_list_postprocess(session_t *ps, c2_lptr_t *list);
|
||||
|
|
15
src/common.h
15
src/common.h
|
@ -98,7 +98,6 @@
|
|||
#define ROUNDED_PERCENT 0.05
|
||||
#define ROUNDED_PIXELS 10
|
||||
|
||||
#define OPAQUE 0xffffffff
|
||||
#define REGISTER_PROP "_NET_WM_CM_S"
|
||||
|
||||
#define TIME_MS_MAX LONG_MAX
|
||||
|
@ -371,9 +370,6 @@ typedef struct session {
|
|||
bool tmout_unredir_hit;
|
||||
/// Whether we need to redraw the screen
|
||||
bool redraw_needed;
|
||||
/// Whether the program is idling. I.e. no fading, no potential window
|
||||
/// changes.
|
||||
bool fade_running;
|
||||
/// Program start time.
|
||||
struct timeval time_start;
|
||||
/// The region needs to painted on next paint.
|
||||
|
@ -687,11 +683,6 @@ timespec_subtract(struct timespec *result,
|
|||
return x->tv_sec < y->tv_sec;
|
||||
}
|
||||
|
||||
static inline double
|
||||
get_opacity_percent(win *w) {
|
||||
return ((double) w->opacity) / OPAQUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current time in struct timeval.
|
||||
*/
|
||||
|
@ -792,9 +783,10 @@ find_win(session_t *ps, xcb_window_t id) {
|
|||
win *w;
|
||||
|
||||
for (w = ps->list; w; w = w->next) {
|
||||
if (w->id == id && !w->destroying)
|
||||
if (w->id == id && w->state != WSTATE_DESTROYING) {
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -811,9 +803,10 @@ find_toplevel(session_t *ps, xcb_window_t id) {
|
|||
return NULL;
|
||||
|
||||
for (win *w = ps->list; w; w = w->next) {
|
||||
if (w->client_win == id && !w->destroying)
|
||||
if (w->client_win == id && w->state != WSTATE_DESTROYING) {
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#define auto __auto_type
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#define likely_if(x) if (likely(x))
|
||||
#define unlikely_if(x) if (unlikely(x))
|
||||
|
||||
#ifndef __has_attribute
|
||||
# if __GNUC__ >= 4
|
||||
|
|
468
src/compton.c
468
src/compton.c
|
@ -59,12 +59,6 @@
|
|||
(session_t *)((char *)__mptr - offsetof(session_t, member)); \
|
||||
})
|
||||
|
||||
static void
|
||||
finish_destroy_win(session_t *ps, win **_w);
|
||||
|
||||
static void
|
||||
configure_win(session_t *ps, xcb_configure_notify_event_t *ce);
|
||||
|
||||
static void
|
||||
update_refresh_rate(session_t *ps);
|
||||
|
||||
|
@ -91,9 +85,6 @@ redir_stop(session_t *ps);
|
|||
static win *
|
||||
recheck_focus(session_t *ps);
|
||||
|
||||
static double
|
||||
get_opacity_percent(win *w);
|
||||
|
||||
static void
|
||||
restack_win(session_t *ps, win *w, xcb_window_t new_above);
|
||||
|
||||
|
@ -169,25 +160,6 @@ free_xinerama_info(session_t *ps) {
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy all resources in a <code>struct _win</code>.
|
||||
*/
|
||||
static inline void
|
||||
free_win_res(session_t *ps, win *w) {
|
||||
free_win_res_glx(ps, w);
|
||||
free_paint(ps, &w->paint);
|
||||
pixman_region32_fini(&w->bounding_shape);
|
||||
free_paint(ps, &w->shadow_paint);
|
||||
// BadDamage may be thrown if the window is destroyed
|
||||
set_ignore_cookie(ps,
|
||||
xcb_damage_destroy(ps->c, w->damage));
|
||||
rc_region_unref(&w->reg_ignore);
|
||||
free(w->name);
|
||||
free(w->class_instance);
|
||||
free(w->class_general);
|
||||
free(w->role);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current system clock in milliseconds.
|
||||
*/
|
||||
|
@ -200,35 +172,6 @@ get_time_ms(void) {
|
|||
return tv.tv_sec % SEC_WRAP * 1000 + tv.tv_usec / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Xinerama screen a window is on.
|
||||
*
|
||||
* Return an index >= 0, or -1 if not found.
|
||||
*
|
||||
* XXX move to x.c
|
||||
*/
|
||||
static inline void
|
||||
cxinerama_win_upd_scr(session_t *ps, win *w) {
|
||||
#ifdef CONFIG_XINERAMA
|
||||
w->xinerama_scr = -1;
|
||||
|
||||
if (!ps->xinerama_scrs)
|
||||
return;
|
||||
|
||||
xcb_xinerama_screen_info_t *scrs = xcb_xinerama_query_screens_screen_info(ps->xinerama_scrs);
|
||||
int length = xcb_xinerama_query_screens_screen_info_length(ps->xinerama_scrs);
|
||||
for (int i = 0; i < length; i++) {
|
||||
xcb_xinerama_screen_info_t *s = &scrs[i];
|
||||
if (s->x_org <= w->g.x && s->y_org <= w->g.y
|
||||
&& s->x_org + s->width >= w->g.x + w->widthb
|
||||
&& s->y_org + s->height >= w->g.y + w->heightb) {
|
||||
w->xinerama_scr = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// XXX Move to x.c
|
||||
static void
|
||||
cxinerama_upd_scrs(session_t *ps) {
|
||||
|
@ -334,34 +277,48 @@ fade_timeout(session_t *ps) {
|
|||
* Run fading on a window.
|
||||
*
|
||||
* @param steps steps of fading
|
||||
* @return whether we are still in fading mode
|
||||
*/
|
||||
static void
|
||||
run_fade(session_t *ps, win *w, unsigned steps) {
|
||||
// If we have reached target opacity, return
|
||||
if (w->opacity == w->opacity_tgt) {
|
||||
return;
|
||||
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 (!w->fade)
|
||||
if (!win_should_fade(ps, w)) {
|
||||
log_debug("Window %#010x %s doesn't need fading", w->id, w->name);
|
||||
w->opacity = w->opacity_tgt;
|
||||
else if (steps) {
|
||||
// Use double below because opacity_t will probably overflow during
|
||||
// calculations
|
||||
if (w->opacity < w->opacity_tgt)
|
||||
w->opacity = normalize_d_range(
|
||||
(double) w->opacity + (double) ps->o.fade_in_step * steps,
|
||||
0.0, w->opacity_tgt);
|
||||
else
|
||||
w->opacity = normalize_d_range(
|
||||
(double) w->opacity - (double) ps->o.fade_out_step * steps,
|
||||
w->opacity_tgt, OPAQUE);
|
||||
}
|
||||
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 (w->opacity != w->opacity_tgt) {
|
||||
ps->fade_running = true;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Note even if opacity == opacity_tgt, we still want to run preprocess one last
|
||||
// time to finish state transition. So return true in that case too.
|
||||
return true;
|
||||
}
|
||||
|
||||
// === Error handling ===
|
||||
|
||||
static void
|
||||
|
@ -516,8 +473,11 @@ find_client_win(session_t *ps, xcb_window_t w) {
|
|||
}
|
||||
|
||||
static win *
|
||||
paint_preprocess(session_t *ps, win *list) {
|
||||
paint_preprocess(session_t *ps, win *list, 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;
|
||||
|
@ -539,41 +499,51 @@ paint_preprocess(session_t *ps, win *list) {
|
|||
const bool was_painted = w->to_paint;
|
||||
const opacity_t opacity_old = w->opacity;
|
||||
// Restore flags from last paint if the window is being faded out
|
||||
if (w->a.map_state == XCB_MAP_STATE_UNMAPPED) {
|
||||
// TODO probably should just stop updating window flags when window
|
||||
// is fading out
|
||||
if (w->state == WSTATE_UNMAPPING || w->state == WSTATE_DESTROYING) {
|
||||
win_set_shadow(ps, w, w->shadow_last);
|
||||
w->fade = w->fade_last;
|
||||
win_set_invert_color(ps, w, w->invert_color_last);
|
||||
win_set_blur_background(ps, w, w->blur_background_last);
|
||||
}
|
||||
|
||||
// Update window opacity target and dim state if asked
|
||||
if (WFLAG_OPCT_CHANGE & w->flags) {
|
||||
win_calc_opacity(ps, w);
|
||||
win_calc_dim(ps, w);
|
||||
if (win_should_dim(ps, w) != w->dim) {
|
||||
w->dim = win_should_dim(ps, w);
|
||||
add_damage_from_win(ps, w);
|
||||
}
|
||||
|
||||
// Run fading
|
||||
run_fade(ps, w, steps);
|
||||
if (run_fade(ps, &w, steps)) {
|
||||
*fade_running = true;
|
||||
}
|
||||
|
||||
if (win_has_frame(w))
|
||||
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
|
||||
} else {
|
||||
w->frame_opacity = 1.0;
|
||||
}
|
||||
|
||||
// Update window mode
|
||||
win_determine_mode(ps, w);
|
||||
|
||||
// Destroy all reg_ignore above when frame opaque state changes on
|
||||
// SOLID mode
|
||||
if (was_painted && w->mode != mode_old)
|
||||
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)
|
||||
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();
|
||||
|
@ -603,8 +573,8 @@ paint_preprocess(session_t *ps, win *list) {
|
|||
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->a.map_state == XCB_MAP_STATE_UNMAPPED || w->destroying) && !w->paint.pixmap)
|
||||
|| (double) w->opacity / OPAQUE * MAX_ALPHA < 1
|
||||
|| w->state == WSTATE_UNMAPPED
|
||||
|| (double) w->opacity * MAX_ALPHA < 1
|
||||
|| w->paint_excluded)
|
||||
to_paint = false;
|
||||
//log_trace("%s %d %d %d", w->name, to_paint, w->opacity, w->paint_excluded);
|
||||
|
@ -621,7 +591,7 @@ paint_preprocess(session_t *ps, win *list) {
|
|||
goto skip_window;
|
||||
|
||||
// Calculate shadow opacity
|
||||
w->shadow_opacity = ps->o.shadow_opacity * get_opacity_percent(w) * ps->o.frame_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)
|
||||
|
@ -673,7 +643,6 @@ paint_preprocess(session_t *ps, win *list) {
|
|||
reg_ignore_valid = reg_ignore_valid && w->reg_ignore_valid;
|
||||
w->reg_ignore_valid = true;
|
||||
|
||||
assert(w->destroying == (w->fade_callback == finish_destroy_win));
|
||||
win_check_fade_finished(ps, &w);
|
||||
|
||||
// Avoid setting w->to_paint if w is freed
|
||||
|
@ -683,7 +652,6 @@ paint_preprocess(session_t *ps, win *list) {
|
|||
if (w->to_paint) {
|
||||
// Save flags
|
||||
w->shadow_last = w->shadow;
|
||||
w->fade_last = w->fade;
|
||||
w->invert_color_last = w->invert_color;
|
||||
w->blur_background_last = w->blur_background;
|
||||
}
|
||||
|
@ -693,7 +661,7 @@ paint_preprocess(session_t *ps, win *list) {
|
|||
rc_region_unref(&last_reg_ignore);
|
||||
|
||||
// If possible, unredirect all windows and stop painting
|
||||
if (UNSET != ps->o.redirected_force)
|
||||
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,
|
||||
|
@ -791,170 +759,6 @@ repair_win(session_t *ps, win *w) {
|
|||
add_damage(ps, &parts);
|
||||
pixman_region32_fini(&parts);
|
||||
}
|
||||
|
||||
static void
|
||||
finish_map_win(session_t *ps, win **_w) {
|
||||
win *w = *_w;
|
||||
w->in_openclose = false;
|
||||
if (ps->o.no_fading_openclose) {
|
||||
win_determine_fade(ps, w);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
map_win(session_t *ps, xcb_window_t id) {
|
||||
// Unmap overlay window if it got mapped but we are currently not
|
||||
// in redirected state.
|
||||
if (ps->overlay && id == ps->overlay && !ps->redirected) {
|
||||
auto e = xcb_request_check(ps->c, xcb_unmap_window(ps->c, ps->overlay));
|
||||
if (e) {
|
||||
log_error("Failed to unmap the overlay window");
|
||||
free(e);
|
||||
}
|
||||
// We don't track the overlay window, so we can return
|
||||
return;
|
||||
}
|
||||
|
||||
win *w = find_win(ps, id);
|
||||
|
||||
log_trace("(%#010x \"%s\"): %p", id, (w ? w->name: NULL), w);
|
||||
|
||||
// Don't care about window mapping if it's an InputOnly window
|
||||
// Try avoiding mapping a window twice
|
||||
if (!w || InputOnly == w->a._class
|
||||
|| w->a.map_state == XCB_MAP_STATE_VIEWABLE)
|
||||
return;
|
||||
|
||||
assert(!win_is_focused_real(ps, w));
|
||||
|
||||
w->a.map_state = XCB_MAP_STATE_VIEWABLE;
|
||||
|
||||
cxinerama_win_upd_scr(ps, w);
|
||||
|
||||
// Set window event mask before reading properties so that no property
|
||||
// changes are lost
|
||||
xcb_change_window_attributes(ps->c, id, XCB_CW_EVENT_MASK,
|
||||
(const uint32_t[]) { determine_evmask(ps, id, WIN_EVMODE_FRAME) });
|
||||
|
||||
// Notify compton when the shape of a window changes
|
||||
if (ps->shape_exists) {
|
||||
xcb_shape_select_input(ps->c, id, 1);
|
||||
}
|
||||
|
||||
// Make sure the select input requests are sent
|
||||
x_sync(ps->c);
|
||||
|
||||
// Update window mode here to check for ARGB windows
|
||||
win_determine_mode(ps, w);
|
||||
|
||||
// Detect client window here instead of in add_win() as the client
|
||||
// window should have been prepared at this point
|
||||
if (!w->client_win) {
|
||||
win_recheck_client(ps, w);
|
||||
} else {
|
||||
// Re-mark client window here
|
||||
win_mark_client(ps, w, w->client_win);
|
||||
}
|
||||
|
||||
assert(w->client_win);
|
||||
|
||||
log_trace("(%#010x): type %s", w->id, WINTYPES[w->window_type]);
|
||||
|
||||
// FocusIn/Out may be ignored when the window is unmapped, so we must
|
||||
// recheck focus here
|
||||
if (ps->o.track_focus)
|
||||
recheck_focus(ps);
|
||||
|
||||
// Update window focus state
|
||||
win_update_focused(ps, w);
|
||||
|
||||
// Update opacity and dim state
|
||||
win_update_opacity_prop(ps, w);
|
||||
w->flags |= WFLAG_OPCT_CHANGE;
|
||||
|
||||
// Check for _COMPTON_SHADOW
|
||||
if (ps->o.respect_prop_shadow)
|
||||
win_update_prop_shadow_raw(ps, w);
|
||||
|
||||
// Many things above could affect shadow
|
||||
win_determine_shadow(ps, w);
|
||||
|
||||
// Set fading state
|
||||
w->in_openclose = true;
|
||||
win_set_fade_callback(ps, &w, finish_map_win, true);
|
||||
win_determine_fade(ps, w);
|
||||
|
||||
win_determine_blur_background(ps, w);
|
||||
|
||||
w->ever_damaged = false;
|
||||
|
||||
/* if any configure events happened while
|
||||
the window was unmapped, then configure
|
||||
the window to its correct place */
|
||||
if (w->need_configure)
|
||||
configure_win(ps, &w->queue_configure);
|
||||
|
||||
// We stopped listening on ShapeNotify events
|
||||
// when the window is unmapped (XXX we shouldn't),
|
||||
// so the shape of the window might have changed,
|
||||
// update. (Issue #35)
|
||||
win_update_bounding_shape(ps, w);
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
// Send D-Bus signal
|
||||
if (ps->o.dbus) {
|
||||
cdbus_ev_win_mapped(ps, w);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
finish_unmap_win(session_t *ps, win **_w) {
|
||||
win *w = *_w;
|
||||
w->ever_damaged = false;
|
||||
w->in_openclose = false;
|
||||
w->reg_ignore_valid = false;
|
||||
|
||||
/* damage region */
|
||||
add_damage_from_win(ps, w);
|
||||
|
||||
free_paint(ps, &w->paint);
|
||||
free_paint(ps, &w->shadow_paint);
|
||||
}
|
||||
|
||||
static void
|
||||
unmap_win(session_t *ps, win **_w) {
|
||||
win *w = *_w;
|
||||
if (!w || w->a.map_state == XCB_MAP_STATE_UNMAPPED) return;
|
||||
|
||||
if (w->destroying) return;
|
||||
|
||||
// Set focus out
|
||||
win_set_focused(ps, w, false);
|
||||
|
||||
w->a.map_state = XCB_MAP_STATE_UNMAPPED;
|
||||
|
||||
// Fading out
|
||||
w->flags |= WFLAG_OPCT_CHANGE;
|
||||
win_set_fade_callback(ps, _w, finish_unmap_win, false);
|
||||
w->in_openclose = true;
|
||||
win_determine_fade(ps, w);
|
||||
|
||||
// Validate pixmap if we have to do fading
|
||||
if (w->fade)
|
||||
win_validate_pixmap(ps, w);
|
||||
|
||||
// don't care about properties anymore
|
||||
win_ev_stop(ps, w);
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
// Send D-Bus signal
|
||||
if (ps->o.dbus) {
|
||||
cdbus_ev_win_unmapped(ps, w);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
restack_win(session_t *ps, win *w, xcb_window_t new_above) {
|
||||
xcb_window_t old_above;
|
||||
|
@ -986,7 +790,7 @@ restack_win(session_t *ps, win *w, xcb_window_t new_above) {
|
|||
|
||||
// rehook
|
||||
for (prev = &ps->list; *prev; prev = &(*prev)->next) {
|
||||
if ((*prev)->id == new_above && !(*prev)->destroying) {
|
||||
if ((*prev)->id == new_above && (*prev)->state != WSTATE_DESTROYING) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
@ -1037,7 +841,7 @@ restack_win(session_t *ps, win *w, xcb_window_t new_above) {
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
|
||||
// On root window changes
|
||||
if (ce->window == ps->root) {
|
||||
|
@ -1131,7 +935,7 @@ configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
|
|||
if (factor_change) {
|
||||
win_on_factor_change(ps, w);
|
||||
add_damage(ps, &damage);
|
||||
cxinerama_win_upd_scr(ps, w);
|
||||
win_update_screen(ps, w);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1158,67 +962,6 @@ circulate_win(session_t *ps, xcb_circulate_notify_event_t *ce) {
|
|||
restack_win(ps, w, new_above);
|
||||
}
|
||||
|
||||
// TODO move to win.c
|
||||
static void
|
||||
finish_destroy_win(session_t *ps, win **_w) {
|
||||
win *w = *_w;
|
||||
assert(w->destroying);
|
||||
win **prev = NULL, *i = NULL;
|
||||
|
||||
log_trace("(%#010x): Starting...", w->id);
|
||||
|
||||
for (prev = &ps->list; (i = *prev); prev = &i->next) {
|
||||
if (w == i) {
|
||||
log_trace("(%#010x \"%s\"): %p", w->id, w->name, w);
|
||||
|
||||
finish_unmap_win(ps, _w);
|
||||
*prev = w->next;
|
||||
|
||||
// Clear active_win if it's pointing to the destroyed window
|
||||
if (w == ps->active_win)
|
||||
ps->active_win = NULL;
|
||||
|
||||
free_win_res(ps, w);
|
||||
|
||||
// Drop w from all prev_trans to avoid accessing freed memory in
|
||||
// repair_win()
|
||||
for (win *w2 = ps->list; w2; w2 = w2->next)
|
||||
if (w == w2->prev_trans)
|
||||
w2->prev_trans = NULL;
|
||||
|
||||
free(w);
|
||||
*_w = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_win(session_t *ps, xcb_window_t id) {
|
||||
win *w = find_win(ps, id);
|
||||
|
||||
log_trace("%#010x \"%s\": %p", id, (w ? w->name: NULL), w);
|
||||
|
||||
if (w) {
|
||||
unmap_win(ps, &w);
|
||||
|
||||
w->destroying = true;
|
||||
|
||||
if (ps->o.no_fading_destroyed_argb)
|
||||
win_determine_fade(ps, w);
|
||||
|
||||
// Set fading callback
|
||||
win_set_fade_callback(ps, &w, finish_destroy_win, false);
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
// Send D-Bus signal
|
||||
if (ps->o.dbus) {
|
||||
cdbus_ev_win_destroyed(ps, w);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
root_damaged(session_t *ps) {
|
||||
if (ps->root_tile_paint.pixmap) {
|
||||
|
@ -1284,14 +1027,12 @@ win_set_shadow_force(session_t *ps, win *w, switch_t val) {
|
|||
|
||||
/**
|
||||
* Set w->fade_force of a window.
|
||||
*
|
||||
* Doesn't affect fading already in progress
|
||||
*/
|
||||
void
|
||||
win_set_fade_force(session_t *ps, win *w, switch_t val) {
|
||||
if (val != w->fade_force) {
|
||||
w->fade_force = val;
|
||||
win_determine_fade(ps, w);
|
||||
queue_redraw(ps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1343,15 +1084,12 @@ opts_init_track_focus(session_t *ps) {
|
|||
|
||||
/**
|
||||
* Set no_fading_openclose option.
|
||||
*
|
||||
* Don't affect fading already in progress
|
||||
*/
|
||||
void
|
||||
opts_set_no_fading_openclose(session_t *ps, bool newval) {
|
||||
if (newval != ps->o.no_fading_openclose) {
|
||||
ps->o.no_fading_openclose = newval;
|
||||
for (win *w = ps->list; w; w = w->next)
|
||||
win_determine_fade(ps, w);
|
||||
queue_redraw(ps);
|
||||
}
|
||||
}
|
||||
|
||||
//!@}
|
||||
|
@ -1518,20 +1256,28 @@ ev_configure_notify(session_t *ps, xcb_configure_notify_event_t *ev) {
|
|||
|
||||
inline static void
|
||||
ev_destroy_notify(session_t *ps, xcb_destroy_notify_event_t *ev) {
|
||||
destroy_win(ps, ev->window);
|
||||
win *w = find_win(ps, ev->window);
|
||||
if (w) {
|
||||
unmap_win(ps, &w, true);
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
ev_map_notify(session_t *ps, xcb_map_notify_event_t *ev) {
|
||||
map_win(ps, ev->window);
|
||||
// FocusIn/Out may be ignored when the window is unmapped, so we must
|
||||
// recheck focus here
|
||||
if (ps->o.track_focus) {
|
||||
recheck_focus(ps);
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
ev_unmap_notify(session_t *ps, xcb_unmap_notify_event_t *ev) {
|
||||
win *w = find_win(ps, ev->window);
|
||||
|
||||
if (w)
|
||||
unmap_win(ps, &w);
|
||||
if (w) {
|
||||
unmap_win(ps, &w, false);
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
|
@ -1540,9 +1286,14 @@ ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t *ev) {
|
|||
ev->parent, ev->override_redirect);
|
||||
|
||||
if (ev->parent == ps->root) {
|
||||
// new window
|
||||
add_win(ps, ev->window, 0);
|
||||
} else {
|
||||
destroy_win(ps, ev->window);
|
||||
// otherwise, find and destroy the window first
|
||||
win *w = find_win(ps, ev->window);
|
||||
if (w) {
|
||||
unmap_win(ps, &w, true);
|
||||
}
|
||||
|
||||
// Reset event mask in case something wrong happens
|
||||
xcb_change_window_attributes(ps->c, ev->window, XCB_CW_EVENT_MASK,
|
||||
|
@ -1687,7 +1438,13 @@ ev_property_notify(session_t *ps, xcb_property_notify_event_t *ev) {
|
|||
win *w = find_win(ps, ev->window) ?: find_toplevel(ps, ev->window);
|
||||
if (w) {
|
||||
win_update_opacity_prop(ps, w);
|
||||
w->flags |= WFLAG_OPCT_CHANGE;
|
||||
// we cannot receive OPACITY change when window is destroyed
|
||||
assert(w->state != WSTATE_DESTROYING);
|
||||
if (w->state == WSTATE_MAPPED) {
|
||||
// See the winstate_t transition table
|
||||
w->state = WSTATE_FADING;
|
||||
}
|
||||
w->opacity_tgt = win_get_opacity_target(ps, w);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2228,7 +1985,7 @@ init_overlay(session_t *ps) {
|
|||
static void
|
||||
redir_start(session_t *ps) {
|
||||
if (!ps->redirected) {
|
||||
log_trace("Screen redirected.");
|
||||
log_debug("Screen redirected.");
|
||||
|
||||
// Map overlay window. Done firstly according to this:
|
||||
// https://bugzilla.gnome.org/show_bug.cgi?id=597014
|
||||
|
@ -2262,7 +2019,7 @@ redir_start(session_t *ps) {
|
|||
static void
|
||||
redir_stop(session_t *ps) {
|
||||
if (ps->redirected) {
|
||||
log_trace("Screen unredirected.");
|
||||
log_debug("Screen unredirected.");
|
||||
// Destroy all Pictures as they expire once windows are unredirected
|
||||
// If we don't destroy them here, looks like the resources are just
|
||||
// kept inaccessible somehow
|
||||
|
@ -2337,14 +2094,14 @@ _draw_callback(EV_P_ session_t *ps, int revents) {
|
|||
}
|
||||
}
|
||||
|
||||
ps->fade_running = false;
|
||||
win *t = paint_preprocess(ps, ps->list);
|
||||
bool fade_running = false;
|
||||
win *t = paint_preprocess(ps, ps->list, &fade_running);
|
||||
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))
|
||||
if (!fade_running && ev_is_active(&ps->fade_timer))
|
||||
ev_timer_stop(ps->loop, &ps->fade_timer);
|
||||
else if (ps->fade_running && !ev_is_active(&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);
|
||||
}
|
||||
|
@ -2359,7 +2116,7 @@ _draw_callback(EV_P_ session_t *ps, int revents) {
|
|||
exit(0);
|
||||
}
|
||||
|
||||
if (!ps->fade_running)
|
||||
if (!fade_running)
|
||||
ps->fade_time = 0L;
|
||||
|
||||
ps->redraw_needed = false;
|
||||
|
@ -2516,16 +2273,16 @@ session_init(int argc, char **argv, Display *dpy, const char *config_file,
|
|||
.respect_prop_shadow = false,
|
||||
.xinerama_shadow_crop = false,
|
||||
|
||||
.fade_in_step = 0.028 * OPAQUE,
|
||||
.fade_out_step = 0.03 * OPAQUE,
|
||||
.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 = OPAQUE,
|
||||
.inactive_opacity = 1.0,
|
||||
.inactive_opacity_override = false,
|
||||
.active_opacity = OPAQUE,
|
||||
.active_opacity = 1.0,
|
||||
.frame_opacity = 1.0,
|
||||
.detect_client_opacity = false,
|
||||
|
||||
|
@ -2552,7 +2309,6 @@ session_init(int argc, char **argv, Display *dpy, const char *config_file,
|
|||
.time_start = { 0, 0 },
|
||||
.redirected = false,
|
||||
.alpha_picts = NULL,
|
||||
.fade_running = false,
|
||||
.fade_time = 0L,
|
||||
.ignore_head = NULL,
|
||||
.ignore_tail = NULL,
|
||||
|
@ -3167,20 +2923,16 @@ session_destroy(session_t *ps) {
|
|||
*/
|
||||
static void
|
||||
session_run(session_t *ps) {
|
||||
win *t;
|
||||
|
||||
if (ps->o.sw_opti)
|
||||
ps->paint_tm_offset = get_time_timeval().tv_usec;
|
||||
|
||||
t = paint_preprocess(ps, ps->list);
|
||||
|
||||
if (ps->redirected)
|
||||
paint_all(ps, t, true);
|
||||
|
||||
// In benchmark mode, we want draw_idle handler to always be active
|
||||
if (ps->o.benchmark)
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -148,14 +148,4 @@ dump_drawable(session_t *ps, xcb_drawable_t drawable) {
|
|||
free(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate pixmap of a window, and destroy pixmap and picture if invalid.
|
||||
*/
|
||||
static inline void
|
||||
win_validate_pixmap(session_t *ps, win *w) {
|
||||
// Destroy pixmap and picture, if invalid
|
||||
if (!x_validate_pixmap(ps->c, w->paint.pixmap))
|
||||
free_paint(ps, &w->paint);
|
||||
}
|
||||
|
||||
// vim: set et sw=2 :
|
||||
|
|
11
src/config.h
11
src/config.h
|
@ -167,9 +167,9 @@ typedef struct options_t {
|
|||
|
||||
// === Fading ===
|
||||
/// How much to fade in in a single fading step.
|
||||
opacity_t fade_in_step;
|
||||
double fade_in_step;
|
||||
/// How much to fade out in a single fading step.
|
||||
opacity_t fade_out_step;
|
||||
double fade_out_step;
|
||||
/// Fading time delta. In milliseconds.
|
||||
unsigned long fade_delta;
|
||||
/// Whether to disable fading on window open/close.
|
||||
|
@ -181,11 +181,10 @@ typedef struct options_t {
|
|||
|
||||
// === Opacity ===
|
||||
/// Default opacity for inactive windows.
|
||||
/// 32-bit integer with the format of _NET_WM_OPACITY. 0 stands for
|
||||
/// not enabled, default.
|
||||
opacity_t inactive_opacity;
|
||||
/// 32-bit integer with the format of _NET_WM_OPACITY.
|
||||
double inactive_opacity;
|
||||
/// Default opacity for inactive windows.
|
||||
opacity_t active_opacity;
|
||||
double active_opacity;
|
||||
/// Whether inactive_opacity overrides the opacity set by window
|
||||
/// attributes.
|
||||
bool inactive_opacity_override;
|
||||
|
|
|
@ -218,10 +218,10 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
|
|||
opt->fade_delta = ival;
|
||||
// -I (fade_in_step)
|
||||
if (config_lookup_float(&cfg, "fade-in-step", &dval))
|
||||
opt->fade_in_step = normalize_d(dval) * OPAQUE;
|
||||
opt->fade_in_step = normalize_d(dval);
|
||||
// -O (fade_out_step)
|
||||
if (config_lookup_float(&cfg, "fade-out-step", &dval))
|
||||
opt->fade_out_step = normalize_d(dval) * OPAQUE;
|
||||
opt->fade_out_step = normalize_d(dval);
|
||||
// -r (shadow_radius)
|
||||
config_lookup_int(&cfg, "shadow-radius", &opt->shadow_radius);
|
||||
// -o (shadow_opacity)
|
||||
|
@ -232,10 +232,10 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
|
|||
config_lookup_int(&cfg, "shadow-offset-y", &opt->shadow_offset_y);
|
||||
// -i (inactive_opacity)
|
||||
if (config_lookup_float(&cfg, "inactive-opacity", &dval))
|
||||
opt->inactive_opacity = normalize_d(dval) * OPAQUE;
|
||||
opt->inactive_opacity = normalize_d(dval);
|
||||
// --active_opacity
|
||||
if (config_lookup_float(&cfg, "active-opacity", &dval))
|
||||
opt->active_opacity = normalize_d(dval) * OPAQUE;
|
||||
opt->active_opacity = normalize_d(dval);
|
||||
// -e (frame_opacity)
|
||||
config_lookup_float(&cfg, "frame-opacity", &opt->frame_opacity);
|
||||
// -c (shadow_enable)
|
||||
|
|
11
src/dbus.c
11
src/dbus.c
|
@ -493,9 +493,10 @@ cdbus_apdarg_wids(session_t *ps, DBusMessage *msg, const void *data) {
|
|||
// Get the number of wids we are to include
|
||||
unsigned count = 0;
|
||||
for (win *w = ps->list; w; w = w->next) {
|
||||
if (!w->destroying)
|
||||
if (w->state != WSTATE_DESTROYING) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
// Nothing to append
|
||||
|
@ -509,7 +510,7 @@ cdbus_apdarg_wids(session_t *ps, DBusMessage *msg, const void *data) {
|
|||
{
|
||||
cdbus_window_t *pcur = arr;
|
||||
for (win *w = ps->list; w; w = w->next) {
|
||||
if (!w->destroying) {
|
||||
if (w->state != WSTATE_DESTROYING) {
|
||||
*pcur = w->id;
|
||||
++pcur;
|
||||
assert(pcur <= arr + count);
|
||||
|
@ -812,7 +813,6 @@ cdbus_process_win_get(session_t *ps, DBusMessage *msg) {
|
|||
cdbus_m_win_get_do(mode, cdbus_reply_enum);
|
||||
cdbus_m_win_get_do(client_win, cdbus_reply_wid);
|
||||
cdbus_m_win_get_do(ever_damaged, cdbus_reply_bool);
|
||||
cdbus_m_win_get_do(destroying, cdbus_reply_bool);
|
||||
cdbus_m_win_get_do(window_type, cdbus_reply_enum);
|
||||
cdbus_m_win_get_do(wmwin, cdbus_reply_bool);
|
||||
cdbus_m_win_get_do(leader, cdbus_reply_wid);
|
||||
|
@ -856,7 +856,6 @@ cdbus_process_win_get(session_t *ps, DBusMessage *msg) {
|
|||
}
|
||||
|
||||
cdbus_m_win_get_do(shadow, cdbus_reply_bool);
|
||||
cdbus_m_win_get_do(fade, cdbus_reply_bool);
|
||||
cdbus_m_win_get_do(invert_color, cdbus_reply_bool);
|
||||
cdbus_m_win_get_do(blur_background, cdbus_reply_bool);
|
||||
#undef cdbus_m_win_get_do
|
||||
|
@ -1140,7 +1139,7 @@ cdbus_process_opts_set(session_t *ps, DBusMessage *msg) {
|
|||
double val = 0.0;
|
||||
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_DOUBLE, &val))
|
||||
return false;
|
||||
ps->o.fade_in_step = normalize_d(val) * OPAQUE;
|
||||
ps->o.fade_in_step = normalize_d(val);
|
||||
goto cdbus_process_opts_set_success;
|
||||
}
|
||||
|
||||
|
@ -1149,7 +1148,7 @@ cdbus_process_opts_set(session_t *ps, DBusMessage *msg) {
|
|||
double val = 0.0;
|
||||
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_DOUBLE, &val))
|
||||
return false;
|
||||
ps->o.fade_out_step = normalize_d(val) * OPAQUE;
|
||||
ps->o.fade_out_step = normalize_d(val);
|
||||
goto cdbus_process_opts_set_success;
|
||||
}
|
||||
|
||||
|
|
|
@ -570,8 +570,8 @@ void get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
|
|||
// These options are handled by get_early_config()
|
||||
break;
|
||||
P_CASELONG('D', fade_delta);
|
||||
case 'I': opt->fade_in_step = normalize_d(atof(optarg)) * OPAQUE; break;
|
||||
case 'O': opt->fade_out_step = normalize_d(atof(optarg)) * OPAQUE; break;
|
||||
case 'I': opt->fade_in_step = normalize_d(atof(optarg)); break;
|
||||
case 'O': opt->fade_out_step = normalize_d(atof(optarg)); break;
|
||||
case 'c': shadow_enable = true; break;
|
||||
case 'C':
|
||||
winopt_mask[WINTYPE_DOCK].shadow = true;
|
||||
|
@ -600,7 +600,7 @@ void get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
|
|||
P_CASELONG('l', shadow_offset_x);
|
||||
P_CASELONG('t', shadow_offset_y);
|
||||
case 'i':
|
||||
opt->inactive_opacity = (normalize_d(atof(optarg)) * OPAQUE);
|
||||
opt->inactive_opacity = normalize_d(atof(optarg));
|
||||
break;
|
||||
case 'e': opt->frame_opacity = atof(optarg); break;
|
||||
case 'z':
|
||||
|
@ -718,7 +718,7 @@ void get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
|
|||
break;
|
||||
case 297:
|
||||
// --active-opacity
|
||||
opt->active_opacity = (normalize_d(atof(optarg)) * OPAQUE);
|
||||
opt->active_opacity = normalize_d(atof(optarg));
|
||||
break;
|
||||
P_CASEBOOL(298, glx_no_rebind_pixmap);
|
||||
case 299:
|
||||
|
|
12
src/render.c
12
src/render.c
|
@ -307,10 +307,8 @@ void paint_one(session_t *ps, win *w, const region_t *reg_paint) {
|
|||
}
|
||||
}
|
||||
|
||||
const double dopacity = get_opacity_percent(w);
|
||||
|
||||
if (w->frame_opacity == 1) {
|
||||
paint_region(ps, w, 0, 0, wid, hei, dopacity, reg_paint, pict);
|
||||
paint_region(ps, w, 0, 0, wid, hei, w->opacity, reg_paint, pict);
|
||||
} else {
|
||||
// Painting parameters
|
||||
const margin_t extents = win_calc_frame_extents(w);
|
||||
|
@ -320,7 +318,7 @@ void paint_one(session_t *ps, win *w, const region_t *reg_paint) {
|
|||
const int r = extents.right;
|
||||
|
||||
#define COMP_BDR(cx, cy, cwid, chei) \
|
||||
paint_region(ps, w, (cx), (cy), (cwid), (chei), w->frame_opacity *dopacity, \
|
||||
paint_region(ps, w, (cx), (cy), (cwid), (chei), w->frame_opacity * w->opacity, \
|
||||
reg_paint, pict)
|
||||
|
||||
// Sanitize the margins, in case some broken WM makes
|
||||
|
@ -372,7 +370,7 @@ void paint_one(session_t *ps, win *w, const region_t *reg_paint) {
|
|||
|
||||
// body
|
||||
paint_region(ps, w, cleft, ctop, body_width, body_height,
|
||||
dopacity, reg_paint, pict);
|
||||
w->opacity, reg_paint, pict);
|
||||
} while (0);
|
||||
}
|
||||
|
||||
|
@ -385,7 +383,7 @@ void paint_one(session_t *ps, win *w, const region_t *reg_paint) {
|
|||
if (w->dim) {
|
||||
double dim_opacity = ps->o.inactive_dim;
|
||||
if (!ps->o.inactive_dim_fixed)
|
||||
dim_opacity *= get_opacity_percent(w);
|
||||
dim_opacity *= w->opacity;
|
||||
|
||||
switch (ps->o.backend) {
|
||||
case BKEND_XRENDER:
|
||||
|
@ -678,7 +676,7 @@ static inline void win_blur_background(session_t *ps, win *w, xcb_render_picture
|
|||
// Adjust blur strength according to window opacity, to make it appear
|
||||
// better during fading
|
||||
if (!ps->o.blur_background_fixed) {
|
||||
double pct = 1.0 - get_opacity_percent(w) * (1.0 - 1.0 / 9.0);
|
||||
double pct = 1.0 - w->opacity * (1.0 - 1.0 / 9.0);
|
||||
factor_center = pct * 8.0 / (1.1 - pct);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
/// Enumeration type to represent switches.
|
||||
typedef enum {
|
||||
OFF, // false
|
||||
OFF = 0, // false
|
||||
ON, // true
|
||||
UNSET
|
||||
} switch_t;
|
||||
|
|
462
src/win.c
462
src/win.c
|
@ -30,8 +30,15 @@
|
|||
#include "dbus.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OPENGL
|
||||
// TODO remove this include
|
||||
#include "opengl.h"
|
||||
#endif
|
||||
|
||||
#include "win.h"
|
||||
|
||||
#define OPAQUE 0xffffffff
|
||||
|
||||
/// Generate a "return by value" function, from a function that returns the
|
||||
/// region via a region_t pointer argument.
|
||||
/// Function signature has to be (win *, region_t *)
|
||||
|
@ -74,7 +81,7 @@ group_update_focused(session_t *ps, xcb_window_t leader) {
|
|||
return;
|
||||
|
||||
for (win *w = ps->list; w; w = w->next) {
|
||||
if (win_get_leader(ps, w) == leader && !w->destroying)
|
||||
if (win_get_leader(ps, w) == leader && w->state != WSTATE_DESTROYING)
|
||||
win_update_focused(ps, w);
|
||||
}
|
||||
|
||||
|
@ -93,7 +100,7 @@ group_is_focused(session_t *ps, xcb_window_t leader) {
|
|||
return false;
|
||||
|
||||
for (win *w = ps->list; w; w = w->next) {
|
||||
if (win_get_leader(ps, w) == leader && !w->destroying
|
||||
if (win_get_leader(ps, w) == leader && w->state != WSTATE_DESTROYING
|
||||
&& win_is_focused_real(ps, w))
|
||||
return true;
|
||||
}
|
||||
|
@ -292,14 +299,14 @@ bool wid_get_opacity_prop(session_t *ps, xcb_window_t wid, opacity_t def,
|
|||
}
|
||||
|
||||
// XXX should distinguish between frame has alpha and window body has alpha
|
||||
bool win_has_alpha(win *w) {
|
||||
bool win_has_alpha(const win *w) {
|
||||
return w->pictfmt &&
|
||||
w->pictfmt->type == XCB_RENDER_PICT_TYPE_DIRECT &&
|
||||
w->pictfmt->direct.alpha_mask;
|
||||
}
|
||||
|
||||
void win_determine_mode(session_t *ps, win *w) {
|
||||
if (win_has_alpha(w) || w->opacity != OPAQUE) {
|
||||
if (win_has_alpha(w) || w->opacity < 1.0) {
|
||||
w->mode = WMODE_TRANS;
|
||||
} else if (w->frame_opacity != 1.0) {
|
||||
w->mode = WMODE_FRAME_TRANS;
|
||||
|
@ -309,7 +316,7 @@ void win_determine_mode(session_t *ps, win *w) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Calculate and set the opacity of a window.
|
||||
* Calculate and return the opacity target of a window.
|
||||
*
|
||||
* If window is inactive and inactive_opacity_override is set, the
|
||||
* priority is: (Simulates the old behavior)
|
||||
|
@ -325,78 +332,81 @@ void win_determine_mode(session_t *ps, win *w) {
|
|||
*
|
||||
* @param ps current session
|
||||
* @param w struct _win object representing the window
|
||||
*
|
||||
* @return target opacity
|
||||
*/
|
||||
void win_calc_opacity(session_t *ps, win *w) {
|
||||
opacity_t opacity = OPAQUE;
|
||||
double win_get_opacity_target(session_t *ps, const win *w) {
|
||||
double opacity = 1;
|
||||
|
||||
if (w->destroying || w->a.map_state != XCB_MAP_STATE_VIEWABLE)
|
||||
opacity = 0;
|
||||
else {
|
||||
if (w->state == WSTATE_UNMAPPED) {
|
||||
// be consistent
|
||||
return 0;
|
||||
}
|
||||
if (w->state == WSTATE_UNMAPPING || w->state == WSTATE_DESTROYING) {
|
||||
return 0;
|
||||
}
|
||||
// Try obeying opacity property and window type opacity firstly
|
||||
if (w->has_opacity_prop)
|
||||
opacity = w->opacity_prop;
|
||||
else if (!safe_isnan(ps->o.wintype_option[w->window_type].opacity))
|
||||
opacity = ps->o.wintype_option[w->window_type].opacity * OPAQUE;
|
||||
else {
|
||||
if (w->has_opacity_prop) {
|
||||
opacity = ((double)w->opacity_prop) / OPAQUE;
|
||||
} else if (!safe_isnan(ps->o.wintype_option[w->window_type].opacity)) {
|
||||
opacity = ps->o.wintype_option[w->window_type].opacity;
|
||||
} else {
|
||||
// Respect active_opacity only when the window is physically focused
|
||||
if (win_is_focused_real(ps, w))
|
||||
opacity = ps->o.active_opacity;
|
||||
else if (false == w->focused)
|
||||
else if (!w->focused)
|
||||
// Respect inactive_opacity in some cases
|
||||
opacity = ps->o.inactive_opacity;
|
||||
}
|
||||
|
||||
// respect inactive override
|
||||
if (ps->o.inactive_opacity_override && false == w->focused)
|
||||
if (ps->o.inactive_opacity_override && !w->focused)
|
||||
opacity = ps->o.inactive_opacity;
|
||||
}
|
||||
|
||||
w->opacity_tgt = opacity;
|
||||
return opacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a window is to be dimmed.
|
||||
*/
|
||||
void win_calc_dim(session_t *ps, win *w) {
|
||||
bool dim;
|
||||
|
||||
bool win_should_dim(session_t *ps, const win *w) {
|
||||
// Make sure we do nothing if the window is unmapped / being destroyed
|
||||
if (w->destroying || w->a.map_state != XCB_MAP_STATE_VIEWABLE)
|
||||
return;
|
||||
|
||||
if (ps->o.inactive_dim && !(w->focused)) {
|
||||
dim = true;
|
||||
} else {
|
||||
dim = false;
|
||||
if (w->state == WSTATE_UNMAPPED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dim != w->dim) {
|
||||
w->dim = dim;
|
||||
add_damage_from_win(ps, w);
|
||||
if (ps->o.inactive_dim && !(w->focused)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a window should fade on opacity change.
|
||||
*/
|
||||
void win_determine_fade(session_t *ps, win *w) {
|
||||
bool win_should_fade(session_t *ps, const win *w) {
|
||||
// To prevent it from being overwritten by last-paint value if the window is
|
||||
// unmapped on next frame, write w->fade_last as well
|
||||
if (UNSET != w->fade_force)
|
||||
w->fade_last = w->fade = w->fade_force;
|
||||
else if (ps->o.no_fading_openclose && w->in_openclose)
|
||||
w->fade_last = w->fade = false;
|
||||
else if (ps->o.no_fading_destroyed_argb && w->destroying &&
|
||||
if (w->fade_force != UNSET) {
|
||||
return w->fade_force;
|
||||
}
|
||||
if (ps->o.no_fading_openclose && w->in_openclose) {
|
||||
return false;
|
||||
}
|
||||
if (ps->o.no_fading_destroyed_argb && w->state == WSTATE_DESTROYING &&
|
||||
win_has_alpha(w) && w->client_win && w->client_win != w->id) {
|
||||
w->fade_last = w->fade = false;
|
||||
// deprecated
|
||||
return false;
|
||||
}
|
||||
// Ignore other possible causes of fading state changes after window
|
||||
// gets unmapped
|
||||
else if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) {
|
||||
} else if (c2_match(ps, w, ps->o.fade_blacklist, &w->cache_fblst, NULL))
|
||||
w->fade = false;
|
||||
else
|
||||
w->fade = ps->o.wintype_option[w->window_type].fade;
|
||||
//if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) {
|
||||
//}
|
||||
if (c2_match(ps, w, ps->o.fade_blacklist, NULL)) {
|
||||
return false;
|
||||
}
|
||||
return ps->o.wintype_option[w->window_type].fade;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -467,7 +477,7 @@ void win_determine_shadow(session_t *ps, win *w) {
|
|||
shadow_new = w->shadow_force;
|
||||
else if (w->a.map_state == XCB_MAP_STATE_VIEWABLE)
|
||||
shadow_new = (ps->o.wintype_option[w->window_type].shadow &&
|
||||
!c2_match(ps, w, ps->o.shadow_blacklist, &w->cache_sblst, NULL) &&
|
||||
!c2_match(ps, w, ps->o.shadow_blacklist, NULL) &&
|
||||
!(ps->o.shadow_ignore_shaped && w->bounding_shaped &&
|
||||
!w->rounded_corners) &&
|
||||
!(ps->o.respect_prop_shadow && 0 == w->prop_shadow));
|
||||
|
@ -494,7 +504,7 @@ void win_determine_invert_color(session_t *ps, win *w) {
|
|||
invert_color_new = w->invert_color_force;
|
||||
else if (w->a.map_state == XCB_MAP_STATE_VIEWABLE)
|
||||
invert_color_new =
|
||||
c2_match(ps, w, ps->o.invert_color_list, &w->cache_ivclst, NULL);
|
||||
c2_match(ps, w, ps->o.invert_color_list, NULL);
|
||||
|
||||
win_set_invert_color(ps, w, invert_color_new);
|
||||
}
|
||||
|
@ -520,23 +530,26 @@ void win_determine_blur_background(session_t *ps, win *w) {
|
|||
|
||||
bool blur_background_new =
|
||||
ps->o.blur_background &&
|
||||
!c2_match(ps, w, ps->o.blur_background_blacklist, &w->cache_bbblst, NULL);
|
||||
!c2_match(ps, w, ps->o.blur_background_blacklist, NULL);
|
||||
|
||||
win_set_blur_background(ps, w, blur_background_new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update window opacity according to opacity rules.
|
||||
*
|
||||
* TODO This override the window's opacity property, may not be
|
||||
* a good idea.
|
||||
*/
|
||||
void win_update_opacity_rule(session_t *ps, win *w) {
|
||||
if (w->a.map_state != XCB_MAP_STATE_VIEWABLE)
|
||||
return;
|
||||
|
||||
opacity_t opacity = OPAQUE;
|
||||
double opacity = 1.0;
|
||||
bool is_set = false;
|
||||
void *val = NULL;
|
||||
if (c2_match(ps, w, ps->o.opacity_rules, &w->cache_oparule, &val)) {
|
||||
opacity = ((double)(long)val) / 100.0 * OPAQUE;
|
||||
if (c2_match(ps, w, ps->o.opacity_rules, &val)) {
|
||||
opacity = ((double)(long)val) / 100.0;
|
||||
is_set = true;
|
||||
}
|
||||
|
||||
|
@ -548,7 +561,7 @@ void win_update_opacity_rule(session_t *ps, win *w) {
|
|||
if (!is_set)
|
||||
wid_rm_opacity_prop(ps, w->id);
|
||||
else
|
||||
wid_set_opacity_prop(ps, w->id, opacity);
|
||||
wid_set_opacity_prop(ps, w->id, opacity * OPAQUE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -556,7 +569,6 @@ void win_update_opacity_rule(session_t *ps, win *w) {
|
|||
*/
|
||||
void win_on_wtype_change(session_t *ps, win *w) {
|
||||
win_determine_shadow(ps, w);
|
||||
win_determine_fade(ps, w);
|
||||
win_update_focused(ps, w);
|
||||
if (ps->o.invert_color_list)
|
||||
win_determine_invert_color(ps, w);
|
||||
|
@ -566,12 +578,12 @@ void win_on_wtype_change(session_t *ps, win *w) {
|
|||
|
||||
/**
|
||||
* Function to be called on window data changes.
|
||||
*
|
||||
* TODO need better name
|
||||
*/
|
||||
void win_on_factor_change(session_t *ps, win *w) {
|
||||
if (ps->o.shadow_blacklist)
|
||||
win_determine_shadow(ps, w);
|
||||
if (ps->o.fade_blacklist)
|
||||
win_determine_fade(ps, w);
|
||||
if (ps->o.invert_color_list)
|
||||
win_determine_invert_color(ps, w);
|
||||
if (ps->o.focus_blacklist)
|
||||
|
@ -582,10 +594,10 @@ void win_on_factor_change(session_t *ps, win *w) {
|
|||
win_update_opacity_rule(ps, w);
|
||||
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE && ps->o.paint_blacklist)
|
||||
w->paint_excluded =
|
||||
c2_match(ps, w, ps->o.paint_blacklist, &w->cache_pblst, NULL);
|
||||
c2_match(ps, w, ps->o.paint_blacklist, NULL);
|
||||
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE && ps->o.unredir_if_possible_blacklist)
|
||||
w->unredir_if_possible_excluded = c2_match(
|
||||
ps, w, ps->o.unredir_if_possible_blacklist, &w->cache_uipblst, NULL);
|
||||
ps, w, ps->o.unredir_if_possible_blacklist, NULL);
|
||||
w->reg_ignore_valid = false;
|
||||
}
|
||||
|
||||
|
@ -733,6 +745,31 @@ void win_recheck_client(session_t *ps, win *w) {
|
|||
win_mark_client(ps, w, cw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free all resources in a <code>struct _win</code>.
|
||||
*/
|
||||
void free_win_res(session_t *ps, win *w) {
|
||||
// No need to call backend release_win here because
|
||||
// finish_unmap_win should've done that for us.
|
||||
// XXX unless we are called by session_destroy
|
||||
// assert(w->win_data == NULL);
|
||||
free_win_res_glx(ps, w);
|
||||
free_paint(ps, &w->paint);
|
||||
free_paint(ps, &w->shadow_paint);
|
||||
// Above should be done during unmapping
|
||||
// Except when we are called by session_destroy
|
||||
|
||||
pixman_region32_fini(&w->bounding_shape);
|
||||
// BadDamage may be thrown if the window is destroyed
|
||||
set_ignore_cookie(ps,
|
||||
xcb_damage_destroy(ps->c, w->damage));
|
||||
rc_region_unref(&w->reg_ignore);
|
||||
free(w->name);
|
||||
free(w->class_instance);
|
||||
free(w->class_general);
|
||||
free(w->role);
|
||||
}
|
||||
|
||||
// TODO: probably split into win_new (in win.c) and add_win (in compton.c)
|
||||
bool add_win(session_t *ps, xcb_window_t id, xcb_window_t prev) {
|
||||
static const win win_def = {
|
||||
|
@ -759,11 +796,14 @@ bool add_win(session_t *ps, xcb_window_t id, xcb_window_t prev) {
|
|||
|
||||
.widthb = 0,
|
||||
.heightb = 0,
|
||||
.destroying = false,
|
||||
.state = WSTATE_UNMAPPED,
|
||||
.bounding_shaped = false,
|
||||
.rounded_corners = false,
|
||||
.to_paint = false,
|
||||
.in_openclose = false,
|
||||
|
||||
// true when the window is first created.
|
||||
// set to false after the first map is done
|
||||
.in_openclose = true,
|
||||
|
||||
.client_win = XCB_NONE,
|
||||
.window_type = WINTYPE_UNKNOWN,
|
||||
|
@ -778,23 +818,15 @@ bool add_win(session_t *ps, xcb_window_t id, xcb_window_t prev) {
|
|||
.class_instance = NULL,
|
||||
.class_general = NULL,
|
||||
.role = NULL,
|
||||
.cache_sblst = NULL,
|
||||
.cache_fblst = NULL,
|
||||
.cache_fcblst = NULL,
|
||||
.cache_ivclst = NULL,
|
||||
.cache_bbblst = NULL,
|
||||
.cache_oparule = NULL,
|
||||
|
||||
.opacity = 0,
|
||||
.opacity_tgt = 0,
|
||||
.has_opacity_prop = false,
|
||||
.opacity_prop = OPAQUE,
|
||||
.opacity_is_set = false,
|
||||
.opacity_set = OPAQUE,
|
||||
.opacity_set = 1,
|
||||
|
||||
.fade = false,
|
||||
.fade_force = UNSET,
|
||||
.fade_callback = NULL,
|
||||
|
||||
.frame_opacity = 1.0,
|
||||
.frame_extents = MARGIN_INIT,
|
||||
|
@ -834,7 +866,7 @@ bool add_win(session_t *ps, xcb_window_t id, xcb_window_t prev) {
|
|||
win **p = NULL;
|
||||
if (prev) {
|
||||
for (p = &ps->list; *p; p = &(*p)->next) {
|
||||
if ((*p)->id == prev && !(*p)->destroying)
|
||||
if ((*p)->id == prev && (*p)->state != WSTATE_DESTROYING)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
@ -874,7 +906,7 @@ bool add_win(session_t *ps, xcb_window_t id, xcb_window_t prev) {
|
|||
assert(map_state == XCB_MAP_STATE_VIEWABLE || map_state == XCB_MAP_STATE_UNMAPPED);
|
||||
new->a.map_state = XCB_MAP_STATE_UNMAPPED;
|
||||
|
||||
if (InputOutput == new->a._class) {
|
||||
if (new->a._class == XCB_WINDOW_CLASS_INPUT_OUTPUT) {
|
||||
// Create Damage for window
|
||||
new->damage = xcb_generate_id(ps->c);
|
||||
xcb_generic_error_t *e = xcb_request_check(ps->c,
|
||||
|
@ -924,7 +956,7 @@ void win_update_focused(session_t *ps, win *w) {
|
|||
|| (ps->o.mark_ovredir_focused &&
|
||||
w->id == w->client_win && !w->wmwin)
|
||||
|| (w->a.map_state == XCB_MAP_STATE_VIEWABLE &&
|
||||
c2_match(ps, w, ps->o.focus_blacklist, &w->cache_fcblst, NULL)))
|
||||
c2_match(ps, w, ps->o.focus_blacklist, NULL)))
|
||||
w->focused = true;
|
||||
|
||||
// If window grouping detection is enabled, mark the window active if
|
||||
|
@ -938,7 +970,8 @@ void win_update_focused(session_t *ps, win *w) {
|
|||
// Always recalculate the window target opacity, since some opacity-related
|
||||
// options depend on the output value of win_is_focused_real() instead of
|
||||
// w->focused
|
||||
w->flags |= WFLAG_OPCT_CHANGE;
|
||||
w->opacity_tgt = win_get_opacity_target(ps, w);
|
||||
w->state = WSTATE_FADING;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1288,24 +1321,120 @@ void win_ev_stop(session_t *ps, win *w) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set fade callback of a window, and possibly execute the previous
|
||||
* 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
|
||||
*/
|
||||
void win_set_fade_callback(session_t *ps, win **_w,
|
||||
void (*callback) (session_t *ps, win **w), bool exec_callback) {
|
||||
static void
|
||||
finish_unmap_win(session_t *ps, win **_w) {
|
||||
win *w = *_w;
|
||||
void (*old_callback) (session_t *ps, win **w) = w->fade_callback;
|
||||
w->ever_damaged = false;
|
||||
w->reg_ignore_valid = false;
|
||||
w->state = WSTATE_UNMAPPED;
|
||||
w->flags = 0;
|
||||
|
||||
w->fade_callback = callback;
|
||||
// Must be the last line as the callback could destroy w!
|
||||
if (exec_callback && old_callback)
|
||||
old_callback(ps, _w);
|
||||
free_paint(ps, &w->paint);
|
||||
free_paint(ps, &w->shadow_paint);
|
||||
}
|
||||
|
||||
static void
|
||||
finish_destroy_win(session_t *ps, win **_w) {
|
||||
win *w = *_w;
|
||||
win **prev = NULL;
|
||||
|
||||
// Window can't go from UNMAPPED to DESTROYING, and
|
||||
// UNMAPPED is the only state where the window resource
|
||||
// is freed. That means the window resources have not
|
||||
// been freed at this point. call finish_unmap_win to
|
||||
// free them.
|
||||
finish_unmap_win(ps, _w);
|
||||
|
||||
log_trace("Trying to destroy (%#010x)", w->id);
|
||||
for (prev = &ps->list; *prev; prev = &(*prev)->next) {
|
||||
if (w == *prev) {
|
||||
log_trace("Found (%#010x \"%s\")", w->id, w->name);
|
||||
*prev = w->next;
|
||||
|
||||
if (w == ps->active_win) {
|
||||
ps->active_win = NULL;
|
||||
}
|
||||
|
||||
free_win_res(ps, w);
|
||||
|
||||
// Drop w from all prev_trans to avoid accessing freed memory in
|
||||
// repair_win()
|
||||
// TODO there can only be one prev_trans pointing to w
|
||||
for (win *w2 = ps->list; w2; w2 = w2->next) {
|
||||
if (w == w2->prev_trans) {
|
||||
w2->prev_trans = NULL;
|
||||
}
|
||||
}
|
||||
free(w);
|
||||
*_w = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
log_warn("Destroyed window is not in window list");
|
||||
assert(false);
|
||||
}
|
||||
|
||||
static void
|
||||
finish_map_win(session_t *ps, win **_w) {
|
||||
win *w = *_w;
|
||||
w->in_openclose = false;
|
||||
w->state = WSTATE_MAPPED;
|
||||
}
|
||||
|
||||
void
|
||||
unmap_win(session_t *ps, win **_w, bool destroy) {
|
||||
win *w = *_w;
|
||||
|
||||
log_trace("Unmapping %#010x \"%s\", destroy = %d", w->id, (w ? w->name: NULL), destroy);
|
||||
winstate_t target_state = destroy ? WSTATE_DESTROYING : WSTATE_UNMAPPING;
|
||||
|
||||
if (unlikely(!w)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(w->state == WSTATE_DESTROYING && !destroy)) {
|
||||
log_warn("Trying to undestroy a window?");
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// If the window is already in the state we want
|
||||
if (unlikely(w->state == target_state)) {
|
||||
log_warn("%s a window twice", destroy ? "Destroying" : "Unmapping");
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(w->state == WSTATE_UNMAPPED)) {
|
||||
if (unlikely(!destroy)) {
|
||||
log_warn("Unmapping an already unmapped window twice");
|
||||
return;
|
||||
}
|
||||
// Window is already unmapped, just destroy it
|
||||
finish_destroy_win(ps, _w);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set focus out
|
||||
win_set_focused(ps, w, false);
|
||||
|
||||
w->a.map_state = XCB_MAP_STATE_UNMAPPED;
|
||||
w->state = target_state;
|
||||
w->opacity_tgt = win_get_opacity_target(ps, w);
|
||||
|
||||
w->in_openclose = destroy;
|
||||
|
||||
// don't care about properties anymore
|
||||
win_ev_stop(ps, w);
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
// Send D-Bus signal
|
||||
if (ps->o.dbus) {
|
||||
if (destroy) {
|
||||
cdbus_ev_win_destroyed(ps, w);
|
||||
} else {
|
||||
cdbus_ev_win_unmapped(ps, w);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1314,8 +1443,161 @@ void win_set_fade_callback(session_t *ps, win **_w,
|
|||
void
|
||||
win_check_fade_finished(session_t *ps, win **_w) {
|
||||
win *w = *_w;
|
||||
if (w->fade_callback && w->opacity == w->opacity_tgt) {
|
||||
// Must be the last line as the callback could destroy w!
|
||||
win_set_fade_callback(ps, _w, NULL, true);
|
||||
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
|
||||
// No fading in progress
|
||||
assert(w->opacity_tgt == w->opacity);
|
||||
return;
|
||||
}
|
||||
if (w->opacity == w->opacity_tgt) {
|
||||
switch (w->state) {
|
||||
case WSTATE_UNMAPPING: return finish_unmap_win(ps, _w);
|
||||
case WSTATE_DESTROYING: return finish_destroy_win(ps, _w);
|
||||
case WSTATE_MAPPING: return finish_map_win(ps, _w);
|
||||
case WSTATE_FADING: w->state = WSTATE_MAPPED; break;
|
||||
default: unreachable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Xinerama screen a window is on.
|
||||
*
|
||||
* Return an index >= 0, or -1 if not found.
|
||||
*
|
||||
* XXX move to x.c
|
||||
*/
|
||||
void win_update_screen(session_t *ps, win *w) {
|
||||
#ifdef CONFIG_XINERAMA
|
||||
w->xinerama_scr = -1;
|
||||
|
||||
if (!ps->xinerama_scrs)
|
||||
return;
|
||||
|
||||
xcb_xinerama_screen_info_t *scrs = xcb_xinerama_query_screens_screen_info(ps->xinerama_scrs);
|
||||
int length = xcb_xinerama_query_screens_screen_info_length(ps->xinerama_scrs);
|
||||
for (int i = 0; i < length; i++) {
|
||||
xcb_xinerama_screen_info_t *s = &scrs[i];
|
||||
if (s->x_org <= w->g.x && s->y_org <= w->g.y
|
||||
&& s->x_org + s->width >= w->g.x + w->widthb
|
||||
&& s->y_org + s->height >= w->g.y + w->heightb) {
|
||||
w->xinerama_scr = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO remove this
|
||||
void configure_win(session_t *, xcb_configure_notify_event_t *);
|
||||
|
||||
/// Map an already registered window
|
||||
void
|
||||
map_win(session_t *ps, xcb_window_t id) {
|
||||
// Unmap overlay window if it got mapped but we are currently not
|
||||
// in redirected state.
|
||||
if (ps->overlay && id == ps->overlay && !ps->redirected) {
|
||||
log_debug("Overlay is mapped while we are not redirected");
|
||||
auto e = xcb_request_check(ps->c, xcb_unmap_window(ps->c, ps->overlay));
|
||||
if (e) {
|
||||
log_error("Failed to unmap the overlay window");
|
||||
free(e);
|
||||
}
|
||||
// We don't track the overlay window, so we can return
|
||||
return;
|
||||
}
|
||||
|
||||
win *w = find_win(ps, id);
|
||||
log_debug("Mapping (%#010x \"%s\")", id, (w ? w->name: NULL));
|
||||
|
||||
// Don't care about window mapping if it's an InputOnly window
|
||||
// Also, try avoiding mapping a window twice
|
||||
// TODO don't even add the input only windows
|
||||
if (!w || w->a._class == XCB_WINDOW_CLASS_INPUT_ONLY) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (w->state != WSTATE_UNMAPPED && w->state != WSTATE_UNMAPPING) {
|
||||
log_warn("Mapping an already mapped window");
|
||||
return;
|
||||
}
|
||||
|
||||
// XXX ???
|
||||
assert(!win_is_focused_real(ps, w));
|
||||
|
||||
// XXX Can we assume map_state is always viewable?
|
||||
w->a.map_state = XCB_MAP_STATE_VIEWABLE;
|
||||
|
||||
win_update_screen(ps, w);
|
||||
|
||||
// Set window event mask before reading properties so that no property
|
||||
// changes are lost
|
||||
xcb_change_window_attributes(ps->c, id, XCB_CW_EVENT_MASK,
|
||||
(const uint32_t[]) { determine_evmask(ps, id, WIN_EVMODE_FRAME) });
|
||||
|
||||
// Notify compton when the shape of a window changes
|
||||
if (ps->shape_exists) {
|
||||
xcb_shape_select_input(ps->c, id, 1);
|
||||
}
|
||||
|
||||
// Update window mode here to check for ARGB windows
|
||||
win_determine_mode(ps, w);
|
||||
|
||||
// Detect client window here instead of in add_win() as the client
|
||||
// window should have been prepared at this point
|
||||
if (!w->client_win) {
|
||||
win_recheck_client(ps, w);
|
||||
} else {
|
||||
// Re-mark client window here
|
||||
win_mark_client(ps, w, w->client_win);
|
||||
}
|
||||
assert(w->client_win);
|
||||
|
||||
log_debug("Window (%#010x) has type %s", w->id, WINTYPES[w->window_type]);
|
||||
|
||||
// Update window focus state
|
||||
win_update_focused(ps, w);
|
||||
|
||||
// Update opacity and dim state
|
||||
win_update_opacity_prop(ps, w);
|
||||
|
||||
// Check for _COMPTON_SHADOW
|
||||
if (ps->o.respect_prop_shadow) {
|
||||
win_update_prop_shadow_raw(ps, w);
|
||||
}
|
||||
|
||||
// Many things above could affect shadow
|
||||
win_determine_shadow(ps, w);
|
||||
|
||||
// XXX We need to make sure that win_data is available
|
||||
// iff `state` is MAPPED
|
||||
w->state = WSTATE_MAPPING;
|
||||
w->opacity_tgt = win_get_opacity_target(ps, w);
|
||||
log_debug("Window %#010x has opacity %f, opacity target is %f", w->id, w->opacity, w->opacity_tgt);
|
||||
|
||||
win_determine_blur_background(ps, w);
|
||||
|
||||
w->ever_damaged = false;
|
||||
|
||||
/* if any configure events happened while
|
||||
the window was unmapped, then configure
|
||||
the window to its correct place */
|
||||
if (w->need_configure) {
|
||||
configure_win(ps, &w->queue_configure);
|
||||
}
|
||||
|
||||
// We stopped listening on ShapeNotify events
|
||||
// when the window is unmapped (XXX we shouldn't),
|
||||
// so the shape of the window might have changed,
|
||||
// update. (Issue #35)
|
||||
win_update_bounding_shape(ps, w);
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
// Send D-Bus signal
|
||||
if (ps->o.dbus) {
|
||||
cdbus_ev_win_mapped(ps, w);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// vim: set et sw=2 :
|
||||
|
|
92
src/win.h
92
src/win.h
|
@ -64,6 +64,46 @@ typedef enum {
|
|||
WMODE_SOLID, // The window is opaque including the frame
|
||||
} winmode_t;
|
||||
|
||||
/// Transition table:
|
||||
/// (DESTROYED is when the win struct is destroyed and freed)
|
||||
/// ('o' means in all other cases)
|
||||
/// (Window is created in the UNMAPPED state)
|
||||
/// +-------------+---------+----------+-------+-------+--------+--------+---------+
|
||||
/// | |UNMAPPING|DESTROYING|MAPPING|FADING |UNMAPPED| MAPPED |DESTROYED|
|
||||
/// +-------------+---------+----------+-------+-------+--------+--------+---------+
|
||||
/// | UNMAPPING | o | Window |Window | - | Fading | - | - |
|
||||
/// | | |destroyed |mapped | |finished| | |
|
||||
/// +-------------+---------+----------+-------+-------+--------+--------+---------+
|
||||
/// | DESTROYING | - | o | - | - | - | - | Fading |
|
||||
/// | | | | | | | |finished |
|
||||
/// +-------------+---------+----------+-------+-------+--------+--------+---------+
|
||||
/// | MAPPING | Window | Window | o | - | - | Fading | - |
|
||||
/// | |unmapped |destroyed | | | |finished| |
|
||||
/// +-------------+---------+----------+-------+-------+--------+--------+---------+
|
||||
/// | FADING | Window | Window | - | o | - | Fading | - |
|
||||
/// | |unmapped |destroyed | | | |finished| |
|
||||
/// +-------------+---------+----------+-------+-------+--------+--------+---------+
|
||||
/// | UNMAPPED | - | - |Window | - | o | - | Window |
|
||||
/// | | | |mapped | | | |destroyed|
|
||||
/// +-------------+---------+----------+-------+-------+--------+--------+---------+
|
||||
/// | MAPPED | Window | Window | - |Opacity| - | o | - |
|
||||
/// | |unmapped |destroyed | |change | | | |
|
||||
/// +-------------+---------+----------+-------+-------+--------+--------+---------+
|
||||
typedef enum {
|
||||
// The window is being faded out because it's unmapped.
|
||||
WSTATE_UNMAPPING,
|
||||
// The window is being faded out because it's destroyed,
|
||||
WSTATE_DESTROYING,
|
||||
// The window is being faded in
|
||||
WSTATE_MAPPING,
|
||||
// Window opacity is not at the target level
|
||||
WSTATE_FADING,
|
||||
// The window is mapped, no fading is in progress.
|
||||
WSTATE_MAPPED,
|
||||
// The window is unmapped, no fading is in progress.
|
||||
WSTATE_UNMAPPED,
|
||||
} winstate_t;
|
||||
|
||||
/**
|
||||
* About coordinate systems
|
||||
*
|
||||
|
@ -88,6 +128,9 @@ struct win {
|
|||
// Core members
|
||||
/// ID of the top-level frame window.
|
||||
xcb_window_t id;
|
||||
/// The "mapped state" of this window, doesn't necessary
|
||||
/// match X mapped state, because of fading.
|
||||
winstate_t state;
|
||||
/// Window attributes.
|
||||
xcb_get_window_attributes_reply_t a;
|
||||
xcb_get_geometry_reply_t g;
|
||||
|
@ -175,20 +218,12 @@ struct win {
|
|||
char *class_general;
|
||||
/// <code>WM_WINDOW_ROLE</code> value of the window.
|
||||
char *role;
|
||||
const c2_lptr_t *cache_sblst;
|
||||
const c2_lptr_t *cache_fblst;
|
||||
const c2_lptr_t *cache_fcblst;
|
||||
const c2_lptr_t *cache_ivclst;
|
||||
const c2_lptr_t *cache_bbblst;
|
||||
const c2_lptr_t *cache_oparule;
|
||||
const c2_lptr_t *cache_pblst;
|
||||
const c2_lptr_t *cache_uipblst;
|
||||
|
||||
// Opacity-related members
|
||||
/// Current window opacity.
|
||||
opacity_t opacity;
|
||||
double opacity;
|
||||
/// Target window opacity.
|
||||
opacity_t opacity_tgt;
|
||||
double opacity_tgt;
|
||||
/// true if window (or client window, for broken window managers
|
||||
/// not transferring client window's _NET_WM_OPACITY value) has opacity prop
|
||||
bool has_opacity_prop;
|
||||
|
@ -197,18 +232,11 @@ struct win {
|
|||
/// true if opacity is set by some rules
|
||||
bool opacity_is_set;
|
||||
/// Last window opacity value we set.
|
||||
opacity_t opacity_set;
|
||||
double opacity_set;
|
||||
|
||||
// Fading-related members
|
||||
/// Do not fade if it's false. Change on window type change.
|
||||
/// Used by fading blacklist in the future.
|
||||
bool fade;
|
||||
/// Fade state on last paint.
|
||||
bool fade_last;
|
||||
/// Override value of window fade state. Set by D-Bus method calls.
|
||||
switch_t fade_force;
|
||||
/// Callback to be called after fading completed.
|
||||
void (*fade_callback) (session_t *ps, win **w);
|
||||
|
||||
// Frame-opacity-related members
|
||||
/// Current window frame opacity. Affected by window opacity.
|
||||
|
@ -269,7 +297,7 @@ void win_determine_mode(session_t *ps, win *w);
|
|||
* Set real focused state of a window.
|
||||
*/
|
||||
void win_set_focused(session_t *ps, win *w, bool focused);
|
||||
void win_determine_fade(session_t *ps, win *w);
|
||||
bool attr_const win_should_fade(session_t *ps, const win *w);
|
||||
void win_update_prop_shadow_raw(session_t *ps, win *w);
|
||||
void win_update_prop_shadow(session_t *ps, win *w);
|
||||
void win_set_shadow(session_t *ps, win *w, bool shadow_new);
|
||||
|
@ -288,8 +316,11 @@ void win_unmark_client(session_t *ps, win *w);
|
|||
void win_recheck_client(session_t *ps, win *w);
|
||||
xcb_window_t win_get_leader_raw(session_t *ps, win *w, int recursions);
|
||||
bool win_get_class(session_t *ps, win *w);
|
||||
void win_calc_opacity(session_t *ps, win *w);
|
||||
void win_calc_dim(session_t *ps, win *w);
|
||||
double attr_const win_get_opacity_target(session_t *ps, const win *w);
|
||||
bool attr_const win_should_dim(session_t *ps, const win *w);
|
||||
void win_update_screen(session_t *, win *);
|
||||
/// Prepare window for fading because opacity target changed
|
||||
void win_start_fade(session_t *, win **);
|
||||
/**
|
||||
* Reread opacity property of a window.
|
||||
*/
|
||||
|
@ -336,18 +367,8 @@ region_t win_get_region_noframe_local_by_val(win *w);
|
|||
void
|
||||
win_update_frame_extents(session_t *ps, win *w, xcb_window_t client);
|
||||
bool add_win(session_t *ps, xcb_window_t id, xcb_window_t prev);
|
||||
|
||||
/**
|
||||
* Set fade callback of a window, and possibly execute the previous
|
||||
* 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
|
||||
*/
|
||||
void win_set_fade_callback(session_t *ps, win **_w,
|
||||
void (*callback) (session_t *ps, win **w), bool exec_callback);
|
||||
/// Unmap or destroy a window
|
||||
void unmap_win(session_t *ps, win **, bool destroy);
|
||||
|
||||
/**
|
||||
* Execute fade callback of a window if fading finished.
|
||||
|
@ -369,11 +390,14 @@ win_get_leader(session_t *ps, win *w) {
|
|||
}
|
||||
|
||||
/// check if window has ARGB visual
|
||||
bool win_has_alpha(win *w);
|
||||
bool attr_const win_has_alpha(const win *w);
|
||||
|
||||
/// check if reg_ignore_valid is true for all windows above us
|
||||
bool win_is_region_ignore_valid(session_t *ps, win *w);
|
||||
|
||||
/// Free all resources in a struct win
|
||||
void free_win_res(session_t *ps, win *w);
|
||||
|
||||
static inline region_t
|
||||
win_get_bounding_shape_global_by_val(win *w) {
|
||||
region_t ret;
|
||||
|
|
Loading…
Reference in New Issue