gdk4/cairo_interaction.rs
1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use cairo::{Context, Region};
4use gdk_pixbuf::Pixbuf;
5use glib::translate::*;
6
7use crate::{ffi, Rectangle, Surface, RGBA};
8
9// rustdoc-stripper-ignore-next
10/// Trait containing integration methods with [`cairo::Surface`].
11pub trait GdkCairoSurfaceExt {
12 /// Creates region that covers the area where the given
13 /// @surface is more than 50% opaque.
14 ///
15 /// This function takes into account device offsets that might be
16 /// set with cairo_surface_set_device_offset().
17 /// ## `surface`
18 /// a cairo surface
19 ///
20 /// # Returns
21 ///
22 /// A [`cairo::Region`][crate::cairo::Region]
23 #[doc(alias = "gdk_cairo_region_create_from_surface")]
24 fn create_region(&self) -> Region;
25}
26
27impl GdkCairoSurfaceExt for cairo::Surface {
28 fn create_region(&self) -> Region {
29 unsafe {
30 from_glib_full(ffi::gdk_cairo_region_create_from_surface(
31 self.to_glib_none().0,
32 ))
33 }
34 }
35}
36
37// rustdoc-stripper-ignore-next
38/// Trait containing integration methods with [`cairo::Context`].
39pub trait GdkCairoContextExt: sealed::Sealed {
40 // rustdoc-stripper-ignore-next
41 /// # Safety
42 ///
43 /// It's the responsibility of the caller to ensure that source
44 /// is a valid GL resource.
45 // rustdoc-stripper-ignore-next-stop
46 /// The main way to not draw GL content in GTK.
47 ///
48 /// It takes a render buffer ID (@source_type == GL_RENDERBUFFER) or a texture
49 /// id (@source_type == GL_TEXTURE) and draws it onto @cr with an OVER operation,
50 /// respecting the current clip. The top left corner of the rectangle specified
51 /// by @x, @y, @width and @height will be drawn at the current (0,0) position of
52 /// the [`cairo::Context`][crate::cairo::Context].
53 ///
54 /// This will work for *all* [`cairo::Context`][crate::cairo::Context], as long as @surface is realized, but the
55 /// fallback implementation that reads back the pixels from the buffer may be
56 /// used in the general case. In the case of direct drawing to a surface with
57 /// no special effects applied to @cr it will however use a more efficient
58 /// approach.
59 ///
60 /// For GL_RENDERBUFFER the code will always fall back to software for buffers
61 /// with alpha components, so make sure you use GL_TEXTURE if using alpha.
62 ///
63 /// Calling this may change the current GL context.
64 ///
65 /// # Deprecated since 4.6
66 ///
67 /// The function is overly complex and produces broken output
68 /// in various combinations of arguments. If you want to draw with GL textures
69 /// in GTK, use [`GLTexture::new()`][crate::GLTexture::new()]; if you want to use that texture in
70 /// Cairo, use [`TextureExtManual::download()`][crate::prelude::TextureExtManual::download()] to download the data into a Cairo
71 /// image surface.
72 /// ## `cr`
73 /// a cairo context
74 /// ## `surface`
75 /// The surface we're rendering for (not necessarily into)
76 /// ## `source`
77 /// The GL ID of the source buffer
78 /// ## `source_type`
79 /// The type of the @source
80 /// ## `buffer_scale`
81 /// The scale-factor that the @source buffer is allocated for
82 /// ## `x`
83 /// The source x position in @source to start copying from in GL coordinates
84 /// ## `y`
85 /// The source y position in @source to start copying from in GL coordinates
86 /// ## `width`
87 /// The width of the region to draw
88 /// ## `height`
89 /// The height of the region to draw
90 #[doc(alias = "gdk_cairo_draw_from_gl")]
91 #[allow(clippy::too_many_arguments)]
92 unsafe fn draw_from_gl(
93 &self,
94 surface: &Surface,
95 source: i32,
96 source_type: i32,
97 buffer_scale: i32,
98 x: i32,
99 y: i32,
100 width: i32,
101 height: i32,
102 ) {
103 skip_assert_initialized!();
104 ffi::gdk_cairo_draw_from_gl(
105 self.to_raw(),
106 surface.to_glib_none().0,
107 source,
108 source_type,
109 buffer_scale,
110 x,
111 y,
112 width,
113 height,
114 );
115 }
116
117 /// Sets the specified [`RGBA`][crate::RGBA] as the source color of @cr.
118 /// ## `cr`
119 /// a cairo context
120 /// ## `rgba`
121 /// a [`RGBA`][crate::RGBA]
122 #[doc(alias = "gdk_cairo_set_source_rgba")]
123 #[doc(alias = "set_source_rgba")]
124 fn set_source_color(&self, rgba: &RGBA) {
125 unsafe {
126 ffi::gdk_cairo_set_source_rgba(self.to_raw(), rgba.to_glib_none().0);
127 }
128 }
129
130 /// Sets the given pixbuf as the source pattern for @cr.
131 ///
132 /// The pattern has an extend mode of `CAIRO_EXTEND_NONE` and is aligned
133 /// so that the origin of @pixbuf is @pixbuf_x, @pixbuf_y.
134 /// ## `cr`
135 /// a cairo context
136 /// ## `pixbuf`
137 /// a [`gdk_pixbuf::Pixbuf`][crate::gdk_pixbuf::Pixbuf]
138 /// ## `pixbuf_x`
139 /// X coordinate of location to place upper left corner of @pixbuf
140 /// ## `pixbuf_y`
141 /// Y coordinate of location to place upper left corner of @pixbuf
142 #[doc(alias = "gdk_cairo_set_source_pixbuf")]
143 fn set_source_pixbuf(&self, pixbuf: &Pixbuf, x: f64, y: f64) {
144 unsafe {
145 ffi::gdk_cairo_set_source_pixbuf(self.to_raw(), pixbuf.to_glib_none().0, x, y);
146 }
147 }
148
149 /// Adds the given rectangle to the current path of @cr.
150 /// ## `cr`
151 /// a cairo context
152 /// ## `rectangle`
153 /// a [`Rectangle`][crate::Rectangle]
154 #[doc(alias = "gdk_cairo_rectangle")]
155 fn add_rectangle(&self, rectangle: &Rectangle) {
156 unsafe {
157 ffi::gdk_cairo_rectangle(self.to_raw(), rectangle.to_glib_none().0);
158 }
159 }
160
161 /// Adds the given region to the current path of @cr.
162 /// ## `cr`
163 /// a cairo context
164 /// ## `region`
165 /// a [`cairo::Region`][crate::cairo::Region]
166 #[doc(alias = "gdk_cairo_region")]
167 fn add_region(&self, region: &Region) {
168 unsafe {
169 ffi::gdk_cairo_region(self.to_raw(), region.to_glib_none().0);
170 }
171 }
172}
173
174impl GdkCairoContextExt for Context {}
175
176mod sealed {
177 use cairo::{ffi::cairo_t, Context};
178
179 pub trait Sealed {
180 fn to_raw(&self) -> *mut cairo_t;
181 }
182
183 impl Sealed for Context {
184 fn to_raw(&self) -> *mut cairo_t {
185 self.to_raw_none()
186 }
187 }
188}