ClangFormat: apply to source, most of 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 && window->getCursorGrabMode() != GHOST_kGrabNormal)
364       {
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(getMilliSeconds(), GHOST_kEventCursorMove, window, x_new, y_new);
394         }
395         else {
396           g_event = new GHOST_EventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, x_root + x_accum, y_root + y_accum);
397         }
398       }
399       else
400 #endif
401       {
402         g_event = new GHOST_EventCursor(
403             getMilliSeconds(), GHOST_kEventCursorMove, window, x_root, y_root);
404       }
405       break;
406     }
407     case SDL_MOUSEBUTTONUP:
408     case SDL_MOUSEBUTTONDOWN: {
409       SDL_MouseButtonEvent &sdl_sub_evt = sdl_event->button;
410       GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft;
411       GHOST_TEventType type = (sdl_sub_evt.state == SDL_PRESSED) ? GHOST_kEventButtonDown :
412                                                                    GHOST_kEventButtonUp;
413
414       GHOST_WindowSDL *window = findGhostWindow(
415           SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
416       assert(window != NULL);
417
418       /* process rest of normal mouse buttons */
419       if (sdl_sub_evt.button == SDL_BUTTON_LEFT)
420         gbmask = GHOST_kButtonMaskLeft;
421       else if (sdl_sub_evt.button == SDL_BUTTON_MIDDLE)
422         gbmask = GHOST_kButtonMaskMiddle;
423       else if (sdl_sub_evt.button == SDL_BUTTON_RIGHT)
424         gbmask = GHOST_kButtonMaskRight;
425       /* these buttons are untested! */
426       else if (sdl_sub_evt.button == SDL_BUTTON_X1)
427         gbmask = GHOST_kButtonMaskButton4;
428       else if (sdl_sub_evt.button == SDL_BUTTON_X2)
429         gbmask = GHOST_kButtonMaskButton5;
430       else
431         break;
432
433       g_event = new GHOST_EventButton(getMilliSeconds(), type, window, gbmask);
434       break;
435     }
436     case SDL_MOUSEWHEEL: {
437       SDL_MouseWheelEvent &sdl_sub_evt = sdl_event->wheel;
438       GHOST_WindowSDL *window = findGhostWindow(
439           SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
440       assert(window != NULL);
441       g_event = new GHOST_EventWheel(getMilliSeconds(), window, sdl_sub_evt.y);
442       break;
443     }
444     case SDL_KEYDOWN:
445     case SDL_KEYUP: {
446       SDL_KeyboardEvent &sdl_sub_evt = sdl_event->key;
447       SDL_Keycode sym = sdl_sub_evt.keysym.sym;
448       GHOST_TEventType type = (sdl_sub_evt.state == SDL_PRESSED) ? GHOST_kEventKeyDown :
449                                                                    GHOST_kEventKeyUp;
450
451       GHOST_WindowSDL *window = findGhostWindow(
452           SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
453       assert(window != NULL);
454
455       GHOST_TKey gkey = convertSDLKey(sdl_sub_evt.keysym.scancode);
456       /* note, the sdl_sub_evt.keysym.sym is truncated, for unicode support ghost has to be modified */
457       /* printf("%d\n", sym); */
458       if (sym > 127) {
459         switch (sym) {
460           case SDLK_KP_DIVIDE:
461             sym = '/';
462             break;
463           case SDLK_KP_MULTIPLY:
464             sym = '*';
465             break;
466           case SDLK_KP_MINUS:
467             sym = '-';
468             break;
469           case SDLK_KP_PLUS:
470             sym = '+';
471             break;
472           case SDLK_KP_1:
473             sym = '1';
474             break;
475           case SDLK_KP_2:
476             sym = '2';
477             break;
478           case SDLK_KP_3:
479             sym = '3';
480             break;
481           case SDLK_KP_4:
482             sym = '4';
483             break;
484           case SDLK_KP_5:
485             sym = '5';
486             break;
487           case SDLK_KP_6:
488             sym = '6';
489             break;
490           case SDLK_KP_7:
491             sym = '7';
492             break;
493           case SDLK_KP_8:
494             sym = '8';
495             break;
496           case SDLK_KP_9:
497             sym = '9';
498             break;
499           case SDLK_KP_0:
500             sym = '0';
501             break;
502           case SDLK_KP_PERIOD:
503             sym = '.';
504             break;
505           default:
506             sym = 0;
507             break;
508         }
509       }
510       else {
511         if (sdl_sub_evt.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT)) {
512           /* lame US keyboard assumptions */
513           if (sym >= 'a' && sym <= ('a' + 32)) {
514             sym -= 32;
515           }
516           else {
517             switch (sym) {
518               case '`':
519                 sym = '~';
520                 break;
521               case '1':
522                 sym = '!';
523                 break;
524               case '2':
525                 sym = '@';
526                 break;
527               case '3':
528                 sym = '#';
529                 break;
530               case '4':
531                 sym = '$';
532                 break;
533               case '5':
534                 sym = '%';
535                 break;
536               case '6':
537                 sym = '^';
538                 break;
539               case '7':
540                 sym = '&';
541                 break;
542               case '8':
543                 sym = '*';
544                 break;
545               case '9':
546                 sym = '(';
547                 break;
548               case '0':
549                 sym = ')';
550                 break;
551               case '-':
552                 sym = '_';
553                 break;
554               case '=':
555                 sym = '+';
556                 break;
557               case '[':
558                 sym = '{';
559                 break;
560               case ']':
561                 sym = '}';
562                 break;
563               case '\\':
564                 sym = '|';
565                 break;
566               case ';':
567                 sym = ':';
568                 break;
569               case '\'':
570                 sym = '"';
571                 break;
572               case ',':
573                 sym = '<';
574                 break;
575               case '.':
576                 sym = '>';
577                 break;
578               case '/':
579                 sym = '?';
580                 break;
581               default:
582                 break;
583             }
584           }
585         }
586       }
587
588       g_event = new GHOST_EventKey(getMilliSeconds(), type, window, gkey, sym, NULL);
589       break;
590     }
591   }
592
593   if (g_event) {
594     pushEvent(g_event);
595   }
596 }
597
598 GHOST_TSuccess GHOST_SystemSDL::getCursorPosition(GHOST_TInt32 &x, GHOST_TInt32 &y) const
599 {
600   int x_win, y_win;
601   SDL_Window *win = SDL_GetMouseFocus();
602   SDL_GetWindowPosition(win, &x_win, &y_win);
603
604   int xi, yi;
605   SDL_GetMouseState(&xi, &yi);
606   x = xi + x_win;
607   y = yi + x_win;
608
609   return GHOST_kSuccess;
610 }
611
612 GHOST_TSuccess GHOST_SystemSDL::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y)
613 {
614   int x_win, y_win;
615   SDL_Window *win = SDL_GetMouseFocus();
616   SDL_GetWindowPosition(win, &x_win, &y_win);
617
618   SDL_WarpMouseInWindow(win, x - x_win, y - y_win);
619   return GHOST_kSuccess;
620 }
621
622 bool GHOST_SystemSDL::generateWindowExposeEvents()
623 {
624   std::vector<GHOST_WindowSDL *>::iterator w_start = m_dirty_windows.begin();
625   std::vector<GHOST_WindowSDL *>::const_iterator w_end = m_dirty_windows.end();
626   bool anyProcessed = false;
627
628   for (; w_start != w_end; ++w_start) {
629     GHOST_Event *g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, *w_start);
630
631     (*w_start)->validate();
632
633     if (g_event) {
634       //printf("Expose events pushed\n");
635       pushEvent(g_event);
636       anyProcessed = true;
637     }
638   }
639
640   m_dirty_windows.clear();
641   return anyProcessed;
642 }
643
644 bool GHOST_SystemSDL::processEvents(bool waitForEvent)
645 {
646   // Get all the current events -- translate them into
647   // ghost events and call base class pushEvent() method.
648
649   bool anyProcessed = false;
650
651   do {
652     GHOST_TimerManager *timerMgr = getTimerManager();
653
654     if (waitForEvent && m_dirty_windows.empty() && !SDL_HasEvents(SDL_FIRSTEVENT, SDL_LASTEVENT)) {
655       GHOST_TUns64 next = timerMgr->nextFireTime();
656
657       if (next == GHOST_kFireTimeNever) {
658         SDL_WaitEventTimeout(NULL, -1);
659         //SleepTillEvent(m_display, -1);
660       }
661       else {
662         GHOST_TInt64 maxSleep = next - getMilliSeconds();
663
664         if (maxSleep >= 0) {
665           SDL_WaitEventTimeout(NULL, next - getMilliSeconds());
666           // SleepTillEvent(m_display, next - getMilliSeconds()); // X11
667         }
668       }
669     }
670
671     if (timerMgr->fireTimers(getMilliSeconds())) {
672       anyProcessed = true;
673     }
674
675     SDL_Event sdl_event;
676     while (SDL_PollEvent(&sdl_event)) {
677       processEvent(&sdl_event);
678       anyProcessed = true;
679     }
680
681     if (generateWindowExposeEvents()) {
682       anyProcessed = true;
683     }
684   } while (waitForEvent && !anyProcessed);
685
686   return anyProcessed;
687 }
688
689 GHOST_WindowSDL *GHOST_SystemSDL::findGhostWindow(SDL_Window *sdl_win)
690 {
691   if (sdl_win == NULL)
692     return NULL;
693
694   // It is not entirely safe to do this as the backptr may point
695   // to a window that has recently been removed.
696   // We should always check the window manager's list of windows
697   // and only process events on these windows.
698
699   std::vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
700
701   std::vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
702   std::vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
703
704   for (; win_it != win_end; ++win_it) {
705     GHOST_WindowSDL *window = static_cast<GHOST_WindowSDL *>(*win_it);
706     if (window->getSDLWindow() == sdl_win) {
707       return window;
708     }
709   }
710   return NULL;
711 }
712
713 void GHOST_SystemSDL::addDirtyWindow(GHOST_WindowSDL *bad_wind)
714 {
715   GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
716
717   m_dirty_windows.push_back(bad_wind);
718 }
719
720 bool GHOST_SystemSDL::supportsNativeDialogs(void)
721 {
722   return false;
723 }
724
725 GHOST_TSuccess GHOST_SystemSDL::getButtons(GHOST_Buttons &buttons) const
726 {
727   Uint8 state = SDL_GetMouseState(NULL, NULL);
728   buttons.set(GHOST_kButtonMaskLeft, (state & SDL_BUTTON_LMASK) != 0);
729   buttons.set(GHOST_kButtonMaskMiddle, (state & SDL_BUTTON_MMASK) != 0);
730   buttons.set(GHOST_kButtonMaskRight, (state & SDL_BUTTON_RMASK) != 0);
731
732   return GHOST_kSuccess;
733 }
734
735 GHOST_TUns8 *GHOST_SystemSDL::getClipboard(bool selection) const
736 {
737   return (GHOST_TUns8 *)SDL_GetClipboardText();
738 }
739
740 void GHOST_SystemSDL::putClipboard(GHOST_TInt8 *buffer, bool selection) const
741 {
742   SDL_SetClipboardText(buffer);
743 }
744
745 GHOST_TUns64 GHOST_SystemSDL::getMilliSeconds()
746 {
747   return GHOST_TUns64(SDL_GetTicks()); /* note, 32 -> 64bits */
748 }