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 static void
install_corners (MetaWindow *window, scan_visible_region (guchar *mask_data,
MetaFrameBorders *borders, int stride,
cairo_t *cr) 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; int x, y;
MetaRectangle outer; cairo_rectangle_int_t rect;
meta_frame_get_corner_radiuses (window->frame, cairo_region_get_rectangle (scan_area, i, &rect);
&top_left,
&top_right,
&bottom_left,
&bottom_right);
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 */ if (w > 0)
x = borders->invisible.left; {
y = borders->invisible.top; cairo_rectangle_int_t tmp = { x, y, w - x, 1 };
cairo_region_union_rectangle (union_against, &tmp);
cairo_arc (cr, x = w;
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);
} }
static void static void
generate_mask (MetaWindowActor *self, build_and_scan_frame_mask (MetaWindowActor *self,
MetaFrameBorders *borders, cairo_rectangle_int_t *client_area,
cairo_region_t *shape_region) cairo_region_t *shape_region)
{ {
MetaWindowActorPrivate *priv = self->priv; MetaWindowActorPrivate *priv = self->priv;
@ -2106,6 +2079,12 @@ generate_mask (MetaWindowActor *self,
{ {
cairo_t *cr; cairo_t *cr;
cairo_surface_t *surface; 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, surface = cairo_image_surface_create_for_data (mask_data,
CAIRO_FORMAT_A8, CAIRO_FORMAT_A8,
@ -2114,7 +2093,13 @@ generate_mask (MetaWindowActor *self,
stride); stride);
cr = cairo_create (surface); 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_destroy (cr);
cairo_surface_destroy (surface); cairo_surface_destroy (surface);
@ -2157,45 +2142,30 @@ check_needs_reshape (MetaWindowActor *self)
MetaDisplay *display = meta_screen_get_display (screen); MetaDisplay *display = meta_screen_get_display (screen);
MetaFrameBorders borders; MetaFrameBorders borders;
cairo_region_t *region; cairo_region_t *region;
cairo_rectangle_int_t client_area;
if (!priv->needs_reshape) if (!priv->needs_reshape)
return; 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); meta_frame_calc_borders (priv->window->frame, &borders);
region = meta_window_get_frame_bounds (priv->window); client_area.x = borders.total.left;
if (region != NULL) client_area.y = borders.total.top;
{ client_area.width = priv->window->rect.width;
/* This returns the window's internal frame bounds region, client_area.height = priv->window->rect.height;
* so we need to copy it because we modify it below. */
region = cairo_region_copy (region); meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), COGL_INVALID_HANDLE);
} meta_window_actor_clear_shape_region (self);
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);
}
#ifdef HAVE_SHAPE #ifdef HAVE_SHAPE
if (priv->window->has_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); Display *xdisplay = meta_display_get_xdisplay (display);
XRectangle *rects; XRectangle *rects;
cairo_rectangle_int_t *cairo_rects = NULL; cairo_rectangle_int_t *cairo_rects = NULL;
int n_rects, ordering; 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); meta_error_trap_push (display);
rects = XShapeGetRectangles (xdisplay, rects = XShapeGetRectangles (xdisplay,
@ -2222,10 +2192,21 @@ check_needs_reshape (MetaWindowActor *self)
region = cairo_region_create_rectangles (cairo_rects, n_rects); region = cairo_region_create_rectangles (cairo_rects, n_rects);
g_free (cairo_rects); g_free (cairo_rects);
} }
else
#endif #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); meta_window_actor_update_shape_region (self, region);
generate_mask (self, &borders, region);
priv->needs_reshape = FALSE; priv->needs_reshape = FALSE;
meta_window_actor_invalidate_shadow (self); meta_window_actor_invalidate_shadow (self);

View File

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

View File

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

View File

@ -687,28 +687,22 @@ meta_frames_get_borders (MetaFrames *frames,
} }
void void
meta_frames_get_corner_radiuses (MetaFrames *frames, meta_frames_render_background (MetaFrames *frames,
Window xwindow, Window xwindow,
float *top_left, cairo_t *cr)
float *top_right,
float *bottom_left,
float *bottom_right)
{ {
MetaUIFrame *frame; MetaUIFrame *frame;
MetaFrameGeometry fgeom; MetaFrameGeometry fgeom;
MetaFrameFlags flags;
frame = meta_frames_lookup_window (frames, xwindow); 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) meta_frames_calc_geometry (frames, frame, &fgeom);
*top_left = fgeom.top_left_corner_rounded_radius; meta_theme_render_background (frame->tv->style_context, cr, flags, &fgeom);
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;
} }
void void

View File

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

View File

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

View File

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

View File

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

View File

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