/* When there are multiple monitors with different resolutions, the visible area
 * within the root window may not be rectangular (it may have an L-shape, for
 * example).  In that case, mask out the areas of the root window which would
 * not be visible in the monitors, so that screenshot do not end up with content
 * that the user won't ever see.
 */
static void
mask_monitors (GdkPixbuf *pixbuf, GdkWindow *root_window)
{
  GdkScreen *screen;
  cairo_region_t *region_with_monitors;
  cairo_region_t *invisible_region;
  cairo_rectangle_int_t rect;

  screen = gdk_window_get_screen (root_window);

  region_with_monitors = make_region_with_monitors (screen);

  rect.x = 0;
  rect.y = 0;
  rect.width = gdk_screen_get_width (screen);
  rect.height = gdk_screen_get_height (screen);

  invisible_region = cairo_region_create_rectangle (&rect);
  cairo_region_subtract (invisible_region, region_with_monitors);

  blank_region_in_pixbuf (pixbuf, invisible_region);

  cairo_region_destroy (region_with_monitors);
  cairo_region_destroy (invisible_region);
}
Exemple #2
0
void
meta_tile_preview_show (MetaTilePreview *preview,
                        MetaRectangle   *tile_rect)
{
  GdkWindow *window;
  GdkRectangle old_rect;

  if (gtk_widget_get_visible (preview->preview_window)
      && preview->tile_rect.x == tile_rect->x
      && preview->tile_rect.y == tile_rect->y
      && preview->tile_rect.width == tile_rect->width
      && preview->tile_rect.height == tile_rect->height)
    return; /* nothing to do */

  gtk_widget_show (preview->preview_window);
  window = gtk_widget_get_window (preview->preview_window);
  meta_core_lower_beneath_grab_window (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
                                       GDK_WINDOW_XID (window),
                                       gtk_get_current_event_time ());

  old_rect.x = old_rect.y = 0;
  old_rect.width = preview->tile_rect.width;
  old_rect.height = preview->tile_rect.height;

  gdk_window_invalidate_rect (window, &old_rect, FALSE);

  preview->tile_rect = *tile_rect;

  gdk_window_move_resize (window,
                          preview->tile_rect.x, preview->tile_rect.y,
                          preview->tile_rect.width, preview->tile_rect.height);

  if (!preview->has_alpha)
    {
      cairo_region_t *outer_region, *inner_region;
      GdkRectangle outer_rect, inner_rect;
      GdkRGBA black = { 0.0, 0.0, 0.0, 1.0 };

      gdk_window_set_background_rgba (window, &black);

      outer_rect.x = outer_rect.y = 0;
      outer_rect.width = preview->tile_rect.width;
      outer_rect.height = preview->tile_rect.height;

      inner_rect.x = OUTLINE_WIDTH;
      inner_rect.y = OUTLINE_WIDTH;
      inner_rect.width = outer_rect.width - 2 * OUTLINE_WIDTH;
      inner_rect.height = outer_rect.height - 2 * OUTLINE_WIDTH;

      outer_region = cairo_region_create_rectangle (&outer_rect);
      inner_region = cairo_region_create_rectangle (&inner_rect);

      cairo_region_subtract (outer_region, inner_region);
      cairo_region_destroy (inner_region);

      gdk_window_shape_combine_region (window, outer_region, 0, 0);
      cairo_region_destroy (outer_region);
    }
}
Exemple #3
0
// cairo_public cairo_status_t
// cairo_region_subtract (cairo_region_t *dst, const cairo_region_t *other);
static int l_cairo_region_subtract (lua_State* L)
{
    cairo_region_t *dst = get_cairo_region_t (L, 1);
    const cairo_region_t *other = get_cairo_region_t (L, 2);
    cairo_status_t v = cairo_region_subtract (dst, other);
    lua_pushinteger(L, v);
    return 1;
}
Exemple #4
0
static void
resize(JoyBubble *self, gint width, gint height)
{
    struct Private *priv = GET_PRIVATE(self);
    if (G_LIKELY(priv->surface)) {
        cairo_surface_destroy(priv->surface);
        priv->surface = NULL;
        priv->image = NULL;
    }
    cairo_region_subtract(priv->area, priv->area);
    JOY_BUBBLE_CLASS(joy_gfx3d_window_parent_class)->
    resize(self, width, height);
}
Exemple #5
0
JOY_GNUC_HOT
static void
submit(JoyScreen *self)
{
	struct Private *priv = GET_PRIVATE(self);
	// update cursor
	if (priv->cursor && priv->moved) {
		GFX3D_Cursor_Position_Set(priv->cursor,
				priv->x - priv->x_hot,
				priv->y - priv->y_hot);
	}
	// clear exposed areas of the frame buffer
	cairo_region_intersect(priv->expose, priv->area);
	for (gint i = 0; i < cairo_region_num_rectangles(priv->expose); ++i) {
		cairo_rectangle_int_t rect;
		cairo_region_get_rectangle(priv->expose, i, &rect);
		GFX3D_Display_ClearAlpha2D(priv->display, NULL,
				(gpointer)&rect, 0., 0., 0., 0.);
		g_array_append_val(priv->rects, rect);
	}
	if (priv->rects->len) {
		cairo_region_subtract(priv->expose, priv->expose);
#if !CAIRO_HAS_GFX3D_SURFACE
		GFX3D_Display_Cache_Flush(priv->display);
#endif // !CAIRO_HAS_GFX3D_SURFACE
		GFX3D_NATIVE_Display display =
			GFX3D_Display_Get_NATIVE_Display(priv->display);
		GFX3D_NATIVE_Surface surface =
			GFX3D_Display_FrameBuffer_Get_NATIVE_Surface(
					priv->display);
		// copy windows to the frame buffer
		for (GList *node = g_queue_peek_head_link(priv->windows);
				node; node = node->next) {
			JoyBubble *window = node->data;
			joy_gfx3d_window_submit(window, display, surface,
					priv->area);
		}
		// flip the display
		GFX3D_Display_Show_Partial(priv->display,
				(gpointer)priv->rects->data,
				priv->rects->len, 1);
		g_array_set_size(priv->rects, 0);
	} else {
		if (priv->moved && priv->cursor) {
			GFX3D_Display_Show_Ch_Reload(priv->cursor);
		}
	}
	priv->moved = FALSE;
}
Exemple #6
0
bool wxRegion::DoSubtract( const wxRegion& region )
{
    if (region.m_refData == NULL || m_refData == NULL)
        return false;

    AllocExclusive();

#ifdef __WXGTK3__
    cairo_region_subtract(M_REGIONDATA->m_region, M_REGIONDATA_OF(region)->m_region);
#else
    gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
#endif

    return true;
}
void ChromeClient::scroll(const IntSize& delta, const IntRect& rectToScroll, const IntRect& clipRect)
{
    GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(m_webView));
    if (!window)
        return;

    m_pendingScrollInvalidations = true;

    // We cannot use gdk_window_scroll here because it is only able to
    // scroll the whole window at once, and we often need to scroll
    // portions of the window only (think frames).
    GdkRectangle area = clipRect;
    GdkRectangle moveRect;

    GdkRectangle sourceRect = area;
    sourceRect.x -= delta.width();
    sourceRect.y -= delta.height();

#ifdef GTK_API_VERSION_2
    GdkRegion* invalidRegion = gdk_region_rectangle(&area);

    if (gdk_rectangle_intersect(&area, &sourceRect, &moveRect)) {
        GdkRegion* moveRegion = gdk_region_rectangle(&moveRect);
        gdk_window_move_region(window, moveRegion, delta.width(), delta.height());
        gdk_region_offset(moveRegion, delta.width(), delta.height());
        gdk_region_subtract(invalidRegion, moveRegion);
        gdk_region_destroy(moveRegion);
    }

    gdk_window_invalidate_region(window, invalidRegion, FALSE);
    gdk_region_destroy(invalidRegion);
