1use crate::Cursor;
4use crate::EventMask;
5use crate::Visual;
6use crate::Window;
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 #[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 #[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 #[doc(alias = "gdk_window_create_similar_image_surface")]
236 pub fn create_similar_image_surface(
237 &self,
238 format: cairo::Format,
239 width: i32,
240 height: i32,
241 scale: i32,
242 ) -> Option<cairo::Surface> {
243 unsafe {
244 from_glib_full(ffi::gdk_window_create_similar_image_surface(
245 self.to_glib_none().0,
246 format.into(),
247 width,
248 height,
249 scale,
250 ))
251 }
252 }
253}
254
255mod sealed {
256 pub trait Sealed {}
257 impl<T: glib::IsA<crate::Window>> Sealed for T {}
258}
259
260pub trait WindowExtManual: IsA<Window> + sealed::Sealed + 'static {
261 #[doc(alias = "gdk_window_set_user_data")]
262 unsafe fn set_user_data<T>(&self, user_data: &mut T) {
263 ffi::gdk_window_set_user_data(
264 self.as_ref().to_glib_none().0,
265 user_data as *mut T as *mut _,
266 )
267 }
268
269 #[allow(clippy::mut_from_ref)]
270 #[doc(alias = "gdk_window_get_user_data")]
271 #[doc(alias = "get_user_data")]
272 unsafe fn user_data<T>(&self) -> &mut T {
273 let mut pointer = ::std::ptr::null_mut();
274 ffi::gdk_window_get_user_data(self.as_ref().to_glib_none().0, &mut pointer);
275 &mut *(pointer as *mut T)
276 }
277
278 #[doc(alias = "gdk_get_default_root_window")]
279 #[doc(alias = "get_default_root_window")]
280 fn default_root_window() -> Window {
281 assert_initialized_main_thread!();
282 unsafe { from_glib_none(ffi::gdk_get_default_root_window()) }
283 }
284
285 #[doc(alias = "gdk_offscreen_window_set_embedder")]
286 fn offscreen_window_set_embedder(&self, embedder: &Window) {
287 unsafe {
288 ffi::gdk_offscreen_window_set_embedder(
289 self.as_ref().to_glib_none().0,
290 embedder.to_glib_none().0,
291 )
292 }
293 }
294
295 #[doc(alias = "gdk_offscreen_window_get_embedder")]
296 fn offscreen_window_get_embedder(&self) -> Option<Window> {
297 unsafe {
298 from_glib_none(ffi::gdk_offscreen_window_get_embedder(
299 self.as_ref().to_glib_none().0,
300 ))
301 }
302 }
303
304 #[doc(alias = "gdk_offscreen_window_get_surface")]
305 fn offscreen_window_get_surface(&self) -> Option<Surface> {
306 skip_assert_initialized!();
307 unsafe {
308 from_glib_none(ffi::gdk_offscreen_window_get_surface(
309 self.as_ref().to_glib_none().0,
310 ))
311 }
312 }
313
314 #[doc(alias = "gdk_pixbuf_get_from_window")]
315 #[doc(alias = "get_pixbuf")]
316 fn pixbuf(
317 &self,
318 src_x: i32,
319 src_y: i32,
320 width: i32,
321 height: i32,
322 ) -> Option<gdk_pixbuf::Pixbuf> {
323 skip_assert_initialized!();
324 unsafe {
325 from_glib_full(ffi::gdk_pixbuf_get_from_window(
326 self.as_ref().to_glib_none().0,
327 src_x,
328 src_y,
329 width,
330 height,
331 ))
332 }
333 }
334
335 #[doc(alias = "gdk_window_get_background_pattern")]
336 #[doc(alias = "get_background_pattern")]
337 fn background_pattern(&self) -> Option<cairo::Pattern> {
338 unsafe {
339 let ret = ffi::gdk_window_get_background_pattern(self.as_ref().to_glib_none().0);
340 if ret.is_null() {
341 None
342 } else {
343 Some(cairo::Pattern::from_raw_none(ret))
344 }
345 }
346 }
347
348 #[doc(alias = "gdk_window_set_background_pattern")]
349 fn set_background_pattern(&self, pattern: Option<&cairo::Pattern>) {
350 unsafe {
351 let ptr = if let Some(pattern) = pattern {
352 pattern.to_raw_none()
353 } else {
354 ::std::ptr::null_mut()
355 };
356 ffi::gdk_window_set_background_pattern(self.as_ref().to_glib_none().0, ptr);
357 }
358 }
359}
360
361impl<O: IsA<Window>> WindowExtManual for O {}