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