#else
    cairo_region_t* invalidRegion = cairo_region_create_rectangle(&area);

    if (gdk_rectangle_intersect(&area, &sourceRect, &moveRect)) {
        cairo_region_t* moveRegion = cairo_region_create_rectangle(&moveRect);
        gdk_window_move_region(window, moveRegion, delta.width(), delta.height());
        cairo_region_translate(moveRegion, delta.width(), delta.height());
        cairo_region_subtract(invalidRegion, moveRegion);
        cairo_region_destroy(moveRegion);
    }

    gdk_window_invalidate_region(window, invalidRegion, FALSE);
    cairo_region_destroy(invalidRegion);
#endif
}
Exemple #8
0
/* Drill the window in the area where the ardesia bar is located. */
void 
drill_window_in_bar_area     (GtkWidget *widget)
{
  GtkWidget *bar= get_bar_window ();
  gint x, y, width, height;

  gtk_window_get_position (GTK_WINDOW (bar), &x, &y);
  gtk_window_get_size (GTK_WINDOW (bar), &width, &height);

  const cairo_rectangle_int_t widget_rect = { x+1, y+1, width-1, height-1 };               
  cairo_region_t *widget_reg = cairo_region_create_rectangle (&widget_rect);
                                  
  const cairo_rectangle_int_t ann_rect = { 0, 0, gdk_screen_width (), gdk_screen_height () };                        
  cairo_region_t *ann_reg = cairo_region_create_rectangle (&ann_rect);                              
                                  
  cairo_region_subtract (ann_reg, widget_reg);
                                                                                        
  gtk_widget_input_shape_combine_region (widget, ann_reg);
  cairo_region_destroy (ann_reg);
  cairo_region_destroy (widget_reg);
}
static cairo_region_t *
gimp_canvas_passe_partout_get_extents (GimpCanvasItem *item)
{
  GimpDisplayShell      *shell = gimp_canvas_item_get_shell (item);
  cairo_rectangle_int_t  rectangle;
  cairo_region_t        *inner;
  cairo_region_t        *outer;

  rectangle.x = - shell->offset_x;
  rectangle.y = - shell->offset_y;
  gimp_display_shell_scale_get_image_size (shell,
                                           &rectangle.width,
                                           &rectangle.height);

  outer = cairo_region_create_rectangle (&rectangle);

  inner = GIMP_CANVAS_ITEM_CLASS (parent_class)->get_extents (item);

  cairo_region_subtract (outer, inner);

  return outer;
}
void
_gdk_x11_window_process_expose (GdkWindow    *window,
                                gulong        serial,
                                GdkRectangle *area)
{
  cairo_region_t *invalidate_region = cairo_region_create_rectangle (area);
  GdkX11Display *display_x11 = GDK_X11_DISPLAY (GDK_WINDOW_DISPLAY (window));

  if (display_x11->translate_queue)
    {
      GList *tmp_list = display_x11->translate_queue->head;

      while (tmp_list)
        {
          GdkWindowQueueItem *item = tmp_list->data;
          GList *next = tmp_list->next;

          /* an overflow-safe (serial < item->serial) */
          if (serial - item->serial > (gulong) G_MAXLONG)
            {
              if (item->window == window)
		cairo_region_subtract (invalidate_region, item->antiexpose_area);
            }
          else
            {
              queue_delete_link (display_x11->translate_queue, tmp_list);
              queue_item_free (item);
            }
          tmp_list = next;
        }
    }

  if (!cairo_region_is_empty (invalidate_region))
    _gdk_window_invalidate_for_expose (window, invalidate_region);

  cairo_region_destroy (invalidate_region);
}
static cairo_status_t
_combine_region (cairo_surface_t *surface,
		 const cairo_region_t *region,
		 const cairo_rectangle_int_t *extents)
{
    cairo_region_t clear_region;
    cairo_status_t status;

    _cairo_region_init_rectangle (&clear_region, extents);
    status = cairo_region_subtract (&clear_region, region);
    if (unlikely (status))
	return status;

    if (! cairo_region_is_empty (&clear_region)) {
	cairo_region_translate (&clear_region, -extents->x, -extents->y);
	status = _cairo_surface_fill_region (surface,
					     CAIRO_OPERATOR_CLEAR,
					     CAIRO_COLOR_TRANSPARENT,
					     &clear_region);
    }
    _cairo_region_fini (&clear_region);

    return status;
}
Exemple #12
0
JOY_GNUC_HOT
void
joy_gfx3d_window_submit(JoyBubble *self, GFX3D_NATIVE_Display display,
                        GFX3D_NATIVE_Surface fb, cairo_region_t *area)
{
    g_return_if_fail(JOY_IS_GFX3D_WINDOW(self));
    g_return_if_fail(display);
    g_return_if_fail(fb);
    struct Private *priv = GET_PRIVATE(self);
    if (G_UNLIKELY(!priv->image)) {
        return;
    }
    gint x = joy_bubble_get_x(self);
    gint y = joy_bubble_get_y(self);
    cairo_region_intersect(priv->expose, priv->area);
    cairo_region_intersect(priv->expose, area);
    if (cairo_region_is_empty(priv->expose)) {
        return;
    }
    GFX3D_NATIVE_Surface surface =
        GFX3D_Image_Get_NATIVE_Surface(priv->image);
    gint n = cairo_region_num_rectangles(priv->expose);
    gdouble alpha = joy_bubble_get_alpha(self);
    if (1. == alpha) {
        GFX3D_NATIVE_Blit_Blend_Generic_Parms_t parameters = {
            {
                GFX3D_NATIVE_BLIT_BLEND_CONST_eOne,
                GFX3D_NATIVE_BLIT_BLEND_CONST_eSourceColor,
                0,
                GFX3D_NATIVE_BLIT_BLEND_CONST_eDestinationColor,
                GFX3D_NATIVE_BLIT_BLEND_CONST_eInverseSourceAlpha,
                0,
                GFX3D_NATIVE_BLIT_BLEND_CONST_eZero
            },
            {
                GFX3D_NATIVE_BLIT_BLEND_CONST_eOne,
                GFX3D_NATIVE_BLIT_BLEND_CONST_eSourceAlpha,
                0,
                GFX3D_NATIVE_BLIT_BLEND_CONST_eDestinationAlpha,
                GFX3D_NATIVE_BLIT_BLEND_CONST_eInverseSourceAlpha,
                0,
                GFX3D_NATIVE_BLIT_BLEND_CONST_eZero,
            },
            0,
            0,
            0,
            GFX3D_NATIVE_BLIT_FilterCoeffs_eNone,
            GFX3D_NATIVE_BLIT_FilterCoeffs_eNone,
            0,
            0
        };
        for (gint i = 0; i < n; ++i) {
            cairo_rectangle_int_t rect;
            cairo_region_get_rectangle(priv->expose, i, &rect);
            GFX3D_NATIVE_Rect dst = {
                rect.x + x,
                rect.y + y,
                rect.width,
                rect.height
            };
            GFX3D_NATIVE_Blit_Blend_Generic(display,
                                            fb, &dst,
                                            surface, (gpointer)&rect,
                                            fb, &dst,
                                            &parameters);
        }
    } else {
        GFX3D_NATIVE_Blit_Blend_Generic_Parms_t parameters = {
            {
                GFX3D_NATIVE_BLIT_BLEND_CONST_eConstantAlpha,
                GFX3D_NATIVE_BLIT_BLEND_CONST_eSourceColor,
                0,
                GFX3D_NATIVE_BLIT_BLEND_CONST_eDestinationColor,
                GFX3D_NATIVE_BLIT_BLEND_CONST_eInverseSourceAlpha,
                0,
                GFX3D_NATIVE_BLIT_BLEND_CONST_eZero
            },
            {
                GFX3D_NATIVE_BLIT_BLEND_CONST_eOne,
                GFX3D_NATIVE_BLIT_BLEND_CONST_eSourceAlpha,
                0,
                GFX3D_NATIVE_BLIT_BLEND_CONST_eDestinationAlpha,
                GFX3D_NATIVE_BLIT_BLEND_CONST_eInverseSourceAlpha,
                0,
                GFX3D_NATIVE_BLIT_BLEND_CONST_eZero,
            },
            (gint)(0xff * alpha) << 24,
            0,
            0,
            GFX3D_NATIVE_BLIT_FilterCoeffs_eNone,
            GFX3D_NATIVE_BLIT_FilterCoeffs_eNone,
            0,
            0
        };
        for (gint i = 0; i < n; ++i) {
            cairo_rectangle_int_t rect;
            cairo_region_get_rectangle(priv->expose, i, &rect);
            GFX3D_NATIVE_Rect dst = {
                rect.x + x,
                rect.y + y,
                rect.width,
                rect.height
            };
            GFX3D_NATIVE_Blit_Blend_Generic(display,
                                            fb, &dst,
                                            surface, (gpointer)&rect,
                                            fb, &dst,
                                            &parameters);
        }
    }
    cairo_region_subtract(priv->expose, priv->expose);
}
Exemple #13
0
void
_gtk_pixel_cache_set_position (GtkPixelCache         *cache,
			       cairo_rectangle_int_t *view_rect,
			       cairo_rectangle_int_t *canvas_rect)
{
  cairo_rectangle_int_t r, view_pos;
  cairo_region_t *copy_region;
  int new_surf_x, new_surf_y;
  cairo_t *backing_cr;

  if (cache->surface == NULL)
    return;

  /* Position of view inside canvas */
  view_pos.x = -canvas_rect->x;
  view_pos.y = -canvas_rect->y;
  view_pos.width = view_rect->width;
  view_pos.height = view_rect->height;

  /* Reposition so all is visible */
  if (view_pos.x < cache->surface_x ||
      view_pos.x + view_pos.width >
      cache->surface_x + cache->surface_w ||
      view_pos.y < cache->surface_y ||
      view_pos.y + view_pos.height >
      cache->surface_y + cache->surface_h)
    {
      new_surf_x = cache->surface_x;
      if (view_pos.x < cache->surface_x)
	new_surf_x = MAX (view_pos.x + view_pos.width - cache->surface_w, 0);
      else if (view_pos.x + view_pos.width >
	       cache->surface_x + cache->surface_w)
	new_surf_x = MIN (view_pos.x, canvas_rect->width - cache->surface_w);

      new_surf_y = cache->surface_y;
      if (view_pos.y < cache->surface_y)
	new_surf_y = MAX (view_pos.y + view_pos.height - cache->surface_h, 0);
      else if (view_pos.y + view_pos.height >
	       cache->surface_y + cache->surface_h)
	new_surf_y = MIN (view_pos.y, canvas_rect->height - cache->surface_h);

      r.x = 0;
      r.y = 0;
      r.width = cache->surface_w;
      r.height = cache->surface_h;
      copy_region = cairo_region_create_rectangle (&r);

      if (cache->surface_dirty)
	{
	  cairo_region_subtract (copy_region, cache->surface_dirty);
	  cairo_region_destroy (cache->surface_dirty);
	  cache->surface_dirty = NULL;
	}

      cairo_region_translate (copy_region,
			      cache->surface_x - new_surf_x,
			      cache->surface_y - new_surf_y);
      cairo_region_intersect_rectangle (copy_region, &r);

      backing_cr = cairo_create (cache->surface);
      gdk_cairo_region (backing_cr, copy_region);
      cairo_set_operator (backing_cr, CAIRO_OPERATOR_SOURCE);
      cairo_clip (backing_cr);
      cairo_push_group (backing_cr);
      cairo_set_source_surface (backing_cr, cache->surface,
				cache->surface_x - new_surf_x,
				cache->surface_y - new_surf_y);
      cairo_paint (backing_cr);
      cairo_pop_group_to_source (backing_cr);
      cairo_paint (backing_cr);
      cairo_destroy (backing_cr);

      cache->surface_x = new_surf_x;
      cache->surface_y = new_surf_y;

      cairo_region_xor_rectangle (copy_region, &r);
      cache->surface_dirty = copy_region;
    }
}
Exemple #14
0
/**
 * gdk_cairo_draw_from_gl:
 * @cr: a cairo context
 * @window: The window we're rendering for (not necessarily into)
 * @source: The GL ID of the source buffer
 * @source_type: The type of the @source
 * @buffer_scale: The scale-factor that the @source buffer is allocated for
 * @x: The source x position in @source to start copying from in GL coordinates
 * @y: The source y position in @source to start copying from in GL coordinates
 * @width: The width of the region to draw
 * @height: The height of the region to draw
 *
 * This is the main way to draw GL content in GTK+. It takes a render buffer ID
 * (@source_type == #GL_RENDERBUFFER) or a texture id (@source_type == #GL_TEXTURE)
 * and draws it onto @cr with an OVER operation, respecting the current clip.
 * The top left corner of the rectangle specified by @x, @y, @width and @height
 * will be drawn at the current (0,0) position of the cairo_t.
 *
 * This will work for *all* cairo_t, as long as @window is realized, but the
 * fallback implementation that reads back the pixels from the buffer may be
 * used in the general case. In the case of direct drawing to a window with
 * no special effects applied to @cr it will however use a more efficient
 * approach.
 *
 * For #GL_RENDERBUFFER the code will always fall back to software for buffers
 * with alpha components, so make sure you use #GL_TEXTURE if using alpha.
 *
 * Calling this may change the current GL context.
 *
 * Since: 3.16
 */
