1 module gfm.sdl2.window; 2 3 import std..string; 4 5 import bindbc.sdl; 6 7 import std.experimental.logger; 8 9 import gfm.sdl2.sdl, 10 gfm.sdl2.surface, 11 gfm.sdl2.mouse, 12 gfm.sdl2.keyboard; 13 14 15 /// SDL Window wrapper. 16 /// There is two ways to receive events, either by polling a SDL2 object, 17 /// or by overriding the event callbacks. 18 final class SDL2Window 19 { 20 public 21 { 22 /// Creates a SDL window which targets a window. 23 /// See_also: $(LINK http://wiki.libsdl.org/SDL_CreateWindow) 24 /// Throws: $(D SDL2Exception) on error. 25 this(SDL2 sdl2, int x, int y, int width, int height, SDL_WindowFlags flags) 26 { 27 _sdl2 = sdl2; 28 _logger = sdl2._logger; 29 _surface = null; 30 _glContext = null; 31 _surfaceMustBeRenewed = false; 32 33 bool OpenGL = (flags & SDL_WINDOW_OPENGL) != 0; 34 _window = SDL_CreateWindow(toStringz(""), x, y, width, height, flags); 35 if (_window == null) 36 { 37 string message = "SDL_CreateWindow failed: " ~ _sdl2.getErrorString().idup; 38 throw new SDL2Exception(message); 39 } 40 41 _id = SDL_GetWindowID(_window); 42 43 if (OpenGL) 44 _glContext = new SDL2GLContext(this); 45 } 46 47 /// Creates a SDL window from anexisting handle. 48 /// See_also: $(LINK http://wiki.libsdl.org/SDL_CreateWindowFrom) 49 /// Throws: $(D SDL2Exception) on error. 50 this(SDL2 sdl2, void* windowData) 51 { 52 _sdl2 = sdl2; 53 _logger = sdl2._logger; 54 _surface = null; 55 _glContext = null; 56 _surfaceMustBeRenewed = false; 57 _window = SDL_CreateWindowFrom(windowData); 58 if (_window == null) 59 { 60 string message = "SDL_CreateWindowFrom failed: " ~ _sdl2.getErrorString().idup; 61 throw new SDL2Exception(message); 62 } 63 64 _id = SDL_GetWindowID(_window); 65 } 66 67 68 /// Releases the SDL resource. 69 /// See_also: $(LINK http://wiki.libsdl.org/SDL_DestroyWindow) 70 ~this() 71 { 72 if (_glContext !is null) 73 { 74 debug ensureNotInGC("SDL2Window"); 75 _glContext.destroy(); 76 _glContext = null; 77 } 78 79 if (_window !is null) 80 { 81 debug ensureNotInGC("SDL2Window"); 82 SDL_DestroyWindow(_window); 83 _window = null; 84 } 85 } 86 87 /// See_also: $(LINK http://wiki.libsdl.org/SDL_SetWindowFullscreen) 88 /// Throws: $(D SDL2Exception) on error. 89 final void setFullscreenSetting(uint flags) 90 { 91 if (SDL_SetWindowFullscreen(_window, flags) != 0) 92 _sdl2.throwSDL2Exception("SDL_SetWindowFullscreen"); 93 } 94 95 /// Returns: The flags associated with the window. 96 /// See_also: $(LINK https://wiki.libsdl.org/SDL_GetWindowFlags) 97 final uint getWindowFlags() 98 { 99 return SDL_GetWindowFlags(_window); 100 } 101 102 /// Returns: X window coordinate. 103 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetWindowPosition) 104 final int getX() 105 { 106 return getPosition().x; 107 } 108 109 /// Returns: Y window coordinate. 110 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetWindowPosition) 111 final int getY() 112 { 113 return getPosition().y; 114 } 115 116 /// Gets information about the window's display mode 117 /// See_also: $(LINK https://wiki.libsdl.org/SDL_GetWindowDisplayMode) 118 final SDL_DisplayMode getWindowDisplayMode() 119 { 120 SDL_DisplayMode mode; 121 if (0 != SDL_GetWindowDisplayMode(_window, &mode)) 122 _sdl2.throwSDL2Exception("SDL_GetWindowDisplayMode"); 123 return mode; 124 } 125 126 /// Returns: Window coordinates. 127 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetWindowPosition) 128 final SDL_Point getPosition() 129 { 130 int x, y; 131 SDL_GetWindowPosition(_window, &x, &y); 132 return SDL_Point(x, y); 133 } 134 135 /// See_also: $(LINK http://wiki.libsdl.org/SDL_SetWindowPosition) 136 final void setPosition(int positionX, int positionY) 137 { 138 SDL_SetWindowPosition(_window, positionX, positionY); 139 } 140 141 /// See_also: $(LINK http://wiki.libsdl.org/SDL_SetWindowSize) 142 final void setSize(int width, int height) 143 { 144 SDL_SetWindowSize(_window, width, height); 145 } 146 147 /// Get the minimum size setting for the window 148 /// See_also: $(LINK https://wiki.libsdl.org/SDL_GetWindowMinimumSize) 149 final SDL_Point getMinimumSize() 150 { 151 SDL_Point p; 152 SDL_GetWindowMinimumSize(_window, &p.x, &p.y); 153 return p; 154 } 155 156 /// Get the minimum size setting for the window 157 /// See_also: $(LINK https://wiki.libsdl.org/SDL_SetWindowMinimumSize) 158 final void setMinimumSize(int width, int height) 159 { 160 SDL_SetWindowMinimumSize(_window, width, height); 161 } 162 163 /// Get the minimum size setting for the window 164 /// See_also: $(LINK https://wiki.libsdl.org/SDL_GetWindowMaximumSize) 165 final SDL_Point getMaximumSize() 166 { 167 SDL_Point p; 168 SDL_GetWindowMaximumSize(_window, &p.x, &p.y); 169 return p; 170 } 171 172 /// Get the minimum size setting for the window 173 /// See_also: $(LINK https://wiki.libsdl.org/SDL_SetWindowMaximumSize) 174 final void setMaximumSize(int width, int height) 175 { 176 SDL_SetWindowMaximumSize(_window, width, height); 177 } 178 179 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetWindowSize) 180 /// Returns: Window size in pixels. 181 final SDL_Point getSize() 182 { 183 int w, h; 184 SDL_GetWindowSize(_window, &w, &h); 185 return SDL_Point(w, h); 186 } 187 188 /// See_also: $(LINK http://wiki.libsdl.org/SDL_SetWindowIcon) 189 final void setIcon(SDL2Surface icon) 190 { 191 SDL_SetWindowIcon(_window, icon.handle()); 192 } 193 194 /// See_also: $(LINK http://wiki.libsdl.org/SDL_SetWindowBordered) 195 final void setBordered(bool bordered) 196 { 197 SDL_SetWindowBordered(_window, bordered ? SDL_TRUE : SDL_FALSE); 198 } 199 200 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetWindowSize) 201 /// Returns: Window width in pixels. 202 final int getWidth() 203 { 204 int w, h; 205 SDL_GetWindowSize(_window, &w, &h); 206 return w; 207 } 208 209 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetWindowSize) 210 /// Returns: Window height in pixels. 211 final int getHeight() 212 { 213 int w, h; 214 SDL_GetWindowSize(_window, &w, &h); 215 return h; 216 } 217 218 /// See_also: $(LINK http://wiki.libsdl.org/SDL_SetWindowTitle) 219 final void setTitle(string title) 220 { 221 SDL_SetWindowTitle(_window, toStringz(title)); 222 } 223 224 /// See_also: $(LINK http://wiki.libsdl.org/SDL_ShowWindow) 225 final void show() 226 { 227 SDL_ShowWindow(_window); 228 } 229 230 /// See_also: $(LINK http://wiki.libsdl.org/SDL_HideWindow) 231 final void hide() 232 { 233 SDL_HideWindow(_window); 234 } 235 236 /// See_also: $(LINK http://wiki.libsdl.org/SDL_MinimizeWindow) 237 final void minimize() 238 { 239 SDL_MinimizeWindow(_window); 240 } 241 242 /// See_also: $(LINK http://wiki.libsdl.org/SDL_MaximizeWindow) 243 final void maximize() 244 { 245 SDL_MaximizeWindow(_window); 246 } 247 248 /// Returns: Window surface. 249 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetWindowSurface) 250 /// Throws: $(D SDL2Exception) on error. 251 final SDL2Surface surface() 252 { 253 if (!hasValidSurface()) 254 { 255 SDL_Surface* internalSurface = SDL_GetWindowSurface(_window); 256 if (internalSurface is null) 257 _sdl2.throwSDL2Exception("SDL_GetWindowSurface"); 258 259 // renews surface as needed 260 _surfaceMustBeRenewed = false; 261 _surface = new SDL2Surface(_sdl2, internalSurface, SDL2Surface.Owned.NO); 262 } 263 return _surface; 264 } 265 266 /// Submit changes to the window surface. 267 /// See_also: $(LINK http://wiki.libsdl.org/SDL_UpdateWindowSurface) 268 /// Throws: $(D SDL2Exception) on error. 269 final void updateSurface() 270 { 271 if (!hasValidSurface()) 272 surface(); 273 274 int res = SDL_UpdateWindowSurface(_window); 275 if (res != 0) 276 _sdl2.throwSDL2Exception("SDL_UpdateWindowSurface"); 277 278 } 279 280 /// Returns: Window ID. 281 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetWindowID) 282 final int id() 283 { 284 return _id; 285 } 286 287 /// Returns: System-specific window information, useful to use a third-party rendering library. 288 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetWindowWMInfo) 289 /// Throws: $(D SDL2Exception) on error. 290 SDL_SysWMinfo getWindowInfo() 291 { 292 SDL_SysWMinfo info; 293 SDL_VERSION(&info.version_); 294 int res = SDL_GetWindowWMInfo(_window, &info); 295 if (res != SDL_TRUE) 296 _sdl2.throwSDL2Exception("SDL_GetWindowWMInfo"); 297 return info; 298 } 299 300 /// Swap OpenGL buffers. 301 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GL_SwapWindow) 302 /// Throws: $(D SDL2Exception) on error. 303 void swapBuffers() 304 { 305 if (_glContext is null) 306 throw new SDL2Exception("swapBuffers failed: not an OpenGL window"); 307 SDL_GL_SwapWindow(_window); 308 } 309 310 /// Returns: Native SDL window context 311 SDL_Window* nativeWindow() nothrow @nogc pure @safe 312 { 313 return _window; 314 } 315 } 316 317 package 318 { 319 SDL2 _sdl2; 320 SDL_Window* _window; 321 } 322 323 private 324 { 325 Logger _logger; 326 SDL2Surface _surface; 327 SDL2GLContext _glContext; 328 uint _id; 329 330 bool _surfaceMustBeRenewed; 331 332 bool hasValidSurface() 333 { 334 return (!_surfaceMustBeRenewed) && (_surface !is null); 335 } 336 } 337 } 338 339 /// SDL OpenGL context wrapper. You probably don't need to use it directly. 340 final class SDL2GLContext 341 { 342 public 343 { 344 /// Creates an OpenGL context for a given SDL window. 345 this(SDL2Window window) 346 { 347 _window = window; 348 _context = SDL_GL_CreateContext(window._window); 349 _initialized = true; 350 } 351 352 ~this() 353 { 354 close(); 355 } 356 357 /// Release the associated SDL ressource. 358 void close() 359 { 360 if (_initialized) 361 { 362 // work-around Issue #19 363 // SDL complains with log message "wglMakeCurrent(): The handle is invalid." 364 // in the SDL_DestroyWindow() call if we destroy the OpenGL context before-hand 365 // 366 // SDL_GL_DeleteContext(_context); 367 _initialized = false; 368 } 369 } 370 371 /// Makes this OpenGL context current. 372 /// Throws: $(D SDL2Exception) on error. 373 void makeCurrent() 374 { 375 if (0 != SDL_GL_MakeCurrent(_window._window, _context)) 376 _window._sdl2.throwSDL2Exception("SDL_GL_MakeCurrent"); 377 } 378 } 379 380 package 381 { 382 SDL_GLContext _context; 383 SDL2Window _window; 384 } 385 386 private 387 { 388 bool _initialized; 389 } 390 } 391