wayland: Add support for set_opaque_region / set_input_region

https://bugzilla.gnome.org/show_bug.cgi?id=707019
This commit is contained in:
Jasper St. Pierre 2013-08-23 22:20:49 -04:00
parent 95e2d26d03
commit 2d35e07fae
9 changed files with 326 additions and 319 deletions

View File

@ -930,8 +930,8 @@ is_grabbed_event (MetaDisplay *display,
} }
void void
meta_compositor_window_x11_shape_changed (MetaCompositor *compositor, meta_compositor_window_shape_changed (MetaCompositor *compositor,
MetaWindow *window) MetaWindow *window)
{ {
MetaWindowActor *window_actor; MetaWindowActor *window_actor;
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));

View File

@ -10,7 +10,6 @@
#include <math.h> #include <math.h>
#include <X11/extensions/shape.h>
#include <X11/extensions/Xcomposite.h> #include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h> #include <X11/extensions/Xdamage.h>
#include <X11/extensions/Xrender.h> #include <X11/extensions/Xrender.h>
@ -71,7 +70,7 @@ struct _MetaWindowActorPrivate
/* A region that matches the shape of the window, including frame bounds */ /* A region that matches the shape of the window, including frame bounds */
cairo_region_t *shape_region; cairo_region_t *shape_region;
/* If the window has an input shape, a region that matches the shape */ /* If the window has an input shape, a region that matches the shape */
cairo_region_t *input_shape_region; cairo_region_t *input_region;
/* The opaque region, from _NET_WM_OPAQUE_REGION, intersected with /* The opaque region, from _NET_WM_OPAQUE_REGION, intersected with
* the shape region. */ * the shape region. */
cairo_region_t *opaque_region; cairo_region_t *opaque_region;
@ -416,8 +415,8 @@ meta_window_actor_constructed (GObject *object)
/* Start off with empty regions to maintain the invariant that /* Start off with empty regions to maintain the invariant that
these regions are always set */ these regions are always set */
priv->shape_region = cairo_region_create(); priv->shape_region = cairo_region_create ();
priv->input_shape_region = cairo_region_create(); priv->input_region = cairo_region_create ();
} }
static void static void
@ -447,7 +446,7 @@ meta_window_actor_dispose (GObject *object)
} }
g_clear_pointer (&priv->shape_region, cairo_region_destroy); g_clear_pointer (&priv->shape_region, cairo_region_destroy);
g_clear_pointer (&priv->input_shape_region, cairo_region_destroy); g_clear_pointer (&priv->input_region, cairo_region_destroy);
g_clear_pointer (&priv->opaque_region, cairo_region_destroy); g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
g_clear_pointer (&priv->shadow_clip, cairo_region_destroy); g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
@ -1269,7 +1268,7 @@ meta_window_actor_should_unredirect (MetaWindowActor *self)
if (priv->opacity != 0xff) if (priv->opacity != 0xff)
return FALSE; return FALSE;
if (metaWindow->has_shape) if (metaWindow->shape_region != NULL)
return FALSE; return FALSE;
if (priv->argb32 && !meta_window_requested_bypass_compositor (metaWindow)) if (priv->argb32 && !meta_window_requested_bypass_compositor (metaWindow))
@ -2180,85 +2179,21 @@ build_and_scan_frame_mask (MetaWindowActor *self,
g_free (mask_data); g_free (mask_data);
} }
static cairo_region_t *
region_create_from_x_rectangles (const XRectangle *rects,
int n_rects,
int dx,
int dy)
{
int i;
cairo_rectangle_int_t *cairo_rects = g_newa (cairo_rectangle_int_t, n_rects);
for (i = 0; i < n_rects; i ++)
{
cairo_rects[i].x = rects[i].x + dx;
cairo_rects[i].y = rects[i].y + dy;
cairo_rects[i].width = rects[i].width;
cairo_rects[i].height = rects[i].height;
}
return cairo_region_create_rectangles (cairo_rects, n_rects);
}
static void static void
meta_window_actor_update_x11_shape_region (MetaWindowActor *self, meta_window_actor_update_shape_region (MetaWindowActor *self,
cairo_rectangle_int_t *client_area) cairo_rectangle_int_t *client_area)
{ {
MetaWindowActorPrivate *priv = self->priv; MetaWindowActorPrivate *priv = self->priv;
cairo_region_t *region = NULL; cairo_region_t *region = NULL;
gboolean needs_mask;
if (priv->shadow_shape != NULL) if (priv->window->frame != NULL && priv->window->shape_region != NULL)
{ {
meta_window_shape_unref (priv->shadow_shape); region = cairo_region_copy (priv->window->shape_region);
priv->shadow_shape = NULL; cairo_region_translate (region, client_area->x, client_area->y);
} }
else if (priv->window->shape_region != NULL)
meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), NULL);
g_clear_pointer (&priv->shape_region, cairo_region_destroy);
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
#ifdef HAVE_SHAPE
if (priv->window->has_shape)
{ {
/* Translate the set of XShape rectangles that we region = cairo_region_reference (priv->window->shape_region);
* get from the X server to a cairo_region. */
MetaScreen *screen = priv->screen;
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay = meta_display_get_xdisplay (display);
XRectangle *rects;
int n_rects, ordering;
meta_error_trap_push (display);
rects = XShapeGetRectangles (xdisplay,
priv->window->xwindow,
ShapeBounding,
&n_rects,
&ordering);
meta_error_trap_pop (display);
if (rects)
{
region = region_create_from_x_rectangles (rects, n_rects,
client_area->x,
client_area->y);
XFree (rects);
}
}
#endif
needs_mask = (region != NULL) || (priv->window->frame != NULL);
if (region != NULL)
{
/* The shape we get back from the client may have coordinates
* outside of the frame. The X SHAPE Extension requires that
* the overall shape the client provides never exceeds the
* "bounding rectangle" of the window -- the shape that the
* window would have gotten if it was unshaped. In our case,
* this is simply the client area.
*/
cairo_region_intersect_rectangle (region, client_area);
} }
else else
{ {
@ -2268,11 +2203,71 @@ meta_window_actor_update_x11_shape_region (MetaWindowActor *self,
region = cairo_region_create_rectangle (client_area); region = cairo_region_create_rectangle (client_area);
} }
/* The region at this point should be constrained to the meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), NULL);
* bounds of the client rectangle. */ if ((priv->window->shape_region != NULL) || (priv->window->frame != NULL))
build_and_scan_frame_mask (self, client_area, region);
g_clear_pointer (&priv->shape_region, cairo_region_destroy);
priv->shape_region = region;
if (priv->shadow_shape != NULL)
{
meta_window_shape_unref (priv->shadow_shape);
priv->shadow_shape = NULL;
}
meta_window_actor_invalidate_shadow (self);
}
static void
meta_window_actor_update_input_region (MetaWindowActor *self,
cairo_rectangle_int_t *client_area)
{
MetaWindowActorPrivate *priv = self->priv;
MetaShapedTexture *stex = META_SHAPED_TEXTURE (priv->actor);
cairo_region_t *region = NULL;
if (priv->window->frame != NULL && priv->window->input_region != NULL)
{
region = meta_frame_get_frame_bounds (priv->window->frame);
cairo_region_subtract_rectangle (region, client_area);
/* input_region is in client window coordinates, so translate the
* input region into that coordinate system and back */
cairo_region_translate (region, -client_area->x, -client_area->y);
cairo_region_union (region, priv->window->input_region);
cairo_region_translate (region, client_area->x, client_area->y);
}
else if (priv->window->shape_region != NULL)
{
region = cairo_region_reference (priv->window->input_region);
}
else
{
/* 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);
}
meta_shaped_texture_set_input_shape_region (stex, region);
cairo_region_destroy (region);
}
static void
meta_window_actor_update_opaque_region (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
if (priv->argb32 && priv->window->opaque_region != NULL) if (priv->argb32 && priv->window->opaque_region != NULL)
{ {
MetaFrameBorders borders;
meta_frame_calc_borders (priv->window->frame, &borders);
/* The opaque region is defined to be a part of the /* The opaque region is defined to be a part of the
* window which ARGB32 will always paint with opaque * window which ARGB32 will always paint with opaque
* pixels. For these regions, we want to avoid painting * pixels. For these regions, we want to avoid painting
@ -2284,91 +2279,13 @@ meta_window_actor_update_x11_shape_region (MetaWindowActor *self,
* case, graphical glitches will occur. * case, graphical glitches will occur.
*/ */
priv->opaque_region = cairo_region_copy (priv->window->opaque_region); priv->opaque_region = cairo_region_copy (priv->window->opaque_region);
cairo_region_translate (priv->opaque_region, client_area->x, client_area->y); cairo_region_translate (priv->opaque_region, borders.total.left, borders.total.top);
cairo_region_intersect (priv->opaque_region, region); cairo_region_intersect (priv->opaque_region, priv->shape_region);
} }
else if (priv->argb32) else if (priv->argb32)
priv->opaque_region = NULL; priv->opaque_region = NULL;
else else
priv->opaque_region = cairo_region_reference (region); priv->opaque_region = cairo_region_reference (priv->shape_region);
if (needs_mask)
{
/* 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);
}
priv->shape_region = region;
meta_window_actor_invalidate_shadow (self);
}
static void
meta_window_actor_update_x11_input_shape_region (MetaWindowActor *self,
cairo_rectangle_int_t *client_area)
{
MetaWindowActorPrivate *priv = self->priv;
cairo_region_t *region = NULL;
g_clear_pointer (&priv->input_shape_region, cairo_region_destroy);
#ifdef HAVE_SHAPE
/* Note: we currently assume that mutter never sets an input region
* when there is a frame. */
if (priv->window->frame == NULL && priv->window->has_input_shape)
{
MetaScreen *screen = priv->screen;
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay = meta_display_get_xdisplay (display);
XRectangle *rects;
int n_rects, ordering;
/* Note we only actually query the ShapeInput shape of a window
* when we don't have a frame because we assume currently that
* mutter never sets an ShapeInput shape on a frame. */
meta_error_trap_push (display);
rects = XShapeGetRectangles (xdisplay,
priv->window->xwindow,
ShapeInput,
&n_rects,
&ordering);
meta_error_trap_pop (display);
if (rects)
{
region = region_create_from_x_rectangles (rects, n_rects,
client_area->x,
client_area->y);
XFree (rects);
}
}
#endif /* HAVE_SHAPE */
if (region != NULL)
{
/* The X shape extension requires us to intersect the input
* region with the effective bounding shape to determine the
* effective input region.
*/
if (priv->shape_region)
cairo_region_intersect (region, priv->shape_region);
else
cairo_region_intersect_rectangle (region, client_area);
}
else
{
/* 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);
}
priv->input_shape_region = region;
meta_shaped_texture_set_input_shape_region (META_SHAPED_TEXTURE (priv->actor),
priv->input_shape_region);
} }
static void static void
@ -2394,24 +2311,9 @@ check_needs_reshape (MetaWindowActor *self)
else else
client_area.height = priv->window->rect.height; client_area.height = priv->window->rect.height;
if (priv->window->client_type == META_WINDOW_CLIENT_TYPE_X11) meta_window_actor_update_shape_region (self, &client_area);
{ meta_window_actor_update_input_region (self, &client_area);
meta_window_actor_update_x11_shape_region (self, &client_area); meta_window_actor_update_opaque_region (self);
meta_window_actor_update_x11_input_shape_region (self, &client_area);
}
else
{
/* TODO: properly support setting an input region as specified
* via the wayland protocol */
g_clear_pointer (&priv->shape_region, cairo_region_destroy);
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
g_clear_pointer (&priv->input_shape_region, cairo_region_destroy);
priv->shape_region = cairo_region_create_rectangle (&client_area);
priv->opaque_region = cairo_region_reference (priv->shape_region);
priv->input_shape_region = cairo_region_reference (priv->shape_region);
}
priv->needs_reshape = FALSE; priv->needs_reshape = FALSE;
} }

