6eefb48f6e831192993afb1b50fa6dc2e5cbb4d6
[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 #endif
488                         break;
489                 }
490                         
491                 // We're not interested in the following things.(yet...)
492                 case NoExpose : 
493                 case GraphicsExpose :
494                 
495                 case EnterNotify:
496                 case LeaveNotify:
497                         // XCrossingEvents pointer leave enter window.
498                         break;
499                 case MapNotify:
500                 case UnmapNotify:
501                         break;
502                 case MappingNotify:
503                 case ReparentNotify:
504                         break;
505
506         default: {
507                         if(xe->type == window->GetXTablet().MotionEvent) 
508                         {
509                                 XDeviceMotionEvent* data = (XDeviceMotionEvent*)xe;
510                                 window->GetXTablet().CommonData.Pressure= 
511                                         data->axis_data[2]/((float)window->GetXTablet().PressureLevels);
512                         
513                         /* the (short) cast and the &0xffff is bizarre and unexplained anywhere,
514                          * but I got garbage data without it. Found it in the xidump.c source --matt */
515                                 window->GetXTablet().CommonData.Xtilt= 
516                                         (short)(data->axis_data[3]&0xffff)/((float)window->GetXTablet().XtiltLevels);
517                                 window->GetXTablet().CommonData.Ytilt= 
518                                         (short)(data->axis_data[4]&0xffff)/((float)window->GetXTablet().YtiltLevels);
519                         }
520                         else if(xe->type == window->GetXTablet().ProxInEvent) 
521                         {
522                                 XProximityNotifyEvent* data = (XProximityNotifyEvent*)xe;
523                                 if(data->deviceid == window->GetXTablet().StylusID)
524                                         window->GetXTablet().CommonData.Active= 1;
525                                 else if(data->deviceid == window->GetXTablet().EraserID)
526                                         window->GetXTablet().CommonData.Active= 2;
527                         }
528                         else if(xe->type == window->GetXTablet().ProxOutEvent)
529                                 window->GetXTablet().CommonData.Active= 0;
530
531                         break;
532                 }
533         }
534
535         if (g_event) {
536                 pushEvent(g_event);
537         }
538 }
539
540         void *
541 GHOST_SystemX11::
542 prepareNdofInfo(volatile GHOST_TEventNDOFData *currentNdofValues)
543 {
544         const vector<GHOST_IWindow*>& v(m_windowManager->getWindows());
545         if (v.size() > 0)
546         sNdofInfo.window = static_cast<GHOST_WindowX11*>(v[0])->getXWindow();
547         sNdofInfo.display = m_display;
548         sNdofInfo.currValues = currentNdofValues;
549         return (void*)&sNdofInfo;
550 }
551
552         GHOST_TSuccess 
553 GHOST_SystemX11::
554 getModifierKeys(
555         GHOST_ModifierKeys& keys
556 ) const {
557
558         // analyse the masks retuned from XQueryPointer.
559
560         memset(m_keyboard_vector,0,sizeof(m_keyboard_vector));
561
562         XQueryKeymap(m_display,m_keyboard_vector);
563
564         // now translate key symobols into keycodes and
565         // test with vector.
566
567         const KeyCode shift_l = XKeysymToKeycode(m_display,XK_Shift_L);
568         const KeyCode shift_r = XKeysymToKeycode(m_display,XK_Shift_R);
569         const KeyCode control_l = XKeysymToKeycode(m_display,XK_Control_L);
570         const KeyCode control_r = XKeysymToKeycode(m_display,XK_Control_R);
571         const KeyCode alt_l = XKeysymToKeycode(m_display,XK_Alt_L);
572         const KeyCode alt_r = XKeysymToKeycode(m_display,XK_Alt_R);
573
574         // Shift
575         if ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) {
576                 keys.set(GHOST_kModifierKeyLeftShift,true);
577         } else {
578                 keys.set(GHOST_kModifierKeyLeftShift,false);
579         }
580         if ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) {
581
582                 keys.set(GHOST_kModifierKeyRightShift,true);
583         } else {
584                 keys.set(GHOST_kModifierKeyRightShift,false);
585         }
586
587         // control (weep)
588         if ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) {
589                 keys.set(GHOST_kModifierKeyLeftControl,true);
590         } else {
591                 keys.set(GHOST_kModifierKeyLeftControl,false);
592         }
593         if ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) {
594                 keys.set(GHOST_kModifierKeyRightControl,true);
595         } else {
596                 keys.set(GHOST_kModifierKeyRightControl,false);
597         }
598
599         // Alt (yawn)
600         if ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) {
601                 keys.set(GHOST_kModifierKeyLeftAlt,true);
602         } else {
603                 keys.set(GHOST_kModifierKeyLeftAlt,false);
604         }       
605         if ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) {
606                 keys.set(GHOST_kModifierKeyRightAlt,true);
607         } else {
608                 keys.set(GHOST_kModifierKeyRightAlt,false);
609         }
610         return GHOST_kSuccess;
611 }
612
613         GHOST_TSuccess 
614 GHOST_SystemX11::
615 getButtons(
616         GHOST_Buttons& buttons
617 ) const {
618
619         Window root_return, child_return;
620         int rx,ry,wx,wy;
621         unsigned int mask_return;
622
623         if (XQueryPointer(
624                 m_display,
625                 RootWindow(m_display,DefaultScreen(m_display)),
626                 &root_return,
627                 &child_return,
628                 &rx,&ry,
629                 &wx,&wy,
630                 &mask_return
631         ) == False) {
632                 return GHOST_kFailure;
633         } else {
634
635                 if (mask_return & Button1Mask) {
636                         buttons.set(GHOST_kButtonMaskLeft,true);
637                 } else {
638                         buttons.set(GHOST_kButtonMaskLeft,false);
639                 }
640
641                 if (mask_return & Button2Mask) {
642                         buttons.set(GHOST_kButtonMaskMiddle,true);
643                 } else {
644                         buttons.set(GHOST_kButtonMaskMiddle,false);
645                 }
646
647                 if (mask_return & Button3Mask) {
648                         buttons.set(GHOST_kButtonMaskRight,true);
649                 } else {
650                         buttons.set(GHOST_kButtonMaskRight,false);
651                 }
652         }       
653
654         return GHOST_kSuccess;
655 }
656
657
658         GHOST_TSuccess 
659 GHOST_SystemX11::
660 getCursorPosition(
661         GHOST_TInt32& x,
662         GHOST_TInt32& y
663 ) const {
664
665         Window root_return, child_return;
666         int rx,ry,wx,wy;
667         unsigned int mask_return;
668
669         if (XQueryPointer(
670                 m_display,
671                 RootWindow(m_display,DefaultScreen(m_display)),
672                 &root_return,
673                 &child_return,
674                 &rx,&ry,
675                 &wx,&wy,
676                 &mask_return
677         ) == False) {
678                 return GHOST_kFailure;
679         } else {
680                 x = rx;
681                 y = ry;
682         }       
683         return GHOST_kSuccess;
684 }
685
686
687         GHOST_TSuccess 
688 GHOST_SystemX11::
689 setCursorPosition(
690         GHOST_TInt32 x,
691         GHOST_TInt32 y
692 ) const {
693
694         // This is a brute force move in screen coordinates
695         // XWarpPointer does relative moves so first determine the
696         // current pointer position.
697
698         int cx,cy;
699         if (getCursorPosition(cx,cy) == GHOST_kFailure) {
700                 return GHOST_kFailure;
701         }
702
703         int relx = x-cx;
704         int rely = y-cy;
705
706         XWarpPointer(m_display,None,None,0,0,0,0,relx,rely);
707         XFlush(m_display);
708         
709         return GHOST_kSuccess;
710 }
711
712
713         void
714 GHOST_SystemX11::
715 addDirtyWindow(
716         GHOST_WindowX11 * bad_wind
717 ){
718
719         GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
720         
721         m_dirty_windows.push_back(bad_wind);
722 }
723
724
725         bool
726 GHOST_SystemX11::
727 generateWindowExposeEvents(
728 ){
729
730         vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin();
731         vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end();
732         bool anyProcessed = false;
733         
734         for (;w_start != w_end; ++w_start) {
735                 GHOST_Event * g_event = new 
736                         GHOST_Event(
737                                 getMilliSeconds(),
738                                 GHOST_kEventWindowUpdate,
739                                 *w_start
740                         );                      
741
742                 (*w_start)->validate(); 
743                 
744                 if (g_event) {
745                         pushEvent(g_event);
746                         anyProcessed = true;
747                 }
748         }
749
750         m_dirty_windows.clear();
751         return anyProcessed;
752 }
753
754 #define GXMAP(k,x,y) case x: k = y; break; 
755
756         GHOST_TKey
757 GHOST_SystemX11::
758 convertXKey(
759         KeySym key
760 ){
761         GHOST_TKey type;
762
763         if ((key >= XK_A) && (key <= XK_Z)) {
764                 type = GHOST_TKey( key - XK_A + int(GHOST_kKeyA));
765         } else if ((key >= XK_a) && (key <= XK_z)) {
766                 type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA));
767         } else if ((key >= XK_0) && (key <= XK_9)) {
768                 type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0));
769         } else if ((key >= XK_F1) && (key <= XK_F24)) {
770                 type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1));
771 #if defined(__sun) || defined(__sun__) 
772                 /* This is a bit of a hack, but it looks like sun
773                    Used F11 and friends for its special keys Stop,again etc..
774                    So this little patch enables F11 and F12 to work as expected
775                    following link has documentation on it: 
776                    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4734408
777                    also from /usr/include/X11/Sunkeysym.h 
778 #define SunXK_F36               0x1005FF10      // Labeled F11
779 #define SunXK_F37               0x1005FF11      // Labeled F12 
780
781                                 mein@cs.umn.edu
782                  */
783                 
784         } else if (key == 268828432) {
785                 type = GHOST_kKeyF11;
786         } else if (key == 268828433) {
787                 type = GHOST_kKeyF12;
788 #endif
789         } else {
790                 switch(key) {
791                         GXMAP(type,XK_BackSpace,        GHOST_kKeyBackSpace);
792                         GXMAP(type,XK_Tab,              GHOST_kKeyTab);
793                         GXMAP(type,XK_Return,           GHOST_kKeyEnter);
794                         GXMAP(type,XK_Escape,           GHOST_kKeyEsc);
795                         GXMAP(type,XK_space,            GHOST_kKeySpace);
796                         
797                         GXMAP(type,XK_Linefeed,         GHOST_kKeyLinefeed);
798                         GXMAP(type,XK_semicolon,        GHOST_kKeySemicolon);
799                         GXMAP(type,XK_period,           GHOST_kKeyPeriod);
800                         GXMAP(type,XK_comma,            GHOST_kKeyComma);
801                         GXMAP(type,XK_quoteright,       GHOST_kKeyQuote);
802                         GXMAP(type,XK_quoteleft,        GHOST_kKeyAccentGrave);
803                         GXMAP(type,XK_minus,            GHOST_kKeyMinus);
804                         GXMAP(type,XK_slash,            GHOST_kKeySlash);
805                         GXMAP(type,XK_backslash,        GHOST_kKeyBackslash);
806                         GXMAP(type,XK_equal,            GHOST_kKeyEqual);
807                         GXMAP(type,XK_bracketleft,      GHOST_kKeyLeftBracket);
808                         GXMAP(type,XK_bracketright,     GHOST_kKeyRightBracket);
809                         GXMAP(type,XK_Pause,            GHOST_kKeyPause);
810                         
811                         GXMAP(type,XK_Shift_L,          GHOST_kKeyLeftShift);
812                         GXMAP(type,XK_Shift_R,          GHOST_kKeyRightShift);
813                         GXMAP(type,XK_Control_L,        GHOST_kKeyLeftControl);
814                         GXMAP(type,XK_Control_R,        GHOST_kKeyRightControl);
815                         GXMAP(type,XK_Alt_L,            GHOST_kKeyLeftAlt);
816                         GXMAP(type,XK_Alt_R,            GHOST_kKeyRightAlt);
817
818                         GXMAP(type,XK_Insert,           GHOST_kKeyInsert);
819                         GXMAP(type,XK_Delete,           GHOST_kKeyDelete);
820                         GXMAP(type,XK_Home,                     GHOST_kKeyHome);
821                         GXMAP(type,XK_End,                      GHOST_kKeyEnd);
822                         GXMAP(type,XK_Page_Up,          GHOST_kKeyUpPage);
823                         GXMAP(type,XK_Page_Down,        GHOST_kKeyDownPage);
824
825                         GXMAP(type,XK_Left,                     GHOST_kKeyLeftArrow);
826                         GXMAP(type,XK_Right,            GHOST_kKeyRightArrow);
827                         GXMAP(type,XK_Up,                       GHOST_kKeyUpArrow);
828                         GXMAP(type,XK_Down,                     GHOST_kKeyDownArrow);
829
830                         GXMAP(type,XK_Caps_Lock,        GHOST_kKeyCapsLock);
831                         GXMAP(type,XK_Scroll_Lock,      GHOST_kKeyScrollLock);
832                         GXMAP(type,XK_Num_Lock,         GHOST_kKeyNumLock);
833                         
834                                 /* keypad events */
835                                 
836                         GXMAP(type,XK_KP_0,                     GHOST_kKeyNumpad0);
837                         GXMAP(type,XK_KP_1,                     GHOST_kKeyNumpad1);
838                         GXMAP(type,XK_KP_2,                     GHOST_kKeyNumpad2);
839                         GXMAP(type,XK_KP_3,                     GHOST_kKeyNumpad3);
840                         GXMAP(type,XK_KP_4,                     GHOST_kKeyNumpad4);
841                         GXMAP(type,XK_KP_5,                     GHOST_kKeyNumpad5);
842                         GXMAP(type,XK_KP_6,                     GHOST_kKeyNumpad6);
843                         GXMAP(type,XK_KP_7,                     GHOST_kKeyNumpad7);
844                         GXMAP(type,XK_KP_8,                     GHOST_kKeyNumpad8);
845                         GXMAP(type,XK_KP_9,                     GHOST_kKeyNumpad9);
846                         GXMAP(type,XK_KP_Decimal,       GHOST_kKeyNumpadPeriod);
847
848                         GXMAP(type,XK_KP_Insert,        GHOST_kKeyNumpad0);
849                         GXMAP(type,XK_KP_End,           GHOST_kKeyNumpad1);
850                         GXMAP(type,XK_KP_Down,          GHOST_kKeyNumpad2);
851                         GXMAP(type,XK_KP_Page_Down,     GHOST_kKeyNumpad3);
852                         GXMAP(type,XK_KP_Left,          GHOST_kKeyNumpad4);
853                         GXMAP(type,XK_KP_Begin,         GHOST_kKeyNumpad5);
854                         GXMAP(type,XK_KP_Right,         GHOST_kKeyNumpad6);
855                         GXMAP(type,XK_KP_Home,          GHOST_kKeyNumpad7);
856                         GXMAP(type,XK_KP_Up,            GHOST_kKeyNumpad8);
857                         GXMAP(type,XK_KP_Page_Up,       GHOST_kKeyNumpad9);
858                         GXMAP(type,XK_KP_Delete,        GHOST_kKeyNumpadPeriod);
859
860                         GXMAP(type,XK_KP_Enter,         GHOST_kKeyNumpadEnter);
861                         GXMAP(type,XK_KP_Add,           GHOST_kKeyNumpadPlus);
862                         GXMAP(type,XK_KP_Subtract,      GHOST_kKeyNumpadMinus);
863                         GXMAP(type,XK_KP_Multiply,      GHOST_kKeyNumpadAsterisk);
864                         GXMAP(type,XK_KP_Divide,        GHOST_kKeyNumpadSlash);
865
866                                 /* some extra sun cruft (NICE KEYBOARD!) */
867 #ifdef __sun__
868                         GXMAP(type,0xffde,                      GHOST_kKeyNumpad1);
869                         GXMAP(type,0xffe0,                      GHOST_kKeyNumpad3);
870                         GXMAP(type,0xffdc,                      GHOST_kKeyNumpad5);
871                         GXMAP(type,0xffd8,                      GHOST_kKeyNumpad7);
872                         GXMAP(type,0xffda,                      GHOST_kKeyNumpad9);
873
874                         GXMAP(type,0xffd6,                      GHOST_kKeyNumpadSlash);
875                         GXMAP(type,0xffd7,                      GHOST_kKeyNumpadAsterisk);
876 #endif
877
878                         default :
879                                 type = GHOST_kKeyUnknown;
880                                 break;
881                 }
882         }
883
884         return type;
885 }
886
887 #undef GXMAP