Torque3D/Engine/source/windowManager/sdl/sdlWindow.cpp

646 lines
15 KiB
C++

//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "math/mMath.h"
#include "gfx/gfxStructs.h"
#include "windowManager/sdl/sdlWindow.h"
#include "windowManager/sdl/sdlWindowMgr.h"
#include "windowManager/sdl/sdlCursorController.h"
#include "platformSDL/sdlInput.h"
#include "platform/platformInput.h"
#include "gfx/gfxDevice.h"
#ifdef TORQUE_OS_LINUX
#define SDL_VIDEO_DRIVER_X11 // TODO SDL
#endif
#include "SDL.h"
#include "SDL_syswm.h"
#define SCREENSAVER_QUERY_DENY 0 // Disable screensaver
#ifndef IDI_ICON1
#define IDI_ICON1 107
#endif
namespace
{
U32 getTorqueModFromSDL(U16 mod)
{
U32 ret = 0;
if (mod & KMOD_LSHIFT)
{
ret |= SI_LSHIFT;
ret |= SI_SHIFT;
}
if (mod & KMOD_RSHIFT)
{
ret |= SI_RSHIFT;
ret |= SI_SHIFT;
}
if (mod & KMOD_LCTRL)
{
ret |= SI_LCTRL;
ret |= SI_CTRL;
}
if (mod & KMOD_RCTRL)
{
ret |= SI_RCTRL;
ret |= SI_CTRL;
}
if (mod & KMOD_LALT)
{
ret |= SI_LALT;
ret |= SI_ALT;
}
if (mod & KMOD_RALT)
{
ret |= SI_RALT;
ret |= SI_ALT;
}
return ret;
}
}
PlatformWindowSDL::PlatformWindowSDL():
mOwningManager(NULL),
mNextWindow(NULL),
mWindowHandle(NULL),
mOldParent(NULL),
mDevice(NULL),
mTarget(NULL),
mPosition(0,0),
mMouseLocked(false),
mShouldLockMouse(false),
mSuppressReset(false),
mMenuHandle(NULL)
{
mCursorController = new PlatformCursorControllerSDL( this );
mVideoMode.bitDepth = 32;
mVideoMode.fullScreen = false;
mVideoMode.refreshRate = 60;
mVideoMode.resolution.set(800,600);
}
PlatformWindowSDL::~PlatformWindowSDL()
{
// delete our sdl handle..
SDL_DestroyWindow(mWindowHandle);
// unlink ourselves from the window list...
AssertFatal(mOwningManager, "PlatformWindowSDL::~PlatformWindowSDL - orphan window, cannot unlink!");
mOwningManager->unlinkWindow(this);
}
GFXDevice * PlatformWindowSDL::getGFXDevice()
{
return mDevice;
}
GFXWindowTarget * PlatformWindowSDL::getGFXTarget()
{
return mTarget;
}
const GFXVideoMode & PlatformWindowSDL::getVideoMode()
{
return mVideoMode;
}
void* PlatformWindowSDL::getSystemWindow(const WindowSystem system)
{
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
SDL_GetWindowWMInfo(mWindowHandle,&info);
#ifdef TORQUE_OS_WIN
if( system == WindowSystem_Windows && info.subsystem == SDL_SYSWM_WINDOWS)
return info.info.win.window;
#endif
#if defined(TORQUE_OS_LINUX)
if( system == WindowSystem_X11 && info.subsystem == SDL_SYSWM_X11)
return (void*)info.info.x11.window;
#endif
AssertFatal(0, "");
return NULL;
}
void PlatformWindowSDL::setVideoMode( const GFXVideoMode &mode )
{
mVideoMode = mode;
mSuppressReset = true;
// Set our window to have the right style based on the mode
if(mode.fullScreen && !Platform::getWebDeployment() && !mOffscreenRender)
{
setSize(mode.resolution);
SDL_SetWindowFullscreen( mWindowHandle, SDL_WINDOW_FULLSCREEN);
// When switching to Fullscreen, reset device after setting style
if(mTarget.isValid())
mTarget->resetMode();
}
else
{
// Reset device *first*, so that when we call setSize() and let it
// access the monitor settings, it won't end up with our fullscreen
// geometry that is just about to change.
if(mTarget.isValid())
mTarget->resetMode();
if (!mOffscreenRender)
{
SDL_SetWindowFullscreen( mWindowHandle, 0);
}
setSize(mode.resolution);
centerWindow();
}
mSuppressReset = false;
}
bool PlatformWindowSDL::clearFullscreen()
{
return true;
}
bool PlatformWindowSDL::isFullscreen()
{
U32 flags = SDL_GetWindowFlags( mWindowHandle );
if( flags & SDL_WINDOW_FULLSCREEN || flags & SDL_WINDOW_FULLSCREEN_DESKTOP )
return true;
return false;
}
void PlatformWindowSDL::_setFullscreen(const bool fullscreen)
{
if( isFullscreen() )
return;
if(fullscreen && !mOffscreenRender)
{
Con::printf("PlatformWindowSDL::setFullscreen (full) enter");
SDL_SetWindowFullscreen( mWindowHandle, SDL_WINDOW_FULLSCREEN);
}
else
{
Con::printf("PlatformWindowSDL::setFullscreen (windowed) enter");
if (!mOffscreenRender)
{
SDL_SetWindowFullscreen( mWindowHandle, SDL_WINDOW_FULLSCREEN_DESKTOP);
}
setSize(mVideoMode.resolution);
}
Con::printf("PlatformWindowSDL::setFullscreen exit");
}
bool PlatformWindowSDL::setCaption( const char *cap )
{
SDL_SetWindowTitle(mWindowHandle, cap);
return true;
}
const char * PlatformWindowSDL::getCaption()
{
return StringTable->insert( SDL_GetWindowTitle(mWindowHandle) );
}
void PlatformWindowSDL::setFocus()
{
SDL_SetWindowGrab( mWindowHandle, SDL_TRUE );
}
void PlatformWindowSDL::setClientExtent( const Point2I newExtent )
{
Point2I oldExtent = getClientExtent();
if (oldExtent == newExtent)
return;
SDL_SetWindowSize(mWindowHandle, newExtent.x, newExtent.y);
}
const Point2I PlatformWindowSDL::getClientExtent()
{
// Fetch Client Rect from Windows
Point2I size;
SDL_GetWindowSize(mWindowHandle, &size.x, &size.y);
return size;
}
void PlatformWindowSDL::setBounds( const RectI &newBounds )
{
// TODO SDL
}
const RectI PlatformWindowSDL::getBounds() const
{
// TODO SDL
return RectI(0, 0, 0, 0);
}
void PlatformWindowSDL::setPosition( const Point2I newPosition )
{
SDL_SetWindowPosition( mWindowHandle, newPosition.x, newPosition.y );
}
const Point2I PlatformWindowSDL::getPosition()
{
Point2I position;
SDL_GetWindowPosition( mWindowHandle, &position.x, &position.y );
// Return position
return position;
}
Point2I PlatformWindowSDL::clientToScreen( const Point2I& pos )
{
Point2I position;
SDL_GetWindowPosition( mWindowHandle, &position.x, &position.y );
return pos + position;
}
Point2I PlatformWindowSDL::screenToClient( const Point2I& pos )
{
Point2I position;
SDL_GetWindowPosition( mWindowHandle, &position.x, &position.y );
return pos - position;
}
void PlatformWindowSDL::centerWindow()
{
int sizeX, sizeY;
SDL_GetWindowSize(mWindowHandle, &sizeX, &sizeY);
SDL_DisplayMode mode;
SDL_GetDesktopDisplayMode(0, &mode);
U32 posX = (mode.w/2) - (sizeX/2);
U32 posY = (mode.h/2) - (sizeY/2);
SDL_SetWindowPosition( mWindowHandle, posX, posY);
}
bool PlatformWindowSDL::setSize( const Point2I &newSize )
{
SDL_SetWindowSize(mWindowHandle, newSize.x, newSize.y);
// Let GFX get an update about the new resolution
if (mTarget.isValid())
mTarget->resetMode();
return true;
}
bool PlatformWindowSDL::isOpen()
{
return mWindowHandle;
}
bool PlatformWindowSDL::isVisible()
{
// Is the window open and visible, ie. not minimized?
if(!mWindowHandle)
return false;
if (mOffscreenRender)
return true;
U32 flags = SDL_GetWindowFlags( mWindowHandle );
if( flags & SDL_WINDOW_SHOWN)
return true;
return false;
}
bool PlatformWindowSDL::isFocused()
{
if (mOffscreenRender)
return true;
U32 flags = SDL_GetWindowFlags( mWindowHandle );
if( flags & SDL_WINDOW_INPUT_FOCUS || flags & SDL_WINDOW_INPUT_GRABBED || flags & SDL_WINDOW_MOUSE_FOCUS )
return true;
return false;
}
bool PlatformWindowSDL::isMinimized()
{
if (mOffscreenRender)
return false;
U32 flags = SDL_GetWindowFlags( mWindowHandle );
if( flags & SDL_WINDOW_MINIMIZED)
return true;
return false;
}
bool PlatformWindowSDL::isMaximized()
{
if (mOffscreenRender)
return true;
U32 flags = SDL_GetWindowFlags( mWindowHandle );
if( flags & SDL_WINDOW_MAXIMIZED)
return true;
return false;
}
WindowId PlatformWindowSDL::getWindowId()
{
return mWindowId;
}
void PlatformWindowSDL::minimize()
{
if (mOffscreenRender)
return;
SDL_MinimizeWindow( mWindowHandle );
}
void PlatformWindowSDL::maximize()
{
if (mOffscreenRender)
return;
SDL_MaximizeWindow( mWindowHandle );
}
void PlatformWindowSDL::restore()
{
if (mOffscreenRender)
return;
SDL_RestoreWindow( mWindowHandle );
}
void PlatformWindowSDL::hide()
{
if (mOffscreenRender)
return;
SDL_HideWindow( mWindowHandle );
}
void PlatformWindowSDL::show()
{
if (mOffscreenRender)
return;
SDL_ShowWindow( mWindowHandle );
}
void PlatformWindowSDL::close()
{
delete this;
}
void PlatformWindowSDL::defaultRender()
{
// TODO SDL
}
void PlatformWindowSDL::_triggerMouseLocationNotify(const SDL_Event& evt)
{
U32 mods = getTorqueModFromSDL(SDL_GetModState());
if(!mMouseLocked)
mouseEvent.trigger(getWindowId(), mods, evt.motion.x, evt.motion.y, false);
else
mouseEvent.trigger(getWindowId(), mods, evt.motion.xrel, evt.motion.yrel, true);
}
void PlatformWindowSDL::_triggerMouseWheelNotify(const SDL_Event& evt)
{
U32 mods = getTorqueModFromSDL(SDL_GetModState());
S32 wheelDelta = Con::getIntVariable("$pref::Input::MouseWheelSpeed", 120);
wheelEvent.trigger(getWindowId(), mods, evt.wheel.x * wheelDelta, evt.wheel.y * wheelDelta);
}
void PlatformWindowSDL::_triggerMouseButtonNotify(const SDL_Event& event)
{
S32 action = (event.type == SDL_MOUSEBUTTONDOWN) ? SI_MAKE : SI_BREAK;
S32 button = -1;
switch (event.button.button)
{
case SDL_BUTTON_LEFT:
button = 0;
break;
case SDL_BUTTON_RIGHT:
button = 1;
break;
case SDL_BUTTON_MIDDLE:
button = 2;
break;
default:
return;
}
U32 mod = getTorqueModFromSDL( SDL_GetModState() );
buttonEvent.trigger(getWindowId(), mod, action, button );
}
void PlatformWindowSDL::_triggerKeyNotify(const SDL_Event& evt)
{
U32 inputAction = IA_MAKE;
SDL_Keysym tKey = evt.key.keysym;
if(evt.type == SDL_KEYUP)
{
inputAction = IA_BREAK;
}
if(evt.key.repeat)
{
inputAction = IA_REPEAT;
}
U32 torqueModifiers = getTorqueModFromSDL(evt.key.keysym.mod);
U32 torqueKey = KeyMapSDL::getTorqueScanCodeFromSDL(tKey.scancode);
if(tKey.scancode)
{
keyEvent.trigger(getWindowId(), torqueModifiers, inputAction, torqueKey);
//Con::printf("Key %d : %d", tKey.sym, inputAction);
if (inputAction == IA_MAKE && SDL_IsTextInputActive())
{
// We have to check if we already have a first responder active.
// We don't want to type the character if it actually creates another responder!
if (mWindowInputGenerator->lastKeyWasGlobalActionMap())
{
// Turn off Text input, and the next frame turn it back on. This tells SDL
// to not generate a text event for this global action map key.
SDL_StopTextInput();
mOwningManager->updateSDLTextInputState(PlatformWindowManagerSDL::KeyboardInputState::TEXT_INPUT);
}
}
}
}
void PlatformWindowSDL::_triggerTextNotify(const SDL_Event& evt)
{
U32 mod = getTorqueModFromSDL( SDL_GetModState() );
if( !evt.text.text[1] ) // get a char
{
U16 wchar = evt.text.text[0];
charEvent.trigger(getWindowId(), mod, wchar );
//Con::printf("Char: %c", wchar);
return;
}
else // get a wchar string
{
const U32 len = strlen(evt.text.text);
U16 wchar[16] = {};
dMemcpy(wchar, evt.text.text, sizeof(char)*len);
for(int i = 0; i < 16; ++i)
{
if( !wchar[i] )
return;
charEvent.trigger(getWindowId(), mod, wchar[i] );
}
}
}
void PlatformWindowSDL::_processSDLEvent(SDL_Event &evt)
{
switch(evt.type)
{
case SDL_KEYDOWN:
case SDL_KEYUP:
{
_triggerKeyNotify(evt);
break;
}
case SDL_TEXTINPUT:
{
_triggerTextNotify(evt);
break;
}
case SDL_MOUSEWHEEL:
{
_triggerMouseWheelNotify(evt);
break;
}
case SDL_MOUSEMOTION:
{
_triggerMouseLocationNotify(evt);
break;
}
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
{
appEvent.trigger(getWindowId(), GainFocus);
_triggerMouseButtonNotify(evt);
break;
}
case SDL_WINDOWEVENT:
{
switch( evt.window.event )
{
case SDL_WINDOWEVENT_MAXIMIZED:
case SDL_WINDOWEVENT_RESIZED:
{
int width, height;
SDL_GetWindowSize( mWindowHandle, &width, &height );
mVideoMode.resolution.set( width, height );
getGFXTarget()->resetMode();
break;
}
default:
break;
}
}
}
}
//-----------------------------------------------------------------------------
// Mouse Locking
//-----------------------------------------------------------------------------
void PlatformWindowSDL::setMouseLocked( bool enable )
{
if (mOffscreenRender)
return;
mMouseLocked = enable;
SDL_SetWindowGrab( mWindowHandle, SDL_bool(enable) );
SDL_SetRelativeMouseMode( SDL_bool(enable) );
}
const UTF16 *PlatformWindowSDL::getWindowClassName()
{
// TODO SDL
static String str("WindowClassName");
return str.utf16();
}
const UTF16 *PlatformWindowSDL::getCurtainWindowClassName()
{
// TODO SDL
static String str("CurtainWindowClassName");
return str.utf16();
}
void PlatformWindowSDL::setKeyboardTranslation(const bool enabled)
{
mEnableKeyboardTranslation = enabled;
// Flag for update. Let SDL know what kind of input state we are changing to.
if (enabled)
mOwningManager->updateSDLTextInputState(PlatformWindowManagerSDL::KeyboardInputState::TEXT_INPUT);
else
mOwningManager->updateSDLTextInputState(PlatformWindowManagerSDL::KeyboardInputState::RAW_INPUT);
}