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