/* 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); }
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); } }
// 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; }
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); }
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; }
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 }
/* 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; }
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, ¶meters); } } 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, ¶meters); } } cairo_region_subtract(priv->expose, priv->expose); }
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; } }
/** * 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)); }
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); }
void Region::Subtract (Region *region) { status = cairo_region_subtract (cairo_region, region->cairo_region); }
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); }
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); }
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; }