void
gdk_cairo_draw_from_gl (cairo_t              *cr,
                        GdkWindow            *window,
                        int                   source,
                        int                   source_type,
                        int                   buffer_scale,
                        int                   x,
                        int                   y,
                        int                   width,
                        int                   height)
{
    GdkGLContext *paint_context;
    cairo_surface_t *image;
    cairo_matrix_t matrix;
    int dx, dy, window_scale;
    gboolean trivial_transform;
    cairo_surface_t *group_target;
    GdkWindow *direct_window, *impl_window;
    guint framebuffer;
    int alpha_size = 0;
    cairo_region_t *clip_region;
    GdkGLContextPaintData *paint_data;

    impl_window = window->impl_window;

    window_scale = gdk_window_get_scale_factor (impl_window);

    paint_context = gdk_window_get_paint_gl_context (window, NULL);
    if (paint_context == NULL)
    {
        g_warning ("gdk_cairo_draw_gl_render_buffer failed - no paint context");
        return;
    }

    clip_region = gdk_cairo_region_from_clip (cr);

    gdk_gl_context_make_current (paint_context);
    paint_data = gdk_gl_context_get_paint_data (paint_context);

    if (paint_data->tmp_framebuffer == 0)
        glGenFramebuffersEXT (1, &paint_data->tmp_framebuffer);

    if (source_type == GL_RENDERBUFFER)
    {
        glBindRenderbuffer (GL_RENDERBUFFER, source);
        glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_ALPHA_SIZE,  &alpha_size);
    }
    else if (source_type == GL_TEXTURE)
    {
        glBindTexture (GL_TEXTURE_2D, source);

        glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_ALPHA_SIZE,  &alpha_size);
    }
    else
    {
        g_warning ("Unsupported gl source type %d\n", source_type);
        return;
    }

    group_target = cairo_get_group_target (cr);
    direct_window = cairo_surface_get_user_data (group_target, &direct_key);

    cairo_get_matrix (cr, &matrix);

    dx = matrix.x0;
    dy = matrix.y0;

    /* Trivial == integer-only translation */
    trivial_transform =
        (double)dx == matrix.x0 && (double)dy == matrix.y0 &&
        matrix.xx == 1.0 && matrix.xy == 0.0 &&
        matrix.yx == 0.0 && matrix.yy == 1.0;

    /* For direct paint of non-alpha renderbuffer, we can
       just do a bitblit */
    if ((_gdk_gl_flags & GDK_GL_SOFTWARE_DRAW_GL) == 0 &&
            source_type == GL_RENDERBUFFER &&
            alpha_size == 0 &&
            direct_window != NULL &&
            direct_window->current_paint.use_gl &&
            trivial_transform &&
            clip_region != NULL)
    {
        int unscaled_window_height;
        int i;

        /* Create a framebuffer with the source renderbuffer and
           make it the current target for reads */
        framebuffer = paint_data->tmp_framebuffer;
        glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, framebuffer);
        glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
                                      GL_RENDERBUFFER_EXT, source);
        glBindFramebufferEXT (GL_DRAW_FRAMEBUFFER_EXT, 0);

        /* Translate to impl coords */
        cairo_region_translate (clip_region, dx, dy);

        glEnable (GL_SCISSOR_TEST);

        gdk_window_get_unscaled_size (impl_window, NULL, &unscaled_window_height);
        glDrawBuffer (GL_BACK);

