commiting fixes from Ettore for building on linux & win 32
[blender.git] / intern / ghost / intern / GHOST_SystemX11.cpp
1 /**
2  * $Id$
3  * ***** BEGIN GPL/BL DUAL 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. The Blender
9  * Foundation also sells licenses for use in proprietary software under
10  * the Blender License.  See http://www.blender.org/BL/ for information
11  * about this.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30  */
31
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35
36 #include "GHOST_SystemX11.h"
37 #include "GHOST_WindowX11.h"
38 #include "GHOST_WindowManager.h"
39 #include "GHOST_TimerManager.h"
40 #include "GHOST_EventCursor.h"
41 #include "GHOST_EventKey.h"
42 #include "GHOST_EventButton.h"
43 #include "GHOST_EventWheel.h"
44 #include "GHOST_EventNDOF.h"
45 #include "GHOST_NDOFManager.h"
46 #include "GHOST_DisplayManagerX11.h"
47
48 #include "GHOST_Debug.h"
49
50 #include <X11/Xatom.h>
51 #include <X11/keysym.h>
52
53 #ifdef __sgi
54
55 #if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS)
56 #include <X11/SGIFastAtom.h>
57 #else
58 #define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how)
59 #endif
60
61 #endif
62
63 // For timing
64
65 #include <sys/time.h>
66 #include <unistd.h>
67
68 #include <vector>
69
70 typedef struct NDOFPlatformInfo {
71         Display *display;
72         Window window;
73         volatile GHOST_TEventNDOFData *currValues;
74 } NDOFPlatformInfo;
75
76 static NDOFPlatformInfo sNdofInfo = {NULL, 0, NULL};
77
78 using namespace std;
79
80 GHOST_SystemX11::
81 GHOST_SystemX11(
82 ) : 
83         GHOST_System(),
84         m_start_time(0)
85 {
86         m_display = XOpenDisplay(NULL);
87         
88         if (!m_display) return;
89         
90 #ifdef __sgi
91         m_delete_window_atom 
92           = XSGIFastInternAtom(m_display,
93                                "WM_DELETE_WINDOW", 
94                                SGI_XA_WM_DELETE_WINDOW, False);
95 #else
96         m_delete_window_atom 
97           = XInternAtom(m_display, "WM_DELETE_WINDOW", True);
98 #endif
99
100         // compute the initial time
101         timeval tv;
102         if (gettimeofday(&tv,NULL) == -1) {
103                 GHOST_ASSERT(false,"Could not instantiate timer!");
104         }
105
106         m_start_time = GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000);
107 }
108
109         GHOST_TSuccess 
110 GHOST_SystemX11::
111 init(
112 ){
113         GHOST_TSuccess success = GHOST_System::init();
114
115         if (success) {
116                 m_keyboard_vector = new char[32];
117
118                 m_displayManager = new GHOST_DisplayManagerX11(this);
119
120                 if (m_keyboard_vector && m_displayManager) {
121                         return GHOST_kSuccess;
122                 }
123         }
124
125         return GHOST_kFailure;
126 }
127
128         GHOST_TUns64
129 GHOST_SystemX11::
130 getMilliSeconds(
131 ) const {
132         timeval tv;
133         if (gettimeofday(&tv,NULL) == -1) {
134                 GHOST_ASSERT(false,"Could not compute time!");
135         }
136
137         return  GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000) - m_start_time;
138 }
139         
140         GHOST_TUns8 
141 GHOST_SystemX11::
142 getNumDisplays(
143 ) const {
144         return GHOST_TUns8(1);
145 }
146
147         /**
148          * Returns the dimensions of the main display on this system.
149          * @return The dimension of the main display.
150          */
151         void 
152 GHOST_SystemX11::
153 getMainDisplayDimensions(
154         GHOST_TUns32& width,
155         GHOST_TUns32& height
156 ) const {       
157         if (m_display) {
158                 width  = DisplayWidth(m_display, DefaultScreen(m_display));
159                 height = DisplayHeight(m_display, DefaultScreen(m_display));
160         }
161 }
162
163         /**
164          * Create a new window.
165          * The new window is added to the list of windows managed.
166          * Never explicitly delete the window, use disposeWindow() instead.
167          * @param       title   The name of the window (displayed in the title bar of the window if the OS supports it).
168          * @param       left    The coordinate of the left edge of the window.
169          * @param       top             The coordinate of the top edge of the window.
170          * @param       width   The width the window.
171          * @param       height  The height the window.
172          * @param       state   The state of the window when opened.
173          * @param       type    The type of drawing context installed in this window.
174          * @return      The new window (or 0 if creation failed).
175          */
176         GHOST_IWindow* 
177 GHOST_SystemX11::
178 createWindow(
179         const STR_String& title,
180         GHOST_TInt32 left,
181         GHOST_TInt32 top,
182         GHOST_TUns32 width,
183         GHOST_TUns32 height,
184         GHOST_TWindowState state,
185         GHOST_TDrawingContextType type,
186         bool stereoVisual
187 ){
188         GHOST_WindowX11 * window = 0;
189         
190         if (!m_display) return 0;
191         
192         window = new GHOST_WindowX11 (
193                 this,m_display,title, left, top, width, height, state, type, stereoVisual
194         );
195
196         if (window) {
197
198                 // Install a new protocol for this window - so we can overide
199                 // the default window closure mechanism.
200
201                 XSetWMProtocols(m_display, window->getXWindow(), &m_delete_window_atom, 1);
202
203                 if (window->getValid()) {
204                         // Store the pointer to the window 
205                         m_windowManager->addWindow(window);
206                         
207                         pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) );
208                 }
209                 else {
210                         delete window;
211                         window = 0;
212                 }
213         }
214         return window;
215 }
216
217         GHOST_WindowX11 * 
218 GHOST_SystemX11::
219 findGhostWindow(
220         Window xwind
221 ) const {
222         
223         if (xwind == 0) return NULL;
224
225         // It is not entirely safe to do this as the backptr may point
226         // to a window that has recently been removed. 
227         // We should always check the window manager's list of windows 
228         // and only process events on these windows.
229
230         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
231
232         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
233         vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
234         
235         for (; win_it != win_end; ++win_it) {
236                 GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
237                 if (window->getXWindow() == xwind) {
238                         return window;
239                 }
240         }
241         return NULL;
242         
243 }
244
245 static void SleepTillEvent(Display *display, GHOST_TInt64 maxSleep) {
246         int fd = ConnectionNumber(display);
247         fd_set fds;
248         
249         FD_ZERO(&fds);
250         FD_SET(fd, &fds);
251
252         if (maxSleep == -1) {
253             select(fd + 1, &fds, NULL, NULL, NULL);
254         } else {
255                 timeval tv;
256
257                 tv.tv_sec = maxSleep/1000;
258                 tv.tv_usec = (maxSleep - tv.tv_sec*1000)*1000;
259         
260             select(fd + 1, &fds, NULL, NULL, &tv);
261         }
262 }
263
264         bool 
265 GHOST_SystemX11::
266 processEvents(
267         bool waitForEvent
268 ){
269         // Get all the current events -- translate them into 
270         // ghost events and call base class pushEvent() method.
271         
272         bool anyProcessed = false;
273         
274         do {
275                 GHOST_TimerManager* timerMgr = getTimerManager();
276                 
277                 if (waitForEvent && m_dirty_windows.empty() && !XPending(m_display)) {
278                         GHOST_TUns64 next = timerMgr->nextFireTime();
279                         
280                         if (next==GHOST_kFireTimeNever) {
281                                 SleepTillEvent(m_display, -1);
282                         } else {
283                                 SleepTillEvent(m_display, next - getMilliSeconds());
284                         }
285                 }
286                 
287                 if (timerMgr->fireTimers(getMilliSeconds())) {
288                         anyProcessed = true;
289                 }
290                 
291                 while (XPending(m_display)) {
292                         XEvent xevent;
293                         XNextEvent(m_display, &xevent);
294                         processEvent(&xevent);
295                         anyProcessed = true;
296                 }
297                 
298                 if (generateWindowExposeEvents()) {
299                         anyProcessed = true;
300                 }
301         } while (waitForEvent && !anyProcessed);
302         
303         return anyProcessed;
304 }
305
306         void
307 GHOST_SystemX11::processEvent(XEvent *xe)
308 {
309         GHOST_WindowX11 * window = findGhostWindow(xe->xany.window);    
310         GHOST_Event * g_event = NULL;
311
312         if (!window) {
313                 return;
314         }
315
316         switch (xe->type) {
317                 case Expose:
318                 {
319                         XExposeEvent & xee = xe->xexpose;
320
321                         if (xee.count == 0) {
322                                 // Only generate a single expose event
323                                 // per read of the event queue.
324
325                                 g_event = new 
326                                 GHOST_Event(
327                                         getMilliSeconds(),
328                                         GHOST_kEventWindowUpdate,
329                                         window
330                                 );                      
331                         }
332                         break;
333                 }
334
335                 case MotionNotify:
336                 {
337                         XMotionEvent &xme = xe->xmotion;
338                         
339                         g_event = new 
340                         GHOST_EventCursor(
341                                 getMilliSeconds(),
342                                 GHOST_kEventCursorMove,
343                                 window,
344                                 xme.x_root,
345                                 xme.y_root
346                         );
347                         break;
348                 }
349
350                 case KeyPress:
351                 case KeyRelease:
352                 {
353                         XKeyEvent *xke = &(xe->xkey);
354                 
355                         KeySym key_sym = XLookupKeysym(xke,0);
356                         char ascii;
357                         
358                         GHOST_TKey gkey = convertXKey(key_sym);
359                         GHOST_TEventType type = (xke->type == KeyPress) ? 
360                                 GHOST_kEventKeyDown : GHOST_kEventKeyUp;
361                         
362                         if (!XLookupString(xke, &ascii, 1, NULL, NULL)) {
363                                 ascii = '\0';
364                         }
365                         
366                         g_event = new
367                         GHOST_EventKey(
368                                 getMilliSeconds(),
369                                 type,
370                                 window,
371                                 gkey,
372                                 ascii
373                         );
374                         
375                 break;
376                 }
377
378                 case ButtonPress:
379                 {
380                         /* process wheel mouse events and break */
381                         if (xe->xbutton.button == 4) {
382                                 g_event = new GHOST_EventWheel(getMilliSeconds(), window, 1);
383                                 break;
384                         }
385                         if (xe->xbutton.button == 5) {
386                                 g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1);
387                                 break;
388                         }
389                 }
390                 case ButtonRelease:
391                 {
392
393                         XButtonEvent & xbe = xe->xbutton;
394                         GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft;
395
396                         switch (xbe.button) {
397                                 case Button1 : gbmask = GHOST_kButtonMaskLeft; break;
398                                 case Button3 : gbmask = GHOST_kButtonMaskRight; break;
399                                 default:
400                                 case Button2 : gbmask = GHOST_kButtonMaskMiddle; break;
401                         }
402                         
403                         GHOST_TEventType type = (xbe.type == ButtonPress) ? 
404                                 GHOST_kEventButtonDown : GHOST_kEventButtonUp;
405                         
406                         g_event = new
407                         GHOST_EventButton(
408                                 getMilliSeconds(),
409                                 type,
410                                 window,
411                                 gbmask
412                         );
413                         break;
414                 }
415                         
416                         // change of size, border, layer etc.
417                 case ConfigureNotify:
418                 {
419                         /* XConfigureEvent & xce = xe->xconfigure; */
420
421                         g_event = new 
422                         GHOST_Event(
423                                 getMilliSeconds(),
424                                 GHOST_kEventWindowSize,
425                                 window
426                         );                      
427                         break;
428                 }
429
430                 case FocusIn:
431                 case FocusOut:
432                 {
433                         XFocusChangeEvent &xfe = xe->xfocus;
434                 
435                         // May have to look at the type of event and filter some
436                         // out.
437                                                                         
438                         GHOST_TEventType gtype = (xfe.type == FocusIn) ? 
439                                 GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate;
440
441                         g_event = new 
442                         GHOST_Event(    
443                                 getMilliSeconds(),
444                                 gtype,
445                                 window
446                         );
447                         break;
448
449                 }
450                 case ClientMessage:
451                 {
452                         XClientMessageEvent & xcme = xe->xclient;
453
454 #ifndef __sgi                   
455                         if (xcme.data.l[0] == m_delete_window_atom) {
456                                 g_event = new 
457                                 GHOST_Event(    
458                                         getMilliSeconds(),
459                                         GHOST_kEventWindowClose,
460                                         window
461                                 );
462                         } else 
463 #endif
464                         if (sNdofInfo.currValues) {
465                                 sNdofInfo.currValues->changed = 1;
466                                 sNdofInfo.currValues->delta = xcme.data.s[8] - sNdofInfo.currValues->time;
467                                 sNdofInfo.currValues->time = xcme.data.s[8];
468                                 sNdofInfo.currValues->tx = xcme.data.s[2] >> 4;
469                                 sNdofInfo.currValues->ty = xcme.data.s[3] >> 4;
470                                 sNdofInfo.currValues->tz = xcme.data.s[4] >> 4;
471                                 sNdofInfo.currValues->rx = xcme.data.s[5];
472                                 sNdofInfo.currValues->ry = xcme.data.s[6];
473                                 sNdofInfo.currValues->rz = xcme.data.s[7];
474
475                                 /*fprintf(stderr, "ClientMessage: [%d %d %d][%d %d %d] t=%llu\n",
476                                         sNdofInfo.currValues->tx, sNdofInfo.currValues->ty, 
477                                         sNdofInfo.currValues->tz, sNdofInfo.currValues->rx, 
478                                         sNdofInfo.currValues->ry, sNdofInfo.currValues->rz, 
479                                                 sNdofInfo.currValues->time); */
480                                 
481                                 g_event = new GHOST_EventNDOF(getMilliSeconds(), 
482                                                               GHOST_kEventNDOFMotion, 
483                                                               window, *sNdofInfo.currValues);
484                         } else {
485                                 /* Unknown client message, ignore */
486                         }
487                         break;
488                 }
489                         
490                 // We're not interested in the following things.(yet...)
491                 case NoExpose : 
492                 case GraphicsExpose :
493                 
494                 case EnterNotify:
495                 case LeaveNotify:
496                         // XCrossingEvents pointer leave enter window.
497                         break;
498                 case MapNotify:
499                 case UnmapNotify:
500                         break;
501                 case MappingNotify:
502                 case ReparentNotify:
503                         break;
504
505         default: {
506                         if(xe->type == window->GetXTablet().MotionEvent) 
507                         {
508                                 XDeviceMotionEvent* data = (XDeviceMotionEvent*)xe;
509                                 window->GetXTablet().CommonData.Pressure= 
510                                         data->axis_data[2]/((float)window->GetXTablet().PressureLevels);
511                         
512                         /* the (short) cast and the &0xffff is bizarre and unexplained anywhere,
513                          * but I got garbage data without it. Found it in the xidump.c source --matt */
514                                 window->GetXTablet().CommonData.Xtilt= 
515                                         (short)(data->axis_data[3]&0xffff)/((float)window->GetXTablet().XtiltLevels);
516                                 window->GetXTablet().CommonData.Ytilt= 
517                                         (short)(data->axis_data[4]&0xffff)/((float)window->GetXTablet().YtiltLevels);
518                         }
519                         else if(xe->type == window->GetXTablet().ProxInEvent) 
520                         {
521                                 XProximityNotifyEvent* data = (XProximityNotifyEvent*)xe;
522                                 if(data->deviceid == window->GetXTablet().StylusID)
523                                         window->GetXTablet().CommonData.Active= 1;
524                                 else if(data->deviceid == window->GetXTablet().EraserID)
525                                         window->GetXTablet().CommonData.Active= 2;
526                         }
527                         else if(xe->type == window->GetXTablet().ProxOutEvent)
528                                 window->GetXTablet().CommonData.Active= 0;
529
530                         break;
531                 }
532         }
533
534         if (g_event) {
535                 pushEvent(g_event);
536         }
537 }
538
539         void *
540 GHOST_SystemX11::
541 prepareNdofInfo(volatile GHOST_TEventNDOFData *currentNdofValues)
542 {
543         const vector<GHOST_IWindow*>& v(m_windowManager->getWindows());
544         if (v.size() > 0)
545                 sNdofInfo.window = static_cast<GHOST_WindowX11*>(v[0])->getXWindow();
546         sNdofInfo.display = m_display;
547         sNdofInfo.currValues = currentNdofValues;
548         return (void*)&sNdofInfo;
549 }
550
551         GHOST_TSuccess 
552 GHOST_SystemX11::
553 getModifierKeys(
554         GHOST_ModifierKeys& keys
555 ) const {
556
557         // analyse the masks retuned from XQueryPointer.
558
559         memset(m_keyboard_vector,0,sizeof(m_keyboard_vector));
560
561         XQueryKeymap(m_display,m_keyboard_vector);
562
563         // now translate key symobols into keycodes and
564         // test with vector.
565
566         const KeyCode shift_l = XKeysymToKeycode(m_display,XK_Shift_L);
567         const KeyCode shift_r = XKeysymToKeycode(m_display,XK_Shift_R);
568         const KeyCode control_l = XKeysymToKeycode(m_display,XK_Control_L);
569         const KeyCode control_r = XKeysymToKeycode(m_display,XK_Control_R);
570         const KeyCode alt_l = XKeysymToKeycode(m_display,XK_Alt_L);
571         const KeyCode alt_r = XKeysymToKeycode(m_display,XK_Alt_R);
572
573         // Shift
574         if ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) {
575                 keys.set(GHOST_kModifierKeyLeftShift,true);
576         } else {
577                 keys.set(GHOST_kModifierKeyLeftShift,false);
578         }
579         if ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) {
580
581                 keys.set(GHOST_kModifierKeyRightShift,true);
582         } else {
583                 keys.set(GHOST_kModifierKeyRightShift,false);
584         }
585
586         // control (weep)
587         if ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) {
588                 keys.set(GHOST_kModifierKeyLeftControl,true);
589         } else {
590                 keys.set(GHOST_kModifierKeyLeftControl,false);
591         }
592         if ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) {
593                 keys.set(GHOST_kModifierKeyRightControl,true);
594         } else {
595                 keys.set(GHOST_kModifierKeyRightControl,false);
596         }
597
598         // Alt (yawn)
599         if ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) {
600                 keys.set(GHOST_kModifierKeyLeftAlt,true);
601         } else {
602                 keys.set(GHOST_kModifierKeyLeftAlt,false);
603         }       
604         if ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) {
605                 keys.set(GHOST_kModifierKeyRightAlt,true);
606         } else {
607                 keys.set(GHOST_kModifierKeyRightAlt,false);
608         }
609         return GHOST_kSuccess;
610 }
611
612         GHOST_TSuccess 
613 GHOST_SystemX11::
614 getButtons(
615         GHOST_Buttons& buttons
616 ) const {
617
618         Window root_return, child_return;
619         int rx,ry,wx,wy;
620         unsigned int mask_return;
621
622         if (XQueryPointer(
623                 m_display,
624                 RootWindow(m_display,DefaultScreen(m_display)),
625                 &root_return,
626                 &child_return,
627                 &rx,&ry,
628                 &wx,&wy,
629                 &mask_return
630         ) == False) {
631                 return GHOST_kFailure;
632         } else {
633
634                 if (mask_return & Button1Mask) {
635                         buttons.set(GHOST_kButtonMaskLeft,true);
636                 } else {
637                         buttons.set(GHOST_kButtonMaskLeft,false);
638                 }
639
640                 if (mask_return & Button2Mask) {
641                         buttons.set(GHOST_kButtonMaskMiddle,true);
642                 } else {
643                         buttons.set(GHOST_kButtonMaskMiddle,false);
644                 }
645
646                 if (mask_return & Button3Mask) {
647                         buttons.set(GHOST_kButtonMaskRight,true);
648                 } else {
649                         buttons.set(GHOST_kButtonMaskRight,false);
650                 }
651         }       
652
653         return GHOST_kSuccess;
654 }
655
656
657         GHOST_TSuccess 
658 GHOST_SystemX11::
659 getCursorPosition(
660         GHOST_TInt32& x,
661         GHOST_TInt32& y
662 ) const {
663
664         Window root_return, child_return;
665         int rx,ry,wx,wy;
666         unsigned int mask_return;
667
668         if (XQueryPointer(
669                 m_display,
670                 RootWindow(m_display,DefaultScreen(m_display)),
671                 &root_return,
672                 &child_return,
673                 &rx,&ry,
674                 &wx,&wy,
675                 &mask_return
676         ) == False) {
677                 return GHOST_kFailure;
678         } else {
679                 x = rx;
680                 y = ry;
681         }       
682         return GHOST_kSuccess;
683 }
684
685
686         GHOST_TSuccess 
687 GHOST_SystemX11::
688 setCursorPosition(
689         GHOST_TInt32 x,
690         GHOST_TInt32 y
691 ) const {
692
693         // This is a brute force move in screen coordinates
694         // XWarpPointer does relative moves so first determine the
695         // current pointer position.
696
697         int cx,cy;
698         if (getCursorPosition(cx,cy) == GHOST_kFailure) {
699                 return GHOST_kFailure;
700         }
701
702         int relx = x-cx;
703         int rely = y-cy;
704
705         XWarpPointer(m_display,None,None,0,0,0,0,relx,rely);
706         XFlush(m_display);
707         
708         return GHOST_kSuccess;
709 }
710
711
712         void
713 GHOST_SystemX11::
714 addDirtyWindow(
715         GHOST_WindowX11 * bad_wind
716 ){
717
718         GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
719         
720         m_dirty_windows.push_back(bad_wind);
721 }
722
723
724         bool
725 GHOST_SystemX11::
726 generateWindowExposeEvents(
727 ){
728
729         vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin();
730         vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end();
731         bool anyProcessed = false;
732         
733         for (;w_start != w_end; ++w_start) {
734                 GHOST_Event * g_event = new 
735                         GHOST_Event(
736                                 getMilliSeconds(),
737                                 GHOST_kEventWindowUpdate,
738                                 *w_start
739                         );                      
740
741                 (*w_start)->validate(); 
742                 
743                 if (g_event) {
744                         pushEvent(g_event);
745                         anyProcessed = true;
746                 }
747         }
748
749         m_dirty_windows.clear();
750         return anyProcessed;
751 }
752
753 #define GXMAP(k,x,y) case x: k = y; break; 
754
755         GHOST_TKey
756 GHOST_SystemX11::
757 convertXKey(
758         KeySym key
759 ){
760         GHOST_TKey type;
761
762         if ((key >= XK_A) && (key <= XK_Z)) {
763                 type = GHOST_TKey( key - XK_A + int(GHOST_kKeyA));
764         } else if ((key >= XK_a) && (key <= XK_z)) {
765                 type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA));
766         } else if ((key >= XK_0) && (key <= XK_9)) {
767                 type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0));
768         } else if ((key >= XK_F1) && (key <= XK_F24)) {
769                 type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1));
770 #if defined(__sun) || defined(__sun__) 
771                 /* This is a bit of a hack, but it looks like sun
772                    Used F11 and friends for its special keys Stop,again etc..
773                    So this little patch enables F11 and F12 to work as expected
774                    following link has documentation on it: 
775                    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4734408
776                    also from /usr/include/X11/Sunkeysym.h 
777 #define SunXK_F36               0x1005FF10      // Labeled F11
778 #define SunXK_F37               0x1005FF11      // Labeled F12 
779
780                                 mein@cs.umn.edu
781                  */
782                 
783         } else if (key == 268828432) {
784                 type = GHOST_kKeyF11;
785         } else if (key == 268828433) {
786                 type = GHOST_kKeyF12;
787 #endif
788         } else {
789                 switch(key) {
790                         GXMAP(type,XK_BackSpace,        GHOST_kKeyBackSpace);
791                         GXMAP(type,XK_Tab,              GHOST_kKeyTab);
792                         GXMAP(type,XK_Return,           GHOST_kKeyEnter);
793                         GXMAP(type,XK_Escape,           GHOST_kKeyEsc);
794                         GXMAP(type,XK_space,            GHOST_kKeySpace);
795                         
796                         GXMAP(type,XK_Linefeed,         GHOST_kKeyLinefeed);
797                         GXMAP(type,XK_semicolon,        GHOST_kKeySemicolon);
798                         GXMAP(type,XK_period,           GHOST_kKeyPeriod);
799                         GXMAP(type,XK_comma,            GHOST_kKeyComma);
800                         GXMAP(type,XK_quoteright,       GHOST_kKeyQuote);
801                         GXMAP(type,XK_quoteleft,        GHOST_kKeyAccentGrave);
802                         GXMAP(type,XK_minus,            GHOST_kKeyMinus);
803                         GXMAP(type,XK_slash,            GHOST_kKeySlash);
804                         GXMAP(type,XK_backslash,        GHOST_kKeyBackslash);
805                         GXMAP(type,XK_equal,            GHOST_kKeyEqual);
806                         GXMAP(type,XK_bracketleft,      GHOST_kKeyLeftBracket);
807                         GXMAP(type,XK_bracketright,     GHOST_kKeyRightBracket);
808                         GXMAP(type,XK_Pause,            GHOST_kKeyPause);
809                         
810                         GXMAP(type,XK_Shift_L,          GHOST_kKeyLeftShift);
811                         GXMAP(type,XK_Shift_R,          GHOST_kKeyRightShift);
812                         GXMAP(type,XK_Control_L,        GHOST_kKeyLeftControl);
813                         GXMAP(type,XK_Control_R,        GHOST_kKeyRightControl);
814                         GXMAP(type,XK_Alt_L,            GHOST_kKeyLeftAlt);
815                         GXMAP(type,XK_Alt_R,            GHOST_kKeyRightAlt);
816
817                         GXMAP(type,XK_Insert,           GHOST_kKeyInsert);
818                         GXMAP(type,XK_Delete,           GHOST_kKeyDelete);
819                         GXMAP(type,XK_Home,                     GHOST_kKeyHome);
820                         GXMAP(type,XK_End,                      GHOST_kKeyEnd);
821                         GXMAP(type,XK_Page_Up,          GHOST_kKeyUpPage);
822                         GXMAP(type,XK_Page_Down,        GHOST_kKeyDownPage);
823
824                         GXMAP(type,XK_Left,                     GHOST_kKeyLeftArrow);
825                         GXMAP(type,XK_Right,            GHOST_kKeyRightArrow);
826                         GXMAP(type,XK_Up,                       GHOST_kKeyUpArrow);
827                         GXMAP(type,XK_Down,                     GHOST_kKeyDownArrow);
828
829                         GXMAP(type,XK_Caps_Lock,        GHOST_kKeyCapsLock);
830                         GXMAP(type,XK_Scroll_Lock,      GHOST_kKeyScrollLock);
831                         GXMAP(type,XK_Num_Lock,         GHOST_kKeyNumLock);
832                         
833                                 /* keypad events */
834                                 
835                         GXMAP(type,XK_KP_0,                     GHOST_kKeyNumpad0);
836                         GXMAP(type,XK_KP_1,                     GHOST_kKeyNumpad1);
837                         GXMAP(type,XK_KP_2,                     GHOST_kKeyNumpad2);
838                         GXMAP(type,XK_KP_3,                     GHOST_kKeyNumpad3);
839                         GXMAP(type,XK_KP_4,                     GHOST_kKeyNumpad4);
840                         GXMAP(type,XK_KP_5,                     GHOST_kKeyNumpad5);
841                         GXMAP(type,XK_KP_6,                     GHOST_kKeyNumpad6);
842                         GXMAP(type,XK_KP_7,                     GHOST_kKeyNumpad7);
843                         GXMAP(type,XK_KP_8,                     GHOST_kKeyNumpad8);
844                         GXMAP(type,XK_KP_9,                     GHOST_kKeyNumpad9);
845                         GXMAP(type,XK_KP_Decimal,       GHOST_kKeyNumpadPeriod);
846
847                         GXMAP(type,XK_KP_Insert,        GHOST_kKeyNumpad0);
848                         GXMAP(type,XK_KP_End,           GHOST_kKeyNumpad1);
849                         GXMAP(type,XK_KP_Down,          GHOST_kKeyNumpad2);
850                         GXMAP(type,XK_KP_Page_Down,     GHOST_kKeyNumpad3);
851                         GXMAP(type,XK_KP_Left,          GHOST_kKeyNumpad4);
852                         GXMAP(type,XK_KP_Begin,         GHOST_kKeyNumpad5);
853                         GXMAP(type,XK_KP_Right,         GHOST_kKeyNumpad6);
854                         GXMAP(type,XK_KP_Home,          GHOST_kKeyNumpad7);
855                         GXMAP(type,XK_KP_Up,            GHOST_kKeyNumpad8);
856                         GXMAP(type,XK_KP_Page_Up,       GHOST_kKeyNumpad9);
857                         GXMAP(type,XK_KP_Delete,        GHOST_kKeyNumpadPeriod);
858
859                         GXMAP(type,XK_KP_Enter,         GHOST_kKeyNumpadEnter);
860                         GXMAP(type,XK_KP_Add,           GHOST_kKeyNumpadPlus);
861                         GXMAP(type,XK_KP_Subtract,      GHOST_kKeyNumpadMinus);
862                         GXMAP(type,XK_KP_Multiply,      GHOST_kKeyNumpadAsterisk);
863                         GXMAP(type,XK_KP_Divide,        GHOST_kKeyNumpadSlash);
864
865                                 /* some extra sun cruft (NICE KEYBOARD!) */
866 #ifdef __sun__
867                         GXMAP(type,0xffde,                      GHOST_kKeyNumpad1);
868                         GXMAP(type,0xffe0,                      GHOST_kKeyNumpad3);
869                         GXMAP(type,0xffdc,                      GHOST_kKeyNumpad5);
870                         GXMAP(type,0xffd8,                      GHOST_kKeyNumpad7);
871                         GXMAP(type,0xffda,                      GHOST_kKeyNumpad9);
872
873                         GXMAP(type,0xffd6,                      GHOST_kKeyNumpadSlash);
874                         GXMAP(type,0xffd7,                      GHOST_kKeyNumpadAsterisk);
875 #endif
876
877                         default :
878                                 type = GHOST_kKeyUnknown;
879                                 break;
880                 }
881         }
882
883         return type;
884 }
885
886 #undef GXMAP