1 /++
2  + Authors: Avaxar <avaxar@nekkl.org>
3  + Copyright: Copyright © 2023, Avaxar
4  + License: $(LINK2 https://mit-license.org, MIT License)
5  +/
6 
7 module dsdl2.window;
8 @safe:
9 
10 import bindbc.sdl;
11 import dsdl2.sdl;
12 import dsdl2.display;
13 import dsdl2.pixels;
14 import dsdl2.rect;
15 import dsdl2.renderer;
16 import dsdl2.surface;
17 
18 import core.memory : GC;
19 import std.conv : to;
20 import std.format : format;
21 import std.string : toStringz;
22 import std.typecons : Nullable, nullable;
23 
24 /++
25  + D enum that wraps `SDL_WINDOWPOS_*` to specify certain state of position in `dsdl2.Window` construction
26  +/
27 enum WindowPos : uint {
28     centered = SDL_WINDOWPOS_CENTERED, /// Wraps `SDL_WINDOWPOS_CENTERED` which sets the window to be in the center
29     undefined = SDL_WINDOWPOS_UNDEFINED /// Wraps `SDL_WINDOWPOS_UNDEFINED` which leaves the window's position undefined
30 }
31 
32 private uint toSDLWindowFlags(bool fullscreen, bool fullscreenDesktop, bool openGL, bool shown, bool hidden,
33     bool borderless, bool resizable, bool minimized, bool maximized, bool inputGrabbed, bool inputFocus,
34     bool mouseFocus, bool foreign, bool allowHighDPI, bool mouseCapture, bool alwaysOnTop, bool skipTaskbar,
35     bool utility, bool tooltip, bool popupMenu, bool vulkan, bool metal, bool mouseGrabbed, bool keyboardGrabbed)
36 in {
37     static if (sdlSupport < SDLSupport.v2_0_1) {
38         assert(allowHighDPI == false);
39     }
40     else {
41         if (allowHighDPI) {
42             assert(getVersion() >= Version(2, 0, 1));
43         }
44     }
45 
46     static if (sdlSupport < SDLSupport.v2_0_4) {
47         assert(mouseCapture == false);
48     }
49     else {
50         if (mouseCapture) {
51             assert(getVersion() >= Version(2, 0, 4));
52         }
53     }
54 
55     static if (sdlSupport < SDLSupport.v2_0_5) {
56         assert(alwaysOnTop == false);
57         assert(skipTaskbar == false);
58         assert(utility == false);
59         assert(tooltip == false);
60         assert(popupMenu == false);
61     }
62     else {
63         if (alwaysOnTop || skipTaskbar || utility || tooltip || popupMenu) {
64             assert(getVersion() >= Version(2, 0, 5));
65         }
66     }
67 
68     static if (sdlSupport < SDLSupport.v2_0_6) {
69         assert(vulkan == false);
70         assert(metal == false);
71     }
72     else {
73         if (vulkan || metal) {
74             assert(getVersion() >= Version(2, 0, 6));
75         }
76     }
77 
78     static if (sdlSupport < SDLSupport.v2_0_16) {
79         assert(mouseGrabbed == false);
80         assert(keyboardGrabbed == false);
81     }
82     else {
83         if (mouseGrabbed || keyboardGrabbed) {
84             assert(getVersion() >= Version(2, 0, 16));
85         }
86     }
87 }
88 do {
89     uint flags = 0;
90 
91     flags |= fullscreen ? SDL_WINDOW_FULLSCREEN : 0;
92     flags |= fullscreenDesktop ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0;
93     flags |= openGL ? SDL_WINDOW_OPENGL : 0;
94     flags |= shown ? SDL_WINDOW_SHOWN : 0;
95     flags |= hidden ? SDL_WINDOW_HIDDEN : 0;
96     flags |= borderless ? SDL_WINDOW_BORDERLESS : 0;
97     flags |= resizable ? SDL_WINDOW_RESIZABLE : 0;
98     flags |= minimized ? SDL_WINDOW_MINIMIZED : 0;
99     flags |= maximized ? SDL_WINDOW_MAXIMIZED : 0;
100     flags |= inputGrabbed ? SDL_WINDOW_INPUT_GRABBED : 0;
101     flags |= inputFocus ? SDL_WINDOW_INPUT_FOCUS : 0;
102     flags |= mouseFocus ? SDL_WINDOW_MOUSE_FOCUS : 0;
103     flags |= foreign ? SDL_WINDOW_FOREIGN : 0;
104 
105     static if (sdlSupport >= SDLSupport.v2_0_1) {
106         flags |= allowHighDPI ? SDL_WINDOW_ALLOW_HIGHDPI : 0;
107     }
108     static if (sdlSupport >= SDLSupport.v2_0_4) {
109         flags |= mouseCapture ? SDL_WINDOW_MOUSE_CAPTURE : 0;
110     }
111     static if (sdlSupport >= SDLSupport.v2_0_5) {
112         flags |= alwaysOnTop ? SDL_WINDOW_ALWAYS_ON_TOP : 0;
113         flags |= skipTaskbar ? SDL_WINDOW_SKIP_TASKBAR : 0;
114         flags |= utility ? SDL_WINDOW_UTILITY : 0;
115         flags |= tooltip ? SDL_WINDOW_TOOLTIP : 0;
116         flags |= popupMenu ? SDL_WINDOW_POPUP_MENU : 0;
117     }
118     static if (sdlSupport >= SDLSupport.v2_0_6) {
119         flags |= vulkan ? SDL_WINDOW_VULKAN : 0;
120         flags |= metal ? SDL_WINDOW_METAL : 0;
121     }
122     static if (sdlSupport >= SDLSupport.v2_0_16) {
123         flags |= mouseGrabbed ? SDL_WINDOW_MOUSE_GRABBED : 0;
124         flags |= keyboardGrabbed ? SDL_WINDOW_KEYBOARD_GRABBED : 0;
125     }
126 
127     return flags;
128 }
129 
130 static if (sdlSupport >= SDLSupport.v2_0_16) {
131     /++
132      + D enum that wraps `SDL_FlashOperation` (from SDL 2.0.16) defining window flashing operations
133      +/
134     enum FlashOperation {
135         /++
136          + Wraps `SDL_FLASH_*` enumeration constants
137          +/
138         cancel = SDL_FLASH_CANCEL,
139         briefly = SDL_FLASH_BRIEFLY, /// ditto
140         untilFocused = SDL_FLASH_UNTIL_FOCUSED /// ditto
141     }
142 }
143 
144 /++
145  + D class that wraps `SDL_Window` managing a window instance specific to the OS
146  +
147  + `dsdl2.Window` provides access to creating windows and managing them for rendering. Internally, SDL uses
148  + OS functions to summon the window.
149  +
150  + Example:
151  + ---
152  + auto window = new dsdl2.Window("My Window", [dsdl2.WindowPos.centered, dsdl2.WindowPos.centered], [800, 600]);
153  + window.surface.fill(dsdl2.Color(255, 0, 0));
154  + window.update();
155  + ---
156  +/
157 final class Window {
158     private PixelFormat pixelFormatProxy = null;
159     private Surface surfaceProxy = null;
160     private bool isOwner = true;
161     private void* userRef = null;
162 
163     @system SDL_Window* sdlWindow = null; /// Internal `SDL_Window` pointer
164 
165     /++
166      + Constructs a `dsdl2.Window` from a vanilla `SDL_Window*` from bindbc-sdl
167      +
168      + Params:
169      +   sdlWindow = the `SDL_Window` pointer to manage
170      +   isOwner = whether the instance owns the given `SDL_Window*` and should destroy it on its own
171      +   userRef = optional pointer to maintain reference link, avoiding GC cleanup
172      +/
173     this(SDL_Window* sdlWindow, bool isOwner = true, void* userRef = null) @system
174     in {
175         assert(sdlWindow !is null);
176     }
177     do {
178         this.sdlWindow = sdlWindow;
179         this.isOwner = isOwner;
180         this.userRef = userRef;
181     }
182 
183     /++
184      + Creates an SDL-handled window from a native pointer handle of the OS, which wraps `SDL_CreateWindowFrom`
185      +
186      + Params:
187      +   nativeHandle = pointer to the native OS window
188      + Throws: `dsdl2.SDLException` if window creation failed
189      +/
190     this(void* nativeHandle) @system
191     in {
192         assert(nativeHandle !is null);
193     }
194     do {
195         this.sdlWindow = SDL_CreateWindowFrom(nativeHandle);
196         if (this.sdlWindow is null) {
197             throw new SDLException;
198         }
199     }
200 
201     /++
202      + Creates a window on the desktop placed at a coordinate in the screen, which wraps `SDL_CreateWindow`
203      +
204      + Params:
205      +   title = title given to the shown window
206      +   position = top-left position of the window in the desktop environment (pair of two `uint`s or flags from
207      +              `dsdl2.WindowPos`)
208      +   size = size of the window in pixels
209      +   shaped = `true` to use `SDL_CreateShapedWindow`; `false` to use `SDL_CreateWindow` instead
210      +   fullscreen = adds `SDL_WINDOW_FULLSCREEN` flag
211      +   fullscreenDesktop = adds `SDL_WINDOW_FULLSCREEN_DESKTOP` flag
212      +   openGL = adds `SDL_WINDOW_OPENGL` flag
213      +   shown = adds `SDL_WINDOW_SHOWN` flag
214      +   hidden = adds `SDL_WINDOW_HIDDEN` flag
215      +   borderless = adds `SDL_WINDOW_BORDERLESS` flag
216      +   resizable = adds `SDL_WINDOW_RESIZABLE` flag
217      +   minimized = adds `SDL_WINDOW_MINIMIZED` flag
218      +   maximized = adds `SDL_WINDOW_MAXIMIZED` flag
219      +   inputGrabbed = adds `SDL_WINDOW_INPUT_GRABBED` flag
220      +   inputFocus = adds `SDL_WINDOW_INPUT_FOCUS` flag
221      +   mouseFocus = adds `SDL_WINDOW_MOUSE_FOCUS` flag
222      +   foreign = adds `SDL_WINDOW_FOREIGN` flag
223      +   allowHighDPI = adds `SDL_WINDOW_ALLOW_HIGHDPI` flag (from SDL 2.0.1)
224      +   mouseCapture = adds `SDL_WINDOW_MOUSE_CAPTURE` flag (from SDL 2.0.2)
225      +   alwaysOnTop = adds `SDL_WINDOW_ALWAYS_ON_TOP` flag (from SDL 2.0.5)
226      +   skipTaskbar = adds `SDL_WINDOW_SKIP_TASKBAR` flag (from SDL 2.0.5)
227      +   utility = adds `SDL_WINDOW_UTILITY` flag (from SDL 2.0.5)
228      +   tooltip = adds `SDL_WINDOW_TOOLTIP` flag (from SDL 2.0.5)
229      +   popupMenu = adds `SDL_WINDOW_POPUP_MENU` flag (from SDL 2.0.5)
230      +   vulkan = adds `SDL_WINDOW_VULKAN` flag (from SDL 2.0.6)
231      +   metal = adds `SDL_WINDOW_METAL` flag (from SDL 2.0.6)
232      +   mouseGrabbed = adds `SDL_WINDOW_MOUSE_GRABBED` flag (from SDL 2.0.16)
233      +   keyboardGrabbed = adds `SDL_WINDOW_KEYBOARD_GRABBED` flag (from SDL 2.0.16)
234      + Throws: `dsdl2.SDLException` if window creation failed
235      +/
236     this(string title, uint[2] position, uint[2] size, bool shaped = false, bool fullscreen = false,
237         bool fullscreenDesktop = false, bool openGL = false, bool shown = false, bool hidden = false,
238         bool borderless = false, bool resizable = false, bool minimized = false, bool maximized = false,
239         bool inputGrabbed = false, bool inputFocus = false, bool mouseFocus = false, bool foreign = false,
240         bool allowHighDPI = false, bool mouseCapture = false, bool alwaysOnTop = false, bool skipTaskbar = false,
241         bool utility = false, bool tooltip = false, bool popupMenu = false, bool vulkan = false, bool metal = false,
242         bool mouseGrabbed = false, bool keyboardGrabbed = false) @trusted
243     in {
244         assert(title !is null);
245     }
246     do {
247         uint flags = toSDLWindowFlags(fullscreen, fullscreenDesktop, openGL, shown, hidden, borderless, resizable,
248             minimized, maximized, inputGrabbed, inputFocus, mouseFocus, foreign, allowHighDPI, mouseCapture,
249             alwaysOnTop, skipTaskbar, utility, tooltip, popupMenu, vulkan, metal, mouseGrabbed, keyboardGrabbed);
250 
251         if (shaped) {
252             this.sdlWindow = SDL_CreateShapedWindow(title.toStringz(), position[0].to!int, position[1].to!int,
253                 size[0].to!int, size[1].to!int, flags);
254         }
255         else {
256             this.sdlWindow = SDL_CreateWindow(title.toStringz(), position[0].to!int, position[1].to!int,
257                 size[0].to!int, size[1].to!int, flags);
258         }
259 
260         if (this.sdlWindow is null) {
261             throw new SDLException;
262         }
263     }
264 
265     ~this() @trusted {
266         if (this.isOwner) {
267             SDL_DestroyWindow(this.sdlWindow);
268         }
269     }
270 
271     @trusted invariant { // @suppress(dscanner.trust_too_much)
272         // Instance might be in an invalid state due to holding a non-owned externally-freed object when
273         // destructed in an unpredictable order.
274         if (!this.isOwner && GC.inFinalizer) {
275             return;
276         }
277 
278         assert(this.sdlWindow !is null);
279     }
280 
281     /++
282      + Equality operator overload
283      +/
284     bool opEquals(const Window rhs) const @trusted {
285         return this.sdlWindow is rhs.sdlWindow;
286     }
287 
288     /++
289      + Gets the hash of the `dsdl2.Window`
290      +
291      + Returns: unique hash for the instance being the pointer of the internal `SDL_Window` pointer
292      +/
293     override hash_t toHash() const @trusted {
294         return cast(hash_t) this.sdlWindow;
295     }
296 
297     /++
298      + Formats the `dsdl2.Window` into its construction representation: `"dsdl2.Window(<sdlWindow>)"`
299      +
300      + Returns: the formatted `string`
301      +/
302     override string toString() const @trusted {
303         return "dsdl2.Window(0x%x)".format(this.sdlWindow);
304     }
305 
306     /++
307      + Wraps `SDL_GetWindowID` which gets the internal window ID of the `dsdl2.Window`
308      +
309      + Returns: `uint` of the internal window ID
310      +/
311     uint id() const @property @trusted {
312         return SDL_GetWindowID(cast(SDL_Window*) this.sdlWindow);
313     }
314 
315     /++
316      + Wraps `SDL_GetWindowDisplayIndex` which gets the display where the center of the window is located
317      +
318      + Returns: `dsdl2.Display` of the display the window is located
319      + Throws: `dsdl2.SDLException` if failed to get the display
320      +/
321     const(Display) display() const @property @trusted {
322         int index = SDL_GetWindowDisplayIndex(cast(SDL_Window*) this.sdlWindow);
323         if (index < 0) {
324             throw new SDLException;
325         }
326 
327         return getDisplays()[index];
328     }
329 
330     /++
331      + Wraps `SDL_GetWindowDisplayMode` which gets the window's display mode attributes
332      +
333      + Returns: `dsdl2.DisplayMode` storing the attributes
334      + Throws: `dsdl2.SDLException` if failed to get the display mode
335      +/
336     DisplayMode displayMode() const @property @trusted {
337         SDL_DisplayMode sdlMode = void;
338         if (SDL_GetWindowDisplayMode(cast(SDL_Window*) this.sdlWindow, &sdlMode) != 0) {
339             throw new SDLException;
340         }
341 
342         return DisplayMode(sdlMode);
343     }
344 
345     /++
346      + Wraps `SDL_SetWindowDisplayMode` which sets new display mode attributes to the window
347      +
348      + Params:
349      +   newDisplayMode = `dsdl2.DisplayMode` containing the desired attributes
350      + Throws: `dsdl2.SDLException` if failed to set the display mode
351      +/
352     void displayMode(DisplayMode newDisplayMode) @property @trusted {
353         SDL_DisplayMode sdlMode = newDisplayMode.sdlDisplayMode;
354         if (SDL_SetWindowDisplayMode(this.sdlWindow, &sdlMode) != 0) {
355             throw new SDLException;
356         }
357     }
358 
359     /++
360      + Gets the `dsdl2.PixelFormat` used for pixel data of the window
361      +
362      + Returns: read-only `dsdl2.PixelFormat` instance
363      +/
364     const(PixelFormat) pixelFormat() const @property @trusted {
365         // If the internal pixel format pointer happens to change, rewire the proxy.
366         if (this.pixelFormatProxy is null ||
367             this.pixelFormatProxy.sdlPixelFormatEnum !is SDL_GetWindowPixelFormat(cast(SDL_Window*) this.sdlWindow)) {
368             (cast(Window) this).pixelFormatProxy =
369                 new PixelFormat(SDL_GetWindowPixelFormat(cast(SDL_Window*) this.sdlWindow));
370         }
371 
372         return this.pixelFormatProxy;
373     }
374 
375     /++
376      + Wraps `SDL_GetRenderer` which gets the renderer of the window
377      +
378      + Returns: `dsdl2.Renderer` proxy
379      +/
380     inout(Renderer) renderer() inout @property @trusted {
381         if (SDL_Renderer* sdlRenderer = SDL_GetRenderer(cast(SDL_Window*) this.sdlWindow)) {
382             return cast(inout(Renderer)) new Renderer(sdlRenderer, false, cast(void*) this);
383         }
384         else {
385             throw new SDLException;
386         }
387     }
388 
389     /++
390      + Wraps `SDL_GetWindowTitle` which gets the shown title of the window
391      +
392      + Returns: title `string` of the window
393      +/
394     string title() const @property @trusted {
395         return SDL_GetWindowTitle(cast(SDL_Window*) this.sdlWindow).to!string;
396     }
397 
398     /++
399      + Wraps `SDL_SetWindowTitle` which sets a new title to the window
400      +
401      + Params:
402      +   newTitle = `string` of the new title
403      +/
404     void title(string newTitle) @property @trusted {
405         SDL_SetWindowTitle(this.sdlWindow, newTitle.toStringz());
406     }
407 
408     /++
409      + Wraps `SDL_SetWindowIcon` which sets a new icon to the window
410      +
411      + Params:
412      +   newIcon = `dsdl2.Surface` of the new icon
413      +/
414     void icon(Surface newIcon) @property @trusted
415     in {
416         assert(newIcon !is null);
417     }
418     do {
419         SDL_SetWindowIcon(this.sdlWindow, newIcon.sdlSurface);
420     }
421 
422     /++
423      + Wraps `SDL_GetWindowPosition` which gets the top-left X coordinate position of the window in
424      + the desktop environment
425      +
426      + Returns: top-left X coordinate position of the window in the desktop environment
427      +/
428     int x() const @property @trusted {
429         int x = void;
430         SDL_GetWindowPosition(cast(SDL_Window*) this.sdlWindow, &x, null);
431         return x;
432     }
433 
434     /++
435      + Wraps `SDL_SetWindowPosition` which sets the X position of the window in the desktop environment
436      +
437      + Params:
438      +   newX = top-left X coordinate of the new window position in the desktop environment
439      +/
440     void x(int newX) @property @trusted {
441         SDL_SetWindowPosition(this.sdlWindow, newX, this.y);
442     }
443 
444     /++
445      + Wraps `SDL_GetWindowPosition` which gets the top-left Y coordinate position of the window in
446      + the desktop environment
447      +
448      + Returns: top-left Y coordinate position of the window in the desktop environment
449      +/
450     int y() const @property @trusted {
451         int y = void;
452         SDL_GetWindowPosition(cast(SDL_Window*) this.sdlWindow, null, &y);
453         return y;
454     }
455 
456     /++
457      + Wraps `SDL_SetWindowPosition` which sets the Y position of the window in the desktop environment
458      +
459      + Params:
460      +   newY = top-left Y coordinate of the new window position in the desktop environment
461      +/
462     void y(int newY) @property @trusted {
463         SDL_SetWindowPosition(this.sdlWindow, this.x, newY);
464     }
465 
466     /++
467      + Wraps `SDL_GetWindowPosition` which gets the top-left coordinate position of the window in
468      + the desktop environment
469      +
470      + Returns: top-left coordinate position of the window in the desktop environment
471      +/
472     int[2] position() const @property @trusted {
473         int[2] xy = void;
474         SDL_GetWindowPosition(cast(SDL_Window*) this.sdlWindow, &xy[0], &xy[1]);
475         return xy;
476     }
477 
478     /++
479      + Wraps `SDL_SetWindowPosition` which sets the position of the window in the desktop environment
480      +
481      + Params:
482      +   newPosition = top-left coordinate of the new window position in the desktop environment
483      +/
484     void position(int[2] newPosition) @property @trusted {
485         SDL_SetWindowPosition(this.sdlWindow, newPosition[0], newPosition[1]);
486     }
487 
488     /++
489      + Wraps `SDL_GetWindowSize` which gets the width of the window in pixels
490      +
491      + Returns: width of the window in pixels
492      +/
493     uint width() const @property @trusted {
494         uint w = void;
495         SDL_GetWindowSize(cast(SDL_Window*) this.sdlWindow, cast(int*)&w, null);
496         return w;
497     }
498 
499     /++
500      + Wraps `SDL_SetWindowSize` which resizes the width of the window in pixels
501      +
502      + Params:
503      +   newWidth = new resized width of the window in pixels
504      +/
505     void width(uint newWidth) @property @trusted {
506         SDL_SetWindowSize(this.sdlWindow, newWidth.to!int, this.height);
507     }
508 
509     /++
510      + Wraps `SDL_GetWindowSize` which gets the height of the window in pixels
511      +
512      + Returns: height of the window in pixels
513      +/
514     uint height() const @property @trusted {
515         uint h = void;
516         SDL_GetWindowSize(cast(SDL_Window*) this.sdlWindow, null, cast(int*)&h);
517         return h;
518     }
519 
520     /++
521      + Wraps `SDL_SetWindowSize` which resizes the height of the window in pixels
522      +
523      + Params:
524      +   newHeight = new resized height of the window in pixels
525      +/
526     void height(uint newHeight) @property @trusted {
527         SDL_SetWindowSize(this.sdlWindow, this.width, newHeight.to!int);
528     }
529 
530     /++
531      + Wraps `SDL_GetWindowSize` which gets the size of the window in pixels
532      +
533      + Returns: size of the window in pixels
534      +/
535     uint[2] size() const @property @trusted {
536         uint[2] wh = void;
537         SDL_GetWindowSize(cast(SDL_Window*) this.sdlWindow, cast(int*)&wh[0], cast(int*)&wh[1]);
538         return wh;
539     }
540 
541     /++
542      + Wraps `SDL_SetWindowSize` which resizes the size of the window in pixels
543      +
544      + Params:
545      +   newSize = new resized size of the window in pixels (width and height)
546      +/
547     void size(uint[2] newSize) @property @trusted {
548         SDL_SetWindowSize(this.sdlWindow, newSize[0].to!int, newSize[1].to!int);
549     }
550 
551     /++
552      + Wraps `SDL_GetWindowMinimumSize` which gets the minimum size in pixels that the window can be
553      + resized to
554      +
555      + Returns: minimum set size of the window in pixels
556      +/
557     uint[2] minimumSize() const @property @trusted {
558         uint[2] wh;
559         SDL_GetWindowMinimumSize(cast(SDL_Window*) this.sdlWindow, cast(int*)&wh[0], cast(int*)&wh[1]);
560         return wh;
561     }
562 
563     /++
564      + Wraps `SDL_SetWindowMinimumSize` which sets the minimum size in pixels that the window can be
565      + resized to
566      +
567      + Params:
568      +   newMinimumSize = new minimum set size of the window in pixels (width and height)
569      +/
570     void minimumSize(uint[2] newMinimumSize) @property @trusted {
571         SDL_SetWindowMinimumSize(this.sdlWindow, newMinimumSize[0].to!int,
572             newMinimumSize[1].to!int);
573     }
574 
575     /++
576      + Wraps `SDL_GetWindowMaximumSize` which gets the maximum size in pixels that the window can be
577      + resized to
578      +
579      + Returns: maximum set size of the window in pixels
580      +/
581     uint[2] maximumSize() const @property @trusted {
582         uint[2] wh;
583         SDL_GetWindowMaximumSize(cast(SDL_Window*) this.sdlWindow, cast(int*)&wh[0], cast(int*)&wh[1]);
584         return wh;
585     }
586 
587     /++
588      + Wraps `SDL_SetWindowMaximumSize` which sets the maximum size in pixels that the window can be
589      + resized to
590      +
591      + Params:
592      +   newMaximumSize = new maximum set size of the window in pixels (width and height)
593      +/
594     void maximumSize(uint[2] newMaximumSize) @property @trusted {
595         SDL_SetWindowMaximumSize(this.sdlWindow, newMaximumSize[0].to!int,
596             newMaximumSize[1].to!int);
597     }
598 
599     /++
600      + Wraps `SDL_ShowWindow` which sets the window to be visible in the desktop environment
601      +/
602     void show() @trusted {
603         SDL_ShowWindow(this.sdlWindow);
604     }
605 
606     /++
607      + Wraps `SDL_HideWindow` which sets the window to be invisible in the desktop environment
608      +/
609     void hide() @trusted {
610         SDL_HideWindow(this.sdlWindow);
611     }
612 
613     /++
614      + Wraps `SDL_RaiseWindow` which raises the window above other windows, and sets input focus to the window
615      +/
616     void raise() @trusted {
617         SDL_RaiseWindow(this.sdlWindow);
618     }
619 
620     /++
621      + Wraps `SDL_MaximizeWindow` which maximizes the window in the desktop environment
622      +/
623     void maximize() @trusted {
624         SDL_MaximizeWindow(this.sdlWindow);
625     }
626 
627     /++
628      + Wraps `SDL_MinimizeWindow` which minimizes the window in the desktop environment
629      +/
630     void minimize() @trusted {
631         SDL_MinimizeWindow(this.sdlWindow);
632     }
633 
634     /++
635      + Wraps `SDL_RestoreWindow` which restores the size and position of the window as it was originally
636      +/
637     void restore() @trusted {
638         SDL_RestoreWindow(this.sdlWindow);
639     }
640 
641     /++
642      + Wraps `SDL_GetWindowFlags` to check whether the window is in real fullscreen
643      +
644      + Returns: `true` if the the window is in real fullscreen, otherwise `false`
645      +/
646     bool fullscreen() const @property @trusted {
647         return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN;
648     }
649 
650     /++
651      + Wraps `SDL_SetWindowFullscreen` which sets the fullscreen mode of the window
652      +
653      + Params:
654      +   newFullscreen = `true` to make the window fullscreen, otherwise `false`
655      + Throws: `dsdl2.SDLException` if failed to set the window's fullscreen mode
656      +/
657     void fullscreen(bool newFullscreen) @property @trusted {
658         if (SDL_SetWindowFullscreen(this.sdlWindow, newFullscreen ? SDL_WINDOW_FULLSCREEN : 0) != 0) {
659             throw new SDLException;
660         }
661     }
662 
663     /++
664      + Wraps `SDL_GetWindowFlags` to check whether the window is in desktop fullscreen
665      +
666      + Returns: `true` if the the window is in desktop fullscreen, otherwise `false`
667      +/
668     bool fullscreenDesktop() const @property @trusted {
669         return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP) ==
670             SDL_WINDOW_FULLSCREEN_DESKTOP;
671     }
672 
673     /++
674      + Wraps `SDL_GetWindowFlags` to check whether the window utilizes OpenGL
675      +
676      + Returns: `true` if the the window utilizes OpenGL, otherwise `false`
677      +/
678     bool openGL() const @property @trusted {
679         return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_OPENGL) == SDL_WINDOW_OPENGL;
680     }
681 
682     static if (sdlSupport >= SDLSupport.v2_0_6) {
683         /++
684          + Wraps `SDL_GetWindowFlags` to check whether the window utilizes Vulkan (from SDL 2.0.6)
685          +
686          + Returns: `true` if the the window utilizes Vulkan, otherwise `false`
687          +/
688         bool vulkan() const @property @trusted
689         in {
690             assert(getVersion() >= Version(2, 0, 6));
691         }
692         do {
693             return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_VULKAN) == SDL_WINDOW_VULKAN;
694         }
695 
696         /++
697          + Wraps `SDL_GetWindowFlags` to check whether the window utilizes Metal (from SDL 2.0.6)
698          +
699          + Returns: `true` if the the window utilizes Metal, otherwise `false`
700          +/
701         bool metal() const @property @trusted
702         in {
703             assert(getVersion() >= Version(2, 0, 6));
704         }
705         do {
706             return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_METAL) == SDL_WINDOW_METAL;
707         }
708     }
709 
710     /++
711      + Wraps `SDL_GetWindowFlags` to check whether the window is foreign
712      +
713      + Returns: `true` if the the window is foreign, otherwise `false`
714      +/
715     bool foreign() const @property @trusted {
716         return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_FOREIGN) == SDL_WINDOW_FOREIGN;
717     }
718 
719     /++
720      + Wraps `SDL_GetWindowFlags` to check whether the window is shown
721      +
722      + Returns: `true` if the the window is shown, otherwise `false`
723      +/
724     bool shown() const @property @trusted {
725         return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_SHOWN) == SDL_WINDOW_SHOWN;
726     }
727 
728     /++
729      + Wraps `SDL_GetWindowFlags` to check whether the window is hidden
730      +
731      + Returns: `true` if the the window is hidden, otherwise `false`
732      +/
733     bool hidden() const @property @trusted {
734         return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_HIDDEN) == SDL_WINDOW_HIDDEN;
735     }
736 
737     /++
738      + Wraps `SDL_GetWindowFlags` to check whether the borders of the window are non-existent
739      +
740      + Returns: `true` if borders of the window are non-existent, otherwise `false`
741      +/
742     bool borderless() const @property @trusted {
743         return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_BORDERLESS) == SDL_WINDOW_BORDERLESS;
744     }
745 
746     /++
747      + Wraps `SDL_GetWindowFlags` to check whether the borders of the window are visible
748      +
749      + Returns: `true` if borders are visible, otherwise `false`
750      +/
751     bool bordered() const @property @trusted {
752         return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_BORDERLESS) != SDL_WINDOW_BORDERLESS;
753     }
754 
755     /++
756      + Wraps `SDL_SetWindowBordered` which sets whether the borders' visibility
757      +
758      + Params:
759      +   newBordered = `true` to make the borders visible, otherwise `false`
760      +/
761     void bordered(bool newBordered) @property @trusted {
762         SDL_SetWindowBordered(this.sdlWindow, newBordered);
763     }
764 
765     /++
766      + Wraps `SDL_GetWindowFlags` to check whether the window's size is resizable by the user
767      +
768      + Returns: `true` if the window is resizable, otherwise `false`
769      +/
770     bool resizable() const @property @trusted {
771         return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_RESIZABLE) == SDL_WINDOW_RESIZABLE;
772     }
773 
774     static if (sdlSupport >= SDLSupport.v2_0_5) {
775         /++
776          + Wraps `SDL_SetWindowResizable` (from SDL 2.0.5) which sets the window's resizability
777          +
778          + Params:
779          +   newResizable = `true` to make the window resizable, otherwise `false`
780          +/
781         void resizable(bool newResizable) @property @trusted
782         in {
783             assert(getVersion() >= Version(2, 0, 5));
784         }
785         do {
786             SDL_SetWindowResizable(this.sdlWindow, newResizable);
787         }
788     }
789 
790     /++
791      + Wraps `SDL_GetWindowFlags` to check whether the window is minimized
792      +
793      + Returns: `true` if window is minimized, otherwise `false`
794      +/
795     bool minimized() const @property @trusted {
796         return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_MINIMIZED) == SDL_WINDOW_MINIMIZED;
797     }
798 
799     /++
800      + Wraps `SDL_GetWindowFlags` to check whether the window is maximized
801      +
802      + Returns: `true` if window is maximized, otherwise `false`
803      +/
804     bool maximized() const @property @trusted {
805         return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_MAXIMIZED) == SDL_WINDOW_MAXIMIZED;
806     }
807 
808     static if (sdlSupport >= SDLSupport.v2_0_1) {
809         /++
810          + Wraps `SDL_GetWindowFlags` to check whether the window allows high DPI (from SDL 2.0.1)
811          +
812          + Returns: `true` if window allows high DPI, otherwise `false`
813          +/
814         bool allowsHighDPI() const @property @trusted
815         in {
816             assert(getVersion() >= Version(2, 0, 1));
817         }
818         do {
819             return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_ALLOW_HIGHDPI) ==
820                 SDL_WINDOW_ALLOW_HIGHDPI;
821         }
822     }
823 
824     static if (sdlSupport >= SDLSupport.v2_0_5) {
825         /++
826          + Wraps `SDL_GetWindowFlags` to check whether the window is always on top (from SDL 2.0.5)
827          +
828          + Returns: `true` if window is always on top, otherwise `false`
829          +/
830         bool alwaysOnTop() const @property @trusted
831         in {
832             assert(getVersion() >= Version(2, 0, 5));
833         }
834         do {
835             return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_ALWAYS_ON_TOP) ==
836                 SDL_WINDOW_ALWAYS_ON_TOP;
837         }
838 
839         /++
840          + Wraps `SDL_GetWindowFlags` to check whether the window is not on the taskbar (from SDL 2.0.5)
841          +
842          + Returns: `true` if window is not on the taskbar, otherwise `false`
843          +/
844         bool skipsTaskbar() const @property @trusted
845         in {
846             assert(getVersion() >= Version(2, 0, 5));
847         }
848         do {
849             return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_SKIP_TASKBAR) ==
850                 SDL_WINDOW_SKIP_TASKBAR;
851         }
852 
853         /++
854          + Wraps `SDL_GetWindowFlags` to check whether the window is treated as a utility window (from SDL 2.0.5)
855          +
856          + Returns: `true` if window is treated as a utility window, otherwise `false`
857          +/
858         bool utility() const @property @trusted
859         in {
860             assert(getVersion() >= Version(2, 0, 5));
861         }
862         do {
863             return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_UTILITY) ==
864                 SDL_WINDOW_UTILITY;
865         }
866 
867         /++
868          + Wraps `SDL_GetWindowFlags` to check whether the window is treated as a tooltip window (from SDL 2.0.5)
869          +
870          + Returns: `true` if window is treated as a tooltip window, otherwise `false`
871          +/
872         bool tooltip() const @property @trusted
873         in {
874             assert(getVersion() >= Version(2, 0, 5));
875         }
876         do {
877             return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_TOOLTIP) ==
878                 SDL_WINDOW_TOOLTIP;
879         }
880 
881         /++
882          + Wraps `SDL_GetWindowFlags` to check whether the window is treated as a popup menu (from SDL 2.0.5)
883          +
884          + Returns: `true` if window is treated as a popup menu, otherwise `false`
885          +/
886         bool popupMenu() const @property @trusted
887         in {
888             assert(getVersion() >= Version(2, 0, 5));
889         }
890         do {
891             return (SDL_GetWindowFlags(cast(SDL_Window*) this.sdlWindow) & SDL_WINDOW_POPUP_MENU) ==
892                 SDL_WINDOW_POPUP_MENU;
893         }
894     }
895 
896     /++
897      + Wraps `SDL_GetWindowGrab` which gets the window's input grab mode
898      +
899      + Returns: `true` if the window is in input grab mode, otherwise `false`
900      +/
901     bool inputGrab() const @property @trusted {
902         return SDL_GetWindowGrab(cast(SDL_Window*) this.sdlWindow) == SDL_TRUE;
903     }
904 
905     /++
906      + Wraps `SDL_SetWindowGrab` which sets the window's input grab mode
907      +
908      + Params:
909      +   newGrab = `true` to set the window on input grab mode, otherwise `false`
910      +/
911     void inputGrab(bool newGrab) @property @trusted {
912         SDL_SetWindowGrab(this.sdlWindow, newGrab);
913     }
914 
915     /++
916      + Wraps `SDL_GetWindowBrightness` which gets the window's brightness value
917      +
918      + Returns: `float` value from `0.0` to `1.0` indicating the window's brightness
919      +/
920     float brightness() const @property @trusted {
921         return SDL_GetWindowBrightness(cast(SDL_Window*) this.sdlWindow);
922     }
923 
924     /++
925      + Wraps `SDL_SetWindowBrightness` which sets the window's brightness value
926      +
927      + Params:
928      +   newBrightness = `float` value specifying the window's brightness from `0.0` (darkest) to `1.0` (brightest)
929      + Throws: `dsdl2.SDLException` if failed to set the window's brightness value
930      +/
931     void brightness(float newBrightness) @property @trusted {
932         if (SDL_SetWindowBrightness(this.sdlWindow, newBrightness) != 0) {
933             throw new SDLException;
934         }
935     }
936 
937     /++
938      + Wraps `SDL_IsScreenKeyboardShown` which checks whether the screen keyboard is shown on the window
939      +
940      + Returns: `true` if the screen keyboard is shown, otherwise `false`
941      +/
942     bool hasShownScreenKeyboard() const @property @trusted {
943         return SDL_IsScreenKeyboardShown(cast(SDL_Window*) this.sdlWindow) == SDL_TRUE;
944     }
945 
946     /++
947      + Wraps `SDL_GetKeyboardFocus` which verifies whether keyboard input is focused to the window
948      +
949      + Returns: `true` if keyboard input is focused, otherwise `false`
950      +/
951     bool keyboardFocused() const @property @trusted {
952         return SDL_GetKeyboardFocus() == this.sdlWindow;
953     }
954 
955     /++
956      + Wraps `SDL_GetMouseFocus` which verifies whether mouse input is focused to the window
957      +
958      + Returns: `true` if mouse input is focused, otherwise `false`
959      +/
960     bool mouseFocused() const @property @trusted {
961         return SDL_GetMouseFocus() == this.sdlWindow;
962     }
963 
964     /++
965      + Wraps `SDL_GetMouseState` which gets the mouse position in the window
966      +
967      + Returns: `[x, y]` of the mouse position relative to the window, otherwise `[-1, -1]` if mouse input is not
968      +          focused to the window
969      +/
970     int[2] mousePosition() const @property @trusted {
971         if (SDL_GetMouseFocus() != this.sdlWindow) {
972             return [-1, -1];
973         }
974 
975         int[2] pos = void;
976         SDL_GetMouseState(&pos[0], &pos[1]);
977         return pos;
978     }
979 
980     /++
981      + Wraps `SDL_WarpMouseInWindow` which sets the mouse position in the window
982      +
983      + Params:
984      +   newMousePosition = coordinate of the mouse position to set
985      +/
986     void mousePosition(int[2] newMousePosition) @property @trusted {
987         SDL_WarpMouseInWindow(this.sdlWindow, newMousePosition[0], newMousePosition[1]);
988     }
989 
990     /++
991      + Wraps `SDL_GetWindowSurface` which gets the window's surface for software rendering
992      +
993      + Returns: `dsdl2.Surface` proxy to the window's surface
994      + Throws: `dsdl2.SDLException` if failed to get the window's surface
995      +/
996     inout(Surface) surface() inout @property @trusted {
997         SDL_Surface* surfacePtr = SDL_GetWindowSurface(cast(SDL_Window*) this.sdlWindow);
998         if (surfacePtr is null) {
999             throw new SDLException;
1000         }
1001 
1002         if (this.surfaceProxy is null) {
1003             (cast(Window) this).surfaceProxy = new Surface(surfacePtr, false, cast(void*) this);
1004         }
1005 
1006         // If the surface pointer happens to change, rewire the proxy.
1007         if (this.surfaceProxy.sdlSurface !is surfacePtr) {
1008             (cast(Window) this).surfaceProxy.sdlSurface = surfacePtr;
1009         }
1010 
1011         return this.surfaceProxy;
1012     }
1013 
1014     static if (sdlSupport >= SDLSupport.v2_28) {
1015         /++
1016          + Wraps `SDL_DestroyWindowSurface` (from SDL 2.28) which destructs the underlying associated surface
1017          + of the window
1018          +
1019          + Throws: `dsdl2.SDLException` if failed to destruct the surface
1020          +/
1021         void surface(typeof(null) _) @property @trusted
1022         in {
1023             assert(getVersion() >= Version(2, 28));
1024         }
1025         do {
1026             if (SDL_DestroyWindowSurface(this.sdlWindow) != 0) {
1027                 throw new SDLException;
1028             }
1029         }
1030 
1031         /++
1032          + Wraps `SDL_HasWindowSurface` (from SDL 2.28) which checks whether there is a surface associated with
1033          + the window
1034          +
1035          + Returns: `true` if the window has an associated surface, otherwise `false`
1036          +/
1037         bool hasSurface() const @property @trusted
1038         in {
1039             assert(getVersion() >= Version(2, 28));
1040         }
1041         do {
1042             return SDL_HasWindowSurface(cast(SDL_Window*) this.sdlWindow) == SDL_TRUE;
1043         }
1044     }
1045 
1046     /++
1047      + Wraps `SDL_UpdateWindowSurface` which makes the changes to the window's surface current
1048      +
1049      + Throws: `dsdl2.SDLException` if failed to update the window's changes
1050      +/
1051     void update() @trusted {
1052         if (SDL_UpdateWindowSurface(this.sdlWindow) != 0) {
1053             throw new SDLException;
1054         }
1055     }
1056 
1057     /++
1058      + Wraps `SDL_UpdateWindowSurfaceRects` which makes the changes of certain parts of the window surface
1059      + as defined by a list of `dsdl2.Rect`s current
1060      +
1061      + Params:
1062      +   rects = array of `dsdl2.Rect`s defining parts of the window surface to update
1063      + Throws: `dsdl2.SDLException` if failed to update the window's changes
1064      +/
1065     void update(Rect[] rects) @trusted {
1066         if (SDL_UpdateWindowSurfaceRects(this.sdlWindow, cast(SDL_Rect*) rects.ptr,
1067                 rects.length.to!int) != 0) {
1068             throw new SDLException;
1069         }
1070     }
1071 
1072     /++
1073      + Wraps `SDL_GL_SwapWindow` which updates the window with any OpenGL changes
1074      +/
1075     void swapGL() @trusted {
1076         SDL_GL_SwapWindow(this.sdlWindow);
1077     }
1078 
1079     static if (sdlSupport >= SDLSupport.v2_0_1) {
1080         /++
1081          + Wraps `SDL_GL_GetDrawableSize` (from SDL 2.0.1) which gets the drawable height of the window in OpenGL
1082          + in pixels
1083          +
1084          + Returns: height of the window in OpenGL in pixels
1085          +/
1086         uint drawableGLWidth() const @property @trusted
1087         in {
1088             assert(getVersion() >= Version(2, 0, 1));
1089         }
1090         do {
1091             uint w = void;
1092             SDL_GL_GetDrawableSize(cast(SDL_Window*) this.sdlWindow, cast(int*)&w, null);
1093             return w;
1094         }
1095 
1096         /++
1097          + Wraps `SDL_GL_GetDrawableSize` (from SDL 2.0.1) which gets the drawable width of the window in OpenGL
1098          + in pixels
1099          +
1100          + Returns: width of the window in OpenGL in pixels
1101          +/
1102         uint drawableGLHeight() const @property @trusted
1103         in {
1104             assert(getVersion() >= Version(2, 0, 1));
1105         }
1106         do {
1107             uint h = void;
1108             SDL_GL_GetDrawableSize(cast(SDL_Window*) this.sdlWindow, null, cast(int*)&h);
1109             return h;
1110         }
1111 
1112         /++
1113          + Wraps `SDL_GL_GetDrawableSize` (from SDL 2.0.1) which gets the drawable size of the window in OpenGL
1114          + in pixels
1115          +
1116          + Returns: size of the window in OpenGL in pixels
1117          +/
1118         uint[2] drawableGLSize() const @property @trusted
1119         in {
1120             assert(getVersion() >= Version(2, 0, 1));
1121         }
1122         do {
1123             uint[2] wh = void;
1124             SDL_GL_GetDrawableSize(cast(SDL_Window*) this.sdlWindow, cast(int*)&wh[0], cast(int*)&wh[1]);
1125             return wh;
1126         }
1127     }
1128 
1129     static if (sdlSupport >= SDLSupport.v2_0_5) {
1130         /++
1131          + Wraps `SDL_SetWindowInputFocus` (from SDL 2.0.5) which focuses the window to be in reach to the user
1132          +
1133          + Throws: `dsdl2.SDLException` if failed to focus the window
1134          +/
1135         void focus() @trusted
1136         in {
1137             assert(getVersion() >= Version(2, 0, 5));
1138         }
1139         do {
1140             if (SDL_SetWindowInputFocus(this.sdlWindow) != 0) {
1141                 throw new SDLException;
1142             }
1143         }
1144 
1145         /++
1146          + Wraps `SDL_SetWindowModalFor` (from SDL 2.0.5) which sets the window to be a modal of another parent
1147          + window, making the window always be above its parent window
1148          +
1149          + Params:
1150          +   parent = the parent window which owns the window as a modal
1151          + Throws: `dsdl2.SDLException` if failed to set the window as modal
1152          +/
1153         void modalFor(Window parent) @trusted
1154         in {
1155             assert(getVersion() >= Version(2, 0, 5));
1156             assert(parent !is null);
1157         }
1158         do {
1159             if (SDL_SetWindowModalFor(this.sdlWindow, parent.sdlWindow) != 0) {
1160                 throw new SDLException;
1161             }
1162         }
1163 
1164         /++
1165          + Wraps `SDL_GetWindowOpacity` (from SDL 2.0.5) which gets the opacity of the window
1166          +
1167          + Returns: `float` indicating the opacity of the window from `0.0` (transparent) to `1.0` (opaque)
1168          + Throws: `dsdl2.SDLException` if failed to get the window's opacity
1169          +/
1170         float opacity() const @property @trusted
1171         in {
1172             assert(getVersion() >= Version(2, 0, 5));
1173         }
1174         do {
1175             float alpha = void;
1176             if (SDL_GetWindowOpacity(cast(SDL_Window*) this.sdlWindow, &alpha) != 0) {
1177                 throw new SDLException;
1178             }
1179 
1180             return alpha;
1181         }
1182 
1183         /++
1184          + Wraps `SDL_SetWindowOpacity` (from SDL 2.0.5) which sets the opacity of the window
1185          +
1186          + Params:
1187          +   newOpacity = `float` indicating the opacity of the window from `0.0` (transparent) to `1.0` (opaque)
1188          + Throws: `dsdl2.SDLException` if failed to set the window's opacity
1189          +/
1190         void opacity(float newOpacity) @property @trusted
1191         in {
1192             assert(getVersion() >= Version(2, 0, 5));
1193         }
1194         do {
1195             if (SDL_SetWindowOpacity(this.sdlWindow, newOpacity) != 0) {
1196                 throw new SDLException;
1197             }
1198         }
1199     }
1200 
1201     static if (sdlSupport >= SDLSupport.v2_0_16) {
1202         /++
1203          + Wraps `SDL_FlashWindow` (from SDL 2.0.16) which flashes the window in the desktop environment
1204          +
1205          + Params:
1206          +   operation = flashing operation to do
1207          + Throws: `dsdl2.SDLException` if failed to flash the window
1208          +/
1209         void flash(FlashOperation operation) @trusted
1210         in {
1211             assert(getVersion() >= Version(2, 0, 16));
1212         }
1213         do {
1214             if (SDL_FlashWindow(this.sdlWindow, operation) != 0) {
1215                 throw new SDLException;
1216             }
1217         }
1218 
1219         /++
1220          + Wraps `SDL_SetWindowAlwaysOnTop` (from SDL 2.0.16) which sets the status of the window always
1221          + being on top above other windows
1222          +
1223          + Params:
1224          +   newOnTop = `true` to always make the window to be on top, otherwise `false`
1225          +/
1226         void onTop(bool newOnTop) @property @trusted
1227         in {
1228             assert(getVersion() >= Version(2, 0, 16));
1229         }
1230         do {
1231             SDL_SetWindowAlwaysOnTop(this.sdlWindow, newOnTop);
1232         }
1233 
1234         /++
1235          + Wraps `SDL_GetWindowKeyboardGrab` (from SDL 2.0.16) which gets the status of the window grabbing
1236          + onto keyboard input
1237          +
1238          + Returns: `true` if the window is grabbing onto keyboard input, otherwise `false`
1239          +/
1240         bool keyboardGrab() const @property @trusted
1241         in {
1242             assert(getVersion() >= Version(2, 0, 16));
1243         }
1244         do {
1245             return SDL_GetWindowKeyboardGrab(cast(SDL_Window*) this.sdlWindow) == SDL_TRUE;
1246         }
1247 
1248         /++
1249          + Wraps `SDL_SetWindowKeyboardGrab` (from SDL 2.0.16) which sets the status of the window grabbing
1250          + onto keyboard input
1251          +
1252          + Params:
1253          +   newKeyboardGrab = `true` to enable keyboard grab, otherwise `false`
1254          +/
1255         void keyboardGrab(bool newKeyboardGrab) @property @trusted
1256         in {
1257             assert(getVersion() >= Version(2, 0, 16));
1258         }
1259         do {
1260             SDL_SetWindowKeyboardGrab(this.sdlWindow, newKeyboardGrab);
1261         }
1262 
1263         /++
1264          + Wraps `SDL_GetWindowMouseGrab` (from SDL 2.0.16) which gets the status of the window grabbing
1265          + onto mouse input
1266          +
1267          + Returns: `true` if the window is grabbing onto mouse input, otherwise `false`
1268          +/
1269         bool mouseGrab() const @property @trusted
1270         in {
1271             assert(getVersion() >= Version(2, 0, 16));
1272         }
1273         do {
1274             return SDL_GetWindowMouseGrab(cast(SDL_Window*) this.sdlWindow) == SDL_TRUE;
1275         }
1276 
1277         /++
1278          + Wraps `SDL_SetWindowMouseGrab` (from SDL 2.0.16) which sets the status of the window grabbing
1279          + onto mouse input
1280          +
1281          + Params:
1282          +   newMouseGrab = `true` to enable mouse grab, otherwise `false`
1283          +/
1284         void mouseGrab(bool newMouseGrab) @property @trusted
1285         in {
1286             assert(getVersion() >= Version(2, 0, 16));
1287         }
1288         do {
1289             SDL_SetWindowMouseGrab(this.sdlWindow, newMouseGrab);
1290         }
1291     }
1292 
1293     static if (sdlSupport >= SDLSupport.v2_0_18) {
1294         /++
1295          + Wraps `SDL_GetWindowICCProfile` (from SDL 2.0.18) which gets the raw ICC profile data for the
1296          + screen the window is currently on
1297          +
1298          + Returns: untyped array buffer of the raw ICC profile data
1299          + Throws `dsdl2.SDLException` if failed to obtain the ICC profile data
1300          +/
1301         void[] iccProfile() const @property @trusted
1302         in {
1303             assert(getVersion() >= Version(2, 0, 18));
1304         }
1305         do {
1306             size_t size = void;
1307             void* data = SDL_GetWindowICCProfile(cast(SDL_Window*) this.sdlWindow, &size);
1308             scope (exit)
1309                 SDL_free(data);
1310 
1311             if (data is null) {
1312                 throw new SDLException;
1313             }
1314 
1315             // Copies the data under allocation with the GC, as `data` is a manually-handled resource
1316             // allocated by SDL
1317             return data[0 .. size].dup;
1318         }
1319 
1320         /++
1321          + Wraps `SDL_GetWindowMouseRect` (from SDL 2.0.18) which gets the window's mouse confinement rectangle
1322          +
1323          + Returns: `dsdl2.Rect` of the mouse's confinement rectangle in the window
1324          +/
1325         Nullable!Rect mouseRect() const @property @trusted
1326         in {
1327             assert(getVersion() >= Version(2, 0, 18));
1328         }
1329         do {
1330             const(SDL_Rect)* rect = SDL_GetWindowMouseRect(cast(SDL_Window*) this.sdlWindow);
1331             if (rect is null) {
1332                 return Nullable!Rect.init;
1333             }
1334             else {
1335                 return Rect(*rect).nullable;
1336             }
1337         }
1338 
1339         /++
1340          + Wraps `SDL_SetWindowMouseRect` (from SDL 2.0.18) which sets the window's mouse confinement rectangle
1341          +
1342          + Params:
1343          +   newMouseRect = `dsdl2.Rect` specifying the rectangle in window coordinate space to confine the mouse
1344          +                  pointer in
1345          + Throws: `dsdl2.SDLException` if failed to set the confinement
1346          +/
1347         void mouseRect(Rect newMouseRect) @property @trusted
1348         in {
1349             assert(getVersion() >= Version(2, 0, 18));
1350         }
1351         do {
1352             if (SDL_SetWindowMouseRect(this.sdlWindow, &newMouseRect.sdlRect) != 0) {
1353                 throw new SDLException;
1354             }
1355         }
1356 
1357         /++
1358          + Acts as `SDL_SetWindowMouseRect(window, NULL)` (from SDL 2.0.18) which resets the window's mouse
1359          + confinement rectangle
1360          +
1361          + Throws: `dsdl2.SDLException` if failed to reset the confinement
1362          +/
1363         void mouseRect(typeof(null) _) @property @trusted
1364         in {
1365             assert(getVersion() >= Version(2, 0, 18));
1366         }
1367         do {
1368             if (SDL_SetWindowMouseRect(this.sdlWindow, null) != 0) {
1369                 throw new SDLException;
1370             }
1371         }
1372 
1373         /++
1374          + Wraps `SDL_SetWindowMouseRect` (from SDL 2.0.18) which sets or resets the window's mouse
1375          + confinement rectangle
1376          +
1377          + Params:
1378          +   newMouseRect = `dsdl2.Rect` specifying the rectangle in window coordinate space to confine the mouse
1379          +                  pointer in; `null` to reset the confinement
1380          + Throws: `dsdl2.SDLException` if failed to set or reset the confinement
1381          +/
1382         void mouseRect(Nullable!Rect newMouseRect) @property @trusted
1383         in {
1384             assert(getVersion() >= Version(2, 0, 18));
1385         }
1386         do {
1387             if (newMouseRect.isNull) {
1388                 this.mouseRect = null;
1389             }
1390             else {
1391                 this.mouseRect = newMouseRect.get;
1392             }
1393         }
1394     }
1395 
1396     static if (sdlSupport >= SDLSupport.v2_26) {
1397         /++
1398          + Wraps `SDL_GetWindowSizeInPixels` (from SDL 2.26) which gets the actual size of the window in the
1399          + screen in pixels
1400          +
1401          + Returns: actual size of the window in the screen in pixels
1402          +/
1403         uint[2] sizeInPixels() const @property @trusted
1404         in {
1405             assert(getVersion() >= Version(2, 26));
1406         }
1407         do {
1408             uint[2] size = void;
1409             SDL_GetWindowSizeInPixels(cast(SDL_Window*) this.sdlWindow, cast(int*)&size[0],
1410                 cast(int*)&size[1]);
1411             return size;
1412         }
1413     }
1414 }