#define FLIP_Y(_y) (unscaled_window_height - (_y))

        for (i = 0; i < cairo_region_num_rectangles (clip_region); i++)
        {
            cairo_rectangle_int_t clip_rect, dest;

            cairo_region_get_rectangle (clip_region, i, &clip_rect);
            clip_rect.x *= window_scale;
            clip_rect.y *= window_scale;
            clip_rect.width *= window_scale;
            clip_rect.height *= window_scale;

            glScissor (clip_rect.x, FLIP_Y (clip_rect.y + clip_rect.height),
                       clip_rect.width, clip_rect.height);

            dest.x = dx * window_scale;
            dest.y = dy * window_scale;
            dest.width = width * window_scale / buffer_scale;
            dest.height = height * window_scale / buffer_scale;

            if (gdk_rectangle_intersect (&clip_rect, &dest, &dest))
            {
                int clipped_src_x = x + (dest.x - dx * window_scale);
                int clipped_src_y = y + (height - dest.height - (dest.y - dy * window_scale));
                glBlitFramebufferEXT(clipped_src_x, clipped_src_y,
                                     (clipped_src_x + dest.width), (clipped_src_y + dest.height),
                                     dest.x, FLIP_Y(dest.y + dest.height),
                                     dest.x + dest.width, FLIP_Y(dest.y),
                                     GL_COLOR_BUFFER_BIT, GL_NEAREST);
                if (impl_window->current_paint.flushed_region)
                {
                    cairo_rectangle_int_t flushed_rect;

                    flushed_rect.x = dest.x / window_scale;
                    flushed_rect.y = dest.y / window_scale;
                    flushed_rect.width = (dest.x + dest.width + window_scale - 1) / window_scale - flushed_rect.x;
                    flushed_rect.height = (dest.y + dest.height + window_scale - 1) / window_scale - flushed_rect.y;

                    cairo_region_union_rectangle (impl_window->current_paint.flushed_region,
                                                  &flushed_rect);
                    cairo_region_subtract_rectangle (impl_window->current_paint.need_blend_region,
                                                     &flushed_rect);
                }
            }
        }

        glDisable (GL_SCISSOR_TEST);

        glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);

#undef FLIP_Y

    }
    /* For direct paint of alpha or non-alpha textures we can use texturing */
    else if ((_gdk_gl_flags & GDK_GL_SOFTWARE_DRAW_GL) == 0 &&
             source_type == GL_TEXTURE &&
             direct_window != NULL &&
             direct_window->current_paint.use_gl &&
             trivial_transform &&
             clip_region != NULL)
    {
        int unscaled_window_height;
        GLint texture_width;
        GLint texture_height;
        int i, n_rects, n_quads;
        GdkTexturedQuad *quads;
        cairo_rectangle_int_t clip_rect;

        /* Translate to impl coords */
        cairo_region_translate (clip_region, dx, dy);

        if (alpha_size != 0)
        {
            cairo_region_t *opaque_region, *blend_region;

            opaque_region = cairo_region_copy (clip_region);
            cairo_region_subtract (opaque_region, impl_window->current_paint.flushed_region);
            cairo_region_subtract (opaque_region, impl_window->current_paint.need_blend_region);

            if (!cairo_region_is_empty (opaque_region))
                gdk_gl_texture_from_surface (impl_window->current_paint.surface,
                                             opaque_region);

            blend_region = cairo_region_copy (clip_region);
            cairo_region_intersect (blend_region, impl_window->current_paint.need_blend_region);

            glEnable (GL_BLEND);
            if (!cairo_region_is_empty (blend_region))
                gdk_gl_texture_from_surface (impl_window->current_paint.surface,
                                             blend_region);

            cairo_region_destroy (opaque_region);
            cairo_region_destroy (blend_region);
        }

        glBindTexture (GL_TEXTURE_2D, source);

        glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,  &texture_width);
        glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT,  &texture_height);

        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glEnable (GL_SCISSOR_TEST);

        gdk_window_get_unscaled_size (impl_window, NULL, &unscaled_window_height);

#define FLIP_Y(_y) (unscaled_window_height - (_y))

        cairo_region_get_extents (clip_region, &clip_rect);

        glScissor (clip_rect.x * window_scale, FLIP_Y ((clip_rect.y + clip_rect.height) * window_scale),
                   clip_rect.width * window_scale, clip_rect.height * window_scale);

        n_quads = 0;
        n_rects = cairo_region_num_rectangles (clip_region);
        quads = g_new (GdkTexturedQuad, n_rects);
        for (i = 0; i < n_rects; i++)
        {
            cairo_rectangle_int_t dest;

            cairo_region_get_rectangle (clip_region, i, &clip_rect);

            clip_rect.x *= window_scale;
            clip_rect.y *= window_scale;
            clip_rect.width *= window_scale;
            clip_rect.height *= window_scale;

            dest.x = dx * window_scale;
            dest.y = dy * window_scale;
            dest.width = width * window_scale / buffer_scale;
            dest.height = height * window_scale / buffer_scale;

            if (gdk_rectangle_intersect (&clip_rect, &dest, &dest))
            {
                int clipped_src_x = x + (dest.x - dx * window_scale);
                int clipped_src_y = y + (height - dest.height - (dest.y - dy * window_scale));
                GdkTexturedQuad quad = {
                    dest.x, FLIP_Y(dest.y),
                    dest.x + dest.width, FLIP_Y(dest.y + dest.height),
                    clipped_src_x / (float)texture_width, (clipped_src_y + dest.height) / (float)texture_height,
                    (clipped_src_x + dest.width) / (float)texture_width, clipped_src_y / (float)texture_height,
                };

                quads[n_quads++] = quad;

                if (impl_window->current_paint.flushed_region)
                {
                    cairo_rectangle_int_t flushed_rect;

                    flushed_rect.x = dest.x / window_scale;
                    flushed_rect.y = dest.y / window_scale;
                    flushed_rect.width = (dest.x + dest.width + window_scale - 1) / window_scale - flushed_rect.x;
                    flushed_rect.height = (dest.y + dest.height + window_scale - 1) / window_scale - flushed_rect.y;

                    cairo_region_union_rectangle (impl_window->current_paint.flushed_region,
                                                  &flushed_rect);
                    cairo_region_subtract_rectangle (impl_window->current_paint.need_blend_region,
                                                     &flushed_rect);
                }
            }
        }

        if (n_quads > 0)
            gdk_gl_texture_quads (paint_context, GL_TEXTURE_2D, n_quads, quads);

        g_free (quads);

        if (alpha_size != 0)
            glDisable (GL_BLEND);

