sdlWindow.cpp
Engine/source/windowManager/sdl/sdlWindow.cpp
Public Defines
define
IDI_ICON1() 107
define
Detailed Description
Public Defines
IDI_ICON1() 107
SCREENSAVER_QUERY_DENY() 0
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "math/mMath.h" 25#include "gfx/gfxStructs.h" 26 27#include "windowManager/sdl/sdlWindow.h" 28#include "windowManager/sdl/sdlWindowMgr.h" 29#include "windowManager/sdl/sdlCursorController.h" 30#include "platformSDL/sdlInput.h" 31#include "platform/platformInput.h" 32 33#include "gfx/gfxDevice.h" 34 35#ifdef TORQUE_OS_LINUX 36#define SDL_VIDEO_DRIVER_X11 // TODO SDL 37#endif 38 39#include "SDL.h" 40#include "SDL_syswm.h" 41 42#define SCREENSAVER_QUERY_DENY 0 // Disable screensaver 43 44#ifndef IDI_ICON1 45#define IDI_ICON1 107 46#endif 47 48namespace 49{ 50 U32 getTorqueModFromSDL(U16 mod) 51 { 52 U32 ret = 0; 53 54 if (mod & KMOD_LSHIFT) 55 { 56 ret |= SI_LSHIFT; 57 ret |= SI_SHIFT; 58 } 59 60 if (mod & KMOD_RSHIFT) 61 { 62 ret |= SI_RSHIFT; 63 ret |= SI_SHIFT; 64 } 65 66 if (mod & KMOD_LCTRL) 67 { 68 ret |= SI_LCTRL; 69 ret |= SI_CTRL; 70 } 71 72 if (mod & KMOD_RCTRL) 73 { 74 ret |= SI_RCTRL; 75 ret |= SI_CTRL; 76 } 77 78 if (mod & KMOD_LALT) 79 { 80 ret |= SI_LALT; 81 ret |= SI_ALT; 82 } 83 84 if (mod & KMOD_RALT) 85 { 86 ret |= SI_RALT; 87 ret |= SI_ALT; 88 } 89 90 return ret; 91 } 92} 93 94PlatformWindowSDL::PlatformWindowSDL(): 95mOwningManager(NULL), 96mNextWindow(NULL), 97mWindowHandle(NULL), 98mOldParent(NULL), 99mDevice(NULL), 100mTarget(NULL), 101mPosition(0,0), 102mMouseLocked(false), 103mShouldLockMouse(false), 104mSuppressReset(false), 105mMenuHandle(NULL), 106mClosing(false) 107{ 108 mCursorController = new PlatformCursorControllerSDL( this ); 109 110 mVideoMode.bitDepth = 32; 111 mVideoMode.fullScreen = false; 112 mVideoMode.refreshRate = 60; 113 mVideoMode.resolution.set(800,600); 114} 115 116PlatformWindowSDL::~PlatformWindowSDL() 117{ 118 // delete our sdl handle.. 119 SDL_DestroyWindow(mWindowHandle); 120 121 // unlink ourselves from the window list... 122 AssertFatal(mOwningManager, "PlatformWindowSDL::~PlatformWindowSDL - orphan window, cannot unlink!"); 123 mOwningManager->unlinkWindow(this); 124} 125 126GFXDevice * PlatformWindowSDL::getGFXDevice() 127{ 128 return mDevice; 129} 130 131GFXWindowTarget * PlatformWindowSDL::getGFXTarget() 132{ 133 return mTarget; 134} 135 136const GFXVideoMode & PlatformWindowSDL::getVideoMode() 137{ 138 return mVideoMode; 139} 140 141void* PlatformWindowSDL::getSystemWindow(const WindowSystem system) 142{ 143 SDL_SysWMinfo info; 144 SDL_VERSION(&info.version); 145 SDL_GetWindowWMInfo(mWindowHandle,&info); 146 147#ifdef TORQUE_OS_WIN 148 if( system == WindowSystem_Windows && info.subsystem == SDL_SYSWM_WINDOWS) 149 return info.info.win.window; 150#endif 151 152#if defined(TORQUE_OS_LINUX) 153 if( system == WindowSystem_X11 && info.subsystem == SDL_SYSWM_X11) 154 return (void*)info.info.x11.window; 155#endif 156 157 AssertFatal(0, ""); 158 return NULL; 159} 160 161void PlatformWindowSDL::_setVideoMode( const GFXVideoMode &mode ) 162{ 163 mVideoMode = mode; 164 mSuppressReset = true; 165 S32 newDisplay = Con::getIntVariable("pref::Video::deviceId", 0); 166 167 // Set our window to have the right style based on the mode 168 if(mode.fullScreen && !Platform::getWebDeployment() && !mOffscreenRender) 169 { 170 SDL_Rect rect_sdl; 171 // Move the window onto the correct monitor before setting fullscreen 172 if (0 == SDL_GetDisplayBounds(newDisplay, &rect_sdl)) 173 { 174 SDL_SetWindowPosition(mWindowHandle, rect_sdl.x, rect_sdl.y); 175 } 176 177 setSize(mode.resolution); 178 179 SDL_SetWindowFullscreen( mWindowHandle, SDL_WINDOW_FULLSCREEN); 180 181 // When switching to Fullscreen, reset device after setting style 182 if(mTarget.isValid()) 183 mTarget->resetMode(); 184 } 185 else 186 { 187 // Reset device *first*, so that when we call setSize() and let it 188 // access the monitor settings, it won't end up with our fullscreen 189 // geometry that is just about to change. 190 191 if(mTarget.isValid()) 192 mTarget->resetMode(); 193 194 if (!mOffscreenRender) 195 { 196 SDL_SetWindowFullscreen( mWindowHandle, 0); 197 } 198 199 // Restore the window to it's original size/position before applying changes 200 SDL_RestoreWindow(mWindowHandle); 201 202 // pref::Video::deviceMode values 0-windowed, 1-borderless, 2-fullscreen 203 bool hasBorder = (0 == Con::getIntVariable("pref::Video::deviceMode", 0)); 204 SDL_SetWindowBordered(mWindowHandle, hasBorder ? SDL_TRUE : SDL_FALSE); 205 setSize(mode.resolution); 206 SDL_SetWindowPosition(mWindowHandle, SDL_WINDOWPOS_CENTERED_DISPLAY(newDisplay), SDL_WINDOWPOS_CENTERED_DISPLAY(newDisplay)); 207 if (hasBorder && Con::getBoolVariable("pref::Video::isMaximized", false)) 208 SDL_MaximizeWindow(mWindowHandle); 209 } 210 211 getScreenResChangeSignal().trigger(this, true); 212 mSuppressReset = false; 213} 214 215bool PlatformWindowSDL::clearFullscreen() 216{ 217 return true; 218} 219 220bool PlatformWindowSDL::isFullscreen() 221{ 222 U32 flags = SDL_GetWindowFlags( mWindowHandle ); 223 if( flags & SDL_WINDOW_FULLSCREEN || flags & SDL_WINDOW_FULLSCREEN_DESKTOP ) 224 return true; 225 226 return false; 227} 228 229void PlatformWindowSDL::_setFullscreen(const bool fullscreen) 230{ 231 if( isFullscreen() ) 232 return; 233 234 if(fullscreen && !mOffscreenRender) 235 { 236 Con::printf("PlatformWindowSDL::setFullscreen (full) enter"); 237 SDL_SetWindowFullscreen( mWindowHandle, SDL_WINDOW_FULLSCREEN); 238 } 239 else 240 { 241 Con::printf("PlatformWindowSDL::setFullscreen (windowed) enter"); 242 if (!mOffscreenRender) 243 { 244 SDL_SetWindowFullscreen( mWindowHandle, SDL_WINDOW_FULLSCREEN_DESKTOP); 245 } 246 247 setSize(mVideoMode.resolution); 248 249 } 250 Con::printf("PlatformWindowSDL::setFullscreen exit"); 251} 252 253bool PlatformWindowSDL::setCaption( const char *cap ) 254{ 255 SDL_SetWindowTitle(mWindowHandle, cap); 256 return true; 257} 258 259const char * PlatformWindowSDL::getCaption() 260{ 261 return StringTable->insert( SDL_GetWindowTitle(mWindowHandle) ); 262} 263 264void PlatformWindowSDL::setFocus() 265{ 266 SDL_RaiseWindow(mWindowHandle); 267} 268 269void PlatformWindowSDL::setClientExtent( const Point2I newExtent ) 270{ 271 Point2I oldExtent = getClientExtent(); 272 if (oldExtent == newExtent) 273 return; 274 275 SDL_SetWindowSize(mWindowHandle, newExtent.x, newExtent.y); 276} 277 278const Point2I PlatformWindowSDL::getClientExtent() 279{ 280 // Fetch Client Rect from Windows 281 Point2I size; 282 SDL_GetWindowSize(mWindowHandle, &size.x, &size.y); 283 284 return size; 285} 286 287void PlatformWindowSDL::setBounds( const RectI &newBounds ) 288{ 289 // TODO SDL 290} 291 292const RectI PlatformWindowSDL::getBounds() const 293{ 294 // TODO SDL 295 return RectI(0, 0, 0, 0); 296} 297 298void PlatformWindowSDL::setPosition( const Point2I newPosition ) 299{ 300 SDL_SetWindowPosition( mWindowHandle, newPosition.x, newPosition.y ); 301} 302 303const Point2I PlatformWindowSDL::getPosition() 304{ 305 Point2I position; 306 SDL_GetWindowPosition( mWindowHandle, &position.x, &position.y ); 307 308 // Return position 309 return position; 310} 311 312Point2I PlatformWindowSDL::clientToScreen( const Point2I& pos ) 313{ 314 Point2I position; 315 SDL_GetWindowPosition( mWindowHandle, &position.x, &position.y ); 316 return pos + position; 317} 318 319Point2I PlatformWindowSDL::screenToClient( const Point2I& pos ) 320{ 321 Point2I position; 322 SDL_GetWindowPosition( mWindowHandle, &position.x, &position.y ); 323 return pos - position; 324} 325 326void PlatformWindowSDL::centerWindow() 327{ 328 int sizeX, sizeY; 329 SDL_GetWindowSize(mWindowHandle, &sizeX, &sizeY); 330 331 SDL_DisplayMode mode; 332 SDL_GetDesktopDisplayMode(0, &mode); 333 334 U32 posX = (mode.w/2) - (sizeX/2); 335 U32 posY = (mode.h/2) - (sizeY/2); 336 337 SDL_SetWindowPosition( mWindowHandle, posX, posY); 338} 339 340bool PlatformWindowSDL::setSize( const Point2I &newSize ) 341{ 342 SDL_SetWindowSize(mWindowHandle, newSize.x, newSize.y); 343 return true; 344} 345 346bool PlatformWindowSDL::isOpen() 347{ 348 return mWindowHandle; 349} 350 351bool PlatformWindowSDL::isVisible() 352{ 353 // Is the window open and visible, ie. not minimized? 354 if(!mWindowHandle) 355 return false; 356 357 if (mOffscreenRender) 358 return true; 359 360 U32 flags = SDL_GetWindowFlags( mWindowHandle ); 361 if( flags & SDL_WINDOW_SHOWN) 362 return true; 363 364 return false; 365} 366 367bool PlatformWindowSDL::isFocused() 368{ 369 if (mOffscreenRender) 370 return true; 371 372 U32 flags = SDL_GetWindowFlags( mWindowHandle ); 373 if( flags & SDL_WINDOW_INPUT_FOCUS || flags & SDL_WINDOW_INPUT_GRABBED || flags & SDL_WINDOW_MOUSE_FOCUS ) 374 return true; 375 376 return false; 377} 378 379bool PlatformWindowSDL::isMinimized() 380{ 381 if (mOffscreenRender) 382 return false; 383 384 U32 flags = SDL_GetWindowFlags( mWindowHandle ); 385 if( flags & SDL_WINDOW_MINIMIZED) 386 return true; 387 388 return false; 389} 390 391bool PlatformWindowSDL::isMaximized() 392{ 393 if (mOffscreenRender) 394 return true; 395 396 U32 flags = SDL_GetWindowFlags( mWindowHandle ); 397 if( flags & SDL_WINDOW_MAXIMIZED) 398 return true; 399 400 return false; 401} 402 403WindowId PlatformWindowSDL::getWindowId() 404{ 405 return mWindowId; 406} 407 408void PlatformWindowSDL::minimize() 409{ 410 if (mOffscreenRender) 411 return; 412 413 SDL_MinimizeWindow( mWindowHandle ); 414} 415 416void PlatformWindowSDL::maximize() 417{ 418 if (mOffscreenRender) 419 return; 420 421 SDL_MaximizeWindow( mWindowHandle ); 422} 423 424void PlatformWindowSDL::restore() 425{ 426 if (mOffscreenRender) 427 return; 428 429 SDL_RestoreWindow( mWindowHandle ); 430} 431 432void PlatformWindowSDL::hide() 433{ 434 if (mOffscreenRender) 435 return; 436 437 SDL_HideWindow( mWindowHandle ); 438} 439 440void PlatformWindowSDL::show() 441{ 442 if (mOffscreenRender) 443 return; 444 445 SDL_ShowWindow( mWindowHandle ); 446} 447 448void PlatformWindowSDL::close() 449{ 450 delete this; 451} 452 453void PlatformWindowSDL::defaultRender() 454{ 455 // TODO SDL 456} 457 458void PlatformWindowSDL::_triggerMouseLocationNotify(const SDL_Event& evt) 459{ 460 U32 mods = getTorqueModFromSDL(SDL_GetModState()); 461 462 if(!mMouseLocked) 463 mouseEvent.trigger(getWindowId(), mods, evt.motion.x, evt.motion.y, false); 464 else 465 mouseEvent.trigger(getWindowId(), mods, evt.motion.xrel, evt.motion.yrel, true); 466} 467 468void PlatformWindowSDL::_triggerMouseWheelNotify(const SDL_Event& evt) 469{ 470 U32 mods = getTorqueModFromSDL(SDL_GetModState()); 471 S32 wheelDelta = Con::getIntVariable("$pref::Input::MouseWheelSpeed", 120); 472 wheelEvent.trigger(getWindowId(), mods, evt.wheel.x * wheelDelta, evt.wheel.y * wheelDelta); 473} 474 475void PlatformWindowSDL::_triggerMouseButtonNotify(const SDL_Event& event) 476{ 477 S32 action = (event.type == SDL_MOUSEBUTTONDOWN) ? SI_MAKE : SI_BREAK; 478 S32 button = -1; 479 480 switch (event.button.button) 481 { 482 case SDL_BUTTON_LEFT: 483 button = 0; 484 break; 485 case SDL_BUTTON_RIGHT: 486 button = 1; 487 break; 488 case SDL_BUTTON_MIDDLE: 489 button = 2; 490 break; 491 case SDL_BUTTON_X1: 492 button = 3; 493 break; 494 case SDL_BUTTON_X2: 495 button = 4; 496 break; 497 default: 498 return; 499 } 500 501 U32 mod = getTorqueModFromSDL( SDL_GetModState() ); 502 buttonEvent.trigger(getWindowId(), mod, action, button ); 503} 504 505void PlatformWindowSDL::_triggerKeyNotify(const SDL_Event& evt) 506{ 507 U32 inputAction = IA_MAKE; 508 SDL_Keysym tKey = evt.key.keysym; 509 510 if(evt.type == SDL_KEYUP) 511 { 512 inputAction = IA_BREAK; 513 } 514 515 if(evt.key.repeat) 516 { 517 inputAction = IA_REPEAT; 518 } 519 520 U32 torqueModifiers = getTorqueModFromSDL(evt.key.keysym.mod); 521 U32 torqueKey = KeyMapSDL::getTorqueScanCodeFromSDL(tKey.scancode); 522 if(tKey.scancode) 523 { 524 keyEvent.trigger(getWindowId(), torqueModifiers, inputAction, torqueKey); 525 //Con::printf("Key %d : %d", tKey.sym, inputAction); 526 527 if (inputAction == IA_MAKE && SDL_IsTextInputActive()) 528 { 529 // We have to check if we already have a first responder active. 530 // We don't want to type the character if it actually creates another responder! 531 if (mWindowInputGenerator->lastKeyWasGlobalActionMap()) 532 { 533 // Turn off Text input, and the next frame turn it back on. This tells SDL 534 // to not generate a text event for this global action map key. 535 SDL_StopTextInput(); 536 mOwningManager->updateSDLTextInputState(PlatformWindowManagerSDL::KeyboardInputState::TEXT_INPUT); 537 } 538 } 539 } 540} 541 542void PlatformWindowSDL::_triggerTextNotify(const SDL_Event& evt) 543{ 544 U32 mod = getTorqueModFromSDL( SDL_GetModState() ); 545 546 if( !evt.text.text[1] ) // get a char 547 { 548 U16 wchar = evt.text.text[0]; 549 charEvent.trigger(getWindowId(), mod, wchar ); 550 //Con::printf("Char: %c", wchar); 551 return; 552 } 553 else // get a wchar string 554 { 555 const U32 len = strlen(evt.text.text); 556 U16 wchar[16] = {}; 557 dMemcpy(wchar, evt.text.text, sizeof(char)*len); 558 559 for(int i = 0; i < 16; ++i) 560 { 561 if( !wchar[i] ) 562 return; 563 564 charEvent.trigger(getWindowId(), mod, wchar[i] ); 565 } 566 } 567} 568 569void PlatformWindowSDL::_updateMonitorFromMove(const SDL_Event& evt) 570{ 571 SDL_Rect sdlRect; 572 S32 monitorCount = SDL_GetNumVideoDisplays(); 573 for (S32 index = 0; index < monitorCount; ++index) 574 { 575 if (0 == SDL_GetDisplayBounds(index, &sdlRect)) 576 { 577 if ((evt.window.data1 >= sdlRect.x) && (evt.window.data1 < (sdlRect.x + sdlRect.w)) && 578 (evt.window.data2 >= sdlRect.y) && (evt.window.data2 < (sdlRect.y + sdlRect.h))) 579 { 580 Con::setIntVariable("pref::Video::deviceId", index); 581 return; 582 } 583 } 584 } 585} 586 587void PlatformWindowSDL::_processSDLEvent(SDL_Event &evt) 588{ 589 switch(evt.type) 590 { 591 case SDL_KEYDOWN: 592 case SDL_KEYUP: 593 { 594 _triggerKeyNotify(evt); 595 break; 596 } 597 598 case SDL_TEXTINPUT: 599 { 600 _triggerTextNotify(evt); 601 break; 602 } 603 604 case SDL_MOUSEWHEEL: 605 { 606 _triggerMouseWheelNotify(evt); 607 break; 608 } 609 610 case SDL_MOUSEMOTION: 611 { 612 _triggerMouseLocationNotify(evt); 613 break; 614 } 615 case SDL_MOUSEBUTTONDOWN: 616 case SDL_MOUSEBUTTONUP: 617 { 618 _triggerMouseButtonNotify(evt); 619 break; 620 } 621 622 case SDL_WINDOWEVENT: 623 { 624 if (!mClosing) 625 { 626 switch (evt.window.event) 627 { 628 case SDL_WINDOWEVENT_FOCUS_GAINED: 629 appEvent.trigger(getWindowId(), GainFocus); 630 break; 631 case SDL_WINDOWEVENT_FOCUS_LOST: 632 appEvent.trigger(getWindowId(), LoseFocus); 633 break; 634 case SDL_WINDOWEVENT_MOVED: 635 { 636 _updateMonitorFromMove(evt); 637 break; 638 } 639 case SDL_WINDOWEVENT_RESIZED: 640 { 641 int width, height; 642 SDL_GetWindowSize(mWindowHandle, &width, &height); 643 mVideoMode.resolution.set(width, height); 644 getGFXTarget()->resetMode(); 645 resizeEvent.trigger(getWindowId(), width, height); 646 getScreenResChangeSignal().trigger(this, true); 647 break; 648 } 649 case SDL_WINDOWEVENT_CLOSE: 650 { 651 appEvent.trigger(getWindowId(), WindowClose); 652 mClosing = true; 653 } 654 case SDL_WINDOWEVENT_MINIMIZED: 655 break; 656 case SDL_WINDOWEVENT_MAXIMIZED: 657 Con::setBoolVariable("pref::Video::isMaximized", true); 658 break; 659 case SDL_WINDOWEVENT_RESTORED: 660 Con::setBoolVariable("pref::Video::isMaximized", false); 661 break; 662 663 default: 664 break; 665 } 666 } 667 } 668 } 669 670} 671 672//----------------------------------------------------------------------------- 673// Mouse Locking 674//----------------------------------------------------------------------------- 675 676void PlatformWindowSDL::setMouseLocked( bool enable ) 677{ 678 if (mOffscreenRender) 679 return; 680 681 mMouseLocked = enable; 682 683 SDL_SetWindowGrab( mWindowHandle, SDL_bool(enable) ); 684 SDL_SetRelativeMouseMode( SDL_bool(enable) ); 685} 686 687const UTF16 *PlatformWindowSDL::getWindowClassName() 688{ 689 // TODO SDL 690 static String str("WindowClassName"); 691 return str.utf16(); 692} 693 694const UTF16 *PlatformWindowSDL::getCurtainWindowClassName() 695{ 696 // TODO SDL 697 static String str("CurtainWindowClassName"); 698 return str.utf16(); 699} 700 701void PlatformWindowSDL::setKeyboardTranslation(const bool enabled) 702{ 703 mEnableKeyboardTranslation = enabled; 704 705 // Flag for update. Let SDL know what kind of input state we are changing to. 706 if (enabled) 707 mOwningManager->updateSDLTextInputState(PlatformWindowManagerSDL::KeyboardInputState::TEXT_INPUT); 708 else 709 mOwningManager->updateSDLTextInputState(PlatformWindowManagerSDL::KeyboardInputState::RAW_INPUT); 710} 711