Skip to main content

gdk/
window.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::EventMask;
4use crate::Visual;
5use crate::Window;
6use crate::{Cursor, ffi};
7use cairo::{self, Surface};
8use glib::object::IsA;
9use glib::translate::*;
10use libc::{c_char, c_int};
11use std::ptr;
12
13use crate::{WindowType, WindowTypeHint, WindowWindowClass};
14
15pub struct WindowAttr {
16    pub title: Option<String>,
17    pub event_mask: EventMask,
18    pub x: Option<i32>,
19    pub y: Option<i32>,
20    pub width: i32,
21    pub height: i32,
22    pub wclass: WindowWindowClass,
23    pub visual: Option<Visual>,
24    pub window_type: WindowType,
25    pub cursor: Option<Cursor>,
26    pub override_redirect: bool,
27    pub type_hint: Option<WindowTypeHint>,
28}
29
30impl Default for WindowAttr {
31    fn default() -> Self {
32        skip_assert_initialized!();
33        Self {
34            title: None,
35            event_mask: EventMask::empty(),
36            x: None,
37            y: None,
38            width: 400,
39            height: 300,
40            wclass: WindowWindowClass::InputOutput,
41            visual: None,
42            window_type: WindowType::Toplevel,
43            cursor: None,
44            override_redirect: false,
45            type_hint: None,
46        }
47    }
48}
49
50impl WindowAttr {
51    #[doc(alias = "get_mask")]
52    fn mask(&self) -> u32 {
53        let mut mask: ffi::GdkWindowAttributesType = 0;
54        if self.title.is_some() {
55            mask |= ffi::GDK_WA_TITLE;
56        }
57        if self.x.is_some() {
58            mask |= ffi::GDK_WA_X;
59        }
60        if self.y.is_some() {
61            mask |= ffi::GDK_WA_Y;
62        }
63        if self.cursor.is_some() {
64            mask |= ffi::GDK_WA_CURSOR;
65        }
66        if self.visual.is_some() {
67            mask |= ffi::GDK_WA_VISUAL;
68        }
69        if self.override_redirect {
70            mask |= ffi::GDK_WA_NOREDIR;
71        }
72        if self.type_hint.is_some() {
73            mask |= ffi::GDK_WA_TYPE_HINT;
74        }
75        mask
76    }
77}
78
79#[allow(clippy::type_complexity)]
80impl<'a> ToGlibPtr<'a, *mut ffi::GdkWindowAttr> for WindowAttr {
81    type Storage = (
82        Box<ffi::GdkWindowAttr>,
83        Stash<'a, *mut ffi::GdkVisual, Option<Visual>>,
84        Stash<'a, *mut ffi::GdkCursor, Option<Cursor>>,
85        Stash<'a, *const c_char, Option<String>>,
86    );
87
88    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GdkWindowAttr, Self> {
89        let title = self.title.to_glib_none();
90        let visual = self.visual.to_glib_none();
91        let cursor = self.cursor.to_glib_none();
92
93        let mut attrs = Box::new(ffi::GdkWindowAttr {
94            title: title.0 as *mut c_char,
95            event_mask: self.event_mask.bits() as i32,
96            x: self.x.unwrap_or(0),
97            y: self.y.unwrap_or(0),
98            width: self.width,
99            height: self.height,
100            wclass: self.wclass.into_glib(),
101            visual: visual.0,
102            window_type: self.window_type.into_glib(),
103            cursor: cursor.0,
104            wmclass_name: ptr::null_mut(),
105            wmclass_class: ptr::null_mut(),
106            override_redirect: self.override_redirect.into_glib(),
107            type_hint: self.type_hint.unwrap_or(WindowTypeHint::Normal).into_glib(),
108        });
109
110        Stash(&mut *attrs, (attrs, visual, cursor, title))
111    }
112}
113
114impl Window {
115    /// Creates a new [`Window`][crate::Window] using the attributes from
116    /// `attributes`. See `GdkWindowAttr` and `GdkWindowAttributesType` for
117    /// more details. Note: to use this on displays other than the default
118    /// display, `parent` must be specified.
119    /// ## `parent`
120    /// a [`Window`][crate::Window], or [`None`] to create the window as a child of
121    ///  the default root window for the default display.
122    /// ## `attributes`
123    /// attributes of the new window
124    /// ## `attributes_mask`
125    /// mask indicating which
126    ///  fields in `attributes` are valid
127    ///
128    /// # Returns
129    ///
130    /// the new [`Window`][crate::Window]
131    #[doc(alias = "gdk_window_new")]
132    pub fn new(parent: Option<&Window>, attributes: &WindowAttr) -> Window {
133        assert_initialized_main_thread!();
134        unsafe {
135            from_glib_full(ffi::gdk_window_new(
136                parent.to_glib_none().0,
137                attributes.to_glib_none().0,
138                attributes.mask() as c_int,
139            ))
140        }
141    }
142
143    /// Create a new surface that is as compatible as possible with the
144    /// given `self`. For example the new surface will have the same
145    /// fallback resolution and font options as `self`. Generally, the new
146    /// surface will also use the same backend as `self`, unless that is
147    /// not possible for some reason. The type of the returned surface may
148    /// be examined with `cairo_surface_get_type()`.
149    ///
150    /// Initially the surface contents are all 0 (transparent if contents
151    /// have transparency, black otherwise.)
152    /// ## `content`
153    /// the content for the new surface
154    /// ## `width`
155    /// width of the new surface
156    /// ## `height`
157    /// height of the new surface
158    ///
159    /// # Returns
160    ///
161    /// a pointer to the newly allocated surface. The caller
162    /// owns the surface and should call `cairo_surface_destroy()` when done
163    /// with it.
164    ///
165    /// This function always returns a valid pointer, but it will return a
166    /// pointer to a “nil” surface if `other` is already in an error state
167    /// or any other error occurs.
168    #[doc(alias = "gdk_window_create_similar_surface")]
169    pub fn create_similar_surface(
170        &self,
171        content: cairo::Content,
172        width: i32,
173        height: i32,
174    ) -> Option<Surface> {
175        unsafe {
176            from_glib_full(ffi::gdk_window_create_similar_surface(
177                self.to_glib_none().0,
178                content.into(),
179                width,
180                height,
181            ))
182        }
183    }
184
185    ///
186    ///  int scale = gdk_window_get_scale_factor (window);
187    ///  int width = gdk_window_get_width (window) * scale;
188    ///  int height = gdk_window_get_height (window) * scale;
189    ///
190    ///  // format is set elsewhere
191    ///  cairo_surface_t *surface =
192    ///  gdk_window_create_similar_image_surface (window,
193    ///  format,
194    ///  width, height,
195    ///  scale);
196    /// ]|
197    ///
198    /// Note that unlike `cairo_surface_create_similar_image()`, the new
199    /// surface's device scale is set to `scale`, or to the scale factor of
200    /// `self` if `scale` is 0.
201    /// ## `format`
202    /// the format for the new surface
203    /// ## `width`
204    /// width of the new surface
205    /// ## `height`
206    /// height of the new surface
207    /// ## `scale`
208    /// the scale of the new surface, or 0 to use same as `self`
209    ///
210    /// # Returns
211    ///
212    /// a pointer to the newly allocated surface. The caller
213    /// owns the surface and should call `cairo_surface_destroy()` when done
214    /// with it.
215    ///
216    /// This function always returns a valid pointer, but it will return a
217    /// pointer to a “nil” surface if `other` is already in an error state
218    /// or any other error occurs.
219    #[doc(alias = "gdk_window_create_similar_image_surface")]
220    pub fn create_similar_image_surface(
221        &self,
222        format: cairo::Format,
223        width: i32,
224        height: i32,
225        scale: i32,
226    ) -> Option<cairo::Surface> {
227        unsafe {
228            from_glib_full(ffi::gdk_window_create_similar_image_surface(
229                self.to_glib_none().0,
230                format.into(),
231                width,
232                height,
233                scale,
234            ))
235        }
236    }
237}
238
239mod sealed {
240    pub trait Sealed {}
241    impl<T: glib::object::IsA<crate::Window>> Sealed for T {}
242}
243
244pub trait WindowExtManual: IsA<Window> + sealed::Sealed + 'static {
245    #[doc(alias = "gdk_window_set_user_data")]
246    unsafe fn set_user_data<T>(&self, user_data: &mut T) {
247        unsafe {
248            ffi::gdk_window_set_user_data(
249                self.as_ref().to_glib_none().0,
250                user_data as *mut T as *mut _,
251            )
252        }
253    }
254
255    #[allow(clippy::mut_from_ref)]
256    #[doc(alias = "gdk_window_get_user_data")]
257    #[doc(alias = "get_user_data")]
258    unsafe fn user_data<T>(&self) -> &mut T {
259        unsafe {
260            let mut pointer = ::std::ptr::null_mut();
261            ffi::gdk_window_get_user_data(self.as_ref().to_glib_none().0, &mut pointer);
262            &mut *(pointer as *mut T)
263        }
264    }
265
266    #[doc(alias = "gdk_get_default_root_window")]
267    #[doc(alias = "get_default_root_window")]
268    fn default_root_window() -> Window {
269        assert_initialized_main_thread!();
270        unsafe { from_glib_none(ffi::gdk_get_default_root_window()) }
271    }
272
273    #[doc(alias = "gdk_offscreen_window_set_embedder")]
274    fn offscreen_window_set_embedder(&self, embedder: &Window) {
275        unsafe {
276            ffi::gdk_offscreen_window_set_embedder(
277                self.as_ref().to_glib_none().0,
278                embedder.to_glib_none().0,
279            )
280        }
281    }
282
283    #[doc(alias = "gdk_offscreen_window_get_embedder")]
284    fn offscreen_window_get_embedder(&self) -> Option<Window> {
285        unsafe {
286            from_glib_none(ffi::gdk_offscreen_window_get_embedder(
287                self.as_ref().to_glib_none().0,
288            ))
289        }
290    }
291
292    #[doc(alias = "gdk_offscreen_window_get_surface")]
293    fn offscreen_window_get_surface(&self) -> Option<Surface> {
294        skip_assert_initialized!();
295        unsafe {
296            from_glib_none(ffi::gdk_offscreen_window_get_surface(
297                self.as_ref().to_glib_none().0,
298            ))
299        }
300    }
301
302    #[doc(alias = "gdk_pixbuf_get_from_window")]
303    #[doc(alias = "get_pixbuf")]
304    fn pixbuf(
305        &self,
306        src_x: i32,
307        src_y: i32,
308        width: i32,
309        height: i32,
310    ) -> Option<gdk_pixbuf::Pixbuf> {
311        skip_assert_initialized!();
312        unsafe {
313            from_glib_full(ffi::gdk_pixbuf_get_from_window(
314                self.as_ref().to_glib_none().0,
315                src_x,
316                src_y,
317                width,
318                height,
319            ))
320        }
321    }
322
323    #[doc(alias = "gdk_window_get_background_pattern")]
324    #[doc(alias = "get_background_pattern")]
325    fn background_pattern(&self) -> Option<cairo::Pattern> {
326        unsafe {
327            let ret = ffi::gdk_window_get_background_pattern(self.as_ref().to_glib_none().0);
328            if ret.is_null() {
329                None
330            } else {
331                Some(cairo::Pattern::from_raw_none(ret))
332            }
333        }
334    }
335
336    #[doc(alias = "gdk_window_set_background_pattern")]
337    fn set_background_pattern(&self, pattern: Option<&cairo::Pattern>) {
338        unsafe {
339            let ptr = if let Some(pattern) = pattern {
340                pattern.to_raw_none()
341            } else {
342                ::std::ptr::null_mut()
343            };
344            ffi::gdk_window_set_background_pattern(self.as_ref().to_glib_none().0, ptr);
345        }
346    }
347}
348
349impl<O: IsA<Window>> WindowExtManual for O {}