#undef FLIP_Y

    }
    else
    {
        /* Software fallback */

        /* TODO: avoid reading back non-required data due to dest clip */
        image = cairo_surface_create_similar_image (cairo_get_target (cr),
                (alpha_size == 0) ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32,
                width, height);

        cairo_surface_set_device_scale (image, buffer_scale, buffer_scale);

        framebuffer = paint_data->tmp_framebuffer;
        glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, framebuffer);

        if (source_type == GL_RENDERBUFFER)
        {
            /* Create a framebuffer with the source renderbuffer and
               make it the current target for reads */
            glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
                                          GL_RENDERBUFFER_EXT, source);
        }
        else
        {
            glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
                                       GL_TEXTURE_2D, source, 0);
        }

        glPixelStorei (GL_PACK_ALIGNMENT, 4);
        glPixelStorei (GL_PACK_ROW_LENGTH, cairo_image_surface_get_stride (image) / 4);

        glReadPixels (x, y, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
                      cairo_image_surface_get_data (image));

        glPixelStorei (GL_PACK_ROW_LENGTH, 0);

        glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);

        cairo_surface_mark_dirty (image);

        /* Invert due to opengl having different origin */
        cairo_scale (cr, 1, -1);
        cairo_translate (cr, 0, -height / buffer_scale);

        cairo_set_source_surface (cr, image, 0, 0);
        cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
        cairo_paint (cr);

        cairo_surface_destroy (image);
    }

    if (clip_region)
        cairo_region_destroy (clip_region);

}
void FloatingWindow::display(bool startup)
// Does the bookkeeping necessary for displaying the floating box.
// startup: whether the box is started at program startup.
{
  // Settings.
  extern Settings *settings;

  // The parameters of all the windows.
  WindowData window_parameters(false);

  // Clear the new window's position.
  my_gdk_rectangle.x = 0;
  my_gdk_rectangle.y = 0;
  my_gdk_rectangle.width = 0;
  my_gdk_rectangle.height = 0;

  // At program startup extract the position and size of the window from the general configuration.
  // It does not matter whether the space for the window is already taken up by another window,
  // because the user wishes to use the coordinates that he has set for this window.
  for (unsigned int i = 0; i < window_parameters.widths.size(); i++) {
    if ((window_parameters.ids[i] == window_id) && (window_parameters.titles[i] == title) && startup) {
      my_gdk_rectangle.x = window_parameters.x_positions[i];
      my_gdk_rectangle.y = window_parameters.y_positions[i];
      my_gdk_rectangle.width = window_parameters.widths[i];
      my_gdk_rectangle.height = window_parameters.heights[i];
    }
  }

  // Reject zero width and zero height values on startup.
  if ((my_gdk_rectangle.width == 0) || (my_gdk_rectangle.height == 0)) {
    startup = false;
  }

  // When a new window needs to be allocated, there are a few steps to be taken.
  if (!startup) {

    // Step 1: The area rectangle where the window should fit in is defined. 
#if GTK_CHECK_VERSION(3,0,0)
    GdkRectangle area_rectangle;
#else
    cairo_rectangle_int_t area_rectangle;
#endif
    area_rectangle.x = 0;
    area_rectangle.y = 0;
    area_rectangle.width = 0;
    area_rectangle.height = 0;
    {
      guint width, height;
      gtk_layout_get_size (GTK_LAYOUT (layout), &width, &height);
      area_rectangle.width = width;
      area_rectangle.height = height;
    }

    // Step 2: An available region is made of that whole area.
    cairo_region_t *available_region = cairo_region_create_rectangle(&area_rectangle);

    // Step 3: The regions of each of the open windows is substracted from the available region.
    for (unsigned int i = 0; i < settings->session.open_floating_windows.size(); i++) {
      FloatingWindow * floating_window = (FloatingWindow *) settings->session.open_floating_windows[i];
      GdkRectangle rectangle = floating_window->rectangle_get();
#if GTK_CHECK_VERSION(3,0,0)
      cairo_region_t *region = cairo_region_create_rectangle(&rectangle);
#else
      cairo_rectangle_int_t cairo_rectangle = {
              rectangle.x, rectangle.y,
              rectangle.width, rectangle.height
      };
      cairo_region_t *region = cairo_region_create_rectangle(&cairo_rectangle);
#endif
      cairo_region_subtract(available_region, region);
      cairo_region_destroy(region);
    }

    // Step 4: The rectangles that the area region consists of are requested,
    // and the biggest suitable rectangle is chosen for the window.
    // A rectangle is considered suitable if it has at least 10% of the width, and 10% of the height of the area rectangle.
    gint rectangle_count = cairo_region_num_rectangles(available_region);
    for (int i = 0; i < rectangle_count; ++i) {
#if GTK_CHECK_VERSION(3,0,0)
      GdkRectangle rectangle;
#else
      cairo_rectangle_int_t rectangle;
#endif
      cairo_region_get_rectangle(available_region, i, &rectangle);
      if (rectangle.width >= (area_rectangle.width / 10)) {
        if (rectangle.height >= (area_rectangle.height / 10)) {
          if ((rectangle.width * rectangle.height) > (my_gdk_rectangle.width * my_gdk_rectangle.height)) {
#if GTK_CHECK_VERSION(3,0,0)
            my_gdk_rectangle = rectangle;
#else
            my_gdk_rectangle.x = rectangle.x;
            my_gdk_rectangle.y = rectangle.y;
            my_gdk_rectangle.width = rectangle.width;
            my_gdk_rectangle.height = rectangle.height;
#endif
          }
        }
      }
    }

    // Step 5: The available region is destroyed.
    cairo_region_destroy(available_region);

    // Step 6: If no area big enough is found, then the window that takes most space in the area is chosen, 
    // the longest side is halved, and the new window is put in that freed area.
    if ((my_gdk_rectangle.width == 0) || (my_gdk_rectangle.height == 0)) {
      FloatingWindow * resize_window_pointer = NULL;
      int largest_size = 0;
      for (unsigned int i = 0; i < settings->session.open_floating_windows.size(); i++) {
        FloatingWindow *floating_window = (FloatingWindow *) settings->session.open_floating_windows[i];
        GdkRectangle rectangle = floating_window->rectangle_get ();
        int size = rectangle.width * rectangle.height;
        if (size > largest_size) {
          resize_window_pointer = floating_window;
          largest_size = size;
        }
      }
      if (resize_window_pointer) {
        GdkRectangle resize_window_rectangle = resize_window_pointer->rectangle_get();
        my_gdk_rectangle = resize_window_pointer->rectangle_get();
        if (resize_window_rectangle.width > resize_window_rectangle.height) {
          resize_window_rectangle.width /= 2;
          my_gdk_rectangle.width /= 2;
          my_gdk_rectangle.x += resize_window_rectangle.width;
        } else {
          resize_window_rectangle.height /= 2;
          my_gdk_rectangle.height /= 2;
          my_gdk_rectangle.y += resize_window_rectangle.height;
        }
        resize_window_pointer->rectangle_set (resize_window_rectangle);
      }
    }
  }
  // Add the window to the layout and set its position and size.
  gtk_layout_put (GTK_LAYOUT (layout), vbox_window, my_gdk_rectangle.x, my_gdk_rectangle.y);
  rectangle_set (my_gdk_rectangle);
  // Store a pointer to this window in the Session.
  settings->session.open_floating_windows.push_back(gpointer (this));
}
Exemple #16
0
static void
meta_window_group_paint (ClutterActor *actor)
{
  cairo_region_t *visible_region;
  cairo_region_t *unredirected_window_region = NULL;
  ClutterActor *stage;
  cairo_rectangle_int_t visible_rect, unredirected_rect;
  GList *children, *l;

  MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
  MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen);
  if (info->unredirected_window != NULL)
    {
      meta_window_actor_get_shape_bounds (META_WINDOW_ACTOR (info->unredirected_window), &unredirected_rect);
      unredirected_window_region = cairo_region_create_rectangle (&unredirected_rect);
    }

  /* We walk the list from top to bottom (opposite of painting order),
   * and subtract the opaque area of each window out of the visible
   * region that we pass to the windows below.
   */
  children = clutter_container_get_children (CLUTTER_CONTAINER (actor));
  children = g_list_reverse (children);

  /* Get the clipped redraw bounds from Clutter so that we can avoid
   * painting shadows on windows that don't need to be painted in this
   * frame. In the case of a multihead setup with mismatched monitor
   * sizes, we could intersect this with an accurate union of the
   * monitors to avoid painting shadows that are visible only in the
   * holes. */
  stage = clutter_actor_get_stage (actor);
  clutter_stage_get_redraw_clip_bounds (CLUTTER_STAGE (stage),
                                        &visible_rect);

  visible_region = cairo_region_create_rectangle (&visible_rect);

  if (unredirected_window_region)
    cairo_region_subtract (visible_region, unredirected_window_region);

  for (l = children; l; l = l->next)
    {
      if (!CLUTTER_ACTOR_IS_VISIBLE (l->data))
        continue;

      /* If an actor has effects applied, then that can change the area
       * it paints and the opacity, so we no longer can figure out what
       * portion of the actor is obscured and what portion of the screen
       * it obscures, so we skip the actor.
       *
       * This has a secondary beneficial effect: if a ClutterOffscreenEffect
       * is applied to an actor, then our clipped redraws interfere with the
       * caching of the FBO - even if we only need to draw a small portion
       * of the window right now, ClutterOffscreenEffect may use other portions
       * of the FBO later. So, skipping actors with effects applied also
       * prevents these bugs.
       *
       * Theoretically, we should check clutter_actor_get_offscreen_redirect()
       * as well for the same reason, but omitted for simplicity in the
       * hopes that no-one will do that.
       */
      if (clutter_actor_has_effects (l->data))
        continue;

      if (META_IS_WINDOW_ACTOR (l->data))
        {
          MetaWindowActor *window_actor = l->data;
          int x, y;

          if (!actor_is_untransformed (CLUTTER_ACTOR (window_actor), &x, &y))
            continue;

          /* Temporarily move to the coordinate system of the actor */
          cairo_region_translate (visible_region, - x, - y);

          meta_window_actor_set_visible_region (window_actor, visible_region);

          if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
            {
              cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
              if (obscured_region)
                cairo_region_subtract (visible_region, obscured_region);
            }

          meta_window_actor_set_visible_region_beneath (window_actor, visible_region);
          cairo_region_translate (visible_region, x, y);
        }
      else if (META_IS_BACKGROUND_ACTOR (l->data))
        {
          MetaBackgroundActor *background_actor = l->data;
          meta_background_actor_set_visible_region (background_actor, visible_region);
        }
    }

  cairo_region_destroy (visible_region);

  if (unredirected_window_region)
    cairo_region_destroy (unredirected_window_region);

  CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);

  /* Now that we are done painting, unset the visible regions (they will
   * mess up painting clones of our actors)
   */
  for (l = children; l; l = l->next)
    {
      if (META_IS_WINDOW_ACTOR (l->data))
        {
          MetaWindowActor *window_actor = l->data;
          window_actor = l->data;
          meta_window_actor_reset_visible_regions (window_actor);
        }
      else if (META_IS_BACKGROUND_ACTOR (l->data))
        {
          MetaBackgroundActor *background_actor = l->data;
          meta_background_actor_set_visible_region (background_actor, NULL);
        }
    }

  g_list_free (children);
}
Exemple #17
0
void
Region::Subtract (Region *region)
{
	status = cairo_region_subtract (cairo_region, region->cairo_region);
}
Exemple #18
0
static void
meta_window_group_paint (ClutterActor *actor)
{
  cairo_region_t *visible_region;
  ClutterActor *stage;
  cairo_rectangle_int_t visible_rect;
  GList *children, *l;
  int paint_x_origin, paint_y_origin;
  int actor_x_origin, actor_y_origin;
  int paint_x_offset, paint_y_offset;

  MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
  MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen);

  /* Normally we expect an actor to be drawn at it's position on the screen.
   * However, if we're inside the paint of a ClutterClone, that won't be the
   * case and we need to compensate. We look at the position of the window
   * group under the current model-view matrix and the position of the actor.
   * If they are both simply integer translations, then we can compensate
   * easily, otherwise we give up.
   *
   * Possible cleanup: work entirely in paint space - we can compute the
   * combination of the model-view matrix with the local matrix for each child
   * actor and get a total transformation for that actor for how we are
   * painting currently, and never worry about how actors are positioned
   * on the stage.
   */
  if (!painting_untransformed (window_group, &paint_x_origin, &paint_y_origin) ||
      !meta_actor_is_untransformed (actor, &actor_x_origin, &actor_y_origin))
    {
      CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);
      return;
    }

  paint_x_offset = paint_x_origin - actor_x_origin;
  paint_y_offset = paint_y_origin - actor_y_origin;

  /* We walk the list from top to bottom (opposite of painting order),
   * and subtract the opaque area of each window out of the visible
   * region that we pass to the windows below.
   */
  children = clutter_actor_get_children (actor);
  children = g_list_reverse (children);

  /* Get the clipped redraw bounds from Clutter so that we can avoid
   * painting shadows on windows that don't need to be painted in this
   * frame. In the case of a multihead setup with mismatched monitor
   * sizes, we could intersect this with an accurate union of the
   * monitors to avoid painting shadows that are visible only in the
   * holes. */
  stage = clutter_actor_get_stage (actor);
  clutter_stage_get_redraw_clip_bounds (CLUTTER_STAGE (stage),
                                        &visible_rect);

  visible_region = cairo_region_create_rectangle (&visible_rect);

  if (info->unredirected_window != NULL)
    {
      cairo_rectangle_int_t unredirected_rect;
      MetaWindow *window = meta_window_actor_get_meta_window (info->unredirected_window);

      meta_window_get_outer_rect (window, (MetaRectangle *)&unredirected_rect);
      cairo_region_subtract_rectangle (visible_region, &unredirected_rect);
    }

  for (l = children; l; l = l->next)
    {
      if (!CLUTTER_ACTOR_IS_VISIBLE (l->data))
        continue;

      if (l->data == info->unredirected_window)
        continue;

      /* If an actor has effects applied, then that can change the area
       * it paints and the opacity, so we no longer can figure out what
       * portion of the actor is obscured and what portion of the screen
       * it obscures, so we skip the actor.
       *
       * This has a secondary beneficial effect: if a ClutterOffscreenEffect
       * is applied to an actor, then our clipped redraws interfere with the
       * caching of the FBO - even if we only need to draw a small portion
       * of the window right now, ClutterOffscreenEffect may use other portions
       * of the FBO later. So, skipping actors with effects applied also
       * prevents these bugs.
       *
       * Theoretically, we should check clutter_actor_get_offscreen_redirect()
       * as well for the same reason, but omitted for simplicity in the
       * hopes that no-one will do that.
       */
      if (clutter_actor_has_effects (l->data))
        continue;

      if (META_IS_WINDOW_ACTOR (l->data))
        {
          MetaWindowActor *window_actor = l->data;
          int x, y;

          if (!meta_actor_is_untransformed (CLUTTER_ACTOR (window_actor), &x, &y))
            continue;

          x += paint_x_offset;
          y += paint_y_offset;

          /* Temporarily move to the coordinate system of the actor */
          cairo_region_translate (visible_region, - x, - y);

          meta_window_actor_set_visible_region (window_actor, visible_region);

          if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
            {
              cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
              if (obscured_region)
                cairo_region_subtract (visible_region, obscured_region);
            }

          meta_window_actor_set_visible_region_beneath (window_actor, visible_region);
          cairo_region_translate (visible_region, x, y);
        }
      else if (META_IS_BACKGROUND_ACTOR (l->data) ||
               META_IS_BACKGROUND_GROUP (l->data))
        {
          ClutterActor *background_actor = l->data;
          int x, y;

          if (!meta_actor_is_untransformed (CLUTTER_ACTOR (background_actor), &x, &y))
            continue;

          x += paint_x_offset;
          y += paint_y_offset;

          cairo_region_translate (visible_region, - x, - y);

          if (META_IS_BACKGROUND_GROUP (background_actor))
            meta_background_group_set_visible_region (META_BACKGROUND_GROUP (background_actor), visible_region);
          else
            meta_background_actor_set_visible_region (META_BACKGROUND_ACTOR (background_actor), visible_region);
          cairo_region_translate (visible_region, x, y);
        }
    }

  cairo_region_destroy (visible_region);

  CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);

  /* Now that we are done painting, unset the visible regions (they will
   * mess up painting clones of our actors)
   */
  for (l = children; l; l = l->next)
    {
      if (META_IS_WINDOW_ACTOR (l->data))
        {
          MetaWindowActor *window_actor = l->data;
          meta_window_actor_reset_visible_regions (window_actor);
        }
      else if (META_IS_BACKGROUND_ACTOR (l->data))
        {
          MetaBackgroundActor *background_actor = l->data;
          meta_background_actor_set_visible_region (background_actor, NULL);
        }
    }

  g_list_free (children);
}
Exemple #19
0
static void
meta_window_group_cull_out (MetaWindowGroup *group,
                            ClutterActor    *unredirected_window,
                            gboolean         has_unredirected_window,
                            cairo_region_t  *unobscured_region,
                            cairo_region_t  *clip_region)
{
  ClutterActor *actor = CLUTTER_ACTOR (group);
  ClutterActor *child;
  ClutterActorIter iter;

  /* We walk the list from top to bottom (opposite of painting order),
   * and subtract the opaque area of each window out of the visible
   * region that we pass to the windows below.
   */
  clutter_actor_iter_init (&iter, actor);
  while (clutter_actor_iter_prev (&iter, &child))
    {
      if (!CLUTTER_ACTOR_IS_VISIBLE (child))
        continue;

      if (has_unredirected_window && child == unredirected_window)
        continue;

      /* If an actor has effects applied, then that can change the area
       * it paints and the opacity, so we no longer can figure out what
       * portion of the actor is obscured and what portion of the screen
       * it obscures, so we skip the actor.
       *
       * This has a secondary beneficial effect: if a ClutterOffscreenEffect
       * is applied to an actor, then our clipped redraws interfere with the
       * caching of the FBO - even if we only need to draw a small portion
       * of the window right now, ClutterOffscreenEffect may use other portions
       * of the FBO later. So, skipping actors with effects applied also
       * prevents these bugs.
       *
       * Theoretically, we should check clutter_actor_get_offscreen_redirect()
       * as well for the same reason, but omitted for simplicity in the
       * hopes that no-one will do that.
       */
      if (clutter_actor_has_effects (child))
        continue;

      if (META_IS_WINDOW_ACTOR (child))
        {
          MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
          int x, y;

          if (!meta_actor_is_untransformed (CLUTTER_ACTOR (window_actor), &x, &y))
            continue;

          /* Temporarily move to the coordinate system of the actor */
          cairo_region_translate (unobscured_region, - x, - y);
          cairo_region_translate (clip_region, - x, - y);

          meta_window_actor_set_unobscured_region (window_actor, unobscured_region);
          meta_window_actor_set_visible_region (window_actor, clip_region);

          if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
            {
              cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
              if (obscured_region)
                {
                  cairo_region_subtract (unobscured_region, obscured_region);
                  cairo_region_subtract (clip_region, obscured_region);
                }
            }

          meta_window_actor_set_visible_region_beneath (window_actor, clip_region);

          cairo_region_translate (unobscured_region, x, y);
          cairo_region_translate (clip_region, x, y);
        }
      else if (META_IS_BACKGROUND_ACTOR (child))
        {
          int x, y;

          if (!meta_actor_is_untransformed (child, &x, &y))
            continue;

          cairo_region_translate (clip_region, - x, - y);

          meta_background_actor_set_visible_region (META_BACKGROUND_ACTOR (child), clip_region);

          cairo_region_translate (clip_region, x, y);
        }
    }
}
/* Warning: This call modifies the coordinates of traps */
static cairo_status_t
_clip_and_composite_trapezoids (const cairo_pattern_t *src,
				cairo_operator_t op,
				cairo_surface_t *dst,
				cairo_traps_t *traps,
				cairo_clip_t *clip,
				cairo_antialias_t antialias)
{
    cairo_status_t status;
    cairo_region_t *trap_region = NULL;
    cairo_region_t *clear_region = NULL;
    cairo_rectangle_int_t extents;
    cairo_composite_traps_info_t traps_info;

    if (_cairo_operator_bounded_by_mask (op) && traps->num_traps == 0)
        return CAIRO_STATUS_SUCCESS;

    status = _cairo_surface_get_extents (dst, &extents);
    if (unlikely (status))
        return status;

    status = _cairo_traps_extract_region (traps, &trap_region);
    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
	return status;

    if (_cairo_operator_bounded_by_mask (op)) {
        cairo_rectangle_int_t trap_extents;

        if (trap_region) {
            status = _cairo_clip_intersect_to_region (clip, trap_region);
            if (unlikely (status))
                goto out;

            cairo_region_get_extents (trap_region, &trap_extents);
        } else {
            cairo_box_t trap_box;
            _cairo_traps_extents (traps, &trap_box);
            _cairo_box_round_to_rectangle (&trap_box, &trap_extents);
        }

        if (! _cairo_rectangle_intersect (&extents, &trap_extents)) {
	    status = CAIRO_STATUS_SUCCESS;
	    goto out;
	}

        status = _cairo_clip_intersect_to_rectangle (clip, &extents);
        if (unlikely (status))
            goto out;
    } else {
        cairo_surface_t *clip_surface = clip ? clip->surface : NULL;

        if (trap_region && !clip_surface) {
            /* If we optimize drawing with an unbounded operator to
             * _cairo_surface_fill_rectangles() or to drawing with a
             * clip region, then we have an additional region to clear.
             */
            clear_region = cairo_region_create_rectangle (&extents);

	    status = cairo_region_status (clear_region);
	    if (unlikely (status))
		goto out;

            status = _cairo_clip_intersect_to_region (clip, clear_region);
            if (unlikely (status))
                goto out;

            cairo_region_get_extents (clear_region, &extents);

            status = cairo_region_subtract (clear_region, trap_region);
            if (unlikely (status))
                goto out;

            if (cairo_region_is_empty (clear_region)) {
                cairo_region_destroy (clear_region);
		clear_region = NULL;
            }
        } else {
            status = _cairo_clip_intersect_to_rectangle (clip, &extents);
        }
    }

    if (unlikely (status))
        goto out;

    if (trap_region) {
        cairo_surface_t *clip_surface = clip ? clip->surface : NULL;

        if ((src->type == CAIRO_PATTERN_TYPE_SOLID ||
             op == CAIRO_OPERATOR_CLEAR) && !clip_surface) {
            const cairo_color_t *color;

            if (op == CAIRO_OPERATOR_CLEAR) {
                color = CAIRO_COLOR_TRANSPARENT;
            } else {
                color = &((cairo_solid_pattern_t *)src)->color;
            }

            /* Solid rectangles special case */
            status = _cairo_surface_fill_region (dst, op, color, trap_region);

            if (!status && clear_region) {
                status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
                                                     CAIRO_COLOR_TRANSPARENT,
                                                     clear_region);
	    }

            goto out;
        }

        if ((_cairo_operator_bounded_by_mask (op) &&
             op != CAIRO_OPERATOR_SOURCE) || !clip_surface) {
            /* For a simple rectangle, we can just use composite(), for more
             * rectangles, we have to set a clip region. The cost of rasterizing
             * trapezoids is pretty high for most backends currently, so it's
             * worthwhile even if a region is needed.
             *
             * If we have a clip surface, we set it as the mask; this only works
             * for bounded operators other than SOURCE; for unbounded operators,
             * clip and mask cannot be interchanged. For SOURCE, the operator
             * as implemented by the backends is different in its handling
             * of the mask then what we want.
             *
             * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has
             * more than rectangle and the destination doesn't support clip
             * regions. In that case, we fall through.
             */
            status = _composite_trap_region (clip, src, op, dst,
                                             trap_region, &extents);

            if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
                if (!status && clear_region)
                    status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
                                                         CAIRO_COLOR_TRANSPARENT,
                                                         clear_region);
                goto out;
            }
        }
    }

    traps_info.traps = traps;
    traps_info.antialias = antialias;

    status = _clip_and_composite (clip, op, src,
                                  _composite_traps_draw_func,
                                  &traps_info, dst, &extents);

