8561dbfd639cdea13030e6526e065c48d958eba1
[blender-staging.git] / intern / ghost / intern / GHOST_SystemSDL.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Campbell Barton
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file ghost/intern/GHOST_SystemSDL.cpp
24  *  \ingroup GHOST
25  */
26
27 #include <assert.h>
28
29 #include "GHOST_SystemSDL.h"
30 #include "GHOST_WindowSDL.h"
31
32 #include "GHOST_WindowManager.h"
33
34 #include "GHOST_EventCursor.h"
35 #include "GHOST_EventKey.h"
36 #include "GHOST_EventButton.h"
37 #include "GHOST_EventWheel.h"
38
39 GHOST_SystemSDL::GHOST_SystemSDL()
40     :
41       GHOST_System()
42 {
43         if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) {
44                 printf("Error initializing SDL:  %s\n", SDL_GetError());
45         }
46
47         /* SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); */
48         /* SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); */
49         SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
50         SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
51         SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
52         SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
53         SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
54         SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
55 }
56
57 GHOST_SystemSDL::~GHOST_SystemSDL()
58 {
59         SDL_Quit();
60 }
61
62 GHOST_IWindow *
63 GHOST_SystemSDL::createWindow(const STR_String& title,
64                               GHOST_TInt32 left,
65                               GHOST_TInt32 top,
66                               GHOST_TUns32 width,
67                               GHOST_TUns32 height,
68                               GHOST_TWindowState state,
69                               GHOST_TDrawingContextType type,
70                               GHOST_GLSettings glSettings,
71                               const bool exclusive,
72                               const GHOST_TEmbedderWindowID parentWindow
73                               )
74 {
75         GHOST_WindowSDL *window = NULL;
76
77         window = new GHOST_WindowSDL(this, title,
78                                      left, top, width, height,
79                                      state, parentWindow, type,
80                                      ((glSettings.flags & GHOST_glStereoVisual) != 0), exclusive,
81                                      glSettings.numOfAASamples);
82
83         if (window) {
84                 if (GHOST_kWindowStateFullScreen == state) {
85                         SDL_Window *sdl_win = window->getSDLWindow();
86                         SDL_DisplayMode mode;
87
88                         static_cast<GHOST_DisplayManagerSDL *> (m_displayManager)->getCurrentDisplayModeSDL(mode);
89
90                         SDL_SetWindowDisplayMode(sdl_win, &mode);
91                         SDL_ShowWindow(sdl_win);
92                         SDL_SetWindowFullscreen(sdl_win, SDL_TRUE);
93                 }
94
95                 if (window->getValid()) {
96                         m_windowManager->addWindow(window);
97                         pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window));
98                 }
99                 else {
100                         delete window;
101                         window = NULL;
102                 }
103         }
104         return window;
105 }
106
107 GHOST_TSuccess
108 GHOST_SystemSDL::init() {
109         GHOST_TSuccess success = GHOST_System::init();
110
111         if (success) {
112                 m_displayManager = new GHOST_DisplayManagerSDL(this);
113
114                 if (m_displayManager) {
115                         return GHOST_kSuccess;
116                 }
117         }
118
119         return GHOST_kFailure;
120 }
121
122 /**
123  * Returns the dimensions of the main display on this system.
124  * \return The dimension of the main display.
125  */
126 void
127 GHOST_SystemSDL::getAllDisplayDimensions(GHOST_TUns32& width,
128                                          GHOST_TUns32& height) const
129 {
130         SDL_DisplayMode mode;
131         SDL_GetDesktopDisplayMode(0, &mode); /* note, always 0 display */
132         width = mode.w;
133         height = mode.h;
134 }
135
136 void
137 GHOST_SystemSDL::getMainDisplayDimensions(GHOST_TUns32& width,
138                                           GHOST_TUns32& height) const
139 {
140         SDL_DisplayMode mode;
141         SDL_GetCurrentDisplayMode(0, &mode); /* note, always 0 display */
142         width = mode.w;
143         height = mode.h;
144 }
145
146 GHOST_TUns8
147 GHOST_SystemSDL::getNumDisplays() const
148 {
149         return SDL_GetNumVideoDisplays();
150 }
151
152 GHOST_TSuccess
153 GHOST_SystemSDL::getModifierKeys(GHOST_ModifierKeys& keys) const
154 {
155         SDL_Keymod mod = SDL_GetModState();
156
157         keys.set(GHOST_kModifierKeyLeftShift,    (mod & KMOD_LSHIFT) != 0);
158         keys.set(GHOST_kModifierKeyRightShift,   (mod & KMOD_RSHIFT) != 0);
159         keys.set(GHOST_kModifierKeyLeftControl,  (mod & KMOD_LCTRL) != 0);
160         keys.set(GHOST_kModifierKeyRightControl, (mod & KMOD_RCTRL) != 0);
161         keys.set(GHOST_kModifierKeyLeftAlt,      (mod & KMOD_LALT) != 0);
162         keys.set(GHOST_kModifierKeyRightAlt,     (mod & KMOD_RALT) != 0);
163         keys.set(GHOST_kModifierKeyOS,           (mod & (KMOD_LGUI | KMOD_RGUI)) != 0);
164
165         return GHOST_kSuccess;
166 }
167
168 #define GXMAP(k, x, y) case x: k = y; break
169
170 static GHOST_TKey
171 convertSDLKey(SDL_Scancode key)
172 {
173         GHOST_TKey type;
174
175         if ((key >= SDL_SCANCODE_A) && (key <= SDL_SCANCODE_Z)) {
176                 type = GHOST_TKey(key - SDL_SCANCODE_A + int(GHOST_kKeyA));
177         }
178         else if ((key >= SDL_SCANCODE_1) && (key <= SDL_SCANCODE_0)) {
179                 type = (key == SDL_SCANCODE_0) ? GHOST_kKey0 : GHOST_TKey(key - SDL_SCANCODE_1 + int(GHOST_kKey1));
180         }
181         else if ((key >= SDL_SCANCODE_F1) && (key <= SDL_SCANCODE_F12)) {
182                 type = GHOST_TKey(key - SDL_SCANCODE_F1 + int(GHOST_kKeyF1));
183         }
184         else if ((key >= SDL_SCANCODE_F13) && (key <= SDL_SCANCODE_F24)) {
185                 type = GHOST_TKey(key - SDL_SCANCODE_F13 + int(GHOST_kKeyF13));
186         }
187         else {
188                 switch (key) {
189                         /* TODO SDL_SCANCODE_NONUSBACKSLASH */
190
191                         GXMAP(type, SDL_SCANCODE_BACKSPACE,      GHOST_kKeyBackSpace);
192                         GXMAP(type, SDL_SCANCODE_TAB,            GHOST_kKeyTab);
193                         GXMAP(type, SDL_SCANCODE_RETURN,         GHOST_kKeyEnter);
194                         GXMAP(type, SDL_SCANCODE_ESCAPE,         GHOST_kKeyEsc);
195                         GXMAP(type, SDL_SCANCODE_SPACE,          GHOST_kKeySpace);
196
197                         GXMAP(type, SDL_SCANCODE_SEMICOLON,      GHOST_kKeySemicolon);
198                         GXMAP(type, SDL_SCANCODE_PERIOD,         GHOST_kKeyPeriod);
199                         GXMAP(type, SDL_SCANCODE_COMMA,          GHOST_kKeyComma);
200                         GXMAP(type, SDL_SCANCODE_APOSTROPHE,     GHOST_kKeyQuote);
201                         GXMAP(type, SDL_SCANCODE_GRAVE,          GHOST_kKeyAccentGrave);
202                         GXMAP(type, SDL_SCANCODE_MINUS,          GHOST_kKeyMinus);
203                         GXMAP(type, SDL_SCANCODE_EQUALS,         GHOST_kKeyEqual);
204
205                         GXMAP(type, SDL_SCANCODE_SLASH,          GHOST_kKeySlash);
206                         GXMAP(type, SDL_SCANCODE_BACKSLASH,      GHOST_kKeyBackslash);
207                         GXMAP(type, SDL_SCANCODE_KP_EQUALS,      GHOST_kKeyEqual);
208                         GXMAP(type, SDL_SCANCODE_LEFTBRACKET,    GHOST_kKeyLeftBracket);
209                         GXMAP(type, SDL_SCANCODE_RIGHTBRACKET,   GHOST_kKeyRightBracket);
210                         GXMAP(type, SDL_SCANCODE_PAUSE,          GHOST_kKeyPause);
211
212                         GXMAP(type, SDL_SCANCODE_LSHIFT,         GHOST_kKeyLeftShift);
213                         GXMAP(type, SDL_SCANCODE_RSHIFT,         GHOST_kKeyRightShift);
214                         GXMAP(type, SDL_SCANCODE_LCTRL,          GHOST_kKeyLeftControl);
215                         GXMAP(type, SDL_SCANCODE_RCTRL,          GHOST_kKeyRightControl);
216                         GXMAP(type, SDL_SCANCODE_LALT,           GHOST_kKeyLeftAlt);
217                         GXMAP(type, SDL_SCANCODE_RALT,           GHOST_kKeyRightAlt);
218                         GXMAP(type, SDL_SCANCODE_LGUI,           GHOST_kKeyOS);
219                         GXMAP(type, SDL_SCANCODE_RGUI,           GHOST_kKeyOS);
220
221                         GXMAP(type, SDL_SCANCODE_INSERT,         GHOST_kKeyInsert);
222                         GXMAP(type, SDL_SCANCODE_DELETE,         GHOST_kKeyDelete);
223                         GXMAP(type, SDL_SCANCODE_HOME,           GHOST_kKeyHome);
224                         GXMAP(type, SDL_SCANCODE_END,            GHOST_kKeyEnd);
225                         GXMAP(type, SDL_SCANCODE_PAGEUP,         GHOST_kKeyUpPage);
226                         GXMAP(type, SDL_SCANCODE_PAGEDOWN,       GHOST_kKeyDownPage);
227
228                         GXMAP(type, SDL_SCANCODE_LEFT,           GHOST_kKeyLeftArrow);
229                         GXMAP(type, SDL_SCANCODE_RIGHT,          GHOST_kKeyRightArrow);
230                         GXMAP(type, SDL_SCANCODE_UP,             GHOST_kKeyUpArrow);
231                         GXMAP(type, SDL_SCANCODE_DOWN,           GHOST_kKeyDownArrow);
232
233                         GXMAP(type, SDL_SCANCODE_CAPSLOCK,       GHOST_kKeyCapsLock);
234                         GXMAP(type, SDL_SCANCODE_SCROLLLOCK,     GHOST_kKeyScrollLock);
235                         GXMAP(type, SDL_SCANCODE_NUMLOCKCLEAR,   GHOST_kKeyNumLock);
236                         GXMAP(type, SDL_SCANCODE_PRINTSCREEN,    GHOST_kKeyPrintScreen);
237
238                         /* keypad events */
239
240                         /* note, sdl defines a bunch of kp defines I never saw before like
241                          * SDL_SCANCODE_KP_PERCENT, SDL_SCANCODE_KP_XOR - campbell */
242                         GXMAP(type, SDL_SCANCODE_KP_0,           GHOST_kKeyNumpad0);
243                         GXMAP(type, SDL_SCANCODE_KP_1,           GHOST_kKeyNumpad1);
244                         GXMAP(type, SDL_SCANCODE_KP_2,           GHOST_kKeyNumpad2);
245                         GXMAP(type, SDL_SCANCODE_KP_3,           GHOST_kKeyNumpad3);
246                         GXMAP(type, SDL_SCANCODE_KP_4,           GHOST_kKeyNumpad4);
247                         GXMAP(type, SDL_SCANCODE_KP_5,           GHOST_kKeyNumpad5);
248                         GXMAP(type, SDL_SCANCODE_KP_6,           GHOST_kKeyNumpad6);
249                         GXMAP(type, SDL_SCANCODE_KP_7,           GHOST_kKeyNumpad7);
250                         GXMAP(type, SDL_SCANCODE_KP_8,           GHOST_kKeyNumpad8);
251                         GXMAP(type, SDL_SCANCODE_KP_9,           GHOST_kKeyNumpad9);
252                         GXMAP(type, SDL_SCANCODE_KP_PERIOD,      GHOST_kKeyNumpadPeriod);
253
254                         GXMAP(type, SDL_SCANCODE_KP_ENTER,       GHOST_kKeyNumpadEnter);
255                         GXMAP(type, SDL_SCANCODE_KP_PLUS,        GHOST_kKeyNumpadPlus);
256                         GXMAP(type, SDL_SCANCODE_KP_MINUS,       GHOST_kKeyNumpadMinus);
257                         GXMAP(type, SDL_SCANCODE_KP_MULTIPLY,    GHOST_kKeyNumpadAsterisk);
258                         GXMAP(type, SDL_SCANCODE_KP_DIVIDE,      GHOST_kKeyNumpadSlash);
259
260                         /* Media keys in some keyboards and laptops with XFree86/Xorg */
261                         GXMAP(type, SDL_SCANCODE_AUDIOPLAY,      GHOST_kKeyMediaPlay);
262                         GXMAP(type, SDL_SCANCODE_AUDIOSTOP,      GHOST_kKeyMediaStop);
263                         GXMAP(type, SDL_SCANCODE_AUDIOPREV,      GHOST_kKeyMediaFirst);
264                         // GXMAP(type,XF86XK_AudioRewind,       GHOST_kKeyMediaFirst);
265                         GXMAP(type, SDL_SCANCODE_AUDIONEXT,      GHOST_kKeyMediaLast);
266
267                         default:
268                                 printf("Unknown\n");
269                                 type = GHOST_kKeyUnknown;
270                                 break;
271                 }
272         }
273
274         return type;
275 }
276 #undef GXMAP
277
278 /**
279  * Events don't always have valid windows,
280  * but GHOST needs a window _always_. fallback to the GL window.
281  */
282 static SDL_Window *SDL_GetWindowFromID_fallback(Uint32 id)
283 {
284         SDL_Window *sdl_win = SDL_GetWindowFromID(id);
285         if (sdl_win == NULL) {
286                 sdl_win = SDL_GL_GetCurrentWindow();
287         }
288         return sdl_win;
289 }
290
291 void
292 GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
293 {
294         GHOST_Event *g_event = NULL;
295
296         switch (sdl_event->type) {
297                 case SDL_WINDOWEVENT:
298                 {
299                         SDL_WindowEvent &sdl_sub_evt = sdl_event->window;
300                         GHOST_WindowSDL *window = findGhostWindow(SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
301                         //assert(window != NULL); // can be NULL on close window.
302
303                         switch (sdl_sub_evt.event) {
304                                 case SDL_WINDOWEVENT_EXPOSED:
305                                         g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window);
306                                         break;
307                                 case SDL_WINDOWEVENT_RESIZED:
308                                         g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window);
309                                         break;
310                                 case SDL_WINDOWEVENT_MOVED:
311                                         g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowMove, window);
312                                         break;
313                                 case SDL_WINDOWEVENT_FOCUS_GAINED:
314                                         g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window);
315                                         break;
316                                 case SDL_WINDOWEVENT_FOCUS_LOST:
317                                         g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowDeactivate, window);
318                                         break;
319                                 case SDL_WINDOWEVENT_CLOSE:
320                                         g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, window);
321                                         break;
322                         }
323                 }
324                         break;
325                 case SDL_QUIT:
326                         g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventQuit, NULL);
327                         break;
328
329                 case SDL_MOUSEMOTION:
330                 {
331                         SDL_MouseMotionEvent &sdl_sub_evt = sdl_event->motion;
332                         SDL_Window *sdl_win = SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID);
333                         GHOST_WindowSDL *window = findGhostWindow(sdl_win);
334                         assert(window != NULL);
335
336                         int x_win, y_win;
337                         SDL_GetWindowPosition(sdl_win, &x_win, &y_win);
338
339                         GHOST_TInt32 x_root = sdl_sub_evt.x + x_win;
340                         GHOST_TInt32 y_root = sdl_sub_evt.y + y_win;
341
342 #if 0
343                         if (window->getCursorGrabMode() != GHOST_kGrabDisable && window->getCursorGrabMode() != GHOST_kGrabNormal)
344                         {
345                                 GHOST_TInt32 x_new = x_root;
346                                 GHOST_TInt32 y_new = y_root;
347                                 GHOST_TInt32 x_accum, y_accum;
348                                 GHOST_Rect bounds;
349
350                                 /* fallback to window bounds */
351                                 if (window->getCursorGrabBounds(bounds) == GHOST_kFailure)
352                                         window->getClientBounds(bounds);
353
354                                 /* could also clamp to screen bounds
355                                  * wrap with a window outside the view will fail atm  */
356                                 bounds.wrapPoint(x_new, y_new, 8); /* offset of one incase blender is at screen bounds */
357                                 window->getCursorGrabAccum(x_accum, y_accum);
358
359                                 // cant use setCursorPosition because the mouse may have no focus!
360                                 if (x_new != x_root || y_new != y_root) {
361                                         if (1) {  //xme.time > m_last_warp) {
362                                                 /* when wrapping we don't need to add an event because the
363                                                  * setCursorPosition call will cause a new event after */
364                                                 SDL_WarpMouseInWindow(sdl_win, x_new - x_win, y_new - y_win); /* wrap */
365                                                 window->setCursorGrabAccum(x_accum + (x_root - x_new), y_accum + (y_root - y_new));
366                                                 // m_last_warp= lastEventTime(xme.time);
367                                         }
368                                         else {
369                                                 // setCursorPosition(x_new, y_new); /* wrap but don't accumulate */
370                                                 SDL_WarpMouseInWindow(sdl_win, x_new - x_win, y_new - y_win);
371                                         }
372
373                                         g_event = new GHOST_EventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, x_new, y_new);
374                                 }
375                                 else {
376                                         g_event = new GHOST_EventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, x_root + x_accum, y_root + y_accum);
377                                 }
378                         }
379                         else
380 #endif
381                         {
382                                 g_event = new GHOST_EventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, x_root, y_root);
383                         }
384                         break;
385                 }
386                 case SDL_MOUSEBUTTONUP:
387                 case SDL_MOUSEBUTTONDOWN:
388                 {
389                         SDL_MouseButtonEvent &sdl_sub_evt = sdl_event->button;
390                         GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft;
391                         GHOST_TEventType type = (sdl_sub_evt.state == SDL_PRESSED) ? GHOST_kEventButtonDown : GHOST_kEventButtonUp;
392
393                         GHOST_WindowSDL *window = findGhostWindow(SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
394                         assert(window != NULL);
395
396                         /* process rest of normal mouse buttons */
397                         if (sdl_sub_evt.button == SDL_BUTTON_LEFT)
398                                 gbmask = GHOST_kButtonMaskLeft;
399                         else if (sdl_sub_evt.button == SDL_BUTTON_MIDDLE)
400                                 gbmask = GHOST_kButtonMaskMiddle;
401                         else if (sdl_sub_evt.button == SDL_BUTTON_RIGHT)
402                                 gbmask = GHOST_kButtonMaskRight;
403                         /* these buttons are untested! */
404                         else if (sdl_sub_evt.button == SDL_BUTTON_X1)
405                                 gbmask = GHOST_kButtonMaskButton4;
406                         else if (sdl_sub_evt.button == SDL_BUTTON_X2)
407                                 gbmask = GHOST_kButtonMaskButton5;
408                         else
409                                 break;
410
411                         g_event = new GHOST_EventButton(getMilliSeconds(), type, window, gbmask);
412                         break;
413                 }
414                 case SDL_MOUSEWHEEL:
415                 {
416                         SDL_MouseWheelEvent &sdl_sub_evt = sdl_event->wheel;
417                         GHOST_WindowSDL *window = findGhostWindow(SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
418                         assert(window != NULL);
419                         g_event = new GHOST_EventWheel(getMilliSeconds(), window, sdl_sub_evt.y);
420                 }
421                         break;
422                 case SDL_KEYDOWN:
423                 case SDL_KEYUP:
424                 {
425                         SDL_KeyboardEvent &sdl_sub_evt = sdl_event->key;
426                         SDL_Keycode sym = sdl_sub_evt.keysym.sym;
427                         GHOST_TEventType type = (sdl_sub_evt.state == SDL_PRESSED) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp;
428
429                         GHOST_WindowSDL *window = findGhostWindow(SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
430                         assert(window != NULL);
431
432                         GHOST_TKey gkey = convertSDLKey(sdl_sub_evt.keysym.scancode);
433                         /* note, the sdl_sub_evt.keysym.sym is truncated, for unicode support ghost has to be modified */
434                         /* printf("%d\n", sym); */
435                         if (sym > 127) {
436                                 switch (sym) {
437                                         case SDLK_KP_DIVIDE: sym = '/'; break;
438                                         case SDLK_KP_MULTIPLY: sym = '*'; break;
439                                         case SDLK_KP_MINUS: sym = '-'; break;
440                                         case SDLK_KP_PLUS: sym = '+'; break;
441                                         case SDLK_KP_1: sym = '1'; break;
442                                         case SDLK_KP_2: sym = '2'; break;
443                                         case SDLK_KP_3: sym = '3'; break;
444                                         case SDLK_KP_4: sym = '4'; break;
445                                         case SDLK_KP_5: sym = '5'; break;
446                                         case SDLK_KP_6: sym = '6'; break;
447                                         case SDLK_KP_7: sym = '7'; break;
448                                         case SDLK_KP_8: sym = '8'; break;
449                                         case SDLK_KP_9: sym = '9'; break;
450                                         case SDLK_KP_0: sym = '0'; break;
451                                         case SDLK_KP_PERIOD: sym = '.'; break;
452                                         default: sym = 0; break;
453                                 }
454                         }
455                         else {
456                                 if (sdl_sub_evt.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT)) {
457                                         /* lame US keyboard assumptions */
458                                         if (sym >= 'a' && sym <= ('a' + 32)) {
459                                                 sym -= 32;
460                                         }
461                                         else {
462                                                 switch (sym) {
463                                                         case '`': sym = '~'; break;
464                                                         case '1': sym = '!'; break;
465                                                         case '2': sym = '@'; break;
466                                                         case '3': sym = '#'; break;
467                                                         case '4': sym = '$'; break;
468                                                         case '5': sym = '%'; break;
469                                                         case '6': sym = '^'; break;
470                                                         case '7': sym = '&'; break;
471                                                         case '8': sym = '*'; break;
472                                                         case '9': sym = '('; break;
473                                                         case '0': sym = ')'; break;
474                                                         case '-': sym = '_'; break;
475                                                         case '=': sym = '+'; break;
476                                                         case '[': sym = '{'; break;
477                                                         case ']': sym = '}'; break;
478                                                         case '\\': sym = '|'; break;
479                                                         case ';': sym = ':'; break;
480                                                         case '\'': sym = '"'; break;
481                                                         case ',': sym = '<'; break;
482                                                         case '.': sym = '>'; break;
483                                                         case '/': sym = '?'; break;
484                                                         default:            break;
485                                                 }
486                                         }
487                                 }
488                         }
489
490                         g_event = new GHOST_EventKey(getMilliSeconds(), type, window, gkey, sym, NULL);
491                 }
492                         break;
493         }
494
495         if (g_event) {
496                 pushEvent(g_event);
497         }
498 }
499
500 GHOST_TSuccess
501 GHOST_SystemSDL::getCursorPosition(GHOST_TInt32& x,
502                                    GHOST_TInt32& y) const
503 {
504         int x_win, y_win;
505         SDL_Window *win = SDL_GetMouseFocus();
506         SDL_GetWindowPosition(win, &x_win, &y_win);
507
508         int xi, yi;
509         SDL_GetMouseState(&xi, &yi);
510         x = xi + x_win;
511         y = yi + x_win;
512
513         return GHOST_kSuccess;
514 }
515
516 GHOST_TSuccess
517 GHOST_SystemSDL::setCursorPosition(GHOST_TInt32 x,
518                                    GHOST_TInt32 y)
519 {
520         int x_win, y_win;
521         SDL_Window *win = SDL_GetMouseFocus();
522         SDL_GetWindowPosition(win, &x_win, &y_win);
523
524         SDL_WarpMouseInWindow(win, x - x_win, y - y_win);
525         return GHOST_kSuccess;
526 }
527
528 bool
529 GHOST_SystemSDL::generateWindowExposeEvents()
530 {
531         std::vector<GHOST_WindowSDL *>::iterator w_start = m_dirty_windows.begin();
532         std::vector<GHOST_WindowSDL *>::const_iterator w_end = m_dirty_windows.end();
533         bool anyProcessed = false;
534
535         for (; w_start != w_end; ++w_start) {
536                 GHOST_Event *g_event = new
537                                        GHOST_Event(
538                                            getMilliSeconds(),
539                                            GHOST_kEventWindowUpdate,
540                                            *w_start
541                                            );
542
543                 (*w_start)->validate();
544
545                 if (g_event) {
546                         //printf("Expose events pushed\n");
547                         pushEvent(g_event);
548                         anyProcessed = true;
549                 }
550         }
551
552         m_dirty_windows.clear();
553         return anyProcessed;
554 }
555
556
557 bool
558 GHOST_SystemSDL::processEvents(bool waitForEvent)
559 {
560         // Get all the current events -- translate them into
561         // ghost events and call base class pushEvent() method.
562
563         bool anyProcessed = false;
564
565         do {
566                 GHOST_TimerManager *timerMgr = getTimerManager();
567
568                 if (waitForEvent && m_dirty_windows.empty() && !SDL_HasEvents(SDL_FIRSTEVENT, SDL_LASTEVENT)) {
569                         GHOST_TUns64 next = timerMgr->nextFireTime();
570
571                         if (next == GHOST_kFireTimeNever) {
572                                 SDL_WaitEventTimeout(NULL, -1);
573                                 //SleepTillEvent(m_display, -1);
574                         }
575                         else {
576                                 GHOST_TInt64 maxSleep = next - getMilliSeconds();
577
578                                 if (maxSleep >= 0) {
579                                         SDL_WaitEventTimeout(NULL, next - getMilliSeconds());
580                                         // SleepTillEvent(m_display, next - getMilliSeconds()); // X11
581                                 }
582                         }
583                 }
584
585                 if (timerMgr->fireTimers(getMilliSeconds())) {
586                         anyProcessed = true;
587                 }
588
589                 SDL_Event sdl_event;
590                 while (SDL_PollEvent(&sdl_event)) {
591                         processEvent(&sdl_event);
592                         anyProcessed = true;
593                 }
594
595                 if (generateWindowExposeEvents()) {
596                         anyProcessed = true;
597                 }
598         } while (waitForEvent && !anyProcessed);
599
600         return anyProcessed;
601 }
602
603
604 GHOST_WindowSDL *
605 GHOST_SystemSDL::findGhostWindow(SDL_Window *sdl_win)
606 {
607         if (sdl_win == NULL) return NULL;
608
609         // It is not entirely safe to do this as the backptr may point
610         // to a window that has recently been removed.
611         // We should always check the window manager's list of windows
612         // and only process events on these windows.
613
614         std::vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
615
616         std::vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
617         std::vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
618
619         for (; win_it != win_end; ++win_it) {
620                 GHOST_WindowSDL *window = static_cast<GHOST_WindowSDL *>(*win_it);
621                 if (window->getSDLWindow() == sdl_win) {
622                         return window;
623                 }
624         }
625         return NULL;
626 }
627
628
629 void
630 GHOST_SystemSDL::addDirtyWindow(GHOST_WindowSDL *bad_wind)
631 {
632         GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
633
634         m_dirty_windows.push_back(bad_wind);
635 }
636
637
638 GHOST_TSuccess GHOST_SystemSDL::getButtons(GHOST_Buttons& buttons) const
639 {
640         Uint8 state = SDL_GetMouseState(NULL, NULL);
641         buttons.set(GHOST_kButtonMaskLeft,   (state & SDL_BUTTON_LMASK) != 0);
642         buttons.set(GHOST_kButtonMaskMiddle, (state & SDL_BUTTON_MMASK) != 0);
643         buttons.set(GHOST_kButtonMaskRight,  (state & SDL_BUTTON_RMASK) != 0);
644
645         return GHOST_kSuccess;
646 }
647
648 GHOST_TUns8 *
649 GHOST_SystemSDL::getClipboard(bool selection) const
650 {
651         return (GHOST_TUns8 *)SDL_GetClipboardText();
652 }
653
654 void
655 GHOST_SystemSDL::putClipboard(GHOST_TInt8 *buffer, bool selection) const
656 {
657         SDL_SetClipboardText(buffer);
658 }
659
660 GHOST_TUns64
661 GHOST_SystemSDL::getMilliSeconds()
662 {
663         return GHOST_TUns64(SDL_GetTicks()); /* note, 32 -> 64bits */
664 }