diff --git a/src/common.h b/src/common.h index 7778c74..1414ceb 100644 --- a/src/common.h +++ b/src/common.h @@ -1028,6 +1028,16 @@ typedef struct session { #endif } session_t; +/** + * About coordinate systems + * + * In general, X is the horizontal axis, Y is the vertical axis. + * X goes from left to right, Y goes downwards. + * + * Global: the origin is the top left corner of the Xorg screen. + * Local: the origin is the top left corner of the window, including border. + */ + /// Structure representing a top-level window compton manages. struct win { /// Pointer to the next lower window in window stack. @@ -1061,7 +1071,8 @@ struct win { xcb_damage_damage_t damage; /// Paint info of the window. paint_t paint; - /// Bounding shape of the window. + /// Bounding shape of the window. In local coordinates. + /// See above about coordinate systems. region_t bounding_shape; /// Window flags. Definitions above. int_fast16_t flags; diff --git a/src/compton.c b/src/compton.c index ab8fbdd..b2b991c 100644 --- a/src/compton.c +++ b/src/compton.c @@ -654,6 +654,7 @@ static bool win_build_shadow(session_t *ps, win *w, double opacity) { const int width = w->widthb; const int height = w->heightb; + //printf_errf("(): building shadow for %s %d %d", w->name, width, height); xcb_image_t *shadow_image = NULL; xcb_pixmap_t shadow_pixmap = None, shadow_pixmap_argb = None; @@ -1113,6 +1114,7 @@ paint_preprocess(session_t *ps, win *list) { || get_alpha_pict_o(ps, w->opacity) == ps->alpha_picts[0] || w->paint_excluded) to_paint = false; + //printf_errf("(): %s %d %d %d", w->name, to_paint, w->opacity, w->paint_excluded); // Add window to damaged area if its painting status changes // or opacity changes @@ -1125,11 +1127,6 @@ paint_preprocess(session_t *ps, win *list) { if (!to_paint) goto skip_window; - // XXX shouldn't need these - // Fetch bounding region - if (!pixman_region32_not_empty(&w->bounding_shape)) - win_update_bounding_shape(ps, w); - // Fetch window extents region_t extents; pixman_region32_init(&extents); @@ -1148,10 +1145,11 @@ paint_preprocess(session_t *ps, win *list) { if (w->mode == WMODE_SOLID && !ps->o.force_win_blend) { region_t *tmp = rc_region_new(); if (w->frame_opacity == 1) - copy_region(tmp, &w->bounding_shape); + *tmp = win_get_bounding_shape_global_by_val(w); else { - win_get_region_noframe(ps, w, true, tmp); + win_get_region_noframe_local(ps, w, tmp); pixman_region32_intersect(tmp, tmp, &w->bounding_shape); + pixman_region32_translate(tmp, w->g.x, w->g.y); } pixman_region32_union(tmp, tmp, last_reg_ignore); @@ -1389,13 +1387,12 @@ win_blur_background(session_t *ps, win *w, xcb_render_picture_t tgt_buffer, // Minimize the region we try to blur, if the window itself is not // opaque, only the frame is. - region_t reg_blur; - pixman_region32_init(®_blur); - pixman_region32_copy(®_blur, &w->bounding_shape); + region_t reg_blur = win_get_bounding_shape_global_by_val(w); if (win_is_solid(ps, w)) { region_t reg_noframe; pixman_region32_init(®_noframe); - win_get_region_noframe(ps, w, true, ®_noframe); + win_get_region_noframe_local(ps, w, ®_noframe); + pixman_region32_translate(®_noframe, w->g.x, w->g.y); pixman_region32_subtract(®_blur, ®_blur, ®_noframe); pixman_region32_fini(®_noframe); } @@ -1754,6 +1751,7 @@ paint_all(session_t *ps, region_t *region, const region_t *region_real, win * co // // Whether this is beneficial is to be determined XXX for (win *w = t; w; w = w->prev_trans) { + region_t bshape = win_get_bounding_shape_global_by_val(w); // Painting shadow if (w->shadow) { // Lazy shadow building @@ -1777,7 +1775,7 @@ paint_all(session_t *ps, region_t *region, const region_t *region_real, win * co // Mask out the body of the window from the shadow // Doing it here instead of in make_shadow() for saving GPU // power and handling shaped windows (XXX unconfirmed) - pixman_region32_subtract(®_tmp, ®_tmp, &w->bounding_shape); + pixman_region32_subtract(®_tmp, ®_tmp, &bshape); #ifdef CONFIG_XINERAMA if (ps->o.xinerama_shadow_crop && w->xinerama_scr >= 0) @@ -1796,7 +1794,8 @@ paint_all(session_t *ps, region_t *region, const region_t *region_real, win * co // window and the bounding region // XXX XXX pixman_region32_subtract(®_tmp, region, w->reg_ignore); - pixman_region32_intersect(®_tmp, ®_tmp, &w->bounding_shape); + pixman_region32_intersect(®_tmp, ®_tmp, &bshape); + pixman_region32_fini(&bshape); if (pixman_region32_not_empty(®_tmp)) { set_tgt_clip(ps, ®_tmp); @@ -2280,18 +2279,12 @@ configure_win(session_t *ps, xcb_configure_notify_event_t *ce) { // If window geometry change, free old extents if (w->g.x != ce->x || w->g.y != ce->y || w->g.width != ce->width || w->g.height != ce->height - || w->g.border_width != ce->border_width) { + || w->g.border_width != ce->border_width) factor_change = true; - pixman_region32_clear(&w->bounding_shape); - } w->g.x = ce->x; w->g.y = ce->y; - if (w->g.width != ce->width || w->g.height != ce->height - || w->g.border_width != ce->border_width) - free_wpaint(ps, w); - if (w->g.width != ce->width || w->g.height != ce->height || w->g.border_width != ce->border_width) { w->g.width = ce->width; @@ -2310,7 +2303,6 @@ configure_win(session_t *ps, xcb_configure_notify_event_t *ce) { if (factor_change) { add_damage(ps, &damage); cxinerama_win_upd_scr(ps, w); - win_on_factor_change(ps, w); } } @@ -2981,10 +2973,17 @@ ev_shape_notify(session_t *ps, xcb_shape_notify_event_t *ev) { * if we attempt to rebuild border_size */ // Mark the old border_size as damaged - add_damage(ps, &w->bounding_shape); + region_t tmp = win_get_bounding_shape_global_by_val(w); + add_damage(ps, &tmp); + pixman_region32_fini(&tmp); + win_update_bounding_shape(ps, w); + // Mark the new border_size as damaged - add_damage(ps, &w->bounding_shape); + tmp = win_get_bounding_shape_global_by_val(w); + add_damage(ps, &tmp); + pixman_region32_fini(&tmp); + w->reg_ignore_valid = false; } diff --git a/src/win.c b/src/win.c index 73d4e2d..ab205f2 100644 --- a/src/win.c +++ b/src/win.c @@ -16,6 +16,16 @@ #include "win.h" +/// 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 *) +#define gen_by_val(fun) void region_t fun##_by_val(win *w) { \ + region_t ret; \ + pixman_region32_init(&ret); \ + fun(w, &ret); \ + return ret; \ +} + /** * Clear leader cache of all windows. */ @@ -78,23 +88,20 @@ group_is_focused(session_t *ps, Window leader) { /** * Get a rectangular region a window occupies, excluding shadow. */ -void win_get_region(session_t *ps, win *w, bool global, region_t *res) { +static void win_get_region_local(session_t *ps, win *w, region_t *res) { pixman_region32_fini(res); - pixman_region32_init_rect(res, - global ? w->g.x : 0, - global ? w->g.y : 0, - w->widthb, w->heightb); + pixman_region32_init_rect(res, 0, 0, w->widthb, w->heightb); } /** * Get a rectangular region a window occupies, excluding frame and shadow. */ -void win_get_region_noframe(session_t *ps, win *w, bool global, region_t *res) { +void win_get_region_noframe_local(session_t *ps, win *w, region_t *res) { const margin_t extents = win_calc_frame_extents(ps, w); - int x = (global ? w->g.x: 0) + extents.left; - int y = (global ? w->g.y: 0) + extents.top; + int x = extents.left; + int y = extents.top; int width = max_i(w->g.width - extents.left - extents.right, 0); int height = max_i(w->g.height - extents.top - extents.bottom, 0); @@ -880,6 +887,7 @@ bool add_win(session_t *ps, Window id, Window prev) { new->next = *p; *p = new; + win_update_bounding_shape(ps, new); #ifdef CONFIG_DBUS // Send D-Bus signal @@ -1144,10 +1152,11 @@ void win_update_bounding_shape(session_t *ps, win *w) { pixman_region32_clear(&w->bounding_shape); // Start with the window rectangular region - win_get_region(ps, w, true, &w->bounding_shape); + win_get_region_local(ps, w, &w->bounding_shape); // Only request for a bounding region if the window is shaped - if (w->bounding_shaped) { + // (while loop is used to avoid goto, not an actual loop) + while (w->bounding_shaped) { /* * if window doesn't exist anymore, this will generate an error * as well as not generate a region. @@ -1157,7 +1166,7 @@ void win_update_bounding_shape(session_t *ps, win *w) { xcb_shape_get_rectangles(ps->c, w->id, XCB_SHAPE_SK_BOUNDING), NULL); if (!r) - return; + break; xcb_rectangle_t *xrects = xcb_shape_get_rectangles_rectangles(r); int nrects = xcb_shape_get_rectangles_rectangles_length(r); @@ -1171,22 +1180,24 @@ void win_update_bounding_shape(session_t *ps, win *w) { // Add border width because we are using a different origin. // X thinks the top left of the inner window is the origin, // We think the top left of the border is the origin - pixman_region32_translate(&br, w->g.x + w->g.border_width, - w->g.y + w->g.border_width); + pixman_region32_translate(&br, w->g.border_width, w->g.border_width); // Intersect the bounding region we got with the window rectangle, to // make sure the bounding region is not bigger than the window // rectangle pixman_region32_intersect(&w->bounding_shape, &w->bounding_shape, &br); pixman_region32_fini(&br); + break; } if (w->bounding_shaped && ps->o.detect_rounded_corners) win_rounded_corners(ps, w); - // XXX Window shape changed, and if we didn't fill in the pixels - // behind the window (not implemented yet), we should rebuild - // the shadow_pict + // Window shape changed, we should free old wpaint and shadow pict + free_wpaint(ps, w); + free_paint(ps, &w->shadow_paint); + //printf_errf("(): free out dated pict"); + win_on_factor_change(ps, w); } diff --git a/src/win.h b/src/win.h index 9374283..42b0cc0 100644 --- a/src/win.h +++ b/src/win.h @@ -70,16 +70,12 @@ void win_extents(win *w, region_t *res); * @param w struct _win element representing the window */ void add_damage_from_win(session_t *ps, win *w); -/** - * Get a rectangular region a window occupies, excluding shadow. - * - * global = use global coordinates - */ -void win_get_region(session_t *ps, win *w, bool global, region_t *); /** * Get a rectangular region a window occupies, excluding frame and shadow. + * + * Return region in global coordinates. */ -void win_get_region_noframe(session_t *ps, win *w, bool global, region_t *); +void win_get_region_noframe_local(session_t *ps, win *w, region_t *); /** * Retrieve frame extents from a window. */ @@ -102,3 +98,12 @@ bool win_has_alpha(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); + +static inline region_t +win_get_bounding_shape_global_by_val(win *w) { + region_t ret; + pixman_region32_init(&ret); + pixman_region32_copy(&ret, &w->bounding_shape); + pixman_region32_translate(&ret, w->g.x, w->g.y); + return ret; +}