out:
    if (trap_region)
        cairo_region_destroy (trap_region);
    if (clear_region)
        cairo_region_destroy (clear_region);

    return status;
}
static void
_clutter_stage_wayland_repair_dirty(ClutterStageWayland *stage_wayland,
				       ClutterStage     *stage)
{
  CoglMaterial *outline = NULL;
  CoglHandle vbo;
  float vertices[8], texcoords[8];
  CoglMatrix modelview;
  cairo_region_t *dirty;
  cairo_rectangle_int_t rect;
  int i, count;
  float width, height;

  dirty = stage_wayland->back_buffer->dirty_region;
  stage_wayland->back_buffer->dirty_region = NULL;
  cairo_region_subtract (dirty, stage_wayland->repaint_region);
  width = stage_wayland->allocation.width;
  height = stage_wayland->allocation.height;
  
  /* If this is the first time we render, there is no front buffer to
   * copy back from, but then the dirty region not covered by the
   * repaint should be empty, because we repaint the entire stage.
   *
   * assert(stage_wayland->front_buffer != NULL) ||
   *   cairo_region_is_empty(dirty);
   *
   * FIXME: in test-rotate, the stage never queues a full repaint
   * initially, it's restricted to the paint box of it's rotating
   * children.
   */

  if (!stage_wayland->front_buffer)
    return;

  outline = cogl_material_new ();
  cogl_material_set_layer (outline, 0, stage_wayland->front_buffer->tex);
  count = cairo_region_num_rectangles (dirty);

  for (i = 0; i < count; i++)
    {
      cairo_region_get_rectangle (dirty, i, &rect);
      vbo = cogl_vertex_buffer_new (4);

      vertices[0] = rect.x - 1;
      vertices[1] = rect.y - 1;
      vertices[2] = rect.x + rect.width + 1;
      vertices[3] = rect.y - 1;
      vertices[4] = rect.x + rect.width + 1;
      vertices[5] = rect.y + rect.height + 1;
      vertices[6] = rect.x - 1;
      vertices[7] = rect.y + rect.height + 1;

      cogl_vertex_buffer_add (vbo,
			      "gl_Vertex",
			      2, /* n_components */
			      COGL_ATTRIBUTE_TYPE_FLOAT,
			      FALSE, /* normalized */
			      0, /* stride */
			      vertices);

      texcoords[0] = vertices[0] / width;
      texcoords[1] = vertices[1] / height;
      texcoords[2] = vertices[2] / width;
      texcoords[3] = vertices[3] / height;
      texcoords[4] = vertices[4] / width;
      texcoords[5] = vertices[5] / height;
      texcoords[6] = vertices[6] / width;
      texcoords[7] = vertices[7] / height;

      cogl_vertex_buffer_add (vbo,
			      "gl_MultiTexCoord0",
			      2, /* n_components */
			      COGL_ATTRIBUTE_TYPE_FLOAT,
			      FALSE, /* normalized */
			      0, /* stride */
			      texcoords);

      cogl_vertex_buffer_submit (vbo);

      cogl_push_matrix ();
      cogl_matrix_init_identity (&modelview);
      _clutter_actor_apply_modelview_transform (CLUTTER_ACTOR (stage),
						&modelview);
      cogl_set_modelview_matrix (&modelview);
      cogl_set_source (outline);
      cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_TRIANGLE_FAN,
			       0 , 4);
      cogl_pop_matrix ();
      cogl_object_unref (vbo);
    }

  cairo_region_destroy (dirty);
}
Exemple #22
0
static void
display_entry (MetaTabPopup *popup,
               TabEntry     *te)
{
  GdkRectangle rect;
  GdkWindow *window;

  
  if (popup->current_selected_entry)
  {
    if (popup->outline)
      unselect_image (popup->current_selected_entry->widget);
    else
      unselect_workspace (popup->current_selected_entry->widget);
  }
  
  gtk_label_set_markup (GTK_LABEL (popup->label), te->title);

  if (popup->outline)
    select_image (te->widget);
  else
    select_workspace (te->widget);

  if (popup->outline)
    {
      cairo_region_t *region;
      cairo_region_t *inner_region;
      GdkRGBA black = { 0.0, 0.0, 0.0, 1.0 };

      window = gtk_widget_get_window (popup->outline_window);

      /* Do stuff behind gtk's back */
      gdk_window_hide (window);
      meta_core_increment_event_serial (
          GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
  
      rect = te->rect;
      rect.x = 0;
      rect.y = 0;

      gdk_window_move_resize (window,
                              te->rect.x, te->rect.y,
                              te->rect.width, te->rect.height);
  
      gdk_window_set_background_rgba (window, &black);


      region = cairo_region_create_rectangle (&rect);
      inner_region = cairo_region_create_rectangle (&te->inner_rect);
      cairo_region_subtract (region, inner_region);
      cairo_region_destroy (inner_region);

      gdk_window_shape_combine_region (window,
                                       region,
                                       0, 0);

      cairo_region_destroy (region);
    

      /* This should piss off gtk a bit, but we don't want to raise
       * above the tab popup.  So, instead of calling gtk_widget_show,
       * we manually set the window as mapped and then manually map it
       * with gdk functions.
       */
      gtk_widget_set_mapped (popup->outline_window, TRUE);
      gdk_window_show_unraised (window);
    }

  /* Must be before we handle an expose for the outline window */
  popup->current_selected_entry = te;
}