2
0

sdlWindowMgr.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "windowManager/sdl/sdlWindowMgr.h"
  23. #include "platformSDL/sdlInputManager.h"
  24. #include "platform/platformVolume.h"
  25. #include "core/util/path.h"
  26. #include "gfx/gfxDevice.h"
  27. #include "core/util/journal/process.h"
  28. #include "core/strings/unicode.h"
  29. #include "gfx/bitmap/gBitmap.h"
  30. #include "SDL.h"
  31. // ------------------------------------------------------------------------
  32. void sdl_CloseSplashWindow(void* hinst);
  33. #ifdef TORQUE_SDL
  34. PlatformWindowManager * CreatePlatformWindowManager()
  35. {
  36. return new PlatformWindowManagerSDL();
  37. }
  38. #endif
  39. // ------------------------------------------------------------------------
  40. PlatformWindowManagerSDL::PlatformWindowManagerSDL()
  41. {
  42. // Register in the process list.
  43. mOnProcessSignalSlot.setDelegate( this, &PlatformWindowManagerSDL::_process );
  44. Process::notify( mOnProcessSignalSlot, PROCESS_INPUT_ORDER );
  45. // Init our list of allocated windows.
  46. mWindowListHead = NULL;
  47. // By default, we have no parent window.
  48. mParentWindow = NULL;
  49. mCurtainWindow = NULL;
  50. mDisplayWindow = true;
  51. mOffscreenRender = false;
  52. mInputState = KeyboardInputState::NONE;
  53. }
  54. PlatformWindowManagerSDL::~PlatformWindowManagerSDL()
  55. {
  56. if (mWindowListHead == NULL)
  57. return;
  58. // Kill all our windows first.
  59. while(mWindowListHead)
  60. // The destructors update the list, so this works just fine.
  61. delete mWindowListHead;
  62. }
  63. RectI PlatformWindowManagerSDL::getPrimaryDesktopArea()
  64. {
  65. // Primary is monitor 0
  66. return getMonitorRect(0);
  67. }
  68. Point2I PlatformWindowManagerSDL::getDesktopResolution()
  69. {
  70. SDL_DisplayMode mode;
  71. SDL_GetDesktopDisplayMode(0, &mode);
  72. // Return Resolution
  73. return Point2I(mode.w, mode.h);
  74. }
  75. S32 PlatformWindowManagerSDL::getDesktopBitDepth()
  76. {
  77. // Return Bits per Pixel
  78. SDL_DisplayMode mode;
  79. SDL_GetDesktopDisplayMode(0, &mode);
  80. int bbp;
  81. unsigned int r,g,b,a;
  82. SDL_PixelFormatEnumToMasks(mode.format, &bbp, &r, &g, &b, &a);
  83. return bbp;
  84. }
  85. S32 PlatformWindowManagerSDL::findFirstMatchingMonitor(const char* name)
  86. {
  87. S32 count = SDL_GetNumVideoDisplays();
  88. for (U32 index = 0; index < count; ++index)
  89. {
  90. if (dStrstr(name, SDL_GetDisplayName(index)) == name)
  91. return index;
  92. }
  93. return 0;
  94. }
  95. U32 PlatformWindowManagerSDL::getMonitorCount()
  96. {
  97. S32 monitorCount = SDL_GetNumVideoDisplays();
  98. if (monitorCount < 0)
  99. {
  100. Con::errorf("SDL_GetNumVideoDisplays() failed: %s", SDL_GetError());
  101. monitorCount = 0;
  102. }
  103. return (U32)monitorCount;
  104. }
  105. const char* PlatformWindowManagerSDL::getMonitorName(U32 index)
  106. {
  107. const char* monitorName = SDL_GetDisplayName(index);
  108. if (monitorName == NULL)
  109. Con::errorf("SDL_GetDisplayName() failed: %s", SDL_GetError());
  110. return monitorName;
  111. }
  112. RectI PlatformWindowManagerSDL::getMonitorRect(U32 index)
  113. {
  114. SDL_Rect sdlRect;
  115. if (0 != SDL_GetDisplayBounds(index, &sdlRect))
  116. {
  117. Con::errorf("SDL_GetDisplayBounds() failed: %s", SDL_GetError());
  118. return RectI(0, 0, 0, 0);
  119. }
  120. return RectI(sdlRect.x, sdlRect.y, sdlRect.w, sdlRect.h);
  121. }
  122. RectI PlatformWindowManagerSDL::getMonitorUsableRect(U32 index)
  123. {
  124. SDL_Rect sdlRect;
  125. if (0 != SDL_GetDisplayUsableBounds(index, &sdlRect))
  126. {
  127. Con::errorf("SDL_GetDisplayUsableBounds() failed: %s", SDL_GetError());
  128. return RectI(0, 0, 0, 0);
  129. }
  130. return RectI(sdlRect.x, sdlRect.y, sdlRect.w, sdlRect.h);
  131. }
  132. U32 PlatformWindowManagerSDL::getMonitorModeCount(U32 monitorIndex)
  133. {
  134. S32 modeCount = SDL_GetNumDisplayModes(monitorIndex);
  135. if (modeCount < 0)
  136. {
  137. Con::errorf("SDL_GetNumDisplayModes(%d) failed: %s", monitorIndex, SDL_GetError());
  138. modeCount = 0;
  139. }
  140. return (U32)modeCount;
  141. }
  142. const String PlatformWindowManagerSDL::getMonitorMode(U32 monitorIndex, U32 modeIndex)
  143. {
  144. SDL_DisplayMode mode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 };
  145. if (SDL_GetDisplayMode(monitorIndex, modeIndex, &mode) != 0)
  146. {
  147. Con::errorf("SDL_GetDisplayMode(%d, %d) failed: %s", monitorIndex, modeIndex, SDL_GetError());
  148. return String::EmptyString;
  149. }
  150. GFXVideoMode vm;
  151. vm.resolution.set(mode.w, mode.h);
  152. vm.refreshRate = mode.refresh_rate;
  153. vm.bitDepth = 32;
  154. vm.antialiasLevel = 0;
  155. vm.fullScreen = false;
  156. vm.wideScreen = false;
  157. return vm.toString();
  158. }
  159. const String PlatformWindowManagerSDL::getMonitorDesktopMode(U32 monitorIndex)
  160. {
  161. SDL_DisplayMode mode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 };
  162. if (SDL_GetDesktopDisplayMode(monitorIndex, &mode) != 0)
  163. {
  164. Con::errorf("SDL_GetDesktopDisplayMode(%d) failed: %s", monitorIndex, SDL_GetError());
  165. return String::EmptyString;
  166. }
  167. GFXVideoMode vm;
  168. vm.resolution.set(mode.w, mode.h);
  169. vm.refreshRate = mode.refresh_rate;
  170. int bbp;
  171. unsigned int r, g, b, a;
  172. SDL_PixelFormatEnumToMasks(mode.format, &bbp, &r, &g, &b, &a);
  173. vm.bitDepth = bbp;
  174. vm.antialiasLevel = 0;
  175. vm.fullScreen = false;
  176. vm.wideScreen = ((mode.w / 16) * 9) == mode.h;
  177. return vm.toString();
  178. }
  179. void PlatformWindowManagerSDL::getMonitorRegions(Vector<RectI> &regions)
  180. {
  181. SDL_Rect sdlRect;
  182. S32 monitorCount = SDL_GetNumVideoDisplays();
  183. for (S32 index = 0; index < monitorCount; ++index)
  184. {
  185. if (0 == SDL_GetDisplayBounds(index, &sdlRect))
  186. regions.push_back(RectI(sdlRect.x, sdlRect.y, sdlRect.w, sdlRect.h));
  187. }
  188. }
  189. void PlatformWindowManagerSDL::getWindows(VectorPtr<PlatformWindow*> &windows)
  190. {
  191. PlatformWindowSDL *win = mWindowListHead;
  192. while(win)
  193. {
  194. windows.push_back(win);
  195. win = win->mNextWindow;
  196. }
  197. }
  198. PlatformWindow *PlatformWindowManagerSDL::createWindow(GFXDevice *device, const GFXVideoMode &mode)
  199. {
  200. // Do the allocation.
  201. PlatformWindowSDL *window = new PlatformWindowSDL();
  202. U32 windowFlags = /*SDL_WINDOW_SHOWN |*/ SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN;
  203. if(GFX->getAdapterType() == OpenGL)
  204. windowFlags |= SDL_WINDOW_OPENGL;
  205. window->mWindowHandle = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, mode.resolution.x, mode.resolution.y, windowFlags );
  206. window->mWindowId = SDL_GetWindowID( window->mWindowHandle );
  207. window->mOwningManager = this;
  208. mWindowMap[ window->mWindowId ] = window;
  209. //Now, fetch our window icon, if any
  210. Torque::Path iconPath = Torque::Path(Con::getVariable( "$Core::windowIcon" ));
  211. if (iconPath.getExtension() == String("bmp"))
  212. {
  213. Con::errorf("Unable to use bmp format images for the window icon. Please use a different format.");
  214. }
  215. else
  216. {
  217. Resource<GBitmap> img = GBitmap::load(iconPath);
  218. if (img != NULL)
  219. {
  220. U32 pitch;
  221. U32 width = img->getWidth();
  222. bool hasAlpha = img->getHasTransparency();
  223. U32 depth;
  224. if (hasAlpha)
  225. {
  226. pitch = 4 * width;
  227. depth = 32;
  228. }
  229. else
  230. {
  231. pitch = 3 * width;
  232. depth = 24;
  233. }
  234. Uint32 rmask, gmask, bmask, amask;
  235. if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
  236. {
  237. S32 shift = hasAlpha ? 8 : 0;
  238. rmask = 0xff000000 >> shift;
  239. gmask = 0x00ff0000 >> shift;
  240. bmask = 0x0000ff00 >> shift;
  241. amask = 0x000000ff >> shift;
  242. }
  243. else
  244. {
  245. rmask = 0x000000ff;
  246. gmask = 0x0000ff00;
  247. bmask = 0x00ff0000;
  248. amask = hasAlpha ? 0xff000000 : 0;
  249. }
  250. SDL_Surface* iconSurface = SDL_CreateRGBSurfaceFrom(img->getAddress(0, 0), img->getWidth(), img->getHeight(), depth, pitch, rmask, gmask, bmask, amask);
  251. SDL_SetWindowIcon(window->mWindowHandle, iconSurface);
  252. SDL_FreeSurface(iconSurface);
  253. }
  254. }
  255. if(device)
  256. {
  257. window->mDevice = device;
  258. window->mTarget = device->allocWindowTarget(window);
  259. AssertISV(window->mTarget, "PlatformWindowManagerSDL::createWindow - failed to get a window target back from the device.");
  260. }
  261. else
  262. {
  263. Con::warnf("PlatformWindowManagerSDL::createWindow - created a window with no device!");
  264. }
  265. //Set it up for drag-n-drop events
  266. #ifdef TORQUE_TOOLS
  267. SDL_EventState(SDL_DROPBEGIN, SDL_ENABLE);
  268. SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
  269. SDL_EventState(SDL_DROPCOMPLETE, SDL_ENABLE);
  270. #endif
  271. linkWindow(window);
  272. SDL_SetWindowMinimumSize(window->mWindowHandle, Con::getIntVariable("$Video::minimumXResolution", 1024),
  273. Con::getIntVariable("$Video::minimumYResolution", 720));
  274. return window;
  275. }
  276. void PlatformWindowManagerSDL::setParentWindow(void* newParent)
  277. {
  278. }
  279. void* PlatformWindowManagerSDL::getParentWindow()
  280. {
  281. return NULL;
  282. }
  283. void PlatformWindowManagerSDL::_process()
  284. {
  285. SDL_Event evt;
  286. while( SDL_PollEvent(&evt) )
  287. {
  288. if (evt.type >= SDL_JOYAXISMOTION && evt.type <= SDL_CONTROLLERDEVICEREMAPPED)
  289. {
  290. SDLInputManager* mgr = static_cast<SDLInputManager*>(Input::getManager());
  291. if (mgr)
  292. mgr->processEvent(evt);
  293. continue;
  294. }
  295. switch(evt.type)
  296. {
  297. case SDL_QUIT:
  298. {
  299. PlatformWindowSDL *window = static_cast<PlatformWindowSDL*>( getFirstWindow() );
  300. if(window)
  301. window->appEvent.trigger( window->getWindowId(), WindowClose );
  302. break;
  303. }
  304. case SDL_KEYDOWN:
  305. case SDL_KEYUP:
  306. {
  307. PlatformWindowSDL *window = mWindowMap[evt.key.windowID];
  308. if(window)
  309. window->_processSDLEvent(evt);
  310. break;
  311. }
  312. case SDL_MOUSEWHEEL:
  313. {
  314. PlatformWindowSDL *window = mWindowMap[evt.wheel.windowID];
  315. if (window)
  316. window->_processSDLEvent(evt);
  317. break;
  318. }
  319. case SDL_MOUSEMOTION:
  320. {
  321. PlatformWindowSDL *window = mWindowMap[evt.motion.windowID];
  322. if(window)
  323. window->_processSDLEvent(evt);
  324. break;
  325. }
  326. case SDL_MOUSEBUTTONDOWN:
  327. case SDL_MOUSEBUTTONUP:
  328. {
  329. PlatformWindowSDL *window = mWindowMap[evt.button.windowID];
  330. if(window)
  331. window->_processSDLEvent(evt);
  332. break;
  333. }
  334. case SDL_TEXTINPUT:
  335. {
  336. PlatformWindowSDL *window = mWindowMap[evt.text.windowID];
  337. if(window)
  338. window->_processSDLEvent(evt);
  339. break;
  340. }
  341. case SDL_WINDOWEVENT:
  342. {
  343. PlatformWindowSDL *window = mWindowMap[evt.window.windowID];
  344. if(window)
  345. window->_processSDLEvent(evt);
  346. break;
  347. }
  348. case(SDL_DROPBEGIN):
  349. {
  350. if (!Con::isFunction("onDropBegin"))
  351. break;
  352. Con::executef("onDropBegin");
  353. }
  354. case (SDL_DROPFILE):
  355. {
  356. // In case if dropped file
  357. if (!Con::isFunction("onDropFile"))
  358. break;
  359. char* fileName = evt.drop.file;
  360. if (!Platform::isDirectory(fileName) && !Platform::isFile(fileName))
  361. break;
  362. Con::executef("onDropFile", StringTable->insert(fileName));
  363. SDL_free(fileName); // Free dropped_filedir memory
  364. break;
  365. }
  366. case(SDL_DROPCOMPLETE):
  367. {
  368. if (Con::isFunction("onDropEnd"))
  369. Con::executef("onDropEnd");
  370. break;
  371. }
  372. default:
  373. {
  374. #ifdef TORQUE_DEBUG
  375. Con::warnf("Unhandled SDL input event: 0x%04x", evt.type);
  376. #endif
  377. }
  378. }
  379. }
  380. // After the event loop is processed, we can now see if we have to notify
  381. // SDL that we want text based events. This fixes a bug where text based
  382. // events would be generated while key presses would still be happening.
  383. // See KeyboardInputState for further documentation.
  384. if (mInputState != KeyboardInputState::NONE)
  385. {
  386. // Update text mode toggling.
  387. if (mInputState == KeyboardInputState::TEXT_INPUT)
  388. SDL_StartTextInput();
  389. else
  390. SDL_StopTextInput();
  391. // Done until we need to update it again.
  392. mInputState = KeyboardInputState::NONE;
  393. }
  394. }
  395. PlatformWindow * PlatformWindowManagerSDL::getWindowById( WindowId id )
  396. {
  397. // Walk the list and find the matching id, if any.
  398. PlatformWindowSDL *win = mWindowListHead;
  399. while(win)
  400. {
  401. if(win->getWindowId() == id)
  402. return win;
  403. win = win->mNextWindow;
  404. }
  405. return NULL;
  406. }
  407. PlatformWindow * PlatformWindowManagerSDL::getFirstWindow()
  408. {
  409. return mWindowListHead != NULL ? mWindowListHead : NULL;
  410. }
  411. PlatformWindow* PlatformWindowManagerSDL::getFocusedWindow()
  412. {
  413. PlatformWindowSDL* window = mWindowListHead;
  414. while( window )
  415. {
  416. if( window->isFocused() )
  417. return window;
  418. window = window->mNextWindow;
  419. }
  420. return NULL;
  421. }
  422. void PlatformWindowManagerSDL::linkWindow( PlatformWindowSDL *w )
  423. {
  424. w->mNextWindow = mWindowListHead;
  425. mWindowListHead = w;
  426. }
  427. void PlatformWindowManagerSDL::unlinkWindow( PlatformWindowSDL *w )
  428. {
  429. PlatformWindowSDL **walk = &mWindowListHead;
  430. while(*walk)
  431. {
  432. if(*walk != w)
  433. {
  434. // Advance to next item in list.
  435. walk = &(*walk)->mNextWindow;
  436. continue;
  437. }
  438. // Got a match - unlink and return.
  439. *walk = (*walk)->mNextWindow;
  440. return;
  441. }
  442. }
  443. void PlatformWindowManagerSDL::_processCmdLineArgs( const S32 argc, const char **argv )
  444. {
  445. // TODO SDL
  446. }
  447. void PlatformWindowManagerSDL::lowerCurtain()
  448. {
  449. if(mCurtainWindow)
  450. return;
  451. // TODO SDL
  452. }
  453. void PlatformWindowManagerSDL::raiseCurtain()
  454. {
  455. if(!mCurtainWindow)
  456. return;
  457. // TODO SDL
  458. }
  459. void PlatformWindowManagerSDL::updateSDLTextInputState(KeyboardInputState state)
  460. {
  461. // Force update state. This will respond at the end of the event loop.
  462. mInputState = state;
  463. }
  464. void Platform::openFolder(const char* path )
  465. {
  466. AssertFatal(0, "Not Implemented");
  467. }
  468. void Platform::openFile(const char* path )
  469. {
  470. AssertFatal(0, "Not Implemented");
  471. }
  472. //------------------------------------------------------------------------------
  473. namespace GL
  474. {
  475. void gglPerformBinds();
  476. }
  477. void InitWindowingSystem()
  478. {
  479. }
  480. AFTER_MODULE_INIT(gfx)
  481. {
  482. #if !defined(TORQUE_DEDICATED)
  483. int res = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE);
  484. AssertFatal(res != -1, avar("SDL error:%s", SDL_GetError()));
  485. // By default, SDL enables text input. We disable it on initialization, and
  486. // we will enable it whenever the time is right.
  487. SDL_StopTextInput();
  488. #endif
  489. }