Merge pull request #111 from yshui/winstate-refactor

Window state tracking refactor
This commit is contained in:
yshui 2019-02-17 16:56:27 +00:00 committed by GitHub
commit ecb3050eaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 596 additions and 572 deletions

View File

@ -3,11 +3,11 @@
#include <xcb/xcb.h> #include <xcb/xcb.h>
#include "backend.h" #include "backend.h"
#include "config.h"
#include "win.h"
#include "region.h"
#include "common.h" #include "common.h"
#include "compiler.h" #include "compiler.h"
#include "config.h"
#include "region.h"
#include "win.h"
backend_info_t *backend_list[NUM_BKEND] = { backend_info_t *backend_list[NUM_BKEND] = {
[BKEND_XRENDER] = &xrender_backend, [BKEND_XRENDER] = &xrender_backend,
@ -107,8 +107,7 @@ void paint_all_new(session_t *ps, win *const t, bool ignore_damage) {
&reg_noframe); &reg_noframe);
pixman_region32_fini(&reg_noframe); pixman_region32_fini(&reg_noframe);
} }
bi->blur(ps->backend_data, ps, bi->blur(ps->backend_data, ps, w->opacity, &reg_blur);
(double)w->opacity / OPAQUE, &reg_blur);
pixman_region32_fini(&reg_blur); pixman_region32_fini(&reg_blur);
} }

View File

