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