View File

@ -186,7 +186,6 @@ meta_window_group_paint (ClutterActor *actor)
if (META_IS_WINDOW_ACTOR (child)) if (META_IS_WINDOW_ACTOR (child))
{ {
MetaWindow *meta_window;
MetaWindowActor *window_actor = META_WINDOW_ACTOR (child); MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
int x, y; int x, y;
@ -201,14 +200,7 @@ meta_window_group_paint (ClutterActor *actor)
meta_window_actor_set_visible_region (window_actor, visible_region); meta_window_actor_set_visible_region (window_actor, visible_region);
/* TODO: Track the opaque regions of wayland clients. if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
* Although wayland clients can report opaque window
* regions, for now we assume that all wayland clients are
* transparent... */
meta_window = meta_window_actor_get_meta_window (window_actor);
if (meta_window->client_type != META_WINDOW_CLIENT_TYPE_WAYLAND &&
clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
{ {
cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor); cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
if (obscured_region) if (obscured_region)

View File

@ -2336,59 +2336,9 @@ meta_display_handle_event (MetaDisplay *display,
XShapeEvent *sev = (XShapeEvent*) event; XShapeEvent *sev = (XShapeEvent*) event;
if (sev->kind == ShapeBounding) if (sev->kind == ShapeBounding)
{ meta_window_update_shape_region_x11 (window);
if (sev->shaped && !window->has_shape)
{
window->has_shape = TRUE;
meta_topic (META_DEBUG_SHAPES,
"Window %s now has a shape\n",
window->desc);
}
else if (!sev->shaped && window->has_shape)
{
window->has_shape = FALSE;
meta_topic (META_DEBUG_SHAPES,
"Window %s no longer has a shape\n",
window->desc);
}
else
{
meta_topic (META_DEBUG_SHAPES,
"Window %s shape changed\n",
window->desc);
}
if (display->compositor)
meta_compositor_window_x11_shape_changed (display->compositor,
window);
}
else if (sev->kind == ShapeInput) else if (sev->kind == ShapeInput)
{ meta_window_update_input_region_x11 (window);
if (sev->shaped && !window->has_input_shape)
{
window->has_input_shape = TRUE;
meta_topic (META_DEBUG_SHAPES,
"Window %s now has an input shape\n",
window->desc);
}
else if (!sev->shaped && window->has_input_shape)
{
window->has_input_shape = FALSE;
meta_topic (META_DEBUG_SHAPES,
"Window %s no longer has an input shape\n",
window->desc);
}
else
{
meta_topic (META_DEBUG_SHAPES,
"Window %s input shape changed\n",
window->desc);
}
if (display->compositor)
meta_compositor_window_x11_shape_changed (display->compositor,
window);
}
} }
else else
{ {

View File

@ -339,11 +339,6 @@ struct _MetaWindow
guint using_net_wm_icon_name : 1; /* vs. plain wm_icon_name */ guint using_net_wm_icon_name : 1; /* vs. plain wm_icon_name */
guint using_net_wm_visible_icon_name : 1; /* tracked so we can clear it */ guint using_net_wm_visible_icon_name : 1; /* tracked so we can clear it */
/* has a bounding shape mask */
guint has_shape : 1;
/* has an input shape mask */
guint has_input_shape : 1;
/* icon props have changed */ /* icon props have changed */
guint need_reread_icon : 1; guint need_reread_icon : 1;
@ -365,9 +360,15 @@ struct _MetaWindow
/* if non-NULL, the bounds of the window frame */ /* if non-NULL, the bounds of the window frame */
cairo_region_t *frame_bounds; cairo_region_t *frame_bounds;
/* if non-NULL, the bounding shape region of the window */
cairo_region_t *shape_region;
/* if non-NULL, the opaque region _NET_WM_OPAQUE_REGION */ /* if non-NULL, the opaque region _NET_WM_OPAQUE_REGION */
cairo_region_t *opaque_region; cairo_region_t *opaque_region;
/* the input shape region for picking */
cairo_region_t *input_region;
/* if TRUE, the we have the new form of sync request counter which /* if TRUE, the we have the new form of sync request counter which
* also handles application frames */ * also handles application frames */
guint extended_sync_request_counter : 1; guint extended_sync_request_counter : 1;
@ -685,7 +686,6 @@ void meta_window_update_icon_now (MetaWindow *window);
void meta_window_update_role (MetaWindow *window); void meta_window_update_role (MetaWindow *window);
void meta_window_update_net_wm_type (MetaWindow *window); void meta_window_update_net_wm_type (MetaWindow *window);
void meta_window_update_opaque_region (MetaWindow *window);
void meta_window_update_for_monitors_changed (MetaWindow *window); void meta_window_update_for_monitors_changed (MetaWindow *window);
void meta_window_update_on_all_workspaces (MetaWindow *window); void meta_window_update_on_all_workspaces (MetaWindow *window);
@ -699,4 +699,16 @@ void meta_window_compute_tile_match (MetaWindow *window);
gboolean meta_window_updates_are_frozen (MetaWindow *window); gboolean meta_window_updates_are_frozen (MetaWindow *window);
void meta_window_set_opaque_region (MetaWindow *window,
cairo_region_t *region);
void meta_window_update_opaque_region_x11 (MetaWindow *window);
void meta_window_set_input_region (MetaWindow *window,
cairo_region_t *region);
void meta_window_update_input_region_x11 (MetaWindow *window);
void meta_window_set_shape_region (MetaWindow *window,
cairo_region_t *region);
void meta_window_update_shape_region_x11 (MetaWindow *window);
#endif #endif

View File

@ -565,7 +565,7 @@ reload_opaque_region (MetaWindow *window,
MetaPropValue *value, MetaPropValue *value,
gboolean initial) gboolean initial)
{ {
meta_window_update_opaque_region (window); meta_window_update_opaque_region_x11 (window);
} }
static void static void

View File

@ -822,8 +822,6 @@ meta_window_new_shared (MetaDisplay *display,
Window xwindow, Window xwindow,
gboolean must_be_viewable, gboolean must_be_viewable,
gulong existing_wm_state, gulong existing_wm_state,
gboolean has_shape,
gboolean has_input_shape,
MetaCompEffect effect, MetaCompEffect effect,
XWindowAttributes *attrs) XWindowAttributes *attrs)
{ {
@ -876,9 +874,6 @@ meta_window_new_shared (MetaDisplay *display,
/* avoid tons of stack updates */ /* avoid tons of stack updates */
meta_stack_freeze (window->screen->stack); meta_stack_freeze (window->screen->stack);
window->has_shape = has_shape;
window->has_input_shape = has_input_shape;
window->rect.x = attrs->x; window->rect.x = attrs->x;
window->rect.y = attrs->y; window->rect.y = attrs->y;
window->rect.width = attrs->width; window->rect.width = attrs->width;
@ -1059,6 +1054,8 @@ meta_window_new_shared (MetaDisplay *display,
} }
meta_display_register_x_window (display, &window->xwindow, window); meta_display_register_x_window (display, &window->xwindow, window);
meta_window_update_shape_region_x11 (window);
meta_window_update_input_region_x11 (window);
} }
/* assign the window to its group, or create a new group if needed /* assign the window to its group, or create a new group if needed
@ -1425,8 +1422,6 @@ meta_window_new_for_wayland (MetaDisplay *display,
None, None,
TRUE, TRUE,
WithdrawnState, WithdrawnState,
FALSE, /* has shape */
FALSE, /* has input shape */
META_COMP_EFFECT_NONE, META_COMP_EFFECT_NONE,
&attrs); &attrs);
@ -1455,8 +1450,6 @@ meta_window_new_with_attrs (MetaDisplay *display,
gulong existing_wm_state; gulong existing_wm_state;
MetaWindow *window; MetaWindow *window;
gulong event_mask; gulong event_mask;
gboolean has_shape = FALSE;
gboolean has_input_shape = FALSE;
meta_verbose ("Attempting to manage 0x%lx\n", xwindow); meta_verbose ("Attempting to manage 0x%lx\n", xwindow);
@ -1576,53 +1569,6 @@ meta_window_new_with_attrs (MetaDisplay *display,
XISelectEvents (display->xdisplay, xwindow, &mask, 1); XISelectEvents (display->xdisplay, xwindow, &mask, 1);
} }
#ifdef HAVE_SHAPE
if (META_DISPLAY_HAS_SHAPE (display))
{
int x_bounding, y_bounding, x_clip, y_clip;
unsigned w_bounding, h_bounding, w_clip, h_clip;
int bounding_shaped, clip_shaped;
XRectangle *input_rectangles;
int n_rects, ordering;
XShapeSelectInput (display->xdisplay, xwindow, ShapeNotifyMask);
XShapeQueryExtents (display->xdisplay, xwindow,
&bounding_shaped, &x_bounding, &y_bounding,
&w_bounding, &h_bounding,
&clip_shaped, &x_clip, &y_clip,
&w_clip, &h_clip);
has_shape = bounding_shaped != FALSE;
/* XXX: The x shape extension doesn't provide a way to only test if an
* input shape has been specified, so we have to query and throw away the
* rectangles. */
meta_error_trap_push (display);
input_rectangles = XShapeGetRectangles (display->xdisplay, xwindow,
ShapeInput, &n_rects, &ordering);
meta_error_trap_pop (display);
if (input_rectangles)
{
if (n_rects > 1 ||
(n_rects == 1 &&
(input_rectangles[0].x != x_bounding ||
input_rectangles[1].y != y_bounding ||
input_rectangles[2].width != w_bounding ||
input_rectangles[3].height != h_bounding)))
{
has_input_shape = TRUE;
}
XFree (input_rectangles);
}
meta_topic (META_DEBUG_SHAPES,
"Window has_shape = %d extents %d,%d %u x %u\n",
has_shape, x_bounding, y_bounding,
w_bounding, h_bounding);
}
#endif
/* Get rid of any borders */ /* Get rid of any borders */
if (attrs->border_width != 0) if (attrs->border_width != 0)
XSetWindowBorderWidth (display->xdisplay, xwindow, 0); XSetWindowBorderWidth (display->xdisplay, xwindow, 0);
@ -1656,8 +1602,6 @@ meta_window_new_with_attrs (MetaDisplay *display,
xwindow, xwindow,
must_be_viewable, must_be_viewable,
existing_wm_state, existing_wm_state,
has_shape,
has_input_shape,
effect, effect,
attrs); attrs);
@ -7810,14 +7754,25 @@ meta_window_update_net_wm_type (MetaWindow *window)
} }
void void
meta_window_update_opaque_region (MetaWindow *window) meta_window_set_opaque_region (MetaWindow *window,
cairo_region_t *region)
{
g_clear_pointer (&window->opaque_region, cairo_region_destroy);
if (region != NULL)
window->opaque_region = cairo_region_reference (region);
if (window->display->compositor)
meta_compositor_window_shape_changed (window->display->compositor, window);
}
void
meta_window_update_opaque_region_x11 (MetaWindow *window)
{ {
cairo_region_t *opaque_region = NULL; cairo_region_t *opaque_region = NULL;
gulong *region = NULL; gulong *region = NULL;
int nitems; int nitems;
g_clear_pointer (&window->opaque_region, cairo_region_destroy);
if (meta_prop_get_cardinal_list (window->display, if (meta_prop_get_cardinal_list (window->display,
window->xwindow, window->xwindow,
window->display->atom__NET_WM_OPAQUE_REGION, window->display->atom__NET_WM_OPAQUE_REGION,
@ -7860,11 +7815,191 @@ meta_window_update_opaque_region (MetaWindow *window)
} }
out: out:
window->opaque_region = opaque_region;
meta_XFree (region); meta_XFree (region);
meta_window_set_opaque_region (window, opaque_region);
cairo_region_destroy (opaque_region);
}
static cairo_region_t *
region_create_from_x_rectangles (const XRectangle *rects,
int n_rects)
{
int i;
cairo_rectangle_int_t *cairo_rects = g_newa (cairo_rectangle_int_t, n_rects);
for (i = 0; i < n_rects; i ++)
{
cairo_rects[i].x = rects[i].x;
cairo_rects[i].y = rects[i].y;
cairo_rects[i].width = rects[i].width;
cairo_rects[i].height = rects[i].height;
}
return cairo_region_create_rectangles (cairo_rects, n_rects);
}
void
meta_window_set_input_region (MetaWindow *window,
cairo_region_t *region)
{
g_clear_pointer (&window->input_region, cairo_region_destroy);
if (region != NULL)
window->input_region = cairo_region_reference (region);
if (window->display->compositor) if (window->display->compositor)
meta_compositor_window_x11_shape_changed (window->display->compositor, window); meta_compositor_window_shape_changed (window->display->compositor, window);
}
void
meta_window_update_input_region_x11 (MetaWindow *window)
{
cairo_region_t *region = NULL;
#ifdef HAVE_SHAPE
if (META_DISPLAY_HAS_SHAPE (window->display))
{
/* Translate the set of XShape rectangles that we
* get from the X server to a cairo_region. */
XRectangle *rects = NULL;
int n_rects, ordering;
int x_bounding, y_bounding, x_clip, y_clip;
unsigned w_bounding, h_bounding, w_clip, h_clip;
int bounding_shaped, clip_shaped;
meta_error_trap_push (window->display);
XShapeQueryExtents (window->display->xdisplay, window->xwindow,
&bounding_shaped, &x_bounding, &y_bounding,
&w_bounding, &h_bounding,
&clip_shaped, &x_clip, &y_clip,
&w_clip, &h_clip);
rects = XShapeGetRectangles (window->display->xdisplay,
window->xwindow,
ShapeInput,
&n_rects,
&ordering);
meta_error_trap_pop (window->display);
/* XXX: The x shape extension doesn't provide a way to only test if an
* input shape has been specified, so we have to query and throw away the
* rectangles. */
if (rects)
{
if (n_rects > 1 ||
(n_rects == 1 &&
(rects[0].x != x_bounding ||
rects[1].y != y_bounding ||
rects[2].width != w_bounding ||
rects[3].height != h_bounding)))
region = region_create_from_x_rectangles (rects, n_rects);
XFree (rects);
}
}
#endif /* HAVE_SHAPE */
if (region != NULL)
{
cairo_rectangle_int_t client_area;
client_area.x = 0;
client_area.y = 0;
client_area.width = window->rect.width;
client_area.height = window->rect.height;
/* The shape we get back from the client may have coordinates
* outside of the frame. The X SHAPE Extension requires that
* the overall shape the client provides never exceeds the
* "bounding rectangle" of the window -- the shape that the
* window would have gotten if it was unshaped. In our case,
* this is simply the client area.
*/
cairo_region_intersect_rectangle (region, &client_area);
}
meta_window_set_input_region (window, region);
cairo_region_destroy (region);
}
void
meta_window_set_shape_region (MetaWindow *window,
cairo_region_t *region)
{
g_clear_pointer (&window->shape_region, cairo_region_destroy);
if (region != NULL)
window->shape_region = cairo_region_reference (region);
if (window->display->compositor)
meta_compositor_window_shape_changed (window->display->compositor, window);
}
void
meta_window_update_shape_region_x11 (MetaWindow *window)
{
cairo_region_t *region = NULL;
#ifdef HAVE_SHAPE
if (META_DISPLAY_HAS_SHAPE (window->display))
{
/* Translate the set of XShape rectangles that we
* get from the X server to a cairo_region. */
XRectangle *rects = NULL;
int n_rects, ordering;
int x_bounding, y_bounding, x_clip, y_clip;
unsigned w_bounding, h_bounding, w_clip, h_clip;
int bounding_shaped, clip_shaped;
meta_error_trap_push (window->display);
XShapeQueryExtents (window->display->xdisplay, window->xwindow,
&bounding_shaped, &x_bounding, &y_bounding,
&w_bounding, &h_bounding,
&clip_shaped, &x_clip, &y_clip,
&w_clip, &h_clip);
if (bounding_shaped)
{
rects = XShapeGetRectangles (window->display->xdisplay,
window->xwindow,
ShapeBounding,
&n_rects,
&ordering);
}
meta_error_trap_pop (window->display);
if (rects)
{
region = region_create_from_x_rectangles (rects, n_rects);
XFree (rects);
}
}
#endif /* HAVE_SHAPE */
if (region != NULL)
{
cairo_rectangle_int_t client_area;
client_area.x = 0;
client_area.y = 0;
client_area.width = window->rect.width;
client_area.height = window->rect.height;
/* The shape we get back from the client may have coordinates
* outside of the frame. The X SHAPE Extension requires that
* the overall shape the client provides never exceeds the
* "bounding rectangle" of the window -- the shape that the
* window would have gotten if it was unshaped. In our case,
* this is simply the client area.
*/
cairo_region_intersect_rectangle (region, &client_area);
}
meta_window_set_shape_region (window, region);
cairo_region_destroy (region);
} }
static void static void

View File

@ -64,8 +64,8 @@ void meta_compositor_manage_screen (MetaCompositor *compositor,
void meta_compositor_unmanage_screen (MetaCompositor *compositor, void meta_compositor_unmanage_screen (MetaCompositor *compositor,
MetaScreen *screen); MetaScreen *screen);
void meta_compositor_window_x11_shape_changed (MetaCompositor *compositor, void meta_compositor_window_shape_changed (MetaCompositor *compositor,
MetaWindow *window); MetaWindow *window);
gboolean meta_compositor_process_event (MetaCompositor *compositor, gboolean meta_compositor_process_event (MetaCompositor *compositor,
XEvent *event, XEvent *event,

View File

@ -324,18 +324,34 @@ meta_wayland_surface_frame (struct wl_client *client,
static void static void
meta_wayland_surface_set_opaque_region (struct wl_client *client, meta_wayland_surface_set_opaque_region (struct wl_client *client,
struct wl_resource *resource, struct wl_resource *surface_resource,
struct wl_resource *region) struct wl_resource *region_resource)
{ {
g_warning ("TODO: support set_opaque_region request"); MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
/* X11 unmanaged window */
if (!surface)
return;
if (surface->window)
meta_window_set_opaque_region (surface->window, cairo_region_copy (region->region));
} }
static void static void
meta_wayland_surface_set_input_region (struct wl_client *client, meta_wayland_surface_set_input_region (struct wl_client *client,
struct wl_resource *resource, struct wl_resource *surface_resource,
struct wl_resource *region) struct wl_resource *region_resource)
{ {
g_warning ("TODO: support set_input_region request"); MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
/* X11 unmanaged window */
if (!surface)
return;
if (surface->window)
meta_window_set_input_region (surface->window, cairo_region_copy (region->region));
} }
static void static void