1use 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 #[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")]
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 {}