Window.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. /**
  2. * Copyright (c) 2006-2014 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. // LOVE
  21. #include "common/config.h"
  22. #include "graphics/Graphics.h"
  23. #include "Window.h"
  24. // C++
  25. #include <iostream>
  26. #include <vector>
  27. #include <algorithm>
  28. namespace love
  29. {
  30. namespace window
  31. {
  32. namespace sdl
  33. {
  34. Window::Window()
  35. : windowTitle("")
  36. , created(false)
  37. , mouseGrabbed(false)
  38. , window(0)
  39. , context(0)
  40. {
  41. if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
  42. throw love::Exception("%s", SDL_GetError());
  43. }
  44. Window::~Window()
  45. {
  46. if (curMode.icon)
  47. curMode.icon->release();
  48. if (window)
  49. SDL_DestroyWindow(window);
  50. if (context)
  51. SDL_GL_DeleteContext(context);
  52. SDL_QuitSubSystem(SDL_INIT_VIDEO);
  53. }
  54. Window::_currentMode::_currentMode()
  55. : width(800)
  56. , height(600)
  57. , settings()
  58. , icon(0)
  59. {
  60. }
  61. bool Window::setWindow(int width, int height, WindowSettings *settings)
  62. {
  63. graphics::Graphics *gfx = (graphics::Graphics *) Module::findInstance("love.graphics.");
  64. if (gfx != nullptr)
  65. gfx->unSetMode();
  66. WindowSettings f;
  67. if (settings)
  68. f = *settings;
  69. f.minwidth = std::max(f.minwidth, 1);
  70. f.minheight = std::max(f.minheight, 1);
  71. f.display = std::min(std::max(f.display, 0), getDisplayCount() - 1);
  72. // Use the desktop resolution if a width or height of 0 is specified.
  73. if (width == 0 || height == 0)
  74. {
  75. SDL_DisplayMode mode = {};
  76. SDL_GetDesktopDisplayMode(f.display, &mode);
  77. width = mode.w;
  78. height = mode.h;
  79. }
  80. Uint32 sdlflags = SDL_WINDOW_OPENGL;
  81. if (f.fullscreen)
  82. {
  83. if (f.fstype == FULLSCREEN_TYPE_DESKTOP)
  84. sdlflags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
  85. else
  86. {
  87. sdlflags |= SDL_WINDOW_FULLSCREEN;
  88. // Fullscreen window creation will bug out if no mode can be used.
  89. SDL_DisplayMode mode = {0, width, height, 0, 0};
  90. if (SDL_GetClosestDisplayMode(f.display, &mode, &mode) == 0)
  91. return false;
  92. }
  93. }
  94. if (f.resizable)
  95. sdlflags |= SDL_WINDOW_RESIZABLE;
  96. if (f.borderless)
  97. sdlflags |= SDL_WINDOW_BORDERLESS;
  98. // FIXME: disabled in Linux for runtime SDL 2.0.0 compatibility.
  99. #if SDL_VERSION_ATLEAST(2,0,1) && !defined(LOVE_LINUX)
  100. if (f.highdpi)
  101. sdlflags |= SDL_WINDOW_ALLOW_HIGHDPI;
  102. #endif
  103. // Destroy and recreate the window if the dimensions or flags have changed.
  104. if (window)
  105. {
  106. int curdisplay = SDL_GetWindowDisplayIndex(window);
  107. Uint32 wflags = SDL_GetWindowFlags(window);
  108. Uint32 testflags = SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN_DESKTOP
  109. | SDL_WINDOW_RESIZABLE | SDL_WINDOW_BORDERLESS;
  110. // FIXME: disabled in Linux for runtime SDL 2.0.0 compatibility.
  111. #if SDL_VERSION_ATLEAST(2,0,1) && !defined(LOVE_LINUX)
  112. testflags |= SDL_WINDOW_ALLOW_HIGHDPI;
  113. #endif
  114. wflags &= testflags;
  115. if (sdlflags != wflags || width != curMode.width || height != curMode.height
  116. || f.display != curdisplay || f.fsaa != curMode.settings.fsaa)
  117. {
  118. SDL_DestroyWindow(window);
  119. window = 0;
  120. // The old window may have generated pending events which are no
  121. // longer relevant. Destroy them all!
  122. SDL_FlushEvent(SDL_WINDOWEVENT);
  123. }
  124. }
  125. int centeredpos = SDL_WINDOWPOS_CENTERED_DISPLAY(f.display);
  126. int uncenteredpos = SDL_WINDOWPOS_UNDEFINED_DISPLAY(f.display);
  127. if (!window)
  128. {
  129. // In Windows and Linux, some GL attributes are set on window creation.
  130. setWindowGLAttributes(f.fsaa, f.sRGB);
  131. const char *title = windowTitle.c_str();
  132. int pos = f.centered ? centeredpos : uncenteredpos;
  133. window = SDL_CreateWindow(title, pos, pos, width, height, sdlflags);
  134. if (!window && f.fsaa > 0)
  135. {
  136. // FSAA might have caused the failure, disable it and try again.
  137. SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
  138. SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
  139. window = SDL_CreateWindow(title, pos, pos, width, height, sdlflags);
  140. f.fsaa = 0;
  141. }
  142. // Make sure the window keeps any previously set icon.
  143. if (window && curMode.icon)
  144. setIcon(curMode.icon);
  145. }
  146. if (!window)
  147. {
  148. std::cerr << "Could not set video mode: " << SDL_GetError() << std::endl;
  149. return false;
  150. }
  151. // Enforce minimum window dimensions.
  152. SDL_SetWindowMinimumSize(window, f.minwidth, f.minheight);
  153. if (f.centered && !f.fullscreen)
  154. SDL_SetWindowPosition(window, centeredpos, centeredpos);
  155. SDL_RaiseWindow(window);
  156. if (!setContext(f.fsaa, f.vsync, f.sRGB))
  157. return false;
  158. created = true;
  159. updateSettings(f);
  160. if (gfx != nullptr)
  161. {
  162. int width = curMode.width;
  163. int height = curMode.height;
  164. // FIXME: disabled in Linux for runtime SDL 2.0.0 compatibility.
  165. #if SDL_VERSION_ATLEAST(2,0,1) && !defined(LOVE_LINUX)
  166. SDL_GL_GetDrawableSize(window, &width, &height);
  167. #endif
  168. gfx->setMode(width, height, curMode.settings.sRGB);
  169. }
  170. // Make sure the mouse keeps its previous grab setting.
  171. setMouseGrab(mouseGrabbed);
  172. return true;
  173. }
  174. bool Window::onWindowResize(int width, int height)
  175. {
  176. if (!window)
  177. return false;
  178. curMode.width = width;
  179. curMode.height = height;
  180. return true;
  181. }
  182. bool Window::setContext(int fsaa, bool vsync, bool sRGB)
  183. {
  184. // We would normally only need to recreate the context if FSAA changes or
  185. // SDL_GL_MakeCurrent is unsuccessful, but in Windows MakeCurrent can
  186. // sometimes claim success but the context will actually be trashed.
  187. if (context)
  188. {
  189. SDL_GL_DeleteContext(context);
  190. context = 0;
  191. }
  192. // Make sure the proper attributes are set.
  193. setWindowGLAttributes(fsaa, sRGB);
  194. context = SDL_GL_CreateContext(window);
  195. if (!context && fsaa > 0)
  196. {
  197. // FSAA might have caused the failure, disable it and try again.
  198. SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
  199. SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
  200. context = SDL_GL_CreateContext(window);
  201. }
  202. if (!context)
  203. {
  204. int flags = 0;
  205. SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &flags);
  206. if (flags & SDL_GL_CONTEXT_DEBUG_FLAG)
  207. {
  208. SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
  209. SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
  210. context = SDL_GL_CreateContext(window);
  211. }
  212. }
  213. if (!context)
  214. {
  215. std::cerr << "Could not set video mode: " << SDL_GetError() << std::endl;
  216. return false;
  217. }
  218. // Set vertical synchronization.
  219. SDL_GL_SetSwapInterval(vsync ? 1 : 0);
  220. // Verify FSAA setting.
  221. int buffers;
  222. int samples;
  223. SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &buffers);
  224. SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &samples);
  225. // Don't fail because of this, but issue a warning.
  226. if ((!buffers && fsaa) || (samples != fsaa))
  227. {
  228. std::cerr << "Warning, FSAA setting failed! (Result: buffers: " << buffers << ", samples: " << samples << ")" << std::endl;
  229. fsaa = (buffers > 0) ? samples : 0;
  230. }
  231. curMode.settings.fsaa = fsaa;
  232. curMode.settings.vsync = SDL_GL_GetSwapInterval() != 0;
  233. return true;
  234. }
  235. void Window::setWindowGLAttributes(int fsaa, bool /* sRGB */) const
  236. {
  237. // Set GL window attributes.
  238. SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
  239. SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
  240. SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
  241. SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
  242. SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  243. SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1);
  244. // FSAA.
  245. SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (fsaa > 0) ? 1 : 0);
  246. SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (fsaa > 0) ? fsaa : 0);
  247. /* FIXME: Enable this code but make sure to try to re-create the window and
  248. * context with this disabled, if creation fails with it enabled.
  249. * We can leave this out for now because in practice the framebuffer will
  250. * already be sRGB-capable (on desktops at least.)
  251. #if SDL_VERSION_ATLEAST(2,0,1)
  252. SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, sRGB ? 1 : 0);
  253. #endif
  254. */
  255. // Do we want a debug context?
  256. const char *debugenv = SDL_GetHint("LOVE_GRAPHICS_DEBUG");
  257. if (debugenv && *debugenv == '1')
  258. {
  259. SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
  260. SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
  261. }
  262. else
  263. {
  264. SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
  265. SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
  266. }
  267. }
  268. void Window::updateSettings(const WindowSettings &newsettings)
  269. {
  270. Uint32 wflags = SDL_GetWindowFlags(window);
  271. // Set the new display mode as the current display mode.
  272. SDL_GetWindowSize(window, &curMode.width, &curMode.height);
  273. if ((wflags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP)
  274. {
  275. curMode.settings.fullscreen = true;
  276. curMode.settings.fstype = FULLSCREEN_TYPE_DESKTOP;
  277. }
  278. else if ((wflags & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN)
  279. {
  280. curMode.settings.fullscreen = true;
  281. curMode.settings.fstype = FULLSCREEN_TYPE_NORMAL;
  282. }
  283. else
  284. {
  285. curMode.settings.fullscreen = false;
  286. curMode.settings.fstype = newsettings.fstype;
  287. }
  288. // The min width/height is set to 0 internally in SDL when in fullscreen.
  289. if (curMode.settings.fullscreen)
  290. {
  291. curMode.settings.minwidth = newsettings.minwidth;
  292. curMode.settings.minheight = newsettings.minheight;
  293. }
  294. else
  295. SDL_GetWindowMinimumSize(window, &curMode.settings.minwidth, &curMode.settings.minheight);
  296. curMode.settings.resizable = (wflags & SDL_WINDOW_RESIZABLE) != 0;
  297. curMode.settings.borderless = (wflags & SDL_WINDOW_BORDERLESS) != 0;
  298. curMode.settings.centered = newsettings.centered;
  299. curMode.settings.display = std::max(SDL_GetWindowDisplayIndex(window), 0);
  300. #if SDL_VERSION_ATLEAST(2,0,1)
  301. curMode.settings.highdpi = (wflags & SDL_WINDOW_ALLOW_HIGHDPI) != 0;
  302. #else
  303. curMode.settings.highdpi = false;
  304. #endif
  305. // Only minimize on focus loss if the window is in exclusive-fullscreen
  306. // mode.
  307. if (curMode.settings.fullscreen && curMode.settings.fstype == FULLSCREEN_TYPE_NORMAL)
  308. SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "1");
  309. else
  310. SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
  311. curMode.settings.sRGB = newsettings.sRGB;
  312. }
  313. void Window::getWindow(int &width, int &height, WindowSettings &settings)
  314. {
  315. // The window might have been modified (moved, resized, etc.) by the user.
  316. if (window)
  317. updateSettings(curMode.settings);
  318. width = curMode.width;
  319. height = curMode.height;
  320. settings = curMode.settings;
  321. }
  322. bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype)
  323. {
  324. if (!window)
  325. return false;
  326. WindowSettings newsettings = curMode.settings;
  327. newsettings.fullscreen = fullscreen;
  328. newsettings.fstype = fstype;
  329. Uint32 sdlflags = 0;
  330. if (fullscreen)
  331. {
  332. if (fstype == FULLSCREEN_TYPE_DESKTOP)
  333. sdlflags = SDL_WINDOW_FULLSCREEN_DESKTOP;
  334. else
  335. {
  336. sdlflags = SDL_WINDOW_FULLSCREEN;
  337. SDL_DisplayMode mode = {};
  338. mode.w = curMode.width;
  339. mode.h = curMode.height;
  340. SDL_GetClosestDisplayMode(SDL_GetWindowDisplayIndex(window), &mode, &mode);
  341. SDL_SetWindowDisplayMode(window, &mode);
  342. }
  343. }
  344. if (SDL_SetWindowFullscreen(window, sdlflags) == 0)
  345. {
  346. SDL_GL_MakeCurrent(window, context);
  347. updateSettings(newsettings);
  348. // Update the viewport size now instead of waiting for event polling.
  349. graphics::Graphics *gfx = (graphics::Graphics *) Module::findInstance("love.graphics.");
  350. if (gfx != nullptr)
  351. {
  352. int width = curMode.width;
  353. int height = curMode.height;
  354. // FIXME: disabled in Linux for runtime SDL 2.0.0 compatibility.
  355. #if SDL_VERSION_ATLEAST(2,0,1) && !defined(LOVE_LINUX)
  356. SDL_GL_GetDrawableSize(window, &width, &height);
  357. #endif
  358. gfx->setViewportSize(width, height);
  359. }
  360. return true;
  361. }
  362. return false;
  363. }
  364. bool Window::setFullscreen(bool fullscreen)
  365. {
  366. return setFullscreen(fullscreen, curMode.settings.fstype);
  367. }
  368. int Window::getDisplayCount() const
  369. {
  370. return SDL_GetNumVideoDisplays();
  371. }
  372. typedef Window::WindowSize WindowSize;
  373. std::vector<WindowSize> Window::getFullscreenSizes(int displayindex) const
  374. {
  375. std::vector<WindowSize> sizes;
  376. SDL_DisplayMode mode = {};
  377. std::vector<WindowSize>::const_iterator it;
  378. for (int i = 0; i < SDL_GetNumDisplayModes(displayindex); i++)
  379. {
  380. SDL_GetDisplayMode(displayindex, i, &mode);
  381. // SDL2's display mode list has multiple entries for modes of the same
  382. // size with different bits per pixel, so we need to filter those out.
  383. bool alreadyhassize = false;
  384. for (it = sizes.begin(); it != sizes.end(); ++it)
  385. {
  386. if (it->width == mode.w && it->height == mode.h)
  387. {
  388. alreadyhassize = true;
  389. break;
  390. }
  391. }
  392. if (!alreadyhassize)
  393. {
  394. WindowSize w = {mode.w, mode.h};
  395. sizes.push_back(w);
  396. }
  397. }
  398. return sizes;
  399. }
  400. int Window::getWidth() const
  401. {
  402. return curMode.width;
  403. }
  404. int Window::getHeight() const
  405. {
  406. return curMode.height;
  407. }
  408. void Window::getDesktopDimensions(int displayindex, int &width, int &height) const
  409. {
  410. if (displayindex >= 0 && displayindex < getDisplayCount())
  411. {
  412. SDL_DisplayMode mode = {};
  413. SDL_GetDesktopDisplayMode(displayindex, &mode);
  414. width = mode.w;
  415. height = mode.h;
  416. }
  417. else
  418. {
  419. width = 0;
  420. height = 0;
  421. }
  422. }
  423. bool Window::isCreated() const
  424. {
  425. return created;
  426. }
  427. void Window::setWindowTitle(const std::string &title)
  428. {
  429. windowTitle = title;
  430. if (window)
  431. SDL_SetWindowTitle(window, title.c_str());
  432. }
  433. const std::string &Window::getWindowTitle() const
  434. {
  435. return windowTitle;
  436. }
  437. bool Window::setIcon(love::image::ImageData *imgd)
  438. {
  439. if (!imgd)
  440. return false;
  441. imgd->retain();
  442. if (curMode.icon)
  443. curMode.icon->release();
  444. curMode.icon = imgd;
  445. if (!window)
  446. return false;
  447. Uint32 rmask, gmask, bmask, amask;
  448. #ifdef LOVE_BIG_ENDIAN
  449. rmask = 0xFF000000;
  450. gmask = 0x00FF0000;
  451. bmask = 0x0000FF00;
  452. amask = 0x000000FF;
  453. #else
  454. rmask = 0x000000FF;
  455. gmask = 0x0000FF00;
  456. bmask = 0x00FF0000;
  457. amask = 0xFF000000;
  458. #endif
  459. int w = imgd->getWidth();
  460. int h = imgd->getHeight();
  461. int pitch = imgd->getWidth() * 4;
  462. SDL_Surface *sdlicon = 0;
  463. {
  464. // We don't want another thread modifying the ImageData mid-copy.
  465. love::thread::Lock lock(imgd->getMutex());
  466. sdlicon = SDL_CreateRGBSurfaceFrom(imgd->getData(), w, h, 32, pitch, rmask, gmask, bmask, amask);
  467. }
  468. if (!sdlicon)
  469. return false;
  470. SDL_SetWindowIcon(window, sdlicon);
  471. SDL_FreeSurface(sdlicon);
  472. return true;
  473. }
  474. love::image::ImageData *Window::getIcon()
  475. {
  476. return curMode.icon;
  477. }
  478. void Window::swapBuffers()
  479. {
  480. SDL_GL_SwapWindow(window);
  481. }
  482. bool Window::hasFocus() const
  483. {
  484. return (window && SDL_GetKeyboardFocus() == window);
  485. }
  486. bool Window::hasMouseFocus() const
  487. {
  488. return (window && SDL_GetMouseFocus() == window);
  489. }
  490. bool Window::isVisible() const
  491. {
  492. return window && (SDL_GetWindowFlags(window) & SDL_WINDOW_SHOWN) != 0;
  493. }
  494. void Window::setMouseVisible(bool visible)
  495. {
  496. SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE);
  497. }
  498. bool Window::getMouseVisible() const
  499. {
  500. return (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE);
  501. }
  502. void Window::setMouseGrab(bool grab)
  503. {
  504. mouseGrabbed = grab;
  505. if (window)
  506. SDL_SetWindowGrab(window, (SDL_bool) grab);
  507. }
  508. bool Window::isMouseGrabbed() const
  509. {
  510. if (window)
  511. return (bool) SDL_GetWindowGrab(window);
  512. else
  513. return mouseGrabbed;
  514. }
  515. double Window::getPixelScale() const
  516. {
  517. double scale = 1.0;
  518. // FIXME: disabled in Linux for runtime SDL 2.0.0 compatibility.
  519. #if SDL_VERSION_ATLEAST(2,0,1) && !defined(LOVE_LINUX)
  520. if (window)
  521. {
  522. int wheight;
  523. SDL_GetWindowSize(window, nullptr, &wheight);
  524. int dheight = wheight;
  525. SDL_GL_GetDrawableSize(window, nullptr, &dheight);
  526. scale = (double) dheight / wheight;
  527. }
  528. #endif
  529. return scale;
  530. }
  531. const void *Window::getHandle() const
  532. {
  533. return window;
  534. }
  535. love::window::Window *Window::createSingleton()
  536. {
  537. if (!singleton)
  538. singleton = new Window();
  539. else
  540. singleton->retain();
  541. return singleton;
  542. }
  543. love::window::Window *Window::getSingleton()
  544. {
  545. return singleton;
  546. }
  547. const char *Window::getName() const
  548. {
  549. return "love.window.sdl";
  550. }
  551. } // sdl
  552. } // window
  553. } // love