sdlWindow.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  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 "math/mMath.h"
  23. #include "gfx/gfxStructs.h"
  24. #include "windowManager/sdl/sdlWindow.h"
  25. #include "windowManager/sdl/sdlWindowMgr.h"
  26. #include "windowManager/sdl/sdlCursorController.h"
  27. #include "platformSDL/sdlInput.h"
  28. #include "platform/menus/popupMenu.h"
  29. #include "platform/platformInput.h"
  30. #include "gfx/gfxDevice.h"
  31. #ifdef TORQUE_OS_LINUX
  32. #define SDL_VIDEO_DRIVER_X11 // TODO SDL
  33. #endif
  34. #include "SDL.h"
  35. #include "SDL_syswm.h"
  36. #define SCREENSAVER_QUERY_DENY 0 // Disable screensaver
  37. #ifndef IDI_ICON1
  38. #define IDI_ICON1 107
  39. #endif
  40. namespace
  41. {
  42. U32 getTorqueModFromSDL(U16 mod)
  43. {
  44. U32 ret = 0;
  45. if (mod & KMOD_LSHIFT)
  46. {
  47. ret |= SI_LSHIFT;
  48. ret |= SI_SHIFT;
  49. }
  50. if (mod & KMOD_RSHIFT)
  51. {
  52. ret |= SI_RSHIFT;
  53. ret |= SI_SHIFT;
  54. }
  55. if (mod & KMOD_LCTRL)
  56. {
  57. ret |= SI_LCTRL;
  58. ret |= SI_CTRL;
  59. }
  60. if (mod & KMOD_RCTRL)
  61. {
  62. ret |= SI_RCTRL;
  63. ret |= SI_CTRL;
  64. }
  65. if (mod & KMOD_LALT)
  66. {
  67. ret |= SI_LALT;
  68. ret |= SI_ALT;
  69. }
  70. if (mod & KMOD_RALT)
  71. {
  72. ret |= SI_RALT;
  73. ret |= SI_ALT;
  74. }
  75. return ret;
  76. }
  77. }
  78. PlatformWindowSDL::PlatformWindowSDL():
  79. mOwningManager(NULL),
  80. mNextWindow(NULL),
  81. mWindowHandle(NULL),
  82. mOldParent(NULL),
  83. mDevice(NULL),
  84. mTarget(NULL),
  85. mPosition(0,0),
  86. mMouseLocked(false),
  87. mShouldLockMouse(false),
  88. mSuppressReset(false),
  89. mMenuHandle(NULL)
  90. {
  91. mCursorController = new PlatformCursorControllerSDL( this );
  92. mVideoMode.bitDepth = 32;
  93. mVideoMode.fullScreen = false;
  94. mVideoMode.refreshRate = 60;
  95. mVideoMode.resolution.set(800,600);
  96. }
  97. PlatformWindowSDL::~PlatformWindowSDL()
  98. {
  99. // delete our sdl handle..
  100. SDL_DestroyWindow(mWindowHandle);
  101. // unlink ourselves from the window list...
  102. AssertFatal(mOwningManager, "PlatformWindowSDL::~PlatformWindowSDL - orphan window, cannot unlink!");
  103. mOwningManager->unlinkWindow(this);
  104. }
  105. GFXDevice * PlatformWindowSDL::getGFXDevice()
  106. {
  107. return mDevice;
  108. }
  109. GFXWindowTarget * PlatformWindowSDL::getGFXTarget()
  110. {
  111. return mTarget;
  112. }
  113. const GFXVideoMode & PlatformWindowSDL::getVideoMode()
  114. {
  115. return mVideoMode;
  116. }
  117. void* PlatformWindowSDL::getSystemWindow(const WindowSystem system)
  118. {
  119. SDL_SysWMinfo info;
  120. SDL_VERSION(&info.version);
  121. SDL_GetWindowWMInfo(mWindowHandle,&info);
  122. #ifdef TORQUE_OS_WIN
  123. if( system == WindowSystem_Windows && info.subsystem == SDL_SYSWM_WINDOWS)
  124. return info.info.win.window;
  125. #endif
  126. #if defined(TORQUE_OS_LINUX)
  127. if( system == WindowSystem_X11 && info.subsystem == SDL_SYSWM_X11)
  128. return (void*)info.info.x11.window;
  129. #endif
  130. AssertFatal(0, "");
  131. return NULL;
  132. }
  133. void PlatformWindowSDL::setVideoMode( const GFXVideoMode &mode )
  134. {
  135. mVideoMode = mode;
  136. mSuppressReset = true;
  137. // Set our window to have the right style based on the mode
  138. if(mode.fullScreen && !Platform::getWebDeployment() && !mOffscreenRender)
  139. {
  140. setSize(mode.resolution);
  141. SDL_SetWindowFullscreen( mWindowHandle, SDL_WINDOW_FULLSCREEN);
  142. // When switching to Fullscreen, reset device after setting style
  143. if(mTarget.isValid())
  144. mTarget->resetMode();
  145. }
  146. else
  147. {
  148. // Reset device *first*, so that when we call setSize() and let it
  149. // access the monitor settings, it won't end up with our fullscreen
  150. // geometry that is just about to change.
  151. if(mTarget.isValid())
  152. mTarget->resetMode();
  153. if (!mOffscreenRender)
  154. {
  155. SDL_SetWindowFullscreen( mWindowHandle, 0);
  156. }
  157. setSize(mode.resolution);
  158. centerWindow();
  159. }
  160. mSuppressReset = false;
  161. }
  162. bool PlatformWindowSDL::clearFullscreen()
  163. {
  164. return true;
  165. }
  166. bool PlatformWindowSDL::isFullscreen()
  167. {
  168. U32 flags = SDL_GetWindowFlags( mWindowHandle );
  169. if( flags & SDL_WINDOW_FULLSCREEN || flags & SDL_WINDOW_FULLSCREEN_DESKTOP )
  170. return true;
  171. return false;
  172. }
  173. void PlatformWindowSDL::_setFullscreen(const bool fullscreen)
  174. {
  175. if( isFullscreen() )
  176. return;
  177. if(fullscreen && !mOffscreenRender)
  178. {
  179. Con::printf("PlatformWindowSDL::setFullscreen (full) enter");
  180. SDL_SetWindowFullscreen( mWindowHandle, SDL_WINDOW_FULLSCREEN);
  181. }
  182. else
  183. {
  184. Con::printf("PlatformWindowSDL::setFullscreen (windowed) enter");
  185. if (!mOffscreenRender)
  186. {
  187. SDL_SetWindowFullscreen( mWindowHandle, SDL_WINDOW_FULLSCREEN_DESKTOP);
  188. }
  189. setSize(mVideoMode.resolution);
  190. }
  191. Con::printf("PlatformWindowSDL::setFullscreen exit");
  192. }
  193. bool PlatformWindowSDL::setCaption( const char *cap )
  194. {
  195. SDL_SetWindowTitle(mWindowHandle, cap);
  196. return true;
  197. }
  198. const char * PlatformWindowSDL::getCaption()
  199. {
  200. return StringTable->insert( SDL_GetWindowTitle(mWindowHandle) );
  201. }
  202. void PlatformWindowSDL::setFocus()
  203. {
  204. SDL_SetWindowGrab( mWindowHandle, SDL_TRUE );
  205. }
  206. void PlatformWindowSDL::setClientExtent( const Point2I newExtent )
  207. {
  208. Point2I oldExtent = getClientExtent();
  209. if (oldExtent == newExtent)
  210. return;
  211. SDL_SetWindowSize(mWindowHandle, newExtent.x, newExtent.y);
  212. }
  213. const Point2I PlatformWindowSDL::getClientExtent()
  214. {
  215. // Fetch Client Rect from Windows
  216. Point2I size;
  217. SDL_GetWindowSize(mWindowHandle, &size.x, &size.y);
  218. return size;
  219. }
  220. void PlatformWindowSDL::setBounds( const RectI &newBounds )
  221. {
  222. // TODO SDL
  223. }
  224. const RectI PlatformWindowSDL::getBounds() const
  225. {
  226. // TODO SDL
  227. return RectI(0, 0, 0, 0);
  228. }
  229. void PlatformWindowSDL::setPosition( const Point2I newPosition )
  230. {
  231. SDL_SetWindowPosition( mWindowHandle, newPosition.x, newPosition.y );
  232. }
  233. const Point2I PlatformWindowSDL::getPosition()
  234. {
  235. Point2I position;
  236. SDL_GetWindowPosition( mWindowHandle, &position.x, &position.y );
  237. // Return position
  238. return position;
  239. }
  240. Point2I PlatformWindowSDL::clientToScreen( const Point2I& pos )
  241. {
  242. Point2I position;
  243. SDL_GetWindowPosition( mWindowHandle, &position.x, &position.y );
  244. return pos + position;
  245. }
  246. Point2I PlatformWindowSDL::screenToClient( const Point2I& pos )
  247. {
  248. Point2I position;
  249. SDL_GetWindowPosition( mWindowHandle, &position.x, &position.y );
  250. return pos - position;
  251. }
  252. void PlatformWindowSDL::centerWindow()
  253. {
  254. int sizeX, sizeY;
  255. SDL_GetWindowSize(mWindowHandle, &sizeX, &sizeY);
  256. SDL_DisplayMode mode;
  257. SDL_GetDesktopDisplayMode(0, &mode);
  258. U32 posX = (mode.w/2) - (sizeX/2);
  259. U32 posY = (mode.h/2) - (sizeY/2);
  260. SDL_SetWindowPosition( mWindowHandle, posX, posY);
  261. }
  262. bool PlatformWindowSDL::setSize( const Point2I &newSize )
  263. {
  264. SDL_SetWindowSize(mWindowHandle, newSize.x, newSize.y);
  265. // Let GFX get an update about the new resolution
  266. if (mTarget.isValid())
  267. mTarget->resetMode();
  268. return true;
  269. }
  270. bool PlatformWindowSDL::isOpen()
  271. {
  272. return mWindowHandle;
  273. }
  274. bool PlatformWindowSDL::isVisible()
  275. {
  276. // Is the window open and visible, ie. not minimized?
  277. if(!mWindowHandle)
  278. return false;
  279. if (mOffscreenRender)
  280. return true;
  281. U32 flags = SDL_GetWindowFlags( mWindowHandle );
  282. if( flags & SDL_WINDOW_SHOWN)
  283. return true;
  284. return false;
  285. }
  286. bool PlatformWindowSDL::isFocused()
  287. {
  288. if (mOffscreenRender)
  289. return true;
  290. U32 flags = SDL_GetWindowFlags( mWindowHandle );
  291. if( flags & SDL_WINDOW_INPUT_FOCUS || flags & SDL_WINDOW_INPUT_GRABBED || flags & SDL_WINDOW_MOUSE_FOCUS )
  292. return true;
  293. return false;
  294. }
  295. bool PlatformWindowSDL::isMinimized()
  296. {
  297. if (mOffscreenRender)
  298. return false;
  299. U32 flags = SDL_GetWindowFlags( mWindowHandle );
  300. if( flags & SDL_WINDOW_MINIMIZED)
  301. return true;
  302. return false;
  303. }
  304. bool PlatformWindowSDL::isMaximized()
  305. {
  306. if (mOffscreenRender)
  307. return true;
  308. U32 flags = SDL_GetWindowFlags( mWindowHandle );
  309. if( flags & SDL_WINDOW_MAXIMIZED)
  310. return true;
  311. return false;
  312. }
  313. WindowId PlatformWindowSDL::getWindowId()
  314. {
  315. return mWindowId;
  316. }
  317. void PlatformWindowSDL::minimize()
  318. {
  319. if (mOffscreenRender)
  320. return;
  321. SDL_MinimizeWindow( mWindowHandle );
  322. }
  323. void PlatformWindowSDL::maximize()
  324. {
  325. if (mOffscreenRender)
  326. return;
  327. SDL_MaximizeWindow( mWindowHandle );
  328. }
  329. void PlatformWindowSDL::restore()
  330. {
  331. if (mOffscreenRender)
  332. return;
  333. SDL_RestoreWindow( mWindowHandle );
  334. }
  335. void PlatformWindowSDL::hide()
  336. {
  337. if (mOffscreenRender)
  338. return;
  339. SDL_HideWindow( mWindowHandle );
  340. }
  341. void PlatformWindowSDL::show()
  342. {
  343. if (mOffscreenRender)
  344. return;
  345. SDL_ShowWindow( mWindowHandle );
  346. }
  347. void PlatformWindowSDL::close()
  348. {
  349. delete this;
  350. }
  351. void PlatformWindowSDL::defaultRender()
  352. {
  353. // TODO SDL
  354. }
  355. void PlatformWindowSDL::_triggerMouseLocationNotify(const SDL_Event& evt)
  356. {
  357. U32 mods = getTorqueModFromSDL(SDL_GetModState());
  358. if(!mMouseLocked)
  359. mouseEvent.trigger(getWindowId(), mods, evt.motion.x, evt.motion.y, false);
  360. else
  361. mouseEvent.trigger(getWindowId(), mods, evt.motion.xrel, evt.motion.yrel, true);
  362. }
  363. void PlatformWindowSDL::_triggerMouseWheelNotify(const SDL_Event& evt)
  364. {
  365. U32 mods = getTorqueModFromSDL(SDL_GetModState());
  366. S32 wheelDelta = Con::getIntVariable("$pref::Input::MouseWheelSpeed", 120);
  367. wheelEvent.trigger(getWindowId(), mods, evt.wheel.x * wheelDelta, evt.wheel.y * wheelDelta);
  368. }
  369. void PlatformWindowSDL::_triggerMouseButtonNotify(const SDL_Event& event)
  370. {
  371. S32 action = (event.type == SDL_MOUSEBUTTONDOWN) ? SI_MAKE : SI_BREAK;
  372. S32 button = -1;
  373. switch (event.button.button)
  374. {
  375. case SDL_BUTTON_LEFT:
  376. button = 0;
  377. break;
  378. case SDL_BUTTON_RIGHT:
  379. button = 1;
  380. break;
  381. case SDL_BUTTON_MIDDLE:
  382. button = 2;
  383. break;
  384. default:
  385. return;
  386. }
  387. U32 mod = getTorqueModFromSDL( SDL_GetModState() );
  388. buttonEvent.trigger(getWindowId(), mod, action, button );
  389. }
  390. void PlatformWindowSDL::_triggerKeyNotify(const SDL_Event& evt)
  391. {
  392. U32 inputAction = IA_MAKE;
  393. SDL_Keysym tKey = evt.key.keysym;
  394. if(evt.type == SDL_KEYUP)
  395. {
  396. inputAction = IA_BREAK;
  397. }
  398. if(evt.key.repeat)
  399. {
  400. inputAction = IA_REPEAT;
  401. }
  402. U32 torqueModifiers = getTorqueModFromSDL(evt.key.keysym.mod);
  403. U32 torqueKey = KeyMapSDL::getTorqueScanCodeFromSDL(tKey.scancode);
  404. if(tKey.scancode)
  405. {
  406. keyEvent.trigger(getWindowId(), torqueModifiers, inputAction, torqueKey);
  407. //Con::printf("Key %d : %d", tKey.sym, inputAction);
  408. if (inputAction == IA_MAKE && SDL_IsTextInputActive())
  409. {
  410. // We have to check if we already have a first responder active.
  411. // We don't want to type the character if it actually creates another responder!
  412. if (mWindowInputGenerator->lastKeyWasGlobalActionMap())
  413. {
  414. // Turn off Text input, and the next frame turn it back on. This tells SDL
  415. // to not generate a text event for this global action map key.
  416. SDL_StopTextInput();
  417. mOwningManager->updateSDLTextInputState(PlatformWindowManagerSDL::KeyboardInputState::TEXT_INPUT);
  418. }
  419. }
  420. }
  421. }
  422. void PlatformWindowSDL::_triggerTextNotify(const SDL_Event& evt)
  423. {
  424. U32 mod = getTorqueModFromSDL( SDL_GetModState() );
  425. if( !evt.text.text[1] ) // get a char
  426. {
  427. U16 wchar = evt.text.text[0];
  428. charEvent.trigger(getWindowId(), mod, wchar );
  429. //Con::printf("Char: %c", wchar);
  430. return;
  431. }
  432. else // get a wchar string
  433. {
  434. const U32 len = strlen(evt.text.text);
  435. U16 wchar[16] = {};
  436. dMemcpy(wchar, evt.text.text, sizeof(char)*len);
  437. for(int i = 0; i < 16; ++i)
  438. {
  439. if( !wchar[i] )
  440. return;
  441. charEvent.trigger(getWindowId(), mod, wchar[i] );
  442. }
  443. }
  444. }
  445. void PlatformWindowSDL::_processSDLEvent(SDL_Event &evt)
  446. {
  447. switch(evt.type)
  448. {
  449. case SDL_KEYDOWN:
  450. case SDL_KEYUP:
  451. {
  452. _triggerKeyNotify(evt);
  453. break;
  454. }
  455. case SDL_TEXTINPUT:
  456. {
  457. _triggerTextNotify(evt);
  458. break;
  459. }
  460. case SDL_MOUSEWHEEL:
  461. {
  462. _triggerMouseWheelNotify(evt);
  463. break;
  464. }
  465. case SDL_MOUSEMOTION:
  466. {
  467. _triggerMouseLocationNotify(evt);
  468. break;
  469. }
  470. case SDL_MOUSEBUTTONDOWN:
  471. case SDL_MOUSEBUTTONUP:
  472. {
  473. appEvent.trigger(getWindowId(), GainFocus);
  474. _triggerMouseButtonNotify(evt);
  475. break;
  476. }
  477. case SDL_WINDOWEVENT:
  478. {
  479. switch( evt.window.event )
  480. {
  481. case SDL_WINDOWEVENT_MAXIMIZED:
  482. case SDL_WINDOWEVENT_RESIZED:
  483. {
  484. int width, height;
  485. SDL_GetWindowSize( mWindowHandle, &width, &height );
  486. mVideoMode.resolution.set( width, height );
  487. getGFXTarget()->resetMode();
  488. break;
  489. }
  490. default:
  491. break;
  492. }
  493. }
  494. }
  495. }
  496. //-----------------------------------------------------------------------------
  497. // Mouse Locking
  498. //-----------------------------------------------------------------------------
  499. void PlatformWindowSDL::setMouseLocked( bool enable )
  500. {
  501. if (mOffscreenRender)
  502. return;
  503. mMouseLocked = enable;
  504. SDL_SetWindowGrab( mWindowHandle, SDL_bool(enable) );
  505. SDL_SetRelativeMouseMode( SDL_bool(enable) );
  506. }
  507. const UTF16 *PlatformWindowSDL::getWindowClassName()
  508. {
  509. // TODO SDL
  510. static String str("WindowClassName");
  511. return str.utf16();
  512. }
  513. const UTF16 *PlatformWindowSDL::getCurtainWindowClassName()
  514. {
  515. // TODO SDL
  516. static String str("CurtainWindowClassName");
  517. return str.utf16();
  518. }
  519. void PlatformWindowSDL::setKeyboardTranslation(const bool enabled)
  520. {
  521. mEnableKeyboardTranslation = enabled;
  522. // Flag for update. Let SDL know what kind of input state we are changing to.
  523. if (enabled)
  524. mOwningManager->updateSDLTextInputState(PlatformWindowManagerSDL::KeyboardInputState::TEXT_INPUT);
  525. else
  526. mOwningManager->updateSDLTextInputState(PlatformWindowManagerSDL::KeyboardInputState::RAW_INPUT);
  527. }