1 use libc::{c_int, c_uint, c_float, uint32_t, c_char};
2 use std::ffi::{CStr, CString, NulError};
3 use std::{mem, ptr, fmt};
4 use std::rc::Rc;
5 use std::error::Error;
6 use std::ops::{Deref, DerefMut};
7 
8 use crate::rect::Rect;
9 use crate::render::CanvasBuilder;
10 use crate::surface::SurfaceRef;
11 use crate::pixels::PixelFormatEnum;
12 use crate::VideoSubsystem;
13 use crate::EventPump;
14 use num::FromPrimitive;
15 use crate::common::{validate_int, IntegerOrSdlError};
16 
17 use crate::get_error;
18 
19 use crate::sys;
20 
21 pub use crate::sys::{VkInstance, VkSurfaceKHR};
22 
23 
24 pub struct WindowSurfaceRef<'a>(&'a mut SurfaceRef, &'a Window);
25 
26 impl<'a> Deref for WindowSurfaceRef<'a> {
27     type Target = SurfaceRef;
28 
29     #[inline]
deref(&self) -> &SurfaceRef30     fn deref(&self) -> &SurfaceRef {
31         self.0
32     }
33 }
34 
35 impl<'a> DerefMut for WindowSurfaceRef<'a> {
36     #[inline]
deref_mut(&mut self) -> &mut SurfaceRef37     fn deref_mut(&mut self) -> &mut SurfaceRef {
38         &mut self.0
39     }
40 }
41 
42 impl<'a> WindowSurfaceRef<'a> {
43     /// Updates the change made to the inner Surface to the Window it was created from.
44     ///
45     /// This would effectively be the theoretical equivalent of `present` from a Canvas.
update_window(&self) -> Result<(), String>46     pub fn update_window(&self) -> Result<(), String> {
47         unsafe {
48             if sys::SDL_UpdateWindowSurface(self.1.context.raw) == 0 {
49                 Ok(())
50             } else {
51                 Err(get_error())
52             }
53         }
54     }
55 
56     /// Same as `update_window`, but only update the parts included in `rects` to the Window it was
57     /// created from.
update_window_rects(&self, rects: &[Rect]) -> Result<(), String>58     pub fn update_window_rects(&self, rects: &[Rect]) -> Result<(), String> {
59         unsafe {
60             if sys::SDL_UpdateWindowSurfaceRects(self.1.context.raw, Rect::raw_slice(rects), rects.len() as c_int) == 0 {
61                 Ok(())
62             } else {
63                 Err(get_error())
64             }
65         }
66     }
67 
68     /// Gives up this WindowSurfaceRef, allowing to use the window freely again. Before being
69     /// destroyed, calls `update_window` one last time.
70     ///
71     /// If you don't want to `update_window` one last time, simply Drop this struct. However
72     /// beware, since the Surface will still be in the state you left it the next time you will
73     /// call `window.surface()` again.
finish(self) -> Result<(), String>74     pub fn finish(self) -> Result<(), String> {
75         self.update_window()
76     }
77 }
78 
79 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
80 pub enum GLProfile {
81     /// OpenGL core profile - deprecated functions are disabled
82     Core,
83     /// OpenGL compatibility profile - deprecated functions are allowed
84     Compatibility,
85     /// OpenGL ES profile - only a subset of the base OpenGL functionality is available
86     GLES,
87     /// Unknown profile - SDL will tend to return 0 if you ask when no particular profile
88     /// has been defined or requested.
89     Unknown(i32)
90 }
91 
92 trait GLAttrTypeUtil {
to_gl_value(self) -> i3293     fn to_gl_value(self) -> i32;
from_gl_value(value: i32) -> Self94     fn from_gl_value(value: i32) -> Self;
95 }
96 
97 impl GLAttrTypeUtil for u8 {
to_gl_value(self) -> i3298     fn to_gl_value(self) -> i32 { self as i32 }
from_gl_value(value: i32) -> u899     fn from_gl_value(value: i32) -> u8 { value as u8 }
100 }
101 
102 impl GLAttrTypeUtil for bool {
to_gl_value(self) -> i32103     fn to_gl_value(self) -> i32 { if self { 1 } else { 0 } }
from_gl_value(value: i32) -> bool104     fn from_gl_value(value: i32) -> bool { value != 0 }
105 }
106 
107 impl GLAttrTypeUtil for GLProfile {
to_gl_value(self) -> i32108     fn to_gl_value(self) -> i32 {
109         use self::GLProfile::*;
110 
111         match self {
112             Unknown(i) => i,
113             Core => 1,
114             Compatibility => 2,
115             GLES => 4,
116         }
117     }
from_gl_value(value: i32) -> GLProfile118     fn from_gl_value(value: i32) -> GLProfile {
119         use self::GLProfile::*;
120 
121         match value {
122             1 => Core,
123             2 => Compatibility,
124             4 => GLES,
125             i => Unknown(i),
126         }
127     }
128 }
129 
130 macro_rules! attrs {
131     (
132         $(($attr_name:ident, $set_property:ident, $get_property:ident, $t:ty, $doc:expr)),*
133     ) => (
134 
135         $(
136         #[doc = "**Sets** the attribute: "]
137         #[doc = $doc]
138         #[inline]
139         pub fn $set_property(&self, value: $t) {
140             gl_set_attribute!($attr_name, value.to_gl_value());
141         }
142 
143         #[doc = "**Gets** the attribute: "]
144         #[doc = $doc]
145         #[inline]
146         pub fn $get_property(&self) -> $t {
147             let value = gl_get_attribute!($attr_name);
148             GLAttrTypeUtil::from_gl_value(value)
149         }
150         )*
151     );
152 }
153 
154 /// OpenGL context getters and setters
155 ///
156 /// # Example
157 /// ```no_run
158 /// use sdl2::video::GLProfile;
159 ///
160 /// let sdl_context = sdl2::init().unwrap();
161 /// let video_subsystem = sdl_context.video().unwrap();
162 /// let gl_attr = video_subsystem.gl_attr();
163 ///
164 /// // Don't use deprecated OpenGL functions
165 /// gl_attr.set_context_profile(GLProfile::Core);
166 ///
167 /// // Set the context into debug mode
168 /// gl_attr.set_context_flags().debug().set();
169 ///
170 /// // Set the OpenGL context version (OpenGL 3.2)
171 /// gl_attr.set_context_version(3, 2);
172 ///
173 /// // Enable anti-aliasing
174 /// gl_attr.set_multisample_buffers(1);
175 /// gl_attr.set_multisample_samples(4);
176 ///
177 /// let window = video_subsystem.window("rust-sdl2 demo: Video", 800, 600).opengl().build().unwrap();
178 ///
179 /// // Yes, we're still using the Core profile
180 /// assert_eq!(gl_attr.context_profile(), GLProfile::Core);
181 /// // ... and we're still using OpenGL 3.2
182 /// assert_eq!(gl_attr.context_version(), (3, 2));
183 /// ```
184 pub mod gl_attr {
185     use crate::sys;
186     use crate::get_error;
187     use std::marker::PhantomData;
188     use super::{GLProfile, GLAttrTypeUtil};
189 
190     /// OpenGL context getters and setters. Obtain with `VideoSubsystem::gl_attr()`.
191     pub struct GLAttr<'a> {
192         _marker: PhantomData<&'a crate::VideoSubsystem>
193     }
194 
195     impl crate::VideoSubsystem {
196         /// Obtains access to the OpenGL window attributes.
gl_attr(&self) -> GLAttr197         pub fn gl_attr(&self) -> GLAttr {
198             GLAttr {
199                 _marker: PhantomData
200             }
201         }
202     }
203 
204     macro_rules! gl_set_attribute {
205         ($attr:ident, $value:expr) => ({
206             let result = unsafe {
207                 sys::SDL_GL_SetAttribute(sys::SDL_GLattr::$attr, $value)
208             };
209 
210             if result != 0 {
211                 // Panic and print the attribute that failed.
212                 panic!("couldn't set attribute {}: {}", stringify!($attr), get_error());
213             }
214         })
215     }
216 
217     macro_rules! gl_get_attribute {
218         ($attr:ident) => ({
219             let mut value = 0;
220             let result = unsafe {
221                 sys::SDL_GL_GetAttribute(sys::SDL_GLattr::$attr, &mut value)
222             };
223             if result != 0 {
224                 // Panic and print the attribute that failed.
225                 panic!("couldn't get attribute {}: {}", stringify!($attr), get_error());
226             }
227             value
228         })
229     }
230 
231     impl<'a> GLAttr<'a> {
232 
233     // Note: Wish I could avoid the redundancy of set_property and property (without namespacing into new modules),
234     // but Rust's `concat_idents!` macro isn't stable.
235     attrs! {
236         (SDL_GL_RED_SIZE, set_red_size, red_size, u8,
237             "the minimum number of bits for the red channel of the color buffer; defaults to 3"),
238 
239         (SDL_GL_GREEN_SIZE, set_green_size, green_size, u8,
240             "the minimum number of bits for the green channel of the color buffer; defaults to 3"),
241 
242         (SDL_GL_BLUE_SIZE, set_blue_size, blue_size, u8,
243             "the minimum number of bits for the blue channel of the color buffer; defaults to 2"),
244 
245         (SDL_GL_ALPHA_SIZE, set_alpha_size, alpha_size, u8,
246             "the minimum number of bits for the alpha channel of the color buffer; defaults to 0"),
247 
248         (SDL_GL_BUFFER_SIZE, set_buffer_size, buffer_size, u8,
249             "the minimum number of bits for frame buffer size; defaults to 0"),
250 
251         (SDL_GL_DOUBLEBUFFER, set_double_buffer, double_buffer, bool,
252             "whether the output is single or double buffered; defaults to double buffering on"),
253 
254         (SDL_GL_DEPTH_SIZE, set_depth_size, depth_size, u8,
255             "the minimum number of bits in the depth buffer; defaults to 16"),
256 
257         (SDL_GL_STENCIL_SIZE, set_stencil_size, stencil_size, u8,
258             "the minimum number of bits in the stencil buffer; defaults to 0"),
259 
260         (SDL_GL_ACCUM_RED_SIZE, set_accum_red_size, accum_red_size, u8,
261             "the minimum number of bits for the red channel of the accumulation buffer; defaults to 0"),
262 
263         (SDL_GL_ACCUM_GREEN_SIZE, set_accum_green_size, accum_green_size, u8,
264             "the minimum number of bits for the green channel of the accumulation buffer; defaults to 0"),
265 
266         (SDL_GL_ACCUM_BLUE_SIZE, set_accum_blue_size, accum_blue_size, u8,
267             "the minimum number of bits for the blue channel of the accumulation buffer; defaults to 0"),
268 
269         (SDL_GL_ACCUM_ALPHA_SIZE, set_accum_alpha_size, accum_alpha_size, u8,
270             "the minimum number of bits for the alpha channel of the accumulation buffer; defaults to 0"),
271 
272         (SDL_GL_STEREO, set_stereo, stereo, bool,
273             "whether the output is stereo 3D; defaults to off"),
274 
275         (SDL_GL_MULTISAMPLEBUFFERS, set_multisample_buffers, multisample_buffers, u8,
276             "the number of buffers used for multisample anti-aliasing; defaults to 0"),
277 
278         (SDL_GL_MULTISAMPLESAMPLES, set_multisample_samples, multisample_samples, u8,
279             "the number of samples used around the current pixel used for multisample anti-aliasing; defaults to 0"),
280 
281         (SDL_GL_ACCELERATED_VISUAL, set_accelerated_visual, accelerated_visual, bool,
282             "whether to require hardware acceleration; false to force software rendering; defaults to allow either"),
283 
284         (SDL_GL_CONTEXT_MAJOR_VERSION, set_context_major_version, context_major_version, u8,
285             "OpenGL context major version"),
286 
287         (SDL_GL_CONTEXT_MINOR_VERSION, set_context_minor_version, context_minor_version, u8,
288             "OpenGL context minor version"),
289 
290         (SDL_GL_CONTEXT_PROFILE_MASK, set_context_profile, context_profile, GLProfile,
291             "type of GL context (Core, Compatibility, ES)"),
292 
293         (SDL_GL_SHARE_WITH_CURRENT_CONTEXT, set_share_with_current_context, share_with_current_context, bool,
294             "OpenGL context sharing; defaults to false"),
295 
296         (SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, set_framebuffer_srgb_compatible, framebuffer_srgb_compatible, bool,
297             "requests sRGB capable visual; defaults to false (>= SDL 2.0.1)")
298     }
299 
300     /// **Sets** the OpenGL context major and minor versions.
301     #[inline]
set_context_version(&self, major: u8, minor: u8)302     pub fn set_context_version(&self, major: u8, minor: u8) {
303         self.set_context_major_version(major);
304         self.set_context_minor_version(minor);
305     }
306 
307     /// **Gets** the OpenGL context major and minor versions as a tuple.
308     #[inline]
context_version(&self) -> (u8, u8)309     pub fn context_version(&self) -> (u8, u8) {
310         (self.context_major_version(), self.context_minor_version())
311     }
312 
313     }
314 
315     /// The type that allows you to build a OpenGL context configuration.
316     pub struct ContextFlagsBuilder<'a> {
317         flags: i32,
318         _marker: PhantomData<&'a crate::VideoSubsystem>
319     }
320 
321     impl<'a> ContextFlagsBuilder<'a> {
322         /// Finishes the builder and applies the GL context flags to the GL context.
323         #[inline]
set(&self)324         pub fn set(&self) {
325             gl_set_attribute!(SDL_GL_CONTEXT_FLAGS, self.flags);
326         }
327 
328         /// Sets the context into "debug" mode.
329         #[inline]
debug(&mut self) -> &mut ContextFlagsBuilder<'a>330         pub fn debug(&mut self) -> &mut ContextFlagsBuilder<'a> {
331             self.flags |= 0x0001;
332             self
333         }
334 
335         /// Sets the context into "forward compatible" mode.
336         #[inline]
forward_compatible(&mut self) -> &mut ContextFlagsBuilder<'a>337         pub fn forward_compatible(&mut self) -> &mut ContextFlagsBuilder<'a> {
338             self.flags |= 0x0002;
339             self
340         }
341 
342         #[inline]
robust_access(&mut self) -> &mut ContextFlagsBuilder<'a>343         pub fn robust_access(&mut self) -> &mut ContextFlagsBuilder<'a> {
344             self.flags |= 0x0004;
345             self
346         }
347 
348         #[inline]
reset_isolation(&mut self) -> &mut ContextFlagsBuilder<'a>349         pub fn reset_isolation(&mut self) -> &mut ContextFlagsBuilder<'a> {
350             self.flags |= 0x0008;
351             self
352         }
353     }
354 
355     pub struct ContextFlags {
356         flags: i32
357     }
358 
359     impl ContextFlags {
360         #[inline]
has_debug(&self) -> bool361         pub fn has_debug(&self) -> bool { self.flags & 0x0001 != 0 }
362 
363         #[inline]
has_forward_compatible(&self) -> bool364         pub fn has_forward_compatible(&self) -> bool { self.flags & 0x0002 != 0 }
365 
366         #[inline]
has_robust_access(&self) -> bool367         pub fn has_robust_access(&self) -> bool { self.flags & 0x0004 != 0 }
368 
369         #[inline]
has_reset_isolation(&self) -> bool370         pub fn has_reset_isolation(&self) -> bool { self.flags & 0x0008 != 0 }
371     }
372 
373     impl<'a> GLAttr<'a> {
374 
375     /// **Sets** any combination of OpenGL context configuration flags.
376     ///
377     /// Note that calling this will reset any existing context flags.
378     ///
379     /// # Example
380     /// ```no_run
381     /// let sdl_context = sdl2::init().unwrap();
382     /// let video_subsystem = sdl_context.video().unwrap();
383     /// let gl_attr = video_subsystem.gl_attr();
384     ///
385     /// // Sets the GL context into debug mode.
386     /// gl_attr.set_context_flags().debug().set();
387     /// ```
set_context_flags(&self) -> ContextFlagsBuilder388     pub fn set_context_flags(&self) -> ContextFlagsBuilder {
389         ContextFlagsBuilder {
390             flags: 0,
391             _marker: PhantomData
392         }
393     }
394 
395     /// **Gets** the applied OpenGL context configuration flags.
396     ///
397     /// # Example
398     /// ```no_run
399     /// let sdl_context = sdl2::init().unwrap();
400     /// let video_subsystem = sdl_context.video().unwrap();
401     /// let gl_attr = video_subsystem.gl_attr();
402     ///
403     /// // Is the GL context in debug mode?
404     /// if gl_attr.context_flags().has_debug() {
405     ///     println!("Debug mode");
406     /// }
407     /// ```
context_flags(&self) -> ContextFlags408     pub fn context_flags(&self) -> ContextFlags {
409         let flags = gl_get_attribute!(SDL_GL_CONTEXT_FLAGS);
410 
411         ContextFlags {
412             flags: flags
413         }
414     }
415 
416     }
417 }
418 
419 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
420 pub struct DisplayMode {
421     pub format: PixelFormatEnum,
422     pub w: i32,
423     pub h: i32,
424     pub refresh_rate: i32
425 }
426 
427 impl DisplayMode {
new(format: PixelFormatEnum, w: i32, h: i32, refresh_rate: i32) -> DisplayMode428     pub fn new(format: PixelFormatEnum, w: i32, h: i32, refresh_rate: i32) -> DisplayMode {
429         DisplayMode {
430             format: format,
431             w: w,
432             h: h,
433             refresh_rate: refresh_rate
434         }
435     }
436 
from_ll(raw: &sys::SDL_DisplayMode) -> DisplayMode437     pub fn from_ll(raw: &sys::SDL_DisplayMode) -> DisplayMode {
438         DisplayMode::new(
439             PixelFormatEnum::from_u32(raw.format as u32).unwrap_or(PixelFormatEnum::Unknown),
440             raw.w as i32,
441             raw.h as i32,
442             raw.refresh_rate as i32
443         )
444     }
445 
to_ll(&self) -> sys::SDL_DisplayMode446     pub fn to_ll(&self) -> sys::SDL_DisplayMode {
447         sys::SDL_DisplayMode {
448             format: self.format as uint32_t,
449             w: self.w as c_int,
450             h: self.h as c_int,
451             refresh_rate: self.refresh_rate as c_int,
452             driverdata: ptr::null_mut()
453         }
454     }
455 }
456 
457 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
458 pub enum FullscreenType {
459     Off = 0,
460     True = 0x00_00_00_01,
461     Desktop = 0x00_00_10_01,
462 }
463 
464 impl FullscreenType {
from_window_flags(window_flags:u32) -> FullscreenType465     pub fn from_window_flags(window_flags:u32) -> FullscreenType {
466         if window_flags & FullscreenType::Desktop as u32 == FullscreenType::Desktop as u32 {
467             FullscreenType::Desktop
468         } else if window_flags & FullscreenType::True as u32 == FullscreenType::True as u32  {
469             FullscreenType::True
470         } else {
471             FullscreenType::Off
472         }
473     }
474 }
475 
476 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
477 pub enum WindowPos {
478     Undefined,
479     Centered,
480     Positioned(i32)
481 }
482 
to_ll_windowpos(pos: WindowPos) -> c_int483 fn to_ll_windowpos (pos: WindowPos) -> c_int {
484     match pos {
485         WindowPos::Undefined => sys::SDL_WINDOWPOS_UNDEFINED_MASK as c_int,
486         WindowPos::Centered => sys::SDL_WINDOWPOS_CENTERED_MASK as c_int,
487         WindowPos::Positioned(x) => x as c_int
488     }
489 }
490 
491 pub struct GLContext {
492     raw: sys::SDL_GLContext
493 }
494 
495 impl Drop for GLContext {
drop(&mut self)496     fn drop(&mut self) {
497         unsafe {
498             sys::SDL_GL_DeleteContext(self.raw)
499         }
500     }
501 }
502 
503 impl GLContext {
504     /// Returns true if the OpenGL context is the current one in the thread.
is_current(&self) -> bool505     pub fn is_current(&self) -> bool {
506         let current_raw = unsafe { sys::SDL_GL_GetCurrentContext() };
507         self.raw == current_raw
508     }
509 }
510 
511 /// Holds a `SDL_Window`
512 ///
513 /// When the `WindowContext` is dropped, it destroys the `SDL_Window`
514 pub struct WindowContext {
515     subsystem: VideoSubsystem,
516     raw: *mut sys::SDL_Window,
517 }
518 
519 impl Drop for WindowContext {
520     #[inline]
drop(&mut self)521     fn drop(&mut self) {
522         unsafe { sys::SDL_DestroyWindow(self.raw) };
523     }
524 }
525 
526 impl WindowContext {
527     #[inline]
528     /// Unsafe if the `*mut SDL_Window` is used after the `WindowContext` is dropped
from_ll(subsystem: VideoSubsystem, raw: *mut sys::SDL_Window) -> WindowContext529     pub unsafe fn from_ll(subsystem: VideoSubsystem, raw: *mut sys::SDL_Window) -> WindowContext {
530         WindowContext {
531             subsystem: subsystem.clone(),
532             raw: raw,
533         }
534     }
535 }
536 
537 /// Represents a setting for vsync/swap interval.
538 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
539 #[repr(i32)]
540 pub enum SwapInterval {
541     Immediate = 0,
542     VSync = 1,
543     LateSwapTearing = -1,
544 }
545 
546 impl From<i32> for SwapInterval {
from(i: i32) -> Self547     fn from(i: i32) -> Self {
548         match i {
549             -1 => SwapInterval::LateSwapTearing,
550             0  => SwapInterval::Immediate,
551             1  => SwapInterval::VSync,
552             other => panic!("Invalid value for SwapInterval: {}; valid values are -1, 0, 1", other),
553         }
554     }
555 }
556 
557 /// Represents the "shell" of a `Window`.
558 ///
559 /// You can set get and set many of the `SDL_Window` properties (i.e., border, size, `PixelFormat`, etc)
560 ///
561 /// However, you cannot directly access the pixels of the `Window`.
562 /// It needs to be converted to a `Canvas` to access the rendering functions.
563 ///
564 /// Note: If a `Window` goes out of scope but it cloned its context,
565 /// then the `SDL_Window` will not be destroyed until there are no more references to the `WindowContext`.
566 /// This may happen when a `TextureCreator<Window>` outlives the `Canvas<Window>`
567 pub struct Window {
568     context: Rc<WindowContext>,
569 }
570 
571 impl From<WindowContext> for Window {
from(context: WindowContext) -> Window572     fn from(context: WindowContext) -> Window {
573         Window { context: Rc::new(context) }
574     }
575 }
576 
577 impl_raw_accessors!(
578     (GLContext, sys::SDL_GLContext)
579 );
580 
581 impl VideoSubsystem {
582     /// Initializes a new `WindowBuilder`; a convenience method that calls `WindowBuilder::new()`.
window(&self, title: &str, width: u32, height: u32) -> WindowBuilder583     pub fn window(&self, title: &str, width: u32, height: u32) -> WindowBuilder {
584         WindowBuilder::new(self, title, width, height)
585     }
586 
current_video_driver(&self) -> &'static str587     pub fn current_video_driver(&self) -> &'static str {
588         use std::str;
589 
590         unsafe {
591             let buf = sys::SDL_GetCurrentVideoDriver();
592             assert!(!buf.is_null());
593 
594             str::from_utf8(CStr::from_ptr(buf as *const _).to_bytes()).unwrap()
595         }
596     }
597 
num_video_displays(&self) -> Result<i32, String>598     pub fn num_video_displays(&self) -> Result<i32, String> {
599         let result = unsafe { sys::SDL_GetNumVideoDisplays() };
600         if result < 0 {
601             Err(get_error())
602         } else {
603             Ok(result as i32)
604         }
605     }
606 
607     /// Get the name of the display at the index `display_name`.
608     ///
609     /// Will return an error if the index is out of bounds or if SDL experienced a failure; inspect
610     /// the returned string for further info.
display_name(&self, display_index: i32) -> Result<String, String>611     pub fn display_name(&self, display_index: i32) -> Result<String, String> {
612         unsafe {
613             let display = sys::SDL_GetDisplayName(display_index as c_int);
614             if display.is_null() {
615                 Err(get_error())
616             } else {
617                 Ok(CStr::from_ptr(display as *const _).to_str().unwrap().to_owned())
618             }
619         }
620     }
621 
display_bounds(&self, display_index: i32) -> Result<Rect, String>622     pub fn display_bounds(&self, display_index: i32) -> Result<Rect, String> {
623         let mut out = unsafe { mem::uninitialized() };
624         let result = unsafe { sys::SDL_GetDisplayBounds(display_index as c_int, &mut out) == 0 };
625 
626         if result {
627             Ok(Rect::from_ll(out))
628         } else {
629             Err(get_error())
630         }
631     }
632 
num_display_modes(&self, display_index: i32) -> Result<i32, String>633     pub fn num_display_modes(&self, display_index: i32) -> Result<i32, String> {
634         let result = unsafe { sys::SDL_GetNumDisplayModes(display_index as c_int) };
635         if result < 0 {
636             Err(get_error())
637         } else {
638             Ok(result as i32)
639         }
640     }
641 
display_mode(&self, display_index: i32, mode_index: i32) -> Result<DisplayMode, String>642     pub fn display_mode(&self, display_index: i32, mode_index: i32) -> Result<DisplayMode, String> {
643         let mut dm = unsafe { mem::uninitialized() };
644         let result = unsafe { sys::SDL_GetDisplayMode(display_index as c_int, mode_index as c_int, &mut dm) == 0};
645 
646         if result {
647             Ok(DisplayMode::from_ll(&dm))
648         } else {
649             Err(get_error())
650         }
651     }
652 
desktop_display_mode(&self, display_index: i32) -> Result<DisplayMode, String>653     pub fn desktop_display_mode(&self, display_index: i32) -> Result<DisplayMode, String> {
654         let mut dm = unsafe { mem::uninitialized() };
655         let result = unsafe { sys::SDL_GetDesktopDisplayMode(display_index as c_int, &mut dm) == 0};
656 
657         if result {
658             Ok(DisplayMode::from_ll(&dm))
659         } else {
660             Err(get_error())
661         }
662     }
663 
current_display_mode(&self, display_index: i32) -> Result<DisplayMode, String>664     pub fn current_display_mode(&self, display_index: i32) -> Result<DisplayMode, String> {
665         let mut dm = unsafe { mem::uninitialized() };
666         let result = unsafe { sys::SDL_GetCurrentDisplayMode(display_index as c_int, &mut dm) == 0};
667 
668         if result {
669             Ok(DisplayMode::from_ll(&dm))
670         } else {
671             Err(get_error())
672         }
673     }
674 
closest_display_mode(&self, display_index: i32, mode: &DisplayMode) -> Result<DisplayMode, String>675     pub fn closest_display_mode(&self, display_index: i32, mode: &DisplayMode) -> Result<DisplayMode, String> {
676         let input = mode.to_ll();
677         let mut dm = unsafe { mem::uninitialized() };
678 
679         let result = unsafe { sys::SDL_GetClosestDisplayMode(display_index as c_int, &input, &mut dm) };
680 
681         if result.is_null() {
682             Err(get_error())
683         } else {
684             Ok(DisplayMode::from_ll(&dm))
685         }
686     }
687 
688     /// Return a triplet `(ddpi, hdpi, vdpi)` containing the diagonal, horizontal and vertical
689     /// dots/pixels-per-inch of a display
display_dpi(&self, display_index: i32) -> Result<(f32, f32, f32), String>690     pub fn display_dpi(&self, display_index: i32) -> Result<(f32, f32, f32), String> {
691         let mut ddpi = 0.0;
692         let mut hdpi = 0.0;
693         let mut vdpi = 0.0;
694         let result = unsafe { sys::SDL_GetDisplayDPI(display_index as c_int, &mut ddpi, &mut hdpi, &mut vdpi) };
695         if result < 0 {
696             Err(get_error())
697         } else {
698             Ok((ddpi, hdpi, vdpi))
699         }
700     }
701 
is_screen_saver_enabled(&self) -> bool702     pub fn is_screen_saver_enabled(&self) -> bool {
703         unsafe { sys::SDL_IsScreenSaverEnabled() == sys::SDL_bool::SDL_TRUE }
704     }
705 
enable_screen_saver(&self)706     pub fn enable_screen_saver(&self) {
707         unsafe { sys::SDL_EnableScreenSaver() }
708     }
709 
disable_screen_saver(&self)710     pub fn disable_screen_saver(&self) {
711         unsafe { sys::SDL_DisableScreenSaver() }
712     }
713 
714     /// Loads the default OpenGL library.
715     ///
716     /// This should be done after initializing the video driver, but before creating any OpenGL windows.
717     /// If no OpenGL library is loaded, the default library will be loaded upon creation of the first OpenGL window.
718     ///
719     /// If a different library is already loaded, this function will return an error.
gl_load_library_default(&self) -> Result<(), String>720     pub fn gl_load_library_default(&self) -> Result<(), String> {
721         unsafe {
722             if sys::SDL_GL_LoadLibrary(ptr::null()) == 0 {
723                 Ok(())
724             } else {
725                 Err(get_error())
726             }
727         }
728     }
729 
730     /// Loads the OpenGL library using a platform-dependent OpenGL library name (usually a file path).
731     ///
732     /// This should be done after initializing the video driver, but before creating any OpenGL windows.
733     /// If no OpenGL library is loaded, the default library will be loaded upon creation of the first OpenGL window.
734     ///
735     /// If a different library is already loaded, this function will return an error.
gl_load_library<P: AsRef<::std::path::Path>>(&self, path: P) -> Result<(), String>736     pub fn gl_load_library<P: AsRef<::std::path::Path>>(&self, path: P) -> Result<(), String> {
737         unsafe {
738             // TODO: use OsStr::to_cstring() once it's stable
739             let path = CString::new(path.as_ref().to_str().unwrap()).unwrap();
740             if sys::SDL_GL_LoadLibrary(path.as_ptr() as *const c_char) == 0 {
741                 Ok(())
742             } else {
743                 Err(get_error())
744             }
745         }
746     }
747 
748     /// Unloads the current OpenGL library.
749     ///
750     /// To completely unload the library, this should be called for every successful load of the
751     /// OpenGL library.
gl_unload_library(&self)752     pub fn gl_unload_library(&self) {
753         unsafe { sys::SDL_GL_UnloadLibrary(); }
754     }
755 
756     /// Gets the pointer to the named OpenGL function.
757     ///
758     /// This is useful for OpenGL wrappers such as [`gl-rs`](https://github.com/bjz/gl-rs).
gl_get_proc_address(&self, procname: &str) -> *const ()759     pub fn gl_get_proc_address(&self, procname: &str) -> *const () {
760         match CString::new(procname) {
761             Ok(procname) => unsafe { sys::SDL_GL_GetProcAddress(procname.as_ptr() as *const c_char) as *const () },
762             // string contains a nul byte - it won't match anything.
763             Err(_) => ptr::null()
764         }
765     }
766 
gl_extension_supported(&self, extension: &str) -> bool767     pub fn gl_extension_supported(&self, extension: &str) -> bool {
768         match CString::new(extension) {
769             Ok(extension) => unsafe { sys::SDL_GL_ExtensionSupported(extension.as_ptr() as *const c_char) != sys::SDL_bool::SDL_FALSE },
770             // string contains a nul byte - it won't match anything.
771             Err(_) => false
772         }
773     }
774 
gl_get_current_window_id(&self) -> Result<u32, String>775     pub fn gl_get_current_window_id(&self) -> Result<u32, String> {
776         let raw = unsafe { sys::SDL_GL_GetCurrentWindow() };
777         if raw.is_null() {
778             Err(get_error())
779         } else {
780             let id = unsafe { sys::SDL_GetWindowID(raw) };
781             Ok(id)
782         }
783     }
784 
785     /// Releases the thread's current OpenGL context, i.e. sets the current OpenGL context to nothing.
gl_release_current_context(&self) -> Result<(), String>786     pub fn gl_release_current_context(&self) -> Result<(), String> {
787         let result = unsafe { sys::SDL_GL_MakeCurrent(ptr::null_mut(), ptr::null_mut()) };
788 
789         if result == 0 {
790             Ok(())
791         } else {
792             Err(get_error())
793         }
794     }
795 
gl_set_swap_interval<S: Into<SwapInterval>>(&self, interval: S) -> Result<(), String>796     pub fn gl_set_swap_interval<S: Into<SwapInterval>>(&self, interval: S) -> Result<(), String> {
797         let result = unsafe { sys::SDL_GL_SetSwapInterval(interval.into() as c_int) };
798         if result == 0{
799             Ok(())
800         } else {
801             Err(get_error())
802         }
803     }
804 
gl_get_swap_interval(&self) -> SwapInterval805     pub fn gl_get_swap_interval(&self) -> SwapInterval {
806         unsafe {
807             let interval = sys::SDL_GL_GetSwapInterval() as i32;
808             assert!(interval == -1 || interval == 0 || interval == 1);
809             mem::transmute(interval)
810         }
811     }
812 
813     /// Loads the default Vulkan library.
814     ///
815     /// This should be done after initializing the video driver, but before creating any Vulkan windows.
816     /// If no Vulkan library is loaded, the default library will be loaded upon creation of the first Vulkan window.
817     ///
818     /// If a different library is already loaded, this function will return an error.
vulkan_load_library_default(&self) -> Result<(), String>819     pub fn vulkan_load_library_default(&self) -> Result<(), String> {
820         unsafe {
821             if sys::SDL_Vulkan_LoadLibrary(ptr::null()) == 0 {
822                 Ok(())
823             } else {
824                 Err(get_error())
825             }
826         }
827     }
828 
829     /// Loads the Vulkan library using a platform-dependent Vulkan library name (usually a file path).
830     ///
831     /// This should be done after initializing the video driver, but before creating any Vulkan windows.
832     /// If no Vulkan library is loaded, the default library will be loaded upon creation of the first Vulkan window.
833     ///
834     /// If a different library is already loaded, this function will return an error.
vulkan_load_library<P: AsRef<::std::path::Path>>(&self, path: P) -> Result<(), String>835     pub fn vulkan_load_library<P: AsRef<::std::path::Path>>(&self, path: P) -> Result<(), String> {
836         unsafe {
837             // TODO: use OsStr::to_cstring() once it's stable
838             let path = CString::new(path.as_ref().to_str().unwrap()).unwrap();
839             if sys::SDL_Vulkan_LoadLibrary(path.as_ptr() as *const c_char) == 0 {
840                 Ok(())
841             } else {
842                 Err(get_error())
843             }
844         }
845     }
846 
847     /// Unloads the current Vulkan library.
848     ///
849     /// To completely unload the library, this should be called for every successful load of the
850     /// Vulkan library.
vulkan_unload_library(&self)851     pub fn vulkan_unload_library(&self) {
852         unsafe { sys::SDL_Vulkan_UnloadLibrary(); }
853     }
854 
855     /// Gets the pointer to the
856     /// [`vkGetInstanceProcAddr`](https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkGetInstanceProcAddr.html)
857     /// Vulkan function. This function can be called to retrieve the address of other Vulkan
858     /// functions.
vulkan_get_proc_address_function(&self) -> Result<*const (), String>859     pub fn vulkan_get_proc_address_function(&self) -> Result<*const (), String> {
860         let result = unsafe { sys::SDL_Vulkan_GetVkGetInstanceProcAddr() as *const () };
861         if result.is_null() {
862             Err(get_error())
863         } else {
864             Ok(result)
865         }
866     }
867 }
868 
869 #[derive(Debug)]
870 pub enum WindowBuildError {
871     HeightOverflows(u32),
872     WidthOverflows(u32),
873     InvalidTitle(NulError),
874     SdlError(String),
875 }
876 
877 impl fmt::Display for WindowBuildError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result878     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
879         use self::WindowBuildError::*;
880 
881         match *self {
882             HeightOverflows(h) => write!(f, "Window height ({}) is too high.", h),
883             WidthOverflows(w) => write!(f, "Window width ({}) is too high.", w),
884             InvalidTitle(ref e) => write!(f, "Invalid window title: {}", e),
885             SdlError(ref e) => write!(f, "SDL error: {}", e),
886         }
887     }
888 }
889 
890 impl Error for WindowBuildError {
description(&self) -> &str891     fn description(&self) -> &str {
892         use self::WindowBuildError::*;
893 
894         match *self {
895             HeightOverflows(_) => "window height overflow",
896             WidthOverflows(_) => "window width overflow",
897             InvalidTitle(_) => "invalid window title",
898             SdlError(ref e) => e,
899         }
900     }
901 }
902 
903 /// The type that allows you to build windows.
904 #[derive(Debug)]
905 pub struct WindowBuilder {
906     title: String,
907     width: u32,
908     height: u32,
909     x: WindowPos,
910     y: WindowPos,
911     window_flags: u32,
912     /// The window builder cannot be built on a non-main thread, so prevent cross-threaded moves and references.
913     /// `!Send` and `!Sync`,
914     subsystem: VideoSubsystem
915 }
916 
917 impl WindowBuilder {
918     /// Initializes a new `WindowBuilder`.
new(v: &VideoSubsystem, title: &str, width: u32, height: u32) -> WindowBuilder919     pub fn new(v: &VideoSubsystem, title: &str, width: u32, height: u32) -> WindowBuilder {
920         WindowBuilder {
921             title: title.to_owned(),
922             width: width,
923             height: height,
924             x: WindowPos::Undefined,
925             y: WindowPos::Undefined,
926             window_flags: 0,
927             subsystem: v.clone()
928         }
929     }
930 
931     /// Builds the window.
build(&self) -> Result<Window, WindowBuildError>932     pub fn build(&self) -> Result<Window, WindowBuildError> {
933         use self::WindowBuildError::*;
934         let title = match CString::new(self.title.clone()) {
935             Ok(t) => t,
936             Err(err) => return Err(InvalidTitle(err)),
937         };
938         if self.width >= (1 << 31) {
939             return Err(WidthOverflows(self.width));
940         }
941         if self.height >= (1 << 31) {
942             return Err(HeightOverflows(self.width));
943         }
944 
945         let raw_width = self.width as c_int;
946         let raw_height = self.height as c_int;
947         unsafe {
948             let raw = sys::SDL_CreateWindow(
949                 title.as_ptr() as *const c_char,
950                 to_ll_windowpos(self.x),
951                 to_ll_windowpos(self.y),
952                 raw_width,
953                 raw_height,
954                 self.window_flags
955             );
956 
957             if raw.is_null() {
958                 Err(SdlError(get_error()))
959             } else {
960                 Ok(Window::from_ll(self.subsystem.clone(), raw))
961             }
962         }
963     }
964 
965     /// Gets the underlying window flags.
window_flags(&self) -> u32966     pub fn window_flags(&self) -> u32 { self.window_flags }
967 
968     /// Sets the underlying window flags.
969     /// This will effectively undo any previous build operations, excluding window size and position.
set_window_flags(&mut self, flags: u32) -> &mut WindowBuilder970     pub fn set_window_flags(&mut self, flags: u32) -> &mut WindowBuilder {
971         self.window_flags = flags;
972         self
973     }
974 
975     /// Sets the window position.
position(&mut self, x: i32, y: i32) -> &mut WindowBuilder976     pub fn position(&mut self, x: i32, y: i32) -> &mut WindowBuilder {
977         self.x = WindowPos::Positioned(x);
978         self.y = WindowPos::Positioned(y);
979         self
980     }
981 
982     /// Centers the window.
position_centered(&mut self) -> &mut WindowBuilder983     pub fn position_centered(&mut self) -> &mut WindowBuilder {
984         self.x = WindowPos::Centered;
985         self.y = WindowPos::Centered;
986         self
987     }
988 
989     /// Sets the window to fullscreen.
fullscreen(&mut self) -> &mut WindowBuilder990     pub fn fullscreen(&mut self) -> &mut WindowBuilder {
991         self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_FULLSCREEN as u32;
992         self
993     }
994 
995     /// Sets the window to fullscreen at the current desktop resolution.
fullscreen_desktop(&mut self) -> &mut WindowBuilder996     pub fn fullscreen_desktop(&mut self) -> &mut WindowBuilder {
997         self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_FULLSCREEN_DESKTOP as u32;
998         self
999     }
1000 
1001     /// Sets the window to be usable with an OpenGL context
opengl(&mut self) -> & mut WindowBuilder1002     pub fn opengl(&mut self) -> & mut WindowBuilder {
1003         self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_OPENGL as u32;
1004         self
1005     }
1006 
1007     /// Sets the window to be usable with a Vulkan instance
vulkan(&mut self) -> & mut WindowBuilder1008     pub fn vulkan(&mut self) -> & mut WindowBuilder {
1009         self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_VULKAN as u32;
1010         self
1011     }
1012 
1013     /// Hides the window.
hidden(&mut self) -> &mut WindowBuilder1014     pub fn hidden(&mut self) -> &mut WindowBuilder {
1015         self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_HIDDEN as u32;
1016         self
1017     }
1018 
1019     /// Removes the window decoration.
borderless(&mut self) -> &mut WindowBuilder1020     pub fn borderless(&mut self) -> &mut WindowBuilder {
1021         self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_BORDERLESS as u32;
1022         self
1023     }
1024 
1025     /// Sets the window to be resizable.
resizable(&mut self) -> &mut WindowBuilder1026     pub fn resizable(&mut self) -> &mut WindowBuilder {
1027         self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_RESIZABLE as u32;
1028         self
1029     }
1030 
1031     /// Minimizes the window.
minimized(&mut self) -> &mut WindowBuilder1032     pub fn minimized(&mut self) -> &mut WindowBuilder {
1033         self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_MINIMIZED as u32;
1034         self
1035     }
1036 
1037     /// Maximizes the window.
maximized(&mut self) -> &mut WindowBuilder1038     pub fn maximized(&mut self) -> &mut WindowBuilder {
1039         self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_MAXIMIZED as u32;
1040         self
1041     }
1042 
1043     /// Sets the window to have grabbed input focus.
input_grabbed(&mut self) -> &mut WindowBuilder1044     pub fn input_grabbed(&mut self) -> &mut WindowBuilder {
1045         self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_INPUT_GRABBED as u32;
1046         self
1047     }
1048 
1049     /// Creates the window in high-DPI mode if supported (>= SDL 2.0.1)
allow_highdpi(&mut self) -> &mut WindowBuilder1050     pub fn allow_highdpi(&mut self) -> &mut WindowBuilder {
1051         self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_ALLOW_HIGHDPI as u32;
1052         self
1053     }
1054 }
1055 
1056 impl From<Window> for CanvasBuilder {
from(window: Window) -> CanvasBuilder1057     fn from(window: Window) -> CanvasBuilder {
1058         CanvasBuilder::new(window)
1059     }
1060 }
1061 
1062 impl Window {
1063     #[inline]
raw(&self) -> *mut sys::SDL_Window1064     pub fn raw(&self) -> *mut sys::SDL_Window { self.context.raw }
1065 
1066     #[inline]
from_ll(subsystem: VideoSubsystem, raw: *mut sys::SDL_Window) -> Window1067     pub unsafe fn from_ll(subsystem: VideoSubsystem, raw: *mut sys::SDL_Window) -> Window {
1068         let context = WindowContext::from_ll(subsystem, raw);
1069         context.into()
1070     }
1071 
1072     #[inline]
1073     /// Create a new `Window` without taking ownership of the `WindowContext`
from_ref(context: Rc<WindowContext>) -> Window1074     pub unsafe fn from_ref(context: Rc<WindowContext>) -> Window {
1075         Window { context: context }
1076     }
1077 
1078     #[inline]
subsystem(&self) -> &VideoSubsystem1079     pub fn subsystem(&self) -> &VideoSubsystem { &self.context.subsystem }
1080 
1081     /// Initializes a new `CanvasBuilder`; a convenience method that calls `CanvasBuilder::new()`.
into_canvas(self) -> CanvasBuilder1082     pub fn into_canvas(self) -> CanvasBuilder {
1083         self.into()
1084     }
1085 
context(&self) -> Rc<WindowContext>1086     pub fn context(&self) -> Rc<WindowContext> {
1087         self.context.clone()
1088     }
1089 
id(&self) -> u321090     pub fn id(&self) -> u32 {
1091         unsafe { sys::SDL_GetWindowID(self.context.raw) }
1092     }
1093 
gl_create_context(&self) -> Result<GLContext, String>1094     pub fn gl_create_context(&self) -> Result<GLContext, String> {
1095         let result = unsafe { sys::SDL_GL_CreateContext(self.context.raw) };
1096         if result.is_null() {
1097             Err(get_error())
1098         } else {
1099             Ok(GLContext{ raw: result })
1100         }
1101     }
1102 
1103     /// Set the window's OpenGL context to the current context on the thread.
gl_set_context_to_current(&self) -> Result<(), String>1104     pub fn gl_set_context_to_current(&self) -> Result<(), String> {
1105         unsafe {
1106             let context_raw = sys::SDL_GL_GetCurrentContext();
1107 
1108             if !context_raw.is_null() && sys::SDL_GL_MakeCurrent(self.context.raw, context_raw) == 0 {
1109                 Ok(())
1110             } else {
1111                 Err(get_error())
1112             }
1113         }
1114     }
1115 
gl_make_current(&self, context: &GLContext) -> Result<(), String>1116     pub fn gl_make_current(&self, context: &GLContext) -> Result<(), String> {
1117         unsafe {
1118             if sys::SDL_GL_MakeCurrent(self.context.raw, context.raw) == 0 {
1119                 Ok(())
1120             } else {
1121                 Err(get_error())
1122             }
1123         }
1124     }
1125 
gl_swap_window(&self)1126     pub fn gl_swap_window(&self) {
1127         unsafe { sys::SDL_GL_SwapWindow(self.context.raw) }
1128     }
1129 
1130     /// Get the names of the Vulkan instance extensions needed to create a surface with `vulkan_create_surface`.
vulkan_instance_extensions(&self) -> Result<Vec<&'static str>, String>1131     pub fn vulkan_instance_extensions(&self) -> Result<Vec<&'static str>, String> {
1132         let mut count: c_uint = 0;
1133         if unsafe { sys::SDL_Vulkan_GetInstanceExtensions(self.context.raw, &mut count, ptr::null_mut()) } == sys::SDL_bool::SDL_FALSE {
1134             return Err(get_error());
1135         }
1136         let mut names: Vec<*const c_char> = vec![ptr::null(); count as usize];
1137         if unsafe { sys::SDL_Vulkan_GetInstanceExtensions(self.context.raw, &mut count, names.as_mut_ptr()) } == sys::SDL_bool::SDL_FALSE {
1138             return Err(get_error());
1139         }
1140         Ok(names.iter().map(|&val| unsafe { CStr::from_ptr(val) }.to_str().unwrap()).collect())
1141     }
1142 
1143     /// Create a Vulkan rendering surface for a window.
1144     ///
1145     /// The `VkInstance` must be created using a prior call to the
1146     /// [`vkCreateInstance`](https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCreateInstance.html)
1147     /// function in the Vulkan library.
vulkan_create_surface(&self, instance: VkInstance) -> Result<VkSurfaceKHR, String>1148     pub fn vulkan_create_surface(&self, instance: VkInstance) -> Result<VkSurfaceKHR, String> {
1149         let mut surface: VkSurfaceKHR = 0;
1150         if unsafe { sys::SDL_Vulkan_CreateSurface(self.context.raw, instance, &mut surface) } == sys::SDL_bool::SDL_FALSE {
1151             Err(get_error())
1152         } else {
1153             Ok(surface)
1154         }
1155     }
1156 
display_index(&self) -> Result<i32, String>1157     pub fn display_index(&self) -> Result<i32, String> {
1158         let result = unsafe { sys::SDL_GetWindowDisplayIndex(self.context.raw) };
1159         if result < 0 {
1160             Err(get_error())
1161         } else {
1162             Ok(result as i32)
1163         }
1164     }
1165 
set_display_mode<D>(&mut self, display_mode: D) -> Result<(), String> where D: Into<Option<DisplayMode>>1166     pub fn set_display_mode<D>(&mut self, display_mode: D) -> Result<(), String>
1167     where D: Into<Option<DisplayMode>>
1168     {
1169         unsafe {
1170             let result = sys::SDL_SetWindowDisplayMode(
1171                 self.context.raw,
1172                 match display_mode.into() {
1173                     Some(ref mode) => &mode.to_ll(),
1174                     None => ptr::null()
1175                 }
1176             );
1177             if result < 0 {
1178                 Err(get_error())
1179             } else {
1180                 Ok(())
1181             }
1182         }
1183     }
1184 
display_mode(&self) -> Result<DisplayMode, String>1185     pub fn display_mode(&self) -> Result<DisplayMode, String> {
1186         let mut dm = unsafe { mem::uninitialized() };
1187 
1188         let result = unsafe {
1189             sys::SDL_GetWindowDisplayMode(
1190                 self.context.raw,
1191                 &mut dm
1192             ) == 0
1193         };
1194 
1195         if result {
1196             Ok(DisplayMode::from_ll(&dm))
1197         } else {
1198             Err(get_error())
1199         }
1200     }
1201 
window_pixel_format(&self) -> PixelFormatEnum1202     pub fn window_pixel_format(&self) -> PixelFormatEnum {
1203         unsafe{ FromPrimitive::from_u64(sys::SDL_GetWindowPixelFormat(self.context.raw) as u64).unwrap() }
1204     }
1205 
window_flags(&self) -> u321206     pub fn window_flags(&self) -> u32 {
1207         unsafe {
1208             sys::SDL_GetWindowFlags(self.context.raw)
1209         }
1210     }
1211 
set_title(&mut self, title: &str) -> Result<(), NulError>1212     pub fn set_title(&mut self, title: &str) -> Result<(), NulError> {
1213         let title = r#try!(CString::new(title));
1214         Ok(unsafe {
1215             sys::SDL_SetWindowTitle(self.context.raw, title.as_ptr() as *const c_char);
1216         })
1217     }
1218 
title(&self) -> &str1219     pub fn title(&self) -> &str {
1220         unsafe {
1221             let buf = sys::SDL_GetWindowTitle(self.context.raw);
1222 
1223             // The window title must be encoded in UTF-8.
1224             CStr::from_ptr(buf as *const _).to_str().unwrap()
1225         }
1226     }
1227 
set_icon<S: AsRef<SurfaceRef>>(&mut self, icon: S)1228     pub fn set_icon<S: AsRef<SurfaceRef>>(&mut self, icon: S) {
1229         unsafe {
1230             sys::SDL_SetWindowIcon(self.context.raw, icon.as_ref().raw())
1231         }
1232     }
1233 
1234     //pub fn SDL_SetWindowData(window: *SDL_Window, name: *c_char, userdata: *c_void) -> *c_void; //TODO: Figure out what this does
1235     //pub fn SDL_GetWindowData(window: *SDL_Window, name: *c_char) -> *c_void;
1236 
set_position(&mut self, x: WindowPos, y: WindowPos)1237     pub fn set_position(&mut self, x: WindowPos, y: WindowPos) {
1238         unsafe {
1239             sys::SDL_SetWindowPosition(
1240                 self.context.raw, to_ll_windowpos(x), to_ll_windowpos(y)
1241             )
1242         }
1243     }
1244 
position(&self) -> (i32, i32)1245     pub fn position(&self) -> (i32, i32) {
1246         let mut x: c_int = 0;
1247         let mut y: c_int = 0;
1248         unsafe { sys::SDL_GetWindowPosition(self.context.raw, &mut x, &mut y) };
1249         (x as i32, y as i32)
1250     }
1251 
1252     /// Use this function to get the size of a window's borders (decorations) around the client area.
1253     ///
1254     /// # Remarks
1255     /// This function is only supported on X11, otherwise an error is returned.
border_size(&self) -> Result<(u16, u16, u16, u16), String>1256     pub fn border_size(&self) -> Result<(u16, u16, u16, u16), String> {
1257         let mut top: c_int = 0;
1258         let mut left: c_int = 0;
1259         let mut bottom: c_int = 0;
1260         let mut right: c_int = 0;
1261         let result = unsafe { sys::SDL_GetWindowBordersSize(self.context.raw, &mut top, &mut left, &mut bottom, &mut right) };
1262         if result < 0 {
1263             Err(get_error())
1264         } else {
1265             Ok((top as u16, left as u16, bottom as u16, right as u16))
1266         }
1267     }
1268 
set_size(&mut self, width: u32, height: u32) -> Result<(), IntegerOrSdlError>1269     pub fn set_size(&mut self, width: u32, height: u32)
1270             -> Result<(), IntegerOrSdlError> {
1271         let w = r#try!(validate_int(width, "width"));
1272         let h = r#try!(validate_int(height, "height"));
1273         Ok(unsafe {
1274             sys::SDL_SetWindowSize(self.context.raw, w, h)
1275         })
1276     }
1277 
size(&self) -> (u32, u32)1278     pub fn size(&self) -> (u32, u32) {
1279         let mut w: c_int = 0;
1280         let mut h: c_int = 0;
1281         unsafe { sys::SDL_GetWindowSize(self.context.raw, &mut w, &mut h) };
1282         (w as u32, h as u32)
1283     }
1284 
drawable_size(&self) -> (u32, u32)1285     pub fn drawable_size(&self) -> (u32, u32) {
1286         let mut w: c_int = 0;
1287         let mut h: c_int = 0;
1288         unsafe { sys::SDL_GL_GetDrawableSize(self.context.raw, &mut w, &mut h) };
1289         (w as u32, h as u32)
1290     }
1291 
vulkan_drawable_size(&self) -> (u32, u32)1292     pub fn vulkan_drawable_size(&self) -> (u32, u32) {
1293         let mut w: c_int = 0;
1294         let mut h: c_int = 0;
1295         unsafe { sys::SDL_Vulkan_GetDrawableSize(self.context.raw, &mut w, &mut h) };
1296         (w as u32, h as u32)
1297     }
1298 
set_minimum_size(&mut self, width: u32, height: u32) -> Result<(), IntegerOrSdlError>1299     pub fn set_minimum_size(&mut self, width: u32, height: u32)
1300             -> Result<(), IntegerOrSdlError> {
1301         let w = r#try!(validate_int(width, "width"));
1302         let h = r#try!(validate_int(height, "height"));
1303         Ok(unsafe {
1304             sys::SDL_SetWindowMinimumSize(self.context.raw, w, h)
1305         })
1306     }
1307 
minimum_size(&self) -> (u32, u32)1308     pub fn minimum_size(&self) -> (u32, u32) {
1309         let mut w: c_int = 0;
1310         let mut h: c_int = 0;
1311         unsafe { sys::SDL_GetWindowMinimumSize(self.context.raw, &mut w, &mut h) };
1312         (w as u32, h as u32)
1313     }
1314 
set_maximum_size(&mut self, width: u32, height: u32) -> Result<(), IntegerOrSdlError>1315     pub fn set_maximum_size(&mut self, width: u32, height: u32)
1316             -> Result<(), IntegerOrSdlError> {
1317         let w = r#try!(validate_int(width, "width"));
1318         let h = r#try!(validate_int(height, "height"));
1319         Ok(unsafe {
1320             sys::SDL_SetWindowMaximumSize(self.context.raw, w, h)
1321         })
1322     }
1323 
maximum_size(&self) -> (u32, u32)1324     pub fn maximum_size(&self) -> (u32, u32) {
1325         let mut w: c_int = 0;
1326         let mut h: c_int = 0;
1327         unsafe {
1328             sys::SDL_GetWindowMaximumSize(self.context.raw, &mut w, &mut h)
1329         };
1330         (w as u32, h as u32)
1331     }
1332 
set_bordered(&mut self, bordered: bool)1333     pub fn set_bordered(&mut self, bordered: bool) {
1334         unsafe {
1335             sys::SDL_SetWindowBordered(
1336                 self.context.raw,
1337                 if bordered { sys::SDL_bool::SDL_TRUE } else { sys::SDL_bool::SDL_FALSE }
1338             )
1339         }
1340     }
1341 
show(&mut self)1342     pub fn show(&mut self) {
1343         unsafe { sys::SDL_ShowWindow(self.context.raw) }
1344     }
1345 
hide(&mut self)1346     pub fn hide(&mut self) {
1347         unsafe { sys::SDL_HideWindow(self.context.raw) }
1348     }
1349 
raise(&mut self)1350     pub fn raise(&mut self) {
1351         unsafe { sys::SDL_RaiseWindow(self.context.raw) }
1352     }
1353 
maximize(&mut self)1354     pub fn maximize(&mut self) {
1355         unsafe { sys::SDL_MaximizeWindow(self.context.raw) }
1356     }
1357 
minimize(&mut self)1358     pub fn minimize(&mut self) {
1359         unsafe { sys::SDL_MinimizeWindow(self.context.raw) }
1360     }
1361 
restore(&mut self)1362     pub fn restore(&mut self) {
1363         unsafe { sys::SDL_RestoreWindow(self.context.raw) }
1364     }
1365 
fullscreen_state(&self) -> FullscreenType1366     pub fn fullscreen_state(&self) -> FullscreenType {
1367         FullscreenType::from_window_flags(self.window_flags())
1368     }
1369 
set_fullscreen(&mut self, fullscreen_type: FullscreenType) -> Result<(), String>1370     pub fn set_fullscreen(&mut self, fullscreen_type: FullscreenType)
1371             -> Result<(), String> {
1372         unsafe {
1373             let result = sys::SDL_SetWindowFullscreen(
1374                 self.context.raw, fullscreen_type as uint32_t
1375             );
1376             if result == 0 {
1377                 Ok(())
1378             } else {
1379                 Err(get_error())
1380             }
1381         }
1382     }
1383 
1384     /// Returns a WindowSurfaceRef, which can be used like a regular Surface. This is an
1385     /// alternative way to the Renderer (Canvas) way to modify pixels directly in the Window.
1386     ///
1387     /// For this to happen, simply create a `WindowSurfaceRef` via this method, use the underlying
1388     /// Surface however you like, and when the changes of the Surface must be applied to the
1389     /// screen, call `update_window` if you intend to keep using the WindowSurfaceRef afterwards,
1390     /// or `finish` if you don't intend to use it afterwards.
1391     ///
1392     /// The Renderer way is of course much more flexible and recommended; even though you only want
1393     /// to support Software Rendering (which is what using Surface is), you can still create a
1394     /// Renderer which renders in a Software-based manner, so try to rely on a Renderer as much as
1395     /// possible !
surface<'a>(&'a self, _e: &'a EventPump) -> Result<WindowSurfaceRef<'a>, String>1396     pub fn surface<'a>(&'a self, _e: &'a EventPump) -> Result<WindowSurfaceRef<'a>, String> {
1397         let raw = unsafe { sys::SDL_GetWindowSurface(self.context.raw) };
1398 
1399         if raw.is_null() {
1400             Err(get_error())
1401         } else {
1402             let surface_ref = unsafe { SurfaceRef::from_ll_mut(raw) };
1403             Ok(WindowSurfaceRef(surface_ref, self))
1404         }
1405     }
1406 
set_grab(&mut self, grabbed: bool)1407     pub fn set_grab(&mut self, grabbed: bool) {
1408         unsafe { sys::SDL_SetWindowGrab(self.context.raw, if grabbed { sys::SDL_bool::SDL_TRUE } else { sys::SDL_bool::SDL_FALSE }) }
1409     }
1410 
grab(&self) -> bool1411     pub fn grab(&self) -> bool {
1412         unsafe { sys::SDL_GetWindowGrab(self.context.raw) == sys::SDL_bool::SDL_TRUE }
1413     }
1414 
set_brightness(&mut self, brightness: f64) -> Result<(), String>1415     pub fn set_brightness(&mut self, brightness: f64) -> Result<(), String> {
1416         unsafe {
1417             if sys::SDL_SetWindowBrightness(self.context.raw, brightness as c_float) == 0 {
1418                 Ok(())
1419             } else {
1420                 Err(get_error())
1421             }
1422         }
1423     }
1424 
brightness(&self) -> f641425     pub fn brightness(&self) -> f64 {
1426         unsafe { sys::SDL_GetWindowBrightness(self.context.raw) as f64 }
1427     }
1428 
set_gamma_ramp<'a, 'b, 'c, R, G, B>(&mut self, red: R, green: G, blue: B) -> Result<(), String> where R: Into<Option<&'a [u16; 256]>>, G: Into<Option<&'b [u16; 256]>>, B: Into<Option<&'c [u16; 256]>>,1429     pub fn set_gamma_ramp<'a, 'b, 'c, R, G, B>(&mut self, red: R, green: G, blue: B) -> Result<(), String>
1430     where R: Into<Option<&'a [u16; 256]>>,
1431           G: Into<Option<&'b [u16; 256]>>,
1432           B: Into<Option<&'c [u16; 256]>>,
1433     {
1434         let unwrapped_red = match red.into() {
1435             Some(values) => values.as_ptr(),
1436             None => ptr::null()
1437         };
1438         let unwrapped_green = match green.into() {
1439             Some(values) => values.as_ptr(),
1440             None => ptr::null()
1441         };
1442         let unwrapped_blue = match blue.into() {
1443             Some(values) => values.as_ptr(),
1444             None => ptr::null()
1445         };
1446         let result = unsafe {
1447             sys::SDL_SetWindowGammaRamp(
1448                 self.context.raw, unwrapped_red, unwrapped_green, unwrapped_blue
1449             )
1450         };
1451         if result != 0 {
1452             Err(get_error())
1453         } else {
1454             Ok(())
1455         }
1456     }
1457 
1458     #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
gamma_ramp(&self) -> Result<(Vec<u16>, Vec<u16>, Vec<u16>), String>1459     pub fn gamma_ramp(&self) -> Result<(Vec<u16>, Vec<u16>, Vec<u16>), String> {
1460         let mut red: Vec<u16> = Vec::with_capacity(256);
1461         let mut green: Vec<u16> = Vec::with_capacity(256);
1462         let mut blue: Vec<u16> = Vec::with_capacity(256);
1463         let result = unsafe {
1464             sys::SDL_GetWindowGammaRamp(
1465                 self.context.raw, red.as_mut_ptr(), green.as_mut_ptr(),
1466                 blue.as_mut_ptr()
1467             )
1468         };
1469         if result == 0 {
1470             Ok((red, green, blue))
1471         } else {
1472             Err(get_error())
1473         }
1474     }
1475 
1476     /// Set the transparency of the window. The given value will be clamped internally between
1477     /// `0.0` (fully transparent), and `1.0` (fully opaque).
1478     ///
1479     /// This method returns an error if opacity isn't supported by the current platform.
set_opacity(&mut self, opacity: f32) -> Result<(), String>1480     pub fn set_opacity(&mut self, opacity: f32) -> Result<(), String> {
1481         let result = unsafe { sys::SDL_SetWindowOpacity(self.context.raw, opacity) };
1482         if result < 0 {
1483             Err(get_error())
1484         } else {
1485             Ok(())
1486         }
1487     }
1488 
1489     /// Returns the transparency of the window, as a value between `0.0` (fully transparent), and
1490     /// `1.0` (fully opaque).
1491     ///
1492     /// If opacity isn't supported by the current platform, this method returns `Ok(1.0)` instead
1493     /// of an error.
opacity(&self) -> Result<f32, String>1494     pub fn opacity(&self) -> Result<f32, String> {
1495         let mut opacity = 0.0;
1496         let result = unsafe { sys::SDL_GetWindowOpacity(self.context.raw, &mut opacity) };
1497         if result < 0 {
1498             Err(get_error())
1499         } else {
1500             Ok(opacity)
1501         }
1502     }
1503 }
1504 
1505 #[derive(Copy, Clone)]
1506 pub struct DriverIterator {
1507     length: i32,
1508     index: i32
1509 }
1510 
1511 impl Iterator for DriverIterator {
1512     type Item = &'static str;
1513 
1514     #[inline]
next(&mut self) -> Option<&'static str>1515     fn next(&mut self) -> Option<&'static str> {
1516         if self.index >= self.length {
1517             None
1518         } else {
1519             use std::str;
1520 
1521             unsafe {
1522                 let buf = sys::SDL_GetVideoDriver(self.index);
1523                 assert!(!buf.is_null());
1524                 self.index += 1;
1525 
1526                 Some(str::from_utf8(CStr::from_ptr(buf as *const _).to_bytes()).unwrap())
1527             }
1528         }
1529     }
1530 
1531     #[inline]
size_hint(&self) -> (usize, Option<usize>)1532     fn size_hint(&self) -> (usize, Option<usize>) {
1533         let l = self.length as usize;
1534         (l, Some(l))
1535     }
1536 }
1537 
1538 impl ExactSizeIterator for DriverIterator { }
1539 
1540 /// Gets an iterator of all video drivers compiled into the SDL2 library.
1541 #[inline]
drivers() -> DriverIterator1542 pub fn drivers() -> DriverIterator {
1543     // This function is thread-safe and doesn't require the video subsystem to be initialized.
1544     // The list of drivers are read-only and statically compiled into SDL2, varying by platform.
1545 
1546     // SDL_GetNumVideoDrivers can never return a negative value.
1547     DriverIterator {
1548         length: unsafe { sys::SDL_GetNumVideoDrivers() },
1549         index: 0
1550     }
1551 }
1552