sdlWindowMgr.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  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 "gfx/gfxDevice.h"
  25. #include "core/util/journal/process.h"
  26. #include "core/strings/unicode.h"
  27. #include "gfx/bitmap/gBitmap.h"
  28. #include "SDL.h"
  29. // ------------------------------------------------------------------------
  30. void sdl_CloseSplashWindow(void* hinst);
  31. #ifdef TORQUE_SDL
  32. PlatformWindowManager * CreatePlatformWindowManager()
  33. {
  34. return new PlatformWindowManagerSDL();
  35. }
  36. #endif
  37. // ------------------------------------------------------------------------
  38. PlatformWindowManagerSDL::PlatformWindowManagerSDL()
  39. {
  40. // Register in the process list.
  41. mOnProcessSignalSlot.setDelegate( this, &PlatformWindowManagerSDL::_process );
  42. Process::notify( mOnProcessSignalSlot, PROCESS_INPUT_ORDER );
  43. // Init our list of allocated windows.
  44. mWindowListHead = NULL;
  45. // By default, we have no parent window.
  46. mParentWindow = NULL;
  47. mCurtainWindow = NULL;
  48. mDisplayWindow = true;
  49. mOffscreenRender = false;
  50. mInputState = KeyboardInputState::NONE;
  51. }
  52. PlatformWindowManagerSDL::~PlatformWindowManagerSDL()
  53. {
  54. // Kill all our windows first.
  55. while(mWindowListHead)
  56. // The destructors update the list, so this works just fine.
  57. delete mWindowListHead;
  58. }
  59. RectI PlatformWindowManagerSDL::getPrimaryDesktopArea()
  60. {
  61. // Primary is monitor 0
  62. return getMonitorRect(0);
  63. }
  64. Point2I PlatformWindowManagerSDL::getDesktopResolution()
  65. {
  66. SDL_DisplayMode mode;
  67. SDL_GetDesktopDisplayMode(0, &mode);
  68. // Return Resolution
  69. return Point2I(mode.w, mode.h);
  70. }
  71. S32 PlatformWindowManagerSDL::getDesktopBitDepth()
  72. {
  73. // Return Bits per Pixel
  74. SDL_DisplayMode mode;
  75. SDL_GetDesktopDisplayMode(0, &mode);
  76. int bbp;
  77. unsigned int r,g,b,a;
  78. SDL_PixelFormatEnumToMasks(mode.format, &bbp, &r, &g, &b, &a);
  79. return bbp;
  80. }
  81. S32 PlatformWindowManagerSDL::findFirstMatchingMonitor(const char* name)
  82. {
  83. S32 count = SDL_GetNumVideoDisplays();
  84. for (U32 index = 0; index < count; ++index)
  85. {
  86. if (dStrstr(name, SDL_GetDisplayName(index)) == name)
  87. return index;
  88. }
  89. return 0;
  90. }
  91. U32 PlatformWindowManagerSDL::getMonitorCount()
  92. {
  93. S32 monitorCount = SDL_GetNumVideoDisplays();
  94. if (monitorCount < 0)
  95. {
  96. Con::errorf("SDL_GetNumVideoDisplays() failed: %s", SDL_GetError());
  97. monitorCount = 0;
  98. }
  99. return (U32)monitorCount;
  100. }
  101. const char* PlatformWindowManagerSDL::getMonitorName(U32 index)
  102. {
  103. const char* monitorName = SDL_GetDisplayName(index);
  104. if (monitorName == NULL)
  105. Con::errorf("SDL_GetDisplayName() failed: %s", SDL_GetError());
  106. return monitorName;
  107. }
  108. RectI PlatformWindowManagerSDL::getMonitorRect(U32 index)
  109. {
  110. SDL_Rect sdlRect;
  111. if (0 != SDL_GetDisplayBounds(index, &sdlRect))
  112. {
  113. Con::errorf("SDL_GetDisplayBounds() failed: %s", SDL_GetError());
  114. return RectI(0, 0, 0, 0);
  115. }
  116. return RectI(sdlRect.x, sdlRect.y, sdlRect.w, sdlRect.h);
  117. }
  118. void PlatformWindowManagerSDL::getMonitorRegions(Vector<RectI> &regions)
  119. {
  120. SDL_Rect sdlRect;
  121. S32 monitorCount = SDL_GetNumVideoDisplays();
  122. for (S32 index = 0; index < monitorCount; ++index)
  123. {
  124. if (0 == SDL_GetDisplayBounds(index, &sdlRect))
  125. regions.push_back(RectI(sdlRect.x, sdlRect.y, sdlRect.w, sdlRect.h));
  126. }
  127. }
  128. void PlatformWindowManagerSDL::getWindows(VectorPtr<PlatformWindow*> &windows)
  129. {
  130. PlatformWindowSDL *win = mWindowListHead;
  131. while(win)
  132. {
  133. windows.push_back(win);
  134. win = win->mNextWindow;
  135. }
  136. }
  137. PlatformWindow *PlatformWindowManagerSDL::createWindow(GFXDevice *device, const GFXVideoMode &mode)
  138. {
  139. // Do the allocation.
  140. PlatformWindowSDL *window = new PlatformWindowSDL();
  141. U32 windowFlags = /*SDL_WINDOW_SHOWN |*/ SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN;
  142. if(GFX->getAdapterType() == OpenGL)
  143. windowFlags |= SDL_WINDOW_OPENGL;
  144. window->mWindowHandle = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, mode.resolution.x, mode.resolution.y, windowFlags );
  145. window->mWindowId = SDL_GetWindowID( window->mWindowHandle );
  146. window->mOwningManager = this;
  147. mWindowMap[ window->mWindowId ] = window;
  148. //Now, fetch our window icon, if any
  149. Torque::Path iconPath = Torque::Path(Con::getVariable( "$Core::windowIcon" ));
  150. if (iconPath.getExtension() == String("bmp"))
  151. {
  152. Con::errorf("Unable to use bmp format images for the window icon. Please use a different format.");
  153. }
  154. else
  155. {
  156. Resource<GBitmap> img = GBitmap::load(iconPath);
  157. if (img != NULL)
  158. {
  159. U32 pitch;
  160. U32 width = img->getWidth();
  161. bool hasAlpha = img->getHasTransparency();
  162. U32 depth;
  163. if (hasAlpha)
  164. {
  165. pitch = 4 * width;
  166. depth = 32;
  167. }
  168. else
  169. {
  170. pitch = 3 * width;
  171. depth = 24;
  172. }
  173. Uint32 rmask, gmask, bmask, amask;
  174. if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
  175. {
  176. S32 shift = hasAlpha ? 8 : 0;
  177. rmask = 0xff000000 >> shift;
  178. gmask = 0x00ff0000 >> shift;
  179. bmask = 0x0000ff00 >> shift;
  180. amask = 0x000000ff >> shift;
  181. }
  182. else
  183. {
  184. rmask = 0x000000ff;
  185. gmask = 0x0000ff00;
  186. bmask = 0x00ff0000;
  187. amask = hasAlpha ? 0xff000000 : 0;
  188. }
  189. SDL_Surface* iconSurface = SDL_CreateRGBSurfaceFrom(img->getAddress(0, 0), img->getWidth(), img->getHeight(), depth, pitch, rmask, gmask, bmask, amask);
  190. SDL_SetWindowIcon(window->mWindowHandle, iconSurface);
  191. SDL_FreeSurface(iconSurface);
  192. }
  193. }
  194. if(device)
  195. {
  196. window->mDevice = device;
  197. window->mTarget = device->allocWindowTarget(window);
  198. AssertISV(window->mTarget, "PlatformWindowManagerSDL::createWindow - failed to get a window target back from the device.");
  199. }
  200. else
  201. {
  202. Con::warnf("PlatformWindowManagerSDL::createWindow - created a window with no device!");
  203. }
  204. //Set it up for drag-n-drop events
  205. #ifdef TORQUE_TOOLS
  206. SDL_EventState(SDL_DROPBEGIN, SDL_ENABLE);
  207. SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
  208. SDL_EventState(SDL_DROPCOMPLETE, SDL_ENABLE);
  209. #endif
  210. linkWindow(window);
  211. return window;
  212. }
  213. void PlatformWindowManagerSDL::setParentWindow(void* newParent)
  214. {
  215. }
  216. void* PlatformWindowManagerSDL::getParentWindow()
  217. {
  218. return NULL;
  219. }
  220. void PlatformWindowManagerSDL::_process()
  221. {
  222. SDL_Event evt;
  223. while( SDL_PollEvent(&evt) )
  224. {
  225. if (evt.type >= SDL_JOYAXISMOTION && evt.type <= SDL_CONTROLLERDEVICEREMAPPED)
  226. {
  227. SDLInputManager* mgr = static_cast<SDLInputManager*>(Input::getManager());
  228. if (mgr)
  229. mgr->processEvent(evt);
  230. continue;
  231. }
  232. switch(evt.type)
  233. {
  234. case SDL_QUIT:
  235. {
  236. PlatformWindowSDL *window = static_cast<PlatformWindowSDL*>( getFirstWindow() );
  237. if(window)
  238. window->appEvent.trigger( window->getWindowId(), WindowClose );
  239. break;
  240. }
  241. case SDL_KEYDOWN:
  242. case SDL_KEYUP:
  243. {
  244. PlatformWindowSDL *window = mWindowMap[evt.key.windowID];
  245. if(window)
  246. window->_processSDLEvent(evt);
  247. break;
  248. }
  249. case SDL_MOUSEWHEEL:
  250. {
  251. PlatformWindowSDL *window = mWindowMap[evt.wheel.windowID];
  252. if (window)
  253. window->_processSDLEvent(evt);
  254. break;
  255. }
  256. case SDL_MOUSEMOTION:
  257. {
  258. PlatformWindowSDL *window = mWindowMap[evt.motion.windowID];
  259. if(window)
  260. window->_processSDLEvent(evt);
  261. break;
  262. }
  263. case SDL_MOUSEBUTTONDOWN:
  264. case SDL_MOUSEBUTTONUP:
  265. {
  266. PlatformWindowSDL *window = mWindowMap[evt.button.windowID];
  267. if(window)
  268. window->_processSDLEvent(evt);
  269. break;
  270. }
  271. case SDL_TEXTINPUT:
  272. {
  273. PlatformWindowSDL *window = mWindowMap[evt.text.windowID];
  274. if(window)
  275. window->_processSDLEvent(evt);
  276. break;
  277. }
  278. case SDL_WINDOWEVENT:
  279. {
  280. PlatformWindowSDL *window = mWindowMap[evt.window.windowID];
  281. if(window)
  282. window->_processSDLEvent(evt);
  283. break;
  284. }
  285. case(SDL_DROPBEGIN):
  286. {
  287. if (!Con::isFunction("onDropBegin"))
  288. break;
  289. Con::executef("onDropBegin");
  290. }
  291. case (SDL_DROPFILE):
  292. {
  293. // In case if dropped file
  294. if (!Con::isFunction("onDropFile"))
  295. break;
  296. char* fileName = evt.drop.file;
  297. if (!Platform::isFile(fileName))
  298. break;
  299. Con::executef("onDropFile", StringTable->insert(fileName));
  300. SDL_free(fileName); // Free dropped_filedir memory
  301. break;
  302. }
  303. case(SDL_DROPCOMPLETE):
  304. {
  305. if (Con::isFunction("onDropEnd"))
  306. Con::executef("onDropEnd");
  307. break;
  308. }
  309. default:
  310. {
  311. #ifdef TORQUE_DEBUG
  312. Con::warnf("Unhandled SDL input event: 0x%04x", evt.type);
  313. #endif
  314. }
  315. }
  316. }
  317. // After the event loop is processed, we can now see if we have to notify
  318. // SDL that we want text based events. This fixes a bug where text based
  319. // events would be generated while key presses would still be happening.
  320. // See KeyboardInputState for further documentation.
  321. if (mInputState != KeyboardInputState::NONE)
  322. {
  323. // Update text mode toggling.
  324. if (mInputState == KeyboardInputState::TEXT_INPUT)
  325. SDL_StartTextInput();
  326. else
  327. SDL_StopTextInput();
  328. // Done until we need to update it again.
  329. mInputState = KeyboardInputState::NONE;
  330. }
  331. }
  332. PlatformWindow * PlatformWindowManagerSDL::getWindowById( WindowId id )
  333. {
  334. // Walk the list and find the matching id, if any.
  335. PlatformWindowSDL *win = mWindowListHead;
  336. while(win)
  337. {
  338. if(win->getWindowId() == id)
  339. return win;
  340. win = win->mNextWindow;
  341. }
  342. return NULL;
  343. }
  344. PlatformWindow * PlatformWindowManagerSDL::getFirstWindow()
  345. {
  346. return mWindowListHead != NULL ? mWindowListHead : NULL;
  347. }
  348. PlatformWindow* PlatformWindowManagerSDL::getFocusedWindow()
  349. {
  350. PlatformWindowSDL* window = mWindowListHead;
  351. while( window )
  352. {
  353. if( window->isFocused() )
  354. return window;
  355. window = window->mNextWindow;
  356. }
  357. return NULL;
  358. }
  359. void PlatformWindowManagerSDL::linkWindow( PlatformWindowSDL *w )
  360. {
  361. w->mNextWindow = mWindowListHead;
  362. mWindowListHead = w;
  363. }
  364. void PlatformWindowManagerSDL::unlinkWindow( PlatformWindowSDL *w )
  365. {
  366. PlatformWindowSDL **walk = &mWindowListHead;
  367. while(*walk)
  368. {
  369. if(*walk != w)
  370. {
  371. // Advance to next item in list.
  372. walk = &(*walk)->mNextWindow;
  373. continue;
  374. }
  375. // Got a match - unlink and return.
  376. *walk = (*walk)->mNextWindow;
  377. return;
  378. }
  379. }
  380. void PlatformWindowManagerSDL::_processCmdLineArgs( const S32 argc, const char **argv )
  381. {
  382. // TODO SDL
  383. }
  384. void PlatformWindowManagerSDL::lowerCurtain()
  385. {
  386. if(mCurtainWindow)
  387. return;
  388. // TODO SDL
  389. }
  390. void PlatformWindowManagerSDL::raiseCurtain()
  391. {
  392. if(!mCurtainWindow)
  393. return;
  394. // TODO SDL
  395. }
  396. void PlatformWindowManagerSDL::updateSDLTextInputState(KeyboardInputState state)
  397. {
  398. // Force update state. This will respond at the end of the event loop.
  399. mInputState = state;
  400. }
  401. void Platform::openFolder(const char* path )
  402. {
  403. AssertFatal(0, "Not Implemented");
  404. }
  405. void Platform::openFile(const char* path )
  406. {
  407. AssertFatal(0, "Not Implemented");
  408. }
  409. //------------------------------------------------------------------------------
  410. namespace GL
  411. {
  412. void gglPerformBinds();
  413. }
  414. void InitWindowingSystem()
  415. {
  416. }
  417. AFTER_MODULE_INIT(gfx)
  418. {
  419. #if !defined(TORQUE_DEDICATED)
  420. int res = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE);
  421. AssertFatal(res != -1, avar("SDL error:%s", SDL_GetError()));
  422. // By default, SDL enables text input. We disable it on initialization, and
  423. // we will enable it whenever the time is right.
  424. SDL_StopTextInput();
  425. #endif
  426. }