Files
test/intern/ghost/intern/GHOST_SystemSDL.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

749 lines
24 KiB
C++
Raw Normal View History

/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup GHOST
*/
#include <assert.h>
#include "GHOST_ContextSDL.h"
#include "GHOST_SystemSDL.h"
#include "GHOST_WindowSDL.h"
#include "GHOST_WindowManager.h"
#include "GHOST_EventButton.h"
#include "GHOST_EventCursor.h"
#include "GHOST_EventKey.h"
#include "GHOST_EventWheel.h"
GHOST_SystemSDL::GHOST_SystemSDL() : GHOST_System()
{
2012-05-19 09:57:55 +00:00
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) {
printf("Error initializing SDL: %s\n", SDL_GetError());
}
2012-05-19 09:57:55 +00:00
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
}
GHOST_SystemSDL::~GHOST_SystemSDL()
{
SDL_Quit();
}
GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title,
int32_t left,
int32_t top,
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive,
UI: Register File Browser as Child/Dialog-Window for the OS For many users, this will make the File Browser window behave more like what they would expect. It addresses the issue of the File Browser becoming hidden behind the main window by clicking anywhere in the latter. It communicates the interruptive, but temporary nature of the operation a bit better. Further, on tiling window managers the File Browser now opens as floating by default, like in other applications. Note that this also makes sure the File Browser is always opened as separate window, so it doesn't re-use the Preferences, or any other temporary window anymore. This seems to have been a common annoyance. More concretely, this makes the File Browser window behave as follows: * Stays on top of its parent Blender window, but not on top of non-Blender windows. * Minimizes with its parent window * Can be moved independently * Doesn't add an own item in task bars * Doesn't block other Blender windows (we may want to have this though) * Opens as floating window for tiling window managers (e.g. i3wm/Sway) Further notes: * When opening a file browser from the Preference window (or any temporary window), the main window, as the file browsers parent is moved on top of the Preferences, which makes it seem like the Preferences were closed. This is the general issue of bad secondary window handling as window activation changes. I made it so that the window is moved back once the file browser is closed. This behavior is confusing and would be nice to avoid. It's a separate issue though. * On most window managers on Linux the temporary window can not be minimized and maximized, they disable that for dialog windows. * On Windows and macOS, only minimizing is disabled, as there is no decent way yet to restore a window if it's not shown in the taskbar. Reviewed By: Brecht van Lommel, Campbell Barton, William Reynish Edits and macOS implementation by Brecht. Differential Revision: https://developer.blender.org/D5810 Part of T69652.
2019-10-03 16:59:49 +02:00
const bool /* is_dialog */,
2019-11-05 15:33:23 +01:00
const GHOST_IWindow *parentWindow)
{
2012-05-19 09:57:55 +00:00
GHOST_WindowSDL *window = NULL;
window = new GHOST_WindowSDL(this,
title,
left,
top,
width,
height,
state,
type,
((glSettings.flags & GHOST_glStereoVisual) != 0),
2019-11-05 15:33:23 +01:00
exclusive,
parentWindow);
if (window) {
if (GHOST_kWindowStateFullScreen == state) {
SDL_Window *sdl_win = window->getSDLWindow();
SDL_DisplayMode mode;
static_cast<GHOST_DisplayManagerSDL *>(m_displayManager)->getCurrentDisplayModeSDL(mode);
SDL_SetWindowDisplayMode(sdl_win, &mode);
SDL_ShowWindow(sdl_win);
SDL_SetWindowFullscreen(sdl_win, SDL_TRUE);
}
if (window->getValid()) {
m_windowManager->addWindow(window);
pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window));
}
else {
delete window;
2012-05-19 09:57:55 +00:00
window = NULL;
}
}
return window;
}
GHOST_TSuccess GHOST_SystemSDL::init()
{
GHOST_TSuccess success = GHOST_System::init();
if (success) {
m_displayManager = new GHOST_DisplayManagerSDL(this);
if (m_displayManager) {
return GHOST_kSuccess;
}
}
return GHOST_kFailure;
}
2013-02-08 08:02:05 +00:00
/**
* Returns the dimensions of the main display on this system.
* \return The dimension of the main display.
*/
void GHOST_SystemSDL::getAllDisplayDimensions(uint32_t &width, uint32_t &height) const
2013-02-08 08:02:05 +00:00
{
SDL_DisplayMode mode;
SDL_GetDesktopDisplayMode(0, &mode); /* NOTE: always 0 display. */
2013-02-08 08:02:05 +00:00
width = mode.w;
height = mode.h;
}
void GHOST_SystemSDL::getMainDisplayDimensions(uint32_t &width, uint32_t &height) const
{
SDL_DisplayMode mode;
SDL_GetCurrentDisplayMode(0, &mode); /* NOTE: always 0 display. */
2012-05-19 09:57:55 +00:00
width = mode.w;
height = mode.h;
}
uint8_t GHOST_SystemSDL::getNumDisplays() const
{
return SDL_GetNumVideoDisplays();
}
GHOST_IContext *GHOST_SystemSDL::createOffscreenContext(GHOST_GLSettings glSettings)
{
GHOST_Context *context = new GHOST_ContextSDL(0,
NULL,
0, /* Profile bit. */
3,
3,
GHOST_OPENGL_SDL_CONTEXT_FLAGS,
GHOST_OPENGL_SDL_RESET_NOTIFICATION_STRATEGY);
if (context->initializeDrawingContext())
return context;
else
delete context;
return NULL;
}
GHOST_TSuccess GHOST_SystemSDL::disposeContext(GHOST_IContext *context)
{
delete context;
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_SystemSDL::getModifierKeys(GHOST_ModifierKeys &keys) const
{
2012-05-19 09:57:55 +00:00
SDL_Keymod mod = SDL_GetModState();
keys.set(GHOST_kModifierKeyLeftShift, (mod & KMOD_LSHIFT) != 0);
keys.set(GHOST_kModifierKeyRightShift, (mod & KMOD_RSHIFT) != 0);
keys.set(GHOST_kModifierKeyLeftControl, (mod & KMOD_LCTRL) != 0);
keys.set(GHOST_kModifierKeyRightControl, (mod & KMOD_RCTRL) != 0);
keys.set(GHOST_kModifierKeyLeftAlt, (mod & KMOD_LALT) != 0);
keys.set(GHOST_kModifierKeyRightAlt, (mod & KMOD_RALT) != 0);
2012-05-19 09:57:55 +00:00
keys.set(GHOST_kModifierKeyOS, (mod & (KMOD_LGUI | KMOD_RGUI)) != 0);
return GHOST_kSuccess;
}
2012-05-19 09:57:55 +00:00
#define GXMAP(k, x, y) \
case x: \
k = y; \
break
static GHOST_TKey convertSDLKey(SDL_Scancode key)
{
GHOST_TKey type;
if ((key >= SDL_SCANCODE_A) && (key <= SDL_SCANCODE_Z)) {
2012-05-19 09:57:55 +00:00
type = GHOST_TKey(key - SDL_SCANCODE_A + int(GHOST_kKeyA));
}
else if ((key >= SDL_SCANCODE_1) && (key <= SDL_SCANCODE_0)) {
type = (key == SDL_SCANCODE_0) ? GHOST_kKey0 :
GHOST_TKey(key - SDL_SCANCODE_1 + int(GHOST_kKey1));
}
else if ((key >= SDL_SCANCODE_F1) && (key <= SDL_SCANCODE_F12)) {
type = GHOST_TKey(key - SDL_SCANCODE_F1 + int(GHOST_kKeyF1));
}
else if ((key >= SDL_SCANCODE_F13) && (key <= SDL_SCANCODE_F24)) {
type = GHOST_TKey(key - SDL_SCANCODE_F13 + int(GHOST_kKeyF13));
}
else {
switch (key) {
/* TODO SDL_SCANCODE_NONUSBACKSLASH */
2012-05-19 09:57:55 +00:00
GXMAP(type, SDL_SCANCODE_BACKSPACE, GHOST_kKeyBackSpace);
GXMAP(type, SDL_SCANCODE_TAB, GHOST_kKeyTab);
GXMAP(type, SDL_SCANCODE_RETURN, GHOST_kKeyEnter);
GXMAP(type, SDL_SCANCODE_ESCAPE, GHOST_kKeyEsc);
GXMAP(type, SDL_SCANCODE_SPACE, GHOST_kKeySpace);
2012-05-19 09:57:55 +00:00
GXMAP(type, SDL_SCANCODE_SEMICOLON, GHOST_kKeySemicolon);
GXMAP(type, SDL_SCANCODE_PERIOD, GHOST_kKeyPeriod);
GXMAP(type, SDL_SCANCODE_COMMA, GHOST_kKeyComma);
GXMAP(type, SDL_SCANCODE_APOSTROPHE, GHOST_kKeyQuote);
GXMAP(type, SDL_SCANCODE_GRAVE, GHOST_kKeyAccentGrave);
GXMAP(type, SDL_SCANCODE_MINUS, GHOST_kKeyMinus);
GXMAP(type, SDL_SCANCODE_EQUALS, GHOST_kKeyEqual);
2012-05-19 09:57:55 +00:00
GXMAP(type, SDL_SCANCODE_SLASH, GHOST_kKeySlash);
GXMAP(type, SDL_SCANCODE_BACKSLASH, GHOST_kKeyBackslash);
GXMAP(type, SDL_SCANCODE_KP_EQUALS, GHOST_kKeyEqual);
GXMAP(type, SDL_SCANCODE_LEFTBRACKET, GHOST_kKeyLeftBracket);
GXMAP(type, SDL_SCANCODE_RIGHTBRACKET, GHOST_kKeyRightBracket);
GXMAP(type, SDL_SCANCODE_PAUSE, GHOST_kKeyPause);
2012-05-19 09:57:55 +00:00
GXMAP(type, SDL_SCANCODE_LSHIFT, GHOST_kKeyLeftShift);
GXMAP(type, SDL_SCANCODE_RSHIFT, GHOST_kKeyRightShift);
GXMAP(type, SDL_SCANCODE_LCTRL, GHOST_kKeyLeftControl);
GXMAP(type, SDL_SCANCODE_RCTRL, GHOST_kKeyRightControl);
GXMAP(type, SDL_SCANCODE_LALT, GHOST_kKeyLeftAlt);
GXMAP(type, SDL_SCANCODE_RALT, GHOST_kKeyRightAlt);
GXMAP(type, SDL_SCANCODE_LGUI, GHOST_kKeyOS);
GXMAP(type, SDL_SCANCODE_RGUI, GHOST_kKeyOS);
GXMAP(type, SDL_SCANCODE_APPLICATION, GHOST_kKeyApp);
2012-05-19 09:57:55 +00:00
GXMAP(type, SDL_SCANCODE_INSERT, GHOST_kKeyInsert);
GXMAP(type, SDL_SCANCODE_DELETE, GHOST_kKeyDelete);
GXMAP(type, SDL_SCANCODE_HOME, GHOST_kKeyHome);
GXMAP(type, SDL_SCANCODE_END, GHOST_kKeyEnd);
GXMAP(type, SDL_SCANCODE_PAGEUP, GHOST_kKeyUpPage);
GXMAP(type, SDL_SCANCODE_PAGEDOWN, GHOST_kKeyDownPage);
2012-05-19 09:57:55 +00:00
GXMAP(type, SDL_SCANCODE_LEFT, GHOST_kKeyLeftArrow);
GXMAP(type, SDL_SCANCODE_RIGHT, GHOST_kKeyRightArrow);
GXMAP(type, SDL_SCANCODE_UP, GHOST_kKeyUpArrow);
GXMAP(type, SDL_SCANCODE_DOWN, GHOST_kKeyDownArrow);
2012-05-19 09:57:55 +00:00
GXMAP(type, SDL_SCANCODE_CAPSLOCK, GHOST_kKeyCapsLock);
GXMAP(type, SDL_SCANCODE_SCROLLLOCK, GHOST_kKeyScrollLock);
GXMAP(type, SDL_SCANCODE_NUMLOCKCLEAR, GHOST_kKeyNumLock);
GXMAP(type, SDL_SCANCODE_PRINTSCREEN, GHOST_kKeyPrintScreen);
2012-05-19 09:57:55 +00:00
/* keypad events */
2020-10-09 12:12:29 +11:00
/* NOTE: SDL defines a bunch of key-pad identifiers that aren't supported by GHOST,
* such as #SDL_SCANCODE_KP_PERCENT, #SDL_SCANCODE_KP_XOR. */
2012-05-19 09:57:55 +00:00
GXMAP(type, SDL_SCANCODE_KP_0, GHOST_kKeyNumpad0);
GXMAP(type, SDL_SCANCODE_KP_1, GHOST_kKeyNumpad1);
GXMAP(type, SDL_SCANCODE_KP_2, GHOST_kKeyNumpad2);
GXMAP(type, SDL_SCANCODE_KP_3, GHOST_kKeyNumpad3);
GXMAP(type, SDL_SCANCODE_KP_4, GHOST_kKeyNumpad4);
GXMAP(type, SDL_SCANCODE_KP_5, GHOST_kKeyNumpad5);
GXMAP(type, SDL_SCANCODE_KP_6, GHOST_kKeyNumpad6);
GXMAP(type, SDL_SCANCODE_KP_7, GHOST_kKeyNumpad7);
GXMAP(type, SDL_SCANCODE_KP_8, GHOST_kKeyNumpad8);
GXMAP(type, SDL_SCANCODE_KP_9, GHOST_kKeyNumpad9);
GXMAP(type, SDL_SCANCODE_KP_PERIOD, GHOST_kKeyNumpadPeriod);
2012-05-19 09:57:55 +00:00
GXMAP(type, SDL_SCANCODE_KP_ENTER, GHOST_kKeyNumpadEnter);
GXMAP(type, SDL_SCANCODE_KP_PLUS, GHOST_kKeyNumpadPlus);
GXMAP(type, SDL_SCANCODE_KP_MINUS, GHOST_kKeyNumpadMinus);
GXMAP(type, SDL_SCANCODE_KP_MULTIPLY, GHOST_kKeyNumpadAsterisk);
GXMAP(type, SDL_SCANCODE_KP_DIVIDE, GHOST_kKeyNumpadSlash);
2012-05-19 09:57:55 +00:00
/* Media keys in some keyboards and laptops with XFree86/Xorg */
GXMAP(type, SDL_SCANCODE_AUDIOPLAY, GHOST_kKeyMediaPlay);
GXMAP(type, SDL_SCANCODE_AUDIOSTOP, GHOST_kKeyMediaStop);
GXMAP(type, SDL_SCANCODE_AUDIOPREV, GHOST_kKeyMediaFirst);
// GXMAP(type, XF86XK_AudioRewind, GHOST_kKeyMediaFirst);
2012-05-19 09:57:55 +00:00
GXMAP(type, SDL_SCANCODE_AUDIONEXT, GHOST_kKeyMediaLast);
2012-05-19 09:57:55 +00:00
default:
printf("Unknown\n");
type = GHOST_kKeyUnknown;
break;
}
}
return type;
}
#undef GXMAP
/**
* Events don't always have valid windows,
* but GHOST needs a window _always_. fallback to the GL window.
*/
static SDL_Window *SDL_GetWindowFromID_fallback(Uint32 id)
{
SDL_Window *sdl_win = SDL_GetWindowFromID(id);
if (sdl_win == NULL) {
sdl_win = SDL_GL_GetCurrentWindow();
}
return sdl_win;
}
void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
{
2012-05-19 09:57:55 +00:00
GHOST_Event *g_event = NULL;
2012-05-19 09:57:55 +00:00
switch (sdl_event->type) {
case SDL_WINDOWEVENT: {
SDL_WindowEvent &sdl_sub_evt = sdl_event->window;
GHOST_WindowSDL *window = findGhostWindow(
SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
/* Can be NULL on close window. */
#if 0
assert(window != NULL);
#endif
switch (sdl_sub_evt.event) {
2012-05-19 09:57:55 +00:00
case SDL_WINDOWEVENT_EXPOSED:
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window);
break;
case SDL_WINDOWEVENT_RESIZED:
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window);
break;
case SDL_WINDOWEVENT_MOVED:
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowMove, window);
break;
case SDL_WINDOWEVENT_FOCUS_GAINED:
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window);
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowDeactivate, window);
break;
case SDL_WINDOWEVENT_CLOSE:
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, window);
break;
}
2012-05-19 09:57:55 +00:00
break;
2015-07-18 19:02:39 +10:00
}
case SDL_QUIT: {
GHOST_IWindow *window = m_windowManager->getActiveWindow();
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventQuitRequest, window);
2012-05-19 09:57:55 +00:00
break;
}
2012-05-19 09:57:55 +00:00
case SDL_MOUSEMOTION: {
SDL_MouseMotionEvent &sdl_sub_evt = sdl_event->motion;
SDL_Window *sdl_win = SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID);
2012-05-19 09:57:55 +00:00
GHOST_WindowSDL *window = findGhostWindow(sdl_win);
assert(window != NULL);
int x_win, y_win;
SDL_GetWindowPosition(sdl_win, &x_win, &y_win);
int32_t x_root = sdl_sub_evt.x + x_win;
int32_t y_root = sdl_sub_evt.y + y_win;
#if 0
if (window->getCursorGrabMode() != GHOST_kGrabDisable &&
window->getCursorGrabMode() != GHOST_kGrabNormal) {
int32_t x_new = x_root;
int32_t y_new = y_root;
int32_t x_accum, y_accum;
GHOST_Rect bounds;
/* fallback to window bounds */
2012-05-19 09:57:55 +00:00
if (window->getCursorGrabBounds(bounds) == GHOST_kFailure)
window->getClientBounds(bounds);
2021-09-24 11:31:23 +10:00
/* Could also clamp to screen bounds wrap with a window outside the view will
* fail at the moment. Use offset of 8 in case the window is at screen bounds. */
bounds.wrapPoint(x_new, y_new, 8, window->getCursorGrabAxis());
window->getCursorGrabAccum(x_accum, y_accum);
/* Can't use #setCursorPosition because the mouse may have no focus! */
2012-05-19 09:57:55 +00:00
if (x_new != x_root || y_new != y_root) {
if (1 /* `xme.time > m_last_warp` */ ) {
/* when wrapping we don't need to add an event because the
* #setCursorPosition call will cause a new event after */
SDL_WarpMouseInWindow(sdl_win, x_new - x_win, y_new - y_win); /* wrap */
window->setCursorGrabAccum(x_accum + (x_root - x_new), y_accum + (y_root - y_new));
// m_last_warp = lastEventTime(xme.time);
2012-05-19 09:57:55 +00:00
}
else {
// setCursorPosition(x_new, y_new); /* wrap but don't accumulate */
SDL_WarpMouseInWindow(sdl_win, x_new - x_win, y_new - y_win);
}
g_event = new GHOST_EventCursor(getMilliSeconds(),
GHOST_kEventCursorMove,
window,
x_new,
y_new,
GHOST_TABLET_DATA_NONE);
}
else {
g_event = new GHOST_EventCursor(getMilliSeconds(),
GHOST_kEventCursorMove,
window,
x_root + x_accum,
y_root + y_accum,
GHOST_TABLET_DATA_NONE);
}
}
else
#endif
{
g_event = new GHOST_EventCursor(getMilliSeconds(),
GHOST_kEventCursorMove,
window,
x_root,
y_root,
GHOST_TABLET_DATA_NONE);
}
break;
}
2012-05-19 09:57:55 +00:00
case SDL_MOUSEBUTTONUP:
case SDL_MOUSEBUTTONDOWN: {
SDL_MouseButtonEvent &sdl_sub_evt = sdl_event->button;
GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft;
GHOST_TEventType type = (sdl_sub_evt.state == SDL_PRESSED) ? GHOST_kEventButtonDown :
GHOST_kEventButtonUp;
GHOST_WindowSDL *window = findGhostWindow(
SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
assert(window != NULL);
/* process rest of normal mouse buttons */
if (sdl_sub_evt.button == SDL_BUTTON_LEFT)
2012-05-19 09:57:55 +00:00
gbmask = GHOST_kButtonMaskLeft;
else if (sdl_sub_evt.button == SDL_BUTTON_MIDDLE)
2012-05-19 09:57:55 +00:00
gbmask = GHOST_kButtonMaskMiddle;
else if (sdl_sub_evt.button == SDL_BUTTON_RIGHT)
2012-05-19 09:57:55 +00:00
gbmask = GHOST_kButtonMaskRight;
/* these buttons are untested! */
else if (sdl_sub_evt.button == SDL_BUTTON_X1)
2012-05-19 09:57:55 +00:00
gbmask = GHOST_kButtonMaskButton4;
else if (sdl_sub_evt.button == SDL_BUTTON_X2)
2012-05-19 09:57:55 +00:00
gbmask = GHOST_kButtonMaskButton5;
else
break;
g_event = new GHOST_EventButton(
getMilliSeconds(), type, window, gbmask, GHOST_TABLET_DATA_NONE);
break;
}
2012-05-19 09:57:55 +00:00
case SDL_MOUSEWHEEL: {
SDL_MouseWheelEvent &sdl_sub_evt = sdl_event->wheel;
GHOST_WindowSDL *window = findGhostWindow(
SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
2012-05-19 09:57:55 +00:00
assert(window != NULL);
g_event = new GHOST_EventWheel(getMilliSeconds(), window, sdl_sub_evt.y);
break;
}
2012-05-19 09:57:55 +00:00
case SDL_KEYDOWN:
case SDL_KEYUP: {
2012-05-19 09:57:55 +00:00
SDL_KeyboardEvent &sdl_sub_evt = sdl_event->key;
SDL_Keycode sym = sdl_sub_evt.keysym.sym;
GHOST_TEventType type = (sdl_sub_evt.state == SDL_PRESSED) ? GHOST_kEventKeyDown :
GHOST_kEventKeyUp;
GHOST_WindowSDL *window = findGhostWindow(
SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
assert(window != NULL);
2012-05-19 09:57:55 +00:00
GHOST_TKey gkey = convertSDLKey(sdl_sub_evt.keysym.scancode);
/* NOTE: the `sdl_sub_evt.keysym.sym` is truncated,
* for unicode support ghost has to be modified. */
// printf("%d\n", sym);
2012-05-19 09:57:55 +00:00
if (sym > 127) {
switch (sym) {
case SDLK_KP_DIVIDE:
sym = '/';
break;
2012-05-19 09:57:55 +00:00
case SDLK_KP_MULTIPLY:
sym = '*';
2012-05-19 09:57:55 +00:00
break;
case SDLK_KP_MINUS:
sym = '-';
break;
2012-05-19 09:57:55 +00:00
case SDLK_KP_PLUS:
sym = '+';
break;
2012-05-19 09:57:55 +00:00
case SDLK_KP_1:
sym = '1';
break;
2012-05-19 09:57:55 +00:00
case SDLK_KP_2:
sym = '2';
break;
case SDLK_KP_3:
sym = '3';
break;
2012-05-19 09:57:55 +00:00
case SDLK_KP_4:
sym = '4';
break;
2012-05-19 09:57:55 +00:00
case SDLK_KP_5:
sym = '5';
break;
2012-05-19 09:57:55 +00:00
case SDLK_KP_6:
sym = '6';
break;
2012-05-19 09:57:55 +00:00
case SDLK_KP_7:
sym = '7';
break;
case SDLK_KP_8:
sym = '8';
break;
case SDLK_KP_9:
sym = '9';
break;
case SDLK_KP_0:
sym = '0';
break;
case SDLK_KP_PERIOD:
sym = '.';
break;
default:
sym = 0;
break;
}
2011-08-16 13:07:46 +00:00
}
else {
2012-05-19 09:57:55 +00:00
if (sdl_sub_evt.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT)) {
/* lame US keyboard assumptions */
2012-05-19 09:57:55 +00:00
if (sym >= 'a' && sym <= ('a' + 32)) {
sym -= 32;
}
else {
2012-05-19 09:57:55 +00:00
switch (sym) {
case '`':
2012-05-19 09:57:55 +00:00
sym = '~';
break;
2012-05-19 09:57:55 +00:00
case '1':
sym = '!';
break;
case '2':
sym = '@';
break;
case '3':
sym = '#';
break;
case '4':
sym = '$';
break;
case '5':
sym = '%';
break;
case '6':
sym = '^';
break;
case '7':
sym = '&';
break;
case '8':
sym = '*';
break;
case '9':
sym = '(';
break;
case '0':
sym = ')';
break;
case '-':
sym = '_';
break;
case '=':
sym = '+';
break;
case '[':
sym = '{';
break;
case ']':
sym = '}';
break;
case '\\':
sym = '|';
break;
case ';':
sym = ':';
break;
case '\'':
sym = '"';
break;
case ',':
sym = '<';
break;
case '.':
sym = '>';
break;
case '/':
sym = '?';
break;
default:
break;
}
}
}
}
g_event = new GHOST_EventKey(getMilliSeconds(), type, window, gkey, sym, NULL, false);
2012-05-19 09:57:55 +00:00
break;
}
}
if (g_event) {
pushEvent(g_event);
}
}
GHOST_TSuccess GHOST_SystemSDL::getCursorPosition(int32_t &x, int32_t &y) const
{
int x_win, y_win;
2012-05-19 09:57:55 +00:00
SDL_Window *win = SDL_GetMouseFocus();
SDL_GetWindowPosition(win, &x_win, &y_win);
int xi, yi;
SDL_GetMouseState(&xi, &yi);
2012-05-19 09:57:55 +00:00
x = xi + x_win;
y = yi + x_win;
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_SystemSDL::setCursorPosition(int32_t x, int32_t y)
{
int x_win, y_win;
2012-05-19 09:57:55 +00:00
SDL_Window *win = SDL_GetMouseFocus();
SDL_GetWindowPosition(win, &x_win, &y_win);
2012-05-19 09:57:55 +00:00
SDL_WarpMouseInWindow(win, x - x_win, y - y_win);
return GHOST_kSuccess;
}
bool GHOST_SystemSDL::generateWindowExposeEvents()
{
std::vector<GHOST_WindowSDL *>::iterator w_start = m_dirty_windows.begin();
2012-05-19 09:57:55 +00:00
std::vector<GHOST_WindowSDL *>::const_iterator w_end = m_dirty_windows.end();
bool anyProcessed = false;
2012-05-19 09:57:55 +00:00
for (; w_start != w_end; ++w_start) {
GHOST_Event *g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, *w_start);
(*w_start)->validate();
2012-05-19 09:57:55 +00:00
if (g_event) {
// printf("Expose events pushed\n");
pushEvent(g_event);
2012-05-19 09:57:55 +00:00
anyProcessed = true;
}
}
2012-05-19 09:57:55 +00:00
m_dirty_windows.clear();
return anyProcessed;
}
2012-05-19 09:57:55 +00:00
bool GHOST_SystemSDL::processEvents(bool waitForEvent)
{
/* Get all the current events - translate them into
* ghost events and call base class #pushEvent() method. */
2012-05-19 09:57:55 +00:00
bool anyProcessed = false;
2012-05-19 09:57:55 +00:00
do {
GHOST_TimerManager *timerMgr = getTimerManager();
if (waitForEvent && m_dirty_windows.empty() && !SDL_HasEvents(SDL_FIRSTEVENT, SDL_LASTEVENT)) {
uint64_t next = timerMgr->nextFireTime();
if (next == GHOST_kFireTimeNever) {
SDL_WaitEventTimeout(NULL, -1);
// SleepTillEvent(m_display, -1);
}
else {
int64_t maxSleep = next - getMilliSeconds();
2012-05-19 09:57:55 +00:00
if (maxSleep >= 0) {
SDL_WaitEventTimeout(NULL, next - getMilliSeconds());
// SleepTillEvent(m_display, next - getMilliSeconds()); /* X11. */
}
}
}
if (timerMgr->fireTimers(getMilliSeconds())) {
2012-05-19 09:57:55 +00:00
anyProcessed = true;
}
SDL_Event sdl_event;
while (SDL_PollEvent(&sdl_event)) {
processEvent(&sdl_event);
2012-05-19 09:57:55 +00:00
anyProcessed = true;
}
if (generateWindowExposeEvents()) {
2012-05-19 09:57:55 +00:00
anyProcessed = true;
}
} while (waitForEvent && !anyProcessed);
return anyProcessed;
}
GHOST_WindowSDL *GHOST_SystemSDL::findGhostWindow(SDL_Window *sdl_win)
{
if (sdl_win == NULL)
return NULL;
/* It is not entirely safe to do this as the backptr may point
* to a window that has recently been removed.
* We should always check the window manager's list of windows
* and only process events on these windows. */
const std::vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
std::vector<GHOST_IWindow *>::const_iterator win_it = win_vec.begin();
2012-05-19 09:57:55 +00:00
std::vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
for (; win_it != win_end; ++win_it) {
GHOST_WindowSDL *window = static_cast<GHOST_WindowSDL *>(*win_it);
if (window->getSDLWindow() == sdl_win) {
return window;
}
}
return NULL;
}
void GHOST_SystemSDL::addDirtyWindow(GHOST_WindowSDL *bad_wind)
{
GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
m_dirty_windows.push_back(bad_wind);
}
GHOST_TSuccess GHOST_SystemSDL::getButtons(GHOST_Buttons &buttons) const
{
2012-05-19 09:57:55 +00:00
Uint8 state = SDL_GetMouseState(NULL, NULL);
buttons.set(GHOST_kButtonMaskLeft, (state & SDL_BUTTON_LMASK) != 0);
buttons.set(GHOST_kButtonMaskMiddle, (state & SDL_BUTTON_MMASK) != 0);
buttons.set(GHOST_kButtonMaskRight, (state & SDL_BUTTON_RMASK) != 0);
return GHOST_kSuccess;
}
char *GHOST_SystemSDL::getClipboard(bool selection) const
{
return (char *)SDL_GetClipboardText();
}
void GHOST_SystemSDL::putClipboard(const char *buffer, bool selection) const
{
SDL_SetClipboardText(buffer);
}
uint64_t GHOST_SystemSDL::getMilliSeconds()
{
return uint64_t(SDL_GetTicks()); /* NOTE: 32 -> 64bits. */
}