1use cairo::{self, Surface};
6use gdk_pixbuf;
7use gdk_sys;
8use glib::object::IsA;
9use glib::translate::*;
10use libc::{c_char, c_int};
11use std::ptr;
12use Cursor;
13use Visual;
14use Window;
15
16use {WindowHints, WindowType, WindowTypeHint, WindowWindowClass};
17
18pub struct WindowAttr {
19 pub title: Option<String>,
20 pub event_mask: i32,
21 pub x: Option<i32>,
22 pub y: Option<i32>,
23 pub width: i32,
24 pub height: i32,
25 pub wclass: WindowWindowClass,
26 pub visual: Option<Visual>,
27 pub window_type: WindowType,
28 pub cursor: Option<Cursor>,
29 pub override_redirect: bool,
30 pub type_hint: Option<WindowTypeHint>,
31}
32
33impl Default for WindowAttr {
34 fn default() -> WindowAttr {
35 skip_assert_initialized!();
36 WindowAttr {
37 title: None,
38 event_mask: 0,
39 x: None,
40 y: None,
41 width: 400,
42 height: 300,
43 wclass: WindowWindowClass::InputOutput,
44 visual: None,
45 window_type: WindowType::Toplevel,
46 cursor: None,
47 override_redirect: false,
48 type_hint: None,
49 }
50 }
51}
52
53impl WindowAttr {
54 fn get_mask(&self) -> u32 {
55 let mut mask: gdk_sys::GdkWindowAttributesType = 0;
56 if self.title.is_some() {
57 mask |= gdk_sys::GDK_WA_TITLE;
58 }
59 if self.x.is_some() {
60 mask |= gdk_sys::GDK_WA_X;
61 }
62 if self.y.is_some() {
63 mask |= gdk_sys::GDK_WA_Y;
64 }
65 if self.cursor.is_some() {
66 mask |= gdk_sys::GDK_WA_CURSOR;
67 }
68 if self.visual.is_some() {
69 mask |= gdk_sys::GDK_WA_VISUAL;
70 }
71 if self.override_redirect {
72 mask |= gdk_sys::GDK_WA_NOREDIR;
73 }
74 if self.type_hint.is_some() {
75 mask |= gdk_sys::GDK_WA_TYPE_HINT;
76 }
77 mask
78 }
79}
80
81#[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
82impl<'a> ToGlibPtr<'a, *mut gdk_sys::GdkWindowAttr> for WindowAttr {
83 type Storage = (
84 Box<gdk_sys::GdkWindowAttr>,
85 Stash<'a, *mut gdk_sys::GdkVisual, Option<Visual>>,
86 Stash<'a, *mut gdk_sys::GdkCursor, Option<Cursor>>,
87 Stash<'a, *const c_char, Option<String>>,
88 );
89
90 fn to_glib_none(&'a self) -> Stash<'a, *mut gdk_sys::GdkWindowAttr, Self> {
91 let title = self.title.to_glib_none();
92 let visual = self.visual.to_glib_none();
93 let cursor = self.cursor.to_glib_none();
94
95 let mut attrs = Box::new(gdk_sys::GdkWindowAttr {
96 title: title.0 as *mut c_char,
97 event_mask: self.event_mask,
98 x: self.x.unwrap_or(0),
99 y: self.y.unwrap_or(0),
100 width: self.width,
101 height: self.height,
102 wclass: self.wclass.to_glib(),
103 visual: visual.0,
104 window_type: self.window_type.to_glib(),
105 cursor: cursor.0,
106 wmclass_name: ptr::null_mut(),
107 wmclass_class: ptr::null_mut(),
108 override_redirect: self.override_redirect.to_glib(),
109 type_hint: self.type_hint.unwrap_or(WindowTypeHint::Normal).to_glib(),
110 });
111
112 Stash(&mut *attrs, (attrs, visual, cursor, title))
113 }
114}
115
116impl Window {
117 pub fn new(parent: Option<&Window>, attributes: &WindowAttr) -> Window {
118 assert_initialized_main_thread!();
119 unsafe {
120 from_glib_full(gdk_sys::gdk_window_new(
121 parent.to_glib_none().0,
122 attributes.to_glib_none().0,
123 attributes.get_mask() as c_int,
124 ))
125 }
126 }
127
128 pub fn create_similar_surface(
129 &self,
130 content: cairo::Content,
131 width: i32,
132 height: i32,
133 ) -> Option<Surface> {
134 unsafe {
135 from_glib_full(gdk_sys::gdk_window_create_similar_surface(
136 self.to_glib_none().0,
137 content.into(),
138 width,
139 height,
140 ))
141 }
142 }
143}
144
145pub trait WindowExtManual: 'static {
146 unsafe fn set_user_data<T>(&self, user_data: &mut T);
147
148 #[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref))]
149 unsafe fn get_user_data<T>(&self) -> &mut T;
150
151 fn set_geometry_hints(&self, geometry: &gdk_sys::GdkGeometry, geom_mask: WindowHints);
152
153 fn get_default_root_window() -> Window;
154
155 fn offscreen_window_set_embedder(&self, embedder: &Window);
156
157 fn offscreen_window_get_embedder(&self) -> Option<Window>;
158
159 fn offscreen_window_get_surface(&self) -> Option<Surface>;
160
161 fn get_pixbuf(
162 &self,
163 src_x: i32,
164 src_y: i32,
165 width: i32,
166 height: i32,
167 ) -> Option<gdk_pixbuf::Pixbuf>;
168
169 fn get_background_pattern(&self) -> Option<cairo::Pattern>;
170
171 fn set_background_pattern(&self, pattern: Option<&cairo::Pattern>);
172}
173
174impl<O: IsA<Window>> WindowExtManual for O {
175 unsafe fn set_user_data<T>(&self, user_data: &mut T) {
176 gdk_sys::gdk_window_set_user_data(
177 self.as_ref().to_glib_none().0,
178 user_data as *mut T as *mut _,
179 )
180 }
181
182 unsafe fn get_user_data<T>(&self) -> &mut T {
183 let mut pointer = ::std::ptr::null_mut();
184 gdk_sys::gdk_window_get_user_data(self.as_ref().to_glib_none().0, &mut pointer);
185 &mut *(pointer as *mut T)
186 }
187
188 fn set_geometry_hints(&self, geometry: &gdk_sys::GdkGeometry, geom_mask: WindowHints) {
189 unsafe {
190 gdk_sys::gdk_window_set_geometry_hints(
191 self.as_ref().to_glib_none().0,
192 geometry,
193 geom_mask.to_glib(),
194 )
195 }
196 }
197
198 fn get_default_root_window() -> Window {
199 assert_initialized_main_thread!();
200 unsafe { from_glib_none(gdk_sys::gdk_get_default_root_window()) }
201 }
202
203 fn offscreen_window_set_embedder(&self, embedder: &Window) {
204 unsafe {
205 gdk_sys::gdk_offscreen_window_set_embedder(
206 self.as_ref().to_glib_none().0,
207 embedder.to_glib_none().0,
208 )
209 }
210 }
211
212 fn offscreen_window_get_embedder(&self) -> Option<Window> {
213 unsafe {
214 from_glib_none(gdk_sys::gdk_offscreen_window_get_embedder(
215 self.as_ref().to_glib_none().0,
216 ))
217 }
218 }
219
220 fn offscreen_window_get_surface(&self) -> Option<Surface> {
221 skip_assert_initialized!();
222 unsafe {
223 from_glib_none(gdk_sys::gdk_offscreen_window_get_surface(
224 self.as_ref().to_glib_none().0,
225 ))
226 }
227 }
228
229 fn get_pixbuf(
230 &self,
231 src_x: i32,
232 src_y: i32,
233 width: i32,
234 height: i32,
235 ) -> Option<gdk_pixbuf::Pixbuf> {
236 skip_assert_initialized!();
237 unsafe {
238 from_glib_full(gdk_sys::gdk_pixbuf_get_from_window(
239 self.as_ref().to_glib_none().0,
240 src_x,
241 src_y,
242 width,
243 height,
244 ))
245 }
246 }
247
248 fn get_background_pattern(&self) -> Option<cairo::Pattern> {
249 unsafe {
250 let ret = gdk_sys::gdk_window_get_background_pattern(self.as_ref().to_glib_none().0);
251 if ret.is_null() {
252 None
253 } else {
254 Some(cairo::Pattern::from_raw_none(ret))
255 }
256 }
257 }
258
259 fn set_background_pattern(&self, pattern: Option<&cairo::Pattern>) {
260 unsafe {
261 let ptr = if let Some(pattern) = pattern {
262 pattern.to_raw_none()
263 } else {
264 ::std::ptr::null_mut()
265 };
266 gdk_sys::gdk_window_set_background_pattern(self.as_ref().to_glib_none().0, ptr);
267 }
268 }
269}