@ -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) || bool blend = default_is_frame_transparent(NULL, w, win_data) ||
default_is_win_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); 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, // XXX Move shadow drawing into a separate function,
// also do shadow excluding outside of backend // 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); 0, 0, 0, 0, w->widthb, w->heightb);
} }
const double dopacity = get_opacity_percent(w);
if (w->frame_opacity != 1) { if (w->frame_opacity != 1) {
// Handle transparent frame // Handle transparent frame
// Step 1: clip paint area to 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 // Draw the frame with frame opacity
xcb_render_picture_t alpha_pict = 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); x_set_picture_clip_region(ps->c, wd->rendered_pict, 0, 0, &frame_reg);
// Step 2: multiply alpha value // 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; double dim_opacity = ps->o.inactive_dim;
if (!ps->o.inactive_dim_fixed) if (!ps->o.inactive_dim_fixed)
dim_opacity *= get_opacity_percent(w); dim_opacity *= w->opacity;
xcb_render_color_t color = { xcb_render_color_t color = {
.red = 0, .green = 0, .blue = 0, .alpha = 0xffff * dim_opacity}; .red = 0, .green = 0, .blue = 0, .alpha = 0xffff * dim_opacity};

View File

@ -353,7 +353,7 @@ static xcb_atom_t
c2_get_atom_type(const c2_l_t *pleaf); c2_get_atom_type(const c2_l_t *pleaf);
static bool 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. * Parse a condition string.
@ -1365,7 +1365,7 @@ c2_get_atom_type(const c2_l_t *pleaf) {
* For internal use. * For internal use.
*/ */
static inline void 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) { bool *pres, bool *perr) {
assert(pleaf); 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. * @return true if matched, false otherwise.
*/ */
static bool 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 result = false;
bool error = true; 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. * @return true if matched, false otherwise.
*/ */
bool bool
c2_match(session_t *ps, win *w, const c2_lptr_t *condlst, c2_match(session_t *ps, const win *w, const c2_lptr_t *condlst, void **pdata) {
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;
}
// Then go through the whole linked list // Then go through the whole linked list
for (; condlst; condlst = condlst->next) { for (; condlst; condlst = condlst->next) {
if (c2_match_once(ps, w, condlst->ptr)) { if (c2_match_once(ps, w, condlst->ptr)) {
if (cache)
*cache = condlst;
if (pdata) if (pdata)
*pdata = condlst->data; *pdata = condlst->data;
return true; return true;

View File

@ -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); 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, bool c2_match(session_t *ps, const win *w, const c2_lptr_t *condlst, void **pdata);
void **pdata);
bool c2_list_postprocess(session_t *ps, c2_lptr_t *list); bool c2_list_postprocess(session_t *ps, c2_lptr_t *list);

View File

@ -98,7 +98,6 @@
#define ROUNDED_PERCENT 0.05 #define ROUNDED_PERCENT 0.05
#define ROUNDED_PIXELS 10 #define ROUNDED_PIXELS 10
#define OPAQUE 0xffffffff
#define REGISTER_PROP "_NET_WM_CM_S" #define REGISTER_PROP "_NET_WM_CM_S"
#define TIME_MS_MAX LONG_MAX #define TIME_MS_MAX LONG_MAX
@ -371,9 +370,6 @@ typedef struct session {
bool tmout_unredir_hit; bool tmout_unredir_hit;
/// Whether we need to redraw the screen /// Whether we need to redraw the screen
bool redraw_needed; bool redraw_needed;
/// Whether the program is idling. I.e. no fading, no potential window
/// changes.
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.
@ -687,11 +683,6 @@ timespec_subtract(struct timespec *result,
return x->tv_sec < y->tv_sec; 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. * Get current time in struct timeval.
*/ */
@ -792,8 +783,9 @@ find_win(session_t *ps, xcb_window_t id) {
win *w; win *w;
for (w = ps->list; w; w = w->next) { 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 w;
}
} }
return 0; return 0;
@ -811,8 +803,9 @@ find_toplevel(session_t *ps, xcb_window_t id) {
return NULL; return NULL;
for (win *w = ps->list; w; w = w->next) { 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 w;
}
} }
return NULL; return NULL;

View File

@ -4,9 +4,11 @@
#include <stdc-predef.h> #include <stdc-predef.h>
#define auto __auto_type #define auto __auto_type
#define likely(x) __builtin_expect(!!(x), 1) #define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0) #define unlikely(x) __builtin_expect(!!(x), 0)
#define likely_if(x) if (likely(x))
#define unlikely_if(x) if (unlikely(x))
#ifndef __has_attribute #ifndef __has_attribute
# if __GNUC__ >= 4 # if __GNUC__ >= 4

View File

@ -59,12 +59,6 @@
(session_t *)((char *)__mptr - offsetof(session_t, member)); \ (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 static void
update_refresh_rate(session_t *ps); update_refresh_rate(session_t *ps);
@ -91,9 +85,6 @@ redir_stop(session_t *ps);
static win * static win *
recheck_focus(session_t *ps); recheck_focus(session_t *ps);
static double
get_opacity_percent(win *w);
static void static void
restack_win(session_t *ps, win *w, xcb_window_t new_above); restack_win(session_t *ps, win *w, xcb_window_t new_above);
@ -169,25 +160,6 @@ free_xinerama_info(session_t *ps) {
#endif #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. * 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; 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 // XXX Move to x.c
static void static void
cxinerama_upd_scrs(session_t *ps) { cxinerama_upd_scrs(session_t *ps) {
@ -334,32 +277,46 @@ fade_timeout(session_t *ps) {
* Run fading on a window. * Run fading on a window.
* *
* @param steps steps of fading * @param steps steps of fading
* @return whether we are still in fading mode
*/ */
static void static bool
run_fade(session_t *ps, win *w, unsigned steps) { run_fade(session_t *ps, win **_w, unsigned steps) {
// If we have reached target opacity, return win *w = *_w;
if (w->opacity == w->opacity_tgt) { if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
return; // 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; w->opacity = w->opacity_tgt;
else if (steps) { }
// Use double below because opacity_t will probably overflow during if (w->opacity == w->opacity_tgt) {
// calculations // We have reached target opacity, wrapping up.
if (w->opacity < w->opacity_tgt) // Note, we reach here after we have rendered the window with the target
w->opacity = normalize_d_range( // opacity at least once. If the window is destroyed because it is faded out,
(double) w->opacity + (double) ps->o.fade_in_step * steps, // there is no need to add damage here.
0.0, w->opacity_tgt); log_debug("Fading finished for window %#010x %s", w->id, w->name);
else win_check_fade_finished(ps, _w);
w->opacity = normalize_d_range( return false;
(double) w->opacity - (double) ps->o.fade_out_step * steps,
w->opacity_tgt, OPAQUE);
} }
if (w->opacity != w->opacity_tgt) { if (steps) {
ps->fade_running = true; 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 === // === Error handling ===
@ -516,8 +473,11 @@ find_client_win(session_t *ps, xcb_window_t w) {
} }
static win * 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; win *t = NULL, *next = NULL;
*fade_running = false;
// Fading step calculation // Fading step calculation
unsigned long steps = 0L; unsigned long steps = 0L;
@ -539,40 +499,50 @@ paint_preprocess(session_t *ps, win *list) {
const bool was_painted = w->to_paint; const bool was_painted = w->to_paint;
const opacity_t opacity_old = w->opacity; const opacity_t opacity_old = w->opacity;
// Restore flags from last paint if the window is being faded out // 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); 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_invert_color(ps, w, w->invert_color_last);
win_set_blur_background(ps, w, w->blur_background_last); win_set_blur_background(ps, w, w->blur_background_last);
} }
// Update window opacity target and dim state if asked if (win_should_dim(ps, w) != w->dim) {
if (WFLAG_OPCT_CHANGE & w->flags) { w->dim = win_should_dim(ps, w);
win_calc_opacity(ps, w); add_damage_from_win(ps, w);
win_calc_dim(ps, w);
} }
// Run fading // 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; w->frame_opacity = ps->o.frame_opacity;
else } else {
w->frame_opacity = 1.0; w->frame_opacity = 1.0;
}
// Update window mode // Update window mode
win_determine_mode(ps, w); win_determine_mode(ps, w);
// Destroy all reg_ignore above when frame opaque state changes on // Destroy all reg_ignore above when frame opaque state changes on
// SOLID mode // SOLID mode
if (was_painted && w->mode != mode_old) if (was_painted && w->mode != mode_old) {
w->reg_ignore_valid = false; w->reg_ignore_valid = false;
}
// Add window to damaged area if its opacity changes // 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, 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 == 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); add_damage_from_win(ps, w);
}
} }
// Opacity will not change, from now on. // Opacity will not change, from now on.
@ -603,8 +573,8 @@ paint_preprocess(session_t *ps, win *list) {
if (!w->ever_damaged if (!w->ever_damaged
|| w->g.x + w->g.width < 1 || w->g.y + w->g.height < 1 || 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->g.x >= ps->root_width || w->g.y >= ps->root_height
|| ((w->a.map_state == XCB_MAP_STATE_UNMAPPED || w->destroying) && !w->paint.pixmap) || w->state == WSTATE_UNMAPPED
|| (double) w->opacity / OPAQUE * MAX_ALPHA < 1 || (double) w->opacity * MAX_ALPHA < 1
|| w->paint_excluded) || w->paint_excluded)
to_paint = false; to_paint = false;
//log_trace("%s %d %d %d", w->name, to_paint, w->opacity, w->paint_excluded); //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; goto skip_window;
// Calculate shadow opacity // 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 // Generate ignore region for painting to reduce GPU load
if (!w->reg_ignore) 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; reg_ignore_valid = reg_ignore_valid && w->reg_ignore_valid;
w->reg_ignore_valid = true; w->reg_ignore_valid = true;
assert(w->destroying == (w->fade_callback == finish_destroy_win));
win_check_fade_finished(ps, &w); win_check_fade_finished(ps, &w);
// Avoid setting w->to_paint if w is freed // Avoid setting w->to_paint if w is freed
@ -683,7 +652,6 @@ paint_preprocess(session_t *ps, win *list) {
if (w->to_paint) { if (w->to_paint) {
// Save flags // Save flags
w->shadow_last = w->shadow; w->shadow_last = w->shadow;
w->fade_last = w->fade;
w->invert_color_last = w->invert_color; w->invert_color_last = w->invert_color;
w->blur_background_last = w->blur_background; w->blur_background_last = w->blur_background;
} }
@ -693,7 +661,7 @@ paint_preprocess(session_t *ps, win *list) {
rc_region_unref(&last_reg_ignore); rc_region_unref(&last_reg_ignore);
// If possible, unredirect all windows and stop painting // 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; unredir_possible = !ps->o.redirected_force;
else if (ps->o.unredir_if_possible && is_highest && !ps->redirected) else if (ps->o.unredir_if_possible && is_highest && !ps->redirected)
// If there's no window to paint, and the screen isn't 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); add_damage(ps, &parts);
pixman_region32_fini(&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 static void
restack_win(session_t *ps, win *w, xcb_window_t new_above) { restack_win(session_t *ps, win *w, xcb_window_t new_above) {
xcb_window_t old_above; xcb_window_t old_above;
@ -986,7 +790,7 @@ restack_win(session_t *ps, win *w, xcb_window_t new_above) {
// rehook // rehook
for (prev = &ps->list; *prev; prev = &(*prev)->next) { 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; found = true;
break; 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) { configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
// On root window changes // On root window changes
if (ce->window == ps->root) { if (ce->window == ps->root) {
@ -1131,7 +935,7 @@ configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
if (factor_change) { if (factor_change) {
win_on_factor_change(ps, w); win_on_factor_change(ps, w);
add_damage(ps, &damage); 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); 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 static inline void
root_damaged(session_t *ps) { root_damaged(session_t *ps) {
if (ps->root_tile_paint.pixmap) { 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. * Set w->fade_force of a window.
*
* Doesn't affect fading already in progress
*/ */
void void
win_set_fade_force(session_t *ps, win *w, switch_t val) { win_set_fade_force(session_t *ps, win *w, switch_t val) {
if (val != w->fade_force) { w->fade_force = val;
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. * Set no_fading_openclose option.
*
* Don't affect fading already in progress
*/ */
void void
opts_set_no_fading_openclose(session_t *ps, bool newval) { opts_set_no_fading_openclose(session_t *ps, bool newval) {
if (newval != ps->o.no_fading_openclose) { ps->o.no_fading_openclose = newval;
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 inline static void
ev_destroy_notify(session_t *ps, xcb_destroy_notify_event_t *ev) { 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 inline static void
ev_map_notify(session_t *ps, xcb_map_notify_event_t *ev) { ev_map_notify(session_t *ps, xcb_map_notify_event_t *ev) {
map_win(ps, ev->window); 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 inline static void
ev_unmap_notify(session_t *ps, xcb_unmap_notify_event_t *ev) { ev_unmap_notify(session_t *ps, xcb_unmap_notify_event_t *ev) {
win *w = find_win(ps, ev->window); win *w = find_win(ps, ev->window);
if (w) {
if (w) unmap_win(ps, &w, false);
unmap_win(ps, &w); }
} }
inline static void inline static void
@ -1540,9 +1286,14 @@ ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t *ev) {
ev->parent, ev->override_redirect); ev->parent, ev->override_redirect);
if (ev->parent == ps->root) { if (ev->parent == ps->root) {
// new window
add_win(ps, ev->window, 0); add_win(ps, ev->window, 0);
} else { } 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 // Reset event mask in case something wrong happens
xcb_change_window_attributes(ps->c, ev->window, XCB_CW_EVENT_MASK, 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); win *w = find_win(ps, ev->window) ?: find_toplevel(ps, ev->window);
if (w) { if (w) {
win_update_opacity_prop(ps, 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 static void
redir_start(session_t *ps) { redir_start(session_t *ps) {
if (!ps->redirected) { if (!ps->redirected) {
log_trace("Screen redirected."); log_debug("Screen redirected.");
// Map overlay window. Done firstly according to this: // Map overlay window. Done firstly according to this:
// https://bugzilla.gnome.org/show_bug.cgi?id=597014 // https://bugzilla.gnome.org/show_bug.cgi?id=597014
@ -2262,7 +2019,7 @@ redir_start(session_t *ps) {
static void static void
redir_stop(session_t *ps) { redir_stop(session_t *ps) {
if (ps->redirected) { if (ps->redirected) {
log_trace("Screen unredirected."); log_debug("Screen unredirected.");
// Destroy all Pictures as they expire once windows are unredirected // Destroy all Pictures as they expire once windows are unredirected
// If we don't destroy them here, looks like the resources are just // If we don't destroy them here, looks like the resources are just
// kept inaccessible somehow // kept inaccessible somehow
@ -2337,14 +2094,14 @@ _draw_callback(EV_P_ session_t *ps, int revents) {
} }
} }
ps->fade_running = false; bool fade_running = false;
win *t = paint_preprocess(ps, ps->list); win *t = paint_preprocess(ps, ps->list, &fade_running);
ps->tmout_unredir_hit = false; ps->tmout_unredir_hit = false;
// Start/stop fade timer depends on whether window are fading // 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); 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_set(&ps->fade_timer, fade_timeout(ps), 0);
ev_timer_start(ps->loop, &ps->fade_timer); ev_timer_start(ps->loop, &ps->fade_timer);
} }
@ -2359,7 +2116,7 @@ _draw_callback(EV_P_ session_t *ps, int revents) {
exit(0); exit(0);
} }
if (!ps->fade_running) if (!fade_running)
ps->fade_time = 0L; ps->fade_time = 0L;
ps->redraw_needed = false; ps->redraw_needed = false;
@ -2516,16 +2273,16 @@ session_init(int argc, char **argv, Display *dpy, const char *config_file,
.respect_prop_shadow = false, .respect_prop_shadow = false,
.xinerama_shadow_crop = false, .xinerama_shadow_crop = false,
.fade_in_step = 0.028 * OPAQUE, .fade_in_step = 0.028,
.fade_out_step = 0.03 * OPAQUE, .fade_out_step = 0.03,
.fade_delta = 10, .fade_delta = 10,
.no_fading_openclose = false, .no_fading_openclose = false,
.no_fading_destroyed_argb = false, .no_fading_destroyed_argb = false,
.fade_blacklist = NULL, .fade_blacklist = NULL,
.inactive_opacity = OPAQUE, .inactive_opacity = 1.0,
.inactive_opacity_override = false, .inactive_opacity_override = false,
.active_opacity = OPAQUE, .active_opacity = 1.0,
.frame_opacity = 1.0, .frame_opacity = 1.0,
.detect_client_opacity = false, .detect_client_opacity = false,
@ -2552,7 +2309,6 @@ session_init(int argc, char **argv, Display *dpy, const char *config_file,
.time_start = { 0, 0 }, .time_start = { 0, 0 },
.redirected = false, .redirected = false,
.alpha_picts = NULL, .alpha_picts = NULL,
.fade_running = false,
.fade_time = 0L, .fade_time = 0L,
.ignore_head = NULL, .ignore_head = NULL,
.ignore_tail = NULL, .ignore_tail = NULL,
@ -3167,20 +2923,16 @@ session_destroy(session_t *ps) {
*/ */
static void static void
session_run(session_t *ps) { session_run(session_t *ps) {
win *t;
if (ps->o.sw_opti) if (ps->o.sw_opti)
ps->paint_tm_offset = get_time_timeval().tv_usec; 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 // 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); ev_idle_start(ps->loop, &ps->draw_idle);
} else {
// Let's draw our first frame!
queue_redraw(ps);
}
ev_run(ps->loop, 0); ev_run(ps->loop, 0);
} }

View File

@ -148,14 +148,4 @@ dump_drawable(session_t *ps, xcb_drawable_t drawable) {
free(r); 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 : // vim: set et sw=2 :

View File

@ -167,9 +167,9 @@ typedef struct options_t {
// === Fading === // === Fading ===
/// How much to fade in in a single fading step. /// 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. /// How much to fade out in a single fading step.
opacity_t fade_out_step; double fade_out_step;
/// Fading time delta. In milliseconds. /// Fading time delta. In milliseconds.
unsigned long fade_delta; unsigned long fade_delta;
/// Whether to disable fading on window open/close. /// Whether to disable fading on window open/close.
@ -181,11 +181,10 @@ typedef struct options_t {
// === Opacity === // === Opacity ===
/// Default opacity for inactive windows. /// Default opacity for inactive windows.
/// 32-bit integer with the format of _NET_WM_OPACITY. 0 stands for /// 32-bit integer with the format of _NET_WM_OPACITY.
/// not enabled, default. double inactive_opacity;
opacity_t inactive_opacity;
/// Default opacity for inactive windows. /// Default opacity for inactive windows.
opacity_t active_opacity; double active_opacity;
/// Whether inactive_opacity overrides the opacity set by window /// Whether inactive_opacity overrides the opacity set by window
/// attributes. /// attributes.
bool inactive_opacity_override; bool inactive_opacity_override;

View File

@ -218,10 +218,10 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
opt->fade_delta = ival; opt->fade_delta = ival;
// -I (fade_in_step) // -I (fade_in_step)
if (config_lookup_float(&cfg, "fade-in-step", &dval)) 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) // -O (fade_out_step)
if (config_lookup_float(&cfg, "fade-out-step", &dval)) 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) // -r (shadow_radius)
config_lookup_int(&cfg, "shadow-radius", &opt->shadow_radius); config_lookup_int(&cfg, "shadow-radius", &opt->shadow_radius);
// -o (shadow_opacity) // -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); config_lookup_int(&cfg, "shadow-offset-y", &opt->shadow_offset_y);
// -i (inactive_opacity) // -i (inactive_opacity)
if (config_lookup_float(&cfg, "inactive-opacity", &dval)) if (config_lookup_float(&cfg, "inactive-opacity", &dval))
opt->inactive_opacity = normalize_d(dval) * OPAQUE; opt->inactive_opacity = normalize_d(dval);
// --active_opacity // --active_opacity
if (config_lookup_float(&cfg, "active-opacity", &dval)) if (config_lookup_float(&cfg, "active-opacity", &dval))
opt->active_opacity = normalize_d(dval) * OPAQUE; opt->active_opacity = normalize_d(dval);
// -e (frame_opacity) // -e (frame_opacity)
config_lookup_float(&cfg, "frame-opacity", &opt->frame_opacity); config_lookup_float(&cfg, "frame-opacity", &opt->frame_opacity);
// -c (shadow_enable) // -c (shadow_enable)

View File

@ -493,8 +493,9 @@ cdbus_apdarg_wids(session_t *ps, DBusMessage *msg, const void *data) {
// Get the number of wids we are to include // Get the number of wids we are to include
unsigned count = 0; unsigned count = 0;
for (win *w = ps->list; w; w = w->next) { for (win *w = ps->list; w; w = w->next) {
if (!w->destroying) if (w->state != WSTATE_DESTROYING) {
++count; ++count;
}
} }
if (!count) { if (!count) {
@ -509,7 +510,7 @@ cdbus_apdarg_wids(session_t *ps, DBusMessage *msg, const void *data) {
{ {
cdbus_window_t *pcur = arr; cdbus_window_t *pcur = arr;
for (win *w = ps->list; w; w = w->next) { for (win *w = ps->list; w; w = w->next) {
if (!w->destroying) { if (w->state != WSTATE_DESTROYING) {
*pcur = w->id; *pcur = w->id;
++pcur; ++pcur;
assert(pcur <= arr + count); 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(mode, cdbus_reply_enum);
cdbus_m_win_get_do(client_win, cdbus_reply_wid); 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(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(window_type, cdbus_reply_enum);
cdbus_m_win_get_do(wmwin, cdbus_reply_bool); cdbus_m_win_get_do(wmwin, cdbus_reply_bool);
cdbus_m_win_get_do(leader, cdbus_reply_wid); 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(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(invert_color, cdbus_reply_bool);
cdbus_m_win_get_do(blur_background, cdbus_reply_bool); cdbus_m_win_get_do(blur_background, cdbus_reply_bool);
#undef cdbus_m_win_get_do #undef cdbus_m_win_get_do
@ -1140,7 +1139,7 @@ cdbus_process_opts_set(session_t *ps, DBusMessage *msg) {
double val = 0.0; double val = 0.0;
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_DOUBLE, &val)) if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_DOUBLE, &val))
return false; 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; goto cdbus_process_opts_set_success;
} }
@ -1149,7 +1148,7 @@ cdbus_process_opts_set(session_t *ps, DBusMessage *msg) {
double val = 0.0; double val = 0.0;
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_DOUBLE, &val)) if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_DOUBLE, &val))
return false; 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; goto cdbus_process_opts_set_success;
} }

View File

@ -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() // These options are handled by get_early_config()
break; break;
P_CASELONG('D', fade_delta); P_CASELONG('D', fade_delta);
case 'I': opt->fade_in_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)) * OPAQUE; break; case 'O': opt->fade_out_step = normalize_d(atof(optarg)); break;
case 'c': shadow_enable = true; break; case 'c': shadow_enable = true; break;
case 'C': case 'C':
winopt_mask[WINTYPE_DOCK].shadow = true; 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('l', shadow_offset_x);
P_CASELONG('t', shadow_offset_y); P_CASELONG('t', shadow_offset_y);
case 'i': case 'i':
opt->inactive_opacity = (normalize_d(atof(optarg)) * OPAQUE); opt->inactive_opacity = normalize_d(atof(optarg));
break; break;
case 'e': opt->frame_opacity = atof(optarg); break; case 'e': opt->frame_opacity = atof(optarg); break;
case 'z': case 'z':
@ -718,7 +718,7 @@ void get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
break; break;
case 297: case 297:
// --active-opacity // --active-opacity
opt->active_opacity = (normalize_d(atof(optarg)) * OPAQUE); opt->active_opacity = normalize_d(atof(optarg));
break; break;
P_CASEBOOL(298, glx_no_rebind_pixmap); P_CASEBOOL(298, glx_no_rebind_pixmap);
case 299: case 299:

View File

@ -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) { 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 { } else {
// Painting parameters // Painting parameters
const margin_t extents = win_calc_frame_extents(w); 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; const int r = extents.right;
#define COMP_BDR(cx, cy, cwid, chei) \ #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) reg_paint, pict)
// Sanitize the margins, in case some broken WM makes // 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 // body
paint_region(ps, w, cleft, ctop, body_width, body_height, paint_region(ps, w, cleft, ctop, body_width, body_height,
dopacity, reg_paint, pict); w->opacity, reg_paint, pict);
} while (0); } while (0);
} }
@ -385,7 +383,7 @@ void paint_one(session_t *ps, win *w, const region_t *reg_paint) {
if (w->dim) { if (w->dim) {
double dim_opacity = ps->o.inactive_dim; double dim_opacity = ps->o.inactive_dim;
if (!ps->o.inactive_dim_fixed) if (!ps->o.inactive_dim_fixed)
dim_opacity *= get_opacity_percent(w); dim_opacity *= w->opacity;
switch (ps->o.backend) { switch (ps->o.backend) {
case BKEND_XRENDER: 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 // Adjust blur strength according to window opacity, to make it appear
// better during fading // better during fading
if (!ps->o.blur_background_fixed) { 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); factor_center = pct * 8.0 / (1.1 - pct);
} }

View File

@ -9,7 +9,7 @@
/// Enumeration type to represent switches. /// Enumeration type to represent switches.
typedef enum { typedef enum {
OFF, // false OFF = 0, // false
ON, // true ON, // true
UNSET UNSET
} switch_t; } switch_t;

480
src/win.c
View File

@ -30,8 +30,15 @@
#include "dbus.h" #include "dbus.h"
#endif #endif
#ifdef CONFIG_OPENGL
// TODO remove this include
#include "opengl.h"
#endif
#include "win.h" #include "win.h"
#define OPAQUE 0xffffffff
/// Generate a "return by value" function, from a function that returns the /// Generate a "return by value" function, from a function that returns the
/// region via a region_t pointer argument. /// region via a region_t pointer argument.
/// Function signature has to be (win *, region_t *) /// Function signature has to be (win *, region_t *)
@ -74,7 +81,7 @@ group_update_focused(session_t *ps, xcb_window_t leader) {
return; return;
for (win *w = ps->list; w; w = w->next) { 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); win_update_focused(ps, w);
} }
@ -93,7 +100,7 @@ group_is_focused(session_t *ps, xcb_window_t leader) {
return false; return false;
for (win *w = ps->list; w; w = w->next) { 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)) && win_is_focused_real(ps, w))
return true; 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 // 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 && return w->pictfmt &&
w->pictfmt->type == XCB_RENDER_PICT_TYPE_DIRECT && w->pictfmt->type == XCB_RENDER_PICT_TYPE_DIRECT &&
w->pictfmt->direct.alpha_mask; w->pictfmt->direct.alpha_mask;
} }
void win_determine_mode(session_t *ps, win *w) { 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; w->mode = WMODE_TRANS;
} else if (w->frame_opacity != 1.0) { } else if (w->frame_opacity != 1.0) {
w->mode = WMODE_FRAME_TRANS; 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 * If window is inactive and inactive_opacity_override is set, the
* priority is: (Simulates the old behavior) * priority is: (Simulates the old behavior)
@ -325,78 +332,81 @@ void win_determine_mode(session_t *ps, win *w) {
* *
* @param ps current session * @param ps current session
* @param w struct _win object representing the window * @param w struct _win object representing the window
*
* @return target opacity
*/ */
void win_calc_opacity(session_t *ps, win *w) { double win_get_opacity_target(session_t *ps, const win *w) {
opacity_t opacity = OPAQUE; double opacity = 1;
if (w->destroying || w->a.map_state != XCB_MAP_STATE_VIEWABLE) if (w->state == WSTATE_UNMAPPED) {
opacity = 0; // be consistent
else { return 0;
// Try obeying opacity property and window type opacity firstly }
if (w->has_opacity_prop) if (w->state == WSTATE_UNMAPPING || w->state == WSTATE_DESTROYING) {
opacity = w->opacity_prop; return 0;
else if (!safe_isnan(ps->o.wintype_option[w->window_type].opacity)) }
opacity = ps->o.wintype_option[w->window_type].opacity * OPAQUE; // Try obeying opacity property and window type opacity firstly
else { if (w->has_opacity_prop) {
// Respect active_opacity only when the window is physically focused opacity = ((double)w->opacity_prop) / OPAQUE;
if (win_is_focused_real(ps, w)) } else if (!safe_isnan(ps->o.wintype_option[w->window_type].opacity)) {
opacity = ps->o.active_opacity; opacity = ps->o.wintype_option[w->window_type].opacity;
else if (false == w->focused) } else {
// Respect inactive_opacity in some cases // Respect active_opacity only when the window is physically focused
opacity = ps->o.inactive_opacity; if (win_is_focused_real(ps, w))
} opacity = ps->o.active_opacity;
else if (!w->focused)
// respect inactive override // Respect inactive_opacity in some cases
if (ps->o.inactive_opacity_override && false == w->focused)
opacity = ps->o.inactive_opacity; opacity = ps->o.inactive_opacity;
} }
w->opacity_tgt = opacity; // respect inactive override
if (ps->o.inactive_opacity_override && !w->focused)
opacity = ps->o.inactive_opacity;
return opacity;
} }
/** /**
* Determine whether a window is to be dimmed. * Determine whether a window is to be dimmed.
*/ */
void win_calc_dim(session_t *ps, win *w) { bool win_should_dim(session_t *ps, const win *w) {
bool dim;
// Make sure we do nothing if the window is unmapped / being destroyed // Make sure we do nothing if the window is unmapped / being destroyed
if (w->destroying || w->a.map_state != XCB_MAP_STATE_VIEWABLE) if (w->state == WSTATE_UNMAPPED) {
return; return false;
if (ps->o.inactive_dim && !(w->focused)) {
dim = true;
} else {
dim = false;
} }
if (dim != w->dim) { if (ps->o.inactive_dim && !(w->focused)) {
w->dim = dim; return true;
add_damage_from_win(ps, w); } else {
return false;
} }
} }
/** /**
* Determine if a window should fade on opacity change. * 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 // To prevent it from being overwritten by last-paint value if the window is
// unmapped on next frame, write w->fade_last as well // unmapped on next frame, write w->fade_last as well
if (UNSET != w->fade_force) if (w->fade_force != UNSET) {
w->fade_last = w->fade = w->fade_force; return w->fade_force;
else if (ps->o.no_fading_openclose && w->in_openclose) }
w->fade_last = w->fade = false; if (ps->o.no_fading_openclose && w->in_openclose) {
else if (ps->o.no_fading_destroyed_argb && w->destroying && return false;
win_has_alpha(w) && w->client_win && w->client_win != w->id) { }
w->fade_last = w->fade = false; if (ps->o.no_fading_destroyed_argb && w->state == WSTATE_DESTROYING &&
win_has_alpha(w) && w->client_win && w->client_win != w->id) {
// deprecated
return false;
} }
// Ignore other possible causes of fading state changes after window // Ignore other possible causes of fading state changes after window
// gets unmapped // gets unmapped
else if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) { //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; if (c2_match(ps, w, ps->o.fade_blacklist, NULL)) {
else return false;
w->fade = ps->o.wintype_option[w->window_type].fade; }
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; shadow_new = w->shadow_force;
else if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) else if (w->a.map_state == XCB_MAP_STATE_VIEWABLE)
shadow_new = (ps->o.wintype_option[w->window_type].shadow && 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 && !(ps->o.shadow_ignore_shaped && w->bounding_shaped &&
!w->rounded_corners) && !w->rounded_corners) &&
!(ps->o.respect_prop_shadow && 0 == w->prop_shadow)); !(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; invert_color_new = w->invert_color_force;
else if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) else if (w->a.map_state == XCB_MAP_STATE_VIEWABLE)
invert_color_new = 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); 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 = bool blur_background_new =
ps->o.blur_background && 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); win_set_blur_background(ps, w, blur_background_new);
} }
/** /**
* Update window opacity according to opacity rules. * 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) { void win_update_opacity_rule(session_t *ps, win *w) {
if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) if (w->a.map_state != XCB_MAP_STATE_VIEWABLE)
return; return;
opacity_t opacity = OPAQUE; double opacity = 1.0;
bool is_set = false; bool is_set = false;
void *val = NULL; void *val = NULL;
if (c2_match(ps, w, ps->o.opacity_rules, &w->cache_oparule, &val)) { if (c2_match(ps, w, ps->o.opacity_rules, &val)) {
opacity = ((double)(long)val) / 100.0 * OPAQUE; opacity = ((double)(long)val) / 100.0;
is_set = true; is_set = true;
} }
@ -548,7 +561,7 @@ void win_update_opacity_rule(session_t *ps, win *w) {
if (!is_set) if (!is_set)
wid_rm_opacity_prop(ps, w->id); wid_rm_opacity_prop(ps, w->id);
else 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) { void win_on_wtype_change(session_t *ps, win *w) {
win_determine_shadow(ps, w); win_determine_shadow(ps, w);
win_determine_fade(ps, w);
win_update_focused(ps, w); win_update_focused(ps, w);
if (ps->o.invert_color_list) if (ps->o.invert_color_list)
win_determine_invert_color(ps, w); 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. * Function to be called on window data changes.
*
* TODO need better name
*/ */
void win_on_factor_change(session_t *ps, win *w) { void win_on_factor_change(session_t *ps, win *w) {
if (ps->o.shadow_blacklist) if (ps->o.shadow_blacklist)
win_determine_shadow(ps, w); win_determine_shadow(ps, w);
if (ps->o.fade_blacklist)
win_determine_fade(ps, w);
if (ps->o.invert_color_list) if (ps->o.invert_color_list)
win_determine_invert_color(ps, w); win_determine_invert_color(ps, w);
if (ps->o.focus_blacklist) 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); win_update_opacity_rule(ps, w);
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE && ps->o.paint_blacklist) if (w->a.map_state == XCB_MAP_STATE_VIEWABLE && ps->o.paint_blacklist)
w->paint_excluded = 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) if (w->a.map_state == XCB_MAP_STATE_VIEWABLE && ps->o.unredir_if_possible_blacklist)
w->unredir_if_possible_excluded = c2_match( 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; w->reg_ignore_valid = false;
} }
@ -733,6 +745,31 @@ void win_recheck_client(session_t *ps, win *w) {
win_mark_client(ps, w, cw); 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) // 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) { bool add_win(session_t *ps, xcb_window_t id, xcb_window_t prev) {
static const win win_def = { 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, .widthb = 0,
.heightb = 0, .heightb = 0,
.destroying = false, .state = WSTATE_UNMAPPED,
.bounding_shaped = false, .bounding_shaped = false,
.rounded_corners = false, .rounded_corners = false,
.to_paint = 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, .client_win = XCB_NONE,
.window_type = WINTYPE_UNKNOWN, .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_instance = NULL,
.class_general = NULL, .class_general = NULL,
.role = NULL, .role = NULL,
.cache_sblst = NULL,
.cache_fblst = NULL,
.cache_fcblst = NULL,
.cache_ivclst = NULL,
.cache_bbblst = NULL,
.cache_oparule = NULL,
.opacity = 0, .opacity = 0,
.opacity_tgt = 0, .opacity_tgt = 0,
.has_opacity_prop = false, .has_opacity_prop = false,
.opacity_prop = OPAQUE, .opacity_prop = OPAQUE,
.opacity_is_set = false, .opacity_is_set = false,
.opacity_set = OPAQUE, .opacity_set = 1,
.fade = false,
.fade_force = UNSET, .fade_force = UNSET,
.fade_callback = NULL,
.frame_opacity = 1.0, .frame_opacity = 1.0,
.frame_extents = MARGIN_INIT, .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; win **p = NULL;
if (prev) { if (prev) {
for (p = &ps->list; *p; p = &(*p)->next) { for (p = &ps->list; *p; p = &(*p)->next) {
if ((*p)->id == prev && !(*p)->destroying) if ((*p)->id == prev && (*p)->state != WSTATE_DESTROYING)
break; break;
} }
} else { } 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); assert(map_state == XCB_MAP_STATE_VIEWABLE || map_state == XCB_MAP_STATE_UNMAPPED);
new->a.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 // Create Damage for window
new->damage = xcb_generate_id(ps->c); new->damage = xcb_generate_id(ps->c);
xcb_generic_error_t *e = xcb_request_check(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 && || (ps->o.mark_ovredir_focused &&
w->id == w->client_win && !w->wmwin) w->id == w->client_win && !w->wmwin)
|| (w->a.map_state == XCB_MAP_STATE_VIEWABLE && || (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; w->focused = true;
// If window grouping detection is enabled, mark the window active if // 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 // Always recalculate the window target opacity, since some opacity-related
// options depend on the output value of win_is_focused_real() instead of // options depend on the output value of win_is_focused_real() instead of
// w->focused // 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) {
} }
} }
/** static void
* Set fade callback of a window, and possibly execute the previous finish_unmap_win(session_t *ps, win **_w) {
* 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) {
win *w = *_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; free_paint(ps, &w->paint);
// Must be the last line as the callback could destroy w! free_paint(ps, &w->shadow_paint);
if (exec_callback && old_callback) }
old_callback(ps, _w);
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 void
win_check_fade_finished(session_t *ps, win **_w) { win_check_fade_finished(session_t *ps, win **_w) {
win *w = *_w; win *w = *_w;
if (w->fade_callback && w->opacity == w->opacity_tgt) { if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
// Must be the last line as the callback could destroy w! // No fading in progress
win_set_fade_callback(ps, _w, NULL, true); 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 :

View File

@ -64,6 +64,46 @@ typedef enum {
WMODE_SOLID, // The window is opaque including the frame WMODE_SOLID, // The window is opaque including the frame
} winmode_t; } 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 * About coordinate systems
* *
@ -88,6 +128,9 @@ struct win {
// Core members // Core members
/// ID of the top-level frame window. /// ID of the top-level frame window.
xcb_window_t id; 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. /// Window attributes.
xcb_get_window_attributes_reply_t a; xcb_get_window_attributes_reply_t a;
xcb_get_geometry_reply_t g; xcb_get_geometry_reply_t g;
@ -175,20 +218,12 @@ struct win {
char *class_general; char *class_general;
/// <code>WM_WINDOW_ROLE</code> value of the window. /// <code>WM_WINDOW_ROLE</code> value of the window.
char *role; 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 // Opacity-related members
/// Current window opacity. /// Current window opacity.
opacity_t opacity; double opacity;
/// Target window opacity. /// Target window opacity.
opacity_t opacity_tgt; double opacity_tgt;
/// true if window (or client window, for broken window managers /// true if window (or client window, for broken window managers
/// not transferring client window's _NET_WM_OPACITY value) has opacity prop /// not transferring client window's _NET_WM_OPACITY value) has opacity prop
bool has_opacity_prop; bool has_opacity_prop;
@ -197,18 +232,11 @@ struct win {
/// true if opacity is set by some rules /// true if opacity is set by some rules
bool opacity_is_set; bool opacity_is_set;
/// Last window opacity value we set. /// Last window opacity value we set.
opacity_t opacity_set; double opacity_set;
// Fading-related members // 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. /// Override value of window fade state. Set by D-Bus method calls.
switch_t fade_force; switch_t fade_force;
/// Callback to be called after fading completed.
void (*fade_callback) (session_t *ps, win **w);
// Frame-opacity-related members // Frame-opacity-related members
/// Current window frame opacity. Affected by window opacity. /// 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. * Set real focused state of a window.
*/ */
void win_set_focused(session_t *ps, win *w, bool focused); 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_raw(session_t *ps, win *w);
void win_update_prop_shadow(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); 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); void win_recheck_client(session_t *ps, win *w);
xcb_window_t win_get_leader_raw(session_t *ps, win *w, int recursions); xcb_window_t win_get_leader_raw(session_t *ps, win *w, int recursions);
bool win_get_class(session_t *ps, win *w); bool win_get_class(session_t *ps, win *w);
void win_calc_opacity(session_t *ps, win *w); double attr_const win_get_opacity_target(session_t *ps, const win *w);
void win_calc_dim(session_t *ps, 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. * Reread opacity property of a window.
*/ */
@ -336,18 +367,8 @@ region_t win_get_region_noframe_local_by_val(win *w);
void void
win_update_frame_extents(session_t *ps, win *w, xcb_window_t client); 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); bool add_win(session_t *ps, xcb_window_t id, xcb_window_t prev);
/// Unmap or destroy a window
/** void unmap_win(session_t *ps, win **, bool destroy);
* 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);
/** /**
* Execute fade callback of a window if fading finished. * 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 /// 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 /// check if reg_ignore_valid is true for all windows above us
bool win_is_region_ignore_valid(session_t *ps, win *w); 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 static inline region_t
win_get_bounding_shape_global_by_val(win *w) { win_get_bounding_shape_global_by_val(win *w) {
region_t ret; region_t ret;