mirror of
https://github.com/brl/mutter.git
synced 2025-07-03 09:43:18 +00:00
Only shadow ARGB windows with a frame outside the frame
An ARGB window with a frame is likely something like a transparent terminal. It looks awful (and breaks transparency) to draw a big opaque black shadow under the window, so clip out the region under the terminal from the shadow we draw. Add meta_window_get_frame_bounds() to get a cairo region for the outer bounds of the frame of a window, and modify the frame handling code to notice changes to the frame shape and discard a cached region. meta_frames_apply_shapes() is refactored so we can extract meta_frames_get_frame_bounds() from it. https://bugzilla.gnome.org/show_bug.cgi?id=635268
This commit is contained in:
241
src/ui/frames.c
241
src/ui/frames.c
@ -797,6 +797,122 @@ apply_cairo_region_to_window (Display *display,
|
||||
}
|
||||
#endif
|
||||
|
||||
static cairo_region_t *
|
||||
get_bounds_region (MetaFrames *frames,
|
||||
MetaUIFrame *frame,
|
||||
MetaFrameGeometry *fgeom,
|
||||
int window_width,
|
||||
int window_height)
|
||||
{
|
||||
cairo_region_t *corners_region;
|
||||
cairo_region_t *bounds_region;
|
||||
cairo_rectangle_int_t rect;
|
||||
|
||||
corners_region = cairo_region_create ();
|
||||
|
||||
if (fgeom->top_left_corner_rounded_radius != 0)
|
||||
{
|
||||
const int corner = fgeom->top_left_corner_rounded_radius;
|
||||
const float radius = sqrt(corner) + corner;
|
||||
int i;
|
||||
|
||||
for (i=0; i<corner; i++)
|
||||
{
|
||||
const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
|
||||
rect.x = 0;
|
||||
rect.y = i;
|
||||
rect.width = width;
|
||||
rect.height = 1;
|
||||
|
||||
cairo_region_union_rectangle (corners_region, &rect);
|
||||
}
|
||||
}
|
||||
|
||||
if (fgeom->top_right_corner_rounded_radius != 0)
|
||||
{
|
||||
const int corner = fgeom->top_right_corner_rounded_radius;
|
||||
const float radius = sqrt(corner) + corner;
|
||||
int i;
|
||||
|
||||
for (i=0; i<corner; i++)
|
||||
{
|
||||
const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
|
||||
rect.x = window_width - width;
|
||||
rect.y = i;
|
||||
rect.width = width;
|
||||
rect.height = 1;
|
||||
|
||||
cairo_region_union_rectangle (corners_region, &rect);
|
||||
}
|
||||
}
|
||||
|
||||
if (fgeom->bottom_left_corner_rounded_radius != 0)
|
||||
{
|
||||
const int corner = fgeom->bottom_left_corner_rounded_radius;
|
||||
const float radius = sqrt(corner) + corner;
|
||||
int i;
|
||||
|
||||
for (i=0; i<corner; i++)
|
||||
{
|
||||
const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
|
||||
rect.x = 0;
|
||||
rect.y = window_height - i - 1;
|
||||
rect.width = width;
|
||||
rect.height = 1;
|
||||
|
||||
cairo_region_union_rectangle (corners_region, &rect);
|
||||
}
|
||||
}
|
||||
|
||||
if (fgeom->bottom_right_corner_rounded_radius != 0)
|
||||
{
|
||||
const int corner = fgeom->bottom_right_corner_rounded_radius;
|
||||
const float radius = sqrt(corner) + corner;
|
||||
int i;
|
||||
|
||||
for (i=0; i<corner; i++)
|
||||
{
|
||||
const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
|
||||
rect.x = window_width - width;
|
||||
rect.y = window_height - i - 1;
|
||||
rect.width = width;
|
||||
rect.height = 1;
|
||||
|
||||
cairo_region_union_rectangle (corners_region, &rect);
|
||||
}
|
||||
}
|
||||
|
||||
bounds_region = cairo_region_create ();
|
||||
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = window_width;
|
||||
rect.height = window_height;
|
||||
|
||||
cairo_region_union_rectangle (bounds_region, &rect);
|
||||
|
||||
cairo_region_subtract (bounds_region, corners_region);
|
||||
|
||||
cairo_region_destroy (corners_region);
|
||||
|
||||
return bounds_region;
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
get_client_region (MetaFrameGeometry *fgeom,
|
||||
int window_width,
|
||||
int window_height)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
|
||||
rect.x = fgeom->left_width;
|
||||
rect.y = fgeom->top_height;
|
||||
rect.width = window_width - fgeom->right_width - rect.x;
|
||||
rect.height = window_height - fgeom->bottom_height - rect.y;
|
||||
|
||||
return cairo_region_create_rectangle (&rect);
|
||||
}
|
||||
|
||||
void
|
||||
meta_frames_apply_shapes (MetaFrames *frames,
|
||||
Window xwindow,
|
||||
@ -808,8 +924,6 @@ meta_frames_apply_shapes (MetaFrames *frames,
|
||||
/* Apply shapes as if window had new_window_width, new_window_height */
|
||||
MetaUIFrame *frame;
|
||||
MetaFrameGeometry fgeom;
|
||||
cairo_rectangle_int_t rect;
|
||||
cairo_region_t *corners_region;
|
||||
cairo_region_t *window_region;
|
||||
Display *display;
|
||||
|
||||
@ -831,7 +945,7 @@ meta_frames_apply_shapes (MetaFrames *frames,
|
||||
meta_topic (META_DEBUG_SHAPES,
|
||||
"Unsetting shape mask on frame 0x%lx\n",
|
||||
frame->xwindow);
|
||||
|
||||
|
||||
XShapeCombineMask (display, frame->xwindow,
|
||||
ShapeBounding, 0, 0, None, ShapeSet);
|
||||
frame->shape_applied = FALSE;
|
||||
@ -842,97 +956,14 @@ meta_frames_apply_shapes (MetaFrames *frames,
|
||||
"Frame 0x%lx still doesn't need a shape mask\n",
|
||||
frame->xwindow);
|
||||
}
|
||||
|
||||
|
||||
return; /* nothing to do */
|
||||
}
|
||||
|
||||
corners_region = cairo_region_create ();
|
||||
|
||||
if (fgeom.top_left_corner_rounded_radius != 0)
|
||||
{
|
||||
const int corner = fgeom.top_left_corner_rounded_radius;
|
||||
const float radius = sqrt(corner) + corner;
|
||||
int i;
|
||||
|
||||
for (i=0; i<corner; i++)
|
||||
{
|
||||
const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
|
||||
rect.x = 0;
|
||||
rect.y = i;
|
||||
rect.width = width;
|
||||
rect.height = 1;
|
||||
|
||||
cairo_region_union_rectangle (corners_region, &rect);
|
||||
}
|
||||
}
|
||||
window_region = get_bounds_region (frames, frame,
|
||||
&fgeom,
|
||||
new_window_width, new_window_height);
|
||||
|
||||
if (fgeom.top_right_corner_rounded_radius != 0)
|
||||
{
|
||||
const int corner = fgeom.top_right_corner_rounded_radius;
|
||||
const float radius = sqrt(corner) + corner;
|
||||
int i;
|
||||
|
||||
for (i=0; i<corner; i++)
|
||||
{
|
||||
const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
|
||||
rect.x = new_window_width - width;
|
||||
rect.y = i;
|
||||
rect.width = width;
|
||||
rect.height = 1;
|
||||
|
||||
cairo_region_union_rectangle (corners_region, &rect);
|
||||
}
|
||||
}
|
||||
|
||||
if (fgeom.bottom_left_corner_rounded_radius != 0)
|
||||
{
|
||||
const int corner = fgeom.bottom_left_corner_rounded_radius;
|
||||
const float radius = sqrt(corner) + corner;
|
||||
int i;
|
||||
|
||||
for (i=0; i<corner; i++)
|
||||
{
|
||||
const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
|
||||
rect.x = 0;
|
||||
rect.y = new_window_height - i - 1;
|
||||
rect.width = width;
|
||||
rect.height = 1;
|
||||
|
||||
cairo_region_union_rectangle (corners_region, &rect);
|
||||
}
|
||||
}
|
||||
|
||||
if (fgeom.bottom_right_corner_rounded_radius != 0)
|
||||
{
|
||||
const int corner = fgeom.bottom_right_corner_rounded_radius;
|
||||
const float radius = sqrt(corner) + corner;
|
||||
int i;
|
||||
|
||||
for (i=0; i<corner; i++)
|
||||
{
|
||||
const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
|
||||
rect.x = new_window_width - width;
|
||||
rect.y = new_window_height - i - 1;
|
||||
rect.width = width;
|
||||
rect.height = 1;
|
||||
|
||||
cairo_region_union_rectangle (corners_region, &rect);
|
||||
}
|
||||
}
|
||||
|
||||
window_region = cairo_region_create ();
|
||||
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = new_window_width;
|
||||
rect.height = new_window_height;
|
||||
|
||||
cairo_region_union_rectangle (window_region, &rect);
|
||||
|
||||
cairo_region_subtract (window_region, corners_region);
|
||||
|
||||
cairo_region_destroy (corners_region);
|
||||
|
||||
if (window_has_shape)
|
||||
{
|
||||
/* The client window is oclock or something and has a shape
|
||||
@ -984,15 +1015,10 @@ meta_frames_apply_shapes (MetaFrames *frames,
|
||||
/* Punch the client area out of the normal frame shape,
|
||||
* then union it with the shape_window's existing shape
|
||||
*/
|
||||
client_region = cairo_region_create ();
|
||||
|
||||
rect.x = fgeom.left_width;
|
||||
rect.y = fgeom.top_height;
|
||||
rect.width = new_window_width - fgeom.right_width - rect.x;
|
||||
rect.height = new_window_height - fgeom.bottom_height - rect.y;
|
||||
client_region = get_client_region (&fgeom,
|
||||
new_window_width,
|
||||
new_window_height);
|
||||
|
||||
cairo_region_union_rectangle (client_region, &rect);
|
||||
|
||||
cairo_region_subtract (window_region, client_region);
|
||||
|
||||
cairo_region_destroy (client_region);
|
||||
@ -1027,6 +1053,25 @@ meta_frames_apply_shapes (MetaFrames *frames,
|
||||
#endif /* HAVE_SHAPE */
|
||||
}
|
||||
|
||||
cairo_region_t *
|
||||
meta_frames_get_frame_bounds (MetaFrames *frames,
|
||||
Window xwindow,
|
||||
int window_width,
|
||||
int window_height)
|
||||
{
|
||||
MetaUIFrame *frame;
|
||||
MetaFrameGeometry fgeom;
|
||||
|
||||
frame = meta_frames_lookup_window (frames, xwindow);
|
||||
g_return_val_if_fail (frame != NULL, NULL);
|
||||
|
||||
meta_frames_calc_geometry (frames, frame, &fgeom);
|
||||
|
||||
return get_bounds_region (frames, frame,
|
||||
&fgeom,
|
||||
window_width, window_height);
|
||||
}
|
||||
|
||||
void
|
||||
meta_frames_move_resize_frame (MetaFrames *frames,
|
||||
Window xwindow,
|
||||
|
Reference in New Issue
Block a user