wayland: Add support for set_opaque_region / set_input_region
https://bugzilla.gnome.org/show_bug.cgi?id=707019
This commit is contained in:
parent
95e2d26d03
commit
2d35e07fae
@ -930,7 +930,7 @@ 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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -64,7 +64,7 @@ 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,
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user