window-actor: Paint the frame mask with GTK+ as well

Use meta_theme_render_background to paint the background of the frame,
and then scan it to give us a region we can use to generate the shape
region from. It may be worth looking at the uses of the shape region
to see if we can replace some (all?) of them by masks instead, so we
don't have to scan the mask.
This commit is contained in:
Jasper St. Pierre 2012-04-29 07:40:25 -04:00
parent fd13dad0c4
commit 302302a116
9 changed files with 118 additions and 147 deletions

View File

@ -1991,70 +1991,43 @@ meta_window_actor_sync_visibility (MetaWindowActor *self)
}
static void
install_corners (MetaWindow *window,
MetaFrameBorders *borders,
cairo_t *cr)
scan_visible_region (guchar *mask_data,
int stride,
cairo_region_t *scan_area,
cairo_region_t *union_against)
{
int i, n_rects;
n_rects = cairo_region_num_rectangles (scan_area);
for (i = 0; i < n_rects; i++)
{
float top_left, top_right, bottom_left, bottom_right;
int x, y;
MetaRectangle outer;
cairo_rectangle_int_t rect;
meta_frame_get_corner_radiuses (window->frame,
&top_left,
&top_right,
&bottom_left,
&bottom_right);
cairo_region_get_rectangle (scan_area, i, &rect);
meta_window_get_outer_rect (window, &outer);
for (y = rect.y; y < (rect.y + rect.height); y++)
{
for (x = rect.x; x < (rect.x + rect.width); x++)
{
int w = x;
while (mask_data[y * stride + w] == 255 && w < (rect.x + rect.width))
w++;
/* top left */
x = borders->invisible.left;
y = borders->invisible.top;
cairo_arc (cr,
x + top_left,
y + top_left,
top_left,
0, M_PI*2);
/* top right */
x = borders->invisible.left + outer.width - top_right;
y = borders->invisible.top;
cairo_arc (cr,
x,
y + top_right,
top_right,
0, M_PI*2);
/* bottom right */
x = borders->invisible.left + outer.width - bottom_right;
y = borders->invisible.top + outer.height - bottom_right;
cairo_arc (cr,
x,
y,
bottom_right,
0, M_PI*2);
/* bottom left */
x = borders->invisible.left;
y = borders->invisible.top + outer.height - bottom_left;
cairo_arc (cr,
x + bottom_left,
y,
bottom_left,
0, M_PI*2);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba (cr, 1, 1, 1, 1);
cairo_fill (cr);
if (w > 0)
{
cairo_rectangle_int_t tmp = { x, y, w - x, 1 };
cairo_region_union_rectangle (union_against, &tmp);
x = w;
}
}
}
}
}
static void
generate_mask (MetaWindowActor *self,
MetaFrameBorders *borders,
build_and_scan_frame_mask (MetaWindowActor *self,
cairo_rectangle_int_t *client_area,
cairo_region_t *shape_region)
{
MetaWindowActorPrivate *priv = self->priv;
@ -2106,6 +2079,12 @@ generate_mask (MetaWindowActor *self,
{
cairo_t *cr;
cairo_surface_t *surface;
cairo_region_t *frame_paint_region;
cairo_rectangle_int_t rect = { 0, 0, tex_width, tex_height };
/* Make sure we don't paint the frame over the client window. */
frame_paint_region = cairo_region_create_rectangle (&rect);
cairo_region_subtract_rectangle (frame_paint_region, client_area);
surface = cairo_image_surface_create_for_data (mask_data,
CAIRO_FORMAT_A8,
@ -2114,7 +2093,13 @@ generate_mask (MetaWindowActor *self,
stride);
cr = cairo_create (surface);
install_corners (priv->window, borders, cr);
gdk_cairo_region (cr, frame_paint_region);
cairo_clip (cr);
meta_frame_render_background (priv->window->frame, cr);
cairo_surface_flush (surface);
scan_visible_region (mask_data, stride, frame_paint_region, shape_region);
cairo_destroy (cr);
cairo_surface_destroy (surface);
@ -2157,45 +2142,30 @@ check_needs_reshape (MetaWindowActor *self)
MetaDisplay *display = meta_screen_get_display (screen);
MetaFrameBorders borders;
cairo_region_t *region;
cairo_rectangle_int_t client_area;
if (!priv->needs_reshape)
return;
meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), COGL_INVALID_HANDLE);
meta_window_actor_clear_shape_region (self);
meta_frame_calc_borders (priv->window->frame, &borders);
region = meta_window_get_frame_bounds (priv->window);
if (region != NULL)
{
/* This returns the window's internal frame bounds region,
* so we need to copy it because we modify it below. */
region = cairo_region_copy (region);
}
else
{
/* If we have no region, we have no frame. We have no frame,
* so just use the bounding region instead */
region = cairo_region_copy (priv->bounding_region);
}
client_area.x = borders.total.left;
client_area.y = borders.total.top;
client_area.width = priv->window->rect.width;
client_area.height = priv->window->rect.height;
meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), COGL_INVALID_HANDLE);
meta_window_actor_clear_shape_region (self);
#ifdef HAVE_SHAPE
if (priv->window->has_shape)
{
/* Translate the set of XShape rectangles that we
* get from the X server to a cairo_region. */
Display *xdisplay = meta_display_get_xdisplay (display);
XRectangle *rects;
cairo_rectangle_int_t *cairo_rects = NULL;
int n_rects, ordering;
cairo_rectangle_int_t client_area;
client_area.width = priv->window->rect.width;
client_area.height = priv->window->rect.height;
client_area.x = borders.total.left;
client_area.y = borders.total.top;
/* Punch out client area. */
cairo_region_subtract_rectangle (region, &client_area);
meta_error_trap_push (display);
rects = XShapeGetRectangles (xdisplay,
@ -2222,10 +2192,21 @@ check_needs_reshape (MetaWindowActor *self)
region = cairo_region_create_rectangles (cairo_rects, n_rects);
g_free (cairo_rects);
}
else
#endif
{
/* If we don't have a shape on the server, that means that
* we have an implicit shape of one rectangle covering the
* entire window. */
region = cairo_region_create_rectangle (&client_area);
}
/* This takes the region, generates a mask using GTK+
* and scans the mask looking for all opaque pixels,
* adding it to region.
*/
build_and_scan_frame_mask (self, &client_area, region);
meta_window_actor_update_shape_region (self, region);
generate_mask (self, &borders, region);
priv->needs_reshape = FALSE;
meta_window_actor_invalidate_shadow (self);

View File

@ -333,16 +333,12 @@ meta_frame_calc_borders (MetaFrame *frame,
}
void
meta_frame_get_corner_radiuses (MetaFrame *frame,
float *top_left,
float *top_right,
float *bottom_left,
float *bottom_right)
meta_frame_render_background (MetaFrame *frame,
cairo_t *cr)
{
meta_ui_get_corner_radiuses (frame->window->screen->ui,
meta_ui_render_background (frame->window->screen->ui,
frame->xwindow,
top_left, top_right,
bottom_left, bottom_right);
cr);
}
gboolean

View File

@ -63,11 +63,8 @@ Window meta_frame_get_xwindow (MetaFrame *frame);
void meta_frame_calc_borders (MetaFrame *frame,
MetaFrameBorders *borders);
void meta_frame_get_corner_radiuses (MetaFrame *frame,
float *top_left,
float *top_right,
float *bottom_left,
float *bottom_right);
void meta_frame_render_background (MetaFrame *frame,
cairo_t *cr);
gboolean meta_frame_sync_to_window (MetaFrame *frame,
int gravity,

View File

@ -687,28 +687,22 @@ meta_frames_get_borders (MetaFrames *frames,
}
void
meta_frames_get_corner_radiuses (MetaFrames *frames,
meta_frames_render_background (MetaFrames *frames,
Window xwindow,
float *top_left,
float *top_right,
float *bottom_left,
float *bottom_right)
cairo_t *cr)
{
MetaUIFrame *frame;
MetaFrameGeometry fgeom;
MetaFrameFlags flags;
frame = meta_frames_lookup_window (frames, xwindow);
meta_frames_calc_geometry (frames, frame, &fgeom);
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
META_CORE_GET_FRAME_FLAGS, &flags,
META_CORE_GET_END);
if (top_left)
*top_left = fgeom.top_left_corner_rounded_radius;
if (top_right)
*top_right = fgeom.top_right_corner_rounded_radius;
if (bottom_left)
*bottom_left = fgeom.bottom_left_corner_rounded_radius;
if (bottom_right)
*bottom_right = fgeom.bottom_right_corner_rounded_radius;
meta_frames_calc_geometry (frames, frame, &fgeom);
meta_theme_render_background (frame->tv->style_context, cr, flags, &fgeom);
}
void

View File

@ -143,12 +143,9 @@ cairo_region_t *meta_frames_get_frame_bounds (MetaFrames *frames,
int window_width,
int window_height);
void meta_frames_get_corner_radiuses (MetaFrames *frames,
void meta_frames_render_background (MetaFrames *frames,
Window xwindow,
float *top_left,
float *top_right,
float *bottom_left,
float *bottom_right);
cairo_t *cr);
void meta_frames_move_resize_frame (MetaFrames *frames,
Window xwindow,

View File

@ -1030,6 +1030,11 @@ double meta_theme_get_title_scale (MetaTheme *theme,
MetaFrameType type,
MetaFrameFlags flags);
void meta_theme_render_background (GtkStyleContext *style,
cairo_t *cr,
MetaFrameFlags flags,
const MetaFrameGeometry *fgeom);
void meta_theme_draw_frame (MetaTheme *theme,
GtkWidget *widget,
cairo_t *cr,

View File

@ -4117,19 +4117,11 @@ button_rect (MetaButtonType type,
}
}
static void
meta_frame_style_draw_with_style (MetaFrameStyle *style,
GtkStyleContext *style_gtk,
MetaFrameFlags flags,
void
meta_theme_render_background (GtkStyleContext *style_gtk,
cairo_t *cr,
const MetaFrameGeometry *fgeom,
int client_width,
int client_height,
PangoLayout *title_layout,
int text_height,
MetaButtonState button_states[META_BUTTON_TYPE_LAST],
GdkPixbuf *mini_icon,
GdkPixbuf *icon)
MetaFrameFlags flags,
const MetaFrameGeometry *fgeom)
{
GdkRectangle visible_rect;
const MetaFrameBorders *borders;
@ -4158,6 +4150,23 @@ meta_frame_style_draw_with_style (MetaFrameStyle *style,
visible_rect.height);
gtk_style_context_restore (style_gtk);
}
static void
meta_frame_style_draw_with_style (MetaFrameStyle *style,
GtkStyleContext *style_gtk,
MetaFrameFlags flags,
cairo_t *cr,
const MetaFrameGeometry *fgeom,
int client_width,
int client_height,
PangoLayout *title_layout,
int text_height,
MetaButtonState button_states[META_BUTTON_TYPE_LAST],
GdkPixbuf *mini_icon,
GdkPixbuf *icon)
{
meta_theme_render_background (style_gtk, cr, flags, fgeom);
#if 0
int i, j;

View File

@ -318,16 +318,11 @@ meta_ui_get_frame_borders (MetaUI *ui,
}
void
meta_ui_get_corner_radiuses (MetaUI *ui,
meta_ui_render_background (MetaUI *ui,
Window xwindow,
float *top_left,
float *top_right,
float *bottom_left,
float *bottom_right)
cairo_t *cr)
{
meta_frames_get_corner_radiuses (ui->frames, xwindow,
top_left, top_right,
bottom_left, bottom_right);
meta_frames_render_background (ui->frames, xwindow, cr);
}
Window

View File

@ -100,12 +100,9 @@ cairo_region_t *meta_ui_get_frame_bounds (MetaUI *ui,
int window_width,
int window_height);
void meta_ui_get_corner_radiuses (MetaUI *ui,
void meta_ui_render_background (MetaUI *ui,
Window xwindow,
float *top_left,
float *top_right,
float *bottom_left,
float *bottom_right);
cairo_t *cr);
void meta_ui_queue_frame_draw (MetaUI *ui,
Window xwindow);