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