1use libc::{c_char, c_float, c_int, c_uint};
2use std::convert::TryFrom;
3use std::error::Error;
4use std::ffi::{CStr, CString, NulError};
5use std::ops::{Deref, DerefMut};
6use std::rc::Rc;
7use std::{fmt, mem, ptr};
8
9use crate::common::{validate_int, IntegerOrSdlError};
10use crate::pixels::PixelFormatEnum;
11use crate::rect::Rect;
12use crate::render::CanvasBuilder;
13use crate::surface::SurfaceRef;
14use crate::EventPump;
15use crate::VideoSubsystem;
16
17use crate::get_error;
18
19use crate::sys;
20
21pub use crate::sys::{VkInstance, VkSurfaceKHR};
22
23pub struct WindowSurfaceRef<'a>(&'a mut SurfaceRef, &'a Window);
24
25impl<'a> Deref for WindowSurfaceRef<'a> {
26 type Target = SurfaceRef;
27
28 #[inline]
29 fn deref(&self) -> &SurfaceRef {
30 self.0
31 }
32}
33
34impl<'a> DerefMut for WindowSurfaceRef<'a> {
35 #[inline]
36 fn deref_mut(&mut self) -> &mut SurfaceRef {
37 self.0
38 }
39}
40
41impl<'a> WindowSurfaceRef<'a> {
42 #[doc(alias = "SDL_UpdateWindowSurface")]
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 #[doc(alias = "SDL_UpdateWindowSurfaceRects")]
59 pub fn update_window_rects(&self, rects: &[Rect]) -> Result<(), String> {
60 unsafe {
61 if sys::SDL_UpdateWindowSurfaceRects(
62 self.1.context.raw,
63 Rect::raw_slice(rects),
64 rects.len() as c_int,
65 ) == 0
66 {
67 Ok(())
68 } else {
69 Err(get_error())
70 }
71 }
72 }
73
74 pub fn finish(self) -> Result<(), String> {
81 self.update_window()
82 }
83}
84
85#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
86pub enum GLProfile {
87 Core,
89 Compatibility,
91 GLES,
93 Unknown(i32),
96}
97
98trait GLAttrTypeUtil {
99 fn to_gl_value(self) -> i32;
100 fn from_gl_value(value: i32) -> Self;
101}
102
103impl GLAttrTypeUtil for u8 {
104 fn to_gl_value(self) -> i32 {
105 self as i32
106 }
107 fn from_gl_value(value: i32) -> u8 {
108 value as u8
109 }
110}
111
112impl GLAttrTypeUtil for bool {
113 fn to_gl_value(self) -> i32 {
114 if self {
115 1
116 } else {
117 0
118 }
119 }
120 fn from_gl_value(value: i32) -> bool {
121 value != 0
122 }
123}
124
125impl GLAttrTypeUtil for GLProfile {
126 fn to_gl_value(self) -> i32 {
127 use self::GLProfile::*;
128
129 match self {
130 Unknown(i) => i,
131 Core => 1,
132 Compatibility => 2,
133 GLES => 4,
134 }
135 }
136 fn from_gl_value(value: i32) -> GLProfile {
137 use self::GLProfile::*;
138
139 match value {
140 1 => Core,
141 2 => Compatibility,
142 4 => GLES,
143 i => Unknown(i),
144 }
145 }
146}
147
148macro_rules! attrs {
149 (
150 $(($attr_name:ident, $set_property:ident, $get_property:ident, $t:ty, $doc:expr)),*
151 ) => (
152
153 $(
154 #[doc = "**Sets** the attribute: "]
155 #[doc = $doc]
156 #[inline]
157 pub fn $set_property(&self, value: $t) {
158 gl_set_attribute!($attr_name, value.to_gl_value());
159 }
160
161 #[doc = "**Gets** the attribute: "]
162 #[doc = $doc]
163 #[inline]
164 pub fn $get_property(&self) -> $t {
165 let value = gl_get_attribute!($attr_name);
166 GLAttrTypeUtil::from_gl_value(value)
167 }
168 )*
169 );
170}
171
172pub mod gl_attr {
203 use super::{GLAttrTypeUtil, GLProfile};
204 use crate::get_error;
205 use crate::sys;
206 use std::marker::PhantomData;
207
208 pub struct GLAttr<'a> {
210 _marker: PhantomData<&'a crate::VideoSubsystem>,
211 }
212
213 impl crate::VideoSubsystem {
214 pub fn gl_attr(&self) -> GLAttr {
216 GLAttr {
217 _marker: PhantomData,
218 }
219 }
220 }
221
222 macro_rules! gl_set_attribute {
223 ($attr:ident, $value:expr) => {{
224 let result = unsafe { sys::SDL_GL_SetAttribute(sys::SDL_GLattr::$attr, $value) };
225
226 if result != 0 {
227 panic!(
229 "couldn't set attribute {}: {}",
230 stringify!($attr),
231 get_error()
232 );
233 }
234 }};
235 }
236
237 macro_rules! gl_get_attribute {
238 ($attr:ident) => {{
239 let mut value = 0;
240 let result = unsafe { sys::SDL_GL_GetAttribute(sys::SDL_GLattr::$attr, &mut value) };
241 if result != 0 {
242 panic!(
244 "couldn't get attribute {}: {}",
245 stringify!($attr),
246 get_error()
247 );
248 }
249 value
250 }};
251 }
252
253 impl<'a> GLAttr<'a> {
254 attrs! {
257 (SDL_GL_RED_SIZE, set_red_size, red_size, u8,
258 "the minimum number of bits for the red channel of the color buffer; defaults to 3"),
259
260 (SDL_GL_GREEN_SIZE, set_green_size, green_size, u8,
261 "the minimum number of bits for the green channel of the color buffer; defaults to 3"),
262
263 (SDL_GL_BLUE_SIZE, set_blue_size, blue_size, u8,
264 "the minimum number of bits for the blue channel of the color buffer; defaults to 2"),
265
266 (SDL_GL_ALPHA_SIZE, set_alpha_size, alpha_size, u8,
267 "the minimum number of bits for the alpha channel of the color buffer; defaults to 0"),
268
269 (SDL_GL_BUFFER_SIZE, set_buffer_size, buffer_size, u8,
270 "the minimum number of bits for frame buffer size; defaults to 0"),
271
272 (SDL_GL_DOUBLEBUFFER, set_double_buffer, double_buffer, bool,
273 "whether the output is single or double buffered; defaults to double buffering on"),
274
275 (SDL_GL_DEPTH_SIZE, set_depth_size, depth_size, u8,
276 "the minimum number of bits in the depth buffer; defaults to 16"),
277
278 (SDL_GL_STENCIL_SIZE, set_stencil_size, stencil_size, u8,
279 "the minimum number of bits in the stencil buffer; defaults to 0"),
280
281 (SDL_GL_ACCUM_RED_SIZE, set_accum_red_size, accum_red_size, u8,
282 "the minimum number of bits for the red channel of the accumulation buffer; defaults to 0"),
283
284 (SDL_GL_ACCUM_GREEN_SIZE, set_accum_green_size, accum_green_size, u8,
285 "the minimum number of bits for the green channel of the accumulation buffer; defaults to 0"),
286
287 (SDL_GL_ACCUM_BLUE_SIZE, set_accum_blue_size, accum_blue_size, u8,
288 "the minimum number of bits for the blue channel of the accumulation buffer; defaults to 0"),
289
290 (SDL_GL_ACCUM_ALPHA_SIZE, set_accum_alpha_size, accum_alpha_size, u8,
291 "the minimum number of bits for the alpha channel of the accumulation buffer; defaults to 0"),
292
293 (SDL_GL_STEREO, set_stereo, stereo, bool,
294 "whether the output is stereo 3D; defaults to off"),
295
296 (SDL_GL_MULTISAMPLEBUFFERS, set_multisample_buffers, multisample_buffers, u8,
297 "the number of buffers used for multisample anti-aliasing; defaults to 0"),
298
299 (SDL_GL_MULTISAMPLESAMPLES, set_multisample_samples, multisample_samples, u8,
300 "the number of samples used around the current pixel used for multisample anti-aliasing; defaults to 0"),
301
302 (SDL_GL_ACCELERATED_VISUAL, set_accelerated_visual, accelerated_visual, bool,
303 "whether to require hardware acceleration; false to force software rendering; defaults to allow either"),
304
305 (SDL_GL_CONTEXT_MAJOR_VERSION, set_context_major_version, context_major_version, u8,
306 "OpenGL context major version"),
307
308 (SDL_GL_CONTEXT_MINOR_VERSION, set_context_minor_version, context_minor_version, u8,
309 "OpenGL context minor version"),
310
311 (SDL_GL_CONTEXT_PROFILE_MASK, set_context_profile, context_profile, GLProfile,
312 "type of GL context (Core, Compatibility, ES)"),
313
314 (SDL_GL_SHARE_WITH_CURRENT_CONTEXT, set_share_with_current_context, share_with_current_context, bool,
315 "OpenGL context sharing; defaults to false"),
316
317 (SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, set_framebuffer_srgb_compatible, framebuffer_srgb_compatible, bool,
318 "requests sRGB capable visual; defaults to false (>= SDL 2.0.1)"),
319
320 (SDL_GL_CONTEXT_NO_ERROR, set_context_no_error, context_no_error, bool,
321 "disables OpenGL error checking; defaults to false (>= SDL 2.0.6)")
322 }
323
324 #[inline]
326 pub fn set_context_version(&self, major: u8, minor: u8) {
327 self.set_context_major_version(major);
328 self.set_context_minor_version(minor);
329 }
330
331 #[inline]
333 pub fn context_version(&self) -> (u8, u8) {
334 (self.context_major_version(), self.context_minor_version())
335 }
336 }
337
338 pub struct ContextFlagsBuilder<'a> {
340 flags: i32,
341 _marker: PhantomData<&'a crate::VideoSubsystem>,
342 }
343
344 impl<'a> ContextFlagsBuilder<'a> {
345 #[inline]
347 pub fn set(&self) {
348 gl_set_attribute!(SDL_GL_CONTEXT_FLAGS, self.flags);
349 }
350
351 #[inline]
353 pub fn debug(&mut self) -> &mut ContextFlagsBuilder<'a> {
354 self.flags |= 0x0001;
355 self
356 }
357
358 #[inline]
360 pub fn forward_compatible(&mut self) -> &mut ContextFlagsBuilder<'a> {
361 self.flags |= 0x0002;
362 self
363 }
364
365 #[inline]
366 pub fn robust_access(&mut self) -> &mut ContextFlagsBuilder<'a> {
367 self.flags |= 0x0004;
368 self
369 }
370
371 #[inline]
372 pub fn reset_isolation(&mut self) -> &mut ContextFlagsBuilder<'a> {
373 self.flags |= 0x0008;
374 self
375 }
376 }
377
378 pub struct ContextFlags {
379 flags: i32,
380 }
381
382 impl ContextFlags {
383 #[inline]
384 pub const fn has_debug(&self) -> bool {
385 self.flags & 0x0001 != 0
386 }
387
388 #[inline]
389 pub const fn has_forward_compatible(&self) -> bool {
390 self.flags & 0x0002 != 0
391 }
392
393 #[inline]
394 pub const fn has_robust_access(&self) -> bool {
395 self.flags & 0x0004 != 0
396 }
397
398 #[inline]
399 pub const fn has_reset_isolation(&self) -> bool {
400 self.flags & 0x0008 != 0
401 }
402 }
403
404 impl<'a> GLAttr<'a> {
405 pub fn set_context_flags(&self) -> ContextFlagsBuilder {
419 ContextFlagsBuilder {
420 flags: 0,
421 _marker: PhantomData,
422 }
423 }
424
425 pub fn context_flags(&self) -> ContextFlags {
439 let flags = gl_get_attribute!(SDL_GL_CONTEXT_FLAGS);
440
441 ContextFlags { flags }
442 }
443 }
444}
445
446#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
447pub struct DisplayMode {
448 pub format: PixelFormatEnum,
449 pub w: i32,
450 pub h: i32,
451 pub refresh_rate: i32,
452}
453
454impl DisplayMode {
455 pub fn new(format: PixelFormatEnum, w: i32, h: i32, refresh_rate: i32) -> DisplayMode {
456 DisplayMode {
457 format,
458 w,
459 h,
460 refresh_rate,
461 }
462 }
463
464 pub fn from_ll(raw: &sys::SDL_DisplayMode) -> DisplayMode {
465 DisplayMode::new(
466 PixelFormatEnum::try_from(raw.format).unwrap_or(PixelFormatEnum::Unknown),
467 raw.w,
468 raw.h,
469 raw.refresh_rate,
470 )
471 }
472
473 pub fn to_ll(&self) -> sys::SDL_DisplayMode {
474 sys::SDL_DisplayMode {
475 format: self.format as u32,
476 w: self.w as c_int,
477 h: self.h as c_int,
478 refresh_rate: self.refresh_rate as c_int,
479 driverdata: ptr::null_mut(),
480 }
481 }
482}
483
484#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
485pub enum FullscreenType {
486 Off = 0,
487 True = 0x00_00_00_01,
488 Desktop = 0x00_00_10_01,
489}
490
491impl FullscreenType {
492 pub fn from_window_flags(window_flags: u32) -> FullscreenType {
493 if window_flags & FullscreenType::Desktop as u32 == FullscreenType::Desktop as u32 {
494 FullscreenType::Desktop
495 } else if window_flags & FullscreenType::True as u32 == FullscreenType::True as u32 {
496 FullscreenType::True
497 } else {
498 FullscreenType::Off
499 }
500 }
501}
502
503#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
504pub enum WindowPos {
505 Undefined,
506 Centered,
507 Positioned(i32),
508}
509
510impl From<i32> for WindowPos {
511 fn from(pos: i32) -> Self {
512 WindowPos::Positioned(pos)
513 }
514}
515
516fn to_ll_windowpos(pos: WindowPos) -> c_int {
517 match pos {
518 WindowPos::Undefined => sys::SDL_WINDOWPOS_UNDEFINED_MASK as c_int,
519 WindowPos::Centered => sys::SDL_WINDOWPOS_CENTERED_MASK as c_int,
520 WindowPos::Positioned(x) => x as c_int,
521 }
522}
523
524pub struct GLContext {
525 raw: sys::SDL_GLContext,
526}
527
528impl Drop for GLContext {
529 #[doc(alias = "SDL_GL_DeleteContext")]
530 fn drop(&mut self) {
531 unsafe { sys::SDL_GL_DeleteContext(self.raw) }
532 }
533}
534
535impl GLContext {
536 #[doc(alias = "SDL_GL_GetCurrentContext")]
538 pub fn is_current(&self) -> bool {
539 let current_raw = unsafe { sys::SDL_GL_GetCurrentContext() };
540 self.raw == current_raw
541 }
542}
543
544pub struct WindowContext {
548 subsystem: VideoSubsystem,
549 raw: *mut sys::SDL_Window,
550 #[allow(dead_code)]
551 pub(crate) metal_view: sys::SDL_MetalView,
552}
553
554impl Drop for WindowContext {
555 #[inline]
556 #[doc(alias = "SDL_DestroyWindow")]
557 fn drop(&mut self) {
558 unsafe {
559 #[cfg(target_os = "macos")]
560 if !self.metal_view.is_null() {
561 sys::SDL_Metal_DestroyView(self.metal_view);
562 }
563 sys::SDL_DestroyWindow(self.raw)
564 };
565 }
566}
567
568impl WindowContext {
569 #[inline]
570 pub unsafe fn from_ll(
574 subsystem: VideoSubsystem,
575 raw: *mut sys::SDL_Window,
576 metal_view: sys::SDL_MetalView,
577 ) -> WindowContext {
578 WindowContext {
579 subsystem,
580 raw,
581 metal_view,
582 }
583 }
584}
585
586#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
588#[repr(i32)]
589pub enum SwapInterval {
590 Immediate = 0,
591 VSync = 1,
592 LateSwapTearing = -1,
593}
594
595impl From<i32> for SwapInterval {
596 fn from(i: i32) -> Self {
597 match i {
598 -1 => SwapInterval::LateSwapTearing,
599 0 => SwapInterval::Immediate,
600 1 => SwapInterval::VSync,
601 other => panic!(
602 "Invalid value for SwapInterval: {}; valid values are -1, 0, 1",
603 other
604 ),
605 }
606 }
607}
608
609#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
611#[repr(i32)]
612pub enum Orientation {
613 Unknown = sys::SDL_DisplayOrientation::SDL_ORIENTATION_UNKNOWN as i32,
615 Landscape = sys::SDL_DisplayOrientation::SDL_ORIENTATION_LANDSCAPE as i32,
617 LandscapeFlipped = sys::SDL_DisplayOrientation::SDL_ORIENTATION_LANDSCAPE_FLIPPED as i32,
619 Portrait = sys::SDL_DisplayOrientation::SDL_ORIENTATION_PORTRAIT as i32,
621 PortraitFlipped = sys::SDL_DisplayOrientation::SDL_ORIENTATION_PORTRAIT_FLIPPED as i32,
623}
624
625impl Orientation {
626 pub fn from_ll(orientation: sys::SDL_DisplayOrientation) -> Orientation {
627 match orientation {
628 sys::SDL_DisplayOrientation::SDL_ORIENTATION_UNKNOWN => Orientation::Unknown,
629 sys::SDL_DisplayOrientation::SDL_ORIENTATION_LANDSCAPE => Orientation::Landscape,
630 sys::SDL_DisplayOrientation::SDL_ORIENTATION_LANDSCAPE_FLIPPED => {
631 Orientation::LandscapeFlipped
632 }
633 sys::SDL_DisplayOrientation::SDL_ORIENTATION_PORTRAIT => Orientation::Portrait,
634 sys::SDL_DisplayOrientation::SDL_ORIENTATION_PORTRAIT_FLIPPED => {
635 Orientation::PortraitFlipped
636 }
637 }
638 }
639
640 pub fn to_ll(self) -> sys::SDL_DisplayOrientation {
641 match self {
642 Orientation::Unknown => sys::SDL_DisplayOrientation::SDL_ORIENTATION_UNKNOWN,
643 Orientation::Landscape => sys::SDL_DisplayOrientation::SDL_ORIENTATION_LANDSCAPE,
644 Orientation::LandscapeFlipped => {
645 sys::SDL_DisplayOrientation::SDL_ORIENTATION_LANDSCAPE_FLIPPED
646 }
647 Orientation::Portrait => sys::SDL_DisplayOrientation::SDL_ORIENTATION_PORTRAIT,
648 Orientation::PortraitFlipped => {
649 sys::SDL_DisplayOrientation::SDL_ORIENTATION_PORTRAIT_FLIPPED
650 }
651 }
652 }
653}
654
655#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
657#[repr(i32)]
658pub enum FlashOperation {
659 Cancel = sys::SDL_FlashOperation::SDL_FLASH_CANCEL as i32,
661 Briefly = sys::SDL_FlashOperation::SDL_FLASH_BRIEFLY as i32,
663 UntilFocused = sys::SDL_FlashOperation::SDL_FLASH_UNTIL_FOCUSED as i32,
665}
666
667impl FlashOperation {
668 pub fn from_ll(flash_operation: sys::SDL_FlashOperation) -> FlashOperation {
669 match flash_operation {
670 sys::SDL_FlashOperation::SDL_FLASH_CANCEL => FlashOperation::Cancel,
671 sys::SDL_FlashOperation::SDL_FLASH_BRIEFLY => FlashOperation::Briefly,
672 sys::SDL_FlashOperation::SDL_FLASH_UNTIL_FOCUSED => FlashOperation::UntilFocused,
673 }
674 }
675
676 pub fn to_ll(self) -> sys::SDL_FlashOperation {
677 match self {
678 FlashOperation::Cancel => sys::SDL_FlashOperation::SDL_FLASH_CANCEL,
679 FlashOperation::Briefly => sys::SDL_FlashOperation::SDL_FLASH_BRIEFLY,
680 FlashOperation::UntilFocused => sys::SDL_FlashOperation::SDL_FLASH_UNTIL_FOCUSED,
681 }
682 }
683}
684
685#[derive(Clone)]
696pub struct Window {
697 context: Rc<WindowContext>,
698}
699
700impl From<WindowContext> for Window {
701 fn from(context: WindowContext) -> Window {
702 Window {
703 context: Rc::new(context),
704 }
705 }
706}
707
708impl_raw_accessors!((GLContext, sys::SDL_GLContext));
709
710impl VideoSubsystem {
711 pub fn window(&self, title: &str, width: u32, height: u32) -> WindowBuilder {
713 WindowBuilder::new(self, title, width, height)
714 }
715
716 #[doc(alias = "SDL_GetCurrentVideoDriver")]
718 pub fn current_video_driver(&self) -> &'static str {
719 use std::str;
720
721 unsafe {
722 let buf = sys::SDL_GetCurrentVideoDriver();
723 assert!(!buf.is_null());
724
725 str::from_utf8(CStr::from_ptr(buf as *const _).to_bytes()).unwrap()
726 }
727 }
728
729 #[doc(alias = "SDL_GetNumVideoDisplays")]
731 pub fn num_video_displays(&self) -> Result<i32, String> {
732 let result = unsafe { sys::SDL_GetNumVideoDisplays() };
733 if result < 0 {
734 Err(get_error())
735 } else {
736 Ok(result as i32)
737 }
738 }
739
740 #[doc(alias = "SDL_GetDisplayName")]
745 pub fn display_name(&self, display_index: i32) -> Result<String, String> {
746 unsafe {
747 let display = sys::SDL_GetDisplayName(display_index as c_int);
748 if display.is_null() {
749 Err(get_error())
750 } else {
751 Ok(CStr::from_ptr(display as *const _)
752 .to_str()
753 .unwrap()
754 .to_owned())
755 }
756 }
757 }
758
759 #[doc(alias = "SDL_GetDisplayBounds")]
763 pub fn display_bounds(&self, display_index: i32) -> Result<Rect, String> {
764 let mut out = mem::MaybeUninit::uninit();
765 let result =
766 unsafe { sys::SDL_GetDisplayBounds(display_index as c_int, out.as_mut_ptr()) == 0 };
767
768 if result {
769 let out = unsafe { out.assume_init() };
770 Ok(Rect::from_ll(out))
771 } else {
772 Err(get_error())
773 }
774 }
775
776 #[doc(alias = "SDL_GetDisplayUsableBounds")]
786 pub fn display_usable_bounds(&self, display_index: i32) -> Result<Rect, String> {
787 let mut out = mem::MaybeUninit::uninit();
788 let result =
789 unsafe { sys::SDL_GetDisplayUsableBounds(display_index as c_int, out.as_mut_ptr()) };
790 if result == 0 {
791 let out = unsafe { out.assume_init() };
792 Ok(Rect::from_ll(out))
793 } else {
794 Err(get_error())
795 }
796 }
797
798 #[doc(alias = "SDL_GetNumDisplayModes")]
800 pub fn num_display_modes(&self, display_index: i32) -> Result<i32, String> {
801 let result = unsafe { sys::SDL_GetNumDisplayModes(display_index as c_int) };
802 if result < 0 {
803 Err(get_error())
804 } else {
805 Ok(result as i32)
806 }
807 }
808
809 #[doc(alias = "SDL_GetDisplayMode")]
818 pub fn display_mode(&self, display_index: i32, mode_index: i32) -> Result<DisplayMode, String> {
819 let mut dm = mem::MaybeUninit::uninit();
820 let result = unsafe {
821 sys::SDL_GetDisplayMode(display_index as c_int, mode_index as c_int, dm.as_mut_ptr())
822 == 0
823 };
824
825 if result {
826 let dm = unsafe { dm.assume_init() };
827 Ok(DisplayMode::from_ll(&dm))
828 } else {
829 Err(get_error())
830 }
831 }
832
833 #[doc(alias = "SDL_GetDesktopDisplayMode")]
840 pub fn desktop_display_mode(&self, display_index: i32) -> Result<DisplayMode, String> {
841 let mut dm = mem::MaybeUninit::uninit();
842 let result =
843 unsafe { sys::SDL_GetDesktopDisplayMode(display_index as c_int, dm.as_mut_ptr()) == 0 };
844
845 if result {
846 let dm = unsafe { dm.assume_init() };
847 Ok(DisplayMode::from_ll(&dm))
848 } else {
849 Err(get_error())
850 }
851 }
852
853 #[doc(alias = "SDL_GetCurrentDisplayMode")]
860 pub fn current_display_mode(&self, display_index: i32) -> Result<DisplayMode, String> {
861 let mut dm = mem::MaybeUninit::uninit();
862 let result =
863 unsafe { sys::SDL_GetCurrentDisplayMode(display_index as c_int, dm.as_mut_ptr()) == 0 };
864
865 if result {
866 let dm = unsafe { dm.assume_init() };
867 Ok(DisplayMode::from_ll(&dm))
868 } else {
869 Err(get_error())
870 }
871 }
872
873 #[doc(alias = "SDL_GetClosestDisplayMode")]
883 pub fn closest_display_mode(
884 &self,
885 display_index: i32,
886 mode: &DisplayMode,
887 ) -> Result<DisplayMode, String> {
888 let input = mode.to_ll();
889 let mut dm = mem::MaybeUninit::uninit();
890
891 let result = unsafe {
892 sys::SDL_GetClosestDisplayMode(display_index as c_int, &input, dm.as_mut_ptr())
893 };
894
895 if result.is_null() {
896 Err(get_error())
897 } else {
898 let dm = unsafe { dm.assume_init() };
899 Ok(DisplayMode::from_ll(&dm))
900 }
901 }
902
903 #[doc(alias = "SDL_GetDisplayDPI")]
906 pub fn display_dpi(&self, display_index: i32) -> Result<(f32, f32, f32), String> {
907 let mut ddpi = 0.0;
908 let mut hdpi = 0.0;
909 let mut vdpi = 0.0;
910 let result = unsafe {
911 sys::SDL_GetDisplayDPI(display_index as c_int, &mut ddpi, &mut hdpi, &mut vdpi)
912 };
913 if result < 0 {
914 Err(get_error())
915 } else {
916 Ok((ddpi, hdpi, vdpi))
917 }
918 }
919
920 #[doc(alias = "SDL_GetDisplayOrientation")]
922 pub fn display_orientation(&self, display_index: i32) -> Orientation {
923 Orientation::from_ll(unsafe { sys::SDL_GetDisplayOrientation(display_index as c_int) })
924 }
925
926 #[doc(alias = "SDL_IsScreenSaverEnabled")]
928 pub fn is_screen_saver_enabled(&self) -> bool {
929 unsafe { sys::SDL_IsScreenSaverEnabled() == sys::SDL_bool::SDL_TRUE }
930 }
931
932 #[doc(alias = "SDL_EnableScreenSaver")]
934 pub fn enable_screen_saver(&self) {
935 unsafe { sys::SDL_EnableScreenSaver() }
936 }
937
938 #[doc(alias = "SDL_DisableScreenSaver")]
940 pub fn disable_screen_saver(&self) {
941 unsafe { sys::SDL_DisableScreenSaver() }
942 }
943
944 #[doc(alias = "SDL_GL_LoadLibrary")]
951 pub fn gl_load_library_default(&self) -> Result<(), String> {
952 unsafe {
953 if sys::SDL_GL_LoadLibrary(ptr::null()) == 0 {
954 Ok(())
955 } else {
956 Err(get_error())
957 }
958 }
959 }
960
961 #[doc(alias = "SDL_GL_LoadLibrary")]
968 pub fn gl_load_library<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), String> {
969 unsafe {
970 let path = CString::new(path.as_ref().to_str().unwrap()).unwrap();
971 if sys::SDL_GL_LoadLibrary(path.as_ptr() as *const c_char) == 0 {
972 Ok(())
973 } else {
974 Err(get_error())
975 }
976 }
977 }
978
979 #[doc(alias = "SDL_GL_UnloadLibrary")]
984 pub fn gl_unload_library(&self) {
985 unsafe {
986 sys::SDL_GL_UnloadLibrary();
987 }
988 }
989
990 #[doc(alias = "SDL_GL_GetProcAddress")]
994 pub fn gl_get_proc_address(&self, procname: &str) -> *const () {
995 match CString::new(procname) {
996 Ok(procname) => unsafe {
997 sys::SDL_GL_GetProcAddress(procname.as_ptr() as *const c_char) as *const ()
998 },
999 Err(_) => ptr::null(),
1001 }
1002 }
1003
1004 #[doc(alias = "SDL_GL_ExtensionSupported")]
1014 pub fn gl_extension_supported(&self, extension: &str) -> bool {
1015 match CString::new(extension) {
1016 Ok(extension) => unsafe {
1017 sys::SDL_GL_ExtensionSupported(extension.as_ptr() as *const c_char)
1018 != sys::SDL_bool::SDL_FALSE
1019 },
1020 Err(_) => false,
1022 }
1023 }
1024
1025 #[doc(alias = "SDL_GL_GetCurrentWindow")]
1027 pub fn gl_get_current_window_id(&self) -> Result<u32, String> {
1028 let raw = unsafe { sys::SDL_GL_GetCurrentWindow() };
1029 if raw.is_null() {
1030 Err(get_error())
1031 } else {
1032 let id = unsafe { sys::SDL_GetWindowID(raw) };
1033 Ok(id)
1034 }
1035 }
1036
1037 #[doc(alias = "SDL_GL_MakeCurrent")]
1039 pub fn gl_release_current_context(&self) -> Result<(), String> {
1040 let result = unsafe { sys::SDL_GL_MakeCurrent(ptr::null_mut(), ptr::null_mut()) };
1041
1042 if result == 0 {
1043 Ok(())
1044 } else {
1045 Err(get_error())
1046 }
1047 }
1048
1049 #[doc(alias = "SDL_GL_SetSwapInterval")]
1051 pub fn gl_set_swap_interval<S: Into<SwapInterval>>(&self, interval: S) -> Result<(), String> {
1052 let result = unsafe { sys::SDL_GL_SetSwapInterval(interval.into() as c_int) };
1053 if result == 0 {
1054 Ok(())
1055 } else {
1056 Err(get_error())
1057 }
1058 }
1059
1060 #[doc(alias = "SDL_GL_GetSwapInterval")]
1061 pub fn gl_get_swap_interval(&self) -> SwapInterval {
1062 unsafe {
1063 let interval = sys::SDL_GL_GetSwapInterval() as i32;
1064 assert!(interval == -1 || interval == 0 || interval == 1);
1065 mem::transmute(interval)
1066 }
1067 }
1068
1069 #[doc(alias = "SDL_Vulkan_LoadLibrary")]
1076 pub fn vulkan_load_library_default(&self) -> Result<(), String> {
1077 unsafe {
1078 if sys::SDL_Vulkan_LoadLibrary(ptr::null()) == 0 {
1079 Ok(())
1080 } else {
1081 Err(get_error())
1082 }
1083 }
1084 }
1085
1086 #[doc(alias = "SDL_Vulkan_LoadLibrary")]
1093 pub fn vulkan_load_library<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), String> {
1094 unsafe {
1095 let path = CString::new(path.as_ref().to_str().unwrap()).unwrap();
1096 if sys::SDL_Vulkan_LoadLibrary(path.as_ptr() as *const c_char) == 0 {
1097 Ok(())
1098 } else {
1099 Err(get_error())
1100 }
1101 }
1102 }
1103
1104 #[doc(alias = "SDL_Vulkan_UnloadLibrary")]
1109 pub fn vulkan_unload_library(&self) {
1110 unsafe {
1111 sys::SDL_Vulkan_UnloadLibrary();
1112 }
1113 }
1114
1115 #[doc(alias = "SDL_Vulkan_GetVkGetInstanceProcAddr")]
1120 pub fn vulkan_get_proc_address_function(&self) -> Result<*const (), String> {
1121 let result = unsafe { sys::SDL_Vulkan_GetVkGetInstanceProcAddr() as *const () };
1122 if result.is_null() {
1123 Err(get_error())
1124 } else {
1125 Ok(result)
1126 }
1127 }
1128}
1129
1130#[derive(Debug, Clone)]
1131pub enum WindowBuildError {
1132 HeightOverflows(u32),
1133 WidthOverflows(u32),
1134 InvalidTitle(NulError),
1135 SdlError(String),
1136}
1137
1138impl fmt::Display for WindowBuildError {
1139 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1140 use self::WindowBuildError::*;
1141
1142 match *self {
1143 HeightOverflows(h) => write!(f, "Window height ({}) is too high.", h),
1144 WidthOverflows(w) => write!(f, "Window width ({}) is too high.", w),
1145 InvalidTitle(ref e) => write!(f, "Invalid window title: {}", e),
1146 SdlError(ref e) => write!(f, "SDL error: {}", e),
1147 }
1148 }
1149}
1150
1151impl Error for WindowBuildError {
1152 fn source(&self) -> Option<&(dyn Error + 'static)> {
1153 match self {
1154 Self::InvalidTitle(err) => Some(err),
1155 Self::HeightOverflows(_) | Self::WidthOverflows(_) | Self::SdlError(_) => None,
1156 }
1157 }
1158}
1159
1160#[derive(Debug)]
1162pub struct WindowBuilder {
1163 title: String,
1164 width: u32,
1165 height: u32,
1166 x: WindowPos,
1167 y: WindowPos,
1168 window_flags: u32,
1169 create_metal_view: bool,
1170 subsystem: VideoSubsystem,
1173 shaped: bool,
1174}
1175
1176impl WindowBuilder {
1177 pub fn new(v: &VideoSubsystem, title: &str, width: u32, height: u32) -> WindowBuilder {
1179 WindowBuilder {
1180 title: title.to_owned(),
1181 width,
1182 height,
1183 x: WindowPos::Undefined,
1184 y: WindowPos::Undefined,
1185 window_flags: 0,
1186 subsystem: v.clone(),
1187 create_metal_view: false,
1188 shaped: false,
1189 }
1190 }
1191
1192 #[doc(alias = "SDL_CreateWindow")]
1194 pub fn build(&self) -> Result<Window, WindowBuildError> {
1195 use self::WindowBuildError::*;
1196 let title = match CString::new(self.title.as_bytes()) {
1197 Ok(t) => t,
1198 Err(err) => return Err(InvalidTitle(err)),
1199 };
1200 if self.width >= (1 << 31) {
1201 return Err(WidthOverflows(self.width));
1202 }
1203 if self.height >= (1 << 31) {
1204 return Err(HeightOverflows(self.height));
1205 }
1206
1207 let raw_width = self.width as c_int;
1208 let raw_height = self.height as c_int;
1209 unsafe {
1210 let raw = if self.shaped {
1211 sys::SDL_CreateShapedWindow(
1212 title.as_ptr() as *const c_char,
1213 to_ll_windowpos(self.x) as u32,
1214 to_ll_windowpos(self.y) as u32,
1215 raw_width as u32,
1216 raw_height as u32,
1217 self.window_flags,
1218 )
1219 } else {
1220 sys::SDL_CreateWindow(
1221 title.as_ptr() as *const c_char,
1222 to_ll_windowpos(self.x),
1223 to_ll_windowpos(self.y),
1224 raw_width,
1225 raw_height,
1226 self.window_flags,
1227 )
1228 };
1229
1230 if raw.is_null() {
1231 Err(SdlError(get_error()))
1232 } else {
1233 let metal_view = match self.create_metal_view {
1234 #[cfg(target_os = "macos")]
1235 true => sys::SDL_Metal_CreateView(raw),
1236 _ => 0 as sys::SDL_MetalView,
1237 };
1238
1239 Ok(Window::from_ll(self.subsystem.clone(), raw, metal_view))
1240 }
1241 }
1242 }
1243
1244 pub fn window_flags(&self) -> u32 {
1246 self.window_flags
1247 }
1248
1249 pub fn set_window_flags(&mut self, flags: u32) -> &mut WindowBuilder {
1252 self.window_flags = flags;
1253 self
1254 }
1255
1256 pub fn position(&mut self, x: i32, y: i32) -> &mut WindowBuilder {
1258 self.x = WindowPos::Positioned(x);
1259 self.y = WindowPos::Positioned(y);
1260 self
1261 }
1262
1263 pub fn position_centered(&mut self) -> &mut WindowBuilder {
1265 self.x = WindowPos::Centered;
1266 self.y = WindowPos::Centered;
1267 self
1268 }
1269
1270 pub fn fullscreen(&mut self) -> &mut WindowBuilder {
1272 self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_FULLSCREEN as u32;
1273 self
1274 }
1275
1276 pub fn fullscreen_desktop(&mut self) -> &mut WindowBuilder {
1278 self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_FULLSCREEN_DESKTOP as u32;
1279 self
1280 }
1281
1282 pub fn opengl(&mut self) -> &mut WindowBuilder {
1284 self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_OPENGL as u32;
1285 self
1286 }
1287
1288 pub fn vulkan(&mut self) -> &mut WindowBuilder {
1290 self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_VULKAN as u32;
1291 self
1292 }
1293
1294 pub fn hidden(&mut self) -> &mut WindowBuilder {
1296 self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_HIDDEN as u32;
1297 self
1298 }
1299
1300 pub fn borderless(&mut self) -> &mut WindowBuilder {
1302 self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_BORDERLESS as u32;
1303 self
1304 }
1305
1306 pub fn resizable(&mut self) -> &mut WindowBuilder {
1308 self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_RESIZABLE as u32;
1309 self
1310 }
1311
1312 pub fn minimized(&mut self) -> &mut WindowBuilder {
1314 self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_MINIMIZED as u32;
1315 self
1316 }
1317
1318 pub fn maximized(&mut self) -> &mut WindowBuilder {
1320 self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_MAXIMIZED as u32;
1321 self
1322 }
1323
1324 pub fn input_grabbed(&mut self) -> &mut WindowBuilder {
1326 self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_INPUT_GRABBED as u32;
1327 self
1328 }
1329
1330 pub fn allow_highdpi(&mut self) -> &mut WindowBuilder {
1332 self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_ALLOW_HIGHDPI as u32;
1333 self
1334 }
1335
1336 pub fn always_on_top(&mut self) -> &mut WindowBuilder {
1338 self.window_flags |= sys::SDL_WindowFlags::SDL_WINDOW_ALWAYS_ON_TOP as u32;
1339 self
1340 }
1341
1342 pub fn metal_view(&mut self) -> &mut WindowBuilder {
1346 self.create_metal_view = true;
1347 self
1348 }
1349
1350 pub fn set_shaped(&mut self) -> &mut WindowBuilder {
1352 self.shaped = true;
1353 self
1354 }
1355}
1356
1357impl From<Window> for CanvasBuilder {
1358 fn from(window: Window) -> CanvasBuilder {
1359 CanvasBuilder::new(window)
1360 }
1361}
1362
1363impl Window {
1364 #[inline]
1365 #[allow(clippy::trivially_copy_pass_by_ref)]
1368 pub fn raw(&self) -> *mut sys::SDL_Window {
1369 self.context.raw
1370 }
1371
1372 #[inline]
1373 pub unsafe fn from_ll(
1374 subsystem: VideoSubsystem,
1375 raw: *mut sys::SDL_Window,
1376 metal_view: sys::SDL_MetalView,
1377 ) -> Window {
1378 let context = WindowContext::from_ll(subsystem, raw, metal_view);
1379 context.into()
1380 }
1381
1382 #[inline]
1383 pub const fn from_ref(context: Rc<WindowContext>) -> Window {
1385 Window { context }
1386 }
1387
1388 #[inline]
1390 pub fn subsystem(&self) -> &VideoSubsystem {
1391 &self.context.subsystem
1392 }
1393
1394 pub fn into_canvas(self) -> CanvasBuilder {
1396 self.into()
1397 }
1398
1399 pub fn context(&self) -> Rc<WindowContext> {
1401 self.context.clone()
1402 }
1403
1404 #[doc(alias = "SDL_GetWindowID")]
1406 pub fn id(&self) -> u32 {
1407 unsafe { sys::SDL_GetWindowID(self.context.raw) }
1408 }
1409
1410 #[doc(alias = "SDL_GL_CreateContext")]
1412 pub fn gl_create_context(&self) -> Result<GLContext, String> {
1413 let result = unsafe { sys::SDL_GL_CreateContext(self.context.raw) };
1414 if result.is_null() {
1415 Err(get_error())
1416 } else {
1417 Ok(GLContext { raw: result })
1418 }
1419 }
1420
1421 #[doc(alias = "SDL_GL_GetCurrentContext")]
1423 pub unsafe fn gl_get_current_context(&self) -> Option<GLContext> {
1424 let context_raw = sys::SDL_GL_GetCurrentContext();
1425
1426 if !context_raw.is_null() {
1427 Some(GLContext { raw: context_raw })
1428 } else {
1429 None
1430 }
1431 }
1432
1433 #[doc(alias = "SDL_GL_MakeCurrent")]
1435 pub fn gl_set_context_to_current(&self) -> Result<(), String> {
1436 unsafe {
1437 let context_raw = sys::SDL_GL_GetCurrentContext();
1438
1439 if !context_raw.is_null() && sys::SDL_GL_MakeCurrent(self.context.raw, context_raw) == 0
1440 {
1441 Ok(())
1442 } else {
1443 Err(get_error())
1444 }
1445 }
1446 }
1447
1448 #[doc(alias = "SDL_GL_MakeCurrent")]
1452 pub fn gl_make_current(&self, context: &GLContext) -> Result<(), String> {
1453 unsafe {
1454 if sys::SDL_GL_MakeCurrent(self.context.raw, context.raw) == 0 {
1455 Ok(())
1456 } else {
1457 Err(get_error())
1458 }
1459 }
1460 }
1461
1462 #[doc(alias = "SDL_GL_SwapWindow")]
1470 pub fn gl_swap_window(&self) {
1471 unsafe { sys::SDL_GL_SwapWindow(self.context.raw) }
1472 }
1473
1474 #[doc(alias = "SDL_Vulkan_GetInstanceExtensions")]
1476 pub fn vulkan_instance_extensions(&self) -> Result<Vec<&'static str>, String> {
1477 let mut count: c_uint = 0;
1478 if unsafe {
1479 sys::SDL_Vulkan_GetInstanceExtensions(self.context.raw, &mut count, ptr::null_mut())
1480 } == sys::SDL_bool::SDL_FALSE
1481 {
1482 return Err(get_error());
1483 }
1484 let mut names: Vec<*const c_char> = vec![ptr::null(); count as usize];
1485 if unsafe {
1486 sys::SDL_Vulkan_GetInstanceExtensions(self.context.raw, &mut count, names.as_mut_ptr())
1487 } == sys::SDL_bool::SDL_FALSE
1488 {
1489 return Err(get_error());
1490 }
1491 Ok(names
1492 .iter()
1493 .map(|&val| unsafe { CStr::from_ptr(val) }.to_str().unwrap())
1494 .collect())
1495 }
1496
1497 #[doc(alias = "SDL_Vulkan_CreateSurface")]
1503 pub fn vulkan_create_surface(&self, instance: VkInstance) -> Result<VkSurfaceKHR, String> {
1504 let mut surface: VkSurfaceKHR = 0;
1505 if unsafe { sys::SDL_Vulkan_CreateSurface(self.context.raw, instance, &mut surface) }
1506 == sys::SDL_bool::SDL_FALSE
1507 {
1508 Err(get_error())
1509 } else {
1510 Ok(surface)
1511 }
1512 }
1513
1514 #[doc(alias = "SDL_GetWindowDisplayIndex")]
1516 pub fn display_index(&self) -> Result<i32, String> {
1517 let result = unsafe { sys::SDL_GetWindowDisplayIndex(self.context.raw) };
1518 if result < 0 {
1519 Err(get_error())
1520 } else {
1521 Ok(result as i32)
1522 }
1523 }
1524
1525 #[doc(alias = "SDL_SetWindowDisplayMode")]
1530 pub fn set_display_mode<D>(&mut self, display_mode: D) -> Result<(), String>
1531 where
1532 D: Into<Option<DisplayMode>>,
1533 {
1534 unsafe {
1535 let result = sys::SDL_SetWindowDisplayMode(
1536 self.context.raw,
1537 match display_mode.into() {
1538 Some(ref mode) => &mode.to_ll(),
1539 None => ptr::null(),
1540 },
1541 );
1542 if result < 0 {
1543 Err(get_error())
1544 } else {
1545 Ok(())
1546 }
1547 }
1548 }
1549
1550 #[doc(alias = "SDL_GetWindowDisplayMode")]
1552 pub fn display_mode(&self) -> Result<DisplayMode, String> {
1553 let mut dm = mem::MaybeUninit::uninit();
1554
1555 let result =
1556 unsafe { sys::SDL_GetWindowDisplayMode(self.context.raw, dm.as_mut_ptr()) == 0 };
1557
1558 if result {
1559 let dm = unsafe { dm.assume_init() };
1560 Ok(DisplayMode::from_ll(&dm))
1561 } else {
1562 Err(get_error())
1563 }
1564 }
1565
1566 #[doc(alias = "SDL_GetWindowICCProfile")]
1568 pub fn icc_profile(&self) -> Result<Vec<u8>, String> {
1569 unsafe {
1570 let mut size: libc::size_t = 0;
1571 let data = sys::SDL_GetWindowICCProfile(self.context.raw, &mut size as *mut _);
1572 if data.is_null() {
1573 return Err(get_error());
1574 }
1575 let mut result = vec![0; size as usize];
1576 result.copy_from_slice(std::slice::from_raw_parts(data as *const u8, size as usize));
1577 sys::SDL_free(data);
1578 Ok(result)
1579 }
1580 }
1581
1582 #[doc(alias = "SDL_GetWindowPixelFormat")]
1584 pub fn window_pixel_format(&self) -> PixelFormatEnum {
1585 unsafe {
1586 PixelFormatEnum::try_from(sys::SDL_GetWindowPixelFormat(self.context.raw) as u32)
1587 .unwrap()
1588 }
1589 }
1590
1591 #[doc(alias = "SDL_GetWindowFlags")]
1592 pub fn window_flags(&self) -> u32 {
1593 unsafe { sys::SDL_GetWindowFlags(self.context.raw) }
1594 }
1595
1596 pub fn has_input_focus(&self) -> bool {
1598 0 != self.window_flags() & sys::SDL_WindowFlags::SDL_WINDOW_INPUT_FOCUS as u32
1599 }
1600
1601 pub fn has_input_grabbed(&self) -> bool {
1603 0 != self.window_flags() & sys::SDL_WindowFlags::SDL_WINDOW_INPUT_GRABBED as u32
1604 }
1605
1606 pub fn has_mouse_focus(&self) -> bool {
1608 0 != self.window_flags() & sys::SDL_WindowFlags::SDL_WINDOW_MOUSE_FOCUS as u32
1609 }
1610
1611 pub fn is_maximized(&self) -> bool {
1613 0 != self.window_flags() & sys::SDL_WindowFlags::SDL_WINDOW_MAXIMIZED as u32
1614 }
1615
1616 pub fn is_minimized(&self) -> bool {
1618 0 != self.window_flags() & sys::SDL_WindowFlags::SDL_WINDOW_MINIMIZED as u32
1619 }
1620
1621 pub fn is_always_on_top(&self) -> bool {
1623 0 != self.window_flags() & sys::SDL_WindowFlags::SDL_WINDOW_ALWAYS_ON_TOP as u32
1624 }
1625
1626 #[doc(alias = "SDL_SetWindowResizable")]
1628 pub fn set_resizable(&mut self, resizable: bool) {
1629 let resizable = if resizable {
1630 sys::SDL_bool::SDL_TRUE
1631 } else {
1632 sys::SDL_bool::SDL_FALSE
1633 };
1634 unsafe {
1635 sys::SDL_SetWindowResizable(self.context.raw, resizable);
1636 }
1637 }
1638
1639 pub fn set_window_shape_alpha<S: AsRef<SurfaceRef>>(
1646 &mut self,
1647 shape: S,
1648 binarization_cutoff: u8,
1649 ) -> Result<(), i32> {
1650 let mode = sys::WindowShapeMode::ShapeModeBinarizeAlpha;
1651 let parameters = sys::SDL_WindowShapeParams {
1652 binarizationCutoff: binarization_cutoff,
1653 };
1654 let mut shape_mode = sys::SDL_WindowShapeMode { mode, parameters };
1655 let result = unsafe {
1656 sys::SDL_SetWindowShape(self.context.raw, shape.as_ref().raw(), &mut shape_mode)
1657 };
1658 if result == 0 {
1659 Ok(())
1660 } else {
1661 Err(result)
1662 }
1663 }
1664
1665 #[doc(alias = "SDL_SetWindowTitle")]
1667 pub fn set_title(&mut self, title: &str) -> Result<(), NulError> {
1668 let title = CString::new(title)?;
1669 unsafe {
1670 sys::SDL_SetWindowTitle(self.context.raw, title.as_ptr() as *const c_char);
1671 }
1672 Ok(())
1673 }
1674 #[doc(alias = "SDL_GetWindowTitle")]
1676 pub fn title(&self) -> &str {
1677 unsafe {
1678 let buf = sys::SDL_GetWindowTitle(self.context.raw);
1679
1680 CStr::from_ptr(buf as *const _).to_str().unwrap()
1682 }
1683 }
1684
1685 #[doc(alias = "SDL_SetWindowIcon")]
1696 pub fn set_icon<S: AsRef<SurfaceRef>>(&mut self, icon: S) {
1697 unsafe { sys::SDL_SetWindowIcon(self.context.raw, icon.as_ref().raw()) }
1698 }
1699
1700 #[doc(alias = "SDL_SetWindowPosition")]
1706 pub fn set_position(&mut self, x: WindowPos, y: WindowPos) {
1707 unsafe {
1708 sys::SDL_SetWindowPosition(self.context.raw, to_ll_windowpos(x), to_ll_windowpos(y))
1709 }
1710 }
1711
1712 #[doc(alias = "SDL_GetWindowPosition")]
1714 pub fn position(&self) -> (i32, i32) {
1715 let mut x: c_int = 0;
1716 let mut y: c_int = 0;
1717 unsafe { sys::SDL_GetWindowPosition(self.context.raw, &mut x, &mut y) };
1718 (x as i32, y as i32)
1719 }
1720
1721 #[doc(alias = "SDL_GetWindowBordersSize")]
1726 pub fn border_size(&self) -> Result<(u16, u16, u16, u16), String> {
1727 let mut top: c_int = 0;
1728 let mut left: c_int = 0;
1729 let mut bottom: c_int = 0;
1730 let mut right: c_int = 0;
1731 let result = unsafe {
1732 sys::SDL_GetWindowBordersSize(
1733 self.context.raw,
1734 &mut top,
1735 &mut left,
1736 &mut bottom,
1737 &mut right,
1738 )
1739 };
1740 if result < 0 {
1741 Err(get_error())
1742 } else {
1743 Ok((top as u16, left as u16, bottom as u16, right as u16))
1744 }
1745 }
1746
1747 #[doc(alias = "SDL_SetWindowSize")]
1749 pub fn set_size(&mut self, width: u32, height: u32) -> Result<(), IntegerOrSdlError> {
1750 let w = validate_int(width, "width")?;
1751 let h = validate_int(height, "height")?;
1752 unsafe {
1753 sys::SDL_SetWindowSize(self.context.raw, w, h);
1754 }
1755 Ok(())
1756 }
1757
1758 #[doc(alias = "SDL_GetWindowSize")]
1760 pub fn size(&self) -> (u32, u32) {
1761 let mut w: c_int = 0;
1762 let mut h: c_int = 0;
1763 unsafe { sys::SDL_GetWindowSize(self.context.raw, &mut w, &mut h) };
1764 (w as u32, h as u32)
1765 }
1766
1767 #[doc(alias = "SDL_GL_GetDrawableSize")]
1772 pub fn drawable_size(&self) -> (u32, u32) {
1773 let mut w: c_int = 0;
1774 let mut h: c_int = 0;
1775 unsafe { sys::SDL_GL_GetDrawableSize(self.context.raw, &mut w, &mut h) };
1776 (w as u32, h as u32)
1777 }
1778
1779 #[doc(alias = "SDL_Vulkan_GetDrawableSize")]
1784 pub fn vulkan_drawable_size(&self) -> (u32, u32) {
1785 let mut w: c_int = 0;
1786 let mut h: c_int = 0;
1787 unsafe { sys::SDL_Vulkan_GetDrawableSize(self.context.raw, &mut w, &mut h) };
1788 (w as u32, h as u32)
1789 }
1790
1791 #[doc(alias = "SDL_SetWindowMinimumSize")]
1793 pub fn set_minimum_size(&mut self, width: u32, height: u32) -> Result<(), IntegerOrSdlError> {
1794 let w = validate_int(width, "width")?;
1795 let h = validate_int(height, "height")?;
1796 unsafe {
1797 sys::SDL_SetWindowMinimumSize(self.context.raw, w, h);
1798 }
1799 Ok(())
1800 }
1801
1802 #[doc(alias = "SDL_GetWindowMinimumSize")]
1804 pub fn minimum_size(&self) -> (u32, u32) {
1805 let mut w: c_int = 0;
1806 let mut h: c_int = 0;
1807 unsafe { sys::SDL_GetWindowMinimumSize(self.context.raw, &mut w, &mut h) };
1808 (w as u32, h as u32)
1809 }
1810
1811 #[doc(alias = "SDL_SetWindowMaximumSize")]
1813 pub fn set_maximum_size(&mut self, width: u32, height: u32) -> Result<(), IntegerOrSdlError> {
1814 let w = validate_int(width, "width")?;
1815 let h = validate_int(height, "height")?;
1816 unsafe {
1817 sys::SDL_SetWindowMaximumSize(self.context.raw, w, h);
1818 }
1819 Ok(())
1820 }
1821
1822 #[doc(alias = "SDL_GetWindowMaximumSize")]
1824 pub fn maximum_size(&self) -> (u32, u32) {
1825 let mut w: c_int = 0;
1826 let mut h: c_int = 0;
1827 unsafe { sys::SDL_GetWindowMaximumSize(self.context.raw, &mut w, &mut h) };
1828 (w as u32, h as u32)
1829 }
1830
1831 #[doc(alias = "SDL_SetWindowBordered")]
1835 pub fn set_bordered(&mut self, bordered: bool) {
1836 unsafe {
1837 sys::SDL_SetWindowBordered(
1838 self.context.raw,
1839 if bordered {
1840 sys::SDL_bool::SDL_TRUE
1841 } else {
1842 sys::SDL_bool::SDL_FALSE
1843 },
1844 )
1845 }
1846 }
1847
1848 #[doc(alias = "SDL_ShowWindow")]
1850 pub fn show(&mut self) {
1851 unsafe { sys::SDL_ShowWindow(self.context.raw) }
1852 }
1853
1854 #[doc(alias = "SDL_HideWindow")]
1856 pub fn hide(&mut self) {
1857 unsafe { sys::SDL_HideWindow(self.context.raw) }
1858 }
1859
1860 #[doc(alias = "SDL_RaiseWindow")]
1862 pub fn raise(&mut self) {
1863 unsafe { sys::SDL_RaiseWindow(self.context.raw) }
1864 }
1865
1866 #[doc(alias = "SDL_MaximizeWindow")]
1868 pub fn maximize(&mut self) {
1869 unsafe { sys::SDL_MaximizeWindow(self.context.raw) }
1870 }
1871
1872 #[doc(alias = "SDL_MinimizeWindow")]
1874 pub fn minimize(&mut self) {
1875 unsafe { sys::SDL_MinimizeWindow(self.context.raw) }
1876 }
1877
1878 #[doc(alias = "SDL_RestoreWindow")]
1880 pub fn restore(&mut self) {
1881 unsafe { sys::SDL_RestoreWindow(self.context.raw) }
1882 }
1883
1884 pub fn fullscreen_state(&self) -> FullscreenType {
1886 FullscreenType::from_window_flags(self.window_flags())
1887 }
1888
1889 #[doc(alias = "SDL_SetWindowFullscreen")]
1891 pub fn set_fullscreen(&mut self, fullscreen_type: FullscreenType) -> Result<(), String> {
1892 unsafe {
1893 let result = sys::SDL_SetWindowFullscreen(self.context.raw, fullscreen_type as u32);
1894 if result == 0 {
1895 Ok(())
1896 } else {
1897 Err(get_error())
1898 }
1899 }
1900 }
1901
1902 #[doc(alias = "SDL_GetWindowSurface")]
1915 pub fn surface<'a>(&'a self, _e: &'a EventPump) -> Result<WindowSurfaceRef<'a>, String> {
1916 let raw = unsafe { sys::SDL_GetWindowSurface(self.context.raw) };
1917
1918 if raw.is_null() {
1919 Err(get_error())
1920 } else {
1921 let surface_ref = unsafe { SurfaceRef::from_ll_mut(raw) };
1922 Ok(WindowSurfaceRef(surface_ref, self))
1923 }
1924 }
1925
1926 #[doc(alias = "SDL_SetWindowGrab")]
1928 pub fn set_grab(&mut self, grabbed: bool) {
1929 unsafe {
1930 sys::SDL_SetWindowGrab(
1931 self.context.raw,
1932 if grabbed {
1933 sys::SDL_bool::SDL_TRUE
1934 } else {
1935 sys::SDL_bool::SDL_FALSE
1936 },
1937 )
1938 }
1939 }
1940
1941 #[doc(alias = "SDL_SetWindowKeyboardGrab")]
1947 pub fn set_keyboard_grab(&mut self, grabbed: bool) {
1948 unsafe {
1949 sys::SDL_SetWindowKeyboardGrab(
1950 self.context.raw,
1951 if grabbed {
1952 sys::SDL_bool::SDL_TRUE
1953 } else {
1954 sys::SDL_bool::SDL_FALSE
1955 },
1956 )
1957 }
1958 }
1959
1960 #[doc(alias = "SDL_SetWindowMouseGrab")]
1962 pub fn set_mouse_grab(&mut self, grabbed: bool) {
1963 unsafe {
1964 sys::SDL_SetWindowMouseGrab(
1965 self.context.raw,
1966 if grabbed {
1967 sys::SDL_bool::SDL_TRUE
1968 } else {
1969 sys::SDL_bool::SDL_FALSE
1970 },
1971 )
1972 }
1973 }
1974
1975 #[doc(alias = "SDL_GetWindowGrab")]
1977 pub fn grab(&self) -> bool {
1978 unsafe { sys::SDL_GetWindowGrab(self.context.raw) == sys::SDL_bool::SDL_TRUE }
1979 }
1980
1981 #[doc(alias = "SDL_GetWindowKeyboardGrab")]
1983 pub fn keyboard_grab(&self) -> bool {
1984 unsafe { sys::SDL_GetWindowKeyboardGrab(self.context.raw) == sys::SDL_bool::SDL_TRUE }
1985 }
1986
1987 #[doc(alias = "SDL_GetWindowMouseGrab")]
1989 pub fn mouse_grab(&self) -> bool {
1990 unsafe { sys::SDL_GetWindowMouseGrab(self.context.raw) == sys::SDL_bool::SDL_TRUE }
1991 }
1992
1993 #[doc(alias = "SDL_SetWindowMouseRect")]
1997 pub fn set_mouse_rect<R>(&self, rect: R) -> Result<(), String>
1998 where
1999 R: Into<Option<Rect>>,
2000 {
2001 let rect = rect.into();
2002 let rect_raw_ptr = match rect {
2003 Some(ref rect) => rect.raw(),
2004 None => ptr::null(),
2005 };
2006
2007 unsafe {
2008 if sys::SDL_SetWindowMouseRect(self.context.raw, rect_raw_ptr) == 0 {
2009 Ok(())
2010 } else {
2011 Err(get_error())
2012 }
2013 }
2014 }
2015
2016 #[doc(alias = "SDL_GetWindowMouseRect")]
2020 pub fn mouse_rect(&self) -> Option<Rect> {
2021 unsafe {
2022 let raw_rect = sys::SDL_GetWindowMouseRect(self.context.raw);
2023 if raw_rect.is_null() {
2024 None
2025 } else {
2026 Some(Rect::new(
2027 (*raw_rect).x,
2028 (*raw_rect).y,
2029 (*raw_rect).w as u32,
2030 (*raw_rect).h as u32,
2031 ))
2032 }
2033 }
2034 }
2035
2036 #[doc(alias = "SDL_SetWindowBrightness")]
2043 pub fn set_brightness(&mut self, brightness: f64) -> Result<(), String> {
2044 unsafe {
2045 if sys::SDL_SetWindowBrightness(self.context.raw, brightness as c_float) == 0 {
2046 Ok(())
2047 } else {
2048 Err(get_error())
2049 }
2050 }
2051 }
2052
2053 #[doc(alias = "SDL_GetWindowBrightness")]
2054 pub fn brightness(&self) -> f64 {
2055 unsafe { sys::SDL_GetWindowBrightness(self.context.raw) as f64 }
2056 }
2057
2058 #[doc(alias = "SDL_SetWindowGammaRamp")]
2065 pub fn set_gamma_ramp<'a, 'b, 'c, R, G, B>(
2066 &mut self,
2067 red: R,
2068 green: G,
2069 blue: B,
2070 ) -> Result<(), String>
2071 where
2072 R: Into<Option<&'a [u16; 256]>>,
2073 G: Into<Option<&'b [u16; 256]>>,
2074 B: Into<Option<&'c [u16; 256]>>,
2075 {
2076 let unwrapped_red = match red.into() {
2077 Some(values) => values.as_ptr(),
2078 None => ptr::null(),
2079 };
2080 let unwrapped_green = match green.into() {
2081 Some(values) => values.as_ptr(),
2082 None => ptr::null(),
2083 };
2084 let unwrapped_blue = match blue.into() {
2085 Some(values) => values.as_ptr(),
2086 None => ptr::null(),
2087 };
2088 let result = unsafe {
2089 sys::SDL_SetWindowGammaRamp(
2090 self.context.raw,
2091 unwrapped_red,
2092 unwrapped_green,
2093 unwrapped_blue,
2094 )
2095 };
2096 if result != 0 {
2097 Err(get_error())
2098 } else {
2099 Ok(())
2100 }
2101 }
2102
2103 #[allow(clippy::type_complexity)]
2109 #[doc(alias = "SDL_GetWindowGammaRamp")]
2110 pub fn gamma_ramp(&self) -> Result<(Vec<u16>, Vec<u16>, Vec<u16>), String> {
2111 let mut red: Vec<u16> = vec![0; 256];
2112 let mut green: Vec<u16> = vec![0; 256];
2113 let mut blue: Vec<u16> = vec![0; 256];
2114 let result = unsafe {
2115 sys::SDL_GetWindowGammaRamp(
2116 self.context.raw,
2117 red.as_mut_ptr(),
2118 green.as_mut_ptr(),
2119 blue.as_mut_ptr(),
2120 )
2121 };
2122 if result == 0 {
2123 Ok((red, green, blue))
2124 } else {
2125 Err(get_error())
2126 }
2127 }
2128
2129 #[doc(alias = "SDL_GetWindowGammaRamp")]
2135 pub fn gamma_ramp_arrays(&self) -> Result<[[u16; 256]; 3], String> {
2136 let [mut red, mut green, mut blue] = [mem::MaybeUninit::<[u16; 256]>::uninit(); 3];
2137 let result = unsafe {
2138 sys::SDL_GetWindowGammaRamp(
2139 self.context.raw,
2140 red.as_mut_ptr().cast::<u16>(),
2141 green.as_mut_ptr().cast::<u16>(),
2142 blue.as_mut_ptr().cast::<u16>(),
2143 )
2144 };
2145 if result == 0 {
2146 Ok(unsafe { [red.assume_init(), green.assume_init(), blue.assume_init()] })
2147 } else {
2148 Err(get_error())
2149 }
2150 }
2151
2152 #[doc(alias = "SDL_SetWindowOpacity")]
2157 pub fn set_opacity(&mut self, opacity: f32) -> Result<(), String> {
2158 let result = unsafe { sys::SDL_SetWindowOpacity(self.context.raw, opacity) };
2159 if result < 0 {
2160 Err(get_error())
2161 } else {
2162 Ok(())
2163 }
2164 }
2165
2166 #[doc(alias = "SDL_GetWindowOpacity")]
2172 pub fn opacity(&self) -> Result<f32, String> {
2173 let mut opacity = 0.0;
2174 let result = unsafe { sys::SDL_GetWindowOpacity(self.context.raw, &mut opacity) };
2175 if result < 0 {
2176 Err(get_error())
2177 } else {
2178 Ok(opacity)
2179 }
2180 }
2181
2182 #[doc(alias = "SDL_FlashWindow")]
2184 pub fn flash(&mut self, operation: FlashOperation) -> Result<(), String> {
2185 let result = unsafe { sys::SDL_FlashWindow(self.context.raw, operation.to_ll()) };
2186 if result == 0 {
2187 Ok(())
2188 } else {
2189 Err(get_error())
2190 }
2191 }
2192
2193 #[doc(alias = "SDL_SetWindowAlwaysOnTop")]
2195 pub fn set_always_on_top(&mut self, on_top: bool) {
2196 unsafe {
2197 sys::SDL_SetWindowAlwaysOnTop(
2198 self.context.raw,
2199 if on_top {
2200 sys::SDL_bool::SDL_TRUE
2201 } else {
2202 sys::SDL_bool::SDL_FALSE
2203 },
2204 )
2205 };
2206 }
2207}
2208
2209#[derive(Copy, Clone)]
2210#[doc(alias = "SDL_GetVideoDriver")]
2211pub struct DriverIterator {
2212 length: i32,
2213 index: i32,
2214}
2215
2216fn get_video_driver(index: i32) -> &'static str {
2220 use std::str;
2221
2222 unsafe {
2223 let buf = sys::SDL_GetVideoDriver(index);
2224 assert!(!buf.is_null());
2225
2226 str::from_utf8(CStr::from_ptr(buf as *const _).to_bytes()).unwrap()
2227 }
2228}
2229
2230impl Iterator for DriverIterator {
2231 type Item = &'static str;
2232
2233 #[inline]
2234 fn next(&mut self) -> Option<&'static str> {
2235 if self.index >= self.length {
2236 None
2237 } else {
2238 let driver = get_video_driver(self.index);
2239 self.index += 1;
2240
2241 Some(driver)
2242 }
2243 }
2244
2245 #[inline]
2246 fn size_hint(&self) -> (usize, Option<usize>) {
2247 let remaining = (self.length - self.index) as usize;
2248 (remaining, Some(remaining))
2249 }
2250
2251 #[inline]
2252 fn nth(&mut self, n: usize) -> Option<&'static str> {
2253 use std::convert::TryInto;
2254
2255 self.index = match n.try_into().ok().and_then(|n| self.index.checked_add(n)) {
2256 Some(index) if index < self.length => index,
2257 _ => self.length,
2258 };
2259
2260 self.next()
2261 }
2262}
2263
2264impl DoubleEndedIterator for DriverIterator {
2265 #[inline]
2266 fn next_back(&mut self) -> Option<&'static str> {
2267 if self.index >= self.length {
2268 None
2269 } else {
2270 self.length -= 1;
2271
2272 Some(get_video_driver(self.length))
2273 }
2274 }
2275
2276 #[inline]
2277 fn nth_back(&mut self, n: usize) -> Option<&'static str> {
2278 use std::convert::TryInto;
2279
2280 self.length = match n.try_into().ok().and_then(|n| self.length.checked_sub(n)) {
2281 Some(length) if length > self.index => length,
2282 _ => self.index,
2283 };
2284
2285 self.next_back()
2286 }
2287}
2288
2289impl ExactSizeIterator for DriverIterator {}
2290
2291impl std::iter::FusedIterator for DriverIterator {}
2292
2293#[inline]
2295#[doc(alias = "SDL_GetVideoDriver")]
2296pub fn drivers() -> DriverIterator {
2297 DriverIterator {
2302 length: unsafe { sys::SDL_GetNumVideoDrivers() },
2303 index: 0,
2304 }
2305}
2306
2307#[doc(alias = "SDL_CalculateGammaRamp")]
2308pub fn calculate_gamma_ramp(gamma: f32) -> [u16; 256] {
2309 unsafe {
2310 let mut ret = mem::MaybeUninit::<[u16; 256]>::uninit();
2311 sys::SDL_CalculateGammaRamp(gamma as c_float, ret.as_mut_ptr().cast::<u16>());
2312 ret.assume_init()
2313 }
2314}