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