1 | /* GDK - The GIMP Drawing Kit |
2 | * |
3 | * gdkcairocontext-x11.c: X11 specific Cairo wrappers |
4 | * |
5 | * Copyright © 2016 Benjamin Otte |
6 | * |
7 | * This library is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Library General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2 of the License, or (at your option) any later version. |
11 | * |
12 | * This library is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Library General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU Library General Public |
18 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
19 | */ |
20 | |
21 | #include "config.h" |
22 | |
23 | #include "gdkcairocontext-x11.h" |
24 | |
25 | #include "gdkprivate-x11.h" |
26 | |
27 | #include "gdkcairo.h" |
28 | #include "gdksurfaceprivate.h" |
29 | |
30 | #include <X11/Xlib.h> |
31 | |
32 | G_DEFINE_TYPE (GdkX11CairoContext, gdk_x11_cairo_context, GDK_TYPE_CAIRO_CONTEXT) |
33 | |
34 | static cairo_surface_t * |
35 | create_cairo_surface_for_surface (GdkSurface *surface) |
36 | { |
37 | GdkDisplay *display; |
38 | cairo_surface_t *cairo_surface; |
39 | Visual *visual; |
40 | int scale; |
41 | |
42 | display = gdk_surface_get_display (surface); |
43 | scale = gdk_surface_get_scale_factor (surface); |
44 | |
45 | visual = gdk_x11_display_get_window_visual (GDK_X11_DISPLAY (display)); |
46 | cairo_surface = cairo_xlib_surface_create (dpy: gdk_x11_display_get_xdisplay (display), |
47 | GDK_SURFACE_XID (surface), |
48 | visual, |
49 | width: gdk_surface_get_width (surface) * scale, |
50 | height: gdk_surface_get_height (surface) * scale); |
51 | cairo_surface_set_device_scale (surface: cairo_surface, x_scale: scale, y_scale: scale); |
52 | |
53 | return cairo_surface; |
54 | } |
55 | |
56 | static void |
57 | gdk_x11_cairo_context_begin_frame (GdkDrawContext *draw_context, |
58 | gboolean prefers_high_depth, |
59 | cairo_region_t *region) |
60 | { |
61 | GdkX11CairoContext *self = GDK_X11_CAIRO_CONTEXT (draw_context); |
62 | GdkRectangle clip_box; |
63 | GdkSurface *surface; |
64 | double sx, sy; |
65 | |
66 | surface = gdk_draw_context_get_surface (context: draw_context); |
67 | cairo_region_get_extents (region, extents: &clip_box); |
68 | |
69 | self->window_surface = create_cairo_surface_for_surface (surface); |
70 | self->paint_surface = gdk_surface_create_similar_surface (surface, |
71 | content: cairo_surface_get_content (surface: self->window_surface), |
72 | MAX (clip_box.width, 1), |
73 | MAX (clip_box.height, 1)); |
74 | |
75 | sx = sy = 1; |
76 | cairo_surface_get_device_scale (surface: self->paint_surface, x_scale: &sx, y_scale: &sy); |
77 | cairo_surface_set_device_offset (surface: self->paint_surface, x_offset: -clip_box.x*sx, y_offset: -clip_box.y*sy); |
78 | } |
79 | |
80 | static void |
81 | gdk_x11_cairo_context_end_frame (GdkDrawContext *draw_context, |
82 | cairo_region_t *painted) |
83 | { |
84 | GdkX11CairoContext *self = GDK_X11_CAIRO_CONTEXT (draw_context); |
85 | cairo_t *cr; |
86 | |
87 | cr = cairo_create (target: self->window_surface); |
88 | |
89 | cairo_set_source_surface (cr, surface: self->paint_surface, x: 0, y: 0); |
90 | gdk_cairo_region (cr, region: painted); |
91 | cairo_clip (cr); |
92 | |
93 | cairo_set_operator (cr, op: CAIRO_OPERATOR_SOURCE); |
94 | cairo_paint (cr); |
95 | |
96 | cairo_destroy (cr); |
97 | |
98 | cairo_surface_flush (surface: self->window_surface); |
99 | |
100 | g_clear_pointer (&self->paint_surface, cairo_surface_destroy); |
101 | g_clear_pointer (&self->window_surface, cairo_surface_destroy); |
102 | } |
103 | |
104 | static cairo_t * |
105 | gdk_x11_cairo_context_cairo_create (GdkCairoContext *context) |
106 | { |
107 | GdkX11CairoContext *self = GDK_X11_CAIRO_CONTEXT (context); |
108 | |
109 | return cairo_create (target: self->paint_surface); |
110 | } |
111 | |
112 | static void |
113 | gdk_x11_cairo_context_class_init (GdkX11CairoContextClass *klass) |
114 | { |
115 | GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass); |
116 | GdkCairoContextClass *cairo_context_class = GDK_CAIRO_CONTEXT_CLASS (klass); |
117 | |
118 | draw_context_class->begin_frame = gdk_x11_cairo_context_begin_frame; |
119 | draw_context_class->end_frame = gdk_x11_cairo_context_end_frame; |
120 | |
121 | cairo_context_class->cairo_create = gdk_x11_cairo_context_cairo_create; |
122 | } |
123 | |
124 | static void |
125 | gdk_x11_cairo_context_init (GdkX11CairoContext *self) |
126 | { |
127 | } |
128 | |
129 | |