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