Window.cpp 17 KB

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